From 440159e8a06feb3bcfe5f781e7b8451380a8ff9c Mon Sep 17 00:00:00 2001
From: zhaoyuhang <1045078399@qq.com>
Date: Sat, 1 Jul 2023 13:42:10 +0800
Subject: [PATCH] chatAI-handler
---
.../common/common/constant/RedisKey.java | 9 +-
.../src/main/resources/application.yml | 15 +-
.../domain/vo/request/ChatMessageReq.java | 4 +
.../chat/service/impl/ChatServiceImpl.java | 2 -
.../enums/ChatGPTModelEnum.java} | 10 +-
.../chatai/handler/AbstractChatAIHandler.java | 130 +++++++++++++
.../chatai/handler/ChatAIHandlerFactory.java | 42 +++++
.../chatai/handler/ChatGLM2Handler.java | 136 ++++++++++++++
.../chatai/handler/GPTChatAIHandler.java | 86 +++++++++
.../chatai/properties/ChatGLM2Properties.java | 43 +++++
.../chatai/properties/ChatGPTProperties.java | 44 +++++
.../custom/chatai/service/IChatAIService.java | 8 +
.../service/impl/ChatAIServiceImpl.java | 26 +++
.../custom/chatai/utils/ChatGLM2Utils.java | 107 +++++++++++
.../utils/ChatGPTUtils.java} | 30 +--
.../event/listener/MessageSendListener.java | 10 +
.../custom/openai/event/OpenAIEvent.java | 14 --
.../openai/event/listener/OpenAIListener.java | 63 -------
.../custom/openai/service/IOpenAIService.java | 11 --
.../service/impl/OpenAIServiceImpl.java | 171 ------------------
20 files changed, 673 insertions(+), 288 deletions(-)
rename mallchat-custom-server/src/main/java/com/abin/mallchat/custom/{openai/enums/OpenAIModelEnums.java => chatai/enums/ChatGPTModelEnum.java} (92%)
create mode 100644 mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chatai/handler/AbstractChatAIHandler.java
create mode 100644 mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chatai/handler/ChatAIHandlerFactory.java
create mode 100644 mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chatai/handler/ChatGLM2Handler.java
create mode 100644 mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chatai/handler/GPTChatAIHandler.java
create mode 100644 mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chatai/properties/ChatGLM2Properties.java
create mode 100644 mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chatai/properties/ChatGPTProperties.java
create mode 100644 mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chatai/service/IChatAIService.java
create mode 100644 mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chatai/service/impl/ChatAIServiceImpl.java
create mode 100644 mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chatai/utils/ChatGLM2Utils.java
rename mallchat-custom-server/src/main/java/com/abin/mallchat/custom/{openai/utils/OpenAIUtils.java => chatai/utils/ChatGPTUtils.java} (85%)
delete mode 100644 mallchat-custom-server/src/main/java/com/abin/mallchat/custom/openai/event/OpenAIEvent.java
delete mode 100644 mallchat-custom-server/src/main/java/com/abin/mallchat/custom/openai/event/listener/OpenAIListener.java
delete mode 100644 mallchat-custom-server/src/main/java/com/abin/mallchat/custom/openai/service/IOpenAIService.java
delete mode 100644 mallchat-custom-server/src/main/java/com/abin/mallchat/custom/openai/service/impl/OpenAIServiceImpl.java
diff --git a/mallchat-common/src/main/java/com/abin/mallchat/common/common/constant/RedisKey.java b/mallchat-common/src/main/java/com/abin/mallchat/common/common/constant/RedisKey.java
index a86d1c4..0cc9bd0 100644
--- a/mallchat-common/src/main/java/com/abin/mallchat/common/common/constant/RedisKey.java
+++ b/mallchat-common/src/main/java/com/abin/mallchat/common/common/constant/RedisKey.java
@@ -37,9 +37,14 @@ public class RedisKey {
public static final String USER_SUMMARY_STRING = "userSummary:uid_%d";
/**
- * 用户AI聊天次数
+ * 用户GPT聊天次数
*/
- public static final String USER_CHAT_NUM = "userAIChatNum:uid_%d";
+ public static final String USER_CHAT_NUM = "useChatGPTNum:uid_%d";
+
+ /**
+ * 用户上次使用GLM使用时间
+ */
+ public static final String USER_GLM2_TIME_LAST = "userGLM2UseTime:uid_%d";
public static String getKey(String key, Object... objects) {
return BASE_KEY + String.format(key, objects);
diff --git a/mallchat-common/src/main/resources/application.yml b/mallchat-common/src/main/resources/application.yml
index 0293bb6..e0f925e 100644
--- a/mallchat-common/src/main/resources/application.yml
+++ b/mallchat-common/src/main/resources/application.yml
@@ -63,8 +63,13 @@ wx:
secret: ${mallchat.wx.secret} # 公众号的appsecret
token: ${mallchat.wx.token} # 接口配置里的Token值
aesKey: ${mallchat.wx.aesKey} # 接口配置里的EncodingAESKey值
-openai:
- use-openai: true
- ai-user-id: xxxxx
- key: xxxxxxx
- proxy-url: https://xxxxxxx
\ No newline at end of file
+chatai:
+ chatgpt:
+ use: true
+ AIUserId: 10450
+ key: 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
+ chatglm2:
+ use: true
+ url: http://vastmiao.natapp1.cc
+ minute: 3 # 每个用户每3分钟可以请求一次
+ AIUserId: 10451
diff --git a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/domain/vo/request/ChatMessageReq.java b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/domain/vo/request/ChatMessageReq.java
index a6a6095..2fd2040 100644
--- a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/domain/vo/request/ChatMessageReq.java
+++ b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/domain/vo/request/ChatMessageReq.java
@@ -11,9 +11,13 @@ import javax.validation.constraints.NotNull;
/**
+ * 聊天信息点播
* Description: 消息发送请求体
* Author: abin
* Date: 2023-03-23
+ *
+ * @author zhaoyuhang
+ * @date 2023/06/30
*/
@Data
@Builder
diff --git a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/service/impl/ChatServiceImpl.java b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/service/impl/ChatServiceImpl.java
index 177dbfa..adbb1d3 100644
--- a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/service/impl/ChatServiceImpl.java
+++ b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/service/impl/ChatServiceImpl.java
@@ -38,7 +38,6 @@ import com.abin.mallchat.custom.chat.service.strategy.mark.MsgMarkFactory;
import com.abin.mallchat.custom.chat.service.strategy.msg.AbstractMsgHandler;
import com.abin.mallchat.custom.chat.service.strategy.msg.MsgHandlerFactory;
import com.abin.mallchat.custom.chat.service.strategy.msg.RecallMsgHandler;
-import com.abin.mallchat.custom.openai.event.OpenAIEvent;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
@@ -96,7 +95,6 @@ public class ChatServiceImpl implements ChatService {
msgHandler.saveMsg(insert, request);
//发布消息发送事件
applicationEventPublisher.publishEvent(new MessageSendEvent(this, insert.getId()));
- applicationEventPublisher.publishEvent(new OpenAIEvent(this, insert.getId()));
return insert.getId();
}
diff --git a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/openai/enums/OpenAIModelEnums.java b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chatai/enums/ChatGPTModelEnum.java
similarity index 92%
rename from mallchat-custom-server/src/main/java/com/abin/mallchat/custom/openai/enums/OpenAIModelEnums.java
rename to mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chatai/enums/ChatGPTModelEnum.java
index 194c3df..6b73b0f 100644
--- a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/openai/enums/OpenAIModelEnums.java
+++ b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chatai/enums/ChatGPTModelEnum.java
@@ -1,4 +1,4 @@
-package com.abin.mallchat.custom.openai.enums;
+package com.abin.mallchat.custom.chatai.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
@@ -10,7 +10,7 @@ import java.util.stream.Collectors;
@AllArgsConstructor
@Getter
-public enum OpenAIModelEnums {
+public enum ChatGPTModelEnum {
// chat
GPT_35_TURBO("gpt-3.5-turbo", 3, 40000),
GPT_35_TURBO_0301("gpt-3.5-turbo-0301", 3, 40000),
@@ -79,13 +79,13 @@ public enum OpenAIModelEnums {
*/
private final Integer TPM;
- private static final Map cache;
+ private static final Map cache;
static {
- cache = Arrays.stream(OpenAIModelEnums.values()).collect(Collectors.toMap(OpenAIModelEnums::getName, Function.identity()));
+ cache = Arrays.stream(ChatGPTModelEnum.values()).collect(Collectors.toMap(ChatGPTModelEnum::getName, Function.identity()));
}
- public static OpenAIModelEnums of(String name) {
+ public static ChatGPTModelEnum of(String name) {
return cache.get(name);
}
diff --git a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chatai/handler/AbstractChatAIHandler.java b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chatai/handler/AbstractChatAIHandler.java
new file mode 100644
index 0000000..04e5a6e
--- /dev/null
+++ b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chatai/handler/AbstractChatAIHandler.java
@@ -0,0 +1,130 @@
+package com.abin.mallchat.custom.chatai.handler;
+
+import cn.hutool.core.thread.NamedThreadFactory;
+import com.abin.mallchat.common.chat.domain.entity.Message;
+import com.abin.mallchat.common.chat.domain.enums.MessageTypeEnum;
+import com.abin.mallchat.common.common.exception.BusinessException;
+import com.abin.mallchat.common.common.handler.GlobalUncaughtExceptionHandler;
+import com.abin.mallchat.custom.chat.domain.vo.request.ChatMessageReq;
+import com.abin.mallchat.custom.chat.domain.vo.request.msg.TextMsgReq;
+import com.abin.mallchat.custom.chat.service.ChatService;
+import com.abin.mallchat.custom.user.domain.vo.response.user.UserInfoResp;
+import com.abin.mallchat.custom.user.service.UserService;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.DisposableBean;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.PostConstruct;
+import java.util.Collections;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+
+@Slf4j
+@Component
+public abstract class AbstractChatAIHandler implements DisposableBean, InitializingBean {
+ public static ExecutorService EXECUTOR;
+
+ @Autowired
+ protected ChatService chatService;
+ @Autowired
+ protected UserService userService;
+
+ @PostConstruct
+ private void init() {
+ ChatAIHandlerFactory.register(getChatAIUserId(), getChatAIName(), this);
+ }
+ // 获取机器人id
+ public abstract Long getChatAIUserId();
+ // 获取机器人名称
+ public abstract String getChatAIName();
+
+ public void chat(Message message) {
+ if (!supports(message)) {
+ return;
+ }
+ EXECUTOR.execute(() -> {
+ String text = doChat(message);
+ if (StringUtils.isNotBlank(text)) {
+ answerMsg(text, message.getRoomId(), message.getFromUid());
+ }
+ });
+ }
+
+ /**
+ * 支持
+ *
+ * @param message 消息
+ * @return boolean true 支持 false 不支持
+ */
+ protected abstract boolean supports(Message message);
+
+ /**
+ * 执行聊天
+ *
+ * @param message 消息
+ * @return {@link String} AI回答的内容
+ */
+ protected abstract String doChat(Message message);
+
+
+ protected void answerMsg(String text, Long roomId, Long uid) {
+ UserInfoResp userInfo = userService.getUserInfo(uid);
+ text = "@" + userInfo.getName() + " " + text;
+ if (text.length() < 450) {
+ save(text, roomId, uid);
+ }else {
+ int maxLen = 450;
+ int len = text.length();
+ int count = (len + maxLen - 1) / maxLen;
+
+ for (int i = 0; i < count; i++) {
+ int start = i * maxLen;
+ int end = Math.min(start + maxLen, len);
+ save(text.substring(start, end), roomId, uid);
+ }
+ }
+ }
+
+ private void save(String text, Long roomId, Long uid) {
+ ChatMessageReq answerReq = new ChatMessageReq();
+ answerReq.setRoomId(roomId);
+ answerReq.setMsgType(MessageTypeEnum.TEXT.getType());
+ TextMsgReq textMsgReq = new TextMsgReq();
+ textMsgReq.setContent(text);
+ textMsgReq.setAtUidList(Collections.singletonList(uid));
+ answerReq.setBody(textMsgReq);
+ chatService.sendMsg(answerReq, getChatAIUserId());
+ }
+
+ @Override
+ public void afterPropertiesSet() {
+ EXECUTOR = new ThreadPoolExecutor(
+ 10,
+ 10,
+ 0L,
+ TimeUnit.MILLISECONDS,
+ new LinkedBlockingQueue<>(15),
+ new NamedThreadFactory("openAI-chat-gpt",
+ null,
+ false,
+ new GlobalUncaughtExceptionHandler()),
+ (r, executor) -> {
+ throw new BusinessException("别问的太快了,我的脑子不够用了");
+ });
+ }
+
+ @Override
+ public void destroy() throws Exception {
+ EXECUTOR.shutdown();
+ if (!EXECUTOR.awaitTermination(30, TimeUnit.SECONDS)) { //最多等30秒,处理不完就拉倒
+ if (log.isErrorEnabled()) {
+ log.error("Timed out while waiting for executor [{}] to terminate", EXECUTOR);
+ }
+ }
+ }
+}
diff --git a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chatai/handler/ChatAIHandlerFactory.java b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chatai/handler/ChatAIHandlerFactory.java
new file mode 100644
index 0000000..8d6356d
--- /dev/null
+++ b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chatai/handler/ChatAIHandlerFactory.java
@@ -0,0 +1,42 @@
+package com.abin.mallchat.custom.chatai.handler;
+
+import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
+import com.baomidou.mybatisplus.core.toolkit.StringUtils;
+
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+public class ChatAIHandlerFactory {
+ private static final Map CHATAI_ID_MAP = new ConcurrentHashMap<>();
+ private static final Map CHATAI_NAME_MAP = new ConcurrentHashMap<>();
+
+ public static void register(Long aIUserId, String name, AbstractChatAIHandler chatAIHandler) {
+ CHATAI_ID_MAP.put(aIUserId, chatAIHandler);
+ CHATAI_NAME_MAP.put(name, chatAIHandler);
+ }
+
+ public static AbstractChatAIHandler getChatAIHandlerById(List userIds) {
+ if (CollectionUtils.isEmpty(userIds)) {
+ return null;
+ }
+ for (Long userId : userIds) {
+ AbstractChatAIHandler chatAIHandler = CHATAI_ID_MAP.get(userId);
+ if (chatAIHandler != null) {
+ return chatAIHandler;
+ }
+ }
+ return null;
+ }
+ public static AbstractChatAIHandler getChatAIHandlerByName(String text) {
+ if (StringUtils.isBlank(text)) {
+ return null;
+ }
+ for (Map.Entry entry : CHATAI_NAME_MAP.entrySet()) {
+ if (text.contains("@"+entry.getKey())) {
+ return entry.getValue();
+ }
+ }
+ return null;
+ }
+}
diff --git a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chatai/handler/ChatGLM2Handler.java b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chatai/handler/ChatGLM2Handler.java
new file mode 100644
index 0000000..ca529f3
--- /dev/null
+++ b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chatai/handler/ChatGLM2Handler.java
@@ -0,0 +1,136 @@
+package com.abin.mallchat.custom.chatai.handler;
+
+import cn.hutool.http.HttpResponse;
+import com.abin.mallchat.common.chat.domain.entity.Message;
+import com.abin.mallchat.common.common.constant.RedisKey;
+import com.abin.mallchat.common.common.utils.RedisUtils;
+import com.abin.mallchat.custom.chatai.properties.ChatGLM2Properties;
+import com.abin.mallchat.custom.chatai.utils.ChatGLM2Utils;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.util.Arrays;
+import java.util.Date;
+import java.util.List;
+import java.util.Random;
+import java.util.concurrent.TimeUnit;
+
+import static com.abin.mallchat.common.common.constant.RedisKey.USER_GLM2_TIME_LAST;
+
+@Slf4j
+@Component
+public class ChatGLM2Handler extends AbstractChatAIHandler {
+
+ private static final List ERROR_MSG = Arrays.asList(
+ "还摸鱼呢?你不下班我还要下班呢。。。。",
+ "没给钱,矿工了。。。。",
+ "服务器被你们玩儿坏了。。。。",
+ "你们这群人,我都不想理你们了。。。。",
+ "还艾特我呢?那是另外的价钱。。。。",
+ "得加钱");
+
+
+ private static final Random RANDOM = new Random();
+
+ @Autowired
+ private ChatGLM2Properties glm2Properties;
+
+ @Override
+ public Long getChatAIUserId() {
+ return glm2Properties.getAIUserId();
+ }
+
+ @Override
+ public String getChatAIName() {
+ if (StringUtils.isNotBlank(glm2Properties.getAIUserName())) {
+ return glm2Properties.getAIUserName();
+ }
+ String name = userService.getUserInfo(glm2Properties.getAIUserId()).getName();
+ glm2Properties.setAIUserName(name);
+ return name;
+ }
+
+ @Override
+ protected String doChat(Message message) {
+ String content = message.getContent().replace("@" +glm2Properties.getAIUserName(), "").trim();
+ Long uid = message.getFromUid();
+ Long minute;
+ String text;
+ if ((minute = userMinutesLater(uid)) > 0) {
+ text = "你太快了 " + minute + "分钟后重试";
+ } else {
+ HttpResponse response = null;
+ try {
+ response = ChatGLM2Utils
+ .create()
+ .url(glm2Properties.getUrl())
+ .prompt(content)
+ .send();
+ } catch (Exception e) {
+ e.printStackTrace();
+ return getErrorText();
+ }
+ text = ChatGLM2Utils.parseText(response);
+ if (StringUtils.isNotBlank(text)) {
+ RedisUtils.set(RedisKey.getKey(USER_GLM2_TIME_LAST, uid), new Date(), glm2Properties.getMinute(), TimeUnit.MINUTES);
+ }
+ }
+ return text;
+ }
+
+ private static String getErrorText() {
+ int index = RANDOM.nextInt(ERROR_MSG.size());
+ return ERROR_MSG.get(index);
+ }
+
+ /**
+ * 用户多少分钟后才能再次聊天
+ *
+ * @param uid
+ * @return
+ */
+ private Long userMinutesLater(Long uid) {
+ // 获取用户最后聊天时间
+ Date lastChatTime = RedisUtils.get(RedisKey.getKey(USER_GLM2_TIME_LAST, uid), Date.class);
+ if (lastChatTime == null) {
+ // 如果没有聊天记录,则可以立即聊天
+ return 0L;
+ }
+ // 计算当前时间和上次聊天时间之间的时间差
+ long now = System.currentTimeMillis();
+ long lastChatTimeMillis = lastChatTime.getTime();
+ long durationMillis = now - lastChatTimeMillis;
+ long minutes = TimeUnit.MILLISECONDS.toMinutes(durationMillis);
+ // 计算剩余等待时间
+ long remainingMinutes = glm2Properties.getMinute() - minutes;
+ return remainingMinutes > 0 ? remainingMinutes : 0L;
+ }
+
+
+ @Override
+ protected boolean supports(Message message) {
+ if (!glm2Properties.isUse()) {
+ return false;
+ }
+ /* 前端传@信息后取消注释 */
+
+// MessageExtra extra = message.getExtra();
+// if (extra == null) {
+// return false;
+// }
+// if (CollectionUtils.isEmpty(extra.getAtUidList())) {
+// return false;
+// }
+// if (!extra.getAtUidList().contains(ChatAIServiceImpl.AI_USER_ID)) {
+// return false;
+// }
+
+ if (StringUtils.isBlank(message.getContent())) {
+ return false;
+ }
+ return StringUtils.contains(message.getContent(), "@" + glm2Properties.getAIUserName())
+ && StringUtils.isNotBlank(message.getContent().replace(glm2Properties.getAIUserName(), "").trim());
+ }
+}
diff --git a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chatai/handler/GPTChatAIHandler.java b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chatai/handler/GPTChatAIHandler.java
new file mode 100644
index 0000000..e981fa7
--- /dev/null
+++ b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chatai/handler/GPTChatAIHandler.java
@@ -0,0 +1,86 @@
+package com.abin.mallchat.custom.chatai.handler;
+
+import cn.hutool.http.HttpResponse;
+import com.abin.mallchat.common.chat.domain.entity.Message;
+import com.abin.mallchat.common.common.constant.RedisKey;
+import com.abin.mallchat.common.common.utils.DateUtils;
+import com.abin.mallchat.common.common.utils.RedisUtils;
+import com.abin.mallchat.custom.chatai.properties.ChatGPTProperties;
+import com.abin.mallchat.custom.chatai.utils.ChatGPTUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.util.concurrent.TimeUnit;
+
+@Component
+public class GPTChatAIHandler extends AbstractChatAIHandler {
+
+ @Autowired
+ private ChatGPTProperties chatGPTProperties;
+
+ @Override
+ public Long getChatAIUserId() {
+ return chatGPTProperties.getAIUserId();
+ }
+
+ @Override
+ public String getChatAIName() {
+ if (StringUtils.isNotBlank(chatGPTProperties.getAIUserName())) {
+ return chatGPTProperties.getAIUserName();
+ }
+ String name = userService.getUserInfo(chatGPTProperties.getAIUserId()).getName();
+ chatGPTProperties.setAIUserName(name);
+ return name;
+ }
+
+ @Override
+ protected String doChat(Message message) {
+ String content = message.getContent().replace("@" +chatGPTProperties.getAIUserName(), "").trim();
+ Long uid = message.getFromUid();
+ Long chatNum;
+ String text;
+ if ((chatNum = userChatNumInrc(uid)) > chatGPTProperties.getLimit()) {
+ text = "你今天已经和我聊了" + chatNum + "次了,我累了,明天再聊吧";
+ } else {
+ HttpResponse response = ChatGPTUtils.create(chatGPTProperties.getKey())
+ .proxyUrl(chatGPTProperties.getProxyUrl())
+ .model(chatGPTProperties.getModelName())
+ .prompt(content)
+ .send();
+ text = ChatGPTUtils.parseText(response);
+ }
+ return text;
+ }
+
+ private Long userChatNumInrc(Long uid) {
+ //todo:白名单
+ return RedisUtils.inc(RedisKey.getKey(RedisKey.USER_CHAT_NUM, uid), DateUtils.getEndTimeByToday().intValue(), TimeUnit.MILLISECONDS);
+ }
+
+
+ @Override
+ protected boolean supports(Message message) {
+ if (!chatGPTProperties.isUse()) {
+ return false;
+ }
+ /* 前端传@信息后取消注释 */
+
+// MessageExtra extra = message.getExtra();
+// if (extra == null) {
+// return false;
+// }
+// if (CollectionUtils.isEmpty(extra.getAtUidList())) {
+// return false;
+// }
+// if (!extra.getAtUidList().contains(ChatAIServiceImpl.AI_USER_ID)) {
+// return false;
+// }
+
+ if (StringUtils.isBlank(message.getContent())) {
+ return false;
+ }
+ return StringUtils.contains(message.getContent(), "@" + chatGPTProperties.getAIUserName())
+ && StringUtils.isNotBlank(message.getContent().replace(chatGPTProperties.getAIUserName(), "").trim());
+ }
+}
diff --git a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chatai/properties/ChatGLM2Properties.java b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chatai/properties/ChatGLM2Properties.java
new file mode 100644
index 0000000..582ce4a
--- /dev/null
+++ b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chatai/properties/ChatGLM2Properties.java
@@ -0,0 +1,43 @@
+package com.abin.mallchat.custom.chatai.properties;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+
+/**
+ * ChatGLM2 配置文件
+ *
+ * @author zhaoyuhang
+ * @date 2023/06/30
+ */
+@Data
+@Component
+@ConfigurationProperties(prefix = "chatai.chatglm2")
+public class ChatGLM2Properties {
+
+ /**
+ * 使用
+ */
+ private boolean use;
+
+ /**
+ * url
+ */
+ private String url;
+
+ /**
+ * 机器人 id
+ */
+ private Long AIUserId;
+
+ /**
+ * 机器人名称
+ */
+ private String AIUserName;
+
+ /**
+ * 每个用户每3分钟可以请求一次
+ */
+ private Long minute = 3L;
+
+}
diff --git a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chatai/properties/ChatGPTProperties.java b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chatai/properties/ChatGPTProperties.java
new file mode 100644
index 0000000..b7a5c56
--- /dev/null
+++ b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chatai/properties/ChatGPTProperties.java
@@ -0,0 +1,44 @@
+package com.abin.mallchat.custom.chatai.properties;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+
+
+@Data
+@Component
+@ConfigurationProperties(prefix = "chatai.chatgpt")
+public class ChatGPTProperties {
+
+ /**
+ * 是否使用openAI
+ */
+ private boolean use;
+ /**
+ * 机器人 id
+ */
+ private Long AIUserId;
+
+ /**
+ * 机器人名称
+ */
+ private String AIUserName;
+ /**
+ * 模型名称
+ */
+ private String modelName = "text-davinci-003";
+ /**
+ * openAI key
+ */
+ private String key;
+ /**
+ * 代理地址
+ */
+ private String proxyUrl;
+
+ /**
+ * 用户每天条数限制
+ */
+ private Integer limit = 5;
+
+}
diff --git a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chatai/service/IChatAIService.java b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chatai/service/IChatAIService.java
new file mode 100644
index 0000000..8cded22
--- /dev/null
+++ b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chatai/service/IChatAIService.java
@@ -0,0 +1,8 @@
+package com.abin.mallchat.custom.chatai.service;
+
+import com.abin.mallchat.common.chat.domain.entity.Message;
+
+public interface IChatAIService {
+
+ void chat(Message message);
+}
diff --git a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chatai/service/impl/ChatAIServiceImpl.java b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chatai/service/impl/ChatAIServiceImpl.java
new file mode 100644
index 0000000..37af88e
--- /dev/null
+++ b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chatai/service/impl/ChatAIServiceImpl.java
@@ -0,0 +1,26 @@
+package com.abin.mallchat.custom.chatai.service.impl;
+
+import com.abin.mallchat.common.chat.domain.entity.Message;
+import com.abin.mallchat.common.chat.domain.entity.msg.MessageExtra;
+import com.abin.mallchat.custom.chatai.handler.AbstractChatAIHandler;
+import com.abin.mallchat.custom.chatai.handler.ChatAIHandlerFactory;
+import com.abin.mallchat.custom.chatai.service.IChatAIService;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+
+@Slf4j
+@Service
+public class ChatAIServiceImpl implements IChatAIService {
+ @Override
+ public void chat(Message message) {
+ MessageExtra extra = message.getExtra();
+ if (extra == null) {
+ return;
+ }
+ AbstractChatAIHandler chatAI = ChatAIHandlerFactory.getChatAIHandlerByName(message.getContent());
+// AbstractChatAIHandler chatAI = ChatAIHandlerFactory.getChatAIHandlerById(extra.getAtUidList());
+ if (chatAI != null) {
+ chatAI.chat(message);
+ }
+ }
+}
\ No newline at end of file
diff --git a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chatai/utils/ChatGLM2Utils.java b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chatai/utils/ChatGLM2Utils.java
new file mode 100644
index 0000000..2729e0a
--- /dev/null
+++ b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chatai/utils/ChatGLM2Utils.java
@@ -0,0 +1,107 @@
+package com.abin.mallchat.custom.chatai.utils;
+
+import cn.hutool.http.HttpResponse;
+import cn.hutool.http.HttpUtil;
+import cn.hutool.json.JSONObject;
+import lombok.extern.slf4j.Slf4j;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+@Slf4j
+public class ChatGLM2Utils {
+
+
+ private final Map headers;
+ /**
+ * 超时30秒
+ */
+ private Integer timeout = 60 * 1000;
+
+ private String url;
+ /**
+ * 提示词
+ */
+ private String prompt;
+
+ /**
+ * 历史
+ */
+ private List