|
|
@ -6,14 +6,19 @@ |
|
|
<script lang="ts" setup> |
|
|
<script lang="ts" setup> |
|
|
import { |
|
|
import { |
|
|
Promotion, |
|
|
Promotion, |
|
|
Remove |
|
|
Remove, |
|
|
|
|
|
ArrowLeft, |
|
|
} from '@element-plus/icons-vue' |
|
|
} from '@element-plus/icons-vue' |
|
|
import { doAiTraining,doAiChat,aiChatData,getAiChatList,getAiChat,setAiChat,delAiChat} from "@/api/doc/space" |
|
|
import { userStror } from "@/utils/pinia/stores/modules/userOrders"; |
|
|
import {ElText,ElInput, ButtonInstance} from "element-plus"; |
|
|
import router from "@/utils/router"; |
|
|
|
|
|
import { doAiChat,getAiChatList,getAiChat,setAiChat,delAiChat,getAiagentList} from "@/api/doc/space" |
|
|
|
|
|
import {ElText,ElInput} from "element-plus"; |
|
|
import { VueMarkdown } from '@crazydos/vue-markdown' |
|
|
import { VueMarkdown } from '@crazydos/vue-markdown' |
|
|
import rehypeRaw from 'rehype-raw' |
|
|
import rehypeRaw from 'rehype-raw' |
|
|
import remarkGfm from 'remark-gfm' |
|
|
import remarkGfm from 'remark-gfm' |
|
|
|
|
|
|
|
|
|
|
|
const userStore = userStror(); |
|
|
|
|
|
const userid=ref("") |
|
|
//选中的咨询模式 |
|
|
//选中的咨询模式 |
|
|
const checkedModel = ref([]) |
|
|
const checkedModel = ref([]) |
|
|
//支持的模式 |
|
|
//支持的模式 |
|
|
@ -25,15 +30,11 @@ const controller = ref<AbortController | null>(null) |
|
|
const inputState=ref(true) |
|
|
const inputState=ref(true) |
|
|
const conversations=ref<chatRecord[]>([]) |
|
|
const conversations=ref<chatRecord[]>([]) |
|
|
const centHoverItem=ref("") |
|
|
const centHoverItem=ref("") |
|
|
|
|
|
|
|
|
const interact_msg=ref<{ask:boolean,think:string,content:string,docinfo?:any[]}[]>([]) |
|
|
const interact_msg=ref<{ask:boolean,think:string,content:string,docinfo?:any[]}[]>([]) |
|
|
const props = withDefaults(defineProps<{ |
|
|
const agent=ref<{name:string,uuid:string}>({name:"通用AI",uuid:import.meta.env.VITE_DEFAULT_AI_AGENT}) |
|
|
userid:string, |
|
|
const agentList=ref<{name:string,uuid:string}[]>([{name:"通用AI",uuid:import.meta.env.VITE_DEFAULT_AI_AGENT}]) |
|
|
closefunc:()=>void, |
|
|
|
|
|
agent:{model:boolean,name:string,uuid:string} |
|
|
|
|
|
}>(),{}) |
|
|
|
|
|
|
|
|
|
|
|
const respMsg=ref("") |
|
|
const respMsg=ref("") |
|
|
|
|
|
const drawerModel=ref(false) |
|
|
|
|
|
|
|
|
//消息体 |
|
|
//消息体 |
|
|
interface message{ |
|
|
interface message{ |
|
|
@ -78,12 +79,12 @@ async function onSendTextToAI(){ |
|
|
let docinfo:any=[] |
|
|
let docinfo:any=[] |
|
|
controller.value = new AbortController(); |
|
|
controller.value = new AbortController(); |
|
|
try{ |
|
|
try{ |
|
|
const res= await doAiChat(`${baseURL}/aibot/agents/${props.agent.uuid}/chat`,{ |
|
|
const res= await doAiChat(`${baseURL}/aibot/agents/${agent.value.uuid}/chat`,{ |
|
|
inputs: params, |
|
|
inputs: params, |
|
|
query:myquestion.value, |
|
|
query:myquestion.value, |
|
|
response_mode:"streaming", |
|
|
response_mode:"streaming", |
|
|
conversation_id:conversation.value, |
|
|
conversation_id:conversation.value, |
|
|
user:atob(props.userid),//这里已经base64解析了 |
|
|
user:userid.value,//这里已经base64解析了 |
|
|
},controller.value.signal |
|
|
},controller.value.signal |
|
|
) |
|
|
) |
|
|
|
|
|
|
|
|
@ -137,8 +138,9 @@ async function onSendTextToAI(){ |
|
|
|
|
|
|
|
|
respMsg.value="" |
|
|
respMsg.value="" |
|
|
setAiChat({ |
|
|
setAiChat({ |
|
|
"userid":atob(props.userid), |
|
|
"userid":userid.value, |
|
|
"uuid":conversation.value, |
|
|
"uuid":conversation.value, |
|
|
|
|
|
"agentuuid":agent.value.uuid, |
|
|
"brief":interact_msg.value[0].content, |
|
|
"brief":interact_msg.value[0].content, |
|
|
"content":JSON.stringify(interact_msg.value) |
|
|
"content":JSON.stringify(interact_msg.value) |
|
|
}) |
|
|
}) |
|
|
@ -147,26 +149,30 @@ async function onSendTextToAI(){ |
|
|
//加载交流记录列表 |
|
|
//加载交流记录列表 |
|
|
function loadKnownLibList(){ |
|
|
function loadKnownLibList(){ |
|
|
//userid 需要 base64解析 |
|
|
//userid 需要 base64解析 |
|
|
getAiChatList({"userid":atob(props.userid)}).then(resp=>{ |
|
|
getAiChatList({"userid":userid.value}).then(resp=>{ |
|
|
conversations.value=resp.data |
|
|
conversations.value=resp.data |
|
|
}) |
|
|
}) |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
//查看具体的历史记录 |
|
|
//查看具体的历史记录 |
|
|
function showChat(uuid:string){ |
|
|
function showChat(uuid:string){ |
|
|
|
|
|
drawerModel.value=false; |
|
|
getAiChat({ |
|
|
getAiChat({ |
|
|
"userid":atob(props.userid), |
|
|
"userid":userid.value, |
|
|
"uuid":uuid |
|
|
"uuid":uuid |
|
|
}).then(resp=>{ |
|
|
}).then(resp=>{ |
|
|
interact_msg.value = JSON.parse(resp.data.content) |
|
|
interact_msg.value = JSON.parse(resp.data.content) |
|
|
conversation.value=resp.data.uuid |
|
|
conversation.value=resp.data.uuid |
|
|
|
|
|
if(resp.data.agentuuid!=""){ |
|
|
|
|
|
agent.value={name:"会话",uuid:resp.data.agentuuid} |
|
|
|
|
|
} |
|
|
}) |
|
|
}) |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
//删除具体的历史记录 |
|
|
//删除具体的历史记录 |
|
|
function onDelChat(uuid:string){ |
|
|
function onDelChat(uuid:string){ |
|
|
delAiChat({ |
|
|
delAiChat({ |
|
|
"userid":atob(props.userid), |
|
|
"userid":userid.value, |
|
|
"uuid":uuid |
|
|
"uuid":uuid |
|
|
}).then(resp=>{ |
|
|
}).then(resp=>{ |
|
|
loadKnownLibList() |
|
|
loadKnownLibList() |
|
|
@ -182,10 +188,11 @@ function handleMouseLeave(){ |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
function newContext(){ |
|
|
function newContext(){ |
|
|
|
|
|
drawerModel.value=false; |
|
|
const c =conversations.value.find(c=>c.uuid==conversation.value) |
|
|
const c =conversations.value.find(c=>c.uuid==conversation.value) |
|
|
if(!c){ |
|
|
if(!c && interact_msg.value.length>0){ |
|
|
conversations.value.push({ |
|
|
conversations.value.push({ |
|
|
"agentuuid":props.agent.uuid, |
|
|
"agentuuid":agent.value.uuid, |
|
|
"uuid":conversation.value, |
|
|
"uuid":conversation.value, |
|
|
"brief":interact_msg.value[0].content, |
|
|
"brief":interact_msg.value[0].content, |
|
|
"messages":interact_msg.value |
|
|
"messages":interact_msg.value |
|
|
@ -201,43 +208,61 @@ function newContext(){ |
|
|
function resetContext(){ |
|
|
function resetContext(){ |
|
|
interact_msg.value=[] |
|
|
interact_msg.value=[] |
|
|
conversation.value="" |
|
|
conversation.value="" |
|
|
props.closefunc() |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
//处理ai返回的引用信息 |
|
|
//处理ai返回的引用信息 |
|
|
function formatRefContent(content:string){ |
|
|
function formatRefContent(content:string){ |
|
|
let result=content.replaceAll(/"/g,'') |
|
|
let result=content.replace(/"/g,'') |
|
|
result=result.replaceAll(/Unnamed: /g,' ') |
|
|
result=result.replace(/Unnamed: /g,' ') |
|
|
return result |
|
|
return result |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
//渲染完页面再执行 |
|
|
//渲染完页面再执行 |
|
|
onMounted(() => { |
|
|
onMounted(() => { |
|
|
|
|
|
if(userStore.userInfoCont == ""){ |
|
|
|
|
|
userStore.getInfo().then(()=>{ |
|
|
|
|
|
userid.value="p0"+userStore.userInfoCont.userId; |
|
|
|
|
|
}) |
|
|
|
|
|
}else{ |
|
|
|
|
|
userid.value="p0"+userStore.userInfoCont.userId; |
|
|
|
|
|
} |
|
|
|
|
|
getAiagentList().then(resp=>{ |
|
|
|
|
|
agentList.value.push(...resp.data) |
|
|
|
|
|
}) |
|
|
|
|
|
|
|
|
loadKnownLibList() |
|
|
loadKnownLibList() |
|
|
}); |
|
|
}); |
|
|
</script> |
|
|
</script> |
|
|
|
|
|
|
|
|
<template> |
|
|
<template> |
|
|
<el-drawer |
|
|
<el-drawer |
|
|
:model-value="agent.model" |
|
|
:model-value="drawerModel" |
|
|
:title="agent.name+' : 知识库'" |
|
|
:title="agent.name+' : 知识库'" |
|
|
direction="rtl" |
|
|
direction="ltr" |
|
|
size="80%" |
|
|
size="86%" |
|
|
@close="resetContext" |
|
|
@close="drawerModel=false;" |
|
|
:style="{padding:'17px',backgroundColor:'#f3f3f3'}"> |
|
|
> |
|
|
<div style="display:grid;grid-template-columns:1fr 4fr; width: 100%;height: 100%;"> |
|
|
<div style="overflow-y: auto;padding: 8px;"> |
|
|
<div style="overflow-y: auto;"> |
|
|
|
|
|
<ul> |
|
|
<ul> |
|
|
<li class="action_menu" @click="newContext"> |
|
|
<li class="action_menu" @click="newContext"> |
|
|
【新建会话】 |
|
|
【新建会话】 |
|
|
</li> |
|
|
</li> |
|
|
<li class="list_item" v-for="item in conversations" @mouseover="handleMouseEnter(item)" @mouseleave="handleMouseLeave()" @click="showChat(item.uuid)"> |
|
|
<li class="agent-item" v-for="ag in agentList" @click="agent=ag;newContext()"> |
|
|
|
|
|
<el-icon><Star /></el-icon> <span>{{ ag.name }}智能体</span> |
|
|
|
|
|
</li> |
|
|
|
|
|
<span><el-icon><Clock /></el-icon> 历史会话</span> |
|
|
|
|
|
<li class="list_item" v-for="item in conversations" @click="showChat(item.uuid)"> |
|
|
<span>{{ item.brief }}</span> |
|
|
<span>{{ item.brief }}</span> |
|
|
<el-button v-show="centHoverItem == item.uuid" icon="Delete" size="small" circle @click="(e)=>{e.stopPropagation();onDelChat(item.uuid)}"></el-button> |
|
|
<el-button icon="Delete" size="small" circle @click="(e)=>{e.stopPropagation();onDelChat(item.uuid)}"></el-button> |
|
|
</li> |
|
|
</li> |
|
|
</ul> |
|
|
</ul> |
|
|
</div> |
|
|
</div> |
|
|
<div style="position: relative;background: white;overflow-y: auto;"> |
|
|
</el-drawer> |
|
|
|
|
|
<div class="navBtn"> |
|
|
|
|
|
<el-button type="text" :icon="ArrowLeft" @click="router.back()"> 返回</el-button> |
|
|
|
|
|
<el-button icon="expand" size="small" @click="drawerModel=true;"></el-button> |
|
|
|
|
|
</div> |
|
|
|
|
|
<div class="app_container"> |
|
|
<div class="reply_area" > |
|
|
<div class="reply_area" > |
|
|
<template v-for="msg of interact_msg"> |
|
|
<template v-for="msg of interact_msg"> |
|
|
<el-text v-if="msg.ask" class="t_ask" >{{ msg.content }}</el-text> |
|
|
<el-text v-if="msg.ask" class="t_ask" >{{ msg.content }}</el-text> |
|
|
@ -259,51 +284,52 @@ onMounted(() => { |
|
|
<VueMarkdown :markdown="respMsg" :rehype-plugins="[rehypeRaw]" class="t_resp"></VueMarkdown> |
|
|
<VueMarkdown :markdown="respMsg" :rehype-plugins="[rehypeRaw]" class="t_resp"></VueMarkdown> |
|
|
</div> |
|
|
</div> |
|
|
<div class="question_com" :class="{newquestion:conversation!='' || !inputState}"> |
|
|
<div class="question_com" :class="{newquestion:conversation!='' || !inputState}"> |
|
|
<h1 v-show="conversation =='' && inputState" style="font-size: 56px;margin: 10px;">恒信高科AI平台</h1> |
|
|
<h1 v-show="conversation =='' && inputState" style="font-size: 32px;margin: 10px;">恒信高科AI平台</h1> |
|
|
<el-checkbox-group v-model="checkedModel" style="display:flex; margin-bottom: 10px;"> |
|
|
<el-checkbox-group v-model="checkedModel" style="display:flex; margin-bottom: 10px;"> |
|
|
<el-checkbox-button v-for="mod in aimodels" :value="mod.key"> |
|
|
<el-checkbox-button v-for="mod in aimodels" :value="mod.key"> |
|
|
{{ mod.name }} |
|
|
{{ mod.name }} |
|
|
</el-checkbox-button> |
|
|
</el-checkbox-button> |
|
|
</el-checkbox-group> |
|
|
</el-checkbox-group> |
|
|
|
|
|
|
|
|
<el-input placeholder="问灵犀..." v-model="myquestion" input-style="border-radius: 20px;" |
|
|
<el-input placeholder="问灵犀..." v-model="myquestion" input-style="border-radius: 18px;" |
|
|
resize="none" :autosize="{minRows: 4}" type="textarea" /> |
|
|
resize="none" :autosize="{minRows: 4}" type="textarea" /> |
|
|
<el-button :style="{display :inputState ? '':'none'}" type="primary" :icon="Promotion" circle @click="onSendTextToAI"/> |
|
|
<el-button :style="{display :inputState ? '':'none'}" type="primary" :icon="Promotion" circle @click="onSendTextToAI"/> |
|
|
<el-button :style="{display :inputState ? 'none':''}" type="primary" :icon="Remove" circle @click="abortFetch"/> |
|
|
<el-button :style="{display :inputState ? 'none':''}" type="primary" :icon="Remove" circle @click="abortFetch"/> |
|
|
<span>内容由 AI 生成,请仔细甄别</span> |
|
|
<span>内容由 AI 生成,请仔细甄别</span> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
|
|
|
</el-drawer> |
|
|
|
|
|
</template> |
|
|
</template> |
|
|
|
|
|
|
|
|
<style lang="scss" scoped> |
|
|
<style lang="scss" scoped> |
|
|
.app_container { |
|
|
.app_container { |
|
|
padding: 10px 30px 0px 30px; |
|
|
padding: 10px; |
|
|
height: 100%; |
|
|
height: 100%; |
|
|
width: 100%; |
|
|
width: 100%; |
|
|
|
|
|
background-color: white; |
|
|
|
|
|
} |
|
|
|
|
|
.navBtn{ |
|
|
|
|
|
margin: 5px; |
|
|
|
|
|
position: fixed; |
|
|
} |
|
|
} |
|
|
.newquestion{ |
|
|
.newquestion{ |
|
|
bottom: 20px; |
|
|
bottom: 20px; |
|
|
} |
|
|
} |
|
|
.question_com{ |
|
|
.question_com{ |
|
|
position: fixed; |
|
|
position: fixed; |
|
|
width: 52%; |
|
|
padding: 0 13px; |
|
|
margin: 0 50px; |
|
|
|
|
|
text-align: center; |
|
|
text-align: center; |
|
|
display: block; |
|
|
display: block; |
|
|
button{ |
|
|
button{ |
|
|
position: absolute; |
|
|
position: absolute; |
|
|
bottom: 25px; |
|
|
bottom: 27px; |
|
|
right: 5px; |
|
|
right: 20px; |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
.reply_area{ |
|
|
.reply_area{ |
|
|
display: flex; |
|
|
display: flex; |
|
|
min-height: 20%; |
|
|
min-height: 20%; |
|
|
flex-direction: column; |
|
|
flex-direction: column; |
|
|
margin: 15px 15px 110px 0px; |
|
|
margin: 15px 15px 110px 15px; |
|
|
} |
|
|
} |
|
|
.t_ask{ |
|
|
.t_ask{ |
|
|
align-self: end; |
|
|
align-self: end; |
|
|
@ -311,13 +337,11 @@ onMounted(() => { |
|
|
background-color: rgb(188 211 241); |
|
|
background-color: rgb(188 211 241); |
|
|
padding: 0 30px; |
|
|
padding: 0 30px; |
|
|
border-radius:10px; |
|
|
border-radius:10px; |
|
|
margin: 15px; |
|
|
|
|
|
} |
|
|
} |
|
|
.t_resp{ |
|
|
.t_resp{ |
|
|
align-self: start; |
|
|
align-self: start; |
|
|
line-height: 30px; |
|
|
line-height: 23px; |
|
|
margin: 20px 33px; |
|
|
font-size: 13px; |
|
|
font-size: 16px; |
|
|
|
|
|
color: black; |
|
|
color: black; |
|
|
} |
|
|
} |
|
|
.dynamic-width-message-box-byme .el-message-box__message{ |
|
|
.dynamic-width-message-box-byme .el-message-box__message{ |
|
|
@ -330,11 +354,16 @@ onMounted(() => { |
|
|
border-radius: 8px; |
|
|
border-radius: 8px; |
|
|
border: 1px solid #c9c6c6; |
|
|
border: 1px solid #c9c6c6; |
|
|
} |
|
|
} |
|
|
|
|
|
.agent-item{ |
|
|
|
|
|
padding: 4px 8px; |
|
|
|
|
|
margin: 3px 14px 3px 0; |
|
|
|
|
|
border-radius: 8px; |
|
|
|
|
|
} |
|
|
.list_item{ |
|
|
.list_item{ |
|
|
display: flex; |
|
|
display: flex; |
|
|
background-color: #dddddd; |
|
|
background-color: #dddddd; |
|
|
padding: 10px 8px; |
|
|
padding: 8px; |
|
|
margin: 3px 14px 3px 0; |
|
|
margin: 3px 14px 3px 10px; |
|
|
border-radius: 8px; |
|
|
border-radius: 8px; |
|
|
span{ |
|
|
span{ |
|
|
width: 90%; |
|
|
width: 90%; |
|
|
@ -351,10 +380,10 @@ onMounted(() => { |
|
|
display: flex; |
|
|
display: flex; |
|
|
flex-wrap: wrap; |
|
|
flex-wrap: wrap; |
|
|
hr{ |
|
|
hr{ |
|
|
width: 90%; |
|
|
width: 70%; |
|
|
margin: inherit; |
|
|
margin: 11px; |
|
|
border: none; |
|
|
border: none; |
|
|
border-top: .5px solid rgb(26 25 25 / 23%); |
|
|
border-top: 0px solid rgb(26 25 25 / 23%); |
|
|
} |
|
|
} |
|
|
span{ |
|
|
span{ |
|
|
width: 300px; |
|
|
width: 300px; |
|
|
|