"""Render and stream real assessment stages without estimated percentages.""" import html from contextvars import copy_context from queue import Queue from threading import Thread def stage_names(mode): steps = [("audio", "Prepare audio"), ("model", "Prepare model")] if mode == "Reference-free": steps.append(("transcribe", "Transcribe speech")) return steps + [("score", "Scoring")] def stage_markup(mode, active=None, complete=False, failed=False): steps = stage_names(mode) index = next((i for i, (key, _) in enumerate(steps) if key == active), -1) items = [] for i, (key, label) in enumerate(steps): state = "done" if complete or 0 <= i < index else "active" if i == index else "pending" if failed and i == index: state = "failed" number = "✓" if state == "done" else str(i + 1) items.append(f'
' f'{number}{label}' '
') caption = "Assessment complete" if complete else "Assessment stopped" if failed else ( f"Stage {index + 1} of {len(steps)} · {steps[index][1]}" if index >= 0 else f"{len(steps)} assessment stages") return '
' + html.escape(caption) + '
' + ''.join(items) + '
' def stream_work(work): """Run blocking inference while forwarding stage transitions to Gradio.""" events = Queue() def run(): try: result = work(lambda stage: events.put(("stage", stage))) events.put(("result", result)) except Exception as error: events.put(("error", error)) context = copy_context() Thread(target=lambda: context.run(run), daemon=True).start() while True: kind, payload = events.get() yield kind, payload if kind != "stage": return