package config import ( "fmt" "html" "regexp" "strings" "sync" "github.com/spf13/viper" ) // Config 包含应用程序的所有配置 type Config struct { Server ServerConfig `mapstructure:"server"` TTS TTSConfig `mapstructure:"tts"` OpenAI OpenAIConfig `mapstructure:"openai"` SSML SSMLConfig `mapstructure:"ssml"` } // OpenAIConfig 包含OpenAI API配置 type OpenAIConfig struct { ApiKey string `mapstructure:"api_key"` } // ServerConfig 包含HTTP服务器配置 type ServerConfig struct { Port int `mapstructure:"port"` ReadTimeout int `mapstructure:"read_timeout"` WriteTimeout int `mapstructure:"write_timeout"` BasePath string `mapstructure:"base_path"` } // TTSConfig 包含Microsoft TTS API配置 type TTSConfig struct { ApiKey string `mapstructure:"api_key"` Region string `mapstructure:"region"` DefaultVoice string `mapstructure:"default_voice"` DefaultRate string `mapstructure:"default_rate"` DefaultPitch string `mapstructure:"default_pitch"` DefaultFormat string `mapstructure:"default_format"` MaxTextLength int `mapstructure:"max_text_length"` RequestTimeout int `mapstructure:"request_timeout"` MaxConcurrent int `mapstructure:"max_concurrent"` SegmentThreshold int `mapstructure:"segment_threshold"` MinSentenceLength int `mapstructure:"min_sentence_length"` MaxSentenceLength int `mapstructure:"max_sentence_length"` VoiceMapping map[string]string `mapstructure:"voice_mapping"` } var ( config Config once sync.Once ) // Load 从指定路径加载配置文件 func Load(configPath string) (*Config, error) { var err error once.Do(func() { v := viper.New() // 配置 Viper v.SetConfigName("config") v.SetConfigType("yaml") v.SetEnvKeyReplacer(strings.NewReplacer(".", "_")) v.AutomaticEnv() // 自动绑定环境变量 // 从配置文件加载 if configPath != "" { v.SetConfigFile(configPath) if err = v.ReadInConfig(); err != nil { err = fmt.Errorf("加载配置文件失败: %w", err) return } } // 将配置绑定到结构体 if err = v.Unmarshal(&config); err != nil { err = fmt.Errorf("解析配置失败: %w", err) return } }) if err != nil { return nil, err } return &config, nil } // Get 返回已加载的配置 func Get() *Config { return &config } // TagPattern 定义标签模式及其名称 type TagPattern struct { Name string `mapstructure:"name"` // 标签名称,用于日志和调试 Pattern string `mapstructure:"pattern"` // 标签的正则表达式模式 } // SSMLConfig 存储SSML标签配置 type SSMLConfig struct { // PreserveTags 包含所有需要保留的标签的正则表达式模式 PreserveTags []TagPattern `mapstructure:"preserve_tags"` } // SSMLProcessor 处理SSML内容 type SSMLProcessor struct { config *SSMLConfig patternCache map[string]*regexp.Regexp } // NewSSMLProcessor 从配置对象创建SSMLProcessor func NewSSMLProcessor(config *SSMLConfig) (*SSMLProcessor, error) { processor := &SSMLProcessor{ config: config, patternCache: make(map[string]*regexp.Regexp), } // 预编译正则表达式 for _, tagPattern := range config.PreserveTags { regex, err := regexp.Compile(tagPattern.Pattern) if err != nil { return nil, fmt.Errorf("编译正则表达式'%s'失败: %w", tagPattern.Name, err) } processor.patternCache[tagPattern.Name] = regex } return processor, nil } // EscapeSSML 转义SSML内容,但保留配置的标签 func (p *SSMLProcessor) EscapeSSML(ssml string) string { // 使用占位符替换标签 placeholders := make(map[string]string) processedSSML := ssml counter := 0 // 处理所有配置的标签 for name, pattern := range p.patternCache { processedSSML = pattern.ReplaceAllStringFunc(processedSSML, func(match string) string { placeholder := fmt.Sprintf("__SSML_PLACEHOLDER_%s_%d__", name, counter) placeholders[placeholder] = match counter++ return placeholder }) } // 对处理后的文本进行HTML转义 escapedContent := html.EscapeString(processedSSML) // 恢复所有标签占位符 for placeholder, tag := range placeholders { escapedContent = strings.Replace(escapedContent, placeholder, tag, 1) } return escapedContent }