"""Markdown → PDF conversion endpoint (delegates to tools/generate_pdf.py).""" import json import subprocess import constants class PDFHandlers: """Mixin for /api/pdf.""" def handle_pdf_post(self): """Convert markdown to PDF (text-based) by spawning the venv python.""" try: content_length = int(self.headers['Content-Length']) post_data = self.rfile.read(content_length).decode('utf-8') data = json.loads(post_data) markdown_content = data.get('markdown', '') filename = data.get('filename', 'document.pdf') if not markdown_content: self.send_json({'error': 'No markdown content'}, 400) return venv_python = constants.VENV_PYTHON pdf_script = constants.TOOLS_DIR / 'generate_pdf.py' if not venv_python.exists(): self.send_json({'error': 'Venv Python not found'}, 500) return if not pdf_script.exists(): self.send_json({'error': 'PDF generator script not found'}, 500) return input_data = json.dumps({'markdown': markdown_content, 'filename': filename}) result = subprocess.run( [str(venv_python), str(pdf_script)], input=input_data.encode('utf-8'), capture_output=True, timeout=30, ) if result.returncode != 0: error_msg = result.stderr.decode('utf-8', errors='replace') try: error_json = json.loads(error_msg) self.send_json(error_json, 500) except Exception: self.send_json({'error': error_msg}, 500) return pdf_bytes = result.stdout self.send_response(200) self.send_header('Content-Type', 'application/pdf') self.send_header('Content-Disposition', f'attachment; filename="{filename}"') self.send_header('Content-Length', str(len(pdf_bytes))) self.end_headers() self.wfile.write(pdf_bytes) except subprocess.TimeoutExpired: self.send_json({'error': 'PDF generation timeout'}, 500) except Exception as e: self.send_json({'error': str(e)}, 500)