- 接入豆包TTS V1 WebSocket API,支持故事朗读语音合成 - 新增 PillProgressButton 组件(药丸形进度按钮) - 新增 TTSService 单例,后台生成不中断 - 音频保存到 Capybara audio/ 目录 - 唱片架当前播放歌曲高亮(金色卡片+音波动效+喇叭图标) - 播放时气泡持续显示当前歌名,暂停后隐藏 - 音乐总监Prompt去固定模板,歌名不再重复 - 新增 API 参考文档(豆包语音合成) Co-authored-by: Cursor <cursoragent@cursor.com>
236 lines
13 KiB
Markdown
236 lines
13 KiB
Markdown
# 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→16,Slider 激活色紫色→暖橙 #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→48,plush字号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 1(0→15%):卡片轻微放大到 1.05("蓄力"张力感)
|
||
- Phase 2(15%→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` 调真实 API,SSE 实时进度(连接→生成→解析→完成)
|
||
- `StoryDetailPage` 无需改动,已支持接收动态故事数据
|
||
- **故事保存**:生成的故事文本保存到 `Capybara stories/` 目录
|
||
- **错误处理**:超时提示、API 异常、空内容兜底,错误时显示"返回重试"按钮
|
||
|
||
#### 唱片架高度优化
|
||
- 限制唱片架弹窗高度为 3.5 行,超出部分滚动查看
|
||
- 半行露出作为"还有更多"的视觉提示
|
||
|
||
#### Windows 编码问题全面修复
|
||
- `sys.stdout` / `sys.stderr` 强制 UTF-8(Windows 默认 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 有中国站 API(platform.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` | 👈 **就是本文件,开发进度存档** |
|