在进行 socket 连接前先关闭之前连接。实现新建会话功能。

This commit is contained in:
RockYang 2023-04-19 15:18:13 +08:00
parent 50ff591dbb
commit 14a351b477
8 changed files with 158 additions and 22 deletions

View File

@ -290,6 +290,17 @@ func (s *Server) RemoveUserHandle(c *gin.Context) {
// GetUserListHandle 获取用户列表
func (s *Server) GetUserListHandle(c *gin.Context) {
username := c.PostForm("username")
if username != "" {
user, err := GetUser(username)
if err != nil {
c.JSON(http.StatusOK, types.BizVo{Code: types.Failed, Message: "User not exists"})
} else {
c.JSON(http.StatusOK, types.BizVo{Code: types.Success, Message: types.OkMsg, Data: user})
}
return
}
c.JSON(http.StatusOK, types.BizVo{Code: types.Success, Message: types.OkMsg, Data: GetUsers()})
}

View File

@ -129,7 +129,7 @@ func (s *Server) Run(webRoot embed.FS, path string, debug bool) {
for {
for key, ctx := range s.ChatContexts {
// 清理超过 60min 没有更新,则表示为过期会话
if time.Now().Unix()-ctx.LastAccessTime > int64(s.Config.Chat.ChatContextExpireTime) {
if time.Now().Unix()-ctx.LastAccessTime >= int64(s.Config.Chat.ChatContextExpireTime) {
logger.Infof("清理会话上下文: %s", key)
delete(s.ChatContexts, key)
}

View File

@ -3,7 +3,6 @@ package utils
import (
"math/rand"
"strconv"
"strings"
"time"
)
@ -27,10 +26,6 @@ func Long2IP(ipInt int64) string {
return b0 + "." + b1 + "." + b2 + "." + b3
}
func IsBlank(value string) bool {
return len(strings.TrimSpace(value)) == 0
}
func ContainsStr(slice []string, item string) bool {
for _, e := range slice {
if e == item {

View File

@ -13,7 +13,7 @@
class="box-item"
effect="dark"
content="复制回答"
placement="top"
placement="bottom"
>
<el-button type="info" class="copy-reply" :data-clipboard-text="orgContent" plain>
<el-icon>

View File

@ -1,12 +1,13 @@
/* eslint-disable no-constant-condition */
import {dateFormat} from "@/utils/libs";
import Storage from 'good-storage'
/**
* storage handler
*/
const SessionUserKey = 'LOGIN_USER';
export const Global = {}
const ChatHistoryKey = "CHAT_HISTORY";
export function getSessionId() {
const user = getLoginUser();
@ -36,3 +37,26 @@ export function getUserInfo() {
}
return {}
}
// 追加历史记录
export function appendChatHistory(chatId, message) {
let history = Storage.get(ChatHistoryKey);
if (!history) {
history = {};
}
if (!history[chatId]) {
history[chatId] = [message];
} else {
history[chatId].push(message);
}
Storage.set(ChatHistoryKey, history);
}
// 获取指定会话的历史记录
export function getChatHistory(chatId) {
const history = Storage.get(ChatHistoryKey);
if (history && history[chatId]) {
return history[chatId];
}
return [];
}

View File

@ -208,6 +208,12 @@ export default defineComponent({
},
// socket
connect: function () {
//
if (this.socket !== null) {
this.activelyClose = true;
this.socket.close();
}
// WebSocket
const sessionId = getSessionId();
const socket = new WebSocket(process.env.VUE_APP_WS_HOST + `/api/chat?sessionId=${sessionId}&role=${this.role}`);
@ -226,6 +232,7 @@ export default defineComponent({
}
this.sending = false; //
this.activelyClose = false;
if (this.errorMessage !== null) {
this.errorMessage.close(); //
}
@ -282,6 +289,10 @@ export default defineComponent({
});
socket.addEventListener('close', () => {
if (this.activelyClose) { //
return;
}
//
this.sending = true;
this.checkSession();

View File

@ -8,13 +8,23 @@
<span class="text">新建会话</span>
<span class="btn" @click="toggleSidebar"><el-button size="small" type="info" circle><el-icon><CloseBold/></el-icon></el-button></span>
</a></li>
<li v-for="session in sessionList" :key="session.id"><a>
<li v-for="chat in chatList" :key="chat.id"><a>
<span class="icon"><el-icon><ChatRound/></el-icon></span>
<span class="text">{{ session.title }}</span>
<span class="btn">
<el-icon title="编辑"><Edit/></el-icon>
<el-icon title="删除会话"><Delete/></el-icon>
<span class="text" v-if="chat.edit">
<el-input v-model="tmpChatTitle" size="small" placeholder="请输入会话标题"/>
</span>
<span class="text" v-else>{{ chat.title }}</span>
<span class="btn btn-check" v-if="chat.edit || chat.removing">
<el-icon @click="confirm(chat)"><Check/></el-icon>
<el-icon @click="cancel(chat)"><Close/></el-icon>
</span>
<span class="btn" v-else>
<el-icon title="编辑" @click="editChatTitle(chat)"><Edit/></el-icon>
<el-icon title="删除会话" @click="removeChat(chat)"><Delete/></el-icon>
</span>
</a></li>
</ul>
@ -123,7 +133,7 @@
<script>
import {defineComponent, nextTick} from "vue"
import {
ChatRound,
ChatRound, Check, Close,
CloseBold,
Delete, Edit,
Fold,
@ -145,6 +155,8 @@ import Clipboard from "clipboard";
export default defineComponent({
name: 'ChatFree',
components: {
Close,
Check,
Edit,
Delete,
CloseBold,
@ -166,10 +178,11 @@ export default defineComponent({
showLoginDialog: false,
role: 'gpt',
replyIcon: 'images/avatar/gpt.png', //
sessionList: [{
id: randString(32),
title: '响应式页面布局代码'
}], //
chatList: [], //
tmpChatTitle: '',
curOpt: '', //
curChat: null, //
showStopGenerate: false,
showReGenerate: false,
@ -180,6 +193,7 @@ export default defineComponent({
lineBuffer: '', //
errorMessage: null, //
socket: null,
activelyClose: false, //
inputBoxWidth: 0,
sending: true,
loading: true,
@ -226,6 +240,12 @@ export default defineComponent({
},
// socket
connect: function () {
//
if (this.socket !== null) {
this.activelyClose = true;
this.socket.close();
}
// WebSocket
const sessionId = getSessionId();
const socket = new WebSocket(process.env.VUE_APP_WS_HOST + `/api/chat?sessionId=${sessionId}&role=${this.role}`);
@ -235,6 +255,8 @@ export default defineComponent({
if (this.errorMessage !== null) {
this.errorMessage.close(); //
}
this.activelyClose = false;
// this.chatList.push(this.curChat);
//
this.fetchChatHistory();
});
@ -288,6 +310,10 @@ export default defineComponent({
});
socket.addEventListener('close', () => {
if (this.activelyClose) { //
return;
}
//
this.sending = true;
this.checkSession();
@ -484,8 +510,50 @@ export default defineComponent({
//
newChat: function () {
this.curChat = {
id: randString(32),
edit: false, //
removing: false, //
title: '新会话 - ' + this.chatList.length
};
//
this.connect();
},
//
editChatTitle: function (chat) {
chat.edit = true;
this.curOpt = 'edit';
this.tmpChatTitle = chat.title;
},
//
confirm: function (chat) {
if (this.curOpt === 'edit') {
chat.title = this.tmpChatTitle;
chat.edit = false;
} else if (this.curOpt === 'remove') {
for (let i = 0; i < this.chatList.length; i++) {
if (this.chatList[i].id === chat.id) {
this.chatList.remove(i)
}
}
}
},
cancel: function (chat) {
chat.edit = false;
chat.removing = false;
},
//
removeChat: function (chat) {
chat.removing = true;
this.curOpt = 'remove';
}
}
})
</script>
@ -522,6 +590,13 @@ export default defineComponent({
&:hover {
background-color #2E2F39
a {
.btn {
display block
background-color: #282A32;
}
}
}
a {
@ -539,11 +614,13 @@ export default defineComponent({
font-size 14px;
padding-top 2px;
overflow hidden
white-space: nowrap;
text-overflow: ellipsis;
max-width 200px;
}
.btn {
//display none
display none
position absolute
right 0;
top 2px;
@ -558,8 +635,14 @@ export default defineComponent({
}
}
}
.btn-check {
.el-icon {
margin-left 10px;
font-size 18px;
}
}
}
}

View File

@ -238,6 +238,7 @@ export default defineComponent({
connectingMessageBox: null, //
errorMessage: null, //
socket: null,
activelyClose: false, //
mainWinHeight: 0, //
chatBoxHeight: 0, //
leftBoxHeight: 0,
@ -284,6 +285,12 @@ export default defineComponent({
},
// socket
connect: function () {
//
if (this.socket !== null) {
this.activelyClose = true;
this.socket.close();
}
// WebSocket
const sessionId = getSessionId();
const socket = new WebSocket(process.env.VUE_APP_WS_HOST + `/api/chat?sessionId=${sessionId}&role=${this.role}`);
@ -303,6 +310,7 @@ export default defineComponent({
}
this.sending = false; //
this.activelyClose = false;
if (this.errorMessage !== null) {
this.errorMessage.close(); //
}
@ -359,6 +367,10 @@ export default defineComponent({
});
socket.addEventListener('close', () => {
if (this.activelyClose) { //
return;
}
//
this.sending = true;
this.checkSession();