Spaces:
Paused
Paused
| # core/integrations/doc_converter | |
| import os | |
| import re | |
| import uuid | |
| import tempfile | |
| import pypandoc | |
| from loguru import logger | |
| from fastapi.responses import FileResponse | |
| # Control de descargas (máximo 2 por archivo) | |
| _descargas = {} | |
| def limpiar_lineas_hr(markdown_text: str) -> str: | |
| """Reemplaza líneas horizontales '---' por saltos de línea.""" | |
| return re.sub(r"^\s*---\s*$", "\n", markdown_text, flags=re.MULTILINE) | |
| def normalizar_ecuaciones(md: str) -> str: | |
| """Convierte ecuaciones LaTeX escapadas a formato estándar.""" | |
| 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 limpiar_backticks(markdown_text: str) -> str: | |
| # """ | |
| # Elimina los backticks triples si encapsulan todo el contenido. | |
| # """ | |
| # markdown_text = markdown_text.strip() | |
| # if markdown_text.startswith("```") and markdown_text.endswith("```"): | |
| # logger.info("🧹 Eliminando backticks triples de la respuesta LLM.") | |
| # return markdown_text[3:-3].strip() | |
| # return markdown_text | |
| def limpiar_backticks(markdown_text: str) -> str: | |
| """ | |
| Elimina los backticks triples (``` o ```markdown) si encapsulan todo el contenido. | |
| """ | |
| markdown_text = markdown_text.strip() | |
| # Elimina bloque inicial ``` o ```markdown y final ``` | |
| if markdown_text.startswith("```") and markdown_text.endswith("```"): | |
| # Reemplaza ` ```markdown\n` por vacío | |
| markdown_text = re.sub(r"^```[a-zA-Z]*\n?", "", markdown_text) | |
| # Quita los ``` finales | |
| markdown_text = re.sub(r"\n?```$", "", markdown_text) | |
| logger.info("🧹 Eliminando bloque ``` del inicio y final.") | |
| return markdown_text.strip() | |
| return markdown_text | |
| def procesar_markdown(markdown_content: str) -> dict: | |
| try: | |
| # Limpieza previa del contenido | |
| markdown_content = limpiar_backticks(markdown_content) | |
| contenido_limpio = normalizar_ecuaciones(limpiar_lineas_hr(markdown_content)) | |
| uid = str(uuid.uuid4()) | |
| temp_dir = tempfile.gettempdir() | |
| input_md = os.path.join(temp_dir, f"{uid}.md") | |
| output_docx = os.path.join(temp_dir, f"{uid}.docx") | |
| with open(input_md, "w", encoding="utf-8") as f: | |
| f.write(contenido_limpio) | |
| pypandoc.convert_file( | |
| source_file=input_md, | |
| to="docx", | |
| outputfile=output_docx, | |
| format="md", | |
| extra_args=["--standalone"], | |
| ) | |
| os.remove(input_md) | |
| _descargas[uid] = 0 | |
| logger.success(f"✅ DOCX generado correctamente: {output_docx}") | |
| return {"message": "Archivo DOCX generado exitosamente.", "file_id": uid} | |
| except Exception as e: | |
| logger.error(f"❌ Error al procesar Markdown: {e}") | |
| return {"error": "Fallo en la conversión de Markdown a DOCX."} | |
| def gestionar_descarga(file_id: str): | |
| """ | |
| Controla la descarga de archivos. Permite solo 2 descargas por archivo. | |
| """ | |
| temp_dir = tempfile.gettempdir() | |
| output_docx = os.path.join(temp_dir, f"{file_id}.docx") | |
| if not os.path.exists(output_docx): | |
| logger.warning(f"⚠️ Archivo no encontrado: {output_docx}") | |
| return {"error": "El archivo no existe o fue eliminado.", "status": 404} | |
| if file_id not in _descargas: | |
| logger.warning(f"⚠️ ID inválido de descarga: {file_id}") | |
| return {"error": "ID de archivo no válido.", "status": 400} | |
| if _descargas[file_id] >= 2: | |
| os.remove(output_docx) | |
| del _descargas[file_id] | |
| logger.info(f"🗑️ Archivo eliminado tras exceder descargas: {file_id}") | |
| return {"error": "Límite de descargas alcanzado.", "status": 410} | |
| _descargas[file_id] += 1 | |
| logger.info(f"⬇️ Descarga {_descargas[file_id]} de 2 para archivo: {file_id}") | |
| return FileResponse( | |
| path=output_docx, | |
| filename="material_educativo.docx", | |
| media_type="application/vnd.openxmlformats-officedocument.wordprocessingml.document", | |
| ) | |