Files
Cyrene-For-Android/devdocs/01-功能拆解与分步路线.md
T
AskaEth 2369dd2115 meta(docs): devdocs/ 纳入版本库 —— 交接与协同文档不再只存在于本机
主人 2026-10-04 指示「项目仓库也可以写进去」。因此把 devdocs/ 从 .gitignore 移除并首次入库:

- `05-开发进度与交接.md` —— 跨会话交接锚点:当前状态、易忘的实现约定、踩过的坑、实机验收方法
- `02-前后端协同事项.md` —— 与后端会话的**交换文档**(两边都会读写:我们登记缺口,对面写回执)
- `01/03/04/06/07` + `DESIGN.md` —— 路线、客户端细化方案、构建环境、迁移说明、给后端会话的交接

**凭据扫描已过**:无账号口令、无 token/refreshToken 明文、无 API key 或私钥。
文档里只记「登录凭据不写进文档,问主人」这条口径本身。

(此前忽略它的理由已不成立:文档现在承担跨会话交接与前后端协同两件正事,
只留在本机磁盘会随机器丢失,而这批内容的价值恰恰在「后来人读得到」。)
2026-10-04 19:00:18 +08:00

91 lines
8.2 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.
# 01 — 功能拆解与分步路线(Cyrene-For-Android 讨论稿 v1)
> 配套 `DESIGN.md`(总览)。本文按**分步**展开:每模块给出「做什么 / 交互 / 数据流 / 依赖 / 验收 / 边界 / Miuix 组件映射」。状态:**讨论稿**,与主人在本会话逐模块细化后定稿。
> 前提(已定案):主界面=常规 AI APP;长按电源键=系统默认语音助手(VOICE_INTERACTION_SERVICE,全屏,无悬浮球);ASR/TTS 后端化;先纯文本版;UI 严格 Miuix(compose-miuix-ui)。
---
## 阶段 0 · 工程骨架
**S0.1 工程搭建**
- Gradle(版本目录)、Kotlin + Compose、`compose-miuix-ui` 依赖、`BuildConfig.BASE_URL`(debug `http://<host>:8080`,release 换 HTTPS)、单 Module `app`、包 `com.askaeth.cyrene.{app,core,data,domain,platform,ui}`。
- 依赖:Retrofit+OkHttp、kotlinx-serialization、okhttp-WebSocket、EncryptedSharedPreferences、Hilt(可选)、Coil(图片)。
- 验收:`./gradlew :app:assembleDebug` 通过,App 能起空壳 Miuix 首页。
- 边界:暂不接后端。
## 阶段 1 · P0 纯文本聊天(零后端改动,契约现成)
### S1.1 登录(已定稿 2026-09-08)
- **服务器地址可配**(开源,各人部署地址不同):登录卡放「服务器地址」折叠项/入口,默认 `http://<host>:8080`,用户可改;存本地(EncryptedPrefs/DataStore)。
- **仅 `.env` 单管理员**(`ADMIN_USERNAME/PASSWORD`)可登录,无注册/找回;成功 `role=owner`。
- **自动登录**:默认记住 token(EncryptedPrefs),重启免登;仅 `401/auth_expired` 才清 token 回登录。
- **报错**:**已建立连接**(服务端有响应)时用服务端 `{error.message}`;**本地错误**(连不上/证书/DNS/超时)**由客户端本地文案负责**——不把本机错误误当服务端文案。
- **密码默认隐藏**(可切换明文)。
- **数据流**:`AuthManager.login(baseUrl,username,password)` → `POST {base}/api/v1/auth/login` → `{token,expiresAt,role}` → `EncryptedPrefs` 存(baseUrl+token+role+expiresAt)→ `HomeScreen`。
- **状态机**:`Idle→Loading→Success(Home)|Error(msg)`(`error.from==="server"` 用后端 `message`,`"local"` 用本地文案);登录中禁用按钮防连点;登录失败不清已存 token。
### S1.2 会话列表(已定稿 2026-09-08)
- **主结构 = A**:启动**直接进主会话「与昔涟」(`web`) 聊天**;**顶栏汉堡 → 侧边栏**含【会话列表(切主/次级)+ IoT + App 设置 + 登出】。
- **列表显示**:主会话="与昔涟",次级="会话 2/N"(按序号,title **自动**,零后端改动);无预览/时间(后端 `/sessions` 只有 id)。
- **新建**:侧栏"+"新建次级(`POST /sessions` → `sessionId` → 切进去)。
- **删除**:次级长按/滑出 → 确认 `Dialog` → `DELETE /sessions/{id}`;主会话禁删(提示"主会话不可删")。
- **切换**:侧栏会话列表点选 → 切聊天页。
- **数据流**:`GET /api/v1/sessions`(主会话 `web` 恒首位)。**依赖**:S1.1。**验收**:启动即主会话聊天;侧栏可切/建/删次级;主会话不可删;重启记住上次会话(可后续)。
### S1.3 聊天页:历史加载(已定稿 2026-09-08)
- **数据流**:`GET /sessions/{id}/messages?limit=50&before=<ms>&platform=` **倒序**返回,客户端**逆序渲染**(最新在底)。**`platform` 不传 = 看全量主会话**(a,能同步 web/kook/微信所有主会话消息)。
- **分页**:初始 50 条;**上拉**加载更多用 `before=<最早时间>` 再往前翻(**50 步进**),追加顶部。
- **消息来源标识**:每条消息**默认显示来源**(`platform`/`deviceId` 小字角标,如"来自 web" / "来自 kook" / "来自微信" / "来自安卓(voiceassist)")——主人既定诉求。
- **时间**:**完全隐藏**(不显示时间戳/分组,对话沉浸)。
- **空态**:主会话无消息 → 昔涟欢迎语。
- **依赖**:S1.2。**验收**:进会话拉 50 条倒序展示;上拉翻 50/页;每条标来源;无时间戳。
### S1.4 聊天页:发消息 + 流式(已定稿 2026-09-08)
- **发消息**:WS `/ws/chat` 上行 `chat {sessionId,text,deviceId}`(**stream 流式**);本地乐观追加自己消息。
- **流式渲染**:下行 `message.start` 开气泡 → `message.delta` **逐段追加**(气泡尾+光标)→ `message.end` 收口。
- **流式期间新消息 = 两种模式(用户可切,默认「追加队列」)**:
① **追加队列**(新消息进队列,流式结束后依次处理——豆包式);
② **打断**(新消息触发 `interrupt`,保留残缺上下文 + 显示"打断"提示)。
- **思维链 `thinking` / 工具卡 `tool_call`**:**默认展开**(方便观察思维;可折叠 + "总是收起"开关)。
- **旁白 `<action>/<narration>`**:灰斜体小字,**按出现位置依附气泡上/下**。
- **`mood`**:显示情绪标签(可关)。
- **渲染**:`<p>` 拆气泡;图片;忙态 `session_busy/pending_*` 提示;`409/202` 兜底。
### S1.5 侧边栏(汉堡抽屉)
- **做什么**:顶栏左上汉堡 → `Drawer` 侧边栏:当前会话/聊天、**[预留] IoT 入口**、**[预留] App 设置入口**、登出。
- **数据流**:登出 → 清 token + 断开 WS → 回登录。
- **验收**:汉堡展开侧栏;IoT/设置点开显示"规划中"(Miuix 空态);登出回登录页。
- **边界**:侧栏入口预留(P0 占位不真做)。
### S1.6 401 / token 过期
- **做什么**:REST 401 → `auth_expired` 清 token 停 WS → 回登录;WS 握手失败同理。
- **验收**:JWT 过期或轮换后,下条请求自动登出重登,不无限 reconnect。
## 阶段 2 · P1 语音助手(后端 ASR/TTS,依赖本会话 TTS/ASR 进程接通后端)
### S2.1 系统默认语音助手
- **做什么**:Manifest 声明 `VOICE_INTERACTION_SERVICE`/`AssistantService`(`android:role="Assist"`),用户在系统「语音助手/电源键」设本 App 默认 → 长按电源键由系统拉起本 App `AssistantActivity`(全屏)。
- **依赖**:系统设置入口(MIUI 自家更顺);Android 版本/厂商适配。
- **验收**:长按电源键 → 本 App 全屏助手打开(无悬浮球)。
### S2.2 全屏助手 UI(AssistantActivity)
- **做什么**:聆听动画 → 已识别文本(ASR 结果)→ 昔涟回复(流式)→ 重听/TTS;按钮:结束/放弃/再次说话。全程单页全屏,Miuix 玻璃质感。
- **验收**:说话 → 文本上屏 → 昔涟回复 + 朗读。
### S2.3 语音闭环(后端 ASR/TTS)
- **链路**:录音(`MediaRecorder`/`AudioRecord`)→ **REST 上传到后端**(音频→ASR)→ 文本 → `POST /api/v1/chat {text,deviceId}`(或 WS)→ 昔涟回复 → **后端 TTS** 返回音频 → 本端播放。`voice_output`(WS)也可拿音频。
- **依赖**:**后端 ASR/TTS 真接通**(本会话 TTS/ASR 进程:真实 STT/TTS provider + REST 语音端点绕 4KB + `voice_input.deviceId`)。
- **验收**:对话 3 轮语音一问一答;IM 渠道(微信/KOOK)语音也走同一后端 ASR/TTS。
## 阶段 3 · P2 智能
- **IoT**:设备/场景列表(Miuix;预留接口 `GET /api/v1/iot/*`)。
- **App 设置**:主题(Miuix 深/浅)、通知开关、语音偏好(ASR/TTS 后端已定)、关于。
- **主动推送**:后端 proactive/backthink → 系统通知;前台服务保活(可选)。
- **多角色**:`GET /personas` 只读展示;切换人格。
- **记忆/子代理/自主思考**:只读面板(`memory`/`subagent`/`backthink` 过滤器)。
---
## 跨模块约定
- **deviceId**:`voiceassist:myapp:v1`(design/16 §4.5),所有 `chat`/`voice_input` 携带 → 落库标来源、跨端可辨。
- **主会话同步**:Android 加入 `web` 主会话,与 Web/IM 共享上下文;渲染按 `platform` 区分"本端/他端"(design/16 §4.4)。
- **Miuix 映射**:`TopAppBar`(汉堡/标题)、`Scaffold`+`Drawer`(侧栏)、气泡(自定义 `BubbleView` 或 Miuix 卡片+毛玻璃)、`TextField`、`Button`(发送/语音)、`Snackbar`/`Dialog`(确认/错误)。**禁原生 Material**。
- **安全红线**:token 加密存储、401 即登出、权限最小化、无悬浮球、不打日志敏感。