File size: 19,503 Bytes
f1c3ff2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
75b7ba3
f1c3ff2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
75b7ba3
 
f1c3ff2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
"""Help knowledge base: page guides + docs snippets + static FAQs.

CPU-friendly: pure Python tokenization / scoring, no embeddings or GPU.
"""

from __future__ import annotations

from dataclasses import dataclass
from functools import lru_cache
from pathlib import Path
from typing import Dict, List, Optional

from sensorflow.about.catalog import get_about

# ---------------------------------------------------------------------------
# Compact page guides (mirrors hf-space/src/help/pageGuides.ts summaries)
# ---------------------------------------------------------------------------

PAGE_GUIDES: Dict[str, Dict[str, object]] = {
    "command": {
        "title": "Command Center",
        "summary": "Aggregate-first quality cockpit for mega-scale evaluation: cohorts and containers first, annotations only at deepest drill-down.",
        "key_actions": [
            "Switch population / evaluation run / baseline",
            "Generate a population or launch an evaluation run",
            "Drill cohorts, sort containers, compare runs for promotion",
        ],
    },
    "overview": {
        "title": "Overview",
        "summary": "Single-glance pipeline health: live counters, headline quality metrics, stage status and alerts.",
        "key_actions": [
            "Monitor counters and alerts",
            "Bootstrap with a synthetic dataset when empty",
            "Follow evidence links from alerts",
        ],
    },
    "datasets": {
        "title": "Datasets",
        "summary": "Registry of ingested datasets — the pipeline entry point.",
        "key_actions": ["Ingest or select the active dataset", "Inspect per-group quality metrics"],
    },
    "label-generation": {
        "title": "Label Generation",
        "summary": "Auto-labeling queue: raw frames → candidate labels with live throughput.",
        "key_actions": ["Start or re-run label generation", "Monitor queue depth and class mix"],
    },
    "rare-events": {
        "title": "Rare Events",
        "summary": "Anomaly-ensemble mining for the long tail of risky samples.",
        "key_actions": ["Tune detectors and fusion strategy", "Re-run detection and benchmark techniques"],
    },
    "raremine": {
        "title": "Rare-Event Miner",
        "summary": "Multimodal miner for costumed pedestrians — proposals, never verdicts.",
        "key_actions": ["Generate a scene bank", "Run the miner", "Approve or reject candidates into datasets"],
    },
    "quality": {
        "title": "Quality Engine",
        "summary": "GT-free structural validation: geometry, sensor consistency, plausibility.",
        "key_actions": ["Inspect pass/fail distributions per check", "Trace thresholds to the quality policy"],
    },
    "regression": {
        "title": "Regression",
        "summary": "Model-version regression tracking across quality metrics and classes.",
        "key_actions": ["Compare model versions", "Inspect regressed classes and deltas"],
    },
    "rca": {
        "title": "Root Cause Lab",
        "summary": "Staged offline-vs-shadow forensics for regression root causes.",
        "key_actions": ["Walk staged RCA boards", "Compare offline and shadow evidence"],
    },
    "triage": {
        "title": "Triage",
        "summary": "Quality-policy gate routing: AUTO_GRADED / FLAGGED / REJECTED with reasons.",
        "key_actions": ["Review gate lines and failure reasons", "Inspect routing counts"],
    },
    "review": {
        "title": "Human Review",
        "summary": "HITL queue for flagged and sampled labels with multi-sensor evidence.",
        "key_actions": ["Verify, correct, or reject labels", "Use sampling plans for CI-backed metrics"],
    },
    "training": {
        "title": "Training",
        "summary": "Flywheel: verified labels → training jobs → new model versions.",
        "key_actions": ["Select a verified dataset", "Start training", "Watch job metrics"],
    },
    "models": {
        "title": "Models",
        "summary": "Registered model versions and their evaluation / regression status.",
        "key_actions": ["Browse models", "Open regression status for a version"],
    },
    "evaluation": {
        "title": "Evaluation Records",
        "summary": "Per-annotation evaluation evidence browser.",
        "key_actions": ["Search and open evaluation records", "Ask the MITL copilot for advisory analysis"],
    },
    "audit": {
        "title": "Audit",
        "summary": "Process-unit accounting and immutable audit trail of decisions.",
        "key_actions": ["Inspect process units", "Filter audit events"],
    },
    "pipeline": {
        "title": "Pipeline Architecture",
        "summary": "How Sensorflow stages connect from ingest through flywheel.",
        "key_actions": ["Read the architecture diagram", "Jump to related pages"],
    },
    "hillclimb": {
        "title": "Hill Climbing EM",
        "summary": "Adaptive EM development and interview-readiness coaching.",
        "key_actions": ["Run interviews and design lab", "Track readiness scores"],
    },
    "vitis": {
        "title": "Hardware Acceleration",
        "summary": "Vitis Vision HIL: quantization gap, ISP augment, temporal stability (emulated).",
        "key_actions": ["Run HIL / ISP / temporal demos", "Compare CPU vs accelerated paths"],
    },
    "ssam": {
        "title": "SSAM Safety",
        "summary": "Legacy statewide SSAM conflict map and street annotations.",
        "key_actions": ["Query statewide conflicts", "Annotate streets on the map"],
    },
    "safety-odd": {
        "title": "ODD Coverage",
        "summary": "Operational design domain coverage vs required cells.",
        "key_actions": ["Inspect coverage gaps", "Filter ODD dimensions"],
    },
    "safety-gates": {
        "title": "Release Gates",
        "summary": "Deterministic release / stop-ship gates for safety claims.",
        "key_actions": ["Evaluate gate sets", "Read fail reasons"],
    },
    "safety-evidence": {
        "title": "Evidence Package",
        "summary": "Assembled safety evidence package for a release candidate.",
        "key_actions": ["Browse evidence artifacts", "Export package summaries"],
    },
    "safety-ssam": {
        "title": "SSAM Conflicts",
        "summary": "SSAM conflict analysis integrated into the safety layer.",
        "key_actions": ["Inspect TTC/PET conflicts", "Link conflicts to scenarios"],
    },
    "safety-calibration": {
        "title": "Calibration",
        "summary": "Sensor calibration validation across camera–LiDAR extrinsics.",
        "key_actions": ["Run calibration checks", "Inspect residual errors"],
    },
    "safety-discrepancy": {
        "title": "Discrepancy Mining",
        "summary": "Mine disagreements between sensors, graders, or model versions.",
        "key_actions": ["Run discrepancy queries", "Triage high-value disagreements"],
    },
    "safety-scenarios": {
        "title": "Scenario DB",
        "summary": "Structured scenario database for safety evaluation coverage.",
        "key_actions": ["Filter scenarios", "Inspect tags and outcomes"],
    },
    "safety-search": {
        "title": "Semantic Search",
        "summary": "Natural-language / semantic search over safety scenarios.",
        "key_actions": ["Query scenarios in plain language", "Open matching scenario cards"],
    },
    "seqeval": {
        "title": "Sequential Regression",
        "summary": "Anytime-valid sequential regression testing with budgets and pairing.",
        "key_actions": ["Configure sequential tests", "Read six-outcome regression status"],
    },
    "bevfusion": {
        "title": "Perception Engines",
        "summary": "BEV fusion camera+LiDAR perception demos and self-eval.",
        "key_actions": ["Run fusion scenes", "Inspect BEV replay and tracks"],
    },
    "scenario-composer": {
        "title": "Scenario Composer",
        "summary": "Compose synthetic evaluation scenarios for studio workflows.",
        "key_actions": ["Build scenario configs", "Save layouts"],
    },
    "pipeline-builder": {
        "title": "Pipeline Builder",
        "summary": "Visual pipeline composition for studio evaluation flows.",
        "key_actions": ["Connect pipeline nodes", "Persist builder layouts"],
    },
    "my-dashboard": {
        "title": "My Dashboard",
        "summary": "Personalizable studio dashboard of key evaluation widgets.",
        "key_actions": ["Arrange widgets", "Save dashboard layout"],
    },
    "retro": {
        "title": "Retrospective Analyzer",
        "summary": "Evidence-tiered failure retrospectives with safety-case RAG.",
        "key_actions": ["Open a retrospective case", "Review severity and launch policy"],
    },
    "closed-loop-lab": {
        "title": "Closed-Loop Lab",
        "summary": "Closed-loop behavioral evaluation and counterfactual simulation.",
        "key_actions": ["Run closed-loop scenarios", "Inspect validity gates"],
    },
    "launch-readiness": {
        "title": "Launch Readiness",
        "summary": "Agentic misclassification triage and launch-readiness scorecard.",
        "key_actions": ["Run agentic triage", "Read launch verdict and evidence graph"],
    },
    "studio2": {
        "title": "Studio 2.0 Governance",
        "summary": "Control plane: entity registry, release gate matrix, observability funnel.",
        "key_actions": ["Browse registry entities", "Evaluate release gate", "Inspect funnel"],
    },
    "legacy": {
        "title": "Legacy Studio",
        "summary": "Classic YOLO train/infer/SSAM studio embedded for compatibility.",
        "key_actions": ["Use legacy train/infer workflows", "Open full-window legacy UI"],
    },
    "production-readiness": {
        "title": "Production Readiness",
        "summary": "Hardening audit scorecard — honest NOT PRODUCTION READY while Criticals remain.",
        "key_actions": ["Filter findings", "Follow FILE:LINE refs", "Review remediation board"],
    },
    "rotr": {
        "title": "ROTR Control Center",
        "summary": "Right-of-the-road violation detection, attribution, consequence, and flywheel.",
        "key_actions": [
            "Generate a scenario bank and run detection",
            "Inspect attribution and consequence replay",
            "Validate HITL items into the regression suite",
        ],
    },
}

PLATFORM_OVERVIEW = (
    "Sensorflow Studio evaluates machine-generated perception labels at scale. "
    "The core loop: measure every label, gate it against a versioned quality policy, "
    "route the uncertain minority to humans (HITL), and feed verified results back into "
    "training. Aggregates lead; individual annotations are drill-down. Major areas: "
    "Command Center (megaeval), label pipeline (datasets → generation → quality → triage → review), "
    "safety & compliance, perception engines (BEV/seqeval), ROTR, and Studio 2.0 governance."
)

STATIC_FAQS: List[Dict[str, str]] = [
    {
        "id": "faq-what-is-sensorflow",
        "title": "What is Sensorflow Studio?",
        "question": "what is sensorflow studio platform overview purpose",
        "answer": PLATFORM_OVERVIEW,
    },
    {
        "id": "faq-how-to-start",
        "title": "How do I get started?",
        "question": "how to start begin bootstrap first steps empty overview",
        "answer": (
            "On Overview, if counters are zero, click “Generate synthetic dataset & run pipeline”. "
            "Or open Datasets to ingest/select data, then Label Generation → Quality → Triage → Human Review. "
            "For mega-scale aggregates, open Command Center and generate a population, then launch an evaluation run."
        ),
    },
    {
        "id": "faq-nav-tips",
        "title": "Navigation tips",
        "question": "keyboard navigation tips hash url sidebar drawer navigate pages",
        "answer": (
            "Use the left drawer to switch pages. URLs are hash-routed (#/page or #/page/entityId) so "
            "browser back/forward and deep links work. The AppBar (?) opens Help (How it works, Glossary, "
            "Pages, Tips, Docs). The chat bubble answers questions about pages and features. "
            "Page headers include an expandable “About this page” panel."
        ),
    },
    {
        "id": "faq-hitl",
        "title": "When do humans review labels?",
        "question": "human review hitl flagged triage sampling verify correct reject",
        "answer": (
            "Triage routes gate failures to FLAGGED (and hopeless cases to REJECTED). Flagged labels plus "
            "statistically sampled labels enter Human Review. Reviewers verify, correct, or reject with "
            "camera / LiDAR / BEV / temporal evidence. Sampling also puts confidence intervals on headline metrics."
        ),
    },
    {
        "id": "faq-no-gpu",
        "title": "Does the help chatbot need a GPU?",
        "question": "gpu ollama llm offline cpu space chatbot requirements",
        "answer": (
            "No. Help chat uses a local FAQ / page-guide matcher by default and works on CPU Hugging Face Spaces. "
            "If a local Ollama endpoint is reachable it may enrich answers; otherwise you still get deterministic FAQ replies."
        ),
    },
    {
        "id": "faq-quality-vs-eval",
        "title": "Quality Engine vs Evaluation Records",
        "question": "difference quality engine evaluation records gt-free reference",
        "answer": (
            "Quality Engine runs GT-free structural checks (geometry, point support, sensor agreement) on every label. "
            "Evaluation Records show per-annotation measurements when reference GT or graders are available, including "
            "IoU, anomaly scores, and triage decisions."
        ),
    },
    {
        "id": "faq-docs",
        "title": "Where are the docs?",
        "question": "documentation docs architecture prd hardening readme",
        "answer": (
            "In-repo docs live under hf-space/docs/ (architecture, hardening audit, PRDs, retro reports) plus "
            "top-level README / ARCHITECTURE / DASHBOARD_README. The Help menu Docs tab lists the same guides."
        ),
    },
]


def _version_faqs() -> List[Dict[str, str]]:
    """FAQs derived from the About catalog so version numbers stay in sync."""
    about = get_about()
    version = about["version"]
    name = about["name"]
    links = about["links"]
    releases = about["releases"] or []
    latest = releases[0] if releases else {"version": version, "date": "", "title": "", "highlights": []}
    highlights = "; ".join(str(h) for h in (latest.get("highlights") or [])[:6])
    history = "; ".join(f"{r.get('version')} ({r.get('date')}) {r.get('title')}" for r in releases[:8])
    return [
        {
            "id": "faq-version",
            "title": "What version is Sensorflow Studio?",
            "question": "what version current app version about release number v0",
            "answer": (
                f"{name} is version {version}. Click the AppBar v{version} chip or open Help → About. "
                f"GitHub: {links['github']}. Hugging Face Space: {links['hf_space']}."
            ),
        },
        {
            "id": "faq-whats-new",
            "title": "What's new?",
            "question": "what's new whats new recent changes updates latest release changelog",
            "answer": (
                f"Latest release {latest.get('version')} ({latest.get('date')}): {latest.get('title')}. "
                f"{highlights} Open Help → About or the version chip for the full list."
            ),
        },
        {
            "id": "faq-release-notes",
            "title": "Where are the release notes?",
            "question": "release notes changelog versions history each version about page",
            "answer": (
                f"Release notes are listed newest-first on About (Help → About, or the v{version} chip). "
                f"Notable versions: {history}."
            ),
        },
        {
            "id": "faq-about",
            "title": "About Sensorflow Studio",
            "question": "about sensorflow studio product github huggingface space links",
            "answer": (
                f"{about['description']} Current version {version}. "
                f"GitHub: {links['github']}. Hugging Face Space: {links['hf_space']}."
            ),
        },
    ]


STATIC_FAQS.extend(_version_faqs())


@dataclass(frozen=True)
class KnowledgeDoc:
    id: str
    title: str
    kind: str  # page | faq | docs
    text: str
    page_id: Optional[str] = None


def _docs_root() -> Path:
    # sensorflow/help/ → hf-space/
    return Path(__file__).resolve().parents[2] / "docs"


def _snippet_from_markdown(path: Path, max_chars: int = 900) -> str:
    try:
        raw = path.read_text(encoding="utf-8", errors="ignore")
    except OSError:
        return ""
    lines: List[str] = []
    for line in raw.splitlines():
        s = line.strip()
        if not s or s.startswith("```"):
            continue
        if s.startswith("#"):
            s = s.lstrip("#").strip()
        lines.append(s)
        if sum(len(x) for x in lines) > max_chars:
            break
    return " ".join(lines)[:max_chars]


@lru_cache(maxsize=1)
def build_knowledge_index() -> List[KnowledgeDoc]:
    docs: List[KnowledgeDoc] = []

    docs.append(
        KnowledgeDoc(
            id="platform-overview",
            title="Platform overview",
            kind="faq",
            text=PLATFORM_OVERVIEW,
        )
    )

    for pid, guide in PAGE_GUIDES.items():
        title = str(guide["title"])
        summary = str(guide["summary"])
        actions = "; ".join(str(a) for a in guide.get("key_actions", []))  # type: ignore[arg-type]
        text = f"{title}. {summary} Key actions: {actions}"
        docs.append(
            KnowledgeDoc(
                id=f"page:{pid}",
                title=title,
                kind="page",
                text=text,
                page_id=pid,
            )
        )

    for faq in STATIC_FAQS:
        docs.append(
            KnowledgeDoc(
                id=faq["id"],
                title=faq["title"],
                kind="faq",
                text=f"{faq['question']}. {faq['answer']}",
            )
        )

    root = _docs_root()
    preferred = [
        "PLATFORM_INVENTORY.md",
        "POPULATION_SCALE_ROADMAP.md",
        "hardening/audit.md",
        "architecture/rotr-architecture.md",
        "architecture/studio2-review.md",
        "architecture/nextgen-adr.md",
        "prd/vitis-hil-regression.md",
        "retro/final-report.md",
    ]
    for rel in preferred:
        path = root / rel
        if not path.is_file():
            continue
        snippet = _snippet_from_markdown(path)
        if not snippet:
            continue
        docs.append(
            KnowledgeDoc(
                id=f"docs:{rel}",
                title=f"Docs · {rel}",
                kind="docs",
                text=snippet,
            )
        )

    return docs


def list_page_guides() -> List[Dict[str, object]]:
    out: List[Dict[str, object]] = []
    for pid, guide in PAGE_GUIDES.items():
        out.append(
            {
                "page_id": pid,
                "title": guide["title"],
                "summary": guide["summary"],
                "key_actions": guide["key_actions"],
            }
        )
    return out