Data e IAEmergentes

Cómo construir un sistema de seguimiento de gastos con IA

9 Mins de lectura

Descubre cómo podemos ayudarte a aprovechar el potencial de la IA para impulsar tu negocio.

¿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:

  1. 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

    Artículos relacionados

    Deja una respuesta

    Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

    ¡No te pierdas nada!

    Te mantenemos al dia de tendencias y novedades sobre el futuro del trabajo, formas de hacer crecer tu negocio, liderazgo digital y muchas cosas más..

    Newsletter