您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Displays rate limit for the selected Grok model (Grok 3 or Grok 4)
当前为
// ==UserScript== // @name Grok 4 Rate Limit Display // @namespace http://tampermonkey.net/ // @version 2.3 // @description Displays rate limit for the selected Grok model (Grok 3 or Grok 4) // @author blankspeaker // @match https://grok.com/chat/* // @match https://x.com/i/grok* // @match https://grok.x.ai/chat/* // @grant none // ==/UserScript== (function() { 'use strict'; console.log('Grok Rate Limit Display script loaded v2.3'); let cachedRateLimit = null; let lastFetchTime = 0; const MIN_FETCH_INTERVAL = 5000; // 5 seconds // Debounce function function debounce(func, delay) { let timeout; return function(...args) { clearTimeout(timeout); timeout = setTimeout(() => func(...args), delay); }; } // Function to get the current model function getCurrentModel() { const modelLabel = document.querySelector('.inline-block.text-primary.text-xs'); if (modelLabel) { const labelText = modelLabel.textContent.trim(); console.log('Model label found:', labelText); if (labelText.includes('Grok 3')) { return { displayName: 'Grok 3', modelName: 'grok-3' }; } else if (labelText.includes('Grok 4')) { return { displayName: 'Grok 4', modelName: 'grok-4' }; } else { console.log('Unknown model, defaulting to Grok 3'); return { displayName: 'Grok 3', modelName: 'grok-3' }; } } console.log('Model label not found, defaulting to Grok 3'); return { displayName: 'Grok 3', modelName: 'grok-3' }; } // Function to fetch rate limit with caching and throttling async function fetchRateLimit(modelName) { if (Date.now() - lastFetchTime < MIN_FETCH_INTERVAL) { console.log('Using cached rate limit data due to throttle'); return cachedRateLimit; } try { const response = await fetch('https://grok.com/rest/rate-limits', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ requestKind: 'DEFAULT', modelName: modelName, }), credentials: 'include', }); if (!response.ok) { throw new Error(`HTTP error: ${response.status}`); } const data = await response.json(); console.log('Rate limit data for ' + modelName + ':', data); cachedRateLimit = data; lastFetchTime = Date.now(); return data; } catch (error) { console.error('Failed to fetch rate limit for ' + modelName + ':', error); return null; } } // Function to display or update the rate limit async function displayRateLimit() { console.log('Attempting to display rate limit'); let rateLimitDiv = document.querySelector('#rate-limit-div'); if (!rateLimitDiv) { // Create the div if it doesn't exist rateLimitDiv = document.createElement('div'); rateLimitDiv.id = 'rate-limit-div'; rateLimitDiv.style.position = 'fixed'; rateLimitDiv.style.top = '10px'; rateLimitDiv.style.left = '50%'; rateLimitDiv.style.transform = 'translateX(-50%)'; rateLimitDiv.style.backgroundColor = 'transparent'; rateLimitDiv.style.padding = '0'; rateLimitDiv.style.border = 'none'; rateLimitDiv.style.borderRadius = '0'; rateLimitDiv.style.zIndex = '9999'; rateLimitDiv.style.color = '#666'; // Gray color for visibility on page background rateLimitDiv.style.fontSize = '16px'; rateLimitDiv.textContent = 'Loading rate limit...'; document.body.appendChild(rateLimitDiv); console.log('Rate limit div created'); } const currentModel = getCurrentModel(); const rateLimitData = await fetchRateLimit(currentModel.modelName); if (rateLimitData) { const remaining = rateLimitData.remainingQueries ?? 'Unknown'; const total = rateLimitData.totalQueries ?? 'Unknown'; rateLimitDiv.textContent = `${currentModel.displayName} Queries left: ${remaining} of ${total}`; console.log(`Displayed: ${currentModel.displayName} ${remaining} of ${total}`); } else if (cachedRateLimit) { const remaining = cachedRateLimit.remainingQueries ?? 'Unknown'; const total = cachedRateLimit.totalQueries ?? 'Unknown'; rateLimitDiv.textContent = `${currentModel.displayName} Queries left: ${remaining} of ${total} (cached)`; console.log(`Displayed cached: ${currentModel.displayName} ${remaining} of ${total}`); } else { rateLimitDiv.textContent = `${currentModel.displayName} Queries left: Error fetching data`; } } const debouncedDisplayRateLimit = debounce(displayRateLimit, 1000); // Function to attach submit listeners function attachSubmitListeners() { const maxAttempts = 20; let attempts = 0; const interval = setInterval(() => { const textarea = document.querySelector('textarea'); if (textarea) { textarea.addEventListener('keydown', (e) => { if (e.key === 'Enter' && !e.shiftKey) { console.log('Query submitted via Enter'); setTimeout(debouncedDisplayRateLimit, 2000); // Delay to allow the query to process } }); console.log('Textarea found and listener added'); clearInterval(interval); } else { attempts++; if (attempts >= maxAttempts) { console.log('Textarea not found after max attempts'); clearInterval(interval); } } }, 500); } // Function to init function init() { console.log('Init: displaying rate limit'); displayRateLimit(); attachSubmitListeners(); } // Run initially if (document.readyState === 'complete') { init(); } else { window.addEventListener('load', init); } // Periodically refresh rate limit (every 30 seconds) setInterval(() => { console.log('Periodic refresh'); debouncedDisplayRateLimit(); }, 30000); // MutationObserver to update if model changes const observer = new MutationObserver(() => { console.log('Mutation observed, updating display'); debouncedDisplayRateLimit(); }); observer.observe(document.body, { childList: true, subtree: true, characterData: true }); console.log('MutationObserver started for model changes'); })();