您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Modifies the behavior of the chat interface on the OpenAI website
当前为
// ==UserScript== // @name ChatGPT Utils // @description Modifies the behavior of the chat interface on the OpenAI website // @namespace ChatGPTUtils // @version 1.6.8 // @author CriDos // @match https://chat.openai.com/* // @icon https://www.google.com/s2/favicons?sz=64&domain=chat.openai.com // @grant GM_xmlhttpRequest // @run-at document-end // @license MIT // ==/UserScript== 'use strict'; console.log(`ChatGPT Utils initializing...`); let debug = false; setInterval(() => { try { addAutoTranslate(); //addTranslateButtons(); } catch (error) { console.error(error); } try { findAndHookTextareaElement(); } catch (error) { console.error(error); } }, 100); function addAutoTranslate() { var messages = document.querySelectorAll(".markdown.prose"); for (var i = 0; i < messages.length; i++) { const msgMarkdownNode = messages[i]; const parentMsgMarkdown = msgMarkdownNode.parentElement; if (parentMsgMarkdown.isAutoTranslate) { continue; } parentMsgMarkdown.isAutoTranslate = true; setInterval(async () => { await translateNode(msgMarkdownNode); }, 500); } } function addTranslateButtons() { var messages = document.querySelectorAll(".markdown.prose"); for (var i = 0; i < messages.length; i++) { const msgMarkdownNode = messages[i]; const msgIcon = msgMarkdownNode.parentElement.parentElement.parentElement.previousElementSibling; if (!msgIcon.querySelector(".translate-button")) { var btn = document.createElement("button"); btn.textContent = "Tr"; btn.classList.add("translate-button"); btn.style.cssText = "width: 30px; height: 30px;"; msgIcon.insertBefore(btn, msgIcon.firstChild); btn.addEventListener("click", async () => { await translateNode(msgMarkdownNode); }); } } } function findAndHookTextareaElement() { const targetElement = document.querySelector("textarea"); if (targetElement === null) { return; } if (targetElement.isAddHookKeydownEvent === true) { return; } targetElement.isAddHookKeydownEvent = true; console.log(`Textarea element found. Adding keydown event listener.`); targetElement.addEventListener("keydown", async event => await handleSubmit(event, targetElement), true); } async function handleSubmit(event, targetElement) { console.log(`Keydown event detected: type - ${event.type}, key - ${event.key}`); if (event.shiftKey && event.key === "Enter") { return; } if (window.isActiveOnSubmit === true) { return; } if (event.key === "F2") { const request = targetElement.value; targetElement.value = ""; const translatedText = await translateText(request, "ru", "en"); targetElement.focus(); targetElement.value = translatedText; } else if (event.key === "Enter") { window.isActiveOnSubmit = true; event.stopImmediatePropagation(); const request = targetElement.value; targetElement.value = ""; const translatedText = await translateText(request, "ru", "en"); targetElement.focus(); targetElement.value = translatedText; const enterEvent = new KeyboardEvent("keydown", { bubbles: true, cancelable: true, key: "Enter", code: "Enter" }); targetElement.dispatchEvent(enterEvent); window.isActiveOnSubmit = false; } } async function translateNode(msgMarkdownNode) { const translateClassName = "translate-markdown"; const parentMsgMarkdown = msgMarkdownNode.parentElement; const msgMarkdownContent = msgMarkdownNode.outerHTML; if (msgMarkdownNode.storeContent == msgMarkdownContent) { return; } msgMarkdownNode.storeContent = msgMarkdownContent; var translateNode = parentMsgMarkdown.querySelector(`.${translateClassName}`); if (translateNode == null) { translateNode = msgMarkdownNode.cloneNode(true); translateNode.classList.add(translateClassName); parentMsgMarkdown.insertBefore(translateNode, parentMsgMarkdown.firstChild); } var msgMarkdownClone = msgMarkdownNode.cloneNode(true); msgMarkdownClone.classList.add(translateClassName); const msgMarkdownCloneContent = msgMarkdownClone.outerHTML; msgMarkdownClone = null; var translatedContent = await translateHTML(msgMarkdownCloneContent, "en", navigator.language) translatedContent = translatedContent.replace('< div>', '<div>') translatedContent = translatedContent.replace('< дел>', '<div>') translatedContent = translatedContent.replace('<дел>', '<div>') translatedContent = translatedContent.replace('< /div>', '</div>') translatedContent = translatedContent.replace('< /дел>', '</div>') translatedContent = translatedContent.replace('</дел>', '</div>') translatedContent = translatedContent.replace('< p>', '<p>') translatedContent = translatedContent.replace('< /p>', '</p>') translateNode.outerHTML = translatedContent + `<p>.......... конец_перевода ..........</p></div>`; } async function translateHTML(html, sLang, tLang) { const excludeTagRegex = /<(pre|code)[^>]*>([\s\S]*?)<\/(pre|code)>/g; const excludeTags = []; const excludePlaceholder = 'e0x0c'; let translateHTML = html; let excludeTagsMatch; while (excludeTagsMatch = excludeTagRegex.exec(html)) { excludeTags.push(excludeTagsMatch[0]); translateHTML = translateHTML.replace(excludeTagsMatch[0], `${excludePlaceholder}${excludeTags.length - 1}`); } if (debug) { console.log(`preTranslateHTML: ${html}`); } translateHTML = await translateText(translateHTML, sLang, tLang); for (let i = 0; i < excludeTags.length; i++) { translateHTML = translateHTML.replace(`${excludePlaceholder}${i}`, excludeTags[i]); } if (debug) { console.log(`postTranslateHTML: ${translateHTML}`); } return translateHTML; } async function translateText(text, sLang, tLang) { const url = `https://translate.googleapis.com/translate_a/single?client=gtx&format=text&sl=${sLang}&tl=${tLang}&dt=t&q=${encodeURIComponent(text)}`; try { if (debug) { console.log(`preTranslate: ${text}`); } const response = await doXHR(url); const responseText = JSON.parse(response.responseText); let postTranslate = ""; responseText[0].forEach(part => { postTranslate += part[0]; }); if (debug) { console.log(`postTranslate: ${postTranslate}`); } return postTranslate; } catch (error) { console.error(error); } } async function doXHR(url) { return new Promise((resolve, reject) => { const xhr = new XMLHttpRequest(); xhr.open("GET", url); xhr.onload = () => resolve(xhr); xhr.onerror = () => reject(xhr.statusText); xhr.send(); }); }