WhatsApp Audio — Pipeline de Transcrição (STT)
Visão Geral
O MediaFetcherService baixa áudios enviados por WhatsApp (voz/PTT) e os encaminha para transcrição via AssistantService.transcribeAudio(). O texto transcrito é então tratado como mensagem de texto pelo fluxo de IA (pedido do cliente ou assistente admin).
Arquivos
| Arquivo | Papel |
|---|---|
backend/src/whatsapp-ordering/media-fetcher.service.ts | Fetch de bytes de áudio (Meta + Evolution) |
backend/src/whatsapp-ordering/whatsapp-ordering.controller.ts | Entry point webhook — detecta message.type === 'audio' |
backend/src/whatsapp-ordering/conversation.schema.ts | Schema de conversa com AudioTranscriptEntry[] |
backend/src/assistant/assistant.service.ts | transcribeAudio(bytes, mimeType, filename) |
Fluxo Completo
WhatsApp (Meta/Evolution)
│
▼
POST /webhooks/whatsapp/:tenantId (WhatsAppOrderingController)
│
├── message.type === 'text' → passa direto para AI
│
└── message.type === 'audio'
│
├── Verifica duração ≤ 60s (cap de tamanho)
│ Se > 60s → responde "Áudio muito longo" e retorna
│
├── MediaFetcherService.fetchMeta(mediaId, tenantId)
│ ou MediaFetcherService.fetchEvolution(messageId, baseUrl, apiKey)
│
├── AssistantService.transcribeAudio(bytes, 'audio/ogg', 'audio.ogg')
│
├── persistTranscript(tenantId, phone, { source, mediaId, durationSec, transcript })
│
└── text = transcript → fluxo AI normal (admin ou customer)MediaFetcherService
fetchMeta(mediaId, tenantId)
- Usa
tenant.whatsappConfig.metaAccessToken(por tenant). - Passo 1:
GET https://graph.facebook.com/v18.0/{mediaId}→ resolve URL presigned. - Passo 2: Download dos bytes brutos com o mesmo token.
- Retorna
Buffer.
fetchEvolution(messageId, instanceBaseUrl, apiKey)
- Chama
GET {instanceBaseUrl}/message/getBase64FromMediaMessage/{messageId}com headerapikey. - Decodifica
data.base64→Buffer.
Auditoria de Transcrições
Cada áudio processado gera uma entrada no campo WhatsAppConversation.transcripts[]:
| Campo | Tipo | Descrição |
|---|---|---|
source | 'meta' | 'evolution' | Provedor do áudio |
mediaId | string | ID do media no provedor |
durationSec | number | Duração declarada pelo provedor |
transcript | string | Texto transcrito |
receivedAt | Date | Timestamp |
A persistência é feita via upsert em WhatsAppConversation (keyed por phone + tenant).
Limites e Restrições
| Parâmetro | Valor |
|---|---|
| Duração máxima de áudio | 60 segundos |
| Formato aceito | audio/ogg (WhatsApp PTT/voice) |
| Rate limit webhook | Sem throttle próprio (depende do provider) |
Tenant sem metaAccessToken | BadRequestException ("no Meta access token configured") |
Configuração
Para habilitar áudio via Meta Cloud API:
- Configure
WHATSAPP_VERIFY_TOKENnas variáveis de ambiente. - No documento Tenant, salve
whatsappConfig.metaAccessTokencom o token permanente da Meta. - No painel Meta for Developers, aponte o webhook para
POST /webhooks/whatsapp/:tenantId.
Para Evolution API:
- Configure
evolutionInstanceno documento Branch (cada branch pode ter instância própria). - A chave de API é resolvida via
WhatsAppService.resolveInstance(tenantId).