diff --git a/CHANGELOG.md b/CHANGELOG.md index 364194c1..1ad163df 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,6 +32,7 @@ and this project adheres to - ⬆️(dependencies) update django to v5.2.13 [SECURITY] - 🔒(backend) rely on backend to allow participant update their metadata - 🐛(summary) fix failure webhook notification #1233 +- 🐛(summary) relax whisperX payload format #1233 ## [1.13.0] - 2026-03-31 diff --git a/src/summary/summary/core/shared_models.py b/src/summary/summary/core/shared_models.py index 340a9959..043ea759 100644 --- a/src/summary/summary/core/shared_models.py +++ b/src/summary/summary/core/shared_models.py @@ -9,21 +9,33 @@ class WordSegment(BaseModel): """Word segment model for transcription tasks.""" word: str = Field(title="Word") - start: float = Field(title="Start Time", description="Start time in seconds.") - end: float = Field(title="End Time", description="End time in seconds.") + start: float | None = Field( + default=None, title="Start Time", description="Start time in seconds." + ) + end: float | None = Field( + default=None, title="End Time", description="End time in seconds." + ) score: float | None = Field( - title="Confidence Score", description="Confidence score for the word segment." + default=None, + title="Confidence Score", + description="Confidence score for the word segment.", ) speaker: str | None = Field( - title="Speaker", description="Speaker identifier for the word segment." + default=None, + title="Speaker", + description="Speaker identifier for the word segment.", ) class Segment(BaseModel): """Segment model for transcription tasks.""" - start: float = Field(title="Start Time", description="Start time in seconds.") - end: float = Field(title="End Time", description="End time in seconds.") + start: float | None = Field( + default=None, title="Start Time", description="Start time in seconds." + ) + end: float | None = Field( + default=None, title="End Time", description="End time in seconds." + ) text: str = Field( title="Segment Text", description="Transcribed text for the segment." ) @@ -31,7 +43,7 @@ class Segment(BaseModel): title="Word Segments", description="List of word segments within the segment." ) speaker: str | None = Field( - title="Speaker", description="Speaker identifier for the segment." + default=None, title="Speaker", description="Speaker identifier for the segment." ) diff --git a/src/summary/tests/models/__init__.py b/src/summary/tests/models/__init__.py new file mode 100644 index 00000000..7c3c4e3c --- /dev/null +++ b/src/summary/tests/models/__init__.py @@ -0,0 +1 @@ +"""Tests for models.""" diff --git a/src/summary/tests/models/test_whisper_x_response.py b/src/summary/tests/models/test_whisper_x_response.py new file mode 100644 index 00000000..86c33323 --- /dev/null +++ b/src/summary/tests/models/test_whisper_x_response.py @@ -0,0 +1,60 @@ +"""Tests for WhisperXResponse.""" + +from summary.core.shared_models import WhisperXResponse + + +def test_whisper_x_response_partial_response_is_valid(): + """A partial response from WhisperX is valid. + + Sometimes WhisperX Api doesn't return all the data and timestamps, + we don't want to fail the whole process. + """ + WhisperXResponse.model_validate( + { + "segments": [ + { + "start": 1.135, + "end": 7.3, + "text": " Test 1, 2, 3... Est-?", + "words": [ + { + "word": "Test", + "start": 1.135, + "end": 2.216, + "score": 0.654, + "speaker": "SPEAKER_00", + }, + { + "word": "1,", + "start": None, + "end": None, + "score": None, + "speaker": None, + }, + { + "word": "2,", + "start": None, + "end": None, + "score": None, + "speaker": None, + }, + { + "word": "3...", + }, + ], + "speaker": "SPEAKER_00", + } + ], + "word_segments": [ + { + "word": "Test", + "start": 1.135, + "end": 2.216, + "score": 0.654, + "speaker": "SPEAKER_00", + }, + {"word": "1,"}, + {"word": "?"}, + ], + } + )