"""Convert DOCX bytes to PDF via LibreOffice headless.""" from __future__ import annotations import shutil import subprocess import tempfile from pathlib import Path class PdfConversionError(RuntimeError): pass def find_soffice() -> str | None: for name in ("soffice", "libreoffice"): path = shutil.which(name) if path: return path # common Windows / Linux paths for candidate in ( r"C:\Program Files\LibreOffice\program\soffice.exe", "/usr/bin/soffice", "/usr/bin/libreoffice", ): if Path(candidate).exists(): return candidate return None def docx_bytes_to_pdf(docx_bytes: bytes, timeout_sec: int = 120) -> bytes: soffice = find_soffice() if not soffice: raise PdfConversionError( "LibreOffice (soffice) не найден. Установите libreoffice-writer в контейнере API." ) with tempfile.TemporaryDirectory(prefix="espd_preview_") as tmp: tmp_path = Path(tmp) src = tmp_path / "document.docx" src.write_bytes(docx_bytes) try: proc = subprocess.run( [ soffice, "--headless", "--nologo", "--nofirststartwizard", "--convert-to", "pdf", "--outdir", str(tmp_path), str(src), ], capture_output=True, text=True, timeout=timeout_sec, check=False, ) except subprocess.TimeoutExpired as e: raise PdfConversionError("Таймаут конвертации DOCX→PDF") from e pdf_path = tmp_path / "document.pdf" if proc.returncode != 0 or not pdf_path.exists(): detail = (proc.stderr or proc.stdout or "").strip()[:500] raise PdfConversionError(f"Ошибка LibreOffice: {detail or proc.returncode}") return pdf_path.read_bytes()