feat: 支持 nutrition_data_json 嵌套格式存储(带 value/unit)
- 新增 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 实现
This commit is contained in:
@@ -614,7 +614,9 @@ public class ToolCommunityServiceImpl implements ToolCommunityService {
|
|||||||
Map<String, Object> nutrition = toolNutritionFillService.fillFromText(text.toString());
|
Map<String, Object> nutrition = toolNutritionFillService.fillFromText(text.toString());
|
||||||
if (nutrition.isEmpty()) throw new CrmebException("AI 未能估算出营养数据");
|
if (nutrition.isEmpty()) throw new CrmebException("AI 未能估算出营养数据");
|
||||||
|
|
||||||
post.setNutritionDataJson(JSON.toJSONString(nutrition));
|
// 存库使用嵌套格式(value/unit),与 v2_community_posts.nutrition_data_json 约定一致
|
||||||
|
Map<String, Object> nested = toolNutritionFillService.flatToNestedForDb(nutrition);
|
||||||
|
post.setNutritionDataJson(JSON.toJSONString(nested));
|
||||||
post.setUpdatedAt(new Date());
|
post.setUpdatedAt(new Date());
|
||||||
v2CommunityPostDao.updateById(post);
|
v2CommunityPostDao.updateById(post);
|
||||||
return nutrition;
|
return nutrition;
|
||||||
|
|||||||
@@ -97,4 +97,53 @@ public class ToolNutritionFillServiceImpl implements ToolNutritionFillService {
|
|||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, Object> flatToNestedForDb(Map<String, Object> flat) {
|
||||||
|
if (flat == null || flat.isEmpty()) return new HashMap<>();
|
||||||
|
Map<String, Object> 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<String, Object> nested, Map<String, Object> flat,
|
||||||
|
String flatKey, String nestedKey, String unit) {
|
||||||
|
Object v = flat.get(flatKey);
|
||||||
|
if (v == null) return;
|
||||||
|
if (v instanceof Number) {
|
||||||
|
Map<String, Object> entry = new HashMap<>();
|
||||||
|
entry.put("value", ((Number) v).doubleValue());
|
||||||
|
entry.put("unit", unit);
|
||||||
|
nested.put(nestedKey, entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public Map<String, Object> nestedToFlat(Map<String, Object> nested) {
|
||||||
|
if (nested == null || nested.isEmpty()) return new HashMap<>();
|
||||||
|
Map<String, Object> 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<String, Object> flat, Map<String, Object> 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());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,10 +11,26 @@ import java.util.Map;
|
|||||||
public interface ToolNutritionFillService {
|
public interface ToolNutritionFillService {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据一段饮食/菜品描述文本,调用 AI 估算营养数据并返回结构化结果
|
* 根据一段饮食/菜品描述文本,调用 AI 估算营养数据并返回结构化结果(扁平格式,供 AI/接口使用)
|
||||||
*
|
*
|
||||||
* @param text 饮食描述(如「今天中午吃了一碗米饭、一份青椒肉丝、一碗紫菜蛋花汤」)
|
* @param text 饮食描述(如「今天中午吃了一碗米饭、一份青椒肉丝、一碗紫菜蛋花汤」)
|
||||||
* @return 包含 energyKcal, proteinG, potassiumMg, phosphorusMg 的 Map,估算不出时为 null
|
* @return 包含 energyKcal, proteinG, potassiumMg, phosphorusMg 的 Map,估算不出时为 null
|
||||||
*/
|
*/
|
||||||
Map<String, Object> fillFromText(String text);
|
Map<String, Object> 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<String, Object> flatToNestedForDb(Map<String, Object> flat);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将数据库中的嵌套格式(value/unit)转为扁平格式,便于前端或 AI 使用
|
||||||
|
*
|
||||||
|
* @param nested 嵌套格式,如 {"calories":{"value":1850,"unit":"kcal"},...}
|
||||||
|
* @return 扁平格式,如 {"energyKcal":1850,"proteinG":65,...}
|
||||||
|
*/
|
||||||
|
Map<String, Object> nestedToFlat(Map<String, Object> nested);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user