Spaces:
Running
Running
File size: 8,061 Bytes
d5b743a a5ad035 d5b743a a5ad035 d5b743a a5ad035 d5b743a a5ad035 d5b743a a5ad035 d5b743a a5ad035 d5b743a a5ad035 d5b743a a5ad035 d5b743a a5ad035 d5b743a a5ad035 d5b743a a5ad035 d5b743a a5ad035 d5b743a a5ad035 d5b743a a5ad035 d5b743a a5ad035 d5b743a a5ad035 d5b743a a5ad035 d5b743a a5ad035 d5b743a a5ad035 d5b743a a5ad035 d5b743a a5ad035 d5b743a |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 |
# ---------------------------------------------------------------------------------
# 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 `df.query("geo == 'X'")` to filter the country, instead of chained comparisons.
- Avoid using filters like `df[df['geo'] == 'Germany']`.
- 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 5 years. The summary should:
- Identify the **year with the largest increase** and the percent change.
- Identify the **year with the largest decrease** and the percent change.
- Provide a **brief overall trend interpretation** (e.g., steady growth, fluctuating, recovery, etc.).
- Avoid listing every year individually, summarize intelligently.
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
#TODO: Continuar mejorando el 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
# ---------------------------------------------------------------------------------
# TODO: La idea es luego usar todas las tablas, cuando ya funcione.
# Se puede si el modelo funciona con las gr谩ficas, sino que toca mejorarlo porque ser铆an consultas m谩s complejas.
labor_data = load_data("labor")
fertility_data = load_data("fertility")
# population_data = load_data("population")
# predictions_data = load_data("predictions")
# TODO: Buscar la forma de disminuir la latencia (muchos datos = mucha latencia)
# ---------------------------------------------------------------------------------
# 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}) # TODO: Probar Agent con multiples dfs
agent = Agent(
[
labor_data,
fertility_data
],
config={
"llm": lm_studio_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:")
# TODO: Poner instrucciones al usuario sobre c贸mo hacer un muy buen prompt (sin tecnisismos, pensando en el usuario final)
# Entrada de usuario para describir el gr谩fico
user_input = st.text_input("What graphics do you have in mind")
generate_button = st.button("Generate")
if generate_button and user_input:
with st.spinner('Generating answer...'):
try:
print(f"\nGenerating prompt...\n")
prompt = generate_graph_prompt(user_input)
print(f"\nPrompt generated\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}")
# TODO: Output estructurado si vemos que es necesario. |