1
This commit is contained in:
63
src/main/java/plugin/App.java
Normal file
63
src/main/java/plugin/App.java
Normal file
@@ -0,0 +1,63 @@
|
||||
package plugin;
|
||||
|
||||
import net.mamoe.mirai.console.plugin.jvm.JavaPlugin;
|
||||
import net.mamoe.mirai.console.plugin.jvm.JvmPluginDescriptionBuilder;
|
||||
import net.mamoe.mirai.event.GlobalEventChannel;
|
||||
import net.mamoe.mirai.event.events.FriendMessageEvent;
|
||||
import net.mamoe.mirai.event.events.GroupMessageEvent;
|
||||
import net.mamoe.mirai.utils.MiraiLogger;
|
||||
import plugin.listener.UserMessageListener;
|
||||
import plugin.utils.ConfigUtil;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import static plugin.utils.ConfigUtil.config;
|
||||
|
||||
|
||||
public final class App extends JavaPlugin {
|
||||
public static final App INSTANCE = new App();
|
||||
public static MiraiLogger logger;
|
||||
private String owner, bot;
|
||||
|
||||
private App() {
|
||||
super(new JvmPluginDescriptionBuilder("com.plugin.chatAI-InGroup-v2", "0.1.0")
|
||||
.name("ChatAI-InGroup-v2")
|
||||
.author("SLHAF")
|
||||
.build());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
//加载配置
|
||||
try {
|
||||
logger = getLogger();
|
||||
ConfigUtil.load();
|
||||
owner = config.get("owner").substring(1);
|
||||
bot = config.get("bot").substring(1);
|
||||
|
||||
} catch (IOException | ClassNotFoundException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
getLogger().info("ChatAI-InGroup-v2 loaded!");
|
||||
|
||||
|
||||
//群聊监听器
|
||||
GlobalEventChannel.INSTANCE.filterIsInstance(GroupMessageEvent.class)
|
||||
.filter(event -> {
|
||||
String msg = event.getMessage().contentToString();
|
||||
return (msg.startsWith(".") && msg.length() != 1) || msg.startsWith("@"+bot) || msg.startsWith("/c ");
|
||||
}).registerListenerHost(new UserMessageListener());
|
||||
|
||||
//私聊监听器
|
||||
GlobalEventChannel.INSTANCE.filterIsInstance(FriendMessageEvent.class)
|
||||
.filter(event -> true)
|
||||
.registerListenerHost(new UserMessageListener());
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisable() {
|
||||
getLogger().info("ChatAI-InGroup-v2 disabled!");
|
||||
}
|
||||
}
|
||||
17
src/main/java/plugin/constant/AIConstant.java
Normal file
17
src/main/java/plugin/constant/AIConstant.java
Normal file
@@ -0,0 +1,17 @@
|
||||
package plugin.constant;
|
||||
|
||||
/**
|
||||
* @author SLHAF
|
||||
*/
|
||||
public class AIConstant {
|
||||
/**
|
||||
* 当前模型
|
||||
*/
|
||||
public static final String CURRENT_MODEL = "当前模型";
|
||||
|
||||
|
||||
/**
|
||||
* 错误结果
|
||||
*/
|
||||
public static final String ERROR = "ERROR";
|
||||
}
|
||||
47
src/main/java/plugin/constant/ChatConstant.java
Normal file
47
src/main/java/plugin/constant/ChatConstant.java
Normal file
@@ -0,0 +1,47 @@
|
||||
package plugin.constant;
|
||||
|
||||
/**
|
||||
* @author SLHAF
|
||||
*/
|
||||
public class ChatConstant {
|
||||
|
||||
/**
|
||||
* 匹配含有图片信息的消息
|
||||
*/
|
||||
public static final String MATCH_MESSAGE = ".*[mirai:image:(https?://[\\w./?&=]+)].*";
|
||||
|
||||
/**
|
||||
* 匹配图片信息
|
||||
*/
|
||||
public static final String MATCH_IMAGE = "\\[mirai:image:(.*?)]";
|
||||
|
||||
/**
|
||||
* 单次对话标志
|
||||
*/
|
||||
public static final String ONCE_MESSAGE_START = ".";
|
||||
|
||||
/**
|
||||
* 普通对话标志
|
||||
*/
|
||||
public static final String NORMAL_MESSAGE_START = "@";
|
||||
|
||||
/**
|
||||
* code对话标志
|
||||
*/
|
||||
public static final String CODE_MESSAGE_START = "/c ";
|
||||
|
||||
/**
|
||||
* 切换模型
|
||||
*/
|
||||
public static final String CHANGE_MODEL = "切换模型";
|
||||
|
||||
/**
|
||||
* 所有者
|
||||
*/
|
||||
public static final String OWNER = "owner";
|
||||
|
||||
/**
|
||||
* 清理消息
|
||||
*/
|
||||
public static final String CLEAR = "clear";
|
||||
}
|
||||
149
src/main/java/plugin/listener/UserMessageListener.java
Normal file
149
src/main/java/plugin/listener/UserMessageListener.java
Normal file
@@ -0,0 +1,149 @@
|
||||
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.utils.AIUtil;
|
||||
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import static plugin.App.logger;
|
||||
import static plugin.utils.ConfigUtil.config;
|
||||
|
||||
/**
|
||||
* @author SLHAF
|
||||
*/
|
||||
public class UserMessageListener extends SimpleListenerHost {
|
||||
|
||||
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.get(ChatConstant.OWNER).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.get(ChatConstant.OWNER).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);
|
||||
}
|
||||
}
|
||||
253
src/main/java/plugin/pojo/OCRDataInfo.java
Normal file
253
src/main/java/plugin/pojo/OCRDataInfo.java
Normal file
@@ -0,0 +1,253 @@
|
||||
package plugin.pojo;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class OCRDataInfo {
|
||||
|
||||
/**
|
||||
* algo_version
|
||||
*/
|
||||
private String algo_version;
|
||||
/**
|
||||
* 文字内容-段落
|
||||
*/
|
||||
private String content;
|
||||
/**
|
||||
* height
|
||||
*/
|
||||
private int height;
|
||||
/**
|
||||
* orgHeight
|
||||
*/
|
||||
private int orgHeight;
|
||||
/**
|
||||
* orgWidth
|
||||
*/
|
||||
private int orgWidth;
|
||||
/**
|
||||
* prism_version
|
||||
*/
|
||||
private String prism_version;
|
||||
/**
|
||||
* prism_wnum
|
||||
*/
|
||||
private int prism_wnum;
|
||||
/**
|
||||
* prism_wordsInfo
|
||||
*/
|
||||
private List<PrismWordsInfoBean> prism_wordsInfo;
|
||||
/**
|
||||
* width
|
||||
*/
|
||||
private int width;
|
||||
|
||||
public String getAlgo_version() {
|
||||
return algo_version;
|
||||
}
|
||||
|
||||
public void setAlgo_version(String algo_version) {
|
||||
this.algo_version = algo_version;
|
||||
}
|
||||
|
||||
public String getContent() {
|
||||
return content;
|
||||
}
|
||||
|
||||
public void setContent(String content) {
|
||||
this.content = content;
|
||||
}
|
||||
|
||||
public int getHeight() {
|
||||
return height;
|
||||
}
|
||||
|
||||
public void setHeight(int height) {
|
||||
this.height = height;
|
||||
}
|
||||
|
||||
public int getOrgHeight() {
|
||||
return orgHeight;
|
||||
}
|
||||
|
||||
public void setOrgHeight(int orgHeight) {
|
||||
this.orgHeight = orgHeight;
|
||||
}
|
||||
|
||||
public int getOrgWidth() {
|
||||
return orgWidth;
|
||||
}
|
||||
|
||||
public void setOrgWidth(int orgWidth) {
|
||||
this.orgWidth = orgWidth;
|
||||
}
|
||||
|
||||
public String getPrism_version() {
|
||||
return prism_version;
|
||||
}
|
||||
|
||||
public void setPrism_version(String prism_version) {
|
||||
this.prism_version = prism_version;
|
||||
}
|
||||
|
||||
public int getPrism_wnum() {
|
||||
return prism_wnum;
|
||||
}
|
||||
|
||||
public void setPrism_wnum(int prism_wnum) {
|
||||
this.prism_wnum = prism_wnum;
|
||||
}
|
||||
|
||||
public List<PrismWordsInfoBean> getPrism_wordsInfo() {
|
||||
return prism_wordsInfo;
|
||||
}
|
||||
|
||||
public void setPrism_wordsInfo(List<PrismWordsInfoBean> prism_wordsInfo) {
|
||||
this.prism_wordsInfo = prism_wordsInfo;
|
||||
}
|
||||
|
||||
public int getWidth() {
|
||||
return width;
|
||||
}
|
||||
|
||||
public void setWidth(int width) {
|
||||
this.width = width;
|
||||
}
|
||||
|
||||
public static class PrismWordsInfoBean {
|
||||
/**
|
||||
* angle
|
||||
*/
|
||||
private int angle;
|
||||
/**
|
||||
* direction
|
||||
*/
|
||||
private int direction;
|
||||
/**
|
||||
* height
|
||||
*/
|
||||
private int height;
|
||||
/**
|
||||
* pos
|
||||
*/
|
||||
private List<PosBean> pos;
|
||||
/**
|
||||
* prob
|
||||
*/
|
||||
private int prob;
|
||||
/**
|
||||
* width
|
||||
*/
|
||||
private int width;
|
||||
/**
|
||||
* 文字内容-行
|
||||
*/
|
||||
private String word;
|
||||
/**
|
||||
* x
|
||||
*/
|
||||
private int x;
|
||||
/**
|
||||
* y
|
||||
*/
|
||||
private int y;
|
||||
|
||||
public int getAngle() {
|
||||
return angle;
|
||||
}
|
||||
|
||||
public void setAngle(int angle) {
|
||||
this.angle = angle;
|
||||
}
|
||||
|
||||
public int getDirection() {
|
||||
return direction;
|
||||
}
|
||||
|
||||
public void setDirection(int direction) {
|
||||
this.direction = direction;
|
||||
}
|
||||
|
||||
public int getHeight() {
|
||||
return height;
|
||||
}
|
||||
|
||||
public void setHeight(int height) {
|
||||
this.height = height;
|
||||
}
|
||||
|
||||
public List<PosBean> getPos() {
|
||||
return pos;
|
||||
}
|
||||
|
||||
public void setPos(List<PosBean> pos) {
|
||||
this.pos = pos;
|
||||
}
|
||||
|
||||
public int getProb() {
|
||||
return prob;
|
||||
}
|
||||
|
||||
public void setProb(int prob) {
|
||||
this.prob = prob;
|
||||
}
|
||||
|
||||
public int getWidth() {
|
||||
return width;
|
||||
}
|
||||
|
||||
public void setWidth(int width) {
|
||||
this.width = width;
|
||||
}
|
||||
|
||||
public String getWord() {
|
||||
return word;
|
||||
}
|
||||
|
||||
public void setWord(String word) {
|
||||
this.word = word;
|
||||
}
|
||||
|
||||
public int getX() {
|
||||
return x;
|
||||
}
|
||||
|
||||
public void setX(int x) {
|
||||
this.x = x;
|
||||
}
|
||||
|
||||
public int getY() {
|
||||
return y;
|
||||
}
|
||||
|
||||
public void setY(int y) {
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
public static class PosBean {
|
||||
/**
|
||||
* x
|
||||
*/
|
||||
private int x;
|
||||
/**
|
||||
* y
|
||||
*/
|
||||
private int y;
|
||||
|
||||
public int getX() {
|
||||
return x;
|
||||
}
|
||||
|
||||
public void setX(int x) {
|
||||
this.x = x;
|
||||
}
|
||||
|
||||
public int getY() {
|
||||
return y;
|
||||
}
|
||||
|
||||
public void setY(int y) {
|
||||
this.y = y;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
240
src/main/java/plugin/utils/AIUtil.java
Normal file
240
src/main/java/plugin/utils/AIUtil.java
Normal file
@@ -0,0 +1,240 @@
|
||||
package plugin.utils;
|
||||
|
||||
import com.zhipu.oapi.ClientV4;
|
||||
import com.zhipu.oapi.Constants;
|
||||
import com.zhipu.oapi.service.v4.model.ChatCompletionRequest;
|
||||
import com.zhipu.oapi.service.v4.model.ChatMessage;
|
||||
import com.zhipu.oapi.service.v4.model.ChatMessageRole;
|
||||
import com.zhipu.oapi.service.v4.model.ModelApiResponse;
|
||||
import plugin.constant.AIConstant;
|
||||
import plugin.constant.ChatConstant;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
import static plugin.App.logger;
|
||||
import static plugin.utils.ConfigUtil.config;
|
||||
|
||||
/**
|
||||
* @author SLHAF
|
||||
*/
|
||||
public class AIUtil {
|
||||
private static final String apikey;
|
||||
private static final ClientV4 client;
|
||||
private static final String requestIdTemplate = "ChatAI_InGroup_v2";
|
||||
private static final HashMap<Long, List<ChatMessage>> userMessagesNormal = new HashMap<>();
|
||||
private static final HashMap<Long, Long> userLatestTimeNormal = new HashMap<>();
|
||||
private static String modelNormal;
|
||||
|
||||
private static final HashMap<Long, List<ChatMessage>> userMessagesCode = new HashMap<>();
|
||||
private static final HashMap<Long, Long> userLatestTimeCode = new HashMap<>();
|
||||
private static String modelCode;
|
||||
|
||||
private static final Long checkTime, timeout;
|
||||
|
||||
static {
|
||||
apikey = config.get("apikey");
|
||||
client = new ClientV4.Builder(apikey).build();
|
||||
modelNormal = config.get("model_normal");
|
||||
modelCode = config.get("model_code");
|
||||
checkTime = Long.valueOf(ConfigUtil.config.get("time_check").substring(1));
|
||||
timeout = Long.valueOf(config.get("timeout").substring(1));
|
||||
new Thread(() -> {
|
||||
while (true) {
|
||||
try {
|
||||
Thread.sleep(checkTime);
|
||||
} catch (InterruptedException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
synchronized (userMessagesNormal) {
|
||||
if (!userLatestTimeNormal.isEmpty()) {
|
||||
//查看user最近时间,如果超过30min,则清理对应记录
|
||||
userLatestTimeNormal.forEach((id, latestTime) -> {
|
||||
Long currentTime = System.currentTimeMillis();
|
||||
if (currentTime - latestTime > timeout && userMessagesNormal.containsKey(id)) {
|
||||
userMessagesNormal.remove(id);
|
||||
logger.info("Normal记录清理:" + id);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
synchronized (userMessagesCode) {
|
||||
if (!userLatestTimeCode.isEmpty()) {
|
||||
//查看user最近时间,如果超过30min,则清理对应记录
|
||||
userLatestTimeCode.forEach((id, latestTime) -> {
|
||||
Long currentTime = System.currentTimeMillis();
|
||||
if (currentTime - latestTime > 30 * 60 * 1000 && userMessagesCode.containsKey(id)) {
|
||||
userMessagesCode.remove(id);
|
||||
logger.info("Code记录清理:" + id);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}).start();
|
||||
logger.info("清理线程启动");
|
||||
logger.info("当前代码模型: " + modelCode);
|
||||
logger.info("当前聊天模型: " + modelNormal);
|
||||
}
|
||||
|
||||
private AIUtil() {
|
||||
}
|
||||
|
||||
public static String chatCode(Long id, String content, String url) {
|
||||
synchronized (userMessagesCode) {
|
||||
if (ChatConstant.CLEAR.equals(content.replace(" ", ""))) {
|
||||
userMessagesCode.remove(id);
|
||||
return "消息记录已清空";
|
||||
} else if (content.replace(" ", "").startsWith(ChatConstant.CHANGE_MODEL)) {
|
||||
content = content.replace(" ", "");
|
||||
modelCode = content.substring(4);
|
||||
ConfigUtil.modelCodeChange(modelCode);
|
||||
return "聊天模型切换为: " + modelCode;
|
||||
} else if (AIConstant.CURRENT_MODEL.equals(content.replace(" ", ""))) {
|
||||
return "当前模型为: " + modelCode;
|
||||
}
|
||||
//查看本次id是否有记录存在
|
||||
if (!userMessagesCode.containsKey(id)) {
|
||||
//创建消息list
|
||||
List<ChatMessage> chatMessage = new ArrayList<>();
|
||||
chatMessage.add(new ChatMessage(ChatMessageRole.SYSTEM.value(), "你是一位智能编程助手,你会为用户回答关于编程、代码、计算机方面的任何问题,并提供格式规范、可以执行、准确安全的代码,并在必要时提供详细的解释。 请用中文回答。"));
|
||||
userMessagesCode.put(id, chatMessage);
|
||||
}
|
||||
return getChatResponse(id, content, url,modelCode, userMessagesCode, userLatestTimeCode);
|
||||
}
|
||||
}
|
||||
|
||||
public static String chatNormal(Long id, String content,String url) {
|
||||
synchronized (userMessagesNormal) {
|
||||
if (ChatConstant.CLEAR.equals(content.replace(" ", ""))) {
|
||||
userMessagesNormal.remove(id);
|
||||
return "消息记录已清空";
|
||||
} else if (content.replace(" ", "").startsWith(ChatConstant.CHANGE_MODEL)) {
|
||||
content = content.replace(" ", "");
|
||||
modelNormal = content.substring(4);
|
||||
ConfigUtil.modelNormalChange(modelNormal);
|
||||
return "聊天模型切换为: " + modelNormal;
|
||||
} else if (ChatConstant.CHANGE_MODEL.equals(content.replace(" ", ""))) {
|
||||
return "当前模型为: " + modelNormal;
|
||||
}
|
||||
//查看本次id是否有记录存在
|
||||
if (!userMessagesNormal.containsKey(id)) {
|
||||
//创建消息list
|
||||
List<ChatMessage> chatMessage = new ArrayList<>();
|
||||
userMessagesNormal.put(id, chatMessage);
|
||||
}
|
||||
return getChatResponse(id, content, url,modelNormal, userMessagesNormal, userLatestTimeNormal);
|
||||
}
|
||||
}
|
||||
|
||||
public static String chatOnce(String content,String url) {
|
||||
if (content.replace(" ", "").startsWith(ChatConstant.CHANGE_MODEL)) {
|
||||
content = content.replace(" ", "");
|
||||
modelNormal = content.substring(4);
|
||||
ConfigUtil.modelNormalChange(modelNormal);
|
||||
return "代码模型切换为: " + modelNormal;
|
||||
} else if (AIConstant.CURRENT_MODEL.equals(content.replace(" ", ""))) {
|
||||
return "当前模型为: " + modelNormal;
|
||||
}
|
||||
String result = "";
|
||||
if(url != null){
|
||||
if (!OCRUtil.isSupported){
|
||||
return "当前不支持文字识别,请检查阿里云OCR相关配置。";
|
||||
} else {
|
||||
String contentOfImage = OCRUtil.getContentOfImage(url);
|
||||
if (contentOfImage == null){
|
||||
result = "未识别出图片内容。";
|
||||
}else if (AIConstant.ERROR.equals(contentOfImage)){
|
||||
result = "识别图片内容出错,请查看控制台。";
|
||||
}else {
|
||||
content = content.replace("[图片]", "\r\n[" + contentOfImage + "]\r\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
String requestId = String.format(requestIdTemplate, System.currentTimeMillis());
|
||||
List<ChatMessage> messages = new ArrayList<>();
|
||||
messages.add(new ChatMessage(ChatMessageRole.USER.value(), content));
|
||||
ChatCompletionRequest chatCompletionRequest = ChatCompletionRequest.builder()
|
||||
.model(modelNormal)
|
||||
.stream(Boolean.FALSE)
|
||||
.invokeMethod(Constants.invokeMethod)
|
||||
.messages(messages)
|
||||
.requestId(requestId)
|
||||
.build();
|
||||
ModelApiResponse invokeModelApiResp = client.invokeModelApi(chatCompletionRequest);
|
||||
int code = invokeModelApiResp.getCode();
|
||||
if (code == 200) {
|
||||
printTokenInfo(invokeModelApiResp);
|
||||
return invokeModelApiResp.getData().getChoices().get(0).getMessage().getContent().toString();
|
||||
} else {
|
||||
logger.warning("code: " + code);
|
||||
logger.warning("ErrorCode:" + invokeModelApiResp.getData().getError().getCode());
|
||||
logger.warning("msg:" + invokeModelApiResp.getData().getError().getMessage());
|
||||
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) {
|
||||
userLatestTime.put(id, System.currentTimeMillis());
|
||||
|
||||
String requestId = String.format(requestIdTemplate, System.currentTimeMillis());
|
||||
//处理url内容
|
||||
String result = "";
|
||||
if(url != null){
|
||||
if (!OCRUtil.isSupported){
|
||||
logger.warning("unSupportedOCR");
|
||||
return "当前不支持文字识别,请检查阿里云OCR相关配置。";
|
||||
} else {
|
||||
String contentOfImage = OCRUtil.getContentOfImage(url);
|
||||
if (contentOfImage == null){
|
||||
result = "未识别出图片内容。";
|
||||
}else if (AIConstant.ERROR.equals(contentOfImage)){
|
||||
result = "识别图片内容出错,请查看控制台。";
|
||||
}else {
|
||||
content = content.replace("[图片]", "\r\n[" + contentOfImage + "]\r\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
logger.info("final content:" + content);
|
||||
|
||||
//添加消息
|
||||
userMessages.get(id).add(new ChatMessage(ChatMessageRole.USER.value(), content));
|
||||
|
||||
//创建并发送请求
|
||||
ChatCompletionRequest chatCompletionRequest = ChatCompletionRequest.builder()
|
||||
.model(model)
|
||||
.stream(Boolean.FALSE)
|
||||
.invokeMethod(Constants.invokeMethod)
|
||||
.messages(userMessages.get(id))
|
||||
.requestId(requestId)
|
||||
.build();
|
||||
|
||||
ModelApiResponse invokeModelApiResp = client.invokeModelApi(chatCompletionRequest);
|
||||
int code = invokeModelApiResp.getCode();
|
||||
if (code == 200) {
|
||||
printTokenInfo(invokeModelApiResp);
|
||||
String response = invokeModelApiResp.getData().getChoices().get(0).getMessage().getContent().toString();
|
||||
userMessages.get(id).add(new ChatMessage(ChatMessageRole.ASSISTANT.value(), response));
|
||||
return response;
|
||||
} else {
|
||||
logger.warning("code: " + code);
|
||||
logger.warning("ErrorCode:" + invokeModelApiResp.getData().getError().getCode());
|
||||
logger.warning("msg:" + invokeModelApiResp.getData().getError().getMessage());
|
||||
return invokeModelApiResp.getMsg()+"\r\n<"+result+">";
|
||||
}
|
||||
}
|
||||
|
||||
private static void printTokenInfo(ModelApiResponse invokeModelApiResp) {
|
||||
int promptTokens = invokeModelApiResp.getData().getUsage().getPromptTokens();
|
||||
int completionTokens = invokeModelApiResp.getData().getUsage().getCompletionTokens();
|
||||
int totalTokens = invokeModelApiResp.getData().getUsage().getTotalTokens();
|
||||
logger.info("prompt_tokens: " + promptTokens);
|
||||
logger.info("completion_tokens: " + completionTokens);
|
||||
logger.info("total_tokens: " + totalTokens);
|
||||
}
|
||||
|
||||
}
|
||||
85
src/main/java/plugin/utils/ConfigUtil.java
Normal file
85
src/main/java/plugin/utils/ConfigUtil.java
Normal file
@@ -0,0 +1,85 @@
|
||||
package plugin.utils;
|
||||
|
||||
import org.yaml.snakeyaml.DumperOptions;
|
||||
import org.yaml.snakeyaml.Yaml;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.HashMap;
|
||||
|
||||
import static plugin.App.logger;
|
||||
|
||||
/**
|
||||
* @author SLHAF
|
||||
*/
|
||||
public class ConfigUtil {
|
||||
public static HashMap<String, String> config;
|
||||
private static final String CONFIG_PATH = "./config/ChatAIinGroup/config.yaml";
|
||||
private static final Yaml yaml;
|
||||
|
||||
private ConfigUtil() {
|
||||
}
|
||||
|
||||
static{
|
||||
DumperOptions options = new DumperOptions();
|
||||
options.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK);
|
||||
yaml = new Yaml(options);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查配置
|
||||
* @throws IOException 配置文件写入出错
|
||||
*/
|
||||
public static void load() throws IOException, ClassNotFoundException {
|
||||
//检查配置文件
|
||||
File file = new File(CONFIG_PATH);
|
||||
if (!file.exists()) {
|
||||
//创建配置文件
|
||||
file.getParentFile().mkdirs();
|
||||
file.createNewFile();
|
||||
FileWriter writer = new FileWriter(file);
|
||||
writer.write("apikey: \r\n");
|
||||
writer.write("accessKeyId: \r\n");
|
||||
writer.write("accessKeySecret: \r\n");
|
||||
writer.write("owner: \r\n");
|
||||
writer.write("model_normal: \r\n");
|
||||
writer.write("model_code: \r\n");
|
||||
writer.write("bot: \r\n");
|
||||
writer.write("timeout: M3600000\r\n");
|
||||
writer.write("time_check: M60000");
|
||||
writer.flush();
|
||||
writer.close();
|
||||
logger.warning("配置文件创建成功,请关闭后进行配置");
|
||||
System.exit(0);
|
||||
} else {
|
||||
//读取配置文件
|
||||
InputStream inputStream = new FileInputStream(CONFIG_PATH);
|
||||
config = yaml.load(inputStream);
|
||||
inputStream.close();
|
||||
logger.info(config.toString());
|
||||
logger.info("读取配置文件完毕");
|
||||
Class.forName("plugin.utils.AIUtil");
|
||||
Class.forName("plugin.utils.OCRUtil");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 配置改变(模型)
|
||||
* @param modelName 模型名称
|
||||
*/
|
||||
public static void modelNormalChange(String modelName) {
|
||||
try {
|
||||
config.put("model_normal", modelName);
|
||||
yaml.dump(config, new FileWriter(CONFIG_PATH));
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
public static void modelCodeChange(String modelName) {
|
||||
try {
|
||||
config.put("model_code", modelName);
|
||||
yaml.dump(config, new FileWriter(CONFIG_PATH));
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
83
src/main/java/plugin/utils/OCRUtil.java
Normal file
83
src/main/java/plugin/utils/OCRUtil.java
Normal file
@@ -0,0 +1,83 @@
|
||||
package plugin.utils;
|
||||
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.aliyun.ocr_api20210707.Client;
|
||||
import com.aliyun.ocr_api20210707.models.RecognizeAdvancedRequest;
|
||||
import com.aliyun.ocr_api20210707.models.RecognizeAdvancedResponse;
|
||||
import com.aliyun.tea.TeaException;
|
||||
import com.aliyun.teaopenapi.models.Config;
|
||||
import com.aliyun.teautil.models.RuntimeOptions;
|
||||
import plugin.pojo.OCRDataInfo;
|
||||
|
||||
import static plugin.App.logger;
|
||||
import static plugin.utils.ConfigUtil.config;
|
||||
|
||||
public class OCRUtil {
|
||||
private static Client client;
|
||||
public static boolean isSupported;
|
||||
|
||||
static {
|
||||
//读取密钥
|
||||
String accessKeyId = config.get("accessKeyId");
|
||||
String accessKeySecret = config.get("accessKeySecret");
|
||||
if (accessKeySecret == null || accessKeyId == null) {
|
||||
isSupported = false;
|
||||
logger.warning("未检测到阿里云OCR配置信息,图片文字识别将不可用。");
|
||||
} else {
|
||||
isSupported = true;
|
||||
Config config = new Config()
|
||||
.setAccessKeyId(accessKeyId)
|
||||
.setAccessKeySecret(accessKeySecret);
|
||||
config.endpoint = "ocr-api.cn-hangzhou.aliyuncs.com";
|
||||
try {
|
||||
client = new Client(config);
|
||||
} catch (Exception e) {
|
||||
logger.error("创建client出错");
|
||||
logger.error(e.getMessage());
|
||||
}
|
||||
logger.info("阿里云OCR已配置。");
|
||||
}
|
||||
}
|
||||
|
||||
public static String getContentOfImage(String url) {
|
||||
//设置请求信息
|
||||
RecognizeAdvancedRequest recognizeAdvancedRequest = new RecognizeAdvancedRequest()
|
||||
.setUrl(url).setNeedRotate(Boolean.TRUE)
|
||||
.setNeedRotate(Boolean.TRUE);
|
||||
|
||||
try {
|
||||
//发送请求并处理回应
|
||||
RecognizeAdvancedResponse response = client.recognizeAdvancedWithOptions(recognizeAdvancedRequest, new RuntimeOptions());
|
||||
OCRDataInfo ocrDataInfo = JSONUtil.toBean(response.getBody().getData(), OCRDataInfo.class);
|
||||
if (!ocrDataInfo.getContent().isEmpty()) {
|
||||
StringBuilder str = new StringBuilder();
|
||||
ocrDataInfo.getPrism_wordsInfo().forEach(prismWordsInfoBean -> {
|
||||
str.append(prismWordsInfoBean.getWord());
|
||||
if (!ocrDataInfo.getPrism_wordsInfo().get(ocrDataInfo.getPrism_wordsInfo().size() - 1).equals(prismWordsInfoBean)) {
|
||||
str.append("\r\n");
|
||||
}
|
||||
});
|
||||
return str.toString();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
} catch (TeaException error) {
|
||||
// 此处仅做打印展示,请谨慎对待异常处理,在工程项目中切勿直接忽略异常。
|
||||
// 错误 message
|
||||
logger.error(error.getMessage());
|
||||
// 诊断地址
|
||||
logger.error(error.getData().get("Recommend").toString());
|
||||
com.aliyun.teautil.Common.assertAsString(error.message);
|
||||
return "ERROR";
|
||||
} catch (Exception _error) {
|
||||
TeaException error = new TeaException(_error.getMessage(), _error);
|
||||
// 此处仅做打印展示,请谨慎对待异常处理,在工程项目中切勿直接忽略异常。
|
||||
// 错误 message
|
||||
logger.error(error.getMessage());
|
||||
// 诊断地址
|
||||
logger.error(error.getData().get("Recommend").toString());
|
||||
com.aliyun.teautil.Common.assertAsString(error.message);
|
||||
return "ERROR";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
plugin.App
|
||||
Reference in New Issue
Block a user