fix(whatsapp-web): strip MIME parameters before matching in audio_mime_to_filename

MIME strings like 'audio/webm; codecs=opus' were incorrectly matched by
the 'opus' branch (contains-check) before reaching the 'webm' branch,
returning 'voice.opus' instead of 'voice.webm'. This could cause the
Groq Whisper API to reject or misidentify the file format.

Fix: split on ';' to extract only the base MIME type, then match
exhaustively. Also add 'audio/x-wav' as a wav alias.

Adds a regression test: audio_mime_to_filename('audio/webm; codecs=opus')
must return 'voice.webm'.

Reported by CodeRabbit in PR review.
This commit is contained in:
Jaime Linares 2026-02-26 18:51:37 -05:00
parent 325241aeb6
commit 84861c727a

View File

@ -232,23 +232,24 @@ impl WhatsAppWebChannel {
/// Map a WhatsApp audio MIME type to a filename accepted by the Groq Whisper API.
///
/// WhatsApp voice notes are typically `audio/ogg; codecs=opus`.
/// MIME parameters (e.g. `; codecs=opus`) are stripped before matching so that
/// `audio/webm; codecs=opus` maps to `voice.webm`, not `voice.opus`.
#[cfg(feature = "whatsapp-web")]
fn audio_mime_to_filename(mime: &str) -> &'static str {
let lower = mime.to_ascii_lowercase();
if lower.contains("ogg") || lower.contains("oga") {
"voice.ogg"
} else if lower.contains("opus") {
"voice.opus"
} else if lower.contains("mp4") || lower.contains("m4a") || lower.contains("aac") {
"voice.m4a"
} else if lower.contains("mpeg") || lower.contains("mp3") {
"voice.mp3"
} else if lower.contains("webm") {
"voice.webm"
} else if lower.contains("wav") {
"voice.wav"
} else {
"voice.ogg"
let base = mime
.split(';')
.next()
.unwrap_or("")
.trim()
.to_ascii_lowercase();
match base.as_str() {
"audio/ogg" | "audio/oga" => "voice.ogg",
"audio/webm" => "voice.webm",
"audio/opus" => "voice.opus",
"audio/mp4" | "audio/m4a" | "audio/aac" => "voice.m4a",
"audio/mpeg" | "audio/mp3" => "voice.mp3",
"audio/wav" | "audio/x-wav" => "voice.wav",
_ => "voice.ogg",
}
}