inline-core 1.2.3__tar.gz → 1.2.6__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {inline_core-1.2.3 → inline_core-1.2.6}/CLAUDE.md +33 -4
- {inline_core-1.2.3 → inline_core-1.2.6}/PKG-INFO +60 -19
- {inline_core-1.2.3 → inline_core-1.2.6}/README.md +37 -16
- {inline_core-1.2.3 → inline_core-1.2.6}/pyproject.toml +42 -6
- inline_core-1.2.6/src/inline_core/__init__.py +14 -0
- {inline_core-1.2.3 → inline_core-1.2.6}/src/inline_core/device/memory.py +16 -4
- {inline_core-1.2.3 → inline_core-1.2.6}/src/inline_core/device/policy.py +5 -1
- inline_core-1.2.6/src/inline_core/ffmpeg.py +30 -0
- {inline_core-1.2.3 → inline_core-1.2.6}/src/inline_core/graph/cache.py +35 -2
- {inline_core-1.2.3 → inline_core-1.2.6}/src/inline_core/graph/executor.py +16 -4
- {inline_core-1.2.3 → inline_core-1.2.6}/src/inline_core/graph/loader_runners.py +32 -1
- {inline_core-1.2.3 → inline_core-1.2.6}/src/inline_core/graph/primitives.py +16 -1
- {inline_core-1.2.3 → inline_core-1.2.6}/src/inline_core/graph/schema.py +6 -1
- {inline_core-1.2.3 → inline_core-1.2.6}/src/inline_core/models/catalog.py +21 -0
- inline_core-1.2.6/src/inline_core/models/checkpoint.py +92 -0
- inline_core-1.2.6/src/inline_core/models/controlspace.py +26 -0
- inline_core-1.2.6/src/inline_core/models/flux2/__init__.py +1 -0
- inline_core-1.2.6/src/inline_core/models/flux2/controlnet.py +234 -0
- inline_core-1.2.6/src/inline_core/models/flux2/embeds.py +165 -0
- inline_core-1.2.6/src/inline_core/models/flux2/provider.py +84 -0
- inline_core-1.2.6/src/inline_core/models/flux2/requirements.py +414 -0
- inline_core-1.2.6/src/inline_core/models/flux2/runner.py +677 -0
- inline_core-1.2.6/src/inline_core/models/flux2/variants.py +334 -0
- inline_core-1.2.6/src/inline_core/models/krea2/__init__.py +9 -0
- inline_core-1.2.6/src/inline_core/models/krea2/convert.py +138 -0
- inline_core-1.2.6/src/inline_core/models/krea2/depth_control.py +149 -0
- inline_core-1.2.6/src/inline_core/models/krea2/img2img.py +89 -0
- inline_core-1.2.6/src/inline_core/models/krea2/provider.py +68 -0
- inline_core-1.2.6/src/inline_core/models/krea2/requirements.py +254 -0
- inline_core-1.2.6/src/inline_core/models/krea2/runner.py +466 -0
- inline_core-1.2.6/src/inline_core/models/loaders.py +1385 -0
- inline_core-1.2.6/src/inline_core/models/lora.py +190 -0
- inline_core-1.2.6/src/inline_core/models/pipeline_runtime.py +563 -0
- inline_core-1.2.6/src/inline_core/models/preprocess/__init__.py +5 -0
- inline_core-1.2.6/src/inline_core/models/preprocess/requirements.py +59 -0
- inline_core-1.2.6/src/inline_core/models/preprocess/runner.py +174 -0
- {inline_core-1.2.3 → inline_core-1.2.6}/src/inline_core/models/requirements.py +47 -0
- {inline_core-1.2.3 → inline_core-1.2.6}/src/inline_core/models/zimage/provider.py +12 -0
- {inline_core-1.2.3 → inline_core-1.2.6}/src/inline_core/models/zimage/requirements.py +90 -4
- inline_core-1.2.6/src/inline_core/models/zimage/runner.py +529 -0
- {inline_core-1.2.3 → inline_core-1.2.6}/src/inline_core/server/app.py +39 -4
- {inline_core-1.2.3 → inline_core-1.2.6}/src/inline_core/server/bootstrap.py +35 -0
- {inline_core-1.2.3 → inline_core-1.2.6}/src/inline_core/server/rpc.py +5 -0
- {inline_core-1.2.3 → inline_core-1.2.6}/src/inline_core/server/serialize.py +28 -4
- {inline_core-1.2.3 → inline_core-1.2.6}/src/inline_core/studio/fal.py +43 -5
- {inline_core-1.2.3 → inline_core-1.2.6}/src/inline_core/studio/frames.py +44 -18
- {inline_core-1.2.3 → inline_core-1.2.6}/src/inline_core/studio/generation.py +38 -8
- inline_core-1.2.6/src/inline_core/studio/graph_build.py +326 -0
- {inline_core-1.2.3 → inline_core-1.2.6}/src/inline_core/studio/handlers.py +82 -8
- inline_core-1.2.6/src/inline_core/studio/image_meta.py +36 -0
- {inline_core-1.2.3 → inline_core-1.2.6}/src/inline_core/studio/models.py +6 -2
- {inline_core-1.2.3 → inline_core-1.2.6}/src/inline_core/studio/moodboard.py +157 -25
- inline_core-1.2.6/src/inline_core/studio/recipe.py +109 -0
- {inline_core-1.2.3 → inline_core-1.2.6}/src/inline_core/studio/schema.py +66 -4
- inline_core-1.2.6/src/inline_core/studio/system_stats.py +92 -0
- inline_core-1.2.6/src/inline_core/studio/training.py +485 -0
- inline_core-1.2.6/src/inline_core/studio/training_store.py +274 -0
- inline_core-1.2.6/src/inline_core/training/__init__.py +10 -0
- inline_core-1.2.6/src/inline_core/training/__main__.py +74 -0
- inline_core-1.2.6/src/inline_core/training/arch.py +287 -0
- inline_core-1.2.6/src/inline_core/training/caption.py +160 -0
- inline_core-1.2.6/src/inline_core/training/dataset.py +209 -0
- inline_core-1.2.6/src/inline_core/training/models.py +418 -0
- inline_core-1.2.6/src/inline_core/training/protocol.py +56 -0
- inline_core-1.2.6/src/inline_core/training/trainer.py +261 -0
- {inline_core-1.2.3 → inline_core-1.2.6}/tests/helpers.py +1 -0
- inline_core-1.2.6/tests/test_cache.py +116 -0
- inline_core-1.2.6/tests/test_checkpoint.py +79 -0
- {inline_core-1.2.3 → inline_core-1.2.6}/tests/test_executor.py +26 -1
- inline_core-1.2.6/tests/test_flux2_controlnet.py +159 -0
- inline_core-1.2.6/tests/test_flux2_folder.py +179 -0
- inline_core-1.2.6/tests/test_flux2_resolve.py +176 -0
- inline_core-1.2.6/tests/test_flux2_runner.py +126 -0
- inline_core-1.2.6/tests/test_flux2_training.py +199 -0
- inline_core-1.2.6/tests/test_flux2_variants.py +129 -0
- inline_core-1.2.6/tests/test_krea2_convert.py +157 -0
- inline_core-1.2.6/tests/test_krea2_depth_control.py +104 -0
- inline_core-1.2.6/tests/test_krea2_requirements.py +148 -0
- inline_core-1.2.6/tests/test_krea2_runner.py +164 -0
- {inline_core-1.2.3 → inline_core-1.2.6}/tests/test_loaders.py +50 -3
- inline_core-1.2.6/tests/test_lora.py +218 -0
- inline_core-1.2.6/tests/test_lora_download.py +75 -0
- {inline_core-1.2.3 → inline_core-1.2.6}/tests/test_memory_policy.py +39 -0
- {inline_core-1.2.3 → inline_core-1.2.6}/tests/test_model_requirements.py +25 -0
- inline_core-1.2.6/tests/test_pipeline_cache.py +82 -0
- inline_core-1.2.6/tests/test_recipe.py +100 -0
- {inline_core-1.2.3 → inline_core-1.2.6}/tests/test_studio_fal.py +46 -0
- {inline_core-1.2.3 → inline_core-1.2.6}/tests/test_studio_generation.py +41 -3
- inline_core-1.2.6/tests/test_studio_graph_build.py +111 -0
- {inline_core-1.2.3 → inline_core-1.2.6}/tests/test_studio_models.py +20 -0
- inline_core-1.2.6/tests/test_studio_multi_reference.py +163 -0
- inline_core-1.2.6/tests/test_studio_node_size.py +58 -0
- {inline_core-1.2.3 → inline_core-1.2.6}/tests/test_studio_rpc.py +16 -0
- {inline_core-1.2.3 → inline_core-1.2.6}/tests/test_studio_schema.py +19 -0
- inline_core-1.2.6/tests/test_studio_training.py +81 -0
- inline_core-1.2.6/tests/test_training_arch.py +113 -0
- inline_core-1.2.6/tests/test_training_dataset.py +103 -0
- inline_core-1.2.6/tests/test_training_models.py +135 -0
- inline_core-1.2.6/tests/test_training_resolve.py +90 -0
- inline_core-1.2.6/tests/test_webui_install.py +154 -0
- {inline_core-1.2.3 → inline_core-1.2.6}/tests/test_zimage_resolve.py +6 -2
- {inline_core-1.2.3 → inline_core-1.2.6}/tests/test_zimage_runner.py +128 -29
- {inline_core-1.2.3 → inline_core-1.2.6}/uv.lock +387 -4
- inline_core-1.2.6/webui.bat +319 -0
- {inline_core-1.2.3 → inline_core-1.2.6}/webui.sh +97 -19
- inline_core-1.2.3/src/inline_core/__init__.py +0 -7
- inline_core-1.2.3/src/inline_core/models/loaders.py +0 -471
- inline_core-1.2.3/src/inline_core/models/zimage/runner.py +0 -945
- inline_core-1.2.3/src/inline_core/studio/graph_build.py +0 -141
- inline_core-1.2.3/tests/test_cache.py +0 -48
- {inline_core-1.2.3 → inline_core-1.2.6}/.gitignore +0 -0
- {inline_core-1.2.3 → inline_core-1.2.6}/.python-version +0 -0
- {inline_core-1.2.3 → inline_core-1.2.6}/main.py +0 -0
- {inline_core-1.2.3 → inline_core-1.2.6}/scripts/reference.py +0 -0
- {inline_core-1.2.3 → inline_core-1.2.6}/src/inline_core/components/__init__.py +0 -0
- {inline_core-1.2.3 → inline_core-1.2.6}/src/inline_core/components/conditioning.py +0 -0
- {inline_core-1.2.3 → inline_core-1.2.6}/src/inline_core/components/interfaces.py +0 -0
- {inline_core-1.2.3 → inline_core-1.2.6}/src/inline_core/config.py +0 -0
- {inline_core-1.2.3 → inline_core-1.2.6}/src/inline_core/device/__init__.py +0 -0
- {inline_core-1.2.3 → inline_core-1.2.6}/src/inline_core/device/auto.py +0 -0
- {inline_core-1.2.3 → inline_core-1.2.6}/src/inline_core/device/detect.py +0 -0
- {inline_core-1.2.3 → inline_core-1.2.6}/src/inline_core/device/types.py +0 -0
- {inline_core-1.2.3 → inline_core-1.2.6}/src/inline_core/errors.py +0 -0
- {inline_core-1.2.3 → inline_core-1.2.6}/src/inline_core/extensions/__init__.py +0 -0
- {inline_core-1.2.3 → inline_core-1.2.6}/src/inline_core/extensions/api.py +0 -0
- {inline_core-1.2.3 → inline_core-1.2.6}/src/inline_core/extensions/constraints.py +0 -0
- {inline_core-1.2.3 → inline_core-1.2.6}/src/inline_core/extensions/fetch.py +0 -0
- {inline_core-1.2.3 → inline_core-1.2.6}/src/inline_core/extensions/handlers.py +0 -0
- {inline_core-1.2.3 → inline_core-1.2.6}/src/inline_core/extensions/importer.py +0 -0
- {inline_core-1.2.3 → inline_core-1.2.6}/src/inline_core/extensions/install.py +0 -0
- {inline_core-1.2.3 → inline_core-1.2.6}/src/inline_core/extensions/loader.py +0 -0
- {inline_core-1.2.3 → inline_core-1.2.6}/src/inline_core/extensions/manifest.py +0 -0
- {inline_core-1.2.3 → inline_core-1.2.6}/src/inline_core/extensions/models.py +0 -0
- {inline_core-1.2.3 → inline_core-1.2.6}/src/inline_core/extensions/paths.py +0 -0
- {inline_core-1.2.3 → inline_core-1.2.6}/src/inline_core/extensions/resolve.py +0 -0
- {inline_core-1.2.3 → inline_core-1.2.6}/src/inline_core/extensions/scanner.py +0 -0
- {inline_core-1.2.3 → inline_core-1.2.6}/src/inline_core/extensions/state.py +0 -0
- {inline_core-1.2.3 → inline_core-1.2.6}/src/inline_core/extensions/tools.py +0 -0
- {inline_core-1.2.3 → inline_core-1.2.6}/src/inline_core/graph/__init__.py +0 -0
- {inline_core-1.2.3 → inline_core-1.2.6}/src/inline_core/graph/descriptor.py +0 -0
- {inline_core-1.2.3 → inline_core-1.2.6}/src/inline_core/graph/registry.py +0 -0
- {inline_core-1.2.3 → inline_core-1.2.6}/src/inline_core/graph/runners.py +0 -0
- {inline_core-1.2.3 → inline_core-1.2.6}/src/inline_core/graph/topo.py +0 -0
- {inline_core-1.2.3 → inline_core-1.2.6}/src/inline_core/graph/validate.py +0 -0
- {inline_core-1.2.3 → inline_core-1.2.6}/src/inline_core/media.py +0 -0
- {inline_core-1.2.3 → inline_core-1.2.6}/src/inline_core/models/__init__.py +0 -0
- {inline_core-1.2.3 → inline_core-1.2.6}/src/inline_core/models/sampling.py +0 -0
- {inline_core-1.2.3 → inline_core-1.2.6}/src/inline_core/models/zimage/__init__.py +0 -0
- {inline_core-1.2.3 → inline_core-1.2.6}/src/inline_core/models/zimage/primitives.py +0 -0
- {inline_core-1.2.3 → inline_core-1.2.6}/src/inline_core/parallel/__init__.py +0 -0
- {inline_core-1.2.3 → inline_core-1.2.6}/src/inline_core/parallel/config.py +0 -0
- {inline_core-1.2.3 → inline_core-1.2.6}/src/inline_core/parallel/group.py +0 -0
- {inline_core-1.2.3 → inline_core-1.2.6}/src/inline_core/parallel/launch.py +0 -0
- {inline_core-1.2.3 → inline_core-1.2.6}/src/inline_core/parallel/protocol.py +0 -0
- {inline_core-1.2.3 → inline_core-1.2.6}/src/inline_core/parallel/registry.py +0 -0
- {inline_core-1.2.3 → inline_core-1.2.6}/src/inline_core/parallel/worker.py +0 -0
- {inline_core-1.2.3 → inline_core-1.2.6}/src/inline_core/runtime/__init__.py +0 -0
- {inline_core-1.2.3 → inline_core-1.2.6}/src/inline_core/runtime/context.py +0 -0
- {inline_core-1.2.3 → inline_core-1.2.6}/src/inline_core/runtime/file_store.py +0 -0
- {inline_core-1.2.3 → inline_core-1.2.6}/src/inline_core/runtime/progress.py +0 -0
- {inline_core-1.2.3 → inline_core-1.2.6}/src/inline_core/runtime/run.py +0 -0
- {inline_core-1.2.3 → inline_core-1.2.6}/src/inline_core/runtime/store.py +0 -0
- {inline_core-1.2.3 → inline_core-1.2.6}/src/inline_core/sampling/__init__.py +0 -0
- {inline_core-1.2.3 → inline_core-1.2.6}/src/inline_core/sampling/batch.py +0 -0
- {inline_core-1.2.3 → inline_core-1.2.6}/src/inline_core/server/__init__.py +0 -0
- {inline_core-1.2.3 → inline_core-1.2.6}/src/inline_core/server/__main__.py +0 -0
- {inline_core-1.2.3 → inline_core-1.2.6}/src/inline_core/server/assets.py +0 -0
- {inline_core-1.2.3 → inline_core-1.2.6}/src/inline_core/server/frontend.py +0 -0
- {inline_core-1.2.3 → inline_core-1.2.6}/src/inline_core/server/manager.py +0 -0
- {inline_core-1.2.3 → inline_core-1.2.6}/src/inline_core/server/run_store.py +0 -0
- {inline_core-1.2.3 → inline_core-1.2.6}/src/inline_core/studio/__init__.py +0 -0
- {inline_core-1.2.3 → inline_core-1.2.6}/src/inline_core/studio/assets.py +0 -0
- {inline_core-1.2.3 → inline_core-1.2.6}/src/inline_core/studio/config.py +0 -0
- {inline_core-1.2.3 → inline_core-1.2.6}/src/inline_core/studio/peaks.py +0 -0
- {inline_core-1.2.3 → inline_core-1.2.6}/src/inline_core/studio/store.py +0 -0
- {inline_core-1.2.3 → inline_core-1.2.6}/src/inline_core/studio/timeline/__init__.py +0 -0
- {inline_core-1.2.3 → inline_core-1.2.6}/src/inline_core/studio/timeline/compose.py +0 -0
- {inline_core-1.2.3 → inline_core-1.2.6}/src/inline_core/studio/timeline/ffmpeg.py +0 -0
- {inline_core-1.2.3 → inline_core-1.2.6}/src/inline_core/studio/timeline/render.py +0 -0
- {inline_core-1.2.3 → inline_core-1.2.6}/src/inline_core/studio/timeline/resolve.py +0 -0
- {inline_core-1.2.3 → inline_core-1.2.6}/src/inline_core/takes.py +0 -0
- {inline_core-1.2.3 → inline_core-1.2.6}/tests/test_catalog.py +0 -0
- {inline_core-1.2.3 → inline_core-1.2.6}/tests/test_config.py +0 -0
- {inline_core-1.2.3 → inline_core-1.2.6}/tests/test_device_detect.py +0 -0
- {inline_core-1.2.3 → inline_core-1.2.6}/tests/test_extension_api.py +0 -0
- {inline_core-1.2.3 → inline_core-1.2.6}/tests/test_extension_install.py +0 -0
- {inline_core-1.2.3 → inline_core-1.2.6}/tests/test_extension_manifest.py +0 -0
- {inline_core-1.2.3 → inline_core-1.2.6}/tests/test_extension_resolve.py +0 -0
- {inline_core-1.2.3 → inline_core-1.2.6}/tests/test_extension_scanner.py +0 -0
- {inline_core-1.2.3 → inline_core-1.2.6}/tests/test_extension_spine.py +0 -0
- {inline_core-1.2.3 → inline_core-1.2.6}/tests/test_extension_state.py +0 -0
- {inline_core-1.2.3 → inline_core-1.2.6}/tests/test_file_store.py +0 -0
- {inline_core-1.2.3 → inline_core-1.2.6}/tests/test_frontend_serving.py +0 -0
- {inline_core-1.2.3 → inline_core-1.2.6}/tests/test_hidden_nodes.py +0 -0
- {inline_core-1.2.3 → inline_core-1.2.6}/tests/test_loader_runners.py +0 -0
- {inline_core-1.2.3 → inline_core-1.2.6}/tests/test_parallel_group.py +0 -0
- {inline_core-1.2.3 → inline_core-1.2.6}/tests/test_primitives.py +0 -0
- {inline_core-1.2.3 → inline_core-1.2.6}/tests/test_rpc_bridge.py +0 -0
- {inline_core-1.2.3 → inline_core-1.2.6}/tests/test_run_store.py +0 -0
- {inline_core-1.2.3 → inline_core-1.2.6}/tests/test_sampling.py +0 -0
- {inline_core-1.2.3 → inline_core-1.2.6}/tests/test_schema.py +0 -0
- {inline_core-1.2.3 → inline_core-1.2.6}/tests/test_server.py +0 -0
- {inline_core-1.2.3 → inline_core-1.2.6}/tests/test_studio_assets.py +0 -0
- {inline_core-1.2.3 → inline_core-1.2.6}/tests/test_studio_frames.py +0 -0
- {inline_core-1.2.3 → inline_core-1.2.6}/tests/test_studio_moodboard.py +0 -0
- {inline_core-1.2.3 → inline_core-1.2.6}/tests/test_studio_peaks.py +0 -0
- {inline_core-1.2.3 → inline_core-1.2.6}/tests/test_studio_store.py +0 -0
- {inline_core-1.2.3 → inline_core-1.2.6}/tests/test_studio_timeline.py +0 -0
- {inline_core-1.2.3 → inline_core-1.2.6}/tests/test_take_bytes.py +0 -0
- {inline_core-1.2.3 → inline_core-1.2.6}/tests/test_topo.py +0 -0
- {inline_core-1.2.3 → inline_core-1.2.6}/tests/test_validate.py +0 -0
- {inline_core-1.2.3 → inline_core-1.2.6}/tests/test_xfuser_sampler.py +0 -0
- {inline_core-1.2.3 → inline_core-1.2.6}/tests/test_zimage_primitives.py +0 -0
|
@@ -95,7 +95,16 @@ HTTP/WS → server/app.py → RunManager → Executor → Registry (desc
|
|
|
95
95
|
the ComfyUI-equivalent decomposed graph and the intended long-term surface. **Descriptor-only
|
|
96
96
|
today - their runners land in C2.** A graph built from them validates and type-checks but raises
|
|
97
97
|
`No runner registered` at execution.
|
|
98
|
-
- **Model runners** (`models/<name>/`) - high-level single generation nodes. **`
|
|
98
|
+
- **Model runners** (`models/<name>/`) - high-level single generation nodes. **`black-forest-labs/flux-2`
|
|
99
|
+
(`models/flux2/`) is the reference for a _family_:** one node covers klein 4B/9B, their base builds,
|
|
100
|
+
the KV variant and dev, because the picked checkpoint is identified from its own tensor shapes
|
|
101
|
+
(`flux2/variants.py`) and everything else follows. Adding a checkpoint is a row in that table.
|
|
102
|
+
Two rules it establishes: **identify a checkpoint by content, never by filename** (`diffusion_models/`
|
|
103
|
+
is shared across architectures, and Qwen3-4B and Qwen3-VL-4B have byte-identical embedding shapes),
|
|
104
|
+
and **derive geometry from the checkpoint** rather than bundling a config per variant, so a future
|
|
105
|
+
build loads with no code change. A **diffusers folder** is a valid checkpoint too, which is the only
|
|
106
|
+
way a 32B model reaches a 24 GB card: its NF4 shards stream through `from_pretrained`, where
|
|
107
|
+
`from_single_file` cannot quantize at all. **`alibaba/z-image-turbo`
|
|
99
108
|
(`models/zimage/`) is the one runnable generation path today** (prompt + optional image → one take,
|
|
100
109
|
backed by diffusers' `ZImagePipeline`/`ZImageImg2ImgPipeline`). This is the "Z-Image pipeline that
|
|
101
110
|
already works" - the primitives will reach parity in C2. It loads from a **single diffusion
|
|
@@ -143,6 +152,18 @@ between nodes and are never takes.
|
|
|
143
152
|
(Turing/Volta - compute capability < 8.0, e.g. a T4): same footprint, but it uses the fp16 tensor
|
|
144
153
|
cores instead of bf16's slow path. The **VAE stays upcast** (bf16, or fp32 when the denoiser is
|
|
145
154
|
fp16) because fp16 VAE decode can overflow to black/NaN images (`_compute_dtype` in `device/`).
|
|
155
|
+
- **Quantization rungs** - the fit ladder is full-precision resident → int8 resident → **NF4 resident**
|
|
156
|
+
→ sequential offload → wont-fit. NF4 is what makes a 32B model viable on a 24 GB card. Note int8
|
|
157
|
+
forces bf16 (torchao's weight-only int8 silently no-ops under fp16) while NF4 does not, so a Turing
|
|
158
|
+
card keeps its fp16 tensor cores under NF4.
|
|
159
|
+
- **Prequantized checkpoints must not be re-quantized.** A checkpoint that ships already quantized
|
|
160
|
+
(`flux2/variants.is_prequantized`) has an on-disk size that already _is_ its resident size, so the
|
|
161
|
+
ladder's assumption that quantization halves it does not hold, and handing diffusers a second,
|
|
162
|
+
different quantization config is a hard error. Pass `Quantization.NONE` for those.
|
|
163
|
+
- **Staged loading** - when the text encoder and the transformer cannot be co-resident (dev is a
|
|
164
|
+
15 GB encoder beside an 18 GB transformer), the prompt is encoded first and the encoder freed before
|
|
165
|
+
the transformer loads. The decision has to be made _before_ the load: by the time an OOM fires there
|
|
166
|
+
is nothing left to free.
|
|
146
167
|
- **Multi-GPU** - `INLINE_PARALLEL` (e.g. `pipefusion=2`, `pipefusion=2,ulysses=2`); degrees multiply
|
|
147
168
|
to the world size, which must equal the GPU count.
|
|
148
169
|
|
|
@@ -202,6 +223,11 @@ real codec that moves tensors lives with the model runner.
|
|
|
202
223
|
Don't scatter it.
|
|
203
224
|
- **Bring-your-own models.** Nothing is downloaded by the engine. The catalog scans; the user places
|
|
204
225
|
files. A model picker is a `SELECT` param with `options_from="<category>"`.
|
|
226
|
+
- **Verify image models by rendering.** The FLUX.2 work shipped five bugs past a green test suite,
|
|
227
|
+
and every one produced a _wrong image rather than an error_: a mis-keyed checkpoint, a
|
|
228
|
+
vision-language encoder loaded in place of a text one, an unnormalized latent, and a control context
|
|
229
|
+
cast to a quantized weight's `uint8` storage dtype. A unit test cannot see a plausible-but-wrong
|
|
230
|
+
image. Render something and look at it.
|
|
205
231
|
- **Tests (pytest).** Cover the logic that matters: graph validate/topo/executor/cache, the catalog
|
|
206
232
|
scan, the run store + server contract, the device/memory policy, the parallel group + xfuser seam,
|
|
207
233
|
and each model runner (import-guarded, no GPU needed). See `tests/`.
|
|
@@ -211,14 +237,17 @@ real codec that moves tensors lives with the model runner.
|
|
|
211
237
|
|
|
212
238
|
```
|
|
213
239
|
uv venv # create ./.venv
|
|
214
|
-
|
|
215
|
-
uv pip install -e ".[
|
|
216
|
-
uv pip install -e ".[runtime
|
|
240
|
+
# --python pins the target: without it uv installs into an activated venv/conda env, not ./.venv
|
|
241
|
+
uv pip install --python .venv/bin/python -e ".[server,dev]" # engine + server + test tooling
|
|
242
|
+
uv pip install --python .venv/bin/python -e ".[runtime]" # + torch, diffusers, transformers
|
|
243
|
+
uv pip install --python .venv/bin/python -e ".[runtime,parallel]" # + xfuser, multi-GPU denoise
|
|
217
244
|
|
|
218
245
|
./webui.sh # run (loopback:8848); friendly flags → INLINE_* env
|
|
219
246
|
./webui.sh --listen --port 9000 # bind all interfaces
|
|
220
247
|
./webui.sh --lowvram # tight-VRAM profile
|
|
221
248
|
./webui.sh --install --extra runtime # set up ./.venv with the model runtime, then exit
|
|
249
|
+
# (reuses an existing ./.venv; --recreate rebuilds it, and
|
|
250
|
+
# an activated foreign env is reported, never modified)
|
|
222
251
|
python -m inline_core.server # run the server directly (INLINE_HOST / INLINE_PORT)
|
|
223
252
|
|
|
224
253
|
ruff check . # lint (zero warnings)
|
|
@@ -1,18 +1,28 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: inline-core
|
|
3
|
-
Version: 1.2.
|
|
3
|
+
Version: 1.2.6
|
|
4
4
|
Summary: The generation engine behind Inline Studio.
|
|
5
|
+
License-Expression: GPL-3.0-or-later
|
|
5
6
|
Requires-Python: >=3.11
|
|
6
7
|
Requires-Dist: numpy>=1.26
|
|
7
8
|
Requires-Dist: psutil>=5.9
|
|
8
9
|
Provides-Extra: all
|
|
9
10
|
Requires-Dist: accelerate>=0.30; extra == 'all'
|
|
10
|
-
Requires-Dist:
|
|
11
|
+
Requires-Dist: bitsandbytes>=0.43; (platform_system != 'Darwin') and extra == 'all'
|
|
12
|
+
Requires-Dist: controlnet-aux>=0.0.7; extra == 'all'
|
|
13
|
+
Requires-Dist: diffusers>=0.39; extra == 'all'
|
|
14
|
+
Requires-Dist: einops>=0.7; extra == 'all'
|
|
11
15
|
Requires-Dist: fastapi>=0.110; extra == 'all'
|
|
12
16
|
Requires-Dist: huggingface-hub>=0.23; extra == 'all'
|
|
13
17
|
Requires-Dist: imageio-ffmpeg>=0.4; extra == 'all'
|
|
18
|
+
Requires-Dist: nvidia-ml-py>=12; extra == 'all'
|
|
19
|
+
Requires-Dist: onnxruntime>=1.17; extra == 'all'
|
|
20
|
+
Requires-Dist: peft>=0.11; extra == 'all'
|
|
21
|
+
Requires-Dist: pillow>=10; extra == 'all'
|
|
22
|
+
Requires-Dist: psutil>=5.9; extra == 'all'
|
|
14
23
|
Requires-Dist: safetensors>=0.4; extra == 'all'
|
|
15
24
|
Requires-Dist: scipy>=1.11; extra == 'all'
|
|
25
|
+
Requires-Dist: timm>=1.0; extra == 'all'
|
|
16
26
|
Requires-Dist: torch>=2.2; extra == 'all'
|
|
17
27
|
Requires-Dist: torchao>=0.14; extra == 'all'
|
|
18
28
|
Requires-Dist: transformers>=4.44; extra == 'all'
|
|
@@ -27,8 +37,10 @@ Requires-Dist: nvidia-ml-py>=12; extra == 'parallel'
|
|
|
27
37
|
Requires-Dist: xfuser>=0.4; extra == 'parallel'
|
|
28
38
|
Provides-Extra: runtime
|
|
29
39
|
Requires-Dist: accelerate>=0.30; extra == 'runtime'
|
|
30
|
-
Requires-Dist:
|
|
40
|
+
Requires-Dist: controlnet-aux>=0.0.7; extra == 'runtime'
|
|
41
|
+
Requires-Dist: diffusers>=0.39; extra == 'runtime'
|
|
31
42
|
Requires-Dist: huggingface-hub>=0.23; extra == 'runtime'
|
|
43
|
+
Requires-Dist: onnxruntime>=1.17; extra == 'runtime'
|
|
32
44
|
Requires-Dist: safetensors>=0.4; extra == 'runtime'
|
|
33
45
|
Requires-Dist: scipy>=1.11; extra == 'runtime'
|
|
34
46
|
Requires-Dist: torch>=2.2; extra == 'runtime'
|
|
@@ -38,6 +50,14 @@ Provides-Extra: server
|
|
|
38
50
|
Requires-Dist: fastapi>=0.110; extra == 'server'
|
|
39
51
|
Requires-Dist: imageio-ffmpeg>=0.4; extra == 'server'
|
|
40
52
|
Requires-Dist: uvicorn[standard]>=0.29; extra == 'server'
|
|
53
|
+
Provides-Extra: training
|
|
54
|
+
Requires-Dist: bitsandbytes>=0.43; (platform_system != 'Darwin') and extra == 'training'
|
|
55
|
+
Requires-Dist: einops>=0.7; extra == 'training'
|
|
56
|
+
Requires-Dist: nvidia-ml-py>=12; extra == 'training'
|
|
57
|
+
Requires-Dist: peft>=0.11; extra == 'training'
|
|
58
|
+
Requires-Dist: pillow>=10; extra == 'training'
|
|
59
|
+
Requires-Dist: psutil>=5.9; extra == 'training'
|
|
60
|
+
Requires-Dist: timm>=1.0; extra == 'training'
|
|
41
61
|
Description-Content-Type: text/markdown
|
|
42
62
|
|
|
43
63
|
# Inline Core
|
|
@@ -47,8 +67,9 @@ The generation engine behind Inline. It takes a typed node graph (JSON) and retu
|
|
|
47
67
|
low-VRAM laptops up to multi-GPU machines that split a single image's sampling across GPUs (via
|
|
48
68
|
xDiT). It is Inline Studio's built-in render backend.
|
|
49
69
|
|
|
50
|
-
|
|
51
|
-
already supports, so the multi-GPU split works on it from the start)
|
|
70
|
+
Models today: **Z-Image** (Alibaba Tongyi), a 6B rectified-flow diffusion transformer and the model
|
|
71
|
+
xDiT already supports, so the multi-GPU split works on it from the start; and **Krea 2** (Krea AI),
|
|
72
|
+
a 12.9B single-stream MMDiT released as an undistilled RAW base plus an 8-step distilled Turbo.
|
|
52
73
|
|
|
53
74
|
> Status: early, and running end to end against a stub engine. In place and tested: the graph engine,
|
|
54
75
|
> the typed `/v1` HTTP + websocket API (durable runs, streamed progress, coalescing), the model-dir
|
|
@@ -80,13 +101,18 @@ a 6 GB laptop, pure CPU, or split across several GPUs, without touching the grap
|
|
|
80
101
|
|
|
81
102
|
Requires Python 3.11+ and [uv](https://docs.astral.sh/uv/).
|
|
82
103
|
|
|
104
|
+
`--python` pins each install to `./.venv`; without it uv targets whatever venv or conda env is
|
|
105
|
+
activated in your shell, and installs land there instead.
|
|
106
|
+
|
|
83
107
|
```
|
|
84
108
|
uv venv
|
|
85
|
-
uv pip install -e ".[server]"
|
|
86
|
-
uv pip install -e ".[runtime]"
|
|
87
|
-
uv pip install -e ".[runtime,parallel]" # + xfuser,
|
|
109
|
+
uv pip install --python .venv/bin/python -e ".[server]" # engine + HTTP/websocket API
|
|
110
|
+
uv pip install --python .venv/bin/python -e ".[runtime]" # + torch, diffusers, transformers
|
|
111
|
+
uv pip install --python .venv/bin/python -e ".[runtime,parallel]" # + xfuser, 2+ GPUs
|
|
88
112
|
```
|
|
89
113
|
|
|
114
|
+
Or let the launcher do it: `./webui.sh --install --extra runtime` (Windows: `.\webui.bat`).
|
|
115
|
+
|
|
90
116
|
## Models
|
|
91
117
|
|
|
92
118
|
Drop files into the models dir (default `./models`, override with `INLINE_MODELS_DIR`), ComfyUI-style,
|
|
@@ -94,9 +120,13 @@ by category:
|
|
|
94
120
|
|
|
95
121
|
```
|
|
96
122
|
models/
|
|
97
|
-
diffusion_models/ z_image_turbo_bf16.safetensors
|
|
98
|
-
|
|
99
|
-
|
|
123
|
+
diffusion_models/ z_image_turbo_bf16.safetensors <- Z-Image
|
|
124
|
+
krea2_turbo_bf16.safetensors <- Krea 2 Turbo (generate)
|
|
125
|
+
krea2_raw_bf16.safetensors <- Krea 2 RAW (fine-tune)
|
|
126
|
+
vae/ ae.safetensors <- Z-Image
|
|
127
|
+
qwen_image_vae_diffusers.safetensors <- Krea 2
|
|
128
|
+
text_encoders/ qwen_3_4b.safetensors <- Z-Image
|
|
129
|
+
qwen3vl_4b_bf16.safetensors <- Krea 2
|
|
100
130
|
loras/ controlnet/ checkpoints/ ...
|
|
101
131
|
```
|
|
102
132
|
|
|
@@ -115,8 +145,17 @@ paths:
|
|
|
115
145
|
`models/`** (never the hidden HF cache) with visible progress.
|
|
116
146
|
|
|
117
147
|
Override the diffusion source with `INLINE_ZIMAGE_MODEL` (a file or a diffusers dir), and the supporting
|
|
118
|
-
components with `INLINE_ZIMAGE_VAE` / `INLINE_ZIMAGE_TEXT_ENCODER
|
|
119
|
-
start; a node's model pickers list what is present.
|
|
148
|
+
components with `INLINE_ZIMAGE_VAE` / `INLINE_ZIMAGE_TEXT_ENCODER`; Krea 2 has the same three under
|
|
149
|
+
`INLINE_KREA2_*`. The engine scans the models dir on start; a node's model pickers list what is present.
|
|
150
|
+
|
|
151
|
+
**Krea 2 loads from the same ComfyUI single files**, with two constraints worth knowing. Only the
|
|
152
|
+
**bf16** builds in [`Comfy-Org/Krea-2`](https://huggingface.co/Comfy-Org/Krea-2) are loadable: the
|
|
153
|
+
fp8/int8/nvfp4 variants carry ComfyUI-specific scale tensors, and the loader refuses them by name
|
|
154
|
+
rather than failing mid-load. And the **VAE must be the diffusers-format** Qwen-Image file (the
|
|
155
|
+
node's popup fetches it from `Qwen/Qwen-Image`), because ComfyUI's copy of the same weights uses a
|
|
156
|
+
module layout diffusers has no converter for. `Krea2Transformer2DModel` has no `from_single_file`, so
|
|
157
|
+
the transformer checkpoint is renamed into diffusers naming on load (`models/krea2/convert.py`) and
|
|
158
|
+
streamed tensor by tensor onto the GPU.
|
|
120
159
|
|
|
121
160
|
## Nodes
|
|
122
161
|
|
|
@@ -124,8 +163,9 @@ start; a node's model pickers list what is present.
|
|
|
124
163
|
renders any node generically - adding a node type needs no UI release.
|
|
125
164
|
|
|
126
165
|
**High-level model nodes are what the user sees.** Generation is one-click: you drop a single
|
|
127
|
-
**Z-Image Turbo** node, wire a Prompt into it, and hit Run. The
|
|
128
|
-
and text-encoder behind the scenes - no loader/sampler
|
|
166
|
+
**Z-Image Turbo**, **Krea 2 Turbo** or **Krea 2 RAW** node, wire a Prompt into it, and hit Run. The
|
|
167
|
+
node hooks up the diffusion model, VAE, and text-encoder behind the scenes - no loader/sampler
|
|
168
|
+
wiring.
|
|
129
169
|
|
|
130
170
|
Underneath, a **low-level primitive vocabulary** exists (`load/diffusion-model`, `load/vae`,
|
|
131
171
|
`load/text-encoder`, `encode/text`, `latent/empty`, `sample`, `vae/decode`, `vae/encode`) - the
|
|
@@ -207,17 +247,18 @@ offload machinery, `--vram-budget GB` / `INLINE_VRAM_BUDGET_GB` to cap the assum
|
|
|
207
247
|
|
|
208
248
|
## Run
|
|
209
249
|
|
|
210
|
-
The easy path is `webui.sh
|
|
250
|
+
The easy path is `webui.sh` (macOS/Linux) or `webui.bat` (Windows), which maps friendly flags onto the
|
|
251
|
+
engine's `INLINE_*` env knobs. Windows must use `webui.bat` - `webui.sh` is a bash script:
|
|
211
252
|
|
|
212
253
|
```
|
|
213
|
-
./webui.sh # loopback, port 8848
|
|
254
|
+
./webui.sh # loopback, port 8848 (Windows: .\webui.bat)
|
|
214
255
|
./webui.sh --listen --port 9000 # bind all interfaces on 9000
|
|
215
256
|
./webui.sh --multi-gpu # split one image across GPUs (auto with 2+ GPUs)
|
|
216
257
|
./webui.sh --lowvram # tight-VRAM profile
|
|
217
|
-
./webui.sh --install --extra
|
|
258
|
+
./webui.sh --install --extra runtime # set up ./.venv with the model runtime, then exit
|
|
218
259
|
```
|
|
219
260
|
|
|
220
|
-
`./webui.sh --help` lists every flag (networking, multi-GPU, device/memory profile, paths). The same
|
|
261
|
+
`./webui.sh --help` (or `.\webui.bat --help`) lists every flag (networking, multi-GPU, device/memory profile, paths). The same
|
|
221
262
|
flags are available on the Python entrypoint - `python main.py --help` - which is the dev path (it also
|
|
222
263
|
takes `--front-end-root DIR` to serve a local SPA build). Or run the server module directly:
|
|
223
264
|
|
|
@@ -5,8 +5,9 @@ The generation engine behind Inline. It takes a typed node graph (JSON) and retu
|
|
|
5
5
|
low-VRAM laptops up to multi-GPU machines that split a single image's sampling across GPUs (via
|
|
6
6
|
xDiT). It is Inline Studio's built-in render backend.
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
already supports, so the multi-GPU split works on it from the start)
|
|
8
|
+
Models today: **Z-Image** (Alibaba Tongyi), a 6B rectified-flow diffusion transformer and the model
|
|
9
|
+
xDiT already supports, so the multi-GPU split works on it from the start; and **Krea 2** (Krea AI),
|
|
10
|
+
a 12.9B single-stream MMDiT released as an undistilled RAW base plus an 8-step distilled Turbo.
|
|
10
11
|
|
|
11
12
|
> Status: early, and running end to end against a stub engine. In place and tested: the graph engine,
|
|
12
13
|
> the typed `/v1` HTTP + websocket API (durable runs, streamed progress, coalescing), the model-dir
|
|
@@ -38,13 +39,18 @@ a 6 GB laptop, pure CPU, or split across several GPUs, without touching the grap
|
|
|
38
39
|
|
|
39
40
|
Requires Python 3.11+ and [uv](https://docs.astral.sh/uv/).
|
|
40
41
|
|
|
42
|
+
`--python` pins each install to `./.venv`; without it uv targets whatever venv or conda env is
|
|
43
|
+
activated in your shell, and installs land there instead.
|
|
44
|
+
|
|
41
45
|
```
|
|
42
46
|
uv venv
|
|
43
|
-
uv pip install -e ".[server]"
|
|
44
|
-
uv pip install -e ".[runtime]"
|
|
45
|
-
uv pip install -e ".[runtime,parallel]" # + xfuser,
|
|
47
|
+
uv pip install --python .venv/bin/python -e ".[server]" # engine + HTTP/websocket API
|
|
48
|
+
uv pip install --python .venv/bin/python -e ".[runtime]" # + torch, diffusers, transformers
|
|
49
|
+
uv pip install --python .venv/bin/python -e ".[runtime,parallel]" # + xfuser, 2+ GPUs
|
|
46
50
|
```
|
|
47
51
|
|
|
52
|
+
Or let the launcher do it: `./webui.sh --install --extra runtime` (Windows: `.\webui.bat`).
|
|
53
|
+
|
|
48
54
|
## Models
|
|
49
55
|
|
|
50
56
|
Drop files into the models dir (default `./models`, override with `INLINE_MODELS_DIR`), ComfyUI-style,
|
|
@@ -52,9 +58,13 @@ by category:
|
|
|
52
58
|
|
|
53
59
|
```
|
|
54
60
|
models/
|
|
55
|
-
diffusion_models/ z_image_turbo_bf16.safetensors
|
|
56
|
-
|
|
57
|
-
|
|
61
|
+
diffusion_models/ z_image_turbo_bf16.safetensors <- Z-Image
|
|
62
|
+
krea2_turbo_bf16.safetensors <- Krea 2 Turbo (generate)
|
|
63
|
+
krea2_raw_bf16.safetensors <- Krea 2 RAW (fine-tune)
|
|
64
|
+
vae/ ae.safetensors <- Z-Image
|
|
65
|
+
qwen_image_vae_diffusers.safetensors <- Krea 2
|
|
66
|
+
text_encoders/ qwen_3_4b.safetensors <- Z-Image
|
|
67
|
+
qwen3vl_4b_bf16.safetensors <- Krea 2
|
|
58
68
|
loras/ controlnet/ checkpoints/ ...
|
|
59
69
|
```
|
|
60
70
|
|
|
@@ -73,8 +83,17 @@ paths:
|
|
|
73
83
|
`models/`** (never the hidden HF cache) with visible progress.
|
|
74
84
|
|
|
75
85
|
Override the diffusion source with `INLINE_ZIMAGE_MODEL` (a file or a diffusers dir), and the supporting
|
|
76
|
-
components with `INLINE_ZIMAGE_VAE` / `INLINE_ZIMAGE_TEXT_ENCODER
|
|
77
|
-
start; a node's model pickers list what is present.
|
|
86
|
+
components with `INLINE_ZIMAGE_VAE` / `INLINE_ZIMAGE_TEXT_ENCODER`; Krea 2 has the same three under
|
|
87
|
+
`INLINE_KREA2_*`. The engine scans the models dir on start; a node's model pickers list what is present.
|
|
88
|
+
|
|
89
|
+
**Krea 2 loads from the same ComfyUI single files**, with two constraints worth knowing. Only the
|
|
90
|
+
**bf16** builds in [`Comfy-Org/Krea-2`](https://huggingface.co/Comfy-Org/Krea-2) are loadable: the
|
|
91
|
+
fp8/int8/nvfp4 variants carry ComfyUI-specific scale tensors, and the loader refuses them by name
|
|
92
|
+
rather than failing mid-load. And the **VAE must be the diffusers-format** Qwen-Image file (the
|
|
93
|
+
node's popup fetches it from `Qwen/Qwen-Image`), because ComfyUI's copy of the same weights uses a
|
|
94
|
+
module layout diffusers has no converter for. `Krea2Transformer2DModel` has no `from_single_file`, so
|
|
95
|
+
the transformer checkpoint is renamed into diffusers naming on load (`models/krea2/convert.py`) and
|
|
96
|
+
streamed tensor by tensor onto the GPU.
|
|
78
97
|
|
|
79
98
|
## Nodes
|
|
80
99
|
|
|
@@ -82,8 +101,9 @@ start; a node's model pickers list what is present.
|
|
|
82
101
|
renders any node generically - adding a node type needs no UI release.
|
|
83
102
|
|
|
84
103
|
**High-level model nodes are what the user sees.** Generation is one-click: you drop a single
|
|
85
|
-
**Z-Image Turbo** node, wire a Prompt into it, and hit Run. The
|
|
86
|
-
and text-encoder behind the scenes - no loader/sampler
|
|
104
|
+
**Z-Image Turbo**, **Krea 2 Turbo** or **Krea 2 RAW** node, wire a Prompt into it, and hit Run. The
|
|
105
|
+
node hooks up the diffusion model, VAE, and text-encoder behind the scenes - no loader/sampler
|
|
106
|
+
wiring.
|
|
87
107
|
|
|
88
108
|
Underneath, a **low-level primitive vocabulary** exists (`load/diffusion-model`, `load/vae`,
|
|
89
109
|
`load/text-encoder`, `encode/text`, `latent/empty`, `sample`, `vae/decode`, `vae/encode`) - the
|
|
@@ -165,17 +185,18 @@ offload machinery, `--vram-budget GB` / `INLINE_VRAM_BUDGET_GB` to cap the assum
|
|
|
165
185
|
|
|
166
186
|
## Run
|
|
167
187
|
|
|
168
|
-
The easy path is `webui.sh
|
|
188
|
+
The easy path is `webui.sh` (macOS/Linux) or `webui.bat` (Windows), which maps friendly flags onto the
|
|
189
|
+
engine's `INLINE_*` env knobs. Windows must use `webui.bat` - `webui.sh` is a bash script:
|
|
169
190
|
|
|
170
191
|
```
|
|
171
|
-
./webui.sh # loopback, port 8848
|
|
192
|
+
./webui.sh # loopback, port 8848 (Windows: .\webui.bat)
|
|
172
193
|
./webui.sh --listen --port 9000 # bind all interfaces on 9000
|
|
173
194
|
./webui.sh --multi-gpu # split one image across GPUs (auto with 2+ GPUs)
|
|
174
195
|
./webui.sh --lowvram # tight-VRAM profile
|
|
175
|
-
./webui.sh --install --extra
|
|
196
|
+
./webui.sh --install --extra runtime # set up ./.venv with the model runtime, then exit
|
|
176
197
|
```
|
|
177
198
|
|
|
178
|
-
`./webui.sh --help` lists every flag (networking, multi-GPU, device/memory profile, paths). The same
|
|
199
|
+
`./webui.sh --help` (or `.\webui.bat --help`) lists every flag (networking, multi-GPU, device/memory profile, paths). The same
|
|
179
200
|
flags are available on the Python entrypoint - `python main.py --help` - which is the dev path (it also
|
|
180
201
|
takes `--front-end-root DIR` to serve a local SPA build). Or run the server module directly:
|
|
181
202
|
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
# PyPI name; the import package is `inline_core` (src/inline_core).
|
|
3
3
|
name = "inline-core"
|
|
4
|
-
version = "1.2.
|
|
4
|
+
version = "1.2.6"
|
|
5
5
|
description = "The generation engine behind Inline Studio."
|
|
6
6
|
readme = "README.md"
|
|
7
|
+
license = "GPL-3.0-or-later"
|
|
7
8
|
requires-python = ">=3.11"
|
|
8
9
|
# Deliberately torch-free so the engine boots and serves source nodes with no ML stack installed.
|
|
9
10
|
dependencies = [
|
|
@@ -16,8 +17,8 @@ dependencies = [
|
|
|
16
17
|
runtime = [
|
|
17
18
|
# A bare `torch` is CPU-only on Windows; see [tool.uv] below and requirements.txt.
|
|
18
19
|
"torch>=2.2",
|
|
19
|
-
# Z-Image needs
|
|
20
|
-
"diffusers>=0.
|
|
20
|
+
# Krea 2 needs diffusers >= 0.39 (Krea2Pipeline); Z-Image needs >= 0.36 (ZImagePipeline).
|
|
21
|
+
"diffusers>=0.39",
|
|
21
22
|
"transformers>=4.44",
|
|
22
23
|
"accelerate>=0.30",
|
|
23
24
|
"safetensors>=0.4",
|
|
@@ -27,6 +28,10 @@ runtime = [
|
|
|
27
28
|
"scipy>=1.11",
|
|
28
29
|
# We call snapshot_download directly for the model popup, so pin it rather than rely on transit.
|
|
29
30
|
"huggingface_hub>=0.23",
|
|
31
|
+
# ControlNet preprocessors (the Apply ControlNet node): OpenPose/DWPose, MiDaS/Zoe depth, canny,
|
|
32
|
+
# HED, lineart, MLSD, scribble, normal. DWPose runs its detector on ONNX Runtime.
|
|
33
|
+
"controlnet-aux>=0.0.7",
|
|
34
|
+
"onnxruntime>=1.17",
|
|
30
35
|
]
|
|
31
36
|
server = [
|
|
32
37
|
"fastapi>=0.110",
|
|
@@ -39,25 +44,54 @@ parallel = [
|
|
|
39
44
|
"xfuser>=0.4",
|
|
40
45
|
"nvidia-ml-py>=12",
|
|
41
46
|
]
|
|
47
|
+
# LoRA training (the Trainer tab): PEFT adapter training + local auto-caption + host/GPU telemetry.
|
|
48
|
+
# Install alongside `runtime`: `.[runtime,training]`. Reuses runtime's torch/diffusers/accelerate.
|
|
49
|
+
training = [
|
|
50
|
+
"peft>=0.11",
|
|
51
|
+
# 8-bit Adam keeps optimizer state small; no macOS wheels, so skip it there (AdamW fallback).
|
|
52
|
+
"bitsandbytes>=0.43; platform_system != 'Darwin'",
|
|
53
|
+
"Pillow>=10",
|
|
54
|
+
# Telemetry (CPU/RAM + per-GPU NVML) for the Trainer tab.
|
|
55
|
+
"psutil>=5.9",
|
|
56
|
+
"nvidia-ml-py>=12",
|
|
57
|
+
# Florence-2 auto-captioner is loaded via trust_remote_code and needs these.
|
|
58
|
+
"timm>=1.0",
|
|
59
|
+
"einops>=0.7",
|
|
60
|
+
]
|
|
42
61
|
dev = [
|
|
43
62
|
"pytest>=8",
|
|
44
63
|
"ruff>=0.6",
|
|
45
64
|
"pyright>=1.1",
|
|
46
65
|
"httpx>=0.27",
|
|
47
66
|
]
|
|
48
|
-
# Everything
|
|
67
|
+
# Everything a local install needs in one extra: runtime + server + training (the LoRA trainer),
|
|
68
|
+
# so `--install --extra all` is a single "install everything" command. Multi-GPU (xfuser, the
|
|
69
|
+
# `parallel` extra) is left out on purpose - it is niche and can fail to build on many systems.
|
|
70
|
+
# Lists concrete packages, never `inline-core[...]` self-refs.
|
|
49
71
|
all = [
|
|
72
|
+
# runtime
|
|
50
73
|
"torch>=2.2",
|
|
51
|
-
"diffusers>=0.
|
|
74
|
+
"diffusers>=0.39",
|
|
52
75
|
"transformers>=4.44",
|
|
53
76
|
"accelerate>=0.30",
|
|
54
77
|
"safetensors>=0.4",
|
|
55
78
|
"torchao>=0.14",
|
|
56
79
|
"scipy>=1.11",
|
|
57
80
|
"huggingface_hub>=0.23",
|
|
81
|
+
"controlnet-aux>=0.0.7",
|
|
82
|
+
"onnxruntime>=1.17",
|
|
83
|
+
# server
|
|
58
84
|
"fastapi>=0.110",
|
|
59
85
|
"uvicorn[standard]>=0.29",
|
|
60
86
|
"imageio-ffmpeg>=0.4",
|
|
87
|
+
# training (the Trainer tab)
|
|
88
|
+
"peft>=0.11",
|
|
89
|
+
"bitsandbytes>=0.43; platform_system != 'Darwin'",
|
|
90
|
+
"Pillow>=10",
|
|
91
|
+
"psutil>=5.9",
|
|
92
|
+
"nvidia-ml-py>=12",
|
|
93
|
+
"timm>=1.0",
|
|
94
|
+
"einops>=0.7",
|
|
61
95
|
]
|
|
62
96
|
|
|
63
97
|
# PyPI ships CPU-only torch on Windows; pin the CUDA index there (pip: see requirements.txt).
|
|
@@ -93,4 +127,6 @@ typeCheckingMode = "strict"
|
|
|
93
127
|
|
|
94
128
|
[tool.pytest.ini_options]
|
|
95
129
|
testpaths = ["tests"]
|
|
96
|
-
|
|
130
|
+
# "." so `tests` imports as a package: several suites share fixtures via `from tests.x import y`,
|
|
131
|
+
# and without it those modules fail to collect and silently stop running.
|
|
132
|
+
pythonpath = ["src", "."]
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"""Inline Core: the generation engine behind Inline.
|
|
2
|
+
|
|
3
|
+
Takes a typed node graph and returns immutable takes. See PLAN.md for the architecture and
|
|
4
|
+
docs/contract.md for the Storyline API.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from importlib.metadata import PackageNotFoundError, version
|
|
8
|
+
|
|
9
|
+
try:
|
|
10
|
+
#: Resolved from the installed package, so pyproject.toml stays the only place a release is
|
|
11
|
+
#: bumped. An editable install records this at install time; reinstall after bumping.
|
|
12
|
+
__version__ = version("inline-core")
|
|
13
|
+
except PackageNotFoundError: # a source tree that was never installed
|
|
14
|
+
__version__ = "0.0.0"
|
|
@@ -47,6 +47,10 @@ _SMART_RESIDENT_MIN_VRAM_GB = 6.0
|
|
|
47
47
|
# ~half the fp16 weight bytes. Deliberately generous so the estimate errs toward a lighter plan.
|
|
48
48
|
_ACTIVATION_HEADROOM_GB = 2.5
|
|
49
49
|
_INT8_FACTOR = 0.5
|
|
50
|
+
# NF4 (bitsandbytes) stores 4-bit weights plus per-block scales, so ~0.55 bytes per parameter
|
|
51
|
+
# against fp16's 2. The rung exists for the very large checkpoints (FLUX.2 dev and friends) that
|
|
52
|
+
# int8 still cannot fit; it is CUDA-only and, like int8, never combined with CPU offload.
|
|
53
|
+
_NF4_FACTOR = 0.28
|
|
50
54
|
|
|
51
55
|
|
|
52
56
|
def _system_ram_gb() -> float | None:
|
|
@@ -202,9 +206,10 @@ class MemoryPolicy(DevicePolicy):
|
|
|
202
206
|
return None
|
|
203
207
|
cap = max(0.0, budget - _ACTIVATION_HEADROOM_GB)
|
|
204
208
|
big = (fp.diffusion_bytes + fp.text_encoder_bytes) / 1e9
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
209
|
+
# The VAE and a ControlNet are never quantized, so they cost the same under every plan.
|
|
210
|
+
fixed = (fp.vae_bytes + fp.controlnet_bytes) / 1e9
|
|
211
|
+
full = big + fixed
|
|
212
|
+
int8 = big * _INT8_FACTOR + fixed
|
|
208
213
|
forced = _env_profile() is not None # explicit --profile pins the profile; fit picks quant
|
|
209
214
|
|
|
210
215
|
def prof(auto: Profile) -> Profile:
|
|
@@ -221,7 +226,14 @@ class MemoryPolicy(DevicePolicy):
|
|
|
221
226
|
int8, budget, True,
|
|
222
227
|
"Weights are int8-quantized to fit this GPU's VRAM.",
|
|
223
228
|
)
|
|
224
|
-
|
|
229
|
+
nf4 = big * _NF4_FACTOR + fixed
|
|
230
|
+
if nf4 <= cap:
|
|
231
|
+
return FitEstimate(
|
|
232
|
+
"nf4", Quantization.NF4, OffloadMode.NONE, prof(Profile.LOWVRAM),
|
|
233
|
+
nf4, budget, True,
|
|
234
|
+
"Weights are 4-bit (NF4) quantized to fit this GPU's VRAM.",
|
|
235
|
+
)
|
|
236
|
+
# Even 4-bit won't fit resident -> CPU-offload streaming. Only viable if the (unquantized)
|
|
225
237
|
# model fits in system RAM, since sequential offload holds the off-GPU weights there.
|
|
226
238
|
ram = self._ram_gb
|
|
227
239
|
if ram is not None and full > ram:
|
|
@@ -87,10 +87,14 @@ class ModelFootprint:
|
|
|
87
87
|
diffusion_bytes: int = 0
|
|
88
88
|
text_encoder_bytes: int = 0
|
|
89
89
|
vae_bytes: int = 0
|
|
90
|
+
#: A ControlNet loaded alongside the denoiser. Never quantized, so it counts full in every plan.
|
|
91
|
+
controlnet_bytes: int = 0
|
|
90
92
|
|
|
91
93
|
@property
|
|
92
94
|
def total_bytes(self) -> int:
|
|
93
|
-
return
|
|
95
|
+
return (
|
|
96
|
+
self.diffusion_bytes + self.text_encoder_bytes + self.vae_bytes + self.controlnet_bytes
|
|
97
|
+
)
|
|
94
98
|
|
|
95
99
|
|
|
96
100
|
@dataclass(frozen=True)
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"""Locate the ffmpeg/ffprobe binaries. Prefers a bundled ``imageio-ffmpeg``, else PATH.
|
|
2
|
+
|
|
3
|
+
Lives at the top level rather than under ``studio/`` because both the timeline (studio) and the
|
|
4
|
+
take store (runtime) need it, and runtime must not import studio.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import shutil
|
|
10
|
+
from functools import lru_cache
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@lru_cache(maxsize=1)
|
|
14
|
+
def ffmpeg_exe() -> str | None:
|
|
15
|
+
try:
|
|
16
|
+
import imageio_ffmpeg
|
|
17
|
+
|
|
18
|
+
return imageio_ffmpeg.get_ffmpeg_exe()
|
|
19
|
+
except Exception: # noqa: BLE001
|
|
20
|
+
return shutil.which("ffmpeg")
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@lru_cache(maxsize=1)
|
|
24
|
+
def ffprobe_exe() -> str | None:
|
|
25
|
+
"""PATH only - imageio bundles ffmpeg alone, so probing degrades gracefully when absent."""
|
|
26
|
+
return shutil.which("ffprobe")
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def ffmpeg_available() -> bool:
|
|
30
|
+
return ffmpeg_exe() is not None
|
|
@@ -12,7 +12,7 @@ from typing import Any
|
|
|
12
12
|
|
|
13
13
|
from ..takes import Take
|
|
14
14
|
from .registry import Registry
|
|
15
|
-
from .schema import Graph, Node
|
|
15
|
+
from .schema import Graph, Node, PortKind
|
|
16
16
|
|
|
17
17
|
|
|
18
18
|
class NodeCache(ABC):
|
|
@@ -40,8 +40,15 @@ def _canonical_params(node: Node, registry: Registry) -> dict[str, Any]:
|
|
|
40
40
|
|
|
41
41
|
|
|
42
42
|
def is_cache_eligible(node: Node, registry: Registry) -> bool:
|
|
43
|
-
"""False when any seed param resolves to a negative (random) value.
|
|
43
|
+
"""False when a control map is wired, or any seed param resolves to a negative (random) value.
|
|
44
|
+
|
|
45
|
+
A node driven by a control map re-runs every time: the user iterates on the pose/depth and
|
|
46
|
+
expects each run to apply the current control, so a cached take would read as "control not
|
|
47
|
+
taking effect" (even a re-render at the same seed must re-apply it)."""
|
|
44
48
|
descriptor = registry.get(node.type)
|
|
49
|
+
for port in descriptor.inputs:
|
|
50
|
+
if port.kind is PortKind.CONTROL and node.inputs.get(port.id):
|
|
51
|
+
return False
|
|
45
52
|
defaults = descriptor.defaults()
|
|
46
53
|
for key in descriptor.seed_keys():
|
|
47
54
|
value = node.params.get(key, defaults.get(key))
|
|
@@ -81,3 +88,29 @@ def node_cache_key(
|
|
|
81
88
|
digest = hashlib.sha256(json.dumps(payload, sort_keys=True, default=str).encode()).hexdigest()
|
|
82
89
|
memo[node_id] = digest
|
|
83
90
|
return digest
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def asset_content_hashes(graph: Graph) -> dict[str, str]:
|
|
94
|
+
"""The byte hash of each file-backed source node's asset, keyed by node id. Feeds
|
|
95
|
+
``node_cache_key`` so the cache invalidates when a file's *content* changes even though its path
|
|
96
|
+
did not (a re-rendered control map, an in-place-replaced input image). Only ``ref="path"`` refs
|
|
97
|
+
are hashable; a missing file is skipped - its path still keys the node through its params."""
|
|
98
|
+
import os
|
|
99
|
+
|
|
100
|
+
hashes: dict[str, str] = {}
|
|
101
|
+
for node in graph.nodes:
|
|
102
|
+
asset = node.params.get("asset")
|
|
103
|
+
if not isinstance(asset, dict) or asset.get("ref") != "path":
|
|
104
|
+
continue
|
|
105
|
+
path = asset.get("path")
|
|
106
|
+
if isinstance(path, str) and os.path.isfile(path):
|
|
107
|
+
hashes[node.id] = _file_hash(path)
|
|
108
|
+
return hashes
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def _file_hash(path: str) -> str:
|
|
112
|
+
digest = hashlib.sha256()
|
|
113
|
+
with open(path, "rb") as handle:
|
|
114
|
+
for chunk in iter(lambda: handle.read(1 << 20), b""):
|
|
115
|
+
digest.update(chunk)
|
|
116
|
+
return digest.hexdigest()
|