- 实现文本转语音功能(支持多种音色) - 支持流式输出(--stream)和直接播放(--play) - 实现自动语气转换器(根据标点自动添加语气标签) - 使用 crossterm 美化 CLI 输出 - 配置分层设计(项目配置 + 用户配置) - 独立模块划分:api.rs, cli.rs, config.rs, tone.rs, ui.rs v0.1.0
348 lines
13 KiB
Markdown
348 lines
13 KiB
Markdown
# 讨论记录 (taolun.md)
|
||
|
||
## 2026-04-24 - 项目启动
|
||
|
||
### 用户需求
|
||
基于 Mimo-TTS API 开发 Rust CLI 工具,要求:
|
||
- Rust 编写,单一二进制可执行文件
|
||
- 后期通过 skill 给其他 claw 工具使用
|
||
- CLI 参数调用方式
|
||
- OOP + 设计模式架构
|
||
- 全程中文沟通
|
||
- 详细中文注释
|
||
- 每次操作前先更新文档
|
||
|
||
### API 信息
|
||
- Endpoint: `POST https://api.xiaomimimo.com/v1/chat/completions`
|
||
- 认证:双 Header (`api-key` + `Authorization: Bearer`)
|
||
- 音频格式:WAV(Base64 编码)
|
||
|
||
---
|
||
|
||
## 2026-04-24 - 实施记录
|
||
|
||
### 第一轮完成
|
||
1. ✅ 创建三个文档(taolun.md、changelog.md、agents.md)
|
||
2. ✅ 配置 Rust 国内源(稀疏索引协议)
|
||
3. ✅ 实现项目代码(config.rs、api.rs、cli.rs、main.rs)
|
||
4. ✅ Debug + Release 构建成功
|
||
5. ✅ 基本功能测试通过
|
||
|
||
### 第二轮修改
|
||
**用户新增需求:**
|
||
1. **project.config.toml**: 项目根目录,含 version,与 git version 一致
|
||
2. **统一配置路径**:所有平台使用 `~/.config/tts/config.toml`
|
||
3. **API Key**: sk-csa6s3bvpwqw21zfs3urbmqgrw720eoa1qdz6o42abk5xoj8
|
||
4. **onboard 命令**:CLI 引导式配置初始化
|
||
|
||
**执行内容:**
|
||
1. ✅ 创建 `project.config.toml` (version = "0.1.0")
|
||
2. ✅ 修改 `Cargo.toml`(移除 dirs,添加 home 依赖)
|
||
3. ✅ 修改 `config.rs`(统一路径为 `~/.config/tts/config.toml`)
|
||
4. ✅ 修改 `cli.rs`(添加 Onboard 子命令)
|
||
5. ✅ 修改 `main.rs`(处理 Onboard,恢复 main() 函数)
|
||
6. ✅ 配置 API Key 成功
|
||
7. ✅ 语音合成测试成功(test.wav、final_test.wav)
|
||
8. ✅ Release 构建成功(无警告)
|
||
|
||
### 踩坑记录
|
||
1. **Cargo 国内源超时**
|
||
- 解决:改用稀疏索引协议(sparse+https://)
|
||
|
||
2. **clap derive 模式缺少 Parser trait 导入**
|
||
- 解决:添加 `use clap::Parser;`
|
||
|
||
3. **main() 函数丢失**
|
||
- 原因:编辑时不小心删除
|
||
- 解决:恢复 main() 函数和 ExitCode 枚举
|
||
|
||
4. **配置文件路径统一**
|
||
- 需求:所有平台使用 `~/.config/tts/config.toml`
|
||
- 解决:使用 home 库获取家目录,手动拼接路径
|
||
|
||
### 项目最终状态
|
||
- **位置**: /Users/titor/tts
|
||
- **二进制**: target/release/mimo-tts (4.5MB)
|
||
- **配置**: ~/.config/tts/config.toml(已配置 API Key)
|
||
- **项目配置**: project.config.toml (version = "0.1.0")
|
||
- **功能**:
|
||
- ✅ TTS 语音合成
|
||
- ✅ 配置管理(config set/show)
|
||
- ✅ 引导式配置(onboard)
|
||
- ✅ 列出音色(voices)
|
||
- **架构**: Builder 模式 + Singleton 模式 + OOP
|
||
|
||
### 退出码规范
|
||
- 0: 成功
|
||
- 1: 参数错误
|
||
- 2: 配置错误
|
||
- 3: API 调用失败
|
||
- 4: 文件操作失败
|
||
|
||
## 2026-04-24 - 第三轮修改
|
||
|
||
### 用户新需求
|
||
**不要保存语音到本地,使用流式数据输出**
|
||
- 语音数据直接输出到 stdout(二进制流)
|
||
- 便于其他程序通过管道读取
|
||
- 更适合作为 claw skill 集成
|
||
|
||
### 修改计划
|
||
1. 修改 `synthesize()` 函数,返回音频数据而不是保存文件
|
||
2. 修改 `main.rs`,支持输出到 stdout(二进制模式)
|
||
3. 保留可选的 `--output` 参数用于保存到文件(向后兼容)
|
||
4. 当输出到 stdout 时,不输出其他文本信息(避免污染二进制流)
|
||
5. 流式调用可能需要使用 pcm16 格式(根据 API 文档)
|
||
|
||
|
||
## 2026-04-24 - 第四轮修改
|
||
|
||
### 用户新需求
|
||
**添加音频播放功能**
|
||
- 使用 rodio 库直接播放音频
|
||
- 添加 --play 参数触发播放模式
|
||
- 默认单次播放,不循环
|
||
- 保留 --output 和 stdout 输出功能
|
||
|
||
### 技术选型
|
||
- HTTP 客户端:reqwest(已使用)
|
||
- 异步运行时:tokio(已使用)
|
||
- 音频播放:rodio 0.19
|
||
- WAV 处理:无需额外库(rodio 直接支持)
|
||
|
||
## 2026-04-24 - 第四轮实施完成
|
||
|
||
### 已完成
|
||
1. ✅ 修改 Cargo.toml 添加 rodio 0.19 依赖
|
||
2. ✅ 修改 cli.rs 添加 --play 参数
|
||
3. ✅ 修改 main.rs:
|
||
- synthesize() 返回 Vec<u8>(音频数据)
|
||
- 添加 play_audio() 函数(使用 rodio 播放)
|
||
- 修改 run() 支持三种输出方式(播放/保存/stdout)
|
||
4. ✅ 修复编译错误(synthesize() 重复代码、未使用导入)
|
||
5. ✅ 修复 stdout 输出污染问题(移除 synthesize() 中的 println)
|
||
6. ✅ Release 构建成功(无警告)
|
||
7. ✅ 功能测试通过:
|
||
- --play 播放音频 ✅
|
||
- --output 保存文件 ✅
|
||
- stdout 二进制流输出 ✅
|
||
|
||
### 最终项目状态
|
||
- 二进制文件:target/release/mimo-tts (约 6MB,包含 rodio)
|
||
- 支持三种输出方式:播放、保存、流式输出
|
||
- 所有功能测试通过
|
||
|
||
## 2026-04-24 - 第五轮修改
|
||
|
||
### 用户确认需求
|
||
**扩展音色支持**
|
||
1. ✅ 更新音色列表为 Mimo-TTS 完整列表(8个音色)
|
||
2. ✅ 默认音色从 default_zh 改为 mimo_default
|
||
3. ✅ 添加音色验证,无效时使用默认音色
|
||
4. ✅ 废弃 default_zh 和 default_en
|
||
|
||
### 完整音色列表
|
||
| Voice ID | 语言 | 性别 | 说明 |
|
||
|----------|------|------|------|
|
||
| mimo_default | 多语言 | - | MiMo默认(中国集群=冰糖)|
|
||
| 冰糖 | 中文 | 女性 | 甜美清脆的女声 |
|
||
| 茉莉 | 中文 | 女性 | 温柔知性的女声 |
|
||
| 苏打 | 中文 | 男性 | 阳光活力的男声 |
|
||
| 白桦 | 中文 | 男性 | 沉稳大气的男声 |
|
||
| Mia | 英文 | 女性 | Sweet and gentle female |
|
||
| Chloe | 英文 | 女性 | Warm and articulate female |
|
||
| Milo | 英文 | 男性 | Energetic young male |
|
||
| Dean | 英文 | 男性 | Deep and steady male |
|
||
|
||
## 2026-04-24 - 第五轮修改(修复)
|
||
|
||
### 问题修复
|
||
- **默认音色未生效**:config.rs 中 `default_voice()` 函数返回值仍是 `default_zh`
|
||
- 修复:将 `config.rs:39` 默认值改为 `mimo_default`
|
||
- 更新配置文件 `~/.config/tts/config.toml` 中的 `default_voice`
|
||
- 验证:show-config 现在正确显示 `mimo_default`
|
||
|
||
## 2026-04-24 - 第六轮修改
|
||
|
||
### 用户需求
|
||
**UI 主题化所有 CLI 输出**
|
||
1. 使用 ratatui + crossterm 美化 CLI 输出
|
||
2. onboard 改为完整表单页面(同时显示所有配置项)
|
||
3. API Key 输入支持隐藏(显示 * 代替)
|
||
4. 所有命令输出都使用主题美化
|
||
5. 不需要简洁模式
|
||
|
||
### 实施方案
|
||
- 新增 src/ui.rs 模块(主题、组件)
|
||
- 修改 Cargo.toml 添加 ratatui + crossterm
|
||
- 美化 list_voices()、show_config() 输出
|
||
- 重写 onboard() 为完整交互式表单
|
||
- 美化所有命令输出(播放、保存等)
|
||
|
||
### 第六轮实施完成
|
||
1. ✅ 创建 src/ui.rs 模块(使用 crossterm 美化输出)
|
||
2. ✅ 修改 main.rs 引入 ui 模块
|
||
3. ✅ 美化 list_voices() 输出(彩色表格)
|
||
4. ✅ 美化 show_config() 输出(彩色标签)
|
||
5. ✅ 重写 onboard() 为交互式表单(支持密码隐藏输入)
|
||
6. ✅ 美化播放和保存完成消息
|
||
7. ✅ Release 构建成功(仅有未使用代码警告)
|
||
8. ✅ 功能测试通过(voices、show-config)
|
||
|
||
### 技术细节
|
||
- 使用 crossterm 而非完整的 ratatui Terminal(简化实现)
|
||
- 密码输入使用 enable_raw_mode 实现字符隐藏
|
||
- 输出使用颜色主题(PRIMARY、SUCCESS、ERROR 等)
|
||
- show_onboard_form 返回 Result 类型,由调用者处理错误
|
||
|
||
### 第七轮修改
|
||
|
||
### 用户需求
|
||
**配置分层设计**
|
||
1. `project.config.toml` - 项目默认配置(全量配置)
|
||
- version
|
||
- base_url
|
||
- default_format
|
||
2. `~/.config/tts/config.toml` - 用户配置(仅覆盖项)
|
||
- api_key
|
||
- default_voice
|
||
3. 临时文件只允许存放在当前目录下
|
||
|
||
### 实施方案
|
||
- 修改 `project.config.toml` 添加 base_url 和 default_format
|
||
- 重写 `config.rs` 实现分层配置加载
|
||
- 修改 `cli.rs` 移除 base_url 参数
|
||
- 修改 `ui.rs` 简化显示和表单(只处理 api_key 和 default_voice)
|
||
- 修改 `main.rs` 使用新的配置结构
|
||
- 测试时临时文件输出到当前目录
|
||
|
||
### 第七轮实施完成
|
||
1. ✅ 创建分层配置结构(ProjectConfig + UserConfig + Config)
|
||
2. ✅ `project.config.toml` 包含默认配置(base_url、default_format)
|
||
3. ✅ 用户配置只保存 api_key 和 default_voice
|
||
4. ✅ 修改 cli.rs 移除 base_url 参数
|
||
5. ✅ 修改 ui.rs 简化显示和表单
|
||
6. ✅ Release 构建成功(仅有未使用字段警告)
|
||
7. ✅ 功能测试通过(show-config、voices、语音合成)
|
||
8. ✅ 临时文件生成在当前目录
|
||
|
||
### 技术细节
|
||
- ConfigManager 先加载项目配置,再加载用户配置,最后合并
|
||
- save() 只保存 UserConfig(api_key、default_voice)
|
||
- project.config.toml 从当前项目目录读取
|
||
- 用户配置路径:`~/.config/tts/config.toml`
|
||
|
||
## 2026-04-24 - 第八轮修改
|
||
|
||
### 用户反馈
|
||
**使用 --voice 提示失败**
|
||
- 问题:使用 `--voice '茉莉'` 时报错:Unknown voice
|
||
- 原因:之前使用了错误的 API 文档,实际 API 只支持 3 个预置音色
|
||
- 最新发现:mimo-v2.5-tts 模型支持更多音色(9 个)
|
||
- 模型名应为 `mimo-v2.5-tts`(不是 `mimo-v2-tts`)
|
||
|
||
### 音色列表(mimo-v2.5-tts)
|
||
| Voice ID | 语言 | 性别 | 说明 |
|
||
|----------|------|------|------|
|
||
| mimo_default | 多语言 | - | MiMo默认(中国集群=冰糖)|
|
||
| 冰糖 | 中文 | 女性 | 甜美清脆的女声 |
|
||
| 茉莉 | 中文 | 女性 | 温柔知性的女声 |
|
||
| 苏打 | 中文 | 男性 | 阳光活力的男声 |
|
||
| 白桦 | 中文 | 男性 | 沉稳大气的男声 |
|
||
| Mia | 英文 | 女性 | Sweet and gentle female |
|
||
| Chloe | 英文 | 女性 | Warm and articulate female |
|
||
| Milo | 英文 | 男性 | Energetic young male |
|
||
| Dean | 英文 | 男性 | Deep and steady male |
|
||
|
||
### 新增功能
|
||
- `--style` 参数:风格描述(如:开心、东北话、孙悟空、唱歌等)
|
||
- 风格通过 `user` 消息传递(不是 `<style>` 标签)
|
||
- 模型名更新为 `mimo-v2.5-tts`
|
||
|
||
### 第八轮实施完成
|
||
1. ✅ 更新模型名为 `mimo-v2.5-tts`
|
||
2. ✅ 恢复 9 个音色列表
|
||
3. ✅ 添加 `--style` 参数支持
|
||
4. ✅ 修改风格传递方式(用 user 消息而非 `<style>` 标签)
|
||
5. ✅ 修复编译错误(删除多余代码块)
|
||
6. ✅ 测试通过(默认音色、茉莉音色均正常)
|
||
7. ✅ 临时文件生成在当前目录
|
||
|
||
## 2026-04-24 - 第九轮修改
|
||
|
||
### 用户需求
|
||
**实现流式输出功能**
|
||
- `--stream` 参数已在 cli.rs 定义,需要实现
|
||
- 流式输出时格式自动改为 pcm16
|
||
- 使用流式 API 调用(Server-Sent Events)
|
||
- 输出到 stdout(二进制流)
|
||
|
||
### 实施方案
|
||
- 修改 api.rs 添加流式请求方法
|
||
- 使用 reqwest 的流式响应处理
|
||
- 处理 SSE(Server-Sent Events)格式
|
||
- 拼接音频数据后输出到 stdout
|
||
- 如果指定了 --output,则保存到文件
|
||
|
||
### 第九轮实施完成
|
||
|
||
1. ✅ 修改 Cargo.toml 添加依赖(futures、tokio-util、reqwest stream feature)
|
||
2. ✅ 修改 main.rs:
|
||
- synthesize() 函数添加 stream 参数
|
||
- 流式输出时自动使用 pcm16 格式
|
||
- 传递 stream 参数给 API 调用
|
||
- 支持 --stream 和 --play 同时使用(PCM16 转 WAV)
|
||
3. ✅ 修改 api.rs:
|
||
- 修复 read_stream_response 函数(使用 futures::StreamExt)
|
||
- 正确处理 SSE 格式流式响应
|
||
4. ✅ 新增 pcm16_to_wav() 函数(封装 WAV 头)
|
||
5. ✅ Release 构建成功(仅有未使用代码警告)
|
||
6. ✅ 流式输出测试通过(PCM16 数据正常)
|
||
7. ✅ 流式播放测试通过(--stream --play 正常工作)
|
||
|
||
### 技术细节
|
||
- 流式 API 返回原始 PCM16 数据(无 WAV 头)
|
||
- 使用 futures::StreamExt 处理 reqwest 的 bytes_stream()
|
||
- SSE 格式解析:`data: {...}` 和 `data: [DONE]`
|
||
- 每个 chunk 包含 Base64 编码的音频数据
|
||
- PCM16 转 WAV:添加 44 字节 WAV 头(24000Hz, 16bit, mono)
|
||
- --stream 和 --play 同时使用时自动封装 WAV 格式后播放
|
||
|
||
## 2026-04-24 - 第十轮修改
|
||
|
||
### 用户需求
|
||
**实现自动语气转换器(独立模块)**
|
||
- 创建 `src/tone.rs` 独立模块(高内聚低耦合)
|
||
- 默认启用,无需额外参数
|
||
- 根据标点符号自动添加语气标签
|
||
- 支持整体风格标签和细粒度控制标签
|
||
|
||
### 语气映射规则
|
||
|
||
#### 整体风格标签(文本开头)
|
||
- 包含 `!` → `[激动]`
|
||
- 包含 `?` → `[疑惑]`
|
||
- 包含 `。` → `[平静]`(默认)
|
||
- 多种标点组合 → `[激动 疑惑]` 等
|
||
|
||
#### 细粒度控制标签(文本中间)
|
||
- `!` → `!(激动)`
|
||
- `?` → `?(疑惑)`
|
||
- `。` → `。(停顿)`
|
||
- `……` → `……(拖长音)`
|
||
|
||
### 第十轮实施完成
|
||
|
||
1. ✅ 创建 src/tone.rs 模块
|
||
2. ✅ 实现 apply_tone() 函数(整体语气)
|
||
3. ✅ 实现 insert_mid_tone() 函数(细粒度控制)
|
||
4. ✅ 实现 analyze_tone() 函数(分析语气)
|
||
5. ✅ 实现 has_tone_tag() 函数(检测已有标签)
|
||
6. ✅ 修改 main.rs 引入 tone 模块
|
||
7. ✅ 在 synthesize() 中调用语气转换
|
||
8. ✅ Release 构建成功
|
||
9. ✅ 单元测试通过(4 个测试)
|
||
10. ✅ 功能测试通过(激动语气、疑惑语气)
|
||
|
||
## 2026-04-24 - 第十轮修改
|