chat-octopus

let octopus send message for you

目前为 2023-03-28 提交的版本。查看 最新版本

  1. // ==UserScript==
  2. // @name chat-octopus
  3. // @namespace https://github.com/mefengl
  4. // @version 0.1.2
  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 get_submit_button = () => {
  73. const form = document.querySelector('form');
  74. const buttons = form.querySelectorAll('button');
  75. const result = buttons[buttons.length - 1]; // by textContent maybe better
  76. return result;
  77. };
  78. const get_textarea = () => {
  79. const form = document.querySelector('form');
  80. const textareas = form.querySelectorAll('textarea');
  81. const result = textareas[0];
  82. return result;
  83. };
  84. const get_regenerate_button = () => {
  85. const form = document.querySelector('form');
  86. const buttons = form.querySelectorAll('button');
  87. for (let i = 0; i < buttons.length; i++) {
  88. const buttonText = buttons[i].textContent.trim().toLowerCase();
  89. if (buttonText.includes('regenerate')) {
  90. return buttons[i];
  91. }
  92. }
  93. };
  94. const chatgpt_send = (text) => {
  95. const textarea = get_textarea();
  96. textarea.value = text;
  97. textarea.dispatchEvent(new Event('input'));
  98. const submitButton = get_submit_button();
  99. submitButton.click();
  100. };
  101. // ChatGPT send prompt to other ai
  102. let chatgpt_last_prompt = '';
  103. $(() => {
  104. if (menu_all.openai && location.href.includes("chat.openai")) {
  105. const submit_button = get_submit_button();
  106. submit_button.addEventListener('click', () => {
  107. const textarea = get_textarea();
  108. const prompt = textarea.value;
  109. chatgpt_last_prompt = prompt;
  110. GM_setValue('bard_prompt_texts', [prompt]);
  111. GM_setValue('bing_prompt_texts', [prompt]);
  112. })
  113. }
  114. });
  115. // ChatGPT response to prompt comes from other ai
  116. let last_trigger_time = +new Date();
  117. $(() => {
  118. if (location.href.includes("chat.openai")) {
  119. console.log("chatgpt add value change listener");
  120. GM_addValueChangeListener("chatgpt_prompt_texts", (name, old_value, new_value) => {
  121. console.log("prompt_texts changed in chatgpt");
  122. console.log(new_value);
  123. if (+new Date() - last_trigger_time < 500) {
  124. return;
  125. }
  126. last_trigger_time = new Date();
  127. setTimeout(async () => {
  128. const prompt_texts = new_value;
  129. if (prompt_texts.length > 0) {
  130. // get prompt_texts from local
  131. let firstTime = true;
  132. while (prompt_texts.length > 0) {
  133. if (!firstTime) { await new Promise(resolve => setTimeout(resolve, 2000)); }
  134. if (!firstTime && get_regenerate_button() == undefined) { continue; }
  135. firstTime = false;
  136. const prompt_text = prompt_texts.shift();
  137. if (prompt_text === chatgpt_last_prompt) { continue; }
  138. console.log("chatgpt send prompt_text", prompt_text);
  139. chatgpt_send(prompt_text);
  140. }
  141. }
  142. }, 0);
  143. GM_setValue("chatgpt_prompt_texts", []);
  144. });
  145. }
  146. });
  147.  
  148. /* ************************************************************************* */
  149. function getSubmitButton() {
  150. return document.querySelector('button[aria-label="Send message"]');
  151. };
  152. function getInputArea() {
  153. return document.querySelector(".input-area");
  154. };
  155. function getTextarea() {
  156. const inputArea = getInputArea();
  157. return inputArea.querySelector('textarea');
  158. };
  159. function getRegenerateButton() {
  160. return document.querySelector('button[aria-label="Retry"]');
  161. };
  162. function bard_send(text) {
  163. const textarea = getTextarea();
  164. textarea.value = text;
  165. textarea.dispatchEvent(new Event('input'));
  166. const submitButton = getSubmitButton();
  167. submitButton.click();
  168. };
  169. // Bard send prompt to other ai
  170. let bard_last_prompt = "";
  171. $(async () => {
  172. if (menu_all.bard && location.href.includes("bard.google")) {
  173. while (!getSubmitButton()) { await new Promise(resolve => setTimeout(resolve, 500)); }
  174. const submit_button = getSubmitButton();
  175. submit_button.addEventListener('mousedown', () => {
  176. console.log("bard send");
  177. const textarea = getTextarea();
  178. const prompt = textarea.value;
  179. console.log(prompt);
  180. bard_last_prompt = prompt;
  181. GM_setValue('chatgpt_prompt_texts', [prompt]);
  182. GM_setValue('bing_prompt_texts', [prompt]);
  183. })
  184. }
  185. });
  186. // Bard response to prompt_texts
  187. let lastTriggerTime = +new Date();
  188. if (location.href.includes("bard.google")) {
  189. GM_addValueChangeListener("bard_prompt_texts", (name, old_value, new_value) => {
  190. if (+new Date() - lastTriggerTime < 500) {
  191. return;
  192. }
  193. lastTriggerTime = new Date();
  194. setTimeout(async () => {
  195. const promptTexts = new_value;
  196. if (promptTexts.length > 0) {
  197. // get promptTexts from local
  198. let firstTime = true;
  199. while (promptTexts.length > 0) {
  200. if (!firstTime) { await new Promise(resolve => setTimeout(resolve, 2000)); }
  201. if (!firstTime && getRegenerateButton() == undefined) { continue; }
  202. firstTime = false;
  203. const promptText = promptTexts.shift();
  204. if (promptText === bard_last_prompt) { continue; }
  205. bard_send(promptText);
  206. }
  207. }
  208. }, 0);
  209. GM_setValue("bard_prompt_texts", []);
  210. });
  211. }
  212. /* ************************************************************************* */
  213. const bing = {
  214. getActionBar: function () {
  215. return document.querySelector("cib-serp")?.shadowRoot?.querySelector("cib-action-bar")?.shadowRoot;
  216. },
  217. getSubmitButton: function () {
  218. const actionBar = this.getActionBar();
  219. if (!actionBar) { return null; }
  220. return actionBar.querySelector('button[aria-label="Submit"]');
  221. },
  222. getTextarea: function () {
  223. const actionBar = this.getActionBar();
  224. if (!actionBar) { return null; }
  225. return actionBar.querySelector('textarea');
  226. },
  227. getStopGeneratingButton: function () {
  228. const actionBar = this.getActionBar();
  229. if (!actionBar) { return null; }
  230. const stopGeneratingButton = actionBar.querySelector('cib-typing-indicator')?.shadowRoot?.querySelector('button[aria-label="Stop Responding"]');
  231. if (!stopGeneratingButton) { return null; }
  232. if (stopGeneratingButton.disabled) { return null; }
  233. return stopGeneratingButton;
  234. },
  235. getNewChatButton: function () {
  236. const actionBar = this.getActionBar();
  237. if (!actionBar) { return null; }
  238. return actionBar.querySelector('button[aria-label="New topic"]');
  239. },
  240. getConversation: function () {
  241. return document.querySelector("cib-serp")?.shadowRoot?.querySelector("cib-conversation")?.shadowRoot;
  242. },
  243. getChatTurns: function () {
  244. const conversation = this.getConversation();
  245. if (!conversation) { return null; }
  246. return Array.from(conversation.querySelectorAll('cib-chat-turn')).map(t => t.shadowRoot);
  247. },
  248. getLastChatTurn: function () {
  249. const chatTurns = this.getChatTurns();
  250. if (!chatTurns) { return null; }
  251. return chatTurns[chatTurns.length - 1];
  252. },
  253. getLastResponse: function () {
  254. const lastChatTurn = this.getLastChatTurn();
  255. if (!lastChatTurn) { return null; }
  256. return lastChatTurn.querySelectorAll('cib-message-group')[1]?.shadowRoot;
  257. },
  258. getLastResponseText: function () {
  259. const lastResponse = this.getLastResponse();
  260. if (!lastResponse) { return null; }
  261. return Array.from(lastResponse.querySelectorAll('cib-message'))
  262. .map(m => m.shadowRoot)
  263. .find(m => m.querySelector('cib-shared'))
  264. .textContent.trim();
  265. },
  266. send: function (text) {
  267. const textarea = this.getTextarea();
  268. if (!textarea) { return null; }
  269. textarea.value = text;
  270. textarea.dispatchEvent(new Event('input'));
  271. const submitButton = this.getSubmitButton();
  272. if (!submitButton) { return null; }
  273. submitButton.click();
  274. }
  275. };
  276. // bing send prompt to other ai
  277. let bing_last_prompt = "";
  278. $(async () => {
  279. if (menu_all.bing && location.href.includes("Bing+AI")) {
  280. console.log("bing");
  281. while (!bing.getSubmitButton()) { await new Promise(resolve => setTimeout(resolve, 500)); }
  282. console.log("get bing submit button");
  283. const submit_button = bing.getSubmitButton();
  284. submit_button.addEventListener('mousedown', () => {
  285. console.log("bing send");
  286. const textarea = bing.getTextarea();
  287. const prompt = textarea.value;
  288. console.log(prompt);
  289. bing_last_prompt = prompt;
  290. GM_setValue('chatgpt_prompt_texts', [prompt]);
  291. GM_setValue('bard_prompt_texts', [prompt]);
  292. })
  293. }
  294. });
  295. // bing response to prompt_texts
  296. let last_trigger_time_bing = +new Date();
  297. if (location.href.includes("Bing+AI")) {
  298. GM_addValueChangeListener("bing_prompt_texts", (name, old_value, new_value) => {
  299. if (+new Date() - last_trigger_time_bing < 500) {
  300. return;
  301. }
  302. last_trigger_time_bing = new Date();
  303. setTimeout(async () => {
  304. const prompt_texts = new_value;
  305. if (prompt_texts.length > 0) {
  306. // get prompt_texts from local
  307. let firstTime = true;
  308. while (prompt_texts.length > 0) {
  309. if (!firstTime) { await new Promise(resolve => setTimeout(resolve, 2000)); }
  310. if (!firstTime && bing.getStopGeneratingButton() != undefined) { continue; }
  311. firstTime = false;
  312. const prompt_text = prompt_texts.shift();
  313. if (prompt_text === bing_last_prompt) { continue; }
  314. console.log("bing send prompt_text", prompt_text);
  315. bing.send(prompt_text);
  316. }
  317. }
  318. }, 0);
  319. GM_setValue("bing_prompt_texts", []);
  320. });
  321. }
  322. })();
  323.