Spaces:
Running
Running
File size: 2,542 Bytes
e0effe1 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 |
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()
@app.get("/")
def index():
return FileResponse(BASE_DIR / "index.html")
@app.get("/{path:path}")
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)
@app.post("/api/docx")
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}"'},
)
|