0

Pitch: FalaAI, uma API e um servidor MCP que transformam conversas de atendimento em JSON com schema fixo e relatório auditável

Disclosure: sou o autor e criador do FalaAI (Action Tec Brasil). Escrevi este post para contar as decisões técnicas do projeto e receber feedback de quem trabalha com contact center, QA, compliance e integrações.

TL;DR

  • FalaAI transforma conversas (áudio, texto, export de WhatsApp) em diagnóstico estruturado e auditoria de risco, com relatório HTML que cita o trecho literal e o timestamp.
  • Mesma conta e mesmos créditos para três interfaces: API REST, Studio (navegador, sem código) e MCP (Claude Code, VS Code, Cursor, Gemini CLI).
  • Saída com schema JSON fixo e taxonomia fechada (30 categorias, 79 subcategorias), para a mesma conversa gerar o mesmo formato sempre.
  • Zero-Storage: áudio, texto e resultado são processados e descartados.
  • SDKs oficiais (MIT) em 7 linguagens: Python, Node, PHP, Go, Ruby, Java e .NET.

🎬 Demo em vídeo (1 min 32 s, gravação de tela, sem narração): do export do WhatsApp ao relatório auditável → https://falaai.action.tec.br/videos/falaai-studio-demo.mp4


O problema que me levou a construir isso

Em operações de atendimento, a monitoria de qualidade costuma olhar de 2% a 5% das conversas. Um analista ouve, preenche um formulário e anota. O resultado é que promessa indevida, desvio de script e violação de compliance passam despercebidos na maior parte do volume, e a avaliação fica difícil de defender depois, porque é uma opinião sem evidência.

A ideia do projeto é aplicar a mesma régua a todas as conversas, com evidência literal em cada achado.

Decisões técnicas (e por quê)

1. Saída previsível em vez de texto livre

Colar uma conversa num chat e pedir uma análise funciona, mas, sem restrição de formato e de vocabulário, o formato muda a cada resposta e os rótulos são inventados a cada execução. Isso inviabiliza BI, comparação entre períodos e auditoria. Por isso:

  • a resposta é JSON com schema fixo, documentado em OpenAPI;
  • os rótulos vêm de uma taxonomia fechada (30 categorias, 79 subcategorias);
  • sentimento, motivo e ação (resolvido, escalonado, abandonado etc.) são eixos fechados. Eles enriquecem a análise, mas não alteram o score;
  • o score da auditoria usa regras de negócio dedicadas e se baseia em COPC CX, ISO 18295-1, Kirkpatrick e CES/CSAT, com matriz de ações baseada na ISO 31000. É uma referência de método, não uma certificação.

A taxonomia e os eixos podem ser personalizados em plano sob medida.

2. Pipeline em etapas independentes

flowchart LR
    A["Áudio"] --> T["Transcrição<br/>diarização + eventos sonoros"]
    W["Export do WhatsApp<br/>.zip / .txt"] --> E["Extração de conversas<br/>segmentação"]
    X["Texto ou diálogo<br/>BYOT"]

    T --> D["Diagnóstico<br/>6 análises"]
    T --> R["Auditoria de Risco<br/>score + veredito"]
    E --> D
    E --> R
    X --> D
    X --> R

    T --> S["Saída<br/>JSON estruturado + relatório HTML"]
    D --> S
    R --> S

Formatos de entrada: áudio em mp3, wav, m4a, flac, ogg, webm, aac e opus; export do WhatsApp em .zip ou .txt; texto ou diálogo em .txt, .srt, .vtt e .json.

Cada etapa funciona sozinha. Quem já tem a transcrição (BYOT, bring your own transcript) envia o texto direto e pula a transcrição.

  • Transcrição: diarização por falante e detecção de eventos sonoros (suspiros, risadas, interrupções), com modificadores de intensidade baseados em VAD (Valência, Ativação e Domínio). A auditoria cruza o texto com esses eventos.
  • Extração do WhatsApp: recebe o export, segmenta em conversas e processa mídias (áudios de voz, figurinhas, GIFs, emojis).
  • Diagnóstico: resumo executivo, motivo do contato, ação tomada, classificação por tema, sentimento e identificação de participantes (agente, cliente, bot), tudo numa chamada.
  • Auditoria de Risco: score, detecções por categoria, veredito automático e relatório HTML. Idiomas: pt-BR, en-US e es-ES.

3. Evidência literal no relatório

Cada achado aponta o trecho original com timestamp. O relatório também traz:

  • Turno de virada: o ponto em que o sentimento mudou (ex.: de frustração para hostilidade);
  • Negative Phrase Bank: os termos reais detectados, para você montar seu próprio banco e monitorar reincidência;
  • Matriz de responsabilização: cada achado gera ação recomendada com prioridade.

Exemplos com dados anonimizados:

O relatório é apoio documental técnico. Não é parecer jurídico e não substitui revisão humana.

4. Zero-Storage e suas consequências

Nada do conteúdo é guardado: áudio, texto e resultado são processados e descartados. Ficam só registros de uso e auditoria, sem conteúdo. O lado ruim dessa decisão é que o JSON/HTML que você recebe é o único registro, então quem integra precisa persistir o resultado do seu lado. Em LGPD, o cliente é o controlador e a Action Tec Brasil é a operadora.

5. Resposta síncrona

Cada análise é uma requisição, e a resposta volta na mesma chamada (o tempo cresce com o tamanho da conversa). Isso simplifica a integração (sem polling nem fila), mas significa que não há monitoramento em tempo real, agendamento nem alerta de risco: quem decide quando analisar é você.

6. Cobrança por crédito, não por token

A unidade é algo que o usuário consegue prever antes de chamar:

ServiçoUnidadeMínimo
Transcrição1 crédito por segundo de áudio10
Diagnóstico30 créditos por 1.000 caracteres15
Auditoria de Risco90 créditos por 1.000 caracteres90
Extração WhatsApppor conversa e por mídia (tabela completa na documentação)—

Exemplo: uma conversa de 5 minutos (≈ 4.000 caracteres) consome 780 créditos no fluxo completo (300 + 120 + 360), ou 480 se você já tem a transcrição. No extract_whatsapp do MCP existe dry_run, que estima o custo sem chamar IA e sem cobrar.


Como usar

API

Autenticação por Bearer token (fai_...). O health é público e não consome crédito:

curl -fsS https://api01-falaai.action.tec.br/v1/health

Fluxo mínimo:

  1. POST /v1/audio/transcriptions para transcrever o áudio;
  2. POST /v1/analyze/diagnostic para o diagnóstico em JSON;
  3. POST /v1/analyze/riskAudit para a auditoria completa.

Schemas completos: https://api01-falaai.action.tec.br/docs · Quickstart: https://falaai.action.tec.br/pt/api/quickstart

SDKs oficiais (MIT):

LinguagemInstalação
Pythonpip install falaai-api
Node / TypeScriptnpm install falaai-api
PHPcomposer require actiontecbr/falaai-api
Gogo get github.com/actiontecbr/falaai-api-go
Rubygem install falaai-api
Javaio.github.actiontecbr:falaai-api (Maven Central)
.NETdotnet add package FalaAI.Api

Webhooks de assinatura e crédito

Eventos como subscription.created, credits.low, credits.exhausted e payment.failed chegam por e-mail e por webhook assinado. O header FalaAI-Signature traz t=<unix_int>,v0=<assinatura>, com HMAC-SHA256 de "<t>.<corpo_cru>" usando o seu secret. O t é o horário do disparo, em segundos, e é independente do timestamp dentro do JSON. Para aceitar, recompute o HMAC e confira que o t está dentro de 5 minutos: sem essa janela, uma requisição capturada pode ser reenviada depois (replay). O retry usa backoff exponencial, com até 5 tentativas; depois de 5 falhas seguidas o webhook é desativado. (1)

Esboço de verificação em Python (1) (confira o formato exato na documentação):

import hmac, hashlib, time

TOLERANCIA = 300  # segundos

def assinatura_valida(header: str, body: bytes, secret: str) -> bool:
    partes = dict(p.split("=", 1) for p in header.split(",") if "=" in p)
    t, v0 = partes.get("t"), partes.get("v0")
    if not t or not v0 or not t.isdigit():
        return False
    if abs(time.time() - int(t)) > TOLERANCIA:
        return False
    esperado = hmac.new(secret.encode(), f"{t}.".encode() + body, hashlib.sha256).hexdigest()
    return hmac.compare_digest(esperado, v0)

O t é o horário do disparo e entra no material assinado ("<t>.<body>"), então não pode ser falsificado: é o que permite recusar replay comparando com o relógio. O retry reusa o mesmo t. (1)

Os webhooks são de assinatura e crédito, não de risco.

MCP: as tools dentro do assistente

O MCP expõe o mesmo motor da API com outro contrato: o assistente descobre as tools, escolhe qual chamar e recebe o resultado no contexto, sem você escrever HTTP.

Endpoint: https://mcp-falaai.action.tec.br/mcp (mesmo Bearer fai_...). Guia de configuração por cliente e detalhes das tools: https://falaai.action.tec.br/pt/mcp

ToolO que faz
healthTesta a conexão (grátis, sem chave)
transcribe_audioÁudio → transcrição com diarização e eventos sonoros
diagnosticDiagnóstico estruturado da conversa
risk_auditScore, detecções, veredito e relatório HTML
extract_whatsappSegmenta o export do WhatsApp em conversas (dry_run estima sem cobrar)

Exemplo no Claude Code (.mcp.json):

{
  "mcpServers": {
    "falaai": {
      "type": "http",
      "url": "https://mcp-falaai.action.tec.br/mcp",
      "headers": { "Authorization": "Bearer fai_..." }
    }
  }
}

VS Code, Cursor e Gemini CLI usam a mesma URL e o mesmo header Authorization; só muda o nome do arquivo e de algumas chaves, e isso varia entre versões, então vale conferir a página do MCP (https://falaai.action.tec.br/pt/mcp) e a documentação de cada cliente.

Limitação de design: não existe tool de lote (análise em lote e assíncrona está planejada), então N conversas significam N chamadas. Para auditar uma pasta de gravações, o agente lê a pasta (isso é do cliente MCP, não da FalaAI), transcreve cada áudio e roda risk_audit em cada um.

Limitação de design: o upload viaja dentro do contexto (1). transcribe_audio e extract_whatsapp recebem o arquivo como file_base64, e o MCP não tem upload fora de banda: quem preenche o argumento é o modelo, então os bytes passam pelo contexto do assistente. Base64 é cerca de 1,33x o arquivo e uns 4 caracteres por token, ou seja, 1 minuto de MP3 a 64 kbps (~480 KB) custa por volta de 160 mil tokens. Somando a isso, o corpo da requisição MCP é limitado a 64 MB (uns 45 MB de arquivo), bem abaixo do 1 GB do REST. Na prática: áudio curto vai bem pelo MCP; gravação longa deve ir por POST /v1/audio/transcriptions (multipart, fora do contexto) e o MCP entra só na análise, ou direto em diagnostic/risk_audit com a transcrição pronta (BYOT). Upload assinado, com a tool recebendo apenas um id, é o próximo passo do MCP.

Integrações

Se a conversa vira texto ou áudio, a API analisa. Hoje a integração é via API, SDK, MCP ou adaptador sob medida. Conectores nativos de CRM e PABX ainda estão no roadmap. O que já foi testado em produção (3CX, DirectCall, Asterisk) e o que só está documentado (ex.: Twilio) está separado no site.


O que a FalaAI não faz

  • Não armazena o conteúdo das conversas nem o resultado.
  • Não monitora em tempo real nem agenda análises.
  • Não envia alerta de risco.
  • Não substitui revisão humana nem parecer jurídico.
  • Ainda não tem conectores nativos de ingestão (CRM, PABX).

O que eu aprendi construindo

Listas de termos não convergem. Minha primeira tentativa foi análise semântica clássica, com termos específicos de auditoria por categoria. O problema é que, a cada rodada de testes, apareciam termos novos que a lista não cobria. O vocabulário nunca fechava e a manutenção virava uma corrida sem fim. Por isso migrei para um LLM generativo, que interpreta o sentido da frase em vez de depender de uma lista. Para não perder previsibilidade, ele classifica dentro de uma taxonomia fechada e de um schema fixo, as decisões descritas acima.

De onde vieram as categorias. As 30 categorias e 79 subcategorias foram definidas depois de analisar vários estudos acadêmicos e abordagens de análise de linguagem natural usadas hoje em LLMs.

O que ainda falta: lote e assíncrono. Hoje cada análise é uma chamada síncrona e não existe tool de lote. Isso pesa principalmente na auditoria de risco, que leva em média cerca de 12,6 s por chamada (números abaixo): tolerável para uma conversa, incômodo para grandes volumes ou clientes com timeout curto. Processamento em lote e assíncrono é a próxima evolução que pretendo implementar.

Números de operação hoje

A página de status é pública e atualiza a cada 60 segundos: https://falaai.action.tec.br/pt/api/status. Um retrato de 28/10/2026, 13h (Brasília):

  • Disponibilidade (30 dias): 100%, medida por monitor externo (UptimeRobot), com 0 incidentes. A meta de SLA é 99,9%.
  • Latência fim-a-fim (24 h): média de 1.140 ms, mínima de 343 ms e máxima de 3.873 ms.
  • Taxa de erro 5xx: 0,572% (métrica interna, extraída dos logs da API).
  • Tempo médio por endpoint:
EndpointTempo médio
POST /v1/audio/transcriptions488 ms a cada 10 s de áudio
POST /v1/analyze/diagnostic1.521 ms a cada 1.000 caracteres
POST /v1/analyze/riskAudit12.646 ms

Esses números mudam, então confira a página para os valores atuais.

Status e o que eu busco

A API e o Studio já estão no ar, e há um plano gratuito de teste (2.000 créditos, sem cartão) compartilhado entre os três produtos. Isso dá para cerca de 2 conversas de 5 minutos no fluxo completo, ou 4 se você já tiver a transcrição. Ainda não tenho cases públicos nem depoimentos de clientes, então este post é, de verdade, um pedido de feedback:

  • Quem trabalha com QA/contact center: a taxonomia e o formato do relatório fazem sentido na sua operação?
  • Quem integra: o que falta no contrato da API, nos SDKs ou nas tools do MCP?
  • Qual integração você gostaria de ver primeiro como conector nativo?

Se você testar, me conta nos comentários o que funcionou e o que quebrou.


Revisão 1 — 28/10/2026, 16:42 (Brasília): os trechos marcados com (1) foram corrigidos depois da publicação.

  1. Webhooks — parágrafo de assinatura: header agora explicado como t=<unix_int>,v0=<assinatura>, HMAC-SHA256 de "<t>.<corpo_cru>", t independente do timestamp do JSON e exigência da janela de 5 minutos contra replay.
  2. Webhooks — esboço em Python: passou a validar o t (janela de 300 s) e a comparar com hmac.compare_digest; antes só recomputava o HMAC.
  3. Webhooks — nota abaixo do código: registra que o t entra no material assinado e que o retry reusa o mesmo t.
  4. MCP — limitação de upload: documentado que o arquivo vai como file_base64 e atravessa o contexto do modelo, com o teto real de 64 MB do transporte (~45 MB de arquivo) contra o 1 GB do REST, e os caminhos para arquivo longo (multipart ou BYOT).

Alterações motivadas pelos apontamentos de @plugandship.

Carregando publicação patrocinada...
1

Fiquei com uma dúvida no MCP remoto: como o transcribe_audio recebe o arquivo? O servidor não enxerga o disco de quem usa, então se o áudio entrar como base64 no argumento da tool ele passa pelo contexto do modelo, e poucos minutos de áudio já viram muito mais token do que cabe. Um jeito comum é a tool devolver uma URL de upload assinada, o agente sobe o arquivo com curl e depois chama a análise passando só o id.

No esboço de verificação do webhook eu incluiria a checagem do t, recusando timestamp com mais de uns 5 minutos. Sem isso, quem capturar uma requisição válida consegue reenviar ela depois.

1

@plugandship, os dois pontos procedem.

No transcribe_audio o áudio entra como file_base64 e o servidor converte para multipart internamente, então o conteúdo passa pelo contexto do modelo mesmo. Sua conta está certa: base64 é ~1,33x os bytes e ~4 caracteres por token, então 1 min de MP3 a 64 kbps (480 KB) já dá 160 mil tokens. É limitação de design do MCP remoto (argumento de tool é JSON, binário só entra como base64 ou como referência) — e, somando, o body do MCP é limitado a 64 MB, bem abaixo do 1 GB do REST. Documentei isso no post: para arquivo longo, o caminho é o multipart do REST, ou enviar a transcrição pronta (BYOT) e usar só diagnostic/risk_audit. Upload assinado, com a tool recebendo apenas um id, é o próximo passo.

No webhook você achou um erro meu: o exemplo só recomputava o HMAC e não validava o t. Corrigi no post — agora recusa fora da janela de 5 minutos, e o t entra no material assinado ("."), então não é falsificável. O retry reusa o mesmo t, então a janela não quebra retry legítimo. Se o receptor executa ação a partir do evento, vale deduplicar por (event, timestamp do payload) também.

Obrigado pelo review — as duas correções estão registradas na Revisão 1 no final do post.