Automatizando o Planejamento de Metas com IA e Google Apps Script

Automatizando o Planejamento de Metas com IA e Google Apps Script

No post anterior, você aprendeu como a IA pode ajudar a definir metas financeiras realistas e recebeu uma planilha no Google Sheets para colocar esse planejamento em prática. Hoje vamos um passo além: vamos fazer a própria planilha chamar a IA automaticamente e escrever a análise para você — tudo com um clique, usando Google Apps Script e a API da OpenAI.

Fonte: https://br.freepik.com/

O que vamos construir

Ao final deste tutorial, sua planilha terá um menu customizado 🤖 Análise IA que, ao ser acionado, vai:

  • Ler seus dados financeiros do mês (receitas, despesas, objetivos e metas)
  • Montar um prompt contextualizado com essas informações
  • Enviar esse prompt para o modelo gpt-4o (ou outro modelo de sua preferência) via API
  • Escrever os resultados diretamente na aba IA_Analises da planilha, nas linhas de Resumo mensal, Alertas e Sugestões

Pré-requisitos

  • A planilha do post anterior (se ainda não tem, baixe aqui)
  • Uma conta na OpenAI Platform com créditos disponíveis
  • Conhecimento básico de JavaScript — o Apps Script usa uma variante dele

Obtendo sua chave da API

Acesse platform.openai.com/api-keys, crie uma nova chave e guarde-a em um lugar seguro. Você vai usá-la em instantes.

Neste post mostramos em detalhes como obter sua chave da API OpenAI.

Atenção: nunca exponha sua API key em código compartilhado ou versionado. Mais abaixo mostramos como armazená-la de forma segura usando o PropertiesService do próprio Apps Script.

Acessando o Apps Script

Na sua planilha, vá em Extensões → Apps Script. O editor será aberto em uma nova aba. Apague qualquer código padrão que estiver lá e cole o código abaixo.

O Código Completo

//  CONFIG — use PropertiesService em produção (veja abaixo)

const OPENAI_API_KEY = PropertiesService.getScriptProperties().getProperty("OPENAI_API_KEY");
const OPENAI_MODEL   = "gpt-4o";

//  MENU CUSTOMIZADO

function onOpen() {
  SpreadsheetApp.getUi()
    .createMenu("🤖 Análise IA")
    .addItem("Analisar minhas metas", "analisarMetas")
    .addToUi();
}

//  FUNÇÃO PRINCIPAL

function analisarMetas() {
  const ss = SpreadsheetApp.getActiveSpreadsheet();

  const config    = lerAbaComoObjeto(ss, "Configurações");
  const resumo    = lerAbaComoObjeto(ss, "Resumo_Mensal");
  const objetivos = lerAbaComoTabela(ss, "Objetivos");
  const metas     = lerAbaComoTabela(ss, "Metas_Mensais");

  const prompt  = montarPrompt(config, resumo, objetivos, metas);
  const resposta = chamarOpenAI(prompt);

  if (!resposta) {
    SpreadsheetApp.getUi().alert("Erro ao chamar a API da OpenAI. Verifique os logs.");
    return;
  }

  escreverAnalises(ss, resposta);
  SpreadsheetApp.getUi().alert("✅ Análise concluída! Veja a aba IA_Analises.");
}

//  HELPERS DE LEITURA

function lerAbaComoObjeto(ss, nomeAba) {
  const aba  = ss.getSheetByName(nomeAba);
  if (!aba) return {};
  const dados = aba.getDataRange().getValues();
  const obj   = {};
  dados.forEach(([campo, valor]) => { if (campo) obj[campo] = valor; });
  return obj;
}

function lerAbaComoTabela(ss, nomeAba) {
  const aba = ss.getSheetByName(nomeAba);
  if (!aba) return [];
  const dados     = aba.getDataRange().getValues();
  const cabecalho = dados[0];
  return dados.slice(1)
    .filter(linha => linha.some(cel => cel !== "" && cel !== 0))
    .map(linha => {
      const obj = {};
      cabecalho.forEach((col, i) => { obj[col] = linha[i]; });
      return obj;
    });
}

//  MONTAGEM DO PROMPT

function montarPrompt(config, resumo, objetivos, metas) {
  const objetivosTexto = objetivos.length
    ? objetivos.map(o =>
        `- ${o["Objetivo"]} | Tipo: ${o["Tipo"]} | Prioridade: ${o["Prioridade"]} | ` +
        `Valor: R$ ${o["Valor total"]} | Prazo: ${o["Prazo (meses)"]} meses | Status: ${o["Status"]}`
      ).join("\n")
    : "Nenhum objetivo cadastrado.";

  const metasTexto = metas.length
    ? metas.map(m =>
        `- ${m["Objetivo"]}: Ideal R$ ${m["Valor ideal"]} | Mínimo R$ ${m["Valor mínimo"]} | ` +
        `Sugerido R$ ${m["Valor sugerido"]} | Realizado R$ ${m["Valor realizado"]} | ` +
        `Diferença R$ ${m["Diferença"]}`
      ).join("\n")
    : "Nenhuma meta mensal cadastrada.";

  return `
Você é um consultor financeiro pessoal especializado em planejamento de metas.
Analise os dados financeiros abaixo e responda EXCLUSIVAMENTE no seguinte formato JSON:

{
  "resumo_mensal": "texto corrido com análise geral do mês",
  "alertas": "texto corrido com alertas sobre riscos ou desvios identificados",
  "sugestoes": "texto corrido com sugestões práticas e priorizadas"
}

=== DADOS DO USUÁRIO ===

Perfil: ${config["Perfil financeiro"] || "Não informado"}
Período: ${config["Mês/Ano"] || "Não informado"}
Renda total: R$ ${config["Renda total"] || 0}
Limite de comprometimento: ${config["Limite comprometimento (%)"] || 0}%
Meta mínima de poupança: ${config["Meta mínima (%)"] || 0}%

Resumo do mês:
- Total de Receitas: R$ ${resumo["Total de Receitas"] || 0}
- Total de Despesas: R$ ${resumo["Total de Despesas"] || 0}
- Saldo do Mês: R$ ${resumo["Saldo do Mês"] || 0}
- % da Renda Comprometida: ${resumo["% da Renda Comprometida"] || 0}
- Capacidade para Metas: R$ ${resumo["Capacidade para Metas"] || 0}

Objetivos cadastrados:
${objetivosTexto}

Metas mensais:
${metasTexto}

Responda apenas o JSON, sem markdown, sem explicações fora do JSON.
  `.trim();
}

//  CHAMADA À API DA OPENAI

function chamarOpenAI(prompt) {
  const url     = "https://api.openai.com/v1/chat/completions";
  const payload = {
    model: OPENAI_MODEL,
    messages: [{ role: "user", content: prompt }],
    temperature: 0.7,
    response_format: { type: "json_object" }
  };

  const options = {
    method: "post",
    contentType: "application/json",
    headers: { Authorization: `Bearer ${OPENAI_API_KEY}` },
    payload: JSON.stringify(payload),
    muteHttpExceptions: true
  };

  try {
    const response = UrlFetchApp.fetch(url, options);
    const json     = JSON.parse(response.getContentText());
    if (json.error) {
      console.error("Erro OpenAI:", json.error.message);
      return null;
    }
    return JSON.parse(json.choices[0].message.content);
  } catch (e) {
    console.error("Exceção:", e.message);
    return null;
  }
}

//  ESCRITA NA ABA IA_Analises

function escreverAnalises(ss, resposta) {
  const aba   = ss.getSheetByName("IA_Analises");
  if (!aba) return;
  const dados = aba.getDataRange().getValues();
  dados.forEach((linha, i) => {
    const tipo = linha[0];
    if (tipo === "Resumo mensal")   aba.getRange(i + 1, 2).setValue(resposta.resumo_mensal || "");
    if (tipo === "Alertas")         aba.getRange(i + 1, 2).setValue(resposta.alertas       || "");
    if (tipo === "Sugestões")       aba.getRange(i + 1, 2).setValue(resposta.sugestoes     || "");
  });
}

Armazenando a chave com segurança

Em vez de colocar a API key da OpenAI diretamente no código, use o PropertiesService. Execute a função abaixo uma única vez pelo editor do Apps Script e depois a apague:

function salvarChave() {
  PropertiesService.getScriptProperties().setProperty("OPENAI_API_KEY", "sk-SUA_CHAVE_AQUI");
}

Se preferir pode usar o menu do projeto para armazenar a chave, assim como fizemos no post Como Integrar ChatGPT com Google Sheets usando Google Apps Script.

A partir daí, o código já busca a chave automaticamente com o código PropertiesService.getScriptProperties().getProperty("OPENAI_API_KEY") — sem risco de exposição acidental.

Entendendo o fluxo

Vale a pena detalhar o que acontece por baixo dos panos quando o leitor clica no menu 🤖 Análise IA:

  1. Leitura dos dados — as funções lerAbaComoObjeto e lerAbaComoTabela transformam os dados das abas em objetos JavaScript simples, filtrando linhas vazias automaticamente.
  2. Montagem do prompt — a função montarPrompt injeta esses dados em um prompt estruturado que instrui o modelo a responder apenas em JSON, evitando texto livre que quebraria o parse, o processo de converter os dados recebidos.
  3. Chamada à APIUrlFetchApp.fetch é o equivalente do fetch nativo no ambiente do Apps Script. O parâmetro response_format: { type: "json_object" } garante que o gpt-4o sempre retorne um JSON válido.
  4. Escrita dos resultados — a função escreverAnalises percorre a aba IA_Analises procurando as linhas pelo valor da coluna A ("Resumo mensal", "Alertas", "Sugestões") e escreve o conteúdo correspondente na coluna B.

Resultado esperado

Após clicar em 🤖 Análise IA → Analisar minhas metas, a aba IA_Analises da planilha será preenchida automaticamente com três análises textuais geradas pelo gpt-4o com base nos seus dados reais do mês.

Próximos passos possíveis

Se quiser evoluir esse projeto, algumas ideias:
  • Histórico de análises — salvar cada análise na aba Historico com data e timestamp
  • Trigger automático — configurar um gatilho para a análise rodar todo dia 1º do mês sem intervenção manual
  • Análise do Simulador — incluir os dados da aba Simulador no prompt para que a IA avalie cenários de variação de renda e despesas
Ficou com dúvida ou quer sugerir uma melhoria? Deixa nos comentários!

Comentários