提交 72dd9105 编写于 作者: 小傅哥's avatar 小傅哥

小傅哥,feat:第7节:多组任务服务配置

上级 eef57654
......@@ -34,6 +34,12 @@
<artifactId>chatbot-api-domain</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>cn.bugstack.ai</groupId>
<artifactId>chatbot-api-common</artifactId>
<version>1.0-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
</dependencies>
</project>
\ No newline at end of file
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<String, Map<String, Object>> 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<String, Object> taskGroupProps = PropertyUtil.handle(environment, prefix + groupKey, Map.class);
taskGroupMap.put(groupKey, taskGroupProps);
}
}
@Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
Set<String> taskGroups = taskGroupMap.keySet();
for (String groupKey : taskGroups) {
Map<String, Object> 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);
}
}
}
......@@ -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> 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);
}
}
......
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>chatbot-api</artifactId>
<groupId>cn.bugstack.ai</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>chatbot-api-common</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
</dependencies>
</project>
\ No newline at end of file
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 <T> : refer to @param targetClass
* @return T
*/
@SuppressWarnings("unchecked")
public static <T> T handle(final Environment environment, final String prefix, final Class<T> 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);
}
}
}
......@@ -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;
}
......@@ -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();
......
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
......@@ -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();
......
......@@ -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);
}
......
......@@ -14,6 +14,7 @@
<module>chatbot-api-application</module>
<module>chatbot-api-interfaces</module>
<module>chatbot-api-infrastructure</module>
<module>chatbot-api-common</module>
</modules>
<parent>
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册