mirror of
https://github.com/QuentinFuxa/WhisperLiveKit.git
synced 2026-03-07 14:23:18 +00:00
140 lines
3.8 KiB
Python
140 lines
3.8 KiB
Python
"""
|
|
Thread Safety Configuration for WhisperLiveKit
|
|
|
|
This module provides thread safety configuration and utilities.
|
|
|
|
Environment Variables:
|
|
WHISPERLIVEKIT_MODEL_LOCK: Enable/disable model locking (default: 1)
|
|
Set to "0" to disable for single-connection deployments
|
|
|
|
WHISPERLIVEKIT_LOCK_TIMEOUT: Lock acquisition timeout in seconds (default: 30)
|
|
|
|
Usage:
|
|
# Enable model locking (default)
|
|
export WHISPERLIVEKIT_MODEL_LOCK=1
|
|
|
|
# Disable for single-connection deployment
|
|
export WHISPERLIVEKIT_MODEL_LOCK=0
|
|
|
|
# Custom timeout
|
|
export WHISPERLIVEKIT_LOCK_TIMEOUT=60
|
|
"""
|
|
|
|
import os
|
|
import logging
|
|
import threading
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
# Configuration
|
|
USE_MODEL_LOCK = os.environ.get("WHISPERLIVEKIT_MODEL_LOCK", "1") == "1"
|
|
LOCK_TIMEOUT = float(os.environ.get("WHISPERLIVEKIT_LOCK_TIMEOUT", "30.0"))
|
|
|
|
# Global model lock
|
|
_model_lock = threading.Lock()
|
|
|
|
# Log configuration on import
|
|
if USE_MODEL_LOCK:
|
|
logger.info(f"Model locking ENABLED (timeout: {LOCK_TIMEOUT}s)")
|
|
logger.info("For single-connection deployments, set WHISPERLIVEKIT_MODEL_LOCK=0")
|
|
else:
|
|
logger.warning("Model locking DISABLED - only safe for single-connection deployments")
|
|
|
|
|
|
def get_model_lock():
|
|
"""Get the global model lock instance"""
|
|
return _model_lock
|
|
|
|
|
|
def acquire_model_lock(timeout=None):
|
|
"""
|
|
Acquire model lock with timeout.
|
|
|
|
Args:
|
|
timeout: Lock acquisition timeout (default: use LOCK_TIMEOUT)
|
|
|
|
Returns:
|
|
bool: True if lock acquired, False on timeout
|
|
"""
|
|
if not USE_MODEL_LOCK:
|
|
return True
|
|
|
|
timeout = timeout or LOCK_TIMEOUT
|
|
acquired = _model_lock.acquire(timeout=timeout)
|
|
|
|
if not acquired:
|
|
logger.error(f"Failed to acquire model lock within {timeout}s")
|
|
|
|
return acquired
|
|
|
|
|
|
def release_model_lock():
|
|
"""Release model lock"""
|
|
if not USE_MODEL_LOCK:
|
|
return
|
|
|
|
try:
|
|
_model_lock.release()
|
|
except RuntimeError:
|
|
# Lock not held - this is fine
|
|
pass
|
|
|
|
|
|
class ModelLockContext:
|
|
"""Context manager for model lock"""
|
|
|
|
def __init__(self, timeout=None):
|
|
self.timeout = timeout
|
|
self.acquired = False
|
|
|
|
def __enter__(self):
|
|
self.acquired = acquire_model_lock(self.timeout)
|
|
return self.acquired
|
|
|
|
def __exit__(self, exc_type, exc_val, exc_tb):
|
|
if self.acquired:
|
|
release_model_lock()
|
|
return False
|
|
|
|
|
|
# Concurrency recommendations
|
|
RECOMMENDED_CONNECTIONS_PER_WORKER = 1 if USE_MODEL_LOCK else 1
|
|
RECOMMENDED_WORKERS = 4
|
|
|
|
def print_deployment_recommendations():
|
|
"""Print recommended deployment configuration"""
|
|
print("\n" + "="*60)
|
|
print("WhisperLiveKit Deployment Recommendations")
|
|
print("="*60)
|
|
|
|
if USE_MODEL_LOCK:
|
|
print("⚠️ Model locking is ENABLED")
|
|
print(" This serializes inference across connections.")
|
|
print()
|
|
print("Recommended deployment:")
|
|
print(f" gunicorn -w {RECOMMENDED_WORKERS} \\")
|
|
print(" -k uvicorn.workers.UvicornWorker \\")
|
|
print(" --worker-connections 1 \\")
|
|
print(" whisperlivekit.basic_server:app")
|
|
print()
|
|
print("Expected capacity:")
|
|
print(f" - {RECOMMENDED_WORKERS} concurrent users (1 per worker)")
|
|
print(f" - Memory: ~{RECOMMENDED_WORKERS}x model size")
|
|
else:
|
|
print("✅ Model locking is DISABLED")
|
|
print(" ⚠️ ONLY safe for single-connection deployments")
|
|
print()
|
|
print("Recommended deployment:")
|
|
print(" uvicorn whisperlivekit.basic_server:app \\")
|
|
print(" --host 0.0.0.0 --port 8000 \\")
|
|
print(" --workers 1")
|
|
print()
|
|
print("Expected capacity:")
|
|
print(" - 1 concurrent user only")
|
|
|
|
print("="*60 + "\n")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
print_deployment_recommendations()
|