Skip to main content

Production toolkit around Qwen3-ForcedAligner: VAD pre-segmentation, multi-language word/char-level alignment, and speaker diarization.

Project description

qwen-aligner-toolkit

Production toolkit around Qwen3-ForcedAligner: VAD pre-segmentation, multi-language word/char-level forced alignment, and speaker diarization.

Why

qwen-asr ships an excellent forced aligner (Qwen3-ForcedAligner-0.6B) that handles multiple languages with one model — no per-language wav2vec2 needed, no kanji vocab gaps. This toolkit packages it with the surrounding pieces you typically need in production:

  • VAD (pyannote/segmentation-3.0) to chunk long audio
  • Diarization (pyannote/speaker-diarization-community-1) with per-word speaker assignment and run smoothing
  • Audio utilities (path / URL / bytes / np.ndarray → 16 kHz mono)
  • AVX-less CPU compatibility via a nagisa char-level stub

The toolkit does not do ASR. Bring your own transcript (from Whisper via vLLM, faster-whisper, qwen-asr itself, or any other system) and the toolkit will time-align it and label speakers.

Install

pip install qwen-aligner-toolkit
pip install qwen-aligner-toolkit[full]    # with VAD + diarization

Usage

Simple alignment (short audio)

from qwen_aligner_toolkit import Aligner

aligner = Aligner.from_pretrained()
words = aligner.align(
    text="甚至出现交易几乎停滞的情况。",
    audio="https://qianwen-res.oss-cn-beijing.aliyuncs.com/Qwen3-ASR-Repo/asr_zh.wav",
    language="Chinese",
)
for w in words:
    print(w.start_time, w.end_time, w.text)

ASR segments → word-level + speakers

from qwen_aligner_toolkit import Pipeline

pipeline = Pipeline.from_pretrained(hf_token="hf_...", device="cuda")

segments = [
    {"text": "おはようございます。", "start": 0.0, "end": 2.3},
    {"text": "今日は良い天気ですね。", "start": 2.3, "end": 5.1},
]

result = pipeline.align_segments(
    segments=segments,
    audio="audio.wav",
    language="Japanese",
    diarize=True,
)

for w in result.words:
    print(f"{w.start_time:.2f}-{w.end_time:.2f} [{w.speaker}] {w.text}")

VAD only

from qwen_aligner_toolkit import VAD

vad = VAD.from_pretrained(hf_token="hf_...")
chunks = vad.detect("audio.wav")

Sharing the segmentation model between VAD and Diarizer

pyannote/speaker-diarization-community-1 already loads a copy of pyannote/segmentation-3.0 internally. To avoid loading it twice when you also need standalone VAD, build the VAD on top of the diarizer's segmentation submodel:

from qwen_aligner_toolkit import Diarizer, VAD

diarizer = Diarizer.from_pretrained(hf_token="hf_...")
vad = VAD.from_segmentation_model(diarizer.segmentation_model)
chunks = vad.detect("audio.wav")

Per-speaker grouped output

If you want speaker turns with joined text (one entry per consecutive same-speaker run, with short-run smoothing), call Diarizer.split_words_by_speaker on word-level dicts:

from qwen_aligner_toolkit import Diarizer

words = [
    {"word": "hi",  "start": 0.0, "end": 1.0, "speaker": "A"},
    {"word": "yes", "start": 1.0, "end": 2.0, "speaker": "B"},
]
turns = Diarizer.split_words_by_speaker(words, min_duration_sec=0.3)
# [{"text": "hi", "start_time": 0.0, "end_time": 1.0, "speaker": "A"},
#  {"text": "yes", "start_time": 1.0, "end_time": 2.0, "speaker": "B"}]

For CJK languages where you don't want a space between concatenated tokens, pass join_separator="". The dict keys are configurable via word_key / start_key / end_key / speaker_key.

Configuration knobs

The toolkit has no global config — every knob is a function parameter. The table below maps common production env-var conventions to the corresponding toolkit argument, so you can wire them up with one-line plumbing.

VAD

Env var Default Toolkit argument
ASR_VAD_ONSET 0.5 VAD.detect(onset=...)
ASR_VAD_OFFSET 0.5 VAD.detect(offset=...)
ASR_VAD_MIN_DURATION_ON 0.25 VAD.detect(min_duration_on=...)
ASR_VAD_MIN_DURATION_OFF 0.5 VAD.detect(min_duration_off=...)
ASR_VAD_MAX_CHUNK_SEC 30.0 merge_segments(max_chunk_sec=...) / Pipeline.vad_chunks(max_chunk_sec=...)
ASR_VAD_MAX_GAP_SEC 0.5 merge_segments(max_gap_sec=...)
ASR_VAD_PADDING_SEC 0.2 Aligner.align_segments(padding_sec=...)

Diarization

Env var Default Toolkit argument
HF_TOKEN Diarizer.from_pretrained(hf_token=...)
ASR_DIARIZATION_MODEL pyannote/speaker-diarization-community-1 Diarizer.from_pretrained(model_id=...)
ASR_SPEAKER_MIN_DURATION_SEC 0.3 Diarizer.split_words_by_speaker(min_duration_sec=...)

Device / sample rate

Env var Default Toolkit argument
ASR_DEVICE cuda (or cpu if no GPU) Aligner.from_pretrained(device_map=...), Diarizer.from_pretrained(device=...), VAD.from_pretrained(device=...), Pipeline.from_pretrained(device=...)

All device= / device_map= arguments accept None to auto-detect (cuda if available, else cpu).

The toolkit operates internally at 16 kHz mono. Audio is auto-resampled on load; there is no target_sample_rate knob exposed at the public API.

Feature toggles

Flags like ASR_VAD_ENABLED or ASR_DIARIZATION_ENABLED belong to the orchestration layer of your application, not the toolkit. The toolkit exposes capabilities as separate classes (VAD, Diarizer) and the Pipeline constructor takes explicit with_vad= / with_diarization= flags:

Pipeline.from_pretrained(
    hf_token=HF_TOKEN if ASR_DIARIZATION_ENABLED else None,
    with_vad=ASR_VAD_ENABLED,
    with_diarization=ASR_DIARIZATION_ENABLED,
)

CPU compatibility (AVX requirement)

qwen-asr depends on nagisa, which ships DyNet38 compiled with AVX. On AVX-less CPUs (Intel Celeron G-series, some embedded SoCs), importing nagisa crashes with SIGILL.

If that affects you, install the char-level stub:

qwen-aligner-toolkit install-nagisa-stub
# or
python -m qwen_aligner_toolkit.compat install-stub

This downgrades Japanese tokenization from morpheme-level to character-level (other languages are unaffected). For forced alignment the difference is mostly cosmetic; speaker boundaries may even be detected at finer granularity.

For Docker:

RUN pip install qwen-aligner-toolkit && \
    qwen-aligner-toolkit install-nagisa-stub

License

Apache 2.0. See LICENSE.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

qwen_aligner_toolkit-0.1.2.tar.gz (17.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

qwen_aligner_toolkit-0.1.2-py3-none-any.whl (16.4 kB view details)

Uploaded Python 3

File details

Details for the file qwen_aligner_toolkit-0.1.2.tar.gz.

File metadata

  • Download URL: qwen_aligner_toolkit-0.1.2.tar.gz
  • Upload date:
  • Size: 17.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for qwen_aligner_toolkit-0.1.2.tar.gz
Algorithm Hash digest
SHA256 1f49fdeb877247e60874c7b6069db1b96984defbe260b3b682fd896b9d61483a
MD5 406b5d9b6f269bec4d9b106e93761ddd
BLAKE2b-256 82156407f1128329fe05c139c17a2f24c6615c06ae16f5d95f4ce55476d8e206

See more details on using hashes here.

Provenance

The following attestation bundles were made for qwen_aligner_toolkit-0.1.2.tar.gz:

Publisher: publish.yml on Anes1032/qwen-aligner-toolkit

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file qwen_aligner_toolkit-0.1.2-py3-none-any.whl.

File metadata

File hashes

Hashes for qwen_aligner_toolkit-0.1.2-py3-none-any.whl
Algorithm Hash digest
SHA256 8c2423fb3e321f26e34952ca41269bd7ea33acc2f0a26943f42bc0442516dfd0
MD5 2d00b5d7f3ea3744064fc810ccafe49d
BLAKE2b-256 da72ace30ff32b04f0ed5dc6526cd8d89b828eb2474412a3bd74242fb80bd27c

See more details on using hashes here.

Provenance

The following attestation bundles were made for qwen_aligner_toolkit-0.1.2-py3-none-any.whl:

Publisher: publish.yml on Anes1032/qwen-aligner-toolkit

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page