Spaces:
Running
Running
| from __future__ import annotations | |
| import mimetypes | |
| import os | |
| import subprocess | |
| import tempfile | |
| from pathlib import Path | |
| from fastapi import FastAPI, HTTPException | |
| from fastapi.responses import FileResponse, Response | |
| from pydantic import BaseModel | |
| BASE_DIR = Path(__file__).resolve().parent | |
| DOCX_MIME = "application/vnd.openxmlformats-officedocument.wordprocessingml.document" | |
| class DocxRequest(BaseModel): | |
| markdown: str | |
| filename: str | None = None | |
| app = FastAPI() | |
| def index(): | |
| return FileResponse(BASE_DIR / "index.html") | |
| def static_files(path: str): | |
| if path.startswith("api/"): | |
| raise HTTPException(status_code=404) | |
| candidate = (BASE_DIR / path).resolve() | |
| if candidate == BASE_DIR or BASE_DIR not in candidate.parents: | |
| raise HTTPException(status_code=404) | |
| if not candidate.exists() or not candidate.is_file(): | |
| raise HTTPException(status_code=404) | |
| media_type, _ = mimetypes.guess_type(str(candidate)) | |
| return FileResponse(candidate, media_type=media_type) | |
| def export_docx(req: DocxRequest): | |
| markdown = (req.markdown or "").strip() | |
| if not markdown: | |
| raise HTTPException(status_code=400, detail="empty markdown") | |
| filename = (req.filename or "output.docx").strip() or "output.docx" | |
| if not filename.lower().endswith(".docx"): | |
| filename += ".docx" | |
| with tempfile.TemporaryDirectory() as td: | |
| td_path = Path(td) | |
| input_md = td_path / "input.md" | |
| output_docx = td_path / "output.docx" | |
| input_md.write_text(markdown, encoding="utf-8") | |
| cmd = [ | |
| "pandoc", | |
| str(input_md), | |
| "--from", | |
| "markdown+tex_math_dollars+tex_math_single_backslash", | |
| "--to", | |
| "docx", | |
| "--output", | |
| str(output_docx), | |
| ] | |
| try: | |
| subprocess.run(cmd, check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) | |
| except FileNotFoundError as e: | |
| raise HTTPException(status_code=500, detail="pandoc not installed") from e | |
| except subprocess.CalledProcessError as e: | |
| detail = (e.stderr or b"").decode("utf-8", errors="replace")[-4000:] | |
| raise HTTPException(status_code=400, detail=f"pandoc failed: {detail}") from e | |
| data = output_docx.read_bytes() | |
| return Response( | |
| content=data, | |
| media_type=DOCX_MIME, | |
| headers={"Content-Disposition": f'attachment; filename="{filename}"'}, | |
| ) | |