Fix audio chunking edge cases
This commit is contained in:
parent
b4c2f15297
commit
f008703a6c
|
|
@ -219,13 +219,14 @@ class AudioProcessor:
|
|||
raise ValidationException("Audio upload is empty")
|
||||
|
||||
suffix = self.get_output_suffix(filename, content_type)
|
||||
normalized_filename = self.ensure_audio_filename(filename, suffix)
|
||||
duration_seconds = self._probe_audio_duration_seconds(content, suffix)
|
||||
|
||||
if (
|
||||
len(content) <= settings.AUDIO.MAX_CHUNK_BYTES
|
||||
and duration_seconds <= settings.AUDIO.MAX_CHUNK_DURATION_SECONDS
|
||||
):
|
||||
return [AudioSegment(index=0, filename=filename, content=content)]
|
||||
return [AudioSegment(index=0, filename=normalized_filename, content=content)]
|
||||
|
||||
segment_count = self._estimate_initial_segment_count(
|
||||
duration_seconds=duration_seconds,
|
||||
|
|
@ -253,6 +254,13 @@ class AudioProcessor:
|
|||
return segments
|
||||
|
||||
if duration_seconds / segment_count <= 1.0:
|
||||
if suffix == ".wav":
|
||||
suffix = ".mp3"
|
||||
segment_count = self._estimate_initial_segment_count(
|
||||
duration_seconds=duration_seconds,
|
||||
suffix=suffix,
|
||||
)
|
||||
continue
|
||||
raise FileProcessingError(
|
||||
"Audio segmentation could not satisfy max chunk size"
|
||||
)
|
||||
|
|
@ -347,6 +355,12 @@ class AudioProcessor:
|
|||
return ".wav"
|
||||
return ".mp3"
|
||||
|
||||
def ensure_audio_filename(self, filename: str, suffix: str) -> str:
|
||||
path = Path(filename)
|
||||
if path.suffix.lower() == suffix:
|
||||
return filename
|
||||
return f"{filename}{suffix}"
|
||||
|
||||
def _probe_audio_duration_seconds(self, content: bytes, suffix: str) -> float:
|
||||
with tempfile.NamedTemporaryFile(suffix=suffix, delete=False) as temp_file:
|
||||
temp_file.write(content)
|
||||
|
|
|
|||
|
|
@ -342,6 +342,71 @@ def test_split_audio_segments_splits_long_wav_when_duration_exceeds_limit():
|
|||
assert all(segment.content for segment in segments)
|
||||
|
||||
|
||||
def test_split_audio_segments_normalizes_small_mime_only_audio_filename():
|
||||
processor = AudioProcessor()
|
||||
|
||||
original_duration_limit = settings.AUDIO.MAX_CHUNK_DURATION_SECONDS
|
||||
original_chunk_bytes = settings.AUDIO.MAX_CHUNK_BYTES
|
||||
settings.AUDIO.MAX_CHUNK_DURATION_SECONDS = 60
|
||||
settings.AUDIO.MAX_CHUNK_BYTES = 1024
|
||||
try:
|
||||
with patch.object(
|
||||
processor,
|
||||
"_probe_audio_duration_seconds",
|
||||
return_value=0.5,
|
||||
):
|
||||
segments = processor.split_audio_segments(
|
||||
b"audio-bytes",
|
||||
filename="blob",
|
||||
content_type="audio/mpeg",
|
||||
)
|
||||
finally:
|
||||
settings.AUDIO.MAX_CHUNK_DURATION_SECONDS = original_duration_limit
|
||||
settings.AUDIO.MAX_CHUNK_BYTES = original_chunk_bytes
|
||||
|
||||
assert len(segments) == 1
|
||||
assert segments[0].filename == "blob.mp3"
|
||||
|
||||
|
||||
def test_split_audio_segments_falls_back_to_mp3_when_wav_floor_exceeds_byte_limit():
|
||||
processor = AudioProcessor()
|
||||
|
||||
original_duration_limit = settings.AUDIO.MAX_CHUNK_DURATION_SECONDS
|
||||
original_chunk_bytes = settings.AUDIO.MAX_CHUNK_BYTES
|
||||
settings.AUDIO.MAX_CHUNK_DURATION_SECONDS = 60
|
||||
settings.AUDIO.MAX_CHUNK_BYTES = 200_000
|
||||
build_segments = [
|
||||
[AudioSegment(index=0, filename="segment_000.wav", content=b"x" * 200_001)],
|
||||
[AudioSegment(index=0, filename="segment_000.mp3", content=b"x" * 10)],
|
||||
]
|
||||
try:
|
||||
with (
|
||||
patch.object(
|
||||
processor,
|
||||
"_probe_audio_duration_seconds",
|
||||
return_value=1.0,
|
||||
),
|
||||
patch.object(
|
||||
processor,
|
||||
"_build_audio_segments",
|
||||
side_effect=build_segments,
|
||||
) as mock_build,
|
||||
):
|
||||
segments = processor.split_audio_segments(
|
||||
b"x" * 200_001,
|
||||
filename="clip.wav",
|
||||
content_type="audio/wav",
|
||||
)
|
||||
finally:
|
||||
settings.AUDIO.MAX_CHUNK_DURATION_SECONDS = original_duration_limit
|
||||
settings.AUDIO.MAX_CHUNK_BYTES = original_chunk_bytes
|
||||
|
||||
assert len(segments) == 1
|
||||
assert segments[0].filename.endswith(".mp3")
|
||||
assert mock_build.call_args_list[0].kwargs["suffix"] == ".wav"
|
||||
assert mock_build.call_args_list[1].kwargs["suffix"] == ".mp3"
|
||||
|
||||
|
||||
def test_split_audio_segments_raises_validation_for_invalid_audio_bytes():
|
||||
processor = AudioProcessor()
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue