feat: implement core architecture (v0.0.2)
- Implement Config class with YAML loading and environment variable support - Implement Provider interface and factory pattern - Implement SiliconFlow provider as example - Implement Translator core class with prompt management - Create CLI entry point - Add configuration template and unit tests - Update changelog and discussion records Version: 0.0.2
This commit is contained in:
131
internal/translator/prompt.go
Normal file
131
internal/translator/prompt.go
Normal file
@@ -0,0 +1,131 @@
|
||||
package translator
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// PromptManager Prompt管理器
|
||||
type PromptManager struct {
|
||||
prompts map[string]string
|
||||
}
|
||||
|
||||
// NewPromptManager 创建Prompt管理器
|
||||
func NewPromptManager(prompts map[string]string) *PromptManager {
|
||||
if prompts == nil {
|
||||
prompts = make(map[string]string)
|
||||
}
|
||||
return &PromptManager{
|
||||
prompts: prompts,
|
||||
}
|
||||
}
|
||||
|
||||
// GetPrompt 获取指定名称的Prompt
|
||||
func (pm *PromptManager) GetPrompt(name string) string {
|
||||
prompt, exists := pm.prompts[name]
|
||||
if !exists {
|
||||
return ""
|
||||
}
|
||||
return prompt
|
||||
}
|
||||
|
||||
// SetPrompt 设置Prompt
|
||||
func (pm *PromptManager) SetPrompt(name, content string) {
|
||||
pm.prompts[name] = content
|
||||
}
|
||||
|
||||
// DeletePrompt 删除Prompt
|
||||
func (pm *PromptManager) DeletePrompt(name string) {
|
||||
delete(pm.prompts, name)
|
||||
}
|
||||
|
||||
// HasPrompt 检查Prompt是否存在
|
||||
func (pm *PromptManager) HasPrompt(name string) bool {
|
||||
_, exists := pm.prompts[name]
|
||||
return exists
|
||||
}
|
||||
|
||||
// GetAllPrompts 获取所有Prompt名称
|
||||
func (pm *PromptManager) GetAllPrompts() []string {
|
||||
names := make([]string, 0, len(pm.prompts))
|
||||
for name := range pm.prompts {
|
||||
names = append(names, name)
|
||||
}
|
||||
return names
|
||||
}
|
||||
|
||||
// GetPromptCount 获取Prompt数量
|
||||
func (pm *PromptManager) GetPromptCount() int {
|
||||
return len(pm.prompts)
|
||||
}
|
||||
|
||||
// FormatPrompt 格式化Prompt,替换变量
|
||||
func (pm *PromptManager) FormatPrompt(name string, vars map[string]string) string {
|
||||
prompt := pm.GetPrompt(name)
|
||||
if prompt == "" {
|
||||
return ""
|
||||
}
|
||||
|
||||
// 替换变量
|
||||
for key, value := range vars {
|
||||
placeholder := fmt.Sprintf("{{%s}}", key)
|
||||
prompt = strings.ReplaceAll(prompt, placeholder, value)
|
||||
}
|
||||
|
||||
return prompt
|
||||
}
|
||||
|
||||
// ValidatePrompt 验证Prompt是否包含必要变量
|
||||
func (pm *PromptManager) ValidatePrompt(name string, requiredVars []string) error {
|
||||
prompt := pm.GetPrompt(name)
|
||||
if prompt == "" {
|
||||
return fmt.Errorf("prompt '%s' 不存在", name)
|
||||
}
|
||||
|
||||
for _, varName := range requiredVars {
|
||||
placeholder := fmt.Sprintf("{{%s}}", varName)
|
||||
if !strings.Contains(prompt, placeholder) {
|
||||
return fmt.Errorf("prompt '%s' 缺少必要变量: %s", name, varName)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// AddDefaultPrompts 添加默认Prompts
|
||||
func (pm *PromptManager) AddDefaultPrompts() {
|
||||
defaults := map[string]string{
|
||||
"technical": "你是一位专业的技术翻译,请准确翻译以下技术文档,保持专业术语的准确性。",
|
||||
"creative": "你是一位富有创造力的翻译家,请用优美流畅的语言翻译以下内容。",
|
||||
"academic": "你是一位学术翻译专家,请用严谨的学术语言翻译以下内容。",
|
||||
"simple": "请用简单易懂的语言翻译以下内容。",
|
||||
"code": "你是一位专业的代码翻译专家,请准确翻译以下代码注释和文档,保持代码结构和注释格式。",
|
||||
}
|
||||
|
||||
for name, content := range defaults {
|
||||
if !pm.HasPrompt(name) {
|
||||
pm.SetPrompt(name, content)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// GetPromptWithFallback 获取Prompt,如果不存在则返回默认Prompt
|
||||
func (pm *PromptManager) GetPromptWithFallback(name, fallback string) string {
|
||||
prompt := pm.GetPrompt(name)
|
||||
if prompt == "" {
|
||||
return fallback
|
||||
}
|
||||
return prompt
|
||||
}
|
||||
|
||||
// MergePrompts 合并多个Prompt
|
||||
func (pm *PromptManager) MergePrompts(names []string, separator string) string {
|
||||
var prompts []string
|
||||
for _, name := range names {
|
||||
prompt := pm.GetPrompt(name)
|
||||
if prompt != "" {
|
||||
prompts = append(prompts, prompt)
|
||||
}
|
||||
}
|
||||
return strings.Join(prompts, separator)
|
||||
}
|
||||
177
internal/translator/translator.go
Normal file
177
internal/translator/translator.go
Normal file
@@ -0,0 +1,177 @@
|
||||
package translator
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/titor/fanyi/internal/config"
|
||||
"github.com/titor/fanyi/internal/provider"
|
||||
)
|
||||
|
||||
// Translator 核心翻译类
|
||||
type Translator struct {
|
||||
config *config.Config
|
||||
provider provider.Provider
|
||||
prompt *PromptManager
|
||||
}
|
||||
|
||||
// NewTranslator 创建翻译器实例
|
||||
func NewTranslator(config *config.Config, provider provider.Provider) *Translator {
|
||||
return &Translator{
|
||||
config: config,
|
||||
provider: provider,
|
||||
prompt: NewPromptManager(config.Prompts),
|
||||
}
|
||||
}
|
||||
|
||||
// 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()
|
||||
|
||||
// 选择Prompt
|
||||
prompt := ""
|
||||
if options.PromptName != "" {
|
||||
prompt = t.prompt.GetPrompt(options.PromptName)
|
||||
}
|
||||
|
||||
// 构建请求
|
||||
req := &provider.TranslateRequest{
|
||||
Text: text,
|
||||
FromLang: options.FromLang,
|
||||
ToLang: options.ToLang,
|
||||
Prompt: prompt,
|
||||
Model: t.selectModel(options.Model),
|
||||
Options: options.ExtraOptions,
|
||||
}
|
||||
|
||||
// 调用厂商API
|
||||
resp, err := t.provider.Translate(timeoutCtx, req)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("翻译失败: %w", err)
|
||||
}
|
||||
|
||||
// 构建结果
|
||||
return &TranslateResult{
|
||||
Original: text,
|
||||
Translated: resp.Text,
|
||||
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
|
||||
}
|
||||
Reference in New Issue
Block a user