迁移音频生成与语音合成到 gateway 并补充 simulation 测试
This commit is contained in:
@@ -2,6 +2,7 @@ package clients
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
@@ -65,6 +66,35 @@ func TestSimulationClientReturnsVideoDemoAssets(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestSimulationClientReturnsAudioDemoAssets(t *testing.T) {
|
||||
response, err := (SimulationClient{}).Run(context.Background(), Request{
|
||||
Kind: "speech.generations",
|
||||
ModelType: "text_to_speech",
|
||||
Model: "speech-2.6-turbo",
|
||||
Body: map[string]any{
|
||||
"text": "hello from simulation",
|
||||
"voice_id": "female-shaonv",
|
||||
"count": 2,
|
||||
"simulationDurationMs": 5,
|
||||
},
|
||||
Candidate: store.RuntimeModelCandidate{Provider: "simulation"},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("run simulation audio client: %v", err)
|
||||
}
|
||||
data, _ := response.Result["data"].([]any)
|
||||
if len(data) != 2 || response.Result["status"] != "success" {
|
||||
t.Fatalf("unexpected simulated audio response: %+v", response.Result)
|
||||
}
|
||||
item, _ := data[0].(map[string]any)
|
||||
if item["type"] != "audio" || item["url"] != "/static/simulation/audio.wav" || item["audio_url"] != "/static/simulation/audio.wav" {
|
||||
t.Fatalf("unexpected simulated audio item: %+v", item)
|
||||
}
|
||||
if item["revised_text"] != "hello from simulation" || item["assetSource"] != "simulation" {
|
||||
t.Fatalf("unexpected simulated audio metadata: %+v", item)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSimulationDurationDefaultsByMediaType(t *testing.T) {
|
||||
imageDuration := simulationDuration(Request{Kind: "images.generations"})
|
||||
if imageDuration < 10*time.Second || imageDuration > 30*time.Second {
|
||||
@@ -74,12 +104,84 @@ func TestSimulationDurationDefaultsByMediaType(t *testing.T) {
|
||||
if videoDuration < 2*time.Minute || videoDuration > 3*time.Minute {
|
||||
t.Fatalf("video simulation duration should default to 2-3m, got %s", videoDuration)
|
||||
}
|
||||
audioDuration := simulationDuration(Request{Kind: "speech.generations"})
|
||||
if audioDuration < 2*time.Second || audioDuration > 6*time.Second {
|
||||
t.Fatalf("audio simulation duration should default to 2-6s, got %s", audioDuration)
|
||||
}
|
||||
textDuration := simulationDuration(Request{Kind: "chat.completions"})
|
||||
if textDuration < 800*time.Millisecond || textDuration > 2400*time.Millisecond {
|
||||
t.Fatalf("text simulation duration should keep short defaults, got %s", textDuration)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMinimaxClientSpeechUsesT2AV2AndNormalizesAudio(t *testing.T) {
|
||||
var captured map[string]any
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodPost || r.URL.Path != "/t2a_v2" {
|
||||
t.Fatalf("unexpected request: %s %s", r.Method, r.URL.String())
|
||||
}
|
||||
if got := r.Header.Get("Authorization"); got != "Bearer test-key" {
|
||||
t.Fatalf("unexpected auth header: %q", got)
|
||||
}
|
||||
if err := json.NewDecoder(r.Body).Decode(&captured); err != nil {
|
||||
t.Fatalf("decode request: %v", err)
|
||||
}
|
||||
w.Header().Set("x-request-id", "req-minimax-speech")
|
||||
_ = json.NewEncoder(w).Encode(map[string]any{
|
||||
"data": map[string]any{"audio": "68656c6c6f"},
|
||||
"base_resp": map[string]any{"status_code": 0},
|
||||
})
|
||||
}))
|
||||
defer server.Close()
|
||||
|
||||
response, err := (MinimaxClient{HTTPClient: server.Client()}).Run(context.Background(), Request{
|
||||
Kind: "speech.generations",
|
||||
Model: "MiniMax Speech 2.6 Turbo",
|
||||
Body: map[string]any{
|
||||
"text": "hello",
|
||||
"voice_id": "female-shaonv",
|
||||
"speed": 1.2,
|
||||
"vol": 0.8,
|
||||
"pitch": -1,
|
||||
"emotion": "happy",
|
||||
},
|
||||
Candidate: store.RuntimeModelCandidate{
|
||||
Provider: "minimax",
|
||||
BaseURL: server.URL,
|
||||
ProviderModelName: "speech-2.6-turbo",
|
||||
Credentials: map[string]any{"apiKey": "test-key"},
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("run minimax speech client: %v", err)
|
||||
}
|
||||
if captured["model"] != "speech-2.6-turbo" || captured["text"] != "hello" {
|
||||
t.Fatalf("unexpected minimax speech payload: %+v", captured)
|
||||
}
|
||||
if _, ok := captured["voice_id"]; ok {
|
||||
t.Fatalf("voice_id should be moved into voice_setting: %+v", captured)
|
||||
}
|
||||
voiceSetting, ok := captured["voice_setting"].(map[string]any)
|
||||
if !ok {
|
||||
t.Fatalf("missing voice_setting: %+v", captured)
|
||||
}
|
||||
if voiceSetting["voice_id"] != "female-shaonv" || voiceSetting["speed"] != 1.2 || voiceSetting["vol"] != 0.8 || voiceSetting["pitch"] != float64(-1) || voiceSetting["emotion"] != "happy" {
|
||||
t.Fatalf("unexpected voice_setting: %+v", voiceSetting)
|
||||
}
|
||||
data, _ := response.Result["data"].([]any)
|
||||
if len(data) != 1 {
|
||||
t.Fatalf("unexpected minimax speech response: %+v", response.Result)
|
||||
}
|
||||
item, _ := data[0].(map[string]any)
|
||||
expectedContent := "data:audio/mpeg;base64," + base64.StdEncoding.EncodeToString([]byte("hello"))
|
||||
if item["type"] != "audio" || item["content"] != expectedContent || item["mime_type"] != "audio/mpeg" {
|
||||
t.Fatalf("unexpected normalized audio item: %+v", item)
|
||||
}
|
||||
if response.RequestID != "req-minimax-speech" {
|
||||
t.Fatalf("unexpected request id: %q", response.RequestID)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSimulationDurationCanBeControlledByParams(t *testing.T) {
|
||||
fixedDuration := simulationDuration(Request{Body: map[string]any{"simulationDurationSeconds": 7}})
|
||||
if fixedDuration != 7*time.Second {
|
||||
|
||||
Reference in New Issue
Block a user