| # `ui/` โ AI usage evaluator UI shell |
|
|
| Self-contained Gradio front-end. Runs standalone (no backend / ML deps) so it can be developed |
| and deployed independently of the `prompt_card` workstream. |
|
|
| ## Run |
| ```bash |
| python -m ui.app # serves the Gradio app |
| ``` |
|
|
| ## Layout |
| ``` |
| ui/ |
| app.py # gr.Blocks, event wiring, the staged-reveal generator |
| theme.py # design tokens, dark CSS, CDN head (fonts + Chart.js + flip/radar JS) |
| data.py # CardData contract + stub provider โ shared data shape |
| components/card.py# render CardData -> flip-card HTML + accordion bodies |
| screens/ # intake / processing / result column builders |
| parsing/ # Task 2: ChatGPT+Claude .json/.zip parser + zero-dep language gate |
| scoring/ # Task 3: Scorer protocol + DummyScorer (heuristic placeholder) |
| ``` |
|
|
| ## The three adoption seams (where the real backend plugs in) |
| 1. **Parsing** โ `ui/parsing/parser.py::parse_export(path) -> ParsedExport`. |
| Mirrors the real export shapes; the backend's `prompt_card.adapters` are the reuse target |
| when the workstreams merge. |
| 2. **Scoring** โ `ui/scoring/interface.py::Scorer`. Implement `score(parsed) -> ScoreResult` |
| with a real model and pass it where `DummyScorer()` is used in `app.py`. The UI is unchanged. |
| 3. **Card data** โ `ui/data.py::CardData` is the stable render contract. `score_to_card` maps a |
| `ScoreResult` onto it. |
|
|
| ## Status (stubbed vs real) |
| - Real: export parsing, language split, processing facts (counts/date range/busiest slot). |
| - **Scoring ADOPTED** (`ui/scoring/observable.py::ObservableScorer`): the 5 axis scores, overall/tier, and |
| per-axis confidence (measured Cohen's ฮบ) now come from the backend `prompt_card.observable_pipeline` |
| (base MiniCPM4.1-8B + the locked per-category LoRA hybrid). `app.py` calls `get_scorer()`, which returns |
| the real scorer when `OPENBMB_BASE_URL`/`OPENBMB_TOKEN` are set, else falls back to `DummyScorer` (so the |
| UI still runs standalone with zero ML deps). A live scoring failure degrades to the dummy mid-demo. |
| - Now REAL too: per-axis **evidence quotes** are the actual user turns where each axis fired (pipeline |
| `data["evidence"]`; falls back to a representative turn only when an axis had zero positives), and the |
| **critical breakdown** shows true per-type **counts** (pipeline `data["critical_type_counts"]`). |
| - Still heuristic/static: the per-axis **tips** and the **improvement** line (advice, not measurements). |
|
|