Add vLLM plugin support for high-performance ASR serving
This commit is contained in:
@@ -1,3 +1,6 @@
|
||||
import os
|
||||
import threading
|
||||
|
||||
import numpy as np
|
||||
from subprocess import run
|
||||
from typing import List, Optional, Union, Dict, Any
|
||||
@@ -57,6 +60,7 @@ def load_audio_use_ffmpeg(file: str, resample: bool = False, target_sr: int = 24
|
||||
|
||||
cmd = [
|
||||
"ffmpeg",
|
||||
"-loglevel", "error",
|
||||
"-nostdin",
|
||||
"-threads", "0",
|
||||
"-i", file,
|
||||
@@ -64,14 +68,84 @@ def load_audio_use_ffmpeg(file: str, resample: bool = False, target_sr: int = 24
|
||||
"-ac", "1",
|
||||
"-acodec", "pcm_s16le",
|
||||
"-ar", str(sr_to_use),
|
||||
"-"
|
||||
"-",
|
||||
]
|
||||
|
||||
out = run(cmd, capture_output=True, check=True).stdout
|
||||
out = _run_ffmpeg(cmd).stdout
|
||||
audio_data = np.frombuffer(out, np.int16).flatten().astype(np.float32) / 32768.0
|
||||
|
||||
return audio_data, sr_to_use
|
||||
|
||||
|
||||
def _get_ffmpeg_max_concurrency() -> int:
|
||||
"""Get the maximum FFmpeg concurrency from environment variable."""
|
||||
v = os.getenv("VIBEVOICE_FFMPEG_MAX_CONCURRENCY", "")
|
||||
try:
|
||||
n = int(v) if v.strip() else 0
|
||||
except Exception:
|
||||
n = 0
|
||||
# 0/negative means no explicit limit.
|
||||
return n
|
||||
|
||||
|
||||
_FFMPEG_MAX_CONCURRENCY = _get_ffmpeg_max_concurrency()
|
||||
_FFMPEG_SEM = threading.Semaphore(_FFMPEG_MAX_CONCURRENCY) if _FFMPEG_MAX_CONCURRENCY > 0 else None
|
||||
|
||||
|
||||
def _run_ffmpeg(cmd: list, *, stdin_bytes: bytes = None):
|
||||
"""Run ffmpeg with optional global concurrency limiting.
|
||||
|
||||
This is important for vLLM multi-request concurrency: spawning too many
|
||||
ffmpeg processes can saturate CPU/IO and cause request failures/timeouts.
|
||||
"""
|
||||
if _FFMPEG_SEM is None:
|
||||
return run(cmd, capture_output=True, check=True, input=stdin_bytes)
|
||||
with _FFMPEG_SEM:
|
||||
return run(cmd, capture_output=True, check=True, input=stdin_bytes)
|
||||
|
||||
|
||||
def load_audio_bytes_use_ffmpeg(data: bytes, *, resample: bool = False, target_sr: int = 24000):
|
||||
"""Decode audio bytes via ffmpeg stdin pipe.
|
||||
|
||||
Compared to writing bytes to a temp file, this avoids filesystem IO and
|
||||
reduces contention under high request concurrency.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
data: bytes
|
||||
The audio data bytes
|
||||
resample: bool
|
||||
Whether to resample the audio (must be True)
|
||||
target_sr: int
|
||||
The target sample rate if resampling is requested
|
||||
|
||||
Returns
|
||||
-------
|
||||
A tuple containing:
|
||||
- A NumPy array with the audio waveform in float32 dtype
|
||||
- The sample rate
|
||||
"""
|
||||
if not resample:
|
||||
# For stdin bytes, we don't have a cheap/robust way to probe original sr.
|
||||
# Keep behavior explicit.
|
||||
raise ValueError("load_audio_bytes_use_ffmpeg requires resample=True")
|
||||
|
||||
cmd = [
|
||||
"ffmpeg",
|
||||
"-loglevel", "error",
|
||||
"-threads", "0",
|
||||
"-i", "pipe:0",
|
||||
"-f", "s16le",
|
||||
"-ac", "1",
|
||||
"-acodec", "pcm_s16le",
|
||||
"-ar", str(target_sr),
|
||||
"-",
|
||||
]
|
||||
out = _run_ffmpeg(cmd, stdin_bytes=data).stdout
|
||||
audio_data = np.frombuffer(out, np.int16).flatten().astype(np.float32) / 32768.0
|
||||
return audio_data, target_sr
|
||||
|
||||
|
||||
class AudioNormalizer:
|
||||
"""
|
||||
Audio normalization class for VibeVoice tokenizer.
|
||||
|
||||
Reference in New Issue
Block a user