foro_interactivo_postdoc / utils_gdmk.py
jcmachicao's picture
Update utils_gdmk.py
5eb3afe verified
import networkx as nx
import matplotlib.pyplot as plt
import json
import requests
import pandas as pd
import os
import gradio as gr
import openai
import scipy as sp
# Load OpenAI API Key
API_KEY = os.getenv("OAIK")
client = openai.OpenAI(api_key=API_KEY)
api_key_airt = os.getenv("AIRT_KEY")
AIRT_DBASE = 'appUuBVTJR5ju0y6J'
AIRT_TABLE = 'foros_postdoc'
url = f"https://api.airtable.com/v0/{AIRT_DBASE}/{AIRT_TABLE}"
headers = {
"Authorization": f"Bearer {api_key_airt}",
"Content-Type": "application/json"
}
def cargar_vocabulario(archivo):
with open(archivo, "r", encoding="utf-8") as f:
vocabulario = [line.strip() for line in f if line.strip()] # Eliminar espacios y líneas vacías
return vocabulario
def cargar_nombres(archivo):
with open(archivo, "r", encoding="utf-8") as f:
students = [line.strip() for line in f if line.strip()] # Eliminar espacios y líneas vacías
return students
students = cargar_nombres("nombres_postdoc.txt")
VOCABULARY = cargar_vocabulario("vocabulario_postdoc.txt")
G = nx.DiGraph()
def extract_concepts(text):
instrucciones = os.getenv('instrucciones_postdoc')
prompt = f"""Utilizando como base este vocabulario de términos, {VOCABULARY}, explora el siguiente texto: '{text}', y genera una \
lista corta de los conceptos presentes en el texto coincidentes con los términos del vocabulario, la lista debe ser una \
secuencia simple de términos encontrados coincidentes separados por comas."""
version_model = 'gpt-3.5-turbo-0125'
response = client.chat.completions.create(
model=version_model,
messages=[{"role": "system", "content": instrucciones},
{"role": "user", "content": prompt}],
temperature=0.8,
max_tokens=300,
)
extract_concepts = response.choices[0].message.content.split(',')
return extract_concepts
def cargar_desde_airtable():
response = requests.get(url, headers=headers)
if response.status_code != 200:
print(f"Error: {response.status_code} - {response.text}")
return pd.DataFrame(columns=["Nombre", "Conceptos"])
records = response.json().get("records", [])
aportes = []
for record in records:
nombre = record["fields"].get("Nombre", "").strip()
conceptos = record["fields"].get("Conceptos", "").strip()
aportes.append([nombre, conceptos])
df = pd.DataFrame(aportes, columns=["Nombre", "Conceptos"])
print("Loaded Airtable Data:")
print(df) # 🔍 Debugging: Print the loaded data
return df
def inicializar_grafo():
df = cargar_desde_airtable()
for _, row in df.iterrows():
nombre = row["Nombre"].strip()
conceptos = row["Conceptos"].strip()
if not nombre or not conceptos:
continue # Skip empty rows
# ✅ Ensure name is added as a node first
if not G.has_node(nombre):
G.add_node(nombre, color='lightblue')
for termino in conceptos.split(','):
termino = termino.strip()
if termino: # ✅ Fix empty terms issue
if not G.has_node(termino):
G.add_node(termino, color='lightgreen')
if not G.has_edge(nombre, termino):
G.add_edge(nombre, termino)
# print("✅ Graph Nodes:", list(G.nodes))
# print("✅ Graph Edges:", list(G.edges))
def visualizar_grafo(kdis):
plt.figure(figsize=(8, 6)) # Aumenta el tamaño de la imagen para mejorar la visibilidad
if len(G.nodes) == 0:
print("⚠️ Warning: The graph is empty! Check if data was loaded correctly.")
plt.text(0.5, 0.5, "No data available", fontsize=12, ha='center')
plt.savefig("graph.png")
plt.close()
return "graph.png"
centrality = nx.betweenness_centrality(G)
# pos = nx.kamada_kawai_layout(G, scale=2.0) # 🔄 Expandir el grafo
pos = nx.spring_layout(G, k=kdis, iterations=100)
node_colors = []
node_sizes = []
for node in G.nodes():
if node in students:
node_colors.append('lightblue') # 🔵 Color para estudiantes
else:
node_colors.append('lightgreen') # 🟢 Color para conceptos
node_sizes.append(800 + 5000 * centrality.get(node, 0)) # 🔽 Reduce la escala
nx.draw(
G, pos, with_labels=True, node_color=node_colors, edge_color='gray',
node_size=node_sizes, font_size=8 # 🔄 Reduce font_size para más espacio
)
edge_labels = nx.get_edge_attributes(G, 'label')
nx.draw_networkx_edge_labels(G, pos, edge_labels=edge_labels, font_size=7)
plt.title("Red de Aportes - Optimizada y Expandida")
plt.savefig("graph.png")
plt.close()
return "graph.png"
def guardar_en_airtable(nombre, conceptos, texto):
if isinstance(conceptos, list):
conceptos = [c.strip().replace("'", "").replace('"', '') for c in conceptos if c.strip()]
data = {"fields": {"Nombre": nombre, "Conceptos": ", ".join(conceptos), "Texto_Aporte": texto}}
response = requests.post(url, headers=headers, json=data)
if response.status_code != 200:
print(f"Error saving to Airtable: {response.status_code} - {response.text}")
def agregar_aporte(nombre, texto, kdis):
conceptos = extract_concepts(texto) # ✅ Extract concepts dynamically
print(f"Extracted Concepts: {conceptos}") # 🔍 Debugging
if not G.has_node(nombre):
G.add_node(nombre, color='lightblue')
for termino in conceptos:
termino = termino.strip()
if not G.has_node(termino):
G.add_node(termino, color='lightgreen')
if not G.has_edge(nombre, termino):
G.add_edge(nombre, termino)
guardar_en_airtable(nombre, conceptos, texto)
return visualizar_grafo(kdis)
def reload_data(kdis):
global G # Asegura que modificamos el grafo global
G.clear() # Borra el contenido actual del grafo
inicializar_grafo() # Vuelve a poblarlo desde Airtable
return visualizar_grafo(kdis) # Retorna la imagen actualizada