Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 9 additions & 22 deletions server/internal/http_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -72,9 +72,6 @@ const (
languageChinese = "zh-CN"
languageEnglish = "en-US"

ManifestJsonFile = "./agents/manifest.json"
ManifestJsonFileElevenlabs = "./agents/manifest.elevenlabs.json"

TTSVendorAzure = "azure"
TTSVendorElevenlabs = "elevenlabs"

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
}

Expand Down Expand Up @@ -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 {
Expand Down
125 changes: 125 additions & 0 deletions server/internal/manifest.go
Original file line number Diff line number Diff line change
@@ -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
}
74 changes: 8 additions & 66 deletions server/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@ import (
"os"
"strconv"

"github.com/tidwall/sjson"

"app/internal"
)

Expand All @@ -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")
Expand All @@ -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()
}