Mensagens de voz

Uma mensagem de voz chega como texto. A transcrição acontece à entrada, antes de o agente correr.

Mensagens de voz

Envia uma mensagem de voz ao teu bot do Telegram e o agente recebe texto. O áudio é transcrito à chegada, antes de existir uma sessão e antes de qualquer decisão de encaminhamento, por isso o que chega ao agente é uma mensagem vulgar.

Nem sempre foi assim. O gateway gravava o ficheiro na área de trabalho do agente e entregava-lhe o caminho, deixando-o descobrir sozinho como escutar: encontrar um transcritor, instalá-lo, executá-lo, ler o resultado. Cada mensagem de voz tornava-se um pequeno projeto de investigação. Era lento, saía diferente de cada vez, e gastava uma barreira de permissão só para ler a mensagem que acabara de chegar.

Nada para configurar

Se já tens uma ligação de modelo à OpenAI ou à Groq, a transcrição já funciona. O Pepe reaproveita essa credencial e pede ao provider o modelo de transcrição dele (whisper-1 na OpenAI, whisper-large-v3-turbo na Groq) em vez do modelo de chat com que a ligação foi configurada. Envia uma mensagem de voz e ela é respondida. Não há nada a definir.

Como a rota é escolhida

O Pepe tenta estas rotas por esta ordem, e qualquer uma delas pode não existir:

  1. media.audio.model: uma ligação de modelo, referida pelo nome. A cadeia de fallbacks dessa ligação também se aplica aqui, por isso o failover não custa nada de extra.
  2. media.audio.command: um comando local, por exemplo whisper-cli -f {file}. O {file} é substituído pelo caminho do áudio. Isto é tentado antes da deteção automática, de propósito: quem configurou um transcritor local fê-lo para o áudio não sair da máquina, e passar-lhe à frente para chamar um provider derrotaria o objetivo.
  3. Deteção automática: a rota sem configuração descrita acima.
  4. Nada disponível: o ficheiro vai para o agente, que se desenrasca com as ferramentas que tem. Esse caminho fica como rede de segurança; não é a porta de entrada.

Configurar isto

Aponta a transcrição para uma ligação de modelo específica, ou um comando local, pela CLI:

pepe media audio --model groq --language pt --echo true
pepe media audio --command "whisper-cli -f {file}"   # mantém o áudio na máquina
pepe media audio off                                 # volta à deteção automática

--echo true devolve a transcrição ao chat, para quem falou ver o que foi entendido. As mesmas opções estão na página Config do painel, e no pepe setup em Media.

Porque é que transcrever primeiro faz diferença

Como as palavras existem antes de o encaminhamento correr, o encaminhamento consegue lê-las. Daqui saem duas consequências, nenhuma delas possível enquanto a transcrição só aparecia dentro do turno do agente:

Áudio torna-se texto; fotografia torna-se visão. A fala é transcrita logo à porta. Uma fotografia é enviada ao modelo como uma imagem que ele consegue mesmo ver (num modelo com visão, veja abaixo). Um documento é extraído para texto.

Responder de volta

Responde a uma mensagem de voz com outra mensagem de voz. Desligado por predefinição; aponta media.tts para uma ligação de modelo que sirva um /audio/speech compatível com OpenAI e liga-se:

pepe media tts --model openai --voice nova
pepe media tts off

A resposta em texto continua a ser o registo que fica guardado. O áudio é um extra, e tem um limite de tamanho para uma resposta longa nunca se tornar um clip de cinco minutos. Uma falha no TTS é silenciosa: a resposta em texto já foi enviada, por isso nada se perde, só não ganha voz nesse turno. As mesmas opções estão na página Config do painel, e no pepe setup em Media.

Fotografias

Envie uma fotografia ao seu bot do Telegram e, num modelo com visão, o agente vê a imagem de verdade, não um nome de ficheiro. Antes recebia apenas uma linha de texto (“o utilizador enviou uma fotografia, guardada em ”) enquanto a própria imagem nunca chegava ao modelo, pelo que o agente ficava a adivinhar, ou a inventar, o que lá estava. Agora a imagem segue juntamente com a mensagem.

Fica desligado a menos que diga que o modelo enxerga. Nem todos os endpoints compatíveis com a OpenAI aceitam uma imagem, e enviar uma para um modelo só de texto é um erro, por isso a visão é opcional por ligação:

{
  "models": {
    "gpt4o": {
      "base_url": "https://api.openai.com/v1",
      "api_key": "${OPENAI_API_KEY}",
      "model": "gpt-4o",
      "vision": true
    }
  }
}

Com vision ativo, uma fotografia (com ou sem legenda) chega ao modelo como imagem no turno em que é recebida. Funciona da mesma forma em ligações compatíveis com a OpenAI, Anthropic e Responses/Codex. A imagem acompanha apenas esse turno: como uma transcrição, o registo que fica é a resposta do agente sobre ela, não os bytes, pelo que nunca incha a sessão nem é reenviada a cada turno. Um modelo sem vision volta ao comportamento antigo (o caminho do ficheiro no prompt, para o agente abrir com as suas próprias ferramentas).

O Telegram já envia cada fotografia em vários tamanhos pré-redimensionados, por isso o Pepe escolhe o maior que cabe no teto de bytes, sem qualquer biblioteca de processamento de imagem para instalar. Um álbum de fotografias é enviado como várias imagens em conjunto. Os limites ficam em media.image e ambos têm predefinições:

{
  "media": {
    "image": { "max_mb": 5, "max_parts": 4 }
  }
}

Configuração

Todas as chaves são opcionais e vivem em media.audio, no ~/.pepe/config.json:

{
  "media": {
    "audio": {
      "model": "groq",
      "language": "pt",
      "max_mb": 20,
      "timeout": 60,
      "echo": true
    }
  }
}

Para manter o áudio na máquina, usa um comando em vez de uma ligação:

{
  "media": {
    "audio": {
      "command": "whisper-cli -f {file}",
      "timeout": 120
    }
  }
}

Salvaguardas