Commit
路
0771b1e
1
Parent(s):
cb33bba
ahora debe poder devolver html sin css
Browse files- README.md +27 -0
- app/main.py +1 -1
- app/renderer.py +13 -3
- app/templates/base.html.j2 +4 -0
README.md
CHANGED
|
@@ -8,3 +8,30 @@ pinned: false
|
|
| 8 |
---
|
| 9 |
|
| 10 |
Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 8 |
---
|
| 9 |
|
| 10 |
Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
|
| 11 |
+
|
| 12 |
+
## Manual verification
|
| 13 |
+
|
| 14 |
+
Run the API locally:
|
| 15 |
+
|
| 16 |
+
```
|
| 17 |
+
uvicorn app.main:app --reload
|
| 18 |
+
```
|
| 19 |
+
|
| 20 |
+
Render HTML without inline styles:
|
| 21 |
+
|
| 22 |
+
```
|
| 23 |
+
curl -X POST http://localhost:8000/compile/html ^
|
| 24 |
+
-H "Content-Type: application/json" ^
|
| 25 |
+
-d @sample.json > out.html
|
| 26 |
+
findstr /i "<style" out.html && echo "inline styles found"
|
| 27 |
+
```
|
| 28 |
+
|
| 29 |
+
Render PDF (keeps styles for WeasyPrint):
|
| 30 |
+
|
| 31 |
+
```
|
| 32 |
+
curl -X POST http://localhost:8000/compile/pdf ^
|
| 33 |
+
-H "Content-Type: application/json" ^
|
| 34 |
+
-d @sample.json --output out.pdf
|
| 35 |
+
```
|
| 36 |
+
|
| 37 |
+
Open `out.pdf` to visually confirm the layout.
|
app/main.py
CHANGED
|
@@ -61,7 +61,7 @@ def compile_html(req: CompileRequest):
|
|
| 61 |
raise HTTPException(status_code=400, detail="Campo 'doc' es obligatorio")
|
| 62 |
|
| 63 |
try:
|
| 64 |
-
html = render_html(req.doc)
|
| 65 |
except Exception as exc:
|
| 66 |
raise HTTPException(
|
| 67 |
status_code=500,
|
|
|
|
| 61 |
raise HTTPException(status_code=400, detail="Campo 'doc' es obligatorio")
|
| 62 |
|
| 63 |
try:
|
| 64 |
+
html = render_html(req.doc, mode="html")
|
| 65 |
except Exception as exc:
|
| 66 |
raise HTTPException(
|
| 67 |
status_code=500,
|
app/renderer.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
| 1 |
from __future__ import annotations
|
| 2 |
|
| 3 |
from datetime import datetime
|
| 4 |
-
from typing import Any, Dict
|
| 5 |
|
| 6 |
from jinja2 import Environment, FileSystemLoader, select_autoescape
|
| 7 |
from weasyprint import HTML
|
|
@@ -111,13 +111,23 @@ def _resolve_template(doc: Dict[str, Any]) -> str:
|
|
| 111 |
# =========================
|
| 112 |
# RENDER HTML
|
| 113 |
# =========================
|
| 114 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 115 |
template_name = _resolve_template(doc)
|
| 116 |
template = env.get_template(template_name)
|
| 117 |
|
|
|
|
|
|
|
|
|
|
| 118 |
return template.render(
|
| 119 |
doc=doc,
|
| 120 |
generated_at=datetime.utcnow().strftime("%Y-%m-%d %H:%M UTC"),
|
|
|
|
| 121 |
)
|
| 122 |
|
| 123 |
|
|
@@ -125,7 +135,7 @@ def render_html(doc: Dict[str, Any]) -> str:
|
|
| 125 |
# RENDER PDF
|
| 126 |
# =========================
|
| 127 |
def render_pdf_bytes(doc: Dict[str, Any]) -> bytes:
|
| 128 |
-
html = render_html(doc)
|
| 129 |
|
| 130 |
pdf_bytes: bytes = HTML(
|
| 131 |
string=html,
|
|
|
|
| 1 |
from __future__ import annotations
|
| 2 |
|
| 3 |
from datetime import datetime
|
| 4 |
+
from typing import Any, Dict, Literal
|
| 5 |
|
| 6 |
from jinja2 import Environment, FileSystemLoader, select_autoescape
|
| 7 |
from weasyprint import HTML
|
|
|
|
| 111 |
# =========================
|
| 112 |
# RENDER HTML
|
| 113 |
# =========================
|
| 114 |
+
RenderMode = Literal["html", "pdf"]
|
| 115 |
+
|
| 116 |
+
|
| 117 |
+
# =========================
|
| 118 |
+
# RENDER HTML
|
| 119 |
+
# =========================
|
| 120 |
+
def render_html(doc: Dict[str, Any], mode: RenderMode = "html") -> str:
|
| 121 |
template_name = _resolve_template(doc)
|
| 122 |
template = env.get_template(template_name)
|
| 123 |
|
| 124 |
+
normalized_mode = (mode or "html").lower()
|
| 125 |
+
include_styles = normalized_mode == "pdf"
|
| 126 |
+
|
| 127 |
return template.render(
|
| 128 |
doc=doc,
|
| 129 |
generated_at=datetime.utcnow().strftime("%Y-%m-%d %H:%M UTC"),
|
| 130 |
+
include_styles=include_styles,
|
| 131 |
)
|
| 132 |
|
| 133 |
|
|
|
|
| 135 |
# RENDER PDF
|
| 136 |
# =========================
|
| 137 |
def render_pdf_bytes(doc: Dict[str, Any]) -> bytes:
|
| 138 |
+
html = render_html(doc, mode="pdf")
|
| 139 |
|
| 140 |
pdf_bytes: bytes = HTML(
|
| 141 |
string=html,
|
app/templates/base.html.j2
CHANGED
|
@@ -4,6 +4,7 @@
|
|
| 4 |
<meta charset="UTF-8" />
|
| 5 |
<title>{{ doc.metadata.description or "Documentaci贸n de Script" }}</title>
|
| 6 |
|
|
|
|
| 7 |
{# Opcional: si QUIERES forzar Inter en modo PDF standalone, descomenta esto
|
| 8 |
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
| 9 |
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
|
@@ -12,7 +13,9 @@
|
|
| 12 |
rel="stylesheet"
|
| 13 |
/>
|
| 14 |
#}
|
|
|
|
| 15 |
|
|
|
|
| 16 |
<style>
|
| 17 |
/* ----------------------------------------
|
| 18 |
VARIABLES DE TEMA (sobrescribibles)
|
|
@@ -296,6 +299,7 @@
|
|
| 296 |
background: var(--doc-color-surface);
|
| 297 |
}
|
| 298 |
</style>
|
|
|
|
| 299 |
</head>
|
| 300 |
<body>
|
| 301 |
<div class="doc-page">
|
|
|
|
| 4 |
<meta charset="UTF-8" />
|
| 5 |
<title>{{ doc.metadata.description or "Documentaci贸n de Script" }}</title>
|
| 6 |
|
| 7 |
+
{% if include_styles | default(true) %}
|
| 8 |
{# Opcional: si QUIERES forzar Inter en modo PDF standalone, descomenta esto
|
| 9 |
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
| 10 |
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
|
|
|
| 13 |
rel="stylesheet"
|
| 14 |
/>
|
| 15 |
#}
|
| 16 |
+
{% endif %}
|
| 17 |
|
| 18 |
+
{% if include_styles | default(true) %}
|
| 19 |
<style>
|
| 20 |
/* ----------------------------------------
|
| 21 |
VARIABLES DE TEMA (sobrescribibles)
|
|
|
|
| 299 |
background: var(--doc-color-surface);
|
| 300 |
}
|
| 301 |
</style>
|
| 302 |
+
{% endif %}
|
| 303 |
</head>
|
| 304 |
<body>
|
| 305 |
<div class="doc-page">
|