Production passes student audio as a URL to an object in a bucket, but no URL reaches transcription today. There are two separate failures.
1. The extension check does not survive a query string. is_audio_input calls os.path.splitext on the whole string, so a presigned URL reads as .wav?X-Amz-Signature=..., which is not in AUDIO_EXTENSIONS:
https://x.com/rec.wav -> detected as audio
https://x.com/rec.wav?sig=abc -> not detected
An undetected URL falls through to json.loads() in prepare_input, which raises JSONDecodeError out of evaluation_function — a 500 rather than a feedback message. preview.py repeats the same splitext and shows "This submission could not be read as MIDI", so the student sees a confusing preview and then a server error on submit.
2. Even a detected URL cannot be read. transcribe_audio hands the string to Basic Pitch, which calls librosa.load(str(audio_path)). librosa 0.11 dropped the audioread fallback, so soundfile tries to open the URL as a local file path and fails. Fixing only the extension check would move the failure, not remove it.
Minimal fix
- Parse the extension from the URL path, not the raw string, so query strings and fragments are ignored. Local paths go through the same helper unchanged.
- Download a URL to a temporary file before transcription and remove it afterwards.
preview.py shows os.path.basename(response), which for a presigned URL prints the whole signature back to the student. Use the URL path's base name.
Out of scope for now: caching, retries, size limits, content-type sniffing, and any allowlist on the fetched host.
Production passes student audio as a URL to an object in a bucket, but no URL reaches transcription today. There are two separate failures.
1. The extension check does not survive a query string.
is_audio_inputcallsos.path.splitexton the whole string, so a presigned URL reads as.wav?X-Amz-Signature=..., which is not inAUDIO_EXTENSIONS:An undetected URL falls through to
json.loads()inprepare_input, which raisesJSONDecodeErrorout ofevaluation_function— a 500 rather than a feedback message.preview.pyrepeats the samesplitextand shows "This submission could not be read as MIDI", so the student sees a confusing preview and then a server error on submit.2. Even a detected URL cannot be read.
transcribe_audiohands the string to Basic Pitch, which callslibrosa.load(str(audio_path)). librosa 0.11 dropped the audioread fallback, so soundfile tries to open the URL as a local file path and fails. Fixing only the extension check would move the failure, not remove it.Minimal fix
preview.pyshowsos.path.basename(response), which for a presigned URL prints the whole signature back to the student. Use the URL path's base name.Out of scope for now: caching, retries, size limits, content-type sniffing, and any allowlist on the fetched host.