File size: 4,066 Bytes
c46095c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
# 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",
    )