Spaces:
Running
v0.7.0: SWA Unmasker (anti-bullshit #1) + foldable main panels + preset auto-fill
Browse filesShips the first feature of the v0.7 anti-bullshit pack inspired by HF community pain points: detect when a model card claims a max_position_embeddings far larger than its effective context (Mistral-7B-v0.1: declared 32k, attends ~8k via SWA).
NEW
- 🪟 Unmask mode: paste an HF model id (or raw config.json) → 1-second verdict (HONEST / INFLATED / SEVERELY INFLATED / YARN-EXTENDED). Pure browser arithmetic on config.json: SWA window + RoPE-scaling + GQA/d_head heuristics. No GPU, no inference.
- js/swa_unmasker.js: pure logic module, no human strings. Returns warning codes + params; main.js renders via i18n with {placeholder} substitution so EN/ES/FR/ZH all work.
- tFmt() i18n helper: t(key) with {placeholder} replacement.
UX
- All <main> sections now wrapped at runtime in <details open> with foldable header (idempotent wrapMainSectionsAsFoldable). Big ▼ arrow rotates to ▶ when collapsed. Triple-browser marker hide (list-style + ::-webkit-details-marker + ::marker).
- Inventory modal: 4 inv-cards now <details open> with arrow per card.
- Architectures-supported defaults to open; tooltip text removed "(click to expand)".
- Profile + Recipe preset dropdowns now also auto-fill the HF id input (presets are HF model ids; clarifies dual source of truth — preset = cached, 📥 Fetch = live HF Hub).
i18n cleanup (the big one)
- swa_unmasker hardcoded English strings: GONE. All warnings/recommendations/verdict labels live in i18n with {placeholder} substitution × EN/ES/FR/ZH.
- 8 mode-desc strings: refactored from inline string switch to t(`mode_desc.${mode}`) lookup. Section show/hide reduced to a sectionMap object.
- modes.tip updated: "7 modes" → "8 modes" (added Unmask).
- 423 keys × 4 langs, 0 missing / 0 extra (parity verified).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- index.html +42 -13
- js/i18n.js +232 -8
- js/main.js +209 -35
- js/swa_unmasker.js +107 -0
- style.css +146 -4
|
@@ -249,8 +249,8 @@
|
|
| 249 |
<button class="help-close" id="inventory-close" aria-label="Close inventory">×</button>
|
| 250 |
<h2 id="inv-modal-title" data-i18n="inv.title">🧰 What this tool gives you</h2>
|
| 251 |
<div class="inventory-grid">
|
| 252 |
-
<
|
| 253 |
-
<
|
| 254 |
<ul>
|
| 255 |
<li><strong data-i18n="inv.recipes.x1.title">Custom train vs API</strong>: <span data-i18n="inv.recipes.x1.body">which is cheaper for your traffic?</span></li>
|
| 256 |
<li><strong data-i18n="inv.recipes.x2.title">Long context</strong>: <span data-i18n="inv.recipes.x2.body">will it handle 32k / 128k tokens reliably?</span></li>
|
|
@@ -261,35 +261,35 @@
|
|
| 261 |
<li><strong data-i18n="inv.recipes.x22.title">Compute-context</strong>: <span data-i18n="inv.recipes.x22.body">does the model fit the empirical band?</span></li>
|
| 262 |
<li><strong data-i18n="inv.recipes.x23.title">IH-phase</strong>: <span data-i18n="inv.recipes.x23.body">pre- or post-induction-head?</span></li>
|
| 263 |
</ul>
|
| 264 |
-
</
|
| 265 |
-
<
|
| 266 |
-
<
|
| 267 |
<ul>
|
| 268 |
<li data-i18n="inv.diag.gamma"><strong>γ predicted vs observed</strong> — auto-classifies the model into 5 regimes (normal · fraud / inflated context · compressed · over-Padé · sliding-window)</li>
|
| 269 |
<li data-i18n="inv.diag.cardy"><strong>Cardy ΔH</strong> — entropy shift between observed and nominal context</li>
|
| 270 |
<li data-i18n="inv.diag.fals"><strong>Falsification dashboard</strong> — checks 23 specific predictions (F1–F23)</li>
|
| 271 |
<li data-i18n="inv.diag.alg"><strong>Algebraic consistency</strong> — 8 mathematical identities the model must satisfy</li>
|
| 272 |
</ul>
|
| 273 |
-
</
|
| 274 |
-
<
|
| 275 |
-
<
|
| 276 |
<ul>
|
| 277 |
<li data-i18n="inv.verify.count"><strong>37 theorems</strong> machine-proven in Lean 4 + Mathlib4</li>
|
| 278 |
<li data-i18n="inv.verify.click">Click any badge → opens the source line on GitHub</li>
|
| 279 |
<li data-i18n="inv.verify.reverify">Verify yourself: <code>lake build</code> (≈5 s after cache fetch)</li>
|
| 280 |
</ul>
|
| 281 |
-
</
|
| 282 |
-
<
|
| 283 |
-
<
|
| 284 |
<ul>
|
| 285 |
<li data-i18n="inv.export.formats"><strong>JSON · Markdown · LaTeX</strong> (paper-ready)</li>
|
| 286 |
<li data-i18n="inv.export.share">Reproducible share link (state encoded in URL)</li>
|
| 287 |
<li data-i18n="inv.export.registry">Submit to community registry on GitHub</li>
|
| 288 |
</ul>
|
| 289 |
-
</
|
| 290 |
</div>
|
| 291 |
|
| 292 |
-
<details class="arch-supported">
|
| 293 |
<summary data-i18n="arch.summary">Architectures supported (click to expand)</summary>
|
| 294 |
<div class="arch-badges">
|
| 295 |
<span class="badge">✓ RoPE-MHA <span class="info"><span class="tooltip" data-i18n="tooltip.mha">Multi-Head Attention: each token position attends through several parallel heads at once.</span></span></span>
|
|
@@ -334,6 +334,7 @@
|
|
| 334 |
<button class="mode-btn" data-mode="recipe" role="tab" aria-selected="false" data-i18n="modes.recipe">📋 Pick recipe</button>
|
| 335 |
<button class="mode-btn" data-mode="diagnose" role="tab" aria-selected="false" data-i18n="modes.diagnose">🩺 Diagnose CLI</button>
|
| 336 |
<button class="mode-btn" data-mode="phase" role="tab" aria-selected="false" data-i18n="modes.phase">📊 Phase diagram</button>
|
|
|
|
| 337 |
</div>
|
| 338 |
<p id="mode-desc" class="recipe-desc" data-i18n="modes.desc">
|
| 339 |
<strong>Quickest start</strong>: paste any HuggingFace model id (e.g. <code>meta-llama/Meta-Llama-3-8B</code>),
|
|
@@ -623,6 +624,34 @@
|
|
| 623 |
<div id="phase-info" class="recipe-desc" style="margin-top:0.6em;"></div>
|
| 624 |
</section>
|
| 625 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 626 |
<!-- Recipe selector (mode=recipe) -->
|
| 627 |
<section id="recipe-section" style="display:none;">
|
| 628 |
<h2 data-i18n="recipe.title">📋 Recipe</h2>
|
|
|
|
| 249 |
<button class="help-close" id="inventory-close" aria-label="Close inventory">×</button>
|
| 250 |
<h2 id="inv-modal-title" data-i18n="inv.title">🧰 What this tool gives you</h2>
|
| 251 |
<div class="inventory-grid">
|
| 252 |
+
<details class="inv-card" open>
|
| 253 |
+
<summary class="inv-card-title" data-i18n="inv.recipes.title">🎯 8 recipes — does this model fit your use case?</summary>
|
| 254 |
<ul>
|
| 255 |
<li><strong data-i18n="inv.recipes.x1.title">Custom train vs API</strong>: <span data-i18n="inv.recipes.x1.body">which is cheaper for your traffic?</span></li>
|
| 256 |
<li><strong data-i18n="inv.recipes.x2.title">Long context</strong>: <span data-i18n="inv.recipes.x2.body">will it handle 32k / 128k tokens reliably?</span></li>
|
|
|
|
| 261 |
<li><strong data-i18n="inv.recipes.x22.title">Compute-context</strong>: <span data-i18n="inv.recipes.x22.body">does the model fit the empirical band?</span></li>
|
| 262 |
<li><strong data-i18n="inv.recipes.x23.title">IH-phase</strong>: <span data-i18n="inv.recipes.x23.body">pre- or post-induction-head?</span></li>
|
| 263 |
</ul>
|
| 264 |
+
</details>
|
| 265 |
+
<details class="inv-card" open>
|
| 266 |
+
<summary class="inv-card-title" data-i18n="inv.diag.title">🔬 Diagnostics</summary>
|
| 267 |
<ul>
|
| 268 |
<li data-i18n="inv.diag.gamma"><strong>γ predicted vs observed</strong> — auto-classifies the model into 5 regimes (normal · fraud / inflated context · compressed · over-Padé · sliding-window)</li>
|
| 269 |
<li data-i18n="inv.diag.cardy"><strong>Cardy ΔH</strong> — entropy shift between observed and nominal context</li>
|
| 270 |
<li data-i18n="inv.diag.fals"><strong>Falsification dashboard</strong> — checks 23 specific predictions (F1–F23)</li>
|
| 271 |
<li data-i18n="inv.diag.alg"><strong>Algebraic consistency</strong> — 8 mathematical identities the model must satisfy</li>
|
| 272 |
</ul>
|
| 273 |
+
</details>
|
| 274 |
+
<details class="inv-card" open>
|
| 275 |
+
<summary class="inv-card-title" data-i18n="inv.verify.title">✓ Formally verified math</summary>
|
| 276 |
<ul>
|
| 277 |
<li data-i18n="inv.verify.count"><strong>37 theorems</strong> machine-proven in Lean 4 + Mathlib4</li>
|
| 278 |
<li data-i18n="inv.verify.click">Click any badge → opens the source line on GitHub</li>
|
| 279 |
<li data-i18n="inv.verify.reverify">Verify yourself: <code>lake build</code> (≈5 s after cache fetch)</li>
|
| 280 |
</ul>
|
| 281 |
+
</details>
|
| 282 |
+
<details class="inv-card" open>
|
| 283 |
+
<summary class="inv-card-title" data-i18n="inv.export.title">📤 Export & share</summary>
|
| 284 |
<ul>
|
| 285 |
<li data-i18n="inv.export.formats"><strong>JSON · Markdown · LaTeX</strong> (paper-ready)</li>
|
| 286 |
<li data-i18n="inv.export.share">Reproducible share link (state encoded in URL)</li>
|
| 287 |
<li data-i18n="inv.export.registry">Submit to community registry on GitHub</li>
|
| 288 |
</ul>
|
| 289 |
+
</details>
|
| 290 |
</div>
|
| 291 |
|
| 292 |
+
<details class="arch-supported" open>
|
| 293 |
<summary data-i18n="arch.summary">Architectures supported (click to expand)</summary>
|
| 294 |
<div class="arch-badges">
|
| 295 |
<span class="badge">✓ RoPE-MHA <span class="info"><span class="tooltip" data-i18n="tooltip.mha">Multi-Head Attention: each token position attends through several parallel heads at once.</span></span></span>
|
|
|
|
| 334 |
<button class="mode-btn" data-mode="recipe" role="tab" aria-selected="false" data-i18n="modes.recipe">📋 Pick recipe</button>
|
| 335 |
<button class="mode-btn" data-mode="diagnose" role="tab" aria-selected="false" data-i18n="modes.diagnose">🩺 Diagnose CLI</button>
|
| 336 |
<button class="mode-btn" data-mode="phase" role="tab" aria-selected="false" data-i18n="modes.phase">📊 Phase diagram</button>
|
| 337 |
+
<button class="mode-btn" data-mode="unmask" role="tab" aria-selected="false" data-i18n="modes.unmask">🪟 Unmask</button>
|
| 338 |
</div>
|
| 339 |
<p id="mode-desc" class="recipe-desc" data-i18n="modes.desc">
|
| 340 |
<strong>Quickest start</strong>: paste any HuggingFace model id (e.g. <code>meta-llama/Meta-Llama-3-8B</code>),
|
|
|
|
| 624 |
<div id="phase-info" class="recipe-desc" style="margin-top:0.6em;"></div>
|
| 625 |
</section>
|
| 626 |
|
| 627 |
+
<!-- Unmask mode: detect misleading max_position_embeddings via SWA / RoPE-scaling -->
|
| 628 |
+
<section id="unmask-section" style="display:none;">
|
| 629 |
+
<h2><span data-i18n="unmask.title">🪟 Context Unmasker</span>
|
| 630 |
+
<span class="info"><span class="tooltip" data-i18n="unmask.tip">
|
| 631 |
+
Paste a HuggingFace model id (or raw config.json). The tool checks for
|
| 632 |
+
sliding-window attention, RoPE scaling (YaRN/linear/dynamic NTK), and
|
| 633 |
+
GQA — anything that makes <code>max_position_embeddings</code> larger
|
| 634 |
+
than the practical effective context. Mistral-7B-v0.1 is the canonical
|
| 635 |
+
example: declared 32k, attends within ~4-8k.
|
| 636 |
+
</span></span>
|
| 637 |
+
</h2>
|
| 638 |
+
<p class="recipe-desc" data-i18n="unmask.desc">
|
| 639 |
+
<strong>Are you about to spend money on a model that won't actually attend that far?</strong> Paste an id and find out in 1 second. No GPU, no inference — just config.json arithmetic.
|
| 640 |
+
</p>
|
| 641 |
+
<div class="form-row">
|
| 642 |
+
<label for="unmask-id" data-i18n="unmask.id_label">HF model id:</label>
|
| 643 |
+
<input type="text" id="unmask-id" placeholder="e.g. mistralai/Mistral-7B-v0.1" />
|
| 644 |
+
<button type="button" id="unmask-fetch-btn" data-i18n="unmask.fetch_btn">🔍 Unmask</button>
|
| 645 |
+
</div>
|
| 646 |
+
<p id="unmask-status" class="recipe-desc" style="font-size:0.92em;"></p>
|
| 647 |
+
<details style="margin: 0.6em 0;">
|
| 648 |
+
<summary style="cursor:pointer; font-size:0.92em;" data-i18n="unmask.paste_summary">Or paste raw config.json (private / in-dev models)</summary>
|
| 649 |
+
<textarea id="unmask-paste" rows="6" style="width:100%; font-family:monospace; font-size:0.85em; margin-top:0.4em;" placeholder='{"max_position_embeddings": 32768, "sliding_window": 4096, ...}'></textarea>
|
| 650 |
+
<button type="button" id="unmask-paste-btn" data-i18n="unmask.paste_btn" style="margin-top:0.4em;">🔍 Unmask pasted config</button>
|
| 651 |
+
</details>
|
| 652 |
+
<div id="unmask-output" style="margin-top: 1em;"></div>
|
| 653 |
+
</section>
|
| 654 |
+
|
| 655 |
<!-- Recipe selector (mode=recipe) -->
|
| 656 |
<section id="recipe-section" style="display:none;">
|
| 657 |
<h2 data-i18n="recipe.title">📋 Recipe</h2>
|
|
@@ -125,7 +125,7 @@ export const TRANSLATIONS = {
|
|
| 125 |
"inv.export.formats": "<strong>JSON · Markdown · LaTeX</strong> (paper-ready)",
|
| 126 |
"inv.export.share": "Reproducible share link (state encoded in URL)",
|
| 127 |
"inv.export.registry": "Submit to community registry on GitHub",
|
| 128 |
-
"arch.summary": "Architectures supported
|
| 129 |
"arch.anyhf": "✓ Any HuggingFace public model",
|
| 130 |
"tooltip.mha": "Multi-Head Attention: each token position attends through several parallel heads at once.",
|
| 131 |
"tooltip.gqa": "Grouped Query Attention: queries share fewer keys/values than heads (saves memory but pushes γ toward Hagedorn).",
|
|
@@ -133,6 +133,62 @@ export const TRANSLATIONS = {
|
|
| 133 |
"tooltip.abspe": "Absolute Position Embeddings: each position has a fixed learned vector added to the token embedding.",
|
| 134 |
"tooltip.swa": "Sliding Window Attention: each token only attends within a fixed local window (Mistral, gemma-2 use this).",
|
| 135 |
"tooltip.ssm": "State Space Model: a sequence layer that maintains internal state instead of attention (Mamba, Jamba use this).",
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 136 |
"share.import_desc": "Got a JSON file from someone else's TAF analysis? Load it here to see the verdict + chain locally. Same view as if you'd run it yourself.",
|
| 137 |
"share.import_btn": "📂 Load shared JSON",
|
| 138 |
"synthesis.system": "You are a precise transformer LLM diagnostic assistant. Given pre-computed TAF formula results, write a clear plain-English summary in 4-6 sentences. Cite the section number (§X.Y) for each number you mention. Always give a concrete recommendation. Do NOT invent numbers.",
|
|
@@ -225,7 +281,7 @@ export const TRANSLATIONS = {
|
|
| 225 |
"common.no": "No",
|
| 226 |
|
| 227 |
// Mode tooltips
|
| 228 |
-
"modes.tip": "<strong>
|
| 229 |
"profile.tip": "<strong>One-click full diagnosis</strong>. Paste any HF model id (or pick preset). Tool runs all 5 recipes (long-context, KV-compression, custom-vs-API, budget, hardware) and produces a single <strong>TAF Card</strong> with verdict per dimension + key numbers + architecture classification.<br><br><strong>Use case</strong>: \"I'm evaluating Qwen2.5-32B for production — what's its full viability profile?\" → paste id → Profile → done.",
|
| 230 |
"compare.tip": "<strong>Same recipe, multiple models</strong>. Pick 2-3 candidate models and one recipe. See verdicts in a single comparison table.<br><br><strong>Use case</strong>: \"I need long-context retrieval at 16K — which is best: Llama-3-8B, Mistral-7B, or Qwen-7B?\" → pick 3 + X-2 + 16K → see winner.",
|
| 231 |
|
|
@@ -682,7 +738,7 @@ export const TRANSLATIONS = {
|
|
| 682 |
"inv.export.formats": "<strong>JSON · Markdown · LaTeX</strong> (listo para paper)",
|
| 683 |
"inv.export.share": "Link reproducible (estado codificado en URL)",
|
| 684 |
"inv.export.registry": "Envía al registro comunitario en GitHub",
|
| 685 |
-
"arch.summary": "Arquitecturas soportadas
|
| 686 |
"arch.anyhf": "✓ Cualquier modelo público de HuggingFace",
|
| 687 |
"tooltip.mha": "Multi-Head Attention: cada posición atiende mediante varios heads paralelos a la vez.",
|
| 688 |
"tooltip.gqa": "Grouped Query Attention: las queries comparten menos keys/values que heads (ahorra memoria pero empuja γ hacia Hagedorn).",
|
|
@@ -690,6 +746,62 @@ export const TRANSLATIONS = {
|
|
| 690 |
"tooltip.abspe": "Absolute Position Embeddings: cada posición tiene un vector fijo aprendido sumado al embedding del token.",
|
| 691 |
"tooltip.swa": "Sliding Window Attention: cada token solo atiende dentro de una ventana local fija (Mistral, gemma-2 lo usan).",
|
| 692 |
"tooltip.ssm": "State Space Model: capa de secuencia que mantiene estado interno en lugar de atención (Mamba, Jamba lo usan).",
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 693 |
"share.import_desc": "¿Tienes un fichero JSON del análisis TAF de alguien? Cárgalo aquí para ver el veredicto + cadena localmente. La misma vista que si lo hubieras ejecutado tú.",
|
| 694 |
"share.import_btn": "📂 Cargar JSON compartido",
|
| 695 |
"synthesis.system": "Eres un asistente de diagnóstico preciso para LLMs transformer. Dados resultados de fórmulas TAF pre-calculados, escribe un resumen claro en español de 4-6 frases. Cita el número de sección (§X.Y) para cada número que menciones. Da siempre una recomendación concreta. NO inventes números.",
|
|
@@ -782,7 +894,7 @@ export const TRANSLATIONS = {
|
|
| 782 |
"common.no": "No",
|
| 783 |
|
| 784 |
// Tooltips de modos
|
| 785 |
-
"modes.tip": "<strong>
|
| 786 |
"profile.tip": "<strong>Diagnóstico completo en un click</strong>. Pega cualquier id de modelo HF (o elige preset). La herramienta ejecuta las 5 recetas (contexto largo, compresión KV, custom vs API, presupuesto, hardware) y produce una única <strong>TAF Card</strong> con veredicto por dimensión + números clave + clasificación arquitectónica.<br><br><strong>Caso de uso</strong>: \"Estoy evaluando Qwen2.5-32B para producción — ¿cuál es su perfil completo de viabilidad?\" → pega id → Perfilar → listo.",
|
| 787 |
"compare.tip": "<strong>Misma receta, múltiples modelos</strong>. Elige 2-3 modelos candidatos y una receta. Ve los veredictos en una única tabla comparativa.<br><br><strong>Caso de uso</strong>: \"Necesito recuperación de contexto largo a 16K — ¿cuál es mejor: Llama-3-8B, Mistral-7B o Qwen-7B?\" → elige 3 + X-2 + 16K → ve el ganador.",
|
| 788 |
|
|
@@ -1103,7 +1215,7 @@ export const TRANSLATIONS = {
|
|
| 1103 |
"inv.export.formats": "<strong>JSON · Markdown · LaTeX</strong> (prêt pour papier)",
|
| 1104 |
"inv.export.share": "Lien reproductible (état encodé dans l'URL)",
|
| 1105 |
"inv.export.registry": "Soumettre au registre communautaire sur GitHub",
|
| 1106 |
-
"arch.summary": "Architectures prises en charge
|
| 1107 |
"arch.anyhf": "✓ Tout modèle public HuggingFace",
|
| 1108 |
"tooltip.mha": "Multi-Head Attention : chaque position attend via plusieurs têtes parallèles à la fois.",
|
| 1109 |
"tooltip.gqa": "Grouped Query Attention : les queries partagent moins de keys/values que de heads (économise mémoire mais pousse γ vers Hagedorn).",
|
|
@@ -1111,6 +1223,62 @@ export const TRANSLATIONS = {
|
|
| 1111 |
"tooltip.abspe": "Absolute Position Embeddings : chaque position a un vecteur fixe appris ajouté au token.",
|
| 1112 |
"tooltip.swa": "Sliding Window Attention : chaque token n'attend que dans une fenêtre locale fixe (Mistral, gemma-2 l'utilisent).",
|
| 1113 |
"tooltip.ssm": "State Space Model : couche de séquence qui maintient un état interne au lieu d'attention (Mamba, Jamba l'utilisent).",
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1114 |
"share.import_desc": "Vous avez un fichier JSON de l'analyse TAF de quelqu'un ? Chargez-le ici pour voir le verdict + la chaîne localement. La même vue que si vous l'aviez exécuté vous-même.",
|
| 1115 |
"share.import_btn": "📂 Charger JSON partagé",
|
| 1116 |
"synthesis.system": "Vous êtes un assistant de diagnostic précis pour LLMs transformer. Étant donné des résultats de formules TAF pré-calculés, écrivez un résumé clair en français de 4-6 phrases. Citez le numéro de section (§X.Y) pour chaque nombre mentionné. Donnez toujours une recommandation concrète. N'INVENTEZ PAS de nombres.",
|
|
@@ -1203,7 +1371,7 @@ export const TRANSLATIONS = {
|
|
| 1203 |
"common.no": "Non",
|
| 1204 |
|
| 1205 |
// Tooltips des modes
|
| 1206 |
-
"modes.tip": "<strong>
|
| 1207 |
"profile.tip": "<strong>Diagnostic complet en un clic</strong>. Collez n'importe quel id de modèle HF (ou choisissez préréglage). L'outil exécute les 5 recettes (contexte long, compression KV, custom vs API, budget, hardware) et produit une <strong>TAF Card</strong> unique avec verdict par dimension + nombres clés + classification architecturale.<br><br><strong>Cas d'usage</strong>: « J'évalue Qwen2.5-32B pour la production — quel est son profil complet de viabilité ? » → collez id → Profiler → fait.",
|
| 1208 |
"compare.tip": "<strong>Même recette, plusieurs modèles</strong>. Choisissez 2-3 modèles candidats et une recette. Voyez les verdicts dans un seul tableau comparatif.<br><br><strong>Cas d'usage</strong>: « J'ai besoin de récupération longue contexte à 16K — quel est le meilleur : Llama-3-8B, Mistral-7B ou Qwen-7B ? » → choisissez 3 + X-2 + 16K → voyez le gagnant.",
|
| 1209 |
|
|
@@ -1524,7 +1692,7 @@ export const TRANSLATIONS = {
|
|
| 1524 |
"inv.export.formats": "<strong>JSON · Markdown · LaTeX</strong>(论文级)",
|
| 1525 |
"inv.export.share": "可复现的分享链接(状态编入 URL)",
|
| 1526 |
"inv.export.registry": "提交到 GitHub 上的社区登记",
|
| 1527 |
-
"arch.summary": "支持的架构
|
| 1528 |
"arch.anyhf": "✓ 任意 HuggingFace 公开模型",
|
| 1529 |
"tooltip.mha": "Multi-Head Attention:每个 token 位置同时通过多个并行 head 进行注意力计算。",
|
| 1530 |
"tooltip.gqa": "Grouped Query Attention:queries 共享比 heads 更少的 keys/values(节省内存但把 γ 推向 Hagedorn)。",
|
|
@@ -1532,6 +1700,62 @@ export const TRANSLATIONS = {
|
|
| 1532 |
"tooltip.abspe": "Absolute Position Embeddings:每个位置有一个固定的学习向量加到 token embedding。",
|
| 1533 |
"tooltip.swa": "Sliding Window Attention:每个 token 仅在固定局部窗口内做注意力(Mistral、gemma-2 使用此机制)。",
|
| 1534 |
"tooltip.ssm": "State Space Model:维护内部状态的序列层(取代注意力,Mamba、Jamba 使用此机制)。",
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1535 |
"share.import_desc": "有他人 TAF 分析的 JSON 文件? 在这里加载以本地查看判定 + 链。与您自己运行的视图相同。",
|
| 1536 |
"share.import_btn": "📂 加载共享的 JSON",
|
| 1537 |
"synthesis.system": "您是 transformer LLM 的精确诊断助手。给定预先计算的 TAF 公式结果,用 4-6 句中文写出清晰的摘要。为每个提到的数字引用章节号 (§X.Y)。始终给出具体建议。不要编造数字。",
|
|
@@ -1624,7 +1848,7 @@ export const TRANSLATIONS = {
|
|
| 1624 |
"common.no": "否",
|
| 1625 |
|
| 1626 |
// 模式提示
|
| 1627 |
-
"modes.tip": "<strong>
|
| 1628 |
"profile.tip": "<strong>一键完整诊断</strong>。粘贴任意 HF 模型 id (或选择预设)。工具运行所有 5 个配方 (长上下文、KV 压缩、自定义 vs API、预算、硬件),生成单个 <strong>TAF 卡</strong>,显示每个维度的判定 + 关键数字 + 架构分类。<br><br><strong>用例</strong>: \"我正在为生产评估 Qwen2.5-32B — 它的完整可行性概况是什么?\" → 粘贴 id → 画像 → 完成。",
|
| 1629 |
"compare.tip": "<strong>同一配方,多个模型</strong>。选择 2-3 个候选模型和一个配方。在单个比较表中查看判定。<br><br><strong>用例</strong>: \"我需要在 16K 进行长上下文检索 — 哪个最好: Llama-3-8B、Mistral-7B 或 Qwen-7B?\" → 选择 3 个 + X-2 + 16K → 看赢家。",
|
| 1630 |
|
|
|
|
| 125 |
"inv.export.formats": "<strong>JSON · Markdown · LaTeX</strong> (paper-ready)",
|
| 126 |
"inv.export.share": "Reproducible share link (state encoded in URL)",
|
| 127 |
"inv.export.registry": "Submit to community registry on GitHub",
|
| 128 |
+
"arch.summary": "Architectures supported",
|
| 129 |
"arch.anyhf": "✓ Any HuggingFace public model",
|
| 130 |
"tooltip.mha": "Multi-Head Attention: each token position attends through several parallel heads at once.",
|
| 131 |
"tooltip.gqa": "Grouped Query Attention: queries share fewer keys/values than heads (saves memory but pushes γ toward Hagedorn).",
|
|
|
|
| 133 |
"tooltip.abspe": "Absolute Position Embeddings: each position has a fixed learned vector added to the token embedding.",
|
| 134 |
"tooltip.swa": "Sliding Window Attention: each token only attends within a fixed local window (Mistral, gemma-2 use this).",
|
| 135 |
"tooltip.ssm": "State Space Model: a sequence layer that maintains internal state instead of attention (Mamba, Jamba use this).",
|
| 136 |
+
|
| 137 |
+
// v0.7.0 — anti-bullshit pack #1: SWA / RoPE-scaling unmasker
|
| 138 |
+
"modes.unmask": "🪟 Unmask",
|
| 139 |
+
"unmask.title": "🪟 Context Unmasker",
|
| 140 |
+
"unmask.tip": "Paste a HuggingFace model id (or raw config.json). The tool checks for sliding-window attention, RoPE scaling (YaRN/linear/dynamic NTK), and GQA — anything that makes <code>max_position_embeddings</code> larger than the practical effective context. Mistral-7B-v0.1 is the canonical example: declared 32k, attends within ~4-8k.",
|
| 141 |
+
"unmask.desc": "<strong>Are you about to spend money on a model that won't actually attend that far?</strong> Paste an id and find out in 1 second. No GPU, no inference — just config.json arithmetic.",
|
| 142 |
+
"unmask.id_label": "HF model id:",
|
| 143 |
+
"unmask.fetch_btn": "🔍 Unmask",
|
| 144 |
+
"unmask.paste_summary": "Or paste raw config.json (private / in-dev models)",
|
| 145 |
+
"unmask.paste_btn": "🔍 Unmask pasted config",
|
| 146 |
+
"unmask.label.declared": "Declared context",
|
| 147 |
+
"unmask.label.effective": "Effective (estimate)",
|
| 148 |
+
"unmask.label.ratio": "Ratio",
|
| 149 |
+
"unmask.section.flags": "Architecture flags",
|
| 150 |
+
"unmask.section.warnings": "Warnings",
|
| 151 |
+
"unmask.section.reco": "Recommendation",
|
| 152 |
+
"unmask.flag.swa": "SWA",
|
| 153 |
+
"unmask.flag.rope": "RoPE scaling",
|
| 154 |
+
"unmask.flag.gqa": "GQA",
|
| 155 |
+
"unmask.flag.layers": "Layers",
|
| 156 |
+
"unmask.flag.dhead": "d_head",
|
| 157 |
+
"unmask.flag.theta": "RoPE θ",
|
| 158 |
+
"unmask.flag.yes": "yes",
|
| 159 |
+
"unmask.flag.no": "no",
|
| 160 |
+
"unmask.flag.full_mha": "no (full MHA, {n} heads)",
|
| 161 |
+
"unmask.verdict.honest": "✅ HONEST",
|
| 162 |
+
"unmask.verdict.inflated": "⚠ INFLATED",
|
| 163 |
+
"unmask.verdict.severely_inflated": "❌ SEVERELY INFLATED",
|
| 164 |
+
"unmask.verdict.yarn_extended": "⚠ YARN-EXTENDED",
|
| 165 |
+
"unmask.verdict.unknown": "❓ UNKNOWN",
|
| 166 |
+
"unmask.warn.swa_window": "SWA window: {window} tokens — each layer only attends within this window.",
|
| 167 |
+
"unmask.warn.multihop": "Multi-hop estimate: ~{multiHop} tokens (conservative: window × {factor}).",
|
| 168 |
+
"unmask.warn.yarn": "RoPE scaling ({type}) extends context {factor}× from ~{original} to {declared} tokens.",
|
| 169 |
+
"unmask.warn.yarn_advice": "RoPE-extended context — verify γ behavior at the full claimed length with the γ_check diagnostic.",
|
| 170 |
+
"unmask.warn.gqa_small_dhead": "Small head dim ({d_head}) + GQA: KV cache compression at long context is likely (γ pushed toward Hagedorn).",
|
| 171 |
+
"unmask.reco.honest": "Standard full-attention model. Effective context matches declared ({declared} tokens).",
|
| 172 |
+
"unmask.reco.inflated": "Effective ~{effective} tokens via SWA. Use γ_check to verify behavior at your target evaluation length.",
|
| 173 |
+
"unmask.reco.severely_inflated": "Treat as a ~{effective}-token context model in practice. The {declared}-token claim only applies via cross-layer attention chains, which empirically degrade past ~2× the SWA window.",
|
| 174 |
+
"unmask.reco.yarn_extended": "RoPE-extended context. Run a long-context benchmark (NIAH at 8k / 16k / 32k / full) to confirm the extension holds. Use γ_check with T_eval = {declared}.",
|
| 175 |
+
"unmask.reco.unknown": "Could not parse config. Verify the URL is a valid HF model with public config.json.",
|
| 176 |
+
"unmask.status.empty_id": "⚠ Enter a model id (e.g. mistralai/Mistral-7B-v0.1).",
|
| 177 |
+
"unmask.status.fetching": "⏳ Fetching config.json for {modelId}...",
|
| 178 |
+
"unmask.status.success": "✅ Analyzed {modelId} (verdict: {verdict})",
|
| 179 |
+
"unmask.status.empty_paste": "⚠ Paste a config.json first.",
|
| 180 |
+
"unmask.status.invalid_json": "❌ Not valid JSON: {error}",
|
| 181 |
+
"unmask.status.success_paste": "✅ Analyzed pasted config (verdict: {verdict})",
|
| 182 |
+
"unmask.pasted_label": "(pasted config)",
|
| 183 |
+
"mode_desc.ask": "Type a free-form question. The in-browser LLM picks the right recipe and runs it.",
|
| 184 |
+
"mode_desc.recipe": "Pick a recipe directly and fill the form. Full manual control.",
|
| 185 |
+
"mode_desc.profile": "Quickest start: paste any HuggingFace model id, click Profile. See all 5 recipes scored in seconds.",
|
| 186 |
+
"mode_desc.compare": "Pick 2-3 candidate models + one recipe. See verdicts side-by-side in a comparison table.",
|
| 187 |
+
"mode_desc.inspector": "Paste a config.json directly. Useful for private/in-development models not on HF Hub.",
|
| 188 |
+
"mode_desc.diagnose": "Build the diagnose_model.py CLI command to MEASURE γ_obs on real GPU. Browser predicts; CLI measures.",
|
| 189 |
+
"mode_desc.phase": "γ × θ scatter of the paper's empirical panel. Hover a dot for details, click to load into Diagnose / Recipe forms.",
|
| 190 |
+
"mode_desc.unmask": "Detects whether max_position_embeddings is misleading (SWA / YaRN / RoPE-scaling). Paste a model id, get a 1-line verdict.",
|
| 191 |
+
"profile.preset_loaded": "✅ Loaded preset for <strong>{id}</strong>. Form pre-filled. (Click 📥 Fetch to override with the latest config from HF Hub.)",
|
| 192 |
"share.import_desc": "Got a JSON file from someone else's TAF analysis? Load it here to see the verdict + chain locally. Same view as if you'd run it yourself.",
|
| 193 |
"share.import_btn": "📂 Load shared JSON",
|
| 194 |
"synthesis.system": "You are a precise transformer LLM diagnostic assistant. Given pre-computed TAF formula results, write a clear plain-English summary in 4-6 sentences. Cite the section number (§X.Y) for each number you mention. Always give a concrete recommendation. Do NOT invent numbers.",
|
|
|
|
| 281 |
"common.no": "No",
|
| 282 |
|
| 283 |
// Mode tooltips
|
| 284 |
+
"modes.tip": "<strong>Eight ways to use the tool</strong>.<br><strong>📇 Profile</strong>: paste a model id → 5-recipe TAF Card.<br><strong>🆚 Compare</strong>: 2-3 models side-by-side on one recipe.<br><strong>🔍 Inspect config</strong>: paste raw config.json → full Profile.<br><strong>💬 Ask</strong>: free-form question, browser LLM picks the recipe.<br><strong>📋 Recipe</strong>: manual selection with full form control.<br><strong>🩺 Diagnose CLI</strong>: generate Python command for local γ measurement.<br><strong>📊 Phase diagram</strong>: 23-model panel on (log θ, γ) plane.<br><strong>🪟 Unmask</strong>: detect misleading max_position_embeddings (SWA / YaRN / RoPE-scaling).",
|
| 285 |
"profile.tip": "<strong>One-click full diagnosis</strong>. Paste any HF model id (or pick preset). Tool runs all 5 recipes (long-context, KV-compression, custom-vs-API, budget, hardware) and produces a single <strong>TAF Card</strong> with verdict per dimension + key numbers + architecture classification.<br><br><strong>Use case</strong>: \"I'm evaluating Qwen2.5-32B for production — what's its full viability profile?\" → paste id → Profile → done.",
|
| 286 |
"compare.tip": "<strong>Same recipe, multiple models</strong>. Pick 2-3 candidate models and one recipe. See verdicts in a single comparison table.<br><br><strong>Use case</strong>: \"I need long-context retrieval at 16K — which is best: Llama-3-8B, Mistral-7B, or Qwen-7B?\" → pick 3 + X-2 + 16K → see winner.",
|
| 287 |
|
|
|
|
| 738 |
"inv.export.formats": "<strong>JSON · Markdown · LaTeX</strong> (listo para paper)",
|
| 739 |
"inv.export.share": "Link reproducible (estado codificado en URL)",
|
| 740 |
"inv.export.registry": "Envía al registro comunitario en GitHub",
|
| 741 |
+
"arch.summary": "Arquitecturas soportadas",
|
| 742 |
"arch.anyhf": "✓ Cualquier modelo público de HuggingFace",
|
| 743 |
"tooltip.mha": "Multi-Head Attention: cada posición atiende mediante varios heads paralelos a la vez.",
|
| 744 |
"tooltip.gqa": "Grouped Query Attention: las queries comparten menos keys/values que heads (ahorra memoria pero empuja γ hacia Hagedorn).",
|
|
|
|
| 746 |
"tooltip.abspe": "Absolute Position Embeddings: cada posición tiene un vector fijo aprendido sumado al embedding del token.",
|
| 747 |
"tooltip.swa": "Sliding Window Attention: cada token solo atiende dentro de una ventana local fija (Mistral, gemma-2 lo usan).",
|
| 748 |
"tooltip.ssm": "State Space Model: capa de secuencia que mantiene estado interno en lugar de atención (Mamba, Jamba lo usan).",
|
| 749 |
+
|
| 750 |
+
// v0.7.0 — anti-bullshit pack #1: SWA / RoPE-scaling unmasker
|
| 751 |
+
"modes.unmask": "🪟 Desenmascarar",
|
| 752 |
+
"unmask.title": "🪟 Desenmascarador de contexto",
|
| 753 |
+
"unmask.tip": "Pega un id de modelo HuggingFace (o config.json crudo). La herramienta detecta sliding-window attention, RoPE scaling (YaRN/linear/dynamic NTK), y GQA — todo lo que hace que <code>max_position_embeddings</code> sea mayor que el contexto efectivo real. Mistral-7B-v0.1 es el ejemplo canónico: declara 32k, atiende dentro de ~4-8k.",
|
| 754 |
+
"unmask.desc": "<strong>¿Estás a punto de gastar dinero en un modelo que en realidad no atiende tan lejos?</strong> Pega un id y descúbrelo en 1 segundo. Sin GPU, sin inferencia — solo aritmética sobre config.json.",
|
| 755 |
+
"unmask.id_label": "ID modelo HF:",
|
| 756 |
+
"unmask.fetch_btn": "🔍 Desenmascarar",
|
| 757 |
+
"unmask.paste_summary": "O pega config.json crudo (modelos privados / en desarrollo)",
|
| 758 |
+
"unmask.paste_btn": "🔍 Desenmascarar config pegado",
|
| 759 |
+
"unmask.label.declared": "Contexto declarado",
|
| 760 |
+
"unmask.label.effective": "Efectivo (estimado)",
|
| 761 |
+
"unmask.label.ratio": "Ratio",
|
| 762 |
+
"unmask.section.flags": "Banderas de arquitectura",
|
| 763 |
+
"unmask.section.warnings": "Avisos",
|
| 764 |
+
"unmask.section.reco": "Recomendación",
|
| 765 |
+
"unmask.flag.swa": "SWA",
|
| 766 |
+
"unmask.flag.rope": "RoPE scaling",
|
| 767 |
+
"unmask.flag.gqa": "GQA",
|
| 768 |
+
"unmask.flag.layers": "Capas",
|
| 769 |
+
"unmask.flag.dhead": "d_head",
|
| 770 |
+
"unmask.flag.theta": "RoPE θ",
|
| 771 |
+
"unmask.flag.yes": "sí",
|
| 772 |
+
"unmask.flag.no": "no",
|
| 773 |
+
"unmask.flag.full_mha": "no (MHA completo, {n} heads)",
|
| 774 |
+
"unmask.verdict.honest": "✅ HONESTO",
|
| 775 |
+
"unmask.verdict.inflated": "⚠ INFLADO",
|
| 776 |
+
"unmask.verdict.severely_inflated": "❌ GRAVEMENTE INFLADO",
|
| 777 |
+
"unmask.verdict.yarn_extended": "⚠ YARN-EXTENDIDO",
|
| 778 |
+
"unmask.verdict.unknown": "❓ DESCONOCIDO",
|
| 779 |
+
"unmask.warn.swa_window": "Ventana SWA: {window} tokens — cada capa solo atiende dentro de esta ventana.",
|
| 780 |
+
"unmask.warn.multihop": "Estimación multi-hop: ~{multiHop} tokens (conservador: ventana × {factor}).",
|
| 781 |
+
"unmask.warn.yarn": "RoPE scaling ({type}) extiende contexto {factor}× desde ~{original} hasta {declared} tokens.",
|
| 782 |
+
"unmask.warn.yarn_advice": "Contexto RoPE-extendido — verifica el comportamiento de γ a la longitud declarada con el diagnóstico γ_check.",
|
| 783 |
+
"unmask.warn.gqa_small_dhead": "head dim pequeño ({d_head}) + GQA: probable compresión de KV cache a contexto largo (γ empujado hacia Hagedorn).",
|
| 784 |
+
"unmask.reco.honest": "Modelo de atención completa estándar. Contexto efectivo coincide con declarado ({declared} tokens).",
|
| 785 |
+
"unmask.reco.inflated": "Efectivo ~{effective} tokens vía SWA. Usa γ_check para verificar el comportamiento a tu longitud objetivo.",
|
| 786 |
+
"unmask.reco.severely_inflated": "Trátalo como un modelo de ~{effective} tokens en la práctica. El claim de {declared} tokens solo aplica vía cadenas de atención cross-layer, que empíricamente degradan más allá de ~2× la ventana SWA.",
|
| 787 |
+
"unmask.reco.yarn_extended": "Contexto RoPE-extendido. Corre un benchmark long-context (NIAH a 8k / 16k / 32k / full) para confirmar que la extensión se sostiene. Usa γ_check con T_eval = {declared}.",
|
| 788 |
+
"unmask.reco.unknown": "No se pudo parsear el config. Verifica que la URL sea un modelo HF válido con config.json público.",
|
| 789 |
+
"unmask.status.empty_id": "⚠ Introduce un model id (ej. mistralai/Mistral-7B-v0.1).",
|
| 790 |
+
"unmask.status.fetching": "⏳ Obteniendo config.json para {modelId}...",
|
| 791 |
+
"unmask.status.success": "✅ Analizado {modelId} (veredicto: {verdict})",
|
| 792 |
+
"unmask.status.empty_paste": "⚠ Pega un config.json primero.",
|
| 793 |
+
"unmask.status.invalid_json": "❌ JSON inválido: {error}",
|
| 794 |
+
"unmask.status.success_paste": "✅ Config pegado analizado (veredicto: {verdict})",
|
| 795 |
+
"unmask.pasted_label": "(config pegado)",
|
| 796 |
+
"mode_desc.ask": "Escribe una pregunta libre. El LLM en el navegador elige la receta correcta y la ejecuta.",
|
| 797 |
+
"mode_desc.recipe": "Selecciona una receta directamente y rellena el formulario. Control manual completo.",
|
| 798 |
+
"mode_desc.profile": "Inicio más rápido: pega cualquier model id de HuggingFace, click Profile. Mira las 5 recetas en segundos.",
|
| 799 |
+
"mode_desc.compare": "Elige 2-3 modelos candidatos + una receta. Ve veredictos lado a lado en tabla.",
|
| 800 |
+
"mode_desc.inspector": "Pega un config.json directamente. Útil para modelos privados / en desarrollo no en HF Hub.",
|
| 801 |
+
"mode_desc.diagnose": "Construye el comando CLI diagnose_model.py para MEDIR γ_obs en GPU real. El navegador predice; el CLI mide.",
|
| 802 |
+
"mode_desc.phase": "Scatter γ × θ del panel empírico del paper. Hover sobre puntos para detalles, click para cargar en Diagnose / Recipe.",
|
| 803 |
+
"mode_desc.unmask": "Detecta si max_position_embeddings es engañoso (SWA / YaRN / RoPE-scaling). Pega un model id, obtén un veredicto en 1 línea.",
|
| 804 |
+
"profile.preset_loaded": "✅ Preset cargado para <strong>{id}</strong>. Formulario pre-rellenado. (Click 📥 Fetch para sobreescribir con el último config de HF Hub.)",
|
| 805 |
"share.import_desc": "¿Tienes un fichero JSON del análisis TAF de alguien? Cárgalo aquí para ver el veredicto + cadena localmente. La misma vista que si lo hubieras ejecutado tú.",
|
| 806 |
"share.import_btn": "📂 Cargar JSON compartido",
|
| 807 |
"synthesis.system": "Eres un asistente de diagnóstico preciso para LLMs transformer. Dados resultados de fórmulas TAF pre-calculados, escribe un resumen claro en español de 4-6 frases. Cita el número de sección (§X.Y) para cada número que menciones. Da siempre una recomendación concreta. NO inventes números.",
|
|
|
|
| 894 |
"common.no": "No",
|
| 895 |
|
| 896 |
// Tooltips de modos
|
| 897 |
+
"modes.tip": "<strong>Ocho formas de usar la herramienta</strong>.<br><strong>📇 Perfil</strong>: pega un id → TAF Card de 5 recetas.<br><strong>🆚 Comparar</strong>: 2-3 modelos lado a lado en una receta.<br><strong>🔍 Inspeccionar config</strong>: pega config.json crudo → Perfil completo.<br><strong>💬 Pregunta</strong>: pregunta libre, el LLM del navegador elige la receta.<br><strong>📋 Receta</strong>: selección manual con control total del formulario.<br><strong>🩺 Diagnóstico CLI</strong>: genera comando Python para medir γ localmente.<br><strong>📊 Diagrama de fase</strong>: panel de 23 modelos en plano (log θ, γ).<br><strong>🪟 Desenmascarar</strong>: detecta max_position_embeddings engañoso (SWA / YaRN / RoPE-scaling).",
|
| 898 |
"profile.tip": "<strong>Diagnóstico completo en un click</strong>. Pega cualquier id de modelo HF (o elige preset). La herramienta ejecuta las 5 recetas (contexto largo, compresión KV, custom vs API, presupuesto, hardware) y produce una única <strong>TAF Card</strong> con veredicto por dimensión + números clave + clasificación arquitectónica.<br><br><strong>Caso de uso</strong>: \"Estoy evaluando Qwen2.5-32B para producción — ¿cuál es su perfil completo de viabilidad?\" → pega id → Perfilar → listo.",
|
| 899 |
"compare.tip": "<strong>Misma receta, múltiples modelos</strong>. Elige 2-3 modelos candidatos y una receta. Ve los veredictos en una única tabla comparativa.<br><br><strong>Caso de uso</strong>: \"Necesito recuperación de contexto largo a 16K — ¿cuál es mejor: Llama-3-8B, Mistral-7B o Qwen-7B?\" → elige 3 + X-2 + 16K → ve el ganador.",
|
| 900 |
|
|
|
|
| 1215 |
"inv.export.formats": "<strong>JSON · Markdown · LaTeX</strong> (prêt pour papier)",
|
| 1216 |
"inv.export.share": "Lien reproductible (état encodé dans l'URL)",
|
| 1217 |
"inv.export.registry": "Soumettre au registre communautaire sur GitHub",
|
| 1218 |
+
"arch.summary": "Architectures prises en charge",
|
| 1219 |
"arch.anyhf": "✓ Tout modèle public HuggingFace",
|
| 1220 |
"tooltip.mha": "Multi-Head Attention : chaque position attend via plusieurs têtes parallèles à la fois.",
|
| 1221 |
"tooltip.gqa": "Grouped Query Attention : les queries partagent moins de keys/values que de heads (économise mémoire mais pousse γ vers Hagedorn).",
|
|
|
|
| 1223 |
"tooltip.abspe": "Absolute Position Embeddings : chaque position a un vecteur fixe appris ajouté au token.",
|
| 1224 |
"tooltip.swa": "Sliding Window Attention : chaque token n'attend que dans une fenêtre locale fixe (Mistral, gemma-2 l'utilisent).",
|
| 1225 |
"tooltip.ssm": "State Space Model : couche de séquence qui maintient un état interne au lieu d'attention (Mamba, Jamba l'utilisent).",
|
| 1226 |
+
|
| 1227 |
+
// v0.7.0 — anti-bullshit pack #1: SWA / RoPE-scaling unmasker
|
| 1228 |
+
"modes.unmask": "🪟 Démasquer",
|
| 1229 |
+
"unmask.title": "🪟 Démasqueur de contexte",
|
| 1230 |
+
"unmask.tip": "Collez un id de modèle HuggingFace (ou config.json brut). L'outil détecte sliding-window attention, RoPE scaling (YaRN/linear/dynamic NTK), et GQA — tout ce qui rend <code>max_position_embeddings</code> plus grand que le contexte effectif réel. Mistral-7B-v0.1 est l'exemple canonique : déclare 32k, attend dans ~4-8k.",
|
| 1231 |
+
"unmask.desc": "<strong>Êtes-vous sur le point de dépenser de l'argent sur un modèle qui n'attend pas vraiment aussi loin ?</strong> Collez un id et découvrez-le en 1 seconde. Sans GPU, sans inférence — juste de l'arithmétique sur config.json.",
|
| 1232 |
+
"unmask.id_label": "ID modèle HF :",
|
| 1233 |
+
"unmask.fetch_btn": "🔍 Démasquer",
|
| 1234 |
+
"unmask.paste_summary": "Ou collez config.json brut (modèles privés / en dev)",
|
| 1235 |
+
"unmask.paste_btn": "🔍 Démasquer config collé",
|
| 1236 |
+
"unmask.label.declared": "Contexte déclaré",
|
| 1237 |
+
"unmask.label.effective": "Effectif (estimé)",
|
| 1238 |
+
"unmask.label.ratio": "Ratio",
|
| 1239 |
+
"unmask.section.flags": "Drapeaux d'architecture",
|
| 1240 |
+
"unmask.section.warnings": "Avertissements",
|
| 1241 |
+
"unmask.section.reco": "Recommandation",
|
| 1242 |
+
"unmask.flag.swa": "SWA",
|
| 1243 |
+
"unmask.flag.rope": "RoPE scaling",
|
| 1244 |
+
"unmask.flag.gqa": "GQA",
|
| 1245 |
+
"unmask.flag.layers": "Couches",
|
| 1246 |
+
"unmask.flag.dhead": "d_head",
|
| 1247 |
+
"unmask.flag.theta": "RoPE θ",
|
| 1248 |
+
"unmask.flag.yes": "oui",
|
| 1249 |
+
"unmask.flag.no": "non",
|
| 1250 |
+
"unmask.flag.full_mha": "non (MHA complet, {n} heads)",
|
| 1251 |
+
"unmask.verdict.honest": "✅ HONNÊTE",
|
| 1252 |
+
"unmask.verdict.inflated": "⚠ GONFLÉ",
|
| 1253 |
+
"unmask.verdict.severely_inflated": "❌ GRAVEMENT GONFLÉ",
|
| 1254 |
+
"unmask.verdict.yarn_extended": "⚠ YARN-ÉTENDU",
|
| 1255 |
+
"unmask.verdict.unknown": "❓ INCONNU",
|
| 1256 |
+
"unmask.warn.swa_window": "Fenêtre SWA : {window} tokens — chaque couche n'attend que dans cette fenêtre.",
|
| 1257 |
+
"unmask.warn.multihop": "Estimation multi-hop : ~{multiHop} tokens (conservateur : fenêtre × {factor}).",
|
| 1258 |
+
"unmask.warn.yarn": "RoPE scaling ({type}) étend le contexte {factor}× de ~{original} à {declared} tokens.",
|
| 1259 |
+
"unmask.warn.yarn_advice": "Contexte RoPE-étendu — vérifiez le comportement de γ à la longueur déclarée avec le diagnostic γ_check.",
|
| 1260 |
+
"unmask.warn.gqa_small_dhead": "Petite head dim ({d_head}) + GQA : compression de KV cache probable en contexte long (γ poussé vers Hagedorn).",
|
| 1261 |
+
"unmask.reco.honest": "Modèle d'attention complète standard. Contexte effectif correspond au déclaré ({declared} tokens).",
|
| 1262 |
+
"unmask.reco.inflated": "Effectif ~{effective} tokens via SWA. Utilisez γ_check pour vérifier le comportement à votre longueur cible.",
|
| 1263 |
+
"unmask.reco.severely_inflated": "Traitez-le comme un modèle de ~{effective} tokens en pratique. Le claim de {declared} tokens ne s'applique que via des chaînes d'attention cross-layer, qui dégradent empiriquement au-delà de ~2× la fenêtre SWA.",
|
| 1264 |
+
"unmask.reco.yarn_extended": "Contexte RoPE-étendu. Lancez un benchmark long-context (NIAH à 8k / 16k / 32k / full) pour confirmer que l'extension tient. Utilisez γ_check avec T_eval = {declared}.",
|
| 1265 |
+
"unmask.reco.unknown": "Impossible de parser le config. Vérifiez que l'URL est un modèle HF valide avec config.json public.",
|
| 1266 |
+
"unmask.status.empty_id": "⚠ Saisissez un model id (ex. mistralai/Mistral-7B-v0.1).",
|
| 1267 |
+
"unmask.status.fetching": "⏳ Récupération config.json pour {modelId}...",
|
| 1268 |
+
"unmask.status.success": "✅ {modelId} analysé (verdict : {verdict})",
|
| 1269 |
+
"unmask.status.empty_paste": "⚠ Collez d'abord un config.json.",
|
| 1270 |
+
"unmask.status.invalid_json": "❌ JSON invalide : {error}",
|
| 1271 |
+
"unmask.status.success_paste": "✅ Config collé analysé (verdict : {verdict})",
|
| 1272 |
+
"unmask.pasted_label": "(config collé)",
|
| 1273 |
+
"mode_desc.ask": "Tapez une question libre. Le LLM dans le navigateur choisit la recette et l'exécute.",
|
| 1274 |
+
"mode_desc.recipe": "Sélectionnez une recette directement et remplissez le formulaire. Contrôle manuel complet.",
|
| 1275 |
+
"mode_desc.profile": "Démarrage le plus rapide : collez n'importe quel model id HuggingFace, cliquez Profile. Voyez les 5 recettes en quelques secondes.",
|
| 1276 |
+
"mode_desc.compare": "Choisissez 2-3 modèles candidats + une recette. Verdicts côte à côte dans un tableau.",
|
| 1277 |
+
"mode_desc.inspector": "Collez un config.json directement. Utile pour modèles privés / en dev non publiés sur HF Hub.",
|
| 1278 |
+
"mode_desc.diagnose": "Construit la commande CLI diagnose_model.py pour MESURER γ_obs sur GPU réel. Le navigateur prédit ; le CLI mesure.",
|
| 1279 |
+
"mode_desc.phase": "Scatter γ × θ du panel empirique du papier. Survolez les points pour détails, cliquez pour charger dans Diagnose / Recipe.",
|
| 1280 |
+
"mode_desc.unmask": "Détecte si max_position_embeddings est trompeur (SWA / YaRN / RoPE-scaling). Collez un model id, obtenez un verdict en 1 ligne.",
|
| 1281 |
+
"profile.preset_loaded": "✅ Préréglage chargé pour <strong>{id}</strong>. Formulaire pré-rempli. (Cliquez 📥 Fetch pour écraser avec le dernier config depuis HF Hub.)",
|
| 1282 |
"share.import_desc": "Vous avez un fichier JSON de l'analyse TAF de quelqu'un ? Chargez-le ici pour voir le verdict + la chaîne localement. La même vue que si vous l'aviez exécuté vous-même.",
|
| 1283 |
"share.import_btn": "📂 Charger JSON partagé",
|
| 1284 |
"synthesis.system": "Vous êtes un assistant de diagnostic précis pour LLMs transformer. Étant donné des résultats de formules TAF pré-calculés, écrivez un résumé clair en français de 4-6 phrases. Citez le numéro de section (§X.Y) pour chaque nombre mentionné. Donnez toujours une recommandation concrète. N'INVENTEZ PAS de nombres.",
|
|
|
|
| 1371 |
"common.no": "Non",
|
| 1372 |
|
| 1373 |
// Tooltips des modes
|
| 1374 |
+
"modes.tip": "<strong>Huit façons d'utiliser l'outil</strong>.<br><strong>📇 Profil</strong>: collez un id → TAF Card avec 5 recettes.<br><strong>🆚 Comparer</strong>: 2-3 modèles côte à côte sur une recette.<br><strong>🔍 Inspecter config</strong>: collez config.json brut → Profil complet.<br><strong>💬 Question</strong>: question libre, le LLM du navigateur choisit la recette.<br><strong>📋 Recette</strong>: sélection manuelle avec contrôle total du formulaire.<br><strong>🩺 Diagnostic CLI</strong>: génère commande Python pour mesurer γ localement.<br><strong>📊 Diagramme de phase</strong>: panel de 23 modèles dans le plan (log θ, γ).<br><strong>🪟 Démasquer</strong>: détecte un max_position_embeddings trompeur (SWA / YaRN / RoPE-scaling).",
|
| 1375 |
"profile.tip": "<strong>Diagnostic complet en un clic</strong>. Collez n'importe quel id de modèle HF (ou choisissez préréglage). L'outil exécute les 5 recettes (contexte long, compression KV, custom vs API, budget, hardware) et produit une <strong>TAF Card</strong> unique avec verdict par dimension + nombres clés + classification architecturale.<br><br><strong>Cas d'usage</strong>: « J'évalue Qwen2.5-32B pour la production — quel est son profil complet de viabilité ? » → collez id → Profiler → fait.",
|
| 1376 |
"compare.tip": "<strong>Même recette, plusieurs modèles</strong>. Choisissez 2-3 modèles candidats et une recette. Voyez les verdicts dans un seul tableau comparatif.<br><br><strong>Cas d'usage</strong>: « J'ai besoin de récupération longue contexte à 16K — quel est le meilleur : Llama-3-8B, Mistral-7B ou Qwen-7B ? » → choisissez 3 + X-2 + 16K → voyez le gagnant.",
|
| 1377 |
|
|
|
|
| 1692 |
"inv.export.formats": "<strong>JSON · Markdown · LaTeX</strong>(论文级)",
|
| 1693 |
"inv.export.share": "可复现的分享链接(状态编入 URL)",
|
| 1694 |
"inv.export.registry": "提交到 GitHub 上的社区登记",
|
| 1695 |
+
"arch.summary": "支持的架构",
|
| 1696 |
"arch.anyhf": "✓ 任意 HuggingFace 公开模型",
|
| 1697 |
"tooltip.mha": "Multi-Head Attention:每个 token 位置同时通过多个并行 head 进行注意力计算。",
|
| 1698 |
"tooltip.gqa": "Grouped Query Attention:queries 共享比 heads 更少的 keys/values(节省内存但把 γ 推向 Hagedorn)。",
|
|
|
|
| 1700 |
"tooltip.abspe": "Absolute Position Embeddings:每个位置有一个固定的学习向量加到 token embedding。",
|
| 1701 |
"tooltip.swa": "Sliding Window Attention:每个 token 仅在固定局部窗口内做注意力(Mistral、gemma-2 使用此机制)。",
|
| 1702 |
"tooltip.ssm": "State Space Model:维护内部状态的序列层(取代注意力,Mamba、Jamba 使用此机制)。",
|
| 1703 |
+
|
| 1704 |
+
// v0.7.0 — anti-bullshit pack #1: SWA / RoPE-scaling 揭示器
|
| 1705 |
+
"modes.unmask": "🪟 揭示",
|
| 1706 |
+
"unmask.title": "🪟 上下文揭示器",
|
| 1707 |
+
"unmask.tip": "粘贴 HuggingFace 模型 id(或原始 config.json)。工具检测 sliding-window attention、RoPE 缩放(YaRN/linear/dynamic NTK)和 GQA — 所有使 <code>max_position_embeddings</code> 大于实际有效上下文的因素。Mistral-7B-v0.1 是经典例子:声称 32k,实际只在 ~4-8k 范围内做注意力。",
|
| 1708 |
+
"unmask.desc": "<strong>你即将为一个实际上注意力不到那么远的模型花钱吗?</strong> 粘贴 id,1 秒内得知。无需 GPU,无需推理 — 只是对 config.json 做算术。",
|
| 1709 |
+
"unmask.id_label": "HF 模型 id:",
|
| 1710 |
+
"unmask.fetch_btn": "🔍 揭示",
|
| 1711 |
+
"unmask.paste_summary": "或粘贴原始 config.json(私有 / 在研模型)",
|
| 1712 |
+
"unmask.paste_btn": "🔍 揭示已粘贴的 config",
|
| 1713 |
+
"unmask.label.declared": "声明上下文",
|
| 1714 |
+
"unmask.label.effective": "有效(估计)",
|
| 1715 |
+
"unmask.label.ratio": "比率",
|
| 1716 |
+
"unmask.section.flags": "架构标志",
|
| 1717 |
+
"unmask.section.warnings": "警告",
|
| 1718 |
+
"unmask.section.reco": "建议",
|
| 1719 |
+
"unmask.flag.swa": "SWA",
|
| 1720 |
+
"unmask.flag.rope": "RoPE 缩放",
|
| 1721 |
+
"unmask.flag.gqa": "GQA",
|
| 1722 |
+
"unmask.flag.layers": "层数",
|
| 1723 |
+
"unmask.flag.dhead": "d_head",
|
| 1724 |
+
"unmask.flag.theta": "RoPE θ",
|
| 1725 |
+
"unmask.flag.yes": "是",
|
| 1726 |
+
"unmask.flag.no": "否",
|
| 1727 |
+
"unmask.flag.full_mha": "否(完整 MHA,{n} heads)",
|
| 1728 |
+
"unmask.verdict.honest": "✅ 诚实",
|
| 1729 |
+
"unmask.verdict.inflated": "⚠ 夸大",
|
| 1730 |
+
"unmask.verdict.severely_inflated": "❌ 严重夸大",
|
| 1731 |
+
"unmask.verdict.yarn_extended": "⚠ YARN 扩展",
|
| 1732 |
+
"unmask.verdict.unknown": "❓ 未知",
|
| 1733 |
+
"unmask.warn.swa_window": "SWA 窗口:{window} tokens — 每层仅在此窗口内做注意力。",
|
| 1734 |
+
"unmask.warn.multihop": "多跳估计:~{multiHop} tokens(保守:窗口 × {factor})。",
|
| 1735 |
+
"unmask.warn.yarn": "RoPE 缩放({type})将上下文从 ~{original} 扩展 {factor}× 到 {declared} tokens。",
|
| 1736 |
+
"unmask.warn.yarn_advice": "RoPE 扩展的上下文 — 用 γ_check 诊断在声称的全长度验证 γ 行为。",
|
| 1737 |
+
"unmask.warn.gqa_small_dhead": "小 head dim({d_head})+ GQA:长上下文下 KV 缓存压缩很可能(γ 推向 Hagedorn)。",
|
| 1738 |
+
"unmask.reco.honest": "标准全注意力模型。有效上下文与声明一致({declared} tokens)。",
|
| 1739 |
+
"unmask.reco.inflated": "通过 SWA 有效 ~{effective} tokens。用 γ_check 验证你目标长度的行为。",
|
| 1740 |
+
"unmask.reco.severely_inflated": "实际把它当作 ~{effective} tokens 上下文模型。{declared} tokens 的声明仅通过跨层注意力链生效,经验上超过 ~2× SWA 窗口后会退化。",
|
| 1741 |
+
"unmask.reco.yarn_extended": "RoPE 扩展上下文。运行长上下文 benchmark(NIAH 在 8k / 16k / 32k / 全长度)以确认扩展是否成立。用 γ_check 设 T_eval = {declared}。",
|
| 1742 |
+
"unmask.reco.unknown": "无法解析 config。验证 URL 是带公开 config.json 的有效 HF 模型。",
|
| 1743 |
+
"unmask.status.empty_id": "⚠ 输入一个 model id(例如 mistralai/Mistral-7B-v0.1)。",
|
| 1744 |
+
"unmask.status.fetching": "⏳ 正在获取 {modelId} 的 config.json...",
|
| 1745 |
+
"unmask.status.success": "✅ 已分析 {modelId}(判定:{verdict})",
|
| 1746 |
+
"unmask.status.empty_paste": "⚠ 请先粘贴 config.json。",
|
| 1747 |
+
"unmask.status.invalid_json": "❌ JSON 无效:{error}",
|
| 1748 |
+
"unmask.status.success_paste": "✅ 已分析粘贴的 config(判定:{verdict})",
|
| 1749 |
+
"unmask.pasted_label": "(已粘贴 config)",
|
| 1750 |
+
"mode_desc.ask": "输入自由问题。浏览器内的 LLM 选择正确的 recipe 并运行。",
|
| 1751 |
+
"mode_desc.recipe": "直接选择一个 recipe 并填表。完整手动控制。",
|
| 1752 |
+
"mode_desc.profile": "最快开始:粘贴任意 HuggingFace model id,点击 Profile。几秒内看到 5 个 recipe。",
|
| 1753 |
+
"mode_desc.compare": "选择 2-3 个候选模型 + 一个 recipe。在表格中并排查看判定。",
|
| 1754 |
+
"mode_desc.inspector": "直接粘贴 config.json。适用于未发布 HF Hub 的私有 / 在研模型。",
|
| 1755 |
+
"mode_desc.diagnose": "构建 diagnose_model.py 的 CLI 命令,在真实 GPU 上测量 γ_obs。浏览器预测;CLI 测量。",
|
| 1756 |
+
"mode_desc.phase": "论文经验面板的 γ × θ 散点图。悬停点查看详情,点击加载到 Diagnose / Recipe 表单。",
|
| 1757 |
+
"mode_desc.unmask": "检测 max_position_embeddings 是否误导(SWA / YaRN / RoPE 缩放)。粘贴 model id,1 行判定。",
|
| 1758 |
+
"profile.preset_loaded": "✅ 已为 <strong>{id}</strong> 加载预设。表单已预填。(点击 📥 Fetch 用 HF Hub 最新 config 覆盖。)",
|
| 1759 |
"share.import_desc": "有他人 TAF 分析的 JSON 文件? 在这里加载以本地查看判定 + 链。与您自己运行的视图相同。",
|
| 1760 |
"share.import_btn": "📂 加载共享的 JSON",
|
| 1761 |
"synthesis.system": "您是 transformer LLM 的精确诊断助手。给定预先计算的 TAF 公式结果,用 4-6 句中文写出清晰的摘要。为每个提到的数字引用章节号 (§X.Y)。始终给出具体建议。不要编造数字。",
|
|
|
|
| 1848 |
"common.no": "否",
|
| 1849 |
|
| 1850 |
// 模式提示
|
| 1851 |
+
"modes.tip": "<strong>八种使用方式</strong>。<br><strong>📇 画像</strong>: 粘贴模型 id → 5 个配方的 TAF 卡。<br><strong>🆚 比较</strong>: 2-3 个模型在一个配方上并排比较。<br><strong>🔍 检查 config</strong>: 粘贴原始 config.json → 完整画像。<br><strong>💬 提问</strong>: 自由形式问题,浏览器 LLM 选择配方。<br><strong>📋 配方</strong>: 手动选择,完全控制表单。<br><strong>🩺 CLI 诊断</strong>: 生成 Python 命令在本地测量 γ。<br><strong>📊 相图</strong>: 23 个面板模型在 (log θ, γ) 平面上。<br><strong>🪟 揭示</strong>: 检测误导的 max_position_embeddings(SWA / YaRN / RoPE 缩放)。",
|
| 1852 |
"profile.tip": "<strong>一键完整诊断</strong>。粘贴任意 HF 模型 id (或选择预设)。工具运行所有 5 个配方 (长上下文、KV 压缩、自定义 vs API、预算、硬件),生成单个 <strong>TAF 卡</strong>,显示每个维度的判定 + 关键数字 + 架构分类。<br><br><strong>用例</strong>: \"我正在为生产评估 Qwen2.5-32B — 它的完整可行性概况是什么?\" → 粘贴 id → 画像 → 完成。",
|
| 1853 |
"compare.tip": "<strong>同一配方,多个模型</strong>。选择 2-3 个候选模型和一个配方。在单个比较表中查看判定。<br><br><strong>用例</strong>: \"我需要在 16K 进行长上下文检索 — 哪个最好: Llama-3-8B、Mistral-7B 或 Qwen-7B?\" → 选择 3 个 + X-2 + 16K → 看赢家。",
|
| 1854 |
|
|
@@ -11,6 +11,7 @@ import { initI18n, setLang, t } from "./i18n.js";
|
|
| 11 |
import { initPhaseDiagram } from "./phase_diagram.js";
|
| 12 |
import { gammaCheckAll, REGIME_META } from "./gamma_check.js";
|
| 13 |
import { loadLeanManifest, badgeHtml, badgesForUiBinding, renderTheoremTable, getManifest } from "./lean_badges.js";
|
|
|
|
| 14 |
|
| 15 |
const TAF_BROWSER_URL = "python/taf_browser.py";
|
| 16 |
const ENABLE_WEBLLM = true;
|
|
@@ -137,6 +138,38 @@ function enableUI() {
|
|
| 137 |
|
| 138 |
function setStatus(msg) { $("status").textContent = msg; }
|
| 139 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 140 |
// ════════════════════════════════════════════════════════════════════
|
| 141 |
// Mode toggle
|
| 142 |
// ════════════════════════════════════════════════════════════════════
|
|
@@ -153,41 +186,20 @@ document.querySelectorAll(".mode-btn").forEach(btn => {
|
|
| 153 |
// Hide all mode sections
|
| 154 |
["ask-section", "recipe-section", "form-section",
|
| 155 |
"profile-section", "compare-section", "inspector-section",
|
| 156 |
-
"diagnose-section", "phase-section"].forEach(id => {
|
| 157 |
const el = $(id);
|
| 158 |
if (el) el.style.display = "none";
|
| 159 |
});
|
| 160 |
// Show selected
|
| 161 |
-
|
| 162 |
-
|
| 163 |
-
|
| 164 |
-
|
| 165 |
-
}
|
| 166 |
-
|
| 167 |
-
|
| 168 |
-
|
| 169 |
-
|
| 170 |
-
$("profile-section").style.display = "";
|
| 171 |
-
$("mode-desc").textContent =
|
| 172 |
-
"Quickest start: paste any HuggingFace model id, click Profile. See all 5 recipes scored in seconds.";
|
| 173 |
-
} else if (mode === "compare") {
|
| 174 |
-
$("compare-section").style.display = "";
|
| 175 |
-
$("mode-desc").textContent =
|
| 176 |
-
"Pick 2-3 candidate models + one recipe. See verdicts side-by-side in a comparison table.";
|
| 177 |
-
} else if (mode === "inspector") {
|
| 178 |
-
$("inspector-section").style.display = "";
|
| 179 |
-
$("mode-desc").textContent =
|
| 180 |
-
"Paste a config.json directly. Useful for private/in-development models not on HF Hub.";
|
| 181 |
-
} else if (mode === "diagnose") {
|
| 182 |
-
$("diagnose-section").style.display = "";
|
| 183 |
-
$("mode-desc").textContent =
|
| 184 |
-
"Build the diagnose_model.py CLI command to MEASURE γ_obs on real GPU. Browser predicts; CLI measures.";
|
| 185 |
-
} else if (mode === "phase") {
|
| 186 |
-
$("phase-section").style.display = "";
|
| 187 |
-
$("mode-desc").textContent =
|
| 188 |
-
"γ × θ scatter of the paper's empirical panel. Hover a dot for details, click to load into Diagnose / Recipe forms.";
|
| 189 |
-
initPhaseDiagram();
|
| 190 |
-
}
|
| 191 |
});
|
| 192 |
});
|
| 193 |
|
|
@@ -353,8 +365,14 @@ function getRecipeDefaults(recipeId) {
|
|
| 353 |
// ════════════════════════════════════════════════════════════════════
|
| 354 |
$("preset").addEventListener("change", (e) => {
|
| 355 |
if (!e.target.value) return;
|
| 356 |
-
|
| 357 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 358 |
const preset = proxy.toJs ? proxy.toJs({ dict_converter: Object.fromEntries }) : proxy;
|
| 359 |
if (!preset || Object.keys(preset).length === 0) return;
|
| 360 |
fillRecipeForm(preset);
|
|
@@ -417,6 +435,152 @@ $("hf-fetch-btn").addEventListener("click", async () => {
|
|
| 417 |
}
|
| 418 |
});
|
| 419 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 420 |
function configToPreset(cfg, modelId) {
|
| 421 |
const n_attn = cfg.num_attention_heads || cfg.n_head || 0;
|
| 422 |
const n_kv = cfg.num_key_value_heads || cfg.num_attention_heads || cfg.n_head || 0;
|
|
@@ -988,8 +1152,18 @@ function relativeTime(d) {
|
|
| 988 |
// ════════════════════════════════════════════════════════════════════
|
| 989 |
$("profile-preset").addEventListener("change", (e) => {
|
| 990 |
if (!e.target.value) return;
|
| 991 |
-
|
| 992 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 993 |
const p = proxy.toJs ? proxy.toJs({ dict_converter: Object.fromEntries }) : proxy;
|
| 994 |
if (!p || Object.keys(p).length === 0) return;
|
| 995 |
$("profile-theta").value = p.theta;
|
|
|
|
| 11 |
import { initPhaseDiagram } from "./phase_diagram.js";
|
| 12 |
import { gammaCheckAll, REGIME_META } from "./gamma_check.js";
|
| 13 |
import { loadLeanManifest, badgeHtml, badgesForUiBinding, renderTheoremTable, getManifest } from "./lean_badges.js";
|
| 14 |
+
import { unmaskConfig } from "./swa_unmasker.js";
|
| 15 |
|
| 16 |
const TAF_BROWSER_URL = "python/taf_browser.py";
|
| 17 |
const ENABLE_WEBLLM = true;
|
|
|
|
| 138 |
|
| 139 |
function setStatus(msg) { $("status").textContent = msg; }
|
| 140 |
|
| 141 |
+
// ════════════════════════════════════════════════════════════════════
|
| 142 |
+
// Main-panel wrap: every <main> section gets a foldable details/summary
|
| 143 |
+
// shell at runtime so users can collapse any panel they don't need open.
|
| 144 |
+
// h2 is moved INTO summary so its data-i18n binding survives. Idempotent.
|
| 145 |
+
// ════════════════════════════════════════════════════════════════════
|
| 146 |
+
function wrapMainSectionsAsFoldable() {
|
| 147 |
+
document.querySelectorAll("main > section").forEach(section => {
|
| 148 |
+
if (section.id === "status-bar") return; // skip loading bar
|
| 149 |
+
if (section.querySelector(":scope > details.main-panel")) return; // already wrapped
|
| 150 |
+
const h2 = section.querySelector(":scope > h2");
|
| 151 |
+
if (!h2) return;
|
| 152 |
+
|
| 153 |
+
const details = document.createElement("details");
|
| 154 |
+
details.className = "main-panel";
|
| 155 |
+
details.open = true;
|
| 156 |
+
|
| 157 |
+
const summary = document.createElement("summary");
|
| 158 |
+
summary.className = "main-panel-title";
|
| 159 |
+
summary.appendChild(h2); // preserve h2 + its data-i18n + all children
|
| 160 |
+
|
| 161 |
+
details.appendChild(summary);
|
| 162 |
+
while (section.firstChild) details.appendChild(section.firstChild);
|
| 163 |
+
section.appendChild(details);
|
| 164 |
+
});
|
| 165 |
+
|
| 166 |
+
// Stop ⓘ tooltip clicks inside summaries from toggling the panel.
|
| 167 |
+
document.querySelectorAll(".main-panel > .main-panel-title .info").forEach(el => {
|
| 168 |
+
el.addEventListener("click", (e) => e.stopPropagation());
|
| 169 |
+
});
|
| 170 |
+
}
|
| 171 |
+
wrapMainSectionsAsFoldable();
|
| 172 |
+
|
| 173 |
// ════════════════════════════════════════════════════════════════════
|
| 174 |
// Mode toggle
|
| 175 |
// ════════════════════════════════════════════════════════════════════
|
|
|
|
| 186 |
// Hide all mode sections
|
| 187 |
["ask-section", "recipe-section", "form-section",
|
| 188 |
"profile-section", "compare-section", "inspector-section",
|
| 189 |
+
"diagnose-section", "phase-section", "unmask-section"].forEach(id => {
|
| 190 |
const el = $(id);
|
| 191 |
if (el) el.style.display = "none";
|
| 192 |
});
|
| 193 |
// Show selected
|
| 194 |
+
const sectionMap = {
|
| 195 |
+
ask: "ask-section", recipe: "recipe-section", profile: "profile-section",
|
| 196 |
+
compare: "compare-section", inspector: "inspector-section",
|
| 197 |
+
diagnose: "diagnose-section", phase: "phase-section", unmask: "unmask-section",
|
| 198 |
+
};
|
| 199 |
+
const sectionId = sectionMap[mode];
|
| 200 |
+
if (sectionId) $(sectionId).style.display = "";
|
| 201 |
+
$("mode-desc").textContent = t(`mode_desc.${mode}`) || "";
|
| 202 |
+
if (mode === "phase") initPhaseDiagram();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 203 |
});
|
| 204 |
});
|
| 205 |
|
|
|
|
| 365 |
// ════════════════════════════════════════════════════════════════════
|
| 366 |
$("preset").addEventListener("change", (e) => {
|
| 367 |
if (!e.target.value) return;
|
| 368 |
+
const modelId = e.target.value;
|
| 369 |
+
state.lastModelId = modelId; // remember for filename/hash
|
| 370 |
+
// Mirror behavior with profile-preset: also fill HF id input if present.
|
| 371 |
+
if ($("hf-id")) {
|
| 372 |
+
$("hf-id").value = modelId;
|
| 373 |
+
if ($("hf-status")) $("hf-status").textContent = tFmt("profile.preset_loaded", { id: modelId });
|
| 374 |
+
}
|
| 375 |
+
const proxy = state.pyodide.runPython(`get_preset(${JSON.stringify(modelId)})`);
|
| 376 |
const preset = proxy.toJs ? proxy.toJs({ dict_converter: Object.fromEntries }) : proxy;
|
| 377 |
if (!preset || Object.keys(preset).length === 0) return;
|
| 378 |
fillRecipeForm(preset);
|
|
|
|
| 435 |
}
|
| 436 |
});
|
| 437 |
|
| 438 |
+
// ════════════════════════════════════════════════════════════════════
|
| 439 |
+
// 🪟 Unmask mode (v0.7.0 anti-bullshit pack #1)
|
| 440 |
+
// ════════════════════════════════════════════════════════════════════
|
| 441 |
+
|
| 442 |
+
// Tiny string-template helper: t(key) with {placeholder} substitution.
|
| 443 |
+
// Falls back to the raw key when the i18n entry is missing so dev sees the gap.
|
| 444 |
+
function tFmt(key, params = {}) {
|
| 445 |
+
let s = t(key) || key;
|
| 446 |
+
for (const [k, v] of Object.entries(params)) {
|
| 447 |
+
const fmtVal = v === null || v === undefined ? "—"
|
| 448 |
+
: (typeof v === "number" ? v.toLocaleString() : String(v));
|
| 449 |
+
s = s.replace(new RegExp(`\\{${k}\\}`, "g"), fmtVal);
|
| 450 |
+
}
|
| 451 |
+
return s;
|
| 452 |
+
}
|
| 453 |
+
|
| 454 |
+
const VERDICT_COLOR = {
|
| 455 |
+
honest: "#3fb950",
|
| 456 |
+
inflated: "#f1c40f",
|
| 457 |
+
severely_inflated: "#f85149",
|
| 458 |
+
yarn_extended: "#f1c40f",
|
| 459 |
+
unknown: "#8b949e",
|
| 460 |
+
};
|
| 461 |
+
|
| 462 |
+
function renderUnmaskCard(result, modelId = "") {
|
| 463 |
+
const color = VERDICT_COLOR[result.verdict] || VERDICT_COLOR.unknown;
|
| 464 |
+
const ratioPct = (result.ratio * 100).toFixed(1);
|
| 465 |
+
const f = result.flags;
|
| 466 |
+
const fmtN = (x) => x === null || x === undefined ? "—" : Number(x).toLocaleString();
|
| 467 |
+
const escapeHtml = (s) => String(s).replace(/[&<>"']/g, c =>
|
| 468 |
+
({"&":"&","<":"<",">":">",'"':""","'":"'"}[c]));
|
| 469 |
+
|
| 470 |
+
const verdictLabel = t(`unmask.verdict.${result.verdict}`) || result.verdict;
|
| 471 |
+
const labelDeclared = t("unmask.label.declared") || "Declared context";
|
| 472 |
+
const labelEffective = t("unmask.label.effective") || "Effective (estimate)";
|
| 473 |
+
const labelRatio = t("unmask.label.ratio") || "Ratio";
|
| 474 |
+
const sectionFlags = t("unmask.section.flags") || "Architecture flags";
|
| 475 |
+
const sectionWarn = t("unmask.section.warnings")|| "Warnings";
|
| 476 |
+
const sectionReco = t("unmask.section.reco") || "Recommendation";
|
| 477 |
+
|
| 478 |
+
// Architecture flags row labels
|
| 479 |
+
const flagSwa = t("unmask.flag.swa") || "SWA";
|
| 480 |
+
const flagRope = t("unmask.flag.rope") || "RoPE scaling";
|
| 481 |
+
const flagGqa = t("unmask.flag.gqa") || "GQA";
|
| 482 |
+
const flagLayers = t("unmask.flag.layers") || "Layers";
|
| 483 |
+
const flagDhead = t("unmask.flag.dhead") || "d_head";
|
| 484 |
+
const flagTheta = t("unmask.flag.theta") || "RoPE θ";
|
| 485 |
+
const flagYes = t("unmask.flag.yes") || "yes";
|
| 486 |
+
const flagNo = t("unmask.flag.no") || "no";
|
| 487 |
+
|
| 488 |
+
const swaText = f.hasSWA
|
| 489 |
+
? `${flagYes} (window = ${fmtN(f.swaWindow)})`
|
| 490 |
+
: flagNo;
|
| 491 |
+
const ropeText = f.hasYaRN
|
| 492 |
+
? `${f.ropeScalingType} (factor = ${f.yarnFactor}, original = ${fmtN(f.yarnOriginal)})`
|
| 493 |
+
: flagNo;
|
| 494 |
+
const gqaText = f.hasGQA
|
| 495 |
+
? `${flagYes} (${f.n_kv_heads} kv / ${f.n_attn_heads} attn heads)`
|
| 496 |
+
: (t("unmask.flag.full_mha") || "no (full MHA, {n} heads)").replace("{n}", f.n_attn_heads ?? "?");
|
| 497 |
+
|
| 498 |
+
const warningsHtml = result.warnings.length
|
| 499 |
+
? `<details class="unmask-panel" open><summary class="unmask-panel-title">${sectionWarn}</summary><ul>${result.warnings.map(w =>
|
| 500 |
+
`<li>${tFmt("unmask.warn." + w.code, w.params)}</li>`).join("")}</ul></details>`
|
| 501 |
+
: "";
|
| 502 |
+
|
| 503 |
+
const recoHtml = result.recoCode
|
| 504 |
+
? `<details class="unmask-panel" open><summary class="unmask-panel-title">${sectionReco}</summary><p class="unmask-reco">${tFmt("unmask.reco." + result.recoCode, result.recoParams)}</p></details>`
|
| 505 |
+
: "";
|
| 506 |
+
|
| 507 |
+
return `
|
| 508 |
+
<div class="unmask-result">
|
| 509 |
+
<div class="unmask-hero" style="border-color: ${color};">
|
| 510 |
+
<div class="unmask-verdict" style="color: ${color};">${verdictLabel}</div>
|
| 511 |
+
${modelId ? `<div class="unmask-model"><code>${escapeHtml(modelId)}</code></div>` : ""}
|
| 512 |
+
<div class="unmask-numbers">
|
| 513 |
+
<div><span class="unmask-num-label">${labelDeclared}</span><span class="unmask-num-val">${fmtN(result.declaredContext)}</span></div>
|
| 514 |
+
<div><span class="unmask-num-label">${labelEffective}</span><span class="unmask-num-val">${fmtN(result.effectiveContext)}</span></div>
|
| 515 |
+
<div><span class="unmask-num-label">${labelRatio}</span><span class="unmask-num-val">${ratioPct}%</span></div>
|
| 516 |
+
</div>
|
| 517 |
+
</div>
|
| 518 |
+
|
| 519 |
+
<div class="unmask-details">
|
| 520 |
+
<details class="unmask-panel" open>
|
| 521 |
+
<summary class="unmask-panel-title">${sectionFlags}</summary>
|
| 522 |
+
<ul>
|
| 523 |
+
<li><strong>${flagSwa}:</strong> ${swaText}</li>
|
| 524 |
+
<li><strong>${flagRope}:</strong> ${ropeText}</li>
|
| 525 |
+
<li><strong>${flagGqa}:</strong> ${gqaText}</li>
|
| 526 |
+
<li><strong>${flagLayers}:</strong> ${fmtN(f.n_layers)} · <strong>${flagDhead}:</strong> ${fmtN(f.d_head)} · <strong>${flagTheta}:</strong> ${fmtN(f.rope_theta)}</li>
|
| 527 |
+
</ul>
|
| 528 |
+
</details>
|
| 529 |
+
${warningsHtml}
|
| 530 |
+
${recoHtml}
|
| 531 |
+
</div>
|
| 532 |
+
</div>
|
| 533 |
+
`;
|
| 534 |
+
}
|
| 535 |
+
|
| 536 |
+
async function runUnmaskFromId() {
|
| 537 |
+
const modelId = ($("unmask-id").value || "").trim();
|
| 538 |
+
if (!modelId) {
|
| 539 |
+
$("unmask-status").textContent = t("unmask.status.empty_id") || "⚠ Enter a model id.";
|
| 540 |
+
return;
|
| 541 |
+
}
|
| 542 |
+
$("unmask-status").textContent = tFmt("unmask.status.fetching", { modelId });
|
| 543 |
+
$("unmask-fetch-btn").disabled = true;
|
| 544 |
+
try {
|
| 545 |
+
const cfg = await fetchHfConfig(modelId);
|
| 546 |
+
const result = unmaskConfig(cfg);
|
| 547 |
+
$("unmask-output").innerHTML = renderUnmaskCard(result, modelId);
|
| 548 |
+
const verdictLocalized = t(`unmask.verdict.${result.verdict}`) || result.verdict;
|
| 549 |
+
$("unmask-status").textContent = tFmt("unmask.status.success", { modelId, verdict: verdictLocalized });
|
| 550 |
+
} catch (err) {
|
| 551 |
+
$("unmask-status").textContent = `❌ ${err.message}`;
|
| 552 |
+
$("unmask-output").innerHTML = "";
|
| 553 |
+
} finally {
|
| 554 |
+
$("unmask-fetch-btn").disabled = false;
|
| 555 |
+
}
|
| 556 |
+
}
|
| 557 |
+
|
| 558 |
+
function runUnmaskFromPaste() {
|
| 559 |
+
const raw = ($("unmask-paste").value || "").trim();
|
| 560 |
+
if (!raw) {
|
| 561 |
+
$("unmask-status").textContent = t("unmask.status.empty_paste") || "⚠ Paste a config.json first.";
|
| 562 |
+
return;
|
| 563 |
+
}
|
| 564 |
+
let cfg;
|
| 565 |
+
try {
|
| 566 |
+
cfg = JSON.parse(raw);
|
| 567 |
+
} catch (e) {
|
| 568 |
+
$("unmask-status").textContent = tFmt("unmask.status.invalid_json", { error: e.message });
|
| 569 |
+
return;
|
| 570 |
+
}
|
| 571 |
+
const result = unmaskConfig(cfg);
|
| 572 |
+
const pastedLabel = t("unmask.pasted_label") || "(pasted config)";
|
| 573 |
+
$("unmask-output").innerHTML = renderUnmaskCard(result, pastedLabel);
|
| 574 |
+
const verdictLocalized = t(`unmask.verdict.${result.verdict}`) || result.verdict;
|
| 575 |
+
$("unmask-status").textContent = tFmt("unmask.status.success_paste", { verdict: verdictLocalized });
|
| 576 |
+
}
|
| 577 |
+
|
| 578 |
+
$("unmask-fetch-btn")?.addEventListener("click", runUnmaskFromId);
|
| 579 |
+
$("unmask-paste-btn")?.addEventListener("click", runUnmaskFromPaste);
|
| 580 |
+
$("unmask-id")?.addEventListener("keydown", (e) => {
|
| 581 |
+
if (e.key === "Enter") { e.preventDefault(); runUnmaskFromId(); }
|
| 582 |
+
});
|
| 583 |
+
|
| 584 |
function configToPreset(cfg, modelId) {
|
| 585 |
const n_attn = cfg.num_attention_heads || cfg.n_head || 0;
|
| 586 |
const n_kv = cfg.num_key_value_heads || cfg.num_attention_heads || cfg.n_head || 0;
|
|
|
|
| 1152 |
// ════════════════════════════════════════════════════════════════════
|
| 1153 |
$("profile-preset").addEventListener("change", (e) => {
|
| 1154 |
if (!e.target.value) return;
|
| 1155 |
+
const modelId = e.target.value;
|
| 1156 |
+
state.lastModelId = modelId; // remember for filename/hash
|
| 1157 |
+
// Preset keys ARE valid HF model ids (e.g. "meta-llama/Llama-3.2-1B"). Auto-fill
|
| 1158 |
+
// the HF id input so the user can also click 📥 Fetch to refresh from HF Hub
|
| 1159 |
+
// without retyping. Status hint clarifies the dual source of truth.
|
| 1160 |
+
if ($("profile-hf-id")) {
|
| 1161 |
+
$("profile-hf-id").value = modelId;
|
| 1162 |
+
if ($("profile-hf-status")) {
|
| 1163 |
+
$("profile-hf-status").textContent = tFmt("profile.preset_loaded", { id: modelId });
|
| 1164 |
+
}
|
| 1165 |
+
}
|
| 1166 |
+
const proxy = state.pyodide.runPython(`get_preset(${JSON.stringify(modelId)})`);
|
| 1167 |
const p = proxy.toJs ? proxy.toJs({ dict_converter: Object.fromEntries }) : proxy;
|
| 1168 |
if (!p || Object.keys(p).length === 0) return;
|
| 1169 |
$("profile-theta").value = p.theta;
|
|
@@ -0,0 +1,107 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// SWA Unmasker (v0.7.0 anti-bullshit pack #1)
|
| 2 |
+
// Pure logic — no human-readable strings. Returns structured warnings/reco
|
| 3 |
+
// codes + params; main.js does the i18n lookup so EN/ES/FR/ZH all work.
|
| 4 |
+
|
| 5 |
+
// Conservative multi-hop bound for SWA models. Empirically the effective
|
| 6 |
+
// "reasoning" context is roughly 2× the window, NOT window × n_layers
|
| 7 |
+
// (which is the theoretical upper bound but breaks down past a few hops).
|
| 8 |
+
const SWA_MULTIHOP_FACTOR = 2;
|
| 9 |
+
|
| 10 |
+
export function unmaskConfig(config) {
|
| 11 |
+
const out = {
|
| 12 |
+
declaredContext: config.max_position_embeddings ?? null,
|
| 13 |
+
effectiveContext: null,
|
| 14 |
+
verdict: "honest",
|
| 15 |
+
ratio: 1.0,
|
| 16 |
+
flags: {
|
| 17 |
+
hasSWA: false,
|
| 18 |
+
swaWindow: null,
|
| 19 |
+
hasYaRN: false,
|
| 20 |
+
yarnFactor: null,
|
| 21 |
+
yarnOriginal: null,
|
| 22 |
+
ropeScalingType: null,
|
| 23 |
+
hasGQA: false,
|
| 24 |
+
n_kv_heads: config.num_key_value_heads ?? config.num_attention_heads ?? null,
|
| 25 |
+
n_attn_heads: config.num_attention_heads ?? null,
|
| 26 |
+
n_layers: config.num_hidden_layers ?? null,
|
| 27 |
+
rope_theta: config.rope_theta ?? null,
|
| 28 |
+
d_head: null,
|
| 29 |
+
},
|
| 30 |
+
warnings: [], // each: { code, params }
|
| 31 |
+
recoCode: null,
|
| 32 |
+
recoParams: {},
|
| 33 |
+
};
|
| 34 |
+
|
| 35 |
+
if (out.flags.n_attn_heads && out.flags.n_kv_heads) {
|
| 36 |
+
out.flags.hasGQA = out.flags.n_kv_heads < out.flags.n_attn_heads;
|
| 37 |
+
}
|
| 38 |
+
if (config.hidden_size && out.flags.n_attn_heads) {
|
| 39 |
+
out.flags.d_head = config.hidden_size / out.flags.n_attn_heads;
|
| 40 |
+
}
|
| 41 |
+
|
| 42 |
+
// SWA: explicit sliding_window field (Mistral, Gemma-2). Some configs set
|
| 43 |
+
// it to null or to max_pe — treat as "no SWA" in those cases.
|
| 44 |
+
const sw = config.sliding_window;
|
| 45 |
+
if (typeof sw === "number" && sw > 0
|
| 46 |
+
&& (!out.declaredContext || sw < out.declaredContext)) {
|
| 47 |
+
out.flags.hasSWA = true;
|
| 48 |
+
out.flags.swaWindow = sw;
|
| 49 |
+
}
|
| 50 |
+
|
| 51 |
+
// RoPE scaling (YaRN / linear / dynamic NTK). Only flag if factor > 1.
|
| 52 |
+
const rs = config.rope_scaling;
|
| 53 |
+
if (rs && typeof rs === "object") {
|
| 54 |
+
out.flags.ropeScalingType = rs.type ?? rs.rope_type ?? null;
|
| 55 |
+
out.flags.yarnFactor = rs.factor ?? null;
|
| 56 |
+
out.flags.yarnOriginal = rs.original_max_position_embeddings ?? null;
|
| 57 |
+
if (out.flags.ropeScalingType && out.flags.yarnFactor && out.flags.yarnFactor > 1) {
|
| 58 |
+
out.flags.hasYaRN = true;
|
| 59 |
+
}
|
| 60 |
+
}
|
| 61 |
+
|
| 62 |
+
// Compute verdict
|
| 63 |
+
if (out.flags.hasSWA) {
|
| 64 |
+
const multiHop = out.flags.swaWindow * SWA_MULTIHOP_FACTOR;
|
| 65 |
+
out.effectiveContext = Math.min(multiHop, out.declaredContext ?? multiHop);
|
| 66 |
+
out.ratio = out.declaredContext ? out.effectiveContext / out.declaredContext : 1.0;
|
| 67 |
+
// <= 0.25 catches the canonical Mistral case (window=4096, declared=32768, ratio=0.25 exact)
|
| 68 |
+
out.verdict = out.ratio <= 0.25 ? "severely_inflated" : "inflated";
|
| 69 |
+
out.warnings.push(
|
| 70 |
+
{ code: "swa_window", params: { window: out.flags.swaWindow } },
|
| 71 |
+
{ code: "multihop", params: { multiHop, factor: SWA_MULTIHOP_FACTOR } },
|
| 72 |
+
);
|
| 73 |
+
out.recoCode = out.verdict;
|
| 74 |
+
out.recoParams = {
|
| 75 |
+
effective: out.effectiveContext,
|
| 76 |
+
declared: out.declaredContext,
|
| 77 |
+
};
|
| 78 |
+
} else if (out.flags.hasYaRN) {
|
| 79 |
+
out.verdict = "yarn_extended";
|
| 80 |
+
const orig = out.flags.yarnOriginal
|
| 81 |
+
?? (out.declaredContext ? out.declaredContext / out.flags.yarnFactor : null);
|
| 82 |
+
out.effectiveContext = out.declaredContext;
|
| 83 |
+
out.ratio = 1.0;
|
| 84 |
+
out.warnings.push(
|
| 85 |
+
{ code: "yarn", params: { type: out.flags.ropeScalingType, factor: out.flags.yarnFactor, original: orig ? Math.round(orig) : null, declared: out.declaredContext } },
|
| 86 |
+
{ code: "yarn_advice", params: {} },
|
| 87 |
+
);
|
| 88 |
+
out.recoCode = "yarn_extended";
|
| 89 |
+
out.recoParams = { declared: out.declaredContext };
|
| 90 |
+
} else if (out.declaredContext) {
|
| 91 |
+
out.effectiveContext = out.declaredContext;
|
| 92 |
+
out.verdict = "honest";
|
| 93 |
+
out.recoCode = "honest";
|
| 94 |
+
out.recoParams = { declared: out.declaredContext };
|
| 95 |
+
} else {
|
| 96 |
+
out.verdict = "unknown";
|
| 97 |
+
out.recoCode = "unknown";
|
| 98 |
+
out.recoParams = {};
|
| 99 |
+
}
|
| 100 |
+
|
| 101 |
+
// KV-cache compression hint for small d_head + GQA — independent of verdict
|
| 102 |
+
if (out.flags.hasGQA && out.flags.d_head && out.flags.d_head < 64) {
|
| 103 |
+
out.warnings.push({ code: "gqa_small_dhead", params: { d_head: out.flags.d_head } });
|
| 104 |
+
}
|
| 105 |
+
|
| 106 |
+
return out;
|
| 107 |
+
}
|
|
@@ -1,5 +1,130 @@
|
|
| 1 |
/* TAF Agent — minimal clean styling */
|
| 2 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3 |
/* v0.6.2 — landing rework: quick-start strip + inventory grid + arch-supported */
|
| 4 |
#quickstart-strip {
|
| 5 |
margin: 1.5em auto 1em;
|
|
@@ -72,18 +197,35 @@
|
|
| 72 |
gap: 0.8em;
|
| 73 |
}
|
| 74 |
.inv-card {
|
| 75 |
-
padding: 0.
|
| 76 |
background: #12181f;
|
| 77 |
border: 1px solid rgba(255, 255, 255, 0.08);
|
| 78 |
border-radius: 8px;
|
| 79 |
}
|
| 80 |
-
.inv-card
|
| 81 |
-
|
| 82 |
font-size: 1em;
|
|
|
|
| 83 |
color: #58a6ff;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 84 |
}
|
|
|
|
| 85 |
.inv-card ul {
|
| 86 |
-
margin: 0;
|
| 87 |
padding-left: 1em;
|
| 88 |
font-size: 0.92em;
|
| 89 |
line-height: 1.5;
|
|
|
|
| 1 |
/* TAF Agent — minimal clean styling */
|
| 2 |
|
| 3 |
+
/* v0.7.0 — main panels foldable (every section under <main>) */
|
| 4 |
+
.main-panel { margin: 0; }
|
| 5 |
+
.main-panel > .main-panel-title {
|
| 6 |
+
cursor: pointer;
|
| 7 |
+
list-style: none;
|
| 8 |
+
user-select: none;
|
| 9 |
+
padding: 0 0 0.5em;
|
| 10 |
+
margin-bottom: 0.6em;
|
| 11 |
+
border-bottom: 1px solid rgba(255, 255, 255, 0.06);
|
| 12 |
+
display: flex;
|
| 13 |
+
align-items: baseline;
|
| 14 |
+
gap: 0.5em;
|
| 15 |
+
}
|
| 16 |
+
.main-panel > .main-panel-title::-webkit-details-marker { display: none; }
|
| 17 |
+
.main-panel > .main-panel-title::marker { content: ""; }
|
| 18 |
+
.main-panel > .main-panel-title::before {
|
| 19 |
+
content: "▼";
|
| 20 |
+
display: inline-block;
|
| 21 |
+
font-size: 0.65em;
|
| 22 |
+
color: #58a6ff;
|
| 23 |
+
margin-right: 0.3em;
|
| 24 |
+
transition: transform 0.15s ease;
|
| 25 |
+
flex-shrink: 0;
|
| 26 |
+
}
|
| 27 |
+
.main-panel:not([open]) > .main-panel-title::before { transform: rotate(-90deg); }
|
| 28 |
+
.main-panel > .main-panel-title:hover { background: rgba(255, 255, 255, 0.02); }
|
| 29 |
+
.main-panel > .main-panel-title h2 {
|
| 30 |
+
display: inline;
|
| 31 |
+
margin: 0;
|
| 32 |
+
vertical-align: baseline;
|
| 33 |
+
flex: 1;
|
| 34 |
+
}
|
| 35 |
+
|
| 36 |
+
/* v0.7.0 — Unmask mode (SWA + RoPE-scaling detector) */
|
| 37 |
+
.unmask-result {
|
| 38 |
+
margin-top: 0.8em;
|
| 39 |
+
}
|
| 40 |
+
.unmask-hero {
|
| 41 |
+
padding: 1em 1.2em;
|
| 42 |
+
border: 2px solid #58a6ff;
|
| 43 |
+
border-radius: 10px;
|
| 44 |
+
background: #12181f;
|
| 45 |
+
margin-bottom: 0.8em;
|
| 46 |
+
}
|
| 47 |
+
.unmask-verdict {
|
| 48 |
+
font-size: 1.6em;
|
| 49 |
+
font-weight: 700;
|
| 50 |
+
margin-bottom: 0.2em;
|
| 51 |
+
}
|
| 52 |
+
.unmask-model {
|
| 53 |
+
font-size: 0.92em;
|
| 54 |
+
opacity: 0.85;
|
| 55 |
+
margin-bottom: 0.6em;
|
| 56 |
+
}
|
| 57 |
+
.unmask-numbers {
|
| 58 |
+
display: grid;
|
| 59 |
+
grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
|
| 60 |
+
gap: 0.6em;
|
| 61 |
+
margin-top: 0.5em;
|
| 62 |
+
}
|
| 63 |
+
.unmask-numbers > div {
|
| 64 |
+
display: flex;
|
| 65 |
+
flex-direction: column;
|
| 66 |
+
padding: 0.5em 0.7em;
|
| 67 |
+
background: rgba(0, 0, 0, 0.25);
|
| 68 |
+
border-radius: 6px;
|
| 69 |
+
}
|
| 70 |
+
.unmask-num-label {
|
| 71 |
+
font-size: 0.78em;
|
| 72 |
+
opacity: 0.75;
|
| 73 |
+
text-transform: uppercase;
|
| 74 |
+
letter-spacing: 0.04em;
|
| 75 |
+
}
|
| 76 |
+
.unmask-num-val {
|
| 77 |
+
font-size: 1.3em;
|
| 78 |
+
font-weight: 600;
|
| 79 |
+
font-family: monospace;
|
| 80 |
+
margin-top: 0.15em;
|
| 81 |
+
}
|
| 82 |
+
.unmask-details {
|
| 83 |
+
padding: 0.8em 1em;
|
| 84 |
+
background: #12181f;
|
| 85 |
+
border: 1px solid rgba(255, 255, 255, 0.08);
|
| 86 |
+
border-radius: 8px;
|
| 87 |
+
}
|
| 88 |
+
.unmask-details h4,
|
| 89 |
+
.unmask-panel-title {
|
| 90 |
+
margin: 0.4em 0 0.3em;
|
| 91 |
+
color: #58a6ff;
|
| 92 |
+
font-size: 0.95em;
|
| 93 |
+
cursor: pointer;
|
| 94 |
+
list-style: none;
|
| 95 |
+
user-select: none;
|
| 96 |
+
font-weight: 600;
|
| 97 |
+
}
|
| 98 |
+
.unmask-panel-title::-webkit-details-marker { display: none; }
|
| 99 |
+
.unmask-panel-title::marker { content: ""; }
|
| 100 |
+
.unmask-panel-title::before {
|
| 101 |
+
content: "▼";
|
| 102 |
+
display: inline-block;
|
| 103 |
+
font-size: 0.75em;
|
| 104 |
+
margin-right: 0.4em;
|
| 105 |
+
color: #58a6ff;
|
| 106 |
+
transition: transform 0.15s ease;
|
| 107 |
+
width: 0.9em;
|
| 108 |
+
text-align: center;
|
| 109 |
+
}
|
| 110 |
+
.unmask-panel:not([open]) > .unmask-panel-title::before { transform: rotate(-90deg); }
|
| 111 |
+
.unmask-panel { margin: 0.5em 0; }
|
| 112 |
+
.unmask-details ul {
|
| 113 |
+
margin: 0.2em 0 0.6em;
|
| 114 |
+
padding-left: 1.2em;
|
| 115 |
+
font-size: 0.92em;
|
| 116 |
+
line-height: 1.5;
|
| 117 |
+
}
|
| 118 |
+
.unmask-reco {
|
| 119 |
+
margin: 0.2em 0 0.4em;
|
| 120 |
+
padding: 0.6em 0.8em;
|
| 121 |
+
background: rgba(88, 166, 255, 0.08);
|
| 122 |
+
border-left: 3px solid #58a6ff;
|
| 123 |
+
border-radius: 0 6px 6px 0;
|
| 124 |
+
font-size: 0.92em;
|
| 125 |
+
line-height: 1.5;
|
| 126 |
+
}
|
| 127 |
+
|
| 128 |
/* v0.6.2 — landing rework: quick-start strip + inventory grid + arch-supported */
|
| 129 |
#quickstart-strip {
|
| 130 |
margin: 1.5em auto 1em;
|
|
|
|
| 197 |
gap: 0.8em;
|
| 198 |
}
|
| 199 |
.inv-card {
|
| 200 |
+
padding: 0.7em 1em;
|
| 201 |
background: #12181f;
|
| 202 |
border: 1px solid rgba(255, 255, 255, 0.08);
|
| 203 |
border-radius: 8px;
|
| 204 |
}
|
| 205 |
+
.inv-card-title {
|
| 206 |
+
cursor: pointer;
|
| 207 |
font-size: 1em;
|
| 208 |
+
font-weight: 600;
|
| 209 |
color: #58a6ff;
|
| 210 |
+
padding: 0.2em 0;
|
| 211 |
+
list-style: none; /* hide native marker (Chrome, Safari) */
|
| 212 |
+
user-select: none;
|
| 213 |
+
}
|
| 214 |
+
.inv-card-title::-webkit-details-marker { display: none; } /* Safari */
|
| 215 |
+
.inv-card-title::marker { content: ""; } /* Firefox */
|
| 216 |
+
.inv-card-title::before {
|
| 217 |
+
content: "▼";
|
| 218 |
+
display: inline-block;
|
| 219 |
+
font-size: 0.75em;
|
| 220 |
+
margin-right: 0.4em;
|
| 221 |
+
color: #58a6ff;
|
| 222 |
+
transition: transform 0.15s ease;
|
| 223 |
+
width: 0.9em;
|
| 224 |
+
text-align: center;
|
| 225 |
}
|
| 226 |
+
.inv-card:not([open]) > .inv-card-title::before { transform: rotate(-90deg); }
|
| 227 |
.inv-card ul {
|
| 228 |
+
margin: 0.4em 0 0;
|
| 229 |
padding-left: 1em;
|
| 230 |
font-size: 0.92em;
|
| 231 |
line-height: 1.5;
|