File size: 3,016 Bytes
63dd946
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
#!/usr/bin/env python
# Copyright (c) 2026 The Anuvani-Diarization authors
# SPDX-License-Identifier: MIT OR Apache-2.0
"""Anuvani-Diarization (Indic model, release 1.0) — audio in, RTTM out.

  python diarize.py --out OUT_DIR audio1.wav [audio2.flac ...]
  python diarize.py --out OUT_DIR --in-dir AUDIO_DIR

Utterance-style segments matching IndicDiarBench's labelling convention (cannot-link VBx clustering and a learned
decoder; see README.md).
Determinism: FP32, TF32 off, deterministic kernels, seed 3407 per file. Byte-identical outputs to the published
reference RTTMs were verified with the defaults (--batch-size 8, --threads 2); see tools/verify_golden.py.
"""
import argparse
import hashlib
import json
import platform
import sys
import time
from pathlib import Path

HERE = Path(__file__).resolve().parent
sys.path.insert(0, str(HERE))

AUDIO_EXT = ("*.wav", "*.flac", "*.mp3", "*.m4a", "*.ogg")


def main():
    p = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter)
    p.add_argument("audio", nargs="*", type=Path)
    p.add_argument("--in-dir", type=Path)
    p.add_argument("--out", type=Path, required=True)
    p.add_argument("--bundle", type=Path, default=HERE / "bundle")
    p.add_argument("--device", default="cuda:0", help="cuda:N or cpu")
    p.add_argument("--batch-size", type=int, default=8)
    p.add_argument("--threads", type=int, default=2)
    a = p.parse_args()
    files = list(a.audio)
    if a.in_dir:
        for ext in AUDIO_EXT:
            files.extend(sorted(a.in_dir.glob(ext)))
    files = [f for f in files if f.is_file()]
    if not files:
        raise SystemExit("no audio files given")
    from anuvani_diar_ref.frontend import load_bundle, load_audio, analyse
    from anuvani_diar_ref.modes import indic_mode, write_rttm_indic
    from anuvani_diar_ref.decoder import load_decoder
    manifest = json.loads((a.bundle / "MANIFEST.json").read_text())
    mode = manifest["modes"]["indic"]
    model = load_bundle(a.bundle, a.device, a.batch_size, a.threads)
    decoder = load_decoder(a.bundle / mode["decoder"])
    a.out.mkdir(parents=True, exist_ok=True)
    log = dict(version=manifest["version"], model_config=mode, bundle_sha256=manifest["files"],
               device=a.device, batch_size=a.batch_size, threads=a.threads, python=platform.python_version(), files=[])
    for f in files:
        t0 = time.monotonic()
        audio, sr = load_audio(f)
        d = analyse(model, audio, sr)
        uri = f.stem
        out = a.out / f"{uri}.rttm"
        write_rttm_indic(out, uri, indic_mode(d, mode["clustering"], decoder))
        rec = dict(input=str(f), rttm=str(out), duration_s=round(len(audio) / sr, 3), seconds=round(time.monotonic() - t0, 2),
                   rttm_sha256=hashlib.sha256(out.read_bytes()).hexdigest())
        log["files"].append(rec)
        print(json.dumps(rec), flush=True)
    (a.out / "run.json").write_text(json.dumps(log, indent=1))


if __name__ == "__main__":
    main()