Spaces:
Sleeping
Sleeping
feat: add Reconstruct button and optimize codec processing logic
Browse files- app.py +34 -54
- compare_codec/dac.py +9 -1
- compare_codec/encodec_codec.py +6 -2
- compare_codec/mimi_codec.py +5 -5
- compare_codec/snac_codec.py +10 -2
- pyproject.toml +1 -0
- uv.lock +48 -0
app.py
CHANGED
|
@@ -43,6 +43,7 @@ def build_ui() -> gr.Blocks:
|
|
| 43 |
type="filepath",
|
| 44 |
label="Input audio",
|
| 45 |
)
|
|
|
|
| 46 |
|
| 47 |
tab_components: dict[str, dict] = {}
|
| 48 |
|
|
@@ -87,75 +88,54 @@ def build_ui() -> gr.Blocks:
|
|
| 87 |
c = tab_components[name]
|
| 88 |
all_outputs.extend([c["audio_out"], c["stats_md"], c["spec_img"]])
|
| 89 |
|
| 90 |
-
def
|
| 91 |
-
"""
|
| 92 |
if audio_path is None:
|
| 93 |
-
return
|
| 94 |
|
| 95 |
dd_map = dict(zip(ordered_names, dropdown_values))
|
| 96 |
-
|
| 97 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 98 |
for name in ordered_names:
|
| 99 |
-
|
| 100 |
-
|
| 101 |
-
|
| 102 |
-
|
| 103 |
-
|
| 104 |
-
|
| 105 |
-
|
| 106 |
-
|
| 107 |
-
|
| 108 |
-
|
| 109 |
-
|
| 110 |
-
audio_out, sr, elapsed = _encode_decode_one(
|
| 111 |
-
Path(audio_path), name, cfg
|
| 112 |
-
)
|
| 113 |
-
spec_path = make_spectrogram(audio_out, sr)
|
| 114 |
-
|
| 115 |
-
stats_text = (
|
| 116 |
-
f"**{elapsed:.2f}s** | "
|
| 117 |
-
f"{sr / 1000:.0f} kHz | "
|
| 118 |
-
f"{cfg_label}"
|
| 119 |
-
)
|
| 120 |
-
|
| 121 |
-
results[name] = (
|
| 122 |
-
gr.update(value=(sr, audio_out)),
|
| 123 |
-
gr.update(value=stats_text),
|
| 124 |
-
gr.update(value=str(spec_path)),
|
| 125 |
-
)
|
| 126 |
-
|
| 127 |
-
flat = []
|
| 128 |
-
for n in ordered_names:
|
| 129 |
-
flat.extend(results[n])
|
| 130 |
-
yield flat
|
| 131 |
|
| 132 |
all_dropdowns = [tab_components[n]["config_dd"] for n in ordered_names]
|
| 133 |
|
| 134 |
-
|
| 135 |
-
fn=
|
| 136 |
inputs=[audio_in, active_tab] + all_dropdowns,
|
| 137 |
outputs=all_outputs,
|
| 138 |
)
|
| 139 |
|
| 140 |
-
dropdown_events = []
|
| 141 |
-
for name in ordered_names:
|
| 142 |
-
evt = tab_components[name]["config_dd"].change(
|
| 143 |
-
fn=process_all,
|
| 144 |
-
inputs=[audio_in, active_tab] + all_dropdowns,
|
| 145 |
-
outputs=all_outputs,
|
| 146 |
-
)
|
| 147 |
-
dropdown_events.append(evt)
|
| 148 |
-
|
| 149 |
for codec_name, comps in tab_components.items():
|
| 150 |
comps["tab"].select(
|
| 151 |
fn=lambda name=codec_name: name,
|
| 152 |
inputs=[],
|
| 153 |
outputs=[active_tab],
|
| 154 |
-
).then(
|
| 155 |
-
fn=process_all,
|
| 156 |
-
inputs=[audio_in, active_tab] + all_dropdowns,
|
| 157 |
-
outputs=all_outputs,
|
| 158 |
-
cancels=[upload_event] + dropdown_events,
|
| 159 |
)
|
| 160 |
|
| 161 |
return demo
|
|
@@ -164,4 +144,4 @@ def build_ui() -> gr.Blocks:
|
|
| 164 |
demo = build_ui()
|
| 165 |
|
| 166 |
if __name__ == "__main__":
|
| 167 |
-
demo.launch()
|
|
|
|
| 43 |
type="filepath",
|
| 44 |
label="Input audio",
|
| 45 |
)
|
| 46 |
+
run_btn = gr.Button("Reconstruct", variant="primary")
|
| 47 |
|
| 48 |
tab_components: dict[str, dict] = {}
|
| 49 |
|
|
|
|
| 88 |
c = tab_components[name]
|
| 89 |
all_outputs.extend([c["audio_out"], c["stats_md"], c["spec_img"]])
|
| 90 |
|
| 91 |
+
def process_active(audio_path: str | None, current_tab: str, *dropdown_values):
|
| 92 |
+
"""Reconstruct only the active tab's codec."""
|
| 93 |
if audio_path is None:
|
| 94 |
+
return [gr.update()] * len(all_outputs)
|
| 95 |
|
| 96 |
dd_map = dict(zip(ordered_names, dropdown_values))
|
| 97 |
+
comps = tab_components[current_tab]
|
| 98 |
+
cfg_label = dd_map[current_tab]
|
| 99 |
+
cfg = next(c for c in comps["configs"] if c.name == cfg_label)
|
| 100 |
+
|
| 101 |
+
audio_out, sr, elapsed = _encode_decode_one(
|
| 102 |
+
Path(audio_path), current_tab, cfg
|
| 103 |
+
)
|
| 104 |
+
spec_path = make_spectrogram(audio_out, sr)
|
| 105 |
+
|
| 106 |
+
stats_text = (
|
| 107 |
+
f"**{elapsed:.2f}s** | "
|
| 108 |
+
f"{sr / 1000:.0f} kHz | "
|
| 109 |
+
f"{cfg_label}"
|
| 110 |
+
)
|
| 111 |
+
|
| 112 |
+
flat = []
|
| 113 |
for name in ordered_names:
|
| 114 |
+
if name == current_tab:
|
| 115 |
+
flat.extend(
|
| 116 |
+
[
|
| 117 |
+
gr.update(value=(sr, audio_out)),
|
| 118 |
+
gr.update(value=stats_text),
|
| 119 |
+
gr.update(value=str(spec_path)),
|
| 120 |
+
]
|
| 121 |
+
)
|
| 122 |
+
else:
|
| 123 |
+
flat.extend([gr.update(), gr.update(), gr.update()])
|
| 124 |
+
return flat
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 125 |
|
| 126 |
all_dropdowns = [tab_components[n]["config_dd"] for n in ordered_names]
|
| 127 |
|
| 128 |
+
btn_event = run_btn.click(
|
| 129 |
+
fn=process_active,
|
| 130 |
inputs=[audio_in, active_tab] + all_dropdowns,
|
| 131 |
outputs=all_outputs,
|
| 132 |
)
|
| 133 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 134 |
for codec_name, comps in tab_components.items():
|
| 135 |
comps["tab"].select(
|
| 136 |
fn=lambda name=codec_name: name,
|
| 137 |
inputs=[],
|
| 138 |
outputs=[active_tab],
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 139 |
)
|
| 140 |
|
| 141 |
return demo
|
|
|
|
| 144 |
demo = build_ui()
|
| 145 |
|
| 146 |
if __name__ == "__main__":
|
| 147 |
+
demo.launch()
|
compare_codec/dac.py
CHANGED
|
@@ -9,6 +9,14 @@ import torch
|
|
| 9 |
|
| 10 |
from compare_codec import CodecConfig, register
|
| 11 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 12 |
|
| 13 |
class DACCodec:
|
| 14 |
"""DAC codec with lazy model loading."""
|
|
@@ -50,7 +58,7 @@ class DACCodec:
|
|
| 50 |
|
| 51 |
model_path = _dac.utils.download(model_type=model_type)
|
| 52 |
model = _dac.DAC.load(model_path)
|
| 53 |
-
model.eval()
|
| 54 |
self._models[model_type] = model
|
| 55 |
return self._models[model_type]
|
| 56 |
|
|
|
|
| 9 |
|
| 10 |
from compare_codec import CodecConfig, register
|
| 11 |
|
| 12 |
+
_device = torch.device(
|
| 13 |
+
"cuda"
|
| 14 |
+
if torch.cuda.is_available()
|
| 15 |
+
else "mps"
|
| 16 |
+
if torch.backends.mps.is_available()
|
| 17 |
+
else "cpu"
|
| 18 |
+
)
|
| 19 |
+
|
| 20 |
|
| 21 |
class DACCodec:
|
| 22 |
"""DAC codec with lazy model loading."""
|
|
|
|
| 58 |
|
| 59 |
model_path = _dac.utils.download(model_type=model_type)
|
| 60 |
model = _dac.DAC.load(model_path)
|
| 61 |
+
model.eval().to(_device)
|
| 62 |
self._models[model_type] = model
|
| 63 |
return self._models[model_type]
|
| 64 |
|
compare_codec/encodec_codec.py
CHANGED
|
@@ -41,7 +41,9 @@ class EnCodecCodec:
|
|
| 41 |
if self._model is None:
|
| 42 |
from transformers import AutoProcessor, EncodecModel
|
| 43 |
|
| 44 |
-
self._model = EncodecModel.from_pretrained(
|
|
|
|
|
|
|
| 45 |
self._model.eval()
|
| 46 |
self._processor = AutoProcessor.from_pretrained("facebook/encodec_24khz")
|
| 47 |
|
|
@@ -62,6 +64,8 @@ class EnCodecCodec:
|
|
| 62 |
sampling_rate=target_sr,
|
| 63 |
return_tensors="pt",
|
| 64 |
)
|
|
|
|
|
|
|
| 65 |
enc = self._model.encode(
|
| 66 |
inputs["input_values"],
|
| 67 |
inputs["padding_mask"],
|
|
@@ -76,4 +80,4 @@ class EnCodecCodec:
|
|
| 76 |
return audio_out.squeeze(0).squeeze(0).cpu().numpy()
|
| 77 |
|
| 78 |
|
| 79 |
-
register(EnCodecCodec())
|
|
|
|
| 41 |
if self._model is None:
|
| 42 |
from transformers import AutoProcessor, EncodecModel
|
| 43 |
|
| 44 |
+
self._model = EncodecModel.from_pretrained(
|
| 45 |
+
"facebook/encodec_24khz", device_map="auto"
|
| 46 |
+
)
|
| 47 |
self._model.eval()
|
| 48 |
self._processor = AutoProcessor.from_pretrained("facebook/encodec_24khz")
|
| 49 |
|
|
|
|
| 64 |
sampling_rate=target_sr,
|
| 65 |
return_tensors="pt",
|
| 66 |
)
|
| 67 |
+
device = self._model.device
|
| 68 |
+
inputs = {k: v.to(device) for k, v in inputs.items()}
|
| 69 |
enc = self._model.encode(
|
| 70 |
inputs["input_values"],
|
| 71 |
inputs["padding_mask"],
|
|
|
|
| 80 |
return audio_out.squeeze(0).squeeze(0).cpu().numpy()
|
| 81 |
|
| 82 |
|
| 83 |
+
register(EnCodecCodec())
|
compare_codec/mimi_codec.py
CHANGED
|
@@ -38,7 +38,7 @@ class MimiCodec:
|
|
| 38 |
if self._model is None:
|
| 39 |
from transformers import AutoFeatureExtractor, MimiModel
|
| 40 |
|
| 41 |
-
self._model = MimiModel.from_pretrained("kyutai/mimi")
|
| 42 |
self._model.eval()
|
| 43 |
self._fe = AutoFeatureExtractor.from_pretrained("kyutai/mimi")
|
| 44 |
|
|
@@ -59,14 +59,14 @@ class MimiCodec:
|
|
| 59 |
sampling_rate=target_sr,
|
| 60 |
return_tensors="pt",
|
| 61 |
)
|
|
|
|
|
|
|
| 62 |
enc = self._model.encode(inputs["input_values"], inputs["padding_mask"])
|
| 63 |
-
audio_out = self._model.decode(
|
| 64 |
-
enc.audio_codes, inputs["padding_mask"]
|
| 65 |
-
)[0]
|
| 66 |
|
| 67 |
# Trim to original length (Mimi may pad).
|
| 68 |
audio_out = audio_out.squeeze(0).squeeze(0).cpu().numpy()[:original_len]
|
| 69 |
return audio_out
|
| 70 |
|
| 71 |
|
| 72 |
-
register(MimiCodec())
|
|
|
|
| 38 |
if self._model is None:
|
| 39 |
from transformers import AutoFeatureExtractor, MimiModel
|
| 40 |
|
| 41 |
+
self._model = MimiModel.from_pretrained("kyutai/mimi", device_map="auto")
|
| 42 |
self._model.eval()
|
| 43 |
self._fe = AutoFeatureExtractor.from_pretrained("kyutai/mimi")
|
| 44 |
|
|
|
|
| 59 |
sampling_rate=target_sr,
|
| 60 |
return_tensors="pt",
|
| 61 |
)
|
| 62 |
+
device = self._model.device
|
| 63 |
+
inputs = {k: v.to(device) for k, v in inputs.items()}
|
| 64 |
enc = self._model.encode(inputs["input_values"], inputs["padding_mask"])
|
| 65 |
+
audio_out = self._model.decode(enc.audio_codes, inputs["padding_mask"])[0]
|
|
|
|
|
|
|
| 66 |
|
| 67 |
# Trim to original length (Mimi may pad).
|
| 68 |
audio_out = audio_out.squeeze(0).squeeze(0).cpu().numpy()[:original_len]
|
| 69 |
return audio_out
|
| 70 |
|
| 71 |
|
| 72 |
+
register(MimiCodec())
|
compare_codec/snac_codec.py
CHANGED
|
@@ -10,6 +10,14 @@ import torchaudio
|
|
| 10 |
|
| 11 |
from compare_codec import CodecConfig, register
|
| 12 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 13 |
_MODELS = [
|
| 14 |
("hubertsiuzdak/snac_24khz", 24_000),
|
| 15 |
("hubertsiuzdak/snac_32khz", 32_000),
|
|
@@ -47,7 +55,7 @@ class SNACCodec:
|
|
| 47 |
if model_id not in self._models:
|
| 48 |
from snac import SNAC
|
| 49 |
|
| 50 |
-
model = SNAC.from_pretrained(model_id)
|
| 51 |
self._models[model_id] = model
|
| 52 |
return self._models[model_id]
|
| 53 |
|
|
@@ -66,7 +74,7 @@ class SNACCodec:
|
|
| 66 |
if sr != target_sr:
|
| 67 |
wav = torchaudio.functional.resample(wav, sr, target_sr)
|
| 68 |
# SNAC expects (B, 1, T).
|
| 69 |
-
wav = wav.unsqueeze(0)
|
| 70 |
|
| 71 |
audio_hat, _ = model(wav)
|
| 72 |
|
|
|
|
| 10 |
|
| 11 |
from compare_codec import CodecConfig, register
|
| 12 |
|
| 13 |
+
_device = torch.device(
|
| 14 |
+
"cuda"
|
| 15 |
+
if torch.cuda.is_available()
|
| 16 |
+
else "mps"
|
| 17 |
+
if torch.backends.mps.is_available()
|
| 18 |
+
else "cpu"
|
| 19 |
+
)
|
| 20 |
+
|
| 21 |
_MODELS = [
|
| 22 |
("hubertsiuzdak/snac_24khz", 24_000),
|
| 23 |
("hubertsiuzdak/snac_32khz", 32_000),
|
|
|
|
| 55 |
if model_id not in self._models:
|
| 56 |
from snac import SNAC
|
| 57 |
|
| 58 |
+
model = SNAC.from_pretrained(model_id).to(_device)
|
| 59 |
self._models[model_id] = model
|
| 60 |
return self._models[model_id]
|
| 61 |
|
|
|
|
| 74 |
if sr != target_sr:
|
| 75 |
wav = torchaudio.functional.resample(wav, sr, target_sr)
|
| 76 |
# SNAC expects (B, 1, T).
|
| 77 |
+
wav = wav.unsqueeze(0).to(_device)
|
| 78 |
|
| 79 |
audio_hat, _ = model(wav)
|
| 80 |
|
pyproject.toml
CHANGED
|
@@ -6,6 +6,7 @@ readme = "README.md"
|
|
| 6 |
license = "Apache-2.0"
|
| 7 |
requires-python = ">=3.12"
|
| 8 |
dependencies = [
|
|
|
|
| 9 |
"descript-audio-codec>=1.0.0",
|
| 10 |
"encodec>=0.1.1",
|
| 11 |
"gradio",
|
|
|
|
| 6 |
license = "Apache-2.0"
|
| 7 |
requires-python = ">=3.12"
|
| 8 |
dependencies = [
|
| 9 |
+
"accelerate>=1.13.0",
|
| 10 |
"descript-audio-codec>=1.0.0",
|
| 11 |
"encodec>=0.1.1",
|
| 12 |
"gradio",
|
uv.lock
CHANGED
|
@@ -25,6 +25,24 @@ wheels = [
|
|
| 25 |
{ 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" },
|
| 26 |
]
|
| 27 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 28 |
[[package]]
|
| 29 |
name = "annotated-doc"
|
| 30 |
version = "0.0.4"
|
|
@@ -347,6 +365,7 @@ name = "compare-codec"
|
|
| 347 |
version = "0.1.0"
|
| 348 |
source = { virtual = "." }
|
| 349 |
dependencies = [
|
|
|
|
| 350 |
{ name = "descript-audio-codec" },
|
| 351 |
{ name = "encodec" },
|
| 352 |
{ name = "gradio" },
|
|
@@ -367,6 +386,7 @@ dev = [
|
|
| 367 |
|
| 368 |
[package.metadata]
|
| 369 |
requires-dist = [
|
|
|
|
| 370 |
{ name = "descript-audio-codec", specifier = ">=1.0.0" },
|
| 371 |
{ name = "encodec", specifier = ">=0.1.1" },
|
| 372 |
{ name = "gradio" },
|
|
@@ -1918,6 +1938,34 @@ wheels = [
|
|
| 1918 |
{ url = "https://files.pythonhosted.org/packages/32/27/1141a8232723dcb10a595cc0ce4321dcbbd5215300bf4acfc142343205bf/protobuf-3.19.6-py2.py3-none-any.whl", hash = "sha256:14082457dc02be946f60b15aad35e9f5c69e738f80ebbc0900a19bc83734a5a4", size = 162648, upload-time = "2022-09-29T22:07:20.303Z" },
|
| 1919 |
]
|
| 1920 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1921 |
[[package]]
|
| 1922 |
name = "ptyprocess"
|
| 1923 |
version = "0.7.0"
|
|
|
|
| 25 |
{ 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" },
|
| 26 |
]
|
| 27 |
|
| 28 |
+
[[package]]
|
| 29 |
+
name = "accelerate"
|
| 30 |
+
version = "1.13.0"
|
| 31 |
+
source = { registry = "https://pypi.org/simple" }
|
| 32 |
+
dependencies = [
|
| 33 |
+
{ name = "huggingface-hub" },
|
| 34 |
+
{ name = "numpy" },
|
| 35 |
+
{ name = "packaging" },
|
| 36 |
+
{ name = "psutil" },
|
| 37 |
+
{ name = "pyyaml" },
|
| 38 |
+
{ name = "safetensors" },
|
| 39 |
+
{ name = "torch" },
|
| 40 |
+
]
|
| 41 |
+
sdist = { url = "https://files.pythonhosted.org/packages/ca/14/787e5498cd062640f0f3d92ef4ae4063174f76f9afd29d13fc52a319daae/accelerate-1.13.0.tar.gz", hash = "sha256:d631b4e0f5b3de4aff2d7e9e6857d164810dfc3237d54d017f075122d057b236", size = 402835, upload-time = "2026-03-04T19:34:12.359Z" }
|
| 42 |
+
wheels = [
|
| 43 |
+
{ url = "https://files.pythonhosted.org/packages/7e/46/02ac5e262d4af18054b3e922b2baedbb2a03289ee792162de60a865defc5/accelerate-1.13.0-py3-none-any.whl", hash = "sha256:cf1a3efb96c18f7b152eb0fa7490f3710b19c3f395699358f08decca2b8b62e0", size = 383744, upload-time = "2026-03-04T19:34:10.313Z" },
|
| 44 |
+
]
|
| 45 |
+
|
| 46 |
[[package]]
|
| 47 |
name = "annotated-doc"
|
| 48 |
version = "0.0.4"
|
|
|
|
| 365 |
version = "0.1.0"
|
| 366 |
source = { virtual = "." }
|
| 367 |
dependencies = [
|
| 368 |
+
{ name = "accelerate" },
|
| 369 |
{ name = "descript-audio-codec" },
|
| 370 |
{ name = "encodec" },
|
| 371 |
{ name = "gradio" },
|
|
|
|
| 386 |
|
| 387 |
[package.metadata]
|
| 388 |
requires-dist = [
|
| 389 |
+
{ name = "accelerate", specifier = ">=1.13.0" },
|
| 390 |
{ name = "descript-audio-codec", specifier = ">=1.0.0" },
|
| 391 |
{ name = "encodec", specifier = ">=0.1.1" },
|
| 392 |
{ name = "gradio" },
|
|
|
|
| 1938 |
{ url = "https://files.pythonhosted.org/packages/32/27/1141a8232723dcb10a595cc0ce4321dcbbd5215300bf4acfc142343205bf/protobuf-3.19.6-py2.py3-none-any.whl", hash = "sha256:14082457dc02be946f60b15aad35e9f5c69e738f80ebbc0900a19bc83734a5a4", size = 162648, upload-time = "2022-09-29T22:07:20.303Z" },
|
| 1939 |
]
|
| 1940 |
|
| 1941 |
+
[[package]]
|
| 1942 |
+
name = "psutil"
|
| 1943 |
+
version = "7.2.2"
|
| 1944 |
+
source = { registry = "https://pypi.org/simple" }
|
| 1945 |
+
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" }
|
| 1946 |
+
wheels = [
|
| 1947 |
+
{ 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" },
|
| 1948 |
+
{ 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" },
|
| 1949 |
+
{ 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" },
|
| 1950 |
+
{ 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" },
|
| 1951 |
+
{ 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" },
|
| 1952 |
+
{ 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" },
|
| 1953 |
+
{ 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" },
|
| 1954 |
+
{ 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" },
|
| 1955 |
+
{ 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" },
|
| 1956 |
+
{ 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" },
|
| 1957 |
+
{ 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" },
|
| 1958 |
+
{ 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" },
|
| 1959 |
+
{ 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" },
|
| 1960 |
+
{ 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" },
|
| 1961 |
+
{ 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" },
|
| 1962 |
+
{ 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" },
|
| 1963 |
+
{ 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" },
|
| 1964 |
+
{ 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" },
|
| 1965 |
+
{ 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" },
|
| 1966 |
+
{ 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" },
|
| 1967 |
+
]
|
| 1968 |
+
|
| 1969 |
[[package]]
|
| 1970 |
name = "ptyprocess"
|
| 1971 |
version = "0.7.0"
|