Fixed review comments.
This commit is contained in:
1
changelog/4022.changed.md
Normal file
1
changelog/4022.changed.md
Normal file
@@ -0,0 +1 @@
|
|||||||
|
- Added `KrispVivaVadAnalyzer` for Voice Activity Detection using the Krisp VIVA SDK (requires `krisp_audio`).
|
||||||
@@ -60,19 +60,19 @@ transport_params = {
|
|||||||
"daily": lambda: DailyParams(
|
"daily": lambda: DailyParams(
|
||||||
audio_in_enabled=True,
|
audio_in_enabled=True,
|
||||||
audio_out_enabled=True,
|
audio_out_enabled=True,
|
||||||
vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)),
|
vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), # or KrispVivaVadAnalyzer
|
||||||
audio_in_filter=KrispVivaFilter(),
|
audio_in_filter=KrispVivaFilter(),
|
||||||
),
|
),
|
||||||
"twilio": lambda: FastAPIWebsocketParams(
|
"twilio": lambda: FastAPIWebsocketParams(
|
||||||
audio_in_enabled=True,
|
audio_in_enabled=True,
|
||||||
audio_out_enabled=True,
|
audio_out_enabled=True,
|
||||||
vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)),
|
vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), # or KrispVivaVadAnalyzer
|
||||||
audio_in_filter=KrispVivaFilter(),
|
audio_in_filter=KrispVivaFilter(),
|
||||||
),
|
),
|
||||||
"webrtc": lambda: TransportParams(
|
"webrtc": lambda: TransportParams(
|
||||||
audio_in_enabled=True,
|
audio_in_enabled=True,
|
||||||
audio_out_enabled=True,
|
audio_out_enabled=True,
|
||||||
vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)),
|
vad_analyzer=SileroVADAnalyzer(params=VADParams(stop_secs=0.2)), # or KrispVivaVadAnalyzer
|
||||||
audio_in_filter=KrispVivaFilter(),
|
audio_in_filter=KrispVivaFilter(),
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -207,8 +207,8 @@ class KrispVivaVadAnalyzer(VADAnalyzer):
|
|||||||
logger.error(f"Error analyzing audio with Krisp VIVA VAD: {e}", exc_info=True)
|
logger.error(f"Error analyzing audio with Krisp VIVA VAD: {e}", exc_info=True)
|
||||||
return 0.0
|
return 0.0
|
||||||
|
|
||||||
def __del__(self):
|
async def cleanup(self):
|
||||||
"""Cleanup when the analyzer is destroyed."""
|
"""Cleanup analyzer resources."""
|
||||||
try:
|
try:
|
||||||
self._session = None
|
self._session = None
|
||||||
KrispVivaSDKManager.release()
|
KrispVivaSDKManager.release()
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
"""Unit tests for KrispVivaVadAnalyzer."""
|
"""Unit tests for KrispVivaVadAnalyzer."""
|
||||||
|
|
||||||
|
import asyncio
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import tempfile
|
import tempfile
|
||||||
@@ -132,7 +133,7 @@ class TestKrispVivaVadAnalyzer(unittest.TestCase):
|
|||||||
self.assertIn("Model path", str(context.exception))
|
self.assertIn("Model path", str(context.exception))
|
||||||
# acquire() is not called because exception is raised before it
|
# acquire() is not called because exception is raised before it
|
||||||
self.mock_sdk_manager.acquire.assert_not_called()
|
self.mock_sdk_manager.acquire.assert_not_called()
|
||||||
# release() is called in exception handler and also in __del__ when object is destroyed
|
# release() is called in the initialization exception handler
|
||||||
self.assertGreaterEqual(self.mock_sdk_manager.release.call_count, 1)
|
self.assertGreaterEqual(self.mock_sdk_manager.release.call_count, 1)
|
||||||
|
|
||||||
def test_initialization_with_invalid_extension(self):
|
def test_initialization_with_invalid_extension(self):
|
||||||
@@ -148,7 +149,7 @@ class TestKrispVivaVadAnalyzer(unittest.TestCase):
|
|||||||
self.assertIn(".kef extension", str(context.exception))
|
self.assertIn(".kef extension", str(context.exception))
|
||||||
# acquire() is not called because exception is raised before it
|
# acquire() is not called because exception is raised before it
|
||||||
self.mock_sdk_manager.acquire.assert_not_called()
|
self.mock_sdk_manager.acquire.assert_not_called()
|
||||||
# release() is called in exception handler and also in __del__ when object is destroyed
|
# release() is called in the initialization exception handler
|
||||||
self.assertGreaterEqual(self.mock_sdk_manager.release.call_count, 1)
|
self.assertGreaterEqual(self.mock_sdk_manager.release.call_count, 1)
|
||||||
finally:
|
finally:
|
||||||
os.unlink(tmp_path)
|
os.unlink(tmp_path)
|
||||||
@@ -160,7 +161,7 @@ class TestKrispVivaVadAnalyzer(unittest.TestCase):
|
|||||||
|
|
||||||
# acquire() is not called because exception is raised before it
|
# acquire() is not called because exception is raised before it
|
||||||
self.mock_sdk_manager.acquire.assert_not_called()
|
self.mock_sdk_manager.acquire.assert_not_called()
|
||||||
# release() is called in exception handler and also in __del__ when object is destroyed
|
# release() is called in the initialization exception handler
|
||||||
self.assertGreaterEqual(self.mock_sdk_manager.release.call_count, 1)
|
self.assertGreaterEqual(self.mock_sdk_manager.release.call_count, 1)
|
||||||
|
|
||||||
def test_initialization_with_custom_frame_duration(self):
|
def test_initialization_with_custom_frame_duration(self):
|
||||||
@@ -348,19 +349,19 @@ class TestKrispVivaVadAnalyzer(unittest.TestCase):
|
|||||||
self.assertGreaterEqual(confidence, 0.0)
|
self.assertGreaterEqual(confidence, 0.0)
|
||||||
self.assertLessEqual(confidence, 1.0)
|
self.assertLessEqual(confidence, 1.0)
|
||||||
|
|
||||||
def test_cleanup_on_destruction(self):
|
def test_cleanup(self):
|
||||||
"""Test that cleanup happens when analyzer is destroyed."""
|
"""Test that cleanup releases resources explicitly."""
|
||||||
analyzer = KrispVivaVadAnalyzer(model_path=self.model_path)
|
analyzer = KrispVivaVadAnalyzer(model_path=self.model_path)
|
||||||
analyzer.set_sample_rate(16000)
|
analyzer.set_sample_rate(16000)
|
||||||
|
|
||||||
# Reset mock to track calls
|
# Reset mock to track calls
|
||||||
self.mock_sdk_manager.release.reset_mock()
|
self.mock_sdk_manager.release.reset_mock()
|
||||||
|
|
||||||
# Delete analyzer (triggers __del__)
|
asyncio.run(analyzer.cleanup())
|
||||||
del analyzer
|
|
||||||
|
|
||||||
# Verify SDK was released
|
# Verify SDK was released and session was cleared
|
||||||
self.mock_sdk_manager.release.assert_called_once()
|
self.mock_sdk_manager.release.assert_called_once()
|
||||||
|
self.assertIsNone(analyzer._session)
|
||||||
|
|
||||||
def test_initialization_with_vad_params(self):
|
def test_initialization_with_vad_params(self):
|
||||||
"""Test analyzer initialization with VAD parameters."""
|
"""Test analyzer initialization with VAD parameters."""
|
||||||
|
|||||||
Reference in New Issue
Block a user