provider: 音频多模态序列化为 OpenAI「input_audio」格式

HomeAgent 的 ContentBlock.AudioURL 原本输出 audio_url(非 OpenAI 标准块);
现通过 MarshalJSON 在 base64 数据时自动转为 OpenAI input_audio
({data,format}),供支持音频的模型识别。非 base64(url)保留原样透传。
- parseAudioDataURL: data:mime;base64,data → (data,format)
- audioFormatFromMIME: wav/mp3/mp4/ogg/flac
- 新增单测:base64 转 input_audio、url 保留 audio_url

验证: go test ./... 27 包 0 失败;Windows 交叉编译通过;部署后服务健康
This commit is contained in:
root
2026-08-10 12:55:43 +08:00
parent 27183312ad
commit c19fea2584
2 changed files with 105 additions and 4 deletions

View File

@ -2,14 +2,16 @@ package api
import (
"context"
"encoding/json"
"strings"
"testing"
)
// stubRoutableProvider implements both Provider and RoutableProvider.
type stubRoutableProvider struct {
name string
model string
prio int
name string
model string
prio int
}
func (s *stubRoutableProvider) Name() string { return s.name }
@ -63,4 +65,41 @@ func names(ps []Provider) []string {
out[i] = p.Name()
}
return out
}
}
func TestMessageAudioBlockToInputAudio(t *testing.T) {
const b64 = "QUJDREVG" // base64 of "ABCDEF"
m := Message{
Role: "user",
Blocks: []ContentBlock{
{Type: "text", Text: "what is this"},
{Type: "audio_url", AudioURL: &AudioURL{URL: "data:audio/wav;base64," + b64}},
},
}
data, err := json.Marshal(m)
if err != nil {
t.Fatalf("marshal: %v", err)
}
s := string(data)
if !strings.Contains(s, `"type":"input_audio"`) {
t.Fatalf("expected input_audio, got: %s", s)
}
if !strings.Contains(s, `"format":"wav"`) || !strings.Contains(s, b64) {
t.Fatalf("missing data/format: %s", s)
}
if strings.Contains(s, `"type":"audio_url"`) {
t.Fatalf("audio_url should be converted: %s", s)
}
}
func TestMessageAudioURLPassthroughWhenNotBase64(t *testing.T) {
m := Message{
Role: "user",
Blocks: []ContentBlock{
{Type: "audio_url", AudioURL: &AudioURL{URL: "https://cdn.example/a.wav"}},
},
}
data, _ := json.Marshal(m)
if !strings.Contains(string(data), `"type":"audio_url"`) {
t.Fatalf("non-base64 audio_url should stay: %s", data)
}
}