the function to save user chat history is ready

This commit is contained in:
RockYang 2023-04-19 17:32:41 +08:00
parent 14a351b477
commit a13c1bc669
9 changed files with 190 additions and 68 deletions

View File

@ -61,18 +61,18 @@ func (s *Server) ChatHandle(c *gin.Context) {
return return
} }
logger.Info("Receive a message: ", string(message)) logger.Info("Receive a message: ", string(message))
//replyMessage(client, "当前 TOKEN 无效,请使用合法的 TOKEN 登录!", false) replyMessage(client, "当前 TOKEN 无效,请使用合法的 TOKEN 登录!", false)
//replyMessage(client, "![](images/wx.png)", true) //replyMessage(client, "![](images/wx.png)", true)
ctx, cancel := context.WithCancel(context.Background()) //ctx, cancel := context.WithCancel(context.Background())
s.ReqCancelFunc[sessionId] = cancel //s.ReqCancelFunc[sessionId] = cancel
// 回复消息 //// 回复消息
err = s.sendMessage(ctx, session, chatRole, string(message), client, false) //err = s.sendMessage(ctx, session, chatRole, string(message), client, false)
if err != nil { //if err != nil {
logger.Error(err) // logger.Error(err)
} else { //} else {
replyChunkMessage(client, types.WsMessage{Type: types.WsEnd, IsHelloMsg: false}) // replyChunkMessage(client, types.WsMessage{Type: types.WsEnd, IsHelloMsg: false})
logger.Info("回答完毕: " + string(message)) // logger.Info("回答完毕: " + string(message))
} //}
} }
}() }()

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

View File

@ -62,7 +62,7 @@ export default defineComponent({
.content { .content {
word-break break-word; word-break break-word;
padding: 5px 10px; padding: 6px 10px;
background-color: #98E165; background-color: #98E165;
color var(--content-color); color var(--content-color);
font-size: var(--content-font-size); font-size: var(--content-font-size);

View File

@ -97,7 +97,7 @@ export default defineComponent({
.content { .content {
min-height 20px; min-height 20px;
word-break break-word; word-break break-word;
padding: 8px 10px; padding: 6px 10px;
color var(--content-color) color var(--content-color)
background-color: #fff; background-color: #fff;
font-size: var(--content-font-size); font-size: var(--content-font-size);

View File

@ -34,7 +34,7 @@ const routes = [
}, },
{ {
name: 'free', path: '/free', component: ChatFree, meta: { name: 'free', path: '/free', component: ChatFree, meta: {
title: 'ChatGPT 通用免费版' title: '【文心一言】免费版'
} }
}, },
{ {

View File

@ -7,7 +7,8 @@ import Storage from 'good-storage'
*/ */
const SessionUserKey = 'LOGIN_USER'; const SessionUserKey = 'LOGIN_USER';
const ChatHistoryKey = "CHAT_HISTORY"; const ChatHistoryKey = 'CHAT_HISTORY';
const ChatListKey = 'CHAT_LIST';
export function getSessionId() { export function getSessionId() {
const user = getLoginUser(); const user = getLoginUser();
@ -55,8 +56,32 @@ export function appendChatHistory(chatId, message) {
// 获取指定会话的历史记录 // 获取指定会话的历史记录
export function getChatHistory(chatId) { export function getChatHistory(chatId) {
const history = Storage.get(ChatHistoryKey); const history = Storage.get(ChatHistoryKey);
if (history && history[chatId]) { if (!history) {
return history[chatId]; return null;
} }
return [];
return history[chatId] ? history[chatId] : null;
}
export function getChatList() {
return Storage.get(ChatListKey);
}
export function getChat(chatId) {
let chatList = Storage.get(ChatListKey);
if (!chatList) {
return null;
}
return chatList[chatId] ? chatList[chatId] : null;
}
export function setChat(chat) {
let chatList = Storage.get(ChatListKey);
if (!chatList) {
chatList = {};
}
chatList[chat.id] = chat;
Storage.set(ChatListKey, chatList);
} }

View File

@ -213,7 +213,7 @@ export default defineComponent({
this.activelyClose = true; this.activelyClose = true;
this.socket.close(); this.socket.close();
} }
// WebSocket // WebSocket
const sessionId = getSessionId(); const sessionId = getSessionId();
const socket = new WebSocket(process.env.VUE_APP_WS_HOST + `/api/chat?sessionId=${sessionId}&role=${this.role}`); const socket = new WebSocket(process.env.VUE_APP_WS_HOST + `/api/chat?sessionId=${sessionId}&role=${this.role}`);
@ -252,7 +252,6 @@ export default defineComponent({
id: randString(32), id: randString(32),
icon: this.replyIcon, icon: this.replyIcon,
content: "", content: "",
cursor: true
}); });
if (data['is_hello_msg'] !== true) { if (data['is_hello_msg'] !== true) {
this.canReGenerate = true; this.canReGenerate = true;

View File

@ -2,13 +2,21 @@
<div class="chat-free-page"> <div class="chat-free-page">
<div class="sidebar" id="sidebar"> <div class="sidebar" id="sidebar">
<nav> <nav>
<ul> <div class="new-chat" @click="newChat">
<li class="new-chat" @click="newChat"><a> <a>
<span class="icon"><el-icon><Plus/></el-icon></span> <span class="icon"><el-icon><Plus/></el-icon></span>
<span class="text">新建会话</span> <span class="text">新建会话</span>
<span class="btn" @click="toggleSidebar"><el-button size="small" type="info" circle><el-icon><CloseBold/></el-icon></el-button></span> <span class="btn" @click="toggleSidebar"><el-button size="small" type="info" circle><el-icon><CloseBold/></el-icon></el-button></span>
</a></li> </a>
<li v-for="chat in chatList" :key="chat.id"><a> </div>
<ul>
<!-- <li class="new-chat" @click="newChat"><a>-->
<!-- <span class="icon"><el-icon><Plus/></el-icon></span>-->
<!-- <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="chat in chatList" :key="chat.id" @click="changeChat(chat)" :class="chat.active ? 'active' : ''"><a>
<span class="icon"><el-icon><ChatRound/></el-icon></span> <span class="icon"><el-icon><ChatRound/></el-icon></span>
<span class="text" v-if="chat.edit"> <span class="text" v-if="chat.edit">
@ -47,7 +55,7 @@
:icon="chat.icon" :icon="chat.icon"
:content="chat.content"/> :content="chat.content"/>
<chat-reply v-else-if="chat.type==='reply'" <chat-reply v-else-if="chat.type==='reply'"
:icon="chat.icon" :icon="replyIcon"
:org-content="chat.orgContent" :org-content="chat.orgContent"
:content="chat.content"/> :content="chat.content"/>
</div> </div>
@ -146,7 +154,15 @@ import {httpGet, httpPost} from "@/utils/http";
import hl from "highlight.js"; import hl from "highlight.js";
import ChatReply from "@/components/ChatReply.vue"; import ChatReply from "@/components/ChatReply.vue";
import ChatPrompt from "@/components/ChatPrompt.vue"; import ChatPrompt from "@/components/ChatPrompt.vue";
import {getSessionId, getUserInfo, setLoginUser} from "@/utils/storage"; import {
setChat,
appendChatHistory,
getChatHistory,
getChatList,
getSessionId,
getUserInfo,
setLoginUser
} from "@/utils/storage";
import {ElMessage, ElMessageBox} from "element-plus"; import {ElMessage, ElMessageBox} from "element-plus";
import {isMobile, randString} from "@/utils/libs"; import {isMobile, randString} from "@/utils/libs";
import Clipboard from "clipboard"; import Clipboard from "clipboard";
@ -177,12 +193,13 @@ export default defineComponent({
userInfo: {}, userInfo: {},
showLoginDialog: false, showLoginDialog: false,
role: 'gpt', role: 'gpt',
replyIcon: 'images/avatar/gpt.png', // replyIcon: 'images/avatar/yi_yan.png', //
chatList: [], // chatList: [], //
tmpChatTitle: '', tmpChatTitle: '',
curOpt: '', // curOpt: '', //
curChat: null, // curChat: null, //
curPrompt: null, //
showStopGenerate: false, showStopGenerate: false,
showReGenerate: false, showReGenerate: false,
@ -202,8 +219,6 @@ export default defineComponent({
}, },
mounted() { mounted() {
this.fetchChatHistory();
const clipboard = new Clipboard('.copy-reply'); const clipboard = new Clipboard('.copy-reply');
clipboard.on('success', () => { clipboard.on('success', () => {
ElMessage.success('复制成功!'); ElMessage.success('复制成功!');
@ -229,7 +244,7 @@ export default defineComponent({
} }
}); });
this.connect(); this.newChat();
}, },
@ -256,7 +271,6 @@ export default defineComponent({
this.errorMessage.close(); // this.errorMessage.close(); //
} }
this.activelyClose = false; this.activelyClose = false;
// this.chatList.push(this.curChat);
// //
this.fetchChatHistory(); this.fetchChatHistory();
}); });
@ -273,7 +287,6 @@ export default defineComponent({
id: randString(32), id: randString(32),
icon: this.replyIcon, icon: this.replyIcon,
content: "", content: "",
cursor: true
}); });
if (data['is_hello_msg'] !== true) { if (data['is_hello_msg'] !== true) {
this.canReGenerate = true; this.canReGenerate = true;
@ -282,9 +295,19 @@ export default defineComponent({
this.sending = false; this.sending = false;
if (data['is_hello_msg'] !== true) { if (data['is_hello_msg'] !== true) {
this.showReGenerate = true; this.showReGenerate = true;
//
appendChatHistory(this.curChat.id, this.curPrompt);
appendChatHistory(this.curChat.id, {
type: "reply",
id: randString(32),
icon: this.replyIcon,
content: this.lineBuffer,
})
} }
this.showStopGenerate = false; this.showStopGenerate = false;
this.lineBuffer = ''; // this.lineBuffer = ''; //
} else { } else {
this.lineBuffer += data.content; this.lineBuffer += data.content;
this.chatData[this.chatData.length - 1]['orgContent'] = this.lineBuffer; this.chatData[this.chatData.length - 1]['orgContent'] = this.lineBuffer;
@ -313,7 +336,7 @@ export default defineComponent({
if (this.activelyClose) { // if (this.activelyClose) { //
return; return;
} }
// //
this.sending = true; this.sending = true;
this.checkSession(); this.checkSession();
@ -350,33 +373,34 @@ export default defineComponent({
// //
fetchChatHistory: function () { fetchChatHistory: function () {
httpPost("/api/chat/history", {role: this.role}).then((res) => { const chatList = getChatList();
if (this.chatData.length > 0) { // if (chatList) {
return this.chatList = chatList;
}
const data = res.data const list = getChatHistory(this.curChat.id);
const md = require('markdown-it')(); if (list) {
for (let i = 0; i < data.length; i++) { const md = require('markdown-it')();
if (data[i].type === "prompt") { for (let i = 0; i < list.length; i++) {
this.chatData.push(data[i]); if (list[i].type === "prompt") {
continue; this.chatData.push(list[i]);
continue;
}
list[i].orgContent = list[i].content;
list[i].content = md.render(list[i].content);
this.chatData.push(list[i]);
} }
data[i].orgContent = data[i].content;
data[i].content = md.render(data[i].content); nextTick(() => {
this.chatData.push(data[i]); hl.configure({ignoreUnescapedHTML: true})
const blocks = document.querySelector("#chat-box").querySelectorAll('pre code');
blocks.forEach((block) => {
hl.highlightElement(block)
})
})
} }
nextTick(() => {
hl.configure({ignoreUnescapedHTML: true}) }
const blocks = document.querySelector("#chat-box").querySelectorAll('pre code');
blocks.forEach((block) => {
hl.highlightElement(block)
})
})
}).catch(() => {
// console.error(e.message)
})
}, },
inputKeyDown: function (e) { inputKeyDown: function (e) {
@ -405,12 +429,13 @@ export default defineComponent({
} }
// //
this.chatData.push({ this.curPrompt = {
type: "prompt", type: "prompt",
id: randString(32), id: randString(32),
icon: 'images/avatar/user.png', icon: 'images/avatar/user.png',
content: this.inputValue content: this.inputValue
}); };
this.chatData.push(this.curPrompt);
this.sending = true; this.sending = true;
this.showStopGenerate = true; this.showStopGenerate = true;
@ -510,14 +535,25 @@ export default defineComponent({
// //
newChat: function () { newChat: function () {
//
if (this.curChat !== null) {
const chatHistory = getChatHistory(this.curChat.id);
if (chatHistory === null) {
return;
}
//
setChat(this.curChat);
}
this.curChat = { this.curChat = {
id: randString(32), id: randString(32),
edit: false, // edit: false, //
removing: false, // removing: false, //
title: '新会话 - ' + this.chatList.length active: false,
title: '新会话 - 0'
}; };
// this.chatData = [];
this.connect(); this.connect();
}, },
@ -533,6 +569,7 @@ export default defineComponent({
if (this.curOpt === 'edit') { if (this.curOpt === 'edit') {
chat.title = this.tmpChatTitle; chat.title = this.tmpChatTitle;
chat.edit = false; chat.edit = false;
setChat(chat)
} else if (this.curOpt === 'remove') { } else if (this.curOpt === 'remove') {
for (let i = 0; i < this.chatList.length; i++) { for (let i = 0; i < this.chatList.length; i++) {
if (this.chatList[i].id === chat.id) { if (this.chatList[i].id === chat.id) {
@ -551,8 +588,23 @@ export default defineComponent({
removeChat: function (chat) { removeChat: function (chat) {
chat.removing = true; chat.removing = true;
this.curOpt = 'remove'; this.curOpt = 'remove';
} },
//
changeChat: function (chat) {
if (this.curChat.id === chat.id) {
return;
}
this.curChat.active = false;
chat.active = true;
this.curChat = chat;
const chatHistory = getChatHistory(chat.id);
if (!chatHistory) {
return;
}
this.chatData = chatHistory;
}
} }
}) })
@ -574,10 +626,51 @@ export default defineComponent({
margin 0 margin 0
padding 0 padding 0
width 100% width 100%
height calc(100vh - 150px)
border 1px solid red;
overflow-y auto
.new-chat {
position fixed;
color: #ffffff
padding 10px;
cursor pointer
&:hover {
background-color #3E3F49
a {
.btn {
display block
background-color: #3E3F49;
}
}
}
a {
border: 1px solid #4A4B4D;
box-sizing: border-box;
border-radius 5px;
width 100%;
display flex;
padding 10px;
.btn {
display none
right -2px;
top -2px;
.el-icon {
margin-left 0;
color #ffffff
}
}
}
}
ul { ul {
list-style-type: none list-style-type: none
padding 5px padding 50px 5px 5px 5px
margin 0 margin 0
li { li {
@ -589,12 +682,12 @@ export default defineComponent({
border-radius 5px; border-radius 5px;
&:hover { &:hover {
background-color #2E2F39 background-color #3E3F49
a { a {
.btn { .btn {
display block display block
background-color: #282A32; background-color: #3E3F49;
} }
} }
} }
@ -647,7 +740,7 @@ export default defineComponent({
} }
li.active { li.active {
background-color #2E2F39 background-color #3E3F49
} }
li.new-chat { li.new-chat {
@ -669,6 +762,11 @@ export default defineComponent({
} }
} }
nav::-webkit-scrollbar {
width: 0;
height: 0;
}
} }
.main-content { .main-content {
@ -707,6 +805,7 @@ export default defineComponent({
justify-content flex-start justify-content flex-start
.chat-box { .chat-box {
width 100%;
padding: 10px; padding: 10px;
overflow-y: auto; overflow-y: auto;
height: calc(100vh - 80px); height: calc(100vh - 80px);

View File

@ -329,8 +329,7 @@ export default defineComponent({
type: "reply", type: "reply",
id: randString(32), id: randString(32),
icon: this.replyIcon, icon: this.replyIcon,
content: "", content: ""
cursor: true
}); });
if (data['is_hello_msg'] !== true) { if (data['is_hello_msg'] !== true) {
this.canReGenerate = true; this.canReGenerate = true;
@ -370,7 +369,7 @@ export default defineComponent({
if (this.activelyClose) { // if (this.activelyClose) { //
return; return;
} }
// //
this.sending = true; this.sending = true;
this.checkSession(); this.checkSession();