rohitsar567 Claude Opus 4.7 (1M context) commited on
Commit
a2a4ece
·
1 Parent(s): d31e132

docs: add tools/build_readme_pdf.py (PDF gitignored — HF rejects binaries)

Browse files

The HF Space pre-receive hook rejects binary files in the Space repo
(use Xet/LFS or releases instead). Putting README.pdf in the gitignore
keeps both remotes in sync at the same tree.

To regenerate the PDF locally for sharing:
uv pip install --python ~/.cache/uv-venvs/insurance-sales-bot/bin/python markdown-pdf
python tools/build_readme_pdf.py
# → README.pdf (~730 KB, ready to email / Slack)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

Files changed (2) hide show
  1. .gitignore +5 -0
  2. tools/build_readme_pdf.py +80 -0
.gitignore CHANGED
@@ -77,3 +77,8 @@ Thumbs.db
77
 
78
  # Local backup of HF dataset (not for git — too large)
79
  rag/_hf_dataset_backup/
 
 
 
 
 
 
77
 
78
  # Local backup of HF dataset (not for git — too large)
79
  rag/_hf_dataset_backup/
80
+
81
+ # README.pdf is the build artifact from tools/build_readme_pdf.py;
82
+ # HF Space rejects binaries in the repo (use Xet/Releases instead).
83
+ # Regenerate locally any time via 'python tools/build_readme_pdf.py'.
84
+ README.pdf
tools/build_readme_pdf.py ADDED
@@ -0,0 +1,80 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Render README.md → README.pdf.
2
+
3
+ Pure-Python: `markdown-pdf` package (pymupdf-backed) — no system deps like
4
+ cairo/pango. Trade-off vs WeasyPrint: slightly less CSS-perfect output but
5
+ renders all the README's tables, code fences, headings, and links cleanly
6
+ without needing Homebrew or apt to install glib/pango libraries.
7
+
8
+ Run:
9
+ uv pip install --python ~/.cache/uv-venvs/insurance-sales-bot/bin/python markdown-pdf
10
+ python tools/build_readme_pdf.py
11
+
12
+ Output: README.pdf in the repo root, ready to share / download from GitHub.
13
+ """
14
+ from __future__ import annotations
15
+
16
+ import re
17
+ from pathlib import Path
18
+
19
+ from markdown_pdf import MarkdownPdf, Section
20
+
21
+ ROOT = Path(__file__).resolve().parent.parent
22
+ README_PATH = ROOT / "README.md"
23
+ OUT_PATH = ROOT / "README.pdf"
24
+
25
+
26
+ def strip_yaml_frontmatter(text: str) -> str:
27
+ """HF Spaces' YAML metadata at the top of README is meaningless in the PDF."""
28
+ if not text.startswith("---"):
29
+ return text
30
+ end = text.find("\n---", 3)
31
+ if end == -1:
32
+ return text
33
+ return text[end + 4:].lstrip()
34
+
35
+
36
+ def strip_anchor_links(text: str) -> str:
37
+ """Convert `[Text](#anchor)` → `Text` so pymupdf doesn't blow up looking
38
+ for the link target. External `[Text](https://…)` links stay intact."""
39
+ return re.sub(r"\[([^\]]+)\]\(#[^)]+\)", r"\1", text)
40
+
41
+
42
+ CSS = """
43
+ body { font-family: -apple-system, 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 11pt; color: #1f2937; line-height: 1.55; }
44
+ h1 { font-size: 22pt; color: #0f172a; margin-top: 0.5em; margin-bottom: 0.3em; border-bottom: 2px solid #0f766e; padding-bottom: 4px; }
45
+ h2 { font-size: 16pt; color: #134e4a; margin-top: 1.4em; margin-bottom: 0.4em; border-bottom: 1px solid #94a3b8; padding-bottom: 3px; }
46
+ h3 { font-size: 13pt; color: #0f766e; margin-top: 1.2em; margin-bottom: 0.3em; }
47
+ h4 { font-size: 11.5pt; color: #1e3a8a; margin-top: 1em; margin-bottom: 0.3em; }
48
+ p { margin: 0.4em 0; }
49
+ a { color: #0d6efd; text-decoration: none; }
50
+ code { font-family: 'SF Mono', Menlo, Monaco, Consolas, monospace; font-size: 9.5pt; background-color: #f1f5f9; padding: 1px 4px; border-radius: 3px; color: #b91c1c; }
51
+ pre { font-family: 'SF Mono', Menlo, Monaco, Consolas, monospace; font-size: 9.5pt; background-color: #f8fafc; border-left: 3px solid #0f766e; padding: 8px 10px; border-radius: 4px; line-height: 1.4; }
52
+ pre code { background: transparent; padding: 0; color: #0f172a; }
53
+ blockquote { border-left: 3px solid #94a3b8; margin: 0.8em 0; padding: 4px 12px; color: #475569; background: #f8fafc; }
54
+ table { border-collapse: collapse; width: 100%; margin: 0.6em 0; font-size: 10pt; }
55
+ th, td { border: 1px solid #cbd5e1; padding: 5px 8px; text-align: left; vertical-align: top; }
56
+ th { background-color: #f1f5f9; font-weight: 600; color: #0f172a; }
57
+ ul, ol { padding-left: 20px; margin: 0.4em 0; }
58
+ li { margin: 0.2em 0; }
59
+ hr { border: none; border-top: 1px solid #cbd5e1; margin: 1.5em 0; }
60
+ strong { color: #0f172a; }
61
+ """
62
+
63
+
64
+ def main() -> None:
65
+ raw = README_PATH.read_text(encoding="utf-8")
66
+ cleaned = strip_anchor_links(strip_yaml_frontmatter(raw))
67
+
68
+ pdf = MarkdownPdf(toc_level=0, optimize=True)
69
+ pdf.meta["title"] = "Insurance Sales Portfolio Expert — README"
70
+ pdf.meta["author"] = "Rohit Saraf"
71
+ pdf.meta["subject"] = "Voice-first AI advisor for Indian health insurance — Sarvam AI takehome"
72
+ pdf.add_section(Section(cleaned, toc=False), user_css=CSS)
73
+ pdf.save(str(OUT_PATH))
74
+
75
+ size_kb = OUT_PATH.stat().st_size / 1024
76
+ print(f"wrote {OUT_PATH.relative_to(ROOT)} ({size_kb:.1f} KB)")
77
+
78
+
79
+ if __name__ == "__main__":
80
+ main()