bgonpin commited on
Commit
3949424
·
verified ·
1 Parent(s): a7c7a04

Upload folder using huggingface_hub

Browse files
.gitattributes CHANGED
@@ -33,3 +33,4 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ chroma/chroma.sqlite3 filter=lfs diff=lfs merge=lfs -text
.gradio/certificate.pem ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ -----BEGIN CERTIFICATE-----
2
+ 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
31
+ -----END CERTIFICATE-----
README.md CHANGED
@@ -1,12 +1,6 @@
1
  ---
2
- title: Rag
3
- emoji: 🏢
4
- colorFrom: green
5
- colorTo: green
6
  sdk: gradio
7
  sdk_version: 5.49.1
8
- app_file: app.py
9
- pinned: false
10
  ---
11
-
12
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
1
  ---
2
+ title: rag
3
+ app_file: main gradio.py
 
 
4
  sdk: gradio
5
  sdk_version: 5.49.1
 
 
6
  ---
 
 
chroma/092fb627-93b2-4d3e-a593-fdf24c2837e5/data_level0.bin ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:894fd6d44d3938ae64a415331f238daa8c597a68998993c54b6d70ad16a2820d
3
+ size 19272000
chroma/092fb627-93b2-4d3e-a593-fdf24c2837e5/header.bin ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:12b8b68dcd9c6f50b045f924bbada46386ffed1804ddae18b0b3009a8db66de7
3
+ size 100
chroma/092fb627-93b2-4d3e-a593-fdf24c2837e5/index_metadata.pickle ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:a33b46411f79d7f99f6ca00b2497e6857b10e53f429222e8ca2cd7c367236c22
3
+ size 346027
chroma/092fb627-93b2-4d3e-a593-fdf24c2837e5/length.bin ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:a012229d16bde9de5c4632f4daf2bad6357c9087edc1394f4a62d4c0c53e5a3c
3
+ size 24000
chroma/092fb627-93b2-4d3e-a593-fdf24c2837e5/link_lists.bin ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:6c32223982fdf536a8c748ae676d72910e766ef6ab52322bef3622564cc78dcf
3
+ size 51880
chroma/chroma.sqlite3 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:b8f0e0767557f4624675f7782d6aa53deb250858a3f5ae99648439e0c46f79a1
3
+ size 37646336
main gradio.py ADDED
@@ -0,0 +1,363 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import gradio as gr
3
+ import shutil
4
+ from typing import List
5
+
6
+ from src.file_processor import chunk_pdfs, chunk_all_documents
7
+ from src.chroma_db import save_to_chroma_db, get_chroma_client
8
+ from langchain_core.prompts import ChatPromptTemplate
9
+ from langchain_ollama import OllamaEmbeddings
10
+ from langchain_ollama import ChatOllama
11
+
12
+ # Initialize components - procesamiento condicional
13
+ def initialize_system(process_documents=True):
14
+ """
15
+ Inicializa el sistema RAG con opción de procesar documentos
16
+ """
17
+ if process_documents:
18
+ print("Procesando documentos...")
19
+ processed_documents = chunk_pdfs()
20
+
21
+ print("Inicializando modelo de embeddings...")
22
+ embedding_model = OllamaEmbeddings(
23
+ model="nomic-embed-text"
24
+ )
25
+
26
+ print("Guardando documentos en la base de datos...")
27
+ db = save_to_chroma_db(processed_documents, embedding_model)
28
+ return db, embedding_model
29
+ else:
30
+ print("Saltando procesamiento de documentos...")
31
+ print("Inicializando modelo de embeddings...")
32
+ embedding_model = OllamaEmbeddings(
33
+ model="nomic-embed-text"
34
+ )
35
+
36
+ # Intentar conectar con base de datos existente
37
+ try:
38
+ db = get_chroma_client()
39
+ print("Conectado a base de datos existente")
40
+ return db, embedding_model
41
+ except Exception as e:
42
+ print(f"Error conectando a base de datos existente: {e}")
43
+ return None, embedding_model
44
+
45
+ # Estado global para controlar si los documentos están procesados
46
+ documents_processed = False
47
+ db = None
48
+ embedding_model = None
49
+
50
+ # Define the prompt template
51
+ PROMPT_TEMPLATE = """
52
+ Tienes que responder la siguiente pregunta basada en el contexto proporcionado:
53
+ {context}
54
+
55
+ Responde la siguiente pregunta: {question}
56
+
57
+ Proporciona una respuesta con un enfoque de análisis histórico, considerando las causas, consecuencias y evolución de los hechos descritos.
58
+ Sitúa los eventos en su marco temporal y geopolítico, y explica los factores sociales, económicos y políticos relevantes.
59
+ Evita opiniones o juicios de valor y no incluyas información que no esté sustentada en el contexto.
60
+ """
61
+
62
+
63
+ prompt_template = ChatPromptTemplate.from_template(PROMPT_TEMPLATE)
64
+
65
+ # Initialize Ollama LLM model
66
+ model = ChatOllama(model="hf.co/unsloth/granite-4.0-h-small-GGUF:Q2_K_L")
67
+
68
+
69
+
70
+ def answer_question(question):
71
+ """
72
+ Función que responde preguntas basadas en el contexto de los documentos usando ChromaDB Docker
73
+ """
74
+ global documents_processed, db
75
+
76
+ if not question.strip():
77
+ return "Por favor ingresa una pregunta válida."
78
+
79
+ if not documents_processed or db is None:
80
+ return "❌ No hay documentos procesados disponibles. Por favor, procesa algunos documentos primero usando la opción de arriba."
81
+
82
+ try:
83
+ # Perform similarity search with the query
84
+ docs = db.similarity_search_with_score(question, k=3)
85
+
86
+ if not docs:
87
+ return "No se encontraron documentos relevantes para responder tu pregunta."
88
+
89
+ context = "\n\n---\n\n".join([doc.page_content for doc, _score in docs])
90
+
91
+ # Generate the prompt
92
+ prompt = prompt_template.format(context=context, question=question)
93
+
94
+ # Get response from model
95
+ response = model.invoke(prompt)
96
+
97
+ return response.content if hasattr(response, 'content') else str(response)
98
+
99
+ except Exception as e:
100
+ return f"Error al procesar la pregunta: {str(e)}. Verifica que ChromaDB Docker esté funcionando en el puerto 8000."
101
+
102
+ # Definir constante para la carpeta de aportaciones
103
+ APORTACIONES_PATH = 'aportaciones'
104
+
105
+ def handle_file_upload(files) -> str:
106
+ """
107
+ Función que maneja la subida de archivos de los usuarios
108
+ """
109
+ if not files:
110
+ return "😅 ¡Ups! No has seleccionado ningún archivo. ¡Inténtalo de nuevo!"
111
+
112
+ success_count = 0
113
+ error_count = 0
114
+ error_messages = []
115
+
116
+ # Crear carpeta aportaciones si no existe
117
+ os.makedirs(APORTACIONES_PATH, exist_ok=True)
118
+
119
+ for file_obj in files:
120
+ try:
121
+ # Obtener el nombre del archivo
122
+ filename = os.path.basename(file_obj.name)
123
+
124
+ # Crear ruta de destino
125
+ destination_path = os.path.join(APORTACIONES_PATH, filename)
126
+
127
+ # Copiar el archivo a la carpeta aportaciones
128
+ shutil.copy2(file_obj.name, destination_path)
129
+
130
+ print(f"✅ Archivo {filename} subido exitosamente a {APORTACIONES_PATH}")
131
+ success_count += 1
132
+
133
+ except Exception as e:
134
+ error_message = f"❌ Error al subir {filename}: {str(e)}"
135
+ print(error_message)
136
+ error_messages.append(error_message)
137
+ error_count += 1
138
+
139
+ # Crear mensaje de respuesta jovial
140
+ if success_count > 0 and error_count == 0:
141
+ return f"🎉 ¡Genial! Has subido {success_count} archivo(s) exitosamente a la carpeta 'aportaciones'. ¡Tu conocimiento ahora forma parte del sistema! 🚀"
142
+ elif success_count > 0 and error_count > 0:
143
+ return f"⚠️ {success_count} archivo(s) subido(s) correctamente, pero {error_count} archivo(s) tuvieron problemas:\n" + "\n".join(error_messages)
144
+ else:
145
+ return f"😞 ¡Vaya! Hubo problemas al subir los archivos:\n" + "\n".join(error_messages)
146
+
147
+ def process_user_documents():
148
+ """
149
+ Función que procesa los documentos subidos por usuarios
150
+ """
151
+ global documents_processed, db, embedding_model
152
+
153
+ try:
154
+ print("🔄 Procesando documentos de usuarios...")
155
+
156
+ # Procesar documentos de ambas carpetas
157
+ processed_documents = chunk_all_documents()
158
+
159
+ if not processed_documents:
160
+ return "😅 No se encontraron documentos para procesar. ¡Sube algunos archivos primero!"
161
+
162
+ print("🔗 Inicializando modelo de embeddings...")
163
+ embedding_model = OllamaEmbeddings(
164
+ model="nomic-embed-text"
165
+ )
166
+
167
+ print("💾 Guardando documentos en la base de datos...")
168
+ db = save_to_chroma_db(processed_documents, embedding_model)
169
+
170
+ documents_processed = True
171
+
172
+ return f"🎊 ¡Perfecto! Se procesaron {len(processed_documents)} documentos exitosamente. ¡Ya puedes hacer preguntas sobre tu nuevo contenido! 📚✨"
173
+
174
+ except Exception as e:
175
+ return f"❌ Error al procesar documentos: {str(e)}. Asegúrate de que todos los servicios estén funcionando correctamente."
176
+
177
+ # Create Gradio interface
178
+ with gr.Blocks(
179
+ title="Sistema RAG - Consulta de Documentos",
180
+ theme=gr.themes.Soft(),
181
+ css="""
182
+ .gradio-container {
183
+ max-width: 800px;
184
+ margin: auto;
185
+ }
186
+ .title {
187
+ text-align: center;
188
+ color: #2563eb;
189
+ font-size: 2.5em;
190
+ margin-bottom: 1em;
191
+ }
192
+ .subtitle {
193
+ text-align: center;
194
+ color: #64748b;
195
+ font-size: 1.1em;
196
+ margin-bottom: 2em;
197
+ }
198
+ """
199
+ ) as demo:
200
+ gr.HTML("<h1 class='title'>🤖 Sistema RAG - Consulta de Documentos</h1>")
201
+ gr.HTML("<p class='subtitle'>Haz preguntas sobre el contenido de tus documentos usando IA con ChromaDB Docker</p>")
202
+
203
+ gr.HTML("""
204
+ <div style="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
205
+ padding: 20px;
206
+ border-radius: 15px;
207
+ margin: 20px 0;
208
+ text-align: center;
209
+ color: white;">
210
+ <h3 style="margin: 0 0 10px 0;">🚀 ¡Comparte tu conocimiento!</h3>
211
+ <p style="margin: 0; font-size: 1.1em;">
212
+ ¿Tienes documentos interesantes que quieres añadir al sistema?
213
+ ¡Súbelos aquí y forma parte de esta aventura del conocimiento! 📚✨
214
+ </p>
215
+ </div>
216
+ """)
217
+
218
+ with gr.Row():
219
+ with gr.Column(scale=2):
220
+ file_upload = gr.File(
221
+ label="📎 Subir documentos",
222
+ file_count="multiple",
223
+ file_types=[".pdf", ".txt", ".md"],
224
+ elem_id="file_upload"
225
+ )
226
+
227
+ with gr.Column(scale=1):
228
+ upload_btn = gr.Button(
229
+ "⬆️ Subir archivos",
230
+ variant="secondary",
231
+ size="lg"
232
+ )
233
+
234
+ upload_output = gr.Markdown(
235
+ label="Estado de subida",
236
+ elem_id="upload_status"
237
+ )
238
+
239
+ with gr.Row():
240
+ process_btn = gr.Button(
241
+ "🔄 Procesar documentos",
242
+ variant="primary",
243
+ size="lg"
244
+ )
245
+
246
+ process_output = gr.Markdown(
247
+ label="Estado de procesamiento",
248
+ elem_id="process_status"
249
+ )
250
+
251
+ question_input = gr.Textbox(
252
+ label="Tu pregunta",
253
+ placeholder="Ej: ¿Cuáles son los pasos recomendados para fertilizar un jardín de vegetales?",
254
+ lines=3,
255
+ max_lines=10
256
+ )
257
+
258
+ submit_btn = gr.Button(
259
+ "🔍 Consultar",
260
+ variant="primary",
261
+ size="lg"
262
+ )
263
+
264
+ answer_output = gr.Markdown(
265
+ label="Respuesta",
266
+ show_copy_button=True
267
+ )
268
+
269
+ # Examples
270
+ gr.Examples(
271
+ examples=[
272
+ "¿Cuál es el orgigen étnico de los habitantes de Gaza?",
273
+ "¿Qué documentos históricos están disponibles?",
274
+ "¿Qué ocurrió el 7 de octubre de 2023?",
275
+ ],
276
+ inputs=question_input,
277
+ label="Ejemplos de preguntas"
278
+ )
279
+
280
+ # Event handlers
281
+ submit_btn.click(
282
+ fn=answer_question,
283
+ inputs=[question_input],
284
+ outputs=[answer_output]
285
+ )
286
+
287
+ question_input.submit(
288
+ fn=answer_question,
289
+ inputs=[question_input],
290
+ outputs=[answer_output]
291
+ )
292
+
293
+ # Event handlers para subida de archivos
294
+ upload_btn.click(
295
+ fn=handle_file_upload,
296
+ inputs=[file_upload],
297
+ outputs=[upload_output]
298
+ )
299
+
300
+ process_btn.click(
301
+ fn=process_user_documents,
302
+ inputs=[],
303
+ outputs=[process_output]
304
+ )
305
+
306
+ gr.HTML("""
307
+ <div style="text-align: center; margin-top: 2em; color: #64748b; font-size: 0.9em;">
308
+ <p>Sistema RAG con LangChain, Ollama y ChromaDB Docker</p>
309
+ <p style="font-size: 0.8em; margin-top: 0.5em;">🌐 ChromaDB corriendo en contenedor Docker (puerto 8000)</p>
310
+ </div>
311
+ """)
312
+
313
+ if __name__ == "__main__":
314
+ print("🚀 Sistema RAG - Consulta de Documentos")
315
+ print("=" * 50)
316
+
317
+ # Preguntar al usuario qué acción realizar
318
+ print("¿Qué deseas hacer?")
319
+ print("1. Procesar documentos de las carpetas 'documents' y 'aportaciones' (recomendado si tienes documentos nuevos) 🚀")
320
+ print("2. Pasar directamente al RAG (usar base de datos existente)")
321
+
322
+ print("\n💡 ¡Novedad! Los usuarios ahora pueden subir documentos a la carpeta 'aportaciones' desde la interfaz web")
323
+ print(" ¡Comparte tu conocimiento y enriquecer el sistema! 📚✨")
324
+
325
+ while True:
326
+ try:
327
+ choice = input("\nElige una opción (1 o 2): ").strip()
328
+ if choice == "1":
329
+ print("\n📁 Procesando documentos...")
330
+ process_documents = True
331
+ break
332
+ elif choice == "2":
333
+ print("\n🚀 Pasando directamente al RAG...")
334
+ process_documents = False
335
+ break
336
+ else:
337
+ print("❌ Opción no válida. Por favor elige 1 o 2.")
338
+ except KeyboardInterrupt:
339
+ print("\n\n👋 ¡Hasta luego!")
340
+ exit(0)
341
+
342
+ # Inicializar sistema basado en la elección del usuario
343
+ print("\nInicializando sistema...")
344
+ db, embedding_model = initialize_system(process_documents)
345
+
346
+ if process_documents:
347
+ documents_processed = True
348
+ print("✅ Sistema inicializado con documentos procesados")
349
+ else:
350
+ documents_processed = (db is not None)
351
+ if documents_processed:
352
+ print("✅ Sistema inicializado con documentos existentes")
353
+ else:
354
+ print("⚠️ No se pudo conectar a documentos existentes")
355
+ print("💡 Sugerencia: Ejecuta el script con la opción 1 para procesar documentos")
356
+
357
+ print("\n🚀 Iniciando interfaz web...")
358
+ demo.launch(
359
+ server_name="0.0.0.0",
360
+ server_port=7861,
361
+ share=True,
362
+ debug=False
363
+ )
src/__pycache__/chroma_db.cpython-312.pyc ADDED
Binary file (3.86 kB). View file
 
src/__pycache__/chroma_db.cpython-313.pyc ADDED
Binary file (1.18 kB). View file
 
src/__pycache__/file_processor.cpython-312.pyc ADDED
Binary file (4.41 kB). View file
 
src/__pycache__/file_processor.cpython-313.pyc ADDED
Binary file (960 Bytes). View file
 
src/chroma_db.py ADDED
@@ -0,0 +1,89 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import shutil
3
+ from langchain_community.vectorstores import Chroma
4
+ from langchain_core.documents import Document
5
+
6
+ # Configuración para ChromaDB
7
+ CHROMA_PATH = 'chroma'
8
+
9
+ def save_to_chroma_db(chunks: list[Document], embedding_model) -> Chroma:
10
+ """
11
+ Guarda documentos en ChromaDB usando modo local con procesamiento por lotes
12
+ """
13
+
14
+ print(f"Usando modo local de ChromaDB en {CHROMA_PATH}")
15
+
16
+ # Limpiar base de datos local existente
17
+ if os.path.exists(CHROMA_PATH):
18
+ try:
19
+ shutil.rmtree(CHROMA_PATH)
20
+ print(f"Base de datos local existente eliminada: {CHROMA_PATH}")
21
+ except Exception as e:
22
+ print(f"Error eliminando base de datos local: {e}")
23
+
24
+ try:
25
+ # Procesar en lotes para manejar gran volumen de datos
26
+ batch_size = 1000 # Procesar 1000 chunks por vez
27
+ total_chunks = len(chunks)
28
+
29
+ print(f"Procesando {total_chunks} chunks en lotes de {batch_size}...")
30
+
31
+ # Crear primera colección con el primer lote
32
+ first_batch = chunks[:batch_size]
33
+ print(f"Procesando primer lote: {len(first_batch)} chunks...")
34
+
35
+ db = Chroma.from_documents(
36
+ first_batch,
37
+ persist_directory=CHROMA_PATH,
38
+ embedding=embedding_model
39
+ )
40
+
41
+ print(f"Primer lote completado. Guardado en {CHROMA_PATH}")
42
+
43
+ # Procesar lotes restantes
44
+ for i in range(batch_size, total_chunks, batch_size):
45
+ end_idx = min(i + batch_size, total_chunks)
46
+ batch = chunks[i:end_idx]
47
+ batch_num = (i // batch_size) + 1
48
+ total_batches = (total_chunks + batch_size - 1) // batch_size
49
+
50
+ print(f"Procesando lote {batch_num}/{total_batches}: {len(batch)} chunks...")
51
+
52
+ try:
53
+ db.add_documents(batch)
54
+ print(f"Lote {batch_num}/{total_batches} completado")
55
+ except Exception as e:
56
+ print(f"Error procesando lote {batch_num}: {e}")
57
+ print("Continuando con siguiente lote...")
58
+
59
+ print(f"Procesamiento completado: {total_chunks} chunks guardados exitosamente")
60
+ return db
61
+
62
+ except Exception as e:
63
+ print(f"Error crítico creando base de datos: {e}")
64
+ print("Verifica que Ollama esté funcionando y el modelo nomic-embed-text esté disponible")
65
+ return None
66
+
67
+ def get_chroma_client() -> Chroma:
68
+ """
69
+ Obtiene un cliente ChromaDB para consultas
70
+ """
71
+ try:
72
+ if os.path.exists(CHROMA_PATH):
73
+ # Crear función de embedding para consultas
74
+ from langchain_ollama import OllamaEmbeddings
75
+ embedding_model = OllamaEmbeddings(model="nomic-embed-text")
76
+
77
+ db = Chroma(
78
+ persist_directory=CHROMA_PATH,
79
+ embedding_function=embedding_model # Agregar función de embedding
80
+ )
81
+ print(f"Conectado a ChromaDB local en {CHROMA_PATH}")
82
+ return db
83
+ else:
84
+ print("Base de datos local no encontrada")
85
+ return None
86
+
87
+ except Exception as e:
88
+ print(f"Error conectando a ChromaDB local: {e}")
89
+ return None
src/file_processor.py ADDED
@@ -0,0 +1,83 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from langchain_community.document_loaders import PyPDFDirectoryLoader, TextLoader
2
+ from langchain.text_splitter import RecursiveCharacterTextSplitter
3
+ from langchain_core.documents import Document
4
+ import os
5
+ from typing import List
6
+
7
+ # Paths to the directories containing the files
8
+ DOCUMENTS_PATH = 'documents'
9
+ APORTACIONES_PATH = 'aportaciones'
10
+
11
+ def chunk_all_documents() -> List[Document]:
12
+ """
13
+ Procesa todos los archivos de las carpetas documents y aportaciones (PDFs y archivos de texto/Markdown)
14
+ y los divide en chunks para el procesamiento de embeddings.
15
+ """
16
+ all_documents = []
17
+
18
+ # Procesar documentos de la carpeta documents
19
+ print("📁 Procesando documentos de la carpeta 'documents'...")
20
+ if os.path.exists(DOCUMENTS_PATH):
21
+ # Procesar archivos PDF
22
+ if any(file.endswith('.pdf') for file in os.listdir(DOCUMENTS_PATH)):
23
+ pdf_loader = PyPDFDirectoryLoader(DOCUMENTS_PATH)
24
+ pdf_documents = pdf_loader.load()
25
+ all_documents.extend(pdf_documents)
26
+ print(f" ✅ Se cargaron {len(pdf_documents)} documentos PDF de 'documents'")
27
+
28
+ # Procesar archivos de texto y markdown
29
+ text_files = []
30
+ for file in os.listdir(DOCUMENTS_PATH):
31
+ if file.endswith(('.txt', '.md')):
32
+ text_files.append(os.path.join(DOCUMENTS_PATH, file))
33
+
34
+ for text_file in text_files:
35
+ text_loader = TextLoader(text_file, encoding='utf-8')
36
+ text_documents = text_loader.load()
37
+ all_documents.extend(text_documents)
38
+
39
+ print(f" ✅ Se cargaron {len(text_files)} archivos de texto/markdown de 'documents'")
40
+
41
+ # Procesar documentos de la carpeta aportaciones
42
+ print("🚀 Procesando documentos de la carpeta 'aportaciones'...")
43
+ if os.path.exists(APORTACIONES_PATH):
44
+ # Procesar archivos PDF
45
+ if any(file.endswith('.pdf') for file in os.listdir(APORTACIONES_PATH)):
46
+ pdf_loader = PyPDFDirectoryLoader(APORTACIONES_PATH)
47
+ pdf_documents = pdf_loader.load()
48
+ all_documents.extend(pdf_documents)
49
+ print(f" ✅ Se cargaron {len(pdf_documents)} documentos PDF de 'aportaciones'")
50
+
51
+ # Procesar archivos de texto y markdown
52
+ text_files = []
53
+ for file in os.listdir(APORTACIONES_PATH):
54
+ if file.endswith(('.txt', '.md')):
55
+ text_files.append(os.path.join(APORTACIONES_PATH, file))
56
+
57
+ for text_file in text_files:
58
+ text_loader = TextLoader(text_file, encoding='utf-8')
59
+ text_documents = text_loader.load()
60
+ all_documents.extend(text_documents)
61
+
62
+ print(f" ✅ Se cargaron {len(text_files)} archivos de texto/markdown de 'aportaciones'")
63
+
64
+ print(f"📊 Total de documentos cargados: {len(all_documents)}")
65
+
66
+ # Initialize the text splitter
67
+ text_splitter = RecursiveCharacterTextSplitter(
68
+ chunk_size=800, # Size of each chunk in characters
69
+ chunk_overlap=100, # Overlap between chunks in characters
70
+ length_function=len, # Function to calculate the length of the text
71
+ add_start_index=True, # Add start index to the chunks
72
+ )
73
+
74
+ # Split the documents into chunks
75
+ chunks = text_splitter.split_documents(all_documents)
76
+
77
+ print(f"Se crearon {len(chunks)} chunks de texto")
78
+ return chunks
79
+
80
+ # Mantener función anterior para compatibilidad
81
+ def chunk_pdfs() -> List[Document]:
82
+ """Función legacy para procesar solo PDFs"""
83
+ return chunk_all_documents()