{"id":48459,"date":"2025-03-07T09:00:11","date_gmt":"2025-03-07T08:00:11","guid":{"rendered":"https:\/\/www.hiberus.com\/crecemos-contigo\/?p=48459"},"modified":"2025-03-20T13:18:17","modified_gmt":"2025-03-20T12:18:17","slug":"construyendo-un-sistema-de-seguimiento-de-gastos-con-ia-usando-gradio-pydantic-ai-supabase-y-deepseek-una-guia-completa","status":"publish","type":"post","link":"https:\/\/www.hiberus.com\/crecemos-contigo\/construyendo-un-sistema-de-seguimiento-de-gastos-con-ia-usando-gradio-pydantic-ai-supabase-y-deepseek-una-guia-completa\/","title":{"rendered":"C\u00f3mo construir un sistema de seguimiento de gastos con IA"},"content":{"rendered":"<p>\u00bfAlguna vez te has preguntado c\u00f3mo aprovechar la IA para rastrear tus gastos de manera sencilla? Soy Abbaoui Achraf, ingeniero de machine learning apasionado por las aplicaciones de IA.\u00a0 Acomp\u00e1\u00f1ame a construir una <strong>aplicaci\u00f3n de seguimiento de gastos impulsada por IA<\/strong> utilizando herramientas de vanguardia como <strong>DeepSeek<\/strong>, <strong>Gradio<\/strong>, <strong>Pydantic<\/strong>, <strong>Pydantic-AI<\/strong> y <strong>Supabase<\/strong>. Juntos, crearemos un sistema inteligente que no solo ayuda a las personas usuarias a gestionar sus gastos, sino que tambi\u00e9n proporciona insights inteligentes sobre sus patrones de gasto, todo mientras mantiene sus datos seguros en una <strong>base de datos de Supabase<\/strong>.<\/p>\n<h2>\u00bfPor qu\u00e9 crear tu aplicaci\u00f3n de seguimiento de gastos con IA con Supabase?<\/h2>\n<p><strong>Supabase<\/strong> ofrece una soluci\u00f3n backend como servicio (BaaS) que incluye bases de datos PostgreSQL en tiempo real, autenticaci\u00f3n y m\u00e1s. Es una excelente opci\u00f3n para este proyecto porque nos permite centrarnos en la l\u00f3gica de la aplicaci\u00f3n y el agente de IA, en lugar de preocuparnos por configurar y gestionar nuestra propia base de datos.<\/p>\n<p>\u00a1Comencemos!<\/p>\n<h2>C\u00f3mo crear un seguimiento de gastos con IA paso a paso<\/h2>\n<h3>1. Configuraci\u00f3n del Entorno<\/h3>\n<p>Primero, instala las bibliotecas necesarias para configurar el proyecto. Abre una terminal y ejecuta:<\/p>\n<pre><code class=\"language-bash\">pip install gradio pydantic pydantic-ai supabase logfire\r\n<\/code><\/pre>\n<p>Una vez instaladas las bibliotecas, podemos comenzar a configurar el entorno.<\/p>\n<p><!-- notionvc: de3e7395-78f7-473d-964b-e549d6b58c2e --><\/p>\n<h3>2. Configuraci\u00f3n del Registro de Actividades (Logging)<\/h3>\n<p>Antes de sumergirnos en la aplicaci\u00f3n principal, es una buena pr\u00e1ctica configurar el registro de actividades para rastrear cualquier problema u operaci\u00f3n. Esto ayuda en la depuraci\u00f3n y mantenimiento de la aplicaci\u00f3n.<\/p>\n<pre><code class=\"language-python\">import logfire\r\nlogfire.configure()\r\n<\/code><\/pre>\n<h3>3. Definici\u00f3n de Modelos de Datos con Pydantic<\/h3>\n<p><!-- notionvc: 705a68af-89a4-40e7-ba90-f3984ea7234a --><\/p>\n<p>Necesitamos definir los modelos de datos que representan la estructura de los gastos. Estos modelos aseguran que mantengamos datos consistentes y v\u00e1lidos en toda la aplicaci\u00f3n.<\/p>\n<h4>Definici\u00f3n de Categor\u00edas de Gastos<\/h4>\n<p>Definimos las diferentes categor\u00edas de gastos, como <strong>comida<\/strong>, <strong>transporte<\/strong>, etc.<\/p>\n<pre><code class=\"language-python\">from enum import Enum\r\n\r\nclass ExpenseCategory(str, Enum):\r\n    FOOD = \"comida\"\r\n    TRANSPORT = \"transporte\"\r\n    ENTERTAINMENT = \"entretenimiento\"\r\n    UTILITIES = \"servicios\"\r\n    RENT = \"alquiler\"\r\n    OTHER = \"otros\"\r\n<\/code><\/pre>\n<h4>Creaci\u00f3n del Modelo Base de Gastos<\/h4>\n<p>Este es el modelo que representa una entrada de gasto individual:<\/p>\n<pre><code class=\"language-python\">from pydantic import BaseModel, Field\r\nfrom datetime import date\r\nfrom uuid import UUID\r\n\r\nclass ExpenseBase(BaseModel):\r\n    uuid: UUID = Field(description='ID \u00fanico generado al crear un gasto')\r\n    title: str = Field(..., max_length=100)\r\n    date: date\r\n    description: str = Field(..., max_length=500)\r\n    category: ExpenseCategory\r\n    amount: float = Field(..., gt=0)\r\n<\/code><\/pre>\n<h4>Creaci\u00f3n del Modelo de Respuesta<\/h4>\n<p>Este modelo estructurar\u00e1 la respuesta del agente de IA, incluyendo consejos para la persona usuaria y la lista de gastos:<\/p>\n<pre><code class=\"language-python\">from typing import List, Tuple, Union\r\n\r\nclass ResultAnswer(BaseModel):\r\n    answer_to_user: str = Field(description='La respuesta que se debe devolver al usuario, debe ser clara, directa y en un tono amigable.')\r\n    expense: Union[List[ExpenseBase] | None]\r\n    tips_to_user: Tuple[bool, Union[str, None]]\r\n<\/code><\/pre>\n<h3>4. Integraci\u00f3n de Pydantic-AI<\/h3>\n<p>Ahora que hemos definido nuestros modelos de datos, podemos crear nuestro <strong>agente de IA<\/strong> usando <strong>Pydantic-AI<\/strong>. Este agente ser\u00e1 responsable de interpretar las consultas del usuario, proporcionar respuestas e interactuar con la base de datos de <strong>Supabase<\/strong>.<\/p>\n<pre><code class=\"language-python\">from pydantic_ai import Agent, RunContext\r\nfrom pydantic_ai.models.openai import OpenAIModel\r\nfrom pydantic_ai.usage import UsageLimits\r\nfrom supabase import Client\r\nfrom uuid import UUID\r\n\r\n@dataclass\r\nclass Dependencies:\r\n    user_uuid: UUID # Para este demo no lo usaremos\r\n    supabase: Client | None\r\n\r\nexpense_agent = Agent(\r\n    model=OpenAIModel(\r\n        'deepseek-chat',  # Usa el nombre de tu modelo aqu\u00ed\r\n        base_url='&lt;https:\/\/api.deepseek.com\/v1&gt;',\r\n        api_key='tu_api_key',  # Reemplaza con tu clave API real\r\n    ),\r\n    deps_type=Dependencies,\r\n    result_type=ResultAnswer,\r\n    system_prompt=(\r\n        '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. '\r\n        'Tus funcionalidades incluyen registrar gastos, generar informes, enviar alertas de presupuesto y proporcionar insights basados en patrones de gasto.'\r\n    ),\r\n    model_settings={'temperature': 0.0} # Cuanto mayor sea la temperatura, m\u00e1s diversas pueden ser las respuestas del modelo\r\n)\r\n\r\n<\/code><\/pre>\n<h2>5. Trabajando con Supabase<\/h2>\n<p>Supabase es una alternativa de c\u00f3digo abierto a Firebase y ofrece un conjunto completo de servicios backend, como autenticaci\u00f3n, almacenamiento y una potente base de datos PostgreSQL. Para este proyecto, usaremos principalmente la base de datos <strong>PostgreSQL<\/strong> de Supabase para almacenar, recuperar y actualizar los gastos de los usuarios.<\/p>\n<h3>1. Configuraci\u00f3n del Cliente de Supabase<\/h3>\n<p>Para interactuar con Supabase, necesitas inicializar el <strong>cliente de Supabase<\/strong> en tu aplicaci\u00f3n. Esto nos permitir\u00e1 hacer consultas a la base de datos, como agregar o recuperar gastos.<\/p>\n<pre><code class=\"language-python\">from supabase import create_client, Client\r\n\r\nurl = '&lt;https:\/\/xyz.supabase.co&gt;'  # Reemplaza con tu URL de Supabase\r\nkey = 'public-anon-key'  # Reemplaza con tu clave API de Supabase\r\n\r\nsupabase: Client = create_client(url, key)\r\n<\/code><\/pre>\n<h3>2. Creaci\u00f3n de la Tabla de Gastos en Supabase<\/h3>\n<p>Antes de agregar o recuperar datos de Supabase, aseg\u00farate de haber creado una tabla para almacenar los gastos. Aqu\u00ed tienes un ejemplo de consulta SQL para crear la tabla <code>expenses<\/code>:<\/p>\n<pre><code class=\"language-sql\">CREATE TABLE expenses (\r\n    uuid UUID PRIMARY KEY,\r\n    title TEXT NOT NULL,\r\n    date DATE NOT NULL,\r\n    description TEXT,\r\n    category TEXT NOT NULL,\r\n    amount FLOAT NOT NULL\r\n);\r\n<\/code><\/pre>\n<p>Puedes ejecutar esta consulta SQL en el <strong>Panel de Control de Supabase<\/strong> en la pesta\u00f1a \u00abSQL Editor\u00bb.<\/p>\n<h2>6. Implementaci\u00f3n de Funciones de Interacci\u00f3n con la Base de Datos<\/h2>\n<h3>Agregar Gastos a Supabase<\/h3>\n<p>Implementaremos una funci\u00f3n que insertar\u00e1 los datos de gastos en la base de datos de <strong>Supabase<\/strong>:<\/p>\n<pre><code class=\"language-python\">@expense_agent.tool\r\nasync def add_to_database(ctx: RunContext[Dependencies], expenses: List[ExpenseBase]) -&gt; str:\r\n    \"\"\"\r\n    Agrega gastos a la base de datos.\r\n    \"\"\"\r\n    try:\r\n        supabase: Client = ctx.deps.supabase_client\r\n        user_uuid: str = ctx.deps.user_uuid\r\n\r\n        rows_to_insert = []\r\n        for expense in expenses:\r\n            rows_to_insert.append({\r\n                \"user_uuid\": user_uuid,\r\n                \"title\": expense.title,\r\n                \"date\": expense.date.isoformat(),\r\n                \"description\": expense.description,\r\n                \"category\": expense.category.value,\r\n                \"amount\": expense.amount,\r\n            })\r\n\r\n        response = supabase.table(\"expenses\").insert(rows_to_insert).execute()\r\n\r\n        return f\"Tus gastos han sido guardados. Insertados: {json.dumps(response.data, indent=2)}\"\r\n    except Exception as e:\r\n        return f\"Error al agregar gastos a la base de datos. Error: {e}\"\r\n<\/code><\/pre>\n<p>Esta funci\u00f3n convierte el gasto en un diccionario, asegura que el UUID est\u00e9 correctamente formateado y luego inserta el gasto en la base de datos de <strong>Supabase<\/strong>.<\/p>\n<h2>7. Recuperar Gastos de Supabase<\/h2>\n<p>Para recuperar una lista de gastos de la base de datos, implementamos una funci\u00f3n que consulta la tabla <code>expenses<\/code>:<\/p>\n<pre><code class=\"language-python\">@expense_agent.tool\r\nasync def retrive_from_database(ctx: RunContext[Dependencies]) -&gt; str:\r\n    \"\"\"\r\n    Recupera todos los gastos del usuario actual de la base de datos.\r\n    \"\"\"\r\n    try:\r\n        supabase: Client = ctx.deps.supabase_client\r\n        user_uuid: str = ctx.deps.user_uuid\r\n\r\n        response = (\r\n            supabase\r\n            .table(\"expenses\")\r\n            .select(\"*\")\r\n            .eq(\"user_uuid\", user_uuid)\r\n            .order(\"created_at\", desc=True)  # o el orden que prefieras\r\n            .execute()\r\n        )\r\n\r\n        return json.dumps(response.data, indent=2)\r\n    except Exception as e:\r\n        return f\"Error al recuperar gastos de la base de datos. Error: {e}\"\r\n<\/code><\/pre>\n<p>Esta funci\u00f3n consulta todos los registros de la tabla <code>expenses<\/code> y los devuelve como objetos <code>ExpenseBase<\/code>.<\/p>\n<p><!-- notionvc: 2003155d-7721-4a0d-a2c2-540b38f48467 --><\/p>\n<h3>8. Actualizar Gastos en Supabase<\/h3>\n<p>Finalmente, agregaremos una funci\u00f3n para actualizar un gasto existente en la base de datos:<\/p>\n<pre><code class=\"language-python\">@expense_agent.tool\r\nasync def update_from_database(ctx: RunContext[Dependencies], expense: ExpenseBase) -&gt; str:\r\n    \"\"\"\r\n    Actualiza un gasto en la base de datos usando expense.uuid como clave primaria.\r\n    \"\"\"\r\n    try:\r\n        supabase: Client = ctx.deps.supabase_client\r\n\r\n        update_fields = {\r\n            \"title\": expense.title,\r\n            \"date\": expense.date.isoformat(),\r\n            \"description\": expense.description,\r\n            \"category\": expense.category.value,\r\n            \"amount\": expense.amount\r\n        }\r\n\r\n        # Usa expense.uuid para localizar el registro en la base de datos (asumiendo que \"expense_id\" es la PK)\r\n        response = (\r\n            supabase\r\n            .table(\"expenses\")\r\n            .update(update_fields)\r\n            .eq(\"expense_id\", str(expense.uuid))\r\n            .execute()\r\n        )\r\n\r\n        return f\"Gasto {expense.uuid} actualizado correctamente. Resultado: {json.dumps(response.data, indent=2)}\"\r\n\r\n    except Exception as e:\r\n        return f\"Error al actualizar el gasto en la base de datos. Error: {e}\"\r\n\r\n<\/code><\/pre>\n<h4>Otras herramientas para ayudar al modelo a generar gastos<\/h4>\n<pre><code class=\"language-python\">@expense_agent.tool\r\nasync def todays_date(ctx: RunContext[Dependencies]) -&gt; str:\r\n    return str(date.today())\r\n\r\n@expense_agent.tool\r\nasync def generate_uuid(ctx: RunContext[Dependencies]) -&gt; str:\r\n    return str(uuid.uuid4())\r\n<\/code><\/pre>\n<h4>Prueba de la respuesta del agente<\/h4>\n<pre><code class=\"language-python\">from IPython.display import Markdown, display\r\n\r\nr = expense_agent.run_sync(\r\n    'Compr\u00e9 10 caramelos, cada uno por 15dh, 2 botellas de agua por 5dh cada una y un s\u00e1ndwich por 20dh.',\r\n    deps=Dependencies(\r\n        user_uuid='cdb64645-e1e4-4686-af86-de8f581b8037',\r\n        supabase_client=None\r\n    ),\r\n    usage_limits=UsageLimits(request_limit=5),\r\n)\r\nprint(f\"Respuesta para el usuario:\\\\n&gt;&gt;{r.data.answer_to_user}\")\r\nprint(f\"Consejos para el usuario:\\\\n&gt;&gt;{r.data.tips_to_user[1] if r.data.tips_to_user[0] else 'Sin consejos'}\")\r\nprint(f\"Gasto registrado:\\\\n&gt;&gt;{r.data.expense}\")\r\n\r\n<\/code><\/pre>\n<h4>Ejemplo de salida<\/h4>\n<p>Respuesta para el usuario:<\/p>\n<p>Tus gastos han sido registrados con \u00e9xito. Aqu\u00ed tienes un resumen de tus gastos recientes:<\/p>\n<ul>\n<li>Caramelos: 10 caramelos a 15dh cada uno, total 150dh<\/li>\n<li>Botellas de agua: 2 botellas a 5dh cada una, total 10dh<\/li>\n<li>S\u00e1ndwich: 1 s\u00e1ndwich, total 20dh<\/li>\n<\/ul>\n<p>Total gastado en comida: 180dh<\/p>\n<p><strong>Consejos para el usuario:<\/strong><\/p>\n<ol>\n<li>Considera comprar en grandes cantidades o buscar descuentos para ahorrar en gastos de comida.<\/li>\n<\/ol>\n<p><strong>Gasto registrado:<\/strong><\/p>\n<pre><code class=\"language-python\">[\r\n\tExpenseBase(\r\n\t\tuuid=UUID('313af951-1c1f-493d-afd9-ab2cd0b0f0ae'),\r\n\t\ttitle='Caramelos',\r\n\t\tdate=datetime.date(2025, 2, 24),\r\n\t\tdescription='10 caramelos a 15dh cada uno',\r\n\t\tcategory=&lt;ExpenseCategory.FOOD: 'comida'&gt;,\r\n\t\tamount=150.0\r\n\t),\r\n\tExpenseBase(\r\n\t\tuuid=UUID('d3979bc8-cd47-4d5b-996a-adbdbe8aea62'),\r\n\t\ttitle='Botellas de agua',\r\n\t\tdate=datetime.date(2025, 2, 24),\r\n\t\tdescription='2 botellas de agua a 5dh cada una',\r\n\t\tcategory=&lt;ExpenseCategory.FOOD: 'comida'&gt;,\r\n\t\tamount=10.0\r\n\t),\r\n\tExpenseBase(\r\n\t\tuuid=UUID('c4a86d69-ff74-4888-a335-471247f03b8f'),\r\n\t\ttitle='S\u00e1ndwich',\r\n\t\tdate=datetime.date(2025, 2, 24),\r\n\t\tdescription='1 s\u00e1ndwich',\r\n\t\tcategory=&lt;ExpenseCategory.FOOD: 'comida'&gt;,\r\n\t\tamount=20.0\r\n\t)\r\n]\r\n\u00a0<\/code><\/pre>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-48469\" src=\"https:\/\/www.hiberus.com\/crecemos-contigo\/wp-content\/uploads\/2025\/03\/image-26.png\" alt=\"\" width=\"2196\" height=\"222\" srcset=\"https:\/\/www.hiberus.com\/crecemos-contigo\/wp-content\/uploads\/2025\/03\/image-26.png 2196w, https:\/\/www.hiberus.com\/crecemos-contigo\/wp-content\/uploads\/2025\/03\/image-26-300x30.png 300w, https:\/\/www.hiberus.com\/crecemos-contigo\/wp-content\/uploads\/2025\/03\/image-26-1024x104.png 1024w, https:\/\/www.hiberus.com\/crecemos-contigo\/wp-content\/uploads\/2025\/03\/image-26-768x78.png 768w, https:\/\/www.hiberus.com\/crecemos-contigo\/wp-content\/uploads\/2025\/03\/image-26-1536x155.png 1536w, https:\/\/www.hiberus.com\/crecemos-contigo\/wp-content\/uploads\/2025\/03\/image-26-2048x207.png 2048w, https:\/\/www.hiberus.com\/crecemos-contigo\/wp-content\/uploads\/2025\/03\/image-26-360x36.png 360w\" sizes=\"auto, (max-width: 2196px) 100vw, 2196px\" \/><\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-48470\" src=\"https:\/\/www.hiberus.com\/crecemos-contigo\/wp-content\/uploads\/2025\/03\/image-27.png\" alt=\"\" width=\"1736\" height=\"78\" srcset=\"https:\/\/www.hiberus.com\/crecemos-contigo\/wp-content\/uploads\/2025\/03\/image-27.png 1736w, https:\/\/www.hiberus.com\/crecemos-contigo\/wp-content\/uploads\/2025\/03\/image-27-300x13.png 300w, https:\/\/www.hiberus.com\/crecemos-contigo\/wp-content\/uploads\/2025\/03\/image-27-1024x46.png 1024w, https:\/\/www.hiberus.com\/crecemos-contigo\/wp-content\/uploads\/2025\/03\/image-27-768x35.png 768w, https:\/\/www.hiberus.com\/crecemos-contigo\/wp-content\/uploads\/2025\/03\/image-27-1536x69.png 1536w, https:\/\/www.hiberus.com\/crecemos-contigo\/wp-content\/uploads\/2025\/03\/image-27-360x16.png 360w\" sizes=\"auto, (max-width: 1736px) 100vw, 1736px\" \/><\/p>\n<p>El resultado anterior muestra c\u00f3mo 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\u00e1ndwich, el agente no solo registra los gastos, sino que tambi\u00e9n realiza los c\u00e1lculos necesarios y proporciona consejos personalizados para ahorrar dinero. Esto demuestra la capacidad del agente para combinar el seguimiento de gastos con asesoramiento financiero inteligente.<\/p>\n<p><!-- notionvc: ddf8470e-4585-4964-bd8a-b6e3ee55ef8c --><\/p>\n<h4>Base de datos Postgres en Supabase<\/h4>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-48471\" src=\"https:\/\/www.hiberus.com\/crecemos-contigo\/wp-content\/uploads\/2025\/03\/image-28.png\" alt=\"\" width=\"1862\" height=\"239\" srcset=\"https:\/\/www.hiberus.com\/crecemos-contigo\/wp-content\/uploads\/2025\/03\/image-28.png 1862w, https:\/\/www.hiberus.com\/crecemos-contigo\/wp-content\/uploads\/2025\/03\/image-28-300x39.png 300w, https:\/\/www.hiberus.com\/crecemos-contigo\/wp-content\/uploads\/2025\/03\/image-28-1024x131.png 1024w, https:\/\/www.hiberus.com\/crecemos-contigo\/wp-content\/uploads\/2025\/03\/image-28-768x99.png 768w, https:\/\/www.hiberus.com\/crecemos-contigo\/wp-content\/uploads\/2025\/03\/image-28-1536x197.png 1536w, https:\/\/www.hiberus.com\/crecemos-contigo\/wp-content\/uploads\/2025\/03\/image-28-360x46.png 360w\" sizes=\"auto, (max-width: 1862px) 100vw, 1862px\" \/><\/p>\n<p>En el panel de Supabase, podemos ver que el <code>expense_agent<\/code> ha agregado los gastos descritos por el usuario en la base de datos.<\/p>\n<h3>9. Creaci\u00f3n de la Interfaz con Gradio<\/h3>\n<p>Usaremos <strong>Gradio<\/strong> para crear una interfaz interactiva donde los usuarios puedan ingresar los detalles de sus gastos e interactuar con el agente de IA. As\u00ed es como puedes configurar la interfaz:<\/p>\n<pre><code class=\"language-python\">import gradio as gr\r\n\r\ndef run_expense_agent(user_input, *args, **kwargs):\r\n    response = expense_agent.run_sync(\r\n        user_input,\r\n        deps=Dependencies(\r\n            user_uuid='tu-uuid-de-usuario',  # Reemplaza con el UUID real del usuario\r\n            supabase_client=supabase\r\n        ),\r\n        usage_limits=UsageLimits(request_limit=5),\r\n    )\r\n    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\r\n\r\n# Construye la interfaz\r\nwith gr.Blocks(theme=gr.themes.Soft()) as demo:\r\n    gr.Markdown(\"# Asistente de Gesti\u00f3n de Gastos\")\r\n    gr.Markdown(\"Sube recibos o gastos y haz preguntas sobre tus finanzas.\")\r\n\r\n    with gr.Row():\r\n        with gr.Column(scale=3):\r\n            chatbot = gr.Chatbot(height=500, elem_id=\"chatbot\")\r\n\r\n            with gr.Row():\r\n                msg = gr.MultimodalTextbox(\r\n                    placeholder=\"Sube recibos y haz preguntas...\",\r\n                    file_count=\"multiple\",\r\n                    file_types=[\"image\", \"pdf\"]\r\n                )\r\n                submit_btn = gr.Button(\"Enviar\", variant=\"primary\")\r\n\r\n        with gr.Column(scale=1):\r\n            with gr.Accordion(\"Consejos\", open=False):\r\n                tips_output = gr.Textbox(label=\"Consejos de Gastos\")\r\n\r\n            with gr.Accordion(\"Detalles del Gasto\", open=False):\r\n                expense_output = gr.JSON(label=\"Datos Extra\u00eddos\")\r\n\r\n            with gr.Accordion(\"Archivos\", open=False):\r\n                file_output = gr.Textbox(label=\"Archivos Procesados\")\r\n\r\n    # Configura la funcionalidad del chat\r\n    def respond(message, chat_history, files):\r\n        if message == \"\":\r\n            return \"\", chat_history, \"\", None, \"\"\r\n\r\n        answer, tips, expense, file_info = run_expense_agent(message, files, chat_history)\r\n        chat_history.append((message, answer))\r\n        return \"\", chat_history, tips, expense, file_info\r\n\r\n    submit_btn.click(\r\n        respond,\r\n        inputs=[msg, chatbot],\r\n        outputs=[msg, chatbot, tips_output, expense_output, file_output]\r\n    )\r\n    msg.submit(\r\n        respond,\r\n        inputs=[msg, chatbot],\r\n        outputs=[msg, chatbot, tips_output, expense_output, file_output]\r\n    )\r\n\r\n    gr.Markdown(\"### \u00bfNecesitas ayuda? Prueba preguntando:\")\r\n    gr.Examples(\r\n        [\r\n            \"\u00bfCu\u00e1les son mis gastos totales de este mes?\",\r\n            \"Categoriza este recibo por m\u00ed\",\r\n            \"\u00bfCu\u00e1ndo fue mi \u00faltimo gasto de negocio?\",\r\n            \"Mu\u00e9strame todos los gastos mayores a $100\"\r\n        ],\r\n        inputs=msg\r\n    )\r\n\r\ndemo.launch()\r\n<\/code><\/pre>\n<h4>Interfaz de Uso despu\u00e9s de renderizar<\/h4>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-48472\" src=\"https:\/\/www.hiberus.com\/crecemos-contigo\/wp-content\/uploads\/2025\/03\/image-29.png\" alt=\"\" width=\"4599\" height=\"3115\" srcset=\"https:\/\/www.hiberus.com\/crecemos-contigo\/wp-content\/uploads\/2025\/03\/image-29.png 4599w, https:\/\/www.hiberus.com\/crecemos-contigo\/wp-content\/uploads\/2025\/03\/image-29-300x203.png 300w, https:\/\/www.hiberus.com\/crecemos-contigo\/wp-content\/uploads\/2025\/03\/image-29-1024x694.png 1024w, https:\/\/www.hiberus.com\/crecemos-contigo\/wp-content\/uploads\/2025\/03\/image-29-768x520.png 768w, https:\/\/www.hiberus.com\/crecemos-contigo\/wp-content\/uploads\/2025\/03\/image-29-1536x1040.png 1536w, https:\/\/www.hiberus.com\/crecemos-contigo\/wp-content\/uploads\/2025\/03\/image-29-2048x1387.png 2048w, https:\/\/www.hiberus.com\/crecemos-contigo\/wp-content\/uploads\/2025\/03\/image-29-360x244.png 360w\" sizes=\"auto, (max-width: 4599px) 100vw, 4599px\" \/><\/p>\n<p>La interfaz de uso presenta un dise\u00f1o limpio e intuitivo con un modelo de interacci\u00f3n similar a un chat. Las personas usuarias pueden ingresar f\u00e1cilmente sus gastos a trav\u00e9s de texto o subiendo recibos, mientras que el asistente de IA proporciona retroalimentaci\u00f3n en tiempo real y insights financieros. La interfaz tambi\u00e9n incluye secciones dedicadas para ver consejos de gastos y datos detallados de transacciones.<\/p>\n<h3>10. Pruebas y Despliegue<\/h3>\n<p>Ahora que todo est\u00e1 configurado, puedes ejecutar la aplicaci\u00f3n localmente o desplegarla en una plataforma como <strong>Heroku<\/strong> o <strong>DigitalOcean<\/strong>. La interfaz de Gradio permitir\u00e1 a las personas usuarias ingresar detalles de gastos, y el agente de IA responder\u00e1 con insights y almacenar\u00e1 los datos en <strong>Supabase<\/strong>.<\/p>\n<p>&nbsp;<\/p>\n<p>En este tutorial, hemos creado un sistema funcional de <strong>seguimiento de gastos con IA<\/strong> utilizando <strong>DeepSeek Model<\/strong>, <strong>Gradio<\/strong>, <strong>Pydantic<\/strong>, <strong>Pydantic-AI<\/strong> y <strong>Supabase<\/strong>. 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.<\/p>\n<p>Siguiendo este tutorial, puedes f\u00e1cilmente extender el sistema para agregar m\u00e1s caracter\u00edsticas como seguimiento de presupuesto, gastos recurrentes, y m\u00e1s informaci\u00f3n avanzada.<\/p>\n<p>Gracias por leer, y \u00a1feliz programaci\u00f3n!<\/p>\n<hr \/>\n<p>\u00bfQuieres aprovechar el poder de la IA para impulsar tu negocio? Contamos con un equipo de <a href=\"https:\/\/www.hiberus.com\/data-ia\/ia\" target=\"_blank\" rel=\"noopener\">expertos en <strong>IA Generativa y Data<\/strong><\/a> que ha desarrollado <strong>GenIA Ecosystem<\/strong>, un ecosistema de soluciones propias de IA conversacional, generaci\u00f3n de contenido y data adaptadas a las necesidades de cada mercado y cliente. Cont\u00e1ctanos y estaremos encantados de ayudarte.<\/p>\n        <div class=\"row\">\n            <div class=\"block-cta-form\" style=\"background-color: #003664;\">\n                <div class=\"content-cta-form\">\n                    <div class=\"text-cta-form\">\n                        <p class=\"title-cta-form\">\u00bfQuieres m\u00e1s informaci\u00f3n sobre nuestros servicios de inteligencia artificial?<\/p>\n                        <p>Contacta con nuestro equipo de Data &amp; AI<\/p>\n                    <\/div>\n                    <div class=\"form-fields\">\n                        \n<div class=\"wpcf7 no-js\" id=\"wpcf7-f33973-o1\" lang=\"es-ES\" dir=\"ltr\" data-wpcf7-id=\"33973\">\n<div class=\"screen-reader-response\"><p role=\"status\" aria-live=\"polite\" aria-atomic=\"true\"><\/p> <ul><\/ul><\/div>\n<form action=\"\/crecemos-contigo\/wp-json\/wp\/v2\/posts\/48459#wpcf7-f33973-o1\" method=\"post\" class=\"wpcf7-form init\" aria-label=\"Formulario de contacto\" novalidate=\"novalidate\" data-status=\"init\">\n<fieldset class=\"hidden-fields-container\"><input type=\"hidden\" name=\"_wpcf7\" value=\"33973\" \/><input type=\"hidden\" name=\"_wpcf7_version\" value=\"6.1.5\" \/><input type=\"hidden\" name=\"_wpcf7_locale\" value=\"es_ES\" \/><input type=\"hidden\" name=\"_wpcf7_unit_tag\" value=\"wpcf7-f33973-o1\" \/><input type=\"hidden\" name=\"_wpcf7_container_post\" value=\"0\" \/><input type=\"hidden\" name=\"_wpcf7_posted_data_hash\" value=\"\" \/><input type=\"hidden\" name=\"_wpcf7_recaptcha_response\" value=\"\" \/>\n<\/fieldset>\n<div id=\"responsive-form\" class=\"clearfix\">\n\t<div class=\"form-row\">\n\t\t<div class=\"column-half\">\n\t\t\t<p><span class=\"wpcf7-form-control-wrap\" data-name=\"nombre\"><input size=\"40\" maxlength=\"400\" class=\"wpcf7-form-control wpcf7-text wpcf7-validates-as-required\" aria-required=\"true\" aria-invalid=\"false\" placeholder=\"Nombre *\" value=\"\" type=\"text\" name=\"nombre\" \/><\/span>\n\t\t\t<\/p>\n\t\t<\/div>\n\t\t<div class=\"column-half\">\n\t\t\t<p><span class=\"wpcf7-form-control-wrap\" data-name=\"apellido\"><input size=\"40\" maxlength=\"400\" class=\"wpcf7-form-control wpcf7-text wpcf7-validates-as-required\" aria-required=\"true\" aria-invalid=\"false\" placeholder=\"Apellido *\" value=\"\" type=\"text\" name=\"apellido\" \/><\/span>\n\t\t\t<\/p>\n\t\t<\/div>\n\t<\/div>\n\t<div class=\"form-row\">\n\t\t<div class=\"column-half\">\n\t\t\t<p><span class=\"wpcf7-form-control-wrap\" data-name=\"correo\"><input size=\"40\" maxlength=\"400\" class=\"wpcf7-form-control wpcf7-email wpcf7-validates-as-required wpcf7-text wpcf7-validates-as-email\" aria-required=\"true\" aria-invalid=\"false\" placeholder=\"Correo corporativo *\" value=\"\" type=\"email\" name=\"correo\" \/><\/span>\n\t\t\t<\/p>\n\t\t<\/div>\n\t\t<div class=\"column-half\">\n\t\t\t<p><span class=\"wpcf7-form-control-wrap\" data-name=\"telf-contacto\"><input size=\"40\" maxlength=\"400\" class=\"wpcf7-form-control wpcf7-tel wpcf7-validates-as-required wpcf7-text wpcf7-validates-as-tel\" aria-required=\"true\" aria-invalid=\"false\" placeholder=\"Tel\u00e9fono *\" value=\"\" type=\"tel\" name=\"telf-contacto\" \/><\/span>\n\t\t\t<\/p>\n\t\t<\/div>\n\t<\/div>\n\t<div class=\"form-row\">\n\t\t<div class=\"column-half\">\n\t\t\t<p><span class=\"wpcf7-form-control-wrap\" data-name=\"compania\"><input size=\"40\" maxlength=\"400\" class=\"wpcf7-form-control wpcf7-text wpcf7-validates-as-required\" aria-required=\"true\" aria-invalid=\"false\" placeholder=\"Compa\u00f1ia *\" value=\"\" type=\"text\" name=\"compania\" \/><\/span>\n\t\t\t<\/p>\n\t\t<\/div>\n\t<\/div>\n\t<div class=\"form-row\">\n\t\t<div class=\"column-full\">\n\t\t\t<p><span class=\"wpcf7-form-control-wrap\" data-name=\"mensaje\"><textarea cols=\"40\" rows=\"10\" maxlength=\"2000\" class=\"wpcf7-form-control wpcf7-textarea wpcf7-validates-as-required\" aria-required=\"true\" aria-invalid=\"false\" placeholder=\"Mensaje *\" name=\"mensaje\"><\/textarea><\/span>\n\t\t\t<\/p>\n\t\t<\/div>\n\t<\/div>\n\t<div class=\"form-row\">\n\t\t<div class=\"column-full color-acceptance\">\n\t\t\t<p><span class=\"wpcf7-form-control-wrap\" data-name=\"politica\"><span class=\"wpcf7-form-control wpcf7-acceptance\"><span class=\"wpcf7-list-item\"><label><input type=\"checkbox\" name=\"politica\" value=\"1\" aria-invalid=\"false\" \/><span class=\"wpcf7-list-item-label\">He le\u00eddo y acepto la <a href=\"https:\/\/www.hiberus.com\/politica\" target=\"_blank\"><u>Pol\u00edtica de privacidad<\/u><\/a><\/span><\/label><\/span><\/span><\/span>\n\t\t\t<\/p>\n\t\t<\/div>\n\t<\/div>\n\t<div class=\"form-row\">\n\t\t<div class=\"column-full color-acceptance\">\n\t\t\t<p><span class=\"wpcf7-form-control-wrap\" data-name=\"marketing\"><span class=\"wpcf7-form-control wpcf7-acceptance optional\"><span class=\"wpcf7-list-item\"><label><input type=\"checkbox\" name=\"marketing\" value=\"1\" aria-invalid=\"false\" \/><span class=\"wpcf7-list-item-label\">Me gustar\u00eda recibir comunicaciones de marketing de Hiberus y sobre sus productos, servicios y eventos.<\/span><\/label><\/span><\/span><\/span>\n\t\t\t<\/p>\n\t\t<\/div>\n\t<\/div>\n\t<div class=\"form-row\">\n\t\t<div class=\"column-half\">\n\t\t\t<p><input class=\"wpcf7-form-control wpcf7-submit has-spinner\" type=\"submit\" value=\"Contacta con nosotros\" \/>\n\t\t\t<\/p>\n\t\t<\/div>\n\t<\/div>\n\t<div class=\"form-row\">\n\t\t<div id=\"campos_ocultos\" class=\"hidden\">\n\t\t\t<p><span class=\"wpcf7-form-control-wrap\" data-name=\"oculto_analitica_new1\"><input size=\"40\" maxlength=\"400\" class=\"wpcf7-form-control wpcf7-text\" id=\"oculto_analitica_new1\" aria-invalid=\"false\" value=\"\" type=\"text\" name=\"oculto_analitica_new1\" \/><\/span><br \/>\n<span class=\"wpcf7-form-control-wrap\" data-name=\"oculto_analitica_new2\"><input size=\"40\" maxlength=\"400\" class=\"wpcf7-form-control wpcf7-text\" id=\"oculto_analitica_new2\" aria-invalid=\"false\" value=\"\" type=\"text\" name=\"oculto_analitica_new2\" \/><\/span><br \/>\n<span class=\"wpcf7-form-control-wrap\" data-name=\"oculto_analitica_new3\"><input size=\"40\" maxlength=\"400\" class=\"wpcf7-form-control wpcf7-text\" id=\"oculto_analitica_new3\" aria-invalid=\"false\" value=\"\" type=\"text\" name=\"oculto_analitica_new3\" \/><\/span><br \/>\n<span class=\"wpcf7-form-control-wrap\" data-name=\"oculto_analitica_new4\"><input size=\"40\" maxlength=\"400\" class=\"wpcf7-form-control wpcf7-text\" id=\"oculto_analitica_new4\" aria-invalid=\"false\" value=\"\" type=\"text\" name=\"oculto_analitica_new4\" \/><\/span><br \/>\n<span class=\"wpcf7-form-control-wrap\" data-name=\"oculto_analitica_new_p\"><input size=\"40\" maxlength=\"400\" class=\"wpcf7-form-control wpcf7-text\" id=\"oculto_analitica_new_p\" aria-invalid=\"false\" value=\"\" type=\"text\" name=\"oculto_analitica_new_p\" \/><\/span>\n\t\t\t<\/p>\n\t\t<\/div>\n\t<\/div>\n<\/div>\n\n<!--end responsive-form--><div class=\"wpcf7-response-output\" aria-hidden=\"true\"><\/div>\n<\/form>\n<\/div>\n                    <\/div>\n                <\/div>\n            <\/div>\n        <\/div>\n        \n<p><!-- notionvc: 55b06b11-6246-4d76-ac22-f2cfea23b223 --><\/p>\n<p><!-- notionvc: ebca43d1-6460-4826-935c-a7d510be1342 --><\/p>\n","protected":false},"excerpt":{"rendered":"<p>\u00bfAlguna vez te has preguntado c\u00f3mo aprovechar la IA para rastrear tus gastos de manera sencilla? Soy Abbaoui Achraf, ingeniero de machine&#8230;<\/p>\n","protected":false},"author":426,"featured_media":48477,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"_ayudawp_aiss_exclude":false,"footnotes":""},"categories":[236,7],"tags":[156],"class_list":{"0":"post-48459","1":"post","2":"type-post","3":"status-publish","4":"format-standard","5":"has-post-thumbnail","7":"category-data-ia","8":"category-next-tech","9":"tag-inteligencia-artificial"},"acf":[],"_links":{"self":[{"href":"https:\/\/www.hiberus.com\/crecemos-contigo\/wp-json\/wp\/v2\/posts\/48459","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.hiberus.com\/crecemos-contigo\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.hiberus.com\/crecemos-contigo\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.hiberus.com\/crecemos-contigo\/wp-json\/wp\/v2\/users\/426"}],"replies":[{"embeddable":true,"href":"https:\/\/www.hiberus.com\/crecemos-contigo\/wp-json\/wp\/v2\/comments?post=48459"}],"version-history":[{"count":13,"href":"https:\/\/www.hiberus.com\/crecemos-contigo\/wp-json\/wp\/v2\/posts\/48459\/revisions"}],"predecessor-version":[{"id":48566,"href":"https:\/\/www.hiberus.com\/crecemos-contigo\/wp-json\/wp\/v2\/posts\/48459\/revisions\/48566"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.hiberus.com\/crecemos-contigo\/wp-json\/wp\/v2\/media\/48477"}],"wp:attachment":[{"href":"https:\/\/www.hiberus.com\/crecemos-contigo\/wp-json\/wp\/v2\/media?parent=48459"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.hiberus.com\/crecemos-contigo\/wp-json\/wp\/v2\/categories?post=48459"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.hiberus.com\/crecemos-contigo\/wp-json\/wp\/v2\/tags?post=48459"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}