7eb5e984c2
- auth: Login 简化为管理员始终通过 .env 验证,GetProfile 修正 admin DB 查询 - devtools: .sh/.bat 同步重写为完整 CLI (start/stop/status/logs/build/db:*) - docs: 新增 devtools.md,重写 Deploy.md (三种方式+Windows说明),更新 README/gateway-api - voice-service: DashScope 实时流式 STT 支持 - gateway: Phase 6 多模型配置 + 多端客户端管理 + WebSocket 增强 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
111 lines
2.5 KiB
Go
111 lines
2.5 KiB
Go
package config
|
|
|
|
import (
|
|
"encoding/json"
|
|
"os"
|
|
"path/filepath"
|
|
)
|
|
|
|
// ModelsJSON 映射 models.json 文件结构(仅提取语音相关字段)。
|
|
type ModelsJSON struct {
|
|
Providers map[string]ModelsProvider `json:"providers"`
|
|
Models map[string]ModelsModel `json:"models"`
|
|
Routing map[string]ModelsRouting `json:"routing"`
|
|
}
|
|
|
|
type ModelsProvider struct {
|
|
Name string `json:"name"`
|
|
BaseURL string `json:"base_url"`
|
|
APIKey string `json:"api_key"`
|
|
}
|
|
|
|
type ModelsModel struct {
|
|
ID string `json:"id"`
|
|
Name string `json:"name"`
|
|
Provider string `json:"provider"`
|
|
}
|
|
|
|
type ModelsRouting struct {
|
|
Purpose string `json:"purpose"`
|
|
FallbackChain []string `json:"fallback_chain"`
|
|
}
|
|
|
|
// LoadModelsConfig 从 backend/models.json 加载模型配置。
|
|
// 返回 provider API key 和 ASR 模型名称。如果文件不存在则返回零值。
|
|
func LoadModelsConfig() (apiKey string, offlineModel string, realtimeModel string) {
|
|
// 尝试多个可能的路径
|
|
candidates := []string{
|
|
"models.json",
|
|
"../models.json",
|
|
"../../models.json",
|
|
filepath.Join("..", "models.json"),
|
|
}
|
|
|
|
var data []byte
|
|
var err error
|
|
for _, p := range candidates {
|
|
data, err = os.ReadFile(p)
|
|
if err == nil {
|
|
break
|
|
}
|
|
}
|
|
if data == nil {
|
|
return
|
|
}
|
|
|
|
var cfg ModelsJSON
|
|
if err := json.Unmarshal(data, &cfg); err != nil {
|
|
return
|
|
}
|
|
|
|
// 从 speech_recognition_offline 路由取离线模型
|
|
if r, ok := cfg.Routing["speech_recognition_offline"]; ok && len(r.FallbackChain) > 0 {
|
|
modelID := r.FallbackChain[0]
|
|
if m, ok := cfg.Models[modelID]; ok {
|
|
offlineModel = m.Name
|
|
if m.Name == "" {
|
|
offlineModel = m.ID
|
|
}
|
|
// 从 provider 取 API key
|
|
if p, ok := cfg.Providers[m.Provider]; ok && apiKey == "" {
|
|
apiKey = p.APIKey
|
|
}
|
|
}
|
|
}
|
|
|
|
// 从 speech_recognition 路由取实时模型
|
|
if r, ok := cfg.Routing["speech_recognition"]; ok && len(r.FallbackChain) > 0 {
|
|
modelID := r.FallbackChain[0]
|
|
if m, ok := cfg.Models[modelID]; ok {
|
|
realtimeModel = m.Name
|
|
if realtimeModel == "" {
|
|
realtimeModel = m.ID
|
|
}
|
|
// 从 provider 取 API key
|
|
if p, ok := cfg.Providers[m.Provider]; ok && apiKey == "" {
|
|
apiKey = p.APIKey
|
|
}
|
|
}
|
|
}
|
|
|
|
// 如果 routing 里没有,尝试从所有 models 中找带有 ASR tag 的模型
|
|
if offlineModel == "" {
|
|
for _, m := range cfg.Models {
|
|
if m.Provider == "dashscope" && m.Name != "" {
|
|
if offlineModel == "" {
|
|
offlineModel = m.Name
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// 从 provider 取 API key (兜底)
|
|
if apiKey == "" {
|
|
if p, ok := cfg.Providers["dashscope"]; ok {
|
|
apiKey = p.APIKey
|
|
}
|
|
}
|
|
|
|
return
|
|
}
|