// voiceconfig 把火山语音配置写入数据库(等价于 admin「语音设置」页保存一次)。 // 供本地联调 / 无头环境快速配好语音,免开 admin 控制台。API Key 只走环境变量、加密入库, // 绝不进代码/git;写库前复用 gateway 同一套 AES 加密(voice.Config.EncryptedForStore)。 // // 用法: // // export POSTGRES_DSN="postgres://sundynix:sundynix@localhost:5432/sundynix?sslmode=disable" // export VOLC_API_KEY=<你的APIKey> // export VOLC_ASR_RESOURCE_ID=volc.seedasr.sauc.duration // export VOLC_TTS_RESOURCE_ID=seed-tts-2.0 // export VOLC_TTS_VOICE=zh_male_m191_uranus_bigtts // # SUNDYNIX_SECRET_KEY 须与 gateway 一致(都不设=同用开发默认) // go run ./cmd/voiceconfig package main import ( "context" "encoding/json" "fmt" "os" "github.com/sundynix/sundynix-gateway/internal/store" "github.com/sundynix/sundynix-gateway/internal/voice" ) const settingVoice = "voice_config" // 与 handler.SettingVoice 对齐 func main() { dsn := os.Getenv("POSTGRES_DSN") if dsn == "" { fatal("缺 POSTGRES_DSN") } cfg := voice.Config{ APIKey: os.Getenv("VOLC_API_KEY"), AppID: os.Getenv("VOLC_APP_ID"), ASRResourceID: os.Getenv("VOLC_ASR_RESOURCE_ID"), TTSResourceID: os.Getenv("VOLC_TTS_RESOURCE_ID"), TTSVoiceType: os.Getenv("VOLC_TTS_VOICE"), } if cfg.APIKey == "" { fatal("缺 VOLC_API_KEY") } db := store.OpenPostgres(dsn) if !db.Enabled() { fatal("连不上数据库(检查 POSTGRES_DSN / 容器是否起)") } stored, err := cfg.EncryptedForStore() // AES-256-GCM 加密 APIKey(同 gateway) if err != nil { fatal("加密失败:" + err.Error()) } raw, _ := json.Marshal(stored) if err := db.SetSetting(context.Background(), settingVoice, string(raw)); err != nil { fatal("写库失败:" + err.Error()) } fmt.Printf("✅ 语音配置已入库(%s)\n", settingVoice) fmt.Printf(" ASR resource=%q 可用=%v\n", cfg.ASRResourceID, cfg.ASREnabled()) fmt.Printf(" TTS resource=%q 音色=%q 可用=%v\n", cfg.TTSResourceID, cfg.TTSVoiceType, cfg.TTSEnabled()) fmt.Println(" 网关每次请求现读,无需重启;刷新桌面端点麦克风即可。") } func fatal(msg string) { fmt.Fprintln(os.Stderr, "❌ "+msg) os.Exit(1) }