chat-octopus

let octopus send message for you

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

  1. // ==UserScript==
  2. // @name chat-octopus
  3. // @namespace https://github.com/mefengl
  4. // @version 0.2.7
  5. // @description let octopus send message for you
  6. // @icon https://www.google.com/s2/favicons?sz=64&domain=openai.com
  7. // @author mefengl
  8. // @match https://chat.openai.com/*
  9. // @match https://bard.google.com/*
  10. // @match https://www.bing.com/search*q=Bing+AI*
  11. // @require https://cdn.staticfile.org/jquery/3.6.1/jquery.min.js
  12. // @grant GM_openInTab
  13. // @grant GM_registerMenuCommand
  14. // @grant GM_unregisterMenuCommand
  15. // @grant GM_getValue
  16. // @grant GM_setValue
  17. // @grant GM_addValueChangeListener
  18. // @license MIT
  19. // ==/UserScript==
  20.  
  21. (function () {
  22. 'use strict';
  23.  
  24. const default_menu_all = {
  25. };
  26. const menu_all = GM_getValue("menu_all", default_menu_all);
  27. // 菜单更新的逻辑
  28. const menus = [
  29. { checker: () => location.href.includes("chat.openai"), name: "openai", value: true },
  30. { checker: () => location.href.includes("bard.google"), name: "bard", value: true },
  31. { checker: () => location.href.includes("Bing+AI"), name: "bing", value: true },
  32. ];
  33.  
  34. menus.forEach(menu => {
  35. $(() => menu.checker() && GM_setValue(menu.name, true));
  36. if (GM_getValue(menu.name) == true) {
  37. default_menu_all[menu.name] = menu.value;
  38. }
  39. });
  40.  
  41. // 检查是否有新增菜单
  42. for (let name in default_menu_all) {
  43. if (!(name in menu_all)) {
  44. menu_all[name] = default_menu_all[name];
  45. }
  46. }
  47. const menu_id = GM_getValue("menu_id", {});
  48.  
  49. function registerMenuCommand(name, value) {
  50. const menuText = ` ${name}:${value ? '✅' : '❌'}`;
  51. const commandCallback = () => {
  52. menu_all[name] = !menu_all[name];
  53. GM_setValue('menu_all', menu_all);
  54. update_menu();
  55. location.reload();
  56. };
  57. return GM_registerMenuCommand(menuText, commandCallback);
  58. }
  59. function update_menu() {
  60. for (let name in menu_all) {
  61. const value = menu_all[name];
  62. if (menu_id[name]) {
  63. GM_unregisterMenuCommand(menu_id[name]);
  64. }
  65. menu_id[name] = registerMenuCommand(name, value);
  66. }
  67. GM_setValue('menu_id', menu_id);
  68. }
  69. update_menu();
  70.  
  71. /* ************************************************************************* */
  72. const chatgpt = {
  73. getSubmitButton: function () {
  74. const form = document.querySelector('form');
  75. if (!form) return;
  76. const buttons = form.querySelectorAll('button');
  77. const result = buttons[buttons.length - 1];
  78. return result;
  79. },
  80. getTextarea: function () {
  81. const form = document.querySelector('form');
  82. if (!form) return;
  83. const textareas = form.querySelectorAll('textarea');
  84. const result = textareas[0];
  85. return result;
  86. },
  87. getRegenerateButton: function () {
  88. const form = document.querySelector('form');
  89. if (!form) return;
  90. const buttons = form.querySelectorAll('button');
  91. for (let i = 0; i < buttons.length; i++) {
  92. const buttonText = buttons[i]?.textContent?.trim().toLowerCase();
  93. if (buttonText?.includes('regenerate')) {
  94. return buttons[i];
  95. }
  96. }
  97. },
  98. getStopGeneratingButton: function () {
  99. const form = document.querySelector('form');
  100. if (!form) return;
  101. const buttons = form.querySelectorAll('button');
  102. if (buttons.length === 0) return;
  103. for (let i = 0; i < buttons.length; i++) {
  104. const buttonText = buttons[i]?.textContent?.trim().toLowerCase();
  105. if (buttonText?.includes('stop')) {
  106. return buttons[i];
  107. }
  108. }
  109. },
  110. send: function (text) {
  111. const textarea = this.getTextarea();
  112. if (!textarea) return;
  113. textarea.value = text;
  114. textarea.dispatchEvent(new Event('input', { bubbles: true }));
  115. textarea.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter', bubbles: true }));
  116. },
  117. onSend: function (callback) {
  118. const textarea = this.getTextarea();
  119. if (!textarea) return;
  120. textarea.addEventListener("keydown", function (event) {
  121. if (event.key === "Enter" && !event.shiftKey) {
  122. callback();
  123. }
  124. });
  125. const sendButton = this.getSubmitButton();
  126. if (!sendButton) return;
  127. sendButton.addEventListener('mousedown', callback);
  128. },
  129. };
  130. // ChatGPT send prompt to other ai
  131. let chatgpt_last_prompt = '';
  132. $(() => {
  133. if (menu_all.openai && location.href.includes("chat.openai")) {
  134. chatgpt.onSend(() => {
  135. const textarea = chatgpt.getTextarea();
  136. const prompt = textarea.value;
  137. chatgpt_last_prompt = prompt;
  138. GM_setValue('bard_prompt_texts', [prompt]);
  139. GM_setValue('bing_prompt_texts', [prompt]);
  140. });
  141. }
  142. });
  143. // ChatGPT response to prompt comes from other ai
  144. let last_trigger_time = +new Date();
  145. $(() => {
  146. if (location.href.includes("chat.openai")) {
  147. console.log("chatgpt add value change listener");
  148. GM_addValueChangeListener("chatgpt_prompt_texts", (name, old_value, new_value) => {
  149. console.log("prompt_texts changed in chatgpt");
  150. console.log(new_value);
  151. if (+new Date() - last_trigger_time < 500) {
  152. return;
  153. }
  154. last_trigger_time = + new Date();
  155. setTimeout(async () => {
  156. const prompt_texts = new_value;
  157. if (prompt_texts.length > 0) {
  158. // get prompt_texts from local
  159. let firstTime = true;
  160. while (prompt_texts.length > 0) {
  161. if (!firstTime) { await new Promise(resolve => setTimeout(resolve, 2000)); }
  162. if (!firstTime && chatgpt.getRegenerateButton() == undefined) { continue; }
  163. firstTime = false;
  164. const prompt_text = prompt_texts.shift();
  165. if (prompt_text === chatgpt_last_prompt) { continue; }
  166. console.log("chatgpt send prompt_text", prompt_text);
  167. chatgpt.send(prompt_text);
  168. }
  169. }
  170. }, 0);
  171. GM_setValue("chatgpt_prompt_texts", []);
  172. });
  173. }
  174. });
  175.  
  176. /* ************************************************************************* */
  177. const bard = {
  178. getSubmitButton: function () {
  179. return document.querySelector('button[aria-label="Send message"]');
  180. },
  181. getInputArea: function () {
  182. return document.querySelector(".input-area");
  183. },
  184. getTextarea: function () {
  185. const inputArea = this.getInputArea();
  186. return inputArea.querySelector('textarea');
  187. },
  188. getRegenerateButton: function () {
  189. return document.querySelector('button[aria-label="Retry"]');
  190. },
  191. getLastPrompt: function () {
  192. const promptElements = document.querySelectorAll('.query-text');
  193. const lastPrompt = promptElements[promptElements.length - 1];
  194. return lastPrompt;
  195. },
  196. getLatestPromptText: function () {
  197. const lastPrompt = this.getLastPrompt();
  198. if (!lastPrompt) return "";
  199. const lastPromptText = lastPrompt.textContent;
  200. return lastPromptText;
  201. },
  202. send: function (text) {
  203. const textarea = this.getTextarea();
  204. textarea.value = text;
  205. textarea.dispatchEvent(new Event('input'));
  206. const submitButton = this.getSubmitButton();
  207. submitButton.click();
  208. },
  209. onSend: function (callback) {
  210. const textarea = this.getTextarea();
  211. if (!textarea) return;
  212. textarea.addEventListener("keydown", function (event) {
  213. if (event.key === "Enter" && !event.shiftKey) {
  214. callback();
  215. }
  216. });
  217. const sendButton = this.getSubmitButton();
  218. if (!sendButton) return;
  219. sendButton.addEventListener('mousedown', callback);
  220. },
  221. };
  222. // Bard send prompt to other ai
  223. let bard_last_prompt = "";
  224. $(async () => {
  225. if (menu_all.bard && location.href.includes("bard.google")) {
  226. while (!bard.getSubmitButton()) { await new Promise(resolve => setTimeout(resolve, 500)); }
  227. bard.onSend(() => {
  228. console.log("bard send");
  229. const textarea = bard.getTextarea();
  230. let prompt = textarea.value;
  231. if (!prompt) {
  232. prompt = bard.getLatestPromptText();
  233. }
  234. console.log(prompt);
  235. bard_last_prompt = prompt;
  236. GM_setValue('chatgpt_prompt_texts', [prompt]);
  237. GM_setValue('bing_prompt_texts', [prompt]);
  238. });
  239. }
  240. });
  241. // Bard response to prompt_texts
  242. let lastTriggerTime = +new Date();
  243. if (location.href.includes("bard.google")) {
  244. GM_addValueChangeListener("bard_prompt_texts", (name, old_value, new_value) => {
  245. if (+new Date() - lastTriggerTime < 500) {
  246. return;
  247. }
  248. lastTriggerTime = + new Date();
  249. setTimeout(async () => {
  250. const promptTexts = new_value;
  251. if (promptTexts.length > 0) {
  252. // get promptTexts from local
  253. let firstTime = true;
  254. while (promptTexts.length > 0) {
  255. if (!firstTime) { await new Promise(resolve => setTimeout(resolve, 2000)); }
  256. if (!firstTime && bard.getRegenerateButton() == undefined) { continue; }
  257. firstTime = false;
  258. const promptText = promptTexts.shift();
  259. if (promptText === bard_last_prompt) { continue; }
  260. bard.send(promptText);
  261. }
  262. }
  263. }, 0);
  264. GM_setValue("bard_prompt_texts", []);
  265. });
  266. }
  267. /* ************************************************************************* */
  268. const bing = {
  269. getActionBar: function () {
  270. return document.querySelector("cib-serp")?.shadowRoot?.querySelector("cib-action-bar")?.shadowRoot;
  271. },
  272. getSubmitButton: function () {
  273. const actionBar = this.getActionBar();
  274. if (!actionBar) { return null; }
  275. return actionBar.querySelector('button[aria-label="Submit"]');
  276. },
  277. getTextarea: function () {
  278. const actionBar = this.getActionBar();
  279. if (!actionBar) { return null; }
  280. return actionBar.querySelector('textarea');
  281. },
  282. getStopGeneratingButton: function () {
  283. const actionBar = this.getActionBar();
  284. if (!actionBar) { return null; }
  285. const stopGeneratingButton = actionBar.querySelector('cib-typing-indicator')?.shadowRoot?.querySelector('button[aria-label="Stop Responding"]');
  286. if (!stopGeneratingButton) { return null; }
  287. if (stopGeneratingButton.disabled) { return null; }
  288. return stopGeneratingButton;
  289. },
  290. getNewChatButton: function () {
  291. const actionBar = this.getActionBar();
  292. if (!actionBar) { return null; }
  293. return actionBar.querySelector('button[aria-label="New topic"]');
  294. },
  295. getConversation: function () {
  296. return document.querySelector("cib-serp")?.shadowRoot?.querySelector("cib-conversation")?.shadowRoot;
  297. },
  298. getChatTurns: function () {
  299. const conversation = this.getConversation();
  300. if (!conversation) { return null; }
  301. return Array.from(conversation.querySelectorAll('cib-chat-turn')).map(t => t.shadowRoot);
  302. },
  303. getLastChatTurn: function () {
  304. const chatTurns = this.getChatTurns();
  305. if (!chatTurns) { return null; }
  306. return chatTurns[chatTurns.length - 1];
  307. },
  308. getLastResponse: function () {
  309. const lastChatTurn = this.getLastChatTurn();
  310. if (!lastChatTurn) { return null; }
  311. return lastChatTurn.querySelectorAll('cib-message-group')[1]?.shadowRoot;
  312. },
  313. getLastResponseText: function () {
  314. const lastResponse = this.getLastResponse();
  315. if (!lastResponse) { return null; }
  316. return Array.from(lastResponse.querySelectorAll('cib-message'))
  317. .map(m => m.shadowRoot)
  318. .find(m => m.querySelector('cib-shared'))
  319. .textContent.trim();
  320. },
  321. send: function (text) {
  322. const textarea = this.getTextarea();
  323. if (!textarea) { return null; }
  324. textarea.value = text;
  325. textarea.dispatchEvent(new Event('input'));
  326. const submitButton = this.getSubmitButton();
  327. if (!submitButton) { return null; }
  328. submitButton.click();
  329. },
  330. onSend: function (callback) {
  331. const textarea = this.getTextarea();
  332. if (!textarea) return;
  333. textarea.addEventListener("keydown", function (event) {
  334. if (event.key === "Enter" && !event.shiftKey) {
  335. callback();
  336. }
  337. });
  338. const sendButton = this.getSubmitButton();
  339. if (!sendButton) return;
  340. sendButton.addEventListener('mousedown', callback);
  341. }
  342. };
  343. // bing send prompt to other ai
  344. let bing_last_prompt = "";
  345. $(async () => {
  346. if (menu_all.bing && location.href.includes("Bing+AI")) {
  347. console.log("bing");
  348. while (!bing.getSubmitButton()) { await new Promise(resolve => setTimeout(resolve, 500)); }
  349. console.log("get bing submit button");
  350. bing.onSend(() => {
  351. console.log("bing send");
  352. const textarea = bing.getTextarea();
  353. const prompt = textarea.value;
  354. console.log(prompt);
  355. bing_last_prompt = prompt;
  356. GM_setValue('chatgpt_prompt_texts', [prompt]);
  357. GM_setValue('bard_prompt_texts', [prompt]);
  358. });
  359. }
  360. });
  361. // bing response to prompt_texts
  362. let last_trigger_time_bing = +new Date();
  363. if (location.href.includes("Bing+AI")) {
  364. GM_addValueChangeListener("bing_prompt_texts", (name, old_value, new_value) => {
  365. if (+new Date() - last_trigger_time_bing < 500) {
  366. return;
  367. }
  368. last_trigger_time_bing = new Date();
  369. setTimeout(async () => {
  370. const prompt_texts = new_value;
  371. if (prompt_texts.length > 0) {
  372. // get prompt_texts from local
  373. let firstTime = true;
  374. while (prompt_texts.length > 0) {
  375. if (!firstTime) { await new Promise(resolve => setTimeout(resolve, 2000)); }
  376. if (!firstTime && bing.getStopGeneratingButton() != undefined) { continue; }
  377. firstTime = false;
  378. const prompt_text = prompt_texts.shift();
  379. if (prompt_text === bing_last_prompt) { continue; }
  380. console.log("bing send prompt_text", prompt_text);
  381. bing.send(prompt_text);
  382. }
  383. }
  384. }, 0);
  385. GM_setValue("bing_prompt_texts", []);
  386. });
  387. }
  388. })();