添加消息持久化和服务模块分离的内容

This commit is contained in:
2025-09-25 14:23:57 +08:00
parent 5e8b9af17b
commit 50226b27a1

View File

@@ -1,6 +1,6 @@
# AI_Chat_Assistant PRD
# AI 聊天助手需求设计文档
# AI 聊天助手需求设计文档(产品需求文档 PRD
### 文档介绍
@@ -10,15 +10,17 @@
| 版本 | v1.0.0+1 |
| 文档版本 | v1.0 |
| 创建日期 | 2025-09-23 |
| 产品经理 | - |
| 技术负责人 | - |
| 目标平台 | Flutter (Android/iOS) |
| 最近更新时间 | 2025-09-24 |
| 产品经理 | (待指定) |
| 技术负责人 | (待指定) |
| 目标平台 | Flutter (Android / iOS首期 Android 优先) |
| 发布形态 | Flutter 第三方插件(支持示例 App |
### 修订记录
| 版本 | 日期 | 作者 | 内容 |
| --- | --- | --- | --- |
| 1.0 | 2025-09-23 | - | AI助手需求整理 |
| 1.0 | 2025-09-23 | - | 初版功能需求整理 |
## **1. 引言**
@@ -39,25 +41,28 @@
| 3 | TTS | Text-To-Speech语音合成将文本转换为语音。 |
| 4 | SSE | Server-Sent Events一种服务器向客户端推送数据的技术。 |
| 5 | 车控命令 | 通过语音或界面触发的,用于控制车辆功能(如门锁、空调)的指令。 |
| 6 | 场景Scenario| 不同业务上下文(购车 / 用车) |
### **1.4 统一异常处理**
1. **网络异常**语音识别或AI对话过程中出现网络错误应有明确提示“网络连接失败请检查后重试”并提供重试选项。
2. **权限拒绝**:当未授予麦克风或音频录制权限时,应引导用户前往系统设置开启权限。
3. **语音识别失败**识别无结果或置信度过低时,应提示用户“抱歉,我没有听清,请再说一遍”。
4. **命令执行失败**:车控命令下发后执行失败应通过TTS和UI界面明确反馈失败原因。
3. **语音识别失败**返回空文本或低置信度,提示“抱歉,我没有听清,请再说一遍”。(补充:不缓存失败结果。)
4. **命令执行失败**:车控执行失败需双通道反馈UI + TTS并显示失败原因或错误类型标签。补充通用错误尽量转化为用户友好语义。
## 2. 产品概述
### 2.1 产品简介
AI Chat Assistant 是一个功能丰富的 AI 聊天助手 Flutter 插件提供完整的AI语音交互解决方案支持语音识别、智能对话、车控命令执行语音反馈等功能。
聊天助手现在分为车控助手和用车助手,车控助手支持 20+ 种车辆控制命令(空调、车窗、车门、座椅加热等);用车助手会根据用户手册的内容智能回复。
AI Chat Assistant 是一个集成语音识别、智能对话、车控指令解析与执行语音反馈渲染于一体的 Flutter 插件。支持“车控助手”与“用车助手”双场景:
- 车控助手:支持 20+ 车辆控制命令(如空调、车窗、车门、座椅加热等)。
- 用车助手:基于用户手册 / 知识库进行问答。(包含 保养咨询、能耗优化建议等)
- 购车助手:基于厂家的经销政策以及车辆配置信息进行问答
### 2.2 产品流程图
现有的产品主要流程是用户长按点击语音按钮,经过权限判断之后,需要将语音转化为文本,然后通过分类结果来判断是普通问答(知识库)还是车控指令。
现有核心流程:用户长按语音按钮 → 权限校验 → 录音 + 识别 → 文本分类 → 路由到问答/车控/错误反馈 → 结果播报与展示。
```mermaid
graph TD
@@ -89,6 +94,41 @@ graph TD
- 支持自然语言车控命令识别与执行
- 轻量级架构,易于集成和定制
### 2.4 顶层功能结构
```mermaid
graph LR
ASR[语音采集/ASR] --> CLASS[文本/意图分类]
CLASS -->|车控| CMD[车控解析/执行]
CLASS -->|问答| QA[对话引擎 SSE/WS]
CLASS -->|兜底| FALL[引导重试/澄清]
QA --> TTS[TTS 播报]
CMD --> FEED[执行反馈]
TTS --> MSG[消息渲染]
FEED --> MSG
MSG --> STORE[(本地持久化)]
```
### 2.5 语音交互主流程
```mermaid
graph TD
START[长按/唤醒触发] --> PERM[权限校验]
PERM -->|通过| REC[开始录音]
PERM -->|拒绝| EXIT[权限引导提示]
REC --> ASR[实时增量识别]
ASR --> RELEASE[松手/结束]
RELEASE --> CLASSIFY[分类/意图识别]
CLASSIFY -->|车控| CONTROL[结构化命令]
CLASSIFY -->|问答| STREAM[流式对话输出]
CLASSIFY -->|无匹配| GUIDE[兜底提示]
CONTROL --> EXEC[调用车控处理器]
EXEC --> RESULT[结果反馈]
STREAM --> MERGE[增量合并/渲染]
RESULT --> RENDER[消息渲染 + TTS]
MERGE --> RENDER
RENDER --> STORE[(持久化过滤保存)]
```
## 3. 功能需求
### 3.1 用户页面展示
@@ -97,7 +137,7 @@ graph TD
- **用户场景**
在主应用界面上提供一个常驻的、可随意拖拽的AI助手入口。
在主应用界面上提供一个常驻的、可随意拖拽的AI助手入口,作为全局统一入口,维持轻量可达性,不干扰主业务操作
- **功能描述**
@@ -107,14 +147,13 @@ graph TD
- **拖拽吸附**:支持在屏幕内自由拖拽,松开时自动吸附到最近的屏幕边缘。
- **交互响应**
- **点击** 进入全屏的聊天页面,全屏模式为一个新的页面
- **长按**:变为聆听模式,直接开始语音录制,出现聊天窗口
聊天窗口的位置需要根据浮动按钮的位置变化,如果浮动按钮位置过于靠上,则聊天窗口显示在浮动按钮的下方,默认情况下显示在浮动按钮的上方
- **长按**:变为聆听模式,直接开始语音录制,出现聊天窗口
- **位置自适应**:聊天窗口的位置需要根据浮动按钮的位置变化,如果浮动按钮位置过于靠上,则聊天窗口显示在浮动按钮的下方,默认显示在浮动按钮的上方
- **状态指示**:通过动画(如呼吸效果)表示待机、聆听、思考等不同状态。
默认为待机状态,长按会进入聆听状态,思考中的状态会在聊天显示思考中的状态聊天气泡
- **补充说明**:长按阈值建议 300ms误触策略短按抬起不触发录音。
![image.png](images/db1d92f4-107d-46c9-8154-fc58cb471acc.png)
@@ -128,7 +167,7 @@ graph TD
- **功能描述**
提供弹出式聊天窗口,展示对话记录并提供输入方式
提供弹出式聊天窗口,展示对话记录并提供输入方式,不承担复杂历史翻阅与批量操作
- **需求说明**
@@ -144,17 +183,17 @@ graph TD
- **用户场景**
用户与AI助手进行可视化的文本和语音交互。
用户与AI助手进行可视化的文本和语音交互,适用于长对话、多轮引用、查看历史与多类型气泡的交互
- **功能描述**
提供全屏聊天界面,展示对话记录并提供输入方式。全屏的聊天页面功能更加丰富,分为不同的场景
提供全屏聊天界面,展示对话记录并提供输入方式。全屏的聊天页面功能更加丰富,多类型气泡、快捷指令区、功能按钮区、历史分页加载
- **需求说明**
- 全屏聊天模式下会保留之前浮动聊天窗口的聊天记录
- 不同的场景为不同的AI助手现有两种场景购车助手和用车助手
- 不同的场景为不同的AI助手现有两种场景购车助手和用车助手(根据入口来判断)
- 顶部会有可配置的功能按钮区域(用户服务/购车服务)
- 功能按钮下方会有快捷对话的区域,可以点击换一换来更换快捷指令
- 功能按钮下方会有快捷对话的区域,可以点击换一换来更换快捷指令,支持“换一换”刷新策略(本地轮换或服务侧下发)
- 聊天页面底部会有功能栏,分别为**删除当前对话****按住说话****切换文本输入**
- 如果存在本地对话记录,点击 **显示历史对话记录** 会加载之前的5条对话记录同样可以通过上拉来加载历史对话记录
@@ -166,7 +205,7 @@ graph TD
- **用户场景**
用户未绑定车辆的情况下爱车页面变为购车页面购车页面也会有AI助手
用户未绑定车辆的情况下爱车页面变为购车页面购车页面也会有AI助手,未绑定车辆用户获取车型配置、优惠、推荐。
- **功能描述**
@@ -176,7 +215,7 @@ graph TD
- 浮动按钮点击可进入全屏的AI助手页面顶部的功能按钮为热门车型推荐同样是icon+text的按钮点击之后会快捷输入车型的名称AI助手会回复车型的相关信息同时快捷对话的区域会按照对话来进行变化
- 购车助手同样可以通过文本的语义来进行推荐车型,以及解读购车的优惠信息;
- 如果在购车助手场景下,本身并没有绑定车辆,如果有车控的语音输入,则返回:您还未绑定车辆,无法使用车控指令;
- 如果是用车助手场景,包含购车助手的全部功能,同样可以回复相应车型来获取配置信息以及购车政策。
- 如果是用车助手场景,包含购车助手的全部功能,同样可以回复相应车型来获取配置信息以及购车政策。
![image.png](images/image%203.png)
@@ -194,7 +233,7 @@ graph TD
- **需求说明**
- 用车场景下的功能按钮为官方推荐,内容包括智能场景推荐、数据埋点和运营位,其中智能场景推荐包括售后维保提醒,智能场景建议;数据埋点包括能耗报告,行为分析,用户习惯操作;运营位则是推荐的车型,用户复购建议;
- 点击 常见功能按钮,会输入一个常见功能的聊天记录,返回的数据为经过大数据分析之后得到的常用功能,聊天气泡中显示多个按钮,可以点击进行快捷回复;
- 常见功能按钮 → 发送一条“功能集合”消息气泡(含多个按钮)。
- 点击 更多工具按钮跟常见功能按钮一样,会返回一条聊天记录,里面会包含多个按钮,点击按钮可以进行快捷回复;
- 快捷回复区域是可以变化的,会根据对话的最后一个回复进行变化,快捷回复区域会跟在最后一个对话的底部;例如刚进入会跟在 功能按钮的底部,但是新的聊天记录出现后,就会自动拼接到聊天气泡的底部(聊天气泡类型分为多种,后面会详细介绍);
@@ -204,17 +243,18 @@ graph TD
- **用户场景**
在开通语音醒功能之后,购车页面和爱车页面都可以使用语音唤醒
在开通语音醒功能之后,购车页面和爱车页面都可以使用语音唤醒,免手动触发,提高便利性
- **功能描述**
用户可以通过语音唤醒功能在不需要点击按钮的情况下激活AI助手提高使用便捷性和用户体验。当用户说出设定的唤醒词你好,众众系统会自动启动AI助手并进入聆听模式。
用户可以通过语音唤醒功能在不需要点击按钮的情况下激活AI助手提高使用便捷性和用户体验。唤醒词你好,众众”,唤醒后直接进入聆听模式并高亮反馈
- **需求说明**
用户可通过说出"你好,众众"唤醒AI助手系统将自动进入聆听模式。语音唤醒功能需要用户在设置App设置页面或AI助手的设置页面中开启并且可以在有较高环境噪音的情况下进行降噪处理。唤醒后助手会给予明确的视觉和声音反馈确保用户知道系统已经准备好接收指令
语音唤醒功能需要一定的权限(例如麦克风访问权限),系统会在首次使用时提示用户授予必要权限。为保护用户隐私,语音数据会在本地进行初步处理,只有确认唤醒后才会发送到服务器。此功能在使用过程中会考虑电池消耗,在低电量模式下可能会自动降低敏感度或暂时关闭
- 设置页开启后常驻监听(低功耗策略)。
- 唤醒检测在本地执行,未唤醒音频不上传
- 唤醒成功:音效 + 动画反馈。
- 低电量模式:可自动降敏或暂停
- 权限缺失:首次引导开启麦克风权限。
### 3.3 聊天模块
@@ -259,7 +299,9 @@ graph TD
普通问答现在只有用车助手这个场景,后续增加新的场景:购车助手;需要先通过文本语义判断是哪个场景,然后根据相应场景来回复问题。
- **需求说明**
- 场景识别由后端完成,前端仅消费分类结果
- SSE按流片段累积合并为 Markdown
不管是购车场景还是用车场景或者是开放式对话都有一个问答的流程场景的区分不是前端来判断。现在流程是将语音转化的文本通过接口发给后台服务然后后台会根据body里面的text和conversation_id 来返回一个文件流客户端这边会把文件流的全部数据接受完成后合并为一个markdown语法的文本。
```mermaid
@@ -274,7 +316,7 @@ graph TD
现在有两个新的调整方案一个是Socket连接另外一个方案是在现有的流程基础上新增消息类型。
1. Socket方案
1. Socket方案
每次进入AI助手会话会创建一个随机的taskId然后每次对话都会有一个conversationId使用taskId 连接Socket成功后就可以通过Socket发送语音或者文本消息。然后Socket 会返回三种不同的消息类型,`it消息 (识别文本)``gb消息 (回复文本)``tts消息 (语音数据)`
@@ -303,7 +345,7 @@ sequenceDiagram
Note over C, S: 连接保持,可继续发送新语音或关闭
```
1. HTTP方案
2. HTTP方案
HTTP方案是保持原有流程的情况下进行扩展chat API 不再是返回一个数据流而是返回一个json数据json数据里面会有不同的消息返回对应上面不同的气泡类型消息类似分为`stream``text``media``bussines``stream`消息就是之前的数据流的消息,通过`messageId`就可以获取到数据;`text`消息是普通的文本消息,可以实现上面的链接气泡,按钮气泡;`media`消息则可以实现负责的图文混排,或者是一个单纯的视频教程;`bussines`消息主要以业务相关的,会根据业务类型显示不一样的样式,内容和按钮也会有变化。
@@ -359,6 +401,243 @@ HTTP方案是保持原有流程的情况下进行扩展chat API 不再是返
- **后备箱控制**:开启、关闭
- **特殊功能**:鸣笛、车辆定位、一键备车、一键融雪
#### **3.3.4 聊天信息持久化**
- **用户场景**
用户在与AI助手进行对话时会产生多条聊天记录。为保护用户隐私和提升体验这些聊天记录默认仅保存在本地设备不会上传至云端。
- **功能描述**
系统支持本地化持久化存储普通问答类型的聊天记录。所有文本类消息将以结构化数据形式保存至本地数据库推荐使用SQLite或Hive等Flutter主流轻量级数据库便于后续检索和管理。
- **需求说明**
- **本地存储**所有与AI助手的聊天记录包括文本、语音、气泡类型、时间戳等需保存在本地设备支持持久化
- **存储方式**采用本地数据库如SQLite、Hive等Flutter常用方案或文件存储保证数据安全和高效读写
- **读取与展示**:用户重新进入聊天界面时,不会自动加载历史聊天记录,点击显示历史记录之后才会加载聊天记录,按时间顺序展示;
- **数据结构**每条聊天记录需包含消息ID、会话ID、消息类型文本/语音/卡片/按钮/富媒体)、内容、时间戳、发送方(用户/AI、气泡类型等
- **删除与清理**支持用户手动删除单条或全部聊天记录支持定期自动清理如超过30天自动删除
- **持久化逻辑**在Socket和HTTP两种消息方案下收到消息体后系统会优先将stream和text类型消息持久化保存其他类型消息仅用于即时展示不做持久化处理。
有了消息的持久化AI助手聊天消息的显示逻辑也会跟着变化按照上面的`Socket`方案和`HTTP`方案,收到消息体之后首先会保存到本地,特别是`HTTP`方案中会有多条消息返回持久化只会保存stream和text消息其他消息不会保存。
```mermaid
graph TD
A[收到AI助手消息] --> B[显示消息到聊天界面]
B --> C{消息类型判断}
C -->|stream/text| D[持久化保存到本地数据库]
C -->|其他类型| E[仅显示,不持久化]
D --> F[历史消息管理]
F --> G[用户点击显示历史记录]
G --> H[加载历史消息并展示]
```
## 4. 非功能需求
### 4.1 服务模块
#### **4.1.1 模块设计目标**
服务模块负责“输入 → 解析 → 对话/车控 → 反馈 → 持久化”全链路的能力封装向上提供简单一致的编程接口向下屏蔽多种后端形态HTTP / SSE与原生能力录音、TTS、权限、ASR
设计目标:
- 解耦:各服务单一职责,可独立替换;
- 可扩展:新协议 / 新命令 / 新气泡类型通过注册或策略扩展;
- 可裁剪:按需选择(如不需要车控,可不接入 command 子模块)。
#### **4.1.2 模块目录设计**
拟将现有核心服务抽离为独立基础包例如ai_chat_core供 UI 插件依赖。
建议目录结构:
```
packages/
ai_chat_core/
ai_chat_core.dart # 对外统一入口
src/ # 代码目录
models/ # models
message.dart # 消息和消息块
message_chunk.dart
vehicle_command.dart # 车控
vehicle_command_response.dart
command_result.dart
enums/ # enums
message_type.dart
message_status.dart
command_type.dart
service_state.dart # 服务状态
input/
audio_recorder_service.dart # 录音以及保存文件
voice_recognition_service.dart # 目前项目未使用
wake_word_service.dart # 预留(可选)
nlp/ # 自然语言处理相关
text_classification_service.dart
vehicle_command_service.dart
dialog/ #对话相关的
chat_channel/
chat_sse_service.dart # SSE
chat_ws_service.dart # 预留 WebSocket可选
chat_http_service.dart # 批量 HTTP 方案(可选)
message_service.dart # 核心编排/状态更新
tts/ # TTS
tts_service.dart
tts_task_queue.dart
command/ # 车控相关
command_service.dart # Command Register Callback已更新为抽象类的方式
vehicle_command_handler.dart # 自定义实现车控命令
persistence/ # 持久化
persistence_service.dart # 提供持久化服务
dao/ # dao
message_dao.dart # 消息体的 dao 对象
infra/ # infra 的服务
config_service.dart
redis_service.dart
location_service.dart
vehicle_state_service.dart # 预留
logger.dart
error_mapper.dart
utils/ # 工具类
markdown_cleaner.dart
id_generator.dart
throttle.dart
```
对外暴露ai_chat_core.dart仅导出
- models / enums
- MessageService主入口
- VehicleCommandHandler 抽象
- 配置初始化initCore / setConfig
#### **4.1.3 核心服务说明**
| 服务 | 角色 | 主要职责 | 关键点 |
| ---- | ---- | -------- | ------ |
| MessageService | 总编排 | 状态机、消息生命周期、调用链调度 | 统一入口 |
| AudioRecorderService | 输入 | 录音启动/停止、静音检测 | 录制参数配置 |
| VoiceRecognitionService | 输入处理 | 语音转文本(在线识别 / 中英判别) | 失败降级提示 |
| WakeWordService | 输入唤醒 | 本地唤醒词检测 | 低功耗策略 |
| TextClassificationService | 语义分类 | 业务场景 / 指令 / 问答判断 | 分类缓存 |
| VehicleCommandService | 语义→结构 | 解析多条车控命令列表 + 参数 | 容错解析 |
| CommandService | 执行派发 | 调用 Host 注入的 VehicleCommandHandler | 失败重试 |
| ChatSseService | 对话通道 | SSE 流接收与分片回调 | 首 Token 优化 |
| ChatWsService预留 | 对话通道 | WebSocket 统一多类型消息 | 心跳+重连 |
| ChatHttpService预留 | 对话通道 | 一次性批量消息 | 并行补拉 |
| TtsService + TtsTaskQueue | 输出播报 | 分句 / 排队 / 抢占 / 语言切换 | 顺序一致性 |
| PersistenceService | 持久化 | 消息落地 / 分页 / 过期清理 | schema 迁移 |
| RedisService | 辅助缓存 | 临时状态(可选) | 可替换 |
| LocationService | 扩展 | 位置信息(用于上下文) | 可选注入 |
| VehicleStateService | 扩展 | 实时车况(未来支持) | 监听通道 |
| ConfigService | 基础设施 | 端点 / 超时 / 重试策略统一 | 环境隔离 |
| Logger | 基础设施 | 分级日志 + 调试开关 | 生产开关 |
| MarkdownCleaner | 工具 | 清理/裁剪 Markdown 用于 TTS | 多语言规则 |
| ErrorMapper | 工具 | 后端错误码 → 用户友好文案 | 本地化适配 |
#### **4.1.4 服务分层**
- 链路图
```mermaid
sequenceDiagram
autonumber
participant UI as UI层
participant MS as MessageService
participant AR as AudioRecorder
participant ASR as VoiceRecognition
participant CLS as TextClassification
participant VCS as VehicleCommandService
participant DLG as ChatSse/WS/HTTP
participant CMD as CommandService
participant HND as VehicleCommandHandler(Host)
participant TTS as TtsService
participant PERS as PersistenceService
UI->>MS: startVoiceInput()
MS->>AR: start()
AR-->>MS: audioChunks / silenceEnd
MS->>AR: stop()
MS->>ASR: recognize(audio)
ASR-->>MS: recognizedText
MS->>CLS: classify(text)
CLS-->>MS: category / scenario
alt 车控指令
MS->>VCS: parseCommands(text)
VCS-->>MS: commands[]
loop each command
MS->>CMD: execute(command)
CMD->>HND: executeCommand(command)
HND-->>CMD: result(success/fail)
CMD-->>MS: executionResult
MS->>TTS: enqueue("执行结果反馈")
MS->>PERS: save(control_feedback)
end
else 普通问答
MS->>DLG: requestStream(text, convId)
DLG-->>MS: streamChunk/ finalMessage
MS->>TTS: enqueue(chunk/segments)
MS->>PERS: save(text / merged)
else 错误/兜底
MS->>TTS: enqueue(提示语)
MS->>PERS: save(system_message)
end
TTS-->>UI: 播放中事件
PERS-->>MS: persist OK
MS-->>UI: 更新消息列表
```
- 逻辑分层
```mermaid
graph TD
A[UI层] --> B[MessageService]
B --> C1[输入层 AudioRecorder / WakeWord]
B --> C2[语义层 Classification / VehicleCommand]
B --> C3[对话通道层 SSE / WS / HTTP]
B --> C4[执行层 CommandService + Host Handler]
B --> C5[输出层 TtsService]
B --> C6[存储层 PersistenceService]
B --> C7[基础设施 Config / Logger / Redis / Location]
```
#### **4.1.5 代码示例**
- 初始化:
```dart
await AiChatCore.init(
config: CoreConfig(
endpoints: Endpoints(
classify: "...",
sse: "...",
ws: "...",
controlParse: "...",
controlExec: "...",
voice: "...",
),
timeouts: Timeouts(connectMs: 8000, receiveMs: 20000),
enablePersistence: true,
persistenceMode: PersistenceMode.hive,
retryPolicy: RetryPolicy(maxAttempts: 2, backoffBaseMs: 400),
),
commandHandler: MyVehicleCommandHandler(),
logger: CustomLogger(),
);
```
- 统一公共接口:
```dart
abstract class AiChatCore {
static Future<void> init({required CoreConfig config, required VehicleCommandHandler commandHandler, Logger? logger});
static MessageService get messageService;
static PersistenceService? get persistence;
}
class MessageService {
Stream<List<Message>> get messageStream;
Future<void> startVoiceInput();
Future<void> stopAndProcessVoiceInput();
Future<void> sendText(String text);
Future<void> abortAnswer();
Future<void> loadHistory({required int page, required int pageSize});
}
```
## 参考文件
[AI Assistant in One App.pdf](https://telekom-my.sharepoint.de/:b:/r/personal/guangfei_zhao_t-systems_com/Documents/Dokumente/AI%20Assistant%20in%20One%20App.pdf?csf=1&web=1&e=On4V2o)