¿Alguna vez te has preguntado cómo aprovechar la IA para rastrear tus gastos de manera sencilla? Soy Abbaoui Achraf, ingeniero de machine learning apasionado por las aplicaciones de IA. Acompáñame a construir una aplicación de seguimiento de gastos impulsada por IA utilizando herramientas de vanguardia como DeepSeek, Gradio, Pydantic, Pydantic-AI y Supabase. Juntos, crearemos un sistema inteligente que no solo ayuda a las personas usuarias a gestionar sus gastos, sino que también proporciona insights inteligentes sobre sus patrones de gasto, todo mientras mantiene sus datos seguros en una base de datos de Supabase.
¿Por qué crear tu aplicación de seguimiento de gastos con IA con Supabase?
Supabase ofrece una solución backend como servicio (BaaS) que incluye bases de datos PostgreSQL en tiempo real, autenticación y más. Es una excelente opción para este proyecto porque nos permite centrarnos en la lógica de la aplicación y el agente de IA, en lugar de preocuparnos por configurar y gestionar nuestra propia base de datos.
¡Comencemos!
Cómo crear un seguimiento de gastos con IA paso a paso
1. Configuración del Entorno
Primero, instala las bibliotecas necesarias para configurar el proyecto. Abre una terminal y ejecuta:
pip install gradio pydantic pydantic-ai supabase logfire
Una vez instaladas las bibliotecas, podemos comenzar a configurar el entorno.
2. Configuración del Registro de Actividades (Logging)
Antes de sumergirnos en la aplicación principal, es una buena práctica configurar el registro de actividades para rastrear cualquier problema u operación. Esto ayuda en la depuración y mantenimiento de la aplicación.
import logfire
logfire.configure()
3. Definición de Modelos de Datos con Pydantic
Necesitamos definir los modelos de datos que representan la estructura de los gastos. Estos modelos aseguran que mantengamos datos consistentes y válidos en toda la aplicación.
Definición de Categorías de Gastos
Definimos las diferentes categorías de gastos, como comida, transporte, etc.
from enum import Enum
class ExpenseCategory(str, Enum):
FOOD = "comida"
TRANSPORT = "transporte"
ENTERTAINMENT = "entretenimiento"
UTILITIES = "servicios"
RENT = "alquiler"
OTHER = "otros"
Creación del Modelo Base de Gastos
Este es el modelo que representa una entrada de gasto individual:
from pydantic import BaseModel, Field
from datetime import date
from uuid import UUID
class ExpenseBase(BaseModel):
uuid: UUID = Field(description='ID único generado al crear un gasto')
title: str = Field(..., max_length=100)
date: date
description: str = Field(..., max_length=500)
category: ExpenseCategory
amount: float = Field(..., gt=0)
Creación del Modelo de Respuesta
Este modelo estructurará la respuesta del agente de IA, incluyendo consejos para la persona usuaria y la lista de gastos:
from typing import List, Tuple, Union
class ResultAnswer(BaseModel):
answer_to_user: str = Field(description='La respuesta que se debe devolver al usuario, debe ser clara, directa y en un tono amigable.')
expense: Union[List[ExpenseBase] | None]
tips_to_user: Tuple[bool, Union[str, None]]
4. Integración de Pydantic-AI
Ahora que hemos definido nuestros modelos de datos, podemos crear nuestro agente de IA usando Pydantic-AI. Este agente será responsable de interpretar las consultas del usuario, proporcionar respuestas e interactuar con la base de datos de Supabase.
from pydantic_ai import Agent, RunContext
from pydantic_ai.models.openai import OpenAIModel
from pydantic_ai.usage import UsageLimits
from supabase import Client
from uuid import UUID
@dataclass
class Dependencies:
user_uuid: UUID # Para este demo no lo usaremos
supabase: Client | None
expense_agent = Agent(
model=OpenAIModel(
'deepseek-chat', # Usa el nombre de tu modelo aquí
base_url='<https://api.deepseek.com/v1>',
api_key='tu_api_key', # Reemplaza con tu clave API real
),
deps_type=Dependencies,
result_type=ResultAnswer,
system_prompt=(
'Eres un agente de IA especializado en el seguimiento de gastos, encargado de ayudar a los usuarios a gestionar sus finanzas personales de manera efectiva. '
'Tus funcionalidades incluyen registrar gastos, generar informes, enviar alertas de presupuesto y proporcionar insights basados en patrones de gasto.'
),
model_settings={'temperature': 0.0} # Cuanto mayor sea la temperatura, más diversas pueden ser las respuestas del modelo
)
5. Trabajando con Supabase
Supabase es una alternativa de código abierto a Firebase y ofrece un conjunto completo de servicios backend, como autenticación, almacenamiento y una potente base de datos PostgreSQL. Para este proyecto, usaremos principalmente la base de datos PostgreSQL de Supabase para almacenar, recuperar y actualizar los gastos de los usuarios.
1. Configuración del Cliente de Supabase
Para interactuar con Supabase, necesitas inicializar el cliente de Supabase en tu aplicación. Esto nos permitirá hacer consultas a la base de datos, como agregar o recuperar gastos.
from supabase import create_client, Client
url = '<https://xyz.supabase.co>' # Reemplaza con tu URL de Supabase
key = 'public-anon-key' # Reemplaza con tu clave API de Supabase
supabase: Client = create_client(url, key)
2. Creación de la Tabla de Gastos en Supabase
Antes de agregar o recuperar datos de Supabase, asegúrate de haber creado una tabla para almacenar los gastos. Aquí tienes un ejemplo de consulta SQL para crear la tabla expenses
:
CREATE TABLE expenses (
uuid UUID PRIMARY KEY,
title TEXT NOT NULL,
date DATE NOT NULL,
description TEXT,
category TEXT NOT NULL,
amount FLOAT NOT NULL
);
Puedes ejecutar esta consulta SQL en el Panel de Control de Supabase en la pestaña «SQL Editor».
6. Implementación de Funciones de Interacción con la Base de Datos
Agregar Gastos a Supabase
Implementaremos una función que insertará los datos de gastos en la base de datos de Supabase:
@expense_agent.tool
async def add_to_database(ctx: RunContext[Dependencies], expenses: List[ExpenseBase]) -> str:
"""
Agrega gastos a la base de datos.
"""
try:
supabase: Client = ctx.deps.supabase_client
user_uuid: str = ctx.deps.user_uuid
rows_to_insert = []
for expense in expenses:
rows_to_insert.append({
"user_uuid": user_uuid,
"title": expense.title,
"date": expense.date.isoformat(),
"description": expense.description,
"category": expense.category.value,
"amount": expense.amount,
})
response = supabase.table("expenses").insert(rows_to_insert).execute()
return f"Tus gastos han sido guardados. Insertados: {json.dumps(response.data, indent=2)}"
except Exception as e:
return f"Error al agregar gastos a la base de datos. Error: {e}"
Esta función convierte el gasto en un diccionario, asegura que el UUID esté correctamente formateado y luego inserta el gasto en la base de datos de Supabase.
7. Recuperar Gastos de Supabase
Para recuperar una lista de gastos de la base de datos, implementamos una función que consulta la tabla expenses
:
@expense_agent.tool
async def retrive_from_database(ctx: RunContext[Dependencies]) -> str:
"""
Recupera todos los gastos del usuario actual de la base de datos.
"""
try:
supabase: Client = ctx.deps.supabase_client
user_uuid: str = ctx.deps.user_uuid
response = (
supabase
.table("expenses")
.select("*")
.eq("user_uuid", user_uuid)
.order("created_at", desc=True) # o el orden que prefieras
.execute()
)
return json.dumps(response.data, indent=2)
except Exception as e:
return f"Error al recuperar gastos de la base de datos. Error: {e}"
Esta función consulta todos los registros de la tabla expenses
y los devuelve como objetos ExpenseBase
.
8. Actualizar Gastos en Supabase
Finalmente, agregaremos una función para actualizar un gasto existente en la base de datos:
@expense_agent.tool
async def update_from_database(ctx: RunContext[Dependencies], expense: ExpenseBase) -> str:
"""
Actualiza un gasto en la base de datos usando expense.uuid como clave primaria.
"""
try:
supabase: Client = ctx.deps.supabase_client
update_fields = {
"title": expense.title,
"date": expense.date.isoformat(),
"description": expense.description,
"category": expense.category.value,
"amount": expense.amount
}
# Usa expense.uuid para localizar el registro en la base de datos (asumiendo que "expense_id" es la PK)
response = (
supabase
.table("expenses")
.update(update_fields)
.eq("expense_id", str(expense.uuid))
.execute()
)
return f"Gasto {expense.uuid} actualizado correctamente. Resultado: {json.dumps(response.data, indent=2)}"
except Exception as e:
return f"Error al actualizar el gasto en la base de datos. Error: {e}"
Otras herramientas para ayudar al modelo a generar gastos
@expense_agent.tool
async def todays_date(ctx: RunContext[Dependencies]) -> str:
return str(date.today())
@expense_agent.tool
async def generate_uuid(ctx: RunContext[Dependencies]) -> str:
return str(uuid.uuid4())
Prueba de la respuesta del agente
from IPython.display import Markdown, display
r = expense_agent.run_sync(
'Compré 10 caramelos, cada uno por 15dh, 2 botellas de agua por 5dh cada una y un sándwich por 20dh.',
deps=Dependencies(
user_uuid='cdb64645-e1e4-4686-af86-de8f581b8037',
supabase_client=None
),
usage_limits=UsageLimits(request_limit=5),
)
print(f"Respuesta para el usuario:\\n>>{r.data.answer_to_user}")
print(f"Consejos para el usuario:\\n>>{r.data.tips_to_user[1] if r.data.tips_to_user[0] else 'Sin consejos'}")
print(f"Gasto registrado:\\n>>{r.data.expense}")
Ejemplo de salida
Respuesta para el usuario:
Tus gastos han sido registrados con éxito. Aquí tienes un resumen de tus gastos recientes:
- Caramelos: 10 caramelos a 15dh cada uno, total 150dh
- Botellas de agua: 2 botellas a 5dh cada una, total 10dh
- Sándwich: 1 sándwich, total 20dh
Total gastado en comida: 180dh
Consejos para el usuario:
- Considera comprar en grandes cantidades o buscar descuentos para ahorrar en gastos de comida.
Gasto registrado:
[
ExpenseBase(
uuid=UUID('313af951-1c1f-493d-afd9-ab2cd0b0f0ae'),
title='Caramelos',
date=datetime.date(2025, 2, 24),
description='10 caramelos a 15dh cada uno',
category=<ExpenseCategory.FOOD: 'comida'>,
amount=150.0
),
ExpenseBase(
uuid=UUID('d3979bc8-cd47-4d5b-996a-adbdbe8aea62'),
title='Botellas de agua',
date=datetime.date(2025, 2, 24),
description='2 botellas de agua a 5dh cada una',
category=<ExpenseCategory.FOOD: 'comida'>,
amount=10.0
),
ExpenseBase(
uuid=UUID('c4a86d69-ff74-4888-a335-471247f03b8f'),
title='Sándwich',
date=datetime.date(2025, 2, 24),
description='1 sándwich',
category=<ExpenseCategory.FOOD: 'comida'>,
amount=20.0
)
]
El resultado anterior muestra cómo el agente de IA procesa y responde a las consultas del usuario sobre gastos. En este ejemplo, cuando un usuario menciona la compra de caramelos de manera compleja, botellas de agua y un sándwich, el agente no solo registra los gastos, sino que también realiza los cálculos necesarios y proporciona consejos personalizados para ahorrar dinero. Esto demuestra la capacidad del agente para combinar el seguimiento de gastos con asesoramiento financiero inteligente.
Base de datos Postgres en Supabase
En el panel de Supabase, podemos ver que el expense_agent
ha agregado los gastos descritos por el usuario en la base de datos.
9. Creación de la Interfaz con Gradio
Usaremos Gradio para crear una interfaz interactiva donde los usuarios puedan ingresar los detalles de sus gastos e interactuar con el agente de IA. Así es como puedes configurar la interfaz:
import gradio as gr
def run_expense_agent(user_input, *args, **kwargs):
response = expense_agent.run_sync(
user_input,
deps=Dependencies(
user_uuid='tu-uuid-de-usuario', # Reemplaza con el UUID real del usuario
supabase_client=supabase
),
usage_limits=UsageLimits(request_limit=5),
)
return response.data.answer_to_user, response.data.tips_to_user[1] if response.data.tips_to_user[0] else 'No hay consejos', response.data.expense
# Construye la interfaz
with gr.Blocks(theme=gr.themes.Soft()) as demo:
gr.Markdown("# Asistente de Gestión de Gastos")
gr.Markdown("Sube recibos o gastos y haz preguntas sobre tus finanzas.")
with gr.Row():
with gr.Column(scale=3):
chatbot = gr.Chatbot(height=500, elem_id="chatbot")
with gr.Row():
msg = gr.MultimodalTextbox(
placeholder="Sube recibos y haz preguntas...",
file_count="multiple",
file_types=["image", "pdf"]
)
submit_btn = gr.Button("Enviar", variant="primary")
with gr.Column(scale=1):
with gr.Accordion("Consejos", open=False):
tips_output = gr.Textbox(label="Consejos de Gastos")
with gr.Accordion("Detalles del Gasto", open=False):
expense_output = gr.JSON(label="Datos Extraídos")
with gr.Accordion("Archivos", open=False):
file_output = gr.Textbox(label="Archivos Procesados")
# Configura la funcionalidad del chat
def respond(message, chat_history, files):
if message == "":
return "", chat_history, "", None, ""
answer, tips, expense, file_info = run_expense_agent(message, files, chat_history)
chat_history.append((message, answer))
return "", chat_history, tips, expense, file_info
submit_btn.click(
respond,
inputs=[msg, chatbot],
outputs=[msg, chatbot, tips_output, expense_output, file_output]
)
msg.submit(
respond,
inputs=[msg, chatbot],
outputs=[msg, chatbot, tips_output, expense_output, file_output]
)
gr.Markdown("### ¿Necesitas ayuda? Prueba preguntando:")
gr.Examples(
[
"¿Cuáles son mis gastos totales de este mes?",
"Categoriza este recibo por mí",
"¿Cuándo fue mi último gasto de negocio?",
"Muéstrame todos los gastos mayores a $100"
],
inputs=msg
)
demo.launch()
Interfaz de Uso después de renderizar
La interfaz de uso presenta un diseño limpio e intuitivo con un modelo de interacción similar a un chat. Las personas usuarias pueden ingresar fácilmente sus gastos a través de texto o subiendo recibos, mientras que el asistente de IA proporciona retroalimentación en tiempo real y insights financieros. La interfaz también incluye secciones dedicadas para ver consejos de gastos y datos detallados de transacciones.
10. Pruebas y Despliegue
Ahora que todo está configurado, puedes ejecutar la aplicación localmente o desplegarla en una plataforma como Heroku o DigitalOcean. La interfaz de Gradio permitirá a las personas usuarias ingresar detalles de gastos, y el agente de IA responderá con insights y almacenará los datos en Supabase.
En este tutorial, hemos creado un sistema funcional de seguimiento de gastos con IA utilizando DeepSeek Model, Gradio, Pydantic, Pydantic-AI y Supabase. Hemos integrado IA para interpretar consultas de personas usuarias y gestionar los gastos, y Supabase sirve como base de datos backend donde se almacenan y recuperan todos los datos.
Siguiendo este tutorial, puedes fácilmente extender el sistema para agregar más características como seguimiento de presupuesto, gastos recurrentes, y más información avanzada.
Gracias por leer, y ¡feliz programación!
¿Quieres aprovechar el poder de la IA para impulsar tu negocio? Contamos con un equipo de expertos en IA Generativa y Data que ha desarrollado GenIA Ecosystem, un ecosistema de soluciones propias de IA conversacional, generación de contenido y data adaptadas a las necesidades de cada mercado y cliente. Contáctanos y estaremos encantados de ayudarte.
¿Quieres más información sobre nuestros servicios de inteligencia artificial?
Contacta con nuestro equipo de Data & AI