Merge pull request #4562 from vladmandic/dev

merge dev
This commit is contained in:
Vladimir Mandic
2026-01-20 11:01:09 +01:00
committed by GitHub
221 changed files with 4693 additions and 2212 deletions
-138
View File
@@ -1,138 +0,0 @@
{
"root": true,
"parserOptions": {
"ecmaVersion": "latest",
"sourceType": "module"
},
"plugins": [
"html",
"json"
],
"extends": [
"eslint:recommended",
"airbnb-base",
"plugin:css/recommended",
"plugin:json/recommended",
"plugin:node/recommended"
],
"env": {
"browser": true,
"commonjs": true,
"node": true,
"jquery": true,
"es2024": true
},
"rules": {
"max-len": [1, 275, 3],
"camelcase":"off",
"default-case":"off",
"no-await-in-loop":"off",
"no-bitwise":"off",
"no-continue":"off",
"no-confusing-arrow":"off",
"no-console":"off",
"no-empty":"off",
"no-loop-func":"off",
"no-mixed-operators":"off",
"no-param-reassign":"off",
"no-process-exit":"off",
"no-plusplus":"off",
"no-restricted-globals":"off",
"no-restricted-syntax":"off",
"no-return-assign":"off",
"no-unused-vars":"off",
"no-useless-escape":"off",
"object-curly-newline":"off",
"prefer-rest-params":"off",
"prefer-destructuring":"off",
"radix":"off",
"node/shebang": "off"
},
"globals": {
"panzoom": "readonly",
"authFetch": "readonly",
"log": "readonly",
"debug": "readonly",
"error": "readonly",
"xhrGet": "readonly",
"xhrPost": "readonly",
"gradioApp": "readonly",
"executeCallbacks": "readonly",
"onAfterUiUpdate": "readonly",
"onOptionsChanged": "readonly",
"optionsChangedCallbacks": "readonly",
"onUiLoaded": "readonly",
"onUiUpdate": "readonly",
"onUiTabChange": "readonly",
"onUiReady": "readonly",
"uiCurrentTab": "writable",
"uiElementIsVisible": "readonly",
"uiElementInSight": "readonly",
"getUICurrentTabContent": "readonly",
"waitForFlag": "readonly",
"logFn": "readonly",
"generateForever": "readonly",
"showContributors": "readonly",
"opts": "writable",
"sortUIElements": "readonly",
"all_gallery_buttons": "readonly",
"selected_gallery_button": "readonly",
"selected_gallery_index": "readonly",
"switch_to_txt2img": "readonly",
"switch_to_img2img_tab": "readonly",
"switch_to_img2img": "readonly",
"switch_to_sketch": "readonly",
"switch_to_inpaint": "readonly",
"witch_to_inpaint_sketch": "readonly",
"switch_to_extras": "readonly",
"get_tab_index": "readonly",
"create_submit_args": "readonly",
"restartReload": "readonly",
"markSelectedCards": "readonly",
"updateInput": "readonly",
"toggleCompact": "readonly",
"setFontSize": "readonly",
"setTheme": "readonly",
"registerDragDrop": "readonly",
"getToken": "readonly",
"getENActiveTab": "readonly",
"quickApplyStyle": "readonly",
"quickSaveStyle": "readonly",
"setupExtraNetworks": "readonly",
"showNetworks": "readonly",
"localization": "readonly",
"randomId": "readonly",
"requestProgress": "readonly",
"setRefreshInterval": "readonly",
"modalPrevImage": "readonly",
"modalNextImage": "readonly",
"galleryClickEventHandler": "readonly",
"getExif": "readonly",
"jobStatusEl": "readonly",
"removeSplash": "readonly",
"initGPU": "readonly",
"startGPU": "readonly",
"disableNVML": "readonly",
"idbGet": "readonly",
"idbPut": "readonly",
"idbDel": "readonly",
"idbAdd": "readonly",
"idbCount": "readonly",
"idbFolderCleanup": "readonly",
"initChangelog": "readonly",
"sendNotification": "readonly",
"monitorConnection": "readonly"
},
"ignorePatterns": [
"node_modules",
"extensions",
"repositories",
"venv",
"panzoom.js",
"split.js",
"exifr.js",
"jquery.js",
"sparkline.js",
"iframeResizer.min.js"
]
}
+10 -1
View File
@@ -2,5 +2,14 @@
"python.analysis.extraPaths": [".", "./modules", "./scripts", "./pipelines"],
"python.analysis.typeCheckingMode": "off",
"editor.formatOnSave": false,
"python.REPL.enableREPLSmartSend": false
"python.REPL.enableREPLSmartSend": false,
"eslint.enable": true,
"eslint.validate": [
"javascript",
"typescript",
"html",
"css",
"json",
"markdown"
]
}
+110
View File
@@ -1,5 +1,115 @@
# Change Log for SD.Next
## Update for 2025-01-20
### Highlights for 2025-01-20
First release of 2026 brings quite a few new models: **Flux.2-Klein, Qwen-Image-2512, LTX-2-Dev, GLM-Image**
There are also improvements to *SDNQ* quantization engine, updated *Prompt Enhance*, *Image Preview* and many others.
Plus some significant under-the-hood changes to improve code coverage and quality which resulted in more than usual levels of bug-fixes and some ~330 commits!
For full list of changes, see full changelog.
[ReadMe](https://github.com/vladmandic/automatic/blob/master/README.md) | [ChangeLog](https://github.com/vladmandic/automatic/blob/master/CHANGELOG.md) | [Docs](https://vladmandic.github.io/sdnext-docs/) | [WiKi](https://github.com/vladmandic/automatic/wiki) | [Discord](https://discord.com/invite/sd-next-federal-batch-inspectors-1101998836328697867) | [Sponsor](https://github.com/sponsors/vladmandic)
### Details for 2025-01-20
- **Models**
- [Flux.2 Klein](https://bfl.ai/blog/flux2-klein-towards-interactive-visual-intelligence)
Flux.2-Klein is a new family of compact models from BFL in *4B and 9B sizes* and avaialable as *destilled and base* variants
also includes are *sdnq prequantized variants*
*note*: 9B variant is [gated](https://vladmandic.github.io/sdnext-docs/Gated/)
- [Qwen-Image-2512](https://qwen.ai/blog?id=qwen-image-2512)
Qwen-Image successor, significantly reduces the AI-generated look and adds finer natural detailils and improved text rendering
available in both *original*, *sdnq-svd prequantized* and *sdnq-dynamic prequantized* variants
thanks @CalamitousFelicitousness
- [LTX-2 19B Dev](https://ltx.io/model/ltx-2)
LTX-2 is a new very large 19B parameter video generation model from Lightricks using Gemma-3 text encoder
available for T2I/I2I workflows in original and sdnq prequantized variants
*note*: model is very sensitive to input params and will result in errors otherwise
- [GLM-Image](https://z.ai/blog/glm-image)
GLM-image is a new image generation model that adopts a hybrid autoregressive with diffusion decoder architecture
available in both *original* and *sdnq-dynamic prequantized* variants
thanks @CalamitousFelicitousness
*note*: model requires pre-release versions of `transformers` package:
> pip install --upgrade git+https://github.com/huggingface/transformers.git
> ./webui.sh --experimental
- [Nunchaku Z-Image Turbo](https://huggingface.co/nunchaku-tech/nunchaku-z-image-turbo)
nunchaku optimized z-image turbo
- **Feaures**
- **SDNQ**: add *dynamic* quantization method
sdnq can dynamically determine best quantization method for each module layer
slower to quantize on-the-fly, but results in better quality with minimal resource usage
- **SDNQ** now has *19 int* based and *69 float* based quantization types
*note*: not all are exposed via ui purely for simplicity, but all are available via api and scripts
- **wildcards**: allow weights, thanks @Tillerz
- **sampler**: add laplace beta schedule
results in better prompt adherence and smoother infills
- **prompt enhance**: improve handling and refresh ui, thanks @CalamitousFelicitousness
new models such moondream-3 and xiaomo-mimo
add support for *thinking* mode where model can reason about the prompt
add support for *vision* processing where prompt enhance can also optionally analyze input image
add support for *pre-fill* mode where prompt enhance can continue from existing caption
- **chroma**: add inpaint pipeline support
- **taesd preview**: support for more models, thanks @alerikaisattera
- **image ouput paths**: better handling of relative/absolute paths, thanks @CalamitousFelicitousness
- **UI**
- kanvas add send-to functionality
- kanvas improve support for standardui
- improve extensions tab layout and behavior, thanks @awsr
- indicate collapsed/hidden sections
- persistent panel minimize/maximize state
- gallery improve sorting behavior
- gallery implement prev/next navigation in full screen viewer, thanks @ryanmeador
- **Internal**
- **lora** native support by default will now skip text-encoder
can be enabled in *settings -> networks*
- update core js linting to `eslint9`, thanks @awsr
- update modernui js linting to `eslint9`, thanks @awsr
- update kanvas js linting to `eslint9`, thanks @awsr
- update strong typing checks, thanks @awsr
- update reference models previews, thanks @liutyi
- update models specs page, thanks @alerikaisattera
- sdnq improvements
- startup sequence optimizations
- rocm/hip/hipblast detection and initialization improvements
- zluda detection and initialization improvements
- new env variable `SD_VAE_DEFAULT` to force default vae processing
- update `nunchaku==1.1.0`
- lora switch logic from force-diffusers to allow-native
- split `reference.json`
- print system env on startup
- disable fallback on models with custom loaders
- refactor triggering of prompt parser and set secondary prompts when needed
- refactor handling of seeds
- allow unsafe ssl context for downloads
- **Fixes**
- controlnet: controlnet with non-english ui locales
- core: add skip_keys to offloading logic, fixes wan frames mismatch, thanks @ryanmeador
- core: force model move on offload=none
- core: hidiffusion tracing
- core: hip device name detection
- core: reduce triton test verbosity
- core: switch processing class not restoring params
- extension tab: update checker, date handling, formatting etc., thanks @awsr
- lora force unapply on change
- lora handle null description, thanks @CalamitousFelicitousness
- lora loading when using torch without distributed support
- lora skip with strength zero
- lora: generate slowdown when consequtive lora-diffusers enabled
- model: google-genai auth, thanks @CalamitousFelicitousness
- model: improve qwen i2i handling
- model: kandinsky-5 image and video on non-cuda platforms
- model: meituan-longca-image-edit missing image param
- model: wan 2.2 i2v
- model: z-image single-file loader
- other: update civitai base models, thanks @trojaner
- ui: gallery save/delete
- ui: mobile auto-collapse when using side panel, thanks @awsr
- ui: networks filter by model type
- ui: networks icon/list view type switch, thanks @awsr
- vae: force align width/height to vae scale factor
- wildards with folder specification
## Update for 2025-12-26
### Highlights for 2025-12-26
+31 -28
View File
@@ -1,52 +1,54 @@
# TODO
## Known issues
- z-image-turbo controlnet device mismatch: <https://github.com/huggingface/diffusers/pull/12886>
- z-image-turbo safetensors loader: <https://github.com/huggingface/diffusers/issues/12887>
- kandinsky-image-5 hardcoded cuda: <https://github.com/huggingface/diffusers/pull/12814>
- peft lora with torch-rocm-windows: <https://github.com/huggingface/peft/pull/2963>
## Project Board
- <https://github.com/users/vladmandic/projects>
## Internal
- Reimplement `llama` remover for kanvas
- Deploy: Create executable for SD.Next
- Feature: Integrate natural language image search
[ImageDB](https://github.com/vladmandic/imagedb)
- Feature: Transformers unified cache handler
- Feature: Remote Text-Encoder support
- Refactor: [Modular pipelines and guiders](https://github.com/huggingface/diffusers/issues/11915)
- Refactor: move sampler options to settings to config
- Refactor: [GGUF](https://huggingface.co/docs/diffusers/main/en/quantization/gguf)
- Feature: LoRA add OMI format support for SD35/FLUX.1
- Feature: Move `nunchaku` models to refernce instead of internal decision
- Update: `transformers==5.0.0`
- Feature: Unify *huggingface* and *diffusers* model folders
- Reimplement `llama` remover for Kanvas
- Deploy: Create executable for SD.Next
- Feature: Integrate natural language image search
[ImageDB](https://github.com/vladmandic/imagedb)
- Feature: Remote Text-Encoder support
- Refactor: move sampler options to settings to config
- Refactor: [GGUF](https://huggingface.co/docs/diffusers/main/en/quantization/gguf)
- Feature: LoRA add OMI format support for SD35/FLUX.1
- Refactor: remove `CodeFormer`
- Refactor: remove `GFPGAN`
- UI: Lite vs Expert mode
- Video tab: add full API support
- Control tab: add overrides handling
- Refactor: remove `GFPGAN`
- UI: Lite vs Expert mode
- Video tab: add full API support
- Control tab: add overrides handling
- Engine: `TensorRT` acceleration
- Engine: [mmgp](https://github.com/deepbeepmeep/mmgp)
- Engine: [sharpfin](https://github.com/drhead/sharpfin) instead of `torchvision`
## Modular
- Switch to modular pipelines
- Feature: Transformers unified cache handler
- Refactor: [Modular pipelines and guiders](https://github.com/huggingface/diffusers/issues/11915)
- [MagCache](https://github.com/lllyasviel/FramePack/pull/673/files)
- [SmoothCache](https://github.com/huggingface/diffusers/issues/11135)
## Features
- [Flux.2 TinyVAE](https://huggingface.co/fal/FLUX.2-Tiny-AutoEncoder)
- [IPAdapter composition](https://huggingface.co/ostris/ip-composition-adapter)
- [IPAdapter negative guidance](https://github.com/huggingface/diffusers/discussions/7167)
- [MagCache](https://github.com/lllyasviel/FramePack/pull/673/files)
- [SmoothCache](https://github.com/huggingface/diffusers/issues/11135)
- [STG](https://github.com/huggingface/diffusers/blob/main/examples/community/README.md#spatiotemporal-skip-guidance)
- [IPAdapter composition](https://huggingface.co/ostris/ip-composition-adapter)
- [IPAdapter negative guidance](https://github.com/huggingface/diffusers/discussions/7167)
- [STG](https://github.com/huggingface/diffusers/blob/main/examples/community/README.md#spatiotemporal-skip-guidance)
- [Video Inpaint Pipeline](https://github.com/huggingface/diffusers/pull/12506)
- [Sonic Inpaint](https://github.com/ubc-vision/sonic)
### New models / Pipelines
TODO: *Prioritize*!
TODO: Investigate which models are diffusers-compatible and prioritize!
- [Bria FiboEdit](https://github.com/huggingface/diffusers/commit/d7a1c31f4f85bae5a9e01cdce49bd7346bd8ccd6)
- [LTXVideo 0.98 LongMulti](https://github.com/huggingface/diffusers/pull/12614)
- [Cosmos-Predict-2.5](https://huggingface.co/nvidia/Cosmos-Predict2.5-2B)
- [NewBie Image Exp0.1](https://github.com/huggingface/diffusers/pull/12803)
- [Sana-I2V](https://github.com/huggingface/diffusers/pull/12634#issuecomment-3540534268)
@@ -54,7 +56,8 @@ TODO: *Prioritize*!
- [Bytedance Lynx](https://github.com/bytedance/lynx)
- [ByteDance OneReward](https://github.com/bytedance/OneReward)
- [ByteDance USO](https://github.com/bytedance/USO)
- [Chroma1 Radiance](https://huggingface.co/lodestones/Chroma1-Radiance)
- [Chroma Radiance](https://huggingface.co/lodestones/Chroma1-Radiance)
- [Chroma Zeta](https://huggingface.co/lodestones/Zeta-Chroma)
- [DiffSynth Studio](https://github.com/modelscope/DiffSynth-Studio)
- [DiffusionForcing](https://github.com/kwsong0113/diffusion-forcing-transformer)
- [Dream0 guidance](https://huggingface.co/ByteDance/DreamO)
+3 -3
View File
@@ -2,9 +2,9 @@
// simple nodejs script to test sdnext api
const fs = require('fs');
const path = require('path');
const process = require('process');
const fs = require('node:fs');
const path = require('node:path');
const argparse = require('argparse');
const sd_url = process.env.SDAPI_URL || 'http://127.0.0.1:7860';
+1 -2
View File
@@ -2,8 +2,7 @@
// simple nodejs script to test sdnext api
const fs = require('fs'); // eslint-disable-line no-undef
const process = require('process'); // eslint-disable-line no-undef
const fs = require('node:fs');
const sd_url = process.env.SDAPI_URL || 'http://127.0.0.1:7860';
const sd_username = process.env.SDAPI_USR;
-1
View File
@@ -40,7 +40,6 @@ def download_urllib(args):
fn = ''
req = urllib.request.Request(args.url, headers=headers)
res = urllib.request.urlopen(req)
res.getheader('content-length')
content_length = int(res.getheader('content-length') or 0)
fn = get_filename(args, res)
print(f'downloading: url={args.url} file={fn} size={content_length if content_length > 0 else "unknown"} lib=urllib block={args.block}')
+12 -3
View File
@@ -9,10 +9,19 @@ if __name__ == "__main__":
keyword = sys.argv[0] if len(sys.argv) > 0 else ''
hf.logging.set_verbosity_info()
hf_api = hf.HfApi()
res = hf_api.list_models(model_name=keyword, full=True, limit=100, sort="downloads", direction=-1)
res = hf_api.list_models(
model_name=keyword,
full=True,
limit=100,
sort="downloads",
direction=-1,
)
res = sorted(res, key=lambda x: x.id)
exact = [m for m in res if keyword.lower() in m.id.lower()]
if len(exact) > 0:
res = exact
for m in res:
meta = hf_api.model_info(m.id, files_metadata=True)
m.files = [f.rfilename for f in meta.siblings if f.rfilename.endswith('.bin') or f.rfilename.endswith('.safetensors')]
m.size = sum([f.size for f in meta.siblings]) / 1024 / 1024 / 1024 # in GB
print({ 'name': m.id, 'files': len(m.files), 'size': m.size, 'downloads': m.downloads, 'mtime': m.lastModified, 'url': f'https://huggingface.co/{m.id}', 'pipeline': m.pipeline_tag })
m.size = round(sum([f.size for f in meta.siblings]) / 1024 / 1024 / 1024, 2)
print({ 'name': m.id, 'files': len(m.files), 'size': m.size, 'downloads': m.downloads, 'ctime': m.created_at.isoformat(), 'url': f'https://huggingface.co/{m.id}', 'pipeline': m.pipeline_tag })
+2 -2
View File
@@ -1,8 +1,8 @@
#!/usr/bin/env node
// script used to localize sdnext ui and hints to multiple languages using google gemini ai
const fs = require('fs');
const process = require('process');
const fs = require('node:fs');
const { GoogleGenerativeAI } = require('@google/generative-ai');
const api_key = process.env.GOOGLE_AI_API_KEY;
+339
View File
@@ -0,0 +1,339 @@
import path from 'node:path';
import { includeIgnoreFile } from '@eslint/compat';
import css from '@eslint/css';
import js from '@eslint/js';
import json from '@eslint/json';
import markdown from '@eslint/markdown';
import html from '@html-eslint/eslint-plugin';
import { configs, helpers, plugins, rules } from 'eslint-config-airbnb-extended';
import pluginPromise from 'eslint-plugin-promise';
import { defineConfig, globalIgnores } from 'eslint/config';
import globals from 'globals';
const gitignorePath = path.resolve('.', '.gitignore');
const jsConfig = defineConfig([
// ESLint recommended config
{
name: 'js/config',
files: helpers.extensions.allFiles,
...js.configs.recommended,
languageOptions: {
ecmaVersion: 'latest',
parserOptions: {
ecmaVersion: 'latest',
},
globals: { // Set per project
...globals.builtin,
...globals.browser,
...globals.jquery,
panzoom: 'readonly',
authFetch: 'readonly',
log: 'readonly',
debug: 'readonly',
error: 'readonly',
xhrGet: 'readonly',
xhrPost: 'readonly',
gradioApp: 'readonly',
executeCallbacks: 'readonly',
onAfterUiUpdate: 'readonly',
onOptionsChanged: 'readonly',
optionsChangedCallbacks: 'readonly',
onUiLoaded: 'readonly',
onUiUpdate: 'readonly',
onUiTabChange: 'readonly',
onUiReady: 'readonly',
uiCurrentTab: 'writable',
uiElementIsVisible: 'readonly',
uiElementInSight: 'readonly',
getUICurrentTabContent: 'readonly',
waitForFlag: 'readonly',
logFn: 'readonly',
generateForever: 'readonly',
showContributors: 'readonly',
opts: 'writable',
sortUIElements: 'readonly',
all_gallery_buttons: 'readonly',
selected_gallery_button: 'readonly',
selected_gallery_index: 'readonly',
switch_to_txt2img: 'readonly',
switch_to_img2img_tab: 'readonly',
switch_to_img2img: 'readonly',
switch_to_sketch: 'readonly',
switch_to_inpaint: 'readonly',
witch_to_inpaint_sketch: 'readonly',
switch_to_extras: 'readonly',
get_tab_index: 'readonly',
create_submit_args: 'readonly',
restartReload: 'readonly',
markSelectedCards: 'readonly',
updateInput: 'readonly',
toggleCompact: 'readonly',
setFontSize: 'readonly',
setTheme: 'readonly',
registerDragDrop: 'readonly',
getToken: 'readonly',
getENActiveTab: 'readonly',
quickApplyStyle: 'readonly',
quickSaveStyle: 'readonly',
setupExtraNetworks: 'readonly',
showNetworks: 'readonly',
localization: 'readonly',
randomId: 'readonly',
requestProgress: 'readonly',
setRefreshInterval: 'readonly',
modalPrevImage: 'readonly',
modalNextImage: 'readonly',
galleryClickEventHandler: 'readonly',
getExif: 'readonly',
jobStatusEl: 'readonly',
removeSplash: 'readonly',
initGPU: 'readonly',
startGPU: 'readonly',
disableNVML: 'readonly',
idbGet: 'readonly',
idbPut: 'readonly',
idbDel: 'readonly',
idbAdd: 'readonly',
idbCount: 'readonly',
idbFolderCleanup: 'readonly',
initChangelog: 'readonly',
sendNotification: 'readonly',
monitorConnection: 'readonly',
},
},
},
pluginPromise.configs['flat/recommended'],
// Stylistic plugin
plugins.stylistic,
// Import X plugin
plugins.importX,
// Airbnb base recommended config
...configs.base.recommended,
{
name: 'sdnext/js',
files: helpers.extensions.allFiles,
languageOptions: {
ecmaVersion: 'latest',
parserOptions: {
ecmaVersion: 'latest',
},
},
rules: {
camelcase: 'off',
'default-case': 'off',
'max-classes-per-file': 'warn',
'no-await-in-loop': 'off',
'no-bitwise': 'off',
'no-continue': 'off',
'no-console': 'off',
'no-loop-func': 'off',
'no-param-reassign': 'off',
'no-plusplus': 'off',
'no-redeclare': 'off',
'no-restricted-globals': 'off',
'no-restricted-syntax': 'off',
'no-unused-vars': 'off',
'no-use-before-define': 'warn',
'no-useless-escape': 'warn',
'prefer-destructuring': 'off',
'prefer-rest-params': 'off',
'prefer-template': 'warn',
'promise/no-nesting': 'off',
radix: 'off',
'@stylistic/brace-style': [
'error',
'1tbs',
{
allowSingleLine: true,
},
],
'@stylistic/indent': ['error', 2],
'@stylistic/lines-between-class-members': [
'error',
'always',
{
exceptAfterSingleLine: true,
},
],
'@stylistic/max-len': [
'warn',
{
code: 275,
tabWidth: 2,
},
],
'@stylistic/max-statements-per-line': 'off',
'@stylistic/no-mixed-operators': 'off',
'@stylistic/object-curly-newline': [
'error',
{
multiline: true,
consistent: true,
},
],
'@stylistic/quotes': [
'error',
'single',
{
avoidEscape: true,
},
],
'@stylistic/semi': [
'error',
'always',
{
omitLastInOneLineBlock: false,
},
],
'promise/always-return': 'off',
'promise/catch-or-return': 'off',
},
},
]);
// const typescriptConfig = defineConfig([
// // TypeScript ESLint plugin
// plugins.typescriptEslint,
// // Airbnb base TypeScript config
// ...configs.base.typescript,
// {
// name: 'sdnext/typescript',
// files: helpers.extensions.tsFiles,
// rules: {
// '@typescript-eslint/ban-ts-comment': 'off',
// '@typescript-eslint/explicit-module-boundary-types': 'off',
// '@typescript-eslint/no-shadow': 'error',
// '@typescript-eslint/no-var-requires': 'off',
// },
// },
// ]);
const nodeConfig = defineConfig([
// Node plugin
plugins.node,
{
name: 'sdnext/node',
files: ['**/cli/*.js'],
languageOptions: {
globals: {
...globals.node,
},
},
rules: {
// Import as rule sets to override the `files` setting from default config
...rules.node.base.rules,
...rules.node.globals.rules,
...rules.node.noUnsupportedFeatures.rules,
...rules.node.promises.rules,
'n/no-sync': 'off',
'n/no-process-exit': 'off',
'n/hashbang': 'off',
},
},
]);
const jsonConfig = defineConfig([
{
files: ['**/*.json'],
ignores: ['package-lock.json'],
plugins: { json },
language: 'json/json',
extends: ['json/recommended'],
},
]);
const markdownConfig = defineConfig([
{
files: ['**/*.md'],
plugins: { markdown },
language: 'markdown/gfm',
processor: 'markdown/markdown',
extends: ['markdown/recommended'],
},
]);
const cssConfig = defineConfig([
{
files: ['**/*.css'],
language: 'css/css',
plugins: { css },
extends: ['css/recommended'],
// languageOptions: {
// tolerant: true,
// },
rules: {
'css/font-family-fallbacks': 'off',
'css/no-invalid-properties': [
'error',
{
allowUnknownVariables: true,
},
],
'css/no-important': 'off',
'css/use-baseline': 'off',
},
},
]);
const htmlConfig = defineConfig([
{
files: ['**/*.html'],
plugins: {
html,
},
extends: ['html/recommended'],
language: 'html/html',
rules: {
'html/attrs-newline': 'off',
'html/element-newline': 'off',
'html/indent': [
'warn',
2,
],
'html/no-duplicate-class': 'error',
'html/no-extra-spacing-attrs': [
'error',
{
enforceBeforeSelfClose: true,
disallowMissing: true,
disallowTabs: true,
disallowInAssignment: true,
},
],
'html/require-closing-tags': [
'error',
{
selfClosing: 'always',
},
],
'html/use-baseline': 'off',
},
},
]);
export default defineConfig([
// Ignore files and folders listed in .gitignore
includeIgnoreFile(gitignorePath),
globalIgnores([
'**/node_modules',
'**/extensions',
'**/extensions-builtin',
'**/repositories',
'**/venv',
'**/panZoom.js',
'**/split.js',
'**/exifr.js',
'**/jquery.js',
'**/sparkline.js',
'**/iframeResizer.min.js',
]),
...jsConfig,
// ...typescriptConfig,
...nodeConfig,
...jsonConfig,
...markdownConfig,
...cssConfig,
...htmlConfig,
]);
+23 -5
View File
@@ -97,8 +97,11 @@
{"id":"","label":"Build info on first access","localized":"","reload":"","hint":"Prevents server from building EN page on server startup and instead build it when requested"},
{"id":"","label":"Show reference styles","localized":"","reload":"","hint":"Show or hide build-it styles"},
{"id":"","label":"LoRA load using Diffusers method","localized":"","reload":"","hint":"Alternative method uses diffusers built-in LoRA capabilities instead of native SD.Next implementation (may reduce LoRA compatibility)"},
{"id":"","label":"LoRA fuse directly to model","localized":"","reload":"","hint":"When loading LoRAs, immediately merge weights with underlying model instead of applying them on-the-fly"},
{"id":"","label":"LoRA native fuse with model","localized":"","reload":"","hint":"Merge LoRA into the model for lower memory usage.<br><br><b style=\"color: #ef4444\">Warning:</b> After removing or switching a LoRA, you may still see its style in generated images. To get a clean model, reload it from the model selector."},
{"id":"","label":"LoRA memory cache","localized":"","reload":"","hint":"How many LoRAs to keep in network for future use before requiring reloading from storage"},
{"id":"","label":"LoRA force reload always","localized":"","reload":"","hint":"Forces LoRA networks to reload from storage on every generation, even if already cached.<br>Useful for debugging or when LoRA files are being modified externally.<br>Disable for normal use to benefit from caching."},
{"id":"","label":"LoRA diffusers fuse with model","localized":"","reload":"","hint":"Merge LoRA into the model for lower memory usage and torch.compile compatibility.<br><br><b style=\"color: #ef4444\">Warning:</b> After removing or switching a LoRA, you may still see its style in generated images. To get a clean model, reload it from the model selector."},
{"id":"","label":"LoRA precision when quantized","localized":"","reload":"","hint":"When using a BnB 4-bit model, LoRA is applied by decompressing the weights, adding the LoRA, then recompressing. This controls the format used for recompression.<br><br>Only affects BnB 4-bit models. SDNQ models keep their original format."},
{"id":"","label":"Local","localized":"","reload":"","hint":"Models that are downlaoded and ready to use"},
{"id":"","label":"Gallery","localized":"","reload":"","hint":"Image gallery"},
{"id":"","label":"Reference","localized":"","reload":"","hint":"List of reference models that can be automatically downloaded on first use"},
@@ -156,7 +159,7 @@
{"id":"","label":"HDR Maximize","localized":"","reload":"","hint":"Calculates a 'normalization factor' by dividing the maximum tensor value by the specified range multiplied by 4. This factor is then used to shift the channels within the given boundary, ensuring maximum dynamic range for subsequent processing. The objective is to optimize dynamic range for external applications like Photoshop, particularly for adjusting levels, contrast, and brightness"},
{"id":"","label":"Enable refine pass","localized":"","reload":"","hint":"Use a similar process as image to image to upscale and/or add detail to the final image. Optionally uses refiner model to enhance image details."},
{"id":"","label":"Enable detailer pass","localized":"","reload":"","hint":"Detect target objects such as face and reprocess it at higher resolution"},
{"id":"","label":"Include detection results","localized":"","reload":"","hint":"Include original image with detected areas marked"},
{"id":"","label":"Include detections","localized":"","reload":"","hint":"Include original image with detected areas marked"},
{"id":"","label":"Sort detections","localized":"","reload":"","hint":"Sort detected areas by from left to right instead of detection score"},
{"id":"","label":"Denoising strength","localized":"","reload":"","hint":"Determines how little respect the algorithm should have for image's content. At 0, nothing will change, and at 1 you'll get an unrelated image. With values below 1.0, processing will take less steps than the Sampling Steps slider specifies"},
{"id":"","label":"Denoise start","localized":"","reload":"","hint":"Override denoise strength by stating how early base model should finish and when refiner should start. Only applicable to refiner usage. If set to 0 or 1, denoising strength will be used"},
@@ -241,6 +244,21 @@
{"id":"","label":"Sort by","localized":"","reload":"","hint":"Sort by"},
{"id":"","label":"Nudenet","localized":"","reload":"","hint":"Flexible extension that can detect and obfustate nudity in images"},
{"id":"","label":"Prompt enhance","localized":"","reload":"","hint":"Extension that can use different LLMs to rewrite prompt for improved results"},
{"id":"","label":"Enhance now","localized":"","reload":"","hint":"Run prompt enhancement using the selected LLM model"},
{"id":"","label":"Apply to prompt","localized":"","reload":"","hint":"Automatically copy enhanced result to the prompt input box"},
{"id":"","label":"Auto enhance","localized":"","reload":"","hint":"Automatically enhance prompt before every image generation"},
{"id":"","label":"Use vision","localized":"","reload":"","hint":"Include input image when enhancing prompt.<br><br>Only available for vision-capable models, marked with \uf06e icon."},
{"id":"","label":"LLM model","localized":"","reload":"","hint":"Select the language model to use for prompt enhancement.<br><br>Models supporting vision are marked with \uf06e icon.<br>Models supporting thinking mode are marked with \uf0eb icon."},
{"id":"","label":"Model repo","localized":"","reload":"","hint":"HuggingFace repository ID for the model"},
{"id":"","label":"Model gguf","localized":"","reload":"","hint":"Optional GGUF quantized model repository on HuggingFace"},
{"id":"","label":"Model type","localized":"","reload":"","hint":"Optional GGUF model quantization type"},
{"id":"","label":"Model file","localized":"","reload":"","hint":"Optional specific GGUF model file inside the repository"},
{"id":"","label":"Load custom model","localized":"","reload":"","hint":"Load a custom model with the specified configuration"},
{"id":"","label":"NSFW allowed","localized":"","reload":"","hint":"Allow the model to generate adult content in enhanced prompts"},
{"id":"","label":"Prompt prefix","localized":"","reload":"","hint":"Text prepended at the beginning of the enhanced prompt result.<br><br>Useful for adding prompt elements which need to be copied to the image prompt unchanged, like quality tags 'masterpiece, best quality' or artist names, which would otherwise be rewritten by the LLM."},
{"id":"","label":"Prompt suffix","localized":"","reload":"","hint":"Text appended to the end of the enhanced prompt result.<br><br>Useful for adding prompt elements which need to be copied to the image prompt unchanged, which would otherwise be rewritten by the LLM."},
{"id":"","label":"Enhanced prompt","localized":"","reload":"","hint":"The enhanced prompt output from the LLM"},
{"id":"","label":"Set prompt","localized":"","reload":"","hint":"Copy the enhanced prompt to the main prompt input"},
{"id":"","label":"Manage extensions","localized":"","reload":"","hint":"Manage extensions"},
{"id":"","label":"Manual install","localized":"","reload":"","hint":"Manually install extension"},
{"id":"","label":"Extension GIT repository URL","localized":"","reload":"","hint":"Specify extension repository URL on GitHub"},
@@ -876,8 +894,8 @@
{"id":"","label":"loaded lora","localized":"","reload":"","hint":"loaded lora"},
{"id":"","label":"logsnr","localized":"","reload":"","hint":"logsnr"},
{"id":"","label":"loop","localized":"","reload":"","hint":"loop"},
{"id":"","label":"lora add hash info to metadata","localized":"","reload":"","hint":"lora add hash info to metadata"},
{"id":"","label":"lora auto-apply tags","localized":"","reload":"","hint":"lora auto-apply tags"},
{"id":"","label":"LoRA add hash info to metadata","localized":"","reload":"","hint":"Include LoRA file hashes in generated image metadata.<br>Useful for reproducibility and tracking which exact LoRA versions were used."},
{"id":"","label":"LoRA auto-apply tags","localized":"","reload":"","hint":"Automatically add trigger words/tags from LoRA metadata to your prompt.<br>Set to the number of tags to auto-apply, e.g., 3 = add top 3 trigger tags.<br>Set to 0 to disable, -1 to add all available tags."},
{"id":"","label":"lora load using diffusers method for selected models","localized":"","reload":"","hint":"lora load using diffusers method for selected models"},
{"id":"","label":"lora load using legacy method","localized":"","reload":"","hint":"lora load using legacy method"},
{"id":"","label":"lora target filename","localized":"","reload":"","hint":"lora target filename"},
@@ -1209,7 +1227,7 @@
{"id":"","label":"tdd","localized":"","reload":"","hint":"tdd"},
{"id":"","label":"te","localized":"","reload":"","hint":"te"},
{"id":"","label":"temperature","localized":"","reload":"","hint":"Controls randomness in token selection by reshaping the probability distribution.<br>Like adjusting a dial between cautious predictability (low values ~0.4) and creative exploration (higher values ~1). Higher temperatures increase willingness to choose less obvious options, but makes outputs more unpredictable.<br><br>Set to 0 to disable, resulting in silent switch to greedy decoding, disabling sampling."},
{"id":"","label":"Thinking mode","localized":"","reload":"","hint":"Enables thinking/reasoning, allowing the model to take more time to generate responses.<br>This can lead to more thoughtful and detailed answers, but will increase response time.<br>This setting affects both hybrid and thinking-only models, and in some may result in lower overall quality than expected. For thinking-only models like Qwen3-VL this setting might have to be combined with prefill to guarantee preventing thinking.<br><br>Models supporting this feature are marked with an \uf0eb icon."},
{"id":"","label":"Thinking Mode","localized":"","reload":"","hint":"Enables thinking/reasoning, allowing the model to take more time to generate responses.<br>This can lead to more thoughtful and detailed answers, but will increase response time.<br>This setting affects both hybrid and thinking-only models, and in some may result in lower overall quality than expected. For thinking-only models like Qwen3-VL this setting might have to be combined with prefill to guarantee preventing thinking.<br><br>Models supporting this feature are marked with an \uf0eb icon."},
{"id":"","label":"Repetition penalty","localized":"","reload":"","hint":"Discourages reusing tokens that already appear in the prompt or output by penalizing their probabilities.<br>Like adding friction to revisiting previous choices. Helps break repetitive loops but may reduce coherence at aggressive values.<br><br>Set to 1 to disable."},
{"id":"","label":"text guidance scale","localized":"","reload":"","hint":"text guidance scale"},
{"id":"","label":"template","localized":"","reload":"","hint":"template"},
+16
View File
@@ -0,0 +1,16 @@
{
"Google Gemini 2.5 Flash Nano Banana": {
"path": "gemini-2.5-flash-image",
"desc": "Gemini can generate and process images conversationally. You can prompt Gemini with text, images, or a combination of both allowing you to create, edit, and iterate on visuals with unprecedented control.",
"preview": "gemini-2.5-flash-image.jpg",
"tags": "cloud",
"skip": true
},
"Google Gemini 3.0 Pro Nano Banana": {
"path": "gemini-3-pro-image-preview",
"desc": "Built on Gemini 3. Create and edit images with studio-quality levels of precision and control",
"preview": "gemini-3-pro-image-preview.jpg",
"tags": "cloud",
"skip": true
}
}
+132
View File
@@ -0,0 +1,132 @@
{
"Tempest-by-Vlad XL": {
"path": "tempestByVlad_baseV01.safetensors@https://civitai.com/api/download/models/1301775",
"preview": "tempestByVlad_baseV01.jpg",
"desc": "Flexible SDXL model with custom encoder and finetuned for larger landscape resolutions with high details and high contrast.",
"tags": "community",
"size": 6.94,
"date": "2025 January",
"extras": ""
},
"Tempest-by-Vlad XL Hyper": {
"path": "tempestByVlad_hyperV01.safetensors@https://civitai.com/api/download/models/1343512",
"preview": "tempestByVlad_hyperV01.jpg",
"desc": "Custom distilled variant with goal to get as-normal-as-possible model that works with low steps and guidance-free",
"tags": "community",
"size": 6.94,
"date": "2025 January",
"extras": ""
},
"Juggernaut XL XI": {
"path": "juggernautXL_juggXIByRundiffusion.safetensors@https://civitai.com/api/download/models/782002",
"preview": "juggernautXL_juggXIByRundiffusion.jpg",
"desc": "Showcase finetuned model based on Stable diffusion XL",
"date": "2024 August",
"size": 6.94,
"tags": "community",
"extras": "sampler: DEIS, steps: 20, cfg_scale: 6.0"
},
"Juggernaut XL XI Lightning": {
"path": "juggernautXL_juggXILightningByRD.safetensors@https://civitai.com/api/download/models/920957",
"preview": "juggernautXL_juggXILightningByRD.jpg",
"desc": "Showcase finetuned model based on Stable diffusion XL",
"date": "2024 August",
"size": 6.94,
"tags": "community",
"extras": "sampler: DPM SDE, steps: 6, cfg_scale: 2.0"
},
"Juggernaut SD Reborn": {
"original": true,
"path": "juggernaut_reborn.safetensors@https://civitai.com/api/download/models/274039",
"preview": "juggernaut_reborn.jpg",
"desc": "Showcase finetuned model based on Stable diffusion 1.5",
"date": "2023 December",
"size": 2.28,
"tags": "community",
"extras": "width: 512, height: 512, sampler: DEIS, steps: 20, cfg_scale: 6.0"
},
"WAI Illustrious XL v15": {
"path": "waiIllustriousSDXL_v150.safetensors@https://civitai.com/api/download/models/2167369",
"preview": "waiIllustriousSDXL_v150.jpg",
"desc": "",
"tags": "community",
"size": 6.94,
"date": "2025 August",
"extras": ""
},
"Pony Realism XL v2.3": {
"path": "ponyRealism_V23.safetensors@https://civitai.com/api/download/models/1763661",
"preview": "ponyRealism_V23.jpg",
"desc": "",
"tags": "community",
"size": 6.94,
"date": "2025 May",
"extras": ""
},
"NoobAI XL 1.0 V-Pred": {
"path": "noobaiXLNAIXL_vPred10Version.safetensors@https://huggingface.co/Laxhar/noobai-XL-Vpred-1.0/resolve/main/NoobAI-XL-Vpred-v1.0.safetensors",
"preview": "noobaiXLNAIXL_vPred10Version.jpg",
"desc": "",
"tags": "community",
"size": 6.94,
"date": "2024 December",
"extras": ""
},
"NoobAI XL 1.1 Epsilon": {
"path": "noobaiXLNAIXL_epsilonPred11Version.safetensors@https://huggingface.co/Laxhar/noobai-XL-1.1/resolve/main/NoobAI-XL-v1.1.safetensors",
"preview": "noobaiXLNAIXL_epsilonPred11Version.jpg",
"desc": "",
"tags": "community",
"size": 6.94,
"date": "2024 November",
"extras": ""
},
"WAI-Ani-Pony XL v14": {
"path": "waiANIPONYXL_v140.safetensors.safetensors@https://civitai.com/api/download/models/1767402",
"preview": "waiANIPONYXL_v140.jpg",
"desc": "",
"tags": "community",
"size": 6.94,
"date": "2025 May",
"extras": ""
},
"Tiwaz CenKreChro": {
"path": "Tiwaz/CenKreChro",
"preview": "Tiwaz--CenKreChro.jpg",
"skip": true,
"desc": "Based Centerfold Flux 5, trying to merge in Chroma and Krea.",
"extras": "",
"tags": "community",
"date": "2025 September"
},
"purplesmartai Pony 7": {
"path": "purplesmartai/pony-v7-base",
"preview": "purplesmartai--pony-v7-base.jpg",
"skip": true,
"desc": "Pony V7 is a versatile character generation model based on AuraFlow architecture. It supports a wide range of styles and species types (humanoid, anthro, feral, and more) and handles character interactions through natural language prompts.",
"extras": "",
"tags": "community",
"date": "October September"
},
"ShuttleAI Shuttle 3.0 Diffusion": {
"path": "shuttleai/shuttle-3-diffusion",
"desc": "Shuttle uses Flux.1 Schnell as its base. It can produce images similar to Flux Dev or Pro in just 4 steps, and it is licensed under Apache 2. The model was partially de-distilled during training. When used beyond 10 steps, it enters refiner mode enhancing image details without altering the composition",
"preview": "shuttleai--shuttle-3-diffusion.jpg",
"tags": "community",
"skip": true
},
"ShuttleAI Shuttle 3.1 Aesthetic": {
"path": "shuttleai/shuttle-3.1-aesthetic",
"desc": "Shuttle uses Flux.1 Schnell as its base. It can produce images similar to Flux Dev or Pro in just 4 steps, and it is licensed under Apache 2. The model was partially de-distilled during training. When used beyond 10 steps, it enters refiner mode enhancing image details without altering the composition",
"preview": "shuttleai--shuttle-3_1-aestetic.jpg",
"tags": "community",
"skip": true
},
"ShuttleAI Shuttle Jaguar": {
"path": "shuttleai/shuttle-jaguar",
"desc": "Shuttle uses Flux.1 Schnell as its base. It can produce images similar to Flux Dev or Pro in just 4 steps, and it is licensed under Apache 2. The model was partially de-distilled during training. When used beyond 10 steps, it enters refiner mode enhancing image details without altering the composition",
"preview": "shuttleai--shuttle-jaguar.jpg",
"tags": "community",
"skip": true
}
}
+185
View File
@@ -0,0 +1,185 @@
{
"StabilityAI StableDiffusion XL Turbo": {
"path": "stabilityai/sdxl-turbo",
"preview": "stabilityai--sdxl-turbo.jpg",
"desc": "SDXL-Turbo is a fast generative text-to-image model that can synthesize photorealistic images from a text prompt in a 1-4 steps.",
"skip": true,
"variant": "fp16",
"tags": "distilled",
"extras": "steps: 4, cfg_scale: 0.0"
},
"StabilityAI Stable Cascade Lite": {
"path": "huggingface/stabilityai/stable-cascade-lite",
"skip": true,
"variant": "bf16",
"desc": "Stable Cascade is a diffusion model built upon the Würstchen architecture and its main difference to other models like Stable Diffusion is that it is working at a much smaller latent space. Why is this important? The smaller the latent space, the faster you can run inference and the cheaper the training becomes. How small is the latent space? Stable Diffusion uses a compression factor of 8, resulting in a 1024x1024 image being encoded to 128x128. Stable Cascade achieves a compression factor of 42, meaning that it is possible to encode a 1024x1024 image to 24x24, while maintaining crisp reconstructions. The text-conditional model is then trained in the highly compressed latent space. Previous versions of this architecture, achieved a 16x cost reduction over Stable Diffusion 1.5",
"preview": "stabilityai--stable-cascade-lite.jpg",
"extras": "sampler: Default, cfg_scale: 4.0, image_cfg_scale: 1.0",
"size": 4.97,
"tags": "distilled",
"date": "2024 February"
},
"StabilityAI Stable Diffusion 3.5 Turbo": {
"path": "stabilityai/stable-diffusion-3.5-large-turbo",
"skip": true,
"variant": "fp16",
"desc": "Stable Diffusion 3.5 Large Turbo is a Multimodal Diffusion Transformer (MMDiT) text-to-image model with Adversarial Diffusion Distillation (ADD) that features improved performance in image quality, typography, complex prompt understanding, and resource-efficiency, with a focus on fewer inference steps.",
"preview": "stabilityai--stable-diffusion-3_5-large-turbo.jpg",
"tags": "distilled",
"extras": "sampler: Default, cfg_scale: 7.0"
},
"Tencent FLUX.1 Dev SRPO": {
"path": "vladmandic/flux.1-dev-SRPO",
"preview": "vladmandic--flux.1-dev-SRPO.jpg",
"desc": "FLUX.1 Dev SRPO is Tencent trained with specific technique: Directly Aligning the Full Diffusion Trajectory with Fine-Grained Human Preference",
"tags": "distilled",
"skip": true,
"extras": "sampler: Default, cfg_scale: 4.5"
},
"Qwen-Image-Lightning": {
"path": "vladmandic/Qwen-Lightning",
"preview": "vladmandic--Qwen-Lightning.jpg",
"desc": "Qwen-Lightning is step-distilled from Qwen-Image to allow for generation in 8 steps.",
"skip": true,
"extras": "steps: 8",
"size": 56.1,
"tags": "distilled",
"date": "2025 August"
},
"Qwen-Image-Distill": {
"path": "SahilCarterr/Qwen-Image-Distill-Full",
"preview": "SahilCarterr--Qwen-Image-Distill-Full.jpg",
"desc": "Qwen-Image-Distill is a distilled and accelerated version of Qwen-Image by DiffSynth-Studio.",
"skip": true,
"extras": "steps: 15",
"size": 56.1,
"tags": "distilled",
"date": "2025 August"
},
"Qwen-Image-Lightning-Edit": {
"path": "vladmandic/Qwen-Lightning-Edit",
"preview": "vladmandic--Qwen-Lightning-Edit.jpg",
"desc": "Qwen-Lightning-Edit is step-distilled from Qwen-Image-Edit to allow for generation in 8 steps.",
"skip": true,
"extras": "steps: 8",
"size": 56.1,
"tags": "distilled",
"date": "2025 August"
},
"Qwen-Image Pruning-12B": {
"path": "OPPOer/Qwen-Image-Pruning",
"subfolder": "Qwen-Image-12B-8steps",
"preview": "OPPOer--Qwen-Image-Pruning.jpg",
"desc": "This open-source project is based on Qwen-Image and has attempted model pruning, removing 20 layers while retaining the weights of 40 layers, resulting in a model size of 12B parameters.",
"skip": true,
"tags": "distilled",
"date": "2025 Ocotober"
},
"Qwen-Image-Edit Pruning-13B": {
"path": "OPPOer/Qwen-Image-Edit-Pruning",
"subfolder": "Qwen-Image-Edit-13B-4steps",
"preview": "OPPOer--Qwen-Image-Edit-Pruning.jpg",
"desc": "This open-source project is based on Qwen-Image-Edit and has attempted model pruning, removing 20 layers while retaining the weights of 40 layers, resulting in a model size of 13.6B parameters.",
"skip": true,
"tags": "distilled",
"date": "2025 Ocotober"
},
"Qwen-Image-Edit-2509 Pruning-13B": {
"path": "OPPOer/Qwen-Image-Edit-2509-Pruning",
"subfolder": "Qwen-Image-Edit-2509-13B-4steps",
"preview": "OPPOer--Qwen-Image-Edit-2509-Pruning.jpg",
"desc": "This open-source project is based on Qwen-Image-Edit and has attempted model pruning, removing 20 layers while retaining the weights of 40 layers, resulting in a model size of 13.6B parameters.",
"skip": true,
"tags": "distilled",
"date": "2025 Ocotober"
},
"lodestones Chroma1 Flash": {
"path": "lodestones/Chroma1-Flash",
"preview": "lodestones--Chroma1-Flash.jpg",
"desc": "Chroma is a 8.9B parameter model based on FLUX.1-schnell. Its fully Apache 2.0 licensed, ensuring that anyone can use, modify, and build on top of it—no corporate gatekeeping. A fine-tuned version of the Chroma1-Base made to find the best way to make these flow matching models faster.",
"skip": true,
"extras": "",
"size": 26.84,
"tags": "distilled",
"date": "2025 July"
},
"SDXL Flash Mini": {
"path": "SDXL-Flash_Mini.safetensors@https://huggingface.co/sd-community/sdxl-flash-mini/resolve/main/SDXL-Flash_Mini.safetensors?download=true",
"preview": "SDXL-Flash_Mini.jpg",
"desc": "Introducing the new fast model SDXL Flash (Mini), we learned that all fast XL models work fast, but the quality decreases, and we also made a fast model, but it is not as fast as LCM, Turbo, Lightning and Hyper, but the quality is higher.",
"extras": "width: 2048, height: 1024, sampler: DEIS, steps: 40, cfg_scale: 6.0",
"tags": "distilled",
"experimental": true
},
"NVLabs Sana 1.5 1.6B 1k Sprint": {
"path": "Efficient-Large-Model/Sana_Sprint_1.6B_1024px_diffusers",
"desc": "SANA-Sprint is an ultra-efficient diffusion model for text-to-image (T2I) generation, reducing inference steps from 20 to 1-4 while achieving state-of-the-art performance.",
"preview": "Efficient-Large-Model--Sana15_Sprint_1600M_1024px_diffusers.jpg",
"tags": "distilled",
"skip": true
},
"Segmind SSD-1B": {
"path": "huggingface/segmind/SSD-1B",
"preview": "segmind--SSD-1B.jpg",
"desc": "The Segmind Stable Diffusion Model (SSD-1B) offers a compact, efficient, and distilled version of the SDXL model. At 50% smaller and 60% faster than Stable Diffusion XL (SDXL), it provides quick and seamless performance without sacrificing image quality.",
"variant": "fp16",
"skip": true,
"extras": "sampler: Default, cfg_scale: 9.0",
"size": 8.72,
"tags": "distilled",
"date": "2023 October"
},
"Segmind Tiny": {
"path": "segmind/tiny-sd",
"preview": "segmind--tiny-sd.jpg",
"desc": "Segmind's Tiny-SD offers a compact, efficient, and distilled version of Realistic Vision 4.0 and is up to 80% faster than SD1.5",
"extras": "width: 512, height: 512, sampler: Default, cfg_scale: 9.0",
"size": 1.03,
"tags": "distilled",
"date": "2023 July"
},
"Tencent HunyuanImage 2.1 Distilled": {
"path": "hunyuanvideo-community/HunyuanImage-2.1-Distilled-Diffusers",
"desc": "HunyuanImage-2.1, a highly efficient text-to-image model that is capable of generating 2K (2048 × 2048) resolution images.",
"preview": "hunyuanvideo-community--HunyuanImage-2.1-Distilled-Diffusers.jpg",
"extras": "",
"tags": "distilled",
"skip": true,
"size": 0,
"date": "2025 August"
},
"Tencent HunyuanDiT 1.2 Distilled": {
"path": "Tencent-Hunyuan/HunyuanDiT-v1.2-Diffusers-Distilled",
"desc": "Hunyuan-DiT : A Powerful Multi-Resolution Diffusion Transformer with Fine-Grained Chinese Understanding.",
"preview": "Tencent-Hunyuan--HunyuanDiT-v1.2-Diffusers-Distilled.jpg",
"tags": "distilled",
"extras": "sampler: Default, cfg_scale: 2.0"
},
"Tencent HunyuanDiT 1.1 Distilled": {
"path": "Tencent-Hunyuan/HunyuanDiT-v1.1-Diffusers-Distilled",
"desc": "Hunyuan-DiT : A Powerful Multi-Resolution Diffusion Transformer with Fine-Grained Chinese Understanding.",
"preview": "Tencent-Hunyuan--HunyuanDiT-v1.1-Diffusers-Distilled.jpg",
"tags": "distilled",
"extras": "sampler: Default, cfg_scale: 2.0"
},
"Black Forest Labs FLUX.2 Klein 4B": {
"path": "black-forest-labs/FLUX.2-klein-4B",
"preview": "black-forest-labs--FLUX.2-klein-4B.jpg",
"desc": "FLUX.2-klein-4B is a 4 billion parameter size-distilled version of FLUX.2-dev optimized for consumer GPUs. Achieves sub-second inference with 4 steps. Supports both text-to-image generation and multi-reference image editing. Apache 2.0 licensed.",
"skip": true,
"tags": "distilled",
"extras": "sampler: Default, cfg_scale: 1.0, steps: 4",
"size": 8.5,
"date": "2025 January"
},
"Black Forest Labs FLUX.2 Klein 9B": {
"path": "black-forest-labs/FLUX.2-klein-9B",
"preview": "black-forest-labs--FLUX.2-klein-9B.jpg",
"desc": "FLUX.2-klein-9B is a 9 billion parameter size-distilled version of FLUX.2-dev. Higher quality than 4B variant with sub-second inference using 4 steps. Supports text-to-image and multi-reference editing. Non-commercial license.",
"skip": true,
"tags": "distilled",
"extras": "sampler: Default, cfg_scale: 1.0, steps: 4",
"size": 18.5,
"date": "2025 January"
}
}
+239
View File
@@ -0,0 +1,239 @@
{
"FLUX.1-Dev sdnq-svd-uint4": {
"path": "Disty0/FLUX.1-dev-SDNQ-uint4-svd-r32",
"preview": "Disty0--FLUX.1-dev-SDNQ-uint4-svd-r32.jpg",
"desc": "Quantization of black-forest-labs/FLUX.1-dev using SDNQ: sdnq-svd 4-bit uint with svd rank 32",
"skip": true,
"tags": "quantized",
"size": 12.60,
"date": "2025 October",
"extras": ""
},
"FLUX.1-Schnell sdnq-svd-uint4": {
"path": "Disty0/FLUX.1-schnell-SDNQ-uint4-svd-r32",
"preview": "Disty0--FLUX.1-schnell-SDNQ-uint4-svd-r32.jpg",
"desc": "Quantization of black-forest-labs/FLUX.1-schnell using SDNQ: sdnq-svd 4-bit uint with svd rank 32",
"skip": true,
"tags": "quantized",
"size": 12.60,
"date": "2025 October",
"extras": ""
},
"FLUX.1-Dev Krea sdnq-svd-uint4": {
"path": "Disty0/FLUX.1-Krea-dev-SDNQ-uint4-svd-r32",
"preview": "Disty0--FLUX.1-Krea-dev-SDNQ-uint4-svd-r32.jpg",
"desc": "Quantization of black-forest-labs/FLUX.1-Krea-dev using SDNQ: sdnq-svd 4-bit uint with svd rank 32",
"skip": true,
"tags": "quantized",
"size": 12.60,
"date": "2025 October",
"extras": ""
},
"FLUX.1-Dev Kontext sdnq-svd-uint4": {
"path": "Disty0/FLUX.1-Kontext-dev-SDNQ-uint4-svd-r32",
"preview": "Disty0--FLUX.1-Kontext-dev-SDNQ-uint4-svd-r32.jpg",
"desc": "Quantization of black-forest-labs/FLUX.1-Kontext-dev using SDNQ: sdnq-svd 4-bit uint with svd rank 32",
"skip": true,
"tags": "quantized",
"size": 12.60,
"date": "2025 October",
"extras": ""
},
"FLUX.2 Dev sdnq-svd-uint4": {
"path": "Disty0/FLUX.2-dev-SDNQ-uint4-svd-r32",
"preview": "Disty0--FLUX.2-dev-SDNQ-uint4-svd-r32.jpg",
"desc": "Quantization of black-forest-labs/FLUX.2-dev using SDNQ: sdnq-svd 4-bit uint with svd rank 32",
"skip": true,
"tags": "quantized",
"extras": "",
"size": 31.58,
"date": "2025 November"
},
"Black Forest Labs FLUX.2 Klein 4B sdnq-uint4-dynamic": {
"path": "Disty0/FLUX.2-klein-4B-SDNQ-4bit-dynamic",
"preview": "Disty0--FLUX.2-klein-4B-SDNQ-4bit-dynamic.jpg",
"desc": "Dynamic 4-bit quantization of black-forest-labs/FLUX.2-klein-4B using SDNQ.",
"skip": true,
"extras": "sampler: Default, cfg_scale: 1.0, steps: 4",
"tags": "quantized",
"size": 5.1,
"date": "2026 January"
},
"Black Forest Labs FLUX.2 Klein 9B sdnq-uint4-dynamic-svd": {
"path": "Disty0/FLUX.2-klein-9B-SDNQ-4bit-dynamic-svd-r32",
"preview": "Disty0--FLUX.2-klein-9B-SDNQ-4bit-dynamic-svd-r32.jpg",
"desc": "Dynamic 4-bit quantization of black-forest-labs/FLUX.2-klein-9B using SDNQ with SVD rank 32.",
"skip": true,
"extras": "sampler: Default, cfg_scale: 1.0, steps: 4",
"tags": "quantized",
"size": 11.7,
"date": "2026 January"
},
"Chroma1-HD sdnq-svd-uint4": {
"path": "Disty0/Chroma1-HD-SDNQ-uint4-svd-r32",
"preview": "Disty0--Chroma1-HD-SDNQ-uint4-svd-r32.jpg",
"desc": "Quantization of lodestones/Chroma1-HD using SDNQ: sdnq-svd 4-bit uint with svd rank 32",
"skip": true,
"tags": "quantized",
"size": 11.89,
"date": "2025 October",
"extras": ""
},
"Wan-AI Wan2.2 A14B T2I sdnq-svd-uint4": {
"path": "Disty0/Wan2.2-T2V-A14B-SDNQ-uint4-svd-r32",
"preview": "Wan-AI--Wan2.2-T2V-A14B-Diffusers.jpg",
"desc": "Quantization of black-forest-labs/FLUX.1-dev using SDNQ: sdnq-svd 4-bit uint with svd rank 32",
"skip": true,
"tags": "quantized",
"date": "2025 October",
"size": 23.54,
"extras": ""
},
"Wan-AI Wan2.2 A14B I2I sdnq-svd-uint4": {
"path": "Disty0/Wan2.2-I2V-A14B-SDNQ-uint4-svd-r32",
"preview": "Wan-AI--Wan2.2-T2V-A14B-Diffusers.jpg",
"desc": "Quantization of Laxhar/noobai-XL-1.1 using SDNQ: sdnq-svd 4-bit uint with svd rank 128",
"skip": true,
"tags": "quantized",
"date": "2025 October",
"size": 23.55,
"extras": ""
},
"Z-Image-Turbo sdnq-svd-uint4": {
"path": "Disty0/Z-Image-Turbo-SDNQ-uint4-svd-r32",
"preview": "Disty0--Z-Image-Turbo-SDNQ-uint4-svd-r32.jpg",
"desc": "Quantization of Tongyi-MAI/Z-Image-Turbo using SDNQ: sdnq-svd 4-bit uint with svd rank 32",
"skip": true,
"tags": "quantized",
"extras": "sampler: Default, cfg_scale: 1.0, steps: 9",
"size": 6.5,
"date": "2025 November"
},
"Qwen-Image sdnq-svd-uint4": {
"path": "Disty0/Qwen-Image-SDNQ-uint4-svd-r32",
"preview": "Qwen--Qwen-Image.jpg",
"desc": "Quantization of Qwen/Qwen-Image using SDNQ: sdnq-svd 4-bit uint with svd rank 32",
"skip": true,
"tags": "quantized",
"date": "2025 October",
"size": 16.09,
"extras": ""
},
"Qwen-Image-2512 sdnq-svd-uint4": {
"path": "Disty0/Qwen-Image-2512-SDNQ-uint4-svd-r32",
"preview": "Disty0--Qwen-Image-2512-SDNQ-uint4-svd-r32.jpg",
"desc": "Quantization of Qwen/Qwen-Image-2512 using SDNQ: sdnq-svd 4-bit uint with svd rank 32",
"skip": true,
"tags": "quantized",
"extras": "",
"size": 16.10,
"date": "2025 December"
},
"Qwen-Image-2512 sdnq-dynamic-uint4": {
"path": "Disty0/Qwen-Image-2512-SDNQ-4bit-dynamic",
"preview": "Disty0--Qwen-Image-2512-SDNQ-uint4-svd-r32.jpg",
"desc": "Quantization of Qwen/Qwen-Image-2512 using SDNQ: sdnq-dynamic 4-bit uint",
"skip": true,
"tags": "quantized",
"extras": "",
"size": 17.2,
"date": "2026 January"
},
"Qwen-Image-Edit sdnq-svd-uint4": {
"path": "Disty0/Qwen-Image-Edit-SDNQ-uint4-svd-r32",
"preview": "Qwen--Qwen-Image-Edit.jpg",
"desc": "Quantization of Qwen/Qwen-Image-Edit using SDNQ: sdnq-svd 4-bit uint with svd rank 32",
"skip": true,
"tags": "quantized",
"date": "2025 October",
"size": 16.10,
"extras": ""
},
"Qwen-Image-Edit-2509 sdnq-svd-uint4": {
"path": "Disty0/Qwen-Image-Edit-2509-SDNQ-uint4-svd-r32",
"preview": "Qwen--Qwen-Image-Edit-2509.jpg",
"desc": "Quantization of Qwen/Qwen-Image-Edit-2509 using SDNQ: sdnq-svd 4-bit uint with svd rank 32",
"skip": true,
"tags": "quantized",
"date": "2025 October",
"size": 16.10,
"extras": ""
},
"Qwen-Image-Edit-2511 sdnq-svd-uint4": {
"path": "Disty0/Qwen-Image-Edit-2511-SDNQ-uint4-svd-r32",
"preview": "Disty0--Qwen-Image-Edit-2511-SDNQ-uint4-svd-r32.jpg",
"desc": "Quantization of Qwen/Qwen-Image-Edit-2511 using SDNQ: sdnq-svd 4-bit uint with svd rank 32",
"skip": true,
"tags": "quantized",
"date": "2025 December",
"size": 16.10,
"extras": ""
},
"Qwen-Image-Layered sdnq-svd-uint4": {
"path": "Disty0/Qwen-Image-Layered-SDNQ-uint4-svd-r32",
"preview": "Disty0--Qwen-Image-Layered-SDNQ-uint4-svd-r32.jpg",
"desc": "Quantization of Qwen/Qwen-Image-Layered using SDNQ: sdnq-svd 4-bit uint with svd rank 32",
"skip": true,
"tags": "quantized",
"date": "2025 December",
"size": 16.10,
"extras": ""
},
"nVidia ChronoEdit sdnq-svd-uint4": {
"path": "Disty0/ChronoEdit-14B-SDNQ-uint4-svd-r32",
"preview": "Disty0--ChronoEdit-14B-SDNQ-uint4-svd-r32.jpg",
"desc": "Quantization of nvidia/ChronoEdit-14B-Diffusers using SDNQ: sdnq-svd 4-bit uint with svd rank 32.",
"skip": true,
"tags": "quantized",
"date": "2025 October",
"size": 18.10,
"extras": ""
},
"Tencent HunyuanImage 3.0 sdnq-svd-uint4": {
"path": "Disty0/HunyuanImage3-SDNQ-uint4-svd-r32",
"desc": "Quantization of tencent/HunyuanImage-3.0 using SDNQ: sdnq-svd 4-bit uint with svd rank 32.",
"preview": "Disty0--HunyuanImage3-SDNQ-uint4-svd-r32.jpg",
"extras": "",
"skip": true,
"tags": "quantized",
"size": 57.06,
"date": "2025 September"
},
"Tempest-by-Vlad XL sdnq-svd-uint4": {
"path": "vladmandic/tempestByVlad_baseV01-SDNQ-uint4-svd",
"preview": "vladmandic--tempestByVlad_baseV01-SDNQ-uint4-svd.jpg",
"desc": "Quantization of vladmandic/tempestByVlad_baseV01 using SDNQ: sdnq-svd 4-bit uint with svd rank 128",
"tags": "quantized",
"size": 3.37,
"date": "2025 October",
"extras": ""
},
"NoobAI-XL v1.1 epsilon sdnq-svd-uint4": {
"path": "Disty0/NoobAI-XL-v1.1-SDNQ-uint4-svd-r128",
"preview": "Disty0--NoobAI-XL-v1.1-SDNQ-uint4-svd-r128.jpg",
"desc": "Quantization of Laxhar/noobai-XL-1.1 using SDNQ: sdnq-svd 4-bit uint with svd rank 128",
"tags": "quantized",
"size": 3.37,
"date": "2025 October",
"extras": ""
},
"NoobAI-XL v1.0 v-pred sdnq-svd-uint4": {
"path": "Disty0/NoobAI-XL-Vpred-v1.0-SDNQ-uint4-svd-r128",
"preview": "Disty0--NoobAI-XL-Vpred-v1.0-SDNQ-uint4-svd-r128.jpg",
"desc": "Quantization of Laxhar/noobai-XL-Vpred-1.0 using SDNQ: sdnq-svd 4-bit uint with svd rank 128",
"tags": "quantized",
"size": 3.37,
"date": "2025 October",
"extras": ""
},
"ZAI GLM-Image sdnq-dynamic-uint4": {
"path": "Disty0/GLM-Image-SDNQ-4bit-dynamic",
"preview": "zai-org--GLM-Image.jpg",
"desc": "Quantization of ZAI GLM-Image using SDNQ: sdnq-dynamic 4-bit uint",
"skip": true,
"extras": "sampler: Default, cfg_scale: 1.5, steps: 50",
"size": 11.6,
"tags": "quantized",
"date": "2026 January"
}
}
+38 -517
View File
@@ -38,15 +38,6 @@
"size": 6.94,
"date": "2023 July"
},
"StabilityAI StableDiffusion XL Turbo": {
"path": "stabilityai/sdxl-turbo",
"preview": "stabilityai--sdxl-turbo.jpg",
"desc": "SDXL-Turbo is a fast generative text-to-image model that can synthesize photorealistic images from a text prompt in a 1-4 steps.",
"skip": true,
"variant": "fp16",
"tags": "distilled",
"extras": "steps: 4, cfg_scale: 0.0"
},
"StabilityAI Stable Cascade": {
"path": "huggingface/stabilityai/stable-cascade",
"skip": true,
@@ -57,17 +48,6 @@
"size": 11.82,
"date": "2024 February"
},
"StabilityAI Stable Cascade Lite": {
"path": "huggingface/stabilityai/stable-cascade-lite",
"skip": true,
"variant": "bf16",
"desc": "Stable Cascade is a diffusion model built upon the Würstchen architecture and its main difference to other models like Stable Diffusion is that it is working at a much smaller latent space. Why is this important? The smaller the latent space, the faster you can run inference and the cheaper the training becomes. How small is the latent space? Stable Diffusion uses a compression factor of 8, resulting in a 1024x1024 image being encoded to 128x128. Stable Cascade achieves a compression factor of 42, meaning that it is possible to encode a 1024x1024 image to 24x24, while maintaining crisp reconstructions. The text-conditional model is then trained in the highly compressed latent space. Previous versions of this architecture, achieved a 16x cost reduction over Stable Diffusion 1.5",
"preview": "stabilityai--stable-cascade-lite.jpg",
"extras": "sampler: Default, cfg_scale: 4.0, image_cfg_scale: 1.0",
"size": 4.97,
"tags": "distilled",
"date": "2024 February"
},
"StabilityAI Stable Diffusion 3.0 Medium": {
"path": "stabilityai/stable-diffusion-3-medium-diffusers",
"skip": true,
@@ -98,15 +78,6 @@
"size": 26.98,
"date": "2024 October"
},
"StabilityAI Stable Diffusion 3.5 Turbo": {
"path": "stabilityai/stable-diffusion-3.5-large-turbo",
"skip": true,
"variant": "fp16",
"desc": "Stable Diffusion 3.5 Large Turbo is a Multimodal Diffusion Transformer (MMDiT) text-to-image model with Adversarial Diffusion Distillation (ADD) that features improved performance in image quality, typography, complex prompt understanding, and resource-efficiency, with a focus on fewer inference steps.",
"preview": "stabilityai--stable-diffusion-3_5-large-turbo.jpg",
"tags": "distilled",
"extras": "sampler: Default, cfg_scale: 7.0"
},
"Black Forest Labs FLUX.1 Dev": {
"path": "black-forest-labs/FLUX.1-dev",
@@ -153,20 +124,29 @@
"size": 104.74,
"date": "2025 November"
},
"Tencent FLUX.1 Dev SRPO": {
"path": "vladmandic/flux.1-dev-SRPO",
"preview": "vladmandic--flux.1-dev-SRPO.jpg",
"desc": "FLUX.1 Dev SRPO is Tencent trained with specific technique: Directly Aligning the Full Diffusion Trajectory with Fine-Grained Human Preference",
"tags": "distilled",
"Black Forest Labs FLUX.2 Klein Base 4B": {
"path": "black-forest-labs/FLUX.2-klein-base-4B",
"preview": "black-forest-labs--FLUX.2-klein-base-4B.jpg",
"desc": "FLUX.2-klein-base-4B is the undistilled 4 billion parameter base model of FLUX.2-klein. Requires 50 inference steps for full quality but offers flexibility for fine-tuning. Supports text-to-image and multi-reference editing. Apache 2.0 licensed.",
"skip": true,
"extras": "sampler: Default, cfg_scale: 4.5"
"extras": "sampler: Default, cfg_scale: 4.0, steps: 50",
"size": 8.5,
"date": "2025 January"
},
"Black Forest Labs FLUX.2 Klein Base 9B": {
"path": "black-forest-labs/FLUX.2-klein-base-9B",
"preview": "black-forest-labs--FLUX.2-klein-base-9B.jpg",
"desc": "FLUX.2-klein-base-9B is the undistilled 9 billion parameter base model of FLUX.2-klein. Requires 50 inference steps for full quality but offers flexibility for fine-tuning. Supports text-to-image and multi-reference editing. Non-commercial license.",
"skip": true,
"extras": "sampler: Default, cfg_scale: 4.0, steps: 50",
"size": 18.5,
"date": "2025 January"
},
"Z-Image-Turbo": {
"path": "Tongyi-MAI/Z-Image-Turbo",
"preview": "Tongyi-MAI--Z-Image-Turbo.jpg",
"desc": "Z-Image-Turbo, a distilled version of Z-Image that matches or exceeds leading competitors with only 8 NFEs (Number of Function Evaluations). It offers sub-second inference latency on enterprise-grade H800 GPUs and fits comfortably within 16G VRAM consumer devices. It excels in photorealistic image generation, bilingual text rendering (English & Chinese), and robust instruction adherence.",
"tags": "distilled",
"desc": "Z-Image-Turbo, a distilled version of Z-Image that matches or exceeds leading competitors with only 8 NFEs (Number of Function Evaluations). It excels in photorealistic image generation, bilingual text rendering (English & Chinese), and robust instruction adherence.",
"skip": true,
"extras": "sampler: Default, cfg_scale: 1.0, steps: 9",
"size": 20.3,
@@ -182,6 +162,15 @@
"size": 56.1,
"date": "2025 August"
},
"Qwen-Image-2512": {
"path": "Qwen/Qwen-Image-2512",
"preview": "Qwen--Qwen-Image-2512.jpg",
"desc": "Qwen-Image-2512 is an Qwen Image successor, that significantly reduces the AI-generated look, got finer natural detailils and improved text rendering.",
"skip": true,
"extras": "",
"size": 53.7,
"date": "2025 December"
},
"Qwen-Image-Edit": {
"path": "Qwen/Qwen-Image-Edit",
"preview": "Qwen--Qwen-Image-Edit.jpg",
@@ -202,7 +191,7 @@
},
"Qwen-Image-Edit-2511": {
"path": "Qwen/Qwen-Image-Edit-2511",
"preview": "Qwen--Qwen-Image-Edit-2509.jpg",
"preview": "Qwen--Qwen-Image-Edit-2511.jpg",
"desc": "Key enhancements: mitigate image drift, improved character consistency, enhanced industrial design generation, and strengthened geometric reasoning ability.",
"skip": true,
"extras": "",
@@ -211,74 +200,17 @@
},
"Qwen-Image-Layered": {
"path": "Qwen/Qwen-Image-Layered",
"preview": "Qwen--Qwen-Image-Edit-2509.jpg",
"preview": "Qwen--Qwen-Image-Layered.jpg",
"desc": "Qwen-Image-Layered, a model capable of decomposing an image into multiple RGBA layers",
"skip": true,
"extras": "",
"size": 53.7,
"date": "2025 December"
},
"Qwen-Image-Lightning": {
"path": "vladmandic/Qwen-Lightning",
"preview": "vladmandic--Qwen-Lightning.jpg",
"desc": "Qwen-Lightning is step-distilled from Qwen-Image to allow for generation in 8 steps.",
"skip": true,
"extras": "steps: 8",
"size": 56.1,
"tags": "distilled",
"date": "2025 August"
},
"Qwen-Image-Distill": {
"path": "SahilCarterr/Qwen-Image-Distill-Full",
"preview": "SahilCarterr--Qwen-Image-Distill-Full.jpg",
"desc": "Qwen-Image-Distill is a distilled and accelerated version of Qwen-Image by DiffSynth-Studio.",
"skip": true,
"extras": "steps: 15",
"size": 56.1,
"tags": "distilled",
"date": "2025 August"
},
"Qwen-Image-Lightning-Edit": {
"path": "vladmandic/Qwen-Lightning-Edit",
"preview": "vladmandic--Qwen-Lightning-Edit.jpg",
"desc": "Qwen-Lightning-Edit is step-distilled from Qwen-Image-Edit to allow for generation in 8 steps.",
"skip": true,
"extras": "steps: 8",
"size": 56.1,
"tags": "distilled",
"date": "2025 August"
},
"Qwen-Image Pruning-12B": {
"path": "OPPOer/Qwen-Image-Pruning",
"subfolder": "Qwen-Image-12B-8steps",
"preview": "OPPOer--Qwen-Image-Pruning.jpg",
"desc": "This open-source project is based on Qwen-Image and has attempted model pruning, removing 20 layers while retaining the weights of 40 layers, resulting in a model size of 12B parameters.",
"skip": true,
"tags": "distilled",
"date": "2025 Ocotober"
},
"Qwen-Image-Edit Pruning-13B": {
"path": "OPPOer/Qwen-Image-Edit-Pruning",
"subfolder": "Qwen-Image-Edit-13B-4steps",
"preview": "OPPOer--Qwen-Image-Edit-Pruning.jpg",
"desc": "This open-source project is based on Qwen-Image-Edit and has attempted model pruning, removing 20 layers while retaining the weights of 40 layers, resulting in a model size of 13.6B parameters.",
"skip": true,
"tags": "distilled",
"date": "2025 Ocotober"
},
"Qwen-Image-Edit-2509 Pruning-13B": {
"path": "OPPOer/Qwen-Image-Edit-2509-Pruning",
"subfolder": "Qwen-Image-Edit-2509-13B-4steps",
"preview": "OPPOer--Qwen-Image-Edit-2509-Pruning.jpg",
"desc": "This open-source project is based on Qwen-Image-Edit and has attempted model pruning, removing 20 layers while retaining the weights of 40 layers, resulting in a model size of 13.6B parameters.",
"skip": true,
"tags": "distilled",
"date": "2025 Ocotober"
},
"lodestones Chroma1 HD": {
"path": "lodestones/Chroma1-HD",
"preview": "lodestones--Chroma-HD.jpg",
"preview": "lodestones--Chroma1-HD.jpg",
"desc": "Chroma is a 8.9B parameter model based on FLUX.1-schnell. Its fully Apache 2.0 licensed, ensuring that anyone can use, modify, and build on top of it—no corporate gatekeeping. This is the high-res fine-tune of the Chroma1-Base at a 1024x1024 resolution.",
"skip": true,
"extras": "",
@@ -287,50 +219,22 @@
},
"lodestones Chroma1 Base": {
"path": "lodestones/Chroma1-Base",
"preview": "lodestones--Chroma-Base.jpg",
"preview": "lodestones--Chroma1-Base.jpg",
"desc": "Chroma is a 8.9B parameter model based on FLUX.1-schnell. Its fully Apache 2.0 licensed, ensuring that anyone can use, modify, and build on top of it—no corporate gatekeeping. This is the core 512x512 model. It's a solid, all-around foundation for pretty much any creative project.",
"skip": true,
"extras": "",
"size": 26.84,
"date": "2025 July"
},
"lodestones Chroma1 Flash": {
"path": "lodestones/Chroma1-Flash",
"preview": "lodestones--Chroma-flash.jpg",
"desc": "Chroma is a 8.9B parameter model based on FLUX.1-schnell. Its fully Apache 2.0 licensed, ensuring that anyone can use, modify, and build on top of it—no corporate gatekeeping. A fine-tuned version of the Chroma1-Base made to find the best way to make these flow matching models faster.",
"skip": true,
"extras": "",
"size": 26.84,
"tags": "distilled",
"date": "2025 July"
},
"lodestones Chroma1 v50 Preview Annealed": {
"path": "vladmandic/chroma-unlocked-v50-annealed",
"preview": "lodestones--Chroma-annealed.jpg",
"preview": "vladmandic--chroma-unlocked-v50-annealed.jpg",
"desc": "Chroma is a 8.9B parameter model based on FLUX.1-schnell. Its fully Apache 2.0 licensed, ensuring that anyone can use, modify, and build on top of it—no corporate gatekeeping. Re-tweaked variant with extra noise added.",
"skip": true,
"extras": "",
"size": 26.84,
"date": "2025 July"
},
"lodestones Chroma1 v48 Preview": {
"path": "vladmandic/chroma-unlocked-v48",
"preview": "lodestones--Chroma.jpg",
"desc": "Chroma is a 8.9B parameter model based on FLUX.1-schnell. Its fully Apache 2.0 licensed, ensuring that anyone can use, modify, and build on top of it—no corporate gatekeeping. Last raw version of Chroma before final finetuning.",
"skip": true,
"extras": "",
"size": 26.84,
"date": "2025 July"
},
"lodestones Chroma1 v48 Preview Calibrated": {
"path": "vladmandic/chroma-unlocked-v48-detail-calibrated",
"preview": "lodestones--Chroma-detail.jpg",
"desc": "Chroma is a 8.9B parameter model based on FLUX.1-schnell. Its fully Apache 2.0 licensed, ensuring that anyone can use, modify, and build on top of it—no corporate gatekeeping. Last raw version of Chroma before final finetuning but with some detail calibration.",
"skip": true,
"extras": "",
"size": 26.84,
"date": "2025 July"
},
"Meituan LongCat Image": {
"path": "meituan-longcat/LongCat-Image",
@@ -451,14 +355,6 @@
"desc": "SDXS: Real-Time One-Step Latent Diffusion Models with Image Conditions",
"extras": "width: 512, height: 512, sampler: CMSI, steps: 1, cfg_scale: 0.0"
},
"SDXL Flash Mini": {
"path": "SDXL-Flash_Mini.safetensors@https://huggingface.co/sd-community/sdxl-flash-mini/resolve/main/SDXL-Flash_Mini.safetensors?download=true",
"preview": "SDXL-Flash_Mini.jpg",
"desc": "Introducing the new fast model SDXL Flash (Mini), we learned that all fast XL models work fast, but the quality decreases, and we also made a fast model, but it is not as fast as LCM, Turbo, Lightning and Hyper, but the quality is higher.",
"extras": "width: 2048, height: 1024, sampler: DEIS, steps: 40, cfg_scale: 6.0",
"tags": "distilled",
"experimental": true
},
"NVLabs Sana 1.5 1.6B 1k": {
"path": "Efficient-Large-Model/SANA1.5_1.6B_1024px_diffusers",
@@ -476,13 +372,6 @@
"size": 15.58,
"date": "2025 March"
},
"NVLabs Sana 1.5 1.6B 1k Sprint": {
"path": "Efficient-Large-Model/Sana_Sprint_1.6B_1024px_diffusers",
"desc": "SANA-Sprint is an ultra-efficient diffusion model for text-to-image (T2I) generation, reducing inference steps from 20 to 1-4 while achieving state-of-the-art performance.",
"preview": "Efficient-Large-Model--Sana15_Sprint_1600M_1024px_diffusers.jpg",
"tags": "distilled",
"skip": true
},
"NVLabs Sana 1.0 1.6B 4k": {
"path": "Efficient-Large-Model/Sana_1600M_4Kpx_BF16_diffusers",
"desc": "Sana is a text-to-image framework that can efficiently generate images up to 4096 × 4096 resolution. Sana can synthesize high-resolution, high-quality images with strong text-image alignment at a remarkably fast speed, deployable on laptop GPU.",
@@ -593,26 +482,6 @@
"size": 6.43,
"date": "2023 November"
},
"Segmind SSD-1B": {
"path": "huggingface/segmind/SSD-1B",
"preview": "segmind--SSD-1B.jpg",
"desc": "The Segmind Stable Diffusion Model (SSD-1B) offers a compact, efficient, and distilled version of the SDXL model. At 50% smaller and 60% faster than Stable Diffusion XL (SDXL), it provides quick and seamless performance without sacrificing image quality.",
"variant": "fp16",
"skip": true,
"extras": "sampler: Default, cfg_scale: 9.0",
"size": 8.72,
"tags": "distilled",
"date": "2023 October"
},
"Segmind Tiny": {
"path": "segmind/tiny-sd",
"preview": "segmind--tiny-sd.jpg",
"desc": "Segmind's Tiny-SD offers a compact, efficient, and distilled version of Realistic Vision 4.0 and is up to 80% faster than SD1.5",
"extras": "width: 512, height: 512, sampler: Default, cfg_scale: 9.0",
"size": 1.03,
"tags": "distilled",
"date": "2023 July"
},
"Segmind SegMoE SD 4x2": {
"path": "segmind/SegMoE-SD-4x2-v0",
"preview": "segmind--SegMoE-SD-4x2-v0.jpg",
@@ -672,16 +541,6 @@
"size": 0,
"date": "2025 August"
},
"Tencent HunyuanImage 2.1 Distilled": {
"path": "hunyuanvideo-community/HunyuanImage-2.1-Distilled-Diffusers",
"desc": "HunyuanImage-2.1, a highly efficient text-to-image model that is capable of generating 2K (2048 × 2048) resolution images.",
"preview": "hunyuanvideo-community--HunyuanImage-2.1-Distilled-Diffusers.jpg",
"extras": "",
"tags": "distilled",
"skip": true,
"size": 0,
"date": "2025 August"
},
"Tencent HunyuanImage 2.1 Refiner": {
"path": "hunyuanvideo-community/HunyuanImage-2.1-Refiner-Diffusers",
"desc": "HunyuanImage-2.1, a highly efficient text-to-image model that is capable of generating 2K (2048 × 2048) resolution images.",
@@ -699,26 +558,12 @@
"size": 14.09,
"date": "2024 May"
},
"Tencent HunyuanDiT 1.2 Distilled": {
"path": "Tencent-Hunyuan/HunyuanDiT-v1.2-Diffusers-Distilled",
"desc": "Hunyuan-DiT : A Powerful Multi-Resolution Diffusion Transformer with Fine-Grained Chinese Understanding.",
"preview": "Tencent-Hunyuan--HunyuanDiT-v1.2-Diffusers-Distilled.jpg",
"tags": "distilled",
"extras": "sampler: Default, cfg_scale: 2.0"
},
"Tencent HunyuanDiT 1.1": {
"path": "Tencent-Hunyuan/HunyuanDiT-v1.1-Diffusers",
"desc": "Hunyuan-DiT : A Powerful Multi-Resolution Diffusion Transformer with Fine-Grained Chinese Understanding.",
"preview": "Tencent-Hunyuan--HunyuanDiT-v1.1-Diffusers.jpg",
"extras": "sampler: Default, cfg_scale: 2.0"
},
"Tencent HunyuanDiT 1.1 Distilled": {
"path": "Tencent-Hunyuan/HunyuanDiT-v1.1-Diffusers-Distilled",
"desc": "Hunyuan-DiT : A Powerful Multi-Resolution Diffusion Transformer with Fine-Grained Chinese Understanding.",
"preview": "Tencent-Hunyuan--HunyuanDiT-v1.1-Diffusers-Distilled.jpg",
"tags": "distilled",
"extras": "sampler: Default, cfg_scale: 2.0"
},
"AlphaVLLM Lumina Next SFT": {
"path": "Alpha-VLLM/Lumina-Next-SFT-diffusers",
@@ -1002,338 +847,14 @@
"skip": true
},
"FLUX.1-Dev sdnq-svd-uint4": {
"path": "Disty0/FLUX.1-dev-SDNQ-uint4-svd-r32",
"preview": "Disty0--FLUX.1-dev-SDNQ-uint4-svd-r32.jpg",
"desc": "Quantization of black-forest-labs/FLUX.1-dev using SDNQ: sdnq-svd 4-bit uint with svd rank 32",
"ZAI GLM-Image": {
"path": "zai-org/GLM-Image",
"preview": "zai-org--GLM-Image.jpg",
"desc": "GLM-Image is a two-stage image generation model combining autoregressive token generation (9B vision-language encoder) with diffusion refinement (7B DiT transformer). Features strong text rendering and compositional capabilities.",
"skip": true,
"tags": "quantized",
"size": 12.60,
"date": "2025 October",
"extras": ""
},
"FLUX.1-Schnell sdnq-svd-uint4": {
"path": "Disty0/FLUX.1-schnell-SDNQ-uint4-svd-r32",
"preview": "Disty0--FLUX.1-schnell-SDNQ-uint4-svd-r32.jpg",
"desc": "Quantization of black-forest-labs/FLUX.1-schnell using SDNQ: sdnq-svd 4-bit uint with svd rank 32",
"skip": true,
"tags": "quantized",
"size": 12.60,
"date": "2025 October",
"extras": ""
},
"FLUX.1-Dev Krea sdnq-svd-uint4": {
"path": "Disty0/FLUX.1-Krea-dev-SDNQ-uint4-svd-r32",
"preview": "Disty0--FLUX.1-Krea-dev-SDNQ-uint4-svd-r32.jpg",
"desc": "Quantization of black-forest-labs/FLUX.1-Krea-dev using SDNQ: sdnq-svd 4-bit uint with svd rank 32",
"skip": true,
"tags": "quantized",
"size": 12.60,
"date": "2025 October",
"extras": ""
},
"FLUX.1-Dev Kontext sdnq-svd-uint4": {
"path": "Disty0/FLUX.1-Kontext-dev-SDNQ-uint4-svd-r32",
"preview": "Disty0--FLUX.1-Kontext-dev-SDNQ-uint4-svd-r32.jpg",
"desc": "Quantization of black-forest-labs/FLUX.1-Kontext-dev using SDNQ: sdnq-svd 4-bit uint with svd rank 32",
"skip": true,
"tags": "quantized",
"size": 12.60,
"date": "2025 October",
"extras": ""
},
"FLUX.2 Dev sdnq-svd-uint4": {
"path": "Disty0/FLUX.2-dev-SDNQ-uint4-svd-r32",
"preview": "Disty0--FLUX.2-dev-SDNQ-uint4-svd-r32.jpg",
"desc": "Quantization of black-forest-labs/FLUX.2-dev using SDNQ: sdnq-svd 4-bit uint with svd rank 32",
"skip": true,
"tags": "quantized",
"extras": "",
"size": 31.58,
"date": "2025 November"
},
"Chroma1-HD sdnq-svd-uint4": {
"path": "Disty0/Chroma1-HD-SDNQ-uint4-svd-r32",
"preview": "Disty0--Chroma1-HD-SDNQ-uint4-svd-r32.jpg",
"desc": "Quantization of lodestones/Chroma1-HD using SDNQ: sdnq-svd 4-bit uint with svd rank 32",
"skip": true,
"tags": "quantized",
"size": 11.89,
"date": "2025 October",
"extras": ""
},
"Wan-AI Wan2.2 A14B T2I sdnq-svd-uint4": {
"path": "Disty0/Wan2.2-T2V-A14B-SDNQ-uint4-svd-r32",
"preview": "Wan-AI--Wan2.2-T2V-A14B-Diffusers.jpg",
"desc": "Quantization of black-forest-labs/FLUX.1-dev using SDNQ: sdnq-svd 4-bit uint with svd rank 32",
"skip": true,
"tags": "quantized",
"date": "2025 October",
"size": 23.54,
"extras": ""
},
"Wan-AI Wan2.2 A14B I2I sdnq-svd-uint4": {
"path": "Disty0/Wan2.2-I2V-A14B-SDNQ-uint4-svd-r32",
"preview": "Wan-AI--Wan2.2-T2V-A14B-Diffusers.jpg",
"desc": "Quantization of Laxhar/noobai-XL-1.1 using SDNQ: sdnq-svd 4-bit uint with svd rank 128",
"skip": true,
"tags": "quantized",
"date": "2025 October",
"size": 23.55,
"extras": ""
},
"Z-Image-Turbo sdnq-svd-uint4": {
"path": "Disty0/Z-Image-Turbo-SDNQ-uint4-svd-r32",
"preview": "Disty0--Z-Image-Turbo-SDNQ-uint4-svd-r32.jpg",
"desc": "Quantization of Tongyi-MAI/Z-Image-Turbo using SDNQ: sdnq-svd 4-bit uint with svd rank 32",
"skip": true,
"tags": "quantized",
"extras": "sampler: Default, cfg_scale: 1.0, steps: 9",
"size": 6.5,
"date": "2025 November"
},
"Qwen-Image sdnq-svd-uint4": {
"path": "Disty0/Qwen-Image-SDNQ-uint4-svd-r32",
"preview": "Qwen--Qwen-Image.jpg",
"desc": "Quantization of Qwen/Qwen-Image using SDNQ: sdnq-svd 4-bit uint with svd rank 32",
"skip": true,
"tags": "quantized",
"date": "2025 October",
"size": 16.09,
"extras": ""
},
"Qwen-Image-Edit sdnq-svd-uint4": {
"path": "Disty0/Qwen-Image-Edit-SDNQ-uint4-svd-r32",
"preview": "Qwen--Qwen-Image-Edit.jpg",
"desc": "Quantization of Qwen/Qwen-Image-Edit using SDNQ: sdnq-svd 4-bit uint with svd rank 32",
"skip": true,
"tags": "quantized",
"date": "2025 October",
"size": 16.10,
"extras": ""
},
"Qwen-Image-Edit-2509 sdnq-svd-uint4": {
"path": "Disty0/Qwen-Image-Edit-2509-SDNQ-uint4-svd-r32",
"preview": "Qwen--Qwen-Image-Edit-2509.jpg",
"desc": "Quantization of Qwen/Qwen-Image-Edit-2509 using SDNQ: sdnq-svd 4-bit uint with svd rank 32",
"skip": true,
"tags": "quantized",
"date": "2025 October",
"size": 16.10,
"extras": ""
},
"Qwen-Image-Edit-2511 sdnq-svd-uint4": {
"path": "Disty0/Qwen-Image-Edit-2511-SDNQ-uint4-svd-r32",
"preview": "Qwen--Qwen-Image-Edit-2509.jpg",
"desc": "Quantization of Qwen/Qwen-Image-Edit-2511 using SDNQ: sdnq-svd 4-bit uint with svd rank 32",
"skip": true,
"tags": "quantized",
"date": "2025 December",
"size": 16.10,
"extras": ""
},
"Qwen-Image-Layered sdnq-svd-uint4": {
"path": "Disty0/Qwen-Image-Layered-SDNQ-uint4-svd-r32",
"preview": "Qwen--Qwen-Image-Edit-2509.jpg",
"desc": "Quantization of Qwen/Qwen-Image-Layered using SDNQ: sdnq-svd 4-bit uint with svd rank 32",
"skip": true,
"tags": "quantized",
"date": "2025 December",
"size": 16.10,
"extras": ""
},
"nVidia ChronoEdit sdnq-svd-uint4": {
"path": "Disty0/ChronoEdit-14B-SDNQ-uint4-svd-r32",
"preview": "Disty0--ChronoEdit-14B-SDNQ-uint4-svd-r32.jpg",
"desc": "Quantization of nvidia/ChronoEdit-14B-Diffusers using SDNQ: sdnq-svd 4-bit uint with svd rank 32.",
"skip": true,
"tags": "quantized",
"date": "2025 October",
"size": 18.10,
"extras": ""
},
"Tencent HunyuanImage 3.0 sdnq-svd-uint4": {
"path": "Disty0/HunyuanImage3-SDNQ-uint4-svd-r32",
"desc": "Quantization of tencent/HunyuanImage-3.0 using SDNQ: sdnq-svd 4-bit uint with svd rank 32.",
"preview": "Disty0--HunyuanImage3-SDNQ-uint4-svd-r32.jpg",
"extras": "",
"skip": true,
"tags": "quantized",
"size": 57.06,
"date": "2025 September"
},
"Tempest-by-Vlad XL sdnq-svd-uint4": {
"path": "vladmandic/tempestByVlad_baseV01-SDNQ-uint4-svd",
"preview": "vladmandic--tempestByVlad_baseV01-SDNQ-uint4-svd.jpg",
"desc": "Quantization of vladmandic/tempestByVlad_baseV01 using SDNQ: sdnq-svd 4-bit uint with svd rank 128",
"tags": "quantized",
"size": 3.37,
"date": "2025 October",
"extras": ""
},
"NoobAI-XL v1.1 epsilon sdnq-svd-uint4": {
"path": "Disty0/NoobAI-XL-v1.1-SDNQ-uint4-svd-r128",
"preview": "Disty0--NoobAI-XL-v1.1-SDNQ-uint4-svd-r128.jpg",
"desc": "Quantization of Laxhar/noobai-XL-1.1 using SDNQ: sdnq-svd 4-bit uint with svd rank 128",
"tags": "quantized",
"size": 3.37,
"date": "2025 October",
"extras": ""
},
"NoobAI-XL v1.0 v-pred sdnq-svd-uint4": {
"path": "Disty0/NoobAI-XL-Vpred-v1.0-SDNQ-uint4-svd-r128",
"preview": "Disty0--NoobAI-XL-Vpred-v1.0-SDNQ-uint4-svd-r128.jpg",
"desc": "Quantization of Laxhar/noobai-XL-Vpred-1.0 using SDNQ: sdnq-svd 4-bit uint with svd rank 128",
"tags": "quantized",
"size": 3.37,
"date": "2025 October",
"extras": ""
},
"Tempest-by-Vlad XL": {
"path": "tempestByVlad_baseV01.safetensors@https://civitai.com/api/download/models/1301775",
"preview": "tempestByVlad_baseV01.jpg",
"desc": "Flexible SDXL model with custom encoder and finetuned for larger landscape resolutions with high details and high contrast.",
"tags": "community",
"size": 6.94,
"date": "2025 January",
"extras": ""
},
"Tempest-by-Vlad XL Hyper": {
"path": "tempestByVlad_hyperV01.safetensors@https://civitai.com/api/download/models/1343512",
"preview": "tempestByVlad_hyperV01.jpg",
"desc": "Custom distilled variant with goal to get as-normal-as-possible model that works with low steps and guidance-free",
"tags": "community",
"size": 6.94,
"date": "2025 January",
"extras": ""
},
"Juggernaut XL XI": {
"path": "juggernautXL_juggXIByRundiffusion.safetensors@https://civitai.com/api/download/models/782002",
"preview": "juggernautXL_juggXIByRundiffusion.jpg",
"desc": "Showcase finetuned model based on Stable diffusion XL",
"date": "2024 August",
"size": 6.94,
"tags": "community",
"extras": "sampler: DEIS, steps: 20, cfg_scale: 6.0"
},
"Juggernaut XL XI Lightning": {
"path": "juggernautXL_juggXILightningByRD.safetensors@https://civitai.com/api/download/models/920957",
"preview": "juggernautXL_juggXILightningByRD.jpg",
"desc": "Showcase finetuned model based on Stable diffusion XL",
"date": "2024 August",
"size": 6.94,
"tags": "community",
"extras": "sampler: DPM SDE, steps: 6, cfg_scale: 2.0"
},
"Juggernaut SD Reborn": {
"original": true,
"path": "juggernaut_reborn.safetensors@https://civitai.com/api/download/models/274039",
"preview": "juggernaut_reborn.jpg",
"desc": "Showcase finetuned model based on Stable diffusion 1.5",
"date": "2023 December",
"size": 2.28,
"tags": "community",
"extras": "width: 512, height: 512, sampler: DEIS, steps: 20, cfg_scale: 6.0"
},
"WAI Illustrious XL v15": {
"path": "waiIllustriousSDXL_v150.safetensors@https://civitai.com/api/download/models/2167369",
"preview": "waiIllustriousSDXL_v150.jpg",
"desc": "",
"tags": "community",
"size": 6.94,
"date": "2025 August",
"extras": ""
},
"Pony Realism XL v2.3": {
"path": "ponyRealism_V23.safetensors@https://civitai.com/api/download/models/1763661",
"preview": "ponyRealism_V23.jpg",
"desc": "",
"tags": "community",
"size": 6.94,
"date": "2025 May",
"extras": ""
},
"NoobAI XL 1.0 V-Pred": {
"path": "noobaiXLNAIXL_vPred10Version.safetensors@https://huggingface.co/Laxhar/noobai-XL-Vpred-1.0/resolve/main/NoobAI-XL-Vpred-v1.0.safetensors",
"preview": "noobaiXLNAIXL_vPred10Version.jpg",
"desc": "",
"tags": "community",
"size": 6.94,
"date": "2024 December",
"extras": ""
},
"NoobAI XL 1.1 Epsilon": {
"path": "noobaiXLNAIXL_epsilonPred11Version.safetensors@https://huggingface.co/Laxhar/noobai-XL-1.1/resolve/main/NoobAI-XL-v1.1.safetensors",
"preview": "noobaiXLNAIXL_epsilonPred11Version.jpg",
"desc": "",
"tags": "community",
"size": 6.94,
"date": "2024 November",
"extras": ""
},
"WAI-Ani-Pony XL v14": {
"path": "waiANIPONYXL_v140.safetensors.safetensors@https://civitai.com/api/download/models/1767402",
"preview": "waiANIPONYXL_v140.jpg",
"desc": "",
"tags": "community",
"size": 6.94,
"date": "2025 May",
"extras": ""
},
"Tiwaz CenKreChro": {
"path": "Tiwaz/CenKreChro",
"preview": "Tiwaz--CenKreChro.jpg",
"skip": true,
"desc": "Based Centerfold Flux 5, trying to merge in Chroma and Krea.",
"extras": "",
"tags": "community",
"date": "2025 September"
},
"purplesmartai Pony 7": {
"path": "purplesmartai/pony-v7-base",
"preview": "purplesmartai--pony-v7-base.jpg",
"skip": true,
"desc": "Pony V7 is a versatile character generation model based on AuraFlow architecture. It supports a wide range of styles and species types (humanoid, anthro, feral, and more) and handles character interactions through natural language prompts.",
"extras": "",
"tags": "community",
"date": "October September"
},
"ShuttleAI Shuttle 3.0 Diffusion": {
"path": "shuttleai/shuttle-3-diffusion",
"desc": "Shuttle uses Flux.1 Schnell as its base. It can produce images similar to Flux Dev or Pro in just 4 steps, and it is licensed under Apache 2. The model was partially de-distilled during training. When used beyond 10 steps, it enters refiner mode enhancing image details without altering the composition",
"preview": "shuttleai--shuttle-3-diffusion.jpg",
"tags": "community",
"skip": true
},
"ShuttleAI Shuttle 3.1 Aesthetic": {
"path": "shuttleai/shuttle-3.1-aesthetic",
"desc": "Shuttle uses Flux.1 Schnell as its base. It can produce images similar to Flux Dev or Pro in just 4 steps, and it is licensed under Apache 2. The model was partially de-distilled during training. When used beyond 10 steps, it enters refiner mode enhancing image details without altering the composition",
"preview": "shuttleai--shuttle-3_1-aestetic.jpg",
"tags": "community",
"skip": true
},
"ShuttleAI Shuttle Jaguar": {
"path": "shuttleai/shuttle-jaguar",
"desc": "Shuttle uses Flux.1 Schnell as its base. It can produce images similar to Flux Dev or Pro in just 4 steps, and it is licensed under Apache 2. The model was partially de-distilled during training. When used beyond 10 steps, it enters refiner mode enhancing image details without altering the composition",
"preview": "shuttleai--shuttle-jaguar.jpg",
"tags": "community",
"skip": true
},
"Google Gemini 2.5 Flash Nano Banana": {
"path": "gemini-2.5-flash-image",
"desc": "Gemini can generate and process images conversationally. You can prompt Gemini with text, images, or a combination of both allowing you to create, edit, and iterate on visuals with unprecedented control.",
"preview": "gemini-2.5-flash-image.jpg",
"tags": "cloud",
"skip": true
},
"Google Gemini 3.0 Pro Nano Banana": {
"path": "gemini-3-pro-image-preview",
"desc": "Built on Gemini 3. Create and edit images with studio-quality levels of precision and control",
"preview": "gemini-3-pro-image-preview.jpg",
"tags": "cloud",
"skip": true
"extras": "sampler: Default, cfg_scale: 1.5, steps: 50",
"size": 15.3,
"date": "2025 January"
}
}
+27 -23
View File
@@ -648,7 +648,7 @@ def check_diffusers():
t_start = time.time()
if args.skip_all:
return
sha = 'f6b6a7181eb44f0120b29cd897c129275f366c2a' # diffusers commit hash
sha = 'd7a1c31f4f85bae5a9e01cdce49bd7346bd8ccd6' # diffusers commit hash
# if args.use_rocm or args.use_zluda or args.use_directml:
# sha = '043ab2520f6a19fce78e6e060a68dbc947edb9f9' # lock diffusers versions for now
pkg = pkg_resources.working_set.by_key.get('diffusers', None)
@@ -678,9 +678,12 @@ def check_transformers():
if args.use_directml:
target_transformers = '4.52.4'
target_tokenizers = '0.21.4'
elif args.new:
target_transformers = '5.0.0rc2'
target_tokenizers = '0.22.2'
else:
target_transformers = '4.57.3'
target_tokenizers = '0.22.1'
target_transformers = '4.57.5'
target_tokenizers = '0.22.2'
if (pkg_transformers is None) or ((pkg_transformers.version != target_transformers) or (pkg_tokenizers is None) or ((pkg_tokenizers.version != target_tokenizers) and (not args.experimental))):
if pkg_transformers is None:
log.info(f'Transformers install: version={target_transformers}')
@@ -757,7 +760,7 @@ def install_rocm_zluda():
msg = f'ROCm: version={rocm.version}'
if device is not None:
msg += f', using agent {device.name}'
msg += f', using agent {device}'
log.info(msg)
if sys.platform == "win32":
@@ -778,20 +781,20 @@ def install_rocm_zluda():
zluda_installer.install()
zluda_installer.set_default_agent(device)
except Exception as e:
log.warning(f'Failed to install ZLUDA: {e}')
log.error(f'Install ZLUDA: {e}')
try:
zluda_installer.load()
except Exception as e:
log.warning(f'Failed to load ZLUDA: {e}')
log.error(f'Load ZLUDA: {e}')
else: # TODO rocm: switch to pytorch source when it becomes available
if device is None:
log.warning('No ROCm agent was found. Please make sure that graphics driver is installed and up to date.')
log.error('ROCm: no agent found - make sure that graphics driver is installed and up to date')
if isinstance(rocm.environment, rocm.PythonPackageEnvironment):
check_python(supported_minors=[11, 12, 13], reason='ROCm backend requires a Python version between 3.11 and 3.13')
check_python(supported_minors=[11, 12, 13], reason='ROCm: python==3.11/3.12/3.13 required')
torch_command = os.environ.get('TORCH_COMMAND', f'torch torchvision --index-url https://rocm.nightlies.amd.com/{device.therock}')
else:
check_python(supported_minors=[12], reason='ROCm Windows preview requires Python version 3.12')
check_python(supported_minors=[12], reason='ROCm: Windows preview python==3.12 required')
torch_command = os.environ.get('TORCH_COMMAND', '--no-cache-dir https://repo.radeon.com/rocm/windows/rocm-rel-6.4.4/torch-2.8.0a0%2Bgitfc14c65-cp312-cp312-win_amd64.whl https://repo.radeon.com/rocm/windows/rocm-rel-6.4.4/torchvision-0.24.0a0%2Bc85f008-cp312-cp312-win_amd64.whl')
else:
#check_python(supported_minors=[10, 11, 12, 13, 14], reason='ROCm backend requires a Python version between 3.10 and 3.13')
@@ -818,12 +821,12 @@ def install_rocm_zluda():
log.warning("ROCm: minimum supported version=6.0")
if device is None or os.environ.get("HSA_OVERRIDE_GFX_VERSION", None) is not None:
log.info(f'ROCm: HSA_OVERRIDE_GFX_VERSION auto config skipped: device={device.name if device is not None else None} version={os.environ.get("HSA_OVERRIDE_GFX_VERSION", None)}')
log.info(f'ROCm: HSA_OVERRIDE_GFX_VERSION auto config skipped: device={device} version={os.environ.get("HSA_OVERRIDE_GFX_VERSION", None)}')
else:
gfx_ver = device.get_gfx_version()
if gfx_ver is not None and device.name.removeprefix("gfx") != gfx_ver.replace(".", ""):
os.environ.setdefault('HSA_OVERRIDE_GFX_VERSION', gfx_ver)
log.info(f'ROCm: HSA_OVERRIDE_GFX_VERSION config overridden: device={device.name} version={os.environ.get("HSA_OVERRIDE_GFX_VERSION", None)}')
log.info(f'ROCm: HSA_OVERRIDE_GFX_VERSION config overridden: device={device} version={os.environ.get("HSA_OVERRIDE_GFX_VERSION", None)}')
ts('amd', t_start)
return torch_command
@@ -946,7 +949,7 @@ def check_torch():
if not is_cuda_available and not is_ipex_available and allow_rocm:
from modules import rocm
is_rocm_available = allow_rocm and (args.use_rocm or args.use_zluda or (len(rocm.agents) != 0 if sys.platform == "win32" else rocm.is_installed)) # late eval to avoid unnecessary import
is_rocm_available = allow_rocm and (args.use_rocm or args.use_zluda or rocm.is_installed) # late eval to avoid unnecessary import
if is_cuda_available and args.use_cuda: # prioritize cuda
torch_command = install_cuda()
@@ -1397,6 +1400,7 @@ def set_environment():
log.debug('Setting environment tuning')
os.environ.setdefault('ACCELERATE', 'True')
os.environ.setdefault('ATTN_PRECISION', 'fp16')
os.environ.setdefault('ClDeviceGlobalMemSizeAvailablePercent', '100')
os.environ.setdefault('CUDA_AUTO_BOOST', '1')
os.environ.setdefault('CUDA_CACHE_DISABLE', '0')
os.environ.setdefault('CUDA_DEVICE_DEFAULT_PERSISTING_L2_CACHE_PERCENTAGE_LIMIT', '0')
@@ -1407,20 +1411,27 @@ def set_environment():
os.environ.setdefault('GRADIO_ANALYTICS_ENABLED', 'False')
os.environ.setdefault('K_DIFFUSION_USE_COMPILE', '0')
os.environ.setdefault('KINETO_LOG_LEVEL', '3')
os.environ.setdefault('NEOReadDebugKeys', '1')
os.environ.setdefault('NUMEXPR_MAX_THREADS', '16')
os.environ.setdefault('PYTHONHTTPSVERIFY', '0')
os.environ.setdefault('PYTORCH_ENABLE_MPS_FALLBACK', '1')
os.environ.setdefault('PYTORCH_ENABLE_XPU_FALLBACK', '1')
os.environ.setdefault('RUNAI_STREAMER_CHUNK_BYTESIZE', '2097152')
os.environ.setdefault('RUNAI_STREAMER_LOG_LEVEL', 'DEBUG' if os.environ.get('SD_LOAD_DEBUG') else 'WARNING')
os.environ.setdefault('RUNAI_STREAMER_MEMORY_LIMIT', '-1')
os.environ.setdefault('SAFETENSORS_FAST_GPU', '1')
os.environ.setdefault('SYCL_CACHE_PERSISTENT', '1')
os.environ.setdefault('TF_CPP_MIN_LOG_LEVEL', '2')
os.environ.setdefault('TF_ENABLE_ONEDNN_OPTS', '0')
os.environ.setdefault('TOKENIZERS_PARALLELISM', '0')
os.environ.setdefault('TORCH_CUDNN_V8_API_ENABLED', '1')
os.environ.setdefault('TORCH_FORCE_NO_WEIGHTS_ONLY_LOAD', '1')
os.environ.setdefault('TORCH_ROCM_AOTRITON_ENABLE_EXPERIMENTAL', '1')
os.environ.setdefault('UR_L0_ENABLE_RELAXED_ALLOCATION_LIMITS', '1')
os.environ.setdefault('USE_TORCH', '1')
os.environ.setdefault('UV_INDEX_STRATEGY', 'unsafe-any-match')
os.environ.setdefault('UV_NO_BUILD_ISOLATION', '1')
os.environ.setdefault('UVICORN_TIMEOUT_KEEP_ALIVE', '60')
os.environ.setdefault('RUNAI_STREAMER_CHUNK_BYTESIZE', '2097152')
os.environ.setdefault('RUNAI_STREAMER_MEMORY_LIMIT', '-1')
os.environ.setdefault('RUNAI_STREAMER_LOG_LEVEL', 'DEBUG' if os.environ.get('SD_LOAD_DEBUG') else 'WARNING')
allocator = f'garbage_collection_threshold:{opts.get("torch_gc_threshold", 80)/100:0.2f},max_split_size_mb:512'
if opts.get("torch_malloc", "native") == 'cudaMallocAsync':
allocator += ',backend:cudaMallocAsync'
@@ -1430,14 +1441,6 @@ def set_environment():
os.environ.setdefault('PYTORCH_CUDA_ALLOC_CONF', allocator)
os.environ.setdefault('PYTORCH_HIP_ALLOC_CONF', allocator)
log.debug(f'Torch allocator: "{allocator}"')
os.environ.setdefault('TORCH_ROCM_AOTRITON_ENABLE_EXPERIMENTAL', '1')
os.environ.setdefault('NEOReadDebugKeys', '1')
os.environ.setdefault('ClDeviceGlobalMemSizeAvailablePercent', '100')
os.environ.setdefault('SYCL_CACHE_PERSISTENT', '1')
os.environ.setdefault('UR_L0_ENABLE_RELAXED_ALLOCATION_LIMITS', '1')
os.environ.setdefault('PYTORCH_ENABLE_XPU_FALLBACK', '1')
os.environ.setdefault('PYTORCH_ENABLE_MPS_FALLBACK', '1')
os.environ.setdefault('TOKENIZERS_PARALLELISM', '0')
def check_extensions():
@@ -1644,6 +1647,7 @@ def check_version(reset=True): # pylint: disable=unused-argument
# git('git stash pop')
ver = git('log -1 --pretty=format:"%h %ad"')
log.info(f'Repository upgraded: {ver}')
log.warning('Server restart is recommended to apply changes')
if ver == latest: # double check
restart()
except Exception:
+2 -2
View File
@@ -46,8 +46,8 @@ img { background-color: var(--background-color); }
input[type=range] { height: var(--line-xs) !important; appearance: none !important; margin-top: 0 !important; min-width: max(4em, 100%) !important; width: 100% !important; background: transparent !important; }
input[type=range]::-webkit-slider-runnable-track { width: 100% !important; height: var(--line-xs) !important; cursor: pointer !important; background: var(--input-background-fill) !important; border: 0px solid var(--primary-900) !important; }
input[type=range]::-moz-range-track { width: 100% !important; height: var(--line-xs) !important; cursor: pointer !important; background: var(--input-background-fill) !important; border: 0px solid var(--primary-900) !important; }
input[type=range]::-webkit-slider-thumb { border: 0px solid var(--primary-950)0 !important; height: var(--line-sm) !important; width: var(--line-sm) !important; background: var(--highlight-color) !important; cursor: pointer !important; appearance: none !important; margin-top: -4px; border-radius: 4px; }
input[type=range]::-moz-range-thumb { border: 0px solid var(--primary-950)0 !important; height: var(--line-sm) !important; width: var(--line-sm) !important; background: var(--highlight-color) !important; cursor: pointer !important; appearance: none !important; margin-top: -4px; border-radius: 4px; }
input[type=range]::-webkit-slider-thumb { border: 0px solid var(--primary-950) !important; height: var(--line-sm) !important; width: var(--line-sm) !important; background: var(--highlight-color) !important; cursor: pointer !important; appearance: none !important; margin-top: -4px; border-radius: 4px; }
input[type=range]::-moz-range-thumb { border: 0px solid var(--primary-950) !important; height: var(--line-sm) !important; width: var(--line-sm) !important; background: var(--highlight-color) !important; cursor: pointer !important; appearance: none !important; margin-top: -4px; border-radius: 4px; }
::-webkit-scrollbar { width: 12px; height: 12px; }
::-webkit-scrollbar-track { background: var(--primary-800); }
+3 -3
View File
@@ -553,7 +553,7 @@ svg.feather.feather-image,
}
.output-html {
line-height: 1.2 rem;
line-height: 1.2rem;
overflow-x: hidden;
}
@@ -1016,7 +1016,7 @@ svg.feather.feather-image,
.loading {
color: white;
position: border-box;
position: absolute;
top: 85%;
font-size: 1.5em;
}
@@ -1028,7 +1028,7 @@ svg.feather.feather-image,
border-radius: 50%;
border-top: var(--spacing-md) solid var(--primary-600);
animation: spin 2s linear infinite, pulse 1.5s ease-in-out infinite;
position: border-box;
position: absolute;
}
.loader::before,
+6 -4
View File
@@ -43,12 +43,12 @@
--button-secondary-background-fill-hover: var(--neutral-600);
--block-title-text-color: var(--neutral-300);
--radius-xxs: 0;
--radius-xs: 1;
--radius-xs: 1px;
--radius-sm: 2px;
--radius-md: 3;
--radius-md: 3px;
--radius-lg: 4px;
--radius-xl: 5;
--radius-xxl: 6;
--radius-xl: 5px;
--radius-xxl: 6px;
--line-xs: 1.0em;
--line-sm: 1.2em;
--line-md: 1.4em;
@@ -77,8 +77,10 @@ button { max-width: 400px; white-space: nowrap; }
img { background-color: var(--background-color); }
input[type='range'] { display: block; margin: 0; padding: 0; height: 0.8em; background-color: transparent; overflow: hidden; cursor: pointer; box-shadow: 0 0 0 0 transparent; -webkit-appearance: none; appearance: none; }
/* eslint-disable-next-line css/no-invalid-properties */
input[type='range']::-webkit-slider-thumb { height: .9em; width: .9em; background-color: hsl(180, 54%, 61%); box-shadow: var(--range-shadow); border-radius: var(--radius-xs); }
input[type='range']::-webkit-slider-runnable-track, input[type='range']::-webkit-slider-thumb { -webkit-appearance: none; }
/* eslint-disable-next-line css/no-invalid-properties */
input[type='range']::-moz-range-thumb { height: .9em; width: .9em; background-color: hsl(180, 54%, 61%); box-shadow: var(--range-shadow); }
input[type='range']::-moz-range-track, input[type='range']::-webkit-slider-runnable-track { border: none; background: none; width: 100%; height: 100%; }
+1 -2
View File
@@ -3,7 +3,6 @@ function controlInputMode(inputMode, ...args) {
if (updateEl) updateEl.click();
const tab = gradioApp().querySelector('#control-tab-input button.selected');
if (!tab) return ['Image', ...args];
// let inputTab = tab.innerText;
const tabs = Array.from(gradioApp().querySelectorAll('#control-tab-input button'));
const tabIdx = tabs.findIndex((btn) => btn.classList.contains('selected'));
const tabNames = ['Image', 'Video', 'Batch', 'Folder'];
@@ -21,7 +20,7 @@ async function setupControlUI() {
const tabs = ['input', 'output', 'preview'];
for (const tab of tabs) {
const btn = gradioApp().getElementById(`control-${tab}-button`);
if (!btn) continue; // eslint-disable-line no-continue
if (!btn) continue;
btn.style.cursor = 'pointer';
btn.onclick = () => {
const t = gradioApp().getElementById(`control-tab-${tab}`);
+56 -40
View File
@@ -140,39 +140,55 @@ async function filterExtraNetworksForTab(searchTerm) {
const cards = Array.from(pg.querySelectorAll('.card') || []);
items += cards.length;
if (searchTerm === '' || searchTerm === 'all/') {
cards.forEach((elem) => elem.style.display = '');
cards.forEach((elem) => { elem.style.display = ''; });
} else if (searchTerm === 'reference/') {
cards.forEach((elem) => elem.style.display = elem.dataset.name
.toLowerCase()
.includes('reference/') && elem.dataset.tags === '' ? '' : 'none');
cards.forEach((elem) => {
elem.style.display = elem.dataset.name
.toLowerCase()
.includes('reference/') && elem.dataset.tags === '' ? '' : 'none';
});
} else if (searchTerm === 'distilled/') {
cards.forEach((elem) => elem.style.display = elem.dataset.tags
.toLowerCase()
.includes('distilled') ? '' : 'none');
cards.forEach((elem) => {
elem.style.display = elem.dataset.tags
.toLowerCase()
.includes('distilled') ? '' : 'none';
});
} else if (searchTerm === 'community/') {
cards.forEach((elem) => elem.style.display = elem.dataset.tags
.toLowerCase()
.includes('community') ? '' : 'none');
cards.forEach((elem) => {
elem.style.display = elem.dataset.tags
.toLowerCase()
.includes('community') ? '' : 'none';
});
} else if (searchTerm === 'cloud/') {
cards.forEach((elem) => elem.style.display = elem.dataset.tags
.toLowerCase()
.includes('cloud') ? '' : 'none');
cards.forEach((elem) => {
elem.style.display = elem.dataset.tags
.toLowerCase()
.includes('cloud') ? '' : 'none';
});
} else if (searchTerm === 'quantized/') {
cards.forEach((elem) => elem.style.display = elem.dataset.tags
.toLowerCase()
.includes('quantized') ? '' : 'none');
cards.forEach((elem) => {
elem.style.display = elem.dataset.tags
.toLowerCase()
.includes('quantized') ? '' : 'none';
});
} else if (searchTerm === 'local/') {
cards.forEach((elem) => elem.style.display = elem.dataset.name
.toLowerCase()
.includes('reference/') ? 'none' : '');
cards.forEach((elem) => {
elem.style.display = elem.dataset.name
.toLowerCase()
.includes('reference/') ? 'none' : '';
});
} else if (searchTerm === 'diffusers/') {
cards.forEach((elem) => elem.style.display = elem.dataset.name
.toLowerCase().replace('models--', 'diffusers').replaceAll('\\', '/')
.includes('diffusers/') ? '' : 'none');
cards.forEach((elem) => {
elem.style.display = elem.dataset.name
.toLowerCase().replace('models--', 'diffusers').replaceAll('\\', '/')
.includes('diffusers/') ? '' : 'none';
});
} else if (searchTerm.startsWith('r#')) {
searchTerm = searchTerm.substring(2);
const re = new RegExp(searchTerm, 'i');
cards.forEach((elem) => elem.style.display = re.test(`filename: ${elem.dataset.filename}|name: ${elem.dataset.name}|tags: ${elem.dataset.tags}`) ? '' : 'none');
cards.forEach((elem) => {
elem.style.display = re.test(`filename: ${elem.dataset.filename}|name: ${elem.dataset.name}|tags: ${elem.dataset.tags}`) ? '' : 'none';
});
} else {
const searchList = searchTerm.split('|').filter((s) => s !== '' && !s.startsWith('-')).map((s) => s.trim());
const excludeList = searchTerm.split('|').filter((s) => s !== '' && s.trim().startsWith('-')).map((s) => s.trim().substring(1).trim());
@@ -198,8 +214,8 @@ async function filterExtraNetworksForTab(searchTerm) {
}
function tryToRemoveExtraNetworkFromPrompt(textarea, text) {
const re_extranet = /<([^:]+:[^:]+):[\d\.]+>/;
const re_extranet_g = /\s+<([^:]+:[^:]+):[\d\.]+>/g;
const re_extranet = /<([^:]+:[^:]+):[\d.]+>/;
const re_extranet_g = /\s+<([^:]+:[^:]+):[\d.]+>/g;
let m = text.match(re_extranet);
let replaced = false;
let newTextareaText;
@@ -243,7 +259,7 @@ function sortExtraNetworks(fixed = 'no') {
const cards = Array.from(pg.querySelectorAll('.card') || []);
if (cards.length === 0) return 'sort: no cards';
num += cards.length;
cards.sort((a, b) => { // eslint-disable-line no-loop-func
cards.sort((a, b) => {
switch (sortVal) {
case 0: return 0;
case 1: return a.dataset.name ? a.dataset.name.localeCompare(b.dataset.name) : 0;
@@ -310,21 +326,21 @@ function extraNetworksSearchButton(event) {
function extraNetworksFilterVersion(event) {
const version = event.target.textContent.trim();
const activeTab = getENActiveTab();
const activePage = getENActivePage().toLowerCase();
let cardContainer = gradioApp().querySelector(`#${activeTab}_${activePage}_cards`);
if (!cardContainer) cardContainer = gradioApp().querySelector(`#txt2img_extra_networks_${activePage}_cards`);
log('extraNetworksFilterVersion', { version, activeTab, activePage, cardContainer });
if (!cardContainer) return;
if (cardContainer.dataset.activeVersion === version) {
cardContainer.dataset.activeVersion = '';
cardContainer.querySelectorAll('.card').forEach((card) => card.style.display = '');
} else {
cardContainer.dataset.activeVersion = version;
cardContainer.querySelectorAll('.card').forEach((card) => {
if (card.dataset.version === version) card.style.display = '';
else card.style.display = 'none';
});
const cardContainers = gradioApp().querySelectorAll('.extra-network-cards');
log('extraNetworksFilterVersion', { activePage, version });
for (const cardContainer of cardContainers) {
if (!cardContainer.id.includes(activePage)) continue;
if (cardContainer.dataset.activeVersion === version) {
cardContainer.dataset.activeVersion = '';
cardContainer.querySelectorAll('.card').forEach((card) => { card.style.display = ''; });
} else {
cardContainer.dataset.activeVersion = version;
cardContainer.querySelectorAll('.card').forEach((card) => {
if (card.dataset.version === version) card.style.display = '';
else card.style.display = 'none';
});
}
}
}
+240 -46
View File
@@ -1,12 +1,12 @@
/* eslint-disable max-classes-per-file */
/* eslint lines-between-class-members: ["error", "always", { "exceptAfterSingleLine": true }] */
let ws;
let url;
let currentImage;
let currentImage = null;
let pruneImagesTimer;
let outstanding = 0;
let lastSort = 0;
let lastSortName = 'None';
let gallerySelection = { files: [], index: -1 };
const galleryHashes = new Set();
let maintenanceController = new AbortController();
const folderStylesheet = new CSSStyleSheet();
@@ -24,6 +24,64 @@ const el = {
const SUPPORTED_EXTENSIONS = ['jpg', 'jpeg', 'png', 'webp', 'tiff', 'jp2', 'jxl', 'gif', 'mp4', 'mkv', 'avi', 'mjpeg', 'mpg', 'avr'];
function getVisibleGalleryFiles() {
if (!el.files) return [];
return Array.from(el.files.children).filter((node) => node.name && node.offsetParent);
}
function updateGallerySelectionClasses(files = gallerySelection.files, index = gallerySelection.index) {
files.forEach((file, i) => {
file.classList.toggle('gallery-file-selected', i === index);
});
}
function refreshGallerySelection() {
updateGallerySelectionClasses(gallerySelection.files, -1);
const files = getVisibleGalleryFiles();
const index = files.findIndex((file) => file.src === currentImage);
gallerySelection = { files, index };
updateGallerySelectionClasses(files, index);
}
function resetGallerySelection() {
updateGallerySelectionClasses(gallerySelection.files, -1);
gallerySelection = { files: [], index: -1 };
currentImage = null;
}
function applyGallerySelection(index, { send = true } = {}) {
if (!gallerySelection.files.length) refreshGallerySelection();
const files = gallerySelection.files;
if (!files.length) return;
if (!Number.isInteger(index) || index < 0 || index >= files.length) {
log('gallery selection index out of range', index, files.length);
resetGallerySelection();
return;
}
gallerySelection.index = index;
currentImage = files[index].src;
updateGallerySelectionClasses(files, index);
if (send && el.btnSend) el.btnSend.click();
}
function setGallerySelectionByElement(element, options) {
if (!gallerySelection.files.length) refreshGallerySelection();
let index = gallerySelection.files.findIndex((file) => file === element);
if (index < 0) {
refreshGallerySelection();
index = gallerySelection.files.findIndex((file) => file === element);
}
if (index >= 0) applyGallerySelection(index, options);
}
function buildGalleryFileUrl(path) {
return new URL(`/file=${encodeURI(path)}`, window.location.origin).toString();
}
window.getGallerySelection = () => ({ index: gallerySelection.index, files: gallerySelection.files });
window.setGallerySelection = (index, options) => applyGallerySelection(index, options);
window.getGallerySelectedUrl = () => (currentImage ? buildGalleryFileUrl(currentImage) : null);
/**
* Wait for the `outstanding` variable to be below the specified value
* @param {number} num - Threshold for `outstanding`
@@ -103,11 +161,91 @@ function updateGalleryStyles() {
.gallery-file:hover {
filter: grayscale(100%);
}
:host(.gallery-file-selected) .gallery-file {
box-shadow: 0 0 0 2px var(--sd-button-selected-color);
}
`);
}
// Classes
class SimpleProgressBar {
#container = document.createElement('div');
#progress = document.createElement('div');
#textDiv = document.createElement('div');
#text = document.createElement('span');
#visible = false;
#hideTimeout = null;
#interval = null;
#max = 0;
/** @type {Set} */
#monitoredSet;
constructor(monitoredSet) {
this.#monitoredSet = monitoredSet; // This is required because incrementing a variable with a class method turned out to not be an atomic operation
this.#container.style.cssText = 'position:relative;overflow:hidden;border-radius:var(--sd-border-radius);width:100%;background-color:hsla(0,0%,36%,0.3);height:1.2rem;margin:0;padding:0;display:none;';
this.#progress.style.cssText = 'position:absolute;left:0;height:100%;width:0;transition:width 200ms;';
this.#progress.style.backgroundColor = 'hsla(110, 32%, 35%, 0.80)'; // alt: '#27911d'
this.#textDiv.style.cssText = 'position:relative;margin:auto;width:max-content;height:100%;';
this.#text.style.cssText = 'user-select:none;color:white;';
this.#textDiv.append(this.#text);
this.#container.append(this.#progress, this.#textDiv);
}
start(total) {
this.clear();
this.#max = total;
this.#interval = setInterval(() => {
this.#update(this.#monitoredSet.size, this.#max);
}, 250);
}
attachTo(element) {
if (element.hasChildNodes) {
element.innerHTML = '';
}
element.appendChild(this.#container);
}
clear() {
this.#stop();
clearTimeout(this.#hideTimeout);
this.#hideTimeout = null;
this.#container.style.display = 'none';
this.#visible = false;
this.#progress.style.width = '0';
this.#text.textContent = '';
}
#update(loaded, max) {
if (this.#hideTimeout) {
this.#hideTimeout = null;
}
this.#progress.style.width = `${Math.floor((loaded / max) * 100)}%`;
this.#text.textContent = `${loaded}/${max}`;
if (!this.#visible) {
this.#container.style.display = 'block';
this.#visible = true;
}
if (loaded >= max) {
this.#stop();
this.#hideTimeout = setTimeout(() => {
this.clear();
}, 1000);
}
}
#stop() {
clearInterval(this.#interval);
this.#interval = null;
}
}
const galleryProgressBar = new SimpleProgressBar(galleryHashes);
/* This isn't as robust as the Web Locks API, but it will at least work if accessing a remote machine without HTTPS */
class SimpleFunctionQueue {
#id;
@@ -163,9 +301,16 @@ class SimpleFunctionQueue {
// HTML Elements
class GalleryFolder extends HTMLElement {
constructor(name) {
constructor(folder) {
super();
this.name = decodeURI(name);
// Support both old format (string) and new format (object with path and label)
if (typeof folder === 'object' && folder !== null) {
this.name = decodeURI(folder.path || '');
this.label = decodeURI(folder.label || folder.path || '');
} else {
this.name = decodeURI(folder);
this.label = this.name;
}
this.style.overflowX = 'hidden';
this.shadow = this.attachShadow({ mode: 'open' });
this.shadow.adoptedStyleSheets = [folderStylesheet];
@@ -174,8 +319,8 @@ class GalleryFolder extends HTMLElement {
connectedCallback() {
const div = document.createElement('div');
div.className = 'gallery-folder';
div.innerHTML = `<span class="gallery-folder-icon">\uf03e</span> ${this.name}`;
div.title = this.name;
div.innerHTML = `<span class="gallery-folder-icon">\uf03e</span> ${this.label}`;
div.title = this.name; // Show full path on hover
div.addEventListener('click', () => {
for (const folder of el.folders.children) {
if (folder.name === this.name) folder.shadow.firstElementChild.classList.add('gallery-folder-selected');
@@ -220,7 +365,7 @@ async function handleSeparator(separator) {
if (!f.name) continue; // Skip separators
// Check if file belongs to this exact directory
const fileDir = f.name.match(/(.*)[\/\\]/);
const fileDir = f.name.match(/(.*)[/\\]/);
const fileDirPath = fileDir ? fileDir[1] : '';
if (separator.title.length > 0 && fileDirPath === separator.title) {
@@ -232,14 +377,18 @@ async function handleSeparator(separator) {
}
async function addSeparators() {
document.querySelectorAll('.gallery-separator').forEach((node) => el.files.removeChild(node));
document.querySelectorAll('.gallery-separator').forEach((node) => { el.files.removeChild(node); });
const all = Array.from(el.files.children);
let lastDir;
let isFirstSeparator = true; // Flag to open the first separator by default
// Count root files (files without a directory path)
const hasRootFiles = all.some((f) => f.name && !f.name.match(/[/\\]/));
// Only auto-open first separator if there are no root files to display
let isFirstSeparator = !hasRootFiles;
// First pass: create separators
for (const f of all) {
let dir = f.name?.match(/(.*)[\/\\]/);
let dir = f.name?.match(/(.*)[/\\]/);
if (!dir) dir = '';
else dir = dir[1];
if (dir !== lastDir) {
@@ -249,7 +398,7 @@ async function addSeparators() {
let fileCount = 0;
for (const file of all) {
if (!file.name) continue;
const fileDir = file.name.match(/(.*)[\/\\]/);
const fileDir = file.name.match(/(.*)[/\\]/);
const fileDirPath = fileDir ? fileDir[1] : '';
if (fileDirPath === dir) fileCount++;
}
@@ -299,7 +448,7 @@ async function addSeparators() {
for (const f of all) {
if (!f.name) continue; // Skip separators
const dir = f.name.match(/(.*)[\/\\]/);
const dir = f.name.match(/(.*)[/\\]/);
if (dir && dir[1]) {
const dirPath = dir[1];
const isOpen = separatorStates.get(dirPath);
@@ -357,7 +506,7 @@ class GalleryFile extends HTMLElement {
}
// Check separator state early to hide the element immediately
const dir = this.name.match(/(.*)[\/\\]/);
const dir = this.name.match(/(.*)[/\\]/);
if (dir && dir[1]) {
const dirPath = dir[1];
const isOpen = separatorStates.get(dirPath);
@@ -366,7 +515,9 @@ class GalleryFile extends HTMLElement {
}
}
this.hash = await getHash(`${this.folder}/${this.name}/${this.size}/${this.mtime}`); // eslint-disable-line no-use-before-define
// Normalize path to ensure consistent hash regardless of which folder view is used
const normalizedPath = this.src.replace(/\/+/g, '/').replace(/\/$/, '');
this.hash = await getHash(`${normalizedPath}/${this.size}/${this.mtime}`); // eslint-disable-line no-use-before-define
const cachedData = (this.hash && opts.browser_cache) ? await idbGet(this.hash).catch(() => undefined) : undefined;
const img = document.createElement('img');
img.className = 'gallery-file';
@@ -402,9 +553,11 @@ class GalleryFile extends HTMLElement {
this.size = json.size;
this.mtime = new Date(json.mtime);
if (opts.browser_cache) {
// Store file's actual parent directory (not browsed folder) for consistent cleanup
const fileDir = this.src.replace(/\/+/g, '/').replace(/\/[^/]+$/, '');
await idbAdd({
hash: this.hash,
folder: this.folder,
folder: fileDir,
file: this.name,
size: this.size,
mtime: this.mtime,
@@ -430,8 +583,7 @@ class GalleryFile extends HTMLElement {
return;
} // ... to here unless modifications are also being made to maintenance functionality and the usage of AbortController/AbortSignal
img.onclick = () => {
currentImage = this.src;
el.btnSend.click();
setGallerySelectionByElement(this, { send: true });
};
img.title = `Folder: ${this.folder}\nFile: ${this.name}\nSize: ${this.size.toLocaleString()} bytes\nModified: ${this.mtime.toLocaleString()}`;
if (this.shadow.children.length > 0) {
@@ -538,7 +690,7 @@ async function wsConnect(socket, timeout = 5000) {
let loop = 0;
while (socket.readyState === WebSocket.CONNECTING && loop < ttl) {
await new Promise((resolve) => setTimeout(resolve, intrasleep)); // eslint-disable-line no-promise-executor-return
await new Promise((resolve) => { setTimeout(resolve, intrasleep); });
loop++;
}
return isOpened();
@@ -569,7 +721,7 @@ async function gallerySearch() {
});
allFiles.forEach((f) => {
const dir = f.name.match(/(.*)[\/\\]/);
const dir = f.name.match(/(.*)[/\\]/);
const dirPath = (dir && dir[1]) ? dir[1] : '';
const isOpen = separatorStates.get(dirPath);
f.style.display = (!dirPath || isOpen) ? 'unset' : 'none';
@@ -603,7 +755,7 @@ async function gallerySearch() {
if (isMatch) {
fileMatches.add(f);
totalFound++;
const dir = f.name.match(/(.*)[\/\\]/);
const dir = f.name.match(/(.*)[/\\]/);
const dirPath = (dir && dir[1]) ? dir[1] : '';
directoryMatches.set(dirPath, (directoryMatches.get(dirPath) || 0) + 1);
}
@@ -634,6 +786,7 @@ async function gallerySearch() {
const t1 = performance.now();
updateStatusWithSort('Filter', ['Images', `${totalFound.toLocaleString()} / ${allFiles.length.toLocaleString()}`], `${iconStopwatch} ${Math.floor(t1 - t0).toLocaleString()}ms`);
refreshGallerySelection();
}, 250);
}
@@ -653,59 +806,84 @@ async function gallerySort(btn) {
if (arr.length === 0) return; // no files to sort
if (btn) lastSort = btn.charCodeAt(0);
const fragment = document.createDocumentFragment();
// Helper to get directory path from a file node
const getDirPath = (node) => {
const match = node.name.match(/(.*)[/\\]/);
return match ? match[1] : '';
};
// Partition into root files and subfolder files - root files always stay at top
const rootFiles = arr.filter((node) => !getDirPath(node));
const subfolderFiles = arr.filter((node) => getDirPath(node));
// Group subfolder files by directory
const folderGroups = new Map();
for (const file of subfolderFiles) {
const dir = getDirPath(file);
if (!folderGroups.has(dir)) {
folderGroups.set(dir, []);
}
folderGroups.get(dir).push(file);
}
// Sort function based on current sort mode
let sortFn;
switch (lastSort) {
case 61789: // name asc
lastSortName = 'Name Ascending';
arr
.sort((a, b) => a.name.localeCompare(b.name))
.forEach((node) => fragment.appendChild(node));
sortFn = (a, b) => a.name.localeCompare(b.name);
break;
case 61790: // name dsc
lastSortName = 'Name Descending';
arr
.sort((b, a) => a.name.localeCompare(b.name))
.forEach((node) => fragment.appendChild(node));
sortFn = (a, b) => b.name.localeCompare(a.name);
break;
case 61792: // size asc
lastSortName = 'Size Ascending';
arr
.sort((a, b) => a.size - b.size)
.forEach((node) => fragment.appendChild(node));
sortFn = (a, b) => a.size - b.size;
break;
case 61793: // size dsc
lastSortName = 'Size Descending';
arr
.sort((b, a) => a.size - b.size)
.forEach((node) => fragment.appendChild(node));
sortFn = (a, b) => b.size - a.size;
break;
case 61794: // resolution asc
lastSortName = 'Resolution Ascending';
arr
.sort((a, b) => a.width * a.height - b.width * b.height)
.forEach((node) => fragment.appendChild(node));
sortFn = (a, b) => a.width * a.height - b.width * b.height;
break;
case 61795: // resolution dsc
lastSortName = 'Resolution Descending';
arr
.sort((b, a) => a.width * a.height - b.width * b.height)
.forEach((node) => fragment.appendChild(node));
sortFn = (a, b) => b.width * b.height - a.width * a.height;
break;
case 61662:
lastSortName = 'Modified Ascending';
arr
.sort((a, b) => a.mtime - b.mtime)
.forEach((node) => fragment.appendChild(node));
sortFn = (a, b) => a.mtime - b.mtime;
break;
case 61661:
lastSortName = 'Modified Descending';
arr
.sort((b, a) => a.mtime - b.mtime)
.forEach((node) => fragment.appendChild(node));
sortFn = (a, b) => b.mtime - a.mtime;
break;
default:
lastSortName = 'None';
sortFn = null;
break;
}
// Sort root files
if (sortFn) {
rootFiles.sort(sortFn);
}
rootFiles.forEach((node) => fragment.appendChild(node));
// Sort folder names alphabetically, then sort files within each folder
const sortedFolderNames = Array.from(folderGroups.keys()).sort((a, b) => a.localeCompare(b));
for (const folderName of sortedFolderNames) {
const files = folderGroups.get(folderName);
if (sortFn) {
files.sort(sortFn);
}
files.forEach((node) => fragment.appendChild(node));
}
if (fragment.children.length === 0) return;
el.files.innerHTML = '';
el.files.appendChild(fragment);
@@ -716,7 +894,7 @@ async function gallerySort(btn) {
for (const f of all) {
if (!f.name) continue; // Skip separators
const dir = f.name.match(/(.*)[\/\\]/);
const dir = f.name.match(/(.*)[/\\]/);
if (dir && dir[1]) {
const dirPath = dir[1];
const isOpen = separatorStates.get(dirPath);
@@ -729,6 +907,7 @@ async function gallerySort(btn) {
const t1 = performance.now();
log(`gallerySort: char=${lastSort} len=${arr.length} time=${Math.floor(t1 - t0)} sort=${lastSortName}`);
updateStatusWithSort(['Images', arr.length.toLocaleString()], `${iconStopwatch} ${Math.floor(t1 - t0).toLocaleString()}ms`);
refreshGallerySelection();
}
/**
@@ -856,12 +1035,15 @@ async function fetchFilesHT(evt, controller) {
}
}
if (controller.signal.aborted) return;
el.files.appendChild(fragment);
const t1 = performance.now();
log(`gallery: folder=${evt.target.name} num=${numFiles} time=${Math.floor(t1 - t0)}ms`);
updateStatusWithSort(['Folder', evt.target.name], ['Images', numFiles.toLocaleString()], `${iconStopwatch} ${Math.floor(t1 - t0).toLocaleString()}ms`);
galleryProgressBar.start(numFiles);
addSeparators();
refreshGallerySelection();
thumbCacheCleanup(evt.target.name, numFiles, controller);
}
@@ -871,6 +1053,8 @@ async function fetchFilesWS(evt) { // fetch file-by-file list over websockets
maintenanceController.abort('Gallery update'); // Abort previous controller
maintenanceController = controller; // Point to new controller for next time
galleryHashes.clear(); // Must happen AFTER the AbortController steps
galleryProgressBar.clear();
resetGallerySelection();
el.files.innerHTML = '';
updateGalleryStyles();
@@ -915,11 +1099,14 @@ async function fetchFilesWS(evt) { // fetch file-by-file list over websockets
}
};
ws.onclose = (event) => {
if (controller.signal.aborted) return;
el.files.appendChild(fragment);
// gallerySort();
log(`gallery: folder=${evt.target.name} num=${numFiles} time=${Math.floor(t1 - t0)}ms`);
updateStatusWithSort(['Folder', evt.target.name], ['Images', numFiles.toLocaleString()], `${iconStopwatch} ${Math.floor(t1 - t0).toLocaleString()}ms`);
galleryProgressBar.start(numFiles);
addSeparators();
refreshGallerySelection();
thumbCacheCleanup(evt.target.name, numFiles, controller);
};
ws.onerror = (event) => {
@@ -973,7 +1160,8 @@ async function monitorGalleries() {
async function setOverlayAnimation() {
const busyAnimation = document.createElement('style');
busyAnimation.textContent = '.idbBusyAnim{width:16px;height:16px;border-radius:50%;display:block;margin:40px;position:relative;background:#ff3d00;color:#fff;box-shadow:-24px 0,24px 0;box-sizing:border-box;animation:2s ease-in-out infinite overlayRotation}@keyframes overlayRotation{0%{transform:rotate(0)}100%{transform:rotate(360deg)}}'; // eslint-disable-line max-len
// eslint-disable-next-line @stylistic/max-len
busyAnimation.textContent = '.idbBusyAnim{width:16px;height:16px;border-radius:50%;display:block;margin:40px;position:relative;background:#ff3d00;color:#fff;box-shadow:-24px 0,24px 0;box-sizing:border-box;animation:2s ease-in-out infinite overlayRotation}@keyframes overlayRotation{0%{transform:rotate(0)}100%{transform:rotate(360deg)}}';
document.head.append(busyAnimation);
}
@@ -990,6 +1178,12 @@ async function initGallery() { // triggered on gradio change to monitor when ui
updateGalleryStyles();
injectGalleryStatusCSS();
setOverlayAnimation();
const progress = gradioApp().getElementById('tab-gallery-progress');
if (progress) {
galleryProgressBar.attachTo(progress);
} else {
log('initGallery', 'Failed to attach loading progress bar');
}
el.search.addEventListener('input', gallerySearch);
el.btnSend = gradioApp().getElementById('tab-gallery-send-image');
document.getElementById('tab-gallery-files').style.height = opts.logmonitor_show ? '75vh' : '85vh';
+4 -4
View File
@@ -1,9 +1,9 @@
let gpuInterval = null; // eslint-disable-line prefer-const
let gpuInterval = null;
const chartData = { mem: [], load: [] };
async function updateGPUChart(mem, load) {
const maxLen = 120;
const colorRangeMap = $.range_map({ // eslint-disable-line no-undef
const colorRangeMap = $.range_map({
'0:5': '#fffafa',
'6:10': '#fff7ed',
'11:20': '#fed7aa',
@@ -22,8 +22,8 @@ async function updateGPUChart(mem, load) {
chartData.load.push(load);
if (chartData.mem.length > maxLen) chartData.mem.shift();
chartData.mem.push(mem);
$('#gpuChart').sparkline(chartData.load, sparklineConfigLOAD); // eslint-disable-line no-undef
$('#gpuChart').sparkline(chartData.mem, sparklineConfigMEM); // eslint-disable-line no-undef
$('#gpuChart').sparkline(chartData.load, sparklineConfigLOAD);
$('#gpuChart').sparkline(chartData.mem, sparklineConfigMEM);
}
async function updateGPU() {
+17 -1
View File
@@ -32,6 +32,7 @@ function closeModal(evt, force = false) {
}
function modalImageSwitch(offset) {
const negmod = (n, m) => ((n % m) + m) % m;
const galleryButtons = all_gallery_buttons();
if (galleryButtons.length > 1) {
const currentButton = selected_gallery_button();
@@ -39,7 +40,6 @@ function modalImageSwitch(offset) {
galleryButtons.forEach((v, i) => {
if (v === currentButton) result = i;
});
const negmod = (n, m) => ((n % m) + m) % m;
if (result !== -1) {
const nextButton = galleryButtons[negmod((result + offset), galleryButtons.length)];
nextButton.click();
@@ -47,8 +47,24 @@ function modalImageSwitch(offset) {
const modal = gradioApp().getElementById('lightboxModal');
modalImage.src = nextButton.children[0].src;
if (modalImage.style.display === 'none') modal.style.setProperty('background-image', `url(${modalImage.src})`);
return;
}
}
const galleryFilesContainer = gradioApp().getElementById('tab-gallery-files');
if (!galleryFilesContainer || !galleryFilesContainer.offsetParent) return;
const gallerySelection = window.getGallerySelection();
if (!gallerySelection.files.length || gallerySelection.files.length <= 1) return;
const baseIndex = gallerySelection.index >= 0 ? gallerySelection.index : 0;
const nextIndex = negmod((baseIndex + offset), gallerySelection.files.length);
window.setGallerySelection(nextIndex, { send: true });
const modalImage = gradioApp().getElementById('modalImage');
const modal = gradioApp().getElementById('lightboxModal');
const directSrc = window.getGallerySelectedUrl();
if (modalImage && modal && directSrc) {
modalImage.src = directSrc;
if (modalImage.style.display === 'none') modal.style.setProperty('background-image', `url(${directSrc})`);
}
}
function modalSaveImage(event) {
+4 -1
View File
@@ -150,7 +150,10 @@ async function idbFolderCleanup(keepSet, folder, signal) {
throw new Error('IndexedDB cleaning function must be told the current active folder');
}
let removals = new Set(await idbGetAllKeys('folder', folder));
// Use range query to match folder and all its subdirectories
const folderNormalized = folder.replace(/\/+/g, '/').replace(/\/$/, '');
const range = IDBKeyRange.bound(folderNormalized, `${folderNormalized}\uffff`, false, true);
let removals = new Set(await idbGetAllKeys('folder', range));
removals = removals.difference(keepSet); // Don't need to keep full set in memory
const totalRemovals = removals.size;
if (signal.aborted) {
+1 -1
View File
@@ -56,7 +56,7 @@ async function logMonitor() {
if (imgGallery) imgGallery.style.height = opts.logmonitor_show ? '50vh' : '55vh';
if (!opts.logmonitor_show) {
Array.from(document.getElementsByClassName('log-monitor')).forEach((el) => el.style.display = 'none');
Array.from(document.getElementsByClassName('log-monitor')).forEach((el) => { el.style.display = 'none'; });
return;
}
+3 -3
View File
@@ -10,7 +10,7 @@ const log = async (...msg) => {
window.logger.innerHTML += window.logPrettyPrint(...msg);
scrollBottom(window.logger);
}
console.log(ts, ...msg); // eslint-disable-line no-console
console.log(ts, ...msg);
};
const debug = async (...msg) => {
@@ -20,7 +20,7 @@ const debug = async (...msg) => {
window.logger.innerHTML += window.logPrettyPrint(...msg);
scrollBottom(window.logger);
}
console.debug(ts, ...msg); // eslint-disable-line no-console
console.debug(ts, ...msg);
};
const error = async (...msg) => {
@@ -30,7 +30,7 @@ const error = async (...msg) => {
window.logger.innerHTML += window.logPrettyPrint(...msg);
scrollBottom(window.logger);
}
console.error(ts, ...msg); // eslint-disable-line no-console
console.error(ts, ...msg);
// const txt = msg.join(' ');
// if (!txt.includes('asctime') && !txt.includes('xhr.')) xhrPost('/sdapi/v1/log', { error: txt }); // eslint-disable-line no-use-before-define
};
+1 -1
View File
@@ -7,7 +7,7 @@ function setRefreshInterval() {
document.addEventListener('visibilitychange', () => {
if (document.hidden) refreshInterval = Math.max(2500, opts.live_preview_refresh_period || 1000);
else refreshInterval = opts.live_preview_refresh_period || 1000;
log('refreshInterval', document.visibilityState, refreshInterval);
// log('refreshInterval', document.visibilityState, refreshInterval);
});
}
+25 -24
View File
@@ -2031,42 +2031,43 @@ div:has(>#tab-gallery-folders) {
.loading {
color: white;
position: border-box;
top: 85%;
font-size: 1.5em;
left: 50%;
position: absolute;
top: 20%;
transform: translateX(-50%);
}
.loader {
width: 100px;
height: 100px;
animation: spin 4s linear infinite, hue 5s infinite alternate;
border: var(--spacing-md) solid transparent;
border-radius: 50%;
border-top: var(--spacing-md) solid var(--primary-600);
animation: spin 2s linear infinite, hue 5s infinite alternate;
position: border-box;
border-top: var(--spacing-md) solid var(--sd-main-accent-color);
height: 300px;
position: relative;
width: 300px;
}
.loader::before,
.loader::after {
content: "";
position: absolute;
top: 6px;
bottom: 6px;
left: 6px;
right: 6px;
border-radius: 50%;
.loader::before, .loader::after {
border: var(--spacing-md) solid transparent;
animation: hue 5s infinite alternate;
border-radius: 50%;
bottom: 6px;
content: "";
left: 6px;
position: absolute;
right: 6px;
top: 6px;
}
.loader::before {
border-top-color: var(--primary-900);
animation: spin 3s linear infinite;
animation: 3s spin linear infinite, hue 5s infinite alternate;
border-top-color: var(--sd-main-accent-color);
filter: brightness(50%);
}
.loader::after {
border-top-color: var(--primary-300);
animation: spin 1.5s linear infinite;
animation: spin 1.5s linear infinite, hue 5s infinite alternate;
border-top-color: var(--sd-main-accent-color);
filter: brightness(150%);
}
.docs-search textarea {
@@ -2126,11 +2127,11 @@ div:has(>#tab-gallery-folders) {
.docs-card-h1 {
font-weight: bold;
font-size: 1.0;
font-size: 1.0em;
}
.docs-card-h2 {
font-size: 1.0;
font-size: 1.0em;
max-height: 4em;
overflow: hidden;
}
+1 -1
View File
@@ -173,7 +173,7 @@ async function initModels() {
`;
el.innerHTML = res.length > 0 ? ready() : warn();
el.style.display = 'block';
setTimeout(() => el.style.display = 'none', res.length === 0 ? 30000 : 1500);
setTimeout(() => { el.style.display = 'none'; }, res.length === 0 ? 30000 : 1500);
if (res.length === 0) {
if (en.classList.contains('hide')) gradioApp().getElementById('txt2img_extra_networks_btn').click();
const repeat = setInterval(() => {
+1 -1
View File
@@ -6,7 +6,7 @@ async function waitForOpts() {
// make sure all of the ui is ready and options are loaded
const t0 = performance.now();
let t1 = performance.now();
while (true) { // eslint-disable-line no-constant-condition
while (true) {
if (t1 - t0 > 120000) {
log('waitForOpts timeout');
break;
+1 -1
View File
@@ -1,7 +1,7 @@
function startTrainMonitor() {
gradioApp().querySelector('#train_error').innerHTML = '';
const id = randomId();
const onProgress = (progress) => gradioApp().getElementById('train_progress').innerHTML = progress.textinfo;
const onProgress = (progress) => { gradioApp().getElementById('train_progress').innerHTML = progress.textinfo; };
requestProgress(id, gradioApp().getElementById('train_gallery'), null, onProgress, false);
const res = Array.from(arguments);
res[0] = id;
+39 -10
View File
@@ -33,9 +33,10 @@ function clip_gallery_urls(gallery) {
}
function isVisible(el) {
if (!el) return false;
const rect = el.getBoundingClientRect();
if (rect.width === 0 && rect.height === 0) return false;
return rect.top >= 0 && rect.left >= 0 && rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) && rect.right <= (window.innerWidth || document.documentElement.clientWidth);
return (rect.top >= 0) && (rect.left >= 0) && (rect.bottom <= (window.innerHeight || document.documentElement.clientHeight)) && (rect.right <= (window.innerWidth || document.documentElement.clientWidth));
}
function all_gallery_buttons() {
@@ -63,18 +64,31 @@ function selected_gallery_index() {
const button = selected_gallery_button();
let result = -1;
buttons.forEach((v, i) => { if (v === button) { result = i; } });
if (result === -1 && gradioApp().getElementById('tab-gallery-search')?.checkVisibility()) {
const gallerySelection = window.getGallerySelection();
if (Number.isInteger(gallerySelection.index)) result = gallerySelection.index;
}
return result;
}
function selected_gallery_files() {
function selected_gallery_files(tabname) {
let allImages = [];
let allThumbnails;
if (tabname && tabname !== 'gallery') allThumbnails = gradioApp().querySelectorAll('div[id$=_gallery].gradio-gallery .thumbnail-item.thumbnail-small');
else allThumbnails = gradioApp().querySelectorAll('.gradio-gallery .thumbnails > .thumbnail-item.thumbnail-small');
try {
let allCurrentButtons = gradioApp().querySelectorAll('[style="display: block;"].tabitem div[id$=_gallery].gradio-gallery .thumbnail-item.thumbnail-small');
if (allCurrentButtons.length === 0) allCurrentButtons = gradioApp().querySelectorAll('.gradio-gallery .thumbnails > .thumbnail-item.thumbnail-small');
allImages = Array.from(allCurrentButtons).map((v) => v.querySelector('img')?.src);
allImages = allImages.filter((el) => isVisible(el));
} catch { /**/ }
const selectedIndex = selected_gallery_index();
allImages = Array.from(allThumbnails).map((v) => v.querySelector('img'));
if (tabname && tabname !== 'gallery') allImages = allImages.filter((img) => isVisible(img));
allImages = allImages.map((img) => {
let fn = img.src;
if (fn.includes('file=')) fn = fn.split('file=')[1];
return decodeURI(fn);
});
} catch (err) {
error(`selected_gallery_files: ${err}`);
}
let selectedIndex = -1;
if (tabname && tabname !== 'gallery') selectedIndex = selected_gallery_index();
return [allImages, selectedIndex];
}
@@ -86,6 +100,16 @@ function extract_image_from_gallery(gallery) {
return [gallery[index]];
}
function send_to_kanvas(gallery) {
const [image] = extract_image_from_gallery(gallery);
log('sendToKanvas', image);
if (window.loadFromURL && image.data) window.loadFromURL(image.data);
// const inputPanelEl = gradioApp().getElementById('control-template-column-input');
// if (inputPanelEl) inputPanelEl.classList.remove('hidden');
const inputPanelCb = gradioApp().getElementById('control_dynamic_input');
if (inputPanelCb && !inputPanelCb.checked) inputPanelCb.click();
}
async function setTheme(val, old) {
if (!old || val === old) return;
old = old.replace('modern/', '');
@@ -99,7 +123,7 @@ async function setTheme(val, old) {
const href = link.href.replace(old, val);
const res = await fetch(href);
if (res.ok) {
log('setTheme:', old, val);
log('setTheme', old, val);
link.href = link.href.replace(old, val);
} else {
log('setTheme: CSS not found', val);
@@ -254,7 +278,12 @@ function submit_control(...args) {
const res = create_submit_args(args);
res[0] = id;
res[1] = window.submit_state;
res[2] = gradioApp().querySelector('#control-tabs > .tab-nav > .selected')?.innerText.toLowerCase() || ''; // selected tab name
const tabs = Array.from(gradioApp().querySelectorAll('#control-tabs > .tab-nav > button'));
const tabIdx = tabs.findIndex((btn) => btn.classList.contains('selected'));
const tabNames = ['ControlNet', 'T2I Adapter', 'XS', 'Lite', 'Reference'];
const selectedTab = tabNames[tabIdx] || 'ControlNet';
res[2] = selectedTab.toLowerCase();
window.submit_state = '';
return res;
}
+1 -1
View File
@@ -14,7 +14,7 @@ async function getUIDefaults() {
const btn = gradioApp().getElementById('ui_defaults_view');
if (!btn) return;
const intersectionObserver = new IntersectionObserver((entries) => {
if (entries[0].intersectionRatio <= 0) { }
if (entries[0].intersectionRatio <= 0) { /* Pass */ }
if (entries[0].intersectionRatio > 0) btn.click();
});
intersectionObserver.observe(btn); // monitor visibility of tab
+2 -5
View File
@@ -67,11 +67,8 @@ def get_custom_args():
del env['PS1']
installer.log.trace(f'Environment: {installer.print_dict(env)}')
env = [f'{k}={v}' for k, v in os.environ.items() if k.startswith('SD_')]
installer.log.debug(f'Env flags: {env}')
ldpreload = os.environ.get('LD_PRELOAD', None)
ldpath = os.environ.get('LD_LIBRARY_PATH', None)
if ldpreload is not None or ldpath is not None:
installer.log.debug(f'Linker flags: preload="{ldpreload}" path="{ldpath}"')
ld = [f'{k}={v}' for k, v in os.environ.items() if k.startswith('LD_')]
installer.log.debug(f'Flags: sd={env} ld={ld}')
rec('args')
Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

After

Width:  |  Height:  |  Size: 69 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 97 KiB

After

Width:  |  Height:  |  Size: 77 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 90 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 117 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 124 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 87 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 114 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 94 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 121 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 87 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 99 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 274 KiB

@@ -1081,7 +1081,7 @@ class StableDiffusionXLPipelineAPG(
latents,
)
# 6. Prepare extra step kwargs. TODO: Logic should ideally just be moved out of the pipeline
# 6. Prepare extra step kwargs.
extra_step_kwargs = self.prepare_extra_step_kwargs(generator, eta)
# 7. Prepare added time ids & embeddings
+1 -1
View File
@@ -965,7 +965,7 @@ class StableDiffusionPipelineAPG(
latents,
)
# 6. Prepare extra step kwargs. TODO: Logic should ideally just be moved out of the pipeline
# 6. Prepare extra step kwargs.
extra_step_kwargs = self.prepare_extra_step_kwargs(generator, eta)
# 6.1 Add image embeds for IP-Adapter
+45 -13
View File
@@ -10,6 +10,7 @@ from starlette.websockets import WebSocket, WebSocketState
from pydantic import BaseModel, Field # pylint: disable=no-name-in-module
from PIL import Image
from modules import shared, images, files_cache, modelstats
from modules.paths import resolve_output_path
debug = shared.log.debug if os.environ.get('SD_BROWSER_DEBUG', None) is not None else lambda *args, **kwargs: None
@@ -128,20 +129,51 @@ def register_api(app: FastAPI): # register api
# @app.get('/sdapi/v1/browser/folders', response_model=List[str])
def get_folders():
def make_folder(path, label=None):
"""Create folder entry with path and display label."""
if label is None:
label = os.path.basename(path) or path
return {"path": path, "label": label}
reference_dir = os.path.join('models', 'Reference')
folders = [shared.opts.data.get(f, '') for f in OPTS_FOLDERS]
folders += list(shared.opts.browser_folders.split(','))
folders += [reference_dir]
folders = [f.strip() for f in folders if f != '']
folders = list(dict.fromkeys(folders)) # filter duplicates
folders = [f for f in folders if os.path.isdir(f)]
if shared.demo is not None:
for f in folders:
if f not in shared.demo.allowed_paths:
debug(f'Browser folders allow: {f}')
shared.demo.allowed_paths.append(quote(f))
debug(f'Browser folders: {folders}')
return JSONResponse(content=folders)
base_samples = shared.opts.outdir_samples
base_grids = shared.opts.outdir_grids
# Build list of resolved output paths with labels
folders = []
if base_samples:
folders.append(make_folder(base_samples, os.path.basename(base_samples.rstrip('/\\'))))
if base_grids and base_grids != base_samples:
folders.append(make_folder(base_grids, os.path.basename(base_grids.rstrip('/\\'))))
# Use the specific folder setting values as labels (e.g., "outputs/text" -> "outputs/text")
folders.append(make_folder(resolve_output_path(base_samples, shared.opts.outdir_txt2img_samples), shared.opts.outdir_txt2img_samples))
folders.append(make_folder(resolve_output_path(base_samples, shared.opts.outdir_img2img_samples), shared.opts.outdir_img2img_samples))
folders.append(make_folder(resolve_output_path(base_samples, shared.opts.outdir_control_samples), shared.opts.outdir_control_samples))
folders.append(make_folder(resolve_output_path(base_samples, shared.opts.outdir_extras_samples), shared.opts.outdir_extras_samples))
folders.append(make_folder(resolve_output_path(base_samples, shared.opts.outdir_save), shared.opts.outdir_save))
folders.append(make_folder(resolve_output_path(base_samples, shared.opts.outdir_video), shared.opts.outdir_video))
folders.append(make_folder(resolve_output_path(base_samples, shared.opts.outdir_init_images), shared.opts.outdir_init_images))
folders.append(make_folder(resolve_output_path(base_grids, shared.opts.outdir_txt2img_grids), shared.opts.outdir_txt2img_grids))
folders.append(make_folder(resolve_output_path(base_grids, shared.opts.outdir_img2img_grids), shared.opts.outdir_img2img_grids))
folders.append(make_folder(resolve_output_path(base_grids, shared.opts.outdir_control_grids), shared.opts.outdir_control_grids))
# Custom browser folders and reference dir
for f in shared.opts.browser_folders.split(','):
f = f.strip()
if f:
folders.append(make_folder(f))
folders.append(make_folder(reference_dir, 'Reference'))
# Filter empty and duplicates (by path)
seen_paths = set()
unique_folders = []
for f in folders:
path = f["path"].strip()
if path and path not in seen_paths and os.path.isdir(path):
seen_paths.add(path)
unique_folders.append(f)
if shared.demo is not None and path not in shared.demo.allowed_paths:
debug(f'Browser folders allow: {path}')
shared.demo.allowed_paths.append(quote(path))
debug(f'Browser folders: {unique_folders}')
return JSONResponse(content=unique_folders)
# @app.get("/sdapi/v1/browser/thumb", response_model=dict)
async def get_thumb(file: str):
+5 -4
View File
@@ -3,6 +3,7 @@ from fastapi.responses import JSONResponse
from modules import errors, shared, scripts_manager, ui
from modules.api import models, script, helpers
from modules.processing import StableDiffusionProcessingTxt2Img, StableDiffusionProcessingImg2Img, process_images
from modules.paths import resolve_output_path
errors.install()
@@ -105,8 +106,8 @@ class APIGenerate():
p = StableDiffusionProcessingTxt2Img(sd_model=shared.sd_model, **args)
self.prepare_ip_adapter(txt2imgreq, p)
p.scripts = script_runner
p.outpath_grids = shared.opts.outdir_grids or shared.opts.outdir_txt2img_grids
p.outpath_samples = shared.opts.outdir_samples or shared.opts.outdir_txt2img_samples
p.outpath_grids = resolve_output_path(shared.opts.outdir_grids, shared.opts.outdir_txt2img_grids)
p.outpath_samples = resolve_output_path(shared.opts.outdir_samples, shared.opts.outdir_txt2img_samples)
for key, value in getattr(txt2imgreq, "extra", {}).items():
setattr(p, key, value)
jobid = shared.state.begin('API-TXT', api=True)
@@ -157,8 +158,8 @@ class APIGenerate():
self.prepare_ip_adapter(img2imgreq, p)
p.init_images = [helpers.decode_base64_to_image(x) for x in init_images]
p.scripts = script_runner
p.outpath_grids = shared.opts.outdir_img2img_grids
p.outpath_samples = shared.opts.outdir_img2img_samples
p.outpath_grids = resolve_output_path(shared.opts.outdir_grids, shared.opts.outdir_img2img_grids)
p.outpath_samples = resolve_output_path(shared.opts.outdir_samples, shared.opts.outdir_img2img_samples)
for key, value in getattr(img2imgreq, "extra", {}).items():
setattr(p, key, value)
jobid = shared.state.begin('API-IMG', api=True)
+3 -3
View File
@@ -1,6 +1,6 @@
import os
import time
from typing import Any, Dict
from typing import Any
from fastapi import Request, Depends
from fastapi.exceptions import HTTPException
from fastapi.responses import FileResponse
@@ -95,11 +95,11 @@ def get_config():
del options['sd_lora']
return options
def set_config(req: Dict[str, Any]):
def set_config(req: dict[str, Any]):
updated = []
for k, v in req.items():
updated.append({ k: shared.opts.set(k, v) })
shared.opts.save(shared.config_filename)
shared.opts.save()
return { "updated": updated }
def get_cmd_flags():
+1 -1
View File
@@ -89,7 +89,7 @@ def set_ck_flash_attention(backend: str, device: torch.device):
if backend == "rocm":
if not installed('flash-attn'):
log.info('Torch attention: type="Flash attention" building...')
agent = rocm.Agent(getattr(torch.cuda.get_device_properties(device), "gcnArchName", "gfx0000"))
agent = rocm.Agent(device)
install(rocm.get_flash_attention_command(agent), reinstall=True)
else:
install('flash-attn')
+13 -2
View File
@@ -1,15 +1,26 @@
import os
import sys
import html
import threading
import time
import cProfile
from modules import shared, progress, errors, timer
queue_lock = threading.Lock()
debug = os.environ.get('SD_QUEUE_DEBUG', None) is not None
def get_lock():
if debug:
fn = f'{sys._getframe(3).f_code.co_name}:{sys._getframe(2).f_code.co_name}:{sys._getframe(1).f_code.co_name}' # pylint: disable=protected-access
errors.log.debug(f'Queue: fn={fn} lock={queue_lock.locked()}')
return queue_lock
def wrap_queued_call(func):
def f(*args, **kwargs):
with queue_lock:
with get_lock():
res = func(*args, **kwargs)
return res
return f
@@ -24,7 +35,7 @@ def wrap_gradio_gpu_call(func, extra_outputs=None, name=None):
progress.add_task_to_queue(id_task)
else:
id_task = None
with queue_lock:
with get_lock():
progress.start_task(id_task)
res = [None, '', '', '']
try:
+1 -2
View File
@@ -7,8 +7,7 @@ from installer import install, log
full_dct = False
full_html = False
base_models = ['', 'ODOR', 'SD 1.4', 'SD 1.5', 'SD 1.5 LCM', 'SD 1.5 Hyper', 'SD 2.0', 'SD 2.0 768', 'SD 2.1', 'SD 2.1 768', 'SD 2.1 Unclip', 'SDXL 0.9', 'SDXL 1.0', 'SD 3', 'SD 3.5', 'SD 3.5 Medium', 'SD 3.5 Large', 'SD 3.5 Large Turbo', 'Pony', 'Flux.1 S', 'Flux.1 D', 'Flux.1 Kontext', 'AuraFlow', 'SDXL 1.0 LCM', 'SDXL Distilled', 'SDXL Turbo', 'SDXL Lightning', 'SDXL Hyper', 'Stable Cascade', 'SVD', 'SVD XT', 'Playground v2', 'PixArt a', 'PixArt E', 'Hunyuan 1', 'Hunyuan Video', 'Lumina', 'Kolors', 'Illustrious', 'Mochi', 'LTXV', 'CogVideoX', 'NoobAI', 'Wan Video', 'Wan Video 1.3B t2v', 'Wan Video 14B t2v', 'Wan Video 14B i2v 480p', 'Wan Video 14B i2v 720p', 'HiDream', 'OpenAI', 'Imagen4', 'Other']
base_models = ['', 'AuraFlow', 'Chroma', 'CogVideoX', 'Flux.1 S', 'Flux.1 D', 'Flux.1 Krea', 'Flux.1 Kontext', 'Flux.2 D', 'HiDream', 'Hunyuan 1', 'Hunyuan Video', 'Illustrious', 'Kolors', 'LTXV', 'Lumina', 'Mochi', 'NoobAI', 'PixArt a', 'PixArt E', 'Pony', 'Pony V7', 'Qwen', 'SD 1.4', 'SD 1.5', 'SD 1.5 LCM', 'SD 1.5 Hyper', 'SD 2.0', 'SD 2.1', 'SDXL 1.0', 'SDXL Lightning', 'SDXL Hyper', 'Wan Video 1.3B t2v', 'Wan Video 14B t2v', 'Wan Video 14B i2v 480p', 'Wan Video 14B i2v 720p', 'Wan Video 2.2 TI2V-5B', 'Wan Video 2.2 I2V-A14B', 'Wan Video 2.2 T2V-A14B', 'Wan Video 2.5 T2V', 'Wan Video 2.5 I2V', 'ZImageTurbo', 'Other']
@dataclass
class ModelImage():
@@ -194,7 +194,6 @@ param_scheduler = [
dict(
# use quadratic formula to warm up 5 epochs
# and lr is updated by iteration
# TODO: fix default scope in get function
type='mmdet.QuadraticWarmupLR',
by_epoch=True,
begin=0,
@@ -12,8 +12,6 @@ from torch.nn import functional as F
def swish(x, inplace: bool = False):
"""Swish - Described originally as SiLU (https://arxiv.org/abs/1702.03118v3)
and also as Swish (https://arxiv.org/abs/1710.05941).
TODO Rename to SiLU with addition to PyTorch
"""
return x.mul_(x.sigmoid()) if inplace else x.mul(x.sigmoid())
@@ -22,8 +22,6 @@ __all__ = ['swish_jit', 'SwishJit', 'mish_jit', 'MishJit',
def swish_jit(x, inplace: bool = False):
"""Swish - Described originally as SiLU (https://arxiv.org/abs/1702.03118v3)
and also as Swish (https://arxiv.org/abs/1710.05941).
TODO Rename to SiLU with addition to PyTorch
"""
return x.mul(x.sigmoid())
@@ -36,8 +36,6 @@ class SwishJitAutoFn(torch.autograd.Function):
Swish - Described originally as SiLU (https://arxiv.org/abs/1702.03118v3)
and also as Swish (https://arxiv.org/abs/1710.05941).
TODO Rename to SiLU with addition to PyTorch
"""
@staticmethod
@@ -483,7 +483,7 @@ def _decode_block_str(block_str):
Returns:
A list of block args (dicts)
Raises:
ValueError: if the string def not properly specified (TODO)
ValueError: if the string def not properly specified
"""
assert isinstance(block_str, str)
ops = block_str.split('_')
@@ -155,7 +155,7 @@ class LinearSplitter(nn.Module):
b_prev = b_prev / b_prev.sum(dim=1, keepdim=True) # renormalize for gurantees
# print(b_prev.shape, S_normed.shape)
# if is_for_query:(1).expand(-1, b_prev.size(0)//n, -1, -1, -1, -1).flatten(0,1) # TODO ? can replace all this with a single torch.repeat?
# if is_for_query:(1).expand(-1, b_prev.size(0)//n, -1, -1, -1, -1).flatten(0,1)
b = b_prev.unsqueeze(2) * S_normed
b = b.flatten(1,2) # .shape n, prev_nbins * split_factor, h, w
@@ -395,7 +395,7 @@ def get_config(model_name, mode='train', dataset=None, **overwrite_kwargs):
overwrite_kwargs = split_combined_args(overwrite_kwargs)
config = {**config, **overwrite_kwargs}
# Casting to bool # TODO: Not necessary. Remove and test
# Casting to bool
for key in KEYS_TYPE_BOOL:
if key in config:
config[key] = bool(config[key])
+7 -6
View File
@@ -18,6 +18,7 @@ from modules.processing_class import StableDiffusionProcessingControl
from modules.ui_common import infotext_to_html
from modules.api import script
from modules.generation_parameters_copypaste import create_override_settings_dict
from modules.paths import resolve_output_path
debug = os.environ.get('SD_CONTROL_DEBUG', None) is not None
@@ -402,8 +403,8 @@ def control_run(state: str = '', # pylint: disable=keyword-arg-before-vararg
hdr_mode=hdr_mode, hdr_brightness=hdr_brightness, hdr_color=hdr_color, hdr_sharpen=hdr_sharpen, hdr_clamp=hdr_clamp,
hdr_boundary=hdr_boundary, hdr_threshold=hdr_threshold, hdr_maximize=hdr_maximize, hdr_max_center=hdr_max_center, hdr_max_boundary=hdr_max_boundary, hdr_color_picker=hdr_color_picker, hdr_tint_ratio=hdr_tint_ratio,
# path
outpath_samples=shared.opts.outdir_samples or shared.opts.outdir_control_samples,
outpath_grids=shared.opts.outdir_grids or shared.opts.outdir_control_grids,
outpath_samples=resolve_output_path(shared.opts.outdir_samples, shared.opts.outdir_control_samples),
outpath_grids=resolve_output_path(shared.opts.outdir_grids, shared.opts.outdir_control_grids),
# overrides
override_settings=extra
)
@@ -572,13 +573,13 @@ def control_run(state: str = '', # pylint: disable=keyword-arg-before-vararg
# what are we doing?
if 'control' in p.ops:
p.outpath_samples = shared.opts.outdir_samples or shared.opts.outdir_control_samples
p.outpath_samples = resolve_output_path(shared.opts.outdir_samples, shared.opts.outdir_control_samples)
elif 'img2img' in p.ops:
p.outpath_samples = shared.opts.outdir_samples or shared.opts.outdir_img2img_samples
p.outpath_samples = resolve_output_path(shared.opts.outdir_samples, shared.opts.outdir_img2img_samples)
elif 'txt2img' in p.ops:
p.outpath_samples = shared.opts.outdir_samples or shared.opts.outdir_txt2img_samples
p.outpath_samples = resolve_output_path(shared.opts.outdir_samples, shared.opts.outdir_txt2img_samples)
else: # fallback to txt2img
p.outpath_samples = shared.opts.outdir_samples or shared.opts.outdir_txt2img_samples
p.outpath_samples = resolve_output_path(shared.opts.outdir_samples, shared.opts.outdir_txt2img_samples)
# pipeline
output = None
+3 -3
View File
@@ -181,7 +181,7 @@ def api_list_models(model_type: str = None):
model_list += list(predefined_qwen)
if model_type == 'hunyuandit' or model_type == 'all':
model_list += list(predefined_hunyuandit)
if model_type == 'z_image':
if model_type == 'zimage':
model_list += list(predefined_zimage)
model_list += sorted(find_models())
return model_list
@@ -207,7 +207,7 @@ def list_models(refresh=False):
models = ['None'] + list(predefined_qwen) + sorted(find_models())
elif modules.shared.sd_model_type == 'hunyuandit':
models = ['None'] + list(predefined_hunyuandit) + sorted(find_models())
elif modules.shared.sd_model_type == 'z_image':
elif modules.shared.sd_model_type == 'zimage':
models = ['None'] + list(predefined_zimage) + sorted(find_models())
else:
log.warning(f'Control {what} model list failed: unknown model type')
@@ -273,7 +273,7 @@ class ControlNet():
elif shared.sd_model_type == 'hunyuandit':
from diffusers import HunyuanDiT2DControlNetModel as cls
config = 'Tencent-Hunyuan/HunyuanDiT-v1.2-ControlNet-Diffusers-Canny'
elif shared.sd_model_type == 'z_image':
elif shared.sd_model_type == 'zimage':
from diffusers import ZImageControlNetModel as cls
if '2.0' in model_id:
config = 'hlky/Z-Image-Turbo-Fun-Controlnet-Union-2.0'
+11 -6
View File
@@ -67,6 +67,10 @@ def has_triton(early:bool=False) -> bool:
return test_triton(early=early)
def get_hip_agent() -> rocm.Agent:
return rocm.Agent(device)
def get_backend(shared_cmd_opts):
global args # pylint: disable=global-statement
args = shared_cmd_opts
@@ -91,7 +95,6 @@ def get_backend(shared_cmd_opts):
def get_gpu_info():
def get_driver():
import subprocess
if torch.xpu.is_available():
try:
return torch.xpu.get_device_properties(torch.xpu.current_device()).driver_version
@@ -99,6 +102,7 @@ def get_gpu_info():
return ''
elif torch.cuda.is_available() and torch.version.cuda:
try:
import subprocess
result = subprocess.run('nvidia-smi --query-gpu=driver_version --format=csv,noheader', shell=True, check=False, env=os.environ, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
version = result.stdout.decode(encoding="utf8", errors="ignore").strip()
return version
@@ -110,7 +114,7 @@ def get_gpu_info():
def get_package_version(pkg: str):
import pkg_resources
spec = pkg_resources.working_set.by_key.get(pkg, None) # more reliable than importlib
version = pkg_resources.get_distribution(pkg).version if spec is not None else ''
version = pkg_resources.get_distribution(pkg).version if spec is not None else None
return version
if not torch.cuda.is_available():
@@ -324,9 +328,9 @@ def test_fp16():
elif backend == 'rocm':
# gfx1102 (RX 7600, 7500, 7650 and 7700S) causes segfaults with fp16
# agent can be overriden to gfx1100 to get gfx1102 working with ROCm so check the gpu name as well
agent = getattr(torch.cuda.get_device_properties(device), "gcnArchName", "gfx0000")
agent = get_hip_agent()
agent_name = getattr(torch.cuda.get_device_properties(device), "name", "AMD Radeon RX 0000")
if agent == "gfx1102" or (agent == "gfx1100" and any(i in agent_name for i in ("7600", "7500", "7650", "7700S"))):
if agent.gfx_version == 0x1102 or (agent.gfx_version == 0x1100 and any(i in agent_name for i in ("7600", "7500", "7650", "7700S"))):
fp16_ok = False
return fp16_ok
try:
@@ -355,7 +359,7 @@ def test_bf16():
elif backend == 'rocm' or backend == 'zluda':
agent = None
if backend == 'rocm':
agent = rocm.Agent(getattr(torch.cuda.get_device_properties(device), "gcnArchName", "gfx0000"))
agent = get_hip_agent()
else:
from modules.zluda_installer import default_agent
agent = default_agent
@@ -396,7 +400,8 @@ def test_triton(early: bool = False):
triton_ok = False
except Exception as e:
triton_ok = False
log.warning(f"Triton test fail: {e}")
line = str(e).splitlines()[0]
log.warning(f"Triton test fail: {line}")
if debug:
from modules import errors
errors.display(e, 'Triton')
+32 -4
View File
@@ -1,6 +1,6 @@
from __future__ import annotations
import os
from datetime import datetime
from datetime import datetime, timezone
import git
from modules import shared, errors
from modules.paths import extensions_dir, extensions_builtin_dir
@@ -11,6 +11,34 @@ if not os.path.exists(extensions_dir):
os.makedirs(extensions_dir)
def parse_isotime(time_string: str) -> datetime:
# If Python minimum version is 3.11+, this function can be replaced with datetime.fromisoformat()
trimmed = time_string.rstrip("Z")
if "." in trimmed:
trimmed = trimmed.split(".")[0]
match len(trimmed):
case 16:
return datetime.strptime(trimmed, "%Y-%m-%dT%H:%M").replace(tzinfo=timezone.utc)
case 19:
return datetime.strptime(trimmed, "%Y-%m-%dT%H:%M:%S").replace(tzinfo=timezone.utc)
case _:
raise ValueError(f"Unexpected time string format: '{time_string}'")
def format_dt(d: datetime, seconds = False) -> str:
if d.tzinfo is None:
return d.strftime('%Y-%m-%d %H:%M')
if seconds:
return d.astimezone(timezone.utc).strftime('%Y-%m-%d %H:%M:%S')
return d.astimezone(timezone.utc).strftime('%Y-%m-%d %H:%M')
def ts2utc(timestamp: int) -> datetime:
try:
return datetime.fromtimestamp(timestamp, timezone.utc)
except Exception:
return "unknown"
def active():
if shared.opts.disable_all_extensions == "all":
return []
@@ -106,8 +134,8 @@ class Extension:
self.branch = None
self.remote = None
self.have_info_from_repo = False
self.mtime = 0
self.ctime = 0
self.mtime = "2000-01-01T00:00Z"
self.ctime = "2000-01-01T00:00Z"
def read_info(self, force=False):
if self.have_info_from_repo and not force:
@@ -142,7 +170,7 @@ class Extension:
except Exception:
self.branch = 'unknown'
self.commit_hash = head.hexsha
self.version = f"<p>{self.commit_hash[:8]}</p><p>{datetime.fromtimestamp(self.commit_date).strftime('%a %b%d %Y %H:%M')}</p>"
self.version = f"<p>{self.commit_hash[:8]}</p><p>{format_dt(ts2utc(self.commit_date))}</p>"
except Exception as ex:
shared.log.error(f"Extension: failed reading data from git repo={self.name}: {ex}")
self.remote = None
-1
View File
@@ -108,7 +108,6 @@ def activate(p, extra_network_data=None, step=0, include=[], exclude=[]):
if args is not None:
continue
try:
# extra_network.activate(p, [])
signature = list(inspect.signature(extra_network.activate).parameters)
if 'include' in signature and 'exclude' in signature:
extra_network.activate(p, [], include=include, exclude=exclude)
+1 -1
View File
@@ -882,7 +882,7 @@ class StableDiffusionXLInstantIDPipeline(StableDiffusionXLControlNetPipeline):
guidance_scale_tensor, embedding_dim=self.unet.config.time_cond_proj_dim
).to(device=device, dtype=latents.dtype)
# 7. Prepare extra step kwargs. TODO: Logic should ideally just be moved out of the pipeline
# 7. Prepare extra step kwargs.
extra_step_kwargs = self.prepare_extra_step_kwargs(generator, eta)
# 7.1 Create tensor stating which controlnets to keep
+1 -1
View File
@@ -679,7 +679,7 @@ class PhotoMakerStableDiffusionXLPipeline(StableDiffusionXLPipeline):
latents,
)
# 9. Prepare extra step kwargs. TODO: Logic should ideally just be moved out of the pipeline
# 9. Prepare extra step kwargs.
extra_step_kwargs = self.prepare_extra_step_kwargs(generator, eta)
# 10. Prepare added time ids & embeddings
@@ -181,7 +181,6 @@ def match(threshold, truths, priors, variances, labels, landms, loc_t, conf_t, l
best_prior_idx_filter.squeeze_(1)
best_prior_overlap.squeeze_(1)
best_truth_overlap.index_fill_(0, best_prior_idx_filter, 2) # ensure best prior
# TODO refactor: index best_prior_idx with long tensor
# ensure every gt matches with its prior of max overlap
for j in range(best_prior_idx.size(0)): # 判别此anchor是预测哪一个boxes
best_truth_idx[best_prior_idx[j]] = j
+1 -2
View File
@@ -99,7 +99,7 @@ def align_crop_face_landmarks(img,
# - np.flipud(eye_to_mouth) * [-1, 1]: rotate 90 clockwise
# norm with the hypotenuse: get the direction
x /= np.hypot(*x) # get the hypotenuse of a right triangle
rect_scale = 1 # TODO: you can edit it to get larger rect
rect_scale = 1
x *= max(np.hypot(*eye_to_eye) * 2.0 * rect_scale, np.hypot(*eye_to_mouth) * 1.8 * rect_scale)
# y: half height of the oriented crop rectangle
y = np.flipud(x) * [-1, 1]
@@ -116,7 +116,6 @@ def align_crop_face_landmarks(img,
quad_ori = np.copy(quad)
# Shrink, for large face
# TODO: do we really need shrink
shrink = int(np.floor(qsize / output_size * 0.5))
if shrink > 1:
h, w = img.shape[0:2]
+1 -3
View File
@@ -52,7 +52,6 @@ def _attn_fwd_inner(acc, l_i, m_i, q, k_ptrs, v_ptrs, bias_ptrs, stride_kn, stri
qk = tl.zeros([BLOCK_M, BLOCK_N], dtype=ACCUMULATOR_TYPE)
# We start from end of seqlen_k so only the first iteration would need
# to be checked for padding if it is not a multiple of block_n
# TODO: This can be optimized to only be true for the padded block.
if MASK_STEPS:
# If this is the last block / iteration, we want to
# mask if the sequence length is not a multiple of block size
@@ -105,7 +104,7 @@ def _attn_fwd_inner(acc, l_i, m_i, q, k_ptrs, v_ptrs, bias_ptrs, stride_kn, stri
# CAVEAT: Must update l_ij before applying dropout
l_ij = tl.sum(p, 1)
if ENABLE_DROPOUT:
rng_output = tl.rand(philox_seed, philox_ptrs) # TODO: use tl.randint for better performance
rng_output = tl.rand(philox_seed, philox_ptrs)
dropout_mask = rng_output > dropout_p
# return scores with negative values for dropped vals
@@ -304,7 +303,6 @@ def attn_fwd(Q, K, V, bias, Cache_seqlens, Cache_batch_idx, # pylint: disable=un
# softmax_lse = tl.where(lse_mask, 0.0, softmax_lse)
l_ptrs_mask = offs_m < MAX_SEQLENS_Q
tl.store(l_ptrs, l, mask=l_ptrs_mask)
# TODO: Should dropout and return encoded softmax be handled here too?
return
# If MQA / GQA, set the K and V head offsets appropriately.
-3
View File
@@ -116,7 +116,6 @@ class MetaData():
assert self.cu_seqlens_q is not None
assert self.cu_seqlens_k is not None
assert len(self.cu_seqlens_q) == len(self.cu_seqlens_k)
# TODO: Remove once bias is supported with varlen
assert self.bias is None
# assert not self.return_scores
else:
@@ -125,7 +124,6 @@ class MetaData():
assert self.cu_seqlens_q is None and self.cu_seqlens_k is None
assert k.shape == v.shape
assert q.shape[-1] == k.shape[-1] and q.shape[-1] == v.shape[-1]
# TODO: Change assert if we support qkl f8 and v f16
assert q.dtype == k.dtype and q.dtype == v.dtype
assert o.shape == q.shape
assert (nheads_q % nheads_k) == 0
@@ -243,7 +241,6 @@ def input_helper(
equal_seqlens=False
# gen tensors
# TODO: the gen functions should maybe have different gen modes like random, ones, increasing seqlen
q, cu_seqlens_q, max_seqlen_q = generate_varlen_tensor(TOTAL_SEQLENS_Q, HQ, D_HEAD, batch_size=BATCH, dtype=dtype, device=device, equal_seqlens=equal_seqlens, DEBUG_INPUT=DEBUG_INPUT)
k, cu_seqlens_k, max_seqlen_k = generate_varlen_tensor(TOTAL_SEQLENS_K, HK, D_HEAD, batch_size=BATCH, dtype=dtype, device=device, equal_seqlens=equal_seqlens, DEBUG_INPUT=DEBUG_INPUT)
v, _, _ = generate_varlen_tensor(TOTAL_SEQLENS_K, HK, D_HEAD, batch_size=BATCH, dtype=dtype, device=device, equal_seqlens=equal_seqlens, DEBUG_INPUT=DEBUG_INPUT)
+2 -4
View File
@@ -1,12 +1,11 @@
import os
import re
import random
import threading
import numpy as np
import torch
import gradio as gr
from PIL import Image
from modules import shared, processing, timer, paths, extra_networks, progress, ui_video_vlm
from modules import shared, processing, timer, paths, extra_networks, progress, ui_video_vlm, call_queue
from modules.video_models.video_utils import check_av
from modules.framepack import framepack_install # pylint: disable=wrong-import-order
from modules.framepack import framepack_load # pylint: disable=wrong-import-order
@@ -18,7 +17,6 @@ tmp_dir = os.path.join(paths.data_path, 'tmp', 'framepack')
git_dir = os.path.join(os.path.dirname(__file__), 'framepack')
git_repo = 'https://github.com/lllyasviel/framepack'
git_commit = 'c5d375661a2557383f0b8da9d11d14c23b0c4eaf'
queue_lock = threading.Lock()
loaded_variant = None
@@ -131,7 +129,7 @@ def run_framepack(task_id, _ui_state, init_image, end_image, start_weight, end_w
return
progress.add_task_to_queue(task_id)
with queue_lock:
with call_queue.get_lock():
progress.start_task(task_id)
yield from load_model(variant, attention)
+28 -19
View File
@@ -1,3 +1,4 @@
from __future__ import annotations
import base64
import io
import os
@@ -8,9 +9,9 @@ from modules.infotext import parse, mapping, quote, unquote # pylint: disable=un
type_of_gr_update = type(gr.update())
paste_fields = {}
paste_fields: dict[str, dict] = {}
field_names = {}
registered_param_bindings = []
registered_param_bindings: list[ParamBinding] = []
debug = shared.log.trace if os.environ.get('SD_PASTE_DEBUG', None) is not None else lambda *args, **kwargs: None
debug('Trace: PASTE')
parse_generation_parameters = parse # compatibility
@@ -18,7 +19,7 @@ infotext_to_setting_name_mapping = mapping # compatibility
class ParamBinding:
def __init__(self, paste_button, tabname, source_text_component=None, source_image_component=None, source_tabname=None, override_settings_component=None, paste_field_names=None):
def __init__(self, paste_button, tabname: str, source_text_component=None, source_image_component=None, source_tabname=None, override_settings_component=None, paste_field_names=None):
self.paste_button = paste_button
self.tabname = tabname
self.source_text_component = source_text_component
@@ -60,7 +61,7 @@ def image_from_url_text(filedata):
if len(filedata) == 0:
return None
filedata = filedata[0]
if type(filedata) == dict:
if not isinstance(filedata, str):
shared.log.warning('Incorrect filedata received')
return None
if filedata.startswith("data:image/png;base64,"):
@@ -71,13 +72,13 @@ def image_from_url_text(filedata):
filedata = filedata[len("data:image/jpeg;base64,"):]
if filedata.startswith("data:image/jxl;base64,"):
filedata = filedata[len("data:image/jxl;base64,"):]
filedata = base64.decodebytes(filedata.encode('utf-8'))
image = Image.open(io.BytesIO(filedata))
filebytes = base64.decodebytes(filedata.encode('utf-8'))
image = Image.open(io.BytesIO(filebytes))
images.read_info_from_image(image)
return image
def add_paste_fields(tabname, init_img, fields, override_settings_component=None):
def add_paste_fields(tabname: str, init_img: gr.Image | gr.HTML | None, fields: list[tuple[gr.components.Component, str]] | None, override_settings_component=None):
paste_fields[tabname] = {"init_img": init_img, "fields": fields, "override_settings_component": override_settings_component}
try:
field_names[tabname] = [f[1] for f in fields if f[1] is not None and not callable(f[1])] if fields is not None else [] # tuple (component, label)
@@ -108,7 +109,7 @@ def get_all_fields():
return all_fields
def create_buttons(tabs_list):
def create_buttons(tabs_list: list[str]) -> dict[str, gr.Button]:
buttons = {}
for tab in tabs_list:
name = tab
@@ -128,7 +129,7 @@ def create_buttons(tabs_list):
return buttons
def should_skip(param):
def should_skip(param: str):
skip_params = [p.strip().lower() for p in shared.opts.disable_apply_params.split(",")]
if not shared.opts.clip_skip_enabled:
skip_params += ['clip skip']
@@ -149,18 +150,26 @@ def connect_paste_params_buttons():
if binding.tabname not in paste_fields:
debug(f"Not not registered: tab={binding.tabname}")
continue
fields = paste_fields[binding.tabname]["fields"]
fields: list[tuple[gr.components.Component, str]] = paste_fields[binding.tabname]["fields"]
destination_image_component = paste_fields[binding.tabname]["init_img"]
if binding.source_image_component and destination_image_component:
binding.paste_button.click(
_js="extract_image_from_gallery" if isinstance(binding.source_image_component, gr.Gallery) else None,
fn=send_image,
inputs=[binding.source_image_component],
outputs=[destination_image_component],
show_progress='hidden',
)
if binding.source_image_component:
if isinstance(destination_image_component, gr.Image):
binding.paste_button.click(
_js="extract_image_from_gallery" if isinstance(binding.source_image_component, gr.Gallery) else None,
fn=send_image,
inputs=[binding.source_image_component],
outputs=[destination_image_component],
show_progress='hidden',
)
elif isinstance(destination_image_component, gr.HTML): # kanvas
binding.paste_button.click(
_js="send_to_kanvas",
fn=None,
inputs=[binding.source_image_component],
outputs=[],
show_progress='hidden',
)
override_settings_component = binding.override_settings_component or paste_fields[binding.tabname]["override_settings_component"]
if binding.source_text_component is not None and fields is not None:
connect_paste(binding.paste_button, fields, binding.source_text_component, override_settings_component, binding.tabname)
+26 -13
View File
@@ -19,19 +19,32 @@ def check_tmp_file(gradio, filename):
ok = False
if hasattr(gradio, 'temp_file_sets'):
ok = ok or any(filename in fileset for fileset in gradio.temp_file_sets)
if shared.opts.outdir_samples != '':
ok = ok or Path(shared.opts.outdir_samples).resolve() in Path(filename).resolve().parents
else:
ok = ok or Path(shared.opts.outdir_txt2img_samples).resolve() in Path(filename).resolve().parents
ok = ok or Path(shared.opts.outdir_img2img_samples).resolve() in Path(filename).resolve().parents
ok = ok or Path(shared.opts.outdir_extras_samples).resolve() in Path(filename).resolve().parents
if shared.opts.outdir_grids != '':
ok = ok or Path(shared.opts.outdir_grids).resolve() in Path(filename).resolve().parents
else:
ok = ok or Path(shared.opts.outdir_txt2img_grids).resolve() in Path(filename).resolve().parents
ok = ok or Path(shared.opts.outdir_img2img_grids).resolve() in Path(filename).resolve().parents
ok = ok or Path(shared.opts.outdir_save).resolve() in Path(filename).resolve().parents
ok = ok or Path(shared.opts.outdir_init_images).resolve() in Path(filename).resolve().parents
# Check resolved output paths (base + specific)
base_samples = shared.opts.outdir_samples
base_grids = shared.opts.outdir_grids
resolved_paths = [
paths.resolve_output_path(base_samples, shared.opts.outdir_txt2img_samples),
paths.resolve_output_path(base_samples, shared.opts.outdir_img2img_samples),
paths.resolve_output_path(base_samples, shared.opts.outdir_extras_samples),
paths.resolve_output_path(base_samples, shared.opts.outdir_control_samples),
paths.resolve_output_path(base_samples, shared.opts.outdir_save),
paths.resolve_output_path(base_samples, shared.opts.outdir_video),
paths.resolve_output_path(base_samples, shared.opts.outdir_init_images),
paths.resolve_output_path(base_grids, shared.opts.outdir_txt2img_grids),
paths.resolve_output_path(base_grids, shared.opts.outdir_img2img_grids),
paths.resolve_output_path(base_grids, shared.opts.outdir_control_grids),
]
# Also check base folders directly if set
if base_samples:
resolved_paths.append(base_samples)
if base_grids:
resolved_paths.append(base_grids)
for path in resolved_paths:
if path:
try:
ok = ok or Path(path).resolve() in Path(filename).resolve().parents
except Exception:
pass
return ok
+10 -7
View File
@@ -1,9 +1,11 @@
import hashlib
import os.path
from rich import progress, errors
from modules import shared
from installer import log, console
from modules.json_helpers import readfile, writefile
from modules.paths import data_path
cache_filename = os.path.join(data_path, "cache.json")
cache_data = None
progress_ok = True
@@ -12,17 +14,17 @@ progress_ok = True
def init_cache():
global cache_data # pylint: disable=global-statement
if cache_data is None:
cache_data = {} if not os.path.isfile(cache_filename) else shared.readfile(cache_filename, lock=True, as_type="dict")
cache_data = {} if not os.path.isfile(cache_filename) else readfile(cache_filename, lock=True, as_type="dict")
def dump_cache():
shared.writefile(cache_data, cache_filename)
writefile(cache_data, cache_filename)
def cache(subsection):
global cache_data # pylint: disable=global-statement
if cache_data is None:
cache_data = {} if not os.path.isfile(cache_filename) else shared.readfile(cache_filename, lock=True, as_type="dict")
cache_data = {} if not os.path.isfile(cache_filename) else readfile(cache_filename, lock=True, as_type="dict")
s = cache_data.get(subsection, {})
cache_data[subsection] = s
return s
@@ -35,11 +37,11 @@ def calculate_sha256(filename, quiet=False):
if not quiet:
if progress_ok:
try:
with progress.open(filename, 'rb', description=f'[cyan]Calculating hash: [yellow]{filename}', auto_refresh=True, console=shared.console) as f:
with progress.open(filename, 'rb', description=f'[cyan]Calculating hash: [yellow]{filename}', auto_refresh=True, console=console) as f:
for chunk in iter(lambda: f.read(blksize), b""):
hash_sha256.update(chunk)
except errors.LiveError:
shared.log.warning('Hash: attempting to use function in a thread')
log.warning('Hash: attempting to use function in a thread')
progress_ok = False
if not progress_ok:
with open(filename, 'rb') as f:
@@ -65,6 +67,7 @@ def sha256_from_cache(filename, title, use_addnet_hash=False):
def sha256(filename, title, use_addnet_hash=False):
from modules import shared
global progress_ok # pylint: disable=global-statement
hashes = cache("hashes-addnet") if use_addnet_hash else cache("hashes")
sha256_value = sha256_from_cache(filename, title, use_addnet_hash)
@@ -81,7 +84,7 @@ def sha256(filename, title, use_addnet_hash=False):
with progress.open(filename, 'rb', description=f'[cyan]Calculating hash: [yellow]{filename}', auto_refresh=True, console=shared.console) as f:
sha256_value = addnet_hash_safetensors(f)
except errors.LiveError:
shared.log.warning('Hash: attempting to use function in a thread')
log.warning('Hash: attempting to use function in a thread')
progress_ok = False
if not progress_ok:
with open(filename, 'rb') as f:
+3 -1
View File
@@ -10,6 +10,7 @@ def apply(p, model_type):
shared.log.warning(f'HiDiffusion: class={shared.sd_model.__class__.__name__} not supported')
return
unapply()
pipe = shared.sd_model.pipe if hasattr(shared.sd_model, 'pipe') else shared.sd_model
if getattr(p, 'hidiffusion', False) is True:
t0 = time.time()
hidiffusion.is_aggressive_raunet = shared.opts.hidiffusion_steps > 0
@@ -30,11 +31,12 @@ def apply(p, model_type):
hidiffusion.switching_threshold_ratio_dict['sdxl_4096']['T2_ratio'] = t2
hidiffusion.switching_threshold_ratio_dict['sdxl_turbo_1024']['T2_ratio'] = t2
p.extra_generation_params['HiDiffusion Ratios'] = f'{shared.opts.hidiffusion_t1}/{shared.opts.hidiffusion_t2}'
pipe = shared.sd_model.pipe if hasattr(shared.sd_model, 'pipe') else shared.sd_model
hidiffusion.apply_hidiffusion(pipe, apply_raunet=shared.opts.hidiffusion_raunet, apply_window_attn=shared.opts.hidiffusion_attn, model_type=model_type, steps=p.steps)
p.extra_generation_params['HiDiffusion'] = f'{shared.opts.hidiffusion_raunet}/{shared.opts.hidiffusion_attn}/{shared.opts.hidiffusion_steps > 0}:{shared.opts.hidiffusion_steps}'
t1 = time.time()
shared.log.debug(f'Applying HiDiffusion: raunet={shared.opts.hidiffusion_raunet} attn={shared.opts.hidiffusion_attn} aggressive={shared.opts.hidiffusion_steps > 0}:{shared.opts.hidiffusion_steps} t1={shared.opts.hidiffusion_t1} t2={shared.opts.hidiffusion_t2} time={t1-t0:.2f} type={shared.sd_model_type} width={p.width} height={p.height}')
elif hasattr(pipe, 'unet') and getattr(pipe.unet, 'hidiffusion', False):
shared.log.warning('HiDiffusion: model reload recomended')
def unapply():
+44 -48
View File
@@ -2,7 +2,6 @@ from typing import Type, Dict, Any, Tuple, Optional
import math
import torch
import torch.nn.functional as F
from diffusers.utils.torch_utils import is_torch_version
from diffusers.pipelines import auto_pipeline
@@ -85,7 +84,6 @@ def make_diffusers_transformer_block(block_class: Type[torch.nn.Module]) -> Type
class transformer_block(block_class):
# Save for unpatching later
_parent = block_class
_forward = block_class.forward
def forward(
self,
@@ -98,7 +96,6 @@ def make_diffusers_transformer_block(block_class: Type[torch.nn.Module]) -> Type
class_labels: Optional[torch.LongTensor] = None,
added_cond_kwargs: Optional[Dict[str, torch.Tensor]] = None,
) -> torch.FloatTensor:
# reference: https://github.com/microsoft/Swin-Transformer
def window_partition(x, window_size, shift_size, H, W):
B, _N, C = x.shape
@@ -158,7 +155,11 @@ def make_diffusers_transformer_block(block_class: Type[torch.nn.Module]) -> Type
# MSW-MSA
rand_num = torch.rand(1)
_B, N, _C = hidden_states.shape
ori_H, ori_W = self.info['size']
try:
ori_H, ori_W = self.info['size']
except Exception as e:
raise RuntimeError(f'HiDiffusion: cls={self.__class__.__name__} info={hasattr(self, "info")} parent={hasattr(self, "_parent")} orphaned call') from e
downsample_ratio = round(((ori_H*ori_W) / N)**0.5)
H, W = (math.ceil(ori_H/downsample_ratio), math.ceil(ori_W/downsample_ratio))
widow_size = (math.ceil(H/2), math.ceil(W/2))
@@ -249,7 +250,6 @@ def make_diffusers_transformer_block(block_class: Type[torch.nn.Module]) -> Type
hidden_states = hidden_states.squeeze(1)
return hidden_states
_patched_forward = forward
return transformer_block
@@ -257,7 +257,6 @@ def make_diffusers_cross_attn_down_block(block_class: Type[torch.nn.Module]) ->
# replace conventional downsampler with resolution-aware downsampler
class cross_attn_down_block(block_class):
_parent = block_class # Save for unpatching later
_forward = block_class.forward
timestep = 0
aggressive_raunet = False
T1_ratio = 0
@@ -280,7 +279,10 @@ def make_diffusers_cross_attn_down_block(block_class: Type[torch.nn.Module]) ->
self.info['pipeline']._num_timesteps = self.max_timestep # pylint: disable=protected-access
self.max_timestep = self.info['pipeline']._num_timesteps # pylint: disable=protected-access
# self.max_timestep = len(self.info['scheduler'].timesteps)
ori_H, ori_W = self.info['size']
try:
ori_H, ori_W = self.info['size']
except Exception as e:
raise RuntimeError(f'HiDiffusion: cls={self.__class__.__name__} info={hasattr(self, "info")} parent={hasattr(self, "_parent")} orphaned call') from e
if self.model == 'sd15':
if ori_H < 256 or ori_W < 256:
self.T1_ratio = switching_threshold_ratio_dict['sd15_1024'][self.switching_threshold_ratio]
@@ -294,8 +296,6 @@ def make_diffusers_cross_attn_down_block(block_class: Type[torch.nn.Module]) ->
self.T1_ratio = switching_threshold_ratio_dict['sdxl_2048'][self.switching_threshold_ratio]
if self.info['is_inpainting_task']:
self.aggressive_raunet = inpainting_is_aggressive_raunet
elif self.info['is_playground']:
self.aggressive_raunet = playground_is_aggressive_raunet
else:
self.aggressive_raunet = is_aggressive_raunet
else:
@@ -329,7 +329,7 @@ def make_diffusers_cross_attn_down_block(block_class: Type[torch.nn.Module]) ->
return custom_forward
ckpt_kwargs: Dict[str, Any] = {"use_reentrant": False} if is_torch_version(">=", "1.11.0") else {}
ckpt_kwargs: Dict[str, Any] = {"use_reentrant": False}
hidden_states = torch.utils.checkpoint.checkpoint(
create_custom_forward(resnet),
hidden_states,
@@ -382,7 +382,6 @@ def make_diffusers_cross_attn_down_block(block_class: Type[torch.nn.Module]) ->
return hidden_states, output_states
_patched_forward = forward
return cross_attn_down_block
@@ -391,7 +390,6 @@ def make_diffusers_cross_attn_up_block(block_class: Type[torch.nn.Module]) -> Ty
class cross_attn_up_block(block_class):
# Save for unpatching later
_parent = block_class
_forward = block_class.forward
timestep = 0
aggressive_raunet = False
T1_ratio = 0
@@ -411,7 +409,6 @@ def make_diffusers_cross_attn_up_block(block_class: Type[torch.nn.Module]) -> Ty
attention_mask: Optional[torch.FloatTensor] = None,
encoder_attention_mask: Optional[torch.FloatTensor] = None,
) -> torch.FloatTensor:
def fix_scale(first, second):
if (first.shape[-1] != second.shape[-1] or first.shape[-2] != second.shape[-2]):
rescale = min(second.shape[-2] / first.shape[-2], second.shape[-1] / first.shape[-1])
@@ -420,7 +417,10 @@ def make_diffusers_cross_attn_up_block(block_class: Type[torch.nn.Module]) -> Ty
return first
self.max_timestep = self.info['pipeline']._num_timesteps # pylint: disable=protected-access
ori_H, ori_W = self.info['size']
try:
ori_H, ori_W = self.info['size']
except Exception as e:
raise RuntimeError(f'HiDiffusion: cls={self.__class__.__name__} info={hasattr(self, "info")} parent={hasattr(self, "_parent")} orphaned call') from e
if self.model == 'sd15':
if ori_H < 256 or ori_W < 256:
self.T1_ratio = switching_threshold_ratio_dict['sd15_1024'][self.switching_threshold_ratio]
@@ -435,8 +435,6 @@ def make_diffusers_cross_attn_up_block(block_class: Type[torch.nn.Module]) -> Ty
if self.info['is_inpainting_task']:
self.aggressive_raunet = inpainting_is_aggressive_raunet
elif self.info['is_playground']:
self.aggressive_raunet = playground_is_aggressive_raunet
else:
self.aggressive_raunet = is_aggressive_raunet
@@ -483,7 +481,6 @@ def make_diffusers_cross_attn_up_block(block_class: Type[torch.nn.Module]) -> Ty
self.timestep = 0
return hidden_states
_patched_forward = forward
return cross_attn_up_block
@@ -492,7 +489,6 @@ def make_diffusers_downsampler_block(block_class: Type[torch.nn.Module]) -> Type
class downsampler_block(block_class):
# Save for unpatching later
_parent = block_class
_forward = block_class.forward
T1_ratio = 0
T1 = 0
timestep = 0
@@ -502,7 +498,10 @@ def make_diffusers_downsampler_block(block_class: Type[torch.nn.Module]) -> Type
def forward(self, hidden_states: torch.Tensor, scale = 1.0) -> torch.Tensor: # pylint: disable=unused-argument
self.max_timestep = self.info['pipeline']._num_timesteps # pylint: disable=protected-access
# self.max_timestep = len(self.info['scheduler'].timesteps)
ori_H, ori_W = self.info['size']
try:
ori_H, ori_W = self.info['size']
except Exception as e:
raise RuntimeError(f'HiDiffusion: cls={self.__class__.__name__} info={hasattr(self, "info")} parent={hasattr(self, "_parent")} orphaned call') from e
if self.model == 'sd15':
if ori_H < 256 or ori_W < 256:
self.T1_ratio = switching_threshold_ratio_dict['sd15_1024'][self.switching_threshold_ratio]
@@ -516,8 +515,6 @@ def make_diffusers_downsampler_block(block_class: Type[torch.nn.Module]) -> Type
self.T1_ratio = switching_threshold_ratio_dict['sdxl_2048'][self.switching_threshold_ratio]
if self.info['is_inpainting_task']:
self.aggressive_raunet = inpainting_is_aggressive_raunet
elif self.info['is_playground']:
self.aggressive_raunet = playground_is_aggressive_raunet
else:
self.aggressive_raunet = is_aggressive_raunet
else:
@@ -551,7 +548,6 @@ def make_diffusers_downsampler_block(block_class: Type[torch.nn.Module]) -> Type
self.timestep = 0
return hidden_states
_patched_forward = forward
return downsampler_block
@@ -560,7 +556,6 @@ def make_diffusers_upsampler_block(block_class: Type[torch.nn.Module]) -> Type[t
class upsampler_block(block_class):
# Save for unpatching later
_parent = block_class
_forward = block_class.forward
T1_ratio = 0
T1 = 0
timestep = 0
@@ -570,7 +565,10 @@ def make_diffusers_upsampler_block(block_class: Type[torch.nn.Module]) -> Type[t
def forward(self, hidden_states: torch.Tensor, scale = 1.0) -> torch.Tensor: # pylint: disable=unused-argument
self.max_timestep = self.info['pipeline']._num_timesteps # pylint: disable=protected-access
# self.max_timestep = len(self.info['scheduler'].timesteps)
ori_H, ori_W = self.info['size']
try:
ori_H, ori_W = self.info['size']
except Exception as e:
raise RuntimeError(f'HiDiffusion: cls={self.__class__.__name__} info={hasattr(self, "info")} parent={hasattr(self, "_parent")} orphaned call') from e
if self.model == 'sd15':
if ori_H < 256 or ori_W < 256:
self.T1_ratio = switching_threshold_ratio_dict['sd15_1024'][self.switching_threshold_ratio]
@@ -585,8 +583,6 @@ def make_diffusers_upsampler_block(block_class: Type[torch.nn.Module]) -> Type[t
if self.info['is_inpainting_task']:
self.aggressive_raunet = inpainting_is_aggressive_raunet
elif self.info['is_playground']:
self.aggressive_raunet = playground_is_aggressive_raunet
else:
self.aggressive_raunet = is_aggressive_raunet
else:
@@ -606,7 +602,6 @@ def make_diffusers_upsampler_block(block_class: Type[torch.nn.Module]) -> Type[t
return F.conv2d(hidden_states, self.weight, self.bias, self.stride, self.padding, self.dilation, self.groups)
_patched_forward = forward
return upsampler_block
@@ -632,12 +627,13 @@ def apply_hidiffusion(
"""
global current_steps # pylint: disable=global-statement
current_steps = steps
if hasattr(model, 'controlnet'):
if hasattr(model, 'controlnet') and (model_type == 'sd' or model_type == 'sdxl'):
from .hidiffusion_controlnet import make_diffusers_sdxl_contrtolnet_ppl, make_diffusers_unet_2d_condition
make_ppl_fn = make_diffusers_sdxl_contrtolnet_ppl
model.__class__ = make_ppl_fn(model.__class__)
make_block_fn = make_diffusers_unet_2d_condition
model.unet.__class__ = make_block_fn(model.unet.__class__)
diffusion_model = model.unet if hasattr(model, "unet") else model
diffusion_model.num_upsamplers += 12
diffusion_model.info = {
@@ -646,14 +642,13 @@ def apply_hidiffusion(
'hooks': [],
'text_to_img_controlnet': hasattr(model, 'controlnet'),
'is_inpainting_task': model.__class__ in auto_pipeline.AUTO_INPAINT_PIPELINES_MAPPING.values(),
'is_playground': False,
'pipeline': model}
model.info = diffusion_model.info
hook_diffusion_model(diffusion_model)
if model_type == 'sd':
modified_key = sd15_hidiffusion_key()
for key, module in diffusion_model.named_modules():
if hasattr(module, "_parent"):
raise RuntimeError(f'HiDiffusion: key={key} module={module.__class__} already patched')
if apply_raunet and key in modified_key['down_module_key']:
module.__class__ = make_diffusers_downsampler_block(module.__class__)
module.switching_threshold_ratio = 'T1_ratio'
@@ -668,15 +663,15 @@ def apply_hidiffusion(
module.switching_threshold_ratio = 'T2_ratio'
if apply_window_attn and key in modified_key['windown_attn_module_key']:
module.__class__ = make_diffusers_transformer_block(module.__class__)
if hasattr(module, "_patched_forward"):
module.forward = module._patched_forward # pylint: disable=protected-access
module.model = 'sd15'
module.info = diffusion_model.info
if hasattr(module, "_parent"):
module.model = 'sd15'
module.info = diffusion_model.info
elif model_type == 'sdxl':
modified_key = sdxl_hidiffusion_key()
for key, module in diffusion_model.named_modules():
if hasattr(module, "_parent"):
raise RuntimeError(f'HiDiffusion: key={key} module={module.__class__} already patched')
if apply_raunet and key in modified_key['down_module_key']:
module.__class__ = make_diffusers_cross_attn_down_block(module.__class__)
module.switching_threshold_ratio = 'T1_ratio'
@@ -691,25 +686,26 @@ def apply_hidiffusion(
module.switching_threshold_ratio = 'T2_ratio'
if apply_window_attn and key in modified_key['windown_attn_module_key']:
module.__class__ = make_diffusers_transformer_block(module.__class__)
if hasattr(module, "_patched_forward"):
module.forward = module._patched_forward # pylint: disable=protected-access
module.model = 'sdxl'
module.info = diffusion_model.info
if hasattr(module, "_parent"):
module.model = 'sdxl'
module.info = diffusion_model.info
else:
raise RuntimeError('HiDiffusion: unsupported model type')
return model
model.info = diffusion_model.info
model.hidiffusion = True
hook_diffusion_model(diffusion_model)
def remove_hidiffusion(model: torch.nn.Module):
""" Removes hidiffusion from a Diffusion module if it was already patched. """
for _, module in model.unet.named_modules():
model = model.unet if hasattr(model, "unet") else model
for _, module in model.named_modules():
while hasattr(module, "_parent"):
model.hidiffusion = True
module.__class__ = module._parent # pylint: disable=protected-access
if hasattr(module, "info"):
for hook in module.info["hooks"]:
for hook in module.info.get("hooks", []):
hook.remove()
module.info["hooks"].clear()
del module.info
if hasattr(module, "_forward"):
module.forward = module._forward # pylint: disable=protected-access
if hasattr(module, "_parent"):
module.__class__ = module._parent # pylint: disable=protected-access
return model
@@ -15,6 +15,7 @@ def make_diffusers_unet_2d_condition(block_class):
class unet_2d_condition(block_class):
# Save for unpatching later
_parent = block_class
def forward(
self,
sample: torch.FloatTensor,
@@ -549,7 +550,7 @@ def make_diffusers_sdxl_contrtolnet_ppl(block_class):
# # scale the initial noise by the standard deviation required by the scheduler
# latents = latents * self.scheduler.init_noise_sigma
# 7. Prepare extra step kwargs. TODO: Logic should ideally just be moved out of the pipeline
# 7. Prepare extra step kwargs.
extra_step_kwargs = self.prepare_extra_step_kwargs(generator, eta)
# 7.1 Create tensor stating which controlnets to keep
+1 -4
View File
@@ -1,8 +1,5 @@
"""
TODO:
- apply metadata
- preview
- load/save
TODO: apply metadata, preview, load/save
"""
import sys
+3 -3
View File
@@ -164,7 +164,7 @@ def save_image(image,
if not check_grid_size([image]):
return None, None, None
if path is None or path == '': # set default path to avoid errors when functions are triggered manually or via api and param is not set
path = shared.opts.outdir_save
path = paths.resolve_output_path(shared.opts.outdir_samples, shared.opts.outdir_save)
namegen = FilenameGenerator(p, seed, prompt, image, grid=grid)
suffix = suffix if suffix is not None else ''
basename = '' if basename is None else basename
@@ -311,7 +311,7 @@ def parse_novelai_metadata(data: dict):
return geninfo
def read_info_from_image(image: Image, watermark: bool = False):
def read_info_from_image(image: Image.Image, watermark: bool = False):
if image is None:
return '', {}
if isinstance(image, str):
@@ -419,7 +419,7 @@ def draw_overlay(im, text: str = '', y_offset: int = 0):
return im
def set_watermark(image, wm_text: str = None, wm_image: Image.Image = None):
def set_watermark(image, wm_text: str | None = None, wm_image: Image.Image | None = None):
if shared.opts.image_watermark_position != 'none' and wm_image is not None: # visible watermark
if isinstance(wm_image, str):
try:
+3 -2
View File
@@ -7,6 +7,7 @@ from modules import scripts_manager, shared, processing, images, errors
from modules.generation_parameters_copypaste import create_override_settings_dict
from modules.ui_common import plaintext_to_html
from modules.memstats import memory_stats
from modules.paths import resolve_output_path
debug = shared.log.trace if os.environ.get('SD_PROCESS_DEBUG', None) is not None else lambda *args, **kwargs: None
@@ -239,8 +240,8 @@ def img2img(id_task: str, state: str, mode: int,
p = processing.StableDiffusionProcessingImg2Img(
sd_model=shared.sd_model,
outpath_samples=shared.opts.outdir_samples or shared.opts.outdir_img2img_samples,
outpath_grids=shared.opts.outdir_grids or shared.opts.outdir_img2img_grids,
outpath_samples=resolve_output_path(shared.opts.outdir_samples, shared.opts.outdir_img2img_samples),
outpath_grids=resolve_output_path(shared.opts.outdir_grids, shared.opts.outdir_img2img_grids),
prompt=prompt,
negative_prompt=negative_prompt,
styles=prompt_styles,
+28 -11
View File
@@ -143,12 +143,11 @@ def torch_tensor(data, *args, dtype=None, device=None, **kwargs):
global device_supports_fp64
if check_cuda(device):
device = return_xpu(device)
if not device_supports_fp64:
if check_device_type(device, "xpu"):
if dtype == torch.float64:
dtype = torch.float32
elif dtype is None and (hasattr(data, "dtype") and (data.dtype == torch.float64 or data.dtype == float)):
dtype = torch.float32
if not device_supports_fp64 and check_device_type(device, "xpu"):
if dtype == torch.float64:
dtype = torch.float32
elif dtype is None and (hasattr(data, "dtype") and (data.dtype == torch.float64 or data.dtype == float)):
dtype = torch.float32
return original_torch_tensor(data, *args, dtype=dtype, device=device, **kwargs)
@@ -223,8 +222,6 @@ def torch_empty(*args, device=None, **kwargs):
original_torch_randn = torch.randn
@wraps(torch.randn)
def torch_randn(*args, device=None, dtype=None, **kwargs):
if dtype is bytes:
dtype = None
if check_cuda(device):
return original_torch_randn(*args, device=return_xpu(device), dtype=dtype, **kwargs)
else:
@@ -258,13 +255,32 @@ def torch_full(*args, device=None, **kwargs):
return original_torch_full(*args, device=device, **kwargs)
original_torch_arange = torch.arange
@wraps(torch.arange)
def torch_arange(*args, device=None, dtype=None, **kwargs):
global device_supports_fp64
if check_cuda(device):
if not device_supports_fp64 and dtype == torch.float64:
dtype = torch.float32
return original_torch_arange(*args, device=return_xpu(device), dtype=dtype, **kwargs)
else:
if not device_supports_fp64 and check_device_type(device, "xpu") and dtype == torch.float64:
dtype = torch.float32
return original_torch_arange(*args, device=device, dtype=dtype, **kwargs)
original_torch_linspace = torch.linspace
@wraps(torch.linspace)
def torch_linspace(*args, device=None, **kwargs):
def torch_linspace(*args, device=None, dtype=None, **kwargs):
global device_supports_fp64
if check_cuda(device):
return original_torch_linspace(*args, device=return_xpu(device), **kwargs)
if not device_supports_fp64 and dtype == torch.float64:
dtype = torch.float32
return original_torch_linspace(*args, device=return_xpu(device), dtype=dtype, **kwargs)
else:
return original_torch_linspace(*args, device=device, **kwargs)
if not device_supports_fp64 and check_device_type(device, "xpu") and dtype == torch.float64:
dtype = torch.float32
return original_torch_linspace(*args, device=device, dtype=dtype, **kwargs)
original_torch_eye = torch.eye
@@ -358,6 +374,7 @@ def ipex_hijacks():
torch.ones = torch_ones
torch.zeros = torch_zeros
torch.full = torch_full
torch.arange = torch_arange
torch.linspace = torch_linspace
torch.eye = torch_eye
torch.load = torch_load

Some files were not shown because too many files have changed in this diff Show More