| | |
| | | style=" |
| | | width: 80%; |
| | | overflow: auto; |
| | | height: calc(100vh - 380px); |
| | | height: calc(100vh - 400px); |
| | | margin: 0px auto 20px; |
| | | " |
| | | > |
| | | <div class="chat-item" v-for="(sessionDetail, index) in sessionDetailList"> |
| | | <a-comment v-if="sessionDetail.role === 'user'"> |
| | | <a-comment v-if="sessionDetail?.role === 'user'"> |
| | | <template #avatar> |
| | | <img |
| | | class="icon-user-jpg" |
| | |
| | | <div :class="{ chartUserText: theme === 'light' }" |
| | | >{{ sessionDetail.content }} |
| | | </div> |
| | | |
| | | <!-- <div class="uploadFileList fileList"> |
| | | <a-comment |
| | | content="232323" |
| | | style=" |
| | | background: var(--color-bg-2); |
| | | padding: 10px; |
| | | border-radius: 10px; |
| | | font-size: 12px; |
| | | " |
| | | > |
| | | <template #avatar> |
| | | <img :src="getIconByExtension('wps')" alt="" /> |
| | | </template> |
| | | </a-comment> |
| | | </div> --> |
| | | </template> |
| | | </a-comment> |
| | | <a-comment v-else-if="sessionDetail.role === 'assistant'"> |
| | | <a-comment v-else-if="sessionDetail?.role === 'assistant'"> |
| | | <template #avatar> |
| | | <img |
| | | class="icon-user-jpg" |
| | |
| | | <!-- </div>--> |
| | | <!-- </a-card>--> |
| | | <a-textarea |
| | | v-if="sessionDetail?.content" |
| | | readonly |
| | | auto-size |
| | | v-model="sessionDetail.content" |
| | |
| | | style="border: none" |
| | | > |
| | | </a-textarea> |
| | | <div v-else> |
| | | <!-- <a-textarea |
| | | readonly |
| | | auto-size |
| | | :default-value="chartText(sessionDetail.code, sessionDetail.sql)" |
| | | :class="{ chatItemAnswer: theme === 'light' }" |
| | | :style="{ |
| | | backgroundColor: theme === 'light' ? '#ffffff' : '#000000', |
| | | }" |
| | | style="border: none" |
| | | > |
| | | </a-textarea> --> |
| | | <!-- <codemirror |
| | | v-model="sessionDetail.code" |
| | | placeholder="Code gose here..." |
| | | :style="{ height: '100%' }" |
| | | :autofocus="true" |
| | | :tabSize="2" |
| | | /> --> |
| | | <div class="codeStle"> |
| | | <div class="language">python</div> |
| | | <pre |
| | | style="background: #2c2c36; padding: 10px; margin-top: 0" |
| | | ><code class="language-js line-numbers">{{ sessionDetail.code+ sessionDetail.sql}}</code></pre> |
| | | </div> |
| | | |
| | | <a-image |
| | | v-if="sessionDetail?.image_name" |
| | | :src="getImg(sessionDetail)" |
| | | alt="" |
| | | /> |
| | | <div class="uploadFileList fileList"> |
| | | <a-comment |
| | | :content="sessionDetail.excel_name" |
| | | style=" |
| | | background: var(--color-bg-2); |
| | | padding: 10px; |
| | | border-radius: 10px; |
| | | font-size: 12px; |
| | | " |
| | | > |
| | | <template #avatar> |
| | | <img :src="getIconByExtension('xlsx')" alt="" /> |
| | | </template> |
| | | </a-comment> |
| | | </div> |
| | | </div> |
| | | <div class="prompt" v-if="!activeSessionId"> |
| | | <ul> |
| | | <li |
| | |
| | | </li> |
| | | </ul> |
| | | </div> |
| | | <div> |
| | | <!-- <a-image |
| | | width="200" |
| | | src="https://p1-arco.byteimg.com/tos-cn-i-uwbnlip3yd/a8c8cdb109cb051163646151a4a5083b.png~tplv-uwbnlip3yd-webp.webp" |
| | | /> --> |
| | | </div> |
| | | </template> |
| | | <template #actions> |
| | | <span |
| | | class="action" |
| | | v-if="index != 0" |
| | | v-if="index != 0 && sessionDetail?.content" |
| | | @click="copy(sessionDetail.content)" |
| | | > |
| | | <icon-copy /> 复制 |
| | | </span> |
| | | <span |
| | | class="action" |
| | | v-if="index != 0 && sessionDetail?.code" |
| | | @click="copy(sessionDetail.code + sessionDetail.sql)" |
| | | > |
| | | <icon-copy /> 复制 |
| | | </span> |
| | |
| | | @click="iconDownload(sessionDetail)" |
| | | ><icon-to-bottom />下载 |
| | | </span> |
| | | <span |
| | | class="action" |
| | | v-if="sessionDetail?.excel_name" |
| | | @click="iconDownloadXsl(sessionDetail)" |
| | | ><icon-to-bottom />下载 |
| | | </span> |
| | | </template> |
| | | </a-comment> |
| | | <a-comment v-else-if="sessionDetail.role === 'last'"> |
| | | <a-comment v-else-if="sessionDetail?.role === 'last'"> |
| | | <template #avatar> |
| | | <img |
| | | class="icon-user-jpg" |
| | |
| | | maxRows: 5, |
| | | }" |
| | | /> |
| | | <div style="width: 100%; display: flex; justify-content: space-between"> |
| | | <span></span> |
| | | <div |
| | | style="width: 100%; display: flex; justify-content: space-between" |
| | | class="uploadFileDis" |
| | | > |
| | | <!-- <updataFile |
| | | ref="fileInput" |
| | | :sessionId="activeSessionId" |
| | | @selectFileCallback="selectFileCallback" |
| | | ></updataFile> --> |
| | | <span v-if="getAent"></span> |
| | | <uploadFile |
| | | v-if="agentObj.id == 'excel_talk' || dialog_id == 'excel_talk'" |
| | | ref="fileInput" |
| | | :sessionId="activeSessionId" |
| | | @selectFileCallback="selectFileCallback" |
| | | ></uploadFile> |
| | | <a-button |
| | | :disabled="chatDis" |
| | | @click="sentClick" |
| | |
| | | <icon-send size="32" style="color: #0960bd" /> |
| | | </a-button> |
| | | </div> |
| | | |
| | | <!-- <div class="btn-send">--> |
| | | <!-- <!– <icon-send size="32" /> –>--> |
| | | <!-- <a-button--> |
| | |
| | | <!-- </a-button--> |
| | | <!-- >--> |
| | | <!-- </div>--> |
| | | </div> |
| | | <div class="uploadFileList" v-if="uploaditemList.length > 0"> |
| | | <div |
| | | class="files" |
| | | v-for="(item, index) in uploaditemList" |
| | | :key="index" |
| | | style=" |
| | | position: relative; |
| | | width: 220px; |
| | | margin-top: 10px; |
| | | margin-right: 20px; |
| | | " |
| | | > |
| | | <a-comment |
| | | :author="item.name" |
| | | :content="item.size" |
| | | style=" |
| | | background: var(--color-bg-2); |
| | | padding: 10px; |
| | | border-radius: 10px; |
| | | font-size: 12px; |
| | | " |
| | | > |
| | | <template #avatar> |
| | | <a-spin |
| | | :loading="onFileSelectedLoading" |
| | | v-if="onFileSelectedLoading" |
| | | > |
| | | <template #icon> |
| | | <icon-sync /> |
| | | </template> |
| | | <template #tip> |
| | | <div style="font-size: 12px">{{ textName }}</div> |
| | | </template> |
| | | </a-spin> |
| | | <!-- <a-button type="text" :loading="onFileSelectedLoading" v-if="onFileSelectedLoading"></a-button>--> |
| | | <!-- <a-avatar v-if="!onFileSelectedLoading">--> |
| | | <!-- <icon-file style="color: #0960bd" />--> |
| | | <!-- </a-avatar>--> |
| | | <img :src="getIconByExtension(item.name)" alt="" /> |
| | | </template> |
| | | </a-comment> |
| | | <icon-close-circle-fill |
| | | size="18px" |
| | | @click="deleteFile(item, index)" |
| | | style=" |
| | | position: absolute; |
| | | right: -4px; |
| | | top: -4px; |
| | | color: red; |
| | | cursor: pointer; |
| | | " |
| | | /> |
| | | </div> |
| | | </div> |
| | | <a-modal |
| | | v-model:visible="visible" |
| | |
| | | import { Message } from '@arco-design/web-vue'; |
| | | import { useAppStore } from '@/store'; |
| | | import { getAuthorization } from '@/utils/auth'; |
| | | import updataFile from './updataFile.vue'; |
| | | import uploadFile from './uploadFile.vue'; |
| | | import { EventSourceParserStream } from 'eventsource-parser/stream'; |
| | | import { |
| | | agentResetApi, |
| | |
| | | agentConversationSetApi, |
| | | agentConverDownloadApi, |
| | | downloadFile, |
| | | agentUploadApi, |
| | | } from '@/api/agentSession'; |
| | | import EventBus from '@/utils/EventBus'; |
| | | import useClipboard from 'vue-clipboard3'; |
| | | import { addSessionApi, getSessionDetailsApi } from '@/api/session'; |
| | | import pdfImg1 from '@/assets/session/PDF.png'; |
| | | import pdfImg2 from '@/assets/session/wps-write.png'; |
| | | import pdfImg3 from '@/assets/session/execl.png'; |
| | | import pdfImg4 from '@/assets/session/icon-txt.png'; |
| | | import pdfImg5 from '@/assets/session/txt.png'; |
| | | import tipImage from '@/assets/session/tip.png'; |
| | | import { userModelState } from '@/store'; |
| | | // import { Codemirror } from 'vue-codemirror'; |
| | | // import { javascript } from '@codemirror/lang-javascript'; |
| | | // import { oneDark } from '@codemirror/theme-one-dark'; |
| | | |
| | | import Prism from 'prismjs'; //导入代码高亮插件的core(里面提供了其他官方插件及代码高亮样式主题,你只需要引入即可) |
| | | import 'prismjs/themes/prism-tomorrow.min.css'; //引入代码高亮主题(这个去node_modules的安装prismjs中找到想使用的主题即可) |
| | | |
| | | const props = defineProps({ |
| | | modalObj: Object, |
| | | }); |
| | | |
| | | const modelStore = userModelState(); |
| | | |
| | | // const emit = defineEmits(['addSession']); |
| | | |
| | |
| | | role: 'assistant', |
| | | }, |
| | | ]); //根据会话id出来的会话详情 |
| | | const httpUrl = modelStore.hrefUrl; |
| | | const sessionList = ref([]); //会话列表 |
| | | const modalObj = reactive({}); |
| | | const dialogId = ref(''); |
| | |
| | | const conversation_id = ref(''); |
| | | const fieldNames = { value: 'id', label: 'name' }; |
| | | const agentObj = reactive({}); |
| | | const dialog_id = ref(''); |
| | | const getAent = ref(false); |
| | | const agentList = ref([]); |
| | | const selectValue = ref(''); |
| | | const sectionList = ref({}); |
| | |
| | | const isStopChat = ref(false); |
| | | const appStore = useAppStore(); |
| | | const sessionObj = reactive({}); |
| | | const uploaditemList = ref([]); |
| | | const prompts = ref([]); |
| | | |
| | | const theme = computed(() => { |
| | | return appStore.theme; |
| | | }); |
| | |
| | | |
| | | prompts.value = session.prompts; |
| | | activeSessionId.value = ''; |
| | | uploaditemList.value = []; |
| | | console.log(12123); |
| | | getAentId(session.id); |
| | | |
| | | Object.assign(agentObj, session); |
| | | from.name = session.name; |
| | | const dataSession = session.prompt_config; |
| | | if (dataSession.prologue) { |
| | | if (dataSession?.prologue) { |
| | | sessionDetailList.value[0].content = dataSession.prologue; |
| | | } |
| | | |
| | |
| | | loading.value = false; |
| | | inputMsg.value = ''; |
| | | }; |
| | | |
| | | //渲染文字 |
| | | const chartText = (val, sql) => { |
| | | console.log(val + sql, 77); |
| | | return val + '\n' + sql; |
| | | }; |
| | | |
| | | //获取图片地址 |
| | | const getImg = (val) => { |
| | | const id = val?.image_name; |
| | | |
| | | if (id) { |
| | | return ( |
| | | httpUrl + |
| | | '/api/v1/advanced-agent/download?file_id=' + |
| | | id + |
| | | '&app_id=excel_talk&file_type=image' |
| | | ); |
| | | } |
| | | }; |
| | | |
| | | // 调用get方法 |
| | | const queryAgentSessionDetails = async (id) => { |
| | | const { code, data } = await getSessionDetailsApi(id); |
| | |
| | | // nextTick(() => { |
| | | // sessionDetailList.value = data.dsl.messages; |
| | | // }); |
| | | |
| | | sessionDetailList.value = data.message; |
| | | |
| | | agentTitle.value = `${data.name}` || '未命名会话'; |
| | |
| | | inputMsg.value = text; |
| | | }; |
| | | |
| | | const getAentId = (id) => { |
| | | if (id == 'excel_talk') { |
| | | console.log(1); |
| | | getAent.value = false; |
| | | } |
| | | if (id == 'questions_talk') { |
| | | console.log(2); |
| | | getAent.value = true; |
| | | } |
| | | }; |
| | | |
| | | // 历史记录跳转获取agent会话详情 |
| | | const querySessionDetail = async (session) => { |
| | | conversation_id.value = session.id; |
| | | activeSessionId.value = session.id; |
| | | dialog_id.value = session.dialog_id; |
| | | console.log(4554); |
| | | getAentId(session.dialog_id); |
| | | from.name = session.name; |
| | | const { code, data } = await getSessionDetailsApi(session.id); |
| | | |
| | |
| | | |
| | | const sentClick = () => { |
| | | sendMessage('click'); |
| | | uploaditemList.value = []; |
| | | }; |
| | | |
| | | // 重新生成 |
| | |
| | | |
| | | // startChat(inputMsg.value); |
| | | // inputMsg.value = ''; |
| | | createSession(); |
| | | createSession(''); |
| | | } else { |
| | | Message.warning('消息不能为空'); |
| | | chatDis.value = false; |
| | |
| | | } |
| | | }; |
| | | //创建会话 |
| | | const createSession = async () => { |
| | | const createSession = async (val) => { |
| | | try { |
| | | loading.value = true; |
| | | chatDis.value = true; |
| | |
| | | // console.log(res.data.conversation_id); |
| | | activeSessionId.value = res.data?.id; |
| | | |
| | | startChat(inputMsg.value); |
| | | inputMsg.value = ''; |
| | | if (!val) { |
| | | startChat(inputMsg.value); |
| | | inputMsg.value = ''; |
| | | } else { |
| | | loading.value = false; |
| | | chatDis.value = false; |
| | | } |
| | | } |
| | | } else { |
| | | startChat(inputMsg.value); |
| | |
| | | }); |
| | | }; |
| | | |
| | | //下载xsl |
| | | const iconDownloadXsl = async (val) => { |
| | | await downloadFile({ |
| | | url: |
| | | `/api/v1/advanced-agent/download?file_id=` + |
| | | val.excel_name + |
| | | '&app_id=excel_talk&file_type=excel', |
| | | }); |
| | | }; |
| | | |
| | | //上传 |
| | | const selectFileCallback = async (resData, file) => { |
| | | console.log(111); |
| | | try { |
| | | const formData = new FormData(); |
| | | uploaditemList.value = resData; |
| | | if (!activeSessionId.value) { |
| | | await createSession(1); |
| | | } |
| | | |
| | | onFileSelectedLoading.value = true; |
| | | textName.value = '上传中'; |
| | | // for (let i = 0; i < file.length; i++) { |
| | | // formData.append('files', file[i].file); |
| | | // formData.append('conversation_id', activeSessionId.value); |
| | | // formData.append('app_id', agentObj.id); |
| | | // } |
| | | formData.append('files', file[0].file); |
| | | formData.append('conversation_id', activeSessionId.value); |
| | | formData.append('app_id', agentObj.id); |
| | | console.log(formData, 'formData'); |
| | | const { data, code } = await agentUploadApi(formData); |
| | | if (code === 200) { |
| | | onFileSelectedLoading.value = false; |
| | | textName.value = '上传成功'; |
| | | } |
| | | } catch (err) { |
| | | onFileSelectedLoading.value = false; |
| | | textName.value = '上传失败'; |
| | | Message.error('上传失败'); |
| | | } |
| | | }; |
| | | |
| | | const getIconByExten = (extension) => { |
| | | const fileExtension = ref(''); |
| | | fileExtension.value = extension.split('.').pop(); |
| | | let type = ''; |
| | | parser_idsArr.value.forEach((item) => { |
| | | // 包含元素 |
| | | if (item.formats.includes(fileExtension.value)) { |
| | | type = item.id; |
| | | } |
| | | }); |
| | | return type; |
| | | }; |
| | | |
| | | let onFileSelectedLoading = ref(true); |
| | | const textName = ref('上传成功'); |
| | | |
| | | const deleteFile = (item) => { |
| | | console.log(uploaditemList.value); |
| | | uploaditemList.value.splice(item.index, 1); |
| | | }; |
| | | const getIconByExtension = computed(() => (extension) => { |
| | | const fileExtension = ref(''); |
| | | fileExtension.value = extension.split('.').pop(); |
| | | switch (fileExtension.value) { |
| | | case 'pptx': |
| | | case 'ppt': |
| | | case 'pdf': |
| | | return pdfImg1; // PDF图标的URL |
| | | case 'docx': |
| | | case 'doc': |
| | | case 'wps': |
| | | return pdfImg2; // Word图标的URL |
| | | case 'xlsx': |
| | | case 'xls': |
| | | return pdfImg3; // Excel图标的URL |
| | | case 'txt': |
| | | return pdfImg4; // 文本文档图标的URL |
| | | default: |
| | | return pdfImg5; // 默认图标 |
| | | } |
| | | }); |
| | | |
| | | //聊天 |
| | | const startChat = async (valMsg) => { |
| | | sessionDetailList.value.push({ |
| | |
| | | let chatStr = { |
| | | id: activeSessionId.value, |
| | | message: valMsg, |
| | | app_id: agentObj.id, |
| | | }; |
| | | if (isHistory.value) { |
| | | chatStr.dsl = dsl; |
| | |
| | | isHistory.value = true; |
| | | querySessionDetail(data); |
| | | }); |
| | | setTimeout(() => { |
| | | Prism.highlightAll(); // 全局代码高亮 |
| | | }, 1000); |
| | | // Prism.highlightAll(); // 全局代码高亮 |
| | | }); |
| | | onBeforeUnmount(() => { |
| | | EventBus.off('createSeniorAgent'); |
| | |
| | | </script> |
| | | |
| | | <style scoped lang="scss"> |
| | | // @import 'prismjs/themes/prism.css'; |
| | | .dark { |
| | | color: gray !important; |
| | | } |
| | |
| | | |
| | | .center { |
| | | box-sizing: border-box; |
| | | height: calc(100vh - 200px); |
| | | height: calc(100vh - 140px); |
| | | position: relative; |
| | | |
| | | .center-title { |
| | |
| | | font-weight: 500; |
| | | } |
| | | .chat_bottom { |
| | | display: flex; |
| | | align-items: center; |
| | | // display: flex; |
| | | // align-items: center; |
| | | // width: 78%; |
| | | // margin: 0 auto; |
| | | width: 78%; |
| | | margin: 0 auto; |
| | | position: relative; |
| | | .center-bottom { |
| | | // position: absolute; |
| | | // width: 90%; |
| | |
| | | display: flex; |
| | | flex: 1 1; |
| | | flex-direction: column; |
| | | overflow: hidden; |
| | | // overflow: hidden; |
| | | position: relative; |
| | | // padding-top:10px; |
| | | :deep(.arco-textarea-wrapper) { |
| | |
| | | .btn-send { |
| | | position: absolute !important; |
| | | right: 4px; |
| | | top: 80px; |
| | | top: 90px; |
| | | z-index: 10; |
| | | } |
| | | |
| | | :deep(.arco-btn-size-large) { |
| | | height: 28px; |
| | | width: 50px; |
| | | width: 60px; |
| | | } |
| | | } |
| | | :deep(.arco-textarea-wrapper) { |
| | |
| | | } |
| | | .icon-user-jpg { |
| | | border: 1px solid #d9d9d9; |
| | | } |
| | | .codeStle { |
| | | .language { |
| | | color: #fff; |
| | | padding-left: 10px; |
| | | font-size: 14px; |
| | | height: 30px; |
| | | line-height: 30px; |
| | | background-color: #373739; |
| | | } |
| | | } |
| | | .prompt { |
| | | ul { |
| | |
| | | } |
| | | } |
| | | } |
| | | .fileList { |
| | | padding: 10px 0 !important; |
| | | margin-bottom: 0 !important; |
| | | :deep(.arco-comment-inner) { |
| | | line-height: 29px; |
| | | } |
| | | } |
| | | .uploadFileList { |
| | | width: 100%; |
| | | max-height: 140px; |
| | | overflow-y: auto; |
| | | padding: 10px; |
| | | display: flex; |
| | | flex-wrap: wrap; |
| | | margin-bottom: 100px; |
| | | :deep(.arco-comment-author) { |
| | | width: 110px; |
| | | display: inline-block; |
| | | overflow: hidden; /* 隐藏超出的内容 */ |
| | | text-overflow: ellipsis; /* 使用省略号来代替被隐藏的文字 */ |
| | | white-space: nowrap; /* 不换行,使内容在一行内显示 */ |
| | | } |
| | | :deep(.arco-spin-tip) { |
| | | margin-top: 0px; |
| | | } |
| | | } |
| | | .uploadFileDis { |
| | | :deep(.arco-upload-list-type-text) { |
| | | display: none; |
| | | } |
| | | } |
| | | |
| | | .action { |
| | | cursor: pointer; |