Greasy Fork

来自缓存

Greasy Fork is available in English.

求职魔法师 - 求职神器|智能填充工作信息|免去输入烦恼

点击输入框时请求ChatGPT,并显示智能建议供选择,点击一键填充输入框

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         求职魔法师 - 求职神器|智能填充工作信息|免去输入烦恼
// @namespace    http://t.net/1
// @version      0.91
// @description  点击输入框时请求ChatGPT,并显示智能建议供选择,点击一键填充输入框
// @author       jiguang
// @match        *://*/*
// @grant        GM_xmlhttpRequest
// @license MIT
// ==/UserScript==

(function () {
  "use strict";

  // OpenAI API 的密钥
  const API_KEY = "sk-XXXXXXX"; // 请替换为你的 OpenAI API 密钥

  // 向 OpenAI API 发送请求
  const fetchSuggestions = async (inputHTML, isTextarea) => {
    // 获取 body 的 innerText
    let text = document.body.innerText;

    // 截取前 1000 个字符或全部内容(如果少于 1000 个字符)
    let first1000Chars = text.length > 1000 ? text.slice(0, 1000) : text;
    const response = await fetch(
      "https://api.openai.com/v1/chat/completions",
      {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
          Authorization: `Bearer ${API_KEY}`,
        },
        body: JSON.stringify({
          model: "gpt-4o-mini",
          messages: [
            {
              role: "user",
              content: `我的名字:张三
        手机号:13111112222
        身份证号:111211199012011111
        生日:1991年1月1日
        地址:北京市
        邮箱(密码可以是邮箱):[email protected]
        求职意向:Web 开发

        教育背景:

        - 2016.9-2020.6 清华大学软件工程专业,专业排名年级前 10%
        - 主修课程:操作系统、计算机组成原理、计算机网络、数据结构与算法、C 语言程序设计、Java 语言程序设计、JavaWeb 开发与框架开发、Python 程序开发、嵌入式开发、Linux 操作系统、软件工程、软件测试、项目管理等

        工作经历:

        - 2022.02-2022.05 XXX有限公司 Python 后端工程师
          - XXXXX
        - 2022.06-2023.12 XXX公司 Java后端工程师
          - XXXXX
        - 2024.2 至今 XXXX公司 技术总监
          - 负责技术管理工作

        技能荣誉:

        - 校级奖学金 2019-6

        自我评价:
        我具备较强的问题解决能力。在面对挑战时,我能够冷静分析情况,快速找出解决方案并付诸实施。这使我在项目进程中能够保持高效运作,并不断推动工作向前发展。在专业技能方面,我不断学习和提升自己,通过参加培训和阅读相关书籍,积累了丰富的知识和经验。我对新事物保持开放的态度,乐于尝试新的工作方法,力求在工作中寻求创新和突破。
        。`,
            },
            {
              role: "user",
              content: `网页信息: ${first1000Chars}`,
              //content: `网页信息: ${document.body.innerHTML}`,
            },
            {
              role: "user",
              content: `要填充的元素: ${inputHTML}`,
            },
            {
              role: "user",
              content: `请基于以上HTML内容和我的个人信息,推测3-6条我要需要填充进去的内容${
                isTextarea ? "(每条不少于200字)" : ""
              },一行一个,请你只回复推测结果的内容,不要有其他内容,也不要有序号`,
            },
          ],
          max_tokens: isTextarea ? 3000 : 300,
        }),
      }
    );

    if (!response.ok) {
      throw new Error(`Error: ${response.statusText}`);
    }

    const data = await response.json();
    return data.choices[0]?.message?.content?.trim()?.split("\n") || [];
  };

  // 创建下拉框
  const createDropdown = () => {
    const dropdown = document.createElement("div");
    dropdown.style.position = "absolute";
    dropdown.style.display = "none";
    dropdown.style.backgroundColor = "white";
    dropdown.style.border = "1px solid #ccc";
    dropdown.style.zIndex = "1000";
    dropdown.style.maxHeight = "150px";
    dropdown.style.overflowY = "auto";
    dropdown.style.boxShadow = "0px 0px 5px rgba(0, 0, 0, 0.3)";
    return dropdown;
  };

  // 创建加载动画
  const createLoadingSpinner = () => {
    const spinner = document.createElement("div");
    spinner.className = "loading-spinner";
    spinner.style.position = "absolute";
    spinner.style.border = "4px solid #f3f3f3";
    spinner.style.borderTop = "4px solid #3498db";
    spinner.style.borderRadius = "50%";
    spinner.style.width = "20px";
    spinner.style.height = "20px";
    spinner.style.animation = "spin 1s linear infinite";
    spinner.style.zIndex = "1001"; // 确保加载动画在最上层
    return spinner;
  };

  // 在输入框上点击时显示下拉列表
  const attachDropdownToInput = (input) => {
    let dropdown = createDropdown(); // 创建下拉框
    let spinner = createLoadingSpinner(); // 创建加载动画
    document.body.appendChild(dropdown); // 将下拉框添加到DOM
    document.body.appendChild(spinner); // 将加载动画添加到DOM
    let isDropdownVisible = false; // 下拉框是否可见的标记

    input.addEventListener("focus", async (event) => {
      const rect = event.target.getBoundingClientRect();
      dropdown.style.left = `${rect.left + window.scrollX}px`;
      dropdown.style.top = `${rect.bottom + window.scrollY}px`;
      spinner.style.left = `${rect.left + window.scrollX}px`; // 移动到左上角
      spinner.style.top = `${rect.top + window.scrollY - 30}px`; // 移动到左上角
      spinner.style.display = "block"; // 显示加载动画

      // 请求 OpenAI API 获取建议
      try {
        const isTextarea = input.tagName.toLowerCase() === "textarea";
        const suggestions = await fetchSuggestions(input.outerHTML, isTextarea);
        dropdown.innerHTML = ""; // 清空之前的选项

        suggestions.forEach((optionValue) => {
          const option = document.createElement("div");
          option.textContent = optionValue;
          option.style.padding = "5px 10px";
          option.style.cursor = "pointer";

          option.addEventListener("click", () => {
            input.value = ""; // 先清空输入框
            const inputEvent = new Event("input", { bubbles: true }); // 创建输入事件
            for (let char of optionValue.replace(/\s+/g, "")) {
              input.value += char; // 模拟逐字符输入
              input.dispatchEvent(inputEvent); // 触发输入事件
            }
            dropdown.style.display = "none"; // 选择后隐藏下拉列表
            isDropdownVisible = false; // 更新标记
          });

          option.addEventListener("mouseenter", () => {
            option.style.backgroundColor = "#f0f0f0"; // 高亮显示
          });

          option.addEventListener("mouseleave", () => {
            option.style.backgroundColor = "white"; // 恢复颜色
          });

          dropdown.appendChild(option);
        });

        dropdown.style.display = "block"; // 显示下拉列表
        isDropdownVisible = true; // 更新标记
      } catch (error) {
        console.error("Error fetching suggestions:", error);
        dropdown.innerHTML = '<div style="padding:10px;">无法获取建议</div>';
        dropdown.style.display = "block"; // 显示错误信息
        isDropdownVisible = true; // 更新标记
      } finally {
        spinner.style.display = "none"; // 隐藏加载动画
      }
    });

    input.addEventListener("blur", () => {
      setTimeout(() => {
        if (!isDropdownVisible) {
          dropdown.style.display = "none"; // 隐藏下拉框
        }
      }, 150); // 延迟以容许选择下拉框选项
    });

    // 在下拉框聚焦时,用户交互时更改标记
    dropdown.addEventListener("mouseenter", () => {
      isDropdownVisible = true; // 进入下拉框时标记为可见
    });

    dropdown.addEventListener("mouseleave", () => {
      isDropdownVisible = false; // 离开下拉框时标记为不可见
      dropdown.style.display = "none"; // 隐藏下拉框
    });
  };

  // 查找所有的输入框和文本区域并嵌入下拉列表
  const updateInputs = () => {
    const inputs = document.querySelectorAll(
      "input:not([updated]), textarea:not([updated])"
    );

    inputs.forEach((input) => {
      if (
        input.tagName.toLowerCase() === "textarea" ||
        ["text", "password", "email", "search", "url", "tel"].includes(
          input.type
        )
      ) {
        attachDropdownToInput(input);
        input.setAttribute("updated", "true");
      }
    });
  };

  // 每隔3秒执行一次
  setInterval(updateInputs, 3000);

  // 添加 CSS 动画
  const style = document.createElement("style");
  style.innerHTML = `
      @keyframes spin {
        0% { transform: rotate(0deg); }
        100% { transform: rotate(360deg); }
      }
      .loading-spinner {
        display: none;
      }
    `;
  document.head.appendChild(style);
})();