fix(audio): 兼容百炼 OpenAI 音频输入
为阿里云百炼 OpenAI-compatible Chat 统一保留标准 input_audio,并将旧版 audio_url 转换为 input_audio,同时根据 MIME 或扩展名补齐音频格式。 补充请求资产水合测试,确认 input_audio.data 会转换为裸 Base64 且保留 format。 验证:在 apps/api 执行 env -u AI_GATEWAY_TEST_DATABASE_URL go test ./... -count=1 全部通过。
This commit is contained in:
@@ -344,6 +344,79 @@ func TestOpenAIClientChatContract(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestOpenAIClientAliyunChatSendsStandardInputAudioAndNormalizesLegacyAudioURL(t *testing.T) {
|
||||
var captured map[string]any
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if err := json.NewDecoder(r.Body).Decode(&captured); err != nil {
|
||||
t.Fatalf("decode request: %v", err)
|
||||
}
|
||||
_ = json.NewEncoder(w).Encode(map[string]any{
|
||||
"id": "chatcmpl-audio",
|
||||
"object": "chat.completion",
|
||||
"model": captured["model"],
|
||||
"choices": []any{map[string]any{
|
||||
"message": map[string]any{"role": "assistant", "content": "ok"},
|
||||
}},
|
||||
})
|
||||
}))
|
||||
defer server.Close()
|
||||
|
||||
_, err := (OpenAIClient{HTTPClient: server.Client()}).Run(context.Background(), Request{
|
||||
Kind: "chat.completions",
|
||||
Model: "qwen-omni",
|
||||
Body: map[string]any{
|
||||
"model": "qwen-omni",
|
||||
"messages": []any{
|
||||
map[string]any{
|
||||
"role": "user",
|
||||
"content": []any{
|
||||
map[string]any{
|
||||
"type": "input_audio",
|
||||
"input_audio": map[string]any{
|
||||
"data": "https://cdn.example.com/audio/standard.wav",
|
||||
"format": "wav",
|
||||
},
|
||||
},
|
||||
map[string]any{
|
||||
"type": "audio_url",
|
||||
"audio_url": map[string]any{"url": "https://cdn.example.com/audio/legacy.m4a"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Candidate: store.RuntimeModelCandidate{
|
||||
Provider: "aliyun-bailian-openai",
|
||||
BaseURL: server.URL,
|
||||
ProviderModelName: "qwen-omni",
|
||||
Credentials: map[string]any{"apiKey": "test-key"},
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("run aliyun openai-compatible client: %v", err)
|
||||
}
|
||||
|
||||
messages, _ := captured["messages"].([]any)
|
||||
message, _ := messages[0].(map[string]any)
|
||||
content, _ := message["content"].([]any)
|
||||
standard, _ := content[0].(map[string]any)
|
||||
if standard["type"] != "input_audio" {
|
||||
t.Fatalf("standard input_audio was not preserved: %+v", standard)
|
||||
}
|
||||
standardAudio, _ := standard["input_audio"].(map[string]any)
|
||||
if standardAudio["data"] != "https://cdn.example.com/audio/standard.wav" || standardAudio["format"] != "wav" {
|
||||
t.Fatalf("unexpected standard input_audio: %+v", standardAudio)
|
||||
}
|
||||
legacy, _ := content[1].(map[string]any)
|
||||
if legacy["type"] != "input_audio" {
|
||||
t.Fatalf("legacy audio_url was not normalized: %+v", legacy)
|
||||
}
|
||||
legacyAudio, _ := legacy["input_audio"].(map[string]any)
|
||||
if legacyAudio["data"] != "https://cdn.example.com/audio/legacy.m4a" || legacyAudio["format"] != "m4a" {
|
||||
t.Fatalf("unexpected normalized legacy audio: %+v", legacyAudio)
|
||||
}
|
||||
}
|
||||
|
||||
func TestOpenAIClientImageEditUsesMultipartWithMultipleImages(t *testing.T) {
|
||||
var contentType string
|
||||
var receivedFields map[string][]string
|
||||
|
||||
Reference in New Issue
Block a user