import os import shutil import gradio as gr # Langchain imports from langchain_community.document_loaders import DirectoryLoader from langchain.text_splitter import RecursiveCharacterTextSplitter from langchain_community.embeddings import OpenAIEmbeddings from langchain_community.vectorstores import Chroma from langchain.chains import ConversationalRetrievalChain from langchain_community.llms import OpenAI # from langchain_openai import OpenAIEmbeddings, OpenAI # Alternativa si tienes langchain-openai # Configuración de API Key OPENAI_API_KEY = os.getenv('OPENAI_API_KEY') if not OPENAI_API_KEY: raise ValueError("La variable de entorno OPENAI_API_KEY no está configurada. " "Por favor, configúrala como un Secret en tu Hugging Face Space.") # Directorio de la aplicación actual APP_DIR = os.path.dirname(os.path.abspath(__file__)) logo_filename = "logo.jpeg" # Solo el nombre del archivo para Gradio full_logo_path_for_os_check = os.path.join(APP_DIR, logo_filename) # Ruta completa para os.path.exists # Directorio persistente para ChromaDB (dentro del directorio de la app) PERSIST_DIRECTORY_NAME = "chroma_db_persistent_data" persist_directory = os.path.join(APP_DIR, PERSIST_DIRECTORY_NAME) # Asegurarse de que el directorio persistente exista try: os.makedirs(persist_directory, exist_ok=True) print(f"Directorio persistente '{persist_directory}' listo.") except OSError as e: print(f"CRITICAL: Error al crear el directorio persistente '{persist_directory}': {e}") raise def initialize_vectorstore(documents=None, force_recreate=False, db_path=persist_directory): """Inicializa o carga la base de datos vectorial Chroma.""" try: os.makedirs(db_path, exist_ok=True) if force_recreate and os.path.exists(db_path) and os.listdir(db_path): print(f"Borrando directorio de ChromaDB existente: {db_path}") shutil.rmtree(db_path) os.makedirs(db_path, exist_ok=True) embeddings = OpenAIEmbeddings(openai_api_key=OPENAI_API_KEY) db_file_path = os.path.join(db_path, "chroma.sqlite3") if not force_recreate and os.path.exists(db_file_path): print(f"Intentando cargar base de datos vectorial existente desde: {db_path}") vectorstore = Chroma(persist_directory=db_path, embedding_function=embeddings) print("Base de datos vectorial cargada exitosamente.") elif documents: print(f"Creando nueva base de datos vectorial desde {len(documents)} documentos en: {db_path}") vectorstore = Chroma.from_documents(documents, embeddings, persist_directory=db_path) print("Nueva base de datos vectorial creada y guardada.") else: print(f"Inicializando una base de datos vectorial vacía en: {db_path}. " "No se proporcionaron documentos y no se encontró una base existente (o se forzó la recreación).") vectorstore = Chroma(persist_directory=db_path, embedding_function=embeddings) print("Base de datos vectorial vacía inicializada.") return vectorstore except Exception as e: print(f"Error crítico durante la inicialización de la base de datos vectorial en '{db_path}': {e}") raise # --- Carga y procesamiento de documentos --- documents_for_vectorstore = None db_file_check = os.path.join(persist_directory, "chroma.sqlite3") if not os.path.exists(db_file_check): print(f"Base de datos vectorial no encontrada en '{db_file_check}'. Procesando documentos...") DOCUMENTS_DIR = os.path.join(APP_DIR, 'archivos') if not os.path.isdir(DOCUMENTS_DIR): print(f"ADVERTENCIA: El directorio de documentos '{DOCUMENTS_DIR}' no existe. " "El chatbot podría no tener conocimiento específico.") else: pdf_loader = DirectoryLoader(DOCUMENTS_DIR, glob="**/*.pdf", show_progress=True, use_multithreading=True) loaded_documents = pdf_loader.load() if not loaded_documents: print("ADVERTENCIA: No se cargaron documentos desde el directorio 'archivos'.") else: print(f"Cargados {len(loaded_documents)} documentos.") text_splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=200, length_function=len) documents_for_vectorstore = text_splitter.split_documents(loaded_documents) print(f"Documentos divididos en {len(documents_for_vectorstore)} chunks.") vectorstore = initialize_vectorstore(documents=documents_for_vectorstore, force_recreate=True) else: print(f"Base de datos vectorial existente encontrada en '{persist_directory}'. Cargando...") vectorstore = initialize_vectorstore(documents=None, force_recreate=False) # Crear cadena de recuperación conversacional retriever = vectorstore.as_retriever(search_type="similarity", search_kwargs={"k": 3}) qa_chain = ConversationalRetrievalChain.from_llm( OpenAI(temperature=0.5, openai_api_key=OPENAI_API_KEY), retriever, return_source_documents=True ) # --- Interfaz de usuario con Gradio --- with gr.Blocks(theme=gr.themes.Soft()) as demo: # Mostrar logo img1 = gr.Image("logo.jpeg") img1.css = "max-width: 200px; max-height: 200px; display: block; margin: 0 auto;" gr.Markdown( """
Convivencia escolar, respeto y resolución pacífica de conflictos.
Escribe tu caso y recibe indicaciones sobre la ruta de acción para su solución.