Zotero GPT Connector

Zotero GPT Pro, support ChatGPT Gemini Poe Kimi

目前為 2024-05-22 提交的版本,檢視 最新版本

  1. // ==UserScript==
  2. // @name Zotero GPT Connector
  3. // @namespace http://tampermonkey.net/
  4. // @version 2.1
  5. // @description Zotero GPT Pro, support ChatGPT Gemini Poe Kimi
  6. // @author Polygon
  7. // @match https://chatgpt.com/*
  8. // @match https://gemini.google.com/app*
  9. // @match https://poe.com/*
  10. // @match https://www.coze.com/*
  11. // @match https://kimi.moonshot.cn/*
  12. // @icon https://cdn.oaistatic.com/_next/static/media/favicon-32x32.be48395e.png
  13. // @grant GM_xmlhttpRequest
  14. // @grant GM_registerMenuCommand
  15. // @grant GM_cookie
  16. // @grant unsafeWindow
  17. // @run-at document-start
  18. // ==/UserScript==
  19.  
  20. (async function () {
  21. 'use strict';
  22. let isRunning = true
  23. let AI = ""
  24. if (location.host == 'chatgpt.com') {
  25. AI = "ChatGPT"
  26. } else if (location.host == 'gemini.google.com') {
  27. AI = "Gemini"
  28. } else if (location.host == 'poe.com') {
  29. AI = "Poe"
  30. } else if (location.host == 'kimi.moonshot.cn') {
  31. AI = "Kimi"
  32. } else if (location.host == 'www.coze.com') {
  33. GM_cookie.list({ url: 'https://www.coze.com/' }, function (cookies, error) {
  34. if (!error) {
  35. const cookie = `sessionid_ss=${cookies.find(i => i.name == "sessionid_ss").value};`
  36. console.log(cookie)
  37. }
  38. });
  39. AI = "Coze"
  40. }
  41. // 在Zotero中执行代码
  42. async function execInZotero(code) {
  43. return new Promise((resolve, reject) => {
  44. GM_xmlhttpRequest({
  45. method: "POST",
  46. url: "http://127.0.0.1:23119/zoterogpt",
  47. headers: {
  48. "Content-Type": "application/json",
  49. },
  50. responseType: "json",
  51. data: JSON.stringify({ code }),
  52. onload: function (response) {
  53. if (response.status >= 200 && response.status < 300) {
  54. resolve(response.response.result);
  55. } else {
  56. reject(new Error(`Request failed with status: ${response.status}`));
  57. }
  58. },
  59. onerror: function (error) {
  60. reject(new Error('Network error'));
  61. }
  62. });
  63. });
  64. }
  65.  
  66. // 设定ChatGPT输入框文本并发送
  67. const setText = (text) => {
  68. if (AI == "ChatGPT") {
  69. // 获取 input 输入框的dom对象
  70. var element_input = window.document.querySelector('#prompt-textarea');
  71. // 修改input的值
  72. element_input.value = text;
  73. // 设置输入框的 input 事件
  74. var event = new InputEvent('input', {
  75. 'bubbles': true,
  76. 'cancelable': true,
  77. });
  78. element_input.dispatchEvent(event);
  79. const buttons = document.querySelector("#prompt-textarea").parentElement.parentElement.querySelectorAll("button");
  80. const button = buttons[buttons.length-1]
  81. button.click()
  82. setTimeout(() => {
  83. button.click()
  84. }, 100)
  85. } else if (AI == "Gemini") {
  86. // 获取 input 输入框的dom对象
  87. var element_input = window.document.querySelector('rich-textarea .textarea');
  88. // 修改input的值
  89. element_input.textContent = text;
  90. document.querySelector(".send-button").click();
  91. setTimeout(() => {
  92. document.querySelector(".send-button").click()
  93. }, 100)
  94. } else if (AI == "Poe") {
  95. var element_input = window.document.querySelector('textarea[class*=GrowingTextArea_textArea]');
  96. element_input.value = text;
  97. // 设置输入框的 input 事件
  98. var event = new InputEvent('input', {
  99. 'bubbles': true,
  100. 'cancelable': true,
  101. });
  102. element_input.dispatchEvent(event);
  103. document.querySelector("button[class*=ChatMessageSendButton_sendButton]").click();
  104. setTimeout(() => {
  105. document.querySelector("button[class*=ChatMessageSendButton_sendButton]").click()
  106. }, 100)
  107. } else if (AI == "Kimi") {
  108. fetch(`https://kimi.moonshot.cn/api/chat/${location.href.match(/chat\/([0-9a-z]+)/)[1]}/completion/stream`, {
  109. method: 'POST',
  110. headers: {
  111. 'Content-Type': 'application/json',
  112. "Authorization": `Bearer ${localStorage.access_token}`
  113. },
  114. body: JSON.stringify({ "messages": [{ "role": "user", "content": text }], "refs": [], "use_search": false })
  115. })
  116. .then(response => {
  117. if (response.status == 200) {
  118. return response.body.getReader()
  119. } else {
  120. throw Error("授权失败")
  121. }
  122. })
  123. .then(reader => {
  124. let text = ""
  125. const decoder = new TextDecoder();
  126. window.setTimeout(async () => {
  127. while (true) {
  128. const { done, value } = await reader.read();
  129. if (done) {
  130. await execInZotero(`
  131. let task = window.Meet.tasks[window.Meet.tasks.length-1]
  132. task.responseText = ${JSON.stringify(text)};
  133. task.type = "done";
  134. task.responseType = "markdown"
  135. `)
  136. break
  137. }
  138. try {
  139. const newLines = decoder.decode(value, { stream: true })
  140. for (let line of newLines.match(/data: .+/g)) {
  141. try {
  142. const data = JSON.parse(line.split("data: ")[1])
  143. if (data.event && data.event == "cmpl") {
  144. text += data.text
  145. } else if (data.error) {
  146. text += data.error.message;
  147. console.log(data);
  148. document.querySelector("[data-testid=msh-sidebar-new]").click();
  149. window.setTimeout(() => {
  150. setText(text)
  151. }, 1000)
  152. return
  153. }
  154. } catch { }
  155. execInZotero(`
  156. let task = window.Meet.tasks[window.Meet.tasks.length-1]
  157. task.responseText = ${JSON.stringify(text)};
  158. task.type = "pending";
  159. task.responseType = "markdown"
  160. `)
  161. }
  162. } catch (e) {
  163. console.log(e)
  164. }
  165.  
  166. }
  167. }, 0)
  168. })
  169. .catch(e => {
  170. console.log(e)
  171.  
  172. window.setTimeout(async () => {
  173. const res = await fetch("https://kimi.moonshot.cn/api/auth/token/refresh", {
  174. headers: {
  175. "Authorization": `Bearer ${localStorage.refresh_token}`
  176. }
  177. })
  178. const data = await res.json()
  179. localStorage.access_token = data.access_token
  180. localStorage.refresh_token = data.refresh_token
  181. setText(text)
  182. })
  183. })
  184. } else if (AI == "Coze") {
  185. GM_cookie.list({ url: 'https://www.coze.com/' }, function (cookies, error) {
  186. if (!error) {
  187. const cookie = `sessionid_ss=${cookies.find(i => i.name == "sessionid_ss").value};`
  188. console.log(cookie)
  189. }
  190. });
  191.  
  192. }
  193. }
  194.  
  195. // 阻塞
  196. function sleep(ms) {
  197. return new Promise(resolve => setTimeout(resolve, ms));
  198. }
  199.  
  200. GM_registerMenuCommand('🔗 运行', () => {
  201. isRunning = true
  202. window.alert("🔗 已运行")
  203. });
  204. GM_registerMenuCommand('🎊 断开', () => {
  205. isRunning = false
  206. window.alert("🎊 断开")
  207. });
  208.  
  209.  
  210. // 通信
  211. await sleep(3000)
  212. while (true) {
  213. if (!isRunning) {
  214. await execInZotero(`
  215. window.Meet.tasks = undefined
  216. `)
  217. await sleep(1000)
  218. continue;
  219. }
  220. try {
  221. const result = await execInZotero(`
  222. if (!window.Meet.tasks){
  223. window.Meet.tasks = []
  224. } else {
  225. window.Meet.tasks
  226. }
  227. `)
  228. const tasks = result;
  229. if (!tasks || tasks.length == 0) {
  230. await sleep(500)
  231. continue
  232. }
  233. const task = tasks.slice(-1)[0]
  234. if (task.type == "pending") {
  235. if (task.requestText) {
  236. // 操作浏览器提问
  237. if (AI == "ChatGPT") {
  238. let getUserQuestionNum = () => document.querySelectorAll("[data-message-author-role=user]").length
  239. const questionNum = getUserQuestionNum()
  240. setText(task.requestText)
  241. while (getUserQuestionNum() == questionNum) {
  242. await sleep(100)
  243. }
  244. } else if (AI == "Gemini") {
  245. let getUserQuestionNum = () => document.querySelectorAll("user-query").length
  246. const questionNum = getUserQuestionNum()
  247. setText(task.requestText)
  248. while (getUserQuestionNum() == questionNum) {
  249. await sleep(100)
  250. }
  251. while (document.querySelectorAll('model-response').length != getUserQuestionNum()) {
  252. await sleep(100)
  253.  
  254. }
  255. } else if (AI == "Poe") {
  256. let getUserQuestionNum = () => document.querySelectorAll("[class*=ChatMessage_humanMessageWrapper]").length
  257. const questionNum = getUserQuestionNum()
  258. setText(task.requestText)
  259. while (getUserQuestionNum() == questionNum) {
  260. await sleep(100)
  261. }
  262. while (document.querySelectorAll('[class*=Message_botMessageBubble]').length != getUserQuestionNum()) {
  263. await sleep(100)
  264. }
  265. } else if (AI == "Kimi") {
  266. setText(task.requestText)
  267. }
  268. await execInZotero(`
  269. let task = window.Meet.tasks[window.Meet.tasks.length-1]
  270. task.requestText = "";
  271. task.responseText = "<p>Answering (本过程不消耗Api Key额度)...</p>";
  272. `)
  273. } else {
  274.  
  275. let isDone = false, text = "", type = "html"
  276. const setZoteroText = async () => {
  277. await execInZotero(`
  278. let task = window.Meet.tasks[window.Meet.tasks.length-1]
  279. task.responseText = ${JSON.stringify(text)};
  280. task.type = ${isDone} ? "done" : "pending";
  281. task.responseType = "${type}"
  282. `)
  283. if (isDone) {
  284. await sleep(1000)
  285. await execInZotero(`
  286. let task = window.Meet.tasks[window.Meet.tasks.length-1]
  287. task.responseText = ${JSON.stringify(text)};
  288. `)
  289. }
  290. }
  291. if (AI == "ChatGPT") {
  292. const outputEle = [...document.querySelectorAll('[data-testid^=conversation-turn]')].slice(-1)[0];
  293. // const contentEle = outputEle.querySelector("div>div>div:nth-child(2)>div:nth-child(2)>div")
  294. isDone = Boolean(outputEle.querySelector("span[data-state=closed]"))
  295. text = outputEle.querySelector(".markdown").innerHTML
  296. await setZoteroText()
  297. } else if (AI == "Gemini") {
  298. const outputEle = [...document.querySelectorAll('model-response')].slice(-1)[0];
  299. const contentEle = outputEle.querySelector(".response-content message-content")
  300. isDone = Boolean(outputEle.querySelector(".complete"))
  301. text = contentEle.querySelector(".markdown").innerHTML
  302. await setZoteroText()
  303. } else if (AI == "Poe") {
  304. const outputEle = [...document.querySelectorAll('[class*=Message_botMessageBubble]')].slice(-1)[0];
  305. const contentEle = outputEle.querySelector("[class*=Markdown_markdownContainer]")
  306. isDone = Boolean(document.querySelector("[class*=ChatMessageActionBar_actionBar]"))
  307. text = contentEle.innerHTML
  308. await setZoteroText()
  309. } else if (AI == "Kimi") {
  310. //
  311. }
  312.  
  313. }
  314. }
  315. } catch (e) {
  316. console.log(e)
  317. }
  318. await sleep(100)
  319. }
  320. })();

QingJ © 2025

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