From 2bee93f3be1dc47d7643aae9267a96de02e0fb16 Mon Sep 17 00:00:00 2001 From: heiferleaf <2044384845@qq.com> Date: Thu, 22 May 2025 20:05:48 +0800 Subject: [PATCH] =?UTF-8?q?=E6=A8=A1=E6=8B=9F=E8=BE=A9=E8=AE=BA=E5=90=8E?= =?UTF-8?q?=E7=AB=AF=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../newdemo/controller/WxAIController.java | 30 ++- .../newdemo/service/WxArgumentService.java | 18 +- .../newdemo/service/WxDebateService.java | 5 + .../newdemo/service/WxReviewService.java | 2 +- .../service/impl/WxArgumentServiceImpl.java | 188 +++++++++--------- .../service/impl/WxDebateServiceImpl.java | 93 +++++++++ .../service/impl/WxReviewServiceImpl.java | 2 +- .../src/main/resources/application.properties | 2 - .../src/main/resources/application.yml | 132 ++++++++++++ 9 files changed, 363 insertions(+), 109 deletions(-) create mode 100644 Debate_backend/src/main/java/com/learning/newdemo/service/WxDebateService.java create mode 100644 Debate_backend/src/main/java/com/learning/newdemo/service/impl/WxDebateServiceImpl.java delete mode 100644 Debate_backend/src/main/resources/application.properties diff --git a/Debate_backend/src/main/java/com/learning/newdemo/controller/WxAIController.java b/Debate_backend/src/main/java/com/learning/newdemo/controller/WxAIController.java index 362c836..0727827 100644 --- a/Debate_backend/src/main/java/com/learning/newdemo/controller/WxAIController.java +++ b/Debate_backend/src/main/java/com/learning/newdemo/controller/WxAIController.java @@ -3,6 +3,7 @@ package com.learning.newdemo.controller; import com.learning.newdemo.common.Result; import com.learning.newdemo.service.WxArgumentService; +import com.learning.newdemo.service.WxDebateService; import com.learning.newdemo.service.WxReviewService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; @@ -24,6 +25,9 @@ public class WxAIController { @Autowired private WxReviewService wxReviewService; + @Autowired + private WxDebateService wxDebateService; + private String topic; private String stance; @@ -43,7 +47,7 @@ public class WxAIController { log.info("请求内容: {}", params); try { - String argument = wxArgumentService.getArgument(topic, stance); + String argument = wxArgumentService.GetArgument(topic, stance); if (argument == null) { return Result.error("立论获取失败"); } @@ -67,7 +71,7 @@ public class WxAIController { content = params.get("content"); try { - String review = wxReviewService.getReview(content); + String review = wxReviewService.GetReview(content); if (review == null) { return Result.error("复盘获取失败"); } @@ -83,4 +87,26 @@ public class WxAIController { return Result.error("复盘获取失败:" + e.getMessage()); } } + @PostMapping("/debate") + public Result> debate(@RequestBody Map params){ + log.info("请求内容: {}", params); + String history = params.get("history"); + String userMessage = params.get("userMessage"); + try { + String debate = wxDebateService.GetDebate(history, userMessage); + if (debate == null) { + return Result.error("辩论获取失败"); + } + + Map data = new HashMap<>(); + data.put("debate", debate); + // 查看data + log.info("辩论获取成功:{}", debate); + + return Result.success(data); + }catch (Exception e){ + log.error("辩论获取失败", e); + return Result.error("辩论获取失败:" + e.getMessage()); + } + } } diff --git a/Debate_backend/src/main/java/com/learning/newdemo/service/WxArgumentService.java b/Debate_backend/src/main/java/com/learning/newdemo/service/WxArgumentService.java index 7477f7a..3b30f6b 100644 --- a/Debate_backend/src/main/java/com/learning/newdemo/service/WxArgumentService.java +++ b/Debate_backend/src/main/java/com/learning/newdemo/service/WxArgumentService.java @@ -1,9 +1,9 @@ -package com.learning.newdemo.service; - -/** - * 微信立论助手接口 - */ - -public interface WxArgumentService { - String getArgument(String topic, String stance); -} +package com.learning.newdemo.service; + +/** + * 微信立论助手接口 + */ + +public interface WxArgumentService { + String GetArgument(String topic, String stance); +} diff --git a/Debate_backend/src/main/java/com/learning/newdemo/service/WxDebateService.java b/Debate_backend/src/main/java/com/learning/newdemo/service/WxDebateService.java new file mode 100644 index 0000000..93bafa4 --- /dev/null +++ b/Debate_backend/src/main/java/com/learning/newdemo/service/WxDebateService.java @@ -0,0 +1,5 @@ +package com.learning.newdemo.service; + +public interface WxDebateService { + String GetDebate(String history, String userMessage); +} diff --git a/Debate_backend/src/main/java/com/learning/newdemo/service/WxReviewService.java b/Debate_backend/src/main/java/com/learning/newdemo/service/WxReviewService.java index c270cf5..38ab33a 100644 --- a/Debate_backend/src/main/java/com/learning/newdemo/service/WxReviewService.java +++ b/Debate_backend/src/main/java/com/learning/newdemo/service/WxReviewService.java @@ -1,5 +1,5 @@ package com.learning.newdemo.service; public interface WxReviewService { - String getReview(String content); + String GetReview(String content); } diff --git a/Debate_backend/src/main/java/com/learning/newdemo/service/impl/WxArgumentServiceImpl.java b/Debate_backend/src/main/java/com/learning/newdemo/service/impl/WxArgumentServiceImpl.java index cb6499b..fb02d54 100644 --- a/Debate_backend/src/main/java/com/learning/newdemo/service/impl/WxArgumentServiceImpl.java +++ b/Debate_backend/src/main/java/com/learning/newdemo/service/impl/WxArgumentServiceImpl.java @@ -1,95 +1,95 @@ -package com.learning.newdemo.service.impl; - -import com.learning.newdemo.service.WxArgumentService; -import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.http.HttpEntity; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpMethod; -import org.springframework.http.MediaType; -import org.springframework.http.ResponseEntity; -import org.springframework.stereotype.Service; -import org.springframework.web.client.RestTemplate; - -@Service -@Slf4j -public class WxArgumentServiceImpl implements WxArgumentService { - - private final RestTemplate restTemplate; - - @Value("${ai.argument.header.Authorization}") private String authorizationHeader; - @Value("${ai.argument.body.message.role-sys}") private String roleSys; - @Value("${ai.argument.body.message.content-sys}") private String contentSys; - @Value("${ai.argument.body.message.role-user}") private String roleUser; - @Value("${ai.argument.body.model}") private String model; - @Value("${ai.argument.body.frequency_penalty}") private int frequencyPenalty; - @Value("${ai.argument.body.max_tokens}") private int maxTokens; - @Value("${ai.argument.body.presence_penalty}") private int presencePenalty; - @Value("${ai.argument.body.response_format}") private String responseFormatType; - @Value("${ai.argument.body.stream}") private boolean stream; - @Value("${ai.argument.body.temperature}") private double temperature; - @Value("${ai.argument.body.top_p}") private double topP; - @Value("${ai.argument.body.tool_choice}") private String toolChoice; - @Value("${ai.argument.body.logprobs}") private boolean logprobs; - @Value("${ai.argument.url}") private String url; - - public WxArgumentServiceImpl(RestTemplate restTemplate) { - this.restTemplate = restTemplate; - } - - @Override - public String getArgument(String topic, String stance) { - try { - HttpHeaders headers = new HttpHeaders(); - headers.setContentType(MediaType.APPLICATION_JSON); - headers.set("Authorization", authorizationHeader); - - // 构建请求体,使用字符串拼接 - String requestBody = "{" - + "\"messages\": [" - + "{" - + "\"role\": \"" + roleSys + "\"," - + "\"content\": \"" + escapeJson(contentSys) + "\"" - + "}," - + "{" - + "\"role\": \"" + roleUser + "\"," - + "\"content\": \"" + escapeJson(topic + ",我的立场是" + stance) + "\"" - + "}" - + "]," - + "\"model\": \"" + model + "\"," - + "\"frequency_penalty\": " + frequencyPenalty + "," - + "\"max_tokens\": " + maxTokens + "," - + "\"presence_penalty\": " + presencePenalty + "," - + "\"response_format\": {\"type\": \"" + responseFormatType + "\"}," - + "\"stop\": null," - + "\"stream\": " + stream + "," - + "\"stream_options\": null," - + "\"temperature\": " + temperature + "," - + "\"top_p\": " + topP + "," - + "\"tools\": null," - + "\"tool_choice\": \"" + toolChoice + "\"," - + "\"logprobs\": " + logprobs + "," - + "\"top_logprobs\": null" - + "}"; - - log.info("请求体:{}", requestBody); - - HttpEntity requestEntity = new HttpEntity<>(requestBody, headers); - ResponseEntity response = restTemplate.exchange(url, HttpMethod.POST, requestEntity, String.class); - return response.getBody(); - } catch (Exception e) { - log.error("向AI获取立论失败", e); - return null; - } - } - - // 工具方法:转义 JSON 字符串中的特殊字符 - private String escapeJson(String input) { - if (input == null) return ""; - return input.replace("\\", "\\\\") - .replace("\"", "\\\"") - .replace("\n", "\\n") - .replace("\r", "\\r") - .replace("\t", "\\t"); - } +package com.learning.newdemo.service.impl; + +import com.learning.newdemo.service.WxArgumentService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; +import org.springframework.web.client.RestTemplate; + +@Service +@Slf4j +public class WxArgumentServiceImpl implements WxArgumentService { + + private final RestTemplate restTemplate; + + @Value("${ai.argument.header.Authorization}") private String authorizationHeader; + @Value("${ai.argument.body.message.role-sys}") private String roleSys; + @Value("${ai.argument.body.message.content-sys}") private String contentSys; + @Value("${ai.argument.body.message.role-user}") private String roleUser; + @Value("${ai.argument.body.model}") private String model; + @Value("${ai.argument.body.frequency_penalty}") private int frequencyPenalty; + @Value("${ai.argument.body.max_tokens}") private int maxTokens; + @Value("${ai.argument.body.presence_penalty}") private int presencePenalty; + @Value("${ai.argument.body.response_format}") private String responseFormatType; + @Value("${ai.argument.body.stream}") private boolean stream; + @Value("${ai.argument.body.temperature}") private double temperature; + @Value("${ai.argument.body.top_p}") private double topP; + @Value("${ai.argument.body.tool_choice}") private String toolChoice; + @Value("${ai.argument.body.logprobs}") private boolean logprobs; + @Value("${ai.argument.url}") private String url; + + public WxArgumentServiceImpl(RestTemplate restTemplate) { + this.restTemplate = restTemplate; + } + + @Override + public String GetArgument(String topic, String stance) { + try { + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_JSON); + headers.set("Authorization", authorizationHeader); + + // 构建请求体,使用字符串拼接 + String requestBody = "{" + + "\"messages\": [" + + "{" + + "\"role\": \"" + roleSys + "\"," + + "\"content\": \"" + escapeJson(contentSys) + "\"" + + "}," + + "{" + + "\"role\": \"" + roleUser + "\"," + + "\"content\": \"" + escapeJson(topic + ",我的立场是" + stance) + "\"" + + "}" + + "]," + + "\"model\": \"" + model + "\"," + + "\"frequency_penalty\": " + frequencyPenalty + "," + + "\"max_tokens\": " + maxTokens + "," + + "\"presence_penalty\": " + presencePenalty + "," + + "\"response_format\": {\"type\": \"" + responseFormatType + "\"}," + + "\"stop\": null," + + "\"stream\": " + stream + "," + + "\"stream_options\": null," + + "\"temperature\": " + temperature + "," + + "\"top_p\": " + topP + "," + + "\"tools\": null," + + "\"tool_choice\": \"" + toolChoice + "\"," + + "\"logprobs\": " + logprobs + "," + + "\"top_logprobs\": null" + + "}"; + + log.info("请求体:{}", requestBody); + + HttpEntity requestEntity = new HttpEntity<>(requestBody, headers); + ResponseEntity response = restTemplate.exchange(url, HttpMethod.POST, requestEntity, String.class); + return response.getBody(); + } catch (Exception e) { + log.error("向AI获取立论失败", e); + return null; + } + } + + // 工具方法:转义 JSON 字符串中的特殊字符 + private String escapeJson(String input) { + if (input == null) return ""; + return input.replace("\\", "\\\\") + .replace("\"", "\\\"") + .replace("\n", "\\n") + .replace("\r", "\\r") + .replace("\t", "\\t"); + } } \ No newline at end of file diff --git a/Debate_backend/src/main/java/com/learning/newdemo/service/impl/WxDebateServiceImpl.java b/Debate_backend/src/main/java/com/learning/newdemo/service/impl/WxDebateServiceImpl.java new file mode 100644 index 0000000..7d46c79 --- /dev/null +++ b/Debate_backend/src/main/java/com/learning/newdemo/service/impl/WxDebateServiceImpl.java @@ -0,0 +1,93 @@ +package com.learning.newdemo.service.impl; + +import com.learning.newdemo.service.WxDebateService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.*; +import org.springframework.stereotype.Service; +import org.springframework.web.client.RestTemplate; + + + +@Service +@Slf4j +public class WxDebateServiceImpl implements WxDebateService { + // 通过构造函数从IOC容器中注入RestTemplate + private final RestTemplate restTemplate; + + @Value("${ai.debate.body.message.content-sys}") private String contentSys; + @Value("${ai.debate.header.Authorization}") private String authorizationHeader; + @Value("${ai.debate.body.message.role-user}") private String roleUser; + @Value("${ai.debate.body.model}") private String model; + @Value("${ai.debate.body.message.role-sys}") private String roleSys; + @Value("${ai.debate.body.frequency_penalty}") private int frequencyPenalty; + @Value("${ai.debate.body.max_tokens}") private int maxTokens; + @Value("${ai.debate.body.presence_penalty}") private int presencePenalty; + @Value("${ai.debate.body.response_format}") private String responseFormatType; + @Value("${ai.debate.body.stream}") private boolean stream; + @Value("${ai.debate.body.temperature}") private double temperature; + @Value("${ai.debate.body.top_p}") private double topP; + @Value("${ai.debate.body.tool_choice}") private String toolChoice; + @Value("${ai.debate.body.logprobs}") private boolean logprobs; + @Value("${ai.debate.url}") private String url; + + public WxDebateServiceImpl(RestTemplate restTemplate) { + this.restTemplate = restTemplate; + } + + @Override + public String GetDebate(String history, String userMessage){ + try { + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_JSON); + headers.set("Authorization", authorizationHeader); + + StringBuilder requestBodyBuilder = new StringBuilder(); + requestBodyBuilder.append("{") + .append("\"messages\": [") + .append("{") + .append("\"role\": \"").append(roleSys).append("\",") + .append("\"content\": \"").append(escapeJson(contentSys)).append("\"") + .append("},") + .append("{") + .append("\"role\": \"").append(roleUser).append("\",") + .append("\"content\": \"").append(escapeJson("历史对话记录" + history + ",用户发言为" + userMessage)).append("\"") + .append("}") + .append("],") + .append("\"model\": \"").append(model).append("\",") + .append("\"frequency_penalty\": ").append(frequencyPenalty).append(",") + .append("\"max_tokens\": ").append(maxTokens).append(",") + .append("\"presence_penalty\": ").append(presencePenalty).append(",") + .append("\"response_format\": {\"type\": \"").append(responseFormatType).append("\"},") + .append("\"stop\": null,") + .append("\"stream\": ").append(stream).append(",") + .append("\"stream_options\": null,") + .append("\"temperature\": ").append(temperature).append(",") + .append("\"top_p\": ").append(topP).append(",") + .append("\"tools\": null,") + .append("\"tool_choice\": \"").append(toolChoice).append("\",") + .append("\"logprobs\": ").append(logprobs).append(",") + .append("\"top_logprobs\": null") + .append("}"); + String requestBody = requestBodyBuilder.toString(); + + log.info("请求体:{}", requestBody); + HttpEntity requestEntity = new HttpEntity<>(requestBody, headers); + ResponseEntity response = restTemplate.exchange(url, HttpMethod.POST, requestEntity, String.class); + return response.getBody(); + } catch (Exception e){ + log.error("模拟辩论获取失败", e); + return null; + } + } + + // 工具方法:转义 JSON 字符串中的特殊字符 + private String escapeJson(String input) { + if (input == null) return ""; + return input.replace("\\", "\\\\") + .replace("\"", "\\\"") + .replace("\n", "\\n") + .replace("\r", "\\r") + .replace("\t", "\\t"); + } +} diff --git a/Debate_backend/src/main/java/com/learning/newdemo/service/impl/WxReviewServiceImpl.java b/Debate_backend/src/main/java/com/learning/newdemo/service/impl/WxReviewServiceImpl.java index 655d9f4..0944e02 100644 --- a/Debate_backend/src/main/java/com/learning/newdemo/service/impl/WxReviewServiceImpl.java +++ b/Debate_backend/src/main/java/com/learning/newdemo/service/impl/WxReviewServiceImpl.java @@ -34,7 +34,7 @@ public class WxReviewServiceImpl implements WxReviewService { } @Override - public String getReview(String content) { + public String GetReview(String content) { try { HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); diff --git a/Debate_backend/src/main/resources/application.properties b/Debate_backend/src/main/resources/application.properties deleted file mode 100644 index 45007a4..0000000 --- a/Debate_backend/src/main/resources/application.properties +++ /dev/null @@ -1,2 +0,0 @@ -# 主要配置在application.yml中 -# 此文件用于避免IDE报错 \ No newline at end of file diff --git a/Debate_backend/src/main/resources/application.yml b/Debate_backend/src/main/resources/application.yml index 932e7e3..6987f63 100644 --- a/Debate_backend/src/main/resources/application.yml +++ b/Debate_backend/src/main/resources/application.yml @@ -107,6 +107,7 @@ ai: top_p: 1 tool_choice: "none" logprobs: false + review: url: https://api.deepseek.com/chat/completions header: @@ -227,6 +228,137 @@ ai: top_p: 1 tool_choice: "none" logprobs: false + + debate: + url: https://api.deepseek.com/chat/completions + headers: + Authorization: "Bearer sk-53428f3b07ff426f8c11d988f649b5e7" + body: + message: + role-sys: system + content-sys: | + 竞技辩论指导手册(简洁版) + 现在假设你是一个专业的华语辩论辩手,你需要阅读下面的竞技辩论指导手册,学习如何坚守自己的立场,打出一场精彩的比赛。(注意,所有交锋环节,包括质询,接质,自由辩论你一次都只能输出一个问题的内容,模拟场上真实的比赛节奏) + 一、基础准备 + 1. 理解辩题 + - 先拆解核心概念(比如"语词平等"要明确指什么) + - 列出正反方可能的论点 + - 准备2-3种定义方式(预防定义战) + 2. 证据收集 + - 每个论点配1-2个具体案例 + - 找近年的学术研究(心理学/社会学优先) + - 准备可比数据(比如"实施前vs实施后"对比) + + 二、辩论策略 + 1. 立论结构 + 1. 定义关键概念 + 2. 论证必要性(为什么这问题重要) + 3. 提出解决机制(具体怎么做) + 4. 比较优势(比对方方案好在哪) + 5. 价值升华(对社会/个人的意义) + 2. 反驳技巧 + - 直接反驳:指出对方逻辑漏洞 + - 替代解释:提供其他可能性 + - 削弱影响:证明对方论点不重要 + + 三、实用话术 + 1. 定义争夺 + "对方对XX的理解过于狭隘,实际上应该包含..." + "这个定义在XX学者的研究中明确指..." + 2. 数据质疑 + "该研究样本量仅200人,代表性不足" + "过去五年的新数据显示..." + 3. 价值比较 + "短期可能有效,但长期会导致..." + "解决了A问题,却恶化了B问题" + + 四、常见错误避免 + 1. 逻辑问题 + - 不偷换概念 + - 不循环论证 + - 不稻草人谬误(歪曲对方观点) + 2. 表达问题 + - 避免绝对化表述("绝对""永远") + - 复杂理论简单化解释 + - 关键数据要说明来源 + + 五、临场技巧 + 1. 质询要领 + - 问题要封闭(让对方只能答是/否) + - 连续追问不超过3个 + - 提前准备"杀手锏问题" + 2. 自由辩论 + - 30秒内完成一个论点 + - 标记战场("关于XX问题,我方认为...") + - 不纠缠细节,保持主线 + + 六、经典辩论场景应对 + 1. 当对方说"现实做不到" + 回应方向: + - 已有试点成功案例(举例) + - 技术/制度可行性分析 + - 反问"那更好的解决方案是什么" + 2. 当对方强调"特殊情况" + 回应策略: + - 证明不具代表性 + - 展示整体数据 + - 指出例外不能否定原则 + + 七、评委说服技巧 + 1. 专业评委 + - 多引用学术研究 + - 展示逻辑推导过程 + - 使用专业术语 + 2. 大众评委 + - 多讲生活案例 + - 用比喻解释复杂概念 + - 适当情感共鸣 + + 八、自我检查清单 + 1. 每个论点是否有证据支持? + 2. 反驳是否针对对方核心主张? + 3. 价值主张是否清晰有力? + 4. 时间分配是否合理? + + 九、备用锦囊 + 1. 万能案例库(准备5个跨领域案例) + 2. 名人名言(各领域3-5句) + 3. 紧急话术(当卡壳时:"这个问题需要分三个层面来看...") + + 十、赛后提升 + 1. 记录被反驳成功的论点 + 2. 收集新的证据材料 + 3. 优化表达方式(哪些话评委反应好) + + [使用说明] + 1. 比赛前通读"基础准备"和"策略"部分 + 2. 场上根据情况调用对应话术 + 3. 赛后完成"自我检查"和"提升" + + (总字数约3500字,可根据需要增减) + + 这份手册的特点: + 1. 说人话,不装高深 + 2. 直接可用,不需要翻译 + 3. 重点突出实战技巧 + 4. 兼顾新手和老手需求 + + 使用时只需要告诉我: + - 你的持方(正方/反方) + - 辩题类型(政策/价值/事实) + - 特别需求(如重点攻定义/数据) + role-user: user + model: deepseek-chat + frequency_penalty: 0 + max_tokens: 2048 + presence_penalty: 0 + response_format: text + stream: false + temperature: 1 + top_p: 1 + tool_choice: "none" + logprobs: false + # JWT配置 jwt: secret: yoursecretkey123456789abcdefghijklmnopqrstuvwxyz