|
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 |
|
|
|
|
|
os.makedirs('./data_embeddings', exist_ok=True) |
|
|
|
|
|
model = SentenceTransformer("jinaai/jina-embeddings-v2-base-es", trust_remote_code=True) |
|
|
|
|
|
file_path = './v12_db_turismo.csv' |
|
|
|
|
|
df = pd.read_csv(file_path, encoding='latin-1') |
|
|
|
|
|
def limpiar_texto(texto): |
|
texto = str(texto) |
|
texto = re.sub(r'[^a-zA-Z谩茅铆贸煤帽脕脡脥脫脷脩0-9\s]', '', texto) |
|
texto = texto.lower() |
|
return texto.strip() |
|
|
|
|
|
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 |
|
) |
|
|
|
|
|
print("Generando embeddings en lotes...") |
|
df['embeddings'] = list( |
|
model.encode( |
|
df['text'].tolist(), |
|
batch_size=64, |
|
show_progress_bar=True |
|
) |
|
) |
|
|
|
|
|
df['ids'] = df.index.astype(str) |
|
|
|
|
|
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) |
|
|
|
|
|
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()}") |
|
|
|
|
|
def obtener_recomendaciones(preferencias, top_k=5): |
|
|
|
preferencias = limpiar_texto(preferencias) |
|
consulta_embedding = model.encode(preferencias, show_progress_bar=False) |
|
|
|
|
|
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) |
|
|
|
|
|
recomendaciones = sorted(recomendaciones, key=lambda x: (x['distancia_euclidiana'], -x['similitud_coseno'])) |
|
return recomendaciones |
|
|
|
|
|
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) |
|
|
|
|
|
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) |
|
|