Compare commits

..

No commits in common. "fix/health-model-ws-defaults-20260628" and "main" have entirely different histories.

4 changed files with 17 additions and 52 deletions

2
.env
View File

@ -8,5 +8,5 @@ HTTP_PORT=8080
WHISPERLIVE_SSL=false WHISPERLIVE_SSL=false
WHISPL_USE_CUSTOM_MODEL=false WHISPL_USE_CUSTOM_MODEL=false
FASTERWHISPER_MODEL=large-v3-turbo FASTERWHISPER_MODEL=faster-whisper-large-v3
WHISPERLIVE_URL=${APP_WS_PROTOCOL}://whisperlive.${APP_URL} WHISPERLIVE_URL=${APP_WS_PROTOCOL}://whisperlive.${APP_URL}

1
.gitignore vendored
View File

@ -1 +0,0 @@
hf-cache/

View File

@ -21,7 +21,6 @@ services:
- ./models:/app/models - ./models:/app/models
- ./ssl:/app/ssl - ./ssl:/app/ssl
- ./logs:/app/logs - ./logs:/app/logs
- ./hf-cache:/root/.cache/huggingface
deploy: deploy:
resources: resources:
reservations: reservations:

View File

@ -78,49 +78,27 @@ class HybridWhisperServer:
from whisper_live.server import TranscriptionServer from whisper_live.server import TranscriptionServer
self.whisper_server = TranscriptionServer() self.whisper_server = TranscriptionServer()
# Create a shared transcriber instance for HTTP requests. # Create a shared transcriber instance for HTTP requests
# Prefer the configured production model over the previous hard-coded
# base default; faster-whisper accepts either a model size (for example
# large-v3-turbo) or a converted model path.
self.default_model = self.faster_whisper_custom_model_path or os.getenv("FASTERWHISPER_MODEL", "large-v3-turbo")
self.shared_transcriber = None self.shared_transcriber = None
if self.backend == "faster_whisper": if self.backend == "faster_whisper":
from whisper_live.transcriber import WhisperModel from whisper_live.transcriber import WhisperModel
self.shared_transcriber = WhisperModel( # Use base model as default for HTTP requests
self.default_model, model_size = "base"
device="cuda", if self.faster_whisper_custom_model_path:
compute_type="int8", model_size = self.faster_whisper_custom_model_path
) self.shared_transcriber = WhisperModel(model_size)
def setup_routes(self): def setup_routes(self):
@self.app.route('/health', methods=['GET']) @self.app.route('/health', methods=['GET'])
def health_check(): def health_check():
# Query the GPUs visible inside the container. Docker CDI maps the # Get GPU memory from nvidia-smi (GPU 1)
# assigned host GPU to container-local index 0, so hard-coding -i 1
# reports 0.0 even while WhisperLive is using CUDA.
import subprocess import subprocess
gpu_mem_used = 0.0
gpu_mem_total = 0.0
try: try:
output = subprocess.check_output( gpu_mem = float(subprocess.check_output(
[ 'nvidia-smi --query-gpu=memory.used --format=csv,noheader,nounits -i 1', shell=True
'nvidia-smi', ).decode().strip()) / 1024.0
'--query-gpu=memory.used,memory.total',
'--format=csv,noheader,nounits',
],
text=True,
)
for line in output.splitlines():
if not line.strip():
continue
used, total = [float(part.strip()) for part in line.split(',', 1)]
gpu_mem_used += used
gpu_mem_total += total
gpu_mem_used /= 1024.0
gpu_mem_total /= 1024.0
except Exception: except Exception:
pass gpu_mem = 0.0
# Get active WS connections # Get active WS connections
active = len(self.whisper_server.clients) if hasattr(self.whisper_server, 'clients') else 0 active = len(self.whisper_server.clients) if hasattr(self.whisper_server, 'clients') else 0
@ -129,9 +107,7 @@ class HybridWhisperServer:
'status': 'healthy', 'status': 'healthy',
'service': 'WhisperLive Hybrid Server', 'service': 'WhisperLive Hybrid Server',
'model_loaded': self.shared_transcriber is not None, 'model_loaded': self.shared_transcriber is not None,
'model': self.default_model, 'gpu_memory_used_gb': round(gpu_mem, 1),
'gpu_memory_used_gb': round(gpu_mem_used, 1),
'gpu_memory_total_gb': round(gpu_mem_total, 1),
'active_connections': active 'active_connections': active
}) })
@ -1110,8 +1086,9 @@ print(transcription.text)</code></pre>
# Bridges browser WebSocket connections on the HTTP port (8080) # Bridges browser WebSocket connections on the HTTP port (8080)
# to the internal WhisperLive WebSocket server (port 5000). # to the internal WhisperLive WebSocket server (port 5000).
# This allows live transcription through a single HTTPS port via NPM. # This allows live transcription through a single HTTPS port via NPM.
def handle_ws_bridge(ws): @self.sock.route('/ws')
"""Bridge WebSocket from HTTP port to internal WhisperLive WS server.""" def ws_bridge(ws):
"""Bridge WebSocket from HTTP port to internal WhisperLive WS server"""
internal_url = f"ws://127.0.0.1:{self.websocket_port}" internal_url = f"ws://127.0.0.1:{self.websocket_port}"
logger.info(f"WebSocket bridge: new connection, proxying to {internal_url}") logger.info(f"WebSocket bridge: new connection, proxying to {internal_url}")
@ -1167,16 +1144,6 @@ print(transcription.text)</code></pre>
pass pass
logger.info("WebSocket bridge: connection closed") logger.info("WebSocket bridge: connection closed")
@self.sock.route('/ws')
def ws_bridge(ws):
"""Canonical WebSocket bridge path for NPM/Cloudflare."""
return handle_ws_bridge(ws)
@self.sock.route('/')
def ws_bridge_root(ws):
"""Compatibility bridge for clients configured with the bare WSS origin."""
return handle_ws_bridge(ws)
def run_websocket_server(self): def run_websocket_server(self):
"""Run the WebSocket server in a separate thread""" """Run the WebSocket server in a separate thread"""
logger.info(f"Starting WebSocket server on port {self.websocket_port}") logger.info(f"Starting WebSocket server on port {self.websocket_port}")
@ -1221,7 +1188,7 @@ if __name__ == "__main__":
help='Backends from ["tensorrt", "faster_whisper"]') help='Backends from ["tensorrt", "faster_whisper"]')
parser.add_argument('--faster_whisper_custom_model_path', '-fw', parser.add_argument('--faster_whisper_custom_model_path', '-fw',
type=str, default=None, type=str, default=None,
help="Custom Faster Whisper converted model path") help="Custom Faster Whisper Model")
parser.add_argument('--trt_model_path', '-trt', parser.add_argument('--trt_model_path', '-trt',
type=str, type=str,
default=None, default=None,