""" PDF 生成工具模块 使用 Pandoc 将 Markdown 文本转换为 PDF 文件 """ import os import base64 import subprocess import tempfile from datetime import datetime class PDFGenerator: """PDF 生成器类(Pandoc 版)""" def __init__(self, main_font: str = "Noto Serif CJK SC"): """ 初始化 PDF 生成器 Args: main_font: Pandoc / XeLaTeX 使用的中文字体名 """ self.main_font = main_font def generate_pdf_from_text( self, text_content: str, output_path: str = None, title: str = "维修报告", return_base64: bool = True ) -> dict: """ 将 Markdown 文本内容生成 PDF 文件(方法名不变) Args: text_content: Markdown 文本内容 output_path: PDF 输出路径(可选) title: PDF 标题 return_base64: 是否返回 base64 编码内容 """ try: # 输出路径 if output_path is None: timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") output_path = f"temp_report_{timestamp}.pdf" # 生成临时 Markdown 文件 with tempfile.NamedTemporaryFile( mode="w", suffix=".md", delete=False, encoding="utf-8" ) as md_file: md_path = md_file.name # 写入标题 + 内容(Pandoc 标准) if title: md_file.write(f"# {title}\n\n") md_file.write(text_content.strip()) # Pandoc 命令 cmd = [ "pandoc", md_path, "--pdf-engine=xelatex", "-V", f"mainfont={self.main_font}", "-o", output_path ] # 执行转换 subprocess.run( cmd, check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE ) result = { "success": True, "file_path": output_path } # 返回 base64 if return_base64: with open(output_path, "rb") as f: result["base64_content"] = base64.b64encode( f.read() ).decode("utf-8") return result except subprocess.CalledProcessError as e: return { "success": False, "error": e.stderr.decode("utf-8") } except Exception as e: return { "success": False, "error": str(e) } finally: # 清理临时 md 文件 if "md_path" in locals() and os.path.exists(md_path): os.remove(md_path) def generate_report_pdf( report_content: str, device_name: str = "未知设备", output_dir: str = None ) -> dict: """ 生成维修报告 PDF(方法名不变) """ generator = PDFGenerator() # 文件名规则不变 timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") safe_device_name = device_name.replace(" ", "_").replace("/", "_") file_name = f"{safe_device_name}_维修报告_{timestamp}.pdf" if output_dir: os.makedirs(output_dir, exist_ok=True) output_path = os.path.join(output_dir, file_name) else: output_path = file_name result = generator.generate_pdf_from_text( text_content=report_content, output_path=output_path, title="设备维修报告", return_base64=True ) if result.get("success"): result["file_name"] = file_name return result # 测试代码 if __name__ == "__main__": test_md = """ 爱因斯坦质能方程: $$E = mc^2$$ 该公式揭示了质量与能量的等价性。在核反应中,微小的质量亏损 $\Delta m$ 会释放巨大能量: $$\Delta E = \Delta m \cdot c^2$$ 其中 $c = 3 \times 10^8 \, \text{m/s}$ 为真空光速。 ## 实验数据对比 下表展示了不同材料在相同条件下的能量释放效率: | 材料类型 | 质量亏损 (kg) | 释放能量 (J) | 能量密度 (J/kg) | |------------|----------------|---------------------|----------------------| | 铀-235 | $1.0 \times 10^{-3}$ | $9.0 \times 10^{13}$ | $9.0 \times 10^{16}$ | | 氘氚聚变 | $3.1 \times 10^{-3}$ | $2.8 \times 10^{14}$ | $9.0 \times 10^{16}$ | | 化学燃烧 | $1.0 \times 10^{-3}$ | $3.0 \times 10^{4}$ | $3.0 \times 10^{7}$ | ## 结论 - 核反应的能量密度远高于化学反应(约 $10^9$ 倍)。 - 公式 $a^2 + b^2 = c^2$ 虽为几何关系,但在相对论四维时空中有深刻类比。 """ result = generate_report_pdf( test_md, device_name="测试设备" ) if result["success"]: print(f"✓ PDF 生成成功:{result['file_name']}") print(f"✓ 文件路径:{result['file_path']}") print(f"✓ Base64 长度:{len(result['base64_content'])}") else: print(f"✗ PDF 生成失败:{result['error']}")