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