diff --git a/server/internal/http_server.go b/server/internal/http_server.go index cf49a94f0f..d602b92949 100644 --- a/server/internal/http_server.go +++ b/server/internal/http_server.go @@ -27,13 +27,13 @@ import ( ) type HttpServer struct { - config *HttpServerConfig + config *HttpServerConfig + manifestProvider *ManifestProvider } type HttpServerConfig struct { AppId string AppCertificate string - ManifestJsonFile string Port string TTSVendorChinese string TTSVendorEnglish string @@ -72,9 +72,6 @@ const ( languageChinese = "zh-CN" languageEnglish = "en-US" - ManifestJsonFile = "./agents/manifest.json" - ManifestJsonFileElevenlabs = "./agents/manifest.elevenlabs.json" - TTSVendorAzure = "azure" TTSVendorElevenlabs = "elevenlabs" @@ -109,23 +106,13 @@ var ( logTag = slog.String("service", "HTTP_SERVER") ) -func NewHttpServer(httpServerConfig *HttpServerConfig) *HttpServer { +func NewHttpServer(httpServerConfig *HttpServerConfig, manifestProvider *ManifestProvider) *HttpServer { return &HttpServer{ - config: httpServerConfig, + config: httpServerConfig, + manifestProvider: manifestProvider, } } -func (s *HttpServer) getManifestJsonFile(language string) (manifestJsonFile string) { - ttsVendor := s.getTtsVendor(language) - manifestJsonFile = ManifestJsonFile - - if ttsVendor == TTSVendorElevenlabs { - manifestJsonFile = ManifestJsonFileElevenlabs - } - - return -} - func (s *HttpServer) getTtsVendor(language string) string { if language == languageChinese { return s.config.TTSVendorChinese @@ -295,11 +282,12 @@ func (s *HttpServer) output(c *gin.Context, code *Code, data any, httpStatus ... c.JSON(httpStatus[0], gin.H{"code": code.code, "msg": code.msg, "data": data}) } +// processManifest create worker temporary Mainfest. func (s *HttpServer) processManifest(req *StartReq) (manifestJsonFile string, logFile string, err error) { - manifestJsonFile = s.getManifestJsonFile(req.AgoraAsrLanguage) - content, err := os.ReadFile(manifestJsonFile) + ttsVendor := s.getTtsVendor(req.AgoraAsrLanguage) + content, err := s.manifestProvider.GetManifestJson(ttsVendor) if err != nil { - slog.Error("handlerStart read manifest.json failed", "err", err, "manifestJsonFile", manifestJsonFile, "requestId", req.RequestId, logTag) + slog.Error("handlerStart get manifest json failed", "err", err, "ttsVendor", ttsVendor, "requestId", req.RequestId, logTag) return } @@ -333,7 +321,6 @@ func (s *HttpServer) processManifest(req *StartReq) (manifestJsonFile string, lo language := gjson.Get(manifestJson, `predefined_graphs.0.nodes.#(name=="agora_rtc").property.agora_asr_language`).String() - ttsVendor := s.getTtsVendor(language) voiceName := voiceNameMap[language][ttsVendor][req.VoiceType] if voiceName != "" { if ttsVendor == TTSVendorAzure { diff --git a/server/internal/manifest.go b/server/internal/manifest.go new file mode 100644 index 0000000000..cc4e947515 --- /dev/null +++ b/server/internal/manifest.go @@ -0,0 +1,125 @@ +package internal + +import ( + "fmt" + "log/slog" + "os" + "path/filepath" + "regexp" + + "github.com/tidwall/sjson" +) + +type ManifestProvider struct { + // manifestJsons + // key: fileName string `manifest.json` `manifest.elevenlabs.json` + // value: manifestJson string + manifestJsons map[string]string +} + +func NewManifestProvider() *ManifestProvider { + return &ManifestProvider{ + manifestJsons: make(map[string]string), + } +} + +// LoadManifest read manifest from dir. +func (p *ManifestProvider) LoadManifest(manifestJsonDir string) error { + files, err := os.ReadDir(manifestJsonDir) + if err != nil { + slog.Error("read manifestJsonDir failed", "err", err, "manifestJsonDir", manifestJsonDir) + return err + } + + matcher := regexp.MustCompile(`^manifest(\..+)?\.json$`) // `manifest.json` or `manifest.elevenlabs.json` + for _, file := range files { + if file.IsDir() { + continue + } + if !matcher.MatchString(file.Name()) { + continue + } + + manifestJsonFile := filepath.Join(manifestJsonDir, file.Name()) + content, err := os.ReadFile(manifestJsonFile) + if err != nil { + slog.Error("read manifest json failed", "err", err, "manifestJsonFile", manifestJsonFile) + return err + } + + manifestJson := string(content) + manifestJson = p.injectEnvVar(manifestJson) + + p.manifestJsons[file.Name()] = manifestJson + } + + return nil +} + +// injectEnvVar inject Environment Variable to json content. +func (p *ManifestProvider) injectEnvVar(manifestJson string) string { + appId := os.Getenv("AGORA_APP_ID") + if appId != "" { + manifestJson, _ = sjson.Set(manifestJson, `predefined_graphs.0.nodes.#(name=="agora_rtc").property.app_id`, appId) + } + + azureSttKey := os.Getenv("AZURE_STT_KEY") + if azureSttKey != "" { + manifestJson, _ = sjson.Set(manifestJson, `predefined_graphs.0.nodes.#(name=="agora_rtc").property.agora_asr_vendor_key`, azureSttKey) + } + + azureSttRegion := os.Getenv("AZURE_STT_REGION") + if azureSttRegion != "" { + manifestJson, _ = sjson.Set(manifestJson, `predefined_graphs.0.nodes.#(name=="agora_rtc").property.agora_asr_vendor_region`, azureSttRegion) + } + + openaiBaseUrl := os.Getenv("OPENAI_BASE_URL") + if openaiBaseUrl != "" { + manifestJson, _ = sjson.Set(manifestJson, `predefined_graphs.0.nodes.#(name=="openai_chatgpt").property.base_url`, openaiBaseUrl) + } + + openaiApiKey := os.Getenv("OPENAI_API_KEY") + if openaiApiKey != "" { + manifestJson, _ = sjson.Set(manifestJson, `predefined_graphs.0.nodes.#(name=="openai_chatgpt").property.api_key`, openaiApiKey) + } + + openaiModel := os.Getenv("OPENAI_MODEL") + if openaiModel != "" { + manifestJson, _ = sjson.Set(manifestJson, `predefined_graphs.0.nodes.#(name=="openai_chatgpt").property.model`, openaiModel) + } + + proxyUrl := os.Getenv("PROXY_URL") + if proxyUrl != "" { + manifestJson, _ = sjson.Set(manifestJson, `predefined_graphs.0.nodes.#(name=="openai_chatgpt").property.proxy_url`, proxyUrl) + } + + azureTtsKey := os.Getenv("AZURE_TTS_KEY") + if azureTtsKey != "" { + manifestJson, _ = sjson.Set(manifestJson, `predefined_graphs.0.nodes.#(name=="azure_tts").property.azure_subscription_key`, azureTtsKey) + } + + azureTtsRegion := os.Getenv("AZURE_TTS_REGION") + if azureTtsRegion != "" { + manifestJson, _ = sjson.Set(manifestJson, `predefined_graphs.0.nodes.#(name=="azure_tts").property.azure_subscription_region`, azureTtsRegion) + } + + elevenlabsTtsKey := os.Getenv("ELEVENLABS_TTS_KEY") + if elevenlabsTtsKey != "" { + manifestJson, _ = sjson.Set(manifestJson, `predefined_graphs.0.nodes.#(name=="elevenlabs_tts").property.api_key`, elevenlabsTtsKey) + } + + return manifestJson +} + +// GetManifestJson give a vendor, return manifestJson. +func (p *ManifestProvider) GetManifestJson(vendor string) (manifestJson string, err error) { + if len(vendor) > 0 { + vendor = "." + vendor + } + manifestJson, ok := p.manifestJsons["manifest"+vendor+".json"] // `manifest.json` or `manifest.elevenlabs.json` + if !ok { + return "", fmt.Errorf("unknow manifest vendor: %s", vendor) + } + + return manifestJson, nil +} diff --git a/server/main.go b/server/main.go index d190387bc2..deff044cb5 100644 --- a/server/main.go +++ b/server/main.go @@ -6,8 +6,6 @@ import ( "os" "strconv" - "github.com/tidwall/sjson" - "app/internal" ) @@ -34,9 +32,12 @@ func main() { workerQuitTimeoutSeconds = 60 } + var manifestJsonDir string + flag.StringVar(&httpServerConfig.AppId, "appId", os.Getenv("AGORA_APP_ID"), "agora appid") flag.StringVar(&httpServerConfig.AppCertificate, "appCertificate", os.Getenv("AGORA_APP_CERTIFICATE"), "agora certificate") flag.StringVar(&httpServerConfig.Port, "port", ":8080", "http server port") + flag.StringVar(&manifestJsonDir, "manifestJsonDir", "./agents/", "manifest json dir") flag.StringVar(&httpServerConfig.TTSVendorChinese, "ttsVendorChinese", ttsVendorChinese, "tts vendor for chinese") flag.StringVar(&httpServerConfig.TTSVendorEnglish, "ttsVendorEnglish", ttsVendorEnglish, "tts vendor for english") flag.IntVar(&httpServerConfig.WorkersMax, "workersMax", workersMax, "workers max") @@ -46,71 +47,12 @@ func main() { slog.Info("server config", "ttsVendorChinese", httpServerConfig.TTSVendorChinese, "ttsVendorEnglish", httpServerConfig.TTSVendorEnglish, "workersMax", httpServerConfig.WorkersMax, "workerQuitTimeoutSeconds", httpServerConfig.WorkerQuitTimeoutSeconds) - processManifest(internal.ManifestJsonFile) - processManifest(internal.ManifestJsonFileElevenlabs) - httpServer := internal.NewHttpServer(httpServerConfig) - httpServer.Start() -} - -func processManifest(manifestJsonFile string) (err error) { - content, err := os.ReadFile(manifestJsonFile) + manifestProvider := internal.NewManifestProvider() + err = manifestProvider.LoadManifest(manifestJsonDir) if err != nil { - slog.Error("read manifest.json failed", "err", err, "manifestJsonFile", manifestJsonFile) - return - } - - manifestJson := string(content) - - appId := os.Getenv("AGORA_APP_ID") - if appId != "" { - manifestJson, _ = sjson.Set(manifestJson, `predefined_graphs.0.nodes.#(name=="agora_rtc").property.app_id`, appId) - } - - azureSttKey := os.Getenv("AZURE_STT_KEY") - if azureSttKey != "" { - manifestJson, _ = sjson.Set(manifestJson, `predefined_graphs.0.nodes.#(name=="agora_rtc").property.agora_asr_vendor_key`, azureSttKey) - } - - azureSttRegion := os.Getenv("AZURE_STT_REGION") - if azureSttRegion != "" { - manifestJson, _ = sjson.Set(manifestJson, `predefined_graphs.0.nodes.#(name=="agora_rtc").property.agora_asr_vendor_region`, azureSttRegion) - } - - openaiBaseUrl := os.Getenv("OPENAI_BASE_URL") - if openaiBaseUrl != "" { - manifestJson, _ = sjson.Set(manifestJson, `predefined_graphs.0.nodes.#(name=="openai_chatgpt").property.base_url`, openaiBaseUrl) + panic(err) } - openaiApiKey := os.Getenv("OPENAI_API_KEY") - if openaiApiKey != "" { - manifestJson, _ = sjson.Set(manifestJson, `predefined_graphs.0.nodes.#(name=="openai_chatgpt").property.api_key`, openaiApiKey) - } - - openaiModel := os.Getenv("OPENAI_MODEL") - if openaiModel != "" { - manifestJson, _ = sjson.Set(manifestJson, `predefined_graphs.0.nodes.#(name=="openai_chatgpt").property.model`, openaiModel) - } - - proxyUrl := os.Getenv("PROXY_URL") - if proxyUrl != "" { - manifestJson, _ = sjson.Set(manifestJson, `predefined_graphs.0.nodes.#(name=="openai_chatgpt").property.proxy_url`, proxyUrl) - } - - azureTtsKey := os.Getenv("AZURE_TTS_KEY") - if azureTtsKey != "" { - manifestJson, _ = sjson.Set(manifestJson, `predefined_graphs.0.nodes.#(name=="azure_tts").property.azure_subscription_key`, azureTtsKey) - } - - azureTtsRegion := os.Getenv("AZURE_TTS_REGION") - if azureTtsRegion != "" { - manifestJson, _ = sjson.Set(manifestJson, `predefined_graphs.0.nodes.#(name=="azure_tts").property.azure_subscription_region`, azureTtsRegion) - } - - elevenlabsTtsKey := os.Getenv("ELEVENLABS_TTS_KEY") - if elevenlabsTtsKey != "" { - manifestJson, _ = sjson.Set(manifestJson, `predefined_graphs.0.nodes.#(name=="elevenlabs_tts").property.api_key`, elevenlabsTtsKey) - } - - err = os.WriteFile(manifestJsonFile, []byte(manifestJson), 0644) - return + httpServer := internal.NewHttpServer(httpServerConfig, manifestProvider) + httpServer.Start() }