feat: 添加本地缓存功能,减少API调用
- 实现SQLite缓存模块,支持高效查询和存储 - 添加缓存键生成策略(基于原文+语言对的SHA256哈希) - 集成缓存到Translator类,先查缓存再调用API - 添加缓存管理命令:cache clear, cache stats, cache cleanup - 实现组合缓存清理策略(数量限制+时间过期) - 添加完整的单元测试 - 更新配置文件模板,添加缓存配置 - 更新文档和版本记录 版本: v0.5.1
This commit is contained in:
@@ -5,6 +5,7 @@ import (
|
||||
"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"
|
||||
@@ -16,16 +17,32 @@ type Translator struct {
|
||||
provider provider.Provider
|
||||
prompt *PromptManager
|
||||
contentParser *content.Parser
|
||||
cache cache.Cache
|
||||
}
|
||||
|
||||
// NewTranslator 创建翻译器实例
|
||||
func NewTranslator(config *config.Config, provider provider.Provider) *Translator {
|
||||
return &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 执行翻译
|
||||
@@ -68,6 +85,26 @@ func (t *Translator) Translate(ctx context.Context, text string, options *Transl
|
||||
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 {
|
||||
@@ -81,6 +118,26 @@ func (t *Translator) Translate(ctx context.Context, text string, options *Transl
|
||||
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,
|
||||
|
||||
Reference in New Issue
Block a user