initial: project structure and documentation setup

- Create project directory structure
- Initialize Go module
- Set up development documentation (why.md, taolun.md, changelog.md, memory.md, AGENTS.md)
- Configure YAML config template
- Set up .gitignore and .env.example
- Design OOP architecture with factory and strategy patterns

Version: 0.0.1
This commit is contained in:
2026-03-28 23:19:13 +08:00
commit 8a200e2bcd
9 changed files with 1235 additions and 0 deletions

13
.env.example Normal file
View File

@@ -0,0 +1,13 @@
# YOYO翻译工具环境变量配置
# 复制此文件为.env并填入您的API密钥
# 大模型API配置
SILICONFLOW_API_KEY=your_siliconflow_api_key
VOLCANO_API_KEY=your_volcano_api_key
NATIONAL_API_KEY=your_national_api_key
QWEN_API_KEY=your_qwen_api_key
OPENAI_API_KEY=your_openai_api_key
# 应用配置(可选)
YOYO_DEFAULT_PROVIDER=siliconflow
YOYO_TIMEOUT=30

37
.gitignore vendored Normal file
View File

@@ -0,0 +1,37 @@
# 二进制文件
yoyo
*.exe
*.exe~
*.dll
*.so
*.dylib
# 测试
*.test
*.out
coverage.txt
# 配置文件(敏感信息)
.env
config.local.yaml
# IDE
.idea/
.vscode/
*.swp
*.swo
# 依赖
vendor/
# 构建输出
dist/
build/
# Go工作区
go.work
go.work.sum
# 本地配置文件
configs/local.yaml
configs/*.local.yaml

767
AGENTS.md Normal file
View File

@@ -0,0 +1,767 @@
# AGENTS.md - YOYO翻译工具开发指南
## 项目概述
YOYO是一个命令行翻译工具使用Go语言编写采用面向对象设计模式。它通过调用在线大模型API结合不同的Prompt配置实现多样化的翻译特色。
## OOP设计模式
### 核心类设计
项目采用以下面向对象设计,结合工厂模式和策略模式:
```
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ Config │ │ Provider │ │ Translator │
│ (全局配置) │──────│ (厂商接口) │──────│ (核心翻译) │
└─────────────────┘ └─────────────────┘ └─────────────────┘
│ │ │
│ │ │
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ ConfigLoader │ │ ProviderFactory │ │ TranslationTask │
│ (配置加载) │ │ (工厂模式) │ │ (任务管理) │
└─────────────────┘ └─────────────────┘ └─────────────────┘
```
### 1. 全局配置类 (Config)
负责读取YAML配置文件提供默认值。
```go
// internal/config/config.go
package config
import (
"os"
"path/filepath"
"gopkg.in/yaml.v3"
)
// Config 全局配置结构
type Config struct {
// 全局设置
DefaultProvider string `yaml:"default_provider"`
DefaultModel string `yaml:"default_model"`
Timeout int `yaml:"timeout"` // 秒
// 厂商配置
Providers map[string]ProviderConfig `yaml:"providers"`
// Prompt配置
Prompts map[string]string `yaml:"prompts"`
}
// ProviderConfig 厂商配置
type ProviderConfig struct {
APIHost string `yaml:"api_host"`
APIKey string `yaml:"api_key"`
Model string `yaml:"model"`
Enabled bool `yaml:"enabled"`
}
// ConfigLoader 配置加载器接口
type ConfigLoader interface {
Load(path string) (*Config, error)
Save(config *Config, path string) error
}
// YAMLConfigLoader YAML配置加载器实现
type YAMLConfigLoader struct{}
// Load 加载YAML配置文件
func (l *YAMLConfigLoader) Load(path string) (*Config, error) {
data, err := os.ReadFile(path)
if err != nil {
return nil, fmt.Errorf("读取配置文件失败: %w", err)
}
config := &Config{}
if err := yaml.Unmarshal(data, config); err != nil {
return nil, fmt.Errorf("解析配置文件失败: %w", err)
}
// 设置默认值
config.setDefaults()
return config, nil
}
// setDefaults 设置默认值
func (c *Config) setDefaults() {
if c.DefaultProvider == "" {
c.DefaultProvider = "siliconflow"
}
if c.Timeout <= 0 {
c.Timeout = 30
}
// 为每个厂商设置默认值
for name, provider := range c.Providers {
if provider.Model == "" {
provider.Model = "gpt-3.5-turbo"
c.Providers[name] = provider
}
}
}
```
### 2. 大模型厂商接口 (Provider)
定义统一的厂商接口,采用策略模式。
```go
// internal/provider/provider.go
package provider
import (
"context"
)
// Provider 厂商接口
type Provider interface {
// Translate 调用厂商API进行翻译
Translate(ctx context.Context, req *TranslateRequest) (*TranslateResponse, error)
// Name 返回厂商名称
Name() string
// Validate 验证配置是否有效
Validate() error
}
// TranslateRequest 翻译请求
type TranslateRequest struct {
Text string `json:"text"`
FromLang string `json:"from_lang"`
ToLang string `json:"to_lang"`
Prompt string `json:"prompt"`
Model string `json:"model"`
Options map[string]interface{} `json:"options"`
}
// TranslateResponse 翻译响应
type TranslateResponse struct {
Text string `json:"text"`
FromLang string `json:"from_lang"`
ToLang string `json:"to_lang"`
Model string `json:"model"`
Usage *Usage `json:"usage"`
RawResponse []byte `json:"raw_response,omitempty"`
}
// Usage 用量统计
type Usage struct {
PromptTokens int `json:"prompt_tokens"`
CompletionTokens int `json:"completion_tokens"`
TotalTokens int `json:"total_tokens"`
}
```
### 3. 具体厂商实现示例
```go
// internal/provider/siliconflow.go
package provider
import (
"context"
"encoding/json"
"net/http"
)
// SiliconFlowProvider 硅基流动厂商实现
type SiliconFlowProvider struct {
config ProviderConfig
client *http.Client
}
// ProviderConfig 厂商配置从config包导入
type ProviderConfig struct {
APIHost string
APIKey string
Model string
}
// NewSiliconFlowProvider 创建硅基流动厂商实例
func NewSiliconFlowProvider(config ProviderConfig) *SiliconFlowProvider {
return &SiliconFlowProvider{
config: config,
client: &http.Client{},
}
}
// Name 返回厂商名称
func (p *SiliconFlowProvider) Name() string {
return "siliconflow"
}
// Validate 验证配置
func (p *SiliconFlowProvider) Validate() error {
if p.config.APIKey == "" {
return fmt.Errorf("siliconflow: API key 不能为空")
}
if p.config.APIHost == "" {
p.config.APIHost = "https://api.siliconflow.cn/v1"
}
return nil
}
// Translate 调用硅基流动API
func (p *SiliconFlowProvider) Translate(ctx context.Context, req *TranslateRequest) (*TranslateResponse, error) {
// 实现具体的API调用逻辑
// 1. 构建请求体
// 2. 发送HTTP请求
// 3. 解析响应
// 示例代码(简化)
url := p.config.APIHost + "/chat/completions"
requestBody := map[string]interface{}{
"model": p.config.Model,
"messages": []map[string]string{
{"role": "user", "content": req.Text},
},
}
// 实际实现需要完整的HTTP客户端代码
return &TranslateResponse{
Text: "翻译结果",
FromLang: req.FromLang,
ToLang: req.ToLang,
Model: p.config.Model,
}, nil
}
```
### 4. 工厂模式 - ProviderFactory
```go
// internal/provider/factory.go
package provider
import (
"fmt"
)
// ProviderFactory 厂商工厂
type ProviderFactory struct {
providers map[string]func(ProviderConfig) Provider
}
// NewProviderFactory 创建工厂实例
func NewProviderFactory() *ProviderFactory {
factory := &ProviderFactory{
providers: make(map[string]func(ProviderConfig) Provider),
}
// 注册所有厂商
factory.Register("siliconflow", NewSiliconFlowProvider)
factory.Register("volcano", NewVolcanoEngineProvider)
factory.Register("national", NewNationalSupercomputingProvider)
factory.Register("qwen", NewQwenProvider)
factory.Register("openai", NewOpenAICompatibleProvider)
return factory
}
// Register 注册厂商构造函数
func (f *ProviderFactory) Register(name string, creator func(ProviderConfig) Provider) {
f.providers[name] = creator
}
// Create 创建厂商实例
func (f *ProviderFactory) Create(name string, config ProviderConfig) (Provider, error) {
creator, exists := f.providers[name]
if !exists {
return nil, fmt.Errorf("不支持的厂商: %s", name)
}
provider := creator(config)
if err := provider.Validate(); err != nil {
return nil, fmt.Errorf("厂商配置验证失败: %w", err)
}
return provider, nil
}
```
### 5. 核心翻译类 (Translator)
```go
// internal/translator/translator.go
package translator
import (
"context"
"time"
)
// 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()
// 构建请求
req := &provider.TranslateRequest{
Text: text,
FromLang: options.FromLang,
ToLang: options.ToLang,
Prompt: t.prompt.GetPrompt(options.PromptName),
Model: t.selectModel(options.Model),
}
// 调用厂商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
}
// selectModel 选择模型
func (t *Translator) selectModel(model string) string {
if model != "" {
return model
}
return t.config.DefaultModel
}
// TranslateOptions 翻译选项
type TranslateOptions struct {
FromLang string
ToLang string
PromptName string
Model string
Temperature float64
}
// TranslateResult 翻译结果
type TranslateResult struct {
Original string
Translated string
FromLang string
ToLang string
Model string
Usage *provider.Usage
}
```
### 6. 设计模式应用
#### 工厂模式
- `ProviderFactory` 用于创建不同厂商实例
- 统一创建接口,隐藏具体实现细节
#### 策略模式
- `Provider` 接口定义统一行为
- 每个厂商实现不同的API调用策略
- 运行时动态选择策略
#### 单例模式
- 全局配置通常只需要一个实例
- 可通过包级变量或sync.Once实现
#### 依赖注入
- `Translator` 依赖 `Provider` 接口,而不是具体实现
- 通过构造函数注入依赖
## 项目结构
```
yoyo/
├── cmd/
│ └── yoyo/ # CLI入口
├── internal/
│ ├── config/ # 全局配置
│ │ ├── config.go
│ │ └── loader.go
│ ├── provider/ # 厂商实现
│ │ ├── provider.go # 接口定义
│ │ ├── factory.go # 工厂模式
│ │ ├── siliconflow.go
│ │ ├── volcano.go
│ │ ├── national.go
│ │ ├── qwen.go
│ │ └── openai.go
│ ├── translator/ # 核心翻译
│ │ ├── translator.go
│ │ └── prompt.go
│ └── prompt/ # Prompt管理
├── pkg/ # 公共工具
├── configs/ # 配置文件目录
│ └── config.yaml
├── go.mod
└── go.sum
```
## 配置文件示例 (YAML)
```yaml
# config.yaml
default_provider: "siliconflow"
default_model: "gpt-3.5-turbo"
timeout: 30
providers:
siliconflow:
api_host: "https://api.siliconflow.cn/v1"
api_key: "${SILICONFLOW_API_KEY}"
model: "siliconflow-base"
enabled: true
volcano:
api_host: "https://api.volcengine.com/v1"
api_key: "${VOLCANO_API_KEY}"
model: "volcano-chat"
enabled: true
national:
api_host: "https://api.nsc.gov.cn/v1"
api_key: "${NATIONAL_API_KEY}"
model: "nsc-base"
enabled: false
qwen:
api_host: "https://dashscope.aliyuncs.com/compatible-mode/v1"
api_key: "${QWEN_API_KEY}"
model: "qwen-turbo"
enabled: true
openai:
api_host: "https://api.openai.com/v1"
api_key: "${OPENAI_API_KEY}"
model: "gpt-3.5-turbo"
enabled: true
prompts:
technical: "你是一位专业的技术翻译,请准确翻译以下技术文档,保持专业术语的准确性。"
creative: "你是一位富有创造力的翻译家,请用优美流畅的语言翻译以下内容。"
academic: "你是一位学术翻译专家,请用严谨的学术语言翻译以下内容。"
simple: "请用简单易懂的语言翻译以下内容。"
```
## 开发顺序建议
1. 实现 `Config``ConfigLoader`
2. 实现 `Provider` 接口和工厂
3. 实现至少一个厂商如SiliconFlow
4. 实现 `Translator` 核心类
5. 集成测试
6. 实现其他厂商
## 测试策略
```go
// 内部测试示例
func TestTranslator_Translate(t *testing.T) {
// Mock provider
mockProvider := &MockProvider{
TranslateFunc: func(ctx context.Context, req *provider.TranslateRequest) (*provider.TranslateResponse, error) {
return &provider.TranslateResponse{Text: "翻译结果"}, nil
},
}
translator := NewTranslator(testConfig, mockProvider)
result, err := translator.Translate(context.Background(), "Hello", &TranslateOptions{
ToLang: "zh",
})
if err != nil {
t.Fatalf("翻译失败: %v", err)
}
if result.Translated != "翻译结果" {
t.Errorf("期望 '翻译结果', 得到 '%s'", result.Translated)
}
}
```
## 错误处理最佳实践
- 每个厂商实现应定义具体的错误类型
- 使用 `%w` 包装错误以保留原始错误信息
- 提供清晰的错误消息帮助调试
## 安全注意事项
- API密钥使用环境变量
- 配置文件中不存储真实密钥
- 使用 `os.Getenv` 读取敏感信息
- 定期轮换API密钥
## 开发规范
### 文档管理
#### 文档文件列表
1. **why.md** - 项目初衷文档(仅用户编辑)
2. **taolun.md** - 讨论记录(时间轴格式)
3. **changelog.md** - 版本记录(包含讨论链接)
4. **memory.md** - 知识纠正(踩坑记录)
#### 文档协作规范
| 文档 | 编辑者 | 内容 | 更新频率 |
|------|--------|------|----------|
| why.md | 用户 | 项目初衷、愿景、目标 | 随时 |
| taolun.md | AI+用户 | 讨论记录、决策过程 | 每次重要讨论后 |
| changelog.md | AI | 版本变更、任务状态 | 每次版本更新 |
| memory.md | AI | 经验总结、术语定义 | 遇到问题后 |
#### 特殊文档说明
**why.md**:
- 项目初衷文档,只能由用户编辑
- AI不应修改此文件内容
- 用于记录创始人的个人想法和项目愿景
- 位置:项目根目录
**AI责任边界**:
- ✅ 可以编辑taolun.md、changelog.md、memory.md
- ❌ 不应编辑why.md、用户个人配置文件
- ✅ 可以建议why.md的内容结构但不强制
### 文档链接
- 项目初衷: [why.md](why.md)
- 讨论记录: [taolun.md](taolun.md)
- 版本记录: [changelog.md](changelog.md)
- 知识纠正: [memory.md](memory.md)
### 版本号管理
- 格式:主版本.次版本.修订版本(00-99)
- 更新时机测试完成后git操作前
- 递增规则:小修复第三位+1新功能第二位+1重大变更第一位+1
### 分支策略
- main: 稳定上线版
- dev: 开发分支
- 功能开发从dev创建功能分支
### 提交规范
- 提交前更新相关文档
- 使用清晰的提交信息
- 版本更新时打标签
## 开发命令
### 构建
```bash
# 构建二进制文件
go build -o yoyo ./cmd/yoyo
# 交叉编译Linux
GOOS=linux GOARCH=amd64 go build -o yoyo-linux ./cmd/yoyo
# 交叉编译macOS
GOOS=darwin GOARCH=amd64 go build -o yoyo-mac ./cmd/yoyo
```
### 测试
```bash
# 运行所有测试
go test ./...
# 运行特定包的测试
go test ./internal/translator
# 运行单个测试函数
go test -run TestTranslate ./internal/translator
# 运行测试并显示详细输出
go test -v ./...
# 运行基准测试
go test -bench=. ./...
```
### 代码检查与格式化
```bash
# 代码格式化(必须)
gofmt -w .
# 代码检查
go vet ./...
# 使用golangci-lint推荐
golangci-lint run
# 生成依赖图
go mod graph
```
### 运行工具
```bash
# 直接运行
go run ./cmd/yoyo "This is translation content..."
# 使用构建的二进制
./yoyo "This is translation content..."
# 指定翻译模式
./yoyo --mode=technical "API documentation text"
```
## 代码风格指南
### 命名约定
- **包名**:小写单词,简洁明了(如`translator``config`
- **函数/方法名**:驼峰命名,动词开头(如`TranslateText``LoadConfig`
- **变量名**:驼峰命名,简洁(如`inputText``apiResponse`
- **常量**:全大写加下划线(如`MAX_RETRY_COUNT`
- **接口名**:以`-er`结尾或描述性名称(如`Translator``ConfigLoader`
### 导入顺序
```go
import (
// 标准库
"context"
"fmt"
// 第三方包
"github.com/spf13/cobra"
// 项目内部包
"github.com/username/yoyo/internal/api"
"github.com/username/yoyo/internal/config"
)
```
### 错误处理
```go
// 包装错误以提供更多上下文
if err := loadConfig(); err != nil {
return fmt.Errorf("failed to load config: %w", err)
}
// 定义哨兵错误
var (
ErrInvalidAPIKey = errors.New("invalid API key")
ErrNetworkFailed = errors.New("network request failed")
)
// 错误检查使用errors.Is
if errors.Is(err, ErrInvalidAPIKey) {
// 处理特定错误
}
```
### 类型使用
- 优先使用具体类型,必要时使用接口
- 避免使用`interface{}`,使用泛型或具体类型
- 结构体字段使用大写开头(导出)或小写开头(私有)
- 为复杂类型添加文档注释
### 并发处理
```go
// 使用context传递取消信号
func Translate(ctx context.Context, text string) (string, error) {
select {
case <-ctx.Done():
return "", ctx.Err()
default:
// 继续翻译
}
}
// 使用goroutine和channel时注意资源清理
go func() {
defer close(doneCh)
// 执行任务
}()
```
### 注释规范
- 包注释:描述包的功能和用途
- 函数注释:描述函数功能、参数、返回值
- 导出类型/函数必须有注释
- 使用Godoc格式
## 测试指南
- 每个公共函数都应有对应的测试
- 测试函数命名:`TestFunctionName`
- 使用表格驱动测试
- Mock外部依赖
- 测试文件放在同一目录,以`_test.go`结尾
```go
// 示例测试
func TestTranslator_Translate(t *testing.T) {
tests := []struct {
name string
input string
expected string
}{
{"simple text", "hello", "你好"},
{"empty string", "", ""},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result, err := translator.Translate(tt.input)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if result != tt.expected {
t.Errorf("got %v, want %v", result, tt.expected)
}
})
}
}
```
## 依赖管理
- 使用Go Modules管理依赖
- 保持`go.mod``go.sum`整洁
- 定期更新依赖:`go get -u ./...`
- 移除未使用的依赖:`go mod tidy`
## 提交前检查清单
1. ✅ 运行`gofmt -w .`格式化代码
2. ✅ 运行`go vet ./...`检查代码
3. ✅ 运行`go test ./...`确保测试通过
4. ✅ 确保所有导出函数有注释
5. ✅ 检查错误处理是否完善
6. ✅ 验证API密钥等敏感信息已忽略
## 敏感信息处理
- API密钥使用环境变量或配置文件
-`.env`添加到`.gitignore`
- 不要在日志中打印敏感信息
- 使用`os.Getenv`读取环境变量
## 构建和发布
```bash
# 发布版本
git tag v1.0.0
git push origin v1.0.0
# 使用GoReleaser推荐
goreleaser release --clean
```
## 常见问题
### Q: 如何添加新的翻译模式?
A: 在`internal/prompt/`目录下创建新的Prompt配置然后在`internal/translator/`中注册。
### Q: 如何处理API限流
A: 使用指数退避重试,并在`internal/api/`中实现限流器。
### Q: 如何支持更多语言?
A: 在配置文件中添加语言映射,并更新翻译逻辑。
## 参考资源
- [Effective Go](https://go.dev/doc/effective_go)
- [Go Code Review Comments](https://github.com/golang/go/wiki/CodeReviewComments)
- [Go Style Guide](https://google.github.io/styleguide/go/)

85
changelog.md Normal file
View File

@@ -0,0 +1,85 @@
# 变更日志 (changelog.md)
> 本文档记录所有版本变更,包含功能、修复和讨论链接。
## 使用说明
- 版本号格式:`主版本.次版本.修订版本`(如 `0.0.1`
- 第三位为00-99超过99时增加第二位
- 每个版本包含指向讨论记录的链接
## 未来架构想法
- [ ] 支持流式翻译输出
- [ ] 添加本地缓存减少API调用
- [ ] 实现插件系统支持自定义厂商
- [ ] 支持批量翻译文件
- [ ] 添加Web界面可选
## 待实现
- [ ] 实现硅基流动厂商
- [ ] 实现火山引擎厂商
- [ ] 实现国家超算厂商
- [ ] 实现Qwen厂商
- [ ] 实现OpenAI兼容厂商
- [ ] 配置文件热重载
- [ ] 翻译历史记录
## 当前正实现
- [ ] 项目基础架构搭建
- [ ] 核心类设计实现
## 待修复BUG
-
## 版本历史
### 0.0.1 (2026-03-28) - 项目初始化
**类型**: 初始化版本
**状态**: 开发中
**变更内容**:
- ✅ 确定技术栈为Go语言
- ✅ 设计OOP架构Config、Provider、Translator
- ✅ 制定开发规范taolun.md、changelog.md、memory.md、why.md
- ✅ 确定分支策略main、dev
- ✅ 设计项目结构
- ✅ 创建项目初衷文档why.md
**讨论记录**:
- [确定技术栈](taolun.md#2026-03-28-2230-版本-001-确定技术栈)
- [设计OOP架构](taolun.md#2026-03-28-2300-版本-001-设计oop架构)
- [制定开发规范](taolun.md#2026-03-28-2330-版本-001-制定开发规范)
- [创建项目初衷文档](taolun.md#2026-03-28-2345-版本-001-创建项目初衷文档)
**下一步**:
- 创建项目目录结构
- 初始化Go模块
- 实现Config类
- 实现Provider接口
- 用户填写why.md内容
---
## 版本号管理规则
### 版本号格式
`主版本.次版本.修订版本`(例如:`1.2.3`
### 更新规则
1. **主版本**(第一位):重大架构变更、不兼容更新
2. **次版本**(第二位):新功能、重要特性
3. **修订版本**第三位小修复、优化00-99
### 更新流程
1. 完成开发并测试
2. 更新changelog.md
3. 更新taolun.md如有讨论
4. 更新memory.md如有新知识
5. 更新版本号
6. 提交到dev分支
7. 测试通过后合并到main
8. 创建版本标签:`git tag v0.0.1`
### 示例版本递增
- `0.0.1``0.0.2`:小修复
- `0.0.99``0.1.0`:新功能(修订版本溢出)
- `1.2.3``2.0.0`:重大架构变更

43
configs/config.yaml Normal file
View File

@@ -0,0 +1,43 @@
# YOYO翻译工具配置文件
# 注意API密钥使用环境变量不要直接写入真实密钥
default_provider: "siliconflow"
default_model: "gpt-3.5-turbo"
timeout: 30
providers:
siliconflow:
api_host: "https://api.siliconflow.cn/v1"
api_key: "${SILICONFLOW_API_KEY}"
model: "siliconflow-base"
enabled: true
volcano:
api_host: "https://api.volcengine.com/v1"
api_key: "${VOLCANO_API_KEY}"
model: "volcano-chat"
enabled: true
national:
api_host: "https://api.nsc.gov.cn/v1"
api_key: "${NATIONAL_API_KEY}"
model: "nsc-base"
enabled: false
qwen:
api_host: "https://dashscope.aliyuncs.com/compatible-mode/v1"
api_key: "${QWEN_API_KEY}"
model: "qwen-turbo"
enabled: true
openai:
api_host: "https://api.openai.com/v1"
api_key: "${OPENAI_API_KEY}"
model: "gpt-3.5-turbo"
enabled: true
prompts:
technical: "你是一位专业的技术翻译,请准确翻译以下技术文档,保持专业术语的准确性。"
creative: "你是一位富有创造力的翻译家,请用优美流畅的语言翻译以下内容。"
academic: "你是一位学术翻译专家,请用严谨的学术语言翻译以下内容。"
simple: "请用简单易懂的语言翻译以下内容。"

3
go.mod Normal file
View File

@@ -0,0 +1,3 @@
module github.com/titor/fanyi
go 1.26.1

166
memory.md Normal file
View File

@@ -0,0 +1,166 @@
# 记忆纠正 (memory.md)
> 本文档记录开发过程中的重要定义、踩过的坑和经验总结用于AI内部知识纠正。
## 使用说明
- 定期更新,特别是遇到问题后
- 按类别组织,便于查找
- 包含具体示例和解决方案
## 技术决策记录
### Go语言选择
**决策**: 使用Go语言而非Node.js或Deno
**原因**:
1. Go编译为单一二进制文件部署方便
2. 性能优秀适合CLI工具
3. 强大的标准库支持
4. 用户愿意学习Go
**影响**: 项目结构、依赖管理、开发工具链
---
### 面向对象设计
**决策**: 在Go中实现面向对象设计模式
**模式应用**:
1. **工厂模式**: ProviderFactory创建厂商实例
2. **策略模式**: Provider接口定义不同厂商策略
3. **依赖注入**: Translator依赖Provider接口
**注意事项**:
- Go中没有类使用结构体
- 继承通过组合实现
- 多态通过接口实现
---
## 术语定义
### 厂商 (Provider)
指提供大模型API的服务商如硅基流动、火山引擎等。每个厂商实现统一的`Provider`接口。
### 配置 (Config)
全局配置对象包含API密钥、模型选择、超时设置等。使用YAML格式。
### 核心翻译器 (Translator)
负责协调配置、厂商和Prompt管理执行翻译任务的核心类。
## 踩过的坑
### 环境变量加载问题
**问题**: 配置文件中的环境变量(如`${API_KEY}`)没有正确解析
**原因**: 没有实现环境变量替换功能
**解决方案**:
1. 使用`os.Getenv`读取环境变量
2. 在配置加载时进行字符串替换
3. 添加环境变量验证
**预防措施**:
- 在配置加载后验证所有必需的环境变量
- 提供清晰的错误信息
---
### 厂商API差异
**问题**: 不同厂商的API格式差异较大
**原因**: 每个厂商有自己的请求/响应格式
**解决方案**:
1. 定义统一的`TranslateRequest``TranslateResponse`
2. 在每个厂商实现中进行格式转换
3. 使用适配器模式
**经验**:
- 优先设计统一接口
- 将厂商特定逻辑封装在实现内部
- 提供原始响应用于调试
---
### 版本号管理混乱
**问题**: 版本号递增规则不明确
**原因**: 没有明确的版本管理规范
**解决方案**:
1. 采用语义化版本:主版本.次版本.修订版本
2. 第三位限制为00-99
3. 建立更新流程
**规范**:
- 小修复:修订版本+1
- 新功能:次版本+1修订版本重置为00
- 重大变更:主版本+1次版本和修订版本重置
---
## 配置最佳实践
### 安全配置
- API密钥使用环境变量
- 不提交敏感信息到版本控制
- 提供`.env.example`模板
### 配置验证
- 启动时验证所有必需配置
- 提供有意义的错误信息
- 支持配置热重载(未来)
### 默认值策略
- 为非必需配置提供合理的默认值
- 默认值应在`config.setDefaults()`中设置
- 记录默认值的作用
---
## 开发工作流
### 日常开发流程
1.`dev`分支创建功能分支
2. 开发并测试功能
3. 更新相关文档taolun.md、changelog.md
4. 提交到功能分支
5. 合并到`dev`分支
6. 测试通过后合并到`main`
### 版本发布流程
1. 确保`dev`分支稳定
2. 更新版本号
3. 更新changelog.md
4. 创建版本标签
5. 合并到`main`分支
### 文档维护
- 每次重要讨论后更新taolun.md
- 每个版本更新changelog.md
- 遇到问题后更新memory.md
---
## 文档管理规范
### why.md (项目初衷文档)
**用途**: 记录项目初衷、愿景、目标和个人笔记
**编辑权限**: 只能由项目所有者(用户)编辑
**位置**: 项目根目录
**内容建议**:
- 项目愿景
- 核心问题
- 目标用户
- 期望功能
- 个人笔记
**注意事项**:
- AI不应修改此文件
- 文件内容反映创始人的个人想法
- 可以自由格式,不强制结构
### 文档协作规范
**taolun.md**: AI与用户共同维护的讨论记录
**changelog.md**: AI与用户共同维护的版本记录
**memory.md**: AI主导的知识纠正和经验总结
**why.md**: 用户专属的项目初衷文档
**编辑流程**:
1. 用户编辑why.md记录初衷
2. AI编辑taolun.md记录讨论
3. AI更新changelog.md记录版本
4. AI更新memory.md记录经验

88
taolun.md Normal file
View File

@@ -0,0 +1,88 @@
# 讨论记录 (taolun.md)
> 本文档记录开发过程中的重要讨论,以时间轴方式存储,便于版本追溯。
## 使用说明
- 每次重要讨论后更新此文件
- 使用上下文压缩总结,突出重点
- 格式:时间 - 版本号 - 主题
## 时间轴记录
### [2026-03-28 22:30] 版本 0.0.1 - 确定技术栈
**原因**: 项目启动,需要确定技术栈
**分析**:
- 比较Go、Deno+TS、Node.js+TS
- Go优势原生二进制、性能好、CLI工具友好
- 用户不会Go但愿意学习
**解决方案**:
- 使用Go语言开发
- 采用面向对象设计模式
- 支持多个大模型厂商
**相关决策**:
- 项目结构采用`cmd/``internal/`布局
- 使用YAML配置文件
- 实现工厂模式和策略模式
**关联版本**: [changelog.md#0.0.1](changelog.md#001)
---
### [2026-03-28 23:00] 版本 0.0.1 - 设计OOP架构
**原因**: 用户要求面向对象开发模式
**分析**:
- Go不是传统OOP语言但可通过结构体和接口实现
- 需要三个核心类:配置、厂商、翻译器
**解决方案**:
- `Config`类:全局配置管理
- `Provider`接口:厂商抽象
- `Translator`类:核心翻译逻辑
- `ProviderFactory`:工厂模式创建厂商实例
**相关链接**:
- [AGENTS.md#OOP设计模式](AGENTS.md#oop设计模式)
- [changelog.md#0.0.1](changelog.md#001)
---
### [2026-03-28 23:30] 版本 0.0.1 - 制定开发规范
**原因**: 建立规范的开发流程
**分析**:
- 需要记录讨论过程、版本变更和知识积累
- 版本号需要遵循语义化版本规范
**解决方案**:
- 创建taolun.md记录讨论
- 创建changelog.md记录版本
- 创建memory.md记录知识纠正
- 版本号格式:大版本.新功能.小修复(00-99)
**关联文档**:
- [changelog.md#0.0.1](changelog.md#001)
- [memory.md#版本管理](memory.md#版本管理)
---
### [2026-03-28 23:45] 版本 0.0.1 - 创建项目初衷文档
**原因**: 需要一个地方记录项目初衷和愿景
**分析**:
- 项目需要明确的目标和方向
- 创始人需要记录个人想法和灵感
- 与其他文档taolun.md、changelog.md、memory.md区分
**解决方案**:
- 创建`why.md`文件专门记录项目初衷
- 规定只能由项目所有者编辑
- 提供基本结构建议,但不强制内容
**文档规范**:
- 文件位置:项目根目录
- 权限:仅用户可编辑
- 内容:项目愿景、目标、个人笔记等
**关联文档**:
- [AGENTS.md#文档管理](AGENTS.md#开发规范)
- [changelog.md#0.0.1](changelog.md#001)

33
why.md Normal file
View File

@@ -0,0 +1,33 @@
# 项目初衷 (why.md)
> 本文档记录YOYO翻译工具项目的初衷、愿景和目标。
> **注意:此文档只能由项目所有者编辑。**
## 项目愿景
创建一个高效、易用的命令行翻译工具,支持多个大模型厂商,提供多样化的翻译特色。
## 核心问题
1. 现有翻译工具功能单一,缺乏定制化
2. 不同翻译场景需要不同的Prompt策略
3. 需要一个统一的CLI工具集成多个翻译API
## 目标用户
- 开发者:需要翻译技术文档
- 写作者:需要翻译创意内容
- 学生:需要翻译学术论文
- 普通用户:日常翻译需求
## 期望功能
- [ ] 支持多个大模型厂商
- [ ] 可配置的Prompt模板
- [ ] 批量翻译文件
- [ ] 翻译历史记录
- [ ] 本地缓存减少API调用
## 个人笔记
(在此记录您的个人想法、灵感和笔记)
---
*最后更新2026-03-28*
*版本0.0.1*