refactor: formaliza formatos de áudio e alinhamento PCM

This commit is contained in:
alex alves
2026-11-03 16:43:22 -03:00
parent 4d7ff46a36
commit 76d15b8e52
23 changed files with 349 additions and 82 deletions

View File

@@ -1,58 +1,36 @@
"""
Canonical audio models for the Voice Assistant.
"""PCM format contracts shared by application, transports, and providers.
Purpose:
Define the provider-independent audio format used internally by
the Voice Core.
Responsibilities:
- Describe an audio format in a typed structure.
- Define the canonical audio format used by the Voice Core.
- Provide a shared audio contract for transports and providers.
Non-responsibilities:
- Encoding or decoding audio.
- Resampling audio.
- Converting provider-specific audio formats.
- Managing WebSocket audio frames.
- Performing STT or TTS operations.
Architecture:
Client / Transport
|
v
Canonical Audio
PCM S16LE / 16 kHz / mono
|
v
Voice Core
|
+-----+-----+
| |
v v
STT TTS
Adapter Adapter
Provider-specific format conversion, when required, belongs
inside the corresponding provider adapter.
The canonical input is mono PCM S16LE at 16 kHz. Output uses the format
explicitly declared by the TTS provider. Declaring a sample rate does not
convert or resample audio; provider adapters own any required conversion.
"""
from typing import Literal
from pydantic import BaseModel
from pydantic import BaseModel, ConfigDict, Field
class AudioFormat(BaseModel):
"""
Describe one PCM audio format.
"""An immutable PCM format; a frame contains one sample per channel."""
This model is independent from WebSocket, STT, TTS, or any
concrete provider.
"""
model_config = ConfigDict(frozen=True)
encoding: Literal["pcm_s16le"]
sample_rate: int
channels: int
sample_rate: int = Field(gt=0, strict=True)
channels: int = Field(gt=0, strict=True)
@property
def frame_size_bytes(self) -> int:
return 2 * self.channels
def validate_chunk(self, audio: bytes) -> None:
if not audio:
raise ValueError("Audio chunk cannot be empty.")
if len(audio) % self.frame_size_bytes:
raise ValueError(
"PCM chunk must contain complete frames of "
f"{self.frame_size_bytes} bytes."
)
CANONICAL_AUDIO_FORMAT = AudioFormat(
@@ -60,4 +38,3 @@ CANONICAL_AUDIO_FORMAT = AudioFormat(
sample_rate=16000,
channels=1,
)