graph_generator / app.py
juancamval's picture
Update app.py (#6)
6f70ef7 verified
raw
history blame contribute delete
7.39 kB
# ---------------------------------------------------------------------------------
# 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}")