- // ==UserScript==
- // @name Zotero GPT Connector
- // @description Zotero GPT Pro, support ChatGPT Gemini Poe Kimi Coze Chatglm Yiyan Tongyi Claude Mytan ChanlderAi DeepSeek Doubao AIStudio
- // @namespace http://tampermonkey.net/
- // @icon https://github.com/MuiseDestiny/zotero-gpt/blob/bootstrap/addon/chrome/content/icons/favicon.png?raw=true
- // @version 3.1.6
- // @author Polygon
- // @match https://chatgpt.com/*
- // @match https://gemini.google.com/app*
- // @match https://poe.com/*
- // @match https://www.coze.com/*
- // @match https://kimi.moonshot.cn/*
- // @match https://chatglm.cn/*
- // @match https://yiyan.baidu.com/*
- // @match https://tongyi.aliyun.com/*
- // @match https://qianwen.aliyun.com/*
- // @match https://claude.ai/*
- // @match https://mytan.maiseed.com.cn/*
- // @match https://mychandler.bet/*
- // @match https://chat.deepseek.com/*
- // @match https://www.doubao.com/chat/*
- // @match https://*.chatshare.biz/*
- // @match https://chat.kelaode.ai/*
- // @match https://chat.rawchat.cn/*
- // @match https://chat.sharedchat.top/*
- // @match https://node.dawuai.buzz/*
- // @match https://aistudio.google.com/*
- // @match https://claude.ai0.cn/*
- // @connect *
- // @grant GM_xmlhttpRequest
- // @grant GM_registerMenuCommand
- // @grant GM_cookie
- // @grant unsafeWindow
- // @run-at document-start
- // ==/UserScript==
-
- (async function () {
- 'use strict';
- let isRunning = true
- let AI = "ChatGPT"
- const host = location.host
- if (host == 'chatgpt.com') {
- AI = "ChatGPT"
- } else if (host == 'gemini.google.com') {
- AI = "Gemini"
- } else if (host == 'poe.com') {
- AI = "Poe"
- } else if (host == 'kimi.moonshot.cn') {
- AI = "Kimi"
- } else if (host == 'www.coze.com') {
- AI = "Coze"
- } else if (host == "chatglm.cn") {
- localStorage.conversation_id = ""
- AI = "Chatglm"
- } else if (host == 'yiyan.baidu.com') {
- AI = "Yiyan"
- } else if (host == 'tongyi.aliyun.com' || host == 'qianwen.aliyun.com') {
- AI = "Tongyi"
- } else if (host == "claude.ai" || host == 'chat.kelaode.ai' || host.includes("claude")) {
- AI = "Claude"
- } else if (host == 'mytan.maiseed.com.cn') {
- AI = "MyTan"
- } else if (host == 'mychandler.bet') {
- localStorage.conversation_id = ""
- AI = "ChanlderAi"
- } else if (host == 'chat.deepseek.com') {
- AI = "DeepSeek"
- } else if (host == "www.doubao.com") {
- AI = "Doubao"
- } else if (host == 'aistudio.google.com') {
- AI = "AIStudio"
- }
- const requestPatchArr = [
- {
- AI: "Kimi",
- regex: /https:\/\/kimi.moonshot.cn\/api\/chat\/.+\/completion\/stream/,
- extract: (text) => {
- let deltaText = ""
- for (let line of text.split("\n")) {
- if (line.startsWith("data")) {
- const data = JSON.parse(line.split("data: ")[1])
- if (data.event == "cmpl") {
- deltaText += data.text
- }
- }
- }
- return deltaText
- },
- text: ""
- },
- {
- AI: "AIStudio",
- regex: /GenerateContent$/,
- extract: (text) => {
- while (true) {
- try {
- JSON.parse(text)
- break
- } catch {
- text += "]"
- }
- }
- const data = JSON.parse(text)
- return data[0].map(i => i[0][0][0][0][0][1]).join("")
- },
- text: ""
- },
- {
- AI: "ChatGPT",
- regex: /backend-api\/conversation$/,
- extract: (text) => {
- let deltaText = ""
- for (let line of text.split("\n")) {
- if (line.startsWith("data: {")) {
- try { JSON.parse(line.split("data: ")[1]) } catch { continue }
- const data = JSON.parse(line.split("data: ")[1])
- if (data.p && data.p.length > 0) { deltaText+="\n"}
- if (typeof(data.v) == "string") {
- deltaText += data.v
- } else if (data.v instanceof Array) {
- if (data.v[0].o == "append") {
- deltaText += data.v[0].v
- }
- }
- }
- }
- return deltaText
- },
- text: ""
- },
- {
- AI: "Claude",
- regex: /chat_conversations\/.+\/completion/,
- extract: (text) => {
- console.log(text)
- let deltaText = ""
- for (let line of text.split("\n")) {
- if (line.startsWith("data: {")) {
- try { JSON.parse(line.split("data: ")[1]) } catch { continue }
- const data = JSON.parse(line.split("data: ")[1])
- if (data.type && data.type == "completion") {
- deltaText += data.completion
- }
- }
- }
- return deltaText
- },
- text: ""
- }
- ]
-
- // 数据拦截,部分网站需要
-
- const originalXhrOpen = XMLHttpRequest.prototype.open;
- XMLHttpRequest.prototype.open = function (method, url, async) {
- this.addEventListener('readystatechange', async function () {
- let requestPatch
- if ((requestPatch = requestPatchArr.find(i => i.regex.test(url)))) {
- if (this.readyState === 3) {
- requestPatch.text = ""
- // 请求返回数据的流式部分
- try {
- requestPatch.text = requestPatch.extract(this.responseText)
- } catch {
- console.log(this.responseText)
- }
- await execInZotero(`
- let task = window.Meet.Connector.tasks[window.Meet.Connector.tasks.length-1]
- task.responseText = ${JSON.stringify(requestPatch.text)};
- task.type = "pending";
- task.responseType = "markdown"
- `)
- } else if (this.readyState == 0) {
- await execInZotero(`
- let task = window.Meet.Connector.tasks[window.Meet.Connector.tasks.length-1]
- task.responseText = ${JSON.stringify(requestPatch.text)};
- task.type = "done";
- task.responseType = "markdown"
- `)
- }
- }
- });
- originalXhrOpen.apply(this, arguments);
- };
-
-
- const originalFetch = window.fetch;
- unsafeWindow.fetch = function () {
- return originalFetch.apply(this, arguments)
- .then(response => {
- const url = response.url
- const requestPatch = requestPatchArr.find(i => i.regex.test(url))
- if (requestPatch) {
- const clonedResponse = response.clone();
- console.log("requestPatch", requestPatch)
- requestPatch.text = ""
- console.log(clonedResponse)
- const reader = clonedResponse.body.getReader();
- const decoder = new TextDecoder()
- function processStream() {
- reader.read().then(({ done, value }) => {
- if (done) {
- execInZotero(`
- let task = window.Meet.Connector.tasks[window.Meet.Connector.tasks.length - 1];
- task.responseText = ${JSON.stringify(requestPatch.text)};
- task.type = "done";
- task.responseType = "markdown";
- `);
- return;
- }
-
- // 将 Uint8Array 转为字符串
- const text = decoder.decode(value, {stream: true});
- requestPatch.text += (requestPatch.extract(text) || "");
-
- execInZotero(`
- let task = window.Meet.Connector.tasks[window.Meet.Connector.tasks.length - 1];
- task.responseText = ${JSON.stringify(requestPatch.text)};
- task.type = "pending";
- task.responseType = "markdown";
- `);
-
- // 递归调用,继续读取流数据
- processStream();
- }).catch(error => {
- // 捕获所有错误,包括 AbortError
- console.log("Error when Patch", error)
- execInZotero(`
- let task = window.Meet.Connector.tasks[window.Meet.Connector.tasks.length - 1];
- task.responseText = ${JSON.stringify(requestPatch.text)};
- task.type = "done";
- task.responseType = "markdown";
- `);
- });
- }
-
- // 开始处理流
- processStream();
- // try {
- // if (done) {
- // execInZotero(`
- // let task = window.Meet.Connector.tasks[window.Meet.Connector.tasks.length-1]
- // task.responseText = ${JSON.stringify(requestPatch.text)};
- // task.type = "done";
- // task.responseType = "markdown"
- // `)
- // return
- // };
- // // 将 Uint8Array 转为字符串
- // const text = new TextDecoder().decode(value);
- // requestPatch.text += (requestPatch.extract(text) || "")
- // execInZotero(`
- // let task = window.Meet.Connector.tasks[window.Meet.Connector.tasks.length-1]
- // task.responseText = ${JSON.stringify(requestPatch.text)};
- // task.type = "pending";
- // task.responseType = "markdown"
- // `)
- // // 递归读取剩余流数据
- // reader.read().then(processStream);
- // } catch {
- // execInZotero(`
- // let task = window.Meet.Connector.tasks[window.Meet.Connector.tasks.length-1]
- // task.responseText = ${JSON.stringify(requestPatch.text)};
- // task.type = "done";
- // task.responseType = "markdown"
- // `)
- // }
- // });
- }
- return response;
- });
- };
-
-
- // 在Zotero中执行代码
- async function execInZotero(code) {
- try {
- 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'));
- }
- });
- });
- } catch (e) {
- window.alert("execInZotero error: " + code);
- return ""
- }
- }
-
- // 设定ChatGPT输入框文本并发送
- const setText = async (text) => {
- const dispatchInput = (selector) => {
- // 获取 input 输入框的dom对象
- var inputNode = document.querySelector(selector);
- if (!inputNode) { return }
- // 修改input的值
- inputNode.value = text;
- // plus
- inputNode.innerText = text;
- // 设置输入框的 input 事件
- var event = new InputEvent('input', {
- 'bubbles': true,
- 'cancelable': true,
- });
- inputNode.dispatchEvent(event);
- }
- const originalText = text
- if (AI == "ChatGPT") {
- dispatchInput('#prompt-textarea')
- await sleep(100)
- await send("article", () => {
- const button = document.querySelector('[data-testid="send-button"]');
- button.click()
- })
- } else if (AI == "Gemini") {
- // 获取 input 输入框的dom对象
- const element_input = window.document.querySelector('rich-textarea .textarea');
- // 修改input的值
- element_input.textContent = text;
- await send(".conversation-container", () => {
- const button = document.querySelector('.send-button');
- button.click()
- })
- } else if (AI == "Poe") {
- dispatchInput('textarea[class*=GrowingTextArea_textArea]')
- document.querySelector("button[class*=ChatMessageSendButton_sendButton]").click();
- setTimeout(() => {
- document.querySelector("button[class*=ChatMessageSendButton_sendButton]").click()
- }, 100)
- } else if (AI == "Kimi") {
- const node = document.querySelector("[class^=inputInner]")
- await node[Object.keys(node)[1]].children[1][1].ref.current.insertText(text)
-
- await send("[class^=segmentItem]", () => {
- const button = document.querySelector('[data-testid=msh-chatinput-send-button]');
- button.click()
- })
-
- } else if (AI == "Coze") {
- const node = document.querySelector(".b5gKALp6yXERRDn8TV4r")
- node[Object.keys(node)[0]].pendingProps.children[0].props.onSendMessage({ text, mentionList: [] })
- } else if (AI == "Chatglm") {
- const token = document.cookie.match(/chatglm_token=([^;]+);/)[1];
- requestStream({
- api: `https://chatglm.cn/chatglm/backend-api/assistant/stream`,
- token,
- data: {
- "assistant_id": "65940acff94777010aa6b796",
- "conversation_id": localStorage.conversation_id || "",
- "meta_data": {
- "mention_conversation_id": "",
- "is_test": false,
- "input_question_type": "xxxx",
- "channel": "",
- "draft_id": ""
- }, "messages": [
- { "role": "user", "content": [{ "type": "text", "text": text }] }]
- },
- lineRegex: /event:message\ndata: .+/g,
- getContent: (data) => data.parts[0].content[0].type == "text" ? data.parts[0].content[0].text : "",
- midFunction: (data) => {
- if (!localStorage.conversation_id || localStorage.conversation_id.length == 0) {
- localStorage.conversation_id = data.conversation_id
- }
- },
- isNotDelta: true
- })
- } else if (AI == "Yiyan") {
- const node = document.querySelector("#eb_model_footer")
- node[Object.keys(node)[1]].children[3].props.children[2].props.children[0].props.setText(text);
- document.querySelector(".VAtmtpqL").click()
- } else if (AI == "Tongyi") {
- const node = document.querySelector(".chatInput--eJzBH8LP")
- await node[Object.keys(node)[1]].children[0].props.setText(text);
-
- await send("[class^=questionItem]", () => {
- const node2 = document.querySelector(".operateBtn--zFx6rSR0");
- node2[Object.keys(node2)[1]].onClick()
- })
- } else if (AI == "Claude") {
- const node = document.querySelector("fieldset")
- const props = node[Object.keys(node)[1]].children[0].props.children[0].props.children[0].props;
- props.setInput(text);
- document.querySelector("button[aria-label='Send Message']").click();
- } else if (AI == "MyTan") {
- const conversation_id = location.href.split("chat/")?.[1]
- const data = {
- "content": [
- { "type": "text", "text": text }
- ],
- "stream": true,
- }
- if (conversation_id) {
- data.conversation_id = conversation_id
- } else {
- data.conversation = { title: "新对话", model: JSON.parse(localStorage["chosen-model-obj"]).model }
- }
- requestStream({
- api: `https://mytan.maiseed.com.cn/api/v2/messages`,
- token: JSON.parse(localStorage["chat-tan-token"]).token,
- data,
- lineRegex: /data: .+/g,
- getContent: (data) => data.choices[0].delta.content,
- })
- } else if (AI == "ChanlderAi") {
- // 更新id
- if (!localStorage.conversation_id || localStorage.conversation_id == "") {
- async function readStream(stream) {
- const reader = stream.getReader();
- let result = '';
- const decoder = new TextDecoder();
- while (true) {
- const { done, value } = await reader.read();
- if (done) break;
-
- result += decoder.decode(value, { stream: true });
- }
- return result
- }
- const res = await fetch("https://api.chandler.bet/api/chat/chatHistory", {
- method: 'POST',
- headers: {
- 'Content-Type': 'application/json',
- "Authorization": `Bearer ${localStorage.token}`,
- "accept": "application/json, text/plain, */*"
- },
- body: JSON.stringify({ "keywords": "", "model_names": [], "page_size": 10, "page_num": 1 }),
- })
- const data = JSON.parse(await readStream(res.body)).data[0]
- localStorage.conversation_id = data.conversation_id
- localStorage.model_name = data.model_name
- localStorage.parent_message_id = data.parent_message_id
- }
- const appData = JSON.parse(localStorage.appLocalStorage)
- requestStream({
- api: `https://api.chandler.bet/api/chat/Chat`,
- token: localStorage.token,
- data: {
- "uid": appData.email,
- "prompt": text,
- "model_name": localStorage.model_name,
- "request_timeout": 30,
- "global_timeout": 100,
- "max_retries": 1,
- "attachment_list": [],
- "parent_message_id": localStorage.parent_message_id,
- "conversation_id": localStorage.conversation_id,
- "answer_again": false,
- "aireply": "",
- "timestamp": (new Date()).getTime(),
- "status": "",
- "app_name": "",
- "web_url": "https://api.chandler.bet"
- },
- lineRegex: /event:message\ndata:.+/g,
- getContent: (data) => data.delta
- })
- } else if (AI == "DeepSeek") {
- requestStream({
- api: `https://chat.deepseek.com/api/v0/chat/completions`,
- token: JSON.parse(localStorage.userToken).value,
- data: {
- "message": text,
- "stream": true,
- "model_preference": null,
- "model_class":
- "deepseek_chat",
- "temperature": 0
- },
- lineRegex: /data: .+/g,
- getContent: (data) => data.choices[0].delta.content || ""
- })
- } else if (AI == "Doubao") {
- const node = document.querySelector("[class^=footer]")
- await node[Object.keys(node)[1]].children.ref.current.autoTransValue(text);
- await sleep(1e3)
- document.querySelector("button#flow-end-msg-send").click();
- } else if (AI == "AIStudio") {
- dispatchInput(".input-wrapper textarea")
- await sleep(100)
- await send("ms-chat-turn", () => {
- const button = document.querySelector('run-button button');
- button.click()
- })
- }
- }
-
- // 连续发送
- const send = async (selector, callback) => {
- const oldNumber = document.querySelectorAll(selector).length;
- callback();
- await sleep(100);
- while (document.querySelectorAll(selector).length == oldNumber) {
- callback();
- await sleep(100);
- }
- }
-
- const uploadFile = async (base64String, fileName) => {
- try {
- let type
- if (fileName.endsWith("pdf")) {
- type = "application/pdf"
- } else if (fileName.endsWith("png")) {
- type = "image/png"
- }
- function base64ToArrayBuffer(base64) {
- const binaryString = atob(base64);
- const len = binaryString.length;
- const bytes = new Uint8Array(len);
- for (let i = 0; i < len; i++) {
- bytes[i] = binaryString.charCodeAt(i);
- }
- return bytes.buffer;
- }
- if (AI == "AIStudio") {
- const button = document.querySelector("ms-add-chunk-menu button")
- button && button.click()
- }
- // 创建一个虚拟的 PDF 文件对象
- const fileContent = base64ToArrayBuffer(base64String);
- const file = new File([fileContent], fileName, { type });
-
- // 创建一个DataTransfer对象
- const dataTransfer = new DataTransfer();
- dataTransfer.items.add(file);
- const fileInput = document.querySelector("input[type=file]") ||
- document.querySelector('[data-testid="file-upload"]') // Claude
-
- fileInput.files = dataTransfer.files
- fileInput.dispatchEvent(new Event('change', { bubbles: true }));
- // 需要特殊处理的
- if (AI == "AIStudio") {
- const button = document.querySelector("ms-add-chunk-menu button")
- button && button.click()
- }
- } catch (e) {
- // window.alert(e)
- }
- }
-
- /**
- * {api, token, data, lineRegex, getContent, errorFunction, midFunction}
- * @param {*} data
- */
- const requestStream = async (params) => {
- fetch(params.api, {
- method: 'POST',
- headers: {
- 'Content-Type': 'application/json',
- 'Authorization': `Bearer ${params.token}`
- },
- body: JSON.stringify(params.data)
- })
- .then(response => {
- if (response.status == 200) {
- return response.body.getReader()
- } else if (response.status == 400) {
- throw new Error('频率过高');
- } {
- throw new Error('授权失败');
- }
- })
- .then(reader => {
- let text = ""
- const decoder = new TextDecoder();
- window.setTimeout(async () => {
- while (true) {
- const { done, value } = await reader.read();
- if (done) {
- await execInZotero(`
- let task = window.Meet.Connector.tasks[window.Meet.Connector.tasks.length-1]
- task.responseText = ${JSON.stringify(text)};
- task.type = "done";
- task.responseType = "markdown"
- `)
- break
- }
- try {
- const newLines = decoder.decode(value, { stream: true })
- for (let line of newLines.match(params.lineRegex)) {
- try {
- const data = JSON.parse(line.split("data:")[1].trim())
- params.midFunction && params.midFunction(data)
- text = params.isNotDelta ? params.getContent(data) : (text + params.getContent(data));
- } catch (e) {
- if (String(e).includes("Stop")) { return }
- }
- execInZotero(`
- let task = window.Meet.Connector.tasks[window.Meet.Connector.tasks.length-1]
- task.responseText = ${JSON.stringify(text)};
- task.type = "pending";
- task.responseType = "markdown"
- `)
- }
- } catch (e) {
- console.log(e)
- }
- }
- }, 0)
- })
- .catch(e => {
- params.errorFunction && params.errorFunction()
- })
- }
- // 阻塞
- function sleep(ms) {
- return new Promise(resolve => setTimeout(resolve, ms));
- }
-
- GM_registerMenuCommand('🔗 运行', () => {
- isRunning = true
- window.alert("🔗 已运行")
- });
- GM_registerMenuCommand('🎊 断开', () => {
- isRunning = false
- window.alert("🎊 断开")
- });
-
- const waitSend = async (selector) => {
- let getUserQuestionNum = () => document.querySelectorAll(selector).length
- const questionNum = getUserQuestionNum()
- while (getUserQuestionNum() == questionNum) {
- await sleep(100)
- }
- }
-
- // 通信
- await sleep(3000)
- while (true) {
- if (!isRunning) {
- await execInZotero(`
- window.Meet.Connector.time = 0;
- `)
- await sleep(1000)
- continue;
- }
- try {
- const tasks = (await execInZotero(`
- if (!window.Meet.Connector){
- window.Meet.Connector = ${JSON.stringify({
- AI, time: Date.now() / 1e3, tasks: []
- })};
- } else {
- window.Meet.Connector.time = ${Date.now() / 1e3};
- window.Meet.Connector.AI = "${AI}";
- }
- window.Meet.Connector
- `)).tasks
- if (!tasks || tasks.length == 0) {
- await sleep(500)
- continue
- }
- const task = tasks.slice(-1)[0]
- if (task.type == "pending") {
- if (task.file) {
- // document.querySelector("[data-testid='create-new-chat-button']").click();
- // await sleep(1e3)
- await uploadFile(task.file.base64String, task.file.name)
- await execInZotero(`
- let task = window.Meet.Connector.tasks[window.Meet.Connector.tasks.length-1]
- task.type = "done"
- `)
- } else if (task.requestText) {
- await setText(task.requestText)
- // 操作浏览器提问
- await execInZotero(`
- let task = window.Meet.Connector.tasks[window.Meet.Connector.tasks.length-1]
- task.requestText = "";
- task.responseText = "<p>Waiting ${AI}...</p>";
- `)
- } else {
- let isDone = false, text = "", type = "html"
- const setZoteroText = async () => {
- if (typeof (text) !== "string") { return }
- await execInZotero(`
- let task = window.Meet.Connector.tasks[window.Meet.Connector.tasks.length-1]
- task.responseText = ${JSON.stringify(text)};
- task.type = ${isDone} ? "done" : "pending";
- task.responseType = "${type}"
- `)
- if (isDone) {
- await sleep(1000)
- await execInZotero(`
- let task = window.Meet.Connector.tasks[window.Meet.Connector.tasks.length-1]
- task.responseText = ${JSON.stringify(text)};
- `)
- }
- }
- if (AI == "Gemini") {
- const outputEle = [...document.querySelectorAll('.conversation-container')].slice(-1)[0];
- const contentEle = outputEle.querySelector("model-response .response-content message-content")
- if (contentEle) {
- isDone = Boolean(outputEle.querySelector(".complete"))
- text = contentEle.querySelector(".markdown").innerHTML
- await setZoteroText()
- }
- } else if (AI == "Poe") {
- type = "markdown"
- const lastNode = [...document.querySelectorAll("[class^=ChatMessagesView_messagePair]")].slice(-1)[0]
- const props = lastNode[Object.keys(lastNode)[0]].child.memoizedProps
- text = props.pairedMessage.text
- isDone = props.pairedMessage.state == "complete"
- await setZoteroText()
- } else if (AI == "Coze") {
- const outputEle = document.querySelector(".message-group-wrapper");
- const contentEle = outputEle.querySelector("[data-testid='bot.ide.chat_area.message_box'] .flow-markdown-body")
- isDone = Boolean(outputEle.querySelector(".chat-uikit-message-box-container__message__message-box__footer").childNodes.length != 0)
- text = contentEle.innerHTML.replace(/<br .+?>/g, "").replace(/<hr .+?>/g, "<hr/>")
- await setZoteroText()
- } else if (AI == "Yiyan") {
- const outputEle = document.querySelector(".ErXhAgf5 .RmHagX8t");
- const contentEle = outputEle.querySelector(".custom-html.md-stream-desktop")
- isDone = Boolean(outputEle.querySelector(".fXxD0Rtx"))
- text = contentEle.innerHTML.replace(/<br .+?>/g, "").replace(/<hr .+?>/g, "<hr/>")
- await setZoteroText()
- } else if (AI == "Tongyi") {
- const lastAnwser = [...document.querySelectorAll("[class^=answerItem]")].slice(-1)[0]
- type = "markdown"
- const message = lastAnwser[Object.keys(lastAnwser)[0]].memoizedProps.children.find(i => { try { return i.props.children[2].props.message } catch { } }).props.children[2].props.message
- isDone = message.contents[message.contents.length - 1].status == "finished"
- text = message.contents[message.contents.length - 1].content
- await setZoteroText()
- } else if (AI == "Doubao") {
- const nodes = [...document.querySelectorAll("[class^=message-box-content-wrapper]")]
- const node = nodes.slice(-1)[0]
- const data = node[Object.keys(node)[0]].child.child.child.child.memoizedState.memoizedState.current.value
- type = "markdown"
- text = data.content_obj.text;
- isDone = data.ext.is_finish == "1";
- await setZoteroText()
- }
- }
- }
- } catch (e) {
- console.log(e)
- await sleep(1000)
- }
- await sleep(10)
- }
- })();