src/api/agentSession.ts | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/api/session.ts | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/store/modules/user/index.ts | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/views/sessionManager/components/chatMenu.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/views/sessionManager/components/historySession.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/views/sessionManager/components/seniorAgentSession.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/views/sessionManager/components/smartAi.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/views/sessionManager/components/updataFile.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/views/sessionManager/components/uploadFile.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/views/sessionManager/index.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 |
src/api/agentSession.ts
@@ -59,3 +59,43 @@ data ); } //高级agent会话 export function agentConversationSetApi(data) { return axios.post( '/api/v1/advanced-agent/conversation-set', data ); } //高级会话下载 export function agentConverDownloadApi(data) { return axios.post( '/api/v1/advanced-agent/download', data ); } export const downloadFile = ({ url, filename, target, }: { url: string; filename?: string; target?: string; }) => { const downloadElement = document.createElement('a'); downloadElement.style.display = 'none'; downloadElement.href = url; if (target) { downloadElement.target = '_blank'; } downloadElement.rel = 'noopener noreferrer'; if (filename) { downloadElement.download = filename; } document.body.appendChild(downloadElement); downloadElement.click(); document.body.removeChild(downloadElement); }; src/api/session.ts
@@ -67,3 +67,22 @@ export function getParseMethodsListApi() { return axios.get<ISessionListResult>('/api/v1/user/parse-methods'); } // 上传v1/document/upload_and_parse export function uploadAndParse(params) { const config = { headers: { 'Content-Type': 'application/x-www-form-urlencoded', // token: token, }, }; return axios.post('/api/v1/document/upload_and_parse', params, config); } //高级会话 export function seniorAgentApi(params) { return axios.get<ISessionListResult>( '/api/v1/advanced-agent/list', params ); } src/store/modules/user/index.ts
@@ -86,6 +86,7 @@ setUserResources(JSON.stringify(this.resources)) for (const r of this.resources) { if (r.menuType == 0) { return r.component } } src/views/sessionManager/components/chatMenu.vue
@@ -14,7 +14,11 @@ " > <div class="myAgentToolIcon___gaAKI myAgentToolIconNew___DBZrW"> <img src="@/assets/images/icon-new.png" style="width: 24px" alt="" /> <img src="@/assets/images/icon-new.png" style="width: 24px" alt="" /> </div> </div> <div @@ -50,7 +54,10 @@ > <div class="myAgentToolIcon___gaAKI myAgentToolIconSquare___Rj1o_"> <!-- <img src="@/assets/images/agent.png" style="width: 24px" alt=""/> --> <img src="@/assets/images/icon-zhi.png" style="width: 24px" alt="" <img src="@/assets/images/icon-zhi.png" style="width: 24px" alt="" /> </div> </div> src/views/sessionManager/components/historySession.vue
@@ -9,7 +9,8 @@ left: -40px; font-size: 30px; z-index: 99; cursor: pointer" cursor: pointer; " @click="emit('changeAgentType','1')" > <template #icon> @@ -30,7 +31,6 @@ > <div class="historyTitle___F_iam">历史会话</div> <div class="search"> <!-- 查询框--> <div class="search-box"> @@ -38,12 +38,10 @@ <a-input placeholder="搜索历史会话" v-model="searchValue" style="width: 90%;" style="width: 90%" /> </div> </div> <div class="historyCenter"> <div @@ -61,8 +59,7 @@ /> {{ session.name }} </div> <div class="time" > <div class="time"> <span v-show="session.showtype == 1" style="font-size: 14px"> {{ moment(new Date(session.create_time)).format( @@ -71,7 +68,12 @@ }} </span> </div> <a-button type="text" @click.stop="deleteSession(session)" style="color: red;position: absolute;right: 10px;top: 10px;" v-show="session.showtype == 2"> <a-button type="text" @click.stop="deleteSession(session)" style="color: red; position: absolute; right: 10px; top: 10px" v-show="session.showtype == 2" > <icon-delete style="font-size: 14px" /> </a-button> </div> @@ -83,37 +85,46 @@ import { IconClose, IconSearch, IconTiktokColor } from "@arco-design/web-vue/es/icon"; import { useAppStore, useUserStore } from "@/store"; import { computed, nextTick, onMounted, watch, reactive, ref, onBeforeMount, onBeforeUnmount } from "vue"; IconTiktokColor, } from '@arco-design/web-vue/es/icon'; import { useAppStore, useUserStore } from '@/store'; import { computed, nextTick, onMounted, watch, reactive, ref, onBeforeMount, onBeforeUnmount, } from 'vue'; import { Message, Modal } from "@arco-design/web-vue"; import { Message, Modal } from '@arco-design/web-vue'; import EventBus from '@/utils/EventBus'; import moment from "moment"; import moment from 'moment'; import { addSessionApi, chatApi, getDialogListApi, getSessionDetailsApi, deleteSessionApi, sessionListApiPage } from "@/api/session"; sessionListApiPage, } from '@/api/session'; import { queryCanvasList } from "@/api/Agent"; const emit = defineEmits(["querySessionDetail","changeAgentType"]); import logo from "@/assets/images/model.png"; import { deleteKnow } from "@/api/kbList"; import { getAgentSessionDetailsApi } from "@/api/agentSession"; import { queryCanvasList } from '@/api/Agent'; const emit = defineEmits(['querySessionDetail', 'changeAgentType']); import logo from '@/assets/images/model.png'; import { deleteKnow } from '@/api/kbList'; import { getAgentSessionDetailsApi } from '@/api/agentSession'; const sessionList = ref([]); //会话列表 const activeSessionId = ref(""); const fieldNames = { value: "id", label: "name" }; const activeSessionId = ref(''); const fieldNames = { value: 'id', label: 'name' }; const dialogs = ref([]); const dialogObj = reactive({}); const agentObj = reactive({}); const agentList = ref([]); const searchValue = ref(""); const selectValue = ref(""); const searchValue = ref(''); const selectValue = ref(''); const sectionList = ref({}); const scrollRef = ref(null); const httpUrl = localStorage.getItem('httpUrl'); @@ -121,8 +132,8 @@ let scrollTopVal = ref(0); let queryPage = reactive({ page: 1, page_size: 50 }) page_size: 50, }); let total = ref(0); let sessionScrollList = ref([]); let isReached = ref(true); @@ -135,7 +146,7 @@ dialogs.value = data.map((item) => { return { ...item, type: 1 //智能体 type: 1, //智能体 }; }); // console.log(data, "dialogs"); @@ -147,12 +158,12 @@ const queryCanvas = async (params = {}) => { try { const { data } = await queryCanvasList(params); console.log(data, "agent"); console.log(data, 'agent'); agentList.value = data.map((item) => { return { ...item, name: item.title, type: 2 //agent type: 2, //agent }; }); // 合并数组 @@ -165,37 +176,32 @@ // } //新建会话 querySessionList(dialogs.value[0].id); } catch (err) { // you can report use errorHandler or other } finally { } }; // 查询会话列表 const querySessionList = async (id) => { const { code, data } = await sessionListApiPage({ dialog_id: id, ...queryPage ...queryPage, }); if (code === 200) { sessionList.value = data.map((item) => { return { ...item, showtype: 1 } showtype: 1, }; }); isReached.value = false; setTimeout(()=>{ isReached.value = true; },100) }, 100); // total.value = sessionList.value.length; } else { Message.warning("查询失败"); Message.warning('查询失败'); } }; @@ -236,11 +242,13 @@ // // title: session.name, // // } // } EventBus.emit("queryAgentSessionDetail",session); EventBus.emit('queryAgentSessionDetail', session); emit('changeAgentType','2'); } else if (session.base == 'advanced-agent') { EventBus.emit('queryAgentSessionDetails', session); emit('changeAgentType', '5'); } } }; const handleMouseEnter = (session) => { session.showtype = 2; @@ -249,7 +257,6 @@ const handleMouseLeave = (session) => { session.showtype = 1; }; const handleScroll = async (e: any) => { scrollTopVal.value = e.target.scrollTop; @@ -268,17 +275,17 @@ // // // } queryPage.page++ queryPage.page++; const { code, data } = await sessionListApiPage({ dialog_id: '', ...queryPage ...queryPage, }); if (code === 200) { sessionScrollList.value = data.map((item) => { return { ...item, showtype: 1 } showtype: 1, }; }); // total.value = sessionList.value.length; sessionList.value = [...sessionList.value,...sessionScrollList.value]; @@ -289,32 +296,26 @@ scrollRef.value.scrollTop(scrollTopVal.value); // console.log(scrollRef.value.$el.scrollTop,'scrollTopVal'); // console.log(scrollTopVal.value,'scrollTopVal'); }) },100) }); }, 100); } else { Message.warning("查询失败"); } Message.warning('查询失败'); } } }; onBeforeMount(()=>{ // DialogList() querySessionList(''); }) }); onMounted(() => { console.log(httpUrl,'当前地址'); EventBus.on("history", () => { EventBus.on('history', () => { emit('changeAgentType','3'); // DialogList() queryPage.page = 1; querySessionList(''); }); // 添加滚动事件监听器 scrollRef.value.$el.addEventListener('scroll', handleScroll); @@ -323,15 +324,10 @@ return () => { scrollRef.value.$el.removeEventListener('scroll', handleScroll); }; }) onBeforeUnmount(() => { EventBus.off("history"); }); onBeforeUnmount(() => { EventBus.off('history'); }); </script> <style scoped lang="less"> .layoutHisCenter{ @@ -385,15 +381,9 @@ color: var(--color-text-2); //border: 1px solid var(--color-neutral-3); background: var(--color-bg-3); box-shadow: 0 1px 2px -2px rgba(0, 0, 0, 0.16), 0 3px 6px 0 rgba(0, 0, 0, 0.12), 0 5px 12px 4px rgba(0, 0, 0, 0.09); box-shadow: 0 1px 2px -2px rgba(0, 0, 0, 0.16), 0 3px 6px 0 rgba(0, 0, 0, 0.12), 0 5px 12px 4px rgba(0, 0, 0, 0.09); } } } </style> src/views/sessionManager/components/seniorAgentSession.vue
New file @@ -0,0 +1,978 @@ <template> <!-- 内容--> <div class="header___section"> <div class="chatHeader"> <div class="chatHeaderBox"> <!-- <span class="title">{{agentTitle}}</span>--> <a-popover position="bottom" trigger="click"> <a-button border> <span style=" width: 100px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; " >{{ from.name }}</span > <icon-down style="margin-left: 4px" /> </a-button> <template #content> <a-button type="text" class="button" style="color: #2a2a2b" @click="handleClick()" > <template #icon> <icon-edit /> </template> 修改名称 </a-button> <!-- <a-divider style="margin: 10px 0" />--> </template> </a-popover> </div> </div> </div> <a-scrollbar ref="scrollbar" id="agentHome" class="chat-list" style=" width: 80%; overflow: auto; height: calc(100vh - 380px); margin: 0px auto 20px; " > <div class="chat-item" v-for="(sessionDetail, index) in sessionDetailList"> <a-comment v-if="sessionDetail.role === 'user'"> <template #avatar> <img class="icon-user-jpg" src="../../../assets/images/icon-user.jpg" alt="本地图片" /> </template> <template #content> <div :class="{ chartUserText: theme === 'light' }" >{{ sessionDetail.content }} </div> </template> </a-comment> <a-comment v-else-if="sessionDetail.role === 'assistant'"> <template #avatar> <img class="icon-user-jpg" src="../../../assets/images/icon-picture.png" alt="本地图片" /> </template> <template #content> <!-- <a-card :class="{ chatItemAnswer: theme === 'light' }">--> <!-- <div :class="{ light: theme === 'light' }"--> <!-- >{{ sessionDetail.content }}--> <!-- </div>--> <!-- </a-card>--> <a-textarea readonly auto-size v-model="sessionDetail.content" :class="{ chatItemAnswer: theme === 'light' }" :style="{ backgroundColor: theme === 'light' ? '#ffffff' : '#000000', }" style="border: none" > </a-textarea> <!-- <div class="prompt"> <ul> <li class="prompt-item" @click="copyText('43234')"> <span> 344343klsdjkjksdjkjksdjk就开始大家看数据库登记卡受打击凯撒登记卡受打击凯撒登记卡受打击凯撒的43</span > <span style="margin-left: 20px"> <icon-right /> </span> </li> </ul> </div> --> </template> <template #actions> <span class="action" v-if="index != 0" @click="copy(sessionDetail.content)" > <icon-copy /> 复制 </span> <span class="action" v-if="index != 0 && index == sessionDetailList.length - 1" @click="reGenerate()" > <icon-refresh /> 重新生成 </span> <span class="action" v-if="sessionDetail.filename" @click="iconDownload(sessionDetail)" ><icon-to-bottom />下载 </span> </template> </a-comment> <a-comment v-else-if="sessionDetail.role === 'last'"> <template #avatar> <img class="icon-user-jpg" src="../../../assets/images/icon-picture.png" alt="本地图片" /> </template> <template #content> <a-textarea readonly auto-size v-model="displayedText" :class="{ chatItemAnswer: theme === 'light' }" :style="{ backgroundColor: theme === 'light' ? '#ffffff' : '#000000', }" style="border: none" > </a-textarea> </template> <template #actions> <div class="action" @click="stopChat" style=" background: var(--color-bg-2); color: var(--color-primary-light-4); " v-if="displayedText != ''" > <icon-record-stop /> 停止生成 </div> </template> </a-comment> </div> <!-- <div class="chartStart" v-if="isStart" @click="startChat" >停止生成</div > <div class="chartStart v-else" @click="stopChat">重新生成</div> --> </a-scrollbar> <div class="chat_bottom"> <div class="center-bottom"> <a-textarea v-model="inputMsg" @keydown.shift.enter="handleShiftEnter" @keydown.enter="sendMessage" placeholder="输入您想了解的内容,Shift+Enter换行,Enter发送" allow-clear show-word-limit :disabled="chatDis" :class="{ textItemAnswer: theme === 'dark' }" :style="{ backgroundColor: theme === 'light' ? '#ffffff' : '#000000' }" style="border: none" :auto-size="{ minRows: 12, maxRows: 5, }" /> <div style="width: 100%; display: flex; justify-content: space-between"> <span></span> <a-button :disabled="chatDis" @click="sentClick" type="text" style="border-radius: 24px" :loading="loading" > <icon-send size="32" style="color: #0960bd" /> </a-button> </div> <!-- <div class="btn-send">--> <!-- <!– <icon-send size="32" /> –>--> <!-- <a-button--> <!-- :disabled="chatDis"--> <!-- @click="sentClick"--> <!-- type="text"--> <!-- style="border-radius: 24px"--> <!-- :loading="loading"--> <!-- >--> <!-- <icon-send size="32" style="color: #0960bd;"/>--> <!-- </a-button--> <!-- >--> <!-- </div>--> </div> <a-modal v-model:visible="visible" title="修改名称" @before-open="handleOpened" @cancel="handleCancel" :footer="false" title-align="start" > <a-form ref="formRef" :rules="rules" :model="from" @submit="handleSubmit"> <a-form-item field="name" label="名称"> <a-input v-model="from.name" placeholder="请输入名称" /> </a-form-item> <a-form-item> <div style="width: 100%; text-align: right"> <a-button @click="visible = false">取消</a-button> <a-button style="margin-left: 10px" type="primary" html-type="submit" >确定</a-button > </div> </a-form-item> </a-form> </a-modal> </div> </template> <script setup lang="ts"> import { defineProps, ref, watch, defineEmits, onMounted, reactive, computed, nextTick, onBeforeUnmount, } from 'vue'; import { Message } from '@arco-design/web-vue'; import { useAppStore } from '@/store'; import { getAuthorization } from '@/utils/auth'; import { EventSourceParserStream } from 'eventsource-parser/stream'; import { agentResetApi, agentSetApi, getAgentSessionDetailsApi, agentConversationSetApi, agentConverDownloadApi, downloadFile, } from '@/api/agentSession'; import EventBus from '@/utils/EventBus'; import useClipboard from 'vue-clipboard3'; import { addSessionApi, getSessionDetailsApi } from '@/api/session'; const props = defineProps({ modalObj: Object, }); // const emit = defineEmits(['addSession']); const sessionDetailList = ref([ { content: '你好! 我是你的助理,有什么可以帮到你的吗?', role: 'assistant', }, ]); //根据会话id出来的会话详情 const sessionList = ref([]); //会话列表 const modalObj = reactive({}); const dialogId = ref(''); const chatDis = ref(false); const loading = ref(false); const agentTitle = ref('未命名会话'); const currIndex = ref(0); const displayedText = ref(''); // 正在显示的文字 let timer: number | null = null; const streamStr = ref(''); const inputMsg = ref(''); const activeSessionId = ref(''); const conversation_id = ref(''); const fieldNames = { value: 'id', label: 'name' }; const agentObj = reactive({}); const agentList = ref([]); const selectValue = ref(''); const sectionList = ref({}); let chatObj = reactive({}); const isStopChat = ref(false); const appStore = useAppStore(); const sessionObj = reactive({}); const theme = computed(() => { return appStore.theme; }); let from = reactive({ name: '未命名会话', }); const visible = ref(false); let isHistory = ref(false); //是否是历史记录 let dsl = reactive({}); const chatDataMeg = reactive({}); const rules = { name: [ { required: true, message: '名称不允许为空', }, ], }; const handleSubmit = async ({ values, errors }) => { if (errors) return; let chatData = { id: conversation_id.value, conversation_id: conversation_id.value, name: from.name, }; const { code, data } = await addSessionApi(chatData); if (data) { Message.success('修改成功'); handleCancel(); } }; const handleClick = () => { visible.value = true; }; const handleCancel = () => { visible.value = false; }; const handleOpened = (el) => { // Object.assign(form,{ // name: '',// 用户名 // }); // formRef.value.resetFields(); }; // 初始化页面 const initPage = async () => { // agentSet(); }; const createNewAgent = async (session) => { sessionDetailList.value = [ { content: '你好! 我是你的助理,有什么可以帮到你的吗?', role: 'assistant', }, ]; Object.assign(agentObj, session); from.name = session.name; const dataSession = session.prompt_config; if (dataSession.prologue) { sessionDetailList.value[0].content = dataSession.prologue; } isHistory.value = false; initPage(); }; // 调用set方法 const agentSet = async () => { const res = await agentSetApi({ id: agentObj.id, title: agentObj.title, dsl: agentObj.dsl, }); // console.log(res,'agentSet'); if (res.code == 0) { conversation_id.value = res.data.conversation_id; agentReset(); } }; // 调用reset方法 const agentReset = async () => { const res = await agentResetApi({ id: agentObj.id, }); if (res.code == 0) { // Message.success('修改成功'); agentCompletion(); } }; // 调用completion方法 const agentCompletion = async () => { const response = await fetch('/api/v1/canvas/completion', { method: 'POST', headers: { 'Authorization': getAuthorization(), 'Content-Type': 'application/json', }, body: JSON.stringify({ id: agentObj.id, }), }); const reader = response?.body ?.pipeThrough(new TextDecoderStream()) .pipeThrough(new EventSourceParserStream()) .getReader(); currIndex.value = 0; while (true) { const x = await reader?.read(); if (x) { const { done, value } = x; try { const val = JSON.parse(value?.data || ''); const d = val?.data; if (typeof d !== 'boolean') { console.info('data:', d); streamStr.value = d.content; startDisplayStr(); } } catch (e) { console.warn(e); } if (done) { console.info('done'); displayedText.value = ''; // queryAgentSessionDetail(activeSessionId.value); break; } } } chatDis.value = false; loading.value = false; inputMsg.value = ''; }; // 调用get方法 const queryAgentSessionDetails = async (id) => { const { code, data } = await getSessionDetailsApi(id); if (code == 200) { console.log(data, 'agent会话详情'); Object.assign(chatObj, data); // nextTick(() => { // sessionDetailList.value = data.dsl.messages; // }); sessionDetailList.value = data.message; agentTitle.value = `${data.name}` || '未命名会话'; from.name = `${data.name}` || '未命名会话'; refreshScroll(); //刷新滚动条位置 } }; const copyText = (text) => { inputMsg.value = text; }; // 历史记录跳转获取agent会话详情 const querySessionDetail = async (session) => { conversation_id.value = session.id; activeSessionId.value = session.id; from.name = session.name; const { code, data } = await getSessionDetailsApi(session.id); if (code == 200) { sessionDetailList.value = data.message; refreshScroll(); //刷新滚动条位置 // const res = await getAgentSessionDetailsApi(session.dialog_id); // if (res.code == 0) { // Object.assign(agentObj, res.data); // Object.assign(chatObj, res.data); // Object.assign(dsl, res.data.dsl); // refreshScroll(); //刷新滚动条位置 // } } }; const { toClipboard } = useClipboard(); const copy = async (text) => { await toClipboard(text); //参数为要复制的文本 }; const sentClick = () => { sendMessage('click'); }; // 重新生成 const reGenerate = () => { let inputContent = sessionDetailList.value[sessionDetailList.value.length - 2].content; startChat(inputContent); }; const sendMessage = async (event) => { if (event.keyCode == 13 || event === 'click') { if (!event.shiftKey) { //只有enter没有shift,或进行你的其他逻辑 if (event !== 'click') { event.preventDefault(); // 阻止默认行为,即不换行 } // chatDis.value = true; // loading.value = true; // if (!agentObj.id) { // Message.warning('请选择会话'); // chatDis.value = false; // loading.value = false; // return; // } // if (displayedText.value) { // querySessionList(); // } if (inputMsg.value) { // const res = await addSessionApi({ // dialog_id: '', // conversation_desc: inputMsg.value, // }); // // console.log(res, "res"); // if (res.code == 200) { // // console.log(res.data.conversation_id); // activeSessionId.value = res.data?.conversation_id; // const { code, data } = await getSessionDetailsApi( // res.data?.conversation_id // ); // if (code === 200) { // console.log(data, '新建会话详情'); // Object.assign(chatObj, data); // startChat(inputMsg.value); // inputMsg.value = ''; // } // } else { // Message.error('创建会话失败,请重试'); // } // startChat(inputMsg.value); // inputMsg.value = ''; createSession(); } else { Message.warning('消息不能为空'); chatDis.value = false; loading.value = false; } } } }; //创建会话 const createSession = async () => { try { loading.value = true; chatDis.value = true; if (!activeSessionId.value) { let message = [ { content: sessionDetailList.value[0].content, role: 'assistant', }, { content: inputMsg.value, role: 'user', }, ]; const res = await agentConversationSetApi({ id: '', app_id: agentObj.id, name: inputMsg.value, message: message, }); // console.log(res, "res"); if (res.code == 200) { // console.log(res.data.conversation_id); activeSessionId.value = res.data?.id; startChat(inputMsg.value); inputMsg.value = ''; } } else { startChat(inputMsg.value); inputMsg.value = ''; } } catch (err) { // throw err; Message.error('创建会话失败,请重试'); loading.value = false; chatDis.value = false; } }; //下载 const iconDownload = async (val) => { await downloadFile({ url: `/api/v1/advanced-agent/download?file_id=` + val.filename, }); }; //聊天 const startChat = async (valMsg) => { sessionDetailList.value.push({ content: valMsg, role: 'user', }); sessionDetailList.value.push({ role: 'last' }); refreshScroll(); let chatStr = { id: activeSessionId.value, message: valMsg, }; if (isHistory.value) { chatStr.dsl = dsl; } const response = await fetch('/api/v1/advanced-agent/completion', { method: 'POST', headers: { 'Authorization': getAuthorization(), 'Content-Type': 'application/json', }, body: JSON.stringify(chatStr), }); const reader = response?.body ?.pipeThrough(new TextDecoderStream()) .pipeThrough(new EventSourceParserStream()) .getReader(); currIndex.value = 0; while (true) { const x = await reader?.read(); if (x) { const { done, value } = x; // console.log(x, 999); if (value && value?.event == 'message') { try { const val = JSON.parse(value?.data || ''); const d = val?.data; if (typeof d !== 'boolean') { console.info('data:', d); streamStr.value = d.content; startDisplayStr(); } } catch (e) { console.warn(e); } } if (done) { console.info('done'); // displayedText.value = ''; if (isStopChat.value) { isStopChat.value = false; setChatDataMeg(chatDataMeg); } else { // queryAgentSessionDetail(activeSessionId.value); // EventBus.emit('queryAppUsageList'); } break; } } } chatDis.value = false; loading.value = false; }; const stopChat = async () => { // const { code, data } = await stopChatApi(agentObj.id); // if (code === 200) { // Message.success("已停止"); // } loading.value = false; chatDis.value = false; isStopChat.value = true; let inputText = sessionDetailList.value[sessionDetailList.value.length - 2].content; // 数组合并 let lastArr = [ { content: inputText, role: 'user', }, { content: displayedText.value, role: 'assistant', }, ]; sessionDetailList.value = sessionDetailList.value .splice(0, sessionDetailList.value.length - 2) .concat(lastArr); chatObj.dsl.messages = chatObj.dsl.messages.concat(lastArr); Object.assign(chatDataMeg, { id: chatObj.id, conversation_id: chatObj.id, message: sessionDetailList.value, }); }; const setChatDataMeg = async (chatData) => { const { code, data } = await addSessionApi(chatData); if (data) { //停止定时器 clearTimeout(timer!); timer = null; // displayedText.value = ""; queryAgentSessionDetails(activeSessionId.value); } }; const handleShiftEnter = (event) => { event.preventDefault(); inputMsg.value += '\n'; }; //文字动态输出 const startDisplayStr = () => { if (timer) { clearTimeout(timer!); } const res = streamStr.value; // 将数组中的字符串拼接起来 if (currIndex.value < res.length) { displayedText.value += res[currIndex.value]; currIndex.value++; setTimeout(startDisplayStr, 100); refreshScroll(); } else { displayedText.value = ''; queryAgentSessionDetails(activeSessionId.value); clearTimeout(timer!); timer = null; } }; const scrollbar = ref(null); const refreshScroll = () => { nextTick(() => { const container = document.getElementById('agentHome'); scrollbar.value.scrollTop(container.scrollHeight); }); }; onMounted(() => { EventBus.on('createSeniorAgent', (data) => { createNewAgent(data); }); EventBus.on('queryAgentSessionDetails', (data) => { isHistory.value = true; querySessionDetail(data); }); }); onBeforeUnmount(() => { EventBus.off('createSeniorAgent'); EventBus.off('queryAgentSessionDetails'); }); watch( () => props.modalObj, (newVal, oldVal) => { // Object.assign(agentObj, newVal); //调用agent初始化方法 if (JSON.stringify(newVal) != '{}') { // initPage(); } }, { immediate: true, deep: true, } ); </script> <style scoped lang="scss"> .dark { color: gray !important; } .container { .chatItemAnswer { box-sizing: border-box; background: #f1f1f1; border-radius: 10px; padding: 5px; .light { box-sizing: border-box; background: #f1f1f1; border-radius: 10px; } } .textItemAnswer { background-color: #373739; } .center { box-sizing: border-box; height: calc(100vh - 200px); position: relative; .center-title { line-height: 60px; font-size: 25px; font-family: 黑体; color: deepskyblue; } .center-content { font-size: 14px; color: gray; } .center-question { margin-top: 20px; display: flex; justify-content: space-between; .center-question-left { margin-top: 5px; margin-left: 20px; } .center-question-right { margin-right: 20px; } } .center-list { margin-top: 10px; .item { border-radius: 10px; margin-top: 10px; padding: 10px; min-height: 120px; background-color: #e9f3ff; .item-content { color: #666; } .item-title { text-align: center; line-height: 40px; font-size: 20px; font-family: 黑体; color: #333; } } } .chartStart { color: #4955f5; cursor: pointer; font-family: PingFangSC-Medium; font-size: 12px; font-weight: 500; } .chat_bottom { display: flex; align-items: center; width: 78%; margin: 0 auto; .center-bottom { // position: absolute; // width: 90%; // bottom: 20px; // left: 5%; background: #fff; border: 1px solid #00000014; border-radius: 24px; display: flex; flex: 1 1; flex-direction: column; overflow: hidden; position: relative; // padding-top:10px; :deep(.arco-textarea-wrapper) { border-radius: 24px; } .btn-send { position: absolute !important; right: 4px; top: 80px; z-index: 10; } :deep(.arco-btn-size-large) { height: 28px; width: 50px; } } :deep(.arco-textarea-wrapper) { padding-top: 5px; } } } .chat-item { padding: 10px 0; .chartUserText { font-weight: 600; font-size: 14px; color: #333; margin-top: 4px; } .icon-user-jpg { border: 1px solid #d9d9d9; } .prompt { ul { margin: 0; padding: 0; display: flex; } ul > li { list-style-type: none; } .prompt-item { display: flex; justify-content: space-between; background-color: #fff; cursor: pointer; border-radius: 8px; padding: 10px; border: #e5e5e5; &:hover { background-color: #eee; } } } } } .header___section { width: 100%; height: 46px; position: relative; backdrop-filter: blur(15px); display: flex; align-items: center; justify-content: center; -webkit-backdrop-filter: blur(15px); .chatHeaderBox { width: auto; border-radius: 8px; padding: 4px 20px; transition: all var(--animation-duration) var(--animation-transition); display: flex; align-items: flex-end; overflow: hidden; /* 隐藏超出的内容 */ text-overflow: ellipsis; /* 使用省略号来代替被隐藏的文字 */ white-space: nowrap; /* 不换行,使内容在一行内显示 */ max-width: 200px; .title { color: var(--color-text-1); font-size: 12px; } } } .action { cursor: pointer; display: inline-block; padding: 0 10px; color: var(--color-text-1); line-height: 24px; background: transparent; border-radius: 2px; cursor: pointer; transition: all 0.1s ease; font-size: 12px; } .action:hover { background: var(--color-fill-3); } </style> src/views/sessionManager/components/smartAi.vue
@@ -55,6 +55,29 @@ <div class="time"> </div> </div> </a-col> <a-col :span="8" v-for="item in seniorAgentList"> <div class="item agentCenter-box" @click="createNewSession(item)"> <div class="text"> <a-avatar> <img :style="{ width: '100%' }" alt="dessert" :src="item.icon || imgSrc" /> </a-avatar> <span style=" margin-left: 10px; font-weight: 500; color: var(--color-text-1); " > {{ item.name }} </span> </div> <div class="time"> </div> </div> </a-col> </a-row> </div> </a-scrollbar> @@ -87,6 +110,7 @@ getDialogListApi, getSessionDetailsApi, sessionListApi, seniorAgentApi, } from '@/api/session'; import { queryCanvasList } from '@/api/Agent'; const emit = defineEmits([ @@ -95,6 +119,7 @@ 'createSession', ]); import logo from '@/assets/images/model.png'; import { create } from 'lodash'; const sessionList = ref([]); //会话列表 const activeSessionId = ref(''); const fieldNames = { value: 'id', label: 'name' }; @@ -102,6 +127,7 @@ const dialogObj = reactive({}); const agentObj = reactive({}); const agentList = ref([]); const seniorAgentList = ref([]); const searchValue = ref(''); const selectValue = ref(''); const sectionList = ref({}); @@ -142,6 +168,14 @@ } }; //高级会话 const querySeniorAgent = async () => { const { code, data } = await seniorAgentApi(); if (code === 200) { seniorAgentList.value = data; } }; // 查询会话列表 const querySessionList = async (id) => { const { code, data } = await sessionListApi(id); @@ -155,6 +189,12 @@ const createNewSession = async (session) => { console.log(session, 'session'); // emit('querySessionDetail',session); if (session.app_type == '3') { //高级agent EventBus.emit('createSeniorAgent', session); emit('changeAgentType', '5'); } else { if (session.type == '1') { // 生成智能体新的对话 emit('createSession', session.id, `和${session.name}的会话`); @@ -164,10 +204,13 @@ EventBus.emit('createAgent', session); emit('changeAgentType', '2'); } } }; onBeforeMount(() => { DialogList(); queryCanvas(); querySeniorAgent(); }); onMounted(() => { @@ -175,6 +218,7 @@ emit('changeAgentType', '4'); DialogList(); queryCanvas(); querySeniorAgent(); }); }); onBeforeUnmount(() => { src/views/sessionManager/components/updataFile.vue
@@ -42,9 +42,7 @@ <a-radio :value="item.value" style="margin-right: 10px">{{ item.name }}</a-radio> <!-- <template #content> <p style="max-width: 300px">{{ item.parser_config_str }}</p> </template> --> <template #content> <p>{{ item.parser_config_str }}</p> </template> @@ -93,6 +91,7 @@ getParseMethodsListApi, getSessionDetailsApi, uploadWithoutKb, uploadAndParse, } from '@/api/session'; const visible = ref(false); @@ -337,6 +336,19 @@ formData.append('parser_id', parser_id.value); } } console.log(formData, 'formData'); // uploadAndParse(formData).then((res) => { // debugger; // onFileSelectedLoading.value = false; // if (res.code == 200) { // cancel(); // // uploaditemList.value = []; // emit('selectFileCallback', uploaditemList.value); // Message.success('上传成功'); // } else { // Message.error('上传失败'); // } // }); uploadWithoutKb(formData).then((res) => { onFileSelectedLoading.value = false; if (res.code == 200) { src/views/sessionManager/components/uploadFile.vue
New file @@ -0,0 +1,122 @@ <template> <div> <a-upload v-model:fileList="fileList" :limit="limit" @change="handleChange" @before-remove="beforeRemove" image-preview > <template #upload-button> <a-button type="text" style="border-radius: 24px" @click="visibleChange" > <icon-attachment size="28" style="color: #0960bd" /> </a-button> </template> </a-upload> </div> </template> <script setup> import { computed, ref, onMounted, watch, watchEffect } from 'vue'; import { uploadAndParse } from '@/api/session'; import { useUserStore } from '@/store'; const userStore = useUserStore(); const props = defineProps({ limit: { type: Number, default: 3, }, sessionId: String, action: String, // 上传的服务器地址 url: String, //回显的文件地址 }); const emit = defineEmits([ 'update:fileList', 'success', 'handleRemove', 'selectFileCallback', ]); const urls = computed(() => props.url); const fileList = ref([]); watch( () => [props.url, props.sessionId], ([newVal, newSessionId], [oldVal, oldSessionId]) => { // if (newVal) { // fileList.value = newVal.split(',').map((item) => ({ // uid: item, // name: item, // status: 'done', // url: item, // })); // } }, { deep: true, // 开启深度监听 } ); onMounted(() => { if (urls.value) { fileList.value = urls.value.split(',').map((item) => ({ uid: item, name: item, status: 'done', url: item, })); } }); // console.log(urls.value, 8988); const beforeRemove = (file) => { emit('handleRemove'); fileList.value = []; }; const handleChange = (fileList) => { // emit('update:fileList', fileList); // const successFiles = fileList.filter((item) => item.status === 'done'); // if (successFiles.length > 0) { // emit( // 'success', // successFiles.map((item) => item.response.data) // ); // emit( // 'selectFileCallback', // successFiles.map((item) => item.response.data) // ); const formData = new FormData(); for (let i = 0; i < fileList.length; i++) { formData.append('file', fileList[i].file); formData.append('conversation_id', props.sessionId); // formData.append('parser_config', ''); // if (!parser_id.value) { // formData.append( // 'parser_id', // getIconByExtension(successFiles[i].name) // ); // } else { // formData.append('parser_id', parser_id.value); // } } uploadAndParse(formData).then((res) => { onFileSelectedLoading.value = false; if (res.code == 200) { cancel(); // uploaditemList.value = []; emit('selectFileCallback', uploaditemList.value); Message.success('上传成功'); } else { Message.error('上传失败'); } }); // } }; </script> src/views/sessionManager/index.vue
@@ -373,12 +373,18 @@ display: flex; justify-content: space-between; " class="uploadFileDis" > <updataFile ref="fileInput" :sessionId="activeSessionId" @selectFileCallback="selectFileCallback" ></updataFile> <!-- <uploadFile ref="fileInput" :sessionId="activeSessionId" @selectFileCallback="selectFileCallback" ></uploadFile> --> <a-button :disabled="chatDis" @click="sentClick" @@ -466,6 +472,11 @@ ></smartAi> </div> </a-col> <a-col :span="23" v-show="agentType == '5'"> <div class="center"> <seniorAgentSession :modalObj="agentObj"></seniorAgentSession> </div> </a-col> </a-row> <a-modal title=" " v-model:visible="fileVisible" :footer="false" fullscreen> <!-- <docx previewSrc="http://192.168.20.116:1080/v1/document/get/405c3efa4d8c11ef97560242ac120006"></docx>--> @@ -519,9 +530,11 @@ import chatMenu from '@/views/sessionManager/components/chatMenu.vue'; import AddSession from '@/views/sessionManager/components/addSession.vue'; import agentSession from '@/views/sessionManager/components/agentSession.vue'; import seniorAgentSession from '@/views/sessionManager/components/seniorAgentSession.vue'; import historySession from '@/views/sessionManager/components/historySession.vue'; import smartAi from '@/views/sessionManager/components/smartAi.vue'; import updataFile from '@/views/sessionManager/components/updataFile.vue'; import EventBus from '@/utils/EventBus'; import { addSessionApi, @@ -546,6 +559,7 @@ import excel from '@/views/dmx/knowledgeLib/components/excel.vue'; import txtPdf from '@/views/dmx/knowledgeLib/components/txtPdf.vue'; import { is } from 'immutable'; import uploadFile from './components/uploadFile.vue'; // const url = ref('../../assets/session/PDF.png'); @@ -586,7 +600,7 @@ const uploadRef = ref(); const files = ref([]); const file = ref(''); const fileInput = ref(null); const fileInput = ref(); const chatDataMeg = reactive({}); const visible = ref(false); const fileVisible = ref(false); @@ -752,6 +766,7 @@ }; const selectFileCallback = (data) => { debugger; console.log(data, 'selectFileCallback'); uploaditemList.value = [...uploaditemList.value, ...data]; }; @@ -1212,6 +1227,11 @@ } } } .uploadFileDis { :deep(.arco-upload-list-type-text) { display: none; } } .prompt { ul { margin: 0;