chatgpt-page-translate-button

🍓 let ChatGPT translate the web page you are reading in one click

目前为 2023-04-15 提交的版本,查看 最新版本

  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.2
  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. // ==/UserScript==
  14. (() => {
  15. var __async = (__this, __arguments, generator) => {
  16. return new Promise((resolve, reject) => {
  17. var fulfilled = (value) => {
  18. try {
  19. step(generator.next(value));
  20. } catch (e) {
  21. reject(e);
  22. }
  23. };
  24. var rejected = (value) => {
  25. try {
  26. step(generator.throw(value));
  27. } catch (e) {
  28. reject(e);
  29. }
  30. };
  31. var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
  32. step((generator = generator.apply(__this, __arguments)).next());
  33. });
  34. };
  35.  
  36. // ../../packages/chatkit/dist/index.mjs
  37. function getTextarea() {
  38. const form = document.querySelector("form");
  39. if (!form)
  40. return;
  41. const textareas = form.querySelectorAll("textarea");
  42. const result = textareas[0];
  43. return result;
  44. }
  45. function getSubmitButton() {
  46. const textarea = getTextarea();
  47. if (!textarea)
  48. return;
  49. return textarea.nextElementSibling;
  50. }
  51. function getRegenerateButton() {
  52. const form = document.querySelector("form");
  53. if (!form)
  54. return;
  55. const buttons = form.querySelectorAll("button");
  56. const result = Array.from(buttons).find((button) => {
  57. var _a;
  58. return (_a = button.textContent) == null ? void 0 : _a.trim().toLowerCase().includes("regenerate");
  59. });
  60. return result;
  61. }
  62. function getStopGeneratingButton() {
  63. const form = document.querySelector("form");
  64. if (!form)
  65. return;
  66. const buttons = form.querySelectorAll("button");
  67. const result = Array.from(buttons).find((button) => {
  68. var _a;
  69. return (_a = button.textContent) == null ? void 0 : _a.trim().toLowerCase().includes("stop generating");
  70. });
  71. return result;
  72. }
  73. function getLastResponseElement() {
  74. const responseElements = document.querySelectorAll(".group.w-full");
  75. return responseElements[responseElements.length - 1];
  76. }
  77. function getLastResponse() {
  78. const lastResponseElement = getLastResponseElement();
  79. if (!lastResponseElement)
  80. return;
  81. const lastResponse = lastResponseElement.textContent;
  82. return lastResponse;
  83. }
  84. function getTextareaValue() {
  85. var _a;
  86. return ((_a = getTextarea()) == null ? void 0 : _a.value) || "";
  87. }
  88. function setTextarea(message) {
  89. const textarea = getTextarea();
  90. if (!textarea)
  91. return;
  92. textarea.value = message;
  93. textarea.dispatchEvent(new Event("input"));
  94. }
  95. function send(message) {
  96. setTextarea(message);
  97. const textarea = getTextarea();
  98. if (!textarea)
  99. return;
  100. textarea.dispatchEvent(new KeyboardEvent("keydown", { key: "Enter", bubbles: true }));
  101. }
  102. function regenerate() {
  103. const regenerateButton = getRegenerateButton();
  104. if (!regenerateButton)
  105. return;
  106. regenerateButton.click();
  107. }
  108. function onSend(callback) {
  109. const textarea = getTextarea();
  110. if (!textarea)
  111. return;
  112. textarea.addEventListener("keydown", function(event) {
  113. if (event.key === "Enter" && !event.shiftKey) {
  114. callback();
  115. }
  116. });
  117. const sendButton = getSubmitButton();
  118. if (!sendButton)
  119. return;
  120. sendButton.addEventListener("mousedown", callback);
  121. }
  122. function isGenerating() {
  123. var _a, _b;
  124. return ((_b = (_a = getSubmitButton()) == null ? void 0 : _a.firstElementChild) == null ? void 0 : _b.childElementCount) === 3;
  125. }
  126. function waitForIdle() {
  127. return new Promise((resolve) => {
  128. const interval = setInterval(() => {
  129. if (!isGenerating()) {
  130. clearInterval(interval);
  131. resolve();
  132. }
  133. }, 1e3);
  134. });
  135. }
  136. function setListener(key = "prompt_texts") {
  137. let last_trigger_time = +/* @__PURE__ */ new Date();
  138. if (location.href.includes("chat.openai")) {
  139. GM_addValueChangeListener(key, (name, old_value, new_value) => __async(this, null, function* () {
  140. if (+/* @__PURE__ */ new Date() - last_trigger_time < 500) {
  141. return;
  142. }
  143. last_trigger_time = +/* @__PURE__ */ new Date();
  144. setTimeout(() => __async(this, null, function* () {
  145. const prompt_texts = new_value;
  146. if (prompt_texts.length > 0) {
  147. let firstTime = true;
  148. while (prompt_texts.length > 0) {
  149. if (!firstTime) {
  150. yield new Promise((resolve) => setTimeout(resolve, 2e3));
  151. }
  152. if (!firstTime && chatgpt.isGenerating()) {
  153. continue;
  154. }
  155. firstTime = false;
  156. const prompt_text = prompt_texts.shift() || "";
  157. chatgpt.send(prompt_text);
  158. }
  159. }
  160. }), 0);
  161. GM_setValue(key, []);
  162. }));
  163. }
  164. }
  165. var chatgpt = {
  166. getTextarea,
  167. getSubmitButton,
  168. getRegenerateButton,
  169. getStopGeneratingButton,
  170. getLastResponseElement,
  171. getLastResponse,
  172. getTextareaValue,
  173. setTextarea,
  174. send,
  175. regenerate,
  176. onSend,
  177. isGenerating,
  178. waitForIdle,
  179. setListener
  180. };
  181. var chatgpt_default = chatgpt;
  182.  
  183. // src/createButton/index.ts
  184. function createButton(callback) {
  185. if (window.location.href.includes("chat.openai")) {
  186. return;
  187. }
  188. const hideRight = document.title.match(/[\u4e00-\u9fa5]/) ? "-130px" : "-120px";
  189. const button = document.createElement("button");
  190. button.innerHTML = "\u7F51\u9875\u7FFB\u8BD1";
  191. button.style.position = "fixed";
  192. button.style.width = "140px";
  193. button.style.top = "120px";
  194. button.style.right = hideRight;
  195. button.style.zIndex = "999999";
  196. button.style.backgroundColor = "#4285f4";
  197. button.style.color = "#fff";
  198. button.style.opacity = "0.8";
  199. button.style.border = "none";
  200. button.style.borderRadius = "4px";
  201. button.style.padding = "10px 16px";
  202. button.style.fontSize = "18px";
  203. button.style.cursor = "pointer";
  204. button.style.transition = "right 0.3s";
  205. document.body.appendChild(button);
  206. button.addEventListener("mouseenter", () => {
  207. button.style.right = "-10px";
  208. });
  209. button.addEventListener("mouseleave", () => {
  210. button.style.right = hideRight;
  211. });
  212. document.addEventListener("fullscreenchange", () => {
  213. if (document.fullscreenElement) {
  214. button.style.display = "none";
  215. } else {
  216. button.style.display = "block";
  217. }
  218. });
  219. button.addEventListener("click", callback);
  220. }
  221. var createButton_default = createButton;
  222.  
  223. // src/SimpleArticleSegmentation/index.ts
  224. var MIN_PARAGRAPH_LENGTH = 1600;
  225. var MAX_PARAGRAPH_LENGTH = 1800;
  226. var SimpleArticleSegmentation = class {
  227. constructor(text) {
  228. this.text = text;
  229. }
  230. segment() {
  231. const paragraphs = [];
  232. const sentences = this.text.split(new RegExp("(?<=[.!?])\\s+"));
  233. let paragraph = "";
  234. for (const sentence of sentences) {
  235. if (paragraph.length + sentence.length + 1 <= MAX_PARAGRAPH_LENGTH) {
  236. paragraph += (paragraph.length > 0 ? " " : "") + sentence;
  237. } else {
  238. if (paragraph.length >= MIN_PARAGRAPH_LENGTH) {
  239. paragraphs.push(paragraph);
  240. paragraph = sentence;
  241. } else {
  242. paragraph += " " + sentence;
  243. }
  244. }
  245. }
  246. if (paragraph.length >= MIN_PARAGRAPH_LENGTH) {
  247. paragraphs.push(paragraph);
  248. }
  249. return paragraphs;
  250. }
  251. };
  252. var SimpleArticleSegmentation_default = SimpleArticleSegmentation;
  253.  
  254. // src/getParagraphs/index.ts
  255. function getParagraphs() {
  256. try {
  257. let docClone = document.cloneNode(true);
  258. let article = new Readability(docClone).parse();
  259. if (article && article.textContent) {
  260. const segmenter = new SimpleArticleSegmentation_default(article.textContent);
  261. const paragraphs = segmenter.segment();
  262. return paragraphs;
  263. } else {
  264. console.warn("Readability.js could not extract any text content from this page.");
  265. return [];
  266. }
  267. } catch (error) {
  268. console.error("An error occurred while using Readability.js:", error);
  269. return [];
  270. }
  271. }
  272. var getParagraphs_default = getParagraphs;
  273.  
  274. // src/index.ts
  275. function initialize() {
  276. return __async(this, null, function* () {
  277. yield new Promise((resolve) => window.addEventListener("load", resolve));
  278. yield new Promise((resolve) => setTimeout(resolve, 1e3));
  279. });
  280. }
  281. function main() {
  282. return __async(this, null, function* () {
  283. yield initialize();
  284. const key = "prompt_texts";
  285. chatgpt_default.setListener(key);
  286. const translateWeb = () => __async(this, null, function* () {
  287. const paragraphs = getParagraphs_default();
  288. const prompt_texts = paragraphs.map((paragraph) => {
  289. return `${paragraph}
  290. translate above paragraph to Chinese:`;
  291. });
  292. GM_setValue(key, prompt_texts);
  293. });
  294. createButton_default(translateWeb);
  295. });
  296. }
  297. (function() {
  298. main();
  299. })();
  300. })();