Doozy

A wonderful day spent with ChatGPT

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

  1. // ==UserScript==
  2. // @name Doozy
  3. // @namespace https://github.com/mefengl
  4. // @version 0.7.3
  5. // @description A wonderful day spent with ChatGPT
  6. // @icon https://www.google.com/s2/favicons?sz=64&domain=openai.com
  7. // @author mefengl
  8. // @match https://chat.openai.com/chat
  9. // @match http://*/*
  10. // @match https://*/*
  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("book.douban"), name: "douban_book", value: true },
  30. { checker: () => location.href.includes("zhihu"), name: "zhihu", value: true },
  31. { checker: () => location.href.includes("news.ycombinator"), name: "hackernews", value: true },
  32. { checker: () => location.href.includes("github"), name: "github", value: true },
  33. { checker: () => location.href.includes("wikipedia"), name: "wikipedia", value: true },
  34. { checker: () => location.href.includes("nytimes.com"), name: "nytimes", value: true },
  35. { checker: () => location.href.includes("baidu.com"), name: "baidu", value: true },
  36. { checker: () => location.href.includes("reddit.com"), name: "reddit", value: true },
  37. { checker: () => location.href.includes("google.com"), name: "google", value: true },
  38. { checker: () => location.href.includes("youtube.com"), name: "youtube", value: true },
  39. ];
  40.  
  41. menus.forEach(menu => {
  42. $(() => menu.checker() && GM_setValue(menu.name, true) && console.log(`开启 ${menu.name} 菜单`));
  43. if (GM_getValue(menu.name) == true) {
  44. default_menu_all[menu.name] = menu.value;
  45. }
  46. });
  47.  
  48. // 检查是否有新增菜单
  49. for (let name in default_menu_all) {
  50. if (!(name in menu_all)) {
  51. menu_all[name] = default_menu_all[name];
  52. }
  53. }
  54. const menu_id = GM_getValue("menu_id", {});
  55.  
  56. function registerMenuCommand(name, value) {
  57. const menuText = ` ${name}:${value ? '✅' : '❌'}`;
  58. const commandCallback = () => {
  59. menu_all[name] = !menu_all[name];
  60. GM_setValue('menu_all', menu_all);
  61. update_menu();
  62. location.reload();
  63. };
  64. return GM_registerMenuCommand(menuText, commandCallback);
  65. }
  66. function update_menu() {
  67. for (let name in menu_all) {
  68. const value = menu_all[name];
  69. if (menu_id[name]) {
  70. GM_unregisterMenuCommand(menu_id[name]);
  71. }
  72. menu_id[name] = registerMenuCommand(name, value);
  73. }
  74. GM_setValue('menu_id', menu_id);
  75. }
  76. update_menu();
  77.  
  78. const douban_book_prompts = [
  79. ({ title, author }) => `${author}的《${title}》的主要观点列成表格会是:`,
  80. ({ title, author }) => `${author}的《${title}》比较重要的章节会是:`,
  81. ({ title, author }) => `${author}的《${title}》在哪些方面是有争议的会是:`,
  82. ({ title, author }) => `${author}的《${title}》当人们生活在不同的时代时,会有什么不同的观点会是:`,
  83. ({ title, author }) => `${author}的《${title}》综合Goodreads评分和豆瓣等各种评分和评价会是:`,
  84. ({ title, author }) => `${author}的《${title}》的类似书籍或文章和它们的区别会是:`,
  85. ({ title, author }) => `${author}的《${title}》的观点相反的书籍或文章和对应的观点会是:`,
  86. ]
  87. const question_prompts = [
  88. ({ question }) => `问题:${question},暗含的观点是:`,
  89. ({ question }) => `问题:${question},应该去反思:`,
  90. ({ question }) => `问题:${question},想要改进或解决它,可以从这些方面入手:`,
  91. ({ question }) => `问题:${question},提问者和提问者的目的是:`,
  92. ({ question }) => `问题:${question},问题的相关历史是:`,
  93. ({ question }) => `问题:${question},不同的国家对这个问题的看法会是:`,
  94. ({ question }) => `问题:${question},类似问题和它们的区别会是:`,
  95. ({ question }) => `问题:${question},观点相反的问题和对应的观点会是:`,
  96. ({ question }) => `问题:${question},幽默的回答会是:`,
  97. ({ question }) => `问题:${question},主要观点列成表格会是:`,
  98. ({ question }) => `问题:${question},相关书籍、文章、视频或网站会是:`,
  99. ({ question }) => `从这个问题:${question},可以引申出这些问题:`,
  100. ]
  101. const github_prompts = [
  102. ({ website }) => `${website}的最佳实践是:`,
  103. ({ website }) => `${website}的类似项目是:`,
  104. ({ website }) => `${website}的相关书籍、文章、视频或网站是:`,
  105. ]
  106.  
  107. function chatgpt_trigger(prompt_prepare, prompts) {
  108. const prepare_data = prompt_prepare();
  109. const prompt_texts = prompts.map(prompt => prompt(prepare_data));
  110. GM_setValue("prompt_texts", prompt_texts);
  111. }
  112.  
  113. const triggers = [
  114. {
  115. checker: () => menu_all.douban_book && location.href.includes("book.douban.com/subject"),
  116. prepare: () => {
  117. const title = $("meta[property='og:title']").attr("content");
  118. const author = $("meta[property='book:author']").attr("content");
  119. return { title, author };
  120. },
  121. prompts: douban_book_prompts
  122. },
  123. {
  124. checker: () => menu_all.zhihu && location.href.includes("zhihu.com/question"),
  125. prepare: () => {
  126. const question = $('meta[itemprop="name"]').attr('content');
  127. return { question };
  128. },
  129. prompts: [...question_prompts]
  130. },
  131. {
  132. checker: () => menu_all.hackernews && location.href.includes("news.ycombinator.com/item"),
  133. prepare: () => {
  134. const question = $('td.title > span.titleline > a').text();
  135. return { question };
  136. },
  137. prompts: [...question_prompts]
  138. },
  139. {
  140. checker: () => menu_all.github && location.href.includes("github.com"),
  141. prepare: () => {
  142. const parts = location.href.split("/");
  143. if (parts.length >= 5 && parts[parts.length - 2] && parts[parts.length - 1]) {
  144. const website = parts[parts.length - 2] + "/" + parts[parts.length - 1];
  145. return { website };
  146. }
  147. },
  148. prompts: github_prompts
  149. },
  150. {
  151. checker: () => menu_all.wikipedia && location.href.includes("wikipedia.org/wiki/"),
  152. prepare: () => {
  153. const title = $("h1#firstHeading").text();
  154. const summary = $("div.mw-parser-output p").first().text();
  155. return { title, summary };
  156. },
  157. prompts: [
  158. ({ title }) => `${title}的历史和重要事件有哪些?`,
  159. ({ title }) => `${title}与其他相关主题的比较和对比会是:`,
  160. ({ title }) => `${title}的主要观点列成表格会是:`,
  161. ({ title }) => `${title}的关键概念和术语是什么?`,
  162. ({ title }) => `${title}的类似词条或相关研究和它们的区别会是:`,
  163. ]
  164. },
  165. {
  166. checker: () => menu_all.nytimes && location.href.includes("nytimes.com"),
  167. prepare: () => {
  168. const articleTitle = $("h1").text();
  169. return { question: articleTitle };
  170. },
  171. prompts: [...question_prompts]
  172. },
  173. {
  174. checker: () => menu_all.baidu && location.href.includes("www.baidu.com/s"),
  175. prepare: () => {
  176. const keyword = $("input#kw").val();
  177. return { keyword };
  178. },
  179. prompts: [
  180. ({ keyword }) => `关于"${keyword}"的最新新闻有哪些?`,
  181. ({ keyword }) => `"${keyword}"的定义和解释是什么?`,
  182. ({ keyword }) => `对于"${keyword}"这个话题,你有什么观点或看法?`,
  183. ({ keyword }) => `跟"${keyword}"相关的人物或事件有哪些?`,
  184. ({ keyword }) => `最近跟"${keyword}"相关的热门话题是什么?`,
  185. ]
  186. },
  187. {
  188. checker: () => menu_all.reddit && location.href.includes("reddit.com"),
  189. prepare: () => {
  190. const postTitle = $("h1._eYtD2XCVieq6emjKBH3m").text();
  191. const postContent = $("div._3W_31WoaKsKsZfNldTiz5M").first().text();
  192. return { postTitle, postContent };
  193. },
  194. prompts: [
  195. ({ postTitle }) => `关于"${postTitle}",你有什么想法或评论?`,
  196. ({ postTitle }) => `能给大家分享一些"${postTitle}"的相关信息吗?`,
  197. ({ postTitle }) => `在"${postTitle}"的讨论中,有哪些观点或意见最值得关注?`,
  198. ({ postTitle }) => `对于"${postTitle}",你的看法是否与其他人不同?`,
  199. ({ postTitle }) => `请简要介绍一下"${postTitle}"的主要内容和背景。`,
  200. ]
  201. },
  202. {
  203. checker: () => menu_all.google && location.href.includes("google.com/search?q="),
  204. prepare: () => {
  205. const keyword = $("input[name='q']").val();
  206. return { keyword };
  207. },
  208. prompts: [
  209. ({ keyword }) => `关于"${keyword}"的最新搜索结果有哪些?`,
  210. ({ keyword }) => `对于"${keyword}"这个话题,你有什么观点或看法?`,
  211. ({ keyword }) => `跟"${keyword}"相关的人物或事件有哪些?`,
  212. ({ keyword }) => `最近跟"${keyword}"相关的热门话题是什么?`,
  213. ]
  214. },
  215. {
  216. checker: () => menu_all.youtube && location.href.includes("youtube.com/watch"),
  217. prepare: () => {
  218. const metaTitle = $('meta[name="title"]').attr('content');
  219. return { metaTitle };
  220. },
  221. prompts: [
  222. ({ metaTitle }) => `关于"${metaTitle}"的观点或评论有哪些?`,
  223. ({ metaTitle }) => `能给大家分享一些关于"${metaTitle}"的相关信息吗?`,
  224. ({ metaTitle }) => `在"${metaTitle}"的讨论中,有哪些观点或意见最值得关注?`,
  225. ({ metaTitle }) => `对于"${metaTitle}",你的看法是否与其他人不同?`,
  226. ({ metaTitle }) => `请简要介绍一下"${metaTitle}"的主要内容和背景。`,
  227. ]
  228. }
  229. ];
  230.  
  231. triggers.forEach(trigger => {
  232. trigger.checker() && chatgpt_trigger(trigger.prepare, trigger.prompts);
  233. });
  234.  
  235. /* ************************************************************************* */
  236. // ChatGPT response to prompt_texts
  237. const get_submit_button = () => {
  238. const form = document.querySelector('form');
  239. const buttons = form.querySelectorAll('button');
  240. const result = buttons[buttons.length - 1]; // by textContent maybe better
  241. return result;
  242. };
  243. const get_textarea = () => {
  244. const form = document.querySelector('form');
  245. const textareas = form.querySelectorAll('textarea');
  246. const result = textareas[0];
  247. return result;
  248. };
  249. const get_regenerate_button = () => {
  250. const form = document.querySelector('form');
  251. const buttons = form.querySelectorAll('button');
  252. for (let i = 0; i < buttons.length; i++) {
  253. const buttonText = buttons[i].textContent.trim().toLowerCase();
  254. if (buttonText.includes('regenerate')) {
  255. return buttons[i];
  256. }
  257. }
  258. };
  259.  
  260. let last_trigger_time = +new Date();
  261. $(() => {
  262. if (location.href.includes("chat.openai")) {
  263. console.log("ChatGPT");
  264. GM_addValueChangeListener("prompt_texts", (name, old_value, new_value) => {
  265. if (+new Date() - last_trigger_time < 500) {
  266. return;
  267. }
  268. last_trigger_time = new Date();
  269. setTimeout(async () => {
  270. console.log("ChatGPT页面响应prompt_texts");
  271. const prompt_texts = new_value;
  272. console.log(prompt_texts);
  273. if (prompt_texts.length > 0) {
  274. console.log("进入处理");
  275. // get prompt_texts from local
  276. let firstTime = true;
  277. while (prompt_texts.length > 0) {
  278. if (!firstTime) {
  279. await new Promise(resolve => setTimeout(resolve, 2000));
  280. }
  281. if (!firstTime && get_regenerate_button() == undefined) {
  282. continue;
  283. }
  284. firstTime = false;
  285. const prompt_text = prompt_texts.shift();
  286. console.log(prompt_text);
  287. // write the prompt_text
  288. get_textarea().value = prompt_text;
  289. // submit
  290. get_submit_button().click();
  291. }
  292. }
  293. }, 0);
  294. GM_setValue("prompt_texts", []);
  295. });
  296. }
  297. });
  298. })();