Como Integrar ChatGPT com Google Sheets usando Google Apps Script

Como Integrar ChatGPT com Google Sheets usando Google Apps Script

Vimos no post anterior como integrar ChatGPT com Google Sheets utilizando uma extensão. Ao usar uma extensão ficamos limitados às funções que a ferramenta oferece, e isso pode não ser o melhor dos mundos ao criar uma planilha.

Neste artigo iremos introduzir uma alternativa ao uso de extensões. Vamos programar nossas próprias funções, adequando-as às nossas necessidades. Para isso usaremos o Apps Script, uma plataforma JavaScript baseada na nuvem com a tecnologia Google Drive que permite integração e automação de tarefas nos produtos do Google, não apenas no Sheets.

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

Pré-requisitos

Será necessário que você tenha um token da API OpenAI. Neste artigo nós mostramos como obtê-lo. Reforçando que o uso desta API tem um custo e devemos estar cientes disso.

É necessário conhecimento de JavaScript. Não está no escopo deste post introduzir o leitor nesta linguagem. Se for necessário estudar os fundamentos de JavaScript, recomendo o tutorial da W3School.

O que será criado

Vamos criar uma função personalizada no Google Sheets, que usa o ChatGPT para extrair dados de uma transação informada pelo usuário na forma textual. Por exemplo: 98 reais remédios. Essa frase será digitada na coluna Descrição. E o script criado por nós estará numa opção de menu, e ao ser executado, irá analisar a frase e preencher as demais colunas da linha: Data, Valor, Categoria e Tipo.

Primeiro passo

Inicialmente crie uma planilha com as seguintes colunas: Descrição, Data, Valor, Categoria e Tipo. Nomeie a planilha como Finanças Pessoais e a página como Transações, por exemplo. Você pode atribuir qualquer nome. Em seguida clique no item de menu Extensões -> Apps Script. Será aberta uma nova aba no navegador com esta aparência:

Tela do Projeto Apps Script vinculado à planilha

Clique em Projeto sem título e renomeie-o. Por exemplo, pode dar o nome de ChatGPT for Sheets. E agora estamos prontos para criar nossa função. No entanto, antes de começar, vamos inserir o token da API OpenAI. Para isso, clique na engrenagem à esquerda: Configurações do projeto. Role a tela até encontrar Propriedades do script e clique em Adicionar propriedade do script.

Tela para adicionar propriedade

Digite o nome da propriedade na caixa Propriedade: API_TOKEN, por exemplo, e cole o token na caixa Valor. Agora, clique no botão Salvar propriedades do script. Com isso, nós evitamos expor o token no código do script, o que é uma prática recomendada. Para retornar ao script, clique no ícone Editor à esquerda.

Segundo passo

A seguir vamos iniciar a criação do script, explicando o conceito de namespace. Namespace, no contexto de linguagens de programação, é um espaço nomeado onde podemos declarar variáveis, objetos, classes, funções, etc., os quais estão fora do escopo global. Para acessar qualquer desses elementos precisamos utilizar primeiro o nome do espaço, seguido do identificador do elemento. Estamos usando esse recurso para prevenir que funções internas ao script sejam acessadas em uma célula da planilha.

Antes de digitar qualquer linha de código, delete as linhas existentes no editor e digite o seguinte trecho. Esse é o código da função que lê o token da API armazenado nas propriedades do script:

const Utils = {
  getApiKey: function() {
    var scriptProperties = PropertiesService.getScriptProperties();
    var apiKey = scriptProperties.getProperty('API_TOKEN');
    return apiKey;
  }
}

Aqui definimos Utils como um namespace e escrevemos as funções que desejamos sejam privadas dentro desse espaço. Namespace é um objeto JavaScript, onde cada elemento é definido na forma chave/valor. Neste caso, getApiKey é a chave, e o valor é a declaração da função. Basicamente, estamos usando a classe PropertiesService para obter o valor da propriedade API_TOKEN, que definimos anteriormente. Além de ler uma propriedade, esta classe também pode gravar novas propriedades, mas isso não nos interessa agora.

Em seguida, escrevemos a função que faz a requisição à API da OpenAI, dentro do namespace. Esta função recebe o prompt do sistema e do usuário, faz a requisição e retorna a mensagem respondida pelo modelo. Assim, você pode criar depois outras funções customizadas, além desta que analisa o texto da transação. Apenas defina os prompts e chame getResponseAI().

const Utils = {
  getApiKey: function() {
    var scriptProperties = PropertiesService.getScriptProperties();
    var apiKey = scriptProperties.getProperty('API_TOKEN');
    return apiKey;
  },

  getResponseAI: function(system_prompt,user_prompt) {
    var requestOptions = {
      "method": 'POST',
      "headers": {
        "Content-Type": "application/json",
        "Authorization": `Bearer ${Utils.getApiKey()}`
      },
      "payload": JSON.stringify({
        "model": 'gpt-4.1',
        "input": user_prompt,
        "instructions": system_prompt,
        "max_output_tokens":500
      })
    };

    var response = UrlFetchApp.fetch("https://api.openai.com/v1/responses", requestOptions);
    if (response.getResponseCode() !== 200) {
      Logger.log(response.getContentText());
      throw new Error("Falha na requisição à IA: " + response.getContentText());
    }
    
    response = JSON.parse(response);

    return response.output[0].content[0].text;
  }
}

Note que, antes de iniciar a nova função, foi inserida uma vírgula após o elemento anterior. Isso é parte da sintaxe do objeto JavaScript.

Diferente do que vimos no artigo Seu Assistente Financeiro Pessoal no Telegram: Integrando IA ao Bot do Google Sheets, onde usamos uma biblioteca Python para acessar a API OpenAI, aqui não temos intermediário. A requisição (fetch) é feita diretamente ao endpoint da API, informando as opções da requisição, de acordo com as instruções da documentação.

Função personalizada

Mesmo não sendo a solução que iremos adotar neste exemplo, vamos apresentar uma função personalizada que interpreta a frase e retorna os valores da transação: Data, Valor, Categoria e Tipo.

/**
 * Interpreta uma transação em forma textual.
 * @customfunction
*/
function INTERPRETAR(text) {
  if (text === null || text === "") {
    return [[]];
  }
  var system_prompt = 'Você é um sistema de categorização de transações financeiras. Responda APENAS em formato JSON válido, sem explicações adicionais.';
  var user_prompt = `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 ${new Date()})

                    Frase: ${text}

                    Retorne APENAS JSON, exemplo:
                        {{"valor": 58,.0, "tipo": "Despesa",
                            "categoria": "Alimentacao",
                            "data": "28/11/2025"}}`;
  json_response = JSON.parse(Utils.getResponseAI(system_prompt, user_prompt));
  return [[json_response.data, json_response.valor, json_response.categoria, json_response.tipo]];
}

A função INTERPRETAR() fica após o namespace Utils. Ou seja, fora do escopo do namespace. Uma função personalizada precisa ter a anotação @customfunction a fim de que apareça na complementação quando digitamos = numa célula. Mas não é obrigatório. Bem como não é obrigatório que nome da função esteja em caixa alta. Apenas seguimos o padrão de nomes das funções.

Se o retorno de uma função customizada for um único valor, este é lançado na célula corrente. Se for um array, os valores deste são lançados na coluna a partir da célula corrente. Se retornar um array de arrays, então um trecho de tabela é lançado a partir da célula corrente, onde cada elemento array compõe uma linha.

No nosso caso queremos lançar os dados da transação a partir da coluna Data, por isso retornamos um array de array. Logo no início da função INTERPRETAR(), que recebe como parâmetro o nome da célula onde está a frase, é verificado se o conteúdo dessa célula é vazio. Caso seja, a função retorna um array de array vazio.

Em seguida são criados os prompts, tanto de sistema quanto de usuário, e estes são passados para Utils.getResponseAI(), a qual retorna um JSON, de acordo com as instruções nos prompts.

E porque não adotamos essa função como solução para o nosso problema? Dois motivos são determinantes:
  • Sempre que a planilha é atualizada, a função INTERPRETAR() é executada, do mesmo modo que ocorre com qualquer fórmula ou operação. Com isso, é feita uma requisição à API, gerando um custo desnecessário.
  • Outro inconveniente, decorrente da atualização, é que a Data da transação, caso não seja informada na frase, é definida como a data corrente, conforme nossas instruções nos prompts. Dessa forma, depois de uma atualização, todas as transações passam a ter a data corrente e deixam de ter a data dos seus respectivos lançamentos.
Devido a esses motivos, optamos por criar um menu personalizado e um item de menu que chama a função que fará a interpretação.

Menu personalizado

Um menu personalizado é adicionado ao menu padrão do Google Sheets, ou de outra ferramenta do Google, utilizando a função onOpen(), que define alguma ação que ocorre ao abrir uma planilha ou documento. Nessa função é criado o menu IA Financeira e o item Processar Frase Selecionada. O mesmo método que cria o item recebe o nome de uma função a ser executada, no caso processarFraseIA.

function onOpen() {
  SpreadsheetApp.getUi()
    .createMenu('IA Financeira')
    .addItem('Processar Frase Selecionada', 'processarFraseIA')
    .addToUi();
}

function processarFraseIA() {
  const sheet = SpreadsheetApp.getActiveSheet();
  const cell = sheet.getActiveCell();
  const text = cell.getValue();

  if (!text || typeof text !== 'string') {
    SpreadsheetApp.getUi().alert("Selecione uma célula com uma frase.");
    return;
  }

  const dados = interpretar(text);

  const row = cell.getRow();
  const col = cell.getColumn();

  // Grava dados nas células seguintes
  sheet.getRange(row, col + 1).setValue(dados.data);
  sheet.getRange(row, col + 2).setValue(dados.valor);
  sheet.getRange(row, col + 3).setValue(dados.categoria);
  sheet.getRange(row, col + 4).setValue(dados.tipo);
  
  SpreadsheetApp.getUi().alert("Transação registrada!");
}

function interpretar(text) {
  var system_prompt = 'Você é um sistema de categorização de transações financeiras. Responda APENAS em formato JSON válido, sem explicações adicionais.';
  var user_prompt = `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 ${new Date()})

                    Frase: ${text}

                    Retorne APENAS JSON, exemplo:
                        {{"valor": 58,.0, "tipo": "Despesa",
                            "categoria": "Alimentacao",
                            "data": "28/11/2025"}}`;
  json_response = JSON.parse(Utils.getResponseAI(system_prompt, user_prompt));
  return json_response;
}

A função processarFraseIA() espera que a célula selecionada contenha a frase a ser analisada. Então ela verifica a existência da frase e chama a função interpretar(). Esta irá retornar um JSON, cujos dados são lançados nas células seguintes à direita da célula corrente.

Assim, você deve passar a ter um novo menu na sua planilha, como mostra a imagem:

Tela da planilha com o menu personalizado

Agora, digite a frase na coluna A, por exemplo, e clique no menu IA Financeira -> Processar Frase Selecionada. Os dados extraídos serão inseridos nas células à direita.

Conclusão

Apps Script nos oferece inúmeras possibilidades de criar planilhas poderosas para ajudar nosso controle das finanças pessoais. Mas deve ser usado com cautela, principalmente devido a questões relacionadas à segurança.

Apps Script pede permissão para acessar seus dados de Google Sheets, Google Drive, etc. Conceda apenas a permissão mínima necessária.

Evite copiar códigos de terceiros na Web. Eles podem fazer acesso aos seus dados, arquivos. Confie apenas em fontes verificadas.

Não exponha senhas, chaves de API, etc. no seu código. Procure guardá-los de forma segura, preferencialmente criptografados.

Comentários