Zotero GPT Connector

Connector

当前为 2023-11-30 提交的版本,查看 最新版本

// ==UserScript==
// @name         Zotero GPT Connector
// @namespace    http://tampermonkey.net/
// @version      0.5
// @description  Connector
// @author       Polygon
// @match        https://chat.openai.com/*
// @icon         https://cdn.oaistatic.com/_next/static/media/favicon-32x32.be48395e.png
// @grant        GM_xmlhttpRequest
// @grant        GM_registerMenuCommand
// @grant        unsafeWindow
// @run-at       document-start
// ==/UserScript==

(async function () {
  'use strict';
  // 在Zotero中执行代码
  function execInZotero(code) {
    return new Promise((resolve, reject) => {
      GM_xmlhttpRequest({
        method: "POST",
        url: "http://127.0.0.1:23119/zoterogpt",
        headers: {
          "Content-Type": "application/json",
        },
        responseType: "json",
        data: JSON.stringify({code}),
        onload: function (response) {
          if (response.status >= 200 && response.status < 300) {
            resolve(response.response.result);
          } else {
            reject(new Error(`Request failed with status: ${response.status}`));
          }
        },
        onerror: function (error) {
          reject(new Error('Network error'));
        }
      });
    });
  }

  // 设定ChatGPT输入框文本并发送
  const setText = (text) => {
    // 获取 input 输入框的dom对象
    var element_input = window.document.querySelector('#prompt-textarea');
    // 修改input的值
    element_input.value = text;
    // 设置输入框的 input 事件
    var event = new InputEvent('input', {
      'bubbles': true,
      'cancelable': true,
    });
    element_input.dispatchEvent(event);
    document.querySelector("[data-testid=send-button]").click()
    setTimeout(() => {
      document.querySelector("[data-testid=send-button]").click()
    }, 100)
  }

  // 阻塞
  function sleep(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
  }
  let isRunning = true
  GM_registerMenuCommand('🔗 运行', () => {
    isRunning = true
    window.alert("🔗 已运行")
  });
  GM_registerMenuCommand('🎊 断开', () => {
    isRunning = false
    window.alert("🎊 断开")
  });

  // Ctrl+Enter 发送到Zotero GPT执行
  const callback = async (e) => {
    e.stopPropagation();
    e.preventDefault();
    const text = document.querySelector('#prompt-textarea').value
    document.querySelector('#prompt-textarea').innerHTML = "Thinking..."
    document.querySelector('#prompt-textarea').value = "Thinking..."
    console.log("接收文本", JSON.stringify(text))
    await execInZotero(`
        const views = Zotero.ZoteroGPT.views;
        views.inputContainer.querySelector("input").value = ${JSON.stringify(text) }
        window.setTimeout(async()=>{
          await Zotero.ZoteroGPT.views.execText(${
            JSON.stringify(text)
          }) 
        })
      `)
  }
  window.setInterval(() => {
    const isListener = document.querySelector('#prompt-textarea').getAttribute("is-listener")
    if (!isListener) {
      document.querySelector('#prompt-textarea')
        .addEventListener("keydown", async (e) => {
          if (!(e.ctrlKey && e.key == "Enter" && isRunning)) { return }
          callback(e)
        })
      document.querySelector('#prompt-textarea').setAttribute("is-listener", "1")
    }
  }, 1000)
  
  
  // 通信
  while (true) {
    if (!isRunning) {
      await execInZotero(`
        window.Meet.tasks = undefined
      `)
      await sleep(1000)
      continue;
    }
    try {
      const result = await execInZotero(`
        if (!window.Meet.tasks){
          window.Meet.tasks = []
        } else {
          window.Meet.tasks
        }
      `)
      const tasks = result;
      if (!tasks || tasks.length == 0) {
        await sleep(500)
        continue
      }
      const task = tasks.slice(-1)[0]
      if (task.type == "request") {
        // 操作浏览器提问
        let getUserQuestionNum = () => document.querySelectorAll("[data-message-author-role=user]").length
        const questionNum = getUserQuestionNum()
        console.log(task.text)
        setText(task.text)
        while (getUserQuestionNum() == questionNum) {
          await sleep(100)
        }
        await execInZotero(`
          window.Meet.tasks.push({
            type: "response",
            text: ""
          })
          const views = Zotero.ZoteroGPT.views;
          views.setText("Thinking...", false, true, "text")
        `)
      } else if (task.type == "response") {
        const outputEle = [...document.querySelectorAll('[data-testid^=conversation-turn]')].slice(-1)[0];
        const contentEle = outputEle.querySelector("div>div>div:nth-child(2)>div:nth-child(2)>div")
        const isDone = Boolean(outputEle.querySelector("div>div>div:nth-child(2)>div:nth-child(2)>div:nth-child(2) button"))
        const text = contentEle.querySelector(".markdown").innerHTML
        const taskJson = JSON.stringify({
          type: "response",
          text,
          isDone
        })
        console.log(taskJson)
        execInZotero(`
          let task = window.Meet.tasks[window.Meet.tasks.length-1]
          if (task.type == "response" && !task.isSetDone) {
            task = (window.Meet.tasks[window.Meet.tasks.length-1] = ${taskJson})
            const views = Zotero.ZoteroGPT.views;
            views.setText(task.text, task.isDone, true, "html")
            if (task.isDone) {
              task.isSetDone = true
            }
          }
        `)
      }
    } catch (e) {
      // console.log(e)
    }
    await sleep(10)
  }
})();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址