diff --git a/src/api/doc/space.ts b/src/api/doc/space.ts index 5985b3a..3dd52b7 100644 --- a/src/api/doc/space.ts +++ b/src/api/doc/space.ts @@ -128,4 +128,54 @@ export function doAiChat(_url:string,data: aiChatData,sig?:AbortSignal){ body: JSON.stringify(data) } ) +} +/** + * 通过userid获取记录列表 + * @requires userid + */ +export function getAiChatList(data:any){ + return request({ + url: '/aibot/chat/list', + method: 'post', + data: data + }); +} + +/** + * 获取单个会话 + * @requires userid + * @requires uuid + */ +export function getAiChat(data: any){ + return request({ + url: '/aibot/chat', + method: 'post', + data: data + }); +} + +/** + * 删除单个会话 + * @requires userid + * @requires uuid + */ +export function delAiChat(data: any){ + return request({ + url: '/aibot/chat/del', + method: 'post', + data: data + }); +} + +/** + * 更新会话 + * @requires userid + * @requires uuid + */ +export function setAiChat(data: any){ + return request({ + url: '/aibot/chat/update', + method: 'post', + data: data + }); } \ No newline at end of file diff --git a/src/views/doc/agent.vue b/src/views/doc/agent.vue index 21ece31..9a31a00 100644 --- a/src/views/doc/agent.vue +++ b/src/views/doc/agent.vue @@ -8,7 +8,7 @@ import { Promotion, Remove } from '@element-plus/icons-vue' -import { doAiTraining,doAiChat,aiChatData} from "@/api/doc/space" +import { doAiTraining,doAiChat,aiChatData,getAiChatList,getAiChat,setAiChat,delAiChat} from "@/api/doc/space" import {ElText,ElInput, ButtonInstance} from "element-plus"; import { VueMarkdown } from '@crazydos/vue-markdown' import rehypeRaw from 'rehype-raw' @@ -17,12 +17,14 @@ import remarkGfm from 'remark-gfm' //选中的咨询模式 const checkedModel = ref([]) //支持的模式 -const aimodels = [{name:'新对话',key:"context"}, {name:'联网检索',key:"onlineSearch"}, {name:'公司知识库',key:"useDataset"}] +const aimodels = [{name:'联网检索',key:"onlineSearch"}, {name:'公司知识库',key:"useDataset"}] const baseURL=import.meta.env.VITE_APP_BASE_API -const conversation=ref("") +const conversation=ref("") //当前会话的uuid const myquestion=ref('') const controller = ref(null) const inputState=ref(true) +const conversations=ref([]) +const centHoverItem=ref("") const interact_msg=ref<{ask:boolean,think:string,content:string}[]>([]) const props = withDefaults(defineProps<{ @@ -33,6 +35,20 @@ const props = withDefaults(defineProps<{ const respMsg=ref("") +//消息体 +interface message{ + ask:boolean, + think:string, + content:string +} +//会话记录 +interface chatRecord{ + uuid:string, + agentuuid:string, + brief:string, + messages:message[] +} + /* 中断函数,供按钮调用 */ function abortFetch() { if (controller.value) { @@ -44,18 +60,22 @@ function abortFetch() { async function onSendTextToAI(){ if(myquestion.value==="")return; inputState.value=false - interact_msg.value.push({ask:true,think:"", content:myquestion.value}) const params={ "onlineSearch":"否", "useDataset":"否" } for (let item of checkedModel.value){ - if(item==="context") conversation.value="" if(item==="onlineSearch") params.onlineSearch="是" if(item==="useDataset") params.useDataset="是" } - + if (conversation.value==""){ + //开启新对话 + interact_msg.value=[{ask:true,think:"", content:myquestion.value}] + }else{ + interact_msg.value.push({ask:true,think:"", content:myquestion.value}) + } + controller.value = new AbortController(); try{ const res= await doAiChat(`${baseURL}/aibot/agents/${props.agent.uuid}/chat`,{ @@ -63,7 +83,7 @@ async function onSendTextToAI(){ query:myquestion.value, response_mode:"streaming", conversation_id:conversation.value, - user:atob(props.userid), + user:atob(props.userid),//这里已经base64解析了 },controller.value.signal ) @@ -100,6 +120,7 @@ async function onSendTextToAI(){ if (e.name === 'AbortError') { console.log('用户手动中断') } + }finally{ inputState.value=true } @@ -112,13 +133,69 @@ async function onSendTextToAI(){ } respMsg.value="" + + setAiChat({ + "userid":atob(props.userid), + "uuid":conversation.value, + "brief":interact_msg.value[0].content, + "content":JSON.stringify(interact_msg.value) + }) } - + +//加载交流记录列表 +function loadKnownLibList(){ + //userid 需要 base64解析 + getAiChatList({"userid":atob(props.userid)}).then(resp=>{ + conversations.value=resp.data + }) +} + +//查看具体的历史记录 +function showChat(uuid:string){ + getAiChat({ + "userid":atob(props.userid), + "uuid":uuid + }).then(resp=>{ + interact_msg.value = JSON.parse(resp.data.content) + conversation.value=resp.data.uuid + }) +} + +//删除具体的历史记录 +function onDelChat(uuid:string){ + delAiChat({ + "userid":atob(props.userid), + "uuid":uuid + }).then(resp=>{ + loadKnownLibList() + }) +} + +function handleMouseEnter(row:any){ + if(centHoverItem.value==row.uuid) return; + centHoverItem.value=row.uuid +} +function handleMouseLeave(){ + centHoverItem.value="" +} + +function newContext(){ + inputState.value=true + interact_msg.value=[] + conversation.value="" + loadKnownLibList() //刷新对话列表 +} + +function resetContext(){ + interact_msg.value=[] + conversation.value="" + props.closefunc() +} + //渲染完页面再执行 onMounted(() => { - //loadKnownLibList() + loadKnownLibList() }); - @@ -167,9 +255,11 @@ onMounted(() => { height: 100%; width: 100%; } +.newquestion{ + bottom: 20px; +} .question_com{ position: fixed; - bottom: 25px; width: 52%; margin: 0 50px; text-align: center; @@ -182,6 +272,7 @@ onMounted(() => { } .reply_area{ display: flex; + min-height: 20%; flex-direction: column; margin: 15px 15px 110px 0px; } @@ -203,6 +294,27 @@ onMounted(() => { .dynamic-width-message-box-byme .el-message-box__message{ width: 100%; } +.action_menu{ + background-color: white; + padding: 10px 8px; + margin: 3px 14px 18px 0; + border-radius: 8px; + border: 1px solid #c9c6c6; +} +.list_item{ + display: flex; + background-color: #dddddd; + padding: 10px 8px; + margin: 3px 14px 3px 0; + overflow: hidden; + text-overflow: ellipsis; + border-radius: 8px; + text-wrap-mode: nowrap; + button{ + margin-left: auto; + } +} +