Files
msh-system/.cursor/plans/食谱百科食物图ai生成与oss更新_b5228ab9.plan.md

92 lines
7.7 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.
---
name: 食谱百科食物图AI生成与OSS更新
overview: 对 v2_foods 表中 image 非阿里云 OSS 的记录,根据 name 调用 KieAI 生成图片(压缩至不超过 100KB上传到 OSS 并回写 v2_foods.image复用现有 DishImageServiceImpl 的 KieAI + 压缩 + OSS 能力,扩展“食物”场景并增加更新数据库的入口与触发方式。
todos: []
isProject: false
---
# 食谱百科食物图 AI 生成并更新 v2_foods.image
## 现状
- **食谱百科前端**`[msh_single_uniapp/pages/tool/food-encyclopedia.vue](msh_single_uniapp/pages/tool/food-encyclopedia.vue)` 通过 `getFoodList` / `searchFood``[api/tool.js](msh_single_uniapp/api/tool.js)`)请求 `tool/food/list``tool/food/search`,列表项中的 `image` 直接来自后端。
- **后端数据**`[ToolFoodServiceImpl](msh_crmeb_22/crmeb-service/src/main/java/com/zbkj/service/service/impl/tool/ToolFoodServiceImpl.java)``v2_foods` 查数据,返回的 map 包含 `image``[V2Food](msh_crmeb_22/crmeb-common/src/main/java/com/zbkj/common/model/tool/V2Food.java)``image` 字段)。当前部分记录的 `image` 为 Figma/非 OSS 等非阿里云地址。
- **可复用能力**`[DishImageServiceImpl](msh_crmeb_22/crmeb-service/src/main/java/com/zbkj/service/service/impl/tool/DishImageServiceImpl.java)` 已实现KieAI 文生图 → 下载图片 → **压缩至 100KB**`MAX_IMAGE_BYTES = 100*1024``compressImageToMaxBytes`)→ 上传 OSS`recipes/`)→ 写 `V2DishImageCache`。菜品 prompt 为“一道精美的中式菜品照片:{name}…”。
## 目标
-**v2_foods****image 非阿里云 OSS** 的记录:根据 **name** 调用 AI 生成图片,生成图 **不超过 100KB**,上传到 OSS 后 **更新 v2_foods.image** 为 OSS 地址。
- 判断“非 OSS”`image` 为空或 `image` 不包含当前项目使用的 OSS 域名(如配置中的 `alUploadUrl` 或固定包含 `aliyuncs.com`)。
## 实现方案
### 1. 判断“是否为 OSS 地址”
- 在公共工具或 Service 内封装:若 `image` 为空/blank视为非 OSS若不为空则判断是否包含 OSS 域名(可从 `SystemConfigService.getValueByKey(SysConfigConstants.CONFIG_AL_UPLOAD_URL)` 取域名,或简单用 `image.contains("aliyuncs.com")`)。满足则为 OSS否则需要补图。
### 2. 后端:扩展“食物图片”能力并写回 v2_foods
**方案 A推荐在现有 DishImageServiceImpl 上扩展**
-`[DishImageServiceImpl](msh_crmeb_22/crmeb-service/src/main/java/com/zbkj/service/service/impl/tool/DishImageServiceImpl.java)` 中:
- 增加 **食物** 用 prompt 方法,例如:`buildFoodImagePrompt(String foodName)`,内容为“一份新鲜的食物/食材照片:{name},高清静物摄影,白色背景或餐盘,自然光,细节清晰”(与菜品区分开)。
- 增加 **食物** 的 OSS 路径常量,如 `OSS_FOODS_PATH = "foods/"`,上传时使用 `foods/food-{sanitizedName}-{timestamp}.jpg`,与 `recipes/` 区分。
- 新增 **公共流程**`generateImageAndUploadToOss(String name, String prompt, String ossPathPrefix)`(或拆成:用现有 KieAI + 下载 + `compressImageToMaxBytes(imageBytes, 100*1024)` + 上传,仅参数为 name/prompt/路径前缀),返回 OSS 完整 URL。
- 注入 `V2FoodDao`,新增方法:`ensureFoodImageAndUpdateDb(Long foodId)`
- 根据 foodId 查 `V2Food`
-`image` 已是 OSS用上述判断直接返回当前 image
- 否则用 `buildFoodImagePrompt(food.getName())` 调用上述“生成并上传”流程,得到 ossUrl
- 更新 `food.setImage(ossUrl)``v2FoodDao.updateById(food)`
- 失败时可按现有逻辑降级为占位图并同样写回 DB或只打日志不更新视产品要求而定。
-`[DishImageService](msh_crmeb_22/crmeb-service/src/main/java/com/zbkj/service/service/tool/DishImageService.java)` 接口中声明 `ensureFoodImageAndUpdateDb(Long foodId)`(或返回 String 的 `ensureFoodImageUrl(Long foodId)` 由调用方更新 DB二选一即可
**方案 B新建 FoodImageService**
- 新建 `FoodImageService` + `FoodImageServiceImpl`,内部注入 `DishImageService` 或直接复用 KieAI、Oss、压缩逻辑若将 DishImageServiceImpl 中下载/压缩/上传抽成 package 内可复用方法,或抽到公共工具类)。
- `FoodImageServiceImpl.ensureFoodImageAndUpdateDb(Long foodId)` 查 v2_foods → 判断 image 非 OSS → 调 KieAI 生图 → 压缩 ≤100KB → 上传 OSS路径 `foods/`)→ 更新 `v2_foods.image`
- 与方案 A 二选一即可;方案 A 复用更集中,改动面小。
### 3. 触发方式(可选其一或组合)
- **按需(列表/详情)**:在 `[ToolFoodServiceImpl](msh_crmeb_22/crmeb-service/src/main/java/com/zbkj/service/service/impl/tool/ToolFoodServiceImpl.java)``getList`/`search` 返回列表前,对每条记录的 `image` 判断;若非 OSS可**异步**调用 `ensureFoodImageAndUpdateDb(food.getFoodId())`,本次仍返回原 image下次请求得到 OSS 地址;或**同步**调用(会拉长接口耗时,需权衡)。详情 `getDetail` 同理,对当前条若 image 非 OSS 可同步/异步补图并更新。
- **批量/管理端**:在 `[ToolController](msh_crmeb_22/crmeb-front/src/main/java/com/zbkj/front/controller/ToolController.java)` 或管理端增加接口,例如 `POST /api/front/tool/food/refresh-images` 或后台 `POST /api/admin/tool/food/refresh-images`:查询 `v2_foods``image` 为空或非 OSS 的记录,循环调用 `ensureFoodImageAndUpdateDb(foodId)`,可限制单次条数(如 20并返回处理数量避免一次性跑全表。
### 4. 技术细节摘要
- **图片大小**:沿用 `DishImageServiceImpl``compressImageToMaxBytes(bytes, 100*1024L)`,保证上传前 ≤100KB。
- **OSS 路径**:使用 `foods/food-{sanitizedName}-{timestamp}.jpg`,与菜品 `recipes/dish-...` 区分,便于运维与排查。
- **KieAI 配置**:与现有菜品一致,使用 `KieAIConfig``ToolKieAIService`;未配置 Token 时可按现有逻辑降级(占位图或跳过更新)。
- **前端**:无需改;列表/详情接口返回的 `image` 更新为 OSS 后,`[food-encyclopedia.vue](msh_single_uniapp/pages/tool/food-encyclopedia.vue)``[food-detail.vue](msh_single_uniapp/pages/tool/food-detail.vue)` 会自然展示新图。
### 5. 可选说明(不阻塞本次需求)
- 食谱百科列表跳详情当前为 `id=${item.name}`,而后端 `getFoodDetail``Long id`;若实际数据以 id 为主,建议前端改为传 `id=${item.id}` 并在详情用 id 请求,避免按 name 查的兼容逻辑。
## 涉及文件(建议)
| 类型 | 路径 |
| -------- | ---------------------------------------------------------------------------------------------------------------------------- |
| 接口 | `msh_crmeb_22/crmeb-service/.../tool/DishImageService.java` |
| 实现 | `msh_crmeb_22/crmeb-service/.../tool/DishImageServiceImpl.java` |
| 食物服务/控制器 | `msh_crmeb_22/crmeb-service/.../tool/ToolFoodServiceImpl.java``msh_crmeb_22/crmeb-front/.../ToolController.java`(若做按需或批量触发) |
## 流程概览
```mermaid
flowchart LR
A[v2_foods 记录] --> B{image 是否 OSS?}
B -->|是| C[直接使用]
B -->|否| D[buildFoodImagePrompt]
D --> E[KieAI 文生图]
E --> F[下载图片]
F --> G[压缩至 100KB]
G --> H[上传 OSS foods/]
H --> I[更新 v2_foods.image]
I --> C
```