改变了带有预设的聊天的实现逻辑,去除了正常聊天内容中“切换模型”这一指令

This commit is contained in:
slhaf
2024-10-02 22:52:39 +08:00
parent 9f7629eb20
commit 3d0ad90ef7
15 changed files with 476 additions and 299 deletions

View File

@@ -16,6 +16,8 @@ dependencies{
implementation("cn.bigmodel.openapi:oapi-java-sdk:release-V4-2.0.2") implementation("cn.bigmodel.openapi:oapi-java-sdk:release-V4-2.0.2")
implementation ("com.aliyun:ocr_api20210707:3.1.1") implementation ("com.aliyun:ocr_api20210707:3.1.1")
implementation ("junit:junit:4.13.2") implementation ("junit:junit:4.13.2")
implementation ("org.apache.logging.log4j:log4j-core:2.23.1")
implementation ("org.apache.logging.log4j:log4j-api:2.23.1")
} }

View File

@@ -6,18 +6,21 @@ import net.mamoe.mirai.event.GlobalEventChannel;
import net.mamoe.mirai.event.events.FriendMessageEvent; import net.mamoe.mirai.event.events.FriendMessageEvent;
import net.mamoe.mirai.event.events.GroupMessageEvent; import net.mamoe.mirai.event.events.GroupMessageEvent;
import net.mamoe.mirai.utils.MiraiLogger; import net.mamoe.mirai.utils.MiraiLogger;
import plugin.listener.UserMessageListener; import plugin.constant.ChatConstant;
import plugin.listener.FriendMessageListener;
import plugin.listener.GroupMessageListener;
import plugin.listener.OwnerMessageListener;
import plugin.pojo.Config; import plugin.pojo.Config;
import plugin.utils.ConfigUtil; import plugin.utils.ConfigUtil;
import java.io.IOException; import java.io.IOException;
import java.util.HashMap;
public final class App extends JavaPlugin { public final class App extends JavaPlugin {
public static final App INSTANCE = new App(); public static final App INSTANCE = new App();
public static MiraiLogger logger;
private String owner, bot; private String owner, bot;
private static HashMap<String,String> customCommands;
private App() { private App() {
super(new JvmPluginDescriptionBuilder("com.plugin.chatAI-InGroup-v2", "0.1.0") super(new JvmPluginDescriptionBuilder("com.plugin.chatAI-InGroup-v2", "0.1.0")
@@ -31,12 +34,12 @@ public final class App extends JavaPlugin {
public void onEnable() { public void onEnable() {
//加载配置 //加载配置
try { try {
logger = getLogger();
ConfigUtil.load(); ConfigUtil.load();
Thread.sleep(1500); Thread.sleep(1500);
Config config = ConfigUtil.getConfig(); Config config = ConfigUtil.getConfig();
owner = config.getOwner().substring(1); owner = config.getOwner().substring(1);
bot = config.getBot().substring(1); bot = config.getBot().substring(1);
customCommands = config.getCustomCommands();
} catch (IOException | ClassNotFoundException | InterruptedException e) { } catch (IOException | ClassNotFoundException | InterruptedException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
@@ -48,13 +51,21 @@ public final class App extends JavaPlugin {
GlobalEventChannel.INSTANCE.filterIsInstance(GroupMessageEvent.class) GlobalEventChannel.INSTANCE.filterIsInstance(GroupMessageEvent.class)
.filter(event -> { .filter(event -> {
String msg = event.getMessage().contentToString(); String msg = event.getMessage().contentToString();
return (msg.startsWith(".") && msg.length() != 1) || msg.startsWith("@"+bot) || msg.startsWith("/c "); return (msg.startsWith(".") && msg.length() != 1) || msg.startsWith("@"+bot) || customCommands.containsKey(msg.split(" ")[0]);
}).registerListenerHost(new UserMessageListener()); }).registerListenerHost(new GroupMessageListener());
//所有者监听
GlobalEventChannel.INSTANCE.filterIsInstance(GroupMessageEvent.class)
.filter(event -> {
String msg = event.getMessage().contentToString();
String sender = String.valueOf(event.getSender().getId());
return msg.startsWith(ChatConstant.SET) && sender.equals(owner);
}).registerListenerHost(new OwnerMessageListener());
//私聊监听器 //私聊监听器
GlobalEventChannel.INSTANCE.filterIsInstance(FriendMessageEvent.class) GlobalEventChannel.INSTANCE.filterIsInstance(FriendMessageEvent.class)
.filter(event -> true) .filter(event -> true)
.registerListenerHost(new UserMessageListener()); .registerListenerHost(new FriendMessageListener());
} }

View File

@@ -23,12 +23,14 @@ public class ChatConstant {
/** /**
* 普通对话标志 * 普通对话标志
*/ */
public static final String NORMAL_MESSAGE_START = "@"; public static final String DEFAULT_MESSAGE_START = "@";
/** /**
* code对话标志 * 分隔符(空格)
*/ */
public static final String CODE_MESSAGE_START = "/c "; public static final String BLANK = " ";
public static final String SET = "/set ";
/** /**
* 切换模型 * 切换模型
@@ -44,4 +46,9 @@ public class ChatConstant {
* 清理消息 * 清理消息
*/ */
public static final String CLEAR = "clear"; public static final String CLEAR = "clear";
/**
* 当前模型
*/
public static final String CURRENT_MODEL = "当前模型";
} }

View File

@@ -0,0 +1,13 @@
package plugin.constant;
/**
* @author SLHAF
*/
public class ConfigConstant {
public static final String DEFAULT = "default";
public static final String NULL = "null";
public static final String CUSTOM_SPLIT = "\\|";
}

View File

@@ -0,0 +1,23 @@
package plugin.constant;
public enum MethodsConstant {
/**
* 正常对话
*/
NORMAL,
/**
* 单次对话
*/
ONCE,
/**
* 预设对话
*/
CUSTOM,
/**
* 未匹配
*/
NONE
}

View File

@@ -0,0 +1,63 @@
package plugin.listener;
import net.mamoe.mirai.event.EventHandler;
import net.mamoe.mirai.event.SimpleListenerHost;
import net.mamoe.mirai.event.events.FriendMessageEvent;
import plugin.constant.ChatConstant;
import plugin.constant.MethodsConstant;
import plugin.pojo.Config;
import plugin.utils.AIUtil;
import plugin.utils.ConfigUtil;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class FriendMessageListener extends SimpleListenerHost {
private static final Config config = ConfigUtil.getConfig();
@EventHandler
public void friendMessageHandler(FriendMessageEvent event) {
/*String id = String.valueOf(event.getFriend().getId());
String content = event.getMessage().contentToString();
String miraiCode = event.getMessage().serializeToMiraiCode();
String url = null;
if (miraiCode.matches(ChatConstant.MATCH_MESSAGE)) {
String regex = ChatConstant.MATCH_IMAGE;
Pattern pattern = Pattern.compile(regex);
// 创建Matcher对象
Matcher matcher = pattern.matcher(miraiCode);
// 查找并提取链接
if (matcher.find()) {
//提取第一个括号内的内容
url = matcher.group(1);
}
}
MethodsConstant method = MethodsConstant.NORMAL;
if (content.contains(ChatConstant.CHANGE_MODEL) && !id.equals(config.getOwner().substring(1))) {
event.getFriend().sendMessage("没有权限!");
return;
}
//处理消息头
if (content.startsWith(ChatConstant.CODE_MESSAGE_START)) {
content = content.substring(3);
method = MethodsConstant.CUSTOM;
} else if (content.startsWith(ChatConstant.ONCE_MESSAGE_START)) {
content = content.substring(1);
method = MethodsConstant.ONCE;
}
//发送请求并获取回应
String response = switch (method) {
case CUSTOM -> AIUtil.customChat(Long.valueOf(id), content, url, chatCommand);
case ONCE -> AIUtil.chatOnce(content, url);
case NORMAL -> AIUtil.defaultChat(Long.valueOf(id), content, url);
default -> "ERROR!";
};
event.getFriend().sendMessage(response);*/
}
}

View File

@@ -0,0 +1,90 @@
package plugin.listener;
import kotlin.coroutines.CoroutineContext;
import net.mamoe.mirai.event.EventHandler;
import net.mamoe.mirai.event.SimpleListenerHost;
import net.mamoe.mirai.event.events.GroupMessageEvent;
import net.mamoe.mirai.message.data.At;
import org.jetbrains.annotations.NotNull;
import plugin.constant.ChatConstant;
import plugin.constant.MethodsConstant;
import plugin.pojo.Config;
import plugin.utils.AIUtil;
import plugin.utils.ConfigUtil;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import static plugin.utils.ConfigUtil.logger;
/**
* @author SLHAF
*/
public class GroupMessageListener extends SimpleListenerHost {
private static final Config config = ConfigUtil.getConfig();
@Override
public void handleException(@NotNull CoroutineContext context, @NotNull Throwable exception) {
super.handleException(context, exception);
logger.error(exception.getMessage());
}
/**
* 负责提取链接、获取消息内容去除指令头提取指令、提取发送者id
* @param event 接收群聊消息
*/
@EventHandler
public void groupMessageHandler(GroupMessageEvent event) {
//处理消息
String id = String.valueOf(event.getSender().getId());
String content = event.getMessage().contentToString();
String miraiCode = event.getMessage().serializeToMiraiCode();
String url = null;
String chatCommand = null;
if (miraiCode.matches(ChatConstant.MATCH_MESSAGE)) {
String regex = ChatConstant.MATCH_IMAGE;
Pattern pattern = Pattern.compile(regex);
// 创建Matcher对象
Matcher matcher = pattern.matcher(miraiCode);
// 查找并提取链接
if (matcher.find()) {
//提取第一个括号内的内容
url = matcher.group(1);
}
}
MethodsConstant method = MethodsConstant.NONE;
//消息头处理
if (content.startsWith(ChatConstant.ONCE_MESSAGE_START)) {
//单次对话
content = content.substring(1);
method = MethodsConstant.ONCE;
} else if (content.startsWith(ChatConstant.DEFAULT_MESSAGE_START + event.getBot().getId())) {
//默认对话
content = content.substring((ChatConstant.DEFAULT_MESSAGE_START + event.getBot().getId()).length());
method = MethodsConstant.NORMAL;
} else if (config.getCustomCommands().containsKey(content.split(ChatConstant.BLANK)[0])) {
//预设对话
content = content.split(ChatConstant.BLANK)[1];
method = MethodsConstant.CUSTOM;
chatCommand = content.split(ChatConstant.BLANK)[0];
}
//消息内容处理
if (content.isBlank()) {
content = "在吗";
}
//发送请求并获取回应
String response = switch (method) {
case CUSTOM -> AIUtil.customChat(Long.valueOf(id), content, url,chatCommand);
case NORMAL -> AIUtil.defaultChat(Long.valueOf(id), content, url);
case ONCE -> AIUtil.chatOnce(content, url);
default -> "ERROR!";
};
event.getGroup().sendMessage(new At(Long.parseLong(id)).plus("\r\n").plus(response));
}
}

View File

@@ -0,0 +1,6 @@
package plugin.listener;
import net.mamoe.mirai.event.SimpleListenerHost;
public class OwnerMessageListener extends SimpleListenerHost {
}

View File

@@ -1,152 +0,0 @@
package plugin.listener;
import kotlin.coroutines.CoroutineContext;
import net.mamoe.mirai.event.EventHandler;
import net.mamoe.mirai.event.SimpleListenerHost;
import net.mamoe.mirai.event.events.FriendMessageEvent;
import net.mamoe.mirai.event.events.GroupMessageEvent;
import net.mamoe.mirai.message.data.At;
import org.jetbrains.annotations.NotNull;
import plugin.constant.ChatConstant;
import plugin.pojo.Config;
import plugin.utils.AIUtil;
import plugin.utils.ConfigUtil;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import static plugin.App.logger;
/**
* @author SLHAF
*/
public class UserMessageListener extends SimpleListenerHost {
private static final Config config = ConfigUtil.getConfig();
public enum Methods {
/**
* 正常对话
*/
NORMAL,
/**
* 单次对话
*/
ONCE,
/**
* 预设code
*/
CODE,
/**
* 未匹配
*/
NONE
}
@Override
public void handleException(@NotNull CoroutineContext context, @NotNull Throwable exception) {
super.handleException(context, exception);
logger.error(exception.getMessage());
}
@EventHandler
public void groupMessageHandler(GroupMessageEvent event) {
//处理消息
String id = String.valueOf(event.getSender().getId());
String content = event.getMessage().contentToString();
String miraiCode = event.getMessage().serializeToMiraiCode();
String url = null;
if (miraiCode.matches(ChatConstant.MATCH_MESSAGE)) {
String regex = ChatConstant.MATCH_IMAGE;
Pattern pattern = Pattern.compile(regex);
// 创建Matcher对象
Matcher matcher = pattern.matcher(miraiCode);
// 查找并提取链接
if (matcher.find()) {
//提取第一个括号内的内容
url = matcher.group(1);
}
}
Methods method = Methods.NONE;
if (content.contains(ChatConstant.CHANGE_MODEL) && !id.equals(config.getOwner().substring(1))) {
event.getGroup().sendMessage(new At(Long.parseLong(id)).plus("没有权限!"));
return;
}
//消息头处理
if (content.startsWith(ChatConstant.ONCE_MESSAGE_START)) {
content = content.substring(1);
method = Methods.ONCE;
} else if (content.startsWith(ChatConstant.NORMAL_MESSAGE_START + event.getBot().getId())) {
content = content.substring((ChatConstant.NORMAL_MESSAGE_START + event.getBot().getId()).length());
method = Methods.NORMAL;
} else if (content.startsWith(ChatConstant.CODE_MESSAGE_START)) {
content = content.substring(3);
method = Methods.CODE;
}
//消息内容处理
if (content.isBlank()) {
content = "在吗";
}
//发送请求并获取回应
String response = switch (method) {
case CODE -> AIUtil.chatCode(Long.valueOf(id), content, url);
case NORMAL -> AIUtil.chatNormal(Long.valueOf(id), content, url);
case ONCE -> AIUtil.chatOnce(content, url);
default -> "ERROR!";
};
event.getGroup().sendMessage(new At(Long.parseLong(id)).plus("\r\n").plus(response));
}
@EventHandler
public void friendMessageHandler(FriendMessageEvent event) {
String id = String.valueOf(event.getFriend().getId());
String content = event.getMessage().contentToString();
String miraiCode = event.getMessage().serializeToMiraiCode();
String url = null;
if (miraiCode.matches(ChatConstant.MATCH_MESSAGE)) {
String regex = ChatConstant.MATCH_IMAGE;
Pattern pattern = Pattern.compile(regex);
// 创建Matcher对象
Matcher matcher = pattern.matcher(miraiCode);
// 查找并提取链接
if (matcher.find()) {
//提取第一个括号内的内容
url = matcher.group(1);
}
}
Methods method = Methods.NORMAL;
if (content.contains(ChatConstant.CHANGE_MODEL) && !id.equals(config.getOwner().substring(1))) {
event.getFriend().sendMessage("没有权限!");
return;
}
//处理消息头
if (content.startsWith(ChatConstant.CODE_MESSAGE_START)) {
content = content.substring(3);
method = Methods.CODE;
} else if (content.startsWith(ChatConstant.ONCE_MESSAGE_START)) {
content = content.substring(1);
method = Methods.ONCE;
}
//发送请求并获取回应
String response = switch (method) {
case CODE -> AIUtil.chatCode(Long.valueOf(id), content, url);
case ONCE -> AIUtil.chatOnce(content, url);
case NORMAL -> AIUtil.chatNormal(Long.valueOf(id), content, url);
default -> "ERROR!";
};
event.getFriend().sendMessage(response);
}
}

View File

@@ -1,6 +1,7 @@
package plugin.pojo; package plugin.pojo;
import java.util.HashMap; import java.util.HashMap;
import java.util.LinkedHashMap;
public class Config { public class Config {
/** /**
@@ -18,8 +19,7 @@ public class Config {
* 基础配置 * 基础配置
*/ */
private String owner; private String owner;
private String modelNormal; private String defaultModel;
private String modelCode;
private String bot; private String bot;
private String timeout; private String timeout;
private String timeCheck; private String timeCheck;
@@ -27,18 +27,17 @@ public class Config {
/** /**
* 自定义预设 * 自定义预设
*/ */
private HashMap<String,String> customCommands; private LinkedHashMap<String,String> customCommands;
public Config() { public Config() {
} }
public Config(String apikey, String accessKeyId, String accessKeySecret, String owner, String modelNormal, String modelCode, String bot, String timeout, String timeCheck, HashMap<String, String> customCommands) { public Config(String apikey, String accessKeyId, String accessKeySecret, String owner, String defaultModel, String bot, String timeout, String timeCheck, LinkedHashMap<String, String> customCommands) {
this.apikey = apikey; this.apikey = apikey;
this.accessKeyId = accessKeyId; this.accessKeyId = accessKeyId;
this.accessKeySecret = accessKeySecret; this.accessKeySecret = accessKeySecret;
this.owner = owner; this.owner = owner;
this.modelNormal = modelNormal; this.defaultModel = defaultModel;
this.modelCode = modelCode;
this.bot = bot; this.bot = bot;
this.timeout = timeout; this.timeout = timeout;
this.timeCheck = timeCheck; this.timeCheck = timeCheck;
@@ -113,32 +112,16 @@ public class Config {
* 获取 * 获取
* @return modelNormal * @return modelNormal
*/ */
public String getModelNormal() { public String getDefaultModel() {
return modelNormal; return defaultModel;
} }
/** /**
* 设置 * 设置
* @param modelNormal * @param defaultModel
*/ */
public void setModelNormal(String modelNormal) { public void setDefaultModel(String defaultModel) {
this.modelNormal = modelNormal; this.defaultModel = defaultModel;
}
/**
* 获取
* @return modelCode
*/
public String getModelCode() {
return modelCode;
}
/**
* 设置
* @param modelCode
*/
public void setModelCode(String modelCode) {
this.modelCode = modelCode;
} }
/** /**
@@ -201,12 +184,12 @@ public class Config {
* 设置 * 设置
* @param customCommands * @param customCommands
*/ */
public void setCustomCommands(HashMap<String, String> customCommands) { public void setCustomCommands(LinkedHashMap<String, String> customCommands) {
this.customCommands = customCommands; this.customCommands = customCommands;
} }
@Override @Override
public String toString() { public String toString() {
return "Config{apikey = " + apikey + ", accessKeyId = " + accessKeyId + ", accessKeySecret = " + accessKeySecret + ", owner = " + owner + ", modelNormal = " + modelNormal + ", modelCode = " + modelCode + ", bot = " + bot + ", timeout = " + timeout + ", timeCheck = " + timeCheck + ", customCommands = " + customCommands + "}"; return "Config{apikey = " + apikey + ", accessKeyId = " + accessKeyId + ", accessKeySecret = " + accessKeySecret + ", owner = " + owner + ", modelNormal = " + defaultModel + ", modelCode = " + ", bot = " + bot + ", timeout = " + timeout + ", timeCheck = " + timeCheck + ", customCommands = " + customCommands + "}";
} }
} }

View File

@@ -0,0 +1,56 @@
package plugin.pojo;
import com.zhipu.oapi.service.v4.model.ChatMessage;
import java.util.List;
public class UserCustomMessage {
private String command;
private List<ChatMessage> messages;
public UserCustomMessage() {
}
public UserCustomMessage(String command, List<ChatMessage> messages) {
this.command = command;
this.messages = messages;
}
/**
* 获取
* @return command
*/
public String getCommand() {
return command;
}
/**
* 设置
* @param command
*/
public void setCommand(String command) {
this.command = command;
}
/**
* 获取
* @return messages
*/
public List<ChatMessage> getMessages() {
return messages;
}
/**
* 设置
* @param messages
*/
public void setMessages(List<ChatMessage> messages) {
this.messages = messages;
}
@Override
public String toString() {
return "UserCustomMessage{command = " + command + ", messages = " + messages + "}";
}
}

View File

@@ -8,13 +8,17 @@ import com.zhipu.oapi.service.v4.model.ChatMessageRole;
import com.zhipu.oapi.service.v4.model.ModelApiResponse; import com.zhipu.oapi.service.v4.model.ModelApiResponse;
import plugin.constant.AIConstant; import plugin.constant.AIConstant;
import plugin.constant.ChatConstant; import plugin.constant.ChatConstant;
import plugin.constant.ConfigConstant;
import plugin.constant.MethodsConstant;
import plugin.pojo.Config; import plugin.pojo.Config;
import plugin.pojo.UserCustomMessage;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import static plugin.App.logger; import static plugin.utils.ConfigUtil.logger;
/** /**
* @author SLHAF * @author SLHAF
@@ -23,13 +27,18 @@ public class AIUtil {
private static final String APIKEY; private static final String APIKEY;
private static final ClientV4 CLIENT; private static final ClientV4 CLIENT;
private static final String REQUEST_ID_TEMPLATE = "ChatAI_InGroup_v2"; private static final String REQUEST_ID_TEMPLATE = "ChatAI_InGroup_v2";
private static final HashMap<Long, List<ChatMessage>> userMessagesNormal = new HashMap<>(); private static final HashMap<Long, List<ChatMessage>> userDefaultMessages = new HashMap<>();
private static final HashMap<Long, Long> userLatestTimeNormal = new HashMap<>(); private static final HashMap<Long, Long> userLatestTimeOfDefault = new HashMap<>();
private static String modelNormal; private static String defaultModel;
private static final HashMap<Long, List<ChatMessage>> userMessagesCode = new HashMap<>(); private static final HashMap<Long, List<UserCustomMessage>> userCustomMessages = new HashMap<>();
private static final HashMap<Long, Long> userLatestTimeCode = new HashMap<>(); private static final HashMap<Long, Long> userLatestTimeOfCustom = new HashMap<>();
private static String modelCode; /*private static String modelCode;*/
/**
* 结构:
* /c : glm-4-flush|预设内容
*/
private static HashMap<String, String> customCommands;
private static final Long CHECK_TIME, TIMEOUT; private static final Long CHECK_TIME, TIMEOUT;
@@ -37,8 +46,8 @@ public class AIUtil {
Config config = ConfigUtil.getConfig(); Config config = ConfigUtil.getConfig();
APIKEY = config.getApikey(); APIKEY = config.getApikey();
CLIENT = new ClientV4.Builder(APIKEY).build(); CLIENT = new ClientV4.Builder(APIKEY).build();
modelNormal = config.getModelNormal(); defaultModel = config.getDefaultModel();
modelCode = config.getModelCode(); customCommands = config.getCustomCommands();
CHECK_TIME = Long.valueOf(config.getTimeCheck().substring(1)); CHECK_TIME = Long.valueOf(config.getTimeCheck().substring(1));
TIMEOUT = Long.valueOf(config.getTimeout().substring(1)); TIMEOUT = Long.valueOf(config.getTimeout().substring(1));
new Thread(() -> { new Thread(() -> {
@@ -49,117 +58,120 @@ public class AIUtil {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
synchronized (userMessagesNormal) { if (!userLatestTimeOfDefault.isEmpty()) {
if (!userLatestTimeNormal.isEmpty()) {
//查看user最近时间如果超过30min则清理对应记录 //查看user最近时间如果超过30min则清理对应记录
userLatestTimeNormal.forEach((id, latestTime) -> { userLatestTimeOfDefault.forEach((id, latestTime) -> {
synchronized (userDefaultMessages.get(id)) {
Long currentTime = System.currentTimeMillis(); Long currentTime = System.currentTimeMillis();
if (currentTime - latestTime > TIMEOUT && userMessagesNormal.containsKey(id)) { if (currentTime - latestTime > TIMEOUT && userDefaultMessages.containsKey(id)) {
userMessagesNormal.remove(id); userDefaultMessages.remove(id);
logger.info("Normal记录清理:" + id); logger.info("default记录清理:" + id);
}
} }
}); });
} }
}
synchronized (userMessagesCode) {
if (!userLatestTimeCode.isEmpty()) { if (!userLatestTimeOfCustom.isEmpty()) {
//查看user最近时间如果超过30min则清理对应记录 //查看user最近时间如果超过30min则清理对应记录
userLatestTimeCode.forEach((id, latestTime) -> { userLatestTimeOfCustom.forEach((id, latestTime) -> {
synchronized (userCustomMessages.get(id)) {
Long currentTime = System.currentTimeMillis(); Long currentTime = System.currentTimeMillis();
if (currentTime - latestTime > 30 * 60 * 1000 && userMessagesCode.containsKey(id)) { if (currentTime - latestTime > 30 * 60 * 1000 && userCustomMessages.containsKey(id)) {
userMessagesCode.remove(id); userCustomMessages.remove(id);
logger.info("Code记录清理:" + id); logger.info("custom记录清理:" + id);
}
} }
}); });
} }
}
} }
}).start(); }).start();
logger.info("清理线程启动"); logger.info("清理线程启动");
logger.info("当前代码模型: " + modelCode); logger.info("当前默认聊天模型: " + defaultModel);
logger.info("当前聊天模型: " + modelNormal);
} }
private AIUtil() { private AIUtil() {
} }
public static String chatCode(Long id, String content, String url) { public static String customChat(Long id, String content, String url, String chatCommand) {
synchronized (userMessagesCode) { if (ChatConstant.CLEAR.equals(content.replace(ChatConstant.BLANK, ""))) {
if (ChatConstant.CLEAR.equals(content.replace(" ", ""))) { userCustomMessages.remove(id);
userMessagesCode.remove(id);
return "消息记录已清空"; return "消息记录已清空";
} else if (content.replace(" ", "").startsWith(ChatConstant.CHANGE_MODEL)) { } /*else if (content.replace(ChatConstant.BLANK, "").startsWith(ChatConstant.CHANGE_MODEL)) {
content = content.replace(" ", ""); content = content.replace(ChatConstant.BLANK, "");
modelCode = content.substring(4); modelCode = content.substring(4);
ConfigUtil.modelCodeChange(modelCode); ConfigUtil.modelCodeChange(modelCode);
return "聊天模型切换为: " + modelCode; return "聊天模型切换为: " + modelCode;
} else if (AIConstant.CURRENT_MODEL.equals(content.replace(" ", ""))) { } */ else if (AIConstant.CURRENT_MODEL.equals(content.replace(ChatConstant.BLANK, ""))) {
return "当前模型为: " + modelCode; String modelName = customCommands.get(chatCommand).split(ConfigConstant.CUSTOM_SPLIT)[0];
return "当前模型为: " + modelName;
} }
//查看本次id是否有记录存在 //查看本次id是否有记录存在
if (!userMessagesCode.containsKey(id)) { if (!userCustomMessages.containsKey(id)) {
//创建消息list //创建消息list
List<ChatMessage> chatMessage = new ArrayList<>(); List<ChatMessage> chatMessages = new ArrayList<>();
chatMessage.add(new ChatMessage(ChatMessageRole.SYSTEM.value(), "你是一位智能编程助手,你会为用户回答关于编程、代码、计算机方面的任何问题,并提供格式规范、可以执行、准确安全的代码,并在必要时提供详细的解释。 请用中文回答。")); if (!customCommands.get(chatCommand).split(ConfigConstant.CUSTOM_SPLIT)[1].equals(ConfigConstant.NULL)) {
userMessagesCode.put(id, chatMessage); ChatMessage customMessage = new ChatMessage(ChatMessageRole.SYSTEM.value(), customCommands.get(chatCommand).split(ConfigConstant.CUSTOM_SPLIT)[1]);
chatMessages.add(customMessage);
} }
return getChatResponse(id, content, url,modelCode, userMessagesCode, userLatestTimeCode); List<UserCustomMessage> userCustomMessageList = new ArrayList<>();
userCustomMessageList.add(new UserCustomMessage(chatCommand, chatMessages));
userCustomMessages.put(id, userCustomMessageList);
}
String modelName = customCommands.get(chatCommand).split(ConfigConstant.CUSTOM_SPLIT)[0];
synchronized (userCustomMessages.get(id)) {
return getChatResponse(id, content, url, modelName, userLatestTimeOfCustom, chatCommand);
} }
} }
public static String chatNormal(Long id, String content,String url) { public static String defaultChat(Long id, String content, String url) {
synchronized (userMessagesNormal) { if (ChatConstant.CLEAR.equals(content.replace(ChatConstant.BLANK, ""))) {
if (ChatConstant.CLEAR.equals(content.replace(" ", ""))) { userDefaultMessages.remove(id);
userMessagesNormal.remove(id);
return "消息记录已清空"; return "消息记录已清空";
} else if (content.replace(" ", "").startsWith(ChatConstant.CHANGE_MODEL)) { }else if (ChatConstant.CURRENT_MODEL.equals(content.replace(ChatConstant.BLANK, ""))) {
content = content.replace(" ", ""); return "当前模型为: " + defaultModel;
modelNormal = content.substring(4);
ConfigUtil.modelNormalChange(modelNormal);
return "聊天模型切换为: " + modelNormal;
} else if (ChatConstant.CHANGE_MODEL.equals(content.replace(" ", ""))) {
return "当前模型为: " + modelNormal;
} }
//查看本次id是否有记录存在 //查看本次id是否有记录存在
if (!userMessagesNormal.containsKey(id)) { if (!userDefaultMessages.containsKey(id)) {
//创建消息list //创建消息list
List<ChatMessage> chatMessage = new ArrayList<>(); List<ChatMessage> chatMessages = new ArrayList<>();
userMessagesNormal.put(id, chatMessage); if (customCommands.containsKey(ConfigConstant.DEFAULT) && !ConfigConstant.NULL.equals(customCommands.get(ConfigConstant.DEFAULT))) {
ChatMessage customMessage = new ChatMessage(ChatMessageRole.SYSTEM.value(), customCommands.get(ConfigConstant.DEFAULT));
chatMessages.add(customMessage);
} }
return getChatResponse(id, content, url,modelNormal, userMessagesNormal, userLatestTimeNormal); userDefaultMessages.put(id, chatMessages);
}
synchronized (userDefaultMessages.get(id)) {
return getChatResponse(id, content, url, defaultModel, userLatestTimeOfDefault, null);
} }
} }
public static String chatOnce(String content,String url) { public static String chatOnce(String content, String url) {
if (content.replace(" ", "").startsWith(ChatConstant.CHANGE_MODEL)) {
content = content.replace(" ", ""); if (AIConstant.CURRENT_MODEL.equals(content.replace(ChatConstant.BLANK, ""))) {
modelNormal = content.substring(4); return "当前模型为: " + defaultModel;
ConfigUtil.modelNormalChange(modelNormal);
return "代码模型切换为: " + modelNormal;
} else if (AIConstant.CURRENT_MODEL.equals(content.replace(" ", ""))) {
return "当前模型为: " + modelNormal;
} }
String result = ""; String result = "";
if(url != null){ if (url != null) {
if (!OCRUtil.isSupported){ if (!OCRUtil.isSupported) {
return "当前不支持文字识别请检查阿里云OCR相关配置。"; return "当前不支持文字识别请检查阿里云OCR相关配置。";
} else { } else {
String contentOfImage = OCRUtil.getContentOfImage(url); String contentOfImage = OCRUtil.getContentOfImage(url);
if (contentOfImage == null){ if (contentOfImage == null) {
result = "未识别出图片内容。"; result = "未识别出图片内容。";
}else if (AIConstant.ERROR.equals(contentOfImage)){ } else if (AIConstant.ERROR.equals(contentOfImage)) {
result = "识别图片内容出错,请查看控制台。"; result = "识别图片内容出错,请查看控制台。";
}else { } else {
content = content.replace("[图片]", "\r\n[" + contentOfImage + "]\r\n"); content = content.replace("[图片]", "\r\n[" + contentOfImage + "]\r\n");
} }
} }
} }
String requestId = String.format(REQUEST_ID_TEMPLATE, System.currentTimeMillis()); String requestId = REQUEST_ID_TEMPLATE + "_once_"+System.currentTimeMillis();
List<ChatMessage> messages = new ArrayList<>(); List<ChatMessage> messages = new ArrayList<>();
messages.add(new ChatMessage(ChatMessageRole.USER.value(), content)); messages.add(new ChatMessage(ChatMessageRole.USER.value(), content));
ChatCompletionRequest chatCompletionRequest = ChatCompletionRequest.builder() ChatCompletionRequest chatCompletionRequest = ChatCompletionRequest.builder()
.model(modelNormal) .model(defaultModel)
.stream(Boolean.FALSE) .stream(Boolean.FALSE)
.invokeMethod(Constants.invokeMethod) .invokeMethod(Constants.invokeMethod)
.messages(messages) .messages(messages)
@@ -174,43 +186,84 @@ public class AIUtil {
logger.warning("code: " + code); logger.warning("code: " + code);
logger.warning("ErrorCode:" + invokeModelApiResp.getData().getError().getCode()); logger.warning("ErrorCode:" + invokeModelApiResp.getData().getError().getCode());
logger.warning("msg:" + invokeModelApiResp.getData().getError().getMessage()); logger.warning("msg:" + invokeModelApiResp.getData().getError().getMessage());
return invokeModelApiResp.getMsg()+"\r\n<"+result+">"; return invokeModelApiResp.getMsg() + "\r\n<" + result + ">";
} }
} }
private static String getChatResponse(Long id, String content, String url,String model, HashMap<Long, List<ChatMessage>> userMessages, HashMap<Long, Long> userLatestTime) { /**
* 取得回复内容
* <br>chatMessages内容只有两个static变量只需根据传入的chatCommand是否为null进行判断
*
* @param id 聊天用户ID
* @param content 聊天用户发送的内容content已在Listener处进行处理
* @param url 获取到的图片url如果没有图片则为null
* @param model 本次对话所需的模型名称
* <br>当为userDefaultMessages时
* <br><code>
* <br> qq1 : [msg1,msg2,msg3]
* <br> qq2 : [msg1,msg2,msg3]
* <br></code>
* <br>当为userCustomMessages时
* <br><code>
* <br> qq1 : [{command1,[msg1.msg2,msg3]},{command2,[msg1,msg2,msg3]},{command3,[msg1,msg2,msg3]}]
* <br> qq2 : [{command1,[msg1.msg2,msg3]},{command2,[msg1,msg2,msg3]},{command3,[msg1,msg2,msg3]}]
* <br></code>
* @param userLatestTime 最近操作时间
* @param chatCommand
* @return 得到的模型响应内容
*/
private static String getChatResponse(Long id, String content, String url, String model, HashMap<Long, Long> userLatestTime, String chatCommand) {
userLatestTime.put(id, System.currentTimeMillis()); userLatestTime.put(id, System.currentTimeMillis());
String requestId = String.format(REQUEST_ID_TEMPLATE, System.currentTimeMillis()); String requestId = REQUEST_ID_TEMPLATE + "_"+ model + "_" + System.currentTimeMillis();
//处理url内容 //处理url内容
String result = ""; String result = "";
if(url != null){ if (url != null) {
if (!OCRUtil.isSupported){ if (!OCRUtil.isSupported) {
logger.warning("unSupportedOCR"); logger.warning("unSupportedOCR");
return "当前不支持文字识别请检查阿里云OCR相关配置。"; return "当前不支持文字识别请检查阿里云OCR相关配置。";
} else { } else {
String contentOfImage = OCRUtil.getContentOfImage(url); String contentOfImage = OCRUtil.getContentOfImage(url);
if (contentOfImage == null){ if (contentOfImage == null) {
result = "未识别出图片内容。"; result = "未识别出图片内容。";
}else if (AIConstant.ERROR.equals(contentOfImage)){ } else if (AIConstant.ERROR.equals(contentOfImage)) {
result = "识别图片内容出错,请查看控制台。"; result = "识别图片内容出错,请查看控制台。";
}else { } else {
content = content.replace("[图片]", "\r\n[" + contentOfImage + "]\r\n"); content = content.replace("[图片]", "\r\n[" + contentOfImage + "]\r\n");
} }
} }
} }
logger.info("final content:" + content); logger.info("final content:" + content);
//根据primaryUserMessages中的内容来定义userMessages
List<ChatMessage> chatMessages = null;
if (chatCommand == null) {
chatMessages = userDefaultMessages.get(id);
} else {
List<UserCustomMessage> userCustomMessageList = userCustomMessages.get(id);
for (UserCustomMessage userCustomMessage : userCustomMessageList) {
//在调用时已确保存在指令对应的消息记录
if (userCustomMessage.getCommand().equals(chatCommand)) {
chatMessages = userCustomMessage.getMessages();
break;
}
}
}
if (chatMessages == null) {
return "消息记录读取失败";
}
//添加消息 //添加消息
userMessages.get(id).add(new ChatMessage(ChatMessageRole.USER.value(), content)); chatMessages.add(new ChatMessage(ChatMessageRole.USER.value(), content));
//创建并发送请求 //创建并发送请求
ChatCompletionRequest chatCompletionRequest = ChatCompletionRequest.builder() ChatCompletionRequest chatCompletionRequest = ChatCompletionRequest.builder()
.model(model) .model(model)
.stream(Boolean.FALSE) .stream(Boolean.FALSE)
.invokeMethod(Constants.invokeMethod) .invokeMethod(Constants.invokeMethod)
.messages(userMessages.get(id)) .messages(chatMessages)
.requestId(requestId) .requestId(requestId)
.build(); .build();
@@ -219,13 +272,13 @@ public class AIUtil {
if (code == 200) { if (code == 200) {
printTokenInfo(invokeModelApiResp); printTokenInfo(invokeModelApiResp);
String response = invokeModelApiResp.getData().getChoices().get(0).getMessage().getContent().toString(); String response = invokeModelApiResp.getData().getChoices().get(0).getMessage().getContent().toString();
userMessages.get(id).add(new ChatMessage(ChatMessageRole.ASSISTANT.value(), response)); chatMessages.add(new ChatMessage(ChatMessageRole.ASSISTANT.value(), response));
return response; return response;
} else { } else {
logger.warning("code: " + code); logger.warning("code: " + code);
logger.warning("ErrorCode:" + invokeModelApiResp.getData().getError().getCode()); logger.warning("ErrorCode:" + invokeModelApiResp.getData().getError().getCode());
logger.warning("msg:" + invokeModelApiResp.getData().getError().getMessage()); logger.warning("msg:" + invokeModelApiResp.getData().getError().getMessage());
return invokeModelApiResp.getMsg()+"\r\n<"+result+">"; return invokeModelApiResp.getMsg() + "\r\n<" + result + ">";
} }
} }

View File

@@ -1,23 +1,27 @@
package plugin.utils; package plugin.utils;
import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.bean.BeanUtil;
import lombok.Getter; import lombok.extern.slf4j.Slf4j;
import net.mamoe.mirai.utils.LoggerAdapters;
import net.mamoe.mirai.utils.MiraiLogger;
import org.yaml.snakeyaml.DumperOptions; import org.yaml.snakeyaml.DumperOptions;
import org.yaml.snakeyaml.Yaml; import org.yaml.snakeyaml.Yaml;
import plugin.constant.ConfigConstant;
import plugin.pojo.Config; import plugin.pojo.Config;
import java.io.*; import java.io.*;
import java.util.HashMap; import java.util.LinkedHashMap;
import static plugin.App.logger;
/** /**
* @author SLHAF * @author SLHAF
*/ */
@Slf4j
public class ConfigUtil { public class ConfigUtil {
private static final String CONFIG_PATH = "./config/ChatAIinGroup/config.yaml"; private static final String CONFIG_PATH = "./config/ChatAIinGroup/config.yaml";
private static final Yaml yaml; private static final Yaml yaml;
private static Config config; private static Config config;
public static MiraiLogger logger = LoggerAdapters.asMiraiLogger(log);
private ConfigUtil() { private ConfigUtil() {
} }
@@ -45,14 +49,14 @@ public class ConfigUtil {
config.setAccessKeyId("your_ali_access_key_id"); config.setAccessKeyId("your_ali_access_key_id");
config.setAccessKeySecret("your_ali_access_key_secret"); config.setAccessKeySecret("your_ali_access_key_secret");
config.setOwner("your_bot_owner_qq_number(e.g. Q1145141919810)"); config.setOwner("your_bot_owner_qq_number(e.g. Q1145141919810)");
config.setModelNormal("glm-4-flash"); config.setDefaultModel("glm-4-flash");
config.setModelCode("glm-4-flash");
config.setBot("your_bot_qq_number(e.g. Q1145141919810)"); config.setBot("your_bot_qq_number(e.g. Q1145141919810)");
config.setTimeout("M3600000"); config.setTimeout("M3600000");
config.setTimeCheck("M60000"); config.setTimeCheck("M60000");
HashMap<String, String> commands = new HashMap<>(); LinkedHashMap<String, String> commands = new LinkedHashMap<>();
commands.put("/c ", "你是一位智能编程助手,你会为用户回答关于编程、代码、计算机方面的任何问题,并提供格式规范、可以执行、准确安全的代码,并在必要时提供详细的解释。 请用中文回答。"); commands.put("default","glm-4-flash|null");
commands.put("/example", "预设内容"); commands.put("/c ", "glm-4-flash|你是一位智能编程助手,你会为用户回答关于编程、代码、计算机方面的任何问题,并提供格式规范、可以执行、准确安全的代码,并在必要时提供详细的解释。 请用中文回答。");
commands.put("/example ", "模型名称|预设内容");
config.setCustomCommands(commands); config.setCustomCommands(commands);
dump(); dump();
logger.warning("配置文件创建成功,请关闭后进行配置"); logger.warning("配置文件创建成功,请关闭后进行配置");
@@ -78,18 +82,19 @@ public class ConfigUtil {
* *
* @param modelName 模型名称 * @param modelName 模型名称
*/ */
public static void modelNormalChange(String modelName) { public static void defaultModelChange(String modelName) {
try { try {
config.setModelNormal(modelName); config.setDefaultModel(modelName);
dump(); dump();
} catch (IOException e) { } catch (IOException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
} }
public static void modelCodeChange(String modelName) { public static void customModelChange(String command,String modelName) {
try { try {
config.setModelCode(modelName); String customContent = config.getCustomCommands().get(command).split(ConfigConstant.CUSTOM_SPLIT)[1];
config.getCustomCommands().put(command,modelName+ConfigConstant.CUSTOM_SPLIT+customContent);
dump(); dump();
} catch (IOException e) { } catch (IOException e) {
throw new RuntimeException(e); throw new RuntimeException(e);

View File

@@ -9,7 +9,8 @@ import com.aliyun.teautil.models.RuntimeOptions;
import plugin.pojo.Config; import plugin.pojo.Config;
import plugin.pojo.OCRDataInfo; import plugin.pojo.OCRDataInfo;
import static plugin.App.logger; import static plugin.utils.ConfigUtil.logger;
public class OCRUtil { public class OCRUtil {
private static Client client; private static Client client;

View File

@@ -10,8 +10,13 @@ import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicHeader; import org.apache.http.message.BasicHeader;
import org.apache.http.util.EntityUtils; import org.apache.http.util.EntityUtils;
import org.junit.Test; import org.junit.Test;
import plugin.App;
import plugin.utils.AIUtil;
import plugin.utils.ConfigUtil;
import java.io.IOException; import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
@@ -132,4 +137,15 @@ public class MyTest {
response.close(); response.close();
client.close(); client.close();
} }
@Test
public void mainTest() throws ClassNotFoundException, IOException {
ConfigUtil.load();
Long id = 2998813882L;
String content = "hello";
String chatCommand = "/c ";
String s = AIUtil.customChat(id, content, null, chatCommand);
System.out.println(s);
}
} }