feat: 社区帖子详情页自动 AI 填充营养数据
- 在 getDetail() 中添加营养数据为空时的自动填充逻辑 - fillNutritionByAi() 方法调用 Coze 工作流 7613879935811354687 - 统一参数: input(帖子内容) + img(图片URL) - fillNutrition() 同样添加 img 参数支持
This commit is contained in:
@@ -32,6 +32,7 @@ import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONArray;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.*;
|
||||
@@ -231,6 +232,28 @@ public class ToolCommunityServiceImpl implements ToolCommunityService {
|
||||
post.setViewCount(post.getViewCount() + 1);
|
||||
v2CommunityPostDao.updateById(post);
|
||||
|
||||
|
||||
// 如果营养数据为空,使用 AI 自动填充
|
||||
if (StrUtil.isBlank(post.getNutritionDataJson())) {
|
||||
try {
|
||||
log.info("帖子 {} 营养数据为空,调用 AI 自动填充", id);
|
||||
Map<String, Object> nutritionData = fillNutritionByAi(post);
|
||||
if (nutritionData != null && !nutritionData.isEmpty()) {
|
||||
// 存库使用嵌套格式(value/unit)
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> nestedData = (Map<String, Object>) nutritionData.get("nested");
|
||||
if (nestedData != null && !nestedData.isEmpty()) {
|
||||
post.setNutritionDataJson(JSON.toJSONString(nestedData));
|
||||
post.setUpdatedAt(new Date());
|
||||
v2CommunityPostDao.updateById(post);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.warn("帖子 {} AI 营养填充失败: {}", id, e.getMessage());
|
||||
// 不影响详情返回,只是记录日志
|
||||
}
|
||||
}
|
||||
|
||||
Map<String, Object> map = new HashMap<>();
|
||||
map.put("id", post.getPostId());
|
||||
map.put("postId", post.getPostId());
|
||||
@@ -614,15 +637,35 @@ public class ToolCommunityServiceImpl implements ToolCommunityService {
|
||||
if (userId.longValue() != post.getUserId()) throw new CrmebException("只能为自己的帖子填充营养数据");
|
||||
|
||||
StringBuilder text = new StringBuilder();
|
||||
if (StrUtil.isNotBlank(post.getTitle())) text.append(post.getTitle()).append(" ");
|
||||
if (StrUtil.isNotBlank(post.getTitle())) text.append(post.getTitle()).append("\n");
|
||||
if (StrUtil.isNotBlank(post.getContent())) text.append(post.getContent());
|
||||
if (text.length() == 0) throw new CrmebException("帖子标题和内容为空,无法估算营养");
|
||||
|
||||
// 获取第一张图片 URL
|
||||
String firstImageUrl = null;
|
||||
if (StrUtil.isNotBlank(post.getImagesJson())) {
|
||||
try {
|
||||
JSONArray images = JSON.parseArray(post.getImagesJson());
|
||||
if (images != null && !images.isEmpty()) {
|
||||
firstImageUrl = images.getString(0);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.warn("帖子 {} 图片 JSON 解析失败: {}", postId, e.getMessage());
|
||||
}
|
||||
}
|
||||
// 如果没有图片数组,尝试使用封面图
|
||||
if (StrUtil.isBlank(firstImageUrl) && StrUtil.isNotBlank(post.getCoverImage())) {
|
||||
firstImageUrl = post.getCoverImage();
|
||||
}
|
||||
|
||||
// 使用 Coze 工作流进行营养成分分析
|
||||
CozeWorkflowRequest workflowRequest = new CozeWorkflowRequest();
|
||||
workflowRequest.setWorkflowId("7613879935811354687");
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("text", text.toString());
|
||||
params.put("input", text.toString());
|
||||
if (StrUtil.isNotBlank(firstImageUrl)) {
|
||||
params.put("img", firstImageUrl);
|
||||
}
|
||||
workflowRequest.setParameters(params);
|
||||
|
||||
CozeBaseResponse<Object> response = toolCozeService.workflow(workflowRequest);
|
||||
@@ -714,4 +757,95 @@ public class ToolCommunityServiceImpl implements ToolCommunityService {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* AI 自动填充帖子营养数据
|
||||
* 调用 Coze 工作流 7613879935811354687,使用帖子图片和内容进行分析
|
||||
*
|
||||
* @param post 帖子实体
|
||||
* @return 包含 flat 和 nested 格式的营养数据 Map
|
||||
*/
|
||||
private Map<String, Object> fillNutritionByAi(V2CommunityPost post) {
|
||||
if (post == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// 获取帖子内容
|
||||
StringBuilder text = new StringBuilder();
|
||||
if (StrUtil.isNotBlank(post.getTitle())) text.append(post.getTitle()).append("\n");
|
||||
if (StrUtil.isNotBlank(post.getContent())) text.append(post.getContent());
|
||||
|
||||
String content = text.toString().trim();
|
||||
if (StrUtil.isBlank(content)) {
|
||||
log.warn("帖子 {} 标题和内容为空,无法估算营养", post.getPostId());
|
||||
return null;
|
||||
}
|
||||
|
||||
// 获取第一张图片 URL
|
||||
String firstImageUrl = null;
|
||||
if (StrUtil.isNotBlank(post.getImagesJson())) {
|
||||
try {
|
||||
JSONArray images = JSON.parseArray(post.getImagesJson());
|
||||
if (images != null && !images.isEmpty()) {
|
||||
firstImageUrl = images.getString(0);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.warn("帖子 {} 图片 JSON 解析失败: {}", post.getPostId(), e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
// 如果没有图片数组,尝试使用封面图
|
||||
if (StrUtil.isBlank(firstImageUrl) && StrUtil.isNotBlank(post.getCoverImage())) {
|
||||
firstImageUrl = post.getCoverImage();
|
||||
}
|
||||
|
||||
log.info("帖子 {} AI 营养填充,图片: {}, 内容长度: {}",
|
||||
post.getPostId(),
|
||||
firstImageUrl != null ? "有" : "无",
|
||||
content.length()
|
||||
);
|
||||
|
||||
// 调用 Coze 工作流进行营养成分分析
|
||||
CozeWorkflowRequest workflowRequest = new CozeWorkflowRequest();
|
||||
workflowRequest.setWorkflowId("7613879935811354687");
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("input", content);
|
||||
if (StrUtil.isNotBlank(firstImageUrl)) {
|
||||
params.put("img", firstImageUrl);
|
||||
}
|
||||
workflowRequest.setParameters(params);
|
||||
|
||||
CozeBaseResponse<Object> response = toolCozeService.workflow(workflowRequest);
|
||||
if (response == null || response.getData() == null) {
|
||||
log.warn("帖子 {} Coze 工作流调用失败", post.getPostId());
|
||||
return null;
|
||||
}
|
||||
|
||||
// 解析工作流返回结果
|
||||
Map<String, Object> workflowResult = parseWorkflowResponse(response.getData());
|
||||
if (workflowResult == null || workflowResult.isEmpty()) {
|
||||
log.warn("帖子 {} AI 未能估算出营养数据", post.getPostId());
|
||||
return null;
|
||||
}
|
||||
|
||||
// 提取 output 中的营养数据(嵌套格式)
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> output = (Map<String, Object>) workflowResult.get("output");
|
||||
if (output == null || output.isEmpty()) {
|
||||
log.warn("帖子 {} AI 返回数据格式错误", post.getPostId());
|
||||
return null;
|
||||
}
|
||||
|
||||
// 将嵌套格式转为扁平格式
|
||||
Map<String, Object> flatNutrition = nestedToFlat(output);
|
||||
|
||||
// 返回两种格式的数据
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
result.put("flat", flatNutrition);
|
||||
result.put("nested", output);
|
||||
|
||||
log.info("帖子 {} AI 营养填充成功", post.getPostId());
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user