diff --git a/.github/workflows/tier0.yml b/.github/workflows/tier0.yml index f380824..5fb0b15 100644 --- a/.github/workflows/tier0.yml +++ b/.github/workflows/tier0.yml @@ -5,10 +5,10 @@ on: branches: [main] pull_request: -# Minimal-deps run: Tier 0 must work without ComfyUI, coremltools, or -# python_coreml_stable_diffusion (Linux CI image won't have them). The -# in-tree purity gate (tests/unit/test_tier0_purity.py) double-checks -# that the suite hasn't started leaking framework imports. +# Deps are resolved from pyproject.toml via uv, so the toolchain pins live in +# one place. Tier 0 must run without ComfyUI; the in-tree purity gate +# (tests/unit/test_tier0_purity.py) enforces that the suite hasn't started +# leaking framework imports. jobs: unit: runs-on: ubuntu-latest @@ -16,18 +16,12 @@ jobs: steps: - uses: actions/checkout@v4 - - uses: actions/setup-python@v5 + - uses: astral-sh/setup-uv@v7 with: - python-version: "3.11" + enable-cache: true - - name: Install Tier 0 deps - run: | - python -m pip install --upgrade pip - # Tier 0 only needs torch + numpy + pytest; everything else - # is Mac-only. - python -m pip install \ - "torch==2.0.1" "numpy<1.25" \ - "pytest>=8" "pytest-xdist" + - name: uv sync + run: uv sync --no-install-project - name: Run Tier 0 - run: pytest -m unit tests/ -v + run: uv run pytest -m unit tests/ -v diff --git a/.github/workflows/tier1.yml b/.github/workflows/tier1.yml index bb063ea..f805981 100644 --- a/.github/workflows/tier1.yml +++ b/.github/workflows/tier1.yml @@ -1,29 +1,21 @@ -name: Tier 1 — Smoke (macOS-ARM) +name: Tier 1 — Smoke (macOS self-hosted) +# macOS smoke tests run on the self-hosted Apple Silicon runner instead of +# GitHub-hosted macOS (10x minute multiplier), which exhausts the included +# Actions minutes too quickly. on: push: branches: [main] pull_request: - # Gate behind the run-tier1 label too, so external PRs that touch - # only docs don't burn a minute of macOS-ARM time. Maintainers can - # always re-run via the run-tier1 label. - types: [opened, synchronize, reopened, labeled] jobs: smoke: - if: | - github.event_name == 'push' || - github.event.action != 'labeled' || - contains(github.event.pull_request.labels.*.name, 'run-tier1') - runs-on: macos-14 # M1, Apple Silicon hosted runner + runs-on: [self-hosted, macOS, ARM64, coreml] timeout-minutes: 20 steps: - uses: actions/checkout@v4 - - uses: astral-sh/setup-uv@v3 - with: - enable-cache: true - + # The self-hosted runner provides uv; no setup-uv action needed. - name: uv sync run: uv sync --no-install-project diff --git a/.github/workflows/tier2.yml b/.github/workflows/tier2.yml index ccfc913..bb7a895 100644 --- a/.github/workflows/tier2.yml +++ b/.github/workflows/tier2.yml @@ -30,7 +30,7 @@ jobs: # Hybrid ComfyUI strategy: # - schedule (nightly) -> latest origin/master + ComfyUI's own # requirements.txt (constrained). Canary for upstream API breakage. - # - PR label / dispatch -> the pinned requires-comfyui SHA + the frozen + # - PR label / dispatch -> the requires-comfyui version tag + the frozen # `comfy` uv group. Reproducible merge gate, immune to overnight drift. - name: Resolve ComfyUI ref + mode run: | @@ -38,10 +38,12 @@ jobs: echo "COMFY_MODE=latest" >> "$GITHUB_ENV" echo "COMFY_REF=master" >> "$GITHUB_ENV" else - PIN="$(sed -nE 's/^requires-comfyui *= *"==?([0-9a-f]+)".*/\1/p' pyproject.toml)" - if [ -z "$PIN" ]; then echo "could not parse requires-comfyui from pyproject.toml"; exit 1; fi - echo "COMFY_MODE=pinned" >> "$GITHUB_ENV" - echo "COMFY_REF=$PIN" >> "$GITHUB_ENV" + # requires-comfyui is a semver constraint (e.g. ">=0.3.27"); pin the + # gate to the matching ComfyUI release tag (vX.Y.Z). + VERSION="$(sed -nE 's/^requires-comfyui *= *"[^0-9]*([0-9]+\.[0-9]+\.[0-9]+).*/\1/p' pyproject.toml)" + if [ -z "$VERSION" ]; then echo "could not parse requires-comfyui from pyproject.toml"; exit 1; fi + echo "COMFY_MODE=pinned" >> "$GITHUB_ENV" + echo "COMFY_REF=v$VERSION" >> "$GITHUB_ENV" fi - name: Set up ComfyUI checkout @@ -113,10 +115,18 @@ jobs: done echo "comfy failed to start"; tail -100 /tmp/comfyui-ci.log; exit 1 + - name: Purge cached Core ML UNets (force fresh conversion) + # The converter skips when a model of the same name already exists. That + # cache key is conversion *parameters* only, not the conversion code or + # toolchain — so a stale model would let a conversion regression pass. + # Clear it so every Tier 2 run exercises the full convert -> compile -> + # sample path end to end. + run: | + rm -rf "$COMFY_DIR"/models/unet/*.mlpackage "$COMFY_DIR"/models/unet/*.mlmodelc || true + - name: Run Tier 2 (m2 marker) - # The golden-image workflow drives the Core ML Converter node, so the - # UNet is converted on demand on the first run and reused from the - # runner-local cache afterwards. + # Drives the Core ML Converter node, which converts the UNet from the + # checkpoint on every run (cache purged above). run: uv run --no-sync pytest -m m2 tests/ -v - name: Stop ComfyUI server diff --git a/.gitignore b/.gitignore index e1324f1..5733a59 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,3 @@ __pycache__/ models/ .venv/ test_results/ -tests/m2/_latest_generated.png diff --git a/README.md b/README.md index 1c48973..a7eb693 100644 --- a/README.md +++ b/README.md @@ -8,8 +8,8 @@ These models are designed to leverage the Apple Neural Engine (ANE) on Apple Sil thereby enhancing your workflows and improving performance. If you're not sure how to obtain these models, you can download them -[here](https://huggingface.co/coreml-community) or convert your own models using -[coremltools](https://github.com/apple/ml-stable-diffusion). +[here](https://huggingface.co/coreml-community) or convert your own checkpoints +directly with the conversion nodes in this suite (see [How to use](#how-to-use)). In simple terms, think of Core ML models as a tool that can help your ComfyUI work faster and more efficiently. For instance, during my tests on an M2 Pro 32GB machine, @@ -81,6 +81,29 @@ These custom nodes come with a host of features, including: > [!NOTE] > This repository will continue to be updated with more nodes and features over time. +## Conversion & Acknowledgements + +The Core ML conversion pipeline in this repository began as an adaptation of +Apple's [ml-stable-diffusion](https://github.com/apple/ml-stable-diffusion), +which pioneered running Stable Diffusion on the Apple Neural Engine. The +implementation has since diverged and no longer depends on that package: + +- UNet conversion runs natively on `diffusers`' `UNet2DConditionModel`. +- The ANE-friendly attention path (`SPLIT_EINSUM`, `SPLIT_EINSUM_V2`) is + reimplemented as standalone `diffusers` attention processors. +- The toolchain tracks current ComfyUI (NumPy 2, Torch 2.7, coremltools 9, + Python 3.12). + +The goal is to keep iterating on these methods independently and to explore +support beyond SD1.5. + +> [!IMPORTANT] +> **Breaking change in 2.0.0.** The converted Core ML UNet now takes +> `encoder_hidden_states` in the native `diffusers` layout +> `(batch, tokens, hidden)` instead of the previous +> `(batch, hidden, 1, tokens)`. Core ML models converted with earlier versions +> are not compatible with 2.0.0 and must be re-converted. + ## Installation ### Using ComfyUI-Manager @@ -408,16 +431,15 @@ PSNR is comfortably higher (the sampler averages over 20 steps). margin, `none` if you want bit-identical output for golden testing. The default stays `none` so existing workflows produce byte-for-byte -identical output — the golden-image anchor (`tests/m2/test_golden_image.py`) -verifies this on every Tier 2 run. +identical output. ## Limitations - Core ML models are fixed in terms of their inputs and outputs. This means you'll need to use latent images of the same size as the input of the model (512x512 is the default for SD1.5). - However, you can convert the model to a different input size using tools available - in the [apple/ml-stable-diffusion](https://github.com/apple/ml-stable-diffusion) repository. + However, you can re-convert the model to a different input size using the + conversion nodes in this suite (set the desired width and height). - SD2.1 models are not supported. [^1]: diff --git a/coreml_suite/attention.py b/coreml_suite/attention.py new file mode 100644 index 0000000..ffeb979 --- /dev/null +++ b/coreml_suite/attention.py @@ -0,0 +1,5 @@ +ATTENTION_IMPLEMENTATIONS = ( + "SPLIT_EINSUM", + "SPLIT_EINSUM_V2", + "ORIGINAL", +) diff --git a/coreml_suite/config.py b/coreml_suite/config.py index c3f25fb..54a6562 100644 --- a/coreml_suite/config.py +++ b/coreml_suite/config.py @@ -1,17 +1,10 @@ -from enum import Enum - import torch from comfy import supported_models_base from comfy import latent_formats from comfy.model_detection import convert_config - -class ModelVersion(Enum): - SD15 = "sd15" - SDXL = "sdxl" - SDXL_REFINER = "sdxl_refiner" - LCM = "lcm" +from coreml_suite.model_version import ModelVersion config_map = { diff --git a/coreml_suite/conversion/__init__.py b/coreml_suite/conversion/__init__.py new file mode 100644 index 0000000..6eee9cb --- /dev/null +++ b/coreml_suite/conversion/__init__.py @@ -0,0 +1,9 @@ +"""Core ML conversion helpers. + +The conversion approach originates from Apple's ml-stable-diffusion +(https://github.com/apple/ml-stable-diffusion). This implementation has since +diverged: it runs natively on diffusers' UNet2DConditionModel with its own +SPLIT_EINSUM / SPLIT_EINSUM_V2 attention processors and no longer depends on +that package. The intent is to keep iterating on these methods independently +while tracking current tooling. +""" diff --git a/coreml_suite/conversion/attention.py b/coreml_suite/conversion/attention.py new file mode 100644 index 0000000..de6f966 --- /dev/null +++ b/coreml_suite/conversion/attention.py @@ -0,0 +1,239 @@ +import logging + +import torch + +logger = logging.getLogger(__name__) + +CHUNK_SIZE = 512 + + +def apply_attention_implementation(unet, attention_implementation): + if attention_implementation == "ORIGINAL": + return unet + + if attention_implementation == "SPLIT_EINSUM": + unet.set_attn_processor(SplitEinsumAttnProcessor()) + return unet + + if attention_implementation == "SPLIT_EINSUM_V2": + unet.set_attn_processor(SplitEinsumV2AttnProcessor()) + return unet + + raise ValueError(f"Unsupported attention implementation: {attention_implementation}") + + +class SplitEinsumAttnProcessor: + def __call__( + self, + attn, + hidden_states, + encoder_hidden_states=None, + attention_mask=None, + temb=None, + *args, + **kwargs, + ): + return _attention_forward( + attn, + hidden_states, + encoder_hidden_states, + attention_mask, + temb, + split_einsum, + ) + + +class SplitEinsumV2AttnProcessor: + def __call__( + self, + attn, + hidden_states, + encoder_hidden_states=None, + attention_mask=None, + temb=None, + *args, + **kwargs, + ): + return _attention_forward( + attn, + hidden_states, + encoder_hidden_states, + attention_mask, + temb, + split_einsum_v2, + ) + + +def _attention_forward( + attn, + hidden_states, + encoder_hidden_states, + attention_mask, + temb, + attention_fn, +): + residual = hidden_states + + if attn.spatial_norm is not None: + hidden_states = attn.spatial_norm(hidden_states, temb) + + input_ndim = hidden_states.ndim + if input_ndim == 4: + batch_size, channel, height, width = hidden_states.shape + hidden_states = hidden_states.view(batch_size, channel, height * width).transpose(1, 2) + else: + batch_size, _, channel = hidden_states.shape + height = None + width = None + + batch_size, key_sequence_length, _ = ( + hidden_states.shape if encoder_hidden_states is None else encoder_hidden_states.shape + ) + + if attention_mask is not None: + attention_mask = attn.prepare_attention_mask( + attention_mask, + key_sequence_length, + batch_size, + ) + attention_mask = _prepare_split_einsum_mask( + attention_mask, + batch_size, + attn.heads, + key_sequence_length, + ) + + if attn.group_norm is not None: + hidden_states = attn.group_norm(hidden_states.transpose(1, 2)).transpose(1, 2) + + query = attn.to_q(hidden_states) + + if encoder_hidden_states is None: + encoder_hidden_states = hidden_states + elif attn.norm_cross: + encoder_hidden_states = attn.norm_encoder_hidden_states(encoder_hidden_states) + + key = attn.to_k(encoder_hidden_states) + value = attn.to_v(encoder_hidden_states) + + batch_size = query.shape[0] + dim_head = attn.inner_kv_dim // attn.heads + + query = _linear_projection_to_bchw(query) + key = _linear_projection_to_bchw(key) + value = _linear_projection_to_bchw(value) + + hidden_states = attention_fn( + query, + key, + value, + attention_mask, + attn.heads, + dim_head, + ) + hidden_states = hidden_states.squeeze(2).transpose(1, 2) + hidden_states = hidden_states.reshape(batch_size, -1, attn.inner_dim) + + hidden_states = attn.to_out[0](hidden_states) + hidden_states = attn.to_out[1](hidden_states) + + if input_ndim == 4: + hidden_states = hidden_states.transpose(-1, -2).reshape( + batch_size, + channel, + height, + width, + ) + + if attn.residual_connection: + hidden_states = hidden_states + residual + + hidden_states = hidden_states / attn.rescale_output_factor + return hidden_states + + +def split_einsum(q, k, v, mask, heads, dim_head): + q_heads = _split_heads(q, heads, dim_head) + k = k.transpose(1, 3) + k_heads = [ + k[:, :, :, head_idx * dim_head : (head_idx + 1) * dim_head] + for head_idx in range(heads) + ] + v_heads = _split_heads(v, heads, dim_head) + + weights = [ + torch.einsum("bchq,bkhc->bkhq", query, key) * (dim_head**-0.5) + for query, key in zip(q_heads, k_heads) + ] + if mask is not None: + weights = [weight + mask for weight in weights] + + weights = [weight.softmax(dim=1) for weight in weights] + outputs = [ + torch.einsum("bkhq,bchk->bchq", weight, value) + for weight, value in zip(weights, v_heads) + ] + return torch.cat(outputs, dim=1) + + +def split_einsum_v2(q, k, v, mask, heads, dim_head): + query_length = q.size(3) + num_chunks = query_length // CHUNK_SIZE + if num_chunks == 0: + logger.info( + "SPLIT_EINSUM_V2 query sequence is shorter than %s; using SPLIT_EINSUM.", + CHUNK_SIZE, + ) + return split_einsum(q, k, v, mask, heads, dim_head) + + q_heads = _split_heads(q, heads, dim_head) + q_chunks = [ + [ + head[..., chunk_idx * CHUNK_SIZE : (chunk_idx + 1) * CHUNK_SIZE] + for chunk_idx in range(num_chunks) + ] + for head in q_heads + ] + + k = k.transpose(1, 3) + k_heads = [ + k[:, :, :, head_idx * dim_head : (head_idx + 1) * dim_head] + for head_idx in range(heads) + ] + v_heads = _split_heads(v, heads, dim_head) + + head_outputs = [] + for query_chunks, key, value in zip(q_chunks, k_heads, v_heads): + chunk_outputs = [] + for query_chunk in query_chunks: + weights = torch.einsum("bchq,bkhc->bkhq", query_chunk, key) + weights = weights * (dim_head**-0.5) + if mask is not None: + weights = weights + mask + weights = weights.softmax(dim=1) + chunk_outputs.append(torch.einsum("bkhq,bchk->bchq", weights, value)) + head_outputs.append(torch.cat(chunk_outputs, dim=3)) + + return torch.cat(head_outputs, dim=1) + + +def _split_heads(x, heads, dim_head): + return [ + x[:, head_idx * dim_head : (head_idx + 1) * dim_head, :, :] + for head_idx in range(heads) + ] + + +def _linear_projection_to_bchw(x): + return x.transpose(1, 2).unsqueeze(2) + + +def _prepare_split_einsum_mask(mask, batch_size, heads, key_sequence_length): + if mask.ndim == 2: + mask = mask[:, None, :] + if mask.shape[0] == batch_size * heads: + mask = mask.reshape(batch_size, heads, -1, key_sequence_length) + mask = mask[:, 0] + if mask.ndim == 3: + mask = mask[:, :, None, None] + return mask diff --git a/coreml_suite/conversion/shapes.py b/coreml_suite/conversion/shapes.py new file mode 100644 index 0000000..1991e73 --- /dev/null +++ b/coreml_suite/conversion/shapes.py @@ -0,0 +1,20 @@ +def conv2d_output_shape(height, width, conv): + """Return the spatial output shape for a torch.nn.Conv2d-like module.""" + kernel_h, kernel_w = _pair(conv.kernel_size) + stride_h, stride_w = _pair(conv.stride) + pad_h, pad_w = _pair(conv.padding) + dilation_h, dilation_w = _pair(conv.dilation) + + out_h = _conv_output_dim(height, kernel_h, stride_h, pad_h, dilation_h) + out_w = _conv_output_dim(width, kernel_w, stride_w, pad_w, dilation_w) + return out_h, out_w + + +def _conv_output_dim(size, kernel, stride, padding, dilation): + return ((size + (2 * padding) - (dilation * (kernel - 1)) - 1) // stride) + 1 + + +def _pair(value): + if isinstance(value, tuple): + return value + return value, value diff --git a/coreml_suite/conversion/trace.py b/coreml_suite/conversion/trace.py new file mode 100644 index 0000000..ab443bf --- /dev/null +++ b/coreml_suite/conversion/trace.py @@ -0,0 +1,61 @@ +from types import MethodType + +from diffusers.models.transformers.transformer_2d import Transformer2DModel + + +def prepare_unet_for_coreml_trace(unet): + for module in unet.modules(): + if isinstance(module, Transformer2DModel): + module._operate_on_continuous_inputs = MethodType( + _operate_on_continuous_inputs, + module, + ) + module._get_output_for_continuous_inputs = MethodType( + _get_output_for_continuous_inputs, + module, + ) + return unet + + +def _operate_on_continuous_inputs(self, hidden_states): + hidden_states = self.norm(hidden_states) + + if not self.use_linear_projection: + hidden_states = self.proj_in(hidden_states) + inner_dim = self.inner_dim + hidden_states = hidden_states.flatten(2).transpose(1, 2) + else: + inner_dim = hidden_states.shape[1] + hidden_states = hidden_states.flatten(2).transpose(1, 2) + hidden_states = self.proj_in(hidden_states) + + return hidden_states, inner_dim + + +def _get_output_for_continuous_inputs( + self, + hidden_states, + residual, + batch_size, + height, + width, + inner_dim, +): + if not self.use_linear_projection: + hidden_states = hidden_states.transpose(1, 2).reshape( + batch_size, + inner_dim, + height, + width, + ) + hidden_states = self.proj_out(hidden_states) + else: + hidden_states = self.proj_out(hidden_states) + hidden_states = hidden_states.transpose(1, 2).reshape( + batch_size, + inner_dim, + height, + width, + ) + + return hidden_states + residual diff --git a/coreml_suite/conversion/unet.py b/coreml_suite/conversion/unet.py new file mode 100644 index 0000000..0dd01cd --- /dev/null +++ b/coreml_suite/conversion/unet.py @@ -0,0 +1,54 @@ +import torch + + +class CoreMLUNetWrapper(torch.nn.Module): + """Adapt diffusers UNet inputs to CoreMLSuite's stable Core ML contract.""" + + def __init__(self, unet, model_version): + super().__init__() + self.unet = unet + self.model_version = model_version + + def forward(self, sample, timestep, encoder_hidden_states, *extra_inputs): + input_index = 0 + timestep_cond = None + if self._is_lcm: + timestep_cond = extra_inputs[input_index] + input_index += 1 + + added_cond_kwargs = None + if self._is_sdxl: + time_ids = extra_inputs[input_index] + text_embeds = extra_inputs[input_index + 1] + input_index += 2 + added_cond_kwargs = { + "time_ids": time_ids, + "text_embeds": text_embeds, + } + + additional_residuals = extra_inputs[input_index:] + down_residuals = None + mid_residual = None + if additional_residuals: + down_residuals = tuple(additional_residuals[:-1]) + mid_residual = additional_residuals[-1] + + outputs = self.unet( + sample, + timestep, + encoder_hidden_states=encoder_hidden_states, + timestep_cond=timestep_cond, + added_cond_kwargs=added_cond_kwargs, + down_block_additional_residuals=down_residuals, + mid_block_additional_residual=mid_residual, + return_dict=False, + ) + return outputs[0] + + @property + def _is_lcm(self): + return self.model_version.name == "LCM" + + @property + def _is_sdxl(self): + return self.model_version.name in {"SDXL", "SDXL_REFINER"} diff --git a/coreml_suite/converter.py b/coreml_suite/converter.py index 1af74cd..619cc40 100644 --- a/coreml_suite/converter.py +++ b/coreml_suite/converter.py @@ -2,71 +2,38 @@ import gc import os import shutil import time -from typing import Union import coremltools as ct import numpy as np -import python_coreml_stable_diffusion.unet import torch -from diffusers import ( - StableDiffusionPipeline, - LatentConsistencyModelPipeline, - StableDiffusionXLPipeline, -) -from python_coreml_stable_diffusion.unet import ( - UNet2DConditionModel, - UNet2DConditionModelXL, - AttentionImplementations, -) +from diffusers import UNet2DConditionModel -from coreml_suite.config import ModelVersion -from coreml_suite.lcm.unet import UNet2DConditionModelLCM +from coreml_suite.attention import ATTENTION_IMPLEMENTATIONS +from coreml_suite.conversion.attention import apply_attention_implementation +from coreml_suite.conversion.shapes import conv2d_output_shape +from coreml_suite.conversion.trace import prepare_unet_for_coreml_trace +from coreml_suite.conversion.unet import CoreMLUNetWrapper from coreml_suite.logger import logger -from folder_paths import get_folder_paths +from coreml_suite.model_version import ModelVersion + +DEFAULT_TRACE_TIMESTEP = 999.0 +TEXT_TOKEN_SEQUENCE_LENGTH = 77 -class StableDiffusionLCMPipeline(LatentConsistencyModelPipeline): - pass - - -MODEL_TYPE_TO_UNET_CLS = { - ModelVersion.SD15: UNet2DConditionModel, - ModelVersion.SDXL: UNet2DConditionModelXL, - ModelVersion.LCM: UNet2DConditionModelLCM, -} - -MODEL_TYPE_TO_PIPE_CLS = { - ModelVersion.SD15: StableDiffusionPipeline, - ModelVersion.SDXL: StableDiffusionXLPipeline, - ModelVersion.LCM: StableDiffusionLCMPipeline, -} - - -def get_unet(model_type: ModelVersion, ref_pipe): - ref_unet = ref_pipe.unet - - unet_cls = MODEL_TYPE_TO_UNET_CLS[model_type] - cml_unet = unet_cls.from_config(ref_unet.config).eval() - cml_unet.load_state_dict(ref_unet.state_dict(), strict=False) - - return cml_unet - - -def get_encoder_hidden_states_shape(ref_pipe, batch_size): - text_encoder = ( - ref_pipe.text_encoder_2 - if hasattr(ref_pipe, "text_encoder_2") - else ref_pipe.text_encoder +def get_unet(model_version: ModelVersion, ref_unet, attention_implementation): + ref_unet = prepare_unet_for_coreml_trace(ref_unet) + unet = apply_attention_implementation( + ref_unet.eval(), + attention_implementation, ) + return CoreMLUNetWrapper(unet, model_version) - text_token_sequence_length = text_encoder.config.max_position_embeddings - hidden_size = (text_encoder.config.hidden_size,) +def get_encoder_hidden_states_shape(ref_unet, batch_size): encoder_hidden_states_shape = ( batch_size, - ref_pipe.unet.config.cross_attention_dim or hidden_size, - 1, - text_token_sequence_length, + TEXT_TOKEN_SEQUENCE_LENGTH, + ref_unet.config.cross_attention_dim, ) return encoder_hidden_states_shape @@ -122,6 +89,8 @@ def convert_to_coreml( def get_out_path(submodule_name, model_name): + from folder_paths import get_folder_paths + fname = f"{model_name}_{submodule_name}.mlpackage" unet_path = get_folder_paths(submodule_name)[0] out_path = os.path.join(unet_path, fname) @@ -145,15 +114,13 @@ def compile_coreml_model(source_model_path, output_dir, final_name): return target_path -def get_sample_input(batch_size, encoder_hidden_states_shape, sample_shape, scheduler): +def get_sample_input(batch_size, encoder_hidden_states_shape, sample_shape): sample_unet_inputs = dict( [ ("sample", torch.rand(*sample_shape)), ( "timestep", - torch.tensor([scheduler.timesteps[0].item()] * batch_size).to( - torch.float32 - ), + torch.tensor([DEFAULT_TRACE_TIMESTEP] * batch_size).to(torch.float32), ), ("encoder_hidden_states", torch.rand(*encoder_hidden_states_shape)), ] @@ -166,7 +133,7 @@ def lcm_inputs(sample_unet_inputs): return {"timestep_cond": torch.randn(batch_size, 256).to(torch.float32)} -def sdxl_inputs(sample_unet_inputs, ref_pipe): +def sdxl_inputs(sample_unet_inputs, ref_unet, model_version): sample_shape = sample_unet_inputs["sample"].shape batch_size = sample_shape[0] h = sample_shape[2] * 8 @@ -174,10 +141,7 @@ def sdxl_inputs(sample_unet_inputs, ref_pipe): original_size = (h, w) crops_coords_top_left = (0, 0) - is_refiner = ( - hasattr(ref_pipe.config, "requires_aesthetics_score") - and ref_pipe.config.requires_aesthetics_score - ) + is_refiner = model_version == ModelVersion.SDXL_REFINER if is_refiner: aesthetic_score = (6.0,) @@ -187,7 +151,7 @@ def sdxl_inputs(sample_unet_inputs, ref_pipe): time_ids_list = list(original_size + crops_coords_top_left + target_size) time_ids = torch.tensor(time_ids_list).repeat(batch_size, 1).to(torch.int64) - text_embeds_shape = (batch_size, ref_pipe.text_encoder_2.config.hidden_size) + text_embeds_shape = (batch_size, get_sdxl_text_embeds_dim(ref_unet, len(time_ids_list))) return { "time_ids": time_ids, @@ -195,21 +159,25 @@ def sdxl_inputs(sample_unet_inputs, ref_pipe): } +def get_sdxl_text_embeds_dim(ref_unet, time_ids_dim): + projection_dim = ref_unet.config.projection_class_embeddings_input_dim + time_embed_dim = ref_unet.config.addition_time_embed_dim + return projection_dim - (time_ids_dim * time_embed_dim) + + def get_inputs_spec(inputs): inputs_spec = {k: (v.shape, v.dtype) for k, v in inputs.items()} return inputs_spec def add_cnet_support(sample_shape, reference_unet): - from python_coreml_stable_diffusion.unet import calculate_conv2d_output_shape - additional_residuals_shapes = [] batch_size = sample_shape[0] h, w = sample_shape[2:] # conv_in - out_h, out_w = calculate_conv2d_output_shape( + out_h, out_w = conv2d_output_shape( h, w, reference_unet.conv_in, @@ -226,9 +194,7 @@ def add_cnet_support(sample_shape, reference_unet): ] if hasattr(down_block, "downsamplers") and down_block.downsamplers is not None: for downsampler in down_block.downsamplers: - out_h, out_w = calculate_conv2d_output_shape( - out_h, out_w, downsampler.conv - ) + out_h, out_w = conv2d_output_shape(out_h, out_w, downsampler.conv) additional_residuals_shapes.append( ( batch_size, @@ -252,16 +218,16 @@ def add_cnet_support(sample_shape, reference_unet): def convert_unet( - ref_pipe, + ref_unet, model_version: ModelVersion, unet_out_path: str, batch_size: int = 1, sample_size: tuple[int, int] = (64, 64), controlnet_support: bool = False, + attention_implementation: str = ATTENTION_IMPLEMENTATIONS[0], quantize_nbits: str = "none", ): - coreml_unet = get_unet(model_version, ref_pipe) - ref_unet = ref_pipe.unet + coreml_unet = get_unet(model_version, ref_unet, attention_implementation) sample_shape = ( batch_size, # B @@ -270,20 +236,17 @@ def convert_unet( sample_size[1], # W ) - encoder_hidden_states_shape = get_encoder_hidden_states_shape(ref_pipe, batch_size) - - scheduler = ref_pipe.scheduler - scheduler.set_timesteps(50) + encoder_hidden_states_shape = get_encoder_hidden_states_shape(ref_unet, batch_size) sample_inputs = get_sample_input( - batch_size, encoder_hidden_states_shape, sample_shape, scheduler + batch_size, encoder_hidden_states_shape, sample_shape ) if model_version == ModelVersion.LCM: sample_inputs |= lcm_inputs(sample_inputs) - if model_version == ModelVersion.SDXL: - sample_inputs |= sdxl_inputs(sample_inputs, ref_pipe) + if model_version in {ModelVersion.SDXL, ModelVersion.SDXL_REFINER}: + sample_inputs |= sdxl_inputs(sample_inputs, ref_unet, model_version) if controlnet_support: sample_inputs |= add_cnet_support(sample_shape, ref_unet) @@ -335,8 +298,8 @@ def convert( batch_size: int = 1, sample_size: tuple[int, int] = (64, 64), controlnet_support: bool = False, - lora_weights: list[tuple[Union[str, os.PathLike], float]] = None, - attn_impl: str = AttentionImplementations.SPLIT_EINSUM.name, + lora_weights: list[tuple[str | os.PathLike, float]] = None, + attn_impl: str = ATTENTION_IMPLEMENTATIONS[0], config_path: str = None, quantize_nbits: str = "none", ): @@ -344,37 +307,42 @@ def convert( logger.info(f"Found existing model at {unet_out_path}! Skipping..") return - python_coreml_stable_diffusion.unet.ATTENTION_IMPLEMENTATION_IN_EFFECT = ( - AttentionImplementations(attn_impl) - ) - - ref_pipe = get_pipeline(ckpt_path, config_path, model_version) + if attn_impl not in ATTENTION_IMPLEMENTATIONS: + raise ValueError( + f"Unsupported attention implementation {attn_impl!r}. " + f"Expected one of {ATTENTION_IMPLEMENTATIONS}." + ) + ref_unet = load_unet(ckpt_path, config_path) for i, lora_weight in enumerate(lora_weights or []): lora_path, strength = lora_weight adapter_name = f"lora_{i}" - ref_pipe.load_lora_weights(lora_path, adapter_name=adapter_name) - ref_pipe.set_adapters([adapter_name], adapter_weights=[strength]) - ref_pipe.fuse_lora() + ref_unet.load_lora_adapter(lora_path, adapter_name=adapter_name) + ref_unet.set_adapters([adapter_name], weights=[strength]) + ref_unet.fuse_lora() convert_unet( - ref_pipe, + ref_unet, model_version, unet_out_path, batch_size, sample_size, controlnet_support, + attention_implementation=attn_impl, quantize_nbits=quantize_nbits, ) -def get_pipeline(ckpt_path, config_path, model_version): - pipe_cls = MODEL_TYPE_TO_PIPE_CLS[model_version] - ref_pipe = pipe_cls.from_single_file(ckpt_path, original_config_file=config_path) - return ref_pipe +def load_unet(ckpt_path, config_path): + return UNet2DConditionModel.from_single_file( + ckpt_path, + original_config=config_path, + ) def compile_model(out_path, out_name, submodule_name): + from folder_paths import get_folder_paths + # Compile the model target_path = compile_coreml_model( out_path, get_folder_paths(submodule_name)[0], f"{out_name}_{submodule_name}" diff --git a/coreml_suite/core/inputs.py b/coreml_suite/core/inputs.py index b875c5a..2b4d40f 100644 --- a/coreml_suite/core/inputs.py +++ b/coreml_suite/core/inputs.py @@ -24,7 +24,6 @@ class CoreMLInputs: sample = self.x.cpu().numpy().astype(np.float16) context = self.context.cpu().numpy().astype(np.float16) - context = context.transpose(0, 2, 1)[:, :, None, :] t = self.t.cpu().numpy().astype(np.float16) @@ -57,8 +56,7 @@ class CoreMLInputs: def chunks(self, expected_inputs): sample_shape = expected_inputs["sample"]["shape"] timestep_shape = expected_inputs["timestep"]["shape"] - hidden_shape = expected_inputs["encoder_hidden_states"]["shape"] - context_shape = (hidden_shape[0], hidden_shape[3], hidden_shape[1]) + context_shape = expected_inputs["encoder_hidden_states"]["shape"] chunked_x = chunk_batch(self.x, sample_shape) ts = list(torch.full((len(chunked_x), timestep_shape[0]), self.t[0])) diff --git a/coreml_suite/coreml_model.py b/coreml_suite/coreml_model.py new file mode 100644 index 0000000..14b2a04 --- /dev/null +++ b/coreml_suite/coreml_model.py @@ -0,0 +1,42 @@ +import time + +import coremltools as ct + +from coreml_suite.logger import logger + + +class CoreMLModel: + """Small runtime wrapper around coremltools.models.MLModel. + + This keeps the inference path independent from apple/ml-stable-diffusion's + CoreMLModel wrapper while preserving the contract used by the sampler code: + ``expected_inputs`` and callable prediction. + """ + + def __init__(self, model_path, compute_unit): + self.model_path = model_path + self.compute_unit = self._compute_unit(compute_unit) + + logger.info(f"Loading {model_path} to {self.compute_unit.name}") + start = time.time() + self.model = ct.models.MLModel(model_path, compute_units=self.compute_unit) + logger.info(f"Loading {model_path} took {time.time() - start:.1f} seconds") + + self.expected_inputs = self._expected_inputs() + + def __call__(self, **kwargs): + return self.model.predict(kwargs) + + @staticmethod + def _compute_unit(compute_unit): + if isinstance(compute_unit, ct.ComputeUnit): + return compute_unit + return ct.ComputeUnit[compute_unit] + + def _expected_inputs(self): + return { + feature.name: { + "shape": tuple(feature.type.multiArrayType.shape), + } + for feature in self.model.get_spec().description.input + } diff --git a/coreml_suite/lcm/converter.py b/coreml_suite/lcm/converter.py index 6d3c3fc..1a63f7a 100644 --- a/coreml_suite/lcm/converter.py +++ b/coreml_suite/lcm/converter.py @@ -9,24 +9,20 @@ import torch from diffusers import UNet2DConditionModel, LCMScheduler from diffusers.loaders import LoraLoaderMixin -from comfy.model_management import get_torch_device -from coreml_suite.lcm.unet import UNet2DConditionModelLCM +from coreml_suite.conversion.attention import apply_attention_implementation +from coreml_suite.conversion.shapes import conv2d_output_shape +from coreml_suite.conversion.unet import CoreMLUNetWrapper +from coreml_suite.model_version import ModelVersion -from transformers import CLIPTextModel import coremltools as ct -from folder_paths import get_folder_paths - logging.basicConfig() logger = logging.getLogger(__name__) logger.setLevel(logging.DEBUG) MODEL_VERSION = "SimianLuo/LCM_Dreamshaper_v7" MODEL_NAME = MODEL_VERSION.split("/")[-1] + "_4k" - -import python_coreml_stable_diffusion.unet as unet - -unet.ATTENTION_IMPLEMENTATION_IN_EFFECT = unet.AttentionImplementations.SPLIT_EINSUM +TEXT_TOKEN_SEQUENCE_LENGTH = 77 def get_unets(): @@ -37,31 +33,27 @@ def get_unets(): low_cpu_mem_usage=False, ) - cml_unet = UNet2DConditionModelLCM.from_config(ref_unet.config).eval() - cml_unet.load_state_dict(ref_unet.state_dict(), strict=False) + cml_unet = CoreMLUNetWrapper( + apply_attention_implementation(ref_unet.eval(), "SPLIT_EINSUM"), + ModelVersion.LCM, + ) return cml_unet, ref_unet def get_encoder_hidden_states_shape(unet_config, batch_size): - text_encoder = CLIPTextModel.from_pretrained( - MODEL_VERSION, subfolder="text_encoder" - ) - - text_token_sequence_length = text_encoder.config.max_position_embeddings - hidden_size = (text_encoder.config.hidden_size,) - encoder_hidden_states_shape = ( batch_size, - unet_config.cross_attention_dim or hidden_size, - 1, - text_token_sequence_length, + TEXT_TOKEN_SEQUENCE_LENGTH, + unet_config.cross_attention_dim, ) return encoder_hidden_states_shape def get_scheduler(): + from comfy.model_management import get_torch_device + scheduler = LCMScheduler.from_pretrained(MODEL_VERSION, subfolder="scheduler") scheduler.set_timesteps(50, get_torch_device(), 50) return scheduler @@ -117,6 +109,8 @@ def convert_to_coreml( def get_out_path(submodule_name, model_name): + from folder_paths import get_folder_paths + fname = f"{model_name}_{submodule_name}.mlpackage" unet_path = get_folder_paths(submodule_name)[0] out_path = os.path.join(unet_path, fname) @@ -165,15 +159,13 @@ def get_unet_inputs_spec(sample_unet_inputs): def add_cnet_support(sample_shape, reference_unet): - from python_coreml_stable_diffusion.unet import calculate_conv2d_output_shape - additional_residuals_shapes = [] batch_size = sample_shape[0] h, w = sample_shape[2:] # conv_in - out_h, out_w = calculate_conv2d_output_shape( + out_h, out_w = conv2d_output_shape( h, w, reference_unet.conv_in, @@ -190,9 +182,7 @@ def add_cnet_support(sample_shape, reference_unet): ] if hasattr(down_block, "downsamplers") and down_block.downsamplers is not None: for downsampler in down_block.downsamplers: - out_h, out_w = calculate_conv2d_output_shape( - out_h, out_w, downsampler.conv - ) + out_h, out_w = conv2d_output_shape(out_h, out_w, downsampler.conv) additional_residuals_shapes.append( ( batch_size, @@ -273,6 +263,8 @@ def convert( def compile_model(out_path, out_name): + from folder_paths import get_folder_paths + # Compile the model target_path = compile_coreml_model( out_path, get_folder_paths("unet")[0], f"{out_name}_unet" diff --git a/coreml_suite/lcm/nodes.py b/coreml_suite/lcm/nodes.py index 6c7d885..ee1c491 100644 --- a/coreml_suite/lcm/nodes.py +++ b/coreml_suite/lcm/nodes.py @@ -1,10 +1,9 @@ import os from coremltools import ComputeUnit -from python_coreml_stable_diffusion.coreml_model import CoreMLModel from coreml_suite import COREML_NODE -from coreml_suite.lcm import converter as lcm_converter +from coreml_suite.coreml_model import CoreMLModel class COREML_CONVERT_LCM(COREML_NODE): @@ -48,6 +47,8 @@ class COREML_CONVERT_LCM(COREML_NODE): The converted model is also saved to "models/unet" directory and can be loaded with the "LCMCoreMLLoaderUNet" node. """ + from coreml_suite.lcm import converter as lcm_converter + h = height w = width sample_size = (h // 8, w // 8) @@ -67,4 +68,4 @@ class COREML_CONVERT_LCM(COREML_NODE): ) target_path = lcm_converter.compile_model(out_path=out_path, out_name=out_name) - return (CoreMLModel(target_path, compute_unit, "compiled"),) + return (CoreMLModel(target_path, compute_unit),) diff --git a/coreml_suite/lcm/unet.py b/coreml_suite/lcm/unet.py index 729d41f..115a3d7 100644 --- a/coreml_suite/lcm/unet.py +++ b/coreml_suite/lcm/unet.py @@ -1,5 +1,5 @@ -from overrides import overrides -from python_coreml_stable_diffusion.unet import UNet2DConditionModel, TimestepEmbedding +from diffusers import UNet2DConditionModel +from diffusers.models.embeddings import TimestepEmbedding class UNet2DConditionModelLCM(UNet2DConditionModel): @@ -17,7 +17,6 @@ class UNet2DConditionModelLCM(UNet2DConditionModel): ) self.time_embedding = time_embedding - @overrides(check_signature=False) def forward( self, sample, diff --git a/coreml_suite/model_version.py b/coreml_suite/model_version.py new file mode 100644 index 0000000..d4d2fa1 --- /dev/null +++ b/coreml_suite/model_version.py @@ -0,0 +1,8 @@ +from enum import Enum + + +class ModelVersion(Enum): + SD15 = "sd15" + SDXL = "sdxl" + SDXL_REFINER = "sdxl_refiner" + LCM = "lcm" diff --git a/coreml_suite/nodes.py b/coreml_suite/nodes.py index 00025fc..1d15278 100644 --- a/coreml_suite/nodes.py +++ b/coreml_suite/nodes.py @@ -1,13 +1,11 @@ import os from coremltools import ComputeUnit -from python_coreml_stable_diffusion.coreml_model import CoreMLModel -from python_coreml_stable_diffusion.unet import AttentionImplementations import folder_paths from coreml_suite import COREML_NODE -from coreml_suite import converter -from coreml_suite.config import ModelVersion +from coreml_suite.attention import ATTENTION_IMPLEMENTATIONS +from coreml_suite.coreml_model import CoreMLModel from coreml_suite.core.naming import ( QUANT_NBITS_VALUES, compose_out_name, @@ -15,6 +13,7 @@ from coreml_suite.core.naming import ( ) from coreml_suite.lcm.utils import add_lcm_model_options, lcm_patch, is_lcm from coreml_suite.logger import logger +from coreml_suite.model_version import ModelVersion from nodes import KSampler, LoraLoader, KSamplerAdvanced from coreml_suite.models import ( @@ -179,9 +178,7 @@ class CoreMLLoader(COREML_NODE): coreml_path = self.coreml_filenames()[coreml_name] - sources = "compiled" if coreml_name.endswith(".mlmodelc") else "packages" - - return (CoreMLModel(coreml_path, compute_unit, sources),) + return (CoreMLModel(coreml_path, compute_unit),) class CoreMLLoaderUNet(CoreMLLoader): @@ -232,11 +229,7 @@ class CoreMLConverter(COREML_NODE): "width": ("INT", {"default": 512, "min": 256, "max": 2048, "step": 8}), "batch_size": ("INT", {"default": 1, "min": 1, "max": 64}), "attention_implementation": ( - [ - AttentionImplementations.SPLIT_EINSUM.name, - AttentionImplementations.SPLIT_EINSUM_V2.name, - AttentionImplementations.ORIGINAL.name, - ], + list(ATTENTION_IMPLEMENTATIONS), ), "compute_unit": ( [ @@ -322,6 +315,8 @@ class CoreMLConverter(COREML_NODE): for lora_param in lora_params: logger.info(f" {lora_param[0]} - strength: {lora_param[1]}") + from coreml_suite import converter + unet_out_path = converter.get_out_path("unet", f"{out_name}") ckpt_path = folder_paths.get_full_path("checkpoints", ckpt_name) @@ -346,7 +341,7 @@ class CoreMLConverter(COREML_NODE): out_path=unet_out_path, out_name=out_name, submodule_name="unet" ) - return (CoreMLModel(unet_target_path, compute_unit, "compiled"),) + return (CoreMLModel(unet_target_path, compute_unit),) @staticmethod def lora_path(lora_name): diff --git a/pyproject.toml b/pyproject.toml index 79aeea4..bddbe47 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,50 +1,35 @@ [project] name = "comfyui-coremlsuite" description = "This extension contains a set of custom nodes for ComfyUI that allow you to use Core ML models in your ComfyUI workflows." -version = "1.0.1" +version = "2.0.0" license = "MIT" requires-python = ">=3.12,<3.13" packages = [{ include = "coreml_suite" }] dependencies = [ - # Python 3.12, coremltools 9, torch 2.7. - # numpy stays in the 1.24..1.x range — none of our modules need - # numpy 2, and coremltools + ml-stable-diffusion's SD UNet trace - # hit hard bugs under numpy 2 (`_cast` int(ndarray) strictness and - # `view` mixed-Var shape lists). - # torch 2.7 is the latest version coremltools 9's PyTorch frontend - # has been tested against. - "python-coreml-stable-diffusion @ git+https://github.com/apple/ml-stable-diffusion.git@e5d960c41a6a4ab200b8db379194127607b1c590", "torch>=2.7,<2.8", "coremltools>=9,<10", - "numpy>=1.24,<2", - "overrides", - "diffusers>=0.22", - "peft>=0.6.2", + "numpy>=2,<3", + "diffusers>=0.30", + "peft>=0.13", "omegaconf>=2.3", + "transformers>=4.44", ] [project.urls] Repository = "https://github.com/aszc-dev/ComfyUI-CoreMLSuite" -# Used by Comfy Registry https://comfyregistry.org [tool.comfy] PublisherId = "aszc-dev" DisplayName = "ComfyUI-CoreMLSuite" Icon = "" -# Pinned to the ComfyUI commit this toolchain was validated against. -requires-comfyui = "==ab5413351eee61f3d7f10c74e75286df0058bb18" +requires-comfyui = ">=0.3.27" [dependency-groups] dev = [ "pillow>=12.2.0", "psutil>=7.2.2", + "pytest>=9.0.3", ] -# ComfyUI runtime deps that aren't part of our package's runtime contract -# but are needed to spin up the ComfyUI server for Tier 2 integration tests. -# Kept in a uv group so `uv sync --group comfy` brings them in without -# polluting the published metadata (and without re-bumping our torch pin -# via `uv pip install -r ComfyUI/requirements.txt`, which would float to -# the latest torch and break the coremltools 9 compatibility ceiling). comfy = [ "comfyui-frontend-package==1.14.6", "torchvision", @@ -61,34 +46,11 @@ comfy = [ "sentencepiece", ] -[tool.uv] -# ml-stable-diffusion's setup.py hard-pins numpy<1.24, diffusers==0.30.2 -# and transformers==4.44.2, which blocks the modern torch / coremltools -# combo on Python 3.12. Override the four blocking pins; the .unet / -# .coreml_model symbols we actually import are stable across the bumped -# versions. -override-dependencies = [ - "numpy>=1.24,<2", - "diffusers>=0.30", - "transformers>=4.44", - "huggingface-hub>=0.24", -] - [tool.pytest.ini_options] -# Tier markers gate which environment a test needs. -# - unit: framework-free pure-logic tests (Tier 0; run without ComfyUI on -# Linux). -# - m2: needs an Apple Silicon Mac with the Neural Engine (Tier 2), -# typically a self-hosted runner or local M-series box. -# - smoke: lightweight checks that need Apple Silicon + coremltools but no -# ANE/real model (Tier 1). markers = [ "unit: framework-free unit test (Tier 0)", - "m2: requires Apple Silicon + Neural Engine (Tier 2)", "smoke: macOS-ARM smoke test on a synthetic micro-model (Tier 1)", + "m2: requires Apple Silicon + Neural Engine (Tier 2)", ] testpaths = ["tests"] -# importlib mode keeps pytest from importing the repo-root __init__.py -# (which is the ComfyUI custom-node entry and pulls in comfy + nodes). -# Without this Tier-0 leaks the entire ComfyUI runtime on collection. addopts = ["--import-mode=importlib", "--confcutdir=tests"] diff --git a/requirements.txt b/requirements.txt index a6eebec..2824535 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,8 +1,7 @@ -git+https://github.com/apple/ml-stable-diffusion.git@e5d960c41a6a4ab200b8db379194127607b1c590 torch>=2.7,<2.8 -coremltools==8.2 +coremltools>=9,<10 numpy>=2,<3 -overrides -diffusers>=0.22 -peft>=0.6.2 +diffusers>=0.30 +peft>=0.13 omegaconf>=2.3 +transformers>=4.44 diff --git a/tests/conftest.py b/tests/conftest.py index 95ecb9d..1f7c3cb 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -4,7 +4,7 @@ that transitively import `comfy.*` resolve when pytest is invoked from this package's root. - Auto-applies tier markers based on the directory a test lives in, so - individual files don't have to repeat @pytest.mark.unit / .m2. + individual files don't have to repeat @pytest.mark.unit / .smoke. """ import sys from pathlib import Path @@ -26,9 +26,9 @@ _TIER_BY_DIR = { "tests/smoke": "smoke", } -# When the user asks for a single tier (-m unit / -m m2), skip the other -# directories at collection time. Tier-0 cannot afford to import tests/m2 -# files because they pull in PIL + ComfyUI runtime which Linux CI won't have. +# When the user asks for a single tier (-m unit / -m smoke), skip the other +# directories at collection time. Tier-0 cannot afford to import tests/smoke +# files because they pull in coremltools which Linux CI won't have. _TIER_DIRS = { "unit": ("/tests/unit/",), "m2": ("/tests/m2/", "/tests/integration/"), diff --git a/tests/smoke/test_split_einsum_attention.py b/tests/smoke/test_split_einsum_attention.py new file mode 100644 index 0000000..44c89d6 --- /dev/null +++ b/tests/smoke/test_split_einsum_attention.py @@ -0,0 +1,41 @@ +import platform + +import pytest +import torch +from diffusers.models.attention_processor import Attention, AttnProcessor + +from coreml_suite.conversion.attention import ( + SplitEinsumAttnProcessor, + SplitEinsumV2AttnProcessor, +) + + +pytestmark = pytest.mark.skipif( + platform.system() != "Darwin" or platform.machine() != "arm64", + reason="Tier 1 requires macOS on Apple Silicon", +) + + +@pytest.mark.parametrize( + "processor", + [ + SplitEinsumAttnProcessor(), + SplitEinsumV2AttnProcessor(), + ], +) +def test_split_einsum_processor_matches_diffusers_attention(processor): + torch.manual_seed(0) + reference = Attention(query_dim=32, heads=4, dim_head=8, dropout=0.0) + reference.set_processor(AttnProcessor()) + + candidate = Attention(query_dim=32, heads=4, dim_head=8, dropout=0.0) + candidate.load_state_dict(reference.state_dict()) + candidate.set_processor(processor) + + hidden_states = torch.randn(2, 17, 32) + encoder_hidden_states = torch.randn(2, 11, 32) + + expected = reference(hidden_states, encoder_hidden_states=encoder_hidden_states) + actual = candidate(hidden_states, encoder_hidden_states=encoder_hidden_states) + + assert torch.allclose(actual, expected, atol=1e-5) diff --git a/tests/smoke/test_synthetic_unet.py b/tests/smoke/test_synthetic_unet.py index b5f074c..1f14f84 100644 --- a/tests/smoke/test_synthetic_unet.py +++ b/tests/smoke/test_synthetic_unet.py @@ -1,13 +1,13 @@ """Tier 1 smoke: convert a synthetic micro-UNet through coremltools and load -it back with python_coreml_stable_diffusion's CoreMLModel. +it back with CoreMLSuite's runtime CoreMLModel wrapper. -Purpose: catch API breakage in coremltools / ml-stable-diffusion *without* -needing a real SD checkpoint, the ANE, or a converted .mlmodelc on disk. +Purpose: catch API breakage in coremltools *without* needing a real SD +checkpoint, the ANE, or a converted .mlmodelc on disk. Runs in minutes on a hosted macOS-ARM runner (no Apple internal stuff). What it asserts: - coremltools.convert still accepts the call shape we use today - - the resulting .mlpackage round-trips through CoreMLModel + - the resulting .mlpackage round-trips through CoreMLSuite's CoreMLModel - expected_inputs exposes the input names/shapes we declared - calling the model returns the named output (`noise_pred`) @@ -15,12 +15,15 @@ Auto-skips on non-Apple-Silicon hosts so Tier 0 CI on Linux ignores it. """ import platform import shutil +from types import SimpleNamespace import numpy as np import pytest import torch import torch.nn as nn +from coreml_suite.conversion.unet import CoreMLUNetWrapper + pytestmark = pytest.mark.skipif( platform.system() != "Darwin" or platform.machine() != "arm64", @@ -32,7 +35,7 @@ pytestmark = pytest.mark.skipif( # coremltools, small enough that conversion finishes in seconds on CPU. SAMPLE_SHAPE = (1, 4, 8, 8) TIMESTEP_SHAPE = (1,) -ENCODER_SHAPE = (1, 64, 1, 4) # matches SD's transposed encoder_hidden_states layout +ENCODER_SHAPE = (1, 4, 64) # native diffusers encoder_hidden_states (batch, tokens, hidden) OUT_NAME = "noise_pred" @@ -41,7 +44,7 @@ class TinyUNet(nn.Module): Not a real diffusion model. Just enough op variety to exercise the PyTorch -> MIL frontend in coremltools and confirm we can still wire - the inputs/outputs the way ml-stable-diffusion expects. + the inputs/outputs the way CoreMLSuite's runtime expects. """ def __init__(self): @@ -51,12 +54,22 @@ class TinyUNet(nn.Module): self.time_proj = nn.Linear(1, 8) self.text_proj = nn.Linear(64, 8) - def forward(self, sample, timestep, encoder_hidden_states): + def forward( + self, + sample, + timestep, + encoder_hidden_states, + timestep_cond=None, + added_cond_kwargs=None, + down_block_additional_residuals=None, + mid_block_additional_residual=None, + return_dict=True, + ): h = self.conv_in(sample) t_emb = self.time_proj(timestep.unsqueeze(-1)).view(1, 8, 1, 1) - c_emb = self.text_proj(encoder_hidden_states.squeeze(2).mean(-1)).view(1, 8, 1, 1) + c_emb = self.text_proj(encoder_hidden_states.mean(1)).view(1, 8, 1, 1) h = h + t_emb + c_emb - return self.conv_out(h) + return (self.conv_out(h),) @pytest.fixture(scope="module") @@ -65,7 +78,10 @@ def tiny_mlpackage(tmp_path_factory): import coremltools as ct torch.manual_seed(0) - model = TinyUNet().eval() + model = CoreMLUNetWrapper( + TinyUNet().eval(), + SimpleNamespace(name="SD15"), + ) example = ( torch.randn(*SAMPLE_SHAPE), torch.randn(*TIMESTEP_SHAPE), @@ -95,9 +111,9 @@ def tiny_mlpackage(tmp_path_factory): def test_coremltools_convert_round_trips_via_coreml_model(tiny_mlpackage): - from python_coreml_stable_diffusion.coreml_model import CoreMLModel + from coreml_suite.coreml_model import CoreMLModel - model = CoreMLModel(str(tiny_mlpackage), "CPU_ONLY", "packages") + model = CoreMLModel(str(tiny_mlpackage), "CPU_ONLY") # expected_inputs is the contract our wrappers depend on. Lock the shape # of the dict + a sample entry. diff --git a/tests/unit/test_characterization_controlnet.py b/tests/unit/test_characterization_controlnet.py index dfdcecb..7144312 100644 --- a/tests/unit/test_characterization_controlnet.py +++ b/tests/unit/test_characterization_controlnet.py @@ -30,7 +30,7 @@ SD15_RESIDUAL_SPEC = { } NON_RESIDUAL_SPEC = { "sample": {"shape": (2, 4, 64, 64)}, - "encoder_hidden_states": {"shape": (2, 768, 1, 77)}, + "encoder_hidden_states": {"shape": (2, 77, 768)}, } diff --git a/tests/unit/test_characterization_inputs.py b/tests/unit/test_characterization_inputs.py index 2f47b5f..fed1e6c 100644 --- a/tests/unit/test_characterization_inputs.py +++ b/tests/unit/test_characterization_inputs.py @@ -25,7 +25,7 @@ def _deterministic_seed(): SD15_EXPECTED = { "sample": {"shape": (2, 4, 64, 64)}, "timestep": {"shape": (2,)}, - "encoder_hidden_states": {"shape": (2, 768, 1, 77)}, + "encoder_hidden_states": {"shape": (2, 77, 768)}, } SD15_WITH_CN = { @@ -42,7 +42,7 @@ LCM_EXPECTED = { SDXL_BASE_EXPECTED = { "sample": {"shape": (2, 4, 128, 128)}, "timestep": {"shape": (2,)}, - "encoder_hidden_states": {"shape": (2, 2048, 1, 77)}, + "encoder_hidden_states": {"shape": (2, 77, 2048)}, "time_ids": {"shape": (2, 6)}, "text_embeds": {"shape": (2, 1280)}, } @@ -50,7 +50,7 @@ SDXL_BASE_EXPECTED = { SDXL_REFINER_EXPECTED = { "sample": {"shape": (2, 4, 128, 128)}, "timestep": {"shape": (2,)}, - "encoder_hidden_states": {"shape": (2, 1280, 1, 77)}, + "encoder_hidden_states": {"shape": (2, 77, 1280)}, "time_ids": {"shape": (2, 5)}, "text_embeds": {"shape": (2, 1280)}, } @@ -93,8 +93,8 @@ def test_coreml_kwargs_sd15_shapes_and_fp16(): assert set(out.keys()) == {"sample", "encoder_hidden_states", "timestep"} assert out["sample"].shape == (1, 4, 64, 64) assert out["sample"].dtype == np.float16 - # encoder_hidden_states is transposed (b, seq, dim) -> (b, dim, 1, seq). - assert out["encoder_hidden_states"].shape == (1, 768, 1, 77) + # encoder_hidden_states keeps Comfy's native (b, seq, dim) layout. + assert out["encoder_hidden_states"].shape == (1, 77, 768) assert out["encoder_hidden_states"].dtype == np.float16 assert out["timestep"].shape == (1,) assert out["timestep"].dtype == np.float16 diff --git a/tests/unit/test_characterization_sdxl_options.py b/tests/unit/test_characterization_sdxl_options.py index 85cbd1b..347e79d 100644 --- a/tests/unit/test_characterization_sdxl_options.py +++ b/tests/unit/test_characterization_sdxl_options.py @@ -2,8 +2,8 @@ The SDXL time_ids / text_embeds math lives in coreml_suite.core.sdxl as pure builders. The framework adapter -add_sdxl_model_options (in models.py) is exercised separately by the m2 -golden image test; here we just lock the pure math. +add_sdxl_model_options lives in models.py; here we just lock the pure +math. """ import inspect diff --git a/tests/unit/test_chunks.py b/tests/unit/test_chunks.py index f1f1dd7..ad1f258 100644 --- a/tests/unit/test_chunks.py +++ b/tests/unit/test_chunks.py @@ -20,7 +20,7 @@ def expected_inputs(): "sample": {"shape": (2, 4, 64, 64)}, "timestep": {"shape": (2,)}, "timestep_cond": {"shape": (2, 256)}, - "encoder_hidden_states": {"shape": (2, 768, 1, 77)}, + "encoder_hidden_states": {"shape": (2, 77, 768)}, "additional_residual_0": {"shape": (2, 320, 64, 64)}, "additional_residual_1": {"shape": (2, 640, 32, 32)}, } diff --git a/tests/unit/test_conversion_helpers.py b/tests/unit/test_conversion_helpers.py new file mode 100644 index 0000000..0b3c53d --- /dev/null +++ b/tests/unit/test_conversion_helpers.py @@ -0,0 +1,183 @@ +from types import SimpleNamespace + +import torch + +from coreml_suite.conversion.attention import ( + SplitEinsumAttnProcessor, + SplitEinsumV2AttnProcessor, + apply_attention_implementation, + split_einsum, + split_einsum_v2, +) +from coreml_suite.conversion.shapes import conv2d_output_shape +from coreml_suite.conversion.unet import CoreMLUNetWrapper + + +class RecordingUNet(torch.nn.Module): + def __init__(self): + super().__init__() + self.call = None + + def forward( + self, + sample, + timestep, + encoder_hidden_states, + timestep_cond=None, + added_cond_kwargs=None, + down_block_additional_residuals=None, + mid_block_additional_residual=None, + return_dict=True, + **kwargs, + ): + self.call = { + "sample": sample, + "timestep": timestep, + "encoder_hidden_states": encoder_hidden_states, + "timestep_cond": timestep_cond, + "added_cond_kwargs": added_cond_kwargs, + "down_block_additional_residuals": down_block_additional_residuals, + "mid_block_additional_residual": mid_block_additional_residual, + "return_dict": return_dict, + } + return (sample + 1,) + + +def test_conv2d_output_shape_matches_torch_conv2d_contract(): + conv = torch.nn.Conv2d( + 4, + 8, + kernel_size=(3, 5), + stride=(2, 3), + padding=(1, 2), + dilation=(1, 2), + ) + + assert conv2d_output_shape(17, 19, conv) == (9, 5) + + +def test_unet_wrapper_passes_context_through_for_sd15(): + unet = RecordingUNet() + wrapper = CoreMLUNetWrapper(unet, SimpleNamespace(name="SD15")) + + sample = torch.randn(2, 4, 8, 8) + timestep = torch.randn(2) + context = torch.randn(2, 77, 768) + + out = wrapper(sample, timestep, context) + + assert torch.equal(out, sample + 1) + assert unet.call["encoder_hidden_states"] is context + assert unet.call["return_dict"] is False + + +def test_unet_wrapper_routes_lcm_sdxl_and_controlnet_inputs(): + unet = RecordingUNet() + wrapper = CoreMLUNetWrapper(unet, SimpleNamespace(name="LCM")) + + sample = torch.randn(1, 4, 8, 8) + timestep = torch.randn(1) + context = torch.randn(1, 77, 768) + timestep_cond = torch.randn(1, 256) + down_residual = torch.randn(1, 320, 8, 8) + mid_residual = torch.randn(1, 1280, 1, 1) + + wrapper(sample, timestep, context, timestep_cond, down_residual, mid_residual) + + assert unet.call["timestep_cond"] is timestep_cond + assert len(unet.call["down_block_additional_residuals"]) == 1 + assert unet.call["down_block_additional_residuals"][0] is down_residual + assert unet.call["mid_block_additional_residual"] is mid_residual + + +def test_unet_wrapper_routes_sdxl_added_conditioning(): + unet = RecordingUNet() + wrapper = CoreMLUNetWrapper(unet, SimpleNamespace(name="SDXL")) + + sample = torch.randn(1, 4, 8, 8) + timestep = torch.randn(1) + context = torch.randn(1, 77, 2048) + time_ids = torch.randn(1, 6) + text_embeds = torch.randn(1, 1280) + + wrapper(sample, timestep, context, time_ids, text_embeds) + + assert unet.call["added_cond_kwargs"]["time_ids"] is time_ids + assert unet.call["added_cond_kwargs"]["text_embeds"] is text_embeds + + +def test_split_einsum_matches_original_attention_math(): + torch.manual_seed(0) + batch = 2 + heads = 3 + dim_head = 4 + sequence = 16 + channels = heads * dim_head + q = torch.randn(batch, channels, 1, sequence) + k = torch.randn(batch, channels, 1, sequence) + v = torch.randn(batch, channels, 1, sequence) + + expected = _original_attention(q, k, v, None, heads, dim_head) + + # split-einsum reorders the float32 reductions vs the reference, so equality + # only holds up to rounding; the drift exceeds allclose's default atol on + # some BLAS backends (e.g. Linux x86 CI). + assert torch.allclose(split_einsum(q, k, v, None, heads, dim_head), expected, atol=1e-6) + assert torch.allclose(split_einsum_v2(q, k, v, None, heads, dim_head), expected, atol=1e-6) + + +def test_split_einsum_v2_chunked_path_matches_original_attention_math(): + torch.manual_seed(0) + batch = 1 + heads = 2 + dim_head = 2 + sequence = 512 + channels = heads * dim_head + q = torch.randn(batch, channels, 1, sequence) + k = torch.randn(batch, channels, 1, sequence) + v = torch.randn(batch, channels, 1, sequence) + + expected = _original_attention(q, k, v, None, heads, dim_head) + + assert torch.allclose( + split_einsum_v2(q, k, v, None, heads, dim_head), + expected, + atol=1e-6, + ) + + +def test_apply_attention_implementation_sets_split_processors(): + unet = RecordingProcessorUNet() + + assert apply_attention_implementation(unet, "ORIGINAL") is unet + assert unet.processor is None + + apply_attention_implementation(unet, "SPLIT_EINSUM") + assert isinstance(unet.processor, SplitEinsumAttnProcessor) + + apply_attention_implementation(unet, "SPLIT_EINSUM_V2") + assert isinstance(unet.processor, SplitEinsumV2AttnProcessor) + + +class RecordingProcessorUNet: + def __init__(self): + self.processor = None + + def set_attn_processor(self, processor): + self.processor = processor + + +def _original_attention(q, k, v, mask, heads, dim_head): + batch = q.size(0) + mh_q = q.view(batch, heads, dim_head, -1) + mh_k = k.view(batch, heads, dim_head, -1) + mh_v = v.view(batch, heads, dim_head, -1) + + weights = torch.einsum("bhcq,bhck->bhqk", mh_q, mh_k) + weights = weights * (dim_head**-0.5) + if mask is not None: + weights = weights + mask + weights = weights.softmax(dim=3) + + attn = torch.einsum("bhqk,bhck->bhcq", weights, mh_v) + return attn.contiguous().view(batch, heads * dim_head, 1, -1) diff --git a/tests/unit/test_tier0_purity.py b/tests/unit/test_tier0_purity.py index cff52f5..ba22b23 100644 --- a/tests/unit/test_tier0_purity.py +++ b/tests/unit/test_tier0_purity.py @@ -7,10 +7,10 @@ after collection. If they are, a tests/unit/ file is transitively pulling them in and the Tier-0 promise — "runs on Linux with no Mac stack" — is broken. -When other tiers (m2 / integration) are also collected, comfy is -expected in sys.modules (integration imports it deliberately), so the -check is skipped in mixed runs — Tier-0 purity is only meaningful when -nothing else is loaded. +When other tiers are also collected, framework modules may be imported +deliberately (e.g. smoke pulls in coremltools), so the check is skipped +unless the run is purely `-m unit` — Tier-0 purity is only meaningful +when nothing else is loaded. """ import sys diff --git a/uv.lock b/uv.lock index 87780c6..92200a9 100644 --- a/uv.lock +++ b/uv.lock @@ -2,14 +2,6 @@ version = 1 revision = 3 requires-python = "==3.12.*" -[manifest] -overrides = [ - { name = "diffusers", specifier = ">=0.30" }, - { name = "huggingface-hub", specifier = ">=0.24" }, - { name = "numpy", specifier = ">=1.24,<2" }, - { name = "transformers", specifier = ">=4.44" }, -] - [[package]] name = "accelerate" version = "1.13.0" @@ -85,12 +77,12 @@ wheels = [ ] [[package]] -name = "annotated-types" -version = "0.7.0" +name = "annotated-doc" +version = "0.0.4" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", size = 16081, upload-time = "2024-05-20T21:33:25.928Z" } +sdist = { url = "https://files.pythonhosted.org/packages/57/ba/046ceea27344560984e26a590f90bc7f4a75b06701f653222458922b558c/annotated_doc-0.0.4.tar.gz", hash = "sha256:fbcda96e87e9c92ad167c2e53839e57503ecfda18804ea28102353485033faa4", size = 7288, upload-time = "2025-11-10T22:07:42.062Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643, upload-time = "2024-05-20T21:33:24.1Z" }, + { url = "https://files.pythonhosted.org/packages/1e/d3/26bf1008eb3d2daa8ef4cacc7f3bfdc11818d111f7e2d0201bc6e3b49d45/annotated_doc-0.0.4-py3-none-any.whl", hash = "sha256:571ac1dc6991c450b25a9c2d84a3705e2ae7a53467b5d111c24fa8baabbed320", size = 5303, upload-time = "2025-11-10T22:07:40.673Z" }, ] [[package]] @@ -100,20 +92,17 @@ source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/3e/38/7859ff46355f76f8d19459005ca000b6e7012f2f1ca597746cbcd1fbfe5e/antlr4-python3-runtime-4.9.3.tar.gz", hash = "sha256:f224469b4168294902bb1efa80a8bf7855f24c99aef99cbefc1bcd3cce77881b", size = 117034, upload-time = "2021-11-06T17:52:23.524Z" } [[package]] -name = "argmaxtools" -version = "0.1.23" +name = "anyio" +version = "4.13.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "beartype" }, - { name = "coremltools" }, - { name = "huggingface-hub" }, - { name = "jaxtyping" }, - { name = "scikit-learn" }, - { name = "tabulate" }, - { name = "torch" }, - { name = "wandb" }, + { name = "idna" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/19/14/2c5dd9f512b66549ae92767a9c7b330ae88e1932ca57876909410251fe13/anyio-4.13.0.tar.gz", hash = "sha256:334b70e641fd2221c1505b3890c69882fe4a2df910cba14d97019b90b24439dc", size = 231622, upload-time = "2026-03-24T12:59:09.671Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/da/42/e921fccf5015463e32a3cf6ee7f980a6ed0f395ceeaa45060b61d86486c2/anyio-4.13.0-py3-none-any.whl", hash = "sha256:08b310f9e24a9594186fd75b4f73f4a4152069e3853f1ed8bfbf58369f4ad708", size = 114353, upload-time = "2026-03-24T12:59:08.246Z" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/21/23/b7a21bd4c6c124b2e42d6c25bdd66c1ad0656d0ed9e86caf9387e8353cae/argmaxtools-0.1.23.tar.gz", hash = "sha256:2f275f490bb18d56f8340f0e0bfcb527ac208a5fbdaa20e1a2003960e8ec2499", size = 43365, upload-time = "2025-07-08T00:43:22.404Z" } [[package]] name = "attrs" @@ -124,15 +113,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl", hash = "sha256:c647aa4a12dfbad9333ca4e71fe62ddc36f4e63b2d260a37a8b83d2f043ac309", size = 67548, upload-time = "2026-03-19T14:22:23.645Z" }, ] -[[package]] -name = "beartype" -version = "0.22.9" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/c7/94/1009e248bbfbab11397abca7193bea6626806be9a327d399810d523a07cb/beartype-0.22.9.tar.gz", hash = "sha256:8f82b54aa723a2848a56008d18875f91c1db02c32ef6a62319a002e3e25a975f", size = 1608866, upload-time = "2025-12-13T06:50:30.72Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/71/cc/18245721fa7747065ab478316c7fea7c74777d07f37ae60db2e84f8172e8/beartype-0.22.9-py3-none-any.whl", hash = "sha256:d16c9bbc61ea14637596c5f6fbff2ee99cbe3573e46a716401734ef50c3060c2", size = 1333658, upload-time = "2025-12-13T06:50:28.266Z" }, -] - [[package]] name = "cattrs" version = "26.1.0" @@ -226,17 +206,16 @@ wheels = [ [[package]] name = "comfyui-coremlsuite" -version = "1.0.1" +version = "2.0.0" source = { virtual = "." } dependencies = [ { name = "coremltools" }, { name = "diffusers" }, { name = "numpy" }, { name = "omegaconf" }, - { name = "overrides" }, { name = "peft" }, - { name = "python-coreml-stable-diffusion" }, { name = "torch" }, + { name = "transformers" }, ] [package.dev-dependencies] @@ -258,18 +237,18 @@ comfy = [ dev = [ { name = "pillow" }, { name = "psutil" }, + { name = "pytest" }, ] [package.metadata] requires-dist = [ { name = "coremltools", specifier = ">=9,<10" }, - { name = "diffusers", specifier = ">=0.22" }, - { name = "numpy", specifier = ">=1.24,<2" }, + { name = "diffusers", specifier = ">=0.30" }, + { name = "numpy", specifier = ">=2,<3" }, { name = "omegaconf", specifier = ">=2.3" }, - { name = "overrides" }, - { name = "peft", specifier = ">=0.6.2" }, - { name = "python-coreml-stable-diffusion", git = "https://github.com/apple/ml-stable-diffusion.git?rev=e5d960c41a6a4ab200b8db379194127607b1c590" }, + { name = "peft", specifier = ">=0.13" }, { name = "torch", specifier = ">=2.7,<2.8" }, + { name = "transformers", specifier = ">=4.44" }, ] [package.metadata.requires-dev] @@ -291,6 +270,7 @@ comfy = [ dev = [ { name = "pillow", specifier = ">=12.2.0" }, { name = "psutil", specifier = ">=7.2.2" }, + { name = "pytest", specifier = ">=9.0.3" }, ] [[package]] @@ -302,27 +282,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/00/25/26c0d75006470d32bfc9eb39ac61a22600bfa509d672405ff3fe1561e2a8/comfyui_frontend_package-1.14.6-py3-none-any.whl", hash = "sha256:1044e30ff3c025dfb63f4c68ecd808a77050c3a5cc3c1f3e6421ea39800bbf40", size = 34873501, upload-time = "2025-03-27T15:50:30.726Z" }, ] -[[package]] -name = "contourpy" -version = "1.3.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "numpy" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/66/54/eb9bfc647b19f2009dd5c7f5ec51c4e6ca831725f1aea7a993034f483147/contourpy-1.3.2.tar.gz", hash = "sha256:b6945942715a034c671b7fc54f9588126b0b8bf23db2696e3ca8328f3ff0ab54", size = 13466130, upload-time = "2025-04-15T17:47:53.79Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/34/f7/44785876384eff370c251d58fd65f6ad7f39adce4a093c934d4a67a7c6b6/contourpy-1.3.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4caf2bcd2969402bf77edc4cb6034c7dd7c0803213b3523f111eb7460a51b8d2", size = 271580, upload-time = "2025-04-15T17:37:03.105Z" }, - { url = "https://files.pythonhosted.org/packages/93/3b/0004767622a9826ea3d95f0e9d98cd8729015768075d61f9fea8eeca42a8/contourpy-1.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:82199cb78276249796419fe36b7386bd8d2cc3f28b3bc19fe2454fe2e26c4c15", size = 255530, upload-time = "2025-04-15T17:37:07.026Z" }, - { url = "https://files.pythonhosted.org/packages/e7/bb/7bd49e1f4fa805772d9fd130e0d375554ebc771ed7172f48dfcd4ca61549/contourpy-1.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:106fab697af11456fcba3e352ad50effe493a90f893fca6c2ca5c033820cea92", size = 307688, upload-time = "2025-04-15T17:37:11.481Z" }, - { url = "https://files.pythonhosted.org/packages/fc/97/e1d5dbbfa170725ef78357a9a0edc996b09ae4af170927ba8ce977e60a5f/contourpy-1.3.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d14f12932a8d620e307f715857107b1d1845cc44fdb5da2bc8e850f5ceba9f87", size = 347331, upload-time = "2025-04-15T17:37:18.212Z" }, - { url = "https://files.pythonhosted.org/packages/6f/66/e69e6e904f5ecf6901be3dd16e7e54d41b6ec6ae3405a535286d4418ffb4/contourpy-1.3.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:532fd26e715560721bb0d5fc7610fce279b3699b018600ab999d1be895b09415", size = 318963, upload-time = "2025-04-15T17:37:22.76Z" }, - { url = "https://files.pythonhosted.org/packages/a8/32/b8a1c8965e4f72482ff2d1ac2cd670ce0b542f203c8e1d34e7c3e6925da7/contourpy-1.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f26b383144cf2d2c29f01a1e8170f50dacf0eac02d64139dcd709a8ac4eb3cfe", size = 323681, upload-time = "2025-04-15T17:37:33.001Z" }, - { url = "https://files.pythonhosted.org/packages/30/c6/12a7e6811d08757c7162a541ca4c5c6a34c0f4e98ef2b338791093518e40/contourpy-1.3.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:c49f73e61f1f774650a55d221803b101d966ca0c5a2d6d5e4320ec3997489441", size = 1308674, upload-time = "2025-04-15T17:37:48.64Z" }, - { url = "https://files.pythonhosted.org/packages/2a/8a/bebe5a3f68b484d3a2b8ffaf84704b3e343ef1addea528132ef148e22b3b/contourpy-1.3.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3d80b2c0300583228ac98d0a927a1ba6a2ba6b8a742463c564f1d419ee5b211e", size = 1380480, upload-time = "2025-04-15T17:38:06.7Z" }, - { url = "https://files.pythonhosted.org/packages/34/db/fcd325f19b5978fb509a7d55e06d99f5f856294c1991097534360b307cf1/contourpy-1.3.2-cp312-cp312-win32.whl", hash = "sha256:90df94c89a91b7362e1142cbee7568f86514412ab8a2c0d0fca72d7e91b62912", size = 178489, upload-time = "2025-04-15T17:38:10.338Z" }, - { url = "https://files.pythonhosted.org/packages/01/c8/fadd0b92ffa7b5eb5949bf340a63a4a496a6930a6c37a7ba0f12acb076d6/contourpy-1.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:8c942a01d9163e2e5cfb05cb66110121b8d07ad438a17f9e766317bcb62abf73", size = 223042, upload-time = "2025-04-15T17:38:14.239Z" }, -] - [[package]] name = "coremltools" version = "9.0" @@ -344,21 +303,13 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/b5/87/add15e7b4537765bef9cb47ffbd6a5d48493e65181df9864afeffa13b99b/coremltools-9.0-cp312-none-manylinux1_x86_64.whl", hash = "sha256:99a101085a7919de9f1c18e514c17d2b3e6a06ad4f7a35aae9515ad47f5a843f", size = 2308591, upload-time = "2025-11-10T21:48:47.269Z" }, ] -[[package]] -name = "cycler" -version = "0.12.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a9/95/a3dbbb5028f35eafb79008e7522a75244477d2838f38cbb722248dabc2a8/cycler-0.12.1.tar.gz", hash = "sha256:88bb128f02ba341da8ef447245a9e138fae777f6a23943da4540077d3601eb1c", size = 7615, upload-time = "2023-10-07T05:32:18.335Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e7/05/c19819d5e3d95294a6f5947fb9b9629efb316b96de511b418c53d245aae6/cycler-0.12.1-py3-none-any.whl", hash = "sha256:85cef7cff222d8644161529808465972e51340599459b8ac3ccbac5a854e0d30", size = 8321, upload-time = "2023-10-07T05:32:16.783Z" }, -] - [[package]] name = "diffusers" -version = "0.30.2" +version = "0.37.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "filelock" }, + { name = "httpx" }, { name = "huggingface-hub" }, { name = "importlib-metadata" }, { name = "numpy" }, @@ -367,28 +318,9 @@ dependencies = [ { name = "requests" }, { name = "safetensors" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/04/ee/13a6327f04f21420ab4d8ada635aba7d884bf57b09f9b847b9af3818b348/diffusers-0.30.2.tar.gz", hash = "sha256:641875f78f36bdfa4b9af752b124d1fd6d431eadd5547fe0a3f354ae0af2636c", size = 2095560, upload-time = "2024-08-31T00:05:36.947Z" } +sdist = { url = "https://files.pythonhosted.org/packages/46/5c/f4c2eb8d481fe8784a7e2331fbaab820079c06676185fa6d2177b386d590/diffusers-0.37.1.tar.gz", hash = "sha256:2346c21f77f835f273b7aacbaada1c34a596a3a2cc6ddc99d149efcd0ec298fa", size = 4135139, upload-time = "2026-03-25T08:04:04.515Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/2f/ee/f67b0888229be96a276257579a58eb2331733d246fdb8620e09ca7253971/diffusers-0.30.2-py3-none-any.whl", hash = "sha256:739826043147c2b59560944591dfdea5d24cd4fb15e751abbe20679a289bece8", size = 2636928, upload-time = "2024-08-31T00:05:34.542Z" }, -] - -[[package]] -name = "diffusionkit" -version = "0.4.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "argmaxtools" }, - { name = "jaxtyping" }, - { name = "mlx" }, - { name = "pillow" }, - { name = "safetensors" }, - { name = "sentencepiece" }, - { name = "torch" }, - { name = "transformers" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/5c/7c/107e46c576ea639646a4370f6ad806d88dad9edeb2d0bb1c4abba55b8858/diffusionkit-0.4.0.tar.gz", hash = "sha256:d13721321e91258e5b6355366d0b2d7042ee4f8a9163c6e3eac492e250c19706", size = 45115, upload-time = "2024-09-09T23:52:38.971Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/7b/1f/d972cd232a2346b03a2bf380d99ade51271ea97bf491efa414799a3b682f/diffusionkit-0.4.0-py3-none-any.whl", hash = "sha256:1e977165a6f638a7c587f95253b13f3f804ab7838a40b03a3876ed45cf64162d", size = 52994, upload-time = "2024-09-09T23:52:37.875Z" }, + { url = "https://files.pythonhosted.org/packages/9c/dd/51c38785ce5e1c287b5ad17ba550edaaaffce0deb0da4857019c6700fbaf/diffusers-0.37.1-py3-none-any.whl", hash = "sha256:0537c0b28cb53cf39d6195489bcf8f833986df556c10f5e28ab7427b86fc8b90", size = 5001536, upload-time = "2026-03-25T08:04:02.385Z" }, ] [[package]] @@ -409,23 +341,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/81/47/dd9a212ef6e343a6857485ffe25bba537304f1913bdbed446a23f7f592e1/filelock-3.29.0-py3-none-any.whl", hash = "sha256:96f5f6344709aa1572bbf631c640e4ebeeb519e08da902c39a001882f30ac258", size = 39812, upload-time = "2026-04-19T15:39:08.752Z" }, ] -[[package]] -name = "fonttools" -version = "4.63.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/84/69/c97f2c18e0db87d2c7b15da1974dace76ae938f1cfa22e2727a648b7ed43/fonttools-4.63.0.tar.gz", hash = "sha256:caeb583deeb5168e694b65cda8b4ee62abedfa66cf88488734466f2366b9c4e0", size = 3597189, upload-time = "2026-05-14T12:04:30.958Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/08/ef/b3c6b9b5be2f82416d73fe2ed2e96e2793cd80e7510bd6a17ca79cdd88ec/fonttools-4.63.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:37dd23e621e3b0aef1baa70a303b80aaf38449632cfc8fd2a55fb285bbccfc02", size = 2881131, upload-time = "2026-05-14T12:03:13.386Z" }, - { url = "https://files.pythonhosted.org/packages/44/a0/c815bea63117fa63e4e1c01f8a1110d2112fa003f838e6467094ec2432ce/fonttools-4.63.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:a9faff9e0c1f76f9fd55899d2ce785832efebab37eb8ae13995853aef178bef0", size = 2426704, upload-time = "2026-05-14T12:03:15.801Z" }, - { url = "https://files.pythonhosted.org/packages/44/04/0b91d8e916e92ad1fac9e4624760baf0fd5ff2ead614c2f68fb21373f03f/fonttools-4.63.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ef3048ef05dbb552b89817713d9cac912e00d0fde4a3105c00d29e52e10c89af", size = 5044298, upload-time = "2026-05-14T12:03:18.085Z" }, - { url = "https://files.pythonhosted.org/packages/77/c7/2342da9830e3e9d4870305ca5d2091d2a83284f2953079b7bdd3b5e029d8/fonttools-4.63.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:58dc6bb86a78d782f00f9190ca02c119cf5bbe2807536e361e18d42019f877d8", size = 4999800, upload-time = "2026-05-14T12:03:20.161Z" }, - { url = "https://files.pythonhosted.org/packages/e6/6d/67fe16c48d7ce050979b33f47e0d28a318f02da030602e944c34f7a16ef3/fonttools-4.63.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ee08ebfa58f6e1aeff5697ab9582105bb620008c1caafb681e4c557e7483027b", size = 4982666, upload-time = "2026-05-14T12:03:22.87Z" }, - { url = "https://files.pythonhosted.org/packages/f2/00/3bbab338c07c71fa56269953845e92c951a61457bbbb0f1022551ea266d9/fonttools-4.63.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:27fdc65af8da6f88b9c6121c47a464cbe359fcfff7ff6fc2d37a1f395d755b78", size = 5133598, upload-time = "2026-05-14T12:03:25.168Z" }, - { url = "https://files.pythonhosted.org/packages/62/f2/aa27c7f98db5b064883dadcc5283947e81e034de42e22a33675878d98b54/fonttools-4.63.0-cp312-cp312-win32.whl", hash = "sha256:af2fd1664d00a397d75f806985ddb36282091c2131a73a6485c23b4a34722263", size = 2292575, upload-time = "2026-05-14T12:03:27.496Z" }, - { url = "https://files.pythonhosted.org/packages/87/36/cccb9bc2a6ab63d1b2980374f0dca72ce95ae267c9b4cfe77455bb70d0d4/fonttools-4.63.0-cp312-cp312-win_amd64.whl", hash = "sha256:59ac449f8cca9b4ffa08d2e7bbadad87ce710d69d1eda5c3c1ce579baa987272", size = 2343211, upload-time = "2026-05-14T12:03:30.057Z" }, - { url = "https://files.pythonhosted.org/packages/2c/47/c99d5268f354002ce80f8d029cd9d7d872969da1de8b93d32de4dc56d6f4/fonttools-4.63.0-py3-none-any.whl", hash = "sha256:445af2eab030a16b9171ea8bdda7ebf7d96bda2df88ee182a464252f6e05e20d", size = 1164562, upload-time = "2026-05-14T12:04:29.092Z" }, -] - [[package]] name = "frozenlist" version = "1.8.0" @@ -461,45 +376,76 @@ wheels = [ ] [[package]] -name = "gitdb" -version = "4.0.12" +name = "h11" +version = "0.16.0" source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "smmap" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/72/94/63b0fc47eb32792c7ba1fe1b694daec9a63620db1e313033d18140c2320a/gitdb-4.0.12.tar.gz", hash = "sha256:5ef71f855d191a3326fcfbc0d5da835f26b13fbcba60c32c21091c349ffdb571", size = 394684, upload-time = "2025-01-02T07:20:46.413Z" } +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/a0/61/5c78b91c3143ed5c14207f463aecfc8f9dbb5092fb2869baf37c273b2705/gitdb-4.0.12-py3-none-any.whl", hash = "sha256:67073e15955400952c6565cc3e707c554a4eea2e428946f7a4c162fab9bd9bcf", size = 62794, upload-time = "2025-01-02T07:20:43.624Z" }, + { 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 = "gitpython" -version = "3.1.50" +name = "hf-xet" +version = "1.5.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/74/d8/5c06fc76461418326a7decf8367480c35be11a41fd938633929c60a9ec6b/hf_xet-1.5.0.tar.gz", hash = "sha256:e0fb0a34d9f406eed88233e829a67ec016bec5af19e480eac65a233ea289a948", size = 837196, upload-time = "2026-05-06T06:18:15.583Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3d/fb/69ff198a82cae7eb1a69fb84d93b3a3e4816564d76817fe541ddc96874eb/hf_xet-1.5.0-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:dad0dc84e941b8ba3c860659fe1fdc35c049d47cce293f003287757e971a8f56", size = 4030814, upload-time = "2026-05-06T06:17:57.933Z" }, + { url = "https://files.pythonhosted.org/packages/9b/ff/edcc2b40162bef3ff78e14ab637e5f3b89243d6aee72f5949d3bb6a5af83/hf_xet-1.5.0-cp37-abi3-macosx_11_0_arm64.whl", hash = "sha256:fd6e5a9b0fdac4ed03ed45ef79254a655b1aaab514a02202617fbf643f5fdf7a", size = 3798444, upload-time = "2026-05-06T06:17:55.79Z" }, + { url = "https://files.pythonhosted.org/packages/49/4d/103f76b04310e5e57656696cc184690d20c466af0bca3ca88f8c8ea5d4f3/hf_xet-1.5.0-cp37-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3531b1823a0e6d77d80f9ed15ca0e00f0d115094f8ac033d5cae88f4564cc949", size = 4465986, upload-time = "2026-05-06T06:17:44.886Z" }, + { url = "https://files.pythonhosted.org/packages/c4/a2/546f47f464737b3edbab6f8ddb57f2599b93d2cbb66f06abb475ccb48651/hf_xet-1.5.0-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:9a0ee58cd18d5ea799f7ed11290bbccbe56bdd8b1d97ca74b9cc49a3945d7a3b", size = 4259865, upload-time = "2026-05-06T06:17:42.639Z" }, + { url = "https://files.pythonhosted.org/packages/95/7f/1be593c1f28613be2e196473481cd81bfc5910795e30a34e8f744f6cac4f/hf_xet-1.5.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:1e60df5a42e9bed8628b6416af2cba4cba57ae9f02de226a06b020d98e1aab18", size = 4459835, upload-time = "2026-05-06T06:18:08.026Z" }, + { url = "https://files.pythonhosted.org/packages/aa/b2/703569fc881f3284487e68cda7b42179978480da3c438042a6bbbb4a671c/hf_xet-1.5.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:4b35549ce62601b84da4ff9b24d970032ace3d4430f52d91bcbb26c901d6c690", size = 4672414, upload-time = "2026-05-06T06:18:09.864Z" }, + { url = "https://files.pythonhosted.org/packages/af/37/1b6def445c567286b50aa3b33828158e135b1be44938dde59f11382a500c/hf_xet-1.5.0-cp37-abi3-win_amd64.whl", hash = "sha256:2806c7c17b4d23f8d88f7c4814f838c3b6150773fe339c20af23e1cfaf2797e4", size = 3977238, upload-time = "2026-05-06T06:18:23.621Z" }, + { url = "https://files.pythonhosted.org/packages/62/94/3b66b148778ee100dcfd69c2ca22b57b41b44d3063ceec934f209e9184ce/hf_xet-1.5.0-cp37-abi3-win_arm64.whl", hash = "sha256:b6c9df403040248c76d808d3e047d64db2d923bae593eb244c41e425cf6cd7be", size = 3806916, upload-time = "2026-05-06T06:18:21.7Z" }, +] + +[[package]] +name = "httpcore" +version = "1.0.9" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "gitdb" }, + { name = "certifi" }, + { name = "h11" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/33/f6/354ae6491228b5eb40e10d89c4d13c651fe1cf7556e35ebdded50cff57ce/gitpython-3.1.50.tar.gz", hash = "sha256:80da2d12504d52e1f998772dc5baf6e553f8d2fcfe1fcc226c9d9a2ee3372dcc", size = 219798, upload-time = "2026-05-06T04:01:26.571Z" } +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/20/7a/1c6e3562dfd8950adbb11ffbc65d21e7c89d01a6e4f137fa981056de25c5/gitpython-3.1.50-py3-none-any.whl", hash = "sha256:d352abe2908d07355014abdd21ddf798c2a961469239afec4962e9da884858f9", size = 212507, upload-time = "2026-05-06T04:01:23.799Z" }, + { 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.24.6" +version = "1.16.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "filelock" }, { name = "fsspec" }, + { name = "hf-xet", marker = "platform_machine == 'AMD64' or platform_machine == 'aarch64' or platform_machine == 'amd64' or platform_machine == 'arm64' or platform_machine == 'x86_64'" }, + { name = "httpx" }, { name = "packaging" }, { name = "pyyaml" }, - { name = "requests" }, { name = "tqdm" }, + { name = "typer" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/65/24/b98fce967b7d63700e5805b915012ba25bb538a81fcf11e97f3cc3f4f012/huggingface_hub-0.24.6.tar.gz", hash = "sha256:cc2579e761d070713eaa9c323e3debe39d5b464ae3a7261c39a9195b27bb8000", size = 349200, upload-time = "2024-08-19T15:15:03.822Z" } +sdist = { url = "https://files.pythonhosted.org/packages/48/0f/ed994dbade67a54407c28cab96ef845e0e6d25500be56aca6394f8bfc9dd/huggingface_hub-1.16.1.tar.gz", hash = "sha256:7f1dc4c5ec21aed69be630ad0c3378616be16f3de1a47b141c0e812965d9c832", size = 792534, upload-time = "2026-05-21T18:40:00.908Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/b9/8f/d6718641c14d98a5848c6a24d2376028d292074ffade0702940a4b1dde76/huggingface_hub-0.24.6-py3-none-any.whl", hash = "sha256:a990f3232aa985fe749bc9474060cbad75e8b2f115f6665a9fda5b9c97818970", size = 417509, upload-time = "2024-08-19T15:15:01.429Z" }, + { url = "https://files.pythonhosted.org/packages/49/79/621a7dbb80c70974f73a597275351ebe03ce5bc65cb5f8f4acb5859252bc/huggingface_hub-1.16.1-py3-none-any.whl", hash = "sha256:64340de934b9ce37857ef85a82de72f5629e8a270f9119eabb12bf495eb53c22", size = 668176, upload-time = "2026-05-21T18:39:58.596Z" }, ] [[package]] @@ -532,33 +478,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12", size = 7484, upload-time = "2025-10-18T21:55:41.639Z" }, ] -[[package]] -name = "invisible-watermark" -version = "0.2.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "numpy" }, - { name = "opencv-python" }, - { name = "pillow" }, - { name = "pywavelets" }, - { name = "torch" }, -] -wheels = [ - { url = "https://files.pythonhosted.org/packages/2b/57/18b5a914f6d7994dd349252873169e946dc824328e9a37fd15ed836deedc/invisible_watermark-0.2.0-py3-none-any.whl", hash = "sha256:644311beed9cfe4a9a5a4a46c740f47800cef184fe2e1297f3f4542e2d992f8b", size = 1633253, upload-time = "2023-07-06T13:56:28.715Z" }, -] - -[[package]] -name = "jaxtyping" -version = "0.3.9" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "wadler-lindig" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/c2/be/00294e369938937e31b094437d5ea040e4fd1a20b998ebe572c4a1dcfa68/jaxtyping-0.3.9.tar.gz", hash = "sha256:f8c02d1b623d5f1b6665d4f3ddaec675d70004f16a792102c2fc51264190951d", size = 45857, upload-time = "2026-02-16T10:35:13.263Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/94/05/3e39d416fb92b2738a76e8265e6bfc5d10542f90a7c32ad1eb831eea3fa3/jaxtyping-0.3.9-py3-none-any.whl", hash = "sha256:a00557a9d616eff157491f06ed2e21ed94886fad3832399273eb912b345da378", size = 56274, upload-time = "2026-02-16T10:35:11.795Z" }, -] - [[package]] name = "jinja2" version = "3.1.6" @@ -571,42 +490,6 @@ 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 = "kiwisolver" -version = "1.5.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d0/67/9c61eccb13f0bdca9307614e782fec49ffdde0f7a2314935d489fa93cd9c/kiwisolver-1.5.0.tar.gz", hash = "sha256:d4193f3d9dc3f6f79aaed0e5637f45d98850ebf01f7ca20e69457f3e8946b66a", size = 103482, upload-time = "2026-03-09T13:15:53.382Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/4d/b2/818b74ebea34dabe6d0c51cb1c572e046730e64844da6ed646d5298c40ce/kiwisolver-1.5.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:4e9750bc21b886308024f8a54ccb9a2cc38ac9fa813bf4348434e3d54f337ff9", size = 123158, upload-time = "2026-03-09T13:13:23.127Z" }, - { url = "https://files.pythonhosted.org/packages/bf/d9/405320f8077e8e1c5c4bd6adc45e1e6edf6d727b6da7f2e2533cf58bff71/kiwisolver-1.5.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:72ec46b7eba5b395e0a7b63025490d3214c11013f4aacb4f5e8d6c3041829588", size = 66388, upload-time = "2026-03-09T13:13:24.765Z" }, - { url = "https://files.pythonhosted.org/packages/99/9f/795fedf35634f746151ca8839d05681ceb6287fbed6cc1c9bf235f7887c2/kiwisolver-1.5.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ed3a984b31da7481b103f68776f7128a89ef26ed40f4dc41a2223cda7fb24819", size = 64068, upload-time = "2026-03-09T13:13:25.878Z" }, - { url = "https://files.pythonhosted.org/packages/c4/13/680c54afe3e65767bed7ec1a15571e1a2f1257128733851ade24abcefbcc/kiwisolver-1.5.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:bb5136fb5352d3f422df33f0c879a1b0c204004324150cc3b5e3c4f310c9049f", size = 1477934, upload-time = "2026-03-09T13:13:27.166Z" }, - { url = "https://files.pythonhosted.org/packages/c8/2f/cebfcdb60fd6a9b0f6b47a9337198bcbad6fbe15e68189b7011fd914911f/kiwisolver-1.5.0-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b2af221f268f5af85e776a73d62b0845fc8baf8ef0abfae79d29c77d0e776aaf", size = 1278537, upload-time = "2026-03-09T13:13:28.707Z" }, - { url = "https://files.pythonhosted.org/packages/f2/0d/9b782923aada3fafb1d6b84e13121954515c669b18af0c26e7d21f579855/kiwisolver-1.5.0-cp312-cp312-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b0f172dc8ffaccb8522d7c5d899de00133f2f1ca7b0a49b7da98e901de87bf2d", size = 1296685, upload-time = "2026-03-09T13:13:30.528Z" }, - { url = "https://files.pythonhosted.org/packages/27/70/83241b6634b04fe44e892688d5208332bde130f38e610c0418f9ede47ded/kiwisolver-1.5.0-cp312-cp312-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:6ab8ba9152203feec73758dad83af9a0bbe05001eb4639e547207c40cfb52083", size = 1346024, upload-time = "2026-03-09T13:13:32.818Z" }, - { url = "https://files.pythonhosted.org/packages/e4/db/30ed226fb271ae1a6431fc0fe0edffb2efe23cadb01e798caeb9f2ceae8f/kiwisolver-1.5.0-cp312-cp312-manylinux_2_39_riscv64.whl", hash = "sha256:cdee07c4d7f6d72008d3f73b9bf027f4e11550224c7c50d8df1ae4a37c1402a6", size = 987241, upload-time = "2026-03-09T13:13:34.435Z" }, - { url = "https://files.pythonhosted.org/packages/ec/bd/c314595208e4c9587652d50959ead9e461995389664e490f4dce7ff0f782/kiwisolver-1.5.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:7c60d3c9b06fb23bd9c6139281ccbdc384297579ae037f08ae90c69f6845c0b1", size = 2227742, upload-time = "2026-03-09T13:13:36.4Z" }, - { url = "https://files.pythonhosted.org/packages/c1/43/0499cec932d935229b5543d073c2b87c9c22846aab48881e9d8d6e742a2d/kiwisolver-1.5.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:e315e5ec90d88e140f57696ff85b484ff68bb311e36f2c414aa4286293e6dee0", size = 2323966, upload-time = "2026-03-09T13:13:38.204Z" }, - { url = "https://files.pythonhosted.org/packages/3d/6f/79b0d760907965acfd9d61826a3d41f8f093c538f55cd2633d3f0db269f6/kiwisolver-1.5.0-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:1465387ac63576c3e125e5337a6892b9e99e0627d52317f3ca79e6930d889d15", size = 1977417, upload-time = "2026-03-09T13:13:39.966Z" }, - { url = "https://files.pythonhosted.org/packages/ab/31/01d0537c41cb75a551a438c3c7a80d0c60d60b81f694dac83dd436aec0d0/kiwisolver-1.5.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:530a3fd64c87cffa844d4b6b9768774763d9caa299e9b75d8eca6a4423b31314", size = 2491238, upload-time = "2026-03-09T13:13:41.698Z" }, - { url = "https://files.pythonhosted.org/packages/e4/34/8aefdd0be9cfd00a44509251ba864f5caf2991e36772e61c408007e7f417/kiwisolver-1.5.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1d9daea4ea6b9be74fe2f01f7fbade8d6ffab263e781274cffca0dba9be9eec9", size = 2294947, upload-time = "2026-03-09T13:13:43.343Z" }, - { url = "https://files.pythonhosted.org/packages/ad/cf/0348374369ca588f8fe9c338fae49fa4e16eeb10ffb3d012f23a54578a9e/kiwisolver-1.5.0-cp312-cp312-win_amd64.whl", hash = "sha256:f18c2d9782259a6dc132fdc7a63c168cbc74b35284b6d75c673958982a378384", size = 73569, upload-time = "2026-03-09T13:13:45.792Z" }, - { url = "https://files.pythonhosted.org/packages/28/26/192b26196e2316e2bd29deef67e37cdf9870d9af8e085e521afff0fed526/kiwisolver-1.5.0-cp312-cp312-win_arm64.whl", hash = "sha256:f7c7553b13f69c1b29a5bde08ddc6d9d0c8bfb84f9ed01c30db25944aeb852a7", size = 64997, upload-time = "2026-03-09T13:13:46.878Z" }, - { url = "https://files.pythonhosted.org/packages/1c/fa/2910df836372d8761bb6eff7d8bdcb1613b5c2e03f260efe7abe34d388a7/kiwisolver-1.5.0-graalpy312-graalpy250_312_native-macosx_10_13_x86_64.whl", hash = "sha256:5ae8e62c147495b01a0f4765c878e9bfdf843412446a247e28df59936e99e797", size = 130262, upload-time = "2026-03-09T13:15:35.629Z" }, - { url = "https://files.pythonhosted.org/packages/0f/41/c5f71f9f00aabcc71fee8b7475e3f64747282580c2fe748961ba29b18385/kiwisolver-1.5.0-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:f6764a4ccab3078db14a632420930f6186058750df066b8ea2a7106df91d3203", size = 138036, upload-time = "2026-03-09T13:15:36.894Z" }, - { url = "https://files.pythonhosted.org/packages/fa/06/7399a607f434119c6e1fdc8ec89a8d51ccccadf3341dee4ead6bd14caaf5/kiwisolver-1.5.0-graalpy312-graalpy250_312_native-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c31c13da98624f957b0fb1b5bae5383b2333c2c3f6793d9825dd5ce79b525cb7", size = 194295, upload-time = "2026-03-09T13:15:38.22Z" }, - { url = "https://files.pythonhosted.org/packages/b5/91/53255615acd2a1eaca307ede3c90eb550bae9c94581f8c00081b6b1c8f44/kiwisolver-1.5.0-graalpy312-graalpy250_312_native-win_amd64.whl", hash = "sha256:1f1489f769582498610e015a8ef2d36f28f505ab3096d0e16b4858a9ec214f57", size = 75987, upload-time = "2026-03-09T13:15:39.65Z" }, -] - [[package]] name = "kornia" version = "0.8.3" @@ -634,6 +517,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/e0/6f/01e0e2cf90c47ecf26656263cdabe491a1b206c94c0c30a1dd7e4d13ed29/kornia_rs-0.1.14-cp312-cp312-win_amd64.whl", hash = "sha256:ac4bbd0a8fd73b5058a39707c790fecec4c5204a42d1f5af17f1fa57cc83d406", size = 3367565, upload-time = "2026-05-19T07:46:16.682Z" }, ] +[[package]] +name = "markdown-it-py" +version = "4.2.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "mdurl" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/06/ff/7841249c247aa650a76b9ee4bbaeae59370dc8bfd2f6c01f3630c35eb134/markdown_it_py-4.2.0.tar.gz", hash = "sha256:04a21681d6fbb623de53f6f364d352309d4094dd4194040a10fd51833e418d49", size = 82454, upload-time = "2026-05-07T12:08:28.36Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl", hash = "sha256:9f7ebbcd14fe59494226453aed97c1070d83f8d24b6fc3a3bcf9a38092641c4a", size = 91687, upload-time = "2026-05-07T12:08:27.182Z" }, +] + [[package]] name = "markupsafe" version = "3.0.3" @@ -654,54 +549,12 @@ wheels = [ ] [[package]] -name = "matplotlib" -version = "3.10.9" +name = "mdurl" +version = "0.1.2" source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "contourpy" }, - { name = "cycler" }, - { name = "fonttools" }, - { name = "kiwisolver" }, - { name = "numpy" }, - { name = "packaging" }, - { name = "pillow" }, - { name = "pyparsing" }, - { name = "python-dateutil" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/63/1b/4be5be87d43d327a0cf4de1a56e86f7f84c89312452406cf122efe2839e6/matplotlib-3.10.9.tar.gz", hash = "sha256:fd66508e8c6877d98e586654b608a0456db8d7e8a546eb1e2600efd957302358", size = 34811233, upload-time = "2026-04-24T00:14:13.539Z" } +sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729, upload-time = "2022-08-14T12:40:10.846Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/35/c6/5581e26c72233ebb2a2a6fed2d24fb7c66b4700120b813f51b0555acf0b6/matplotlib-3.10.9-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f0c3c28d9fbcc1fe7a03be236d73430cf6409c41fb2383a7ac52fe932b072cb1", size = 8319908, upload-time = "2026-04-24T00:12:21.323Z" }, - { url = "https://files.pythonhosted.org/packages/b7/18/4880dd762e40cd360c1bf06e890c5a97b997e91cb324602b1a19950ad5ce/matplotlib-3.10.9-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:41cb28c2bd769aa3e98322c6ab09854cbcc52ab69d2759d681bba3e327b2b320", size = 8216016, upload-time = "2026-04-24T00:12:23.4Z" }, - { url = "https://files.pythonhosted.org/packages/32/91/d024616abdba99e83120e07a20658976f6a343646710760c4a51df126029/matplotlib-3.10.9-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ae20801130378b82d647ff5047c07316295b68dc054ca6b3c13519d0ea624285", size = 8789336, upload-time = "2026-04-24T00:12:26.096Z" }, - { url = "https://files.pythonhosted.org/packages/5c/04/030a2f61ef2158f5e4c259487a92ac877732499fb33d871585d89e03c42d/matplotlib-3.10.9-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6c63ebcd8b4b169eb2f5c200552ae6b8be8999a005b6b507ed76fb8d7d674fe2", size = 9604602, upload-time = "2026-04-24T00:12:29.052Z" }, - { url = "https://files.pythonhosted.org/packages/fc/c2/541e4d09d87bb6b5830fc28b4c887a9a8cf4e1c6cee698a8c05552ae2003/matplotlib-3.10.9-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:d75d11c949914165976c621b2324f9ef162af7ebf4b057ddf95dd1dba7e5edcf", size = 9670966, upload-time = "2026-04-24T00:12:32.131Z" }, - { url = "https://files.pythonhosted.org/packages/04/a1/4571fc46e7702de8d0c2dc54ad1b2f8e29328dea3ee90831181f7353d93c/matplotlib-3.10.9-cp312-cp312-win_amd64.whl", hash = "sha256:d091f9d758b34aaaaa6331d13574bf01891d903b3dec59bfff458ef7551de5d6", size = 8217462, upload-time = "2026-04-24T00:12:35.226Z" }, - { url = "https://files.pythonhosted.org/packages/4b/d0/2269edb12aa30c13c8bcc9382892e39943ce1d28aab4ec296e0381798e81/matplotlib-3.10.9-cp312-cp312-win_arm64.whl", hash = "sha256:10cc5ce06d10231c36f40e875f3c7e8050362a4ee8f0ee5d29a6b3277d57bb42", size = 8136688, upload-time = "2026-04-24T00:12:37.442Z" }, -] - -[[package]] -name = "mlx" -version = "0.31.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "mlx-metal", marker = "sys_platform == 'darwin'" }, -] -wheels = [ - { url = "https://files.pythonhosted.org/packages/c3/47/5f33906cb03d6a378a697cd2d2641a26b37dea17ee3d9124d7e39e8eca01/mlx-0.31.2-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:e5067aaf2be1f3d7bba5be52348775804f111173c1ed04639618fd713b1a530f", size = 584863, upload-time = "2026-04-22T03:14:38.211Z" }, - { url = "https://files.pythonhosted.org/packages/08/e7/a851a451b1327af9fb4df3991b9ae87d066b6f6630e854af55c288b0995a/mlx-0.31.2-cp312-cp312-macosx_15_0_arm64.whl", hash = "sha256:edb9797db7d852477ca1c99708058654ee860d4148fe5765f0d55528e2b1aa22", size = 584860, upload-time = "2026-04-22T03:14:39.746Z" }, - { url = "https://files.pythonhosted.org/packages/3b/15/0d1dc0597644e5e7b011ca954ba0c47e13cd880a3b909b0c3f1b4d8bf8f1/mlx-0.31.2-cp312-cp312-macosx_26_0_arm64.whl", hash = "sha256:51ca102db641b01e7cb083ce8ecb580e281530a141a7ca12544bb370641630ae", size = 584887, upload-time = "2026-04-22T03:14:41.585Z" }, - { url = "https://files.pythonhosted.org/packages/5d/c3/00664239a98e8bd614733c4182cd402d2bacad2d7f79eca66562ac406870/mlx-0.31.2-cp312-cp312-manylinux_2_35_aarch64.whl", hash = "sha256:117c7583cae0ca107cd53c591cc34f8e75f97a505aa47088844b7dc0fc69dc67", size = 627863, upload-time = "2026-04-22T03:14:43.326Z" }, - { url = "https://files.pythonhosted.org/packages/53/7b/af6cd73a79772af6f19eab2cb4c48eda23a9294d1650a4c1269a9996e532/mlx-0.31.2-cp312-cp312-manylinux_2_35_x86_64.whl", hash = "sha256:99572133181481640a8bf8d449daf083816d0af3ee050c8adfc5bf45ceca91c6", size = 685090, upload-time = "2026-04-22T03:14:45.058Z" }, -] - -[[package]] -name = "mlx-metal" -version = "0.31.2" -source = { registry = "https://pypi.org/simple" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/3f/69/fe3b783ebe999f3118234e1e940feb622518bfb1dea6ac5d13b1d36a8449/mlx_metal-0.31.2-py3-none-macosx_14_0_arm64.whl", hash = "sha256:b25385bcee18fc194092255b8b53b9a3d8489eb650e59160f1b57aadd07aa2dc", size = 40055588, upload-time = "2026-04-22T03:14:14.43Z" }, - { url = "https://files.pythonhosted.org/packages/4f/5d/4c690d5b93c30ba002656c37363159d978705bf8eb801b8481840fb942c2/mlx_metal-0.31.2-py3-none-macosx_15_0_arm64.whl", hash = "sha256:e9d4e5fce6ca10a87a0e388597f99519ad594d09e674708b5312bd8bd4f5997d", size = 40053220, upload-time = "2026-04-22T03:14:18.048Z" }, - { url = "https://files.pythonhosted.org/packages/99/82/11fd62a8d7a3e96e5c43220b17de0151e3f10101f8bb3b865f5bd9cdd074/mlx_metal-0.31.2-py3-none-macosx_26_0_arm64.whl", hash = "sha256:84ffb60ee503f03eb684f5fb168d5cff31e2a16b7f27c1731eaf7662bd6e9b46", size = 55792151, upload-time = "2026-04-22T03:14:22.059Z" }, + { url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979, upload-time = "2022-08-14T12:40:09.779Z" }, ] [[package]] @@ -751,18 +604,21 @@ wheels = [ [[package]] name = "numpy" -version = "1.26.4" +version = "2.4.6" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/65/6e/09db70a523a96d25e115e71cc56a6f9031e7b8cd166c1ac8438307c14058/numpy-1.26.4.tar.gz", hash = "sha256:2a02aba9ed12e4ac4eb3ea9421c420301a0c6460d9830d74a9df87efa4912010", size = 15786129, upload-time = "2024-02-06T00:26:44.495Z" } +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/95/12/8f2020a8e8b8383ac0177dc9570aad031a3beb12e38847f7129bacd96228/numpy-1.26.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:b3ce300f3644fb06443ee2222c2201dd3a89ea6040541412b8fa189341847218", size = 20335901, upload-time = "2024-02-05T23:55:32.801Z" }, - { url = "https://files.pythonhosted.org/packages/75/5b/ca6c8bd14007e5ca171c7c03102d17b4f4e0ceb53957e8c44343a9546dcc/numpy-1.26.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:03a8c78d01d9781b28a6989f6fa1bb2c4f2d51201cf99d3dd875df6fbd96b23b", size = 13685868, upload-time = "2024-02-05T23:55:56.28Z" }, - { url = "https://files.pythonhosted.org/packages/79/f8/97f10e6755e2a7d027ca783f63044d5b1bc1ae7acb12afe6a9b4286eac17/numpy-1.26.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9fad7dcb1aac3c7f0584a5a8133e3a43eeb2fe127f47e3632d43d677c66c102b", size = 13925109, upload-time = "2024-02-05T23:56:20.368Z" }, - { url = "https://files.pythonhosted.org/packages/0f/50/de23fde84e45f5c4fda2488c759b69990fd4512387a8632860f3ac9cd225/numpy-1.26.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:675d61ffbfa78604709862923189bad94014bef562cc35cf61d3a07bba02a7ed", size = 17950613, upload-time = "2024-02-05T23:56:56.054Z" }, - { url = "https://files.pythonhosted.org/packages/4c/0c/9c603826b6465e82591e05ca230dfc13376da512b25ccd0894709b054ed0/numpy-1.26.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:ab47dbe5cc8210f55aa58e4805fe224dac469cde56b9f731a4c098b91917159a", size = 13572172, upload-time = "2024-02-05T23:57:21.56Z" }, - { url = "https://files.pythonhosted.org/packages/76/8c/2ba3902e1a0fc1c74962ea9bb33a534bb05984ad7ff9515bf8d07527cadd/numpy-1.26.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:1dda2e7b4ec9dd512f84935c5f126c8bd8b9f2fc001e9f54af255e8c5f16b0e0", size = 17786643, upload-time = "2024-02-05T23:57:56.585Z" }, - { url = "https://files.pythonhosted.org/packages/28/4a/46d9e65106879492374999e76eb85f87b15328e06bd1550668f79f7b18c6/numpy-1.26.4-cp312-cp312-win32.whl", hash = "sha256:50193e430acfc1346175fcbdaa28ffec49947a06918b7b92130744e81e640110", size = 5677803, upload-time = "2024-02-05T23:58:08.963Z" }, - { url = "https://files.pythonhosted.org/packages/16/2e/86f24451c2d530c88daf997cb8d6ac622c1d40d19f5a031ed68a4b73a374/numpy-1.26.4-cp312-cp312-win_amd64.whl", hash = "sha256:08beddf13648eb95f8d867350f6a018a4be2e5ad54c8d8caed89ebca558b2818", size = 15517754, upload-time = "2024-02-05T23:58:36.364Z" }, + { 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" }, ] [[package]] @@ -911,32 +767,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/e3/94/1843518e420fa3ed6919835845df698c7e27e183cb997394e4a670973a65/omegaconf-2.3.0-py3-none-any.whl", hash = "sha256:7b4df175cdb08ba400f45cae3bdcae7ba8365db4d165fc65fd04b050ab63b46b", size = 79500, upload-time = "2022-12-08T20:59:19.686Z" }, ] -[[package]] -name = "opencv-python" -version = "4.11.0.86" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "numpy" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/17/06/68c27a523103dad5837dc5b87e71285280c4f098c60e4fe8a8db6486ab09/opencv-python-4.11.0.86.tar.gz", hash = "sha256:03d60ccae62304860d232272e4a4fda93c39d595780cb40b161b310244b736a4", size = 95171956, upload-time = "2025-01-16T13:52:24.737Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/05/4d/53b30a2a3ac1f75f65a59eb29cf2ee7207ce64867db47036ad61743d5a23/opencv_python-4.11.0.86-cp37-abi3-macosx_13_0_arm64.whl", hash = "sha256:432f67c223f1dc2824f5e73cdfcd9db0efc8710647d4e813012195dc9122a52a", size = 37326322, upload-time = "2025-01-16T13:52:25.887Z" }, - { url = "https://files.pythonhosted.org/packages/3b/84/0a67490741867eacdfa37bc18df96e08a9d579583b419010d7f3da8ff503/opencv_python-4.11.0.86-cp37-abi3-macosx_13_0_x86_64.whl", hash = "sha256:9d05ef13d23fe97f575153558653e2d6e87103995d54e6a35db3f282fe1f9c66", size = 56723197, upload-time = "2025-01-16T13:55:21.222Z" }, - { url = "https://files.pythonhosted.org/packages/f3/bd/29c126788da65c1fb2b5fb621b7fed0ed5f9122aa22a0868c5e2c15c6d23/opencv_python-4.11.0.86-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1b92ae2c8852208817e6776ba1ea0d6b1e0a1b5431e971a2a0ddd2a8cc398202", size = 42230439, upload-time = "2025-01-16T13:51:35.822Z" }, - { url = "https://files.pythonhosted.org/packages/2c/8b/90eb44a40476fa0e71e05a0283947cfd74a5d36121a11d926ad6f3193cc4/opencv_python-4.11.0.86-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6b02611523803495003bd87362db3e1d2a0454a6a63025dc6658a9830570aa0d", size = 62986597, upload-time = "2025-01-16T13:52:08.836Z" }, - { url = "https://files.pythonhosted.org/packages/fb/d7/1d5941a9dde095468b288d989ff6539dd69cd429dbf1b9e839013d21b6f0/opencv_python-4.11.0.86-cp37-abi3-win32.whl", hash = "sha256:810549cb2a4aedaa84ad9a1c92fbfdfc14090e2749cedf2c1589ad8359aa169b", size = 29384337, upload-time = "2025-01-16T13:52:13.549Z" }, - { url = "https://files.pythonhosted.org/packages/a4/7d/f1c30a92854540bf789e9cd5dde7ef49bbe63f855b85a2e6b3db8135c591/opencv_python-4.11.0.86-cp37-abi3-win_amd64.whl", hash = "sha256:085ad9b77c18853ea66283e98affefe2de8cc4c1f43eda4c100cf9b2721142ec", size = 39488044, upload-time = "2025-01-16T13:52:21.928Z" }, -] - -[[package]] -name = "overrides" -version = "7.7.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/36/86/b585f53236dec60aba864e050778b25045f857e17f6e5ea0ae95fe80edd2/overrides-7.7.0.tar.gz", hash = "sha256:55158fa3d93b98cc75299b1e67078ad9003ca27945c76162c1c0766d6f91820a", size = 22812, upload-time = "2024-01-27T21:01:33.423Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/2c/ab/fc8290c6a4c722e5514d80f62b2dc4c4df1a68a41d1364e625c35990fcf3/overrides-7.7.0-py3-none-any.whl", hash = "sha256:c7ed9d062f78b8e4c1a7b70bd8796b35ead4d9f510227ef9c5dc7626c60d7e49", size = 17832, upload-time = "2024-01-27T21:01:31.393Z" }, -] - [[package]] name = "packaging" version = "26.2" @@ -948,7 +778,7 @@ wheels = [ [[package]] name = "peft" -version = "0.13.2" +version = "0.19.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "accelerate" }, @@ -962,9 +792,9 @@ dependencies = [ { name = "tqdm" }, { name = "transformers" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/97/e1/aab80b861b4c18e85482940d504b3a7ee525bdf6ed93a1a2871881a180f1/peft-0.13.2.tar.gz", hash = "sha256:0e0cbd40ebdf5fe4ea79f255880d02f96712d18899509369a2cc5768ad46d672", size = 350390, upload-time = "2024-10-11T11:42:21.874Z" } +sdist = { url = "https://files.pythonhosted.org/packages/86/cf/037f1e3d5186496c05513a6754639e2dab3038a05f384284d49a9bd06a2d/peft-0.19.1.tar.gz", hash = "sha256:0d97542fe96dcdaa20d3b81c06f26f988618f416a73544ab23c3618ccb674a40", size = 763738, upload-time = "2026-04-16T15:46:45.105Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/78/9d/5f95bfb298c8d3b4e3a107701f9a4e7774a0d4d1f8eb0c9d5420b80f7c9d/peft-0.13.2-py3-none-any.whl", hash = "sha256:d4e0951ec78eac11c45a051801c569913436888c578d48e5ce86996b715bc6ef", size = 320731, upload-time = "2024-10-11T11:42:18.905Z" }, + { url = "https://files.pythonhosted.org/packages/e8/b6/f54d676ed93cc2dd2234c3b172ea9c8c3d7d29361e66b1b23dec57a67465/peft-0.19.1-py3-none-any.whl", hash = "sha256:2113f72a81621b5913ef28f9022204c742df111890c5f49d812716a4a301e356", size = 680692, upload-time = "2026-04-16T15:46:42.886Z" }, ] [[package]] @@ -986,15 +816,6 @@ wheels = [ { 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" }, ] -[[package]] -name = "platformdirs" -version = "4.9.6" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/9f/4a/0883b8e3802965322523f0b200ecf33d31f10991d0401162f4b23c698b42/platformdirs-4.9.6.tar.gz", hash = "sha256:3bfa75b0ad0db84096ae777218481852c0ebc6c727b3168c1b9e0118e458cf0a", size = 29400, upload-time = "2026-04-09T00:04:10.812Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/75/a6/a0a304dc33b49145b21f4808d763822111e67d1c3a32b524a1baf947b6e1/platformdirs-4.9.6-py3-none-any.whl", hash = "sha256:e61adb1d5e5cb3441b4b7710bea7e4c12250ca49439228cc1021c00dcfac0917", size = 21348, upload-time = "2026-04-09T00:04:09.463Z" }, -] - [[package]] name = "pluggy" version = "1.6.0" @@ -1082,51 +903,6 @@ 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 = "pydantic" -version = "2.13.4" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "annotated-types" }, - { name = "pydantic-core" }, - { name = "typing-extensions" }, - { name = "typing-inspection" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/18/a5/b60d21ac674192f8ab0ba4e9fd860690f9b4a6e51ca5df118733b487d8d6/pydantic-2.13.4.tar.gz", hash = "sha256:c40756b57adaa8b1efeeced5c196f3f3b7c435f90e84ea7f443901bec8099ef6", size = 844775, upload-time = "2026-05-06T13:43:05.343Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl", hash = "sha256:45a282cde31d808236fd7ea9d919b128653c8b38b393d1c4ab335c62924d9aba", size = 472262, upload-time = "2026-05-06T13:43:02.641Z" }, -] - -[[package]] -name = "pydantic-core" -version = "2.46.4" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/9d/56/921726b776ace8d8f5db44c4ef961006580d91dc52b803c489fafd1aa249/pydantic_core-2.46.4.tar.gz", hash = "sha256:62f875393d7f270851f20523dd2e29f082bcc82292d66db2b64ea71f64b6e1c1", size = 471464, upload-time = "2026-05-06T13:37:06.98Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ce/8c/af022f0af448d7747c5154288d46b5f2bc5f17366eaa0e23e9aa04d59f3b/pydantic_core-2.46.4-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:3245406455a5d98187ec35530fd772b1d799b26667980872c8d4614991e2c4a2", size = 2106158, upload-time = "2026-05-06T13:38:57.215Z" }, - { url = "https://files.pythonhosted.org/packages/19/95/6195171e385007300f0f5574592e467c568becce2d937a0b6804f218bc49/pydantic_core-2.46.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:962ccbab7b642487b1d8b7df90ef677e03134cf1fd8880bf698649b22a69371f", size = 1951724, upload-time = "2026-05-06T13:37:02.697Z" }, - { url = "https://files.pythonhosted.org/packages/8e/bc/f47d1ff9cbb1620e1b5b697eef06010035735f07820180e74178226b27b3/pydantic_core-2.46.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8233f2947cf85404441fd7e0085f53b10c93e0ee78611099b5c7237e36aacbf7", size = 1975742, upload-time = "2026-05-06T13:37:09.448Z" }, - { url = "https://files.pythonhosted.org/packages/5b/11/9b9a5b0306345664a2da6410877af6e8082481b5884b3ddd78d47c6013ce/pydantic_core-2.46.4-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3a233125ac121aa3ffba9a2b59edfc4a985a76092dc8279586ab4b71390875e7", size = 2052418, upload-time = "2026-05-06T13:37:38.234Z" }, - { url = "https://files.pythonhosted.org/packages/f1/b7/a65fec226f5d78fc39f4a13c4cc0c768c22b113438f60c14adc9d2865038/pydantic_core-2.46.4-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5b712b53160b79a5850310b912a5ef8e57e56947c8ad690c227f5c9d7e561712", size = 2232274, upload-time = "2026-05-06T13:38:27.753Z" }, - { url = "https://files.pythonhosted.org/packages/68/f0/92039db98b907ef49269a8271f67db9cb78ae2fc68062ef7e4e77adb5f61/pydantic_core-2.46.4-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9401557acd873c3a7f3eb9383edef8ac4968f9510e340f4808d427e75667e7b4", size = 2309940, upload-time = "2026-05-06T13:38:05.353Z" }, - { url = "https://files.pythonhosted.org/packages/5f/97/2aab507d3d00ca626e8e57c1eac6a79e4e5fbcc63eb99733ff55d1717f65/pydantic_core-2.46.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:926c9541b14b12b1681dca8a0b75feb510b06c6341b70a8e500c2fdcff837cce", size = 2094516, upload-time = "2026-05-06T13:39:10.577Z" }, - { url = "https://files.pythonhosted.org/packages/22/37/a8aca44d40d737dde2bc05b3c6c07dff0de07ce6f82e9f3167aeaf4d5dea/pydantic_core-2.46.4-cp312-cp312-manylinux_2_31_riscv64.whl", hash = "sha256:56cb4851bcaf3d117eddcef4fe66afd750a50274b0da8e22be256d10e5611987", size = 2136854, upload-time = "2026-05-06T13:40:22.59Z" }, - { url = "https://files.pythonhosted.org/packages/24/99/fcef1b79238c06a8cbec70819ac722ba76e02bc8ada9b0fd66eba40da01b/pydantic_core-2.46.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c68fcd102d71ea85c5b2dfac3f4f8476eff42a9e078fd5faefff6d145063536b", size = 2180306, upload-time = "2026-05-06T13:40:10.666Z" }, - { url = "https://files.pythonhosted.org/packages/ae/6c/fc44000918855b42779d007ae63b0532794739027b2f417321cddbc44f6a/pydantic_core-2.46.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:b2f69dec1725e79a012d920df1707de5caf7ed5e08f3be4435e25803efc47458", size = 2190044, upload-time = "2026-05-06T13:40:43.231Z" }, - { url = "https://files.pythonhosted.org/packages/6b/65/d9cadc9f1920d7a127ad2edba16c1db7916e59719285cd6c94600b0080ba/pydantic_core-2.46.4-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:8d0820e8192167f80d88d64038e609c31452eeca865b4e1d9950a27a4609b00b", size = 2329133, upload-time = "2026-05-06T13:39:57.365Z" }, - { url = "https://files.pythonhosted.org/packages/d0/cf/c873d91679f3a30bcf5e7ac280ce5573483e72295307685120d0d5ad3416/pydantic_core-2.46.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:fbdb89b3e1c94a30cc5edfce477c6e6a5dc4d8f84665b455c27582f211a1c72c", size = 2374464, upload-time = "2026-05-06T13:38:06.976Z" }, - { url = "https://files.pythonhosted.org/packages/47/bd/6f2fc8188f31bf10590f1e98e7b306336161fac930a8c514cd7bd828c7dc/pydantic_core-2.46.4-cp312-cp312-win32.whl", hash = "sha256:9aa768456404a8bf48a4406685ac2bec8e72b62c69313734fa3b73cf33b3a894", size = 1974823, upload-time = "2026-05-06T13:40:47.985Z" }, - { url = "https://files.pythonhosted.org/packages/40/8c/985c1d41ea1107c2534abd9870e4ed5c8e7669b5c308297835c001e7a1c4/pydantic_core-2.46.4-cp312-cp312-win_amd64.whl", hash = "sha256:e9c26f834c65f5752f3f06cb08cb86a913ceb7274d0db6e267808a708b46bc89", size = 2072919, upload-time = "2026-05-06T13:39:21.153Z" }, - { url = "https://files.pythonhosted.org/packages/c4/ba/f463d006e0c47373ca7ec5e1a261c59dc01ef4d62b2657af925fb0deee3a/pydantic_core-2.46.4-cp312-cp312-win_arm64.whl", hash = "sha256:4fc73cb559bdb54b1134a706a2802a4cddd27a0633f5abb7e53056268751ac6a", size = 2027604, upload-time = "2026-05-06T13:39:03.753Z" }, - { url = "https://files.pythonhosted.org/packages/9d/1d/8987ad40f65ae1432753072f214fb5c74fe47ffbd0698bb9cbbb585664f8/pydantic_core-2.46.4-graalpy312-graalpy250_312_native-macosx_10_12_x86_64.whl", hash = "sha256:1d8ba486450b14f3b1d63bc521d410ec7565e52f887b9fb671791886436a42f7", size = 2095527, upload-time = "2026-05-06T13:39:52.283Z" }, - { url = "https://files.pythonhosted.org/packages/64/d3/84c282a7eee1d3ac4c0377546ef5a1ea436ce26840d9ac3b7ed54a377507/pydantic_core-2.46.4-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:3009f12e4e90b7f88b4f9adb1b0c4a3d58fe7820f3238c190047209d148026df", size = 1936024, upload-time = "2026-05-06T13:40:15.671Z" }, - { url = "https://files.pythonhosted.org/packages/d7/ca/eac61596cdeb4d7e174d3dc0bd8a6238f14f75f97a24e7b7db4c7e7340a0/pydantic_core-2.46.4-graalpy312-graalpy250_312_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ad785e92e6dc634c21555edc8bd6b64957ab844541bcb96a1366c202951ae526", size = 1990696, upload-time = "2026-05-06T13:38:34.717Z" }, - { url = "https://files.pythonhosted.org/packages/fa/c3/7c8b240552251faf6b3a957db200fcfbbcec36763c050428b601e0c9b83b/pydantic_core-2.46.4-graalpy312-graalpy250_312_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:00c603d540afdd6b80eb39f078f33ebd46211f02f33e34a32d9f053bba711de0", size = 2147590, upload-time = "2026-05-06T13:39:29.883Z" }, -] - [[package]] name = "pygments" version = "2.20.0" @@ -1136,15 +912,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 = "pyparsing" -version = "3.3.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f3/91/9c6ee907786a473bf81c5f53cf703ba0957b23ab84c264080fb5a450416f/pyparsing-3.3.2.tar.gz", hash = "sha256:c777f4d763f140633dcb6d8a3eda953bf7a214dc4eff598413c070bcdc117cbc", size = 6851574, upload-time = "2026-01-21T03:57:59.36Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/10/bd/c038d7cc38edc1aa5bf91ab8068b63d4308c66c4c8bb3cbba7dfbc049f9c/pyparsing-3.3.2-py3-none-any.whl", hash = "sha256:850ba148bd908d7e2411587e247a1e4f0327839c40e2e5e6d05a007ecc69911d", size = 122781, upload-time = "2026-01-21T03:57:55.912Z" }, -] - [[package]] name = "pytest" version = "9.0.3" @@ -1161,57 +928,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d4/24/a372aaf5c9b7208e7112038812994107bc65a84cd00e0354a88c2c77a617/pytest-9.0.3-py3-none-any.whl", hash = "sha256:2c5efc453d45394fdd706ade797c0a81091eccd1d6e4bccfcd476e2b8e0ab5d9", size = 375249, upload-time = "2026-04-07T17:16:16.13Z" }, ] -[[package]] -name = "python-coreml-stable-diffusion" -version = "1.1.0" -source = { git = "https://github.com/apple/ml-stable-diffusion.git?rev=e5d960c41a6a4ab200b8db379194127607b1c590#e5d960c41a6a4ab200b8db379194127607b1c590" } -dependencies = [ - { name = "coremltools" }, - { name = "diffusers" }, - { name = "diffusionkit" }, - { name = "huggingface-hub" }, - { name = "invisible-watermark" }, - { name = "matplotlib" }, - { name = "numpy" }, - { name = "pytest" }, - { name = "safetensors" }, - { name = "scikit-learn" }, - { name = "scipy" }, - { name = "torch" }, - { name = "transformers" }, -] - -[[package]] -name = "python-dateutil" -version = "2.9.0.post0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "six" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432, upload-time = "2024-03-01T18:36:20.211Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892, upload-time = "2024-03-01T18:36:18.57Z" }, -] - -[[package]] -name = "pywavelets" -version = "1.8.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "numpy" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/48/45/bfaaab38545a33a9f06c61211fc3bea2e23e8a8e00fedeb8e57feda722ff/pywavelets-1.8.0.tar.gz", hash = "sha256:f3800245754840adc143cbc29534a1b8fc4b8cff6e9d403326bd52b7bb5c35aa", size = 3935274, upload-time = "2024-12-04T19:54:20.593Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/2d/8b/4870f11559307416470158a5aa6f61e5c2a910f1645a7a836ffae580b7ad/pywavelets-1.8.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:3f431c9e2aff1a2240765eff5e804975d0fcc24c82d6f3d4271243f228e5963b", size = 4326187, upload-time = "2024-12-04T19:53:35.19Z" }, - { url = "https://files.pythonhosted.org/packages/c4/35/66835d889fd7fbf3119c7a9bd9d9bd567fc0bb603dfba408e9226db7cb44/pywavelets-1.8.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:e39b0e2314e928cb850ee89b9042733a10ea044176a495a54dc84d2c98407a51", size = 4295428, upload-time = "2024-12-04T19:53:36.962Z" }, - { url = "https://files.pythonhosted.org/packages/63/1c/42e5130226538c70d4bbbaee00eb1bc06ec3287f7ea43d5fcf85bfc761ce/pywavelets-1.8.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cae701117f5c7244b7c8d48b9e92a0289637cdc02a9c205e8be83361f0c11fae", size = 4421259, upload-time = "2024-12-04T19:53:39.119Z" }, - { url = "https://files.pythonhosted.org/packages/6f/c5/1ce93657432e22a5debc21e8b52ec6980f819ecb7fa727bb86744224d967/pywavelets-1.8.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:649936baee933e80083788e0adc4d8bc2da7cdd8b10464d3b113475be2cc5308", size = 4447650, upload-time = "2024-12-04T19:53:41.589Z" }, - { url = "https://files.pythonhosted.org/packages/b9/d6/b54ef30daca71824f811f9d2322a978b0a58d27674b8e3af6520f67e9ec6/pywavelets-1.8.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8c68e9d072c536bc646e8bdce443bb1826eeb9aa21b2cb2479a43954dea692a3", size = 4448538, upload-time = "2024-12-04T19:53:44.308Z" }, - { url = "https://files.pythonhosted.org/packages/ce/8c/1688b790e55674667ad644262f174405c2c9873cb13e773432e78b1b33e4/pywavelets-1.8.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:63f67fa2ee1610445de64f746fb9c1df31980ad13d896ea2331fc3755f49b3ae", size = 4485228, upload-time = "2024-12-04T19:53:46.778Z" }, - { url = "https://files.pythonhosted.org/packages/c9/9b/69de31c3b663dadd76d1da6bf8af68d8cefff55df8e880fe96a94bb8c9ac/pywavelets-1.8.0-cp312-cp312-win32.whl", hash = "sha256:4b3c2ab669c91e3474fd63294355487b7dd23f0b51d32f811327ddf3546f4f3d", size = 4134850, upload-time = "2024-12-04T19:53:49.101Z" }, - { url = "https://files.pythonhosted.org/packages/1c/88/9e2aa9d5fde08bfc0fb18ffb1b5307c1ed49c24930b4147e5f48571a7251/pywavelets-1.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:810a23a631da596fef7196ddec49b345b1aab13525bb58547eeebe1769edbbc1", size = 4210786, upload-time = "2024-12-04T19:53:51.546Z" }, -] - [[package]] name = "pyyaml" version = "6.0.3" @@ -1269,6 +985,19 @@ 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 = "rich" +version = "15.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markdown-it-py" }, + { name = "pygments" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c0/8f/0722ca900cc807c13a6a0c696dacf35430f72e0ec571c4275d2371fca3e9/rich-15.0.0.tar.gz", hash = "sha256:edd07a4824c6b40189fb7ac9bc4c52536e9780fbbfbddf6f1e2502c31b068c36", size = 230680, upload-time = "2026-04-12T08:24:00.75Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl", hash = "sha256:33bd4ef74232fb73fe9279a257718407f169c09b78a87ad3d296f548e27de0bb", size = 310654, upload-time = "2026-04-12T08:24:02.83Z" }, +] + [[package]] name = "safetensors" version = "0.7.0" @@ -1291,25 +1020,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/5d/e6/ec8471c8072382cb91233ba7267fd931219753bb43814cbc71757bfd4dab/safetensors-0.7.0-cp38-abi3-win_amd64.whl", hash = "sha256:d1239932053f56f3456f32eb9625590cc7582e905021f94636202a864d470755", size = 341380, upload-time = "2025-11-19T15:18:44.427Z" }, ] -[[package]] -name = "scikit-learn" -version = "1.7.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "joblib" }, - { name = "numpy" }, - { name = "scipy" }, - { name = "threadpoolctl" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/98/c2/a7855e41c9d285dfe86dc50b250978105dce513d6e459ea66a6aeb0e1e0c/scikit_learn-1.7.2.tar.gz", hash = "sha256:20e9e49ecd130598f1ca38a1d85090e1a600147b9c02fa6f15d69cb53d968fda", size = 7193136, upload-time = "2025-09-09T08:21:29.075Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a7/aa/3996e2196075689afb9fce0410ebdb4a09099d7964d061d7213700204409/scikit_learn-1.7.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:8d91a97fa2b706943822398ab943cde71858a50245e31bc71dba62aab1d60a96", size = 9259818, upload-time = "2025-09-09T08:20:43.19Z" }, - { url = "https://files.pythonhosted.org/packages/43/5d/779320063e88af9c4a7c2cf463ff11c21ac9c8bd730c4a294b0000b666c9/scikit_learn-1.7.2-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:acbc0f5fd2edd3432a22c69bed78e837c70cf896cd7993d71d51ba6708507476", size = 8636997, upload-time = "2025-09-09T08:20:45.468Z" }, - { url = "https://files.pythonhosted.org/packages/5c/d0/0c577d9325b05594fdd33aa970bf53fb673f051a45496842caee13cfd7fe/scikit_learn-1.7.2-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:e5bf3d930aee75a65478df91ac1225ff89cd28e9ac7bd1196853a9229b6adb0b", size = 9478381, upload-time = "2025-09-09T08:20:47.982Z" }, - { url = "https://files.pythonhosted.org/packages/82/70/8bf44b933837ba8494ca0fc9a9ab60f1c13b062ad0197f60a56e2fc4c43e/scikit_learn-1.7.2-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b4d6e9deed1a47aca9fe2f267ab8e8fe82ee20b4526b2c0cd9e135cea10feb44", size = 9300296, upload-time = "2025-09-09T08:20:50.366Z" }, - { url = "https://files.pythonhosted.org/packages/c6/99/ed35197a158f1fdc2fe7c3680e9c70d0128f662e1fee4ed495f4b5e13db0/scikit_learn-1.7.2-cp312-cp312-win_amd64.whl", hash = "sha256:6088aa475f0785e01bcf8529f55280a3d7d298679f50c0bb70a2364a82d0b290", size = 8731256, upload-time = "2025-09-09T08:20:52.627Z" }, -] - [[package]] name = "scipy" version = "1.15.3" @@ -1346,19 +1056,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/fe/02/c5e3bc518655d714622bec87d83db9cdba1cd0619a4a04e2109751c4f47f/sentencepiece-0.2.1-cp312-cp312-win_arm64.whl", hash = "sha256:daeb5e9e9fcad012324807856113708614d534f596d5008638eb9b40112cd9e4", size = 1033923, upload-time = "2025-08-12T06:59:51.952Z" }, ] -[[package]] -name = "sentry-sdk" -version = "2.60.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "certifi" }, - { name = "urllib3" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/54/a2/2e6c090db384cc515069f4f85542bd5baf6786852073020ea73d4a76d3ea/sentry_sdk-2.60.0.tar.gz", hash = "sha256:0bd25e54e78ca02d0be512529fa644bbbf9e8470d7b26371294012d4ca93c978", size = 452946, upload-time = "2026-05-13T13:34:52.516Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/29/41/f2b800b7f12a05dd48c2a6280d4dd812d1425fc66ed3fe3fd99420c41d1a/sentry_sdk-2.60.0-py3-none-any.whl", hash = "sha256:28a536c03291c8bcb363cf35c611b32738ec118ff64d8d6383b096448ac4c803", size = 475616, upload-time = "2026-05-13T13:34:50.259Z" }, -] - [[package]] name = "setuptools" version = "81.0.0" @@ -1369,21 +1066,12 @@ wheels = [ ] [[package]] -name = "six" -version = "1.17.0" +name = "shellingham" +version = "1.5.4" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031, upload-time = "2024-12-04T17:35:28.174Z" } +sdist = { url = "https://files.pythonhosted.org/packages/58/15/8b3609fd3830ef7b27b655beb4b4e9c62313a4e8da8c676e142cc210d58e/shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de", size = 10310, upload-time = "2023-10-24T04:13:40.426Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050, upload-time = "2024-12-04T17:35:26.475Z" }, -] - -[[package]] -name = "smmap" -version = "5.0.3" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/1f/ea/49c993d6dfdd7338c9b1000a0f36817ed7ec84577ae2e52f890d1a4ff909/smmap-5.0.3.tar.gz", hash = "sha256:4d9debb8b99007ae47165abc08670bd74cb74b5227dda7f643eccc4e9eb5642c", size = 22506, upload-time = "2026-03-09T03:43:26.1Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c1/d4/59e74daffcb57a07668852eeeb6035af9f32cbfd7a1d2511f17d2fe6a738/smmap-5.0.3-py3-none-any.whl", hash = "sha256:c106e05d5a61449cf6ba9a1e650227ecfb141590d2a98412103ff35d89fc7b2f", size = 24390, upload-time = "2026-03-09T03:43:24.361Z" }, + { url = "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686", size = 9755, upload-time = "2023-10-24T04:13:38.866Z" }, ] [[package]] @@ -1434,45 +1122,30 @@ 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 = "tabulate" -version = "0.10.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/46/58/8c37dea7bbf769b20d58e7ace7e5edfe65b849442b00ffcdd56be88697c6/tabulate-0.10.0.tar.gz", hash = "sha256:e2cfde8f79420f6deeffdeda9aaec3b6bc5abce947655d17ac662b126e48a60d", size = 91754, upload-time = "2026-03-04T18:55:34.402Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/99/55/db07de81b5c630da5cbf5c7df646580ca26dfaefa593667fc6f2fe016d2e/tabulate-0.10.0-py3-none-any.whl", hash = "sha256:f0b0622e567335c8fabaaa659f1b33bcb6ddfe2e496071b743aa113f8774f2d3", size = 39814, upload-time = "2026-03-04T18:55:31.284Z" }, -] - -[[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.19.1" +version = "0.22.2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "huggingface-hub" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/48/04/2071c150f374aab6d5e92aaec38d0f3c368d227dd9e0469a1f0966ac68d1/tokenizers-0.19.1.tar.gz", hash = "sha256:ee59e6680ed0fdbe6b724cf38bd70400a0c1dd623b07ac729087270caeac88e3", size = 321039, upload-time = "2024-04-17T21:40:41.849Z" } +sdist = { url = "https://files.pythonhosted.org/packages/73/6f/f80cfef4a312e1fb34baf7d85c72d4411afde10978d4657f8cdd811d3ccc/tokenizers-0.22.2.tar.gz", hash = "sha256:473b83b915e547aa366d1eee11806deaf419e17be16310ac0a14077f1e28f917", size = 372115, upload-time = "2026-01-05T10:45:15.988Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/63/90/2890cd096898dcdb596ee172cde40c0f54a9cf43b0736aa260a5501252af/tokenizers-0.19.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:621d670e1b1c281a1c9698ed89451395d318802ff88d1fc1accff0867a06f153", size = 2530580, upload-time = "2024-04-17T21:37:10.688Z" }, - { url = "https://files.pythonhosted.org/packages/74/d1/f4e1e950adb36675dfd8f9d0f4be644f3f3aaf22a5677a4f5c81282b662e/tokenizers-0.19.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d924204a3dbe50b75630bd16f821ebda6a5f729928df30f582fb5aade90c818a", size = 2436682, upload-time = "2024-04-17T21:37:12.966Z" }, - { url = "https://files.pythonhosted.org/packages/ed/30/89b321a16c58d233e301ec15072c0d3ed5014825e72da98604cd3ab2fba1/tokenizers-0.19.1-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:4f3fefdc0446b1a1e6d81cd4c07088ac015665d2e812f6dbba4a06267d1a2c95", size = 3693494, upload-time = "2024-04-17T21:37:14.755Z" }, - { url = "https://files.pythonhosted.org/packages/05/40/fa899f32de483500fbc78befd378fd7afba4270f17db707d1a78c0a4ddc3/tokenizers-0.19.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9620b78e0b2d52ef07b0d428323fb34e8ea1219c5eac98c2596311f20f1f9266", size = 3566541, upload-time = "2024-04-17T21:37:17.067Z" }, - { url = "https://files.pythonhosted.org/packages/67/14/e7da32ae5fb4971830f1ef335932fae3fa57e76b537e852f146c850aefdf/tokenizers-0.19.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:04ce49e82d100594715ac1b2ce87d1a36e61891a91de774755f743babcd0dd52", size = 3430792, upload-time = "2024-04-17T21:37:19.055Z" }, - { url = "https://files.pythonhosted.org/packages/f2/4b/aae61bdb6ab584d2612170801703982ee0e35f8b6adacbeefe5a3b277621/tokenizers-0.19.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c5c2ff13d157afe413bf7e25789879dd463e5a4abfb529a2d8f8473d8042e28f", size = 3962812, upload-time = "2024-04-17T21:37:21.008Z" }, - { url = "https://files.pythonhosted.org/packages/0a/b6/f7b7ef89c4da7b20256e6eab23d3835f05d1ca8f451d31c16cbfe3cd9eb6/tokenizers-0.19.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3174c76efd9d08f836bfccaca7cfec3f4d1c0a4cf3acbc7236ad577cc423c840", size = 4024688, upload-time = "2024-04-17T21:37:23.659Z" }, - { url = "https://files.pythonhosted.org/packages/80/54/12047a69f5b382d7ee72044dc89151a2dd0d13b2c9bdcc22654883704d31/tokenizers-0.19.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7c9d5b6c0e7a1e979bec10ff960fae925e947aab95619a6fdb4c1d8ff3708ce3", size = 3610961, upload-time = "2024-04-17T21:37:26.234Z" }, - { url = "https://files.pythonhosted.org/packages/52/b7/1e8a913d18ac28feeda42d4d2d51781874398fb59cd1c1e2653a4b5742ed/tokenizers-0.19.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:a179856d1caee06577220ebcfa332af046d576fb73454b8f4d4b0ba8324423ea", size = 9631367, upload-time = "2024-04-17T21:37:28.752Z" }, - { url = "https://files.pythonhosted.org/packages/ac/3d/2284f6d99f8f21d09352b88b8cfefa24ab88468d962aeb0aa15c20d76b32/tokenizers-0.19.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:952b80dac1a6492170f8c2429bd11fcaa14377e097d12a1dbe0ef2fb2241e16c", size = 9950121, upload-time = "2024-04-17T21:37:31.741Z" }, - { url = "https://files.pythonhosted.org/packages/2a/94/ec3369dbc9b7200c14c8c7a1a04c78b7a7398d0c001e1b7d1ffe30eb93a0/tokenizers-0.19.1-cp312-none-win32.whl", hash = "sha256:01d62812454c188306755c94755465505836fd616f75067abcae529c35edeb57", size = 2044069, upload-time = "2024-04-17T21:37:35.672Z" }, - { url = "https://files.pythonhosted.org/packages/0c/97/80bff6937e0c67d30c0facacd4f0bcf4254e581aa4995c73cef8c8640e56/tokenizers-0.19.1-cp312-none-win_amd64.whl", hash = "sha256:b70bfbe3a82d3e3fb2a5e9b22a39f8d1740c96c68b6ace0086b39074f08ab89a", size = 2214527, upload-time = "2024-04-17T21:37:39.19Z" }, + { url = "https://files.pythonhosted.org/packages/92/97/5dbfabf04c7e348e655e907ed27913e03db0923abb5dfdd120d7b25630e1/tokenizers-0.22.2-cp39-abi3-macosx_10_12_x86_64.whl", hash = "sha256:544dd704ae7238755d790de45ba8da072e9af3eea688f698b137915ae959281c", size = 3100275, upload-time = "2026-01-05T10:41:02.158Z" }, + { url = "https://files.pythonhosted.org/packages/2e/47/174dca0502ef88b28f1c9e06b73ce33500eedfac7a7692108aec220464e7/tokenizers-0.22.2-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:1e418a55456beedca4621dbab65a318981467a2b188e982a23e117f115ce5001", size = 2981472, upload-time = "2026-01-05T10:41:00.276Z" }, + { url = "https://files.pythonhosted.org/packages/d6/84/7990e799f1309a8b87af6b948f31edaa12a3ed22d11b352eaf4f4b2e5753/tokenizers-0.22.2-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2249487018adec45d6e3554c71d46eb39fa8ea67156c640f7513eb26f318cec7", size = 3290736, upload-time = "2026-01-05T10:40:32.165Z" }, + { url = "https://files.pythonhosted.org/packages/78/59/09d0d9ba94dcd5f4f1368d4858d24546b4bdc0231c2354aa31d6199f0399/tokenizers-0.22.2-cp39-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:25b85325d0815e86e0bac263506dd114578953b7b53d7de09a6485e4a160a7dd", size = 3168835, upload-time = "2026-01-05T10:40:38.847Z" }, + { url = "https://files.pythonhosted.org/packages/47/50/b3ebb4243e7160bda8d34b731e54dd8ab8b133e50775872e7a434e524c28/tokenizers-0.22.2-cp39-abi3-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bfb88f22a209ff7b40a576d5324bf8286b519d7358663db21d6246fb17eea2d5", size = 3521673, upload-time = "2026-01-05T10:40:56.614Z" }, + { url = "https://files.pythonhosted.org/packages/e0/fa/89f4cb9e08df770b57adb96f8cbb7e22695a4cb6c2bd5f0c4f0ebcf33b66/tokenizers-0.22.2-cp39-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1c774b1276f71e1ef716e5486f21e76333464f47bece56bbd554485982a9e03e", size = 3724818, upload-time = "2026-01-05T10:40:44.507Z" }, + { url = "https://files.pythonhosted.org/packages/64/04/ca2363f0bfbe3b3d36e95bf67e56a4c88c8e3362b658e616d1ac185d47f2/tokenizers-0.22.2-cp39-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:df6c4265b289083bf710dff49bc51ef252f9d5be33a45ee2bed151114a56207b", size = 3379195, upload-time = "2026-01-05T10:40:51.139Z" }, + { url = "https://files.pythonhosted.org/packages/2e/76/932be4b50ef6ccedf9d3c6639b056a967a86258c6d9200643f01269211ca/tokenizers-0.22.2-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:369cc9fc8cc10cb24143873a0d95438bb8ee257bb80c71989e3ee290e8d72c67", size = 3274982, upload-time = "2026-01-05T10:40:58.331Z" }, + { url = "https://files.pythonhosted.org/packages/1d/28/5f9f5a4cc211b69e89420980e483831bcc29dade307955cc9dc858a40f01/tokenizers-0.22.2-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:29c30b83d8dcd061078b05ae0cb94d3c710555fbb44861139f9f83dcca3dc3e4", size = 9478245, upload-time = "2026-01-05T10:41:04.053Z" }, + { url = "https://files.pythonhosted.org/packages/6c/fb/66e2da4704d6aadebf8cb39f1d6d1957df667ab24cff2326b77cda0dcb85/tokenizers-0.22.2-cp39-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:37ae80a28c1d3265bb1f22464c856bd23c02a05bb211e56d0c5301a435be6c1a", size = 9560069, upload-time = "2026-01-05T10:45:10.673Z" }, + { url = "https://files.pythonhosted.org/packages/16/04/fed398b05caa87ce9b1a1bb5166645e38196081b225059a6edaff6440fac/tokenizers-0.22.2-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:791135ee325f2336f498590eb2f11dc5c295232f288e75c99a36c5dbce63088a", size = 9899263, upload-time = "2026-01-05T10:45:12.559Z" }, + { url = "https://files.pythonhosted.org/packages/05/a1/d62dfe7376beaaf1394917e0f8e93ee5f67fea8fcf4107501db35996586b/tokenizers-0.22.2-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:38337540fbbddff8e999d59970f3c6f35a82de10053206a7562f1ea02d046fa5", size = 10033429, upload-time = "2026-01-05T10:45:14.333Z" }, + { url = "https://files.pythonhosted.org/packages/fd/18/a545c4ea42af3df6effd7d13d250ba77a0a86fb20393143bbb9a92e434d4/tokenizers-0.22.2-cp39-abi3-win32.whl", hash = "sha256:a6bf3f88c554a2b653af81f3204491c818ae2ac6fbc09e76ef4773351292bc92", size = 2502363, upload-time = "2026-01-05T10:45:20.593Z" }, + { url = "https://files.pythonhosted.org/packages/65/71/0670843133a43d43070abeb1949abfdef12a86d490bea9cd9e18e37c5ff7/tokenizers-0.22.2-cp39-abi3-win_amd64.whl", hash = "sha256:c9ea31edff2968b44a88f97d784c2f16dc0729b8b143ed004699ebca91f05c48", size = 2747786, upload-time = "2026-01-05T10:45:18.411Z" }, + { url = "https://files.pythonhosted.org/packages/72/f4/0de46cfa12cdcbcd464cc59fde36912af405696f687e53a091fb432f694c/tokenizers-0.22.2-cp39-abi3-win_arm64.whl", hash = "sha256:9ce725d22864a1e965217204946f830c37876eee3b2ba6fc6255e8e903d5fcbc", size = 2612133, upload-time = "2026-01-05T10:45:17.232Z" }, ] [[package]] @@ -1574,23 +1247,22 @@ wheels = [ [[package]] name = "transformers" -version = "4.44.2" +version = "5.9.0" 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" }, + { name = "typer" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/f8/a3/81de49357a3c6ac4421d48d9662b53293838f217baf3f3bb9eb55f89fab6/transformers-4.44.2.tar.gz", hash = "sha256:36aa17cc92ee154058e426d951684a2dab48751b35b49437896f898931270826", size = 8110312, upload-time = "2024-08-22T16:56:33.522Z" } +sdist = { url = "https://files.pythonhosted.org/packages/51/58/7f843608f2e8421f86bb97060b54649be6239ec612b82bf9d41e65c26c00/transformers-5.9.0.tar.gz", hash = "sha256:25997cb8fa6053533171634b6162d7df54346530ec2aa9b42bb834e63668c842", size = 8642240, upload-time = "2026-05-20T14:50:49.278Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/75/35/07c9879163b603f0e464b0f6e6e628a2340cfc7cdc5ca8e7d52d776710d4/transformers-4.44.2-py3-none-any.whl", hash = "sha256:1c02c65e7bfa5e52a634aff3da52138b583fc6f263c1f28d547dc144ba3d412d", size = 9465369, upload-time = "2024-08-22T16:56:29.207Z" }, + { url = "https://files.pythonhosted.org/packages/02/ca/2eaa5359f2ccb8c2e1656bc26305ad0cf438aa392ce4b29ae67a315c186e/transformers-5.9.0-py3-none-any.whl", hash = "sha256:1d19509bcff7028ebc6b277d71caa712e8353778463d38764237d14b42b52788", size = 10787648, upload-time = "2026-05-20T14:50:45.337Z" }, ] [[package]] @@ -1604,6 +1276,21 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/24/5f/950fb373bf9c01ad4eb5a8cd5eaf32cdf9e238c02f9293557a2129b9c4ac/triton-3.3.1-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9999e83aba21e1a78c1f36f21bce621b77bcaa530277a50484a7cb4a822f6e43", size = 155669138, upload-time = "2025-05-29T23:39:51.771Z" }, ] +[[package]] +name = "typer" +version = "0.25.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "annotated-doc" }, + { name = "click" }, + { name = "rich" }, + { name = "shellingham" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/e4/51/9aed62104cea109b820bbd6c14245af756112017d309da813ef107d42e7e/typer-0.25.1.tar.gz", hash = "sha256:9616eb8853a09ffeabab1698952f33c6f29ffdbceb4eaeecf571880e8d7664cc", size = 122276, upload-time = "2026-04-30T19:32:16.964Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3f/f9/2b3ff4e56e5fa7debfaf9eb135d0da96f3e9a1d5b27222223c7296336e5f/typer-0.25.1-py3-none-any.whl", hash = "sha256:75caa44ed46a03fb2dab8808753ffacdbfea88495e74c85a28c5eefcf5f39c89", size = 58409, upload-time = "2026-04-30T19:32:18.271Z" }, +] + [[package]] name = "typing-extensions" version = "4.15.0" @@ -1613,18 +1300,6 @@ 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 = "typing-inspection" -version = "0.4.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/55/e3/70399cb7dd41c10ac53367ae42139cf4b1ca5f36bb3dc6c9d33acdb43655/typing_inspection-0.4.2.tar.gz", hash = "sha256:ba561c48a67c5958007083d386c3295464928b01faa735ab8547c5692e87f464", size = 75949, upload-time = "2025-10-01T02:14:41.687Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl", hash = "sha256:4ed1cacbdc298c220f1bd249ed5287caa16f34d44ef4e9c3d0cbad5b521545e7", size = 14611, upload-time = "2025-10-01T02:14:40.154Z" }, -] - [[package]] name = "urllib3" version = "2.7.0" @@ -1634,44 +1309,6 @@ 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 = "wadler-lindig" -version = "0.1.7" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/1e/67/cbae4bf7683a64755c2c1778c418fea96d00e34395bb91743f08bd951571/wadler_lindig-0.1.7.tar.gz", hash = "sha256:81d14d3fe77d441acf3ebd7f4aefac20c74128bf460e84b512806dccf7b2cd55", size = 15842, upload-time = "2025-06-18T07:00:42.843Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/8d/96/04e7b441807b26b794da5b11e59ed7f83b2cf8af202bd7eba8ad2fa6046e/wadler_lindig-0.1.7-py3-none-any.whl", hash = "sha256:e3ec83835570fd0a9509f969162aeb9c65618f998b1f42918cfc8d45122fe953", size = 20516, upload-time = "2025-06-18T07:00:41.684Z" }, -] - -[[package]] -name = "wandb" -version = "0.27.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "click" }, - { name = "gitpython" }, - { name = "packaging" }, - { name = "platformdirs" }, - { name = "protobuf" }, - { name = "pydantic" }, - { name = "pyyaml" }, - { name = "requests" }, - { name = "sentry-sdk" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/8e/31/fe53d06b75ef0a7f2f0ee5931a89f7aedc27d233840b1839616860fed256/wandb-0.27.0.tar.gz", hash = "sha256:579e75300173059f9334e1f513a79ef15f6d9ea5c74e20d695633648cdd02031", size = 41090732, upload-time = "2026-05-14T03:44:08.894Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ea/5e/2c199e70e636ecfd217cde0bc7469f4511e1d03d0685eb92bfdfce391430/wandb-0.27.0-py3-none-macosx_12_0_arm64.whl", hash = "sha256:c156be4851485f3c4160cb6eb2e8991b4cdeffbccefc5636d33cf5e254847365", size = 24886476, upload-time = "2026-05-14T03:43:27.569Z" }, - { url = "https://files.pythonhosted.org/packages/0b/cd/a617c871cd304a9804e56a7ec2ec2c65685bf0091a2b9f91910175a149e2/wandb-0.27.0-py3-none-macosx_12_0_x86_64.whl", hash = "sha256:20179f38afb0158859a4141d29ac650d3fdbd0cf801a74ce25565c934f03776c", size = 26045779, upload-time = "2026-05-14T03:43:31.999Z" }, - { url = "https://files.pythonhosted.org/packages/10/0a/d3f159a201530b84b72ca5f98c68d1f351c2d9a1864558ed76c811407fae/wandb-0.27.0-py3-none-manylinux_2_28_aarch64.whl", hash = "sha256:626497d7975fa898d0a4a239da7a510483495ca3514510dbe75004a25963af4d", size = 25480764, upload-time = "2026-05-14T03:43:35.922Z" }, - { url = "https://files.pythonhosted.org/packages/5f/6a/8721fcdf71d42639191040a77a585d2982402b1754700cb2ecfc2ca1470a/wandb-0.27.0-py3-none-manylinux_2_28_x86_64.whl", hash = "sha256:f772da7005cc26a2a32b729a16982a583dc68b3d493df6a09d0aa5c5ca5a2060", size = 27256204, upload-time = "2026-05-14T03:43:39.765Z" }, - { url = "https://files.pythonhosted.org/packages/00/5e/279d167ba79fb7a8a43401c9f25efd0f6663ee9bd1eaf5a8578530198888/wandb-0.27.0-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:63acfc5b994e4a90e4a2fbdee6d45e664da3dd865bb1419942c8995c06c41cf1", size = 25647469, upload-time = "2026-05-14T03:43:44.817Z" }, - { url = "https://files.pythonhosted.org/packages/94/51/a69ac59300e3c813939d0764348959ed2a21e14c668cb1cebcb04010da6a/wandb-0.27.0-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:17aae6e4a88cd05c00ea8f546220918e3ebb6f8c1c36b70ef04a5ac75f0d7160", size = 27599005, upload-time = "2026-05-14T03:43:50.926Z" }, - { url = "https://files.pythonhosted.org/packages/5f/40/bf510c8758727df020f83b717ebc1fcc1739ed7f6ae1796ebef60bf6f592/wandb-0.27.0-py3-none-win32.whl", hash = "sha256:0bd5659417e386bf6538b5e2ffe6885774c6197f0e4853bfed517d5b0db457f1", size = 25036164, upload-time = "2026-05-14T03:43:54.839Z" }, - { url = "https://files.pythonhosted.org/packages/54/ff/69f88e7d90c22b79bcb911143c13e59742ee192080b21015ff83a5a1f60a/wandb-0.27.0-py3-none-win_amd64.whl", hash = "sha256:89d584b73166eecee96fb446f18d0e45b1aa45aba6a3696296f3f06d7454516b", size = 25036170, upload-time = "2026-05-14T03:43:59.227Z" }, - { url = "https://files.pythonhosted.org/packages/f6/38/f7efd7a87297a55c7e9a331a1dbb5b19e54aeacc11fe6f43f8636a73987c/wandb-0.27.0-py3-none-win_arm64.whl", hash = "sha256:a6c129c311edf210a2b4f2f4acc557eff522628125f5f28ed27df19c16c07079", size = 22972710, upload-time = "2026-05-14T03:44:03.275Z" }, -] - [[package]] name = "yarl" version = "1.24.2"