DanielRN commited on
Commit
58e0d35
·
verified ·
1 Parent(s): d6fd836

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +145 -79
app.py CHANGED
@@ -1,121 +1,187 @@
1
- import os
2
  import re
3
- import random
4
  import gradio as gr
5
- from transformers import pipeline
 
6
 
7
- # Cargar dataset desde archivo
8
  def cargar_dataset(filename="datos_alojamientos.txt"):
9
- if not os.path.exists(filename):
10
- raise FileNotFoundError(f"Archivo no encontrado: {filename}")
11
- with open(filename, "r", encoding="utf-8") as f:
12
- contenido = f.read().strip()
13
- return [bloque.strip() for bloque in contenido.split("---") if bloque.strip()]
14
-
15
- dataset = cargar_dataset()
16
-
17
- # Cargar TinyBERT para búsqueda semántica
18
- tinybert_pipeline = pipeline("feature-extraction", model="huawei-noah/TinyBERT_General_4L_312D")
 
 
 
 
 
19
 
20
- # Normalización de texto
21
  def limpiar_texto(texto):
22
  return re.sub(r'\s+', ' ', texto.strip().lower())
23
 
24
- def obtener_valor(texto, patron):
 
25
  match = re.search(patron, texto, re.IGNORECASE | re.MULTILINE)
26
- return match.group(1).strip() if match else "No disponible"
 
 
 
 
 
27
 
 
28
  def obtener_servicios(texto):
29
- match = re.findall(r"servicios\s*:\s*(.+)", texto, re.IGNORECASE | re.MULTILINE)
30
- return "\n".join([f"🛠 {s.strip()}" for s in match[0].split(",")]) if match else "No especificado"
31
-
32
- # Filtrar alojamientos usando TinyBERT
33
- def filtrar_alojamientos(pregunta):
34
- pregunta = limpiar_texto(pregunta)
35
- resultados = []
36
-
37
- # Convertir la pregunta en un embedding usando TinyBERT
38
- pregunta_embedding = tinybert_pipeline(pregunta)[0][0] # Extraer el embedding de la pregunta
39
-
40
- for alojamiento in dataset:
41
- # Convertir el alojamiento en un embedding
42
- alojamiento_embedding = tinybert_pipeline(alojamiento)[0][0]
43
-
44
- # Calcular la similitud entre la pregunta y el alojamiento (similitud de coseno)
45
- producto_punto = sum(p * a for p, a in zip(pregunta_embedding, alojamiento_embedding))
46
- magnitud_pregunta = (sum(p**2 for p in pregunta_embedding)) ** 0.5
47
- magnitud_alojamiento = (sum(a**2 for a in alojamiento_embedding)) ** 0.5
48
- similitud = producto_punto / (magnitud_pregunta * magnitud_alojamiento)
49
-
50
- # Si la similitud es mayor a un umbral, agregar el alojamiento a los resultados
51
- if similitud > 0.7: # Umbral de similitud ajustable
52
- resultados.append((alojamiento, similitud))
53
-
54
- # Ordenar los resultados por similitud (de mayor a menor)
55
- resultados.sort(key=lambda x: x[1], reverse=True)
56
-
57
- # Devolver solo los alojamientos (sin las puntuaciones de similitud)
58
- return [alojamiento for alojamiento, _ in resultados]
59
 
60
- # Formatear la respuesta
61
- def formatear_alojamiento(texto):
62
- nombre = obtener_valor(texto, r"alojamiento\s*:\s*(.+)")
63
- direccion = obtener_valor(texto, r"dirección\s*:\s*(.+)")
64
- telefono = obtener_valor(texto, r"tel[eé]fono[s]*\s*:\s*(.+)")
65
- email = obtener_valor(texto, r"email\s*:\s*(.+)")
66
- plazas = obtener_valor(texto, r"plazas\s*:\s*(\d+)")
67
- mascotas = "Sí" if "mascotas: sí" in texto.lower() else "No"
68
- wifi = "Sí" if "wifi: sí" in texto.lower() else "No"
69
- servicios = obtener_servicios(texto)
70
- return f"""🏠 **{nombre}**\n📍 Dirección: {direccion}\n📞 Teléfono: {telefono}\n📧 Email: {email}\n🛏 Plazas: {plazas}\n🐶 Mascotas: {mascotas}\n📶 Wi-Fi: {wifi}\n{servicios}"""
71
 
72
- # Manejo de paginación
73
  resultados_previos = []
74
 
 
75
  def responder_pregunta(pregunta, historial):
76
  global resultados_previos
77
- resultados = filtrar_alojamientos(pregunta)
 
 
78
 
79
- if not resultados:
80
- return "No se encontraron alojamientos que coincidan con su búsqueda."
 
 
 
 
 
 
 
 
 
 
81
 
82
- mostrar = resultados[:3]
83
- resultados_previos = resultados[3:]
84
- historial += "\n\n".join(formatear_alojamiento(aloj) for aloj in mostrar)
 
 
 
 
85
 
86
- if resultados_previos:
87
- historial += "\n\n¿Desea ver más opciones?"
 
 
 
 
 
 
 
 
 
 
88
 
89
- return historial
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
90
 
 
91
  def ver_mas(historial):
92
  global resultados_previos
 
 
93
  if not resultados_previos:
94
  return historial + "\n\nNo hay más alojamientos para mostrar."
95
 
96
- mostrar = resultados_previos[:3]
97
- resultados_previos = resultados_previos[3:]
98
- historial += "\n\n".join(formatear_alojamiento(aloj) for aloj in mostrar)
99
-
100
- if resultados_previos:
101
- historial += "\n\n¿Desea ver más opciones?"
102
 
 
 
 
 
 
103
  return historial
104
 
105
- # Interfaz con Gradio
106
- with gr.Blocks() as iface:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
107
  gr.Markdown("### Bienvenido a Valer-IA, tu informante turístico virtual 🏡")
 
108
  chat_historial = gr.Textbox(label="Historial de chat", lines=15, interactive=False)
109
  pregunta_input = gr.Textbox(label="Escribe tu consulta:")
110
 
111
  def actualizar_chat(historial, nueva_pregunta):
112
  nueva_pregunta = nueva_pregunta.strip().capitalize()
113
- if nueva_pregunta.lower() == "más" or nueva_pregunta.lower() == "mas":
 
 
 
 
114
  return ver_mas(historial), ""
115
- return responder_pregunta(nueva_pregunta, historial), ""
 
 
 
116
 
117
  preguntar_btn = gr.Button("Preguntar")
 
 
118
  preguntar_btn.click(actualizar_chat, inputs=[chat_historial, pregunta_input], outputs=[chat_historial, pregunta_input])
119
 
120
  if __name__ == "__main__":
121
- iface.launch()
 
 
1
  import re
2
+ import os
3
  import gradio as gr
4
+ import random
5
+ from fuzzywuzzy import fuzz
6
 
7
+ # Función para cargar el dataset desde el archivo local
8
  def cargar_dataset(filename="datos_alojamientos.txt"):
9
+ dataset = []
10
+ try:
11
+ if not os.path.exists(filename):
12
+ print(f"Archivo no encontrado: {filename}")
13
+ return []
14
+
15
+ with open(filename, "r", encoding="utf-8") as f:
16
+ contenido = f.read().strip()
17
+ # Dividir por bloques separados por el separador personalizado
18
+ alojamientos = [bloque.strip() for bloque in contenido.split("------------------------------------------------------------------------------------------") if bloque.strip()]
19
+ print(f"Cargados {len(alojamientos)} alojamientos.")
20
+ return alojamientos
21
+ except Exception as e:
22
+ print(f"Error al cargar el dataset: {e}")
23
+ return []
24
 
25
+ # Función para limpiar y normalizar texto
26
  def limpiar_texto(texto):
27
  return re.sub(r'\s+', ' ', texto.strip().lower())
28
 
29
+ # Función para extraer valores de manera segura
30
+ def obtener_valor(texto, patron, valor_predeterminado="No especificado"):
31
  match = re.search(patron, texto, re.IGNORECASE | re.MULTILINE)
32
+ if match:
33
+ valor = match.group(1).strip() if match.group(1) else valor_predeterminado
34
+ print(f"Valor extraído para patrón '{patron}': {valor}")
35
+ return valor
36
+ print(f"No se encontró coincidencia para patrón '{patron}'.")
37
+ return valor_predeterminado
38
 
39
+ # Función para extraer la lista de servicios correctamente
40
  def obtener_servicios(texto):
41
+ servicios_match = re.findall(r"(?:servicios\s*:\s*)(.+?)(?=\n\S|\Z)", texto, re.IGNORECASE | re.DOTALL)
42
+ if servicios_match:
43
+ servicios_lista = [s.strip() for s in servicios_match[0].split(",")]
44
+ print(f"Servicios extraídos: {servicios_lista}")
45
+ return "\n".join([f"🛠 {servicio}" for servicio in servicios_lista])
46
+ print("No se encontraron servicios.")
47
+ return "No especificado"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
48
 
49
+ # Función para buscar coincidencias difusas
50
+ def buscar_coincidencia(pregunta, texto):
51
+ similitud = fuzz.partial_ratio(limpiar_texto(pregunta), limpiar_texto(texto))
52
+ print(f"Similitud entre '{pregunta}' y texto: {similitud}")
53
+ return similitud > 80 # Umbral ajustado a 80%
 
 
 
 
 
 
54
 
55
+ # Variable global para almacenar resultados previos
56
  resultados_previos = []
57
 
58
+ # Función principal para responder preguntas
59
  def responder_pregunta(pregunta, historial):
60
  global resultados_previos
61
+ pregunta = limpiar_texto(pregunta)
62
+ resultados = []
63
+ cantidad_solicitada = next((int(p) for p in pregunta.split() if p.isdigit()), None)
64
 
65
+ # 🔥 Lista extendida de palabras clave de servicios
66
+ palabras_clave_servicios = [
67
+ "wi fi", "directv", "ropa blanca", "amueblado", "equipado", "habitación",
68
+ "cocina", "comedor", "baño", "sommier", "cama", "vajilla completa", "heladera con freezer",
69
+ "tv led", "aire acondicionado", "parrilla", "pileta", "lavarropas", "garage", "quincho", "balcón",
70
+ "cochera", "terraza", "jardín", "microondas", "cafetera", "tostadora", "secador de pelo",
71
+ "plancha", "calefacción", "ventilador", "caja fuerte", "servicio de limpieza", "desayuno incluido", "servicio de habitaciones", "gimnasio", "sauna", "jacuzzi", "spa", "piscina",
72
+ "estacionamiento", "ascensor", "salón de eventos", "centro de negocios", "alquiler de bicicletas",
73
+ "lavandería", "área de juegos", "sala de estar", "chimenea", "vista al mar", "acceso a la playa",
74
+ "caja de seguridad", "minibar", "bañera de hidromasaje", "ducha", "bidet", "secador de manos",
75
+ "amenities", "Gas", "Gas natural", "cuna", "sofá", "sillón", "armario", "juegos de mesa", "libros"
76
+ ]
77
 
78
+ # Buscar si alguna palabra clave está en la pregunta
79
+ busca_servicio = None
80
+ for servicio in palabras_clave_servicios:
81
+ if servicio in pregunta:
82
+ busca_servicio = servicio
83
+ print(f"Palabra clave de servicio encontrada: {busca_servicio}")
84
+ break
85
 
86
+ # Aplicar filtros de búsqueda
87
+ for alojamiento in dataset:
88
+ texto_alojamiento = limpiar_texto(alojamiento)
89
+
90
+ # Si hay búsqueda de servicio específico, solo incluir alojamientos que tengan ese servicio
91
+ if busca_servicio and busca_servicio not in texto_alojamiento:
92
+ continue
93
+
94
+ # Aplicar los demás criterios de búsqueda
95
+ if buscar_coincidencia(pregunta, alojamiento) or \
96
+ (cantidad_solicitada and (f"{cantidad_solicitada} plazas" in alojamiento or f"para {cantidad_solicitada} personas" in alojamiento)):
97
+ resultados.append(alojamiento)
98
 
99
+ if resultados:
100
+ random.shuffle(resultados) # 🔥 Ordena aleatoriamente los resultados
101
+ mostrar_resultados = resultados[:2] # Muestra al menos 2 alojamientos
102
+ resultados_previos = resultados[2:] # Guarda los resultados restantes para "ver más"
103
+
104
+ historial += "\n\n" + "\n\n---\n\n".join(formatear_alojamiento(aloj) for aloj in mostrar_resultados)
105
+ if len(resultados_previos) > 0:
106
+ historial += "\n\n🔎 ¿Quieres ver más resultados? Escribe 'ver más'."
107
+ else:
108
+ historial += "\n\nNo hay más alojamientos para mostrar."
109
+ return historial
110
+
111
+ # Personalizar mensaje cuando se busca un servicio específico y no hay resultados
112
+ if busca_servicio:
113
+ return f"No encontré alojamientos que tengan '{busca_servicio}' entre sus características."
114
+ else:
115
+ return "No encontré alojamientos que coincidan con tu búsqueda."
116
 
117
+ # Función para mostrar más resultados cuando el usuario escribe "ver más"
118
  def ver_mas(historial):
119
  global resultados_previos
120
+ print(f"Resultados previos disponibles: {len(resultados_previos)}") # Depuración
121
+
122
  if not resultados_previos:
123
  return historial + "\n\nNo hay más alojamientos para mostrar."
124
 
125
+ mostrar_resultados = resultados_previos[:2] # Muestra los siguientes 2 alojamientos
126
+ resultados_previos = resultados_previos[2:] # Actualiza la lista eliminando los ya mostrados
 
 
 
 
127
 
128
+ historial += "\n\n" + "\n\n---\n\n".join(formatear_alojamiento(aloj) for aloj in mostrar_resultados)
129
+ if len(resultados_previos) > 0:
130
+ historial += "\n\n🔎 ¿Quieres ver más resultados? Escribe 'ver más'."
131
+ else:
132
+ historial += "\n\nNo hay más alojamientos para mostrar."
133
  return historial
134
 
135
+ # Función para formatear la información de los alojamientos correctamente
136
+ def formatear_alojamiento(texto):
137
+ nombre = obtener_valor(texto, r"(?:alojamiento\s*:\s*)(.+)")
138
+ direccion = obtener_valor(texto, r"(?:dirección\s*:\s*)(.+)")
139
+ telefono = obtener_valor(texto, r"(?:teléfono|teléfonos)\s*:\s*(.+)")
140
+ plazas = obtener_valor(texto, r"(?:plazas\s*:\s*)(.+)")
141
+ mascotas = "Sí" if "mascotas\s*:\s*sí" in limpiar_texto(texto) else "No"
142
+ wifi = "Sí" if "wifi\s*:\s*sí" in limpiar_texto(texto) else "No"
143
+ servicios = obtener_servicios(texto)
144
+
145
+ # Si el nombre sigue siendo "No especificado", intentamos usar el primer bloque de texto
146
+ if nombre == "No especificado":
147
+ nombre = texto.split("\n")[0].strip()
148
+ print(f"Nombre extraído del primer bloque: {nombre}")
149
+
150
+ return f"""🏠 Nombre: {nombre}
151
+ 📍 Dirección: {direccion}
152
+ 📞 Teléfono: {telefono}
153
+ 🛏 Plazas: {plazas}
154
+ 🐶 Política de mascotas: {mascotas}
155
+ 📶 Wi-Fi: {wifi}
156
+ {servicios}"""
157
+
158
+ # Cargar el dataset
159
+ dataset = cargar_dataset()
160
+
161
+ # Interfaz con Gradio - Mantiene historial del chat
162
+ with gr.Blocks(theme=gr.themes.Default()) as iface:
163
  gr.Markdown("### Bienvenido a Valer-IA, tu informante turístico virtual 🏡")
164
+ gr.Markdown("Escribe una consulta sobre alojamientos, por ejemplo: '¿Qué alojamientos aceptan mascotas?' o 'Alojamiento con pileta y aire acondicionado'")
165
  chat_historial = gr.Textbox(label="Historial de chat", lines=15, interactive=False)
166
  pregunta_input = gr.Textbox(label="Escribe tu consulta:")
167
 
168
  def actualizar_chat(historial, nueva_pregunta):
169
  nueva_pregunta = nueva_pregunta.strip().capitalize()
170
+ saludos = ["hola", "buenos días", "buenas tardes", "buenas noches", "qué tal", "hey", "saludos"]
171
+
172
+ if nueva_pregunta.lower() in saludos:
173
+ respuesta = "¡Hola! 😊 Soy Valer-IA, tu asistente turístico virtual. ¿En qué puedo ayudarte hoy?"
174
+ elif nueva_pregunta.lower() in ["ver mas", "ver más"]:
175
  return ver_mas(historial), ""
176
+ else:
177
+ respuesta = responder_pregunta(nueva_pregunta, historial)
178
+
179
+ return respuesta, ""
180
 
181
  preguntar_btn = gr.Button("Preguntar")
182
+
183
+ # 🔥 Se borra la pregunta después de ser contestada
184
  preguntar_btn.click(actualizar_chat, inputs=[chat_historial, pregunta_input], outputs=[chat_historial, pregunta_input])
185
 
186
  if __name__ == "__main__":
187
+ iface.launch()