JairoDanielMT commited on
Commit
c46095c
·
verified ·
1 Parent(s): 8726650

Update core/integrations/doc_converter.py

Browse files
Files changed (1) hide show
  1. core/integrations/doc_converter.py +114 -98
core/integrations/doc_converter.py CHANGED
@@ -1,98 +1,114 @@
1
- # core/integrations/doc_converter
2
- import os
3
- import re
4
- import uuid
5
- import tempfile
6
- import pypandoc
7
- from loguru import logger
8
- from fastapi.responses import FileResponse
9
-
10
- # Control de descargas (máximo 2 por archivo)
11
- _descargas = {}
12
-
13
-
14
- def limpiar_lineas_hr(markdown_text: str) -> str:
15
- """Reemplaza líneas horizontales '---' por saltos de línea."""
16
- return re.sub(r"^\s*---\s*$", "\n", markdown_text, flags=re.MULTILINE)
17
-
18
-
19
- def normalizar_ecuaciones(md: str) -> str:
20
- """Convierte ecuaciones LaTeX escapadas a formato estándar."""
21
- md = re.sub(r"\\\[\s*(.*?)\s*\\\]", r"$$\1$$", md, flags=re.DOTALL)
22
- md = re.sub(r"\\\(\s*(.*?)\s*\\\)", r"$\1$", md, flags=re.DOTALL)
23
- return md
24
-
25
-
26
- def limpiar_backticks(markdown_text: str) -> str:
27
- """
28
- Elimina los backticks triples si encapsulan todo el contenido.
29
- """
30
- markdown_text = markdown_text.strip()
31
- if markdown_text.startswith("```") and markdown_text.endswith("```"):
32
- logger.info("🧹 Eliminando backticks triples de la respuesta LLM.")
33
- return markdown_text[3:-3].strip()
34
- return markdown_text
35
-
36
-
37
- def procesar_markdown(markdown_content: str) -> dict:
38
- try:
39
- # Limpieza previa del contenido
40
- markdown_content = limpiar_backticks(markdown_content)
41
- contenido_limpio = normalizar_ecuaciones(limpiar_lineas_hr(markdown_content))
42
-
43
- uid = str(uuid.uuid4())
44
- temp_dir = tempfile.gettempdir()
45
- input_md = os.path.join(temp_dir, f"{uid}.md")
46
- output_docx = os.path.join(temp_dir, f"{uid}.docx")
47
-
48
- with open(input_md, "w", encoding="utf-8") as f:
49
- f.write(contenido_limpio)
50
-
51
- pypandoc.convert_file(
52
- source_file=input_md,
53
- to="docx",
54
- outputfile=output_docx,
55
- format="md",
56
- extra_args=["--standalone"],
57
- )
58
-
59
- os.remove(input_md)
60
- _descargas[uid] = 0
61
-
62
- logger.success(f"✅ DOCX generado correctamente: {output_docx}")
63
- return {"message": "Archivo DOCX generado exitosamente.", "file_id": uid}
64
-
65
- except Exception as e:
66
- logger.error(f"❌ Error al procesar Markdown: {e}")
67
- return {"error": "Fallo en la conversión de Markdown a DOCX."}
68
-
69
-
70
- def gestionar_descarga(file_id: str):
71
- """
72
- Controla la descarga de archivos. Permite solo 2 descargas por archivo.
73
- """
74
- temp_dir = tempfile.gettempdir()
75
- output_docx = os.path.join(temp_dir, f"{file_id}.docx")
76
-
77
- if not os.path.exists(output_docx):
78
- logger.warning(f"⚠️ Archivo no encontrado: {output_docx}")
79
- return {"error": "El archivo no existe o fue eliminado.", "status": 404}
80
-
81
- if file_id not in _descargas:
82
- logger.warning(f"⚠️ ID inválido de descarga: {file_id}")
83
- return {"error": "ID de archivo no válido.", "status": 400}
84
-
85
- if _descargas[file_id] >= 2:
86
- os.remove(output_docx)
87
- del _descargas[file_id]
88
- logger.info(f"🗑️ Archivo eliminado tras exceder descargas: {file_id}")
89
- return {"error": "Límite de descargas alcanzado.", "status": 410}
90
-
91
- _descargas[file_id] += 1
92
- logger.info(f"⬇️ Descarga {_descargas[file_id]} de 2 para archivo: {file_id}")
93
-
94
- return FileResponse(
95
- path=output_docx,
96
- filename="material_educativo.docx",
97
- media_type="application/vnd.openxmlformats-officedocument.wordprocessingml.document",
98
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # core/integrations/doc_converter
2
+ import os
3
+ import re
4
+ import uuid
5
+ import tempfile
6
+ import pypandoc
7
+ from loguru import logger
8
+ from fastapi.responses import FileResponse
9
+
10
+ # Control de descargas (máximo 2 por archivo)
11
+ _descargas = {}
12
+
13
+
14
+ def limpiar_lineas_hr(markdown_text: str) -> str:
15
+ """Reemplaza líneas horizontales '---' por saltos de línea."""
16
+ return re.sub(r"^\s*---\s*$", "\n", markdown_text, flags=re.MULTILINE)
17
+
18
+
19
+ def normalizar_ecuaciones(md: str) -> str:
20
+ """Convierte ecuaciones LaTeX escapadas a formato estándar."""
21
+ md = re.sub(r"\\\[\s*(.*?)\s*\\\]", r"$$\1$$", md, flags=re.DOTALL)
22
+ md = re.sub(r"\\\(\s*(.*?)\s*\\\)", r"$\1$", md, flags=re.DOTALL)
23
+ return md
24
+
25
+
26
+ # def limpiar_backticks(markdown_text: str) -> str:
27
+ # """
28
+ # Elimina los backticks triples si encapsulan todo el contenido.
29
+ # """
30
+ # markdown_text = markdown_text.strip()
31
+ # if markdown_text.startswith("```") and markdown_text.endswith("```"):
32
+ # logger.info("🧹 Eliminando backticks triples de la respuesta LLM.")
33
+ # return markdown_text[3:-3].strip()
34
+ # return markdown_text
35
+
36
+ def limpiar_backticks(markdown_text: str) -> str:
37
+ """
38
+ Elimina los backticks triples (``` o ```markdown) si encapsulan todo el contenido.
39
+ """
40
+ markdown_text = markdown_text.strip()
41
+
42
+ # Elimina bloque inicial ``` o ```markdown y final ```
43
+ if markdown_text.startswith("```") and markdown_text.endswith("```"):
44
+ # Reemplaza ` ```markdown\n` por vacío
45
+ markdown_text = re.sub(r"^```[a-zA-Z]*\n?", "", markdown_text)
46
+ # Quita los ``` finales
47
+ markdown_text = re.sub(r"\n?```$", "", markdown_text)
48
+ logger.info("🧹 Eliminando bloque ``` del inicio y final.")
49
+ return markdown_text.strip()
50
+
51
+ return markdown_text
52
+
53
+ def procesar_markdown(markdown_content: str) -> dict:
54
+ try:
55
+ # Limpieza previa del contenido
56
+ markdown_content = limpiar_backticks(markdown_content)
57
+ contenido_limpio = normalizar_ecuaciones(limpiar_lineas_hr(markdown_content))
58
+
59
+ uid = str(uuid.uuid4())
60
+ temp_dir = tempfile.gettempdir()
61
+ input_md = os.path.join(temp_dir, f"{uid}.md")
62
+ output_docx = os.path.join(temp_dir, f"{uid}.docx")
63
+
64
+ with open(input_md, "w", encoding="utf-8") as f:
65
+ f.write(contenido_limpio)
66
+
67
+ pypandoc.convert_file(
68
+ source_file=input_md,
69
+ to="docx",
70
+ outputfile=output_docx,
71
+ format="md",
72
+ extra_args=["--standalone"],
73
+ )
74
+
75
+ os.remove(input_md)
76
+ _descargas[uid] = 0
77
+
78
+ logger.success(f" DOCX generado correctamente: {output_docx}")
79
+ return {"message": "Archivo DOCX generado exitosamente.", "file_id": uid}
80
+
81
+ except Exception as e:
82
+ logger.error(f" Error al procesar Markdown: {e}")
83
+ return {"error": "Fallo en la conversión de Markdown a DOCX."}
84
+
85
+
86
+ def gestionar_descarga(file_id: str):
87
+ """
88
+ Controla la descarga de archivos. Permite solo 2 descargas por archivo.
89
+ """
90
+ temp_dir = tempfile.gettempdir()
91
+ output_docx = os.path.join(temp_dir, f"{file_id}.docx")
92
+
93
+ if not os.path.exists(output_docx):
94
+ logger.warning(f"⚠️ Archivo no encontrado: {output_docx}")
95
+ return {"error": "El archivo no existe o fue eliminado.", "status": 404}
96
+
97
+ if file_id not in _descargas:
98
+ logger.warning(f"⚠️ ID inválido de descarga: {file_id}")
99
+ return {"error": "ID de archivo no válido.", "status": 400}
100
+
101
+ if _descargas[file_id] >= 2:
102
+ os.remove(output_docx)
103
+ del _descargas[file_id]
104
+ logger.info(f"🗑️ Archivo eliminado tras exceder descargas: {file_id}")
105
+ return {"error": "Límite de descargas alcanzado.", "status": 410}
106
+
107
+ _descargas[file_id] += 1
108
+ logger.info(f"⬇️ Descarga {_descargas[file_id]} de 2 para archivo: {file_id}")
109
+
110
+ return FileResponse(
111
+ path=output_docx,
112
+ filename="material_educativo.docx",
113
+ media_type="application/vnd.openxmlformats-officedocument.wordprocessingml.document",
114
+ )