161 lines
4.4 KiB
Go
161 lines
4.4 KiB
Go
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
|
||
}
|