迁移音频生成与语音合成到 gateway 并补充 simulation 测试

This commit is contained in:
2026-06-07 10:26:57 +08:00
parent 78ab867a9f
commit dc14866210
22 changed files with 2475 additions and 55 deletions
@@ -2,6 +2,7 @@ package clients
import (
"context"
"encoding/json"
"errors"
"net/http"
"net/http/httptest"
@@ -227,6 +228,80 @@ func TestProviderTaskClientsSubmitAndPoll(t *testing.T) {
}
}
func TestSunoClientSubmitsAndPollsAudioGeneration(t *testing.T) {
var submitted map[string]any
var submittedRemoteTaskID string
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if got := r.Header.Get("Authorization"); got != "Bearer test-key" {
t.Fatalf("unexpected auth header: %q", got)
}
w.Header().Set("Content-Type", "application/json")
w.Header().Set("x-request-id", "req-suno")
switch {
case r.Method == http.MethodPost && r.URL.Path == "/generator/suno":
if err := json.NewDecoder(r.Body).Decode(&submitted); err != nil {
t.Fatalf("decode suno submit request: %v", err)
}
_, _ = w.Write([]byte(`{"code":200,"data":"suno-task"}`))
case r.Method == http.MethodGet && r.URL.Path == "/v2/sunoinfo" && r.URL.Query().Get("id") == "suno-task":
_, _ = w.Write([]byte(`{"code":200,"data":{"status":"succeeded","result":[{"audio_url":"https://cdn.example/song.mp3"}]}}`))
default:
t.Fatalf("unexpected request: %s %s", r.Method, r.URL.String())
}
}))
defer server.Close()
response, err := (SunoClient{HTTPClient: server.Client()}).Run(context.Background(), Request{
Kind: "song.generations",
ModelType: "audio_generate",
Model: "Suno V5",
Body: map[string]any{
"prompt": "city lights",
"tags": "pop",
"negativeTags": "noise",
},
Candidate: store.RuntimeModelCandidate{
Provider: "suno",
SpecType: "suno",
BaseURL: server.URL,
Credentials: map[string]any{"apiKey": "test-key"},
PlatformConfig: map[string]any{"pollIntervalMs": 1, "pollTimeoutMs": 1000},
ProviderModelName: "chirp-v5-0",
ModelType: "audio_generate",
},
OnRemoteTaskSubmitted: func(remoteTaskID string, payload map[string]any) error {
submittedRemoteTaskID = remoteTaskID
if payload["payload"] == nil || payload["submit"] == nil {
t.Fatalf("missing remote payload: %#v", payload)
}
return nil
},
})
if err != nil {
t.Fatalf("run suno client: %v", err)
}
if submittedRemoteTaskID != "suno-task" {
t.Fatalf("unexpected remote task id: %q", submittedRemoteTaskID)
}
if submitted["task"] != "create" || submitted["model"] != "v50" || submitted["prompt"] != "city lights" {
t.Fatalf("unexpected suno submit payload: %+v", submitted)
}
if submitted["customMode"] != false || submitted["makeInstrumental"] != false {
t.Fatalf("suno defaults should match main-server style payload: %+v", submitted)
}
data, _ := response.Result["data"].([]any)
if len(data) != 1 {
t.Fatalf("unexpected suno response: %+v", response.Result)
}
first, _ := data[0].(map[string]any)
if first["type"] != "audio" || first["url"] != "https://cdn.example/song.mp3" {
t.Fatalf("unexpected suno normalized audio item: %+v", first)
}
if response.RequestID != "req-suno" {
t.Fatalf("unexpected request id: %q", response.RequestID)
}
}
func TestProviderTaskClientFailureAndRetryableErrors(t *testing.T) {
t.Run("poll failure", func(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {