mirror of
https://github.com/leejet/stable-diffusion.cpp.git
synced 2026-11-09 18:36:33 +00:00
Compare commits
6
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e41fbcf455 | ||
|
|
012c7f8866 | ||
|
|
a5e48c66aa | ||
|
|
b29962db7a | ||
|
|
0f76bf5c1e | ||
|
|
bb6a0ccfa3 |
No files matched your search
@@ -26,6 +26,7 @@ on:
|
||||
"ggml",
|
||||
"examples/server/frontend",
|
||||
"examples/server/frontend/**",
|
||||
"examples/server/recipes/*.json",
|
||||
"start-server.sh",
|
||||
"start-server.bat",
|
||||
]
|
||||
@@ -46,6 +47,7 @@ on:
|
||||
"ggml",
|
||||
"examples/server/frontend",
|
||||
"examples/server/frontend/**",
|
||||
"examples/server/recipes/*.json",
|
||||
"start-server.sh",
|
||||
"start-server.bat",
|
||||
]
|
||||
|
||||
@@ -100,10 +100,13 @@ for individual references, identity images, or video control frames.
|
||||
--image-preprocess "target=control-frame,index=2,canny=true"
|
||||
```
|
||||
|
||||
Init and mask sources must have the same dimensions. The mask inherits the
|
||||
init crop, resize, and padding coordinates, while retaining its own filter,
|
||||
padding value, and Canny setting. Conflicting mask geometry is rejected. An
|
||||
omitted mask remains absent until the original pipeline creates its default mask.
|
||||
If init and mask source dimensions differ, the mask is first center-cropped to
|
||||
the init source aspect ratio and resized to the init source dimensions using
|
||||
nearest-exact interpolation. The mask then inherits the init crop, resize, and
|
||||
padding coordinates, while retaining its own filter, padding value, and Canny
|
||||
setting for that transform. Explicit mask geometry is evaluated after this
|
||||
alignment; conflicting geometry is rejected. An omitted mask remains absent
|
||||
until the original pipeline creates its default mask.
|
||||
|
||||
## Downstream behavior
|
||||
|
||||
|
||||
@@ -1959,6 +1959,7 @@ static bool parse_image_json_field(const json& parent,
|
||||
return decode_base64_image(parent.at(key).get<std::string>(), channels, 0, 0, out_image);
|
||||
}
|
||||
|
||||
/** Parses a JSON array of base64 image strings into owned images. */
|
||||
static bool parse_image_array_json_field(const json& parent,
|
||||
const char* key,
|
||||
int channels,
|
||||
@@ -1988,6 +1989,84 @@ static bool parse_image_array_json_field(const json& parent,
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Parses a JSON array of base64 WAV strings into owned audio clips. */
|
||||
static bool parse_audio_array_json_field(const json& parent,
|
||||
const char* key,
|
||||
std::vector<SDAudioOwner>& out_audios) {
|
||||
if (!parent.contains(key)) {
|
||||
return true;
|
||||
}
|
||||
if (parent.at(key).is_null()) {
|
||||
out_audios.clear();
|
||||
return true;
|
||||
}
|
||||
if (!parent.at(key).is_array()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
out_audios.clear();
|
||||
for (const auto& item : parent.at(key)) {
|
||||
if (!item.is_string()) {
|
||||
return false;
|
||||
}
|
||||
std::string encoded = item.get<std::string>();
|
||||
auto comma_pos = encoded.find(',');
|
||||
if (comma_pos != std::string::npos) {
|
||||
encoded = encoded.substr(comma_pos + 1);
|
||||
}
|
||||
std::vector<uint8_t> audio_bytes = decode_base64_bytes(encoded);
|
||||
if (audio_bytes.empty()) {
|
||||
return false;
|
||||
}
|
||||
std::vector<float> samples;
|
||||
uint32_t sample_rate = 0;
|
||||
uint32_t channels = 0;
|
||||
if (!load_wav_from_memory(audio_bytes.data(), audio_bytes.size(), samples, sample_rate, channels)) {
|
||||
return false;
|
||||
}
|
||||
SDAudioOwner audio;
|
||||
audio.reset(std::move(samples), sample_rate, channels);
|
||||
out_audios.push_back(std::move(audio));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Parses a JSON array of per-video base64 frame arrays into owned videos. */
|
||||
static bool parse_video_array_json_field(const json& parent,
|
||||
const char* key,
|
||||
std::vector<std::vector<SDImageOwner>>& out_videos) {
|
||||
if (!parent.contains(key)) {
|
||||
return true;
|
||||
}
|
||||
if (parent.at(key).is_null()) {
|
||||
out_videos.clear();
|
||||
return true;
|
||||
}
|
||||
if (!parent.at(key).is_array()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
out_videos.clear();
|
||||
for (const auto& video : parent.at(key)) {
|
||||
if (!video.is_array() || video.empty()) {
|
||||
return false;
|
||||
}
|
||||
std::vector<SDImageOwner> frames;
|
||||
for (const auto& frame : video) {
|
||||
if (!frame.is_string()) {
|
||||
return false;
|
||||
}
|
||||
SDImageOwner image;
|
||||
if (!decode_base64_image(frame.get<std::string>(), 0, 0, 0, image)) {
|
||||
return false;
|
||||
}
|
||||
frames.push_back(std::move(image));
|
||||
}
|
||||
out_videos.push_back(std::move(frames));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool parse_lora_json_field(const json& parent,
|
||||
const std::function<std::string(const std::string&)>& lora_path_resolver,
|
||||
std::map<std::string, float>& lora_map,
|
||||
@@ -2102,6 +2181,7 @@ bool SDGenerationParams::parse_image_preprocess_json(const std::string& json_str
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Populates generation params from a JSON payload (server APIs); returns false on any malformed field. */
|
||||
bool SDGenerationParams::from_json_str(
|
||||
const std::string& json_str,
|
||||
const std::function<std::string(const std::string&)>& lora_path_resolver) {
|
||||
@@ -2330,8 +2410,11 @@ bool SDGenerationParams::from_json_str(
|
||||
return false;
|
||||
}
|
||||
if (!parse_image_array_json_field(j, "ref_images", 0, ref_images) ||
|
||||
!parse_image_array_json_field(j, "control_frames", 3, control_frames)) {
|
||||
LOG_ERROR("invalid input image array");
|
||||
!parse_image_array_json_field(j, "control_frames", 3, control_frames) ||
|
||||
!parse_audio_array_json_field(j, "ref_audios", ref_audios) ||
|
||||
!parse_audio_array_json_field(j, "ref_video_audios", ref_video_audios) ||
|
||||
!parse_video_array_json_field(j, "ref_videos", ref_videos)) {
|
||||
LOG_ERROR("invalid input image/audio/video array");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -2583,6 +2666,7 @@ bool SDGenerationParams::resolve(const std::string& lora_model_dir, const std::s
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Validates params for a generation mode; enforces mode-specific input rules. */
|
||||
bool SDGenerationParams::validate(SDMode mode) {
|
||||
if (!image_preprocess.empty() && mode != IMG_GEN && mode != VID_GEN) {
|
||||
LOG_ERROR("--image-preprocess requires img_gen or vid_gen mode");
|
||||
@@ -2636,12 +2720,13 @@ bool SDGenerationParams::validate(SDMode mode) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ref_video_audio_paths.size() > ref_video_paths.size()) {
|
||||
if (ref_video_audio_paths.size() + ref_video_audios.size() > ref_video_paths.size() + ref_videos.size()) {
|
||||
LOG_ERROR("error: each --ref-video-audio needs a corresponding --ref-video");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mode != VID_GEN && (!ref_video_paths.empty() || !ref_video_audio_paths.empty() || !ref_audio_paths.empty())) {
|
||||
if (mode != VID_GEN && (!ref_video_paths.empty() || !ref_video_audio_paths.empty() || !ref_audio_paths.empty() ||
|
||||
!ref_videos.empty() || !ref_video_audios.empty() || !ref_audios.empty())) {
|
||||
LOG_ERROR("error: reference video and audio inputs require vid_gen mode");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1437,70 +1437,94 @@ static uint32_t read_le32(const uint8_t* data) {
|
||||
(static_cast<uint32_t>(data[3]) << 24);
|
||||
}
|
||||
|
||||
/** Loads a WAV file from disk and delegates decoding to load_wav_from_memory(). */
|
||||
bool load_wav_from_file(const std::string& path,
|
||||
std::vector<float>& interleaved_samples,
|
||||
uint32_t& sample_rate,
|
||||
uint32_t& channels) {
|
||||
std::ifstream file(fs::u8path(path), std::ios::binary);
|
||||
if (!file) {
|
||||
interleaved_samples.clear();
|
||||
sample_rate = 0;
|
||||
channels = 0;
|
||||
return false;
|
||||
}
|
||||
file.seekg(0, std::ios::end);
|
||||
const std::streamoff file_size = file.tellg();
|
||||
file.seekg(0, std::ios::beg);
|
||||
if (file_size < 0) {
|
||||
interleaved_samples.clear();
|
||||
sample_rate = 0;
|
||||
channels = 0;
|
||||
return false;
|
||||
}
|
||||
std::vector<uint8_t> buffer(static_cast<size_t>(file_size));
|
||||
if (file_size > 0 && !file.read(reinterpret_cast<char*>(buffer.data()), file_size)) {
|
||||
interleaved_samples.clear();
|
||||
sample_rate = 0;
|
||||
channels = 0;
|
||||
return false;
|
||||
}
|
||||
return load_wav_from_memory(buffer.data(), buffer.size(), interleaved_samples, sample_rate, channels);
|
||||
}
|
||||
|
||||
/** Parses a RIFF/WAVE buffer in place; compares chunk sizes against the remaining
|
||||
* bytes so payload-controlled sizes cannot wrap size_t on 32-bit builds. */
|
||||
bool load_wav_from_memory(const uint8_t* data,
|
||||
size_t size,
|
||||
std::vector<float>& interleaved_samples,
|
||||
uint32_t& sample_rate,
|
||||
uint32_t& channels) {
|
||||
interleaved_samples.clear();
|
||||
sample_rate = 0;
|
||||
channels = 0;
|
||||
|
||||
std::ifstream file(fs::u8path(path), std::ios::binary);
|
||||
uint8_t riff_header[12];
|
||||
if (!file.read(reinterpret_cast<char*>(riff_header), sizeof(riff_header)) ||
|
||||
std::memcmp(riff_header, "RIFF", 4) != 0 ||
|
||||
std::memcmp(riff_header + 8, "WAVE", 4) != 0) {
|
||||
if (data == nullptr ||
|
||||
size < 12 ||
|
||||
std::memcmp(data, "RIFF", 4) != 0 ||
|
||||
std::memcmp(data + 8, "WAVE", 4) != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint16_t audio_format = 0;
|
||||
uint16_t bits_per_sample = 0;
|
||||
uint16_t block_align = 0;
|
||||
std::streampos data_pos = std::streampos(-1);
|
||||
size_t data_pos = SIZE_MAX;
|
||||
uint32_t data_size = 0;
|
||||
|
||||
while (file.good()) {
|
||||
uint8_t chunk_header[8];
|
||||
if (!file.read(reinterpret_cast<char*>(chunk_header), sizeof(chunk_header))) {
|
||||
break;
|
||||
}
|
||||
uint32_t chunk_size = read_le32(chunk_header + 4);
|
||||
std::streampos chunk_data_pos = file.tellg();
|
||||
size_t pos = 12;
|
||||
while (pos + 8 <= size) {
|
||||
uint32_t chunk_size = read_le32(data + pos + 4);
|
||||
size_t chunk_data_pos = pos + 8;
|
||||
const size_t remaining = size - chunk_data_pos; // safe: chunk_data_pos <= size
|
||||
// Chunk sizes come from the payload, so compare against the remaining bytes
|
||||
// instead of adding them to offsets (avoids size_t wrap on 32-bit builds).
|
||||
const bool data_fits = static_cast<size_t>(chunk_size) <= remaining;
|
||||
|
||||
if (std::memcmp(chunk_header, "fmt ", 4) == 0) {
|
||||
if (chunk_size < 16) {
|
||||
if (std::memcmp(data + pos, "fmt ", 4) == 0) {
|
||||
if (chunk_size < 16 || !data_fits) {
|
||||
return false;
|
||||
}
|
||||
std::vector<uint8_t> fmt(chunk_size);
|
||||
if (!file.read(reinterpret_cast<char*>(fmt.data()), chunk_size)) {
|
||||
return false;
|
||||
}
|
||||
audio_format = read_le16(fmt.data());
|
||||
channels = read_le16(fmt.data() + 2);
|
||||
sample_rate = read_le32(fmt.data() + 4);
|
||||
block_align = read_le16(fmt.data() + 12);
|
||||
bits_per_sample = read_le16(fmt.data() + 14);
|
||||
audio_format = read_le16(data + chunk_data_pos);
|
||||
channels = read_le16(data + chunk_data_pos + 2);
|
||||
sample_rate = read_le32(data + chunk_data_pos + 4);
|
||||
block_align = read_le16(data + chunk_data_pos + 12);
|
||||
bits_per_sample = read_le16(data + chunk_data_pos + 14);
|
||||
if (audio_format == 0xfffe && chunk_size >= 40) {
|
||||
audio_format = read_le16(fmt.data() + 24);
|
||||
audio_format = read_le16(data + chunk_data_pos + 24);
|
||||
}
|
||||
} else if (std::memcmp(chunk_header, "data", 4) == 0) {
|
||||
} else if (std::memcmp(data + pos, "data", 4) == 0) {
|
||||
data_pos = chunk_data_pos;
|
||||
data_size = chunk_size;
|
||||
file.seekg(chunk_size, std::ios::cur);
|
||||
} else {
|
||||
file.seekg(chunk_size, std::ios::cur);
|
||||
}
|
||||
|
||||
if (!file.good()) {
|
||||
break;
|
||||
}
|
||||
if ((chunk_size & 1) != 0) {
|
||||
file.seekg(1, std::ios::cur);
|
||||
}
|
||||
// Only advance past a chunk whose size and pad byte fully fit (keeps the sum
|
||||
// overflow-free); a chunk truncated at the buffer end terminates the walk.
|
||||
const bool chunk_fits = data_fits && ((chunk_size & 1) == 0 || static_cast<size_t>(chunk_size) < remaining);
|
||||
pos = chunk_fits ? chunk_data_pos + static_cast<size_t>(chunk_size) + (chunk_size & 1) : size;
|
||||
}
|
||||
|
||||
const uint32_t bytes_per_sample = (bits_per_sample + 7) / 8;
|
||||
if (data_pos == std::streampos(-1) || data_size == 0 || channels == 0 || sample_rate == 0 ||
|
||||
if (data_pos == SIZE_MAX || data_size == 0 || channels == 0 || sample_rate == 0 ||
|
||||
block_align == 0 || bytes_per_sample == 0 || block_align < channels * bytes_per_sample ||
|
||||
(audio_format != 1 && audio_format != 3)) {
|
||||
return false;
|
||||
@@ -1510,16 +1534,14 @@ bool load_wav_from_file(const std::string& path,
|
||||
if (frame_count == 0 || frame_count > SIZE_MAX / channels) {
|
||||
return false;
|
||||
}
|
||||
std::vector<uint8_t> pcm(data_size);
|
||||
file.clear();
|
||||
file.seekg(data_pos);
|
||||
if (!file.read(reinterpret_cast<char*>(pcm.data()), data_size)) {
|
||||
if (static_cast<size_t>(data_size) > size - data_pos) {
|
||||
return false;
|
||||
}
|
||||
const uint8_t* pcm = data + data_pos;
|
||||
|
||||
interleaved_samples.resize(static_cast<size_t>(frame_count * channels));
|
||||
for (uint64_t frame = 0; frame < frame_count; ++frame) {
|
||||
const uint8_t* frame_data = pcm.data() + frame * block_align;
|
||||
const uint8_t* frame_data = pcm + frame * block_align;
|
||||
for (uint32_t channel = 0; channel < channels; ++channel) {
|
||||
const uint8_t* sample_data = frame_data + channel * bytes_per_sample;
|
||||
float sample = 0.0f;
|
||||
|
||||
@@ -126,4 +126,11 @@ bool load_wav_from_file(const std::string& path,
|
||||
uint32_t& sample_rate,
|
||||
uint32_t& channels);
|
||||
|
||||
/** Decodes a WAV buffer (PCM 8/16/24/32 or IEEE float 32/64) into interleaved samples. */
|
||||
bool load_wav_from_memory(const uint8_t* data,
|
||||
size_t size,
|
||||
std::vector<float>& interleaved_samples,
|
||||
uint32_t& sample_rate,
|
||||
uint32_t& channels);
|
||||
|
||||
#endif // __MEDIA_IO_H__
|
||||
@@ -89,8 +89,8 @@ FLUX 1/2/3, Chroma, Qwen Image and editing variants; Z-Image, Anima, ERNIE,
|
||||
LENS, PiD and other supported image families; AnimateDiff, Wan, LTX,
|
||||
HunyuanVideo, LingBot Video and MiniMax-H3. Model-specific text encoder
|
||||
labels identify the expected encoder family and size. Loading a video model enables **Video Generation**; I2V also requires a
|
||||
start image. The Models panel can be collapsed and remembers its open state.
|
||||
Its header shows elapsed loading time from the status API and keeps the final
|
||||
start image. The model button below the prompt opens model and recipe selection.
|
||||
Its status summary shows elapsed loading time from the status API and keeps the final
|
||||
time after success or failure, including after a page refresh.
|
||||
Built-ins are embedded in the
|
||||
binary from [recipes/](recipes/), with one JSON file per recipe. Adding or
|
||||
|
||||
+59
-4
@@ -183,6 +183,9 @@ Default-enabled features are `img2img`, `mask_image`, `lora`, `vae_tiling`,
|
||||
| `clip_skip` | CLIP Skip |
|
||||
| `img2img`, `mask_image` | Image initialization/strength and masks |
|
||||
| `ref_images` | Reference image inputs |
|
||||
| `ref_videos` | Reference videos as frame arrays |
|
||||
| `ref_audios` | Standalone reference audio; runtime requires an Audio VAE or Audio Encoder |
|
||||
| `ref_video_audios` | Soundtracks paired with reference videos; runtime requires an Audio VAE |
|
||||
| `controlnet` | Control image and ControlNet strength |
|
||||
| `control_image` | Control image without a separate ControlNet (FLUX Canny/Depth) |
|
||||
| `ip_adapter` | IP-Adapter image and strength |
|
||||
@@ -241,6 +244,7 @@ the same one-recipe-per-file schema:
|
||||
"id": "my-flux",
|
||||
"name": "My FLUX",
|
||||
"description": "FLUX.1 dev",
|
||||
"size_multiple": 16,
|
||||
"model_url": "https://huggingface.co/black-forest-labs/FLUX.1-dev",
|
||||
"slots": [
|
||||
{"id": "diffusion_model", "required": true},
|
||||
@@ -256,7 +260,8 @@ the same one-recipe-per-file schema:
|
||||
|
||||
IDs contain 1–128 ASCII letters, digits, dots, underscores or hyphens.
|
||||
`name`, `schema_version: 1` and `slots` are required; `description` and
|
||||
`model_url`, `required_any`, `defaults`, `context`, `features` and `disabled_features` are optional. Each slot requires only `id` and boolean `required`.
|
||||
`model_url`, `required_any`, `defaults`, `context`, `features`, `disabled_features`
|
||||
and `size_multiple`, `video_constraints` are optional. Each slot requires only `id` and boolean `required`.
|
||||
The server supplies the default label and search directories for each slot.
|
||||
An optional nonempty `label` overrides the display name, for example
|
||||
`{"id": "diffusion_model", "label": "Low-noise diffusion model", "required": true}`.
|
||||
@@ -264,6 +269,45 @@ Legacy `category` fields remain accepted, but must match one of the slot's
|
||||
supported directories; they cannot redefine or restrict its search directories.
|
||||
At least one required `model` or `diffusion_model` slot is necessary.
|
||||
|
||||
`size_multiple` is a positive integer from 1 to 4096 that declares the width and
|
||||
height increment used by the web UI. It defaults to `8` when omitted; the UI also
|
||||
uses `8` before a recipe is selected. For example, `"size_multiple": 16` makes
|
||||
generated size presets multiples of 16. Exact dimensions that do not match the
|
||||
increment require correction before submission. This is recipe metadata, not a
|
||||
generation parameter, and does not change the core model's alignment behavior.
|
||||
|
||||
`video_constraints` is optional metadata for the web UI's Frames / Duration
|
||||
controls. It does not override the runtime's model-specific rules. For example:
|
||||
|
||||
```json
|
||||
"video_constraints": {
|
||||
"frame_step": 4,
|
||||
"frame_offset": 1,
|
||||
"frame_rounding": "floor",
|
||||
"min_frames": 1
|
||||
}
|
||||
```
|
||||
|
||||
Legal frame counts are `frame_step * n + frame_offset`, with integer `n >= 0`,
|
||||
within the inclusive `min_frames` / `max_frames` range. All fields are optional:
|
||||
|
||||
| Field | Default | Accepted values |
|
||||
| --- | --- | --- |
|
||||
| `frame_step` | `1` | Integer 1–4096 |
|
||||
| `frame_offset` | `0` | Integer 0 to `frame_step - 1` |
|
||||
| `frame_rounding` | `"floor"` | `"floor"` or `"ceil"` |
|
||||
| `min_frames` | `1` | Integer 1–4096 |
|
||||
| `max_frames` | `4096` | Integer 1–4096, at least `min_frames` |
|
||||
| `fixed_fps` | Unset | Integer 1–240; locks the FPS control |
|
||||
|
||||
The range must contain at least one legal frame count. Unknown keys are rejected.
|
||||
Omitting the object adds no frame alignment in the UI. `defaults.fps` only sets
|
||||
the initial FPS; it does not lock it. The UI multiplies requested duration by FPS,
|
||||
aligns using the declared rounding direction, then clamps to the legal range.
|
||||
Duration stays in the UI; generation requests still send only `video_frames` and
|
||||
`fps`. Switching input modes preserves the aligned length. Changing FPS keeps
|
||||
frames in Frames mode, and keeps the requested seconds in Duration mode.
|
||||
|
||||
`model_url` is an optional HTTPS Hugging Face model repository link, shown beside
|
||||
the recipe description. Built-ins link to the model's author/publisher, not repacks.
|
||||
`required_any` contains groups of declared slot IDs. At least one model in each
|
||||
@@ -1690,15 +1734,26 @@ When omitted, backend defaults apply to these fields:
|
||||
|
||||
### Frame Count Semantics
|
||||
|
||||
`video_frames` is the requested target length, but the current core video path internally normalizes the effective frame count to the largest `4n + 1` value that does not exceed the requested count.
|
||||
`video_frames` is the requested target length. The core normalizes it according
|
||||
to the loaded model:
|
||||
|
||||
Examples:
|
||||
| Model family | Frame alignment | Fixed FPS |
|
||||
| --- | --- | --- |
|
||||
| Wan, HunyuanVideo, LingBot | `4n + 1`, round down | Wan 2.2 S2V: 16 |
|
||||
| LTX | `8n + 1`, round down | None |
|
||||
| MiniMax-H3 | `17n + 5`, round up, minimum 5 | 24 |
|
||||
| AnimateDiff | Whole frames, maximum 32 | None |
|
||||
|
||||
Wan examples:
|
||||
|
||||
- `video_frames = 33` stays `33`
|
||||
- `video_frames = 34` becomes `33`
|
||||
- `video_frames = 32` becomes `29`
|
||||
|
||||
The completed job payload includes the actual decoded `frame_count`.
|
||||
At 16 FPS, a 5-second target requests 80 frames and aligns to 77 frames for Wan,
|
||||
or approximately 4.813 seconds. Audio-driven generation and temporal upscaling
|
||||
can change the final length. Use the completed job's actual decoded `frame_count`
|
||||
and `fps` for the final playback duration.
|
||||
|
||||
### Completion Result
|
||||
|
||||
|
||||
+1
-1
Submodule examples/server/frontend updated: 34e5ad6edc...fa93429c47.
@@ -291,6 +291,7 @@ static void apply_recipe_context(const json& settings, SDContextParams& params)
|
||||
}
|
||||
}
|
||||
|
||||
// Known recipe feature names with their defaults; recipes may flip any of these.
|
||||
static const std::map<std::string, bool> k_recipe_features = {
|
||||
{"img2img", true},
|
||||
{"mask_image", true},
|
||||
@@ -312,6 +313,9 @@ static const std::map<std::string, bool> k_recipe_features = {
|
||||
{"init_image", false},
|
||||
{"end_image", false},
|
||||
{"control_frames", false},
|
||||
{"ref_videos", false},
|
||||
{"ref_audios", false},
|
||||
{"ref_video_audios", false},
|
||||
{"vace", false},
|
||||
{"high_noise", false},
|
||||
{"cache_unet", false},
|
||||
@@ -365,17 +369,44 @@ json model_generation_features(const ServerRuntime& runtime) {
|
||||
if (runtime.models->active_recipe.value("source", "") == "command_line")
|
||||
return features;
|
||||
// Optional components only become usable once selected and loaded.
|
||||
features["ip_adapter"] = features.value("ip_adapter", false) && !runtime.ctx_params->ip_adapter_path.empty();
|
||||
features["controlnet"] = features.value("controlnet", false) && !runtime.ctx_params->control_net_path.empty();
|
||||
features["high_noise"] = features.value("high_noise", false) && !runtime.ctx_params->high_noise_diffusion_model_path.empty();
|
||||
features["preview_tae"] = features.value("preview_tae", false) && !runtime.ctx_params->taesd_path.empty();
|
||||
features["ip_adapter"] = features.value("ip_adapter", false) && !runtime.ctx_params->ip_adapter_path.empty();
|
||||
features["controlnet"] = features.value("controlnet", false) && !runtime.ctx_params->control_net_path.empty();
|
||||
features["high_noise"] = features.value("high_noise", false) && !runtime.ctx_params->high_noise_diffusion_model_path.empty();
|
||||
features["preview_tae"] = features.value("preview_tae", false) && !runtime.ctx_params->taesd_path.empty();
|
||||
features["ref_audios"] = features.value("ref_audios", false) &&
|
||||
(!runtime.ctx_params->audio_vae_path.empty() || !runtime.ctx_params->audio_encoder_path.empty());
|
||||
features["ref_video_audios"] = features.value("ref_video_audios", false) && !runtime.ctx_params->audio_vae_path.empty();
|
||||
if (!runtime.ctx_params->pulid_weights_path.empty())
|
||||
features["slg"] = false;
|
||||
return features;
|
||||
}
|
||||
|
||||
static void validate_video_constraints(const json& constraints) {
|
||||
check_keys(constraints, {"frame_step", "frame_offset", "frame_rounding", "min_frames", "max_frames", "fixed_fps"});
|
||||
for (const auto* key : {"frame_step", "frame_offset", "min_frames", "max_frames", "fixed_fps"}) {
|
||||
const int minimum = std::string(key) == "frame_offset" ? 0 : 1;
|
||||
const int maximum = std::string(key) == "fixed_fps" ? 240 : 4096;
|
||||
if (constraints.contains(key) &&
|
||||
(!constraints[key].is_number_integer() || constraints[key] < minimum || constraints[key] > maximum)) {
|
||||
throw std::runtime_error(std::string("video_constraints.") + key + " is outside its integer range");
|
||||
}
|
||||
}
|
||||
const int step = constraints.value("frame_step", 1);
|
||||
const int offset = constraints.value("frame_offset", 0);
|
||||
const int minimum = constraints.value("min_frames", 1);
|
||||
const int maximum = constraints.value("max_frames", 4096);
|
||||
if (offset >= step || minimum > maximum ||
|
||||
offset + std::max(0, (minimum - offset + step - 1) / step) * step > maximum) {
|
||||
throw std::runtime_error("video_constraints must describe a nonempty frame range with frame_offset < frame_step");
|
||||
}
|
||||
if (constraints.contains("frame_rounding") &&
|
||||
constraints["frame_rounding"] != "floor" && constraints["frame_rounding"] != "ceil") {
|
||||
throw std::runtime_error("video_constraints.frame_rounding must be floor or ceil");
|
||||
}
|
||||
}
|
||||
|
||||
static void validate_recipe(const json& recipe) {
|
||||
check_keys(recipe, {"schema_version", "id", "name", "description", "model_url", "slots", "required_any", "defaults", "context", "features", "disabled_features"});
|
||||
check_keys(recipe, {"schema_version", "id", "name", "description", "model_url", "slots", "required_any", "defaults", "context", "features", "disabled_features", "size_multiple", "video_constraints"});
|
||||
if (!recipe.at("schema_version").is_number_integer() || recipe.at("schema_version") != 1 ||
|
||||
!valid_identifier(recipe.at("id").get<std::string>()) || recipe.at("name").get<std::string>().empty()) {
|
||||
throw std::runtime_error("invalid schema_version, id or name");
|
||||
@@ -383,6 +414,13 @@ static void validate_recipe(const json& recipe) {
|
||||
if (recipe.contains("description") && !recipe["description"].is_string()) {
|
||||
throw std::runtime_error("description must be a string");
|
||||
}
|
||||
if (recipe.contains("size_multiple") &&
|
||||
(!recipe["size_multiple"].is_number_integer() || recipe["size_multiple"] < 1 || recipe["size_multiple"] > 4096)) {
|
||||
throw std::runtime_error("size_multiple must be an integer from 1 to 4096");
|
||||
}
|
||||
if (recipe.contains("video_constraints")) {
|
||||
validate_video_constraints(recipe["video_constraints"]);
|
||||
}
|
||||
if (recipe.contains("model_url")) {
|
||||
const auto url = recipe.at("model_url").get<std::string>();
|
||||
const std::string prefix = "https://huggingface.co/";
|
||||
@@ -435,6 +473,7 @@ static void validate_recipe(const json& recipe) {
|
||||
|
||||
static json normalize_recipe(json recipe) {
|
||||
validate_recipe(recipe);
|
||||
recipe["size_multiple"] = recipe.value("size_multiple", 8);
|
||||
recipe["effective_features"] = resolve_recipe_features(recipe);
|
||||
for (auto& slot : recipe.at("slots")) {
|
||||
const auto& spec = *find_model_slot(slot.at("id").get<std::string>());
|
||||
@@ -598,6 +637,7 @@ void initialize_server_models(ServerRuntime& runtime) {
|
||||
{"description", "Uses the loaded command-line model and its generation defaults."},
|
||||
{"slots", json::array()},
|
||||
{"defaults", json::object()},
|
||||
{"size_multiple", 8},
|
||||
{"features", features},
|
||||
};
|
||||
models.active_recipe["effective_features"] = resolve_recipe_features(models.active_recipe);
|
||||
|
||||
@@ -77,3 +77,35 @@ These are built-in catalog rules. Users may keep personal presets in
|
||||
`<model-dir>/recipes/`; they need not add those presets to the built-in list.
|
||||
See [the recipe schema and feature reference](../api.md#user-recipe-format)
|
||||
for supported fields.
|
||||
|
||||
## Output dimension alignment
|
||||
|
||||
Set `size_multiple` when the runtime's output dimension alignment differs from
|
||||
the default of `8`. Match `GenerationRequest::align_image_size` in
|
||||
[`src/pipeline/request.cpp`](../../../src/pipeline/request.cpp): the VAE scale
|
||||
factor multiplied by the model definition's `diffusion_down_factor`. The scale
|
||||
comes from [`VAE::get_scale_factor`](../../../src/model/vae/vae.hpp), with the
|
||||
PiD override in [`diffusion_engine.cpp`](../../../src/pipeline/diffusion_engine.cpp);
|
||||
model geometry is defined under [`src/model/integrations`](../../../src/model/integrations/).
|
||||
|
||||
Use the runtime's output alignment, not the nominal patch size: some models pad
|
||||
patches internally and crop their output back to the requested size. Pixel-space
|
||||
models with an alignment of `1` explicitly use `size_multiple: 1`. MiniT2I also
|
||||
has this alignment, but its separate fixed `512 × 512` output restriction still
|
||||
applies. Reference-image preprocessing constraints are independent of this field.
|
||||
|
||||
## Video length constraints
|
||||
|
||||
Video recipes declare `video_constraints` to match `align_video_frames` in
|
||||
[`diffusion_engine.cpp`](../../../src/pipeline/diffusion_engine.cpp) and the FPS
|
||||
and AnimateDiff overrides in
|
||||
[`request.cpp`](../../../src/pipeline/request.cpp). Wan, HunyuanVideo and LingBot
|
||||
round down to `4n + 1`; LTX rounds down to `8n + 1`. MiniMax-H3 rounds up to
|
||||
`17n + 5`, with at least 5 frames and fixed 24 FPS. AnimateDiff accepts whole
|
||||
frames up to 32. Wan 2.2 S2V fixes FPS at 16.
|
||||
|
||||
Declare fixed FPS only where the runtime enforces it; recommended FPS belongs
|
||||
in `defaults.fps`. These constraints guide UI conversion and estimates, not
|
||||
runtime behavior. Audio-driven output and temporal upscaling may still change
|
||||
the final frame count. See the [recipe schema](../api.md#user-recipe-format)
|
||||
for field defaults and validation rules.
|
||||
@@ -2,6 +2,7 @@
|
||||
"schema_version": 1,
|
||||
"id": "animatediff-sd15",
|
||||
"name": "AnimateDiff SD 1.5",
|
||||
"size_multiple": 64,
|
||||
"description": "Use Video Generation with an SD 1.5 checkpoint and compatible motion module.",
|
||||
"model_url": "https://huggingface.co/guoyww/animatediff",
|
||||
"slots": [
|
||||
@@ -22,6 +23,13 @@
|
||||
"required": false
|
||||
}
|
||||
],
|
||||
"video_constraints": {
|
||||
"frame_step": 1,
|
||||
"frame_offset": 0,
|
||||
"frame_rounding": "floor",
|
||||
"min_frames": 1,
|
||||
"max_frames": 32
|
||||
},
|
||||
"defaults": {
|
||||
"sampling_method": "euler",
|
||||
"video_frames": 8,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"schema_version": 1,
|
||||
"id": "chroma-radiance",
|
||||
"name": "Chroma Radiance",
|
||||
"size_multiple": 1,
|
||||
"description": "Pixel-space generation without a VAE. Also accepts the x0 and experimental patch-32 variants.",
|
||||
"model_url": "https://huggingface.co/lodestones/Chroma1-Radiance",
|
||||
"slots": [
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"schema_version": 1,
|
||||
"id": "cosxl-edit",
|
||||
"name": "CosXL Edit",
|
||||
"size_multiple": 64,
|
||||
"description": "Supply the image to edit as a reference image.",
|
||||
"model_url": "https://huggingface.co/stabilityai/cosxl",
|
||||
"slots": [
|
||||
|
||||
@@ -5,6 +5,9 @@ Reviewed against model-publisher cards and reference implementations on 2026-10-
|
||||
These are starting values, not limits on supported resolutions or generation settings.
|
||||
Built-in step defaults above 20 are reduced to 20; the cited sources may recommend more steps.
|
||||
Users can still choose a higher step count.
|
||||
Except for PiD recipes, built-in dimensions above 1,048,576 pixels (1024 x 1024) are reduced to 1024 x 1024, even when the cited source uses a larger size.
|
||||
PiD recipes retain their 2048 x 2048 defaults.
|
||||
Users can still choose a higher resolution.
|
||||
When several aspect ratios or ranges are published, the selected example or square bucket is noted below.
|
||||
A dash means no recipe override: the available primary sources did not establish a fixed value, or the size depends on the input image.
|
||||
Ordinary DiT recipes explicitly use Euler; PiD retains its LCM sampling path.
|
||||
@@ -27,7 +30,7 @@ For community edit adapters and other optional extensions, these are the base-mo
|
||||
| `flux1-canny` | 1 | 20 | 1024 × 1024 | [Source](https://huggingface.co/black-forest-labs/FLUX.1-Canny-dev) |
|
||||
| `flux1-depth` | 1 | 20 | 1024 × 1024 | [Source](https://huggingface.co/black-forest-labs/FLUX.1-Depth-dev) |
|
||||
| `flux1-dev` | 1 | 20 | 1024 × 1024 | [Source](https://huggingface.co/black-forest-labs/FLUX.1-dev) |
|
||||
| `flux1-fill` | 1 | 20 | 1232 × 1632 | [Source](https://huggingface.co/black-forest-labs/FLUX.1-Fill-dev) |
|
||||
| `flux1-fill` | 1 | 20 | 1024 × 1024 | [Source](https://huggingface.co/black-forest-labs/FLUX.1-Fill-dev) |
|
||||
| `flux1-kontext` | 1 | 20 | — | [Source](https://raw.githubusercontent.com/huggingface/diffusers/main/src/diffusers/pipelines/flux/pipeline_flux_kontext.py) Output size normally follows the reference image; no fixed size is imposed by this recipe. |
|
||||
| `flux1-pulid` | 1 | 20 | 1024 × 1024 | [Source](https://huggingface.co/black-forest-labs/FLUX.1-dev) FLUX.1-dev defaults; identity conditioning is provided by PuLID. |
|
||||
| `flux1-schnell` | 1 | 4 | 1024 × 1024 | [Source](https://huggingface.co/black-forest-labs/FLUX.1-schnell) |
|
||||
@@ -38,7 +41,7 @@ For community edit adapters and other optional extensions, these are the base-mo
|
||||
| `flux2-klein-base-9b` | 4 | 20 | 1024 × 1024 | [Source](https://huggingface.co/black-forest-labs/FLUX.2-klein-base-9B) |
|
||||
| `flux3-klein` | 1 | 16 | 1024 × 1024 | [Source](https://raw.githubusercontent.com/black-forest-labs/flux-3-image-klein/main/README.md) |
|
||||
| `flux3-klein-base` | 4 | 20 | 1024 × 1024 | [Source](https://raw.githubusercontent.com/black-forest-labs/flux-3-image-klein/main/src/flux3/pipeline.py) |
|
||||
| `hidream-o1-dev` | 1 | 20 | 2048 × 2048 | [Source](https://huggingface.co/HiDream-ai/HiDream-O1-Image-Dev) |
|
||||
| `hidream-o1-dev` | 1 | 20 | 1024 × 1024 | [Source](https://huggingface.co/HiDream-ai/HiDream-O1-Image-Dev) |
|
||||
| `hunyuan-video-15-i2v` | 6 | 20 | 1280 × 720 | [Source](https://huggingface.co/tencent/HunyuanVideo-1.5) 720p base I2V defaults; CFG/step-distilled and 480p checkpoints use different settings. |
|
||||
| `hunyuan-video-15-t2v` | 6 | 20 | 1280 × 720 | [Source](https://huggingface.co/tencent/HunyuanVideo-1.5) 720p base T2V defaults; CFG-distilled / 480p checkpoints need their published settings. |
|
||||
| `ideogram4` | 7 | 20 | 1024 × 1024 | [Source](https://raw.githubusercontent.com/ideogram-oss/ideogram4/main/docs/inference.md) Constant-guidance pipeline defaults; this recipe does not reproduce the CLI’s per-step guidance schedule. |
|
||||
@@ -46,10 +49,10 @@ For community edit adapters and other optional extensions, these are the base-mo
|
||||
| `iris-3b` | 3 | 20 | 1024 × 1024 | [Source](https://huggingface.co/speridlabs/iris-3b) |
|
||||
| `krea2-raw` | 3.5 | 20 | 1024 × 1024 | [Source](https://huggingface.co/krea/Krea-2-Raw) Base model defaults; edit requires a matching community LoRA with its own settings. |
|
||||
| `krea2-raw-edit` | 3.5 | 20 | 1024 × 1024 | [Source](https://huggingface.co/krea/Krea-2-Raw) Base model defaults; edit requires a matching community LoRA with its own settings. |
|
||||
| `krea2-turbo` | 1 | 8 | 2048 × 2048 | [Source](https://huggingface.co/krea/Krea-2-Turbo) Official CLI example; edit requires a matching community LoRA. |
|
||||
| `krea2-turbo-edit` | 1 | 8 | 2048 × 2048 | [Source](https://huggingface.co/krea/Krea-2-Turbo) Official CLI example; edit requires a matching community LoRA. |
|
||||
| `lens` | 5 | 20 | 1440 × 1440 | [Source](https://huggingface.co/microsoft/Lens) Official model card: RL model, default base_resolution 1440. |
|
||||
| `lens-turbo` | 1 | 4 | 1440 × 1440 | [Source](https://huggingface.co/microsoft/Lens-Turbo) Official model card: 4-step distilled model, default base_resolution 1440. |
|
||||
| `krea2-turbo` | 1 | 8 | 1024 × 1024 | [Source](https://huggingface.co/krea/Krea-2-Turbo) Official CLI example; edit requires a matching community LoRA. |
|
||||
| `krea2-turbo-edit` | 1 | 8 | 1024 × 1024 | [Source](https://huggingface.co/krea/Krea-2-Turbo) Official CLI example; edit requires a matching community LoRA. |
|
||||
| `lens` | 5 | 20 | 1024 × 1024 | [Source](https://huggingface.co/microsoft/Lens) Official model card: RL model, default base_resolution 1440. |
|
||||
| `lens-turbo` | 1 | 4 | 1024 × 1024 | [Source](https://huggingface.co/microsoft/Lens-Turbo) Official model card: 4-step distilled model, default base_resolution 1440. |
|
||||
| `lingbot-video-dense` | 3 | 20 | 832 × 480 | [Source](https://huggingface.co/robbyant/lingbot-video-dense-1.3b) Official first-stage inference example; optional refiner is separate. |
|
||||
| `lingbot-video-moe` | 3 | 20 | 832 × 480 | [Source](https://huggingface.co/robbyant/lingbot-video-moe-30b-a3b) Official inference example. |
|
||||
| `llada-image` | 5 | 20 | 1024 × 1024 | [Source](https://huggingface.co/inclusionAI/LLaDA-Image) |
|
||||
@@ -62,7 +65,7 @@ For community edit adapters and other optional extensions, these are the base-mo
|
||||
| `mage-flow` | 5 | 20 | 1024 × 1024 | [Source](https://huggingface.co/microsoft/Mage-Flow) |
|
||||
| `mage-flow-edit` | 5 | 20 | 1024 × 1024 | [Source](https://huggingface.co/microsoft/Mage-Flow) |
|
||||
| `mage-flow-turbo` | 1 | 4 | 1024 × 1024 | [Source](https://huggingface.co/microsoft/Mage-Flow) |
|
||||
| `ming-image` | 1 | 12 | 2048 × 2048 | [Source](https://huggingface.co/inclusionAI/Ming-Image-0.1-Design) |
|
||||
| `ming-image` | 1 | 12 | 1024 × 1024 | [Source](https://huggingface.co/inclusionAI/Ming-Image-0.1-Design) |
|
||||
| `minimax-h3-fl2va` | 1 | — | 1344 × 768 | [Source](https://huggingface.co/docs/diffusers/main/en/api/pipelines/minimax_h3) Guidance-distilled; official 768p canvas. No fixed step count is prescribed here; the upstream API counts sigma grid points rather than sd.cpp denoising steps. |
|
||||
| `minimax-h3-ref2va` | 1 | — | 1344 × 768 | [Source](https://huggingface.co/docs/diffusers/main/en/api/pipelines/minimax_h3) Guidance-distilled; official 768p canvas. No fixed step count is prescribed here; the upstream API counts sigma grid points rather than sd.cpp denoising steps. |
|
||||
| `minit2i` | 2.5 | 20 | 512 × 512 | [Source](https://huggingface.co/MiniT2I/MiniT2I/raw/main/pipeline.py) B/16 example and native model size; L/16 uses CFG 6. |
|
||||
@@ -81,9 +84,9 @@ For community edit adapters and other optional extensions, these are the base-mo
|
||||
| `pixart-alpha-1024` | 4.5 | 20 | 1024 × 1024 | [Source](https://raw.githubusercontent.com/huggingface/diffusers/main/src/diffusers/pipelines/pixart_alpha/pipeline_pixart_alpha.py) |
|
||||
| `pixart-alpha-512` | 4.5 | 20 | 512 × 512 | [Source](https://raw.githubusercontent.com/huggingface/diffusers/main/src/diffusers/pipelines/pixart_alpha/pipeline_pixart_alpha.py) |
|
||||
| `pixart-sigma` | 4.5 | 20 | 1024 × 1024 | [Source](https://raw.githubusercontent.com/huggingface/diffusers/main/src/diffusers/pipelines/pixart_alpha/pipeline_pixart_sigma.py) |
|
||||
| `qwen-image` | 4 | 20 | 1328 × 1328 | [Source](https://huggingface.co/Qwen/Qwen-Image) Official square resolution bucket; true_cfg_scale maps to cfg_scale. |
|
||||
| `qwen-image-21` | 1 | 20 | 2048 × 2048 | [Source](https://raw.githubusercontent.com/QwenLM/Qwen-Image-2.1/main/README.md) Original checkpoint defaults; select the matching TAEQI2.1 to replace its VAE. |
|
||||
| `qwen-image-21-turbo` | 1 | 8 | 2048 × 2048 | [Model card](https://huggingface.co/Qwen/Qwen-Image-2.1-Turbo), [fixed sigmas](https://huggingface.co/Qwen/Qwen-Image-2.1-Turbo/blob/main/model_index.json). Standalone Turbo weights; the fixed 8-step schedule is applied on model load. |
|
||||
| `qwen-image` | 4 | 20 | 1024 × 1024 | [Source](https://huggingface.co/Qwen/Qwen-Image) The source uses a larger square resolution bucket; true_cfg_scale maps to cfg_scale. |
|
||||
| `qwen-image-21` | 1 | 20 | 1024 × 1024 | [Source](https://raw.githubusercontent.com/QwenLM/Qwen-Image-2.1/main/README.md) Original checkpoint sampling defaults; select the matching TAEQI2.1 to replace its VAE. |
|
||||
| `qwen-image-21-turbo` | 1 | 8 | 1024 × 1024 | [Model card](https://huggingface.co/Qwen/Qwen-Image-2.1-Turbo), [fixed sigmas](https://huggingface.co/Qwen/Qwen-Image-2.1-Turbo/blob/main/model_index.json). Standalone Turbo weights; the fixed 8-step schedule is applied on model load. |
|
||||
| `qwen-image-edit` | 4 | 20 | — | [Source](https://huggingface.co/Qwen/Qwen-Image-Edit) Official editing example; output dimensions follow reference-image aspect ratio. |
|
||||
| `qwen-image-edit-2509` | 4 | 20 | — | [Source](https://huggingface.co/Qwen/Qwen-Image-Edit-2509) Official editing example; output dimensions follow reference-image aspect ratio. |
|
||||
| `qwen-image-edit-2511` | 4 | 20 | — | [Source](https://huggingface.co/Qwen/Qwen-Image-Edit-2511) Official editing example; output dimensions follow reference-image aspect ratio. |
|
||||
@@ -107,7 +110,7 @@ For community edit adapters and other optional extensions, these are the base-mo
|
||||
| `sdxl-turbo` | 1 | 1 | 512 × 512 | [Source](https://huggingface.co/stabilityai/sdxl-turbo) |
|
||||
| `sdxs` | 1 | 1 | 512 × 512 | [Source](https://huggingface.co/IDKiro/sdxs-512-dreamshaper) |
|
||||
| `sefi-image` | 4 | 20 | — | [Source](https://huggingface.co/SeFi-Image/SeFi-Image-5B-Base) Base/RL family defaults; Turbo checkpoints require 4 steps / CFG 1. |
|
||||
| `sensenova-u15` | 4 | 20 | 2048 × 2048 | [Source](https://raw.githubusercontent.com/OpenSenseNova/SenseNova-U1/main/examples/README.md) |
|
||||
| `sensenova-u15` | 4 | 20 | 1024 × 1024 | [Source](https://raw.githubusercontent.com/OpenSenseNova/SenseNova-U1/main/examples/README.md) |
|
||||
| `wan21-flf2v` | 5 | 20 | 1280 × 720 | [Source](https://raw.githubusercontent.com/Wan-Video/Wan2.1/main/generate.py) |
|
||||
| `wan21-i2v` | 5 | 20 | 832 × 480 | [Source](https://raw.githubusercontent.com/Wan-Video/Wan2.1/main/generate.py) 480p base defaults; also accepts compatible SkyReels V2 and single Wan 2.2 I2V experts. |
|
||||
| `wan21-t2v` | 5 | 20 | 1280 × 720 | [Source](https://raw.githubusercontent.com/Wan-Video/Wan2.1/main/generate.py) 14B base defaults; single Wan 2.2 experts and acceleration LoRAs need matching settings. |
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"schema_version": 1,
|
||||
"id": "ernie-image-turbo",
|
||||
"name": "ERNIE Image Turbo",
|
||||
"size_multiple": 16,
|
||||
"model_url": "https://huggingface.co/baidu/ERNIE-Image-Turbo",
|
||||
"slots": [
|
||||
{
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"schema_version": 1,
|
||||
"id": "ernie-image",
|
||||
"name": "ERNIE Image",
|
||||
"size_multiple": 16,
|
||||
"model_url": "https://huggingface.co/baidu/ERNIE-Image",
|
||||
"slots": [
|
||||
{
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"schema_version": 1,
|
||||
"id": "fibo2-dev",
|
||||
"name": "Fibo 2.0 Dev",
|
||||
"size_multiple": 16,
|
||||
"description": "Text-to-image generation and native reference-image editing. Select a separate vision projector for editing when it is not bundled in the text encoder.",
|
||||
"model_url": "https://huggingface.co/briaai/Fibo-2.0-dev",
|
||||
"slots": [
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"schema_version": 1,
|
||||
"id": "fibo2-edit-turbo",
|
||||
"name": "Fibo 2.0 Edit Turbo",
|
||||
"size_multiple": 16,
|
||||
"description": "Dedicated reference-image editing checkpoint; supply reference images. Select a separate vision projector when it is not bundled in the text encoder.",
|
||||
"model_url": "https://huggingface.co/briaai/Fibo-2.0-edit-turbo",
|
||||
"slots": [
|
||||
|
||||
@@ -39,8 +39,8 @@
|
||||
"scheduler": "flux",
|
||||
"cfg_scale": 1,
|
||||
"steps": 20,
|
||||
"width": 1232,
|
||||
"height": 1632
|
||||
"width": 1024,
|
||||
"height": 1024
|
||||
},
|
||||
"features": [
|
||||
"clip_skip",
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"schema_version": 1,
|
||||
"id": "flux2-dev",
|
||||
"name": "FLUX.2 dev",
|
||||
"size_multiple": 16,
|
||||
"description": "Supports text-to-image and reference-image editing.",
|
||||
"model_url": "https://huggingface.co/black-forest-labs/FLUX.2-dev",
|
||||
"slots": [
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"schema_version": 1,
|
||||
"id": "flux2-klein-4b",
|
||||
"name": "FLUX.2 Klein 4B",
|
||||
"size_multiple": 16,
|
||||
"description": "Supports reference-image editing. The FLUX.2 small decoder is an alternative VAE.",
|
||||
"model_url": "https://huggingface.co/black-forest-labs/FLUX.2-klein-4B",
|
||||
"slots": [
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"schema_version": 1,
|
||||
"id": "flux2-klein-9b",
|
||||
"name": "FLUX.2 Klein 9B",
|
||||
"size_multiple": 16,
|
||||
"description": "Supports text-to-image and reference-image editing.",
|
||||
"model_url": "https://huggingface.co/black-forest-labs/FLUX.2-klein-9B",
|
||||
"slots": [
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"schema_version": 1,
|
||||
"id": "flux2-klein-base-4b",
|
||||
"name": "FLUX.2 Klein Base 4B",
|
||||
"size_multiple": 16,
|
||||
"description": "Supports text-to-image and reference-image editing.",
|
||||
"model_url": "https://huggingface.co/black-forest-labs/FLUX.2-klein-base-4B",
|
||||
"slots": [
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"schema_version": 1,
|
||||
"id": "flux2-klein-base-9b",
|
||||
"name": "FLUX.2 Klein Base 9B",
|
||||
"size_multiple": 16,
|
||||
"description": "Use the 9B base transformer with Qwen 3 8B. Supports reference-image editing.",
|
||||
"model_url": "https://huggingface.co/black-forest-labs/FLUX.2-klein-base-9B",
|
||||
"slots": [
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"schema_version": 1,
|
||||
"id": "flux3-klein-base",
|
||||
"name": "FLUX.3 Image Klein Base",
|
||||
"size_multiple": 16,
|
||||
"model_url": "https://huggingface.co/black-forest-labs/flux-3-image-klein-base",
|
||||
"slots": [
|
||||
{
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"schema_version": 1,
|
||||
"id": "flux3-klein",
|
||||
"name": "FLUX.3 Image Klein",
|
||||
"size_multiple": 16,
|
||||
"description": "Supports text-to-image and reference-image editing.",
|
||||
"model_url": "https://huggingface.co/black-forest-labs/flux-3-image-klein",
|
||||
"slots": [
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"schema_version": 1,
|
||||
"id": "hidream-o1-dev",
|
||||
"name": "HiDream O1 Image dev",
|
||||
"size_multiple": 1,
|
||||
"description": "Bundled checkpoint; also supports reference-image editing.",
|
||||
"model_url": "https://huggingface.co/HiDream-ai/HiDream-O1-Image-Dev",
|
||||
"slots": [
|
||||
@@ -13,8 +14,8 @@
|
||||
"defaults": {
|
||||
"cfg_scale": 1,
|
||||
"steps": 20,
|
||||
"width": 2048,
|
||||
"height": 2048,
|
||||
"width": 1024,
|
||||
"height": 1024,
|
||||
"sampling_method": "euler"
|
||||
},
|
||||
"features": [
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"schema_version": 1,
|
||||
"id": "hunyuan-video-15-i2v",
|
||||
"name": "HunyuanVideo 1.5 I2V",
|
||||
"size_multiple": 16,
|
||||
"description": "Select HunyuanVideo 1.5 I2V weights and supply a start image in Video Generation.",
|
||||
"model_url": "https://huggingface.co/tencent/HunyuanVideo-1.5",
|
||||
"slots": [
|
||||
@@ -36,6 +37,12 @@
|
||||
"tae"
|
||||
]
|
||||
],
|
||||
"video_constraints": {
|
||||
"frame_step": 4,
|
||||
"frame_offset": 1,
|
||||
"frame_rounding": "floor",
|
||||
"min_frames": 1
|
||||
},
|
||||
"defaults": {
|
||||
"sampling_method": "euler",
|
||||
"video_frames": 33,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"schema_version": 1,
|
||||
"id": "hunyuan-video-15-t2v",
|
||||
"name": "HunyuanVideo 1.5 T2V",
|
||||
"size_multiple": 16,
|
||||
"description": "Select HunyuanVideo 1.5 T2V weights and use Video Generation. Use the separate I2V recipe for I2V weights.",
|
||||
"model_url": "https://huggingface.co/tencent/HunyuanVideo-1.5",
|
||||
"slots": [
|
||||
@@ -36,6 +37,12 @@
|
||||
"tae"
|
||||
]
|
||||
],
|
||||
"video_constraints": {
|
||||
"frame_step": 4,
|
||||
"frame_offset": 1,
|
||||
"frame_rounding": "floor",
|
||||
"min_frames": 1
|
||||
},
|
||||
"defaults": {
|
||||
"sampling_method": "euler",
|
||||
"video_frames": 33,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"schema_version": 1,
|
||||
"id": "ideogram4",
|
||||
"name": "Ideogram 4",
|
||||
"size_multiple": 16,
|
||||
"description": "Select the matching unconditional transformer for classifier-free guidance.",
|
||||
"model_url": "https://huggingface.co/ideogram-ai/ideogram-4-fp8",
|
||||
"slots": [
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"schema_version": 1,
|
||||
"id": "instruct-pix2pix",
|
||||
"name": "Instruct-Pix2Pix",
|
||||
"size_multiple": 64,
|
||||
"description": "Supply the image to edit as a reference image.",
|
||||
"model_url": "https://huggingface.co/timbrooks/instruct-pix2pix",
|
||||
"slots": [
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"schema_version": 1,
|
||||
"id": "iris-3b",
|
||||
"name": "Iris 3B",
|
||||
"size_multiple": 16,
|
||||
"description": "Pixel-space model; no VAE is required.",
|
||||
"model_url": "https://huggingface.co/speridlabs/iris-3b",
|
||||
"slots": [
|
||||
|
||||
@@ -39,8 +39,8 @@
|
||||
"sampling_method": "euler",
|
||||
"cfg_scale": 1,
|
||||
"steps": 8,
|
||||
"width": 2048,
|
||||
"height": 2048
|
||||
"width": 1024,
|
||||
"height": 1024
|
||||
},
|
||||
"features": [
|
||||
"flow_shift",
|
||||
|
||||
@@ -32,8 +32,8 @@
|
||||
"defaults": {
|
||||
"cfg_scale": 1,
|
||||
"steps": 8,
|
||||
"width": 2048,
|
||||
"height": 2048,
|
||||
"width": 1024,
|
||||
"height": 1024,
|
||||
"sampling_method": "euler"
|
||||
},
|
||||
"features": [
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"schema_version": 1,
|
||||
"id": "lens-turbo",
|
||||
"name": "LENS Turbo",
|
||||
"size_multiple": 16,
|
||||
"model_url": "https://huggingface.co/microsoft/Lens-Turbo",
|
||||
"slots": [
|
||||
{
|
||||
@@ -36,8 +37,8 @@
|
||||
"defaults": {
|
||||
"cfg_scale": 1,
|
||||
"steps": 4,
|
||||
"width": 1440,
|
||||
"height": 1440,
|
||||
"width": 1024,
|
||||
"height": 1024,
|
||||
"sampling_method": "euler"
|
||||
},
|
||||
"features": [
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"schema_version": 1,
|
||||
"id": "lens",
|
||||
"name": "LENS",
|
||||
"size_multiple": 16,
|
||||
"model_url": "https://huggingface.co/microsoft/Lens",
|
||||
"slots": [
|
||||
{
|
||||
@@ -36,8 +37,8 @@
|
||||
"defaults": {
|
||||
"cfg_scale": 5,
|
||||
"steps": 20,
|
||||
"width": 1440,
|
||||
"height": 1440,
|
||||
"width": 1024,
|
||||
"height": 1024,
|
||||
"sampling_method": "euler"
|
||||
},
|
||||
"features": [
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"schema_version": 1,
|
||||
"id": "lingbot-video-dense",
|
||||
"name": "LingBot Video Dense 1.3B",
|
||||
"size_multiple": 16,
|
||||
"description": "Use Video Generation.",
|
||||
"model_url": "https://huggingface.co/robbyant/lingbot-video-dense-1.3b",
|
||||
"slots": [
|
||||
@@ -30,6 +31,12 @@
|
||||
"tae"
|
||||
]
|
||||
],
|
||||
"video_constraints": {
|
||||
"frame_step": 4,
|
||||
"frame_offset": 1,
|
||||
"frame_rounding": "floor",
|
||||
"min_frames": 1
|
||||
},
|
||||
"defaults": {
|
||||
"video_frames": 33,
|
||||
"cfg_scale": 3,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"schema_version": 1,
|
||||
"id": "lingbot-video-moe",
|
||||
"name": "LingBot Video MoE 30B A3B",
|
||||
"size_multiple": 16,
|
||||
"description": "Use Video Generation.",
|
||||
"model_url": "https://huggingface.co/robbyant/lingbot-video-moe-30b-a3b",
|
||||
"slots": [
|
||||
@@ -30,6 +31,12 @@
|
||||
"tae"
|
||||
]
|
||||
],
|
||||
"video_constraints": {
|
||||
"frame_step": 4,
|
||||
"frame_offset": 1,
|
||||
"frame_rounding": "floor",
|
||||
"min_frames": 1
|
||||
},
|
||||
"defaults": {
|
||||
"video_frames": 33,
|
||||
"cfg_scale": 3,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"schema_version": 1,
|
||||
"id": "llada-image-turbo",
|
||||
"name": "LLaDA Image Turbo",
|
||||
"size_multiple": 16,
|
||||
"description": "Use matching turbo text encoder and connectors. Editing needs connectors that include the SigVQ encoder.",
|
||||
"model_url": "https://huggingface.co/inclusionAI/LLaDA-Image-Turbo",
|
||||
"slots": [
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"schema_version": 1,
|
||||
"id": "llada-image",
|
||||
"name": "LLaDA Image (base)",
|
||||
"size_multiple": 16,
|
||||
"description": "Use matching base transformer, text encoder and connectors; do not mix them with Turbo components. Editing needs connectors with SigVQ and 1024x1024 output.",
|
||||
"model_url": "https://huggingface.co/inclusionAI/LLaDA-Image",
|
||||
"slots": [
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"schema_version": 1,
|
||||
"id": "ltx23-dev",
|
||||
"name": "LTX 2.3 dev",
|
||||
"size_multiple": 32,
|
||||
"description": "Supports text, start-image and start/end-image video. Audio VAE is optional for silent video. Configure latent upscaling separately in generation settings. Optional distillation LoRAs use this recipe; select the LoRA and adjust the sampling settings separately.",
|
||||
"model_url": "https://huggingface.co/Lightricks/LTX-2.3",
|
||||
"slots": [
|
||||
@@ -39,6 +40,12 @@
|
||||
"tae"
|
||||
]
|
||||
],
|
||||
"video_constraints": {
|
||||
"frame_step": 8,
|
||||
"frame_offset": 1,
|
||||
"frame_rounding": "floor",
|
||||
"min_frames": 1
|
||||
},
|
||||
"defaults": {
|
||||
"sampling_method": "euler",
|
||||
"video_frames": 33,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"schema_version": 1,
|
||||
"id": "ltx23-distilled",
|
||||
"name": "LTX 2.3 Distilled 1.1",
|
||||
"size_multiple": 32,
|
||||
"description": "Supports text, start-image and start/end-image video. Audio VAE is optional for silent video. Configure latent upscaling separately in generation settings.",
|
||||
"model_url": "https://huggingface.co/Lightricks/LTX-2.3",
|
||||
"slots": [
|
||||
@@ -39,6 +40,12 @@
|
||||
"tae"
|
||||
]
|
||||
],
|
||||
"video_constraints": {
|
||||
"frame_step": 8,
|
||||
"frame_offset": 1,
|
||||
"frame_rounding": "floor",
|
||||
"min_frames": 1
|
||||
},
|
||||
"defaults": {
|
||||
"sampling_method": "euler",
|
||||
"video_frames": 121,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"schema_version": 1,
|
||||
"id": "ltx25-dev",
|
||||
"name": "LTX 2.5 dev",
|
||||
"size_multiple": 32,
|
||||
"description": "Use the conv video VAE and LTX-specific Gemma 4 with bundled projection. Audio VAE is optional for silent video.",
|
||||
"model_url": "https://huggingface.co/Lightricks/LTX-2.5",
|
||||
"slots": [
|
||||
@@ -35,6 +36,12 @@
|
||||
"tae"
|
||||
]
|
||||
],
|
||||
"video_constraints": {
|
||||
"frame_step": 8,
|
||||
"frame_offset": 1,
|
||||
"frame_rounding": "floor",
|
||||
"min_frames": 1
|
||||
},
|
||||
"defaults": {
|
||||
"sampling_method": "euler",
|
||||
"fps": 24,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"schema_version": 1,
|
||||
"id": "mage-flow-edit",
|
||||
"name": "Mage Flow Edit",
|
||||
"size_multiple": 16,
|
||||
"description": "Supply reference images. Select a separate vision projector when it is not bundled in the text encoder.",
|
||||
"model_url": "https://huggingface.co/microsoft/Mage-Flow-Edit",
|
||||
"slots": [
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"schema_version": 1,
|
||||
"id": "mage-flow-turbo",
|
||||
"name": "Mage Flow Turbo",
|
||||
"size_multiple": 16,
|
||||
"model_url": "https://huggingface.co/microsoft/Mage-Flow-Turbo",
|
||||
"slots": [
|
||||
{
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"schema_version": 1,
|
||||
"id": "mage-flow",
|
||||
"name": "Mage Flow",
|
||||
"size_multiple": 16,
|
||||
"model_url": "https://huggingface.co/microsoft/Mage-Flow",
|
||||
"slots": [
|
||||
{
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"schema_version": 1,
|
||||
"id": "ming-image",
|
||||
"name": "Ming Image 0.1",
|
||||
"size_multiple": 16,
|
||||
"model_url": "https://huggingface.co/inclusionAI/Ming-Image-0.1-Design",
|
||||
"slots": [
|
||||
{
|
||||
@@ -36,8 +37,8 @@
|
||||
"defaults": {
|
||||
"cfg_scale": 1,
|
||||
"steps": 12,
|
||||
"width": 2048,
|
||||
"height": 2048,
|
||||
"width": 1024,
|
||||
"height": 1024,
|
||||
"sampling_method": "euler"
|
||||
},
|
||||
"features": [
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"schema_version": 1,
|
||||
"id": "minimax-h3-fl2va",
|
||||
"name": "MiniMax H3 FL2VA",
|
||||
"size_multiple": 32,
|
||||
"description": "Generate video and audio, optionally with start/end images. Supports full and pruned FL2VA weights. Audio VAE is optional for silent video.",
|
||||
"model_url": "https://huggingface.co/MiniMaxAI/MiniMax-H3",
|
||||
"slots": [
|
||||
@@ -35,6 +36,13 @@
|
||||
"tae"
|
||||
]
|
||||
],
|
||||
"video_constraints": {
|
||||
"frame_step": 17,
|
||||
"frame_offset": 5,
|
||||
"frame_rounding": "ceil",
|
||||
"min_frames": 5,
|
||||
"fixed_fps": 24
|
||||
},
|
||||
"defaults": {
|
||||
"video_frames": 56,
|
||||
"fps": 24,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"schema_version": 1,
|
||||
"id": "minimax-h3-ref2va",
|
||||
"name": "MiniMax H3 Ref2VA",
|
||||
"size_multiple": 32,
|
||||
"description": "Supply image, video or audio references with compatible Ref2VA weights. Audio VAE is optional for silent video.",
|
||||
"model_url": "https://huggingface.co/MiniMaxAI/MiniMax-H3",
|
||||
"slots": [
|
||||
@@ -35,6 +36,13 @@
|
||||
"tae"
|
||||
]
|
||||
],
|
||||
"video_constraints": {
|
||||
"frame_step": 17,
|
||||
"frame_offset": 5,
|
||||
"frame_rounding": "ceil",
|
||||
"min_frames": 5,
|
||||
"fixed_fps": 24
|
||||
},
|
||||
"defaults": {
|
||||
"video_frames": 56,
|
||||
"fps": 24,
|
||||
@@ -45,7 +53,10 @@
|
||||
},
|
||||
"features": [
|
||||
"flow_shift",
|
||||
"ref_images"
|
||||
"ref_images",
|
||||
"ref_videos",
|
||||
"ref_audios",
|
||||
"ref_video_audios"
|
||||
],
|
||||
"disabled_features": [
|
||||
"img2img",
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"schema_version": 1,
|
||||
"id": "minit2i",
|
||||
"name": "MiniT2I",
|
||||
"size_multiple": 1,
|
||||
"description": "Pixel-space model; no VAE is required.",
|
||||
"model_url": "https://huggingface.co/MiniT2I/MiniT2I",
|
||||
"slots": [
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"schema_version": 1,
|
||||
"id": "moss-image-base",
|
||||
"name": "MOSS Image Base",
|
||||
"size_multiple": 16,
|
||||
"description": "Select the MOSS-Image-Base transformer with its matching text encoder and FLUX.2 VAE or TAE.",
|
||||
"model_url": "https://huggingface.co/OpenMOSS-Team/MOSS-Image-Base",
|
||||
"slots": [
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"schema_version": 1,
|
||||
"id": "moss-image-sft",
|
||||
"name": "MOSS Image SFT",
|
||||
"size_multiple": 16,
|
||||
"description": "Select the MOSS-Image-SFT transformer with its matching text encoder and FLUX.2 VAE or TAE.",
|
||||
"model_url": "https://huggingface.co/OpenMOSS-Team/MOSS-Image-SFT",
|
||||
"slots": [
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"schema_version": 1,
|
||||
"id": "nitrosd-realism",
|
||||
"name": "NitroSD Realism",
|
||||
"size_multiple": 64,
|
||||
"model_url": "https://huggingface.co/ChenDY/NitroFusion",
|
||||
"slots": [
|
||||
{
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"schema_version": 1,
|
||||
"id": "pid-15-flux2",
|
||||
"name": "PiD 1.5 (Flux.2 VAE)",
|
||||
"size_multiple": 1,
|
||||
"description": "Supply a reference image; the first image is used as the source latent. Select a matching Flux.2 PiD checkpoint and VAE.",
|
||||
"model_url": "https://huggingface.co/nvidia/PiD",
|
||||
"slots": [
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"schema_version": 1,
|
||||
"id": "pid-15-qwen-image",
|
||||
"name": "PiD 1.5 (Qwen Image VAE)",
|
||||
"size_multiple": 1,
|
||||
"description": "Supply a reference image; the first image is used as the source latent. Select a matching Qwen Image PiD checkpoint and VAE. Use the Qwen Image 2D VAE.",
|
||||
"model_url": "https://huggingface.co/nvidia/PiD",
|
||||
"slots": [
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"schema_version": 1,
|
||||
"id": "pid-15-sd3",
|
||||
"name": "PiD 1.5 (SD3 VAE)",
|
||||
"size_multiple": 1,
|
||||
"description": "Supply a reference image; the first image is used as the source latent. Select a matching SD3 PiD checkpoint and VAE.",
|
||||
"model_url": "https://huggingface.co/nvidia/PiD",
|
||||
"slots": [
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"schema_version": 1,
|
||||
"id": "pid-15",
|
||||
"name": "PiD 1.5 (Flux / Z-Image VAE)",
|
||||
"size_multiple": 1,
|
||||
"description": "Supply a reference image; the first image is used as the source latent. Select a Flux/Z-Image PiD checkpoint and matching Flux VAE.",
|
||||
"model_url": "https://huggingface.co/nvidia/PiD",
|
||||
"slots": [
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"schema_version": 1,
|
||||
"id": "pid-flux2",
|
||||
"name": "PiD (Flux.2 VAE)",
|
||||
"size_multiple": 1,
|
||||
"description": "Supply a reference image; the first image is used as the source latent. Select a matching Flux.2 PiD checkpoint and VAE.",
|
||||
"model_url": "https://huggingface.co/nvidia/PiD",
|
||||
"slots": [
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"schema_version": 1,
|
||||
"id": "pid-qwen-image",
|
||||
"name": "PiD (Qwen Image VAE)",
|
||||
"size_multiple": 1,
|
||||
"description": "Supply a reference image; the first image is used as the source latent. Select a matching Qwen Image PiD checkpoint and VAE. Use the Qwen Image 2D VAE.",
|
||||
"model_url": "https://huggingface.co/nvidia/PiD",
|
||||
"slots": [
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"schema_version": 1,
|
||||
"id": "pid-sd3",
|
||||
"name": "PiD (SD3 VAE)",
|
||||
"size_multiple": 1,
|
||||
"description": "Supply a reference image; the first image is used as the source latent. Select a matching SD3 PiD checkpoint and VAE.",
|
||||
"model_url": "https://huggingface.co/nvidia/PiD",
|
||||
"slots": [
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"schema_version": 1,
|
||||
"id": "pid",
|
||||
"name": "PiD (Flux / Z-Image VAE)",
|
||||
"size_multiple": 1,
|
||||
"description": "Supply a reference image; the first image is used as the source latent. Select a Flux/Z-Image PiD checkpoint and matching Flux VAE.",
|
||||
"model_url": "https://huggingface.co/nvidia/PiD",
|
||||
"slots": [
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"schema_version": 1,
|
||||
"id": "pixart-alpha-1024",
|
||||
"name": "PixArt Alpha XL 1024",
|
||||
"size_multiple": 16,
|
||||
"description": "Use the matching PixArt Alpha transformer and SD 1.x-style VAE. Resolution/aspect-ratio micro-conditioning is not currently applied by the runtime.",
|
||||
"model_url": "https://huggingface.co/PixArt-alpha/PixArt-XL-2-1024-MS",
|
||||
"slots": [
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"schema_version": 1,
|
||||
"id": "pixart-alpha-512",
|
||||
"name": "PixArt Alpha XL 512",
|
||||
"size_multiple": 16,
|
||||
"description": "Use the matching PixArt Alpha transformer and SD 1.x-style VAE. Resolution/aspect-ratio micro-conditioning is not currently applied by the runtime.",
|
||||
"model_url": "https://huggingface.co/PixArt-alpha/PixArt-XL-2-512x512",
|
||||
"slots": [
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"schema_version": 1,
|
||||
"id": "pixart-sigma",
|
||||
"name": "PixArt Sigma XL 1024",
|
||||
"size_multiple": 16,
|
||||
"model_url": "https://huggingface.co/PixArt-alpha/PixArt-Sigma-XL-2-1024-MS",
|
||||
"slots": [
|
||||
{
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"schema_version": 1,
|
||||
"id": "qwen-image-21-turbo",
|
||||
"name": "Qwen Image 2.1 Turbo",
|
||||
"size_multiple": 32,
|
||||
"description": "Use the standalone Turbo diffusion weights for generation and editing with the fixed 8-step schedule. Select the Qwen Image 2.1 VAE or TAEQI2.1, and supply a vision projector when needed.",
|
||||
"model_url": "https://huggingface.co/Qwen/Qwen-Image-2.1-Turbo",
|
||||
"slots": [
|
||||
@@ -40,8 +41,8 @@
|
||||
"sampling_method": "euler",
|
||||
"cfg_scale": 1,
|
||||
"steps": 8,
|
||||
"width": 2048,
|
||||
"height": 2048,
|
||||
"width": 1024,
|
||||
"height": 1024,
|
||||
"custom_sigmas": [
|
||||
1.0,
|
||||
0.978453,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"schema_version": 1,
|
||||
"id": "qwen-image-21",
|
||||
"name": "Qwen Image 2.1",
|
||||
"size_multiple": 32,
|
||||
"description": "Supports generation and editing. Select the full Qwen Image 2.1 VAE or TAEQI2.1. Supply a separate vision projector when needed. Select acceleration LoRAs and adjust their settings separately.",
|
||||
"model_url": "https://huggingface.co/Qwen/Qwen-Image-2.1",
|
||||
"slots": [
|
||||
@@ -40,8 +41,8 @@
|
||||
"sampling_method": "euler",
|
||||
"cfg_scale": 1,
|
||||
"steps": 20,
|
||||
"width": 2048,
|
||||
"height": 2048
|
||||
"width": 1024,
|
||||
"height": 1024
|
||||
},
|
||||
"features": [
|
||||
"flow_shift",
|
||||
|
||||
@@ -35,8 +35,8 @@
|
||||
"flow_shift": 3.0,
|
||||
"cfg_scale": 4,
|
||||
"steps": 20,
|
||||
"width": 1328,
|
||||
"height": 1328
|
||||
"width": 1024,
|
||||
"height": 1024
|
||||
},
|
||||
"features": [
|
||||
"flow_shift"
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"schema_version": 1,
|
||||
"id": "sd-turbo",
|
||||
"name": "SD Turbo",
|
||||
"size_multiple": 64,
|
||||
"description": "Select a single-file SD-Turbo checkpoint. Uses one step with CFG disabled (scale 1 in sd.cpp); use more steps for partial image-to-image denoising.",
|
||||
"model_url": "https://huggingface.co/stabilityai/sd-turbo",
|
||||
"slots": [
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"schema_version": 1,
|
||||
"id": "sd1-checkpoint",
|
||||
"name": "SD 1.x",
|
||||
"size_multiple": 64,
|
||||
"description": "Supports SD 1.x, compatible LCM checkpoints and layer-count variants. For LCM weights, select LCM sampling and adjust steps/CFG. Tiny SD Diffusers directories must first be converted into a single-file checkpoint.",
|
||||
"model_url": "https://huggingface.co/CompVis/stable-diffusion-v1-4",
|
||||
"slots": [
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"schema_version": 1,
|
||||
"id": "sd1-controlnet",
|
||||
"name": "SD 1.5 ControlNet",
|
||||
"size_multiple": 64,
|
||||
"description": "Supply a control image; input image and mask are optional for image-to-image or inpainting.",
|
||||
"model_url": "https://huggingface.co/lllyasviel/control_v11p_sd15_canny",
|
||||
"slots": [
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"schema_version": 1,
|
||||
"id": "sd1-inpainting",
|
||||
"name": "SD 1.5 Inpainting",
|
||||
"size_multiple": 64,
|
||||
"description": "Select an inpainting checkpoint, then supply an input image and mask.",
|
||||
"slots": [
|
||||
{
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"schema_version": 1,
|
||||
"id": "sd1-ip-adapter",
|
||||
"name": "SD 1.5 IP-Adapter / Plus",
|
||||
"size_multiple": 64,
|
||||
"description": "Select matching SD 1.5 IP-Adapter or Plus weights and CLIP Vision H, then supply an IP-Adapter image.",
|
||||
"model_url": "https://huggingface.co/h94/IP-Adapter",
|
||||
"slots": [
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"schema_version": 1,
|
||||
"id": "sd2-512-checkpoint",
|
||||
"name": "SD 2.1 512",
|
||||
"size_multiple": 64,
|
||||
"description": "Supports SD 2.x 512 and compatible layer-count variants. Tiny SD2 Diffusers directories must first be converted into a single-file checkpoint.",
|
||||
"slots": [
|
||||
{
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"schema_version": 1,
|
||||
"id": "sd2-768-checkpoint",
|
||||
"name": "SD 2.1 768",
|
||||
"size_multiple": 64,
|
||||
"slots": [
|
||||
{
|
||||
"id": "model",
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"schema_version": 1,
|
||||
"id": "sd2-inpainting",
|
||||
"name": "SD 2 Inpainting",
|
||||
"size_multiple": 64,
|
||||
"description": "Select an inpainting checkpoint, then supply Init Image and Mask Image.",
|
||||
"slots": [
|
||||
{
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"schema_version": 1,
|
||||
"id": "sdxl-checkpoint",
|
||||
"name": "SDXL",
|
||||
"size_multiple": 64,
|
||||
"description": "Supports SDXL and compatible reduced-depth checkpoints such as SSD-1B and Segmind Vega.",
|
||||
"model_url": "https://huggingface.co/stabilityai/stable-diffusion-xl-base-1.0",
|
||||
"slots": [
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"schema_version": 1,
|
||||
"id": "sdxl-controlnet",
|
||||
"name": "SDXL ControlNet",
|
||||
"size_multiple": 64,
|
||||
"description": "Select a compatible SDXL ControlNet and supply a preprocessed control image. Input image and mask are optional for image-to-image or inpainting.",
|
||||
"model_url": "https://huggingface.co/diffusers/controlnet-canny-sdxl-1.0",
|
||||
"slots": [
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"schema_version": 1,
|
||||
"id": "sdxl-inpainting",
|
||||
"name": "SDXL Inpainting",
|
||||
"size_multiple": 64,
|
||||
"description": "Select an inpainting checkpoint, then supply Init Image and Mask Image.",
|
||||
"model_url": "https://huggingface.co/diffusers/stable-diffusion-xl-1.0-inpainting-0.1",
|
||||
"slots": [
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"schema_version": 1,
|
||||
"id": "sdxl-ip-adapter",
|
||||
"name": "SDXL IP-Adapter / Plus",
|
||||
"size_multiple": 64,
|
||||
"description": "Select matching SDXL ViT-H IP-Adapter or Plus weights and CLIP Vision H, then supply an IP-Adapter image.",
|
||||
"model_url": "https://huggingface.co/h94/IP-Adapter",
|
||||
"slots": [
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"schema_version": 1,
|
||||
"id": "sdxl-photomaker",
|
||||
"name": "SDXL PhotoMaker",
|
||||
"size_multiple": 64,
|
||||
"description": "Select PhotoMaker v1 and supply identity images. Include the img trigger in the prompt.",
|
||||
"model_url": "https://huggingface.co/TencentARC/PhotoMaker",
|
||||
"slots": [
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"schema_version": 1,
|
||||
"id": "sdxl-turbo",
|
||||
"name": "SDXL Turbo",
|
||||
"size_multiple": 64,
|
||||
"model_url": "https://huggingface.co/stabilityai/sdxl-turbo",
|
||||
"slots": [
|
||||
{
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"schema_version": 1,
|
||||
"id": "sdxs",
|
||||
"name": "SDXS",
|
||||
"size_multiple": 64,
|
||||
"model_url": "https://huggingface.co/IDKiro/sdxs-512-dreamshaper",
|
||||
"slots": [
|
||||
{
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"schema_version": 1,
|
||||
"id": "sefi-image",
|
||||
"name": "SeFi Image 5B RL",
|
||||
"size_multiple": 16,
|
||||
"model_url": "https://huggingface.co/SeFi-Image/SeFi-Image-5B-Base",
|
||||
"slots": [
|
||||
{
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"schema_version": 1,
|
||||
"id": "sensenova-u15",
|
||||
"name": "SenseNova U1.5",
|
||||
"size_multiple": 32,
|
||||
"description": "Bundled MoT checkpoint.",
|
||||
"model_url": "https://huggingface.co/sensenova/SenseNova-U1.5-8B-MoT",
|
||||
"slots": [
|
||||
@@ -14,8 +15,8 @@
|
||||
"flow_shift": 3.0,
|
||||
"cfg_scale": 4,
|
||||
"steps": 20,
|
||||
"width": 2048,
|
||||
"height": 2048,
|
||||
"width": 1024,
|
||||
"height": 1024,
|
||||
"sampling_method": "euler"
|
||||
},
|
||||
"features": [
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"schema_version": 1,
|
||||
"id": "wan21-flf2v",
|
||||
"name": "Wan 2.1 FLF2V 14B",
|
||||
"size_multiple": 16,
|
||||
"description": "Select FLF2V weights and supply both start and end images.",
|
||||
"model_url": "https://huggingface.co/Wan-AI/Wan2.1-FLF2V-14B-720P",
|
||||
"slots": [
|
||||
@@ -35,6 +36,12 @@
|
||||
"tae"
|
||||
]
|
||||
],
|
||||
"video_constraints": {
|
||||
"frame_step": 4,
|
||||
"frame_offset": 1,
|
||||
"frame_rounding": "floor",
|
||||
"min_frames": 1
|
||||
},
|
||||
"defaults": {
|
||||
"sampling_method": "euler",
|
||||
"flow_shift": 16,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"schema_version": 1,
|
||||
"id": "wan21-i2v",
|
||||
"name": "Wan 2.1 I2V",
|
||||
"size_multiple": 16,
|
||||
"description": "Image-to-video with Wan 2.1, compatible SkyReels V2 weights, or a single Wan 2.2 I2V expert. CLIP Vision is required by Wan 2.1 I2V and is unused by Wan 2.2. Defaults target Wan 2.1 480p.",
|
||||
"model_url": "https://huggingface.co/Wan-AI/Wan2.1-I2V-14B-480P",
|
||||
"slots": [
|
||||
@@ -35,6 +36,12 @@
|
||||
"tae"
|
||||
]
|
||||
],
|
||||
"video_constraints": {
|
||||
"frame_step": 4,
|
||||
"frame_offset": 1,
|
||||
"frame_rounding": "floor",
|
||||
"min_frames": 1
|
||||
},
|
||||
"defaults": {
|
||||
"sampling_method": "euler",
|
||||
"video_frames": 33,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"schema_version": 1,
|
||||
"id": "wan21-t2v",
|
||||
"name": "Wan 2.1 T2V",
|
||||
"size_multiple": 16,
|
||||
"description": "Text-to-video with Wan 2.1 or a compatible single Wan 2.2 T2V expert. Defaults target Wan 2.1 14B; adjust settings for the selected weights and acceleration LoRAs.",
|
||||
"model_url": "https://huggingface.co/Wan-AI/Wan2.1-T2V-14B",
|
||||
"slots": [
|
||||
@@ -30,6 +31,12 @@
|
||||
"tae"
|
||||
]
|
||||
],
|
||||
"video_constraints": {
|
||||
"frame_step": 4,
|
||||
"frame_offset": 1,
|
||||
"frame_rounding": "floor",
|
||||
"min_frames": 1
|
||||
},
|
||||
"defaults": {
|
||||
"sampling_method": "euler",
|
||||
"video_frames": 33,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"schema_version": 1,
|
||||
"id": "wan21-vace",
|
||||
"name": "Wan 2.1 VACE 1.3B / 14B",
|
||||
"size_multiple": 16,
|
||||
"description": "Select matching VACE weights. Supports text, reference images and control video through Video Generation.",
|
||||
"model_url": "https://huggingface.co/Wan-AI/Wan2.1-VACE-14B",
|
||||
"slots": [
|
||||
@@ -30,6 +31,12 @@
|
||||
"tae"
|
||||
]
|
||||
],
|
||||
"video_constraints": {
|
||||
"frame_step": 4,
|
||||
"frame_offset": 1,
|
||||
"frame_rounding": "floor",
|
||||
"min_frames": 1
|
||||
},
|
||||
"defaults": {
|
||||
"sampling_method": "euler",
|
||||
"video_frames": 33,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"schema_version": 1,
|
||||
"id": "wan22-i2v",
|
||||
"name": "Wan 2.2 I2V A14B",
|
||||
"size_multiple": 16,
|
||||
"description": "Image-to-video. Select a start image in Video Generation after loading. LightX2V acceleration LoRAs must match the I2V low- and high-noise models; configure LoRAs and sampling separately.",
|
||||
"model_url": "https://huggingface.co/Wan-AI/Wan2.2-I2V-A14B",
|
||||
"slots": [
|
||||
@@ -35,6 +36,12 @@
|
||||
"tae"
|
||||
]
|
||||
],
|
||||
"video_constraints": {
|
||||
"frame_step": 4,
|
||||
"frame_offset": 1,
|
||||
"frame_rounding": "floor",
|
||||
"min_frames": 1
|
||||
},
|
||||
"defaults": {
|
||||
"sampling_method": "euler",
|
||||
"video_frames": 33,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"schema_version": 1,
|
||||
"id": "wan22-s2v",
|
||||
"name": "Wan 2.2 S2V 14B",
|
||||
"size_multiple": 16,
|
||||
"description": "Supply a start image and reference audio through Video Generation.",
|
||||
"model_url": "https://huggingface.co/Wan-AI/Wan2.2-S2V-14B",
|
||||
"slots": [
|
||||
@@ -35,6 +36,13 @@
|
||||
"tae"
|
||||
]
|
||||
],
|
||||
"video_constraints": {
|
||||
"frame_step": 4,
|
||||
"frame_offset": 1,
|
||||
"frame_rounding": "floor",
|
||||
"min_frames": 1,
|
||||
"fixed_fps": 16
|
||||
},
|
||||
"defaults": {
|
||||
"sampling_method": "euler",
|
||||
"flow_shift": 3,
|
||||
@@ -44,7 +52,8 @@
|
||||
},
|
||||
"features": [
|
||||
"flow_shift",
|
||||
"init_image"
|
||||
"init_image",
|
||||
"ref_audios"
|
||||
],
|
||||
"disabled_features": [
|
||||
"img2img",
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"schema_version": 1,
|
||||
"id": "wan22-t2v",
|
||||
"name": "Wan 2.2 T2V A14B",
|
||||
"size_multiple": 16,
|
||||
"description": "Text-to-video. Use Video Generation after loading. LightX2V acceleration LoRAs must match the T2V low- and high-noise models; configure LoRAs and sampling separately.",
|
||||
"model_url": "https://huggingface.co/Wan-AI/Wan2.2-T2V-A14B",
|
||||
"slots": [
|
||||
@@ -35,6 +36,12 @@
|
||||
"tae"
|
||||
]
|
||||
],
|
||||
"video_constraints": {
|
||||
"frame_step": 4,
|
||||
"frame_offset": 1,
|
||||
"frame_rounding": "floor",
|
||||
"min_frames": 1
|
||||
},
|
||||
"defaults": {
|
||||
"sampling_method": "euler",
|
||||
"video_frames": 33,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"schema_version": 1,
|
||||
"id": "wan22-ti2v-5b",
|
||||
"name": "Wan 2.2 TI2V 5B",
|
||||
"size_multiple": 32,
|
||||
"description": "Use Wan 2.2 VAE. Supports text, start-image and start/end-image conditioning.",
|
||||
"model_url": "https://huggingface.co/Wan-AI/Wan2.2-TI2V-5B",
|
||||
"slots": [
|
||||
@@ -30,6 +31,12 @@
|
||||
"tae"
|
||||
]
|
||||
],
|
||||
"video_constraints": {
|
||||
"frame_step": 4,
|
||||
"frame_offset": 1,
|
||||
"frame_rounding": "floor",
|
||||
"min_frames": 1
|
||||
},
|
||||
"defaults": {
|
||||
"sampling_method": "euler",
|
||||
"video_frames": 33,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"schema_version": 1,
|
||||
"id": "z-image-l2p",
|
||||
"name": "Z-Image L2P",
|
||||
"size_multiple": 16,
|
||||
"description": "Pixel-space L2P checkpoint with Qwen 3 4B; no VAE is needed. Use dimensions divisible by 16.",
|
||||
"model_url": "https://huggingface.co/zhen-nan/L2P",
|
||||
"slots": [
|
||||
|
||||
@@ -212,11 +212,15 @@ static json make_img_gen_features_json() {
|
||||
};
|
||||
}
|
||||
|
||||
/** Builds the default feature set advertised for vid_gen requests. */
|
||||
static json make_vid_gen_features_json() {
|
||||
return {
|
||||
{"init_image", true},
|
||||
{"end_image", true},
|
||||
{"control_frames", true},
|
||||
{"ref_videos", true},
|
||||
{"ref_audios", true},
|
||||
{"ref_video_audios", true},
|
||||
{"high_noise_sample_params", true},
|
||||
{"lora", true},
|
||||
{"vae_tiling", true},
|
||||
@@ -235,6 +239,7 @@ static json make_preview_modes_json() {
|
||||
return modes;
|
||||
}
|
||||
|
||||
/** Builds the /capabilities payload: model, defaults, limits and feature maps. */
|
||||
static json make_capabilities_json(ServerRuntime& runtime) {
|
||||
refresh_lora_cache(runtime);
|
||||
refresh_upscaler_cache(runtime);
|
||||
@@ -351,8 +356,10 @@ static json make_capabilities_json(ServerRuntime& runtime) {
|
||||
const json generation_features = model_generation_features(runtime);
|
||||
auto recipe_features = [&](json features, bool video) {
|
||||
features["init_image"] = generation_features.at(video ? "init_image" : "img2img");
|
||||
for (const char* key : {"mask_image", "ref_images", "end_image", "control_frames", "lora", "vae_tiling", "cache", "preview"}) {
|
||||
if (features.contains(key) || std::string(key) == "ref_images")
|
||||
for (const char* key : {"mask_image", "ref_images", "end_image", "control_frames", "ref_videos", "ref_audios", "ref_video_audios", "lora", "vae_tiling", "cache", "preview"}) {
|
||||
if (features.contains(key) || std::string(key) == "ref_images" ||
|
||||
(video && (std::string(key) == "ref_videos" || std::string(key) == "ref_audios" ||
|
||||
std::string(key) == "ref_video_audios")))
|
||||
features[key] = generation_features.at(key);
|
||||
}
|
||||
if (video)
|
||||
|
||||
@@ -185,7 +185,7 @@ namespace MOSSImage {
|
||||
ggml_build_forward_expand(ctx->graph, parts[i]);
|
||||
}
|
||||
}
|
||||
x = ggml_concat(c, x, text, 1);
|
||||
x = ggml_concat(c, x, text, 1);
|
||||
for (int64_t i = 0; i < config.depth; ++i) {
|
||||
if (std::find(skip.begin(), skip.end(), i) == skip.end()) {
|
||||
x = std::dynamic_pointer_cast<Block>(blocks["layers." + std::to_string(i)])->forward(ctx, x, pe, parts);
|
||||
|
||||
@@ -708,6 +708,24 @@ std::string convert_diffusers_dit_to_original_flux(std::string name) {
|
||||
return name;
|
||||
}
|
||||
|
||||
static std::string convert_diffusers_dit_to_original_flux3(std::string name) {
|
||||
static const std::vector<std::pair<std::string, std::string>> prefix_map = {
|
||||
{"single_transformer_blocks.", "single_blocks."},
|
||||
{"mode_blocks.", "content_mode_blocks."},
|
||||
};
|
||||
static const std::vector<std::pair<std::string, std::string>> name_map = {
|
||||
{".attn.to_q.", ".q_proj."},
|
||||
{".attn.to_k.", ".k_proj."},
|
||||
{".attn.to_v.", ".v_proj."},
|
||||
{".attn.to_out.0.", ".attn_out."},
|
||||
{".ff.linear_in.", ".mlp_in."},
|
||||
{".ff.linear_out.", ".mlp_out."},
|
||||
};
|
||||
replace_with_prefix_map(name, prefix_map);
|
||||
replace_with_name_map(name, name_map);
|
||||
return name;
|
||||
}
|
||||
|
||||
std::string convert_hunyuan_video_to_original_flux(std::string name) {
|
||||
int num_layers = 54;
|
||||
int num_single_layers = 0;
|
||||
@@ -1077,6 +1095,8 @@ std::string convert_diffusion_model_name(std::string name, std::string prefix, S
|
||||
name = convert_diffusers_dit_to_original_sd3(name);
|
||||
} else if (sd_version_is_flux(version) || sd_version_is_flux2(version) || sd_version_is_longcat(version) || sd_version_is_sefi_image(version)) {
|
||||
name = convert_diffusers_dit_to_original_flux(name);
|
||||
} else if (sd_version_is_flux3(version)) {
|
||||
name = convert_diffusers_dit_to_original_flux3(name);
|
||||
} else if (sd_version_is_hunyuan_video(version)) {
|
||||
name = convert_hunyuan_video_to_original_flux(name);
|
||||
} else if (version == VERSION_MOSS_IMAGE) {
|
||||
|
||||
@@ -314,8 +314,8 @@ namespace sd::pipeline {
|
||||
}
|
||||
|
||||
bool skip_vae_encoding = (sd->version == VERSION_HIDREAM_O1) || !(
|
||||
ref_image_params.pass_to_dit || ref_image_params.vlm_use_vae_input ||
|
||||
sd_version_is_unet_edit(sd->version) || sd_version_is_pid(sd->version));
|
||||
ref_image_params.pass_to_dit || ref_image_params.vlm_use_vae_input ||
|
||||
sd_version_is_unet_edit(sd->version) || sd_version_is_pid(sd->version));
|
||||
|
||||
std::vector<sd::Tensor<float>> ref_latents;
|
||||
for (size_t i = 0; i < ref_images.size(); i++) {
|
||||
|
||||
@@ -379,8 +379,13 @@ namespace sd {
|
||||
if (target == ImageTarget::Mask && has_init_transform_) {
|
||||
auto options = resolve_options(target, index);
|
||||
if (image.width != init_transform_.source_width || image.height != init_transform_.source_height) {
|
||||
fail("mask and init source dimensions must match");
|
||||
return {};
|
||||
ImagePreprocessor alignment;
|
||||
tensor = alignment.apply_geometry(tensor, target, index, init_transform_.source_width, init_transform_.source_height,
|
||||
ImageResizeMode::CropResize, ops::InterpolateMode::NearestExact);
|
||||
if (tensor.empty()) {
|
||||
fail("could not align mask to init source dimensions");
|
||||
return {};
|
||||
}
|
||||
}
|
||||
bool geometry_override = options.count("width") || options.count("anchor") ||
|
||||
(options.count("mode") && options.at("mode") != "auto");
|
||||
|
||||
Reference in new issue
Block a user