Skip to content

Transcricao de audio

WPP Hub tem pipeline opt-in de transcricao de audio. Voce ativa por app+chip e recebe message.transcribed separado do message.received. Util pra atendimento humano (agente le sem precisar tocar audio) ou logging searchable.

Como funciona

  1. Mensagem audio chega no chip → hub persiste em messages + dispara message.received (com media_id)
  2. Se app tem transcribe_audio_mode='all' ou 'whitelist': hub enfileira job de transcricao
  3. Worker baixa audio do MinIO, manda pra Whisper API, persiste resultado em transcriptions
  4. Hub dispara message.transcribed so pra app que pediu (nao broadcast)

Setup

1. Provider OpenAI configurado no hub

apps/hub/.env:

TRANSCRIPTION_PROVIDER=openai
OPENAI_API_KEY=sk-proj-...
OPENAI_WHISPER_MODEL=whisper-1
TRANSCRIPTION_COST_CENTS_PER_MINUTE=0.6

(Se voce nao roda o hub, peca pro operador ativar.)

2. Ativar pra sua app no chip especifico

Quando crias o vinculo, escolhe o modo:

POST /v1/app-chip-access
{
"app_id": "01HZTQAPP...",
"chip_id": "01HZTQCHIP...",
"can_send": true,
"can_receive": true,
"transcribe_audio_mode": "all"
}

Modos:

ModoComportamento
'off' (default)nao transcreve nada pra essa app
'all'transcreve TODOS audios recebidos no chip
'whitelist'transcreve so se sender/chat estiver em transcribe_audio_jids

Modo whitelist

{
"transcribe_audio_mode": "whitelist",
"transcribe_audio_jids": [
"5511988887777", // telefone puro
"+55 (11) 99999-8888", // formato amigavel
"5511777776666@s.whatsapp.net", // JID
"5516991423401-1445094123@g.us", // grupo
"12345678901234@lid" // LID (so exact match — nao bate digito)
]
}

Hub aceita varios formatos. Match e por digit-extraction. LIDs nao batem com telefone (digitos diferentes); pra LID precisa exact match na string.

Recebendo a transcricao

app.post('/webhook', async (req, res) => {
// ... validacao HMAC ...
res.sendStatus(200)
const { event, data } = JSON.parse(req.body.toString())
if (event === 'message.received' && data.type === 'audio') {
// Audio entrou — UI pode mostrar "transcrevendo..."
await db.message.create({
...,
transcriptionStatus: 'pending',
})
}
if (event === 'message.transcribed') {
if (data.status === 'success') {
await db.message.update(
{ hubMessageId: data.message_id },
{
transcriptionStatus: 'success',
transcriptionText: data.transcription.text,
transcriptionLang: data.transcription.language,
transcriptionDuration: data.transcription.duration_seconds,
transcriptionCostCents: data.transcription.cost_cents,
},
)
} else {
await db.message.update(
{ hubMessageId: data.message_id },
{ transcriptionStatus: 'failed', transcriptionError: data.error },
)
}
}
})

Latencia tipica

Audio de 30s → Whisper responde em ~3-5s. Total 5-8s entre audio chegar e message.transcribed disparar.

Custo

Whisper-1: $0.006/min ≈ R$0.03/min (cambio 5).

Audio tipico WhatsApp: 30s → R$0.015 por audio.

10k audios/mes = R$150/mes. Pra volume alto, considerar:

  • Modo whitelist pra transcrever so agentes/lojas chave
  • Whisper local (Hub backlog — viavel quando volume justifica deploy de GPU)

Leitura admin

Ver transcricoes existentes

Terminal window
GET /v1/admin/messages?type=audio&limit=50

Retorna mensagens audio com link pra transcricao (se existe).

Re-transcrever manualmente (admin)

Mensagem ja foi parcialmente transcrita ou Whisper falhou? Force re-run:

Terminal window
POST /v1/admin/messages/:id/transcribe
Authorization: Bearer ADMIN_KEY

Idempotente (so cria se nao existe ou se status=‘failed’ anterior).

Cuidados

  1. Custo de OpenAI — monitora transcriptions.cost_cents mensal. WPP Hub expoe gauge wpp_transcription_cost_cents_total{provider, model} no Prometheus
  2. Falha em audio corrompido — Whisper retorna erro. Hub salva status='failed' + error. Sua UI deve degradar com graca (mostrar mensagem audio sem transcricao)
  3. Timingmessage.received chega ANTES de message.transcribed. Sua UI precisa lidar com isso (placeholder “transcrevendo…”)
  4. Multiplas apps — se 2 apps tem transcribe_audio_mode='all' no mesmo chip, hub dedupa Whisper (1 chamada API) mas grava 1 row por app em transcriptions + dispara webhook pra cada app. Cobranca por app