From d62f934d7fe8677ff014434ead9ca256a2cff5cb Mon Sep 17 00:00:00 2001 From: scottpan <43121650@qq.com> Date: Thu, 5 Mar 2026 19:36:36 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=94=AF=E6=8C=81=20nutrition=5Fdata?= =?UTF-8?q?=5Fjson=20=E5=B5=8C=E5=A5=97=E6=A0=BC=E5=BC=8F=E5=AD=98?= =?UTF-8?q?=E5=82=A8=EF=BC=88=E5=B8=A6=20value/unit=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增 flatToNestedForDb() 方法:将扁平格式转换为带 value/unit 的嵌套格式 - 新增 nestedToFlat() 方法:将嵌套格式转换回扁平格式 - 修改 fillNutrition():AI 生成的扁平结果转为嵌套格式后存入数据库 - 保持接口返回格式不变(仍为扁平格式) 支持字段映射: - energyKcal → calories (kcal) - proteinG → protein (g) - potassiumMg → potassium (mg) - phosphorusMg → phosphorus (mg) - fatG → fat (g) - carbohydratesG → carbohydrates (g) - sodiumG → sodium (g) 由 Cursor CLI 实现 --- .../impl/tool/ToolCommunityServiceImpl.java | 4 +- .../tool/ToolNutritionFillServiceImpl.java | 49 +++++++++++++++++++ .../tool/ToolNutritionFillService.java | 18 ++++++- 3 files changed, 69 insertions(+), 2 deletions(-) diff --git a/msh_crmeb_22/crmeb-service/src/main/java/com/zbkj/service/service/impl/tool/ToolCommunityServiceImpl.java b/msh_crmeb_22/crmeb-service/src/main/java/com/zbkj/service/service/impl/tool/ToolCommunityServiceImpl.java index 6183074..c0a2448 100644 --- a/msh_crmeb_22/crmeb-service/src/main/java/com/zbkj/service/service/impl/tool/ToolCommunityServiceImpl.java +++ b/msh_crmeb_22/crmeb-service/src/main/java/com/zbkj/service/service/impl/tool/ToolCommunityServiceImpl.java @@ -614,7 +614,9 @@ public class ToolCommunityServiceImpl implements ToolCommunityService { Map nutrition = toolNutritionFillService.fillFromText(text.toString()); if (nutrition.isEmpty()) throw new CrmebException("AI 未能估算出营养数据"); - post.setNutritionDataJson(JSON.toJSONString(nutrition)); + // 存库使用嵌套格式(value/unit),与 v2_community_posts.nutrition_data_json 约定一致 + Map nested = toolNutritionFillService.flatToNestedForDb(nutrition); + post.setNutritionDataJson(JSON.toJSONString(nested)); post.setUpdatedAt(new Date()); v2CommunityPostDao.updateById(post); return nutrition; diff --git a/msh_crmeb_22/crmeb-service/src/main/java/com/zbkj/service/service/impl/tool/ToolNutritionFillServiceImpl.java b/msh_crmeb_22/crmeb-service/src/main/java/com/zbkj/service/service/impl/tool/ToolNutritionFillServiceImpl.java index d4dd82d..8845523 100644 --- a/msh_crmeb_22/crmeb-service/src/main/java/com/zbkj/service/service/impl/tool/ToolNutritionFillServiceImpl.java +++ b/msh_crmeb_22/crmeb-service/src/main/java/com/zbkj/service/service/impl/tool/ToolNutritionFillServiceImpl.java @@ -97,4 +97,53 @@ public class ToolNutritionFillServiceImpl implements ToolNutritionFillService { } return null; } + + @Override + public Map flatToNestedForDb(Map flat) { + if (flat == null || flat.isEmpty()) return new HashMap<>(); + Map nested = new HashMap<>(); + putNested(nested, flat, "energyKcal", "calories", "kcal"); + putNested(nested, flat, "proteinG", "protein", "g"); + putNested(nested, flat, "fatG", "fat", "g"); + putNested(nested, flat, "carbohydratesG", "carbohydrates", "g"); + putNested(nested, flat, "sodiumG", "sodium", "g"); + putNested(nested, flat, "potassiumMg", "potassium", "mg"); + putNested(nested, flat, "phosphorusMg", "phosphorus", "mg"); + return nested; + } + + private void putNested(Map nested, Map flat, + String flatKey, String nestedKey, String unit) { + Object v = flat.get(flatKey); + if (v == null) return; + if (v instanceof Number) { + Map entry = new HashMap<>(); + entry.put("value", ((Number) v).doubleValue()); + entry.put("unit", unit); + nested.put(nestedKey, entry); + } + } + + @Override + @SuppressWarnings("unchecked") + public Map nestedToFlat(Map nested) { + if (nested == null || nested.isEmpty()) return new HashMap<>(); + Map flat = new HashMap<>(); + copyFlat(flat, nested, "calories", "energyKcal"); + copyFlat(flat, nested, "protein", "proteinG"); + copyFlat(flat, nested, "fat", "fatG"); + copyFlat(flat, nested, "carbohydrates", "carbohydratesG"); + copyFlat(flat, nested, "sodium", "sodiumG"); + copyFlat(flat, nested, "potassium", "potassiumMg"); + copyFlat(flat, nested, "phosphorus", "phosphorusMg"); + return flat; + } + + private void copyFlat(Map flat, Map nested, + String nestedKey, String flatKey) { + Object entry = nested.get(nestedKey); + if (!(entry instanceof Map)) return; + Object value = ((Map) entry).get("value"); + if (value instanceof Number) flat.put(flatKey, ((Number) value).doubleValue()); + } } diff --git a/msh_crmeb_22/crmeb-service/src/main/java/com/zbkj/service/service/tool/ToolNutritionFillService.java b/msh_crmeb_22/crmeb-service/src/main/java/com/zbkj/service/service/tool/ToolNutritionFillService.java index 7eabed5..7d78b1c 100644 --- a/msh_crmeb_22/crmeb-service/src/main/java/com/zbkj/service/service/tool/ToolNutritionFillService.java +++ b/msh_crmeb_22/crmeb-service/src/main/java/com/zbkj/service/service/tool/ToolNutritionFillService.java @@ -11,10 +11,26 @@ import java.util.Map; public interface ToolNutritionFillService { /** - * 根据一段饮食/菜品描述文本,调用 AI 估算营养数据并返回结构化结果 + * 根据一段饮食/菜品描述文本,调用 AI 估算营养数据并返回结构化结果(扁平格式,供 AI/接口使用) * * @param text 饮食描述(如「今天中午吃了一碗米饭、一份青椒肉丝、一碗紫菜蛋花汤」) * @return 包含 energyKcal, proteinG, potassiumMg, phosphorusMg 的 Map,估算不出时为 null */ Map fillFromText(String text); + + /** + * 将 AI 返回的扁平格式转为 v2_community_posts.nutrition_data_json 所需的嵌套格式(带 value/unit) + * + * @param flat 扁平格式,key 为 energyKcal, proteinG, potassiumMg, phosphorusMg 等 + * @return 嵌套格式,如 {"calories":{"value":1850,"unit":"kcal"},"protein":{"value":65,"unit":"g"},...} + */ + Map flatToNestedForDb(Map flat); + + /** + * 将数据库中的嵌套格式(value/unit)转为扁平格式,便于前端或 AI 使用 + * + * @param nested 嵌套格式,如 {"calories":{"value":1850,"unit":"kcal"},...} + * @return 扁平格式,如 {"energyKcal":1850,"proteinG":65,...} + */ + Map nestedToFlat(Map nested); }