Files
Cyrene-For-Android/devdocs/DESIGN.md
T
AskaEth 84de51c7b7 feat: 初始化 Android 客户端(M0 骨架 + M1 登录 + M2 基础模块)
M0:Gradle 9.7.1 / AGP 9.2.1 / Kotlin 2.4 / Miuix 0.9.3,minSdk 33,compileSdk 37。
M1:登录页(服务器地址可配、服务端/本地错误分流、EncryptedSharedPreferences、自动登录与静默重登、401 登出)。
M2 基础模块:消息内容解析器(<p>/<action>/<narration> + 流式增量)、WebSocket 客户端、REST 数据层与分页去重。
45 个单元测试全绿,真机验证通过(登录页 + 启动图标)。
devdocs/ 收录设计文档、前后端协同事项与细化方案。
2026-09-08 20:40:58 +08:00

96 lines
9.9 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.
# Cyrene-For-Android — Cyrene 安卓客户端设计文档(超详细讨论稿 v1)
> 配套 Cyrene v2(git.yeij.top/AskaEth/Cyrene_v2)的 Android 客户端。
> **主人已确认的关键决策**(2026-09-08):
> - 主界面 = **常规 AI APP 风格**(会话列表 + 聊天流)。
> - **长按电源键唤醒 = 全屏语音助手**(系统级语音助手交互),**不要悬浮球**。
> - UI **严格遵守 MIUIx / Miuix 设计风格**:官网 https://compose-miuix-ui.github.io/miuix/zh_CN/ ,组件库 https://compose-miuix-ui.github.io/miuix/zh_CN/components/ 。
> - **先做纯文本版本**(P0);语音(P1)后续。
> - 顶栏左上角**汉堡菜单**展开**侧边栏**,**预留 IoT 入口 + App 设置页入口**。
> - 后端契约详见 `Cyrene v2` 的 `Docs/api-reference.md` + `DevDocs/design/21-安卓app语音助手.md`(本文件为端侧细化)。
> 命名:仓库作者 `AskaEth`,日常名 `YeiJi / 叶酱`;App 名 `Cyrene`,角色 `昔涟`。
---
## 0. 目录与工程形态
- **单 Module**:`app`(Kotlin + Jetpack Compose),Gradle 版本目录。
- 依赖:`compose-miuix-ui`(Miuix 组件)、`androidx.lifecycle.viewmodel-compose`、`Retrofit + OkHttp + kotlinx-serialization`、`okhttp`(WebSocket)、`EncryptedSharedPreferences`(JWT)、`hilt`(DI,可选)。
- `BuildConfig`:`BASE_URL`(默认可 `http://<host>:8080`,release 换 HTTPS)。
- 包结构:`com.askaeth.cyrene.{app,core,data,domain,platform,ui}`(`app`=Activity/导航;`core`=Miuix 主题/Auth;`data`=Retrofit/WS/仓库;`domain`=会话/消息模型;`platform`=语音/权限/电源键;`ui`=各 Screen/组件)。
## 1. 总体信息架构(功能分类)
```
Cyrene-For-Android
├─ A. 聊天(主界面,AI APP 风格)
│ ├─ 会话列表:主会话「与昔涟」(web) + 次级会话(web:<uuid>),可新建/删除/恢复
│ └─ 聊天页:气泡流(<p>多气泡、<action>/<narration> 旁白灰斜体仅chat、思维链/工具卡折叠、图片)、输入框+发送、语音按钮(P0占位)
├─ B. 侧边栏(汉堡抽屉)
│ ├─ 会话/聊天
│ ├─ [预留] IoT(设备/场景)入口
│ ├─ [预留] App 设置入口
│ ├─ [可选] 记忆 / 子代理 / 自主思考(只读)
│ └─ 关于 / 登出
├─ C. 语音助手(长按电源键唤醒,P1)— 全屏,无悬浮球
│ ├─ 展开: 聆听动画 → 已识别文本 → 昔涟回复 → 再听/TTS
│ └─ 系统级: AccessibilityService/系统语音助手回调 → 启动助手 Activity(全屏)
├─ D. [预留] IoT:设备/场景列表(占位)
└─ E. [预留] App 设置:主题(Miuix 深/浅)、通知、语音偏好(ASR/TTS 端侧 vs 后端)、关于
```
## 2. 页面路由(单 Activity + 导航)
- `LoginScreen`(首启无 token)→ `HomeScreen`(会话列表,含顶栏汉堡)→ `ChatScreen({sessionId})`(聊天)
- `AssistantActivity`(P1 全屏语音助手,长按电源键拉起;无悬浮球,就一个全屏页)
- `IotScreen` / `SettingsScreen`(占位页,P0 展示"规划中")
## 3. 数据层(对照现有契约,P0 纯文本即用)
- **认证**:`POST /api/v1/auth/login {username,password}` → `{token,expiresAt,role}`(`role=owner`,单账号)。JWT `Authorization: Bearer`+`X-API-Version: 1`;`EncryptedSharedPreferences` 存 token;**REST 401 → `auth_expired` 清 token → 回登录**;WS 握手失败同理。
- **会话**:`GET /api/v1/sessions`(主会话 `id="web"` 恒在);`POST /api/v1/sessions` 建次级;`GET /sessions/{id}/messages?limit=50&before=<ms>&platform=`(**倒序热分页**,`platform=` 过滤);`DELETE /sessions/{id}`(主会话删=403)。
- **发消息**:`POST /api/v1/chat {sessionId,text,deviceId,stream?}`(`stream:true`→转 WS;忙时 `202 {queued,queueDepth}`、队满 `409 chat_busy`)。
- **WS** `/ws/chat?token=`:上行 `chat`/`interrupt`;下行 `message.start|delta|end`、`thinking.*`、`tool_call.*`、`message_persisted`、`history`(握手后首帧主会话最近 50 条)、`mood`、`session_busy`/`pending_*`/`session_idle`、`voice_output`(P1)。`message_persisted`/`history` 载荷为 `historyMessage`。
- **消息 DTO**:`{id,sessionId,role,content,mode?,mood?,image?,thinking?,platform?,deviceId?,senderName?,adapterId?,createdAt}`;`thinking` 仅 owner 可见;主流 `mode` 有 `chat`(含 `<p>`/`<action>/<narration>` 需端侧解析)。
- **deviceId**:`voiceassist:myapp:v1`(design/16 §4.5 允许自定可读前缀),`POST /chat`/ws `chat` 携带 → 落库标注来源;主会话 `web` 与 Web 共享上下文(multiplatform 同步)。
## 4. 消息渲染(聊天页核心)
- 按 `mode` 决定形态:`chat` 用气泡;其它 `mode`(backthink/工具/审计等 refs)卡片化或折叠。
- **`chat` 文本解析**:把 content 按 **`<p>`** 拆成多条气泡(每段一条);`<action>…</action>`/`<narration>…</narration>` 解析为**灰斜体小字旁白**(依附气泡,不独立成气泡);`*…*`/`*…*` 兼容。**非 chat 消息不解析**这些标签。
- `thinking`(仅 owner):可折叠「思维链」面板;`tool_call` →「工具卡」(折叠,可看参数/结果)。
- 流式:`message.delta` 追加到当前气泡末尾 + 光标;`message.end` 收口。
- 图片:`image`(base64 data: URI 或 URL)→ Coil 加载。
## 5. 语音助手(P1,长按电源键 全屏,无悬浮球)— 端侧与后端协同
- **触发**:① 系统级语音助手回调(`VOICE_INTERACTION` / `AssistantService`)或 ② `AccessibilityService` 监听 `KEYCODE_POWER` **长按**(Android 对电源键长按有限制,需在系统「电源键双击/长按」设置里把本 App 设为语音助手,或通过系统辅助「voice assistant」入口)。落地:**声明 `VOICE_INTERACTION_SERVICE`**,长按电源键由系统拉起本 App 的 `AssistantActivity`(全屏)。
- **链路**:`AssistantActivity` 聆听(`MediaRecorder`/`AudioRecord`)→ 录音交给 **ASR**(**端侧 or 后端**,见开放问题;后端当前 ASR/TTS 是占位,需先补 design/21 后端补强或端侧 whisper)→ 出文本 → `POST /api/v1/chat {text,deviceId}`(或 WS 流式)→ 昔涟回复 → **TTS** 合成朗读(端侧 e.g. `TextToSpeech` 或后端)。全程单页无悬浮球。
- **保活/后台**:可选前台服务(语音持续/推送),权限最小化;无需悬浮球全局浮层。
## 6. MIUIx / Miuix 映射(紧跟 compose-miuix-ui)
- 用 `compose-miuix-ui` 的 `MiuixTheme` + 组件:`TopAppBar`(汉堡/标题)、`Scaffold`/`Drawer`(侧边栏)、气泡用 `BubbleView`/卡片、`TextField`(输入)、`Button`(发送)、`Switch`/`List`(设置)、`Snackbar`/`Dialog`。**禁用原生 Material 组件**,全 Miuix 风格(圆角、毛玻璃、液态玻璃、强调色)。
- 顶栏左上汉堡 → 侧边栏(`Drawer`);侧边栏含「IoT」「App 设置」占位入口(P0 点开显示"规划中")。
## 7. P0(纯文本)MVP 任务清单
1. 工程搭建:Gradle + Compose + Miuix 依赖 + `BuildConfig.BASE_URL` + Hilt(可选)。
2. `core`:Miuix 主题、AuthManager(EncryptedPrefs 存 JWT、401→auth_expired→登出)。
3. `data`:Retrofit(login/sessions/messages/chat)、WS `ChatSocket`(`/ws/chat?token=`,事件分发到 StateFlow)、`ApiClient`(`Authorization: Bearer`+`X-API-Version`)。
4. `domain`:`Conference`/`ChatMessage` 模型、`HistoryMessage` 映射、`<p>`/`<action>/<narration>` 解析器。
5. `ui`:`LoginScreen` → `HomeScreen`(会话列表)→ `ChatScreen`(气泡流 + 流式 + 思维链/工具卡 + 输入框)。顶栏汉堡侧边栏(IoT/设置/登出)。
6. 设备标识:`deviceId=voiceassist:myapp:v1`。
7. 验证:登录 → 拉主会话历史 → 发消息 → WS 流式收到回复 → 跨端(web/微信)同步显示。
## 8. 长线 roadmap
- **P0(纯文本)**:⑦ 完成 → 可日常聊天,多端同步。
- **P1(语音助手)**:后端补 ASR/TTS(design/21)→ 电源键长按唤起全屏助手 → 聆听/ASR/chat/TTS 朗读闭环 → 无悬浮球。
- **P2(智能)**:IoT 入口真实现(设备/场景)、App 设置功能化(主题/通知/语音偏好)、主动推送 + 系统通知、多角色(persona)切换、记忆/子代理/自主思考只读面板、多会话管理增强。
## 9. 开放问题(待与主人讨论 / 后续敲定)
1. **[已定案] 长按电源键**:设置 App 为**系统默认语音助手**(`VOICE_INTERACTION_SERVICE` / `AssistantService`),由系统在长按电源键(或系统语音助手入口)时拉起本 App 的 `AssistantActivity`(全屏),无悬浮球。厂商(MIUI)自家更顺,需在系统「语音助手 / 电源键」设置里把本 App 设为默认。
2. **[已定案] ASR/TTS 后端化**:**不在端侧**——因第三方适配器(微信 / KOOK 等 IM 渠道语音)**无法在端侧实现**,且为大后期**语音 / 视频通话**打基础。语音闭环统一走后端真实 ASR / TTS。**依赖**:后端 `voice` 链路当前是降级占位(cloud endpoint 空 → 降级、silent 空音频),需先接通真实 ASR / TTS(本会话 TTS/ASR 进程在做)。Android 语音 P1 依赖这项完成后接入。
3. **Miuix 组件精确映射**:到 `components` 页逐组件对照,列出"我们用哪个"。
4. **多角色**:现在登录恒 owner,暂无双角色切换;`GET /personas` 可只读展示人格列表。
5. **会话管理 UI**:次级会话的新建/切换/删除入口。
6. **Hilt vs 手写 DI**:视复杂度定。
## 10. 红线(必须遵守)
- JWT 存储加密(EncryptedPrefs),不落明文/不打日志;401 即登出。
- 身份靠 actor 元数据 + owner.yaml 白名单(登录即 owner),不靠提示词。
- 语音/音频:权限最小化、显式授权;**不做悬浮球全局浮层**。
- 严格 Miuix,禁原生 Material;`Docs/api-reference.md` 契约随实现更新。