mirror of
https://github.com/yangjian102621/geekai.git
synced 2025-09-17 16:56:38 +08:00
优化用户聊天记录显示
This commit is contained in:
parent
ebc2041e8a
commit
4e575d01db
@ -4,7 +4,7 @@
|
||||
|
||||
## TODOLIST
|
||||
|
||||
* [ ] 使用 level DB 保存用户聊天记录
|
||||
* [x] 使用 level DB 保存用户聊天记录
|
||||
* [x] 用户聊天鉴权,设置口令模式
|
||||
* [ ] 定期清理不在线的会话 sessionID 和聊天上下文记录
|
||||
* [x] 给 Token 设置调用次数
|
||||
|
@ -341,3 +341,25 @@ func (s *Server) GetChatHistoryHandle(c *gin.Context) {
|
||||
|
||||
c.JSON(http.StatusOK, types.BizVo{Code: types.Success, Data: messages})
|
||||
}
|
||||
|
||||
// ClearHistoryHandle 清空聊天记录
|
||||
func (s *Server) ClearHistoryHandle(c *gin.Context) {
|
||||
sessionId := c.GetHeader(types.TokenName)
|
||||
var data struct {
|
||||
Role string `json:"role"`
|
||||
}
|
||||
err := json.NewDecoder(c.Request.Body).Decode(&data)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusOK, types.BizVo{Code: types.Failed, Message: "Invalid args"})
|
||||
return
|
||||
}
|
||||
|
||||
session := s.ChatSession[sessionId]
|
||||
err = ClearChatHistory(session.Username, data.Role)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusOK, types.BizVo{Code: types.Failed, Message: "Failed to remove data from DB"})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, types.BizVo{Code: types.Success})
|
||||
}
|
||||
|
@ -291,6 +291,7 @@ func (s *Server) GetChatRoleListHandle(c *gin.Context) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, types.BizVo{Code: types.Success, Message: types.OkMsg, Data: res})
|
||||
}
|
||||
|
||||
|
@ -83,6 +83,7 @@ func (s *Server) Run(webRoot embed.FS, path string, debug bool) {
|
||||
engine.POST("/api/login", s.LoginHandle)
|
||||
engine.Any("/api/chat", s.ChatHandle)
|
||||
engine.POST("api/chat/history", s.GetChatHistoryHandle)
|
||||
engine.POST("api/chat/history/clear", s.ClearHistoryHandle)
|
||||
|
||||
engine.POST("/api/config/set", s.ConfigSetHandle)
|
||||
engine.GET("/api/config/chat-roles/get", s.GetChatRoleListHandle)
|
||||
@ -157,7 +158,7 @@ func corsMiddleware() gin.HandlerFunc {
|
||||
c.Header("Access-Control-Allow-Origin", origin)
|
||||
c.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE, UPDATE")
|
||||
//允许跨域设置可以返回其他子段,可以自定义字段
|
||||
c.Header("Access-Control-Allow-Headers", "Authorization, Content-Length, Content-Type, ChatGPT-Username")
|
||||
c.Header("Access-Control-Allow-Headers", "Authorization, Content-Length, Content-Type, ChatGPT-TOKEN")
|
||||
// 允许浏览器(客户端)可以解析的头部 (重要)
|
||||
c.Header("Access-Control-Expose-Headers", "Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers")
|
||||
//设置缓存时间
|
||||
|
@ -3,7 +3,7 @@
|
||||
<div id="container">
|
||||
<div class="tool-box">
|
||||
<el-image style="width: 24px; height: 24px" :src="logo"/>
|
||||
<el-button round>欢迎来到人工智能时代</el-button>
|
||||
<!-- <el-button round>WeChatGPT</el-button>-->
|
||||
<el-select v-model="role" class="chat-role"
|
||||
v-on:change="changeRole"
|
||||
placeholder="请选择对话角色">
|
||||
@ -14,6 +14,12 @@
|
||||
:value="item.key"
|
||||
/>
|
||||
</el-select>
|
||||
|
||||
<el-button type="danger" class="clear-history" size="small" circle @click="clearChatHistory">
|
||||
<el-icon>
|
||||
<Delete/>
|
||||
</el-icon>
|
||||
</el-button>
|
||||
</div>
|
||||
|
||||
<div class="chat-box" id="chat-box" :style="{height: chatBoxHeight+'px'}">
|
||||
@ -89,7 +95,7 @@ import ChatPrompt from "@/components/ChatPrompt.vue";
|
||||
import ChatReply from "@/components/ChatReply.vue";
|
||||
import {randString} from "@/utils/libs";
|
||||
import {ElMessage, ElMessageBox} from 'element-plus'
|
||||
import {Tools, Lock} from '@element-plus/icons-vue'
|
||||
import {Tools, Lock, Delete} from '@element-plus/icons-vue'
|
||||
import ConfigDialog from '@/components/ConfigDialog.vue'
|
||||
import {httpPost, httpGet} from "@/utils/http";
|
||||
import {getSessionId, setSessionId} from "@/utils/storage";
|
||||
@ -98,7 +104,7 @@ import 'highlight.js/styles/a11y-dark.css'
|
||||
|
||||
export default defineComponent({
|
||||
name: "XChat",
|
||||
components: {ChatPrompt, ChatReply, Tools, Lock, ConfigDialog},
|
||||
components: {ChatPrompt, ChatReply, Tools, Lock, Delete, ConfigDialog},
|
||||
data() {
|
||||
return {
|
||||
title: 'ChatGPT 控制台',
|
||||
@ -118,7 +124,7 @@ export default defineComponent({
|
||||
socket: null,
|
||||
toolBoxHeight: 61 + 42, // 工具框的高度
|
||||
inputBoxWidth: window.innerWidth - 20,
|
||||
sending: true,
|
||||
sending: false,
|
||||
loading: false
|
||||
}
|
||||
},
|
||||
@ -189,9 +195,6 @@ export default defineComponent({
|
||||
});
|
||||
|
||||
this.connect();
|
||||
|
||||
this.fetchChatHistory();
|
||||
|
||||
},
|
||||
|
||||
methods: {
|
||||
@ -203,13 +206,16 @@ export default defineComponent({
|
||||
socket.addEventListener('open', () => {
|
||||
// 获取聊天角色
|
||||
httpGet("/api/config/chat-roles/get").then((res) => {
|
||||
ElMessage.success('创建会话成功!');
|
||||
// ElMessage.success('创建会话成功!');
|
||||
this.chatRoles = res.data;
|
||||
this.loading = false
|
||||
}).catch(() => {
|
||||
ElMessage.error("获取聊天角色失败");
|
||||
})
|
||||
|
||||
// 加载聊天记录
|
||||
this.fetchChatHistory();
|
||||
|
||||
if (this.connectingMessageBox && typeof this.connectingMessageBox.close === 'function') {
|
||||
this.connectingMessageBox.close();
|
||||
this.connectingMessageBox = null;
|
||||
@ -303,16 +309,33 @@ export default defineComponent({
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
this.fetchChatHistory();
|
||||
},
|
||||
|
||||
// 从后端获取聊天历史记录
|
||||
fetchChatHistory: function () {
|
||||
httpPost("/api/chat/history", {role: this.role}).then((res) => {
|
||||
this.chatData = res.data
|
||||
}).catch((e) => {
|
||||
console.error(e.message)
|
||||
const data = res.data
|
||||
const md = require('markdown-it')();
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
if (data[i].type === "prompt") {
|
||||
this.chatData.push(data[i]);
|
||||
continue;
|
||||
}
|
||||
|
||||
data[i].content = md.render(data[i].content);
|
||||
this.chatData.push(data[i]);
|
||||
}
|
||||
|
||||
nextTick(() => {
|
||||
hl.configure({ignoreUnescapedHTML: true})
|
||||
const lines = document.querySelectorAll('.chat-line');
|
||||
const blocks = lines[lines.length - 1].querySelectorAll('pre code');
|
||||
blocks.forEach((block) => {
|
||||
hl.highlightElement(block)
|
||||
})
|
||||
})
|
||||
}).catch(() => {
|
||||
// console.error(e.message)
|
||||
})
|
||||
},
|
||||
|
||||
@ -390,6 +413,31 @@ export default defineComponent({
|
||||
if (e.keyCode === 13) {
|
||||
this.submitToken();
|
||||
}
|
||||
},
|
||||
|
||||
// 清空聊天记录
|
||||
clearChatHistory: function () {
|
||||
ElMessageBox.confirm(
|
||||
'确认要清空当前角色聊天历史记录吗?<br/>此操作不可以撤销!',
|
||||
'操作提示:',
|
||||
{
|
||||
confirmButtonText: '确认',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
dangerouslyUseHTMLString: true,
|
||||
showClose: true,
|
||||
closeOnClickModal: false,
|
||||
center: true,
|
||||
}
|
||||
).then(() => {
|
||||
httpPost("/api/chat/history/clear", {role: this.role}).then(() => {
|
||||
ElMessage.success("当前角色会话已清空");
|
||||
this.chatData = [];
|
||||
}).catch(() => {
|
||||
ElMessage.error("删除失败")
|
||||
})
|
||||
}).catch(() => {
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
@ -418,7 +466,7 @@ export default defineComponent({
|
||||
align-items center;
|
||||
|
||||
.el-select {
|
||||
max-width 150px;
|
||||
max-width 120px;
|
||||
}
|
||||
|
||||
.chat-role {
|
||||
@ -428,6 +476,10 @@ export default defineComponent({
|
||||
.el-image {
|
||||
margin-right 5px;
|
||||
}
|
||||
|
||||
.clear-history {
|
||||
margin-left 5px;
|
||||
}
|
||||
}
|
||||
|
||||
.chat-box {
|
||||
|
Loading…
Reference in New Issue
Block a user