Files
guides/backend/routes.py
2026-05-25 22:59:37 +02:00

111 lines
3.6 KiB
Python

import asyncio
import uuid
from datetime import datetime, timezone
from pathlib import Path
from fastapi import APIRouter, HTTPException
from fastapi.responses import FileResponse
from config import FORMAT_META, STORAGE_DIR
from database import create_guide, delete_guide, get_guide, list_guides
from generator import generate_guide, rework_guide, cancel_guide
from models import GuideCreateRequest, GuideReworkRequest, GuideResponse
router = APIRouter(prefix="/api")
@router.get("/formats")
async def get_formats():
return FORMAT_META
@router.post("/guides", response_model=GuideResponse)
async def create(req: GuideCreateRequest):
now = datetime.now(timezone.utc).isoformat()
guide = {
"id": str(uuid.uuid4()),
"topic": req.topic.strip(),
"format": req.format,
"instructions": req.instructions.strip(),
"status": "queued",
"progress": None,
"html_path": None,
"pdf_path": None,
"created_at": now,
"updated_at": now,
}
await create_guide(guide)
asyncio.create_task(generate_guide(guide["id"], guide["topic"], guide["format"], guide["instructions"]))
return guide
@router.get("/guides", response_model=list[GuideResponse])
async def list_all():
return await list_guides()
@router.get("/guides/{guide_id}", response_model=GuideResponse)
async def get_one(guide_id: str):
guide = await get_guide(guide_id)
if guide is None:
raise HTTPException(404, "Guide nicht gefunden")
return guide
@router.get("/guides/{guide_id}/html")
async def download_html(guide_id: str):
guide = await get_guide(guide_id)
if guide is None:
raise HTTPException(404, "Guide nicht gefunden")
if guide["status"] != "done" or not guide["html_path"]:
raise HTTPException(404, "HTML nicht verfügbar")
path = Path(guide["html_path"])
if not path.exists():
raise HTTPException(404, "Datei nicht gefunden")
return FileResponse(path, filename=f"{guide['topic']}-{guide['format']}.html", media_type="text/html")
@router.post("/guides/{guide_id}/rework")
async def rework(guide_id: str, req: GuideReworkRequest):
guide = await get_guide(guide_id)
if guide is None:
raise HTTPException(404, "Guide nicht gefunden")
if guide["status"] != "done":
raise HTTPException(400, "Guide muss fertig sein")
asyncio.create_task(rework_guide(guide_id, guide["topic"], guide["format"], req.instructions.strip()))
return {"ok": True}
@router.post("/guides/{guide_id}/cancel")
async def cancel(guide_id: str):
cancelled = await cancel_guide(guide_id)
if not cancelled:
raise HTTPException(404, "Kein aktiver Prozess gefunden")
return {"ok": True}
@router.get("/guides/{guide_id}/pdf")
async def download_pdf(guide_id: str):
guide = await get_guide(guide_id)
if guide is None:
raise HTTPException(404, "Guide nicht gefunden")
if guide["status"] != "done" or not guide["pdf_path"]:
raise HTTPException(404, "PDF nicht verfügbar")
path = Path(guide["pdf_path"])
if not path.exists():
raise HTTPException(404, "Datei nicht gefunden")
return FileResponse(path, filename=f"{guide['topic']}-{guide['format']}.pdf", media_type="application/pdf")
@router.delete("/guides/{guide_id}")
async def remove(guide_id: str):
guide = await get_guide(guide_id)
if guide is None:
raise HTTPException(404, "Guide nicht gefunden")
if guide["html_path"]:
Path(guide["html_path"]).unlink(missing_ok=True)
if guide["pdf_path"]:
Path(guide["pdf_path"]).unlink(missing_ok=True)
await delete_guide(guide_id)
return {"ok": True}