rtc_prd/阶段总结/session_progress.md
seaislee1209 84243f2be4 feat: TTS语音合成 + 唱片架播放状态 + 气泡持续显示 + 音乐Prompt优化
- 接入豆包TTS V1 WebSocket API,支持故事朗读语音合成
- 新增 PillProgressButton 组件(药丸形进度按钮)
- 新增 TTSService 单例,后台生成不中断
- 音频保存到 Capybara audio/ 目录
- 唱片架当前播放歌曲高亮(金色卡片+音波动效+喇叭图标)
- 播放时气泡持续显示当前歌名,暂停后隐藏
- 音乐总监Prompt去固定模板,歌名不再重复
- 新增 API 参考文档(豆包语音合成)

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-10 22:51:26 +08:00

236 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Airhub 开发进度存档 🔖
> **用途**:每次对话结束前 / 做完一个阶段后更新此文件。
> 新对话开始时AI 先读此文件恢复上下文。
>
> **最后更新**2026-02-10 (第九次对话)
---
## 当前阶段HTML → Flutter 迁移 & UI 还原
### 总体目标
将所有 HTML 原型页面 1:1 还原为 Flutter 原生代码,使 App 脱离 WebView 依赖。
### 本次完成的工作第三次对话2026-02-06
#### 1. 全局字体修复(最重要)
- 把全项目所有 `fontFamily: 'Inter'` 替换为正确字体
- PRD 规范:标题用 **Outfit**,正文用 **DM Sans**Logo 用 **Press Start 2P**
- 修改了 `app_theme.dart`:设置 DM Sans 为全局默认字体Outfit 用于 heading styles
- 修改了 `design_tokens.dart`AppTextStyles 全部改为 GoogleFonts 调用
- 修改了 `gradient_button.dart`:按钮文字改 DM Sans
- 修改了所有页面文件(共 15+ 个文件),零 Inter 残留
#### 2. 逐页 UI 对齐 HTML 原版
- **settings_page.dart**:标题字号 18→16Slider 激活色紫色→暖橙 #FFB088
- **bluetooth_page.dart**:标题字号 18→17设备名字号 24→20
- **wifi_config_page.dart**:标题字号 18→17
- **home_page.dart**Mascot 尺寸 280→320px添加 translateX(5%) 偏移
- **device_control_page.dart**Mascot 阴影色紫→粉,导航栏阴影色紫→中性灰
- **login_page.dart**两个版本Logo 字号 26→28
- **product_selection_page.dart**:标题字体改 Outfit
- **glass_dialog.dart**:对话框标题改 Outfit
- **story files**:清除所有 Inter 引用
#### 3. 编译验证通过
-`flutter run -d web-server --web-port=8080` 编译成功
- 浏览器预览所有页面确认正常
### 第四次对话完成的工作2026-02-07
#### 修复音乐播放功能
- **问题**:音乐页面按播放键只有黑胶唱片旋转动画,完全没有接入 just_audio 播放器
- **根因**`music_creation_page.dart` 没有导入 `just_audio`,没有创建 `AudioPlayer``_togglePlay()` 只改 UI 状态不播放音频
- **修复内容**
- 导入 `just_audio` 并创建 `AudioPlayer` 实例
- `initState` 中初始化播放器 + 监听 position/duration/playerState 三条流
- `_togglePlay()` 现在真正调用 `play()` / `pause()`
- `_playTrack()` 加载对应 asset 并播放
- 进度条双向绑定:拖拽时 seek播放时实时更新
- 播完自动切下一首(循环播放列表)
- 错误处理 + 语音气泡提示
- **MP3 文件**9 首歌已在 `assets/www/music/`pubspec.yaml 已声明,播放列表用了前 4 首
### 第五次对话完成的工作2026-02-07
#### UI 规范化 & 按钮/头部统一
- **书架页面优化**:高度、布局、解锁动画丝滑化
- **头部统一**12 个文件统一为标准头部样式40×40按钮、圆角12、arrow_back_ios_new、17px标题
- **主按钮统一**9 个手写按钮改为 GradientButton 组件(光泽+涟漪+DM Sans
- **GradientButton 规范化**默认高度50→48plush字号18→17统一
- **次级按钮规范化**统一高度48、圆角24
- **全局 Toast**SnackBar → iOS 风格 AppToast
- **新增文档**`flutter_style_guide.md`Flutter 专属样式规范)
- **阶段总结**`阶段总结/phase5_ui_standardization.md`
- 详见 `阶段总结/phase5_ui_standardization.md`
#### 故事详情页修复
- loading 页传完整故事内容(不再是占位符)
- 5 个书架故事补全 content 字段(不再显示 null
- "重写"按钮改为跳转 loading 页重新生成
- 内容卡片加圆角和边距,头部 padding 加大
- footer 去掉多余白色底板
- content 兜底逻辑:无内容时自动用默认故事
### 第六次对话完成的工作2026-02-08
#### 故事保存"精灵吸入"动画Genie Suck
- **实现位置**`story_detail_page.dart`
- **动画效果**:点击"保存故事"后,故事卡片执行三段式吸入动画
- Phase 10→15%):卡片轻微放大到 1.05"蓄力"张力感)
- Phase 215%→100%):卡片极速缩小到 0.05、向下移动、模糊 + 淡出
- 缓动曲线cubic-bezier(0.6, -0.28, 0.735, 0.045)(带回弹的快速吸入)
- **底部按钮**:动画开始时 300ms 渐隐 + 禁用点击
- **总时长**0.8s,动画完成后自动 pop('saved') → 触发书架页 bookPop + 粒子效果
- **三段式完整链路**Genie Suck故事页→ bookPop书架页→ sparkle 粒子(书架页)
- **编译验证**web-server 编译通过,无 lint 错误
### 第七次对话完成的工作2026-02-08
#### 音乐页心情卡片 UI 全面重做
- **卡片风格**:回归玻璃拟态,每张卡片均匀铺一层淡主题色(不再用左白右彩的丑渐变)
- **边框优化**:去掉彩色粗描边,默认极淡主题色边框,选中才加深
- **图标简化**:去掉 40x40 色块方框,改为裸图标 + 主题色着色,更干净
- **选中态**:右上角 8px 主题色圆点指示器 + 卡片颜色加深 + 阴影发光
- **标题字号**:从 13px 回到 14px对应 HTML 原版
- **自由创作**:恢复白底玻璃质感,与心情卡片明确区分
- **盲盒惊喜**:换紫色调(#D4A0E8+ 颜色更浓 + 斜扫柔光动画3s 循环)
#### 歌词可读性优化
- 歌词文字不透明度从 0.75 提到 0.92
- 字号从 11px 提到 12px
- 歌词区域加暗色圆形遮罩,解决纹路干扰
#### 选中态交互修复
- 生成完成后自动清除 `_selectedMoodIndex`,不再残留选中状态
### 第八次对话完成的工作2026-02-09
#### 音乐生成 API 全链路接入(第七次对话中完成,此处补记)
- **SSE 实时进度**:点击心情卡片 → 发 POST 到后端 → SSE 流式推送 lyrics/music/saving/done/error 各阶段
- **MusicGenerationService 单例**:生成任务在后台运行,页面切走不中断
- **切回页面恢复**:切回音乐页弹窗通知生成结果,不在其他页面自动播放
- **进度环动画**:环形光晕进度条(匹配 HTML 版视觉)+ 翻面歌词时仍可见
- **进度条防闪烁**:用 `_crawlId` 取消令牌确保同一时间只有一条爬升动画
- **超时友好提示**:气泡显示"网络开小差了,再试一次~"
- **歌词清洗**:前后端双重清理(去 `\n`、去 `[verse]` 等结构标签、去 JSON 引号)
- **歌名修复**:后端优先取 LLM 返回的 `song_title`,歌词增长至 16-24 行
- **对话气泡样式**:文字垂直居中 + 三角尾巴
- **通知页展开 bug 修复**`AnimatedCrossFade``ClipRect + AnimatedSize` 避免文字竖排
#### 启动时加载历史歌曲
- **后端**`/api/playlist` 接口扫描 `Capybara music/` 目录,返回所有 mp3 + 歌词
- **Service 层**`MusicGenerationService.fetchPlaylist()` 拉取列表
- **前端**`initState` 异步调用,将服务器歌曲插入唱片架最前面(去重,不重复加载硬编码的 4 首)
- **当前服务器上有 19 首 AI 生成歌曲 + 4 首原始歌曲,重编译后唱片架不再丢失**
#### 故事生成接入豆包 API
- **后端**`server.py` 新增 `/api/create_story` 接口SSE 流式调用豆包 Chat API
- **模型**Doubao-Seed-1.6-lite`doubao-seed-1-6-lite-250515`),关闭深度思考加快响应
- **Prompt**`prompts/story_director.md`儿童故事创作大师400-600 字JSON 输出
- **前端串联**
- `StoryGeneratorModal` 返回选中素材 Map角色/场景/道具分类)
- `DeviceControlPage` 把素材传给 `StoryLoadingPage`
- `StoryLoadingPage` 调真实 APISSE 实时进度(连接→生成→解析→完成)
- `StoryDetailPage` 无需改动,已支持接收动态故事数据
- **故事保存**:生成的故事文本保存到 `Capybara stories/` 目录
- **错误处理**超时提示、API 异常、空内容兜底,错误时显示"返回重试"按钮
#### 唱片架高度优化
- 限制唱片架弹窗高度为 3.5 行,超出部分滚动查看
- 半行露出作为"还有更多"的视觉提示
#### Windows 编码问题全面修复
- `sys.stdout` / `sys.stderr` 强制 UTF-8Windows 默认 GBK 导致中文乱码)
- Doubao API 请求体手动 `json.dumps + encode("utf-8")`,避免 `requests` 用 GBK 编码
- SSE 流使用 `ensure_ascii=True`,确保前端 `jsonDecode` 100% 正常
- `resp.encoding = "utf-8"` 强制豆包返回流按 UTF-8 解码
- 已清理 4 个编码出错时保存的乱码故事文件
#### 书架加载历史故事
- **后端**`/api/stories` 接口扫描 `Capybara stories/` 返回所有故事标题+内容
- **前端**`initState` 异步拉取,历史故事排在预设故事之后
- **保存联动**:新生成的故事保存后,真实标题+内容即时加入书架(不再用 mock 数据)
- **封面区分**预设故事显示封面图AI 生成的故事显示淡紫渐变"暂无封面"占位
- **乱码过滤**API 层自动跳过无中文标题的异常文件
### 第九次对话完成的工作2026-02-10
#### TTS 语音合成全链路接入(上次对话完成,此处补记)
- **后端**`server.py` 新增 `/api/tts` 接口WebSocket 流式调用豆包 TTS V1 API
- **音色**:可爱女生(`ICL_zh_female_keainvsheng_tob`
- **前端组件**`PillProgressButton`(药丸形进度按钮)替代旧 RingProgressButton
- 5 种状态idle / ready / generating / completed / playing / paused / error
- 进度环动画 + 音波动效 + 发光效果
- **TTSService 单例**:后台持续运行,切页面不中断生成
- **音频保存**:生成的 TTS 音频保存到 `Capybara audio/` 目录
- **暂停/续播修复**:显式 seek 到暂停位置再 play解决 Web 端从头播放的 bug
- **按钮状态修复**:新增 `ready` 状态,未播放过的音频显示"播放"而非"继续"
- **自动播放控制**:仅在用户停留在故事页时自动播放,切出页面不自动播
#### 音乐总监 Prompt 优化
- **歌名去重复**:移除固定示例("温泉咔咔乐"等),改为"根据场景自由发挥,不要套用固定模板"
- **效果**AI 每次为相似场景生成不同歌名,唱片架不再出现一堆同名歌曲
#### 唱片架播放状态可视化
- **卡片高亮**:当前播放的歌曲整张卡片变暖金色底 + 金色边框 + 阴影
- **标题标识**:播放中的歌曲标题前加小喇叭图标 + 金色加粗文字
- **音波动效**:播放中的唱片中心叠加跳动音波 CustomPaint 动画
#### 气泡持续显示当前歌名
- 播放期间气泡始终显示"正在播放: xxx",不再 3 秒后消失
- 直接点播放按钮(非从唱片架选歌)也会显示歌名
- 暂停时气泡自动隐藏,切歌时自动更新
- 使用 `_playStickyText` 机制,即使其他临时消息弹出后也会恢复播放信息
#### 调研 AI 音乐生成平台
- 对比了 MiniMax Music 2.5现用、Mureka昆仑万维、天谱乐、ACE-Step
- 发现 Mureka 有中国站 APIplatform.mureka.cn质量评测超越 Suno V4
- 用户的朋友用的 Muse AI App 底层就是 Mureka 模型
- MiniMax 文本模型abab6.5s-chat价格偏高可考虑切豆包
- 歌词生成费用极低(每次约 0.005 元主要成本在音乐生成1 元/首)
### 正在做的 / 待办
- 故事封面方案待定(付费生成 or 免费生成)
- 考虑将音乐生成从 MiniMax 切换到 Mureka用户在评估中
- 考虑将歌词生成的 LLM 从 MiniMax abab6.5s-chat 切到豆包(更便宜)
- 长歌名 fallback 问题LLM 返回空 song_title 时用了用户输入原文当歌名,后续可优化
---
## 重复登录页说明
- `lib/features/auth/presentation/pages/login_page.dart` — 路由使用,带 Riverpod 认证
- `lib/pages/login_page.dart` — 完整 UI 实现,作为参考保留
- 后续需要把 pages/ 版本的完整 UI 合并到 auth 版本
---
## 三步走计划
1. ✅ 修已转换页面的 UI 差异(本次完成)
2. 🔄 构建音乐创作页面(进行中)
3. ⬜ 转换剩余 WebView 页面Profile、收藏、帮助等
---
## 开发环境备忘
- **预览方式**`flutter run -d web-server --web-port=PORT`,用 Cursor 内置浏览器看
- **镜像源**:需设 `PUB_HOSTED_URL``FLUTTER_STORAGE_BASE_URL` 为国内源
- **Android 模拟器**已装好VTX 已开,但编译慢,非最终验收不用
- **Flutter web-server 当前运行在端口 8080**
---
## 关键文件索引
| 文件 | 说明 |
|------|------|
| `PRD.md` | 产品需求文档 |
| `design_system.md` | 视觉设计规范 |
| `airhub_app/migration_report.md` | HTML→Flutter 迁移进度 & UI 差异 |
| `music-creation.html` | 音乐创作页面 HTML 原版 |
| `阶段总结/task.md` | "我的"模块任务清单 |
| `阶段总结/phase_summary.md` | 音乐电台功能阶段总结 |
| `阶段总结/session_progress.md` | 👈 **就是本文件,开发进度存档** |