mirror of
https://github.com/mudler/LocalAI.git
synced 2025-12-27 00:19:25 -05:00
* Initial plan Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * Add dynamic loader for diffusers pipelines and refactor backend.py Co-authored-by: mudler <2420543+mudler@users.noreply.github.com> Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * Fix pipeline discovery error handling and test mock issue Co-authored-by: mudler <2420543+mudler@users.noreply.github.com> Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * Address code review feedback: direct imports, better error handling, improved tests Co-authored-by: mudler <2420543+mudler@users.noreply.github.com> Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * Address remaining code review feedback: specific exceptions, registry access, test imports Co-authored-by: mudler <2420543+mudler@users.noreply.github.com> Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * Add defensive fallback for DiffusionPipeline registry access Co-authored-by: mudler <2420543+mudler@users.noreply.github.com> Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * Actually use dynamic pipeline loading for all pipelines in backend Co-authored-by: mudler <2420543+mudler@users.noreply.github.com> Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * Use dynamic loader consistently for all pipelines including AutoPipelineForText2Image Co-authored-by: mudler <2420543+mudler@users.noreply.github.com> Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * Move dynamic loader tests into test.py for CI compatibility Co-authored-by: mudler <2420543+mudler@users.noreply.github.com> Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * Extend dynamic loader to discover any diffusers class type, not just DiffusionPipeline Co-authored-by: mudler <2420543+mudler@users.noreply.github.com> Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * Add AutoPipeline classes to pipeline registry for default model loading Co-authored-by: mudler <2420543+mudler@users.noreply.github.com> Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * fix(python): set pyvenv python home Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * do pyenv update during start Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * Minor changes Signed-off-by: Ettore Di Giacinto <mudler@localai.io> --------- Signed-off-by: Ettore Di Giacinto <mudler@localai.io> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: mudler <2420543+mudler@users.noreply.github.com> Co-authored-by: Ettore Di Giacinto <mudler@localai.io> Co-authored-by: Ettore Di Giacinto <mudler@users.noreply.github.com>
136 lines
4.7 KiB
Markdown
136 lines
4.7 KiB
Markdown
# LocalAI Diffusers Backend
|
|
|
|
This backend provides gRPC access to Hugging Face diffusers pipelines with dynamic pipeline loading.
|
|
|
|
## Creating a separate environment for the diffusers project
|
|
|
|
```
|
|
make diffusers
|
|
```
|
|
|
|
## Dynamic Pipeline Loader
|
|
|
|
The diffusers backend includes a dynamic pipeline loader (`diffusers_dynamic_loader.py`) that automatically discovers and loads diffusers pipelines at runtime. This eliminates the need for per-pipeline conditional statements - new pipelines added to diffusers become available automatically without code changes.
|
|
|
|
### How It Works
|
|
|
|
1. **Pipeline Discovery**: On first use, the loader scans the `diffusers` package to find all classes that inherit from `DiffusionPipeline`.
|
|
|
|
2. **Registry Caching**: Discovery results are cached for the lifetime of the process to avoid repeated scanning.
|
|
|
|
3. **Task Aliases**: The loader automatically derives task aliases from class names (e.g., "text-to-image", "image-to-image", "inpainting") without hardcoding.
|
|
|
|
4. **Multiple Resolution Methods**: Pipelines can be resolved by:
|
|
- Exact class name (e.g., `StableDiffusionPipeline`)
|
|
- Task alias (e.g., `text-to-image`, `img2img`)
|
|
- Model ID (uses HuggingFace Hub to infer pipeline type)
|
|
|
|
### Usage Examples
|
|
|
|
```python
|
|
from diffusers_dynamic_loader import (
|
|
load_diffusers_pipeline,
|
|
get_available_pipelines,
|
|
get_available_tasks,
|
|
resolve_pipeline_class,
|
|
discover_diffusers_classes,
|
|
get_available_classes,
|
|
)
|
|
|
|
# List all available pipelines
|
|
pipelines = get_available_pipelines()
|
|
print(f"Available pipelines: {pipelines[:10]}...")
|
|
|
|
# List all task aliases
|
|
tasks = get_available_tasks()
|
|
print(f"Available tasks: {tasks}")
|
|
|
|
# Resolve a pipeline class by name
|
|
cls = resolve_pipeline_class(class_name="StableDiffusionPipeline")
|
|
|
|
# Resolve by task alias
|
|
cls = resolve_pipeline_class(task="stable-diffusion")
|
|
|
|
# Load and instantiate a pipeline
|
|
pipe = load_diffusers_pipeline(
|
|
class_name="StableDiffusionPipeline",
|
|
model_id="runwayml/stable-diffusion-v1-5",
|
|
torch_dtype=torch.float16
|
|
)
|
|
|
|
# Load from single file
|
|
pipe = load_diffusers_pipeline(
|
|
class_name="StableDiffusionPipeline",
|
|
model_id="/path/to/model.safetensors",
|
|
from_single_file=True,
|
|
torch_dtype=torch.float16
|
|
)
|
|
|
|
# Discover other diffusers classes (schedulers, models, etc.)
|
|
schedulers = discover_diffusers_classes("SchedulerMixin")
|
|
print(f"Available schedulers: {list(schedulers.keys())[:5]}...")
|
|
|
|
# Get list of available scheduler classes
|
|
scheduler_list = get_available_classes("SchedulerMixin")
|
|
```
|
|
|
|
### Generic Class Discovery
|
|
|
|
The dynamic loader can discover not just pipelines but any class type from diffusers:
|
|
|
|
```python
|
|
# Discover all scheduler classes
|
|
schedulers = discover_diffusers_classes("SchedulerMixin")
|
|
|
|
# Discover all model classes
|
|
models = discover_diffusers_classes("ModelMixin")
|
|
|
|
# Get a sorted list of available classes
|
|
scheduler_names = get_available_classes("SchedulerMixin")
|
|
```
|
|
|
|
### Special Pipeline Handling
|
|
|
|
Most pipelines are loaded dynamically through `load_diffusers_pipeline()`. Only pipelines requiring truly custom initialization logic are handled explicitly:
|
|
|
|
- `FluxTransformer2DModel`: Requires quantization and custom transformer loading (cannot use dynamic loader)
|
|
- `WanPipeline` / `WanImageToVideoPipeline`: Uses dynamic loader with special VAE (float32 dtype)
|
|
- `SanaPipeline`: Uses dynamic loader with post-load dtype conversion for VAE/text encoder
|
|
- `StableVideoDiffusionPipeline`: Uses dynamic loader with CPU offload handling
|
|
- `VideoDiffusionPipeline`: Alias for DiffusionPipeline with video flags
|
|
|
|
All other pipelines (StableDiffusionPipeline, StableDiffusionXLPipeline, FluxPipeline, etc.) are loaded purely through the dynamic loader.
|
|
|
|
### Error Handling
|
|
|
|
When a pipeline cannot be resolved, the loader provides helpful error messages listing available pipelines and tasks:
|
|
|
|
```
|
|
ValueError: Unknown pipeline class 'NonExistentPipeline'.
|
|
Available pipelines: AnimateDiffPipeline, AnimateDiffVideoToVideoPipeline, ...
|
|
```
|
|
|
|
## Environment Variables
|
|
|
|
| Variable | Default | Description |
|
|
|----------|---------|-------------|
|
|
| `COMPEL` | `0` | Enable Compel for prompt weighting |
|
|
| `XPU` | `0` | Enable Intel XPU support |
|
|
| `CLIPSKIP` | `1` | Enable CLIP skip support |
|
|
| `SAFETENSORS` | `1` | Use safetensors format |
|
|
| `CHUNK_SIZE` | `8` | Decode chunk size for video |
|
|
| `FPS` | `7` | Video frames per second |
|
|
| `DISABLE_CPU_OFFLOAD` | `0` | Disable CPU offload |
|
|
| `FRAMES` | `64` | Number of video frames |
|
|
| `BFL_REPO` | `ChuckMcSneed/FLUX.1-dev` | Flux base repo |
|
|
| `PYTHON_GRPC_MAX_WORKERS` | `1` | Max gRPC workers |
|
|
|
|
## Running Tests
|
|
|
|
```bash
|
|
./test.sh
|
|
```
|
|
|
|
The test suite includes:
|
|
- Unit tests for the dynamic loader (`test_dynamic_loader.py`)
|
|
- Integration tests for the gRPC backend (`test.py`) |