b32669caa7
Problema: i template puntavano a un path host hardcoded
(stylesheet: /home/adriano/.../themes/tielogic.css), quindi il file .md
generato non era portabile — su un'altra macchina md-to-pdf non trovava
il CSS e produceva PDF senza stile.
Soluzione: il Renderer legge il CSS da Settings.inline_stylesheet_path
(default /app/themes/tielogic.css nel container) e lo inietta come
blocco <style>...</style> subito dopo il frontmatter YAML del Markdown
restituito dall'LLM. Il file .md risultante è autocontenuto e portabile.
- renderer.py: nuovo arg inline_stylesheet_path + funzione
_inject_inline_stylesheet (idempotente, gestisce Markdown senza
frontmatter, no-op se CSS vuoto)
- config.py: Settings.inline_stylesheet_path: Path | None
- main.py: passa il path al Renderer
- mcp-docugen.Dockerfile: COPY themes ./themes nello stage builder per
trasportare /app/themes/tielogic.css nell'immagine runtime
- templates_seed/{offerta,report-analisi}/template.md: rimossa la riga
`stylesheet:` dal frontmatter di output + regola tassativa che vieta
all'LLM di emettere blocchi <style> di sua iniziativa (evita
conflitti di cascade visti in test)
- 4 nuovi test unit (76 totali): iniezione dopo frontmatter, prepend
quando frontmatter assente, no-op CSS vuoto, integrazione full E2E
via Renderer.generate
scripts/bundle-css.py: utility per fixare file .md legacy che
referenziavano stylesheet: come path host (sostituisce la riga con
<style> inline pescando il CSS dal repo)
README aggiornato con rationale e workflow.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
85 lines
2.5 KiB
Python
Executable File
85 lines
2.5 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""Rendere autocontenuto un .md generato da mcp-docugen.
|
|
|
|
Sostituisce un eventuale `stylesheet: <path>` nel frontmatter con un
|
|
blocco `<style>` inline contenente il CSS letto dal path indicato (o dal
|
|
default `themes/tielogic.css` del repo). Il file risultante è portabile:
|
|
chi lo riceve può convertirlo in PDF anche senza avere il CSS sull'host.
|
|
|
|
Uso:
|
|
scripts/bundle-css.py <file.md> [--css path/to/theme.css] [--in-place]
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import argparse
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
REPO_ROOT = Path(__file__).resolve().parent.parent
|
|
DEFAULT_CSS = REPO_ROOT / "themes" / "tielogic.css"
|
|
|
|
FRONTMATTER_DELIM = "---"
|
|
|
|
|
|
def strip_stylesheet_line(frontmatter: str) -> str:
|
|
out = []
|
|
for line in frontmatter.splitlines():
|
|
if line.lstrip().startswith("stylesheet:"):
|
|
continue
|
|
out.append(line)
|
|
return "\n".join(out)
|
|
|
|
|
|
def bundle(md_path: Path, css_path: Path, in_place: bool) -> Path:
|
|
text = md_path.read_text(encoding="utf-8")
|
|
css = css_path.read_text(encoding="utf-8").strip()
|
|
|
|
if not text.startswith(FRONTMATTER_DELIM):
|
|
raise SystemExit(f"{md_path}: nessun frontmatter YAML iniziale")
|
|
|
|
end_idx = text.find(f"\n{FRONTMATTER_DELIM}\n", len(FRONTMATTER_DELIM))
|
|
if end_idx == -1:
|
|
raise SystemExit(f"{md_path}: chiusura frontmatter non trovata")
|
|
|
|
fm = text[: end_idx + 1]
|
|
rest = text[end_idx + len(f"\n{FRONTMATTER_DELIM}\n") :]
|
|
|
|
fm = strip_stylesheet_line(fm)
|
|
if "<style>" in rest:
|
|
raise SystemExit(
|
|
f"{md_path}: blocco <style> già presente — niente da fare"
|
|
)
|
|
|
|
bundled = (
|
|
f"{fm}\n{FRONTMATTER_DELIM}\n\n<style>\n{css}\n</style>\n\n{rest.lstrip()}"
|
|
)
|
|
|
|
if in_place:
|
|
md_path.write_text(bundled, encoding="utf-8")
|
|
return md_path
|
|
|
|
out_path = md_path.with_name(md_path.stem + ".bundled.md")
|
|
out_path.write_text(bundled, encoding="utf-8")
|
|
return out_path
|
|
|
|
|
|
def main() -> None:
|
|
parser = argparse.ArgumentParser()
|
|
parser.add_argument("md_file", type=Path)
|
|
parser.add_argument("--css", type=Path, default=DEFAULT_CSS)
|
|
parser.add_argument("--in-place", action="store_true")
|
|
args = parser.parse_args()
|
|
|
|
if not args.md_file.is_file():
|
|
raise SystemExit(f"file non trovato: {args.md_file}")
|
|
if not args.css.is_file():
|
|
raise SystemExit(f"CSS non trovato: {args.css}")
|
|
|
|
out = bundle(args.md_file, args.css, args.in_place)
|
|
print(f"OK: {out}", file=sys.stderr)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|