# Áudio persistente, fallback local e streaming — Design ## Objetivo Guardar os 10 áudios mais recentes enviados à transcrição, permitir salvar qualquer um deles em um local escolhido pelo usuário, usar Whisper local em PT-BR quando a API falhar e inserir texto progressivamente quando a API responder em streaming. ## Escopo e decisões ### Histórico de áudio - Cada gravação finalizada permanece no diretório de dados do aplicativo como WAV. - O histórico é limitado a 10 arquivos, ordenados por data de modificação decrescente. Ao finalizar uma gravação, arquivos mais antigos são removidos. - Cada item expõe somente `id` (nome de arquivo validado), nome, tamanho e data. Caminhos absolutos nunca são enviados ao frontend. - O frontend mostra um `
` compacto de “Áudios recentes”, com “Baixar último áudio” e ações de salvar por item. - O salvamento usa o diálogo nativo de arquivo e copia o WAV para a localização escolhida. Cancelar o diálogo não é erro. ### Fallback API → Whisper - O modo de servidor tenta a API configurada primeiro. - Qualquer falha antes de texto parcial aciona Whisper embarcado com idioma fixo `pt`. - Se uma resposta streaming já tiver emitido texto parcial, não há fallback automático: repetir o texto poderia duplicar o que já foi inserido no campo ativo. O erro é mostrado para revisão. - O modo local continua usando Whisper primeiro e API como fallback, preservando o comportamento existente. ### Streaming de resposta - O cliente envia `Accept: text/event-stream, application/x-ndjson, application/json`. - A API é detectada como streaming exclusivamente pelo `Content-Type` da resposta: `text/event-stream` ou `application/x-ndjson`. - Eventos SSE/NDJSON aceitam `delta`, `text`, `transcript`, `result`, `output`, `data` e `choices[0].delta.content`; payloads cumulativos são convertidos em somente o sufixo novo. - Na janela principal, cada fragmento atualiza o editor de transcrição. - No atalho global, o primeiro fragmento esconde a barra não focável e tenta colar imediatamente no campo externo ativo; a transcrição final não é colada uma segunda vez. - Respostas JSON normais mantêm o fluxo atual: texto completo somente após concluir. ## Segurança e limites - IDs de áudio são nomes simples de WAV; separadores de diretório, extensões diferentes e caminhos fora do diretório de gravações são rejeitados. - O backend nunca recebe um destino de arquivo escolhido pelo frontend; o diálogo nativo escolhe o destino e o backend executa a cópia local. - Áudio é dado potencialmente sensível. A retenção fixa em 10 arquivos é deliberada e visível na UI; não há telemetria nem upload adicional. ## Testes - Histórico: limita a 10, remove o mais antigo, rejeita IDs inseguros. - Fallback: API-only usa Whisper PT-BR quando não houve parcial; streaming parcial não dispara fallback. - Streaming: detecta Content-Type, extrai deltas/cumulativos e evita duplicação. - Frontend: renderiza histórico e pede download do item selecionado.