Skip to content

[Feature Request / Bug]: Support non-WAV / browser audio uploads (WebM/Opus, MP3, OGG) on /v1/audio/transcriptions for Open WebUI compatibility #313

Description

@ampersandru

Description

Currently, the POST /v1/audio/transcriptions endpoint strictly expects raw WAV PCM audio uploads (RIFF....WAVE header).

When integrating audio.cpp with popular web clients like Open WebUI, transcription fails because modern web browsers (Chrome, Edge, Firefox, Safari) using the HTML5 MediaRecorder API record microphone input in audio/webm;codecs=opus (or audio/ogg). Browsers do not support recording native WAV via MediaRecorder.

As a result, sending microphone recordings from Open WebUI to any ASR model (e.g. parakeet_tdt, granite5asr, whisper) fails with:
Error transcribing chunk: External: 500, message='Internal Server Error', url='http://:8080/v1/audio/transcriptions'

In contrast, clients that buffer and convert audio to WAV beforehand (such as Home Assistant via wyoming_openai or curl -F file=@sample.wav) succeed with exceptional sub-30ms latency.


Steps to Reproduce

  1. Start audiocpp_server with any ASR model (e.g., parakeet_tdt or granite5asr):
    {
      "models": [
        {
          "id": "parakeet_tdt",
          "family": "parakeet_tdt",
          "path": "/models/parakeet-tdt-0.6b-v3-q8_0.gguf",
          "task": "asr",
          "mode": "offline"
        }
      ]
    }
    
  2. In Open WebUI (Admin Settings ➔ Audio):
  • Set Speech-to-Text Engine: OpenAI
  • Set API Base URL: http://:8080/v1
  • Set STT Model: parakeet_tdt
  1. Click the microphone button in Open WebUI chat to record speech.
  2. Open WebUI fails with HTTP 500.

Root Cause

handle_transcription_multipart in app/server/runtime.cpp checks is_wav_upload_filename and directly parses bytes using engine::audio::read_wav_f32(), rejecting .webm, .mp3, .ogg, and .m4a files.
When browsers send MediaRecorder chunks or blobs (often named audio.webm or blob), the server throws an unhandled exception or returns a 400/500 error instead of decoding the compressed audio stream.

Suggested Fixes & Solutions

Solution 1: Lightweight In-Tree Decoders (Recommended)

Embed header-only C/C++ audio decoders (similar to how ggml or llama.cpp bundle dependencies) so audio.cpp remains self-contained without external runtime dependencies:

miniaudio (Public Domain / MIT, single-file) — handles MP3, FLAC, WAV, and Vorbis decoding natively.
opusfile / libopus — decodes WebM/Ogg Opus streams directly to 16 kHz float32 PCM in memory.

Solution 2: Optional Server-Side Transcoder Bridge

If external tools are acceptable when present, allow audiocpp_server to detect and pipe incoming non-WAV multipart bytes through ffmpeg or libavcodec to convert to 16 kHz mono WAV PCM in memory before running inference.

Solution 3: Graceful Handling of Empty / Incomplete Chunks

When MediaRecorder begins recording, the initial chunk may sometimes be 0 bytes or header-incomplete. Returning {"text": ""} (HTTP 200) instead of throwing an unhandled exception ensures the client does not crash before the full audio is delivered.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions