// ==UserScript== // @name ChatGPT功能增强 // @namespace http://tampermonkey.net/ // @version 1.3.7 // @description 目前功能:1.关闭数据监管;2.会话导入导出;3.高负载限制解锁 4.混合接入API(GPT3.5) 5.链接维持 ( 减少An error occured ) 6.聊天记录下载 // @author bigemon; 捈荼 // @match https://chat.openai.com/* // @icon https://chat.openai.com/favicon.ico // @license GPL-3.0 // @run-at document-idie // @grant none // @downloadURL https://update.greasyfork.icu/scripts/456901/ChatGPT%E5%8A%9F%E8%83%BD%E5%A2%9E%E5%BC%BA.user.js // @updateURL https://update.greasyfork.icu/scripts/456901/ChatGPT%E5%8A%9F%E8%83%BD%E5%A2%9E%E5%BC%BA.meta.js // ==/UserScript== function dispose(_alert) { /* This file is automatically generated by ChatGPT based on instructions */ // Get the entire page's source code as a string var pageSource = document.documentElement.outerHTML; if (pageSource.indexOf('cf-spinner-please-wait') === -1 && !window.oofPatch && window.location.href.indexOf("/auth/login") !== -1) { window.oofPatch = true; // Replace '"oof":true' with '"oof":false' pageSource = pageSource.replace(/\"oof\":true/g, '"oof":false'); // Replace the current page's source code with the modified version document.open(); document.write(pageSource); document.close(); } window.enableFakeMod = (localStorage.getItem("enable_fakemod") == 'false') ? false : true; // 创建一个新的style元素 var style = document.createElement('style'); // 在style元素中添加CSS样式 style.innerHTML = '.switch{position:relative;display:inline-block;width:60px;height:34px;}.switch input{opacity:0;width:0;height:0;}.slider{position:absolute;cursor:pointer;top:0;left:0;right:0;bottom:0;background-color:#ccc;-webkit-transition:.4s;transition:.4s;}.slider:before{position:absolute;content:"";height:26px;width:26px;left:4px;bottom:4px;background-color:white;-webkit-transition:.4s;transition:.4s;}input:checked + .slider{background-color:#2196F3;}input:focus + .slider{box-shadow:0 0 1px #2196F3;}input:checked + .slider:before{-webkit-transform:translateX(26px);-ms-transform:translateX(26px);transform:translateX(26px);}.slider.round{border-radius:34px;}.slider.round:before{border-radius:50%;}'; // 将style元素添加到页面的head中 document.head.appendChild(style); window.switchEnableFakeMod = function () { let cswitch = document.querySelector("input#cswitch"); let checked = cswitch ? cswitch.checked : false; if (checked) { window.enableFakeMod = true; localStorage.setItem("enable_fakemod", true); } else { window.enableFakeMod = false; localStorage.setItem('enable_fakemod', false); } }; window.clearAllBoxItem = function () { let navs = document.querySelectorAll('nav'); for (var x = 0; x < navs.length; x++) { var allItems = navs[x].querySelectorAll('div.toolbox-item'); for (var i = 0; i < allItems.length; i++) { allItems[i].remove(); } } }; window.exportSaveData = function () { var conversation_id = window.conversation_id_last || ""; var parent_message_id = window.parent_message_id_last || ""; var authorization = window.authorization_last; if (conversation_id == "" || parent_message_id == "" || conversation_id == "undefined" || parent_message_id == "undefined") { alert("请至少说两句话再使用这个功能!"); return; } var jsonObject = { conversation_id: conversation_id, parent_message_id: parent_message_id, authorization: authorization }; var jsonString = JSON.stringify(jsonObject); var base64String = window.btoa(jsonString); return base64String; }; window.importSaveData = function (savB64) { var decodedString = window.atob(savB64); var jsonObject = JSON.parse(decodedString); if (!jsonObject || jsonObject.conversation_id === undefined || jsonObject.parent_message_id === undefined) { alert("会话存档已损坏, 请确保完整复制!"); return } let authUnix = window.getAuthTimestamp(jsonObject.authorization) || 0; if (authUnix && Math.floor(Date.now() / 1000) > authUnix) { if (!confirm("这个会话存档的Token看起来已过期,或许无法正常工作。\r\n假如这个存档是由当前账号所导出,您可以尝试使用当前会话覆盖导入的状态。\r\n是否继续?")) { return } } else { alert("这个会话存档的有效期最长至:\r\n" + (new Date(authUnix * 1000)).toLocaleString('en-US') + "\r\n\r\n请注意:导入的会话无法被再次导出,也无法保存"); window.import_authorization = jsonObject.authorization; } window.next_conversation_id = jsonObject.conversation_id; window.next_parent_message_id = jsonObject.parent_message_id; alert("导入成功,当前会话状态已「暂时」附加到导入的存档。这将对您的下一句话生效。\r\n如果该存档的宿主已退出登录或释放该会话,则存档也会一起失效\r\n此时您可能会被提示登录过期。\r\n\r\n若要中途解除附加状态。请刷新浏览器、点击「 +New chat 」新建会话或切换到其它的会话。"); }; window.clearTempValues = function () { delete window.import_authorization; delete window.next_parent_message_id; delete window.next_conversation_id; delete window.parent_message_id_last; delete window.conversation_id_last; delete window.authorization_last; }; window.boxInit = function () { createShowPlusUIDButton(); unblockAccessDenied(); const toolboxItemDivs = document.querySelectorAll('div[class*="toolbox-item"]'); if (toolboxItemDivs.length > 0) { // console.log("存在包含 'toolbox-item' 类名的 div 元素。"); return; } window.clearAllBoxItem(); var navs = document.querySelectorAll('nav'); for (var x = 0; x < navs.length; x++) { let nav = navs[x]; let switchLabel = document.createElement("div"); let aEle = nav.querySelectorAll('a'); if (!nav.childNodes[0].hasOwnProperty('patched')) { nav.childNodes[0].addEventListener("click", handleNewChatClick); Object.defineProperty(nav.childNodes[0], 'patched', { value: true, enumerable: false }); } function handleNewChatClick(event) { event.preventDefault(); if (confirm("创建新的会话后, 使用导入功能导入的会话将失效,是否继续?")) { nav.childNodes[0].removeEventListener('click', handleNewChatClick); window.clearTempValues(); nav.childNodes[0].click(); } } switchLabel.setAttribute("class", "toolbox-item flex py-3 px-3 items-center gap-3 rounded-md hover:bg-gray-500/10 transition-colors duration-200 text-white cursor-pointer text-sm flex-shrink-0 border border-white/20"); switchLabel.innerHTML = `禁用数据监管`; nav.insertBefore(switchLabel, nav.childNodes[1]); // 在 nav 元素的第二个子元素之前插入新建的 switchLabel 元素 let importExportLabel = document.createElement("div"); importExportLabel.setAttribute("class", "toolbox-item flex py-3 px-3 items-center gap-3 rounded-md hover:bg-gray-500/10 transition-colors duration-200 text-white cursor-pointer text-sm flex-shrink-0 border border-white/20"); importExportLabel.innerHTML = ` `; // 找到具有id为“exportSession”的按钮,为按钮设置单击事件处理程序 let exportButton = importExportLabel.querySelector('#exportSession'); exportButton.onclick = function () { var textarea = document.querySelector("textarea"); let savB64 = window.exportSaveData(); if (savB64) { prompt("↓请复制您的会话存档↓", savB64); } }; // 找到具有id为“importSession”的按钮,为按钮设置单击事件处理程序 let importButton = importExportLabel.querySelector('#importSession'); importButton.onclick = function () { if (!window.location.href.includes("chat.openai.com/c/")) { alert("请在一个您已经存在的会话里使用这个功能,\r\n而不是在「 New Chat 」的空会话上下文里附加"); return } var userInput = prompt("请在此粘贴会话存档"); window.importSaveData(userInput); }; nav.insertBefore(importExportLabel, nav.childNodes[1]); // 找到具有id为“importSession”的按钮,为按钮设置单击事件处理程序 let loadAPIConfigButton = importExportLabel.querySelector('#loadAPIConfigWindow'); loadAPIConfigButton.onclick = function () { LoadAPITemplateWindow(); }; nav.insertBefore(importExportLabel, nav.childNodes[1]); } }; window.getAuthTimestamp = function (authBearer) { var authArray = authBearer.split('.'); if (authArray.length < 2) { return 0; } var decodedString = window.atob(authArray[1]); var jsonObject = JSON.parse(decodedString); if (jsonObject && jsonObject.exp) { return jsonObject.exp; } return 0; }; window.boxInit(); const oldFetch = window.fetch; window.fetch = async function (...args) { if (args[0].includes("moderations") && window.enableFakeMod) { return new Response('{}', { status: 200, statusText: "ok", }); } if (args[0].includes("signout") && window.enableFakeMod) { if (!confirm("是否要退出登录?")) { return new Response('{}', { status: 200, statusText: "ok", }); } } if (args[0].includes("/conversation/") || args[0].includes("/conversations") || args[0].includes("/chat.json")) { if (args[0].includes("/conversations") && args[1].method === "PATCH") { let bodyJson = JSON.parse(args[1].body); bodyJson.is_visible = !(confirm("警告:真的要清空您账户下所有的会话记录?") && confirm("警告:第二次确认,清空后您将无法找回之前的所有记录!是否继续?")); if (!bodyJson.is_visible) { window.clearTempValues(); } args[1].body = JSON.stringify(bodyJson); } setTimeout(window.onresize, 1000); window.clearTempValues(); } else if (args[0].includes("conversation")) { if (args[1].body && args[1].method === "POST") { const jsonObj = JSON.parse(args[1].body); const message = jsonObj?.messages?.[0]?.content?.parts?.[0] ?? ''; const regex = /^\/api (.*)/; if (regex.test(message)) { const result = message.replace(regex, '$1'); console.log("发现API调用", result); // 输出:"get-user-info" await new Promise(resolve => setTimeout(resolve, 1000)); let apiRes = await window.sendAPI(result); console.log("apires:", apiRes); if (apiRes !== '') { let msgLog = formatOutputArray([{ role: 'user', content: result }, { role: 'assistant', content: apiRes }]); jsonObj.messages[0].content.parts[0] = '以下是因网络故障丢失的记录,你看完后只允许回复我一个字:"1",用来表示目前网络畅通:\r\n\r\n```\r\n' + msgLog + '\r\n```\r\n\r\n\r\n注意:你什么也不用做,只需要回复一个字:"1",表示目前网络畅通。'; const matchedDivs = document.querySelectorAll('div[class*="min-h-"][class*="flex"][class*="items-start"][class*="gap-"][class*="whitespace-pre-wrap"]'); if (matchedDivs.length >= 2) { if (matchedDivs.length == 2) { alert("若在第一句话就使用API,则可能会观察到数据回滚。\r\n建议您刷新页面/切换会话后,再进行后续的对话。"); } matchedDivs[matchedDivs.length - 2].innerText = jsonObj.messages[0].content.parts[0]; } } else { return new Response('{}', { status: 500, statusText: "error", }); } args[1].body = JSON.stringify(jsonObj); } else { console.log(message); // 输出:"/api get-user-info" } //覆盖原始鉴权 var headers = new Headers(args[1].headers); let lastAuth = headers.get("authorization"); window.authorization_last = lastAuth; let authorization = window.import_authorization ? window.import_authorization : lastAuth; headers.set("authorization", authorization); args[1].headers = headers; //处理会话数据附加 if (window.next_conversation_id && window.next_parent_message_id) { let bodyJson = JSON.parse(args[1].body); bodyJson.conversation_id = window.next_conversation_id ? window.next_conversation_id : bodyJson.conversation_id; bodyJson.parent_message_id = window.next_parent_message_id ? window.next_parent_message_id : bodyJson.parent_message_id; args[1].body = JSON.stringify(bodyJson); delete window.next_parent_message_id; delete window.next_conversation_id; } else { let bodyJson = JSON.parse(args[1].body); window.conversation_id_last = bodyJson.conversation_id; window.parent_message_id_last = bodyJson.parent_message_id; } } } return oldFetch(...args); }; window.openaiChatCompletionsP = async function (message, api_key) { const headers = { 'Content-Type': 'application/json', 'Authorization': `Bearer ${api_key}` }; const data = { model: 'gpt-3.5-turbo', messages: message }; const response = await fetch('https://api.openai.com/v1/chat/completions', { method: 'POST', headers: headers, body: JSON.stringify(data) }); const json = await response.json(); return json; }; window.sendAPI = async function (newMsg) { // 从localStorage中读取api-template字段的值 const apiTemplateValue = localStorage.getItem('api-template'); if (!apiTemplateValue) { alert('您尚未设置API_KEY,请先打开设置窗口设置'); LoadAPITemplateWindow(); return ''; } // 尝试反序列化apiTemplateValue let apiTemplate = {}; try { apiTemplate = JSON.parse(apiTemplateValue); } catch (e) { console.error('无法解析api-template的值,忽略'); return ''; } if (!apiTemplate.apiKey || apiTemplate.apiKey === "") { console.error('用户未设置api_key,忽略'); alert('您尚未设置API_KEY,请先打开设置窗口设置'); LoadAPITemplateWindow(); return ''; } //获取历史聊天记录,限4000字节 var msgHistory = generateOutputArrayWithMaxLength('div.text-base', 99, 4000); console.info("msgHistory:", msgHistory); if (msgHistory.length >= 2) { msgHistory.splice(-2);//移除最后两个 } let msgs = mergeMessages(apiTemplate, msgHistory, newMsg); let res = await window.openaiChatCompletionsP(msgs, apiTemplate.apiKey); console.info("res:", res); if (res && res.error && res.error.message) { alert(`API返回错误信息:\r\n ${res.error.message}`); } console.info("content:", res?.choices?.[0]?.message?.[0]?.content ?? ''); return res?.choices?.[0]?.message?.content ?? ''; }; window.openaiChatCompletions = function (message, api_key) { const data = { model: 'gpt-3.5-turbo', messages: message }; const xhr = new XMLHttpRequest(); xhr.open('POST', 'https://api.openai.com/v1/chat/completions', false); xhr.setRequestHeader('Content-Type', 'application/json'); xhr.setRequestHeader('Authorization', `Bearer ${api_key}`); xhr.send(JSON.stringify(data)); const response = JSON.parse(xhr.responseText); return response; }; var resizeTimer = null; window.onresize = function () { if (resizeTimer) clearTimeout(resizeTimer); resizeTimer = setTimeout(function () { window.boxInit(); var buttons = document.getElementsByTagName('button'); for (var i = 0; i < buttons.length; i++) { var button = buttons[i]; if (button.innerHTML.indexOf('sidebar') !== -1) { button.addEventListener('click', function () { window.setTimeout(function () { window.boxInit() }, 300) }); } } const textareas = document.querySelectorAll('[class*="m-"][class*="w-full"][class*="resize-none"][class*="border-0"][class*="bg-transparent"][class*="p-"][class*="pl-"][class*="pr-"][class*="focus:ring-0"][class*="focus-visible:ring-0"][class*="dark:bg-transparent"][class*="md:pl-"]'); if (textareas.length > 0) { textareas[0].placeholder = '/api 命令 可调用GPT3.5API (注意空格)'; } else { return } }, 200); }; window.onresize(); window.InitCSS = function () { // fillTextAndSubmit("你好。"); // 确保样式表只被添加一次的标志变量 window.toolboxStyleAdded = false; // 添加样式表的函数 function addStylesheet() { // 获取页面的
元素 const head = document.head || document.getElementsByTagName('head')[0]; // 创建一个