您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Adds a dropdown to code blocks in StackOverflow to switch the code language. Powered by GPT-3 AI.
// ==UserScript== // @name StackOverflow Code Language Switcher // @namespace https://github.com/Christopher-Hayes/stackoverflow-code-language-switcher // @homepageURL https://github.com/Christopher-Hayes/stackoverflow-code-language-switcher // @supportURL https://github.com/Christopher-Hayes/stackoverflow-code-language-switcher // @description Adds a dropdown to code blocks in StackOverflow to switch the code language. Powered by GPT-3 AI. // @match https://stackoverflow.com/questions/* // @grant GM_getValue // @grant GM_setValue // @grant GM_addValueChangeListener // @grant GM_setClipboard // @version 1.0 // @author Chris Hayes // @license GPL3 // ==/UserScript== class LangConvert { constructor() { this.key = GM_getValue("openai_key", ""); if (!this.key || this.key === "your-openai-key-here") { GM_setValue("openai_key", "your-openai-key-here"); console.error( '"openai_key" not set in violent monkey script. Please get an OpenAI key and set this config value to use the OpenAI API.' ); } this.supportedLanguages = GM_getValue("supported_languages", [ "javascript", "typescript", "python", "java", "bash", "css", "scss", "html", "c", "c++", "c#", "rust", "go", "kotlin", "php", "ruby", "liquid", "swift", "react", "vue", "svelte", "angular", ]); GM_setValue("supported_languages", this.supportedLanguages); this.previousConversions = {}; } setKey(newKey) { this.key = newKey; } setSupportedLanguages(newLanguages) { this.supportedLanguages = newLanguages; } async makeGPT3Request(code, oldLang, newLang) { const url = "https://api.openai.com/v1/completions"; const headers = { "Content-Type": "application/json", Authorization: `Bearer ${this.key}`, }; // Uses Davinci 003 text-completion // code-completion and edit were slower and didn't work as well const body = { model: "text-davinci-003", prompt: `# Convert this${oldLang ? " from " + oldLang : ""} to ${newLang} # ${oldLang ? oldLang : "Old"} version ${code} # ${newLang} version`, max_tokens: 1000, }; const response = await fetch(url, { method: "POST", headers, body: JSON.stringify(body), }); console.log( "[StackOverflow Code Language Switcher] Full OpenAI response:", response ); const data = await response.json(); console.log("[StackOverflow Code Language Switcher] Response data:", data); let newCode = data.choices[0].text; // if the first line is an empty newline, remove it if (newCode.startsWith("\n")) { newCode = newCode.slice(1); } // if the last line is an empty newline, remove it if (newCode.endsWith("\n")) { newCode = newCode.slice(0, -1); } return newCode; } getCodeElements() { return Array.from(document.querySelectorAll(".s-prose pre code")); } setup() { const codeElements = this.getCodeElements(); for (const codeElem of codeElements) { const pre = codeElem.parentElement; const div = document.createElement("div"); div.classList.add("lang-convert"); div.style = ` height: 0; float: right; margin-bottom: -20px; display: block; position: relative; top: 10px; right: 8px; `; // Show supported languages in dropdown const select = document.createElement("select"); select.innerHTML = `${this.supportedLanguages .slice(0, 20) .map((lang) => `<option value="${lang}">${lang}</option>`) .join("")}`; select.style = ` background: #181818; color: #999; outline: none; border: 0; padding: .5em 0.7em; border-radius: 7px; font-size: 12px; `; // Change style of select element when hovered over select.addEventListener("mouseenter", () => { select.style.background = "black"; select.style.color = "white"; }); select.addEventListener("mouseleave", () => { select.style.background = "#181818"; select.style.color = "#999"; }); div.appendChild(select); // Add div before pre element pre.parentElement.insertBefore(div, pre); // Set default value of dropdown to the language of the code element const lang = codeElem.className.split("-")[1]; select.value = lang; this.previousConversions[lang] = codeElem.textContent; select.addEventListener("change", async (e) => { const oldLang = codeElem.className.split("-")[1]; const newLang = e.target.value; if (oldLang === newLang) return; // Show "converting" overlay message const overlay = document.createElement("div"); overlay.style = ` position: absolute; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0, 0, 0, 0.5); display: flex; justify-content: center; align-items: center; color: white; font-size: 20px; font-weight: bold; `; overlay.innerHTML = "Converting..."; pre.style.position = "relative"; pre.appendChild(overlay); const oldCode = codeElem.textContent; let newCode = ""; if (this.previousConversions[newLang]) { newCode = this.previousConversions[newLang]; } else { newCode = await this.makeGPT3Request(oldCode, oldLang, newLang); this.previousConversions[newLang] = newCode; } GM_setClipboard(newCode); codeElem.classList.remove(`language-${oldLang}`); codeElem.classList.add(`language-${newLang}`); codeElem.textContent = newCode; // add a script to the page that will highlight the new code using window.hljs // This must be injected to have access to the highlight.js object already loaded into StackOverflow const codeID = Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15); codeElem.id = codeID; const script = document.createElement("script"); script.innerHTML = `if (window.hljs) window.hljs.highlightElement(document.getElementById("${codeID}"));`; document.body.appendChild(script); // Remove "converting" overlay message pre.removeChild(overlay); pre.style.position = "static"; }); } } } let langConvert = new LangConvert(); langConvert.setup(); GM_addValueChangeListener("openai_key", (name, oldValue, newValue) => { langConvert.setKey(newValue); }); GM_addValueChangeListener("supported_languages", (name, oldValue, newValue) => { langConvert.setSupportedLanguages(newValue); });