from fastapi import FastAPI from fastapi.responses import FileResponse, JSONResponse from pydantic import BaseModel import uuid import os import glob import re import pypandoc app = FastAPI() # Control de descargas por archivo descargas = {} class MarkdownInput(BaseModel): content: str # Reemplaza '---' por saltos de línea def limpiar_lineas_hr(markdown_text: str) -> str: return re.sub(r'^\s*---\s*$', '\n', markdown_text, flags=re.MULTILINE) # Convierte \[...\] y \(...\) a $$...$$ y $...$ def normalizar_ecuaciones(md: str) -> str: md = re.sub(r'\\\[\s*(.*?)\s*\\\]', r'$$\1$$', md, flags=re.DOTALL) md = re.sub(r'\\\(\s*(.*?)\s*\\\)', r'$\1$', md, flags=re.DOTALL) return md def save_markdown_to_file(content: str, path: str): with open(path, "w", encoding="utf-8") as f: f.write(content) def convert_markdown_to_docx(input_md: str, output_docx: str): pypandoc.convert_file( source_file=input_md, to="docx", format="md", outputfile=output_docx, extra_args=["--standalone"] ) def limpieza(): for ext in ["*.docx", "*.md"]: for file in glob.glob(ext): try: os.remove(file) except Exception as e: print(f"No se pudo eliminar {file}: {e}") @app.post("/convert/") def convert(data: MarkdownInput): try: limpieza() uid = str(uuid.uuid4()) input_md = f"{uid}.md" output_docx = f"{uid}.docx" contenido_limpio = limpiar_lineas_hr(data.content) contenido_limpio = normalizar_ecuaciones(contenido_limpio) save_markdown_to_file(contenido_limpio, input_md) convert_markdown_to_docx(input_md, output_docx) os.remove(input_md) descargas[uid] = 0 return { "message": "Archivo generado exitosamente, para descargar acceder a la URL", "url": f"https://jairodanielmt-markdown-docx.hf.space/download/{uid}" } except Exception as e: return JSONResponse(content={"error": str(e)}, status_code=500) @app.get("/download/{file_id}") def download(file_id: str): output_docx = f"{file_id}.docx" if not os.path.exists(output_docx): return JSONResponse( content={"error": "El archivo no existe o ya fue eliminado."}, status_code=404 ) if file_id not in descargas: return JSONResponse( content={"error": "ID de archivo no válido."}, status_code=400 ) if descargas[file_id] >= 2: os.remove(output_docx) del descargas[file_id] return JSONResponse( content={"error": "El archivo ya no está disponible. Genere uno nuevo."}, status_code=410 ) descargas[file_id] += 1 return FileResponse( path=output_docx, filename="material_educativo.docx", media_type="application/vnd.openxmlformats-officedocument.wordprocessingml.document", )