新增了"智慧树"平台的AI答题功能;
抽取了部分任务共用逻辑至TaskUtil中;
This commit is contained in:
@@ -12,4 +12,7 @@
|
|||||||
- 视频播放
|
- 视频播放
|
||||||
- 文档浏览
|
- 文档浏览
|
||||||
- 网页浏览
|
- 网页浏览
|
||||||
|
- AI答题
|
||||||
> 登录需确保智慧树账号绑定QQ号,使用时需确保QQ在线,通过QQ进行自动登录
|
> 登录需确保智慧树账号绑定QQ号,使用时需确保QQ在线,通过QQ进行自动登录
|
||||||
|
|
||||||
|
> AI答题部分简答题模块目前只遇到且实现了单空题的作答,不清楚是否存在多个输入框的题目
|
||||||
|
|||||||
@@ -172,7 +172,7 @@ public class CxstudyTask {
|
|||||||
|
|
||||||
TextQuestion textQuestion = new TextQuestion();
|
TextQuestion textQuestion = new TextQuestion();
|
||||||
textQuestion.setTitle(questionTitle);
|
textQuestion.setTitle(questionTitle);
|
||||||
Answer answer = getAnswer(textQuestion);
|
Answer answer = TaskUtil.getAnswer(textQuestion);
|
||||||
TextAnswer textAnswer = (TextAnswer) answer;
|
TextAnswer textAnswer = (TextAnswer) answer;
|
||||||
WebElement inputArea = driver.findElement(By.xpath(".//body[@contenteditable='true']"));
|
WebElement inputArea = driver.findElement(By.xpath(".//body[@contenteditable='true']"));
|
||||||
//输入答案,并检测是否正确输入
|
//输入答案,并检测是否正确输入
|
||||||
@@ -207,7 +207,7 @@ public class CxstudyTask {
|
|||||||
multiChoiceQuestion.setTitle(questionTitle);
|
multiChoiceQuestion.setTitle(questionTitle);
|
||||||
List<String> choices = getChoices(choiceElements);
|
List<String> choices = getChoices(choiceElements);
|
||||||
multiChoiceQuestion.setChoices(choices);
|
multiChoiceQuestion.setChoices(choices);
|
||||||
Answer answer = getAnswer(multiChoiceQuestion);
|
Answer answer = TaskUtil.getAnswer(multiChoiceQuestion);
|
||||||
MultiChoiceAnswer multiChoiceAnswer = (MultiChoiceAnswer) answer;
|
MultiChoiceAnswer multiChoiceAnswer = (MultiChoiceAnswer) answer;
|
||||||
List<String> answers = multiChoiceAnswer.getAnswers();
|
List<String> answers = multiChoiceAnswer.getAnswers();
|
||||||
//输入答案,并检测是否正确输入
|
//输入答案,并检测是否正确输入
|
||||||
@@ -233,7 +233,7 @@ public class CxstudyTask {
|
|||||||
singleChoiceQuestion.setTitle(questionTitle);
|
singleChoiceQuestion.setTitle(questionTitle);
|
||||||
List<String> choices = getChoices(choiceElements);
|
List<String> choices = getChoices(choiceElements);
|
||||||
singleChoiceQuestion.setChoices(choices);
|
singleChoiceQuestion.setChoices(choices);
|
||||||
Answer primaryAnswer = getAnswer(singleChoiceQuestion);
|
Answer primaryAnswer = TaskUtil.getAnswer(singleChoiceQuestion);
|
||||||
SingleChoiceAnswer answer = (SingleChoiceAnswer) primaryAnswer;
|
SingleChoiceAnswer answer = (SingleChoiceAnswer) primaryAnswer;
|
||||||
String answerContent = answer.getAnswer();
|
String answerContent = answer.getAnswer();
|
||||||
log.info("答案: {}", answerContent);
|
log.info("答案: {}", answerContent);
|
||||||
@@ -264,42 +264,6 @@ public class CxstudyTask {
|
|||||||
return choices;
|
return choices;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Answer getAnswer(Question question) throws InterruptedException {
|
|
||||||
Answer answer = null;
|
|
||||||
int tryTimes = 0;
|
|
||||||
while (tryTimes < 3) {
|
|
||||||
try {
|
|
||||||
String questionStr = JSONUtil.toJsonPrettyStr(question);
|
|
||||||
String responseStr = AiUtil.runChat(questionStr);
|
|
||||||
// 使用正则表达式提取Markdown代码块中的JSON内容
|
|
||||||
String jsonPattern = "```[\\s\\S]*?\\n([\\s\\S]*?)\\n```";
|
|
||||||
Pattern pattern = Pattern.compile(jsonPattern);
|
|
||||||
Matcher matcher = pattern.matcher(responseStr);
|
|
||||||
String jsonStr = "";
|
|
||||||
if (matcher.find()) {
|
|
||||||
jsonStr = matcher.group(1).trim();
|
|
||||||
}
|
|
||||||
if (jsonStr.isEmpty()) {
|
|
||||||
throw new AiResponseFormatException("AI 回答格式不匹配: " + jsonStr);
|
|
||||||
}
|
|
||||||
if (question instanceof SingleChoiceQuestion) {
|
|
||||||
answer = JSONUtil.toBean(jsonStr, SingleChoiceAnswer.class);
|
|
||||||
} else if (question instanceof MultiChoiceQuestion) {
|
|
||||||
answer = JSONUtil.toBean(jsonStr, MultiChoiceAnswer.class);
|
|
||||||
} else if (question instanceof TextQuestion) {
|
|
||||||
answer = JSONUtil.toBean(jsonStr, TextAnswer.class);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
} catch (AiResponseFormatException e) {
|
|
||||||
log.warn(e.getLocalizedMessage());
|
|
||||||
log.warn("3s后重试...");
|
|
||||||
Thread.sleep(3000);
|
|
||||||
tryTimes++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return answer;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void handleVideoTask(int i) throws InterruptedException {
|
private void handleVideoTask(int i) throws InterruptedException {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -3,12 +3,19 @@ package work.slhaf.task;
|
|||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.openqa.selenium.*;
|
import org.openqa.selenium.*;
|
||||||
|
import org.openqa.selenium.NoSuchElementException;
|
||||||
import org.openqa.selenium.interactions.Actions;
|
import org.openqa.selenium.interactions.Actions;
|
||||||
import org.openqa.selenium.support.ui.ExpectedConditions;
|
import org.openqa.selenium.support.ui.ExpectedConditions;
|
||||||
import org.openqa.selenium.support.ui.WebDriverWait;
|
import org.openqa.selenium.support.ui.WebDriverWait;
|
||||||
import work.slhaf.config.Config;
|
import work.slhaf.config.Config;
|
||||||
import work.slhaf.exception.TargetClassNotFoundException;
|
import work.slhaf.exception.TargetClassNotFoundException;
|
||||||
import work.slhaf.exception.UnknownTaskPointException;
|
import work.slhaf.exception.UnknownTaskPointException;
|
||||||
|
import work.slhaf.pojo.answer.MultiChoiceAnswer;
|
||||||
|
import work.slhaf.pojo.answer.SingleChoiceAnswer;
|
||||||
|
import work.slhaf.pojo.answer.TextAnswer;
|
||||||
|
import work.slhaf.pojo.question.MultiChoiceQuestion;
|
||||||
|
import work.slhaf.pojo.question.SingleChoiceQuestion;
|
||||||
|
import work.slhaf.pojo.question.TextQuestion;
|
||||||
import work.slhaf.util.TaskUtil;
|
import work.slhaf.util.TaskUtil;
|
||||||
|
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
@@ -32,32 +39,13 @@ public class ZhsTask {
|
|||||||
while (true) {
|
while (true) {
|
||||||
try {
|
try {
|
||||||
switchPage();
|
switchPage();
|
||||||
List<WebElement> todoTasks = getTodoTasks();
|
List<WebElement> todoLearningTasks = getTodoLearningTasks();
|
||||||
while (!todoTasks.isEmpty()) {
|
handleTodoLearningTasks(todoLearningTasks);
|
||||||
todoTasks.getFirst().click();
|
if (aiEnable) {
|
||||||
System.out.println();
|
List<WebElement> todoTestTasks = getTodoTestTasks();
|
||||||
try {
|
handleTodoTestTasks(todoTestTasks);
|
||||||
wait.until(ExpectedConditions.elementToBeClickable(By.xpath("//div[@class='resources-list']")));
|
}else {
|
||||||
} catch (Exception e) {
|
log.info("AI答题未开启, 不处理测验任务");
|
||||||
driver.get(driver.getCurrentUrl());
|
|
||||||
}
|
|
||||||
HashMap<WebElement, String> todoTaskPoints = getTodoTaskPoints();
|
|
||||||
log.info("发现{}个任务点", todoTaskPoints.size());
|
|
||||||
AtomicInteger count = new AtomicInteger(0);
|
|
||||||
for (Map.Entry<WebElement, String> entry : todoTaskPoints.entrySet()) {
|
|
||||||
WebElement k = entry.getKey();
|
|
||||||
String v = entry.getValue();
|
|
||||||
count.incrementAndGet();
|
|
||||||
log.info("处理第{}个任务点", count.get());
|
|
||||||
switch (v) {
|
|
||||||
case "icon-box video" -> handleVideoTask(k);
|
|
||||||
case "icon-box baidu", "icon-box bzhan" -> handleWebTask(k);
|
|
||||||
case "icon-box book", "icon-box other", "icon-box img" -> handleDocTask(k);
|
|
||||||
default -> throw new UnknownTaskPointException("未设置处理策略的任务点类型: " + v);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
driver.findElement(By.xpath("//img[@alt='back']")).click();
|
|
||||||
todoTasks = getTodoTasks();
|
|
||||||
}
|
}
|
||||||
log.info("任务完成!");
|
log.info("任务完成!");
|
||||||
driver.quit();
|
driver.quit();
|
||||||
@@ -77,6 +65,172 @@ public class ZhsTask {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void handleTodoTestTasks(List<WebElement> todoTestTasks) throws InterruptedException {
|
||||||
|
log.info("开始处理测验任务...");
|
||||||
|
while (!todoTestTasks.isEmpty()){
|
||||||
|
todoTestTasks.getFirst().click();
|
||||||
|
waitingTaskPageLoading();
|
||||||
|
//跳转答题页面,并等待题目加载
|
||||||
|
driver.findElement(By.xpath("//div[@class='practice-handle ZHIHUISHU_QZMD']")).click();
|
||||||
|
while (true) {
|
||||||
|
WebElement questionContent = wait.until(ExpectedConditions.elementToBeClickable(By.xpath("//div[@class='questionContent']")));
|
||||||
|
Thread.sleep(3000);
|
||||||
|
//读取题目信息并获取答案
|
||||||
|
String questionType = null;
|
||||||
|
while (questionType == null) {
|
||||||
|
try {
|
||||||
|
questionType = questionContent.findElement(By.xpath(".//div[@class='questionTitle']")).getText().split(" ")[1];
|
||||||
|
}catch (ArrayIndexOutOfBoundsException ignored){
|
||||||
|
Thread.sleep(200);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
String questionTitle = questionContent.findElement(By.xpath(".//div[@class='centent-pre']")).getText();
|
||||||
|
switch (questionType) {
|
||||||
|
case "单选题", "判断题" -> {
|
||||||
|
SingleChoiceQuestion singleChoiceQuestion = new SingleChoiceQuestion();
|
||||||
|
singleChoiceQuestion.setTitle(questionTitle);
|
||||||
|
List<String> choices = new ArrayList<>();
|
||||||
|
List<WebElement> choiceElements = questionContent.findElements(By.xpath(".//li[@class='clearfix']"));
|
||||||
|
for (WebElement choiceElement : choiceElements) {
|
||||||
|
choices.add(choiceElement.getText());
|
||||||
|
}
|
||||||
|
singleChoiceQuestion.setChoices(choices);
|
||||||
|
|
||||||
|
handleSingleChoiceQuestion(singleChoiceQuestion, choiceElements);
|
||||||
|
}
|
||||||
|
case "多选题" -> {
|
||||||
|
MultiChoiceQuestion multiChoiceQuestion = new MultiChoiceQuestion();
|
||||||
|
multiChoiceQuestion.setTitle(questionTitle);
|
||||||
|
List<WebElement> choiceElements = questionContent.findElements(By.xpath(".//label[@class='el-checkbox']"));
|
||||||
|
List<String> choices = new ArrayList<>();
|
||||||
|
HashMap<String, WebElement> choiceElementsMap = new HashMap<>();
|
||||||
|
for (WebElement choiceElement : choiceElements) {
|
||||||
|
String choice = choiceElement.getText();
|
||||||
|
choices.add(choiceElement.getText());
|
||||||
|
choiceElementsMap.put(choice.substring(0, 1), choiceElement);
|
||||||
|
}
|
||||||
|
multiChoiceQuestion.setChoices(choices);
|
||||||
|
|
||||||
|
handleMultiChoiceQuestion(multiChoiceQuestion, choiceElementsMap);
|
||||||
|
}
|
||||||
|
default -> {
|
||||||
|
TextQuestion textQuestion = new TextQuestion();
|
||||||
|
textQuestion.setTitle(questionTitle);
|
||||||
|
|
||||||
|
handleTextQuestion(textQuestion);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
//下一题或提交
|
||||||
|
WebElement nextButton = driver.findElement(By.xpath("//span[contains(@class,'next-topic')]"));
|
||||||
|
boolean hasNoNext = nextButton.getDomAttribute("class").contains("noNext");
|
||||||
|
if (hasNoNext) {
|
||||||
|
driver.findElement(By.xpath("//span[contains(@class,'reviewDone')]")).click();
|
||||||
|
break;
|
||||||
|
}else {
|
||||||
|
nextButton.click();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//回到任务列表页面
|
||||||
|
log.info("作答完毕");
|
||||||
|
wait.until(ExpectedConditions.elementToBeClickable(By.xpath("//div[@class='backup-icon']"))).click();
|
||||||
|
wait.until(ExpectedConditions.elementToBeClickable(By.xpath("//img[@alt='back']"))).click();
|
||||||
|
//重新获取测验任务列表
|
||||||
|
todoTestTasks = getTodoTestTasks();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleTextQuestion(TextQuestion textQuestion) throws InterruptedException {
|
||||||
|
TextAnswer textAnswer = (TextAnswer) TaskUtil.getAnswer(textQuestion);
|
||||||
|
String answer = textAnswer.getAnswer();
|
||||||
|
driver.findElement(By.xpath("//input[@class='el-input__inner']")).sendKeys(answer);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleMultiChoiceQuestion(MultiChoiceQuestion multiChoiceQuestion, HashMap<String,WebElement> choiceElementsMap) throws InterruptedException {
|
||||||
|
MultiChoiceAnswer multiChoiceAnswer = (MultiChoiceAnswer) TaskUtil.getAnswer(multiChoiceQuestion);
|
||||||
|
List<String> answers = multiChoiceAnswer.getAnswers();
|
||||||
|
for (String answer : answers) {
|
||||||
|
WebElement answerElement = choiceElementsMap.get(answer);
|
||||||
|
while (answerElement.getDomAttribute("class").equals("el-checkbox")) {
|
||||||
|
answerElement.click();
|
||||||
|
Thread.sleep(300);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleSingleChoiceQuestion(SingleChoiceQuestion singleChoiceQuestion, List<WebElement> choiceElements) throws InterruptedException {
|
||||||
|
SingleChoiceAnswer singleChoiceAnswer = (SingleChoiceAnswer) TaskUtil.getAnswer(singleChoiceQuestion);
|
||||||
|
String answer = singleChoiceAnswer.getAnswer();
|
||||||
|
for (WebElement choiceElement : choiceElements) {
|
||||||
|
if (choiceElement.getText().startsWith(answer)) {
|
||||||
|
String checkedAttribute = choiceElement.findElement(By.xpath(".//i[contains(@class,'iconfont checkIcon fl')]")).getDomAttribute("class");
|
||||||
|
while ("iconfont checkIcon fl".equals(checkedAttribute)) {
|
||||||
|
choiceElement.click();
|
||||||
|
Thread.sleep(300);
|
||||||
|
checkedAttribute = choiceElement.findElement(By.xpath(".//i[contains(@class,'iconfont checkIcon fl')]")).getDomAttribute("class");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleTodoLearningTasks(List<WebElement> todoLearningTasks) throws InterruptedException {
|
||||||
|
log.info("开始处理学习任务...");
|
||||||
|
while (!todoLearningTasks.isEmpty()) {
|
||||||
|
todoLearningTasks.getFirst().click();
|
||||||
|
waitingTaskPageLoading();
|
||||||
|
|
||||||
|
HashMap<WebElement, String> todoTaskPoints = getTodoTaskPoints();
|
||||||
|
log.info("发现{}个任务点", todoTaskPoints.size());
|
||||||
|
AtomicInteger count = new AtomicInteger(0);
|
||||||
|
for (Map.Entry<WebElement, String> entry : todoTaskPoints.entrySet()) {
|
||||||
|
WebElement k = entry.getKey();
|
||||||
|
String v = entry.getValue();
|
||||||
|
count.incrementAndGet();
|
||||||
|
log.info("处理第{}个任务点", count.get());
|
||||||
|
switch (v) {
|
||||||
|
case "icon-box video" -> handleVideoTask(k);
|
||||||
|
case "icon-box baidu", "icon-box bzhan" -> handleWebTask(k);
|
||||||
|
case "icon-box book", "icon-box other", "icon-box img" -> handleDocTask(k);
|
||||||
|
default -> throw new UnknownTaskPointException("未设置处理策略的任务点类型: " + v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
driver.findElement(By.xpath("//img[@alt='back']")).click();
|
||||||
|
todoLearningTasks = getTodoLearningTasks();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void waitingTaskPageLoading() {
|
||||||
|
while (true) {
|
||||||
|
try {
|
||||||
|
wait.until(ExpectedConditions.elementToBeClickable(By.xpath("//div[@class='resources-list']")));
|
||||||
|
break;
|
||||||
|
} catch (Exception e) {
|
||||||
|
driver.get(driver.getCurrentUrl());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<WebElement> getTodoTestTasks() {
|
||||||
|
log.info("获取测验任务...");
|
||||||
|
//必须通过item-content定位元素, 但页面在默认情况下都是item-content
|
||||||
|
wait.until(ExpectedConditions.elementToBeClickable(By.xpath("//div[@class='item-content']")));
|
||||||
|
List<WebElement> totalTasks = driver.findElements(By.xpath("//div[@class='item-content']"));
|
||||||
|
List<WebElement> todoTasks = new ArrayList<>();
|
||||||
|
for (WebElement task : totalTasks) {
|
||||||
|
try{
|
||||||
|
String progress = task.findElement(By.xpath(".//div[@class='el-progress__text']")).getText();
|
||||||
|
if (progress.equals("0 %")){
|
||||||
|
todoTasks.add(task);
|
||||||
|
}
|
||||||
|
} catch (NoSuchElementException ignored) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log.info("获取到{}个测验任务", todoTasks.size());
|
||||||
|
return todoTasks;
|
||||||
|
}
|
||||||
|
|
||||||
private void handleWebTask(WebElement task) throws InterruptedException {
|
private void handleWebTask(WebElement task) throws InterruptedException {
|
||||||
//记录当前句柄
|
//记录当前句柄
|
||||||
String primaryHandle = driver.getWindowHandle();
|
String primaryHandle = driver.getWindowHandle();
|
||||||
@@ -158,7 +312,8 @@ public class ZhsTask {
|
|||||||
return todoTaskPoints;
|
return todoTaskPoints;
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<WebElement> getTodoTasks() {
|
private List<WebElement> getTodoLearningTasks() {
|
||||||
|
log.info("获取学习任务...");
|
||||||
List<WebElement> totalTasks;
|
List<WebElement> totalTasks;
|
||||||
List<WebElement> todoTasks = new ArrayList<>();
|
List<WebElement> todoTasks = new ArrayList<>();
|
||||||
boolean pct = false;
|
boolean pct = false;
|
||||||
@@ -186,7 +341,7 @@ public class ZhsTask {
|
|||||||
}
|
}
|
||||||
todoTasks.add(task);
|
todoTasks.add(task);
|
||||||
}
|
}
|
||||||
log.info("获取到{}个任务", todoTasks.size());
|
log.info("获取到{}个学习任务", todoTasks.size());
|
||||||
return todoTasks;
|
return todoTasks;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -207,7 +362,7 @@ public class ZhsTask {
|
|||||||
throw new TargetClassNotFoundException("未找到课程: " + targetClassName);
|
throw new TargetClassNotFoundException("未找到课程: " + targetClassName);
|
||||||
}
|
}
|
||||||
targetClass.click();
|
targetClass.click();
|
||||||
System.out.println();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void login() {
|
private void login() {
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
package work.slhaf.util;
|
package work.slhaf.util;
|
||||||
|
|
||||||
|
import cn.hutool.json.JSONUtil;
|
||||||
import io.github.bonigarcia.wdm.WebDriverManager;
|
import io.github.bonigarcia.wdm.WebDriverManager;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.openqa.selenium.WebDriver;
|
import org.openqa.selenium.WebDriver;
|
||||||
import org.openqa.selenium.chrome.ChromeDriver;
|
import org.openqa.selenium.chrome.ChromeDriver;
|
||||||
import org.openqa.selenium.chrome.ChromeOptions;
|
import org.openqa.selenium.chrome.ChromeOptions;
|
||||||
@@ -9,7 +11,20 @@ import org.openqa.selenium.edge.EdgeOptions;
|
|||||||
import org.openqa.selenium.firefox.FirefoxDriver;
|
import org.openqa.selenium.firefox.FirefoxDriver;
|
||||||
import org.openqa.selenium.firefox.FirefoxOptions;
|
import org.openqa.selenium.firefox.FirefoxOptions;
|
||||||
import work.slhaf.config.Config;
|
import work.slhaf.config.Config;
|
||||||
|
import work.slhaf.exception.AiResponseFormatException;
|
||||||
|
import work.slhaf.pojo.answer.Answer;
|
||||||
|
import work.slhaf.pojo.answer.MultiChoiceAnswer;
|
||||||
|
import work.slhaf.pojo.answer.SingleChoiceAnswer;
|
||||||
|
import work.slhaf.pojo.answer.TextAnswer;
|
||||||
|
import work.slhaf.pojo.question.MultiChoiceQuestion;
|
||||||
|
import work.slhaf.pojo.question.Question;
|
||||||
|
import work.slhaf.pojo.question.SingleChoiceQuestion;
|
||||||
|
import work.slhaf.pojo.question.TextQuestion;
|
||||||
|
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
public class TaskUtil {
|
public class TaskUtil {
|
||||||
private TaskUtil() {}
|
private TaskUtil() {}
|
||||||
|
|
||||||
@@ -30,4 +45,42 @@ public class TaskUtil {
|
|||||||
default -> throw new IllegalStateException("不支持的浏览器驱动!: " + config.getBrowser());
|
default -> throw new IllegalStateException("不支持的浏览器驱动!: " + config.getBrowser());
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Answer getAnswer(Question question) throws InterruptedException {
|
||||||
|
Answer answer = null;
|
||||||
|
int tryTimes = 0;
|
||||||
|
while (tryTimes < 3) {
|
||||||
|
try {
|
||||||
|
String questionStr = JSONUtil.toJsonPrettyStr(question);
|
||||||
|
String responseStr = AiUtil.runChat(questionStr);
|
||||||
|
// 使用正则表达式提取Markdown代码块中的JSON内容
|
||||||
|
String jsonPattern = "```[\\s\\S]*?\\n([\\s\\S]*?)\\n```";
|
||||||
|
Pattern pattern = Pattern.compile(jsonPattern);
|
||||||
|
Matcher matcher = pattern.matcher(responseStr);
|
||||||
|
String jsonStr = "";
|
||||||
|
if (matcher.find()) {
|
||||||
|
jsonStr = matcher.group(1).trim();
|
||||||
|
}
|
||||||
|
if (jsonStr.isEmpty()) {
|
||||||
|
throw new AiResponseFormatException("AI 回答格式不匹配: " + jsonStr);
|
||||||
|
}
|
||||||
|
if (question instanceof SingleChoiceQuestion) {
|
||||||
|
answer = JSONUtil.toBean(jsonStr, SingleChoiceAnswer.class);
|
||||||
|
} else if (question instanceof MultiChoiceQuestion) {
|
||||||
|
answer = JSONUtil.toBean(jsonStr, MultiChoiceAnswer.class);
|
||||||
|
} else if (question instanceof TextQuestion) {
|
||||||
|
answer = JSONUtil.toBean(jsonStr, TextAnswer.class);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
} catch (AiResponseFormatException e) {
|
||||||
|
log.warn(e.getLocalizedMessage());
|
||||||
|
log.warn("3s后重试...");
|
||||||
|
Thread.sleep(3000);
|
||||||
|
tryTimes++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return answer;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user