Files
echo-core/tools/generate_pdf.py
MoltBot Service f2973aa76f stage-1: project bootstrap
Structure, config loader, personality/tools/memory from clawd, venv, 22 tests passing.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 10:20:55 +00:00

114 lines
3.6 KiB
Python

#!/usr/bin/env python3
"""
Generate PDF from markdown content.
Outputs PDF to stdout as binary.
Simple, robust approach focusing on text content.
"""
import sys
import json
from pathlib import Path
# Read JSON from stdin
input_data = json.load(sys.stdin)
markdown_content = input_data.get('markdown', '')
filename = input_data.get('filename', 'document.pdf')
try:
from fpdf import FPDF
import re
# Create PDF
pdf = FPDF(format='A4')
pdf.add_page()
pdf.set_margins(12, 12, 12)
# Try to use DejaVu font for Romanian support
try:
dejavu_path = Path("/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf")
if dejavu_path.exists():
pdf.add_font("DejaVu", "", str(dejavu_path))
pdf.add_font("DejaVu", "B", "/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf")
pdf.set_font("DejaVu", "", 10)
use_dejavu = True
else:
raise Exception("DejaVu font not found")
except:
pdf.set_font("Helvetica", "", 10)
use_dejavu = False
# Parse markdown line by line
lines = markdown_content.split('\n')
i = 0
while i < len(lines):
line = lines[i]
# Skip empty lines but add spacing
if not line.strip():
pdf.ln(2)
i += 1
continue
# H1 - Main heading
if line.startswith('# '):
pdf.set_font("DejaVu" if use_dejavu else "Helvetica", "B", 16)
text = line.replace('# ', '', 1).strip()
pdf.multi_cell(0, 7, text, ln=True)
pdf.ln(1)
pdf.set_font("DejaVu" if use_dejavu else "Helvetica", "", 10)
# H2 - Section heading
elif line.startswith('## '):
pdf.set_font("DejaVu" if use_dejavu else "Helvetica", "B", 12)
text = line.replace('## ', '', 1).strip()
pdf.multi_cell(0, 6, text, ln=True)
pdf.ln(0.5)
pdf.set_font("DejaVu" if use_dejavu else "Helvetica", "", 10)
# H3 - Subsection
elif line.startswith('### '):
pdf.set_font("DejaVu" if use_dejavu else "Helvetica", "B", 11)
text = line.replace('### ', '', 1).strip()
pdf.multi_cell(0, 5, text, ln=True)
pdf.ln(0.3)
pdf.set_font("DejaVu" if use_dejavu else "Helvetica", "", 10)
# Bullet point
elif line.strip().startswith('- ') or line.strip().startswith('* '):
text = line.strip().lstrip('-*').strip()
# Use simple dash for bullet
pdf.multi_cell(0, 5, '- ' + text, ln=True)
# Numbered list
elif re.match(r'^\s*\d+\.\s', line):
text = re.sub(r'^\s*\d+\.\s', '', line)
pdf.multi_cell(0, 5, text, ln=True)
# Regular text with formatting
else:
# Clean up markdown markers but keep structure
text = line.strip()
# Remove inline markdown
text = re.sub(r'\*\*(.*?)\*\*', r'\1', text) # Bold
text = re.sub(r'__(.*?)__', r'\1', text) # Bold
text = re.sub(r'\*(.*?)\*', r'\1', text) # Italic
text = re.sub(r'_(.*?)_', r'\1', text) # Italic
text = re.sub(r'\[(.*?)\]\(.*?\)', r'\1', text) # Links
if text:
pdf.multi_cell(0, 5, text, ln=True)
i += 1
# Output PDF
pdf_bytes = pdf.output()
sys.stdout.buffer.write(pdf_bytes)
sys.exit(0)
except Exception as e:
error_json = json.dumps({'error': str(e)})
sys.stderr.write(error_json)
sys.exit(1)