chd 4 ay önce
ebeveyn
işleme
ce9a3f8b96

+ 3 - 3
.env

@@ -1,8 +1,8 @@
 VITE_OPENAI_API_KEY_TONG=sk-e9855234f47346049809ce23ed3ebe3f
 VITE_MAX_FILE_NUMBER=10
-VITE_APP_BASE_API='http://192.168.1.166:7777'
+VITE_APP_BASE_API='http://192.168.1.202:13088'
 
 # 接口地址 (WebSocket)
-VITE_API_WS_URL = 'ws://192.168.1.166:7777'
+VITE_API_WS_URL = 'ws://192.168.1.202:13088'
 # 终端ID
-VITE_CLIENT_ID = '765be25e4e78b101b896cb3ecac39b1b'
+VITE_CLIENT_ID = '153062e567553ec0bf1a02b8f1f563b1'

+ 1 - 1
src/entrypoints/background.js

@@ -3,7 +3,7 @@ export default defineBackground(() => {
   let arr = []
   let token = ''
   let userId = ''
-  const url = 'http://192.168.1.166:7777/behavior/user/adds'
+  const url = import.meta.env.VITE_APP_BASE_API +  '/behavior/user/adds'
   // Executed when background is loaded
   chrome.sidePanel
     .setPanelBehavior({ openPanelOnActionClick: true })

+ 7 - 7
src/entrypoints/content.js

@@ -17,10 +17,10 @@ export default defineContentScript({
     let page = document.getElementsByTagName('body')[0]
     const src = chrome.runtime.getURL('images/begin.png')
     window.pageAnalyzer = new PageAnalyzer()
-    window.onload = () => {
-      chrome.runtime.sendMessage(getPageInfo())
-      console.log(document.title)
-    }
+    // window.onload = () => {
+    //   chrome.runtime.sendMessage(getPageInfo())
+    //   console.log(document.title)
+    // }
     let form = null
     let formChildren = []
     let excelDataA = {}
@@ -32,7 +32,7 @@ export default defineContentScript({
         if (e.target.outerHTML.length > 1000) return
         tag = e.target.outerHTML
         innerText = e.target.innerText
-        console.log(e.target.outerHTML.length, e.target.outerHTML);
+        // console.log(e.target.outerHTML.length, e.target.outerHTML);
         chrome.runtime.sendMessage({
           type: 'CLICK_EVENT',
           data: {
@@ -54,7 +54,7 @@ export default defineContentScript({
       if (e.target.outerHTML.length > 1000) return
       tag = e.target.outerHTML
       innerText = e.target.innerText
-      console.log(e.target.outerHTML.length, e.target.outerHTML);
+      // console.log(e.target.outerHTML.length, e.target.outerHTML);
       clearTimeout(timer)
       chrome.runtime.sendMessage({
         type: 'CLICK_EVENT',
@@ -129,7 +129,7 @@ export default defineContentScript({
             item.style.border = '2px solid red'
             function handleClick(e) {
               e.stopPropagation()
-              console.log(this.outerHTML)
+              // console.log(this.outerHTML)
               for (const form of forms) {
                 form.style.border = 'none'
                 form.removeEventListener('click', handleClick, true)

+ 63 - 23
src/entrypoints/sidepanel/Chat.vue

@@ -90,16 +90,18 @@
         <el-input ref="textareaRef" v-model="inputMessage" type="textarea" :rows="3" placeholder="输入消息..."
           @keyup.enter="() => handleAsk()" />
         <div class="chat_area_op">
-          <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
+        
+          <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
+            v-else
+            :style="`background-color:${inputMessage.trim() ? '#4d6bfe' : '#d6dee8'};border-color:${inputMessage.trim() ? '#4d6bfe' : '#d6dee8'}`"
+             type="primary" circle @click="() => handleAsk()"
+            :disabled="disSend">
+            <svg-icon icon-class="send" color="#000000" />
+          </el-button>
         </div>
       </div>
 
@@ -135,7 +137,7 @@ import userAvatar from '@/assets/images/user.png'
 import avatar from '@/public/icon/32.png'
 import {  options, FunctionList } from '@/entrypoints/sidepanel/mock'
 import { useAutoResizeTextarea } from '@/entrypoints/sidepanel/hook/useAutoResizeTextarea.ts'
-import { getPageInfo, getXlsxValue, handleInput } from './utils/index.js'
+import { getPageInfo, getPageInfoClean, handleInput,downloadFile } from './utils/index.js'
 import { useMsgStore } from '@/store/modules/msg.ts'
 import { useUserStore } from '@/store/modules/user'
 import { putChat, uploadFile } from "@/api/index.js";
@@ -152,6 +154,12 @@ const xlsxData = ref({})
 const isShowPage = ref(false)
 const tareRef = useTemplateRef('textareaRef')
 const drawerRef = useTemplateRef('historyComponentRef')
+const disSend = computed(() => {
+  if (pageInfoList.value.length && type.value === FunctionList.Intelligent_Form_filling) return true
+  if (sendLoading.value) return true
+  if (inputMessage.value.trim()) return false
+  return true
+})
 // 获取父组件提供的 Hook 实例
 const msgStore = useMsgStore()
 const { pageInfoList, messages, msgUuid, AIModel,page,hasNext,msgLoading } = storeToRefs(useMsgStore())
@@ -161,18 +169,17 @@ const {
   sendLoading,
   type,
   fetchRes
+
 } = useMsg(scrollbar)
 const inputMessage = ref('')
 const pageInfo = ref('')
 const summaryHtml = ref(false)
 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
@@ -276,7 +283,7 @@ const handleSummaryFile = async () => {
   //   conversationId: msgUuid.value,
   //   })
   // messages.value.push(msg)
-     isShowPage.value = false
+    //  isShowPage.value = false
       pageInfoList.value = []
   //   const resForm = await askQues({
   //   conversationId: msgUuid.value,
@@ -346,8 +353,10 @@ watchEffect(() => {
     summaryHtml.value = false
     type.value = FunctionList.File_Operation
     SystemMsg = null
+    inputMessage.value = ''
   }
 })
+const htmlIcon = ref('')
 async function readClick() {
   if (type.value === FunctionList.Intelligent_Form_filling) {
     pageInfoList.value = []
@@ -361,12 +370,20 @@ async function readClick() {
     return
   }
   const tempPageInfo = await getPageInfo()
+  htmlIcon.value = tempPageInfo.favIconUrl
   const blob = new Blob([tempPageInfo.content.mainContent], { type: 'text/plain' })
-  const file = new File([blob], tempPageInfo.title + '.txt', { type: 'text/plain' })
+  const file = new File([blob], '页面' + '.txt', { type: 'text/plain' })
+  // console.log(file);
+  // 下载文件到本地
+  // downloadFile(file);
+  console.log(tempPageInfo);
+  
   await createFileObj(file)
   // await handleUpload(file,tempPageInfo.title + '.txt')
 }
 
+// 添加下载文件的函数
+
 function deletePageInfo(i) {
   pageInfoList.value.splice(i, 1)
   if (pageInfoList.value.length === 0) {
@@ -403,6 +420,7 @@ function closePageInfo() {
   formInfo.value = null
 }
 async function handleAsk(value) {
+  if (sendLoading.value) return
   const str = value ?? inputMessage.value.trim()
   inputMessage.value = ''
   if (type.value === FunctionList.Intelligent_Form_filling) {
@@ -435,9 +453,8 @@ async function handleAsk(value) {
  * 
  * @param msg 用户消息对象,调用askQues时需要
  */
-function createWS(msg) {
-  try {
-    sendLoading.value = true
+async function createWS(msg) {
+     sendLoading.value = true
   const obj = reactive({
     type: type.value === FunctionList.Intelligent_Form_filling ? 'form' : '',
     rawContent: '',
@@ -448,6 +465,7 @@ function createWS(msg) {
     role: 'system',
     conversationId: msgUuid.value,
   })
+  try {
   messages.value.push(obj)
   nextTick(() => {
     if (scrollbar.value && scrollbar.value.wrapRef) {
@@ -462,10 +480,16 @@ function createWS(msg) {
     question: type.value === FunctionList.File_Operation ? msg.rawContent : buildObjPrompt(xlsxData.value,formInfo.value),
     id: '699637194561691650',
     redisKey:msg.redisKey
-    })
+     }).catch(res => {
+       obj.rawContent = '接口出错,请重试。'
+       obj.content = '接口出错,请重试。'
+      socket.close()
+     })
     socket.onmessage = (event) => {
       try {
         if (event.data === '') {
+          console.log(23223);
+          
           socket.close()
           if (type.value === FunctionList.Intelligent_Form_filling) {
        const formResult = obj.rawContent
@@ -477,10 +501,9 @@ function createWS(msg) {
   
   handleInput(xlsxData.value, form)
     }
+    isShowPage.value = false
         } else {
           obj.rawContent += event.data;
-          console.log( obj.rawContent );
-          
           obj.content = obj.type === 'form' ? obj.rawContent :  formatMessage(obj.rawContent);
           // 滚动到底部
           nextTick(() => {
@@ -519,6 +542,10 @@ function createWS(msg) {
     sendLoading.value = false;
     // 显示错误消息
     obj.content = '连接失败,请重试';
+     putChat({
+      ...obj,
+      content:''
+     });
   } finally {
      
   }
@@ -537,11 +564,7 @@ const createFileObj = async (file) => {
   handleUpload(file)
 }
 const handleUpload = async (file) => {
-  if (type.value === FunctionList.Intelligent_Form_filling) {
-    pageInfoList.value = []
-  }
-  isShowPage.value = true
-  const obj = reactive({
+    const obj = reactive({
     title: file.name,
     state: '上传中...',
     favIconUrl: fileLogo,
@@ -553,6 +576,23 @@ const handleUpload = async (file) => {
       mainContent: ''
     }
   })
+  if (type.value === FunctionList.Intelligent_Form_filling) {
+    pageInfoList.value = []
+  }
+  if (summaryHtml.value) obj.favIconUrl = htmlIcon.value
+  isShowPage.value = true
+  // const obj = reactive({
+  //   title: file.name,
+  //   state: '上传中...',
+  //   favIconUrl: fileLogo,
+  //   loading: true,
+  //   url:'',
+  //   fileId: '',
+  //   redisKey:'',
+  //   content: {
+  //     mainContent: ''
+  //   }
+  // })
   pageInfoList.value = [obj]
   try {
     let formData = new FormData()

+ 6 - 2
src/entrypoints/sidepanel/component/historyComponent.vue

@@ -5,7 +5,9 @@ import { ElMessageBox, ElMessage } from 'element-plus'
 import { getChatList,deleteChat } from '@/api/index.js'
 import { storeToRefs } from 'pinia';
 import { useMsgStore } from '@/store/modules/msg.ts'
+import { useUserStore } from '@/store/modules/user'
 
+const userStore = useUserStore()
 const drawer = ref(false)
 const count = ref(0)
 const input = ref('')
@@ -26,7 +28,8 @@ watch(drawer, (newVal) => {
     loading.value = true
     getChatList({
       page:1,
-      size:50
+      size: 50,
+      senderId:userStore.userInfo.id
     }).then(res => {
       dataList.value = res.data.list
     }).finally(res => loading.value = false)
@@ -62,7 +65,8 @@ function handleDeleteStore(e: any, item: any,name:string) {
       }
       getChatList({
         page: 1,
-        size: 50
+        size: 50,
+        senderId:userStore.userInfo.id
       }).then(res => {
         dataList.value = res.data.list
       }).finally(res => loading.value = false)

+ 9 - 4
src/entrypoints/sidepanel/hook/useMsg.ts

@@ -145,6 +145,11 @@ export function useMsg(scrollbar?: any) {
         )
         const res = await awaitFindForm(obj)
         return [res, obj]
+      } else {
+        putChat({
+          ...msg,
+          content: '',
+        }) 
       }
     } catch (error) {
       obj.content = '流程链执行出错,请重试'
@@ -156,10 +161,10 @@ export function useMsg(scrollbar?: any) {
     } finally {
       sendLoading.value = false
       console.log(messages.value);
-      putChat({
-        ...msg,
-        content:'',
-      })
+      // putChat({
+      //   ...msg,
+      //   content:'',
+      // })
     }
   }
   let str = ''

+ 40 - 1
src/entrypoints/sidepanel/utils/index.js

@@ -1,9 +1,10 @@
 import * as XLSX from 'xlsx'
+import { ElMessage } from 'element-plus'
 export function getPageInfo() {
   return new Promise((res, rej) => {
     chrome.runtime.sendMessage(
       {
-        type: 'FROM_SIDE_PANEL_TO_GET_PAGE_INFO'
+        type: 'FROM_SIDE_PANEL_TO_GET_PAGE_INFO',
       },
       (response) => {
         if (chrome.runtime.lastError) {
@@ -16,6 +17,23 @@ export function getPageInfo() {
     )
   })
 }
+export function getPageInfoClean() {
+  return new Promise((res, rej) => {
+    chrome.runtime.sendMessage(
+      {
+        type: 'FROM_SIDE_PANEL_TO_GET_PAGE_INFO_CLEAN',
+      },
+      (response) => {
+        if (chrome.runtime.lastError) {
+          console.error('消息发送错误:', chrome.runtime.lastError, 555)
+          rej(chrome.runtime.lastError)
+        } else {
+          res(response.data)
+        }
+      }
+    )
+  })
+}
 export function handleInput(xlsxData, formMap) {
   chrome.runtime.sendMessage({
     type: 'FROM_SIDE_PANEL_TO_INPUT_FORM',
@@ -55,3 +73,24 @@ export function getXlsxValue(file) {
     }
   })
 }
+export function downloadFile(file) {
+  try {
+    // 创建一个下载链接
+    const downloadUrl = URL.createObjectURL(file);
+    // 创建一个a标签用于下载
+    const downloadLink = document.createElement('a');
+    downloadLink.href = downloadUrl;
+    downloadLink.download = file.name;
+    // 添加到文档中并触发点击
+    document.body.appendChild(downloadLink);
+    downloadLink.click();
+    // 清理
+    document.body.removeChild(downloadLink);
+    URL.revokeObjectURL(downloadUrl);
+
+    ElMessage.success(`文件 ${file.name} 已下载到本地`);
+  } catch (error) {
+    console.error('下载文件失败:', error);
+    ElMessage.error('下载文件失败');
+  }
+}

+ 20 - 5
src/utils/contentUtils.js

@@ -349,10 +349,24 @@ export function getPageInfo() {
       favIconUrl,
       title: document.title,
       url: window.location.href,
-      content: window.pageAnalyzer.analyzePage()
+      content: fallbackAnalysis()
     }
   }
 }
+function fallbackAnalysis() {
+  return {
+    title: document.title,
+    url: window.location.href,
+    mainContent: extractMainContent(),
+    excerpt: '',
+    siteName: new URL(window.location.href).hostname,
+    wordCount: 0
+  }
+}
+function extractMainContent() {
+  const content = document.body.cloneNode(true)
+  return cleanPage(content)
+}
 export function getFavicon() {
   // 尝试获取动态favicon
   const iconLinks = Array.from(document.querySelectorAll('link[rel*="icon"]'))
@@ -372,8 +386,8 @@ export function getFavicon() {
   const url = new URL(window.location.href)
   return `${url.protocol}//${url.hostname}/favicon.ico`
 }
-export function cleanPage2(body) {
-  const cloneBody = body.cloneNode(true)
+export function cleanPage2(element) {
+  const cloneBody = element.cloneNode(true)
   // 移除所有行内样式
   const elementsWithInlineStyle = cloneBody.querySelectorAll('[style]')
   elementsWithInlineStyle.forEach((element) => {
@@ -417,7 +431,7 @@ export function cleanPage2(body) {
   const regex = /\s+/g
 
   // 定义标准 HTML 属性集合 排除id class style href src target
-  const standardAttributes = new Set([
+  let standardAttributes = new Set([
     'id',
     'class',
     'alt',
@@ -444,7 +458,6 @@ export function cleanPage2(body) {
     'rel',
     'aria-*'
   ])
-
   // 创建一个临时容器
   const temp = document.createElement('div')
   temp.innerHTML = cloneBody.outerHTML
@@ -477,6 +490,8 @@ export function cleanPage2(body) {
 
   // 销毁临时容器
   temp.remove()
+  // console.log(cleanedHtml);
+  
   // content.outerHTML.trim().replace(/\s+/g, " ");
   return cleanedHtml
 }

+ 10 - 29
src/utils/page-analyzer.js

@@ -11,11 +11,7 @@ export default class PageAnalyzer {
   analyzePage(form = false) {
     try {
       // 检查Readability是否可用
-      if (typeof Readability === 'undefined') {
-        console.warn('Readability not loaded, falling back to basic extraction')
-        return this.fallbackAnalysis(form)
-      }
-
+      return this.fallbackAnalysis()
       // 创建文档副本以避免修改原始DOM
       const documentClone = document.cloneNode(true)
       // 初始化 Readability
@@ -40,38 +36,21 @@ export default class PageAnalyzer {
       return this.fallbackAnalysis()
     }
   }
-
   // 基础提取方法作为后备
-  fallbackAnalysis(iframe) {
+  fallbackAnalysis() {
     return {
       title: document.title,
       url: window.location.href,
-      mainContent: this.extractMainContent(iframe),
+      mainContent: this.extractMainContent(),
       excerpt: '',
       siteName: new URL(window.location.href).hostname,
       wordCount: 0
     }
   }
-
   // 基础的内容提取方法
-  extractMainContent(iframe) {
-    // 移除脚本、样式等
-
-    //提取页面的表单
-    if (iframe) {
-      const form = document.querySelector('form')
-      if (form) {
-        content.textContent = form.outerHTML
-      }
-    } else {
-      const content = document.body.cloneNode(true)
-      return cleanPage(content)
-      // return document.documentElement.outerHTML
-      // .trim().replace(/\s+/g, " ")
-      // content
-      //     .querySelectorAll("script, style, iframe, nav, header, footer,svg")
-      //     .forEach((el) => el.remove());
-    }
+  extractMainContent() {
+    const content = document.body.cloneNode(true)
+    return cleanPage(content)
   }
 }
 
@@ -107,8 +86,8 @@ export function cleanPage(body) {
   })
 
   // 可选择移除其他无关内容,比如脚本和广告等
-  // const scripts = body.querySelectorAll('script');
-  // scripts.forEach(script => script.remove());
+  const scripts = body.querySelectorAll('script');
+  scripts.forEach(script => script.remove());
 
   // const iframes = body.querySelectorAll('iframe');
   // iframes.forEach(iframe => iframe.remove());
@@ -193,6 +172,8 @@ export function cleanPage(body) {
   // 销毁临时容器
   temp.remove()
   // content.outerHTML.trim().replace(/\s+/g, " ");
+  console.log(cleanedHtml, cleanedHtml.length);
+  
   return cleanedHtml
 }
 function cleanPage2(body) {