1. Antes de começar
Neste codelab, você vai aprender a automatizar tarefas do Google Workspace com os recursos de chamada de função e multimodalidade da API Gemini.
Pré-requisitos
- Noções básicas do Apps Script, JavaScript ou outra linguagem de programação semelhante
Conteúdo do laboratório
- Como aproveitar os recursos de chamada de função e multimodalidade da API Gemini.
- Como encadear várias chamadas da API Gemini.
- Como automatizar tarefas do Google Workspace com a API Gemini.
O que é necessário
- Um navegador da Web.
- Uma conta do Gmail. Você também pode usar uma conta do Google Workspace que tenha implementado a configuração específica da API Gemini.
- Uma conexão de uma região com suporte para a API Gemini.
- Opcional: uma interface de linha de comando com o programa
curl
para testar solicitações de API diretas.
O código completo deste codelab está disponível no Manual da API Gemini no GitHub (link em inglês). Confira se você precisa do código completo.
2. Configurar a API Gemini
Sobre o Gemini
Os modelos do Gemini são a maior e mais eficiente família de modelos de IA do Google. Para aproveitar esses modelos nos seus apps, use a API Gemini. Você também pode testar a API Gemini no Google AI Studio, uma interface da Web para a API em que você pode testar comandos, ajustar configurações de modelos e ajustar modelos personalizados sem escrever código.
Obter uma chave
- Para usar a API Gemini, crie uma chave de API no Google AI Studio.
Opcional: testar a chave
Se você tiver acesso a uma linha de comando com curl, adicione sua chave à primeira linha do bloco a seguir e execute-a no seu terminal para testar a chave de API.
export GOOGLE_API_KEY=Paste_your_API_key_here
curl "https://generativelanguage.googleapis.com/v1beta/models?key=${GOOGLE_API_KEY}"
Você verá uma lista de modelos no formato JSON, por exemplo, models/gemini-1.0-pro. Isso significa que funcionou.
3. Opcional: fazer uma solicitação para a API Gemini
Nesta etapa opcional, você vai fazer uma solicitação à API Gemini para entender melhor como funciona a geração de conteúdo antes de adicioná-lo a um app do Apps Script.
Sobre os modelos
A API Gemini oferece vários modelos com diferentes recursos e limitações. Cada um dos modelos está listado com os respectivos recursos na página de modelos do Gemini.
Como fazer sua primeira solicitação
Para que a API Gemini preencha um comando de texto, crie uma solicitação JSON e a envie ao endpoint da API REST.
Para isso, siga estas etapas:
- Em um novo arquivo, digite a seguinte solicitação JSON:
{
contents: [
{
parts: [
{ text: 'The most important aspects of a persuasive presentation are:' }
]
}
]
}
A solicitação JSON inclui o seguinte comando: The most important aspects of a persuasive presentation are:
. O modelo completará essa instrução e fornecerá o resultado diretamente.
A solicitação JSON tem três campos de nível superior para preencher: contents
, generationConfig
e safetySettings
. É necessário apenas contents
. Os outros fornecem mecanismos para controlar a saída.
- Salve esse JSON em um arquivo
presentation.txt
e o transmita diretamente paracurl
desta forma:
curl -H 'Content-Type: application/json' -X POST -d @presentation.txt \
'https://generativelanguage.googleapis.com/v1beta/models/gemini-1.0-pro-latest:generateContent?key='${GOOGLE_API_KEY}
Neste exemplo, você define os seguintes valores no URL:
v1beta
especifica a versão da API.gemini-1.0-pro-latest
especifica o Gemini 1.0 Pro como modelo e usa o snapshot mais recente.generateContent
especifica o método de API que será chamado.
Os resultados serão semelhantes aos exibidos abaixo:
{
"candidates": [
{
"content": {
"parts": [
{
"text": "* **Credibility:** The audience must trust that you are an expert on the subject matter and that you have their best interests at heart.\n* **Clearness:** Your message must be easy to understand and follow. Avoid using jargon or technical terms that your audience may not be familiar with.\n* **Concreteness:** Use specific examples and data to support your arguments. Avoid making vague or general claims.\n* **Emotional appeal:** In addition to appealing to the audience's logical side, you should also try to connect with them on an emotional level. Use storytelling, humor, and personal anecdotes to make your points more memorable and engaging.\n* **Strong closing:** End your presentation with a strong call to action. Tell the audience what you want them to do and why it is important for them to do it."
}
],
"role": "model"
},
"finishReason": "STOP",
"index": 0,
"safetyRatings": [...]
}
],
"promptFeedback": {
"safetyRatings": [...]
}
}
Por uma questão de legibilidade, esta é a saída do terminal formatada regularmente:
- Credibilidade:o público precisa confiar que você é especialista no assunto e que você tem os melhores interesses em foco.
- Clareza:sua mensagem precisa ser fácil de entender e acompanhar. Evite usar jargões ou termos técnicos com os quais seu público-alvo pode não estar familiarizado.
- Concreto:use exemplos e dados específicos para embasar seus argumentos. Evite fazer afirmações vagas ou gerais.
- Apelo emocional:além de atrair o lado lógico do público, você também deve tentar se conectar com ele em um nível emocional. Use narrativas, humor e histórias pessoais para tornar seus pontos mais memoráveis e envolventes.
- Fechamento forte:encerre a apresentação com uma call-to-action de impacto. Diga ao público o que você quer que ele faça e por que é importante que ele faça isso.
Para saber mais sobre as outras configurações, incluindo generationConfig
e safetySettings
, consulte os guias de comandos e segurança.
4. Chamar a API Gemini usando o Apps Script
- Acesse script.new. Um arquivo do Apps Script
code.gs
será criado automaticamente para você. - Mantenha o cursor sobre o arquivo
code.gs
e clique em > Renomear. - Mude o nome do arquivo para
utils.gs
. - No arquivo, remova a função
myFunction
para que o arquivo fique vazio.
Adicionar sua chave de API ao projeto
- No menu de navegação, selecione Configurações do projeto.
- Em Propriedades do script, clique em Adicionar propriedade de script.
- Em Propriedade, insira
GOOGLE_API_KEY
. - Em Valor, insira sua chave de API do Google AI Studio.
- Clique em Salvar propriedades do script.
- Volte para o editor.
Adicionar o código da API Gemini
No arquivo utils.gs
, siga estas etapas:
Configure a chave de API e o endpoint:
const properties = PropertiesService.getScriptProperties().getProperties();
const geminiApiKey = properties['GOOGLE_API_KEY'];
const geminiEndpoint = `https://generativelanguage.googleapis.com/v1beta/models/gemini-1.0-pro-latest:generateContent?key=${geminiApiKey}`;
- Adicione a seguinte função que chama a API Gemini com um comando específico:
function callGemini(prompt, temperature=0) {
const payload = {
"contents": [
{
"parts": [
{
"text": prompt
},
]
}
],
"generationConfig": {
"temperature": temperature,
},
};
const options = {
'method' : 'post',
'contentType': 'application/json',
'payload': JSON.stringify(payload)
};
const response = UrlFetchApp.fetch(geminiEndpoint, options);
const data = JSON.parse(response);
const content = data["candidates"][0]["content"]["parts"][0]["text"];
return content;
}
- Adicione a seguinte função que define o comando:
function testGemini() {
const prompt = "The best thing since sliced bread is";
const output = callGemini(prompt);
console.log(prompt, output);
}
Realizar o teste
- Clique em Salvar.
- Escolha
testGemini
na lista suspensa de funções e clique em . - Aceite as permissões necessárias. O código será executado e você verá uma saída do console com os resultados no registro de execução.
Deu certo!
5. Chamar a API Gemini com imagens
Um dos recursos mais avançados da família de modelos Gemini é o suporte à entrada multimodal, o que significa que você pode fornecer mais do que apenas texto. Nesta seção, você vai adicionar uma função que chama a API Gemini com uma imagem.
- Na parte de cima do arquivo
utils.gs
, depois da declaraçãoconst geminiEndpoint
atual, adicione a seguinte linha:
const geminiProVisionEndpoint = `https://generativelanguage.googleapis.com/v1beta/models/gemini-1.0-pro-vision-latest:generateContent?key=${geminiApiKey}`;
Adicionar o código do Gemini Vision
- Adicione uma função ao arquivo
utils.gs
para chamar esse endpoint recém-adicionado:
function callGeminiProVision(prompt, image, temperature=0) {
const imageData = Utilities.base64Encode(image.getAs('image/png').getBytes());
const payload = {
"contents": [
{
"parts": [
{
"text": prompt
},
{
"inlineData": {
"mimeType": "image/png",
"data": imageData
}
}
]
}
],
"generationConfig": {
"temperature": temperature,
},
};
const options = {
'method' : 'post',
'contentType': 'application/json',
'payload': JSON.stringify(payload)
};
const response = UrlFetchApp.fetch(geminiProVisionEndpoint, options);
const data = JSON.parse(response);
const content = data["candidates"][0]["content"]["parts"][0]["text"];
return content;
}
- Adicione a seguinte função de teste:
function testGeminiVision() {
const prompt = "Provide a fun fact about this object.";
const image = UrlFetchApp.fetch('https://storage.googleapis.com/generativeai-downloads/images/instrument.jpg').getBlob();
const output = callGeminiProVision(prompt, image);
console.log(prompt, output);
}
Essa função carrega uma imagem de teste da Internet e a transmite para a função que você definiu. Mais tarde, você o conecta para usar um gráfico de uma planilha, então isso é apenas um teste.
Realizar o teste
- Salve e execute a função
testGeminiVision
e, em seguida, inspecione a saída.
6. Chamar a API Gemini com ferramentas
Além de textos e imagens, você também pode fornecer acesso a ferramentas nos seus comandos.
Adicionar o código de manipulação de ferramentas
- Adicione uma função ao arquivo
utils.gs
que aceite uma especificação de ferramenta:
function callGeminiWithTools(prompt, tools, temperature=0) {
const payload = {
"contents": [
{
"parts": [
{
"text": prompt
},
]
}
],
"tools" : tools,
"generationConfig": {
"temperature": temperature,
},
};
const options = {
'method' : 'post',
'contentType': 'application/json',
'payload': JSON.stringify(payload)
};
const response = UrlFetchApp.fetch(geminiEndpoint, options);
const data = JSON.parse(response);
const content = data["candidates"][0]["content"]["parts"][0]["functionCall"];
return content;
}
Para mais informações sobre esse esquema e os campos disponíveis, consulte a Referência da API FunctionDeclaration
.
Realizar o teste
- Defina uma ferramenta que o modelo possa usar para encontrar a data e a hora atuais:
function testGeminiTools() {
const prompt = "Tell me how many days there are left in this month.";
const tools = {
"function_declarations": [
{
"name": "datetime",
"description": "Returns the current date and time as a formatted string.",
"parameters": {
"type": "string"
}
}
]
};
const output = callGeminiWithTools(prompt, tools);
console.log(prompt, output);
}
O formato usado aqui é o esquema FunctionDeclaration
(link em inglês). Na verdade, você não chama a função de data e hora. Você só recebe uma indicação de que o modelo solicitou uma chamada de função. Você vai gerenciar chamadas de função em uma etapa posterior.
- Salve e execute a função
testGeminiTools
para conferir a saída.
7. Visão geral das integrações de demonstração com o Google Workspace
Agora que você sabe como a chamada de função funciona, é fácil estender os recursos do modelo Gemini para outros serviços. Nas próximas seções, você vai criar integrações com os produtos do Google Workspace, como Google Drive, Apresentações e Planilhas Google. Veja um diagrama simplificado:
De modo geral, quando uma consulta de usuário chega, você usa a chamada de função da API Gemini para determinar qual ferramenta usar. Você cria três ferramentas que podem fazer o seguinte:
- Marque uma reunião. A função
setupMeeting()
no diagrama invoca a API Gemini 1.0 Pro para resumir um blog no Google Drive e adicionar o resumo a uma reunião recém-criada no Google Agenda. - Escreva um e-mail com base nos insights de um gráfico. A função
draftEmail()
no diagrama invoca o Gemini 1.0 Pro Vision para analisar um gráfico nas Planilhas Google e escrever um e-mail no Gmail com base na análise. - Crie uma apresentação básica. A função
createDeck()
no diagrama invoca o Gemini 1.0 Pro para discutir os tópicos de uma apresentação nas Apresentações Google.
Para cada ferramenta, faça o seguinte:
- Determine se a resposta da chamada de função da API Gemini pede para invocar essa ferramenta específica em um bloco
if...else
. - Adicione a função real para implementar a funcionalidade da ferramenta.
- Declare a ferramenta com a API Gemini para que o modelo Gemini saiba da existência dela e possa retornar a resposta correta da chamada de função.
8. Configurar uma reunião com o Apps Script
Primeiro, você automatiza a configuração de uma reunião no Google Agenda e adiciona uma descrição, que é um resumo de um arquivo no Google Drive.
Para isso, siga estas etapas:
- Baixe este arquivo de texto, que é a cópia do blog de lançamento do Gemini 1.5 Pro (links em inglês).
- Faça o upload do arquivo para sua pasta raiz no Google Drive.
- No editor, crie um arquivo
main.gs
e adicione o seguinte código:
function main() {
const userQuery = "Set up a meeting at 10AM tomorrow with Helen to discuss the news in the Gemini-blog.txt file.";
var tool_use = callGeminiWithTools(userQuery, WORKSPACE_TOOLS);
Logger.log(tool_use);
if(tool_use['name'] == "setupMeeting") {
setupMeeting(tool_use['args']['time'], tool_use['args']['recipient'], tool_use['args']['filename']);
Logger.log("Your meeting has been set up.");
}
else
Logger.log("no proper tool found");
}
Aqui você vai invocar o recurso de chamada de função da API Gemini. Em seguida, você precisa definir a função da ferramenta.
- À esquerda do editor, ao lado de Serviços, clique em + Adicionar um serviço > API Google Calendar > Adicionar. Isso ativa o serviço avançado do Google Agenda, que você precisará usar em algumas APIs avançadas mais tarde.
- No arquivo
utils.gs
, adicione o seguinte código:
function attachFileToMeeting(event, file, fileName) {
// Get the iCal ID for the event.
const iCalEventId = event.getId();
// Log the ID and title for debugging.
console.log(`iCal event ID: ${iCalEventId}`);
console.log(`event Title: ${event.getTitle()}`);
// Set up the options for listing the event with the advanced Google Calendar service.
const options = {
iCalUID: iCalEventId,
};
// Use the primary calendar as the calendar ID to list events.
const calendarId = 'primary';
// Use the advanced Google Calendar service to list the event.
const calEvents = Calendar.Events.list(calendarId, options);
// Get the Calendar ID used by the advanced Google Calendar service.
const eventId = calEvents.items[0].id;
// Get the file URL for the attachment.
const fileUrl = file.getUrl();
// Set up the patch options to add the file.
var patch = {
attachments: [{
'fileUrl': fileUrl,
'title': fileName
}]
};
// Patch the event to add the file as an attachment.
Calendar.Events.patch(patch, 'primary', eventId, {"supportsAttachments": true});
}
function setupMeeting(time, recipient, filename) {
const files = DriveApp.getFilesByName(filename);
const file = files.next();
const blogContent = file.getAs("text/*").getDataAsString();
var geminiOutput = callGemini("Give me a really short title of this blog and a summary with less than three sentences. Please return the result as a JSON with two fields: title and summary. \n" + blogContent);
// The Gemini model likes to enclose the JSON with ```json and ```
geminiOutput = JSON.parse(geminiOutput.replace(/```(?:json|)/g, ""));
const title = geminiOutput['title'];
const fileSummary = geminiOutput['summary'];
const event = CalendarApp.getDefaultCalendar().createEventFromDescription(`meet ${recipient} at ${time} to discuss "${title}"`);
event.setDescription(fileSummary);
attachFileToMeeting(event, file, filename);
}
Esse código faz o seguinte:
- A função
setupMeeting()
percorre o Google Drive e encontra o arquivoGemini-blog.txt
. Esse nome de arquivo é retornado automaticamente pela função da API Gemini chamando na etapa 3. - A função
setupMeeting()
chama a API Gemini para resumir o conteúdo do arquivo, configura uma reunião com o app Agenda usando uma descrição em formato livre e adiciona o resumo à reunião. - A função
setupMeeting()
chama a funçãoattachFileToMeeting()
para usar o serviço avançado do Google Agenda e anexar o arquivo do blog à reunião.
- Na parte de cima do arquivo
utils.gs
, adicione o seguinte código:
const WORKSPACE_TOOLS = {
"function_declarations": [
{
"name": "setupMeeting",
"description": "Sets up a meeting in Google Calendar.",
"parameters": {
"type": "object",
"properties": {
"time": {
"type": "string",
"description": "The time of the meeting."
},
"recipient": {
"type": "string",
"description": "The name of the recipient."
},
"filename": {
"type": "string",
"description": "The name of the file."
},
},
"required": [
"time",
"recipient",
"filename"
]
}
},
// You add tools here.
]
};
- No editor, volte para o arquivo
main.gs
e clique em . - Se o Google Workspace solicitar permissão para executar o script, clique em OK.
Em alguns segundos, o registro de execução vai mostrar uma mensagem informando que a reunião foi configurada.
- No Google Agenda, procure a reunião com o resumo e o anexo.
9. Escreva um e-mail com o Apps Script
Agora você vai automatizar o rascunho de um e-mail no Gmail. Este é o cenário: suponha que você realize uma análise de dados no Planilhas Google. Você coloca todos os números no lugar e cria um gráfico. Você quer usar a API Gemini Pro Vision para escrever um e-mail com base no gráfico.
Para isso, siga estas etapas:
- Abra esta planilha e clique em Arquivo -> Faça uma cópia.
- Na caixa de texto Nome da caixa de diálogo Copiar documento, substitua o nome padrão
Copy of CollegeExpenses
porCollegeExpenses
. - No arquivo
main.gs
, substitua a consulta do usuário anterior por uma nova e adicione o seguinte código à instruçãoif...else
:
function main() {
// const userQuery = "Set up a meeting at 5PM with Helen to discuss the news in the Gemini-1.5-blog.txt file.";
const userQuery = "Draft an email for Mary with insights from the chart in the CollegeExpenses sheet.";
if(...) {...}
// Add this code
else if(tool_use['name'] == "draftEmail") {
draftEmail(tool_use['args']['sheet_name'], tool_use['args']['recipient']);
Logger.log("Check your Gmail to review the draft");
}
else {...}
}
- No arquivo
utils.gs
, adicione o seguinte código:
function draftEmail(sheet_name, recipient) {
const prompt = `Compose the email body for ${recipient} with your insights for this chart. Use information in this chart only and do not do historical comparisons. Be concise.`;
var files = DriveApp.getFilesByName(sheet_name);
var sheet = SpreadsheetApp.openById(files.next().getId()).getSheetByName("Sheet1");
var expenseChart = sheet.getCharts()[0];
var chartFile = DriveApp.createFile(expenseChart.getBlob().setName("ExpenseChart.png"));
var emailBody = callGeminiProVision(prompt, expenseChart);
GmailApp.createDraft(recipient+"@demo-email-provider.com", "College expenses", emailBody, {
attachments: [chartFile.getAs(MimeType.PNG)],
name: 'myname'
});
}
Essa função extrai o gráfico de despesas da faculdade da planilha e o envia ao Gemini Pro Vision para redigir o e-mail. O Gemini Pro Vision extrai informações do gráfico e elabora o corpo do e-mail em seu nome.
- No arquivo
utils.gs
, adicione o seguinte código ao objetoWORKSPACE_TOOLS
após o comentárioYou add tools here
:
WORKSPACE_TOOLS = {
"function_declarations": [
// You add tools here.
{
"name": "draftEmail",
"description": "Write an email by analyzing data or charts in a Google Sheets file.",
"parameters": {
"type": "object",
"properties": {
"sheet_name": {
"type": "string",
"description": "The name of the sheet to analyze."
},
"recipient": {
"type": "string",
"description": "The name of the recipient."
},
},
"required": [
"sheet_name",
"recipient"
]
}
},
]
};
- No editor, volte para o arquivo
main.gs
e clique em . - Abra o Gmail depois de 10 a 20 segundos. Você verá um rascunho de e-mail como este:
Você pode revisar o rascunho de e-mail antes de enviá-lo. O e-mail é totalmente escrito pelo Gemini Pro Vision depois que você dá um breve comando e o gráfico.
10. Crie uma apresentação básica com o Apps Script
Em seguida, você vai automatizar a criação de uma apresentação básica no Apresentações Google com o Apps Script.
Para isso, siga estas etapas:
- No arquivo
main.gs
, substitua a consulta do usuário anterior por uma nova e adicione o seguinte código à instruçãoif...else
:
function main() {
// const userQuery = "Draft an email for Mary with insights from the chart in the CollegeExpenses sheet.";
const userQuery = "Help me put together a deck about water conservation.";
if(...) {...}
// Add this code
else if(tool_use['name'] == 'createDeck') {
deckURL = createDeck(tool_use['args']['topic']);
Logger.log("Deck URL: " + deckURL);
}
else {...}
}
- No arquivo
utils.gs
, adicione o seguinte código:
function createDeck(topic) {
const prompt = `I'm preparing a ${NUM_SLIDES}-slide deck to discuss ${topic}. Please help me brainstorm and generate main bullet points for each slide. Keep the title of each slide short. Please produce the result as a valid JSON so that I can pass it to other APIs.`;
var geminiOutput = callGemini(prompt, 0.4);
// The Gemini model likes to enclose the JSON with ```json and ```
geminiOutput = geminiOutput.replace(/```(?:json|)/g, "");
const bulletPoints = JSON.parse(geminiOutput);
// Create a Google Slides presentation.
const presentation = SlidesApp.create("My New Presentation");
// Set up the opening slide.
var slide = presentation.getSlides()[0];
var shapes = slide.getShapes();
shapes[0].getText().setText(topic);
var body;
for (var i = 0; i < NUM_SLIDES; i++) {
slide = presentation.appendSlide(SlidesApp.PredefinedLayout.TITLE_AND_BODY);
shapes = slide.getShapes();
// Set title.
shapes[0].getText().setText(bulletPoints['slides'][i]['title']);
// Set body.
body = "";
for (var j = 0; j < bulletPoints['slides'][i]['bullets'].length; j++) {
body += '* ' + bulletPoints['slides'][i]['bullets'][j] + '\n';
}
shapes[1].getText().setText(body);
}
return presentation.getUrl();
}
Essa função chama a API Gemini para discutir ideias sobre um tema específico e retornar os marcadores no formato
de JSON e depois usar o Apps Script para preencher um esqueleto de apresentação.
- No arquivo
utils.gs
, adicione o seguinte código ao objetoWORKSPACE_TOOLS
após o comentárioYou add tools here
:
WORKSPACE_TOOLS = {
"function_declarations": [
// You add tools here.
{
"name": "createDeck",
"description": "Build a simple presentation deck with Google Slides and return the URL.",
"parameters": {
"type": "object",
"properties": {
"topic": {
"type": "string",
"description": "The topic that the presentation is about."
},
},
"required": [
"topic"
]
}
},
]
};
- Na parte de cima do arquivo
utils.gs
, defina a seguinte constante:
const NUM_SLIDES = 3;
Este é o número de slides que o modelo Gemini cria além do slide de abertura.
- No editor, volte para o arquivo
main.gs
e clique em . Em alguns segundos, o URL da apresentação vai aparecer no registro de execução. - Use o navegador para abrir o URL. Vai aparecer um esqueleto de apresentação cheio de marcadores.
11. Ideias para explorar
Além dessas três integrações, você pode explorar as seguintes ideias:
- Criar um chatbot no Google Chat. Um dos casos de uso mais conhecidos dos modelos de linguagem grandes (LLMs) é a criação de um chatbot. Com a API Gemini, é fácil criar um chatbot para o Google Chat. Para mais informações, consulte a API Google Chat e o codelab Criar apps para o Google Chat com o Gemini.
- Geração Aumentada de Recuperação (RAG) com seus próprios dados no Google Drive ou Keep. Neste codelab, você vai usar apenas um arquivo de texto para fazer resumos. No entanto, também é possível usar o conteúdo do seu Google Drive pessoal e do Keep, como notas, PDFs e imagens, com a API Gemini, um banco de dados de vetores e, opcionalmente, uma ferramenta de orquestração, como o LangChain, para fazer RAG e personalizar a resposta do modelo com base nos seus dados.
- Use o recurso de chamada de função de vários turnos da API Gemini. A chamada de função da API Gemini não se limita a um turno, e você pode fazer chamadas de função em vários turnos para tarefas ainda mais complexas.
- Vá além do Google Workspace. Agora que você sabe como integrar a API Gemini ao Google Workspace, pode ir além do Google Workspace e aproveitar outras APIs do mundo.
12. Parabéns
Você aprendeu sobre os recursos multimodais e a chamada de função da API Gemini. Eles foram usados para automatizar algumas tarefas do Google Workspace com o Apps Script.