ChatGPT 页面翻译按钮

🍓 让 ChatGPT 一键翻译您正在阅读的网页

当前为 2023-04-17 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name chatgpt-page-translate-button
  3. // @description 🍓 let ChatGPT translate the web page you are reading in one click
  4. // @author mefengl
  5. // @version 0.1.4
  6. // @namespace https://github.com/mefengl
  7. // @require https://cdn.jsdelivr.net/npm/moz-readability@0.2.1/Readability.min.js
  8. // @icon https://www.google.com/s2/favicons?sz=64&domain=openai.com
  9. // @license MIT
  10. // @match *://*/*
  11. // @grant GM_setValue
  12. // @grant GM_addValueChangeListener
  13.  
  14. // @name:en ChatGPT Page Translate Button
  15. // @description:en 🍓 let ChatGPT translate the web page you are reading in one click
  16. // @name:zh-CN ChatGPT 页面翻译按钮
  17. // @description:zh-CN 🍓 让 ChatGPT 一键翻译您正在阅读的网页
  18. // @name:es Botón de traducción de página de ChatGPT
  19. // @description:es 🍓 permite que ChatGPT traduzca la página web que estás leyendo con un solo clic
  20. // @name:hi ChatGPT पृष्ठ अनुवाद बटन
  21. // @description:hi 🍓 ChatGPT को वेबपेज जो आप पढ़ रहे हैं को एक क्लिक में अनुवाद करने दें
  22. // @name:ar زر ترجمة الصفحة لـ ChatGPT
  23. // @description:ar 🍓 دع ChatGPT يترجم صفحة الويب التي تقرأها بنقرة واحدة
  24. // @name:pt Botão de tradução de página do ChatGPT
  25. // @description:pt 🍓 permita que o ChatGPT traduza a página da web que você está lendo com um clique
  26. // @name:ru Кнопка перевода страницы ChatGPT
  27. // @description:ru 🍓 позволяет ChatGPT переводить веб-страницу, которую вы читаете, одним щелчком мыши
  28. // @name:ja ChatGPTページ翻訳ボタン
  29. // @description:ja 🍓 ChatGPTで読んでいるWebページをワンクリックで翻訳
  30. // @name:de ChatGPT-Seitenübersetzungs-Button
  31. // @description:de 🍓 Lassen Sie ChatGPT die Webseite, die Sie gerade lesen, mit einem Klick übersetzen
  32. // @name:fr Bouton de traduction de page ChatGPT
  33. // @description:fr 🍓 laissez ChatGPT traduire la page Web que vous lisez en un seul clic
  34. // ==/UserScript==
  35. (() => {
  36. var __async = (__this, __arguments, generator) => {
  37. return new Promise((resolve, reject) => {
  38. var fulfilled = (value) => {
  39. try {
  40. step(generator.next(value));
  41. } catch (e) {
  42. reject(e);
  43. }
  44. };
  45. var rejected = (value) => {
  46. try {
  47. step(generator.throw(value));
  48. } catch (e) {
  49. reject(e);
  50. }
  51. };
  52. var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
  53. step((generator = generator.apply(__this, __arguments)).next());
  54. });
  55. };
  56.  
  57. // ../../packages/chatkit/dist/index.mjs
  58. function getTextarea() {
  59. const form = document.querySelector("form");
  60. if (!form)
  61. return;
  62. const textareas = form.querySelectorAll("textarea");
  63. const result = textareas[0];
  64. return result;
  65. }
  66. function getSubmitButton() {
  67. const textarea = getTextarea();
  68. if (!textarea)
  69. return;
  70. return textarea.nextElementSibling;
  71. }
  72. function getRegenerateButton() {
  73. const form = document.querySelector("form");
  74. if (!form)
  75. return;
  76. const buttons = form.querySelectorAll("button");
  77. const result = Array.from(buttons).find((button) => {
  78. var _a;
  79. return (_a = button.textContent) == null ? void 0 : _a.trim().toLowerCase().includes("regenerate");
  80. });
  81. return result;
  82. }
  83. function getStopGeneratingButton() {
  84. const form = document.querySelector("form");
  85. if (!form)
  86. return;
  87. const buttons = form.querySelectorAll("button");
  88. const result = Array.from(buttons).find((button) => {
  89. var _a;
  90. return (_a = button.textContent) == null ? void 0 : _a.trim().toLowerCase().includes("stop generating");
  91. });
  92. return result;
  93. }
  94. function getLastResponseElement() {
  95. const responseElements = document.querySelectorAll(".group.w-full");
  96. return responseElements[responseElements.length - 1];
  97. }
  98. function getLastResponse() {
  99. const lastResponseElement = getLastResponseElement();
  100. if (!lastResponseElement)
  101. return;
  102. const lastResponse = lastResponseElement.textContent;
  103. return lastResponse;
  104. }
  105. function getTextareaValue() {
  106. var _a;
  107. return ((_a = getTextarea()) == null ? void 0 : _a.value) || "";
  108. }
  109. function setTextarea(message) {
  110. const textarea = getTextarea();
  111. if (!textarea)
  112. return;
  113. textarea.value = message;
  114. textarea.dispatchEvent(new Event("input"));
  115. }
  116. function send(message) {
  117. setTextarea(message);
  118. const textarea = getTextarea();
  119. if (!textarea)
  120. return;
  121. textarea.dispatchEvent(new KeyboardEvent("keydown", { key: "Enter", bubbles: true }));
  122. }
  123. function regenerate() {
  124. const regenerateButton = getRegenerateButton();
  125. if (!regenerateButton)
  126. return;
  127. regenerateButton.click();
  128. }
  129. function onSend(callback) {
  130. const textarea = getTextarea();
  131. if (!textarea)
  132. return;
  133. textarea.addEventListener("keydown", function(event) {
  134. if (event.key === "Enter" && !event.shiftKey) {
  135. callback();
  136. }
  137. });
  138. const sendButton = getSubmitButton();
  139. if (!sendButton)
  140. return;
  141. sendButton.addEventListener("mousedown", callback);
  142. }
  143. function isGenerating() {
  144. var _a, _b;
  145. return ((_b = (_a = getSubmitButton()) == null ? void 0 : _a.firstElementChild) == null ? void 0 : _b.childElementCount) === 3;
  146. }
  147. function waitForIdle() {
  148. return new Promise((resolve) => {
  149. const interval = setInterval(() => {
  150. if (!isGenerating()) {
  151. clearInterval(interval);
  152. resolve();
  153. }
  154. }, 1e3);
  155. });
  156. }
  157. function setListener(key = "prompt_texts") {
  158. let last_trigger_time = +/* @__PURE__ */ new Date();
  159. if (location.href.includes("chat.openai")) {
  160. GM_addValueChangeListener(key, (name, old_value, new_value) => __async(this, null, function* () {
  161. if (+/* @__PURE__ */ new Date() - last_trigger_time < 500) {
  162. return;
  163. }
  164. last_trigger_time = +/* @__PURE__ */ new Date();
  165. setTimeout(() => __async(this, null, function* () {
  166. const prompt_texts = new_value;
  167. if (prompt_texts.length > 0) {
  168. let firstTime = true;
  169. while (prompt_texts.length > 0) {
  170. if (!firstTime) {
  171. yield new Promise((resolve) => setTimeout(resolve, 2e3));
  172. }
  173. if (!firstTime && chatgpt.isGenerating()) {
  174. continue;
  175. }
  176. firstTime = false;
  177. const prompt_text = prompt_texts.shift() || "";
  178. chatgpt.send(prompt_text);
  179. }
  180. }
  181. }), 0);
  182. GM_setValue(key, []);
  183. }));
  184. }
  185. }
  186. var chatgpt = {
  187. getTextarea,
  188. getSubmitButton,
  189. getRegenerateButton,
  190. getStopGeneratingButton,
  191. getLastResponseElement,
  192. getLastResponse,
  193. getTextareaValue,
  194. setTextarea,
  195. send,
  196. regenerate,
  197. onSend,
  198. isGenerating,
  199. waitForIdle,
  200. setListener
  201. };
  202. var chatgpt_default = chatgpt;
  203.  
  204. // src/createButton/index.ts
  205. function createButton(callback) {
  206. if (window.location.href.includes("chat.openai")) {
  207. return;
  208. }
  209. const hideRight = document.title.match(/[\u4e00-\u9fa5]/) ? "-130px" : "-120px";
  210. const button = document.createElement("button");
  211. button.innerHTML = "\u7F51\u9875\u7FFB\u8BD1";
  212. button.style.position = "fixed";
  213. button.style.width = "140px";
  214. button.style.top = "120px";
  215. button.style.right = hideRight;
  216. button.style.zIndex = "999999";
  217. button.style.backgroundColor = "#4285f4";
  218. button.style.color = "#fff";
  219. button.style.opacity = "0.8";
  220. button.style.border = "none";
  221. button.style.borderRadius = "4px";
  222. button.style.padding = "10px 16px";
  223. button.style.fontSize = "18px";
  224. button.style.cursor = "pointer";
  225. button.style.transition = "right 0.3s";
  226. document.body.appendChild(button);
  227. button.addEventListener("mouseenter", () => {
  228. button.style.right = "-10px";
  229. });
  230. button.addEventListener("mouseleave", () => {
  231. button.style.right = hideRight;
  232. });
  233. document.addEventListener("fullscreenchange", () => {
  234. if (document.fullscreenElement) {
  235. button.style.display = "none";
  236. } else {
  237. button.style.display = "block";
  238. }
  239. });
  240. button.addEventListener("click", callback);
  241. }
  242. var createButton_default = createButton;
  243.  
  244. // src/SimpleArticleSegmentation/index.ts
  245. var MIN_PARAGRAPH_LENGTH = 1600;
  246. var MAX_PARAGRAPH_LENGTH = 1800;
  247. var SimpleArticleSegmentation = class {
  248. constructor(text) {
  249. this.text = text;
  250. }
  251. segment() {
  252. const paragraphs = [];
  253. const sentences = this.text.split(new RegExp("(?<=[.!?])\\s+"));
  254. let paragraph = "";
  255. for (const sentence of sentences) {
  256. if (paragraph.length + sentence.length + 1 <= MAX_PARAGRAPH_LENGTH) {
  257. paragraph += (paragraph.length > 0 ? " " : "") + sentence;
  258. } else {
  259. if (paragraph.length >= MIN_PARAGRAPH_LENGTH) {
  260. paragraphs.push(paragraph);
  261. paragraph = sentence;
  262. } else {
  263. paragraph += " " + sentence;
  264. }
  265. }
  266. }
  267. if (paragraph.length >= MIN_PARAGRAPH_LENGTH) {
  268. paragraphs.push(paragraph);
  269. }
  270. return paragraphs;
  271. }
  272. };
  273. var SimpleArticleSegmentation_default = SimpleArticleSegmentation;
  274.  
  275. // src/getParagraphs/index.ts
  276. function getParagraphs() {
  277. try {
  278. let docClone = document.cloneNode(true);
  279. let article = new Readability(docClone).parse();
  280. if (article && article.textContent) {
  281. const segmenter = new SimpleArticleSegmentation_default(article.textContent);
  282. const paragraphs = segmenter.segment();
  283. return paragraphs;
  284. } else {
  285. console.warn("Readability.js could not extract any text content from this page.");
  286. return [];
  287. }
  288. } catch (error) {
  289. console.error("An error occurred while using Readability.js:", error);
  290. return [];
  291. }
  292. }
  293. var getParagraphs_default = getParagraphs;
  294.  
  295. // src/index.ts
  296. function initialize() {
  297. return __async(this, null, function* () {
  298. yield new Promise((resolve) => window.addEventListener("load", resolve));
  299. yield new Promise((resolve) => setTimeout(resolve, 1e3));
  300. });
  301. }
  302. function main() {
  303. return __async(this, null, function* () {
  304. yield initialize();
  305. const key = "prompt_texts";
  306. chatgpt_default.setListener(key);
  307. const translateWeb = () => __async(this, null, function* () {
  308. const paragraphs = getParagraphs_default();
  309. const prompt_texts = paragraphs.map((paragraph) => {
  310. return `${paragraph}
  311. translate above paragraph to Chinese with compact and intuitive format:`;
  312. });
  313. GM_setValue(key, prompt_texts);
  314. });
  315. createButton_default(translateWeb);
  316. });
  317. }
  318. (function() {
  319. main();
  320. })();
  321. })();