feat(voice): voiceconfig 工具——语音配置一键入库(联调/无头环境免开 admin)
等价于 admin「语音设置」保存一次:读 VOLC_* 环境变量→AES 加密(复用 gateway EncryptedForStore)→写 sundynix_setting。网关每请求现读,无需重启。凭证只走 env 不进 git。 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,66 @@
|
|||||||
|
// 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"),
|
||||||
|
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)
|
||||||
|
}
|
||||||
Executable
BIN
Binary file not shown.
Reference in New Issue
Block a user