Zotero GPT Connector

Zotero GPT Pro, support ChatGPT Gemini Poe Kimi Coze Chatglm yiyan

目前為 2024-07-21 提交的版本,檢視 最新版本

  1. // ==UserScript==
  2. // @name Zotero GPT Connector
  3. // @namespace http://tampermonkey.net/
  4. // @version 2.6.3
  5. // @description Zotero GPT Pro, support ChatGPT Gemini Poe Kimi Coze Chatglm yiyan
  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. // @match https://chatglm.cn/*
  13. // @match https://chatglm.cn/*
  14. // @match https://yiyan.baidu.com*
  15. // @match https://tongyi.aliyun.com/qianwen/*
  16. // @icon https://cdn.oaistatic.com/_next/static/media/favicon-32x32.be48395e.png
  17. // @grant GM_xmlhttpRequest
  18. // @grant GM_registerMenuCommand
  19. // @grant GM_cookie
  20. // @grant unsafeWindow
  21. // @run-at document-start
  22. // ==/UserScript==
  23.  
  24. (async function () {
  25. 'use strict';
  26. let isRunning = true
  27. let AI = ""
  28. if (location.host == 'chatgpt.com') {
  29. AI = "ChatGPT"
  30. } else if (location.host == 'gemini.google.com') {
  31. AI = "Gemini"
  32. } else if (location.host == 'poe.com') {
  33. AI = "Poe"
  34. } else if (location.host == 'kimi.moonshot.cn') {
  35. AI = "Kimi"
  36. } else if (location.host == 'www.coze.com') {
  37. AI = "Coze"
  38. } else if (location.host == "chatglm.cn") {
  39. AI = "Chatglm"
  40. GM_cookie.list({
  41. url: 'https://chatglm.cn/chatglm/feed-api/assistant_top/v4/recent_list' }, function (cookies, error) {
  42. if (!error) {
  43. localStorage.setItem("token", cookies.find(i => i.name == "chatglm_token").value);
  44. localStorage.conversation_id = ""
  45. }
  46. });
  47. } else if (location.host == 'yiyan.baidu.com') {
  48. AI = "Yiyan"
  49. } else if (location.host == 'tongyi.aliyun.com') {
  50. AI = "Tongyi"
  51. }
  52. // 在Zotero中执行代码
  53. async function execInZotero(code) {
  54. return new Promise((resolve, reject) => {
  55. GM_xmlhttpRequest({
  56. method: "POST",
  57. url: "http://127.0.0.1:23119/zoterogpt",
  58. headers: {
  59. "Content-Type": "application/json",
  60. },
  61. responseType: "json",
  62. data: JSON.stringify({ code }),
  63. onload: function (response) {
  64. if (response.status >= 200 && response.status < 300) {
  65. resolve(response.response.result);
  66. } else {
  67. reject(new Error(`Request failed with status: ${response.status}`));
  68. }
  69. },
  70. onerror: function (error) {
  71. reject(new Error('Network error'));
  72. }
  73. });
  74. });
  75. }
  76.  
  77. // 设定ChatGPT输入框文本并发送
  78. const setText = (text) => {
  79. const originalText = text
  80. if (AI == "ChatGPT") {
  81. // 获取 input 输入框的dom对象
  82. var element_input = window.document.querySelector('#prompt-textarea');
  83. // 修改input的值
  84. element_input.value = text;
  85. // 设置输入框的 input 事件
  86. var event = new InputEvent('input', {
  87. 'bubbles': true,
  88. 'cancelable': true,
  89. });
  90. element_input.dispatchEvent(event);
  91. const buttons = document.querySelector("#prompt-textarea").parentElement.parentElement.querySelectorAll("button");
  92. const button = buttons[buttons.length - 1]
  93. button.click()
  94. setTimeout(() => {
  95. button.click()
  96. }, 100)
  97. } else if (AI == "Gemini") {
  98. // 获取 input 输入框的dom对象
  99. var element_input = window.document.querySelector('rich-textarea .textarea');
  100. // 修改input的值
  101. element_input.textContent = text;
  102. document.querySelector(".send-button").click();
  103. setTimeout(() => {
  104. document.querySelector(".send-button").click()
  105. }, 100)
  106. } else if (AI == "Poe") {
  107. var element_input = window.document.querySelector('textarea[class*=GrowingTextArea_textArea]');
  108. element_input.value = text;
  109. // 设置输入框的 input 事件
  110. var event = new InputEvent('input', {
  111. 'bubbles': true,
  112. 'cancelable': true,
  113. });
  114. element_input.dispatchEvent(event);
  115. document.querySelector("button[class*=ChatMessageSendButton_sendButton]").click();
  116. setTimeout(() => {
  117. document.querySelector("button[class*=ChatMessageSendButton_sendButton]").click()
  118. }, 100)
  119. } else if (AI == "Kimi") {
  120. fetch(`https://kimi.moonshot.cn/api/chat/${location.href.match(/chat\/([0-9a-z]+)/)[1]}/completion/stream`, {
  121. method: 'POST',
  122. headers: {
  123. 'Content-Type': 'application/json',
  124. "Authorization": `Bearer ${localStorage.access_token}`
  125. },
  126. body: JSON.stringify({ "messages": [{ "role": "user", "content": text }], "refs": [], "use_search": false })
  127. })
  128. .then(response => {
  129. if (response.status == 200) {
  130. return response.body.getReader()
  131. } else {
  132. throw Error("授权失败")
  133. }
  134. })
  135. .then(reader => {
  136. let text = ""
  137. const decoder = new TextDecoder();
  138. window.setTimeout(async () => {
  139. while (true) {
  140. const { done, value } = await reader.read();
  141. if (done) {
  142. await execInZotero(`
  143. let task = window.Meet.tasks[window.Meet.tasks.length-1]
  144. task.responseText = ${JSON.stringify(text)};
  145. task.type = "done";
  146. task.responseType = "markdown"
  147. `)
  148. break
  149. }
  150. try {
  151. const newLines = decoder.decode(value, { stream: true })
  152. for (let line of newLines.match(/data: .+/g)) {
  153. try {
  154. const data = JSON.parse(line.split("data: ")[1])
  155. if (data.event && data.event == "cmpl") {
  156. text += data.text
  157. } else if (data.error) {
  158. text += data.error.message;
  159. console.log(data);
  160. document.querySelector("[data-testid=msh-sidebar-new]").click();
  161. window.setTimeout(() => {
  162. setText(originalText)
  163. }, 1000)
  164. return
  165. }
  166. } catch { }
  167. execInZotero(`
  168. let task = window.Meet.tasks[window.Meet.tasks.length-1]
  169. task.responseText = ${JSON.stringify(text)};
  170. task.type = "pending";
  171. task.responseType = "markdown"
  172. `)
  173. }
  174. } catch (e) {
  175. console.log(e)
  176. }
  177.  
  178. }
  179. }, 0)
  180. })
  181. .catch(e => {
  182. console.log(e)
  183.  
  184. window.setTimeout(async () => {
  185. const res = await fetch("https://kimi.moonshot.cn/api/auth/token/refresh", {
  186. headers: {
  187. "Authorization": `Bearer ${localStorage.refresh_token}`
  188. }
  189. })
  190. const data = await res.json()
  191. localStorage.access_token = data.access_token
  192. localStorage.refresh_token = data.refresh_token
  193. setText(text)
  194. })
  195. })
  196. } else if (AI == "Coze") {
  197. const node = document.querySelector(".b5gKALp6yXERRDn8TV4r")
  198. node[Object.keys(node)[0]].pendingProps.children[0].props.onSendMessage({ text, mentionList: [] })
  199. } else if (AI == "Chatglm") {
  200. fetch(`https://chatglm.cn/chatglm/backend-api/assistant/stream`, {
  201. method: 'POST',
  202. headers: {
  203. 'Content-Type': 'application/json',
  204. "Authorization": `Bearer ${localStorage.token}`
  205. },
  206. body: JSON.stringify({
  207. "assistant_id": "65940acff94777010aa6b796",
  208. "conversation_id": localStorage.conversation_id || "",
  209. "meta_data": {
  210. "mention_conversation_id": "",
  211. "is_test": false,
  212. "input_question_type": "xxxx",
  213. "channel": "",
  214. "draft_id": ""
  215. }, "messages": [
  216. { "role": "user", "content": [{ "type": "text", "text": text }] }]
  217. })
  218. })
  219. .then(response => {
  220. if (response.status == 200) {
  221. return response.body.getReader()
  222. } else {
  223. throw Error("授权失败")
  224. }
  225. })
  226. .then(reader => {
  227. let text = ""
  228. const decoder = new TextDecoder();
  229. window.setTimeout(async () => {
  230. while (true) {
  231. const { done, value } = await reader.read();
  232. if (done) {
  233. await execInZotero(`
  234. let task = window.Meet.tasks[window.Meet.tasks.length-1]
  235. task.responseText = ${JSON.stringify(text)};
  236. task.type = "done";
  237. task.responseType = "markdown"
  238. `)
  239. break
  240. }
  241. try {
  242. const newLines = decoder.decode(value, { stream: true })
  243. for (let line of newLines.match(/event:message\ndata: .+/g)) {
  244. try {
  245. const data = JSON.parse(line.split("data: ")[1])
  246. if (localStorage.conversation_id.length == 0) {
  247. localStorage.conversation_id = data.conversation_id
  248. }
  249. text = data.parts[0].content[0].text
  250. } catch { }
  251. execInZotero(`
  252. let task = window.Meet.tasks[window.Meet.tasks.length-1]
  253. task.responseText = ${JSON.stringify(text)};
  254. task.type = "pending";
  255. task.responseType = "markdown"
  256. `)
  257. }
  258. } catch (e) {
  259. console.log(e)
  260. }
  261.  
  262. }
  263. }, 0)
  264. })
  265. .catch(e => {
  266. console.log(e)
  267. localStorage.conversation_id = ""
  268. })
  269.  
  270. } else if (AI == "Yiyan") {
  271. const node = document.querySelector("#eb_model_footer")
  272. node[Object.keys(node)[1]].children[2].props.children[2].props.children[0].props.setText(text);
  273. document.querySelector(".VAtmtpqL").click()
  274. } else if (AI == "Tongyi") {
  275. const node = document.querySelector(".inputField--PE5FhWzd").children[0]
  276. node[Object.keys(node)[1]].children[3].props.children[0].props.setText(text);
  277. window.setTimeout(async () => {
  278. const node2 = document.querySelector(".operateBtn--zFx6rSR0");
  279. node2[Object.keys(node2)[1]].onClick()
  280. })
  281. }
  282. }
  283.  
  284. // 阻塞
  285. function sleep(ms) {
  286. return new Promise(resolve => setTimeout(resolve, ms));
  287. }
  288.  
  289. GM_registerMenuCommand('🔗 运行', () => {
  290. isRunning = true
  291. window.alert("🔗 已运行")
  292. });
  293. GM_registerMenuCommand('🎊 断开', () => {
  294. isRunning = false
  295. window.alert("🎊 断开")
  296. });
  297.  
  298.  
  299. // 通信
  300. await sleep(3000)
  301. while (true) {
  302. if (!isRunning) {
  303. await execInZotero(`
  304. window.Meet.tasks = undefined
  305. `)
  306. await sleep(1000)
  307. continue;
  308. }
  309. try {
  310. const result = await execInZotero(`
  311. if (!window.Meet.tasks){
  312. window.Meet.tasks = []
  313. } else {
  314. window.Meet.tasks
  315. }
  316. `)
  317. const tasks = result;
  318. if (!tasks || tasks.length == 0) {
  319. await sleep(500)
  320. continue
  321. }
  322. const task = tasks.slice(-1)[0]
  323. if (task.type == "pending") {
  324. if (task.requestText) {
  325. // 操作浏览器提问
  326. if (AI == "ChatGPT") {
  327. let getUserQuestionNum = () => document.querySelectorAll("[data-message-author-role=user]").length
  328. const questionNum = getUserQuestionNum()
  329. setText(task.requestText)
  330. while (getUserQuestionNum() == questionNum) {
  331. await sleep(100)
  332. }
  333. } else if (AI == "Gemini") {
  334. let getUserQuestionNum = () => document.querySelectorAll("user-query").length
  335. const questionNum = getUserQuestionNum()
  336. setText(task.requestText)
  337. while (getUserQuestionNum() == questionNum) {
  338. await sleep(100)
  339. }
  340. while (document.querySelectorAll('model-response').length != getUserQuestionNum()) {
  341. await sleep(100)
  342.  
  343. }
  344. } else if (AI == "Poe") {
  345. let getUserQuestionNum = () => document.querySelectorAll("[class*=ChatMessage_humanMessageWrapper]").length
  346. const questionNum = getUserQuestionNum()
  347. setText(task.requestText)
  348. while (getUserQuestionNum() == questionNum) {
  349. await sleep(100)
  350. }
  351. while (document.querySelectorAll('[class*=Message_botMessageBubble]').length != getUserQuestionNum()) {
  352. await sleep(100)
  353. }
  354. } else if (AI == "Kimi") {
  355. setText(task.requestText)
  356. } else if (AI == "Coze") {
  357. setText(task.requestText)
  358. } else if (AI == "Chatglm") {
  359. setText(task.requestText)
  360. } else if (AI == "Yiyan") {
  361. setText(task.requestText)
  362. } else if (AI == "Tongyi") {
  363. setText(task.requestText)
  364. }
  365. await execInZotero(`
  366. let task = window.Meet.tasks[window.Meet.tasks.length-1]
  367. task.requestText = "";
  368. task.responseText = "<p>Answering (本过程不消耗Api Key额度)...</p>";
  369. `)
  370. } else {
  371. let isDone = false, text = "", type = "html"
  372. const setZoteroText = async () => {
  373. await execInZotero(`
  374. let task = window.Meet.tasks[window.Meet.tasks.length-1]
  375. task.responseText = ${JSON.stringify(text)};
  376. task.type = ${isDone} ? "done" : "pending";
  377. task.responseType = "${type}"
  378. `)
  379. if (isDone) {
  380. await sleep(1000)
  381. await execInZotero(`
  382. let task = window.Meet.tasks[window.Meet.tasks.length-1]
  383. task.responseText = ${JSON.stringify(text)};
  384. `)
  385. }
  386. }
  387. if (AI == "ChatGPT") {
  388. type = "markdown"
  389. const outputEle = [...document.querySelectorAll('[data-testid^=conversation-turn]')].slice(-1)[0];
  390. const node = outputEle.querySelector("[data-message-author-role=assistant]")
  391. // const contentEle = outputEle.querySelector("div>div>div:nth-child(2)>div:nth-child(2)>div")
  392. isDone = Boolean(outputEle.querySelector("span[data-state=closed]"))
  393. text = node[Object.keys(node)[0]].alternate.alternate.pendingProps.children[1].props.messages[0].message.content.parts[0]
  394.  
  395. await setZoteroText()
  396. } else if (AI == "Gemini") {
  397. const outputEle = [...document.querySelectorAll('model-response')].slice(-1)[0];
  398. const contentEle = outputEle.querySelector(".response-content message-content")
  399. isDone = Boolean(outputEle.querySelector(".complete"))
  400. text = contentEle.querySelector(".markdown").innerHTML
  401. await setZoteroText()
  402. } else if (AI == "Poe") {
  403. const outputEle = [...document.querySelectorAll('[class*=Message_botMessageBubble]')].slice(-1)[0];
  404. const contentEle = outputEle.querySelector("[class*=Markdown_markdownContainer]")
  405. isDone = Boolean(document.querySelector("[class*=ChatMessageActionBar_actionBar]"))
  406. text = contentEle.innerHTML
  407. await setZoteroText()
  408. } else if (AI == "Kimi") {
  409. // 无需这一步
  410. } else if (AI == "Coze") {
  411. const outputEle = document.querySelector(".message-group-wrapper");
  412. const contentEle = outputEle.querySelector("[data-testid='bot.ide.chat_area.message_box'] .flow-markdown-body")
  413. isDone = Boolean(outputEle.querySelector(".chat-uikit-message-box-container__message__message-box__footer").childNodes.length != 0)
  414. text = contentEle.innerHTML.replace(/<br .+?>/g, "").replace(/<hr .+?>/g, "<hr/>")
  415. await setZoteroText()
  416. } else if (AI == "Kimi") {
  417. // 无需这一步
  418. } else if (AI == "Yiyan") {
  419. const outputEle = document.querySelector(".ErXhAgf5 .RmHagX8t");
  420. const contentEle = outputEle.querySelector(".custom-html.md-stream-desktop")
  421. isDone = Boolean(outputEle.querySelector(".fXxD0Rtx"))
  422. text = contentEle.innerHTML.replace(/<br .+?>/g, "").replace(/<hr .+?>/g, "<hr/>")
  423. await setZoteroText()
  424. } else if (AI == "Tongyi") {
  425. const lastQuestion = [...document.querySelectorAll(".questionItem--dS3Alcnv")].slice(-1)[0]
  426. const outputEle = lastQuestion.nextElementSibling;
  427. const contentEle = outputEle.querySelector(".tongyi-ui-markdown")
  428. isDone = Boolean(outputEle.querySelector(".tools--IJfoLgka"))
  429. type = "markdown"
  430. text = contentEle[Object.keys(contentEle)[1]].children._owner.pendingProps.children
  431. .replace(/\[ty-private-cursor\]\(ty-private-cursor\)$/, "")
  432.  
  433. await setZoteroText()
  434. }
  435. }
  436. }
  437. } catch (e) {
  438. console.log(e)
  439. }
  440. await sleep(100)
  441. }
  442. })();

QingJ © 2025

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