Traverba: Um App Flutter com 3 Modelos de ASR, um LLM Local e OCR por Câmera — Tudo no Dispositivo

Desenvolvi o Traverba — um tradutor em tempo real que funciona 100% no seu celular, sem APIs na nuvem. Reconhecimento de voz, tradução em 108 idiomas, OCR por câmera em 92 sistemas de escrita, sobreposição de tradução de tela, transcrição de arquivos e chat em grupo offline via Bluetooth para até 7 pessoas.

O app inteiro foi construído com Flutter + código nativo para as tarefas mais pesadas. Aqui está o que o app faz, por que o Flutter foi a escolha certa, e os maiores desafios que enfrentei ao lançá-lo em produção para iOS e Android.

O Que o App Faz

O Traverba tem cinco funcionalidades principais, todas funcionando offline:

Tradução de Voz ao Vivo — Fale em um idioma e ouça e leia a tradução em outro. Três modos: dentro do app, captura de áudio do sistema em sobreposição flutuante (traduz áudio do Zoom/Teams/Meet) e microfone flutuante. Leitura automática em voz alta no idioma de destino.

Tradução por Câmera — Aponte a câmera para um cardápio, placa, formulário ou documento. Dois mecanismos de OCR: modo Basic (ML Kit) para leituras ágeis, e modo Professional (PaddleOCR) para scripts complexos como CJK, árabe, cirílico e Devanagari. Suporta 92 idiomas. O app substitui o texto estrangeiro pelo texto traduzido diretamente na imagem.

Tradução de Tela — Uma sobreposição flutuante que traduz texto dentro de qualquer app. Assistindo a anime, lendo notícias em coreano, jogando um jogo japonês ou recebendo uma mensagem no WeChat? Toque no botão de sobreposição e o texto é traduzido no lugar. Sem trocar de app.

Transcrição de Arquivos — Importe arquivos de áudio ou vídeo (mp3, m4a, wav, mp4) e obtenha transcrições com marcação de tempo, com o texto original e a tradução lado a lado.

Chat em Grupo Offline — Até 7 pessoas se conectam via malha Bluetooth. Cada pessoa fala no seu idioma. Cada mensagem é traduzida para o idioma de todos os participantes em tempo real. Sem internet. Sem servidor. Cada celular processa seu próprio ASR e tradução de forma independente.

Tudo isso roda localmente no processador do celular. Sem chaves de API, sem custos de servidor, sem dados saindo do dispositivo.

Por Que Flutter

Avaliei Flutter, React Native e desenvolvimento totalmente nativo (codebases separadas em Swift + Kotlin) no início do projeto.

Uma base de código multiplataforma era inegociável. Um desenvolvedor solo mantendo duas codebases nativas para um app tão complexo simplesmente não era viável. A camada de UI em Dart — configurações, bolhas de chat, visualizações de transcrição, tour de onboarding, telas de download, seletores de idioma — corresponde a aproximadamente 60% do código total. Escrever tudo isso duas vezes teria dobrado o tempo de desenvolvimento.

O sistema de canais de plataforma do Flutter tornou a integração nativa prática. O trabalho mais pesado de IA (inferência de ASR, tradução por LLM, OCR, malha Bluetooth, sobreposições flutuantes) roda em Swift/Kotlin nativos por meio de canais de plataforma e canais de método. O Flutter não tenta ser o runtime de IA — ele é a camada de UI e orquestração que conecta os motores nativos.

O desempenho foi suficientemente bom. A preocupação com o Flutter para esse tipo de app é a sobrecarga — cada milissegundo importa quando você está encadeando ASR → tradução → TTS em uma conversa. Na prática, a camada Flutter adiciona latência negligível porque o processamento pesado acontece no código nativo. A camada Dart gerencia estado, roteamento e atualizações de UI — tarefas que ela executa bem.

O hot reload acelerou drasticamente a iteração de UI. Com cinco superfícies de funcionalidade distintas (voz, câmera, tela, arquivo, chat em grupo), cada uma com múltiplos estados e modos, a capacidade de iterar na UI sem precisar recompilar foi um multiplicador de produtividade significativo.

A Arquitetura: Flutter como Orquestrador

O app segue uma divisão clara de responsabilidades:

A camada Flutter/Dart gerencia:

  • Toda a UI (Material 3, layouts adaptativos para celular e tablet)
  • Gerenciamento de estado e roteamento de funcionalidades
  • Seleção de idioma/localidade e preferências do usuário
  • Gerenciamento de downloads para modelos opcionais
  • Economia de moedas e controle de assinatura
  • Tour guiado de onboarding

A camada nativa gerencia (via canais de plataforma):

  • Inferência de ASR (sherpa-onnx / whisper.cpp)
  • Tradução por LLM (Gemma via runtime no dispositivo)
  • Tradução por ML tradicional (modelos NMT em ONNX)
  • OCR por câmera (ML Kit + PaddleOCR)
  • Síntese de voz (text-to-speech)
  • Malha Bluetooth para chat em grupo
  • Sobreposição flutuante (tradução de tela + captura de áudio do sistema)
  • Gerenciamento de orçamento de memória e carregamento/remoção de modelos

A ponte entre essas camadas é um conjunto de canais de plataforma com contratos bem definidos. O lado Dart envia comandos ("iniciar ASR para cantonês", "traduzir este texto do japonês para inglês", "capturar tela e fazer OCR"). O lado nativo retorna os resultados de forma assíncrona.

Três Modelos de ASR, Roteamento Automático

Nenhum modelo de reconhecimento de voz sozinho cobre bem todos os idiomas. Em vez de aceitar baixa qualidade para alguns idiomas, o app inclui três modelos especializados:

  • Parakeet Otimizado para inglês. Incluído no app para ASR em inglês instantâneo, sem necessidade de download.
  • Whisper.cpp Ampla cobertura multilíngue em mais de 30 idiomas.
  • Qwen3-ASR Otimizado para CJK com suporte dedicado ao cantonês.

Quando o usuário seleciona um idioma de origem, a camada de roteamento Dart escolhe o melhor modelo e instrui o lado nativo sobre qual motor ativar. O usuário nunca vê nem gerencia a seleção de modelos.

A parte complicada é a memória. Esses modelos variam de 500MB a 1,9GB em RAM. Carregar os três simultaneamente travaria a maioria dos celulares. Um planejador de orçamento de memória (escrito em Dart, consultando estatísticas de memória nativas) rastreia o que está carregado e remove o modelo usado menos recentemente quando um novo precisa ser carregado. Um armazenamento de preferência de backend registra qual backend de computação (NPU, GPU, CPU) funcionou em cada dispositivo específico, para que execuções subsequentes pulem backends com falha.

108 Idiomas em Dois Níveis de Tradução

A tradução acontece por dois caminhos:

Nível 1 — Modelos NMT tradicionais (61 idiomas): Rápidos, com baixo consumo de memória e boa qualidade para pares de idiomas com bastante recursos. Modelos ONNX rodando via sherpa-onnx em ambas as plataformas.

Nível 2 — Gemma LLM no dispositivo (47 idiomas adicionais): Para idiomas sem modelos NMT dedicados (Iorubá, Amárico, Laosiano, Birmanês e outros), um modelo Gemma 2B quantizado realiza a tradução localmente. Mais lento que o Nível 1, mas amplia a cobertura para idiomas que os modelos tradicionais atendem mal.

A camada Dart decide qual nível usar com base no par de idiomas. O usuário tem uma experiência unificada.

OCR por Câmera: Motor Duplo, 92 Idiomas

A tradução por câmera usa dois motores selecionáveis pelo usuário:

Modo Basic usa o reconhecimento de texto no dispositivo do Google ML Kit. Ágil, lida bem com latim, cirílico e CJK. Ideal para uso em tempo real no visor.

Modo Professional usa o PaddleOCR rodando no dispositivo. Maior precisão para layouts complexos, scripts mistos, texto curvo e baixo contraste. Utiliza um sistema de moedas (5 moedas por captura) por ser mais intensivo em processamento.

Uma lição aprendida da forma difícil: o iOS inclui apenas o modelo de script Latin do OCR por padrão. CJK, Devanagari e árabe exigem a adição explícita de pods específicos de script ao Podfile. A falha é completamente silenciosa — o ML Kit retorna resultados vazios para scripts não suportados, sem nenhum erro. Se você estiver desenvolvendo OCR multilíngue no iOS com ML Kit, verifique seu Podfile.

Sobreposição Flutuante: Nativa, Não Flutter

As funcionalidades de tradução de tela e áudio do sistema rodam como sobreposições nativas fora da superfície de renderização do Flutter. No Android, é um serviço de sobreposição do sistema escrito em Kotlin. No iOS, usa APIs de captura de tela em Swift.

Essas sobreposições se comunicam de volta ao motor de tradução do Flutter via canais de plataforma. O desafio arquitetural é o gerenciamento de ciclo de vida — a sobreposição deve permanecer ativa enquanto a activity Flutter principal pode estar em segundo plano.

Uma lição crítica: no iOS, instâncias de bridge nativas devem ser fortemente retidas (estáticas ou mantidas por um singleton). Se a bridge for uma variável de instância que nada retém, o ARC vai coletá-la como lixo e todos os closures de handler silenciosamente se tornam no-ops. Perdi dias com um indicador de progresso de download travado em 0% porque a bridge estava sendo coletada. Sem crash, sem erro, apenas falha silenciosa.

Chat em Grupo via Bluetooth

O chat em grupo offline usa um protocolo de malha Bluetooth. Cada celular atua como receptor e repetidor simultaneamente. As mensagens são transmitidas para todos os dispositivos conectados. Cada dispositivo executa seu próprio ASR e tradução de forma independente — não há celular "host" ou "servidor".

O Flutter gerencia a UI do chat, o estado das mensagens e o gerenciamento de participantes. A pilha Bluetooth é totalmente nativa (CoreBluetooth no iOS, API Bluetooth do Android) com bridge via canais de plataforma.

A latência total do pipeline (voz → ASR → tradução → transmissão → exibição) é de cerca de 1 segundo. A UI em Dart usa exibição otimista (mostra "traduzindo..." imediatamente ao enviar) para que a conversa pareça responsiva.

Números

  • Idiomas: 108 no total (61 ML + 47 IA)
  • Idiomas de ASR: 30 com reconhecimento de voz no dispositivo
  • Idiomas de OCR: 92 com reconhecimento de texto por câmera
  • Tamanho base do app: ~150MB + modelos baixáveis
  • Plataformas: iOS + Android a partir de uma única base de código Flutter
  • Código Dart/Flutter: ~60% do total (UI, estado, roteamento, lógica de negócios)
  • Código nativo: ~40% (ASR, LLM, OCR, Bluetooth, sobreposições, gerenciamento de memória)
  • Tamanho da equipe: 1

O Que o Flutter Acertou Neste Projeto

Base de código única para UI complexa. Cinco superfícies de funcionalidade, múltiplos modos cada, telas de download, tour de onboarding, layouts adaptativos — escrever isso uma vez em vez de duas vezes foi a diferença entre lançar ou não lançar como desenvolvedor solo.

Os canais de plataforma são bem projetados. A bridge entre Dart e código nativo é limpa, bem documentada e confiável. Para um app onde o processamento pesado é nativo mas a experiência do usuário é Flutter, essa é exatamente a arquitetura certa.

Hot reload para iteração rápida. Ajustar layouts, testar estados, iterar em fluxos de UX — o hot reload reduziu o tempo de iteração de minutos para segundos ao longo de centenas de mudanças de UI.

O ecossistema é maduro. Gerenciamento de estado (Riverpod), navegação, localização (117 locales), design adaptativo — o ecossistema Flutter tem soluções de qualidade para produção em todas essas áreas.

O Que Foi Difícil

Pressão de memória é o ponto cego do Flutter. O Flutter não expõe controle granular de memória. Quando você está carregando múltiplos modelos de ML nativos em conjunto com o motor Flutter, é necessário gerenciar a memória no nível nativo e expô-la de volta ao Dart. Não há API Flutter integrada para "quanto de RAM meu app está usando" ou "qual é a pressão de memória do sistema".

Ciclo de vida de sobreposição nativa. Sobreposições flutuantes que operam fora da superfície Flutter são arquiteturalmente complexas. A activity Flutter pode estar em segundo plano enquanto a sobreposição está ativa. Manter a bridge ativa, gerenciar a sincronização de estado e lidar com eventos de ciclo de vida específicos de cada plataforma exigiu um volume significativo de código nativo que o Flutter não consegue abstrair.

Complexidade do build no iOS. CocoaPods com pods de script do ML Kit, entitlements (increased-memory-limit para carregar ASR + LLM juntos), timing do App Tracking Transparency, assinatura de código — o pipeline de build do iOS tem muitas peças móveis que o ferramental do Flutter não gerencia completamente.

Experimente

O Traverba é gratuito em ambas as plataformas. Tradução de voz, câmera, tela e texto são todas gratuitas e ilimitadas. O Premium ($1,99/mês) desbloqueia chat em grupo, transcrição de arquivos e resumos de reuniões.

Disponível no Google Play e na App Store. Saiba mais em traverba.com.

Fico feliz em responder perguntas sobre a arquitetura, padrões de integração Flutter + nativo, ou IA no dispositivo em geral.