feat(api): 添加多媒体内容支持并优化钱包计费系统
- 在 API 接口定义中为 video_url 和 audio_url 类型添加 mime_type 字段 - 实现 Google Gemini 客户端对视频和音频内容的支持,包括媒体类型检测和数据传输 - 添加 Gemini 客户端测试用例验证多媒体内容转换功能 - 重构 Playground 页面的媒体上传逻辑以支持 MIME 类型传递 - 实现钱包计费预留机制,确保任务执行前余额充足 - 添加钱包冻结余额管理,防止并发操作导致的超扣问题 - 实现计费预留释放逻辑,处理任务失败或取消情况下的资金返还 - 优化数据库事务处理,确保计费操作的原子性和一致性 - 添加数据库集成测试验证迁移脚本执行流程 - 统一 Google Gemini 相关模型提供商标识符映射
This commit is contained in:
@@ -129,6 +129,13 @@ func TestCoreLocalFlow(t *testing.T) {
|
||||
if _, err := testPool.Exec(ctx, `UPDATE gateway_users SET roles = '["admin"]'::jsonb WHERE username = $1`, username); err != nil {
|
||||
t.Fatalf("promote smoke user: %v", err)
|
||||
}
|
||||
doJSON(t, server.URL, http.MethodPost, "/api/v1/auth/login", "", map[string]any{
|
||||
"account": username,
|
||||
"password": password,
|
||||
}, http.StatusOK, &loginResponse)
|
||||
if loginResponse.AccessToken == "" {
|
||||
t.Fatal("admin login did not return access token")
|
||||
}
|
||||
var smokeGatewayUserID string
|
||||
if err := testPool.QueryRow(ctx, `SELECT id::text FROM gateway_users WHERE username = $1`, username).Scan(&smokeGatewayUserID); err != nil {
|
||||
t.Fatalf("read smoke gateway user id: %v", err)
|
||||
@@ -1402,14 +1409,41 @@ func applyMigration(t *testing.T, ctx context.Context, databaseURL string) {
|
||||
t.Fatalf("connect migration db: %v", err)
|
||||
}
|
||||
defer pool.Close()
|
||||
if _, err := pool.Exec(ctx, `
|
||||
CREATE TABLE IF NOT EXISTS schema_migrations (
|
||||
version text PRIMARY KEY,
|
||||
applied_at timestamptz NOT NULL DEFAULT now()
|
||||
);`); err != nil {
|
||||
t.Fatalf("ensure schema migrations: %v", err)
|
||||
}
|
||||
for _, migrationPath := range migrationFiles {
|
||||
version := strings.TrimSuffix(filepath.Base(migrationPath), filepath.Ext(migrationPath))
|
||||
var exists bool
|
||||
if err := pool.QueryRow(ctx, "SELECT EXISTS (SELECT 1 FROM schema_migrations WHERE version = $1)", version).Scan(&exists); err != nil {
|
||||
t.Fatalf("check migration %s: %v", filepath.Base(migrationPath), err)
|
||||
}
|
||||
if exists {
|
||||
continue
|
||||
}
|
||||
migration, err := os.ReadFile(migrationPath)
|
||||
if err != nil {
|
||||
t.Fatalf("read migration %s: %v", filepath.Base(migrationPath), err)
|
||||
}
|
||||
if _, err := pool.Exec(ctx, string(migration)); err != nil {
|
||||
tx, err := pool.Begin(ctx)
|
||||
if err != nil {
|
||||
t.Fatalf("begin migration %s: %v", filepath.Base(migrationPath), err)
|
||||
}
|
||||
if _, err := tx.Exec(ctx, string(migration)); err != nil {
|
||||
_ = tx.Rollback(ctx)
|
||||
t.Fatalf("apply migration %s: %v", filepath.Base(migrationPath), err)
|
||||
}
|
||||
if _, err := tx.Exec(ctx, "INSERT INTO schema_migrations(version) VALUES($1)", version); err != nil {
|
||||
_ = tx.Rollback(ctx)
|
||||
t.Fatalf("record migration %s: %v", filepath.Base(migrationPath), err)
|
||||
}
|
||||
if err := tx.Commit(ctx); err != nil {
|
||||
t.Fatalf("commit migration %s: %v", filepath.Base(migrationPath), err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user