Add support for FLUX.1-Krea-dev model (#241)
1
.github/workflows/release.yml
vendored
@ -48,6 +48,5 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
PYPI_API_TOKEN: ${{ secrets.PYPI_API_TOKEN }}
|
PYPI_API_TOKEN: ${{ secrets.PYPI_API_TOKEN }}
|
||||||
TEST_PYPI_API_TOKEN: ${{ secrets.TEST_PYPI_API_TOKEN }}
|
|
||||||
run: |
|
run: |
|
||||||
python -m mflux.release.release_script
|
python -m mflux.release.release_script
|
||||||
|
|||||||
28
CHANGELOG.md
@ -5,6 +5,34 @@ All notable changes to this project will be documented in this file.
|
|||||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
|
## [0.10.0] - 2025-08-02
|
||||||
|
|
||||||
|
# MFLUX v.0.10.0 Release Notes
|
||||||
|
|
||||||
|
### 🎨 Model Improvements
|
||||||
|
|
||||||
|
- **FLUX.1 Krea [dev] Support!**
|
||||||
|
|
||||||
|
### ✨ New Features
|
||||||
|
|
||||||
|
- **5-bit Quantization Support**: Added support for 5-bit quantization as a new option alongside existing 3, 4, 6, and 8-bit quantization levels
|
||||||
|
|
||||||
|
### 🔧 Improvements
|
||||||
|
|
||||||
|
- **Enhanced Default Inference Steps**: Increased default inference steps for dev models from 14 to 25 for improved image quality
|
||||||
|
- **Multiple Model Aliases Support**: Improved model configuration system to properly support multiple aliases per model, making model selection more flexible and robust
|
||||||
|
|
||||||
|
### 🔧 Technical Requirements
|
||||||
|
|
||||||
|
- **MLX Compatibility**: This release assumes MLX 0.27.0 and upwards for optimal performance and compatibility
|
||||||
|
- **MLX Compatibility for test**: Fix MLX version to 0.27.1 for image generation tests
|
||||||
|
- **Non-strict Weight Updates**: Explicitly added non-strict mode (`strict=False`) for weight updates to maintain compatibility with later MLX versions that enforce stricter weight validation by default
|
||||||
|
|
||||||
|
### 👩💻 Developer Experience
|
||||||
|
|
||||||
|
- **Streamlined Release Process**: Removed TestPyPi publishing step from release workflow for simplified deployment
|
||||||
|
---
|
||||||
|
|
||||||
## [0.9.6] - 2025-07-20
|
## [0.9.6] - 2025-07-20
|
||||||
|
|
||||||
# MFLUX v.0.9.6 Release Notes
|
# MFLUX v.0.9.6 Release Notes
|
||||||
|
|||||||
2
Makefile
@ -93,7 +93,7 @@ check: ensure-ruff
|
|||||||
.PHONY: test
|
.PHONY: test
|
||||||
test: ensure-pytest
|
test: ensure-pytest
|
||||||
# 🏗️ Running tests...
|
# 🏗️ Running tests...
|
||||||
uv pip install mlx==0.26.1 # Install pinned MLX version specifically for testing
|
uv pip install mlx==0.27.1 # Install pinned MLX version specifically for testing
|
||||||
$(PYTHON) -m pytest
|
$(PYTHON) -m pytest
|
||||||
# ✅ Tests completed
|
# ✅ Tests completed
|
||||||
|
|
||||||
|
|||||||
40
README.md
@ -186,8 +186,8 @@ from mflux.config.config import Config
|
|||||||
|
|
||||||
# Load the model
|
# Load the model
|
||||||
flux = Flux1.from_name(
|
flux = Flux1.from_name(
|
||||||
model_name="schnell", # "schnell" or "dev"
|
model_name="schnell", # "schnell", "dev", or "krea-dev"
|
||||||
quantize=8, # 4 or 8
|
quantize=8, # 3, 4, 5, 6, or 8
|
||||||
)
|
)
|
||||||
|
|
||||||
# Generate an image
|
# Generate an image
|
||||||
@ -195,7 +195,7 @@ image = flux.generate_image(
|
|||||||
seed=2,
|
seed=2,
|
||||||
prompt="Luxury food photograph",
|
prompt="Luxury food photograph",
|
||||||
config=Config(
|
config=Config(
|
||||||
num_inference_steps=2, # "schnell" works well with 2-4 steps, "dev" works well with 20-25 steps
|
num_inference_steps=2, # "schnell" works well with 2-4 steps, "dev" and "krea-dev" work well with 20-25 steps
|
||||||
height=1024,
|
height=1024,
|
||||||
width=1024,
|
width=1024,
|
||||||
)
|
)
|
||||||
@ -214,6 +214,26 @@ For more advanced Python usage and additional configuration options, you can exp
|
|||||||
|
|
||||||
🔒 [FLUX.1-dev currently requires granted access to its Huggingface repo. For troubleshooting, see the issue tracker](https://github.com/filipstrand/mflux/issues/14) 🔒
|
🔒 [FLUX.1-dev currently requires granted access to its Huggingface repo. For troubleshooting, see the issue tracker](https://github.com/filipstrand/mflux/issues/14) 🔒
|
||||||
|
|
||||||
|
#### 🎨 FLUX.1 Krea [dev]: Enhanced Photorealism
|
||||||
|
|
||||||
|
MFLUX now supports **FLUX.1 Krea [dev]**, an 'opinionated' text-to-image model developed in collaboration with [Krea AI](https://krea.ai). This model overcomes the oversaturated 'AI look' commonly found in generated images, achieving exceptional photorealism with distinctive aesthetics.
|
||||||
|
This model can be used where the `dev` model is used, and it is available as `krea-dev` in MFLUX (also supports the alias `dev-krea`), this includes dreambooth fine-tuning.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
```sh
|
||||||
|
mflux-generate \
|
||||||
|
--model krea-dev \
|
||||||
|
--prompt "A photo of a dog" \
|
||||||
|
--steps 25 \
|
||||||
|
--seed 2674888 \
|
||||||
|
-q 8 \
|
||||||
|
--height 1024 \
|
||||||
|
--width 1024
|
||||||
|
```
|
||||||
|
|
||||||
|
*Learn more about FLUX.1 Krea [dev] in the [official announcement](https://bfl.ai/announcements/flux-1-krea-dev).*
|
||||||
|
|
||||||
#### 📜 Full list of Command-Line Arguments
|
#### 📜 Full list of Command-Line Arguments
|
||||||
|
|
||||||
<details>
|
<details>
|
||||||
@ -226,9 +246,9 @@ For more advanced Python usage and additional configuration options, you can exp
|
|||||||
|
|
||||||
- **`--prompt`** (required, `str`): Text description of the image to generate. Use `-` to read the prompt from stdin (e.g., `echo "A beautiful sunset" | mflux-generate --prompt -`).
|
- **`--prompt`** (required, `str`): Text description of the image to generate. Use `-` to read the prompt from stdin (e.g., `echo "A beautiful sunset" | mflux-generate --prompt -`).
|
||||||
|
|
||||||
- **`--model`** or **`-m`** (required, `str`): Model to use for generation. Can be one of the official models (`"schnell"` or `"dev"`) or a HuggingFace repository ID for a compatible third-party model (e.g., `"Freepik/flux.1-lite-8B-alpha"`).
|
- **`--model`** or **`-m`** (required, `str`): Model to use for generation. Can be one of the official models (`"schnell"`, `"dev"`, or `"krea-dev"`) or a HuggingFace repository ID for a compatible third-party model (e.g., `"Freepik/flux.1-lite-8B-alpha"`).
|
||||||
|
|
||||||
- **`--base-model`** (optional, `str`, default: `None`): Specifies which base architecture a third-party model is derived from (`"schnell"` or `"dev"`). Required when using third-party models from HuggingFace.
|
- **`--base-model`** (optional, `str`, default: `None`): Specifies which base architecture a third-party model is derived from (`"schnell"`, `"dev"`, or `"krea-dev"`). Required when using third-party models from HuggingFace.
|
||||||
|
|
||||||
- **`--output`** (optional, `str`, default: `"image.png"`): Output image filename. If `--seed` or `--auto-seeds` establishes multiple seed values, the output filename will automatically be modified to include the seed value (e.g., `image_seed_42.png`).
|
- **`--output`** (optional, `str`, default: `"image.png"`): Output image filename. If `--seed` or `--auto-seeds` establishes multiple seed values, the output filename will automatically be modified to include the seed value (e.g., `image_seed_42.png`).
|
||||||
|
|
||||||
@ -246,7 +266,7 @@ For more advanced Python usage and additional configuration options, you can exp
|
|||||||
|
|
||||||
- **`--path`** (optional, `str`, default: `None`): Path to a local model on disk.
|
- **`--path`** (optional, `str`, default: `None`): Path to a local model on disk.
|
||||||
|
|
||||||
- **`--quantize`** or **`-q`** (optional, `int`, default: `None`): [Quantization](#%EF%B8%8F-quantization) (choose between `3`, `4`, `6`, or `8` bits).
|
- **`--quantize`** or **`-q`** (optional, `int`, default: `None`): [Quantization](#%EF%B8%8F-quantization) (choose between `3`, `4`, `5`, `6`, or `8` bits).
|
||||||
|
|
||||||
- **`--lora-paths`** (optional, `[str]`, default: `None`): The paths to the [LoRA](#-LoRA) weights.
|
- **`--lora-paths`** (optional, `[str]`, default: `None`): The paths to the [LoRA](#-LoRA) weights.
|
||||||
|
|
||||||
@ -698,7 +718,7 @@ Luxury food photograph of an italian Linguine pasta alle vongole dish with lots
|
|||||||
|
|
||||||
### 🗜️ Quantization
|
### 🗜️ Quantization
|
||||||
|
|
||||||
MFLUX supports running FLUX in 3, 4, 6, or 8-bit quantized mode. Running a quantized version can greatly speed up the
|
MFLUX supports running FLUX in 3, 4, 5, 6, or 8-bit quantized mode. Running a quantized version can greatly speed up the
|
||||||
generation process and reduce the memory consumption by several gigabytes. [Quantized models also take up less disk space](#-size-comparisons-for-quantized-models).
|
generation process and reduce the memory consumption by several gigabytes. [Quantized models also take up less disk space](#-size-comparisons-for-quantized-models).
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
@ -726,9 +746,9 @@ For systems with limited RAM, you can also use the `--low-ram` option which redu
|
|||||||
|
|
||||||
The model sizes for both `schnell` and `dev` at various quantization levels are as follows:
|
The model sizes for both `schnell` and `dev` at various quantization levels are as follows:
|
||||||
|
|
||||||
| 3 bit | 4 bit | 6 bit | 8 bit | Original (16 bit) |
|
| 3 bit | 4 bit | 5 bit | 6 bit | 8 bit | Original (16 bit) |
|
||||||
|--------|--------|---------|---------|-------------------|
|
|--------|--------|---------|---------|---------|-------------------|
|
||||||
| 7.52GB | 9.61GB | 13.81GB | 18.01GB | 33.73GB |
|
| 7.52GB | 9.61GB | 11.71GB | 13.81GB | 18.01GB | 33.73GB |
|
||||||
|
|
||||||
|
|
||||||
#### 💾 Saving a quantized version to disk
|
#### 💾 Saving a quantized version to disk
|
||||||
|
|||||||
@ -15,7 +15,7 @@ source-exclude = [
|
|||||||
|
|
||||||
[project]
|
[project]
|
||||||
name = "mflux"
|
name = "mflux"
|
||||||
version = "0.9.6"
|
version = "0.10.0"
|
||||||
description = "A MLX port of FLUX based on the Huggingface Diffusers implementation."
|
description = "A MLX port of FLUX based on the Huggingface Diffusers implementation."
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
keywords = ["diffusers", "flux", "mlx"]
|
keywords = ["diffusers", "flux", "mlx"]
|
||||||
@ -26,7 +26,7 @@ requires-python = ">=3.10"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"huggingface-hub>=0.24.5,<1.0",
|
"huggingface-hub>=0.24.5,<1.0",
|
||||||
"matplotlib>=3.9.2,<4.0",
|
"matplotlib>=3.9.2,<4.0",
|
||||||
"mlx>=0.22.0,<=0.26.1",
|
"mlx>=0.27.0,<0.28.0",
|
||||||
"numpy>=2.0.1,<3.0",
|
"numpy>=2.0.1,<3.0",
|
||||||
"opencv-python>=4.10.0,<5.0",
|
"opencv-python>=4.10.0,<5.0",
|
||||||
"piexif>=1.1.3,<2.0",
|
"piexif>=1.1.3,<2.0",
|
||||||
@ -61,7 +61,7 @@ classifiers = [
|
|||||||
dev = [
|
dev = [
|
||||||
"pytest>=8.3.0,<9.0",
|
"pytest>=8.3.0,<9.0",
|
||||||
"pytest-timer>=1.0,<2.0",
|
"pytest-timer>=1.0,<2.0",
|
||||||
"mlx==0.26.1", # Used ONLY during test runs to ensure deterministic test results
|
"mlx==0.27.1", # Used ONLY during test runs to ensure deterministic test results
|
||||||
]
|
]
|
||||||
|
|
||||||
[project.urls]
|
[project.urls]
|
||||||
|
|||||||
BIN
src/mflux/assets/krea_dev_example.jpg
Normal file
|
After Width: | Height: | Size: 672 KiB |
@ -24,7 +24,7 @@ This module provides ZSH shell completion support for all mflux CLI commands.
|
|||||||
- **Auto-completion for all 15 mflux commands**: Generate, train, save, upscale, and more
|
- **Auto-completion for all 15 mflux commands**: Generate, train, save, upscale, and more
|
||||||
- **Smart completions**:
|
- **Smart completions**:
|
||||||
- Model names (dev, schnell, dev-fill, or HuggingFace repos)
|
- Model names (dev, schnell, dev-fill, or HuggingFace repos)
|
||||||
- Quantization levels (3, 4, 6, 8)
|
- Quantization levels (3, 4, 5, 6, 8)
|
||||||
- LoRA styles (storyboard, portrait, etc.)
|
- LoRA styles (storyboard, portrait, etc.)
|
||||||
- File paths with native completion
|
- File paths with native completion
|
||||||
- Common percentage values for battery limit
|
- Common percentage values for battery limit
|
||||||
|
|||||||
@ -7,7 +7,7 @@ from mflux.error.error import InvalidBaseModel, ModelConfigError
|
|||||||
class ModelConfig:
|
class ModelConfig:
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
alias: str | None,
|
aliases: list[str],
|
||||||
model_name: str,
|
model_name: str,
|
||||||
base_model: str | None,
|
base_model: str | None,
|
||||||
controlnet_model: str | None,
|
controlnet_model: str | None,
|
||||||
@ -18,7 +18,7 @@ class ModelConfig:
|
|||||||
requires_sigma_shift: bool,
|
requires_sigma_shift: bool,
|
||||||
priority: int,
|
priority: int,
|
||||||
):
|
):
|
||||||
self.alias = alias
|
self.aliases = aliases
|
||||||
self.model_name = model_name
|
self.model_name = model_name
|
||||||
self.base_model = base_model
|
self.base_model = base_model
|
||||||
self.controlnet_model = controlnet_model
|
self.controlnet_model = controlnet_model
|
||||||
@ -79,49 +79,55 @@ class ModelConfig:
|
|||||||
def dev_fill_catvton() -> "ModelConfig":
|
def dev_fill_catvton() -> "ModelConfig":
|
||||||
return AVAILABLE_MODELS["dev-fill-catvton"]
|
return AVAILABLE_MODELS["dev-fill-catvton"]
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
@lru_cache
|
||||||
|
def krea_dev() -> "ModelConfig":
|
||||||
|
return AVAILABLE_MODELS["krea-dev"]
|
||||||
|
|
||||||
def x_embedder_input_dim(self) -> int:
|
def x_embedder_input_dim(self) -> int:
|
||||||
if self.alias and "dev-fill" in self.alias:
|
if "Fill" in self.model_name:
|
||||||
return 384
|
return 384
|
||||||
if self.alias == "dev-depth":
|
if "Depth" in self.model_name:
|
||||||
return 128
|
return 128
|
||||||
else:
|
else:
|
||||||
return 64
|
return 64
|
||||||
|
|
||||||
def is_canny(self) -> bool:
|
def is_canny(self) -> bool:
|
||||||
return self.alias == "dev-controlnet-canny" or self.alias == "schnell-controlnet-canny"
|
return self.controlnet_model is not None and "Canny" in self.controlnet_model
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def from_name(
|
def from_name(
|
||||||
model_name: str,
|
model_name: str,
|
||||||
base_model: Literal["dev", "schnell", "dev-fill"] | None = None,
|
base_model: Literal["dev", "schnell", "krea-dev"] | None = None,
|
||||||
) -> "ModelConfig":
|
) -> "ModelConfig":
|
||||||
# 0. Get all base models (where base_model is None) sorted by priority
|
# 0. Get all base models (where base_model is None) sorted by priority
|
||||||
base_models = sorted(
|
base_models = sorted(
|
||||||
[model for model in AVAILABLE_MODELS.values() if model.base_model is None], key=lambda x: x.priority
|
[model for model in AVAILABLE_MODELS.values() if model.base_model is None], key=lambda x: x.priority
|
||||||
)
|
)
|
||||||
|
|
||||||
# 1. Check if model_name matches any base model's alias or full name
|
# 1. Check if model_name matches any base model's aliases or full name
|
||||||
for base in base_models:
|
for base in base_models:
|
||||||
if model_name in (base.alias, base.model_name):
|
if model_name == base.model_name or model_name in base.aliases:
|
||||||
return base
|
return base
|
||||||
|
|
||||||
# 2. Validate explicit base_model
|
# 2. Validate explicit base_model
|
||||||
allowed_names = []
|
allowed_names = []
|
||||||
for base in base_models:
|
for base in base_models:
|
||||||
allowed_names.extend([base.alias, base.model_name])
|
allowed_names.extend(base.aliases + [base.model_name])
|
||||||
if base_model and base_model not in allowed_names:
|
if base_model and base_model not in allowed_names:
|
||||||
raise InvalidBaseModel(f"Invalid base_model. Choose one of {allowed_names}")
|
raise InvalidBaseModel(f"Invalid base_model. Choose one of {allowed_names}")
|
||||||
|
|
||||||
# 3. Determine the base model (explicit or inferred)
|
# 3. Determine the base model (explicit or inferred)
|
||||||
if base_model:
|
if base_model:
|
||||||
# Find by explicit base_model name
|
# Find by explicit base_model name (check all aliases)
|
||||||
default_base = next((b for b in base_models if base_model in (b.alias, b.model_name)), None)
|
default_base = next((b for b in base_models if base_model == b.model_name or base_model in b.aliases), None)
|
||||||
else:
|
else:
|
||||||
# Infer from model_name substring - prefer longer matches (more specific)
|
# Infer from model_name substring - prefer longer matches (more specific)
|
||||||
matching_bases = [b for b in base_models if b.alias and b.alias in model_name]
|
matching_bases = [(b, alias) for b in base_models for alias in b.aliases if alias and alias in model_name]
|
||||||
|
|
||||||
if matching_bases:
|
if matching_bases:
|
||||||
# Sort by alias length descending, then by priority ascending
|
# Sort by alias length descending, then by priority ascending
|
||||||
default_base = sorted(matching_bases, key=lambda x: (-len(x.alias), x.priority))[0]
|
default_base = sorted(matching_bases, key=lambda x: (-len(x[1]), x[0].priority))[0][0]
|
||||||
else:
|
else:
|
||||||
default_base = None
|
default_base = None
|
||||||
if not default_base:
|
if not default_base:
|
||||||
@ -129,7 +135,7 @@ class ModelConfig:
|
|||||||
|
|
||||||
# 4. Construct the config
|
# 4. Construct the config
|
||||||
return ModelConfig(
|
return ModelConfig(
|
||||||
alias=default_base.alias,
|
aliases=default_base.aliases,
|
||||||
model_name=model_name,
|
model_name=model_name,
|
||||||
base_model=default_base.model_name,
|
base_model=default_base.model_name,
|
||||||
controlnet_model=default_base.controlnet_model,
|
controlnet_model=default_base.controlnet_model,
|
||||||
@ -144,7 +150,7 @@ class ModelConfig:
|
|||||||
|
|
||||||
AVAILABLE_MODELS = {
|
AVAILABLE_MODELS = {
|
||||||
"dev": ModelConfig(
|
"dev": ModelConfig(
|
||||||
alias="dev",
|
aliases=["dev"],
|
||||||
model_name="black-forest-labs/FLUX.1-dev",
|
model_name="black-forest-labs/FLUX.1-dev",
|
||||||
base_model=None,
|
base_model=None,
|
||||||
controlnet_model=None,
|
controlnet_model=None,
|
||||||
@ -156,7 +162,7 @@ AVAILABLE_MODELS = {
|
|||||||
priority=0,
|
priority=0,
|
||||||
),
|
),
|
||||||
"schnell": ModelConfig(
|
"schnell": ModelConfig(
|
||||||
alias="schnell",
|
aliases=["schnell"],
|
||||||
model_name="black-forest-labs/FLUX.1-schnell",
|
model_name="black-forest-labs/FLUX.1-schnell",
|
||||||
base_model=None,
|
base_model=None,
|
||||||
controlnet_model=None,
|
controlnet_model=None,
|
||||||
@ -168,7 +174,7 @@ AVAILABLE_MODELS = {
|
|||||||
priority=1,
|
priority=1,
|
||||||
),
|
),
|
||||||
"dev-kontext": ModelConfig(
|
"dev-kontext": ModelConfig(
|
||||||
alias="dev-kontext",
|
aliases=["dev-kontext"],
|
||||||
model_name="black-forest-labs/FLUX.1-Kontext-dev",
|
model_name="black-forest-labs/FLUX.1-Kontext-dev",
|
||||||
base_model=None,
|
base_model=None,
|
||||||
controlnet_model=None,
|
controlnet_model=None,
|
||||||
@ -180,7 +186,7 @@ AVAILABLE_MODELS = {
|
|||||||
priority=2,
|
priority=2,
|
||||||
),
|
),
|
||||||
"dev-fill": ModelConfig(
|
"dev-fill": ModelConfig(
|
||||||
alias="dev-fill",
|
aliases=["dev-fill"],
|
||||||
model_name="black-forest-labs/FLUX.1-Fill-dev",
|
model_name="black-forest-labs/FLUX.1-Fill-dev",
|
||||||
base_model=None,
|
base_model=None,
|
||||||
controlnet_model=None,
|
controlnet_model=None,
|
||||||
@ -192,7 +198,7 @@ AVAILABLE_MODELS = {
|
|||||||
priority=3,
|
priority=3,
|
||||||
),
|
),
|
||||||
"dev-redux": ModelConfig(
|
"dev-redux": ModelConfig(
|
||||||
alias="dev-redux",
|
aliases=["dev-redux"],
|
||||||
model_name="black-forest-labs/FLUX.1-Redux-dev",
|
model_name="black-forest-labs/FLUX.1-Redux-dev",
|
||||||
base_model=None,
|
base_model=None,
|
||||||
controlnet_model=None,
|
controlnet_model=None,
|
||||||
@ -204,7 +210,7 @@ AVAILABLE_MODELS = {
|
|||||||
priority=4,
|
priority=4,
|
||||||
),
|
),
|
||||||
"dev-depth": ModelConfig(
|
"dev-depth": ModelConfig(
|
||||||
alias="dev-depth",
|
aliases=["dev-depth"],
|
||||||
model_name="black-forest-labs/FLUX.1-Depth-dev",
|
model_name="black-forest-labs/FLUX.1-Depth-dev",
|
||||||
base_model=None,
|
base_model=None,
|
||||||
controlnet_model=None,
|
controlnet_model=None,
|
||||||
@ -216,7 +222,7 @@ AVAILABLE_MODELS = {
|
|||||||
priority=5,
|
priority=5,
|
||||||
),
|
),
|
||||||
"dev-controlnet-canny": ModelConfig(
|
"dev-controlnet-canny": ModelConfig(
|
||||||
alias="dev-controlnet-canny",
|
aliases=["dev-controlnet-canny"],
|
||||||
model_name="black-forest-labs/FLUX.1-dev",
|
model_name="black-forest-labs/FLUX.1-dev",
|
||||||
base_model=None,
|
base_model=None,
|
||||||
controlnet_model="InstantX/FLUX.1-dev-Controlnet-Canny",
|
controlnet_model="InstantX/FLUX.1-dev-Controlnet-Canny",
|
||||||
@ -228,7 +234,7 @@ AVAILABLE_MODELS = {
|
|||||||
priority=6,
|
priority=6,
|
||||||
),
|
),
|
||||||
"schnell-controlnet-canny": ModelConfig(
|
"schnell-controlnet-canny": ModelConfig(
|
||||||
alias="schnell-controlnet-canny",
|
aliases=["schnell-controlnet-canny"],
|
||||||
model_name="black-forest-labs/FLUX.1-schnell",
|
model_name="black-forest-labs/FLUX.1-schnell",
|
||||||
base_model=None,
|
base_model=None,
|
||||||
controlnet_model="InstantX/FLUX.1-dev-Controlnet-Canny",
|
controlnet_model="InstantX/FLUX.1-dev-Controlnet-Canny",
|
||||||
@ -240,7 +246,7 @@ AVAILABLE_MODELS = {
|
|||||||
priority=7,
|
priority=7,
|
||||||
),
|
),
|
||||||
"dev-controlnet-upscaler": ModelConfig(
|
"dev-controlnet-upscaler": ModelConfig(
|
||||||
alias="dev-controlnet-upscaler",
|
aliases=["dev-controlnet-upscaler"],
|
||||||
model_name="black-forest-labs/FLUX.1-dev",
|
model_name="black-forest-labs/FLUX.1-dev",
|
||||||
base_model=None,
|
base_model=None,
|
||||||
controlnet_model="jasperai/Flux.1-dev-Controlnet-Upscaler",
|
controlnet_model="jasperai/Flux.1-dev-Controlnet-Upscaler",
|
||||||
@ -252,7 +258,7 @@ AVAILABLE_MODELS = {
|
|||||||
priority=8,
|
priority=8,
|
||||||
),
|
),
|
||||||
"dev-fill-catvton": ModelConfig(
|
"dev-fill-catvton": ModelConfig(
|
||||||
alias="dev-fill-catvton",
|
aliases=["dev-fill-catvton"],
|
||||||
model_name="black-forest-labs/FLUX.1-Fill-dev",
|
model_name="black-forest-labs/FLUX.1-Fill-dev",
|
||||||
base_model=None,
|
base_model=None,
|
||||||
controlnet_model=None,
|
controlnet_model=None,
|
||||||
@ -263,4 +269,16 @@ AVAILABLE_MODELS = {
|
|||||||
requires_sigma_shift=False, # Not sure why, but produced better results this way...
|
requires_sigma_shift=False, # Not sure why, but produced better results this way...
|
||||||
priority=9,
|
priority=9,
|
||||||
),
|
),
|
||||||
|
"krea-dev": ModelConfig(
|
||||||
|
aliases=["krea-dev", "dev-krea"],
|
||||||
|
model_name="black-forest-labs/FLUX.1-Krea-dev",
|
||||||
|
base_model=None,
|
||||||
|
controlnet_model=None,
|
||||||
|
custom_transformer_model=None,
|
||||||
|
num_train_steps=1000,
|
||||||
|
max_sequence_length=512,
|
||||||
|
supports_guidance=True,
|
||||||
|
requires_sigma_shift=True,
|
||||||
|
priority=10,
|
||||||
|
),
|
||||||
}
|
}
|
||||||
|
|||||||
@ -18,7 +18,7 @@ class DepthProInitializer:
|
|||||||
WeightHandlerDepthPro.reshape_transposed_convolution_weights(depth_pro_weights)
|
WeightHandlerDepthPro.reshape_transposed_convolution_weights(depth_pro_weights)
|
||||||
|
|
||||||
# 2. Assign the weights to the model
|
# 2. Assign the weights to the model
|
||||||
depth_pro_model.update(depth_pro_weights.weights)
|
depth_pro_model.update(depth_pro_weights.weights, strict=False)
|
||||||
|
|
||||||
# 3. Optionally quantize the model
|
# 3. Optionally quantize the model
|
||||||
if quantize:
|
if quantize:
|
||||||
|
|||||||
@ -2,7 +2,6 @@ import shutil
|
|||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Optional
|
|
||||||
|
|
||||||
import requests
|
import requests
|
||||||
from twine.commands import upload
|
from twine.commands import upload
|
||||||
@ -34,9 +33,9 @@ class PyPIPublisher:
|
|||||||
)
|
)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def version_exists_on_pypi(package_name: str, version: str, test_pypi: bool = False) -> bool:
|
def version_exists_on_pypi(package_name: str, version: str) -> bool:
|
||||||
print("🔍 Checking if version already exists on PyPI...")
|
print("🔍 Checking if version already exists on PyPI...")
|
||||||
repo_url = "https://test.pypi.org/pypi" if test_pypi else "https://pypi.org/pypi"
|
repo_url = "https://pypi.org/pypi"
|
||||||
url = f"{repo_url}/{package_name}/json"
|
url = f"{repo_url}/{package_name}/json"
|
||||||
|
|
||||||
for attempt in range(3):
|
for attempt in range(3):
|
||||||
@ -77,21 +76,6 @@ class PyPIPublisher:
|
|||||||
|
|
||||||
raise RuntimeError("Unexpected error in version_exists_on_pypi")
|
raise RuntimeError("Unexpected error in version_exists_on_pypi")
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def publish_to_test_pypi(test_pypi_token: Optional[str], package_name: str, version: str) -> None:
|
|
||||||
if not test_pypi_token:
|
|
||||||
print("⚠️ Test PyPI token not provided, skipping Test PyPI upload")
|
|
||||||
return
|
|
||||||
|
|
||||||
PyPIPublisher._upload_to_pypi(
|
|
||||||
token=test_pypi_token,
|
|
||||||
repository="testpypi",
|
|
||||||
display_name="Test PyPI",
|
|
||||||
package_name=package_name,
|
|
||||||
version=version,
|
|
||||||
optional=True,
|
|
||||||
)
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def publish_to_pypi(pypi_token: str, package_name: str, version: str) -> None:
|
def publish_to_pypi(pypi_token: str, package_name: str, version: str) -> None:
|
||||||
PyPIPublisher._upload_to_pypi(
|
PyPIPublisher._upload_to_pypi(
|
||||||
|
|||||||
@ -1,5 +1,3 @@
|
|||||||
from typing import Optional
|
|
||||||
|
|
||||||
import requests
|
import requests
|
||||||
|
|
||||||
from mflux.release.changelog_parser import ChangelogParser
|
from mflux.release.changelog_parser import ChangelogParser
|
||||||
@ -15,7 +13,6 @@ class ReleaseManager:
|
|||||||
def create_release(
|
def create_release(
|
||||||
github_token: str,
|
github_token: str,
|
||||||
pypi_token: str,
|
pypi_token: str,
|
||||||
test_pypi_token: Optional[str] = None,
|
|
||||||
github_repo: str = "filipstrand/mflux",
|
github_repo: str = "filipstrand/mflux",
|
||||||
package_name: str = "mflux",
|
package_name: str = "mflux",
|
||||||
) -> None:
|
) -> None:
|
||||||
@ -40,7 +37,6 @@ class ReleaseManager:
|
|||||||
# 4. Handle PyPI publishing FIRST (before creating git artifacts)
|
# 4. Handle PyPI publishing FIRST (before creating git artifacts)
|
||||||
if ReleaseManager._should_publish_to_pypi(git_tag_exists, github_release_exists, package_name, version):
|
if ReleaseManager._should_publish_to_pypi(git_tag_exists, github_release_exists, package_name, version):
|
||||||
PyPIPublisher.build_and_verify_package()
|
PyPIPublisher.build_and_verify_package()
|
||||||
PyPIPublisher.publish_to_test_pypi(test_pypi_token, package_name, version)
|
|
||||||
PyPIPublisher.publish_to_pypi(pypi_token, package_name, version)
|
PyPIPublisher.publish_to_pypi(pypi_token, package_name, version)
|
||||||
|
|
||||||
# 5. Create git tag if needed
|
# 5. Create git tag if needed
|
||||||
@ -76,7 +72,7 @@ class ReleaseManager:
|
|||||||
|
|
||||||
# Check if version already exists on PyPI
|
# Check if version already exists on PyPI
|
||||||
try:
|
try:
|
||||||
if PyPIPublisher.version_exists_on_pypi(package_name, version, test_pypi=False):
|
if PyPIPublisher.version_exists_on_pypi(package_name, version):
|
||||||
return False
|
return False
|
||||||
except (requests.RequestException, ValueError, OSError) as e:
|
except (requests.RequestException, ValueError, OSError) as e:
|
||||||
print(f"❌ Failed to check PyPI version: {e}")
|
print(f"❌ Failed to check PyPI version: {e}")
|
||||||
|
|||||||
@ -11,14 +11,12 @@ def main():
|
|||||||
parser = argparse.ArgumentParser(description="MFLUX Release Management")
|
parser = argparse.ArgumentParser(description="MFLUX Release Management")
|
||||||
parser.add_argument("--github-token", help="GitHub token")
|
parser.add_argument("--github-token", help="GitHub token")
|
||||||
parser.add_argument("--pypi-token", help="PyPI API token")
|
parser.add_argument("--pypi-token", help="PyPI API token")
|
||||||
parser.add_argument("--test-pypi-token", help="Test PyPI API token (optional)")
|
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
ReleaseManager.create_release(
|
ReleaseManager.create_release(
|
||||||
github_token=args.github_token or os.getenv("GITHUB_TOKEN"),
|
github_token=args.github_token or os.getenv("GITHUB_TOKEN"),
|
||||||
pypi_token=args.pypi_token or os.getenv("PYPI_API_TOKEN"),
|
pypi_token=args.pypi_token or os.getenv("PYPI_API_TOKEN"),
|
||||||
test_pypi_token=args.test_pypi_token or os.getenv("TEST_PYPI_API_TOKEN"),
|
|
||||||
)
|
)
|
||||||
except (ValueError, FileNotFoundError, requests.RequestException) as e:
|
except (ValueError, FileNotFoundError, requests.RequestException) as e:
|
||||||
print(f"❌ Release failed: {e}")
|
print(f"❌ Release failed: {e}")
|
||||||
|
|||||||
@ -289,7 +289,7 @@ class CommandLineParser(argparse.ArgumentParser):
|
|||||||
self.error("Either --prompt or --prompt-file argument is required, or 'prompt' required in metadata config file")
|
self.error("Either --prompt or --prompt-file argument is required, or 'prompt' required in metadata config file")
|
||||||
|
|
||||||
if self.supports_image_generation and namespace.steps is None:
|
if self.supports_image_generation and namespace.steps is None:
|
||||||
namespace.steps = ui_defaults.MODEL_INFERENCE_STEPS.get(namespace.model, 14)
|
namespace.steps = ui_defaults.MODEL_INFERENCE_STEPS.get(namespace.model, 25)
|
||||||
|
|
||||||
# In-context edit specific validations
|
# In-context edit specific validations
|
||||||
if getattr(self, 'supports_in_context_edit', False):
|
if getattr(self, 'supports_in_context_edit', False):
|
||||||
|
|||||||
@ -17,16 +17,13 @@ GUIDANCE_SCALE_KONTEXT = 2.5
|
|||||||
HEIGHT, WIDTH = 1024, 1024
|
HEIGHT, WIDTH = 1024, 1024
|
||||||
MAX_PIXELS_WARNING_THRESHOLD = 2048 * 2048
|
MAX_PIXELS_WARNING_THRESHOLD = 2048 * 2048
|
||||||
IMAGE_STRENGTH = 0.4
|
IMAGE_STRENGTH = 0.4
|
||||||
MODEL_CHOICES = ["dev", "schnell", "dev-kontext", "dev-fill"]
|
MODEL_CHOICES = ["dev", "schnell", "krea-dev"]
|
||||||
MODEL_INFERENCE_STEPS = {
|
MODEL_INFERENCE_STEPS = {
|
||||||
"dev": 14,
|
"dev": 25,
|
||||||
"dev-fill": 14,
|
"krea-dev": 25,
|
||||||
"dev-depth": 14,
|
|
||||||
"dev-redux": 14,
|
|
||||||
"dev-kontext": 14,
|
|
||||||
"schnell": 4,
|
"schnell": 4,
|
||||||
}
|
}
|
||||||
QUANTIZE_CHOICES = [3, 4, 6, 8]
|
QUANTIZE_CHOICES = [3, 5, 4, 6, 8]
|
||||||
|
|
||||||
|
|
||||||
def _migrate_legacy_cache(new_cache_dir: Path) -> None:
|
def _migrate_legacy_cache(new_cache_dir: Path) -> None:
|
||||||
|
|||||||
@ -57,19 +57,19 @@ class WeightUtil:
|
|||||||
transformer_controlnet: nn.Module,
|
transformer_controlnet: nn.Module,
|
||||||
) -> int | None:
|
) -> int | None:
|
||||||
if weights.meta_data.quantization_level is None and quantize_arg is None:
|
if weights.meta_data.quantization_level is None and quantize_arg is None:
|
||||||
transformer_controlnet.update(weights.controlnet_transformer)
|
transformer_controlnet.update(weights.controlnet_transformer, strict=False)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
if weights.meta_data.quantization_level is None and quantize_arg is not None:
|
if weights.meta_data.quantization_level is None and quantize_arg is not None:
|
||||||
bits = quantize_arg
|
bits = quantize_arg
|
||||||
transformer_controlnet.update(weights.controlnet_transformer)
|
transformer_controlnet.update(weights.controlnet_transformer, strict=False)
|
||||||
QuantizationUtil.quantize_controlnet(bits, weights, transformer_controlnet)
|
QuantizationUtil.quantize_controlnet(bits, weights, transformer_controlnet)
|
||||||
return bits
|
return bits
|
||||||
|
|
||||||
if weights.meta_data.quantization_level is not None:
|
if weights.meta_data.quantization_level is not None:
|
||||||
bits = weights.meta_data.quantization_level
|
bits = weights.meta_data.quantization_level
|
||||||
QuantizationUtil.quantize_controlnet(bits, weights, transformer_controlnet)
|
QuantizationUtil.quantize_controlnet(bits, weights, transformer_controlnet)
|
||||||
transformer_controlnet.update(weights.controlnet_transformer)
|
transformer_controlnet.update(weights.controlnet_transformer, strict=False)
|
||||||
return bits
|
return bits
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@ -80,10 +80,10 @@ class WeightUtil:
|
|||||||
t5_text_encoder: nn.Module,
|
t5_text_encoder: nn.Module,
|
||||||
clip_text_encoder: nn.Module,
|
clip_text_encoder: nn.Module,
|
||||||
):
|
):
|
||||||
vae.update(weights.vae)
|
vae.update(weights.vae, strict=False)
|
||||||
transformer.update(weights.transformer)
|
transformer.update(weights.transformer, strict=False)
|
||||||
t5_text_encoder.update(weights.t5_encoder)
|
t5_text_encoder.update(weights.t5_encoder, strict=False)
|
||||||
clip_text_encoder.update(weights.clip_encoder)
|
clip_text_encoder.update(weights.clip_encoder, strict=False)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _set_redux_model_weights(
|
def _set_redux_model_weights(
|
||||||
@ -91,8 +91,8 @@ class WeightUtil:
|
|||||||
redux_encoder: nn.Module,
|
redux_encoder: nn.Module,
|
||||||
siglip_vision_transformer: nn.Module,
|
siglip_vision_transformer: nn.Module,
|
||||||
):
|
):
|
||||||
redux_encoder.update(weights.redux_encoder)
|
redux_encoder.update(weights.redux_encoder, strict=False)
|
||||||
siglip_vision_transformer.update(weights.siglip["vision_model"])
|
siglip_vision_transformer.update(weights.siglip["vision_model"], strict=False)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def set_redux_weights_and_quantize(
|
def set_redux_weights_and_quantize(
|
||||||
|
|||||||
@ -410,7 +410,7 @@ def test_steps_arg(mflux_generate_parser, mflux_generate_minimal_argv, base_meta
|
|||||||
# test user default value for dev
|
# test user default value for dev
|
||||||
with patch("sys.argv", mflux_generate_minimal_argv + ["--model", "dev"]):
|
with patch("sys.argv", mflux_generate_minimal_argv + ["--model", "dev"]):
|
||||||
args = mflux_generate_parser.parse_args()
|
args = mflux_generate_parser.parse_args()
|
||||||
assert args.steps == 14
|
assert args.steps == 25
|
||||||
|
|
||||||
# test user default value for schnell
|
# test user default value for schnell
|
||||||
with patch("sys.argv", mflux_generate_minimal_argv + ["--model", "schnell"]):
|
with patch("sys.argv", mflux_generate_minimal_argv + ["--model", "schnell"]):
|
||||||
|
|||||||
@ -57,8 +57,8 @@ class TestImageGenerator:
|
|||||||
|
|
||||||
def test_image_generation_dev_image_to_image(self):
|
def test_image_generation_dev_image_to_image(self):
|
||||||
ImageGeneratorTestHelper.assert_matches_reference_image(
|
ImageGeneratorTestHelper.assert_matches_reference_image(
|
||||||
reference_image_path="reference_dev_image_to_image_result.png",
|
reference_image_path="reference_dev_image_to_image.png",
|
||||||
output_image_path="output_dev_image_to_image_result.png",
|
output_image_path="output_dev_image_to_image.png",
|
||||||
image_strength=0.4,
|
image_strength=0.4,
|
||||||
model_config=ModelConfig.dev(),
|
model_config=ModelConfig.dev(),
|
||||||
steps=8,
|
steps=8,
|
||||||
|
|||||||
@ -3,13 +3,11 @@ from tests.image_generation.helpers.image_generation_controlnet_test_helper impo
|
|||||||
|
|
||||||
|
|
||||||
class TestImageGeneratorControlnet:
|
class TestImageGeneratorControlnet:
|
||||||
CONTROLNET_REFERENCE_FILENAME = "controlnet_reference.png"
|
|
||||||
|
|
||||||
def test_image_generation_schnell_controlnet(self):
|
def test_image_generation_schnell_controlnet(self):
|
||||||
ImageGeneratorControlnetTestHelper.assert_matches_reference_image(
|
ImageGeneratorControlnetTestHelper.assert_matches_reference_image(
|
||||||
reference_image_path="reference_controlnet_schnell.png",
|
reference_image_path="reference_controlnet_schnell.png",
|
||||||
output_image_path="output_controlnet_schnell.png",
|
output_image_path="output_controlnet_schnell.png",
|
||||||
controlnet_image_path=TestImageGeneratorControlnet.CONTROLNET_REFERENCE_FILENAME,
|
controlnet_image_path="controlnet_reference.png",
|
||||||
model_config=ModelConfig.schnell_controlnet_canny(),
|
model_config=ModelConfig.schnell_controlnet_canny(),
|
||||||
steps=2,
|
steps=2,
|
||||||
seed=43,
|
seed=43,
|
||||||
@ -23,7 +21,7 @@ class TestImageGeneratorControlnet:
|
|||||||
ImageGeneratorControlnetTestHelper.assert_matches_reference_image(
|
ImageGeneratorControlnetTestHelper.assert_matches_reference_image(
|
||||||
reference_image_path="reference_controlnet_dev.png",
|
reference_image_path="reference_controlnet_dev.png",
|
||||||
output_image_path="output_controlnet_dev.png",
|
output_image_path="output_controlnet_dev.png",
|
||||||
controlnet_image_path=TestImageGeneratorControlnet.CONTROLNET_REFERENCE_FILENAME,
|
controlnet_image_path="controlnet_reference.png",
|
||||||
model_config=ModelConfig.dev_controlnet_canny(),
|
model_config=ModelConfig.dev_controlnet_canny(),
|
||||||
steps=15,
|
steps=15,
|
||||||
seed=42,
|
seed=42,
|
||||||
@ -37,7 +35,7 @@ class TestImageGeneratorControlnet:
|
|||||||
ImageGeneratorControlnetTestHelper.assert_matches_reference_image(
|
ImageGeneratorControlnetTestHelper.assert_matches_reference_image(
|
||||||
reference_image_path="reference_controlnet_dev_lora.png",
|
reference_image_path="reference_controlnet_dev_lora.png",
|
||||||
output_image_path="output_controlnet_dev_lora.png",
|
output_image_path="output_controlnet_dev_lora.png",
|
||||||
controlnet_image_path=TestImageGeneratorControlnet.CONTROLNET_REFERENCE_FILENAME,
|
controlnet_image_path="controlnet_reference.png",
|
||||||
model_config=ModelConfig.dev_controlnet_canny(),
|
model_config=ModelConfig.dev_controlnet_canny(),
|
||||||
steps=15,
|
steps=15,
|
||||||
seed=43,
|
seed=43,
|
||||||
@ -52,7 +50,7 @@ class TestImageGeneratorControlnet:
|
|||||||
def test_image_upscaling(self):
|
def test_image_upscaling(self):
|
||||||
ImageGeneratorControlnetTestHelper.assert_matches_reference_image(
|
ImageGeneratorControlnetTestHelper.assert_matches_reference_image(
|
||||||
reference_image_path="reference_upscaled.png",
|
reference_image_path="reference_upscaled.png",
|
||||||
output_image_path="output_upscaler.png",
|
output_image_path="output_upscaled.png",
|
||||||
controlnet_image_path="low_res.jpg",
|
controlnet_image_path="low_res.jpg",
|
||||||
model_config=ModelConfig.dev_controlnet_upscaler(),
|
model_config=ModelConfig.dev_controlnet_upscaler(),
|
||||||
steps=20,
|
steps=20,
|
||||||
|
|||||||
@ -3,13 +3,11 @@ from tests.image_generation.helpers.image_generation_depth_test_helper import Im
|
|||||||
|
|
||||||
|
|
||||||
class TestImageGeneratorDepth:
|
class TestImageGeneratorDepth:
|
||||||
SOURCE_IMAGE_FILENAME = "reference_controlnet_dev_lora.png"
|
|
||||||
|
|
||||||
def test_image_generation_with_reference_image(self):
|
def test_image_generation_with_reference_image(self):
|
||||||
ImageGeneratorDepthTestHelper.assert_matches_reference_image(
|
ImageGeneratorDepthTestHelper.assert_matches_reference_image(
|
||||||
reference_image_path="reference_depth_dev_from_image.png",
|
reference_image_path="reference_depth_dev_from_image.png",
|
||||||
output_image_path="output_depth_dev_from_image.png",
|
output_image_path="output_depth_dev_from_image.png",
|
||||||
image_path=TestImageGeneratorDepth.SOURCE_IMAGE_FILENAME,
|
image_path="reference_controlnet_dev_lora.png",
|
||||||
model_config=ModelConfig.dev_depth(),
|
model_config=ModelConfig.dev_depth(),
|
||||||
steps=15,
|
steps=15,
|
||||||
seed=42,
|
seed=42,
|
||||||
|
|||||||
@ -3,19 +3,16 @@ from tests.image_generation.helpers.image_generation_fill_test_helper import Ima
|
|||||||
|
|
||||||
|
|
||||||
class TestImageGeneratorFill:
|
class TestImageGeneratorFill:
|
||||||
SOURCE_IMAGE_FILENAME = "reference_dev_image_to_image_result.png"
|
|
||||||
MASK_IMAGE_FILENAME = "mask.png"
|
|
||||||
|
|
||||||
def test_fill(self):
|
def test_fill(self):
|
||||||
ImageGeneratorFillTestHelper.assert_matches_reference_image(
|
ImageGeneratorFillTestHelper.assert_matches_reference_image(
|
||||||
reference_image_path="reference_dev_image_to_image_result_inpaint.png",
|
reference_image_path="reference_dev_image_to_image_fill.png",
|
||||||
output_image_path="output_dev_image_to_image_result_inpaint.png",
|
output_image_path="output_dev_image_to_image_fill.png",
|
||||||
model_config=ModelConfig.dev_fill(),
|
model_config=ModelConfig.dev_fill(),
|
||||||
steps=15,
|
steps=15,
|
||||||
seed=42,
|
seed=42,
|
||||||
height=341,
|
height=341,
|
||||||
width=768,
|
width=768,
|
||||||
prompt="A burger and crispy golden french fries next to it",
|
prompt="A burger and crispy golden french fries next to it",
|
||||||
image_path=TestImageGeneratorFill.SOURCE_IMAGE_FILENAME,
|
image_path="reference_dev_image_to_image.png",
|
||||||
masked_image_path=TestImageGeneratorFill.MASK_IMAGE_FILENAME,
|
masked_image_path="mask.png",
|
||||||
)
|
)
|
||||||
|
|||||||
@ -6,8 +6,8 @@ from tests.image_generation.helpers.image_generation_in_context_test_helper impo
|
|||||||
class TestImageGeneratorInContext:
|
class TestImageGeneratorInContext:
|
||||||
def test_in_context_lora_identity(self):
|
def test_in_context_lora_identity(self):
|
||||||
ImageGeneratorInContextTestHelper.assert_matches_reference_image(
|
ImageGeneratorInContextTestHelper.assert_matches_reference_image(
|
||||||
reference_image_path="ic_lora_reference_in_context_identity.png",
|
reference_image_path="reference_ic_lora_identity.png",
|
||||||
output_image_path="output_ic_lora_reference_in_context_identity.png",
|
output_image_path="output_ic_lora_identity.png",
|
||||||
model_config=ModelConfig.dev(),
|
model_config=ModelConfig.dev(),
|
||||||
steps=25,
|
steps=25,
|
||||||
seed=42,
|
seed=42,
|
||||||
@ -20,7 +20,7 @@ class TestImageGeneratorInContext:
|
|||||||
|
|
||||||
def test_ic_edit_with_instruction(self):
|
def test_ic_edit_with_instruction(self):
|
||||||
ImageGeneratorICEditTestHelper.assert_matches_reference_image(
|
ImageGeneratorICEditTestHelper.assert_matches_reference_image(
|
||||||
reference_image_path="ic_edit_reference.png",
|
reference_image_path="reference_ic_edit.png",
|
||||||
output_image_path="output_ic_edit.png",
|
output_image_path="output_ic_edit.png",
|
||||||
steps=20,
|
steps=20,
|
||||||
seed=2799665,
|
seed=2799665,
|
||||||
|
|||||||
@ -3,8 +3,6 @@ from tests.image_generation.helpers.image_generation_redux_test_helper import Im
|
|||||||
|
|
||||||
|
|
||||||
class TestImageGeneratorRedux:
|
class TestImageGeneratorRedux:
|
||||||
SOURCE_IMAGE_FILENAME = "reference_dev_image_to_image_result.png"
|
|
||||||
|
|
||||||
def test_image_generation_redux(self):
|
def test_image_generation_redux(self):
|
||||||
ImageGeneratorReduxTestHelper.assert_matches_reference_image(
|
ImageGeneratorReduxTestHelper.assert_matches_reference_image(
|
||||||
reference_image_path="reference_redux_dev.png",
|
reference_image_path="reference_redux_dev.png",
|
||||||
@ -15,5 +13,5 @@ class TestImageGeneratorRedux:
|
|||||||
height=341,
|
height=341,
|
||||||
width=768,
|
width=768,
|
||||||
prompt="A delicious burger",
|
prompt="A delicious burger",
|
||||||
redux_image_path=TestImageGeneratorRedux.SOURCE_IMAGE_FILENAME,
|
redux_image_path="reference_dev_image_to_image.png",
|
||||||
)
|
)
|
||||||
|
|||||||
@ -6,8 +6,7 @@ from mflux.error.error import InvalidBaseModel, ModelConfigError
|
|||||||
|
|
||||||
def test_bfl_dev():
|
def test_bfl_dev():
|
||||||
model = ModelConfig.from_name("dev")
|
model = ModelConfig.from_name("dev")
|
||||||
assert model.alias == "dev"
|
assert model.model_name == "black-forest-labs/FLUX.1-dev"
|
||||||
assert model.model_name.startswith("black-forest-labs/")
|
|
||||||
assert model.max_sequence_length == 512
|
assert model.max_sequence_length == 512
|
||||||
assert model.num_train_steps == 1000
|
assert model.num_train_steps == 1000
|
||||||
assert model.supports_guidance is True
|
assert model.supports_guidance is True
|
||||||
@ -16,8 +15,34 @@ def test_bfl_dev():
|
|||||||
|
|
||||||
def test_bfl_dev_full_name():
|
def test_bfl_dev_full_name():
|
||||||
model = ModelConfig.from_name("black-forest-labs/FLUX.1-dev")
|
model = ModelConfig.from_name("black-forest-labs/FLUX.1-dev")
|
||||||
assert model.alias == "dev"
|
assert model.model_name == "black-forest-labs/FLUX.1-dev"
|
||||||
assert model.model_name.startswith("black-forest-labs/")
|
assert model.max_sequence_length == 512
|
||||||
|
assert model.num_train_steps == 1000
|
||||||
|
assert model.supports_guidance is True
|
||||||
|
assert model.requires_sigma_shift is True
|
||||||
|
|
||||||
|
|
||||||
|
def test_bfl_krea_dev():
|
||||||
|
model = ModelConfig.from_name("krea-dev")
|
||||||
|
assert model.model_name == "black-forest-labs/FLUX.1-Krea-dev"
|
||||||
|
assert model.max_sequence_length == 512
|
||||||
|
assert model.num_train_steps == 1000
|
||||||
|
assert model.supports_guidance is True
|
||||||
|
assert model.requires_sigma_shift is True
|
||||||
|
|
||||||
|
|
||||||
|
def test_bfl_dev_krea_alias():
|
||||||
|
model = ModelConfig.from_name("dev-krea")
|
||||||
|
assert model.model_name == "black-forest-labs/FLUX.1-Krea-dev"
|
||||||
|
assert model.max_sequence_length == 512
|
||||||
|
assert model.num_train_steps == 1000
|
||||||
|
assert model.supports_guidance is True
|
||||||
|
assert model.requires_sigma_shift is True
|
||||||
|
|
||||||
|
|
||||||
|
def test_bfl_krea_dev_full_name():
|
||||||
|
model = ModelConfig.from_name("black-forest-labs/FLUX.1-Krea-dev")
|
||||||
|
assert model.model_name == "black-forest-labs/FLUX.1-Krea-dev"
|
||||||
assert model.max_sequence_length == 512
|
assert model.max_sequence_length == 512
|
||||||
assert model.num_train_steps == 1000
|
assert model.num_train_steps == 1000
|
||||||
assert model.supports_guidance is True
|
assert model.supports_guidance is True
|
||||||
@ -26,8 +51,7 @@ def test_bfl_dev_full_name():
|
|||||||
|
|
||||||
def test_bfl_schnell():
|
def test_bfl_schnell():
|
||||||
model = ModelConfig.from_name("schnell")
|
model = ModelConfig.from_name("schnell")
|
||||||
assert model.alias == "schnell"
|
assert model.model_name == "black-forest-labs/FLUX.1-schnell"
|
||||||
assert model.model_name.startswith("black-forest-labs/")
|
|
||||||
assert model.max_sequence_length == 256
|
assert model.max_sequence_length == 256
|
||||||
assert model.num_train_steps == 1000
|
assert model.num_train_steps == 1000
|
||||||
assert model.supports_guidance is False
|
assert model.supports_guidance is False
|
||||||
@ -36,8 +60,7 @@ def test_bfl_schnell():
|
|||||||
|
|
||||||
def test_bfl_schnell_full_name():
|
def test_bfl_schnell_full_name():
|
||||||
model = ModelConfig.from_name("black-forest-labs/FLUX.1-schnell")
|
model = ModelConfig.from_name("black-forest-labs/FLUX.1-schnell")
|
||||||
assert model.alias == "schnell"
|
assert model.model_name == "black-forest-labs/FLUX.1-schnell"
|
||||||
assert model.model_name.startswith("black-forest-labs/")
|
|
||||||
assert model.max_sequence_length == 256
|
assert model.max_sequence_length == 256
|
||||||
assert model.num_train_steps == 1000
|
assert model.num_train_steps == 1000
|
||||||
assert model.supports_guidance is False
|
assert model.supports_guidance is False
|
||||||
@ -46,7 +69,6 @@ def test_bfl_schnell_full_name():
|
|||||||
|
|
||||||
def test_bfl_dev_fill():
|
def test_bfl_dev_fill():
|
||||||
model = ModelConfig.from_name("dev-fill")
|
model = ModelConfig.from_name("dev-fill")
|
||||||
assert model.alias == "dev-fill"
|
|
||||||
assert model.model_name == "black-forest-labs/FLUX.1-Fill-dev"
|
assert model.model_name == "black-forest-labs/FLUX.1-Fill-dev"
|
||||||
assert model.max_sequence_length == 512
|
assert model.max_sequence_length == 512
|
||||||
assert model.num_train_steps == 1000
|
assert model.num_train_steps == 1000
|
||||||
@ -56,7 +78,6 @@ def test_bfl_dev_fill():
|
|||||||
|
|
||||||
def test_bfl_dev_fill_full_name():
|
def test_bfl_dev_fill_full_name():
|
||||||
model = ModelConfig.from_name("black-forest-labs/FLUX.1-Fill-dev")
|
model = ModelConfig.from_name("black-forest-labs/FLUX.1-Fill-dev")
|
||||||
assert model.alias == "dev-fill"
|
|
||||||
assert model.model_name == "black-forest-labs/FLUX.1-Fill-dev"
|
assert model.model_name == "black-forest-labs/FLUX.1-Fill-dev"
|
||||||
assert model.max_sequence_length == 512
|
assert model.max_sequence_length == 512
|
||||||
assert model.num_train_steps == 1000
|
assert model.num_train_steps == 1000
|
||||||
@ -66,7 +87,6 @@ def test_bfl_dev_fill_full_name():
|
|||||||
|
|
||||||
def test_bfl_dev_depth():
|
def test_bfl_dev_depth():
|
||||||
model = ModelConfig.from_name("dev-depth")
|
model = ModelConfig.from_name("dev-depth")
|
||||||
assert model.alias == "dev-depth"
|
|
||||||
assert model.model_name == "black-forest-labs/FLUX.1-Depth-dev"
|
assert model.model_name == "black-forest-labs/FLUX.1-Depth-dev"
|
||||||
assert model.max_sequence_length == 512
|
assert model.max_sequence_length == 512
|
||||||
assert model.num_train_steps == 1000
|
assert model.num_train_steps == 1000
|
||||||
@ -76,7 +96,6 @@ def test_bfl_dev_depth():
|
|||||||
|
|
||||||
def test_bfl_dev_depth_full_name():
|
def test_bfl_dev_depth_full_name():
|
||||||
model = ModelConfig.from_name("black-forest-labs/FLUX.1-Depth-dev")
|
model = ModelConfig.from_name("black-forest-labs/FLUX.1-Depth-dev")
|
||||||
assert model.alias == "dev-depth"
|
|
||||||
assert model.model_name == "black-forest-labs/FLUX.1-Depth-dev"
|
assert model.model_name == "black-forest-labs/FLUX.1-Depth-dev"
|
||||||
assert model.max_sequence_length == 512
|
assert model.max_sequence_length == 512
|
||||||
assert model.num_train_steps == 1000
|
assert model.num_train_steps == 1000
|
||||||
@ -86,7 +105,6 @@ def test_bfl_dev_depth_full_name():
|
|||||||
|
|
||||||
def test_bfl_dev_redux():
|
def test_bfl_dev_redux():
|
||||||
model = ModelConfig.from_name("dev-redux")
|
model = ModelConfig.from_name("dev-redux")
|
||||||
assert model.alias == "dev-redux"
|
|
||||||
assert model.model_name == "black-forest-labs/FLUX.1-Redux-dev"
|
assert model.model_name == "black-forest-labs/FLUX.1-Redux-dev"
|
||||||
assert model.max_sequence_length == 512
|
assert model.max_sequence_length == 512
|
||||||
assert model.num_train_steps == 1000
|
assert model.num_train_steps == 1000
|
||||||
@ -96,7 +114,6 @@ def test_bfl_dev_redux():
|
|||||||
|
|
||||||
def test_bfl_dev_redux_full_name():
|
def test_bfl_dev_redux_full_name():
|
||||||
model = ModelConfig.from_name("black-forest-labs/FLUX.1-Redux-dev")
|
model = ModelConfig.from_name("black-forest-labs/FLUX.1-Redux-dev")
|
||||||
assert model.alias == "dev-redux"
|
|
||||||
assert model.model_name == "black-forest-labs/FLUX.1-Redux-dev"
|
assert model.model_name == "black-forest-labs/FLUX.1-Redux-dev"
|
||||||
assert model.max_sequence_length == 512
|
assert model.max_sequence_length == 512
|
||||||
assert model.num_train_steps == 1000
|
assert model.num_train_steps == 1000
|
||||||
@ -106,7 +123,6 @@ def test_bfl_dev_redux_full_name():
|
|||||||
|
|
||||||
def test_bfl_dev_controlnet_canny():
|
def test_bfl_dev_controlnet_canny():
|
||||||
model = ModelConfig.from_name("dev-controlnet-canny")
|
model = ModelConfig.from_name("dev-controlnet-canny")
|
||||||
assert model.alias == "dev-controlnet-canny"
|
|
||||||
assert model.model_name == "black-forest-labs/FLUX.1-dev"
|
assert model.model_name == "black-forest-labs/FLUX.1-dev"
|
||||||
assert model.controlnet_model == "InstantX/FLUX.1-dev-Controlnet-Canny"
|
assert model.controlnet_model == "InstantX/FLUX.1-dev-Controlnet-Canny"
|
||||||
assert model.max_sequence_length == 512
|
assert model.max_sequence_length == 512
|
||||||
@ -118,7 +134,6 @@ def test_bfl_dev_controlnet_canny():
|
|||||||
|
|
||||||
def test_bfl_schnell_controlnet_canny():
|
def test_bfl_schnell_controlnet_canny():
|
||||||
model = ModelConfig.from_name("schnell-controlnet-canny")
|
model = ModelConfig.from_name("schnell-controlnet-canny")
|
||||||
assert model.alias == "schnell-controlnet-canny"
|
|
||||||
assert model.model_name == "black-forest-labs/FLUX.1-schnell"
|
assert model.model_name == "black-forest-labs/FLUX.1-schnell"
|
||||||
assert model.controlnet_model == "InstantX/FLUX.1-dev-Controlnet-Canny"
|
assert model.controlnet_model == "InstantX/FLUX.1-dev-Controlnet-Canny"
|
||||||
assert model.max_sequence_length == 256
|
assert model.max_sequence_length == 256
|
||||||
@ -130,7 +145,6 @@ def test_bfl_schnell_controlnet_canny():
|
|||||||
|
|
||||||
def test_bfl_dev_controlnet_upscaler():
|
def test_bfl_dev_controlnet_upscaler():
|
||||||
model = ModelConfig.from_name("dev-controlnet-upscaler")
|
model = ModelConfig.from_name("dev-controlnet-upscaler")
|
||||||
assert model.alias == "dev-controlnet-upscaler"
|
|
||||||
assert model.model_name == "black-forest-labs/FLUX.1-dev"
|
assert model.model_name == "black-forest-labs/FLUX.1-dev"
|
||||||
assert model.controlnet_model == "jasperai/Flux.1-dev-Controlnet-Upscaler"
|
assert model.controlnet_model == "jasperai/Flux.1-dev-Controlnet-Upscaler"
|
||||||
assert model.max_sequence_length == 512
|
assert model.max_sequence_length == 512
|
||||||
@ -142,7 +156,7 @@ def test_bfl_dev_controlnet_upscaler():
|
|||||||
|
|
||||||
def test_community_dev_fill_implicit_base_model():
|
def test_community_dev_fill_implicit_base_model():
|
||||||
model = ModelConfig.from_name("acme-lab/some-dev-fill-model")
|
model = ModelConfig.from_name("acme-lab/some-dev-fill-model")
|
||||||
assert model.alias == "dev-fill"
|
assert model.base_model == "black-forest-labs/FLUX.1-Fill-dev"
|
||||||
assert model.max_sequence_length == 512
|
assert model.max_sequence_length == 512
|
||||||
assert model.num_train_steps == 1000
|
assert model.num_train_steps == 1000
|
||||||
assert model.supports_guidance is True
|
assert model.supports_guidance is True
|
||||||
@ -151,7 +165,7 @@ def test_community_dev_fill_implicit_base_model():
|
|||||||
|
|
||||||
def test_community_dev_fill_explicit_base_model():
|
def test_community_dev_fill_explicit_base_model():
|
||||||
model = ModelConfig.from_name("acme-lab/some-model", base_model="dev-fill")
|
model = ModelConfig.from_name("acme-lab/some-model", base_model="dev-fill")
|
||||||
assert model.alias == "dev-fill"
|
assert model.base_model == "black-forest-labs/FLUX.1-Fill-dev"
|
||||||
assert model.max_sequence_length == 512
|
assert model.max_sequence_length == 512
|
||||||
assert model.num_train_steps == 1000
|
assert model.num_train_steps == 1000
|
||||||
assert model.supports_guidance is True
|
assert model.supports_guidance is True
|
||||||
@ -160,7 +174,6 @@ def test_community_dev_fill_explicit_base_model():
|
|||||||
|
|
||||||
def test_implicit_base_model_prefers_dev_fill_over_dev():
|
def test_implicit_base_model_prefers_dev_fill_over_dev():
|
||||||
model = ModelConfig.from_name("acme-lab/dev-fill-based-model")
|
model = ModelConfig.from_name("acme-lab/dev-fill-based-model")
|
||||||
assert model.alias == "dev-fill"
|
|
||||||
assert model.base_model == "black-forest-labs/FLUX.1-Fill-dev"
|
assert model.base_model == "black-forest-labs/FLUX.1-Fill-dev"
|
||||||
assert model.max_sequence_length == 512
|
assert model.max_sequence_length == 512
|
||||||
assert model.num_train_steps == 1000
|
assert model.num_train_steps == 1000
|
||||||
@ -169,7 +182,7 @@ def test_implicit_base_model_prefers_dev_fill_over_dev():
|
|||||||
|
|
||||||
def test_community_dev_implicit_base_model():
|
def test_community_dev_implicit_base_model():
|
||||||
model = ModelConfig.from_name("acme-lab/some-awesome-dev-model")
|
model = ModelConfig.from_name("acme-lab/some-awesome-dev-model")
|
||||||
assert model.alias == "dev"
|
assert model.base_model == "black-forest-labs/FLUX.1-dev"
|
||||||
assert model.max_sequence_length == 512
|
assert model.max_sequence_length == 512
|
||||||
assert model.num_train_steps == 1000
|
assert model.num_train_steps == 1000
|
||||||
assert model.supports_guidance is True
|
assert model.supports_guidance is True
|
||||||
@ -178,7 +191,7 @@ def test_community_dev_implicit_base_model():
|
|||||||
|
|
||||||
def test_community_schnell_implicit_base_model():
|
def test_community_schnell_implicit_base_model():
|
||||||
model = ModelConfig.from_name("acme-lab/some-quick-schnell-model")
|
model = ModelConfig.from_name("acme-lab/some-quick-schnell-model")
|
||||||
assert model.alias == "schnell"
|
assert model.base_model == "black-forest-labs/FLUX.1-schnell"
|
||||||
assert model.max_sequence_length == 256
|
assert model.max_sequence_length == 256
|
||||||
assert model.num_train_steps == 1000
|
assert model.num_train_steps == 1000
|
||||||
assert model.supports_guidance is False
|
assert model.supports_guidance is False
|
||||||
@ -187,7 +200,6 @@ def test_community_schnell_implicit_base_model():
|
|||||||
|
|
||||||
def test_community_dev_explicit_base_model():
|
def test_community_dev_explicit_base_model():
|
||||||
model = ModelConfig.from_name("acme-lab/some-awesome-model", base_model="dev")
|
model = ModelConfig.from_name("acme-lab/some-awesome-model", base_model="dev")
|
||||||
assert model.alias == "dev"
|
|
||||||
assert model.base_model == "black-forest-labs/FLUX.1-dev"
|
assert model.base_model == "black-forest-labs/FLUX.1-dev"
|
||||||
assert model.max_sequence_length == 512
|
assert model.max_sequence_length == 512
|
||||||
assert model.num_train_steps == 1000
|
assert model.num_train_steps == 1000
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 168 KiB |
|
Before Width: | Height: | Size: 76 KiB |
|
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 3.7 KiB |
|
Before Width: | Height: | Size: 5.2 KiB After Width: | Height: | Size: 5.2 KiB |
|
Before Width: | Height: | Size: 411 KiB After Width: | Height: | Size: 412 KiB |
|
Before Width: | Height: | Size: 483 KiB After Width: | Height: | Size: 482 KiB |
|
Before Width: | Height: | Size: 46 KiB After Width: | Height: | Size: 46 KiB |
|
Before Width: | Height: | Size: 271 KiB After Width: | Height: | Size: 271 KiB |
|
Before Width: | Height: | Size: 242 KiB After Width: | Height: | Size: 241 KiB |
|
Before Width: | Height: | Size: 365 KiB After Width: | Height: | Size: 365 KiB |
BIN
tests/resources/reference_dev_image_to_image.png
Normal file
|
After Width: | Height: | Size: 354 KiB |
BIN
tests/resources/reference_dev_image_to_image_fill.png
Normal file
|
After Width: | Height: | Size: 364 KiB |
|
Before Width: | Height: | Size: 354 KiB |
|
Before Width: | Height: | Size: 365 KiB |
|
Before Width: | Height: | Size: 272 KiB After Width: | Height: | Size: 273 KiB |
|
Before Width: | Height: | Size: 377 KiB After Width: | Height: | Size: 378 KiB |
|
Before Width: | Height: | Size: 446 KiB After Width: | Height: | Size: 446 KiB |
BIN
tests/resources/reference_ic_edit.png
Normal file
|
After Width: | Height: | Size: 170 KiB |
BIN
tests/resources/reference_ic_lora_identity.png
Normal file
|
After Width: | Height: | Size: 75 KiB |
|
Before Width: | Height: | Size: 338 KiB After Width: | Height: | Size: 340 KiB |
|
Before Width: | Height: | Size: 395 KiB After Width: | Height: | Size: 396 KiB |
|
Before Width: | Height: | Size: 267 KiB After Width: | Height: | Size: 268 KiB |
53
uv.lock
generated
@ -712,7 +712,7 @@ wheels = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "mflux"
|
name = "mflux"
|
||||||
version = "0.9.6"
|
version = "0.10.0"
|
||||||
source = { editable = "." }
|
source = { editable = "." }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "huggingface-hub" },
|
{ name = "huggingface-hub" },
|
||||||
@ -746,8 +746,8 @@ dev = [
|
|||||||
requires-dist = [
|
requires-dist = [
|
||||||
{ name = "huggingface-hub", specifier = ">=0.24.5,<1.0" },
|
{ name = "huggingface-hub", specifier = ">=0.24.5,<1.0" },
|
||||||
{ name = "matplotlib", specifier = ">=3.9.2,<4.0" },
|
{ name = "matplotlib", specifier = ">=3.9.2,<4.0" },
|
||||||
{ name = "mlx", specifier = ">=0.22.0,<=0.26.1" },
|
{ name = "mlx", specifier = ">=0.27.0,<0.28.0" },
|
||||||
{ name = "mlx", marker = "extra == 'dev'", specifier = "==0.26.1" },
|
{ name = "mlx", marker = "extra == 'dev'", specifier = "==0.27.1" },
|
||||||
{ name = "numpy", specifier = ">=2.0.1,<3.0" },
|
{ name = "numpy", specifier = ">=2.0.1,<3.0" },
|
||||||
{ name = "opencv-python", specifier = ">=4.10.0,<5.0" },
|
{ name = "opencv-python", specifier = ">=4.10.0,<5.0" },
|
||||||
{ name = "piexif", specifier = ">=1.1.3,<2.0" },
|
{ name = "piexif", specifier = ">=1.1.3,<2.0" },
|
||||||
@ -770,25 +770,38 @@ provides-extras = ["dev"]
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "mlx"
|
name = "mlx"
|
||||||
version = "0.26.1"
|
version = "0.27.1"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "mlx-metal", marker = "sys_platform == 'darwin'" },
|
||||||
|
]
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c9/ed/07a7145c500914ed8ab704a7a3828a5134e85f8b4458e1fee887306867d6/mlx-0.27.1-cp310-cp310-macosx_13_0_arm64.whl", hash = "sha256:a033b65fe46425ad5032867d5a71a556a5168108d89aa7092b457556c70d84fc", size = 557679, upload-time = "2025-07-25T22:55:31.942Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/aa/ae/b3e46904ea04b5badb77195169880733f09976a3dfc81c954b99f9adbbc4/mlx-0.27.1-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:2836c6fd9803dc0c6cd06f204e31b3e0191e6c5b6bc8570b28661d926908cba3", size = 530556, upload-time = "2025-07-25T22:56:13.171Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/6e/24/85f5a7dfcf0b4974aa43a2f6dc0d59dfc04e4a1051aacebd7e7810b823ff/mlx-0.27.1-cp310-cp310-macosx_15_0_arm64.whl", hash = "sha256:8b0566054c46d84c470cc99cda2afc3914ad6c7808fbb724dc1ec235e5b2a98c", size = 530559, upload-time = "2025-07-25T22:55:39.055Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/14/bd/91ad900837a3760ba056863c1350f0deabc3e462c3999b4d5ea875368177/mlx-0.27.1-cp310-cp310-manylinux_2_35_x86_64.whl", hash = "sha256:91ef93ce09900c9a8ca662cf34e3c39ab5af2762822ecd6b12fecae518be167f", size = 628183, upload-time = "2025-07-25T22:58:11.553Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ac/63/88cb9a5019bea21244385eacc4c64deb4d074a8bc3b4b6d2d97cdacf97a2/mlx-0.27.1-cp311-cp311-macosx_13_0_arm64.whl", hash = "sha256:d2e5dedbfbcbe558e51a5c476ca6a18e307676f9e49854eb27e53778bc474699", size = 557582, upload-time = "2025-07-25T22:55:22.243Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/fa/87/c2d7343e7b054481c52e23a190911c40aed4f8c77a8dfeda1f48d5cb520a/mlx-0.27.1-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:9f04b9778897a879c9ca22e5413dfa1efc192d86d7211b184e079efec49dfb8b", size = 530820, upload-time = "2025-07-25T22:55:34.121Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/06/bf/20497ca7411028baa56372c20e94a3eaddac973155b415f08fc12592c2cf/mlx-0.27.1-cp311-cp311-macosx_15_0_arm64.whl", hash = "sha256:01d794f9e390438ab4f942a18d9a8ca65bef10c2c2007ef38ca988d039d6d9d3", size = 530821, upload-time = "2025-07-25T22:55:28.847Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/48/68/234a0d846576502ea1bf8ea478c764d87eec9042349e298d2aea58c4e8e9/mlx-0.27.1-cp311-cp311-manylinux_2_35_x86_64.whl", hash = "sha256:fae11432d0639789f1e172b19b35ac8987c8ab9716e55a23fc7a170d6545fc33", size = 628500, upload-time = "2025-07-25T22:57:59.556Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/65/43/125102bbb2be6825880ae2dc8d8702f99cfa7753407f574457b36e422218/mlx-0.27.1-cp312-cp312-macosx_13_0_arm64.whl", hash = "sha256:0c570c9afb57c697bd864504115be8a7c4de97f0b80557a597d496ee426a6812", size = 549869, upload-time = "2025-07-25T22:55:32.698Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f3/79/0bf681700fc8b165517e907f9ec777b5a5d628004a65a777148f68c6baa0/mlx-0.27.1-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:ccff7bbbd9df302b26e79013ef6d0c3531c9ba5963ead521e2d85856811b86a0", size = 531671, upload-time = "2025-07-25T22:57:03.392Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ec/97/f1367b4892bef7f78e38737d3a28094e93124f11684a28a9e92ed5a13b2b/mlx-0.27.1-cp312-cp312-macosx_15_0_arm64.whl", hash = "sha256:9ccadaed449c07dfeae484620992b904c17dfea7564f8df63095c60eed3af02b", size = 531672, upload-time = "2025-07-25T22:55:35.779Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/9c/0f/3ebec0806ed2c5ba8ba151394cd62a46b4d83ea347da33af91b86d8969d4/mlx-0.27.1-cp312-cp312-manylinux_2_35_x86_64.whl", hash = "sha256:742c413e75605b71db69379a176da63e32ba19b9e9ad03b8763adbd1fcfcd394", size = 621661, upload-time = "2025-07-25T22:58:00.96Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/86/f6/4324386b0764deb692e14a97282a348a9a938aa8b441bf8b6c7599f418d4/mlx-0.27.1-cp313-cp313-macosx_13_0_arm64.whl", hash = "sha256:803669a28031766c2b0fe94c0a3bfd030184e706092f0a831b33620c1e2ef865", size = 549847, upload-time = "2025-07-25T22:55:17.581Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/cf/4b/3194ccb03527a050c04d837d731a11599f8620e6ce16d3971798caae1d44/mlx-0.27.1-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:e9649b3d86ce564000797384510c9d07af38a9ce2a07df8e2f7c6a3e0f0f059e", size = 531664, upload-time = "2025-07-25T22:56:02.928Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/cc/57/a6e0d8dc6e7ba08a64d71fb89d743e77446040113ea1dbb7950be8f60f39/mlx-0.27.1-cp313-cp313-macosx_15_0_arm64.whl", hash = "sha256:5c501ceec7c6aa2ea1c850dd4e14e679f5416a142264b9d5d405a4e0aeb991b2", size = 531663, upload-time = "2025-07-25T22:55:38.62Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/48/96/6932e0fa866d08cdf77a3fc37cf624e4cac8960d2e297c3fd80afb49417d/mlx-0.27.1-cp313-cp313-manylinux_2_35_x86_64.whl", hash = "sha256:42bfbabdcd0b7aa1c94748c8963e66680a3cf3f599b01036db14e496bf276eb8", size = 621609, upload-time = "2025-07-25T22:58:21.477Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "mlx-metal"
|
||||||
|
version = "0.27.1"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/91/9d/645600137d0b7d4689e081de1c62247dae448dfadd8ebdac0fea8c70da33/mlx-0.26.1-cp310-cp310-macosx_13_0_arm64.whl", hash = "sha256:8f88900eaef76f8f23e957ef303f3664c273c73a504b4e57bb491e397d7a891e", size = 32399627, upload-time = "2025-06-04T01:02:30.075Z" },
|
{ url = "https://files.pythonhosted.org/packages/8b/77/89fa3327011f018638c9e943e1edc081ce9ca0ed296fe64d6daf93c6ff51/mlx_metal-0.27.1-py3-none-macosx_13_0_arm64.whl", hash = "sha256:c66d9b1adb3c0ea19492fba6493f672bc7542e65dd65f7e2995918815fbeb907", size = 33523035, upload-time = "2025-07-25T22:58:02.533Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/50/8c/132c081c62ff3352f62bd25c9fc4f654d959402ff94de7c269b53479978d/mlx-0.26.1-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:794b52f2ae52969aac8fa5c271f55a668c0f802cbacda70652033db9c11887c6", size = 31869876, upload-time = "2025-06-04T01:03:04.508Z" },
|
{ url = "https://files.pythonhosted.org/packages/d7/a8/ac706ad6ce834834762d5146d791f77710efc896c13ef47fd7d672099056/mlx_metal-0.27.1-py3-none-macosx_14_0_arm64.whl", hash = "sha256:fe4415ddd242974d91c7ca0699cd01507d17da8a5ba304122ef137cdb5e7fff4", size = 32926383, upload-time = "2025-07-25T22:57:54.194Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/1e/11/eba1bdbaa82b6178887ff22eeae5ab90ef6de73e5fdd518753b808bbbc21/mlx-0.26.1-cp310-cp310-macosx_15_0_arm64.whl", hash = "sha256:030b79376da1564d21af24ecfaa4e049bad823adfd7572376e1f81bd0f08af90", size = 31870531, upload-time = "2025-06-04T01:03:15.67Z" },
|
{ url = "https://files.pythonhosted.org/packages/78/77/6963681fb54ecaa0ae5de4209c15504a803a0edd1a33fd074e6c558fd5e0/mlx_metal-0.27.1-py3-none-macosx_15_0_arm64.whl", hash = "sha256:d025dea30bda8baa32c928cfa333eac64a5adc8d07656f8fc55072d99403ebc9", size = 32897065, upload-time = "2025-07-25T22:58:26.362Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/8d/3a/415cf516daa5cc6f95ac953d894346fc69c013f0c2348665223b130fccab/mlx-0.26.1-cp310-cp310-manylinux_2_31_x86_64.whl", hash = "sha256:70a286a1e9a5e9fb69914e552e563a8de33963a24496c8b69f3c084a88e7ef90", size = 10125716, upload-time = "2025-06-06T23:08:07.886Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/63/93/97c0a149cba1ad3fbfb01be4c6b293b4cb9d11e41d4b54735048e3d671bd/mlx-0.26.1-cp311-cp311-macosx_13_0_arm64.whl", hash = "sha256:1973b46817db50328fe8f74b2faa860e761eb08f4230461bb299057a411c070b", size = 32399548, upload-time = "2025-06-04T01:02:34.868Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/1d/4f/3d3b52f0040462ab53d66d65eefd062f577feb0647ec3aa916faa7f0282b/mlx-0.26.1-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:478abbe1de49cb1409a38c263bafe45e70e3c5b6cbefd4fc3f5c5b7db90d2908", size = 31870277, upload-time = "2025-06-04T01:01:29.932Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/80/75/ea19b3f1e9db337a8ef5ceded8f95ae0ed636c66ab40473c6d9eaad5ce01/mlx-0.26.1-cp311-cp311-macosx_15_0_arm64.whl", hash = "sha256:8d76d75d652f252f7887acebc6d1ef5d3aec16e72673332895584f1617c35151", size = 31871009, upload-time = "2025-06-04T01:03:09.963Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/72/a7/b4611911540e15ffd5c5b039ff4a83f43ef64a7ebc51df499b4456815470/mlx-0.26.1-cp311-cp311-manylinux_2_31_x86_64.whl", hash = "sha256:1cedf67d32d21e23e1639116cc24b62b6cc95a5f3bb0aa0ad6833e2910eb802c", size = 10125854, upload-time = "2025-06-06T23:07:39.23Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/73/3e/a099ca333bd9cd313c7792a18ad4dfc47b051957ba24edd59f3bcda87d8c/mlx-0.26.1-cp312-cp312-macosx_13_0_arm64.whl", hash = "sha256:ebcc19c01d90b16462c8ff4255b00837bf45ce149d207170d95770b6699cc5ce", size = 32396393, upload-time = "2025-06-04T01:02:40.689Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/d1/e0/91707351c0becd33c477a1eba1a0fc124b3838cc65e3d2bd06dfa0a0533e/mlx-0.26.1-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:5eea5e025655a2b07c1573602e705013bd6d3ebdf432c39eb8eb29628c6df5a7", size = 31871294, upload-time = "2025-06-04T01:01:14.326Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/8d/e6/d5759fb20faceac183cfd45ede5fa0484f972eecfa2a851f8dd24aa4ace2/mlx-0.26.1-cp312-cp312-macosx_15_0_arm64.whl", hash = "sha256:3b93e1e2375222a7b0f65b4be3c4010855db2ee8c40cc39f8bf2820ff1652b06", size = 31871854, upload-time = "2025-06-04T01:03:14.003Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/e0/98/a95ca1dfb3721d3dbdd197ab17e3bb79b695bf426e37939d71d24cca19ce/mlx-0.26.1-cp312-cp312-manylinux_2_31_x86_64.whl", hash = "sha256:07f2fdb11b908156a65823ed062682cad0b03325a4f11fb9a36ce5acfe7475e5", size = 10120549, upload-time = "2025-06-06T23:07:43.068Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/a2/a7/871c451fe81274d37022a62f825c1dcd22b30e1f8bd2241f91d9f508c9b9/mlx-0.26.1-cp313-cp313-macosx_13_0_arm64.whl", hash = "sha256:ccd8662abad0f1340326412d6051c116fcb5c923c4d2a25ba1277ae65ab140dd", size = 32396333, upload-time = "2025-06-04T01:02:29.963Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/82/77/720bea5a67934b50372dfd5043864458f103743edcc7c30049e788ea3762/mlx-0.26.1-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:0c113dd7c7ac13af6e39f0132d33a8dc78928e858ba8d18f8c89f8bfa694a358", size = 31871172, upload-time = "2025-06-04T01:03:05.075Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/15/4f/83f67bc4fe012dffffd2d96d2767b83fee9b2d7d185611d554ac659cfa4d/mlx-0.26.1-cp313-cp313-macosx_15_0_arm64.whl", hash = "sha256:2ec37131dbb06c0be78ce56b1731ddab6e56183012e7b83bea79b5329ef7d695", size = 31871791, upload-time = "2025-06-04T01:03:15.384Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/4f/fb/4123952002fd91f096ba07ce797b6bb6a32cc7a89c988565e261559f77dd/mlx-0.26.1-cp313-cp313-manylinux_2_31_x86_64.whl", hash = "sha256:db96a53466d8efc6cf2a2918b2d4e29cbf9f25174c838fb3c380c8717a40752f", size = 10120515, upload-time = "2025-06-06T23:07:38.428Z" },
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|||||||