Files
Microsoft-tts/internal/config/config.go

161 lines
4.4 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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
}