- Gerar link
- X
- Outros aplicativos
- Gerar link
- X
- Outros aplicativos
Melhorando Seu Assistente Financeiro Pessoal: Registre Despesas usando IA
Tempo de leitura: 7 minutos
Criamos um Bot Telegram com o objetivo de ser nosso assistente financeiro pessoal nessa tarefa de gerenciar nosso dinheiro. Até então, ele aceita comandos para registrar despesas e receitas, listar os últimos registros e até fazer um diagnóstico e nos oferecer insights para melhorar a gestão do nosso dinheiro. Se você não acompanhou, pode voltar aos posts:
Neste artigo vamos implementar uma funcionalidade que vai facilitar ainda mais nossa tarefa. Vamos enviar uma mensagem informando o valor da transação e a que se refere esse valor. A Inteligência Artificial irá então analisar a mensagem e inferir uma transação a ser lançada na planilha. Dessa maneira não se faz necessário fazermos um registro de transação estruturada como exige o comando /save.
A nova função
No código do Bot apresentado ao final deste post, acrescente as novas linhas conforme mostrado a seguir:
from dotenv import load_dotenv # Acrescentar este import import json import os import logging import pandas as pd from datetime import date from utils import ( conectar_google_sheets, normalizar_string, validar_chat_id) from telegram import Update from telegram.ext import ( ApplicationBuilder, CommandHandler, ContextTypes, # Acrescentar este import MessageHandler, filters) from openai import OpenAI # Restante do código igual ao do post anterior # Acrescentar esta função async def interpretar(update, context): mensagem = update.message.text # Chama IA para extrair informação try: resposta = client.chat.completions.create( model="gpt-3.5-turbo", messages=[ { "role": "system", "content": """Você é um sistema de categorização de transações financeiras. Responda APENAS em formato JSON válido, sem explicações adicionais.""" }, { "role": "user", "content": f"""Extraia da frase abaixo: - valor (float, usar . como separador decimal) - tipo: "Receita" ou "Despesa" - categoria (uma palavra) - data (DD/MM/YYYY; se não informado, usar {date.today().strftime("%d/%m/%Y")}) Frase: "{mensagem}" Retorne APENAS JSON, exemplo: {{"valor": 58,.0, "tipo": "Despesa", "categoria": "Alimentacao", "data": "28/11/2025"}}""" } ], max_tokens=200, temperature=0.3 ) texto = resposta.choices[0].message.content.strip() except Exception as e: logger.exception("Erro chamando OpenAI") await update.message.reply_text(f"Erro na API de IA: {e}") return # Extrair JSON do texto try: start = texto.find("{") end = texto.rfind("}") + 1 if start == -1 or end == 0: raise ValueError("Nenhum JSON encontrado na resposta") json_text = texto[start:end] dados = json.loads(json_text) valor = float(dados["valor"]) tipo = dados["tipo"].capitalize() categoria = dados["categoria"].capitalize() data_str = dados.get("data", date.today().isoformat()).strip() # Validar e normalizar data try: data_obj = pd.to_datetime( data_str, format="%d/%m/%Y", errors='coerce') if pd.isna(data_obj): data = date.today().strftime("%d/%m/%Y") else: data = data_obj.strftime("%d/%m/%Y") except Exception as e: logger.exception("Erro ao parsear data: %s", e) data = date.today().strftime("%d/%m/%Y") except Exception as e: logger.exception("Erro ao parsear resposta da IA") await update.message.reply_text( f"Não consegui interpretar. Erro: {e}\nResposta: {texto[:500]}" ) return try: sheet = abrir_planilha() # Adiciona uma nova linha na planilha com os dados extraídos sheet.append_row( [ data, "", categoria, valor, tipo, ] ) await update.message.reply_text( f"📌 Registrado!\n\n" f"Tipo: {tipo}\n" f"Categoria: {categoria}\n" f"Valor: R$ {valor:,.2f}\n" f"Data: {data}" ) except Exception as e: logger.exception("Erro ao salvar na planilha") await update.message.reply_text(f"Erro ao salvar na planilha: {e}")
E vamos então analisar a função interpretar(), responsável por extrair os dados de uma mensagem enviada em linguagem natural.
Inicialmente, lemos a mensagem enviada ao Bot. Em seguida montamos um prompt para enviar essa mensagem à IA. Note o contexto no prompt e que pedimos quais dados devem ser extraídos. Ainda é solicitado que esses dados sejam retornados em formato json. É importante observar que, mesmo que tenhamos pedido que a IA retorne apenas json, não há garantia que a resposta será assim. Por isso precisamos tratar adequadamente a resposta.
Observe que podemos enviar uma mensagem com uma data passada, para o caso de termos esquecido de fazer um registro. Mas se não enviarmos a data na mensagem, pedimos à IA que considere o lançamento na data corrente.
A fim de extrair o json da resposta, primeiro buscamos as chaves {}, que envolvem um json. Isso irá garantir que existe um json no texto da resposta e que iremos tratar apenas ele. Daí lemos as chaves fundamentais do nosso registro, que são a data, o valor, a categoria e o tipo.
Lidos esses dados, fazemos o lançamento na planilha. Faça vários testes com a IA, enviando mensagens com dados em ordem diferente, data em vários formatos, a fim de confirmar se o modelo irá tratá-las adequadamente.
Finalmente, para adicionar a função ao bot, inclua a seguinte linha à sequencia de app.add_handler() que já existem no método main().
app.add_handler( MessageHandler(authorized_only & filters.TEXT & ~filters.COMMAND, interpretar))
Implementando autorização de uso
Até então não abordamos o tema autorização, que trata de como o bot lida com o acesso de pessoas que não tem permissão para usar os recursos disponíveis. Isso é importante, visto que se trata de um bot de uso pessoal. Ele manipula uma planilha Google Sheets de uso pessoal, e, sendo o bot de acesso público, é fundamental tratar essa questão.
No código do nosso bot nós utilizamos o módulo filters, o qual permite que o bot decida qual mensagem ou comando ele deve tratar. Existem filtros nativos da biblioteca e filtros personalizados, que podem ser criados pelo desenvolvedor.
Neste caso, optamos por um filtro personalizado. Mas a biblioteca oferece filters.User(), que permite ao bot tratar mensagens ou comandos de usuários especificados, tanto pelo ID quanto pelo username.
No filtro que fizemos, foi criada uma lista de IDs de usuários autorizados, a qual mantemos no arquivo .env. Então, sempre que o usuário envia uma mensagem ao bot, o filtro executa e verifica de o ID do uauário pertence a essa lista. Veja como está implementado o filtro:
CHAT_ID_LIST = ast.literal_eval(os.getenv("CHAT_ID_LIST", "[]")) OPENAI_API_KEY = os.getenv("OPENAI_API_KEY") client = OpenAI(api_key=OPENAI_API_KEY) # Filtro customizado para validação de chat_id class AuthorizedOnlyFilter(filters.MessageFilter): def filter( self, update: Update) -> bool: if not update or not update.from_user: return False chat_id = update.from_user.id return chat_id in CHAT_ID_LIST # Instanciar uma única vez authorized_only = AuthorizedOnlyFilter()
O filtro é criado como uma subclasse de filters.MessageFilter na sobrescrevemos o método filter(). Nesse método, se o ID do usuário não pertencer à lista, ele retorna False, e a mensagem não é tratada pelo bot.
Criada a classe, nós a instanciamos. E é essa instância que é passada como parâmetro na criação dos handlers de comandos e mensagens no método main():
app.add_handler( CommandHandler( "start", start, filters=authorized_only)) app.add_handler( CommandHandler("help", help_command, filters=authorized_only)) app.add_handler( CommandHandler("save", save_command, filters=authorized_only)) app.add_handler( CommandHandler( "last", print_last_transactions, filters=authorized_only)) app.add_handler( CommandHandler( "diagnostic", diagnostic_command, filters=authorized_only)) app.add_handler( MessageHandler( authorized_only & filters.TEXT & ~filters.COMMAND, interpretar))
Confira o código completo no GitHub.
Conclusão
Agora o nosso assistente financeiro aceita registro de despesas por meio do comando /save, usando dados estruturados, ou por meio de uma mensagem em linguagem natural, onde a IA interpreta a mensagem, infere os dados e efetiva o lançamento na planilha Google Sheets.
Essa funcionalidade pode ser melhorada, se definirmos um conjunto de categorias nas quais as depesas podem ser lançadas. Essa função vamos deixar para você implementar.
- Gerar link
- X
- Outros aplicativos

Comentários