From 81b4cbbe35c87785518196affdad7642b6221b2e Mon Sep 17 00:00:00 2001
From: JEECG <445654970@qq.com>
Date: Thu, 13 Feb 2025 20:00:15 +0800
Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E9=97=AE=E9=A2=98=EF=BC=9A?=
=?UTF-8?q?=E7=BA=BF=E4=B8=8Aai=E5=8A=A9=E6=89=8B=E5=90=8E=E7=AB=AF?=
=?UTF-8?q?=E5=86=85=E5=AE=B9=E4=B8=80=E6=AC=A1=E6=80=A7=E8=BF=94=E5=9B=9E?=
=?UTF-8?q?=EF=BC=8C=E6=B6=88=E6=81=AF=E4=B8=8D=E6=98=BE=E7=A4=BA?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../OpenAISSEEventSourceListener.java | 63 ++++++++++--------
.../gpt/service/impl/ChatServiceImpl.java | 4 +-
.../jeecg/AiChat/components/chat.vue | 66 +++++++++++--------
3 files changed, 74 insertions(+), 59 deletions(-)
diff --git a/jeecg-boot/jeecg-module-demo/src/main/java/org/jeecg/modules/demo/gpt/listeners/OpenAISSEEventSourceListener.java b/jeecg-boot/jeecg-module-demo/src/main/java/org/jeecg/modules/demo/gpt/listeners/OpenAISSEEventSourceListener.java
index 97257e20..c2d0c1e1 100644
--- a/jeecg-boot/jeecg-module-demo/src/main/java/org/jeecg/modules/demo/gpt/listeners/OpenAISSEEventSourceListener.java
+++ b/jeecg-boot/jeecg-module-demo/src/main/java/org/jeecg/modules/demo/gpt/listeners/OpenAISSEEventSourceListener.java
@@ -17,6 +17,7 @@ import java.util.Objects;
import java.util.function.Consumer;
//update-begin---author:chenrui ---date:20240126 for:【QQYUN-7932】AI助手------------
+
/**
* OpenAI的SSE监听
* @author chenrui
@@ -49,7 +50,7 @@ public class OpenAISSEEventSourceListener extends EventSourceListener {
this.sseEmitter = sseEmitter;
}
- public OpenAISSEEventSourceListener(String topicId,SseEmitter sseEmitter){
+ public OpenAISSEEventSourceListener(String topicId, SseEmitter sseEmitter){
this.topicId = topicId;
this.sseEmitter = sseEmitter;
}
@@ -102,40 +103,44 @@ public class OpenAISSEEventSourceListener extends EventSourceListener {
try {
//update-begin---author:chenrui ---date:20250207 for:[QQYUN-11102/QQYUN-11109]兼容deepseek模型,支持think标签------------
// 兼容think标签
- Message delta = completionResponse.getChoices().get(0).getDelta();
- if (null != delta) {
- String content = delta.getContent();
- if("".equals(content)){
- isThinking = true;
- content = "> ";
- delta.setContent(content);
- }
- if("".equals(content)){
- isThinking = false;
- content = "\n\n";
- delta.setContent(content);
- }
- if (isThinking) {
- if (null != content && content.contains("\n")) {
- content = "\n> ";
+ //update-begin---author:chenrui ---date:20250210 for:判断空,防止反悔的内容为空报错.------------
+ if(null != completionResponse.getChoices()
+ && !completionResponse.getChoices().isEmpty()
+ && null != completionResponse.getChoices().get(0)) {
+ //update-end---author:chenrui ---date:20250210 for:判断空,防止反悔的内容为空报错.------------
+ Message delta = completionResponse.getChoices().get(0).getDelta();
+ if (null != delta) {
+ String content = delta.getContent();
+ if ("".equals(content)) {
+ isThinking = true;
+ content = "> ";
+ delta.setContent(content);
+ }
+ if ("".equals(content)) {
+ isThinking = false;
+ content = "\n\n";
delta.setContent(content);
}
- }else {
- // 响应消息体不记录思考过程
- messageContent += null == content ? "" : content;
+ if (isThinking) {
+ if (null != content && content.contains("\n")) {
+ content = "\n> ";
+ delta.setContent(content);
+ }
+ } else {
+ // 响应消息体不记录思考过程
+ messageContent += null == content ? "" : content;
+ }
+ log.info("ai-chat返回数据,发送给前端:" + content);
+ sseEmitter.send(SseEmitter.event()
+ .id(this.topicId)
+ .data(delta)
+ .reconnectTime(3000));
}
-
-
-
- log.info("ai-chat返回数据,发送给前端:" + content);
- sseEmitter.send(SseEmitter.event()
- .id(this.topicId)
- .data(delta)
- .reconnectTime(3000));
}
//update-end---author:chenrui ---date:20250207 for:[QQYUN-11102/QQYUN-11109]兼容deepseek模型,支持think标签------------
} catch (Exception e) {
- log.error(e.getMessage(),e);
+ log.error("ai-chat返回数据,发生异常"+e.getMessage(),e);
+ sseEmitter.completeWithError(e);
eventSource.cancel();
}
}
diff --git a/jeecg-boot/jeecg-module-demo/src/main/java/org/jeecg/modules/demo/gpt/service/impl/ChatServiceImpl.java b/jeecg-boot/jeecg-module-demo/src/main/java/org/jeecg/modules/demo/gpt/service/impl/ChatServiceImpl.java
index 09465465..c22ace48 100644
--- a/jeecg-boot/jeecg-module-demo/src/main/java/org/jeecg/modules/demo/gpt/service/impl/ChatServiceImpl.java
+++ b/jeecg-boot/jeecg-module-demo/src/main/java/org/jeecg/modules/demo/gpt/service/impl/ChatServiceImpl.java
@@ -104,6 +104,7 @@ public class ChatServiceImpl implements ChatService {
//超时回调
sseEmitter.onTimeout(() -> {
log.info("[{}]连接超时...................", uid);
+ LocalCache.CACHE.remove(uid);
});
//异常回调
sseEmitter.onError(
@@ -115,7 +116,7 @@ public class ChatServiceImpl implements ChatService {
.name("发生异常!")
.data(Message.builder().content("发生异常请重试!").build())
.reconnectTime(3000));
- LocalCache.CACHE.put(uid, sseEmitter);
+ LocalCache.CACHE.remove(uid);
} catch (IOException e) {
log.error(e.getMessage(),e);
}
@@ -179,6 +180,7 @@ public class ChatServiceImpl implements ChatService {
finalMsgHistory.add(tempMessage);
redisTemplate.opsForHash().put(cacheKey, CACHE_KEY_MSG_CONTEXT, JSONUtil.toJsonStr(finalMsgHistory));
});
+ log.info("话题:{},开始发送消息~~~", topicId);
ChatCompletion completion = ChatCompletion
.builder()
.messages(msgHistory)
diff --git a/jeecgboot-vue3/src/components/jeecg/AiChat/components/chat.vue b/jeecgboot-vue3/src/components/jeecg/AiChat/components/chat.vue
index 0f219ee9..c89dda22 100644
--- a/jeecgboot-vue3/src/components/jeecg/AiChat/components/chat.vue
+++ b/jeecgboot-vue3/src/components/jeecg/AiChat/components/chat.vue
@@ -153,6 +153,7 @@
import presetQuestion from './presetQuestion.vue';
import { DeleteOutlined, ExclamationCircleOutlined } from '@ant-design/icons-vue';
import { message, Modal, Tabs } from 'ant-design-vue';
+ import { isObject, isString } from '/@/utils/is';
import '../style/github-markdown.less';
import '../style/highlight.less';
import '../style/style.less';
@@ -250,40 +251,46 @@
// 当从事件源接收到数据时触发
evtSource.onmessage = function (e) {
const data = e.data;
- // console.log(e);
- if (data === '[DONE]') {
- updateChatSome(uuid, props.chatData.length - 1, { loading: false });
- scrollToBottom();
- handleStop();
- evtSource.close(); // 关闭连接
- } else {
- try {
- const _data = JSON.parse(data);
- const content = _data.content;
- if (content != undefined) {
- lastText += content;
- updateChat(uuid.value, props.chatData.length - 1, {
- dateTime: new Date().toLocaleString(),
- text: lastText,
- inversion: false,
- error: false,
- loading: true,
- conversationOptions: e.lastEventId == '[ERR]' ? null : { conversationId: data.conversationId, parentMessageId: e.lastEventId },
- requestOptions: { prompt: message, options: { ...options } },
- });
- scrollToBottom();
- } else {
+ let delay = 0;
+ setTimeout(() => {
+ if (data === '[DONE]') {
+ updateChatSome(uuid, props.chatData.length - 1, { loading: false });
+ scrollToBottom();
+ handleStop();
+ evtSource.close(); // 关闭连接
+ } else {
+ try {
+ const _data = JSON.parse(data);
+ const content = _data.content;
+ if (content != undefined) {
+ lastText += content;
+ updateChat(uuid.value, props.chatData.length - 1, {
+ dateTime: new Date().toLocaleString(),
+ text: lastText,
+ inversion: false,
+ error: false,
+ loading: true,
+ conversationOptions: e.lastEventId == '[ERR]' ? null : { conversationId: data.conversationId, parentMessageId: e.lastEventId },
+ requestOptions: { prompt: message, options: { ...options } },
+ });
+ scrollToBottom();
+ } else {
+ // updateChatSome(uuid.value, props.chatData.length - 1, { loading: false });
+ // scrollToBottom();
+ // handleStop();
+ }
+ } catch (error: any) {
+ console.log('ai 聊天:::', error);
+ if (isObject(error) && isString(error.message) && error.message.endsWith('is not valid JSON')) {
+ return;
+ }
updateChatSome(uuid.value, props.chatData.length - 1, { loading: false });
scrollToBottom();
handleStop();
+ evtSource.close(); // 关闭连接
}
- } catch (error) {
- updateChatSome(uuid.value, props.chatData.length - 1, { loading: false });
- scrollToBottom();
- handleStop();
- evtSource.close(); // 关闭连接
}
- }
+ }, delay);
};
// 与事件源的连接无法打开时触发
evtSource.onerror = function (e) {
@@ -347,6 +354,7 @@
};
// 停止响应
const handleStop = () => {
+ console.log('ai 聊天:::---停止响应');
if (loading.value) {
loading.value = false;
}