|
@@ -5,37 +5,40 @@
|
|
|
<pageMask />
|
|
|
</div>
|
|
|
<!-- 消息列表 -->
|
|
|
- <el-scrollbar v-else class="message-list" ref="scrollbar">
|
|
|
- <div class="messages">
|
|
|
- <div v-for="(message, index) in messages" :key="index"
|
|
|
- :class="['message-item', message.isSelf ? 'self' : 'other']">
|
|
|
- <el-avatar :size="32" :src="message.avatar" />
|
|
|
- <div class="message-content">
|
|
|
- <div class="content" v-if="!message.isSelf" :class="{ 'loading-content': message.content === '' }">
|
|
|
- <span v-html="message.content"></span>
|
|
|
- <span class="loading-indicator" v-if="sendLoading && index === messages.length - 1">
|
|
|
+ <div class="message-list" v-else>
|
|
|
+ <el-scrollbar ref="scrollbar" @scroll="handleScroll">
|
|
|
+ <div class="messages">
|
|
|
+ <div v-for="(message, index) in messages" :key="index"
|
|
|
+ :class="['message-item', message.isSelf ? 'self' : 'other']">
|
|
|
+ <el-avatar :size="32" :src="message.avatar" />
|
|
|
+ <div class="message-content">
|
|
|
+ <div class="content" v-if="!message.isSelf" :class="{ 'loading-content': message.content === '' }">
|
|
|
+ <span v-html="message.content"></span>
|
|
|
+ <span class="loading-indicator" v-if="sendLoading && index === messages.length - 1">
|
|
|
<span class="dot"></span>
|
|
|
<span class="dot"></span>
|
|
|
<span class="dot"></span>
|
|
|
</span>
|
|
|
- </div>
|
|
|
- <document v-else-if="message.type === 'document' && message.isSelf" :content="message.content"
|
|
|
- :rawContent="message.rawContent" />
|
|
|
- <div v-else class="content">
|
|
|
- <span v-if="message.type === ''">{{ message.content }}</span>
|
|
|
- <span class="loading-indicator" v-if="sendLoading && index === messages.length - 1">
|
|
|
+ </div>
|
|
|
+ <document v-else-if="message.type === 'document' && message.isSelf" :content="message.content"
|
|
|
+ :rawContent="message.rawContent" />
|
|
|
+ <div v-else class="content">
|
|
|
+ <span v-if="message.type === ''">{{ message.content }}</span>
|
|
|
+ <span class="loading-indicator" v-if="sendLoading && index === messages.length - 1">
|
|
|
<span class="dot"></span>
|
|
|
<span class="dot"></span>
|
|
|
<span class="dot"></span>
|
|
|
</span>
|
|
|
- </div>
|
|
|
- <div class="timestamp ">{{ moment(message.timestamp).format('MM-DD HH:mm') }}
|
|
|
- <span v-if="message.add" style="cursor: pointer;" @click="handleInput">填充</span>
|
|
|
+ </div>
|
|
|
+ <div class="timestamp ">{{ moment(message.timestamp).format('MM-DD HH:mm') }}
|
|
|
+ <span v-if="message.add" style="cursor: pointer;" @click="handleInput">填充</span>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
- </div>
|
|
|
- </el-scrollbar>
|
|
|
+ </el-scrollbar>
|
|
|
+ <ScrollToBottom :target="scrollbar" ref="scrollToBottomRef" />
|
|
|
+ </div>
|
|
|
|
|
|
<Tools @read-click="readClick"
|
|
|
@upload-file="handleUpload"
|
|
@@ -63,27 +66,27 @@
|
|
|
</div>
|
|
|
</div>
|
|
|
|
|
|
- <div class="card-btn">
|
|
|
+ <div v-show="type !== FunctionList.Intelligent_Form_filling" class="card-btn">
|
|
|
<el-tooltip content="总结当前页面" placement="top">
|
|
|
- <el-button round @click="handleSummary" :disabled="!taklToHtml">总结</el-button>
|
|
|
+ <el-button round @click="handleSummary">总结</el-button>
|
|
|
</el-tooltip>
|
|
|
-
|
|
|
- <!-- <el-tooltip content="选择后,在输入框描述填表流程" placement="top">-->
|
|
|
- <!-- <el-button :class="type === '2' ? 'buttom-clicked' : ''" round @click="handelIntelligentFillingClick"-->
|
|
|
- <!-- :disabled="!taklToHtml">智能填表-->
|
|
|
- <!-- </el-button>-->
|
|
|
- <!-- </el-tooltip>-->
|
|
|
</div>
|
|
|
</div>
|
|
|
|
|
|
<el-input ref="textareaRef" v-model="inputMessage" type="textarea" :rows="3" placeholder="输入消息..."
|
|
|
@keyup.enter="handleAsk" />
|
|
|
<div class="chat_area_op">
|
|
|
- <el-button type="primary" link @click="handleAsk" :disabled="!inputMessage.trim() || sendLoading">
|
|
|
- <el-icon size="18" :color="inputMessage.trim() ? 'black' : 'gray'">
|
|
|
- <Promotion />
|
|
|
- </el-icon>
|
|
|
+ <el-button
|
|
|
+ :style="`background-color:${inputMessage.trim() ? '#4d6bfe' : '#d6dee8'};border-color:${inputMessage.trim() ? '#4d6bfe' : '#d6dee8'}`"
|
|
|
+ v-if="inputMessage.trim() || !sendLoading" type="primary" circle @click="handleAsk"
|
|
|
+ :disabled="!inputMessage.trim() || sendLoading">
|
|
|
+ <svg-icon icon-class="send" color="#000000" />
|
|
|
</el-button>
|
|
|
+ <el-button style="background-color:#ffffff;border:2px solid rgb(134 143 153);" v-else circle
|
|
|
+ @click="handleStopAsk">
|
|
|
+ <svg-icon icon-class="stop" color="red" />
|
|
|
+ </el-button>
|
|
|
+
|
|
|
</div>
|
|
|
</div>
|
|
|
|
|
@@ -99,13 +102,15 @@
|
|
|
import { ref, onMounted, nextTick, inject, useTemplateRef, reactive } from 'vue'
|
|
|
import { ElScrollbar, ElAvatar, ElInput, ElButton } from 'element-plus'
|
|
|
import moment from 'moment'
|
|
|
+import { cloneDeep } from 'lodash'
|
|
|
import fileLogo from '@/assets/svg/file.svg'
|
|
|
import {
|
|
|
buildExcelUnderstandingPrompt,
|
|
|
getSummaryPrompt,
|
|
|
getFileContent,
|
|
|
buildObjPrompt,
|
|
|
- modelFileUpload
|
|
|
+ modelFileUpload,
|
|
|
+ controllerList
|
|
|
} from '@/entrypoints/sidepanel/utils/ai-service.js'
|
|
|
import { storeToRefs } from 'pinia'
|
|
|
import { ElMessage } from 'element-plus'
|
|
@@ -114,6 +119,7 @@ import Tools from '@/entrypoints/sidepanel/component/tools.vue'
|
|
|
import historyComponent from '@/entrypoints/sidepanel/component/historyComponent.vue'
|
|
|
import document from '@/entrypoints/sidepanel/component/document.vue'
|
|
|
import pageMask from '@/entrypoints/sidepanel/component/pageMask.vue'
|
|
|
+import ScrollToBottom from '@/entrypoints/sidepanel/component/ScrollToBottom.vue'
|
|
|
import { mockData, startMsg, mockData2, options, FunctionList } from '@/entrypoints/sidepanel/mock'
|
|
|
import { useAutoResizeTextarea } from '@/entrypoints/sidepanel/hook/useAutoResizeTextarea.ts'
|
|
|
import { getPageInfo, getXlsxValue, handleInput } from './utils/index.js'
|
|
@@ -121,6 +127,7 @@ import { useMsgStore } from '@/store/modules/msg.ts'
|
|
|
|
|
|
// 滚动条引用
|
|
|
const scrollbar = ref(null)
|
|
|
+const scrollToBottomRef = ref(null)
|
|
|
const xlsxData = ref({})
|
|
|
const isShowPage = ref(false)
|
|
|
const tareRef = useTemplateRef('textareaRef')
|
|
@@ -143,12 +150,41 @@ const {
|
|
|
const inputMessage = ref('')
|
|
|
const pageInfo = ref('')
|
|
|
|
|
|
+
|
|
|
+function handleStopAsk() {
|
|
|
+ if (type.value === FunctionList.Intelligent_Form_filling) {
|
|
|
+ inputMessage.value = ''
|
|
|
+ pageInfoList.value = []
|
|
|
+ isShowPage.value = false
|
|
|
+ taklToHtml.value = false
|
|
|
+ type.value = FunctionList.File_Operation
|
|
|
+ }
|
|
|
+ controllerList.value[0].abort()
|
|
|
+ controllerList.value = []
|
|
|
+ sendLoading.value = false
|
|
|
+}
|
|
|
+
|
|
|
+function handleScroll({ scrollTop }) {
|
|
|
+ // scrollTop 滚动条的位置
|
|
|
+ const { wrapRef } = scrollbar.value
|
|
|
+ const { scrollHeight, clientHeight } = wrapRef
|
|
|
+ scrollToBottomRef.value.showButton = scrollHeight - scrollTop - clientHeight >= 350
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* @param {string} msg
|
|
|
* @param {string} raw
|
|
|
* @param {string} type 发送的类型 document 、text
|
|
|
* **/
|
|
|
-const addMessage = (msg, raw, type) => {
|
|
|
+async function addMessage(msg, raw, type) {
|
|
|
+ // 添加indexDB Store配置
|
|
|
+ if (msgUuid.value === '') {
|
|
|
+ msgUuid.value = 'D' + Date.now().toString()
|
|
|
+ await registerStore({
|
|
|
+ name: msgUuid.value,
|
|
|
+ keyPath: 'id'
|
|
|
+ })
|
|
|
+ }
|
|
|
const newMessage = reactive({
|
|
|
id: messages.value.length + 1,
|
|
|
type: type || '',
|
|
@@ -161,14 +197,14 @@ const addMessage = (msg, raw, type) => {
|
|
|
addToHistory: !taklToHtml.value
|
|
|
})
|
|
|
if (type === 'document') {
|
|
|
- newMessage.content = JSON.stringify(msg)
|
|
|
+ newMessage.content = msg
|
|
|
newMessage.rawContent = raw
|
|
|
}
|
|
|
if (!msg) return
|
|
|
|
|
|
messages.value.push(newMessage)
|
|
|
- useStore(msgUuid.value).add({ ...newMessage })
|
|
|
- nextTick(() => {
|
|
|
+ useStore(msgUuid.value).add(cloneDeep(newMessage))
|
|
|
+ await nextTick(() => {
|
|
|
scrollbar.value?.setScrollTop(99999)
|
|
|
})
|
|
|
return newMessage
|
|
@@ -182,11 +218,11 @@ const handleSummary = async () => {
|
|
|
})
|
|
|
params.push({
|
|
|
role: 'user', content: `
|
|
|
- 请根据这几个文件综合分析总结
|
|
|
+ 请根据这几个文件的文本内容综合分析总结
|
|
|
要求:
|
|
|
- 1.抽取各文件的内容
|
|
|
- 2.每个文件的内容进行总结
|
|
|
- 3.所有文件进行综合的总结`
|
|
|
+ 1.抽取文件的文本内容
|
|
|
+ 2.对每个文件中的文本内容进行分别总结
|
|
|
+ 3.对步骤二总结的内容进行综合总结`
|
|
|
})
|
|
|
} else {
|
|
|
let tempStr = ''
|
|
@@ -206,12 +242,12 @@ const handleSummary = async () => {
|
|
|
6. 对这几段内容进行综合分析及联想`
|
|
|
}]
|
|
|
}
|
|
|
- addMessage(pageInfoList.value, '总结', 'document')
|
|
|
+ await addMessage(pageInfoList.value, '总结', 'document')
|
|
|
if (requestFlowFn) {
|
|
|
- await requestFlowFn(params)
|
|
|
- taklToHtml.value = true
|
|
|
- isShowPage.value = true
|
|
|
+ isShowPage.value = false
|
|
|
+ taklToHtml.value = false
|
|
|
pageInfoList.value = []
|
|
|
+ const res = await requestFlowFn(params)
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -220,7 +256,7 @@ async function handelIntelligentFillingClick() {
|
|
|
taklToHtml.value = true
|
|
|
const tempPageInfo = await getPageInfo()
|
|
|
pageInfo.value = tempPageInfo
|
|
|
- pageInfoList.value.unshift(tempPageInfo)
|
|
|
+ pageInfoList.value = [tempPageInfo]
|
|
|
inputMessage.value = '/智能填表 '
|
|
|
type.value = FunctionList.Intelligent_Form_filling
|
|
|
}
|
|
@@ -233,6 +269,11 @@ function handleCurrentChange(e) {
|
|
|
}
|
|
|
})
|
|
|
})
|
|
|
+ if (AIModel.value.file === true) {
|
|
|
+ isShowPage.value = false
|
|
|
+ taklToHtml.value = false
|
|
|
+ pageInfoList.value = []
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
function handleCurrentData(e) {
|
|
@@ -252,7 +293,10 @@ function handleCurrentData(e) {
|
|
|
}
|
|
|
|
|
|
async function readClick() {
|
|
|
- type.value = FunctionList.File_Operation
|
|
|
+ if (type.value === FunctionList.Intelligent_Form_filling) {
|
|
|
+ pageInfoList.value = []
|
|
|
+ type.value = FunctionList.File_Operation
|
|
|
+ }
|
|
|
isShowPage.value = true
|
|
|
taklToHtml.value = true
|
|
|
if (pageInfoList.value.length >= Number(import.meta.env.VITE_MAX_FILE_NUMBER)) {
|
|
@@ -273,6 +317,7 @@ function deletePageInfo(i) {
|
|
|
if (pageInfoList.value.length === 0) {
|
|
|
isShowPage.value = false
|
|
|
taklToHtml.value = false
|
|
|
+ type.value = FunctionList.File_Operation
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -281,20 +326,15 @@ function addNewDialogue() {
|
|
|
ElMessage.warning('已经是新对话')
|
|
|
return
|
|
|
}
|
|
|
+ isShowPage.value = false
|
|
|
+ taklToHtml.value = false
|
|
|
messages.value = []
|
|
|
+ pageInfoList.value = []
|
|
|
msgUuid.value = ''
|
|
|
}
|
|
|
|
|
|
async function handleAsk() {
|
|
|
if (sendLoading.value) return
|
|
|
- // 添加indexDB Store配置
|
|
|
- if (msgUuid.value === '') {
|
|
|
- msgUuid.value = 'D' + Date.now().toString()
|
|
|
- await registerStore({
|
|
|
- name: msgUuid.value,
|
|
|
- keyPath: 'id'
|
|
|
- })
|
|
|
- }
|
|
|
addMessage(inputMessage.value.trim())
|
|
|
if (type.value === FunctionList.Intelligent_Form_filling) {
|
|
|
const res = await fetchRes(inputMessage.value.trim())
|
|
@@ -355,11 +395,20 @@ const handleUpload = async (file) => {
|
|
|
return
|
|
|
}
|
|
|
if (type.value === FunctionList.File_Operation) {
|
|
|
- const fileVaue = await getFileValue(file)
|
|
|
- // streamRes()
|
|
|
+ let formData = new FormData()
|
|
|
+ formData.append('file', file)
|
|
|
+ const res = await getFileContent(formData)
|
|
|
+ pageInfoList.value.unshift({
|
|
|
+ title: file.name,
|
|
|
+ url: 'File',
|
|
|
+ favIconUrl: fileLogo,
|
|
|
+ content: {
|
|
|
+ mainContent: res.data
|
|
|
+ }
|
|
|
+ })
|
|
|
+ isShowPage.value = true
|
|
|
}
|
|
|
}
|
|
|
-let str = ''
|
|
|
|
|
|
async function getFileValue(file) {
|
|
|
const msg = addMessage(`文件上传中`)
|