diff --git a/src/rai_s2s/rai_s2s/asr/agents/initialization.py b/src/rai_s2s/rai_s2s/asr/agents/initialization.py index 9ad163db0..caa744856 100644 --- a/src/rai_s2s/rai_s2s/asr/agents/initialization.py +++ b/src/rai_s2s/rai_s2s/asr/agents/initialization.py @@ -13,6 +13,7 @@ # limitations under the License. from dataclasses import dataclass +import math from typing import Literal, Optional import tomli @@ -24,6 +25,20 @@ class VADConfig: threshold: float = 0.5 silence_grace_period: float = 0.3 + def __post_init__(self) -> None: + if not isinstance(self.threshold, (int, float)) or not math.isfinite(float(self.threshold)): + raise ValueError("threshold must be a finite number") + thr = float(self.threshold) + if thr <= 0.0 or thr > 1.0: + raise ValueError("threshold must be in (0, 1]") + if ( + not isinstance(self.silence_grace_period, (int, float)) + or not math.isfinite(float(self.silence_grace_period)) + ): + raise ValueError("silence_grace_period must be a finite number") + if float(self.silence_grace_period) <= 0.0: + raise ValueError("silence_grace_period must be positive") + @dataclass class WWConfig: @@ -32,6 +47,13 @@ class WWConfig: threshold: float = 0.01 is_used: bool = False + def __post_init__(self) -> None: + if not isinstance(self.threshold, (int, float)) or not math.isfinite(float(self.threshold)): + raise ValueError("threshold must be a finite number") + thr = float(self.threshold) + if thr <= 0.0 or thr > 1.0: + raise ValueError("threshold must be in (0, 1]") + TRANSCRIBE_MODELS = ["LocalWhisper", "FasterWhisper", "OpenAI"] diff --git a/tests/s2s/test_asr_agent_config_guards.py b/tests/s2s/test_asr_agent_config_guards.py new file mode 100644 index 000000000..7cbf898d3 --- /dev/null +++ b/tests/s2s/test_asr_agent_config_guards.py @@ -0,0 +1,39 @@ +# Copyright (C) 2025 Robotec.AI +import math + +import pytest + +from rai_s2s.asr.agents.initialization import VADConfig, WWConfig + + +def test_vad_rejects_non_positive_threshold() -> None: + with pytest.raises(ValueError): + VADConfig(threshold=0.0) + with pytest.raises(ValueError): + VADConfig(threshold=-0.1) + with pytest.raises(ValueError): + VADConfig(threshold=1.1) + + +def test_vad_rejects_non_positive_grace() -> None: + with pytest.raises(ValueError): + VADConfig(silence_grace_period=0.0) + with pytest.raises(ValueError): + VADConfig(silence_grace_period=float("nan")) + + +def test_vad_accepts_defaults() -> None: + cfg = VADConfig() + assert cfg.threshold == 0.5 + + +def test_ww_rejects_bad_threshold() -> None: + with pytest.raises(ValueError): + WWConfig(threshold=0.0) + with pytest.raises(ValueError): + WWConfig(threshold=math.nan) + + +def test_ww_accepts_defaults() -> None: + cfg = WWConfig() + assert 0.0 < cfg.threshold <= 1.0