Grok Model Patcher

Patches grok.com POST requests to switch between grok-3 and grok-2 models

  1. // ==UserScript==
  2. // @name Grok Model Patcher
  3. // @namespace http://tampermonkey.net/
  4. // @version 1.2
  5. // @description Patches grok.com POST requests to switch between grok-3 and grok-2 models
  6. // @author GrokPatcher
  7. // @match https://grok.com/*
  8. // @grant none
  9. // @license MIT
  10. // ==/UserScript==
  11.  
  12. (function() {
  13. 'use strict';
  14. const generateId = () => Math.random().toString(16).slice(2);
  15. const createMenu = () => {
  16. const menu = document.createElement('div');
  17. menu.id = 'grok-patcher-menu';
  18. menu.style.cssText = `
  19. position: fixed;
  20. top: 10px;
  21. left: 10px;
  22. z-index: 10000;
  23. background: #1f2937;
  24. padding: 10px;
  25. border-radius: 5px;
  26. box-shadow: 0 2px 4px rgba(0,0,0,0.2);
  27. cursor: move;
  28. user-select: none;
  29. `;
  30. menu.innerHTML = `
  31. <div class="mb-2">
  32. <button id="toggle_model" class="bg-blue-600 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded w-full">Using grok-3</button>
  33. </div>
  34. <div id="rate_limit_grok3" class="text-white">grok-3 Rate Limit: N/A</div>
  35. <div id="rate_limit_grok2" class="text-white mt-1">grok-2 Rate Limit: N/A</div>
  36. <a id="donation_link" class="text-white underline text-sm mt-2 inline-block cursor-pointer">Donate</a>
  37. `;
  38. document.body.appendChild(menu);
  39. makeDraggable(menu);
  40. return menu;
  41. };
  42. const makeDraggable = (element) => {
  43. let dragging = false;
  44. let xOffset = 0;
  45. let yOffset = 0;
  46. element.addEventListener('mousedown', (e) => {
  47. dragging = true;
  48. xOffset = e.clientX - parseInt(element.style.left || '10');
  49. yOffset = e.clientY - parseInt(element.style.top || '10');
  50. });
  51. document.addEventListener('mousemove', (e) => {
  52. if (dragging) {
  53. element.style.left = `${e.clientX - xOffset}px`;
  54. element.style.top = `${e.clientY - yOffset}px`;
  55. }
  56. });
  57. document.addEventListener('mouseup', () => {
  58. dragging = false;
  59. });
  60. };
  61. const updateRateLimits = (limits) => {
  62. const grok3Elem = document.getElementById('rate_limit_grok3');
  63. const grok2Elem = document.getElementById('rate_limit_grok2');
  64. grok3Elem.textContent = limits?.['grok-3']
  65. ? `grok-3 Rate Limit: ${limits['grok-3'].remainingQueries}/${limits['grok-3'].totalQueries}`
  66. : 'grok-3 Rate Limit: N/A';
  67. grok2Elem.textContent = limits?.['grok-2']
  68. ? `grok-2 Rate Limit: ${limits['grok-2'].remainingQueries}/${limits['grok-2'].totalQueries}`
  69. : 'grok-2 Rate Limit: N/A';
  70. };
  71. const fetchRateLimits = async () => {
  72. try {
  73. const models = ['grok-3', 'grok-2'];
  74. const limits = {};
  75. for (const model of models) {
  76. const response = await fetch('https://grok.com/rest/rate-limits', {
  77. method: 'POST',
  78. headers: {
  79. 'Content-Type': 'application/json',
  80. 'X-Xai-Request-Id': generateId(),
  81. 'Accept-Language': 'en-US,en;q=0.9',
  82. 'User-Agent': navigator.userAgent,
  83. 'Accept': '*/*',
  84. 'Origin': 'https://grok.com',
  85. 'Sec-Fetch-Site': 'same-origin',
  86. 'Sec-Fetch-Mode': 'cors',
  87. 'Sec-Fetch-Dest': 'empty',
  88. 'Referer': 'https://grok.com/',
  89. 'Accept-Encoding': 'gzip, deflate, br',
  90. 'Priority': 'u=1, i'
  91. },
  92. body: JSON.stringify({ requestKind: 'DEFAULT', modelName: model })
  93. });
  94. if (!response.ok) throw new Error(`Failed to fetch ${model} rate limits`);
  95. limits[model] = await response.json();
  96. }
  97. updateRateLimits(limits);
  98. return limits;
  99. } catch (error) {
  100. updateRateLimits(null);
  101. alert('Failed to fetch rate limits. Please try again later.');
  102. }
  103. };
  104. const startRateLimitRefresh = () => {
  105. fetchRateLimits();
  106. setInterval(fetchRateLimits, 30000);
  107. };
  108. const createPatcher = () => {
  109. const originalFetch = window.fetch;
  110. const originalXhrOpen = XMLHttpRequest.prototype.open;
  111. const originalXhrSend = XMLHttpRequest.prototype.send;
  112. let grok2Active = false;
  113. const isTargetUrl = (url) => {
  114. return (url.includes('/rest/app-chat/conversations/') && url.endsWith('/responses')) ||
  115. url === 'https://grok.com/rest/app-chat/conversations/new';
  116. };
  117. const patchFetch = async (input, init) => {
  118. if (grok2Active && init?.method === 'POST' && typeof input === 'string' && isTargetUrl(input)) {
  119. try {
  120. const payload = JSON.parse(init.body);
  121. payload.modelName = 'grok-2';
  122. init.body = JSON.stringify(payload);
  123. } catch (error) {
  124. alert('Failed to patch fetch request.');
  125. }
  126. }
  127. return originalFetch(input, init);
  128. };
  129. const patchXhrOpen = function(method, url) {
  130. this._url = url;
  131. this._method = method;
  132. return originalXhrOpen.apply(this, arguments);
  133. };
  134. const patchXhrSend = function(body) {
  135. if (grok2Active && this._method === 'POST' && isTargetUrl(this._url)) {
  136. try {
  137. const payload = JSON.parse(body);
  138. payload.modelName = 'grok-2';
  139. body = JSON.stringify(payload);
  140. } catch (error) {
  141. alert('Failed to patch XHR request.');
  142. }
  143. }
  144. return originalXhrSend.call(this, body);
  145. };
  146. return {
  147. enable: async () => {
  148. grok2Active = true;
  149. window.fetch = patchFetch;
  150. XMLHttpRequest.prototype.open = patchXhrOpen;
  151. XMLHttpRequest.prototype.send = patchXhrSend;
  152. await fetchRateLimits();
  153. },
  154. disable: async () => {
  155. grok2Active = false;
  156. window.fetch = originalFetch;
  157. XMLHttpRequest.prototype.open = originalXhrOpen;
  158. XMLHttpRequest.prototype.send = originalXhrSend;
  159. await fetchRateLimits();
  160. },
  161. isActive: () => grok2Active
  162. };
  163. };
  164. const init = () => {
  165. const tailwind = document.createElement('script');
  166. tailwind.src = 'https://cdn.tailwindcss.com';
  167. tailwind.onerror = () => alert('Failed to load TailwindCSS. Some styles may not work.');
  168. document.head.appendChild(tailwind);
  169. const menu = createMenu();
  170. const patcher = createPatcher();
  171. tailwind.onload = () => {
  172. const toggleButton = document.getElementById('toggle_model');
  173. const donationLink = document.getElementById('donation_link');
  174. toggleButton.addEventListener('click', async () => {
  175. try {
  176. if (patcher.isActive()) {
  177. await patcher.disable();
  178. toggleButton.textContent = 'Using grok-3';
  179. toggleButton.classList.replace('bg-red-600', 'bg-blue-600');
  180. toggleButton.classList.replace('hover:bg-red-700', 'hover:bg-blue-700');
  181. } else {
  182. await patcher.enable();
  183. toggleButton.textContent = 'Using grok-2';
  184. toggleButton.classList.replace('bg-blue-600', 'bg-red-600');
  185. toggleButton.classList.replace('hover:bg-blue-700', 'hover:bg-red-700');
  186. }
  187. } catch (error) {
  188. alert('Failed to toggle model. Please try again.');
  189. }
  190. });
  191. donationLink.addEventListener('click', (e) => {
  192. e.preventDefault();
  193. const walletPage = window.open('', '_blank');
  194. walletPage.document.write(`
  195. <!DOCTYPE html>
  196. <html lang="en">
  197. <head>
  198. <meta charset="UTF-8">
  199. <title>Donation Wallets</title>
  200. <style>
  201. body { background: #111827; color: white; padding: 20px; font-family: Arial, sans-serif; }
  202. h1 { font-size: 24px; font-weight: bold; margin-bottom: 10px; }
  203. p { margin-bottom: 10px; }
  204. ul { list-style: disc; padding-left: 20px; }
  205. li { margin-bottom: 8px; }
  206. code { font-family: monospace; }
  207. </style>
  208. </head>
  209. <body>
  210. <h1>Donate to Support Us</h1>
  211. <p>Send donations to these wallet addresses:</p>
  212. <ul>
  213. <li>Bitcoin: <code>bc1q7crku5553xc32fqr4mhugu8jneeuywy4rn5eny</code></li>
  214. <li>Ethereum: <code>0x634F663F87DBC3C2938aA95fC6C0eE53CA1bB6a3</code></li>
  215. <li>Monero: <code>42nARSjJfk3MWXERnZ7on3DDowKVDn6sC3b35XRtSJM1SSpVN34CC7x5jcMeBeacMrEHuDo24kh1HaYq5BPpG1Fo3UeZtAL</code></li>
  216. </ul>
  217. </body>
  218. </html>
  219. `);
  220. walletPage.document.close();
  221. });
  222. startRateLimitRefresh();
  223. };
  224. };
  225. init();
  226. })();

QingJ © 2025

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