File size: 5,266 Bytes
a2f8159 7a8b44d 1e83509 7a8b44d 1e83509 7a8b44d b8350d6 7a8b44d 1e83509 7a8b44d 1e83509 7a8b44d a8a537c 7a8b44d b8350d6 7a8b44d 1e83509 7a8b44d 1e83509 7a8b44d 18da99f 1e83509 b8350d6 1e83509 b8350d6 1e83509 a2f8159 b8350d6 a2f8159 b8350d6 1e83509 b8350d6 1e83509 a2f8159 1e83509 b8350d6 1e83509 b8350d6 1e83509 a8a537c |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 |
import os
from sentence_transformers import SentenceTransformer
import pandas as pd
import chromadb
from chromadb.utils import embedding_functions
from scipy.spatial.distance import cosine
import gradio as gr
from tqdm import tqdm
import re
# Crear directorio para almacenamiento persistente
os.makedirs('./data_embeddings', exist_ok=True)
# Cargar el modelo de embeddings
model = SentenceTransformer("jinaai/jina-embeddings-v2-base-es", trust_remote_code=True)
# Ruta del archivo CSV
file_path = './v12_db_turismo.csv'
# Cargar la base de datos
df = pd.read_csv(file_path, encoding='latin-1')
# Función para limpiar y normalizar texto
def limpiar_texto(texto):
texto = str(texto)
texto = re.sub(r'[^a-zA-ZáéíóúñÁÉÍÓÚÑ0-9\s]', '', texto) # Eliminar caracteres especiales
texto = texto.lower() # Convertir a minúsculas
return texto.strip()
# Crear una columna combinada para los embeddings
df['text'] = df.apply(
lambda x: limpiar_texto(
f"Estado: {x['estado']}, "
f"Municipio: {x['municipio']}, "
f"Área natural o aventura: {x['area_natural_aventura']}, "
f"Resumen: {x['resumen']}, "
f"Descripción: {x['descripcion']}, "
f"Ubicación: {x['ubicacion']}, "
f"Link: {x['link']}, "
f"Latitud: {x['latitud']}, Longitud: {x['longitud']}"
), axis=1
)
# Generar embeddings en batches de 64 con barra de progreso
print("Generando embeddings en lotes...")
df['embeddings'] = list(
model.encode(
df['text'].tolist(), # Convertir la columna 'text' a una lista
batch_size=64, # Tamaño del batch
show_progress_bar=True # Mostrar barra de progreso
)
)
# Crear identificadores únicos
df['ids'] = df.index.astype(str)
# Configurar cliente de ChromaDB persistente
chroma_client = chromadb.PersistentClient(path='./data_embeddings')
embedding_function = embedding_functions.SentenceTransformerEmbeddingFunction(model_name="jinaai/jina-embeddings-v2-base-es")
db = chroma_client.get_or_create_collection(name='turismo_db', embedding_function=embedding_function)
# Agregar datos a la colección
db.add(
ids=df['ids'].tolist(),
embeddings=df['embeddings'].tolist(),
documents=df['text'].tolist(),
metadatas=df[['estado', 'municipio', 'area_natural_aventura', 'resumen',
'descripcion', 'ubicacion', 'link', 'latitud', 'longitud']].to_dict('records')
)
print(f"Registros en la colección: {db.count()}")
# Función para realizar consultas
def obtener_recomendaciones(preferencias, top_k=5):
# Limpiar y generar embeddings de la consulta
preferencias = limpiar_texto(preferencias)
consulta_embedding = model.encode(preferencias, show_progress_bar=False)
# Realizar consulta en ChromaDB
results = db.query(query_embeddings=[consulta_embedding], n_results=top_k)
if not results or not results["metadatas"] or not results["metadatas"][0]:
return []
recomendaciones = []
for idx, metadata in enumerate(results["metadatas"][0]):
dist = results["distances"][0][idx]
similitud_coseno = 1 - cosine(consulta_embedding, df['embeddings'].iloc[idx])
metadata['distancia_euclidiana'] = dist
metadata['similitud_coseno'] = similitud_coseno
recomendaciones.append(metadata)
# Ordenar por similitud coseno y distancia euclidiana
recomendaciones = sorted(recomendaciones, key=lambda x: (x['distancia_euclidiana'], -x['similitud_coseno']))
return recomendaciones
# Función para procesar resultados y generar una tabla
def procesar_recomendaciones(preferencias):
recomendaciones = obtener_recomendaciones(preferencias)
if not recomendaciones:
return pd.DataFrame([{"Mensaje": "No se encontraron resultados para las preferencias proporcionadas."}])
resultados = []
for idx, sitio in enumerate(recomendaciones, 1):
resultados.append({
"#": idx,
"Estado": sitio.get('estado', 'Desconocido'),
"Municipio": sitio.get('municipio', 'No disponible'),
"Área Natural o Aventura": sitio.get('area_natural_aventura', 'No disponible'),
"Resumen": sitio.get('resumen', 'No disponible'),
"Descripción": sitio.get('descripcion', 'No disponible'),
"Ubicación": sitio.get('ubicacion', 'No disponible'),
"Link": sitio.get('link', 'No disponible'),
"Distancia Euclidiana": sitio.get('distancia_euclidiana', 'N/A'),
"Similitud Coseno": sitio.get('similitud_coseno', 'N/A'),
})
return pd.DataFrame(resultados)
# Interfaz de Gradio
def interfaz(preferencias):
tabla_resultados = procesar_recomendaciones(preferencias)
return tabla_resultados
ui = gr.Interface(
fn=interfaz,
inputs=gr.Textbox(label="Preferencias", placeholder="Escribe tus preferencias, e.g., cañones, cascadas, áreas naturales"),
outputs=gr.Dataframe(label="Resultados de Búsqueda"),
title="Buscador de Turismo con Búsqueda Semántica Mejorada",
description="Introduce tus preferencias para obtener resultados relevantes basados en similitud semántica y ordenados por relevancia."
)
if __name__ == "__main__":
ui.launch(server_name="0.0.0.0", server_port=7860)
|