Skip to content

Commit 7558b8c

Browse files
switch to ruff and precommit (#360)
* switch to ruff and precommit * ignore the notebook
1 parent fcbd193 commit 7558b8c

7 files changed

Lines changed: 68 additions & 85 deletions

File tree

.github/workflows/test_run.yml

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,20 @@ on:
99
- cron: '0 0 * * TUE'
1010

1111
jobs:
12-
build:
12+
check-python-style:
13+
runs-on: ubuntu-latest
14+
steps:
15+
- uses: actions/checkout@v4
16+
17+
- name: Set up Python 3.10
18+
uses: actions/setup-python@v5
19+
with:
20+
python-version: '3.10'
21+
22+
- uses: pre-commit/action@v3.0.1
1323

24+
test-run:
25+
needs: [check-python-style]
1426
strategy:
1527
fail-fast: false
1628
matrix:
@@ -48,6 +60,6 @@ jobs:
4860
python -m pip install torch torchaudio --index-url https://download.pytorch.org/whl/cpu
4961
uv pip install --system -c constraints.txt -r requirements.txt
5062
51-
- name: Test running a file
63+
- name: Test with msdd diarizer
5264
run: |
53-
python diarize.py -a "./tests/assets/test.opus" --whisper-model tiny.en
65+
python diarize.py -a "./tests/assets/test.opus" --whisper-model tiny.en --diarizer msdd

.pre-commit-config.yaml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
repos:
2+
- repo: https://github.com/astral-sh/ruff-pre-commit
3+
rev: v0.9.9
4+
hooks:
5+
- id: ruff
6+
args: [--fix]
7+
- id: ruff-format

diarization/msdd/msdd.py

Lines changed: 10 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import json
22
import os
33
import tempfile
4+
import wave
45

56
from typing import Union
67

78
import torch
8-
import torchaudio
99

1010
from nemo.collections.asr.models.msdd_models import NeuralDiarizer
1111
from nemo.collections.asr.parts.utils.speaker_utils import rttm_to_labels
@@ -18,12 +18,12 @@ def __init__(self, device: Union[str, torch.device]):
1818

1919
def diarize(self, audio: torch.Tensor):
2020
with tempfile.TemporaryDirectory() as temp_path:
21-
torchaudio.save(
22-
os.path.join(temp_path, "mono_file.wav"),
23-
audio,
24-
16000,
25-
channels_first=True,
26-
)
21+
pcm = (audio.cpu().numpy() * 32768).clip(-32768, 32767).astype("int16")
22+
with wave.open(os.path.join(temp_path, "mono_file.wav"), "wb") as wf:
23+
wf.setnchannels(1)
24+
wf.setsampwidth(2)
25+
wf.setframerate(16000)
26+
wf.writeframes(pcm.tobytes())
2727

2828
manifest_path = os.path.join(temp_path, "manifest.json")
2929
meta = {
@@ -48,9 +48,7 @@ def diarize(self, audio: torch.Tensor):
4848
num_workers=0,
4949
verbose=True,
5050
)
51-
self.model.clustering_embedding.clus_diar_model._diarizer_params.out_dir = (
52-
temp_path
53-
)
51+
self.model.clustering_embedding.clus_diar_model._diarizer_params.out_dir = temp_path
5452
self.model.clustering_embedding.clus_diar_model._diarizer_params.manifest_filepath = (
5553
manifest_path
5654
)
@@ -74,18 +72,14 @@ def diarize(self, audio: torch.Tensor):
7472

7573

7674
def create_config():
77-
config = OmegaConf.load(
78-
os.path.join(os.path.dirname(__file__), "diar_infer_telephonic.yaml")
79-
)
75+
config = OmegaConf.load(os.path.join(os.path.dirname(__file__), "diar_infer_telephonic.yaml"))
8076
pretrained_vad = "vad_multilingual_marblenet"
8177
pretrained_speaker_model = "titanet_large"
8278

8379
config.diarizer.out_dir = None
8480
config.diarizer.manifest_filepath = None
8581
config.diarizer.speaker_embeddings.model_path = pretrained_speaker_model
86-
config.diarizer.oracle_vad = (
87-
False # compute VAD provided with model_path to vad config
88-
)
82+
config.diarizer.oracle_vad = False # compute VAD provided with model_path to vad config
8983
config.diarizer.clustering.parameters.oracle_num_speakers = False
9084

9185
# Here, we use our in-house pretrained NeMo VAD model

diarize.py

Lines changed: 8 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -32,23 +32,18 @@
3232

3333
mtypes = {"cpu": "int8", "cuda": "float16"}
3434

35-
pid = os.getpid()
36-
temp_outputs_dir = f"temp_outputs_{pid}"
37-
temp_path = os.path.join(os.getcwd(), "temp_outputs")
35+
temp_path = os.path.join(os.getcwd(), f"temp_outputs_{os.getpid()}")
3836
os.makedirs(temp_path, exist_ok=True)
3937

4038
# Initialize parser
4139
parser = argparse.ArgumentParser()
42-
parser.add_argument(
43-
"-a", "--audio", help="name of the target audio file", required=True
44-
)
40+
parser.add_argument("-a", "--audio", help="name of the target audio file", required=True)
4541
parser.add_argument(
4642
"--no-stem",
4743
action="store_false",
4844
dest="stemming",
4945
default=True,
50-
help="Disables source separation."
51-
"This helps with long files that don't contain a lot of music.",
46+
help="Disables source separation.This helps with long files that don't contain a lot of music.",
5247
)
5348

5449
parser.add_argument(
@@ -105,7 +100,8 @@
105100
# Isolate vocals from the rest of the audio
106101

107102
return_code = os.system(
108-
f'python -m demucs.separate -n htdemucs --two-stems=vocals "{args.audio}" -o "{temp_outputs_dir}" --device "{args.device}"'
103+
f"python -m demucs.separate -n htdemucs --two-stems=vocals "
104+
f'"{args.audio}" -o "{temp_path}" --device "{args.device}"'
109105
)
110106

111107
if return_code != 0:
@@ -116,7 +112,7 @@
116112
vocal_target = args.audio
117113
else:
118114
vocal_target = os.path.join(
119-
temp_outputs_dir,
115+
temp_path,
120116
"htdemucs",
121117
os.path.splitext(os.path.basename(args.audio))[0],
122118
"vocals.wav",
@@ -133,9 +129,7 @@
133129
whisper_pipeline = faster_whisper.BatchedInferencePipeline(whisper_model)
134130
audio_waveform = faster_whisper.decode_audio(vocal_target)
135131
suppress_tokens = (
136-
find_numeral_symbol_tokens(whisper_model.hf_tokenizer)
137-
if args.suppress_numerals
138-
else [-1]
132+
find_numeral_symbol_tokens(whisper_model.hf_tokenizer) if args.suppress_numerals else [-1]
139133
)
140134

141135
if args.batch_size > 0:
@@ -167,9 +161,7 @@
167161

168162
emissions, stride = generate_emissions(
169163
alignment_model,
170-
torch.from_numpy(audio_waveform)
171-
.to(alignment_model.dtype)
172-
.to(alignment_model.device),
164+
torch.from_numpy(audio_waveform).to(alignment_model.dtype).to(alignment_model.device),
173165
batch_size=args.batch_size,
174166
)
175167

diarize_parallel.py

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,7 @@ def diarize_parallel(audio: torch.Tensor, device, queue: mp.Queue):
5050

5151
# Initialize parser
5252
parser = argparse.ArgumentParser()
53-
parser.add_argument(
54-
"-a", "--audio", help="name of the target audio file", required=True
55-
)
53+
parser.add_argument("-a", "--audio", help="name of the target audio file", required=True)
5654
parser.add_argument(
5755
"--no-stem",
5856
action="store_false",
@@ -116,7 +114,8 @@ def diarize_parallel(audio: torch.Tensor, device, queue: mp.Queue):
116114
# Isolate vocals from the rest of the audio
117115

118116
return_code = os.system(
119-
f'python -m demucs.separate -n htdemucs --two-stems=vocals "{args.audio}" -o "{temp_outputs_dir}" --device "{args.device}"'
117+
f"python -m demucs.separate -n htdemucs --two-stems=vocals "
118+
f'"{args.audio}" -o "{temp_path}" --device "{args.device}"'
120119
)
121120

122121
if return_code != 0:
@@ -156,9 +155,7 @@ def diarize_parallel(audio: torch.Tensor, device, queue: mp.Queue):
156155
whisper_pipeline = faster_whisper.BatchedInferencePipeline(whisper_model)
157156

158157
suppress_tokens = (
159-
find_numeral_symbol_tokens(whisper_model.hf_tokenizer)
160-
if args.suppress_numerals
161-
else [-1]
158+
find_numeral_symbol_tokens(whisper_model.hf_tokenizer) if args.suppress_numerals else [-1]
162159
)
163160

164161
if args.batch_size > 0:
@@ -190,9 +187,7 @@ def diarize_parallel(audio: torch.Tensor, device, queue: mp.Queue):
190187

191188
emissions, stride = generate_emissions(
192189
alignment_model,
193-
torch.from_numpy(audio_waveform)
194-
.to(alignment_model.dtype)
195-
.to(alignment_model.device),
190+
torch.from_numpy(audio_waveform).to(alignment_model.dtype).to(alignment_model.device),
196191
batch_size=args.batch_size,
197192
)
198193

@@ -261,9 +256,7 @@ def diarize_parallel(audio: torch.Tensor, device, queue: mp.Queue):
261256
with open(f"{os.path.splitext(args.audio)[0]}.txt", "w", encoding="utf-8-sig") as f:
262257
get_speaker_aware_transcript(ssm, f)
263258

264-
with open(
265-
f"{os.path.splitext(args.audio)[0]}.srt", "w", encoding="utf-8-sig"
266-
) as srt:
259+
with open(f"{os.path.splitext(args.audio)[0]}.srt", "w", encoding="utf-8-sig") as srt:
267260
write_srt(ssm, srt)
268261

269262
cleanup(temp_path)

helpers.py

Lines changed: 12 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -137,9 +137,7 @@
137137
"castilian": "es",
138138
}
139139

140-
whisper_langs = sorted(LANGUAGES.keys()) + sorted(
141-
[k.title() for k in TO_LANGUAGE_CODE.keys()]
142-
)
140+
whisper_langs = sorted(LANGUAGES.keys()) + sorted([k.title() for k in TO_LANGUAGE_CODE.keys()])
143141

144142
langs_to_iso = {
145143
"af": "afr",
@@ -270,19 +268,15 @@ def get_words_speaker_mapping(wrd_ts, spk_ts, word_anchor_option="start"):
270268
s, e, sp = spk_ts[turn_idx]
271269
if turn_idx == len(spk_ts) - 1:
272270
e = get_word_ts_anchor(ws, we, option="end")
273-
wrd_spk_mapping.append(
274-
{"word": wrd, "start_time": ws, "end_time": we, "speaker": sp}
275-
)
271+
wrd_spk_mapping.append({"word": wrd, "start_time": ws, "end_time": we, "speaker": sp})
276272
return wrd_spk_mapping
277273

278274

279275
sentence_ending_punctuations = ".?!"
280276

281277

282278
def get_first_word_idx_of_sentence(word_idx, word_list, speaker_list, max_words):
283-
is_word_sentence_end = (
284-
lambda x: x >= 0 and word_list[x][-1] in sentence_ending_punctuations
285-
)
279+
is_word_sentence_end = lambda x: x >= 0 and word_list[x][-1] in sentence_ending_punctuations
286280
left_idx = word_idx
287281
while (
288282
left_idx > 0
@@ -296,9 +290,7 @@ def get_first_word_idx_of_sentence(word_idx, word_list, speaker_list, max_words)
296290

297291

298292
def get_last_word_idx_of_sentence(word_idx, word_list, max_words):
299-
is_word_sentence_end = (
300-
lambda x: x >= 0 and word_list[x][-1] in sentence_ending_punctuations
301-
)
293+
is_word_sentence_end = lambda x: x >= 0 and word_list[x][-1] in sentence_ending_punctuations
302294
right_idx = word_idx
303295
while (
304296
right_idx < len(word_list) - 1
@@ -307,19 +299,12 @@ def get_last_word_idx_of_sentence(word_idx, word_list, max_words):
307299
):
308300
right_idx += 1
309301

310-
return (
311-
right_idx
312-
if right_idx == len(word_list) - 1 or is_word_sentence_end(right_idx)
313-
else -1
314-
)
302+
return right_idx if right_idx == len(word_list) - 1 or is_word_sentence_end(right_idx) else -1
315303

316304

317-
def get_realigned_ws_mapping_with_punctuation(
318-
word_speaker_mapping, max_words_in_sentence=50
319-
):
305+
def get_realigned_ws_mapping_with_punctuation(word_speaker_mapping, max_words_in_sentence=50):
320306
is_word_sentence_end = (
321-
lambda x: x >= 0
322-
and word_speaker_mapping[x]["word"][-1] in sentence_ending_punctuations
307+
lambda x: x >= 0 and word_speaker_mapping[x]["word"][-1] in sentence_ending_punctuations
323308
)
324309
wsp_len = len(word_speaker_mapping)
325310

@@ -357,9 +342,7 @@ def get_realigned_ws_mapping_with_punctuation(
357342
k += 1
358343
continue
359344

360-
speaker_list[left_idx : right_idx + 1] = [mod_speaker] * (
361-
right_idx - left_idx + 1
362-
)
345+
speaker_list[left_idx : right_idx + 1] = [mod_speaker] * (right_idx - left_idx + 1)
363346
k = right_idx
364347

365348
k += 1
@@ -434,9 +417,7 @@ def format_timestamp(
434417
milliseconds -= seconds * 1_000
435418

436419
hours_marker = f"{hours:02d}:" if always_include_hours or hours > 0 else ""
437-
return (
438-
f"{hours_marker}{minutes:02d}:{seconds:02d}{decimal_marker}{milliseconds:03d}"
439-
)
420+
return f"{hours_marker}{minutes:02d}:{seconds:02d}{decimal_marker}{milliseconds:03d}"
440421

441422

442423
def write_srt(transcript, file):
@@ -490,17 +471,11 @@ def _get_next_start_timestamp(word_timestamps, current_word_index, final_timesta
490471
return word_timestamps[next_word_index]["start"]
491472

492473

493-
def filter_missing_timestamps(
494-
word_timestamps, initial_timestamp=0, final_timestamp=None
495-
):
474+
def filter_missing_timestamps(word_timestamps, initial_timestamp=0, final_timestamp=None):
496475
# handle the first and last word
497476
if word_timestamps[0].get("start") is None:
498-
word_timestamps[0]["start"] = (
499-
initial_timestamp if initial_timestamp is not None else 0
500-
)
501-
word_timestamps[0]["end"] = _get_next_start_timestamp(
502-
word_timestamps, 0, final_timestamp
503-
)
477+
word_timestamps[0]["start"] = initial_timestamp if initial_timestamp is not None else 0
478+
word_timestamps[0]["end"] = _get_next_start_timestamp(word_timestamps, 0, final_timestamp)
504479

505480
result = [
506481
word_timestamps[0],

pyproject.toml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
[tool.ruff]
2+
line-length = 100
3+
extend-exclude = ["*.ipynb"]
4+
5+
[tool.ruff.lint]
6+
select = ["E", "F", "W", "I"]
7+
ignore = ["E203", "E731"]
8+
9+
[tool.ruff.lint.isort]
10+
lines-between-types = 1

0 commit comments

Comments
 (0)