package main import ( "bytes" "context" "encoding/json" "fmt" "net/http" ) type voiceOption struct { ID string `json:"id"` Label string `json:"label"` } func ttsModels() []voiceOption { return []voiceOption{ {ID: "cosyvoice-v3.5-plus", Label: "CosyVoice v3.5 Plus(复刻/设计音色)"}, {ID: "cosyvoice-v3.5-flash", Label: "CosyVoice v3.5 Flash(低延迟)"}, {ID: "cosyvoice-v3-plus", Label: "CosyVoice v3 Plus"}, {ID: "cosyvoice-v3-flash", Label: "CosyVoice v3 Flash"}, {ID: "cosyvoice-v2", Label: "CosyVoice v2"}, } } func systemVoices() map[string][]voiceOption { v3 := []voiceOption{{ID: "longanhuan", Label: "龙安欢|欢脱元气女"}, {ID: "longanyang", Label: "龙安洋|阳光男声"}} return map[string][]voiceOption{ "cosyvoice-v3-plus": v3, "cosyvoice-v3-flash": v3, "cosyvoice-v2": { {ID: "longxiaochun_v2", Label: "龙小淳|温柔女声"}, {ID: "longwan_v2", Label: "龙婉|普通话女声"}, {ID: "loongbella_v2", Label: "Bella 2.0|新闻女声"}, }, } } func listClonedVoices(ctx context.Context, cfg agentCfg) ([]voiceOption, error) { body, _ := json.Marshal(map[string]any{ "model": "voice-enrollment", "input": map[string]any{"action": "list_voice", "page_index": 0, "page_size": 100}, }) req, err := http.NewRequestWithContext(ctx, http.MethodPost, cfg.VoiceAPIURL, bytes.NewReader(body)) if err != nil { return nil, err } req.Header.Set("Authorization", "Bearer "+cfg.BailianKey) req.Header.Set("Content-Type", "application/json") resp, err := http.DefaultClient.Do(req) if err != nil { return nil, err } defer resp.Body.Close() if resp.StatusCode/100 != 2 { return nil, fmt.Errorf("查询复刻音色失败: HTTP %d", resp.StatusCode) } var result struct { Output struct { Voices []struct { ID string `json:"voice_id"` Status string `json:"status"` } `json:"voice_list"` } `json:"output"` } if err := json.NewDecoder(resp.Body).Decode(&result); err != nil { return nil, err } voices := make([]voiceOption, 0, len(result.Output.Voices)) for _, v := range result.Output.Voices { if v.ID != "" && (v.Status == "" || v.Status == "OK" || v.Status == "SUCCESS") { voices = append(voices, voiceOption{ID: v.ID, Label: v.ID}) } } return voices, nil }