trace-reports / app.py
mervenoyan's picture
Switch back to Inference Providers (Qwen3.5-9B)
2d3963a
"""Gradio Server app: custom HTML frontend + Gradio-managed API endpoint.
The input UI lives in `index.html` and talks to the `generate_bulletin`
endpoint below via `@gradio/client`. Report generation logic is unchanged
from the original Blocks app.
"""
import os
from pathlib import Path
from fastapi.responses import HTMLResponse
from gradio import Server
from analyze import build_report, compute_stats, digest_all, get_client
from dataset import fetch_sessions, list_sessions
from extract import events_to_transcript, truncate_transcript
from render import bulletin_html, empty_bulletin_html
DEFAULT_REPO = "julien-c/pi-sessions"
app = Server()
_INDEX = Path(__file__).parent / "index.html"
def _owner_from(repo_id: str) -> str:
return repo_id.split("/")[0] if "/" in repo_id else repo_id
@app.api(name="generate_bulletin", concurrency_limit=1)
def generate_bulletin(
repo_id: str, max_sessions: int
) -> tuple[str, str]:
"""Streams (status, html) updates; final tick carries the bulletin HTML."""
yield "Connecting…", empty_bulletin_html("Connecting…")
try:
client = get_client()
except Exception as e:
yield f"❌ {e}", empty_bulletin_html("HF_TOKEN missing")
return
try:
yield "Listing sessions…", empty_bulletin_html("Listing sessions…")
paths = list_sessions(repo_id)
if not paths:
yield (
"No sessions found in `sessions/**/*.jsonl`.",
empty_bulletin_html("No sessions to roast."),
)
return
n = min(int(max_sessions), len(paths))
yield (
f"Fetching {n} of {len(paths)} sessions…",
empty_bulletin_html(f"Fetching {n} sessions…"),
)
sessions = fetch_sessions(repo_id, n)
if not sessions:
yield (
"Found session files but couldn't parse any.",
empty_bulletin_html("Parse error."),
)
return
stats = compute_stats(sessions)
transcripts = [
(path, truncate_transcript(events_to_transcript(evs), 40_000))
for path, evs in sessions
]
yield (
f"Reading {len(transcripts)} sessions in parallel…",
empty_bulletin_html("Consulting the traces…"),
)
digests = digest_all(client, transcripts)
if not digests:
yield (
"Every per-session digest failed. Try again or lower max sessions.",
empty_bulletin_html("Digest error."),
)
return
yield (
f"Drafting bulletin from {len(digests)} digests…",
empty_bulletin_html("Drafting bulletin…"),
)
owner = _owner_from(repo_id)
try:
report = build_report(
client=client,
digests=digests,
user=owner,
dataset_id=repo_id,
stats=stats,
)
except Exception as e:
yield (
f"❌ Bulletin generation failed: {e}",
empty_bulletin_html("The presses jammed."),
)
return
yield (
f"Bulletin issued for @{report['user']}{report['archetype'][0]} {report['archetype'][1]}.",
bulletin_html(report),
)
except Exception as e:
yield (
f"❌ {type(e).__name__}: {e}",
empty_bulletin_html("Error."),
)
@app.get("/", response_class=HTMLResponse)
async def homepage():
return _INDEX.read_text(encoding="utf-8")
if __name__ == "__main__":
if not os.environ.get("HF_TOKEN"):
print("warning: HF_TOKEN not set; the app will error on the first click.")
app.launch(show_error=True)