|
|
from __future__ import annotations |
|
|
|
|
|
import io |
|
|
from typing import Any, Dict, Literal, Optional |
|
|
|
|
|
from fastapi import FastAPI, HTTPException |
|
|
from fastapi.responses import HTMLResponse, RedirectResponse, StreamingResponse |
|
|
from pydantic import BaseModel, Field |
|
|
|
|
|
from .renderer import render_html, render_pdf_bytes |
|
|
|
|
|
app = FastAPI( |
|
|
title="Doc Compiler Service", |
|
|
version="1.0.0", |
|
|
description=( |
|
|
"Servicio de compilaci贸n que recibe JSON de documentaci贸n, " |
|
|
"renderiza plantillas Jinja2 y devuelve HTML o PDF." |
|
|
), |
|
|
) |
|
|
|
|
|
|
|
|
class CompileRequest(BaseModel): |
|
|
doc: Dict[str, Any] = Field( |
|
|
..., |
|
|
description=( |
|
|
"JSON de documentaci贸n generado por la IA " |
|
|
"(incluyendo metadata.script_type)." |
|
|
), |
|
|
) |
|
|
job_id: Optional[str] = Field( |
|
|
None, |
|
|
description=( |
|
|
"Identificador opcional para el archivo " |
|
|
"(por ejemplo, nombre del script o job)." |
|
|
), |
|
|
) |
|
|
output: Literal["html", "pdf"] = Field( |
|
|
"pdf", |
|
|
description="Tipo de salida deseada. En estos endpoints se usa como referencia.", |
|
|
) |
|
|
|
|
|
|
|
|
@app.get("/") |
|
|
def root(): |
|
|
"""Endpoint ra铆z que redirige autom谩ticamente a la documentaci贸n.""" |
|
|
return RedirectResponse(url="/docs") |
|
|
|
|
|
|
|
|
@app.get("/health") |
|
|
def health_check(): |
|
|
"""Endpoint simple de healthcheck para monitoreo.""" |
|
|
return {"status": "ok"} |
|
|
|
|
|
|
|
|
@app.post("/compile/html") |
|
|
def compile_html(req: CompileRequest): |
|
|
""" |
|
|
Recibe JSON y devuelve el HTML renderizado (煤til para depuraci贸n o previsualizaci贸n). |
|
|
""" |
|
|
if not req.doc: |
|
|
raise HTTPException(status_code=400, detail="Campo 'doc' es obligatorio") |
|
|
|
|
|
try: |
|
|
html = render_html(req.doc) |
|
|
except Exception as exc: |
|
|
raise HTTPException( |
|
|
status_code=500, |
|
|
detail=f"Error al renderizar HTML: {exc}", |
|
|
) |
|
|
|
|
|
return HTMLResponse(content=html) |
|
|
|
|
|
|
|
|
@app.post("/compile/pdf") |
|
|
def compile_pdf(req: CompileRequest): |
|
|
""" |
|
|
Recibe JSON y devuelve el PDF compilado (WeasyPrint). |
|
|
""" |
|
|
if not req.doc: |
|
|
raise HTTPException(status_code=400, detail="Campo 'doc' es obligatorio") |
|
|
|
|
|
job_id = req.job_id or "document" |
|
|
|
|
|
try: |
|
|
pdf_bytes = render_pdf_bytes(req.doc) |
|
|
except Exception as exc: |
|
|
raise HTTPException( |
|
|
status_code=500, |
|
|
detail=f"Error al generar PDF: {exc}", |
|
|
) |
|
|
|
|
|
filename = f"{job_id}.pdf" |
|
|
|
|
|
return StreamingResponse( |
|
|
io.BytesIO(pdf_bytes), |
|
|
media_type="application/pdf", |
|
|
headers={"Content-Disposition": f'attachment; filename="{filename}"'}, |
|
|
) |
|
|
|