Spaces:
Running
Running
# --------------------------------------------------------------------------------- | |
# Aplicaci贸n principal para cargar el modelo, generar prompts y explicar los datos | |
# --------------------------------------------------------------------------------- | |
import streamlit as st # type: ignore | |
import os | |
import re | |
import pandas as pd # type: ignore | |
from dotenv import load_dotenv # type: ignore # Para cambios locales | |
from supabase import create_client, Client # type: ignore | |
# from pandasai import SmartDataframe # type: ignore | |
from pandasai import SmartDatalake # type: ignore # Porque ya usamos m谩s de un df (m谩s de una tabla de nuestra db) | |
from pandasai.llm.local_llm import LocalLLM # type: ignore | |
from pandasai import Agent | |
import matplotlib.pyplot as plt | |
import time | |
# --------------------------------------------------------------------------------- | |
# Funciones auxiliares | |
# --------------------------------------------------------------------------------- | |
def generate_graph_prompt(user_query): | |
prompt = f""" | |
You are a senior data scientist analyzing European labor force data. | |
Given the user's request: "{user_query}" | |
1. Plot the relevant data using matplotlib: | |
- Use pandas indexing with boolean conditions, not .query(). | |
- For example: df[(df['geo'] == 'Germany') & (df['year'] >= 2018)] | |
- Include clear axis labels and a descriptive title. | |
- Save the plot as an image file (e.g., temp_chart.png). | |
2. After plotting, write a *concise analytical summary* of the trend based on those years. The summary should: | |
- Use .diff() followed by .idxmax() and .idxmin() to find where the largest change occurs. | |
- Use .loc[] to retrieve the corresponding year and value. | |
- Calculate percent changes safely (check for divide-by-zero). | |
- Avoid using .index() on float values. | |
3. Store the summary in a variable named explanation. | |
4. Return a result dictionary structured as follows: | |
result = {{ | |
"type": "plot", | |
"value": "temp_chart.png", | |
"explanation": explanation | |
}} | |
IMPORTANT: Use only the data available in the input DataFrame. | |
""" | |
return prompt | |
# --------------------------------------------------------------------------------- | |
# Configuraci贸n de conexi贸n a Supabase | |
# --------------------------------------------------------------------------------- | |
# Cargar variables de entorno desde archivo .env | |
load_dotenv() | |
# Conectar las credenciales de Supabase (ubicadas en "Secrets" en Streamlit) | |
SUPABASE_URL = os.getenv("SUPABASE_URL") | |
SUPABASE_KEY = os.getenv("SUPABASE_KEY") | |
# Crear cliente Supabase | |
supabase: Client = create_client(SUPABASE_URL, SUPABASE_KEY) | |
# Funci贸n para cargar datos de una tabla de Supabase | |
# Tablas posibles: fertility, geo data, labor, population, predictions | |
def load_data(table): | |
try: | |
if supabase: | |
response = supabase.from_(table).select("*").execute() | |
print(f"Response object: {response}") # Inspeccionar objeto completo | |
print(f"Response type: {type(response)}") # Verificar tipo de objeto | |
# Acceder a atributos relacionados a error o data | |
if hasattr(response, 'data'): | |
print(f"Response data: {response.data}") | |
return pd.DataFrame(response.data) | |
elif hasattr(response, 'status_code'): | |
print(f"Response status code: {response.status_code}") | |
elif hasattr(response, '_error'): # Versiones antiguas | |
print(f"Older error attribute: {response._error}") | |
st.error(f"Error fetching data: {response._error}") | |
return pd.DataFrame() | |
else: | |
st.info("Response object does not have 'data' or known error attributes. Check the logs.") | |
return pd.DataFrame() | |
else: | |
st.error("Supabase client not initialized. Check environment variables.") | |
return pd.DataFrame() | |
except Exception as e: | |
st.error(f"An error occurred during data loading: {e}") | |
return pd.DataFrame() | |
# --------------------------------------------------------------------------------- | |
# Cargar datos iniciales | |
# --------------------------------------------------------------------------------- | |
labor_data = load_data("labor") | |
fertility_data = load_data("fertility") | |
# population_data = load_data("population") | |
# predictions_data = load_data("predictions") | |
# --------------------------------------------------------------------------------- | |
# Inicializar LLM desde Ollama con PandasAI | |
# --------------------------------------------------------------------------------- | |
ollama_llm = LocalLLM(api_base="http://localhost:11434/v1", | |
model="gemma3:12b", | |
temperature=0.1, | |
max_tokens=8000) | |
# lm_studio_llm = LocalLLM(api_base="http://localhost:1234/v1") # el modelo es gemma-3-12b-it-qat | |
# sdl = SmartDatalake([labor_data, fertility_data, population_data, predictions_data], config={"llm": ollama_llm}) # DataFrame PandasAI-ready. | |
# sdl = SmartDatalake([labor_data, fertility_data], config={"llm": ollama_llm}) | |
# agent = Agent([labor_data], config={"llm": lm_studio_llm}) | |
agent = Agent( | |
[ | |
labor_data, | |
fertility_data | |
], | |
config={ | |
"llm": ollama_llm, | |
"enable_cache": False, | |
"enable_filter_extraction": False # evita errores de parseo | |
} | |
) | |
# --------------------------------------------------------------------------------- | |
# Configuraci贸n de la app en Streamlit | |
# --------------------------------------------------------------------------------- | |
# T铆tulo de la app | |
st.title("Europe GraphGen :blue[Graph generator] :flag-eu:") | |
# Entrada de usuario para describir el gr谩fico | |
user_input = st.chat_input("What graphics do you have in mind") | |
if user_input: | |
with st.spinner('Generating answer...'): | |
try: | |
print(f"\nGenerating prompt...\n") | |
prompt = generate_graph_prompt(user_input) | |
print(f"\nPrompt generated: {prompt}\n") | |
start_time = time.time() | |
answer = agent.chat(prompt) | |
print(f"\nAnswer type: {type(answer)}\n") # Verificar tipo de objeto | |
print(f"\nAnswer content: {answer}\n") # Inspeccionar contenido de la respuesta | |
print(f"\nFull result: {agent.last_result}\n") | |
full_result = agent.last_result | |
explanation = full_result.get("explanation", "") | |
elapsed_time = time.time() - start_time | |
print(f"\nExecution time: {elapsed_time:.2f} seconds\n") | |
if isinstance(answer, str) and os.path.isfile(answer): | |
# Si el output es una ruta v谩lida a imagen | |
im = plt.imread(answer) | |
st.image(im) | |
os.remove(answer) # Limpiar archivo temporal | |
if explanation: | |
st.markdown(f"*Explanation:* {explanation}") | |
else: | |
# Si no es una ruta v谩lida, mostrar como texto | |
st.markdown(str(answer)) | |
except Exception as e: | |
st.error(f"Error generating answer: {e}") |