File size: 11,281 Bytes
3949424 f98e1a1 3949424 f98e1a1 3949424 f98e1a1 3949424 f98e1a1 3949424 847c173 3949424 |
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 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 |
import os
import gradio as gr
import shutil
from typing import List
from src.file_processor import chunk_pdfs, chunk_all_documents
from src.chroma_db import save_to_chroma_db, get_chroma_client
from langchain_core.prompts import ChatPromptTemplate
from langchain_ollama import OllamaEmbeddings
from langchain_ollama import ChatOllama
# Initialize components - procesamiento condicional
def initialize_system(process_documents=True):
"""
Inicializa el sistema RAG con opción de procesar documentos
"""
if process_documents:
print("Procesando documentos...")
processed_documents = chunk_pdfs()
print("Inicializando modelo de embeddings...")
embedding_model = OllamaEmbeddings(
model="nomic-embed-text"
)
print("Guardando documentos en la base de datos...")
db = save_to_chroma_db(processed_documents, embedding_model)
return db, embedding_model
else:
print("Saltando procesamiento de documentos...")
print("Inicializando modelo de embeddings...")
embedding_model = OllamaEmbeddings(
model="nomic-embed-text"
)
# Intentar conectar con base de datos existente
try:
db = get_chroma_client()
print("Conectado a base de datos existente")
return db, embedding_model
except Exception as e:
print(f"Error conectando a base de datos existente: {e}")
return None, embedding_model
# Estado global para controlar si los documentos están procesados
documents_processed = False
db = None
embedding_model = None
# Define the prompt template
PROMPT_TEMPLATE = """
Tienes que responder la siguiente pregunta basada en el contexto proporcionado:
{context}
Responde la siguiente pregunta: {question}
Proporciona una respuesta con un enfoque de análisis histórico, considerando las causas, consecuencias y evolución de los hechos descritos.
Sitúa los eventos en su marco temporal y geopolítico, y explica los factores sociales, económicos y políticos relevantes.
Evita opiniones o juicios de valor y no incluyas información que no esté sustentada en el contexto.
"""
prompt_template = ChatPromptTemplate.from_template(PROMPT_TEMPLATE)
# Initialize Ollama LLM model
model = ChatOllama(model="hf.co/unsloth/granite-4.0-h-small-GGUF:Q2_K_L")
def answer_question(question):
"""
Función que responde preguntas basadas en el contexto de los documentos usando ChromaDB Docker
"""
global documents_processed, db
if not question.strip():
return "Por favor ingresa una pregunta válida."
if not documents_processed or db is None:
return "❌ No hay documentos procesados disponibles. Por favor, procesa algunos documentos primero usando la opción de arriba."
try:
# Perform similarity search with the query
docs = db.similarity_search_with_score(question, k=3)
if not docs:
return "No se encontraron documentos relevantes para responder tu pregunta."
context = "\n\n---\n\n".join([doc.page_content for doc, _score in docs])
# Generate the prompt
prompt = prompt_template.format(context=context, question=question)
# Get response from model
response = model.invoke(prompt)
return response.content if hasattr(response, 'content') else str(response)
except Exception as e:
return f"Error al procesar la pregunta: {str(e)}. Verifica que ChromaDB Docker esté funcionando en el puerto 8000."
# Definir constante para la carpeta de aportaciones
APORTACIONES_PATH = 'aportaciones'
def handle_file_upload(files) -> str:
"""
Función que maneja la subida de archivos de los usuarios
"""
if not files:
return "😅 ¡Ups! No has seleccionado ningún archivo. ¡Inténtalo de nuevo!"
success_count = 0
error_count = 0
error_messages = []
# Crear carpeta aportaciones si no existe
os.makedirs(APORTACIONES_PATH, exist_ok=True)
for file_obj in files:
try:
# Obtener el nombre del archivo
filename = os.path.basename(file_obj.name)
# Crear ruta de destino
destination_path = os.path.join(APORTACIONES_PATH, filename)
# Copiar el archivo a la carpeta aportaciones
shutil.copy2(file_obj.name, destination_path)
print(f"✅ Archivo {filename} subido exitosamente a {APORTACIONES_PATH}")
success_count += 1
except Exception as e:
error_message = f"❌ Error al subir {filename}: {str(e)}"
print(error_message)
error_messages.append(error_message)
error_count += 1
# Crear mensaje de respuesta jovial
if success_count > 0 and error_count == 0:
return f"🎉 ¡Genial! Has subido {success_count} archivo(s) exitosamente a la carpeta 'aportaciones'. ¡Tu conocimiento ahora forma parte del sistema! 🚀"
elif success_count > 0 and error_count > 0:
return f"⚠️ {success_count} archivo(s) subido(s) correctamente, pero {error_count} archivo(s) tuvieron problemas:\n" + "\n".join(error_messages)
else:
return f"😞 ¡Vaya! Hubo problemas al subir los archivos:\n" + "\n".join(error_messages)
def process_user_documents():
"""
Función que procesa los documentos subidos por usuarios
"""
global documents_processed, db, embedding_model
try:
print("🔄 Procesando documentos de usuarios...")
# Procesar documentos de ambas carpetas
processed_documents = chunk_all_documents()
if not processed_documents:
return "😅 No se encontraron documentos para procesar. ¡Sube algunos archivos primero!"
print("🔗 Inicializando modelo de embeddings...")
embedding_model = OllamaEmbeddings(
model="nomic-embed-text"
)
print("💾 Guardando documentos en la base de datos...")
db = save_to_chroma_db(processed_documents, embedding_model)
documents_processed = True
return f"🎊 ¡Perfecto! Se procesaron {len(processed_documents)} documentos exitosamente. ¡Ya puedes hacer preguntas sobre tu nuevo contenido! 📚✨"
except Exception as e:
return f"❌ Error al procesar documentos: {str(e)}. Asegúrate de que todos los servicios estén funcionando correctamente."
# Create Gradio interface
with gr.Blocks(
title="Sistema RAG - Consulta de Documentos",
theme=gr.themes.Soft(),
css="""
.gradio-container {
max-width: 800px;
margin: auto;
}
.title {
text-align: center;
color: #2563eb;
font-size: 2.5em;
margin-bottom: 1em;
}
.subtitle {
text-align: center;
color: #64748b;
font-size: 1.1em;
margin-bottom: 2em;
}
"""
) as demo:
gr.HTML("<h1 class='title'>🤖 Sistema RAG - Consulta de Documentos</h1>")
gr.HTML("<p class='subtitle'>Haz preguntas sobre el contenido de tus documentos usando IA con ChromaDB Docker</p>")
gr.HTML("""
<div style="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
padding: 20px;
border-radius: 15px;
margin: 20px 0;
text-align: center;
color: white;">
<h3 style="margin: 0 0 10px 0;">🚀 ¡Comparte tu conocimiento!</h3>
<p style="margin: 0; font-size: 1.1em;">
¿Tienes documentos interesantes que quieres añadir al sistema?
¡Súbelos aquí y forma parte de esta aventura del conocimiento! 📚✨
</p>
</div>
""")
with gr.Row():
with gr.Column(scale=2):
file_upload = gr.File(
label="📎 Subir documentos",
file_count="multiple",
file_types=[".pdf", ".txt", ".md"],
elem_id="file_upload"
)
with gr.Column(scale=1):
upload_btn = gr.Button(
"⬆️ Subir archivos",
variant="secondary",
size="lg"
)
upload_output = gr.Markdown(
label="Estado de subida",
elem_id="upload_status"
)
with gr.Row():
process_btn = gr.Button(
"🔄 Procesar documentos",
variant="primary",
size="lg"
)
process_output = gr.Markdown(
label="Estado de procesamiento",
elem_id="process_status"
)
question_input = gr.Textbox(
label="Tu pregunta",
placeholder="Ej: ¿Cuáles son los pasos recomendados para fertilizar un jardín de vegetales?",
lines=3,
max_lines=10
)
submit_btn = gr.Button(
"🔍 Consultar",
variant="primary",
size="lg"
)
answer_output = gr.Markdown(
label="Respuesta",
show_copy_button=True
)
# Examples
gr.Examples(
examples=[
"¿Cuál es el orgigen étnico de los habitantes de Gaza?",
"¿Qué documentos históricos están disponibles?",
"¿Qué ocurrió el 7 de octubre de 2023?",
],
inputs=question_input,
label="Ejemplos de preguntas"
)
# Event handlers
submit_btn.click(
fn=answer_question,
inputs=[question_input],
outputs=[answer_output]
)
question_input.submit(
fn=answer_question,
inputs=[question_input],
outputs=[answer_output]
)
# Event handlers para subida de archivos
upload_btn.click(
fn=handle_file_upload,
inputs=[file_upload],
outputs=[upload_output]
)
process_btn.click(
fn=process_user_documents,
inputs=[],
outputs=[process_output]
)
gr.HTML("""
<div style="text-align: center; margin-top: 2em; color: #64748b; font-size: 0.9em;">
<p>Sistema RAG con LangChain, Ollama y ChromaDB Docker</p>
<p style="font-size: 0.8em; margin-top: 0.5em;">🌐 ChromaDB corriendo en contenedor Docker (puerto 8000)</p>
</div>
""")
if __name__ == "__main__":
print("🚀 Sistema RAG - Consulta de Documentos")
print("=" * 50)
# Usar siempre la opción de base de datos existente
print("💡 ¡Novedad! Los usuarios ahora pueden subir documentos a la carpeta 'aportaciones' desde la interfaz web")
print(" ¡Comparte tu conocimiento y enriquecer el sistema! 📚✨")
print("\n🚀 Usando base de datos existente directamente...")
process_documents = False
# Inicializar sistema usando base de datos existente
print("\nInicializando sistema...")
db, embedding_model = initialize_system(process_documents)
# Verificar estado de inicialización
documents_processed = (db is not None)
if documents_processed:
print("✅ Sistema inicializado con documentos existentes")
else:
print("⚠️ No se pudo conectar a documentos existentes")
print("💡 Asegúrate de que la base de datos ChromaDB esté disponible en 'chroma/'")
print("\n🚀 Iniciando interfaz web...")
demo.launch(
server_name="0.0.0.0",
server_port=7862,
share=True,
debug=False
) |