Download index.html from LemonData/tokenlab-model-explorer: direct link, hf CLI and curl.
- Browser
- Download file 8.98 kB
-
https://huggingface.co/spaces/LemonData/tokenlab-model-explorer/resolve/main/index.html
- Command line
-
hf download hf://spaces/LemonData/tokenlab-model-explorer/index.html
-
curl -L -o index.html https://huggingface.co/spaces/LemonData/tokenlab-model-explorer/resolve/main/index.html
8.98 kB
| <html lang="en"> | |
| <head> | |
| <meta charset="utf-8" /> | |
| <meta name="viewport" content="width=device-width, initial-scale=1" /> | |
| <title>TokenLab Model Explorer</title> | |
| <style> | |
| :root { | |
| color-scheme: light; | |
| --ink: #172033; | |
| --muted: #667085; | |
| --line: #d9dee9; | |
| --panel: #ffffff; | |
| --wash: #f5f7fb; | |
| --accent: #3155d9; | |
| --accent-wash: #eef2ff; | |
| } | |
| * { box-sizing: border-box; } | |
| body { | |
| margin: 0; | |
| background: var(--wash); | |
| color: var(--ink); | |
| font: 15px/1.5 Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; | |
| } | |
| main { width: min(1180px, calc(100% - 32px)); margin: 0 auto; padding: 34px 0 48px; } | |
| header { display: flex; align-items: flex-start; justify-content: space-between; gap: 24px; margin-bottom: 24px; } | |
| h1 { margin: 0; font-size: clamp(26px, 4vw, 42px); line-height: 1.08; letter-spacing: 0; } | |
| .lede { max-width: 680px; margin: 12px 0 0; color: var(--muted); } | |
| .links { display: flex; flex-wrap: wrap; gap: 8px; justify-content: flex-end; } | |
| a { color: var(--accent); } | |
| .links a, button { border: 1px solid var(--line); border-radius: 7px; background: var(--panel); color: var(--ink); padding: 9px 12px; text-decoration: none; font: inherit; cursor: pointer; } | |
| .links a:hover, button:hover { border-color: var(--accent); color: var(--accent); } | |
| .toolbar { display: grid; grid-template-columns: minmax(220px, 1fr) 180px auto; gap: 10px; margin-bottom: 16px; } | |
| input, select { width: 100%; border: 1px solid var(--line); border-radius: 7px; background: var(--panel); color: var(--ink); padding: 10px 12px; font: inherit; } | |
| .status { color: var(--muted); min-height: 24px; margin: 8px 0 14px; } | |
| .table-wrap { overflow: auto; border: 1px solid var(--line); border-radius: 8px; background: var(--panel); } | |
| table { width: 100%; border-collapse: collapse; min-width: 720px; } | |
| th, td { padding: 12px 14px; text-align: left; border-bottom: 1px solid var(--line); vertical-align: top; } | |
| th { color: var(--muted); font-size: 12px; font-weight: 650; text-transform: uppercase; letter-spacing: .04em; background: #fbfcfe; } | |
| tr:last-child td { border-bottom: 0; } | |
| .model { font-weight: 650; overflow-wrap: anywhere; } | |
| .muted { color: var(--muted); } | |
| .price { white-space: nowrap; } | |
| .example { margin-top: 18px; padding: 16px; border: 1px solid var(--line); border-radius: 8px; background: var(--panel); } | |
| .example-head { display: flex; justify-content: space-between; gap: 12px; align-items: center; } | |
| h2 { margin: 0; font-size: 17px; } | |
| pre { overflow: auto; margin: 12px 0 0; padding: 14px; border-radius: 6px; background: #111827; color: #e5e7eb; font-size: 12px; } | |
| .note { margin-top: 18px; color: var(--muted); font-size: 13px; } | |
| @media (max-width: 720px) { | |
| main { width: min(100% - 22px, 1180px); padding-top: 24px; } | |
| header { display: block; } | |
| .links { justify-content: flex-start; margin-top: 16px; } | |
| .toolbar { grid-template-columns: 1fr; } | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <main> | |
| <header> | |
| <div> | |
| <h1>TokenLab Model Explorer</h1> | |
| <p class="lede">Compare public model metadata and pricing, then copy an OpenAI-compatible or native endpoint example. This explorer is read-only and never asks for an API key.</p> | |
| </div> | |
| <nav class="links" aria-label="TokenLab links"> | |
| <a href="https://tokenlab.sh" target="_blank" rel="noreferrer">Website</a> | |
| <a href="https://docs.tokenlab.sh" target="_blank" rel="noreferrer">Docs</a> | |
| <a href="https://tokenlab-model-explorer.vercel.app/widget" target="_blank" rel="noreferrer">Hosted MCP</a> | |
| </nav> | |
| </header> | |
| <section class="toolbar" aria-label="Model filters"> | |
| <input id="query" type="search" placeholder="Search models" aria-label="Search models" /> | |
| <select id="category" aria-label="Filter by category"><option value="">All categories</option></select> | |
| <button id="refresh" type="button">Refresh public data</button> | |
| </section> | |
| <div id="status" class="status" role="status">Loading public model data...</div> | |
| <div class="table-wrap"> | |
| <table> | |
| <thead><tr><th>Model</th><th>Category</th><th>Provider</th><th>Input / 1M</th><th>Output / 1M</th></tr></thead> | |
| <tbody id="models"><tr><td colspan="5" class="muted">Loading...</td></tr></tbody> | |
| </table> | |
| </div> | |
| <section class="example"> | |
| <div class="example-head"><h2>Endpoint example</h2><button id="copy" type="button">Copy cURL</button></div> | |
| <pre id="curl">Select a model to generate an example.</pre> | |
| </section> | |
| <p class="note">Pricing and model availability can change. Verify current details in the <a href="https://docs.tokenlab.sh" target="_blank" rel="noreferrer">TokenLab documentation</a> before production use.</p> | |
| </main> | |
| <script> | |
| const API = "https://api.tokenlab.sh"; | |
| const state = { models: [], selected: "" }; | |
| const $ = (id) => document.getElementById(id); | |
| function flattenModels(index) { | |
| return Object.entries(index.categories || {}).flatMap(([category, value]) => | |
| (value.models || []).map((id) => ({ id, category })) | |
| ); | |
| } | |
| function endpointExample(model) { | |
| return `curl https://api.tokenlab.sh/v1/chat/completions \\ | |
| -H "Authorization: Bearer $TOKENLAB_API_KEY" \\ | |
| -H "Content-Type: application/json" \\ | |
| -d '{"model":"${model}","messages":[{"role":"user","content":"Hello from TokenLab"}]}'`; | |
| } | |
| function render() { | |
| const query = $("query").value.trim().toLowerCase(); | |
| const category = $("category").value; | |
| const visible = state.models.filter((model) => | |
| (!category || model.category === category) && (!query || model.id.toLowerCase().includes(query)) | |
| ).slice(0, 200); | |
| $("status").textContent = `${visible.length} of ${state.models.length} public models shown.`; | |
| $("models").innerHTML = visible.length ? visible.map((model) => ` | |
| <tr data-model="${encodeURIComponent(model.id)}"> | |
| <td><button class="model" type="button">${model.id}</button></td> | |
| <td>${model.category}</td><td class="muted">${model.provider || "Not listed"}</td> | |
| <td class="price">${model.input_per_1m == null ? "Not listed" : "$" + model.input_per_1m}</td> | |
| <td class="price">${model.output_per_1m == null ? "Not listed" : "$" + model.output_per_1m}</td> | |
| </tr>`).join("") : '<tr><td colspan="5" class="muted">No matching public models.</td></tr>'; | |
| document.querySelectorAll("[data-model]").forEach((row) => row.addEventListener("click", () => { | |
| state.selected = decodeURIComponent(row.dataset.model); | |
| $("curl").textContent = endpointExample(state.selected); | |
| })); | |
| } | |
| async function load() { | |
| $("status").textContent = "Loading public model data..."; | |
| try { | |
| const [modelsResponse, pricingResponse] = await Promise.all([ | |
| fetch(`${API}/models.json`), fetch(`${API}/pricing.json`) | |
| ]); | |
| if (!modelsResponse.ok || !pricingResponse.ok) throw new Error("Public discovery endpoint unavailable"); | |
| const [modelsIndex, pricingIndex] = await Promise.all([modelsResponse.json(), pricingResponse.json()]); | |
| const prices = new Map((pricingIndex.data || []).map((entry) => [entry.model, entry])); | |
| state.models = flattenModels(modelsIndex).map((model) => { | |
| const price = prices.get(model.id) || {}; | |
| return { ...model, provider: price.provider, input_per_1m: price.platform?.input_per_1m, output_per_1m: price.platform?.output_per_1m }; | |
| }); | |
| const categories = [...new Set(state.models.map((model) => model.category))].sort(); | |
| $("category").insertAdjacentHTML("beforeend", categories.map((item) => `<option value="${item}">${item}</option>`).join("")); | |
| render(); | |
| } catch (error) { | |
| $("status").textContent = `Could not load public data: ${error.message}`; | |
| $("models").innerHTML = '<tr><td colspan="5" class="muted">Try refreshing, or use the TokenLab documentation link below.</td></tr>'; | |
| } | |
| } | |
| $("query").addEventListener("input", render); | |
| $("category").addEventListener("change", render); | |
| $("refresh").addEventListener("click", load); | |
| $("copy").addEventListener("click", async () => { | |
| if (!state.selected) return; | |
| await navigator.clipboard.writeText($("curl").textContent); | |
| $("copy").textContent = "Copied"; | |
| setTimeout(() => { $("copy").textContent = "Copy cURL"; }, 1200); | |
| }); | |
| load(); | |
| </script> | |
| </body> | |
| </html> | |