|
@@ -1,31 +1,28 @@
|
|
|
-<!-- Chat.vue -->
|
|
|
<template>
|
|
|
-
|
|
|
- <div class="chat-container" style="padding-top: 3rem;">
|
|
|
+
|
|
|
+ <div class="chat-container items-center" >
|
|
|
<!-- <div v-if="!messages.length && !msgLoading" class="message-list">
|
|
|
<pageMask />
|
|
|
</div> -->
|
|
|
<!-- 消息列表 -->
|
|
|
- <div class="message-list">
|
|
|
+ <div class="message-list w-full">
|
|
|
<el-scrollbar ref="scrollbar" @scroll="handleScroll" v-loading="msgLoading">
|
|
|
<!-- 加载更多指示器 -->
|
|
|
<div v-if="isLoadingMore" class="loading-more-indicator">
|
|
|
<div class="loading-spinner"></div>
|
|
|
<span>加载更多消息...</span>
|
|
|
</div>
|
|
|
- <div class="messages" ref="messagesContainer" >
|
|
|
+ <div class="messages" ref="messagesContainer">
|
|
|
<div v-for="(message, index) in messages" :key="index"
|
|
|
- :class="['message-item', message.role === 'user' ? 'self' : 'other']">
|
|
|
+ :class="['message-item', message.role === 'user' ? 'self' : 'other']">
|
|
|
<el-avatar :size="32" :src="message.role === 'user' ? userAvatar : avatar" />
|
|
|
<div class="message-content">
|
|
|
- <div class="content" v-if="message.role ==='system'"
|
|
|
+ <div class="content w-full" v-if="message.role ==='system'" m,,, j
|
|
|
:class="{ 'loading-content': message.content === '' }">
|
|
|
<StepsDisplay
|
|
|
v-if="message.type === 'plan'"
|
|
|
- :content="message.rawContent"
|
|
|
- :initialStep="initialSteps"
|
|
|
- @step-change="handleStepChange" @complete="handleComplete"
|
|
|
/>
|
|
|
+
|
|
|
<span v-else v-html="message.content"></span>
|
|
|
<span class="loading-indicator" v-if="sendLoading && index === messages.length - 1">
|
|
|
<span class="dot"></span>
|
|
@@ -34,7 +31,7 @@
|
|
|
</span>
|
|
|
</div>
|
|
|
<document v-else-if="message.type === 'document' && message.role === 'user'" :content="message.content"
|
|
|
- :rawContent="message.rawContent" />
|
|
|
+ :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">
|
|
@@ -53,16 +50,15 @@
|
|
|
<ScrollToBottom :target="scrollbar" ref="scrollToBottomRef" />
|
|
|
</div>
|
|
|
|
|
|
- <!-- <Tools v-if="selectModal" :disHistory="sendLoading" :upload="type === FunctionList.File_Operation || !!formInfo" @read-click="readClick" @upload-file="(file) => createFileObj(file)" @handle-capture="handleCapture" @his-records="hisRecords"
|
|
|
- @add-new-dialogue="addNewDialogue" @handle-current-change="handleCurrentChange"
|
|
|
- @handel-intelligent-filling-click="handelIntelligentFillingClick" /> -->
|
|
|
+ <Tools />
|
|
|
|
|
|
- <div>
|
|
|
+ <div class="w-full max-w-[720px] p-[0_12px_12px]">
|
|
|
<!-- 输入区域 -->
|
|
|
- <div class="input-area">
|
|
|
- <el-icon class="closeShow" :style="{ display: isShowPage ? 'block' : 'none'}" size="16px" color="#909399" @click="closePageInfo">
|
|
|
- <CircleClose />
|
|
|
- </el-icon>
|
|
|
+ <div class="input-area w-full">
|
|
|
+ <el-icon class="closeShow" :style="{ display: isShowPage ? 'block' : 'none'}" size="16px" color="#909399"
|
|
|
+ @click="closePageInfo">
|
|
|
+ <CircleClose />
|
|
|
+ </el-icon>
|
|
|
<!-- <div v-show="isShowPage" style="border-bottom: 1px solid #F0F0F0;">
|
|
|
<div class="card_list">
|
|
|
<div v-for="(v, i) in pageInfoList" :key="i"
|
|
@@ -94,17 +90,17 @@
|
|
|
</div> -->
|
|
|
|
|
|
<el-input ref="textareaRef" v-model="inputMessage" type="textarea" :rows="3" placeholder="输入消息..."
|
|
|
- @keyup.enter="() => handleAsk()" />
|
|
|
+ @keyup.enter="() => handleAsk()" />
|
|
|
<div class="chat_area_op">
|
|
|
-
|
|
|
- <el-button v-if="sendLoading" style="background-color:#ffffff;border:2px solid rgb(134 143 153);" circle
|
|
|
- @click="handleStopAsk">
|
|
|
+
|
|
|
+ <el-button v-if="sendLoading" style="background-color:#ffffff;border:2px solid rgb(134 143 153);" circle
|
|
|
+ @click="handleStopAsk">
|
|
|
<svg-icon icon-class="stop" color="red" />
|
|
|
</el-button>
|
|
|
- <el-button
|
|
|
+ <el-button
|
|
|
v-else
|
|
|
:style="`background-color:${inputMessage.trim() ? '#4d6bfe' : '#d6dee8'};border-color:${inputMessage.trim() ? '#4d6bfe' : '#d6dee8'}`"
|
|
|
- type="primary" circle @click="() => handleAsk()"
|
|
|
+ type="primary" circle @click="() => handleAsk()"
|
|
|
:disabled="disSend">
|
|
|
<svg-icon icon-class="send" color="#000000" />
|
|
|
</el-button>
|
|
@@ -113,7 +109,6 @@
|
|
|
|
|
|
</div>
|
|
|
|
|
|
- <!-- <historyComponent :msgUuid="msgUuid" ref="historyComponentRef" @currentData="(e) => handleCurrentData(e)" /> -->
|
|
|
</div>
|
|
|
</template>
|
|
|
|
|
@@ -122,9 +117,8 @@
|
|
|
import { ref, onMounted, nextTick, inject, useTemplateRef, reactive,onBeforeMount } from 'vue'
|
|
|
import { ElScrollbar, ElAvatar, ElInput, ElButton } from 'element-plus'
|
|
|
import moment from 'moment'
|
|
|
-
|
|
|
import {
|
|
|
- controllerList,
|
|
|
+ controllerList
|
|
|
} from '@/entrypoints/sidepanel/utils/ai-service.js'
|
|
|
import { storeToRefs } from 'pinia'
|
|
|
import { useMsg } from '@/entrypoints/sidepanel/hook/useMsg.ts'
|
|
@@ -133,11 +127,14 @@ import ScrollToBottom from '@/entrypoints/sidepanel/component/ScrollToBottom.vue
|
|
|
import StepsDisplay from './component/StepsDisplay.vue'
|
|
|
import userAvatar from '@/assets/images/user.png'
|
|
|
import avatar from '@/public/icon/icon.png'
|
|
|
-import { FunctionList } from '@/entrypoints/sidepanel/mock'
|
|
|
+import { FunctionList } from '@/entrypoints/sidepanel/mock'
|
|
|
import { useAutoResizeTextarea } from '@/entrypoints/sidepanel/hook/useAutoResizeTextarea.ts'
|
|
|
import { useMsgStore } from '@/store/modules/msg.ts'
|
|
|
import { useUserStore } from '@/store/modules/user'
|
|
|
import { debounce } from 'lodash'
|
|
|
+import Tools from '@/entrypoints/sidepanel/component/tools.vue'
|
|
|
+
|
|
|
+
|
|
|
const userStore = useUserStore()
|
|
|
// 在其他状态变量附近添加
|
|
|
const isLoadingMore = ref(false)
|
|
@@ -155,7 +152,7 @@ const disSend = computed(() => {
|
|
|
})
|
|
|
// 获取父组件提供的 Hook 实例
|
|
|
const msgStore = useMsgStore()
|
|
|
-const { pageInfoList, messages, msgUuid,hasNext,msgLoading } = storeToRefs(useMsgStore())
|
|
|
+const { pageInfoList, messages, msgUuid, hasNext, msgLoading } = storeToRefs(useMsgStore())
|
|
|
const formInfo = ref('')
|
|
|
const {
|
|
|
taklToHtml,
|
|
@@ -168,11 +165,11 @@ const pageInfo = ref('')
|
|
|
const summaryHtml = ref(false)
|
|
|
const initialSteps=ref(0)
|
|
|
function handleStopAsk() {
|
|
|
- inputMessage.value = ''
|
|
|
- pageInfoList.value = []
|
|
|
- isShowPage.value = false
|
|
|
- taklToHtml.value = false
|
|
|
- type.value = FunctionList.File_Operation
|
|
|
+ inputMessage.value = ''
|
|
|
+ pageInfoList.value = []
|
|
|
+ isShowPage.value = false
|
|
|
+ taklToHtml.value = false
|
|
|
+ type.value = FunctionList.File_Operation
|
|
|
controllerList.value[0]?.abort()
|
|
|
controllerList.value = []
|
|
|
sendLoading.value = false
|
|
@@ -180,19 +177,21 @@ function handleStopAsk() {
|
|
|
}
|
|
|
|
|
|
function handleScroll(a) {
|
|
|
+ return
|
|
|
const { wrapRef } = scrollbar.value
|
|
|
const { scrollHeight, clientHeight } = wrapRef
|
|
|
scrollToBottomRef.value.showButton = scrollHeight - a.scrollTop - clientHeight >= 350
|
|
|
-
|
|
|
+
|
|
|
// 检测是否滚动到顶部
|
|
|
if (a.scrollTop <= 10 && hasNext.value) {
|
|
|
handleScrollToTop()
|
|
|
}
|
|
|
}
|
|
|
+const format = (percentage) => (percentage === 100 ? 'Full' : `${percentage}%`)
|
|
|
const messagesContainer = ref(null)
|
|
|
let innerText = ''
|
|
|
// 处理滚动到顶部的事件
|
|
|
-const handleScrollToTop = debounce(async function () {
|
|
|
+const handleScrollToTop = debounce(async function() {
|
|
|
console.log('滚动到顶部,可以加载更多历史消息')
|
|
|
if (!sendLoading.value && !isLoadingMore.value) {
|
|
|
isLoadingMore.value = true
|
|
@@ -204,14 +203,14 @@ const handleScrollToTop = debounce(async function () {
|
|
|
await msgStore.changePage()
|
|
|
setTimeout(() => {
|
|
|
if (firstMessage) {
|
|
|
- console.log([...messagesContainer.value.querySelectorAll('.timestamp')].find(_ => _.innerText === innerText).offsetTop, innerText, 778);
|
|
|
+ console.log([...messagesContainer.value.querySelectorAll('.timestamp')].find(_ => _.innerText === innerText).offsetTop, innerText, 778)
|
|
|
const newHeight = [...messagesContainer.value.querySelectorAll('.timestamp')].find(_ => _.innerText === innerText).offsetTop
|
|
|
const scrollOffset = newHeight - oldHeight
|
|
|
scrollbar.value?.setScrollTop(scrollOffset)
|
|
|
}
|
|
|
- }, 400);
|
|
|
+ }, 400)
|
|
|
// 恢复滚动位置
|
|
|
-
|
|
|
+
|
|
|
} finally {
|
|
|
isLoadingMore.value = false
|
|
|
}
|
|
@@ -224,6 +223,7 @@ const handleStepChange = (step) => {
|
|
|
const handleComplete = () => {
|
|
|
console.log('所有步骤已完成')
|
|
|
}
|
|
|
+
|
|
|
/**
|
|
|
* @param {string} msg
|
|
|
* @param {string} raw
|
|
@@ -231,18 +231,18 @@ const handleComplete = () => {
|
|
|
* **/
|
|
|
async function addMessage(msg, raw, type) {
|
|
|
const newMessage = reactive({
|
|
|
- id:+new Date(),
|
|
|
+ id: +new Date(),
|
|
|
type: type || '',
|
|
|
rawContent: raw ?? msg,
|
|
|
senderId: userStore.userInfo.id,
|
|
|
- receiverId:-1, //大模型
|
|
|
+ receiverId: -1, //大模型
|
|
|
content: msg,
|
|
|
sortKey: moment().valueOf(),
|
|
|
role: 'user',
|
|
|
- conversationId:msgUuid.value,
|
|
|
+ conversationId: msgUuid.value,
|
|
|
addToHistory: `${!taklToHtml.value}`,
|
|
|
redisKey: undefined,
|
|
|
- fileId:undefined
|
|
|
+ fileId: undefined
|
|
|
})
|
|
|
if (type === 'document') {
|
|
|
newMessage.content = msg
|
|
@@ -268,34 +268,37 @@ watchEffect(() => {
|
|
|
inputMessage.value = ''
|
|
|
}
|
|
|
})
|
|
|
+
|
|
|
function closePageInfo() {
|
|
|
pageInfoList.value = []
|
|
|
- if (type.value === FunctionList.Intelligent_Form_filling && SystemMsg ) {
|
|
|
- SystemMsg.content = '智能填表流程中断'
|
|
|
- SystemMsg.rawContent = '智能填表流程中断'
|
|
|
- putChat({
|
|
|
- ...SystemMsg,
|
|
|
- content: '',
|
|
|
- })
|
|
|
- }
|
|
|
+ if (type.value === FunctionList.Intelligent_Form_filling && SystemMsg) {
|
|
|
+ SystemMsg.content = '智能填表流程中断'
|
|
|
+ SystemMsg.rawContent = '智能填表流程中断'
|
|
|
+ putChat({
|
|
|
+ ...SystemMsg,
|
|
|
+ content: ''
|
|
|
+ })
|
|
|
+ }
|
|
|
handleStopAsk()
|
|
|
}
|
|
|
-async function handleAsk(value) { if (sendLoading.value) return
|
|
|
+
|
|
|
+async function handleAsk(value) {
|
|
|
+ if (sendLoading.value) return
|
|
|
const str = value ?? inputMessage.value.trim()
|
|
|
inputMessage.value = ''
|
|
|
if (type.value === FunctionList.Intelligent_Form_filling) {
|
|
|
const msg = await addMessage(str)
|
|
|
// await putChat(msg)
|
|
|
- const [res,obj] = await fetchRes(str)
|
|
|
+ const [res, obj] = await fetchRes(str)
|
|
|
if (res.status === 'ok') {
|
|
|
- console.log(obj);
|
|
|
+ console.log(obj)
|
|
|
formInfo.value = res.data
|
|
|
SystemMsg = obj
|
|
|
} else {
|
|
|
type.value = FunctionList.File_Operation
|
|
|
isShowPage.value = false
|
|
|
}
|
|
|
- return
|
|
|
+ return
|
|
|
}
|
|
|
if (sendLoading.value) return
|
|
|
let msg = null
|
|
@@ -304,61 +307,58 @@ async function handleAsk(value) { if (sendLoading.value) return
|
|
|
msg.fileId = pageInfoList.value[0].fileId
|
|
|
msg.redisKey = pageInfoList.value[0].redisKey
|
|
|
} else msg = await addMessage(str)
|
|
|
- pageInfoList.value = []
|
|
|
+ pageInfoList.value = []
|
|
|
isShowPage.value = false
|
|
|
// await putChat(msg)
|
|
|
createWS(msg)
|
|
|
}
|
|
|
+
|
|
|
/**
|
|
|
- *
|
|
|
+ *
|
|
|
* @param msg 用户消息对象,调用askQues时需要
|
|
|
*/
|
|
|
async function createWS(msg) {
|
|
|
- sendLoading.value = true
|
|
|
+ sendLoading.value = true
|
|
|
const obj = reactive({
|
|
|
- type: '',
|
|
|
+ type: '',
|
|
|
rawContent: '',
|
|
|
senderId: -1,
|
|
|
receiverId: userStore.userInfo.id, //大模型
|
|
|
content: '',
|
|
|
sortKey: moment().valueOf(),
|
|
|
role: 'system',
|
|
|
- conversationId: msgUuid.value,
|
|
|
+ conversationId: msgUuid.value
|
|
|
})
|
|
|
try {
|
|
|
- messages.value.push(obj)
|
|
|
- nextTick(() => {
|
|
|
- if (scrollbar.value && scrollbar.value.wrapRef) {
|
|
|
- scrollbar.value.setScrollTop(scrollbar.value.wrapRef.scrollHeight)
|
|
|
+ messages.value.push(obj)
|
|
|
+ nextTick(() => {
|
|
|
+ if (scrollbar.value && scrollbar.value.wrapRef) {
|
|
|
+ scrollbar.value.setScrollTop(scrollbar.value.wrapRef.scrollHeight)
|
|
|
+ }
|
|
|
+ })
|
|
|
+ let params = {
|
|
|
+ conversationId: Math.floor(Math.random() * 1000) + 1,
|
|
|
+ messageId: Math.floor(Math.random() * 1000) + 1,
|
|
|
+ messageContent: msg.rawContent
|
|
|
}
|
|
|
- })
|
|
|
- let param={
|
|
|
- conversationId:Math.floor(Math.random() * 100) + 1,
|
|
|
- messageId:Math.floor(Math.random() * 100) + 1,
|
|
|
- messageContent: msg.rawContent,
|
|
|
- }
|
|
|
- getPlan2(param).then(res => {
|
|
|
+ getPlan2(params).then(res => {
|
|
|
sendLoading.value = false
|
|
|
- obj.type = 'plan'
|
|
|
- console.log(res,5558);
|
|
|
+ obj.type = 'plan'
|
|
|
+ console.log(res, 5558)
|
|
|
obj.rawContent = res.data.plan
|
|
|
chrome.runtime.sendMessage({
|
|
|
type: "FROM_PLAN",
|
|
|
- payload: {param,...res.data.plan},});
|
|
|
- // handlePlan(res)
|
|
|
- }).catch(res => {
|
|
|
- obj.rawContent = '接口出错,请重试。'
|
|
|
- obj.content = '接口出错,请重试。'
|
|
|
- })
|
|
|
+ payload: {params,...res.data.plan},});
|
|
|
+ }).catch(res => {
|
|
|
+ obj.rawContent = '接口出错,请重试。'
|
|
|
+ obj.content = '接口出错,请重试。'
|
|
|
+ })
|
|
|
} finally {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 组件挂载时滚动到底部
|
|
|
-onBeforeMount(async () => {
|
|
|
- await msgStore.initMsg()
|
|
|
- await msgStore.initModal()
|
|
|
-})
|
|
|
+
|
|
|
onMounted(async () => {
|
|
|
// msgStore.updateAIModel(options[0].options[0])
|
|
|
useAutoResizeTextarea(tareRef, inputMessage)
|
|
@@ -366,20 +366,20 @@ onMounted(async () => {
|
|
|
if (message.type === 'TO_SIDE_PANEL_PAGE_INFO') {
|
|
|
pageInfo.value = message.data
|
|
|
// 转发到 content.js
|
|
|
- chrome.tabs.sendMessage(sender.tab.id, {
|
|
|
- type: 'TO_CONTENT_SCRIPT',
|
|
|
- data: message.data
|
|
|
- })
|
|
|
+ // chrome.tabs.sendMessage(sender.tab.id, {
|
|
|
+ // type: 'TO_CONTENT_SCRIPT',
|
|
|
+ // data: message.data
|
|
|
+ // })
|
|
|
}
|
|
|
if (message.type === 'TO_SIDE_PANEL_PAGE_CHANGE') {
|
|
|
pageInfo.value = message.data
|
|
|
}
|
|
|
})
|
|
|
- nextTick(() => {
|
|
|
- if (scrollbar.value && scrollbar.value.wrapRef) {
|
|
|
- scrollbar.value.setScrollTop(scrollbar.value.wrapRef.scrollHeight)
|
|
|
- }
|
|
|
-})
|
|
|
+ nextTick(() => {
|
|
|
+ if (scrollbar.value && scrollbar.value.wrapRef) {
|
|
|
+ scrollbar.value.setScrollTop(scrollbar.value.wrapRef.scrollHeight)
|
|
|
+ }
|
|
|
+ })
|
|
|
})
|
|
|
</script>
|
|
|
|
|
@@ -394,6 +394,7 @@ onMounted(async () => {
|
|
|
padding: 10px 0;
|
|
|
color: #909399;
|
|
|
font-size: 14px;
|
|
|
+
|
|
|
.loading-spinner {
|
|
|
width: 20px;
|
|
|
height: 20px;
|