评论+ds

This commit is contained in:
Van0313
2025-04-28 16:28:31 +08:00
parent 42f65bafd1
commit 5dcae40907
2 changed files with 115 additions and 14 deletions

View File

@@ -3,6 +3,7 @@ package cn.van.business.util;
import cn.van.business.model.jd.OrderRow;
import cn.van.business.repository.OrderRowRepository;
import cn.van.business.util.ds.DeepSeekClientUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
@@ -30,6 +31,7 @@ import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
@@ -76,6 +78,8 @@ public class JDUtil {
private static final String ACCESS_TOKEN = "";
private static final Logger logger = LoggerFactory.getLogger(JDUtil.class);
private static final String INTERACTION_STATE_PREFIX = "interaction_state:";
private static final String COMMENT_TEMPLATES = "comment_templates";
private static final String COMMENT_TEMPLATES_DS = "我需要为我的商品模拟一些商品评论。你协助我生成评价内容100字以内即可。我会为你提供其他真实用户的评论";
private static final long TIMEOUT_MINUTES = 10;
private static final String WENAN_FANAN_LQD = "提供方法自己下单\n" + "全程都是自己的账号下单\n" + "标价就是下单的到手价\n" + "本人有耐心,会一步一步提供教程\n" + "以后有什么质量问题都是用自己的账号走京东售后\n" + "\n" + "更新\n" + "\n" + "用你自己的账号下单\n" + "官方店铺 提供方法自己下单\n" + "——————————————————————————————————————————\n" + "同行可长久合作,可提供神级家电线报\n" + "\n" + "配合家电线报可以自己下单,不用找代购和代下,订单和利润都掌握在自己手中。\n" + "\n" + "一次入会永久使用,包含家电帮,雷神价,韭菜帮,河南&湖南帮,各种暗号帮后返等内部独家家电线报\n" + "\n" + "JD采销采购不定时发放独家优惠券\n" + "\n" + "基本上你能看到的京东家电低价都是从这些渠道里面出来。\n" + "\n" + "2025年家电项目新方向配合家电线报下单秒省1K+。";
private static final String WENAN_FANAN_HG = "手把手教你实现超值下单无需依赖他人全程使用个人专属账号操作所见即所得页面标价即为最终到手价。别担心操作难题我会全程贴心指导每一步都细致讲解助你轻松下单。后续若出现任何质量问题凭借个人账号就能直接对接JD官方售后售后无忧。\n" + "更新\n" + "采用自主账号下单模式,官方店铺商品随心购,专业方法全程提供!\n" + "——————————————————————————————————————————\n" + "诚邀同行建立长期合作关系,海量独家家电优惠线报倾囊相授!\n" + "借助这些优质家电线报,无需寻求代购代下服务,自己就能轻松下单,订单信息与收益牢牢掌握在手中。\n" + "一次加入,终身受益!涵盖家电帮、雷神价、韭菜帮、河南 & 湖南帮等众多渠道,还有各类暗号帮后返等内部专属家电优惠信息一网打尽。\n" + "JD采销团队会不定时发放独家隐藏优惠券市面上那些令人心动的JD家电低价好物大多都源自这些渠道\n" + "2025 年家电选购新趋势,依托线报下单,轻松省下千元开支,开启超值购物之旅!";
@@ -102,6 +106,7 @@ public class JDUtil {
private final StringRedisTemplate redisTemplate;
private final OrderRowRepository orderRowRepository;
private final OrderUtil orderUtil;
private final DeepSeekClientUtil deepSeekClientUtil;
// 添加ObjectMapper来序列化和反序列化UserInteractionState
private final ObjectMapper objectMapper = new ObjectMapper();
private final ConcurrentHashMap<String, UserInteractionState> userInteractionStates = new ConcurrentHashMap<>();
@@ -109,11 +114,12 @@ public class JDUtil {
// 构造函数中注入StringRedisTemplate
@Autowired
public JDUtil(StringRedisTemplate redisTemplate, OrderRowRepository orderRowRepository, WXUtil wxUtil, OrderUtil orderUtil) {
public JDUtil(StringRedisTemplate redisTemplate, OrderRowRepository orderRowRepository, WXUtil wxUtil, OrderUtil orderUtil, DeepSeekClientUtil deepSeekClientUtil) {
this.redisTemplate = redisTemplate;
this.orderRowRepository = orderRowRepository;
this.wxUtil = wxUtil;
this.orderUtil = orderUtil;
this.deepSeekClientUtil = deepSeekClientUtil;
}
private List<OrderRow> filterOrdersByDate(List<OrderRow> orderRows, int daysBack) {
@@ -1615,7 +1621,6 @@ public class JDUtil {
// 设置当前状态为生成评论流程
state.setCurrentState(UserInteractionState.ProcessState.COMMENT_GENERATION);
state.setCurrentField("commentTypeSelection");
// 提示用户选择评论类型
wxUtil.sendTextMessage(fromWxid, "请选择要生成的评论类型:\n回复 1 - 消毒柜评论\n回复 2 - 油烟机评论", 1, fromWxid, false);
logger.info("进入生成评论流程 - 用户: {}", fromWxid);
@@ -1637,7 +1642,16 @@ public class JDUtil {
* 处理生成评论流程中的用户交互
*/
private void handleCommentInteraction(String fromWxid, String message, UserInteractionState state) {
String key = INTERACTION_STATE_PREFIX + fromWxid;
String superOrder = "";
try {
String[] split = message.split("/n");
if (split.length != 0) {
message = split[0];
for (int i = 1; i < split.length; i++) {
superOrder += split[i] + " ";
}
}
} String key = INTERACTION_STATE_PREFIX + fromWxid;
logger.info("处理生成评论流程中的用户交互 - 用户: {}, 状态: {}", fromWxid, state);
try {
// 检查当前状态是否为生成评论流程
@@ -1648,10 +1662,16 @@ public class JDUtil {
// 根据用户输入生成对应的评论
switch (message) {
case "1":
generateComment(fromWxid, "消毒柜");
generateComment(fromWxid, "1", superOrder);
break;
case "1+":
generateComment(fromWxid, "1+", superOrder);
break;
case "2":
generateComment(fromWxid, "油烟机");
generateComment(fromWxid, "2", superOrder);
break;
case "2+":
generateComment(fromWxid, "2+", superOrder);
break;
default:
wxUtil.sendTextMessage(fromWxid, "无效的选择,请回复 1 或 2", 1, fromWxid, false);
@@ -1670,15 +1690,33 @@ public class JDUtil {
/**
* 生成评论内容
*/
private void generateComment(String fromWxid, String productType) {
// 这里可以调用缓存或AI生成文案目前先返回固定模板
String commentTemplate = "这是一条关于%s的评论\n" + "1. 性能非常出色,使用体验极佳。\n" + "2. 安装方便,操作简单。\n" + "3. 售后服务到位,值得信赖。\n" + "感谢您的购买与支持!";
String comment = String.format(commentTemplate, productType);
wxUtil.sendTextMessage(fromWxid, comment, 1, fromWxid, false);
// 重置状态
resetState(fromWxid, loadOrCreateState(INTERACTION_STATE_PREFIX + fromWxid));
private void generateComment(String fromWxid, String productType, String superOrder) {
if (productType.equals("1") || productType.equals("2")) {
// 这里可以调用缓存或AI生成文案目前先返回固定模板
//用redis的 list存放评论模板
List<String> commentTemplates = redisTemplate.opsForList().range(COMMENT_TEMPLATES + productType, 0, -1);
if (commentTemplates == null || commentTemplates.isEmpty()) {
wxUtil.sendTextMessage(fromWxid, "暂无评论模板,请先添加评论模板", 1, fromWxid, false);
return;
}
String comment = commentTemplates.get(new Random().nextInt(commentTemplates.size()));
String deepSeekResponse = "ds响应失败";
try {
deepSeekResponse = deepSeekClientUtil.getDeepSeekResponse(comment);
} catch (IOException e) {
logger.error("生成评论异常 - 用户: {}, ", fromWxid, e);
}
wxUtil.sendTextMessage(fromWxid, deepSeekResponse, 1, fromWxid, false);
// 重置状态
resetState(fromWxid, loadOrCreateState(INTERACTION_STATE_PREFIX + fromWxid));
} else {
if (!superOrder.isEmpty()) {
superOrder = superOrder.replace("+", "");
// 追加评论模板到redis
redisTemplate.opsForList().leftPush(COMMENT_TEMPLATES + productType, superOrder);
wxUtil.sendTextMessage(fromWxid, "评论模板添加成功", 1, fromWxid, false);
}
}
}

View File

@@ -0,0 +1,63 @@
package cn.van.business.util.ds;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.Method;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
@Component
public class DeepSeekClientUtil {
private static final String DEEPSEEK_API_URL = "https://api.deepseek.com/v1/chat/completions"; // 确认 API 地址
private static final String DEEPSEEK_API_KEY = "d99b8cc6b7414cc88a5d950a3ff7585e"; // 替换为你的密钥
private static final ObjectMapper objectMapper = new ObjectMapper(); // Jackson JSON 解析器
/**
* 调用 DeepSeek API 并返回第一次回复的文本内容
*
* @param inputText 用户输入的文本
* @return API 返回的第一个回复内容
* @throws IOException 如果网络请求或 JSON 解析失败
* @throws IllegalArgumentException 如果输入为空或过长
*/
public String getDeepSeekResponse(String inputText) throws IOException {
// 1. 输入校验
if (inputText == null || inputText.trim().isEmpty()) {
throw new IllegalArgumentException("输入文本不能为空");
}
if (inputText.length() > 10000) { // 可根据 API 限制调整
throw new IllegalArgumentException("输入文本过长");
}
// 2. 构建请求体(使用 Jackson 生成 JSON
Map<String, Object> requestBody = new HashMap<>();
requestBody.put("model", "deepseek-chat");
requestBody.put("messages", new Map[]{Map.of("role", "user", "content", inputText)});
requestBody.put("temperature", 0.7);
String jsonBody = objectMapper.writeValueAsString(requestBody);
// 3. 使用 Hutool HTTP 发送请求
HttpResponse response = HttpRequest.of(DEEPSEEK_API_URL).method(Method.POST).header("Content-Type", "application/json").header("Authorization", "Bearer " + DEEPSEEK_API_KEY).header("Accept", "application/json").body(jsonBody).execute();
// 4. 检查 HTTP 状态码
if (response.getStatus() != 200) {
throw new IOException("API 调用失败HTTP 状态码: " + response.getStatus());
}
// 5. 解析 JSON 响应(使用 Jackson
JsonNode rootNode = objectMapper.readTree(response.body());
JsonNode choices = rootNode.path("choices");
if (choices.isEmpty()) {
throw new IOException("API 返回数据格式异常,未找到回复内容");
}
// 6. 提取第一个回复的 content
return choices.get(0).path("message").path("content").asText();
}
}