Spaces:
Running
Running
| import hashlib | |
| import subprocess | |
| import tempfile | |
| from dataclasses import dataclass | |
| from functools import lru_cache | |
| from pathlib import Path | |
| class CompilationResult: | |
| success: bool | |
| pdf_data: bytes = b"" | |
| error_log: str = "" | |
| def _compute_hash(content: str) -> str: | |
| return hashlib.md5(content.encode()).hexdigest() | |
| def _cached_compile(content_hash: str, latex_content: str) -> tuple[bool, bytes, str]: | |
| with tempfile.TemporaryDirectory() as tmpdir: | |
| tmppath = Path(tmpdir) | |
| tex_file = tmppath / "document.tex" | |
| tex_file.write_text(latex_content) | |
| try: | |
| result = subprocess.run( | |
| [ | |
| "pdflatex", | |
| "-interaction=nonstopmode", | |
| "-halt-on-error", | |
| "-output-directory", str(tmppath), | |
| str(tex_file) | |
| ], | |
| capture_output=True, | |
| text=True, | |
| timeout=30 | |
| ) | |
| pdf_file = tmppath / "document.pdf" | |
| if pdf_file.exists(): | |
| return (True, pdf_file.read_bytes(), "") | |
| else: | |
| log_file = tmppath / "document.log" | |
| error_log = log_file.read_text() if log_file.exists() else result.stdout | |
| return (False, b"", _extract_errors(error_log)) | |
| except subprocess.TimeoutExpired: | |
| return (False, b"", "Compilation timed out after 30 seconds") | |
| except FileNotFoundError: | |
| return (False, b"", "pdflatex not found. Please install TeX Live.") | |
| except Exception as e: | |
| return (False, b"", f"Compilation error: {str(e)}") | |
| def _extract_errors(log: str) -> str: | |
| lines = log.split("\n") | |
| error_lines = [] | |
| capture = False | |
| for line in lines: | |
| if line.startswith("!"): | |
| capture = True | |
| if capture: | |
| error_lines.append(line) | |
| if line.strip() == "" and error_lines: | |
| capture = False | |
| if len(error_lines) > 50: | |
| break | |
| return "\n".join(error_lines) if error_lines else log[-2000:] | |
| def compile_latex(latex_content: str) -> CompilationResult: | |
| content_hash = _compute_hash(latex_content) | |
| success, pdf_data, error_log = _cached_compile(content_hash, latex_content) | |
| return CompilationResult(success=success, pdf_data=pdf_data, error_log=error_log) | |