您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Displays rate limits on grok.com
当前为
// ==UserScript== // @name Grok Quota Display // @namespace nisc // @version 2025.06.08-A // @description Displays rate limits on grok.com // @homepageURL https://github.com/nisc/grok-userscripts/ // @author nisc // @match https://grok.com/* // @icon https://grok.com/images/favicon-light.png // @run-at document-end // @grant none // ==/UserScript== (function() { 'use strict'; /** * Configuration object containing all constants used in the script * Organized into logical sections for different aspects of the application */ const CONFIG = { MODEL: { name: 'grok-3' }, REQUEST_TYPES: { DEFAULT: 'Default', REASONING: 'Reason', DEEPSEARCH: 'Deep', DEEPERSEARCH: 'Deeper' }, API: { endpoint: 'https://grok.com/rest/rate-limits', headers: { 'Content-Type': 'application/json', 'Accept-Language': 'en-US,en;q=0.9', 'Accept': '*/*', 'Origin': 'https://grok.com', 'Sec-Fetch-Site': 'same-origin', 'Sec-Fetch-Mode': 'cors', 'Sec-Fetch-Dest': 'empty', 'Referer': 'https://grok.com/', 'Accept-Encoding': 'gzip, deflate, br', 'Priority': 'u=1, i' } }, UI: { styles: ` .grok-rate-limit-wrapper { display: flex; flex-direction: column; gap: 0.25rem; padding: 0.5rem; position: fixed; bottom: 1rem; right: 1rem; z-index: 0.25rem; } .grok-rate-limit-wrapper .grok-menu { display: flex; flex-direction: column; gap: 0.25rem; } .grok-rate-limit-wrapper .grok-column { display: flex; flex-direction: column; gap: 0.25rem; } .grok-rate-limit-wrapper .grok-rate-limit { font-size: 0.75rem; color: inherit; font-family: inherit; line-height: inherit; } `, refreshInterval: 30000 // in milliseconds }, TIME: { SECONDS_PER_HOUR: 3600, SECONDS_PER_DAY: 86400 } }; /** * Utility functions for common operations * - ID generation for API requests * - Element ID formatting * - Time window and value formatting */ const utils = { // Generates a random ID for API request tracking generateId: () => Math.random().toString(16).slice(2), // Creates consistent element IDs for rate limit displays getLimitElementId: type => `rate_limit_${type.toLowerCase()}`, // Formats time windows into days or hours with appropriate units formatTimeWindow: seconds => { if (seconds >= CONFIG.TIME.SECONDS_PER_DAY) { const value = seconds / CONFIG.TIME.SECONDS_PER_DAY; return { value, unit: 'd' }; } const value = seconds / CONFIG.TIME.SECONDS_PER_HOUR; return { value, unit: 'h' }; }, // Formats numeric values, rounding integers and fixing decimals to 1 place formatValue: value => Number.isInteger(value) ? Math.round(value) : value.toFixed(1) }; /** * UI-related functions for creating and updating the display * Handles all DOM manipulation and styling */ const ui = { // Injects custom styles into the document createStyles: () => { const style = document.createElement('style'); style.textContent = CONFIG.UI.styles; document.head.appendChild(style); }, // Creates the rate limit display menu structure createMenu: () => { const wrapper = document.createElement('div'); wrapper.className = 'grok-rate-limit-wrapper'; const menu = document.createElement('div'); menu.id = 'grok-switcher-menu'; menu.className = 'grok-menu'; const column = document.createElement('div'); column.className = 'grok-column'; // Create display elements for each request type Object.entries(CONFIG.REQUEST_TYPES).forEach(([type, displayName]) => { const div = document.createElement('div'); div.id = utils.getLimitElementId(type); div.className = 'grok-rate-limit'; div.textContent = `${displayName}: N/A`; column.appendChild(div); }); menu.appendChild(column); wrapper.appendChild(menu); return wrapper; }, // Updates the display with new rate limit information updateRateLimits: limits => { Object.entries(CONFIG.REQUEST_TYPES).forEach(([type, displayName]) => { const elem = document.getElementById(utils.getLimitElementId(type)); const limit = limits?.[type]; if (limit?.windowSizeSeconds) { const { value, unit } = utils.formatTimeWindow(limit.windowSizeSeconds); const formattedValue = utils.formatValue(value); const display = `${displayName}: <b>${limit.remainingQueries}</b>/${limit.totalQueries} ` + `(${formattedValue}${unit})`; elem.innerHTML = display; } else { elem.textContent = `${displayName}: N/A`; } }); } }; /** * API-related functions for fetching rate limits * Handles all server communication and error handling */ const api = { // Fetches rate limits for all request types in parallel async fetchRateLimits() { try { const limits = {}; // Create an array of promises for parallel execution const requests = Object.keys(CONFIG.REQUEST_TYPES).map(async type => { const headers = { ...CONFIG.API.headers, 'User-Agent': navigator.userAgent, 'X-Xai-Request-Id': utils.generateId() }; const response = await fetch(CONFIG.API.endpoint, { method: 'POST', headers, body: JSON.stringify({ requestKind: type, modelName: CONFIG.MODEL.name }) }); if (!response.ok) { throw new Error(`Failed to fetch ${CONFIG.MODEL.name} ${type} rate limits`); } limits[type] = await response.json(); }); // Wait for all requests to complete await Promise.all(requests); ui.updateRateLimits(limits); } catch (error) { ui.updateRateLimits(null); console.error('Failed to fetch rate limits. Please try again later.'); } } }; /** * Initializes the application: * 1. Creates and injects styles * 2. Creates and adds the display menu * 3. Fetches initial rate limits * 4. Sets up periodic updates */ const init = () => { ui.createStyles(); document.body.appendChild(ui.createMenu()); api.fetchRateLimits(); setInterval(api.fetchRateLimits, CONFIG.UI.refreshInterval); }; // Initialize when DOM is ready if (document.readyState === 'complete' || document.readyState === 'interactive') { init(); } else { document.addEventListener('DOMContentLoaded', init); } })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址