DanielRN commited on
Commit
2363ba5
·
verified ·
1 Parent(s): b66746b

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +179 -80
app.py CHANGED
@@ -1,84 +1,183 @@
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
- alojamientos = [bloque.strip() for bloque in contenido.split("---") if bloque.strip()]
18
- print(f"✅ Cargados {len(alojamientos)} alojamientos.")
19
- return alojamientos
20
- except Exception as e:
21
- print(f"❌ Error al cargar el dataset: {e}")
22
- return []
23
-
24
- # ✅ Función para limpiar y normalizar texto
25
- def limpiar_texto(texto):
26
- return re.sub(r'\s+', ' ', texto.strip().lower())
27
-
28
- # Función para extraer información del alojamiento
29
- def obtener_valor(texto, patron, valor_predeterminado="No especificado"):
30
- match = re.search(patron, texto, re.IGNORECASE | re.MULTILINE)
31
- return match.group(1).strip() if match else valor_predeterminado
32
-
33
- # ✅ Función para buscar alojamientos según la cantidad de plazas solicitada
34
- def buscar_alojamientos(pregunta):
35
- resultados = []
36
- cantidad_solicitada = next((int(p) for p in pregunta.split() if p.isdigit()), None)
37
-
38
- for alojamiento in dataset:
39
- texto_alojamiento = limpiar_texto(alojamiento)
40
- plazas_totales = obtener_valor(alojamiento, r"(?:plazas totales\s*:\s*)(\d+)")
41
- tipos = re.findall(r"(departamento|monoambiente|cabaña).*?plazas\s*:\s*(\d+).+?)\n", texto_alojamiento, re.IGNORECASE | re.DOTALL)
42
-
43
- for tipo, plazas in tipos:
44
- if int(plazas) >= cantidad_solicitada:
45
- resultados.append((alojamiento, tipo, plazas, plazas_totales))
46
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
47
  return resultados
48
 
49
- # Función para formatear la respuesta
50
- def formatear_respuesta(resultados):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
51
  if not resultados:
52
- return "No encontré alojamientos que coincidan con tu búsqueda."
53
-
54
- respuesta = "Aquí tienes algunas opciones:\n\n"
55
- for alojamiento, tipo, plazas, plazas_totales in resultados[:3]:
56
- nombre = obtener_valor(alojamiento, r"(?:alojamiento\s*:\s*)(.+)")
57
- direccion = obtener_valor(alojamiento, r"(?:dirección\s*:\s*)(.+)")
58
- telefono = obtener_valor(alojamiento, r"(?:teléfono\s*:\s*)(.+)")
59
- email = obtener_valor(alojamiento, r"(?:email\s*:\s*)(.+)")
60
- servicios = obtener_valor(alojamiento, r"(?:servicios\s*:\s*)(.+)")
61
-
62
- respuesta += (f"🏠 {nombre}\n📍 {direccion}\n📞 {telefono}\n📧 {email}\n"
63
- f"Plazas Totales: {plazas_totales}\n🏡 {tipo} - Plazas: {plazas}\n🛠 Servicios: {servicios}\n\n---\n\n")
64
- return respuesta
65
-
66
- # Cargar dataset
67
- dataset = cargar_dataset()
68
-
69
- # ✅ Interfaz con Gradio
70
- with gr.Blocks() as iface:
71
- gr.Markdown("### Bienvenido a Valer-IA, tu informante turístico virtual 🏡")
72
- chat_historial = gr.Textbox(label="Historial de chat", lines=15, interactive=False)
73
- pregunta_input = gr.Textbox(label="Escribe tu consulta:")
74
-
75
- def actualizar_chat(historial, nueva_pregunta):
76
- resultados = buscar_alojamientos(nueva_pregunta)
77
- respuesta = formatear_respuesta(resultados)
78
- return historial + "\n\n" + respuesta, ""
79
-
80
- preguntar_btn = gr.Button("Preguntar")
81
- preguntar_btn.click(actualizar_chat, inputs=[chat_historial, pregunta_input], outputs=[chat_historial, pregunta_input])
82
-
83
- if __name__ == "__main__":
84
- iface.launch()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  import gradio as gr
2
+ from transformers import AutoModelForCausalLM, AutoTokenizer
3
+ from collections import defaultdict, OrderedDict
4
+ import re
5
+ import torch
6
+ from threading import Lock
7
+
8
+ # Configuración inicial
9
+ model_name = "microsoft/DialoGPT-small"
10
+ device = "cuda" if torch.cuda.is_available() else "cpu"
11
+ tokenizer = AutoTokenizer.from_pretrained(model_name)
12
+ model = AutoModelForCausalLM.from_pretrained(model_name).to(device)
13
+ model.eval() # Modo evaluación para mayor rapidez
14
+
15
+ # Cargar alojamientos en memoria con preprocesamiento
16
+ def cargar_alojamientos():
17
+ with open("alojamientos.txt", "r", encoding="utf-8") as file:
18
+ alojamientos = file.read().split("\n\n") # Separar por alojamientos
19
+ return {idx: alojamiento for idx, alojamiento in enumerate(alojamientos)}
20
+
21
+ alojamientos_info = cargar_alojamientos()
22
+
23
+ # Índice invertido optimizado
24
+ indice_palabras = defaultdict(set)
25
+ for idx, alojamiento in alojamientos_info.items():
26
+ for palabra in re.split(r'\W+', alojamiento.lower()):
27
+ if len(palabra) > 2: # Ignorar palabras cortas
28
+ indice_palabras[palabra].add(idx)
29
+
30
+ # Caché LRU con límite de tamaño
31
+ class LRUCache:
32
+ def __init__(self, capacity=100):
33
+ self.cache = OrderedDict()
34
+ self.capacity = capacity
35
+ self.lock = Lock()
36
+
37
+ def get(self, key):
38
+ with self.lock:
39
+ if key not in self.cache:
40
+ return None
41
+ self.cache.move_to_end(key)
42
+ return self.cache[key]
43
+
44
+ def put(self, key, value):
45
+ with self.lock:
46
+ if key in self.cache:
47
+ self.cache.move_to_end(key)
48
+ self.cache[key] = value
49
+ if len(self.cache) > self.capacity:
50
+ self.cache.popitem(last=False)
51
+
52
+ cache_respuestas = LRUCache()
53
+ cache_paginas = LRUCache()
54
+
55
+ # Función de búsqueda optimizada
56
+ def buscar_alojamiento(consulta):
57
+ consulta = consulta.lower()
58
+ cached = cache_respuestas.get(consulta)
59
+ if cached is not None:
60
+ return cached
61
+
62
+ # Extraer número de plazas si existe
63
+ match_plazas = re.search(r"\b(\d+)\s*(personas|plazas)\b", consulta)
64
+ plazas = int(match_plazas.group(1)) if match_plazas else None
65
+
66
+ # Búsqueda por palabras clave
67
+ palabras = set(re.split(r'\W+', consulta))
68
+ indices = set()
69
+ for palabra in palabras:
70
+ if palabra in indice_palabras:
71
+ indices.update(indice_palabras[palabra])
72
+
73
+ # Filtrar por plazas si aplica
74
+ resultados = [
75
+ alojamientos_info[idx] for idx in indices
76
+ if not plazas or f"Plazas: {plazas}" in alojamientos_info[idx]
77
+ ]
78
+
79
+ cache_respuestas.put(consulta, resultados)
80
+ cache_paginas.put(consulta, 0) # Reiniciar paginación
81
  return resultados
82
 
83
+ # Formateo visual optimizado
84
+ def formatear_alojamiento(texto):
85
+ lineas = texto.split("\n")
86
+ resultado = ["----------------------------------------------------------"]
87
+ iconos = {
88
+ "Alojamiento:": "🏠", "Dirección:": "📍", "Teléfono:": "📞", "Email:": "📧",
89
+ "Plazas:": "👤", "Mascotas": "���", "Wifi": "📶", "Directv": "📺",
90
+ "Ropa blanca": "🛏️", "Habilitación provincial": "📝", "Servicios:": "🛠"
91
+ }
92
+
93
+ for linea in lineas:
94
+ for clave, icono in iconos.items():
95
+ if clave in linea:
96
+ resultado.append(f"{icono} **{linea}**")
97
+ break
98
+ else:
99
+ if "Descripción:" in linea:
100
+ resultado.append(f"\n🔹 **{linea.replace('Descripción:', '').strip()}**")
101
+ elif linea.strip():
102
+ resultado.append(f" - {linea.strip()}")
103
+
104
+ resultado.append("----------------------------------------------------------")
105
+ return "\n".join(resultado)
106
+
107
+ # Paginación y resultados
108
+ def mostrar_resultados(consulta):
109
+ resultados = buscar_alojamiento(consulta)
110
  if not resultados:
111
+ return "Lo siento, no encontré información exacta. Intenta preguntar de otra manera.", ""
112
+
113
+ pagina = cache_paginas.get(consulta) or 0
114
+ inicio, fin = pagina * 3, (pagina + 1) * 3
115
+ resultados_pagina = resultados[inicio:fin]
116
+
117
+ respuesta = "\n\n".join(formatear_alojamiento(r) for r in resultados_pagina)
118
+ pregunta_mas = ""
119
+ if fin < len(resultados):
120
+ cache_paginas.put(consulta, pagina + 1)
121
+ pregunta_mas = "¿Quieres ver más resultados? Escribe 'sí' para continuar."
122
+ elif pagina > 0:
123
+ pregunta_mas = "¿Quieres ver resultados anteriores? Escribe 'atrás' para volver."
124
+
125
+ return respuesta, pregunta_mas
126
+
127
+ # Generación con DialoGPT
128
+ def generar_respuesta_dialoGPT(message):
129
+ prompt = f"""
130
+ Eres un asistente virtual de turismo especializado en alojamientos.
131
+ Responde de manera clara y concisa a: "{message}"
132
+ Si no tiene relación con alojamientos, di: "Lo siento, no puedo ayudarte con esta consulta."
133
+ """
134
+ with torch.no_grad():
135
+ inputs = tokenizer.encode(prompt + tokenizer.eos_token, return_tensors="pt").to(device)
136
+ reply_ids = model.generate(
137
+ inputs, max_length=100, temperature=0.7, top_p=0.9,
138
+ pad_token_id=tokenizer.eos_token_id, do_sample=True
139
+ )
140
+ return tokenizer.decode(reply_ids[:, inputs.shape[-1]:][0], skip_special_tokens=True)
141
+
142
+ # Lógica del chat
143
+ historial_respuestas = []
144
+
145
+ def chat(message):
146
+ global historial_respuestas
147
+ message = message.strip().lower()
148
+
149
+ if message == "sí" and historial_respuestas:
150
+ consulta = historial_respuestas[-1]["consulta"]
151
+ respuesta, pregunta_mas = mostrar_resultados(consulta)
152
+ elif message == "atrás" and historial_respuestas:
153
+ consulta = historial_respuestas[-1]["consulta"]
154
+ pagina = cache_paginas.get(consulta)
155
+ if pagina > 0:
156
+ cache_paginas.put(consulta, pagina - 1)
157
+ respuesta, pregunta_mas = mostrar_resultados(consulta)
158
+ else:
159
+ resultados = buscar_alojamiento(message)
160
+ if resultados:
161
+ respuesta, pregunta_mas = mostrar_resultados(message)
162
+ else:
163
+ respuesta = generar_respuesta_dialoGPT(message)
164
+ pregunta_mas = ""
165
+
166
+ historial_respuestas.append({"consulta": message, "respuesta": respuesta})
167
+ if len(historial_respuestas) > 10:
168
+ historial_respuestas.pop(0)
169
+
170
+ return "\n\n".join(f"**Pregunta:** {h['consulta']}\n\n{h['respuesta']}" for h in historial_respuestas), pregunta_mas
171
+
172
+ # Interfaz con Gradio
173
+ with gr.Blocks(title="Chat de Turismo") as iface:
174
+ gr.Markdown("### Asistente de Turismo - Alojamientos")
175
+ output_box = gr.Textbox(label="Historial", lines=15, interactive=False)
176
+ input_box = gr.Textbox(label="Consulta", placeholder="Escribe aquí y presiona Enter...")
177
+ extra_box = gr.Textbox(label="Opciones", interactive=False)
178
+ send_button = gr.Button("Enviar")
179
+
180
+ send_button.click(chat, inputs=input_box, outputs=[output_box, extra_box])
181
+ input_box.submit(chat, inputs=input_box, outputs=[output_box, extra_box])
182
+
183
+ iface.launch(share=True, inbrowser=True)