Seu Assistente Financeiro Pessoal no Telegram: Integrando IA ao Bot do Google Sheets
Criar um assistente financeiro pessoal pode ser um grande desafio. Mas com a combinação de Python, Telegram Bot API, Google Sheets e OpenAI, você pode construir uma ferramenta capaz de analisar despesas e receitas, organizar planilhas, gerar diagnósticos financeiros automáticos usando IA e até ajudar outras pessoas a cuidar do dinheiro.
Neste artigo, você vai aprender passo a passo como integrar uma Inteligência Artificial ao bot de Telegram criado no post anterior, a qual será capaz de atuar como um verdadeiro assistente financeiro.
![]() |
| Fonte: https://br.freepik.com/ |
Pré-requisitos
- Recomendamos que você já tenha criado o Bot Telegram descrito neste post
- Bibliotecas pandas e openai
- Conta na OpenAI
Considerando que vamos partir do código funcionando, criado no artigo anterior, será necessário instalar as bibliotecas:
pip install openai pandas
![]() |
| Dashboard da OpenAI Platform |
Clique no botão Create new secret key no canto superior direito. Opcionalmente, você pode dar um nome à sua chave para identificação (ex: "Meu Projeto BOT") e, em seguida, clique em Create key. O seu token (chave secreta) será exibido em uma janela. Copie-o imediatamente e guarde-o em um local seguro, pois, por motivos de segurança, você não conseguirá vê-lo novamente depois de fechar a janela.
A utilização da API da OpenAI geralmente envolve custos baseados no uso (pago por token/uso), e pode ser necessário adicionar um método de pagamento à sua conta para utilizar os serviços. Por exemplo, cerca de 1.000 tokens pode ter um custo $ 0.50, dependendo do modelo utilizado. Para saber mais sobre como os tokens são contados e precificados leia aqui.
Um pouco mais sobre segurança
Num post anterior introduzimos a utilização de dotenv para guardar as chaves secretas. Esse será o mecanismo utilizado também para guardar nossa chave da API da OpenAI. Neste upgrade do nosso bot vamos passar a guardar as credenciais da conta de serviço do Google Cloud que aprendemos a criar neste artigo, também no arquivo .env.
A dica consiste em criar uma chave no .env, por exemplo:
CREDENCIAIS_GOOGLE_SHEETS={"type": "service_account", "project_id": "xxxxxxxxxxxxxxxxxxxxxx", "private_key_id": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx","private_key": "-----BEGIN PRIVATE KEY-----"}
O nome da chave pode ser qualquer um, e o valor é o conteúdo do arquivo json que você baixou quando criou a chave. Sendo que o conteúdo deve estar em forma de string json. Para isso ponha o conteúdo em uma única linha.
Agora precisamos modificar o arquivo utils.py que foi criado no post anterior.
utils.py
CREDENCIAIS = os.getenv("CREDENCIAIS_GOOGLE_SHEETS") def conectar_google_sheets(): scopes = [ "https://www.googleapis.com/auth/spreadsheets", "https://www.googleapis.com/auth/drive", ] # creds = Credentials.from_service_account_file( # "credenciais.json", scopes=scopes) json_credencials = json.loads(CREDENCIAIS) creds = Credentials.from_service_account_info( json_credencials, scopes=scopes) client = gspread.authorize(creds) return client
Note que incluimos uma linha que obtém CREDENCIAIS do arquivo .env e, na função conectar_google_sheets(), substituimos a linha que define creds. Antes ela precisava ler o arquivo credenciais.json e agora utilizamos json.loads() para converter a string CREDENCIAIS em json e definimos creds para buscar as informações desse json.
O que vamos criar
Iremos incluir o comando /diagnostic ao código do Bot Telegram criado no artigo anterior, o qual será responsável por receber a planilha de transações, gerar um resumo e com base nesse resumo, a IA irá fazer, por meio de um relatório, um diagnóstico e propor algumas recomendações para economizar, reduzir despesas, etc.
O resumo financeiro
O resumo será gerado por meio da função gerar_resumo_financeiro(), que recebe como parâmetro a planilha de transações convertida em um Dataframe, o que possibilita um tratamento de dados mais facilitado.
# Outros imports aqui import panda as pd # Algum código aqui def gerar_resumo_financeiro(df: pd.DataFrame) -> dict: """ Espera colunas: ['Data','Descrição','Categoria','Tipo','Valor', ...] Tipo é 'Receita' ou 'Despesa' (case-insensitive) """ df = df.copy() # garantir colunas mínimas required = ['Data', 'Descrição', 'Categoria', 'Tipo', 'Valor'] # tentar mapear colunas sem acento # assume que o usuário usou cabeçalhos corretos for col in required: if col not in df.columns: raise ValueError( f"A coluna obrigatória '{col}' não foi encontrada na planilha." ) # converter tipos df['Valor'] = pd.to_numeric(df['Valor'], errors='coerce').fillna(0.0) df['Tipo'] = df['Tipo'].astype(str).str.strip().str.capitalize() # garantir datas try: df['Data'] = pd.to_datetime(df['Data'], dayfirst=True, errors='coerce') except Exception: df['Data'] = pd.to_datetime(df['Data'], errors='coerce') # calcular métricas básicas receitas = df.loc[df['Tipo'] == 'Receita', 'Valor'].sum() despesas = df.loc[df['Tipo'] == 'Despesa', 'Valor'].sum() saldo = receitas - despesas taxa_poupanca_pct = (saldo / receitas * 100) if receitas != 0 else 0.0 # distribuição por categoria (somente despesas) despesas_por_cat = ( df.loc[df['Tipo'] == 'Despesa'] .groupby('Categoria')['Valor'] .sum() .sort_values(ascending=False) .to_dict() ) # dívida detectada: categoria chamada 'Dívidas' ou 'Dividas' dividas = 0.0 for key in ['Dívidas', 'Dividas', 'Divida', 'Dívida']: if key in df['Categoria'].unique(): dividas += df.loc[ (df['Categoria'] == key) & (df['Tipo'] == 'Despesa'), 'Valor' ].sum() resumo = { "receitas": round(float(receitas), 2), "despesas": round(float(despesas), 2), "saldo": round(float(saldo), 2), "taxa_poupanca_pct": round(float(taxa_poupanca_pct), 2), "despesas_por_categoria": {str(k): float(v) for k, v in despesas_por_cat.items()}, "dividas": round(float(dividas), 2), "periodo_inicio": str(df['Data'].min()) if not df['Data'].isnull().all() else None, "periodo_fim": str(df['Data'].max()) if not df['Data'].isnull().all() else None, } return resumo
Antes de criar o resumo, a função checa se a planilha tem as colunas obrigatórias. Não importa a ordem, se estão em maiúsculas ou não ou se possuem acentuação.
Em seguida é feita a conversão de tipos, tanto os numéricos quanto as strings, e a formatação adequada das datas. Tudo isso para assegurar a criação do resumo, visto que, por exemplo, será necessário totalizar cada categoria, e isso exige que cada uma delas tenha denominação padronizada na planilha inteira.
Finalmente, a função cria e retorna o resumo na forma de um dict.
O prompt
O prompt que será enviado ao modelo é montado na função montar_prompt_para_openai(). A função recebe o resumo criado na função anterior e o envia no prompt. Note que o prompt é bastante específico, detalhando o que se quer da IA. No entanto não é um texto fechado, você sempre pode e deve melhorá-lo.
def montar_prompt_para_openai(resumo: dict) -> str: # Template em PT-BR para o modelo receber e gerar diagnóstico prompt = f""" Você é um especialista em finanças pessoais. Analise o resumo financeiro abaixo e gere um relatório de diagnóstico completo, claro e motivador. Divida o relatório em: Visão geral, Principais pontos de atenção, Oportunidades de economia, Plano de ação (3 a 5 passos) e Recomendação de produtos/contas para reserva de emergência. Seja prático e dê números concretos (valores em reais e percentuais). Resumo financeiro (auto-gerado): - Período: {resumo.get('periodo_inicio')} até {resumo.get('periodo_fim')} - Receitas totais: R$ {resumo.get('receitas'):.2f} - Despesas totais: R$ {resumo.get('despesas'):.2f} - Saldo: R$ {resumo.get('saldo'):.2f} - Taxa de poupança (% sobre a receita): {resumo.get('taxa_poupanca_pct'):.2f}% - Dívidas identificadas (valor): R$ {resumo.get('dividas'):.2f} - Distribuição das maiores categorias de despesa: {resumo.get('despesas_por_categoria')} Dê recomendações específicas com valores (ex.: "reduza X na categoria Y, isso economiza R$ Z por mês") e proponha metas (ex.: reserva de emergência equivalente a N meses de despesas). """ return prompt
A função retorna então esse prompt detalhado, o qual contém informações do resumo.
O comando /diagnostic
O primeiro passo na função diagnostic_command() é conectar ao Google Sheets e ler a planilha alvo no formato de um list de dict. Em seguida, por meio de pd.DataFrame(), converter esse list em um DataFrame.
async def diagnostic_command( update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: cliente = conectar_google_sheets() planilha = cliente.open("Minhas Finanças Pessoais") sheet = planilha.worksheet("Transações") registros = sheet.get_all_records() df = pd.DataFrame(registros) try: resumo = gerar_resumo_financeiro(df) except Exception as e: logger.exception("Erro no resumo financeiro") await update.message.reply_text(f"Erro ao processar os dados: {e}") return prompt = montar_prompt_para_openai(resumo) # chamada básica para OpenAI (Chat Completions) try: response = client.chat.completions.create( model="gpt-3.5-turbo", messages=[ {"role": "developer", "content": """Você é um assistente especialista em finanças pessoais."""}, {"role": "user", "content": prompt} ], max_tokens=800, temperature=0.3) texto_relatorio = response.choices[0].message.content.strip() except Exception as e: logger.exception(f"Erro chamando OpenAI {e}") await update.message.reply_text( f"Erro ao gerar o relatório via OpenAI {e}") texto_relatorio = ( "Relatório automático (fallback):\n\n" f"Receitas: R$ {resumo['receitas']}\n" f"Despesas: R$ {resumo['despesas']}\n" f"Saldo: R$ {resumo['saldo']}\n" f"Taxa poupança: {resumo['taxa_poupanca_pct']}%\n" ) # enviar resultados # primeiro um resumo curto resumo_msg = ( f"✅ Diagnóstico pronto!\n\n" f"Receitas: R$ {resumo['receitas']:.2f}\n" f"Despesas: R$ {resumo['despesas']:.2f}\n" f"Saldo: R$ {resumo['saldo']:.2f}\n" f"Taxa de poupança: {resumo['taxa_poupanca_pct']:.2f}%\n\n" "Relatório completo em anexo (PDF) e abaixo em texto." ) await update.message.reply_text(resumo_msg) await update.message.reply_text(texto_relatorio)
A seguir é chamada a função gerar_resumo_financeiro() passando o DataFrame como argumento. Esta função retorna o resumo, o qual é passado para a função montar_prompt_para_openai(). Esta função retorna o prompt montado.
Com o prompt disponível, é chamada a função client.chat.completions.create(). Esta função é uma chamada à API da OpenAI, que pode interagir com vários modelos da família GPT, bastando especificá-lo no parâmetro model. Além do parâmetro model, é obrigatório o envio de messages, que é uma lista das mensagens da conversa. Messages deverá ter um item de developer e outro de user, no qual passamos o prompt que foi montado antes. O parâmetro max_tokens é usado para controlar os custos das respostas. Por sua vez, temperature determina a aleatoriedade da resposta. Quanto menor o valor, mais focada é a resposta. Seu valor deve estar em 0 e 2.
Para finalizar, o handler do comando /diagnostic é registrado no bot.
Código completo disponível no GitHub.
Conclusão
Agora temos um bot pessoal no Telegram, que facilita o trabalho de lançar as transações na planilha e se integra a uma Inteligência Artificial para, com base nessa planilha, fazer uma análise desses dados e fornecer recomendações a fim de aprimorarmos a getão das nossas finanças.
Esse código é apenas um ponto de partida. Uma das melhorias que podemos implementar é pedir à nossa IA fazer o lançamento na planilha a partir de uma mensagem não estruturada. Por exemplo, podemos ter o comando /register paguei 150,00 num almoço e 30,00 em cervejas. E a partir disso modelo infere categorias, descrições, valores, etc.


Comentários