Grok-3 Rate Limits 状态栏

Grok-3 Rate Limits 状态栏,听我说,谢谢你,grok-3

油猴脚本
// ==UserScript==
// @name         Grok Rate Limit Monitor
// @namespace    http://tampermonkey.net/
// @version      0.9
// @description  自动抓取并显示 grok.com 的 rate-limits 请求结果(美化版),支持拖动窗口并定时请求
// @author       [email protected] and [email protected]
// @match        *://grok.com/*
// @grant        GM_setValue
// @grant        GM_getValue
// ==/UserScript==

(function () {
    'use strict';

    // 调试开关
    const DEBUG = true;
    function log(...args) {
        if (DEBUG) console.log('[Rate Limit Monitor]', ...args);
    }

    // 默认位置
    const defaultTop = 20;
    const defaultRight = 20;

    // 存储速率限制数据
    const rateLimits = {
        default: { windowSizeSeconds: '-', remainingQueries: '-', totalQueries: '-' },
        reasoning: { windowSizeSeconds: '-', remainingQueries: '-', totalQueries: '-' },
        deepsearch: { windowSizeSeconds: '-', remainingQueries: '-', totalQueries: '-' },
    };

    // 创建美化后的显示窗口
    function createDisplay() {
        const div = document.createElement('div');
        div.id = 'rate-limit-display';
        let top = GM_getValue('windowTop', defaultTop);
        let right = GM_getValue('windowRight', defaultRight);
        div.style.cssText = `
            position: fixed;
            top: ${top}px;
            right: ${right}px;
            background: linear-gradient(135deg, #fefefe, #f0f4f8);
            border: 1px solid #e0e6ed;
            border-radius: 8px;
            padding: 12px;
            z-index: 10000;
            box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
            font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
            width: 200px;
            transition: all 0.2s ease;
            color: #2d3748;
        `;
        div.innerHTML = `
            <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px; border-bottom: 1px solid #e2e8f0; padding-bottom: 6px;">
                <h3 id="rate-limit-header" style="margin: 0; font-size: 14px; font-weight: 600; color: #1a202c; cursor: move;">
                    Rate Limits
                </h3>
                <button id="refresh-rate-limits" style="
                    background: #4299e1;
                    border: none;
                    border-radius: 4px;
                    color: white;
                    padding: 4px 8px;
                    font-size: 11px;
                    cursor: pointer;
                    transition: background 0.2s;
                ">刷新</button>
            </div>
            <div style="margin-bottom: 8px;">
                <h4 style="margin: 0 0 4px 0; font-size: 12px; font-weight: 500; color: #4a5568;">Default</h4>
                <p style="margin: 2px 0; font-size: 11px; color: #718096;">
                    Window: <span id="window-size-default" style="color: #2b6cb0; font-weight: 500;">-</span> 秒
                </p>
                <p style="margin: 2px 0; font-size: 11px; color: #718096;">
                    Available: <span id="queries-default" style="color: #2f855a; font-weight: 500;">-/-</span>
                </p>
            </div>
            <div style="margin-bottom: 8px;">
                <h4 style="margin: 0 0 4px 0; font-size: 12px; font-weight: 500; color: #4a5568;">Reasoning</h4>
                <p style="margin: 2px 0; font-size: 11px; color: #718096;">
                    Window: <span id="window-size-reasoning" style="color: #2b6cb0; font-weight: 500;">-</span> 秒
                </p>
                <p style="margin: 2px 0; font-size: 11px; color: #718096;">
                    Available: <span id="queries-reasoning" style="color: #2f855a; font-weight: 500;">-/-</span>
                </p>
            </div>
            <div>
                <h4 style="margin: 0 0 4px 0; font-size: 12px; font-weight: 500; color: #4a5568;">Deepsearch</h4>
                <p style="margin: 2px 0; font-size: 11px; color: #718096;">
                    Window: <span id="window-size-deepsearch" style="color: #2b6cb0; font-weight: 500;">-</span> 秒
                </p>
                <p style="margin: 2px 0; font-size: 11px; color: #718096;">
                    Available: <span id="queries-deepsearch" style="color: #2f855a; font-weight: 500;">-/-</span>
                </p>
            </div>
        `;
        document.body.appendChild(div);

        // 添加鼠标悬停效果
        div.addEventListener('mouseenter', () => {
            div.style.boxShadow = '0 6px 16px rgba(0, 0, 0, 0.15)';
            div.style.transform = 'scale(1.02)';
        });
        div.addEventListener('mouseleave', () => {
            div.style.boxShadow = '0 4px 12px rgba(0, 0, 0, 0.1)';
            div.style.transform = 'scale(1)';
        });

        // 添加刷新按钮效果和点击事件
        const refreshButton = document.getElementById('refresh-rate-limits');
        refreshButton.addEventListener('mouseenter', () => {
            refreshButton.style.background = '#3182ce';
        });
        refreshButton.addEventListener('mouseleave', () => {
            refreshButton.style.background = '#4299e1';
        });
        refreshButton.addEventListener('click', () => {
            refreshButton.style.background = '#2c5282';
            fetchRateLimits('DEFAULT');
            fetchRateLimits('REASONING');
            fetchRateLimits('DEEPSEARCH');
            setTimeout(() => {
                refreshButton.style.background = '#4299e1';
            }, 200);
        });

        // 添加拖动功能
        const header = document.getElementById('rate-limit-header');
        header.addEventListener('mousedown', startDragging);
    }

    // 拖动功能
    function startDragging(e) {
        e.preventDefault();
        const div = document.getElementById('rate-limit-display');
        const initialMouseX = e.clientX;
        const initialMouseY = e.clientY;
        const initialTop = parseInt(div.style.top, 10);
        const initialRight = parseInt(div.style.right, 10);

        function onMouseMove(e) {
            const deltaX = e.clientX - initialMouseX;
            const deltaY = e.clientY - initialMouseY;
            div.style.top = (initialTop + deltaY) + 'px';
            div.style.right = (initialRight - deltaX) + 'px';
        }

        document.addEventListener('mousemove', onMouseMove);
        document.addEventListener('mouseup', function onMouseUp() {
            document.removeEventListener('mousemove', onMouseMove);
            document.removeEventListener('mouseup', onMouseUp);
            const newTop = parseInt(div.style.top, 10);
            const newRight = parseInt(div.style.right, 10);
            GM_setValue('windowTop', newTop);
            GM_setValue('windowRight', newRight);
        });
    }

    // 更新显示内容
    function updateDisplay() {
        document.getElementById('window-size-default').textContent = rateLimits.default.windowSizeSeconds;
        document.getElementById('queries-default').textContent = `${rateLimits.default.remainingQueries}/${rateLimits.default.totalQueries}`;
        document.getElementById('window-size-reasoning').textContent = rateLimits.reasoning.windowSizeSeconds;
        document.getElementById('queries-reasoning').textContent = `${rateLimits.reasoning.remainingQueries}/${rateLimits.reasoning.totalQueries}`;
        document.getElementById('window-size-deepsearch').textContent = rateLimits.deepsearch.windowSizeSeconds;
        document.getElementById('queries-deepsearch').textContent = `${rateLimits.deepsearch.remainingQueries}/${rateLimits.deepsearch.totalQueries}`;
    }

    // 发起 rate-limits 请求
    function fetchRateLimits(kind) {
        log(`Fetching rate limits for ${kind}...`);
        fetch('https://grok.com/rest/rate-limits', {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
                'Cache-Control': 'no-cache',
            },
            body: JSON.stringify({ requestKind: kind, modelName: 'grok-3' }),
        })
            .then(response => {
                log(`Rate limits response status for ${kind}:`, response.status);
                return response.json();
            })
            .then(data => {
                const lowerKind = kind.toLowerCase();
                log(`Rate limits data for ${kind}:`, data);
                rateLimits[lowerKind] = {
                    windowSizeSeconds: data.windowSizeSeconds ?? '-',
                    remainingQueries: data.remainingQueries ?? '-',
                    totalQueries: data.totalQueries ?? '-',
                };
                log(`Updated Rate Limit for ${lowerKind}:`, rateLimits[lowerKind]);
                updateDisplay();
            })
            .catch(error => {
                console.error(`Failed to fetch ${kind} rate-limits:`, error);
                log(`Error details for ${kind}:`, error);
            });
    }

    // 定时请求逻辑
    let intervalId;
    function startPolling() {
        const poll = () => {
            log('Polling rate limits...');
            fetchRateLimits('DEFAULT');
            fetchRateLimits('REASONING');
            fetchRateLimits('DEEPSEARCH');
        };
        poll(); // 立即执行一次
        intervalId = setInterval(poll, 10 * 60 * 1000); // 每10分钟执行一次
    }

    function resetPolling() {
        log('Resetting polling interval...');
        clearInterval(intervalId);
        setTimeout(startPolling, 10 * 60 * 1000); // 延迟10分钟后重新开始
    }

    // 处理 rate-limit 响应的通用函数
    async function handleRateLimitResponse(resource, options, response) {
        log('Handling potential rate limit response:', { resource, options });

        let requestKind = 'default';
        try {
            const body = typeof options.body === 'string' ? JSON.parse(options.body) :
                options.body instanceof Blob ? JSON.parse(await options.body.text()) : null;
            log('Parsed request body:', body);
            requestKind = body?.requestKind?.toLowerCase() || 'default';
        } catch (e) {
            log('Failed to parse rate-limit request body:', e);
            return;
        }

        try {
            const data = typeof response === 'string' ? JSON.parse(response) : await response.json();
            log('Parsed response data:', data);

            if (rateLimits.hasOwnProperty(requestKind)) {
                rateLimits[requestKind] = {
                    windowSizeSeconds: data.windowSizeSeconds ?? '-',
                    remainingQueries: data.remainingQueries ?? '-',
                    totalQueries: data.totalQueries ?? '-',
                };
                log(`Updated Rate Limit for ${requestKind}:`, rateLimits[requestKind]);
                updateDisplay();
                resetPolling();
            }
        } catch (e) {
            log('Failed to parse rate-limit response:', e);
        }
    }

    // 重写 fetch
    const originalFetch = window.fetch;
    window.fetch = async function (resource, options = {}) {
        log('Intercepted fetch request:', { resource, options });
        const response = await originalFetch(resource, options);
        if (typeof resource === 'string' && resource.includes('/rate-limits')) {
            log('Matched rate-limits fetch request');
            const clonedResponse = response.clone();
            handleRateLimitResponse(resource, options, clonedResponse);
        }
        return response;
    };

    // 重写 XMLHttpRequest
    const originalOpen = XMLHttpRequest.prototype.open;
    const originalSend = XMLHttpRequest.prototype.send;
    XMLHttpRequest.prototype.open = function (method, url) {
        this._url = url;
        this._method = method;
        originalOpen.apply(this, arguments);
    };
    XMLHttpRequest.prototype.send = function (body) {
        if (typeof this._url === 'string' && this._url.includes('/rate-limits')) {
            log('Intercepted rate-limits XHR request:', { url: this._url, method: this._method, body });
            this.addEventListener('load', () => {
                handleRateLimitResponse(this._url, { method: this._method, body }, this.responseText);
            });
        }
        originalSend.apply(this, arguments);
    };

    // 初始化显示窗口并启动定时请求
    createDisplay();
    startPolling();

    // 提示脚本已加载
    log('Script loaded with enhanced rate-limit capturing and refresh button.');
})();


拿 claude-3-7-sonnet 重写了下,thinking 模式真的强,审美也在线,新版本真香:

claude-3-7-sonnet 新版本(增加拖拽位置记忆)
// ==UserScript==
// @name         Rate Limits Monitor
// @namespace    http://tampermonkey.net/
// @version      1.0
// @description  Monitor conversation limits for default, deepsearch, and reason modes
// @author       [email protected] & claude-3-7-sonnet-thinking
// @match        https://grok.com/*
// @grant        none
// ==/UserScript==

(function() {
    'use strict';

    // Configuration
    const UPDATE_INTERVAL = 60000*10; // Update every 10 minutes
    const MODES = [
        { name: 'DEFAULT', displayName: 'Default', color: '#4CAF50', valueColor: '#7CFF7C' },
        { name: 'DEEPSEARCH', displayName: 'Deep Search', color: '#2196F3', valueColor: '#7CD5FF' },
        { name: 'REASONING', displayName: 'Reason', color: '#FF9800', valueColor: '#FFC57C' }
    ];

    let timers = {}; // Store timers for each mode
    let lastFetchTime = {}; // Track last fetch time for each mode
    let windowSizes = {}; // Store window sizes for each mode

    // Create monitor UI
    function createMonitorUI() {
        const monitorDiv = document.createElement('div');
        monitorDiv.id = 'limit-monitor';
        monitorDiv.style.cssText = `
            position: fixed;
            bottom: 20px;
            right: 20px;
            background-color: rgba(28, 30, 33, 0.92);
            border-radius: 10px;
            padding: 12px;
            color: #e0e0e0;
            font-family: 'Segoe UI', Arial, sans-serif;
            font-size: 14px;
            z-index: 10000;
            box-shadow: 0 3px 12px rgba(0, 0, 0, 0.4);
            min-width: 220px;
            user-select: none;
            border: 1px solid rgba(255, 255, 255, 0.1);
        `;

        // Create title bar with drag handle
        const titleBar = document.createElement('div');
        titleBar.style.cssText = `
            cursor: move;
            padding-bottom: 8px;
            margin-bottom: 8px;
            border-bottom: 1px solid rgba(255, 255, 255, 0.15);
            display: flex;
            justify-content: space-between;
            align-items: center;
        `;
        titleBar.innerHTML = '<span style="font-weight: bold; font-size: 15px;">Rate Limits Status</span>';

        // Add refresh button
        const refreshBtn = document.createElement('button');
        refreshBtn.textContent = '↻';
        refreshBtn.title = "Refresh all limits";
        refreshBtn.style.cssText = `
            background: rgba(255, 255, 255, 0.1);
            border: none;
            border-radius: 4px;
            color: white;
            cursor: pointer;
            font-size: 16px;
            padding: 2px 8px;
            transition: background 0.2s ease;
        `;
        refreshBtn.onmouseover = () => {
            refreshBtn.style.background = 'rgba(255, 255, 255, 0.2)';
        };
        refreshBtn.onmouseout = () => {
            refreshBtn.style.background = 'rgba(255, 255, 255, 0.1)';
        };
        refreshBtn.onclick = refreshAllLimits;
        titleBar.appendChild(refreshBtn);

        monitorDiv.appendChild(titleBar);

        // Create container for the mode data
        const modesContainer = document.createElement('div');
        modesContainer.id = 'modes-container';

        // Create elements for each mode
        MODES.forEach(mode => {
            const modeDiv = document.createElement('div');
            modeDiv.style.cssText = `
                margin-bottom: 8px;
                display: flex;
                justify-content: space-between;
                align-items: center;
            `;

            const modeLabel = document.createElement('span');
            modeLabel.textContent = mode.displayName + ':';
            modeLabel.style.cssText = `
                font-weight: bold;
                color: ${mode.color};
            `;

            const modeValue = document.createElement('span');
            modeValue.id = `${mode.name.toLowerCase()}-limit`;
            modeValue.textContent = '?/?';
            modeValue.style.cssText = `
                font-weight: bold;
                color: ${mode.valueColor};
                transition: color 0.3s ease;
            `;

            modeDiv.appendChild(modeLabel);
            modeDiv.appendChild(modeValue);
            modesContainer.appendChild(modeDiv);
        });

        monitorDiv.appendChild(modesContainer);
        document.body.appendChild(monitorDiv);

        // Make the monitor draggable
        makeDraggable(monitorDiv, titleBar);

        return monitorDiv;
    }

    // Format seconds to a readable time string
    function formatTime(seconds) {
        if (seconds < 60) {
            return `${seconds}s`;
        } else if (seconds < 3600) {
            return `${Math.floor(seconds / 60)}m`;
        } else {
            const hours = Math.floor(seconds / 3600);
            const minutes = Math.floor((seconds % 3600) / 60);
            return minutes > 0 ? `${hours}h ${minutes}m` : `${hours}h`;
        }
    }

   // Make an element draggable and save position to localStorage
    function makeDraggable(element, handle) {
        let pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0;

        // Load saved position from localStorage if exists
        const savedPosition = JSON.parse(localStorage.getItem('grok-limitMonitorPosition'));
        if (savedPosition) {
            element.style.top = savedPosition.top;
            element.style.left = savedPosition.left;
            element.style.right = 'auto';
            element.style.bottom = 'auto';
        }

        handle.onmousedown = dragMouseDown;

        function dragMouseDown(e) {
            e.preventDefault();
            pos3 = e.clientX;
            pos4 = e.clientY;
            document.onmouseup = closeDragElement;
            document.onmousemove = elementDrag;
        }

        function elementDrag(e) {
            e.preventDefault();
            pos1 = pos3 - e.clientX;
            pos2 = pos4 - e.clientY;
            pos3 = e.clientX;
            pos4 = e.clientY;
            element.style.top = (element.offsetTop - pos2) + "px";
            element.style.left = (element.offsetLeft - pos1) + "px";
            element.style.right = 'auto';
            element.style.bottom = 'auto';
        }

        function closeDragElement() {
            document.onmouseup = null;
            document.onmousemove = null;

            // Save new position to localStorage
            const position = {
                top: element.style.top,
                left: element.style.left
            };
            localStorage.setItem('grok-limitMonitorPosition', JSON.stringify(position));
        }
    }


    // Fetch rate limits for a specific mode
    async function fetchRateLimit(mode) {
        try {
            const response = await fetch('https://grok.com/rest/rate-limits', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json'
                },
                body: JSON.stringify({
                    requestKind: mode,
                    modelName: 'grok-3'
                })
            });

            if (!response.ok) {
                throw new Error(`HTTP error! status: ${response.status}`);
            }

            const data = await response.json();
            lastFetchTime[mode] = Date.now();

            // Store window size
            if (data.windowSizeSeconds) {
                windowSizes[mode] = data.windowSizeSeconds;
            }

            updateLimitDisplay(mode, data);

            return data;
        } catch (error) {
            console.error(`Error fetching rate limits for ${mode}:`, error);
            document.getElementById(`${mode.toLowerCase()}-limit`).textContent = 'Error';
        }
    }

    // Update the display for a specific mode
    function updateLimitDisplay(mode, data) {
        const element = document.getElementById(`${mode.toLowerCase()}-limit`);
        if (element && data) {
            if (data.waitTimeSeconds !== undefined) {
              // 如果存在 waitTimeSeconds,只显示等候时间
              element.textContent = formatTime(data.waitTimeSeconds);
          } else {
              // 否则显示原来的 remaining/total 格式加上时间窗口
              const timeWindow = data.windowSizeSeconds ? ` (${formatTime(data.windowSizeSeconds)})` : '';
              element.textContent = `${data.remainingQueries}/${data.totalQueries}${timeWindow}`;
           }

            // Find the corresponding mode configuration
            const modeConfig = MODES.find(m => m.name === mode);

            // Visual feedback that data was updated
            element.style.color = '#4df94d';
            setTimeout(() => {
                // Return to the mode's value color
                if (modeConfig) {
                    element.style.color = modeConfig.valueColor;
                }
            }, 500);
        }
    }

    // Refresh all limits
    function refreshAllLimits() {
        MODES.forEach(mode => {
            fetchRateLimit(mode.name);
        });
    }

    // Schedule regular updates
    function scheduleUpdates() {
        MODES.forEach(mode => {
            // Clear any existing timer
            if (timers[mode.name]) {
                clearInterval(timers[mode.name]);
            }

            // Set new timer
            timers[mode.name] = setInterval(() => {
                fetchRateLimit(mode.name);
            }, UPDATE_INTERVAL);
        });
    }

    // Intercept fetch to monitor rate-limit requests from the website
    function interceptFetch() {
        const originalFetch = window.fetch;

        window.fetch = async function(input, init) {
            const response = await originalFetch(input, init);

            // Clone the response to avoid consuming it
            const responseClone = response.clone();

            try {
                // Check if this is a rate-limits request
                if (input && input.toString().includes('rate-limits')) {
                    responseClone.json().then(data => {
                        // Try to determine which mode this request was for
                        if (init && init.body) {
                            try {
                                const body = JSON.parse(init.body);
                                if (body.requestKind) {
                                    const mode = body.requestKind;

                                    // Store window size if available
                                    if (data.windowSizeSeconds) {
                                        windowSizes[mode] = data.windowSizeSeconds;
                                    }

                                    // Update the display
                                    updateLimitDisplay(mode, data);

                                    // Update last fetch time
                                    lastFetchTime[mode] = Date.now();

                                    // Reset the timer for this mode
                                    if (timers[mode]) {
                                        clearInterval(timers[mode]);
                                        timers[mode] = setInterval(() => {
                                            fetchRateLimit(mode);
                                        }, UPDATE_INTERVAL);
                                    }
                                }
                            } catch (e) {
                                console.error('Error parsing request body:', e);
                            }
                        }
                    }).catch(e => {
                        console.error('Error parsing response:', e);
                    });
                }
            } catch (e) {
                console.error('Error in fetch interceptor:', e);
            }

            return response;
        };
    }

    // Initialize
    function init() {
        // Create UI
        createMonitorUI();

        // Fetch initial data
        refreshAllLimits();

        // Schedule updates
        scheduleUpdates();

        // Intercept fetch requests
        interceptFetch();
    }

    // Start the script when the page is fully loaded
    window.addEventListener('load', init);
})();


评论区佬友的升级版,更优雅更酷了


补充,如果有发生图标会消失的情况,可以使用这位佬友的版本:

93 Likes

谢谢佬友分享

3 Likes

感谢分享

3 Likes

感谢分享

3 Likes

感谢分享

3 Likes

太强了,立刻使用!

2 Likes


这个位置不能动吗?刚好挡住右上角

3 Likes

鼠标移动到 Rate Limits 那里可以拖动

4 Likes

感谢分享

2 Likes

感谢感谢

2 Likes

厉害的佬:tieba_013:

2 Likes

感觉我写的外观更好看

5 Likes

确实不错

2 Likes

感谢大佬

2 Likes

grok-3 前端审美有待提高 :laughing:

2 Likes

我的咋开启不了呢

2 Likes

这是油猴没启动吧,你看我这里是打勾的

2 Likes

还是不行

2 Likes

可以了;谢佬

1 Like

谢谢分享,很配grok的黑科技风tieba_013,另外能适配xAI

1 Like