- summary 新增明细/聚合/分组三 Tab,对应 SummaryAggregateList(楼层→分类) 和 SummaryGroupList(按物品名分组,可展开查看分布位置) - 新增 exportDataOnly() 仅导出 CSV 不含照片,header 新增两个导出按钮 - MarkerList 聚合 Tab 从 placeholder 升级为按颜色+分类分组的实际视图 - 蓝图新增 ai-recognize 模块(planned),引入 expo-image-manipulator / expo-secure-store 依赖为后续 AI 识别功能做准备 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
69 lines
4.7 KiB
Markdown
69 lines
4.7 KiB
Markdown
---
|
||
id: ai-recognize
|
||
name: AI 照片识别填充表单
|
||
area: rn-app
|
||
status: planned
|
||
---
|
||
|
||
## 概述
|
||
|
||
用户在物品登记表单中,选取当前物品的一张或多张照片,可附加文字补充描述,发送给通义千问 Qwen-VL-Max 进行多模态识别。AI 返回富文本描述后,用户在回复文本中框选任意片段,点击字段注入按钮将其填入表单对应字段(名称、规格、单价、单位、备注)。
|
||
|
||
## 技术选型
|
||
|
||
- **API**:通义千问 Qwen-VL-Max(阿里云灵积 DashScope,OpenAI 兼容格式)
|
||
- **多图策略**:多轮对话叠加(每轮可追加图片或文字)
|
||
- **选区注入**:TextInput selectable + lastSelectionRef(blur 安全)
|
||
- **图片压缩**:expo-image-manipulator(600px / 0.65 质量,约 60KB/张)
|
||
- **密钥存储**:expo-secure-store
|
||
|
||
## 新增依赖
|
||
|
||
```
|
||
expo-secure-store # API Key / access_token 加密存储
|
||
expo-image-manipulator # 识别前压缩图片
|
||
```
|
||
|
||
## 任务卡
|
||
|
||
### 📋 通义千问 API 服务层
|
||
- status: todo
|
||
- complexity: S
|
||
- files: apps/property-survey/src/services/qianfanAI.ts
|
||
- acceptance: 封装 DashScope OpenAI 兼容接口;getApiKey() / saveApiKey() 读写 SecureStore;chat(messages) 发送多轮对话(支持 image_url + text content 混合);token 不存在时抛出带中文提示的 Error;网络/鉴权失败统一抛出可读错误;导出 QianfanMessage 类型
|
||
|
||
### 📋 API Key 设置 UI
|
||
- status: todo
|
||
- complexity: S
|
||
- files: apps/property-survey/src/features/settings/QianfanApiSettings.tsx
|
||
- depends: ai-recognize
|
||
- acceptance: 含 API Key 输入框(secureTextEntry)和保存按钮;「测试连接」按钮调 qianfanAI.chat 发一条纯文字 ping,成功显示绿色"连通 ✓",失败显示红色错误原因;组件可独立渲染,供后续接入设置入口
|
||
|
||
### 📋 useAiRecognize hook
|
||
- status: todo
|
||
- complexity: M
|
||
- files: apps/property-survey/src/features/recognize/useAiRecognize.ts
|
||
- depends: ai-recognize
|
||
- acceptance: 接收 photos: Photo[] 参数;管理 selectedIds(togglePhoto 切换)、hint 文字、messages 历史、loading、response、error 状态;lastSelectionRef 仅在 end>start 时更新(blur 不清空);getSelectedText() 从 lastSelectionRef 提取 response 子串;recognize() 将选中照片 filePath 用 expo-image-manipulator 压缩后转 base64,拼入 messages,调 qianfanAI.chat,追加 AI 回复到 messages 并更新 response;未配置 API Key 时 throw 并在 error 中显示引导文字;支持多轮追加(再次调 recognize() 时保留 messages 历史)
|
||
|
||
### 📋 AI 识别面板 UI
|
||
- status: todo
|
||
- complexity: M
|
||
- files: apps/property-survey/src/features/recognize/AiRecognizePanel.tsx, apps/property-survey/src/features/recognize/PhotoSelector.tsx, apps/property-survey/src/features/recognize/InjectionToolbar.tsx
|
||
- depends: ai-recognize
|
||
- acceptance: AiRecognizePanel 为全屏 Modal;顶部 PhotoSelector 横向滚动展示照片缩略图,选中项右上角绿色勾;hint TextInput 单行(placeholder:"补充描述,如品牌型号…");「识别」按钮 loading 时显示 ActivityIndicator;response 区域用 multiline TextInput(editable=false,selectable=true,onSelectionChange 更新 hook);底部 InjectionToolbar 固定显示「→名称」「→规格」「→单价」「→单位」「→备注」5个按钮,点击时调 onInject(field, selectedText);selectedText 为空时按钮 disabled;注入成功后对应按钮短暂变绿(300ms);error 非空时在 response 区上方显示红色提示条
|
||
|
||
### 📋 表单接线
|
||
- status: todo
|
||
- complexity: S
|
||
- files: apps/property-survey/src/features/item/useItemForm.ts, apps/property-survey/src/features/item/ItemFields.tsx
|
||
- depends: ai-recognize
|
||
- acceptance: useItemForm 新增 injectField(key: keyof FormState, value: string) 方法(调 setField 并标记 isDirty);ItemFields 照片列顶部「照片」标题行右侧增加「✨ AI」文字按钮(仅 photoItemId 非空时显示);点击打开 AiRecognizePanel Modal,传入当前物品照片列表和 injectField 回调;注入后 Modal 保持打开,用户可继续框选其他字段
|
||
|
||
## 决策记录
|
||
|
||
- 选用通义千问 Qwen-VL-Max:阿里电商生态训练数据对家具/家电/品牌商品识别最准,且价格为同档位最低(约 0.003元/千token)
|
||
- 多轮对话而非一次性多图:允许用户逐步追加照片和追问,比一次提交更灵活
|
||
- TextInput selectable 方案而非分句 Chip:原生文本选择体验与系统一致,且支持任意粒度框选(如只选价格数字);用 lastSelectionRef 解决 blur 丢选区问题
|
||
- 图片压缩到 600px/0.65:实测约 55-70KB/张,3张约 200KB,在 4MB API 限制内且不明显影响识别准确度
|