mirror of
https://github.com/m-bain/whisperX.git
synced 2025-07-01 18:17:27 -04:00
Compare commits
6 Commits
v3.3.4
...
a326c15268
Author | SHA1 | Date | |
---|---|---|---|
a326c15268 | |||
b343241253 | |||
6fe0a8784a | |||
5012650d0f | |||
108bd0c400 | |||
ae7ea9f4b6 |
3
.github/workflows/build-and-release.yml
vendored
3
.github/workflows/build-and-release.yml
vendored
@ -17,6 +17,9 @@ jobs:
|
|||||||
version: "0.5.14"
|
version: "0.5.14"
|
||||||
python-version: "3.9"
|
python-version: "3.9"
|
||||||
|
|
||||||
|
- name: Check if lockfile is up to date
|
||||||
|
run: uv lock --check
|
||||||
|
|
||||||
- name: Build package
|
- name: Build package
|
||||||
run: uv build
|
run: uv build
|
||||||
|
|
||||||
|
3
.github/workflows/python-compatibility.yml
vendored
3
.github/workflows/python-compatibility.yml
vendored
@ -23,6 +23,9 @@ jobs:
|
|||||||
version: "0.5.14"
|
version: "0.5.14"
|
||||||
python-version: ${{ matrix.python-version }}
|
python-version: ${{ matrix.python-version }}
|
||||||
|
|
||||||
|
- name: Check if lockfile is up to date
|
||||||
|
run: uv lock --check
|
||||||
|
|
||||||
- name: Install the project
|
- name: Install the project
|
||||||
run: uv sync --all-extras
|
run: uv sync --all-extras
|
||||||
|
|
||||||
|
19
README.md
19
README.md
@ -97,6 +97,25 @@ uv sync --all-extras --dev
|
|||||||
|
|
||||||
You may also need to install ffmpeg, rust etc. Follow openAI instructions here https://github.com/openai/whisper#setup.
|
You may also need to install ffmpeg, rust etc. Follow openAI instructions here https://github.com/openai/whisper#setup.
|
||||||
|
|
||||||
|
### Common Issues & Troubleshooting 🔧
|
||||||
|
|
||||||
|
#### libcudnn Dependencies (GPU Users)
|
||||||
|
|
||||||
|
If you're using WhisperX with GPU support and encounter errors like:
|
||||||
|
|
||||||
|
- `Could not load library libcudnn_ops_infer.so.8`
|
||||||
|
- `Unable to load any of {libcudnn_cnn.so.9.1.0, libcudnn_cnn.so.9.1, libcudnn_cnn.so.9, libcudnn_cnn.so}`
|
||||||
|
- `libcudnn_ops_infer.so.8: cannot open shared object file: No such file or directory`
|
||||||
|
|
||||||
|
This means your system is missing the CUDA Deep Neural Network library (cuDNN). This library is needed for GPU acceleration but isn't always installed by default.
|
||||||
|
|
||||||
|
**Install cuDNN (example for apt based systems):**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo apt update
|
||||||
|
sudo apt install libcudnn8 libcudnn8-dev -y
|
||||||
|
```
|
||||||
|
|
||||||
### Speaker Diarization
|
### Speaker Diarization
|
||||||
|
|
||||||
To **enable Speaker Diarization**, include your Hugging Face access token (read) that you can generate from [Here](https://huggingface.co/settings/tokens) after the `--hf_token` argument and accept the user agreement for the following models: [Segmentation](https://huggingface.co/pyannote/segmentation-3.0) and [Speaker-Diarization-3.1](https://huggingface.co/pyannote/speaker-diarization-3.1) (if you choose to use Speaker-Diarization 2.x, follow requirements [here](https://huggingface.co/pyannote/speaker-diarization) instead.)
|
To **enable Speaker Diarization**, include your Hugging Face access token (read) that you can generate from [Here](https://huggingface.co/settings/tokens) after the `--hf_token` argument and accept the user agreement for the following models: [Segmentation](https://huggingface.co/pyannote/segmentation-3.0) and [Speaker-Diarization-3.1](https://huggingface.co/pyannote/speaker-diarization-3.1) (if you choose to use Speaker-Diarization 2.x, follow requirements [here](https://huggingface.co/pyannote/speaker-diarization) instead.)
|
||||||
|
2
uv.lock
generated
2
uv.lock
generated
@ -2787,7 +2787,7 @@ wheels = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "whisperx"
|
name = "whisperx"
|
||||||
version = "3.3.3"
|
version = "3.3.4"
|
||||||
source = { editable = "." }
|
source = { editable = "." }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "ctranslate2" },
|
{ name = "ctranslate2" },
|
||||||
|
@ -43,6 +43,7 @@ def cli():
|
|||||||
parser.add_argument("--diarize", action="store_true", help="Apply diarization to assign speaker labels to each segment/word")
|
parser.add_argument("--diarize", action="store_true", help="Apply diarization to assign speaker labels to each segment/word")
|
||||||
parser.add_argument("--min_speakers", default=None, type=int, help="Minimum number of speakers to in audio file")
|
parser.add_argument("--min_speakers", default=None, type=int, help="Minimum number of speakers to in audio file")
|
||||||
parser.add_argument("--max_speakers", default=None, type=int, help="Maximum number of speakers to in audio file")
|
parser.add_argument("--max_speakers", default=None, type=int, help="Maximum number of speakers to in audio file")
|
||||||
|
parser.add_argument("--diarize_model", default="pyannote/speaker-diarization-3.1", type=str, help="Name of the speaker diarization model to use")
|
||||||
|
|
||||||
parser.add_argument("--temperature", type=float, default=0, help="temperature to use for sampling")
|
parser.add_argument("--temperature", type=float, default=0, help="temperature to use for sampling")
|
||||||
parser.add_argument("--best_of", type=optional_int, default=5, help="number of candidates when sampling with non-zero temperature")
|
parser.add_argument("--best_of", type=optional_int, default=5, help="number of candidates when sampling with non-zero temperature")
|
||||||
|
@ -58,11 +58,33 @@ def load_audio(file: str, sr: int = SAMPLE_RATE) -> np.ndarray:
|
|||||||
str(sr),
|
str(sr),
|
||||||
"-",
|
"-",
|
||||||
]
|
]
|
||||||
out = subprocess.run(cmd, capture_output=True, check=True).stdout
|
|
||||||
except subprocess.CalledProcessError as e:
|
|
||||||
raise RuntimeError(f"Failed to load audio: {e.stderr.decode()}") from e
|
|
||||||
|
|
||||||
return np.frombuffer(out, np.int16).flatten().astype(np.float32) / 32768.0
|
process = subprocess.Popen(
|
||||||
|
cmd,
|
||||||
|
stdout=subprocess.PIPE,
|
||||||
|
stderr=subprocess.PIPE,
|
||||||
|
bufsize=10 * 1024 * 1024
|
||||||
|
)
|
||||||
|
|
||||||
|
out = bytearray()
|
||||||
|
while True:
|
||||||
|
chunk = process.stdout.read(1024 * 1024)
|
||||||
|
if not chunk:
|
||||||
|
break
|
||||||
|
out.extend(chunk)
|
||||||
|
|
||||||
|
stderr_output = process.stderr.read()
|
||||||
|
return_code = process.wait()
|
||||||
|
|
||||||
|
if return_code != 0:
|
||||||
|
raise RuntimeError(f"FFmpeg process failed with error: {stderr_output.decode()}")
|
||||||
|
|
||||||
|
if len(out) % 2 != 0:
|
||||||
|
raise ValueError("Audio buffer size is not aligned to int16.")
|
||||||
|
|
||||||
|
return np.frombuffer(out, np.int16).astype(np.float32) / 32768.0
|
||||||
|
except Exception as e:
|
||||||
|
raise RuntimeError(f"Error loading audio file {file}: {str(e)}")
|
||||||
|
|
||||||
|
|
||||||
def pad_or_trim(array, length: int = N_SAMPLES, *, axis: int = -1):
|
def pad_or_trim(array, length: int = N_SAMPLES, *, axis: int = -1):
|
||||||
|
@ -11,13 +11,14 @@ from whisperx.types import TranscriptionResult, AlignedTranscriptionResult
|
|||||||
class DiarizationPipeline:
|
class DiarizationPipeline:
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
model_name="pyannote/speaker-diarization-3.1",
|
model_name=None,
|
||||||
use_auth_token=None,
|
use_auth_token=None,
|
||||||
device: Optional[Union[str, torch.device]] = "cpu",
|
device: Optional[Union[str, torch.device]] = "cpu",
|
||||||
):
|
):
|
||||||
if isinstance(device, str):
|
if isinstance(device, str):
|
||||||
device = torch.device(device)
|
device = torch.device(device)
|
||||||
self.model = Pipeline.from_pretrained(model_name, use_auth_token=use_auth_token).to(device)
|
model_config = model_name or "pyannote/speaker-diarization-3.1"
|
||||||
|
self.model = Pipeline.from_pretrained(model_config, use_auth_token=use_auth_token).to(device)
|
||||||
|
|
||||||
def __call__(
|
def __call__(
|
||||||
self,
|
self,
|
||||||
|
@ -57,6 +57,7 @@ def transcribe_task(args: dict, parser: argparse.ArgumentParser):
|
|||||||
diarize: bool = args.pop("diarize")
|
diarize: bool = args.pop("diarize")
|
||||||
min_speakers: int = args.pop("min_speakers")
|
min_speakers: int = args.pop("min_speakers")
|
||||||
max_speakers: int = args.pop("max_speakers")
|
max_speakers: int = args.pop("max_speakers")
|
||||||
|
diarize_model_name: str = args.pop("diarize_model")
|
||||||
print_progress: bool = args.pop("print_progress")
|
print_progress: bool = args.pop("print_progress")
|
||||||
|
|
||||||
if args["language"] is not None:
|
if args["language"] is not None:
|
||||||
@ -204,8 +205,9 @@ def transcribe_task(args: dict, parser: argparse.ArgumentParser):
|
|||||||
)
|
)
|
||||||
tmp_results = results
|
tmp_results = results
|
||||||
print(">>Performing diarization...")
|
print(">>Performing diarization...")
|
||||||
|
print(">>Using model:", diarize_model_name)
|
||||||
results = []
|
results = []
|
||||||
diarize_model = DiarizationPipeline(use_auth_token=hf_token, device=device)
|
diarize_model = DiarizationPipeline(model_name=diarize_model_name, use_auth_token=hf_token, device=device)
|
||||||
for result, input_audio_path in tmp_results:
|
for result, input_audio_path in tmp_results:
|
||||||
diarize_segments = diarize_model(
|
diarize_segments = diarize_model(
|
||||||
input_audio_path, min_speakers=min_speakers, max_speakers=max_speakers
|
input_audio_path, min_speakers=min_speakers, max_speakers=max_speakers
|
||||||
|
Reference in New Issue
Block a user