Spaces:
Sleeping
Sleeping
| from os import getenv | |
| from dotenv import load_dotenv | |
| import gradio as gr | |
| import os | |
| import json | |
| from langchain_huggingface import HuggingFaceEmbeddings | |
| from langchain_chroma import Chroma | |
| from langchain_openai import ChatOpenAI | |
| from langchain.schema import Document | |
| # Cargar variables de entorno desde un archivo .env | |
| load_dotenv() | |
| # Inicializar el modelo de lenguaje de OpenAI | |
| llm = ChatOpenAI( | |
| openai_api_key=getenv("OPENROUTER_API_KEY"), | |
| openai_api_base=getenv("OPENROUTER_BASE_URL"), | |
| model_name="openai/gpt-4o", | |
| model_kwargs={ | |
| "extra_headers": { | |
| "Helicone-Auth": f"Bearer " + getenv("HELICONE_API_KEY") | |
| } | |
| }, | |
| ) | |
| # Cargar datos de preguntas frecuentes desde un archivo JSON | |
| faqs_path = r"faqs.json" | |
| with open(faqs_path, "r") as file: | |
| faqs_data = json.load(file) | |
| # Cargar datos del menú desde un archivo JSON | |
| menu_path = r"menu.json" | |
| with open(menu_path, "r") as file: | |
| menu_data = json.load(file) | |
| # Definir la ruta del archivo de reservas | |
| reservas_path = r"reservas.json" | |
| # Definir la ruta del archivo PDF del menú | |
| menu_pdf_path = r"menu.pdf" | |
| # Crear el archivo de reservas si no existe | |
| if not os.path.exists(reservas_path): | |
| with open(reservas_path, "w") as file: | |
| json.dump([], file) | |
| # Cargar datos de reservas desde un archivo JSON | |
| with open(reservas_path, "r") as file: | |
| reservas_data = json.load(file) | |
| # Crear documentos a partir de las preguntas frecuentes | |
| faqs_documents = [ | |
| Document( | |
| page_content=pair["question"] + " " + pair["answer"], | |
| metadata={"id": str(i)} | |
| ) | |
| for i, pair in enumerate(faqs_data) | |
| ] | |
| # Crear documentos a partir del menú | |
| menu_documents = [ | |
| Document( | |
| page_content=f"{nombre}: Categoría: {info.get('categoria', 'Desconocida')}, " | |
| f"Alérgenos: {', '.join(info.get('alergenos', [])) if info.get('alergenos') else 'Ninguno'}, " | |
| f"Precio: ${info.get('precio', 'Desconocido')}, " | |
| f"Descripción: {info.get('descripcion', 'Sin descripción')}, " | |
| f"Sin Gluten: {'Sí' if info.get('sin_gluten') else 'No'}, " | |
| f"Vegan: {'Sí' if info.get('vegan') else 'No'}", | |
| metadata={"tipo": "menu"} | |
| ) | |
| for nombre, info in menu_data.items() | |
| ] | |
| # Inicializar el modelo de embeddings de HuggingFace | |
| embeddings = HuggingFaceEmbeddings(model_name="sentence-transformers/all-mpnet-base-v2") | |
| # Inicializar la tienda de vectores Chroma | |
| vectorstore = Chroma(embedding_function=embeddings) | |
| # Agregar documentos de preguntas frecuentes y menú a la tienda de vectores | |
| vectorstore.add_documents(faqs_documents) | |
| vectorstore.add_documents(menu_documents) | |
| # Estado de la reserva | |
| estado_reserva = {} | |
| # Función del chatbot | |
| def chatbot(message, history): | |
| global estado_reserva | |
| message_lower = message.lower() | |
| # Palabras clave para mostrar el menú | |
| menu_keywords = [ | |
| "menu completo", "menú completo", "carta completa", | |
| "ver menú", "ver menu", "mostrar menú", "mostrar menu", "quiero ver el menú", | |
| "quiero ver la carta", "mostrar la carta", "ver la carta", "enséñame el menú", | |
| "enséñame la carta", "dame el menú", "dame la carta", "muéstrame el menú", | |
| "muéstrame la carta", "quiero el menú", "quiero la carta", "menu por favor", | |
| "menú por favor", "carta por favor", "puedo ver el menú", "puedo ver la carta" | |
| ] | |
| # Mostrar imagen del menú si el mensaje coincide con alguna palabra clave | |
| if any(message_lower.strip() == word for word in menu_keywords): | |
| yield gr.Image("menu.png") | |
| return | |
| # Continuar con el proceso de reserva si está en proceso | |
| if estado_reserva.get("en_proceso"): | |
| if "dia" not in estado_reserva: | |
| estado_reserva["dia"] = message | |
| yield "¿A qué hora deseas la reserva? (Formato HH:MM)" | |
| return | |
| elif "hora" not in estado_reserva: | |
| estado_reserva["hora"] = message | |
| yield "¿Para cuántas personas será la reserva?" | |
| return | |
| elif "personas" not in estado_reserva: | |
| estado_reserva["personas"] = message | |
| yield "A nombre de quién será la reserva?" | |
| return | |
| elif "nombre" not in estado_reserva: | |
| estado_reserva["nombre"] = message | |
| yield "(Opcional) Proporcione un número de teléfono de contacto o escriba 'no' para omitirlo." | |
| return | |
| elif "telefono" not in estado_reserva: | |
| estado_reserva["telefono"] = message if message.lower() != "no" else "No proporcionado" | |
| # Guardar la nueva reserva en el archivo JSON | |
| nueva_reserva = { | |
| "nombre": estado_reserva["nombre"], | |
| "dia": estado_reserva["dia"], | |
| "hora": estado_reserva["hora"], | |
| "personas": estado_reserva["personas"], | |
| "telefono": estado_reserva["telefono"] | |
| } | |
| with open(reservas_path, "r") as file: | |
| reservas_actuales = json.load(file) | |
| reservas_actuales.append(nueva_reserva) | |
| with open(reservas_path, "w") as file: | |
| json.dump(reservas_actuales, file, indent=2) | |
| estado_reserva = {} | |
| yield f"✅ ¡Reserva guardada con éxito! Aquí están los detalles:\n{json.dumps(nueva_reserva, indent=2)}" | |
| return | |
| # Iniciar el proceso de reserva si se menciona en el mensaje | |
| if "reserva" in message_lower or "quiero reservar" in message_lower: | |
| estado_reserva["en_proceso"] = True | |
| yield "¿Para qué día quieres hacer la reserva? (Formato DD/MM/AAAA)" | |
| return | |
| # Buscar documentos relevantes en la tienda de vectores | |
| relevant_docs = vectorstore.similarity_search(message) | |
| # Crear el contexto para el modelo de lenguaje | |
| context_text = "\n\n".join([doc.page_content for doc in relevant_docs]) | |
| final_prompt = ( | |
| "Eres un asistente virtual en un restaurante. Puedes responder preguntas sobre el menú, las reservas y las preguntas frecuentes. " | |
| "Si el usuario menciona restricciones dietéticas, haz recomendaciones basadas en el menú disponible.\n\n" | |
| f"{json.dumps(menu_data, indent=2)}\n\n" | |
| f"Contexto relevante encontrado en la base de datos:\n{context_text}\n\n" | |
| f"Pregunta: {message}\n" | |
| "Respuesta:" | |
| ) | |
| # Generar la respuesta del modelo de lenguaje | |
| messages = [{"role": "user", "content": final_prompt}] | |
| response = llm.stream(messages) | |
| partial_response = "" | |
| for chunk in response: | |
| if chunk and hasattr(chunk, "content"): | |
| content = chunk.content | |
| if content is not None: | |
| partial_response += content | |
| yield partial_response | |
| # Configurar la interfaz de Gradio | |
| demo = gr.ChatInterface( | |
| chatbot, | |
| chatbot=gr.Chatbot(height=400, type="messages"), | |
| textbox=gr.Textbox(placeholder="Escribe tu mensaje aquí...", container=False, scale=7), | |
| title="ChatBot Restaurante", | |
| description="Asistente virtual para reservas, menú y preguntas frecuentes.", | |
| theme="ocean", | |
| examples=[ | |
| "¿Cuáles son los horarios del restaurante?", | |
| "¿Dónde están ubicados?", | |
| "¿Aceptan pagos con tarjeta?", | |
| "Quiero ver la carta", | |
| "Quiero hacer una reserva" | |
| ], | |
| type="messages", | |
| editable=True, | |
| save_history=True, | |
| ) | |
| # Ejecutar la aplicación | |
| if __name__ == "__main__": | |
| demo.queue().launch() | |