Spaces:
Sleeping
Sleeping
Upload 5 files
Browse files- .gitattributes +1 -0
- app.py +212 -0
- faqs.json +78 -0
- menu.json +147 -0
- menu.png +3 -0
- reservas.json +44 -0
.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 |
+
menu.png filter=lfs diff=lfs merge=lfs -text
|
app.py
ADDED
|
@@ -0,0 +1,212 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from os import getenv
|
| 2 |
+
from dotenv import load_dotenv
|
| 3 |
+
import gradio as gr
|
| 4 |
+
import os
|
| 5 |
+
import json
|
| 6 |
+
from langchain_huggingface import HuggingFaceEmbeddings
|
| 7 |
+
from langchain_chroma import Chroma
|
| 8 |
+
from langchain_openai import ChatOpenAI
|
| 9 |
+
from langchain.schema import Document
|
| 10 |
+
|
| 11 |
+
# Cargar variables de entorno desde un archivo .env
|
| 12 |
+
load_dotenv()
|
| 13 |
+
|
| 14 |
+
# Inicializar el modelo de lenguaje de OpenAI
|
| 15 |
+
llm = ChatOpenAI(
|
| 16 |
+
openai_api_key=getenv("OPENROUTER_API_KEY"),
|
| 17 |
+
openai_api_base=getenv("OPENROUTER_BASE_URL"),
|
| 18 |
+
model_name="openai/gpt-4o",
|
| 19 |
+
model_kwargs={
|
| 20 |
+
"extra_headers": {
|
| 21 |
+
"Helicone-Auth": f"Bearer " + getenv("HELICONE_API_KEY")
|
| 22 |
+
}
|
| 23 |
+
},
|
| 24 |
+
)
|
| 25 |
+
|
| 26 |
+
# Cambiar el directorio de trabajo
|
| 27 |
+
os.chdir(r"MIA/Proyecto 4")
|
| 28 |
+
|
| 29 |
+
# Cargar datos de preguntas frecuentes desde un archivo JSON
|
| 30 |
+
faqs_path = r"faqs.json"
|
| 31 |
+
with open(faqs_path, "r") as file:
|
| 32 |
+
faqs_data = json.load(file)
|
| 33 |
+
|
| 34 |
+
# Cargar datos del menú desde un archivo JSON
|
| 35 |
+
menu_path = r"menu.json"
|
| 36 |
+
with open(menu_path, "r") as file:
|
| 37 |
+
menu_data = json.load(file)
|
| 38 |
+
|
| 39 |
+
# Definir la ruta del archivo de reservas
|
| 40 |
+
reservas_path = r"reservas.json"
|
| 41 |
+
|
| 42 |
+
# Definir la ruta del archivo PDF del menú
|
| 43 |
+
menu_pdf_path = r"menu.pdf"
|
| 44 |
+
|
| 45 |
+
# Crear el archivo de reservas si no existe
|
| 46 |
+
if not os.path.exists(reservas_path):
|
| 47 |
+
with open(reservas_path, "w") as file:
|
| 48 |
+
json.dump([], file)
|
| 49 |
+
|
| 50 |
+
# Cargar datos de reservas desde un archivo JSON
|
| 51 |
+
with open(reservas_path, "r") as file:
|
| 52 |
+
reservas_data = json.load(file)
|
| 53 |
+
|
| 54 |
+
# Crear documentos a partir de las preguntas frecuentes
|
| 55 |
+
faqs_documents = [
|
| 56 |
+
Document(
|
| 57 |
+
page_content=pair["question"] + " " + pair["answer"],
|
| 58 |
+
metadata={"id": str(i)}
|
| 59 |
+
)
|
| 60 |
+
for i, pair in enumerate(faqs_data)
|
| 61 |
+
]
|
| 62 |
+
|
| 63 |
+
# Crear documentos a partir del menú
|
| 64 |
+
menu_documents = [
|
| 65 |
+
Document(
|
| 66 |
+
page_content=f"{nombre}: Categoría: {info.get('categoria', 'Desconocida')}, "
|
| 67 |
+
f"Alérgenos: {', '.join(info.get('alergenos', [])) if info.get('alergenos') else 'Ninguno'}, "
|
| 68 |
+
f"Precio: ${info.get('precio', 'Desconocido')}, "
|
| 69 |
+
f"Descripción: {info.get('descripcion', 'Sin descripción')}, "
|
| 70 |
+
f"Sin Gluten: {'Sí' if info.get('sin_gluten') else 'No'}, "
|
| 71 |
+
f"Vegan: {'Sí' if info.get('vegan') else 'No'}",
|
| 72 |
+
metadata={"tipo": "menu"}
|
| 73 |
+
)
|
| 74 |
+
for nombre, info in menu_data.items()
|
| 75 |
+
]
|
| 76 |
+
|
| 77 |
+
# Inicializar el modelo de embeddings de HuggingFace
|
| 78 |
+
embeddings = HuggingFaceEmbeddings(model_name="sentence-transformers/all-mpnet-base-v2")
|
| 79 |
+
|
| 80 |
+
# Inicializar la tienda de vectores Chroma
|
| 81 |
+
vectorstore = Chroma(embedding_function=embeddings)
|
| 82 |
+
|
| 83 |
+
# Agregar documentos de preguntas frecuentes y menú a la tienda de vectores
|
| 84 |
+
vectorstore.add_documents(faqs_documents)
|
| 85 |
+
vectorstore.add_documents(menu_documents)
|
| 86 |
+
|
| 87 |
+
# Estado de la reserva
|
| 88 |
+
estado_reserva = {}
|
| 89 |
+
|
| 90 |
+
# Función del chatbot
|
| 91 |
+
def chatbot(message, history):
|
| 92 |
+
global estado_reserva
|
| 93 |
+
|
| 94 |
+
message_lower = message.lower()
|
| 95 |
+
|
| 96 |
+
# Palabras clave para mostrar el menú
|
| 97 |
+
menu_keywords = [
|
| 98 |
+
"menu completo", "menú completo", "carta completa",
|
| 99 |
+
"ver menú", "ver menu", "mostrar menú", "mostrar menu", "quiero ver el menú",
|
| 100 |
+
"quiero ver la carta", "mostrar la carta", "ver la carta", "enséñame el menú",
|
| 101 |
+
"enséñame la carta", "dame el menú", "dame la carta", "muéstrame el menú",
|
| 102 |
+
"muéstrame la carta", "quiero el menú", "quiero la carta", "menu por favor",
|
| 103 |
+
"menú por favor", "carta por favor", "puedo ver el menú", "puedo ver la carta"
|
| 104 |
+
]
|
| 105 |
+
|
| 106 |
+
# Mostrar imagen del menú si el mensaje coincide con alguna palabra clave
|
| 107 |
+
if any(message_lower.strip() == word for word in menu_keywords):
|
| 108 |
+
yield gr.Image("menu.png")
|
| 109 |
+
return
|
| 110 |
+
|
| 111 |
+
# Continuar con el proceso de reserva si está en proceso
|
| 112 |
+
if estado_reserva.get("en_proceso"):
|
| 113 |
+
if "dia" not in estado_reserva:
|
| 114 |
+
estado_reserva["dia"] = message
|
| 115 |
+
yield "¿A qué hora deseas la reserva? (Formato HH:MM)"
|
| 116 |
+
return
|
| 117 |
+
|
| 118 |
+
elif "hora" not in estado_reserva:
|
| 119 |
+
estado_reserva["hora"] = message
|
| 120 |
+
yield "¿Para cuántas personas será la reserva?"
|
| 121 |
+
return
|
| 122 |
+
|
| 123 |
+
elif "personas" not in estado_reserva:
|
| 124 |
+
estado_reserva["personas"] = message
|
| 125 |
+
yield "A nombre de quién será la reserva?"
|
| 126 |
+
return
|
| 127 |
+
|
| 128 |
+
elif "nombre" not in estado_reserva:
|
| 129 |
+
estado_reserva["nombre"] = message
|
| 130 |
+
yield "(Opcional) Proporcione un número de teléfono de contacto o escriba 'no' para omitirlo."
|
| 131 |
+
return
|
| 132 |
+
|
| 133 |
+
elif "telefono" not in estado_reserva:
|
| 134 |
+
estado_reserva["telefono"] = message if message.lower() != "no" else "No proporcionado"
|
| 135 |
+
|
| 136 |
+
# Guardar la nueva reserva en el archivo JSON
|
| 137 |
+
nueva_reserva = {
|
| 138 |
+
"nombre": estado_reserva["nombre"],
|
| 139 |
+
"dia": estado_reserva["dia"],
|
| 140 |
+
"hora": estado_reserva["hora"],
|
| 141 |
+
"personas": estado_reserva["personas"],
|
| 142 |
+
"telefono": estado_reserva["telefono"]
|
| 143 |
+
}
|
| 144 |
+
|
| 145 |
+
with open(reservas_path, "r") as file:
|
| 146 |
+
reservas_actuales = json.load(file)
|
| 147 |
+
|
| 148 |
+
reservas_actuales.append(nueva_reserva)
|
| 149 |
+
|
| 150 |
+
with open(reservas_path, "w") as file:
|
| 151 |
+
json.dump(reservas_actuales, file, indent=2)
|
| 152 |
+
|
| 153 |
+
estado_reserva = {}
|
| 154 |
+
yield f"✅ ¡Reserva guardada con éxito! Aquí están los detalles:\n{json.dumps(nueva_reserva, indent=2)}"
|
| 155 |
+
return
|
| 156 |
+
|
| 157 |
+
# Iniciar el proceso de reserva si se menciona en el mensaje
|
| 158 |
+
if "reserva" in message_lower or "quiero reservar" in message_lower:
|
| 159 |
+
estado_reserva["en_proceso"] = True
|
| 160 |
+
yield "¿Para qué día quieres hacer la reserva? (Formato DD/MM/AAAA)"
|
| 161 |
+
return
|
| 162 |
+
|
| 163 |
+
# Buscar documentos relevantes en la tienda de vectores
|
| 164 |
+
relevant_docs = vectorstore.similarity_search(message)
|
| 165 |
+
|
| 166 |
+
# Crear el contexto para el modelo de lenguaje
|
| 167 |
+
context_text = "\n\n".join([doc.page_content for doc in relevant_docs])
|
| 168 |
+
|
| 169 |
+
final_prompt = (
|
| 170 |
+
"Eres un asistente virtual en un restaurante. Puedes responder preguntas sobre el menú, las reservas y las preguntas frecuentes. "
|
| 171 |
+
"Si el usuario menciona restricciones dietéticas, haz recomendaciones basadas en el menú disponible.\n\n"
|
| 172 |
+
f"{json.dumps(menu_data, indent=2)}\n\n"
|
| 173 |
+
f"Contexto relevante encontrado en la base de datos:\n{context_text}\n\n"
|
| 174 |
+
f"Pregunta: {message}\n"
|
| 175 |
+
"Respuesta:"
|
| 176 |
+
)
|
| 177 |
+
|
| 178 |
+
# Generar la respuesta del modelo de lenguaje
|
| 179 |
+
messages = [{"role": "user", "content": final_prompt}]
|
| 180 |
+
response = llm.stream(messages)
|
| 181 |
+
|
| 182 |
+
partial_response = ""
|
| 183 |
+
for chunk in response:
|
| 184 |
+
if chunk and hasattr(chunk, "content"):
|
| 185 |
+
content = chunk.content
|
| 186 |
+
if content is not None:
|
| 187 |
+
partial_response += content
|
| 188 |
+
yield partial_response
|
| 189 |
+
|
| 190 |
+
# Configurar la interfaz de Gradio
|
| 191 |
+
demo = gr.ChatInterface(
|
| 192 |
+
chatbot,
|
| 193 |
+
chatbot=gr.Chatbot(height=400, type="messages"),
|
| 194 |
+
textbox=gr.Textbox(placeholder="Escribe tu mensaje aquí...", container=False, scale=7),
|
| 195 |
+
title="ChatBot Restaurante",
|
| 196 |
+
description="Asistente virtual para reservas, menú y preguntas frecuentes.",
|
| 197 |
+
theme="ocean",
|
| 198 |
+
examples=[
|
| 199 |
+
"¿Cuáles son los horarios del restaurante?",
|
| 200 |
+
"¿Dónde están ubicados?",
|
| 201 |
+
"¿Aceptan pagos con tarjeta?",
|
| 202 |
+
"Quiero ver la carta",
|
| 203 |
+
"Quiero hacer una reserva"
|
| 204 |
+
],
|
| 205 |
+
type="messages",
|
| 206 |
+
editable=True,
|
| 207 |
+
save_history=True,
|
| 208 |
+
)
|
| 209 |
+
|
| 210 |
+
# Ejecutar la aplicación
|
| 211 |
+
if __name__ == "__main__":
|
| 212 |
+
demo.queue().launch()
|
faqs.json
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
[
|
| 2 |
+
{
|
| 3 |
+
"question": "¿Cuáles son los horarios del restaurante?",
|
| 4 |
+
"answer": "Abrimos de 12:00 AM a 11:00 PM todos los días."
|
| 5 |
+
},
|
| 6 |
+
{
|
| 7 |
+
"question": "¿Dónde están ubicados?",
|
| 8 |
+
"answer": "Nos encontramos en Avenida Gastronómica 456, Ciudad."
|
| 9 |
+
},
|
| 10 |
+
{
|
| 11 |
+
"question": "¿Aceptan pagos con tarjeta?",
|
| 12 |
+
"answer": "Sí, aceptamos todas las tarjetas de crédito y débito, así como pagos móviles."
|
| 13 |
+
},
|
| 14 |
+
{
|
| 15 |
+
"question": "¿Ofrecen servicio de entrega a domicilio?",
|
| 16 |
+
"answer": "Sí, realizamos entregas a domicilio a través de nuestras plataformas asociadas."
|
| 17 |
+
},
|
| 18 |
+
{
|
| 19 |
+
"question": "¿Tienen opciones vegetarianas y veganas?",
|
| 20 |
+
"answer": "Sí, contamos con opciones vegetarianas y veganas en nuestro menú."
|
| 21 |
+
},
|
| 22 |
+
{
|
| 23 |
+
"question": "¿Tienen opciones sin gluten?",
|
| 24 |
+
"answer": "Sí, disponemos de opciones sin gluten. Consulte con nuestro personal para más detalles."
|
| 25 |
+
},
|
| 26 |
+
{
|
| 27 |
+
"question": "¿Cuentan con estacionamiento?",
|
| 28 |
+
"answer": "Sí, tenemos un estacionamiento privado para nuestros clientes."
|
| 29 |
+
},
|
| 30 |
+
{
|
| 31 |
+
"question": "¿Se pueden hacer pedidos para llevar?",
|
| 32 |
+
"answer": "Sí, ofrecemos servicio de comida para llevar. Puede realizar su pedido por teléfono o en persona."
|
| 33 |
+
},
|
| 34 |
+
{
|
| 35 |
+
"question": "¿Ofrecen menú infantil?",
|
| 36 |
+
"answer": "Sí, contamos con un menú especial para niños con porciones y opciones adecuadas."
|
| 37 |
+
},
|
| 38 |
+
{
|
| 39 |
+
"question": "¿Se necesita hacer una reserva?",
|
| 40 |
+
"answer": "No es necesario, pero recomendamos hacer una reserva en horarios pico o para grupos grandes."
|
| 41 |
+
},
|
| 42 |
+
{
|
| 43 |
+
"question": "¿Aceptan mascotas?",
|
| 44 |
+
"answer": "Sí, tenemos un área pet-friendly para que puedas disfrutar con tu mascota."
|
| 45 |
+
},
|
| 46 |
+
{
|
| 47 |
+
"question": "¿Tienen opciones sin lactosa?",
|
| 48 |
+
"answer": "Sí, ofrecemos opciones sin lactosa en nuestros platos y postres. Pregunta a nuestro personal."
|
| 49 |
+
},
|
| 50 |
+
{
|
| 51 |
+
"question": "¿Cuáles son las recomendaciones del chef?",
|
| 52 |
+
"answer": "Nuestras recomendaciones varían según la temporada, pero te sugerimos probar el 'Salmón a la Parrilla' y nuestra 'Pizza Margherita'."
|
| 53 |
+
},
|
| 54 |
+
{
|
| 55 |
+
"question": "¿Tienen menú para personas con diabetes?",
|
| 56 |
+
"answer": "Sí, tenemos opciones bajas en azúcar y adaptadas para personas con diabetes. Por favor, consulta con nuestro personal para más detalles."
|
| 57 |
+
},
|
| 58 |
+
{
|
| 59 |
+
"question": "¿Es necesario dejar propina?",
|
| 60 |
+
"answer": "La propina es completamente opcional, pero siempre es apreciada por nuestro equipo. Normalmente, se recomienda entre un 10% y un 15% del total de la cuenta."
|
| 61 |
+
},
|
| 62 |
+
{
|
| 63 |
+
"question": "¿Puedo personalizar los platos según mis preferencias?",
|
| 64 |
+
"answer": "Sí, estamos encantados de adaptar los platos a tus preferencias. Puedes pedir cambios en los ingredientes o ajustar los sabores."
|
| 65 |
+
},
|
| 66 |
+
{
|
| 67 |
+
"question": "¿Tienen algún menú especial para celebraciones?",
|
| 68 |
+
"answer": "Sí, ofrecemos menús especiales para celebraciones y eventos. Puedes pedir más información sobre nuestros paquetes de eventos."
|
| 69 |
+
},
|
| 70 |
+
{
|
| 71 |
+
"question": "¿Qué opciones de bebidas ofrecen?",
|
| 72 |
+
"answer": "Ofrecemos una amplia variedad de bebidas, incluyendo refrescos, jugos naturales, vinos, cervezas y cócteles."
|
| 73 |
+
},
|
| 74 |
+
{
|
| 75 |
+
"question": "¿Cómo puedo ponerme en contacto con ustedes?",
|
| 76 |
+
"answer": "Puedes contactarnos por teléfono, por email o a través de nuestras redes sociales. Todos los detalles están en nuestra página de contacto."
|
| 77 |
+
}
|
| 78 |
+
]
|
menu.json
ADDED
|
@@ -0,0 +1,147 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"Pizza Margherita": {
|
| 3 |
+
"categoria": "Vegetariano",
|
| 4 |
+
"alergenos": ["Gluten", "Lácteos"],
|
| 5 |
+
"precio": 12.00,
|
| 6 |
+
"descripcion": "Pizza clásica con salsa de tomate, mozzarella fresca y albahaca.",
|
| 7 |
+
"sin_gluten": true,
|
| 8 |
+
"vegan": false
|
| 9 |
+
},
|
| 10 |
+
"Hamburguesa Clásica": {
|
| 11 |
+
"categoria": "Carnes",
|
| 12 |
+
"alergenos": ["Gluten", "Huevo"],
|
| 13 |
+
"precio": 15.00,
|
| 14 |
+
"descripcion": "Hamburguesa de carne de res con lechuga, tomate y mayonesa.",
|
| 15 |
+
"sin_gluten": false,
|
| 16 |
+
"vegan": false
|
| 17 |
+
},
|
| 18 |
+
"Ensalada César": {
|
| 19 |
+
"categoria": "Ensaladas",
|
| 20 |
+
"alergenos": ["Lácteos", "Huevo", "Pescado"],
|
| 21 |
+
"precio": 10.00,
|
| 22 |
+
"descripcion": "Lechuga romana, pollo a la parrilla, crutones, queso parmesano y aderezo César.",
|
| 23 |
+
"sin_gluten": false,
|
| 24 |
+
"vegan": false
|
| 25 |
+
},
|
| 26 |
+
"Salmón a la Parrilla": {
|
| 27 |
+
"categoria": "Pescados",
|
| 28 |
+
"alergenos": ["Pescado"],
|
| 29 |
+
"precio": 18.00,
|
| 30 |
+
"descripcion": "Filete de salmón a la parrilla con limón y hierbas.",
|
| 31 |
+
"sin_gluten": true,
|
| 32 |
+
"vegan": false
|
| 33 |
+
},
|
| 34 |
+
"Pasta Alfredo": {
|
| 35 |
+
"categoria": "Pastas",
|
| 36 |
+
"alergenos": ["Gluten", "Lácteos"],
|
| 37 |
+
"precio": 14.00,
|
| 38 |
+
"descripcion": "Pasta con una salsa cremosa de queso parmesano y ajo.",
|
| 39 |
+
"sin_gluten": false,
|
| 40 |
+
"vegan": false
|
| 41 |
+
},
|
| 42 |
+
"Tacos de Pollo": {
|
| 43 |
+
"categoria": "Mexicano",
|
| 44 |
+
"alergenos": ["Gluten"],
|
| 45 |
+
"precio": 13.00,
|
| 46 |
+
"descripcion": "Tacos suaves de pollo con guacamole, salsa picante y cebolla.",
|
| 47 |
+
"sin_gluten": false,
|
| 48 |
+
"vegan": false
|
| 49 |
+
},
|
| 50 |
+
"Sopa de Cebolla": {
|
| 51 |
+
"categoria": "Sopas",
|
| 52 |
+
"alergenos": ["Gluten", "Lácteos"],
|
| 53 |
+
"precio": 9.00,
|
| 54 |
+
"descripcion": "Sopa caliente de cebolla caramelizada con queso gratinado.",
|
| 55 |
+
"sin_gluten": false,
|
| 56 |
+
"vegan": false
|
| 57 |
+
},
|
| 58 |
+
"Tarta de Queso": {
|
| 59 |
+
"categoria": "Postres",
|
| 60 |
+
"alergenos": ["Lácteos", "Huevo"],
|
| 61 |
+
"precio": 7.00,
|
| 62 |
+
"descripcion": "Clásica tarta de queso con base de galleta y coulis de frambuesa.",
|
| 63 |
+
"sin_gluten": false,
|
| 64 |
+
"vegan": false
|
| 65 |
+
},
|
| 66 |
+
"Jugo de Naranja Natural": {
|
| 67 |
+
"categoria": "Bebidas",
|
| 68 |
+
"alergenos": ["Ninguno"],
|
| 69 |
+
"precio": 5.00,
|
| 70 |
+
"descripcion": "Jugo recién exprimido de naranjas frescas.",
|
| 71 |
+
"sin_gluten": true,
|
| 72 |
+
"vegan": true
|
| 73 |
+
},
|
| 74 |
+
"Café Espresso": {
|
| 75 |
+
"categoria": "Bebidas",
|
| 76 |
+
"alergenos": ["Ninguno"],
|
| 77 |
+
"precio": 3.00,
|
| 78 |
+
"descripcion": "Café espresso de grano molido recién hecho.",
|
| 79 |
+
"sin_gluten": true,
|
| 80 |
+
"vegan": true
|
| 81 |
+
},
|
| 82 |
+
"Sushi Roll Especial": {
|
| 83 |
+
"categoria": "Sushi",
|
| 84 |
+
"alergenos": ["Pescado", "Soya", "Gluten"],
|
| 85 |
+
"precio": 20.00,
|
| 86 |
+
"descripcion": "Rollos de sushi con salmón, aguacate, pepino y salsa de soja.",
|
| 87 |
+
"sin_gluten": false,
|
| 88 |
+
"vegan": false
|
| 89 |
+
},
|
| 90 |
+
"Hamburguesa Vegana": {
|
| 91 |
+
"categoria": "Vegana",
|
| 92 |
+
"alergenos": ["Gluten"],
|
| 93 |
+
"precio": 14.00,
|
| 94 |
+
"descripcion": "Hamburguesa vegana con proteína de soja, lechuga, tomate y mayonesa vegana.",
|
| 95 |
+
"sin_gluten": false,
|
| 96 |
+
"vegan": true
|
| 97 |
+
},
|
| 98 |
+
"Pizza Infantil": {
|
| 99 |
+
"categoria": "Menú Infantil",
|
| 100 |
+
"alergenos": ["Gluten", "Lácteos"],
|
| 101 |
+
"precio": 8.00,
|
| 102 |
+
"descripcion": "Mini pizza con salsa de tomate, mozzarella y orégano.",
|
| 103 |
+
"sin_gluten": true,
|
| 104 |
+
"vegan": false
|
| 105 |
+
},
|
| 106 |
+
"Nuggets de Pollo": {
|
| 107 |
+
"categoria": "Menú Infantil",
|
| 108 |
+
"alergenos": ["Gluten", "Huevo"],
|
| 109 |
+
"precio": 7.00,
|
| 110 |
+
"descripcion": "Nuggets de pollo empanados acompañados de salsa de barbacoa.",
|
| 111 |
+
"sin_gluten": false,
|
| 112 |
+
"vegan": false
|
| 113 |
+
},
|
| 114 |
+
"Pasta con Salsa de Tomate": {
|
| 115 |
+
"categoria": "Menú Infantil",
|
| 116 |
+
"alergenos": ["Gluten"],
|
| 117 |
+
"precio": 6.00,
|
| 118 |
+
"descripcion": "Pasta pequeña con salsa de tomate natural y queso rallado.",
|
| 119 |
+
"sin_gluten": false,
|
| 120 |
+
"vegan": false
|
| 121 |
+
},
|
| 122 |
+
"Helado de Vainilla": {
|
| 123 |
+
"categoria": "Menú Infantil",
|
| 124 |
+
"alergenos": ["Lácteos"],
|
| 125 |
+
"precio": 4.00,
|
| 126 |
+
"descripcion": "Helado cremoso de vainilla, servido con sirope de chocolate.",
|
| 127 |
+
"sin_gluten": true,
|
| 128 |
+
"vegan": false
|
| 129 |
+
},
|
| 130 |
+
"Limonada Natural": {
|
| 131 |
+
"categoria": "Menú Infantil",
|
| 132 |
+
"alergenos": ["Ninguno"],
|
| 133 |
+
"precio": 3.00,
|
| 134 |
+
"descripcion": "Limonada casera con agua, limón fresco y un toque de azúcar.",
|
| 135 |
+
"sin_gluten": true,
|
| 136 |
+
"vegan": true
|
| 137 |
+
|
| 138 |
+
},
|
| 139 |
+
"Brownie de Chocolate": {
|
| 140 |
+
"categoria": "Postres",
|
| 141 |
+
"alergenos": ["Gluten", "Lácteos", "Nueces"],
|
| 142 |
+
"precio": 6.00,
|
| 143 |
+
"descripcion": "Brownie de chocolate casero con nueces y sirope de chocolate.",
|
| 144 |
+
"sin_gluten": false,
|
| 145 |
+
"vegan": false
|
| 146 |
+
}
|
| 147 |
+
}
|
menu.png
ADDED
|
Git LFS Details
|
reservas.json
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
[
|
| 2 |
+
{
|
| 3 |
+
"nombre": "Juan Fernandez",
|
| 4 |
+
"dia": "12/02/2025",
|
| 5 |
+
"hora": "21:00",
|
| 6 |
+
"personas": "10",
|
| 7 |
+
"telefono": "642128722"
|
| 8 |
+
},
|
| 9 |
+
{
|
| 10 |
+
"nombre": "Manuel",
|
| 11 |
+
"dia": "20/05/2025",
|
| 12 |
+
"hora": "20:05",
|
| 13 |
+
"personas": "5",
|
| 14 |
+
"telefono": "No proporcionado"
|
| 15 |
+
},
|
| 16 |
+
{
|
| 17 |
+
"nombre": "Pedro",
|
| 18 |
+
"dia": "20/05/2025",
|
| 19 |
+
"hora": "20:30",
|
| 20 |
+
"personas": "5",
|
| 21 |
+
"telefono": "No proporcionado"
|
| 22 |
+
},
|
| 23 |
+
{
|
| 24 |
+
"nombre": "David",
|
| 25 |
+
"dia": "20/03/2025",
|
| 26 |
+
"hora": "20:34",
|
| 27 |
+
"personas": "8",
|
| 28 |
+
"telefono": "No proporcionado"
|
| 29 |
+
},
|
| 30 |
+
{
|
| 31 |
+
"nombre": "David",
|
| 32 |
+
"dia": "20/03/2025",
|
| 33 |
+
"hora": "20:35",
|
| 34 |
+
"personas": "5",
|
| 35 |
+
"telefono": "No proporcionado"
|
| 36 |
+
},
|
| 37 |
+
{
|
| 38 |
+
"nombre": "David",
|
| 39 |
+
"dia": "20/05/2025",
|
| 40 |
+
"hora": "20:35",
|
| 41 |
+
"personas": "5",
|
| 42 |
+
"telefono": "No proporcionado"
|
| 43 |
+
}
|
| 44 |
+
]
|