111 lines
3.6 KiB
Python
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}
|