| | |
| | | <template> |
| | | <div class="container"> |
| | | <div class="container" id="container"> |
| | | <!-- <AddSession--> |
| | | <!-- :modalObj="modalObj"--> |
| | | <!-- @addSession="addSession"--> |
| | |
| | | <!-- <span class="title">{{ agentTitle }}</span>--> |
| | | |
| | | <a-popover position="bottom" trigger="click"> |
| | | <a-button border |
| | | <a-button border> |
| | | <span |
| | | style=" |
| | | width: 100px; |
| | | overflow: hidden; |
| | | text-overflow: ellipsis; |
| | | white-space: nowrap; |
| | | " |
| | | >{{ from.name }}</span |
| | | > |
| | | <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> |
| | |
| | | ref="scrollbar" |
| | | id="home" |
| | | class="chat-list" |
| | | style=" |
| | | width: 80%; |
| | | overflow: auto; |
| | | height: calc(100vh - 380px); |
| | | margin: 0px auto 20px; |
| | | " |
| | | style="width: 80%; overflow: auto; margin: 0px auto 20px" |
| | | :style="{ |
| | | height: |
| | | uploaditemList.length > 0 |
| | | ? 'calc(100vh - 480px)' |
| | | : 'calc(100vh - 380px)', |
| | | }" |
| | | > |
| | | <div |
| | | class="chat-item" |
| | |
| | | /> |
| | | </template> |
| | | <template #content> |
| | | <div :class="{ chartUserText: theme === 'light' }" |
| | | >{{ sessionDetail.content }} |
| | | <div :class="{ chartUserText: theme === 'light' }"> |
| | | {{ sessionDetail.content }} |
| | | <!-- <a-input |
| | | :style="{ width: '100%' }" |
| | | v-model="sessionDetail.content" |
| | | v-if="isEdit" |
| | | /> |
| | | |
| | | <div v-else> |
| | | {{ sessionDetail.content }} |
| | | </div> --> |
| | | </div> |
| | | <!-- <div v-if="!isEdit"> |
| | | <span |
| | | class="action" |
| | | v-if="index != 0" |
| | | @click="copy(sessionDetail.content)" |
| | | > |
| | | <icon-copy /> 复制 |
| | | </span> |
| | | <span class="action" @click="edit()"> |
| | | <icon-pen /> 编辑 |
| | | </span> |
| | | </div> |
| | | <a-space v-else> |
| | | <a-button type="outline" size="mini" @click="cancelEdit(1)" |
| | | >取消</a-button |
| | | > |
| | | <a-button type="primary" size="mini" @click="cancelEdit(2)" |
| | | >确定</a-button |
| | | > |
| | | </a-space> --> |
| | | </template> |
| | | </a-comment> |
| | | <a-comment v-else-if="sessionDetail.role === 'assistant'"> |
| | | <template #avatar> |
| | | <img |
| | | class="icon-user-jpg" |
| | | src="../../assets/images/icon-chart.png" |
| | | src="../../assets/images/icon-picture.png" |
| | | alt="本地图片" |
| | | /> |
| | | </template> |
| | | <template #content> |
| | | <!-- <a-card :class="{ chatItemAnswer: theme === 'light' }">--> |
| | | <!-- <div--> |
| | | <!-- :class="{ light: theme === 'light' }"--> |
| | | <!-- v-html="sessionDetail.content.replace(/\n/g, '<br/>')"--> |
| | | <!-- >--> |
| | | <!-- </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> |
| | | <a-card v-if="isExistTip(sessionDetail.content)" style="padding: 10px"> |
| | | <div |
| | | :class="{ chatItemAnswer: theme === 'light' }" |
| | | :style="{ |
| | | backgroundColor: |
| | | theme === 'light' ? '#ffffff' : '#000000', |
| | | }" |
| | | style="border: none" |
| | | v-for="(breakContent, breakIndex) in breakLine( |
| | | sessionDetail.content |
| | | )" |
| | | > |
| | | <div |
| | | :class="{ chatItemAnswer: theme === 'light' }" |
| | | :style="{ |
| | | backgroundColor: |
| | | theme === 'light' ? '#ffffff' : '#000000', |
| | | }" |
| | | style="border: none" |
| | | v-if="isExistTip(breakContent)" |
| | | > |
| | | <div |
| | | :class="{ chatItemAnswer: theme === 'light' }" |
| | | :style="{ |
| | | backgroundColor: |
| | | theme === 'light' ? '#ffffff' : '#000000', |
| | | }" |
| | | style="border: none" |
| | | v-for="(item, tipIndex) in tipMatch(breakContent)" |
| | | > |
| | | <span v-if="tipIndex == 0"> |
| | | {{ breakContent.substring(0, item.index) }} |
| | | <a-tooltip |
| | | background-color="#3491FA" |
| | | :content=" |
| | | getTipContent(messagenList.reference, index) |
| | | " |
| | | > |
| | | <img |
| | | style="width: 15px; height: 15px" |
| | | :src="tipImage" |
| | | /> |
| | | </a-tooltip> |
| | | <span v-if="tipIndex == item.len - 1"> |
| | | {{ breakContent.substring(item.index + 5) }} |
| | | </span> |
| | | </span> |
| | | <span v-else-if="tipIndex == item.len - 1"> |
| | | {{ |
| | | breakContent.substring( |
| | | item.preIndex + item.item.length, |
| | | item.index |
| | | ) |
| | | }} |
| | | <a-tooltip |
| | | background-color="#3491FA" |
| | | :content=" |
| | | getTipContent(messagenList.reference, index) |
| | | " |
| | | > |
| | | <img |
| | | style="width: 15px; height: 15px" |
| | | :src="tipImage" |
| | | /> |
| | | </a-tooltip> |
| | | {{ breakContent.substring(item.index + 5) }} |
| | | </span> |
| | | <span v-else> |
| | | {{ |
| | | breakContent.substring( |
| | | item.preIndex + item.item.length, |
| | | item.index |
| | | ) |
| | | }} |
| | | <a-tooltip |
| | | background-color="#3491FA" |
| | | :content=" |
| | | getTipContent(messagenList.reference, index) |
| | | " |
| | | > |
| | | <img |
| | | style="width: 15px; height: 15px" |
| | | :src="tipImage" |
| | | /> |
| | | </a-tooltip> |
| | | </span> |
| | | </div> |
| | | </div> |
| | | <div v-else> |
| | | {{ breakContent }} |
| | | </div> |
| | | </div> |
| | | </a-card> |
| | | <a-card v-else> |
| | | <a-textarea |
| | | readonly |
| | | auto-size |
| | | :default-value="chartText(sessionDetail.content)" |
| | | :class="{ chatItemAnswer: theme === 'light' }" |
| | | :style="{ |
| | | backgroundColor: |
| | | theme === 'light' ? '#ffffff' : '#000000', |
| | | }" |
| | | style="border: none" |
| | | > |
| | | </a-textarea> |
| | | </a-card> |
| | | <!-- <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> |
| | | <!-- <div>{{ sessionDetail.role === 'assistant' }}</div> --> |
| | | |
| | | <template #actions> |
| | | <!-- <div |
| | | v-for="(item, leng) in messagenList.reference" |
| | | :key="leng" |
| | | > --> |
| | | |
| | | <div> |
| | | <div> |
| | | <template |
| | |
| | | > |
| | | <icon-refresh /> 重新生成 |
| | | </span> |
| | | <!-- <span class="action"><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-chart.png" |
| | | 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> |
| | | <a-spin :loading="chartLoading" dot style="width: 100%"> |
| | | <a-textarea |
| | | readonly |
| | | auto-size |
| | | v-model="displayedText" |
| | | :class="{ chatItemAnswer: theme === 'light' }" |
| | | :style="{ |
| | | backgroundColor: |
| | | theme === 'light' ? '#ffffff' : '#000000', |
| | | }" |
| | | style="border: none" |
| | | > |
| | | </a-textarea> |
| | | </a-spin> |
| | | </template> |
| | | |
| | | <template #actions> |
| | | <!-- <div class="icon-box"> |
| | | <div> |
| | | <img :src="getIconByExtension('pdf')" alt="" /> |
| | | </div> |
| | | <div class="icon-text"> 文件类型 </div> |
| | | </div> --> |
| | | |
| | | <div |
| | | class="action" |
| | | @click="stopChat" |
| | |
| | | </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="sendMessage" |
| | | style="height: 180px" |
| | | placeholder="输入您想了解的内容,Shift+Enter发送" |
| | | :max-length="500" |
| | | allow-clear |
| | | show-word-limit |
| | | > |
| | | </a-textarea> --> |
| | | |
| | | <a-textarea |
| | | v-model="inputMsg" |
| | | @keydown.shift.enter="handleShiftEnter" |
| | | @keydown.enter="sendMessage" |
| | | placeholder="输入您想了解的内容,Shift+Enter换行,Enter发送" |
| | | :placeholder=" |
| | | uploaditemList.length > 0 |
| | | ? '整理这些文件的核心内容' |
| | | : '输入您想了解的内容,Shift+Enter换行,Enter发送' |
| | | " |
| | | allow-clear |
| | | show-word-limit |
| | | :disabled="chatDis" |
| | |
| | | maxRows: 5, |
| | | }" |
| | | /> |
| | | <div style="width: 100%;display: flex;justify-content: space-between"> |
| | | <a-button |
| | | :disabled="onFileSelectedLoading" |
| | | @click="selectFile" |
| | | type="text" |
| | | style="border-radius: 24px" |
| | | > |
| | | <icon-attachment |
| | | size="28" |
| | | style="color: #0960bd" |
| | | /> |
| | | <input |
| | | ref="fileInput" |
| | | type="file" |
| | | style="display: none" |
| | | @change="onFileSelected" |
| | | /> |
| | | </a-button> |
| | | <span |
| | | style="cursor: pointer;margin-left: 20px;"> |
| | | </span> |
| | | <div |
| | | style=" |
| | | width: 100%; |
| | | display: flex; |
| | | justify-content: space-between; |
| | | " |
| | | class="uploadFileDis" |
| | | > |
| | | <updataFile |
| | | ref="fileInput" |
| | | :sessionId="activeSessionId" |
| | | :hide="hide_upload" |
| | | @selectFileCallback="selectFileCallback" |
| | | ></updataFile> |
| | | |
| | | <a-button |
| | | :disabled="chatDis" |
| | | @click="sentClick" |
| | |
| | | <icon-send size="32" style="color: #0960bd" /> |
| | | </a-button> |
| | | </div> |
| | | <!-- <div class="btn-send">--> |
| | | <!-- <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> |
| | | <!-- <div style="margin-top: 0px">--> |
| | | <!-- <a-upload--> |
| | | <!-- ref="uploadRef"--> |
| | | <!-- :file-list="uploadList"--> |
| | | <!-- :limit="1"--> |
| | | <!-- multiple--> |
| | | <!-- :custom-request="customRequest"--> |
| | | <!-- style="font-size: 24px;margin-bottom: 10px;position: relative;width: 200px">--> |
| | | <!-- <template #upload-button>--> |
| | | <!-- <icon-attachment style="color: #0960bd;position: absolute;top:-50px;left: 20px;z-index: 10000"/>--> |
| | | <!-- </template>--> |
| | | <!-- </a-upload>--> |
| | | <!-- </div>--> |
| | | <!-- <span--> |
| | | <!-- style="--> |
| | | <!-- position: absolute;--> |
| | | <!-- top: 94px;--> |
| | | <!-- left: 20px;--> |
| | | <!-- z-index: 999;--> |
| | | <!-- cursor: pointer;--> |
| | | <!-- "--> |
| | | <!-- >--> |
| | | <!-- <icon-attachment--> |
| | | <!-- size="28"--> |
| | | <!-- @click="selectFile"--> |
| | | <!-- style="color: #0960bd"--> |
| | | <!-- />--> |
| | | <!-- <input--> |
| | | <!-- ref="fileInput"--> |
| | | <!-- type="file"--> |
| | | <!-- style="display: none"--> |
| | | <!-- @change="onFileSelected"--> |
| | | <!-- />--> |
| | | <!-- </span>--> |
| | | <div class="uploadFileList"> |
| | | <div class="uploadFileList" v-if="uploaditemList.length > 0"> |
| | | <div |
| | | class="files" |
| | | v-for="(item, index) in uploaditemList" |
| | | :key="index" |
| | | style="position: relative; width: 200px; margin-top: 10px" |
| | | style=" |
| | | position: relative; |
| | | width: 200px; |
| | | margin-top: 10px; |
| | | margin-right: 20px; |
| | | " |
| | | > |
| | | <a-comment |
| | | :author="item.name" |
| | | :content="(item.size/1024).toFixed(2) + 'K'" |
| | | :content="item.size" |
| | | style=" |
| | | background: var(--color-bg-2); |
| | | padding: 10px; |
| | |
| | | </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> |
| | | <!-- <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 |
| | |
| | | ></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 v-if="documenttype == 'docx'" :previewSrc="previewSrc"></docx> |
| | | <excel v-if="documenttype == ('xlsx' || 'xls')" :previewSrc="previewSrc"></excel> |
| | | <Pdf v-if="documenttype == 'pdf'" :previewSrc="previewSrc"></Pdf> |
| | | <txt v-if="documenttype == 'txt'" :previewSrc="previewSrc"></txt> |
| | | </a-modal> |
| | | <a-modal |
| | | v-model:visible="visible" |
| | | title="修改名称" |
| | |
| | | :footer="false" |
| | | title-align="start" |
| | | > |
| | | <a-form |
| | | ref="formRef" |
| | | :rules="rules" |
| | | :model="from" |
| | | @submit="handleSubmit" |
| | | > |
| | | <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> |
| | |
| | | </div> |
| | | </template> |
| | | <script setup lang="ts"> |
| | | import { |
| | | IconClose, |
| | | IconSearch, |
| | | IconTiktokColor, |
| | | } from '@arco-design/web-vue/es/icon'; |
| | | import { useAppStore, useUserStore } from '@/store'; |
| | | import { useAppStore, userModelState, useUserStore } from '@/store'; |
| | | import { |
| | | computed, |
| | | nextTick, |
| | |
| | | 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 setName from '@/views/sessionManager/components/setName.vue'; |
| | | import updataFile from '@/views/sessionManager/components/updataFile.vue'; |
| | | |
| | | import EventBus from '@/utils/EventBus'; |
| | | import { |
| | | addSessionApi, |
| | |
| | | getSessionDetailsApi, |
| | | sessionListApi, |
| | | uploadWithoutKb, |
| | | uploadAndParse, |
| | | chatInfos, |
| | | chatRm, |
| | | } from '@/api/session'; |
| | | import { getAuthorization } from '@/utils/auth'; |
| | | import { queryCanvasList } from '@/api/Agent'; |
| | |
| | | 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 docx from '@/views/dmx/knowledgeLib/components/docx.vue'; |
| | | import excel from '@/views/dmx/knowledgeLib/components/excel.vue'; |
| | | import Pdf from '@/views/dmx/knowledgeLib/components/Pdf.vue'; |
| | | import txt from '@/views/dmx/knowledgeLib/components/txt.vue'; |
| | | import { is } from 'immutable'; |
| | | import uploadFile from './components/uploadFile.vue'; |
| | | |
| | | // const url = ref('../../assets/session/PDF.png'); |
| | | |
| | | const sessionDetailList = ref([]); //根据会话id出来的会话详情 |
| | | const sessionDetailList = ref([ |
| | | { |
| | | content: '你好! 我是你的助理,有什么可以帮到你的吗?', |
| | | role: 'assistant', |
| | | }, |
| | | ]); //根据会话id出来的会话详情 |
| | | const messagenList = ref({}); |
| | | const sessionList = ref([]); //会话列表 |
| | | const modalObj = reactive({ add: false }); |
| | | const dialogId = ref(''); |
| | | const chatDis = ref(false); |
| | | const chartLoading = ref(false); |
| | | const loading = ref(false); |
| | | const agentType = ref('1'); |
| | | const agentTitle = ref('未命名会话'); |
| | | let chatObj = reactive({}); |
| | | let from = reactive({ |
| | | name:'未命名会话', |
| | | name: '未命名会话', |
| | | }); |
| | | const isStopChat = ref(false); |
| | | |
| | | const currIndex = ref(0); |
| | | const displayedText = ref(''); // 正在显示的文字 |
| | | let timer: number | null = null; |
| | | const streamStr = ref(''); |
| | | const inputMsg = ref(''); |
| | | const activeSessionId = ref(''); |
| | | const hide_upload=ref(2); |
| | | const fieldNames = { value: 'id', label: 'name' }; |
| | | const dialogs = ref([]); |
| | | const dialogObj = reactive({}); |
| | |
| | | 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); |
| | | let toStop = false; |
| | | let documenttype = ref('docx'); |
| | | let previewSrc = ref(''); |
| | | |
| | | const modelStore = userModelState(); |
| | | const httpUrl = modelStore.hrefUrl; |
| | | |
| | | const rules = { |
| | | name: [ |
| | |
| | | if (errors) return; |
| | | let chatData = { |
| | | id: chatObj.id, |
| | | conversation_id: chatObj.id, |
| | | name: from.name, |
| | | dialog_id: chatObj.dialog_id, |
| | | conversation_desc: from.name, |
| | | }; |
| | | const { code, data } = await addSessionApi(chatData); |
| | | if (data) { |
| | | Message.success('修改成功'); |
| | | handleCancel(); |
| | | if (data?.id) { |
| | | activeSessionId.value = data.id; |
| | | } |
| | | queryNewSessionDetail(activeSessionId.value); |
| | | } |
| | | }; |
| | | let dataItem = []; |
| | | const isExistTip = (message: string): boolean => { |
| | | if (/##[0-9]\$\$/.test(message)) { |
| | | return true; |
| | | } else { |
| | | return false; |
| | | } |
| | | }; |
| | | |
| | | const breakLine = (message: string): string[] => { |
| | | //按\n分割字符串 |
| | | let arr = message.split('\n'); |
| | | return arr; |
| | | }; |
| | | |
| | | const chartText = (message: string): string => { |
| | | //去除所有的#和** |
| | | let arr = message.replace(/\*\*|\#\#\#/g, ''); |
| | | return arr; |
| | | }; |
| | | |
| | | const tipMatch = (msg: string): any[] => { |
| | | //match session.content中的##[0-9]$$的索引 |
| | | |
| | | let indexs: any[] = []; |
| | | let preTip = 0; |
| | | let matches = msg.match(/##([0-9]+)\$\$/g); |
| | | matches?.map((item) => { |
| | | let i = msg.indexOf(item); |
| | | indexs.push({ |
| | | index: i, |
| | | item: item, |
| | | preIndex: preTip, |
| | | len: matches.length, |
| | | }); |
| | | preTip = i; |
| | | }); |
| | | return indexs; |
| | | }; |
| | | |
| | | const getTxt = (data, role, message, index) => { |
| | | if (/##0\$\$/.test(message)) { |
| | | if (isExistTip(message)) { |
| | | if (role == 'assistant' && index) { |
| | | data.forEach((item) => { |
| | | if (Object.keys(item).length !== 0 && item?.doc_aggs.length > 0) { |
| | | dataItem = item.doc_aggs; |
| | | } |
| | | }); |
| | | let i = index / 2 - 1 > 0 ? index / 2 - 1 : 0; |
| | | if (data.length == 1) { |
| | | i = 0; |
| | | } |
| | | if (data.length == i) { |
| | | i = data.length-1; |
| | | } |
| | | dataItem = data[i].doc_aggs; |
| | | } |
| | | } else { |
| | | dataItem = []; |
| | |
| | | return dataItem; |
| | | }; |
| | | |
| | | const clickHref = (item) => { |
| | | // return Message.warning('暂无法查看'); |
| | | window.open(`/api/v1/document/show/${item.doc_id}`, '_blank'); |
| | | const getTipContent = (data, index): string => { |
| | | let maxSimilarityContent = ''; |
| | | let i = index / 2 - 1 > 0 ? index / 2 - 1 : 0; |
| | | if (data.length == 1) { |
| | | i = 0; |
| | | } |
| | | if (data.length == i) { |
| | | i = data.length-1; |
| | | } |
| | | let maxSimilarity = 0; |
| | | data[i].chunks.forEach((chunk) => { |
| | | if (chunk.similarity > maxSimilarity) { |
| | | maxSimilarity = chunk.similarity; |
| | | maxSimilarityContent = chunk.content_with_weight; |
| | | } |
| | | }); |
| | | return maxSimilarityContent; |
| | | }; |
| | | |
| | | const clickHref = async (item) => { |
| | | documenttype.value = item.doc_name.split('.').pop(); |
| | | previewSrc.value = httpUrl + `/api/v1/document/get/${item.doc_id}`+"?t="+new Date().getTime(); |
| | | fileVisible.value = true; |
| | | }; |
| | | |
| | | 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); |
| | | }; |
| | | |
| | | const getIconByExtension = computed(() => (extension) => { |
| | |
| | | // formRef.value.resetFields(); |
| | | }; |
| | | |
| | | const selectFile = () => { |
| | | fileInput.value.click(); |
| | | const selectFileCallback = (data,conversation_id) => { |
| | | uploaditemList.value = [...uploaditemList.value, ...data]; |
| | | activeSessionId.value = conversation_id; |
| | | }; |
| | | |
| | | let onFileSelectedLoading = ref(false); |
| | | const onFileSelected = (event) => { |
| | | const file = event.target.files[0]; |
| | | uploaditemList.value = [ |
| | | { |
| | | name: file.name, |
| | | size: file.size, |
| | | }, |
| | | ]; |
| | | if (file) { |
| | | onFileSelectedLoading.value = true; |
| | | const formData = new FormData(); |
| | | formData.append('file', file); |
| | | formData.append('conversation_id', activeSessionId.value); |
| | | uploadWithoutKb(formData).then((res) => { |
| | | // console.log(res); |
| | | if (res.code == 200) { |
| | | console.log(res); |
| | | console.log(uploaditemList.value); |
| | | onFileSelectedLoading.value = false; |
| | | fileInput.value.value = ''; |
| | | uploaditemList.value = []; |
| | | Message.success('上传成功'); |
| | | } else { |
| | | Message.error('上传失败'); |
| | | } |
| | | }); |
| | | |
| | | //上传成功解析getinfo |
| | | const getInfo = async (id) => { |
| | | const { code, data } = await chatInfos({ |
| | | doc_ids: activeSessionId.value, |
| | | }); |
| | | if (code === 200) { |
| | | uploaditemList.value = data; |
| | | } |
| | | }; |
| | | //删除上传文档 |
| | | const deleteUpload = async (id) => { |
| | | const { code, data } = await chatRm({ |
| | | doc_id: id, |
| | | }); |
| | | if (code === 200) { |
| | | getInfo(); |
| | | } |
| | | }; |
| | | |
| | | let onFileSelectedLoading = ref(false); |
| | | |
| | | const deleteFile = (item) => { |
| | | console.log(uploaditemList.value); |
| | | uploaditemList.value = []; |
| | | uploaditemList.value.splice(item.index, 1); |
| | | // EventBus.emit('queryAgent', item); |
| | | }; |
| | | |
| | | const { toClipboard } = useClipboard(); |
| | |
| | | await toClipboard(text); //参数为要复制的文本 |
| | | }; |
| | | |
| | | const onChange = (fileList) => { |
| | | // files.value = fileList; |
| | | const isEdit = ref(false); |
| | | const edit = () => { |
| | | isEdit.value = !isEdit.value; |
| | | }; |
| | | |
| | | // 上传文件 |
| | | const customRequest = async (option) => { |
| | | const { onProgress, onError, onSuccess, fileItem, name } = option; |
| | | fileItem.status = 'ready'; |
| | | if (fileItem.file) { |
| | | const formData = new FormData(); |
| | | formData.append('file', fileItem.file); |
| | | formData.append('conversation_id', activeSessionId.value); |
| | | uploadWithoutKb(formData).then((res) => { |
| | | // console.log(res); |
| | | if (res.code == 200) { |
| | | console.log(res); |
| | | console.log(uploadList.value); |
| | | fileItem.status = 'done'; |
| | | // uploadList.value = []; |
| | | } else { |
| | | fileItem.status = 'error'; |
| | | } |
| | | }); |
| | | const cancelEdit = (val) => { |
| | | if (val == 1) { |
| | | isEdit.value = !isEdit.value; |
| | | } else { |
| | | //编辑保存 |
| | | isEdit.value = !isEdit.value; |
| | | } |
| | | }; |
| | | |
| | |
| | | event.preventDefault(); |
| | | inputMsg.value += '\n'; |
| | | }; |
| | | const dialogChange = (val) => { |
| | | // 判断当前是智能体或agent |
| | | // console.log(val, 'val'); |
| | | dialogId.value = val; |
| | | dialogs.value.forEach((item) => { |
| | | if (item.id === val) { |
| | | Object.assign(dialogObj, item); |
| | | } |
| | | }); |
| | | console.log(dialogObj.type, 'dialogObj'); |
| | | if (dialogObj.type == 1) { |
| | | agentType.value = '1'; |
| | | querySessionList(); |
| | | } else { |
| | | agentType.value = '2'; |
| | | queryAgentSessionList(); |
| | | } |
| | | |
| | | // querySessionList(); |
| | | }; |
| | | |
| | | // 发送 |
| | | const sentClick = () => { |
| | | displayedText.value=""; |
| | | sendMessage('click'); |
| | | uploaditemList.value = []; |
| | | }; |
| | | // 重新生成 |
| | | const reGenerate = () => { |
| | |
| | | event.preventDefault(); // 阻止默认行为,即不换行 |
| | | } |
| | | |
| | | // if (!activeSessionId.value) { |
| | | // Message.warning("请选择会话"); |
| | | // chatDis.value = false; |
| | | // loading.value = false; |
| | | // return; |
| | | // } |
| | | |
| | | // if (displayedText.value) { |
| | | // querySessionList(); |
| | | // } |
| | | |
| | | if (inputMsg.value) { |
| | | startChat(inputMsg.value); |
| | | |
| | | inputMsg.value = ''; |
| | | if (!activeSessionId.value) { |
| | | //新建会话 |
| | | // 如果有会话id |
| | | console.log(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('创建会话失败,请重试'); |
| | | } |
| | | } else { |
| | | startChat(inputMsg.value); |
| | | inputMsg.value = ''; |
| | | } |
| | | } else { |
| | | Message.warning('消息不能为空'); |
| | | } |
| | |
| | | } |
| | | }; |
| | | |
| | | let message_stop = []; |
| | | let message_id = ""; |
| | | const startChat = async (valMsg) => { |
| | | chatDis.value = true; |
| | | loading.value = true; |
| | | toStop = false; |
| | | displayedText.value = ''; |
| | | chartLoading.value = true; |
| | | sessionDetailList.value.push({ |
| | | content: valMsg, |
| | | role: 'user', |
| | |
| | | .getReader(); |
| | | currIndex.value = 0; |
| | | while (true) { |
| | | if (toStop) { |
| | | message_stop.push(message_id); |
| | | setChatDataMeg(chatDataMeg); |
| | | //displayedText.value = ''; |
| | | break; |
| | | } |
| | | const x = await reader?.read(); |
| | | if (x) { |
| | | const { done, value } = x; |
| | |
| | | try { |
| | | const val = JSON.parse(value?.data || ''); |
| | | const d = val?.data; |
| | | if (message_id != d.message_id) { |
| | | message_id = d.message_id; |
| | | message_stop = []; |
| | | } else { |
| | | //message_stop中查找message_id |
| | | const index = message_stop.findIndex(item => item === message_id); |
| | | if (index > -1) { |
| | | break; |
| | | } |
| | | } |
| | | if (typeof d !== 'boolean') { |
| | | // console.info("data:", d); |
| | | streamStr.value = d.content; |
| | | chartLoading.value = false; |
| | | startDisplayStr(); |
| | | } |
| | | } catch (e) { |
| | |
| | | if (done) { |
| | | console.info('done'); |
| | | displayedText.value = ''; |
| | | if (isStopChat.value) { |
| | | setChatDataMeg(chatDataMeg); |
| | | } else { |
| | | queryNewSessionDetail(activeSessionId.value); |
| | | EventBus.emit('queryAppUsageList'); |
| | | } |
| | | chartLoading.value = false; |
| | | queryNewSessionDetail(activeSessionId.value); |
| | | EventBus.emit('queryAppUsageList'); |
| | | break; |
| | | } |
| | | } |
| | |
| | | }; |
| | | |
| | | const stopChat = async () => { |
| | | // const { code, data } = await stopChatApi(activeSessionId.value); |
| | | // if (code === 200) { |
| | | // Message.success("已停止"); |
| | | // queryNewSessionDetail(activeSessionId.value); |
| | | // } |
| | | loading.value = false; |
| | | chatDis.value = false; |
| | | isStopChat.value = true; |
| | | toStop = true; |
| | | console.log('stopChat'); |
| | | console.log(displayedText.value, 'displayedText'); |
| | | console.log(sessionDetailList.value, 'sessionDetailList'); |
| | |
| | | sessionDetailList.value = sessionDetailList.value |
| | | .splice(0, sessionDetailList.value.length - 2) |
| | | .concat(lastArr); |
| | | |
| | | console.log(sessionDetailList.value, 'sessionDetailList2'); |
| | | console.log(chatObj, 'chatObj对象'); |
| | | chatObj.message = chatObj.message.concat(lastArr); |
| | | if (chatObj?.message) { |
| | | chatObj.message = chatObj.message.concat(lastArr); |
| | | } |
| | | Object.assign(chatDataMeg, { |
| | | id: chatObj.id, |
| | | conversation_id: chatObj.id, |
| | |
| | | agentTitle.value = data.name; |
| | | from.name = data.name; |
| | | refreshScroll(); //刷新滚动条位置 |
| | | isStopChat.value = false; |
| | | } |
| | | }; |
| | | |
| | | const changeAgentType = (val, session) => { |
| | | hide_upload.value = hide_upload.value+1; |
| | | uploaditemList.value=[]; |
| | | agentType.value = val; |
| | | console.log(val, 'val'); |
| | | }; |
| | |
| | | from.name = session.name; |
| | | const { code, data } = await getSessionDetailsApi(session.id); |
| | | if (code === 200) { |
| | | Object.assign(chatObj, data); |
| | | sessionDetailList.value = data.message; |
| | | messagenList.value = data; |
| | | refreshScroll(); //刷新滚动条位置 |
| | |
| | | querySessionList(); |
| | | }; |
| | | onBeforeMount(() => { |
| | | // DialogList(); |
| | | //新建会话 |
| | | createSession(''); |
| | | activeSessionId.value = ''; |
| | | }); |
| | | onMounted(() => { |
| | | document.getElementsByTagName; |
| | | let container = document.getElementById('container'); |
| | | container.addEventListener('click', () => { |
| | | // fileInput.value.cancel(); |
| | | }); |
| | | EventBus.on('newChat', () => { |
| | | uploaditemList.value = []; |
| | | agentType.value = '1'; |
| | | createSession(''); |
| | | chatObj = {}; |
| | | hide_upload.value = hide_upload.value+1; |
| | | // createSession(''); |
| | | activeSessionId.value = ''; |
| | | sessionDetailList.value = [ |
| | | { |
| | | content: '你好! 我是你的助理,有什么可以帮到你的吗?', |
| | | role: 'assistant', |
| | | }, |
| | | ]; |
| | | from.name = '未命名会话'; |
| | | }); |
| | | }); |
| | | onBeforeUnmount(() => { |
| | |
| | | font-size: 12px; |
| | | padding-left: 10px; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | // .uploadFileDis { |
| | | // :deep(.arco-upload-list-type-text) { |
| | | // display: none; |
| | | // } |
| | | // } |
| | | .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; |
| | | } |
| | | } |
| | | } |
| | |
| | | } |
| | | } |
| | | } |
| | | .uploadFileDis { |
| | | :deep(.arco-upload-list-type-text) { |
| | | display: none; |
| | | } |
| | | } |
| | | |
| | | .chat-item { |
| | | padding: 10px 0; |
| | |
| | | font-size: 14px; |
| | | color: #333; |
| | | margin-top: 4px; |
| | | } |
| | | :deep(.arco-card-body) { |
| | | padding: 0; |
| | | border-radius: 10px; |
| | | } |
| | | :deep(.arco-textarea) { |
| | | padding-top: 10px !important; |
| | | } |
| | | :deep(.arco-comment-inner-content) { |
| | | border-radius: 10px; |
| | | } |
| | | :deep(.arco-card-bordered) { |
| | | border-radius: 10px; |
| | | } |
| | | |
| | | .icon-user-jpg { |
| | |
| | | .icon-text { |
| | | margin-left: 10px; |
| | | } |
| | | } |
| | | :deep(.arco-spin-loading .arco-spin-mask-icon) { |
| | | left: 10%; |
| | | } |
| | | } |
| | | |
| | |
| | | :deep(.arco-upload-list-item-operation) { |
| | | //display: none; |
| | | } |
| | | .uploadFileList { |
| | | width: 100%; |
| | | max-height: 140px; |
| | | overflow-y: auto; |
| | | padding: 10px; |
| | | display: flex; |
| | | flex-wrap: wrap; |
| | | :deep(.arco-comment-author) { |
| | | width: 100px; |
| | | display: inline-block; |
| | | overflow: hidden; /* 隐藏超出的内容 */ |
| | | text-overflow: ellipsis; /* 使用省略号来代替被隐藏的文字 */ |
| | | white-space: nowrap; /* 不换行,使内容在一行内显示 */ |
| | | } |
| | | } |
| | | </style> |