Greasy Fork镜像 支持简体中文。

ChatGPT 模型切换器(支持 GPT-4 Mobile 及所有可用模型)

通过启用 GPT-4 Mobile 模型,解除 ChatGPT 网页端对 GPT-4 模型使用次数的限制。同时还可启用其他模型进行切换,提供更多的灵活性。一般来说,该脚本不会与其他流行的 ChatGPT 脚本产生冲突。

目前為 2023-06-28 提交的版本,檢視 最新版本

  1. // ==UserScript==
  2. // @name ChatGPT Model Switcher (Supports GPT-4 Mobile and All Available Models)
  3. // @name:zh-CN ChatGPT 模型切换器(支持 GPT-4 Mobile 及所有可用模型)
  4. // @name:zh-TW ChatGPT 模型切换器(支持 GPT-4 Mobile 及所有可用模型)
  5. // @namespace https://github.com/hydrotho/ChatGPT_Model_Switcher
  6. // @copyright 2023, Hydrotho (https://github.com/hydrotho)
  7. // @version 1.1.2
  8. // @description Override GPT-4 usage limits in the ChatGPT web interface by enabling the GPT-4 Mobile model. Additional models can also be enabled for switching, providing more flexibility. Generally, this script does not conflict with other popular ChatGPT scripts.
  9. // @description:zh-CN 通过启用 GPT-4 Mobile 模型,解除 ChatGPT 网页端对 GPT-4 模型使用次数的限制。同时还可启用其他模型进行切换,提供更多的灵活性。一般来说,该脚本不会与其他流行的 ChatGPT 脚本产生冲突。
  10. // @description:zh-TW 通过启用 GPT-4 Mobile 模型,解除 ChatGPT 网页端对 GPT-4 模型使用次数的限制。同时还可启用其他模型进行切换,提供更多的灵活性。一般来说,该脚本不会与其他流行的 ChatGPT 脚本产生冲突。
  11. // @icon data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAH1UExURUxpcXeqn3WqnHWonHSpnHWonHWpnG22knWpnHWpnHSmm3apm3SpnHWonHWpnHSonHWpnHWpm3apnXWpnHWpm3WpnP///8fc19fm43mrn67Nxf7///r8+6HFvNPk4JS8ssXb1XirnsDY0sPa1Pj7+qbHv5i/tXeqnvz9/X6uoo65roq2q+Tu7P3+/qrKwqDEu9bm4vP39qfIwPv9/NXl4ezz8Xqsn+nx73msn5/Dusnd2N7q59zp5pC6r4CwpKLFvIOxpszf2oSypsTa1fn7+/P49t/r6JrAt8LZ1L/X0d3q53aqnczf287h3Ie0qc7g3Pr8/LTQybDOxpvBuObv7c/h3PX5+Ory8ODr6OPt65G7sLnTzYWzp/n7+oi1qv7+/tTk4J7Cucve2Z3Cub7X0H+vo8LZ053CuKnJwff6+tnn4/3+/fD29XytoYWzqJe+tJa+tHapnHeqnaHEu8vf2oGxpazLw3utoMre2ZW9s7XRyu/19H2uou/186XHv6jJwNDi3sjd2OLt6u308ufw7tfm4rjTzK3MxOjw7tvp5dHi3sjd15m/tvL39q/Nxvb5+OPu64y3rIOyptnn5LbSy+Ds6eHs6tbl4cHZ0/v8/H6vo4GwpZ7Dus/h3fb6+ZK7sfT49/f6+aLFvavLw6zLxM3g28bc1pQLf2QAAAAVdFJOUwAtv5bz1PQH/dUuj5WQ/CyYwJHykqKEGP8AAAAJcEhZcwAAAHYAAAB2AU57JggAAAIcSURBVDjLhdNle9swEABgFdK0Kw7uHMfp6iTeAksaThpoUmZuV1x5zMxbx8wM7Xj7nZNjx/L2rNl9kXR6H51snwmhsWFTWQn8FSWGygKihLGmFP4ZpUXG7P5GWDcKZVEDeaKC1mfnHxUvoSV19YQOVFWTLdpiUfJ2POx/jOEzAy4tWU7KctPG95FpOjT0IA2PT80aSHEOpKQ5mSUxIA7bD2OzI5vdTNTt1QXBDvAxMT/7qkE+h8PdyoYC+DX0YgYyX4W+FwBunqYOhpp0YAl/1eN22Or5DPD8Jd6sBTiOZgYa8SfUysAMH+wWW/AK3ndbUWRADKUVMGIex1YrRGcs3uvYxcCzKVCAJTb66FZsFGDXTgHPMjD2WgWcFeCkHd/uoOshj0MD16QoLOI2+Q406ifpPXh4gisaOIXD4JiZXUoqwARx/Ab80zB7TJMzmK17nr4BK2eCOnocJGMMBBH9tO6FqYhveUJSwZsxBrpRDDltl6G3G7/8+K6AtLOZARu65hYwcLfL8s4l30EGCTzGwH6MA3Tew9u0Tp1HBmYOT+u+xZ62nl4AB91uGRQ+ZWAZ53HQqgMwgn3n6BC90+bl0nLJB51qH+QaphUD3EWuHVNuuhiQwlrPaS3n6zhEW+2G3I3TkSE3A5XalG860o/j/sSkcGAf62tS8MdvFfe3Oyf2tugyhBRB3qC/XuF/ADFWVOUHhFSXG4rXA78BYbiLJDUXqsMAAABXelRYdFJhdyBwcm9maWxlIHR5cGUgaXB0YwAAeJzj8gwIcVYoKMpPy8xJ5VIAAyMLLmMLEyMTS5MUAxMgRIA0w2QDI7NUIMvY1MjEzMQcxAfLgEigSi4A6hcRdPJCNZUAAAAASUVORK5CYII=
  12. // @grant none
  13. // @author Hydrotho
  14. // @match http*://chat.openai.com/*
  15. // @supportURL https://github.com/hydrotho/ChatGPT_Model_Switcher/issues
  16. // @license MIT
  17. // ==/UserScript==
  18.  
  19. (function () {
  20. "use strict";
  21.  
  22. let useModelSwitcher = localStorage.getItem("useModelSwitcher") !== "false";
  23. let selectedModel = localStorage.getItem("selectedModel") || "GPT-4 (Mobile)";
  24.  
  25. const modelMapping = {
  26. "GPT-3.5": "text-davinci-002-render-sha",
  27. "GPT-4": "gpt-4",
  28. "GPT-4 Web Browsing": "gpt-4-browsing",
  29. "GPT-4 Plugins": "gpt-4-plugins",
  30. "GPT-3.5 (Mobile)": "text-davinci-002-render-sha-mobile",
  31. "GPT-4 (Mobile)": "gpt-4-mobile",
  32. };
  33.  
  34. const CONVERSATION_API_URL =
  35. "https://chat.openai.com/backend-api/conversation";
  36. const MODELS_API_URL =
  37. "https://chat.openai.com/backend-api/models?history_and_training_disabled=false";
  38. const ARKOSE_TOKEN_URL = "https://ai.fakeopen.com/api/arkose/token";
  39. const ARKOSE_PARAMS_URL = "https://ai.fakeopen.com/api/arkose/params";
  40.  
  41. const arkoseTokenBda = btoa(JSON.stringify({ ct: "", iv: "", s: "" }));
  42. const arkoseTokenPublicKey = "35536E1E-65B4-4D96-9D97-6ADB7EFF8147";
  43. const arkoseTokenSite = "https://chat.openai.com";
  44. const arkoseTokenUserBrowser = navigator.userAgent;
  45. const arkoseTokenCapiVersion = "1.5.2";
  46. const arkoseTokenCapiMode = "lightbox";
  47. const arkoseTokenStyleTheme = "default";
  48. const arkoseTokenRnd = Math.random().toFixed(17);
  49. const arkoseTokenUrl =
  50. "https://tcr9i.chat.openai.com/fc/gt2/public_key/" + arkoseTokenPublicKey;
  51.  
  52. async function getArkoseToken() {
  53. try {
  54. const response = await fetch(ARKOSE_TOKEN_URL);
  55. if (response.ok) {
  56. const data = await response.json();
  57. return data.token;
  58. } else {
  59. throw new Error(
  60. "Unable to fetch arkose_token directly: HTTP " + response.status
  61. );
  62. }
  63. } catch (error) {
  64. console.error(
  65. "Error encountered while fetching arkose_token directly: ",
  66. error
  67. );
  68. return await getArkoseTokenFallback();
  69. }
  70. }
  71.  
  72. async function getArkoseParams() {
  73. try {
  74. const response = await fetch(ARKOSE_PARAMS_URL);
  75. if (response.ok) {
  76. return await response.json();
  77. } else {
  78. throw new Error(
  79. "Unable to fetch Arkose params: HTTP " + response.status
  80. );
  81. }
  82. } catch (error) {
  83. console.error("Error encountered while fetching Arkose params: ", error);
  84. console.info("Use local fallback!");
  85. return {
  86. bda: arkoseTokenBda,
  87. public_key: arkoseTokenPublicKey,
  88. site: arkoseTokenSite,
  89. userbrowser: arkoseTokenUserBrowser,
  90. capi_version: arkoseTokenCapiVersion,
  91. capi_mode: arkoseTokenCapiMode,
  92. style_theme: arkoseTokenStyleTheme,
  93. rnd: arkoseTokenRnd,
  94. };
  95. }
  96. }
  97.  
  98. async function getArkoseTokenFallback(params) {
  99. const arkoseParams = await getArkoseParams();
  100. const formParams = new URLSearchParams(arkoseParams);
  101. try {
  102. const response = await fetch(arkoseTokenUrl, {
  103. method: "POST",
  104. headers: {
  105. "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
  106. },
  107. body: formParams,
  108. });
  109.  
  110. if (response.ok) {
  111. const data = await response.json();
  112. return data.token;
  113. } else {
  114. throw new Error(
  115. "Unable to fetch arkose_token: HTTP " + response.status
  116. );
  117. }
  118. } catch (error) {
  119. console.error("Error encountered while fetching arkose_token: ", error);
  120. return null;
  121. }
  122. }
  123.  
  124. async function handleModelsApiUrlResponse(fetchPromise) {
  125. return fetchPromise.then((response) => {
  126. if (response.ok) {
  127. response
  128. .clone()
  129. .json()
  130. .then((data) => {
  131. const accessibleModels = data.models.map((model) => model.slug);
  132. Object.keys(modelMapping).forEach((model) => {
  133. const mappedSlug = modelMapping[model];
  134. const selectOption = document.querySelector(
  135. `#modelSelect option[value="${model}"]`
  136. );
  137. if (selectOption && !accessibleModels.includes(mappedSlug)) {
  138. selectOption.disabled = true;
  139. if (selectedModel === model) {
  140. selectedModel = "GPT-3.5";
  141. localStorage.setItem("selectedModel", selectedModel);
  142. document.querySelector("#modelSelect").value = selectedModel;
  143. }
  144. }
  145. });
  146. });
  147. }
  148. return response;
  149. });
  150. }
  151.  
  152. window.fetch = new Proxy(window.fetch, {
  153. apply: async function (target, that, args) {
  154. let resource = args[0];
  155. let options = args[1];
  156.  
  157. if (useModelSwitcher && resource === CONVERSATION_API_URL) {
  158. const requestBody = JSON.parse(options.body);
  159. requestBody.model = modelMapping[selectedModel];
  160.  
  161. if (
  162. requestBody.model.startsWith("gpt-4") &&
  163. requestBody.arkose_token === null
  164. ) {
  165. requestBody.arkose_token = await getArkoseToken();
  166. } else if (
  167. requestBody.model.startsWith("text-davinci-002-render-sha") &&
  168. requestBody.arkose_token !== null
  169. ) {
  170. requestBody.arkose_token = null;
  171. }
  172.  
  173. options = { ...options, body: JSON.stringify(requestBody) };
  174. args[0] = resource;
  175. args[1] = options;
  176. }
  177.  
  178. const fetchPromise = Reflect.apply(target, that, args);
  179.  
  180. if (resource.includes(MODELS_API_URL)) {
  181. return handleModelsApiUrlResponse(fetchPromise);
  182. }
  183.  
  184. return fetchPromise;
  185. },
  186. });
  187.  
  188. function createSwitchElement() {
  189. const switchLabel = document.createElement("label");
  190. switchLabel.className = "switch";
  191. switchLabel.title = "Check to enable the model switcher";
  192.  
  193. const switchCheckbox = document.createElement("input");
  194. switchCheckbox.type = "checkbox";
  195. switchCheckbox.id = "useModelSwitcherCheckbox";
  196. switchCheckbox.checked = useModelSwitcher;
  197. switchCheckbox.addEventListener("change", (event) => {
  198. useModelSwitcher = event.target.checked;
  199. localStorage.setItem("useModelSwitcher", useModelSwitcher);
  200. });
  201.  
  202. const switchSlider = document.createElement("span");
  203. switchSlider.className = "slider round";
  204.  
  205. switchLabel.appendChild(switchCheckbox);
  206. switchLabel.appendChild(switchSlider);
  207.  
  208. return switchLabel;
  209. }
  210.  
  211. function createModelSelectElement() {
  212. const selectContainer = document.createElement("div");
  213. selectContainer.style.position = "relative";
  214.  
  215. const select = document.createElement("select");
  216. select.id = "modelSelect";
  217. select.addEventListener("change", (event) => {
  218. selectedModel = event.target.value;
  219. localStorage.setItem("selectedModel", selectedModel);
  220. });
  221.  
  222. for (const model in modelMapping) {
  223. const option = document.createElement("option");
  224. option.text = model;
  225. option.value = model;
  226. select.appendChild(option);
  227. }
  228.  
  229. select.value = selectedModel;
  230.  
  231. const selectArrow = document.createElement("div");
  232. selectArrow.style.cssText = `
  233. position: absolute;
  234. top: 50%;
  235. right: 8px;
  236. transform: translateY(-50%);
  237. width: 12px;
  238. height: 12px;
  239. background-image: url('data:image/svg+xml,%3Csvg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="%23333" width="18px" height="18px"%3E%3Cpath d="M7 10l5 5 5-5z"/%3E%3Cpath d="M0 0h24v24H0z" fill="none"/%3E%3C/svg%3E');
  240. background-repeat: no-repeat;
  241. background-position: center;
  242. pointer-events: none;
  243. `;
  244.  
  245. selectContainer.appendChild(select);
  246. selectContainer.appendChild(selectArrow);
  247.  
  248. return selectContainer;
  249. }
  250.  
  251. function createModelSwitcherContainer() {
  252. const container = document.createElement("div");
  253. container.style.cssText = `
  254. position: fixed;
  255. top: 10px;
  256. right: 18px;
  257. background-color: rgb(32, 33, 35);
  258. border: 1px solid #ddd;
  259. padding: 10px;
  260. border-radius: 5px;
  261. z-index: 9999;
  262. transition: 0.3s;
  263. box-shadow: 0 0 10px rgba(0, 0, 0, 0.2);
  264. display: flex;
  265. align-items: center;
  266. opacity: 0.5;
  267. `;
  268.  
  269. container.addEventListener("mouseenter", () => {
  270. container.style.opacity = "1";
  271. });
  272.  
  273. container.addEventListener("mouseleave", () => {
  274. container.style.opacity = "0.5";
  275. });
  276.  
  277. const switchElement = createSwitchElement();
  278. const modelSelectElement = createModelSelectElement();
  279.  
  280. container.appendChild(switchElement);
  281. container.appendChild(modelSelectElement);
  282.  
  283. return container;
  284. }
  285.  
  286. const container = createModelSwitcherContainer();
  287. document.body.appendChild(container);
  288.  
  289. const style = document.createElement("style");
  290. style.textContent = `
  291. .switch {
  292. position: relative;
  293. display: inline-block;
  294. width: 40px;
  295. height: 20px;
  296. margin-right: 10px;
  297. }
  298.  
  299. .switch input {
  300. opacity: 0;
  301. width: 0;
  302. height: 0;
  303. }
  304.  
  305. .slider {
  306. position: absolute;
  307. cursor: pointer;
  308. top: 0;
  309. left: 0;
  310. right: 0;
  311. bottom: 0;
  312. background-color: #ccc;
  313. transition: .5s;
  314. border-radius: 35px;
  315. }
  316.  
  317. .slider:before {
  318. position: absolute;
  319. content: "";
  320. height: 16px;
  321. width: 16px;
  322. left: 2px;
  323. bottom: 2px;
  324. background-color: white;
  325. transition: .5s;
  326. border-radius: 50%;
  327. }
  328.  
  329. input:checked + .slider {
  330. background-color: #2196F3;
  331. }
  332.  
  333. input:focus + .slider {
  334. box-shadow: 0 0 1px #2196F3;
  335. }
  336.  
  337. input:checked + .slider:before {
  338. transform: translateX(20px);
  339. }
  340.  
  341. .slider.round {
  342. border-radius: 35px;
  343. }
  344.  
  345. .slider.round:before {
  346. border-radius: 50%;
  347. }
  348.  
  349. select {
  350. color: #000000;
  351. background-color: #ffffff;
  352. padding: 5px;
  353. border: none;
  354. border-radius: 5px;
  355. appearance: none;
  356. -webkit-appearance: none;
  357. -moz-appearance: none;
  358. background-image: url('data:image/svg+xml,%3Csvg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="%23333" width="18px" height="18px"%3E%3Cpath d="M7 10l5 5 5-5z"/%3E%3Cpath d="M0 0h24v24H0z" fill="none"/%3E%3C/svg%3E');
  359. background-repeat: no-repeat;
  360. background-position: right center;
  361. padding-right: 20px;
  362. text-overflow: ellipsis;
  363. white-space: nowrap;
  364. overflow: hidden;
  365. }
  366. `;
  367.  
  368. document.head.appendChild(style);
  369. })();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址