### GET /v1/models Source: https://github.com/chenyme/grok2api/blob/main/docs/README.en.md Example of how to list available models using curl. ```bash curl http://localhost:8000/v1/models \ -H "Authorization: Bearer $GROK2API_API_KEY" ``` -------------------------------- ### POST /v1/videos Source: https://github.com/chenyme/grok2api/blob/main/docs/README.en.md Example cURL commands for creating and retrieving videos. ```bash curl http://localhost:8000/v1/videos \ -H "Authorization: Bearer $GROK2API_API_KEY" \ -F "model=grok-imagine-video" \ -F "prompt=A neon rainy street at night, cinematic slow tracking shot" \ -F "seconds=10" \ -F "size=1792x1024" \ -F "resolution_name=720p" \ -F "preset=normal" \ -F "input_reference[]=@/path/to/reference.png" ``` ```bash curl http://localhost:8000/v1/videos/ \ -H "Authorization: Bearer $GROK2API_API_KEY" ``` ```bash curl -L http://localhost:8000/v1/videos//content \ -H "Authorization: Bearer $GROK2API_API_KEY" \ -o result.mp4 ``` -------------------------------- ### POST /v1/chat/completions - Chat Source: https://github.com/chenyme/grok2api/blob/main/README.md Example of a chat completion request. ```bash curl http://localhost:8000/v1/chat/completions \ -H "Content-Type: application/json" \ -H "Authorization: Bearer $GROK2API_API_KEY" \ -d '{ "model": "grok-4.20-auto", "stream": true, "reasoning_effort": "high", "messages": [ {"role":"user","content":"你好"} ] }' ``` -------------------------------- ### POST /v1/responses Source: https://github.com/chenyme/grok2api/blob/main/README.md Example of a request to the Responses API. ```bash curl http://localhost:8000/v1/responses \ -H "Content-Type: application/json" \ -H "Authorization: Bearer $GROK2API_API_KEY" \ -d '{ "model": "grok-4.20-auto", "input": "解释一下量子隧穿", "instructions": "用简洁的中文回答", "stream": true, "reasoning": { "effort": "high" } }' ``` -------------------------------- ### POST /v1/chat/completions - Video Source: https://github.com/chenyme/grok2api/blob/main/docs/README.en.md Example of how to use the chat completions endpoint for video generation. ```bash curl http://localhost:8000/v1/chat/completions \ -H "Content-Type: application/json" \ -H "Authorization: Bearer $GROK2API_API_KEY" \ -d '{ "model": "grok-imagine-video", "stream": true, "messages": [ {"role":"user","content":"A neon rainy street at night, cinematic slow tracking shot"} ], "video_config": { "seconds": 10, "size": "1792x1024", "resolution_name": "720p", "preset": "normal" } }' ``` -------------------------------- ### POST /v1/images/generations Source: https://github.com/chenyme/grok2api/blob/main/README.md Example of a direct image generation request. ```bash curl http://localhost:8000/v1/images/generations \ -H "Content-Type: application/json" \ -H "Authorization: Bearer $GROK2API_API_KEY" \ -d '{ "model": "grok-imagine-image", "prompt": "一只在太空漂浮的猫", "n": 1, "size": "1792x1024", "response_format": "url" }' ``` -------------------------------- ### POST /v1/messages Source: https://github.com/chenyme/grok2api/blob/main/README.md Example of a request to the Messages API. ```bash curl http://localhost:8000/v1/messages \ -H "Content-Type: application/json" \ -H "Authorization: Bearer $GROK2API_API_KEY" \ -d '{ "model": "grok-4.20-auto", "stream": true, "thinking": { "type": "enabled", "budget_tokens": 1024 }, "messages": [ { "role": "user", "content": "用三句话解释量子隧穿" } ] }' ``` -------------------------------- ### POST /v1/images/generations Source: https://github.com/chenyme/grok2api/blob/main/docs/README.en.md Example cURL command for generating images. ```bash curl http://localhost:8000/v1/images/generations \ -H "Content-Type: application/json" \ -H "Authorization: Bearer $GROK2API_API_KEY" \ -d '{ "model": "grok-imagine-image", "prompt": "A cat floating in space", "n": 1, "size": "1792x1024", "response_format": "url" }' ``` -------------------------------- ### POST /v1/chat/completions - Video Source: https://github.com/chenyme/grok2api/blob/main/README.md Example of a video generation request within chat completions. ```bash curl http://localhost:8000/v1/chat/completions \ -H "Content-Type: application/json" \ -H "Authorization: Bearer $GROK2API_API_KEY" \ -d '{ "model": "grok-imagine-video", "stream": true, "messages": [ {"role":"user","content":"霓虹雨夜街头,电影感慢镜头追拍"} ], "video_config": { "seconds": 10, "size": "1792x1024", "resolution_name": "720p", "preset": "normal" } }' ``` -------------------------------- ### POST /v1/chat/completions - Image Source: https://github.com/chenyme/grok2api/blob/main/docs/README.en.md Example of how to use the chat completions endpoint for image generation. ```bash curl http://localhost:8000/v1/chat/completions \ -H "Content-Type: application/json" \ -H "Authorization: Bearer $GROK2API_API_KEY" \ -d '{ "model": "grok-imagine-image", "stream": true, "messages": [ {"role":"user","content":"A cat floating in space"} ], "image_config": { "n": 2, "size": "1024x1024", "response_format": "url" } }' ``` -------------------------------- ### POST /v1/images/edits Source: https://github.com/chenyme/grok2api/blob/main/docs/README.en.md Example cURL command for editing images. ```bash curl http://localhost:8000/v1/images/edits \ -H "Authorization: Bearer $GROK2API_API_KEY" \ -F "model=grok-imagine-image-edit" \ -F "prompt=Make this image sharper" \ -F "image[]=@/path/to/image.png" \ -F "n=1" \ -F "size=1024x1024" \ -F "response_format=url" ``` -------------------------------- ### POST /v1/responses Source: https://github.com/chenyme/grok2api/blob/main/docs/README.en.md Example of how to use the responses endpoint for generating text responses. ```bash curl http://localhost:8000/v1/responses \ -H "Content-Type: application/json" \ -H "Authorization: Bearer $GROK2API_API_KEY" \ -d '{ "model": "grok-4.20-auto", "input": "Explain quantum tunneling", "instructions": "Keep the answer concise.", "stream": true, "reasoning": { "effort": "high" } }' ``` -------------------------------- ### Schema Definition Example Source: https://github.com/chenyme/grok2api/blob/main/app/statics/admin/config.html A JavaScript constant defining the schema structure for application configuration, including system and feature settings. ```javascript const SCHEMA_DEF = [ { id: 'system', label: '系统配置', labelKey: 'config.schema.tabs.system', groups: [ { title: '基础访问控制', titleKey: 'config.schema.groups.baseAccess', section: 'app', fields: [ { key: 'app_url', label: 'APP 访问地址', labelKey: 'config.schema.fields.appUrl.label', type: 'text', desc: '应用对外提供服务的根 URL,格式如 https://your-domain.com。本地代理模式必须配置。', descKey: 'config.schema.fields.appUrl.desc', wide: true }, { key: 'app_key', label: 'APP 访问密码', labelKey: 'config.schema.fields.appKey.label', type: 'password', desc: '管理后台鉴权密码。修改后已有 Session 将立即失效,需重新登录。', descKey: 'config.schema.fields.appKey.desc', rand: true }, { key: 'api_key', label: 'API 调用密钥', labelKey: 'config.schema.fields.apiKey.label', type: 'text', desc: 'OpenAI 兼容 API 的鉴权密钥。多个值请使用英文逗号分隔;留空则禁用鉴权。', descKey: 'config.schema.fields.apiKey.desc', rand: true }, { key: 'webui_enabled', label: '启用 WebUI', labelKey: 'config.schema.fields.webuiEnabled.label', type: 'bool', desc: '开放 WebUI 功能入口。关闭后相关路由将返回 404。', descKey: 'config.schema.fields.webuiEnabled.desc' }, { key: 'webui_key', label: 'WebUI 访问密码', labelKey: 'config.schema.fields.webuiKey.label', type: 'password', desc: 'WebUI 的访问鉴权密码。配置后访问时必须提供。', descKey: 'config.schema.fields.webuiKey.desc', rand: true, showIf: 'app.webui_enabled' } ] }, { title: '日志配置', titleKey: 'config.schema.groups.logging', section: 'logging', fields: [ { key: 'file_level', label: '文件日志等级', labelKey: 'config.schema.fields.fileLogLevel.label', type: 'select', options: [ { value: 'DEBUG', label: 'DEBUG' }, { value: 'INFO', label: 'INFO' }, { value: 'WARNING', label: 'WARNING' }, { value: 'ERROR', label: 'ERROR' } ], desc: '日志文件写入的最低等级,可独立于控制台配置。默认 INFO。', descKey: 'config.schema.fields.fileLogLevel.desc' }, { key: 'max_files', label: '日志保留天数', labelKey: 'config.schema.fields.logMaxFiles.label', type: 'number', desc: '按天轮转时最多保留的日志文件数量。默认 7。', descKey: 'config.schema.fields.logMaxFiles.desc' } ] } ] }, { id: 'features', label: '应用功能', labelKey: 'config.schema.tabs.features', groups: [ { title: '基本功能设置', titleKey: 'config.schema.groups.features', section: 'features', fields: [ { key: 'temporary', label: '临时会话', labelKey: 'config.schema.fields.temporary.label', type: 'bool', desc: '启用后请求不会写入 Grok 会话历史,等同于无痕对话。', descKey: 'config.schema.fields.temporary.desc' }, { key: 'memory', label: '开启会话记忆', labelKey: 'config.schema.fields.memory.label', type: 'bool', desc: '启用 Grok Memory,允许模型跨会话记忆用户偏好与上下文。', descKey: 'config.schema.fields.memory.desc' }, { key: 'stream', label: '默认流式输出', labelKey: 'config.schema.fields.stream.label', type: 'bool', desc: '请求未显式指定 stream 参数时所采用的默认值。', descKey: 'config.schema.fields.stream.desc' }, { key: 'thinking', label: '默认思考输出', labelKey: 'config.schema.fields.thinking.label', type: 'bool', desc: '请求未显式指定 thinking 参数时所采用的默认值。启用后将在 reasoning_content 字段返回思考过程。', descKey: 'config.schema.fields.thinking.desc' }, { key: 'auto_chat_mode_fallback', label: 'AUTO 聊天模式回退', labelKey: 'config.schema.fields.autoChatModeFallback.label', type: 'bool', desc: 'AUTO 聊天模型在 auto 额度不可用时,自动尝试 fast 和 expert 聊天额度窗口。', descKey: 'config.schema.fields.autoChatModeFallback.desc' }, { key: 'thinking_summary', label: '思考精简输出', labelKey: 'config.schema.fields.thinkingSummary.label', type: 'bool', desc: '启用后将思考过程提炼为结构化摘要。关闭时输出完整的原始推理过程,支持多 Agent 模型的协作详情与工具调用展示。', descKey: 'config.schema.fields.thinkingSummary.desc' }, { key: 'dynamic_statsig', label: '动态 Statsig', labelKey: 'config.schema.fields.dynamicStatsig.label', type: 'bool', desc: '为每次请求动态生成 Statsig 设备指纹,以降低风控拦截概率。', descKey: 'config.schema.fields.dynamicStatsig.desc' }, { key: 'enable_nsfw', label: '允许 NSFW 生成', labelKey: 'config.schema.fields.enableNsfw.label', type: 'bool', desc: '允许图像生成接口绕过 NSFW 内容过滤。', descKey: 'config.schema.fields.enableNsfw.desc' }, { key: 'show_search_sources', label: '正文追加信源', labelKey: 'config.schema.fields.showSearchSources.label', type: 'bool', desc: '搜索信源始终以 search_sources 字段输出。此选项控制是否同时在正文末尾追加 ## Sources 段落(兼容文本解析客户端)。', descKey: 'config.schema.fields.showSearchSources.desc' }, { key: 'custom_instruction', label: '全局附加指令', labelKey: 'config.schema.fields.customInstruction.label', type: 'textarea', desc: '为每次请求注入统一的 system 消息,用于约束模型行为或固定角色设定。', descKey: 'config.schema.fields.customInstruction.desc' } ] }, { title: '媒体返回格式', titleKey: 'config.schema.groups.mediaFormat', section: 'features', fields: [ { key: 'image_format', label: '图片返回格式', labelKey: 'config.schema.fields.imageFormat.label', type: 'select', options: [ { value: 'grok_url', label: 'URL(Grok 原生)', labelKey: 'config.schema.options.imageFormat.grokUrl' }, { value: 'local_url', label: 'URL(本地代理)', labelKey: 'config.schema.options.imageFormat.localUrl', disabledWhen: 'no_app_url', disabledTip: '请先' ] } ] } ] } ]; ``` -------------------------------- ### POST /v1/chat/completions - Chat Source: https://github.com/chenyme/grok2api/blob/main/docs/README.en.md Example of how to use the chat completions endpoint for text-based chat. ```bash curl http://localhost:8000/v1/chat/completions \ -H "Content-Type: application/json" \ -H "Authorization: Bearer $GROK2API_API_KEY" \ -d '{ "model": "grok-4.20-auto", "stream": true, "reasoning_effort": "high", "messages": [ {"role":"user","content":"Hello"} ] }' ``` -------------------------------- ### POST /v1/chat/completions - Image Source: https://github.com/chenyme/grok2api/blob/main/README.md Example of an image generation request within chat completions. ```bash curl http://localhost:8000/v1/chat/completions \ -H "Content-Type: application/json" \ -H "Authorization: Bearer $GROK2API_API_KEY" \ -d '{ "model": "grok-imagine-image", "stream": true, "messages": [ {"role":"user","content":"一只在太空漂浮的猫"} ], "image_config": { "n": 2, "size": "1024x1024", "response_format": "url" } }' ``` -------------------------------- ### POST /v1/messages Source: https://github.com/chenyme/grok2api/blob/main/docs/README.en.md Example of how to use the messages endpoint for generating responses with reasoning. ```bash curl http://localhost:8000/v1/messages \ -H "Content-Type: application/json" \ -H "Authorization: Bearer $GROK2API_API_KEY" \ -d '{ "model": "grok-4.20-auto", "stream": true, "thinking": { "type": "enabled", "budget_tokens": 1024 }, "messages": [ { "role": "user", "content": "Explain quantum tunneling in three sentences" } ] }' ``` -------------------------------- ### Local Deployment Source: https://github.com/chenyme/grok2api/blob/main/docs/README.en.md Steps to clone the repository, set up the environment, and run the application locally using uv. ```bash git clone https://github.com/chenyme/grok2api cd grok2api cp .env.example .env uv sync uv run granian --interface asgi --host 0.0.0.0 --port 8000 --workers 1 app.main:app ``` -------------------------------- ### Boot Configuration Page Source: https://github.com/chenyme/grok2api/blob/main/app/statics/admin/config.html Initializes the configuration page by building the schema, applying internationalization, rendering headers and footers, verifying the admin key, loading the configuration, and refreshing the dirty state. ```javascript (async () => { try { SCHEMA = buildSchema(); waitI18n().then(() => { applyConfigI18n(); }).catch((e) => { console.error('i18n init failed', e); }); await renderAdminHeader?.(); await renderSiteFooter?.(); const key = await adminKey.get(); if (!key || !await verifyKey(ADMIN_API + '/verify', key).catch(() => false)) return location.href = '/admin/login'; await load(); } catch (e) { console.error('config page boot failed', e); showToast(tr('config.loadFailed', { message: e.message }, `配置页初始化失败: ${e.message}`), 'error'); } })(); ``` -------------------------------- ### Docker Compose Deployment Source: https://github.com/chenyme/grok2api/blob/main/docs/README.en.md Steps to clone the repository, set up the environment, and run the application using Docker Compose. ```bash git clone https://github.com/chenyme/grok2api cd grok2api cp .env.example .env docker compose up -d ``` -------------------------------- ### Help Tip Management Functions Source: https://github.com/chenyme/grok2api/blob/main/app/statics/admin/config.html JavaScript functions to show, hide, and position help tips that appear when hovering over or focusing on configuration fields. ```javascript helpTipEl.remove(); _helpTipEl = null; _activeHelpButton = null; } function _positionHelpTip(button, tip) { const margin = 12; const rect = button.getBoundingClientRect(); const viewportWidth = window.innerWidth || document.documentElement.clientWidth; const viewportHeight = window.innerHeight || document.documentElement.clientHeight; const maxWidth = Math.max(120, viewportWidth - margin * 2); tip.style.maxWidth = `${Math.min(320, maxWidth)}px`; tip.style.left = '0px'; tip.style.top = '0px'; const tipRect = tip.getBoundingClientRect(); let left = rect.left + rect.width / 2 - tipRect.width / 2; left = Math.max(margin, Math.min(left, viewportWidth - tipRect.width - margin)); let placement = 'top'; let top = rect.top - tipRect.height - 8; if (top < margin) { placement = 'bottom'; top = rect.bottom + 8; } if (top + tipRect.height > viewportHeight - margin) { top = Math.max(margin, viewportHeight - tipRect.height - margin); } const arrowLeft = Math.max(12, Math.min(rect.left + rect.width / 2 - left, tipRect.width - 12)); tip.dataset.placement = placement; tip.style.setProperty('--arrow-left', `${arrowLeft}px`); tip.style.left = `${left}px`; tip.style.top = `${top}px`; } function _showHelpTip(button) { const text = button.getAttribute('data-tip'); if (!text) return; _hideHelpTip(); const tip = _el('div', { class: 'cfg-help-tip', id: 'cfg-help-tip', role: 'tooltip', }, text); document.body.appendChild(tip); button.setAttribute('aria-describedby', 'cfg-help-tip'); _helpTipEl = tip; _activeHelpButton = button; _positionHelpTip(button, tip); requestAnimationFrame(() => tip.classList.add('visible')); } window.addEventListener('resize', _hideHelpTip); window.addEventListener('scroll', _hideHelpTip, true); document.addEventListener('keydown', (event) => { if (event.key === 'Escape') _hideHelpTip(); }); document.addEventListener('click', (event) => { if (!event.target.closest?.('.cfg-help')) _hideHelpTip(); }); ``` -------------------------------- ### Account Management State and Initialization Source: https://github.com/chenyme/grok2api/blob/main/app/statics/admin/account.html This snippet defines the initial state variables for the account management page, including pagination, filtering options, token data, and UI state. It also includes functions for internationalization (i18n) and the initial boot process which waits for i18n to be ready, applies translations, and then loads the account data after verifying the admin key. ```javascript // // State // const PAGE_SIZE_KEY = 'admin.account.page_size'; const PAGE_SIZE_OPTIONS = [50, 100, 200, 500, 1000, 2000]; let allTokens = [], curStatus = 'all', curNsfw = 'all', curPool = 'all', curPage = 1, pageSize = loadSavedPageSize(); const sel = new Set(); const refreshingTokens = new Set(); let _cb = null; let _editingToken = ''; let _filterMenuBound = false; let _tokenViewVersion = 0; let _tokenViewCacheKey = ''; let _tokenViewCache = null; function invalidateTokenView() { _tokenViewVersion += 1; _tokenViewCacheKey = ''; _tokenViewCache = null; } function tr(key, params, fallback) { const value = t(key, params); return value === key ? (fallback ?? key) : value; } function applyAccountI18n() { document.title = tr('account.pageTitle', null, 'Grok2API - 账户管理'); document.querySelectorAll('#page-size-sel option').forEach(opt => { opt.textContent = tr('account.pageSizeOption', { n: opt.value }, `${opt.value} / 页`); }); const toolbarTips = [ ['btn-filter', 'account.filter', '筛选'], ['btn-export', 'account.export', '导出数据'], ['btn-nsfw', 'account.batchNsfw', '开启 NSFW'], ['btn-refresh', 'account.batchRefresh', '刷新选中'], ['btn-disable', 'account.batchDisable', '禁用选中'], ['btn-restore', 'account.batchRestore', '恢复选中'], ['btn-delete', 'account.batchDelete', '删除选中'], ['btn-batch-cancel', 'account.cancel', '取消'], ]; toolbarTips.forEach(([id, key, fallback]) => { const el = document.getElementById(id); if (!el) return; const label = tr(key, null, fallback); el.setAttribute('data-tip', label); el.setAttribute('aria-label', label); el.setAttribute('title', label); }); const pageSizeSel = document.getElementById('page-size-sel'); if (pageSizeSel) pageSizeSel.value = String(pageSize); updateImportFileState(); render(); } function waitI18n() { return new Promise((resolve) => I18n.onReady(resolve)); } // // Boot // (async () => { await waitI18n(); applyAccountI18n(); await renderAdminHeader?.(); await renderSiteFooter?.(); initFilterMenu(); const key = await adminKey.get(); if (!key || !await verifyKey(ADMIN_API + '/verify', key).catch(() => false)) return location.href = '/admin/login'; load(); })(); ``` -------------------------------- ### Element Creation Helper Source: https://github.com/chenyme/grok2api/blob/main/app/statics/admin/config.html A utility function for creating HTML elements with attributes and children. ```javascript function _el(tag, attrs, ...children) { const el = document.createElement(tag); Object.entries(attrs || {}).forEach(([k, v]) => { if (k === 'class') el.className = v; else if (k.startsWith('on')) el.addEventListener(k.slice(2), v); else el.setAttribute(k, v); }); children.flat().forEach(c => { if (c == null) return; el.appendChild(typeof c === 'string' ? document.createTextNode(c) : c); }); return el; } ``` -------------------------------- ### Initialization and Rendering Logic Source: https://github.com/chenyme/grok2api/blob/main/app/statics/admin/cache.html Asynchronous IIFE that handles internationalization, rendering headers/footers, verifying admin key, and loading initial data. ```javascript (async () => { \n await waitI18n(); \n applyCacheI18n(); \n await renderAdminHeader?.(); \n await renderSiteFooter?.(); \n const key = await adminKey.get(); \n if (!key || !await verifyKey(ADMIN_API + '/verify', key).catch(() => false)) { \n location.href = '/admin/login'; \n return; \n } \n loadStats(); \n loadList(); \n _renderAssets(); \n })(); ``` -------------------------------- ### Load Configuration Source: https://github.com/chenyme/grok2api/blob/main/app/statics/admin/config.html Asynchronously loads the configuration from the API, updates the internal state, builds the schema if necessary, renders the configuration, and refreshes the dirty state. ```javascript async function load() { try { _cfg = await _api('GET', '/config'); _dirty = {}; _configLoaded = true; if (!SCHEMA.length) SCHEMA = buildSchema(); renderAll(); _refreshDirtyState({ autoNormalizeSelects: false }); } catch (e) { showToast(tr('config.loadFailed', { message: e.message }, `配置加载失败: ${e.message}`), 'error'); } } ``` -------------------------------- ### Open Import File Modal Source: https://github.com/chenyme/grok2api/blob/main/app/statics/admin/account.html Opens the modal for importing tokens from a file. ```javascript function openImport() { document.getElementById('import-file').value = ''; updateImportFileState(); fillImportPoolOptions('import-file-pool'); openModal('modal-import-file'); } ``` -------------------------------- ### Open Add Token Modal Source: https://github.com/chenyme/grok2api/blob/main/app/statics/admin/account.html Opens the modal for adding tokens manually. ```javascript function openAdd() { document.getElementById('import-tokens').value = ''; fillImportPoolOptions('import-pool'); openModal('modal-import'); } ``` -------------------------------- ### Login Logic Source: https://github.com/chenyme/grok2api/blob/main/app/statics/admin/login.html Handles user input for the admin password, verifies it, and redirects to the admin account page upon successful login. Also includes logic to automatically log in if a valid key is already stored. ```javascript const el = document.getElementById('key'); el.addEventListener('keypress', e => { if (e.key === 'Enter') login(); }); async function login() { const key = el.value.trim(); if (!key) return; try { if (await verifyKey(ADMIN_API+'/verify', key)) { await adminKey.set(key); location.href='/admin/account'; } else { showToast(t('common.invalidKey'), 'error'); } } catch { showToast(t('common.connectionFailed'), 'error'); } } (async () => { const key = await adminKey.get(); if (key) { try { if (await verifyKey(ADMIN_API+'/verify', key)) { location.href='/admin/account'; } } catch {} } await renderSiteFooter?.(); })(); ``` -------------------------------- ### Initialization and Auto-Login Check Source: https://github.com/chenyme/grok2api/blob/main/app/statics/webui/login.html Immediately invoked asynchronous function to check for stored keys, verify them, and attempt auto-login or redirect. ```javascript (async () => { try { const stored = await webuiKey.get(); if (stored && await verifyKey(VERIFY, stored)) { location.href='/webui/chat'; return; } if (stored) { webuiKey.clear(); } if (await verifyKey(VERIFY, '')) { location.href='/webui/chat'; } } catch {} await renderSiteFooter?.(); })(); ``` -------------------------------- ### Populate Import Pool Options Source: https://github.com/chenyme/grok2api/blob/main/app/statics/admin/account.html Fills the options for an import pool dropdown, including an 'auto' recommended option. ```javascript function fillImportPoolOptions(id) { const known = [...new Set(['basic', 'super', 'heavy', ...allTokens.map(t => t.pool || 'basic')])]; const opts = [ ` `, ...known.map(p => ``) ]; document.getElementById(id).innerHTML = opts.join(''); } ``` -------------------------------- ### Helper SVG Icon Source: https://github.com/chenyme/grok2api/blob/main/app/statics/admin/config.html An SVG icon representing a question mark, used for help tooltips. ```html ``` -------------------------------- ### Helper Functions Source: https://github.com/chenyme/grok2api/blob/main/app/statics/admin/account.html This snippet contains various utility functions for formatting data, masking tokens, escaping HTML characters, and formatting dates. These helpers are used throughout the application for consistent data presentation. ```javascript function $(id, v) { const el = document.getElementById(id); if (el) el.textContent = v; } function fmt(n) { return n >= 10000 ? (n/1000).toFixed(1)+'k' : n; } function loadSavedPageSize() { const raw = Number(localStorage.getItem(PAGE_SIZE_KEY) || 0); return PAGE_SIZE_OPTIONS.includes(raw) ? raw : 50; } function fmtRate(success, fail) { const total = success + fail; if (!total) return tr('account.na', null, '—'); return `${Math.round(success / total * 100)}% `; } function mask(t) { return t.length > 20 ? t.slice(0,8) + '…' + t.slice(-8) : t; } function xe(s) { return s.replace(/\\/g,'\\\\').replace(/'/g,"\\'`).replace(/ ``` -------------------------------- ### Tooltip Management Source: https://github.com/chenyme/grok2api/blob/main/app/statics/admin/account.html JavaScript code for creating, showing, hiding, and positioning tooltips based on mouse events and focus. ```javascript const _tooltipEl = document.createElement('div'); _tooltipEl.className = 'admin-tooltip'; document.body.appendChild(_tooltipEl); let _tooltipTarget = null; function _placeTooltip(x, y) { const pad = 12; const rect = _tooltipEl.getBoundingClientRect(); const maxX = window.innerWidth - rect.width - pad; const maxY = window.innerHeight - rect.height - pad; const left = Math.max(pad, Math.min(x + 14, maxX)); const top = Math.max(pad, Math.min(y + 16, maxY)); _tooltipEl.style.left = `${left}px`; _tooltipEl.style.top = `${top}px`; } function _showTooltip(target, x, y) { const text = target?.getAttribute('data-tip'); if (!text) return; _tooltipTarget = target; _tooltipEl.textContent = text; _tooltipEl.classList.add('show'); _placeTooltip(x, y); } function _hideTooltip() { _tooltipTarget = null; _tooltipEl.classList.remove('show'); } document.addEventListener('mouseover', (e) => { const target = e.target.closest('[data-tip]'); if (!target) return _hideTooltip(); _showTooltip(target, e.clientX, e.clientY); }); document.addEventListener('mousemove', (e) => { if (_tooltipTarget) _placeTooltip(e.clientX, e.clientY); }); document.addEventListener('mouseout', (e) => { if (!_tooltipTarget) return; const next = e.relatedTarget; if (next && _tooltipTarget.contains(next)) return; if (e.target.closest('[data-tip]') === _tooltipTarget) _hideTooltip(); }); document.addEventListener('focusin', (e) => { const target = e.target.closest('[data-tip]'); if (!target) return; const rect = target.getBoundingClientRect(); _showTooltip(target, rect.left + rect.width / 2, rect.top); }); document.addEventListener('focusout', (e) => { if (e.target.closest('[data-tip]')) _hideTooltip(); }); ``` -------------------------------- ### Login Key Input Handling Source: https://github.com/chenyme/grok2api/blob/main/app/statics/webui/login.html JavaScript code to handle user input for the access key and trigger login on 'Enter' key press. ```javascript const el = document.getElementById('key'); el.addEventListener('keypress', e => { if (e.key === 'Enter') { login(); } }); ``` -------------------------------- ### Copy to Clipboard Function Source: https://github.com/chenyme/grok2api/blob/main/app/statics/admin/account.html Asynchronously copies text to the clipboard and shows a toast notification for success or failure. ```javascript async function copy(t) { try { await navigator.clipboard.writeText(t); showToast(tr('account.copied', null, '已复制'), 'success'); } catch { showToast(tr('account.copyFailed', null, '复制失败'), 'error'); } } ``` -------------------------------- ### Filter Menu Initialization Source: https://github.com/chenyme/grok2api/blob/main/app/statics/admin/account.html JavaScript code to initialize the filter menu, including event listeners for opening, closing, and interaction. ```javascript function initFilterMenu() { if (_filterMenuBound) return; const menu = document.getElementById('filter-menu'); const trigger = document.getElementById('btn-filter'); const panel = document.getElementById('filter-panel'); if (!menu || !trigger || !panel) return; _filterMenuBound = true; const close = () => { menu.classList.remove('open'); trigger.setAttribute('aria-expanded', 'false'); syncFilterTrigger(); }; trigger.addEventListener('click', (event) => { event.stopPropagation(); const open = !menu.classList.contains('open'); menu.classList.toggle('open', open); trigger.setAttribute('aria-expanded', open ? 'true' : 'false'); syncFilterTrigger(); }); panel.addEventListener('click', (event) => event.stopPropagation()); document.addEventListener('click', (event) => { const target = event.target; if (!(target instanceof Node) || !menu.contains(target)) close(); }); document.addEventListener('keydown', (event) => { if (event.key === 'Escape') close(); }); } ``` -------------------------------- ### Asset List Rendering Source: https://github.com/chenyme/grok2api/blob/main/app/statics/admin/cache.html Renders the list of online assets, including checkboxes for selection and expand/collapse buttons for nested items. ```javascript function _renderAssets(view = getAssetView()) { const tbody = document.getElementById('assets-tbody'); syncAssetSelectAll(view); if (!view.loaded) { tbody.innerHTML = `${\_esc(tr('cache.emptyAssetsIdle', null, '点击右上角获取在线资产列表'))}`; return; } if (!view.totalRows) { tbody.innerHTML = `${\_esc(tr('cache.emptyAccounts', null, '暂无账户数据'))}`; return; } const expandLabel = tr('cache.expand', null, '展开'); const collapseLabel = tr('cache.collapse', null, '收起'); const clearLabel = tr('cache.actionClear', null, '清理'); const deleteLabel = tr('cache.actionDelete', null, '删除'); const naLabel = tr('cache.na', null, '—'); const rows = []; for (const { row, masked, assets, hasItems, isOpen, isSelected } of view.rows) { rows.push( ` ${ hasItems ? `` : '' } ${\_esc(row.name)} ${\_esc(row.size)} ${\_esc(row.count)} ${\_esc(row.used)} ` ); } tbody.innerHTML = rows.join(''); } ``` -------------------------------- ### Utility Functions for Formatting Source: https://github.com/chenyme/grok2api/blob/main/app/statics/admin/cache.html Provides utility functions for formatting memory sizes, byte counts, timestamps, and masking tokens. ```javascript function _fmtMb(mb) { \n if (mb == null) return tr('cache.na', null, '—'); \n if (mb < 1) return `${Math.round(mb * 1024)} KB`; \n return `${mb.toFixed(1)} MB`; \n } \n function _fmtBytes(bytes) { \n if (!bytes) return '0 B'; \n if (bytes < 1024) return `${bytes} B`; \n if (bytes < 1048576) return `${(bytes / 1024).toFixed(1)} KB`; \n return `${(bytes / 1048576).toFixed(1)} MB`; \n } \n function _fmtTime(ts) { \n if (!ts) return tr('cache.na', null, '—'); \n return new Date(ts * 1000).toLocaleString(getLocale(), { hour12: false }); \n } \n function _maskToken(token) { \n return token.length > 16 ? `${token.slice(0, 8)}…${token.slice(-4)}` : token; \n } ``` -------------------------------- ### SVG Icon for WebUI Link Source: https://github.com/chenyme/grok2api/blob/main/app/statics/admin/config.html An SVG icon used for the 'Open WebUI' button, indicating a link to the WebUI. ```html ``` -------------------------------- ### Load List Function Source: https://github.com/chenyme/grok2api/blob/main/app/statics/admin/cache.html Asynchronously loads a list of local cache items based on type, page, and page size, then updates the UI. ```javascript async function loadList() { try { const d = await _api('GET', `/cache/list?type=${_type}&page=${_page}&page_size=${_pageSize}`); _total = d.total ?? 0; _localItems = d.items || []; invalidateLocalView(); _reconcileLocalSelection(); _renderTable(); _renderPagi(); updateLocalBatchButtons(); } catch (e) { showToast(tr('cache.loadFailed', { message: e.message }, `加载失败: ${e.message}`), 'error'); } } ```