chd преди 5 месеца
родител
ревизия
0b3f25ffe2
променени са 3 файла, в които са добавени 169 реда и са изтрити 114 реда
  1. 7 11
      src/entrypoints/content.js
  2. 161 102
      src/entrypoints/sidepanel/Chat.vue
  3. 1 1
      src/utils/ai-service.js

+ 7 - 11
src/entrypoints/content.js

@@ -10,10 +10,8 @@ export default defineContentScript({
         let page = document.getElementsByTagName('body')[0];
         const src = chrome.runtime.getURL('images/begin.png')
         window.pageAnalyzer = new PageAnalyzer();
-        console.log(PageAnalyzer)
         window.onload = () => {
             chrome.runtime.sendMessage(getPageInfo())
-            console.log(getPageInfo());
         }
         let form = null
         let formChildren = []
@@ -26,8 +24,6 @@ export default defineContentScript({
             }
             let dom = null
             if (message.type === "GET_TAG_ACTION") {
-                const a = sendResponse
-                console.log(message);
                 const data = message.data
                 if (data.id) {
                     dom = document.getElementById(data.id)
@@ -39,9 +35,6 @@ export default defineContentScript({
                 }
                 console.log(dom);
                 dom[0].click()
-                await new Promise(res => setTimeout(() => {
-                    res()
-                }, 500))
                 sendResponse({ data: '完成' })
                 return true
             }
@@ -86,6 +79,7 @@ export default defineContentScript({
                 console.log(formData, excelData);
                 await handleFillInput(formData, 0)
             }
+            return true
         });
         function getPageInfo() {
             const favIconUrl = getFavicon()
@@ -217,8 +211,6 @@ export default defineContentScript({
         }
         const simulateCompleteUserAction = async (clickElement, inputElement, inputText, tdTitle) => {
             // 1. 模拟鼠标弹起事件
-            console.log(inputText, inputElement);
-
             const simulateMouseUp = (element) => {
                 const mouseUpEvent = new MouseEvent('mouseup', {
                     bubbles: true,
@@ -341,10 +333,14 @@ export default defineContentScript({
             }
         };
         function formatDate(date) {
+            // 直接创建北京时间的日期对象
             const d = new Date(date);
+
+            // 获取年、月、日
             const year = d.getFullYear();
-            const month = String(d.getMonth() + 1).padStart(2, '0'); // 月份从0开始,需要加1,并确保两位数
-            const day = String(d.getDate()).padStart(2, '0'); // 确保两位数
+            const month = String(d.getMonth() + 1).padStart(2, '0'); // 月份从0开始,需要加1
+            const day = String(d.getDate()).padStart(2, '0');
+
             return `${year}-${month}-${day}`;
         }
 

+ 161 - 102
src/entrypoints/sidepanel/Chat.vue

@@ -25,16 +25,27 @@
             </div>
             <div v-else class="content">{{message.content}}</div>
             <div class="timestamp ">{{ message.timestamp }}
-                <span v-if="message.add" style="cursor: pointer;" @click="handleInput">填充</span>
+                <!-- <span v-if="message.add" style="cursor: pointer;" @click="handleInput">填充</span> -->
             </div>
           </div>
         </div>
       </div>
     </el-scrollbar>
-  <!-- <div style="display: flex;gap: 4px;padding: 1rem;">
-    <el-check-tag :checked="type === '1'" @change="type = '1'">文档总结</el-check-tag>
-    <el-check-tag :checked="type === '2'" @change="type = '2'">表单填写</el-check-tag>
-  </div> -->
+  <div style="display: flex;gap: 4px;padding: 1rem;">
+    <!-- <el-check-tag :checked="type === '1'" @change="type = '1'">文档总结</el-check-tag> -->
+    <el-check-tag :disabled="!taklToHtml" :checked="type === '2'" @change="() => { 
+      if (type !== '2') {
+        inputMessage = '/智能填表 '
+        type = '2'
+      } else {
+        type = ''
+      }
+    }">
+      <el-tooltip content="选择后,在输入框描述填表流程" placement="top">
+        智能填表
+        </el-tooltip>
+      </el-check-tag>
+  </div>
       <div class="card-content">
        <img :src="pageInfo?.favIconUrl" style="width: 32px;"/>
         <div class="title-wrapper">
@@ -53,7 +64,10 @@
         type="textarea"
         :rows="2"
         placeholder="输入消息..."
-        @keyup.enter="() => sendMessage()"
+        @keyup.enter="() => { 
+          addMessage(inputMessage.trim(),true)
+          inputMessage = ''
+        }"
      />
      <div >
          <div style="width: 100px;display: flex;justify-content: space-between;">
@@ -69,12 +83,17 @@
             <el-icon  size="24" :color="taklToHtml ? 'gray' : '#c0c4cc'" style="cursor: pointer;"><Upload /></el-icon>
         </el-upload>
       
-      <el-button size="small" type="primary" @click="() => sendMessage()" :disabled="!inputMessage.trim() || sendLoading">
+      <el-button size="small" type="primary" @click="() => { 
+        addMessage(inputMessage.trim(),true)
+        inputMessage = ''
+      }" :disabled="!inputMessage.trim() || sendLoading">
         发送
       </el-button>
          </div>
          <el-tooltip content="开启后,将会根据左侧网页中的内容做出回答" placement="top">
-             <el-switch size="small" v-model="taklToHtml" />
+             <el-switch size="small" v-model="taklToHtml" @change="(_) => {
+                !_ && (type = '')
+             }"/>
         </el-tooltip>
         与页面对话
      </div>
@@ -88,7 +107,7 @@ import { ref, onMounted, nextTick ,inject} from 'vue'
 import { ElScrollbar, ElAvatar, ElInput, ElButton } from 'element-plus'
 import avator from '@/public/icon/32.png'
 import moment from 'moment'
-import {hepl,getSummaryPrompt,sendMessage as sendServer,formatMessage,buildExcelUnderstandingPrompt} from '@/utils/ai-service.js'
+import {hepl,getSummaryPrompt,sendMessage ,formatMessage,buildExcelUnderstandingPrompt} from '@/utils/ai-service.js'
 import * as XLSX from "xlsx";
 import { ElMessage } from 'element-plus';
 const pageInfo = ref({})
@@ -102,7 +121,8 @@ const messages = ref([
     rawContent: '你好!有什么我可以帮助你的吗?',
     timestamp: moment().format('YYYY-MM-DD HH:mm:ss'),
     isSelf: false,
-    avatar: avator
+    avatar: avator,
+    addToHistory: false
   }
 ])
 
@@ -120,6 +140,8 @@ let xlsxData = {}
 let formMap = []
 let formInfo = []
 const handleInput = () => {
+    console.log(formMap,1005);
+    
     const arr = xlsxData
     chrome.runtime.sendMessage({
         type: 'FROM_SIDE_PANEL_TO_INPUT_FORM',
@@ -131,14 +153,15 @@ const handleInput = () => {
 }
 const taklToHtml = ref(false)
 const handleUpload = (file) => {
-    sendMessage(`已上传文件:${file.name}`)
     chrome.runtime.sendMessage({
          type: 'FROM_SIDE_PANEL_TO_GET_PAGE_FORM',
     },async (response) => {
         if (chrome.runtime.lastError) {
         
         console.error("消息发送错误:", chrome.runtime.lastError);
-    } else {
+        } else {
+    addMessage(`已上传文件:${file.name}`,false)
+      
         formInfo = response.data
             const reader = new FileReader();
            reader.readAsArrayBuffer(file);
@@ -146,25 +169,32 @@ const handleUpload = (file) => {
            const data = new Uint8Array(e.target.result);
            const workbook = XLSX.read(data, {
             type: "array",
-            cellDates: true,
-            cellNF: false,
-            cellText: false,
+            cellDates: false,
+            cellNF: true,
+            cellText: true,
+            dateNF: 'yyyy-mm-dd'
           });
+          
+          // 修复日期处理
           const firstSheet = workbook.Sheets[workbook.SheetNames[0]];
-
+          
           // 转换为JSON数据
           const readData = XLSX.utils.sheet_to_json(firstSheet, {
             header: 1,
-            raw: true,
+            raw: false,
             defval: "",
+            dateNF: 'yyyy-mm-dd'
           });
+          console.log(readData,58);
+          
         readData[0].forEach((header, i) => {
       if (!xlsxData[header]) xlsxData[header] = []
       xlsxData[header].push(readData[1][i])
         })
-         await sendRequese(buildExcelUnderstandingPrompt(readData,file?.name,response),false,true,true)
+             if (type.value === '2') { 
+        await  streamRes(buildExcelUnderstandingPrompt(readData,file?.name,response),false)
+        }
          };
-        // await sendRequese(getSummaryPrompt(response.data.content),true)
         }
     return true
     });
@@ -189,11 +219,11 @@ const getPageInfo = () => {
 }
 const type = ref('')
 const handleCardButtonClick = async () => {
-    sendMessage('总结当前页面')
-    await sendRequese('',true)
+    addMessage('总结当前页面',false)
+    await sendRequese('',false)
 }
 const flag = ref(false)  //true调用算法接口
-const streamRes = async (msg, Summary, format = false, add, copy) => {
+const streamRes = async (msg, addHtml,) => {
   sendLoading.value = true
     console.log(messages.value);
     
@@ -204,11 +234,13 @@ const streamRes = async (msg, Summary, format = false, add, copy) => {
         timestamp: moment().format('YYYY-MM-DD HH:mm:ss'),
         isSelf: false,
         avatar: avator,
-        add: false
+        addToHistory: !taklToHtml.value
     })
   let history = []
+  console.log(messages.value);
+  
      if (taklToHtml.value) {
-       if (!add && !Summary) { 
+       if (addHtml) { 
         history.push({
       role: 'user',
       content: `页面主要内容${pageInfo.value.content.mainContent}`
@@ -219,30 +251,25 @@ const streamRes = async (msg, Summary, format = false, add, copy) => {
       content: msg
     })
      } else {
-      history = messages.value.slice(-20).map(item => ({
+      history = messages.value.filter(item => item.addToHistory).slice(-20).map(item => ({
       role: item.isSelf ? 'user' : 'system',
       content: item.isSelf ? item.content : item.rawContent
       }))
-       const index = history.findIndex(item => item.content === '总结当前页面')
-    if (index !== -1) {
-      history.splice(index, 2)
-       }
-    const index2 = history.findIndex(item => item.has === true)
-    if (index2 !== -1) {
-      history.splice(index2, 1)
-    }
-   (Summary || add) && history.push({
-      role: 'user',
-      content: msg
-    })
-   
+    //    const index = history.findIndex(item => item.content === '总结当前页面')
+    // if (index !== -1) {
+    //   history.splice(index, 2)
+    //    }
+    // const index2 = history.findIndex(item => item.has === true)
+    // if (index2 !== -1) {
+    //   history.splice(index2, 1)
+    // }
   }
     
     messages.value.push(obj)
    nextTick(() => {
      scrollbar.value?.setScrollTop(99999)
   })
-  const iterator = await sendServer(history, Summary)
+  const iterator = await sendMessage(history, addHtml)
   
     for await (const chunk of iterator) {
         if (chunk) {
@@ -259,32 +286,30 @@ const streamRes = async (msg, Summary, format = false, add, copy) => {
     scrollbar.value?.setScrollTop(99999)
     
     // 处理最终内容
-    if (add) {
+    if (type.value === '2') {
         try {
-            formMap = JSON.parse(obj.rawContent.split('json')[1].split('```')[0])
+          formMap = JSON.parse(obj.rawContent.split('json')[1].split('```')[0])
+          console.log(formMap,100);
+          
+            handleInput()
         } catch (e) {
             console.error('解析JSON失败:', e)
         }
     }
-    
-    // 最终格式化完整内容
-    // if (format) {
-    //     try {
-    //         const jsonContent = obj.rawContent.split('json')[1].split('```')[0]
-    //         obj.content = formatMessage(jsonContent)
-    //     } catch (e) {
-    //         console.error('格式化JSON内容失败:', e)
-    //         obj.content = formatMessage(obj.rawContent)
-    //     }
-    // }
     console.log(messages.value);
     sendLoading.value = false
-    obj.add = add
     nextTick(() => {
         scrollbar.value?.setScrollTop(99999)
     })
 }
-const fetchRes = async (msg, Summary, format = false, add, copy) => {
+const mockData = [
+  {action:'click', class: "ant-menu-item", tag: "li", innerHTML: "<span class=\"ant-menu-item-icon\"><span role=\"img\" aria-label=\"book\" class=\"anticon anticon-book\"></span></span><span class=\"ant-menu-title-content\"><span>项目建档</span></span>", id: "", text: "项目建档", next: "是" },
+  {action:'click',class: "ant-menu-item", tag: "button", innerHTML: "<span class=\"ant-menu-item-icon\"><span role=\"img\" aria-label=\"book\" class=\"anticon anticon-book\"></span></span><span class=\"ant-menu-title-content\"><span>项目建档</span></span>", id: "", text: "新增", next: "是"},
+  {action:'show',class: "ant-menu-item", tag: "button", innerHTML: "<span class=\"ant-menu-item-icon\"><span role=\"img\" aria-label=\"book\" class=\"anticon anticon-book\"></span></span><span class=\"ant-menu-title-content\"><span>项目建档</span></span>", id: "", text: "请上传数据", next: "是"},
+]
+let indexTemp = 0
+const fetchRes = async (msg) => {
+  sendLoading.value = true
     const obj =reactive({
            id: moment(),
            username: '用户1',
@@ -292,87 +317,121 @@ const fetchRes = async (msg, Summary, format = false, add, copy) => {
            timestamp: moment().format('YYYY-MM-DD HH:mm:ss'),
            isSelf: false,
            avatar: avator,
-           add:false
+           addToHistory:!taklToHtml.value
          })
-    messages.value.push(obj)
-    strArr = msg.split(',')
+  messages.value.push(obj)
+  if (type.value === '2') {
+    await fetchDataAndProcess(msg,obj)
+    sendLoading.value = false
+    // await handleClick(res)
+  }
+    
+    // strArr = msg.split(',')
 
-    await fetchDataAndProcess(msg)
-    obj.content = '执行操作中'
+    // await fetchDataAndProcess(msg)
+    // obj.content = '执行操作中'
  
 }
 let strArr = []
 let index = 0
-async function fetchDataAndProcess(input) {
+async function fetchDataAndProcess(input,obj) {
     console.log(input);
     
     const pageInfo = await getPageInfo()
     console.log(pageInfo);
     
     // 发起请求获取数据
-    const res = await hepl({
-        input_data: input,
-        body:pageInfo.content.mainContent
+    // const res = await hepl({
+    //     input_data: input,
+    //     body:pageInfo.content.mainContent
+  // })
+    const res = await new Promise((resolve, reject) => {
+      setTimeout(() => {
+        resolve({data:mockData[indexTemp]})
+      }, 1000)
     })
-   await handleClick(res.data)
+    await handleClick(res.data,obj)
  
 }
-let actionValue = ''
-async function handleClick(obj) {
+async function handleClick(res, msgObj) {
+  await new Promise(resolve => setTimeout(resolve, 1000))
+  if (res.action === 'click') {
+    msgObj.content = `点击${res.tag}元素`
     chrome.runtime.sendMessage({
-         type: 'FROM_SIDE_PANEL_TO_ACTION',
-                data:obj
+      type: 'FROM_SIDE_PANEL_TO_ACTION',
+      data: res
     }, async (response) => {
-        if (chrome.runtime.lastError) {
-            console.error("消息发送错误:", chrome.runtime.lastError);
-            rej(chrome.runtime.lastError)
+      if (chrome.runtime.lastError) {
+        console.error("消息发送错误:", chrome.runtime.lastError);
+        rej(chrome.runtime.lastError)
+      } else {
+        if (res.next === '是') {
+          indexTemp++
+          fetchDataAndProcess(strArr[index],msgObj)
         } else {
-            if (obj.next === '是') {
-                console.log(strArr[index]);
-                
-                index++
-                fetchDataAndProcess(strArr[index])
-            } else {
-                ElMessage({ message: '操作执行完成', type: 'success', duration: 2 * 1000, grouping: true })
-                index = 0
-            }
+          ElMessage({ message: '操作执行完成', type: 'success', duration: 2 * 1000, grouping: true })
+          index = 0
         }
-        return true
-});
-}
-const sendRequese = async (msg, Summary = false, format = false, add = false, copy) => {
+      }
+      return true
+    });
+  }
+  if (res.action === 'show') {
+    msgObj.content = `请上传数据`
+    ElMessage({ message: '请上传数据', type: 'success', duration: 4 * 1000, grouping: true })
+  }
+//     chrome.runtime.sendMessage({
+//          type: 'FROM_SIDE_PANEL_TO_ACTION',
+//                 data:obj
+//     }, async (response) => {
+//         if (chrome.runtime.lastError) {
+//             console.error("消息发送错误:", chrome.runtime.lastError);
+//             rej(chrome.runtime.lastError)
+//         } else {
+//             if (obj.next === '是') {
+//                 console.log(strArr[index]);
+                
+//                 index++
+//                 fetchDataAndProcess(strArr[index])
+//             } else {
+//                 ElMessage({ message: '操作执行完成', type: 'success', duration: 2 * 1000, grouping: true })
+//                 index = 0
+//             }
+//         }
+//         return true
+// });
+}
+const sendRequese = async (msg, addHtml = false) => {
     const a = await getPageInfo()
-    // if (msg.startsWith('帮我')) {
-    //     actionValue = msg
-    //     fetchRes(msg, Summary, format = false, add, copy)
-    // }
-    // else {
-    //     if (msg === '') msg = getSummaryPrompt(a.content)
-    //       streamRes(msg, Summary, format = false, add, copy)
-    // }
-    if (msg === '') msg = getSummaryPrompt(a.content)
-  streamRes(msg, Summary, format = false, add, copy)
+    if (type.value === '2' && msg.startsWith('/')) {
+        indexTemp = 0
+        fetchRes(msg, addHtml)
+    }
+    else {
+        if (!addHtml) msg = getSummaryPrompt(a.content)
+          streamRes(msg, addHtml)
+    }
+  //   if (msg === '') msg = getSummaryPrompt(a.content)
+  // streamRes(msg, Summary, format = false, add, copy)
 }
 
 // 发送消息
-const sendMessage = (msg = false) => {
-  if (!msg && !inputMessage.value.trim()) return
+const addMessage = (msg,fetch) => {
+  if (!msg) return
   const newMessage = {
     id: messages.value.length + 1,
     username: '我',
-    content: msg ? msg : inputMessage.value,
+    content: msg,
     timestamp: moment().format('YYYY-MM-DD HH:mm:ss'),
     isSelf: true,
-    avatar: 'https://cube.elemecdn.com/3/7c/3ea6beec64369c2642b92c6726f1epng.png'
+    avatar: 'https://cube.elemecdn.com/3/7c/3ea6beec64369c2642b92c6726f1epng.png',
+    addToHistory: !taklToHtml.value
   }
-
   messages.value.push(newMessage)
-  
   // 滚动到底部
     nextTick(() => {
         scrollbar.value?.setScrollTop(99999)
-       !msg && sendRequese(inputMessage.value.trim(), false)
-       inputMessage.value = ''
+       fetch && sendRequese(msg, taklToHtml.value)
   })
 }
 

+ 1 - 1
src/utils/ai-service.js

@@ -22,7 +22,7 @@ export async function hepl(data) {
 
     }
 }
-export async function sendMessage(message, Summary, html,) {
+export async function sendMessage(message) {
     try {
         // 创建新的 AbortController
         const controller = new AbortController();