chd 7 月之前
父节点
当前提交
be738cca3b
共有 5 个文件被更改,包括 259 次插入47 次删除
  1. 7 9
      js/ai-service.js
  2. 65 27
      js/chat-ui.js
  3. 178 7
      js/content.js
  4. 8 3
      js/page-analyzer.js
  5. 1 1
      sidebar.html

+ 7 - 9
js/ai-service.js

@@ -157,6 +157,10 @@ class AIService {
    * @param {Object} pageInfo 页面信息
    * @returns {string} 提示词
    */
+  // 4. 按重要性排序
+  // 5. 如果内容是新闻,需要包含时间、地点、人物等关键信息
+  // 6. 如果内容是教程,需要突出操作步骤和关键提示
+  // 7. 如果内容是产品介绍,需要包含主要特点和优势
   getSummaryPrompt(pageInfo) {
     return `请帮我总结以下网页内容的要点:
 
@@ -168,15 +172,9 @@ URL:${pageInfo.url}
 ${pageInfo.mainContent}
 
 要求:
-1. 提取3-5个核心要点
-2. 使用简洁清晰的语言
-3. 保持客观中立的语气
-4. 按重要性排序
-5. 如果内容是新闻,需要包含时间、地点、人物等关键信息
-6. 如果内容是教程,需要突出操作步骤和关键提示
-7. 如果内容是产品介绍,需要包含主要特点和优势
-
-请以"以下是对该页面内容的总结:"开头,然后用要点的形式列出主要内容。`;
+1. 帮助我分析表单项与上传excel文件中每一列的关系
+  2- 将excel文件中每一列的内容与表单项进行匹配,并生成对应的数组,在一个字段内返回
+  `;
   }
 
   /**

+ 65 - 27
js/chat-ui.js

@@ -8,10 +8,9 @@ class ChatUI {
     this.promptPanel = document.getElementById("prompt-panel");
     this.uploadButton = document.getElementById("upload-button");
     this.fileInput = document.getElementById("file-input");
-    this.inputs = document.querySelectorAll('input')
     this.ContentInputs = []
-    console.log(this.inputs);
-    
+    this.iframeInfo = null
+
     this.excelData = [];
     // 确保AI服务已经初始化
     if (!window.aiService) {
@@ -179,12 +178,31 @@ class ChatUI {
     });
 
     // 上传按钮点击事件
-    this.uploadButton.addEventListener("click", () => {
+    this.uploadButton.addEventListener("click", async () => {
+      this.iframeInfo = await new Promise((resolve) => {
+        // 创建一次性消息监听器
+        const messageHandler = (event) => {
+          if (event.data.type === "PAGE_ANALYSIS_RESULT") {
+            window.removeEventListener("message", messageHandler);
+            resolve(event.data.pageInfo);
+          }
+        };
+        console.log(this.iframeInfo);
+
+        // 添加消息监听
+        window.addEventListener("message", messageHandler);
+
+        // 发送分析请求到父页面
+        window.parent.postMessage({ type: "ANALYZE_PAGE" }, "*");
+      });
+      console.log(this.iframeInfo);
       this.fileInput.click();
     });
 
     // 文件选择事件
     this.fileInput.addEventListener("change", (event) => {
+      console.log(event);
+
       const files = event.target.files;
       if (files.length > 0) {
         this.handleFileUpload(files);
@@ -228,19 +246,22 @@ class ChatUI {
       this.stopButton.classList.add("show");
       this.setInputState(true); // 禁用输入框
       this.loadingDiv = this.createLoadingMessage();
+      console.log(this.aiService.currentExcelData);
 
       // 如果存在Excel数据,添加上下文提示
       let prompt = message;
       if (this.aiService.currentExcelData) {
-        const { fileName, headers, totalRows } =
+        const { fileName, headers, totalRows, rows } =
           this.aiService.currentExcelData;
         prompt = `请记住之前我们正在讨论的Excel文件:
 - 文件名:${fileName}
 - 列标题:${headers.join(", ")}
+- 列内容:${rows.join(", ")}
+
 - 总行数:${totalRows}
 
 基于这个Excel文件的内容,请回答以下问题:
-${message}`;
+${this.iframeInfo}`;
       }
 
       const response = await this.aiService.sendMessage(prompt);
@@ -349,6 +370,7 @@ ${message}`;
    * @param {string} text 要显示的文字
    */
   async typeMessage(element, text) {
+   return  element.innerHTML = text;
     let index = 0;
     const rawText = text;
     const tempDiv = document.createElement("div");
@@ -655,6 +677,7 @@ ${message}`;
     window.addEventListener("message", (event) => {
       if (event.data.type === "PAGE_INFO") {
         const pageInfo = event.data.pageInfo;
+        this.iframeInfo = event.data.pageInfo.iframe
         this.ContentInputs = pageInfo.inputs
 
         // 更新卡片内容
@@ -698,7 +721,7 @@ ${message}`;
       this.loadingDiv = this.createLoadingMessage();
 
       // 通过postMessage请求页面分析结果
-      const pageInfo = await new Promise((resolve) => {
+      this.iframeInfo = await new Promise((resolve) => {
         // 创建一次性消息监听器
         const messageHandler = (event) => {
           if (event.data.type === "PAGE_ANALYSIS_RESULT") {
@@ -713,7 +736,7 @@ ${message}`;
         // 发送分析请求到父页面
         window.parent.postMessage({ type: "ANALYZE_PAGE" }, "*");
       });
-
+      return
       // 构建提示词
       const prompt = this.aiService.getSummaryPrompt(pageInfo);
 
@@ -752,7 +775,10 @@ ${message}`;
    * @param {FileList} files 上传的文件列表
    */
   async handleFileUpload(files) {
+    console.log(files);
+
     try {
+
       for (const file of files) {
         const extension = file.name.split(".").pop().toLowerCase();
 
@@ -785,7 +811,12 @@ ${message}`;
               this.loadingDiv.remove();
               this.loadingDiv = null;
             }
-
+            window.parent.postMessage({
+              type: "HANDLE_FILL_INPUT", data: {
+                excelData: this.excelData,
+                formData: JSON.parse(response)
+              }
+            }, "*");
             // 显示AI的理解结果
             this.addMessage(response, "assistant", true);
           } catch (error) {
@@ -814,12 +845,16 @@ ${message}`;
       return "这是一个空的Excel文件,请检查文件内容。";
     }
 
+
     const headers = data[0];
     const rows = data.slice(1);
     const sampleRows = rows.slice(0, 2);
     console.log(data);
-    this.excelData = data
-    return `我将向你展示一个通过SheetJS库读取的Excel文件内容。请帮我理解这些数据:
+    data[0].forEach((header, i) => {
+      if (!this.excelData[header]) this.excelData[header] = []
+      this.excelData[header].push(data[1][i])
+    })
+    return `我将向你展示一个通过SheetJS库读取的Excel文件内容和一个form表单。请帮我理解这些数据:
 
 文件名:${fileName}
 列标题:${headers.join(", ")}
@@ -827,20 +862,22 @@ ${message}`;
 
 示例数据(前2行):
 ${sampleRows
-  .map((row, index) => {
-    return `第${index + 1}行: ${row
-      .map((cell, i) => `${headers[i]}=${cell}`)
-      .join(", ")}`;
-  })
-  .join("\n")}
-
-请简要说明:
-1. 这个表格的主要用途
-2. 数据之间的关系
-3. 可能的使用场景
-
-请记住这些数据内容,因为后续我可能会询问更多相关问题。
-请用简洁的语言回复,避免过多修饰词。`;
+        .map((row, index) => {
+          return `第${index + 1}行: ${row
+            .map((cell, i) => `${headers[i]}=${cell}`)
+            .join(", ")}`;
+        })
+        .join("\n")}
+  
+表单内容:
+${this.iframeInfo}
+
+要求:
+1. 请分析表单中实际可操作的表单项,
+2. 并根据实际可操作的表单项的所有信息与上传excel文件中的列标题进行匹配,生成表单项与excel文件中列标题的数组,并使用findBy字段告诉我通过什么信息匹配到的,使用findByValue字段告诉我匹配到的值,使用excelColumn字段告诉我excel文件中列标题的值。在一个字段内返回
+3. 并去除没有匹配到的表单项和excel文件中没有匹配到的列
+4. 如果表单项的输入项有id元素,同时返回id,通过type字段告诉我输入项的类型
+5. 仅返回数组类型的数组,不要带换行符,不要返回任何其他内容。`
   }
 
   /**
@@ -888,9 +925,10 @@ ${sampleRows
 document.addEventListener("DOMContentLoaded", () => {
   try {
     const chatUI = new ChatUI();
-  
-    
+
+
   } catch (error) {
     console.error("Failed to initialize ChatUI:", error);
   }
 });
+

+ 178 - 7
js/content.js

@@ -77,7 +77,22 @@ class SidebarManager {
         childList: true,
       }
     );
+    const simulateUserInput = (element, value) => {
+      // 设置值
+      element.value = value;
 
+      // 创建并触发 input 事件
+      const inputEvent = new Event('input', { bubbles: true });
+      element.dispatchEvent(inputEvent);
+
+      // 创建并触发 change 事件
+      const changeEvent = new Event('change', { bubbles: true });
+      element.dispatchEvent(changeEvent);
+
+      // 可选:如果表单使用了 React/Vue 等框架,可能还需要触发以下事件
+      element.dispatchEvent(new Event('blur'));
+      element.dispatchEvent(new KeyboardEvent('keyup', { key: 'Enter' }));
+    }
     // 监听页面 URL 变化
     new MutationObserver(() => {
       const url = location.href;
@@ -87,7 +102,28 @@ class SidebarManager {
         this.checkAndRestoreState();
       }
     }).observe(document, { subtree: true, childList: true });
-
+    const handleFillInput = (data, i) => {
+      data.forEach(item => {
+        if (item.id) {
+          const input = formChildren.find(child => child.id === item.id)
+          console.log(input);
+          
+          if (item.type === 'text') {
+            if (input) {
+              simulateUserInput(input, excelDataA[item.excelColumn][i])
+            }
+          }
+         
+        } else if (item.findBy === 'placeholder') {
+          const input = formChildren.find(child => child.placeholder === item.findByValue)
+          if (input) {
+            input.value = excelDataA[item.excelColumn][i]
+          }
+        }
+      })
+    }
+    let formChildren = []
+    let excelDataA = []
     // 监听来自sidebar的消息
     window.addEventListener("message", async (event) => {
       if (event.data.type === "COPY_TO_CLIPBOARD") {
@@ -112,9 +148,13 @@ class SidebarManager {
           );
         }
       }
-      if (event.data.type === "FILL_INPUT") {
-        inputs.find(input => input.placeholder.includes('账号')).value = event.data.data[1][0]
-        inputs.find(input => input.placeholder.includes('密码')).value = event.data.data[1][1]
+      if (event.data.type === "HANDLE_FILL_INPUT") {
+        console.log(event.data.data)
+        const { formData, excelData } = event.data.data
+        excelDataA = excelData
+        console.log(formChildren, excelDataA);
+
+        handleFillInput(formData, 0)
       }
     });
 
@@ -135,7 +175,8 @@ class SidebarManager {
           );
         }
         if (event.data.type === "ANALYZE_PAGE") {
-
+          const form = document.querySelectorAll("form")[1];
+          formChildren = [...form.elements]
           // 分析页面并返回结果
           const pageInfo = window.pageAnalyzer.analyzePage();
 
@@ -143,7 +184,7 @@ class SidebarManager {
           event.source.postMessage(
             {
               type: "PAGE_ANALYSIS_RESULT",
-              pageInfo: pageInfo,
+              pageInfo: form.outerHTML,
             },
             "*"
           );
@@ -151,7 +192,9 @@ class SidebarManager {
       }
     });
   }
-
+  handleUserName(input) {
+    return input.placeholder.includes('账号') || input.placeholder.includes('用户名')
+  }
   /**
    * 处理接收到的消息
    * @param {MessageEvent} event
@@ -266,6 +309,7 @@ class SidebarManager {
           favicon,
           title: document.title,
           url: window.location.href,
+          iframe: window.pageAnalyzer.analyzePage()
         },
       },
       "*"
@@ -405,3 +449,130 @@ window.onload = () => {
 
 let inputs = []
 // 创建一个新的js文件用于处理侧边栏内部的关闭按钮事件
+const simulateCompleteUserAction = async (clickElement, inputElement, inputText, tdTitle) => {
+  // 1. 模拟鼠标弹起事件
+  const simulateMouseUp = (element) => {
+    const mouseUpEvent = new MouseEvent('mouseup', {
+      bubbles: true,
+      cancelable: true,
+      view: window,
+      button: 0,
+      buttons: 0,
+      clientX: 0,
+      clientY: 0,
+      detail: 1
+    });
+    element.dispatchEvent(mouseUpEvent);
+  };
+
+  // 2. 模拟键盘输入
+  const simulateTyping = async (element, text, delay = 50) => {
+    element.focus();
+
+    for (let char of text) {
+      await new Promise(resolve => setTimeout(resolve, delay));
+
+      // 按键按下
+      const keydownEvent = new KeyboardEvent('keydown', {
+        key: char,
+        code: `Key${char.toUpperCase()}`,
+        bubbles: true,
+        cancelable: true
+      });
+      element.dispatchEvent(keydownEvent);
+
+      // 更新输入值
+      element.value += char;
+
+      // 触发输入事件
+      const inputEvent = new InputEvent('input', {
+        bubbles: true,
+        cancelable: true,
+        data: char,
+        inputType: 'insertText'
+      });
+      element.dispatchEvent(inputEvent);
+
+      // 按键弹起
+      const keyupEvent = new KeyboardEvent('keyup', {
+        key: char,
+        code: `Key${char.toUpperCase()}`,
+        bubbles: true,
+        cancelable: true
+      });
+      element.dispatchEvent(keyupEvent);
+    }
+
+    // 触发change事件
+    element.dispatchEvent(new Event('change', { bubbles: true }));
+  };
+
+  // 3. 查找td元素
+  const findTdByTitle = (title, timeout = 5000) => {
+    return new Promise((resolve, reject) => {
+      const startTime = Date.now();
+
+      const find = () => {
+        const td = document.querySelector(`td[title="${title}"]`);
+        if (td) {
+          resolve(td);
+          return;
+        }
+
+        if (Date.now() - startTime > timeout) {
+          reject(new Error(`未找到title为"${title}"的td元素`));
+          return;
+        }
+
+        requestAnimationFrame(find);
+      };
+
+      find();
+    });
+  };
+
+  // 4. 模拟点击事件
+  const simulateClick = (element) => {
+    const clickEvent = new MouseEvent('click', {
+      bubbles: true,
+      cancelable: true,
+      view: window,
+      detail: 1
+    });
+    element.dispatchEvent(clickEvent);
+  };
+
+  try {
+    // 执行操作序列
+    console.log('开始模拟用户操作...');
+
+    // 1. 触发鼠标弹起
+    console.log('触发鼠标弹起事件...');
+    simulateMouseUp(clickElement);
+    await new Promise(resolve => setTimeout(resolve, 100));
+
+    // 2. 模拟键盘输入
+    console.log('开始模拟键盘输入...');
+    await simulateTyping(inputElement, inputText);
+    await new Promise(resolve => setTimeout(resolve, 200));
+
+    // 3. 查找并点击td元素
+    console.log('查找目标td元素...');
+    const tdElement = await findTdByTitle(tdTitle);
+    console.log(tdElement);
+
+
+    console.log('找到td元素,触发点击事件...');
+    setTimeout(() => {
+      tdElement.click()
+    }, 1000)
+
+    console.log('所有操作完成');
+    return true;
+  } catch (error) {
+    console.error('操作过程中出现错误:', error);
+    throw error;
+  }
+};
+
+

+ 8 - 3
js/page-analyzer.js

@@ -60,9 +60,14 @@ window.PageAnalyzer = class PageAnalyzer {
   extractMainContent() {
     // 移除脚本、样式等
     const content = document.body.cloneNode(true);
-    content
-      .querySelectorAll("script, style, iframe, nav, header, footer")
-      .forEach((el) => el.remove());
+    // content
+    //   .querySelectorAll("script, style, iframe, nav, header, footer")
+    //   .forEach((el) => el.remove());
+    //提取页面的表单
+    const form = document.querySelector("form");
+    if (form) {
+      content.textContent = form.outerHTML;
+    }
 
     return content.textContent.trim().replace(/\s+/g, " ");
   }

+ 1 - 1
sidebar.html

@@ -35,7 +35,7 @@
         <div class="page-title-container">
           <p class="page-title"></p>
         </div>
-        <button class="summarize-button">总结</button>
+        <!-- <button class="summarize-button">总结</button> -->
       </div>
 
       <div class="chat-input-container">