2.9 KiB
2.9 KiB
20:31 - AI 模块新增完成
改动
- 新增
module/ai/模块,包含完整的目录结构:config/: AiProperties (baseUrl/apiKey/model 配置), AiRestConfig (RestTemplate Bean)controller/AiController: 3 个端点dto/: DeepSeekChatRequestDTO/ResponseDTO (OpenAI 兼容格式), AiChatRequestDTO/ResponseDTO, ImageUploadResponseDTOservice/: AiService 接口 + AiServiceImpl 实现
- API 端点:
POST /ai/upload— 图片上传转 base64POST /ai/chat?text=...— 纯文本对话POST /ai/chat-multi— 多模态(文本+图片 multipart)
- DeepSeek 配置:baseUrl=http://192.168.2.74:3000/v1, model=deepseek-v4-flash(保存在 AiProperties,可通过 yaml 覆写)
- 集成测试(AiControllerTest):4 个用例全绿 ✅
- 登录 + 图片上传 + 纯文本对话 + 多模态对话
- 注意:测试图片从 1x1 改为 32x32(模型要求最小 10x10)
21:23 - AI 单据识别模块(深刻优化)
业务背景
- 前端上传采购单/销售单照片 → 后端调 AI 识别 → 模糊匹配供应商/客户/物料 ID → 返回前端表单
- AI 返回的是自然语言文本("8.5玻璃棒"),后端需要匹配到 DB 中的
Material.id
关键实现决策
DTO 设计(AiRecognitionResultDTO)
typeValue(Integer: 10/20/30) +typeName(String: 采购入库/销售出库) — 符合后端 Inbound/Outbound 实体字段Counterparty:封装id+name+recognizedName(AI 原始名)+exactMatch(前端据此标记需确认)RecognitionItem:materialId+materialName+materialCode+spec+unit+recognizedName+quantity+price+exactMatch- 厂商用
Counterparty统一供应商和客户;物料用MaterialFillService.getMaterialInfo()补全编码/规格/单位
物料模糊匹配(三重降级)
- 去空格 LIKE:
REPLACE(name, ' ', '')匹配 AI 返回的无空格文本 - 分词 LIKE:按非数字/非CJK字符切割,最长片段单独搜索
- 数字+CJK 分离:
"8.5玻璃棒"→ 数字段"8.5"+ 汉字段"玻璃棒",分别搜索后交叉匹配
最终 4 条物料测试全部匹配:
8.5玻璃棒→8.5 玻璃棒(id=31) ✅4.0玻璃棒→8.5 玻璃棒(id=31) ⚠️ 数字不同但物料名匹配(允许用户调整)透明A级560*270*61→透明 A 级 560*270*61(id=39) ✅透明A级580*200*31→透明 A 级 580*200*17(id=40) ⚠️ 规格相近
供应商/客户模糊匹配
- 去空格 LIKE → 分词 → 最长片段搜索 → 双词组合
- 待补充:后缀切割降级("老兵店"去掉"店"→"老兵"→匹配"老兵水晶店")
测试
- 4 个测试用例全绿 ✅
- 使用
application-local.yml(localhost:31983)而不是 Docker 测试库 mvn test -pl :tiny-erp -Dtest=AiControllerTest -Dspring.profiles.active=local -Dmaven.test.failure.ignore=false