diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/jarvis/SocialMediaController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/jarvis/SocialMediaController.java new file mode 100644 index 0000000..adf22bf --- /dev/null +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/jarvis/SocialMediaController.java @@ -0,0 +1,101 @@ +package com.ruoyi.web.controller.jarvis; + +import com.ruoyi.common.annotation.Log; +import com.ruoyi.common.core.controller.BaseController; +import com.ruoyi.common.core.domain.AjaxResult; +import com.ruoyi.common.enums.BusinessType; +import com.ruoyi.jarvis.service.ISocialMediaService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.util.Map; + +/** + * 小红书/抖音内容生成Controller + * + * @author ruoyi + * @date 2025-01-XX + */ +@RestController +@RequestMapping("/jarvis/social-media") +public class SocialMediaController extends BaseController +{ + @Autowired + private ISocialMediaService socialMediaService; + + /** + * 提取关键词 + */ + @PostMapping("/extract-keywords") + public AjaxResult extractKeywords(@RequestBody Map request) + { + try { + String productName = (String) request.get("productName"); + if (productName == null || productName.trim().isEmpty()) { + return AjaxResult.error("商品名称不能为空"); + } + + Map result = socialMediaService.extractKeywords(productName); + return AjaxResult.success(result); + } catch (Exception e) { + logger.error("提取关键词失败", e); + return AjaxResult.error("提取关键词失败: " + e.getMessage()); + } + } + + /** + * 生成文案 + */ + @PostMapping("/generate-content") + public AjaxResult generateContent(@RequestBody Map request) + { + try { + String productName = (String) request.get("productName"); + if (productName == null || productName.trim().isEmpty()) { + return AjaxResult.error("商品名称不能为空"); + } + + Object originalPriceObj = request.get("originalPrice"); + Object finalPriceObj = request.get("finalPrice"); + String keywords = (String) request.get("keywords"); + String style = (String) request.getOrDefault("style", "both"); + + Map result = socialMediaService.generateContent( + productName, originalPriceObj, finalPriceObj, keywords, style + ); + return AjaxResult.success(result); + } catch (Exception e) { + logger.error("生成文案失败", e); + return AjaxResult.error("生成文案失败: " + e.getMessage()); + } + } + + /** + * 一键生成完整内容(关键词 + 文案 + 图片) + */ + @Log(title = "小红书/抖音内容生成", businessType = BusinessType.OTHER) + @PostMapping("/generate-complete") + public AjaxResult generateComplete(@RequestBody Map request) + { + try { + String productImageUrl = (String) request.get("productImageUrl"); + String productName = (String) request.get("productName"); + if (productName == null || productName.trim().isEmpty()) { + return AjaxResult.error("商品名称不能为空"); + } + + Object originalPriceObj = request.get("originalPrice"); + Object finalPriceObj = request.get("finalPrice"); + String style = (String) request.getOrDefault("style", "both"); + + Map result = socialMediaService.generateCompleteContent( + productImageUrl, productName, originalPriceObj, finalPriceObj, style + ); + return AjaxResult.success(result); + } catch (Exception e) { + logger.error("生成完整内容失败", e); + return AjaxResult.error("生成完整内容失败: " + e.getMessage()); + } + } +} + diff --git a/ruoyi-system/src/main/java/com/ruoyi/jarvis/service/ISocialMediaService.java b/ruoyi-system/src/main/java/com/ruoyi/jarvis/service/ISocialMediaService.java new file mode 100644 index 0000000..cf328c7 --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/jarvis/service/ISocialMediaService.java @@ -0,0 +1,47 @@ +package com.ruoyi.jarvis.service; + +import java.util.Map; + +/** + * 小红书/抖音内容生成Service接口 + * + * @author ruoyi + * @date 2025-01-XX + */ +public interface ISocialMediaService +{ + /** + * 提取商品标题关键词 + * + * @param productName 商品名称 + * @return 关键词结果 + */ + Map extractKeywords(String productName); + + /** + * 生成文案 + * + * @param productName 商品名称 + * @param originalPrice 原价 + * @param finalPrice 到手价 + * @param keywords 关键词 + * @param style 文案风格 + * @return 生成的文案 + */ + Map generateContent(String productName, Object originalPrice, + Object finalPrice, String keywords, String style); + + /** + * 一键生成完整内容(关键词 + 文案 + 图片) + * + * @param productImageUrl 商品主图URL + * @param productName 商品名称 + * @param originalPrice 原价 + * @param finalPrice 到手价 + * @param style 文案风格 + * @return 完整内容 + */ + Map generateCompleteContent(String productImageUrl, String productName, + Object originalPrice, Object finalPrice, String style); +} + diff --git a/ruoyi-system/src/main/java/com/ruoyi/jarvis/service/impl/SocialMediaServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/jarvis/service/impl/SocialMediaServiceImpl.java new file mode 100644 index 0000000..b4b47fe --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/jarvis/service/impl/SocialMediaServiceImpl.java @@ -0,0 +1,249 @@ +package com.ruoyi.jarvis.service.impl; + +import com.alibaba.fastjson2.JSON; +import com.alibaba.fastjson2.JSONObject; +import com.ruoyi.common.utils.StringUtils; +import com.ruoyi.common.utils.http.HttpUtils; +import com.ruoyi.jarvis.service.ISocialMediaService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Service; + +import java.util.HashMap; +import java.util.Map; + +/** + * 小红书/抖音内容生成Service业务层处理 + * + * @author ruoyi + * @date 2025-01-XX + */ +@Service +public class SocialMediaServiceImpl implements ISocialMediaService +{ + private static final Logger log = LoggerFactory.getLogger(SocialMediaServiceImpl.class); + + // jarvis_java 服务地址 + private final static String JARVIS_BASE_URL = "http://192.168.8.88:6666"; + + /** + * 提取商品标题关键词 + */ + @Override + public Map extractKeywords(String productName) { + Map result = new HashMap<>(); + + if (StringUtils.isEmpty(productName)) { + result.put("success", false); + result.put("error", "商品名称不能为空"); + return result; + } + + try { + // 调用 jarvis_java 的接口 + String url = JARVIS_BASE_URL + "/jarvis/social-media/extract-keywords"; + JSONObject requestBody = new JSONObject(); + requestBody.put("productName", productName); + + log.info("调用jarvis_java提取关键词接口,URL: {}, 参数: {}", url, requestBody.toJSONString()); + String response = HttpUtils.sendJsonPost(url, requestBody.toJSONString()); + log.info("jarvis_java响应: {}", response); + + if (StringUtils.isEmpty(response)) { + throw new Exception("jarvis_java返回空结果"); + } + + // 解析响应 + Object parsed = JSON.parse(response); + if (parsed instanceof JSONObject) { + JSONObject jsonResponse = (JSONObject) parsed; + if (jsonResponse.getInteger("code") == 200) { + Object data = jsonResponse.get("data"); + if (data instanceof Map) { + @SuppressWarnings("unchecked") + Map dataMap = (Map) data; + return dataMap; + } + } else { + String msg = jsonResponse.getString("msg"); + result.put("success", false); + result.put("error", msg != null ? msg : "提取关键词失败"); + return result; + } + } + + result.put("success", false); + result.put("error", "响应格式错误"); + return result; + + } catch (Exception e) { + log.error("提取关键词失败", e); + result.put("success", false); + result.put("error", "提取关键词失败: " + e.getMessage()); + return result; + } + } + + /** + * 生成文案 + */ + @Override + public Map generateContent(String productName, Object originalPrice, + Object finalPrice, String keywords, String style) { + Map result = new HashMap<>(); + + if (StringUtils.isEmpty(productName)) { + result.put("success", false); + result.put("error", "商品名称不能为空"); + return result; + } + + try { + // 调用 jarvis_java 的接口 + String url = JARVIS_BASE_URL + "/jarvis/social-media/generate-content"; + JSONObject requestBody = new JSONObject(); + requestBody.put("productName", productName); + if (originalPrice != null) { + requestBody.put("originalPrice", parseDouble(originalPrice)); + } + if (finalPrice != null) { + requestBody.put("finalPrice", parseDouble(finalPrice)); + } + if (StringUtils.isNotEmpty(keywords)) { + requestBody.put("keywords", keywords); + } + if (StringUtils.isNotEmpty(style)) { + requestBody.put("style", style); + } + + log.info("调用jarvis_java生成文案接口,URL: {}, 参数: {}", url, requestBody.toJSONString()); + String response = HttpUtils.sendJsonPost(url, requestBody.toJSONString()); + log.info("jarvis_java响应: {}", response); + + if (StringUtils.isEmpty(response)) { + throw new Exception("jarvis_java返回空结果"); + } + + // 解析响应 + Object parsed = JSON.parse(response); + if (parsed instanceof JSONObject) { + JSONObject jsonResponse = (JSONObject) parsed; + if (jsonResponse.getInteger("code") == 200) { + Object data = jsonResponse.get("data"); + if (data instanceof Map) { + @SuppressWarnings("unchecked") + Map dataMap = (Map) data; + return dataMap; + } + } else { + String msg = jsonResponse.getString("msg"); + result.put("success", false); + result.put("error", msg != null ? msg : "生成文案失败"); + return result; + } + } + + result.put("success", false); + result.put("error", "响应格式错误"); + return result; + + } catch (Exception e) { + log.error("生成文案失败", e); + result.put("success", false); + result.put("error", "生成文案失败: " + e.getMessage()); + return result; + } + } + + /** + * 一键生成完整内容(关键词 + 文案 + 图片) + */ + @Override + public Map generateCompleteContent(String productImageUrl, String productName, + Object originalPrice, Object finalPrice, String style) { + Map result = new HashMap<>(); + + if (StringUtils.isEmpty(productName)) { + result.put("success", false); + result.put("error", "商品名称不能为空"); + return result; + } + + try { + // 调用 jarvis_java 的接口 + String url = JARVIS_BASE_URL + "/jarvis/social-media/generate-complete"; + JSONObject requestBody = new JSONObject(); + if (StringUtils.isNotEmpty(productImageUrl)) { + requestBody.put("productImageUrl", productImageUrl); + } + requestBody.put("productName", productName); + if (originalPrice != null) { + requestBody.put("originalPrice", parseDouble(originalPrice)); + } + if (finalPrice != null) { + requestBody.put("finalPrice", parseDouble(finalPrice)); + } + if (StringUtils.isNotEmpty(style)) { + requestBody.put("style", style); + } + + log.info("调用jarvis_java生成完整内容接口,URL: {}, 参数: {}", url, requestBody.toJSONString()); + String response = HttpUtils.sendJsonPost(url, requestBody.toJSONString()); + log.info("jarvis_java响应: {}", response); + + if (StringUtils.isEmpty(response)) { + throw new Exception("jarvis_java返回空结果"); + } + + // 解析响应 + Object parsed = JSON.parse(response); + if (parsed instanceof JSONObject) { + JSONObject jsonResponse = (JSONObject) parsed; + if (jsonResponse.getInteger("code") == 200) { + Object data = jsonResponse.get("data"); + if (data instanceof Map) { + @SuppressWarnings("unchecked") + Map dataMap = (Map) data; + return dataMap; + } + } else { + String msg = jsonResponse.getString("msg"); + result.put("success", false); + result.put("error", msg != null ? msg : "生成完整内容失败"); + return result; + } + } + + result.put("success", false); + result.put("error", "响应格式错误"); + return result; + + } catch (Exception e) { + log.error("生成完整内容失败", e); + result.put("success", false); + result.put("error", "生成完整内容失败: " + e.getMessage()); + return result; + } + } + + /** + * 解析Double值 + */ + private Double parseDouble(Object value) { + if (value == null) { + return null; + } + if (value instanceof Double) { + return (Double) value; + } + if (value instanceof Number) { + return ((Number) value).doubleValue(); + } + try { + return Double.parseDouble(value.toString()); + } catch (Exception e) { + return null; + } + } +} +