Objetivo da Aula
Ao concluir esta aula, você será capaz de:
Implementar resumo automático de transcrições de reunião via LLM
Extrair action items estruturados (responsável, prazo, prioridade) de texto livre
Criar páginas no Notion via API com action items extraídos
Completar os 2 TODOs: resumirReuniao e criarPaginaNotion
Integrar transcrição → resumo → Notion em pipeline automático
Por que isso importa
A maioria das reuniões gera uma lista de “próximos passos” que ninguém persiste. Action items discutidos verbalmente têm taxa de conclusão de ~30%. Quando criados automaticamente no Notion com responsável e prazo, sobem para ~70% (dado de pesquisa de productividade de times).
LLM extrai action items melhor do que humanos porque não filtra subjetivamente: anota tudo que tem estrutura “quem faz o quê até quando”.
Conceitos Fundamentais
TODO 1: resumirReuniao(transcricao, client)
async function resumirReuniao(transcricao, client) {
const response = await client.messages.create({
model: 'claude-haiku-4-5-20251001',
max_tokens: 800,
system: `Você é um assistente especializado em gestão de projetos.
Analise a transcrição e retorne JSON com esta estrutura exata:
{
"resumo": "Resumo executivo em 2-3 frases",
"decisoes": ["Decisão 1", "Decisão 2"],
"action_items": [
{
"descricao": "O que deve ser feito",
"responsavel": "Nome ou 'A definir'",
"prazo": "Data ou 'A definir'",
"prioridade": "alta|media|baixa"
}
],
"proxima_reuniao": "Data/hora ou 'Não definida'"
}`,
messages: [{
role: 'user',
content: `Transcrição da reunião:\n${transcricao}`,
}],
})
const texto = response.content[0].text
const inicio = texto.indexOf('{')
const fim = texto.lastIndexOf('}') + 1
return JSON.parse(texto.slice(inicio, fim))
}TODO 2: criarPaginaNotion(dados, notionToken)
async function criarPaginaNotion(dados, notionToken, databaseId) {
// Notion API - criar página num database
const response = await fetch('https://api.notion.com/v1/pages', {
method: 'POST',
headers: {
'Authorization': `Bearer ${notionToken}`,
'Notion-Version': '2022-06-28',
'Content-Type': 'application/json',
},
body: JSON.stringify({
parent: { database_id: databaseId },
properties: {
Name: { title: [{ text: { content: `Reunião ${new Date().toLocaleDateString('pt-BR')}` } }] },
Status: { select: { name: 'Pendente' } },
},
children: [
{
object: 'block',
type: 'heading_2',
heading_2: { rich_text: [{ text: { content: 'Resumo' } }] },
},
{
object: 'block',
type: 'paragraph',
paragraph: { rich_text: [{ text: { content: dados.resumo } }] },
},
{
object: 'block',
type: 'heading_2',
heading_2: { rich_text: [{ text: { content: 'Action Items' } }] },
},
...dados.action_items.map(item => ({
object: 'block',
type: 'to_do',
to_do: {
rich_text: [{
text: {
content: `[${item.prioridade.toUpperCase()}] ${item.descricao} — ${item.responsavel} (${item.prazo})`,
},
}],
checked: false,
},
})),
],
}),
})
const resultado = await response.json()
return { sucesso: response.ok, url: resultado.url, id: resultado.id }
}Aprofundamento Técnico
Notion API: Estrutura de Database vs Page
Notion workspace
├── Database (tabela de reuniões)
│ ├── Page (reunião 1) → tem properties + children (blocks)
│ ├── Page (reunião 2)
│ └── ...
└── Page standalone (sem database)Para criar páginas num database: parent: { database_id: "..." }. Para criar página avulsa: parent: { page_id: "..." }.
O databaseId vem da URL do Notion: notion.so/workspace/<database_id>?v=...
Mock para Desenvolvimento
async function criarPaginaNotionMock(dados, notionToken, databaseId) {
console.log('NOTION MOCK — Página que seria criada:')
console.log(JSON.stringify({
database: databaseId,
resumo: dados.resumo,
total_action_items: dados.action_items.length,
itens_alta_prioridade: dados.action_items.filter(i => i.prioridade === 'alta').length,
}, null, 2))
return { sucesso: true, url: 'https://notion.so/mock', id: 'mock-id' }
}Exemplos Anotados
Exemplo 1: Pipeline Completo
const transcricao = `
Maria: Ok, precisamos lançar o módulo de pagamentos antes do Q2.
João: Eu fico responsável pela integração com Stripe.
Maria: João, você consegue ter isso pronto até sexta-feira?
João: Sim, até sexta. Pedro, você pode fazer a revisão de segurança na semana que vem?
Pedro: Pode ser, terça ou quarta.
Maria: Decidido então: lançamento no dia 30.
`
// Passo 1: resumir
const resumo = await resumirReuniao(transcricao, client)
// → {
// resumo: "Decisão de lançar módulo de pagamentos no Q2...",
// action_items: [
// { descricao: "Integrar Stripe", responsavel: "João", prazo: "sexta-feira", prioridade: "alta" },
// { descricao: "Revisão de segurança", responsavel: "Pedro", prazo: "terça/quarta", prioridade: "media" },
// ]
// }
// Passo 2: criar no Notion
const pagina = await criarPaginaNotion(resumo, process.env.NOTION_TOKEN, process.env.NOTION_DB_ID)
console.log(`Reunião salva: ${pagina.url}`)Padrões e Armadilhas
Padrões
Padrão 1: Sempre Mock primeiro
const USE_NOTION = process.env.NOTION_TOKEN && process.env.NOTION_DB_ID
const criarPagina = USE_NOTION ? criarPaginaNotion : criarPaginaNotionMockPadrão 2: Action items sem responsável definido
const indefinidos = resumo.action_items.filter(i => i.responsavel === 'A definir')
if (indefinidos.length > 0) {
console.warn(`⚠️ ${indefinidos.length} action items sem responsável`)
}Armadilhas
⚠️ Armadilha 1: Notion rate limit A API aceita ~3 requests/segundo. Para muitos action items, adicione delay entre chamadas.
⚠️ Armadilha 2: LLM inventa prazos Se a transcrição não menciona prazo, use "A definir" — nunca invente uma data. Adicione no system prompt: "Se não mencionar prazo explicitamente, use 'A definir'.".
⚠️ Armadilha 3: JSON com vírgulas em ações
"descricao": "Integrar Stripe, Braintree, e PayPal"
// vírgulas dentro de string são OK — o problema é quando LLM gera JSON malformado
// sempre use try/catch no JSON.parseSe não for realizar o laboratório, pule para o próximo capítulo.
Ponte para o Lab
TODO 1 — resumirReuniao(transcricao, client): system prompt instruindo JSON com resumo, decisoes, action_items[] (com responsavel, prazo, prioridade), proxima_reuniao.
TODO 2 — criarPaginaNotion(dados, notionToken, databaseId): POST para api.notion.com/v1/pages, com parent.database_id, properties e children blocks com to_do items.
Agora você está pronto para o lab.