搜索结果侧栏显示 ChatGPT 回答

在搜索结果侧栏显示 ChatGPT 回答(Google、Bing、百度、DuckDuckGo和DeepL)

当前为 2022-12-10 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name chat-gpt-search-sidebar
  3. // @name:zh-CN 搜索结果侧栏显示 ChatGPT 回答
  4. // @version 0.4.0
  5. // @description Display ChatGPT response alongside Search results(Google/Bing/Baidu/DuckDuckGo/DeepL)
  6. // @description:zh-CN 在搜索结果侧栏显示 ChatGPT 回答(Google、Bing、百度、DuckDuckGo和DeepL)
  7. // @author Zheng Bang-Bo(https://github.com/zhengbangbo)
  8. // @match https://www.google.com/search*
  9. // @match https://www.google.com.hk/search*
  10. // @match https://www.google.co.jp/search*
  11. // @match https://www.bing.com/search*
  12. // @match https://cn.bing.com/search*
  13. // @match https://www.baidu.com/s*
  14. // @match https://duckduckgo.com/*
  15. // @match https://www.deepl.com/translator*
  16. // @grant GM_xmlhttpRequest
  17. // @grant GM_log
  18. // @grant GM_setValue
  19. // @grant GM_getValue
  20. // @grant GM_deleteValue
  21. // @grant GM_addStyle
  22. // @namespace https://greasyfork.org/scripts/456077
  23. // @require https://cdn.jsdelivr.net/npm/uuid@8.3.2/dist/umd/uuidv4.min.js
  24. // @connect chat.openai.com
  25. // @license MIT
  26. // ==/UserScript==
  27.  
  28. const container = document.createElement("div");
  29.  
  30. function getSearchEngine() {
  31. if (location.hostname.startsWith("www.google.")) {
  32. return 'google'
  33. }
  34. switch (location.hostname) {
  35. case 'www.bing.com':
  36. case 'cn.bing.com':
  37. return 'bing'
  38. case 'www.baidu.com':
  39. return 'baidu'
  40. case 'duckduckgo.com':
  41. return 'duckduckgo'
  42. case 'www.deepl.com':
  43. return 'deepl'
  44. default:
  45. return 'unknow'
  46. }
  47. }
  48.  
  49. function getQuestion() {
  50. switch (getSearchEngine()) {
  51. case 'baidu':
  52. return new URL(window.location.href).searchParams.get("wd");
  53. default:
  54. return new URL(window.location.href).searchParams.get("q");
  55. }
  56. }
  57.  
  58. function initContainer() {
  59. container.className = "chat-gpt-container";
  60. container.innerHTML = '<p class="loading">Waiting for ChatGPT response...</p>';
  61. }
  62.  
  63. function initField() {
  64. initContainer()
  65. let siderbarContainer = ''
  66.  
  67. switch (getSearchEngine()) {
  68. case 'google':
  69. siderbarContainer = document.getElementById("rhs");
  70. if (siderbarContainer) {
  71. siderbarContainer.prepend(container);
  72. } else {
  73. container.classList.add("sidebar-free");
  74. document.getElementById("rcnt").appendChild(container);
  75. }
  76. break
  77. case 'bing':
  78. siderbarContainer = document.getElementById("b_context");
  79. siderbarContainer.prepend(container);
  80. break
  81. case 'baidu':
  82. siderbarContainer = document.getElementById("content_right");
  83. siderbarContainer.prepend(container);
  84. break
  85. case 'duckduckgo':
  86. siderbarContainer = document.getElementsByClassName("results--sidebar")[0]
  87. siderbarContainer.prepend(container);
  88. break
  89. case 'deepl':
  90. container.style.maxWidth = '1000px';
  91. const button = document.createElement("button");
  92. button.innerHTML = "Chat GPT Translate";
  93. button.className = "chat-gpt-translate-button"
  94. document.getElementsByClassName("lmt__textarea_container")[0].appendChild(button);
  95. button.addEventListener("click", function () {
  96. initContainer()
  97. try {
  98. document.getElementsByClassName("lmt__raise_alternatives_placement")[0].insertBefore(container, document.getElementsByClassName("lmt__translations_as_text")[0]);
  99. }
  100. catch {
  101. document.getElementsByClassName("lmt__textarea_container")[1].insertBefore(container, document.getElementsByClassName("lmt__translations_as_text")[0]);
  102. }
  103. let outlang = document.querySelectorAll("strong[data-testid='deepl-ui-tooltip-target']")[0].innerHTML
  104. let question = 'Translate the following paragraph into ' + outlang + ' and only '+ outlang +'\n\n' + document.getElementById('source-dummydiv').innerHTML
  105. getAnswer(question)
  106. });
  107. break
  108. }
  109.  
  110. GM_addStyle(`
  111. .chat-gpt-container {
  112. max-width: 369px;
  113. margin-bottom: 30px;
  114. border-radius: 8px;
  115. border: 1px solid #dadce0;
  116. padding: 15px;
  117. flex-basis: 0;
  118. flex-grow: 1;
  119. word-wrap: break-word;
  120. white-space: pre-wrap;
  121. }
  122.  
  123. .chat-gpt-container p {
  124. margin: 0;
  125. }
  126.  
  127. .chat-gpt-container .prefix {
  128. font-weight: bold;
  129. }
  130.  
  131. .chat-gpt-container .loading {
  132. color: #b6b8ba;
  133. animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
  134. }
  135.  
  136. @keyframes pulse {
  137. 0%,
  138. 100% {
  139. opacity: 1;
  140. }
  141. 50% {
  142. opacity: 0.5;
  143. }
  144. }
  145.  
  146. .chat-gpt-container.sidebar-free {
  147. margin-left: 60px;
  148. height: fit-content;
  149. }
  150.  
  151. .chat-gpt-container pre {
  152. white-space: pre-wrap;
  153. min-width: 0;
  154. margin-bottom: 0;
  155. line-height: 20px;
  156. }
  157.  
  158. .chat-gpt-translate-button {
  159. border-radius: 8px;
  160. border: 1px solid #dadce0;
  161. padding: 5px;
  162. }
  163.  
  164. .chat-gpt-translate-button:hover {
  165. color: #006494;
  166. transition: color 100ms ease-out;
  167. }
  168. `)
  169. }
  170.  
  171. function refreshFiled(answer) {
  172. container.innerHTML = '<p><span class="prefix">Chat GPT</span><pre></pre></p>';
  173. container.querySelector("pre").textContent = answer;
  174. }
  175.  
  176. function getAccessToken() {
  177. return new Promise((resolve, rejcet) => {
  178. let accessToken = GM_getValue("accessToken")
  179. if (!accessToken) {
  180. GM_xmlhttpRequest({
  181. url: "https://chat.openai.com/api/auth/session",
  182. onload: function (response) {
  183. const accessToken = JSON.parse(response.responseText).accessToken
  184. if (!accessToken) {
  185. rejcet("UNAUTHORIZED")
  186. }
  187. GM_setValue("accessToken", accessToken)
  188. resolve(accessToken)
  189. },
  190. onerror: function (error) {
  191. rejcet(error)
  192. },
  193. ontimeout: () => {
  194. GM_log("getAccessToken timeout!")
  195. }
  196. })
  197. } else {
  198. resolve(accessToken)
  199. }
  200. })
  201. }
  202.  
  203. async function getAnswer(question) {
  204. try {
  205. const accessToken = await getAccessToken()
  206. GM_xmlhttpRequest({
  207. method: "POST",
  208. url: "https://chat.openai.com/backend-api/conversation",
  209. headers: {
  210. "Content-Type": " application/json",
  211. Authorization: `Bearer ${accessToken}`,
  212. },
  213. data: JSON.stringify({
  214. action: "next",
  215. messages: [
  216. {
  217. id: uuidv4(),
  218. role: "user",
  219. content: {
  220. content_type: "text",
  221. parts: [question],
  222. },
  223. },
  224. ],
  225. model: "text-davinci-002-render",
  226. parent_message_id: uuidv4(),
  227. }),
  228. // onloadstart: function (event) {
  229. // GM_log("getAnswer onloadstart: ", event)
  230. // },
  231. onloadend: function (event) {
  232. // GM_log("getAnswer onloadend: ", event)
  233. if (event.status === 401) {
  234. GM_deleteValue("accessToken")
  235. location.reload()
  236. }
  237. if (event.status != 401 && event.status != 200) {
  238. GM_log('Oops, maybe it is a bug, please submit https://github.com/zhengbangbo/chat-gpt-userscript/issues with follow log of event')
  239. GM_log('event: ', event)
  240. }
  241. if (event.response) {
  242. const answer = JSON.parse(event.response.split("\n\n").slice(-3, -2)[0].slice(6)).message.content.parts[0]
  243. refreshFiled(answer)
  244. }
  245. },
  246. // onprogress: function (event) {
  247. // GM_log("getAnswer onprogress: ", event)
  248. // },
  249. // onreadystatechange: function (event) {
  250. // GM_log("getAnswer onreadystatechange: ", event)
  251. // },
  252. // onload: function (event) {
  253. // GM_log("getAnswer onload: ", event)
  254. // },
  255. onerror: function (event) {
  256. GM_log("getAnswer onerror: ", event)
  257. },
  258. ontimeout: function (event) {
  259. GM_log("getAnswer ontimeout: ", event)
  260. }
  261. })
  262. } catch (error) {
  263. if (error === "UNAUTHORIZED") {
  264. container.innerHTML =
  265. '<p>Please login at <a href="https://chat.openai.com" target="_blank">chat.openai.com</a> first</p>';
  266. }
  267. GM_log("getAccessToken error: ", error)
  268. }
  269. }
  270.  
  271. (async function () {
  272. initField()
  273. getAnswer(getQuestion())
  274. })();