GOOGLE_SLIDES - Integração com Google Slides
O que é este Node?
O GOOGLE_SLIDES é o node responsável por criar e manipular apresentações no Google Slides, permitindo criar, ler, adicionar slides e fazer atualizações em lote automaticamente.
Por que este Node existe?
Apresentações precisam ser geradas dinamicamente. O GOOGLE_SLIDES existe para:
- Gerar apresentações automáticas: Criar slides de relatórios, propostas
- Adicionar slides dinamicamente: Inserir novos slides com conteúdo
- Automatizar criação: Eliminar trabalho manual repetitivo
- Personalizar em escala: Criar múltiplas apresentações customizadas
- Integrar com dados: Conectar apresentações com bases de dados
Como funciona internamente?
Quando o GOOGLE_SLIDES é executado, o sistema:
- Autentica via OAuth2 com Google (access_token e refresh_token)
- Conecta à API do Google Slides v1
- Executa operação solicitada (create, get, batchUpdate, addSlide)
- Processa estrutura da apresentação (slides, elementos, layouts)
- Retorna presentationId, slides ou confirmação
- Se erro: Retorna mensagem de erro detalhada
Código interno (google-executors.service.ts:823-904):
async executeGoogleSlides(data: any, variables: Record<string, any>): Promise<any> {
try {
this.logger.log('🎞️ [GOOGLE SLIDES] Executing operation');
const oauth2Client = new OAuth2Client(
process.env.GOOGLE_CLIENT_ID,
process.env.GOOGLE_CLIENT_SECRET,
process.env.GOOGLE_REDIRECT_URI
);
oauth2Client.setCredentials({
access_token: data.accessToken,
refresh_token: data.refreshToken,
});
const slides = google.slides({ version: 'v1', auth: oauth2Client });
switch (data.operation) {
case 'create':
const createResult = await slides.presentations.create({
requestBody: {
title: data.title,
},
});
return {
success: true,
presentationId: createResult.data.presentationId,
title: createResult.data.title,
};
case 'get':
const getResult = await slides.presentations.get({
presentationId: data.presentationId,
});
return {
success: true,
presentation: getResult.data,
slides: getResult.data.slides,
};
case 'batchUpdate':
const updateResult = await slides.presentations.batchUpdate({
presentationId: data.presentationId,
requestBody: {
requests: data.requests,
},
});
return {
success: true,
replies: updateResult.data.replies,
};
case 'addSlide':
const addSlideResult = await slides.presentations.batchUpdate({
presentationId: data.presentationId,
requestBody: {
requests: [{
createSlide: {
slideLayoutReference: {
predefinedLayout: data.layout || 'BLANK',
},
},
}],
},
});
return {
success: true,
slideId: addSlideResult.data.replies?.[0]?.createSlide?.objectId,
};
default:
throw new Error(`Unknown Google Slides operation: ${data.operation}`);
}
} catch (error) {
this.logger.error('Google Slides execution error:', error);
throw error;
}
}
Quando você DEVE usar este Node?
Use GOOGLE_SLIDES sempre que precisar criar apresentações automaticamente:
Casos de uso
- Relatórios visuais: "Gerar apresentação de resultados mensais"
- Propostas comerciais: "Criar deck de vendas personalizado"
- Apresentações de dados: "Transformar dados em slides"
- Templates dinâmicos: "Personalizar apresentação base"
- Dashboards visuais: "Criar slides com gráficos automáticos"
- Documentação visual: "Gerar apresentação de projeto"
Quando NÃO usar GOOGLE_SLIDES
- Design muito complexo: Templates manuais são melhores
- Imagens pesadas: Considere performance da API
- Edição manual posterior: Verifique se automação vale a pena
Parâmetros
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
| operation | string | Sim | create, get, batchUpdate, addSlide |
| title | string | Condicional | Título da apresentação (para create) |
| presentationId | string | Condicional | ID da apresentação (para get/update) |
| layout | string | Não | Layout do slide (BLANK, TITLE, etc) |
| requests | array | Condicional | Array de requests (para batchUpdate) |
| accessToken | string | Sim | Token OAuth2 do Google |
| refreshToken | string | Sim | Refresh token OAuth2 do Google |
Operações Disponíveis
1. create - Criar apresentação
O que faz: Cria nova apresentação vazia no Google Slides.
Parâmetros obrigatórios: - title - accessToken - refreshToken
2. get - Ler apresentação
O que faz: Obtém estrutura completa da apresentação.
Parâmetros obrigatórios: - presentationId - accessToken - refreshToken
3. addSlide - Adicionar slide
O que faz: Adiciona novo slide à apresentação.
Parâmetros obrigatórios: - presentationId - accessToken - refreshToken
Parâmetros opcionais: - layout (BLANK, TITLE, TITLE_AND_BODY, etc)
4. batchUpdate - Atualizações em lote
O que faz: Executa múltiplas operações de edição em uma chamada.
Parâmetros obrigatórios: - presentationId - requests (array de operações) - accessToken - refreshToken
Exemplo 1: Criar Apresentação de Vendas
Objetivo: Criar apresentação com dados de vendas do mês.
JSON para Importar
{
"name": "Gerar Apresentação de Vendas",
"nodes": [
{
"id": "start_1",
"type": "start",
"position": { "x": 100, "y": 100 },
"data": { "label": "Início" }
},
{
"id": "input_1",
"type": "input",
"position": { "x": 300, "y": 100 },
"data": {
"label": "Mês",
"parameters": {
"message": "Mês do relatório:",
"variable": "mes"
}
}
},
{
"id": "number_1",
"type": "number",
"position": { "x": 500, "y": 100 },
"data": {
"label": "Total Vendas",
"parameters": {
"message": "Total de vendas (R$):",
"variable": "total_vendas",
"decimals": 2
}
}
},
{
"id": "google_slides_1",
"type": "google_slides",
"position": { "x": 700, "y": 100 },
"data": {
"label": "Criar Apresentação",
"parameters": {
"operation": "create",
"title": "Relatório de Vendas - {{mes}}",
"accessToken": "{{google_access_token}}",
"refreshToken": "{{google_refresh_token}}"
}
}
},
{
"id": "google_slides_2",
"type": "google_slides",
"position": { "x": 900, "y": 100 },
"data": {
"label": "Adicionar Slide Título",
"parameters": {
"operation": "addSlide",
"presentationId": "{{presentationId}}",
"layout": "TITLE",
"accessToken": "{{google_access_token}}",
"refreshToken": "{{google_refresh_token}}"
}
}
},
{
"id": "google_slides_3",
"type": "google_slides",
"position": { "x": 1100, "y": 100 },
"data": {
"label": "Adicionar Slide Dados",
"parameters": {
"operation": "addSlide",
"presentationId": "{{presentationId}}",
"layout": "TITLE_AND_BODY",
"accessToken": "{{google_access_token}}",
"refreshToken": "{{google_refresh_token}}"
}
}
},
{
"id": "message_1",
"type": "message",
"position": { "x": 1300, "y": 100 },
"data": {
"label": "Confirmar",
"parameters": {
"message": "✅ Apresentação criada!\n\n📊 {{title}}\n💰 Total: R$ {{total_vendas}}\n\n🔗 https://docs.google.com/presentation/d/{{presentationId}}/edit"
}
}
},
{
"id": "end_1",
"type": "end",
"position": { "x": 1500, "y": 100 },
"data": { "label": "Fim" }
}
],
"edges": [
{ "source": "start_1", "target": "input_1" },
{ "source": "input_1", "target": "number_1" },
{ "source": "number_1", "target": "google_slides_1" },
{ "source": "google_slides_1", "target": "google_slides_2" },
{ "source": "google_slides_2", "target": "google_slides_3" },
{ "source": "google_slides_3", "target": "message_1" },
{ "source": "message_1", "target": "end_1" }
]
}
Saída esperada:
Sistema: Mês do relatório:
Usuário: Janeiro 2025
Sistema: Total de vendas (R$):
Usuário: 150000.00
Sistema: ✅ Apresentação criada!
📊 Relatório de Vendas - Janeiro 2025
💰 Total: R$ 150000.00
🔗 https://docs.google.com/presentation/d/abc123.../edit
Exemplo 2: Ler Apresentação Existente
Objetivo: Obter informações de apresentação existente.
JSON para Importar
{
"name": "Ler Apresentação do Google Slides",
"nodes": [
{
"id": "start_1",
"type": "start",
"position": { "x": 100, "y": 100 },
"data": { "label": "Início" }
},
{
"id": "input_1",
"type": "input",
"position": { "x": 300, "y": 100 },
"data": {
"label": "ID Apresentação",
"parameters": {
"message": "Cole o ID da apresentação:",
"variable": "presentation_id"
}
}
},
{
"id": "google_slides_1",
"type": "google_slides",
"position": { "x": 500, "y": 100 },
"data": {
"label": "Obter Info",
"parameters": {
"operation": "get",
"presentationId": "{{presentation_id}}",
"accessToken": "{{google_access_token}}",
"refreshToken": "{{google_refresh_token}}"
}
}
},
{
"id": "message_1",
"type": "message",
"position": { "x": 700, "y": 100 },
"data": {
"label": "Mostrar Dados",
"parameters": {
"message": "📊 Apresentação carregada!\n\nTítulo: {{presentation.title}}\nTotal de slides: {{slides.length}}"
}
}
},
{
"id": "end_1",
"type": "end",
"position": { "x": 900, "y": 100 },
"data": { "label": "Fim" }
}
],
"edges": [
{ "source": "start_1", "target": "input_1" },
{ "source": "input_1", "target": "google_slides_1" },
{ "source": "google_slides_1", "target": "message_1" },
{ "source": "message_1", "target": "end_1" }
]
}
Exemplo 3: Criar Proposta com Múltiplos Slides
Objetivo: Gerar deck completo de proposta comercial.
JSON para Importar
{
"name": "Deck de Proposta Comercial",
"nodes": [
{
"id": "start_1",
"type": "start",
"position": { "x": 100, "y": 100 },
"data": { "label": "Início" }
},
{
"id": "input_1",
"type": "input",
"position": { "x": 300, "y": 100 },
"data": {
"label": "Cliente",
"parameters": {
"message": "Nome do cliente:",
"variable": "cliente"
}
}
},
{
"id": "google_slides_1",
"type": "google_slides",
"position": { "x": 500, "y": 100 },
"data": {
"label": "Criar Deck",
"parameters": {
"operation": "create",
"title": "Proposta - {{cliente}}",
"accessToken": "{{google_access_token}}",
"refreshToken": "{{google_refresh_token}}"
}
}
},
{
"id": "google_slides_2",
"type": "google_slides",
"position": { "x": 700, "y": 100 },
"data": {
"label": "Slide 1: Capa",
"parameters": {
"operation": "addSlide",
"presentationId": "{{presentationId}}",
"layout": "TITLE",
"accessToken": "{{google_access_token}}",
"refreshToken": "{{google_refresh_token}}"
}
}
},
{
"id": "google_slides_3",
"type": "google_slides",
"position": { "x": 900, "y": 100 },
"data": {
"label": "Slide 2: Sobre Nós",
"parameters": {
"operation": "addSlide",
"presentationId": "{{presentationId}}",
"layout": "TITLE_AND_BODY",
"accessToken": "{{google_access_token}}",
"refreshToken": "{{google_refresh_token}}"
}
}
},
{
"id": "google_slides_4",
"type": "google_slides",
"position": { "x": 1100, "y": 100 },
"data": {
"label": "Slide 3: Solução",
"parameters": {
"operation": "addSlide",
"presentationId": "{{presentationId}}",
"layout": "TITLE_AND_BODY",
"accessToken": "{{google_access_token}}",
"refreshToken": "{{google_refresh_token}}"
}
}
},
{
"id": "google_slides_5",
"type": "google_slides",
"position": { "x": 1300, "y": 100 },
"data": {
"label": "Slide 4: Investimento",
"parameters": {
"operation": "addSlide",
"presentationId": "{{presentationId}}",
"layout": "TITLE_AND_BODY",
"accessToken": "{{google_access_token}}",
"refreshToken": "{{google_refresh_token}}"
}
}
},
{
"id": "message_1",
"type": "message",
"position": { "x": 1500, "y": 100 },
"data": {
"label": "Deck Pronto",
"parameters": {
"message": "✅ Deck de proposta criado!\n\n🏢 Cliente: {{cliente}}\n📊 4 slides criados\n\n🔗 https://docs.google.com/presentation/d/{{presentationId}}/edit"
}
}
},
{
"id": "end_1",
"type": "end",
"position": { "x": 1700, "y": 100 },
"data": { "label": "Fim" }
}
],
"edges": [
{ "source": "start_1", "target": "input_1" },
{ "source": "input_1", "target": "google_slides_1" },
{ "source": "google_slides_1", "target": "google_slides_2" },
{ "source": "google_slides_2", "target": "google_slides_3" },
{ "source": "google_slides_3", "target": "google_slides_4" },
{ "source": "google_slides_4", "target": "google_slides_5" },
{ "source": "google_slides_5", "target": "message_1" },
{ "source": "message_1", "target": "end_1" }
]
}
Resposta do Node
Operação create
{
"success": true,
"presentationId": "1abc123XYZ...",
"title": "Relatório de Vendas - Janeiro"
}
Operação get
{
"success": true,
"presentation": {
"presentationId": "1abc123...",
"title": "Minha Apresentação",
"slides": [
{
"objectId": "slide1",
"slideProperties": {}
}
]
},
"slides": [/* array de slides */]
}
Operação addSlide
{
"success": true,
"slideId": "slide_abc123"
}
Operação batchUpdate
{
"success": true,
"replies": [
/* array de respostas */
]
}
Como obter presentationId
O presentationId está na URL do Google Slides:
https://docs.google.com/presentation/d/1abc123XYZ.../edit
^^^^^^^^^^^
presentationId
Layouts Predefinidos
| Layout | Descrição |
|---|---|
| BLANK | Slide em branco |
| TITLE | Slide de título (capa) |
| TITLE_AND_BODY | Título e corpo de texto |
| TITLE_AND_TWO_COLUMNS | Título com 2 colunas |
| TITLE_ONLY | Apenas título |
| SECTION_HEADER | Cabeçalho de seção |
| SECTION_TITLE_AND_DESCRIPTION | Seção com descrição |
| ONE_COLUMN_TEXT | Uma coluna de texto |
| MAIN_POINT | Ponto principal |
| BIG_NUMBER | Número grande |
Requests do batchUpdate
Operações disponíveis via batchUpdate:
{
"requests": [
{
"createSlide": {
"slideLayoutReference": {
"predefinedLayout": "TITLE_AND_BODY"
}
}
},
{
"insertText": {
"objectId": "slide_id",
"text": "Texto do slide"
}
},
{
"createShape": {
"objectId": "shape_id",
"shapeType": "TEXT_BOX",
"elementProperties": {
"pageObjectId": "slide_id",
"size": {
"width": { "magnitude": 300, "unit": "PT" },
"height": { "magnitude": 100, "unit": "PT" }
}
}
}
}
]
}
Principais operações: - createSlide - deleteObject - insertText - createShape - createImage - updateTextStyle - updateShapeProperties
Estrutura da Apresentação
Presentation
├── presentationId
├── title
├── slides []
│ ├── objectId
│ ├── slideProperties
│ └── pageElements []
│ ├── shape
│ ├── image
│ ├── video
│ └── table
└── layouts []
Boas Práticas
✅ SIM:
- Use layouts predefinidos para consistência
- Salve presentationId para operações futuras
- Agrupe operações em batchUpdate
- Nomeie apresentações de forma descritiva
- Organize por pastas no Drive
❌ NÃO:
- Não crie slides duplicados desnecessariamente
- Não faça muitas operações individuais (use batch)
- Não ignore limites de tamanho de imagens
- Não delete slides sem backup
- Não exponha tokens em logs
Dicas
💡 Templates: Crie apresentação base e clone para personalizar
💡 Imagens: Use Drive API para fazer upload antes de inserir
💡 Performance: batchUpdate é mais eficiente que chamadas múltiplas
💡 Design: Mantenha layouts consistentes entre slides
💡 Colaboração: Configure permissões via Drive API após criar
Troubleshooting
Erro: "Presentation not found"
Causa: presentationId inválido ou sem permissão
Solução: Verifique ID na URL e permissões de acesso
Erro: "Invalid layout"
Causa: Nome de layout incorreto
Solução: Use layouts da tabela acima (BLANK, TITLE, etc)
Erro: "Invalid requests"
Causa: Formato incorreto em batchUpdate
Solução: Siga estrutura da documentação oficial
Erro: "Object not found"
Causa: slideId ou objectId inválido
Solução: Use get para obter IDs válidos
Exportar para PDF
Para converter apresentação em PDF, use Drive API:
GET https://www.googleapis.com/drive/v3/files/{presentationId}/export?mimeType=application/pdf
Próximo Node
→ GOOGLE_DOCS - Criar documentos → GOOGLE_SHEETS - Trabalhar com planilhas → GOOGLE_DRIVE - Gerenciar arquivos