fix(#179): Scorecard via WeasyPrint-PDF (Container hat kein Chromium)
Container hat keine Playwright/Chromium-Installation — PNG-Render deferred. WeasyPrint-PDF mit exaktem Seiten-Setup (1200x630pt fuer og, 1080x1080pt fuer square) liefert jetzt /api/assessment/scorecard.pdf. Folge-Issue fuer PNG: Chromium ins Image bauen oder pypdfium2/pdf2image fuer pdf→png-Konvertierung ergaenzen.
This commit is contained in:
parent
1faf4e9220
commit
727d7d2976
71
app/main.py
71
app/main.py
@ -3413,50 +3413,67 @@ async def scorecard_template(
|
||||
})
|
||||
|
||||
|
||||
@app.get("/api/assessment/scorecard.png")
|
||||
async def api_scorecard_png(
|
||||
@app.get("/api/assessment/scorecard.pdf")
|
||||
async def api_scorecard_pdf(
|
||||
drucksache: str, bundesland: str = "NRW", format: str = "og",
|
||||
):
|
||||
"""Liefert die Scorecard als PNG via Playwright-Render (#179).
|
||||
"""Liefert die Scorecard als PDF via WeasyPrint (#179).
|
||||
|
||||
`format=og` → 1200×630, `format=square` → 1080×1080.
|
||||
`format=og` → 1200×630pt, `format=square` → 1080×1080pt.
|
||||
|
||||
PNG-Render via Playwright wird in einem Folge-Issue ergänzt
|
||||
(Container hat heute kein Chromium installiert).
|
||||
"""
|
||||
from fastapi.responses import Response as _Response
|
||||
from weasyprint import HTML, CSS
|
||||
drucksache = validate_drucksache(drucksache)
|
||||
row = await get_assessment(drucksache)
|
||||
if not row:
|
||||
raise HTTPException(status_code=404, detail="Antrag nicht gefunden")
|
||||
|
||||
if format not in ("og", "square"):
|
||||
raise HTTPException(status_code=400, detail="format muss 'og' oder 'square' sein")
|
||||
|
||||
width, height = ((1200, 630) if format == "og" else (1080, 1080))
|
||||
|
||||
# HTML aus dem internen Template ziehen (gleiche Logik wie /v2/scorecard).
|
||||
from .models import Assessment
|
||||
assessment = Assessment.model_validate(row)
|
||||
matrix_lookup = {e.field: {"rating": e.rating} for e in assessment.gwoe_matrix}
|
||||
fraktionen = list(row.get("fraktionen", []) or [])
|
||||
if isinstance(fraktionen, str):
|
||||
try:
|
||||
from playwright.sync_api import sync_playwright
|
||||
import urllib.parse as _up
|
||||
url = (
|
||||
f"http://127.0.0.1:{settings.port}/v2/scorecard"
|
||||
f"?drucksache={_up.quote(drucksache, safe='')}"
|
||||
f"&bundesland={_up.quote(bundesland)}"
|
||||
f"&format={format}"
|
||||
)
|
||||
with sync_playwright() as pw:
|
||||
browser = pw.chromium.launch(args=["--no-sandbox"])
|
||||
page = browser.new_page(viewport={"width": width, "height": height})
|
||||
page.goto(url, wait_until="networkidle", timeout=15000)
|
||||
png = page.screenshot(
|
||||
clip={"x": 0, "y": 0, "width": width, "height": height}, type="png",
|
||||
)
|
||||
browser.close()
|
||||
except Exception as e:
|
||||
logger.exception("Scorecard-Render fehlgeschlagen")
|
||||
raise HTTPException(status_code=500, detail=f"Render-Fehler: {e}")
|
||||
import json as _json
|
||||
fraktionen = _json.loads(fraktionen) or []
|
||||
except Exception:
|
||||
fraktionen = []
|
||||
|
||||
score = assessment.gwoe_score
|
||||
if score >= 8: score_color = "#1a7f37"
|
||||
elif score >= 5: score_color = "#bf6c10"
|
||||
else: score_color = "#9a2a2a"
|
||||
|
||||
template = templates.env.get_template("v2/screens/scorecard.html")
|
||||
html_content = template.render(
|
||||
request=None,
|
||||
assessment=assessment,
|
||||
bundesland=bundesland,
|
||||
matrix_lookup=matrix_lookup,
|
||||
fraktionen=fraktionen[:4],
|
||||
datum=(row.get("datum") or "")[:10],
|
||||
score_color=score_color,
|
||||
width=width,
|
||||
height=height,
|
||||
)
|
||||
|
||||
# PDF mit exakt einer Seite in der Zielgrösse
|
||||
page_size_css = f"@page {{ size: {width}px {height}px; margin: 0; }}"
|
||||
pdf = HTML(string=html_content).write_pdf(stylesheets=[CSS(string=page_size_css)])
|
||||
safe_name = drucksache.replace("/", "-")
|
||||
return Response(
|
||||
content=png, media_type="image/png",
|
||||
return _Response(
|
||||
content=pdf, media_type="application/pdf",
|
||||
headers={
|
||||
"Content-Disposition": (
|
||||
f'inline; filename="scorecard-{safe_name}-{format}.png"'
|
||||
f'inline; filename="scorecard-{safe_name}-{format}.pdf"'
|
||||
),
|
||||
"Cache-Control": "public, max-age=600",
|
||||
},
|
||||
|
||||
Loading…
Reference in New Issue
Block a user