diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..9f6719f --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "MioCodec"] + path = MioCodec + url = https://github.com/Aratako/MioCodec diff --git a/MioCodec b/MioCodec new file mode 160000 index 0000000..7747354 --- /dev/null +++ b/MioCodec @@ -0,0 +1 @@ +Subproject commit 77473544375d57e96cbdfd5d7d257e8f280fa8e3 diff --git a/__pycache__/infer.cpython-312.pyc b/__pycache__/infer.cpython-312.pyc deleted file mode 100644 index 05539bf..0000000 Binary files a/__pycache__/infer.cpython-312.pyc and /dev/null differ diff --git a/live.py b/live.py new file mode 100644 index 0000000..5cec234 --- /dev/null +++ b/live.py @@ -0,0 +1,413 @@ +import argparse +import math +import queue +import threading +import time +from pathlib import Path + +import numpy as np +import sounddevice as sd +import soundfile as sf +import torch +import torch.nn as nn +import torch.nn.functional as F + +import torchaudio + +from miocodec.model import MioCodecModel + +DEVICE = torch.device("cuda" if torch.cuda.is_available() else "cpu") +import gc + +class StreamingISTFT: + def __init__(self, n_fft, hop, device): + self.n_fft = n_fft + self.win = n_fft + self.hop = hop + self.pad = (self.win - hop) // 2 + self.window = torch.hann_window(self.win, device=device) + self.win_sq = (self.window**2).view(1, -1, 1) + self.carry = self.win - self.hop + self.tail_y = torch.zeros(1, 0, device=device) + self.tail_e = torch.zeros(1, 0, device=device) + self.started = False + + def reset(self): + self.tail_y = self.tail_y[:, :0] + self.tail_e = self.tail_e[:, :0] + self.started = False + + def process(self, spec): + T = spec.shape[-1] + ifft = torch.fft.irfft(spec, self.n_fft, dim=1, norm="backward") * self.window.view(1, -1, 1) + region = (T - 1) * self.hop + self.win + y = F.fold(ifft, (1, region), (1, self.win), stride=(1, self.hop))[:, 0, 0, :] + e = F.fold(self.win_sq.expand(1, self.win, T), (1, region), (1, self.win), stride=(1, self.hop))[:, 0, 0, :] + tl = self.tail_y.shape[-1] + if tl: + y[:, :tl] += self.tail_y + e[:, :tl] += self.tail_e + emit = region - self.carry + out = y[:, :emit] / e[:, :emit].clamp(min=1e-8) + self.tail_y = y[:, emit:].clone() + self.tail_e = e[:, emit:].clone() + if not self.started: + out = out[:, self.pad:] + self.started = True + return out.squeeze(0) + + +class StreamingVC: + def __init__(self, model, device, *, chunk=6, enc_left=48, enc_right=2, + dec_left=32, dec_right=3, ema_alpha=0.9): + self.m = model.to(device).eval() + self.dev = device + + c = model.config + ssl_fps = self.m.ssl_feature_extractor.ssl_sample_rate // self.m.ssl_feature_extractor.hop_size + self.token_hz = ssl_fps // c.downsample_factor + self.sr = c.sample_rate + self.tok_samples = self.sr // self.token_hz + ups_total = self.m.wave_upsampler.total_upsample_factor + self.frames_per_tok = c.wave_upsample_factor * ups_total + assert self.frames_per_tok * c.hop_length == self.tok_samples, "token/frame/sample ratios disagree" + + self.chunk = chunk + self.enc_left, self.enc_right = enc_left, enc_right + self.dec_left, self.dec_right = dec_left, dec_right + self.local_layers = list(self.m.local_ssl_layers) + + self.istft = StreamingISTFT(c.n_fft, c.hop_length, device) + self.global_emb = None + self.src_mean = self.src_std = None + self.tokens = None + self.decoded = 0 + + self.ema_alpha = ema_alpha + self.prev_local_feats = None + + def _raw_local(self, audio): + feats = self.m.ssl_feature_extractor(audio.to(self.dev)) + sel = [feats[i - 1] for i in self.local_layers] + return torch.stack(sel, 0).mean(0) if len(sel) > 1 else sel[0] + + def apply_ema(self, local_feats): + if self.prev_local_feats is not None and local_feats.shape == self.prev_local_feats.shape: + local_feats = self.ema_alpha * local_feats + (1.0 - self.ema_alpha) * self.prev_local_feats + self.prev_local_feats = local_feats.clone() + return local_feats + + @torch.inference_mode() + def set_target(self, ref_audio): + feats = self.m.encode(ref_audio.to(self.dev), return_content=False, return_global=True) + self.global_emb = feats.global_embedding.view(1, -1) + + def _encode_features(self, loc): + loc_norm = (loc - self.src_mean) / (self.src_std + 1e-8) + enc = self.m.local_encoder(loc_norm) + enc = self.m.conv_downsample(enc.transpose(1, 2)).transpose(1, 2) + _, idx = self.m.local_quantizer.encode(enc) + return idx + + @torch.inference_mode() + def seed(self, seed_audio): + self.reset() + if seed_audio.dim() == 1: + seed_audio = seed_audio.unsqueeze(0) + + loc = self._raw_local(seed_audio) + self.src_mean = loc.mean(dim=1, keepdim=True).clone() + self.src_std = loc.std(dim=1, keepdim=True).clone() + + idx = self._encode_features(loc) + self.tokens = idx.clone() + self.decoded = idx.shape[1] + + def reset(self): + self.istft.reset() + self.tokens = None + self.decoded = 0 + self.prev_local_feats = None + + @torch.inference_mode() + def _encode(self, window_audio): + loc = self._raw_local(window_audio) + loc = self.apply_ema(loc) + return self._encode_features(loc) + + @torch.inference_mode() + def _wave_stages(self, tok_window): + Tw = tok_window.shape[1] + emb = self.m.local_quantizer.decode(tok_window) + x = self.m.wave_prenet(emb) + x = self.m.wave_conv_upsample(x.transpose(1, 2)).transpose(1, 2) + x = F.interpolate(x.transpose(1, 2), size=2 * Tw, mode=self.m.config.wave_interpolation_mode).transpose(1, 2) + x = self.m.wave_prior_net(x.transpose(1, 2)).transpose(1, 2) + x = self.m.wave_decoder(x, condition=self.global_emb.unsqueeze(1)) + x = self.m.wave_post_net(x.transpose(1, 2)).transpose(1, 2) + return self.m.wave_upsampler(x.transpose(1, 2)) + + @torch.inference_mode() + def _decode(self, tok_window, keep_left, keep_n): + x = self._wave_stages(tok_window) + h = self.m.istft_head.out(x).transpose(1, 2) + mag, phase = h.chunk(2, dim=1) + mag = torch.exp(mag).clamp(max=1e2) + spec = torch.complex(mag * torch.cos(phase), mag * torch.sin(phase)) + f0 = keep_left * self.frames_per_tok + f1 = (keep_left + keep_n) * self.frames_per_tok + return self.istft.process(spec[..., f0:f1]) + + def _commit_tokens(self, new_idx): + self.tokens = new_idx if self.tokens is None else torch.cat([self.tokens, new_idx], dim=1) + + def _drain(self, final=False): + out = [] + committed = self.tokens.shape[1] + while True: + d0 = self.decoded + avail = committed - d0 + if avail <= 0 or (not final and avail < self.chunk + self.dec_right): + break + keep_n = min(self.chunk, avail) if final else self.chunk + left = min(self.dec_left, d0) + right = min(self.dec_right, committed - (d0 + keep_n)) + win = self.tokens[:, d0 - left: d0 + keep_n + right] + out.append(self._decode(win, left, keep_n)) + self.decoded += keep_n + return torch.cat(out) if out else torch.zeros(0, device=self.dev) + + +def list_devices(): + print(f"{'idx':>4} {'name':<50} {'in':>3} {'out':>3} {'sr':>7}") + print("-" * 76) + for i, d in enumerate(sd.query_devices()): + print(f"{i:>4} {d['name']:<50} {d['max_input_channels']:>3} {d['max_output_channels']:>3} {int(d['default_samplerate']):>7}") + + +def sync_time(fn): + if DEVICE.type == "cuda": + torch.cuda.synchronize() + t0 = time.perf_counter() + out = fn() + if DEVICE.type == "cuda": + torch.cuda.synchronize() + return out, (time.perf_counter() - t0) * 1000 + + +def load_audio(path, target_sr): + a, sr = sf.read(path, dtype="float32", always_2d=True) + a = a.mean(axis=1) + + if sr != target_sr: + print(f"Resampling {path.name} from {sr} Hz to {target_sr} Hz...") + tensor = torch.from_numpy(a) + tensor = torchaudio.functional.resample(tensor, orig_freq=sr, new_freq=target_sr) + else: + tensor = torch.from_numpy(a) + + p = torch.abs(tensor).max() + return tensor / p if p > 1e-8 else tensor + + +def main(): + gc.collect() + gc.freeze() + gc.disable() + parser = argparse.ArgumentParser() + parser.add_argument("--list-devices", action="store_true") + parser.add_argument("--input", type=int) + parser.add_argument("--output", type=int) + parser.add_argument("--target", type=Path, help="Target voice reference WAV") + parser.add_argument("--seed-audio", type=Path, help="Seed speaker calibration WAV (optional)") + parser.add_argument("--chunk", type=int, default=6) + parser.add_argument("--enc-left", type=int, default=48) + parser.add_argument("--enc-right", type=int, default=2) + parser.add_argument("--dec-left", type=int, default=32) + parser.add_argument("--dec-right", type=int, default=3) + parser.add_argument("--ema-alpha", type=float, default=0.9, + help="EMA smoothing on local SSL features (0=full smoothing, 1=no smoothing)") + parser.add_argument("--rms-floor", type=float, default=0.0035, + help="RMS threshold below which audio chunk is evaluated as silence") + parser.add_argument("--hangover-chunks", type=int, default=5, + help="Number of chunks to hold the gate open after RMS drop") + parser.add_argument("--silence-fade-ms", type=float, default=10.0, + help="Ramp-down duration in ms at silence boundary (0 to disable)") + args = parser.parse_args() + + if args.list_devices: + list_devices() + return + + if args.input is None or args.output is None: + parser.error("--input and --output required") + + model = MioCodecModel.from_pretrained("Aratako/MioCodec-25Hz-44.1kHz-v2") + + vc = StreamingVC( + model, DEVICE, chunk=args.chunk, enc_left=args.enc_left, enc_right=args.enc_right, + dec_left=args.dec_left, dec_right=args.dec_right, ema_alpha=args.ema_alpha + ) + + sr = vc.sr + ts = vc.tok_samples + chunk_samples = vc.chunk * ts + left_pad = vc.enc_left * ts + right_pad = vc.enc_right * ts + budget_ms = (vc.chunk / vc.token_hz) * 1000 + fade_samples = int(args.silence_fade_ms * 0.001 * sr) + + print(f"Sample Rate: {sr} Hz | Chunk: {args.chunk} tokens ({budget_ms:.1f}ms budget)") + print(f"EMA alpha: {args.ema_alpha} | Silence fade: {args.silence_fade_ms:.0f}ms") + + print(f"Loading target speaker profile: {args.target}...") + target_audio = load_audio(args.target, sr) + vc.set_target(target_audio) + + in_info = sd.query_devices(args.input) + n_in_ch = min(in_info["max_input_channels"], 2) + + if args.seed_audio: + print(f"Loading speaker calibration profile: {args.seed_audio}...") + seed_audio = load_audio(args.seed_audio, sr) + else: + print("\n" + "=" * 60) + print("No seed-audio provided. Recording 3 seconds for normalization calibration.") + print("Please speak into your microphone...") + print("=" * 60) + recorded = sd.rec(int(3.0 * sr), samplerate=sr, channels=n_in_ch, dtype="float32") + sd.wait() + print("Recording complete. Calibrating feature scaling...") + recorded_mono = recorded.mean(axis=1) if recorded.shape[1] > 1 else recorded[:, 0] + seed_audio = torch.from_numpy(recorded_mono) + + print("Seeding streaming context from speaker profile...") + vc.seed(seed_audio) + + if seed_audio.numel() >= left_pad: + raw_input_accum = seed_audio[-left_pad:].numpy() + else: + raw_input_accum = np.pad(seed_audio.numpy(), (left_pad - seed_audio.numel(), 0)) + + in_q = queue.Queue(maxsize=8) + out_q = queue.Queue(maxsize=2) + stop_event = threading.Event() + + def input_cb(indata, frames, time_info, status): + if in_q.full(): + in_q.get_nowait() + mono = indata.mean(axis=1) if indata.shape[1] > 1 else indata[:, 0] + in_q.put_nowait(mono.copy()) + + def write_thread(out_stream): + while not stop_event.is_set(): + try: + pcm = out_q.get(timeout=0.5) + out_stream.write(pcm) + except queue.Empty: + continue + + print(f"\n{'chunk':>6} {'q_in':>4} {'q_out':>5} {'enc':>7} {'dec':>7} {'total':>7} {'budget':>7} {'gap':>7}") + print("-" * 76) + + chunk_n = 0 + t_last = None + hangover_counter = 0 + + if fade_samples > 0: + ramp_down = np.linspace(1.0, 0.0, fade_samples, dtype=np.float32) + + with sd.InputStream(device=args.input, channels=n_in_ch, samplerate=sr, + blocksize=chunk_samples, dtype="float32", + callback=input_cb, latency="low"): + with sd.OutputStream(device=args.output, channels=2, samplerate=sr, + dtype="float32", latency="low") as out_stream: + + writer = threading.Thread(target=write_thread, args=(out_stream,), daemon=True) + writer.start() + + try: + while True: + raw = in_q.get() + t_now = time.perf_counter() + gap_ms = (t_now - t_last) * 1000 if t_last else 0.0 + t_last = t_now + + rms = float(np.sqrt(np.mean(raw ** 2))) + + if rms >= args.rms_floor: + hangover_counter = args.hangover_chunks + is_silence = False + else: + if hangover_counter > 0: + hangover_counter -= 1 + is_silence = False + else: + is_silence = True + + raw_input_accum = np.concatenate([raw_input_accum, raw]) + required_samples = left_pad + chunk_samples + right_pad + + if len(raw_input_accum) >= required_samples: + window_np = raw_input_accum[:required_samples] + raw_input_accum = raw_input_accum[chunk_samples:] + + if is_silence: + window_np = window_np.copy() + active_start = left_pad + active_end = left_pad + chunk_samples + if fade_samples > 0: + fade_end = active_start + fade_samples + window_np[active_start:fade_end] *= ramp_down + window_np[fade_end:active_end] = 0.0 + else: + window_np[active_start:active_end] = 0.0 + + window_torch = torch.from_numpy(window_np).unsqueeze(0).to(DEVICE) + + with torch.no_grad(): + idx, t_enc = sync_time(lambda: vc._encode(window_torch)) + chunk_tokens = idx[:, vc.enc_left : vc.enc_left + vc.chunk] + vc._commit_tokens(chunk_tokens) + audio_out, t_dec = sync_time(lambda: vc._drain(final=False)) + + if audio_out.numel() == 0: + pcm_out = np.zeros((chunk_samples, 2), dtype=np.float32) + else: + pcm = audio_out.cpu().numpy() + pcm = np.clip(pcm, -1.0, 1.0) + pcm_out = np.stack([pcm, pcm], axis=1) + else: + pcm_out = np.zeros((chunk_samples, 2), dtype=np.float32) + t_enc, t_dec = 0.0, 0.0 + + out_q.put(pcm_out) + + total = t_enc + t_dec + chunk_n += 1 + + if is_silence: + print( + f"{chunk_n:>6} {in_q.qsize():>4} {out_q.qsize():>5} " + f"{'--silence--':>31} rms={rms:.4f}", + flush=True, + ) + else: + print( + f"{chunk_n:>6} {in_q.qsize():>4} {out_q.qsize():>5} " + f"{t_enc:>6.1f}ms {t_dec:>6.1f}ms " + f"{total:>6.1f}ms {budget_ms:>6.0f}ms {gap_ms:>6.1f}ms", + flush=True, + ) + + except KeyboardInterrupt: + pass + finally: + stop_event.set() + writer.join() + + print("stopped") + + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/live_onnx.py b/live_onnx.py index 743ec21..ecee1e8 100644 --- a/live_onnx.py +++ b/live_onnx.py @@ -100,7 +100,7 @@ class StreamingVCONNX: opts = ort.SessionOptions() opts.inter_op_num_threads = 1 - opts.intra_op_num_threads = 0 + opts.intra_op_num_threads = 4 opts.execution_mode = ort.ExecutionMode.ORT_SEQUENTIAL opts.graph_optimization_level = ort.GraphOptimizationLevel.ORT_ENABLE_ALL @@ -123,7 +123,7 @@ class StreamingVCONNX: self.tokens = None self.decoded = 0 self.prev_local_feats = None - self.ema_alpha = 0.4 + self.ema_alpha = 0.9 def _ssl(self, win16): w = take(win16, 0, self.ssl_in).reshape(1, -1) diff --git a/optimize.py b/optimize.py new file mode 100644 index 0000000..647710c --- /dev/null +++ b/optimize.py @@ -0,0 +1,34 @@ +# optimize_models.py +from onnxruntime.transformers.optimizer import optimize_model +from onnxruntime.transformers.fusion_options import FusionOptions + +def optimize_custom(input_path, output_path): + print(f"Optimizing {input_path}...") + + # Load default BERT fusion options + options = FusionOptions("bert") + + # Disable LayerNorm fusions that break on AdaLN / dynamic biases + options.enable_skip_layer_norm = False + options.enable_layer_norm = False + + # Run the optimizer + optimizer = optimize_model( + input=input_path, + model_type="bert", + optimization_options=options + ) + + optimizer.save_model_to_file(output_path) + print(f"Saved optimized model to {output_path}\n") + +if __name__ == "__main__": + optimize_custom("outputs/encode.onnx", "outputs/encode_opt.onnx") + optimize_custom("outputs/decode.onnx", "outputs/decode_opt.onnx") + + # ssl.onnx (WavLM) is a standard BERT architecture, so we can leave + # all standard fusions enabled for maximum speed. + print("Optimizing outputs/ssl.onnx...") + ssl_opt = optimize_model("outputs/ssl.onnx", model_type="bert") + ssl_opt.save_model_to_file("outputs/ssl_opt.onnx") + print("Saved optimized model to outputs/ssl_opt.onnx") \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml index 6e22fa9..36c1eac 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -10,10 +10,8 @@ dependencies = [ "onnxruntime>=1.26.0", "onnxruntime-gpu>=1.26.0", "onnxruntime-openvino>=1.24.1", - "onnxruntime-tools>=1.7.0", "onnxscript>=0.7.0", "sounddevice>=0.5.5", - "sympy>=1.14.0", "torch>=2.11.0", ] diff --git a/uv.lock b/uv.lock index ee8b74a..0e0cbc4 100644 --- a/uv.lock +++ b/uv.lock @@ -121,18 +121,6 @@ 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 = "coloredlogs" -version = "15.0.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "humanfriendly" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/cc/c7/eed8f27100517e8c0e6b923d5f0845d0cb99763da6fdee00478f91db7325/coloredlogs-15.0.1.tar.gz", hash = "sha256:7c991aa71a4577af2f82600d8f8f3a89f936baeaf9b50a9c197da014e5bf16b0", size = 278520, upload-time = "2021-06-11T10:22:45.202Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a7/06/3d6badcf13db419e25b07041d9c7b4a2c331d3f4e7134445ec5df57714cd/coloredlogs-15.0.1-py2.py3-none-any.whl", hash = "sha256:612ee75c546f53e92e70049c9dbfcc18c935a2b9a53b66085ce9ef6a6e5c0934", size = 46018, upload-time = "2021-06-11T10:22:42.561Z" }, -] - [[package]] name = "cuda-bindings" version = "12.9.7" @@ -223,10 +211,8 @@ dependencies = [ { name = "onnxruntime" }, { name = "onnxruntime-gpu" }, { name = "onnxruntime-openvino" }, - { name = "onnxruntime-tools" }, { name = "onnxscript" }, { name = "sounddevice" }, - { name = "sympy" }, { name = "torch", version = "2.11.0+cu128", source = { registry = "https://download.pytorch.org/whl/cu128" }, marker = "sys_platform == 'linux' or sys_platform == 'win32'" }, { name = "torch", version = "2.12.0", source = { registry = "https://pypi.org/simple" }, marker = "sys_platform != 'linux' and sys_platform != 'win32'" }, ] @@ -238,10 +224,8 @@ requires-dist = [ { name = "onnxruntime", specifier = ">=1.26.0" }, { name = "onnxruntime-gpu", specifier = ">=1.26.0" }, { name = "onnxruntime-openvino", specifier = ">=1.24.1" }, - { name = "onnxruntime-tools", specifier = ">=1.7.0" }, { name = "onnxscript", specifier = ">=0.7.0" }, { name = "sounddevice", specifier = ">=0.5.5" }, - { name = "sympy", specifier = ">=1.14.0" }, { name = "torch", specifier = ">=2.11.0" }, ] @@ -370,18 +354,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/02/28/d7cef5e477b855c25d415b8f57e5bc7347c7a90cad3acf1725d0c92ca294/huggingface_hub-1.17.0-py3-none-any.whl", hash = "sha256:3b8156d23118e87f6a587648bfbc04f04a12a757ccb4ed298b35c4ae638bf24c", size = 671546, upload-time = "2026-05-28T15:12:11.441Z" }, ] -[[package]] -name = "humanfriendly" -version = "10.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "pyreadline3", marker = "sys_platform == 'win32'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/cc/3f/2c29224acb2e2df4d2046e4c73ee2662023c58ff5b113c4c1adac0886c43/humanfriendly-10.0.tar.gz", hash = "sha256:6b0b831ce8f15f7300721aa49829fc4e83921a9a301cc7f606be6686a2288ddc", size = 360702, upload-time = "2021-09-17T21:40:43.31Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/f0/0f/310fb31e39e2d734ccaa2c0fb981ee41f7bd5056ce9bc29b2248bd569169/humanfriendly-10.0-py2.py3-none-any.whl", hash = "sha256:1697e1a8a8f550fd43c2865cd84542fc175a61dcb779b6fee18cf6b6ccba1477", size = 86794, upload-time = "2021-09-17T21:40:39.897Z" }, -] - [[package]] name = "idna" version = "3.17" @@ -934,24 +906,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/3e/92/46ae2cd565961a89189900f385bb2f13a9fa731ea4674001d23720fbb1e0/onnxruntime_openvino-1.24.1-cp313-cp313-win_amd64.whl", hash = "sha256:434bf49aa71393c577a456c9d76c98e6d6958a833fa0876793e3d5437b5a511a", size = 13658485, upload-time = "2026-02-26T13:44:53.889Z" }, ] -[[package]] -name = "onnxruntime-tools" -version = "1.7.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "coloredlogs" }, - { name = "numpy" }, - { name = "onnx" }, - { name = "packaging" }, - { name = "psutil" }, - { name = "py-cpuinfo" }, - { name = "py3nvml" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/fd/b5/c36283fef3b1d492a39d1b5f3f195965fbf002b168633daad302c51d8f4c/onnxruntime_tools-1.7.0.tar.gz", hash = "sha256:6dbdcee49424e066bcd10357c37d51bc422ae26494e3c2f0c1970d534f967f6d", size = 141435, upload-time = "2021-03-25T21:42:42.571Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/6f/b0/db0e73356df0aaa8737e6f13c0dac499b5d904d3fa267c8ebf24515e8001/onnxruntime_tools-1.7.0-py3-none-any.whl", hash = "sha256:1dff888b5c482ac5bc627f12e108445fefcb3d600c43f63633975316fe617ad8", size = 212695, upload-time = "2021-03-25T21:42:40.551Z" }, -] - [[package]] name = "onnxscript" version = "0.7.0" @@ -993,55 +947,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/b8/ef/50433d346c56657a70d27f156c7b349ac59a068b01de4eb796e747eecc43/protobuf-7.35.0-py3-none-any.whl", hash = "sha256:c13f325cf242bad135c350629eeb5d54b24228eb472fb3e2e9ebbd4c5dc20ca0", size = 171659, upload-time = "2026-05-19T23:02:27.842Z" }, ] -[[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/51/08/510cbdb69c25a96f4ae523f733cdc963ae654904e8db864c07585ef99875/psutil-7.2.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:2edccc433cbfa046b980b0df0171cd25bcaeb3a68fe9022db0979e7aa74a826b", size = 130595, upload-time = "2026-01-28T18:14:57.293Z" }, - { url = "https://files.pythonhosted.org/packages/d6/f5/97baea3fe7a5a9af7436301f85490905379b1c6f2dd51fe3ecf24b4c5fbf/psutil-7.2.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:e78c8603dcd9a04c7364f1a3e670cea95d51ee865e4efb3556a3a63adef958ea", size = 131082, upload-time = "2026-01-28T18:14:59.732Z" }, - { url = "https://files.pythonhosted.org/packages/37/d6/246513fbf9fa174af531f28412297dd05241d97a75911ac8febefa1a53c6/psutil-7.2.2-cp313-cp313t-manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1a571f2330c966c62aeda00dd24620425d4b0cc86881c89861fbc04549e5dc63", size = 181476, upload-time = "2026-01-28T18:15:01.884Z" }, - { url = "https://files.pythonhosted.org/packages/b8/b5/9182c9af3836cca61696dabe4fd1304e17bc56cb62f17439e1154f225dd3/psutil-7.2.2-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:917e891983ca3c1887b4ef36447b1e0873e70c933afc831c6b6da078ba474312", size = 184062, upload-time = "2026-01-28T18:15:04.436Z" }, - { url = "https://files.pythonhosted.org/packages/16/ba/0756dca669f5a9300d0cbcbfae9a4c30e446dfc7440ffe43ded5724bfd93/psutil-7.2.2-cp313-cp313t-win_amd64.whl", hash = "sha256:ab486563df44c17f5173621c7b198955bd6b613fb87c71c161f827d3fb149a9b", size = 139893, upload-time = "2026-01-28T18:15:06.378Z" }, - { url = "https://files.pythonhosted.org/packages/1c/61/8fa0e26f33623b49949346de05ec1ddaad02ed8ba64af45f40a147dbfa97/psutil-7.2.2-cp313-cp313t-win_arm64.whl", hash = "sha256:ae0aefdd8796a7737eccea863f80f81e468a1e4cf14d926bd9b6f5f2d5f90ca9", size = 135589, upload-time = "2026-01-28T18:15:08.03Z" }, - { url = "https://files.pythonhosted.org/packages/81/69/ef179ab5ca24f32acc1dac0c247fd6a13b501fd5534dbae0e05a1c48b66d/psutil-7.2.2-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:eed63d3b4d62449571547b60578c5b2c4bcccc5387148db46e0c2313dad0ee00", size = 130664, upload-time = "2026-01-28T18:15:09.469Z" }, - { url = "https://files.pythonhosted.org/packages/7b/64/665248b557a236d3fa9efc378d60d95ef56dd0a490c2cd37dafc7660d4a9/psutil-7.2.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7b6d09433a10592ce39b13d7be5a54fbac1d1228ed29abc880fb23df7cb694c9", size = 131087, upload-time = "2026-01-28T18:15:11.724Z" }, - { url = "https://files.pythonhosted.org/packages/d5/2e/e6782744700d6759ebce3043dcfa661fb61e2fb752b91cdeae9af12c2178/psutil-7.2.2-cp314-cp314t-manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1fa4ecf83bcdf6e6c8f4449aff98eefb5d0604bf88cb883d7da3d8d2d909546a", size = 182383, upload-time = "2026-01-28T18:15:13.445Z" }, - { url = "https://files.pythonhosted.org/packages/57/49/0a41cefd10cb7505cdc04dab3eacf24c0c2cb158a998b8c7b1d27ee2c1f5/psutil-7.2.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e452c464a02e7dc7822a05d25db4cde564444a67e58539a00f929c51eddda0cf", size = 185210, upload-time = "2026-01-28T18:15:16.002Z" }, - { url = "https://files.pythonhosted.org/packages/dd/2c/ff9bfb544f283ba5f83ba725a3c5fec6d6b10b8f27ac1dc641c473dc390d/psutil-7.2.2-cp314-cp314t-win_amd64.whl", hash = "sha256:c7663d4e37f13e884d13994247449e9f8f574bc4655d509c3b95e9ec9e2b9dc1", size = 141228, upload-time = "2026-01-28T18:15:18.385Z" }, - { url = "https://files.pythonhosted.org/packages/f2/fc/f8d9c31db14fcec13748d373e668bc3bed94d9077dbc17fb0eebc073233c/psutil-7.2.2-cp314-cp314t-win_arm64.whl", hash = "sha256:11fe5a4f613759764e79c65cf11ebdf26e33d6dd34336f8a337aa2996d71c841", size = 136284, upload-time = "2026-01-28T18:15:19.912Z" }, - { 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 = "py-cpuinfo" -version = "9.0.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/37/a8/d832f7293ebb21690860d2e01d8115e5ff6f2ae8bbdc953f0eb0fa4bd2c7/py-cpuinfo-9.0.0.tar.gz", hash = "sha256:3cdbbf3fac90dc6f118bfd64384f309edeadd902d7c8fb17f02ffa1fc3f49690", size = 104716, upload-time = "2022-10-25T20:38:06.303Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e0/a9/023730ba63db1e494a271cb018dcd361bd2c917ba7004c3e49d5daf795a2/py_cpuinfo-9.0.0-py3-none-any.whl", hash = "sha256:859625bc251f64e21f077d099d4162689c762b5d6a4c3c97553d56241c9674d5", size = 22335, upload-time = "2022-10-25T20:38:27.636Z" }, -] - -[[package]] -name = "py3nvml" -version = "0.2.7" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "xmltodict" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/10/7e/fa282e456b87570d663ce97946b4dcb16850d4495ce4bd625a1a10c8ed56/py3nvml-0.2.7.tar.gz", hash = "sha256:09ee1d04598a6e664e24465f804ce3bfe119a6fdb5362df1c168f8aa929fbd73", size = 58224, upload-time = "2021-11-22T14:30:27.541Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/03/3a/ea6f2419bd20f97f65ee55a9910c722313fe99cacc0bf77afb4b74b446ff/py3nvml-0.2.7-py3-none-any.whl", hash = "sha256:30101170d1f51419c8d21fd8ca6cdc333a552b4f8a945c2fc7d107d77e4220dd", size = 55503, upload-time = "2021-11-22T14:30:25.794Z" }, -] - [[package]] name = "pycparser" version = "3.0" @@ -1060,15 +965,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl", hash = "sha256:81a9e26dd42fd28a23a2d169d86d7ac03b46e2f8b59ed4698fb4785f946d0176", size = 1231151, upload-time = "2026-03-29T13:29:30.038Z" }, ] -[[package]] -name = "pyreadline3" -version = "3.5.6" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b6/6d/f94028646d7bbe6d9d873c47ee7c246f2d29129d253f0d96cb6fcab70733/pyreadline3-3.5.6.tar.gz", hash = "sha256:61e53218b99656091ddb077df9e71f25850e72e030b6183b39c9b7e6e4f4a9bf", size = 100368, upload-time = "2026-05-14T17:55:04.471Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/f7/5e/35c856e186b74678c24927847ad9895a51f1bc02a0c6126477a6c6040064/pyreadline3-3.5.6-py3-none-any.whl", hash = "sha256:8449b734232e42a5dcd74048e39b60db2839a4c38cf3ae2bf7707d58b5389c0d", size = 85243, upload-time = "2026-05-14T17:55:03.262Z" }, -] - [[package]] name = "pyyaml" version = "6.0.3" @@ -1406,12 +1302,3 @@ sdist = { url = "https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac8 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 = "xmltodict" -version = "1.0.4" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/19/70/80f3b7c10d2630aa66414bf23d210386700aa390547278c789afa994fd7e/xmltodict-1.0.4.tar.gz", hash = "sha256:6d94c9f834dd9e44514162799d344d815a3a4faec913717a9ecbfa5be1bb8e61", size = 26124, upload-time = "2026-02-22T02:21:22.074Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/38/34/98a2f52245f4d47be93b580dae5f9861ef58977d73a79eb47c58f1ad1f3a/xmltodict-1.0.4-py3-none-any.whl", hash = "sha256:a4a00d300b0e1c59fc2bfccb53d7b2e88c32f200df138a0dd2229f842497026a", size = 13580, upload-time = "2026-02-22T02:21:21.039Z" }, -]