Add Krisp API key support for new SDK licensing requirement

The Krisp VIVA SDK v1.8.0 requires a license key in globalInit(). Add
api_key parameter to KrispVivaSDKManager, KrispVivaTurn, and
KrispVivaFilter with fallback to KRISP_API_KEY env var. Maintain
backwards compatibility with older SDK versions by catching TypeError
and falling back to the old 3-arg signature.
This commit is contained in:
Mark Backman
2026-02-24 10:16:35 -05:00
parent 65f563ad34
commit 73ee4da7d4
7 changed files with 47 additions and 9 deletions

1
changelog/3809.added.md Normal file
View File

@@ -0,0 +1 @@
- Added `api_key` parameter to `KrispVivaSDKManager`, `KrispVivaTurn`, and `KrispVivaFilter` for Krisp SDK v1.8.0 licensing. Falls back to `KRISP_API_KEY` environment variable. Backwards compatible with older SDK versions.

View File

@@ -1 +1 @@
- Added debug logging to `KrispVivaTurn.analyze_end_of_turn()` to log turn state and probability at decision time. - Added `api_key` parameter to `KrispVivaSDKManager`, `KrispVivaTurn`, and `KrispVivaFilter` for Krisp SDK v1.6.1+ licensing. Falls back to `KRISP_VIVA_API_KEY` environment variable.

View File

@@ -104,6 +104,7 @@ INWORLD_API_KEY=...
KRISP_MODEL_PATH=... KRISP_MODEL_PATH=...
# Krisp Viva # Krisp Viva
KRISP_VIVA_API_KEY=...
KRISP_VIVA_FILTER_MODEL_PATH=... KRISP_VIVA_FILTER_MODEL_PATH=...
KRISP_VIVA_TURN_MODEL_PATH=... KRISP_VIVA_TURN_MODEL_PATH=...

View File

@@ -54,21 +54,24 @@ load_dotenv(override=True)
# We use lambdas to defer transport parameter creation until the transport # We use lambdas to defer transport parameter creation until the transport
# type is selected at runtime. # type is selected at runtime.
krisp_viva_filter = KrispVivaFilter()
transport_params = { transport_params = {
"daily": lambda: DailyParams( "daily": lambda: DailyParams(
audio_in_enabled=True, audio_in_enabled=True,
audio_out_enabled=True, audio_out_enabled=True,
audio_in_filter=KrispVivaFilter(), audio_in_filter=krisp_viva_filter,
), ),
"twilio": lambda: FastAPIWebsocketParams( "twilio": lambda: FastAPIWebsocketParams(
audio_in_enabled=True, audio_in_enabled=True,
audio_out_enabled=True, audio_out_enabled=True,
audio_in_filter=KrispVivaFilter(), audio_in_filter=krisp_viva_filter,
), ),
"webrtc": lambda: TransportParams( "webrtc": lambda: TransportParams(
audio_in_enabled=True, audio_in_enabled=True,
audio_out_enabled=True, audio_out_enabled=True,
audio_in_filter=KrispVivaFilter(), audio_in_filter=krisp_viva_filter,
), ),
} }

View File

@@ -39,7 +39,11 @@ class KrispVivaFilter(BaseAudioFilter):
""" """
def __init__( def __init__(
self, model_path: str = None, frame_duration: int = 10, noise_suppression_level: int = 100 self,
model_path: str = None,
frame_duration: int = 10,
noise_suppression_level: int = 100,
api_key: str = "",
) -> None: ) -> None:
"""Initialize the Krisp noise reduction filter. """Initialize the Krisp noise reduction filter.
@@ -48,6 +52,8 @@ class KrispVivaFilter(BaseAudioFilter):
If None, uses KRISP_VIVA_FILTER_MODEL_PATH environment variable. If None, uses KRISP_VIVA_FILTER_MODEL_PATH environment variable.
frame_duration: Frame duration in milliseconds. frame_duration: Frame duration in milliseconds.
noise_suppression_level: Noise suppression level. noise_suppression_level: Noise suppression level.
api_key: Krisp SDK API key. If empty, falls back to
the KRISP_VIVA_API_KEY environment variable.
Raises: Raises:
ValueError: If model_path is not provided and KRISP_VIVA_FILTER_MODEL_PATH is not set. ValueError: If model_path is not provided and KRISP_VIVA_FILTER_MODEL_PATH is not set.
@@ -57,6 +63,8 @@ class KrispVivaFilter(BaseAudioFilter):
""" """
super().__init__() super().__init__()
self._api_key = api_key
try: try:
# Set model path, checking environment if not specified # Set model path, checking environment if not specified
if model_path: if model_path:
@@ -132,7 +140,7 @@ class KrispVivaFilter(BaseAudioFilter):
""" """
try: try:
# Acquire SDK reference (will initialize on first call) # Acquire SDK reference (will initialize on first call)
KrispVivaSDKManager.acquire() KrispVivaSDKManager.acquire(api_key=self._api_key)
self._session = self._create_session(sample_rate, self._frame_duration_ms) self._session = self._create_session(sample_rate, self._frame_duration_ms)
except Exception as e: except Exception as e:
logger.error(f"Failed to start Krisp session: {e}", exc_info=True) logger.error(f"Failed to start Krisp session: {e}", exc_info=True)

View File

@@ -7,6 +7,7 @@
"""Krisp Instance manager for pipecat audio.""" """Krisp Instance manager for pipecat audio."""
import atexit import atexit
import os
from threading import Lock from threading import Lock
from loguru import logger from loguru import logger
@@ -88,17 +89,26 @@ class KrispVivaSDKManager:
_lock = Lock() _lock = Lock()
_reference_count = 0 _reference_count = 0
@staticmethod
def _license_callback(error, error_message):
"""Callback for Krisp SDK licensing errors."""
logger.error(f"Krisp licensing error: {error} - {error_message}")
@staticmethod @staticmethod
def _log_callback(log_message, log_level): def _log_callback(log_message, log_level):
"""Thread-safe callback for Krisp SDK logging.""" """Thread-safe callback for Krisp SDK logging."""
logger.info(f"[{log_level}] {log_message}") logger.info(f"[{log_level}] {log_message}")
@classmethod @classmethod
def acquire(cls): def acquire(cls, api_key: str = ""):
"""Acquire a reference to the SDK (initializes if needed). """Acquire a reference to the SDK (initializes if needed).
Call this when creating a filter instance. Call this when creating a filter instance.
Args:
api_key: Krisp SDK API key. If empty, falls back to the
KRISP_VIVA_API_KEY environment variable.
Raises: Raises:
Exception: If SDK initialization fails (propagated from krisp_audio) Exception: If SDK initialization fails (propagated from krisp_audio)
""" """
@@ -106,7 +116,19 @@ class KrispVivaSDKManager:
# Initialize SDK on first acquire # Initialize SDK on first acquire
if cls._reference_count == 0: if cls._reference_count == 0:
try: try:
krisp_audio.globalInit("", cls._log_callback, krisp_audio.LogLevel.Off) key = api_key or os.environ.get("KRISP_VIVA_API_KEY", "")
try:
# New SDK signature (requires license key)
krisp_audio.globalInit(
"",
key,
cls._license_callback,
cls._log_callback,
krisp_audio.LogLevel.Off,
)
except TypeError:
# Old SDK signature (no license key)
krisp_audio.globalInit("", cls._log_callback, krisp_audio.LogLevel.Off)
cls._initialized = True cls._initialized = True

View File

@@ -63,6 +63,7 @@ class KrispVivaTurn(BaseTurnAnalyzer):
model_path: Optional[str] = None, model_path: Optional[str] = None,
sample_rate: Optional[int] = None, sample_rate: Optional[int] = None,
params: Optional[KrispTurnParams] = None, params: Optional[KrispTurnParams] = None,
api_key: str = "",
) -> None: ) -> None:
"""Initialize the Krisp turn analyzer. """Initialize the Krisp turn analyzer.
@@ -72,6 +73,8 @@ class KrispVivaTurn(BaseTurnAnalyzer):
sample_rate: Optional initial sample rate for audio processing. sample_rate: Optional initial sample rate for audio processing.
If provided, this will be used as the fixed sample rate. If provided, this will be used as the fixed sample rate.
params: Configuration parameters for turn analysis behavior. params: Configuration parameters for turn analysis behavior.
api_key: Krisp SDK API key. If empty, falls back to
the KRISP_VIVA_API_KEY environment variable.
Raises: Raises:
ValueError: If model_path is not provided and KRISP_VIVA_TURN_MODEL_PATH is not set. ValueError: If model_path is not provided and KRISP_VIVA_TURN_MODEL_PATH is not set.
@@ -83,7 +86,7 @@ class KrispVivaTurn(BaseTurnAnalyzer):
# Acquire SDK reference (will initialize on first call) # Acquire SDK reference (will initialize on first call)
try: try:
KrispVivaSDKManager.acquire() KrispVivaSDKManager.acquire(api_key=api_key)
self._sdk_acquired = True self._sdk_acquired = True
except Exception as e: except Exception as e:
self._sdk_acquired = False self._sdk_acquired = False