From d76d14a19edfa22a26a49bb5b9c1424cccb1d83e Mon Sep 17 00:00:00 2001 From: CJ Pais Date: Fri, 26 Jun 2026 05:40:19 -0700 Subject: [PATCH 1/4] stage 1 --- docs/porting/families/vibevoice.md | 98 +++++++++ .../vibevoice/vibevoice-asr/intake.json | 203 ++++++++++++++++++ scripts/preflight.py | 17 +- .../vibevoice/vibevoice-asr.manifest.json | 12 ++ 4 files changed, 329 insertions(+), 1 deletion(-) create mode 100644 docs/porting/families/vibevoice.md create mode 100644 reports/porting/vibevoice/vibevoice-asr/intake.json create mode 100644 tests/golden/vibevoice/vibevoice-asr.manifest.json diff --git a/docs/porting/families/vibevoice.md b/docs/porting/families/vibevoice.md new file mode 100644 index 00000000..95524599 --- /dev/null +++ b/docs/porting/families/vibevoice.md @@ -0,0 +1,98 @@ +# VibeVoice + +Status: research + +## Identity + +- Family key: `vibevoice` +- Upstream architecture string: `VibeVoiceForASRTraining` (model_type `vibevoice`) +- Hugging Face repo: `microsoft/VibeVoice-ASR` +- Hugging Face revision: `d0c9efdb8d614685062c04425d91e01b6f37d944` +- License: MIT +- Variants: `vibevoice-asr` (~9B params, ~17.4 GB BF16) + +## References + +- Canonical reference: `github.com/microsoft/VibeVoice` — the `vibevoice` Python package + (`vibevoice.modular.modeling_vibevoice_asr.VibeVoiceASRForConditionalGeneration`, + `vibevoice.processor.vibevoice_asr_processor.VibeVoiceASRProcessor`). The HF repo + ships weights + config.json only; no modeling code, processor, tokenizer, or + generation_config. +- Instrumented reference: same package (`demo/vibevoice_asr_inference_from_file.py`). +- Cross-check references: tech report arXiv:2601.18184; `github.com/localai-org/vibevoice.cpp` + (community ggml port — targets VibeVoice **TTS** and small Qwen2.5-0.5B variants, useful + as a causal-conv / tokenizer reference only, not a drop-in for the 9B ASR model). + +LM backbone is Qwen2.5-7B (decoder_config: hidden 3584, 28 layers, 28 heads / 4 KV, +intermediate 18944, vocab 152064, rope_theta 1e6, max_position 131072). The tokenizer +is the stock `Qwen/Qwen2.5-7B` byte-level BPE, loaded by the processor at runtime. + +Frontend is **not** a spectrogram. Raw 24 kHz waveform feeds two parallel causal-conv +VAE encoders (acoustic vae_dim 64, semantic vae_dim 128), each with cumulative 3200x +downsampling → ~7.5 Hz token rate. + +## Commands + +Reference run: + +```bash +# from a checkout of github.com/microsoft/VibeVoice +uv run --project scripts/envs/vibevoice \ + python demo/vibevoice_asr_inference_from_file.py \ + --model_path microsoft/VibeVoice-ASR --audio_files samples/jfk.wav +``` + +Reference dumps: + +```bash +TODO # porting-2-oracle: instrument vibevoice.modular.modeling_vibevoice_asr +``` + +Conversion: + +```bash +TODO # porting-3-convert: scripts/convert-vibevoice.py +``` + +Validation: + +```bash +uv run scripts/validate.py all --family vibevoice --variant vibevoice-asr +``` + +Benchmarks: + +```bash +TODO # porting-6-bench +``` + +## Capability Validation + +Proposed `Target` values below; non-forced rows require user sign-off at intake. + +| Capability | Mode | Command / test | Expected observable | Target | Status | +|------------|------|----------------|---------------------|--------|--------| +| Transcribe | explicit language hint | `build/bin/transcribe-cli -m models/vibevoice-asr/vibevoice-asr-BF16.gguf --language en samples/jfk.wav` | non-empty plausible English transcript | MUST PASS | TODO | +| Transcribe | auto / no language hint | `build/bin/transcribe-cli -m models/vibevoice-asr/vibevoice-asr-BF16.gguf samples/jfk.wav` | non-empty plausible transcript on the auto-detect path | MUST PASS | TODO | +| Translate | only if exposed | n/a | — | OUT OF SCOPE — model transcribes (incl. code-switching) but does not translate; not advertised | TODO | +| Segment timestamps | structured Who/When/What output | `` | segment-level timestamps present in parsed output | MUST PASS | TODO | +| Word timestamps | only if exposed | n/a | — | OUT OF SCOPE — model emits segment-level, not word-level timestamps | TODO | +| Speaker diarization | structured Who/When/What output | `` | speaker labels present in parsed output, DER/cpWER scored | MUST PASS | TODO | +| Hotwords / context bias | prompt-level biasing | `` | biased transcript on domain terms | OUT OF SCOPE — first port uses the default prompt; hotword prompt path deferred | TODO | +| Streaming | non-streaming model | n/a | — | OUT OF SCOPE — model is non-streaming (60-min single pass); `capabilities.streaming: false` | TODO | +| Batch (offline) | run_batch vs serial | `uv run scripts/batch_parity.py --model models/vibevoice-asr/vibevoice-asr-BF16.gguf --samples-dir samples/wer/librispeech-test-clean --batch-sizes 2,4,8 --backend cpu` | byte-identical hypotheses + CPU tensor parity | MUST PASS | TODO | + +## Notes + +- Acceptance dataset: LibriSpeech test-clean (English supported; publisher does not report + LibriSpeech, so the gate is the measured Oracle reference baseline, not a publisher score). + Publisher-reported English WER: 7.99% MLC-Challenge, 18.81% AMI-IHM. +- The model always emits structured Who/When/What output. Plain-WER scoring requires a + normalizer that strips speaker tags + timestamps from the hypothesis (Stage 2 / Stage 7). +- Segment timestamps and speaker diarization are **in scope (MUST PASS)** for this port: + Stage 2/Stage 4 must parse the structured output and Stage 7 must score it (timestamps + + DER/cpWER), in addition to plain transcript WER. +- Long-form (60-minute / 64K-token) inference is deferred; first port targets short utterances + (jfk / LibriSpeech segments). See intake `known_risks` for the full list, including the + learned-VAE frontend, dual-tokenizer fusion, the unused diffusion head, and KV-memory at + long context. diff --git a/reports/porting/vibevoice/vibevoice-asr/intake.json b/reports/porting/vibevoice/vibevoice-asr/intake.json new file mode 100644 index 00000000..67138264 --- /dev/null +++ b/reports/porting/vibevoice/vibevoice-asr/intake.json @@ -0,0 +1,203 @@ +{ + "schema_version": "transcribe-intake-v1", + "family": "vibevoice", + "hf_repo": "microsoft/VibeVoice-ASR", + "hf_revision": "d0c9efdb8d614685062c04425d91e01b6f37d944", + "sources": { + "config": { + "kind": "hf_file", + "path": "config.json", + "status": "found" + }, + "preprocessor": { + "kind": "hf_file", + "path": "preprocessor_config.json|feature_extractor_config.json", + "status": "accepted_gap", + "detail": "No spectrogram preprocessor ships. The frontend is a raw-24kHz-waveform learned VAE tokenizer defined in reference code (acoustic_tokenizer_config + semantic_tokenizer_config in config.json), not an STFT/mel feature extractor." + }, + "tokenizer_config": { + "kind": "hf_file", + "path": "tokenizer_config.json", + "status": "accepted_gap", + "detail": "No tokenizer ships in the model repo. VibeVoiceASRProcessor.from_pretrained loads the LM tokenizer from Qwen/Qwen2.5-7B (language_model_pretrained_name)." + }, + "tokenizer_json": { + "kind": "hf_file", + "path": "tokenizer.json", + "status": "accepted_gap", + "detail": "Inherited from Qwen/Qwen2.5-7B; not present in this repo." + }, + "generation_config": { + "kind": "hf_file", + "path": "generation_config.json", + "status": "missing", + "detail": "Generation params are passed by the demo script at call time (max_new_tokens, num_beams, do_sample, temperature, top_p); capture them from reference code at Stage 2." + }, + "safetensors_metadata": { + "kind": "hf_api", + "path": "HfApi.get_safetensors_metadata", + "status": "found", + "detail": "header-only floating dtype distribution; 8 shards, ~17.4 GB total, BF16=1177; no tensor payloads downloaded" + }, + "reference_code": { + "kind": "reference_code", + "path": "github.com/microsoft/VibeVoice (vibevoice python package): modular/modeling_vibevoice_asr.py, processor/vibevoice_asr_processor.py, demo/vibevoice_asr_inference_from_file.py, docs/vibevoice-asr.md", + "status": "found", + "detail": "Canonical reference implementation. Tech report arXiv:2601.18184." + } + }, + "variants": [ + { + "name": "vibevoice-asr", + "memory_gb": 17.4, + "files": [ + "model-00001-of-00008.safetensors", + "model-00002-of-00008.safetensors", + "model-00003-of-00008.safetensors", + "model-00004-of-00008.safetensors", + "model-00005-of-00008.safetensors", + "model-00006-of-00008.safetensors", + "model-00007-of-00008.safetensors", + "model-00008-of-00008.safetensors" + ] + } + ], + "config": { + "architecture_candidates": [ + "audio-llm" + ], + "key_fields": { + "architectures": [ + "VibeVoiceForASRTraining" + ], + "model_type": "vibevoice", + "decoder_config.model_type": "qwen2", + "decoder_config.hidden_size": 3584, + "decoder_config.num_hidden_layers": 28, + "decoder_config.num_attention_heads": 28, + "decoder_config.num_key_value_heads": 4, + "decoder_config.intermediate_size": 18944, + "decoder_config.vocab_size": 152064, + "decoder_config.max_position_embeddings": 131072, + "decoder_config.rope_theta": 1000000.0, + "acoustic_vae_dim": 64, + "semantic_vae_dim": 128, + "acoustic_tokenizer.encoder_ratios": [8, 5, 5, 4, 2, 2], + "acoustic_tokenizer.encoder_depths": "3-3-3-3-3-3-8", + "acoustic_tokenizer.mixer_layer": "depthwise_conv", + "has_diffusion_head": true + } + }, + "dtype": { + "expected": "bfloat16", + "source": "weights_header", + "evidence": "safetensors header BF16=1177 (all floating tensors); component configs self-declare dtype=bfloat16; model card states BF16. config top-level dtype=float32 is the autoset default and is contradicted by the weights.", + "details": { + "config_declared": "float32", + "header_distribution": { + "BF16": 1177 + } + }, + "expected_f32_tensors": [ + "*norm*", + "*bias*" + ] + }, + "frontend": { + "sample_rate": 24000, + "n_mels": null, + "hop_length": null, + "fft_size": null, + "window": null, + "normalization": null, + "preemphasis": null, + "dither": null, + "center": null, + "padding_mode": "constant", + "mel_filterbank_norm": null + }, + "tokenizer": { + "type": "bpe", + "vocab_size": 152064, + "special_tokens": { + "endoftext": 151643, + "im_start": 151644, + "im_end": 151645 + }, + "has_language_tokens": false, + "vocab_sha256": null + }, + "capabilities": { + "languages": [ + "en", "zh", "es", "pt", "de", "ja", "ko", "fr", "ru", "id", + "sv", "it", "he", "nl", "pl", "no", "tr", "th", "ar", "hu", + "ca", "cs", "da", "fa", "af", "hi", "fi", "et", "aa", "el", + "ro", "vi", "bg", "is", "sl", "sk", "lt", "sw", "uk", "kl", + "lv", "hr", "ne", "sr", "tl", "yi", "ms", "ur", "mn", "hy", "jv" + ], + "language_detection": true, + "translation": false, + "timestamps": ["segment"], + "streaming": false, + "voice_activity_detection": null, + "speaker_diarization": true + }, + "upstream_benchmarks": [ + { + "dataset": "MLC-Challenge en", + "language": "en", + "metric": "wer", + "score": 7.99, + "score_unit": "percent", + "source": "github.com/microsoft/VibeVoice docs/vibevoice-asr.md", + "notes": "English WER reported by publisher." + }, + { + "dataset": "AMI-IHM", + "language": "en", + "metric": "wer", + "score": 18.81, + "score_unit": "percent", + "source": "github.com/microsoft/VibeVoice docs/vibevoice-asr.md", + "notes": "English WER on AMI individual-headset-microphone." + }, + { + "dataset": "LibriSpeech test-clean", + "language": "en", + "metric": "wer", + "score": null, + "score_unit": "percent", + "source": "not reported by publisher", + "notes": "Acceptance target for this port. Publisher does not report LibriSpeech; downstream gates use the measured Oracle reference baseline, not a publisher number." + } + ], + "reference_framework": "author_repo_vibevoice", + "reference_rationale": "The canonical implementation is the microsoft/VibeVoice GitHub repo's `vibevoice` Python package. The ASR classes (VibeVoiceASRForConditionalGeneration in vibevoice.modular.modeling_vibevoice_asr, VibeVoiceASRProcessor in vibevoice.processor.vibevoice_asr_processor) live there, not in mainline transformers; the HF repo ships no modeling code, processor, tokenizer, or generation_config. Despite 'available in a Transformers release' marketing, the load path in the official demo imports from the vibevoice package and pulls the tokenizer from Qwen/Qwen2.5-7B. The author repo is the source of truth.", + "architecture_pattern": "audio-llm", + "known_risks": [ + "Frontend is a learned VAE tokenizer, NOT a spectrogram. Raw 24 kHz waveform feeds two parallel causal-conv VAE encoders (acoustic vae_dim=64 std_dist=gaussian fix_std=0.5; semantic vae_dim=128 std_dist=none), each with cumulative 3200x downsampling (encoder_ratios [8,5,5,4,2,2], depthwise_conv mixer, RMSNorm) yielding a ~7.5 Hz token rate. No existing transcribe.cpp frontend covers this; ggml needs a whole new causal conv-stack + VAE-reparam subsystem. Highest-risk item.", + "Dual-tokenizer fusion is unverified. Both acoustic and semantic latents are consumed and projected into the Qwen2.5 embedding space; how the two streams combine (concat vs sum vs separate projection) and where they scatter into the LM token stream must be read from reference code before C++ work.", + "diffusion_head_config (DDPM, v-prediction, 20 inference steps) is present in the checkpoint. It is the VibeVoice TTS acoustic-generation head and should be unused for ASR. Converter must confirm it (and the acoustic decoder) are dead weight for the ASR path and drop them; risk of porting unused weight or missing a hidden ASR dependency.", + "Qwen2.5-7B LM backbone, ~9B params total, ~17.4 GB BF16. Largest port to date alongside Voxtral-small. KV cache for the advertised 64K-token / 60-minute context is a major memory constraint; shipping will depend on quantization.", + "Structured diarized output ('Who/When/What': speaker labels + timestamps + content). Plain-WER scoring against LibriSpeech requires a normalizer/parser that strips speaker tags and timestamps from the hypothesis. Oracle (Stage 2) and WER (Stage 7) stages need this extraction; LibriSpeech is single-speaker so diarization is trivial there but output is still structured.", + "No tokenizer / preprocessor / generation_config in the HF repo. Tokenizer is the stock Qwen/Qwen2.5-7B byte-level BPE (embedding vocab padded to 152064), loaded at runtime by VibeVoiceASRProcessor. Converter must fetch and embed the Qwen2.5-7B tokenizer plus the processor's prompt/chat template (with add_generation_prompt and the hotword/context fields) into the GGUF; none of it ships with the weights.", + "Hotwords/context biasing is a prompt-text feature, not a separate mechanism. Confirm it is purely text injected into the chat template so it round-trips through GGUF-stored template metadata; if it touches the tokenizer or model wiring the C++ surface grows.", + "Long-context / full-attention design: max_position_embeddings=131072, rope_theta=1e6, no sliding window, Flash-Attention assumed. First port should target short utterances (jfk / LibriSpeech segments); 60-minute long-form and 64K KV behavior are deferred and tracked separately.", + "dtype: config top-level dtype=float32 contradicts BF16 weights (header BF16=1177); treat BF16 as reference and watch for genuinely-F32 tensors (norms/biases) the converter must preserve.", + "A community ggml port exists (localai-org/vibevoice.cpp) but targets VibeVoice TTS and small Qwen2.5-0.5B variants, not the 9B ASR model. Useful as a conv/tokenizer reference only, not a drop-in." + ], + "intake_gaps": [ + { + "field": "tokenizer.special_tokens", + "reason": "endoftext/im_start/im_end ids are the stock Qwen2.5-7B values; confirm the exact eos/pad used by VibeVoiceASRProcessor and the generation config at Stage 2." + }, + { + "field": "frontend", + "reason": "VAE-tokenizer frontend has no schema fields beyond sample_rate=24000; full conv-stack / reparam spec must be lifted from reference code in Stage 2 (oracle) and Stage 4 (cpp)." + }, + { + "field": "capabilities.voice_activity_detection", + "reason": "Model performs implicit segmentation via diarization but exposes no standalone VAD; left null." + } + ] +} diff --git a/scripts/preflight.py b/scripts/preflight.py index 8bb3b562..e0b0eea5 100755 --- a/scripts/preflight.py +++ b/scripts/preflight.py @@ -143,6 +143,7 @@ def load_declared_state(repo_root: Path, family: str, variant: str | None) -> di "hf_repo": data["hf_repo"], "hf_revision": data.get("hf_revision"), "expected_dtype": _expected_dtype_from_intake(data), + "dtype_source": data.get("dtype", {}).get("source"), "frontend": data.get("frontend", {}), "tokenizer": data.get("tokenizer", {}), "capabilities": data.get("capabilities", {}), @@ -160,6 +161,7 @@ def load_declared_state(repo_root: Path, family: str, variant: str | None) -> di "hf_repo": source_model.get("hf_repo"), "hf_revision": source_model.get("hf_revision"), "expected_dtype": data.get("expected_dtype"), + "dtype_source": data.get("dtype_source"), "frontend": data.get("frontend", {}), "tokenizer": data.get("tokenizer_summary", {}), "capabilities": data.get("capabilities", {}), @@ -399,6 +401,13 @@ def check_dtype(declared, gguf_kvs, reference, gate: Gate) -> CheckResult: decl_dtype = declared.get("expected_dtype") cfg_dtype = _config_dtype(reference.get("config")) nemo_authoritative = bool(reference.get("nemo_authoritative")) + # When the intake derived its expected dtype straight from the + # safetensors header, the storage dtype is authoritative and HF + # config.json's top-level torch_dtype is treated as training/default + # metadata (often a vestigial float32 autoset contradicted by all-BF16 + # weights). Same rationale as nemo_authoritative; Gate B still hard-checks + # the declared dtype against the converted GGUF. + weights_authoritative = declared.get("dtype_source") == "weights_header" gguf_ftype = gguf_kvs.get("general.file_type") if gguf_kvs else None gguf_dtype = _gguf_file_type_to_str(gguf_ftype) if gguf_ftype is not None else None @@ -406,6 +415,8 @@ def check_dtype(declared, gguf_kvs, reference, gate: Gate) -> CheckResult: if nemo_authoritative: sources["nemo_authoritative"] = True sources["nemo_source"] = reference.get("nemo_source") + if weights_authoritative: + sources["weights_header_authoritative"] = True if gguf_kvs: sources["gguf_file_type"] = gguf_ftype sources["gguf_dtype"] = gguf_dtype @@ -415,7 +426,7 @@ def check_dtype(declared, gguf_kvs, reference, gate: Gate) -> CheckResult: # When NeMo is authoritative for this variant, HF config.json's torch_dtype # is training/optimizer metadata, not storage — skip the comparison. # Storage dtype is verified at Gate B against the converted GGUF. - n_ref = None if nemo_authoritative else (_norm_dtype(cfg_dtype) if cfg_dtype else None) + n_ref = None if (nemo_authoritative or weights_authoritative) else (_norm_dtype(cfg_dtype) if cfg_dtype else None) # Hard fail: declared vs GGUF disagree. The GGUF is what the C++ loader will see. if n_decl and n_gguf and n_decl != n_gguf: @@ -430,6 +441,10 @@ def check_dtype(declared, gguf_kvs, reference, gate: Gate) -> CheckResult: detail = "no reference or GGUF dtype to cross-check declared value" if nemo_authoritative: detail += " (HF config.json torch_dtype skipped: NeMo .nemo is authoritative)" + elif weights_authoritative: + detail += (f" (HF config.json dtype='{cfg_dtype}' skipped: declared dtype came " + "from the safetensors header, which is authoritative for storage; " + "Gate B verifies against the GGUF)") return CheckResult("dtype_consistency", gate, "warn", sources, detail) return CheckResult("dtype_consistency", gate, "pass", sources) diff --git a/tests/golden/vibevoice/vibevoice-asr.manifest.json b/tests/golden/vibevoice/vibevoice-asr.manifest.json new file mode 100644 index 00000000..b266715d --- /dev/null +++ b/tests/golden/vibevoice/vibevoice-asr.manifest.json @@ -0,0 +1,12 @@ +{ + "schema": "transcribe-golden-manifest-v1", + "family": "vibevoice", + "variant": "vibevoice-asr", + "source_model": { + "hf_repo": "microsoft/VibeVoice-ASR", + "hf_revision": "d0c9efdb8d614685062c04425d91e01b6f37d944" + }, + "expected_dtype": "bfloat16", + "dtype_source": "weights_header", + "_skeleton": true +} From 33ad944384e1cfe8fe6741eb88e1dc477d490da5 Mon Sep 17 00:00:00 2001 From: CJ Pais Date: Fri, 26 Jun 2026 18:15:53 -0700 Subject: [PATCH 2/4] stage 2 --- docs/porting/families/vibevoice.md | 20 +- scripts/_vibevoice_modal_dump.py | 80 + scripts/build_vibevoice_oracle.py | 152 ++ scripts/dump_reference_vibevoice_author.py | 283 ++++ scripts/envs/vibevoice/pyproject.toml | 22 + scripts/envs/vibevoice/uv.lock | 1288 +++++++++++++++++ scripts/wer/run_reference_vibevoice_author.py | 179 +++ .../vibevoice/vibevoice-asr.manifest.json | 40 +- tests/tolerances/vibevoice.json | 135 ++ 9 files changed, 2195 insertions(+), 4 deletions(-) create mode 100644 scripts/_vibevoice_modal_dump.py create mode 100644 scripts/build_vibevoice_oracle.py create mode 100644 scripts/dump_reference_vibevoice_author.py create mode 100644 scripts/envs/vibevoice/pyproject.toml create mode 100644 scripts/envs/vibevoice/uv.lock create mode 100644 scripts/wer/run_reference_vibevoice_author.py create mode 100644 tests/tolerances/vibevoice.json diff --git a/docs/porting/families/vibevoice.md b/docs/porting/families/vibevoice.md index 95524599..11545c5e 100644 --- a/docs/porting/families/vibevoice.md +++ b/docs/porting/families/vibevoice.md @@ -42,10 +42,22 @@ uv run --project scripts/envs/vibevoice \ --model_path microsoft/VibeVoice-ASR --audio_files samples/jfk.wav ``` -Reference dumps: +Reference dumps (Modal — the 9B model needs a >=40 GB GPU; canonical dumper is +`scripts/dump_reference_vibevoice_author.py`, hosted by `_vibevoice_modal_dump.py`): ```bash -TODO # porting-2-oracle: instrument vibevoice.modular.modeling_vibevoice_asr +uv run --project scripts/envs/qwen3_asr modal run scripts/_vibevoice_modal_dump.py +# -> build/validate/vibevoice/vibevoice-asr/jfk/ref/ (+ envelope.json, transcript.json) +uv run scripts/build_vibevoice_oracle.py # dump_coverage.json + provisional tolerances +``` + +Reference WER (Modal L40S; ~2 h for full test-clean): + +```bash +uv run --project scripts/envs/qwen3_asr modal run \ + scripts/wer/remote/modal_sweep.py::reference_sweep \ + --variants vibevoice:vibevoice-asr --gpu L40S +uv run scripts/wer/score.py reports/wer/vibevoice-asr-REF.librispeech-test-clean.jsonl ``` Conversion: @@ -86,7 +98,9 @@ Proposed `Target` values below; non-forced rows require user sign-off at intake. - Acceptance dataset: LibriSpeech test-clean (English supported; publisher does not report LibriSpeech, so the gate is the measured Oracle reference baseline, not a publisher score). - Publisher-reported English WER: 7.99% MLC-Challenge, 18.81% AMI-IHM. + **Measured Oracle reference WER: 2.11%** (2620 utts, 0 errors, CI [1.93%, 2.28%]; mean + acoustic path, BF16 LM, L40S). Publisher-reported English WER on other sets: 7.99% + MLC-Challenge, 18.81% AMI-IHM (harder/multi-speaker — not directly comparable). - The model always emits structured Who/When/What output. Plain-WER scoring requires a normalizer that strips speaker tags + timestamps from the hypothesis (Stage 2 / Stage 7). - Segment timestamps and speaker diarization are **in scope (MUST PASS)** for this port: diff --git a/scripts/_vibevoice_modal_dump.py b/scripts/_vibevoice_modal_dump.py new file mode 100644 index 00000000..8a6f2850 --- /dev/null +++ b/scripts/_vibevoice_modal_dump.py @@ -0,0 +1,80 @@ +#!/usr/bin/env python3 +"""Modal host for the VibeVoice-ASR reference dumper. + +The 9B model can't run on the local 16 GB M4, so the canonical dumper +(scripts/dump_reference_vibevoice_author.py) executes in a Modal L40S container +and the f32 tensor artifacts are tarred back to the laptop, landing under +build/validate/vibevoice/vibevoice-asr/. + + uv run --project scripts/envs/qwen3_asr modal run scripts/_vibevoice_modal_dump.py +""" +import io +import tarfile +from pathlib import Path + +import modal + +VIBEVOICE_SHA = "303b2833e01cff4578ec278bbfe536da54bd19fe" +REPO = Path(__file__).resolve().parents[1] + +image = ( + modal.Image.from_registry( + "nvidia/cuda:12.4.1-runtime-ubuntu22.04", add_python="3.11" + ) + .apt_install("git", "ffmpeg", "libsndfile1", "ca-certificates") + .pip_install( + "torch", "transformers==4.51.3", "accelerate>=1.6.0", "diffusers>=0.30", + "librosa>=0.10", "soundfile>=0.12", "ml-collections>=0.1.1", + "absl-py>=2.0", "einops>=0.7", "numpy>=1.26", "scipy>=1.11", + "huggingface_hub>=0.30", + ) + .run_commands( + "git clone https://github.com/microsoft/VibeVoice /opt/VibeVoice", + f"cd /opt/VibeVoice && git checkout {VIBEVOICE_SHA}", + ) + .add_local_file("samples/jfk.wav", "/root/jfk.wav") + .add_local_file("scripts/dump_reference_vibevoice_author.py", + "/root/scripts/dump_reference_vibevoice_author.py") + .add_local_file("scripts/lib/__init__.py", "/root/scripts/lib/__init__.py") + .add_local_file("scripts/lib/ref_dump.py", "/root/scripts/lib/ref_dump.py") +) + +hf_vol = modal.Volume.from_name("hf-cache", create_if_missing=True) +app = modal.App("vibevoice-dump") + + +@app.function(image=image, gpu="L40S", timeout=3000, + volumes={"/root/.cache/huggingface": hf_vol}, + secrets=[modal.Secret.from_name("huggingface-secret")]) +def dump() -> bytes: + import os + import subprocess + + env = {**os.environ, "VIBEVOICE_SRC": "/opt/VibeVoice", + "PYTORCH_CUDA_ALLOC_CONF": "expandable_segments:True"} + cmd = [ + "python", "/root/scripts/dump_reference_vibevoice_author.py", "dump", + "--model", "microsoft/VibeVoice-ASR", + "--audio", "/root/jfk.wav", + "--out", "/root/out/jfk/ref", + "--device", "cuda", + ] + print("running:", " ".join(cmd)) + subprocess.run(cmd, env=env, check=True) + + buf = io.BytesIO() + with tarfile.open(fileobj=buf, mode="w:gz") as tar: + tar.add("/root/out", arcname=".") + return buf.getvalue() + + +@app.local_entrypoint() +def main(): + data = dump.remote() + dest = REPO / "build" / "validate" / "vibevoice" / "vibevoice-asr" + dest.mkdir(parents=True, exist_ok=True) + with tarfile.open(fileobj=io.BytesIO(data), mode="r:gz") as tar: + tar.extractall(dest) + print(f"extracted {len(data)} bytes -> {dest}") + for p in sorted(dest.rglob("*.json")): + print(" ", p.relative_to(REPO)) diff --git a/scripts/build_vibevoice_oracle.py b/scripts/build_vibevoice_oracle.py new file mode 100644 index 00000000..88088538 --- /dev/null +++ b/scripts/build_vibevoice_oracle.py @@ -0,0 +1,152 @@ +#!/usr/bin/env python3 +""" +Build build/validate/vibevoice//dump_coverage.json and the +family-level tests/tolerances/vibevoice.json from the on-disk tensor sidecars +produced by scripts/dump_reference_vibevoice_author.py (run on Modal). + +One-shot helper used at the end of Stage 2. Not invoked from the runtime. +Layout: build/validate/vibevoice///ref/.{f32,json} +""" +from __future__ import annotations + +import json +import sys +from pathlib import Path + +ROOT = Path(__file__).resolve().parent.parent +BUILD = ROOT / "build" / "validate" / "vibevoice" +TOL = ROOT / "tests" / "tolerances" / "vibevoice.json" +FAMILY = "vibevoice" +VARIANTS = ["vibevoice-asr"] + +# non-tensor behavioral artifacts the dumper writes into the ref dir +NON_TENSOR = {"transcript.json", "transcript.parsed.json", "envelope.json", + "dump_coverage.json"} + + +def is_tensor_sidecar(meta: dict) -> bool: + return all(k in meta for k in ("name", "shape", "dtype", "layout")) + + +def walk_variant(variant: str) -> list[dict]: + variant_dir = BUILD / variant + if not variant_dir.exists(): + print(f" warn: {variant_dir} missing") + return [] + entries: list[dict] = [] + for json_path in sorted(variant_dir.rglob("*.json")): + if json_path.name in NON_TENSOR: + continue + try: + meta = json.loads(json_path.read_text()) + except json.JSONDecodeError as e: + print(f" warn: bad JSON at {json_path}: {e}") + continue + if not is_tensor_sidecar(meta): + continue + rel = json_path.relative_to(variant_dir) + parts = rel.parts + # Layout: /ref/.json + if len(parts) != 3 or parts[-2] != "ref": + print(f" warn: unexpected layout at {json_path}") + continue + entries.append({ + "case": parts[0], + "stage_dir": "ref", + "stage": meta.get("stage", ""), + "name": meta["name"], + "shape": list(meta["shape"]), + "dtype": meta["dtype"], + "rel_path": str(rel), + }) + return entries + + +def write_coverage(variant: str, entries: list[dict]) -> Path: + out = BUILD / variant / "dump_coverage.json" + out.write_text(json.dumps( + {"family": FAMILY, "variant": variant, "tensors": entries}, indent=2) + "\n") + return out + + +def aggregate_tolerances(per_variant: dict[str, list[dict]]) -> dict[str, dict]: + stats: dict[str, list[tuple[str, float, float]]] = {} + for variant, entries in per_variant.items(): + for e in entries: + meta = json.loads((BUILD / variant / e["rel_path"]).read_text()) + stats.setdefault(e["name"], []).append( + (variant, float(meta.get("p99_abs", 0.0)), float(meta.get("rms", 0.0)))) + out: dict[str, dict] = {} + for name, rows in sorted(stats.items()): + worst_p99 = max(r[1] for r in rows) + worst_rms = max(r[2] for r in rows) + out[name] = { + "max_abs": max(1e-4 * worst_p99, 1e-6), + "mean_abs": max(1e-5 * worst_rms, 1e-6), + "_provisional": True, + "_seen_in": sorted({r[0] for r in rows}), + } + return out + + +def main() -> int: + if not BUILD.exists(): + print(f"error: {BUILD} does not exist; run the dumper first") + return 2 + per_variant: dict[str, list[dict]] = {} + print("=== dump_coverage.json per variant ===") + for v in VARIANTS: + entries = walk_variant(v) + if not entries: + print(f" {v}: 0 tensors (skipping)") + continue + cov = write_coverage(v, entries) + per_variant[v] = entries + print(f" {v}: {len(entries)} tensors -> {cov.relative_to(ROOT)}") + + tols = aggregate_tolerances(per_variant) + payload: dict = { + "_comment": [ + "VibeVoice-ASR per-tensor tolerances for compare_tensors.py.", + "", + "CORRECTNESS REGIME", + "- Reference: microsoft/VibeVoice-ASR via the author `vibevoice` package", + " @ 303b2833e01cff4578ec278bbfe536da54bd19fe (HF rev", + " d0c9efdb8d614685062c04425d91e01b6f37d944), run on a Modal L40S GPU,", + " attn_implementation=eager. Dumper: scripts/dump_reference_vibevoice_author.py.", + "- Audio-LLM: raw 24kHz -> acoustic+semantic causal-conv VAE tokenizers", + " (loaded fp32) -> SpeechConnector -> 3584 -> element-wise SUM -> scattered", + " into a Qwen2.5-7B LM (bf16) -> lm_head. C++: ggml, BF16 weights for the LM.", + "", + "DETERMINISM", + "- The acoustic path samples a Gaussian VAE latent (fix_std=0.5); contract", + " tensors use the deterministic MEAN (mode()). Verified: transcription content", + " is identical mean-vs-sampled, and the lm_head argmax is stable across 8 noisy", + " passes (see /ref/envelope.json for the sampled std band). The C++ port", + " must use the acoustic mean, not a sample.", + "", + "ENTRY SOURCING (provisional)", + "- Per-tensor max_abs = max(1e-4 x p99_abs, 1e-6)", + "- Per-tensor mean_abs = max(1e-5 x rms, 1e-6)", + "- All entries carry _provisional: true. Stage 4 finalizes against observed", + " C++ drift and removes the flag tensor-by-tensor.", + "- enc.* (VAE frontend) runs fp32 in the reference; enc.combined feeds the", + " bf16 LM, so expect the largest C++ drift to localize there.", + "", + "DO NOT SHIP a model while _provisional entries remain.", + ], + **tols, + } + TOL.parent.mkdir(parents=True, exist_ok=True) + TOL.write_text(json.dumps(payload, indent=2) + "\n") + vals = sorted(v["max_abs"] for v in tols.values()) + n = len(vals) + print(f"\n wrote {TOL.relative_to(ROOT)} with {n} tensor entries") + if n: + print(f" max_abs distribution: min={vals[0]:.3e} " + f"median={vals[n // 2]:.3e} max={vals[-1]:.3e}") + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/scripts/dump_reference_vibevoice_author.py b/scripts/dump_reference_vibevoice_author.py new file mode 100644 index 00000000..ca6d43e0 --- /dev/null +++ b/scripts/dump_reference_vibevoice_author.py @@ -0,0 +1,283 @@ +#!/usr/bin/env python3 +""" +dump_reference_vibevoice_author.py - VibeVoice-ASR reference tensors from the +microsoft/VibeVoice author package (the canonical implementation; the HF repo +ships weights + config only). + +VibeVoice-ASR is an audio-LLM: raw 24 kHz waveform -> two parallel causal-conv +VAE tokenizers (acoustic vae_dim=64, semantic vae_dim=128) -> SpeechConnectors +(-> 3584) -> element-wise SUM -> scattered into a Qwen2.5-7B LM at the +acoustic-token positions -> lm_head -> structured JSON (Speaker/Start/End/Content). + +DETERMINISM. The stock acoustic path samples a Gaussian VAE latent +(`sample(dist_type='gaussian')`, fix_std=0.5), which is non-deterministic and +unreproducible across a C++ port. The acoustic *mean* (`mode()`) is +deterministic, and we verified the transcription content is identical to the +sampled path (the noise only perturbs post-JSON junk). So the numerical contract +is the MEAN path: this dumper patches `sample` -> mean for all contract tensors, +and additionally records a sampled-envelope (per-tensor std/range over N noisy +passes) so Stage 4 has the "what should it look like" band the published model +operates in. + +Runs in-container on a >=40 GB GPU (the 9B BF16 model + unused TTS decoder / +diffusion-head weights occupy ~21.6 GB; 24 GB cards OOM). The vibevoice source +path comes from $VIBEVOICE_SRC (default models/_vendor/VibeVoice). + +Usage: + VIBEVOICE_SRC=/opt/VibeVoice \ + python scripts/dump_reference_vibevoice_author.py dump \ + --model microsoft/VibeVoice-ASR \ + --audio samples/jfk.wav \ + --out build/validate/vibevoice/vibevoice-asr/jfk + +Dump points (match tests/tolerances/vibevoice.json): + enc.input_waveform normalized 24kHz waveform the model encodes + enc.acoustic.mean acoustic VAE latent mean [T, 64] + enc.acoustic.feat acoustic_connector(mean) [T, 3584] + enc.semantic.mean semantic VAE latent mean [T, 128] + enc.semantic.feat semantic_connector(mean) [T, 3584] + enc.combined acoustic.feat + semantic.feat [T, 3584] (injected) + dec.token_emb LM input embeddings pre-injection [L, 3584] + dec.inputs_embeds embeddings after speech scatter [L, 3584] + dec.block..out selected Qwen2 layer outputs (pre-norm) + dec.final_norm final RMSNorm output [L, 3584] + dec.logits_lastpos lm_head logits at the last prompt position [vocab] +""" +from __future__ import annotations + +import argparse +import json +import os +import sys +from pathlib import Path + +import numpy as np + +sys.path.insert(0, str(Path(__file__).resolve().parent)) +from lib.ref_dump import write_tensor, write_transcript # noqa: E402 + +MODEL_DEFAULT = "microsoft/VibeVoice-ASR" +LM_TOKENIZER = "Qwen/Qwen2.5-7B" +HIDDEN = 3584 +DUMP_LAYERS = (0, 13, 27) # first / middle / last Qwen2 decoder layer (28 total) +ENVELOPE_N = 8 # sampled passes for the stochastic-acoustic band + + +def _vibevoice_src() -> str: + src = os.environ.get("VIBEVOICE_SRC") + if not src: + src = str(Path(__file__).resolve().parents[1] / "models" / "_vendor" / "VibeVoice") + if not Path(src, "vibevoice").is_dir(): + raise SystemExit(f"vibevoice source not found at {src} (set $VIBEVOICE_SRC)") + return src + + +def _np(t) -> np.ndarray: + import torch + return t.detach().to(dtype=torch.float32, device="cpu").numpy() + + +def _as(mod, x): + """Cast x to the module's parameter dtype. The reference loads the VAE + tokenizers / connectors in fp32 while the Qwen2.5 LM is bf16; matching the + module dtype mirrors what the model's own forward does internally.""" + return x.to(next(mod.parameters()).dtype) + + +def load_reference(model_id: str, device: str): + import torch + import transformers + from transformers import PretrainedConfig + + sys.path.insert(0, _vibevoice_src()) + transformers.logging.set_verbosity_error() + # transformers 4.51.3 eagerly builds `logger.info(f"Model config {config}")`; + # this model's nested sub-configs carry torch.dtype under the new `dtype` + # field, which to_json_string can't serialize. Make repr crash-safe. + def _safe_repr(self): + try: + return f"{self.__class__.__name__} {self.to_json_string()}" + except Exception: + return f"{self.__class__.__name__}()" + PretrainedConfig.__repr__ = _safe_repr + + from vibevoice.modular.modeling_vibevoice_asr import VibeVoiceASRForConditionalGeneration + from vibevoice.processor.vibevoice_asr_processor import VibeVoiceASRProcessor + + processor = VibeVoiceASRProcessor.from_pretrained( + model_id, language_model_pretrained_name=LM_TOKENIZER) + # eager attention: deterministic + hookable (no fused SDPA kernels). + model = VibeVoiceASRForConditionalGeneration.from_pretrained( + model_id, dtype=torch.bfloat16, attn_implementation="eager", + device_map=device).eval() + return processor, model + + +def _patch_mean(restore=False): + """Patch the VAE EncoderOutput.sample to return the deterministic mean. + Returns the original callable so the caller can restore it.""" + import vibevoice.modular.modular_vibevoice_tokenizer as tok + orig = tok.VibeVoiceTokenizerEncoderOutput.sample + if restore: + return orig + def mean_sample(self, dist_type="fix"): + return self.mean, self.std + tok.VibeVoiceTokenizerEncoderOutput.sample = mean_sample + return orig + + +def cmd_dump(args: argparse.Namespace) -> None: + import torch + import librosa + sys.path.insert(0, _vibevoice_src()) + import vibevoice.modular.modular_vibevoice_tokenizer as tok + + device = args.device + # validate.py invokes the dumper with --out ...//ref and compares that + # dir against ...//cpp; write flat into whatever --out we're given. + out_dir = Path(args.out) + src = {"framework": "author_repo_vibevoice", "model": args.model} + + processor, model = load_reference(args.model, device) + print(f"loaded {args.model} on {device}") + + wav, sr = librosa.load(args.audio, sr=24000, mono=True) + print(f"audio: {len(wav)} samples @ {sr} ({len(wav)/sr:.1f}s)") + inputs = processor(audio=[wav.astype(np.float32)], sampling_rate=24000, + return_tensors="pt", add_generation_prompt=True) + inputs = {k: (v.to(device) if hasattr(v, "to") else v) for k, v in inputs.items()} + + speech = inputs["speech_tensors"].to(device) # [B, samples]; dtype matched per-module below + mask = inputs["acoustic_input_mask"].to(device) + input_ids = inputs["input_ids"].to(device) + + orig_sample = _patch_mean() # deterministic mean path for all contract tensors + try: + with torch.no_grad(): + write_tensor("enc.input_waveform", _np(speech[0]), "encoder", src, out_dir=out_dir) + + # --- encoder: acoustic + semantic VAE means -> connectors -> sum --- + at, st = model.model.acoustic_tokenizer, model.model.semantic_tokenizer + ac, sc = model.model.acoustic_connector, model.model.semantic_connector + a_mean = at.encode(_as(at, speech.unsqueeze(1))).mean # [B, T, 64] + a_feat = ac(_as(ac, a_mean)) # [B, T, 3584] + s_mean = st.encode(_as(st, speech.unsqueeze(1))).mean # [B, T, 128] + s_feat = sc(_as(sc, s_mean)) # [B, T, 3584] + combined = a_feat + s_feat # [B, T, 3584] + for name, t in [("enc.acoustic.mean", a_mean), ("enc.acoustic.feat", a_feat), + ("enc.semantic.mean", s_mean), ("enc.semantic.feat", s_feat), + ("enc.combined", combined)]: + write_tensor(name, _np(t[0]), "encoder", src, out_dir=out_dir) + + # --- decoder: embed, scatter speech, run Qwen2 with hidden states --- + token_emb = model.get_input_embeddings()(input_ids) # [B, L, 3584] + write_tensor("dec.token_emb", _np(token_emb[0]), "decoder", src, out_dir=out_dir) + + captured = {} + def pre_hook(mod, a, kw): + captured["inputs_embeds"] = kw.get("inputs_embeds") + h = model.model.language_model.register_forward_pre_hook(pre_hook, with_kwargs=True) + out = model(**inputs, output_hidden_states=True, use_cache=False, return_dict=True) + h.remove() + + if captured.get("inputs_embeds") is not None: + write_tensor("dec.inputs_embeds", _np(captured["inputs_embeds"][0]), + "decoder", src, out_dir=out_dir) + hs = out.hidden_states # (emb, layer1, ..., layerN); index i+1 == output of layer i + for i in DUMP_LAYERS: + write_tensor(f"dec.block.{i}.out", _np(hs[i + 1][0]), "decoder", src, out_dir=out_dir) + final_norm = model.model.language_model.norm(hs[-1]) + write_tensor("dec.final_norm", _np(final_norm[0]), "decoder", src, out_dir=out_dir) + write_tensor("dec.logits_lastpos", _np(out.logits[0, -1, :]), "decoder", src, out_dir=out_dir) + + # --- sampled envelope: per-tensor std/range over N noisy acoustic passes --- + tok.VibeVoiceTokenizerEncoderOutput.sample = orig_sample + env = _sampled_envelope(model, inputs, speech, mask, input_ids, device) + (out_dir / "envelope.json").write_text(json.dumps(env, indent=2) + "\n") + print(f" wrote {out_dir/'envelope.json'}") + finally: + tok.VibeVoiceTokenizerEncoderOutput.sample = orig_sample + + # --- transcript (clean stop at JSON end; greedy) --- + transcript = _transcribe(processor, model, inputs, device) + write_transcript(out_dir, transcript["text"], source=src, tokens=transcript["tokens"]) + (out_dir / "transcript.parsed.json").write_text( + json.dumps(transcript["parsed"], indent=2) + "\n") + print(f" transcript: {transcript['parsed']}") + + +def _sampled_envelope(model, inputs, speech, mask, input_ids, device): + import torch + a_samps, logit_samps = [], [] + with torch.no_grad(): + for n in range(ENVELOPE_N): + torch.manual_seed(1000 + n) + if device != "cpu": + torch.cuda.manual_seed_all(1000 + n) + at = model.model.acoustic_tokenizer + ao = at.encode(_as(at, speech.unsqueeze(1))) + a_tok = ao.sample(dist_type=at.std_dist_type)[0] + a_samps.append(_np(a_tok[0])) + out = model(**inputs, output_hidden_states=False, use_cache=False, return_dict=True) + logit_samps.append(_np(out.logits[0, -1, :])) + a = np.stack(a_samps); lg = np.stack(logit_samps) + + def stats(arr_std, arr_mean_axis): + s = arr_std.std(axis=0) + return {"std_mean": float(s.mean()), "std_p99": float(np.quantile(s, 0.99)), + "std_max": float(s.max())} + # how much the sampled acoustic latent deviates run-to-run, and the logit spread + argmax_stable = len(set(int(x.argmax()) for x in logit_samps)) == 1 + return { + "n_passes": ENVELOPE_N, + "acoustic_latent_sample_std": stats(a, 0), + "logits_lastpos_sample_std": stats(lg, 0), + "logits_lastpos_argmax_stable_across_samples": argmax_stable, + "note": "Acoustic path is sampled (gaussian, fix_std=0.5). Contract tensors use the mean; " + "this band shows the run-to-run spread of the published stochastic path.", + } + + +def _transcribe(processor, model, inputs, device): + import torch + orig = _patch_mean() # transcript on the deterministic (mean) path too + try: + eos = processor.tokenizer.eos_token_id + with torch.no_grad(): + torch.manual_seed(0) + out = model.generate(**inputs, max_new_tokens=448, do_sample=False, num_beams=1, + eos_token_id=eos, pad_token_id=eos, + stop_strings=["}]"], tokenizer=processor.tokenizer) + finally: + import vibevoice.modular.modular_vibevoice_tokenizer as tok + tok.VibeVoiceTokenizerEncoderOutput.sample = orig + gen_ids = out[0].tolist() + text = processor.tokenizer.decode(out[0], skip_special_tokens=True) + # pull the JSON array the model emits after "assistant" + parsed = None + import re + m = re.search(r"\[\s*\{.*\}\s*\]", text, re.DOTALL) + if m: + try: + parsed = json.loads(m.group(0)) + except Exception: + parsed = None + return {"text": text, "tokens": gen_ids, "parsed": parsed} + + +def main() -> None: + ap = argparse.ArgumentParser(description=__doc__, + formatter_class=argparse.RawDescriptionHelpFormatter) + sub = ap.add_subparsers(dest="cmd", required=True) + d = sub.add_parser("dump", help="dump reference tensors + transcript for one audio case") + d.add_argument("--model", default=MODEL_DEFAULT) + d.add_argument("--audio", required=True) + d.add_argument("--out", required=True) + d.add_argument("--device", default="cuda") + d.set_defaults(func=cmd_dump) + args = ap.parse_args() + args.func(args) + + +if __name__ == "__main__": + main() diff --git a/scripts/envs/vibevoice/pyproject.toml b/scripts/envs/vibevoice/pyproject.toml new file mode 100644 index 00000000..896a7a59 --- /dev/null +++ b/scripts/envs/vibevoice/pyproject.toml @@ -0,0 +1,22 @@ +[project] +name = "transcribe-vibevoice-env" +version = "0.1.0" +description = "Python env for VibeVoice-ASR reference dumps and conversion. The vibevoice package itself is vendored (source-only) under models/_vendor/VibeVoice and put on sys.path by the dumper; only its real runtime deps are pinned here (the upstream pyproject also drags gradio/aiortc/av/fastapi for the demo server, which we don't need)." +requires-python = ">=3.11,<3.13" +dependencies = [ + "torch>=2.2", + "transformers==4.51.3", + "accelerate>=1.6.0", + "diffusers>=0.30", + "gguf>=0.10", + "huggingface-hub>=0.30", + "safetensors>=0.4", + "numpy>=1.26", + "scipy>=1.11", + "librosa>=0.10", + "soundfile>=0.12", + "ml-collections>=0.1.1", + "absl-py>=2.0", + "einops>=0.7", + "tqdm>=4.66", +] diff --git a/scripts/envs/vibevoice/uv.lock b/scripts/envs/vibevoice/uv.lock new file mode 100644 index 00000000..3bfc255a --- /dev/null +++ b/scripts/envs/vibevoice/uv.lock @@ -0,0 +1,1288 @@ +version = 1 +revision = 3 +requires-python = ">=3.11, <3.13" +resolution-markers = [ + "python_full_version >= '3.12'", + "python_full_version < '3.12'", +] + +[[package]] +name = "absl-py" +version = "2.4.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/64/c7/8de93764ad66968d19329a7e0c147a2bb3c7054c554d4a119111b8f9440f/absl_py-2.4.0.tar.gz", hash = "sha256:8c6af82722b35cf71e0f4d1d47dcaebfff286e27110a99fc359349b247dfb5d4", size = 116543, upload-time = "2026-01-28T10:17:05.322Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/18/a6/907a406bb7d359e6a63f99c313846d9eec4f7e6f7437809e03aa00fa3074/absl_py-2.4.0-py3-none-any.whl", hash = "sha256:88476fd881ca8aab94ffa78b7b6c632a782ab3ba1cd19c9bd423abc4fb4cd28d", size = 135750, upload-time = "2026-01-28T10:17:04.19Z" }, +] + +[[package]] +name = "accelerate" +version = "1.14.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "huggingface-hub" }, + { name = "numpy" }, + { name = "packaging" }, + { name = "psutil" }, + { name = "pyyaml" }, + { name = "safetensors" }, + { name = "torch" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/8d/75/94cd5d389649578aca399e5aa822637eec18319a1dadc400ffe2f9a7493f/accelerate-1.14.0.tar.gz", hash = "sha256:41b9c4377a54e0b460a959b0defa1b736e4ca0a2373252d9a539964c2afe3c8d", size = 412167, upload-time = "2026-06-11T13:45:52.326Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a8/db/253133d7e7cb40d3af384bb2f5c0b4a2b7fdcffbc95c688cc67a20a3c103/accelerate-1.14.0-py3-none-any.whl", hash = "sha256:e94390c2863b873be18f623f9df48a0d8fe5eff13ea7f1a00092b0a7904888c6", size = 389246, upload-time = "2026-06-11T13:45:50.477Z" }, +] + +[[package]] +name = "anyio" +version = "4.14.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "idna" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/3b/72/5562aabb8dd7181e8e860622a38bea08d17842b99ecd4c91f84ac95251b0/anyio-4.14.1.tar.gz", hash = "sha256:8d648a3544c1a700e3ff78615cd679e4c5c3f149904287e73687b2596963629e", size = 254831, upload-time = "2026-06-24T20:56:06.017Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl", hash = "sha256:4e5533c5b8ff0a24f5d7a176cbe6877129cd183893f66b537f8f227d10527d72", size = 124875, upload-time = "2026-06-24T20:56:04.413Z" }, +] + +[[package]] +name = "audioread" +version = "3.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a1/4a/874ecf9b472f998130c2b5e145dcdb9f6131e84786111489103b66772143/audioread-3.1.0.tar.gz", hash = "sha256:1c4ab2f2972764c896a8ac61ac53e261c8d29f0c6ccd652f84e18f08a4cab190", size = 20082, upload-time = "2025-10-26T19:44:13.484Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7e/16/fbe8e1e185a45042f7cd3a282def5bb8d95bb69ab9e9ef6a5368aa17e426/audioread-3.1.0-py3-none-any.whl", hash = "sha256:b30d1df6c5d3de5dcef0fb0e256f6ea17bdcf5f979408df0297d8a408e2971b4", size = 23143, upload-time = "2025-10-26T19:44:12.016Z" }, +] + +[[package]] +name = "certifi" +version = "2026.6.17" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c9/c7/424b75da314c1045981bd9777432fad05a9e0c69daa4ed7e308bbaffe405/certifi-2026.6.17.tar.gz", hash = "sha256:024c88eeec92ca068db80f02b8b07c9cef7b9fe261d1d535abfd5abd6f6af432", size = 134594, upload-time = "2026-06-17T10:31:07.894Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl", hash = "sha256:2227dcbaafe0d2f59279d1762ddddc37783ed4354594f194ffc31d20f41fc3db", size = 133289, upload-time = "2026-06-17T10:31:06.348Z" }, +] + +[[package]] +name = "cffi" +version = "2.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pycparser", marker = "implementation_name != 'PyPy'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/eb/56/b1ba7935a17738ae8453301356628e8147c79dbb825bcbc73dc7401f9846/cffi-2.0.0.tar.gz", hash = "sha256:44d1b5909021139fe36001ae048dbdde8214afa20200eda0f64c068cac5d5529", size = 523588, upload-time = "2025-09-08T23:24:04.541Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/12/4a/3dfd5f7850cbf0d06dc84ba9aa00db766b52ca38d8b86e3a38314d52498c/cffi-2.0.0-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:b4c854ef3adc177950a8dfc81a86f5115d2abd545751a304c5bcf2c2c7283cfe", size = 184344, upload-time = "2025-09-08T23:22:26.456Z" }, + { url = "https://files.pythonhosted.org/packages/4f/8b/f0e4c441227ba756aafbe78f117485b25bb26b1c059d01f137fa6d14896b/cffi-2.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2de9a304e27f7596cd03d16f1b7c72219bd944e99cc52b84d0145aefb07cbd3c", size = 180560, upload-time = "2025-09-08T23:22:28.197Z" }, + { url = "https://files.pythonhosted.org/packages/b1/b7/1200d354378ef52ec227395d95c2576330fd22a869f7a70e88e1447eb234/cffi-2.0.0-cp311-cp311-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:baf5215e0ab74c16e2dd324e8ec067ef59e41125d3eade2b863d294fd5035c92", size = 209613, upload-time = "2025-09-08T23:22:29.475Z" }, + { url = "https://files.pythonhosted.org/packages/b8/56/6033f5e86e8cc9bb629f0077ba71679508bdf54a9a5e112a3c0b91870332/cffi-2.0.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:730cacb21e1bdff3ce90babf007d0a0917cc3e6492f336c2f0134101e0944f93", size = 216476, upload-time = "2025-09-08T23:22:31.063Z" }, + { url = "https://files.pythonhosted.org/packages/dc/7f/55fecd70f7ece178db2f26128ec41430d8720f2d12ca97bf8f0a628207d5/cffi-2.0.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:6824f87845e3396029f3820c206e459ccc91760e8fa24422f8b0c3d1731cbec5", size = 203374, upload-time = "2025-09-08T23:22:32.507Z" }, + { url = "https://files.pythonhosted.org/packages/84/ef/a7b77c8bdc0f77adc3b46888f1ad54be8f3b7821697a7b89126e829e676a/cffi-2.0.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:9de40a7b0323d889cf8d23d1ef214f565ab154443c42737dfe52ff82cf857664", size = 202597, upload-time = "2025-09-08T23:22:34.132Z" }, + { url = "https://files.pythonhosted.org/packages/d7/91/500d892b2bf36529a75b77958edfcd5ad8e2ce4064ce2ecfeab2125d72d1/cffi-2.0.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8941aaadaf67246224cee8c3803777eed332a19d909b47e29c9842ef1e79ac26", size = 215574, upload-time = "2025-09-08T23:22:35.443Z" }, + { url = "https://files.pythonhosted.org/packages/44/64/58f6255b62b101093d5df22dcb752596066c7e89dd725e0afaed242a61be/cffi-2.0.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:a05d0c237b3349096d3981b727493e22147f934b20f6f125a3eba8f994bec4a9", size = 218971, upload-time = "2025-09-08T23:22:36.805Z" }, + { url = "https://files.pythonhosted.org/packages/ab/49/fa72cebe2fd8a55fbe14956f9970fe8eb1ac59e5df042f603ef7c8ba0adc/cffi-2.0.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:94698a9c5f91f9d138526b48fe26a199609544591f859c870d477351dc7b2414", size = 211972, upload-time = "2025-09-08T23:22:38.436Z" }, + { url = "https://files.pythonhosted.org/packages/0b/28/dd0967a76aab36731b6ebfe64dec4e981aff7e0608f60c2d46b46982607d/cffi-2.0.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:5fed36fccc0612a53f1d4d9a816b50a36702c28a2aa880cb8a122b3466638743", size = 217078, upload-time = "2025-09-08T23:22:39.776Z" }, + { url = "https://files.pythonhosted.org/packages/2b/c0/015b25184413d7ab0a410775fdb4a50fca20f5589b5dab1dbbfa3baad8ce/cffi-2.0.0-cp311-cp311-win32.whl", hash = "sha256:c649e3a33450ec82378822b3dad03cc228b8f5963c0c12fc3b1e0ab940f768a5", size = 172076, upload-time = "2025-09-08T23:22:40.95Z" }, + { url = "https://files.pythonhosted.org/packages/ae/8f/dc5531155e7070361eb1b7e4c1a9d896d0cb21c49f807a6c03fd63fc877e/cffi-2.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:66f011380d0e49ed280c789fbd08ff0d40968ee7b665575489afa95c98196ab5", size = 182820, upload-time = "2025-09-08T23:22:42.463Z" }, + { url = "https://files.pythonhosted.org/packages/95/5c/1b493356429f9aecfd56bc171285a4c4ac8697f76e9bbbbb105e537853a1/cffi-2.0.0-cp311-cp311-win_arm64.whl", hash = "sha256:c6638687455baf640e37344fe26d37c404db8b80d037c3d29f58fe8d1c3b194d", size = 177635, upload-time = "2025-09-08T23:22:43.623Z" }, + { url = "https://files.pythonhosted.org/packages/ea/47/4f61023ea636104d4f16ab488e268b93008c3d0bb76893b1b31db1f96802/cffi-2.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6d02d6655b0e54f54c4ef0b94eb6be0607b70853c45ce98bd278dc7de718be5d", size = 185271, upload-time = "2025-09-08T23:22:44.795Z" }, + { url = "https://files.pythonhosted.org/packages/df/a2/781b623f57358e360d62cdd7a8c681f074a71d445418a776eef0aadb4ab4/cffi-2.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8eca2a813c1cb7ad4fb74d368c2ffbbb4789d377ee5bb8df98373c2cc0dee76c", size = 181048, upload-time = "2025-09-08T23:22:45.938Z" }, + { url = "https://files.pythonhosted.org/packages/ff/df/a4f0fbd47331ceeba3d37c2e51e9dfc9722498becbeec2bd8bc856c9538a/cffi-2.0.0-cp312-cp312-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:21d1152871b019407d8ac3985f6775c079416c282e431a4da6afe7aefd2bccbe", size = 212529, upload-time = "2025-09-08T23:22:47.349Z" }, + { url = "https://files.pythonhosted.org/packages/d5/72/12b5f8d3865bf0f87cf1404d8c374e7487dcf097a1c91c436e72e6badd83/cffi-2.0.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:b21e08af67b8a103c71a250401c78d5e0893beff75e28c53c98f4de42f774062", size = 220097, upload-time = "2025-09-08T23:22:48.677Z" }, + { url = "https://files.pythonhosted.org/packages/c2/95/7a135d52a50dfa7c882ab0ac17e8dc11cec9d55d2c18dda414c051c5e69e/cffi-2.0.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:1e3a615586f05fc4065a8b22b8152f0c1b00cdbc60596d187c2a74f9e3036e4e", size = 207983, upload-time = "2025-09-08T23:22:50.06Z" }, + { url = "https://files.pythonhosted.org/packages/3a/c8/15cb9ada8895957ea171c62dc78ff3e99159ee7adb13c0123c001a2546c1/cffi-2.0.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:81afed14892743bbe14dacb9e36d9e0e504cd204e0b165062c488942b9718037", size = 206519, upload-time = "2025-09-08T23:22:51.364Z" }, + { url = "https://files.pythonhosted.org/packages/78/2d/7fa73dfa841b5ac06c7b8855cfc18622132e365f5b81d02230333ff26e9e/cffi-2.0.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3e17ed538242334bf70832644a32a7aae3d83b57567f9fd60a26257e992b79ba", size = 219572, upload-time = "2025-09-08T23:22:52.902Z" }, + { url = "https://files.pythonhosted.org/packages/07/e0/267e57e387b4ca276b90f0434ff88b2c2241ad72b16d31836adddfd6031b/cffi-2.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3925dd22fa2b7699ed2617149842d2e6adde22b262fcbfada50e3d195e4b3a94", size = 222963, upload-time = "2025-09-08T23:22:54.518Z" }, + { url = "https://files.pythonhosted.org/packages/b6/75/1f2747525e06f53efbd878f4d03bac5b859cbc11c633d0fb81432d98a795/cffi-2.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2c8f814d84194c9ea681642fd164267891702542f028a15fc97d4674b6206187", size = 221361, upload-time = "2025-09-08T23:22:55.867Z" }, + { url = "https://files.pythonhosted.org/packages/7b/2b/2b6435f76bfeb6bbf055596976da087377ede68df465419d192acf00c437/cffi-2.0.0-cp312-cp312-win32.whl", hash = "sha256:da902562c3e9c550df360bfa53c035b2f241fed6d9aef119048073680ace4a18", size = 172932, upload-time = "2025-09-08T23:22:57.188Z" }, + { url = "https://files.pythonhosted.org/packages/f8/ed/13bd4418627013bec4ed6e54283b1959cf6db888048c7cf4b4c3b5b36002/cffi-2.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:da68248800ad6320861f129cd9c1bf96ca849a2771a59e0344e88681905916f5", size = 183557, upload-time = "2025-09-08T23:22:58.351Z" }, + { url = "https://files.pythonhosted.org/packages/95/31/9f7f93ad2f8eff1dbc1c3656d7ca5bfd8fb52c9d786b4dcf19b2d02217fa/cffi-2.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:4671d9dd5ec934cb9a73e7ee9676f9362aba54f7f34910956b84d727b0d73fb6", size = 177762, upload-time = "2025-09-08T23:22:59.668Z" }, +] + +[[package]] +name = "charset-normalizer" +version = "3.4.7" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e7/a1/67fe25fac3c7642725500a3f6cfe5821ad557c3abb11c9d20d12c7008d3e/charset_normalizer-3.4.7.tar.gz", hash = "sha256:ae89db9e5f98a11a4bf50407d4363e7b09b31e55bc117b4f7d80aab97ba009e5", size = 144271, upload-time = "2026-04-02T09:28:39.342Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c2/d7/b5b7020a0565c2e9fa8c09f4b5fa6232feb326b8c20081ccded47ea368fd/charset_normalizer-3.4.7-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:7641bb8895e77f921102f72833904dcd9901df5d6d72a2ab8f31d04b7e51e4e7", size = 309705, upload-time = "2026-04-02T09:26:02.191Z" }, + { url = "https://files.pythonhosted.org/packages/5a/53/58c29116c340e5456724ecd2fff4196d236b98f3da97b404bc5e51ac3493/charset_normalizer-3.4.7-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:202389074300232baeb53ae2569a60901f7efadd4245cf3a3bf0617d60b439d7", size = 206419, upload-time = "2026-04-02T09:26:03.583Z" }, + { url = "https://files.pythonhosted.org/packages/b2/02/e8146dc6591a37a00e5144c63f29fb7c97a734ea8a111190783c0e60ab63/charset_normalizer-3.4.7-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:30b8d1d8c52a48c2c5690e152c169b673487a2a58de1ec7393196753063fcd5e", size = 227901, upload-time = "2026-04-02T09:26:04.738Z" }, + { url = "https://files.pythonhosted.org/packages/fb/73/77486c4cd58f1267bf17db420e930c9afa1b3be3fe8c8b8ebbebc9624359/charset_normalizer-3.4.7-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:532bc9bf33a68613fd7d65e4b1c71a6a38d7d42604ecf239c77392e9b4e8998c", size = 222742, upload-time = "2026-04-02T09:26:06.36Z" }, + { url = "https://files.pythonhosted.org/packages/a1/fa/f74eb381a7d94ded44739e9d94de18dc5edc9c17fb8c11f0a6890696c0a9/charset_normalizer-3.4.7-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2fe249cb4651fd12605b7288b24751d8bfd46d35f12a20b1ba33dea122e690df", size = 214061, upload-time = "2026-04-02T09:26:08.347Z" }, + { url = "https://files.pythonhosted.org/packages/dc/92/42bd3cefcf7687253fb86694b45f37b733c97f59af3724f356fa92b8c344/charset_normalizer-3.4.7-cp311-cp311-manylinux_2_31_armv7l.whl", hash = "sha256:65bcd23054beab4d166035cabbc868a09c1a49d1efe458fe8e4361215df40265", size = 199239, upload-time = "2026-04-02T09:26:09.823Z" }, + { url = "https://files.pythonhosted.org/packages/4c/3d/069e7184e2aa3b3cddc700e3dd267413dc259854adc3380421c805c6a17d/charset_normalizer-3.4.7-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:08e721811161356f97b4059a9ba7bafb23ea5ee2255402c42881c214e173c6b4", size = 210173, upload-time = "2026-04-02T09:26:10.953Z" }, + { url = "https://files.pythonhosted.org/packages/62/51/9d56feb5f2e7074c46f93e0ebdbe61f0848ee246e2f0d89f8e20b89ebb8f/charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:e060d01aec0a910bdccb8be71faf34e7799ce36950f8294c8bf612cba65a2c9e", size = 209841, upload-time = "2026-04-02T09:26:12.142Z" }, + { url = "https://files.pythonhosted.org/packages/d2/59/893d8f99cc4c837dda1fe2f1139079703deb9f321aabcb032355de13b6c7/charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:38c0109396c4cfc574d502df99742a45c72c08eff0a36158b6f04000043dbf38", size = 200304, upload-time = "2026-04-02T09:26:13.711Z" }, + { url = "https://files.pythonhosted.org/packages/7d/1d/ee6f3be3464247578d1ed5c46de545ccc3d3ff933695395c402c21fa6b77/charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:1c2a768fdd44ee4a9339a9b0b130049139b8ce3c01d2ce09f67f5a68048d477c", size = 229455, upload-time = "2026-04-02T09:26:14.941Z" }, + { url = "https://files.pythonhosted.org/packages/54/bb/8fb0a946296ea96a488928bdce8ef99023998c48e4713af533e9bb98ef07/charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:1a87ca9d5df6fe460483d9a5bbf2b18f620cbed41b432e2bddb686228282d10b", size = 210036, upload-time = "2026-04-02T09:26:16.478Z" }, + { url = "https://files.pythonhosted.org/packages/9a/bc/015b2387f913749f82afd4fcba07846d05b6d784dd16123cb66860e0237d/charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:d635aab80466bc95771bb78d5370e74d36d1fe31467b6b29b8b57b2a3cd7d22c", size = 224739, upload-time = "2026-04-02T09:26:17.751Z" }, + { url = "https://files.pythonhosted.org/packages/17/ab/63133691f56baae417493cba6b7c641571a2130eb7bceba6773367ab9ec5/charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ae196f021b5e7c78e918242d217db021ed2a6ace2bc6ae94c0fc596221c7f58d", size = 216277, upload-time = "2026-04-02T09:26:18.981Z" }, + { url = "https://files.pythonhosted.org/packages/06/6d/3be70e827977f20db77c12a97e6a9f973631a45b8d186c084527e53e77a4/charset_normalizer-3.4.7-cp311-cp311-win32.whl", hash = "sha256:adb2597b428735679446b46c8badf467b4ca5f5056aae4d51a19f9570301b1ad", size = 147819, upload-time = "2026-04-02T09:26:20.295Z" }, + { url = "https://files.pythonhosted.org/packages/20/d9/5f67790f06b735d7c7637171bbfd89882ad67201891b7275e51116ed8207/charset_normalizer-3.4.7-cp311-cp311-win_amd64.whl", hash = "sha256:8e385e4267ab76874ae30db04c627faaaf0b509e1ccc11a95b3fc3e83f855c00", size = 159281, upload-time = "2026-04-02T09:26:21.74Z" }, + { url = "https://files.pythonhosted.org/packages/ca/83/6413f36c5a34afead88ce6f66684d943d91f233d76dd083798f9602b75ae/charset_normalizer-3.4.7-cp311-cp311-win_arm64.whl", hash = "sha256:d4a48e5b3c2a489fae013b7589308a40146ee081f6f509e047e0e096084ceca1", size = 147843, upload-time = "2026-04-02T09:26:22.901Z" }, + { url = "https://files.pythonhosted.org/packages/0c/eb/4fc8d0a7110eb5fc9cc161723a34a8a6c200ce3b4fbf681bc86feee22308/charset_normalizer-3.4.7-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:eca9705049ad3c7345d574e3510665cb2cf844c2f2dcfe675332677f081cbd46", size = 311328, upload-time = "2026-04-02T09:26:24.331Z" }, + { url = "https://files.pythonhosted.org/packages/f8/e3/0fadc706008ac9d7b9b5be6dc767c05f9d3e5df51744ce4cc9605de7b9f4/charset_normalizer-3.4.7-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6178f72c5508bfc5fd446a5905e698c6212932f25bcdd4b47a757a50605a90e2", size = 208061, upload-time = "2026-04-02T09:26:25.568Z" }, + { url = "https://files.pythonhosted.org/packages/42/f0/3dd1045c47f4a4604df85ec18ad093912ae1344ac706993aff91d38773a2/charset_normalizer-3.4.7-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e1421b502d83040e6d7fb2fb18dff63957f720da3d77b2fbd3187ceb63755d7b", size = 229031, upload-time = "2026-04-02T09:26:26.865Z" }, + { url = "https://files.pythonhosted.org/packages/dc/67/675a46eb016118a2fbde5a277a5d15f4f69d5f3f5f338e5ee2f8948fcf43/charset_normalizer-3.4.7-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:edac0f1ab77644605be2cbba52e6b7f630731fc42b34cb0f634be1a6eface56a", size = 225239, upload-time = "2026-04-02T09:26:28.044Z" }, + { url = "https://files.pythonhosted.org/packages/4b/f8/d0118a2f5f23b02cd166fa385c60f9b0d4f9194f574e2b31cef350ad7223/charset_normalizer-3.4.7-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5649fd1c7bade02f320a462fdefd0b4bd3ce036065836d4f42e0de958038e116", size = 216589, upload-time = "2026-04-02T09:26:29.239Z" }, + { url = "https://files.pythonhosted.org/packages/b1/f1/6d2b0b261b6c4ceef0fcb0d17a01cc5bc53586c2d4796fa04b5c540bc13d/charset_normalizer-3.4.7-cp312-cp312-manylinux_2_31_armv7l.whl", hash = "sha256:203104ed3e428044fd943bc4bf45fa73c0730391f9621e37fe39ecf477b128cb", size = 202733, upload-time = "2026-04-02T09:26:30.5Z" }, + { url = "https://files.pythonhosted.org/packages/6f/c0/7b1f943f7e87cc3db9626ba17807d042c38645f0a1d4415c7a14afb5591f/charset_normalizer-3.4.7-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:298930cec56029e05497a76988377cbd7457ba864beeea92ad7e844fe74cd1f1", size = 212652, upload-time = "2026-04-02T09:26:31.709Z" }, + { url = "https://files.pythonhosted.org/packages/38/dd/5a9ab159fe45c6e72079398f277b7d2b523e7f716acc489726115a910097/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:708838739abf24b2ceb208d0e22403dd018faeef86ddac04319a62ae884c4f15", size = 211229, upload-time = "2026-04-02T09:26:33.282Z" }, + { url = "https://files.pythonhosted.org/packages/d5/ff/531a1cad5ca855d1c1a8b69cb71abfd6d85c0291580146fda7c82857caa1/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:0f7eb884681e3938906ed0434f20c63046eacd0111c4ba96f27b76084cd679f5", size = 203552, upload-time = "2026-04-02T09:26:34.845Z" }, + { url = "https://files.pythonhosted.org/packages/c1/4c/a5fb52d528a8ca41f7598cb619409ece30a169fbdf9cdce592e53b46c3a6/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:4dc1e73c36828f982bfe79fadf5919923f8a6f4df2860804db9a98c48824ce8d", size = 230806, upload-time = "2026-04-02T09:26:36.152Z" }, + { url = "https://files.pythonhosted.org/packages/59/7a/071feed8124111a32b316b33ae4de83d36923039ef8cf48120266844285b/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:aed52fea0513bac0ccde438c188c8a471c4e0f457c2dd20cdbf6ea7a450046c7", size = 212316, upload-time = "2026-04-02T09:26:37.672Z" }, + { url = "https://files.pythonhosted.org/packages/fd/35/f7dba3994312d7ba508e041eaac39a36b120f32d4c8662b8814dab876431/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:fea24543955a6a729c45a73fe90e08c743f0b3334bbf3201e6c4bc1b0c7fa464", size = 227274, upload-time = "2026-04-02T09:26:38.93Z" }, + { url = "https://files.pythonhosted.org/packages/8a/2d/a572df5c9204ab7688ec1edc895a73ebded3b023bb07364710b05dd1c9be/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:bb6d88045545b26da47aa879dd4a89a71d1dce0f0e549b1abcb31dfe4a8eac49", size = 218468, upload-time = "2026-04-02T09:26:40.17Z" }, + { url = "https://files.pythonhosted.org/packages/86/eb/890922a8b03a568ca2f336c36585a4713c55d4d67bf0f0c78924be6315ca/charset_normalizer-3.4.7-cp312-cp312-win32.whl", hash = "sha256:2257141f39fe65a3fdf38aeccae4b953e5f3b3324f4ff0daf9f15b8518666a2c", size = 148460, upload-time = "2026-04-02T09:26:41.416Z" }, + { url = "https://files.pythonhosted.org/packages/35/d9/0e7dffa06c5ab081f75b1b786f0aefc88365825dfcd0ac544bdb7b2b6853/charset_normalizer-3.4.7-cp312-cp312-win_amd64.whl", hash = "sha256:5ed6ab538499c8644b8a3e18debabcd7ce684f3fa91cf867521a7a0279cab2d6", size = 159330, upload-time = "2026-04-02T09:26:42.554Z" }, + { url = "https://files.pythonhosted.org/packages/9e/5d/481bcc2a7c88ea6b0878c299547843b2521ccbc40980cb406267088bc701/charset_normalizer-3.4.7-cp312-cp312-win_arm64.whl", hash = "sha256:56be790f86bfb2c98fb742ce566dfb4816e5a83384616ab59c49e0604d49c51d", size = 147828, upload-time = "2026-04-02T09:26:44.075Z" }, + { url = "https://files.pythonhosted.org/packages/db/8f/61959034484a4a7c527811f4721e75d02d653a35afb0b6054474d8185d4c/charset_normalizer-3.4.7-py3-none-any.whl", hash = "sha256:3dce51d0f5e7951f8bb4900c257dad282f49190fdbebecd4ba99bcc41fef404d", size = 61958, upload-time = "2026-04-02T09:28:37.794Z" }, +] + +[[package]] +name = "colorama" +version = "0.4.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, +] + +[[package]] +name = "cuda-bindings" +version = "13.3.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cuda-pathfinder" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/51/6b/457ca12dad3ee9bfcc9a545cfd6b64b359ba49de40f776f6e028e678f262/cuda_bindings-13.3.1-cp311-cp311-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c5879712accf6e14bb01aa5e67440eb84998b8d104b509cc7a6dc0b8f656a474", size = 6053539, upload-time = "2026-05-29T23:11:43.19Z" }, + { url = "https://files.pythonhosted.org/packages/95/7a/c5e3c34a409b148f5c0f5a4ea374158f95d488862c1dffedf9aa5c639df9/cuda_bindings-13.3.1-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:04436a9364059c84b8f9636f359eccda1cf814341f5b670c71d80d2f79dbc708", size = 6674166, upload-time = "2026-05-29T23:11:45.478Z" }, + { url = "https://files.pythonhosted.org/packages/ce/67/5e7dba1ba576dd73da5dee894ca076ca5e959450dfff66d6d510a255d1f7/cuda_bindings-13.3.1-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c7855c4868aabc0cfae28abbe83d56734bdfbd08f08fc234ac1912a12858bf49", size = 6025351, upload-time = "2026-05-29T23:11:49.685Z" }, + { url = "https://files.pythonhosted.org/packages/39/2a/6d2e9047d1fb243dbaa364b01e0297534b9ed7fd27dba1c9f361519cf69b/cuda_bindings-13.3.1-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e32d08f71ebcdf00f0f41eab2eb37e8da94c8ed411cc9f7f7a019ce6b34abe3a", size = 6657965, upload-time = "2026-05-29T23:11:52.227Z" }, +] + +[[package]] +name = "cuda-pathfinder" +version = "1.5.5" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/11/c8/26f2e4aae92f11522a96043892ba39a90eac610d5242523aa863212bc1c7/cuda_pathfinder-1.5.5-py3-none-any.whl", hash = "sha256:0228c023f95d1480f143ef5c8922d27a2ab052087a942e81dc289c9eb8f91689", size = 51671, upload-time = "2026-05-27T01:21:25.413Z" }, +] + +[[package]] +name = "cuda-toolkit" +version = "13.0.2" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/57/b2/453099f5f3b698d7d0eab38916aac44c7f76229f451709e2eb9db6615dcd/cuda_toolkit-13.0.2-py2.py3-none-any.whl", hash = "sha256:b198824cf2f54003f50d64ada3a0f184b42ca0846c1c94192fa269ecd97a66eb", size = 2364, upload-time = "2025-12-19T23:24:07.328Z" }, +] + +[package.optional-dependencies] +cudart = [ + { name = "nvidia-cuda-runtime", marker = "sys_platform == 'linux' or sys_platform == 'win32'" }, +] +cufft = [ + { name = "nvidia-cufft", marker = "sys_platform == 'linux' or sys_platform == 'win32'" }, +] +cufile = [ + { name = "nvidia-cufile", marker = "sys_platform == 'linux'" }, +] +cupti = [ + { name = "nvidia-cuda-cupti", marker = "sys_platform == 'linux' or sys_platform == 'win32'" }, +] +curand = [ + { name = "nvidia-curand", marker = "sys_platform == 'linux' or sys_platform == 'win32'" }, +] +cusolver = [ + { name = "nvidia-cusolver", marker = "sys_platform == 'linux' or sys_platform == 'win32'" }, +] +cusparse = [ + { name = "nvidia-cusparse", marker = "sys_platform == 'linux' or sys_platform == 'win32'" }, +] +nvjitlink = [ + { name = "nvidia-nvjitlink", marker = "sys_platform == 'linux' or sys_platform == 'win32'" }, +] +nvrtc = [ + { name = "nvidia-cuda-nvrtc", marker = "sys_platform == 'linux' or sys_platform == 'win32'" }, +] +nvtx = [ + { name = "nvidia-nvtx", marker = "sys_platform == 'linux' or sys_platform == 'win32'" }, +] + +[[package]] +name = "decorator" +version = "5.3.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/60/8b/32f9823da46cde7df2087faa08cd98d01b908f8dcab982cdba9c84e85355/decorator-5.3.1.tar.gz", hash = "sha256:4cbcdd55a6efadb9dbea26b858f4fb3264567b52d69ca0d25b721b553f60ea82", size = 58084, upload-time = "2026-05-18T06:03:28.057Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/05/7f/798705f5296a58ca505d600456748d1be48078eac8a7050d8a98bc9edb89/decorator-5.3.1-py3-none-any.whl", hash = "sha256:f47fe6fdbd2edd623ecfe36875d37aba411624e2670dd395dddae1358689bb3c", size = 10365, upload-time = "2026-05-18T06:03:26.517Z" }, +] + +[[package]] +name = "diffusers" +version = "0.38.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "filelock" }, + { name = "httpx" }, + { name = "huggingface-hub" }, + { name = "importlib-metadata" }, + { name = "numpy" }, + { name = "pillow" }, + { name = "regex" }, + { name = "requests" }, + { name = "safetensors" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/01/ed/255d3dfd4a2271dffc8f1895f9d2720b3bf1beaecf02148bb5604439e594/diffusers-0.38.0.tar.gz", hash = "sha256:1e094ec5c16f18c42fb89d37f07a94cf9aab3ebbe527ab059c609597b8857626", size = 4328401, upload-time = "2026-05-01T05:42:15.276Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/42/c0/3237566ea6e3a542f3c0669a253d62fe75f27b84b3d7bd4fb3b5ee89d73c/diffusers-0.38.0-py3-none-any.whl", hash = "sha256:18e53f9e539096320470f62c6360a6fd5727ff28cffda566265316e13fcdb612", size = 5245919, upload-time = "2026-05-01T05:42:12.779Z" }, +] + +[[package]] +name = "einops" +version = "0.8.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/2c/77/850bef8d72ffb9219f0b1aac23fbc1bf7d038ee6ea666f331fa273031aa2/einops-0.8.2.tar.gz", hash = "sha256:609da665570e5e265e27283aab09e7f279ade90c4f01bcfca111f3d3e13f2827", size = 56261, upload-time = "2026-01-26T04:13:17.638Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2a/09/f8d8f8f31e4483c10a906437b4ce31bdf3d6d417b73fe33f1a8b59e34228/einops-0.8.2-py3-none-any.whl", hash = "sha256:54058201ac7087911181bfec4af6091bb59380360f069276601256a76af08193", size = 65638, upload-time = "2026-01-26T04:13:18.546Z" }, +] + +[[package]] +name = "filelock" +version = "3.29.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e6/dc/be6cbe99670cd6e4ad387123647cb08e0c32975e223f82551e914c5568a6/filelock-3.29.4.tar.gz", hash = "sha256:10cdb3656fc44541cdf30652a93fb10ec6b05325620eb316bd26893e4201538a", size = 63028, upload-time = "2026-06-13T16:12:00.744Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/13/37/a065dc3bd6e49423a6532c642ca7378d3f467b1ef44c2800c937af7f9739/filelock-3.29.4-py3-none-any.whl", hash = "sha256:dac1648087d5115554850d113e7dd8c83ab2d38e3435dde2d4f163847e57b767", size = 42757, upload-time = "2026-06-13T16:11:59.582Z" }, +] + +[[package]] +name = "fsspec" +version = "2026.6.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/10/a1/ae4e3e5003468d6391d2c77b6fa1cd73bd5d13511d81c642d7b28ac90ed4/fsspec-2026.6.0.tar.gz", hash = "sha256:f5bac145310fe30e16e1471bd6840b2d990d609e872251d7e674241822abf01a", size = 313646, upload-time = "2026-06-16T01:57:28.105Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e5/22/4222d7ddf3da30f363edaa98e329c2bce6c65497c9cb2810931c8b2c0fbc/fsspec-2026.6.0-py3-none-any.whl", hash = "sha256:02e0b71817df9b2169dc30a16832045764def1191b43dcff5bb85bdee212d2a1", size = 203949, upload-time = "2026-06-16T01:57:26.358Z" }, +] + +[[package]] +name = "gguf" +version = "0.19.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy" }, + { name = "pyyaml" }, + { name = "requests" }, + { name = "tqdm" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/48/ae/17f1308ae45cd7b08ebb521747d5b23f4efc4d172038a4e228dd5106c3ff/gguf-0.19.0.tar.gz", hash = "sha256:dbadcd6cc7ccd44256f2229fe7c2dff5e8aa5cf0612ab987fd2b1a57e428923f", size = 111220, upload-time = "2026-05-06T13:04:03.667Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b3/bb/d71d6da82763528c2c2ed6b59a9d6142c6595545a4c448e2085d155e88c2/gguf-0.19.0-py3-none-any.whl", hash = "sha256:70bcd10edfe697fb2dad6e40af2234b9d8ece9a41a99761405121ebda1c3c1cd", size = 118475, upload-time = "2026-05-06T13:04:02.588Z" }, +] + +[[package]] +name = "h11" +version = "0.16.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/01/ee/02a2c011bdab74c6fb3c75474d40b3052059d95df7e73351460c8588d963/h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1", size = 101250, upload-time = "2025-04-24T03:35:25.427Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515, upload-time = "2025-04-24T03:35:24.344Z" }, +] + +[[package]] +name = "hf-xet" +version = "1.5.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/4b/2d/57fd21d84d93efb4bd0b962383790e19dd1bc053501b4264c97903b4e83e/hf_xet-1.5.1.tar.gz", hash = "sha256:51ef4500dab3764b41135ee1381a4b62ce56fc54d4c92b719b59e597d6df5bf6", size = 876636, upload-time = "2026-06-08T23:02:53.897Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7a/d8/5e54cf37434759d1f4f2ba9b66077ff9d4c4e1f37b6bd7975da5c40d94ab/hf_xet-1.5.1-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:6abd35c3221eff63836618ddfb954dcf84798603f71d8e33e3ed7b04acfdbe6e", size = 4077794, upload-time = "2026-06-08T23:02:40.656Z" }, + { url = "https://files.pythonhosted.org/packages/35/94/4b2ecfbad8f8b04701a23aefb62f540b9137d058b7e1dbef16a32676f0e9/hf_xet-1.5.1-cp37-abi3-macosx_11_0_arm64.whl", hash = "sha256:94e761bbd266bf4c03cee73753916062665ce8365aa40ed321f45afcb934b41e", size = 3845354, upload-time = "2026-06-08T23:02:42.702Z" }, + { url = "https://files.pythonhosted.org/packages/de/cc/f99f4bc7295023d7bd9ebbfd51f75cc530ca262c1227666268b8208f4b77/hf_xet-1.5.1-cp37-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:892e3a3a3aecc12aded8b93cf4f9cd059282c7de0732f7d55026f3abdf474350", size = 4514864, upload-time = "2026-06-08T23:02:44.497Z" }, + { url = "https://files.pythonhosted.org/packages/cd/6e/21f7e5a2381278bd3b7b7a5a4d90038518bb6308a0c1daf5d9f8268bb178/hf_xet-1.5.1-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:a93df2039190502835b1db8cd7e178b0b7b889fe9ab51299d5ced26e0dd879a4", size = 4303784, upload-time = "2026-06-08T23:02:46.203Z" }, + { url = "https://files.pythonhosted.org/packages/35/0e/f992bb6927ac1cb30ef74e62268f551f338bc32b2191f7c96a44c6f7283e/hf_xet-1.5.1-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:0c97106032ef70467b4f6bc2d0ccc266d7613ee076afc56516c502f87ce1c4a6", size = 4500703, upload-time = "2026-06-08T23:02:47.628Z" }, + { url = "https://files.pythonhosted.org/packages/fb/d1/90a498d05447980b977b1669246eeeeae4cfb0ea3e7a286eaba627f91bf9/hf_xet-1.5.1-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:6208adb15d192b90e4c2ad2a27ed864359b2cb0f2494eb6d7c7f3699ac02e2bf", size = 4719498, upload-time = "2026-06-08T23:02:49.268Z" }, + { url = "https://files.pythonhosted.org/packages/6d/b6/20f99cfe97cc663a711f7b33cc21d4793e51968e9a26125b4afcd77315ba/hf_xet-1.5.1-cp37-abi3-win_amd64.whl", hash = "sha256:f7b3002f95d1c13e24bcb4537baa8f0eb3838957067c91bb4959bc004a6435f5", size = 4026419, upload-time = "2026-06-08T23:02:50.829Z" }, + { url = "https://files.pythonhosted.org/packages/f9/fa/77453694888f03e5a8c8852d1514a0894d8e81c622d39edbaf308ea0dcf4/hf_xet-1.5.1-cp37-abi3-win_arm64.whl", hash = "sha256:93d090b57b211133f6c0dab0205ef5cb6d89162979ba75a74845045cc3063b8e", size = 3855178, upload-time = "2026-06-08T23:02:52.452Z" }, +] + +[[package]] +name = "httpcore" +version = "1.0.9" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "certifi" }, + { name = "h11" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/06/94/82699a10bca87a5556c9c59b5963f2d039dbd239f25bc2a63907a05a14cb/httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8", size = 85484, upload-time = "2025-04-24T22:06:22.219Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55", size = 78784, upload-time = "2025-04-24T22:06:20.566Z" }, +] + +[[package]] +name = "httpx" +version = "0.28.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, + { name = "certifi" }, + { name = "httpcore" }, + { name = "idna" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b1/df/48c586a5fe32a0f01324ee087459e112ebb7224f646c0b5023f5e79e9956/httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc", size = 141406, upload-time = "2024-12-06T15:37:23.222Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad", size = 73517, upload-time = "2024-12-06T15:37:21.509Z" }, +] + +[[package]] +name = "huggingface-hub" +version = "0.36.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "filelock" }, + { name = "fsspec" }, + { name = "hf-xet", marker = "platform_machine == 'aarch64' or platform_machine == 'amd64' or platform_machine == 'arm64' or platform_machine == 'x86_64'" }, + { name = "packaging" }, + { name = "pyyaml" }, + { name = "requests" }, + { name = "tqdm" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/7c/b7/8cb61d2eece5fb05a83271da168186721c450eb74e3c31f7ef3169fa475b/huggingface_hub-0.36.2.tar.gz", hash = "sha256:1934304d2fb224f8afa3b87007d58501acfda9215b334eed53072dd5e815ff7a", size = 649782, upload-time = "2026-02-06T09:24:13.098Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a8/af/48ac8483240de756d2438c380746e7130d1c6f75802ef22f3c6d49982787/huggingface_hub-0.36.2-py3-none-any.whl", hash = "sha256:48f0c8eac16145dfce371e9d2d7772854a4f591bcb56c9cf548accf531d54270", size = 566395, upload-time = "2026-02-06T09:24:11.133Z" }, +] + +[[package]] +name = "idna" +version = "3.18" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/cd/63/9496c57188a2ee585e0f1db071d75089a11e98aa86eb99d9d7618fc1edce/idna-3.18.tar.gz", hash = "sha256:ffb385a7e039654cef1ab9ef32c6fafe283c0c0467bba1d9029738ce4a14a848", size = 196711, upload-time = "2026-06-02T14:34:07.794Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl", hash = "sha256:7f952cbe720b688055e3f87de14f5c3e5fdaa8bc3928985c4077ca689de849a2", size = 65455, upload-time = "2026-06-02T14:34:06.319Z" }, +] + +[[package]] +name = "importlib-metadata" +version = "9.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "zipp" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a9/01/15bb152d77b21318514a96f43af312635eb2500c96b55398d020c93d86ea/importlib_metadata-9.0.0.tar.gz", hash = "sha256:a4f57ab599e6a2e3016d7595cfd72eb4661a5106e787a95bcc90c7105b831efc", size = 56405, upload-time = "2026-03-20T06:42:56.999Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/38/3d/2d244233ac4f76e38533cfcb2991c9eb4c7bf688ae0a036d30725b8faafe/importlib_metadata-9.0.0-py3-none-any.whl", hash = "sha256:2d21d1cc5a017bd0559e36150c21c830ab1dc304dedd1b7ea85d20f45ef3edd7", size = 27789, upload-time = "2026-03-20T06:42:55.665Z" }, +] + +[[package]] +name = "jinja2" +version = "3.1.6" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markupsafe" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/df/bf/f7da0350254c0ed7c72f3e33cef02e048281fec7ecec5f032d4aac52226b/jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d", size = 245115, upload-time = "2025-03-05T20:05:02.478Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size = 134899, upload-time = "2025-03-05T20:05:00.369Z" }, +] + +[[package]] +name = "joblib" +version = "1.5.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/41/f2/d34e8b3a08a9cc79a50b2208a93dce981fe615b64d5a4d4abee421d898df/joblib-1.5.3.tar.gz", hash = "sha256:8561a3269e6801106863fd0d6d84bb737be9e7631e33aaed3fb9ce5953688da3", size = 331603, upload-time = "2025-12-15T08:41:46.427Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7b/91/984aca2ec129e2757d1e4e3c81c3fcda9d0f85b74670a094cc443d9ee949/joblib-1.5.3-py3-none-any.whl", hash = "sha256:5fc3c5039fc5ca8c0276333a188bbd59d6b7ab37fe6632daa76bc7f9ec18e713", size = 309071, upload-time = "2025-12-15T08:41:44.973Z" }, +] + +[[package]] +name = "lazy-loader" +version = "0.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "packaging" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/49/ac/21a1f8aa3777f5658576777ea76bfb124b702c520bbe90edf4ae9915eafa/lazy_loader-0.5.tar.gz", hash = "sha256:717f9179a0dbed357012ddad50a5ad3d5e4d9a0b8712680d4e687f5e6e6ed9b3", size = 15294, upload-time = "2026-03-06T15:45:09.054Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8a/a1/8d812e53a5da1687abb10445275d41a8b13adb781bbf7196ddbcf8d88505/lazy_loader-0.5-py3-none-any.whl", hash = "sha256:ab0ea149e9c554d4ffeeb21105ac60bed7f3b4fd69b1d2360a4add51b170b005", size = 8044, upload-time = "2026-03-06T15:45:07.668Z" }, +] + +[[package]] +name = "librosa" +version = "0.11.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "audioread" }, + { name = "decorator" }, + { name = "joblib" }, + { name = "lazy-loader" }, + { name = "msgpack" }, + { name = "numba" }, + { name = "numpy" }, + { name = "pooch" }, + { name = "scikit-learn" }, + { name = "scipy", version = "1.17.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.12'" }, + { name = "scipy", version = "1.18.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" }, + { name = "soundfile" }, + { name = "soxr" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/64/36/360b5aafa0238e29758729e9486c6ed92a6f37fa403b7875e06c115cdf4a/librosa-0.11.0.tar.gz", hash = "sha256:f5ed951ca189b375bbe2e33b2abd7e040ceeee302b9bbaeeffdfddb8d0ace908", size = 327001, upload-time = "2025-03-11T15:09:54.884Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b5/ba/c63c5786dfee4c3417094c4b00966e61e4a63efecee22cb7b4c0387dda83/librosa-0.11.0-py3-none-any.whl", hash = "sha256:0b6415c4fd68bff4c29288abe67c6d80b587e0e1e2cfb0aad23e4559504a7fa1", size = 260749, upload-time = "2025-03-11T15:09:52.982Z" }, +] + +[[package]] +name = "llvmlite" +version = "0.47.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/01/88/a8952b6d5c21e74cbf158515b779666f692846502623e9e3c39d8e8ba25f/llvmlite-0.47.0.tar.gz", hash = "sha256:62031ce968ec74e95092184d4b0e857e444f8fdff0b8f9213707699570c33ccc", size = 193614, upload-time = "2026-03-31T18:29:53.497Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/34/0b/b9d1911cfefa61399821dfb37f486d83e0f42630a8d12f7194270c417002/llvmlite-0.47.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:74090f0dcfd6f24ebbef3f21f11e38111c4d7e6919b54c4416e1e357c3446b07", size = 37232770, upload-time = "2026-03-31T18:28:26.765Z" }, + { url = "https://files.pythonhosted.org/packages/46/27/5799b020e4cdfb25a7c951c06a96397c135efcdc21b78d853bbd9c814c7d/llvmlite-0.47.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ca14f02e29134e837982497959a8e2193d6035235de1cb41a9cb2bd6da4eedbb", size = 56275177, upload-time = "2026-03-31T18:28:31.01Z" }, + { url = "https://files.pythonhosted.org/packages/7e/51/48a53fedf01cb1f3f43ef200be17ebf83c8d9a04018d3783c1a226c342c2/llvmlite-0.47.0-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:12a69d4bb05f402f30477e21eeabe81911e7c251cecb192bed82cd83c9db10d8", size = 55128631, upload-time = "2026-03-31T18:28:36.046Z" }, + { url = "https://files.pythonhosted.org/packages/a2/50/59227d06bdc96e23322713c381af4e77420949d8cd8a042c79e0043096cc/llvmlite-0.47.0-cp311-cp311-win_amd64.whl", hash = "sha256:c37d6eb7aaabfa83ab9c2ff5b5cdb95a5e6830403937b2c588b7490724e05327", size = 38138400, upload-time = "2026-03-31T18:28:40.076Z" }, + { url = "https://files.pythonhosted.org/packages/fa/48/4b7fe0e34c169fa2f12532916133e0b219d2823b540733651b34fdac509a/llvmlite-0.47.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:306a265f408c259067257a732c8e159284334018b4083a9e35f67d19792b164f", size = 37232769, upload-time = "2026-03-31T18:28:43.735Z" }, + { url = "https://files.pythonhosted.org/packages/e6/4b/e3f2cd17822cf772a4a51a0a8080b0032e6d37b2dbe8cfb724eac4e31c52/llvmlite-0.47.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5853bf26160857c0c2573415ff4efe01c4c651e59e2c55c2a088740acfee51cd", size = 56275178, upload-time = "2026-03-31T18:28:48.342Z" }, + { url = "https://files.pythonhosted.org/packages/b6/55/a3b4a543185305a9bdf3d9759d53646ed96e55e7dfd43f53e7a421b8fbae/llvmlite-0.47.0-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:003bcf7fa579e14db59c1a1e113f93ab8a06b56a4be31c7f08264d1d4072d077", size = 55128632, upload-time = "2026-03-31T18:28:52.901Z" }, + { url = "https://files.pythonhosted.org/packages/2f/f5/d281ae0f79378a5a91f308ea9fdb9f9cc068fddd09629edc0725a5a8fde1/llvmlite-0.47.0-cp312-cp312-win_amd64.whl", hash = "sha256:f3079f25bdc24cd9d27c4b2b5e68f5f60c4fdb7e8ad5ee2b9b006007558f9df7", size = 38138692, upload-time = "2026-03-31T18:28:57.147Z" }, +] + +[[package]] +name = "markupsafe" +version = "3.0.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/7e/99/7690b6d4034fffd95959cbe0c02de8deb3098cc577c67bb6a24fe5d7caa7/markupsafe-3.0.3.tar.gz", hash = "sha256:722695808f4b6457b320fdc131280796bdceb04ab50fe1795cd540799ebe1698", size = 80313, upload-time = "2025-09-27T18:37:40.426Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/08/db/fefacb2136439fc8dd20e797950e749aa1f4997ed584c62cfb8ef7c2be0e/markupsafe-3.0.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1cc7ea17a6824959616c525620e387f6dd30fec8cb44f649e31712db02123dad", size = 11631, upload-time = "2025-09-27T18:36:18.185Z" }, + { url = "https://files.pythonhosted.org/packages/e1/2e/5898933336b61975ce9dc04decbc0a7f2fee78c30353c5efba7f2d6ff27a/markupsafe-3.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4bd4cd07944443f5a265608cc6aab442e4f74dff8088b0dfc8238647b8f6ae9a", size = 12058, upload-time = "2025-09-27T18:36:19.444Z" }, + { url = "https://files.pythonhosted.org/packages/1d/09/adf2df3699d87d1d8184038df46a9c80d78c0148492323f4693df54e17bb/markupsafe-3.0.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6b5420a1d9450023228968e7e6a9ce57f65d148ab56d2313fcd589eee96a7a50", size = 24287, upload-time = "2025-09-27T18:36:20.768Z" }, + { url = "https://files.pythonhosted.org/packages/30/ac/0273f6fcb5f42e314c6d8cd99effae6a5354604d461b8d392b5ec9530a54/markupsafe-3.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0bf2a864d67e76e5c9a34dc26ec616a66b9888e25e7b9460e1c76d3293bd9dbf", size = 22940, upload-time = "2025-09-27T18:36:22.249Z" }, + { url = "https://files.pythonhosted.org/packages/19/ae/31c1be199ef767124c042c6c3e904da327a2f7f0cd63a0337e1eca2967a8/markupsafe-3.0.3-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:bc51efed119bc9cfdf792cdeaa4d67e8f6fcccab66ed4bfdd6bde3e59bfcbb2f", size = 21887, upload-time = "2025-09-27T18:36:23.535Z" }, + { url = "https://files.pythonhosted.org/packages/b2/76/7edcab99d5349a4532a459e1fe64f0b0467a3365056ae550d3bcf3f79e1e/markupsafe-3.0.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:068f375c472b3e7acbe2d5318dea141359e6900156b5b2ba06a30b169086b91a", size = 23692, upload-time = "2025-09-27T18:36:24.823Z" }, + { url = "https://files.pythonhosted.org/packages/a4/28/6e74cdd26d7514849143d69f0bf2399f929c37dc2b31e6829fd2045b2765/markupsafe-3.0.3-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:7be7b61bb172e1ed687f1754f8e7484f1c8019780f6f6b0786e76bb01c2ae115", size = 21471, upload-time = "2025-09-27T18:36:25.95Z" }, + { url = "https://files.pythonhosted.org/packages/62/7e/a145f36a5c2945673e590850a6f8014318d5577ed7e5920a4b3448e0865d/markupsafe-3.0.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f9e130248f4462aaa8e2552d547f36ddadbeaa573879158d721bbd33dfe4743a", size = 22923, upload-time = "2025-09-27T18:36:27.109Z" }, + { url = "https://files.pythonhosted.org/packages/0f/62/d9c46a7f5c9adbeeeda52f5b8d802e1094e9717705a645efc71b0913a0a8/markupsafe-3.0.3-cp311-cp311-win32.whl", hash = "sha256:0db14f5dafddbb6d9208827849fad01f1a2609380add406671a26386cdf15a19", size = 14572, upload-time = "2025-09-27T18:36:28.045Z" }, + { url = "https://files.pythonhosted.org/packages/83/8a/4414c03d3f891739326e1783338e48fb49781cc915b2e0ee052aa490d586/markupsafe-3.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:de8a88e63464af587c950061a5e6a67d3632e36df62b986892331d4620a35c01", size = 15077, upload-time = "2025-09-27T18:36:29.025Z" }, + { url = "https://files.pythonhosted.org/packages/35/73/893072b42e6862f319b5207adc9ae06070f095b358655f077f69a35601f0/markupsafe-3.0.3-cp311-cp311-win_arm64.whl", hash = "sha256:3b562dd9e9ea93f13d53989d23a7e775fdfd1066c33494ff43f5418bc8c58a5c", size = 13876, upload-time = "2025-09-27T18:36:29.954Z" }, + { url = "https://files.pythonhosted.org/packages/5a/72/147da192e38635ada20e0a2e1a51cf8823d2119ce8883f7053879c2199b5/markupsafe-3.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d53197da72cc091b024dd97249dfc7794d6a56530370992a5e1a08983ad9230e", size = 11615, upload-time = "2025-09-27T18:36:30.854Z" }, + { url = "https://files.pythonhosted.org/packages/9a/81/7e4e08678a1f98521201c3079f77db69fb552acd56067661f8c2f534a718/markupsafe-3.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1872df69a4de6aead3491198eaf13810b565bdbeec3ae2dc8780f14458ec73ce", size = 12020, upload-time = "2025-09-27T18:36:31.971Z" }, + { url = "https://files.pythonhosted.org/packages/1e/2c/799f4742efc39633a1b54a92eec4082e4f815314869865d876824c257c1e/markupsafe-3.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3a7e8ae81ae39e62a41ec302f972ba6ae23a5c5396c8e60113e9066ef893da0d", size = 24332, upload-time = "2025-09-27T18:36:32.813Z" }, + { url = "https://files.pythonhosted.org/packages/3c/2e/8d0c2ab90a8c1d9a24f0399058ab8519a3279d1bd4289511d74e909f060e/markupsafe-3.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d6dd0be5b5b189d31db7cda48b91d7e0a9795f31430b7f271219ab30f1d3ac9d", size = 22947, upload-time = "2025-09-27T18:36:33.86Z" }, + { url = "https://files.pythonhosted.org/packages/2c/54/887f3092a85238093a0b2154bd629c89444f395618842e8b0c41783898ea/markupsafe-3.0.3-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:94c6f0bb423f739146aec64595853541634bde58b2135f27f61c1ffd1cd4d16a", size = 21962, upload-time = "2025-09-27T18:36:35.099Z" }, + { url = "https://files.pythonhosted.org/packages/c9/2f/336b8c7b6f4a4d95e91119dc8521402461b74a485558d8f238a68312f11c/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:be8813b57049a7dc738189df53d69395eba14fb99345e0a5994914a3864c8a4b", size = 23760, upload-time = "2025-09-27T18:36:36.001Z" }, + { url = "https://files.pythonhosted.org/packages/32/43/67935f2b7e4982ffb50a4d169b724d74b62a3964bc1a9a527f5ac4f1ee2b/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:83891d0e9fb81a825d9a6d61e3f07550ca70a076484292a70fde82c4b807286f", size = 21529, upload-time = "2025-09-27T18:36:36.906Z" }, + { url = "https://files.pythonhosted.org/packages/89/e0/4486f11e51bbba8b0c041098859e869e304d1c261e59244baa3d295d47b7/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:77f0643abe7495da77fb436f50f8dab76dbc6e5fd25d39589a0f1fe6548bfa2b", size = 23015, upload-time = "2025-09-27T18:36:37.868Z" }, + { url = "https://files.pythonhosted.org/packages/2f/e1/78ee7a023dac597a5825441ebd17170785a9dab23de95d2c7508ade94e0e/markupsafe-3.0.3-cp312-cp312-win32.whl", hash = "sha256:d88b440e37a16e651bda4c7c2b930eb586fd15ca7406cb39e211fcff3bf3017d", size = 14540, upload-time = "2025-09-27T18:36:38.761Z" }, + { url = "https://files.pythonhosted.org/packages/aa/5b/bec5aa9bbbb2c946ca2733ef9c4ca91c91b6a24580193e891b5f7dbe8e1e/markupsafe-3.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:26a5784ded40c9e318cfc2bdb30fe164bdb8665ded9cd64d500a34fb42067b1c", size = 15105, upload-time = "2025-09-27T18:36:39.701Z" }, + { url = "https://files.pythonhosted.org/packages/e5/f1/216fc1bbfd74011693a4fd837e7026152e89c4bcf3e77b6692fba9923123/markupsafe-3.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:35add3b638a5d900e807944a078b51922212fb3dedb01633a8defc4b01a3c85f", size = 13906, upload-time = "2025-09-27T18:36:40.689Z" }, +] + +[[package]] +name = "ml-collections" +version = "1.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "absl-py" }, + { name = "pyyaml" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b8/f8/1a9ae6696dbb6bc9c44ddf5c5e84710d77fe9a35a57e8a06722e1836a4a6/ml_collections-1.1.0.tar.gz", hash = "sha256:0ac1ac6511b9f1566863e0bb0afad0c64e906ea278ad3f4d2144a55322671f6f", size = 61356, upload-time = "2025-04-17T08:25:02.247Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ab/8a/18d4ff2c7bd83f30d6924bd4ad97abf418488c3f908dea228d6f0961ad68/ml_collections-1.1.0-py3-none-any.whl", hash = "sha256:23b6fa4772aac1ae745a96044b925a5746145a70734f087eaca6626e92c05cbc", size = 76707, upload-time = "2025-04-17T08:24:59.038Z" }, +] + +[[package]] +name = "mpmath" +version = "1.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e0/47/dd32fa426cc72114383ac549964eecb20ecfd886d1e5ccf5340b55b02f57/mpmath-1.3.0.tar.gz", hash = "sha256:7a28eb2a9774d00c7bc92411c19a89209d5da7c4c9a9e227be8330a23a25b91f", size = 508106, upload-time = "2023-03-07T16:47:11.061Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/43/e3/7d92a15f894aa0c9c4b49b8ee9ac9850d6e63b03c9c32c0367a13ae62209/mpmath-1.3.0-py3-none-any.whl", hash = "sha256:a0b2b9fe80bbcd81a6647ff13108738cfb482d481d826cc0e02f5b35e5c88d2c", size = 536198, upload-time = "2023-03-07T16:47:09.197Z" }, +] + +[[package]] +name = "msgpack" +version = "1.2.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/31/f9/c0a1c127f9049db9155afc316952ea571720dd01833ff5e4d7e8e6352dbb/msgpack-1.2.1.tar.gz", hash = "sha256:04c721c2c7448767e9e3f2520a475663d8ee0f09c31890f6d2bd70fd636a9647", size = 183960, upload-time = "2026-06-18T16:13:52.594Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f4/6b/e9b1cdc042c4458801d2545ed782a95f3d6ba8e270cce8745b8603c7f748/msgpack-1.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:29a3f6e9667868429d8240dfd063ea5ffdc1321c13d783aa23827a38de0dcb22", size = 82812, upload-time = "2026-06-18T16:12:45.022Z" }, + { url = "https://files.pythonhosted.org/packages/0c/3a/dd518a1bf78ed1e9ad8afe57307c079a00eafe4b3068932a27ca1ea56b4f/msgpack-1.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:aded5bdf32609dc7987a49bbbd15a8ef096193f96dd8bbeb791de729e650acf5", size = 82739, upload-time = "2026-06-18T16:12:46.025Z" }, + { url = "https://files.pythonhosted.org/packages/70/e0/7ba9e1542bf0771a27b8b37c1316e3f95ae9d748fd765284655c476ad4ef/msgpack-1.2.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:146ee4e9ce80b365c6d4c47073da9da7bcec473e58194ceee5dd7620ace77e06", size = 414233, upload-time = "2026-06-18T16:12:47.029Z" }, + { url = "https://files.pythonhosted.org/packages/03/8d/671d81534ea0e2b0e8a121be100020da09eb78861fe3aa8f3ef7dcd3bed1/msgpack-1.2.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a28d076ca7c82b9c8728ad90b7147489449557038bed50e4241eb832395169b4", size = 423843, upload-time = "2026-06-18T16:12:48.19Z" }, + { url = "https://files.pythonhosted.org/packages/d2/b6/e5c737515ed1f166664b87601b532f58cbb73d8aa6a90b99f7c2c5037e8e/msgpack-1.2.1-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:7d31c0ac0c640f877804c67cb2bc9f4e23dc2db97e96c2e67fa27d38283b41f8", size = 390772, upload-time = "2026-06-18T16:12:49.624Z" }, + { url = "https://files.pythonhosted.org/packages/a8/46/62ed8c2e87d7021eab19921594d961ef3aa3794eec76c716dc30f3bfd433/msgpack-1.2.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8ff92d7feeaf5bc26c51495b69e2f99ed97ab79346fb6555f44be7dd2ac6503b", size = 409559, upload-time = "2026-06-18T16:12:50.936Z" }, + { url = "https://files.pythonhosted.org/packages/70/ff/59aa3887b860bbf43532835e192b1c388a17590d6068ae4f8b2bc74c906e/msgpack-1.2.1-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:779197a6513bab3c3632265e3d0f7cb3227e62510841a6f34f1eaa37efbb345e", size = 387838, upload-time = "2026-06-18T16:12:52.161Z" }, + { url = "https://files.pythonhosted.org/packages/09/11/f8563e471093420cf6478cb3271a0175d8402b82d879783d4035d2d03360/msgpack-1.2.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:67f6dd22fa72a93752643f07889796d62739a13415ee630169a8ce764f86cf9f", size = 421732, upload-time = "2026-06-18T16:12:53.556Z" }, + { url = "https://files.pythonhosted.org/packages/57/cf/e673683c4c6c90c1022b24c65af4b03eda72b182a1176ef6449069d66acc/msgpack-1.2.1-cp311-cp311-win32.whl", hash = "sha256:91054a783328e0ea7954b8771095705c8d2243b814743fbaadf14552c9c52c5d", size = 64091, upload-time = "2026-06-18T16:12:54.821Z" }, + { url = "https://files.pythonhosted.org/packages/3f/07/ca212739d179f9083bff2c7c08c24101c3555a334fadc2b876b18768a3ae/msgpack-1.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:2eda0b7ebb1283a98d3e4492ac933c8af6aff59fd3df1c3ed024f536af4b1dc8", size = 70462, upload-time = "2026-06-18T16:12:55.898Z" }, + { url = "https://files.pythonhosted.org/packages/6d/be/6798347b425e26f35db82e69dd83c09716c856a3714e7bffc4c0860fd830/msgpack-1.2.1-cp311-cp311-win_arm64.whl", hash = "sha256:6ee967f7c7e1df2890c671ff2ee51a28ded0efc95da3e507176dee881ce36c66", size = 65059, upload-time = "2026-06-18T16:12:57.053Z" }, + { url = "https://files.pythonhosted.org/packages/bc/dd/9e8cbd8f5582ca4b590336f2b91ee5662f6a6ca562b565abaf696a0f81ff/msgpack-1.2.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:2ef59c659f289eddf8aa6623823f19fa2f40a4029266889eac7a2505dd210c35", size = 83531, upload-time = "2026-06-18T16:12:58.249Z" }, + { url = "https://files.pythonhosted.org/packages/50/2e/ebdb85a8da151397a2790363676b7ed7c125924fe618e4c6d8befb0cc62c/msgpack-1.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d3567748a5107cb40cdf66a275430c2f87c07777698f4bfd25c35f44d533258c", size = 82657, upload-time = "2026-06-18T16:12:59.396Z" }, + { url = "https://files.pythonhosted.org/packages/26/aa/753ad8b007b464e1d8aa0c8e650b9c5f4f725e658fc5ac8a7635c55b7f6e/msgpack-1.2.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:60926b75d00c8e816ef98f3034f484a8bc64242d66839cef4cf7e503142316a0", size = 410634, upload-time = "2026-06-18T16:13:00.383Z" }, + { url = "https://files.pythonhosted.org/packages/6a/fd/6adabd4f6d5e686f97dd02ce7fce3fe4cf672cbac36b8f67ff4040e8ad8b/msgpack-1.2.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:020e881a764b20d8d7ca1a54fc01b8175519d108e3c3f194fddc200bda95951a", size = 419989, upload-time = "2026-06-18T16:13:01.776Z" }, + { url = "https://files.pythonhosted.org/packages/5a/cc/85039b7b0eb168aaad7383a23c97e291a11f08351cb45a606ce865e4e3f1/msgpack-1.2.1-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:4202c74688ca06591f78cb18988228bd4cca2cc75d57b60008372892d2f1e6e6", size = 377544, upload-time = "2026-06-18T16:13:03.637Z" }, + { url = "https://files.pythonhosted.org/packages/ed/bf/35963899493b32030c85fc513b723ae66144ac70c11ebc52e889e16e3d99/msgpack-1.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8b267ce94efb76fbd1b3373511420074ee3187f0f7811bf394531de13294735a", size = 400842, upload-time = "2026-06-18T16:13:05.012Z" }, + { url = "https://files.pythonhosted.org/packages/a6/df/8e2ac970c8f99264cd9997d1c73df5466bc19da3301d7dc5500862a9b089/msgpack-1.2.1-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:e4f1d0f8f98ade9634e01fb704a408f9336c0a8f1117b369f5db83dc7551d8b1", size = 374108, upload-time = "2026-06-18T16:13:06.232Z" }, + { url = "https://files.pythonhosted.org/packages/17/dd/fa8bd265110dfa51c20cb529f9e6d240a16fafe7e645004c6af2d01353ba/msgpack-1.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:f02cf17a6ca1abe29b5f980644f7551f94d71f2011509b26d8625ce038f0df64", size = 414939, upload-time = "2026-06-18T16:13:07.478Z" }, + { url = "https://files.pythonhosted.org/packages/2e/b9/8377a5ad8953fc0437c70cc98d9ae29f27fe5ac5109fbec0812085865735/msgpack-1.2.1-cp312-cp312-win32.whl", hash = "sha256:0c0d9802354507bcba62af19c17918e3eb437cc25e6f50657d511b5856a77aac", size = 64504, upload-time = "2026-06-18T16:13:08.822Z" }, + { url = "https://files.pythonhosted.org/packages/57/7f/ce1e377df7e62461fefd9eb23bfb93a4a523f40a517b377b8f844d836828/msgpack-1.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:5c24aa15d5963051e1a5c62b12c50cd705992502b5ec1f3bece6046f33c9fc24", size = 71421, upload-time = "2026-06-18T16:13:09.828Z" }, + { url = "https://files.pythonhosted.org/packages/8f/32/ebfe84c9929f08f188d56c7a2fd913406a9ddad76a634697c1c43b8112e6/msgpack-1.2.1-cp312-cp312-win_arm64.whl", hash = "sha256:4227224aaec8f7fbcbfbd4272319347b2bb4030366502600f8c45588c5187b07", size = 64775, upload-time = "2026-06-18T16:13:11.056Z" }, +] + +[[package]] +name = "narwhals" +version = "2.22.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/62/3c/c4ef2164a71c1a63d7f1ae411c4082c5fa872405106db60a4b7114989ad7/narwhals-2.22.1.tar.gz", hash = "sha256:d62920805a0a43b7ff8b54b0c0d3142d796f8a9301836ada37e573d6a33cbcd9", size = 647493, upload-time = "2026-06-05T12:34:34.051Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/48/ca/36339329c4604adbcc99c899b7eb1ce1a555c499b6a6860757dc9bfed36d/narwhals-2.22.1-py3-none-any.whl", hash = "sha256:60567d774edf77db53906f89d9fbd164e66e56d66d388e1e6990f17ac33cfb53", size = 454815, upload-time = "2026-06-05T12:34:32.289Z" }, +] + +[[package]] +name = "networkx" +version = "3.6.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/6a/51/63fe664f3908c97be9d2e4f1158eb633317598cfa6e1fc14af5383f17512/networkx-3.6.1.tar.gz", hash = "sha256:26b7c357accc0c8cde558ad486283728b65b6a95d85ee1cd66bafab4c8168509", size = 2517025, upload-time = "2025-12-08T17:02:39.908Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9e/c9/b2622292ea83fbb4ec318f5b9ab867d0a28ab43c5717bb85b0a5f6b3b0a4/networkx-3.6.1-py3-none-any.whl", hash = "sha256:d47fbf302e7d9cbbb9e2555a0d267983d2aa476bac30e90dfbe5669bd57f3762", size = 2068504, upload-time = "2025-12-08T17:02:38.159Z" }, +] + +[[package]] +name = "numba" +version = "0.65.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "llvmlite" }, + { name = "numpy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/f6/c5/db2ac3685833d626c0dcae6bd2330cd68433e1fd248d15f70998160d3ad7/numba-0.65.1.tar.gz", hash = "sha256:19357146c32fe9ed25059ab915e8465fb13951cf6b0aace3826b76886373ab23", size = 2765600, upload-time = "2026-04-24T02:02:56.551Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/96/b3/650500c2eab4534d98e9166f4298e0f3c69c742afdf24e6eabccd1f16ad8/numba-0.65.1-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:7020d74b19cdb8cff16506542fdd510756e28c5e7f3bd0b7f574f0f42272fcd9", size = 2680563, upload-time = "2026-04-24T02:02:18.414Z" }, + { url = "https://files.pythonhosted.org/packages/44/0b/0615dbedb98f5b32a35a53290fbdc6e22306968109278d7e58df82d7a9f6/numba-0.65.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f80ed83774b5173abd6581cd8d2165d1d38e13d2e5c8155c0c0b421784745420", size = 3745018, upload-time = "2026-04-24T02:02:20.252Z" }, + { url = "https://files.pythonhosted.org/packages/49/aa/4361698f35bf63bff67dfe6c90493731177f48ede954f77b0588731537bc/numba-0.65.1-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7ed425a43b0a5f9772f2f4e2dd0bbd12eabecae1af0b24efcfd4e053f012aac6", size = 3450962, upload-time = "2026-04-24T02:02:22.449Z" }, + { url = "https://files.pythonhosted.org/packages/bd/9a/af61ec03b3116c161fd7a06b9e8a265729a8718458333e8ffbb06d9a3978/numba-0.65.1-cp311-cp311-win_amd64.whl", hash = "sha256:df40a5028a975b9ea66f6a2a3f7abbdbd541a863070e34ed367aff21141248e4", size = 2747417, upload-time = "2026-04-24T02:02:24.43Z" }, + { url = "https://files.pythonhosted.org/packages/57/bc/76f8f8c5cf9adee47fdb7bbb03be8900f76f902d451d7477cf12b845e1de/numba-0.65.1-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:ac3f1e77c352dd0ea9712732c2d8f9ca507717435eec5b5013bf138ac33c4a08", size = 2681371, upload-time = "2026-04-24T02:02:26.105Z" }, + { url = "https://files.pythonhosted.org/packages/69/47/a415af0283e4db0398104c6d1c11c9861a98dc67a7aa442a7769ed5d6196/numba-0.65.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:52bc6f3ceb8fcaff9b2ae26b4c6b1e9fee39db8d355534c0fe4f39a901246b84", size = 3802467, upload-time = "2026-04-24T02:02:27.712Z" }, + { url = "https://files.pythonhosted.org/packages/46/36/246f73ec99cfeab2f2cb2ce7d4218766cc36a2da418901223f4f4da9c813/numba-0.65.1-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:90ca10b3463bae0bd70589726fe3c77d01d6b5fc86bee54bcdf9fb6b47c28977", size = 3502628, upload-time = "2026-04-24T02:02:29.763Z" }, + { url = "https://files.pythonhosted.org/packages/db/9e/3c679b2ee078425b9e99a91e44f8d132a6830d8ccce5227bc5e9181aeed8/numba-0.65.1-cp312-cp312-win_amd64.whl", hash = "sha256:5971c632be2a2351500431f46213821dba8d02b18a9f7d02fd36bd2743e41a6a", size = 2750611, upload-time = "2026-04-24T02:02:31.477Z" }, +] + +[[package]] +name = "numpy" +version = "2.4.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d0/ad/fed0499ce6a338d2a03ebae59cd15093910c8875328855781952abf6c2fe/numpy-2.4.6.tar.gz", hash = "sha256:f3a3570c4a2a16746ac2c31a7c7c7b0c186b95ce902e33db6f28094ed7387dda", size = 20735807, upload-time = "2026-05-18T23:37:14.07Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b3/49/ec46835a70be8fa6446c495126ac84fdb28cb2558e1620ffb87a10c8b64c/numpy-2.4.6-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0280e0356c0829a18d9de1cb7eee50ec22ca639878d7240307ca0943d73cd2c4", size = 16969194, upload-time = "2026-05-18T23:33:13.503Z" }, + { url = "https://files.pythonhosted.org/packages/0e/0d/f5957185c0ee2f3e12f78715aa9e3b353fd83633316c8532b38faa37e3f6/numpy-2.4.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:110f8b71aacb688ec69062bb7f6938a0f8acb01b7c1c4beb453c65b6d234584d", size = 14964111, upload-time = "2026-05-18T23:33:17.795Z" }, + { url = "https://files.pythonhosted.org/packages/ad/40/40a40ee0ddf7ceb782c49af278894b686e586d65d8c1889c8b5da01a3d7d/numpy-2.4.6-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:4cfe66903cc32a9921a6733d96b19bb6abf310397581bbad89c228f5abaf0ee8", size = 5469159, upload-time = "2026-05-18T23:33:20.654Z" }, + { url = "https://files.pythonhosted.org/packages/63/13/f9a8046535cb21deae82f8d03de9617e08882d274fad2539630761888228/numpy-2.4.6-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:8155154c7c691289fe18f510b5d4657c68c67989f293f0535a91360392ff6538", size = 6798936, upload-time = "2026-05-18T23:33:22.987Z" }, + { url = "https://files.pythonhosted.org/packages/33/a8/6fa8c1a345a8c85dbb21932c447bee07c30a2c2a3f31e369c0a84b300147/numpy-2.4.6-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0ab0a9c4ffb1a6d95ef519fe4247dba8eb6b18ad93999f76b7f657039acabd47", size = 15966692, upload-time = "2026-05-18T23:33:26.62Z" }, + { url = "https://files.pythonhosted.org/packages/02/03/74fe2a4cb3817d94d86402f2506554130a2f01414e299b5a843e5a8a957f/numpy-2.4.6-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:89cd468399cfd2504718f0ba50e410dca55a170b61a02ad92bb18c8a65186e93", size = 16918164, upload-time = "2026-05-18T23:33:29.955Z" }, + { url = "https://files.pythonhosted.org/packages/c5/80/3615be3313f7e7696609bc194b9f0101da809df79e859bdb84e0cd043f46/numpy-2.4.6-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c2d37ab77531417474168eb79d6d80b14f821a966818505d03013d0833edb7a8", size = 17322877, upload-time = "2026-05-18T23:33:34.724Z" }, + { url = "https://files.pythonhosted.org/packages/ca/ac/a691e0fe2675e370d0e08ff905adc49a1c8830e8cae03efe4477e92cd55d/numpy-2.4.6-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f407cb6b8e9d6d8c626bc73c945db1706035af8fd632295547bf1c9e46d092d6", size = 18651487, upload-time = "2026-05-18T23:33:38.217Z" }, + { url = "https://files.pythonhosted.org/packages/15/a7/9bc1cd626d7bf6869bfedf27b91b6ab5dd607758bf8e959d6fa80c6a59cb/numpy-2.4.6-cp311-cp311-win32.whl", hash = "sha256:ddea102b48f9e339f3948bf22040944184627a30fdf7f858667673b9c5f033c8", size = 6233945, upload-time = "2026-05-18T23:33:41.331Z" }, + { url = "https://files.pythonhosted.org/packages/c5/31/7fc6239c12bce7e931463251cca4426c465e1876ba3cc785402ef4dd8f4e/numpy-2.4.6-cp311-cp311-win_amd64.whl", hash = "sha256:1e254a00cdf42b1e4d5b3d68d33af63268d41340d8885df2ab6470f2e1500147", size = 12608406, upload-time = "2026-05-18T23:33:44.131Z" }, + { url = "https://files.pythonhosted.org/packages/27/83/140f85a466595a16382996a1bf06b2b54bcd597488921b0c9daaeeda72af/numpy-2.4.6-cp311-cp311-win_arm64.whl", hash = "sha256:ed9749eef4cbd126da3dc1d6bcb3a57f5eb7ac6a6484146bdbf743f552dfc577", size = 10479528, upload-time = "2026-05-18T23:33:50.725Z" }, + { url = "https://files.pythonhosted.org/packages/95/2a/3d7b5ac8aac24feaf9ad7ed58f45b0bbc06d37e4338ae84c9f2298b570f9/numpy-2.4.6-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:001fbb8e08d942dd57599e781f2472269ee7f2755fae407b4f67b2f0b17da3f1", size = 16689119, upload-time = "2026-05-18T23:33:54.065Z" }, + { url = "https://files.pythonhosted.org/packages/ea/12/92c4c131527599e8288d6918e888d88726f84d805d784b771f32408aeaef/numpy-2.4.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ebfb099f8dcf083deef3ac1ca4c1503f387cf76296fcb3816b66f5ecb5f54fdb", size = 14699246, upload-time = "2026-05-18T23:33:57.621Z" }, + { url = "https://files.pythonhosted.org/packages/ad/fe/c0a6b7b2ca128a8fb228575147073b660656734b8ebe4d76c8fd748dcc79/numpy-2.4.6-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:3213d622a0283a39a93d188f3cf72b26862df52fbb4ca3697f51705016523d41", size = 5204410, upload-time = "2026-05-18T23:34:00.302Z" }, + { url = "https://files.pythonhosted.org/packages/f3/d4/9770d14ba719432bb90a421bfd443872ed0f70f7264b64bec12ea363d5fd/numpy-2.4.6-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:357cc07a6d7b0b182ff02249616a03742827ebb1277546b5c7cd7f7620a45698", size = 6551240, upload-time = "2026-05-18T23:34:02.852Z" }, + { url = "https://files.pythonhosted.org/packages/c9/c6/50a46a6205feba2343f1d6d17438107c5dc491ed1c736e6ea68689fd906b/numpy-2.4.6-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5f9fb9157b4ce2971008323afe46053787b526ef624fea915b261468a8421a0f", size = 15671012, upload-time = "2026-05-18T23:34:05.485Z" }, + { url = "https://files.pythonhosted.org/packages/99/60/14115e6364fa676c5397c2ad3004e527e9aa487abf5d0706ec81bbd08529/numpy-2.4.6-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:90f9849678c75fe7afa2d348ac842c168b0a4d3d61919687216dfc547976d853", size = 16645538, upload-time = "2026-05-18T23:34:09.265Z" }, + { url = "https://files.pythonhosted.org/packages/ae/c5/693cbe59e57db94d2231fa519ca3978dc9e19da5a8f088588f5c6e947ff2/numpy-2.4.6-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:c1a2af6c6ef86344a6b0db6b97834208bf598db514f2b155042439b62605601a", size = 17020706, upload-time = "2026-05-18T23:34:13.053Z" }, + { url = "https://files.pythonhosted.org/packages/ef/fc/85b7c4eff9b4966ade25c2273cf7e7012e92366c032058653934b37de044/numpy-2.4.6-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e5805d5a22fd19c8ccff10a9561f9df94436b0545619ea579db2d3c35294bce2", size = 18368541, upload-time = "2026-05-18T23:34:17.024Z" }, + { url = "https://files.pythonhosted.org/packages/f6/81/e1b27545deedce7f4a0b348618c6b62d74e36a4dc9ccd42f3eb2f85eee32/numpy-2.4.6-cp312-cp312-win32.whl", hash = "sha256:e3eeb0aabd6bd5ce64faae67e9935203a6991b4bc2a485a767fbafb2c5125f45", size = 5962825, upload-time = "2026-05-18T23:34:20.3Z" }, + { url = "https://files.pythonhosted.org/packages/ab/ca/feab00bd44aa5fe1ad2c18f08b4d3bb92e26484b0b1d1443897809ed528c/numpy-2.4.6-cp312-cp312-win_amd64.whl", hash = "sha256:d8e8286dd7cea7895157318d1b91cdacac64c479f3cbc8dce548331728484751", size = 12321687, upload-time = "2026-05-18T23:34:23.095Z" }, + { url = "https://files.pythonhosted.org/packages/63/cf/5a6d34850a39d1093558564f77ee8e8e0bee5061151b8f05a55711001ec7/numpy-2.4.6-cp312-cp312-win_arm64.whl", hash = "sha256:4081eb135ac24158bd51cdfbef16f1c64df7063b1143f24731387137c092bec8", size = 10221482, upload-time = "2026-05-18T23:34:25.876Z" }, + { url = "https://files.pythonhosted.org/packages/de/12/b422cc84439adc0d00de605bf4a308890ae5c26f2c71fbd73e5d08fbb0dd/numpy-2.4.6-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:55cced7c52e981362f708ad635198e97a752dfba412cc03c23bbf3bd8d5cd662", size = 16847511, upload-time = "2026-05-18T23:36:50.673Z" }, + { url = "https://files.pythonhosted.org/packages/44/53/f481bef68011740f8849418d82db07230e825013f31f4eef5ba5b805316a/numpy-2.4.6-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:d6da64deb6b8ed903e7560180a92f2d804ee1ba5eeb849ac2748b8c1aba1f6d7", size = 14889064, upload-time = "2026-05-18T23:36:53.879Z" }, + { url = "https://files.pythonhosted.org/packages/7f/57/42ed575c10ced8af951d426bc4e1f8aff16fd851db33f067036215a7f860/numpy-2.4.6-pp311-pypy311_pp73-macosx_14_0_arm64.whl", hash = "sha256:68a5124b13fa6cc2086764a20005d30bc0548146f7f5322f02fce212ca14317f", size = 5394157, upload-time = "2026-05-18T23:36:57.194Z" }, + { url = "https://files.pythonhosted.org/packages/6a/ef/f66cc724fcc36c1e364c67f51ae9146090b8b584f27d58b97fdae3edd737/numpy-2.4.6-pp311-pypy311_pp73-macosx_14_0_x86_64.whl", hash = "sha256:948424b06129ce883307e8cff868c31396d8dc7630a59c61d70d98dbe70f222c", size = 6708728, upload-time = "2026-05-18T23:36:59.575Z" }, + { url = "https://files.pythonhosted.org/packages/1a/9c/c531f2293b91265d8b48e9b329f54fdd7ffae73cb4134ea10cca4237e9cc/numpy-2.4.6-pp311-pypy311_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5dbbdb29840ca3d91ee0fece42fc29278886d908280bfec0a5846c6f901a3eb0", size = 15798374, upload-time = "2026-05-18T23:37:02.674Z" }, + { url = "https://files.pythonhosted.org/packages/1a/b0/413077f6b1153ed3cba361401c6783bbad6114804a000cc22eb71c13e190/numpy-2.4.6-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8ad03c0965fb3c692200e74d458ca28c1dbb4ce96f9a479a8aa041ad5fabca02", size = 16747286, upload-time = "2026-05-18T23:37:06.327Z" }, + { url = "https://files.pythonhosted.org/packages/15/ce/e5ec180bc41812edcd8daeb8639d205622c0e8c02259d8ab25a0201b3c2a/numpy-2.4.6-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:2803abfebfc990042cd494d8ce2d5f82e9d847af6d35ec486923aa19dbad5e73", size = 12504263, upload-time = "2026-05-18T23:37:09.715Z" }, +] + +[[package]] +name = "nvidia-cublas" +version = "13.1.1.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "nvidia-cuda-nvrtc" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/a7/a1/0bd24ee8c8d03adac032fd2909426a00c88f8c57961b1277ded97f91119f/nvidia_cublas-13.1.1.3-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:b7a210458267ac818974c53038fbec2e969d5c99f305ab15c72522fa9f001dd5", size = 542848918, upload-time = "2026-04-08T18:46:22.985Z" }, + { url = "https://files.pythonhosted.org/packages/3b/cd/154ca20c38269e05eff77c1464e6c1da89f50a6390b565e9d82e06bc11e1/nvidia_cublas-13.1.1.3-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:37936a16db8fe4ac1f065c2139360608a543a09275cb1a1af612e08cfa065436", size = 423138758, upload-time = "2026-04-08T18:46:58.655Z" }, +] + +[[package]] +name = "nvidia-cuda-cupti" +version = "13.0.85" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2a/2a/80353b103fc20ce05ef51e928daed4b6015db4aaa9162ed0997090fe2250/nvidia_cuda_cupti-13.0.85-py3-none-manylinux_2_25_aarch64.whl", hash = "sha256:796bd679890ee55fb14a94629b698b6db54bcfd833d391d5e94017dd9d7d3151", size = 10310827, upload-time = "2025-09-04T08:26:42.012Z" }, + { url = "https://files.pythonhosted.org/packages/33/6d/737d164b4837a9bbd202f5ae3078975f0525a55730fe871d8ed4e3b952b0/nvidia_cuda_cupti-13.0.85-py3-none-manylinux_2_25_x86_64.whl", hash = "sha256:4eb01c08e859bf924d222250d2e8f8b8ff6d3db4721288cf35d14252a4d933c8", size = 10715597, upload-time = "2025-09-04T08:26:51.312Z" }, +] + +[[package]] +name = "nvidia-cuda-nvrtc" +version = "13.0.88" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c3/68/483a78f5e8f31b08fb1bb671559968c0ca3a065ac7acabfc7cee55214fd6/nvidia_cuda_nvrtc-13.0.88-py3-none-manylinux2010_x86_64.manylinux_2_12_x86_64.whl", hash = "sha256:ad9b6d2ead2435f11cbb6868809d2adeeee302e9bb94bcf0539c7a40d80e8575", size = 90215200, upload-time = "2025-09-04T08:28:44.204Z" }, + { url = "https://files.pythonhosted.org/packages/b7/dc/6bb80850e0b7edd6588d560758f17e0550893a1feaf436807d64d2da040f/nvidia_cuda_nvrtc-13.0.88-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d27f20a0ca67a4bb34268a5e951033496c5b74870b868bacd046b1b8e0c3267b", size = 43015449, upload-time = "2025-09-04T08:28:20.239Z" }, +] + +[[package]] +name = "nvidia-cuda-runtime" +version = "13.0.96" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/87/4f/17d7b9b8e285199c58ce28e31b5c5bbaa4d8271af06a89b6405258245de2/nvidia_cuda_runtime-13.0.96-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:ef9bcbe90493a2b9d810e43d249adb3d02e98dd30200d86607d8d02687c43f55", size = 2261060, upload-time = "2025-10-09T08:55:15.78Z" }, + { url = "https://files.pythonhosted.org/packages/2e/24/d1558f3b68b1d26e706813b1d10aa1d785e4698c425af8db8edc3dced472/nvidia_cuda_runtime-13.0.96-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:7f82250d7782aa23b6cfe765ecc7db554bd3c2870c43f3d1821f1d18aebf0548", size = 2243632, upload-time = "2025-10-09T08:55:36.117Z" }, +] + +[[package]] +name = "nvidia-cudnn-cu13" +version = "9.20.0.48" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "nvidia-cublas" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/56/c5/83384d846b2fd17c44bd499b36c75a45ed4f095fbbb2252294e89cea5c5c/nvidia_cudnn_cu13-9.20.0.48-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:e31454ae00094b0c55319d9d15b6fa2fc50a9e1c0f5c8c80fb75258234e731e1", size = 444574296, upload-time = "2026-03-09T19:28:27.751Z" }, + { url = "https://files.pythonhosted.org/packages/6e/5e/edb9c0ae051602c3ccaffe424256463636d639e27d7f302dde9975ef9e7a/nvidia_cudnn_cu13-9.20.0.48-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:0c45dd8eeb50b603f07995b1b300c62ffe6a1980482b82b3bcf94a4ca9d49304", size = 366173588, upload-time = "2026-03-09T19:29:34.474Z" }, +] + +[[package]] +name = "nvidia-cufft" +version = "12.0.0.61" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "nvidia-nvjitlink" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/8b/ae/f417a75c0259e85c1d2f83ca4e960289a5f814ed0cea74d18c353d3e989d/nvidia_cufft-12.0.0.61-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:2708c852ef8cd89d1d2068bdbece0aa188813a0c934db3779b9b1faa8442e5f5", size = 214053554, upload-time = "2025-09-04T08:31:38.196Z" }, + { url = "https://files.pythonhosted.org/packages/a8/2f/7b57e29836ea8714f81e9898409196f47d772d5ddedddf1592eadb8ab743/nvidia_cufft-12.0.0.61-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:6c44f692dce8fd5ffd3e3df134b6cdb9c2f72d99cf40b62c32dde45eea9ddad3", size = 214085489, upload-time = "2025-09-04T08:31:56.044Z" }, +] + +[[package]] +name = "nvidia-cufile" +version = "1.15.1.6" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3f/70/4f193de89a48b71714e74602ee14d04e4019ad36a5a9f20c425776e72cd6/nvidia_cufile-1.15.1.6-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:08a3ecefae5a01c7f5117351c64f17c7c62efa5fffdbe24fc7d298da19cd0b44", size = 1223672, upload-time = "2025-09-04T08:32:22.779Z" }, + { url = "https://files.pythonhosted.org/packages/ab/73/cc4a14c9813a8a0d509417cf5f4bdaba76e924d58beb9864f5a7baceefbf/nvidia_cufile-1.15.1.6-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:bdc0deedc61f548bddf7733bdc216456c2fdb101d020e1ab4b88d232d5e2f6d1", size = 1136992, upload-time = "2025-09-04T08:32:14.119Z" }, +] + +[[package]] +name = "nvidia-curand" +version = "10.4.0.35" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1e/72/7c2ae24fb6b63a32e6ae5d241cc65263ea18d08802aaae087d9f013335a2/nvidia_curand-10.4.0.35-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:133df5a7509c3e292aaa2b477afd0194f06ce4ea24d714d616ff36439cee349a", size = 61962106, upload-time = "2025-08-04T10:21:41.128Z" }, + { url = "https://files.pythonhosted.org/packages/a5/9f/be0a41ca4a4917abf5cb9ae0daff1a6060cc5de950aec0396de9f3b52bc5/nvidia_curand-10.4.0.35-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:1aee33a5da6e1db083fe2b90082def8915f30f3248d5896bcec36a579d941bfc", size = 59544258, upload-time = "2025-08-04T10:22:03.992Z" }, +] + +[[package]] +name = "nvidia-cusolver" +version = "12.0.4.66" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "nvidia-cublas" }, + { name = "nvidia-cusparse" }, + { name = "nvidia-nvjitlink" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/c8/c3/b30c9e935fc01e3da443ec0116ed1b2a009bb867f5324d3f2d7e533e776b/nvidia_cusolver-12.0.4.66-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:02c2457eaa9e39de20f880f4bd8820e6a1cfb9f9a34f820eb12a155aa5bc92d2", size = 223467760, upload-time = "2025-09-04T08:33:04.222Z" }, + { url = "https://files.pythonhosted.org/packages/5f/67/cba3777620cdacb99102da4042883709c41c709f4b6323c10781a9c3aa34/nvidia_cusolver-12.0.4.66-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:0a759da5dea5c0ea10fd307de75cdeb59e7ea4fcb8add0924859b944babf1112", size = 200941980, upload-time = "2025-09-04T08:33:22.767Z" }, +] + +[[package]] +name = "nvidia-cusparse" +version = "12.6.3.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "nvidia-nvjitlink" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/f8/94/5c26f33738ae35276672f12615a64bd008ed5be6d1ebcb23579285d960a9/nvidia_cusparse-12.6.3.3-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:80bcc4662f23f1054ee334a15c72b8940402975e0eab63178fc7e670aa59472c", size = 162155568, upload-time = "2025-09-04T08:33:42.864Z" }, + { url = "https://files.pythonhosted.org/packages/fa/18/623c77619c31d62efd55302939756966f3ecc8d724a14dab2b75f1508850/nvidia_cusparse-12.6.3.3-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:2b3c89c88d01ee0e477cb7f82ef60a11a4bcd57b6b87c33f789350b59759360b", size = 145942937, upload-time = "2025-09-04T08:33:58.029Z" }, +] + +[[package]] +name = "nvidia-cusparselt-cu13" +version = "0.8.1" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/46/e1/cdc1797eadf82d3a9a575a19b33fdc871a97edbec42c00b5b5e914f4aff4/nvidia_cusparselt_cu13-0.8.1-py3-none-manylinux2014_aarch64.whl", hash = "sha256:4dca476c50bf4780d46cd0bfbd82e2bc10a08e4fef7950917ce8d7578d22a23f", size = 221051344, upload-time = "2025-09-05T18:49:51.289Z" }, + { url = "https://files.pythonhosted.org/packages/34/7d/2661f2fb3ac4302f3a246f5fc030213ac60c1fe0bce84f9783dbd831dbb7/nvidia_cusparselt_cu13-0.8.1-py3-none-manylinux2014_x86_64.whl", hash = "sha256:786ce87568c303fadb5afcc7102d454cd3040d75f6f8626f5db460d1871f4dd0", size = 170148586, upload-time = "2025-09-05T18:50:50.248Z" }, +] + +[[package]] +name = "nvidia-nccl-cu13" +version = "2.29.7" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/72/0d/daf50d44177ee0cbc7ff0a0c91eb5ff676c82be42f9a970bc7597f440c3a/nvidia_nccl_cu13-2.29.7-py3-none-manylinux_2_18_aarch64.whl", hash = "sha256:674a12383e3c38a1bcccae7d4f3633b37852230b6047883cb2f4c2d1b36d9bf5", size = 206014712, upload-time = "2026-03-03T05:34:20.843Z" }, + { url = "https://files.pythonhosted.org/packages/67/f4/58e4e91b6919367c7aafb8e36fce9aad1a3047e536bf7e2fd560927d3a4c/nvidia_nccl_cu13-2.29.7-py3-none-manylinux_2_18_x86_64.whl", hash = "sha256:edd81538446786ec3b73972543e53bb43bcaf0bfc8ef76cb679fcc390ffe136d", size = 205976000, upload-time = "2026-03-03T05:36:24.472Z" }, +] + +[[package]] +name = "nvidia-nvjitlink" +version = "13.0.88" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/56/7a/123e033aaff487c77107195fa5a2b8686795ca537935a24efae476c41f05/nvidia_nvjitlink-13.0.88-py3-none-manylinux2010_x86_64.manylinux_2_12_x86_64.whl", hash = "sha256:13a74f429e23b921c1109976abefacc69835f2f433ebd323d3946e11d804e47b", size = 40713933, upload-time = "2025-09-04T08:35:43.553Z" }, + { url = "https://files.pythonhosted.org/packages/ab/2c/93c5250e64df4f894f1cbb397c6fd71f79813f9fd79d7cd61de3f97b3c2d/nvidia_nvjitlink-13.0.88-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:e931536ccc7d467a98ba1d8b89ff7fa7f1fa3b13f2b0069118cd7f47bff07d0c", size = 38768748, upload-time = "2025-09-04T08:35:20.008Z" }, +] + +[[package]] +name = "nvidia-nvshmem-cu13" +version = "3.4.5" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/dc/0f/05cc9c720236dcd2db9c1ab97fff629e96821be2e63103569da0c9b72f19/nvidia_nvshmem_cu13-3.4.5-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:6dc2a197f38e5d0376ad52cd1a2a3617d3cdc150fd5966f4aee9bcebb1d68fe9", size = 60215947, upload-time = "2025-09-06T00:32:20.022Z" }, + { url = "https://files.pythonhosted.org/packages/3c/35/a9bf80a609e74e3b000fef598933235c908fcefcef9026042b8e6dfde2a9/nvidia_nvshmem_cu13-3.4.5-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:290f0a2ee94c9f3687a02502f3b9299a9f9fe826e6d0287ee18482e78d495b80", size = 60412546, upload-time = "2025-09-06T00:32:41.564Z" }, +] + +[[package]] +name = "nvidia-nvtx" +version = "13.0.85" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c2/f3/d86c845465a2723ad7e1e5c36dcd75ddb82898b3f53be47ebd429fb2fa5d/nvidia_nvtx-13.0.85-py3-none-manylinux1_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:4936d1d6780fbe68db454f5e72a42ff64d1fd6397df9f363ae786930fd5c1cd4", size = 148047, upload-time = "2025-09-04T08:29:01.761Z" }, + { url = "https://files.pythonhosted.org/packages/a8/64/3708a90d1ebe202ffdeb7185f878a3c84d15c2b2c31858da2ce0583e2def/nvidia_nvtx-13.0.85-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:cb7780edb6b14107373c835bf8b72e7a178bac7367e23da7acb108f973f157a6", size = 148878, upload-time = "2025-09-04T08:28:53.627Z" }, +] + +[[package]] +name = "packaging" +version = "26.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d7/f1/e7a6dd94a8d4a5626c03e4e99c87f241ba9e350cd9e6d75123f992427270/packaging-26.2.tar.gz", hash = "sha256:ff452ff5a3e828ce110190feff1178bb1f2ea2281fa2075aadb987c2fb221661", size = 228134, upload-time = "2026-04-24T20:15:23.917Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl", hash = "sha256:5fc45236b9446107ff2415ce77c807cee2862cb6fac22b8a73826d0693b0980e", size = 100195, upload-time = "2026-04-24T20:15:22.081Z" }, +] + +[[package]] +name = "pillow" +version = "12.2.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/8c/21/c2bcdd5906101a30244eaffc1b6e6ce71a31bd0742a01eb89e660ebfac2d/pillow-12.2.0.tar.gz", hash = "sha256:a830b1a40919539d07806aa58e1b114df53ddd43213d9c8b75847eee6c0182b5", size = 46987819, upload-time = "2026-04-01T14:46:17.687Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/68/e1/748f5663efe6edcfc4e74b2b93edfb9b8b99b67f21a854c3ae416500a2d9/pillow-12.2.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:8be29e59487a79f173507c30ddf57e733a357f67881430449bb32614075a40ab", size = 5354347, upload-time = "2026-04-01T14:42:44.255Z" }, + { url = "https://files.pythonhosted.org/packages/47/a1/d5ff69e747374c33a3b53b9f98cca7889fce1fd03d79cdc4e1bccc6c5a87/pillow-12.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:71cde9a1e1551df7d34a25462fc60325e8a11a82cc2e2f54578e5e9a1e153d65", size = 4695873, upload-time = "2026-04-01T14:42:46.452Z" }, + { url = "https://files.pythonhosted.org/packages/df/21/e3fbdf54408a973c7f7f89a23b2cb97a7ef30c61ab4142af31eee6aebc88/pillow-12.2.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:f490f9368b6fc026f021db16d7ec2fbf7d89e2edb42e8ec09d2c60505f5729c7", size = 6280168, upload-time = "2026-04-01T14:42:49.228Z" }, + { url = "https://files.pythonhosted.org/packages/d3/f1/00b7278c7dd52b17ad4329153748f87b6756ec195ff786c2bdf12518337d/pillow-12.2.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8bd7903a5f2a4545f6fd5935c90058b89d30045568985a71c79f5fd6edf9b91e", size = 8088188, upload-time = "2026-04-01T14:42:51.735Z" }, + { url = "https://files.pythonhosted.org/packages/ad/cf/220a5994ef1b10e70e85748b75649d77d506499352be135a4989c957b701/pillow-12.2.0-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3997232e10d2920a68d25191392e3a4487d8183039e1c74c2297f00ed1c50705", size = 6394401, upload-time = "2026-04-01T14:42:54.343Z" }, + { url = "https://files.pythonhosted.org/packages/e9/bd/e51a61b1054f09437acfbc2ff9106c30d1eb76bc1453d428399946781253/pillow-12.2.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e74473c875d78b8e9d5da2a70f7099549f9eb37ded4e2f6a463e60125bccd176", size = 7079655, upload-time = "2026-04-01T14:42:56.954Z" }, + { url = "https://files.pythonhosted.org/packages/6b/3d/45132c57d5fb4b5744567c3817026480ac7fc3ce5d4c47902bc0e7f6f853/pillow-12.2.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:56a3f9c60a13133a98ecff6197af34d7824de9b7b38c3654861a725c970c197b", size = 6503105, upload-time = "2026-04-01T14:42:59.847Z" }, + { url = "https://files.pythonhosted.org/packages/7d/2e/9df2fc1e82097b1df3dce58dc43286aa01068e918c07574711fcc53e6fb4/pillow-12.2.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:90e6f81de50ad6b534cab6e5aef77ff6e37722b2f5d908686f4a5c9eba17a909", size = 7203402, upload-time = "2026-04-01T14:43:02.664Z" }, + { url = "https://files.pythonhosted.org/packages/bd/2e/2941e42858ebb67e50ae741473de81c2984e6eff7b397017623c676e2e8d/pillow-12.2.0-cp311-cp311-win32.whl", hash = "sha256:8c984051042858021a54926eb597d6ee3012393ce9c181814115df4c60b9a808", size = 6378149, upload-time = "2026-04-01T14:43:05.274Z" }, + { url = "https://files.pythonhosted.org/packages/69/42/836b6f3cd7f3e5fa10a1f1a5420447c17966044c8fbf589cc0452d5502db/pillow-12.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:6e6b2a0c538fc200b38ff9eb6628228b77908c319a005815f2dde585a0664b60", size = 7082626, upload-time = "2026-04-01T14:43:08.557Z" }, + { url = "https://files.pythonhosted.org/packages/c2/88/549194b5d6f1f494b485e493edc6693c0a16f4ada488e5bd974ed1f42fad/pillow-12.2.0-cp311-cp311-win_arm64.whl", hash = "sha256:9a8a34cc89c67a65ea7437ce257cea81a9dad65b29805f3ecee8c8fe8ff25ffe", size = 2463531, upload-time = "2026-04-01T14:43:10.743Z" }, + { url = "https://files.pythonhosted.org/packages/58/be/7482c8a5ebebbc6470b3eb791812fff7d5e0216c2be3827b30b8bb6603ed/pillow-12.2.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:2d192a155bbcec180f8564f693e6fd9bccff5a7af9b32e2e4bf8c9c69dbad6b5", size = 5308279, upload-time = "2026-04-01T14:43:13.246Z" }, + { url = "https://files.pythonhosted.org/packages/d8/95/0a351b9289c2b5cbde0bacd4a83ebc44023e835490a727b2a3bd60ddc0f4/pillow-12.2.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f3f40b3c5a968281fd507d519e444c35f0ff171237f4fdde090dd60699458421", size = 4695490, upload-time = "2026-04-01T14:43:15.584Z" }, + { url = "https://files.pythonhosted.org/packages/de/af/4e8e6869cbed569d43c416fad3dc4ecb944cb5d9492defaed89ddd6fe871/pillow-12.2.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:03e7e372d5240cc23e9f07deca4d775c0817bffc641b01e9c3af208dbd300987", size = 6284462, upload-time = "2026-04-01T14:43:18.268Z" }, + { url = "https://files.pythonhosted.org/packages/e9/9e/c05e19657fd57841e476be1ab46c4d501bffbadbafdc31a6d665f8b737b6/pillow-12.2.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:b86024e52a1b269467a802258c25521e6d742349d760728092e1bc2d135b4d76", size = 8094744, upload-time = "2026-04-01T14:43:20.716Z" }, + { url = "https://files.pythonhosted.org/packages/2b/54/1789c455ed10176066b6e7e6da1b01e50e36f94ba584dc68d9eebfe9156d/pillow-12.2.0-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7371b48c4fa448d20d2714c9a1f775a81155050d383333e0a6c15b1123dda005", size = 6398371, upload-time = "2026-04-01T14:43:23.443Z" }, + { url = "https://files.pythonhosted.org/packages/43/e3/fdc657359e919462369869f1c9f0e973f353f9a9ee295a39b1fea8ee1a77/pillow-12.2.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:62f5409336adb0663b7caa0da5c7d9e7bdbaae9ce761d34669420c2a801b2780", size = 7087215, upload-time = "2026-04-01T14:43:26.758Z" }, + { url = "https://files.pythonhosted.org/packages/8b/f8/2f6825e441d5b1959d2ca5adec984210f1ec086435b0ed5f52c19b3b8a6e/pillow-12.2.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:01afa7cf67f74f09523699b4e88c73fb55c13346d212a59a2db1f86b0a63e8c5", size = 6509783, upload-time = "2026-04-01T14:43:29.56Z" }, + { url = "https://files.pythonhosted.org/packages/67/f9/029a27095ad20f854f9dba026b3ea6428548316e057e6fc3545409e86651/pillow-12.2.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fc3d34d4a8fbec3e88a79b92e5465e0f9b842b628675850d860b8bd300b159f5", size = 7212112, upload-time = "2026-04-01T14:43:32.091Z" }, + { url = "https://files.pythonhosted.org/packages/be/42/025cfe05d1be22dbfdb4f264fe9de1ccda83f66e4fc3aac94748e784af04/pillow-12.2.0-cp312-cp312-win32.whl", hash = "sha256:58f62cc0f00fd29e64b29f4fd923ffdb3859c9f9e6105bfc37ba1d08994e8940", size = 6378489, upload-time = "2026-04-01T14:43:34.601Z" }, + { url = "https://files.pythonhosted.org/packages/5d/7b/25a221d2c761c6a8ae21bfa3874988ff2583e19cf8a27bf2fee358df7942/pillow-12.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:7f84204dee22a783350679a0333981df803dac21a0190d706a50475e361c93f5", size = 7084129, upload-time = "2026-04-01T14:43:37.213Z" }, + { url = "https://files.pythonhosted.org/packages/10/e1/542a474affab20fd4a0f1836cb234e8493519da6b76899e30bcc5d990b8b/pillow-12.2.0-cp312-cp312-win_arm64.whl", hash = "sha256:af73337013e0b3b46f175e79492d96845b16126ddf79c438d7ea7ff27783a414", size = 2463612, upload-time = "2026-04-01T14:43:39.421Z" }, + { url = "https://files.pythonhosted.org/packages/4e/b7/2437044fb910f499610356d1352e3423753c98e34f915252aafecc64889f/pillow-12.2.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:0538bd5e05efec03ae613fd89c4ce0368ecd2ba239cc25b9f9be7ed426b0af1f", size = 5273969, upload-time = "2026-04-01T14:45:55.538Z" }, + { url = "https://files.pythonhosted.org/packages/f6/f4/8316e31de11b780f4ac08ef3654a75555e624a98db1056ecb2122d008d5a/pillow-12.2.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:394167b21da716608eac917c60aa9b969421b5dcbbe02ae7f013e7b85811c69d", size = 4659674, upload-time = "2026-04-01T14:45:58.093Z" }, + { url = "https://files.pythonhosted.org/packages/d4/37/664fca7201f8bb2aa1d20e2c3d5564a62e6ae5111741966c8319ca802361/pillow-12.2.0-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:5d04bfa02cc2d23b497d1e90a0f927070043f6cbf303e738300532379a4b4e0f", size = 5288479, upload-time = "2026-04-01T14:46:01.141Z" }, + { url = "https://files.pythonhosted.org/packages/49/62/5b0ed78fce87346be7a5cfcfaaad91f6a1f98c26f86bdbafa2066c647ef6/pillow-12.2.0-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:0c838a5125cee37e68edec915651521191cef1e6aa336b855f495766e77a366e", size = 7032230, upload-time = "2026-04-01T14:46:03.874Z" }, + { url = "https://files.pythonhosted.org/packages/c3/28/ec0fc38107fc32536908034e990c47914c57cd7c5a3ece4d8d8f7ffd7e27/pillow-12.2.0-pp311-pypy311_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4a6c9fa44005fa37a91ebfc95d081e8079757d2e904b27103f4f5fa6f0bf78c0", size = 5355404, upload-time = "2026-04-01T14:46:06.33Z" }, + { url = "https://files.pythonhosted.org/packages/5e/8b/51b0eddcfa2180d60e41f06bd6d0a62202b20b59c68f5a132e615b75aecf/pillow-12.2.0-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:25373b66e0dd5905ed63fa3cae13c82fbddf3079f2c8bf15c6fb6a35586324c1", size = 6002215, upload-time = "2026-04-01T14:46:08.83Z" }, + { url = "https://files.pythonhosted.org/packages/bc/60/5382c03e1970de634027cee8e1b7d39776b778b81812aaf45b694dfe9e28/pillow-12.2.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:bfa9c230d2fe991bed5318a5f119bd6780cda2915cca595393649fc118ab895e", size = 7080946, upload-time = "2026-04-01T14:46:11.734Z" }, +] + +[[package]] +name = "platformdirs" +version = "4.10.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d7/47/e4501f49c178ae1d9f4a75073fda4204f52647993f075a9db4d14930e0c5/platformdirs-4.10.0.tar.gz", hash = "sha256:31e761a6a0ca04faf7353ea759bdba55652be214725111e5aac52dfa29d4bef7", size = 31224, upload-time = "2026-05-28T03:32:53.587Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/81/e6/cd9575ac904136b3cbf7aa7ee819ef86eedb7274e46f230e94ea4342e729/platformdirs-4.10.0-py3-none-any.whl", hash = "sha256:fb516cdb12eb0d857d0cd85a7c57cea4d060bee4578d6cf5a14dfdf8cbf8784a", size = 22743, upload-time = "2026-05-28T03:32:52.175Z" }, +] + +[[package]] +name = "pooch" +version = "1.9.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "packaging" }, + { name = "platformdirs" }, + { name = "requests" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/83/43/85ef45e8b36c6a48546af7b266592dc32d7f67837a6514d111bced6d7d75/pooch-1.9.0.tar.gz", hash = "sha256:de46729579b9857ffd3e741987a2f6d5e0e03219892c167c6578c0091fb511ed", size = 61788, upload-time = "2026-01-30T19:15:09.649Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2a/2d/d4bf65e47cea8ff2c794a600c4fd1273a7902f268757c531e0ee9f18aa58/pooch-1.9.0-py3-none-any.whl", hash = "sha256:f265597baa9f760d25ceb29d0beb8186c243d6607b0f60b83ecf14078dbc703b", size = 67175, upload-time = "2026-01-30T19:15:08.36Z" }, +] + +[[package]] +name = "psutil" +version = "7.2.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/aa/c6/d1ddf4abb55e93cebc4f2ed8b5d6dbad109ecb8d63748dd2b20ab5e57ebe/psutil-7.2.2.tar.gz", hash = "sha256:0746f5f8d406af344fd547f1c8daa5f5c33dbc293bb8d6a16d80b4bb88f59372", size = 493740, upload-time = "2026-01-28T18:14:54.428Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e7/36/5ee6e05c9bd427237b11b3937ad82bb8ad2752d72c6969314590dd0c2f6e/psutil-7.2.2-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:ed0cace939114f62738d808fdcecd4c869222507e266e574799e9c0faa17d486", size = 129090, upload-time = "2026-01-28T18:15:22.168Z" }, + { url = "https://files.pythonhosted.org/packages/80/c4/f5af4c1ca8c1eeb2e92ccca14ce8effdeec651d5ab6053c589b074eda6e1/psutil-7.2.2-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:1a7b04c10f32cc88ab39cbf606e117fd74721c831c98a27dc04578deb0c16979", size = 129859, upload-time = "2026-01-28T18:15:23.795Z" }, + { url = "https://files.pythonhosted.org/packages/b5/70/5d8df3b09e25bce090399cf48e452d25c935ab72dad19406c77f4e828045/psutil-7.2.2-cp36-abi3-manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:076a2d2f923fd4821644f5ba89f059523da90dc9014e85f8e45a5774ca5bc6f9", size = 155560, upload-time = "2026-01-28T18:15:25.976Z" }, + { url = "https://files.pythonhosted.org/packages/63/65/37648c0c158dc222aba51c089eb3bdfa238e621674dc42d48706e639204f/psutil-7.2.2-cp36-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b0726cecd84f9474419d67252add4ac0cd9811b04d61123054b9fb6f57df6e9e", size = 156997, upload-time = "2026-01-28T18:15:27.794Z" }, + { url = "https://files.pythonhosted.org/packages/8e/13/125093eadae863ce03c6ffdbae9929430d116a246ef69866dad94da3bfbc/psutil-7.2.2-cp36-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:fd04ef36b4a6d599bbdb225dd1d3f51e00105f6d48a28f006da7f9822f2606d8", size = 148972, upload-time = "2026-01-28T18:15:29.342Z" }, + { url = "https://files.pythonhosted.org/packages/04/78/0acd37ca84ce3ddffaa92ef0f571e073faa6d8ff1f0559ab1272188ea2be/psutil-7.2.2-cp36-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:b58fabe35e80b264a4e3bb23e6b96f9e45a3df7fb7eed419ac0e5947c61e47cc", size = 148266, upload-time = "2026-01-28T18:15:31.597Z" }, + { url = "https://files.pythonhosted.org/packages/b4/90/e2159492b5426be0c1fef7acba807a03511f97c5f86b3caeda6ad92351a7/psutil-7.2.2-cp37-abi3-win_amd64.whl", hash = "sha256:eb7e81434c8d223ec4a219b5fc1c47d0417b12be7ea866e24fb5ad6e84b3d988", size = 137737, upload-time = "2026-01-28T18:15:33.849Z" }, + { url = "https://files.pythonhosted.org/packages/8c/c7/7bb2e321574b10df20cbde462a94e2b71d05f9bbda251ef27d104668306a/psutil-7.2.2-cp37-abi3-win_arm64.whl", hash = "sha256:8c233660f575a5a89e6d4cb65d9f938126312bca76d8fe087b947b3a1aaac9ee", size = 134617, upload-time = "2026-01-28T18:15:36.514Z" }, +] + +[[package]] +name = "pycparser" +version = "3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/1b/7d/92392ff7815c21062bea51aa7b87d45576f649f16458d78b7cf94b9ab2e6/pycparser-3.0.tar.gz", hash = "sha256:600f49d217304a5902ac3c37e1281c9fe94e4d0489de643a9504c5cdfdfc6b29", size = 103492, upload-time = "2026-01-21T14:26:51.89Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl", hash = "sha256:b727414169a36b7d524c1c3e31839a521725078d7b2ff038656844266160a992", size = 48172, upload-time = "2026-01-21T14:26:50.693Z" }, +] + +[[package]] +name = "pyyaml" +version = "6.0.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz", hash = "sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f", size = 130960, upload-time = "2025-09-25T21:33:16.546Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6d/16/a95b6757765b7b031c9374925bb718d55e0a9ba8a1b6a12d25962ea44347/pyyaml-6.0.3-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:44edc647873928551a01e7a563d7452ccdebee747728c1080d881d68af7b997e", size = 185826, upload-time = "2025-09-25T21:31:58.655Z" }, + { url = "https://files.pythonhosted.org/packages/16/19/13de8e4377ed53079ee996e1ab0a9c33ec2faf808a4647b7b4c0d46dd239/pyyaml-6.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:652cb6edd41e718550aad172851962662ff2681490a8a711af6a4d288dd96824", size = 175577, upload-time = "2025-09-25T21:32:00.088Z" }, + { url = "https://files.pythonhosted.org/packages/0c/62/d2eb46264d4b157dae1275b573017abec435397aa59cbcdab6fc978a8af4/pyyaml-6.0.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:10892704fc220243f5305762e276552a0395f7beb4dbf9b14ec8fd43b57f126c", size = 775556, upload-time = "2025-09-25T21:32:01.31Z" }, + { url = "https://files.pythonhosted.org/packages/10/cb/16c3f2cf3266edd25aaa00d6c4350381c8b012ed6f5276675b9eba8d9ff4/pyyaml-6.0.3-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:850774a7879607d3a6f50d36d04f00ee69e7fc816450e5f7e58d7f17f1ae5c00", size = 882114, upload-time = "2025-09-25T21:32:03.376Z" }, + { url = "https://files.pythonhosted.org/packages/71/60/917329f640924b18ff085ab889a11c763e0b573da888e8404ff486657602/pyyaml-6.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b8bb0864c5a28024fac8a632c443c87c5aa6f215c0b126c449ae1a150412f31d", size = 806638, upload-time = "2025-09-25T21:32:04.553Z" }, + { url = "https://files.pythonhosted.org/packages/dd/6f/529b0f316a9fd167281a6c3826b5583e6192dba792dd55e3203d3f8e655a/pyyaml-6.0.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1d37d57ad971609cf3c53ba6a7e365e40660e3be0e5175fa9f2365a379d6095a", size = 767463, upload-time = "2025-09-25T21:32:06.152Z" }, + { url = "https://files.pythonhosted.org/packages/f2/6a/b627b4e0c1dd03718543519ffb2f1deea4a1e6d42fbab8021936a4d22589/pyyaml-6.0.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:37503bfbfc9d2c40b344d06b2199cf0e96e97957ab1c1b546fd4f87e53e5d3e4", size = 794986, upload-time = "2025-09-25T21:32:07.367Z" }, + { url = "https://files.pythonhosted.org/packages/45/91/47a6e1c42d9ee337c4839208f30d9f09caa9f720ec7582917b264defc875/pyyaml-6.0.3-cp311-cp311-win32.whl", hash = "sha256:8098f252adfa6c80ab48096053f512f2321f0b998f98150cea9bd23d83e1467b", size = 142543, upload-time = "2025-09-25T21:32:08.95Z" }, + { url = "https://files.pythonhosted.org/packages/da/e3/ea007450a105ae919a72393cb06f122f288ef60bba2dc64b26e2646fa315/pyyaml-6.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:9f3bfb4965eb874431221a3ff3fdcddc7e74e3b07799e0e84ca4a0f867d449bf", size = 158763, upload-time = "2025-09-25T21:32:09.96Z" }, + { url = "https://files.pythonhosted.org/packages/d1/33/422b98d2195232ca1826284a76852ad5a86fe23e31b009c9886b2d0fb8b2/pyyaml-6.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7f047e29dcae44602496db43be01ad42fc6f1cc0d8cd6c83d342306c32270196", size = 182063, upload-time = "2025-09-25T21:32:11.445Z" }, + { url = "https://files.pythonhosted.org/packages/89/a0/6cf41a19a1f2f3feab0e9c0b74134aa2ce6849093d5517a0c550fe37a648/pyyaml-6.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fc09d0aa354569bc501d4e787133afc08552722d3ab34836a80547331bb5d4a0", size = 173973, upload-time = "2025-09-25T21:32:12.492Z" }, + { url = "https://files.pythonhosted.org/packages/ed/23/7a778b6bd0b9a8039df8b1b1d80e2e2ad78aa04171592c8a5c43a56a6af4/pyyaml-6.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9149cad251584d5fb4981be1ecde53a1ca46c891a79788c0df828d2f166bda28", size = 775116, upload-time = "2025-09-25T21:32:13.652Z" }, + { url = "https://files.pythonhosted.org/packages/65/30/d7353c338e12baef4ecc1b09e877c1970bd3382789c159b4f89d6a70dc09/pyyaml-6.0.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5fdec68f91a0c6739b380c83b951e2c72ac0197ace422360e6d5a959d8d97b2c", size = 844011, upload-time = "2025-09-25T21:32:15.21Z" }, + { url = "https://files.pythonhosted.org/packages/8b/9d/b3589d3877982d4f2329302ef98a8026e7f4443c765c46cfecc8858c6b4b/pyyaml-6.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ba1cc08a7ccde2d2ec775841541641e4548226580ab850948cbfda66a1befcdc", size = 807870, upload-time = "2025-09-25T21:32:16.431Z" }, + { url = "https://files.pythonhosted.org/packages/05/c0/b3be26a015601b822b97d9149ff8cb5ead58c66f981e04fedf4e762f4bd4/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8dc52c23056b9ddd46818a57b78404882310fb473d63f17b07d5c40421e47f8e", size = 761089, upload-time = "2025-09-25T21:32:17.56Z" }, + { url = "https://files.pythonhosted.org/packages/be/8e/98435a21d1d4b46590d5459a22d88128103f8da4c2d4cb8f14f2a96504e1/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:41715c910c881bc081f1e8872880d3c650acf13dfa8214bad49ed4cede7c34ea", size = 790181, upload-time = "2025-09-25T21:32:18.834Z" }, + { url = "https://files.pythonhosted.org/packages/74/93/7baea19427dcfbe1e5a372d81473250b379f04b1bd3c4c5ff825e2327202/pyyaml-6.0.3-cp312-cp312-win32.whl", hash = "sha256:96b533f0e99f6579b3d4d4995707cf36df9100d67e0c8303a0c55b27b5f99bc5", size = 137658, upload-time = "2025-09-25T21:32:20.209Z" }, + { url = "https://files.pythonhosted.org/packages/86/bf/899e81e4cce32febab4fb42bb97dcdf66bc135272882d1987881a4b519e9/pyyaml-6.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:5fcd34e47f6e0b794d17de1b4ff496c00986e1c83f7ab2fb8fcfe9616ff7477b", size = 154003, upload-time = "2025-09-25T21:32:21.167Z" }, + { url = "https://files.pythonhosted.org/packages/1a/08/67bd04656199bbb51dbed1439b7f27601dfb576fb864099c7ef0c3e55531/pyyaml-6.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:64386e5e707d03a7e172c0701abfb7e10f0fb753ee1d773128192742712a98fd", size = 140344, upload-time = "2025-09-25T21:32:22.617Z" }, +] + +[[package]] +name = "regex" +version = "2026.5.9" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/dc/0e/49aee608ad09480e7fd276898c99ec6192985fa331abe4eb3a986094490b/regex-2026.5.9.tar.gz", hash = "sha256:a8234aa23ec39894bfe4a3f1b85616a7032481964a13ac6fc9f10de4f6fca270", size = 416074, upload-time = "2026-05-09T23:15:19.37Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c2/dc/c1f2df4027e82fc54b5a473e4b250f5139faca49a0fbe29a48668d228f34/regex-2026.5.9-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:ccf5249114cc3e772ecdd88a98a86eca0fd74c61ce32a94743758c083fc05d48", size = 489445, upload-time = "2026-05-09T23:12:06.111Z" }, + { url = "https://files.pythonhosted.org/packages/03/d2/59f01110660081cce9c0bc30ebd0b5ee250dacf658e3248ed92f01e0e8ee/regex-2026.5.9-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:46f1326ca6e65b0879d23ca302c0f2415aad42ff0309b9c818e7949fe19a41d8", size = 291271, upload-time = "2026-05-09T23:12:07.731Z" }, + { url = "https://files.pythonhosted.org/packages/58/b6/14b2c84ff90ddb370c81d27503f4a0fcf071496416f4855f6cc8c5d81c35/regex-2026.5.9-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ef31cbfe458e21c6122ba8150ff060e0c7789ed0d26eb423f25472584920b555", size = 289212, upload-time = "2026-05-09T23:12:09.266Z" }, + { url = "https://files.pythonhosted.org/packages/03/d0/4db86529117320de0c84afd90e70bb47434625875e34fcef9d8c127c5b16/regex-2026.5.9-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:992604d02e6d9c6d786c24a706a71ecffe1020fc1ef264044474cd81fa2c3919", size = 792310, upload-time = "2026-05-09T23:12:11.416Z" }, + { url = "https://files.pythonhosted.org/packages/07/78/fe4800cd322f862ecffd2d553409b20d80650e5ed71b9d178f853d020b82/regex-2026.5.9-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c9411dd64ca95477225734a93dfc8583b51916b8d5942f99d6cac21e09965451", size = 861721, upload-time = "2026-05-09T23:12:13.681Z" }, + { url = "https://files.pythonhosted.org/packages/b5/d0/b3618a895dd8feb897c61bb2954edd265e1767d82a01d53065d5871127a3/regex-2026.5.9-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:3dd4a3ff360dfb836fecdb93a4598f9d6e2ac81e3e397125145c6221bf58cf4c", size = 906460, upload-time = "2026-05-09T23:12:15.443Z" }, + { url = "https://files.pythonhosted.org/packages/33/6f/1481597e859ef19508b345eec4afd1416ed6e6b459c75a64026ef193aecf/regex-2026.5.9-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2a661a7d270a61f7cf460caee8b9fa2d5ef9e5c681234bcb9e0fe14f488e7dfc", size = 799843, upload-time = "2026-05-09T23:12:16.892Z" }, + { url = "https://files.pythonhosted.org/packages/73/59/955734c803f59108deccba3597ae440c76b62a652733c0006e6243758420/regex-2026.5.9-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f079e50a0d3cc3cd5091fa9ff45869a2e6b2cd35895731edafb0327901a8d86d", size = 773610, upload-time = "2026-05-09T23:12:19.127Z" }, + { url = "https://files.pythonhosted.org/packages/68/8f/70c04a236d651c81881dac42ef8538bddda6121434509d0a22d9e601503b/regex-2026.5.9-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:4ebe8f0b5ec5a5024dc4a4c59f444c4e9afc5f2abdbb8962065b75d27fb971f9", size = 781645, upload-time = "2026-05-09T23:12:20.806Z" }, + { url = "https://files.pythonhosted.org/packages/1d/96/05c7434d88185e5d27fe54aeb74df86bd77cd79f52f0b4eae54faa8fea70/regex-2026.5.9-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:97cf3bc1b7d7d2306772ec07366c80d9df00ff79e79cea32898883a646d2fae2", size = 854473, upload-time = "2026-05-09T23:12:22.465Z" }, + { url = "https://files.pythonhosted.org/packages/4e/c1/6e3d8202d981f3117004bf341ee74893ba4ba8a9fbaf4b94615846550a08/regex-2026.5.9-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:0f9eede6a5cbdc02d4978090186390936e1776a7d1359b21e41014c609880bcf", size = 763311, upload-time = "2026-05-09T23:12:24.351Z" }, + { url = "https://files.pythonhosted.org/packages/93/c7/e7737f1526b3fb32bd4c337fd6c71c3ebb5c8296fc34d11197e0955d2e35/regex-2026.5.9-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:01f0f5f55f4b64dacec85dc116d3c05fd23ad3ff037bbc73a2085775953c2611", size = 844593, upload-time = "2026-05-09T23:12:26.341Z" }, + { url = "https://files.pythonhosted.org/packages/a5/27/0daffb1a535bb39f422c3d200f4ab023c71110ad66a32b366bee708baba0/regex-2026.5.9-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:1268eddd8486dc561d08eee1156e40aa3a8fe10f4bdec8fa653b455fcbffd12c", size = 789167, upload-time = "2026-05-09T23:12:27.975Z" }, + { url = "https://files.pythonhosted.org/packages/ce/fc/294fe4fac4f2ed67207b17471815870c1c45b3a489e08e0ac96daea16ef6/regex-2026.5.9-cp311-cp311-win32.whl", hash = "sha256:8676474c07469d6f33dd1085ca2cd45f65785f32518f2b20e36d9953ca07f994", size = 266249, upload-time = "2026-05-09T23:12:30.141Z" }, + { url = "https://files.pythonhosted.org/packages/d0/b0/8dce459f6245bcf8f6e9f23ac9569f1a0f15c131cc0745e82b43226204cf/regex-2026.5.9-cp311-cp311-win_amd64.whl", hash = "sha256:246de9d60aa3f8538b519834dd95cbf276ea263d6a7bd5a3666dc3fa0230505b", size = 278423, upload-time = "2026-05-09T23:12:31.676Z" }, + { url = "https://files.pythonhosted.org/packages/db/8d/f9aeff6ad63a3ef720386f2907e6d34a35a510a6e498ebad28b0fb3f6ab6/regex-2026.5.9-cp311-cp311-win_arm64.whl", hash = "sha256:d726ca3f0d76969bf1e8e477d160d3d666bbf999f6860bd314889e5345782046", size = 270420, upload-time = "2026-05-09T23:12:33.194Z" }, + { url = "https://files.pythonhosted.org/packages/50/9b/6550044bc44e17c84d312c031c2ec42fbdb6a4ec4e29093be3a172d08772/regex-2026.5.9-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:57eeeb05db7979413dec5438f2db21d7ecbba787cde7a711df1a6f6df672aa06", size = 490451, upload-time = "2026-05-09T23:12:34.72Z" }, + { url = "https://files.pythonhosted.org/packages/1e/95/fc7ba4303b5a0f92446a12ee6778ef2c6c799233f5060042a31bf390cfe9/regex-2026.5.9-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:398c521292f4c7fb807001dcd54694d3a1fcafc179a36ad9cc56f98df85930b6", size = 292112, upload-time = "2026-05-09T23:12:36.285Z" }, + { url = "https://files.pythonhosted.org/packages/54/4b/ee27938d1b2c443e89a9a10e00d2d19aa5ee300cd3d61140644e93bb083e/regex-2026.5.9-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f7a7c26137296beba7784de6eba69c6a93a63ccebc385e4962fe67e267a91225", size = 289599, upload-time = "2026-05-09T23:12:38.089Z" }, + { url = "https://files.pythonhosted.org/packages/d8/dd/ba103dc19614e25f3880800ca67ce093d6e21b325d72b8383c7bf906e9fa/regex-2026.5.9-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6441cc660d76107934a09c22167200839a0e89604a6297f78a974e66e931d2c0", size = 796732, upload-time = "2026-05-09T23:12:40.062Z" }, + { url = "https://files.pythonhosted.org/packages/cf/e7/f035b4fd858b050b0080bf302968dc0f59ba34e391872d54936758e6844e/regex-2026.5.9-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:91328f1c23d47595ca3ef0a7557fa129c5a23404b775c770697d2f35b33e0107", size = 865440, upload-time = "2026-05-09T23:12:42.059Z" }, + { url = "https://files.pythonhosted.org/packages/0a/51/8cd301ecc899aea28124357f729f4272f44de7806fc7ca02490bfbe253e8/regex-2026.5.9-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:93a7860539414dddaefba2b40f8771765ae17949d4c7182b876ce429e11a8309", size = 912329, upload-time = "2026-05-09T23:12:44.373Z" }, + { url = "https://files.pythonhosted.org/packages/cc/1e/3fbe2fa1e8cebd62f3bb7d3321cff1640aca2e240b51d9bd624aad949260/regex-2026.5.9-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:dd2810d22146b6d838acc5ec15602cb6b47920aa4e33015df3868eedfd20bab8", size = 801239, upload-time = "2026-05-09T23:12:46.268Z" }, + { url = "https://files.pythonhosted.org/packages/17/2f/6f6008682bf2cf98040a0d3153a8e557b6ab728d7713d045cee4ce544ab8/regex-2026.5.9-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:daff2bdbaf1d23e52fdff7c0b7bc2048b68f978df6a4d107ac981f94caef2e66", size = 777054, upload-time = "2026-05-09T23:12:48.051Z" }, + { url = "https://files.pythonhosted.org/packages/19/2b/eee0d20a6842ba04df4b8847a920b57ef56853f14ef85405473e586b605a/regex-2026.5.9-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:4eeb011098fcb77af513dcef521a3dbecbf8849b1e38940759d293b7a93f5026", size = 785098, upload-time = "2026-05-09T23:12:49.851Z" }, + { url = "https://files.pythonhosted.org/packages/4a/98/6fc1e6410feefb92159edaed5041992bfe390e8d26c721865434acbca558/regex-2026.5.9-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:ea9c8ecfa1b73c73b626534d6626e5340d429630943672b8480724f44e84b962", size = 860095, upload-time = "2026-05-09T23:12:51.666Z" }, + { url = "https://files.pythonhosted.org/packages/18/a3/bd855e0f2cb1a978ecf6fa6bb69632dd9c3f6ea3b81cde62fde14c9daec7/regex-2026.5.9-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:cd2846168eb9ee3c513902bc8225409cb1caab31d04728b145171fa1625d9621", size = 765762, upload-time = "2026-05-09T23:12:53.413Z" }, + { url = "https://files.pythonhosted.org/packages/dc/66/0ae8c092e60b14c79d24f8e0b7f0aea5bfbffdcab00b5483d13404d3c3a5/regex-2026.5.9-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:39617fb0cde9c0e6306dc70e3bfc096f3da793219879f7ae7aa341a69fbdcf6d", size = 852100, upload-time = "2026-05-09T23:12:55.256Z" }, + { url = "https://files.pythonhosted.org/packages/21/de/8dfde60fc1b21c946a893ba273403b72617edb261370cb1087099a83f088/regex-2026.5.9-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fd03c4f0e33280d15cae17159b899245d6b7c53d21def19b263b39655061f5ce", size = 789479, upload-time = "2026-05-09T23:12:57.573Z" }, + { url = "https://files.pythonhosted.org/packages/c3/1c/bdcc98f9a4af4fdd166c74941174619ccff4726d3ce32faa8e9a2ecd38dd/regex-2026.5.9-cp312-cp312-win32.whl", hash = "sha256:164eba9b755ea6f244b0d881196fbc1fac09714e9782c9e2732b813142033c8e", size = 266699, upload-time = "2026-05-09T23:12:59.14Z" }, + { url = "https://files.pythonhosted.org/packages/78/87/240d36864f9e48ace85f72e79ced97ceb7f27ce87739a947dcb834b4e6bc/regex-2026.5.9-cp312-cp312-win_amd64.whl", hash = "sha256:86f40a5d6444db30a125c9c9177e6b25dad981cbc37451fd838f145e6edac92e", size = 277783, upload-time = "2026-05-09T23:13:00.789Z" }, + { url = "https://files.pythonhosted.org/packages/4f/b5/7b30f312b0669dff5beebe5b0989dc2d1a312b1a44fab852199c387a5b96/regex-2026.5.9-cp312-cp312-win_arm64.whl", hash = "sha256:96f5f58b54a063d7ea9dca08e1cf57bfe10499c4d579ee672da284f57f5f0070", size = 270513, upload-time = "2026-05-09T23:13:02.426Z" }, +] + +[[package]] +name = "requests" +version = "2.34.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "certifi" }, + { name = "charset-normalizer" }, + { name = "idna" }, + { name = "urllib3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ac/c3/e2a2b89f2d3e2179abd6d00ebd70bff6273f37fb3e0cc209f48b39d00cbf/requests-2.34.2.tar.gz", hash = "sha256:f288924cae4e29463698d6d60bc6a4da69c89185ad1e0bcc4104f584e960b9ed", size = 142856, upload-time = "2026-05-14T19:25:27.735Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl", hash = "sha256:2a0d60c172f83ac6ab31e4554906c0f3b3588d37b5cb939b1c061f4907e278e0", size = 73075, upload-time = "2026-05-14T19:25:26.443Z" }, +] + +[[package]] +name = "safetensors" +version = "0.8.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/45/06/f955dbbb1859e3bd23c8ac6141af5106e7ad5fedec4a3a6e3d60f94b7001/safetensors-0.8.0.tar.gz", hash = "sha256:fabaf3e0f18a6618d9b36560682562157f77c2b71fcffc7b432be2baed9d753d", size = 325846, upload-time = "2026-06-09T07:52:25.563Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/39/a0/f718cda65b05407d228f97602cf60dca269c979867aa5beb25410de26cd3/safetensors-0.8.0-cp310-abi3-macosx_10_12_x86_64.whl", hash = "sha256:c554f85858e05226d3c2828e32395e677434685d6d94594a41643361c5e837f0", size = 473568, upload-time = "2026-06-09T07:52:18.829Z" }, + { url = "https://files.pythonhosted.org/packages/f5/b1/fa7c600e7dceae12e9606c7578cbc9ff1e1ed55844883ee5c92205e86226/safetensors-0.8.0-cp310-abi3-macosx_11_0_arm64.whl", hash = "sha256:c80201d22cbf405b80647a60ada77bba06c8fba2da2743ba1e89cdcc39a81f25", size = 484562, upload-time = "2026-06-09T07:52:17.518Z" }, + { url = "https://files.pythonhosted.org/packages/09/7d/65a7de0af421317bb36a067241e4235fff194eed60b961ed6d3f59a3fc60/safetensors-0.8.0-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7a46e5ff292c356d6991e60942ba7f79817682d3a2cef0702136448cb9c4d235", size = 502844, upload-time = "2026-06-09T07:52:07.624Z" }, + { url = "https://files.pythonhosted.org/packages/91/4f/3175c9d75634e0e0dda0082794193521035edd7c70a6f212bf33ca06ddf4/safetensors-0.8.0-cp310-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4124502b78f03534117c848f87a39b8f31e577b15eff423bf8bfb95f2a8c30d0", size = 511823, upload-time = "2026-06-09T07:52:09.565Z" }, + { url = "https://files.pythonhosted.org/packages/20/87/846c289e7aa2299eff406335717cf43ce8777194ece8aad75772e0411615/safetensors-0.8.0-cp310-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7bc0a787ba8a35be368ee3574edfa2b1ad389eebd0a72e482ae275490e3f6c98", size = 633461, upload-time = "2026-06-09T07:52:11.128Z" }, + { url = "https://files.pythonhosted.org/packages/76/22/8d64d9df2c45d5ded401df889d0ad90882804ca172d79ec4f0df8f727fe0/safetensors-0.8.0-cp310-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:040070828e36dc8e122178bbbd5830ff9e97920affb84cbe0f46442497bed358", size = 545148, upload-time = "2026-06-09T07:52:13.603Z" }, + { url = "https://files.pythonhosted.org/packages/28/50/f203ff3a3ddfe19308efc83c5a3a29ed02bf786732ec35e68bf9162f3365/safetensors-0.8.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd6f3f93c9a0a7cc2788ee63fb763353d4bd2e89b0751bc78fcf7dda00bea774", size = 516040, upload-time = "2026-06-09T07:52:16.29Z" }, + { url = "https://files.pythonhosted.org/packages/46/fb/cdaed17ceb2948784fd9c36b6fd3e951b608547cea81a48e8ee6f8cfdfcb/safetensors-0.8.0-cp310-abi3-manylinux_2_31_riscv64.whl", hash = "sha256:fcdd41ec4628fee5799f807c73c353629130fbd942aa23d83c623dd6c9d52d78", size = 513832, upload-time = "2026-06-09T07:52:12.37Z" }, + { url = "https://files.pythonhosted.org/packages/0d/49/1e15de264dcc3b77943d2d0c56a95809956883b1c2d6d585c792523f180b/safetensors-0.8.0-cp310-abi3-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8e9f537aa183a38ace122d27303dcd986b26bd2a7591f9181d7f0c396f4677ca", size = 559930, upload-time = "2026-06-09T07:52:14.743Z" }, + { url = "https://files.pythonhosted.org/packages/2a/43/bf38443278eab4b1be1fce2931e2b012ad9cb7df52ada751d0aab8f7659a/safetensors-0.8.0-cp310-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:87eec7ffed2b809f05a398a8becb7d013f19f7837cd15d9748580d6cf30dbaf4", size = 678670, upload-time = "2026-06-09T07:52:20.032Z" }, + { url = "https://files.pythonhosted.org/packages/72/e3/68cd3fa5b48488e84add63e04cb12f3bc28ae4638c06d4508c6e88823d0e/safetensors-0.8.0-cp310-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:4a95ae2b05d7726d751da4ebf626a2ca782b706e101bd894c95bc2450b1cffcc", size = 786679, upload-time = "2026-06-09T07:52:21.322Z" }, + { url = "https://files.pythonhosted.org/packages/29/4b/1c19c509d56e01f4fbb3d0a2e597450f6cc04d1d56cf52defb0a62dfd715/safetensors-0.8.0-cp310-abi3-musllinux_1_2_i686.whl", hash = "sha256:3ae091f16662658bdc019a4ff6cb4c085bb7d725eb5978b183ffd265863b6d2d", size = 765683, upload-time = "2026-06-09T07:52:22.594Z" }, + { url = "https://files.pythonhosted.org/packages/27/43/41c1621732edd934d868a00d1b891584c892a7b62a9aab82ea5a0a5623ee/safetensors-0.8.0-cp310-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:8e080062fcde23be189565e1c3305d16751a218ecf9412c8601e64204eb6f846", size = 722361, upload-time = "2026-06-09T07:52:23.924Z" }, + { url = "https://files.pythonhosted.org/packages/8e/3f/73ccf82579412b4a71c4ca673f10b5f1f888d7cf5af7fe24f27d30307be4/safetensors-0.8.0-cp310-abi3-win32.whl", hash = "sha256:2ddf52eac562eda224f99acfa7889d02968c1fd59a5b011ae7d8137c37e9c02d", size = 342401, upload-time = "2026-06-09T07:52:28.895Z" }, + { url = "https://files.pythonhosted.org/packages/1b/6d/3fba214c1e5e0f69991677ec3bc17023f0421776975e1de0c682dca475e2/safetensors-0.8.0-cp310-abi3-win_amd64.whl", hash = "sha256:096ec1a98435df7beb08853bb5aa9081a84f23d0adc67ed1a0a10550f608373f", size = 355540, upload-time = "2026-06-09T07:52:27.832Z" }, + { url = "https://files.pythonhosted.org/packages/8d/fc/7eedc3510d97878876e32774eebbeb61c43f148a96e915c84229a3e967aa/safetensors-0.8.0-cp310-abi3-win_arm64.whl", hash = "sha256:f7838e5135a406ad3e02efdcb8cf2e5397d368b0154537c4fec682dbc544d452", size = 340500, upload-time = "2026-06-09T07:52:26.745Z" }, +] + +[[package]] +name = "scikit-learn" +version = "1.9.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "joblib" }, + { name = "narwhals" }, + { name = "numpy" }, + { name = "scipy", version = "1.17.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.12'" }, + { name = "scipy", version = "1.18.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" }, + { name = "threadpoolctl" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/fa/6f/37092bdb25f712817231799fc5674d8e704066a8a70c1d2d40517e18b4ab/scikit_learn-1.9.0.tar.gz", hash = "sha256:8833266989d3a5110178a9fae30783675460724d0e1efb13b14901d2c660c557", size = 7750767, upload-time = "2026-06-02T11:54:32.706Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f5/be/e844fd9586e66540a15b71924d17a6cbc1bb749e81ddd0a796bcdba4c055/scikit_learn-1.9.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:9db6f4d34e68c8899e4cab27fdf8eafe6ed21f2ba52ceb25ea250cd237f8e47b", size = 8789686, upload-time = "2026-06-02T11:53:05.439Z" }, + { url = "https://files.pythonhosted.org/packages/42/e2/ff880f62677a17d035817d543cb0fc8727d01eccbee81c5f7fc733a9d856/scikit_learn-1.9.0-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:f401448645a3e7bc115aa3c094097865155b34bff1cba8101857d9104e99074c", size = 8256782, upload-time = "2026-06-02T11:53:08.904Z" }, + { url = "https://files.pythonhosted.org/packages/25/64/eb40435e1a508ab1b4e284ce43ae80f6a162e5be5e38ed5a6fab467a9ea4/scikit_learn-1.9.0-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:fd3a8ef0c758555a3b23c03adaa858af32f7736785ded50ad5991f59c4ed03fa", size = 8992419, upload-time = "2026-06-02T11:53:11.551Z" }, + { url = "https://files.pythonhosted.org/packages/8d/da/4810a28e473185429e45a57eebcc91fc991b33d889cc0676063e671db03d/scikit_learn-1.9.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f7e254636164090da847715a27f8e5478feb98c40a9e0ee90cbd277de9e5ceb8", size = 9281411, upload-time = "2026-06-02T11:53:15.063Z" }, + { url = "https://files.pythonhosted.org/packages/3b/67/be3d369f40d8178ba3bd86635d132e08cb5329b023e4669d9426d84bc007/scikit_learn-1.9.0-cp311-cp311-win_amd64.whl", hash = "sha256:5dc1818c77575d149e25fce9ef82dd7b7263ae372f03494158668ad632a69759", size = 8272736, upload-time = "2026-06-02T11:53:18.108Z" }, + { url = "https://files.pythonhosted.org/packages/37/79/a733f02dc2118da7e77a134b34f39f40201a353311b011d20859d2db3556/scikit_learn-1.9.0-cp311-cp311-win_arm64.whl", hash = "sha256:366652351f092b219c248f1e72821e841960a63d8f358f1dcfd54dc1cbdbbc28", size = 7919564, upload-time = "2026-06-02T11:53:21.2Z" }, + { url = "https://files.pythonhosted.org/packages/ac/20/75f915ff375d6249e6550ac740fdbbd66159a068fd3af1400ff62036b07a/scikit_learn-1.9.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:2bd41b0d201bc81575531b96b713d3eb5e5f50fb0b82101ff0f92294fdc236ac", size = 8741122, upload-time = "2026-06-02T11:53:24.08Z" }, + { url = "https://files.pythonhosted.org/packages/cc/d5/2b5148f2279196775e1db2aeb85d14b70ac80e7e32b3b28e7ebeafb0901d/scikit_learn-1.9.0-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:5be45aa4a42a68a533913a6ed736cf309de2226411c79ef8d609a5456f1939b1", size = 8261512, upload-time = "2026-06-02T11:53:27.183Z" }, + { url = "https://files.pythonhosted.org/packages/a0/ee/5adbc77656b71f9456a2f5a7a9fdb4bcf9207a6b962889f1c2f9323afa4e/scikit_learn-1.9.0-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5e50ed4da51974e86e940690e9a3d82e729b62b5a49f7c9bac534d515d39d86f", size = 8837603, upload-time = "2026-06-02T11:53:30.328Z" }, + { url = "https://files.pythonhosted.org/packages/6c/c2/63fdda36c56437eeb44aaf9493c8bcd62ce230ab1598924fc626ffbfa943/scikit_learn-1.9.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:056c92bb67ad4c28463c2f2653d9701449201e7e7a9e94e321be0f71c4fef2b8", size = 9132097, upload-time = "2026-06-02T11:53:33.456Z" }, + { url = "https://files.pythonhosted.org/packages/83/a4/c8e67227c680e2259c8864ae72ff48b06e16a6f51253a22167aa02a8aa4e/scikit_learn-1.9.0-cp312-cp312-win_amd64.whl", hash = "sha256:4306775fad04cc4b472a1b15af1ae9cede1540fbfcc17fbce3767cd8dc7ae283", size = 8211173, upload-time = "2026-06-02T11:53:36.602Z" }, + { url = "https://files.pythonhosted.org/packages/cf/fd/3c0863792e98e67e9184aa4029288a175935eb65443afcd30d4f143450cf/scikit_learn-1.9.0-cp312-cp312-win_arm64.whl", hash = "sha256:26e22435f63bcdcf396b574273f29f13dd531f5ea035801f5be10ba1540a4e60", size = 7867451, upload-time = "2026-06-02T11:53:39.075Z" }, +] + +[[package]] +name = "scipy" +version = "1.17.1" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version < '3.12'", +] +dependencies = [ + { name = "numpy", marker = "python_full_version < '3.12'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/7a/97/5a3609c4f8d58b039179648e62dd220f89864f56f7357f5d4f45c29eb2cc/scipy-1.17.1.tar.gz", hash = "sha256:95d8e012d8cb8816c226aef832200b1d45109ed4464303e997c5b13122b297c0", size = 30573822, upload-time = "2026-02-23T00:26:24.851Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/df/75/b4ce781849931fef6fd529afa6b63711d5a733065722d0c3e2724af9e40a/scipy-1.17.1-cp311-cp311-macosx_10_14_x86_64.whl", hash = "sha256:1f95b894f13729334fb990162e911c9e5dc1ab390c58aa6cbecb389c5b5e28ec", size = 31613675, upload-time = "2026-02-23T00:16:00.13Z" }, + { url = "https://files.pythonhosted.org/packages/f7/58/bccc2861b305abdd1b8663d6130c0b3d7cc22e8d86663edbc8401bfd40d4/scipy-1.17.1-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:e18f12c6b0bc5a592ed23d3f7b891f68fd7f8241d69b7883769eb5d5dfb52696", size = 28162057, upload-time = "2026-02-23T00:16:09.456Z" }, + { url = "https://files.pythonhosted.org/packages/6d/ee/18146b7757ed4976276b9c9819108adbc73c5aad636e5353e20746b73069/scipy-1.17.1-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:a3472cfbca0a54177d0faa68f697d8ba4c80bbdc19908c3465556d9f7efce9ee", size = 20334032, upload-time = "2026-02-23T00:16:17.358Z" }, + { url = "https://files.pythonhosted.org/packages/ec/e6/cef1cf3557f0c54954198554a10016b6a03b2ec9e22a4e1df734936bd99c/scipy-1.17.1-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:766e0dc5a616d026a3a1cffa379af959671729083882f50307e18175797b3dfd", size = 22709533, upload-time = "2026-02-23T00:16:25.791Z" }, + { url = "https://files.pythonhosted.org/packages/4d/60/8804678875fc59362b0fb759ab3ecce1f09c10a735680318ac30da8cd76b/scipy-1.17.1-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:744b2bf3640d907b79f3fd7874efe432d1cf171ee721243e350f55234b4cec4c", size = 33062057, upload-time = "2026-02-23T00:16:36.931Z" }, + { url = "https://files.pythonhosted.org/packages/09/7d/af933f0f6e0767995b4e2d705a0665e454d1c19402aa7e895de3951ebb04/scipy-1.17.1-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:43af8d1f3bea642559019edfe64e9b11192a8978efbd1539d7bc2aaa23d92de4", size = 35349300, upload-time = "2026-02-23T00:16:49.108Z" }, + { url = "https://files.pythonhosted.org/packages/b4/3d/7ccbbdcbb54c8fdc20d3b6930137c782a163fa626f0aef920349873421ba/scipy-1.17.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:cd96a1898c0a47be4520327e01f874acfd61fb48a9420f8aa9f6483412ffa444", size = 35127333, upload-time = "2026-02-23T00:17:01.293Z" }, + { url = "https://files.pythonhosted.org/packages/e8/19/f926cb11c42b15ba08e3a71e376d816ac08614f769b4f47e06c3580c836a/scipy-1.17.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:4eb6c25dd62ee8d5edf68a8e1c171dd71c292fdae95d8aeb3dd7d7de4c364082", size = 37741314, upload-time = "2026-02-23T00:17:12.576Z" }, + { url = "https://files.pythonhosted.org/packages/95/da/0d1df507cf574b3f224ccc3d45244c9a1d732c81dcb26b1e8a766ae271a8/scipy-1.17.1-cp311-cp311-win_amd64.whl", hash = "sha256:d30e57c72013c2a4fe441c2fcb8e77b14e152ad48b5464858e07e2ad9fbfceff", size = 36607512, upload-time = "2026-02-23T00:17:23.424Z" }, + { url = "https://files.pythonhosted.org/packages/68/7f/bdd79ceaad24b671543ffe0ef61ed8e659440eb683b66f033454dcee90eb/scipy-1.17.1-cp311-cp311-win_arm64.whl", hash = "sha256:9ecb4efb1cd6e8c4afea0daa91a87fbddbce1b99d2895d151596716c0b2e859d", size = 24599248, upload-time = "2026-02-23T00:17:34.561Z" }, + { url = "https://files.pythonhosted.org/packages/35/48/b992b488d6f299dbe3f11a20b24d3dda3d46f1a635ede1c46b5b17a7b163/scipy-1.17.1-cp312-cp312-macosx_10_14_x86_64.whl", hash = "sha256:35c3a56d2ef83efc372eaec584314bd0ef2e2f0d2adb21c55e6ad5b344c0dcb8", size = 31610954, upload-time = "2026-02-23T00:17:49.855Z" }, + { url = "https://files.pythonhosted.org/packages/b2/02/cf107b01494c19dc100f1d0b7ac3cc08666e96ba2d64db7626066cee895e/scipy-1.17.1-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:fcb310ddb270a06114bb64bbe53c94926b943f5b7f0842194d585c65eb4edd76", size = 28172662, upload-time = "2026-02-23T00:18:01.64Z" }, + { url = "https://files.pythonhosted.org/packages/cf/a9/599c28631bad314d219cf9ffd40e985b24d603fc8a2f4ccc5ae8419a535b/scipy-1.17.1-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:cc90d2e9c7e5c7f1a482c9875007c095c3194b1cfedca3c2f3291cdc2bc7c086", size = 20344366, upload-time = "2026-02-23T00:18:12.015Z" }, + { url = "https://files.pythonhosted.org/packages/35/f5/906eda513271c8deb5af284e5ef0206d17a96239af79f9fa0aebfe0e36b4/scipy-1.17.1-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:c80be5ede8f3f8eded4eff73cc99a25c388ce98e555b17d31da05287015ffa5b", size = 22704017, upload-time = "2026-02-23T00:18:21.502Z" }, + { url = "https://files.pythonhosted.org/packages/da/34/16f10e3042d2f1d6b66e0428308ab52224b6a23049cb2f5c1756f713815f/scipy-1.17.1-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e19ebea31758fac5893a2ac360fedd00116cbb7628e650842a6691ba7ca28a21", size = 32927842, upload-time = "2026-02-23T00:18:35.367Z" }, + { url = "https://files.pythonhosted.org/packages/01/8e/1e35281b8ab6d5d72ebe9911edcdffa3f36b04ed9d51dec6dd140396e220/scipy-1.17.1-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:02ae3b274fde71c5e92ac4d54bc06c42d80e399fec704383dcd99b301df37458", size = 35235890, upload-time = "2026-02-23T00:18:49.188Z" }, + { url = "https://files.pythonhosted.org/packages/c5/5c/9d7f4c88bea6e0d5a4f1bc0506a53a00e9fcb198de372bfe4d3652cef482/scipy-1.17.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8a604bae87c6195d8b1045eddece0514d041604b14f2727bbc2b3020172045eb", size = 35003557, upload-time = "2026-02-23T00:18:54.74Z" }, + { url = "https://files.pythonhosted.org/packages/65/94/7698add8f276dbab7a9de9fb6b0e02fc13ee61d51c7c3f85ac28b65e1239/scipy-1.17.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:f590cd684941912d10becc07325a3eeb77886fe981415660d9265c4c418d0bea", size = 37625856, upload-time = "2026-02-23T00:19:00.307Z" }, + { url = "https://files.pythonhosted.org/packages/a2/84/dc08d77fbf3d87d3ee27f6a0c6dcce1de5829a64f2eae85a0ecc1f0daa73/scipy-1.17.1-cp312-cp312-win_amd64.whl", hash = "sha256:41b71f4a3a4cab9d366cd9065b288efc4d4f3c0b37a91a8e0947fb5bd7f31d87", size = 36549682, upload-time = "2026-02-23T00:19:07.67Z" }, + { url = "https://files.pythonhosted.org/packages/bc/98/fe9ae9ffb3b54b62559f52dedaebe204b408db8109a8c66fdd04869e6424/scipy-1.17.1-cp312-cp312-win_arm64.whl", hash = "sha256:f4115102802df98b2b0db3cce5cb9b92572633a1197c77b7553e5203f284a5b3", size = 24547340, upload-time = "2026-02-23T00:19:12.024Z" }, +] + +[[package]] +name = "scipy" +version = "1.18.0" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.12'", +] +dependencies = [ + { name = "numpy", marker = "python_full_version >= '3.12'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a7/25/c2700dfaf6442b4effaa91af24ebce5dc9d31bb4a69706313aae70d72cd0/scipy-1.18.0.tar.gz", hash = "sha256:67b2ad2ad54c72ca6d04975a9b2df8c3638c34ddd5b28738e94fc2b57929d378", size = 30774447, upload-time = "2026-06-19T15:01:43.456Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6a/19/ca10ead60b0acc80b2b833c2c4a4f2ff753d0f58b811f70d911c7e94a25c/scipy-1.18.0-cp312-cp312-macosx_10_15_x86_64.whl", hash = "sha256:7bd21faaf5a1a3b2eff922d02db5f191b99a6518db9078a8fb23169f6d22259a", size = 31056519, upload-time = "2026-06-19T14:59:45.203Z" }, + { url = "https://files.pythonhosted.org/packages/96/72/1e6442a00cd2924d361aa1b642ab6373ec35c6fabf311a760be9f76e0f13/scipy-1.18.0-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:265915e79107de9f946b855e50d7470d5893ec3f54b342e1aa6201cbdcd8bb6b", size = 28681889, upload-time = "2026-06-19T14:59:48.103Z" }, + { url = "https://files.pythonhosted.org/packages/9b/2d/11dd93d21e147a73ba22bd75c0b9208d3a2e0ec76d53170ce7d9029b1015/scipy-1.18.0-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:9ab7b758be6940954a713ee466e2043e9f6e2ed965c1fce5c91039f4be3d90a9", size = 20423580, upload-time = "2026-06-19T14:59:50.665Z" }, + { url = "https://files.pythonhosted.org/packages/9c/01/93552f75e0d2a7dd115a45e59209c51e8d514daff02fc887d2623be06fe1/scipy-1.18.0-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:97b6cddaaee0a779ef6b5ca83c9604b27cc16b2b8fc22c142652df8793319fb8", size = 23054441, upload-time = "2026-06-19T14:59:53.564Z" }, + { url = "https://files.pythonhosted.org/packages/3c/23/21f5e703643d66f21faa6b4c73195bfcad70c55efcb4f1ab327cd7c4101a/scipy-1.18.0-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:52a96e21517c7292375c0e27dd796a811f03fcea5fd4d108fdfea8145dcf17ab", size = 33968720, upload-time = "2026-06-19T14:59:56.415Z" }, + { url = "https://files.pythonhosted.org/packages/dd/aa/1b939f6c67ed68635bb538e6752d3dacc02f66535182e939a89581a44e9c/scipy-1.18.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1f55797419e16e7f30cf88ffb3113ce0467f00cfe3f70d5c281730b21769bfc2", size = 35287115, upload-time = "2026-06-19T14:59:59.411Z" }, + { url = "https://files.pythonhosted.org/packages/b6/ff/eec46be7e9234208f801062b53e1983085eddebd693f6c9bfb03b459830d/scipy-1.18.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ad033410e2e0672ffdc1042110cef20e1c46f8fd0616cee1d44d8d58fad8fc11", size = 35577989, upload-time = "2026-06-19T15:00:02.235Z" }, + { url = "https://files.pythonhosted.org/packages/84/ca/210d4759c7210bb7d269437421959b39a33434e2776b60c5cb8a763bb30a/scipy-1.18.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:4a55985d54c769c872e64b7f4c8a81cc30ef700cc04296abbbf3705439c126de", size = 37421717, upload-time = "2026-06-19T15:00:05.102Z" }, + { url = "https://files.pythonhosted.org/packages/2b/54/9a9edb45345bd6744da5ddfb6628e5d5185920494c6a67ec45b6381004cb/scipy-1.18.0-cp312-cp312-win_amd64.whl", hash = "sha256:71ccc8faa2dd16ac310233203474a8b5cb67f10dedd54a3116d34943f4b19132", size = 36597428, upload-time = "2026-06-19T15:00:08.112Z" }, + { url = "https://files.pythonhosted.org/packages/99/0e/33f32a2a58987e26aec0f7df252cbbad1e90ae77bdbc76f40dd4ed0cf0ea/scipy-1.18.0-cp312-cp312-win_arm64.whl", hash = "sha256:d88363fd9d8fbd3511bd273f1a49efb2a540773ddf92a91d57498ce7dd7f3e76", size = 24351481, upload-time = "2026-06-19T15:00:11.103Z" }, +] + +[[package]] +name = "setuptools" +version = "81.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/0d/1c/73e719955c59b8e424d015ab450f51c0af856ae46ea2da83eba51cc88de1/setuptools-81.0.0.tar.gz", hash = "sha256:487b53915f52501f0a79ccfd0c02c165ffe06631443a886740b91af4b7a5845a", size = 1198299, upload-time = "2026-02-06T21:10:39.601Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e1/e3/c164c88b2e5ce7b24d667b9bd83589cf4f3520d97cad01534cd3c4f55fdb/setuptools-81.0.0-py3-none-any.whl", hash = "sha256:fdd925d5c5d9f62e4b74b30d6dd7828ce236fd6ed998a08d81de62ce5a6310d6", size = 1062021, upload-time = "2026-02-06T21:10:37.175Z" }, +] + +[[package]] +name = "soundfile" +version = "0.14.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cffi" }, + { name = "numpy" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/d2/db/949331952a6fb1c5b12e9de80fd08747966c2039d1a61db4764fbd3981c2/soundfile-0.14.0.tar.gz", hash = "sha256:ba1c1a2d618bca5c406647c83b89f07cc8810fa506a50622a6993ba130c1de11", size = 47842, upload-time = "2026-06-06T08:58:47.869Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b1/d1/5e338af9ca6ed0786cd5bb03f6d60de1c325728c1189014f3b59aae7403c/soundfile-0.14.0-py2.py3-none-any.whl", hash = "sha256:8ba81ae3a89fd5ab3bef8a8eb481fbbe794e806309675a89b4df48b8d31908a8", size = 26799, upload-time = "2026-06-06T08:58:33.269Z" }, + { url = "https://files.pythonhosted.org/packages/7e/72/c6b21e58d3113596e7e8de0a08d6f1d95173492cfbca0a4db14148cbba2a/soundfile-0.14.0-py2.py3-none-macosx_10_9_x86_64.whl", hash = "sha256:19be05428da76ed61a4cad29b8e4bcf43a3e5c100089d2ec81dc961eed1b0dd4", size = 1144568, upload-time = "2026-06-06T08:58:35.231Z" }, + { url = "https://files.pythonhosted.org/packages/63/7a/dfdd6f8c748988427119f75eb860a3cedd858d1aea1fe28f39ad8559ef22/soundfile-0.14.0-py2.py3-none-macosx_11_0_arm64.whl", hash = "sha256:d828d35a059626da52f1415b5faee610aeab393319cb3fc4a9aef47b619fc14c", size = 1103726, upload-time = "2026-06-06T08:58:37.948Z" }, + { url = "https://files.pythonhosted.org/packages/4a/f8/fc39fad6f879633461d27394cd1ddaf1f769ffa0597dca35872f51b16461/soundfile-0.14.0-py2.py3-none-manylinux_2_28_aarch64.whl", hash = "sha256:e85724a90bc99a6e8062c0b4ddf725f53b2a3b70afd4da875e9d2cfc4e92f377", size = 1238050, upload-time = "2026-06-06T08:58:39.932Z" }, + { url = "https://files.pythonhosted.org/packages/7b/a2/70fd4432b924684c372df8b0a45708c36c057ef3596c9eb53e0a806b980b/soundfile-0.14.0-py2.py3-none-manylinux_2_28_x86_64.whl", hash = "sha256:1e38bac1853412871318e82a1ba69a8be677619b56025bbfcccdb41b6cafe82d", size = 1315963, upload-time = "2026-06-06T08:58:41.716Z" }, + { url = "https://files.pythonhosted.org/packages/d9/34/c9e80783d83eab739a9531fdee03675d53e0bf1b2ccb4bb3af5844675046/soundfile-0.14.0-py2.py3-none-win32.whl", hash = "sha256:0a6ae43c50c71b4e020cc55382925cb89451c1ed1a0c3d0f5d802da269226849", size = 902199, upload-time = "2026-06-06T08:58:43.289Z" }, + { url = "https://files.pythonhosted.org/packages/ed/97/b39c18ac1df45e755ca22b8b00e872929da5d107998a207a5e4ac831bfda/soundfile-0.14.0-py2.py3-none-win_amd64.whl", hash = "sha256:299491d3499460fb1b74bb4bd78b57ffc2d243a5fafa7b6ec1b264875c78453e", size = 1021480, upload-time = "2026-06-06T08:58:45.016Z" }, + { url = "https://files.pythonhosted.org/packages/f4/83/55c65e61cf457805ce2ec157c1c6ae17715d0851aa2374422de0538838ca/soundfile-0.14.0-py2.py3-none-win_arm64.whl", hash = "sha256:e090704718e124e7c844695236f1fce8d18a5e761eaf7c82dfcd124620805f98", size = 888858, upload-time = "2026-06-06T08:58:46.593Z" }, +] + +[[package]] +name = "soxr" +version = "1.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ed/11/27cebce4a108f77afea7c80545115536b45e3f11ebfb914f638fdd9ba847/soxr-1.1.0.tar.gz", hash = "sha256:9f228ae21c78fa9359ca98d8a5e8e91f30639e438e574133dace62c5b5309e44", size = 173067, upload-time = "2026-05-03T00:15:18.214Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8e/49/3e6bc84f87439f222f40b616e9a29a170f41fb564710ea510df19dc26907/soxr-1.1.0-cp311-cp311-macosx_10_14_x86_64.whl", hash = "sha256:34cc92208c3c412c046813e69da639c04a792c6a41fbfd7d909d359cd3e97a2d", size = 205699, upload-time = "2026-05-03T00:14:46.67Z" }, + { url = "https://files.pythonhosted.org/packages/2f/94/216f46096a85b07d1e6ba7fd44491402e912a3d688cd4f36f0a600ca155f/soxr-1.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:bd30f7201eac896ebf5db7b09156e6f1a1b82601900d29d9c8449bdad8365b11", size = 167381, upload-time = "2026-05-03T00:14:48.012Z" }, + { url = "https://files.pythonhosted.org/packages/94/cb/06caa463b8181ec1981bd6376d4a873748b7008193188b8cfb60391eb131/soxr-1.1.0-cp311-cp311-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1577865e993f98ffb261257c3060fa76ec3db44ed3f181b16464268000424464", size = 210938, upload-time = "2026-05-03T00:14:49.768Z" }, + { url = "https://files.pythonhosted.org/packages/86/47/d5964551ca818b7f0c7ef7f3899056263b60ef098a801066350a9672ca8f/soxr-1.1.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3da87e3ffa3e41823d873b051c7ecb2acebd8d1b6b46b752f5facf10a0d84ab9", size = 245268, upload-time = "2026-05-03T00:14:51.422Z" }, + { url = "https://files.pythonhosted.org/packages/8f/29/371467eb86c7ba6810df0bfe9409bcd9c52ec5615b111190fafe23e4d2e1/soxr-1.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:ae30c48ac795378cf23ba3c7c640b8ff794af714ac388b9fd6b31a40b39e6e86", size = 176779, upload-time = "2026-05-03T00:14:53.09Z" }, + { url = "https://files.pythonhosted.org/packages/06/8a/f3da7973b5f1b05d2d7e94d5376b881dcbc05297900cae6c3d33d95b209b/soxr-1.1.0-cp312-abi3-macosx_10_14_x86_64.whl", hash = "sha256:e0e09fa633ce2e67df08b298afced4d184f6e753fc330f241022250f1d0d61da", size = 204124, upload-time = "2026-05-03T00:14:54.505Z" }, + { url = "https://files.pythonhosted.org/packages/03/dc/200013a74641f8774664bbcd2346c695c05c2e300ea792adcb40a293eed0/soxr-1.1.0-cp312-abi3-macosx_11_0_arm64.whl", hash = "sha256:d6a7ad82b8d5f3fcc04b1d2ca055562b96af571e1d4fa7c6c61d0fb509ac43b4", size = 165457, upload-time = "2026-05-03T00:14:56.007Z" }, + { url = "https://files.pythonhosted.org/packages/88/2b/2e5eba817a762a2ec589ff165b8bc5955b25a0ad140045f7cd8e45410543/soxr-1.1.0-cp312-abi3-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bf98c0d7b7d5ef5bf072fee8d3020e8b664f2d195933ea7bc5089267c2e22a06", size = 206529, upload-time = "2026-05-03T00:14:57.646Z" }, + { url = "https://files.pythonhosted.org/packages/5c/f1/0e55195893228609c9a08c3b13b7a83a46c3a992cd00d3304f0f320cfb07/soxr-1.1.0-cp312-abi3-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3b033078e86f3c4a658e5697fac8995764fad9e799563616b630136b613167f1", size = 240413, upload-time = "2026-05-03T00:14:59.363Z" }, + { url = "https://files.pythonhosted.org/packages/b0/4d/621e4150e4815246ad552d215a8a294a90143fedd19ee442cf82d3b3abc8/soxr-1.1.0-cp312-abi3-win_amd64.whl", hash = "sha256:6ae2a174bffea94e8ead857dad85999d3f49f091774dbad5b046c0417d7092f4", size = 174357, upload-time = "2026-05-03T00:15:00.724Z" }, +] + +[[package]] +name = "sympy" +version = "1.14.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "mpmath" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/83/d3/803453b36afefb7c2bb238361cd4ae6125a569b4db67cd9e79846ba2d68c/sympy-1.14.0.tar.gz", hash = "sha256:d3d3fe8df1e5a0b42f0e7bdf50541697dbe7d23746e894990c030e2b05e72517", size = 7793921, upload-time = "2025-04-27T18:05:01.611Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a2/09/77d55d46fd61b4a135c444fc97158ef34a095e5681d0a6c10b75bf356191/sympy-1.14.0-py3-none-any.whl", hash = "sha256:e091cc3e99d2141a0ba2847328f5479b05d94a6635cb96148ccb3f34671bd8f5", size = 6299353, upload-time = "2025-04-27T18:04:59.103Z" }, +] + +[[package]] +name = "threadpoolctl" +version = "3.6.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b7/4d/08c89e34946fce2aec4fbb45c9016efd5f4d7f24af8e5d93296e935631d8/threadpoolctl-3.6.0.tar.gz", hash = "sha256:8ab8b4aa3491d812b623328249fab5302a68d2d71745c8a4c719a2fcaba9f44e", size = 21274, upload-time = "2025-03-13T13:49:23.031Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/32/d5/f9a850d79b0851d1d4ef6456097579a9005b31fea68726a4ae5f2d82ddd9/threadpoolctl-3.6.0-py3-none-any.whl", hash = "sha256:43a0b8fd5a2928500110039e43a5eed8480b918967083ea48dc3ab9f13c4a7fb", size = 18638, upload-time = "2025-03-13T13:49:21.846Z" }, +] + +[[package]] +name = "tokenizers" +version = "0.21.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "huggingface-hub" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c2/2f/402986d0823f8d7ca139d969af2917fefaa9b947d1fb32f6168c509f2492/tokenizers-0.21.4.tar.gz", hash = "sha256:fa23f85fbc9a02ec5c6978da172cdcbac23498c3ca9f3645c5c68740ac007880", size = 351253, upload-time = "2025-07-28T15:48:54.325Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/98/c6/fdb6f72bf6454f52eb4a2510be7fb0f614e541a2554d6210e370d85efff4/tokenizers-0.21.4-cp39-abi3-macosx_10_12_x86_64.whl", hash = "sha256:2ccc10a7c3bcefe0f242867dc914fc1226ee44321eb618cfe3019b5df3400133", size = 2863987, upload-time = "2025-07-28T15:48:44.877Z" }, + { url = "https://files.pythonhosted.org/packages/8d/a6/28975479e35ddc751dc1ddc97b9b69bf7fcf074db31548aab37f8116674c/tokenizers-0.21.4-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:5e2f601a8e0cd5be5cc7506b20a79112370b9b3e9cb5f13f68ab11acd6ca7d60", size = 2732457, upload-time = "2025-07-28T15:48:43.265Z" }, + { url = "https://files.pythonhosted.org/packages/aa/8f/24f39d7b5c726b7b0be95dca04f344df278a3fe3a4deb15a975d194cbb32/tokenizers-0.21.4-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:39b376f5a1aee67b4d29032ee85511bbd1b99007ec735f7f35c8a2eb104eade5", size = 3012624, upload-time = "2025-07-28T13:22:43.895Z" }, + { url = "https://files.pythonhosted.org/packages/58/47/26358925717687a58cb74d7a508de96649544fad5778f0cd9827398dc499/tokenizers-0.21.4-cp39-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2107ad649e2cda4488d41dfd031469e9da3fcbfd6183e74e4958fa729ffbf9c6", size = 2939681, upload-time = "2025-07-28T13:22:47.499Z" }, + { url = "https://files.pythonhosted.org/packages/99/6f/cc300fea5db2ab5ddc2c8aea5757a27b89c84469899710c3aeddc1d39801/tokenizers-0.21.4-cp39-abi3-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3c73012da95afafdf235ba80047699df4384fdc481527448a078ffd00e45a7d9", size = 3247445, upload-time = "2025-07-28T15:48:39.711Z" }, + { url = "https://files.pythonhosted.org/packages/be/bf/98cb4b9c3c4afd8be89cfa6423704337dc20b73eb4180397a6e0d456c334/tokenizers-0.21.4-cp39-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f23186c40395fc390d27f519679a58023f368a0aad234af145e0f39ad1212732", size = 3428014, upload-time = "2025-07-28T13:22:49.569Z" }, + { url = "https://files.pythonhosted.org/packages/75/c7/96c1cc780e6ca7f01a57c13235dd05b7bc1c0f3588512ebe9d1331b5f5ae/tokenizers-0.21.4-cp39-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cc88bb34e23a54cc42713d6d98af5f1bf79c07653d24fe984d2d695ba2c922a2", size = 3193197, upload-time = "2025-07-28T13:22:51.471Z" }, + { url = "https://files.pythonhosted.org/packages/f2/90/273b6c7ec78af547694eddeea9e05de771278bd20476525ab930cecaf7d8/tokenizers-0.21.4-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:51b7eabb104f46c1c50b486520555715457ae833d5aee9ff6ae853d1130506ff", size = 3115426, upload-time = "2025-07-28T15:48:41.439Z" }, + { url = "https://files.pythonhosted.org/packages/91/43/c640d5a07e95f1cf9d2c92501f20a25f179ac53a4f71e1489a3dcfcc67ee/tokenizers-0.21.4-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:714b05b2e1af1288bd1bc56ce496c4cebb64a20d158ee802887757791191e6e2", size = 9089127, upload-time = "2025-07-28T15:48:46.472Z" }, + { url = "https://files.pythonhosted.org/packages/44/a1/dd23edd6271d4dca788e5200a807b49ec3e6987815cd9d0a07ad9c96c7c2/tokenizers-0.21.4-cp39-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:1340ff877ceedfa937544b7d79f5b7becf33a4cfb58f89b3b49927004ef66f78", size = 9055243, upload-time = "2025-07-28T15:48:48.539Z" }, + { url = "https://files.pythonhosted.org/packages/21/2b/b410d6e9021c4b7ddb57248304dc817c4d4970b73b6ee343674914701197/tokenizers-0.21.4-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:3c1f4317576e465ac9ef0d165b247825a2a4078bcd01cba6b54b867bdf9fdd8b", size = 9298237, upload-time = "2025-07-28T15:48:50.443Z" }, + { url = "https://files.pythonhosted.org/packages/b7/0a/42348c995c67e2e6e5c89ffb9cfd68507cbaeb84ff39c49ee6e0a6dd0fd2/tokenizers-0.21.4-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:c212aa4e45ec0bb5274b16b6f31dd3f1c41944025c2358faaa5782c754e84c24", size = 9461980, upload-time = "2025-07-28T15:48:52.325Z" }, + { url = "https://files.pythonhosted.org/packages/3d/d3/dacccd834404cd71b5c334882f3ba40331ad2120e69ded32cf5fda9a7436/tokenizers-0.21.4-cp39-abi3-win32.whl", hash = "sha256:6c42a930bc5f4c47f4ea775c91de47d27910881902b0f20e4990ebe045a415d0", size = 2329871, upload-time = "2025-07-28T15:48:56.841Z" }, + { url = "https://files.pythonhosted.org/packages/41/f2/fd673d979185f5dcbac4be7d09461cbb99751554ffb6718d0013af8604cb/tokenizers-0.21.4-cp39-abi3-win_amd64.whl", hash = "sha256:475d807a5c3eb72c59ad9b5fcdb254f6e17f53dfcbb9903233b0dfa9c943b597", size = 2507568, upload-time = "2025-07-28T15:48:55.456Z" }, +] + +[[package]] +name = "torch" +version = "2.12.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cuda-bindings", marker = "sys_platform == 'linux'" }, + { name = "cuda-toolkit", extra = ["cudart", "cufft", "cufile", "cupti", "curand", "cusolver", "cusparse", "nvjitlink", "nvrtc", "nvtx"], marker = "sys_platform == 'linux'" }, + { name = "filelock" }, + { name = "fsspec" }, + { name = "jinja2" }, + { name = "networkx" }, + { name = "nvidia-cublas", marker = "sys_platform == 'linux'" }, + { name = "nvidia-cudnn-cu13", marker = "sys_platform == 'linux'" }, + { name = "nvidia-cusparselt-cu13", marker = "sys_platform == 'linux'" }, + { name = "nvidia-nccl-cu13", marker = "sys_platform == 'linux'" }, + { name = "nvidia-nvshmem-cu13", marker = "sys_platform == 'linux'" }, + { name = "setuptools" }, + { name = "sympy" }, + { name = "triton", marker = "sys_platform == 'linux'" }, + { name = "typing-extensions" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/59/38/7028d3be540f1dcdf41660a2b01d0c51d2cb73915fe370d84e4d277a6d47/torch-2.12.1-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:ef81f503912effea2ce3d9b12a2e3a6ed488943e91271c90c7a829f60baf6aa2", size = 87975425, upload-time = "2026-06-17T21:08:34.094Z" }, + { url = "https://files.pythonhosted.org/packages/5a/e3/750b3e3548635ceac03ba255daa26dbc7ed66ca3484dc4b4d955ab7f4501/torch-2.12.1-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:107df6888624bdea41508f9aeb6149d9333c737a5530ceecb56c904e811369ae", size = 426379894, upload-time = "2026-06-17T21:06:55.077Z" }, + { url = "https://files.pythonhosted.org/packages/dc/ca/ed24783da629ff3e640ba3f70a7639e9045d3d88b93ee6bc47b8a28a1f2c/torch-2.12.1-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:6e29e7e74d05bda7d955c75e99459f878ebd970ef851b4057edbd3b34a5eb4a3", size = 532169264, upload-time = "2026-06-17T21:08:17.65Z" }, + { url = "https://files.pythonhosted.org/packages/46/61/c63f0158446f3a98ea672b004d761b848911eba567ea4a624c7db5aadc04/torch-2.12.1-cp311-cp311-win_amd64.whl", hash = "sha256:a513506cfda3c1c78dabeb6574c1597538c0254b3d39af174dde35d8177f4ce3", size = 122953086, upload-time = "2026-06-17T21:08:27.69Z" }, + { url = "https://files.pythonhosted.org/packages/f0/54/efb7ebca77970012b0cc21687a55d70eb2ba514b2c2b8e18d9fb1222f3be/torch-2.12.1-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:d2dd0f2c5f7ccbddaf34cade0deaf476808368f902b9cdb7f36a2ab42301bc0e", size = 87991951, upload-time = "2026-06-17T21:07:49.309Z" }, + { url = "https://files.pythonhosted.org/packages/1e/00/4210d76ca7424981f04033ebe7e48816ab83287a62538747a58825db770c/torch-2.12.1-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:2de4e19b88a481482c6c75291f2d6a52eda3ce51f311b29aa9b68499c830c07c", size = 426382721, upload-time = "2026-06-17T21:06:41.842Z" }, + { url = "https://files.pythonhosted.org/packages/76/1f/bc9f5a5aa569307076365f25afcebacb22e9c754b1bcfbaaa146627c7fda/torch-2.12.1-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:649e4ced014ba646f76f8cb9c9726735a6323eb321b7919f942790a923f90921", size = 532261322, upload-time = "2026-06-17T21:06:06.673Z" }, + { url = "https://files.pythonhosted.org/packages/9e/49/c549461daa008159d006a76a991fbc2f26fa8bac27a4030c858463dcb20f/torch-2.12.1-cp312-cp312-win_amd64.whl", hash = "sha256:e86550597877fb272ddc52db2f85b82cb601ea7bd932576a0340152cae2200b3", size = 122988095, upload-time = "2026-06-17T21:07:44.9Z" }, +] + +[[package]] +name = "tqdm" +version = "4.68.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/87/d7/0535a28b1f5f24f6612fb3ff1e89fb1a8d160fee0f976e0aa6803862134b/tqdm-4.68.3.tar.gz", hash = "sha256:00dfa48452b6b6cfae3dd9885636c23d3422d1ec97c66d96818cbd5e0821d482", size = 170596, upload-time = "2026-06-17T07:36:52.105Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d8/8e/bb97bb0c71802080bfc8952937d174e49cfc50de5c951dd47b2496f0dcdb/tqdm-4.68.3-py3-none-any.whl", hash = "sha256:39832cc2def2789a6f29df83f172db7416cea70052c0907a57801c5f2fdccb03", size = 78337, upload-time = "2026-06-17T07:36:50.132Z" }, +] + +[[package]] +name = "transcribe-vibevoice-env" +version = "0.1.0" +source = { virtual = "." } +dependencies = [ + { name = "absl-py" }, + { name = "accelerate" }, + { name = "diffusers" }, + { name = "einops" }, + { name = "gguf" }, + { name = "huggingface-hub" }, + { name = "librosa" }, + { name = "ml-collections" }, + { name = "numpy" }, + { name = "safetensors" }, + { name = "scipy", version = "1.17.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.12'" }, + { name = "scipy", version = "1.18.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" }, + { name = "soundfile" }, + { name = "torch" }, + { name = "tqdm" }, + { name = "transformers" }, +] + +[package.metadata] +requires-dist = [ + { name = "absl-py", specifier = ">=2.0" }, + { name = "accelerate", specifier = ">=1.6.0" }, + { name = "diffusers", specifier = ">=0.30" }, + { name = "einops", specifier = ">=0.7" }, + { name = "gguf", specifier = ">=0.10" }, + { name = "huggingface-hub", specifier = ">=0.30" }, + { name = "librosa", specifier = ">=0.10" }, + { name = "ml-collections", specifier = ">=0.1.1" }, + { name = "numpy", specifier = ">=1.26" }, + { name = "safetensors", specifier = ">=0.4" }, + { name = "scipy", specifier = ">=1.11" }, + { name = "soundfile", specifier = ">=0.12" }, + { name = "torch", specifier = ">=2.2" }, + { name = "tqdm", specifier = ">=4.66" }, + { name = "transformers", specifier = "==4.51.3" }, +] + +[[package]] +name = "transformers" +version = "4.51.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "filelock" }, + { name = "huggingface-hub" }, + { name = "numpy" }, + { name = "packaging" }, + { name = "pyyaml" }, + { name = "regex" }, + { name = "requests" }, + { name = "safetensors" }, + { name = "tokenizers" }, + { name = "tqdm" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/f1/11/7414d5bc07690002ce4d7553602107bf969af85144bbd02830f9fb471236/transformers-4.51.3.tar.gz", hash = "sha256:e292fcab3990c6defe6328f0f7d2004283ca81a7a07b2de9a46d67fd81ea1409", size = 8941266, upload-time = "2025-04-14T08:15:00.485Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a9/b6/5257d04ae327b44db31f15cce39e6020cc986333c715660b1315a9724d82/transformers-4.51.3-py3-none-any.whl", hash = "sha256:fd3279633ceb2b777013234bbf0b4f5c2d23c4626b05497691f00cfda55e8a83", size = 10383940, upload-time = "2025-04-14T08:13:43.023Z" }, +] + +[[package]] +name = "triton" +version = "3.7.1" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7b/f9/19d842d06a08559534fa1eaab6ca551b1bcf40f06620bddec1babaa2772d/triton-3.7.1-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d4a0e1cd4c4a76370ed74a8432a53cea28716827d19e40ffc732233e35ceb3f6", size = 184664887, upload-time = "2026-06-17T20:03:42.913Z" }, + { url = "https://files.pythonhosted.org/packages/cd/5e/fce69606f7f240297f163e25539906732b199530d486ce67ae319877e821/triton-3.7.1-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6744957e9fd610a29680ec2346057d0c86948ed3812468670719f391e94b44a5", size = 197701306, upload-time = "2026-06-17T19:53:13.673Z" }, + { url = "https://files.pythonhosted.org/packages/94/fa/f856e24deb462d5f18bd4b5a746957862ab9b6ee5834bda60605ec348366/triton-3.7.1-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9497f2e696ee368862a181a90b2dcc03ca978cc4f602abd67c7d81022a6988e1", size = 184692359, upload-time = "2026-06-17T20:03:48.288Z" }, + { url = "https://files.pythonhosted.org/packages/c4/6f/fb96d15db6f36d6eae4cafb998c2e0353bf59d7c4ea1662d7497f269134a/triton-3.7.1-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7e40869937a68206ec70d7f25bb7ec6433cb083f9135e1f36dbd318dc449a728", size = 197719725, upload-time = "2026-06-17T19:53:20.419Z" }, +] + +[[package]] +name = "typing-extensions" +version = "4.15.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", size = 109391, upload-time = "2025-08-25T13:49:26.313Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614, upload-time = "2025-08-25T13:49:24.86Z" }, +] + +[[package]] +name = "urllib3" +version = "2.7.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/53/0c/06f8b233b8fd13b9e5ee11424ef85419ba0d8ba0b3138bf360be2ff56953/urllib3-2.7.0.tar.gz", hash = "sha256:231e0ec3b63ceb14667c67be60f2f2c40a518cb38b03af60abc813da26505f4c", size = 433602, upload-time = "2026-05-07T16:13:18.596Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl", hash = "sha256:9fb4c81ebbb1ce9531cce37674bbc6f1360472bc18ca9a553ede278ef7276897", size = 131087, upload-time = "2026-05-07T16:13:17.151Z" }, +] + +[[package]] +name = "zipp" +version = "4.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b9/d8/eab98a517c14134c0b2eb4e2387bc5f457334293ec5d2dd3857ec2966802/zipp-4.1.0.tar.gz", hash = "sha256:4cb57381f544315db7688e976e922a2b18cdb513d21cc194eb42232ba2a3e602", size = 26214, upload-time = "2026-05-18T20:08:57.967Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3a/13/547360d81e6d88d58492968ffda9f9542854f11310ee556fef14260cc886/zipp-4.1.0-py3-none-any.whl", hash = "sha256:25ad4e16390cd314347dd8f1de67a2ac538ae658ed4ab9db16029c07c188e97f", size = 10238, upload-time = "2026-05-18T20:08:57.045Z" }, +] diff --git a/scripts/wer/run_reference_vibevoice_author.py b/scripts/wer/run_reference_vibevoice_author.py new file mode 100644 index 00000000..6f128934 --- /dev/null +++ b/scripts/wer/run_reference_vibevoice_author.py @@ -0,0 +1,179 @@ +#!/usr/bin/env python3 +""" +run_reference_vibevoice_author.py - VibeVoice-ASR reference WER runner. + +Uniform contract: --manifest --model --out --device --batch-size. Emits the +per-utterance reference hyp JSONL that porting-2-oracle Step 7 scores with +scripts/wer/score.py and that Stage 4 / Stage 7 diff C++ against. + +VibeVoice-ASR emits structured JSON ([{Speaker,Start,End,Content}, ...]); the +reference hyp_text is the concatenation of the Content fields (speaker labels + +timestamps stripped), i.e. the plain-WER normalizer for this family. The +acoustic VAE path is forced to its deterministic mean (mode) - content is +identical to the stochastic path, see reports/porting/vibevoice. + +The model can't run on a 16 GB laptop; this is meant to run on a >=40 GB GPU, +typically via: + modal run scripts/wer/remote/modal_sweep.py::reference_sweep \ + --variants vibevoice:vibevoice-asr --gpu L40S + +The author `vibevoice` package is not on PyPI and the HF repo ships no modeling +code, so the source is bootstrapped at runtime: set $VIBEVOICE_SRC to a checkout, +or it is git-cloned (pinned) to /tmp/VibeVoice. +""" +from __future__ import annotations + +import argparse +import json +import os +import re +import subprocess +import sys +import time +from pathlib import Path + +VIBEVOICE_SHA = "303b2833e01cff4578ec278bbfe536da54bd19fe" +LM_TOKENIZER = "Qwen/Qwen2.5-7B" + + +def _ensure_vibevoice_on_path() -> str: + src = os.environ.get("VIBEVOICE_SRC") + if not src: + src = "/tmp/VibeVoice" + if not Path(src, "vibevoice").is_dir(): + print(f"cloning vibevoice {VIBEVOICE_SHA[:12]} -> {src}", flush=True) + subprocess.run(["git", "clone", "https://github.com/microsoft/VibeVoice", src], + check=True) + subprocess.run(["git", "-C", src, "checkout", VIBEVOICE_SHA], check=True) + if not Path(src, "vibevoice").is_dir(): + raise SystemExit(f"vibevoice source not found at {src}") + sys.path.insert(0, src) + return src + + +def _load_model(model_id: str, device: str): + import torch + import transformers + from transformers import PretrainedConfig + + transformers.logging.set_verbosity_error() + def _safe_repr(self): + try: + return f"{self.__class__.__name__} {self.to_json_string()}" + except Exception: + return f"{self.__class__.__name__}()" + PretrainedConfig.__repr__ = _safe_repr + + from vibevoice.modular.modeling_vibevoice_asr import VibeVoiceASRForConditionalGeneration + from vibevoice.processor.vibevoice_asr_processor import VibeVoiceASRProcessor + import vibevoice.modular.modular_vibevoice_tokenizer as tok + + processor = VibeVoiceASRProcessor.from_pretrained( + model_id, language_model_pretrained_name=LM_TOKENIZER) + model = VibeVoiceASRForConditionalGeneration.from_pretrained( + model_id, dtype=torch.bfloat16, attn_implementation="sdpa", + device_map=device).eval() + + # Deterministic acoustic path (mean). Content is identical to the sampled + # path; this just removes the VAE noise so the baseline is reproducible. + def mean_sample(self, dist_type="fix"): + return self.mean, self.std + tok.VibeVoiceTokenizerEncoderOutput.sample = mean_sample + return processor, model + + +def _parse_hyp(text: str) -> str: + """Pull the structured JSON the model emits and join its Content fields. + Falls back to the post-'assistant' text if JSON parsing fails.""" + m = re.search(r"\[\s*\{.*\}\s*\]", text, re.DOTALL) + if m: + try: + arr = json.loads(m.group(0)) + parts = [str(seg.get("Content", "")).strip() + for seg in arr if isinstance(seg, dict)] + joined = " ".join(p for p in parts if p) + if joined: + return joined + except Exception: + pass + if "assistant" in text: + text = text.rsplit("assistant", 1)[1] + return text.strip() + + +def main() -> int: + import librosa + import torch + + ap = argparse.ArgumentParser(description=__doc__) + ap.add_argument("--manifest", type=Path, required=True) + ap.add_argument("--model", required=True) + ap.add_argument("--out", type=Path, required=True) + ap.add_argument("--device", default="cuda") + ap.add_argument("--batch-size", type=int, default=1, + help="accepted for the uniform contract; runner is serial") + ap.add_argument("--revision", default=None) + ap.add_argument("--max-new-tokens", type=int, default=512) + ap.add_argument("--limit", type=int, default=0) + args = ap.parse_args() + + _ensure_vibevoice_on_path() + + manifest = [json.loads(l) for l in args.manifest.read_text().splitlines() if l.strip()] + if args.limit: + manifest = manifest[: args.limit] + total = len(manifest) + print(f"manifest: {args.manifest} ({total} utts) -> {args.out}", flush=True) + + t0 = time.monotonic() + processor, model = _load_model(args.model, args.device) + eos = processor.tokenizer.eos_token_id + load_ms = round((time.monotonic() - t0) * 1000, 1) + print(f"loaded in {load_ms/1000:.0f}s", flush=True) + + n_done = n_err = 0 + t_loop = time.monotonic() + with open(args.out, "w") as fout: + fout.write(json.dumps({"type": "batch_header", "load_ms": load_ms, + "framework": "author_repo_vibevoice", + "model": args.model}) + "\n") + fout.flush() + for entry in manifest: + uid = entry["id"] + ref_text = entry.get("ref_text", "") + err, hyp_text = "", "" + t_start = time.monotonic() + try: + pcm, _ = librosa.load(entry["audio"], sr=24000, mono=True) + inputs = processor(audio=[pcm.astype("float32")], sampling_rate=24000, + return_tensors="pt", add_generation_prompt=True) + inputs = {k: (v.to(args.device) if hasattr(v, "to") else v) + for k, v in inputs.items()} + with torch.inference_mode(): + gen = model.generate(**inputs, max_new_tokens=args.max_new_tokens, + do_sample=False, num_beams=1, + eos_token_id=eos, pad_token_id=eos, + stop_strings=["}]"], tokenizer=processor.tokenizer) + raw = processor.tokenizer.decode(gen[0], skip_special_tokens=True) + hyp_text = _parse_hyp(raw) + except Exception as e: + err = f"{type(e).__name__}: {e}" + n_err += 1 + elapsed_ms = round((time.monotonic() - t_start) * 1000, 1) + fout.write(json.dumps({ + "id": uid, "ref_text": ref_text, "hyp_text": hyp_text.strip(), + "mel_ms": 0, "encode_ms": 0, "decode_ms": elapsed_ms, + "latency_ms": elapsed_ms, "error": err, + }, ensure_ascii=False) + "\n") + fout.flush() + n_done += 1 + if n_done % 100 == 0: + rate = n_done / (time.monotonic() - t_loop) + print(f"[{n_done}/{total}] {rate:.2f} utt/s " + f"ETA {(total-n_done)/rate:.0f}s err={n_err}", flush=True) + print(f"done: {n_done} utts, {n_err} errors", flush=True) + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/tests/golden/vibevoice/vibevoice-asr.manifest.json b/tests/golden/vibevoice/vibevoice-asr.manifest.json index b266715d..69100f16 100644 --- a/tests/golden/vibevoice/vibevoice-asr.manifest.json +++ b/tests/golden/vibevoice/vibevoice-asr.manifest.json @@ -6,7 +6,45 @@ "hf_repo": "microsoft/VibeVoice-ASR", "hf_revision": "d0c9efdb8d614685062c04425d91e01b6f37d944" }, + "reference": { + "kind": "author_repo_vibevoice", + "source": "https://github.com/microsoft/VibeVoice", + "revision": "303b2833e01cff4578ec278bbfe536da54bd19fe", + "entrypoint": "scripts/dump_reference_vibevoice_author.py" + }, "expected_dtype": "bfloat16", "dtype_source": "weights_header", - "_skeleton": true + "frontend": { + "sample_rate": 24000, + "frontend_kind": "learned_vae_tokenizer", + "n_mels": null, + "hop_length": null, + "fft_size": null, + "window": null, + "normalization": "audio_normalizer", + "speech_tok_compress_ratio": 3200, + "token_rate_hz": 7.5, + "note": "Not a spectrogram. Raw 24kHz waveform -> two parallel causal-conv VAE tokenizers (acoustic vae_dim=64 sampled gaussian fix_std=0.5; semantic vae_dim=128 mean), each 3200x downsample -> SpeechConnector -> 3584 -> element-wise sum -> scattered into Qwen2.5-7B LM at acoustic-token positions. Contract tensors use the deterministic acoustic mean." + }, + "tokenizer_summary": { + "type": "bpe", + "vocab_size": 152064, + "source": "Qwen/Qwen2.5-7B", + "special_tokens": { + "endoftext": 151643, + "im_start": 151644, + "im_end": 151645 + } + }, + "capabilities": { + "languages": ["en", "zh", "es", "pt", "de", "ja", "ko", "fr", "ru", "id", "sv", "it", "he", "nl", "pl", "no", "tr", "th", "ar", "hu", "ca", "cs", "da", "fa", "af", "hi", "fi", "et", "aa", "el", "ro", "vi", "bg", "is", "sl", "sk", "lt", "sw", "uk", "kl", "lv", "hr", "ne", "sr", "tl", "yi", "ms", "ur", "mn", "hy", "jv"], + "language_detection": true, + "translation": false, + "timestamps": ["segment"], + "streaming": false, + "voice_activity_detection": null, + "speaker_diarization": true + }, + "tolerance_file": "tests/tolerances/vibevoice.json", + "cases": ["jfk"] } diff --git a/tests/tolerances/vibevoice.json b/tests/tolerances/vibevoice.json new file mode 100644 index 00000000..7d4915cc --- /dev/null +++ b/tests/tolerances/vibevoice.json @@ -0,0 +1,135 @@ +{ + "_comment": [ + "VibeVoice-ASR per-tensor tolerances for compare_tensors.py.", + "", + "CORRECTNESS REGIME", + "- Reference: microsoft/VibeVoice-ASR via the author `vibevoice` package", + " @ 303b2833e01cff4578ec278bbfe536da54bd19fe (HF rev", + " d0c9efdb8d614685062c04425d91e01b6f37d944), run on a Modal L40S GPU,", + " attn_implementation=eager. Dumper: scripts/dump_reference_vibevoice_author.py.", + "- Audio-LLM: raw 24kHz -> acoustic+semantic causal-conv VAE tokenizers", + " (loaded fp32) -> SpeechConnector -> 3584 -> element-wise SUM -> scattered", + " into a Qwen2.5-7B LM (bf16) -> lm_head. C++: ggml, BF16 weights for the LM.", + "", + "DETERMINISM", + "- The acoustic path samples a Gaussian VAE latent (fix_std=0.5); contract", + " tensors use the deterministic MEAN (mode()). Verified: transcription content", + " is identical mean-vs-sampled, and the lm_head argmax is stable across 8 noisy", + " passes (see /ref/envelope.json for the sampled std band). The C++ port", + " must use the acoustic mean, not a sample.", + "", + "ENTRY SOURCING (provisional)", + "- Per-tensor max_abs = max(1e-4 x p99_abs, 1e-6)", + "- Per-tensor mean_abs = max(1e-5 x rms, 1e-6)", + "- All entries carry _provisional: true. Stage 4 finalizes against observed", + " C++ drift and removes the flag tensor-by-tensor.", + "- enc.* (VAE frontend) runs fp32 in the reference; enc.combined feeds the", + " bf16 LM, so expect the largest C++ drift to localize there.", + "", + "DO NOT SHIP a model while _provisional entries remain." + ], + "dec.block.0.out": { + "max_abs": 0.00034918908548355114, + "mean_abs": 1.1825509090697178e-05, + "_provisional": true, + "_seen_in": [ + "vibevoice-asr" + ] + }, + "dec.block.13.out": { + "max_abs": 0.0017155382480621368, + "mean_abs": 0.00025935811667857696, + "_provisional": true, + "_seen_in": [ + "vibevoice-asr" + ] + }, + "dec.block.27.out": { + "max_abs": 0.0004268157353401184, + "mean_abs": 1.416734189009224e-05, + "_provisional": true, + "_seen_in": [ + "vibevoice-asr" + ] + }, + "dec.final_norm": { + "max_abs": 0.0009737013187408468, + "mean_abs": 2.969060860240193e-05, + "_provisional": true, + "_seen_in": [ + "vibevoice-asr" + ] + }, + "dec.inputs_embeds": { + "max_abs": 0.00031161820697784426, + "mean_abs": 1.0546719566294443e-05, + "_provisional": true, + "_seen_in": [ + "vibevoice-asr" + ] + }, + "dec.logits_lastpos": { + "max_abs": 0.0004904306406974792, + "mean_abs": 1.9985159967555443e-05, + "_provisional": true, + "_seen_in": [ + "vibevoice-asr" + ] + }, + "dec.token_emb": { + "max_abs": 3.3935546875000002e-06, + "mean_abs": 1e-06, + "_provisional": true, + "_seen_in": [ + "vibevoice-asr" + ] + }, + "enc.acoustic.feat": { + "max_abs": 0.00028645717239379856, + "mean_abs": 9.20495305171677e-06, + "_provisional": true, + "_seen_in": [ + "vibevoice-asr" + ] + }, + "enc.acoustic.mean": { + "max_abs": 0.001432571738243104, + "mean_abs": 4.640234410032806e-05, + "_provisional": true, + "_seen_in": [ + "vibevoice-asr" + ] + }, + "enc.combined": { + "max_abs": 0.00037147614979743913, + "mean_abs": 1.384288713252548e-05, + "_provisional": true, + "_seen_in": [ + "vibevoice-asr" + ] + }, + "enc.input_waveform": { + "max_abs": 2.0661220669746416e-05, + "mean_abs": 1e-06, + "_provisional": true, + "_seen_in": [ + "vibevoice-asr" + ] + }, + "enc.semantic.feat": { + "max_abs": 0.00031607579660415636, + "mean_abs": 1.1101145839183082e-05, + "_provisional": true, + "_seen_in": [ + "vibevoice-asr" + ] + }, + "enc.semantic.mean": { + "max_abs": 0.0007712323737144473, + "mean_abs": 2.733901739568905e-05, + "_provisional": true, + "_seen_in": [ + "vibevoice-asr" + ] + } +} From e292dcf4947e86be127d44fbd69396936611b0c9 Mon Sep 17 00:00:00 2001 From: CJ Pais Date: Fri, 26 Jun 2026 21:20:59 -0700 Subject: [PATCH 3/4] stage 4 --- docs/porting/families/vibevoice.md | 39 ++ scripts/convert-vibevoice.py | 662 +++++++++++++++++++++++++++++ 2 files changed, 701 insertions(+) create mode 100644 scripts/convert-vibevoice.py diff --git a/docs/porting/families/vibevoice.md b/docs/porting/families/vibevoice.md index 11545c5e..8ecb726d 100644 --- a/docs/porting/families/vibevoice.md +++ b/docs/porting/families/vibevoice.md @@ -110,3 +110,42 @@ Proposed `Target` values below; non-forced rows require user sign-off at intake. (jfk / LibriSpeech segments). See intake `known_risks` for the full list, including the learned-VAE frontend, dual-tokenizer fusion, the unused diffusion head, and KV-memory at long context. + +### Conversion (Stage 3) + +Reference-dtype GGUF: `models/VibeVoice-ASR/VibeVoice-ASR-BF16.gguf` (slug-cased dir per the +`find_gguf` slug-driven convention, same as `Qwen3-ASR-0.6B`). Converter +`scripts/convert-vibevoice.py`; manifest `reports/convert/vibevoice-asr-BF16.json`. Streams +shards one tensor at a time (never instantiates the 9B model), so it runs on a 16 GB machine. + +Tensor-mapping decisions (the contract Stage 4 `src/arch/vibevoice/weights.cpp` implements +against): + +- **901 tensors kept, 276 dropped.** Dropped = `model.acoustic_tokenizer.decoder.*` (the + VibeVoice TTS acoustic-decoder path; ASR calls only `acoustic_tokenizer.encode(...).mean`). + The config's `diffusion_head_config` ships **no weights** in the ASR checkpoint. The + `semantic_tokenizer` is encoder-only. +- **Naming:** Qwen2.5 LM → `dec.token_embd` / `dec.output_norm` / `dec.output` (untied head; + `lm_head.weight` ships separately, `tie_word_embeddings=false`) + `dec.blocks.{i}.{norm_attn, + attn.{q,k,v,o}[.bias],norm_ffn,ffn.{gate,up,down}}` (Qwen2 carries q/k/v biases, no o bias). + Connectors → `conn.{acoustic,semantic}.{fc1,norm,fc2}`. VAE encoders → `enc.{acoustic, + semantic}.` (suffix preserved, incl. the `conv.conv[.conv]` SConv1d + nesting). +- **Fusion is a Stage-4 runtime op, not baked in:** `enc.combined = acoustic_feat + + semantic_feat` (element-wise sum of the two connector outputs), then scattered into the LM + embedding stream at `speech_pad` positions. The converter only stores both encoders + both + connectors. +- **Per-tensor dtype (BF16 reference):** norms / biases / VAE layer-scale `gamma`+`ffn_gamma` + → F32; all VAE causal-conv kernels → F16 (loader has no BF16 conv; F16 also out-precisions + BF16); linears / embed / head → BF16. Result: 306 BF16, 527 F32, 68 F16. +- **Tokenizer** pulled from stock `Qwen/Qwen2.5-7B` (152064 tokens, 151387 merges, gpt2/qwen2 + byte-level BPE). Speech markers reuse existing Qwen specials: `speech_start=<|object_ref_start|>` + (151646), `speech_end=<|object_ref_end|>` (151647), `speech_pad=<|box_start|>` (151648); + `eos=<|endoftext|>` (151643). Chat template, `SYSTEM_PROMPT`, the three speech-token ids, + `im_start`/`im_end`, and `speech_tok_compress_ratio=3200` are stored as `stt.vibevoice.*` / + `tokenizer.*` KV so Stage 4 can rebuild the prompt (which is otherwise assembled dynamically + from the audio duration and a `ceil(n_samples/3200)`-long speech-pad run). +- **Frontend:** `stt.frontend.type=raw_waveform`, `sample_rate=24000`; no STFT/mel buffers. + +Preflight Gate B: **PASS** (dtype, frontend, tokenizer, architecture, capabilities). Loader-open +smoke returns `unsupported architecture` (expected — `src/arch/vibevoice` is a Stage 4 artifact). diff --git a/scripts/convert-vibevoice.py b/scripts/convert-vibevoice.py new file mode 100644 index 00000000..a2ebc92b --- /dev/null +++ b/scripts/convert-vibevoice.py @@ -0,0 +1,662 @@ +#!/usr/bin/env python3 +""" +convert-vibevoice.py - convert the microsoft/VibeVoice-ASR checkpoint to a +BF16 reference GGUF that transcribe.cpp's loader can ingest. Block +quantization (Q8_0, Q5_K_M, ...) is a Stage 5 concern and goes through +tools/transcribe-quantize. + +Source format: + HuggingFace repo `microsoft/VibeVoice-ASR` — config.json + 8 BF16 + safetensors shards ONLY. No modeling code, processor, tokenizer, or + generation_config ship with the weights; the reference implementation + lives in the `vibevoice` package (vendored under + models/_vendor/VibeVoice) and the tokenizer is the stock + `Qwen/Qwen2.5-7B` byte-level BPE, pulled separately here. + +Architecture: audio-llm. Raw 24 kHz waveform feeds two parallel causal-conv +VAE encoders (acoustic vae_dim 64, semantic vae_dim 128); each encoder's +latent `.mean` is projected to the Qwen2.5 hidden size (3584) by a +SpeechConnector, the two projections are summed, and the result is scattered +into the Qwen2.5-7B LM token stream at the speech-pad positions. State dict +prefixes: + + model.language_model.* -> Qwen2.5-7B causal LM (28 layers, GQA + 28/4, head_dim 128, q/k/v biases, + SwiGLU, rope_theta 1e6) + lm_head.weight -> output projection (untied) + model.acoustic_tokenizer.encoder.* -> acoustic VAE encoder (KEPT) + model.acoustic_tokenizer.decoder.* -> acoustic VAE decoder (DROPPED: + TTS-only, never on the ASR path) + model.semantic_tokenizer.encoder.* -> semantic VAE encoder (KEPT; + semantic tokenizer is encoder-only) + model.acoustic_connector.* -> acoustic latent (64) -> 3584 projector + model.semantic_connector.* -> semantic latent (128) -> 3584 projector + +The acoustic-tokenizer DECODER (276 tensors) and the config's diffusion-head +are the VibeVoice TTS generation path; ASR calls only `.encode(...).mean`, so +they are dropped. This is confirmed by the Stage-2 oracle dumper +(scripts/dump_reference_vibevoice_author.py): the ASR forward only touches the +two encoders, the two connectors, and the LM. + +Layout conversions: NONE. Linear weights stay (out, in); conv1d kernels stay +(out, in, k) which is what ggml expects. + +KV emitted (see body for the full list): + general.architecture = "vibevoice" + stt.variant = "vibevoice-asr" + tokenizer.ggml.* = Qwen2.5-7B gpt2 byte-level BPE + chat template + stt.vibevoice.decoder.* Qwen2.5 LM hparams + stt.vibevoice.acoustic.* acoustic VAE encoder hparams + stt.vibevoice.semantic.* semantic VAE encoder hparams + stt.vibevoice.speech_*_token_id / speech_tok_compress_ratio / system_prompt + stt.frontend.* raw-waveform frontend (sample_rate only) + +CLI: + uv run --project scripts/envs/vibevoice \ + scripts/convert-vibevoice.py microsoft/VibeVoice-ASR \ + --revision d0c9efdb8d614685062c04425d91e01b6f37d944 + +Single-file, top-to-bottom — no hidden helpers. +""" + +from __future__ import annotations + +import argparse +import json +import os +import sys +from contextlib import ExitStack +from pathlib import Path + +import numpy as np +import torch +from gguf import GGMLQuantizationType, GGUFWriter, LlamaFileType +from huggingface_hub import snapshot_download +from safetensors import safe_open + + +class _ShardedSafetensors: + """Multi-file safe_open shim. + + Reads model.safetensors.index.json, opens each shard lazily, and exposes + the same keys()/get_tensor() surface as safe_open so the converter + streams one tensor at a time and never materializes the 9B model. + """ + + def __init__(self, model_dir: Path) -> None: + self._stack = ExitStack() + single = model_dir / "model.safetensors" + if single.is_file(): + self._shard_for: dict[str, str] = {} + sf = self._stack.enter_context(safe_open(str(single), framework="pt")) + self._handles: dict[str, "safe_open"] = {"__single__": sf} + for k in sf.keys(): + self._shard_for[k] = "__single__" + return + + index_path = model_dir / "model.safetensors.index.json" + with index_path.open() as f: + index = json.load(f) + weight_map: dict[str, str] = index["weight_map"] + shards = sorted(set(weight_map.values())) + self._handles = { + name: self._stack.enter_context( + safe_open(str(model_dir / name), framework="pt")) + for name in shards + } + self._shard_for = weight_map + + def __enter__(self): + return self + + def __exit__(self, *args): + self._stack.close() + + def keys(self): + return list(self._shard_for.keys()) + + def get_tensor(self, name: str): + return self._handles[self._shard_for[name]].get_tensor(name) + + +sys.path.insert(0, str(Path(__file__).resolve().parent)) +from lib.gguf_common import ( # noqa: E402 + TOKEN_TYPE_CONTROL, + TOKEN_TYPE_NORMAL, + encode_for_gguf, + gguf_name, + slug_from_repo_id, +) + +REPO_ROOT = Path(__file__).resolve().parent.parent + +REFERENCE_DTYPE_LABEL = "BF16" +REFERENCE_FILE_TYPE = LlamaFileType.MOSTLY_BF16 +REFERENCE_GGML_TYPE = GGMLQuantizationType.BF16 + +# The HF weights repo ships no tokenizer; the processor loads the stock +# Qwen2.5-7B byte-level BPE (vocab padded to 152064). We pull just the +# tokenizer files, not the 15 GB of Qwen weights. +TOKENIZER_REPO = "Qwen/Qwen2.5-7B" +TOKENIZER_FILES = ["vocab.json", "merges.txt", "tokenizer_config.json"] + +# Constants lifted verbatim from the vendored VibeVoice ASR processor / +# tokenizer (models/_vendor/VibeVoice/vibevoice/...). The processor builds the +# LM prompt dynamically (it interpolates the audio duration and a speech-pad +# run of length ceil(n_samples / compress_ratio)); we bake the static pieces +# into the GGUF so the C++ runtime can reconstruct it. +SYSTEM_PROMPT = ( + "You are a helpful assistant that transcribes audio input into text " + "output in JSON format." +) +CHAT_TEMPLATE = ( + "{% for message in messages %}{{'<|im_start|>' + message['role'] + '\n' " + "+ message['content'] + '<|im_end|>' + '\n'}}{% endfor %}{% if " + "add_generation_prompt %}{{ '<|im_start|>assistant\n' }}{% endif %}" +) +# Speech markers REUSE existing Qwen2.5 special tokens (no new vocab). +SPEECH_START_TOKEN = "<|object_ref_start|>" +SPEECH_END_TOKEN = "<|object_ref_end|>" +SPEECH_PAD_TOKEN = "<|box_start|>" +SPEECH_TOK_COMPRESS_RATIO = 3200 # product of encoder_ratios [8,5,5,4,2,2] +TARGET_SAMPLE_RATE = 24000 +GENERATION_STOP_STRING = "}]" + + +# --------------------------------------------------------------------------- +# Tokenizer extraction (Qwen2.5 / Qwen2Tokenizer — byte-level BPE) +# --------------------------------------------------------------------------- + + +def extract_tokenizer(tok_dir: Path, vocab_size: int) -> dict: + vocab_path = tok_dir / "vocab.json" + merges_path = tok_dir / "merges.txt" + tokcfg_path = tok_dir / "tokenizer_config.json" + + with vocab_path.open(encoding="utf-8") as f: + base_vocab: dict[str, int] = json.load(f) + with merges_path.open(encoding="utf-8") as f: + merges = [line.rstrip("\n") for line in f.readlines()] + if merges and merges[0].startswith("#"): + merges = merges[1:] + with tokcfg_path.open(encoding="utf-8") as f: + tokcfg = json.load(f) + + added = tokcfg.get("added_tokens_decoder", {}) or {} + tok_by_id: dict[int, tuple[str, bool]] = {} + for tok, tid in base_vocab.items(): + tok_by_id[int(tid)] = (tok, False) + for tid_str, info in added.items(): + tid = int(tid_str) + tok_by_id[tid] = (info["content"], bool(info.get("special", False))) + + max_id = max(tok_by_id.keys()) + if max_id + 1 > vocab_size: + raise ValueError( + f"tokenizer has id {max_id} but config vocab_size={vocab_size}") + + content_to_id = {content: tid for tid, (content, _) in tok_by_id.items()} + + tokens: list[str] = [] + types: list[int] = [] + for i in range(vocab_size): + if i not in tok_by_id: + tokens.append(f"<|unused_{i}|>") + types.append(TOKEN_TYPE_NORMAL) + continue + tok, is_special = tok_by_id[i] + tokens.append(tok) + types.append(TOKEN_TYPE_CONTROL if is_special else TOKEN_TYPE_NORMAL) + + def _name_to_id(name_field: str) -> int | None: + tok = tokcfg.get(name_field) + if isinstance(tok, dict): + tok = tok.get("content") + if not tok: + return None + return content_to_id.get(tok) + + def _content_id(content: str) -> int: + tid = content_to_id.get(content) + if tid is None: + raise KeyError(f"expected token {content!r} in {TOKENIZER_REPO} vocab") + return tid + + return { + "tokens": tokens, + "types": types, + "merges": merges, + "eos_id": _name_to_id("eos_token"), + "pad_id": _name_to_id("pad_token"), + "bos_id": _name_to_id("bos_token"), + "speech_start_id": _content_id(SPEECH_START_TOKEN), + "speech_end_id": _content_id(SPEECH_END_TOKEN), + "speech_pad_id": _content_id(SPEECH_PAD_TOKEN), + "im_start_id": _content_id("<|im_start|>"), + "im_end_id": _content_id("<|im_end|>"), + } + + +# --------------------------------------------------------------------------- +# Per-tensor reference dtype policy (BF16 reference) +# --------------------------------------------------------------------------- +# +# Local rather than gguf_common.reference_dtype_for because VibeVoice carries +# tensor shapes that family's parakeet-tuned heuristics don't cover: the VAE +# encoders' layer-scale `gamma` / `ffn_gamma` vectors and their bare +# `norm.weight` / `ffn_norm.weight` RMSNorms must stay F32, and all of their +# causal-conv kernels go to F16 (the loader has no BF16 conv path; F16 also +# has more mantissa than BF16, so this is the accuracy-preserving choice). + + +def vibe_dtype_for(name: str) -> GGMLQuantizationType: + if name.endswith(".bias"): + return GGMLQuantizationType.F32 + if name.endswith(".gamma") or name.endswith("_gamma"): + return GGMLQuantizationType.F32 + if (name.endswith("norm.weight") + or name.endswith("norm_attn.weight") + or name.endswith("norm_ffn.weight")): + return GGMLQuantizationType.F32 + if ".conv." in name and name.endswith(".weight"): + return GGMLQuantizationType.F16 + return REFERENCE_GGML_TYPE + + +# --------------------------------------------------------------------------- +# Tensor name mapping +# --------------------------------------------------------------------------- + + +def passthrough(arr: np.ndarray) -> np.ndarray: + return np.ascontiguousarray(arr) + + +# Qwen2.5 LM top-level (untied head: lm_head.weight ships separately). +TEXT_TOP_TABLE: list[tuple[str, str]] = [ + ("model.language_model.embed_tokens.weight", "dec.token_embd.weight"), + ("model.language_model.norm.weight", "dec.output_norm.weight"), + ("lm_head.weight", "dec.output.weight"), +] + +# Per-LM-layer block (Qwen2: q/k/v carry biases, o_proj does not). +TEXT_BLOCK_TABLE: list[tuple[str, str]] = [ + ("input_layernorm.weight", "norm_attn.weight"), + ("post_attention_layernorm.weight", "norm_ffn.weight"), + ("self_attn.q_proj.weight", "attn.q.weight"), + ("self_attn.q_proj.bias", "attn.q.bias"), + ("self_attn.k_proj.weight", "attn.k.weight"), + ("self_attn.k_proj.bias", "attn.k.bias"), + ("self_attn.v_proj.weight", "attn.v.weight"), + ("self_attn.v_proj.bias", "attn.v.bias"), + ("self_attn.o_proj.weight", "attn.o.weight"), + ("mlp.gate_proj.weight", "ffn.gate.weight"), + ("mlp.up_proj.weight", "ffn.up.weight"), + ("mlp.down_proj.weight", "ffn.down.weight"), +] + +# SpeechConnector (fc1 -> RMSNorm -> fc2), one per stream. +CONNECTOR_SUFFIXES = ["fc1.weight", "fc1.bias", "norm.weight", + "fc2.weight", "fc2.bias"] + +# VAE encoder prefixes: every key under these is copied verbatim (suffix +# preserved) under the enc.. namespace. The decoder prefix is dropped. +ENC_PREFIXES = { + "acoustic": "model.acoustic_tokenizer.encoder.", + "semantic": "model.semantic_tokenizer.encoder.", +} +DROP_PREFIX = "model.acoustic_tokenizer.decoder." + + +# --------------------------------------------------------------------------- +# Hparams +# --------------------------------------------------------------------------- + + +def read_hparams(config: dict) -> dict: + dec = config["decoder_config"] + ac = config["acoustic_tokenizer_config"] + sc = config["semantic_tokenizer_config"] + + n_heads = int(dec["num_attention_heads"]) + hidden = int(dec["hidden_size"]) + + def enc_hp(cfg: dict) -> dict: + return { + "vae_dim": int(cfg["vae_dim"]), + "n_filters": int(cfg["encoder_n_filters"]), + "ratios": [int(r) for r in cfg["encoder_ratios"]], + "depths": str(cfg["encoder_depths"]), + "mixer": str(cfg["mixer_layer"]), + "layernorm": str(cfg["layernorm"]), + "layernorm_eps": float(cfg.get("layernorm_eps", 1e-6)), + "layer_scale_init": float(cfg.get("layer_scale_init_value", 1e-6)), + "causal": bool(cfg["causal"]), + "fix_std": float(cfg.get("fix_std", 0.0)), + "std_dist": str(cfg.get("std_dist_type", "none")), + "disable_last_norm": bool(cfg.get("disable_last_norm", False)), + "pad_mode": str(cfg.get("pad_mode", "constant")), + "conv_bias": bool(cfg.get("conv_bias", True)), + } + + return { + "dec_n_layers": int(dec["num_hidden_layers"]), + "dec_hidden": hidden, + "dec_intermediate": int(dec["intermediate_size"]), + "dec_n_heads": n_heads, + "dec_n_kv_heads": int(dec["num_key_value_heads"]), + "dec_head_dim": int(dec.get("head_dim", hidden // n_heads)), + "dec_hidden_act": str(dec.get("hidden_act", "silu")).lower(), + "dec_rms_norm_eps": float(dec["rms_norm_eps"]), + "dec_rope_theta": float(dec["rope_theta"]), + "dec_max_pos_emb": int(dec["max_position_embeddings"]), + "dec_tie_embeddings": bool(dec.get("tie_word_embeddings", False)), + "dec_vocab_size": int(dec["vocab_size"]), + "acoustic_vae_dim": int(config["acoustic_vae_dim"]), + "semantic_vae_dim": int(config["semantic_vae_dim"]), + "acoustic": enc_hp(ac), + "semantic": enc_hp(sc), + } + + +def compute_size_label(total_params: int) -> str: + if total_params >= 1_000_000_000: + return f"{total_params / 1_000_000_000:.1f}B" + if total_params >= 1_000_000: + return f"{total_params / 1_000_000:.0f}M" + return f"{total_params / 1_000:.0f}K" + + +def load_intake_capabilities() -> tuple[list[str], bool]: + """Languages + lang-detect flag from the Stage-1 intake (single source).""" + intake_path = (REPO_ROOT / "reports" / "porting" / "vibevoice" + / "vibevoice-asr" / "intake.json") + with intake_path.open() as f: + intake = json.load(f) + caps = intake.get("capabilities", {}) + return (list(caps.get("languages", [])), + bool(caps.get("language_detection", False))) + + +# --------------------------------------------------------------------------- +# Main converter +# --------------------------------------------------------------------------- + + +def convert(model_dir: Path, tok_dir: Path, out_path: Path, variant: str) -> None: + print(f"Output dtype: {REFERENCE_DTYPE_LABEL} (source/reference dtype)") + + with (model_dir / "config.json").open() as f: + config = json.load(f) + hp = read_hparams(config) + languages, lang_detect = load_intake_capabilities() + + print(f"LM: Qwen2.5 {hp['dec_n_layers']} layers, hidden={hp['dec_hidden']}, " + f"heads={hp['dec_n_heads']}/{hp['dec_n_kv_heads']}, " + f"vocab={hp['dec_vocab_size']}, tie={hp['dec_tie_embeddings']}") + print(f"Acoustic VAE: vae_dim={hp['acoustic_vae_dim']} " + f"ratios={hp['acoustic']['ratios']} depths={hp['acoustic']['depths']}") + print(f"Semantic VAE: vae_dim={hp['semantic_vae_dim']} " + f"ratios={hp['semantic']['ratios']} depths={hp['semantic']['depths']}") + + print(f"Reading Qwen2.5 tokenizer from {tok_dir}") + tok = extract_tokenizer(tok_dir, hp["dec_vocab_size"]) + print(f" eos={tok['eos_id']} pad={tok['pad_id']} " + f"speech_start={tok['speech_start_id']} speech_end={tok['speech_end_id']} " + f"speech_pad={tok['speech_pad_id']}") + + with _ShardedSafetensors(model_dir) as st: + st_keys = set(st.keys()) + + # Build the full (src -> dst) plan up front so we can validate + # coverage before writing a 13 GB file. + plan: list[tuple[str, str]] = list(TEXT_TOP_TABLE) + for i in range(hp["dec_n_layers"]): + for s_src, s_dst in TEXT_BLOCK_TABLE: + plan.append((f"model.language_model.layers.{i}.{s_src}", + f"dec.blocks.{i}.{s_dst}")) + for stream in ("acoustic", "semantic"): + for suffix in CONNECTOR_SUFFIXES: + plan.append((f"model.{stream}_connector.{suffix}", + f"conn.{stream}.{suffix}")) + for stream, prefix in ENC_PREFIXES.items(): + for k in sorted(st_keys): + if k.startswith(prefix): + plan.append((k, f"enc.{stream}." + k[len(prefix):])) + + planned_src = {s for s, _ in plan} + dropped = sorted(k for k in st_keys if k.startswith(DROP_PREFIX)) + unexpected = sorted(st_keys - planned_src - set(dropped)) + if unexpected: + raise RuntimeError( + "unplanned safetensors keys (neither mapped nor dropped):\n " + + "\n ".join(unexpected[:30])) + missing = sorted(planned_src - st_keys) + if missing: + raise KeyError("planned tensors absent from checkpoint:\n " + + "\n ".join(missing[:30])) + print(f"Plan: {len(plan)} tensors kept, {len(dropped)} dropped " + f"(acoustic-tokenizer decoder / TTS dead weight)") + + total = sum(st.get_tensor(s).numel() for s, _ in plan) + size_label = compute_size_label(total) + print(f"Kept params: {total:,} -> size_label={size_label}") + + print(f"Writing GGUF to {out_path}") + writer = GGUFWriter(str(out_path), "vibevoice") + + # ---- general.* ---- + writer.add_string("general.basename", "vibevoice") + writer.add_string("general.size_label", size_label) + writer.add_uint32("general.file_type", int(REFERENCE_FILE_TYPE)) + writer.add_array("general.languages", languages) + + # ---- stt.variant + capabilities ---- + writer.add_string("stt.variant", variant) + writer.add_bool("stt.capability.lang_detect", lang_detect) + writer.add_bool("stt.capability.diarize", True) + + # ---- tokenizer.ggml.* (Qwen2.5 byte-level BPE) ---- + writer.add_string("tokenizer.ggml.model", "gpt2") + writer.add_string("tokenizer.ggml.pre", "qwen2") + writer.add_array("tokenizer.ggml.tokens", tok["tokens"]) + writer.add_array("tokenizer.ggml.token_type", tok["types"]) + writer.add_array("tokenizer.ggml.merges", tok["merges"]) + if tok["eos_id"] is not None: + writer.add_uint32("tokenizer.ggml.eos_token_id", tok["eos_id"]) + if tok["pad_id"] is not None: + writer.add_uint32("tokenizer.ggml.padding_token_id", tok["pad_id"]) + if tok["bos_id"] is not None: + writer.add_uint32("tokenizer.ggml.bos_token_id", tok["bos_id"]) + writer.add_bool("tokenizer.ggml.add_bos_token", False) + writer.add_string("tokenizer.chat_template", CHAT_TEMPLATE) + + # ---- stt.vibevoice.decoder.* (Qwen2.5 LM) ---- + writer.add_uint32("stt.vibevoice.decoder.n_layers", hp["dec_n_layers"]) + writer.add_uint32("stt.vibevoice.decoder.hidden_size", hp["dec_hidden"]) + writer.add_uint32("stt.vibevoice.decoder.intermediate_size", hp["dec_intermediate"]) + writer.add_uint32("stt.vibevoice.decoder.n_heads", hp["dec_n_heads"]) + writer.add_uint32("stt.vibevoice.decoder.n_kv_heads", hp["dec_n_kv_heads"]) + writer.add_uint32("stt.vibevoice.decoder.head_dim", hp["dec_head_dim"]) + writer.add_string("stt.vibevoice.decoder.hidden_act", hp["dec_hidden_act"]) + writer.add_float32("stt.vibevoice.decoder.rms_norm_eps", hp["dec_rms_norm_eps"]) + writer.add_float32("stt.vibevoice.decoder.rope_theta", hp["dec_rope_theta"]) + writer.add_uint32("stt.vibevoice.decoder.max_position_embeddings", + hp["dec_max_pos_emb"]) + writer.add_bool("stt.vibevoice.decoder.tie_word_embeddings", + hp["dec_tie_embeddings"]) + writer.add_uint32("stt.vibevoice.decoder.vocab_size", hp["dec_vocab_size"]) + + # ---- stt.vibevoice.{acoustic,semantic}.* (VAE encoders + connectors) ---- + for stream in ("acoustic", "semantic"): + e = hp[stream] + base = f"stt.vibevoice.{stream}" + writer.add_uint32(f"{base}.vae_dim", e["vae_dim"]) + writer.add_uint32(f"{base}.n_filters", e["n_filters"]) + writer.add_array(f"{base}.encoder_ratios", e["ratios"]) + writer.add_string(f"{base}.encoder_depths", e["depths"]) + writer.add_string(f"{base}.mixer_layer", e["mixer"]) + writer.add_string(f"{base}.layernorm", e["layernorm"]) + writer.add_float32(f"{base}.layernorm_eps", e["layernorm_eps"]) + writer.add_float32(f"{base}.layer_scale_init", e["layer_scale_init"]) + writer.add_bool(f"{base}.causal", e["causal"]) + writer.add_float32(f"{base}.fix_std", e["fix_std"]) + writer.add_string(f"{base}.std_dist_type", e["std_dist"]) + writer.add_bool(f"{base}.disable_last_norm", e["disable_last_norm"]) + writer.add_string(f"{base}.pad_mode", e["pad_mode"]) + writer.add_bool(f"{base}.conv_bias", e["conv_bias"]) + + # ---- speech fusion + prompt metadata ---- + writer.add_uint32("stt.vibevoice.speech_start_token_id", tok["speech_start_id"]) + writer.add_uint32("stt.vibevoice.speech_end_token_id", tok["speech_end_id"]) + writer.add_uint32("stt.vibevoice.speech_pad_token_id", tok["speech_pad_id"]) + writer.add_uint32("stt.vibevoice.im_start_token_id", tok["im_start_id"]) + writer.add_uint32("stt.vibevoice.im_end_token_id", tok["im_end_id"]) + writer.add_uint32("stt.vibevoice.speech_tok_compress_ratio", + SPEECH_TOK_COMPRESS_RATIO) + writer.add_string("stt.vibevoice.system_prompt", SYSTEM_PROMPT) + writer.add_string("stt.vibevoice.generation_stop_string", + GENERATION_STOP_STRING) + + # ---- stt.frontend.* (raw 24 kHz waveform, no STFT/mel) ---- + writer.add_string("stt.frontend.type", "raw_waveform") + writer.add_uint32("stt.frontend.sample_rate", TARGET_SAMPLE_RATE) + + # ---- tensors ---- + n_added = 0 + bytes_in = 0 + bytes_out = 0 + + def add(src_name: str, dst_name: str, transform=passthrough) -> None: + nonlocal n_added, bytes_in, bytes_out + t = st.get_tensor(src_name) + if t.dtype != torch.bfloat16: + raise ValueError( + f"{src_name}: expected torch.bfloat16, got {t.dtype}") + arr = transform(t.float().numpy()) + if arr.dtype != np.float32: + raise ValueError( + f"{src_name}: expected float32 after transform, got {arr.dtype}") + target_type = vibe_dtype_for(dst_name) + encoded, raw_dtype = encode_for_gguf(arr, target_type) + writer.add_tensor(dst_name, encoded, raw_dtype=raw_dtype) + bytes_in += int(arr.nbytes) + bytes_out += int(encoded.nbytes) + n_added += 1 + + for src, dst in plan: + add(src, dst) + + if n_added != len(plan): + raise RuntimeError( + f"tensor count mismatch: added {n_added}, planned {len(plan)}") + print(f"Added {n_added} tensors " + f"({bytes_in / (1024 * 1024):.1f} MB fp32 -> " + f"{bytes_out / (1024 * 1024):.1f} MB on disk)") + + print("Writing header + KV + tensor info...") + writer.write_header_to_file() + writer.write_kv_data_to_file() + print("Writing tensor data...") + writer.write_tensors_to_file() + writer.close() + + print(f"Done. Wrote {out_path} " + f"({out_path.stat().st_size / (1024 * 1024):.1f} MB)") + + +# --------------------------------------------------------------------------- +# CLI +# --------------------------------------------------------------------------- + + +def _looks_like_repo_id(s: str) -> bool: + return "/" in s and not Path(s).exists() + + +def _download_snapshot(repo_id: str, revision: str | None, + allow_patterns: list[str] | None = None, + max_workers: int | None = None) -> Path: + slug = slug_from_repo_id(repo_id) + models_root = os.environ.get("TRANSCRIBE_MODELS_DIR") + local_dir = Path(models_root) / slug if models_root and allow_patterns is None else None + if local_dir is not None: + local_dir.mkdir(parents=True, exist_ok=True) + if revision: + print(f"Downloading {repo_id}@{revision} from Hugging Face " + f"(max_workers={max_workers or 'default'})...", flush=True) + else: + print(f"Downloading {repo_id} from Hugging Face " + f"(no revision pin; reproducibility depends on upstream)...", + flush=True) + kwargs: dict = dict( + repo_id=repo_id, + revision=revision, + allow_patterns=allow_patterns, + local_dir=str(local_dir) if local_dir is not None else None, + ) + if max_workers is not None: + kwargs["max_workers"] = max_workers + resolved = snapshot_download(**kwargs) + return Path(resolved) + + +def main(argv: list[str]) -> int: + p = argparse.ArgumentParser( + description="Convert microsoft/VibeVoice-ASR to a BF16 reference GGUF.") + p.add_argument("model", type=str, + help="HF repo id (microsoft/VibeVoice-ASR) or local dir") + p.add_argument("out_path", type=Path, nargs="?", + help="Output .gguf path (derived from --repo-id when omitted)") + p.add_argument("--repo-id", type=str, default=None, + help="HF repo id used to derive the output slug " + "when converting from a local path") + p.add_argument("--revision", type=str, default=None, + help="HF revision (branch / tag / commit SHA) to pin the " + "download to. Ignored when `model` is a local dir.") + p.add_argument("--tokenizer-repo", type=str, default=TOKENIZER_REPO, + help=f"HF repo for the byte-level BPE tokenizer " + f"(default: {TOKENIZER_REPO}).") + p.add_argument("--variant", type=str, default=None, + help="stt.variant string (default: derived from slug)") + p.add_argument("--max-workers", type=int, default=None, + help="cap snapshot_download parallel workers (default: " + "hub default of 8). Lower (e.g. 4) reduces parallel-TLS " + "saturation on a congested link.") + args = p.parse_args(argv[1:]) + + if _looks_like_repo_id(args.model): + repo_id = args.repo_id or args.model + model_dir = _download_snapshot(args.model, args.revision, + max_workers=args.max_workers) + else: + model_dir = Path(args.model) + if not model_dir.is_dir(): + print(f"error: {model_dir} is not a directory and not an HF repo id", + file=sys.stderr) + return 2 + repo_id = args.repo_id + + tok_dir = _download_snapshot(args.tokenizer_repo, None, + allow_patterns=TOKENIZER_FILES) + + out_path = args.out_path + if out_path is None: + if not repo_id: + print("error: provide out_path, --repo-id, or an HF repo id as model", + file=sys.stderr) + return 2 + slug = slug_from_repo_id(repo_id) + out_path = REPO_ROOT / "models" / slug / gguf_name(slug, REFERENCE_DTYPE_LABEL) + out_path.parent.mkdir(parents=True, exist_ok=True) + + variant = args.variant + if variant is None: + variant = slug_from_repo_id(repo_id).lower() if repo_id else "vibevoice-asr" + + convert(model_dir, tok_dir, out_path, variant) + return 0 + + +if __name__ == "__main__": + raise SystemExit(main(sys.argv)) From 56f55f2f1c9d2b1f4b3dee540af0936511ce09ec Mon Sep 17 00:00:00 2001 From: CJ Pais Date: Sat, 27 Jun 2026 00:44:22 -0700 Subject: [PATCH 4/4] partial vibevoice bu --- reports/porting/vibevoice/forward-map.md | 129 +++++++++++ src/CMakeLists.txt | 3 + src/arch/vibevoice/capabilities.cpp | 27 +++ src/arch/vibevoice/model.cpp | 213 +++++++++++++++++ src/arch/vibevoice/vibevoice.h | 206 +++++++++++++++++ src/arch/vibevoice/weights.cpp | 281 +++++++++++++++++++++++ src/transcribe-arch.cpp | 2 + 7 files changed, 861 insertions(+) create mode 100644 reports/porting/vibevoice/forward-map.md create mode 100644 src/arch/vibevoice/capabilities.cpp create mode 100644 src/arch/vibevoice/model.cpp create mode 100644 src/arch/vibevoice/vibevoice.h create mode 100644 src/arch/vibevoice/weights.cpp diff --git a/reports/porting/vibevoice/forward-map.md b/reports/porting/vibevoice/forward-map.md new file mode 100644 index 00000000..5857dbb1 --- /dev/null +++ b/reports/porting/vibevoice/forward-map.md @@ -0,0 +1,129 @@ +# Forward map - vibevoice + +Reference: `models/_vendor/VibeVoice/vibevoice/` (author `vibevoice` package) @ HF rev +`d0c9efdb8d614685062c04425d91e01b6f37d944`. Canonical modules: +`modular/modeling_vibevoice_asr.py`, `modular/modular_vibevoice_tokenizer.py`, +`processor/vibevoice_asr_processor.py`. +Closest in-tree analog: `src/arch/qwen3_asr/` (audio-llm: audio frontend + Qwen causal LM +with audio-token injection). The VAE conv frontend has **no** in-tree analog. + +Audio-LLM. Raw 24 kHz waveform -> two parallel causal-conv VAE encoders (acoustic vae_dim 64, +semantic vae_dim 128) -> SpeechConnector (-> 3584) each -> **element-wise SUM** -> scattered +into the Qwen2.5-7B LM embedding stream at `speech_pad` positions -> 28 Qwen2 layers -> lm_head +-> greedy decode of structured JSON. **Contract uses the acoustic VAE MEAN, never a sample.** + +## Frontend + +| Stage | Reference location | Output shape | Gate tensor | ggml / C++ pattern | In-tree analog | +|-------|--------------------|--------------|-------------|--------------------|----------------| +| Resample to 24 kHz mono | processor `__call__` (librosa load sr=24000) | [samples] | — | host-side resample (input PCM) | qwen3_asr frontend entry | +| AudioNormalizer | `processor/vibevoice_tokenizer_processor.py` AudioNormalizer (target_dB_FS=-25, eps 1e-6): `rms=sqrt(mean(x^2)); x*=10^(-25/20)/(rms+eps)`; then declip `if max(|x|)>1: x/=max(|x|)+eps` | [samples] | `enc.input_waveform` [264000] | host-side scalar pass over PCM (F32); **pin exact 0.0 drift** (env-inject for isolation) | none (new) | + +## Encoder (acoustic + semantic VAE; same structure, different vae_dim / pad) + +Reference: `modular_vibevoice_tokenizer.py` `TokenizerEncoder.forward` + `encode()`. Both encoders +share structure; acoustic vae_dim=64 (std_dist gaussian, fix_std 0.5 — irrelevant, we use mean), +semantic vae_dim=128 (std_dist none). `disable_last_norm=True` -> final norm is Identity. +encoder_ratios=[8,5,5,4,2,2], depths=[3,3,3,3,3,3,8], n_filters=32, layer_scale 1e-6. + +| Stage | Reference location | Output shape | Gate tensor | ggml / C++ pattern | In-tree analog | +|-------|--------------------|--------------|-------------|--------------------|----------------| +| Stem conv (downsample_layers.0) | SConv1d 1->32, k=7, s=1, causal | [32, S] | — | `ggml_conv_1d` w/ causal left-pad `(k-1)-(s-1)=6`, + stride-align right pad; bias add | none (new) | +| Block stack stage[i] (depth 3 or 8) | `Block1D.forward` | [C, S] | — | per-block: see Block1D pattern below | none (new) | +| Downsample conv (layers.1..6) | SConv1d C->2C, k=2·ratio, s=ratio, causal | [2C, S/ratio] | — | `ggml_conv_1d` stride=ratio, causal left-pad `(k-1)-(s-1)`, declip via `get_extra_padding` (ceil align) | none (new) | +| Final norm | `nn.Identity` (disable_last_norm) | [2048, T] | — | no-op | — | +| Head conv | SConv1d 2048->vae_dim, k=7, causal | [vae_dim, T] | — | `ggml_conv_1d` causal | none (new) | +| Permute -> mean | `encode()` returns `latents.permute(0,2,1)` | [T, vae_dim] | `enc.acoustic.mean` [83,64], `enc.semantic.mean` [83,128] | `ggml_cont(ggml_transpose())` | none (new) | + +**Block1D pattern** (`Block1D.forward`, map once): operates on [C, S]. +1. `r=x; x=ConvRMSNorm(x); x=DepthwiseConv(x); x*=gamma[C]; x=r+x` + - ConvRMSNorm: RMS over channel axis per time step (transpose [C,S]->[S,C], RMSNorm dim=C, weight only, eps; transpose back). **eps: confirm 1e-5 vs 1e-6 in code before finalizing.** + - DepthwiseConv (`mixer`, groups=C, k=7, causal, bias): `ggml_conv_1d_dw` (or grouped conv), causal left-pad 6. + - `gamma` is per-channel layer-scale [C], broadcast over S. +2. `r=x; x=ConvRMSNorm_ffn(x); x=permute[C,S]->[S,C]; x=Linear2(GELU(Linear1(x))); permute back; x*=ffn_gamma[C]; x=r+x` + - FFN linear1/linear2 with bias; activation GELU (`ACT2FN["gelu"]`). + +T for jfk = ceil(264000/3200) = 83, matching `vae_tok_len` (count of speech_pad tokens). + +## Decoder (Qwen2.5-7B LM) + +Reference: `modeling_vibevoice_asr.py` forward + the Qwen2 `language_model`. 28 layers, hidden 3584, +heads 28 / kv 4, head_dim 128, intermediate 18944, rope_theta 1e6, rms_norm_eps 1e-6, vocab 152064. + +| Stage | Reference location | Output shape | Gate tensor | ggml / C++ pattern | In-tree analog | +|-------|--------------------|--------------|-------------|--------------------|----------------| +| Connector (×2) | `SpeechConnector`: fc1(vae_dim->3584)->RMSNorm(3584)->fc2(3584->3584) | [T, 3584] | `enc.acoustic.feat`, `enc.semantic.feat` [83,3584] | matmul+bias, RMSNorm, matmul+bias. **confirm no activation between norm and fc2** | qwen3_asr proj | +| Fusion | `combined = a_feat + s_feat` | [T, 3584] | `enc.combined` [83,3584] | `ggml_add` | none | +| Token embed | `embed_tokens(input_ids)` | [L, 3584] | `dec.token_emb` [143,3584]; pin exact 0.0 | `ggml_get_rows`; pure read | qwen3_asr embed | +| Speech scatter | `inputs_embeds[acoustic_input_mask] = combined` (replace speech_pad embeds) | [L, 3584] | `dec.inputs_embeds` [143,3584] | `ggml_set_rows` / masked copy at speech_pad positions | qwen3_asr audio inject | +| Qwen2 layer ×28 | standard Qwen2 block (pattern below) | [L, 3584] | `dec.block.{0,13,27}.out` | attn+rope+ffn (see pattern) | qwen3_asr decoder (adapt) | +| Final RMSNorm | `language_model.norm` | [L, 3584] | `dec.final_norm` [143,3584] | `ggml_rms_norm`×weight | qwen3_asr | +| lm_head | `lm_head` (untied, `dec.output.weight`) | [L, vocab] | `dec.logits_lastpos` [152064] (last pos) | matmul | qwen3_asr | + +**Qwen2 layer pattern** (differs from qwen3_asr — call out in Deviations): +`r=x; x=RMSNorm_attn(x); q=Wq·x+bq; k=Wk·x+bk; v=Wv·x+bv` (GQA 28/4, head_dim 128, **q/k/v have +bias, no q/k-norm**); `rope(q,k, rotate_half, theta=1e6)`; causal SDPA; `x=r+Wo·attn` (Wo no bias); +`r=x; x=RMSNorm_ffn(x); x=r+Wdown(silu(Wgate·x)*Wup·x)`. + +## Generation / KV Path + +| Stage | Reference location | Output shape | Gate tensor | ggml / C++ pattern | In-tree analog | +|-------|--------------------|--------------|-------------|--------------------|----------------| +| Prompt build | processor `__call__` lines ~340-380 | token ids | — | host: `<\|im_start\|>system\n{SYSTEM_PROMPT}<\|im_end\|>\n<\|im_start\|>user\n` + speech_start + speech_pad×T + speech_end + `\nThis is a {dur:.2f} seconds audio, please transcribe it with these keys: Start time, End time, Speaker ID, Content<\|im_end\|>\n<\|im_start\|>assistant\n` | qwen3_asr prompt builder | +| Prefill | model forward, `use_cache` | [L, vocab] | `dec.logits_lastpos` | full causal prefill, KV fill | qwen3_asr prefill | +| Incremental decode | `generate` greedy; speech inputs only when cache_position[0]==0 | 1 tok/step | **`dec.logits_raw.gen` (N≥8) — MUST ADD to dumper + C++** | KV-cache step, argmax, append | qwen3_asr decode | +| Stop | `eos_token_id` (151643) or `stop_strings=["}]"]`, max_new_tokens=448 | — | — | host: eos + JSON-end string match | qwen3_asr stop | + +## Capabilities And Language Controls + +| Capability | Reference behavior | C++ API behavior | Family-doc Capability Validation row | +|------------|--------------------|------------------|--------------------------------------| +| Transcribe (auto lang) | greedy JSON | non-empty plausible transcript | Transcribe — MUST PASS | +| Language detect | implicit (model self-detects) | advertised via `stt.capability.lang_detect` | (covered by transcribe) | +| Segment timestamps | structured Start/End in JSON | parse JSON -> segment times | Segment timestamps — MUST PASS | +| Speaker diarization | Speaker ID in JSON | parse JSON -> speaker labels | Speaker diarization — MUST PASS | +| Translate / word-ts / streaming / hotwords | n/a | n/a | OUT OF SCOPE (per family doc) | +| Batch (offline) | n/a | `run_batch()` parity | Batch (offline) — MUST PASS | + +## Deviations From Closest Analog (qwen3_asr) + +- **Frontend is a learned causal-conv VAE, not a mel/STFT spectrogram.** Entirely new ggml + subsystem: causal SConv1d (left-pad `(k-1)d-(s-1)` + ceil stride-align right pad), depthwise + conv mixer, ConvRMSNorm (norm over channel axis), per-channel layer-scale gamma. No in-tree code. +- **Two parallel encoders + connectors fused by element-wise SUM**, then scattered into the LM at + `speech_pad` positions. qwen3_asr injects a single audio stream. +- **LM is plain Qwen2.5, not Qwen3:** q/k/v carry biases; NO per-head q/k RMSNorm; **plain + rotate_half RoPE (theta 1e6), NOT MRoPE/interleaved** (qwen3_asr uses mrope_section). Untied + lm_head (`dec.output.weight`). +- **Determinism:** use the acoustic VAE mean (`mode`), never `sample` (fix_std=0.5 gaussian). +- **Structured output:** WER scoring needs a normalizer that strips Speaker/Start/End and keeps + Content (Stage 7); segment-ts + diarization are in scope (parse the JSON). + +## Variant Notes + +- `vibevoice-asr`: family baseline (only variant). ~8.3 B params kept, BF16 reference. Long-form + (60-min / 64K KV) deferred; first port targets short utterances (jfk / LibriSpeech segments). + +## Resolved tensor/shape contract (from GGUF inspection) + +- **Downsample strides come from REVERSED encoder_ratios.** Weight shapes (ggml ne + `[k,in,out]`): `downsample.0`=[7,1,32] stem (s1); `downsample.1`=[4,32,64] s2; … ; + `downsample.6`=[16,1024,2048] s8. **kernel = 2·stride for every strided conv**, so the port + derives `stride = kernel/2` from the loaded weight (ordering-agnostic). Stage channels + C[i]=32·2^i for i=0..6 (32,64,128,256,512,1024,2048); stage i runs AFTER downsample i. +- **VAE FFN = 4× expansion + GELU.** `ffn.linear1` C->4C, `ffn.linear2` 4C->C (e.g. 32->128, + 2048->8192). Both carry bias. `ffn_dim = 4*C`. +- Mixer depthwise weight `[7,1,C]` (groups=C, k=7, s1, causal); head `[7,2048,vae_dim]` (k7,s1). +- Connector: `fc1[vae_dim->3584]` -> `RMSNorm[3584]` -> `fc2[3584->3584]`; fc1/fc2 carry bias. + +## Open items (resolve during Step 2, before sign-off) + +- ConvRMSNorm eps (1e-5 config vs 1e-6 Block1D kwarg default) — read the constructed value. +- SpeechConnector: confirm exact op order and whether any activation sits between RMSNorm and fc2. +- `get_extra_padding_for_conv1d` exact arithmetic (right-pad for ceil stride alignment) — must + match so encoder T == ceil(n_samples/3200). +- ggml causal conv: `conf::conv_1d_f32` takes symmetric padding only; left-pad manually + (`ggml_pad`/view) by `(k-1)d-(s-1)` + ceil right-pad, then conv with padding=0. +- Compute location: the 9B LM will not run on this 16 GB machine; `validate.py all` block/logits + gates and the Step 11 WER gate run on **Modal** (encoder-only gates may run locally). ← the + local→Modal boundary; notify the user here. diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c9fd52b1..ba44d287 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -52,6 +52,9 @@ add_library(transcribe arch/qwen3_asr/weights.cpp arch/qwen3_asr/encoder.cpp arch/qwen3_asr/decoder.cpp + arch/vibevoice/model.cpp + arch/vibevoice/capabilities.cpp + arch/vibevoice/weights.cpp arch/voxtral/model.cpp arch/voxtral/capabilities.cpp arch/voxtral/weights.cpp diff --git a/src/arch/vibevoice/capabilities.cpp b/src/arch/vibevoice/capabilities.cpp new file mode 100644 index 00000000..7c803e1a --- /dev/null +++ b/src/arch/vibevoice/capabilities.cpp @@ -0,0 +1,27 @@ +// arch/vibevoice/capabilities.cpp - family invariants. + +#include "vibevoice.h" + +namespace transcribe::vibevoice { + +void apply_family_invariants(transcribe_model & model) { + transcribe_capabilities & caps = model.caps; + + // VibeVoice-ASR ingests raw 24 kHz waveform (no mel frontend). The + // library's run() contract still hands us 16 kHz mono PCM; the family + // resamples to 24 kHz internally before the VAE tokenizers. + caps.native_sample_rate = 24000; + + // The model emits structured Who/When/What JSON with segment-level + // Start/End times. Segment timestamps are surfaced once the structured + // output parser lands (Stage 4); advertise segment granularity. + caps.max_timestamp_kind = TRANSCRIBE_TIMESTAMPS_SEGMENT; + + // Transcribe (incl. implicit language detection + diarization); no + // speech-to-text translation is advertised. + caps.supports_translate = false; + + transcribe::set_feature(&model, TRANSCRIBE_FEATURE_CANCELLATION, true); +} + +} // namespace transcribe::vibevoice diff --git a/src/arch/vibevoice/model.cpp b/src/arch/vibevoice/model.cpp new file mode 100644 index 00000000..880073ee --- /dev/null +++ b/src/arch/vibevoice/model.cpp @@ -0,0 +1,213 @@ +// arch/vibevoice/model.cpp - VibeVoice-ASR family handler. +// +// Phase A: load() is real (reads GGUF KV, tokenizer, hparams, builds the +// tensor catalog, streams weights) so conversion round-trips are verifiable +// before inference lands. init_context() allocates a bare session; run() +// returns TRANSCRIBE_ERR_NOT_IMPLEMENTED until the VAE encoder (Phase B) and +// Qwen2.5 LM (Phase C) graph builders exist. + +#include "vibevoice.h" + +#include "transcribe-arch.h" +#include "transcribe-load-common.h" +#include "transcribe-loader.h" +#include "transcribe-log.h" +#include "transcribe-meta.h" + +#include "ggml.h" +#include "ggml-backend.h" +#include "gguf.h" + +#include +#include +#include +#include + +namespace transcribe::vibevoice { + +extern const Arch arch; + +static_assert(std::is_base_of_v); +static_assert(std::is_base_of_v); + +namespace { +constexpr const char * k_default_variant = "vibevoice-asr"; +} + +VibeVoiceSession::~VibeVoiceSession() { + if (sched != nullptr) { + ggml_backend_sched_free(sched); + sched = nullptr; + } + if (compute_ctx != nullptr) { + ggml_free(compute_ctx); + compute_ctx = nullptr; + } +} + +VibeVoiceModel::~VibeVoiceModel() { + if (ctx_meta != nullptr) { + ggml_free(ctx_meta); + ctx_meta = nullptr; + } + if (backend_buffer != nullptr) { + ggml_backend_buffer_free(backend_buffer); + backend_buffer = nullptr; + } +} + +transcribe_status load( + Loader & loader, + const transcribe_model_load_params * params, + transcribe_model ** out_model) +{ + const int64_t t_load_start = ggml_time_us(); + + auto m = std::make_unique(); + m->arch = &arch; + m->t_load_us = 0; + m->variant = loader.variant().empty() ? k_default_variant : loader.variant(); + m->backend.clear(); + + apply_family_invariants(*m); + m->caps.n_languages = 0; + m->caps.languages = nullptr; + + if (const transcribe_status st = read_capability_kv(loader.gguf(), m->caps); + st != TRANSCRIBE_OK) return st; + if (const transcribe_status st = read_languages_kv(loader.gguf(), *m); + st != TRANSCRIBE_OK) return st; + + // Tokenizer (byte-level BPE; loader handles the "gpt2" model tag). + if (const transcribe_status st = m->tok.load(loader.gguf()); + st != TRANSCRIBE_OK) return st; + + // Chat template (stored now; required at decode time). + (void)read_optional_string_kv( + loader.gguf(), "tokenizer.chat_template", "vibevoice", "", m->chat_template); + + // Hparams. + if (const transcribe_status st = read_vibevoice_hparams(loader.gguf(), m->hparams); + st != TRANSCRIBE_OK) return st; + + m->hparams.vocab_size = m->tok.n_tokens(); + m->hparams.bos_token_id = m->tok.bos_id(); + m->hparams.eos_token_id = m->tok.eos_id(); + + if (m->hparams.vocab_size != m->hparams.dec_vocab_size) { + log_msg(TRANSCRIBE_LOG_LEVEL_ERROR, + "vibevoice: tokenizer vocab (%d) != decoder vocab_size (%d)", + m->hparams.vocab_size, m->hparams.dec_vocab_size); + return TRANSCRIBE_ERR_GGUF; + } + if (m->hparams.eos_token_id < 0) { + log_msg(TRANSCRIBE_LOG_LEVEL_ERROR, + "vibevoice: GGUF tokenizer has no eos_token_id"); + return TRANSCRIBE_ERR_GGUF; + } + + // Reopen with no_alloc to build the tensor catalog. + gguf_init_params init_params {}; + init_params.no_alloc = true; + init_params.ctx = &m->ctx_meta; + + gguf_context * gguf_data = gguf_init_from_file(loader.path().c_str(), init_params); + if (gguf_data == nullptr) { + return TRANSCRIBE_ERR_GGUF; + } + + if (const transcribe_status st = build_vibevoice_weights( + m->ctx_meta, m->hparams, m->weights); + st != TRANSCRIBE_OK) + { + gguf_free(gguf_data); + return st; + } + + // Backend plan. + const transcribe_backend_request backend_req = + (params != nullptr) ? params->backend : TRANSCRIBE_BACKEND_AUTO; + if (const transcribe_status st = transcribe::load_common::init_backends( + backend_req, (params != nullptr) ? params->gpu_device : 0, + "vibevoice", m->plan); + st != TRANSCRIBE_OK) + { + gguf_free(gguf_data); + return st; + } + m->backend = ggml_backend_name(m->plan.primary); + m->primary_backend = m->plan.primary; + + ggml_backend_buffer_t weights_buffer = + ggml_backend_alloc_ctx_tensors(m->ctx_meta, m->plan.primary); + if (weights_buffer == nullptr) { + gguf_free(gguf_data); + log_msg(TRANSCRIBE_LOG_LEVEL_ERROR, + "vibevoice: ggml_backend_alloc_ctx_tensors failed"); + return TRANSCRIBE_ERR_GGUF; + } + m->backend_buffer = weights_buffer; + ggml_backend_buffer_set_usage(weights_buffer, GGML_BACKEND_BUFFER_USAGE_WEIGHTS); + + if (const transcribe_status st = transcribe::load_common::stream_tensor_data( + loader.path(), gguf_data, m->ctx_meta, "vibevoice"); + st != TRANSCRIBE_OK) + { + gguf_free(gguf_data); + return st; + } + gguf_free(gguf_data); + + m->t_load_us = ggml_time_us() - t_load_start; + *out_model = m.release(); + return TRANSCRIBE_OK; +} + +transcribe_status init_context( + transcribe_model * model, + const transcribe_session_params * params, + transcribe_session ** out_ctx) +{ + if (model->arch != &arch) { + return TRANSCRIBE_ERR_INVALID_ARG; + } + + auto cc = std::make_unique(); + cc->model = model; + cc->n_threads = params->n_threads; + cc->kv_type = params->kv_type; + cc->n_ctx = transcribe_session_params_n_ctx(params); + + *out_ctx = cc.release(); + return TRANSCRIBE_OK; +} + +transcribe_status run( + transcribe_session * ctx, + const float * pcm, + int n_samples, + const transcribe_run_params * params) +{ + (void)ctx; + (void)pcm; + (void)n_samples; + (void)params; + // Phase B (VAE encoder) and Phase C (Qwen2.5 LM) land here. + return TRANSCRIBE_ERR_NOT_IMPLEMENTED; +} + +extern const Arch arch = { + /* .name = */ "vibevoice", + /* .load = */ load, + /* .init_context = */ init_context, + /* .run = */ run, + /* .run_batch = */ nullptr, + /* .stream_validate = */ nullptr, + /* .stream_begin = */ nullptr, + /* .stream_feed = */ nullptr, + /* .stream_finalize = */ nullptr, + /* .stream_reset = */ nullptr, + /* .accepts_ext_kind = */ nullptr, +}; + +} // namespace transcribe::vibevoice diff --git a/src/arch/vibevoice/vibevoice.h b/src/arch/vibevoice/vibevoice.h new file mode 100644 index 00000000..bf5eaf3b --- /dev/null +++ b/src/arch/vibevoice/vibevoice.h @@ -0,0 +1,206 @@ +// arch/vibevoice/vibevoice.h - VibeVoice-ASR model/context types, hparams, +// and tensor catalog. +// +// INTERNAL to src/arch/vibevoice/. Audio-LLM: raw 24 kHz waveform -> two +// parallel causal-conv VAE encoders (acoustic vae_dim 64, semantic vae_dim +// 128) -> SpeechConnector (-> 3584) each -> element-wise SUM -> scattered +// into a Qwen2.5-7B causal LM at the speech_pad positions -> lm_head. +// +// Tensor naming mirrors scripts/convert-vibevoice.py: +// enc.{acoustic,semantic}.* VAE encoder (causal SConv1d stem + 6 strided +// downsample convs, 7 Block1D stages, head) +// conn.{acoustic,semantic}.* SpeechConnector (fc1 -> RMSNorm -> fc2) +// dec.* Qwen2.5 LM (28 layers, GQA 28/4, q/k/v biases, +// plain rotate_half RoPE, untied lm_head) + +#pragma once + +#include "transcribe-backend.h" +#include "transcribe-session.h" +#include "transcribe-model.h" +#include "transcribe-tokenizer.h" + +#include "ggml.h" +#include "ggml-backend.h" + +#include +#include +#include + +struct gguf_context; +struct ggml_context; +struct ggml_tensor; + +namespace transcribe::vibevoice { + +void apply_family_invariants(transcribe_model & model); + +// --------------------------------------------------------------------------- +// Hyperparameters +// --------------------------------------------------------------------------- + +// Per-stream VAE encoder config (acoustic and semantic share structure). +struct VaeHParams { + int32_t vae_dim = 0; // 64 acoustic / 128 semantic + int32_t n_filters = 0; // stem output channels (32); stage i has 32*2^i + std::vector depths; // parsed "3-3-3-3-3-3-8" -> blocks per stage + float layernorm_eps = 1e-5f; + float layer_scale_init = 1e-6f; + float fix_std = 0.0f; // acoustic 0.5 (unused: we take the mean) + std::string std_dist_type; // "gaussian" / "none" + std::string mixer; // "depthwise_conv" + std::string layernorm; // "RMSNorm" + std::string pad_mode; // "constant" + bool causal = true; + bool disable_last_norm = true; // final encoder norm is Identity + bool conv_bias = true; +}; + +struct VibeVoiceHParams { + // Qwen2.5 LM. + int32_t dec_n_layers = 0; + int32_t dec_hidden = 0; + int32_t dec_intermediate = 0; + int32_t dec_n_heads = 0; + int32_t dec_n_kv_heads = 0; + int32_t dec_head_dim = 0; + std::string dec_hidden_act; // "silu" + float dec_rms_norm_eps = 0.0f; + float dec_rope_theta = 0.0f; + int32_t dec_max_position_embeddings = 0; + bool dec_tie_word_embeddings = false; + int32_t dec_vocab_size = 0; + + // VAE encoders. + VaeHParams acoustic; + VaeHParams semantic; + + // Speech fusion + prompt metadata. + int32_t speech_start_token_id = -1; + int32_t speech_end_token_id = -1; + int32_t speech_pad_token_id = -1; + int32_t im_start_token_id = -1; + int32_t im_end_token_id = -1; + int32_t speech_tok_compress_ratio = 0; + + // Frontend (raw 24 kHz waveform; no STFT/mel). + int32_t frontend_sample_rate = 0; + + // Resolved from tokenizer KV at load time. + int32_t bos_token_id = -1; + int32_t eos_token_id = -1; + int32_t vocab_size = 0; +}; + +transcribe_status read_vibevoice_hparams(const gguf_context * gguf, + VibeVoiceHParams & hp); + +// --------------------------------------------------------------------------- +// Weight slots - VAE encoders (acoustic + semantic) +// --------------------------------------------------------------------------- + +// A causal SConv1d (kernel ne = [K, in_ch, out_ch]); strided downsample convs +// derive stride = K/2 at graph-build time. +struct VaeConv { + ggml_tensor * w = nullptr; + ggml_tensor * b = nullptr; +}; + +// One Block1D: ConvRMSNorm -> depthwise-conv mixer -> gamma -> residual, +// then ConvRMSNorm -> FFN(linear1 -> GELU -> linear2) -> ffn_gamma -> residual. +struct VaeBlock { + ggml_tensor * norm_w = nullptr; // ConvRMSNorm (mixer path) + VaeConv mixer; // depthwise conv (groups=C, k=7) + ggml_tensor * gamma = nullptr; // per-channel layer scale [C] + ggml_tensor * ffn_norm_w = nullptr; + ggml_tensor * ffn_lin1_w = nullptr; // [C, 4C] + ggml_tensor * ffn_lin1_b = nullptr; + ggml_tensor * ffn_lin2_w = nullptr; // [4C, C] + ggml_tensor * ffn_lin2_b = nullptr; + ggml_tensor * ffn_gamma = nullptr; // [C] +}; + +struct VaeEncoderWeights { + std::vector downsample; // [0]=stem, [1..]=strided + std::vector> stages; // per stage, per block + VaeConv head; // SConv1d -> vae_dim + // final encoder norm is Identity (disable_last_norm) -> no slot +}; + +// SpeechConnector: fc1 (vae_dim -> hidden) -> RMSNorm(hidden) -> fc2. +struct ConnectorWeights { + ggml_tensor * fc1_w = nullptr; + ggml_tensor * fc1_b = nullptr; + ggml_tensor * norm_w = nullptr; + ggml_tensor * fc2_w = nullptr; + ggml_tensor * fc2_b = nullptr; +}; + +// --------------------------------------------------------------------------- +// Weight slots - Qwen2.5 LM +// --------------------------------------------------------------------------- + +struct VibeVoiceDecBlock { + ggml_tensor * norm_attn_w = nullptr; // input_layernorm (RMSNorm) + // Qwen2: q/k/v carry biases; o_proj has no bias. + ggml_tensor * attn_q_w = nullptr; + ggml_tensor * attn_q_b = nullptr; + ggml_tensor * attn_k_w = nullptr; + ggml_tensor * attn_k_b = nullptr; + ggml_tensor * attn_v_w = nullptr; + ggml_tensor * attn_v_b = nullptr; + ggml_tensor * attn_o_w = nullptr; + ggml_tensor * norm_ffn_w = nullptr; // post_attention_layernorm + ggml_tensor * ffn_gate_w = nullptr; + ggml_tensor * ffn_up_w = nullptr; + ggml_tensor * ffn_down_w = nullptr; +}; + +struct VibeVoiceWeights { + VaeEncoderWeights enc_acoustic; + VaeEncoderWeights enc_semantic; + ConnectorWeights conn_acoustic; + ConnectorWeights conn_semantic; + + ggml_tensor * dec_token_embd = nullptr; // [hidden, vocab] + std::vector dec_blocks; + ggml_tensor * dec_output_norm = nullptr; // RMSNorm before lm_head + ggml_tensor * dec_output = nullptr; // untied lm_head [hidden, vocab] +}; + +transcribe_status build_vibevoice_weights(ggml_context * ctx_meta, + const VibeVoiceHParams & hp, + VibeVoiceWeights & weights); + +// --------------------------------------------------------------------------- +// Model / Context +// --------------------------------------------------------------------------- + +struct VibeVoiceModel final : public transcribe_model { + Tokenizer tok; + VibeVoiceHParams hparams; + VibeVoiceWeights weights; + ggml_context * ctx_meta = nullptr; + + transcribe::BackendPlan plan; + ggml_backend_buffer_t backend_buffer = nullptr; + + std::string chat_template; + + VibeVoiceModel() = default; + ~VibeVoiceModel() override; + + const transcribe::Tokenizer * tokenizer() const override { return &tok; } +}; + +struct VibeVoiceSession final : public transcribe_session { + ggml_context * compute_ctx = nullptr; + ggml_backend_sched_t sched = nullptr; + + std::vector enc_host; // VAE-combined features, host-side + + VibeVoiceSession() = default; + ~VibeVoiceSession() override; +}; + +} // namespace transcribe::vibevoice diff --git a/src/arch/vibevoice/weights.cpp b/src/arch/vibevoice/weights.cpp new file mode 100644 index 00000000..df4357ba --- /dev/null +++ b/src/arch/vibevoice/weights.cpp @@ -0,0 +1,281 @@ +// arch/vibevoice/weights.cpp - read_vibevoice_hparams + build_vibevoice_weights. +// +// Mirrors arch/qwen3_asr/weights.cpp: every required hparam is read +// explicitly (BadType fatal); the tensor catalog is a sequence of +// find_tensor() calls with expected shapes. The converter's tensor names +// (scripts/convert-vibevoice.py) are the contract. +// +// VAE conv kernels: stride is NOT stored — it is derived from the kernel at +// graph-build time (kernel = 2*stride for the strided downsample convs). The +// loader therefore validates only the channel dims (ne[1], ne[2]) against the +// known stage channels and accepts the kernel (ne[0]) the file carries. + +#include "vibevoice.h" + +#include "transcribe-meta.h" +#include "transcribe-weights-util.h" +#include "transcribe-log.h" + +#include "ggml.h" +#include "gguf.h" + +#include +#include +#include +#include + +namespace transcribe::vibevoice { + +using transcribe::weights::find_tensor; +using transcribe::weights::lname; + +namespace { +constexpr const char * kFamilyTag = "vibevoice"; + +// Split an "a-b-c" depths string into ints. Returns false on a malformed +// entry (empty / non-numeric). +bool parse_depths(const std::string & s, std::vector & out) { + out.clear(); + size_t i = 0; + while (i < s.size()) { + size_t j = s.find('-', i); + if (j == std::string::npos) j = s.size(); + const std::string tok = s.substr(i, j - i); + if (tok.empty()) return false; + char * end = nullptr; + const long v = std::strtol(tok.c_str(), &end, 10); + if (end == tok.c_str() || *end != '\0' || v <= 0) return false; + out.push_back(static_cast(v)); + i = j + 1; + } + return !out.empty(); +} + +transcribe_status read_vae_hparams(const gguf_context * gguf, + const char * stream, VaeHParams & v) { + char key[128]; + auto K = [&](const char * suffix) -> const char * { + std::snprintf(key, sizeof key, "stt.vibevoice.%s.%s", stream, suffix); + return key; + }; + if (auto st = read_required_u32_kv(gguf, K("vae_dim"), kFamilyTag, v.vae_dim); st != TRANSCRIBE_OK) return st; + if (auto st = read_required_u32_kv(gguf, K("n_filters"), kFamilyTag, v.n_filters); st != TRANSCRIBE_OK) return st; + + std::string depths_str; + if (auto st = read_required_string_kv(gguf, K("encoder_depths"), kFamilyTag, depths_str); st != TRANSCRIBE_OK) return st; + if (!parse_depths(depths_str, v.depths)) { + log_msg(TRANSCRIBE_LOG_LEVEL_ERROR, + "%s: malformed encoder_depths '%s' for %s", kFamilyTag, + depths_str.c_str(), stream); + return TRANSCRIBE_ERR_GGUF; + } + + if (auto st = read_required_string_kv(gguf, K("mixer_layer"), kFamilyTag, v.mixer); st != TRANSCRIBE_OK) return st; + if (auto st = read_required_string_kv(gguf, K("layernorm"), kFamilyTag, v.layernorm); st != TRANSCRIBE_OK) return st; + if (auto st = read_required_f32_kv (gguf, K("layernorm_eps"), kFamilyTag, v.layernorm_eps); st != TRANSCRIBE_OK) return st; + if (auto st = read_required_f32_kv (gguf, K("layer_scale_init"),kFamilyTag, v.layer_scale_init); st != TRANSCRIBE_OK) return st; + if (auto st = read_required_f32_kv (gguf, K("fix_std"), kFamilyTag, v.fix_std); st != TRANSCRIBE_OK) return st; + if (auto st = read_required_string_kv(gguf, K("std_dist_type"), kFamilyTag, v.std_dist_type); st != TRANSCRIBE_OK) return st; + if (auto st = read_required_string_kv(gguf, K("pad_mode"), kFamilyTag, v.pad_mode); st != TRANSCRIBE_OK) return st; + if (auto st = read_optional_bool_kv (gguf, K("causal"), kFamilyTag, true, v.causal); st != TRANSCRIBE_OK) return st; + if (auto st = read_optional_bool_kv (gguf, K("disable_last_norm"), kFamilyTag, true, v.disable_last_norm); st != TRANSCRIBE_OK) return st; + if (auto st = read_optional_bool_kv (gguf, K("conv_bias"), kFamilyTag, true, v.conv_bias); st != TRANSCRIBE_OK) return st; + return TRANSCRIBE_OK; +} +} // namespace + +transcribe_status read_vibevoice_hparams(const gguf_context * gguf, + VibeVoiceHParams & hp) { + if (gguf == nullptr) return TRANSCRIBE_ERR_INVALID_ARG; + + // Qwen2.5 LM. + if (auto st = read_required_u32_kv(gguf, "stt.vibevoice.decoder.n_layers", kFamilyTag, hp.dec_n_layers); st != TRANSCRIBE_OK) return st; + if (auto st = read_required_u32_kv(gguf, "stt.vibevoice.decoder.hidden_size", kFamilyTag, hp.dec_hidden); st != TRANSCRIBE_OK) return st; + if (auto st = read_required_u32_kv(gguf, "stt.vibevoice.decoder.intermediate_size", kFamilyTag, hp.dec_intermediate); st != TRANSCRIBE_OK) return st; + if (auto st = read_required_u32_kv(gguf, "stt.vibevoice.decoder.n_heads", kFamilyTag, hp.dec_n_heads); st != TRANSCRIBE_OK) return st; + if (auto st = read_required_u32_kv(gguf, "stt.vibevoice.decoder.n_kv_heads", kFamilyTag, hp.dec_n_kv_heads); st != TRANSCRIBE_OK) return st; + if (auto st = read_required_u32_kv(gguf, "stt.vibevoice.decoder.head_dim", kFamilyTag, hp.dec_head_dim); st != TRANSCRIBE_OK) return st; + if (auto st = read_required_string_kv(gguf, "stt.vibevoice.decoder.hidden_act", kFamilyTag, hp.dec_hidden_act); st != TRANSCRIBE_OK) return st; + if (auto st = read_required_f32_kv(gguf, "stt.vibevoice.decoder.rms_norm_eps", kFamilyTag, hp.dec_rms_norm_eps); st != TRANSCRIBE_OK) return st; + if (auto st = read_required_f32_kv(gguf, "stt.vibevoice.decoder.rope_theta", kFamilyTag, hp.dec_rope_theta); st != TRANSCRIBE_OK) return st; + if (auto st = read_required_u32_kv(gguf, "stt.vibevoice.decoder.max_position_embeddings", kFamilyTag, hp.dec_max_position_embeddings); st != TRANSCRIBE_OK) return st; + if (auto st = read_optional_bool_kv(gguf, "stt.vibevoice.decoder.tie_word_embeddings", kFamilyTag, false, hp.dec_tie_word_embeddings); st != TRANSCRIBE_OK) return st; + if (auto st = read_required_u32_kv(gguf, "stt.vibevoice.decoder.vocab_size", kFamilyTag, hp.dec_vocab_size); st != TRANSCRIBE_OK) return st; + + // VAE encoders. + if (auto st = read_vae_hparams(gguf, "acoustic", hp.acoustic); st != TRANSCRIBE_OK) return st; + if (auto st = read_vae_hparams(gguf, "semantic", hp.semantic); st != TRANSCRIBE_OK) return st; + + // Speech fusion / prompt metadata. + if (auto st = read_required_u32_kv(gguf, "stt.vibevoice.speech_start_token_id", kFamilyTag, hp.speech_start_token_id); st != TRANSCRIBE_OK) return st; + if (auto st = read_required_u32_kv(gguf, "stt.vibevoice.speech_end_token_id", kFamilyTag, hp.speech_end_token_id); st != TRANSCRIBE_OK) return st; + if (auto st = read_required_u32_kv(gguf, "stt.vibevoice.speech_pad_token_id", kFamilyTag, hp.speech_pad_token_id); st != TRANSCRIBE_OK) return st; + if (auto st = read_required_u32_kv(gguf, "stt.vibevoice.im_start_token_id", kFamilyTag, hp.im_start_token_id); st != TRANSCRIBE_OK) return st; + if (auto st = read_required_u32_kv(gguf, "stt.vibevoice.im_end_token_id", kFamilyTag, hp.im_end_token_id); st != TRANSCRIBE_OK) return st; + if (auto st = read_required_u32_kv(gguf, "stt.vibevoice.speech_tok_compress_ratio", kFamilyTag, hp.speech_tok_compress_ratio); st != TRANSCRIBE_OK) return st; + + // Frontend (raw waveform). + if (auto st = read_required_u32_kv(gguf, "stt.frontend.sample_rate", kFamilyTag, hp.frontend_sample_rate); st != TRANSCRIBE_OK) return st; + + // Sanity. + if (hp.dec_n_layers <= 0 || hp.dec_hidden <= 0 || hp.dec_n_heads <= 0 || + hp.dec_n_kv_heads <= 0 || hp.dec_head_dim <= 0 || hp.dec_intermediate <= 0) { + log_msg(TRANSCRIBE_LOG_LEVEL_ERROR, "%s: invalid decoder hparams", kFamilyTag); + return TRANSCRIBE_ERR_GGUF; + } + if (hp.dec_n_heads % hp.dec_n_kv_heads != 0) { + log_msg(TRANSCRIBE_LOG_LEVEL_ERROR, + "%s: n_heads (%d) not divisible by n_kv_heads (%d)", + kFamilyTag, hp.dec_n_heads, hp.dec_n_kv_heads); + return TRANSCRIBE_ERR_GGUF; + } + if (hp.acoustic.depths.size() != hp.semantic.depths.size()) { + log_msg(TRANSCRIBE_LOG_LEVEL_ERROR, "%s: acoustic/semantic stage count mismatch", kFamilyTag); + return TRANSCRIBE_ERR_GGUF; + } + return TRANSCRIBE_OK; +} + +// --------------------------------------------------------------------------- +// Tensor catalog +// --------------------------------------------------------------------------- + +#define GET_F32(slot, name, ...) \ + do { \ + ggml_tensor * _t = find_tensor(ctx_meta, (name), \ + {GGML_TYPE_F32}, {__VA_ARGS__}, kFamilyTag); \ + if (_t == nullptr) return TRANSCRIBE_ERR_GGUF; \ + (slot) = _t; \ + } while (0) + +#define GET_LIN(slot, name, ...) \ + do { \ + ggml_tensor * _t = find_tensor(ctx_meta, (name), \ + {TRANSCRIBE_QUANT_LINEAR_TYPES}, {__VA_ARGS__}, kFamilyTag); \ + if (_t == nullptr) return TRANSCRIBE_ERR_GGUF; \ + (slot) = _t; \ + } while (0) + +// Conv kernel: validate channel dims, accept the file's kernel size (ne[0]). +#define GET_CONV(slot, name, in_ch, out_ch) \ + do { \ + ggml_tensor * _p = ggml_get_tensor(ctx_meta, (name)); \ + if (_p == nullptr) { \ + log_msg(TRANSCRIBE_LOG_LEVEL_ERROR, "%s: missing tensor %s", \ + kFamilyTag, (name)); \ + return TRANSCRIBE_ERR_GGUF; \ + } \ + ggml_tensor * _t = find_tensor(ctx_meta, (name), \ + {TRANSCRIBE_QUANT_CONV_TYPES}, \ + {_p->ne[0], (int64_t)(in_ch), (int64_t)(out_ch)}, kFamilyTag); \ + if (_t == nullptr) return TRANSCRIBE_ERR_GGUF; \ + (slot) = _t; \ + } while (0) + +namespace { + +transcribe_status build_vae_encoder(ggml_context * ctx_meta, const char * stream, + const VaeHParams & v, VaeEncoderWeights & w) { + char nm[176]; + const int n_stage = static_cast(v.depths.size()); + const int nf = v.n_filters; + auto chan = [&](int i) -> int64_t { return static_cast(nf) << i; }; // nf * 2^i + + // Downsample layers: [0] stem (1 -> nf, stride 1); [i] strided (C[i-1] -> C[i]). + w.downsample.resize(n_stage); + for (int i = 0; i < n_stage; ++i) { + const int64_t in_ch = (i == 0) ? 1 : chan(i - 1); + const int64_t out_ch = chan(i); + std::snprintf(nm, sizeof nm, "enc.%s.downsample_layers.%d.0.conv.conv.weight", stream, i); + GET_CONV(w.downsample[i].w, nm, in_ch, out_ch); + std::snprintf(nm, sizeof nm, "enc.%s.downsample_layers.%d.0.conv.conv.bias", stream, i); + GET_F32(w.downsample[i].b, nm, out_ch); + } + + // Stages: per stage i (channels C[i]), v.depths[i] Block1D blocks. + w.stages.resize(n_stage); + for (int i = 0; i < n_stage; ++i) { + const int64_t C = chan(i); + const int depth = v.depths[i]; + w.stages[i].resize(depth); + for (int j = 0; j < depth; ++j) { + VaeBlock & b = w.stages[i][j]; + std::snprintf(nm, sizeof nm, "enc.%s.stages.%d.%d.norm.weight", stream, i, j); GET_F32(b.norm_w, nm, C); + std::snprintf(nm, sizeof nm, "enc.%s.stages.%d.%d.mixer.conv.conv.conv.weight", stream, i, j); GET_CONV(b.mixer.w, nm, 1, C); + std::snprintf(nm, sizeof nm, "enc.%s.stages.%d.%d.mixer.conv.conv.conv.bias", stream, i, j); GET_F32(b.mixer.b, nm, C); + std::snprintf(nm, sizeof nm, "enc.%s.stages.%d.%d.gamma", stream, i, j); GET_F32(b.gamma, nm, C); + std::snprintf(nm, sizeof nm, "enc.%s.stages.%d.%d.ffn_norm.weight", stream, i, j); GET_F32(b.ffn_norm_w, nm, C); + std::snprintf(nm, sizeof nm, "enc.%s.stages.%d.%d.ffn.linear1.weight", stream, i, j); GET_LIN(b.ffn_lin1_w, nm, C, 4 * C); + std::snprintf(nm, sizeof nm, "enc.%s.stages.%d.%d.ffn.linear1.bias", stream, i, j); GET_F32(b.ffn_lin1_b, nm, 4 * C); + std::snprintf(nm, sizeof nm, "enc.%s.stages.%d.%d.ffn.linear2.weight", stream, i, j); GET_LIN(b.ffn_lin2_w, nm, 4 * C, C); + std::snprintf(nm, sizeof nm, "enc.%s.stages.%d.%d.ffn.linear2.bias", stream, i, j); GET_F32(b.ffn_lin2_b, nm, C); + std::snprintf(nm, sizeof nm, "enc.%s.stages.%d.%d.ffn_gamma", stream, i, j); GET_F32(b.ffn_gamma, nm, C); + } + } + + // Head: SConv1d C_last -> vae_dim. + const int64_t C_last = chan(n_stage - 1); + std::snprintf(nm, sizeof nm, "enc.%s.head.conv.conv.weight", stream); GET_CONV(w.head.w, nm, C_last, v.vae_dim); + std::snprintf(nm, sizeof nm, "enc.%s.head.conv.conv.bias", stream); GET_F32(w.head.b, nm, v.vae_dim); + return TRANSCRIBE_OK; +} + +transcribe_status build_connector(ggml_context * ctx_meta, const char * stream, + int64_t vae_dim, int64_t hidden, ConnectorWeights & c) { + char nm[128]; + std::snprintf(nm, sizeof nm, "conn.%s.fc1.weight", stream); GET_LIN(c.fc1_w, nm, vae_dim, hidden); + std::snprintf(nm, sizeof nm, "conn.%s.fc1.bias", stream); GET_F32(c.fc1_b, nm, hidden); + std::snprintf(nm, sizeof nm, "conn.%s.norm.weight", stream); GET_F32(c.norm_w, nm, hidden); + std::snprintf(nm, sizeof nm, "conn.%s.fc2.weight", stream); GET_LIN(c.fc2_w, nm, hidden, hidden); + std::snprintf(nm, sizeof nm, "conn.%s.fc2.bias", stream); GET_F32(c.fc2_b, nm, hidden); + return TRANSCRIBE_OK; +} +} // namespace + +transcribe_status build_vibevoice_weights(ggml_context * ctx_meta, + const VibeVoiceHParams & hp, + VibeVoiceWeights & weights) { + if (ctx_meta == nullptr) return TRANSCRIBE_ERR_INVALID_ARG; + + // VAE encoders + connectors. + if (auto st = build_vae_encoder(ctx_meta, "acoustic", hp.acoustic, weights.enc_acoustic); st != TRANSCRIBE_OK) return st; + if (auto st = build_vae_encoder(ctx_meta, "semantic", hp.semantic, weights.enc_semantic); st != TRANSCRIBE_OK) return st; + if (auto st = build_connector(ctx_meta, "acoustic", hp.acoustic.vae_dim, hp.dec_hidden, weights.conn_acoustic); st != TRANSCRIBE_OK) return st; + if (auto st = build_connector(ctx_meta, "semantic", hp.semantic.vae_dim, hp.dec_hidden, weights.conn_semantic); st != TRANSCRIBE_OK) return st; + + // Qwen2.5 LM. + const int64_t hidden = hp.dec_hidden; + const int64_t vocab = hp.dec_vocab_size; + const int64_t q_out = static_cast(hp.dec_n_heads) * hp.dec_head_dim; + const int64_t kv_out = static_cast(hp.dec_n_kv_heads) * hp.dec_head_dim; + const int64_t ffn = hp.dec_intermediate; + + GET_LIN(weights.dec_token_embd, "dec.token_embd.weight", hidden, vocab); + + weights.dec_blocks.resize(hp.dec_n_layers); + for (int i = 0; i < hp.dec_n_layers; ++i) { + VibeVoiceDecBlock & b = weights.dec_blocks[i]; + GET_F32(b.norm_attn_w, lname("dec.blocks.%d.norm_attn.weight", i), hidden); + GET_LIN(b.attn_q_w, lname("dec.blocks.%d.attn.q.weight", i), hidden, q_out); + GET_F32(b.attn_q_b, lname("dec.blocks.%d.attn.q.bias", i), q_out); + GET_LIN(b.attn_k_w, lname("dec.blocks.%d.attn.k.weight", i), hidden, kv_out); + GET_F32(b.attn_k_b, lname("dec.blocks.%d.attn.k.bias", i), kv_out); + GET_LIN(b.attn_v_w, lname("dec.blocks.%d.attn.v.weight", i), hidden, kv_out); + GET_F32(b.attn_v_b, lname("dec.blocks.%d.attn.v.bias", i), kv_out); + GET_LIN(b.attn_o_w, lname("dec.blocks.%d.attn.o.weight", i), q_out, hidden); + GET_F32(b.norm_ffn_w, lname("dec.blocks.%d.norm_ffn.weight", i), hidden); + GET_LIN(b.ffn_gate_w, lname("dec.blocks.%d.ffn.gate.weight", i), hidden, ffn); + GET_LIN(b.ffn_up_w, lname("dec.blocks.%d.ffn.up.weight", i), hidden, ffn); + GET_LIN(b.ffn_down_w, lname("dec.blocks.%d.ffn.down.weight", i), ffn, hidden); + } + + GET_F32(weights.dec_output_norm, "dec.output_norm.weight", hidden); + GET_LIN(weights.dec_output, "dec.output.weight", hidden, vocab); + return TRANSCRIBE_OK; +} + +#undef GET_F32 +#undef GET_LIN +#undef GET_CONV + +} // namespace transcribe::vibevoice diff --git a/src/transcribe-arch.cpp b/src/transcribe-arch.cpp index fbbfdaa0..c41d46ed 100644 --- a/src/transcribe-arch.cpp +++ b/src/transcribe-arch.cpp @@ -34,6 +34,7 @@ namespace gigaam { extern const Arch arch; } namespace granite { extern const Arch arch; } namespace granite_nar { extern const Arch arch; } namespace medasr { extern const Arch arch; } +namespace vibevoice { extern const Arch arch; } const Arch * find_arch(const char * name) { if (name == nullptr) { @@ -57,6 +58,7 @@ const Arch * find_arch(const char * name) { &granite::arch, &granite_nar::arch, &medasr::arch, + &vibevoice::arch, }; constexpr size_t k_n = sizeof(k_archs) / sizeof(k_archs[0]);