From 72dd9105abf0eca14b64e6f636af601e63af67df Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E5=B0=8F=E5=82=85=E5=93=A5?= <184172133@qq.com>
Date: Fri, 27 Jan 2023 20:56:06 +0800
Subject: [PATCH] =?UTF-8?q?=E5=B0=8F=E5=82=85=E5=93=A5=EF=BC=8Cfeat?=
=?UTF-8?q?=EF=BC=9A=E7=AC=AC7=E8=8A=82=EF=BC=9A=E5=A4=9A=E7=BB=84?=
=?UTF-8?q?=E4=BB=BB=E5=8A=A1=E6=9C=8D=E5=8A=A1=E9=85=8D=E7=BD=AE?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
chatbot-api-application/pom.xml | 6 ++
.../ext/TaskRegistrarAutoConfig.java | 74 +++++++++++++++++++
...{ChatbotSchedule.java => ChatbotTask.java} | 45 ++++++-----
chatbot-api-common/pom.xml | 34 +++++++++
.../PropertyUtil.java | 70 ++++++++++++++++++
.../chatbot/api/domain/ai/IOpenAI.java | 2 +-
.../chatbot/api/domain/ai/service/OpenAI.java | 5 +-
.../src/main/resources/application.yml | 17 ++++-
.../cn/bugstack/chatbot/api/test/ApiTest.java | 8 ++
.../chatbot/api/test/SpringBootRunTest.java | 10 ++-
pom.xml | 1 +
11 files changed, 237 insertions(+), 35 deletions(-)
create mode 100644 chatbot-api-application/src/main/java/cn/bugstack/chatbot/api/application/ext/TaskRegistrarAutoConfig.java
rename chatbot-api-application/src/main/java/cn/bugstack/chatbot/api/application/job/{ChatbotSchedule.java => ChatbotTask.java} (59%)
create mode 100644 chatbot-api-common/pom.xml
create mode 100755 chatbot-api-common/src/main/java/cn.bugstack.chatbot.api.common/PropertyUtil.java
diff --git a/chatbot-api-application/pom.xml b/chatbot-api-application/pom.xml
index 5286b91..c19421a 100644
--- a/chatbot-api-application/pom.xml
+++ b/chatbot-api-application/pom.xml
@@ -34,6 +34,12 @@
chatbot-api-domain
1.0-SNAPSHOT
+
+ cn.bugstack.ai
+ chatbot-api-common
+ 1.0-SNAPSHOT
+ compile
+
\ No newline at end of file
diff --git a/chatbot-api-application/src/main/java/cn/bugstack/chatbot/api/application/ext/TaskRegistrarAutoConfig.java b/chatbot-api-application/src/main/java/cn/bugstack/chatbot/api/application/ext/TaskRegistrarAutoConfig.java
new file mode 100644
index 0000000..c55e1a9
--- /dev/null
+++ b/chatbot-api-application/src/main/java/cn/bugstack/chatbot/api/application/ext/TaskRegistrarAutoConfig.java
@@ -0,0 +1,74 @@
+package cn.bugstack.chatbot.api.application.ext;
+
+import cn.bugstack.chatbot.api.application.job.ChatbotTask;
+import cn.bugstack.chatbot.api.common.PropertyUtil;
+import cn.bugstack.chatbot.api.domain.ai.IOpenAI;
+import cn.bugstack.chatbot.api.domain.zsxq.IZsxqApi;
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.context.EnvironmentAware;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.core.env.Environment;
+import org.springframework.scheduling.annotation.EnableScheduling;
+import org.springframework.scheduling.annotation.SchedulingConfigurer;
+import org.springframework.scheduling.config.ScheduledTaskRegistrar;
+
+import javax.annotation.Resource;
+import java.nio.charset.StandardCharsets;
+import java.util.Base64;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * @author 小傅哥,微信:fustack
+ * @description 任务注册服务,支持多组任务配置
+ * @github https://github.com/fuzhengwei
+ * @Copyright 公众号:bugstack虫洞栈 | 博客:https://bugstack.cn - 沉淀、分享、成长,让自己和他人都能有所收获!
+ */
+@Configuration
+@EnableScheduling
+public class TaskRegistrarAutoConfig implements EnvironmentAware, SchedulingConfigurer {
+
+ private Logger logger = LoggerFactory.getLogger(TaskRegistrarAutoConfig.class);
+
+ /**
+ * 任务配置组
+ */
+ private Map> taskGroupMap = new HashMap<>();
+
+ @Resource
+ private IZsxqApi zsxqApi;
+ @Resource
+ private IOpenAI openAI;
+
+ @Override
+ public void setEnvironment(Environment environment) {
+ String prefix = "chatbot-api.";
+ String launchListStr = environment.getProperty(prefix + "launchList");
+ if (StringUtils.isEmpty(launchListStr)) return;
+ for (String groupKey : launchListStr.split(",")) {
+ Map taskGroupProps = PropertyUtil.handle(environment, prefix + groupKey, Map.class);
+ taskGroupMap.put(groupKey, taskGroupProps);
+ }
+ }
+
+ @Override
+ public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
+ Set taskGroups = taskGroupMap.keySet();
+ for (String groupKey : taskGroups) {
+ Map taskGroup = taskGroupMap.get(groupKey);
+ String groupName = taskGroup.get("groupName").toString();
+ String groupId = taskGroup.get("groupId").toString();
+ String cookie = taskGroup.get("cookie").toString();
+ String openAiKey = taskGroup.get("openAiKey").toString();
+ String cronExpressionBase64 = taskGroup.get("cronExpression").toString();
+ String cronExpression = new String(Base64.getDecoder().decode(cronExpressionBase64), StandardCharsets.UTF_8);
+ logger.info("创建任务 groupName:{} groupId:{} cronExpression:{}", groupName, groupId, cronExpression);
+ // 添加任务
+ taskRegistrar.addCronTask(new ChatbotTask(groupName, groupId, cookie, openAiKey, zsxqApi, openAI), cronExpression);
+ }
+ }
+
+}
diff --git a/chatbot-api-application/src/main/java/cn/bugstack/chatbot/api/application/job/ChatbotSchedule.java b/chatbot-api-application/src/main/java/cn/bugstack/chatbot/api/application/job/ChatbotTask.java
similarity index 59%
rename from chatbot-api-application/src/main/java/cn/bugstack/chatbot/api/application/job/ChatbotSchedule.java
rename to chatbot-api-application/src/main/java/cn/bugstack/chatbot/api/application/job/ChatbotTask.java
index 3442328..4eeb0b5 100644
--- a/chatbot-api-application/src/main/java/cn/bugstack/chatbot/api/application/job/ChatbotSchedule.java
+++ b/chatbot-api-application/src/main/java/cn/bugstack/chatbot/api/application/job/ChatbotTask.java
@@ -7,12 +7,7 @@ import cn.bugstack.chatbot.api.domain.zsxq.model.vo.Topics;
import com.alibaba.fastjson.JSON;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.scheduling.annotation.EnableScheduling;
-import org.springframework.scheduling.annotation.Scheduled;
-import javax.annotation.Resource;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.List;
@@ -20,59 +15,63 @@ import java.util.Random;
/**
* @author 小傅哥,微信:fustack
- * @description 问题任务
+ * @description 任务体
* @github https://github.com/fuzhengwei
* @Copyright 公众号:bugstack虫洞栈 | 博客:https://bugstack.cn - 沉淀、分享、成长,让自己和他人都能有所收获!
*/
-@EnableScheduling
-@Configuration
-public class ChatbotSchedule {
+public class ChatbotTask implements Runnable {
- private Logger logger = LoggerFactory.getLogger(ChatbotSchedule.class);
+ private Logger logger = LoggerFactory.getLogger(ChatbotTask.class);
- @Value("${chatbot-api.groupId}")
+ private String groupName;
private String groupId;
- @Value("${chatbot-api.cookie}")
private String cookie;
+ private String openAiKey;
- @Resource
private IZsxqApi zsxqApi;
- @Resource
private IOpenAI openAI;
- // 表达式:cron.qqe2.com
- @Scheduled(cron = "0/30 * * * * ?")
+ public ChatbotTask(String groupName, String groupId, String cookie, String openAiKey, IZsxqApi zsxqApi, IOpenAI openAI) {
+ this.groupName = groupName;
+ this.groupId = groupId;
+ this.cookie = cookie;
+ this.openAiKey = openAiKey;
+ this.zsxqApi = zsxqApi;
+ this.openAI = openAI;
+ }
+
+ @Override
public void run() {
try {
if (new Random().nextBoolean()) {
- logger.info("随机打烊中...");
+ logger.info("{} 随机打烊中...", groupName);
return;
}
GregorianCalendar calendar = new GregorianCalendar();
int hour = calendar.get(Calendar.HOUR_OF_DAY);
if (hour > 22 || hour < 7) {
- logger.info("打烊时间不工作,AI 下班了!");
+ logger.info("{} 打烊时间不工作,AI 下班了!", groupName);
return;
}
// 1. 检索问题
UnAnsweredQuestionsAggregates unAnsweredQuestionsAggregates = zsxqApi.queryUnAnsweredQuestionsTopicId(groupId, cookie);
- logger.info("检索结果:{}", JSON.toJSONString(unAnsweredQuestionsAggregates));
+ logger.info("{} 检索结果:{}", groupName, JSON.toJSONString(unAnsweredQuestionsAggregates));
List topics = unAnsweredQuestionsAggregates.getResp_data().getTopics();
if (null == topics || topics.isEmpty()) {
- logger.info("本次检索未查询到待会答问题");
+ logger.info("{} 本次检索未查询到待会答问题", groupName);
return;
}
// 2. AI 回答
Topics topic = topics.get(topics.size() - 1);
- String answer = openAI.doChatGPT(topic.getQuestion().getText().trim());
+ String answer = openAI.doChatGPT(openAiKey, topic.getQuestion().getText().trim());
// 3. 问题回复
boolean status = zsxqApi.answer(groupId, cookie, topic.getTopic_id(), answer, false);
- logger.info("编号:{} 问题:{} 回答:{} 状态:{}", topic.getTopic_id(), topic.getQuestion().getText(), answer, status);
+ logger.info("{} 编号:{} 问题:{} 回答:{} 状态:{}", groupName, topic.getTopic_id(), topic.getQuestion().getText(), answer, status);
} catch (Exception e) {
- logger.error("自动回答问题异常", e);
+ logger.error("{} 自动回答问题异常", groupName, e);
}
}
diff --git a/chatbot-api-common/pom.xml b/chatbot-api-common/pom.xml
new file mode 100644
index 0000000..db75d12
--- /dev/null
+++ b/chatbot-api-common/pom.xml
@@ -0,0 +1,34 @@
+
+
+
+ chatbot-api
+ cn.bugstack.ai
+ 1.0-SNAPSHOT
+
+ 4.0.0
+
+ chatbot-api-common
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+ com.alibaba
+ fastjson
+
+
+ org.apache.commons
+ commons-lang3
+
+
+
+
\ No newline at end of file
diff --git a/chatbot-api-common/src/main/java/cn.bugstack.chatbot.api.common/PropertyUtil.java b/chatbot-api-common/src/main/java/cn.bugstack.chatbot.api.common/PropertyUtil.java
new file mode 100755
index 0000000..576fded
--- /dev/null
+++ b/chatbot-api-common/src/main/java/cn.bugstack.chatbot.api.common/PropertyUtil.java
@@ -0,0 +1,70 @@
+package cn.bugstack.chatbot.api.common;
+
+import org.springframework.core.env.Environment;
+import org.springframework.core.env.PropertyResolver;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+public class PropertyUtil {
+
+ private static int springBootVersion = 1;
+
+ static {
+ try {
+ Class.forName("org.springframework.boot.bind.RelaxedPropertyResolver");
+ } catch (ClassNotFoundException e) {
+ springBootVersion = 2;
+ }
+ }
+
+ /**
+ * Spring Boot 1.x is compatible with Spring Boot 2.x by Using Java Reflect.
+ * @param environment : the environment context
+ * @param prefix : the prefix part of property key
+ * @param targetClass : the target class type of result
+ * @param : refer to @param targetClass
+ * @return T
+ */
+ @SuppressWarnings("unchecked")
+ public static T handle(final Environment environment, final String prefix, final Class targetClass) {
+ switch (springBootVersion) {
+ case 1:
+ return (T) v1(environment, prefix);
+ default:
+ return (T) v2(environment, prefix, targetClass);
+ }
+ }
+
+ private static Object v1(final Environment environment, final String prefix) {
+ try {
+ Class> resolverClass = Class.forName("org.springframework.boot.bind.RelaxedPropertyResolver");
+ Constructor> resolverConstructor = resolverClass.getDeclaredConstructor(PropertyResolver.class);
+ Method getSubPropertiesMethod = resolverClass.getDeclaredMethod("getSubProperties", String.class);
+ Object resolverObject = resolverConstructor.newInstance(environment);
+ String prefixParam = prefix.endsWith(".") ? prefix : prefix + ".";
+ return getSubPropertiesMethod.invoke(resolverObject, prefixParam);
+ } catch (final ClassNotFoundException | NoSuchMethodException | SecurityException | InstantiationException
+ | IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {
+ throw new RuntimeException(ex.getMessage(), ex);
+ }
+ }
+
+ private static Object v2(final Environment environment, final String prefix, final Class> targetClass) {
+ try {
+ Class> binderClass = Class.forName("org.springframework.boot.context.properties.bind.Binder");
+ Method getMethod = binderClass.getDeclaredMethod("get", Environment.class);
+ Method bindMethod = binderClass.getDeclaredMethod("bind", String.class, Class.class);
+ Object binderObject = getMethod.invoke(null, environment);
+ String prefixParam = prefix.endsWith(".") ? prefix.substring(0, prefix.length() - 1) : prefix;
+ Object bindResultObject = bindMethod.invoke(binderObject, prefixParam, targetClass);
+ Method resultGetMethod = bindResultObject.getClass().getDeclaredMethod("get");
+ return resultGetMethod.invoke(bindResultObject);
+ } catch (final ClassNotFoundException | NoSuchMethodException | SecurityException | IllegalAccessException
+ | IllegalArgumentException | InvocationTargetException ex) {
+ throw new RuntimeException(ex.getMessage(), ex);
+ }
+ }
+
+}
diff --git a/chatbot-api-domain/src/main/java/cn/bugstack/chatbot/api/domain/ai/IOpenAI.java b/chatbot-api-domain/src/main/java/cn/bugstack/chatbot/api/domain/ai/IOpenAI.java
index e2cc5a5..5a16d09 100644
--- a/chatbot-api-domain/src/main/java/cn/bugstack/chatbot/api/domain/ai/IOpenAI.java
+++ b/chatbot-api-domain/src/main/java/cn/bugstack/chatbot/api/domain/ai/IOpenAI.java
@@ -10,6 +10,6 @@ import java.io.IOException;
*/
public interface IOpenAI {
- String doChatGPT(String question) throws IOException;
+ String doChatGPT(String openAiKey, String question) throws IOException;
}
diff --git a/chatbot-api-domain/src/main/java/cn/bugstack/chatbot/api/domain/ai/service/OpenAI.java b/chatbot-api-domain/src/main/java/cn/bugstack/chatbot/api/domain/ai/service/OpenAI.java
index 7713465..505c9bf 100644
--- a/chatbot-api-domain/src/main/java/cn/bugstack/chatbot/api/domain/ai/service/OpenAI.java
+++ b/chatbot-api-domain/src/main/java/cn/bugstack/chatbot/api/domain/ai/service/OpenAI.java
@@ -31,11 +31,8 @@ public class OpenAI implements IOpenAI {
private Logger logger = LoggerFactory.getLogger(OpenAI.class);
- @Value("${chatbot-api.openAiKey}")
- private String openAiKey;
-
@Override
- public String doChatGPT(String question) throws IOException {
+ public String doChatGPT(String openAiKey, String question) throws IOException {
CloseableHttpClient httpClient = HttpClientBuilder.create().build();
diff --git a/chatbot-api-interfaces/src/main/resources/application.yml b/chatbot-api-interfaces/src/main/resources/application.yml
index c002d21..94215e8 100644
--- a/chatbot-api-interfaces/src/main/resources/application.yml
+++ b/chatbot-api-interfaces/src/main/resources/application.yml
@@ -1,7 +1,18 @@
server:
port: 8090
+# 分组任务配置
chatbot-api:
- groupId: 28885518425541 # 知识星球ID
- cookie: # 知识星球个人cookie信息
- openAiKey: # 自行申请 https://beta.openai.com/overview 或者联系小傅哥 fustack 付费申请【购买虚拟号码等需要支付】。
\ No newline at end of file
+ launchList: group01,group02 # 启动几组,就配置几组
+ group01:
+ groupName: ChatGPT AI 问答助手
+ groupId: 28885518425541 # 知识星球ID
+ cookie: # 知识星球个人cookie信息
+ openAiKey: # 自行申请 https://beta.openai.com/overview 或者联系小傅哥 fustack 付费申请【购买虚拟号码等需要支付】。
+ cronExpression: 0/30 * * * * ? # 执行的频次配置,参考:cron.qqe2.com
+ group02:
+ groupName: 码农会锁
+ groupId: 28885518425541 # 知识星球ID
+ cookie: # 知识星球个人cookie信息
+ openAiKey: # 自行申请 https://beta.openai.com/overview 或者联系小傅哥 fustack 付费申请【购买虚拟号码等需要支付】。
+ cronExpression: 0/30 * * * * ? # 执行的频次配置,参考:cron.qqe2.com
\ No newline at end of file
diff --git a/chatbot-api-interfaces/src/test/java/cn/bugstack/chatbot/api/test/ApiTest.java b/chatbot-api-interfaces/src/test/java/cn/bugstack/chatbot/api/test/ApiTest.java
index d991b3f..6df0092 100644
--- a/chatbot-api-interfaces/src/test/java/cn/bugstack/chatbot/api/test/ApiTest.java
+++ b/chatbot-api-interfaces/src/test/java/cn/bugstack/chatbot/api/test/ApiTest.java
@@ -12,6 +12,8 @@ import org.apache.http.util.EntityUtils;
import org.junit.Test;
import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.util.Base64;
/**
* @author 小傅哥,微信:fustack
@@ -21,6 +23,12 @@ import java.io.IOException;
*/
public class ApiTest {
+ @Test
+ public void base64(){
+ String cronExpression = new String(Base64.getDecoder().decode("MC81MCAqICogKiAqID8="), StandardCharsets.UTF_8);
+ System.out.println(cronExpression);
+ }
+
@Test
public void query_unanswered_questions() throws IOException {
CloseableHttpClient httpClient = HttpClientBuilder.create().build();
diff --git a/chatbot-api-interfaces/src/test/java/cn/bugstack/chatbot/api/test/SpringBootRunTest.java b/chatbot-api-interfaces/src/test/java/cn/bugstack/chatbot/api/test/SpringBootRunTest.java
index b8662ba..1c7e996 100644
--- a/chatbot-api-interfaces/src/test/java/cn/bugstack/chatbot/api/test/SpringBootRunTest.java
+++ b/chatbot-api-interfaces/src/test/java/cn/bugstack/chatbot/api/test/SpringBootRunTest.java
@@ -29,10 +29,12 @@ public class SpringBootRunTest {
private Logger logger = LoggerFactory.getLogger(SpringBootRunTest.class);
- @Value("${chatbot-api.groupId}")
+ @Value("${chatbot-api.group01.groupId}")
private String groupId;
- @Value("${chatbot-api.cookie}")
+ @Value("${chatbot-api.group01.cookie}")
private String cookie;
+ @Value("${chatbot-api.group01.openAiKey}")
+ private String openAiKey;
@Resource
private IZsxqApi zsxqApi;
@@ -51,13 +53,13 @@ public class SpringBootRunTest {
logger.info("topicId:{} text:{}", topicId, text);
// 回答问题
- zsxqApi.answer(groupId, cookie, topicId, openAI.doChatGPT(text), false);
+ zsxqApi.answer(groupId, cookie, topicId, openAI.doChatGPT(openAiKey, text), false);
}
}
@Test
public void test_openAi() throws IOException {
- String response = openAI.doChatGPT("帮我写一个java冒泡排序");
+ String response = openAI.doChatGPT(openAiKey, "帮我写一个java冒泡排序");
logger.info("测试结果:{}", response);
}
diff --git a/pom.xml b/pom.xml
index df23ccf..f2a8ebe 100644
--- a/pom.xml
+++ b/pom.xml
@@ -14,6 +14,7 @@
chatbot-api-application
chatbot-api-interfaces
chatbot-api-infrastructure
+ chatbot-api-common
--
GitLab