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/ 收录设计文档、前后端协同事项与细化方案。
9.9 KiB
9.9 KiB
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,单账号)。JWTAuthorization: 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/wschat携带 → 落库标注来源;主会话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 任务清单
- 工程搭建:Gradle + Compose + Miuix 依赖 +
BuildConfig.BASE_URL+ Hilt(可选)。 core:Miuix 主题、AuthManager(EncryptedPrefs 存 JWT、401→auth_expired→登出)。data:Retrofit(login/sessions/messages/chat)、WSChatSocket(/ws/chat?token=,事件分发到 StateFlow)、ApiClient(Authorization: Bearer+X-API-Version)。domain:Conference/ChatMessage模型、HistoryMessage映射、<p>/<action>/<narration>解析器。ui:LoginScreen→HomeScreen(会话列表)→ChatScreen(气泡流 + 流式 + 思维链/工具卡 + 输入框)。顶栏汉堡侧边栏(IoT/设置/登出)。- 设备标识:
deviceId=voiceassist:myapp:v1。 - 验证:登录 → 拉主会话历史 → 发消息 → WS 流式收到回复 → 跨端(web/微信)同步显示。
8. 长线 roadmap
- P0(纯文本):⑦ 完成 → 可日常聊天,多端同步。
- P1(语音助手):后端补 ASR/TTS(design/21)→ 电源键长按唤起全屏助手 → 聆听/ASR/chat/TTS 朗读闭环 → 无悬浮球。
- P2(智能):IoT 入口真实现(设备/场景)、App 设置功能化(主题/通知/语音偏好)、主动推送 + 系统通知、多角色(persona)切换、记忆/子代理/自主思考只读面板、多会话管理增强。
9. 开放问题(待与主人讨论 / 后续敲定)
- [已定案] 长按电源键:设置 App 为系统默认语音助手(
VOICE_INTERACTION_SERVICE/AssistantService),由系统在长按电源键(或系统语音助手入口)时拉起本 App 的AssistantActivity(全屏),无悬浮球。厂商(MIUI)自家更顺,需在系统「语音助手 / 电源键」设置里把本 App 设为默认。 - [已定案] ASR/TTS 后端化:不在端侧——因第三方适配器(微信 / KOOK 等 IM 渠道语音)无法在端侧实现,且为大后期语音 / 视频通话打基础。语音闭环统一走后端真实 ASR / TTS。依赖:后端
voice链路当前是降级占位(cloud endpoint 空 → 降级、silent 空音频),需先接通真实 ASR / TTS(本会话 TTS/ASR 进程在做)。Android 语音 P1 依赖这项完成后接入。 - Miuix 组件精确映射:到
components页逐组件对照,列出"我们用哪个"。 - 多角色:现在登录恒 owner,暂无双角色切换;
GET /personas可只读展示人格列表。 - 会话管理 UI:次级会话的新建/切换/删除入口。
- Hilt vs 手写 DI:视复杂度定。
10. 红线(必须遵守)
- JWT 存储加密(EncryptedPrefs),不落明文/不打日志;401 即登出。
- 身份靠 actor 元数据 + owner.yaml 白名单(登录即 owner),不靠提示词。
- 语音/音频:权限最小化、显式授权;不做悬浮球全局浮层。
- 严格 Miuix,禁原生 Material;
Docs/api-reference.md契约随实现更新。