diff --git a/cosmos_framework/scripts/_convert_model_to_diffusers.py b/cosmos_framework/scripts/_convert_model_to_diffusers.py index e1c14016..da5549ab 100644 --- a/cosmos_framework/scripts/_convert_model_to_diffusers.py +++ b/cosmos_framework/scripts/_convert_model_to_diffusers.py @@ -11,13 +11,18 @@ import pydantic import torch from accelerate import init_empty_weights -from diffusers import AutoencoderKLWan, UniPCMultistepScheduler -from diffusers_cosmos3 import Cosmos3OmniDiffusersPipeline, Cosmos3OmniTransformer +from diffusers import ( + AutoencoderKLWan, + Cosmos3AVAEAudioTokenizer, + Cosmos3OmniPipeline, + Cosmos3OmniTransformer, + UniPCMultistepScheduler, +) from transformers import AutoConfig, AutoTokenizer from cosmos_framework.inference.model import Cosmos3OmniModel -from cosmos_framework.utils import log from cosmos_framework.model.generator.omni_mot_model import OmniMoTModel +from cosmos_framework.utils import log DEFAULT_SOUND_TOKENIZER_CONFIG = { "model_type": "autoencoder_v2", @@ -62,14 +67,6 @@ "latent_std": None, } -SOUND_TOKENIZER_MODEL_INDEX_ENTRY = [ - "diffusers", - "Cosmos3AVAEAudioTokenizer", -] - -LEGACY_SOUND_TOKENIZER_CHECKPOINT_NAME = "model.safetensors" -DIFFUSERS_SOUND_TOKENIZER_CHECKPOINT_NAME = "diffusion_pytorch_model.safetensors" - # Wrapper prefixes that may appear on every key of a legacy AVAE state dict # (DDP wrappers, full-model saves, training exports). Stripped iteratively # until each key reaches a recognised target prefix. @@ -80,6 +77,28 @@ # [snake1, conv1, snake2, conv2]; map sub-index → named attribute. _SOUND_TOKENIZER_RES_UNIT_INNER_NAMES = {0: "snake1", 1: "conv1", 2: "snake2", 3: "conv2"} +# The source language_model nests its transformer stack under a `model.` +# attribute (HF Qwen-style); the diffusers `Cosmos3OmniTransformer` holds +# those layers flat, so the leading `model.` prefix is stripped. The +# PackedAttentionMoT projections are renamed from the source Qwen-style +# names (`q_proj`/… plus cosmos-specific `*_moe_gen`) to the diffusers +# AttentionModuleMixin canonical names. Order matters: the `*_moe_gen` +# substrings must be substituted before the plain ones. +_ATTN_KEY_REMAP = ( + (".q_proj_moe_gen.", ".add_q_proj."), + (".k_proj_moe_gen.", ".add_k_proj."), + (".v_proj_moe_gen.", ".add_v_proj."), + (".o_proj_moe_gen.", ".to_add_out."), + (".q_norm_moe_gen.", ".norm_added_q."), + (".k_norm_moe_gen.", ".norm_added_k."), + (".q_proj.", ".to_q."), + (".k_proj.", ".to_k."), + (".v_proj.", ".to_v."), + (".o_proj.", ".to_out."), + (".q_norm.", ".norm_q."), + (".k_norm.", ".norm_k."), +) + # Legacy TimestepEmbedder stored its MLP as `nn.Sequential([Linear, SiLU, Linear])`, # so state-dict keys were `mlp.0.*` / `mlp.2.*`. The diffusers `TimestepEmbedding` # stores them as named attributes `linear_1` / `linear_2`. Index 1 (SiLU) has no @@ -93,6 +112,7 @@ DEFAULT_VISION_ENCODER_MODEL = "Qwen/Qwen3-VL-8B-Instruct" VISION_ENCODER_CHECKPOINT_PREFIX = "model.visual." +VISION_ENCODER_CHECKPOINT_SUBFOLDER = "vision_encoder" def _get_config_value(*configs, name, default=None): @@ -108,6 +128,19 @@ def _get_config_value(*configs, name, default=None): return default +def _remap_language_model_key(key: str) -> str: + """Rename a source language-model state-dict key to the diffusers + `Cosmos3OmniTransformer` layout: strip the leading `model.` prefix and + apply the attention-projection renames from `_ATTN_KEY_REMAP`. + """ + key = key.removeprefix("model.") + for old, new in _ATTN_KEY_REMAP: + if old in key: + key = key.replace(old, new) + break + return key + + def _load_sound_tokenizer_state_dict(checkpoint_path: pathlib.Path) -> dict[str, torch.Tensor]: if checkpoint_path.suffix == ".safetensors": try: @@ -154,13 +187,15 @@ def _sound_tokenizer_strip_per_key_prefixes(state_dict: dict[str, torch.Tensor]) return out -def _sound_tokenizer_filter_decoder(state_dict: dict[str, torch.Tensor]) -> dict[str, torch.Tensor]: - """Drop encoder and bottleneck keys — only the decoder is used at inference.""" - return {k: v for k, v in state_dict.items() if k.startswith("decoder.")} +def _sound_tokenizer_filter_supported_modules(state_dict: dict[str, torch.Tensor]) -> dict[str, torch.Tensor]: + """Keep only encoder/decoder keys — `Cosmos3AVAEAudioTokenizer` supports + the parameter-free `vae` bottleneck only, so bottleneck keys are dropped. + """ + return {k: v for k, v in state_dict.items() if k.startswith(("encoder.", "decoder."))} def _sound_tokenizer_infer_num_blocks(state_dict: dict[str, torch.Tensor]) -> int: - """Count the OobleckDecoderBlocks present in a flat-`Sequential` legacy + """Count the decoder blocks present in a flat-`Sequential` legacy decoder state dict by spotting `decoder.layers.{N}.layers.{M}.*` keys. """ block_indices: set[int] = set() @@ -173,7 +208,7 @@ def _sound_tokenizer_infer_num_blocks(state_dict: dict[str, torch.Tensor]) -> in def _sound_tokenizer_remap_flat_layout(state_dict: dict[str, torch.Tensor]) -> dict[str, torch.Tensor]: """Rewrite a legacy `decoder.layers.{N}.*` flat-`Sequential` layout to the - diffusers OobleckDecoder named-attribute layout. + diffusers Cosmos3AudioDecoder named-attribute layout. The legacy decoder is Sequential([conv1, block_0, ..., block_{N-1}, snake1, conv2]) @@ -243,7 +278,11 @@ def _sound_tokenizer_reshape_snake_params(state_dict: dict[str, torch.Tensor]) - """ out: dict[str, torch.Tensor] = {} for key, value in state_dict.items(): - if (key.endswith(".alpha") or key.endswith(".beta")) and value.ndim == 1: + if ( + key.startswith(("encoder.", "decoder.")) + and (key.endswith(".alpha") or key.endswith(".beta")) + and value.ndim == 1 + ): value = value.unsqueeze(0).unsqueeze(-1).contiguous() out[key] = value return out @@ -252,7 +291,7 @@ def _sound_tokenizer_reshape_snake_params(state_dict: dict[str, torch.Tensor]) - def _sound_tokenizer_reapply_weight_norm(state_dict: dict[str, torch.Tensor]) -> dict[str, torch.Tensor]: """If a Conv layer has the folded `.weight` tensor but neither `.weight_g` nor `.weight_v`, reconstruct the pair so the resulting checkpoint can be - loaded into the weight-norm-wrapped diffusers OobleckDecoder. + loaded into the weight-norm-wrapped diffusers Cosmos3AudioDecoder. `weight_norm` with `dim=0` parameterises `weight = g * v / ||v||`. Setting `v = weight` and `g = ||weight||` along all non-zero axes is an exact @@ -262,7 +301,11 @@ def _sound_tokenizer_reapply_weight_norm(state_dict: dict[str, torch.Tensor]) -> candidate_keys = [ key for key in state_dict - if key.endswith(".weight") and any(f".{layer}." in key for layer in ("conv1", "conv2", "conv_t1")) + if key.endswith(".weight") + and ( + any(f".{layer}." in key for layer in ("conv1", "conv2", "conv_t1")) + or re.fullmatch(r"encoder\.layers\.\d+\.weight", key) + ) ] for key in candidate_keys: stem = key[: -len(".weight")] @@ -279,24 +322,17 @@ def _sound_tokenizer_reapply_weight_norm(state_dict: dict[str, torch.Tensor]) -> return out -def _remap_time_embedder_state_dict(state_dict: dict[str, torch.Tensor]) -> dict[str, torch.Tensor]: - """Remap a legacy `TimestepEmbedder` state dict (with `nn.Sequential`-style - `mlp.0` / `mlp.2` keys) to the diffusers `TimestepEmbedding` layout - (`linear_1` / `linear_2`). Keys not in `_TIME_EMBEDDER_KEY_REMAP` pass - through unchanged. - """ - return {_TIME_EMBEDDER_KEY_REMAP.get(key, key): value for key, value in state_dict.items()} - - def _remap_sound_tokenizer_state_dict(state_dict: dict[str, torch.Tensor]) -> dict[str, torch.Tensor]: """Apply the full legacy → diffusers conversion pipeline to a sound - tokenizer state dict: strip prefixes, drop non-decoder keys, remap the - flat `nn.Sequential` layout to named attributes, reshape Snake1d params, - and reconstruct `weight_g` / `weight_v` for any folded conv weights. + tokenizer state dict: strip prefixes, drop unsupported (bottleneck) keys, + remap the flat `nn.Sequential` layout to named attributes, reshape Snake1d + params, and reconstruct `weight_g` / `weight_v` for any folded conv weights. """ state_dict = _sound_tokenizer_strip_per_key_prefixes(state_dict) - state_dict = _sound_tokenizer_filter_decoder(state_dict) + state_dict = _sound_tokenizer_filter_supported_modules(state_dict) if not state_dict: + raise RuntimeError("Sound tokenizer state dict has no `encoder.*`/`decoder.*` keys after prefix stripping.") + if not any(key.startswith("decoder.") for key in state_dict): raise RuntimeError("Sound tokenizer state dict has no `decoder.*` keys after prefix stripping.") state_dict = _sound_tokenizer_remap_flat_layout(state_dict) state_dict = _sound_tokenizer_reshape_snake_params(state_dict) @@ -306,57 +342,39 @@ def _remap_sound_tokenizer_state_dict(state_dict: dict[str, torch.Tensor]) -> di return state_dict -def _load_sound_tokenizer_config(config_path: pathlib.Path | None, fallback_config_path: pathlib.Path) -> dict: - selected_config_path = config_path - if selected_config_path is None and fallback_config_path.exists(): - selected_config_path = fallback_config_path - if selected_config_path is None: +def _load_sound_tokenizer_config(config_path: pathlib.Path | None) -> dict: + if config_path is None: return dict(DEFAULT_SOUND_TOKENIZER_CONFIG) - with open(selected_config_path, encoding="utf-8") as f: + with open(config_path, encoding="utf-8") as f: return json.load(f) -def _save_sound_tokenizer( - output_dir: pathlib.Path, +def _build_sound_tokenizer( checkpoint_path: pathlib.Path, config_path: pathlib.Path | None, - remap_keys: bool = False, -) -> None: - try: - from safetensors.torch import save_file - except ImportError as exc: - raise ImportError("Saving AVAE tokenizer weights requires safetensors.") from exc - - sound_tokenizer_dir = output_dir / "sound_tokenizer" - sound_tokenizer_dir.mkdir(parents=True, exist_ok=True) - - config = _load_sound_tokenizer_config(config_path, sound_tokenizer_dir / "config.json") - with open(sound_tokenizer_dir / "config.json", "w", encoding="utf-8") as f: - json.dump(config, f, indent=4) - f.write("\n") +) -> Cosmos3AVAEAudioTokenizer: + config = _load_sound_tokenizer_config(config_path) log.info(f"Loading AVAE sound tokenizer weights from {checkpoint_path} …") - state_dict = _load_sound_tokenizer_state_dict(checkpoint_path) - if remap_keys: - log.info("Remapping AVAE sound tokenizer state dict to diffusers OobleckDecoder layout …") - state_dict = _remap_sound_tokenizer_state_dict(state_dict) - output_filename = ( - DIFFUSERS_SOUND_TOKENIZER_CHECKPOINT_NAME if remap_keys else LEGACY_SOUND_TOKENIZER_CHECKPOINT_NAME + raw_state_dict = _load_sound_tokenizer_state_dict(checkpoint_path) + state_dict = _remap_sound_tokenizer_state_dict(raw_state_dict) + has_encoder = any(key.startswith("encoder.") for key in state_dict) + log.info( + f"Remapped {len(raw_state_dict)} → {len(state_dict)} tokenizer keys " + f"({'encoder+decoder' if has_encoder else 'decoder-only'})." ) - log.info(f"Saving AVAE sound tokenizer to {sound_tokenizer_dir / output_filename} …") - save_file(state_dict, str(sound_tokenizer_dir / output_filename), metadata={"format": "pt"}) - -def _add_sound_tokenizer_to_model_index(output_dir: pathlib.Path) -> None: - model_index_path = output_dir / "model_index.json" - if not model_index_path.exists(): - return - with open(model_index_path, encoding="utf-8") as f: - model_index = json.load(f) - model_index["sound_tokenizer"] = SOUND_TOKENIZER_MODEL_INDEX_ENTRY - with open(model_index_path, "w", encoding="utf-8") as f: - json.dump(model_index, f, indent=2) - f.write("\n") + # `Cosmos3AVAEAudioTokenizer` accepts exactly the keys of the default + # config; unknown keys in a source config JSON are ignored. + tokenizer_kwargs = {name: config.get(name, default) for name, default in DEFAULT_SOUND_TOKENIZER_CONFIG.items()} + sound_tokenizer = Cosmos3AVAEAudioTokenizer(**tokenizer_kwargs, encoder_enabled=has_encoder) + load_result = sound_tokenizer.load_state_dict(state_dict, strict=True) + if load_result.missing_keys or load_result.unexpected_keys: + raise RuntimeError( + "Cosmos3 AVAE sound tokenizer load did not match strictly: " + f"missing={load_result.missing_keys}, unexpected={load_result.unexpected_keys}." + ) + return sound_tokenizer def _checkpoint_weight_map(checkpoint_path: pathlib.Path) -> dict[str, str]: @@ -372,6 +390,20 @@ def _checkpoint_has_weight_prefix(checkpoint_path: pathlib.Path, prefix: str) -> return any(key.startswith(prefix) for key in _checkpoint_weight_map(checkpoint_path)) +def _checkpoint_vision_subfolder_files(checkpoint_path: pathlib.Path) -> dict[str, list[str]]: + """Group root-index keys stored under vision_encoder/ by shard file. + + Diffusers-layout source checkpoints keep bare Qwen3VLVisionModel keys + (`blocks.*`, `patch_embed.*`, …) in the root weight map, mapped to files + under the vision_encoder/ subfolder. + """ + files_to_keys: dict[str, list[str]] = {} + for key, filename in _checkpoint_weight_map(checkpoint_path).items(): + if filename.replace("\\", "/").startswith(f"{VISION_ENCODER_CHECKPOINT_SUBFOLDER}/"): + files_to_keys.setdefault(filename, []).append(key) + return files_to_keys + + def _load_prefixed_safetensors_state_dict(checkpoint_path: pathlib.Path, prefix: str) -> dict[str, torch.Tensor]: try: from safetensors import safe_open @@ -448,6 +480,29 @@ def _build_vision_encoder( return vision_encoder.to(dtype=dtype) +def _load_vision_subfolder_state_dict(checkpoint_path: pathlib.Path) -> dict[str, torch.Tensor]: + try: + from safetensors import safe_open + except ImportError as exc: + raise ImportError("Loading sharded safetensors vision weights requires safetensors.") from exc + + files_to_keys = _checkpoint_vision_subfolder_files(checkpoint_path) + state_dict: dict[str, torch.Tensor] = {} + for filename, keys in sorted(files_to_keys.items()): + shard_path = checkpoint_path / filename + with safe_open(str(shard_path), framework="pt", device="cpu") as shard: + for key in sorted(keys): + state_dict[key] = shard.get_tensor(key).detach().cpu().contiguous() + + if not state_dict: + raise RuntimeError( + f"No vision encoder tensors found under {VISION_ENCODER_CHECKPOINT_SUBFOLDER}/. " + "If the source checkpoint has no Qwen3-VL visual weights (e.g. a vision-generation-only " + "post-training checkpoint), pass --skip-vision-encoder to export without vision_encoder/." + ) + return state_dict + + def _load_vision_encoder( checkpoint_path: pathlib.Path, source_model, @@ -455,11 +510,14 @@ def _load_vision_encoder( dtype: torch.dtype, ): state_dict = _get_source_vision_state_dict(source_model) - if state_dict is None: + if state_dict is not None: + log.info("Extracting Qwen3-VL vision encoder weights from loaded source model …") + elif _checkpoint_has_weight_prefix(checkpoint_path, VISION_ENCODER_CHECKPOINT_PREFIX): log.info(f"Loading Qwen3-VL vision encoder weights from {checkpoint_path} …") state_dict = _load_prefixed_safetensors_state_dict(checkpoint_path, VISION_ENCODER_CHECKPOINT_PREFIX) else: - log.info("Extracting Qwen3-VL vision encoder weights from loaded source model …") + log.info(f"Loading Qwen3-VL vision encoder weights from {checkpoint_path}/vision_encoder …") + state_dict = _load_vision_subfolder_state_dict(checkpoint_path) log.info(f"Building Qwen3-VL vision encoder from {model_name_or_path} …") return _build_vision_encoder(state_dict, model_name_or_path, dtype) @@ -498,21 +556,9 @@ class Args(pydantic.BaseModel): sound_tokenizer_path: str | None = None """Optional AVAE sound tokenizer checkpoint to save under sound_tokenizer/.""" sound_tokenizer_config_path: str | None = None - """Optional AVAE config JSON to save under sound_tokenizer/config.json.""" + """Optional AVAE config JSON describing the sound tokenizer architecture.""" include_sound_tokenizer: bool = False """Require saving sound_tokenizer/ even if the source transformer is video-only.""" - remap_sound_tokenizer_keys: bool = False - """Convert the legacy AVAE state dict into the diffusers OobleckDecoder - layout (strips wrapper prefixes, drops encoder/bottleneck keys, remaps the - flat `nn.Sequential` decoder to named attributes, reshapes Snake1d - alpha/beta, and reconstructs `weight_g` / `weight_v` for folded conv - weights). When enabled, the saved file is `diffusion_pytorch_model.safetensors` - instead of `model.safetensors`.""" - remap_time_embedder_keys: bool = False - """Remap the transformer's `time_embedder` state dict from the legacy - `nn.Sequential` layout (`mlp.0.*` / `mlp.2.*`) to the diffusers - `TimestepEmbedding` layout (`linear_1.*` / `linear_2.*`). Off by default — - keys are forwarded verbatim.""" vision_encoder_model: str = DEFAULT_VISION_ENCODER_MODEL """Qwen3-VL model/config to instantiate model.visual.* weights.""" skip_vision_encoder: bool = False @@ -548,10 +594,11 @@ def convert_model_to_diffusers(args: Args) -> None: vae2llm = _tmp.net.vae2llm llm2vae = _tmp.net.llm2vae time_embedder = _tmp.net.time_embedder - lm_cfg = _tmp.net.language_model.config + # The language model may carry a nested VL config (e.g. Qwen3VLConfig); + # the text-model fields read below live on its text config. + lm_cfg = _tmp.net.language_model.config.get_text_config() net_cfg = _tmp.net.config model_cfg = _tmp.config - vlm_cfg = _tmp.net.config.vlm_config patch_latent_dim = _tmp.net.patch_latent_dim hidden_size = _tmp.net.hidden_size num_attention_heads = _tmp.net.num_heads @@ -561,17 +608,13 @@ def convert_model_to_diffusers(args: Args) -> None: latent_patch_size = _tmp.net.latent_patch_size latent_channel = _tmp.net.latent_channel timestep_scale = _tmp.net.timestep_scale - use_moe = _tmp.net.use_moe - joint_attn_implementation = net_cfg.joint_attn_implementation base_fps = int(net_cfg.base_fps) enable_fps_modulation = net_cfg.enable_fps_modulation max_action_dim = _tmp.config.max_action_dim - position_embedding_type = net_cfg.position_embedding_type unified_3d_mrope_reset_spatial_ids = _tmp.config.diffusion_expert_config.unified_3d_mrope_reset_spatial_ids unified_3d_mrope_temporal_modality_margin = ( _tmp.config.diffusion_expert_config.unified_3d_mrope_temporal_modality_margin ) - video_temporal_causal = net_cfg.video_temporal_causal action2llm = getattr(_tmp.net, "action2llm", None) llm2action = getattr(_tmp.net, "llm2action", None) action_modality_embed = getattr(_tmp.net, "action_modality_embed", None) @@ -598,9 +641,6 @@ def convert_model_to_diffusers(args: Args) -> None: if sound_dim is None and sound2llm is not None: sound_dim = sound2llm.in_features sound_latent_fps = _get_config_value(net_cfg, model_cfg, name="sound_latent_fps", default=25.0) - temporal_compression_factor_sound = _get_config_value( - net_cfg, model_cfg, name="temporal_compression_factor_sound", default=1 - ) if sound_gen: missing_sound_modules = [ name @@ -634,7 +674,9 @@ def convert_model_to_diffusers(args: Args) -> None: f"action projection weights: {missing_action_modules}." ) - has_vision_encoder_weights = _checkpoint_has_weight_prefix(checkpoint_path, VISION_ENCODER_CHECKPOINT_PREFIX) + has_vision_encoder_weights = _checkpoint_has_weight_prefix( + checkpoint_path, VISION_ENCODER_CHECKPOINT_PREFIX + ) or bool(_checkpoint_vision_subfolder_files(checkpoint_path)) vision_gen = bool( _get_config_value(net_cfg, model_cfg, name="vision_gen", default=False) or has_vision_encoder_weights ) @@ -653,66 +695,48 @@ def convert_model_to_diffusers(args: Args) -> None: attention_dropout=lm_cfg.attention_dropout, base_fps=base_fps, enable_fps_modulation=enable_fps_modulation, - freeze_und=vlm_cfg.freeze_und, head_dim=head_dim, - hidden_act=lm_cfg.hidden_act, hidden_size=hidden_size, - initializer_range=lm_cfg.initializer_range, intermediate_size=lm_cfg.intermediate_size, - joint_attn_implementation=joint_attn_implementation, latent_channel=latent_channel, latent_patch_size=latent_patch_size, action_dim=action_dim, action_gen=action_gen, - max_action_dim=max_action_dim, - max_position_embeddings=lm_cfg.max_position_embeddings, - model_type=lm_cfg.model_type, num_embodiment_domains=num_embodiment_domains, num_attention_heads=num_attention_heads, num_hidden_layers=num_hidden_layers, num_key_value_heads=num_key_value_heads, patch_latent_dim=patch_latent_dim, - position_embedding_type=position_embedding_type, - qk_norm_for_diffusion=True, - qk_norm_for_text=vlm_cfg.qk_norm_for_text, rms_norm_eps=lm_cfg.rms_norm_eps, rope_scaling=lm_cfg.rope_scaling, rope_theta=lm_cfg.rope_theta, sound_dim=sound_dim, sound_gen=sound_gen, sound_latent_fps=sound_latent_fps, - temporal_compression_factor_sound=temporal_compression_factor_sound, timestep_scale=timestep_scale, unified_3d_mrope_reset_spatial_ids=unified_3d_mrope_reset_spatial_ids, unified_3d_mrope_temporal_modality_margin=unified_3d_mrope_temporal_modality_margin, - use_cache=lm_cfg.use_cache, - use_moe=use_moe, - video_temporal_causal=video_temporal_causal, vocab_size=lm_cfg.vocab_size, ) - state_dict = language_model.state_dict() + state_dict = {_remap_language_model_key(k): v for k, v in language_model.state_dict().items()} for k, v in vae2llm.state_dict().items(): - state_dict[f"vae2llm.{k}"] = v + state_dict[f"proj_in.{k}"] = v for k, v in llm2vae.state_dict().items(): - state_dict[f"llm2vae.{k}"] = v - time_embedder_state = time_embedder.state_dict() - if args.remap_time_embedder_keys: - log.info("Remapping transformer time_embedder state dict to diffusers TimestepEmbedding layout …") - time_embedder_state = _remap_time_embedder_state_dict(time_embedder_state) - for k, v in time_embedder_state.items(): - state_dict[f"time_embedder.{k}"] = v + state_dict[f"proj_out.{k}"] = v + for k, v in time_embedder.state_dict().items(): + state_dict[f"time_embedder.{_TIME_EMBEDDER_KEY_REMAP[k]}"] = v if action_gen: for k, v in action2llm.state_dict().items(): - state_dict[f"action2llm.{k}"] = v + state_dict[f"action_proj_in.{k}"] = v for k, v in llm2action.state_dict().items(): - state_dict[f"llm2action.{k}"] = v + state_dict[f"action_proj_out.{k}"] = v state_dict["action_modality_embed"] = action_modality_embed if sound_gen: for k, v in sound2llm.state_dict().items(): - state_dict[f"sound2llm.{k}"] = v + state_dict[f"audio_proj_in.{k}"] = v for k, v in llm2sound.state_dict().items(): - state_dict[f"llm2sound.{k}"] = v - state_dict["sound_modality_embed"] = sound_modality_embed + state_dict[f"audio_proj_out.{k}"] = v + state_dict["audio_modality_embed"] = sound_modality_embed transformer.load_state_dict(state_dict, strict=True, assign=True) del ( language_model, @@ -748,6 +772,10 @@ def convert_model_to_diffusers(args: Args) -> None: "Wan-AI/Wan2.2-TI2V-5B-Diffusers", subfolder="vae", torch_dtype=torch.bfloat16 ) + sound_tokenizer = None + if include_sound_tokenizer: + sound_tokenizer = _build_sound_tokenizer(sound_tokenizer_path, sound_tokenizer_config_path) + # Karras schedule approximating FlowUniPCMultistepScheduler with shift=5, 35 steps. # Measured from that schedule: first flow-sigma=0.9998, last flow-sigma=0.1281. # EDM sigma = flow_sigma / (1 - flow_sigma), so: @@ -762,23 +790,25 @@ def convert_model_to_diffusers(args: Args) -> None: sigma_min=0.147, ) - pipeline = Cosmos3OmniDiffusersPipeline( + # enable_safety_checker=False: constructing the checker imports + # cosmos_guardrail, which the converter environment does not ship. + # Consumers can opt back in at load time via + # `Cosmos3OmniPipeline.from_pretrained(..., enable_safety_checker=True)`. + pipeline = Cosmos3OmniPipeline( transformer=transformer, text_tokenizer=text_tokenizer, vae=diffusers_vae, scheduler=scheduler, - vision_encoder=vision_encoder, + sound_tokenizer=sound_tokenizer, + enable_safety_checker=False, ) log.info(f"Saving full pipeline to {output_dir} …") pipeline.save_pretrained(str(output_dir), safe_serialization=True, max_shard_size="5GB") - if include_sound_tokenizer: - _save_sound_tokenizer( - output_dir, - sound_tokenizer_path, - sound_tokenizer_config_path, - remap_keys=args.remap_sound_tokenizer_keys, - ) - _add_sound_tokenizer_to_model_index(output_dir) + if vision_encoder is not None: + # Not a Cosmos3OmniPipeline component — saved as a sidecar folder for + # the transformers/vLLM consumers of the exported repository. + log.info(f"Saving Qwen3-VL vision encoder to {output_dir / 'vision_encoder'} …") + vision_encoder.save_pretrained(str(output_dir / "vision_encoder"), safe_serialization=True) else: log.info(f"Saving transformer to {output_dir} …") transformer.save_pretrained(str(output_dir), safe_serialization=True, max_shard_size="5GB") diff --git a/cosmos_framework/scripts/convert_model_to_diffusers.py b/cosmos_framework/scripts/convert_model_to_diffusers.py index 039a2c71..98aa328a 100644 --- a/cosmos_framework/scripts/convert_model_to_diffusers.py +++ b/cosmos_framework/scripts/convert_model_to_diffusers.py @@ -40,18 +40,6 @@ class Args(pydantic.BaseModel): config_only: bool = False """If True, only save config.""" - remap_sound_tokenizer_keys: bool = True - """If True, remap the legacy AVAE sound tokenizer state dict into the - diffusers OobleckDecoder layout (and save the result as - `diffusion_pytorch_model.safetensors`). Off by default — the sound - tokenizer is written verbatim under `model.safetensors`.""" - - remap_time_embedder_keys: bool = True - """If True, remap the transformer's `time_embedder` state dict from the - legacy `nn.Sequential` layout (`mlp.0.*` / `mlp.2.*`) to the diffusers - `TimestepEmbedding` layout (`linear_1.*` / `linear_2.*`). Off by default — - keys are forwarded verbatim.""" - class SafetensorsIndexMetadata(pydantic.BaseModel): total_size: int = 0 @@ -93,9 +81,17 @@ def convert_model_to_diffusers(args: Args): sound_tokenizer_dir, sound_tokenizer_name = model_dict["config"]["sound_tokenizer"]["avae_path"].rsplit("/", 1) sound_tokenizer_checkpoint = CheckpointConfig.maybe_from_uri(f"s3://bucket/{sound_tokenizer_dir}") assert sound_tokenizer_checkpoint is not None - sound_tokenizer_path = Path(sound_tokenizer_checkpoint.hf.download()) / sound_tokenizer_name + sound_tokenizer_local = Path(sound_tokenizer_checkpoint.hf.download()) + # HF-published checkpoints ship sound_tokenizer/ in the diffusers layout + # (config.json + diffusion_pytorch_model.safetensors), which the converter + # consumes directly; fall back to the legacy AVAE file pair named by the + # model config's avae_path. + sound_tokenizer_path = sound_tokenizer_local / "diffusion_pytorch_model.safetensors" + sound_tokenizer_config_path = sound_tokenizer_local / "config.json" + if not sound_tokenizer_path.is_file(): + sound_tokenizer_path = sound_tokenizer_local / sound_tokenizer_name + sound_tokenizer_config_path = sound_tokenizer_path.with_suffix(".json") assert sound_tokenizer_path.is_file(), f"Sound tokenizer checkpoint not found: {sound_tokenizer_path}" - sound_tokenizer_config_path = sound_tokenizer_path.with_suffix(".json") assert sound_tokenizer_config_path.is_file(), f"Sound tokenizer config not found: {sound_tokenizer_config_path}" vision_encoder_model = model_dict["config"]["vlm_config"]["tokenizer"]["pretrained_model_name"] @@ -116,8 +112,6 @@ def convert_model_to_diffusers(args: Args): sound_tokenizer_path=str(sound_tokenizer_path), sound_tokenizer_config_path=str(sound_tokenizer_config_path), include_sound_tokenizer=True, - remap_sound_tokenizer_keys=args.remap_sound_tokenizer_keys, - remap_time_embedder_keys=args.remap_time_embedder_keys, vision_encoder_model=vision_encoder_model, skip_vision_encoder=False, ) diff --git a/docs/code_structure.md b/docs/code_structure.md index 3c7ecd39..25e72f1b 100644 --- a/docs/code_structure.md +++ b/docs/code_structure.md @@ -38,7 +38,7 @@ Cosmos/ │ ├── inference/ # Inference subpackage (model, args, defaults, Ray serving, common helpers, SFT experiment configs) │ └── ... # Training-infra subpackages: data, model, trainer, callbacks, checkpoint, … │ └── scripts/ # CLI entry-point scripts: train.py, _train.py, inference.py, export_model.py, … -├── packages/ # Backend shim packages: diffusers-cosmos3, transformers-cosmos3, vllm-cosmos3 +├── packages/ # Backend shim packages: transformers-cosmos3, vllm-cosmos3 ├── docs/ # User documentation (you are here) ├── docker/ # Dockerfiles for reproducible environments ├── examples/ # Runnable training / fine-tuning / inference examples @@ -49,7 +49,7 @@ Cosmos/ └── .python-version # Python version pin (used by uv) ``` -`cosmos_framework/` is the single Python package. Training infrastructure (data, model, trainer, callbacks, checkpoint, utils, …) lives in top-level subpackages; inference (Diffusers / Transformers / vLLM-friendly inference core, Ray serving, per-modality defaults, training-side experiment YAMLs) lives under `cosmos_framework/inference/`. The library-style backend shims that load Cosmos3 checkpoints into upstream ecosystems live under `packages/{diffusers,transformers,vllm}-cosmos3/`. +`cosmos_framework/` is the single Python package. Training infrastructure (data, model, trainer, callbacks, checkpoint, utils, …) lives in top-level subpackages; inference (Diffusers / Transformers / vLLM-friendly inference core, Ray serving, per-modality defaults, training-side experiment YAMLs) lives under `cosmos_framework/inference/`. The library-style backend shims that load Cosmos3 checkpoints into upstream ecosystems live under `packages/{transformers,vllm}-cosmos3/` (Diffusers needs no shim: diffusers ≥ 0.39 ships `Cosmos3OmniPipeline` natively). ## The `cosmos_framework/` Package @@ -154,7 +154,7 @@ The full inference subpackage: Training-side experiment SKUs live separately at `cosmos_framework/configs/base/experiment/sft/*.py` (see [`cosmos_framework/configs/`](#cosmos_frameworkconfigs)) — not under `inference/`. -Library-style backend shims that adapt Cosmos3 checkpoints to the Diffusers / Transformers / vLLM ecosystems live separately under `packages/{diffusers,transformers,vllm}-cosmos3/`. +Library-style backend shims that adapt Cosmos3 checkpoints to the Transformers / vLLM ecosystems live separately under `packages/{transformers,vllm}-cosmos3/`. Diffusers needs no shim: diffusers ≥ 0.39 ships `Cosmos3OmniPipeline` / `Cosmos3OmniTransformer` natively. ### `cosmos_framework/launcher/` @@ -197,7 +197,7 @@ Add new worker types as sibling subpackages — each owns its own startup, messa - `examples/` — runnable end-to-end examples; see `examples/README.md`. - `docker/` — Dockerfiles and image build helpers; see `docker/README.md`. - `cosmos_framework/scripts/` — CLI entry-point scripts (`train.py`, `inference.py`, `export_model.py`, …); invoke as `python -m cosmos_framework.scripts.`. Primary training entry point: `cosmos_framework.scripts.train` driven by a structured, pydantic-validated TOML interface (`--sft-toml=`); recipe TOMLs live under [`examples/toml/sft_config/`](../examples/toml/sft_config/) and the schema is defined in [`cosmos_framework/configs/toml_config/sft_config.py`](../cosmos_framework/configs/toml_config/sft_config.py) — see [`examples/README.md`](../examples/README.md) and [`docs/training.md`](./training.md). -- `packages/` — library-style backend shims: `packages/{diffusers,transformers,vllm}-cosmos3/`, each installable independently. +- `packages/` — library-style backend shims: `packages/{transformers,vllm}-cosmos3/`, each installable independently. ## Where to Add New Code diff --git a/packages/diffusers-cosmos3/README.md b/packages/diffusers-cosmos3/README.md deleted file mode 100644 index c97fcc6e..00000000 --- a/packages/diffusers-cosmos3/README.md +++ /dev/null @@ -1 +0,0 @@ -# Cosmos3 diffusers Plugin diff --git a/packages/diffusers-cosmos3/diffusers_cosmos3/__init__.py b/packages/diffusers-cosmos3/diffusers_cosmos3/__init__.py deleted file mode 100644 index df9abed7..00000000 --- a/packages/diffusers-cosmos3/diffusers_cosmos3/__init__.py +++ /dev/null @@ -1,17 +0,0 @@ -# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: OpenMDW-1.1 - -import diffusers - -from .pipeline import Cosmos3OmniDiffusersPipeline -from .transformer import Cosmos3OmniTransformer - -# Spoof the eventual upstream module paths so save_pretrained writes -# "diffusers" as the library in model_index.json. -Cosmos3OmniTransformer.__module__ = "diffusers.models.transformers.transformer_cosmos3" -Cosmos3OmniDiffusersPipeline.__module__ = "diffusers.pipelines.cosmos.pipeline_cosmos3_omni" - -# Loader does `getattr(importlib.import_module(library), class_name)`, -# so the class must be reachable as `diffusers.`. -diffusers.Cosmos3OmniTransformer = Cosmos3OmniTransformer -diffusers.Cosmos3OmniDiffusersPipeline = Cosmos3OmniDiffusersPipeline diff --git a/packages/diffusers-cosmos3/diffusers_cosmos3/pipeline.py b/packages/diffusers-cosmos3/diffusers_cosmos3/pipeline.py deleted file mode 100644 index d514f3e8..00000000 --- a/packages/diffusers-cosmos3/diffusers_cosmos3/pipeline.py +++ /dev/null @@ -1,1124 +0,0 @@ -# Copyright 2025 The NVIDIA Team and The HuggingFace Team. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import json -import math -from pathlib import Path -from typing import List, Optional, Tuple, Union - -import numpy as np -import torch -import torchvision.transforms.functional as TF -from diffusers.models.autoencoders.autoencoder_kl_wan import AutoencoderKLWan -from diffusers.pipelines.pipeline_utils import DiffusionPipeline -from diffusers.schedulers import UniPCMultistepScheduler -from diffusers.utils.torch_utils import randn_tensor -from einops import rearrange -from tqdm import tqdm -from transformers import AutoTokenizer - -from diffusers_cosmos3.sequence_packing import ( - GenerationDataClean, - SequencePlan, - build_packed_sequence, - build_sequence_plans_from_data_batch, - get_all_seq, - pack_input_sequence, -) -from diffusers_cosmos3.transformer import ( - Cosmos3OmniTransformer, -) - -_SYSTEM_PROMPT_IMAGE = "You are a helpful assistant who will generate images from a give prompt." -_SYSTEM_PROMPT_VIDEO = "You are a helpful assistant who will generate videos from a give prompt." - - -def save_img_or_video(sample, save_fp_wo_ext, fps=24, quality=10, ffmpeg_params=None, **kwargs): - # TODO: remove this function and use diffusers-style vidoe processor - # However, it may cause numerical differences in the saved video, so we keep it for now for exact reproducibility of saved videos. - import imageio - from PIL import Image as PILImage - - assert sample.ndim == 4, "Only support 4D tensor" - - if torch.is_floating_point(sample): - sample = sample.clamp(0, 1) - else: - assert sample.dtype == torch.uint8, "Only support uint8 tensor" - sample = sample.float().div(255) - - if sample.shape[1] == 1: - save_obj = PILImage.fromarray( - rearrange((sample.cpu().float().numpy() * 255), "c 1 h w -> h w c").astype(np.uint8), - mode="RGB", - ) - save_obj.save(f"{save_fp_wo_ext}.jpg", format="JPEG", quality=85 if quality is None else quality) - else: - frames = rearrange((sample.cpu().float().numpy() * 255), "c t h w -> t h w c").astype(np.uint8) - h, w = frames.shape[1], frames.shape[2] - out_ffmpeg_params = ffmpeg_params if ffmpeg_params is not None else ["-s", f"{w}x{h}"] - imageio.mimsave( - f"{save_fp_wo_ext}.mp4", - frames, - fps=fps, - quality=quality, - macro_block_size=1, - ffmpeg_params=out_ffmpeg_params, - output_params=["-f", "mp4"], - ) - - -class DiffusersWan22VAE: - """ - Drop-in replacement for Wan2pt2VAEInterface, backed by AutoencoderKLWan. - - Bridges the following interface differences: - - 1. encode – AutoencoderKLWan returns AutoencoderKLOutput(latent_dist= - DiagonalGaussianDistribution); we extract .mode() and apply the same - (μ - mean) * inv_std normalization that WanVAE does internally. - - 2. decode – AutoencoderKLWan expects un-normalized z and returns - DecoderOutput(sample=…); we invert the normalization before calling - decode and unwrap the result to a plain tensor. - - 3. spatial/temporal_compression_factor properties – AutoencoderKLWan - stores these as config.scale_factor_spatial / scale_factor_temporal - and exposes spatial_compression_ratio (not *_factor). - - Note: AutoencoderKLWan._decode() clamps the output to [-1, 1]; - Wan2pt2VAEInterface does not. The pipeline applies .clamp(0, 1) after - decode so this difference does not affect saved videos. - - Numerical equivalence requirements (needed for bitwise-identical output - vs Wan2pt2VAEInterface): - - - No torch.amp.autocast: Wan2pt2VAEInterface constructs WanVAE with - is_amp=False, so the encoder/decoder run as pure bfloat16 with no - autocast context. Wrapping calls in autocast changes how ops such as - F.normalize accumulate internally and breaks the match. - - - mean / inv_std must be initialised directly in `dtype` (bfloat16). - WanVAE.__init__ does: - self.std = torch.tensor(std, dtype=bfloat16) - self.scale = [self.mean, 1.0 / self.std] # division in bfloat16 - Computing 1/std in float32 and then casting to bfloat16 can yield - different bit patterns, so we must perform the division in bfloat16 - from the start. - """ - - def __init__(self, vae: AutoencoderKLWan, dtype: torch.dtype = torch.bfloat16): - self.vae = vae - self.dtype = dtype - # Initialise in `dtype` so 1/std is computed in bfloat16, matching WanVAE. - mean = torch.tensor(vae.config.latents_mean, dtype=dtype) - std = torch.tensor(vae.config.latents_std, dtype=dtype) - self._mean = mean # [z_dim] - self._inv_std = 1.0 / std # [z_dim] - - @torch.no_grad() - def encode(self, x: torch.Tensor) -> torch.Tensor: - """[B,3,T,H,W] -> [B,z_dim,T//4,H//16,W//16] (normalized μ, matching Wan2pt2VAEInterface)""" - in_dtype = x.dtype - device = x.device - mean = self._mean.to(device=device, dtype=self.dtype) - inv_std = self._inv_std.to(device=device, dtype=self.dtype) - # No autocast — mirrors WanVAE(is_amp=False), pure bfloat16 forward pass. - raw_mu = self.vae.encode(x.to(self.dtype)).latent_dist.mode() - normalized = (raw_mu - mean.view(1, -1, 1, 1, 1)) * inv_std.view(1, -1, 1, 1, 1) - return normalized.to(in_dtype) - - @torch.no_grad() - def decode(self, z: torch.Tensor) -> torch.Tensor: - """[B,z_dim,T_lat,H_lat,W_lat] -> [B,3,T,H,W]""" - in_dtype = z.dtype - device = z.device - mean = self._mean.to(device=device, dtype=self.dtype) - inv_std = self._inv_std.to(device=device, dtype=self.dtype) - z_raw = z.to(self.dtype) / inv_std.view(1, -1, 1, 1, 1) + mean.view(1, -1, 1, 1, 1) - # No autocast — mirrors WanVAE(is_amp=False), pure bfloat16 forward pass. - out = self.vae.decode(z_raw).sample - return out.to(in_dtype) - - @property - def spatial_compression_factor(self) -> int: - return self.vae.config.scale_factor_spatial - - @property - def temporal_compression_factor(self) -> int: - return self.vae.config.scale_factor_temporal - - -class Cosmos3OmniDiffusersPipeline(DiffusionPipeline): - _optional_components = ["vision_encoder"] - model_cpu_offload_seq = "transformer" - - def __init__( - self, - transformer: Cosmos3OmniTransformer, - text_tokenizer: AutoTokenizer, - vae: AutoencoderKLWan, - scheduler: UniPCMultistepScheduler, - vision_encoder=None, - ): - super().__init__() - self.register_modules( - transformer=transformer, - text_tokenizer=text_tokenizer, - vae=vae, - scheduler=scheduler, - vision_encoder=vision_encoder, - ) - # Plain attribute (not registered): registering the wrapper would cause save_pretrained to call - # wrapper.save_pretrained(), which fails since DiffusersWan22VAE has no such method. - self.vision_tokenizer = DiffusersWan22VAE(vae) - - self.llm_special_tokens = { - "start_of_generation": text_tokenizer.convert_tokens_to_ids("<|vision_start|>"), - "end_of_generation": text_tokenizer.convert_tokens_to_ids("<|vision_end|>"), - "eos_token_id": text_tokenizer.eos_token_id, - } - - def tokenize_caption( - self, - caption: str, - is_video: bool = False, - use_system_prompt: bool = False, - ) -> list[int]: - """Tokenize a text caption into token IDs using the Qwen2 chat template. - Returns: - List of token IDs representing the full chat-formatted caption. - """ - conversations = [] - # Optionally prepend a system prompt that tells the model whether it is generating - # an image or a video. This changes the conditioning context for the LLM. - if use_system_prompt: - _system_prompt = _SYSTEM_PROMPT_VIDEO if is_video else _SYSTEM_PROMPT_IMAGE - conversations.append({"role": "system", "content": _system_prompt}) - conversations.append({"role": "user", "content": caption}) - - tokenizer_output = self.text_tokenizer.apply_chat_template( - conversations, - tokenize=True, - add_generation_prompt=True, - add_vision_id=False, - ) - return tokenizer_output - - def apply_timestep_embeds_to_noisy_tokens( - self, - packed_tokens: torch.Tensor, - packed_timestep_embeds: torch.Tensor, - noisy_frame_indexes: List[torch.Tensor], - token_shapes: list[tuple[int, ...]], - ) -> torch.Tensor: - start_noisy_index = 0 - flattened_noisy_frame_indexes = [] - for noisy_indexes_i, token_shape_i in zip(noisy_frame_indexes, token_shapes): - assert noisy_indexes_i.numel() <= token_shape_i[0] - spatial_numel_i = math.prod(token_shape_i[1:]) - spatial_indexes_i = torch.arange(spatial_numel_i, device=packed_tokens.device) - noisy_indexes_i = (noisy_indexes_i * spatial_numel_i).unsqueeze(-1).expand(-1, spatial_numel_i) - noisy_indexes_i = noisy_indexes_i.clone() + spatial_indexes_i + start_noisy_index - flattened_noisy_frame_indexes.append(noisy_indexes_i.flatten()) - start_noisy_index += math.prod(token_shape_i) - flattened_noisy_frame_indexes = torch.cat(flattened_noisy_frame_indexes, dim=0) - assert packed_tokens.dim() == 2 - assert packed_timestep_embeds.dim() == 2 - assert packed_timestep_embeds.shape[1] == packed_tokens.shape[1] - assert packed_timestep_embeds.shape[0] <= packed_tokens.shape[0] - assert flattened_noisy_frame_indexes.dim() == 1 - assert flattened_noisy_frame_indexes.shape[0] == packed_timestep_embeds.shape[0] - flattened_noisy_frame_indexes = flattened_noisy_frame_indexes.unsqueeze(-1).expand( - -1, - packed_tokens.shape[1], - ) - return packed_tokens.scatter_add( - dim=0, - index=flattened_noisy_frame_indexes, - src=packed_timestep_embeds, - ) - - def patchify_and_pack_latents( - self, - latent_patch_size: int, - latent_channel: int, - tokens_vision: torch.Tensor, - token_shapes_vision: List[Tuple[int, int, int]], - ) -> tuple[torch.Tensor, List[Tuple[int, int, int]]]: - p = latent_patch_size - packed_latent = [] - original_latent_shapes = [] - for latent, (t, h, w) in zip(tokens_vision, token_shapes_vision): - latent = latent.squeeze(0) # [C,T,H,W] - _, t_actual, h_actual, w_actual = latent.shape - original_latent_shapes.append((t_actual, h_actual, w_actual)) - h_padded = ((h_actual + p - 1) // p) * p - w_padded = ((w_actual + p - 1) // p) * p - if h_padded != h_actual or w_padded != w_actual: - padded = torch.zeros( - (latent_channel, t_actual, h_padded, w_padded), - device=latent.device, - dtype=latent.dtype, - ) - padded[:, :, :h_actual, :w_actual] = latent - latent = padded - h_patches = h_padded // p - w_patches = w_padded // p - latent = latent.reshape(latent_channel, t_actual, h_patches, p, w_patches, p) - latent = torch.einsum("cthpwq->thwpqc", latent).reshape(-1, p * p * latent_channel) - packed_latent.append(latent) - return torch.cat(packed_latent, dim=0), original_latent_shapes - - def unpatchify_and_unpack_latents( - self, - latent_patch_size: int, - latent_channel: int, - packed_mse_preds: torch.Tensor, - token_shapes_vision: List[Tuple[int, int, int]], - noisy_frame_indexes_vision: list[torch.Tensor], - original_latent_shapes: List[Tuple[int, int, int]] | None = None, - ) -> list[torch.Tensor]: - p = latent_patch_size - unpatchified_latents = [] - start_idx = 0 - for i, (t_c, h_c, w_c) in enumerate(token_shapes_vision): - if original_latent_shapes is not None: - t_orig, h_orig, w_orig = original_latent_shapes[i] - h_padded = ((h_orig + p - 1) // p) * p - w_padded = ((w_orig + p - 1) // p) * p - h_patches = h_padded // p - w_patches = w_padded // p - else: - t_orig, h_orig, w_orig = t_c, h_c * p, w_c * p - h_patches, w_patches = h_c, w_c - noisy_frame_indexes = noisy_frame_indexes_vision[i] - t_n = len(noisy_frame_indexes) - output_tensor = torch.zeros( - (latent_channel, t_c, h_orig, w_orig), - device=packed_mse_preds.device, - dtype=packed_mse_preds.dtype, - ) - num_patches = t_n * h_patches * w_patches - if num_patches > 0: - end_idx = start_idx + num_patches - latent_patches = packed_mse_preds[start_idx:end_idx] - latent_patches = latent_patches.reshape(t_n, h_patches, w_patches, p, p, latent_channel) - latent = torch.einsum("thwpqc->cthpwq", latent_patches) - latent = latent.reshape(latent_channel, t_n, h_patches * p, w_patches * p) - latent = latent[:, :, :h_orig, :w_orig] - output_tensor[:, noisy_frame_indexes] = latent - start_idx = end_idx - unpatchified_latents.append(output_tensor.unsqueeze(0)) - return unpatchified_latents - - def decode_vision( - self, - patch_latent_dim: int, - latent_patch_size: int, - latent_channel: int, - packed_seq, - last_hidden_state: torch.Tensor, - original_latent_shapes: List[Tuple[int, int, int]] | None = None, - ) -> list[torch.Tensor]: - """Decode vision predictions from last_hidden_state. Returns preds_vision list.""" - vision = packed_seq.vision - has_noisy_vision = ( - vision is not None - and vision.tokens is not None - and isinstance(vision.mse_loss_indexes, torch.Tensor) - and vision.mse_loss_indexes.numel() > 0 - ) - if not has_noisy_vision: - preds_vision = torch.zeros( - [1, patch_latent_dim], device=last_hidden_state.device, dtype=last_hidden_state.dtype - ) - preds_vision = self.transformer.proj_in(preds_vision) - preds_vision = self.transformer.proj_out(preds_vision) - if vision is not None and vision.tokens is not None: - preds_vision_list = [torch.zeros_like(tok) for tok in vision.tokens] - preds_vision_list[0] = preds_vision_list[0] + 0.0 * preds_vision.sum() - else: - preds_vision_list = [preds_vision] - else: - assert vision is not None - assert isinstance(vision.mse_loss_indexes, torch.Tensor) - assert vision.noisy_frame_indexes is not None - preds_vision = self.transformer.proj_out(last_hidden_state[vision.mse_loss_indexes]) - preds_vision_list = self.unpatchify_and_unpack_latents( - latent_patch_size, - latent_channel, - preds_vision, - token_shapes_vision=vision.token_shapes, - noisy_frame_indexes_vision=vision.noisy_frame_indexes, - original_latent_shapes=original_latent_shapes, - ) - return preds_vision_list - - def normalize_video_databatch_inplace( - self, - input_video_key: str, - data_batch: dict, - input_key: str | None = None, - device: str = "cuda", - dtype: torch.dtype = torch.bfloat16, - ) -> None: - input_key = input_video_key if input_key is None else input_key - if input_key in data_batch: - if data_batch.get("is_preprocessed", False) is True: - for i in range(len(data_batch[input_key])): - assert torch.is_floating_point(data_batch[input_key][i]) - assert torch.all((data_batch[input_key][i] >= -1.0001) & (data_batch[input_key][i] <= 1.0001)) - else: - for i in range(len(data_batch[input_key])): - item = data_batch[input_key][i] - if isinstance(item, torch.Tensor): - item = [item] - assert item[0].dtype == torch.uint8 - data_batch[input_key][i] = torch.stack(item).to(device=device, dtype=dtype) / 127.5 - 1.0 - data_batch["is_preprocessed"] = True - - def augment_image_dim_inplace( - self, - input_image_key: str, - data_batch: dict, - input_key: str | None = None, - device: str = "cuda", - dtype: torch.dtype = torch.bfloat16, - ) -> None: - input_key = input_image_key if input_key is None else input_key - if input_key in data_batch: - if data_batch.get("is_preprocessed", False) is True: - for i in range(len(data_batch[input_key])): - assert data_batch[input_key][i].shape[2] == 1 - return - else: - new_image_tensor_list = [] - for i in range(len(data_batch[input_key])): - for img_tensor in data_batch[input_key][i]: - img_tensor = rearrange(img_tensor, "c h w -> 1 c 1 h w").contiguous() - if img_tensor.dtype == torch.uint8: - img_tensor = img_tensor.to(device=device, dtype=dtype) / 127.5 - 1.0 - new_image_tensor_list.append(img_tensor) - data_batch[input_key] = new_image_tensor_list - data_batch["is_preprocessed"] = True - - def remove_padding_from_latent( - self, - spatial_compression_factor: int, - x0_tokens_vision: list[torch.Tensor], - frame_size: list[torch.Tensor], - ) -> list[torch.Tensor]: - cropped_latents = [] - for i in range(len(x0_tokens_vision)): - fs = frame_size[i] - if fs.dim() == 2: - fs = fs[0] - orig_h = int(fs[2].item()) - orig_w = int(fs[3].item()) - orig_h_latent = orig_h // spatial_compression_factor - orig_w_latent = orig_w // spatial_compression_factor - cropped_latents.append(x0_tokens_vision[i][:, :, :, :orig_h_latent, :orig_w_latent].contiguous()) - return cropped_latents - - def get_data_and_condition( - self, - input_image_key: str, - input_video_key: str, - data_batch: dict, - device: str = "cuda", - dtype: torch.dtype = torch.bfloat16, - ) -> GenerationDataClean: - assert (input_image_key in data_batch) != (input_video_key in data_batch) - is_img = input_image_key in data_batch - sample_vision_list = data_batch[input_image_key if is_img else input_video_key] - - if "num_vision_items_per_sample" not in data_batch: - has_multiple_vision_per_sample = any( - isinstance(v, (list, tuple)) and len(v) > 1 for v in sample_vision_list - ) - num_vision_items_per_sample: list[int] | None = ( - [len(v) for v in sample_vision_list] if has_multiple_vision_per_sample else None - ) - data_batch["num_vision_items_per_sample"] = num_vision_items_per_sample - if has_multiple_vision_per_sample: - media_key = input_video_key if not is_img else input_image_key - data_batch[media_key] = [item.unsqueeze(0) for sublist in sample_vision_list for item in sublist] - if data_batch[media_key][0].dtype == torch.float32 and not is_img: - data_batch["is_preprocessed"] = True - else: - num_vision_items_per_sample = data_batch["num_vision_items_per_sample"] - - batch_size = ( - len(sample_vision_list) if num_vision_items_per_sample is None else len(num_vision_items_per_sample) - ) - - self.normalize_video_databatch_inplace(input_video_key, data_batch, device=device, dtype=dtype) - self.augment_image_dim_inplace(input_image_key, data_batch, device=device, dtype=dtype) - raw_state_vision = data_batch[input_image_key if is_img else input_video_key] - x0_tokens_vision = [ - self.vision_tokenizer.encode(raw_state_vision_i).contiguous().float() - for raw_state_vision_i in raw_state_vision - ] - - frame_size = data_batch.get("image_size", None) - if frame_size is not None: - x0_tokens_vision = self.remove_padding_from_latent( - self.vision_tokenizer.spatial_compression_factor, x0_tokens_vision, frame_size - ) - - fps_raw = data_batch.get("conditioning_fps", None) - if isinstance(fps_raw, list): - fps_raw = torch.stack(fps_raw).flatten() - fps_vision = fps_raw.to(device=device, dtype=dtype) if fps_raw is not None else None - - return GenerationDataClean( - batch_size=batch_size, - is_image_batch=is_img, - raw_state_vision=raw_state_vision, - x0_tokens_vision=x0_tokens_vision, - fps_vision=fps_vision, - num_vision_items_per_sample=num_vision_items_per_sample, - ) - - def get_inference_text_tokens( - self, use_system_prompt: bool, input_caption_key: str, data_batch: dict, has_negative_prompt: bool - ) -> tuple[list[list[int]], list[list[int]]]: - cond_tokens = [ - self.tokenize_caption(c, is_video=False, use_system_prompt=use_system_prompt) - for c in data_batch[input_caption_key] - ] - if has_negative_prompt: - neg_key = "neg_" + input_caption_key - assert neg_key in data_batch, f"Negative prompt ({neg_key}) not found" - uncond_captions = data_batch[neg_key] - else: - uncond_captions = [""] * len(cond_tokens) - uncond_tokens = [ - self.tokenize_caption(c, is_video=False, use_system_prompt=use_system_prompt) for c in uncond_captions - ] - return cond_tokens, uncond_tokens - - def derive_include_end_of_generation_token(self, joint_attn_implementation: str) -> bool: - assert joint_attn_implementation in ("flex", "two_way", "three_way") - return joint_attn_implementation == "flex" - - def prepare_inference_data( - self, - use_system_prompt: bool, - prompt: Union[str, List[str]], - negative_prompt: Optional[Union[str, List[str]]] = None, - image=None, - num_frames: int = 189, - height: int = 720, - width: int = 1280, - fps: float = 24.0, - condition_frame_indexes: Optional[List[int]] = None, - noises: Optional[List[torch.Tensor]] = None, - generator: Optional[torch.Generator] = None, - input_caption_key: str = "ai_caption", - input_video_key: str = "video", - input_image_key: str = "images", - device: str = "cuda", - dtype: torch.dtype = torch.bfloat16, - ) -> tuple[ - list[SequencePlan], - GenerationDataClean, - list[list[int]], - list[list[int]], - torch.Tensor, - ]: - # Build data_batch - prompts = [prompt] if isinstance(prompt, str) else list(prompt) - batch_size = len(prompts) - is_image = num_frames == 1 - - conditioning_frames = None - if image is not None: - conditioning_frames = self._load_image_as_tensor(image, height, width) - - image_size = [ - torch.tensor([[height, width, height, width]], dtype=torch.float32, device=device) - for _ in range(batch_size) - ] - - if is_image: - img_tensor = ( - conditioning_frames.unsqueeze(0).to(device=device, dtype=dtype) - if conditioning_frames is not None - else torch.zeros(1, 3, 1, height, width, dtype=dtype, device=device) - ) - seq_plans = [ - SequencePlan(has_text=True, has_vision=True, condition_frame_indexes_vision=[]) - for _ in range(batch_size) - ] - data_batch = { - input_image_key: [img_tensor] * batch_size, - "image_size": image_size, - "is_preprocessed": True, - "fps": torch.full((batch_size,), float(fps), device=device), - "conditioning_fps": torch.full((batch_size,), float(fps), device=device), - "num_frames": torch.full((batch_size,), num_frames, device=device), - "sequence_plan": seq_plans, - input_caption_key: prompts, - } - else: - cond_indexes = ( - condition_frame_indexes - if condition_frame_indexes is not None - else ([0] if conditioning_frames is not None else []) - ) - if conditioning_frames is not None: - video_data = torch.zeros(1, 3, num_frames, height, width, dtype=dtype) - t_fill = min(conditioning_frames.shape[1], num_frames) - video_data[0, :, :t_fill] = conditioning_frames[:, :t_fill].to(dtype=dtype) - if t_fill < num_frames: - video_data[0, :, t_fill:] = video_data[0, :, t_fill - 1 : t_fill].expand( - -1, num_frames - t_fill, -1, -1 - ) - video_tensor = video_data.to(device=device) - else: - video_tensor = torch.zeros(1, 3, num_frames, height, width, dtype=dtype, device=device) - seq_plans = [ - SequencePlan(has_text=True, has_vision=True, condition_frame_indexes_vision=list(cond_indexes)) - for _ in range(batch_size) - ] - data_batch = { - input_video_key: [video_tensor] * batch_size, - "image_size": image_size, - "is_preprocessed": True, - "fps": torch.full((batch_size,), float(fps), device=device), - "conditioning_fps": torch.full((batch_size,), float(fps), device=device), - "num_frames": torch.full((batch_size,), num_frames, device=device), - "sequence_plan": seq_plans, - input_caption_key: prompts, - } - - has_negative_prompt = negative_prompt is not None - if has_negative_prompt: - neg_prompts = [negative_prompt] if isinstance(negative_prompt, str) else list(negative_prompt) - data_batch["neg_" + input_caption_key] = neg_prompts - - sequence_plans = build_sequence_plans_from_data_batch( - data_batch=data_batch, - input_video_key=input_video_key, - input_image_key=input_image_key, - ) - gen_data_clean = self.get_data_and_condition( - input_image_key, input_video_key, data_batch, device=device, dtype=dtype - ) - num_items_per_sample = gen_data_clean.num_vision_items_per_sample - cond_text_tokens, uncond_text_tokens = self.get_inference_text_tokens( - use_system_prompt, input_caption_key, data_batch, has_negative_prompt - ) - - mask_timesteps = torch.zeros((gen_data_clean.batch_size,), dtype=torch.float32) - packed_seq = pack_input_sequence( - sequence_plans=sequence_plans, - input_text_indexes=cond_text_tokens, - gen_data_clean=gen_data_clean, - input_timesteps=mask_timesteps, - special_tokens=self.llm_special_tokens, - latent_patch_size=self.transformer.config.latent_patch_size, - include_end_of_generation_token=self.derive_include_end_of_generation_token( - self.transformer.config.joint_attn_implementation - ), - position_embedding_type=self.transformer.config.position_embedding_type, - unified_3d_mrope_reset_spatial_ids=self.transformer.config.unified_3d_mrope_reset_spatial_ids, - unified_3d_mrope_temporal_modality_margin=self.transformer.config.unified_3d_mrope_temporal_modality_margin, - enable_fps_modulation=self.transformer.config.enable_fps_modulation, - base_fps=float(self.transformer.config.base_fps), - temporal_compression_factor=self.vision_tokenizer.temporal_compression_factor, - video_temporal_causal=self.transformer.config.video_temporal_causal, - action_dim=self.transformer.config.max_action_dim, - ) - - assert packed_seq.vision is not None - assert packed_seq.vision.condition_mask is not None - assert isinstance(packed_seq.vision.condition_mask, list) - assert gen_data_clean.x0_tokens_vision is not None - - noise_vision_list: list[torch.Tensor] = [] - for i, (x0_token, cond_mask) in enumerate( - zip(gen_data_clean.x0_tokens_vision, packed_seq.vision.condition_mask, strict=True) - ): - if noises is not None: - pure_noise = noises[i].to(device=device, dtype=dtype) - else: - pure_noise = randn_tensor(tuple(x0_token.shape), generator=generator, device=device, dtype=dtype) - noise_vision_list.append( - cond_mask * x0_token.to(device=device, dtype=dtype) + (1.0 - cond_mask) * pure_noise - ) - - initial_noise = torch.cat([t.reshape(-1) for t in noise_vision_list]) - - return sequence_plans, gen_data_clean, cond_text_tokens, uncond_text_tokens, initial_noise - - def encode_text( - self, - hidden_size: int, - packed_seq, - ) -> tuple[torch.Tensor, torch.dtype]: - """Embed text tokens. Returns (hidden_states [N_total, H], target_dtype).""" - packed_text_embedding = self.transformer.embed_tokens(packed_seq.text_ids) # [N_text,H] - hidden_states = packed_text_embedding.new_zeros(size=(packed_seq.sequence_length, hidden_size)) - hidden_states[packed_seq.text_indexes] = packed_text_embedding - return hidden_states, packed_text_embedding.dtype - - def encode_vision( - self, - timestep_scale: float, - latent_patch_size: int, - latent_channel: int, - packed_seq, - hidden_states: torch.Tensor, - target_dtype: torch.dtype, - fps: Optional[torch.Tensor] = None, - ) -> List[Tuple[int, int, int]] | None: - """Project vision tokens into hidden_states in-place. Returns original_latent_shapes.""" - if packed_seq.vision is None or packed_seq.vision.tokens is None: - return None - vision = packed_seq.vision - assert vision.tokens is not None - assert vision.token_shapes is not None - assert isinstance(vision.sequence_indexes, torch.Tensor) - assert isinstance(vision.timesteps, torch.Tensor) - assert isinstance(vision.mse_loss_indexes, torch.Tensor) - - packed_tokens_vision, original_latent_shapes = self.patchify_and_pack_latents( - latent_patch_size, latent_channel, vision.tokens, vision.token_shapes - ) - packed_tokens_vision = self.transformer.proj_in(packed_tokens_vision) - - if vision.mse_loss_indexes.numel() > 0: - timesteps_vision = vision.timesteps * timestep_scale - with torch.autocast("cuda", enabled=True, dtype=torch.float32): - packed_timestep_embeds_vision = self.transformer.time_embedder(timesteps_vision) - packed_timestep_embeds_vision = packed_timestep_embeds_vision.to(target_dtype) - packed_tokens_vision = self.apply_timestep_embeds_to_noisy_tokens( - packed_tokens=packed_tokens_vision, - packed_timestep_embeds=packed_timestep_embeds_vision, - noisy_frame_indexes=vision.noisy_frame_indexes, - token_shapes=vision.token_shapes, - ) - - hidden_states[vision.sequence_indexes] = packed_tokens_vision - return original_latent_shapes - - @torch.no_grad() - def run_single( - self, - packed_seq, - noise_x_vision: list[torch.Tensor], - hidden_size: int, - latent_patch_size: int, - latent_channel: int, - patch_latent_dim: int, - timestep_scale: float, - num_heads: int, - head_dim: int, - num_hidden_layers: int, - use_moe: bool, - joint_attn_implementation: str, - fps_vision: Optional[torch.Tensor], - device: str = "cuda", - dtype: torch.dtype = torch.bfloat16, - ) -> list[torch.Tensor]: - """Inlined forward pass from Cosmos3VFMNetworkSimple.forward().""" - if packed_seq.vision is not None: - packed_seq.vision.tokens = [x.to(device=device, dtype=dtype) for x in noise_x_vision] - packed_seq.to_cuda() - - # 1. Encode text - hidden_states, target_dtype = self.encode_text(hidden_size, packed_seq) - - # 2. Encode vision - original_latent_shapes = self.encode_vision( - timestep_scale, - latent_patch_size, - latent_channel, - packed_seq, - hidden_states, - target_dtype, - fps=fps_vision, - ) - - # 3. Build attention metadata - assert use_moe - assert packed_seq.attn_modes is not None - assert packed_seq.split_lens is not None - all_gen_indexes = [] - if packed_seq.vision is not None: - assert packed_seq.vision.token_shapes is not None - assert isinstance(packed_seq.vision.sequence_indexes, torch.Tensor) - all_gen_indexes.append(packed_seq.vision.sequence_indexes) - vision_sequence_indexes = torch.cat(all_gen_indexes, dim=0) if all_gen_indexes else None - - input_pack, attention_meta, _ = build_packed_sequence( - joint_attn_implementation, - packed_sequence=hidden_states, - attn_modes=packed_seq.attn_modes, - split_lens=packed_seq.split_lens, - sample_lens=packed_seq.sample_lens, - packed_und_token_indexes=packed_seq.text_indexes, - packed_gen_token_indexes=vision_sequence_indexes, - num_heads=num_heads, - is_image_batch=packed_seq.is_image_batch, - head_dim=head_dim, - num_layers=num_hidden_layers, - token_shapes=packed_seq.vision.token_shapes, - natten_parameter_list=None, - cp_world_size=1, - video_temporal_causal=False, - vision_token_shapes=packed_seq.vision.token_shapes if packed_seq.vision else None, - action_token_shapes=None, - temporal_compression_factor_vision=self.vision_tokenizer.temporal_compression_factor, - null_action_supertokens=packed_seq.null_action_supertokens, - pad_for_cuda_graphs=False, - ) - - # 4. Run transformer - packed_outputs, _ = self.transformer( - input_pack, - attention_mask=attention_meta, - position_ids=packed_seq.position_ids, - dual_kv_cache=None, - frame_idx=None, - natten_metadata_list=None, - ) - last_hidden_state = get_all_seq(packed_outputs) - - # 5. Decode vision - return self.decode_vision( - patch_latent_dim, - latent_patch_size, - latent_channel, - packed_seq, - last_hidden_state, - original_latent_shapes, - ) - - @torch.no_grad() - def get_cfg_velocity( - self, - noise_x: torch.Tensor, - timestep: torch.Tensor, - guidance: float, - gen_data_clean: GenerationDataClean, - sequence_plans: list[SequencePlan], - cond_tokens: list[list[int]], - uncond_tokens: list[list[int]], - include_eog: bool, - hidden_size: int, - latent_patch_size: int, - latent_channel: int, - patch_latent_dim: int, - timestep_scale: float, - num_heads: int, - head_dim: int, - num_hidden_layers: int, - use_moe: bool, - joint_attn_implementation: str, - skip_text_tokens_for_cfg: bool = False, - normalize_cfg: bool = False, - device: str = "cuda", - dtype: torch.dtype = torch.bfloat16, - ) -> torch.Tensor: - torch.compiler.cudagraph_mark_step_begin() - assert timestep.ndim == 2 and timestep.shape == (1, 1) - - num_items = gen_data_clean.num_vision_items_per_sample - num_vis = num_items[0] if num_items is not None else 1 - - noise_x_vision: list[torch.Tensor] = [] - offset = 0 - for j in range(num_vis): - vision_shape = gen_data_clean.x0_tokens_vision[j].shape - vision_dim = int(torch.prod(torch.tensor(vision_shape))) - noise_x_vision.append(noise_x[offset : offset + vision_dim].reshape(vision_shape)) - offset += vision_dim - - gen_data_for_packing = GenerationDataClean( - batch_size=1, - is_image_batch=gen_data_clean.is_image_batch, - raw_state_vision=gen_data_clean.raw_state_vision, - x0_tokens_vision=noise_x_vision, - fps_vision=gen_data_clean.fps_vision, - num_vision_items_per_sample=num_items, - ) - - def _run_cond(text_tokens: list[list[int]], skip_text: bool) -> torch.Tensor: - packed_seq = pack_input_sequence( - sequence_plans=sequence_plans, - input_text_indexes=text_tokens, - gen_data_clean=gen_data_for_packing, - input_timesteps=timestep.cpu(), - special_tokens=self.llm_special_tokens, - latent_patch_size=self.transformer.config.latent_patch_size, - include_end_of_generation_token=include_eog, - skip_text_tokens=skip_text, - position_embedding_type=self.transformer.config.position_embedding_type, - unified_3d_mrope_reset_spatial_ids=self.transformer.config.unified_3d_mrope_reset_spatial_ids, - unified_3d_mrope_temporal_modality_margin=self.transformer.config.unified_3d_mrope_temporal_modality_margin, - enable_fps_modulation=self.transformer.config.enable_fps_modulation, - base_fps=float(self.transformer.config.base_fps), - temporal_compression_factor=self.vision_tokenizer.temporal_compression_factor, - video_temporal_causal=self.transformer.config.video_temporal_causal, - action_dim=self.transformer.config.max_action_dim, - ) - preds = self.run_single( - packed_seq, - noise_x_vision, - hidden_size, - latent_patch_size, - latent_channel, - patch_latent_dim, - timestep_scale, - num_heads, - head_dim, - num_hidden_layers, - use_moe, - joint_attn_implementation, - fps_vision=gen_data_clean.fps_vision, - device=device, - dtype=dtype, - ) - - assert packed_seq.vision is not None - assert packed_seq.vision.condition_mask is not None - assert isinstance(packed_seq.vision.condition_mask, list) - velocity_vision = [ - pred * (1.0 - m).to(dtype=pred.dtype, device=pred.device) - if (1.0 - m).sum() > 0 - else torch.zeros_like(pred) - for pred, m in zip(preds, packed_seq.vision.condition_mask) - ] - return torch.cat([v.reshape(-1) for v in velocity_vision]) - - cond_v = _run_cond(cond_tokens, False) - uncond_v = _run_cond(uncond_tokens, skip_text_tokens_for_cfg) - - v_pred = uncond_v + guidance * (cond_v - uncond_v) - - if normalize_cfg: - v_pred = v_pred * (torch.norm(cond_v) / (torch.norm(v_pred) + 1e-8)).clamp(min=0.0, max=1.0) - return v_pred - - def _load_image_as_tensor(self, image, target_h: int, target_w: int) -> torch.Tensor: - """Load image from PIL, path, URL, or tensor; returns [3, 1, H, W] in [-1, 1].""" - from PIL import Image as PILImage - - if isinstance(image, (str, Path)): - image_str = str(image) - if image_str.startswith("http://") or image_str.startswith("https://"): - import io - import urllib.request - - with urllib.request.urlopen(image_str) as resp: - img_bytes = resp.read() - pil_img = PILImage.open(io.BytesIO(img_bytes)).convert("RGB") - else: - with open(image_str, "rb") as f: - pil_img = PILImage.open(f).convert("RGB") - img_t = torch.from_numpy(np.array(pil_img)).permute(2, 0, 1).float() - elif hasattr(image, "convert"): # PIL.Image - img_t = torch.from_numpy(np.array(image.convert("RGB"))).permute(2, 0, 1).float() - elif isinstance(image, torch.Tensor): - img_t = image.float() - if img_t.dim() == 4: - img_t = img_t.squeeze(0) - # if already normalized to [-1, 1], skip the /127.5-1 step below - if img_t.max() <= 1.1: - img_4d = img_t.unsqueeze(0) - orig_h, orig_w = img_4d.shape[2], img_4d.shape[3] - scale = max(target_w / orig_w, target_h / orig_h) - resize_h = int(math.ceil(scale * orig_h)) - resize_w = int(math.ceil(scale * orig_w)) - img_4d = TF.resize(img_4d, [resize_h, resize_w]) - img_4d = TF.center_crop(img_4d, [target_h, target_w]) - return img_4d.squeeze(0).unsqueeze(1) - else: - raise TypeError(f"Unsupported image type: {type(image)}") - - img_4d = img_t.unsqueeze(0) # [1, 3, H, W] (uint8-range [0, 255]) - orig_h, orig_w = img_4d.shape[2], img_4d.shape[3] - scale = max(target_w / orig_w, target_h / orig_h) - resize_h = int(math.ceil(scale * orig_h)) - resize_w = int(math.ceil(scale * orig_w)) - img_4d = TF.resize(img_4d, [resize_h, resize_w]) - img_4d = TF.center_crop(img_4d, [target_h, target_w]) - img_4d = img_4d / 127.5 - 1.0 # normalize after resize, matching load_conditioning_image - return img_4d.squeeze(0).unsqueeze(1) # [3, 1, H, W] - - def _resolve_defaults_and_prompts( - self, - prompt: Union[str, List[str]], - negative_prompt: Optional[Union[str, List[str]]], - image, - num_frames: int, - fps: float, - height: int, - width: int, - ) -> tuple[float, int, float, Union[str, List[str]], Union[str, List[str]]]: - """Load modality defaults and apply duration/resolution templates to prompts. - - Returns (guidance, num_steps, shift, formatted_prompt, formatted_negative_prompt). - """ - model_mode = "image2video" if image is not None else "text2video" - defaults = json.loads((Path(__file__).parent / f"sample_args/{model_mode}.json").read_text()) - - guidance = float(defaults["guidance"]) - num_steps = int(defaults["num_steps"]) - shift = float(defaults["shift"]) - print(f"model_mode={model_mode!r}: guidance={guidance}, num_steps={num_steps}, shift={shift}") - - duration_template = defaults.get("duration_template") - resolution_template = defaults.get("resolution_template") - negative_prompt_base = defaults.get("negative_prompt", "") - keep_metadata = defaults.get("negative_prompt_keep_metadata", False) - - def _apply_templates(text: str) -> str: - if duration_template and num_frames > 1: - text = text.rstrip(".") + ". " + duration_template.format(duration=num_frames / fps, fps=fps) - if resolution_template: - text = text.rstrip(".") + ". " + resolution_template.format(height=height, width=width) - return text - - if isinstance(prompt, str): - prompt = _apply_templates(prompt) - else: - prompt = [_apply_templates(p) for p in prompt] - - if negative_prompt is None: - negative_prompt = _apply_templates(negative_prompt_base) if keep_metadata else negative_prompt_base - - return guidance, num_steps, shift, prompt, negative_prompt - - @torch.no_grad() - def decode_latents(self, vision_list: list[torch.Tensor]) -> list[torch.Tensor]: - """Decode latents to pixel tensors of shape [C, T, H, W] in [0, 1].""" - frames = [] - for vision_latent in vision_list: - vision = self.vision_tokenizer.decode(vision_latent.cuda()) # [1, C, T, H, W] - frames.append(((1.0 + vision) / 2).clamp(0, 1).squeeze(0)) - return frames - - @torch.no_grad() - def __call__( - self, - prompt: Union[str, List[str]], - negative_prompt: Optional[Union[str, List[str]]] = None, - image=None, - num_frames: int = 189, - height: int = 720, - width: int = 1280, - fps: float = 24.0, - condition_frame_indexes: Optional[List[int]] = None, - noises: Optional[List[torch.Tensor]] = None, - generator: Optional[torch.Generator] = None, - use_system_prompt: bool = False, - device: str = "cuda", - dtype: torch.dtype = torch.bfloat16, - output_type: str = "video", - ): - latent_patch_size = self.transformer.config.latent_patch_size - latent_channel = self.transformer.config.latent_channel - patch_latent_dim = self.transformer.config.patch_latent_dim - timestep_scale = self.transformer.config.timestep_scale - hidden_size = self.transformer.config.hidden_size - num_heads = self.transformer.config.num_attention_heads - head_dim = self.transformer.config.head_dim - num_hidden_layers = self.transformer.config.num_hidden_layers - use_moe = self.transformer.config.use_moe - joint_attn_implementation = self.transformer.config.joint_attn_implementation - - guidance, num_steps, shift, prompt, negative_prompt = self._resolve_defaults_and_prompts( - prompt, negative_prompt, image, num_frames, fps, height, width - ) - - sequence_plans, gen_data_clean, cond_tokens, uncond_tokens, initial_noise = self.prepare_inference_data( - use_system_prompt, - prompt=prompt, - negative_prompt=negative_prompt, - image=image, - num_frames=num_frames, - height=height, - width=width, - fps=fps, - condition_frame_indexes=condition_frame_indexes, - noises=noises, - generator=generator, - device=device, - dtype=dtype, - ) - - assert guidance != 1.0, "Guidance weight must be != 1.0" - - device = initial_noise.device - self.scheduler.set_timesteps(num_steps, device=device) - timesteps = self.scheduler.timesteps - # print(f"sigmas: first={self.scheduler.sigmas[0].item():.4f} last={self.scheduler.sigmas[-2].item():.4f}") - # print(f"timesteps: first={timesteps[0].item():.2f} last={timesteps[-1].item():.2f}") - # print(f"timestep_scale: {timestep_scale}") - # breakpoint() - latent = initial_noise - include_eog = self.derive_include_end_of_generation_token(joint_attn_implementation) - - # --- Denoising loop --- - print("Running generate_samples_from_batch …") - for timestep in tqdm(timesteps, desc="Denoising"): - velocity_pred = self.get_cfg_velocity( - latent, - timestep.reshape(1, 1), - guidance, - gen_data_clean, - sequence_plans, - cond_tokens, - uncond_tokens, - include_eog, - hidden_size, - latent_patch_size, - latent_channel, - patch_latent_dim, - timestep_scale, - num_heads, - head_dim, - num_hidden_layers, - use_moe, - joint_attn_implementation, - device=device, - dtype=dtype, - ) - latent = self.scheduler.step( - model_output=velocity_pred, - timestep=timestep, - sample=latent.unsqueeze(0), - return_dict=False, - )[0].squeeze(0) - - # --- Extract vision results --- - num_vision_items = gen_data_clean.num_vision_items_per_sample - n_vis = num_vision_items[0] if num_vision_items is not None else 1 - result_vision: list[torch.Tensor] = [] - offset = 0 - for j in range(n_vis): - vision_shape = gen_data_clean.x0_tokens_vision[j].shape - vision_dim = int(torch.prod(torch.tensor(vision_shape))) - if j == n_vis - 1: - result_vision.append(latent[offset : offset + vision_dim].reshape(vision_shape)) - offset += vision_dim - - if output_type == "latent": - return result_vision - return self.decode_latents(result_vision) diff --git a/packages/diffusers-cosmos3/diffusers_cosmos3/sequence_packing.py b/packages/diffusers-cosmos3/diffusers_cosmos3/sequence_packing.py deleted file mode 100644 index 658eb25f..00000000 --- a/packages/diffusers-cosmos3/diffusers_cosmos3/sequence_packing.py +++ /dev/null @@ -1,1626 +0,0 @@ -# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: OpenMDW-1.1 - -# Copied from cosmos3._src.vfm.datasets.sequence_packing - -import math -from dataclasses import dataclass, field -from typing import Any, Dict, List, Optional, Tuple - -import torch - - -@dataclass -class GenerationDataClean: - batch_size: int - is_image_batch: bool - raw_state_vision: Optional[List[torch.Tensor]] = None - x0_tokens_vision: Optional[List[torch.Tensor]] = None - fps_vision: Optional[torch.Tensor] = None - num_vision_items_per_sample: Optional[List[int]] = None - x0_tokens_action: Optional[List[torch.Tensor]] = None - fps_action: Optional[torch.Tensor] = None - action_domain_id: Optional[List[torch.Tensor]] = None - raw_action_dim: Optional[List[Optional[torch.Tensor]]] = None - x0_tokens_sound: Optional[List[torch.Tensor]] = None - fps_sound: Optional[torch.Tensor] = None - - -# "Fake" types for readability; everything is plain dict at runtime. -FactoredSequencePack = dict[str, Any] -JointSequencePack = dict[str, Any] -SequencePack = FactoredSequencePack | JointSequencePack - - -# ------------------------------------ -# Internal helpers -# ------------------------------------ - - -def _pad_to_N(N, x: torch.Tensor) -> torch.Tensor: - assert x.shape[0] <= N - padded = x.new_zeros((N, *x.shape[1:])) - padded[: x.shape[0]] = x - return padded - - -def _pad( - causal_seq: torch.Tensor, full_only_seq: torch.Tensor, max_causal_len: int, max_full_len: int -) -> tuple[torch.Tensor, torch.Tensor]: - causal_seq = _pad_to_N(max_causal_len, causal_seq) - full_only_seq = _pad_to_N(max_full_len, full_only_seq) - return causal_seq, full_only_seq - - -def _compute_mode_indices_and_offsets( - split_lens: list[int], - attn_modes: list[str], - mode: str, - device: torch.device, -) -> tuple[torch.Tensor, torch.Tensor]: - indices = [] - offsets = [0] - next_offset = 0 - start = 0 - for split_len, attn_mode in zip(split_lens, attn_modes): - if attn_mode == mode: - indices.extend(range(start, start + split_len)) - next_offset += split_len - offsets.append(next_offset) - start += split_len - return ( - torch.tensor(indices, dtype=torch.int32, device=device), - torch.tensor(offsets, dtype=torch.int32, device=device), - ) - - -def _init_sequence_pack( - sample_lens: list[int], - split_lens: list[int], - attn_modes: list[str], - device: torch.device, -) -> dict: - _max_sample_len = max(sample_lens) - _max_causal_len = max((split_lens[i] for i in range(len(split_lens)) if attn_modes[i] == "causal"), default=0) - _max_full_len = max((split_lens[i] for i in range(len(split_lens)) if attn_modes[i] == "full"), default=0) - sample_lens_cu = torch.tensor([0] + sample_lens, device=device, dtype=torch.int32) - _sample_offsets = torch.cumsum(sample_lens_cu, dim=0, dtype=torch.int32) - _causal_indices, _causal_seq_offsets = _compute_mode_indices_and_offsets(split_lens, attn_modes, "causal", device) - _full_indices, _full_only_seq_offsets = _compute_mode_indices_and_offsets(split_lens, attn_modes, "full", device) - return dict( - sample_offsets=_sample_offsets, - max_sample_len=_max_sample_len, - max_causal_len=_max_causal_len, - max_full_len=_max_full_len, - _causal_indices=_causal_indices, - _full_indices=_full_indices, - _causal_seq_offsets=_causal_seq_offsets, - _full_only_seq_offsets=_full_only_seq_offsets, - _num_causal_tokens=len(_causal_indices), - _num_full_tokens=len(_full_indices), - split_lens=split_lens, - attn_modes=attn_modes, - ) - - -def _find_non_causal_text_token_idx( - attn_modes: list[str], - split_lens: list[int], - und_token_indexes: list[int], -) -> list[int]: - out = [] - full_offset = 0 - packed_idx = 0 - und_token_set = set(und_token_indexes) - for attn_mode, split_len in zip(attn_modes, split_lens): - if attn_mode == "full": - for local_idx, split_idx in enumerate(range(packed_idx, packed_idx + split_len)): - if split_idx in und_token_set: - out.append(full_offset + local_idx) - full_offset += split_len - packed_idx += split_len - return out - - -def factored_from_joint_sequence( - packed_sequence: torch.Tensor, - attn_modes: list[str], - split_lens: list[int], - sample_lens: list[int], - packed_und_token_indexes: torch.Tensor, - packed_gen_token_indexes: torch.Tensor, - is_image_batch: bool = False, - cp_world_size: int = 1, - pad_for_cuda_graphs: bool = False, -) -> FactoredSequencePack: - non_causal_text_idxs = _find_non_causal_text_token_idx(attn_modes, split_lens, packed_und_token_indexes.tolist()) - assert len(non_causal_text_idxs) == 0, "non_causal_text_idxs should be empty" - assert sum(sample_lens) == packed_sequence.shape[0] - meta = _init_sequence_pack(sample_lens, split_lens, attn_modes, packed_sequence.device) - causal_seq = packed_sequence[meta["_causal_indices"]] - full_only_seq = packed_sequence[meta["_full_indices"]] - return { - **meta, - "max_num_tokens": sum(sample_lens), - "causal_seq": causal_seq, - "full_only_seq": full_only_seq, - "is_sharded": False, - } - - -class SplitInfo: - def __init__( - self, - split_lens: list[int], - attn_modes: list[str], - sample_lens: list[int], - actual_len: int, - ): - assert sum(sample_lens) == sum(split_lens) - max_causal_len = 0 - max_full_len = 0 - for split_len, attn_mode in zip(split_lens, attn_modes): - if attn_mode == "causal": - max_causal_len = max(max_causal_len, split_len) - elif attn_mode == "full": - max_full_len = max(max_full_len, split_len) - self.max_causal_len = max_causal_len - self.max_full_len = max_full_len - self.max_sample_len = max(sample_lens) - self.split_lens = split_lens - self.attn_modes = attn_modes - self.sample_lens = sample_lens - - -def build_packed_sequence( - joint_attn_implementation: str, - *, - packed_sequence: torch.Tensor, - attn_modes: list[str], - split_lens: list[int], - sample_lens: list[int], - packed_und_token_indexes: torch.LongTensor, - packed_gen_token_indexes: torch.LongTensor, - num_heads: int, - head_dim: int, - num_layers: int, - token_shapes=None, - natten_parameter_list=None, - block_size: int = 128, - is_image_batch: bool = False, - cp_world_size: int = 1, - video_temporal_causal: bool = False, - vision_token_shapes=None, - action_token_shapes=None, - temporal_compression_factor_vision: int = 4, - null_action_supertokens: bool = False, - pad_for_cuda_graphs: bool = False, -) -> tuple[FactoredSequencePack, SplitInfo, None]: - assert joint_attn_implementation == "two_way", ( - f"Only two_way attention is supported, got {joint_attn_implementation!r}" - ) - device = packed_sequence.device - attention_meta = SplitInfo( - split_lens=split_lens, - attn_modes=attn_modes, - sample_lens=sample_lens, - actual_len=int(packed_sequence.shape[0]), - ) - input_pack = factored_from_joint_sequence( - packed_sequence=packed_sequence, - attn_modes=attn_modes, - split_lens=split_lens, - sample_lens=sample_lens, - packed_und_token_indexes=packed_und_token_indexes.to(device), - packed_gen_token_indexes=packed_gen_token_indexes.to(device), - is_image_batch=is_image_batch, - cp_world_size=cp_world_size, - pad_for_cuda_graphs=pad_for_cuda_graphs, - ) - input_pack.pop("split_lens", None) - input_pack.pop("attn_modes", None) - return input_pack, attention_meta, None - - -def _ensure_core_metadata(pack: SequencePack) -> None: - required = [ - "sample_offsets", - "max_sample_len", - "max_causal_len", - "max_full_len", - "_causal_indices", - "_full_indices", - "_causal_seq_offsets", - "_full_only_seq_offsets", - "is_sharded", - ] - for key in required: - if key not in pack: - raise KeyError(f"Missing required pack field: {key}") - - -def from_mode_splits( - causal_seq: torch.Tensor, - full_only_seq: torch.Tensor, - orig: FactoredSequencePack | JointSequencePack, - is_sharded: bool | None = None, -): - """ - Create a new sequence pack from two mode splits. - Args: - causal_seq (torch.Tensor): The causal sequence. - full_only_seq (torch.Tensor): The full-only sequence. - orig (FactoredSequencePack | JointSequencePack): The metadata source to copy from. - is_sharded (bool | None): If True, create a local pack for context parallel. - If None, inherits from orig. - """ - _ensure_core_metadata(orig) - if is_sharded is None: - is_sharded = orig.get("is_sharded", False) - - if "packed_sequence" in orig: - all_len = int(orig["_causal_indices"].shape[0] + orig["_full_indices"].shape[0]) - packed_sequence = causal_seq.new_zeros((all_len, *causal_seq.shape[1:])) # [seq_len,D] - packed_sequence[orig["_causal_indices"]] = causal_seq - packed_sequence[orig["_full_indices"]] = full_only_seq - return from_joint(packed_sequence, orig) - else: - out = dict(orig) - out["causal_seq"] = causal_seq - out["full_only_seq"] = full_only_seq - out["is_sharded"] = is_sharded - return out - - -# ------------------------------------ -# Public API -# ------------------------------------ - - -def zeros_like(orig: FactoredSequencePack | JointSequencePack, shape: Tuple[int, ...] | torch.Size | None = None): - """ - Create a new sequence pack with the same metadata as the original, but with all tokens set to zero. - Args: - orig (FactoredSequencePack | JointSequencePack): The original sequence pack to copy metadata from. - shape (Tuple[int, ...] | torch.Size | None): The shape of the new sequence pack. If None, the shape will be the same as the original. - """ - _ensure_core_metadata(orig) - if "packed_sequence" in orig: - if shape is None: - shape_ = orig["packed_sequence"].shape - else: - assert len(shape) >= 1 and shape[0] == -1 - shape_ = (orig["packed_sequence"].shape[0],) + tuple(shape)[1:] - packed_sequence = torch.zeros( - shape_, device=orig["packed_sequence"].device, dtype=orig["packed_sequence"].dtype - ) # [seq_len,D] - return from_joint(packed_sequence, orig) - else: - if shape is None: - shape_causal = orig["causal_seq"].shape - shape_full = orig["full_only_seq"].shape - else: - assert len(shape) >= 1 and shape[0] == -1 - shape_causal = (orig["causal_seq"].shape[0],) + tuple(shape)[1:] - shape_full = (orig["full_only_seq"].shape[0],) + tuple(shape)[1:] - causal_seq = torch.zeros( - shape_causal, device=orig["causal_seq"].device, dtype=orig["causal_seq"].dtype - ) # [N_causal_tokens,D] - full_only_seq = torch.zeros( - shape_full, device=orig["full_only_seq"].device, dtype=orig["full_only_seq"].dtype - ) # [N_full_tokens,D] - return from_mode_splits(causal_seq, full_only_seq, orig) - - -def from_joint(packed_sequence: torch.Tensor, metadata_source: FactoredSequencePack | JointSequencePack): - """ - Create a new sequence pack from a packed sequence and another sequence pack with the same metadata. - Args: - packed_sequence (torch.Tensor): Tensor containing all tokens in the batch of sequences. - metadata_source (FactoredSequencePack | JointSequencePack): The metadata source to copy from. - """ - _ensure_core_metadata(metadata_source) - if "packed_sequence" in metadata_source: - out = dict(metadata_source) - out["packed_sequence"] = packed_sequence - return out - else: - if metadata_source["is_sharded"]: - # Use sharded sequences as is when is_sharded is True (used in Context Parallel) - causal_seq = packed_sequence[: len(metadata_source["causal_seq"])] # [N_causal_tokens,D] - full_only_seq = packed_sequence[len(metadata_source["causal_seq"]) :] # [N_full_tokens,D] - else: - causal_seq = packed_sequence[metadata_source["_causal_indices"]] # [N_causal_tokens,D] - full_only_seq = packed_sequence[metadata_source["_full_indices"]] # [N_full_tokens,D] - causal_seq, full_only_seq = _pad( - causal_seq, - full_only_seq, - max_causal_len=metadata_source["causal_seq"].shape[0], - max_full_len=metadata_source["full_only_seq"].shape[0], - ) - - return from_mode_splits(causal_seq, full_only_seq, metadata_source) - - -def from_und_gen_splits(und_seq: torch.Tensor, gen_seq: torch.Tensor, orig: FactoredSequencePack | JointSequencePack): - """ - Create a new sequence pack from two und/gen splits. - Args: - und_seq (torch.Tensor): The understanding sequence. - gen_seq (torch.Tensor): The generating sequence. - orig (FactoredSequencePack | JointSequencePack): The metadata source to copy from. - """ - # If we have a joint pack (single packed_sequence), place by und/gen indexes. - if "packed_sequence" in orig and "packed_und_token_indexes" in orig and "packed_gen_token_indexes" in orig: - all_len = int(und_seq.shape[0] + gen_seq.shape[0]) - packed_sequence = und_seq.new_zeros((all_len, *und_seq.shape[1:])) # [seq_len,D] - packed_sequence[orig["packed_und_token_indexes"]] = und_seq - packed_sequence[orig["packed_gen_token_indexes"]] = gen_seq - return from_joint(packed_sequence, orig) - # Otherwise, treat und/gen as mode splits (und == causal; gen == full). - return from_mode_splits(und_seq, gen_seq, orig) - - -def get_und_seq(pack: SequencePack) -> torch.Tensor: - """ - Get all understanding tokens in a sequence pack in a single tensor. - - Args: - pack (FactoredSequencePack | JointSequencePack): The sequence pack to get the understanding sequence from. - Returns: - torch.Tensor: All understanding tokens concatenated over all sequences in the batch. - """ - if "causal_seq" in pack: - return pack["causal_seq"] - if "packed_sequence" in pack and "packed_und_token_indexes" in pack: - return pack["packed_sequence"][pack["packed_und_token_indexes"]] - raise KeyError("Cannot derive und_seq from provided pack") - - -def set_und_seq(pack: SequencePack, value: torch.Tensor) -> None: - """ - Override the understanding tokens in a sequence pack. - The order of tokens passed in must correspond to the order of tokens returned by get_und_seq. - - Args: - pack (FactoredSequencePack | JointSequencePack): The sequence pack to set the understanding sequence in. - value (torch.Tensor): The understanding sequence to set. - """ - if "packed_sequence" in pack and "packed_und_token_indexes" in pack: - pack["packed_sequence"][pack["packed_und_token_indexes"]] = value - elif "causal_seq" in pack: - pack["causal_seq"] = value - else: - raise KeyError("Cannot set und_seq from provided pack") - - -def get_gen_seq(pack: SequencePack) -> torch.Tensor: - """ - Get all generating tokens in a sequence pack in a single tensor. - Args: - pack (FactoredSequencePack | JointSequencePack): The sequence pack to get the generating sequence from. - Returns: - torch.Tensor: All generating tokens concatenated over all sequences in the batch. - """ - if "full_only_seq" in pack: - return pack["full_only_seq"] - if "packed_sequence" in pack and "packed_gen_token_indexes" in pack: - return pack["packed_sequence"][pack["packed_gen_token_indexes"]] - raise KeyError("Cannot derive gen_seq from provided pack") - - -def set_gen_seq(pack: SequencePack, value: torch.Tensor) -> None: - """ - Override the generating tokens in a sequence pack. - The order of tokens passed in must correspond to the order of tokens returned by get_gen_seq. - Args: - pack (FactoredSequencePack | JointSequencePack): The sequence pack to set the generating sequence in. - value (torch.Tensor): The generating sequence to set. - """ - if "packed_sequence" in pack and "packed_gen_token_indexes" in pack: - pack["packed_sequence"][pack["packed_gen_token_indexes"]] = value - elif "full_only_seq" in pack: - pack["full_only_seq"] = value - else: - raise KeyError("Cannot set gen_seq from provided pack") - - -def get_device_and_dtype(pack: SequencePack) -> Tuple[torch.device, torch.dtype]: - """ - Get the device and dtype of a sequence pack. - Args: - pack (FactoredSequencePack | JointSequencePack): The sequence pack to get the device and dtype from. - Returns: - Tuple[torch.device, torch.dtype]: The device and dtype of the sequence pack. - """ - if "packed_sequence" in pack: - return pack["packed_sequence"].device, pack["packed_sequence"].dtype - if "causal_seq" in pack and "full_only_seq" in pack: - return pack["causal_seq"].device, pack["causal_seq"].dtype - raise KeyError("Cannot derive device and dtype from provided pack") - - -def get_all_seq(pack: SequencePack) -> torch.Tensor: - """ - Get all tokens in a sequence pack in a single tensor. - Args: - pack (FactoredSequencePack | JointSequencePack): The sequence pack to get the all sequence from. - Returns: - torch.Tensor: All tokens concatenated over all sequences in the batch. - """ - if "all_seq" in pack: - return pack["all_seq"] - if "packed_sequence" in pack: - return pack["packed_sequence"] - if "causal_seq" in pack and "full_only_seq" in pack: - _ensure_core_metadata(pack) - if pack["is_sharded"]: - assert False, "get_all_seq is not supported in context parallel sharded mode" - else: - out = pack["causal_seq"].new_zeros( - int(pack["_causal_indices"].shape[0] + pack["_full_indices"].shape[0]), *pack["causal_seq"].shape[1:] - ) # [seq_len,D] - if pack["causal_seq"].shape[0] > 0: - out[pack["_causal_indices"]] = pack["causal_seq"][: pack["_causal_indices"].shape[0]] - if pack["full_only_seq"].shape[0] > 0: - out[pack["_full_indices"]] = pack["full_only_seq"][: pack["_full_indices"].shape[0]] - return out - raise KeyError("Cannot derive all_seq from provided pack") - - -def get_causal_seq(pack: SequencePack) -> Tuple[torch.Tensor, torch.Tensor]: - """ - Get the causal sequence and its offsets in a sequence pack. - Args: - pack (FactoredSequencePack | JointSequencePack): The sequence pack to get the causal sequence from. - Returns: - Tuple[torch.Tensor, torch.Tensor]: The concatenated causal sub-sequences and the starting offset for each sub-sequence. - """ - _ensure_core_metadata(pack) - if "causal_seq" in pack: - return pack["causal_seq"], pack["_causal_seq_offsets"] - assert "packed_sequence" in pack - return pack["packed_sequence"][pack["_causal_indices"]], pack["_causal_seq_offsets"] - - -def get_full_only_seq(pack: SequencePack) -> Tuple[torch.Tensor, torch.Tensor]: - """ - Get the full-only sequence and its offsets in a sequence pack. - Args: - pack (FactoredSequencePack | JointSequencePack): The sequence pack to get the full-only sequence from. - Returns: - Tuple[torch.Tensor, torch.Tensor]: The concatenated full-only sub-sequences and the starting offset for each sub-sequence. - """ - _ensure_core_metadata(pack) - if "full_only_seq" in pack: - return pack["full_only_seq"], pack["_full_only_seq_offsets"] - assert "packed_sequence" in pack - return pack["packed_sequence"][pack["_full_indices"]], pack["_full_only_seq_offsets"] - - -# ============================================================================ -# 3D mRoPE position ID utilities -# Copied from cosmos3._src.vfm.models.mot.unified_3dmrope_utils -# ============================================================================ - - -def get_3d_mrope_ids_text_tokens( - num_tokens: int, - temporal_offset: int | float, - use_float_positions: bool = False, -) -> tuple[torch.Tensor, int | float]: - """Generate 3D mRoPE position IDs for text tokens. - - For text tokens, all three axes (temporal, height, width) share the same - monotonically increasing position IDs, starting from ``temporal_offset``. - - Args: - num_tokens: Number of text tokens. - temporal_offset: Current temporal offset to start from. - use_float_positions: If True, generate float position IDs. - - Returns: - Tuple of position IDs tensor of shape (3, num_tokens) and updated temporal offset. - """ - if use_float_positions: - ids = torch.arange(num_tokens, dtype=torch.float32) + temporal_offset - else: - ids = torch.arange(num_tokens, dtype=torch.long) + int(temporal_offset) - - mrope_ids = ids.unsqueeze(0).expand(3, -1).contiguous() # [3,num_tokens] - next_temporal_offset = temporal_offset + num_tokens - return mrope_ids, next_temporal_offset - - -def get_3d_mrope_ids_vae_tokens( - grid_t: int, - grid_h: int, - grid_w: int, - temporal_offset: int | float, - reset_spatial_indices: bool = True, - fps: float | None = None, - base_fps: float = 24.0, - temporal_compression_factor: int = 4, - base_temporal_compression_factor: int | None = None, - start_frame_offset: int = 0, -) -> tuple[torch.Tensor, int | float]: - """Generate 3D mRoPE position IDs for VAE vision tokens (image/video latents). - - Args: - grid_t: Number of temporal frames in the latent grid. - grid_h: Height of the latent grid (after patchification). - grid_w: Width of the latent grid (after patchification). - temporal_offset: Current temporal offset. - reset_spatial_indices: If True, spatial indices start from 0 for each vision segment. - fps: Frames per second. If None, FPS modulation is disabled. - base_fps: Base FPS for normalization. - temporal_compression_factor: VAE temporal compression factor. - base_temporal_compression_factor: Base temporal compression factor. - start_frame_offset: Offset added to frame indices before FPS scaling. - - Returns: - Tuple of position IDs tensor of shape (3, grid_t * grid_h * grid_w) and updated offset. - """ - fps_modulation_enabled = fps is not None and grid_t > 1 - effective_base_tcf = ( - base_temporal_compression_factor - if base_temporal_compression_factor is not None - else temporal_compression_factor - ) - - if fps_modulation_enabled: - tps = fps / temporal_compression_factor - base_tps = base_fps / effective_base_tcf - frame_indices = torch.arange(grid_t, dtype=torch.float32) - scaled_t = (frame_indices + start_frame_offset) / tps * base_tps + temporal_offset - t_index = scaled_t.view(-1, 1).expand(-1, grid_h * grid_w).flatten() - t_dtype = torch.float32 - else: - t_index = ( - torch.arange(grid_t, dtype=torch.long).view(-1, 1).expand(-1, grid_h * grid_w).flatten() - + int(temporal_offset) - + start_frame_offset - ) - t_dtype = torch.long - - h_index = torch.arange(grid_h, dtype=torch.long).view(1, -1, 1).expand(grid_t, -1, grid_w).flatten() - w_index = torch.arange(grid_w, dtype=torch.long).view(1, 1, -1).expand(grid_t, grid_h, -1).flatten() - - if not reset_spatial_indices: - spatial_offset = int(temporal_offset) - h_index = h_index + spatial_offset - w_index = w_index + spatial_offset - - if fps_modulation_enabled: - mrope_ids = torch.stack([t_index, h_index.to(torch.float32), w_index.to(torch.float32)], dim=0) - else: - mrope_ids = torch.stack([t_index, h_index, w_index], dim=0) - - max_position = mrope_ids.max().item() - next_temporal_offset = math.ceil(max_position) + 1 - return mrope_ids, next_temporal_offset - - -# ============================================================================ -# Data structures for sequence packing -# Copied from cosmos3._src.vfm.datasets.sequence_packing -# ============================================================================ - - -@dataclass -class ModalityData: - """Unified container for a single generation modality's data. - - This dataclass serves dual purposes: - 1. During packing: Acts as a builder, accumulating data in lists - 2. After finalize(): Holds finalized tensors ready for model consumption - """ - - sequence_indexes: list[int] | torch.Tensor = field(default_factory=list) - timesteps: list[float] | torch.Tensor = field(default_factory=list) - mse_loss_indexes: list[int] | torch.Tensor = field(default_factory=list) - token_shapes: list = field(default_factory=list) - - tokens: list[torch.Tensor] = field(default_factory=list) - condition_mask: list[torch.Tensor] = field(default_factory=list) - noisy_frame_indexes: list[torch.Tensor] = field(default_factory=list) - domain_id: list[torch.Tensor] = field(default_factory=list) - raw_action_dim: list[torch.Tensor | None] | None = field(default_factory=list) - - def to_cuda(self) -> None: - if isinstance(self.sequence_indexes, torch.Tensor): - self.sequence_indexes = self.sequence_indexes.cuda() - if isinstance(self.timesteps, torch.Tensor): - self.timesteps = self.timesteps.cuda() - if isinstance(self.mse_loss_indexes, torch.Tensor): - self.mse_loss_indexes = self.mse_loss_indexes.cuda() - self.tokens = [token.cuda() for token in self.tokens] - self.condition_mask = [cm.cuda() for cm in self.condition_mask] - self.noisy_frame_indexes = [ni.cuda() for ni in self.noisy_frame_indexes] - self.domain_id = [d.cuda() for d in self.domain_id] - if self.raw_action_dim is not None: - self.raw_action_dim = [d.cuda() if d is not None else None for d in self.raw_action_dim] - - -@dataclass -class PackedSequence: - """Unified sequence container - works as builder during packing and final output.""" - - # Sequence structure - sample_lens: list[int] = field(default_factory=list) - split_lens: list[int] = field(default_factory=list) - attn_modes: list[str] = field(default_factory=list) - is_image_batch: bool = False - sequence_length: int = 0 - - # Build-time tracking - curr: int = 0 - - # Text modality (list during build, tensor after finalize) - text_ids: list[int] | torch.Tensor = field(default_factory=list) - text_indexes: list[int] | torch.Tensor = field(default_factory=list) - position_ids: list[int] | torch.Tensor = field(default_factory=list) - - # Loss computation - Cross Entropy (text) - label_ids: list[int] | torch.Tensor | None = field(default_factory=list) - ce_loss_indexes: list[int] | torch.Tensor | None = field(default_factory=list) - ce_loss_weights: list[float] | torch.Tensor | None = field(default_factory=list) - - # Build-time mRoPE tracking - _use_mrope: bool = False - _mrope_temporal_offset: int | float = 0 - _mrope_reset_spatial: bool = True - - # Temporal causal - null_action_supertokens: bool = False - - # Generation modalities - vision: ModalityData | None = None - action: ModalityData | None = None - sound: ModalityData | None = None - - def finalize( - self, - gen_data_clean: "GenerationDataClean", - ) -> "PackedSequence": - """Convert all lists to tensors and compute derived values.""" - sequence_length = sum(self.sample_lens) - sample_lens = self.sample_lens.copy() - split_lens = self.split_lens.copy() - attn_modes = self.attn_modes.copy() - - label_ids: torch.Tensor | None = None - ce_loss_indexes: torch.Tensor | None = None - ce_loss_weights: torch.Tensor | None = None - if self.label_ids and len(self.label_ids) > 0: - label_ids = torch.tensor(self.label_ids) - ce_loss_indexes = torch.tensor(self.ce_loss_indexes) - ce_loss_weights = torch.tensor(self.ce_loss_weights) - - vision: ModalityData | None = None - if self.vision is not None and len(self.vision.sequence_indexes) > 0: - vision = ModalityData( - sequence_indexes=torch.tensor(self.vision.sequence_indexes, dtype=torch.long), - timesteps=torch.tensor(self.vision.timesteps), - mse_loss_indexes=torch.tensor(self.vision.mse_loss_indexes, dtype=torch.long), - token_shapes=list(self.vision.token_shapes), - tokens=self.vision.tokens, - condition_mask=list(self.vision.condition_mask), - noisy_frame_indexes=list(self.vision.noisy_frame_indexes), - ) - - action: ModalityData | None = None - if self.action is not None and len(self.action.sequence_indexes) > 0: - action = ModalityData( - sequence_indexes=torch.tensor(self.action.sequence_indexes, dtype=torch.long), - timesteps=torch.tensor(self.action.timesteps), - mse_loss_indexes=torch.tensor(self.action.mse_loss_indexes, dtype=torch.long), - token_shapes=list(self.action.token_shapes), - tokens=self.action.tokens, - condition_mask=list(self.action.condition_mask), - noisy_frame_indexes=list(self.action.noisy_frame_indexes), - domain_id=( - gen_data_clean.action_domain_id - if gen_data_clean.action_domain_id is not None - else [torch.zeros(1, dtype=torch.long)] * len(self.action.token_shapes) - ), - raw_action_dim=gen_data_clean.raw_action_dim, - ) - - sound: ModalityData | None = None - if self.sound is not None and len(self.sound.sequence_indexes) > 0: - sound = ModalityData( - sequence_indexes=torch.tensor(self.sound.sequence_indexes, dtype=torch.long), - timesteps=torch.tensor(self.sound.timesteps), - mse_loss_indexes=torch.tensor(self.sound.mse_loss_indexes, dtype=torch.long), - token_shapes=list(self.sound.token_shapes), - tokens=self.sound.tokens, - condition_mask=list(self.sound.condition_mask), - noisy_frame_indexes=list(self.sound.noisy_frame_indexes), - ) - - if self._use_mrope and len(self.position_ids) > 0 and isinstance(self.position_ids[0], torch.Tensor): - mrope_tensors: list[torch.Tensor] = self.position_ids # type: ignore[assignment] - position_ids = torch.cat(mrope_tensors, dim=1) # [3,actual_seq_len] - else: - position_ids = torch.tensor(self.position_ids) # [seq_len] - - return PackedSequence( - sequence_length=sequence_length, - sample_lens=sample_lens, - split_lens=split_lens, - attn_modes=attn_modes, - is_image_batch=gen_data_clean.is_image_batch, - text_ids=torch.tensor(self.text_ids, dtype=torch.long), - text_indexes=torch.tensor(self.text_indexes, dtype=torch.long), - position_ids=position_ids, - label_ids=label_ids, - ce_loss_indexes=ce_loss_indexes, - ce_loss_weights=ce_loss_weights, - vision=vision, - action=action, - sound=sound, - null_action_supertokens=self.null_action_supertokens, - ) - - def to_cuda(self) -> None: - if isinstance(self.text_ids, torch.Tensor): - self.text_ids = self.text_ids.cuda() - if isinstance(self.text_indexes, torch.Tensor): - self.text_indexes = self.text_indexes.cuda() - if isinstance(self.position_ids, torch.Tensor): - self.position_ids = self.position_ids.cuda() - if isinstance(self.label_ids, torch.Tensor): - self.label_ids = self.label_ids.cuda() - if isinstance(self.ce_loss_indexes, torch.Tensor): - self.ce_loss_indexes = self.ce_loss_indexes.cuda() - if isinstance(self.ce_loss_weights, torch.Tensor): - self.ce_loss_weights = self.ce_loss_weights.cuda() - if self.vision is not None: - self.vision.to_cuda() - if self.action is not None: - self.action.to_cuda() - if self.sound is not None: - self.sound.to_cuda() - - -@dataclass -class SequencePlan: - """Plan describing which modalities are present in a sample.""" - - has_text: bool - has_vision: bool = False - condition_frame_indexes_vision: list[int] = field(default_factory=list) - has_action: bool = False - condition_frame_indexes_action: list[int] = field(default_factory=list) - has_sound: bool = False - condition_frame_indexes_sound: list[int] = field(default_factory=list) - - def as_dict(self) -> dict: - return { - "has_text": self.has_text, - "has_vision": self.has_vision, - "has_action": self.has_action, - "has_sound": self.has_sound, - "condition_frame_indexes_vision": self.condition_frame_indexes_vision, - "condition_frame_indexes_action": self.condition_frame_indexes_action, - "condition_frame_indexes_sound": self.condition_frame_indexes_sound, - } - - -# ============================================================================ -# Helper functions for packing sequences -# ============================================================================ - - -def _pack_text_tokens( - packed_seq: PackedSequence, - text_ids: List[int], - special_tokens: Dict[str, int], - curr_rope_id: int, - has_generation: bool, - use_float_positions: bool = False, -) -> Tuple[int, int, int]: - """Pack text tokens into the sequence.""" - assert isinstance(packed_seq.text_ids, list), "PackedSequence must be in build mode" - assert isinstance(packed_seq.text_indexes, list) - assert isinstance(packed_seq.position_ids, list) - assert isinstance(packed_seq.label_ids, list) - assert isinstance(packed_seq.ce_loss_indexes, list) - assert isinstance(packed_seq.ce_loss_weights, list) - - curr = packed_seq.curr - - if "bos_token_id" in special_tokens: - shifted_text_ids = [special_tokens["bos_token_id"]] + text_ids - else: - shifted_text_ids = text_ids - - split_len = 0 - - packed_seq.text_ids.extend(shifted_text_ids) - packed_seq.text_indexes.extend(range(curr, curr + len(shifted_text_ids))) - - packed_seq.ce_loss_indexes.extend(range(curr, curr + len(shifted_text_ids))) - packed_seq.ce_loss_weights.extend([1.0] * len(shifted_text_ids)) - packed_seq.label_ids.extend(text_ids[1:] + [special_tokens["eos_token_id"]]) - - curr += len(shifted_text_ids) - split_len += len(shifted_text_ids) - - packed_seq.text_ids.append(special_tokens["eos_token_id"]) - packed_seq.text_indexes.append(curr) - curr += 1 - split_len += 1 - - if has_generation: - packed_seq.text_ids.append(special_tokens["start_of_generation"]) - packed_seq.text_indexes.append(curr) - curr += 1 - split_len += 1 - - if packed_seq._use_mrope: - text_mrope_ids, packed_seq._mrope_temporal_offset = get_3d_mrope_ids_text_tokens( - num_tokens=split_len, - temporal_offset=packed_seq._mrope_temporal_offset, - use_float_positions=use_float_positions, - ) - packed_seq.position_ids.append(text_mrope_ids) - else: - packed_seq.position_ids.extend(range(curr_rope_id, curr_rope_id + split_len)) - packed_seq.attn_modes.append("causal") - packed_seq.split_lens.append(split_len) - - packed_seq.curr = curr - return curr_rope_id + split_len, split_len, split_len - - -def _pack_vision_tokens( - packed_seq: PackedSequence, - input_vision_tokens: torch.Tensor, - condition_frame_indexes_vision: list[int], - input_timestep: float | torch.Tensor, - curr_rope_id: int, - latent_patch_size: int = 1, - vision_fps: float | None = None, - enable_fps_modulation: bool = False, - base_fps: float = 24.0, - temporal_compression_factor: int = 4, -) -> int: - """Pack vision tokens into the sequence.""" - assert isinstance(packed_seq.position_ids, list), "PackedSequence must be in build mode" - - curr = packed_seq.curr - vision_split_len = 0 - - if packed_seq.vision is None: - packed_seq.vision = ModalityData() - - assert isinstance(packed_seq.vision.sequence_indexes, list) - assert isinstance(packed_seq.vision.mse_loss_indexes, list) - assert isinstance(packed_seq.vision.timesteps, list) - assert isinstance(packed_seq.vision.tokens, list) - - _, _, latent_t, latent_h, latent_w = input_vision_tokens.shape - if latent_patch_size < 1: - raise ValueError(f"latent_patch_size must be >= 1, got {latent_patch_size}") - patch_h = math.ceil(latent_h / latent_patch_size) - patch_w = math.ceil(latent_w / latent_patch_size) - packed_seq.vision.token_shapes.append((latent_t, patch_h, patch_w)) - packed_seq.vision.tokens.append(input_vision_tokens) - - num_vision_tokens = latent_t * patch_h * patch_w - packed_seq.vision.sequence_indexes.extend(range(curr, curr + num_vision_tokens)) - - condition_set = {idx for idx in condition_frame_indexes_vision if 0 <= idx < latent_t} - assert isinstance(packed_seq.vision.condition_mask, list) - - vision_condition_mask = torch.zeros( - (latent_t, 1, 1), device=input_vision_tokens.device, dtype=input_vision_tokens.dtype - ) - for frame_idx in condition_set: - vision_condition_mask[frame_idx, 0, 0] = 1.0 - packed_seq.vision.condition_mask.append(vision_condition_mask) - - vision_noisy_frame_indexes = torch.tensor( - [idx for idx in range(latent_t) if idx not in condition_set], - device=input_vision_tokens.device, - dtype=torch.long, - ) - assert isinstance(packed_seq.vision.noisy_frame_indexes, list) - packed_seq.vision.noisy_frame_indexes.append(vision_noisy_frame_indexes) - - frame_token_stride = patch_h * patch_w - for frame_idx in range(latent_t): - if frame_idx in condition_set: - continue - frame_start = curr + frame_idx * frame_token_stride - frame_end = frame_start + frame_token_stride - packed_seq.vision.mse_loss_indexes.extend(range(frame_start, frame_end)) - if isinstance(input_timestep, torch.Tensor): - frame_ts = input_timestep[frame_idx].item() - else: - frame_ts = input_timestep - packed_seq.vision.timesteps.extend([frame_ts] * frame_token_stride) - - curr += num_vision_tokens - vision_split_len += num_vision_tokens - - if packed_seq._use_mrope: - effective_fps = vision_fps if enable_fps_modulation else None - vision_mrope_ids, packed_seq._mrope_temporal_offset = get_3d_mrope_ids_vae_tokens( - grid_t=latent_t, - grid_h=patch_h, - grid_w=patch_w, - temporal_offset=packed_seq._mrope_temporal_offset, - reset_spatial_indices=packed_seq._mrope_reset_spatial, - fps=effective_fps, - base_fps=base_fps, - temporal_compression_factor=temporal_compression_factor, - ) - packed_seq.position_ids.append(vision_mrope_ids) - else: - packed_seq.position_ids.extend([curr_rope_id] * vision_split_len) - - packed_seq.curr = curr - return vision_split_len - - -def _pack_action_tokens( - packed_seq: PackedSequence, - input_action_tokens: torch.Tensor, - condition_frame_indexes_action: list[int], - input_timestep: float, - curr_rope_id: int, - action_temporal_offset: int | float = 0, - enable_fps_modulation: bool = False, - base_fps: float = 24.0, - action_fps: float | None = None, - base_temporal_compression_factor: int | None = None, -) -> int: - """Pack action tokens into the sequence.""" - assert isinstance(packed_seq.position_ids, list), "PackedSequence must be in build mode" - - curr = packed_seq.curr - action_split_len = input_action_tokens.shape[0] - - if packed_seq.action is None: - packed_seq.action = ModalityData() - - assert isinstance(packed_seq.action.sequence_indexes, list) - assert isinstance(packed_seq.action.mse_loss_indexes, list) - assert isinstance(packed_seq.action.timesteps, list) - assert isinstance(packed_seq.action.tokens, list) - - action_indexes = list(range(curr, curr + action_split_len)) - packed_seq.action.sequence_indexes.extend(action_indexes) - packed_seq.action.token_shapes.append((action_split_len,)) - packed_seq.action.tokens.append(input_action_tokens) - - condition_set = {idx for idx in condition_frame_indexes_action if 0 <= idx < action_split_len} - assert isinstance(packed_seq.action.condition_mask, list) - - action_condition_mask = torch.zeros( - (action_split_len, 1), device=input_action_tokens.device, dtype=input_action_tokens.dtype - ) - for frame_idx in condition_set: - action_condition_mask[frame_idx, 0] = 1.0 - packed_seq.action.condition_mask.append(action_condition_mask) - - action_noisy_frame_indexes = torch.tensor( - [idx for idx in range(action_split_len) if idx not in condition_set], - device=input_action_tokens.device, - dtype=torch.long, - ) - assert isinstance(packed_seq.action.noisy_frame_indexes, list) - packed_seq.action.noisy_frame_indexes.append(action_noisy_frame_indexes) - - frame_token_stride = 1 - for frame_idx in range(action_split_len): - if frame_idx in condition_set: - continue - frame_start = curr + frame_idx * frame_token_stride - frame_end = frame_start + frame_token_stride - packed_seq.action.mse_loss_indexes.extend(range(frame_start, frame_end)) - packed_seq.action.timesteps.extend([input_timestep] * frame_token_stride) - - if packed_seq._use_mrope: - effective_fps = action_fps if enable_fps_modulation else None - action_mrope_ids, _ = get_3d_mrope_ids_vae_tokens( - grid_t=action_split_len, - grid_h=1, - grid_w=1, - temporal_offset=action_temporal_offset, - reset_spatial_indices=packed_seq._mrope_reset_spatial, - fps=effective_fps, - base_fps=base_fps, - temporal_compression_factor=1, - base_temporal_compression_factor=base_temporal_compression_factor, - start_frame_offset=1, - ) - packed_seq.position_ids.append(action_mrope_ids) - else: - packed_seq.position_ids.extend([curr_rope_id] * action_split_len) - - packed_seq.curr = curr + action_split_len - return action_split_len - - -def _pack_sound_tokens( - packed_seq: PackedSequence, - input_sound_tokens: torch.Tensor, - condition_frame_indexes_sound: list[int], - input_timestep: float, - curr_rope_id: int, - sound_temporal_offset: int | float = 0, - enable_fps_modulation: bool = False, - base_fps: float = 24.0, - sound_fps: float | None = None, -) -> int: - """Pack sound/audio tokens into the sequence.""" - assert isinstance(packed_seq.position_ids, list), "PackedSequence must be in build mode" - - curr = packed_seq.curr - _, sound_split_len = input_sound_tokens.shape - - if packed_seq.sound is None: - packed_seq.sound = ModalityData() - - assert isinstance(packed_seq.sound.sequence_indexes, list) - assert isinstance(packed_seq.sound.mse_loss_indexes, list) - assert isinstance(packed_seq.sound.timesteps, list) - assert isinstance(packed_seq.sound.tokens, list) - - packed_seq.sound.token_shapes.append((sound_split_len, 1, 1)) - packed_seq.sound.sequence_indexes.extend(range(curr, curr + sound_split_len)) - packed_seq.sound.tokens.append(input_sound_tokens) - - condition_set = {idx for idx in condition_frame_indexes_sound if 0 <= idx < sound_split_len} - assert isinstance(packed_seq.sound.condition_mask, list) - - sound_condition_mask = torch.zeros( - (sound_split_len, 1), device=input_sound_tokens.device, dtype=input_sound_tokens.dtype - ) - for frame_idx in condition_set: - sound_condition_mask[frame_idx, 0] = 1.0 - packed_seq.sound.condition_mask.append(sound_condition_mask) - - sound_noisy_frame_indexes = torch.tensor( - [idx for idx in range(sound_split_len) if idx not in condition_set], - device=input_sound_tokens.device, - dtype=torch.long, - ) - assert isinstance(packed_seq.sound.noisy_frame_indexes, list) - packed_seq.sound.noisy_frame_indexes.append(sound_noisy_frame_indexes) - - for frame_idx in range(sound_split_len): - if frame_idx in condition_set: - continue - frame_start = curr + frame_idx - frame_end = frame_start + 1 - packed_seq.sound.mse_loss_indexes.extend(range(frame_start, frame_end)) - packed_seq.sound.timesteps.extend([input_timestep]) - - if packed_seq._use_mrope: - effective_fps = sound_fps if enable_fps_modulation else None - sound_mrope_ids, _ = get_3d_mrope_ids_vae_tokens( - grid_t=sound_split_len, - grid_h=1, - grid_w=1, - temporal_offset=sound_temporal_offset, - reset_spatial_indices=packed_seq._mrope_reset_spatial, - fps=effective_fps, - base_fps=base_fps, - temporal_compression_factor=1, - start_frame_offset=0, - ) - packed_seq.position_ids.append(sound_mrope_ids) - else: - packed_seq.position_ids.extend([curr_rope_id] * sound_split_len) - - packed_seq.curr = curr + sound_split_len - return sound_split_len - - -def _pack_supertokens_temporal_causal( - packed_seq: "PackedSequence", - input_vision_tokens: torch.Tensor, - input_action_tokens: torch.Tensor | None, - condition_frame_indexes_vision: list[int], - input_timestep: float | torch.Tensor, - curr_rope_id: int, - latent_patch_size: int, - temporal_compression_factor: int, - action_dim: int, - vision_fps: float | None = None, - action_fps: float | None = None, - enable_fps_modulation: bool = False, - base_fps: float = 24.0, -) -> tuple[int, bool]: - """Pack vision and action tokens in interleaved supertoken order for temporal causal attention. - - Buffer layout: [action_t0, vision_t0, action_t1, vision_t1, ..., action_{T-1}, vision_{T-1}] - """ - assert isinstance(packed_seq.position_ids, list), "PackedSequence must be in build mode" - - _, _, latent_t, latent_h, latent_w = input_vision_tokens.shape - patch_h = math.ceil(latent_h / latent_patch_size) - patch_w = math.ceil(latent_w / latent_patch_size) - tcf = temporal_compression_factor - patches_per_frame = patch_h * patch_w - supertoken_len = tcf + patches_per_frame - - if packed_seq.vision is None: - packed_seq.vision = ModalityData() - if packed_seq.action is None: - packed_seq.action = ModalityData() - - assert isinstance(packed_seq.vision.sequence_indexes, list) - assert isinstance(packed_seq.vision.mse_loss_indexes, list) - assert isinstance(packed_seq.vision.timesteps, list) - assert isinstance(packed_seq.vision.tokens, list) - assert isinstance(packed_seq.vision.condition_mask, list) - assert isinstance(packed_seq.action.sequence_indexes, list) - assert isinstance(packed_seq.action.mse_loss_indexes, list) - assert isinstance(packed_seq.action.timesteps, list) - assert isinstance(packed_seq.action.tokens, list) - assert isinstance(packed_seq.action.condition_mask, list) - - device = input_vision_tokens.device - dtype = input_vision_tokens.dtype - - null_tokens = torch.zeros(tcf, action_dim, device=device, dtype=dtype) - if input_action_tokens is not None: - if input_action_tokens.dim() == 3: - real_actions = input_action_tokens.squeeze(0) - else: - real_actions = input_action_tokens - if latent_t == 1: - all_action_tokens = real_actions - else: - all_action_tokens = torch.cat([null_tokens, real_actions], dim=0) - else: - all_action_tokens = torch.zeros(latent_t * tcf, action_dim, device=device, dtype=dtype) - - null_action_flag = not (latent_t == 1 and input_action_tokens is not None) - - packed_seq.vision.token_shapes.append((latent_t, patch_h, patch_w)) - packed_seq.vision.tokens.append(input_vision_tokens) - - condition_set_vision = {idx for idx in condition_frame_indexes_vision if 0 <= idx < latent_t} - vision_condition_mask = torch.zeros((latent_t, 1, 1), device=device, dtype=dtype) - for fidx in condition_set_vision: - vision_condition_mask[fidx, 0, 0] = 1.0 - packed_seq.vision.condition_mask.append(vision_condition_mask) - - vision_noisy_frame_indexes = torch.tensor( - [idx for idx in range(latent_t) if idx not in condition_set_vision], - device=device, - dtype=torch.long, - ) - packed_seq.vision.noisy_frame_indexes.append(vision_noisy_frame_indexes) - - packed_seq.action.token_shapes.append((latent_t * tcf,)) - packed_seq.action.tokens.append(all_action_tokens) - - action_condition_mask = torch.ones((latent_t * tcf, 1), device=device, dtype=dtype) - packed_seq.action.condition_mask.append(action_condition_mask) - - curr = packed_seq.curr - total_split_len = 0 - - if packed_seq._use_mrope: - temporal_offset = packed_seq._mrope_temporal_offset - effective_action_fps = action_fps if enable_fps_modulation else None - effective_vision_fps = vision_fps if enable_fps_modulation else None - - fps_active = effective_action_fps is not None - t_dtype = torch.float32 if fps_active else torch.long - t_offset = float(temporal_offset) if fps_active else int(temporal_offset) - null_t = torch.full((tcf,), t_offset, dtype=t_dtype) - null_hw = torch.zeros(tcf, dtype=t_dtype) - null_ids = torch.stack([null_t, null_hw, null_hw]) # [3,tcf] - - def _real_action_ids(n_frames: int, start_frame_offset: int) -> torch.Tensor: - flat, _ = get_3d_mrope_ids_vae_tokens( - grid_t=n_frames * tcf, - grid_h=1, - grid_w=1, - temporal_offset=temporal_offset, - reset_spatial_indices=packed_seq._mrope_reset_spatial, - fps=effective_action_fps, - base_fps=base_fps, - temporal_compression_factor=1, - base_temporal_compression_factor=tcf, - start_frame_offset=start_frame_offset, - ) - return flat.reshape(3, n_frames, tcf) - - if latent_t > 1: - null_ids_3d = null_ids.reshape(3, 1, tcf) - real_ids_3d = _real_action_ids(latent_t - 1, start_frame_offset=1) - action_ids_3d = torch.cat([null_ids_3d, real_ids_3d], dim=1) - elif input_action_tokens is None: - action_ids_3d = null_ids.reshape(3, 1, tcf) - else: - action_ids_3d = _real_action_ids(1, start_frame_offset=0) - - vision_ids_flat, new_offset = get_3d_mrope_ids_vae_tokens( - grid_t=latent_t, - grid_h=patch_h, - grid_w=patch_w, - temporal_offset=temporal_offset, - reset_spatial_indices=packed_seq._mrope_reset_spatial, - fps=effective_vision_fps, - base_fps=base_fps, - temporal_compression_factor=tcf, - ) - vision_ids_3d = vision_ids_flat.reshape(3, latent_t, patches_per_frame) - - interleaved_ids = torch.cat([action_ids_3d, vision_ids_3d], dim=2).reshape(3, latent_t * supertoken_len) - packed_seq.position_ids.append(interleaved_ids) - packed_seq._mrope_temporal_offset = new_offset - - for frame_t in range(latent_t): - action_indexes = list(range(curr, curr + tcf)) - packed_seq.action.sequence_indexes.extend(action_indexes) - curr += tcf - total_split_len += tcf - - if not packed_seq._use_mrope: - packed_seq.position_ids.extend([curr_rope_id] * tcf) - - frame_indexes = list(range(curr, curr + patches_per_frame)) - packed_seq.vision.sequence_indexes.extend(frame_indexes) - curr += patches_per_frame - total_split_len += patches_per_frame - - if not packed_seq._use_mrope: - packed_seq.position_ids.extend([curr_rope_id] * patches_per_frame) - - if frame_t not in condition_set_vision: - packed_seq.vision.mse_loss_indexes.extend(frame_indexes) - frame_ts = input_timestep[frame_t].item() if isinstance(input_timestep, torch.Tensor) else input_timestep - packed_seq.vision.timesteps.extend([frame_ts] * patches_per_frame) - - packed_seq.curr = curr - return total_split_len, null_action_flag - - -# ============================================================================ -# Main packing functions -# ============================================================================ - - -def pack_input_sequence( - sequence_plans: list[SequencePlan], - input_text_indexes: list[list[int]], - gen_data_clean: GenerationDataClean, - input_timesteps: torch.Tensor, - special_tokens: dict[str, int], - max_num_tokens: int | None = None, - latent_patch_size: int = 1, - skip_text_tokens: bool = False, - include_end_of_generation_token: bool = False, - position_embedding_type: str = "3d_rope", - unified_3d_mrope_reset_spatial_ids: bool = True, - unified_3d_mrope_temporal_modality_margin: int = 0, - enable_fps_modulation: bool = False, - base_fps: float = 24.0, - temporal_compression_factor: int = 4, - video_temporal_causal: bool = False, - action_dim: int = 32, - initial_mrope_temporal_offset: int | float = 0, -) -> PackedSequence: - """Pack a sequence of input strings and VAE latents into a packed tensor format. - - Args: - sequence_plans: List of SequencePlan items describing which modalities are present. - input_text_indexes: List of text token ID sequences. - gen_data_clean: GenerationDataClean containing vision, action, and sound tensors. - input_timesteps: Diffusion timesteps for each sample. Shape (B,) or (B, 1). - special_tokens: Dictionary containing special token IDs. - max_num_tokens: Maximum number of tokens (unused, kept for API compatibility). - latent_patch_size: Patch size used by the network to pack latents. - skip_text_tokens: If True, skip packing text tokens. - include_end_of_generation_token: If True, append end-of-generation token. - position_embedding_type: Position embedding type for vision tokens. - unified_3d_mrope_reset_spatial_ids: If True, spatial indices start from 0 per segment. - unified_3d_mrope_temporal_modality_margin: Temporal margin between text and vision. - enable_fps_modulation: If True, scale temporal position IDs based on video FPS. - base_fps: Base FPS for normalization. - temporal_compression_factor: VAE temporal compression factor. - video_temporal_causal: If True, pack vision and action as interleaved supertokens. - action_dim: Action token dimension for temporal causal packing. - initial_mrope_temporal_offset: Initial temporal offset for AR inference. - - Returns: - PackedSequence containing all packed tensors and metadata. - """ - del max_num_tokens - - assert special_tokens is not None, "Special tokens must be provided" - assert isinstance(input_timesteps, torch.Tensor), "input_timesteps must be a tensor" - if input_timesteps.is_cuda: - raise ValueError("input_timesteps must be on CPU, not CUDA") - if isinstance(input_text_indexes, torch.Tensor): - raise ValueError("input_text_tokens must be a list, not a tensor") - - packed_seq = PackedSequence() - packed_seq._use_mrope = position_embedding_type == "unified_3d_mrope" - packed_seq._mrope_reset_spatial = unified_3d_mrope_reset_spatial_ids - - idx_text = 0 - idx_vision = 0 - idx_action = 0 - idx_sound = 0 - null_action_flags: list[bool] = [] - - if not skip_text_tokens: - for plan in sequence_plans: - assert plan.has_text, "All sequence plans must have has_text=True when skip_text_tokens=False" - - for sample_idx, sequence_plan in enumerate(sequence_plans): - curr_rope_id = 0 - sample_len = 0 - - packed_seq._mrope_temporal_offset = initial_mrope_temporal_offset - - _ts = input_timesteps[sample_idx] - input_timestep = _ts.item() if _ts.numel() == 1 else _ts - - if sequence_plan.has_text and not skip_text_tokens: - text_ids = input_text_indexes[idx_text] - idx_text += 1 - - has_generation_for_sample = sequence_plan.has_vision or sequence_plan.has_action or sequence_plan.has_sound - curr_rope_id, _, text_sample_len = _pack_text_tokens( - packed_seq, - text_ids, - special_tokens, - curr_rope_id, - has_generation=has_generation_for_sample, - use_float_positions=enable_fps_modulation, - ) - sample_len += text_sample_len - packed_seq._mrope_temporal_offset += unified_3d_mrope_temporal_modality_margin - - vision_start_temporal_offset = packed_seq._mrope_temporal_offset - - if video_temporal_causal and sequence_plan.has_vision: - assert position_embedding_type == "unified_3d_mrope", ( - "video_temporal_causal=True requires position_embedding_type='unified_3d_mrope'" - ) - input_vision_tokens = gen_data_clean.x0_tokens_vision[idx_vision] - idx_vision += 1 - - vision_fps = None - if ( - enable_fps_modulation - and gen_data_clean.fps_vision is not None - and idx_vision - 1 < len(gen_data_clean.fps_vision) - ): - vision_fps = float(gen_data_clean.fps_vision[idx_vision - 1].item()) - - input_action_tokens_tc: torch.Tensor | None = None - action_fps_tc: float | None = None - if sequence_plan.has_action: - input_action_tokens_tc = gen_data_clean.x0_tokens_action[idx_action] - if ( - enable_fps_modulation - and gen_data_clean.fps_action is not None - and idx_action < len(gen_data_clean.fps_action) - ): - action_fps_tc = float(gen_data_clean.fps_action[idx_action].item()) - idx_action += 1 - - supertoken_split_len, null_flag = _pack_supertokens_temporal_causal( - packed_seq=packed_seq, - input_vision_tokens=input_vision_tokens, - input_action_tokens=input_action_tokens_tc, - condition_frame_indexes_vision=sequence_plan.condition_frame_indexes_vision, - input_timestep=input_timestep, - curr_rope_id=curr_rope_id, - latent_patch_size=latent_patch_size, - temporal_compression_factor=temporal_compression_factor, - action_dim=action_dim, - vision_fps=vision_fps, - action_fps=action_fps_tc, - enable_fps_modulation=enable_fps_modulation, - base_fps=base_fps, - ) - null_action_flags.append(null_flag) - sample_len += supertoken_split_len - vision_split_len = supertoken_split_len - action_split_len = 0 - - else: - if sequence_plan.has_vision: - num_vis = ( - gen_data_clean.num_vision_items_per_sample[sample_idx] - if gen_data_clean.num_vision_items_per_sample is not None - else 1 - ) - - vision_split_len = 0 - for item_idx in range(num_vis): - input_vision_tokens = gen_data_clean.x0_tokens_vision[idx_vision] - - vision_fps: float | None = None - if ( - enable_fps_modulation - and gen_data_clean.fps_vision is not None - and idx_vision < len(gen_data_clean.fps_vision) - ): - vision_fps = float(gen_data_clean.fps_vision[idx_vision].item()) - - idx_vision += 1 - - if num_vis > 1 and item_idx < num_vis - 1: - latent_t = input_vision_tokens.shape[2] - item_condition_frames = list(range(latent_t)) - else: - item_condition_frames = sequence_plan.condition_frame_indexes_vision - - item_split_len = _pack_vision_tokens( - packed_seq=packed_seq, - input_vision_tokens=input_vision_tokens, - condition_frame_indexes_vision=item_condition_frames, - input_timestep=input_timestep, - curr_rope_id=curr_rope_id, - latent_patch_size=latent_patch_size, - vision_fps=vision_fps, - enable_fps_modulation=enable_fps_modulation, - base_fps=base_fps, - temporal_compression_factor=temporal_compression_factor, - ) - vision_split_len += item_split_len - sample_len += vision_split_len - - else: - vision_split_len = 0 - - if sequence_plan.has_action: - input_action_tokens = gen_data_clean.x0_tokens_action[idx_action] - - action_fps: float | None = None - if ( - enable_fps_modulation - and gen_data_clean.fps_action is not None - and idx_action < len(gen_data_clean.fps_action) - ): - action_fps = float(gen_data_clean.fps_action[idx_action].item()) - - idx_action += 1 - - action_split_len = _pack_action_tokens( - packed_seq=packed_seq, - input_action_tokens=input_action_tokens, - condition_frame_indexes_action=sequence_plan.condition_frame_indexes_action, - input_timestep=input_timestep, - curr_rope_id=curr_rope_id, - action_temporal_offset=vision_start_temporal_offset, - enable_fps_modulation=enable_fps_modulation, - base_fps=base_fps, - action_fps=action_fps, - base_temporal_compression_factor=temporal_compression_factor, - ) - sample_len += action_split_len - else: - action_split_len = 0 - - if sequence_plan.has_sound: - input_sound_tokens = gen_data_clean.x0_tokens_sound[idx_sound] - - sound_fps: float | None = None - if ( - enable_fps_modulation - and gen_data_clean.fps_sound is not None - and idx_sound < len(gen_data_clean.fps_sound) - ): - sound_fps = float(gen_data_clean.fps_sound[idx_sound].item()) - - idx_sound += 1 - - sound_split_len = _pack_sound_tokens( - packed_seq=packed_seq, - input_sound_tokens=input_sound_tokens, - condition_frame_indexes_sound=sequence_plan.condition_frame_indexes_sound, - input_timestep=input_timestep, - curr_rope_id=curr_rope_id, - sound_temporal_offset=vision_start_temporal_offset, - enable_fps_modulation=enable_fps_modulation, - base_fps=base_fps, - sound_fps=sound_fps, - ) - sample_len += sound_split_len - else: - sound_split_len = 0 - - eov_len = 0 - has_any_generation = sequence_plan.has_vision or sequence_plan.has_action or sequence_plan.has_sound - if include_end_of_generation_token and has_any_generation: - assert isinstance(packed_seq.text_ids, list) - assert isinstance(packed_seq.text_indexes, list) - assert isinstance(packed_seq.position_ids, list) - - packed_seq.text_ids.append(special_tokens["end_of_generation"]) - packed_seq.text_indexes.append(packed_seq.curr) - - if packed_seq._use_mrope: - eov_dtype = torch.float32 if enable_fps_modulation else torch.long - eov_mrope_ids = torch.full((3, 1), packed_seq._mrope_temporal_offset, dtype=eov_dtype) - packed_seq.position_ids.append(eov_mrope_ids) # type: ignore[arg-type] - packed_seq._mrope_temporal_offset += 1 - else: - packed_seq.position_ids.append(curr_rope_id) # type: ignore[arg-type] - - packed_seq.curr += 1 - eov_len = 1 - sample_len += 1 - - combined_split_len = vision_split_len + action_split_len + sound_split_len + eov_len - packed_seq.attn_modes.append("full") - packed_seq.split_lens.append(combined_split_len) - packed_seq.sample_lens.append(sample_len) - - if null_action_flags: - assert len(set(null_action_flags)) == 1, ( - f"Inconsistent null_action_supertokens across samples: {null_action_flags}." - ) - packed_seq.null_action_supertokens = null_action_flags[0] - - return packed_seq.finalize(gen_data_clean=gen_data_clean) - - -def build_sequence_plans_from_data_batch( - data_batch: dict, - input_video_key, - input_image_key: str, -) -> list[SequencePlan]: - """Build or retrieve sequence plans from a data batch dictionary. - - This function extracts sequence plans from the data batch if they exist, - otherwise creates default SequencePlan objects for each sample in the batch. - - Args: - data_batch: Dictionary containing the data batch from the dataloader. - input_video_key: Key for video tensors in the batch. - input_image_key: Key for image tensors in the batch. - - Returns: - List of SequencePlan objects, one per sample in the batch. - """ - # NOTE: this function is ONLY intended for backward compatibility. - # For new modalities, please generate the sequence_plan in the dataset class. - - if "sequence_plan" in data_batch: - return data_batch["sequence_plan"] - - assert "action" not in data_batch or data_batch["action"] is None, "Action data SHOULD have sequence_plans!" - assert "sound" not in data_batch or data_batch["sound"] is None, "Sound data SHOULD have sequence_plans!" - - batch_size = 0 - for key in [input_video_key, input_image_key]: - if key in data_batch: - val = data_batch[key] - if isinstance(val, torch.Tensor): - batch_size = val.shape[0] - break - elif isinstance(val, list): - batch_size = len(val) - break - - if batch_size == 0: - raise ValueError( - f"Cannot determine batch size from data_batch. Expected {input_video_key}, {input_image_key}, or similar key." - ) - - return [ - SequencePlan( - has_text=True, - has_vision=True, - condition_frame_indexes_vision=[], - ) - for _ in range(batch_size) - ] diff --git a/packages/diffusers-cosmos3/diffusers_cosmos3/transformer.py b/packages/diffusers-cosmos3/diffusers_cosmos3/transformer.py deleted file mode 100644 index 7b432712..00000000 --- a/packages/diffusers-cosmos3/diffusers_cosmos3/transformer.py +++ /dev/null @@ -1,819 +0,0 @@ -# Copyright 2025 The NVIDIA Team and The HuggingFace Team. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import math -from typing import Optional, Tuple - -import torch -import torch.nn as nn -from diffusers.configuration_utils import ConfigMixin, register_to_config -from diffusers.models.attention_dispatch import dispatch_attention_fn -from diffusers.models.modeling_utils import ModelMixin -from transformers.activations import ACT2FN -from transformers.integrations import use_kernel_forward_from_hub -from transformers.modeling_rope_utils import ROPE_INIT_FUNCTIONS, dynamic_rope_update -from transformers.models.qwen3_vl.modeling_qwen3_vl import apply_rotary_pos_emb - -from diffusers_cosmos3.sequence_packing import ( - FactoredSequencePack, - from_joint, - from_mode_splits, - from_und_gen_splits, - get_all_seq, - get_causal_seq, - get_device_and_dtype, - get_full_only_seq, - get_gen_seq, - get_und_seq, - set_gen_seq, - set_und_seq, - zeros_like, -) - - -def _pack_to_batch(tokens: torch.Tensor, cu_seqlens: torch.Tensor, max_seqlen: int) -> torch.Tensor: - """Unpack (total_tokens, heads, dim) → (batch, max_seqlen, heads, dim).""" - batch = cu_seqlens.shape[0] - 1 - cu = cu_seqlens.tolist() - out = tokens.new_zeros(batch, max_seqlen, *tokens.shape[1:]) - for i in range(batch): - n = cu[i + 1] - cu[i] - out[i, :n] = tokens[cu[i] : cu[i + 1]] - return out - - -def _batch_to_pack(batched: torch.Tensor, cu_seqlens: torch.Tensor) -> torch.Tensor: - """Repack (batch, max_seqlen, heads, dim) → (total_tokens, heads, dim).""" - cu = cu_seqlens.tolist() - return torch.cat([batched[i, : cu[i + 1] - cu[i]] for i in range(len(cu) - 1)], dim=0) - - -def _kv_padding_mask(cu_seqlens: torch.Tensor, max_seqlen: int, dtype: torch.dtype, device: torch.device): - """Float mask (batch, 1, 1, max_seqlen) with -inf at padding positions, or None if uniform.""" - batch = cu_seqlens.shape[0] - 1 - cu = cu_seqlens.tolist() - mask = torch.zeros(batch, 1, 1, max_seqlen, dtype=dtype, device=device) - for i in range(batch): - kl = cu[i + 1] - cu[i] - if kl < max_seqlen: - mask[i, 0, 0, kl:] = float("-inf") - return None if (mask == 0).all() else mask - - -class CosmosAttnProcessor3_0: - """ - Packed two-way attention processor for Cosmos3. Implements separate causal - (understanding) and full (generation) attention pathways via dispatch_attention_fn. - """ - - def __call__( - self, - packed_query_states: FactoredSequencePack, - packed_key_states: FactoredSequencePack, - packed_value_states: FactoredSequencePack, - ) -> FactoredSequencePack: - causal_q, causal_offsets = get_causal_seq(packed_query_states) - causal_k, _ = get_causal_seq(packed_key_states) - causal_v, _ = get_causal_seq(packed_value_states) - full_q, full_offsets = get_full_only_seq(packed_query_states) - sample_offsets = packed_query_states["sample_offsets"] - max_causal = packed_query_states["max_causal_len"] - max_full = packed_query_states["max_full_len"] - max_sample = packed_query_states["max_sample_len"] - - # Causal (understanding) self-attention - causal_out = dispatch_attention_fn( - _pack_to_batch(causal_q, causal_offsets, max_causal), - _pack_to_batch(causal_k, causal_offsets, max_causal), - _pack_to_batch(causal_v, causal_offsets, max_causal), - is_causal=True, - enable_gqa=True, - ) - causal_out = _batch_to_pack(causal_out, causal_offsets).flatten(-2, -1) - - # Full (generation) cross-attention: Q = gen tokens, K/V = all tokens - all_k = get_all_seq(packed_key_states) - all_v = get_all_seq(packed_value_states) - full_out = dispatch_attention_fn( - _pack_to_batch(full_q, full_offsets, max_full), - _pack_to_batch(all_k, sample_offsets, max_sample), - _pack_to_batch(all_v, sample_offsets, max_sample), - attn_mask=_kv_padding_mask(sample_offsets, max_sample, causal_q.dtype, causal_q.device), - is_causal=False, - enable_gqa=True, - ) - full_out = _batch_to_pack(full_out, full_offsets).flatten(-2, -1) - - return from_mode_splits(causal_out, full_out, packed_query_states) - - -class TimestepEmbedder(nn.Module): - """Embeds scalar timesteps into vector representations.""" - - def __init__(self, hidden_size, frequency_embedding_size=256): - super().__init__() - self.linear_1 = nn.Linear(frequency_embedding_size, hidden_size, bias=True) - self.act = nn.SiLU() - self.linear_2 = nn.Linear(hidden_size, hidden_size, bias=True) - self.frequency_embedding_size = frequency_embedding_size - self.hidden_size = hidden_size - - def _init_weights(self): - std = 1.0 / math.sqrt(self.frequency_embedding_size) - torch.nn.init.trunc_normal_(self.mlp[0].weight, std=std, a=-3 * std, b=3 * std) - torch.nn.init.zeros_(self.mlp[0].bias) - - std = 1.0 / math.sqrt(self.hidden_size) - torch.nn.init.trunc_normal_(self.mlp[2].weight, std=std, a=-3 * std, b=3 * std) - torch.nn.init.zeros_(self.mlp[2].bias) - - @staticmethod - def timestep_embedding(t, dim, max_period=10000): - half = dim // 2 - freqs = torch.exp(-math.log(max_period) * torch.arange(start=0, end=half, dtype=torch.float32) / half).to( - device=t.device - ) - args = t[:, None].float() * freqs[None] - embedding = torch.cat([torch.cos(args), torch.sin(args)], dim=-1) - if dim % 2: - embedding = torch.cat([embedding, torch.zeros_like(embedding[:, :1])], dim=-1) - return embedding - - def forward(self, t): - t_freq = self.timestep_embedding(t, self.frequency_embedding_size) - return self.linear_2(self.act(self.linear_1(t_freq))) - - -class DomainAwareLinear(nn.Module): - """Linear projection with one weight/bias pair per action embodiment domain.""" - - def __init__(self, input_size: int, output_size: int, num_domains: int) -> None: - super().__init__() - self.input_size = int(input_size) - self.output_size = int(output_size) - self.num_domains = int(num_domains) - self.fc = nn.Embedding(self.num_domains, self.output_size * self.input_size) - self.bias = nn.Embedding(self.num_domains, self.output_size) - nn.init.xavier_uniform_(self.fc.weight) - nn.init.zeros_(self.bias.weight) - - def forward(self, x: torch.Tensor, domain_id: torch.Tensor) -> torch.Tensor: - if domain_id.ndim == 0: - domain_id = domain_id.unsqueeze(0) - domain_id = domain_id.to(device=x.device, dtype=torch.long).reshape(-1) - if x.shape[0] != domain_id.shape[0]: - raise ValueError( - "Cosmos3 action domain_id batch size must match action tokens: " - f"tokens={x.shape[0]}, domain_id={domain_id.shape[0]}." - ) - if torch.any((domain_id < 0) | (domain_id >= self.num_domains)): - raise ValueError(f"Cosmos3 action domain_id must be in [0, {self.num_domains}), got {domain_id.tolist()}.") - - weight = self.fc(domain_id).view(domain_id.shape[0], self.input_size, self.output_size) - bias = self.bias(domain_id).view(domain_id.shape[0], self.output_size) - if x.ndim == 2: - return torch.bmm(x.unsqueeze(1), weight).squeeze(1) + bias - if x.ndim == 3: - return torch.bmm(x, weight) + bias.unsqueeze(1) - raise ValueError(f"Cosmos3 DomainAwareLinear expected rank-2 or rank-3 input, got {tuple(x.shape)}.") - - -class LayerTypes: - def __init__(self, is_moe: bool): - self.is_moe = is_moe - if is_moe: # TODO: moe is not yet tested - self.mlp = Qwen3VLMoeTextMLP - self.rms_norm = Qwen3VLMoeTextRMSNorm - self.rotary_embedding = Qwen3VLMoeTextRotaryEmbedding - else: - self.mlp = Cosmos3VLTextMLP - self.rms_norm = Cosmos3VLTextRMSNorm - self.rotary_embedding = Cosmos3VLTextRotaryEmbedding - - -class Cosmos3VLTextRotaryEmbedding(nn.Module): - def __init__(self, config): - super().__init__() - if hasattr(config, "rope_scaling") and config.rope_scaling is not None: - self.rope_type = config.rope_scaling.get("rope_type", "default") - else: - self.rope_type = "default" - self.max_seq_len_cached = config.max_position_embeddings - self.original_max_seq_len = config.max_position_embeddings - - self.config = config - self.rope_init_fn = ROPE_INIT_FUNCTIONS[self.rope_type] - - self.mrope_section = ( - config.rope_scaling.get("mrope_section", [24, 20, 20]) if config.rope_scaling is not None else [24, 20, 20] - ) - - def init_weights(self, buffer_device: torch.device | None = None) -> None: - inv_freq, self.attention_scaling = self.rope_init_fn(self.config, buffer_device) - self.register_buffer("inv_freq", inv_freq, persistent=False) - - def apply_interleaved_mrope(self, freqs, mrope_section): - """Apply interleaved MRoPE to 3D rotary embeddings. - Reorganizes frequency layout from chunked [TTT...HHH...WWW] to - interleaved [THTHWHTHW...TT], preserving frequency continuity. - args: - x: (3, bs, seq_len, head_dim // 2) - mrope_section: (3,) - returns: - x_t: (bs, seq_len, head_dim // 2) - """ - freqs_t = freqs[0] # just overwrite the first dimension T - for dim, offset in enumerate((1, 2), start=1): # H, W - length = mrope_section[dim] * 3 - idx = slice(offset, length, 3) - freqs_t[..., idx] = freqs[dim, ..., idx] - return freqs_t - - @torch.no_grad() - @dynamic_rope_update # power user: used with advanced RoPE types (e.g. dynamic rope) - def forward(self, x, position_ids): - assert self.inv_freq.dtype == torch.float32, f"inv_freq must be float32, but got {self.inv_freq.dtype}" - - # In contrast to other models, Cosmos3Omni has different position ids for the grids - # So we expand the inv_freq to shape (3, ...) - if position_ids.ndim == 2: - position_ids = position_ids[None, ...].expand(3, position_ids.shape[0], -1) # [3,B,N] - inv_freq_expanded = ( - self.inv_freq[None, None, :, None].float().expand(3, position_ids.shape[1], -1, 1).to(x.device) - ) # [3,B,head_dim//2,1] - position_ids_expanded = position_ids[:, :, None, :].float() # [3,B,1,N] - - freqs = (inv_freq_expanded.float() @ position_ids_expanded.float()).transpose(2, 3) # [3,B,N,head_dim//2] - freqs = self.apply_interleaved_mrope(freqs, self.mrope_section) # [B,N,head_dim//2] - emb = torch.cat((freqs, freqs), dim=-1) # [B,N,head_dim] - cos = emb.cos() * self.attention_scaling # [B,N,head_dim] - sin = emb.sin() * self.attention_scaling # [B,N,head_dim] - - return cos.to(dtype=x.dtype), sin.to(dtype=x.dtype) # each: [B,N,head_dim] - - -class Cosmos3VLTextRMSNorm(nn.Module): - def __init__(self, hidden_size: int, eps: float = 1e-6) -> None: - """ - Cosmos3VLTextRMSNorm is equivalent to T5LayerNorm - """ - super().__init__() - self.weight = nn.Parameter(torch.ones(hidden_size)) - self.variance_epsilon = eps - - def forward(self, hidden_states: torch.Tensor) -> torch.Tensor: - input_dtype = hidden_states.dtype - hidden_states = hidden_states.to(torch.float32) - variance = hidden_states.pow(2).mean(-1, keepdim=True) - hidden_states = hidden_states * torch.rsqrt(variance + self.variance_epsilon) - return self.weight * hidden_states.to(input_dtype) - - def extra_repr(self) -> str: - return f"{tuple(self.weight.shape)}, eps={self.variance_epsilon}" - - -class Cosmos3VLTextMLP(nn.Module): - def __init__(self, config): - super().__init__() - self.config = config - self.hidden_size = config.hidden_size - self.intermediate_size = config.intermediate_size - self.gate_proj = nn.Linear(self.hidden_size, self.intermediate_size, bias=False) - self.up_proj = nn.Linear(self.hidden_size, self.intermediate_size, bias=False) - self.down_proj = nn.Linear(self.intermediate_size, self.hidden_size, bias=False) - self.act_fn = ACT2FN[config.hidden_act] - - def forward(self, x): - down_proj = self.down_proj(self.act_fn(self.gate_proj(x)) * self.up_proj(x)) - return down_proj - - -class Cosmos3VLTextAttention(nn.Module): - """Multi-headed attention from 'Attention Is All You Need' paper""" - - def __init__(self, config, layer_idx: int): - super().__init__() - self.config = config - self.layer_idx = layer_idx - self.head_dim = getattr(config, "head_dim", config.hidden_size // config.num_attention_heads) - self.num_key_value_groups = config.num_attention_heads // config.num_key_value_heads - self.scaling = self.head_dim**-0.5 - self.attention_dropout = config.attention_dropout - self.is_causal = True - - self.to_q = nn.Linear( - config.hidden_size, config.num_attention_heads * self.head_dim, bias=config.attention_bias - ) - self.to_k = nn.Linear( - config.hidden_size, config.num_key_value_heads * self.head_dim, bias=config.attention_bias - ) - self.to_v = nn.Linear( - config.hidden_size, config.num_key_value_heads * self.head_dim, bias=config.attention_bias - ) - self.to_out = nn.Linear( - config.num_attention_heads * self.head_dim, config.hidden_size, bias=config.attention_bias - ) - self.norm_q = Cosmos3VLTextRMSNorm(self.head_dim, eps=config.rms_norm_eps) # unlike olmo, only on the head dim! - self.norm_k = Cosmos3VLTextRMSNorm( - self.head_dim, eps=config.rms_norm_eps - ) # thus post norm_q does not need reshape - - -class PackedAttentionMoT(Cosmos3VLTextAttention): - """ - Dual-pathway packed attention for Qwen3VL MoT (Dense version). - Implements understanding and generation pathways with separate projections. - - Note that this implementation is used for both Qwen3VL and Qwen3VL-MoE variants, - even though it derives from the dense version of Qwen3VLTextAttention. - """ - - def __init__(self, config, layer_idx: int, layer_types: LayerTypes): - super().__init__(config, layer_idx) - - # Add missing attributes for MoT compatibility - self.hidden_size = config.hidden_size - self.num_attention_heads = config.num_attention_heads - self.num_key_value_heads = config.num_key_value_heads - self.num_key_value_groups = self.num_attention_heads // self.num_key_value_heads - self.scaling = self.head_dim**-0.5 - self.attention_dropout = config.attention_dropout - - # Generation pathway projections (separate from understanding pathway) - # Qwen3VL already has query/key norms built in, so we add generation versions - self.norm_added_q = layer_types.rms_norm(self.head_dim, eps=config.rms_norm_eps) - self.norm_added_k = layer_types.rms_norm(self.head_dim, eps=config.rms_norm_eps) - - # Generation pathway linear projections - self.add_q_proj = nn.Linear( - self.hidden_size, self.num_attention_heads * self.head_dim, bias=config.attention_bias - ) - self.add_k_proj = nn.Linear( - self.hidden_size, self.num_key_value_heads * self.head_dim, bias=config.attention_bias - ) - self.add_v_proj = nn.Linear( - self.hidden_size, self.num_key_value_heads * self.head_dim, bias=config.attention_bias - ) - self.to_add_out = nn.Linear( - self.num_attention_heads * self.head_dim, self.hidden_size, bias=config.attention_bias - ) - self.dispatch_attention_fn = CosmosAttnProcessor3_0() - self.cp_mesh = None - - def forward( - self, - pack: FactoredSequencePack, - attention_mask, - packed_position_embeddings: Tuple[FactoredSequencePack, FactoredSequencePack], - dual_kv_cache=None, - natten_metadata: dict | None = None, - ) -> FactoredSequencePack: - """Forward pass with optional KV cache for autoregressive generation. - - This method is used for frame 0 where we store K/V for both und and gen tokens. - For frame 1+, forward_with_kv_cache() is used instead (optimized path). - - Args: - pack: Packed sequence with und/gen tokens - attention_mask: Attention mask (BlockMask or SplitInfo) - packed_position_embeddings: RoPE embeddings (cos, sin) - dual_kv_cache: Optional dual KV cache for AR generation (frame 0). - """ - - q_und_in = self.to_q(get_und_seq(pack)) # [N_und,num_heads*head_dim] - q_gen_in = self.add_q_proj(get_gen_seq(pack)) # [N_gen,num_heads*head_dim] - - k_und_in = self.to_k(get_und_seq(pack)) # [N_und,num_kv_heads*head_dim] - k_gen_in = self.add_k_proj(get_gen_seq(pack)) # [N_gen,num_kv_heads*head_dim] - - v_und_in = self.to_v(get_und_seq(pack)) # [N_und,num_kv_heads*head_dim] - v_gen_in = self.add_v_proj(get_gen_seq(pack)) # [N_gen,num_kv_heads*head_dim] - - q_und = q_und_in.view(-1, self.num_attention_heads, self.head_dim) # [N_und,num_heads,head_dim] - k_und = k_und_in.view(-1, self.num_key_value_heads, self.head_dim) # [N_und,num_kv_heads,head_dim] - v_und = v_und_in.view(-1, self.num_key_value_heads, self.head_dim) # [N_und,num_kv_heads,head_dim] - - q_gen = q_gen_in.view(-1, self.num_attention_heads, self.head_dim) # [N_gen,num_heads,head_dim] - k_gen = k_gen_in.view(-1, self.num_key_value_heads, self.head_dim) # [N_gen,num_kv_heads,head_dim] - v_gen = v_gen_in.view(-1, self.num_key_value_heads, self.head_dim) # [N_gen,num_kv_heads,head_dim] - - q_und = self.norm_q(q_und) # [N_und,num_heads,head_dim] - k_und = self.norm_k(k_und) # [N_und,num_kv_heads,head_dim] - - q_gen = self.norm_added_q(q_gen) # [N_gen,num_heads,head_dim] - k_gen = self.norm_added_k(k_gen) # [N_gen,num_kv_heads,head_dim] - - if self.config.freeze_und: - q_und = q_und.detach() - k_und = k_und.detach() - v_und = v_und.detach() - - # Attempted port: Apply RoPE (BAGEL qwen-2.5) - # Note: Position embeddings are now pre-squeezed at model level - packed_cos = packed_position_embeddings[0] - packed_sin = packed_position_embeddings[1] - - q_und_, k_und_ = apply_rotary_pos_emb( - q_und, - k_und, - get_und_seq(packed_cos), - get_und_seq(packed_sin), - unsqueeze_dim=1, - ) # q_und_: [N_und,num_heads,head_dim], k_und_: [N_und,num_kv_heads,head_dim] - q_gen_, k_gen_ = apply_rotary_pos_emb( - q_gen, - k_gen, - get_gen_seq(packed_cos), - get_gen_seq(packed_sin), - unsqueeze_dim=1, - ) # q_gen_: [N_gen,num_heads,head_dim], k_gen_: [N_gen,num_kv_heads,head_dim] - - # === KV CACHE INTEGRATION FOR AUTOREGRESSIVE GENERATION === - # Frame 0: Store und and gen K/V (no fetching) - # Apply cache after RoPE (cached keys already have positional info) - # CP path: storage happens inside context_parallel_attention() after all-to-all, - # so tensors are stored head-sharded [1,S,H/cp,D]. - # Non-CP path: store here as [1,S,H,D] for fetch_kv() dim=1 compat. - if dual_kv_cache is not None and self.cp_mesh is None: - und_len = pack["_num_causal_tokens"] - gen_len = pack["_num_full_tokens"] - if not dual_kv_cache.und_cache.is_initialized: - dual_kv_cache.und_cache.store( - k_und_[:und_len].unsqueeze(0), v_und[:und_len].unsqueeze(0) - ) # [1,S_und,H,D] - dual_kv_cache.gen_cache.store_kv( - k_gen_[:gen_len].unsqueeze(0), v_gen[:gen_len].unsqueeze(0), frame_idx=0 - ) # [1,S_gen,H,D] - - packed_query_states_ = from_und_gen_splits(q_und_, q_gen_, pack) # [N_und+N_gen,num_heads,head_dim] - packed_key_states_ = from_und_gen_splits(k_und_, k_gen_, pack) # [N_und+N_gen,num_kv_heads,head_dim] - packed_value_states_ = from_und_gen_splits(v_und, v_gen, pack) # [N_und+N_gen,num_kv_heads,head_dim] - - # CP: pass dual_kv_cache so context_parallel_attention() stores head-sharded K/V - dispatch_kwargs: dict = {} - if self.cp_mesh is not None and dual_kv_cache is not None: - dispatch_kwargs["dual_kv_cache"] = dual_kv_cache - dispatch_kwargs["frame_idx"] = 0 - - packed_attn_output = self.dispatch_attention_fn( - packed_query_states_, - packed_key_states_, - packed_value_states_, - ) - - # Apply projections directly to get final results - und_seq = self.to_out(get_und_seq(packed_attn_output)) # [N_und,hidden_size] - gen_seq = self.to_add_out(get_gen_seq(packed_attn_output)) # [N_gen,hidden_size] - return from_und_gen_splits(und_seq, gen_seq, pack) # [N_und+N_gen,hidden_size] - - -class Cosmos3VLTextMoTDecoderLayer(nn.Module): - """ - Qwen3VL text MoT (Mixture of Tokens) decoder layer. - Features dual-pathway attention for understanding vs generation. - - This is used for both Dense and MoE models. - """ - - def __init__( - self, - config, - layer_idx: int, - layer_types: LayerTypes, - ): - super().__init__() - self.hidden_size = config.hidden_size - self.freeze_und = config.freeze_und - self.self_attn = PackedAttentionMoT(config, layer_idx, layer_types) - - # TODO: Qwen3VLMoeTextSparseMoeBlock not supported yet - self.mlp = layer_types.mlp(config) - self.mlp_moe_gen = layer_types.mlp(config) - - self.input_layernorm = layer_types.rms_norm(config.hidden_size, eps=config.rms_norm_eps) - self.input_layernorm_moe_gen = layer_types.rms_norm(config.hidden_size, eps=config.rms_norm_eps) - self.post_attention_layernorm = layer_types.rms_norm(config.hidden_size, eps=config.rms_norm_eps) - self.post_attention_layernorm_moe_gen = layer_types.rms_norm(config.hidden_size, eps=config.rms_norm_eps) - - def forward( - self, - input: FactoredSequencePack, - attention_mask, - packed_position_embeddings: Tuple[FactoredSequencePack, FactoredSequencePack], - dual_kv_cache: None = None, - frame_idx: Optional[int] = None, - natten_metadata: dict | None = None, - ) -> FactoredSequencePack: - """Training forward pass with MoT routing - Attempted port from qwen2_mot - - Args: - input: Packed sequence with und/gen tokens - attention_mask: Attention mask - packed_position_embeddings: RoPE embeddings (cos, sin) - dual_kv_cache: Optional dual KV cache for AR generation - frame_idx: Current frame index (default: None, treated as 0) - """ - - # Handle None frame_idx as 0 - if frame_idx is None: - frame_idx = 0 - - # TODO: support gen_only = True and AR generation - gen_only = False - # if dual_kv_cache is not None and isinstance(dual_kv_cache, DualKVCache): - # gen_only = frame_idx > 0 and dual_kv_cache.und_cache.is_initialized - - # Pre-Attention layernorm - pack_norm_out = from_und_gen_splits( - self.input_layernorm(get_und_seq(input)), # [N_und,hidden_size] - self.input_layernorm_moe_gen(get_gen_seq(input)), # [N_gen,hidden_size] - input, - ) # [N_und+N_gen,hidden_size] - - # STANDARD PATH: Process both und and gen tokens (frame 0) - pack_attn_out = self.self_attn( - pack_norm_out, - attention_mask, - packed_position_embeddings, - dual_kv_cache, - natten_metadata=natten_metadata, - ) - residual_und = get_und_seq(input) + get_und_seq(pack_attn_out) # [N_und,hidden_size] - residual_gen = get_gen_seq(input) + get_gen_seq(pack_attn_out) # [N_gen,hidden_size] - - # STANDARD PATH: Process both und and gen tokens - ln_out_und = self.post_attention_layernorm(residual_und) # [N_und,hidden_size] - ln_out_gen = self.post_attention_layernorm_moe_gen(residual_gen) # [N_gen,hidden_size] - - # UNPAD MLP INPUT =============== - # NOTE: This is only need for the MoE auxiliary loss computation and to avoid - # artificial expert inbalance due to routing padding tokens. - gen_len = pack_attn_out["_num_full_tokens"] - und_len = pack_attn_out["_num_causal_tokens"] - ln_out_und_unpadded = ln_out_und[:und_len] # [N_und_unpadded,hidden_size] - ln_out_gen_unpadded = ln_out_gen[:gen_len] # [N_gen_unpadded,hidden_size] - - mlp_out_und_unpadded = self.mlp(ln_out_und_unpadded) # [N_und_unpadded,hidden_size] - mlp_out_gen_unpadded = self.mlp_moe_gen(ln_out_gen_unpadded) # [N_gen_unpadded,hidden_size] - - # PAD MLP OUTPUT =============== - mlp_out_und = torch.cat([mlp_out_und_unpadded, ln_out_und[und_len:]], dim=0) # [N_und,hidden_size] - mlp_out_gen = torch.cat([mlp_out_gen_unpadded, ln_out_gen[gen_len:]], dim=0) # [N_gen,hidden_size] - - mlp_out_und_seq = residual_und + mlp_out_und # [N_und,hidden_size] - mlp_out_gen_seq = residual_gen + mlp_out_gen # [N_gen,hidden_size] - - return from_und_gen_splits(mlp_out_und_seq, mlp_out_gen_seq, input) - - -class Cosmos3OmniTransformer(ModelMixin, ConfigMixin): - @register_to_config - def __init__( - self, - attention_bias: bool = False, - attention_dropout: float = 0.0, - dtype: str = "bfloat16", - freeze_und: bool = False, - head_dim: int = 128, - hidden_act: str = "silu", - hidden_size: int = 4096, - initializer_range: float = 0.02, - intermediate_size: int = 12288, - base_fps: int = 24, - enable_fps_modulation: bool = True, - joint_attn_implementation: str = "two_way", - latent_channel: int = 48, - action_dim: int | None = None, - action_gen: bool = False, - max_action_dim: int = 32, - num_embodiment_domains: int = 32, - position_embedding_type: str = "unified_3d_mrope", - unified_3d_mrope_reset_spatial_ids: bool = True, - unified_3d_mrope_temporal_modality_margin: int = 15000, - video_temporal_causal: bool = False, - latent_patch_size: int = 2, - max_position_embeddings: int = 262144, - model_type: str = "qwen3_vl_text", - num_attention_heads: int = 32, - num_hidden_layers: int = 36, - num_key_value_heads: int = 8, - patch_latent_dim: int = 192, - qk_norm: bool = False, - qk_norm_for_diffusion: bool = True, - qk_norm_for_text: bool = True, - rms_norm_eps: float = 1e-6, - rope_scaling: dict | None = None, - rope_theta: float = 5000000.0, - sound_dim: int | None = None, - sound_gen: bool = False, - sound_latent_fps: float = 25.0, - temporal_compression_factor_sound: int = 1, - timestep_scale: float = 0.001, - use_cache: bool = True, - use_moe: bool = True, - vocab_size: int = 151936, - ): - super().__init__() - - if rope_scaling is None: - rope_scaling = {"mrope_interleaved": True, "mrope_section": [24, 20, 20], "rope_type": "default"} - self.register_to_config(rope_scaling=rope_scaling) - - layer_types = LayerTypes(is_moe=False) - self.embed_tokens = nn.Embedding(self.config.vocab_size, self.config.hidden_size) - self.layers = nn.ModuleList( - [ - Cosmos3VLTextMoTDecoderLayer(self.config, layer_idx, layer_types) - for layer_idx in range(self.config.num_hidden_layers) - ] - ) - # Understanding pathway final norm - self.norm = layer_types.rms_norm(self.config.hidden_size, eps=self.config.rms_norm_eps) - # Generation pathway final norm - self.norm_moe_gen = layer_types.rms_norm(self.config.hidden_size, eps=self.config.rms_norm_eps) - self.rotary_emb = Cosmos3VLTextRotaryEmbedding(config=self.config) - self.vocab_size = vocab_size - self.action_gen = action_gen - self.action_dim = int(max_action_dim if action_dim is None else action_dim) - self.num_embodiment_domains = int(num_embodiment_domains) - self.lm_head = nn.Linear(hidden_size, vocab_size, bias=False) - self.proj_in = nn.Linear(patch_latent_dim, hidden_size, bias=True) - self.proj_out = nn.Linear(hidden_size, patch_latent_dim, bias=True) - self.time_embedder = TimestepEmbedder(hidden_size) - if action_gen: - self.action_proj_in = DomainAwareLinear(self.action_dim, hidden_size, self.num_embodiment_domains) - self.action_proj_out = DomainAwareLinear(hidden_size, self.action_dim, self.num_embodiment_domains) - self.action_modality_embed = nn.Parameter(torch.zeros(hidden_size)) - if sound_gen: - if sound_dim is None: - raise ValueError("`sound_dim` must be provided when `sound_gen=True`.") - self.audio_proj_in = nn.Linear(sound_dim, hidden_size, bias=True) - self.audio_proj_out = nn.Linear(hidden_size, sound_dim, bias=True) - self.audio_modality_embed = nn.Parameter(torch.zeros(hidden_size)) - - @classmethod - def from_pretrained(cls, pretrained_model_name_or_path, **kwargs): - model = super().from_pretrained(pretrained_model_name_or_path, **kwargs) - # inv_freq is a non-persistent buffer absent from the saved state_dict. - # Initialize it on CPU; it will move to the correct device with .to() / .cuda(). - model.rotary_emb.init_weights(buffer_device=None) - return model - - def forward( - self, - pack: FactoredSequencePack, - attention_mask, - position_ids: torch.Tensor, - dual_kv_cache: None = None, - frame_idx: Optional[int] = None, - natten_metadata_list: list | None = None, - ) -> Tuple[FactoredSequencePack, None]: - """Training forward pass - simplified to match qwen3_mot. - - Returns: - (outputs, None) — the None placeholder mirrors the (packed_outputs, lbl_metadata) - tuple returned by the original language_model so callers can unpack both. - """ - # Handle None frame_idx as 0 - if frame_idx is None: - frame_idx = 0 - - # Create position embeddings (Qwen3 style) - squeeze once at model level - # tensor below is only used for its dtype and device - device, dtype = get_device_and_dtype(pack) - _meta_tensor = torch.tensor([], dtype=dtype, device=device) # [0] - cos, sin = self.rotary_emb( - _meta_tensor, - position_ids=position_ids.unsqueeze(0) if position_ids.ndim == 1 else position_ids.unsqueeze(1), - ) # if ndim == 2, then the mrope position_ids is (3, seq_len), we need to put batch dimension in the middle to make it compatible with the rotary_emb - # cos, sin: [1,N,head_dim] (1D pos_ids) or [3,1,N,head_dim] (mrope pos_ids) - cos = cos.squeeze(0) # [N,head_dim] or [3,N,head_dim] - sin = sin.squeeze(0) # [N,head_dim] or [3,N,head_dim] - position_embeddings = ( - from_joint(cos, pack), - from_joint(sin, pack), - ) - - # TODO: Add lbl_metadata_all (we don't need it at inference) - hidden_states = pack - - for i, decoder_layer in enumerate(self.layers): - hidden_states = decoder_layer( - hidden_states, - attention_mask, - position_embeddings, - dual_kv_cache[i] if dual_kv_cache is not None else None, - frame_idx, - natten_metadata=None if natten_metadata_list is None else natten_metadata_list[i], - ) - - outputs = zeros_like(hidden_states) # [N_und+N_gen,hidden_size] - set_und_seq(outputs, self.norm(get_und_seq(hidden_states))) # [N_und,hidden_size] - set_gen_seq(outputs, self.norm_moe_gen(get_gen_seq(hidden_states))) # [N_gen,hidden_size] - return outputs, None - - -@use_kernel_forward_from_hub("RMSNorm") -class Qwen3VLMoeTextRMSNorm(nn.Module): - def __init__(self, hidden_size, eps=1e-6): - """ - Qwen3VLMoeTextRMSNorm is equivalent to T5LayerNorm - """ - super().__init__() - self.weight = nn.Parameter(torch.ones(hidden_size)) - self.variance_epsilon = eps - - def forward(self, hidden_states): - input_dtype = hidden_states.dtype - hidden_states = hidden_states.to(torch.float32) - variance = hidden_states.pow(2).mean(-1, keepdim=True) - hidden_states = hidden_states * torch.rsqrt(variance + self.variance_epsilon) - return self.weight * hidden_states.to(input_dtype) - - def extra_repr(self): - return f"{tuple(self.weight.shape)}, eps={self.variance_epsilon}" - - -class Qwen3VLMoeTextMLP(nn.Module): - def __init__(self, config): - super().__init__() - self.config = config - self.hidden_size = config.hidden_size - self.intermediate_size = config.intermediate_size - self.gate_proj = nn.Linear(self.hidden_size, self.intermediate_size, bias=False) - self.up_proj = nn.Linear(self.hidden_size, self.intermediate_size, bias=False) - self.down_proj = nn.Linear(self.intermediate_size, self.hidden_size, bias=False) - self.act_fn = ACT2FN[config.hidden_act] - - def forward(self, x): - down_proj = self.down_proj(self.act_fn(self.gate_proj(x)) * self.up_proj(x)) - return down_proj - - -class Qwen3VLMoeTextRotaryEmbedding(nn.Module): - def __init__(self, config): - super().__init__() - if hasattr(config, "rope_scaling") and config.rope_scaling is not None: - self.rope_type = config.rope_scaling.get("rope_type", "default") - else: - self.rope_type = "default" - self.max_seq_len_cached = config.max_position_embeddings - self.original_max_seq_len = config.max_position_embeddings - self.mrope_section = config.rope_scaling.get("mrope_section", [24, 20, 20]) - - self.config = config - self.rope_init_fn = ROPE_INIT_FUNCTIONS[self.rope_type] - - def init_weights(self, buffer_device: torch.device | None = None) -> None: - inv_freq, self.attention_scaling = self.rope_init_fn(self.config, buffer_device) - self.register_buffer("inv_freq", inv_freq, persistent=False) - - def apply_interleaved_mrope(self, freqs, mrope_section): - """Apply interleaved MRoPE to 3D rotary embeddings. - Reorganizes frequency layout from chunked [TTT...HHH...WWW] to - interleaved [THTHWHTHW...TT], preserving frequency continuity. - args: - x: (3, bs, seq_len, head_dim // 2) - mrope_section: (3,) - returns: - x_t: (bs, seq_len, head_dim // 2) - """ - freqs_t = freqs[0] # just overwrite the first dimension T - for dim, offset in enumerate((1, 2), start=1): # H, W - length = mrope_section[dim] * 3 - idx = slice(offset, length, 3) - freqs_t[..., idx] = freqs[dim, ..., idx] - return freqs_t - - @torch.no_grad() - @dynamic_rope_update # power user: used with advanced RoPE types (e.g. dynamic rope) - def forward(self, x, position_ids): - assert self.inv_freq.dtype == torch.float32, f"inv_freq must be float32, but got {self.inv_freq.dtype}" - - # In contrast to other models, Qwen3VLMoe has different position ids for the grids - # So we expand the inv_freq to shape (3, ...) - if position_ids.ndim == 2: - position_ids = position_ids[None, ...].expand(3, position_ids.shape[0], -1) # [3,B,N] - inv_freq_expanded = ( - self.inv_freq[None, None, :, None].float().expand(3, position_ids.shape[1], -1, 1) - ) # [3,B,head_dim//2,1] - position_ids_expanded = position_ids[:, :, None, :].float() # [3,B,1,N] - - freqs = (inv_freq_expanded.float() @ position_ids_expanded.float()).transpose(2, 3) # [3,B,N,head_dim//2] - freqs = self.apply_interleaved_mrope(freqs, self.mrope_section) # [B,N,head_dim//2] - emb = torch.cat((freqs, freqs), dim=-1) # [B,N,head_dim] - cos = emb.cos() * self.attention_scaling # [B,N,head_dim] - sin = emb.sin() * self.attention_scaling # [B,N,head_dim] - - return cos.to(dtype=x.dtype), sin.to(dtype=x.dtype) diff --git a/packages/diffusers-cosmos3/pyproject.toml b/packages/diffusers-cosmos3/pyproject.toml deleted file mode 100644 index edf6500d..00000000 --- a/packages/diffusers-cosmos3/pyproject.toml +++ /dev/null @@ -1,13 +0,0 @@ -# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: OpenMDW-1.1 - -[build-system] -requires = ["hatchling"] -build-backend = "hatchling.build" - -[project] -name = "diffusers-cosmos3" -version = "0.1.0" -description = "diffusers plugin that loads Cosmos3 checkpoints" -requires-python = ">=3.10" -dependencies = ["diffusers>=0.37.0"] diff --git a/packages/diffusers-cosmos3/scripts/inference_example.py b/packages/diffusers-cosmos3/scripts/inference_example.py deleted file mode 100755 index ec145319..00000000 --- a/packages/diffusers-cosmos3/scripts/inference_example.py +++ /dev/null @@ -1,79 +0,0 @@ -#!/usr/bin/env python3 -# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: OpenMDW-1.1 -""" -Load a Cosmos3 diffusers pipeline from a converted checkpoint and run inference. - -CUDA_VISIBLE_DEVICES=0 python inference_cosmos3.py \ - --pipeline-path converted/cosmos3-nano-pipeline \ - --input inputs/omni/i2v.json - -The pipeline must have been produced by convert_cosmos3_to_diffusers.py -with --save-pipeline. -""" - -import argparse -import json -import pathlib - -import torch -from diffusers_cosmos3 import Cosmos3OmniDiffusersPipeline -from diffusers_cosmos3.pipeline import save_img_or_video - - -def main(): - parser = argparse.ArgumentParser(description=__doc__) - parser.add_argument( - "--pipeline-path", - default="converted/cosmos3-nano-pipeline", - help="Path to directory saved by cosmos_convert_cosmos_to_diffusers.py --save-pipeline.", - ) - parser.add_argument( - "--input", - default="inputs/omni/i2v.json", - help="Path to JSON input file with 'prompt' and optional 'vision_path'.", - ) - parser.add_argument("--output", default=".", help="Directory to save generated video/image files.") - parser.add_argument("--height", type=int, default=720) - parser.add_argument("--width", type=int, default=1280) - parser.add_argument("--num-frames", type=int, default=189) - args = parser.parse_args() - - pipeline_path = pathlib.Path(args.pipeline_path) - print(f"Loading pipeline from {pipeline_path} …") - pipeline = Cosmos3OmniDiffusersPipeline.from_pretrained( - str(pipeline_path), - torch_dtype=torch.bfloat16, - device_map="cuda", - ) - print("Pipeline loaded successfully.") - - # --- Load JSON input --- - input_path = pathlib.Path(args.input) - print(f"Loading input from {input_path} …") - with open(input_path) as f: - input_data = json.load(f) - prompt = input_data["prompt"] - vision_path = input_data.get("vision_path", None) - - output_dir = pathlib.Path(args.output) - output_dir.mkdir(parents=True, exist_ok=True) - - result_vision = pipeline( - prompt=prompt, - image=vision_path, - num_frames=args.num_frames, - height=args.height, - width=args.width, - output_type="latent", - ) - - result_frames = pipeline.decode_latents(result_vision) - for i, frames in enumerate(result_frames): - save_path = str(output_dir / f"sample-{i}") - save_img_or_video(frames, save_path) - print(f"Saved: {save_path}.mp4") - - -if __name__ == "__main__": - main() diff --git a/packages/diffusers-cosmos3/uv.lock b/packages/diffusers-cosmos3/uv.lock deleted file mode 100644 index ef5f4413..00000000 --- a/packages/diffusers-cosmos3/uv.lock +++ /dev/null @@ -1,924 +0,0 @@ -version = 1 -revision = 3 -requires-python = ">=3.10" -resolution-markers = [ - "python_full_version >= '3.11'", - "python_full_version < '3.11'", -] - -[[package]] -name = "annotated-doc" -version = "0.0.4" -source = { registry = "https://pypi.org/simple" } -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/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]] -name = "anyio" -version = "4.13.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, - { name = "idna" }, - { name = "typing-extensions", marker = "python_full_version < '3.13'" }, -] -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" }, -] - -[[package]] -name = "certifi" -version = "2026.5.20" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f3/ce/ee2ecad540810a79593028e88299baeae54d346cc7a0d94b6199988b89b1/certifi-2026.5.20.tar.gz", hash = "sha256:69dea482ab64caa7b9f6aba1c6bf48bb6a5448d1c0f1b17ab42ad8c763a5344d", size = 135422, upload-time = "2026-05-20T11:46:50.073Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/59/8c/57e832b7af6d7c5abe66eb3fbe3a3a32f4d11ea23a1aa7131371035be991/certifi-2026.5.20-py3-none-any.whl", hash = "sha256:3c52e209ba0a4ad7aebe60436a4ab349c39e1e602e8c134221e546902ad25897", size = 134134, upload-time = "2026-05-20T11:46:48.578Z" }, -] - -[[package]] -name = "charset-normalizer" -version = "3.4.7" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e7/a1/67fe25fac3c7642725500a3f6cfe5821ad557c3abb11c9d20d12c7008d3e/charset_normalizer-3.4.7.tar.gz", hash = "sha256:ae89db9e5f98a11a4bf50407d4363e7b09b31e55bc117b4f7d80aab97ba009e5", size = 144271, upload-time = "2026-04-02T09:28:39.342Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/26/08/0f303cb0b529e456bb116f2d50565a482694fbb94340bf56d44677e7ed03/charset_normalizer-3.4.7-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:cdd68a1fb318e290a2077696b7eb7a21a49163c455979c639bf5a5dcdc46617d", size = 315182, upload-time = "2026-04-02T09:25:40.673Z" }, - { url = "https://files.pythonhosted.org/packages/24/47/b192933e94b546f1b1fe4df9cc1f84fcdbf2359f8d1081d46dd029b50207/charset_normalizer-3.4.7-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e17b8d5d6a8c47c85e68ca8379def1303fd360c3e22093a807cd34a71cd082b8", size = 209329, upload-time = "2026-04-02T09:25:42.354Z" }, - { url = "https://files.pythonhosted.org/packages/c2/b4/01fa81c5ca6141024d89a8fc15968002b71da7f825dd14113207113fabbd/charset_normalizer-3.4.7-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:511ef87c8aec0783e08ac18565a16d435372bc1ac25a91e6ac7f5ef2b0bff790", size = 231230, upload-time = "2026-04-02T09:25:44.281Z" }, - { url = "https://files.pythonhosted.org/packages/20/f7/7b991776844dfa058017e600e6e55ff01984a063290ca5622c0b63162f68/charset_normalizer-3.4.7-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:007d05ec7321d12a40227aae9e2bc6dca73f3cb21058999a1df9e193555a9dcc", size = 225890, upload-time = "2026-04-02T09:25:45.475Z" }, - { url = "https://files.pythonhosted.org/packages/20/e7/bed0024a0f4ab0c8a9c64d4445f39b30c99bd1acd228291959e3de664247/charset_normalizer-3.4.7-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:cf29836da5119f3c8a8a70667b0ef5fdca3bb12f80fd06487cfa575b3909b393", size = 216930, upload-time = "2026-04-02T09:25:46.58Z" }, - { url = "https://files.pythonhosted.org/packages/e2/ab/b18f0ab31cdd7b3ddb8bb76c4a414aeb8160c9810fdf1bc62f269a539d87/charset_normalizer-3.4.7-cp310-cp310-manylinux_2_31_armv7l.whl", hash = "sha256:12d8baf840cc7889b37c7c770f478adea7adce3dcb3944d02ec87508e2dcf153", size = 202109, upload-time = "2026-04-02T09:25:48.031Z" }, - { url = "https://files.pythonhosted.org/packages/82/e5/7e9440768a06dfb3075936490cb82dbf0ee20a133bf0dd8551fa096914ec/charset_normalizer-3.4.7-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:d560742f3c0d62afaccf9f41fe485ed69bd7661a241f86a3ef0f0fb8b1a397af", size = 214684, upload-time = "2026-04-02T09:25:49.245Z" }, - { url = "https://files.pythonhosted.org/packages/71/94/8c61d8da9f062fdf457c80acfa25060ec22bf1d34bbeaca4350f13bcfd07/charset_normalizer-3.4.7-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:b14b2d9dac08e28bb8046a1a0434b1750eb221c8f5b87a68f4fa11a6f97b5e34", size = 212785, upload-time = "2026-04-02T09:25:50.671Z" }, - { url = "https://files.pythonhosted.org/packages/66/cd/6e9889c648e72c0ab2e5967528bb83508f354d706637bc7097190c874e13/charset_normalizer-3.4.7-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:bc17a677b21b3502a21f66a8cc64f5bfad4df8a0b8434d661666f8ce90ac3af1", size = 203055, upload-time = "2026-04-02T09:25:51.802Z" }, - { url = "https://files.pythonhosted.org/packages/92/2e/7a951d6a08aefb7eb8e1b54cdfb580b1365afdd9dd484dc4bee9e5d8f258/charset_normalizer-3.4.7-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:750e02e074872a3fad7f233b47734166440af3cdea0add3e95163110816d6752", size = 232502, upload-time = "2026-04-02T09:25:53.388Z" }, - { url = "https://files.pythonhosted.org/packages/58/d5/abcf2d83bf8e0a1286df55cd0dc1d49af0da4282aa77e986df343e7de124/charset_normalizer-3.4.7-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:4e5163c14bffd570ef2affbfdd77bba66383890797df43dc8b4cc7d6f500bf53", size = 214295, upload-time = "2026-04-02T09:25:54.765Z" }, - { url = "https://files.pythonhosted.org/packages/47/3a/7d4cd7ed54be99973a0dc176032cba5cb1f258082c31fa6df35cff46acfc/charset_normalizer-3.4.7-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:6ed74185b2db44f41ef35fd1617c5888e59792da9bbc9190d6c7300617182616", size = 227145, upload-time = "2026-04-02T09:25:55.904Z" }, - { url = "https://files.pythonhosted.org/packages/1d/98/3a45bf8247889cf28262ebd3d0872edff11565b2a1e3064ccb132db3fbb0/charset_normalizer-3.4.7-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:94e1885b270625a9a828c9793b4d52a64445299baa1fea5a173bf1d3dd9a1a5a", size = 218884, upload-time = "2026-04-02T09:25:57.074Z" }, - { url = "https://files.pythonhosted.org/packages/ad/80/2e8b7f8915ed5c9ef13aa828d82738e33888c485b65ebf744d615040c7ea/charset_normalizer-3.4.7-cp310-cp310-win32.whl", hash = "sha256:6785f414ae0f3c733c437e0f3929197934f526d19dfaa75e18fdb4f94c6fb374", size = 148343, upload-time = "2026-04-02T09:25:58.199Z" }, - { url = "https://files.pythonhosted.org/packages/35/1b/3b8c8c77184af465ee9ad88b5aea46ea6b2e1f7b9dc9502891e37af21e30/charset_normalizer-3.4.7-cp310-cp310-win_amd64.whl", hash = "sha256:6696b7688f54f5af4462118f0bfa7c1621eeb87154f77fa04b9295ce7a8f2943", size = 159174, upload-time = "2026-04-02T09:25:59.322Z" }, - { url = "https://files.pythonhosted.org/packages/be/c1/feb40dca40dbb21e0a908801782d9288c64fc8d8e562c2098e9994c8c21b/charset_normalizer-3.4.7-cp310-cp310-win_arm64.whl", hash = "sha256:66671f93accb62ed07da56613636f3641f1a12c13046ce91ffc923721f23c008", size = 147805, upload-time = "2026-04-02T09:26:00.756Z" }, - { url = "https://files.pythonhosted.org/packages/c2/d7/b5b7020a0565c2e9fa8c09f4b5fa6232feb326b8c20081ccded47ea368fd/charset_normalizer-3.4.7-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:7641bb8895e77f921102f72833904dcd9901df5d6d72a2ab8f31d04b7e51e4e7", size = 309705, upload-time = "2026-04-02T09:26:02.191Z" }, - { url = "https://files.pythonhosted.org/packages/5a/53/58c29116c340e5456724ecd2fff4196d236b98f3da97b404bc5e51ac3493/charset_normalizer-3.4.7-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:202389074300232baeb53ae2569a60901f7efadd4245cf3a3bf0617d60b439d7", size = 206419, upload-time = "2026-04-02T09:26:03.583Z" }, - { url = "https://files.pythonhosted.org/packages/b2/02/e8146dc6591a37a00e5144c63f29fb7c97a734ea8a111190783c0e60ab63/charset_normalizer-3.4.7-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:30b8d1d8c52a48c2c5690e152c169b673487a2a58de1ec7393196753063fcd5e", size = 227901, upload-time = "2026-04-02T09:26:04.738Z" }, - { url = "https://files.pythonhosted.org/packages/fb/73/77486c4cd58f1267bf17db420e930c9afa1b3be3fe8c8b8ebbebc9624359/charset_normalizer-3.4.7-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:532bc9bf33a68613fd7d65e4b1c71a6a38d7d42604ecf239c77392e9b4e8998c", size = 222742, upload-time = "2026-04-02T09:26:06.36Z" }, - { url = "https://files.pythonhosted.org/packages/a1/fa/f74eb381a7d94ded44739e9d94de18dc5edc9c17fb8c11f0a6890696c0a9/charset_normalizer-3.4.7-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2fe249cb4651fd12605b7288b24751d8bfd46d35f12a20b1ba33dea122e690df", size = 214061, upload-time = "2026-04-02T09:26:08.347Z" }, - { url = "https://files.pythonhosted.org/packages/dc/92/42bd3cefcf7687253fb86694b45f37b733c97f59af3724f356fa92b8c344/charset_normalizer-3.4.7-cp311-cp311-manylinux_2_31_armv7l.whl", hash = "sha256:65bcd23054beab4d166035cabbc868a09c1a49d1efe458fe8e4361215df40265", size = 199239, upload-time = "2026-04-02T09:26:09.823Z" }, - { url = "https://files.pythonhosted.org/packages/4c/3d/069e7184e2aa3b3cddc700e3dd267413dc259854adc3380421c805c6a17d/charset_normalizer-3.4.7-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:08e721811161356f97b4059a9ba7bafb23ea5ee2255402c42881c214e173c6b4", size = 210173, upload-time = "2026-04-02T09:26:10.953Z" }, - { url = "https://files.pythonhosted.org/packages/62/51/9d56feb5f2e7074c46f93e0ebdbe61f0848ee246e2f0d89f8e20b89ebb8f/charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:e060d01aec0a910bdccb8be71faf34e7799ce36950f8294c8bf612cba65a2c9e", size = 209841, upload-time = "2026-04-02T09:26:12.142Z" }, - { url = "https://files.pythonhosted.org/packages/d2/59/893d8f99cc4c837dda1fe2f1139079703deb9f321aabcb032355de13b6c7/charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:38c0109396c4cfc574d502df99742a45c72c08eff0a36158b6f04000043dbf38", size = 200304, upload-time = "2026-04-02T09:26:13.711Z" }, - { url = "https://files.pythonhosted.org/packages/7d/1d/ee6f3be3464247578d1ed5c46de545ccc3d3ff933695395c402c21fa6b77/charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:1c2a768fdd44ee4a9339a9b0b130049139b8ce3c01d2ce09f67f5a68048d477c", size = 229455, upload-time = "2026-04-02T09:26:14.941Z" }, - { url = "https://files.pythonhosted.org/packages/54/bb/8fb0a946296ea96a488928bdce8ef99023998c48e4713af533e9bb98ef07/charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:1a87ca9d5df6fe460483d9a5bbf2b18f620cbed41b432e2bddb686228282d10b", size = 210036, upload-time = "2026-04-02T09:26:16.478Z" }, - { url = "https://files.pythonhosted.org/packages/9a/bc/015b2387f913749f82afd4fcba07846d05b6d784dd16123cb66860e0237d/charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:d635aab80466bc95771bb78d5370e74d36d1fe31467b6b29b8b57b2a3cd7d22c", size = 224739, upload-time = "2026-04-02T09:26:17.751Z" }, - { url = "https://files.pythonhosted.org/packages/17/ab/63133691f56baae417493cba6b7c641571a2130eb7bceba6773367ab9ec5/charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ae196f021b5e7c78e918242d217db021ed2a6ace2bc6ae94c0fc596221c7f58d", size = 216277, upload-time = "2026-04-02T09:26:18.981Z" }, - { url = "https://files.pythonhosted.org/packages/06/6d/3be70e827977f20db77c12a97e6a9f973631a45b8d186c084527e53e77a4/charset_normalizer-3.4.7-cp311-cp311-win32.whl", hash = "sha256:adb2597b428735679446b46c8badf467b4ca5f5056aae4d51a19f9570301b1ad", size = 147819, upload-time = "2026-04-02T09:26:20.295Z" }, - { url = "https://files.pythonhosted.org/packages/20/d9/5f67790f06b735d7c7637171bbfd89882ad67201891b7275e51116ed8207/charset_normalizer-3.4.7-cp311-cp311-win_amd64.whl", hash = "sha256:8e385e4267ab76874ae30db04c627faaaf0b509e1ccc11a95b3fc3e83f855c00", size = 159281, upload-time = "2026-04-02T09:26:21.74Z" }, - { url = "https://files.pythonhosted.org/packages/ca/83/6413f36c5a34afead88ce6f66684d943d91f233d76dd083798f9602b75ae/charset_normalizer-3.4.7-cp311-cp311-win_arm64.whl", hash = "sha256:d4a48e5b3c2a489fae013b7589308a40146ee081f6f509e047e0e096084ceca1", size = 147843, upload-time = "2026-04-02T09:26:22.901Z" }, - { url = "https://files.pythonhosted.org/packages/0c/eb/4fc8d0a7110eb5fc9cc161723a34a8a6c200ce3b4fbf681bc86feee22308/charset_normalizer-3.4.7-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:eca9705049ad3c7345d574e3510665cb2cf844c2f2dcfe675332677f081cbd46", size = 311328, upload-time = "2026-04-02T09:26:24.331Z" }, - { url = "https://files.pythonhosted.org/packages/f8/e3/0fadc706008ac9d7b9b5be6dc767c05f9d3e5df51744ce4cc9605de7b9f4/charset_normalizer-3.4.7-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6178f72c5508bfc5fd446a5905e698c6212932f25bcdd4b47a757a50605a90e2", size = 208061, upload-time = "2026-04-02T09:26:25.568Z" }, - { url = "https://files.pythonhosted.org/packages/42/f0/3dd1045c47f4a4604df85ec18ad093912ae1344ac706993aff91d38773a2/charset_normalizer-3.4.7-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e1421b502d83040e6d7fb2fb18dff63957f720da3d77b2fbd3187ceb63755d7b", size = 229031, upload-time = "2026-04-02T09:26:26.865Z" }, - { url = "https://files.pythonhosted.org/packages/dc/67/675a46eb016118a2fbde5a277a5d15f4f69d5f3f5f338e5ee2f8948fcf43/charset_normalizer-3.4.7-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:edac0f1ab77644605be2cbba52e6b7f630731fc42b34cb0f634be1a6eface56a", size = 225239, upload-time = "2026-04-02T09:26:28.044Z" }, - { url = "https://files.pythonhosted.org/packages/4b/f8/d0118a2f5f23b02cd166fa385c60f9b0d4f9194f574e2b31cef350ad7223/charset_normalizer-3.4.7-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5649fd1c7bade02f320a462fdefd0b4bd3ce036065836d4f42e0de958038e116", size = 216589, upload-time = "2026-04-02T09:26:29.239Z" }, - { url = "https://files.pythonhosted.org/packages/b1/f1/6d2b0b261b6c4ceef0fcb0d17a01cc5bc53586c2d4796fa04b5c540bc13d/charset_normalizer-3.4.7-cp312-cp312-manylinux_2_31_armv7l.whl", hash = "sha256:203104ed3e428044fd943bc4bf45fa73c0730391f9621e37fe39ecf477b128cb", size = 202733, upload-time = "2026-04-02T09:26:30.5Z" }, - { url = "https://files.pythonhosted.org/packages/6f/c0/7b1f943f7e87cc3db9626ba17807d042c38645f0a1d4415c7a14afb5591f/charset_normalizer-3.4.7-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:298930cec56029e05497a76988377cbd7457ba864beeea92ad7e844fe74cd1f1", size = 212652, upload-time = "2026-04-02T09:26:31.709Z" }, - { url = "https://files.pythonhosted.org/packages/38/dd/5a9ab159fe45c6e72079398f277b7d2b523e7f716acc489726115a910097/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:708838739abf24b2ceb208d0e22403dd018faeef86ddac04319a62ae884c4f15", size = 211229, upload-time = "2026-04-02T09:26:33.282Z" }, - { url = "https://files.pythonhosted.org/packages/d5/ff/531a1cad5ca855d1c1a8b69cb71abfd6d85c0291580146fda7c82857caa1/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:0f7eb884681e3938906ed0434f20c63046eacd0111c4ba96f27b76084cd679f5", size = 203552, upload-time = "2026-04-02T09:26:34.845Z" }, - { url = "https://files.pythonhosted.org/packages/c1/4c/a5fb52d528a8ca41f7598cb619409ece30a169fbdf9cdce592e53b46c3a6/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:4dc1e73c36828f982bfe79fadf5919923f8a6f4df2860804db9a98c48824ce8d", size = 230806, upload-time = "2026-04-02T09:26:36.152Z" }, - { url = "https://files.pythonhosted.org/packages/59/7a/071feed8124111a32b316b33ae4de83d36923039ef8cf48120266844285b/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:aed52fea0513bac0ccde438c188c8a471c4e0f457c2dd20cdbf6ea7a450046c7", size = 212316, upload-time = "2026-04-02T09:26:37.672Z" }, - { url = "https://files.pythonhosted.org/packages/fd/35/f7dba3994312d7ba508e041eaac39a36b120f32d4c8662b8814dab876431/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:fea24543955a6a729c45a73fe90e08c743f0b3334bbf3201e6c4bc1b0c7fa464", size = 227274, upload-time = "2026-04-02T09:26:38.93Z" }, - { url = "https://files.pythonhosted.org/packages/8a/2d/a572df5c9204ab7688ec1edc895a73ebded3b023bb07364710b05dd1c9be/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:bb6d88045545b26da47aa879dd4a89a71d1dce0f0e549b1abcb31dfe4a8eac49", size = 218468, upload-time = "2026-04-02T09:26:40.17Z" }, - { url = "https://files.pythonhosted.org/packages/86/eb/890922a8b03a568ca2f336c36585a4713c55d4d67bf0f0c78924be6315ca/charset_normalizer-3.4.7-cp312-cp312-win32.whl", hash = "sha256:2257141f39fe65a3fdf38aeccae4b953e5f3b3324f4ff0daf9f15b8518666a2c", size = 148460, upload-time = "2026-04-02T09:26:41.416Z" }, - { url = "https://files.pythonhosted.org/packages/35/d9/0e7dffa06c5ab081f75b1b786f0aefc88365825dfcd0ac544bdb7b2b6853/charset_normalizer-3.4.7-cp312-cp312-win_amd64.whl", hash = "sha256:5ed6ab538499c8644b8a3e18debabcd7ce684f3fa91cf867521a7a0279cab2d6", size = 159330, upload-time = "2026-04-02T09:26:42.554Z" }, - { url = "https://files.pythonhosted.org/packages/9e/5d/481bcc2a7c88ea6b0878c299547843b2521ccbc40980cb406267088bc701/charset_normalizer-3.4.7-cp312-cp312-win_arm64.whl", hash = "sha256:56be790f86bfb2c98fb742ce566dfb4816e5a83384616ab59c49e0604d49c51d", size = 147828, upload-time = "2026-04-02T09:26:44.075Z" }, - { url = "https://files.pythonhosted.org/packages/c1/3b/66777e39d3ae1ddc77ee606be4ec6d8cbd4c801f65e5a1b6f2b11b8346dd/charset_normalizer-3.4.7-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:f496c9c3cc02230093d8330875c4c3cdfc3b73612a5fd921c65d39cbcef08063", size = 309627, upload-time = "2026-04-02T09:26:45.198Z" }, - { url = "https://files.pythonhosted.org/packages/2e/4e/b7f84e617b4854ade48a1b7915c8ccfadeba444d2a18c291f696e37f0d3b/charset_normalizer-3.4.7-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0ea948db76d31190bf08bd371623927ee1339d5f2a0b4b1b4a4439a65298703c", size = 207008, upload-time = "2026-04-02T09:26:46.824Z" }, - { url = "https://files.pythonhosted.org/packages/c4/bb/ec73c0257c9e11b268f018f068f5d00aa0ef8c8b09f7753ebd5f2880e248/charset_normalizer-3.4.7-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a277ab8928b9f299723bc1a2dabb1265911b1a76341f90a510368ca44ad9ab66", size = 228303, upload-time = "2026-04-02T09:26:48.397Z" }, - { url = "https://files.pythonhosted.org/packages/85/fb/32d1f5033484494619f701e719429c69b766bfc4dbc61aa9e9c8c166528b/charset_normalizer-3.4.7-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:3bec022aec2c514d9cf199522a802bd007cd588ab17ab2525f20f9c34d067c18", size = 224282, upload-time = "2026-04-02T09:26:49.684Z" }, - { url = "https://files.pythonhosted.org/packages/fa/07/330e3a0dda4c404d6da83b327270906e9654a24f6c546dc886a0eb0ffb23/charset_normalizer-3.4.7-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e044c39e41b92c845bc815e5ae4230804e8e7bc29e399b0437d64222d92809dd", size = 215595, upload-time = "2026-04-02T09:26:50.915Z" }, - { url = "https://files.pythonhosted.org/packages/e3/7c/fc890655786e423f02556e0216d4b8c6bcb6bdfa890160dc66bf52dee468/charset_normalizer-3.4.7-cp313-cp313-manylinux_2_31_armv7l.whl", hash = "sha256:f495a1652cf3fbab2eb0639776dad966c2fb874d79d87ca07f9d5f059b8bd215", size = 201986, upload-time = "2026-04-02T09:26:52.197Z" }, - { url = "https://files.pythonhosted.org/packages/d8/97/bfb18b3db2aed3b90cf54dc292ad79fdd5ad65c4eae454099475cbeadd0d/charset_normalizer-3.4.7-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e712b419df8ba5e42b226c510472b37bd57b38e897d3eca5e8cfd410a29fa859", size = 211711, upload-time = "2026-04-02T09:26:53.49Z" }, - { url = "https://files.pythonhosted.org/packages/6f/a5/a581c13798546a7fd557c82614a5c65a13df2157e9ad6373166d2a3e645d/charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:7804338df6fcc08105c7745f1502ba68d900f45fd770d5bdd5288ddccb8a42d8", size = 210036, upload-time = "2026-04-02T09:26:54.975Z" }, - { url = "https://files.pythonhosted.org/packages/8c/bf/b3ab5bcb478e4193d517644b0fb2bf5497fbceeaa7a1bc0f4d5b50953861/charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:481551899c856c704d58119b5025793fa6730adda3571971af568f66d2424bb5", size = 202998, upload-time = "2026-04-02T09:26:56.303Z" }, - { url = "https://files.pythonhosted.org/packages/e7/4e/23efd79b65d314fa320ec6017b4b5834d5c12a58ba4610aa353af2e2f577/charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:f59099f9b66f0d7145115e6f80dd8b1d847176df89b234a5a6b3f00437aa0832", size = 230056, upload-time = "2026-04-02T09:26:57.554Z" }, - { url = "https://files.pythonhosted.org/packages/b9/9f/1e1941bc3f0e01df116e68dc37a55c4d249df5e6fa77f008841aef68264f/charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:f59ad4c0e8f6bba240a9bb85504faa1ab438237199d4cce5f622761507b8f6a6", size = 211537, upload-time = "2026-04-02T09:26:58.843Z" }, - { url = "https://files.pythonhosted.org/packages/80/0f/088cbb3020d44428964a6c97fe1edfb1b9550396bf6d278330281e8b709c/charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:3dedcc22d73ec993f42055eff4fcfed9318d1eeb9a6606c55892a26964964e48", size = 226176, upload-time = "2026-04-02T09:27:00.437Z" }, - { url = "https://files.pythonhosted.org/packages/6a/9f/130394f9bbe06f4f63e22641d32fc9b202b7e251c9aef4db044324dac493/charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:64f02c6841d7d83f832cd97ccf8eb8a906d06eb95d5276069175c696b024b60a", size = 217723, upload-time = "2026-04-02T09:27:02.021Z" }, - { url = "https://files.pythonhosted.org/packages/73/55/c469897448a06e49f8fa03f6caae97074fde823f432a98f979cc42b90e69/charset_normalizer-3.4.7-cp313-cp313-win32.whl", hash = "sha256:4042d5c8f957e15221d423ba781e85d553722fc4113f523f2feb7b188cc34c5e", size = 148085, upload-time = "2026-04-02T09:27:03.192Z" }, - { url = "https://files.pythonhosted.org/packages/5d/78/1b74c5bbb3f99b77a1715c91b3e0b5bdb6fe302d95ace4f5b1bec37b0167/charset_normalizer-3.4.7-cp313-cp313-win_amd64.whl", hash = "sha256:3946fa46a0cf3e4c8cb1cc52f56bb536310d34f25f01ca9b6c16afa767dab110", size = 158819, upload-time = "2026-04-02T09:27:04.454Z" }, - { url = "https://files.pythonhosted.org/packages/68/86/46bd42279d323deb8687c4a5a811fd548cb7d1de10cf6535d099877a9a9f/charset_normalizer-3.4.7-cp313-cp313-win_arm64.whl", hash = "sha256:80d04837f55fc81da168b98de4f4b797ef007fc8a79ab71c6ec9bc4dd662b15b", size = 147915, upload-time = "2026-04-02T09:27:05.971Z" }, - { url = "https://files.pythonhosted.org/packages/97/c8/c67cb8c70e19ef1960b97b22ed2a1567711de46c4ddf19799923adc836c2/charset_normalizer-3.4.7-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:c36c333c39be2dbca264d7803333c896ab8fa7d4d6f0ab7edb7dfd7aea6e98c0", size = 309234, upload-time = "2026-04-02T09:27:07.194Z" }, - { url = "https://files.pythonhosted.org/packages/99/85/c091fdee33f20de70d6c8b522743b6f831a2f1cd3ff86de4c6a827c48a76/charset_normalizer-3.4.7-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1c2aed2e5e41f24ea8ef1590b8e848a79b56f3a5564a65ceec43c9d692dc7d8a", size = 208042, upload-time = "2026-04-02T09:27:08.749Z" }, - { url = "https://files.pythonhosted.org/packages/87/1c/ab2ce611b984d2fd5d86a5a8a19c1ae26acac6bad967da4967562c75114d/charset_normalizer-3.4.7-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:54523e136b8948060c0fa0bc7b1b50c32c186f2fceee897a495406bb6e311d2b", size = 228706, upload-time = "2026-04-02T09:27:09.951Z" }, - { url = "https://files.pythonhosted.org/packages/a8/29/2b1d2cb00bf085f59d29eb773ce58ec2d325430f8c216804a0a5cd83cbca/charset_normalizer-3.4.7-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:715479b9a2802ecac752a3b0efa2b0b60285cf962ee38414211abdfccc233b41", size = 224727, upload-time = "2026-04-02T09:27:11.175Z" }, - { url = "https://files.pythonhosted.org/packages/47/5c/032c2d5a07fe4d4855fea851209cca2b6f03ebeb6d4e3afdb3358386a684/charset_normalizer-3.4.7-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bd6c2a1c7573c64738d716488d2cdd3c00e340e4835707d8fdb8dc1a66ef164e", size = 215882, upload-time = "2026-04-02T09:27:12.446Z" }, - { url = "https://files.pythonhosted.org/packages/2c/c2/356065d5a8b78ed04499cae5f339f091946a6a74f91e03476c33f0ab7100/charset_normalizer-3.4.7-cp314-cp314-manylinux_2_31_armv7l.whl", hash = "sha256:c45e9440fb78f8ddabcf714b68f936737a121355bf59f3907f4e17721b9d1aae", size = 200860, upload-time = "2026-04-02T09:27:13.721Z" }, - { url = "https://files.pythonhosted.org/packages/0c/cd/a32a84217ced5039f53b29f460962abb2d4420def55afabe45b1c3c7483d/charset_normalizer-3.4.7-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:3534e7dcbdcf757da6b85a0bbf5b6868786d5982dd959b065e65481644817a18", size = 211564, upload-time = "2026-04-02T09:27:15.272Z" }, - { url = "https://files.pythonhosted.org/packages/44/86/58e6f13ce26cc3b8f4a36b94a0f22ae2f00a72534520f4ae6857c4b81f89/charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:e8ac484bf18ce6975760921bb6148041faa8fef0547200386ea0b52b5d27bf7b", size = 211276, upload-time = "2026-04-02T09:27:16.834Z" }, - { url = "https://files.pythonhosted.org/packages/8f/fe/d17c32dc72e17e155e06883efa84514ca375f8a528ba2546bee73fc4df81/charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:a5fe03b42827c13cdccd08e6c0247b6a6d4b5e3cdc53fd1749f5896adcdc2356", size = 201238, upload-time = "2026-04-02T09:27:18.229Z" }, - { url = "https://files.pythonhosted.org/packages/6a/29/f33daa50b06525a237451cdb6c69da366c381a3dadcd833fa5676bc468b3/charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:2d6eb928e13016cea4f1f21d1e10c1cebd5a421bc57ddf5b1142ae3f86824fab", size = 230189, upload-time = "2026-04-02T09:27:19.445Z" }, - { url = "https://files.pythonhosted.org/packages/b6/6e/52c84015394a6a0bdcd435210a7e944c5f94ea1055f5cc5d56c5fe368e7b/charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:e74327fb75de8986940def6e8dee4f127cc9752bee7355bb323cc5b2659b6d46", size = 211352, upload-time = "2026-04-02T09:27:20.79Z" }, - { url = "https://files.pythonhosted.org/packages/8c/d7/4353be581b373033fb9198bf1da3cf8f09c1082561e8e922aa7b39bf9fe8/charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:d6038d37043bced98a66e68d3aa2b6a35505dc01328cd65217cefe82f25def44", size = 227024, upload-time = "2026-04-02T09:27:22.063Z" }, - { url = "https://files.pythonhosted.org/packages/30/45/99d18aa925bd1740098ccd3060e238e21115fffbfdcb8f3ece837d0ace6c/charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:7579e913a5339fb8fa133f6bbcfd8e6749696206cf05acdbdca71a1b436d8e72", size = 217869, upload-time = "2026-04-02T09:27:23.486Z" }, - { url = "https://files.pythonhosted.org/packages/5c/05/5ee478aa53f4bb7996482153d4bfe1b89e0f087f0ab6b294fcf92d595873/charset_normalizer-3.4.7-cp314-cp314-win32.whl", hash = "sha256:5b77459df20e08151cd6f8b9ef8ef1f961ef73d85c21a555c7eed5b79410ec10", size = 148541, upload-time = "2026-04-02T09:27:25.146Z" }, - { url = "https://files.pythonhosted.org/packages/48/77/72dcb0921b2ce86420b2d79d454c7022bf5be40202a2a07906b9f2a35c97/charset_normalizer-3.4.7-cp314-cp314-win_amd64.whl", hash = "sha256:92a0a01ead5e668468e952e4238cccd7c537364eb7d851ab144ab6627dbbe12f", size = 159634, upload-time = "2026-04-02T09:27:26.642Z" }, - { url = "https://files.pythonhosted.org/packages/c6/a3/c2369911cd72f02386e4e340770f6e158c7980267da16af8f668217abaa0/charset_normalizer-3.4.7-cp314-cp314-win_arm64.whl", hash = "sha256:67f6279d125ca0046a7fd386d01b311c6363844deac3e5b069b514ba3e63c246", size = 148384, upload-time = "2026-04-02T09:27:28.271Z" }, - { url = "https://files.pythonhosted.org/packages/94/09/7e8a7f73d24dba1f0035fbbf014d2c36828fc1bf9c88f84093e57d315935/charset_normalizer-3.4.7-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:effc3f449787117233702311a1b7d8f59cba9ced946ba727bdc329ec69028e24", size = 330133, upload-time = "2026-04-02T09:27:29.474Z" }, - { url = "https://files.pythonhosted.org/packages/8d/da/96975ddb11f8e977f706f45cddd8540fd8242f71ecdb5d18a80723dcf62c/charset_normalizer-3.4.7-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:fbccdc05410c9ee21bbf16a35f4c1d16123dcdeb8a1d38f33654fa21d0234f79", size = 216257, upload-time = "2026-04-02T09:27:30.793Z" }, - { url = "https://files.pythonhosted.org/packages/e5/e8/1d63bf8ef2d388e95c64b2098f45f84758f6d102a087552da1485912637b/charset_normalizer-3.4.7-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:733784b6d6def852c814bce5f318d25da2ee65dd4839a0718641c696e09a2960", size = 234851, upload-time = "2026-04-02T09:27:32.44Z" }, - { url = "https://files.pythonhosted.org/packages/9b/40/e5ff04233e70da2681fa43969ad6f66ca5611d7e669be0246c4c7aaf6dc8/charset_normalizer-3.4.7-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a89c23ef8d2c6b27fd200a42aa4ac72786e7c60d40efdc76e6011260b6e949c4", size = 233393, upload-time = "2026-04-02T09:27:34.03Z" }, - { url = "https://files.pythonhosted.org/packages/be/c1/06c6c49d5a5450f76899992f1ee40b41d076aee9279b49cf9974d2f313d5/charset_normalizer-3.4.7-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6c114670c45346afedc0d947faf3c7f701051d2518b943679c8ff88befe14f8e", size = 223251, upload-time = "2026-04-02T09:27:35.369Z" }, - { url = "https://files.pythonhosted.org/packages/2b/9f/f2ff16fb050946169e3e1f82134d107e5d4ae72647ec8a1b1446c148480f/charset_normalizer-3.4.7-cp314-cp314t-manylinux_2_31_armv7l.whl", hash = "sha256:a180c5e59792af262bf263b21a3c49353f25945d8d9f70628e73de370d55e1e1", size = 206609, upload-time = "2026-04-02T09:27:36.661Z" }, - { url = "https://files.pythonhosted.org/packages/69/d5/a527c0cd8d64d2eab7459784fb4169a0ac76e5a6fc5237337982fd61347e/charset_normalizer-3.4.7-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:3c9a494bc5ec77d43cea229c4f6db1e4d8fe7e1bbffa8b6f0f0032430ff8ab44", size = 220014, upload-time = "2026-04-02T09:27:38.019Z" }, - { url = "https://files.pythonhosted.org/packages/7e/80/8a7b8104a3e203074dc9aa2c613d4b726c0e136bad1cc734594b02867972/charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:8d828b6667a32a728a1ad1d93957cdf37489c57b97ae6c4de2860fa749b8fc1e", size = 218979, upload-time = "2026-04-02T09:27:39.37Z" }, - { url = "https://files.pythonhosted.org/packages/02/9a/b759b503d507f375b2b5c153e4d2ee0a75aa215b7f2489cf314f4541f2c0/charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:cf1493cd8607bec4d8a7b9b004e699fcf8f9103a9284cc94962cb73d20f9d4a3", size = 209238, upload-time = "2026-04-02T09:27:40.722Z" }, - { url = "https://files.pythonhosted.org/packages/c2/4e/0f3f5d47b86bdb79256e7290b26ac847a2832d9a4033f7eb2cd4bcf4bb5b/charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:0c96c3b819b5c3e9e165495db84d41914d6894d55181d2d108cc1a69bfc9cce0", size = 236110, upload-time = "2026-04-02T09:27:42.33Z" }, - { url = "https://files.pythonhosted.org/packages/96/23/bce28734eb3ed2c91dcf93abeb8a5cf393a7b2749725030bb630e554fdd8/charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:752a45dc4a6934060b3b0dab47e04edc3326575f82be64bc4fc293914566503e", size = 219824, upload-time = "2026-04-02T09:27:43.924Z" }, - { url = "https://files.pythonhosted.org/packages/2c/6f/6e897c6984cc4d41af319b077f2f600fc8214eb2fe2d6bcb79141b882400/charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:8778f0c7a52e56f75d12dae53ae320fae900a8b9b4164b981b9c5ce059cd1fcb", size = 233103, upload-time = "2026-04-02T09:27:45.348Z" }, - { url = "https://files.pythonhosted.org/packages/76/22/ef7bd0fe480a0ae9b656189ec00744b60933f68b4f42a7bb06589f6f576a/charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:ce3412fbe1e31eb81ea42f4169ed94861c56e643189e1e75f0041f3fe7020abe", size = 225194, upload-time = "2026-04-02T09:27:46.706Z" }, - { url = "https://files.pythonhosted.org/packages/c5/a7/0e0ab3e0b5bc1219bd80a6a0d4d72ca74d9250cb2382b7c699c147e06017/charset_normalizer-3.4.7-cp314-cp314t-win32.whl", hash = "sha256:c03a41a8784091e67a39648f70c5f97b5b6a37f216896d44d2cdcb82615339a0", size = 159827, upload-time = "2026-04-02T09:27:48.053Z" }, - { url = "https://files.pythonhosted.org/packages/7a/1d/29d32e0fb40864b1f878c7f5a0b343ae676c6e2b271a2d55cc3a152391da/charset_normalizer-3.4.7-cp314-cp314t-win_amd64.whl", hash = "sha256:03853ed82eeebbce3c2abfdbc98c96dc205f32a79627688ac9a27370ea61a49c", size = 174168, upload-time = "2026-04-02T09:27:49.795Z" }, - { url = "https://files.pythonhosted.org/packages/de/32/d92444ad05c7a6e41fb2036749777c163baf7a0301a040cb672d6b2b1ae9/charset_normalizer-3.4.7-cp314-cp314t-win_arm64.whl", hash = "sha256:c35abb8bfff0185efac5878da64c45dafd2b37fb0383add1be155a763c1f083d", size = 153018, upload-time = "2026-04-02T09:27:51.116Z" }, - { url = "https://files.pythonhosted.org/packages/db/8f/61959034484a4a7c527811f4721e75d02d653a35afb0b6054474d8185d4c/charset_normalizer-3.4.7-py3-none-any.whl", hash = "sha256:3dce51d0f5e7951f8bb4900c257dad282f49190fdbebecd4ba99bcc41fef404d", size = 61958, upload-time = "2026-04-02T09:28:37.794Z" }, -] - -[[package]] -name = "click" -version = "8.4.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "colorama", marker = "sys_platform == 'win32'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/9b/98/518d8e5081007684232226f475082b30087d0f585e8457db087298259f49/click-8.4.1.tar.gz", hash = "sha256:918b5633eddf6b41c32d4f454bf0de810065c74e3f7dbf8ee5452f8be88d3e96", size = 353007, upload-time = "2026-05-22T04:08:37.769Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c7/0d/67e5b4109ea4a837e80daa87c2c696711955e40449a97e8926672534def2/click-8.4.1-py3-none-any.whl", hash = "sha256:482be17c6991b8c19c5429a1e995d9b0efdbb63172824c41f99965dc0ade8ec2", size = 116639, upload-time = "2026-05-22T04:08:35.26Z" }, -] - -[[package]] -name = "colorama" -version = "0.4.6" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, -] - -[[package]] -name = "diffusers" -version = "0.37.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "filelock" }, - { name = "httpx" }, - { name = "huggingface-hub" }, - { name = "importlib-metadata" }, - { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, - { name = "numpy", version = "2.4.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, - { name = "pillow" }, - { name = "regex" }, - { name = "requests" }, - { name = "safetensors" }, -] -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/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]] -name = "diffusers-cosmos3" -version = "0.1.0" -source = { editable = "." } -dependencies = [ - { name = "diffusers" }, -] - -[package.metadata] -requires-dist = [{ name = "diffusers", specifier = ">=0.37.0" }] - -[[package]] -name = "exceptiongroup" -version = "1.3.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "typing-extensions", marker = "python_full_version < '3.11'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/50/79/66800aadf48771f6b62f7eb014e352e5d06856655206165d775e675a02c9/exceptiongroup-1.3.1.tar.gz", hash = "sha256:8b412432c6055b0b7d14c310000ae93352ed6754f70fa8f7c34141f91c4e3219", size = 30371, upload-time = "2025-11-21T23:01:54.787Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl", hash = "sha256:a7a39a3bd276781e98394987d3a5701d0c4edffb633bb7a5144577f82c773598", size = 16740, upload-time = "2025-11-21T23:01:53.443Z" }, -] - -[[package]] -name = "filelock" -version = "3.29.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b5/fe/997687a931ab51049acce6fa1f23e8f01216374ea81374ddee763c493db5/filelock-3.29.0.tar.gz", hash = "sha256:69974355e960702e789734cb4871f884ea6fe50bd8404051a3530bc07809cf90", size = 57571, upload-time = "2026-04-19T15:39:10.068Z" } -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 = "fsspec" -version = "2026.4.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d5/8d/1c51c094345df128ca4a990d633fe1a0ff28726c9e6b3c41ba65087bba1d/fsspec-2026.4.0.tar.gz", hash = "sha256:301d8ac70ae90ef3ad05dcf94d6c3754a097f9b5fe4667d2787aa359ec7df7e4", size = 312760, upload-time = "2026-04-29T20:42:38.635Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d5/0c/043d5e551459da400957a1395e0febbf771446ff34291afcbe3d8be2a279/fsspec-2026.4.0-py3-none-any.whl", hash = "sha256:11ef7bb35dab8a394fde6e608221d5cf3e8499401c249bebaeaad760a1a8dec2", size = 203402, upload-time = "2026-04-29T20:42:36.842Z" }, -] - -[[package]] -name = "h11" -version = "0.16.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/01/ee/02a2c011bdab74c6fb3c75474d40b3052059d95df7e73351460c8588d963/h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1", size = 101250, upload-time = "2025-04-24T03:35:25.427Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515, upload-time = "2025-04-24T03:35:24.344Z" }, -] - -[[package]] -name = "hf-xet" -version = "1.5.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/68/9b/6912c99070915a4f28119e3c5b52a9abd1eec0ad5cb293b8c967a0c6f5a2/hf_xet-1.5.0-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:7d70fe2ce97b9db73b9c9b9c81fe3693640aec83416a966c446afea54acfae3c", size = 4023383, upload-time = "2026-05-06T06:17:53.947Z" }, - { url = "https://files.pythonhosted.org/packages/0f/6d/9563cfde59b5d8128a9c7ec972a087f4c782e4f7bac5a85234edfd5d5e49/hf_xet-1.5.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:73a0dae8c71de3b0633a45c73f4a4a5ed09e94b43441d82981a781d4f12baa42", size = 3792751, upload-time = "2026-05-06T06:17:51.791Z" }, - { url = "https://files.pythonhosted.org/packages/07/a5/ed5a0cf35b49a0571af5a8f53416dad1877a718c021c9937c3a53cb45781/hf_xet-1.5.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:a60290ec57e9b71767fba7c3645ddafdd0759974b540441510c629c6db6db24a", size = 4456058, upload-time = "2026-05-06T06:17:40.735Z" }, - { url = "https://files.pythonhosted.org/packages/60/fb/3ae8bf2a7a37a4197d0195d7247fd25b3952e15cb8a599e285dfaa6f52b3/hf_xet-1.5.0-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:e5de0f6deada0dada870bb376a11bcd1f08abf3a968a6d118f33e72d1b1eb480", size = 4250783, upload-time = "2026-05-06T06:17:38.412Z" }, - { url = "https://files.pythonhosted.org/packages/a2/9b/8bae40d4d91525085137196e84eb0ed49cf65b5e96e5c3ecdadd8bd0fac2/hf_xet-1.5.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:c799d49f1a5544a0ef7591c0ee75e0d6b93d6f56dc7a4979f59f7518d2872216", size = 4445594, upload-time = "2026-05-06T06:18:04.219Z" }, - { url = "https://files.pythonhosted.org/packages/13/59/c74efbbd4e8728172b2cc72a2bc014d2947a4b7bdced932fbd3f5da1a4e5/hf_xet-1.5.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:2baea1b0b989e5c152fe81425f7745ddc8901280ba3d97c98d8cdece7b706c60", size = 4663995, upload-time = "2026-05-06T06:18:06.1Z" }, - { url = "https://files.pythonhosted.org/packages/73/32/8e1e0410af64cda9b139d1dcebdc993a8ff9c8c7c0e2696ae356d75ccc0d/hf_xet-1.5.0-cp313-cp313t-win_amd64.whl", hash = "sha256:526345b3ed45f374f6317349df489167606736c876241ba984105afe7fd4839d", size = 3966608, upload-time = "2026-05-06T06:18:19.74Z" }, - { url = "https://files.pythonhosted.org/packages/fc/34/a8febc8f4edbea8b3e21b02ebc8b628679b84ba7e45cde624a7736b51500/hf_xet-1.5.0-cp313-cp313t-win_arm64.whl", hash = "sha256:786d28e2eb8315d5035544b9d137b4a842d600c434bb91bf7d0d953cce906ad4", size = 3796946, upload-time = "2026-05-06T06:18:17.568Z" }, - { url = "https://files.pythonhosted.org/packages/2a/20/8fc8996afe5815fa1a6be8e9e5c02f24500f409d599e905800d498a4e14d/hf_xet-1.5.0-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:872d5601e6deea30d15865ede55d29eac6daf5a534ab417b99b6ef6b076dd96c", size = 4023495, upload-time = "2026-05-06T06:18:01.94Z" }, - { url = "https://files.pythonhosted.org/packages/32/6a/93d84463c00cecb561a7508aa6303e35ee2894294eac14245526924415fe/hf_xet-1.5.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:9929561f5abf4581c8ea79587881dfef6b8abb2a0d8a51915936fc2a614f4e73", size = 3792731, upload-time = "2026-05-06T06:18:00.021Z" }, - { url = "https://files.pythonhosted.org/packages/9d/5a/8ec8e0c863b382d00b3c2e2af6ded6b06371be617144a625903a6d562f4b/hf_xet-1.5.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f7b7bbae318e583a86fb21e5a4a175d6721d628a2874f4bd022d0e660c32a682", size = 4456738, upload-time = "2026-05-06T06:17:49.574Z" }, - { url = "https://files.pythonhosted.org/packages/c5/ca/f7effa1a67717da2bcc6b6c28f71c6ca648c77acaec4e2c32f40cbe16d85/hf_xet-1.5.0-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:cf7b2dc6f31a4ea754bb50f74cde482dcf5d366d184076d8530b9872787f3761", size = 4251622, upload-time = "2026-05-06T06:17:47.096Z" }, - { url = "https://files.pythonhosted.org/packages/65/f2/19247dba3e231cf77dec59ddfb878f00057635ff773d099c9b59d37812c3/hf_xet-1.5.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:8dbcbab554c9ef158ef2c991545c3e970ddd8cc7acdcd0a78c5a41095dab4ded", size = 4445667, upload-time = "2026-05-06T06:18:11.983Z" }, - { url = "https://files.pythonhosted.org/packages/7f/64/6f116801a3bcfb6f59f5c251f48cadc47ea54026441c4a385079286a94fa/hf_xet-1.5.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:5906bf7718d3636dc13402914736abe723492cb730f744834f5f5b67d3a12702", size = 4664619, upload-time = "2026-05-06T06:18:13.771Z" }, - { url = "https://files.pythonhosted.org/packages/5c/e8/069542d37946ed08669b127e1496fa99e78196d71de8d41eda5e9f1b7a58/hf_xet-1.5.0-cp314-cp314t-win_amd64.whl", hash = "sha256:5f3dc2248fc01cc0a00cd392ab497f1ca373fcbc7e3f2da1f452480b384e839e", size = 3966802, upload-time = "2026-05-06T06:18:28.162Z" }, - { url = "https://files.pythonhosted.org/packages/f9/91/fc6fdec27b14d04e88c386ac0a0129732b53fa23f7c4a78f4b83a039c567/hf_xet-1.5.0-cp314-cp314t-win_arm64.whl", hash = "sha256:b285cea1b5bab46b758772716ba8d6854a1a0310fed1c249d678a8b38601e5a0", size = 3797168, upload-time = "2026-05-06T06:18:26.287Z" }, - { 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 = "certifi" }, - { name = "h11" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/06/94/82699a10bca87a5556c9c59b5963f2d039dbd239f25bc2a63907a05a14cb/httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8", size = 85484, upload-time = "2025-04-24T22:06:22.219Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55", size = 78784, upload-time = "2025-04-24T22:06:20.566Z" }, -] - -[[package]] -name = "httpx" -version = "0.28.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "anyio" }, - { name = "certifi" }, - { name = "httpcore" }, - { name = "idna" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/b1/df/48c586a5fe32a0f01324ee087459e112ebb7224f646c0b5023f5e79e9956/httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc", size = 141406, upload-time = "2024-12-06T15:37:23.222Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad", size = 73517, upload-time = "2024-12-06T15:37:21.509Z" }, -] - -[[package]] -name = "huggingface-hub" -version = "1.17.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "click" }, - { 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 = "tqdm" }, - { name = "typer" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/bd/65/9826515abb600b5722bcf53f8b4a2fb58340b1f8bfcaee19f83561c13a44/huggingface_hub-1.17.0.tar.gz", hash = "sha256:fad842b6763ef70ebc3919665b1b9273645203185400a7d6c5eddc2323cc3435", size = 797082, upload-time = "2026-05-28T15:12:13.347Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/02/28/d7cef5e477b855c25d415b8f57e5bc7347c7a90cad3acf1725d0c92ca294/huggingface_hub-1.17.0-py3-none-any.whl", hash = "sha256:3b8156d23118e87f6a587648bfbc04f04a12a757ccb4ed298b35c4ae638bf24c", size = 671546, upload-time = "2026-05-28T15:12:11.441Z" }, -] - -[[package]] -name = "idna" -version = "3.17" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b9/28/99c51f664567218d824af024c0251650fb27e4ca066df188dab0769c5b91/idna-3.17.tar.gz", hash = "sha256:5eb0cb53bc467c12eadcf6de83163ad8527cec9416f44b9b61b19caedad2b87f", size = 196048, upload-time = "2026-05-28T14:32:38.55Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/de/a7/f76514cc40ad6234098ecdebda08732d75964776c51a42845b7da10649e2/idna-3.17-py3-none-any.whl", hash = "sha256:466e48829084efe2548012b855df21540b96f2e20e51bd124c851536556a592c", size = 65316, upload-time = "2026-05-28T14:32:37.035Z" }, -] - -[[package]] -name = "importlib-metadata" -version = "9.0.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "zipp" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/a9/01/15bb152d77b21318514a96f43af312635eb2500c96b55398d020c93d86ea/importlib_metadata-9.0.0.tar.gz", hash = "sha256:a4f57ab599e6a2e3016d7595cfd72eb4661a5106e787a95bcc90c7105b831efc", size = 56405, upload-time = "2026-03-20T06:42:56.999Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/38/3d/2d244233ac4f76e38533cfcb2991c9eb4c7bf688ae0a036d30725b8faafe/importlib_metadata-9.0.0-py3-none-any.whl", hash = "sha256:2d21d1cc5a017bd0559e36150c21c830ab1dc304dedd1b7ea85d20f45ef3edd7", size = 27789, upload-time = "2026-03-20T06:42:55.665Z" }, -] - -[[package]] -name = "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 = "mdurl" -version = "0.1.2" -source = { registry = "https://pypi.org/simple" } -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/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]] -name = "numpy" -version = "2.2.6" -source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version < '3.11'", -] -sdist = { url = "https://files.pythonhosted.org/packages/76/21/7d2a95e4bba9dc13d043ee156a356c0a8f0c6309dff6b21b4d71a073b8a8/numpy-2.2.6.tar.gz", hash = "sha256:e29554e2bef54a90aa5cc07da6ce955accb83f21ab5de01a62c8478897b264fd", size = 20276440, upload-time = "2025-05-17T22:38:04.611Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/9a/3e/ed6db5be21ce87955c0cbd3009f2803f59fa08df21b5df06862e2d8e2bdd/numpy-2.2.6-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b412caa66f72040e6d268491a59f2c43bf03eb6c96dd8f0307829feb7fa2b6fb", size = 21165245, upload-time = "2025-05-17T21:27:58.555Z" }, - { url = "https://files.pythonhosted.org/packages/22/c2/4b9221495b2a132cc9d2eb862e21d42a009f5a60e45fc44b00118c174bff/numpy-2.2.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8e41fd67c52b86603a91c1a505ebaef50b3314de0213461c7a6e99c9a3beff90", size = 14360048, upload-time = "2025-05-17T21:28:21.406Z" }, - { url = "https://files.pythonhosted.org/packages/fd/77/dc2fcfc66943c6410e2bf598062f5959372735ffda175b39906d54f02349/numpy-2.2.6-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:37e990a01ae6ec7fe7fa1c26c55ecb672dd98b19c3d0e1d1f326fa13cb38d163", size = 5340542, upload-time = "2025-05-17T21:28:30.931Z" }, - { url = "https://files.pythonhosted.org/packages/7a/4f/1cb5fdc353a5f5cc7feb692db9b8ec2c3d6405453f982435efc52561df58/numpy-2.2.6-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:5a6429d4be8ca66d889b7cf70f536a397dc45ba6faeb5f8c5427935d9592e9cf", size = 6878301, upload-time = "2025-05-17T21:28:41.613Z" }, - { url = "https://files.pythonhosted.org/packages/eb/17/96a3acd228cec142fcb8723bd3cc39c2a474f7dcf0a5d16731980bcafa95/numpy-2.2.6-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:efd28d4e9cd7d7a8d39074a4d44c63eda73401580c5c76acda2ce969e0a38e83", size = 14297320, upload-time = "2025-05-17T21:29:02.78Z" }, - { url = "https://files.pythonhosted.org/packages/b4/63/3de6a34ad7ad6646ac7d2f55ebc6ad439dbbf9c4370017c50cf403fb19b5/numpy-2.2.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fc7b73d02efb0e18c000e9ad8b83480dfcd5dfd11065997ed4c6747470ae8915", size = 16801050, upload-time = "2025-05-17T21:29:27.675Z" }, - { url = "https://files.pythonhosted.org/packages/07/b6/89d837eddef52b3d0cec5c6ba0456c1bf1b9ef6a6672fc2b7873c3ec4e2e/numpy-2.2.6-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:74d4531beb257d2c3f4b261bfb0fc09e0f9ebb8842d82a7b4209415896adc680", size = 15807034, upload-time = "2025-05-17T21:29:51.102Z" }, - { url = "https://files.pythonhosted.org/packages/01/c8/dc6ae86e3c61cfec1f178e5c9f7858584049b6093f843bca541f94120920/numpy-2.2.6-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:8fc377d995680230e83241d8a96def29f204b5782f371c532579b4f20607a289", size = 18614185, upload-time = "2025-05-17T21:30:18.703Z" }, - { url = "https://files.pythonhosted.org/packages/5b/c5/0064b1b7e7c89137b471ccec1fd2282fceaae0ab3a9550f2568782d80357/numpy-2.2.6-cp310-cp310-win32.whl", hash = "sha256:b093dd74e50a8cba3e873868d9e93a85b78e0daf2e98c6797566ad8044e8363d", size = 6527149, upload-time = "2025-05-17T21:30:29.788Z" }, - { url = "https://files.pythonhosted.org/packages/a3/dd/4b822569d6b96c39d1215dbae0582fd99954dcbcf0c1a13c61783feaca3f/numpy-2.2.6-cp310-cp310-win_amd64.whl", hash = "sha256:f0fd6321b839904e15c46e0d257fdd101dd7f530fe03fd6359c1ea63738703f3", size = 12904620, upload-time = "2025-05-17T21:30:48.994Z" }, - { url = "https://files.pythonhosted.org/packages/da/a8/4f83e2aa666a9fbf56d6118faaaf5f1974d456b1823fda0a176eff722839/numpy-2.2.6-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f9f1adb22318e121c5c69a09142811a201ef17ab257a1e66ca3025065b7f53ae", size = 21176963, upload-time = "2025-05-17T21:31:19.36Z" }, - { url = "https://files.pythonhosted.org/packages/b3/2b/64e1affc7972decb74c9e29e5649fac940514910960ba25cd9af4488b66c/numpy-2.2.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c820a93b0255bc360f53eca31a0e676fd1101f673dda8da93454a12e23fc5f7a", size = 14406743, upload-time = "2025-05-17T21:31:41.087Z" }, - { url = "https://files.pythonhosted.org/packages/4a/9f/0121e375000b5e50ffdd8b25bf78d8e1a5aa4cca3f185d41265198c7b834/numpy-2.2.6-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:3d70692235e759f260c3d837193090014aebdf026dfd167834bcba43e30c2a42", size = 5352616, upload-time = "2025-05-17T21:31:50.072Z" }, - { url = "https://files.pythonhosted.org/packages/31/0d/b48c405c91693635fbe2dcd7bc84a33a602add5f63286e024d3b6741411c/numpy-2.2.6-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:481b49095335f8eed42e39e8041327c05b0f6f4780488f61286ed3c01368d491", size = 6889579, upload-time = "2025-05-17T21:32:01.712Z" }, - { url = "https://files.pythonhosted.org/packages/52/b8/7f0554d49b565d0171eab6e99001846882000883998e7b7d9f0d98b1f934/numpy-2.2.6-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b64d8d4d17135e00c8e346e0a738deb17e754230d7e0810ac5012750bbd85a5a", size = 14312005, upload-time = "2025-05-17T21:32:23.332Z" }, - { url = "https://files.pythonhosted.org/packages/b3/dd/2238b898e51bd6d389b7389ffb20d7f4c10066d80351187ec8e303a5a475/numpy-2.2.6-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba10f8411898fc418a521833e014a77d3ca01c15b0c6cdcce6a0d2897e6dbbdf", size = 16821570, upload-time = "2025-05-17T21:32:47.991Z" }, - { url = "https://files.pythonhosted.org/packages/83/6c/44d0325722cf644f191042bf47eedad61c1e6df2432ed65cbe28509d404e/numpy-2.2.6-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:bd48227a919f1bafbdda0583705e547892342c26fb127219d60a5c36882609d1", size = 15818548, upload-time = "2025-05-17T21:33:11.728Z" }, - { url = "https://files.pythonhosted.org/packages/ae/9d/81e8216030ce66be25279098789b665d49ff19eef08bfa8cb96d4957f422/numpy-2.2.6-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:9551a499bf125c1d4f9e250377c1ee2eddd02e01eac6644c080162c0c51778ab", size = 18620521, upload-time = "2025-05-17T21:33:39.139Z" }, - { url = "https://files.pythonhosted.org/packages/6a/fd/e19617b9530b031db51b0926eed5345ce8ddc669bb3bc0044b23e275ebe8/numpy-2.2.6-cp311-cp311-win32.whl", hash = "sha256:0678000bb9ac1475cd454c6b8c799206af8107e310843532b04d49649c717a47", size = 6525866, upload-time = "2025-05-17T21:33:50.273Z" }, - { url = "https://files.pythonhosted.org/packages/31/0a/f354fb7176b81747d870f7991dc763e157a934c717b67b58456bc63da3df/numpy-2.2.6-cp311-cp311-win_amd64.whl", hash = "sha256:e8213002e427c69c45a52bbd94163084025f533a55a59d6f9c5b820774ef3303", size = 12907455, upload-time = "2025-05-17T21:34:09.135Z" }, - { url = "https://files.pythonhosted.org/packages/82/5d/c00588b6cf18e1da539b45d3598d3557084990dcc4331960c15ee776ee41/numpy-2.2.6-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:41c5a21f4a04fa86436124d388f6ed60a9343a6f767fced1a8a71c3fbca038ff", size = 20875348, upload-time = "2025-05-17T21:34:39.648Z" }, - { url = "https://files.pythonhosted.org/packages/66/ee/560deadcdde6c2f90200450d5938f63a34b37e27ebff162810f716f6a230/numpy-2.2.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:de749064336d37e340f640b05f24e9e3dd678c57318c7289d222a8a2f543e90c", size = 14119362, upload-time = "2025-05-17T21:35:01.241Z" }, - { url = "https://files.pythonhosted.org/packages/3c/65/4baa99f1c53b30adf0acd9a5519078871ddde8d2339dc5a7fde80d9d87da/numpy-2.2.6-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:894b3a42502226a1cac872f840030665f33326fc3dac8e57c607905773cdcde3", size = 5084103, upload-time = "2025-05-17T21:35:10.622Z" }, - { url = "https://files.pythonhosted.org/packages/cc/89/e5a34c071a0570cc40c9a54eb472d113eea6d002e9ae12bb3a8407fb912e/numpy-2.2.6-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:71594f7c51a18e728451bb50cc60a3ce4e6538822731b2933209a1f3614e9282", size = 6625382, upload-time = "2025-05-17T21:35:21.414Z" }, - { url = "https://files.pythonhosted.org/packages/f8/35/8c80729f1ff76b3921d5c9487c7ac3de9b2a103b1cd05e905b3090513510/numpy-2.2.6-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f2618db89be1b4e05f7a1a847a9c1c0abd63e63a1607d892dd54668dd92faf87", size = 14018462, upload-time = "2025-05-17T21:35:42.174Z" }, - { url = "https://files.pythonhosted.org/packages/8c/3d/1e1db36cfd41f895d266b103df00ca5b3cbe965184df824dec5c08c6b803/numpy-2.2.6-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd83c01228a688733f1ded5201c678f0c53ecc1006ffbc404db9f7a899ac6249", size = 16527618, upload-time = "2025-05-17T21:36:06.711Z" }, - { url = "https://files.pythonhosted.org/packages/61/c6/03ed30992602c85aa3cd95b9070a514f8b3c33e31124694438d88809ae36/numpy-2.2.6-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:37c0ca431f82cd5fa716eca9506aefcabc247fb27ba69c5062a6d3ade8cf8f49", size = 15505511, upload-time = "2025-05-17T21:36:29.965Z" }, - { url = "https://files.pythonhosted.org/packages/b7/25/5761d832a81df431e260719ec45de696414266613c9ee268394dd5ad8236/numpy-2.2.6-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fe27749d33bb772c80dcd84ae7e8df2adc920ae8297400dabec45f0dedb3f6de", size = 18313783, upload-time = "2025-05-17T21:36:56.883Z" }, - { url = "https://files.pythonhosted.org/packages/57/0a/72d5a3527c5ebffcd47bde9162c39fae1f90138c961e5296491ce778e682/numpy-2.2.6-cp312-cp312-win32.whl", hash = "sha256:4eeaae00d789f66c7a25ac5f34b71a7035bb474e679f410e5e1a94deb24cf2d4", size = 6246506, upload-time = "2025-05-17T21:37:07.368Z" }, - { url = "https://files.pythonhosted.org/packages/36/fa/8c9210162ca1b88529ab76b41ba02d433fd54fecaf6feb70ef9f124683f1/numpy-2.2.6-cp312-cp312-win_amd64.whl", hash = "sha256:c1f9540be57940698ed329904db803cf7a402f3fc200bfe599334c9bd84a40b2", size = 12614190, upload-time = "2025-05-17T21:37:26.213Z" }, - { url = "https://files.pythonhosted.org/packages/f9/5c/6657823f4f594f72b5471f1db1ab12e26e890bb2e41897522d134d2a3e81/numpy-2.2.6-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0811bb762109d9708cca4d0b13c4f67146e3c3b7cf8d34018c722adb2d957c84", size = 20867828, upload-time = "2025-05-17T21:37:56.699Z" }, - { url = "https://files.pythonhosted.org/packages/dc/9e/14520dc3dadf3c803473bd07e9b2bd1b69bc583cb2497b47000fed2fa92f/numpy-2.2.6-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:287cc3162b6f01463ccd86be154f284d0893d2b3ed7292439ea97eafa8170e0b", size = 14143006, upload-time = "2025-05-17T21:38:18.291Z" }, - { url = "https://files.pythonhosted.org/packages/4f/06/7e96c57d90bebdce9918412087fc22ca9851cceaf5567a45c1f404480e9e/numpy-2.2.6-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:f1372f041402e37e5e633e586f62aa53de2eac8d98cbfb822806ce4bbefcb74d", size = 5076765, upload-time = "2025-05-17T21:38:27.319Z" }, - { url = "https://files.pythonhosted.org/packages/73/ed/63d920c23b4289fdac96ddbdd6132e9427790977d5457cd132f18e76eae0/numpy-2.2.6-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:55a4d33fa519660d69614a9fad433be87e5252f4b03850642f88993f7b2ca566", size = 6617736, upload-time = "2025-05-17T21:38:38.141Z" }, - { url = "https://files.pythonhosted.org/packages/85/c5/e19c8f99d83fd377ec8c7e0cf627a8049746da54afc24ef0a0cb73d5dfb5/numpy-2.2.6-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f92729c95468a2f4f15e9bb94c432a9229d0d50de67304399627a943201baa2f", size = 14010719, upload-time = "2025-05-17T21:38:58.433Z" }, - { url = "https://files.pythonhosted.org/packages/19/49/4df9123aafa7b539317bf6d342cb6d227e49f7a35b99c287a6109b13dd93/numpy-2.2.6-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1bc23a79bfabc5d056d106f9befb8d50c31ced2fbc70eedb8155aec74a45798f", size = 16526072, upload-time = "2025-05-17T21:39:22.638Z" }, - { url = "https://files.pythonhosted.org/packages/b2/6c/04b5f47f4f32f7c2b0e7260442a8cbcf8168b0e1a41ff1495da42f42a14f/numpy-2.2.6-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e3143e4451880bed956e706a3220b4e5cf6172ef05fcc397f6f36a550b1dd868", size = 15503213, upload-time = "2025-05-17T21:39:45.865Z" }, - { url = "https://files.pythonhosted.org/packages/17/0a/5cd92e352c1307640d5b6fec1b2ffb06cd0dabe7d7b8227f97933d378422/numpy-2.2.6-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:b4f13750ce79751586ae2eb824ba7e1e8dba64784086c98cdbbcc6a42112ce0d", size = 18316632, upload-time = "2025-05-17T21:40:13.331Z" }, - { url = "https://files.pythonhosted.org/packages/f0/3b/5cba2b1d88760ef86596ad0f3d484b1cbff7c115ae2429678465057c5155/numpy-2.2.6-cp313-cp313-win32.whl", hash = "sha256:5beb72339d9d4fa36522fc63802f469b13cdbe4fdab4a288f0c441b74272ebfd", size = 6244532, upload-time = "2025-05-17T21:43:46.099Z" }, - { url = "https://files.pythonhosted.org/packages/cb/3b/d58c12eafcb298d4e6d0d40216866ab15f59e55d148a5658bb3132311fcf/numpy-2.2.6-cp313-cp313-win_amd64.whl", hash = "sha256:b0544343a702fa80c95ad5d3d608ea3599dd54d4632df855e4c8d24eb6ecfa1c", size = 12610885, upload-time = "2025-05-17T21:44:05.145Z" }, - { url = "https://files.pythonhosted.org/packages/6b/9e/4bf918b818e516322db999ac25d00c75788ddfd2d2ade4fa66f1f38097e1/numpy-2.2.6-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:0bca768cd85ae743b2affdc762d617eddf3bcf8724435498a1e80132d04879e6", size = 20963467, upload-time = "2025-05-17T21:40:44Z" }, - { url = "https://files.pythonhosted.org/packages/61/66/d2de6b291507517ff2e438e13ff7b1e2cdbdb7cb40b3ed475377aece69f9/numpy-2.2.6-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:fc0c5673685c508a142ca65209b4e79ed6740a4ed6b2267dbba90f34b0b3cfda", size = 14225144, upload-time = "2025-05-17T21:41:05.695Z" }, - { url = "https://files.pythonhosted.org/packages/e4/25/480387655407ead912e28ba3a820bc69af9adf13bcbe40b299d454ec011f/numpy-2.2.6-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:5bd4fc3ac8926b3819797a7c0e2631eb889b4118a9898c84f585a54d475b7e40", size = 5200217, upload-time = "2025-05-17T21:41:15.903Z" }, - { url = "https://files.pythonhosted.org/packages/aa/4a/6e313b5108f53dcbf3aca0c0f3e9c92f4c10ce57a0a721851f9785872895/numpy-2.2.6-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:fee4236c876c4e8369388054d02d0e9bb84821feb1a64dd59e137e6511a551f8", size = 6712014, upload-time = "2025-05-17T21:41:27.321Z" }, - { url = "https://files.pythonhosted.org/packages/b7/30/172c2d5c4be71fdf476e9de553443cf8e25feddbe185e0bd88b096915bcc/numpy-2.2.6-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e1dda9c7e08dc141e0247a5b8f49cf05984955246a327d4c48bda16821947b2f", size = 14077935, upload-time = "2025-05-17T21:41:49.738Z" }, - { url = "https://files.pythonhosted.org/packages/12/fb/9e743f8d4e4d3c710902cf87af3512082ae3d43b945d5d16563f26ec251d/numpy-2.2.6-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f447e6acb680fd307f40d3da4852208af94afdfab89cf850986c3ca00562f4fa", size = 16600122, upload-time = "2025-05-17T21:42:14.046Z" }, - { url = "https://files.pythonhosted.org/packages/12/75/ee20da0e58d3a66f204f38916757e01e33a9737d0b22373b3eb5a27358f9/numpy-2.2.6-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:389d771b1623ec92636b0786bc4ae56abafad4a4c513d36a55dce14bd9ce8571", size = 15586143, upload-time = "2025-05-17T21:42:37.464Z" }, - { url = "https://files.pythonhosted.org/packages/76/95/bef5b37f29fc5e739947e9ce5179ad402875633308504a52d188302319c8/numpy-2.2.6-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:8e9ace4a37db23421249ed236fdcdd457d671e25146786dfc96835cd951aa7c1", size = 18385260, upload-time = "2025-05-17T21:43:05.189Z" }, - { url = "https://files.pythonhosted.org/packages/09/04/f2f83279d287407cf36a7a8053a5abe7be3622a4363337338f2585e4afda/numpy-2.2.6-cp313-cp313t-win32.whl", hash = "sha256:038613e9fb8c72b0a41f025a7e4c3f0b7a1b5d768ece4796b674c8f3fe13efff", size = 6377225, upload-time = "2025-05-17T21:43:16.254Z" }, - { url = "https://files.pythonhosted.org/packages/67/0e/35082d13c09c02c011cf21570543d202ad929d961c02a147493cb0c2bdf5/numpy-2.2.6-cp313-cp313t-win_amd64.whl", hash = "sha256:6031dd6dfecc0cf9f668681a37648373bddd6421fff6c66ec1624eed0180ee06", size = 12771374, upload-time = "2025-05-17T21:43:35.479Z" }, - { url = "https://files.pythonhosted.org/packages/9e/3b/d94a75f4dbf1ef5d321523ecac21ef23a3cd2ac8b78ae2aac40873590229/numpy-2.2.6-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:0b605b275d7bd0c640cad4e5d30fa701a8d59302e127e5f79138ad62762c3e3d", size = 21040391, upload-time = "2025-05-17T21:44:35.948Z" }, - { url = "https://files.pythonhosted.org/packages/17/f4/09b2fa1b58f0fb4f7c7963a1649c64c4d315752240377ed74d9cd878f7b5/numpy-2.2.6-pp310-pypy310_pp73-macosx_14_0_x86_64.whl", hash = "sha256:7befc596a7dc9da8a337f79802ee8adb30a552a94f792b9c9d18c840055907db", size = 6786754, upload-time = "2025-05-17T21:44:47.446Z" }, - { url = "https://files.pythonhosted.org/packages/af/30/feba75f143bdc868a1cc3f44ccfa6c4b9ec522b36458e738cd00f67b573f/numpy-2.2.6-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ce47521a4754c8f4593837384bd3424880629f718d87c5d44f8ed763edd63543", size = 16643476, upload-time = "2025-05-17T21:45:11.871Z" }, - { url = "https://files.pythonhosted.org/packages/37/48/ac2a9584402fb6c0cd5b5d1a91dcf176b15760130dd386bbafdbfe3640bf/numpy-2.2.6-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:d042d24c90c41b54fd506da306759e06e568864df8ec17ccc17e9e884634fd00", size = 12812666, upload-time = "2025-05-17T21:45:31.426Z" }, -] - -[[package]] -name = "numpy" -version = "2.4.6" -source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version >= '3.11'", -] -sdist = { url = "https://files.pythonhosted.org/packages/d0/ad/fed0499ce6a338d2a03ebae59cd15093910c8875328855781952abf6c2fe/numpy-2.4.6.tar.gz", hash = "sha256:f3a3570c4a2a16746ac2c31a7c7c7b0c186b95ce902e33db6f28094ed7387dda", size = 20735807, upload-time = "2026-05-18T23:37:14.07Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b3/49/ec46835a70be8fa6446c495126ac84fdb28cb2558e1620ffb87a10c8b64c/numpy-2.4.6-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0280e0356c0829a18d9de1cb7eee50ec22ca639878d7240307ca0943d73cd2c4", size = 16969194, upload-time = "2026-05-18T23:33:13.503Z" }, - { url = "https://files.pythonhosted.org/packages/0e/0d/f5957185c0ee2f3e12f78715aa9e3b353fd83633316c8532b38faa37e3f6/numpy-2.4.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:110f8b71aacb688ec69062bb7f6938a0f8acb01b7c1c4beb453c65b6d234584d", size = 14964111, upload-time = "2026-05-18T23:33:17.795Z" }, - { url = "https://files.pythonhosted.org/packages/ad/40/40a40ee0ddf7ceb782c49af278894b686e586d65d8c1889c8b5da01a3d7d/numpy-2.4.6-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:4cfe66903cc32a9921a6733d96b19bb6abf310397581bbad89c228f5abaf0ee8", size = 5469159, upload-time = "2026-05-18T23:33:20.654Z" }, - { url = "https://files.pythonhosted.org/packages/63/13/f9a8046535cb21deae82f8d03de9617e08882d274fad2539630761888228/numpy-2.4.6-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:8155154c7c691289fe18f510b5d4657c68c67989f293f0535a91360392ff6538", size = 6798936, upload-time = "2026-05-18T23:33:22.987Z" }, - { url = "https://files.pythonhosted.org/packages/33/a8/6fa8c1a345a8c85dbb21932c447bee07c30a2c2a3f31e369c0a84b300147/numpy-2.4.6-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0ab0a9c4ffb1a6d95ef519fe4247dba8eb6b18ad93999f76b7f657039acabd47", size = 15966692, upload-time = "2026-05-18T23:33:26.62Z" }, - { url = "https://files.pythonhosted.org/packages/02/03/74fe2a4cb3817d94d86402f2506554130a2f01414e299b5a843e5a8a957f/numpy-2.4.6-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:89cd468399cfd2504718f0ba50e410dca55a170b61a02ad92bb18c8a65186e93", size = 16918164, upload-time = "2026-05-18T23:33:29.955Z" }, - { url = "https://files.pythonhosted.org/packages/c5/80/3615be3313f7e7696609bc194b9f0101da809df79e859bdb84e0cd043f46/numpy-2.4.6-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c2d37ab77531417474168eb79d6d80b14f821a966818505d03013d0833edb7a8", size = 17322877, upload-time = "2026-05-18T23:33:34.724Z" }, - { url = "https://files.pythonhosted.org/packages/ca/ac/a691e0fe2675e370d0e08ff905adc49a1c8830e8cae03efe4477e92cd55d/numpy-2.4.6-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f407cb6b8e9d6d8c626bc73c945db1706035af8fd632295547bf1c9e46d092d6", size = 18651487, upload-time = "2026-05-18T23:33:38.217Z" }, - { url = "https://files.pythonhosted.org/packages/15/a7/9bc1cd626d7bf6869bfedf27b91b6ab5dd607758bf8e959d6fa80c6a59cb/numpy-2.4.6-cp311-cp311-win32.whl", hash = "sha256:ddea102b48f9e339f3948bf22040944184627a30fdf7f858667673b9c5f033c8", size = 6233945, upload-time = "2026-05-18T23:33:41.331Z" }, - { url = "https://files.pythonhosted.org/packages/c5/31/7fc6239c12bce7e931463251cca4426c465e1876ba3cc785402ef4dd8f4e/numpy-2.4.6-cp311-cp311-win_amd64.whl", hash = "sha256:1e254a00cdf42b1e4d5b3d68d33af63268d41340d8885df2ab6470f2e1500147", size = 12608406, upload-time = "2026-05-18T23:33:44.131Z" }, - { url = "https://files.pythonhosted.org/packages/27/83/140f85a466595a16382996a1bf06b2b54bcd597488921b0c9daaeeda72af/numpy-2.4.6-cp311-cp311-win_arm64.whl", hash = "sha256:ed9749eef4cbd126da3dc1d6bcb3a57f5eb7ac6a6484146bdbf743f552dfc577", size = 10479528, upload-time = "2026-05-18T23:33:50.725Z" }, - { url = "https://files.pythonhosted.org/packages/95/2a/3d7b5ac8aac24feaf9ad7ed58f45b0bbc06d37e4338ae84c9f2298b570f9/numpy-2.4.6-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:001fbb8e08d942dd57599e781f2472269ee7f2755fae407b4f67b2f0b17da3f1", size = 16689119, upload-time = "2026-05-18T23:33:54.065Z" }, - { url = "https://files.pythonhosted.org/packages/ea/12/92c4c131527599e8288d6918e888d88726f84d805d784b771f32408aeaef/numpy-2.4.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ebfb099f8dcf083deef3ac1ca4c1503f387cf76296fcb3816b66f5ecb5f54fdb", size = 14699246, upload-time = "2026-05-18T23:33:57.621Z" }, - { url = "https://files.pythonhosted.org/packages/ad/fe/c0a6b7b2ca128a8fb228575147073b660656734b8ebe4d76c8fd748dcc79/numpy-2.4.6-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:3213d622a0283a39a93d188f3cf72b26862df52fbb4ca3697f51705016523d41", size = 5204410, upload-time = "2026-05-18T23:34:00.302Z" }, - { url = "https://files.pythonhosted.org/packages/f3/d4/9770d14ba719432bb90a421bfd443872ed0f70f7264b64bec12ea363d5fd/numpy-2.4.6-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:357cc07a6d7b0b182ff02249616a03742827ebb1277546b5c7cd7f7620a45698", size = 6551240, upload-time = "2026-05-18T23:34:02.852Z" }, - { url = "https://files.pythonhosted.org/packages/c9/c6/50a46a6205feba2343f1d6d17438107c5dc491ed1c736e6ea68689fd906b/numpy-2.4.6-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5f9fb9157b4ce2971008323afe46053787b526ef624fea915b261468a8421a0f", size = 15671012, upload-time = "2026-05-18T23:34:05.485Z" }, - { url = "https://files.pythonhosted.org/packages/99/60/14115e6364fa676c5397c2ad3004e527e9aa487abf5d0706ec81bbd08529/numpy-2.4.6-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:90f9849678c75fe7afa2d348ac842c168b0a4d3d61919687216dfc547976d853", size = 16645538, upload-time = "2026-05-18T23:34:09.265Z" }, - { url = "https://files.pythonhosted.org/packages/ae/c5/693cbe59e57db94d2231fa519ca3978dc9e19da5a8f088588f5c6e947ff2/numpy-2.4.6-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:c1a2af6c6ef86344a6b0db6b97834208bf598db514f2b155042439b62605601a", size = 17020706, upload-time = "2026-05-18T23:34:13.053Z" }, - { url = "https://files.pythonhosted.org/packages/ef/fc/85b7c4eff9b4966ade25c2273cf7e7012e92366c032058653934b37de044/numpy-2.4.6-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e5805d5a22fd19c8ccff10a9561f9df94436b0545619ea579db2d3c35294bce2", size = 18368541, upload-time = "2026-05-18T23:34:17.024Z" }, - { url = "https://files.pythonhosted.org/packages/f6/81/e1b27545deedce7f4a0b348618c6b62d74e36a4dc9ccd42f3eb2f85eee32/numpy-2.4.6-cp312-cp312-win32.whl", hash = "sha256:e3eeb0aabd6bd5ce64faae67e9935203a6991b4bc2a485a767fbafb2c5125f45", size = 5962825, upload-time = "2026-05-18T23:34:20.3Z" }, - { url = "https://files.pythonhosted.org/packages/ab/ca/feab00bd44aa5fe1ad2c18f08b4d3bb92e26484b0b1d1443897809ed528c/numpy-2.4.6-cp312-cp312-win_amd64.whl", hash = "sha256:d8e8286dd7cea7895157318d1b91cdacac64c479f3cbc8dce548331728484751", size = 12321687, upload-time = "2026-05-18T23:34:23.095Z" }, - { url = "https://files.pythonhosted.org/packages/63/cf/5a6d34850a39d1093558564f77ee8e8e0bee5061151b8f05a55711001ec7/numpy-2.4.6-cp312-cp312-win_arm64.whl", hash = "sha256:4081eb135ac24158bd51cdfbef16f1c64df7063b1143f24731387137c092bec8", size = 10221482, upload-time = "2026-05-18T23:34:25.876Z" }, - { url = "https://files.pythonhosted.org/packages/fb/82/bdab26d7438c6791ca31b7c024ca37c1eab8b726ba236129005cd4a06e45/numpy-2.4.6-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:511dbaf848decaaaf4b4ca48032619fb3138710c4bf7da7617765edad1ef96b0", size = 16684648, upload-time = "2026-05-18T23:34:29.41Z" }, - { url = "https://files.pythonhosted.org/packages/1b/30/a80189bcc7f5e4258b3fbc3968d909d1756f54d023299ecc39ad6fdb9ef8/numpy-2.4.6-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:bf162abab1c1a736333192707cef898e735a5ca00f38f27eeedf44b39d9e85eb", size = 14693902, upload-time = "2026-05-18T23:34:33.013Z" }, - { url = "https://files.pythonhosted.org/packages/97/12/70b5d0d7c15e1ebb8a6a84a8caa1d19e181d84fb58bb6d70aca29099dec1/numpy-2.4.6-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:043191bfa8eab18c776647b62723ac9dddece59743b13f49b2016094129c2b3f", size = 5198992, upload-time = "2026-05-18T23:34:36.132Z" }, - { url = "https://files.pythonhosted.org/packages/ba/8c/ebd2a8f8a83541f8d38cc5667e8c2b69cecfd30da6e45693e8158857d44b/numpy-2.4.6-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:6180d8b35af935aed8ece3a85e0a43f87393ae0ac87c8d2c8bd2c993f7270ef3", size = 6546944, upload-time = "2026-05-18T23:34:38.484Z" }, - { url = "https://files.pythonhosted.org/packages/bb/c5/7b863a97a91671a0338f4253bd3b5a3d3852f0692dae91711c9f4a10e787/numpy-2.4.6-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:72fbe16c6fac95aedf5937fa873445cec2110be35d8a4e9433d7501fd98dae6b", size = 15669392, upload-time = "2026-05-18T23:34:41.257Z" }, - { url = "https://files.pythonhosted.org/packages/a5/9d/3584b9984ca4c047aea75214ce1a4c4c73d849bd71b604264b7f5653f8a8/numpy-2.4.6-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a7830bab239b79cda9c08c2da014761cafb48da6150e1da17ac06283f43b6089", size = 16633220, upload-time = "2026-05-18T23:34:45.075Z" }, - { url = "https://files.pythonhosted.org/packages/05/ae/7c67fba23bd98caec7c99261f3a16072ade14813486b0282cb29846de832/numpy-2.4.6-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ef4aea96ce4d3b074422cb4f2f64e216bf9e213004bb58ecfdf50ea02ea8eb9a", size = 17020800, upload-time = "2026-05-18T23:34:49.065Z" }, - { url = "https://files.pythonhosted.org/packages/d9/5d/3b6725cb31d983c5e66916f5d36f6d7e5521129e4c4404d64f918292a5b6/numpy-2.4.6-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:dfa20cc6ca228e6b155b11da03825975ce66aea520985dbbddf0f2a5a495c605", size = 18357600, upload-time = "2026-05-18T23:34:52.709Z" }, - { url = "https://files.pythonhosted.org/packages/f7/da/2ccc6c2fe8898dee01d90c75c5f5f914a23daf99e3e0f59516a08760c8b5/numpy-2.4.6-cp313-cp313-win32.whl", hash = "sha256:56b39e5e0622a09a25bf5baf62f4bcf0cb8a41ae6e2819cf49bbc5a74c083f91", size = 5961134, upload-time = "2026-05-18T23:34:55.618Z" }, - { url = "https://files.pythonhosted.org/packages/b5/cd/9cc4dc876fb065d5c220aae4d5e14826b2715331bb7618ce1fb07a679d99/numpy-2.4.6-cp313-cp313-win_amd64.whl", hash = "sha256:c4fc99836233ea196540b17ab0983aff60ed07941751930f5f4d05bc3b3b7359", size = 12318598, upload-time = "2026-05-18T23:34:58.928Z" }, - { url = "https://files.pythonhosted.org/packages/39/1e/c0bcba1f8694116485fe28fd1be698c278fcda4141c5b0e53a2aed8b12a8/numpy-2.4.6-cp313-cp313-win_arm64.whl", hash = "sha256:a7c711e21628b52034bb5ab8d1bce291f752fcc5e92accc615778acee1ff4778", size = 10222272, upload-time = "2026-05-18T23:35:02.167Z" }, - { url = "https://files.pythonhosted.org/packages/63/6d/cc5619247c8f4204e507f5883528372e4ac4bb189e579fb859a12e480b1f/numpy-2.4.6-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:112b06a867b235ef466ed3508ddf0238050df9c727cafb5301ac385b899189a1", size = 14821197, upload-time = "2026-05-18T23:35:05.468Z" }, - { url = "https://files.pythonhosted.org/packages/00/58/f1c39161c87d9e9bed660f1ed4bafc0e403d5ec9650b6dd77aead07d489b/numpy-2.4.6-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:eaf7fa2de5c0be8ae6ff8e9bea2ccd725e980541244521d8d4b5f3354a27babe", size = 5326287, upload-time = "2026-05-18T23:35:08.693Z" }, - { url = "https://files.pythonhosted.org/packages/af/57/3917ab0fd97f271a8694513581b8a36c655f111c446852c302f04ccdb6fc/numpy-2.4.6-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:7265a2f3d436e54ef9f2b52b5c937e6be778781bd97a590319d7348f1c1ca997", size = 6646763, upload-time = "2026-05-18T23:35:11.459Z" }, - { url = "https://files.pythonhosted.org/packages/eb/0f/037e64c494b67581ae18193d770adef354c41f3f2c8ebf865602d949bf8f/numpy-2.4.6-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f74a575920ab21fe304421a3fc28793d82e299cae9eccb37084e9fc7f3617c20", size = 15728070, upload-time = "2026-05-18T23:35:14.79Z" }, - { url = "https://files.pythonhosted.org/packages/21/a6/5d2bae9c9542eb4df16dc9c46dc79c186e9bad53805dfa5399a6023c6db0/numpy-2.4.6-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ede83e07a75dd06bc501566c1eca2afc0d61677c1472ac9ad93fdee6e638a48d", size = 16681752, upload-time = "2026-05-18T23:35:18.836Z" }, - { url = "https://files.pythonhosted.org/packages/92/14/23d1dfb410ae362cd59ce53e936b1513d545eb40db3949ced632e19a459e/numpy-2.4.6-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:68bb27509ac1b9a3443094260f6326150663b06abe40b73a2f81160623da5b67", size = 17086024, upload-time = "2026-05-18T23:35:22.52Z" }, - { url = "https://files.pythonhosted.org/packages/4b/6e/23595a2c642cdf3bc567877064bdd7f91c8b0038a4453cf2daf7248eafe9/numpy-2.4.6-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:a0df0043bdb289bde1f62da130d20df23d58b45429f752bc7a8fc5325a225ecd", size = 18403398, upload-time = "2026-05-18T23:35:26.398Z" }, - { url = "https://files.pythonhosted.org/packages/8a/90/0ac3bc947217e66dec77e7cbc6a1979d1af70b6461b82f620d3bccd5e4c8/numpy-2.4.6-cp313-cp313t-win32.whl", hash = "sha256:29a287e0cf63ff528da061de6b9f64a4618da591ca1046aafc54062e40ca7eab", size = 6084971, upload-time = "2026-05-18T23:35:29.387Z" }, - { url = "https://files.pythonhosted.org/packages/77/71/5673e351671a1d2bd6063b91b44f70c0affea7d1516fa7a6572941ba4aa1/numpy-2.4.6-cp313-cp313t-win_amd64.whl", hash = "sha256:25c692919ac5a01f170a3bfcd62d745b24fd095c353d50812637d6fcab442e75", size = 12458532, upload-time = "2026-05-18T23:35:32.175Z" }, - { url = "https://files.pythonhosted.org/packages/3f/88/19d3503c5046e688f049274b27a3ef3d771152fa80d3ba3d01a3dff61abe/numpy-2.4.6-cp313-cp313t-win_arm64.whl", hash = "sha256:1e978ec1e8bd0e0e4de6bb75de9d30cbb74db6b6a2bb727618613703ca0167dd", size = 10291881, upload-time = "2026-05-18T23:35:35.465Z" }, - { url = "https://files.pythonhosted.org/packages/f8/91/3ab2044d05fd16d343c5ac2e69b127f1b2854040dd20b193257c78028bd3/numpy-2.4.6-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:06ca2f61ec4385a07a6977c55ba998a4466c123642b4a32694d3128fce18c079", size = 16683458, upload-time = "2026-05-18T23:35:38.353Z" }, - { url = "https://files.pythonhosted.org/packages/8e/62/764ce66fa4147ae6d73071a3abf804ffe606f174618697c571acdf26a7c9/numpy-2.4.6-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:38efbc8de75c7a0fc1ac190162d892787f3f47b57cc291231aafee36b80982b7", size = 14704559, upload-time = "2026-05-18T23:35:42.14Z" }, - { url = "https://files.pythonhosted.org/packages/60/61/23f27c172f022e04025b7dc2367f4d63c1a398120607ec896228649a6f48/numpy-2.4.6-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:d581b735e177fdcdce6fed8e7e8880a3fb6ee4e3653a3ac6af01c6f4c03effc5", size = 5209716, upload-time = "2026-05-18T23:35:45.377Z" }, - { url = "https://files.pythonhosted.org/packages/03/71/21cf70dc6ea3e3acb95fc53a265b2fc248b981f0194ceb5b475271b8809d/numpy-2.4.6-cp314-cp314-macosx_14_0_x86_64.whl", hash = "sha256:0a041d3d761dc3c35cc56ce0351506a02bcbc25f7b169f652435141a17db9096", size = 6543947, upload-time = "2026-05-18T23:35:47.926Z" }, - { url = "https://files.pythonhosted.org/packages/d5/91/64288395ee1799bd2e0b04a305dce9666da90c961e1f3fe982a05ee1c036/numpy-2.4.6-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:40fdc1ae7125e518ea98e53e69a4ebc27e1fd50510c47b7ea130cf21e5e1d42b", size = 15685197, upload-time = "2026-05-18T23:35:50.863Z" }, - { url = "https://files.pythonhosted.org/packages/f3/eb/ebffaa97dc55502df69584a8f0dcf07f69a3e0b3e2323670a2722db9aa39/numpy-2.4.6-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a2c306dea656c12c68f51f4cea133cbe78ca7435eb28c735eac1d3ebe73be6e8", size = 16638245, upload-time = "2026-05-18T23:35:54.752Z" }, - { url = "https://files.pythonhosted.org/packages/b8/0b/54f9da33128d7e350fab89c7455902eeae70349ee52bddb448dc4a576f45/numpy-2.4.6-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:33111801a01c12a8a1e3721f0a9232f8cfc8ae2c6b7098167e6f623c6073f402", size = 17036587, upload-time = "2026-05-18T23:35:58.355Z" }, - { url = "https://files.pythonhosted.org/packages/b6/f0/fdebc1052db1cc37c64beb22072d67cd6d1c71adca1299f53dec2b5e20d3/numpy-2.4.6-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:ae506e6902902557576a26ff33eda8695e7ecb3cb36c3b573a0765dee114ebdb", size = 18363226, upload-time = "2026-05-18T23:36:02.845Z" }, - { url = "https://files.pythonhosted.org/packages/aa/b4/298628d98c72b57e57f7165ae6a481a1deaf6f3c28262a6e4c739c275930/numpy-2.4.6-cp314-cp314-win32.whl", hash = "sha256:aaf159caa35993cb1f56fb9b8e4610d35758e7ca005412eb1daa856a78c9c4b1", size = 6010196, upload-time = "2026-05-18T23:36:05.92Z" }, - { url = "https://files.pythonhosted.org/packages/df/ac/46de6dda46478f7942f839e094970be2d4a861e005c4b3bf07c92e291a09/numpy-2.4.6-cp314-cp314-win_amd64.whl", hash = "sha256:b507f5c4c1d508876d1819b6bf9a49d365b96320b5d4993426b33a23ca4b8261", size = 12450334, upload-time = "2026-05-18T23:36:09.107Z" }, - { url = "https://files.pythonhosted.org/packages/78/92/b8b798ac784102c0da830d2257d59358e3d3d90d1e2b3f2575dad976c5cf/numpy-2.4.6-cp314-cp314-win_arm64.whl", hash = "sha256:6f41ae150c4e32db4f3310cdaf64b1593a03dbabe29eec77fc9b50fe64061df6", size = 10495678, upload-time = "2026-05-18T23:36:12.766Z" }, - { url = "https://files.pythonhosted.org/packages/30/34/ec28d1aa8115971537c01469ab2011ee96827930f0a124de1000cc2a7ed7/numpy-2.4.6-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:ece3d2cfe132e7d51f44a832b303895e6f2d499c5e74dfbdb06ee246147a304a", size = 14823672, upload-time = "2026-05-18T23:36:16.473Z" }, - { url = "https://files.pythonhosted.org/packages/16/bd/f6d1fede4e54e8042a7ff97bb495510f3c220f94bcd9e8b228e87c92cc0d/numpy-2.4.6-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:e3e5193ef5a3dc73bceee50f7fdc2c90dbb76c42df8d8fae3d1067a583df579e", size = 5328731, upload-time = "2026-05-18T23:36:19.767Z" }, - { url = "https://files.pythonhosted.org/packages/f4/f0/e105b9e2fd728a9910103884decd6951d9dd73896b914a98d9a231de02ee/numpy-2.4.6-cp314-cp314t-macosx_14_0_x86_64.whl", hash = "sha256:17f9ade344e7d9b464a084d69bcf18fc691cb1db67c62ed80820bf4926d78f0e", size = 6649805, upload-time = "2026-05-18T23:36:22.266Z" }, - { url = "https://files.pythonhosted.org/packages/82/dd/1206a7ca6ab15e3f02069707ca96222e202af681bb73756da7527f3cb837/numpy-2.4.6-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9cd5ffd25db4e7ba6a375693b3fc0fc1791ec636c17db3720da19bde7180ec43", size = 15730496, upload-time = "2026-05-18T23:36:25.713Z" }, - { url = "https://files.pythonhosted.org/packages/51/e7/38d3ea825dcab85a591734decb2f6c67caa7c8367d374df1a1c3842f9b07/numpy-2.4.6-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7d92c3819208a60205a12a245c91ad70cb0a85336659b19b834205573ac8456e", size = 16679616, upload-time = "2026-05-18T23:36:29.652Z" }, - { url = "https://files.pythonhosted.org/packages/93/b7/caabfdf53edf663e0b4eb74d7d405d83baef09eb5e83bcd32d601d72b93e/numpy-2.4.6-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e85b752a1e912b70eaad4fafbd4d1238007ab221de2009b9a2f5ae7461239895", size = 17085145, upload-time = "2026-05-18T23:36:33.449Z" }, - { url = "https://files.pythonhosted.org/packages/f9/45/68d7c33a6bcf3e5aa3bdbd57a367e6f615286dfd6482f97e8ffeb734306e/numpy-2.4.6-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:29cb7f67d10b479ff07c17d33e39f78c07f71c40ef30d63c153d340e96cd3fb4", size = 18403813, upload-time = "2026-05-18T23:36:37.369Z" }, - { url = "https://files.pythonhosted.org/packages/9c/50/0753655aa844c99cd9e018aacf76f130f1bd81d881bb74bc0aef5d73a8ba/numpy-2.4.6-cp314-cp314t-win32.whl", hash = "sha256:260a5d70215b61ab4fadf5c7baacd64821842975eea312125ed3c39a6391b063", size = 6156982, upload-time = "2026-05-18T23:36:40.817Z" }, - { url = "https://files.pythonhosted.org/packages/b2/d4/7c67becf668f973cb490cec3e98dfd799d866f9c989a54d355672cfa0db6/numpy-2.4.6-cp314-cp314t-win_amd64.whl", hash = "sha256:81a1cca95ed5bb92aa8b10dd2cdc9a0d3853a50fad926c28b5d7e8ea54389627", size = 12638908, upload-time = "2026-05-18T23:36:43.996Z" }, - { url = "https://files.pythonhosted.org/packages/43/bb/e1c71a4295b1b1d1393d50dbb4f2a36283c6859d9d3892e84f00ec5a91d5/numpy-2.4.6-cp314-cp314t-win_arm64.whl", hash = "sha256:0c9136e14ed34a9e343a31c533d78a9813a69a3148332bce5e9821cb2f996e66", size = 10565867, upload-time = "2026-05-18T23:36:47.114Z" }, - { url = "https://files.pythonhosted.org/packages/de/12/b422cc84439adc0d00de605bf4a308890ae5c26f2c71fbd73e5d08fbb0dd/numpy-2.4.6-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:55cced7c52e981362f708ad635198e97a752dfba412cc03c23bbf3bd8d5cd662", size = 16847511, upload-time = "2026-05-18T23:36:50.673Z" }, - { url = "https://files.pythonhosted.org/packages/44/53/f481bef68011740f8849418d82db07230e825013f31f4eef5ba5b805316a/numpy-2.4.6-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:d6da64deb6b8ed903e7560180a92f2d804ee1ba5eeb849ac2748b8c1aba1f6d7", size = 14889064, upload-time = "2026-05-18T23:36:53.879Z" }, - { url = "https://files.pythonhosted.org/packages/7f/57/42ed575c10ced8af951d426bc4e1f8aff16fd851db33f067036215a7f860/numpy-2.4.6-pp311-pypy311_pp73-macosx_14_0_arm64.whl", hash = "sha256:68a5124b13fa6cc2086764a20005d30bc0548146f7f5322f02fce212ca14317f", size = 5394157, upload-time = "2026-05-18T23:36:57.194Z" }, - { url = "https://files.pythonhosted.org/packages/6a/ef/f66cc724fcc36c1e364c67f51ae9146090b8b584f27d58b97fdae3edd737/numpy-2.4.6-pp311-pypy311_pp73-macosx_14_0_x86_64.whl", hash = "sha256:948424b06129ce883307e8cff868c31396d8dc7630a59c61d70d98dbe70f222c", size = 6708728, upload-time = "2026-05-18T23:36:59.575Z" }, - { url = "https://files.pythonhosted.org/packages/1a/9c/c531f2293b91265d8b48e9b329f54fdd7ffae73cb4134ea10cca4237e9cc/numpy-2.4.6-pp311-pypy311_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5dbbdb29840ca3d91ee0fece42fc29278886d908280bfec0a5846c6f901a3eb0", size = 15798374, upload-time = "2026-05-18T23:37:02.674Z" }, - { url = "https://files.pythonhosted.org/packages/1a/b0/413077f6b1153ed3cba361401c6783bbad6114804a000cc22eb71c13e190/numpy-2.4.6-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8ad03c0965fb3c692200e74d458ca28c1dbb4ce96f9a479a8aa041ad5fabca02", size = 16747286, upload-time = "2026-05-18T23:37:06.327Z" }, - { url = "https://files.pythonhosted.org/packages/15/ce/e5ec180bc41812edcd8daeb8639d205622c0e8c02259d8ab25a0201b3c2a/numpy-2.4.6-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:2803abfebfc990042cd494d8ce2d5f82e9d847af6d35ec486923aa19dbad5e73", size = 12504263, upload-time = "2026-05-18T23:37:09.715Z" }, -] - -[[package]] -name = "packaging" -version = "26.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d7/f1/e7a6dd94a8d4a5626c03e4e99c87f241ba9e350cd9e6d75123f992427270/packaging-26.2.tar.gz", hash = "sha256:ff452ff5a3e828ce110190feff1178bb1f2ea2281fa2075aadb987c2fb221661", size = 228134, upload-time = "2026-04-24T20:15:23.917Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl", hash = "sha256:5fc45236b9446107ff2415ce77c807cee2862cb6fac22b8a73826d0693b0980e", size = 100195, upload-time = "2026-04-24T20:15:22.081Z" }, -] - -[[package]] -name = "pillow" -version = "12.2.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/8c/21/c2bcdd5906101a30244eaffc1b6e6ce71a31bd0742a01eb89e660ebfac2d/pillow-12.2.0.tar.gz", hash = "sha256:a830b1a40919539d07806aa58e1b114df53ddd43213d9c8b75847eee6c0182b5", size = 46987819, upload-time = "2026-04-01T14:46:17.687Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/3a/aa/d0b28e1c811cd4d5f5c2bfe2e022292bd255ae5744a3b9ac7d6c8f72dd75/pillow-12.2.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:a4e8f36e677d3336f35089648c8955c51c6d386a13cf6ee9c189c5f5bd713a9f", size = 5354355, upload-time = "2026-04-01T14:42:15.402Z" }, - { url = "https://files.pythonhosted.org/packages/27/8e/1d5b39b8ae2bd7650d0c7b6abb9602d16043ead9ebbfef4bc4047454da2a/pillow-12.2.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2e589959f10d9824d39b350472b92f0ce3b443c0a3442ebf41c40cb8361c5b97", size = 4695871, upload-time = "2026-04-01T14:42:18.234Z" }, - { url = "https://files.pythonhosted.org/packages/f0/c5/dcb7a6ca6b7d3be41a76958e90018d56c8462166b3ef223150360850c8da/pillow-12.2.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:a52edc8bfff4429aaabdf4d9ee0daadbbf8562364f940937b941f87a4290f5ff", size = 6269734, upload-time = "2026-04-01T14:42:20.608Z" }, - { url = "https://files.pythonhosted.org/packages/ea/f1/aa1bb13b2f4eba914e9637893c73f2af8e48d7d4023b9d3750d4c5eb2d0c/pillow-12.2.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:975385f4776fafde056abb318f612ef6285b10a1f12b8570f3647ad0d74b48ec", size = 8076080, upload-time = "2026-04-01T14:42:23.095Z" }, - { url = "https://files.pythonhosted.org/packages/a1/2a/8c79d6a53169937784604a8ae8d77e45888c41537f7f6f65ed1f407fe66d/pillow-12.2.0-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bd9c0c7a0c681a347b3194c500cb1e6ca9cab053ea4d82a5cf45b6b754560136", size = 6382236, upload-time = "2026-04-01T14:42:25.82Z" }, - { url = "https://files.pythonhosted.org/packages/b5/42/bbcb6051030e1e421d103ce7a8ecadf837aa2f39b8f82ef1a8d37c3d4ebc/pillow-12.2.0-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:88d387ff40b3ff7c274947ed3125dedf5262ec6919d83946753b5f3d7c67ea4c", size = 7070220, upload-time = "2026-04-01T14:42:28.68Z" }, - { url = "https://files.pythonhosted.org/packages/3f/e1/c2a7d6dd8cfa6b231227da096fd2d58754bab3603b9d73bf609d3c18b64f/pillow-12.2.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:51c4167c34b0d8ba05b547a3bb23578d0ba17b80a5593f93bd8ecb123dd336a3", size = 6493124, upload-time = "2026-04-01T14:42:31.579Z" }, - { url = "https://files.pythonhosted.org/packages/5f/41/7c8617da5d32e1d2f026e509484fdb6f3ad7efaef1749a0c1928adbb099e/pillow-12.2.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:34c0d99ecccea270c04882cb3b86e7b57296079c9a4aff88cb3b33563d95afaa", size = 7194324, upload-time = "2026-04-01T14:42:34.615Z" }, - { url = "https://files.pythonhosted.org/packages/2d/de/a777627e19fd6d62f84070ee1521adde5eeda4855b5cf60fe0b149118bca/pillow-12.2.0-cp310-cp310-win32.whl", hash = "sha256:b85f66ae9eb53e860a873b858b789217ba505e5e405a24b85c0464822fe88032", size = 6376363, upload-time = "2026-04-01T14:42:37.19Z" }, - { url = "https://files.pythonhosted.org/packages/e7/34/fc4cb5204896465842767b96d250c08410f01f2f28afc43b257de842eed5/pillow-12.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:673aa32138f3e7531ccdbca7b3901dba9b70940a19ccecc6a37c77d5fdeb05b5", size = 7083523, upload-time = "2026-04-01T14:42:39.62Z" }, - { url = "https://files.pythonhosted.org/packages/2d/a0/32852d36bc7709f14dc3f64f929a275e958ad8c19a6deba9610d458e28b3/pillow-12.2.0-cp310-cp310-win_arm64.whl", hash = "sha256:3e080565d8d7c671db5802eedfb438e5565ffa40115216eabb8cd52d0ecce024", size = 2463318, upload-time = "2026-04-01T14:42:42.063Z" }, - { url = "https://files.pythonhosted.org/packages/68/e1/748f5663efe6edcfc4e74b2b93edfb9b8b99b67f21a854c3ae416500a2d9/pillow-12.2.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:8be29e59487a79f173507c30ddf57e733a357f67881430449bb32614075a40ab", size = 5354347, upload-time = "2026-04-01T14:42:44.255Z" }, - { url = "https://files.pythonhosted.org/packages/47/a1/d5ff69e747374c33a3b53b9f98cca7889fce1fd03d79cdc4e1bccc6c5a87/pillow-12.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:71cde9a1e1551df7d34a25462fc60325e8a11a82cc2e2f54578e5e9a1e153d65", size = 4695873, upload-time = "2026-04-01T14:42:46.452Z" }, - { url = "https://files.pythonhosted.org/packages/df/21/e3fbdf54408a973c7f7f89a23b2cb97a7ef30c61ab4142af31eee6aebc88/pillow-12.2.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:f490f9368b6fc026f021db16d7ec2fbf7d89e2edb42e8ec09d2c60505f5729c7", size = 6280168, upload-time = "2026-04-01T14:42:49.228Z" }, - { url = "https://files.pythonhosted.org/packages/d3/f1/00b7278c7dd52b17ad4329153748f87b6756ec195ff786c2bdf12518337d/pillow-12.2.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8bd7903a5f2a4545f6fd5935c90058b89d30045568985a71c79f5fd6edf9b91e", size = 8088188, upload-time = "2026-04-01T14:42:51.735Z" }, - { url = "https://files.pythonhosted.org/packages/ad/cf/220a5994ef1b10e70e85748b75649d77d506499352be135a4989c957b701/pillow-12.2.0-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3997232e10d2920a68d25191392e3a4487d8183039e1c74c2297f00ed1c50705", size = 6394401, upload-time = "2026-04-01T14:42:54.343Z" }, - { url = "https://files.pythonhosted.org/packages/e9/bd/e51a61b1054f09437acfbc2ff9106c30d1eb76bc1453d428399946781253/pillow-12.2.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e74473c875d78b8e9d5da2a70f7099549f9eb37ded4e2f6a463e60125bccd176", size = 7079655, upload-time = "2026-04-01T14:42:56.954Z" }, - { url = "https://files.pythonhosted.org/packages/6b/3d/45132c57d5fb4b5744567c3817026480ac7fc3ce5d4c47902bc0e7f6f853/pillow-12.2.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:56a3f9c60a13133a98ecff6197af34d7824de9b7b38c3654861a725c970c197b", size = 6503105, upload-time = "2026-04-01T14:42:59.847Z" }, - { url = "https://files.pythonhosted.org/packages/7d/2e/9df2fc1e82097b1df3dce58dc43286aa01068e918c07574711fcc53e6fb4/pillow-12.2.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:90e6f81de50ad6b534cab6e5aef77ff6e37722b2f5d908686f4a5c9eba17a909", size = 7203402, upload-time = "2026-04-01T14:43:02.664Z" }, - { url = "https://files.pythonhosted.org/packages/bd/2e/2941e42858ebb67e50ae741473de81c2984e6eff7b397017623c676e2e8d/pillow-12.2.0-cp311-cp311-win32.whl", hash = "sha256:8c984051042858021a54926eb597d6ee3012393ce9c181814115df4c60b9a808", size = 6378149, upload-time = "2026-04-01T14:43:05.274Z" }, - { url = "https://files.pythonhosted.org/packages/69/42/836b6f3cd7f3e5fa10a1f1a5420447c17966044c8fbf589cc0452d5502db/pillow-12.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:6e6b2a0c538fc200b38ff9eb6628228b77908c319a005815f2dde585a0664b60", size = 7082626, upload-time = "2026-04-01T14:43:08.557Z" }, - { url = "https://files.pythonhosted.org/packages/c2/88/549194b5d6f1f494b485e493edc6693c0a16f4ada488e5bd974ed1f42fad/pillow-12.2.0-cp311-cp311-win_arm64.whl", hash = "sha256:9a8a34cc89c67a65ea7437ce257cea81a9dad65b29805f3ecee8c8fe8ff25ffe", size = 2463531, upload-time = "2026-04-01T14:43:10.743Z" }, - { url = "https://files.pythonhosted.org/packages/58/be/7482c8a5ebebbc6470b3eb791812fff7d5e0216c2be3827b30b8bb6603ed/pillow-12.2.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:2d192a155bbcec180f8564f693e6fd9bccff5a7af9b32e2e4bf8c9c69dbad6b5", size = 5308279, upload-time = "2026-04-01T14:43:13.246Z" }, - { url = "https://files.pythonhosted.org/packages/d8/95/0a351b9289c2b5cbde0bacd4a83ebc44023e835490a727b2a3bd60ddc0f4/pillow-12.2.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f3f40b3c5a968281fd507d519e444c35f0ff171237f4fdde090dd60699458421", size = 4695490, upload-time = "2026-04-01T14:43:15.584Z" }, - { url = "https://files.pythonhosted.org/packages/de/af/4e8e6869cbed569d43c416fad3dc4ecb944cb5d9492defaed89ddd6fe871/pillow-12.2.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:03e7e372d5240cc23e9f07deca4d775c0817bffc641b01e9c3af208dbd300987", size = 6284462, upload-time = "2026-04-01T14:43:18.268Z" }, - { url = "https://files.pythonhosted.org/packages/e9/9e/c05e19657fd57841e476be1ab46c4d501bffbadbafdc31a6d665f8b737b6/pillow-12.2.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:b86024e52a1b269467a802258c25521e6d742349d760728092e1bc2d135b4d76", size = 8094744, upload-time = "2026-04-01T14:43:20.716Z" }, - { url = "https://files.pythonhosted.org/packages/2b/54/1789c455ed10176066b6e7e6da1b01e50e36f94ba584dc68d9eebfe9156d/pillow-12.2.0-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7371b48c4fa448d20d2714c9a1f775a81155050d383333e0a6c15b1123dda005", size = 6398371, upload-time = "2026-04-01T14:43:23.443Z" }, - { url = "https://files.pythonhosted.org/packages/43/e3/fdc657359e919462369869f1c9f0e973f353f9a9ee295a39b1fea8ee1a77/pillow-12.2.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:62f5409336adb0663b7caa0da5c7d9e7bdbaae9ce761d34669420c2a801b2780", size = 7087215, upload-time = "2026-04-01T14:43:26.758Z" }, - { url = "https://files.pythonhosted.org/packages/8b/f8/2f6825e441d5b1959d2ca5adec984210f1ec086435b0ed5f52c19b3b8a6e/pillow-12.2.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:01afa7cf67f74f09523699b4e88c73fb55c13346d212a59a2db1f86b0a63e8c5", size = 6509783, upload-time = "2026-04-01T14:43:29.56Z" }, - { url = "https://files.pythonhosted.org/packages/67/f9/029a27095ad20f854f9dba026b3ea6428548316e057e6fc3545409e86651/pillow-12.2.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fc3d34d4a8fbec3e88a79b92e5465e0f9b842b628675850d860b8bd300b159f5", size = 7212112, upload-time = "2026-04-01T14:43:32.091Z" }, - { url = "https://files.pythonhosted.org/packages/be/42/025cfe05d1be22dbfdb4f264fe9de1ccda83f66e4fc3aac94748e784af04/pillow-12.2.0-cp312-cp312-win32.whl", hash = "sha256:58f62cc0f00fd29e64b29f4fd923ffdb3859c9f9e6105bfc37ba1d08994e8940", size = 6378489, upload-time = "2026-04-01T14:43:34.601Z" }, - { url = "https://files.pythonhosted.org/packages/5d/7b/25a221d2c761c6a8ae21bfa3874988ff2583e19cf8a27bf2fee358df7942/pillow-12.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:7f84204dee22a783350679a0333981df803dac21a0190d706a50475e361c93f5", size = 7084129, upload-time = "2026-04-01T14:43:37.213Z" }, - { url = "https://files.pythonhosted.org/packages/10/e1/542a474affab20fd4a0f1836cb234e8493519da6b76899e30bcc5d990b8b/pillow-12.2.0-cp312-cp312-win_arm64.whl", hash = "sha256:af73337013e0b3b46f175e79492d96845b16126ddf79c438d7ea7ff27783a414", size = 2463612, upload-time = "2026-04-01T14:43:39.421Z" }, - { url = "https://files.pythonhosted.org/packages/4a/01/53d10cf0dbad820a8db274d259a37ba50b88b24768ddccec07355382d5ad/pillow-12.2.0-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:8297651f5b5679c19968abefd6bb84d95fe30ef712eb1b2d9b2d31ca61267f4c", size = 4100837, upload-time = "2026-04-01T14:43:41.506Z" }, - { url = "https://files.pythonhosted.org/packages/0f/98/f3a6657ecb698c937f6c76ee564882945f29b79bad496abcba0e84659ec5/pillow-12.2.0-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:50d8520da2a6ce0af445fa6d648c4273c3eeefbc32d7ce049f22e8b5c3daecc2", size = 4176528, upload-time = "2026-04-01T14:43:43.773Z" }, - { url = "https://files.pythonhosted.org/packages/69/bc/8986948f05e3ea490b8442ea1c1d4d990b24a7e43d8a51b2c7d8b1dced36/pillow-12.2.0-cp313-cp313-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:766cef22385fa1091258ad7e6216792b156dc16d8d3fa607e7545b2b72061f1c", size = 3640401, upload-time = "2026-04-01T14:43:45.87Z" }, - { url = "https://files.pythonhosted.org/packages/34/46/6c717baadcd62bc8ed51d238d521ab651eaa74838291bda1f86fe1f864c9/pillow-12.2.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:5d2fd0fa6b5d9d1de415060363433f28da8b1526c1c129020435e186794b3795", size = 5308094, upload-time = "2026-04-01T14:43:48.438Z" }, - { url = "https://files.pythonhosted.org/packages/71/43/905a14a8b17fdb1ccb58d282454490662d2cb89a6bfec26af6d3520da5ec/pillow-12.2.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:56b25336f502b6ed02e889f4ece894a72612fe885889a6e8c4c80239ff6e5f5f", size = 4695402, upload-time = "2026-04-01T14:43:51.292Z" }, - { url = "https://files.pythonhosted.org/packages/73/dd/42107efcb777b16fa0393317eac58f5b5cf30e8392e266e76e51cff28c3d/pillow-12.2.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:f1c943e96e85df3d3478f7b691f229887e143f81fedab9b20205349ab04d73ed", size = 6280005, upload-time = "2026-04-01T14:43:54.242Z" }, - { url = "https://files.pythonhosted.org/packages/a8/68/b93e09e5e8549019e61acf49f65b1a8530765a7f812c77a7461bca7e4494/pillow-12.2.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:03f6fab9219220f041c74aeaa2939ff0062bd5c364ba9ce037197f4c6d498cd9", size = 8090669, upload-time = "2026-04-01T14:43:57.335Z" }, - { url = "https://files.pythonhosted.org/packages/4b/6e/3ccb54ce8ec4ddd1accd2d89004308b7b0b21c4ac3d20fa70af4760a4330/pillow-12.2.0-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5cdfebd752ec52bf5bb4e35d9c64b40826bc5b40a13df7c3cda20a2c03a0f5ed", size = 6395194, upload-time = "2026-04-01T14:43:59.864Z" }, - { url = "https://files.pythonhosted.org/packages/67/ee/21d4e8536afd1a328f01b359b4d3997b291ffd35a237c877b331c1c3b71c/pillow-12.2.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:eedf4b74eda2b5a4b2b2fb4c006d6295df3bf29e459e198c90ea48e130dc75c3", size = 7082423, upload-time = "2026-04-01T14:44:02.74Z" }, - { url = "https://files.pythonhosted.org/packages/78/5f/e9f86ab0146464e8c133fe85df987ed9e77e08b29d8d35f9f9f4d6f917ba/pillow-12.2.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:00a2865911330191c0b818c59103b58a5e697cae67042366970a6b6f1b20b7f9", size = 6505667, upload-time = "2026-04-01T14:44:05.381Z" }, - { url = "https://files.pythonhosted.org/packages/ed/1e/409007f56a2fdce61584fd3acbc2bbc259857d555196cedcadc68c015c82/pillow-12.2.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:1e1757442ed87f4912397c6d35a0db6a7b52592156014706f17658ff58bbf795", size = 7208580, upload-time = "2026-04-01T14:44:08.39Z" }, - { url = "https://files.pythonhosted.org/packages/23/c4/7349421080b12fb35414607b8871e9534546c128a11965fd4a7002ccfbee/pillow-12.2.0-cp313-cp313-win32.whl", hash = "sha256:144748b3af2d1b358d41286056d0003f47cb339b8c43a9ea42f5fea4d8c66b6e", size = 6375896, upload-time = "2026-04-01T14:44:11.197Z" }, - { url = "https://files.pythonhosted.org/packages/3f/82/8a3739a5e470b3c6cbb1d21d315800d8e16bff503d1f16b03a4ec3212786/pillow-12.2.0-cp313-cp313-win_amd64.whl", hash = "sha256:390ede346628ccc626e5730107cde16c42d3836b89662a115a921f28440e6a3b", size = 7081266, upload-time = "2026-04-01T14:44:13.947Z" }, - { url = "https://files.pythonhosted.org/packages/c3/25/f968f618a062574294592f668218f8af564830ccebdd1fa6200f598e65c5/pillow-12.2.0-cp313-cp313-win_arm64.whl", hash = "sha256:8023abc91fba39036dbce14a7d6535632f99c0b857807cbbbf21ecc9f4717f06", size = 2463508, upload-time = "2026-04-01T14:44:16.312Z" }, - { url = "https://files.pythonhosted.org/packages/4d/a4/b342930964e3cb4dce5038ae34b0eab4653334995336cd486c5a8c25a00c/pillow-12.2.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:042db20a421b9bafecc4b84a8b6e444686bd9d836c7fd24542db3e7df7baad9b", size = 5309927, upload-time = "2026-04-01T14:44:18.89Z" }, - { url = "https://files.pythonhosted.org/packages/9f/de/23198e0a65a9cf06123f5435a5d95cea62a635697f8f03d134d3f3a96151/pillow-12.2.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:dd025009355c926a84a612fecf58bb315a3f6814b17ead51a8e48d3823d9087f", size = 4698624, upload-time = "2026-04-01T14:44:21.115Z" }, - { url = "https://files.pythonhosted.org/packages/01/a6/1265e977f17d93ea37aa28aa81bad4fa597933879fac2520d24e021c8da3/pillow-12.2.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:88ddbc66737e277852913bd1e07c150cc7bb124539f94c4e2df5344494e0a612", size = 6321252, upload-time = "2026-04-01T14:44:23.663Z" }, - { url = "https://files.pythonhosted.org/packages/3c/83/5982eb4a285967baa70340320be9f88e57665a387e3a53a7f0db8231a0cd/pillow-12.2.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d362d1878f00c142b7e1a16e6e5e780f02be8195123f164edf7eddd911eefe7c", size = 8126550, upload-time = "2026-04-01T14:44:26.772Z" }, - { url = "https://files.pythonhosted.org/packages/4e/48/6ffc514adce69f6050d0753b1a18fd920fce8cac87620d5a31231b04bfc5/pillow-12.2.0-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2c727a6d53cb0018aadd8018c2b938376af27914a68a492f59dfcaca650d5eea", size = 6433114, upload-time = "2026-04-01T14:44:29.615Z" }, - { url = "https://files.pythonhosted.org/packages/36/a3/f9a77144231fb8d40ee27107b4463e205fa4677e2ca2548e14da5cf18dce/pillow-12.2.0-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:efd8c21c98c5cc60653bcb311bef2ce0401642b7ce9d09e03a7da87c878289d4", size = 7115667, upload-time = "2026-04-01T14:44:32.773Z" }, - { url = "https://files.pythonhosted.org/packages/c1/fc/ac4ee3041e7d5a565e1c4fd72a113f03b6394cc72ab7089d27608f8aaccb/pillow-12.2.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9f08483a632889536b8139663db60f6724bfcb443c96f1b18855860d7d5c0fd4", size = 6538966, upload-time = "2026-04-01T14:44:35.252Z" }, - { url = "https://files.pythonhosted.org/packages/c0/a8/27fb307055087f3668f6d0a8ccb636e7431d56ed0750e07a60547b1e083e/pillow-12.2.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:dac8d77255a37e81a2efcbd1fc05f1c15ee82200e6c240d7e127e25e365c39ea", size = 7238241, upload-time = "2026-04-01T14:44:37.875Z" }, - { url = "https://files.pythonhosted.org/packages/ad/4b/926ab182c07fccae9fcb120043464e1ff1564775ec8864f21a0ebce6ac25/pillow-12.2.0-cp313-cp313t-win32.whl", hash = "sha256:ee3120ae9dff32f121610bb08e4313be87e03efeadfc6c0d18f89127e24d0c24", size = 6379592, upload-time = "2026-04-01T14:44:40.336Z" }, - { url = "https://files.pythonhosted.org/packages/c2/c4/f9e476451a098181b30050cc4c9a3556b64c02cf6497ea421ac047e89e4b/pillow-12.2.0-cp313-cp313t-win_amd64.whl", hash = "sha256:325ca0528c6788d2a6c3d40e3568639398137346c3d6e66bb61db96b96511c98", size = 7085542, upload-time = "2026-04-01T14:44:43.251Z" }, - { url = "https://files.pythonhosted.org/packages/00/a4/285f12aeacbe2d6dc36c407dfbbe9e96d4a80b0fb710a337f6d2ad978c75/pillow-12.2.0-cp313-cp313t-win_arm64.whl", hash = "sha256:2e5a76d03a6c6dcef67edabda7a52494afa4035021a79c8558e14af25313d453", size = 2465765, upload-time = "2026-04-01T14:44:45.996Z" }, - { url = "https://files.pythonhosted.org/packages/bf/98/4595daa2365416a86cb0d495248a393dfc84e96d62ad080c8546256cb9c0/pillow-12.2.0-cp314-cp314-ios_13_0_arm64_iphoneos.whl", hash = "sha256:3adc9215e8be0448ed6e814966ecf3d9952f0ea40eb14e89a102b87f450660d8", size = 4100848, upload-time = "2026-04-01T14:44:48.48Z" }, - { url = "https://files.pythonhosted.org/packages/0b/79/40184d464cf89f6663e18dfcf7ca21aae2491fff1a16127681bf1fa9b8cf/pillow-12.2.0-cp314-cp314-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:6a9adfc6d24b10f89588096364cc726174118c62130c817c2837c60cf08a392b", size = 4176515, upload-time = "2026-04-01T14:44:51.353Z" }, - { url = "https://files.pythonhosted.org/packages/b0/63/703f86fd4c422a9cf722833670f4f71418fb116b2853ff7da722ea43f184/pillow-12.2.0-cp314-cp314-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:6a6e67ea2e6feda684ed370f9a1c52e7a243631c025ba42149a2cc5934dec295", size = 3640159, upload-time = "2026-04-01T14:44:53.588Z" }, - { url = "https://files.pythonhosted.org/packages/71/e0/fb22f797187d0be2270f83500aab851536101b254bfa1eae10795709d283/pillow-12.2.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:2bb4a8d594eacdfc59d9e5ad972aa8afdd48d584ffd5f13a937a664c3e7db0ed", size = 5312185, upload-time = "2026-04-01T14:44:56.039Z" }, - { url = "https://files.pythonhosted.org/packages/ba/8c/1a9e46228571de18f8e28f16fabdfc20212a5d019f3e3303452b3f0a580d/pillow-12.2.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:80b2da48193b2f33ed0c32c38140f9d3186583ce7d516526d462645fd98660ae", size = 4695386, upload-time = "2026-04-01T14:44:58.663Z" }, - { url = "https://files.pythonhosted.org/packages/70/62/98f6b7f0c88b9addd0e87c217ded307b36be024d4ff8869a812b241d1345/pillow-12.2.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:22db17c68434de69d8ecfc2fe821569195c0c373b25cccb9cbdacf2c6e53c601", size = 6280384, upload-time = "2026-04-01T14:45:01.5Z" }, - { url = "https://files.pythonhosted.org/packages/5e/03/688747d2e91cfbe0e64f316cd2e8005698f76ada3130d0194664174fa5de/pillow-12.2.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:7b14cc0106cd9aecda615dd6903840a058b4700fcb817687d0ee4fc8b6e389be", size = 8091599, upload-time = "2026-04-01T14:45:04.5Z" }, - { url = "https://files.pythonhosted.org/packages/f6/35/577e22b936fcdd66537329b33af0b4ccfefaeabd8aec04b266528cddb33c/pillow-12.2.0-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8cbeb542b2ebc6fcdacabf8aca8c1a97c9b3ad3927d46b8723f9d4f033288a0f", size = 6396021, upload-time = "2026-04-01T14:45:07.117Z" }, - { url = "https://files.pythonhosted.org/packages/11/8d/d2532ad2a603ca2b93ad9f5135732124e57811d0168155852f37fbce2458/pillow-12.2.0-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4bfd07bc812fbd20395212969e41931001fd59eb55a60658b0e5710872e95286", size = 7083360, upload-time = "2026-04-01T14:45:09.763Z" }, - { url = "https://files.pythonhosted.org/packages/5e/26/d325f9f56c7e039034897e7380e9cc202b1e368bfd04d4cbe6a441f02885/pillow-12.2.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:9aba9a17b623ef750a4d11b742cbafffeb48a869821252b30ee21b5e91392c50", size = 6507628, upload-time = "2026-04-01T14:45:12.378Z" }, - { url = "https://files.pythonhosted.org/packages/5f/f7/769d5632ffb0988f1c5e7660b3e731e30f7f8ec4318e94d0a5d674eb65a4/pillow-12.2.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:deede7c263feb25dba4e82ea23058a235dcc2fe1f6021025dc71f2b618e26104", size = 7209321, upload-time = "2026-04-01T14:45:15.122Z" }, - { url = "https://files.pythonhosted.org/packages/6a/7a/c253e3c645cd47f1aceea6a8bacdba9991bf45bb7dfe927f7c893e89c93c/pillow-12.2.0-cp314-cp314-win32.whl", hash = "sha256:632ff19b2778e43162304d50da0181ce24ac5bb8180122cbe1bf4673428328c7", size = 6479723, upload-time = "2026-04-01T14:45:17.797Z" }, - { url = "https://files.pythonhosted.org/packages/cd/8b/601e6566b957ca50e28725cb6c355c59c2c8609751efbecd980db44e0349/pillow-12.2.0-cp314-cp314-win_amd64.whl", hash = "sha256:4e6c62e9d237e9b65fac06857d511e90d8461a32adcc1b9065ea0c0fa3a28150", size = 7217400, upload-time = "2026-04-01T14:45:20.529Z" }, - { url = "https://files.pythonhosted.org/packages/d6/94/220e46c73065c3e2951bb91c11a1fb636c8c9ad427ac3ce7d7f3359b9b2f/pillow-12.2.0-cp314-cp314-win_arm64.whl", hash = "sha256:b1c1fbd8a5a1af3412a0810d060a78b5136ec0836c8a4ef9aa11807f2a22f4e1", size = 2554835, upload-time = "2026-04-01T14:45:23.162Z" }, - { url = "https://files.pythonhosted.org/packages/b6/ab/1b426a3974cb0e7da5c29ccff4807871d48110933a57207b5a676cccc155/pillow-12.2.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:57850958fe9c751670e49b2cecf6294acc99e562531f4bd317fa5ddee2068463", size = 5314225, upload-time = "2026-04-01T14:45:25.637Z" }, - { url = "https://files.pythonhosted.org/packages/19/1e/dce46f371be2438eecfee2a1960ee2a243bbe5e961890146d2dee1ff0f12/pillow-12.2.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:d5d38f1411c0ed9f97bcb49b7bd59b6b7c314e0e27420e34d99d844b9ce3b6f3", size = 4698541, upload-time = "2026-04-01T14:45:28.355Z" }, - { url = "https://files.pythonhosted.org/packages/55/c3/7fbecf70adb3a0c33b77a300dc52e424dc22ad8cdc06557a2e49523b703d/pillow-12.2.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:5c0a9f29ca8e79f09de89293f82fc9b0270bb4af1d58bc98f540cc4aedf03166", size = 6322251, upload-time = "2026-04-01T14:45:30.924Z" }, - { url = "https://files.pythonhosted.org/packages/1c/3c/7fbc17cfb7e4fe0ef1642e0abc17fc6c94c9f7a16be41498e12e2ba60408/pillow-12.2.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1610dd6c61621ae1cf811bef44d77e149ce3f7b95afe66a4512f8c59f25d9ebe", size = 8127807, upload-time = "2026-04-01T14:45:33.908Z" }, - { url = "https://files.pythonhosted.org/packages/ff/c3/a8ae14d6defd2e448493ff512fae903b1e9bd40b72efb6ec55ce0048c8ce/pillow-12.2.0-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0a34329707af4f73cf1782a36cd2289c0368880654a2c11f027bcee9052d35dd", size = 6433935, upload-time = "2026-04-01T14:45:36.623Z" }, - { url = "https://files.pythonhosted.org/packages/6e/32/2880fb3a074847ac159d8f902cb43278a61e85f681661e7419e6596803ed/pillow-12.2.0-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8e9c4f5b3c546fa3458a29ab22646c1c6c787ea8f5ef51300e5a60300736905e", size = 7116720, upload-time = "2026-04-01T14:45:39.258Z" }, - { url = "https://files.pythonhosted.org/packages/46/87/495cc9c30e0129501643f24d320076f4cc54f718341df18cc70ec94c44e1/pillow-12.2.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:fb043ee2f06b41473269765c2feae53fc2e2fbf96e5e22ca94fb5ad677856f06", size = 6540498, upload-time = "2026-04-01T14:45:41.879Z" }, - { url = "https://files.pythonhosted.org/packages/18/53/773f5edca692009d883a72211b60fdaf8871cbef075eaa9d577f0a2f989e/pillow-12.2.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:f278f034eb75b4e8a13a54a876cc4a5ab39173d2cdd93a638e1b467fc545ac43", size = 7239413, upload-time = "2026-04-01T14:45:44.705Z" }, - { url = "https://files.pythonhosted.org/packages/c9/e4/4b64a97d71b2a83158134abbb2f5bd3f8a2ea691361282f010998f339ec7/pillow-12.2.0-cp314-cp314t-win32.whl", hash = "sha256:6bb77b2dcb06b20f9f4b4a8454caa581cd4dd0643a08bacf821216a16d9c8354", size = 6482084, upload-time = "2026-04-01T14:45:47.568Z" }, - { url = "https://files.pythonhosted.org/packages/ba/13/306d275efd3a3453f72114b7431c877d10b1154014c1ebbedd067770d629/pillow-12.2.0-cp314-cp314t-win_amd64.whl", hash = "sha256:6562ace0d3fb5f20ed7290f1f929cae41b25ae29528f2af1722966a0a02e2aa1", size = 7225152, upload-time = "2026-04-01T14:45:50.032Z" }, - { url = "https://files.pythonhosted.org/packages/ff/6e/cf826fae916b8658848d7b9f38d88da6396895c676e8086fc0988073aaf8/pillow-12.2.0-cp314-cp314t-win_arm64.whl", hash = "sha256:aa88ccfe4e32d362816319ed727a004423aab09c5cea43c01a4b435643fa34eb", size = 2556579, upload-time = "2026-04-01T14:45:52.529Z" }, - { url = "https://files.pythonhosted.org/packages/4e/b7/2437044fb910f499610356d1352e3423753c98e34f915252aafecc64889f/pillow-12.2.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:0538bd5e05efec03ae613fd89c4ce0368ecd2ba239cc25b9f9be7ed426b0af1f", size = 5273969, upload-time = "2026-04-01T14:45:55.538Z" }, - { url = "https://files.pythonhosted.org/packages/f6/f4/8316e31de11b780f4ac08ef3654a75555e624a98db1056ecb2122d008d5a/pillow-12.2.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:394167b21da716608eac917c60aa9b969421b5dcbbe02ae7f013e7b85811c69d", size = 4659674, upload-time = "2026-04-01T14:45:58.093Z" }, - { url = "https://files.pythonhosted.org/packages/d4/37/664fca7201f8bb2aa1d20e2c3d5564a62e6ae5111741966c8319ca802361/pillow-12.2.0-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:5d04bfa02cc2d23b497d1e90a0f927070043f6cbf303e738300532379a4b4e0f", size = 5288479, upload-time = "2026-04-01T14:46:01.141Z" }, - { url = "https://files.pythonhosted.org/packages/49/62/5b0ed78fce87346be7a5cfcfaaad91f6a1f98c26f86bdbafa2066c647ef6/pillow-12.2.0-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:0c838a5125cee37e68edec915651521191cef1e6aa336b855f495766e77a366e", size = 7032230, upload-time = "2026-04-01T14:46:03.874Z" }, - { url = "https://files.pythonhosted.org/packages/c3/28/ec0fc38107fc32536908034e990c47914c57cd7c5a3ece4d8d8f7ffd7e27/pillow-12.2.0-pp311-pypy311_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4a6c9fa44005fa37a91ebfc95d081e8079757d2e904b27103f4f5fa6f0bf78c0", size = 5355404, upload-time = "2026-04-01T14:46:06.33Z" }, - { url = "https://files.pythonhosted.org/packages/5e/8b/51b0eddcfa2180d60e41f06bd6d0a62202b20b59c68f5a132e615b75aecf/pillow-12.2.0-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:25373b66e0dd5905ed63fa3cae13c82fbddf3079f2c8bf15c6fb6a35586324c1", size = 6002215, upload-time = "2026-04-01T14:46:08.83Z" }, - { url = "https://files.pythonhosted.org/packages/bc/60/5382c03e1970de634027cee8e1b7d39776b778b81812aaf45b694dfe9e28/pillow-12.2.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:bfa9c230d2fe991bed5318a5f119bd6780cda2915cca595393649fc118ab895e", size = 7080946, upload-time = "2026-04-01T14:46:11.734Z" }, -] - -[[package]] -name = "pygments" -version = "2.20.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/c3/b2/bc9c9196916376152d655522fdcebac55e66de6603a76a02bca1b6414f6c/pygments-2.20.0.tar.gz", hash = "sha256:6757cd03768053ff99f3039c1a36d6c0aa0b263438fcab17520b30a303a82b5f", size = 4955991, upload-time = "2026-03-29T13:29:33.898Z" } -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 = "pyyaml" -version = "6.0.3" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz", hash = "sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f", size = 130960, upload-time = "2025-09-25T21:33:16.546Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/f4/a0/39350dd17dd6d6c6507025c0e53aef67a9293a6d37d3511f23ea510d5800/pyyaml-6.0.3-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:214ed4befebe12df36bcc8bc2b64b396ca31be9304b8f59e25c11cf94a4c033b", size = 184227, upload-time = "2025-09-25T21:31:46.04Z" }, - { url = "https://files.pythonhosted.org/packages/05/14/52d505b5c59ce73244f59c7a50ecf47093ce4765f116cdb98286a71eeca2/pyyaml-6.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:02ea2dfa234451bbb8772601d7b8e426c2bfa197136796224e50e35a78777956", size = 174019, upload-time = "2025-09-25T21:31:47.706Z" }, - { url = "https://files.pythonhosted.org/packages/43/f7/0e6a5ae5599c838c696adb4e6330a59f463265bfa1e116cfd1fbb0abaaae/pyyaml-6.0.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b30236e45cf30d2b8e7b3e85881719e98507abed1011bf463a8fa23e9c3e98a8", size = 740646, upload-time = "2025-09-25T21:31:49.21Z" }, - { url = "https://files.pythonhosted.org/packages/2f/3a/61b9db1d28f00f8fd0ae760459a5c4bf1b941baf714e207b6eb0657d2578/pyyaml-6.0.3-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:66291b10affd76d76f54fad28e22e51719ef9ba22b29e1d7d03d6777a9174198", size = 840793, upload-time = "2025-09-25T21:31:50.735Z" }, - { url = "https://files.pythonhosted.org/packages/7a/1e/7acc4f0e74c4b3d9531e24739e0ab832a5edf40e64fbae1a9c01941cabd7/pyyaml-6.0.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9c7708761fccb9397fe64bbc0395abcae8c4bf7b0eac081e12b809bf47700d0b", size = 770293, upload-time = "2025-09-25T21:31:51.828Z" }, - { url = "https://files.pythonhosted.org/packages/8b/ef/abd085f06853af0cd59fa5f913d61a8eab65d7639ff2a658d18a25d6a89d/pyyaml-6.0.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:418cf3f2111bc80e0933b2cd8cd04f286338bb88bdc7bc8e6dd775ebde60b5e0", size = 732872, upload-time = "2025-09-25T21:31:53.282Z" }, - { url = "https://files.pythonhosted.org/packages/1f/15/2bc9c8faf6450a8b3c9fc5448ed869c599c0a74ba2669772b1f3a0040180/pyyaml-6.0.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:5e0b74767e5f8c593e8c9b5912019159ed0533c70051e9cce3e8b6aa699fcd69", size = 758828, upload-time = "2025-09-25T21:31:54.807Z" }, - { url = "https://files.pythonhosted.org/packages/a3/00/531e92e88c00f4333ce359e50c19b8d1de9fe8d581b1534e35ccfbc5f393/pyyaml-6.0.3-cp310-cp310-win32.whl", hash = "sha256:28c8d926f98f432f88adc23edf2e6d4921ac26fb084b028c733d01868d19007e", size = 142415, upload-time = "2025-09-25T21:31:55.885Z" }, - { url = "https://files.pythonhosted.org/packages/2a/fa/926c003379b19fca39dd4634818b00dec6c62d87faf628d1394e137354d4/pyyaml-6.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:bdb2c67c6c1390b63c6ff89f210c8fd09d9a1217a465701eac7316313c915e4c", size = 158561, upload-time = "2025-09-25T21:31:57.406Z" }, - { url = "https://files.pythonhosted.org/packages/6d/16/a95b6757765b7b031c9374925bb718d55e0a9ba8a1b6a12d25962ea44347/pyyaml-6.0.3-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:44edc647873928551a01e7a563d7452ccdebee747728c1080d881d68af7b997e", size = 185826, upload-time = "2025-09-25T21:31:58.655Z" }, - { url = "https://files.pythonhosted.org/packages/16/19/13de8e4377ed53079ee996e1ab0a9c33ec2faf808a4647b7b4c0d46dd239/pyyaml-6.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:652cb6edd41e718550aad172851962662ff2681490a8a711af6a4d288dd96824", size = 175577, upload-time = "2025-09-25T21:32:00.088Z" }, - { url = "https://files.pythonhosted.org/packages/0c/62/d2eb46264d4b157dae1275b573017abec435397aa59cbcdab6fc978a8af4/pyyaml-6.0.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:10892704fc220243f5305762e276552a0395f7beb4dbf9b14ec8fd43b57f126c", size = 775556, upload-time = "2025-09-25T21:32:01.31Z" }, - { url = "https://files.pythonhosted.org/packages/10/cb/16c3f2cf3266edd25aaa00d6c4350381c8b012ed6f5276675b9eba8d9ff4/pyyaml-6.0.3-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:850774a7879607d3a6f50d36d04f00ee69e7fc816450e5f7e58d7f17f1ae5c00", size = 882114, upload-time = "2025-09-25T21:32:03.376Z" }, - { url = "https://files.pythonhosted.org/packages/71/60/917329f640924b18ff085ab889a11c763e0b573da888e8404ff486657602/pyyaml-6.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b8bb0864c5a28024fac8a632c443c87c5aa6f215c0b126c449ae1a150412f31d", size = 806638, upload-time = "2025-09-25T21:32:04.553Z" }, - { url = "https://files.pythonhosted.org/packages/dd/6f/529b0f316a9fd167281a6c3826b5583e6192dba792dd55e3203d3f8e655a/pyyaml-6.0.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1d37d57ad971609cf3c53ba6a7e365e40660e3be0e5175fa9f2365a379d6095a", size = 767463, upload-time = "2025-09-25T21:32:06.152Z" }, - { url = "https://files.pythonhosted.org/packages/f2/6a/b627b4e0c1dd03718543519ffb2f1deea4a1e6d42fbab8021936a4d22589/pyyaml-6.0.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:37503bfbfc9d2c40b344d06b2199cf0e96e97957ab1c1b546fd4f87e53e5d3e4", size = 794986, upload-time = "2025-09-25T21:32:07.367Z" }, - { url = "https://files.pythonhosted.org/packages/45/91/47a6e1c42d9ee337c4839208f30d9f09caa9f720ec7582917b264defc875/pyyaml-6.0.3-cp311-cp311-win32.whl", hash = "sha256:8098f252adfa6c80ab48096053f512f2321f0b998f98150cea9bd23d83e1467b", size = 142543, upload-time = "2025-09-25T21:32:08.95Z" }, - { url = "https://files.pythonhosted.org/packages/da/e3/ea007450a105ae919a72393cb06f122f288ef60bba2dc64b26e2646fa315/pyyaml-6.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:9f3bfb4965eb874431221a3ff3fdcddc7e74e3b07799e0e84ca4a0f867d449bf", size = 158763, upload-time = "2025-09-25T21:32:09.96Z" }, - { url = "https://files.pythonhosted.org/packages/d1/33/422b98d2195232ca1826284a76852ad5a86fe23e31b009c9886b2d0fb8b2/pyyaml-6.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7f047e29dcae44602496db43be01ad42fc6f1cc0d8cd6c83d342306c32270196", size = 182063, upload-time = "2025-09-25T21:32:11.445Z" }, - { url = "https://files.pythonhosted.org/packages/89/a0/6cf41a19a1f2f3feab0e9c0b74134aa2ce6849093d5517a0c550fe37a648/pyyaml-6.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fc09d0aa354569bc501d4e787133afc08552722d3ab34836a80547331bb5d4a0", size = 173973, upload-time = "2025-09-25T21:32:12.492Z" }, - { url = "https://files.pythonhosted.org/packages/ed/23/7a778b6bd0b9a8039df8b1b1d80e2e2ad78aa04171592c8a5c43a56a6af4/pyyaml-6.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9149cad251584d5fb4981be1ecde53a1ca46c891a79788c0df828d2f166bda28", size = 775116, upload-time = "2025-09-25T21:32:13.652Z" }, - { url = "https://files.pythonhosted.org/packages/65/30/d7353c338e12baef4ecc1b09e877c1970bd3382789c159b4f89d6a70dc09/pyyaml-6.0.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5fdec68f91a0c6739b380c83b951e2c72ac0197ace422360e6d5a959d8d97b2c", size = 844011, upload-time = "2025-09-25T21:32:15.21Z" }, - { url = "https://files.pythonhosted.org/packages/8b/9d/b3589d3877982d4f2329302ef98a8026e7f4443c765c46cfecc8858c6b4b/pyyaml-6.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ba1cc08a7ccde2d2ec775841541641e4548226580ab850948cbfda66a1befcdc", size = 807870, upload-time = "2025-09-25T21:32:16.431Z" }, - { url = "https://files.pythonhosted.org/packages/05/c0/b3be26a015601b822b97d9149ff8cb5ead58c66f981e04fedf4e762f4bd4/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8dc52c23056b9ddd46818a57b78404882310fb473d63f17b07d5c40421e47f8e", size = 761089, upload-time = "2025-09-25T21:32:17.56Z" }, - { url = "https://files.pythonhosted.org/packages/be/8e/98435a21d1d4b46590d5459a22d88128103f8da4c2d4cb8f14f2a96504e1/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:41715c910c881bc081f1e8872880d3c650acf13dfa8214bad49ed4cede7c34ea", size = 790181, upload-time = "2025-09-25T21:32:18.834Z" }, - { url = "https://files.pythonhosted.org/packages/74/93/7baea19427dcfbe1e5a372d81473250b379f04b1bd3c4c5ff825e2327202/pyyaml-6.0.3-cp312-cp312-win32.whl", hash = "sha256:96b533f0e99f6579b3d4d4995707cf36df9100d67e0c8303a0c55b27b5f99bc5", size = 137658, upload-time = "2025-09-25T21:32:20.209Z" }, - { url = "https://files.pythonhosted.org/packages/86/bf/899e81e4cce32febab4fb42bb97dcdf66bc135272882d1987881a4b519e9/pyyaml-6.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:5fcd34e47f6e0b794d17de1b4ff496c00986e1c83f7ab2fb8fcfe9616ff7477b", size = 154003, upload-time = "2025-09-25T21:32:21.167Z" }, - { url = "https://files.pythonhosted.org/packages/1a/08/67bd04656199bbb51dbed1439b7f27601dfb576fb864099c7ef0c3e55531/pyyaml-6.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:64386e5e707d03a7e172c0701abfb7e10f0fb753ee1d773128192742712a98fd", size = 140344, upload-time = "2025-09-25T21:32:22.617Z" }, - { url = "https://files.pythonhosted.org/packages/d1/11/0fd08f8192109f7169db964b5707a2f1e8b745d4e239b784a5a1dd80d1db/pyyaml-6.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8da9669d359f02c0b91ccc01cac4a67f16afec0dac22c2ad09f46bee0697eba8", size = 181669, upload-time = "2025-09-25T21:32:23.673Z" }, - { url = "https://files.pythonhosted.org/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2283a07e2c21a2aa78d9c4442724ec1eb15f5e42a723b99cb3d822d48f5f7ad1", size = 173252, upload-time = "2025-09-25T21:32:25.149Z" }, - { url = "https://files.pythonhosted.org/packages/50/31/b20f376d3f810b9b2371e72ef5adb33879b25edb7a6d072cb7ca0c486398/pyyaml-6.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ee2922902c45ae8ccada2c5b501ab86c36525b883eff4255313a253a3160861c", size = 767081, upload-time = "2025-09-25T21:32:26.575Z" }, - { url = "https://files.pythonhosted.org/packages/49/1e/a55ca81e949270d5d4432fbbd19dfea5321eda7c41a849d443dc92fd1ff7/pyyaml-6.0.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a33284e20b78bd4a18c8c2282d549d10bc8408a2a7ff57653c0cf0b9be0afce5", size = 841159, upload-time = "2025-09-25T21:32:27.727Z" }, - { url = "https://files.pythonhosted.org/packages/74/27/e5b8f34d02d9995b80abcef563ea1f8b56d20134d8f4e5e81733b1feceb2/pyyaml-6.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0f29edc409a6392443abf94b9cf89ce99889a1dd5376d94316ae5145dfedd5d6", size = 801626, upload-time = "2025-09-25T21:32:28.878Z" }, - { url = "https://files.pythonhosted.org/packages/f9/11/ba845c23988798f40e52ba45f34849aa8a1f2d4af4b798588010792ebad6/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f7057c9a337546edc7973c0d3ba84ddcdf0daa14533c2065749c9075001090e6", size = 753613, upload-time = "2025-09-25T21:32:30.178Z" }, - { url = "https://files.pythonhosted.org/packages/3d/e0/7966e1a7bfc0a45bf0a7fb6b98ea03fc9b8d84fa7f2229e9659680b69ee3/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:eda16858a3cab07b80edaf74336ece1f986ba330fdb8ee0d6c0d68fe82bc96be", size = 794115, upload-time = "2025-09-25T21:32:31.353Z" }, - { url = "https://files.pythonhosted.org/packages/de/94/980b50a6531b3019e45ddeada0626d45fa85cbe22300844a7983285bed3b/pyyaml-6.0.3-cp313-cp313-win32.whl", hash = "sha256:d0eae10f8159e8fdad514efdc92d74fd8d682c933a6dd088030f3834bc8e6b26", size = 137427, upload-time = "2025-09-25T21:32:32.58Z" }, - { url = "https://files.pythonhosted.org/packages/97/c9/39d5b874e8b28845e4ec2202b5da735d0199dbe5b8fb85f91398814a9a46/pyyaml-6.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:79005a0d97d5ddabfeeea4cf676af11e647e41d81c9a7722a193022accdb6b7c", size = 154090, upload-time = "2025-09-25T21:32:33.659Z" }, - { url = "https://files.pythonhosted.org/packages/73/e8/2bdf3ca2090f68bb3d75b44da7bbc71843b19c9f2b9cb9b0f4ab7a5a4329/pyyaml-6.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:5498cd1645aa724a7c71c8f378eb29ebe23da2fc0d7a08071d89469bf1d2defb", size = 140246, upload-time = "2025-09-25T21:32:34.663Z" }, - { url = "https://files.pythonhosted.org/packages/9d/8c/f4bd7f6465179953d3ac9bc44ac1a8a3e6122cf8ada906b4f96c60172d43/pyyaml-6.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:8d1fab6bb153a416f9aeb4b8763bc0f22a5586065f86f7664fc23339fc1c1fac", size = 181814, upload-time = "2025-09-25T21:32:35.712Z" }, - { url = "https://files.pythonhosted.org/packages/bd/9c/4d95bb87eb2063d20db7b60faa3840c1b18025517ae857371c4dd55a6b3a/pyyaml-6.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:34d5fcd24b8445fadc33f9cf348c1047101756fd760b4dacb5c3e99755703310", size = 173809, upload-time = "2025-09-25T21:32:36.789Z" }, - { url = "https://files.pythonhosted.org/packages/92/b5/47e807c2623074914e29dabd16cbbdd4bf5e9b2db9f8090fa64411fc5382/pyyaml-6.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:501a031947e3a9025ed4405a168e6ef5ae3126c59f90ce0cd6f2bfc477be31b7", size = 766454, upload-time = "2025-09-25T21:32:37.966Z" }, - { url = "https://files.pythonhosted.org/packages/02/9e/e5e9b168be58564121efb3de6859c452fccde0ab093d8438905899a3a483/pyyaml-6.0.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b3bc83488de33889877a0f2543ade9f70c67d66d9ebb4ac959502e12de895788", size = 836355, upload-time = "2025-09-25T21:32:39.178Z" }, - { url = "https://files.pythonhosted.org/packages/88/f9/16491d7ed2a919954993e48aa941b200f38040928474c9e85ea9e64222c3/pyyaml-6.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c458b6d084f9b935061bc36216e8a69a7e293a2f1e68bf956dcd9e6cbcd143f5", size = 794175, upload-time = "2025-09-25T21:32:40.865Z" }, - { url = "https://files.pythonhosted.org/packages/dd/3f/5989debef34dc6397317802b527dbbafb2b4760878a53d4166579111411e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7c6610def4f163542a622a73fb39f534f8c101d690126992300bf3207eab9764", size = 755228, upload-time = "2025-09-25T21:32:42.084Z" }, - { url = "https://files.pythonhosted.org/packages/d7/ce/af88a49043cd2e265be63d083fc75b27b6ed062f5f9fd6cdc223ad62f03e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:5190d403f121660ce8d1d2c1bb2ef1bd05b5f68533fc5c2ea899bd15f4399b35", size = 789194, upload-time = "2025-09-25T21:32:43.362Z" }, - { url = "https://files.pythonhosted.org/packages/23/20/bb6982b26a40bb43951265ba29d4c246ef0ff59c9fdcdf0ed04e0687de4d/pyyaml-6.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:4a2e8cebe2ff6ab7d1050ecd59c25d4c8bd7e6f400f5f82b96557ac0abafd0ac", size = 156429, upload-time = "2025-09-25T21:32:57.844Z" }, - { url = "https://files.pythonhosted.org/packages/f4/f4/a4541072bb9422c8a883ab55255f918fa378ecf083f5b85e87fc2b4eda1b/pyyaml-6.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:93dda82c9c22deb0a405ea4dc5f2d0cda384168e466364dec6255b293923b2f3", size = 143912, upload-time = "2025-09-25T21:32:59.247Z" }, - { url = "https://files.pythonhosted.org/packages/7c/f9/07dd09ae774e4616edf6cda684ee78f97777bdd15847253637a6f052a62f/pyyaml-6.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:02893d100e99e03eda1c8fd5c441d8c60103fd175728e23e431db1b589cf5ab3", size = 189108, upload-time = "2025-09-25T21:32:44.377Z" }, - { url = "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c1ff362665ae507275af2853520967820d9124984e0f7466736aea23d8611fba", size = 183641, upload-time = "2025-09-25T21:32:45.407Z" }, - { url = "https://files.pythonhosted.org/packages/7b/5b/3babb19104a46945cf816d047db2788bcaf8c94527a805610b0289a01c6b/pyyaml-6.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6adc77889b628398debc7b65c073bcb99c4a0237b248cacaf3fe8a557563ef6c", size = 831901, upload-time = "2025-09-25T21:32:48.83Z" }, - { url = "https://files.pythonhosted.org/packages/8b/cc/dff0684d8dc44da4d22a13f35f073d558c268780ce3c6ba1b87055bb0b87/pyyaml-6.0.3-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a80cb027f6b349846a3bf6d73b5e95e782175e52f22108cfa17876aaeff93702", size = 861132, upload-time = "2025-09-25T21:32:50.149Z" }, - { url = "https://files.pythonhosted.org/packages/b1/5e/f77dc6b9036943e285ba76b49e118d9ea929885becb0a29ba8a7c75e29fe/pyyaml-6.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:00c4bdeba853cc34e7dd471f16b4114f4162dc03e6b7afcc2128711f0eca823c", size = 839261, upload-time = "2025-09-25T21:32:51.808Z" }, - { url = "https://files.pythonhosted.org/packages/ce/88/a9db1376aa2a228197c58b37302f284b5617f56a5d959fd1763fb1675ce6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:66e1674c3ef6f541c35191caae2d429b967b99e02040f5ba928632d9a7f0f065", size = 805272, upload-time = "2025-09-25T21:32:52.941Z" }, - { url = "https://files.pythonhosted.org/packages/da/92/1446574745d74df0c92e6aa4a7b0b3130706a4142b2d1a5869f2eaa423c6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:16249ee61e95f858e83976573de0f5b2893b3677ba71c9dd36b9cf8be9ac6d65", size = 829923, upload-time = "2025-09-25T21:32:54.537Z" }, - { url = "https://files.pythonhosted.org/packages/f0/7a/1c7270340330e575b92f397352af856a8c06f230aa3e76f86b39d01b416a/pyyaml-6.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4ad1906908f2f5ae4e5a8ddfce73c320c2a1429ec52eafd27138b7f1cbe341c9", size = 174062, upload-time = "2025-09-25T21:32:55.767Z" }, - { url = "https://files.pythonhosted.org/packages/f1/12/de94a39c2ef588c7e6455cfbe7343d3b2dc9d6b6b2f40c4c6565744c873d/pyyaml-6.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:ebc55a14a21cb14062aa4162f906cd962b28e2e9ea38f9b4391244cd8de4ae0b", size = 149341, upload-time = "2025-09-25T21:32:56.828Z" }, -] - -[[package]] -name = "regex" -version = "2026.5.9" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/dc/0e/49aee608ad09480e7fd276898c99ec6192985fa331abe4eb3a986094490b/regex-2026.5.9.tar.gz", hash = "sha256:a8234aa23ec39894bfe4a3f1b85616a7032481964a13ac6fc9f10de4f6fca270", size = 416074, upload-time = "2026-05-09T23:15:19.37Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/fe/ed/0ad2c8edf634918eb4484365d3819fa7bd7f58daf807fe7fb21812c316e5/regex-2026.5.9-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a9e1328e17c84c1a5d22ec9f785ecef4a967fab9a42b6a8dc3bcbebd0a0c9e44", size = 489438, upload-time = "2026-05-09T23:11:29.374Z" }, - { url = "https://files.pythonhosted.org/packages/89/a9/4ed972ad263963b860b7c3e86e0e1bcc791def47b43b8c8efe57e710f139/regex-2026.5.9-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bfe1ce50cbfb569d74e1e4337da6468961f31dbea55fd85aa5de59c0947a805a", size = 291270, upload-time = "2026-05-09T23:11:33.254Z" }, - { url = "https://files.pythonhosted.org/packages/16/81/075930d9fa28c4ea1f53398dd015ee7c882f623539759113cda1257f4b82/regex-2026.5.9-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:15ee42209947f4ca045412eae98416317238163618ace2a8e54f99586a466733", size = 289198, upload-time = "2026-05-09T23:11:35.769Z" }, - { url = "https://files.pythonhosted.org/packages/d4/c8/5cdfbf0b5dc6599e1b6131eff43262e5275d4ec3469ce10216061659aadb/regex-2026.5.9-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b4bb445ff3f725f59df8f6014edb547ee928ec7023a774f6a39a3f953038cbb2", size = 784765, upload-time = "2026-05-09T23:11:37.689Z" }, - { url = "https://files.pythonhosted.org/packages/cd/ca/ae5fd6edc59b7f84b904b31d6ec39a860cbcecd10f64bd5a062ca83a4864/regex-2026.5.9-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:446ddd671e43ab535810c4b21cff7104945c701d4a14d1e6d1cd6f4e445a8bea", size = 852115, upload-time = "2026-05-09T23:11:39.973Z" }, - { url = "https://files.pythonhosted.org/packages/f6/ce/a91cf555afb51f3b74a182e24ba073b91ea7bb64592fc4b315c111bb19fd/regex-2026.5.9-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:7b92817338591505f282cf3864c145244b1edcf5381d237038df955001091538", size = 899503, upload-time = "2026-05-09T23:11:42.48Z" }, - { url = "https://files.pythonhosted.org/packages/55/7f/725a0a2b245a4cf0c4bab29d0e97c74285d94136a65d1b55a6459a583502/regex-2026.5.9-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d6b8a143aca6c39b446ea8092cde25cc8fe9304d4f5fecfbc1a9dbb0282703c2", size = 794093, upload-time = "2026-05-09T23:11:44.681Z" }, - { url = "https://files.pythonhosted.org/packages/e3/2a/996efbd59ce6b5d4a09e3af6180ceb62af171f4a9a6fb557d2f0ae0d462b/regex-2026.5.9-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:0f03aa6898aaaac4592479821df16e68e8d0e29e903e65d8f2dfb2f19028a989", size = 786234, upload-time = "2026-05-09T23:11:46.882Z" }, - { url = "https://files.pythonhosted.org/packages/4b/0a/8731e8b8806174c9cdd5903f80a14990331c1f42fc4209b540952e9e010d/regex-2026.5.9-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:ed457d8e98ae812ed7732bef7bf78de78e834eae0372a74e23ca90ef21d910f9", size = 769895, upload-time = "2026-05-09T23:11:49.324Z" }, - { url = "https://files.pythonhosted.org/packages/9a/0b/932473194bd563f342a412ae2ffbbd6da608306a2bc4e99249a41c2b0b92/regex-2026.5.9-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:71b61c5bfe1c806332defc42ad6c780b3c55f661986d7f40283a3a88274b4c00", size = 774991, upload-time = "2026-05-09T23:11:51.261Z" }, - { url = "https://files.pythonhosted.org/packages/98/80/9523d196010031df25f7177ee0a467efbee436324038e5d99def17a57515/regex-2026.5.9-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:3b1e39888c5e0c7d92cea4fc777396c4a90363b05de75d02eb459a4752200808", size = 848790, upload-time = "2026-05-09T23:11:53.232Z" }, - { url = "https://files.pythonhosted.org/packages/3c/07/56987b35e89edf47e4a38cf2845aeee476bfa688a6bdbd3e820cda461dc1/regex-2026.5.9-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:6ba42b2e7e7f46cf68cc6a5ca36fa07959f9bbd9c6bdcc47b6ee76549a590248", size = 757679, upload-time = "2026-05-09T23:11:55.82Z" }, - { url = "https://files.pythonhosted.org/packages/04/2a/ff713fff0c566507c06a4ce2dc0ae8e7eeebc88811a95fc81cf1e7d534dd/regex-2026.5.9-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:c010eb8caca74bdb40c07498d7ece26b4428fd3f04aa8a72c9ac6f79e8faaac6", size = 837116, upload-time = "2026-05-09T23:11:57.934Z" }, - { url = "https://files.pythonhosted.org/packages/77/90/df6d982b03e3614785c6937ba51b57f6733d97d2ee1c9bc7531dbfab3a54/regex-2026.5.9-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:a6a563446a41adc451393dc6b8e6ad87979efaee3c8738690a8d1b08ebead1b4", size = 782081, upload-time = "2026-05-09T23:11:59.607Z" }, - { url = "https://files.pythonhosted.org/packages/c7/8a/4e88a5f7c3e98489aac4dd23142723d907b2a595b4a6abcbacabefeded09/regex-2026.5.9-cp310-cp310-win32.whl", hash = "sha256:954cc214c04663ee6d266fc61739cad83054683048de65c5bd1d640ad28098ac", size = 266247, upload-time = "2026-05-09T23:12:01.116Z" }, - { url = "https://files.pythonhosted.org/packages/6a/40/4b224cb0582b2dca1786726e6cdabe26abbf757d7f6718332f186da155d2/regex-2026.5.9-cp310-cp310-win_amd64.whl", hash = "sha256:b310768746dd314ea6e2ff4cc89ef215426813396ff4e94ee8e6f7096c8b6e03", size = 278416, upload-time = "2026-05-09T23:12:03.2Z" }, - { url = "https://files.pythonhosted.org/packages/12/4d/014fbe803204cab0947ee428f09f658a29632053dde1d3c6176bb4f0fd4c/regex-2026.5.9-cp310-cp310-win_arm64.whl", hash = "sha256:19c16ceb4a267a8789e25733e583983eeab9f0f8664e66b0bd1c5d21f14c2d4b", size = 270413, upload-time = "2026-05-09T23:12:04.649Z" }, - { url = "https://files.pythonhosted.org/packages/c2/dc/c1f2df4027e82fc54b5a473e4b250f5139faca49a0fbe29a48668d228f34/regex-2026.5.9-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:ccf5249114cc3e772ecdd88a98a86eca0fd74c61ce32a94743758c083fc05d48", size = 489445, upload-time = "2026-05-09T23:12:06.111Z" }, - { url = "https://files.pythonhosted.org/packages/03/d2/59f01110660081cce9c0bc30ebd0b5ee250dacf658e3248ed92f01e0e8ee/regex-2026.5.9-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:46f1326ca6e65b0879d23ca302c0f2415aad42ff0309b9c818e7949fe19a41d8", size = 291271, upload-time = "2026-05-09T23:12:07.731Z" }, - { url = "https://files.pythonhosted.org/packages/58/b6/14b2c84ff90ddb370c81d27503f4a0fcf071496416f4855f6cc8c5d81c35/regex-2026.5.9-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ef31cbfe458e21c6122ba8150ff060e0c7789ed0d26eb423f25472584920b555", size = 289212, upload-time = "2026-05-09T23:12:09.266Z" }, - { url = "https://files.pythonhosted.org/packages/03/d0/4db86529117320de0c84afd90e70bb47434625875e34fcef9d8c127c5b16/regex-2026.5.9-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:992604d02e6d9c6d786c24a706a71ecffe1020fc1ef264044474cd81fa2c3919", size = 792310, upload-time = "2026-05-09T23:12:11.416Z" }, - { url = "https://files.pythonhosted.org/packages/07/78/fe4800cd322f862ecffd2d553409b20d80650e5ed71b9d178f853d020b82/regex-2026.5.9-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c9411dd64ca95477225734a93dfc8583b51916b8d5942f99d6cac21e09965451", size = 861721, upload-time = "2026-05-09T23:12:13.681Z" }, - { url = "https://files.pythonhosted.org/packages/b5/d0/b3618a895dd8feb897c61bb2954edd265e1767d82a01d53065d5871127a3/regex-2026.5.9-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:3dd4a3ff360dfb836fecdb93a4598f9d6e2ac81e3e397125145c6221bf58cf4c", size = 906460, upload-time = "2026-05-09T23:12:15.443Z" }, - { url = "https://files.pythonhosted.org/packages/33/6f/1481597e859ef19508b345eec4afd1416ed6e6b459c75a64026ef193aecf/regex-2026.5.9-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2a661a7d270a61f7cf460caee8b9fa2d5ef9e5c681234bcb9e0fe14f488e7dfc", size = 799843, upload-time = "2026-05-09T23:12:16.892Z" }, - { url = "https://files.pythonhosted.org/packages/73/59/955734c803f59108deccba3597ae440c76b62a652733c0006e6243758420/regex-2026.5.9-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f079e50a0d3cc3cd5091fa9ff45869a2e6b2cd35895731edafb0327901a8d86d", size = 773610, upload-time = "2026-05-09T23:12:19.127Z" }, - { url = "https://files.pythonhosted.org/packages/68/8f/70c04a236d651c81881dac42ef8538bddda6121434509d0a22d9e601503b/regex-2026.5.9-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:4ebe8f0b5ec5a5024dc4a4c59f444c4e9afc5f2abdbb8962065b75d27fb971f9", size = 781645, upload-time = "2026-05-09T23:12:20.806Z" }, - { url = "https://files.pythonhosted.org/packages/1d/96/05c7434d88185e5d27fe54aeb74df86bd77cd79f52f0b4eae54faa8fea70/regex-2026.5.9-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:97cf3bc1b7d7d2306772ec07366c80d9df00ff79e79cea32898883a646d2fae2", size = 854473, upload-time = "2026-05-09T23:12:22.465Z" }, - { url = "https://files.pythonhosted.org/packages/4e/c1/6e3d8202d981f3117004bf341ee74893ba4ba8a9fbaf4b94615846550a08/regex-2026.5.9-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:0f9eede6a5cbdc02d4978090186390936e1776a7d1359b21e41014c609880bcf", size = 763311, upload-time = "2026-05-09T23:12:24.351Z" }, - { url = "https://files.pythonhosted.org/packages/93/c7/e7737f1526b3fb32bd4c337fd6c71c3ebb5c8296fc34d11197e0955d2e35/regex-2026.5.9-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:01f0f5f55f4b64dacec85dc116d3c05fd23ad3ff037bbc73a2085775953c2611", size = 844593, upload-time = "2026-05-09T23:12:26.341Z" }, - { url = "https://files.pythonhosted.org/packages/a5/27/0daffb1a535bb39f422c3d200f4ab023c71110ad66a32b366bee708baba0/regex-2026.5.9-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:1268eddd8486dc561d08eee1156e40aa3a8fe10f4bdec8fa653b455fcbffd12c", size = 789167, upload-time = "2026-05-09T23:12:27.975Z" }, - { url = "https://files.pythonhosted.org/packages/ce/fc/294fe4fac4f2ed67207b17471815870c1c45b3a489e08e0ac96daea16ef6/regex-2026.5.9-cp311-cp311-win32.whl", hash = "sha256:8676474c07469d6f33dd1085ca2cd45f65785f32518f2b20e36d9953ca07f994", size = 266249, upload-time = "2026-05-09T23:12:30.141Z" }, - { url = "https://files.pythonhosted.org/packages/d0/b0/8dce459f6245bcf8f6e9f23ac9569f1a0f15c131cc0745e82b43226204cf/regex-2026.5.9-cp311-cp311-win_amd64.whl", hash = "sha256:246de9d60aa3f8538b519834dd95cbf276ea263d6a7bd5a3666dc3fa0230505b", size = 278423, upload-time = "2026-05-09T23:12:31.676Z" }, - { url = "https://files.pythonhosted.org/packages/db/8d/f9aeff6ad63a3ef720386f2907e6d34a35a510a6e498ebad28b0fb3f6ab6/regex-2026.5.9-cp311-cp311-win_arm64.whl", hash = "sha256:d726ca3f0d76969bf1e8e477d160d3d666bbf999f6860bd314889e5345782046", size = 270420, upload-time = "2026-05-09T23:12:33.194Z" }, - { url = "https://files.pythonhosted.org/packages/50/9b/6550044bc44e17c84d312c031c2ec42fbdb6a4ec4e29093be3a172d08772/regex-2026.5.9-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:57eeeb05db7979413dec5438f2db21d7ecbba787cde7a711df1a6f6df672aa06", size = 490451, upload-time = "2026-05-09T23:12:34.72Z" }, - { url = "https://files.pythonhosted.org/packages/1e/95/fc7ba4303b5a0f92446a12ee6778ef2c6c799233f5060042a31bf390cfe9/regex-2026.5.9-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:398c521292f4c7fb807001dcd54694d3a1fcafc179a36ad9cc56f98df85930b6", size = 292112, upload-time = "2026-05-09T23:12:36.285Z" }, - { url = "https://files.pythonhosted.org/packages/54/4b/ee27938d1b2c443e89a9a10e00d2d19aa5ee300cd3d61140644e93bb083e/regex-2026.5.9-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f7a7c26137296beba7784de6eba69c6a93a63ccebc385e4962fe67e267a91225", size = 289599, upload-time = "2026-05-09T23:12:38.089Z" }, - { url = "https://files.pythonhosted.org/packages/d8/dd/ba103dc19614e25f3880800ca67ce093d6e21b325d72b8383c7bf906e9fa/regex-2026.5.9-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6441cc660d76107934a09c22167200839a0e89604a6297f78a974e66e931d2c0", size = 796732, upload-time = "2026-05-09T23:12:40.062Z" }, - { url = "https://files.pythonhosted.org/packages/cf/e7/f035b4fd858b050b0080bf302968dc0f59ba34e391872d54936758e6844e/regex-2026.5.9-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:91328f1c23d47595ca3ef0a7557fa129c5a23404b775c770697d2f35b33e0107", size = 865440, upload-time = "2026-05-09T23:12:42.059Z" }, - { url = "https://files.pythonhosted.org/packages/0a/51/8cd301ecc899aea28124357f729f4272f44de7806fc7ca02490bfbe253e8/regex-2026.5.9-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:93a7860539414dddaefba2b40f8771765ae17949d4c7182b876ce429e11a8309", size = 912329, upload-time = "2026-05-09T23:12:44.373Z" }, - { url = "https://files.pythonhosted.org/packages/cc/1e/3fbe2fa1e8cebd62f3bb7d3321cff1640aca2e240b51d9bd624aad949260/regex-2026.5.9-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:dd2810d22146b6d838acc5ec15602cb6b47920aa4e33015df3868eedfd20bab8", size = 801239, upload-time = "2026-05-09T23:12:46.268Z" }, - { url = "https://files.pythonhosted.org/packages/17/2f/6f6008682bf2cf98040a0d3153a8e557b6ab728d7713d045cee4ce544ab8/regex-2026.5.9-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:daff2bdbaf1d23e52fdff7c0b7bc2048b68f978df6a4d107ac981f94caef2e66", size = 777054, upload-time = "2026-05-09T23:12:48.051Z" }, - { url = "https://files.pythonhosted.org/packages/19/2b/eee0d20a6842ba04df4b8847a920b57ef56853f14ef85405473e586b605a/regex-2026.5.9-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:4eeb011098fcb77af513dcef521a3dbecbf8849b1e38940759d293b7a93f5026", size = 785098, upload-time = "2026-05-09T23:12:49.851Z" }, - { url = "https://files.pythonhosted.org/packages/4a/98/6fc1e6410feefb92159edaed5041992bfe390e8d26c721865434acbca558/regex-2026.5.9-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:ea9c8ecfa1b73c73b626534d6626e5340d429630943672b8480724f44e84b962", size = 860095, upload-time = "2026-05-09T23:12:51.666Z" }, - { url = "https://files.pythonhosted.org/packages/18/a3/bd855e0f2cb1a978ecf6fa6bb69632dd9c3f6ea3b81cde62fde14c9daec7/regex-2026.5.9-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:cd2846168eb9ee3c513902bc8225409cb1caab31d04728b145171fa1625d9621", size = 765762, upload-time = "2026-05-09T23:12:53.413Z" }, - { url = "https://files.pythonhosted.org/packages/dc/66/0ae8c092e60b14c79d24f8e0b7f0aea5bfbffdcab00b5483d13404d3c3a5/regex-2026.5.9-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:39617fb0cde9c0e6306dc70e3bfc096f3da793219879f7ae7aa341a69fbdcf6d", size = 852100, upload-time = "2026-05-09T23:12:55.256Z" }, - { url = "https://files.pythonhosted.org/packages/21/de/8dfde60fc1b21c946a893ba273403b72617edb261370cb1087099a83f088/regex-2026.5.9-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fd03c4f0e33280d15cae17159b899245d6b7c53d21def19b263b39655061f5ce", size = 789479, upload-time = "2026-05-09T23:12:57.573Z" }, - { url = "https://files.pythonhosted.org/packages/c3/1c/bdcc98f9a4af4fdd166c74941174619ccff4726d3ce32faa8e9a2ecd38dd/regex-2026.5.9-cp312-cp312-win32.whl", hash = "sha256:164eba9b755ea6f244b0d881196fbc1fac09714e9782c9e2732b813142033c8e", size = 266699, upload-time = "2026-05-09T23:12:59.14Z" }, - { url = "https://files.pythonhosted.org/packages/78/87/240d36864f9e48ace85f72e79ced97ceb7f27ce87739a947dcb834b4e6bc/regex-2026.5.9-cp312-cp312-win_amd64.whl", hash = "sha256:86f40a5d6444db30a125c9c9177e6b25dad981cbc37451fd838f145e6edac92e", size = 277783, upload-time = "2026-05-09T23:13:00.789Z" }, - { url = "https://files.pythonhosted.org/packages/4f/b5/7b30f312b0669dff5beebe5b0989dc2d1a312b1a44fab852199c387a5b96/regex-2026.5.9-cp312-cp312-win_arm64.whl", hash = "sha256:96f5f58b54a063d7ea9dca08e1cf57bfe10499c4d579ee672da284f57f5f0070", size = 270513, upload-time = "2026-05-09T23:13:02.426Z" }, - { url = "https://files.pythonhosted.org/packages/aa/da/797e91ecec6f84135da778ddce78c20e0af5d2a15c26f87a81bc3eadb6db/regex-2026.5.9-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:d626b84406444b165fc0ba981604edea39f0588ff1f92baa23fe50799ea9afdb", size = 490303, upload-time = "2026-05-09T23:13:04.382Z" }, - { url = "https://files.pythonhosted.org/packages/44/da/bf30abaaa737b58f4a4b8c4a03659e02fd92092c822e0197ed9e0daab917/regex-2026.5.9-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:d7bdc0ab8f3dd7e1b4f9ab88634e13374669db86bb3c72e8292f07ae313f539f", size = 292019, upload-time = "2026-05-09T23:13:06.022Z" }, - { url = "https://files.pythonhosted.org/packages/2d/e7/d0eaf5713828417b9e5648cf81fa9bacd4961f6ab98c380c2034f8716e35/regex-2026.5.9-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a8820737949116ffff55fe18f9fc644530063ba6ebfcb8314239416e78f1347c", size = 289468, upload-time = "2026-05-09T23:13:08.214Z" }, - { url = "https://files.pythonhosted.org/packages/d3/9b/b3fdd62b003baa1a9b593cd8c8699c9651c2e80cc21a5c715707983c42d7/regex-2026.5.9-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:aa0fbdbac82cb3e4450d0ccde7d7a35607f4cb2dd9fba4b8b69bfaf8c9fa6aed", size = 796749, upload-time = "2026-05-09T23:13:10.573Z" }, - { url = "https://files.pythonhosted.org/packages/d4/30/66ab84588765f5b4b271a9ca09ef7ce2b87caa95176ec3d2ad65d7bc4902/regex-2026.5.9-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:57e8915c7986aa33d25e4d3629cef711cd2863f2961b10409f0c04cb8b7d9020", size = 865445, upload-time = "2026-05-09T23:13:12.523Z" }, - { url = "https://files.pythonhosted.org/packages/1a/89/f05169e8588aac365f35ffc7f3bc3184f095ef4cfded7cfaa3c7fd5dbd89/regex-2026.5.9-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:508f56a89ba9cb26e4168cbc37dbd60a28d82430a9e18ad1d25fe0883c314ca2", size = 912322, upload-time = "2026-05-09T23:13:14.281Z" }, - { url = "https://files.pythonhosted.org/packages/30/e1/c93444052cf41581f3c884ab3fb5823daf0992f11cd4388d4275ca610558/regex-2026.5.9-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b6d189041f15691cfa2b6c4290448ec221244d225b3f5fe9e7771b34ffcdf6e2", size = 801269, upload-time = "2026-05-09T23:13:16.569Z" }, - { url = "https://files.pythonhosted.org/packages/50/fe/0cf96b882f540e62e8b9956599798203d599c44cf4c77917ca27400ff69b/regex-2026.5.9-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e82db382b44d0111b22601c509c89f64434816c9e0eef9d1989cda8cc6ff1c04", size = 777085, upload-time = "2026-05-09T23:13:18.675Z" }, - { url = "https://files.pythonhosted.org/packages/23/5c/d78d4924e7fc875557b9e9b768423925fdfaac5549d06da7810019a9bd26/regex-2026.5.9-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:2acfb48634f64996b57f90f39afa692ff362162722581921fe92239a59960f3c", size = 785153, upload-time = "2026-05-09T23:13:20.525Z" }, - { url = "https://files.pythonhosted.org/packages/bf/e0/5214774090e7b4524dcea3e3c4aa74141d43043f8beb49c1599db1c8b53a/regex-2026.5.9-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:d29eebfc9525db68cad3c97eedd7f754fa265aa5cd0cf4f863b2421e1b48fc9f", size = 860164, upload-time = "2026-05-09T23:13:22.263Z" }, - { url = "https://files.pythonhosted.org/packages/6e/e1/4a57a83350319b1271f0d7a249b8672513ed928b237a741631270de6caea/regex-2026.5.9-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:debb893095e944091c16e641a6e33c1b0f4cb61ab945ec5afbf53ce7068834d8", size = 765731, upload-time = "2026-05-09T23:13:24.277Z" }, - { url = "https://files.pythonhosted.org/packages/12/f4/499e74a20c156fc75836ee04a72a38d1a063978f600937f9760467beb1b0/regex-2026.5.9-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:d659eee77986549c9ea45b861c7567e44d6287c3dc9a4565478853f7b9fe2ff6", size = 852062, upload-time = "2026-05-09T23:13:26.125Z" }, - { url = "https://files.pythonhosted.org/packages/5b/92/7eebc0d0a01e78629695f342ba17e0deaff8fb45e79cc0d7b98287da6e3e/regex-2026.5.9-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:2efa205e6d98b24d1f3ab395c11aa15cdf10935bca283d0285e0499c284fba21", size = 789577, upload-time = "2026-05-09T23:13:27.814Z" }, - { url = "https://files.pythonhosted.org/packages/05/a4/018e71f7d2ad48c1ebe6d3ae0026f9b7cb4802fd15c7cc02fdf724355102/regex-2026.5.9-cp313-cp313-win32.whl", hash = "sha256:f3844f134e834076677dd369976e9f5068679fcb8e50102fdf6b7ac96a3ec127", size = 266691, upload-time = "2026-05-09T23:13:29.549Z" }, - { url = "https://files.pythonhosted.org/packages/e6/1d/861a93719fb9ee7dbfc3761b3797b7a3e112a5d42c6129459d2d741be9b5/regex-2026.5.9-cp313-cp313-win_amd64.whl", hash = "sha256:3527bb4942d2c14552155406cdedd906567456821848aed1cb4933a391bf5eca", size = 277747, upload-time = "2026-05-09T23:13:31.859Z" }, - { url = "https://files.pythonhosted.org/packages/d9/c6/0a2436ae4da1ba76e51cb98943c6838a9a721faa40ebe2dce07694ae34e3/regex-2026.5.9-cp313-cp313-win_arm64.whl", hash = "sha256:56a33f191f17d8c417f99945ebdc1e691d3af9605d86ec68c7e54a57e3e17af6", size = 270500, upload-time = "2026-05-09T23:13:33.525Z" }, - { url = "https://files.pythonhosted.org/packages/e8/e9/d21346f7b60ed58789371358ed66b09d00f832e1bd7c06e55d9da5679882/regex-2026.5.9-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:01f28d868834624c934b8d2e0aa1c8341337e37831f4a012f18a5afcba4cbaf3", size = 494172, upload-time = "2026-05-09T23:13:35.935Z" }, - { url = "https://files.pythonhosted.org/packages/c4/43/fd1177a2032037c681baecdb3422ee4e1424aec4e4f470ef47793d325274/regex-2026.5.9-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:48036f6374aaa79eb3b754ec29c61d1c6b1606749d705a13f8854fa2539671f6", size = 293952, upload-time = "2026-05-09T23:13:38.307Z" }, - { url = "https://files.pythonhosted.org/packages/f2/7d/9fbf919768368d3f8a4f6c692cf2aa61e482b2b81ec6a298ace4cbf02480/regex-2026.5.9-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:b96350aa424e79d4fd6b567b344dcbe2b2d6bfc48dfe7717587e1fa6d43da6ff", size = 292314, upload-time = "2026-05-09T23:13:40.353Z" }, - { url = "https://files.pythonhosted.org/packages/e2/6c/e41bfeecb589716843e7c4df09ba46ff2a42961457afece19059d85caeef/regex-2026.5.9-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8f3af7a4903c5c04a11a196a5aa75cdd7dd3f8508132f9fb3259d9f5908e3b88", size = 811681, upload-time = "2026-05-09T23:13:42.543Z" }, - { url = "https://files.pythonhosted.org/packages/87/83/a5c1c525fba0aa656e88ad0face0b1829788ef4c2fb6b26df58aa1151b84/regex-2026.5.9-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:7e87577720152d2caae19fe2baaf1f8d5ca12091e9e229f03915c37d1e4b9178", size = 871135, upload-time = "2026-05-09T23:13:44.326Z" }, - { url = "https://files.pythonhosted.org/packages/18/d4/80882e799e440dd878b0979cbebf8fa4d54624a332c83037c7a701649e3f/regex-2026.5.9-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:c8b9b9d294cfea3cd19c718ade7cc93492b2c4991abd9a68d0b3477ae6d8e100", size = 917265, upload-time = "2026-05-09T23:13:47.295Z" }, - { url = "https://files.pythonhosted.org/packages/ae/ff/8db60211e2286e396aad7dc7725356c502bff0901ea05bd6cdc2e1a042b9/regex-2026.5.9-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:728d8bfd28a8845c8b6bc5dc7ce010453d206396786c0765c2740cb65f37791e", size = 816311, upload-time = "2026-05-09T23:13:49.885Z" }, - { url = "https://files.pythonhosted.org/packages/4c/47/742ef579c61730f8d268e5cf1f9ce0e37e2ea041ad0f5644724f2378e463/regex-2026.5.9-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:7e30b874d341fac767d7df5a0870540541c2c054b80cfaac116e8d367a8a7ff2", size = 785498, upload-time = "2026-05-09T23:13:52.25Z" }, - { url = "https://files.pythonhosted.org/packages/7f/ab/cb0999802dcb0fb95b1ab005e8d4163d8afdd67efc2cb6b6630ac13f8cb1/regex-2026.5.9-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:fd190e88a895a8901325fad284a3f74ea52b1da8525b76cc811fa9b1edf0ce2b", size = 801348, upload-time = "2026-05-09T23:13:54.127Z" }, - { url = "https://files.pythonhosted.org/packages/7d/62/8ca59a24c55bc34d166eefaf3717bd77772f329fdbf984d86581e0a3571c/regex-2026.5.9-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:8e76e8161ad00694cfce6767d5dea860c6391ac5b83e5c3a39661e696f11fc7e", size = 866493, upload-time = "2026-05-09T23:13:56.067Z" }, - { url = "https://files.pythonhosted.org/packages/8d/3d/30f2ae62cef3278bb5bb821f467277a55fb73f01032cf85997e15e8289a8/regex-2026.5.9-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:ddda5340e6c01a293027dd46232fa79eaff1b48058ce7a98f572b6445b088041", size = 772811, upload-time = "2026-05-09T23:13:57.867Z" }, - { url = "https://files.pythonhosted.org/packages/d8/ae/7d2089bcd78ad0c0161bc684339df50032acb438a7bd3305e7ddb1193cec/regex-2026.5.9-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:205109e96b3cf5adf8f4cd62bedde9487feb282b9497a3535451e5a24cd706a0", size = 856584, upload-time = "2026-05-09T23:13:59.679Z" }, - { url = "https://files.pythonhosted.org/packages/a9/29/92ff47f75990131ea4f24ba17819e5a9d141e10819807e09addd73409af6/regex-2026.5.9-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:dfbe4579b9f08036aa7d101d1835437a20783574ac66327e6b29b4018a138081", size = 803453, upload-time = "2026-05-09T23:14:01.978Z" }, - { url = "https://files.pythonhosted.org/packages/04/99/eff29f1037dcab36702c9ee5d6858cf1ce2336ea8ea2987f64245b99ea5e/regex-2026.5.9-cp313-cp313t-win32.whl", hash = "sha256:ed2c9e8068b614c574d8d30e543d617cf5379b0535d46f97ef00e904745a08b5", size = 269951, upload-time = "2026-05-09T23:14:03.661Z" }, - { url = "https://files.pythonhosted.org/packages/0e/9d/8870b8981d27b22cda77bb26a5ac7ebfa9c7d9e0dea195a834a82380e748/regex-2026.5.9-cp313-cp313t-win_amd64.whl", hash = "sha256:b46b0f094dc1d3b90356c85a0bd2c9bafc4a6a190b9d6f8ddd5a033b6e088ed4", size = 281240, upload-time = "2026-05-09T23:14:05.56Z" }, - { url = "https://files.pythonhosted.org/packages/72/b1/3379415e8f135c13ac551353397cc4fe97b4978f3cac73c5fcbcded548b8/regex-2026.5.9-cp313-cp313t-win_arm64.whl", hash = "sha256:872acc074bd29ffc9913ecdfedf6ea77502312ca44a4aa0d3779089c6069d8de", size = 272383, upload-time = "2026-05-09T23:14:07.843Z" }, - { url = "https://files.pythonhosted.org/packages/13/3e/9c3cd292d8808b3645a2ce517e200179b6d0e903f176300bd8b542e14de5/regex-2026.5.9-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:1bd7587a2948b4085195d5a3374eaf4a425dc3e55784c038175355ecf3bbbf8a", size = 490376, upload-time = "2026-05-09T23:14:09.64Z" }, - { url = "https://files.pythonhosted.org/packages/60/70/d43ee8a2ca0a8b68d167f21658b85520ac0574617c7f320367c5047f7556/regex-2026.5.9-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:dea2e88e1cce4522496cce630e11e67b98b7076620bc4336c3f674bc21a375f4", size = 291964, upload-time = "2026-05-09T23:14:11.424Z" }, - { url = "https://files.pythonhosted.org/packages/21/91/9d50b433828d8e74196904e168a43abf1e6e88b2a15d47ed742456720c37/regex-2026.5.9-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:2099f7e7ff7b6aa3192312650a56e91cc091e49d50b04e4f6f8b6e28b3b27f1c", size = 289682, upload-time = "2026-05-09T23:14:13.123Z" }, - { url = "https://files.pythonhosted.org/packages/3e/d2/b835e3cafbb9d977736912436259ff551d60919f7d7b3d37d46659c63564/regex-2026.5.9-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ecd353045824e4477562a2ac718c25799cdaaa41f7aa925a806a8a3e6848a5b9", size = 796996, upload-time = "2026-05-09T23:14:14.923Z" }, - { url = "https://files.pythonhosted.org/packages/2c/a6/9f992d00019166b9de01c546dd4549bc679f2a68df11b877740b0760b7c2/regex-2026.5.9-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:65c8c8c37377794bd5b2f3ebe51919042bf17aec802e23c833d89782ed0c78af", size = 866089, upload-time = "2026-05-09T23:14:17.757Z" }, - { url = "https://files.pythonhosted.org/packages/e0/08/4d32af657e049b19cb62b02e46e38fe1518797bfb2203ee93a510b21b0dc/regex-2026.5.9-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5b73ab8afcf66c622db143d1c6fda4e58e4d537ee4f125229ad47b1ab80f34c0", size = 911530, upload-time = "2026-05-09T23:14:20.353Z" }, - { url = "https://files.pythonhosted.org/packages/d9/27/2af43dd1dc201d1fecefda64a45f4ad0995855b92724f795a777b402ee69/regex-2026.5.9-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0de5cf193997384ed2ca6f1cd4f78055b255d93d82d5a8cd6ba0d11c10b167e4", size = 800643, upload-time = "2026-05-09T23:14:22.265Z" }, - { url = "https://files.pythonhosted.org/packages/a4/dd/23a249047013b5321d4a60c4d2437462086f601b061776a525e5fba2a59f/regex-2026.5.9-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:d641a8c9a61618047796d572a39a79b26167b0411d2c3031937b2fe2d081e2cf", size = 777223, upload-time = "2026-05-09T23:14:24.179Z" }, - { url = "https://files.pythonhosted.org/packages/94/6a/e85ed9538cd19586d0465076a4578a12e093ce776d15f3f8ce92733a8dd6/regex-2026.5.9-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:24b2355ef5cc9aa5b8f07d17704face1c166fdcc2290fa7bd6e6c925655a8346", size = 785760, upload-time = "2026-05-09T23:14:26.065Z" }, - { url = "https://files.pythonhosted.org/packages/2a/c4/f25473209438638e947c55f9156fd8f236f74169229028cc99116380868e/regex-2026.5.9-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:a24852d3c29ad9e47593593d8a247c44ccc3d0548ef12c822d6ed0810affe676", size = 860891, upload-time = "2026-05-09T23:14:28.17Z" }, - { url = "https://files.pythonhosted.org/packages/f9/f7/f4f86e3c74419c37370e91f150ae0c2ef7d34b2e0e4cdd5da046a02e4022/regex-2026.5.9-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:916714069da19329ef7de197dcbc77bb3104145c7c2c864dbfbe318f46b88b14", size = 765891, upload-time = "2026-05-09T23:14:30.06Z" }, - { url = "https://files.pythonhosted.org/packages/26/70/704d8e13765939146b1cd0ef4e2feb71d7929727d2290f026eed10095955/regex-2026.5.9-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:fa411799ca8da32a8d38d020a88faa5b6f91657d284761352940ecf9f7c3bbdd", size = 851380, upload-time = "2026-05-09T23:14:32.123Z" }, - { url = "https://files.pythonhosted.org/packages/26/29/1a13582a8460038edc38e49f64ceb0dd7c60f5caba77571f4bf6601965d9/regex-2026.5.9-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:1e6da47d679b7010ef27556b6e0f99771b744936db1792a10ceac6547ae1503e", size = 789350, upload-time = "2026-05-09T23:14:34.799Z" }, - { url = "https://files.pythonhosted.org/packages/73/56/3dcafe34fc72e271d62ad9a291801e88a1457bb251c132f15fcc2e5aad1a/regex-2026.5.9-cp314-cp314-win32.whl", hash = "sha256:98bd73080e8756255137e1bd3f3f00295bbc5aa383c0e0f973920e9134d7c4ad", size = 272130, upload-time = "2026-05-09T23:14:36.729Z" }, - { url = "https://files.pythonhosted.org/packages/d0/9c/02eebf0be95efe416c664db7fb8b6b05b7a0b06a7544f2884f2558b0526f/regex-2026.5.9-cp314-cp314-win_amd64.whl", hash = "sha256:ff8d372ac2acdc048d1c19916f27ee61bc5722728458ba6ca5052f2c72d51763", size = 280999, upload-time = "2026-05-09T23:14:39.126Z" }, - { url = "https://files.pythonhosted.org/packages/70/5a/1dd1abee76cb7a846a0bcf42fdc87e5720c3c33c24f3e37814310a513d9f/regex-2026.5.9-cp314-cp314-win_arm64.whl", hash = "sha256:e1d93bf647916292e8edcec150c07ddf3dc50179ccaf770c04a7f9e452155372", size = 273500, upload-time = "2026-05-09T23:14:41.059Z" }, - { url = "https://files.pythonhosted.org/packages/86/c1/c5f619b0057a7965cb78ec559c1d7a45ce8c99a35bea95483d64959a93d9/regex-2026.5.9-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:83d0ee4a57d1c87cb549e195ec300b8f0ec3a82eba66d835e4e2ed8634fe4499", size = 494269, upload-time = "2026-05-09T23:14:42.869Z" }, - { url = "https://files.pythonhosted.org/packages/05/2c/5d01f1aee33de4bbe60c8452945bfc8477ca7c5ae4450f6bfe711036cb36/regex-2026.5.9-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:d3d7eb5c9a7f6df82ed3cfac9beb93882a5cbcb5b8b157b56cb2b3b276574ac1", size = 293954, upload-time = "2026-05-09T23:14:44.822Z" }, - { url = "https://files.pythonhosted.org/packages/7a/fe/e8988b2ae2108c6ef71bd4aa8d87fbe257976dd0810e826cd75f701c68b6/regex-2026.5.9-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:075160bf16658e16d35233300b8453aac25de4cbea808d22348b6979668e924d", size = 292405, upload-time = "2026-05-09T23:14:47.211Z" }, - { url = "https://files.pythonhosted.org/packages/79/34/d2b0937faa7859263f7f0a3c6b103a1296306be6952dc173d0154e9a2f49/regex-2026.5.9-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:45375819235558a4ff1c4971dc32881f022613abdb180128f5cb4768c1765a1c", size = 811855, upload-time = "2026-05-09T23:14:49.21Z" }, - { url = "https://files.pythonhosted.org/packages/80/fe/daf53a47457a8486db66c66c01ceb9c2303eecee3f87197f1e77eb1a736d/regex-2026.5.9-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ead4b163ac30a29574510cd4b3e2e985ac5290c05fc7095557d6a5f403fc31b5", size = 871189, upload-time = "2026-05-09T23:14:51.555Z" }, - { url = "https://files.pythonhosted.org/packages/1c/75/058fc4470cbfbf57d800aff1a0022b929a3f9fa553ee10a0cdf2070eb31f/regex-2026.5.9-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:8c6e4218fbdfbcd4f6c19efca40930d24a621bf4b48cb76bc6640543bd28ef20", size = 917485, upload-time = "2026-05-09T23:14:53.633Z" }, - { url = "https://files.pythonhosted.org/packages/88/e7/179cfda3a28bc843b5c6cfe7f79f23489c791ed95f151083803660878432/regex-2026.5.9-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6351571c8a42b505eb555c0dc47d740d0fb66977dc142919eea6f4325b7c56a0", size = 816369, upload-time = "2026-05-09T23:14:56.198Z" }, - { url = "https://files.pythonhosted.org/packages/41/90/6f0cc422071688266d344fca8462d787cba0a2c144acb25721f9a61ec265/regex-2026.5.9-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:002205cafd2a9e78c6290c7d1df277bf3277b3b7a30e0b4bb0dac2e2e3f7cb2d", size = 785869, upload-time = "2026-05-09T23:14:58.602Z" }, - { url = "https://files.pythonhosted.org/packages/02/67/a31f1760f09c27b251ef39e9beb541f462cf977381d067faa764c2c0e393/regex-2026.5.9-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:8abd33fef90b2a9efac5557d6033ca82d1195ed3a15fea5af15ba7b463c6a63b", size = 801427, upload-time = "2026-05-09T23:15:00.642Z" }, - { url = "https://files.pythonhosted.org/packages/e3/c4/1a80654597b6bc1e1ea0494824c31200e8a956abe290afae9b19a166a148/regex-2026.5.9-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:31037c82eccb44b7ea2e9e221d7c01429430e989a1f4b91ea5a855f6017b509a", size = 866482, upload-time = "2026-05-09T23:15:03.384Z" }, - { url = "https://files.pythonhosted.org/packages/d1/11/960724e06482c08466ff5611e242e86f80062949cdf6b4b9cc317b9dd93d/regex-2026.5.9-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:5604dfd046dc37eca90250fc3be938b076c8059fa772ac0ed6f499b0f0fb0415", size = 773022, upload-time = "2026-05-09T23:15:05.625Z" }, - { url = "https://files.pythonhosted.org/packages/50/a8/a9979c3e7918280e93159ebcab5ef1a65116dd4f3bd6091be0eae4a126e8/regex-2026.5.9-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:0e1b1b4e496afbb24f4a62aba855ee4f88f25578927697b340702e48c9ee6bc2", size = 856642, upload-time = "2026-05-09T23:15:07.966Z" }, - { url = "https://files.pythonhosted.org/packages/fe/d4/a9b732f2f0072c0ab12227483abb24fffcb9f73f8a2b203df0a6d0434735/regex-2026.5.9-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:be3372b9df6ddecff6486d37e19095a7b4973137caf5512407a89f4455361f41", size = 803552, upload-time = "2026-05-09T23:15:10.215Z" }, - { url = "https://files.pythonhosted.org/packages/d5/fe/1b3113817447a1d4155e4ac76d2e072f42c0bcba2f43fa8a0e756ea2cd91/regex-2026.5.9-cp314-cp314t-win32.whl", hash = "sha256:3ddd90103f9e5c471c49c7852ecc1fe27c7e45eb99e977aefe7caa4e779f4f58", size = 275746, upload-time = "2026-05-09T23:15:12.609Z" }, - { url = "https://files.pythonhosted.org/packages/92/73/93d42045302636c91f2e5ef588b65b84b01428f28ec77de256b1dfdfbe5c/regex-2026.5.9-cp314-cp314t-win_amd64.whl", hash = "sha256:ca518ed29c46eecba6010b15f1b9a479314d2de409536e71b6a13aa04e3b8a77", size = 285685, upload-time = "2026-05-09T23:15:15.086Z" }, - { url = "https://files.pythonhosted.org/packages/da/80/35b4c33c804a165a7f55289afda3ea9e3eb6d15800341a2d66455c0f1f30/regex-2026.5.9-cp314-cp314t-win_arm64.whl", hash = "sha256:5e41809d2683fcde7d5a8c87a6567ba1fb1ce0de9f31bff578de00a4b2d76daa", size = 275713, upload-time = "2026-05-09T23:15:16.98Z" }, -] - -[[package]] -name = "requests" -version = "2.34.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "certifi" }, - { name = "charset-normalizer" }, - { name = "idna" }, - { name = "urllib3" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/ac/c3/e2a2b89f2d3e2179abd6d00ebd70bff6273f37fb3e0cc209f48b39d00cbf/requests-2.34.2.tar.gz", hash = "sha256:f288924cae4e29463698d6d60bc6a4da69c89185ad1e0bcc4104f584e960b9ed", size = 142856, upload-time = "2026-05-14T19:25:27.735Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl", hash = "sha256:2a0d60c172f83ac6ab31e4554906c0f3b3588d37b5cb939b1c061f4907e278e0", size = 73075, upload-time = "2026-05-14T19:25:26.443Z" }, -] - -[[package]] -name = "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" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/29/9c/6e74567782559a63bd040a236edca26fd71bc7ba88de2ef35d75df3bca5e/safetensors-0.7.0.tar.gz", hash = "sha256:07663963b67e8bd9f0b8ad15bb9163606cd27cc5a1b96235a50d8369803b96b0", size = 200878, upload-time = "2025-11-19T15:18:43.199Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/fa/47/aef6c06649039accf914afef490268e1067ed82be62bcfa5b7e886ad15e8/safetensors-0.7.0-cp38-abi3-macosx_10_12_x86_64.whl", hash = "sha256:c82f4d474cf725255d9e6acf17252991c3c8aac038d6ef363a4bf8be2f6db517", size = 467781, upload-time = "2025-11-19T15:18:35.84Z" }, - { url = "https://files.pythonhosted.org/packages/e8/00/374c0c068e30cd31f1e1b46b4b5738168ec79e7689ca82ee93ddfea05109/safetensors-0.7.0-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:94fd4858284736bb67a897a41608b5b0c2496c9bdb3bf2af1fa3409127f20d57", size = 447058, upload-time = "2025-11-19T15:18:34.416Z" }, - { url = "https://files.pythonhosted.org/packages/f1/06/578ffed52c2296f93d7fd2d844cabfa92be51a587c38c8afbb8ae449ca89/safetensors-0.7.0-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e07d91d0c92a31200f25351f4acb2bc6aff7f48094e13ebb1d0fb995b54b6542", size = 491748, upload-time = "2025-11-19T15:18:09.79Z" }, - { url = "https://files.pythonhosted.org/packages/ae/33/1debbbb70e4791dde185edb9413d1fe01619255abb64b300157d7f15dddd/safetensors-0.7.0-cp38-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8469155f4cb518bafb4acf4865e8bb9d6804110d2d9bdcaa78564b9fd841e104", size = 503881, upload-time = "2025-11-19T15:18:16.145Z" }, - { url = "https://files.pythonhosted.org/packages/8e/1c/40c2ca924d60792c3be509833df711b553c60effbd91da6f5284a83f7122/safetensors-0.7.0-cp38-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:54bef08bf00a2bff599982f6b08e8770e09cc012d7bba00783fc7ea38f1fb37d", size = 623463, upload-time = "2025-11-19T15:18:21.11Z" }, - { url = "https://files.pythonhosted.org/packages/9b/3a/13784a9364bd43b0d61eef4bea2845039bc2030458b16594a1bd787ae26e/safetensors-0.7.0-cp38-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:42cb091236206bb2016d245c377ed383aa7f78691748f3bb6ee1bfa51ae2ce6a", size = 532855, upload-time = "2025-11-19T15:18:25.719Z" }, - { url = "https://files.pythonhosted.org/packages/a0/60/429e9b1cb3fc651937727befe258ea24122d9663e4d5709a48c9cbfceecb/safetensors-0.7.0-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dac7252938f0696ddea46f5e855dd3138444e82236e3be475f54929f0c510d48", size = 507152, upload-time = "2025-11-19T15:18:33.023Z" }, - { url = "https://files.pythonhosted.org/packages/3c/a8/4b45e4e059270d17af60359713ffd83f97900d45a6afa73aaa0d737d48b6/safetensors-0.7.0-cp38-abi3-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1d060c70284127fa805085d8f10fbd0962792aed71879d00864acda69dbab981", size = 541856, upload-time = "2025-11-19T15:18:31.075Z" }, - { url = "https://files.pythonhosted.org/packages/06/87/d26d8407c44175d8ae164a95b5a62707fcc445f3c0c56108e37d98070a3d/safetensors-0.7.0-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:cdab83a366799fa730f90a4ebb563e494f28e9e92c4819e556152ad55e43591b", size = 674060, upload-time = "2025-11-19T15:18:37.211Z" }, - { url = "https://files.pythonhosted.org/packages/11/f5/57644a2ff08dc6325816ba7217e5095f17269dada2554b658442c66aed51/safetensors-0.7.0-cp38-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:672132907fcad9f2aedcb705b2d7b3b93354a2aec1b2f706c4db852abe338f85", size = 771715, upload-time = "2025-11-19T15:18:38.689Z" }, - { url = "https://files.pythonhosted.org/packages/86/31/17883e13a814bd278ae6e266b13282a01049b0c81341da7fd0e3e71a80a3/safetensors-0.7.0-cp38-abi3-musllinux_1_2_i686.whl", hash = "sha256:5d72abdb8a4d56d4020713724ba81dac065fedb7f3667151c4a637f1d3fb26c0", size = 714377, upload-time = "2025-11-19T15:18:40.162Z" }, - { url = "https://files.pythonhosted.org/packages/4a/d8/0c8a7dc9b41dcac53c4cbf9df2b9c83e0e0097203de8b37a712b345c0be5/safetensors-0.7.0-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:b0f6d66c1c538d5a94a73aa9ddca8ccc4227e6c9ff555322ea40bdd142391dd4", size = 677368, upload-time = "2025-11-19T15:18:41.627Z" }, - { url = "https://files.pythonhosted.org/packages/05/e5/cb4b713c8a93469e3c5be7c3f8d77d307e65fe89673e731f5c2bfd0a9237/safetensors-0.7.0-cp38-abi3-win32.whl", hash = "sha256:c74af94bf3ac15ac4d0f2a7c7b4663a15f8c2ab15ed0fc7531ca61d0835eccba", size = 326423, upload-time = "2025-11-19T15:18:45.74Z" }, - { 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" }, - { url = "https://files.pythonhosted.org/packages/a7/6a/4d08d89a6fcbe905c5ae68b8b34f0791850882fc19782d0d02c65abbdf3b/safetensors-0.7.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f4729811a6640d019a4b7ba8638ee2fd21fa5ca8c7e7bdf0fed62068fcaac737", size = 492430, upload-time = "2025-11-19T15:18:11.884Z" }, - { url = "https://files.pythonhosted.org/packages/dd/29/59ed8152b30f72c42d00d241e58eaca558ae9dbfa5695206e2e0f54c7063/safetensors-0.7.0-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:12f49080303fa6bb424b362149a12949dfbbf1e06811a88f2307276b0c131afd", size = 503977, upload-time = "2025-11-19T15:18:17.523Z" }, - { url = "https://files.pythonhosted.org/packages/d3/0b/4811bfec67fa260e791369b16dab105e4bae82686120554cc484064e22b4/safetensors-0.7.0-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0071bffba4150c2f46cae1432d31995d77acfd9f8db598b5d1a2ce67e8440ad2", size = 623890, upload-time = "2025-11-19T15:18:22.666Z" }, - { url = "https://files.pythonhosted.org/packages/58/5b/632a58724221ef03d78ab65062e82a1010e1bef8e8e0b9d7c6d7b8044841/safetensors-0.7.0-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:473b32699f4200e69801bf5abf93f1a4ecd432a70984df164fc22ccf39c4a6f3", size = 531885, upload-time = "2025-11-19T15:18:27.146Z" }, -] - -[[package]] -name = "shellingham" -version = "1.5.4" -source = { registry = "https://pypi.org/simple" } -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/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]] -name = "tqdm" -version = "4.67.3" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "colorama", marker = "sys_platform == 'win32'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/09/a9/6ba95a270c6f1fbcd8dac228323f2777d886cb206987444e4bce66338dd4/tqdm-4.67.3.tar.gz", hash = "sha256:7d825f03f89244ef73f1d4ce193cb1774a8179fd96f31d7e1dcde62092b960bb", size = 169598, upload-time = "2026-02-03T17:35:53.048Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/16/e1/3079a9ff9b8e11b846c6ac5c8b5bfb7ff225eee721825310c91b3b50304f/tqdm-4.67.3-py3-none-any.whl", hash = "sha256:ee1e4c0e59148062281c49d80b25b67771a127c85fc9676d3be5f243206826bf", size = 78374, upload-time = "2026-02-03T17:35:50.982Z" }, -] - -[[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" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", size = 109391, upload-time = "2025-08-25T13:49:26.313Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614, upload-time = "2025-08-25T13:49:24.86Z" }, -] - -[[package]] -name = "urllib3" -version = "2.7.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/53/0c/06f8b233b8fd13b9e5ee11424ef85419ba0d8ba0b3138bf360be2ff56953/urllib3-2.7.0.tar.gz", hash = "sha256:231e0ec3b63ceb14667c67be60f2f2c40a518cb38b03af60abc813da26505f4c", size = 433602, upload-time = "2026-05-07T16:13:18.596Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl", hash = "sha256:9fb4c81ebbb1ce9531cce37674bbc6f1360472bc18ca9a553ede278ef7276897", size = 131087, upload-time = "2026-05-07T16:13:17.151Z" }, -] - -[[package]] -name = "zipp" -version = "4.1.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b9/d8/eab98a517c14134c0b2eb4e2387bc5f457334293ec5d2dd3857ec2966802/zipp-4.1.0.tar.gz", hash = "sha256:4cb57381f544315db7688e976e922a2b18cdb513d21cc194eb42232ba2a3e602", size = 26214, upload-time = "2026-05-18T20:08:57.967Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/3a/13/547360d81e6d88d58492968ffda9f9542854f11310ee556fef14260cc886/zipp-4.1.0-py3-none-any.whl", hash = "sha256:25ad4e16390cd314347dd8f1de67a2ac538ae658ed4ab9db16029c07c188e97f", size = 10238, upload-time = "2026-05-18T20:08:57.045Z" }, -] diff --git a/pyproject.toml b/pyproject.toml index 2130b4f9..ed9d36b7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -26,7 +26,7 @@ dependencies = [ "accelerate", "av", "cattrs", - "diffusers", + "diffusers>=0.39.0", "einops", "hydra-core", "imageio-ffmpeg", @@ -72,7 +72,6 @@ train = [ "boto3", "botocore", "datasets", - "diffusers-cosmos3", "dists-pytorch", "einx", "fastparquet", @@ -298,7 +297,6 @@ required-environments = [ ] [tool.uv.sources] -diffusers-cosmos3 = { path = "packages/diffusers-cosmos3", editable = true } flash-attn = { index = "cosmos"} flash-attn-3-nv = { index = "cosmos" } lerobot = { git = "https://github.com/mli0603/lerobot.git" } @@ -336,10 +334,6 @@ ignore = [ "PYSEC-2025-217", # flash-attn: flash-attn deserialization isn't used in cosmos3 package "GHSA-7g5w-pq96-8c5w", - # Need diffusers 0.38 - "GHSA-7wx4-6vff-v64p", - "GHSA-98h9-4798-4q5v", - "PYSEC-2026-41", # torch, no fix "PYSEC-2026-139", # Need vllm 0.20 diff --git a/uv.lock b/uv.lock index 81fa99bd..5dc44665 100644 --- a/uv.lock +++ b/uv.lock @@ -1789,7 +1789,6 @@ train = [ { name = "boto3" }, { name = "botocore" }, { name = "datasets" }, - { name = "diffusers-cosmos3" }, { name = "dists-pytorch" }, { name = "einx" }, { name = "fastparquet" }, @@ -2018,8 +2017,7 @@ requires-dist = [ { name = "botocore", marker = "extra == 'train'" }, { name = "cattrs" }, { name = "datasets", marker = "extra == 'train'" }, - { name = "diffusers" }, - { name = "diffusers-cosmos3", marker = "extra == 'train'", editable = "packages/diffusers-cosmos3" }, + { name = "diffusers", specifier = ">=0.39.0" }, { name = "dists-pytorch", marker = "extra == 'train'" }, { name = "einops" }, { name = "einx", marker = "extra == 'train'" }, @@ -2820,7 +2818,7 @@ wheels = [ [[package]] name = "diffusers" -version = "0.37.0" +version = "0.39.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "filelock" }, @@ -2833,22 +2831,11 @@ dependencies = [ { name = "requests" }, { name = "safetensors" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/58/3b/01d0ff800b811c5ad8bba682f4c6abf1d7071cd81464c01724333fefb7ba/diffusers-0.37.0.tar.gz", hash = "sha256:408789af73898585f525afd07ca72b3955affea4216a669558e9f59b5b1fe704", size = 4141136, upload-time = "2026-03-05T14:58:39.704Z" } +sdist = { url = "https://files.pythonhosted.org/packages/1a/81/6095237b86a3116c4789f28c4435d5296c00c0fc74ffde99008fd6b3a36c/diffusers-0.39.0.tar.gz", hash = "sha256:14bb1d98c85a0e463d734c99aaa73b480a7bc9bad22af30fbf730ef8f09c1d67", size = 4651240, upload-time = "2026-07-03T08:48:47.904Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/f7/55/586a3a2b9c95f371c9c3cb048c3cac15aedcce8d6d53ebd6bbc46860722d/diffusers-0.37.0-py3-none-any.whl", hash = "sha256:7eab74bf896974250b5e1027cae813aba1004f02d97c9b44891b83713386aa08", size = 5000449, upload-time = "2026-03-05T14:58:37.361Z" }, -] - -[[package]] -name = "diffusers-cosmos3" -version = "0.1.0" -source = { editable = "packages/diffusers-cosmos3" } -dependencies = [ - { name = "diffusers" }, + { url = "https://files.pythonhosted.org/packages/3f/3f/7469c46e9d22307ea686bab687d70e6bf328722952f9d10339f5e913e608/diffusers-0.39.0-py3-none-any.whl", hash = "sha256:912aca51b5787365110806e984d5555735bf8a461073bb8459029d0bca7870ef", size = 5631176, upload-time = "2026-07-03T08:48:45.337Z" }, ] -[package.metadata] -requires-dist = [{ name = "diffusers", specifier = ">=0.37.0" }] - [[package]] name = "dill" version = "0.4.0" @@ -11377,28 +11364,26 @@ wheels = [ [[package]] name = "safetensors" -version = "0.7.0" +version = "0.8.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/29/9c/6e74567782559a63bd040a236edca26fd71bc7ba88de2ef35d75df3bca5e/safetensors-0.7.0.tar.gz", hash = "sha256:07663963b67e8bd9f0b8ad15bb9163606cd27cc5a1b96235a50d8369803b96b0", size = 200878, upload-time = "2025-11-19T15:18:43.199Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/fa/47/aef6c06649039accf914afef490268e1067ed82be62bcfa5b7e886ad15e8/safetensors-0.7.0-cp38-abi3-macosx_10_12_x86_64.whl", hash = "sha256:c82f4d474cf725255d9e6acf17252991c3c8aac038d6ef363a4bf8be2f6db517", size = 467781, upload-time = "2025-11-19T15:18:35.84Z" }, - { url = "https://files.pythonhosted.org/packages/e8/00/374c0c068e30cd31f1e1b46b4b5738168ec79e7689ca82ee93ddfea05109/safetensors-0.7.0-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:94fd4858284736bb67a897a41608b5b0c2496c9bdb3bf2af1fa3409127f20d57", size = 447058, upload-time = "2025-11-19T15:18:34.416Z" }, - { url = "https://files.pythonhosted.org/packages/f1/06/578ffed52c2296f93d7fd2d844cabfa92be51a587c38c8afbb8ae449ca89/safetensors-0.7.0-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e07d91d0c92a31200f25351f4acb2bc6aff7f48094e13ebb1d0fb995b54b6542", size = 491748, upload-time = "2025-11-19T15:18:09.79Z" }, - { url = "https://files.pythonhosted.org/packages/ae/33/1debbbb70e4791dde185edb9413d1fe01619255abb64b300157d7f15dddd/safetensors-0.7.0-cp38-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8469155f4cb518bafb4acf4865e8bb9d6804110d2d9bdcaa78564b9fd841e104", size = 503881, upload-time = "2025-11-19T15:18:16.145Z" }, - { url = "https://files.pythonhosted.org/packages/8e/1c/40c2ca924d60792c3be509833df711b553c60effbd91da6f5284a83f7122/safetensors-0.7.0-cp38-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:54bef08bf00a2bff599982f6b08e8770e09cc012d7bba00783fc7ea38f1fb37d", size = 623463, upload-time = "2025-11-19T15:18:21.11Z" }, - { url = "https://files.pythonhosted.org/packages/9b/3a/13784a9364bd43b0d61eef4bea2845039bc2030458b16594a1bd787ae26e/safetensors-0.7.0-cp38-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:42cb091236206bb2016d245c377ed383aa7f78691748f3bb6ee1bfa51ae2ce6a", size = 532855, upload-time = "2025-11-19T15:18:25.719Z" }, - { url = "https://files.pythonhosted.org/packages/a0/60/429e9b1cb3fc651937727befe258ea24122d9663e4d5709a48c9cbfceecb/safetensors-0.7.0-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dac7252938f0696ddea46f5e855dd3138444e82236e3be475f54929f0c510d48", size = 507152, upload-time = "2025-11-19T15:18:33.023Z" }, - { url = "https://files.pythonhosted.org/packages/3c/a8/4b45e4e059270d17af60359713ffd83f97900d45a6afa73aaa0d737d48b6/safetensors-0.7.0-cp38-abi3-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1d060c70284127fa805085d8f10fbd0962792aed71879d00864acda69dbab981", size = 541856, upload-time = "2025-11-19T15:18:31.075Z" }, - { url = "https://files.pythonhosted.org/packages/06/87/d26d8407c44175d8ae164a95b5a62707fcc445f3c0c56108e37d98070a3d/safetensors-0.7.0-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:cdab83a366799fa730f90a4ebb563e494f28e9e92c4819e556152ad55e43591b", size = 674060, upload-time = "2025-11-19T15:18:37.211Z" }, - { url = "https://files.pythonhosted.org/packages/11/f5/57644a2ff08dc6325816ba7217e5095f17269dada2554b658442c66aed51/safetensors-0.7.0-cp38-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:672132907fcad9f2aedcb705b2d7b3b93354a2aec1b2f706c4db852abe338f85", size = 771715, upload-time = "2025-11-19T15:18:38.689Z" }, - { url = "https://files.pythonhosted.org/packages/86/31/17883e13a814bd278ae6e266b13282a01049b0c81341da7fd0e3e71a80a3/safetensors-0.7.0-cp38-abi3-musllinux_1_2_i686.whl", hash = "sha256:5d72abdb8a4d56d4020713724ba81dac065fedb7f3667151c4a637f1d3fb26c0", size = 714377, upload-time = "2025-11-19T15:18:40.162Z" }, - { url = "https://files.pythonhosted.org/packages/4a/d8/0c8a7dc9b41dcac53c4cbf9df2b9c83e0e0097203de8b37a712b345c0be5/safetensors-0.7.0-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:b0f6d66c1c538d5a94a73aa9ddca8ccc4227e6c9ff555322ea40bdd142391dd4", size = 677368, upload-time = "2025-11-19T15:18:41.627Z" }, - { url = "https://files.pythonhosted.org/packages/05/e5/cb4b713c8a93469e3c5be7c3f8d77d307e65fe89673e731f5c2bfd0a9237/safetensors-0.7.0-cp38-abi3-win32.whl", hash = "sha256:c74af94bf3ac15ac4d0f2a7c7b4663a15f8c2ab15ed0fc7531ca61d0835eccba", size = 326423, upload-time = "2025-11-19T15:18:45.74Z" }, - { 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" }, - { url = "https://files.pythonhosted.org/packages/a7/6a/4d08d89a6fcbe905c5ae68b8b34f0791850882fc19782d0d02c65abbdf3b/safetensors-0.7.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f4729811a6640d019a4b7ba8638ee2fd21fa5ca8c7e7bdf0fed62068fcaac737", size = 492430, upload-time = "2025-11-19T15:18:11.884Z" }, - { url = "https://files.pythonhosted.org/packages/dd/29/59ed8152b30f72c42d00d241e58eaca558ae9dbfa5695206e2e0f54c7063/safetensors-0.7.0-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:12f49080303fa6bb424b362149a12949dfbbf1e06811a88f2307276b0c131afd", size = 503977, upload-time = "2025-11-19T15:18:17.523Z" }, - { url = "https://files.pythonhosted.org/packages/d3/0b/4811bfec67fa260e791369b16dab105e4bae82686120554cc484064e22b4/safetensors-0.7.0-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0071bffba4150c2f46cae1432d31995d77acfd9f8db598b5d1a2ce67e8440ad2", size = 623890, upload-time = "2025-11-19T15:18:22.666Z" }, - { url = "https://files.pythonhosted.org/packages/58/5b/632a58724221ef03d78ab65062e82a1010e1bef8e8e0b9d7c6d7b8044841/safetensors-0.7.0-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:473b32699f4200e69801bf5abf93f1a4ecd432a70984df164fc22ccf39c4a6f3", size = 531885, upload-time = "2025-11-19T15:18:27.146Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/45/06/f955dbbb1859e3bd23c8ac6141af5106e7ad5fedec4a3a6e3d60f94b7001/safetensors-0.8.0.tar.gz", hash = "sha256:fabaf3e0f18a6618d9b36560682562157f77c2b71fcffc7b432be2baed9d753d", size = 325846, upload-time = "2026-06-09T07:52:25.563Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/39/a0/f718cda65b05407d228f97602cf60dca269c979867aa5beb25410de26cd3/safetensors-0.8.0-cp310-abi3-macosx_10_12_x86_64.whl", hash = "sha256:c554f85858e05226d3c2828e32395e677434685d6d94594a41643361c5e837f0", size = 473568, upload-time = "2026-06-09T07:52:18.829Z" }, + { url = "https://files.pythonhosted.org/packages/f5/b1/fa7c600e7dceae12e9606c7578cbc9ff1e1ed55844883ee5c92205e86226/safetensors-0.8.0-cp310-abi3-macosx_11_0_arm64.whl", hash = "sha256:c80201d22cbf405b80647a60ada77bba06c8fba2da2743ba1e89cdcc39a81f25", size = 484562, upload-time = "2026-06-09T07:52:17.518Z" }, + { url = "https://files.pythonhosted.org/packages/09/7d/65a7de0af421317bb36a067241e4235fff194eed60b961ed6d3f59a3fc60/safetensors-0.8.0-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7a46e5ff292c356d6991e60942ba7f79817682d3a2cef0702136448cb9c4d235", size = 502844, upload-time = "2026-06-09T07:52:07.624Z" }, + { url = "https://files.pythonhosted.org/packages/91/4f/3175c9d75634e0e0dda0082794193521035edd7c70a6f212bf33ca06ddf4/safetensors-0.8.0-cp310-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4124502b78f03534117c848f87a39b8f31e577b15eff423bf8bfb95f2a8c30d0", size = 511823, upload-time = "2026-06-09T07:52:09.565Z" }, + { url = "https://files.pythonhosted.org/packages/20/87/846c289e7aa2299eff406335717cf43ce8777194ece8aad75772e0411615/safetensors-0.8.0-cp310-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7bc0a787ba8a35be368ee3574edfa2b1ad389eebd0a72e482ae275490e3f6c98", size = 633461, upload-time = "2026-06-09T07:52:11.128Z" }, + { url = "https://files.pythonhosted.org/packages/76/22/8d64d9df2c45d5ded401df889d0ad90882804ca172d79ec4f0df8f727fe0/safetensors-0.8.0-cp310-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:040070828e36dc8e122178bbbd5830ff9e97920affb84cbe0f46442497bed358", size = 545148, upload-time = "2026-06-09T07:52:13.603Z" }, + { url = "https://files.pythonhosted.org/packages/28/50/f203ff3a3ddfe19308efc83c5a3a29ed02bf786732ec35e68bf9162f3365/safetensors-0.8.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd6f3f93c9a0a7cc2788ee63fb763353d4bd2e89b0751bc78fcf7dda00bea774", size = 516040, upload-time = "2026-06-09T07:52:16.29Z" }, + { url = "https://files.pythonhosted.org/packages/46/fb/cdaed17ceb2948784fd9c36b6fd3e951b608547cea81a48e8ee6f8cfdfcb/safetensors-0.8.0-cp310-abi3-manylinux_2_31_riscv64.whl", hash = "sha256:fcdd41ec4628fee5799f807c73c353629130fbd942aa23d83c623dd6c9d52d78", size = 513832, upload-time = "2026-06-09T07:52:12.37Z" }, + { url = "https://files.pythonhosted.org/packages/0d/49/1e15de264dcc3b77943d2d0c56a95809956883b1c2d6d585c792523f180b/safetensors-0.8.0-cp310-abi3-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8e9f537aa183a38ace122d27303dcd986b26bd2a7591f9181d7f0c396f4677ca", size = 559930, upload-time = "2026-06-09T07:52:14.743Z" }, + { url = "https://files.pythonhosted.org/packages/2a/43/bf38443278eab4b1be1fce2931e2b012ad9cb7df52ada751d0aab8f7659a/safetensors-0.8.0-cp310-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:87eec7ffed2b809f05a398a8becb7d013f19f7837cd15d9748580d6cf30dbaf4", size = 678670, upload-time = "2026-06-09T07:52:20.032Z" }, + { url = "https://files.pythonhosted.org/packages/72/e3/68cd3fa5b48488e84add63e04cb12f3bc28ae4638c06d4508c6e88823d0e/safetensors-0.8.0-cp310-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:4a95ae2b05d7726d751da4ebf626a2ca782b706e101bd894c95bc2450b1cffcc", size = 786679, upload-time = "2026-06-09T07:52:21.322Z" }, + { url = "https://files.pythonhosted.org/packages/29/4b/1c19c509d56e01f4fbb3d0a2e597450f6cc04d1d56cf52defb0a62dfd715/safetensors-0.8.0-cp310-abi3-musllinux_1_2_i686.whl", hash = "sha256:3ae091f16662658bdc019a4ff6cb4c085bb7d725eb5978b183ffd265863b6d2d", size = 765683, upload-time = "2026-06-09T07:52:22.594Z" }, + { url = "https://files.pythonhosted.org/packages/27/43/41c1621732edd934d868a00d1b891584c892a7b62a9aab82ea5a0a5623ee/safetensors-0.8.0-cp310-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:8e080062fcde23be189565e1c3305d16751a218ecf9412c8601e64204eb6f846", size = 722361, upload-time = "2026-06-09T07:52:23.924Z" }, + { url = "https://files.pythonhosted.org/packages/8e/3f/73ccf82579412b4a71c4ca673f10b5f1f888d7cf5af7fe24f27d30307be4/safetensors-0.8.0-cp310-abi3-win32.whl", hash = "sha256:2ddf52eac562eda224f99acfa7889d02968c1fd59a5b011ae7d8137c37e9c02d", size = 342401, upload-time = "2026-06-09T07:52:28.895Z" }, + { url = "https://files.pythonhosted.org/packages/1b/6d/3fba214c1e5e0f69991677ec3bc17023f0421776975e1de0c682dca475e2/safetensors-0.8.0-cp310-abi3-win_amd64.whl", hash = "sha256:096ec1a98435df7beb08853bb5aa9081a84f23d0adc67ed1a0a10550f608373f", size = 355540, upload-time = "2026-06-09T07:52:27.832Z" }, + { url = "https://files.pythonhosted.org/packages/8d/fc/7eedc3510d97878876e32774eebbeb61c43f148a96e915c84229a3e967aa/safetensors-0.8.0-cp310-abi3-win_arm64.whl", hash = "sha256:f7838e5135a406ad3e02efdcb8cf2e5397d368b0154537c4fec682dbc544d452", size = 340500, upload-time = "2026-06-09T07:52:26.745Z" }, ] [[package]]