2026-03-28 23:19:13 +08:00
|
|
|
|
# 讨论记录 (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#开发规范)
|
2026-03-28 23:27:02 +08:00
|
|
|
|
- [changelog.md#0.0.1](changelog.md#001)
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
### [2026-03-28 23:50] 版本 0.0.2 - 实现核心架构
|
|
|
|
|
|
**原因**: 开始实现项目核心功能
|
|
|
|
|
|
**分析**:
|
|
|
|
|
|
- 根据OOP设计模式实现三个核心类
|
|
|
|
|
|
- 需要先实现配置加载和厂商接口
|
|
|
|
|
|
- 创建基本的CLI入口点
|
|
|
|
|
|
|
|
|
|
|
|
**解决方案**:
|
|
|
|
|
|
1. **Config类实现**:
|
|
|
|
|
|
- 支持YAML配置文件加载
|
|
|
|
|
|
- 环境变量替换
|
|
|
|
|
|
- 配置验证和默认值
|
|
|
|
|
|
|
|
|
|
|
|
2. **Provider接口实现**:
|
|
|
|
|
|
- 定义统一的翻译接口
|
|
|
|
|
|
- 工厂模式创建厂商实例
|
|
|
|
|
|
- 实现硅基流动厂商作为示例
|
|
|
|
|
|
|
|
|
|
|
|
3. **Translator类实现**:
|
|
|
|
|
|
- 核心翻译逻辑
|
|
|
|
|
|
- Prompt管理
|
|
|
|
|
|
- 超时控制
|
|
|
|
|
|
|
|
|
|
|
|
4. **CLI入口点**:
|
|
|
|
|
|
- 命令行参数解析
|
|
|
|
|
|
- 配置加载
|
|
|
|
|
|
- 翻译执行
|
|
|
|
|
|
|
|
|
|
|
|
**技术细节**:
|
|
|
|
|
|
- 使用`gopkg.in/yaml.v3`处理YAML
|
|
|
|
|
|
- 实现工厂模式注册机制
|
|
|
|
|
|
- 使用context处理超时和取消
|
|
|
|
|
|
- 添加基本单元测试
|
|
|
|
|
|
|
|
|
|
|
|
**关联文档**:
|
|
|
|
|
|
- [AGENTS.md#OOP设计模式](AGENTS.md#oop设计模式)
|
2026-03-28 23:30:57 +08:00
|
|
|
|
- [changelog.md#0.0.2](changelog.md#002)
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
### [2026-03-29 00:00] 版本 0.0.3 - 环境变量加载修复
|
|
|
|
|
|
**原因**: 测试CLI时发现环境变量没有正确加载
|
|
|
|
|
|
**分析**:
|
|
|
|
|
|
- 配置文件中使用`${ENV_VAR}`语法
|
|
|
|
|
|
- Go的`os.ExpandEnv`只在加载时替换
|
|
|
|
|
|
- 需要先加载.env文件到环境变量
|
|
|
|
|
|
|
|
|
|
|
|
**解决方案**:
|
|
|
|
|
|
1. 添加`github.com/joho/godotenv`依赖
|
|
|
|
|
|
2. 在main函数开始时调用`godotenv.Load()`
|
|
|
|
|
|
3. 更新memory.md记录踩坑经验
|
|
|
|
|
|
|
|
|
|
|
|
**技术细节**:
|
|
|
|
|
|
- godotenv会自动查找当前目录的.env文件
|
|
|
|
|
|
- 如果文件不存在会返回错误,可以忽略
|
|
|
|
|
|
- 不影响已有的环境变量
|
|
|
|
|
|
|
|
|
|
|
|
**关联文档**:
|
|
|
|
|
|
- [memory.md#环境变量加载问题](memory.md#环境变量加载问题)
|
feat: add language support and onboard configuration wizard (v0.2.0)
- Add language code intelligent parsing module (internal/lang)
- Support --lang parameter for target language specification
- Support multiple language code formats (BCP47, aliases, Chinese names)
- Implement interactive onboard configuration wizard
- Update Config struct with language fields
- Add survey library dependency for interactive UI
- Improve CLI command interface
- Add comprehensive unit tests for language module
- Update documentation (AGENTS.md, changelog.md, taolun.md, memory.md)
Supported language codes:
- Standard: zh-CN, zh-TW, en-US, en-GB, ja, ko, es, fr, de
- Aliases: cn, en, jp, kr, es, fr, de
- Chinese names: chinese, english, japanese
Commands:
- yoyo "Hello world" - basic translation
- yoyo --lang=cn "Hello world" - specify target language
- yoyo onboard - start configuration wizard
- yoyo onboard --force - force reconfiguration
Version: 0.2.0
2026-03-29 01:30:42 +08:00
|
|
|
|
- [changelog.md#0.0.3](changelog.md#003)
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
### [2026-03-29 10:00] 版本 0.2.0 - 语言代码解析设计
|
|
|
|
|
|
**原因**: 用户需要通过 `--lang` 参数指定目标语言,支持多种语言代码格式
|
|
|
|
|
|
**分析**:
|
|
|
|
|
|
- 需要支持标准BCP47格式(如 `zh-CN`、`en-US`)
|
|
|
|
|
|
- 需要支持简短别名(如 `cn`、`en`)
|
|
|
|
|
|
- 需要支持中文名称(如 `chinese`、`english`)
|
|
|
|
|
|
- 需要智能解析和错误提示
|
|
|
|
|
|
|
|
|
|
|
|
**解决方案**:
|
|
|
|
|
|
1. 创建 `internal/lang/lang.go` 模块
|
|
|
|
|
|
2. 实现语言代码映射表和解析函数
|
|
|
|
|
|
3. 支持大小写不敏感和模糊匹配
|
|
|
|
|
|
4. 提供语言名称获取和建议功能
|
|
|
|
|
|
|
|
|
|
|
|
**技术细节**:
|
|
|
|
|
|
- 使用 `map[string]string` 存储语言代码映射
|
|
|
|
|
|
- 实现 `ParseLanguageCode()` 函数进行智能解析
|
|
|
|
|
|
- 支持30+种语言和变体
|
|
|
|
|
|
- 添加完整的单元测试
|
|
|
|
|
|
|
|
|
|
|
|
**关联文档**:
|
|
|
|
|
|
- [AGENTS.md#语言代码处理](AGENTS.md#语言代码处理)
|
|
|
|
|
|
- [changelog.md#0.2.0](changelog.md#020)
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
### [2026-03-29 10:30] 版本 0.2.0 - onboard配置向导
|
|
|
|
|
|
**原因**: 用户需要友好的配置界面,特别是第一次使用时
|
|
|
|
|
|
**分析**:
|
|
|
|
|
|
- 需要交互式配置向导
|
|
|
|
|
|
- 需要支持选择厂商、输入API密钥、设置默认值
|
|
|
|
|
|
- 需要生成标准的YAML配置文件
|
|
|
|
|
|
- 需要支持强制重新配置
|
|
|
|
|
|
|
|
|
|
|
|
**解决方案**:
|
|
|
|
|
|
1. 使用 `github.com/AlecAivazis/survey/v2` 库
|
|
|
|
|
|
2. 实现分步配置流程:选择厂商 → 配置厂商 → 全局设置 → 保存
|
|
|
|
|
|
3. 提供友好的错误处理和用户提示
|
|
|
|
|
|
4. 支持 `--force` 参数强制重新配置
|
|
|
|
|
|
|
|
|
|
|
|
**技术细节**:
|
|
|
|
|
|
- 使用 `survey.Select`、`survey.Input`、`survey.Confirm` 组件
|
|
|
|
|
|
- 实现厂商默认配置和自定义选项
|
|
|
|
|
|
- 生成完整的配置文件包含所有必要字段
|
|
|
|
|
|
- 支持配置文件存在性检查
|
|
|
|
|
|
|
|
|
|
|
|
**关联文档**:
|
|
|
|
|
|
- [AGENTS.md#Onboard配置向导](AGENTS.md#onboard配置向导)
|
|
|
|
|
|
- [changelog.md#0.2.0](changelog.md#020)
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
### [2026-03-29 11:00] 版本 0.2.0 - 分阶段迁移策略
|
|
|
|
|
|
**原因**: 需要平衡开发便利性和最终上线需求
|
|
|
|
|
|
**分析**:
|
|
|
|
|
|
- 开发阶段需要简单配置方式(`.env` + `configs/config.yaml`)
|
|
|
|
|
|
- 上线前需要迁移到用户配置目录(`~/.config/yoo/yoo.yml`)
|
|
|
|
|
|
- 需要平滑的迁移路径和向后兼容性
|
|
|
|
|
|
|
|
|
|
|
|
**解决方案**:
|
|
|
|
|
|
1. **第一阶段(当前)**: 继续使用 `.env` + `configs/config.yaml`
|
|
|
|
|
|
2. **第二阶段(上线前)**: 实现配置文件路径查找和迁移工具
|
|
|
|
|
|
3. **第三阶段(最终)**: 移除 `.env` 依赖,完全使用配置文件
|
|
|
|
|
|
|
|
|
|
|
|
**技术细节**:
|
|
|
|
|
|
- 配置文件路径优先级:命令行 > 环境变量 > 用户目录 > 当前目录
|
|
|
|
|
|
- 保持向后兼容性,支持旧配置格式
|
|
|
|
|
|
- 提供配置验证和错误提示
|
|
|
|
|
|
- 实现配置迁移工具(计划)
|
|
|
|
|
|
|
|
|
|
|
|
**关联文档**:
|
|
|
|
|
|
- [AGENTS.md#分阶段迁移策略](AGENTS.md#分阶段迁移策略)
|
2026-03-29 21:10:28 +08:00
|
|
|
|
- [changelog.md#0.2.0](changelog.md#020)
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
### [2026-03-29 12:00] 版本 0.4.0 - 管道符功能
|
|
|
|
|
|
**原因**: 用户需要与其他命令行工具联合使用
|
|
|
|
|
|
**分析**:
|
|
|
|
|
|
- 用户希望支持管道符功能,如 `cat a.txt | yoyo | grep "who are you"`
|
|
|
|
|
|
- 需要检测管道输入并从stdin读取内容
|
|
|
|
|
|
- 需要控制统计信息输出,避免污染管道输出
|
|
|
|
|
|
- 需要保持向后兼容性
|
|
|
|
|
|
|
|
|
|
|
|
**解决方案**:
|
|
|
|
|
|
1. **管道输入检测**: 实现 `isPipeInput()` 函数,使用 `os.Stdin.Stat()` 检测管道
|
|
|
|
|
|
2. **stdin读取**: 实现 `readFromStdin()` 函数,使用 `bufio.Scanner` 读取所有输入
|
|
|
|
|
|
3. **静默模式**: 添加 `--quiet` 和 `-q` 参数,控制统计信息输出
|
|
|
|
|
|
4. **输出重定向**: 将统计信息输出到stderr,避免污染管道输出
|
|
|
|
|
|
|
|
|
|
|
|
**技术细节**:
|
|
|
|
|
|
- 使用 `os.ModeCharDevice` 检测是否为管道设备
|
|
|
|
|
|
- 使用 `strings.Join()` 合并多行输入为单个字符串
|
|
|
|
|
|
- 统计信息输出到 `os.Stderr` 而不是 `os.Stdout`
|
|
|
|
|
|
- 修复 content/filter.go 中的正则表达式转义问题
|
|
|
|
|
|
|
|
|
|
|
|
**使用示例**:
|
|
|
|
|
|
```bash
|
|
|
|
|
|
# 基本管道功能
|
|
|
|
|
|
echo "Hello world" | yoyo
|
|
|
|
|
|
cat file.txt | yoyo --lang=en
|
|
|
|
|
|
|
|
|
|
|
|
# 静默模式
|
|
|
|
|
|
echo "Hello world" | yoyo -q
|
|
|
|
|
|
echo "Hello world" | yoyo --quiet
|
|
|
|
|
|
|
|
|
|
|
|
# 与其他命令组合
|
|
|
|
|
|
cat file.txt | yoyo | grep "你好"
|
|
|
|
|
|
yoyo "Hello" | wc -l
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
**关联文档**:
|
|
|
|
|
|
- [AGENTS.md#管道符功能](AGENTS.md#管道符功能)
|
|
|
|
|
|
- [changelog.md#0.4.0](changelog.md#040)
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
### [2026-03-29 15:00] 版本 0.5.0 - 本地缓存功能设计
|
|
|
|
|
|
**原因**: 用户希望减少API调用,添加本地缓存功能
|
|
|
|
|
|
**分析**:
|
|
|
|
|
|
- 需要存储翻译结果,避免重复调用API
|
|
|
|
|
|
- 需要设计缓存键策略,确保缓存准确性
|
|
|
|
|
|
- 需要考虑数据库选择、事务处理、性能优化
|
|
|
|
|
|
- 需要设计缓存管理策略
|
|
|
|
|
|
|
|
|
|
|
|
**解决方案**:
|
|
|
|
|
|
1. **数据库选择**: 使用SQLite
|
|
|
|
|
|
- 轻量级,无需服务器
|
|
|
|
|
|
- 支持ACID事务
|
|
|
|
|
|
- Go生态支持良好 (`github.com/mattn/go-sqlite3`)
|
|
|
|
|
|
- 适合嵌入式应用
|
|
|
|
|
|
|
|
|
|
|
|
2. **缓存键设计**:
|
|
|
|
|
|
- 使用文本内容 + 源语言 + 目标语言
|
|
|
|
|
|
- 生成SHA256哈希作为缓存键
|
|
|
|
|
|
- 规范化输入:移除多余空白字符,统一语言代码格式
|
|
|
|
|
|
|
|
|
|
|
|
3. **事务处理**:
|
|
|
|
|
|
- 使用事务保证数据一致性
|
|
|
|
|
|
- 插入操作在事务中执行
|
|
|
|
|
|
- 查询操作不需要显式事务
|
|
|
|
|
|
|
|
|
|
|
|
4. **保存时机**:
|
|
|
|
|
|
- 在输出结果之前保存到数据库
|
|
|
|
|
|
- 确保数据持久化
|
|
|
|
|
|
- 异步保存,不阻塞翻译结果返回
|
|
|
|
|
|
|
|
|
|
|
|
5. **性能优化**:
|
|
|
|
|
|
- 为缓存键创建索引
|
|
|
|
|
|
- 使用哈希键减少存储空间
|
|
|
|
|
|
- 限制缓存表大小(可配置)
|
|
|
|
|
|
- 使用WAL模式提高并发性能
|
|
|
|
|
|
|
|
|
|
|
|
6. **缓存策略**:
|
|
|
|
|
|
- 采用组合策略:数量限制+时间过期
|
|
|
|
|
|
- 默认启用缓存功能
|
|
|
|
|
|
- 提供手动清理命令
|
|
|
|
|
|
|
|
|
|
|
|
7. **存储位置**:
|
|
|
|
|
|
- 数据库文件存储在用户配置目录 `~/.config/yoyo/cache.db`
|
|
|
|
|
|
- 符合XDG规范
|
|
|
|
|
|
- 支持自定义路径配置
|
|
|
|
|
|
|
|
|
|
|
|
**技术细节**:
|
|
|
|
|
|
- 使用 `github.com/mattn/go-sqlite3` 驱动
|
|
|
|
|
|
- 实现 `internal/cache/cache.go` 模块
|
|
|
|
|
|
- 缓存表结构:`id`, `cache_key`, `original_text`, `translated_text`, `from_lang`, `to_lang`, `model`, `prompt`, `created_at`
|
|
|
|
|
|
- 缓存键生成:`sha256(text + "|" + fromLang + "|" + toLang)`
|
|
|
|
|
|
- 查询缓存时使用 `SELECT translated_text FROM cache WHERE cache_key = ?`
|
|
|
|
|
|
- 插入缓存时使用 `INSERT OR IGNORE INTO cache (...) VALUES (...)`
|
|
|
|
|
|
|
|
|
|
|
|
**关联文档**:
|
|
|
|
|
|
- [AGENTS.md#本地缓存功能设计](AGENTS.md#本地缓存功能设计)
|
|
|
|
|
|
- [changelog.md#0.5.0](changelog.md#050)
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
### [2026-03-29 20:00] 版本 0.5.1 - 缓存功能修复
|
|
|
|
|
|
**原因**: 缓存功能测试中发现的问题
|
|
|
|
|
|
**分析**:
|
|
|
|
|
|
1. **VACUUM事务错误**: 缓存清空命令中,VACUUM不能在事务中执行
|
|
|
|
|
|
2. **NULL值转换错误**: 缓存统计查询在空表时,MIN(created_at)返回NULL导致转换错误
|
|
|
|
|
|
3. **过期清理策略**: 当expire_days=0时,清理逻辑不工作
|
|
|
|
|
|
|
|
|
|
|
|
**解决方案**:
|
|
|
|
|
|
1. **修复VACUUM事务错误**:
|
|
|
|
|
|
- 将VACUUM移到事务之外执行
|
|
|
|
|
|
- 先删除记录,再执行VACUUM
|
|
|
|
|
|
|
|
|
|
|
|
2. **修复NULL值转换错误**:
|
|
|
|
|
|
- 使用 `sql.NullString` 和 `sql.NullFloat64` 类型
|
|
|
|
|
|
- 检查 `Valid` 字段判断是否为NULL
|
|
|
|
|
|
- 只在有记录时才查询时间范围
|
|
|
|
|
|
|
|
|
|
|
|
3. **修复过期清理策略**:
|
|
|
|
|
|
- 当cleanupTTL为0时,清理所有记录
|
|
|
|
|
|
- 添加条件判断:`if c.cleanupTTL == 0 { ... }`
|
|
|
|
|
|
|
|
|
|
|
|
**技术细节**:
|
|
|
|
|
|
```go
|
|
|
|
|
|
// 修复VACUUM事务错误
|
|
|
|
|
|
func (c *SQLiteCache) Clear(ctx context.Context) error {
|
|
|
|
|
|
// 先删除所有记录
|
|
|
|
|
|
_, err := c.db.ExecContext(ctx, `DELETE FROM translation_cache`)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return fmt.Errorf("清空缓存失败: %w", err)
|
|
|
|
|
|
}
|
|
|
|
|
|
// 然后执行VACUUM(不能在事务中执行)
|
|
|
|
|
|
_, err = c.db.ExecContext(ctx, `VACUUM`)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return fmt.Errorf("清理数据库失败: %w", err)
|
|
|
|
|
|
}
|
|
|
|
|
|
return nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 修复NULL值转换错误
|
|
|
|
|
|
var oldestStr, newestStr sql.NullString
|
|
|
|
|
|
var avgTokens sql.NullFloat64
|
|
|
|
|
|
err = c.db.QueryRowContext(ctx, `SELECT MIN(created_at), MAX(created_at), AVG(total_tokens) FROM translation_cache`).Scan(&oldestStr, &newestStr, &avgTokens)
|
|
|
|
|
|
|
|
|
|
|
|
if oldestStr.Valid {
|
|
|
|
|
|
stats.OldestRecord, _ = time.Parse("2006-01-02 15:04:05", oldestStr.String)
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
**关联文档**:
|
|
|
|
|
|
- [changelog.md#0.5.1](changelog.md#051)
|
2026-04-06 05:07:36 +08:00
|
|
|
|
- [memory.md#本地缓存实现经验](memory.md#本地缓存实现经验)
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
### [2026-04-06 10:00] 版本 0.6.0 - TUI界面模块拆分计划
|
|
|
|
|
|
**原因**: 当前TUI目录(tui/components、tui/theme)已创建但完全为空,需要从零实现终端交互界面
|
|
|
|
|
|
**分析**:
|
|
|
|
|
|
- 采用分模块逐步实现策略,减少Token消耗和上下文负担
|
|
|
|
|
|
- 每次只实现一个模块,完成后再进入下一个
|
|
|
|
|
|
- 讨论内容仅保存到taolun.md/changelog.md/memory.md,不新增md文件
|
|
|
|
|
|
|
|
|
|
|
|
**解决方案 - TUI模块拆分**:
|
|
|
|
|
|
|
|
|
|
|
|
| 步骤 | 模块 | 内容 | 预计工作量 |
|
|
|
|
|
|
|------|------|------|-----------|
|
|
|
|
|
|
| 1 | TUI框架搭建 | 选择库(bubbletea)、基础App结构、运行循环 | 小 |
|
|
|
|
|
|
| 2 | 输入组件 | 文本输入框、光标、基础编辑 | 中 |
|
|
|
|
|
|
| 3 | 翻译显示区 | 结果展示、格式化、滚动 | 中 |
|
|
|
|
|
|
| 4 | 状态栏/主题 | 底部状态栏、语言选择、主题配色 | 小 |
|
|
|
|
|
|
| 5 | 快捷键系统 | 退出、清空、切换语言等 | 小 |
|
|
|
|
|
|
| 6 | 集成翻译 | 对接现有Translator、加载动画 | 中 |
|
|
|
|
|
|
|
|
|
|
|
|
**技术选型**:
|
|
|
|
|
|
- 优先使用 `charmbracelet/bubbletea` (Elm架构、Go生态最流行)
|
|
|
|
|
|
- 配合 `charmbracelet/lipgloss` 实现样式和主题
|
|
|
|
|
|
- 配合 `charmbracelet/bubbles/textinput` 实现输入框
|
|
|
|
|
|
|
|
|
|
|
|
**当前状态**: ✅ 模块1已完成,模块2待实现
|
|
|
|
|
|
|
|
|
|
|
|
**关联文档**:
|
|
|
|
|
|
- [changelog.md#0.6.0](changelog.md#060)
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
### [2026-04-06 10:30] 版本 0.6.0 - 模块1: TUI框架搭建 (已完成)
|
|
|
|
|
|
**原因**: 实现TUI界面的第一步,建立基础框架结构
|
|
|
|
|
|
**分析**:
|
|
|
|
|
|
- 需要创建基本的App结构和model
|
|
|
|
|
|
- 需要支持config和translator的注入
|
|
|
|
|
|
- 需要修复main.go中版本检查顺序问题
|
|
|
|
|
|
|
|
|
|
|
|
**解决方案**:
|
|
|
|
|
|
1. 创建 `internal/tui/app.go` 基础文件
|
|
|
|
|
|
2. 定义model结构体,包含config和translator字段
|
|
|
|
|
|
3. 实现Init/Update/View三个基本方法
|
|
|
|
|
|
4. 添加bubbletea、bubbles、lipgloss依赖
|
|
|
|
|
|
5. 修复main.go中--version在interactive之前检查
|
|
|
|
|
|
|
|
|
|
|
|
**技术实现**:
|
|
|
|
|
|
```go
|
|
|
|
|
|
type model struct {
|
|
|
|
|
|
config *config.Config
|
|
|
|
|
|
translator *translator.Translator
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func NewApp(cfg *config.Config, t *translator.Translator) *tea.Program {
|
|
|
|
|
|
return tea.NewProgram(model{...})
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
**下一步**: 实现模块2: 输入组件
|
|
|
|
|
|
|
2026-04-06 05:10:00 +08:00
|
|
|
|
**关联文档**:
|
|
|
|
|
|
- [changelog.md#0.6.0](changelog.md#060)
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
### [2026-04-06 11:00] 版本 0.6.0 - 模块2: 输入组件 (已完成)
|
|
|
|
|
|
**原因**: 实现TUI输入功能
|
|
|
|
|
|
**分析**:
|
|
|
|
|
|
- 使用bubbletea的textinput组件
|
|
|
|
|
|
- 需要焦点管理和键盘事件处理
|
|
|
|
|
|
|
|
|
|
|
|
**解决方案**:
|
|
|
|
|
|
1. 添加textinput字段到model
|
|
|
|
|
|
2. 初始化时设置placeholder和prompt
|
|
|
|
|
|
3. Update中处理KeyMsg
|
|
|
|
|
|
4. View中渲染输入框
|
|
|
|
|
|
5. 支持Ctrl+C和Esc退出
|
|
|
|
|
|
|
|
|
|
|
|
**技术实现**:
|
|
|
|
|
|
```go
|
|
|
|
|
|
type model struct {
|
|
|
|
|
|
textInput textinput.Model
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|
|
|
|
|
switch msg := msg.(type) {
|
|
|
|
|
|
case tea.KeyMsg:
|
|
|
|
|
|
if msg.Type == tea.KeyCtrlC || msg.Type == tea.KeyEsc {
|
|
|
|
|
|
return m, tea.Quit
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
m.textInput, cmd = m.textInput.Update(msg)
|
|
|
|
|
|
return m, cmd
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
**下一步**: 实现模块3: 翻译显示区
|
|
|
|
|
|
|
2026-04-06 05:11:23 +08:00
|
|
|
|
**关联文档**:
|
|
|
|
|
|
- [changelog.md#0.6.0](changelog.md#060)
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
### [2026-04-06 11:30] 版本 0.6.0 - 模块3: 翻译显示区 (已完成)
|
|
|
|
|
|
**原因**: 添加翻译结果显示区域
|
|
|
|
|
|
**分析**:
|
|
|
|
|
|
- 需要定义结果展示区域
|
|
|
|
|
|
- 需要为不同区域定义不同样式
|
|
|
|
|
|
|
|
|
|
|
|
**解决方案**:
|
|
|
|
|
|
1. 添加result字段到model
|
|
|
|
|
|
2. 定义headerStyle、resultStyle、helpStyle
|
|
|
|
|
|
3. 实现renderResult()辅助方法
|
|
|
|
|
|
4. View中组合各个区域
|
|
|
|
|
|
|
|
|
|
|
|
**下一步**: 实现模块4: 状态栏/主题
|
|
|
|
|
|
|
2026-04-06 05:13:24 +08:00
|
|
|
|
**关联文档**:
|
|
|
|
|
|
- [changelog.md#0.6.0](changelog.md#060)
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
### [2026-04-06 12:00] 版本 0.6.0 - 模块4: 状态栏/主题 (已完成)
|
|
|
|
|
|
**原因**: 添加底部状态栏和主题配色
|
|
|
|
|
|
**分析**:
|
|
|
|
|
|
- 需要显示当前目标语言
|
|
|
|
|
|
- 需要完善配色方案
|
|
|
|
|
|
- 需要定义状态栏样式
|
|
|
|
|
|
|
|
|
|
|
|
**解决方案**:
|
|
|
|
|
|
1. 添加targetLang字段到model
|
|
|
|
|
|
2. 定义statusBarStyle、langStyle等新样式
|
|
|
|
|
|
3. 实现renderStatusBar()方法
|
|
|
|
|
|
4. View中渲染状态栏
|
|
|
|
|
|
|
|
|
|
|
|
**下一步**: 实现模块5: 快捷键系统
|
|
|
|
|
|
|
2026-04-06 05:15:24 +08:00
|
|
|
|
**关联文档**:
|
|
|
|
|
|
- [changelog.md#0.6.0](changelog.md#060)
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
### [2026-04-06 12:30] 版本 0.6.0 - 模块5: 快捷键系统 (已完成)
|
|
|
|
|
|
**原因**: 添加键盘快捷键提升用户体验
|
|
|
|
|
|
**分析**:
|
|
|
|
|
|
- 需要常用操作快捷键
|
|
|
|
|
|
- 需要清晰显示快捷键提示
|
|
|
|
|
|
|
|
|
|
|
|
**解决方案**:
|
|
|
|
|
|
1. 添加Ctrl+L: 清空输入和结果
|
|
|
|
|
|
2. 添加Ctrl+T: 循环切换语言
|
|
|
|
|
|
3. 添加keyStyle样式高亮快捷键
|
|
|
|
|
|
4. 更新帮助提示显示所有快捷键
|
|
|
|
|
|
|
|
|
|
|
|
**快捷键列表**:
|
|
|
|
|
|
- `Ctrl+L`: 清空输入框和翻译结果
|
|
|
|
|
|
- `Ctrl+T`: 循环切换目标语言 (zh-CN→en-US→ja→ko→...)
|
|
|
|
|
|
- `Ctrl+C`/`Esc`: 退出程序
|
|
|
|
|
|
- `Enter`: 翻译 (后续模块实现)
|
|
|
|
|
|
|
|
|
|
|
|
**下一步**: 实现模块6: 集成翻译
|
|
|
|
|
|
|
2026-04-06 05:18:11 +08:00
|
|
|
|
**关联文档**:
|
|
|
|
|
|
- [changelog.md#0.6.0](changelog.md#060)
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
### [2026-04-06 13:00] 版本 0.6.0 - 模块6: 集成翻译 (已完成)
|
|
|
|
|
|
**原因**: 将Translator集成到TUI,实现真正的翻译功能
|
|
|
|
|
|
**分析**:
|
|
|
|
|
|
- 需要在Enter键时调用翻译API
|
|
|
|
|
|
- 需要异步执行避免阻塞UI
|
|
|
|
|
|
- 需要显示loading状态和错误处理
|
|
|
|
|
|
|
|
|
|
|
|
**解决方案**:
|
|
|
|
|
|
1. 添加translateMsg消息类型处理异步结果
|
|
|
|
|
|
2. 添加loading和errMsg字段
|
|
|
|
|
|
3. 实现doTranslate()函数执行异步翻译
|
|
|
|
|
|
4. Update中处理translateMsg消息
|
|
|
|
|
|
5. View中显示loading状态或错误信息
|
|
|
|
|
|
|
|
|
|
|
|
**技术实现**:
|
|
|
|
|
|
```go
|
|
|
|
|
|
type translateMsg struct {
|
|
|
|
|
|
result string
|
|
|
|
|
|
err error
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (m model) doTranslate(text, toLang string) tea.Cmd {
|
|
|
|
|
|
return func() tea.Msg {
|
|
|
|
|
|
result, err := m.translator.Translate(...)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return translateMsg{err: err}
|
|
|
|
|
|
}
|
|
|
|
|
|
return translateMsg{result: result.Translated}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
**下一步**: 测试TUI界面、优化体验
|
|
|
|
|
|
|
2026-04-06 05:07:36 +08:00
|
|
|
|
**关联文档**:
|
2026-04-06 05:39:21 +08:00
|
|
|
|
- [changelog.md#0.6.0](changelog.md#060)
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
### [2026-04-06 14:00] 版本 0.7.0 - TUI界面改进计划
|
|
|
|
|
|
**原因**: TUI基础功能完成后,讨论改进方向和用户体验优化
|
|
|
|
|
|
**分析**:
|
|
|
|
|
|
- 当前单行textinput无法输入多行文本
|
|
|
|
|
|
- 快捷键固定显示在底部不够美观
|
|
|
|
|
|
- 缺少命令菜单系统
|
|
|
|
|
|
- 长翻译结果无法滚动
|
|
|
|
|
|
|
|
|
|
|
|
**解决方案 - 新增模块**:
|
|
|
|
|
|
|
|
|
|
|
|
| 步骤 | 模块 | 内容 |
|
|
|
|
|
|
|------|------|------|
|
|
|
|
|
|
| 7 | 多行输入 | textarea组件替换textinput |
|
|
|
|
|
|
| 8 | 弹出框组件 | 通用modal,支持快捷键帮助 |
|
|
|
|
|
|
| 9 | 斜杠命令菜单 | / 触发命令选择器,类似opencode |
|
|
|
|
|
|
| 10 | 翻译结果滚动 | viewport组件 |
|
|
|
|
|
|
| 11 | 复制功能 | clipboard集成 |
|
|
|
|
|
|
| 12 | 状态栏扩展 | 耗时、token用量 |
|
|
|
|
|
|
|
|
|
|
|
|
**斜杠命令设计**:
|
|
|
|
|
|
| 命令 | 功能 |
|
|
|
|
|
|
|------|------|
|
|
|
|
|
|
| `/help` | 显示快捷键帮助 |
|
|
|
|
|
|
| `/clear` | 清空内容 |
|
|
|
|
|
|
| `/copy` | 复制翻译结果 |
|
|
|
|
|
|
| `/lang` | 切换语言 |
|
|
|
|
|
|
| `/history` | 翻译历史 |
|
|
|
|
|
|
| `/quit` | 退出 |
|
|
|
|
|
|
|
|
|
|
|
|
**设计亮点**:
|
|
|
|
|
|
1. 隐藏底部快捷键提示,改为按 ? 或 F1 弹出帮助框
|
|
|
|
|
|
2. 输入 / 触发命令菜单,上下键选择,回车执行
|
|
|
|
|
|
3. 命令菜单支持模糊匹配
|
|
|
|
|
|
4. modal组件通用化,可复用于其他弹窗场景
|
|
|
|
|
|
|
|
|
|
|
|
**关联文档**:
|
|
|
|
|
|
- [changelog.md#0.7.0](changelog.md#070)
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
### [2026-04-06 14:30] 版本 0.7.0 - 模块7: 多行输入 (已完成)
|
|
|
|
|
|
**原因**: 当前textinput只支持单行,需要支持多行文本输入
|
|
|
|
|
|
**分析**:
|
|
|
|
|
|
- 长段落、多行文本无法输入
|
|
|
|
|
|
- 需要换用bubbles的textarea组件
|
|
|
|
|
|
|
|
|
|
|
|
**解决方案**:
|
|
|
|
|
|
1. 将textinput替换为textarea
|
|
|
|
|
|
2. 调整样式和布局(宽50,高5)
|
|
|
|
|
|
3. 底部状态栏提示按 / 显示命令
|
|
|
|
|
|
|
|
|
|
|
|
**技术实现**:
|
|
|
|
|
|
- 使用 `github.com/charmbracelet/bubbles/textarea`
|
|
|
|
|
|
- textarea.SetWidth(50)、SetHeight(5) 设置尺寸
|
|
|
|
|
|
- 移除底部固定快捷键提示,改为按需显示
|
2026-04-06 05:43:40 +08:00
|
|
|
|
- 隐藏行号: `ShowLineNumbers = false`
|
|
|
|
|
|
- 移除左侧提示符: `Prompt = ""`
|
|
|
|
|
|
- Enter执行翻译,Ctrl+J换行
|
2026-04-06 05:39:21 +08:00
|
|
|
|
|
|
|
|
|
|
**下一步**: 实现模块8: 弹出框组件
|
|
|
|
|
|
|
|
|
|
|
|
**关联文档**:
|
2026-04-07 04:47:58 +08:00
|
|
|
|
- [changelog.md#0.7.0](changelog.md#070)
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
### [2026-04-06 15:00] 版本 0.8.0 - TUI重构: 聊天风格界面
|
|
|
|
|
|
**原因**: 用户希望使用类似 charmbracelet/crush 的聊天风格界面
|
|
|
|
|
|
**分析**:
|
|
|
|
|
|
- 当前界面:标题在上 → 输入框在中 → 结果在下
|
|
|
|
|
|
- 期望界面:标题在上 → 聊天消息区域(可滚动历史)→ 输入框固定底部 → 状态栏最底部
|
|
|
|
|
|
- 原文+译文成对显示,类似聊天软件
|
|
|
|
|
|
|
|
|
|
|
|
**解决方案**:
|
|
|
|
|
|
1. 界面布局重构:
|
|
|
|
|
|
```
|
|
|
|
|
|
┌─────────────────────────────────────────┐
|
|
|
|
|
|
│ ✦ YOYO 翻译 [Ctrl+C退出] │
|
|
|
|
|
|
├─────────────────────────────────────────┤
|
|
|
|
|
|
│ (聊天消息区域,可滚动查看历史) │
|
|
|
|
|
|
│ ── 用户输入 ── │
|
|
|
|
|
|
│ Hello world │
|
|
|
|
|
|
│ ── 翻译结果 ── │
|
|
|
|
|
|
│ 你好世界 │
|
|
|
|
|
|
│ ... │
|
|
|
|
|
|
├─────────────────────────────────────────┤
|
|
|
|
|
|
│ 输入框... [回车] │
|
|
|
|
|
|
├─────────────────────────────────────────┤
|
|
|
|
|
|
│ 目标:zh-CN │ 模型:gpt-3.5 │ Tokens:125 │
|
|
|
|
|
|
└─────────────────────────────────────────┘
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
2. 技术方案:
|
|
|
|
|
|
- 消息结构:原文+译文成对显示
|
|
|
|
|
|
- 底部固定输入框(textarea)
|
|
|
|
|
|
- 状态栏显示完整信息
|
|
|
|
|
|
- Ctrl+J 换行,Enter 发送
|
|
|
|
|
|
- 自动调整输入框高度
|
|
|
|
|
|
|
|
|
|
|
|
**下一步**: 模块1: 创建TUI模块结构
|
|
|
|
|
|
|
|
|
|
|
|
**关联文档**:
|
|
|
|
|
|
- [changelog.md#0.8.0](changelog.md#080)
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
### [2026-04-06 16:00] 版本 0.8.0 - 输入框踩坑与修复
|
|
|
|
|
|
**原因**: Ctrl+J换行后第一行被遮住,显示错乱
|
|
|
|
|
|
**分析**:
|
|
|
|
|
|
- 换行后 textarea 内部渲染3行但只显示2行
|
|
|
|
|
|
- 第一行内容往上滚动被遮住,光标在第2行,第3行是空行
|
|
|
|
|
|
- 尝试多种方案均无效:移除Width限制、设置SetWidth/SetHeight顺序、动态调整高度
|
|
|
|
|
|
|
|
|
|
|
|
**解决方案**:
|
|
|
|
|
|
1. 放弃动态调整高度方案,固定高度为5行
|
|
|
|
|
|
2. 超过5行时textarea内部自动滚动,光标始终可见
|
|
|
|
|
|
|
|
|
|
|
|
**技术细节**:
|
|
|
|
|
|
- textarea内部使用viewport组件,频繁SetHeight导致滚动位置错乱
|
|
|
|
|
|
- 使用 FocusedStyle/BlurredStyle + Style.Base 设置背景色
|
|
|
|
|
|
|
|
|
|
|
|
**代码变更**:
|
|
|
|
|
|
```go
|
|
|
|
|
|
ta.SetWidth(60)
|
|
|
|
|
|
ta.SetHeight(5) // 固定高度,不动态调整
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
**下一步**: 完善其他UI功能
|
|
|
|
|
|
|
|
|
|
|
|
**关联文档**:
|
|
|
|
|
|
- [memory.md#TUI输入框踩坑记录](memory.md#tui输入框踩坑记录)
|
|
|
|
|
|
- [changelog.md#0.8.0](changelog.md#080)
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
### [2026-04-07 10:00] 版本 0.8.1 - 翻译结果卡片组件设计
|
|
|
|
|
|
**原因**: 用户希望改进翻译结果显示样式,使用lipgloss构建更美观的组件
|
|
|
|
|
|
**分析**:
|
|
|
|
|
|
- 当前翻译结果显示比较简单,只有标签和内容
|
|
|
|
|
|
- 需要设计一个结构化的翻译卡片组件
|
|
|
|
|
|
- 组件需要显示Tokens、翻译时间、模型名称等元信息
|
|
|
|
|
|
|
|
|
|
|
|
**解决方案**:
|
|
|
|
|
|
1. **卡片组件结构**:
|
|
|
|
|
|
```
|
|
|
|
|
|
┌─ 标题栏 ─────────────────────────────────────────┐
|
|
|
|
|
|
│ Tokens: 150 │ 耗时: 1.2s │ 模型: gpt-4 │
|
|
|
|
|
|
└─────────────────────────────────────────────────┘
|
|
|
|
|
|
┌─ 用户输入 ───────────────────────────────────────┐
|
|
|
|
|
|
│ ██████████ 碳黑背景 ████████████████████████████ │
|
|
|
|
|
|
└─────────────────────────────────────────────────┘
|
|
|
|
|
|
┌─ 翻译结果 ───────────────────────────────────────┐
|
|
|
|
|
|
│ AI 翻译的文本内容... │
|
|
|
|
|
|
└─────────────────────────────────────────────────┘
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
2. **技术实现**:
|
|
|
|
|
|
- 使用 lipgloss.Div() 和 lipgloss.JoinVertical() 构建组件
|
|
|
|
|
|
- 背景色: #1A1A1A (碳黑色)
|
|
|
|
|
|
- 用户输入区域: 纯背景色,无边框
|
|
|
|
|
|
- 组件间距: 5px marginBottom
|
|
|
|
|
|
|
|
|
|
|
|
3. **样式定义**:
|
|
|
|
|
|
- CardStyle: 卡片容器,marginBottom(5)
|
|
|
|
|
|
- CardMetaStyle: 元信息行样式,#6B7280 灰色
|
|
|
|
|
|
- CardInputStyle: 用户输入,#1A1A1A 背景 + #E5E7EB 文字
|
|
|
|
|
|
- CardOutputStyle: 翻译结果,白色文字
|
|
|
|
|
|
|
|
|
|
|
|
**下一步**: 实现组件代码
|
|
|
|
|
|
|
|
|
|
|
|
**关联文档**:
|
2026-04-07 07:12:00 +08:00
|
|
|
|
- [changelog.md#0.8.1](changelog.md#081)
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
### [2026-04-07] 版本 1.0.0-beta - Logo和信息栏改造
|
|
|
|
|
|
|
|
|
|
|
|
**原因**: 用户希望改进TUI界面的视觉效果,使标题更独特,输入框和信息栏更美观
|
|
|
|
|
|
|
|
|
|
|
|
**分析**:
|
|
|
|
|
|
- 原标题 "✦ YOYO 翻译" 过于简单
|
|
|
|
|
|
- 输入框需要更好的视觉分隔
|
|
|
|
|
|
- 需要添加翻译状态动画
|
|
|
|
|
|
|
|
|
|
|
|
**解决方案**:
|
|
|
|
|
|
1. **标题Logo**:
|
|
|
|
|
|
- 使用ASCII艺术 "l_ _ _____ _____"
|
|
|
|
|
|
- 实现紫色→粉色渐变效果 (ANSI True Color)
|
|
|
|
|
|
- 右侧显示版本号 [v1.0.0-beta]
|
|
|
|
|
|
|
|
|
|
|
|
2. **输入框改造**:
|
|
|
|
|
|
- 去掉边框
|
|
|
|
|
|
- 上下使用紫色 `:::` 分隔符
|
|
|
|
|
|
- Ctrl+J 启用换行
|
|
|
|
|
|
|
|
|
|
|
|
3. **信息栏改造**:
|
|
|
|
|
|
- 合并显示:语言(红色) + 模型名(白色) + 缓存记录(碳黑)
|
|
|
|
|
|
- 翻译时显示 Spinner 动画 (MiniDot)
|
|
|
|
|
|
|
|
|
|
|
|
4. **翻译卡片优化**:
|
|
|
|
|
|
- `▣` 图标边距调整
|
|
|
|
|
|
|
|
|
|
|
|
**版本号规则**:
|
|
|
|
|
|
- 版本号需与 git 标签、changelog.md 中的版本号保持三方同步
|
|
|
|
|
|
- 遵循语义化版本:主版本.次版本.修订版本
|
|
|
|
|
|
- beta版使用 `-beta` 后缀
|
|
|
|
|
|
|
2026-04-07 23:51:33 +08:00
|
|
|
|
**关联版本**: [changelog.md#1.0.0-beta](changelog.md#100-beta-2026-04-07)
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
### [2026-04-07] 版本 1.1.0 - 配置路径修复和huh迁移
|
|
|
|
|
|
|
|
|
|
|
|
**原因**:
|
|
|
|
|
|
1. 管道模式下(如 `cd /docs && cat readme.md | yoyo`)找不到配置文件
|
|
|
|
|
|
2. onboard配置保存到错误的相对路径
|
|
|
|
|
|
3. 希望用 `charmbracelet/huh` 替代 `survey` 获得更好的UX
|
|
|
|
|
|
|
|
|
|
|
|
**分析**:
|
|
|
|
|
|
- 所有配置路径硬编码为 `configs/config.yaml`(相对CWD)
|
|
|
|
|
|
- 从不同目录运行程序时路径解析失败
|
|
|
|
|
|
- survey库API较老,huh提供更现代的表单体验
|
|
|
|
|
|
|
|
|
|
|
|
**解决方案**:
|
|
|
|
|
|
1. 新增 `internal/config/path.go` 路径解析工具
|
|
|
|
|
|
2. 配置查找优先级:`--config` > `~/.config/yoyo/config.yaml` > `./configs/config.yaml`
|
|
|
|
|
|
3. onboard保存到 `~/.config/yoyo/config.yaml`
|
|
|
|
|
|
4. .env从 `~/.config/yoyo/.env` 加载
|
|
|
|
|
|
5. onboard使用huh重写:Form+Group模式,链式API,泛型支持
|
|
|
|
|
|
|
|
|
|
|
|
**技术细节**:
|
|
|
|
|
|
```go
|
|
|
|
|
|
// 路径解析
|
|
|
|
|
|
config.ResolveConfigPath(userPath) // 智能查找配置
|
|
|
|
|
|
config.GetUserConfigPath() // ~/.config/yoyo/config.yaml
|
|
|
|
|
|
config.GetUserEnvPath() // ~/.config/yoyo/.env
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
**huh迁移要点**:
|
|
|
|
|
|
- `survey.Select` → `huh.NewSelect[string]().Options(huh.NewOption(...)...)`
|
|
|
|
|
|
- `survey.Input` → `huh.NewInput().Value(&var).Validate(fn)`
|
|
|
|
|
|
- `survey.Confirm` → `huh.NewConfirm().Affirmative("是").Negative("否")`
|
|
|
|
|
|
- 分步表单 → `huh.NewForm(huh.NewGroup(...), huh.NewGroup(...))`
|
|
|
|
|
|
|
2026-04-08 01:08:47 +08:00
|
|
|
|
**关联版本**: [changelog.md#1.1.0](changelog.md#110-2026-04-07)
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
### [2026-04-08 00:40] 版本 1.1.1 - Logo模块化与渐变色统一
|
|
|
|
|
|
**原因**:
|
|
|
|
|
|
1. `--help` `-h` `-?` `--version` 在默认交互式模式下无响应
|
|
|
|
|
|
2. 帮助信息头部需要彩色logo展示
|
|
|
|
|
|
|
|
|
|
|
|
**问题分析**:
|
|
|
|
|
|
1. 交互模式判断优先于help/version检查,导致flags被忽略
|
|
|
|
|
|
2. 帮助信息使用硬编码版本号 `YOYO翻译工具 v1.1.0`,无logo
|
|
|
|
|
|
|
|
|
|
|
|
**解决方案**:
|
|
|
|
|
|
1. 修复flag检查顺序:在进入交互模式前先检查 `-h` `--help` `-?` `--version`
|
|
|
|
|
|
2. 新增 `internal/logo/logo.go` 模块统一管理logo
|
|
|
|
|
|
3. 编译时通过 `ldflags` 注入版本号
|
|
|
|
|
|
4. 渐变色使用与TUI一致的紫→青色方案
|
|
|
|
|
|
|
|
|
|
|
|
**技术实现**:
|
|
|
|
|
|
```go
|
|
|
|
|
|
// logo模块核心函数
|
|
|
|
|
|
func GradientText(text string, startColor, endColor string) string { ... }
|
|
|
|
|
|
func GetLogoPattern() string // 返回4行ascii art
|
|
|
|
|
|
func GetVersionSuffix() string // 返回 " (v1.1.1-dirty )" 或 " ( )"
|
|
|
|
|
|
func PrintLogoWithVersion() // 打印完整logo(--help/--version使用)
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
**build.sh版本注入**:
|
|
|
|
|
|
```bash
|
|
|
|
|
|
VERSION=$(git describe --tags --always --dirty 2>/dev/null || echo "")
|
|
|
|
|
|
go build -ldflags "-X github.com/titor/fanyi/internal/logo.version=${VERSION}" -o yoyo ./cmd/yoyo
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
**TUI整合**:
|
|
|
|
|
|
- 移除 `internal/tui/model.go` 中的本地 `logoPattern` 和 `gradientText`
|
|
|
|
|
|
- 直接调用 `logo.GradientText(logo.GetLogoPattern(), "#B413DC", "#00C8C8")`
|
|
|
|
|
|
- 移除 `[Ctrl+C 退出]` 显示
|
|
|
|
|
|
|
|
|
|
|
|
**最终输出格式**(所有位置统一):
|
|
|
|
|
|
```
|
|
|
|
|
|
_ _ _____ _____
|
|
|
|
|
|
( \/ ( _ ( _ )
|
|
|
|
|
|
\ / )(_)( )(_)(
|
|
|
|
|
|
(__)(_____(_____( v1.1.1-dirty )
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
**关联版本**: [changelog.md#1.1.1](changelog.md#111-2026-04-08)
|