| from pathlib import Path |
|
|
| from fastapi import APIRouter, HTTPException, Request |
| from fastapi.responses import HTMLResponse |
| from fastapi.templating import Jinja2Templates |
|
|
| from app.services.engine_registry import get_engine_registry |
| from app.services.job_store import get_job, list_jobs |
|
|
| templates = Jinja2Templates( |
| directory=str(Path(__file__).resolve().parent.parent / "templates") |
| ) |
|
|
| router = APIRouter(prefix="", tags=["ui"]) |
|
|
| UI_MODEL_LABELS = { |
| "supertonic-2": "Supertonic", |
| "kitten-tts-micro-0.8": "Kitten", |
| "kokoro": "Kokoro", |
| "melo-en": "Melo", |
| } |
|
|
|
|
| @router.get("/", response_class=HTMLResponse) |
| async def index_page(request: Request) -> HTMLResponse: |
| registry = get_engine_registry() |
| ui_models: list[dict[str, str]] = [] |
| voice_map: dict[str, list[dict]] = {} |
| for model, label in UI_MODEL_LABELS.items(): |
| try: |
| engine = registry.get_engine(model) |
| ui_models.append({"id": model, "label": label}) |
| voice_map[model] = [ |
| {"alias": b["alias"], "canonical_name": b["canonical_name"]} |
| for b in engine.list_voice_bindings() |
| if b.get("source") != "private" |
| ] |
| except Exception: |
| continue |
| return templates.TemplateResponse( |
| "index.html", |
| { |
| "request": request, |
| "ui_models": ui_models, |
| "voice_map": voice_map, |
| "recent_jobs": list_jobs(limit=5), |
| }, |
| ) |
|
|
|
|
| @router.get("/jobs/{job_id}", response_class=HTMLResponse) |
| async def job_page(request: Request, job_id: str) -> HTMLResponse: |
| job = get_job(job_id) |
| if job is None: |
| raise HTTPException(status_code=404, detail="Job not found") |
| return templates.TemplateResponse("job.html", {"request": request, "job": job}) |
|
|