package translator import ( "context" "fmt" "time" "github.com/titor/fanyi/internal/cache" "github.com/titor/fanyi/internal/config" "github.com/titor/fanyi/internal/content" "github.com/titor/fanyi/internal/provider" ) // Translator 核心翻译类 type Translator struct { config *config.Config provider provider.Provider prompt *PromptManager contentParser *content.Parser cache cache.Cache } // NewTranslator 创建翻译器实例 func NewTranslator(config *config.Config, provider provider.Provider) *Translator { translator := &Translator{ config: config, provider: provider, prompt: NewPromptManager(config.Prompts), contentParser: content.NewParser(config.SkipKeywords), } // 初始化缓存(如果启用) if config.Cache.Enabled { cacheConfig := &cache.CacheConfig{ Enabled: config.Cache.Enabled, MaxRecords: config.Cache.MaxRecords, ExpireDays: config.Cache.ExpireDays, DBPath: config.Cache.DBPath, } if cacheInstance, err := cache.NewSQLiteCache(cacheConfig); err == nil { translator.cache = cacheInstance } } return translator } // Translate 执行翻译 func (t *Translator) Translate(ctx context.Context, text string, options *TranslateOptions) (*TranslateResult, error) { // 设置超时 timeoutCtx, cancel := context.WithTimeout(ctx, time.Duration(t.config.Timeout)*time.Second) defer cancel() // 基础字符过滤 filteredText := content.FilterBasic(text, nil) // 内容解析(包含代码检测) parseResult, parseErr := t.contentParser.Parse(filteredText) // 选择Prompt prompt := "" if options.PromptName != "" { prompt = t.prompt.GetPrompt(options.PromptName) } // 如果包含代码且解析成功,使用增强的Prompt if parseErr == nil && parseResult.HasCode { enhancedPrompt := t.contentParser.BuildPrompt(parseResult) if enhancedPrompt != "" { if prompt != "" { prompt = prompt + "\n\n" + enhancedPrompt } else { prompt = enhancedPrompt } } } // 构建请求 req := &provider.TranslateRequest{ Text: filteredText, FromLang: options.FromLang, ToLang: options.ToLang, Prompt: prompt, Model: t.selectModel(options.Model), Options: options.ExtraOptions, } // 检查缓存 if t.cache != nil { cacheKey := cache.GenerateCacheKey(filteredText, options.FromLang, options.ToLang) if cachedEntry, err := t.cache.Get(ctx, cacheKey); err == nil && cachedEntry != nil { // 缓存命中 return &TranslateResult{ Original: text, Translated: cachedEntry.TranslatedText, FromLang: cachedEntry.FromLang, ToLang: cachedEntry.ToLang, Model: cachedEntry.Model, Usage: &provider.Usage{ PromptTokens: cachedEntry.PromptTokens, CompletionTokens: cachedEntry.CompletionTokens, TotalTokens: cachedEntry.TotalTokens, }, }, nil } } // 调用厂商API resp, err := t.provider.Translate(timeoutCtx, req) if err != nil { return nil, fmt.Errorf("翻译失败: %w", err) } translatedText := resp.Text // 如果包含代码且解析成功,重构结果 if parseErr == nil && parseResult.HasCode { translatedText = t.contentParser.Reconstruct(parseResult, resp.Text) } // 保存到缓存 if t.cache != nil { cacheKey := cache.GenerateCacheKey(filteredText, options.FromLang, options.ToLang) cacheEntry := &cache.CacheEntry{ CacheKey: cacheKey, OriginalText: filteredText, TranslatedText: translatedText, FromLang: resp.FromLang, ToLang: resp.ToLang, Model: resp.Model, PromptName: options.PromptName, PromptContent: prompt, PromptTokens: resp.Usage.PromptTokens, CompletionTokens: resp.Usage.CompletionTokens, TotalTokens: resp.Usage.TotalTokens, } // 异步保存缓存,不阻塞翻译结果返回 go t.cache.Set(context.Background(), cacheEntry) } // 构建结果 return &TranslateResult{ Original: text, Translated: translatedText, FromLang: resp.FromLang, ToLang: resp.ToLang, Model: resp.Model, Usage: resp.Usage, }, nil } // TranslateWithProvider 使用指定厂商执行翻译 func (t *Translator) TranslateWithProvider(ctx context.Context, text string, providerName string, options *TranslateOptions) (*TranslateResult, error) { // 创建指定厂商实例 providerConfig, err := t.config.GetProviderConfig(providerName) if err != nil { return nil, fmt.Errorf("获取厂商配置失败: %w", err) } // 创建厂商实例 providerInstance, err := provider.CreateProvider(providerName, provider.ProviderConfig{ APIHost: providerConfig.APIHost, APIKey: providerConfig.APIKey, Model: providerConfig.Model, }) if err != nil { return nil, fmt.Errorf("创建厂商实例失败: %w", err) } // 临时切换厂商 originalProvider := t.provider t.provider = providerInstance defer func() { t.provider = originalProvider }() // 执行翻译 return t.Translate(ctx, text, options) } // selectModel 选择模型 func (t *Translator) selectModel(model string) string { if model != "" { return model } return t.config.DefaultModel } // GetProvider 获取当前厂商 func (t *Translator) GetProvider() provider.Provider { return t.provider } // GetConfig 获取配置 func (t *Translator) GetConfig() *config.Config { return t.config } // GetPromptManager 获取Prompt管理器 func (t *Translator) GetPromptManager() *PromptManager { return t.prompt } // SetTimeout 设置超时时间 func (t *Translator) SetTimeout(seconds int) { t.config.Timeout = seconds } // TranslateOptions 翻译选项 type TranslateOptions struct { FromLang string ToLang string PromptName string Model string Temperature float64 ExtraOptions map[string]interface{} } // TranslateResult 翻译结果 type TranslateResult struct { Original string Translated string FromLang string ToLang string Model string Usage *provider.Usage } // String 返回翻译结果的字符串表示 func (r *TranslateResult) String() string { return r.Translated } // TranslateResultWithInfo 带详细信息的翻译结果 type TranslateResultWithInfo struct { Result *TranslateResult Duration time.Duration Provider string Timestamp time.Time } // BatchTranslate 批量翻译结果 type BatchTranslateRequest struct { Texts []string Options *TranslateOptions } // BatchTranslateResult 批量翻译结果 type BatchTranslateResult struct { Results []*TranslateResult Errors []error Summary BatchTranslateSummary } // BatchTranslateSummary 批量翻译摘要 type BatchTranslateSummary struct { Total int Success int Failed int Duration time.Duration AvgTokens int }