import pandas as pd import json def generate_interactive_graph(docs_df): if docs_df is None or docs_df.empty: return '''
🌐
Sin datos para el grafo
Ejecuta una bĆŗsqueda primero.
''' try: from sklearn.feature_extraction.text import TfidfVectorizer from sklearn.metrics.pairwise import cosine_similarity has_sklearn = True except ImportError: has_sklearn = False nodes = [] edges = [] docs = docs_df.to_dict(orient="records") # Create Nodes for i, row in enumerate(docs): node_id = i + 1 titulo = str(row.get("Tƭtulo", "")) fuente = str(row.get("Fuente", "")) autores = str(row.get("Autores", "")) aƱo = str(row.get("AƱo", "")) grade = str(row.get("GRADE", "")) # Color based on source color = "#3b82f6" # default blue if "PubMed" in fuente: color = "#10b981" # green elif "ArXiv" in fuente: color = "#f59e0b" # orange elif "Semantic" in fuente: color = "#8b5cf6" # purple elif "Crossref" in fuente: color = "#ef4444" # red # Format label (APA style short) parts = [a.strip() for a in autores.split(",")] surnames = [p.split()[-1] for p in parts if p and "..." not in p] if len(surnames) == 1: cite = f"{surnames[0]} ({aƱo})" elif len(surnames) == 2: cite = f"{surnames[0]} y {surnames[1]} ({aƱo})" elif len(surnames) > 2: cite = f"{surnames[0]} et al. ({aƱo})" else: cite = f"Doc {node_id}" safe_row = json.dumps(row, ensure_ascii=False).replace("'", "'").replace('"', """) nodes.append({ "id": node_id, "label": cite, "title": f"{cite}
{titulo[:80]}...", "color": color, "value": 10, # default size "group": fuente, "paperData": safe_row }) # Create Edges using TF-IDF similarity on titles if len(docs) > 1 and has_sklearn: titles = [str(r.get("TĆ­tulo", "")) for r in docs] vectorizer = TfidfVectorizer(stop_words='english') try: tfidf_matrix = vectorizer.fit_transform(titles) sim_matrix = cosine_similarity(tfidf_matrix) for i in range(len(docs)): for j in range(i+1, len(docs)): sim = sim_matrix[i][j] if sim > 0.2: # Threshold for similarity edges.append({ "from": i + 1, "to": j + 1, "value": float(sim), "title": f"Similitud: {sim:.2f}" }) nodes[i]["value"] += (sim * 5) nodes[j]["value"] += (sim * 5) except Exception: pass # fallback if tfidf fails nodes_json = json.dumps(nodes) edges_json = json.dumps(edges) html = f"""

Detalles del Documento

Selecciona un nodo para ver los detalles.
""" return html