diff --git a/CHANGELOG.md b/CHANGELOG.md index f9db1683e..f0ba9ab99 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,10 +1,167 @@ # Change Log for SD.Next -## Highlights for 2026-08-26 +## Update for 2026-09-17 + +### Highlights for 2026-09-17 + +*What's New*? Well, code-wise, this is a big one... +First, a-lot-of-optimizations: +- Updated core packages +- Improved **LoRA** performance and quality, especially with quantized models +- Newly structured **attention** mechanisms +- Modular pipelines with new **guidance** methods +- Support for different **caching** stacks +- Compute updates across the board + +And some cool new stuff and models: +- **DLSS v5** integration +- New models: **Anima 2.9B**, **LLaDa-Image** +- And few cloud models: *Google's Gemini, NanoBanana, Veo, Omni* and *X.AI's Grok* +- Some (light) UI restyling + +Plus inevitable bug-fixes... + +[Home](https://vladmandic.github.io/sdnext/) | [ChangeLog](https://github.com/vladmandic/automatic/blob/master/CHANGELOG.md) | [Docs](https://vladmandic.github.io/sdnext-docs/) | [Discord](https://discord.com/invite/sd-next-federal-batch-inspectors-1101998836328697867) | [Sponsor](https://github.com/sponsors/vladmandic) + +### Details for 2026-09-17 + +- **Models** + - [Anima 2.9B Preview v1](https://huggingface.co/yeoj34760/Anima-2.9B) + expanded version of Anima 2B + - [inclusionAI LLaDA-Image](https://huggingface.co/inclusionAI/LLaDA-Image) in *base* and *turbo* variants + LLaDA-Image is a 6.5B transformer with massive 16.3B fully-custom MoE text-encoder and optional 1.3B SigVQ conditioning model + with support for text-to-image, vq-conditioned text-to-image and image-editing workflows + *note* model is extremely quantization sensitive so minimum allowed quant type is `uint8` + - [MiniMax-H3](https://huggingface.co/MiniMaxAI/MiniMax-H3) updates + new [SDNQ-uint8](https://huggingface.co/OzzyGT/MiniMax_H3_sdnq_8bit_pruned) pre-quantized *base* and *pruned* variants + new [Nunchaku-Lite](https://huggingface.co/rootonchair/MiniMax-H3-nunchaku-lite-int4) variant + new [VDN](https://huggingface.co/OpenVDN/vdn-minimax-h3) *video-delta-net* variant +- **LoRA** + - see [LoRA docs](https://vladmandic.github.io/sdnext-docs/LoRA) for all of the improvements and usage instructions + *note*: lora now has its own settings section in *settings -> lora* + - new apply engine that allows lora to be applied much faster + - new calibration engine that allows lora to be applied with far smaller error when dealing with highly quantized models + - *note*: calibration data is stored once calculated so it can be reused for future runs + location is `models/calibration` folder + - new factor cache that allows lora effects to be pre-calculated and persistently cached for future runs + location is `models/lora-factor-cache` folder + - multi-network stack modes + can significantly improve lora quality when using multiple loras at once + - per-block strength + - native support for **MiniMax** + see [MiniMax Turbo LoRA collection](https://huggingface.co/vladmandic/MiniMax-H3-Turbo-LoRA) for LoRAs and examples +- **DLSS** + - add DLSS support for: *NeuralRender, SuperSample and FrameGen* + dlls 5 caused quite a stir, but combined with generative ai it becomes a nice tool + - available as part of image/video generate workflows via *extras -> dlss* + or as a standalone *processing* workflow + or via xyz grid + - *note*: requires nvidia rtx gpu, windows platform and compatible gpu drivers + but...it can be used from wsl2: unpack required package on windows host and you can access it from the wsl2 environment + - *install*: requires [DLSS 5 Visual Enhancer](https://github.com/Merserk/dlss5-visual-enhancer/releases/tag/v7.0) + - *diag*: enable `SD_DLSS_DEBUG=true` and monitor `dlss.log` in the package directory +- **Attention** + - see [Attention docs](https://vladmandic.github.io/sdnext-docs/Attention) for details and usage instructions + *note*: attention now has its own settings section in *settings -> cross attention* + *note*: this is a breaking change - if you had custom attention settings in previous releases, you will need to re-apply them in the new settings section + - new `sparse-attention` method that can be combined with other attention methods + to reduce memory usage and improve performance on large models + - new attention mechanisms decision tree and apply method refactor +- **Modular Pipelines** + - see [Modular Pipelines docs](https://vladmandic.github.io/sdnext-docs/Modular-Pipelines) for details and usage instructions + - new model **Guidance** stack for modular pipelines + includes: *CFG, PAG, Auto, Zero, APG, SLG, SEG, TCFG, FDG* + see [Guidance docs](https://vladmandic.github.io/sdnext-docs/Guidance) for details and usage instructions + - new model **Caching** stack for modular pipelines + includes: *FasterCache, FirstBlockCache, LayerSkip, MagCache, PyramidAttentionBroadcast, TaylorSeerCache, TextKVCache* + see [Caching docs](https://vladmandic.github.io/sdnext-docs/Caching) for details and usage instructions + - implement progress and preview + - intercept and profiling hooks + - on-demand convert standard model on-demand +- **Cloud** + - updated support for google models in text, image and video workflows + *note*: requires google api key + - [Google Veo](https://ai.google.dev/gemini-api/docs/veo) in *preview*, *fast* and *lite* variants + workflows: *t2v, i2v* + - [Google Omni](https://ai.google.dev/gemini-api/docs/omni) in *flash* variant + workflows: *t2v, i2v* + - [Google Nano Banana](https://ai.google.dev/gemini-api/docs/models/gemini-3.1-flash-image) in *2* and *2 lite* and *pro* variants + workflows: *caption* + - [Google Gemini](https://ai.google.dev/gemini-api/docs/models/gemini-3.8-flash) in *flash* and *pro* variants + workflows: *caption, prompt-enhance* + - added support for xai grok models + - [X.AI Grok](https://x.ai/grok) in *3*, *3 fast*, *3 mini* and *3 mini fast* variants + workflows: *caption, prompt-enhance* + *note*: requires grok api key +- **Compute** + - cuda: update `torch==2.14.0` with `cuda==13.2` + - openvino: update `openvino==2026.3.1` with `torch==2.13.0` + - option to skip triton autotune and use default config for all triton kernels + in *settings -> compute settings* + *note*: this may improve initial generate time, but may also reduce performance on some models + - rocm: update `rocm` script and add detailed `miopen` logging, thanks @resonantsky + - new optional transformer hooks + in *settings -> compute add-ons* + *PAG: Perturbed attention guidance, PAB: Pyramid attention broadcast, FBC: First Block Cache, FC: Faster Cache, LS: Layer Skip, MC: Mag Cache, TS: TaylorSeer* + *note*: compatibility of different methods varies across different models + - update `numpy` and `scipy` frozen requirements as required by new compute drivers + *note*: this may break compatibility with some legacy packages, so report any finidings +- **Other** + - video preview: TAESD support for **MiniMax** + - support `xai grok` for prompt enhance workflows + *note*: requires grok api key + - remove `/redocs` as `/docs` are primary api docs + - rebuild docs site index +- **UI** + - some (light) re-styling of the *Default* theme + - add new *Tillerz-CleanDark* theme, thanks @Tillerz + - ability to filter samplers and upscalers, thanks @emecii +- **Wiki/Docs**: + - new articles: *Attention, Modular-Pipelines* + - updated: *LoRA, MiniMax* +- **Fixes** + - api: prompt enhance with vision + - autocomplete: skip disabled networks + - compile: keep model compiled state + - detailer: handling of stop/skip/pause + - framepack: correct device assignment, thanks @li-lizhe + - group offload: improve memory management + - installer: better handle git detached head + - json: handle file locks + - log: ansi color handling + - lora: cleanup tags + - lora: support transformer ref models + - lora: keep parsed network data through pipeline + - lucida: handle requirements + - lumina-dimoo: attention-kwargs, thanks @Anai-Guo + - metadata: fix wildcard info + - minimax: crop image to video aspect ratio + - modular: handle module with remote-code + - network: improve type/version lookup + - offline: honor offline mode for more models, thanks @ryanmeador + - openvino: optimize recompile checks and lora loading + - prompt enhance: cloud models use correct system prompt + - prompt enhance: use init image for video + - prompt: cache checks when cfg changes + - prompt: unnecessary secondary prompt if same + - prompt: clean prompt after network parsing + - rife: cleanup dead code, thanks @Anai-Guo + - temp files: handle locking + - theme: fix circular imports changing theme to default + - todo: remove dead code, thanks @Anai-Guo + - ui: js fetch exception handling + - update: handle git errors gracefully + - vae: fetch scale factor from the model + - vdm scheduler: fix steps, thanks @zjn20030811 + - xyz grid: apply bool values + +## Update for 2026-08-26 + +### Highlights for 2026-08-26 Time for a new release, *this is a large one*! Main focus is improving video workflows which also brings full support for new [MiniMax H3](https://vladmandic.github.io/sdnext-docs/MiniMax) and [LTXVideo-2.5](https://vladmandic.github.io/sdnext-docs/LTX) -and improves general video processing with flexible video upscaling, updated interpolation, etc. +and improvements to general video processing with flexible video upscaling, updated interpolation, etc. *What else?* - [Detailer.next](https://vladmandic.github.io/sdnext-docs/Detailer) with new support for *vision-language models* and *per-class prompts* @@ -1898,7 +2055,7 @@ And check out new **history** tab in the right panel, it now shows visualization *note*: this does not impact the actual image resolution, only the resolution at which detailer internally operates - refactor reuse-seed and add functionality to all tabs - refactor modernui js codebase - - move zluda flash attenion to *Triton Flash attention* option + - move zluda flash attenion to *Triton AMD Flash attention* option - remove samplers filtering - allow both flow-matching and discrete samplers for sdxl models - cleanup command line parameters diff --git a/TODO.md b/TODO.md index 032000612..853262554 100644 --- a/TODO.md +++ b/TODO.md @@ -2,15 +2,15 @@ ## Short-term -- LoRA: merge new handler, @CalamitousFelicitousness -- Attn: merge refactor, @CalamitousFelicitousness -- MiniMax LoRA: native loader for MiniMax-H3: fl2va, ref2va, pruned -- MiniMax TAESD: -- MiniMax: Create pre-quant for MiniMax-H3-Turbo -- Benchmark tool productize: @CalamitousFelicitousness -- Inpaint: https://discord.com/channels/1101998836328697867/1130536562422186044/1506850651035144322, @vladmandic - Control tab verify overrides handling, @vladmandic -- LTX: Create pre-quant for LTX-2.5 +- LTX: Implement LTX2DFRPipeline +- ROCm: v10 +- Video: unify execution path for ui and api +- Torch: update ipex, rocm to torch==2.14 + +## Issues + +- [Inpaint](https://discord.com/channels/1101998836328697867/1130536562422186044/1506850651035144322), @vladmandic ## Features @@ -21,20 +21,19 @@ - Lightweight scheduler/queue manager, @vladmandic - Integrate natural language image search: [ImageDB](https://github.com/vladmandic/imagedb), @vladmandic - Support cloud providers, @CalamitousFelicitousness +- Benchmark tool productize: @CalamitousFelicitousness ### Roadmap +- Automated testing and integrate models repo - Video upscaling: LTX-Upscaler +- Video upscaling: [MiniMax-Upscaler](https://huggingface.co/LBH-123-AI/Minimax_h3_latent_Upscaler) - Video capabilities to processing tab, add RIFE, upscaling (once available) - Distraction-free UI mode with prompt-only, chat-based interface -- Revisit transformer caching for modular pipelines -- Revisit guidance for modular pipelines -- Implement modular for some image models - Video models: support finetunes - Incorporate [prompting guides](https://github.com/CalamitousFelicitousness/ai-prompting-guides) - Video models: use Networks/Reference instead of custom - UI Lite vs Expert mode -- Expand custom VAE support - Remove obsolete code: `olive-ai` ### OnHold @@ -51,18 +50,6 @@ - Unify *huggingface* and *diffusers* model folders - JSON image metadata -### Modular - -*Pending finalization of modular pipelines implementation and development of compatibility layer* - -- 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/huggingface/diffusers/pull/12744) -- [SmoothCache](https://github.com/huggingface/diffusers/issues/11135) -- [STG](https://github.com/huggingface/diffusers/blob/main/examples/community/README.md#spatiotemporal-skip-guidance) -- [TextKVCache](https://huggingface.co/NucleusAI/Nucleus-Image#quick-start), @vladmandic - ## New models / Pipelines TODO: Investigate which models are diffusers-compatible and prioritize! diff --git a/cli/api-enhance.py b/cli/api-enhance.py index 0acb7d1ab..f84201375 100755 --- a/cli/api-enhance.py +++ b/cli/api-enhance.py @@ -59,6 +59,7 @@ def enhance(args): # pylint: disable=redefined-outer-name options['model'] = str(args.model) if args.image: options['image'] = encode(args.image) + options['use_vision'] = True response = post('/sdapi/v1/prompt-enhance', options) return response @@ -72,6 +73,6 @@ if __name__ == "__main__": parser.add_argument('--image', type=str, default=None, required=False, help='optional input image') parser.add_argument('--nsfw', type=bool, action=argparse.BooleanOptionalAction, required=False, help='nsfw allowed') args = parser.parse_args() - log.info(f'api-upscale: {args}') + log.info(f'api-enhance: {args}') result = enhance(args) log.info(result) diff --git a/cli/lora-quant-fidelity.py b/cli/lora-quant-fidelity.py new file mode 100644 index 000000000..28036ed66 --- /dev/null +++ b/cli/lora-quant-fidelity.py @@ -0,0 +1,685 @@ +#!/usr/bin/env python +"""LoRA fidelity analyzer for quantized base models. + +Measures, in weight space, how faithfully a LoRA lands on an SDNQ-quantized +model. Every targeted module is rebuilt with the loader's own module class and +its delta taken from the production ``calc_updown``, so all adapter families +(LoRA, LoKR, LoHA, OFT, full, IA3, GLoRA, norm, plus DoRA and bias variants) +are measured as they would actually apply: + +- factor path (plain additive LoRA riding the svd side-channel): storage is + lossless; the reported figure is the delta realized through the result-dtype + materialize, the same bf16 rounding an unquantized model applies. + Eligibility is decided by the loader's own predicate. +- hosted path (non-factorable families on sub-8-bit formats): the seeded svd + truncation at ``--host-rank``, realized the same way. +- requantize path (all other fallbacks): retention ``rho`` of the intended + delta. On-grid rounding erases sub-step deltas down to a ``2/group_size`` + floor, so low-bit formats (<=6 bits) typically show rho ~= 0.02-0.03. +- unquantized modules: the LoRA applies exactly regardless. + +Reported fidelity is per-module ``applied_rho`` (the measured figure for +whichever path the loader would take), summarized as a median and an +energy-weighted mean over the file's modules; ``requant_rho`` always carries +the if-merged figure. ``snr`` sets the delta against the base weight's own +quantization error (uniform rounding from the grid step, or measured with +``--reference``), in the calibrated norm with ``--calib``: it does not depend +on the apply path and compares checkpoints of different widths. + +Works offline against a pre-quantized SDNQ repo (stored tensors + config, +streamed one module at a time so the repo need not fit in memory) or a bf16 +repo with simulated quantization settings, so a combination can be assessed +before committing to a quantized checkpoint. + +Examples: + python cli/lora-quant-fidelity.py --model vladmandic/Krea-2-Base-sdnq-hadamard-uint4 --arch krea2 --lora "~/models/Lora/Krea 2/krea2_turbo_distill_r256.safetensors" + python cli/lora-quant-fidelity.py --model CalamitousFelicitousness/Krea-2-Base-Diffusers --arch krea2 --dtype uint4 --lora lora.safetensors --json report.json +""" + +import os +import re +import sys +import json +import types +import argparse +import importlib +import importlib.util + +sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) +os.environ.setdefault('SD_INSTALL_QUIET', '1') + + +def parse_cli(): + parser = argparse.ArgumentParser(description='lora-quant-fidelity') + parser.add_argument('--model', required=True, help='model dir, transformer dir, or org/name repo id') + parser.add_argument('--arch', default='generic', help='lora key resolver: a native arch (e.g. krea2, zimage, f2) or generic') + parser.add_argument('--lora', required=True, nargs='+', help='lora safetensors file(s)') + parser.add_argument('--dtype', default=None, help='simulate quantization of a bf16 repo at this sdnq dtype (e.g. uint4, int8); bf16 measures the unquantized reference') + parser.add_argument('--group', type=int, default=0, help='sdnq group_size for simulation') + parser.add_argument('--hadamard-group', type=int, default=256, help='sdnq hadamard group for simulation') + parser.add_argument('--sample', type=int, default=40, help='max modules analyzed per lora (evenly sampled)') + parser.add_argument('--full', action='store_true', help='analyze every matched module') + parser.add_argument('--json', default=None, help='write full report to this json file') + parser.add_argument('--host-rank', type=int, default=256, help='svd hosting cap for non-factorable modules on sub-8-bit formats, mirroring lora_sdnq_host_rank; 0 scores the requantize path instead') + parser.add_argument('--calib', default=None, help='activation statistics file (models/calibration/*.safetensors): hosting truncation is then channel-weighted as with lora_sdnq_host_calib, and hosted rho is measured in the activation-weighted norm (the output-error proxy)') + parser.add_argument('--reference', default=None, help='unquantized repo of the same model: the base quantization error each delta competes with is then measured per module instead of estimated from the grid step') + parser.add_argument('--fail-under', type=float, default=None, help='exit 2 when median applied fidelity of any lora is below this') + return parser.parse_args() + + +cli_args = parse_cli() +sys.argv = [sys.argv[0]] # sdnext arg parsing during imports must not see tool args (prefix matching eats --model/--lora) + +import modules.cmd_args # pylint: disable=wrong-import-position +import installer # pylint: disable=wrong-import-position +modules.cmd_args.parse_args() +installer.add_args(modules.cmd_args.parser) +modules.cmd_args.parsed, _unknown = modules.cmd_args.parser.parse_known_args([]) + +import torch # pylint: disable=wrong-import-position +from safetensors import safe_open # pylint: disable=wrong-import-position +from rich import print as rprint # pylint: disable=wrong-import-position + +from modules import shared # pylint: disable=wrong-import-position,unused-import # shared must initialize before sd_models, which imports back into it +from modules.lora import native_adapter, network, network_lora, network_lokr, network_hada, network_oft, network_full, network_ia3, network_glora, network_norm, lora_sdnq # pylint: disable=wrong-import-position +from modules.lora.lora_load import NATIVE_DISPATCH # pylint: disable=wrong-import-position +from sdnq.quantizer import sdnq_quantize_layer_weight # pylint: disable=wrong-import-position +from sdnq.quant_utils import rotate_hadamard # pylint: disable=wrong-import-position + + +MODEL_ROOTS = [ + os.path.expanduser('~/database/models/huggingface'), + os.path.expanduser('~/database/models/Diffusers'), +] +device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') +ARCH_PACKAGES = {'zimage': 'z_image', 'f2': 'flux', 'minimaxh3': 'minimax'} # arches whose pipelines package is not spelled like the arch + +# every adapter family the native loader can build, with the module class that owns its +# apply-time math. deltas are taken from the production calc_updown so the tool cannot +# drift from the loader, and eligibility is decided by the production predicate itself. +FAMILY_SPECS = ( + ('lora', network_lora.NetworkModuleLora, native_adapter.LORA_SUFFIXES, native_adapter.LORA_MARKERS), + ('lokr', network_lokr.NetworkModuleLokr, native_adapter.LOKR_SUFFIXES, native_adapter.LOKR_MARKERS), + ('loha', network_hada.NetworkModuleHada, native_adapter.LOHA_SUFFIXES, native_adapter.LOHA_MARKERS), + ('oft', network_oft.NetworkModuleOFT, native_adapter.OFT_SUFFIXES, native_adapter.OFT_MARKERS), + ('full', network_full.NetworkModuleFull, native_adapter.FULL_SUFFIXES, native_adapter.FULL_MARKERS), + ('ia3', network_ia3.NetworkModuleIa3, native_adapter.IA3_SUFFIXES, native_adapter.IA3_MARKERS), + ('glora', network_glora.NetworkModuleGLora, native_adapter.GLORA_SUFFIXES, native_adapter.GLORA_MARKERS), + ('norm', network_norm.NetworkModuleNorm, native_adapter.NORM_SUFFIXES, native_adapter.NORM_MARKERS), +) + + +class StubOnDisk: + def __init__(self, path): + self.filename = path + self.name = os.path.splitext(os.path.basename(path))[0] + self.shorthash = '' + self.sd_version = 'unknown' + with safe_open(path, framework='pt', device='cpu') as f: + self.metadata = f.metadata() or {} + + +def resolve_model_dir(spec): + """Return the transformer directory for a local path or org/name repo id.""" + candidates = [spec, os.path.join(spec, 'transformer')] + cache_name = 'models--' + spec.replace('/', '--') + for root in MODEL_ROOTS: + snap_root = os.path.join(root, cache_name, 'snapshots') + if os.path.isdir(snap_root): + for snap in sorted(os.listdir(snap_root), reverse=True): + candidates.append(os.path.join(snap_root, snap, 'transformer')) + candidates.append(os.path.join(snap_root, snap)) + for c in candidates: + if os.path.isfile(os.path.join(c, 'config.json')): + return c + raise SystemExit(f'model not found: {spec}') + + +def resolve_arch(name): + """Return the arch lora module for key resolution, or None for generic matching.""" + if name == 'generic': + return None + path = NATIVE_DISPATCH.get({'flux2': 'f2', 'ernie': 'ernieimage'}.get(name, name)) + if path is None: + raise SystemExit(f'unknown arch {name}; choices: {sorted(NATIVE_DISPATCH)} or generic') + return importlib.import_module(path) + + +def map_lora_modules(lora_path, arch_mod): + """Return {model_module_path: (family, weights)} across every adapter family, plus a census. + + Grouping mirrors the native loader: a family is only considered when its + marker is present, and groups resolve to model paths through the arch's own + resolver. A fused save is sliced onto its targets for the lora family; the + other families' chunks are counted but not analyzed (their apply-time math + is arch-owned). + """ + with safe_open(lora_path, framework='pt', device='cpu') as f: + state_dict = {k: f.get_tensor(k) for k in f.keys()} + metadata = f.metadata() or {} + prefixes = getattr(arch_mod, 'KNOWN_PREFIXES', native_adapter.KNOWN_PREFIXES_DEFAULT) + resolve = getattr(arch_mod, 'resolve_targets', None) or (lambda prefix, base: [(base, None)]) + grouper = getattr(arch_mod, 'group_by_suffixes', None) or native_adapter.group_by_suffixes # an arch that rewrites keys before parsing groups them itself + file_alpha = getattr(arch_mod, 'file_alpha', None) + mapped, census, chunked = {}, {}, 0 + for fam, _cls, suffixes, markers in FAMILY_SPECS: + if not native_adapter.has_marker(state_dict, markers): + continue + groups = grouper(state_dict, suffixes, prefixes=prefixes) + if fam == 'lora': + groups = {k: w for k, w in groups.items() if 'lora_down.weight' in w and 'lora_up.weight' in w} + alpha = file_alpha(types.SimpleNamespace(filename=lora_path, metadata=metadata)) if file_alpha is not None else None + if alpha is not None and not any('alpha' in w for w in groups.values()): # a file-level alpha applies only to files without alpha tensors, as in try_load_lora + groups = {k: {**w, 'alpha': torch.tensor(float(alpha))} for k, w in groups.items()} + else: + groups = {k: w for k, w in groups.items() if native_adapter.has_marker({f'x.{s}': None for s in w}, markers)} + if not groups: + continue + census[fam] = len(groups) + for (prefix, base), w in groups.items(): + for path, chunk in native_adapter.resolve_group_targets(resolve, prefix, base): + target = w + if chunk is not None: # a fused save spans several modules; only the lora family slices its up factor + target = None + if fam == 'lora': + fused_out = w['lora_up.weight'].shape[0] + target = native_adapter.slice_lora_chunk(w, chunk) + target = native_adapter.slice_dora_scale(target, chunk, fused_out) + target = native_adapter.slice_bias_delta(target, chunk, fused_out) if target is not None else None + if target is None: + chunked += 1 + continue + mapped.setdefault(path, []).append((fam, target)) # a module can carry several families; the loader applies each + return mapped, census, chunked + + +def stamp_index(paths): + """Map each module path to its stamped form, the way the loader matches. + + The loader compares ``network_prefix + path.replace('.', '_')`` against each + module's stamped ``network_layer_name``, so kohya-style ``lora_unet_`` keys + (whose base arrives already underscored) resolve fine there. Matching on the + stamped form reproduces that and keeps dotted bases working unchanged. + """ + return {p.replace('.', '_'): p for p in paths} + + +def make_stub(shape, dtype=torch.bfloat16): + """Minimal sd_module standing in for a bf16 repo weight: the module classes key off its type and shape.""" + if len(shape) == 2: + return torch.nn.Linear(shape[1], shape[0], bias=False, dtype=dtype, device='meta') + return torch.nn.Conv2d(shape[1], shape[0], shape[2:], bias=False, dtype=dtype, device='meta') + + +def build_module(fam, path, w, net, sd_module): + """Instantiate the family's production NetworkModule for one target.""" + cls = next(c for f, c, _s, _m in FAMILY_SPECS if f == fam) + weights = network.NetworkWeights(network_key=path, sd_key=path, w=w, sd_module=sd_module) + return cls(net, weights) + + +def resolve_transformer_cls(arch, class_name, model_dir=None): + """Resolve the transformer class: an sdnext-owned spec class, then diffusers, then a modeling file beside the weights. + Arches like krea2 keep checkpoint-style names in their own class; pruned MiniMax repos ship theirs as remote code.""" + if not class_name: + return None + if arch: + try: + pkg = importlib.import_module(f'pipelines.{ARCH_PACKAGES.get(arch, arch)}') + for attr in dir(pkg): + if attr.endswith('_SPEC'): + cls = getattr(getattr(pkg, attr), 'cls', None) + if cls is not None and cls.__name__ == class_name: + return cls + except Exception: + pass + import diffusers + cls = getattr(diffusers, class_name, None) + if cls is not None or not model_dir: + return cls + for fname in sorted(os.listdir(model_dir)): + path = os.path.join(model_dir, fname) + if not fname.endswith('.py'): + continue + with open(path, encoding='utf-8') as f: + if re.search(rf'^class {re.escape(class_name)}\b', f.read(), re.MULTILINE) is None: + continue + spec = importlib.util.spec_from_file_location(fname[:-3], path) + module = importlib.util.module_from_spec(spec) + sys.modules[spec.name] = module + spec.loader.exec_module(module) + return getattr(module, class_name) + return None + + +class QuantRepo: + """Per-module access to a pre-quantized SDNQ repo: a meta skeleton built through the sdnq conversion, each layer's + tensors streamed from the shards while it is analyzed; tensors outside the block stacks stay resident for the arch hooks.""" + + LAYER_KEYS = ('weight', 'bias', 'scale', 'zero_point', 'svd_up', 'svd_down') + + def __init__(self, model_dir, model_config, arch=None): + from accelerate import init_empty_weights + from sdnq import SDNQConfig + from sdnq.quantizer import sdnq_post_load_quant + from sdnq.utils import get_quant_args_from_config + cls = resolve_transformer_cls(arch, model_config.get('_class_name'), model_dir) + if cls is None: + raise SystemExit(f'cannot resolve transformer class {model_config.get("_class_name")} for "{model_dir}"') + quant_config = SDNQConfig.from_dict(model_config['quantization_config']) + with init_empty_weights(): + config = cls.load_config(model_dir) + if hasattr(config, 'pop'): + config.pop('quantization_config', None) + model = cls.from_config(config) + model = sdnq_post_load_quant(model, torch_dtype=torch.bfloat16, pre_quantized=True, **get_quant_args_from_config(quant_config)) + self.model = model + self.model_dir = model_dir + self.handles = {} + index = os.path.join(model_dir, 'diffusion_pytorch_model.safetensors.index.json') + if os.path.isfile(index): + with open(index, encoding='utf-8') as f: + weight_map = json.load(f)['weight_map'] + else: + weight_map = {} + for fname in sorted(os.listdir(model_dir)): + if fname.endswith('.safetensors'): + with safe_open(os.path.join(model_dir, fname), framework='pt', device='cpu') as f: + weight_map.update(dict.fromkeys(f.keys(), fname)) + mapping = getattr(model, '_checkpoint_conversion_mapping', None) or {} + self.shards = {} # model key -> (stored key, shard) + for stored, shard in weight_map.items(): + key = stored + for pattern, replacement in mapping.items(): + key = re.sub(pattern, replacement, key) + self.shards[key] = (stored, shard) + self.layers = {} + for name, module in model.named_modules(): + if getattr(module, 'sdnq_dequantizer', None) is not None or (module.__class__.__name__ == 'Linear' and getattr(module, 'weight', None) is not None): + self.layers[name] = module + stacks = tuple(f'{name}.' for name, module in model.named_modules() if isinstance(module, torch.nn.ModuleList)) + resident = {key: self.get(key) for key in self.shards if not key.startswith(stacks)} + model.load_state_dict(resident, strict=False, assign=True) + + def get(self, key): + entry = self.shards.get(key) + if entry is None: + return None + stored, shard = entry + f = self.handles.get(shard) + if f is None: + f = safe_open(os.path.join(self.model_dir, shard), framework='pt', device='cpu') + self.handles[shard] = f + return f.get_tensor(stored) + + def materialize(self, name): + """Load one layer's stored tensors onto the analysis device and return the layer.""" + from sdnq.quant_utils import prepare_weight_for_matmul, prepare_svd_for_matmul + layer = self.layers[name] + state = {} + for local in self.LAYER_KEYS: + t = self.get(f'{name}.{local}') + if t is not None: + state[local] = t.to(device) + layer.load_state_dict(state, strict=False, assign=True) + deq = getattr(layer, 'sdnq_dequantizer', None) + if deq is not None: # the loader's post-processing, so the dequantizer sees the layout it expects + if deq.use_quantized_matmul and not deq.re_quantize_for_matmul: + layer.weight.data = prepare_weight_for_matmul(layer.weight, matmul_dtype=deq.quantized_matmul_dtype) + if getattr(layer, 'svd_up', None) is not None: + layer.svd_up.data, layer.svd_down.data = prepare_svd_for_matmul(layer.svd_up, layer.svd_down, deq.use_quantized_matmul) + return layer + + def release(self, name): + layer = self.layers[name] + state = {local: torch.empty_like(t, device='meta') for local, t in layer.state_dict().items() if t.device.type != 'meta'} + layer.load_state_dict(state, strict=False, assign=True) + + +class Bf16Repo: + """Lazy per-module weight access for a sharded bf16 transformer repo.""" + + def __init__(self, model_dir): + self.model_dir = model_dir + self.handles = {} # reopening a multi-gb shard per module dominates runtime over many loras + index = os.path.join(model_dir, 'diffusion_pytorch_model.safetensors.index.json') + if os.path.isfile(index): + with open(index, encoding='utf-8') as f: + self.weight_map = json.load(f)['weight_map'] + else: + single = os.path.join(model_dir, 'diffusion_pytorch_model.safetensors') + with safe_open(single, framework='pt', device='cpu') as f: + self.weight_map = dict.fromkeys(f.keys(), 'diffusion_pytorch_model.safetensors') + + def get(self, key): + shard = self.weight_map.get(key) + if shard is None: + return None + f = self.handles.get(shard) + if f is None: + f = safe_open(os.path.join(self.model_dir, shard), framework='pt', device='cpu') + self.handles[shard] = f + return f.get_tensor(key) + + +def quant_noise_energy(step, shape, hadamard_group, rms): + """Expected energy of the base weight's quantization error, ``step^2/12`` per element under uniform rounding; + with ``rms`` per input channel it is the output-space energy per token.""" + _out, n_in = shape + s = step.to(device, torch.float32) + if s.ndim == 3: + s = s.squeeze(-1) + if s.ndim == 1: + s = s[:, None] + groups = s.shape[1] + glen = n_in // groups + if rms is None: + power = torch.full((groups,), float(glen), device=s.device) + else: + p = rms.to(s.device, torch.float32).square() + if hadamard_group and n_in % hadamard_group == 0: + p = p.view(-1, hadamard_group).mean(1, keepdim=True).expand(-1, hadamard_group).reshape(-1) + power = p.view(groups, glen).sum(1) + return float(((s.square() / 12) @ power).sum()) + + +def analyze_module(W_dq, deq_params, mods, calib_rms=None, step_live=None, noise=None): + """Return fidelity metrics for one quantized module and the adapters targeting it. + + Deltas come from each module's production calc_updown and sum the way the + loader stacks them, so every family (and dora / dense-bias / diff_b variant) + is measured as applied. A module is factor-path eligible only when every + contribution is a plain additive lora. With ``calib_rms``, hosting mirrors + the calibrated production path and its rho is scored in the weighted norm. + With ``step_live`` (the layer's own pre-add scale), the production routing + rule applies: a delta fat against the grid whose truncation capture is low + reports the requantize path, the way the loader would route it. + + ``snr`` is the delta's energy over the energy of the base weight's own + quantization error, in the calibrated norm when ``calib_rms`` is given: + ``noise`` carries that error's measured ``(plain, weighted)`` energies + against an unquantized reference, else the uniform-rounding estimate from + ``step_live`` stands in. It is independent of the apply path and says + whether what the adapter adds stands above the error the checkpoint + already carries. + """ + D = None + for mod in mods: + d = mod.calc_updown(W_dq)[0].to(device, torch.float32).reshape(W_dq.shape) + D = d if D is None else D + d + nD = D.norm() + control = deq_params['weights_dtype'] == 'bf16' # unquantized reference: the delta just rounds into bf16 + factor_eligible = (not control) and all(lora_sdnq.get_module_factors(m, device, torch.bfloat16) is not None for m in mods) + if float(nD) == 0.0: # an all-zero delta (some full-rank extractions carry empty .diff): retention is undefined, not erased + return dict(rank=getattr(mods[0], 'dim', None), rms_delta=0.0, rms_weight=float(W_dq.pow(2).mean().sqrt()), + step_ratio=None, crossers=None, requant_rho=None, requant_resid=None, + factor_eligible=factor_eligible, hosted=False, applied_rho=None, delta_energy=0.0, + snr=None, snr_plain=None, noise_rms=None, noise_source=None) + snr, snr_plain, noise_rms, noise_source = None, None, None, None + if (noise is not None or step_live is not None) and not deq_params.get('use_codebook', False): + rms = calib_rms.to(device, torch.float32) if (calib_rms is not None and calib_rms.shape[-1] == D.shape[-1]) else None + if noise is not None: + plain, weighted = noise + noise_source = 'measured' + else: + hadamard = deq_params['hadamard_group_size'] if deq_params['use_hadamard'] else 0 + plain = quant_noise_energy(step_live, D.shape, hadamard, None) + weighted = quant_noise_energy(step_live, D.shape, hadamard, rms) if rms is not None else plain + noise_source = 'uniform' + delta_w = float((D * rms).square().sum()) if rms is not None else float(nD.square()) + noise_rms = (plain / D.numel()) ** 0.5 + snr_plain = float(nD.square()) / plain if plain > 0 else None + snr = delta_w / weighted if weighted > 0 else None + step_ratio, crossers = None, None + if control: + W2 = (W_dq + D).to(torch.bfloat16).float() + else: + # mirror network_add_weights: it requantizes with the layer's own svd setting and rank, + # and an svd checkpoint's dequantized weight is not on the plain integer grid + use_svd = deq_params.get('use_svd', False) + kw = dict(layer_class_name='Linear', torch_dtype=torch.bfloat16, group_size=deq_params['group_size'], + hadamard_group_size=deq_params['hadamard_group_size'], use_hadamard=deq_params['use_hadamard'], + weights_dtype=deq_params['weights_dtype'], use_svd=use_svd, svd_rank=deq_params.get('svd_rank', 32), + svd_steps=deq_params.get('svd_steps', 8), use_quantized_matmul=False, dequantize_fp32=False) + deq2, data2 = sdnq_quantize_layer_weight(W_dq + D, **kw) + W2 = deq2(data2['weight'], data2['scale'], zero_point=data2['zero_point'], + svd_up=data2['svd_up'], svd_down=data2['svd_down'], dtype=torch.float32, skip_compile=True) + Dh = rotate_hadamard(D, group_size=deq_params['hadamard_group_size']) if deq_params['use_hadamard'] else D + step = data2['scale'].float() + Dg = Dh.unflatten(-1, (step.shape[1], -1)) if step.ndim == 3 else Dh + step_ratio = float((Dg.abs() / step).mean()) + crossers = float((Dg.abs() > step / 2).float().mean()) + E = W2 - W_dq + rho = float(E.flatten() @ D.flatten() / nD.square()) + resid = float((E - D).norm() / nD) + hosted = False + if factor_eligible: + # the factor path stores the delta losslessly, but the dequantizer materializes + # base + factors in the result dtype (bf16 here), so realized fidelity floors at + # the same ULP rounding an unquantized bf16 model applies to a merged delta + base16 = W_dq.to(torch.bfloat16).float() + realized = (W_dq.to(torch.bfloat16) + D.to(torch.bfloat16)).float() - base16 + applied_rho = float(realized.flatten() @ D.flatten() / nD.square()) + else: + applied_rho = rho + if (not control) and cli_args.host_rank > 0: + from sdnq.common import dtype_dict + if dtype_dict[deq_params['weights_dtype']]['num_bits'] < 8: + # mirror lora_sdnq.apply_hosted: seeded svd truncation, realized through the bf16 materialize + q = min(cli_args.host_rank, *D.shape) + rms = None + if calib_rms is not None and calib_rms.shape[-1] == D.shape[-1]: + rms = calib_rms.to(D.device, torch.float32).clamp(min=1e-8) + Dw = D * rms if rms is not None else D + with torch.random.fork_rng(devices=[D.device] if D.device.type == 'cuda' else []): + torch.manual_seed(0) + U, S, V = torch.svd_lowrank(Dw, q=min(q + 64, *D.shape), niter=8) + energy = float(S[:q].square().sum() / Dw.square().sum().clamp(min=1e-30)) + routed = False + if step_live is not None and not deq_params.get('use_svd', False): + sr = float(D.square().mean().sqrt() / step_live.float().mean()) + routed = sr > lora_sdnq.REQUANT_RATIO and energy < lora_sdnq.REQUANT_ENERGY + if not routed: # the loader routes fat, genuinely-truncated deltas back to requantize + Dk = (U[:, :q] * S[:q]) @ V[:, :q].t() + if rms is not None: + Dk = Dk / rms + base16 = W_dq.to(torch.bfloat16).float() + realized = (W_dq.to(torch.bfloat16) + Dk.to(torch.bfloat16)).float() - base16 + if rms is not None: # weighted norm: the diagonal-covariance output-error proxy the calibrated truncation optimizes + Dr = D * rms + applied_rho = float((realized * rms).flatten() @ Dr.flatten() / Dr.square().sum()) + else: + applied_rho = float(realized.flatten() @ D.flatten() / nD.square()) + hosted = True + return dict(rank=getattr(mods[0], 'dim', None), rms_delta=float(D.pow(2).mean().sqrt()), rms_weight=float(W_dq.pow(2).mean().sqrt()), + step_ratio=step_ratio, crossers=crossers, requant_rho=rho, requant_resid=resid, + factor_eligible=factor_eligible, hosted=hosted, applied_rho=applied_rho, + delta_energy=float(nD.square()), snr=snr, snr_plain=snr_plain, noise_rms=noise_rms, noise_source=noise_source) + + +def main(): + args = cli_args + model_dir = resolve_model_dir(args.model) + arch_mod = resolve_arch(args.arch) + with open(os.path.join(model_dir, 'config.json'), encoding='utf-8') as f: + model_config = json.load(f) + pre_quantized = model_config.get('quantization_config') is not None + + repo, bf16_repo, reference = None, None, None + quant_stamps, bf16_stamps, ref_stamps = {}, {}, {} + adapt = getattr(arch_mod, 'adapt_weights', None) # an arch refits deltas onto a live layout that differs from the trained one + if pre_quantized: + rprint(f'model: "{model_dir}" pre-quantized={pre_quantized}') + repo = QuantRepo(model_dir, model_config, arch=args.arch) + quant_stamps = stamp_index(repo.layers) + if args.reference: + reference = Bf16Repo(resolve_model_dir(args.reference)) + ref_stamps = stamp_index(k[:-len('.weight')] for k in reference.weight_map if k.endswith('.weight')) + rprint(f'reference: "{reference.model_dir}" tensors={len(reference.weight_map)}') + else: + bf16_repo = Bf16Repo(model_dir) + bf16_stamps = stamp_index(k[:-len('.weight')] for k in bf16_repo.weight_map if k.endswith('.weight')) + if args.dtype is None: + rprint('model is not quantized and no --dtype given: loras apply exactly, nothing to analyze') + return 0 + rprint(f'model: "{model_dir}" simulating dtype={args.dtype} group={args.group} hadamard={args.hadamard_group}') + + calib_stats = {} + if args.calib: + with safe_open(os.path.expanduser(args.calib), framework='pt', device='cpu') as f: + calib_stats = {k: f.get_tensor(k) for k in f.keys()} + rprint(f'calib: "{args.calib}" layers={len(calib_stats)}') + + noise_energies = {} # per module, shared by every lora: the base error does not depend on the adapter + def measure_noise(lname, err): + rms = calib_stats.get(lname) + plain = float(err.square().sum()) + weighted = float((err * rms.to(device, torch.float32)).square().sum()) if rms is not None and rms.shape[-1] == err.shape[-1] else plain + noise_energies[lname] = (plain, weighted) + return noise_energies[lname] + + report = {'model': model_dir, 'pre_quantized': pre_quantized, 'loras': []} + worst_effective = 1.0 + def write_report(): + if args.json: + with open(args.json, 'w', encoding='utf-8') as f: + json.dump(report, f, indent=2) + + for lora_path in args.lora: + lora_path = os.path.expanduser(lora_path) + try: + mapped, census, chunked = map_lora_modules(lora_path, arch_mod) + net = network.Network(os.path.basename(lora_path), StubOnDisk(lora_path)) + rows, unquantized, unmatched, failed, non_matrix = [], [], [], [], [] + keys = sorted(mapped) + if not args.full and len(keys) > args.sample: + keys = keys[::max(1, len(keys) // args.sample)][:args.sample] + for path in keys: + entries = mapped[path] + lname = path + noise = None + if pre_quantized: + if path not in repo.layers: + lname = quant_stamps.get(path.replace('.', '_'), '') + layer = repo.layers.get(lname) + if layer is None: + unmatched.append(path) + continue + deq = getattr(layer, 'sdnq_dequantizer', None) + if deq is None: + unquantized.append(path) + continue + if len(deq.original_shape) != 2: + non_matrix.append(path) + continue + layer = repo.materialize(lname) + W_dq = deq(layer.weight, layer.scale, zero_point=layer.zero_point, svd_up=layer.svd_up, svd_down=layer.svd_down, + skip_quantized_matmul=deq.use_quantized_matmul, dtype=torch.float32, skip_compile=True).to(device) + params = dict(weights_dtype=deq.weights_dtype, group_size=deq.group_size, hadamard_group_size=deq.hadamard_group_size, + use_hadamard=deq.use_hadamard, use_svd=layer.svd_up is not None, svd_rank=deq.svd_rank, svd_steps=deq.svd_steps, + use_codebook=getattr(deq, 'use_codebook', False)) + step_live = layer.scale.detach().to(device) + repo.release(lname) + sd_module = layer + if reference is not None: + noise = noise_energies.get(lname) + if noise is None: + W_ref = reference.get(f'{lname}.weight') + if W_ref is None: + W_ref = reference.get(f'{ref_stamps.get(lname.replace(".", "_"), "")}.weight') + if W_ref is not None and tuple(W_ref.shape) == tuple(W_dq.shape): + noise = measure_noise(lname, W_dq - W_ref.to(device, torch.float32)) + else: + W = bf16_repo.get(f'{path}.weight') + if W is None: + W = bf16_repo.get(f'{bf16_stamps.get(path.replace(".", "_"), "")}.weight') + if W is None: + unmatched.append(path) + continue + if W.ndim != 2: # norm/scale targets (e.g. adaLN_modulation) are 1-D; the quantizer and the stub both expect a matrix + non_matrix.append(path) + continue + if args.dtype == 'bf16': + W_dq = W.to(device, torch.bfloat16).float() + params = dict(weights_dtype='bf16', group_size=0, hadamard_group_size=0, use_hadamard=False) + step_live = None + else: + deq0, data0 = sdnq_quantize_layer_weight(W.to(device, torch.float32), layer_class_name='Linear', weights_dtype=args.dtype, + group_size=args.group, hadamard_group_size=args.hadamard_group, use_hadamard=args.hadamard_group > 0, + use_svd=False, use_quantized_matmul=False, dequantize_fp32=False, torch_dtype=torch.bfloat16) + W_dq = deq0(data0['weight'], data0['scale'], zero_point=data0['zero_point'], svd_up=None, svd_down=None, dtype=torch.float32, skip_compile=True) + params = dict(weights_dtype=args.dtype, group_size=deq0.group_size, hadamard_group_size=deq0.hadamard_group_size, use_hadamard=deq0.use_hadamard) + step_live = data0['scale'].detach() + noise = noise_energies.get(path) or measure_noise(path, W_dq - W.to(device, torch.float32)) # the simulated grid's own error, measured + sd_module = make_stub(W.shape) + try: + if adapt is not None and pre_quantized: + entries = [(fam, (adapt(sd_module, path, w, transformers=[repo.model]) or w) if fam == 'lora' else w) for fam, w in entries] + mods = [build_module(fam, path, w, net, sd_module) for fam, w in entries] + row = analyze_module(W_dq, params, mods, calib_rms=calib_stats.get(lname), step_live=step_live, noise=noise) + except Exception as e: # a family the tool cannot rebuild must not read as a clean module + failed.append(f'{path}: {type(e).__name__}: {e}') + del W_dq + continue + row.update(module=path, dtype=params['weights_dtype'], family='+'.join(f for f, _w in entries)) + rows.append(row) + del W_dq # the caching allocator reuses these; emptying it per module costs more than it saves + + scored = [r for r in rows if r['applied_rho'] is not None] # zero-delta modules have no retention to report + applied = sorted(r['applied_rho'] for r in scored) + median_applied = applied[len(applied) // 2] if applied else None + energy = sum(r['delta_energy'] for r in scored) + weighted = (sum(r['applied_rho'] * r['delta_energy'] for r in scored) / energy) if energy > 0 else None + n_exact = sum(1 for r in scored if r['factor_eligible']) + fb = [r['requant_rho'] for r in scored if not r['factor_eligible']] + fb_median = sorted(fb)[len(fb) // 2] if fb else None + if median_applied is not None: + worst_effective = min(worst_effective, median_applied) + snr_rows = [r for r in scored if r['snr'] is not None] + snr_median = sorted(r['snr'] for r in snr_rows)[len(snr_rows) // 2] if snr_rows else None + snr_energy = sum(r['delta_energy'] for r in snr_rows) + snr_weighted = (sum(r['snr'] * r['delta_energy'] for r in snr_rows) / snr_energy) if snr_energy > 0 else None + report['loras'].append({'file': lora_path, 'families': census, 'targets': len(mapped), 'unquantized': unquantized, + 'unmatched': unmatched, 'non_matrix': non_matrix, 'chunked': chunked, 'failed': failed, + 'exact_modules': n_exact, 'fallback_modules': len(fb), 'fallback_median_rho': fb_median, + 'median_applied_rho': median_applied, 'weighted_applied_rho': weighted, + 'snr_median': snr_median, 'snr_weighted': snr_weighted, 'modules': rows}) + write_report() # rewrite per file so a crash keeps completed work + rprint(f'\nlora: "{os.path.basename(lora_path)}" families={census or "none"} targets={len(mapped)} analyzed={len(rows)} scored={len(scored)} exact={n_exact} fallback={len(fb)} unquantized={len(unquantized)} unmatched={len(unmatched)} non_matrix={len(non_matrix)} chunked={chunked} failed={len(failed)}') + if median_applied is None: + rprint(' no analyzable modules: nothing measured') + else: + rprint(f' applied fidelity: median={median_applied:.3f} energy-weighted={weighted:.3f}' + (f' (fallback modules land at median rho={fb_median:.3f})' if fb_median is not None else '')) + if snr_median is not None: + rprint(f' delta over base quantization error: snr median={snr_median:.3g} energy-weighted={snr_weighted:.3g} ({snr_rows[0]["noise_source"]} noise, {"calibrated" if calib_stats else "weight-space"} norm)') + for f in failed[:3]: + rprint(f' [red]could not rebuild[/red]: {f}') + if fb: + worst = sorted((r for r in scored if not r['factor_eligible']), key=lambda r: r['requant_rho'])[:5] + rprint(' lowest-retention modules:') + for r in worst: + grid = f'step-ratio={r["step_ratio"]:.3f} crossers={r["crossers"]*100:5.1f}%' if r['step_ratio'] is not None else 'unquantized reference' + rprint(f' {r["module"]:48s} fam={r["family"]:5s} dtype={r["dtype"]} {grid} rho={r["requant_rho"]:.3f}') + del mapped, net + except KeyboardInterrupt: + raise + except Exception as e: # one broken file must not cost the rest of the batch + rprint(f'\n[red]lora failed[/red]: "{os.path.basename(lora_path)}" {type(e).__name__}: {e}') + report['loras'].append({'file': lora_path, 'error': f'{type(e).__name__}: {e}'}) + write_report() + if device.type == 'cuda': + torch.cuda.empty_cache() # once per file, after its modules are done + + report['complete'] = True + write_report() + if args.json: + rprint(f'\nreport: "{args.json}"') + if args.fail_under is not None and worst_effective < args.fail_under: + rprint(f'FAIL: effective fidelity {worst_effective:.3f} < {args.fail_under}') + return 2 + return 0 + + +if __name__ == '__main__': + with torch.inference_mode(): + sys.exit(main()) diff --git a/cli/sdnq-attention-benchmark.py b/cli/sdnq-attention-benchmark.py index 4d2af0ee0..fbcf9fb36 100755 --- a/cli/sdnq-attention-benchmark.py +++ b/cli/sdnq-attention-benchmark.py @@ -96,25 +96,75 @@ def save_transcript(path): file_console.print(renderable) console.print(f"results saved to {path}") +def key_padding_mask(cfg, device, keep=0.75): + # boolean key-padding mask over the kv axis, first keep fraction of keys valid + kv_tokens = cfg.get("kv_tokens", cfg["tokens"]) + attn_mask = torch.zeros(cfg["batch"], 1, 1, kv_tokens, device=device, dtype=torch.bool) + attn_mask[..., :int(kv_tokens * keep)] = True + return attn_mask + + +def krea2_segment_mask(cfg, device): + # the transformer's segment_mask: text is padded to a fixed 512 tokens ahead of the + # image tokens and the padded tail is masked for queries and keys both, so padding + # query rows are fully masked and yield nan under sdpa (the model nan_to_num's them) + valid = torch.ones(cfg["batch"], cfg["tokens"], device=device, dtype=torch.bool) + valid[:, 128:512] = False + return valid.unsqueeze(1).unsqueeze(2) * valid.unsqueeze(1).unsqueeze(3) + + +def build_preset_mask(cfg, device): + # dense masks come from the preset's mask_fn; the element guard keeps h3-scale presets + # from materializing multi-gigabyte masks, those shapes belong to block-granular masks + mask_fn = cfg.get("mask_fn") + if mask_fn is None: + return None + attn_mask = mask_fn(cfg, device) + if attn_mask is not None and attn_mask.numel() > 2**31: + raise ValueError(f"preset dense mask holds {attn_mask.numel():,} elements; this shape needs a block-granular mask, not a token mask") + return attn_mask + + shape_presets = { # geometry from the model transformer and text-encoder configs; - # optional keys: kv_tokens (cross-attention), kv_heads (gqa), causal + # optional keys: kv_tokens (cross-attention), kv_heads (gqa), causal, + # mask_fn (token-granular attn_mask builder), mask_nan_guard (fully-masked query + # rows nan under stock sdpa), iters/warmup (per-preset run overrides for very large + # shapes), ref_head_chunk (head-sliced fp32 reference to bound peak memory), + # sparse (token layout driving the sparse selector rows) "sd15": dict(batch=2, heads=8, tokens=4096, head_dim=40, desc="SD 1.5 unet self-attention at 512px, batched cfg, head dim padded 40 to 64"), "sdxl": dict(batch=2, heads=10, tokens=4096, head_dim=64, desc="SDXL unet self-attention at 1024px, batched cfg"), "sdxl-cross": dict(batch=2, heads=10, tokens=4096, kv_tokens=77, head_dim=64, desc="SDXL unet cross-attention at 1024px, 77 text tokens"), "qwen3-te": dict(batch=2, heads=16, kv_heads=8, tokens=512, head_dim=128, causal=True, desc="Qwen3 text encoder (Anima), causal gqa 16:8 heads, 512 token prompt"), "anima": dict(batch=1, heads=16, tokens=4096, head_dim=128, desc="Anima 1.0 self-attention at 1024px, one cfg pass"), "flux2": dict(batch=1, heads=32, tokens=4608, head_dim=128, desc="FLUX.2 Klein 9B joint attention at 1024px, 4096 image plus 512 text tokens"), - "krea2": dict(batch=1, heads=48, tokens=4608, head_dim=128, desc="Krea 2 12B joint attention at 1024px, 4096 image plus 512 text tokens (128 real), kv expanded from gqa 48:12, segment mask"), + "krea2": dict(batch=1, heads=48, tokens=4608, head_dim=128, mask_fn=krea2_segment_mask, mask_nan_guard=True, desc="Krea 2 12B joint attention at 1024px, 4096 image plus 512 text tokens (128 real), kv expanded from gqa 48:12, segment mask"), "wan22": dict(batch=1, heads=40, tokens=32760, head_dim=128, desc="Wan 2.2 A14B self-attention, 832x480 81 frames, one cfg pass"), "wan22-cfg": dict(batch=2, heads=40, tokens=32760, head_dim=128, desc="Wan 2.2 A14B self-attention, 832x480 81 frames, batched cfg"), "ltx2": dict(batch=1, heads=32, tokens=13376, head_dim=128, desc="LTX 2.3 self-attention, 1216x704 121 frames, one cfg pass"), - "masked": dict(batch=1, heads=32, tokens=4608, head_dim=128, desc="FLUX.2 Klein shape with boolean key-padding mask, 25% of keys masked"), + "h3": dict(batch=1, heads=56, tokens=38222, head_dim=128, iters=8, warmup=3, ref_head_chunk=14, + sparse=dict(layout=[("text", 0, 512), ("audio", 512, 926), ("video", 926, 38222)]), + desc="MiniMax H3 packed self-attention, 1344x768 124 frames (5.2s): 512 text + 414 audio + 37296 video rows, guidance-free"), + "h3-long": dict(batch=1, heads=56, tokens=109574, head_dim=128, iters=6, warmup=2, ref_head_chunk=8, config_timeout=1200, + sparse=dict(layout=[("text", 0, 512), ("audio", 512, 1718), ("video", 1718, 109574)]), + desc="MiniMax H3 packed self-attention, 1344x768 362 frames (15.1s): 512 text + 1206 audio + 107856 video rows"), + "masked": dict(batch=1, heads=32, tokens=4608, head_dim=128, mask_fn=key_padding_mask, desc="FLUX.2 Klein shape with boolean key-padding mask, 25% of keys masked"), } -full_run = ["sd15", "sdxl", "sdxl-cross", "qwen3-te", "anima", "flux2", "krea2", "wan22", "ltx2"] +# sparse crossover probes at fixed h3 geometry; the smallest token count where a sparse row +# beats dense past the verdict threshold is the measured minimum-sequence gate +for gate_tokens in (2048, 4096, 8192, 16384, 32768, 65536): + shape_presets[f"gate-{gate_tokens // 1024}k"] = dict( + batch=1, heads=56, tokens=gate_tokens, head_dim=128, + sparse=dict(layout=[("text", 0, 512), ("video", 512, gate_tokens)]), + desc=f"sparse crossover probe at h3 geometry, {gate_tokens} tokens", + **(dict(iters=8, warmup=3) if gate_tokens >= 32768 else {}), + ) +full_run = ["sd15", "sdxl", "sdxl-cross", "qwen3-te", "anima", "flux2", "krea2", "wan22", "ltx2", "h3"] +sparse_run = ["krea2", "h3", "h3-long"] +gate_run = [f"gate-{tokens // 1024}k" for tokens in (2048, 4096, 8192, 16384, 32768, 65536)] # settings advice comes from a self-attention shape with the full config set; cross-attention # and text-encoder shapes measure the hijack's cost there but would mislead as global advice -recommendation_presets = ["flux2", "krea2", "anima", "sdxl", "wan22", "ltx2", "sd15"] +recommendation_presets = ["flux2", "krea2", "anima", "sdxl", "wan22", "ltx2", "h3", "sd15"] default_shapes = "sdxl,flux2" all_sections = ["attention", "dequant", "block"] @@ -122,11 +172,16 @@ all_sections = ["attention", "dequant", "block"] # measures a complete configuration of weights dtype x matmul path x attention end to end # generic dit-block geometries from the model transformer configs: flux.1 (3072 wide, # 24 heads, 4x gelu ff, 4096 image plus 512 text tokens) and krea 2 (6144 wide, 48 heads -# after gqa expansion, swiglu at 16384, same joint sequence) +# after gqa expansion, swiglu at 16384, same joint sequence); optional keys: head_dim +# (attention width when heads*head_dim != hidden) and mlp ("gelu" default or "swiglu") block_geometries = { "flux1": dict(hidden=3072, heads=24, mlp_dim=12288, tokens=4608), "krea2": dict(hidden=6144, heads=48, mlp_dim=16384, tokens=4608), + # minimax h3: attention wider than the residual stream (56*128 > 5376), swiglu mlp; the + # full 124-frame token count makes the block section long, so it runs only when selected + "h3": dict(hidden=5376, heads=56, head_dim=128, mlp_dim=14336, mlp="swiglu", tokens=38222, iters=6, warmup=2, config_timeout=900), } +default_block_geometries = "flux1,krea2" block_geometry = block_geometries["flux1"] # active geometry; bench_block_section iterates block_attention_specs = { "sdpa": None, # stock torch sdpa @@ -139,6 +194,19 @@ block_attention_specs = { "sage": "sage", # external baselines, resolved to the sage wrappers in build_bench_block "sage fp16 accum": "sagefp16", } +# attention-table config id measuring the same kernel as each block attention spec, for the +# cross-instrument compute split; specs without a standalone row map to None +block_spec_attention_ids = { + "sdpa": "base", + "atten int8": "int8", + "atten int8 smooth": "smooth", + "atten int8 hadamard": "hadamard", + "atten full": "full", + "atten pv accum": "pvaccum", + "atten fp16 accum": "fp16full-accum", + "sage": "sage", + "sage fp16 accum": "sagefp16", +} # id, weights config (None = bf16), use quantized matmul, attention spec; fp8/fp4 rows use the # dequant path: quantized matmul auto-selects fp8 for float dtypes, unsupported before sm_89 block_configs = [ @@ -173,8 +241,19 @@ bench_configs = [ ("sage", "sageattention", None), # label resolved to the dispatched kernel by sage_kernel_label ("sagefp16", "sage int8 qk + fp16 pv, fp16 accum", None), # sm86 only ("amdflash", "triton flash (amd)", None), + ("flex", "flex attention, dense", None), # compiled: flex reads its block lists only under compile + ("flex-sparse100", "flex + selector, budget 100%", None), # the selector runs but keeps everything, so this row is its overhead alone + ("flex-sparse50", "flex + selector, budget 50%", None), + ("flex-sparse30", "flex + selector, budget 30%", None), + ("flex-sparse15", "flex + selector, budget 15%", None), + ("flex-radial30", "flex + static radial band, 30%", None), # density matched control with no per-call producer ("noquant", "sdnq, quantized matmul off", dict(do_quantize=False)), ("int8", "sdnq int8 qk", dict(matmul_dtype="auto", pv_matmul_dtype="auto")), + ("int8-sparse100", "sdnq int8 qk + selector, budget 100%", dict(matmul_dtype="auto", pv_matmul_dtype="auto")), # the selector runs but keeps everything, so this row is its overhead on the quantized kernel + ("int8-sparse50", "sdnq int8 qk + selector, budget 50%", dict(matmul_dtype="auto", pv_matmul_dtype="auto")), + ("int8-sparse30", "sdnq int8 qk + selector, budget 30%", dict(matmul_dtype="auto", pv_matmul_dtype="auto")), + ("int8-sparse15", "sdnq int8 qk + selector, budget 15%", dict(matmul_dtype="auto", pv_matmul_dtype="auto")), + ("int8-radial30", "sdnq int8 qk + static radial band, 30%", dict(matmul_dtype="auto", pv_matmul_dtype="auto")), # density matched control with no per-call producer ("smooth", "sdnq int8 qk + smooth k", dict(matmul_dtype="auto", pv_matmul_dtype="auto", smooth_k=True)), ("hadamard", "sdnq int8 qk + hadamard", dict(matmul_dtype="auto", pv_matmul_dtype="auto", use_hadamard=True)), ("smooth_hadamard", "sdnq int8 qk + smooth + hadamard", dict(matmul_dtype="auto", pv_matmul_dtype="auto", smooth_k=True, use_hadamard=True)), @@ -193,7 +272,10 @@ bench_configs = [ # external baselines are compared against but never starred or recommended as sdnq configs; # the unsafe accum mode is measured and displayed under the same rule, since its overflow # tail lives outside what mean error can see -external_config_ids = ("base", "sage", "sagefp16", "amdflash") +# baselines and non-sdnq rows: reported, never recommended as an sdnq setting, and the sparse +# rows are lossy by design so a recommendation must not pick one for being fast +external_config_ids = ("base", "sage", "sagefp16", "amdflash", "flex") +sparse_config_ids = ("flex-sparse100", "flex-sparse50", "flex-sparse30", "flex-sparse15", "flex-radial30", "int8-sparse100", "int8-sparse50", "int8-sparse30", "int8-sparse15", "int8-radial30") unsafe_config_ids = ("pvaccum",) # every preset runs the full config list (availability gates still apply per config); only # hard technical exclusions live here, never runtime trims. sd15: compiling hadamard with @@ -281,18 +363,22 @@ def parse_cli(): parser.add_argument("--dequant-sweeps", type=str, default="all", help=f"comma-separated setting sweeps in the dequant section: {', '.join(all_dequant_sweeps)}; 'all' or 'none' (default: %(default)s)") parser.add_argument("--mm-backends", type=str, default="none", help=f"comma-separated quantized-matmul backends to compare in one run: {', '.join(all_mm_backends)}; 'none' benches only the backend this device selects (default: %(default)s)") parser.add_argument("--mm-rounds", type=int, default=2, help="alternating rounds per matmul backend, fastest kept, so clock drift cancels instead of favouring one backend (default: %(default)s)") + parser.add_argument("--configs", type=str, default="all", help=f"comma-separated attention configs: {', '.join(config_id for config_id, _label, _kwargs in bench_configs)}; 'all' runs every one (default: %(default)s)") parser.add_argument("--block-configs", type=str, default="all", help=f"comma-separated combined block configs: {', '.join(config_id for config_id, _w, _mm, _a in block_configs)}; 'all' runs every one (default: %(default)s)") - parser.add_argument("--shapes", type=str, default=default_shapes, help=f"comma-separated attention shape presets: {', '.join(shape_presets)}; 'all' runs {', '.join(full_run)} (default: %(default)s)") + parser.add_argument("--block-geometries", type=str, default=default_block_geometries, help=f"comma-separated block geometries: {', '.join(block_geometries)}; 'all' runs every one (default: %(default)s)") + parser.add_argument("--shapes", type=str, default=default_shapes, help=f"comma-separated attention shape presets: {', '.join(shape_presets)}; 'all' runs {', '.join(full_run)}, 'sparse' and 'gate' run the sparse and crossover lists (default: %(default)s)") parser.add_argument("--iters", type=int, default=12, help="minimum timed iterations per config, scaled up for fast kernels (default: %(default)s)") parser.add_argument("--warmup", type=int, default=4, help="minimum warmup iterations per config, scaled up for fast kernels (default: %(default)s)") parser.add_argument("--skip-checks", action="store_true", help="skip kernel correctness checks") parser.add_argument("--skip-bench", action="store_true", help="skip benchmarks, run checks and the fp8 and compile probes only") parser.add_argument("--dtype", type=str, default="auto", choices=["auto", "bf16", "fp16"], help="tensor dtype for benchmarks; auto uses the dtype the webui selected for this gpu (default: %(default)s)") - parser.add_argument("--config-timeout", type=int, default=300, help="best effort: abort a config whose compile plus first call exceeds this many seconds, 0 disables; cannot interrupt native-level hangs (default: %(default)s)") + parser.add_argument("--config-timeout", type=int, default=None, help="best effort: abort a config whose compile plus first call exceeds this many seconds, 0 disables; cannot interrupt native-level hangs (default: 300, or the limit a preset or block geometry declares for itself)") parser.add_argument("--save", type=str, default="auto", help="plain-text copy of all tables and notes; 'auto' (default) names it -t-.txt in the output directory, 'none' disables, anything else is used as the path") parser.add_argument("--json", type=str, default="auto", help="structured results (environment, probes, per-shape and dequant timings, recommendations); 'auto' (default) names it -t-.json in the output directory, 'none' disables, anything else is used as the path") parser.add_argument("--outdir", type=str, default=None, help="directory for auto-named outputs (default: $SDNQ_BENCH_DIR, or benchmarks/ under the sdnext root)") args = parser.parse_args() + args.timeout_flag = args.config_timeout # None lets a preset or block geometry declare its own limit + args.config_timeout = resolve_timeout(args.timeout_flag) sys.argv = sys.argv[:1] # sdnext parses argv again on import and rejects unknown arguments return args @@ -379,7 +465,7 @@ def load_sdnext(): raise detail = f"exited with code {e.code}" if isinstance(e, SystemExit) else f"{type(e).__name__}: {e}" console.print(f"[red]sdnext failed to start: {detail}[/red]") - text = startup_log["text"].strip() + text = startup_log["text"].strip() # pylint: disable=used-before-assignment if text: console.print(Panel(escape(text[-4000:]), title="sdnext startup log", box=ROUNDED_BOX)) console.print("run from the sdnext root with the venv active; triton is required") @@ -425,6 +511,16 @@ def atten_supports_fp16_accum(): return False +def atten_supports_block_mask(): + # the sdnq sparse rows feed the kernel's block_mask kwarg; skip them on builds without it + if sdnq_triton_atten is None: + return False + try: + return "block_mask" in inspect.signature(inspect.unwrap(sdnq_triton_atten)).parameters + except (TypeError, ValueError): + return False + + def triton_mm_supports_fp16_accum(): try: from sdnq.kernels import triton_mm, triton_scaled_mm @@ -450,6 +546,56 @@ def triton_mm_fp16_accum(): triton_mm.USE_FP16_ACCUM, triton_scaled_mm.USE_FP16_ACCUM = saved +flex_budgets = {"flex-sparse100": 1.0, "flex-sparse50": 0.50, "flex-sparse30": 0.30, "flex-sparse15": 0.15} +sdnq_sparse_budgets = {"int8-sparse100": 1.0, "int8-sparse50": 0.50, "int8-sparse30": 0.30, "int8-sparse15": 0.15} + + +def is_sdnq_sparse(config_id): + return config_id in sdnq_sparse_budgets or config_id == "int8-radial30" + + +def make_sdnq_sparse_fn(config_id, q, k, v, attn_mask, kwargs, causal, gqa): + """The producer the flex rows time, feeding the quantized kernel's block mask input instead.""" + from modules.attention.sparse import selector as sparse_selector + + def attend(selection): + return sdnq_triton_atten(q, k, v, attn_mask=attn_mask, is_causal=causal, enable_gqa=gqa, block_mask=selection.keep, block_mask_m=selection.block_q, block_mask_n=selection.block_kv, **kwargs) + if config_id == "int8-radial30": + static = sparse_selector.radial_blocks(q.shape[-2], k.shape[-2], 0.30, sparse_selector.SparseSpec(), q.device) + return lambda: attend(static) + spec = sparse_selector.SparseSpec(budget=sdnq_sparse_budgets[config_id], force=True) + cache_key = ("bench", config_id, tuple(q.shape), tuple(k.shape)) + return lambda: attend(sparse_selector.select_blocks(q, k, spec, cache_key=cache_key)) + + +def flex_available(): + try: + import modules.attention.sparse.flex # pylint: disable=unused-import + return torch.cuda.is_available() + except Exception: + return False + + +def make_flex_fn(config_id, q, k, v, scale, gqa): + """Time the selector inside the attention it accelerates; a producer measured on its own looks free and is not.""" + from modules.attention.sparse import flex as sparse_flex, selector as sparse_selector + call = sparse_flex.flex_call() + if config_id == "flex": + return lambda: call(q, k, v, scale=scale, enable_gqa=gqa) + if config_id == "flex-radial30": + # a static pattern is built once by construction, which is exactly the advantage it has to defend + static = sparse_flex.to_block_mask(sparse_selector.radial_blocks(q.shape[-2], k.shape[-2], 0.30, sparse_selector.SparseSpec(), q.device)) + return lambda: call(q, k, v, block_mask=static, scale=scale, enable_gqa=gqa) + spec = sparse_selector.SparseSpec(budget=flex_budgets[config_id], force=True) + + cache_key = ("bench", config_id, tuple(q.shape), tuple(k.shape)) # the webui caches the geometry per layout, so measure that path + + def run(): + selection = sparse_selector.select_blocks(q, k, spec, cache_key=cache_key) + return call(q, k, v, block_mask=sparse_flex.to_block_mask(selection), scale=scale, enable_gqa=gqa) + return run + + def sage_attention(): # mirror the backend selection from modules/attention.py: sm86 needs the cuda backend try: @@ -545,13 +691,23 @@ def make_qkv(batch, heads, tokens, head_dim, structured=True, kv_heads=None, kv_ return q, k, v -def fp32_reference(q, k, v, **kwargs): +def fp32_reference(q, k, v, head_chunk=0, **kwargs): # sdnext enables tf32 globally; a math-backend dispatch fallback would degrade the reference to tf32 precision tf32_matmul = torch.backends.cuda.matmul.allow_tf32 tf32_cudnn = torch.backends.cudnn.allow_tf32 torch.backends.cuda.matmul.allow_tf32 = False torch.backends.cudnn.allow_tf32 = False try: + if head_chunk and not kwargs.get("enable_gqa") and q.shape[1] > head_chunk: + # head-sliced reference: bounds the fp32 peak on very long sequences; gqa shapes + # keep the one-shot path since slicing q heads would have to regroup kv heads + attn_mask = kwargs.pop("attn_mask", None) + outs = [] + for start in range(0, q.shape[1], head_chunk): + heads = slice(start, start + head_chunk) + mask_slice = attn_mask[:, heads] if attn_mask is not None and attn_mask.shape[1] > 1 else attn_mask + outs.append(torch.nn.functional.scaled_dot_product_attention(q[:, heads].to(torch.float32), k[:, heads].to(torch.float32), v[:, heads].to(torch.float32), attn_mask=mask_slice, **kwargs)) + return torch.cat(outs, dim=1) return torch.nn.functional.scaled_dot_product_attention(q.to(torch.float32), k.to(torch.float32), v.to(torch.float32), **kwargs) finally: torch.backends.cuda.matmul.allow_tf32 = tf32_matmul @@ -641,6 +797,13 @@ def live_progress(): return progress, task +def resolve_timeout(flag, declared=None): + # the cli flag wins when given; otherwise a preset or block geometry may declare its own limit + if flag is not None: + return flag + return 300 if declared is None else declared + + @contextmanager def time_limit(seconds, label): # torch.compile can spin indefinitely in sympy/inductor on pathological graphs @@ -721,6 +884,9 @@ def run_drift_sigma(): drift_override = None verdict_z = 1.28 # one-sided 90%: an on/off verdict is only stated when its margin test clears this +# split instruments A and B differ systematically (strided views out of the fused projection vs +# contiguous standalone tensors): 0.1-2.5% over 19 same-kernel rows at h3, far below the 17-25% hadamard gap +split_instrument_offset = 0.05 def sidak_z_for(count): @@ -826,7 +992,7 @@ def print_environment(fp8_result, prep_status, prep_detail, weight_dequant_resul lines.append(f"float8_e4m3fn matmul: [red]not supported on this gpu, selecting it fails generation[/red] [dim]({escape(fp8_result['qk'][1])})[/dim]") else: lines.append(f"float8_e4m3fn matmul: [red]failed to compile in this environment, selecting it fails generation[/red]; the error is not the hardware-capability signature, a torch or triton issue is more likely than the gpu [dim]({escape(fp8_result['qk'][1])})[/dim]") - lines.append(f"sdnq attention enabled in current config: {'[green]yes[/green]' if 'SDNQ attention' in shared.opts.sdp_overrides else '[yellow]no, enable via Compute Settings -> SDP overrides (requires restart)[/yellow]'}") + lines.append(f"sdnq attention enabled in current config: {'[green]yes[/green]' if 'SDNQ attention' in shared.opts.cross_attention_optimization else '[yellow]no, enable via Compute Settings -> Cross Attention (requires restart)[/yellow]'}") if prep_status == "disabled": lines.append("compiled input prep: torch.compile disabled in config, input prep runs eager") elif prep_status == "working": @@ -853,6 +1019,8 @@ def print_environment(fp8_result, prep_status, prep_detail, weight_dequant_resul lines.append(f"compiled weight dequant, float8_e5m2 storage: {e5m2_verdict}") if not atten_supports_fp16_accum(): lines.append("fp16 accumulation kwarg: [yellow]absent in this sdnq build, accum rows skipped[/yellow]") + if not atten_supports_block_mask(): + lines.append("block mask kwarg: [yellow]absent in this sdnq build, sdnq sparse rows skipped[/yellow]") overrides = [f"{key}={value}" for key, value in os.environ.items() if key.startswith("SDNQ_TRITON_ATTEN") or key.startswith("SDNQ_TRITON_MM") or key.startswith("SDNQ_ALLOW_FP8") or key.startswith("SDNQ_COMPILE")] if overrides: lines.append(f"env overrides: {' '.join(overrides)}") @@ -870,6 +1038,7 @@ def print_environment(fp8_result, prep_status, prep_detail, weight_dequant_resul **runtime_versions, fp8_attention_matmul=fp8_result["qk"][0] if fp8_result is not None else None, atten_fp16_accum=atten_supports_fp16_accum(), + atten_block_mask=atten_supports_block_mask(), triton_mm_fp16_accum=os.environ.get("SDNQ_TRITON_MM_USE_FP16_ACCUM", None), compiled_input_prep=prep_status, fp8_compile_gate=fp8_compile_gate_flag(), @@ -1009,35 +1178,56 @@ def make_source_weight(out_features, in_features, seed=1234): class BenchBlock(torch.nn.Module): - # dit-style block: fused qkv self-attention plus a gelu mlp, both with residuals; the - # attention_fn attribute is set per benchmark config (stock sdpa or sdnq attention) - def __init__(self, hidden, heads, mlp_dim, device=None, dtype=None): + # dit-style block: fused qkv self-attention plus a gelu or swiglu mlp, both with residuals; + # head_dim decouples attention width from hidden for models whose attention is wider than + # the residual stream; the attention_fn attribute is set per benchmark config + def __init__(self, hidden, heads, mlp_dim, head_dim=None, mlp="gelu", device=None, dtype=None): super().__init__() self.heads = heads + self.head_dim = head_dim if head_dim is not None else hidden // heads + self.mlp = mlp + inner = heads * self.head_dim self.norm1 = torch.nn.LayerNorm(hidden, elementwise_affine=False, device=device, dtype=dtype) self.norm2 = torch.nn.LayerNorm(hidden, elementwise_affine=False, device=device, dtype=dtype) - self.qkv = torch.nn.Linear(hidden, hidden * 3, bias=False, device=device, dtype=dtype) - self.proj = torch.nn.Linear(hidden, hidden, bias=False, device=device, dtype=dtype) + self.qkv = torch.nn.Linear(hidden, inner * 3, bias=False, device=device, dtype=dtype) + self.proj = torch.nn.Linear(inner, hidden, bias=False, device=device, dtype=dtype) self.up = torch.nn.Linear(hidden, mlp_dim, bias=False, device=device, dtype=dtype) + if mlp == "swiglu": + self.gate = torch.nn.Linear(hidden, mlp_dim, bias=False, device=device, dtype=dtype) self.down = torch.nn.Linear(mlp_dim, hidden, bias=False, device=device, dtype=dtype) self.attention_fn = None def forward(self, x): - batch, tokens, channels = x.shape + batch, tokens, _channels = x.shape h = self.norm1(x) - qkv = self.qkv(h).view(batch, tokens, 3, self.heads, channels // self.heads).permute(2, 0, 3, 1, 4) - attn = self.attention_fn(qkv[0], qkv[1], qkv[2]).transpose(1, 2).reshape(batch, tokens, channels) + qkv = self.qkv(h).view(batch, tokens, 3, self.heads, self.head_dim).permute(2, 0, 3, 1, 4) + attn = self.attention_fn(qkv[0], qkv[1], qkv[2]).transpose(1, 2).reshape(batch, tokens, self.heads * self.head_dim) x = x + self.proj(attn) h = self.norm2(x) + if self.mlp == "swiglu": + return x + self.down(torch.nn.functional.silu(self.gate(h)) * self.up(h)) return x + self.down(torch.nn.functional.gelu(self.up(h))) +def build_block_module(dtype=None): + # construct a block for the active geometry; every construction site goes through here so + # geometry keys are read in exactly one place + return BenchBlock( + block_geometry["hidden"], block_geometry["heads"], block_geometry["mlp_dim"], + head_dim=block_geometry.get("head_dim"), mlp=block_geometry.get("mlp", "gelu"), + device=torch_device, dtype=dtype if dtype is not None else bench_dtype, + ) + + def make_block_master(): - # one master weight set shared by every block config, so all rows quantize identical weights - hidden, heads, mlp_dim = block_geometry["hidden"], block_geometry["heads"], block_geometry["mlp_dim"] - block = BenchBlock(hidden, heads, mlp_dim, device=torch_device, dtype=bench_dtype) + # one master weight set shared by every block config, so all rows quantize identical weights; + # seed order keeps gelu geometries bitwise stable, swiglu appends its gate after up + block = build_block_module() + linears = [block.qkv, block.proj, block.up, block.down] + if hasattr(block, "gate"): + linears.append(block.gate) with torch.no_grad(): - for seed, linear in enumerate((block.qkv, block.proj, block.up, block.down), start=1): + for seed, linear in enumerate(linears, start=1): linear.weight.copy_(make_source_weight(linear.out_features, linear.in_features, seed=seed)) return {key: value.clone() for key, value in block.state_dict().items()} @@ -1045,8 +1235,7 @@ def make_block_master(): def build_bench_block(master_sd, weights_cfg, use_mm, attention_spec): from sdnq import SDNQConfig from sdnq.quantizer import apply_sdnq_to_module - hidden, heads, mlp_dim = block_geometry["hidden"], block_geometry["heads"], block_geometry["mlp_dim"] - block = BenchBlock(hidden, heads, mlp_dim, device=torch_device, dtype=bench_dtype) + block = build_block_module() block.load_state_dict(master_sd) block.eval() for param in block.parameters(): @@ -1335,36 +1524,29 @@ def make_prep_fn(q, k, v, attn_mask, kwargs, is_causal=False, enable_gqa=False): return prep -def bench_shape(preset, iters, warmup, position=None, config_timeout=300, fp8_result=None): +def bench_shape(preset, iters, warmup, position=None, config_timeout=None, fp8_result=None, selected=None): preset_cfg = shape_presets[preset] + config_timeout = resolve_timeout(config_timeout, preset_cfg.get("config_timeout")) batch, heads, tokens, head_dim = preset_cfg["batch"], preset_cfg["heads"], preset_cfg["tokens"], preset_cfg["head_dim"] kv_tokens = preset_cfg.get("kv_tokens", tokens) kv_heads = preset_cfg.get("kv_heads", heads) causal = preset_cfg.get("causal", False) gqa = kv_heads != heads description = preset_cfg["desc"] + iters = preset_cfg.get("iters", iters) + warmup = preset_cfg.get("warmup", warmup) + ref_head_chunk = preset_cfg.get("ref_head_chunk", 0) excluded_configs = preset_excluded_configs.get(preset, set()) if preset == "sd15": emit("[yellow]sd15: hadamard configs skipped, compiling hadamard with a non pow2 head dim currently hangs torch inductor[/yellow]") - attn_mask = None - mask_nan_guard = False - if preset == "masked": - attn_mask = torch.zeros(batch, 1, 1, tokens, device=torch_device, dtype=torch.bool) - attn_mask[..., :int(tokens * 0.75)] = True - elif preset == "krea2": - # the transformer's segment_mask: text is padded to a fixed 512 tokens ahead of the - # image tokens and the padded tail is masked for queries and keys both, so padding - # query rows are fully masked and yield nan under sdpa (the model nan_to_num's them) - valid = torch.ones(batch, tokens, device=torch_device, dtype=torch.bool) - valid[:, 128:512] = False - attn_mask = valid.unsqueeze(1).unsqueeze(2) * valid.unsqueeze(1).unsqueeze(3) - mask_nan_guard = True + attn_mask = build_preset_mask(preset_cfg, torch_device) + mask_nan_guard = preset_cfg.get("mask_nan_guard", False) sage = sage_attention() sage_fp16 = sage_attention_fp16_accum() amd_flash = amd_triton_flash() selected_configs = [] for config_id, label, kwargs in bench_configs: - if config_id in excluded_configs: + if config_id in excluded_configs or (selected is not None and config_id not in selected): continue if config_id == "sage" and (sage is None or attn_mask is not None or head_dim not in {64, 96, 128} or kv_tokens != tokens or gqa or causal): continue @@ -1372,6 +1554,10 @@ def bench_shape(preset, iters, warmup, position=None, config_timeout=300, fp8_re continue if config_id == "amdflash" and (amd_flash is None or attn_mask is not None or head_dim > 128 or gqa): continue + if config_id.startswith("flex") and (not flex_available() or attn_mask is not None or causal or kv_tokens != tokens): + continue # a block only mask cannot carry a token mask or a causal rule, and cross attention is not sparsified + if is_sdnq_sparse(config_id) and (not atten_supports_block_mask() or causal or kv_tokens != tokens): + continue # the kernel composes a token mask with the block mask, so only the causal and cross attention rules apply if config_id == "fp8qk" and not (fp8_result and fp8_result["qk"][0]): continue if config_id == "fp8pv" and not (fp8_result and fp8_result["pv"][0]): @@ -1413,7 +1599,7 @@ def bench_shape(preset, iters, warmup, position=None, config_timeout=300, fp8_re progress.update(task, description=f"{prefix}{preset}: preparing inputs and fp32 reference") q, k, v = make_qkv(batch, heads, tokens, head_dim, kv_heads=kv_heads, kv_tokens=kv_tokens) scale = head_dim ** -0.5 - ref = fp32_reference(q, k, v, attn_mask=attn_mask, is_causal=causal, enable_gqa=gqa) + ref = fp32_reference(q, k, v, attn_mask=attn_mask, is_causal=causal, enable_gqa=gqa, head_chunk=ref_head_chunk) if mask_nan_guard: ref = torch.nan_to_num(ref) anchor_fn = None @@ -1432,6 +1618,10 @@ def bench_shape(preset, iters, warmup, position=None, config_timeout=300, fp8_re elif config_id == "amdflash": def fn(sm=scale): return amd_flash(q, k, v, sm, is_causal=causal) + elif config_id.startswith("flex"): + fn = make_flex_fn(config_id, q, k, v, scale, gqa) + elif is_sdnq_sparse(config_id): + fn = make_sdnq_sparse_fn(config_id, q, k, v, attn_mask, kwargs, causal, gqa) else: def fn(kw=kwargs, mask=attn_mask): return sdnq_triton_atten(q, k, v, attn_mask=mask, is_causal=causal, enable_gqa=gqa, **kw) @@ -2039,7 +2229,7 @@ def resolved_group_label(layer, in_features): return "row" -def bench_group_sizes(shape_label, out_features, in_features, plain_results, selected_dtypes, iters, warmup, config_timeout=300): +def bench_group_sizes(shape_label, out_features, in_features, plain_results, selected_dtypes, iters, warmup, config_timeout=300): # pylint: disable=unused-argument # the Group size setting: 0 = auto, -1 = row-wise, explicit values snap to a divisor of # in_features; grouping forces a per-forward re-quantize when quantized matmul is on, so # the mm cells price that cost alongside the accuracy gain @@ -2514,17 +2704,24 @@ def block_label(weights_cfg, use_mm, attention_spec): return f"{weights_part} + {attention_spec}" -def bench_block_section(iters, warmup, config_timeout=300, selected=None): +def bench_block_section(iters, warmup, config_timeout=None, selected=None, geometries=None): global block_geometry # pylint: disable=global-statement all_results = {} for family, geometry in block_geometries.items(): + if geometries is not None and family not in geometries: + continue block_geometry = geometry - results = bench_block_geometry(iters, warmup, config_timeout=config_timeout, selected=selected) + geometry_iters = geometry.get("iters", iters) + geometry_warmup = geometry.get("warmup", warmup) + geometry_timeout = resolve_timeout(config_timeout, geometry.get("config_timeout")) + results = bench_block_geometry(geometry_iters, geometry_warmup, config_timeout=geometry_timeout, selected=selected) all_results[family] = results - report.setdefault("blocks", {})[family] = dict(geometry=dict(geometry), results=results) - # the first family also lands at the flat block key, which replays and the buyback + report.setdefault("blocks", {})[family] = dict(geometry=dict(geometry), results=results, split=None) + if not all_results: + return {} + # the first family run also lands at the flat block key, which replays and the buyback # veto fall back to when no family matches the reference shape - primary = next(iter(block_geometries)) + primary = next(iter(all_results)) report["block"] = report["blocks"][primary] return all_results.get(primary, {}) @@ -2556,7 +2753,7 @@ def bench_block_geometry(iters, warmup, config_timeout=300, selected=None): table.add_column("out err", justify="right") table.add_column("max tok err", justify="right") table.add_column("err x4 blocks", justify="right") - panel = Panel(table, title=f"combined block: hidden={hidden} heads={heads} mlp={mlp_dim} tokens={tokens} {dtype_label()}", subtitle="[dim]dit block, fused qkv + gelu mlp with residuals; err vs an fp32 reference block, max tok = worst single token, x4 = four stacked blocks[/dim]", box=ROUNDED_BOX, expand=False) + panel = Panel(table, title=f"combined block: hidden={hidden} heads={heads} mlp={mlp_dim} tokens={tokens} {dtype_label()}", subtitle="[dim]dit block, fused qkv attention + mlp with residuals; err vs an fp32 reference block, max tok = worst single token, x4 = four stacked blocks[/dim]", box=ROUNDED_BOX, expand=False) def run_depth(block, x0, depth): h = x0 @@ -2572,7 +2769,7 @@ def bench_block_geometry(iters, warmup, config_timeout=300, selected=None): master = make_block_master() generator = torch.Generator(device=torch_device).manual_seed(7) x = torch.randn(1, tokens, hidden, device=torch_device, dtype=bench_dtype, generator=generator) - ref_block = BenchBlock(hidden, heads, mlp_dim, device=torch_device, dtype=torch.float32) + ref_block = build_block_module(dtype=torch.float32) ref_block.load_state_dict(master) ref_block.eval() def ref_attention(q, k, v): @@ -2619,6 +2816,15 @@ def bench_block_geometry(iters, warmup, config_timeout=300, selected=None): phase("measuring depth-4 error") with torch.no_grad(): entry["err4"] = rel_err(run_depth(block, x, 4), ref_out4) + phase("timing identity-attention variant") + real_attention_fn = block.attention_fn + def identity_attention_fn(q, k, v): # pylint: disable=unused-argument # same shapes and permutes, zero attention flops + return v + block.attention_fn = identity_attention_fn + try: + entry["identity_ms"], entry["identity_ms_sigma"] = bench_stats(fn, warmup, iters, on_phase=phase) + finally: + block.attention_fn = real_attention_fn del block, out if base_ms is None: base_ms = entry["ms"] @@ -2643,7 +2849,7 @@ def bench_block_geometry(iters, warmup, config_timeout=300, selected=None): weights_mode = str(getattr(shared.opts, "sdnq_quantize_weights_mode", "")) current_id = None if weights_mode == "int8" and getattr(shared.opts, "sdnq_quantize_matmul_mode", "disabled") != "disabled": - current_id = "int8-mm-atten" if "SDNQ attention" in shared.opts.sdp_overrides else "int8-mm" + current_id = "int8-mm-atten" if "SDNQ attention" in shared.opts.cross_attention_optimization else "int8-mm" if current_id and results.get(current_id, {}).get("ms"): notes.append(f"current config runs the {results[current_id]['label']} row for int8-quantized models") if any(entry.get("ms") for config_id, entry in results.items() if config_id.endswith("sagefp16")): @@ -2653,6 +2859,72 @@ def bench_block_geometry(iters, warmup, config_timeout=300, selected=None): return results +def emit_block_splits(): + # instrument B reads the attention tables, so the split renders once both sections are in + for family, data in (report.get("blocks") or {}).items(): + data["split"] = block_split_table(family, data["geometry"], data["results"]) + + +def block_split_table(family, geometry, results): + # compute split per config from two independent instruments: A subtracts the identity- + # attention variant timed inside the block, B reads the standalone attention table at the + # same geometry from this run; a speedup ceiling is only stated where the two agree + head_dim = geometry.get("head_dim") or geometry["hidden"] // geometry["heads"] + expected_geometry = f"batch=1 heads={geometry['heads']} tokens={geometry['tokens']} head_dim={head_dim}" + attention_preset = None + for preset_name, data in (report.get("attention") or {}).items(): + if data.get("geometry") == expected_geometry and not shape_presets.get(preset_name, {}).get("mask_fn"): + attention_preset = preset_name + break + attention_results = (report.get("attention") or {}).get(attention_preset, {}).get("results", {}) if attention_preset else {} + spec_by_config = {config_id: spec for config_id, _w, _mm, spec in block_configs} + budgets = (0.5, 0.3, 0.15) + + table = Table(box=box.SIMPLE_HEAVY) + table.add_column("config") + table.add_column("block ms", justify="right") + table.add_column("rest ms", justify="right") + table.add_column("attn A", justify="right") + table.add_column("attn B", justify="right") + table.add_column("agree", justify="right") + for budget in budgets: + table.add_column(f"ceil@{int(budget * 100)}%", justify="right") + + split = {} + for config_id, entry in results.items(): + ms, identity_ms = entry.get("ms"), entry.get("identity_ms") + if not ms or not identity_ms: + continue + attn_a = ms - identity_ms + if attn_a <= 0: + continue + attention_id = block_spec_attention_ids.get(spec_by_config.get(config_id)) + attention_entry = attention_results.get(attention_id) or {} + attn_b = attention_entry.get("ms") + agree = None + if attn_b: + # subtraction amplifies the relative sigma of instrument A by ms/attn_a + sigma_a = (row_sigma(entry) or 0.0) * (ms / attn_a) + sigma_b = row_sigma(attention_entry, "ms") or 0.0 + threshold = max(verdict_z * math.sqrt(sigma_a * sigma_a + sigma_b * sigma_b), run_drift_sigma(), split_instrument_offset) + agree = abs(math.log(attn_a / attn_b)) <= threshold + ceilings = {budget: ms / (budget * attn_a + identity_ms) for budget in budgets} if agree else None + split[config_id] = dict(ms=ms, rest_ms=identity_ms, attn_a_ms=attn_a, attn_b_ms=attn_b, agree=agree, ceilings=ceilings) + agree_cell = "-" if agree is None else ("yes" if agree else "[yellow]no[/yellow]") + ceiling_cells = [f"{ceilings[budget]:.2f}x" if ceilings else "-" for budget in budgets] + table.add_row(entry["label"], f"{ms:8.3f} ms", f"{identity_ms:8.3f} ms", f"{attn_a:8.3f} ms", f"{attn_b:8.3f} ms" if attn_b else "-", agree_cell, *ceiling_cells) + + if split: + subtitle = "[dim]rest = identity-attention variant; A = block minus rest, B = standalone attention table" + subtitle += f" ({attention_preset})" if attention_preset else " (no matching attention preset this run)" + subtitle += "; ceilings are per-block upper bounds at the given kv budget, generation adds te/vae/projections[/dim]" + emit(Panel(table, title=f"compute split: {family}", subtitle=subtitle, box=ROUNDED_BOX, expand=False)) + disagreements = [config_id for config_id, row in split.items() if row["agree"] is False] + if disagreements: + emit(f"[yellow]split instruments disagree on {', '.join(disagreements)}; ceilings withheld there, treat the split with suspicion[/yellow]") + return split + + def measured(results, config_id): entry = results.get(config_id) or {} ms = entry.get("ms") @@ -2661,7 +2933,7 @@ def measured(results, config_id): def best_config(results): # lowest error among rows within 5% of the fastest sdnq time - candidates = [(config_id, entry["ms"], entry["err"]) for config_id, entry in results.items() if entry.get("ms") is not None and config_id not in external_config_ids and config_id not in unsafe_config_ids] + candidates = [(config_id, entry["ms"], entry["err"]) for config_id, entry in results.items() if entry.get("ms") is not None and config_id not in external_config_ids and config_id not in sparse_config_ids and config_id not in unsafe_config_ids] if not candidates: return None fastest = min(ms for _config_id, ms, _err in candidates) @@ -2695,7 +2967,7 @@ def select_attention_config(results): pool, capped = [], [] for config_id, label, kwargs in bench_configs: settings = config_settings(kwargs) - if settings is None: + if settings is None or config_id in sparse_config_ids: # a sparse row shares a settings tuple with its dense row but is a stage over it, not a setting continue if settings["accum"] and settings["pv"] == "disabled": continue # the unsafe accumulation combo is never a candidate; the accum row cites it directly @@ -3503,11 +3775,24 @@ def main(): sys.exit(1) known_blocks = [config_id for config_id, _w, _mm, _a in block_configs] selected_blocks = None if args.block_configs.strip().lower() == "all" else [s.strip() for s in args.block_configs.split(",") if s.strip()] + selected_geometries = None if args.block_geometries.strip().lower() == "all" else [s.strip() for s in args.block_geometries.split(",") if s.strip()] + if selected_geometries is not None: + unknown_geometries = [s for s in selected_geometries if s not in block_geometries] + if unknown_geometries: + console.print(f"[red]unknown block geometry(ies): {', '.join(unknown_geometries)}; available: {', '.join(block_geometries)}[/red]") + sys.exit(1) if selected_blocks is not None: unknown_blocks = [s for s in selected_blocks if s not in known_blocks] if unknown_blocks: console.print(f"[red]unknown block config(s): {', '.join(unknown_blocks)}; available: {', '.join(known_blocks)}[/red]") sys.exit(1) + known_attention = [config_id for config_id, _label, _kwargs in bench_configs] + selected_attention = None if args.configs.strip().lower() == "all" else [s.strip() for s in args.configs.split(",") if s.strip()] + if selected_attention is not None: + unknown_attention = [s for s in selected_attention if s not in known_attention] + if unknown_attention: + console.print(f"[red]unknown attention config(s): {', '.join(unknown_attention)}; available: {', '.join(known_attention)}[/red]") + sys.exit(1) known_variants = [variant_id for variant_id, _cfg in dequant_variant_configs] variants_arg = args.dequant_variants.strip().lower() if variants_arg == "all": @@ -3550,7 +3835,9 @@ def main(): bench_dtype = devices.dtype else: bench_dtype = {"bf16": torch.bfloat16, "fp16": torch.float16}[args.dtype] - selected = list(full_run) if args.shapes.strip().lower() == "all" else [s.strip() for s in args.shapes.split(",") if s.strip()] + shapes_arg = args.shapes.strip().lower() + shape_run_aliases = {"all": full_run, "sparse": sparse_run, "gate": gate_run} + selected = list(shape_run_aliases[shapes_arg]) if shapes_arg in shape_run_aliases else [s.strip() for s in args.shapes.split(",") if s.strip()] unknown = [s for s in selected if s not in shape_presets] if unknown: console.print(f"[red]unknown shape preset(s): {', '.join(unknown)}; available: {', '.join(shape_presets)}[/red]") @@ -3615,7 +3902,9 @@ def main(): if free_vram_gb() < 3.0: emit(f"[yellow]skipping block benchmarks: needs about 3 gb free vram, {free_vram_gb():.1f} gb available[/yellow]") else: - bench_block_section(args.iters, args.warmup, config_timeout=args.config_timeout, selected=selected_blocks) + bench_block_section(args.iters, args.warmup, config_timeout=args.timeout_flag, selected=selected_blocks, geometries=selected_geometries) + if "attention" not in sections: + emit_block_splits() if "attention" in sections: # bench the prep mode the advice points to: compiled, static workaround, or eager @@ -3637,7 +3926,8 @@ def main(): if free_vram_gb() < needed: emit(f"[yellow]skipping {preset}: needs about {needed:.0f} gb free vram, {free_vram_gb():.1f} gb available[/yellow]") continue - all_results[preset] = bench_shape(preset, args.iters, args.warmup, position=(index, len(selected)), config_timeout=args.config_timeout, fp8_result=fp8_result) + all_results[preset] = bench_shape(preset, args.iters, args.warmup, position=(index, len(selected)), config_timeout=args.timeout_flag, fp8_result=fp8_result, selected=selected_attention) + emit_block_splits() build_recommendations(all_results, fp8_result, prep_status, block_results=(report.get("block") or {}).get("results"), block_variants=report.get("blocks")) if drift_samples: diff --git a/constraints.txt b/constraints.txt index a14553032..34078295e 100644 --- a/constraints.txt +++ b/constraints.txt @@ -1,3 +1,2 @@ fastapi==0.124.4 -numpy==2.1.2 Pillow==12.2.0 diff --git a/data/reference-base.json b/data/reference-base.json index 5ad8fad56..9407512d3 100644 --- a/data/reference-base.json +++ b/data/reference-base.json @@ -26,676 +26,21 @@ "desc": "This stable-diffusion-2 model is resumed from stable-diffusion-2-base (512-base-ema.ckpt) and trained for 150k steps using a v-objective on the same dataset. Resumed for another 140k steps on 768x768 images", "extras": "width: 768, height: 768, sampler: DEIS, steps: 20, cfg_scale: 6.0" }, - "StabilityAI StableDiffusion XL": { - "path": "stabilityai/stable-diffusion-xl-base-1.0", - "preview": "stabilityai--stable-diffusion-xl-base-1.0.jpg", - "desc": "Stable Diffusion XL (SDXL) is AI image generation model that is tailored towards more photorealistic outputs with more detailed imagery and composition compared to previous SD models, including SD 2.1. It can make realistic faces and better image composition, all while using shorter and simpler prompts at a greatly increased base resolution of 1024x1024. Just like its predecessors, SDXL has the ability to generate image variations using image-to-image prompting, inpainting (reimagining of the selected parts of an image), and outpainting (creating new parts that lie outside the image borders).", - "variant": "fp16", - "size": 32.0, - "date": "2023 July" - }, - "Microsoft Lens": { - "path": "Jinstudio/Lens", - "preview": "microsoft--Lens.jpg", - "desc": "Microsoft Lens is a text-to-image DiT model using GPT-OSS chat-style prompt encoding and Flux2 VAE decoding.", - "size": 28.43, - "date": "2026 May" - }, - "Boogu Image 0.1 Base": { - "path": "Boogu/Boogu-Image-0.1-Base", - "preview": "Boogu--Boogu-Image-0.1-Base.jpg", - "desc": "Boogu Image 0.1 Base is the core Boogu text-to-image model with Qwen3-VL instruction encoding and a mixed single/double-stream diffusion transformer.", - "size": 35.81, - "date": "2026 June" - }, - "Boogu Image 0.1 Edit": { - "path": "Boogu/Boogu-Image-0.1-Edit", - "preview": "Boogu--Boogu-Image-0.1-Edit.jpg", - "desc": "Boogu Image 0.1 Edit is optimized for image editing with the same instruction-aware Boogu transformer and flow-match scheduler.", - "size": 35.81, - "date": "2026 June" - }, - "Microsoft Lens Base": { - "path": "Jinstudio/Lens-Base", - "preview": "microsoft--Lens-Base.jpg", - "desc": "Microsoft Lens-Base is the base variant of Lens for text-to-image generation with GPT-OSS prompt features.", - "size": 28.43, - "date": "2026 May" - }, - "StabilityAI Stable Cascade": { - "path": "huggingface/stabilityai/stable-cascade", - "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.jpg", - "extras": "sampler: Default, cfg_scale: 4.0, cfg_image: 1.0", - "size": 2.59, - "date": "2024 February" - }, - "StabilityAI Stable Diffusion 3.0 Medium": { - "path": "stabilityai/stable-diffusion-3-medium-diffusers", - "variant": "fp16", - "desc": "Stable Diffusion 3 Medium is a Multimodal Diffusion Transformer (MMDiT) text-to-image model that features greatly improved performance in image quality, typography, complex prompt understanding, and resource-efficiency", - "preview": "stabilityai--stable-diffusion-3.jpg", - "extras": "sampler: Default, cfg_scale: 7.0", - "size": 28.87, - "date": "2024 June" - }, - "StabilityAI Stable Diffusion 3.5 Medium": { - "path": "stabilityai/stable-diffusion-3.5-medium", - "variant": "fp16", - "desc": "Stable Diffusion 3.5 Medium is a Multimodal Diffusion Transformer with improvements (MMDiT-X) text-to-image model that features improved performance in image quality, typography, complex prompt understanding, and resource-efficiency.", - "preview": "stabilityai--stable-diffusion-3_5-medium.jpg", - "extras": "sampler: Default, cfg_scale: 7.0", - "size": 25.55, - "date": "2024 October" - }, - "StabilityAI Stable Diffusion 3.5 Large": { - "path": "stabilityai/stable-diffusion-3.5-large", - "variant": "fp16", - "desc": "Stable Diffusion 3.5 Large is a Multimodal Diffusion Transformer (MMDiT) text-to-image model that features improved performance in image quality, typography, complex prompt understanding, and resource-efficiency.", - "preview": "stabilityai--stable-diffusion-3_5-large.jpg", - "extras": "sampler: Default, cfg_scale: 7.0", - "size": 36.12, - "date": "2024 October" - }, - "Black Forest Labs FLUX.1 Dev": { - "path": "black-forest-labs/FLUX.1-dev", - "preview": "black-forest-labs--FLUX.1-dev.jpg", - "desc": "FLUX.1 models are based on a hybrid architecture of multimodal and parallel diffusion transformer blocks, scaled to 12B parameters and builing on flow matching", - "extras": "sampler: Default, cfg_scale: 3.5", - "size": 31.42, - "date": "2024 July" - }, - "Black Forest Labs FLUX.1 Schnell": { - "path": "black-forest-labs/FLUX.1-schnell", - "preview": "black-forest-labs--FLUX.1-schnell.jpg", - "desc": "FLUX.1 models are based on a hybrid architecture of multimodal and parallel diffusion transformer blocks, scaled to 12B parameters and builing on flow matching. Trained using latent adversarial diffusion distillation, FLUX.1 [schnell] can generate high-quality images in only 1 to 4 steps", - "extras": "sampler: Default, cfg_scale: 3.5", - "size": 31.41, - "date": "2024 July" - }, - "Black Forest Labs FLUX.1 Kontext Dev": { - "path": "black-forest-labs/FLUX.1-Kontext-dev", - "preview": "black-forest-labs--FLUX.1-Kontext-dev.jpg", - "desc": "FLUX.1 Kontext [dev] is a 12 billion parameter rectified flow transformer capable of editing images based on text instructions.", - "extras": "sampler: Default, cfg_scale: 3.5", - "size": 31.42, - "date": "2025 May" - }, - "Black Forest Labs FLUX.1 Krea Dev": { - "path": "black-forest-labs/FLUX.1-Krea-dev", - "preview": "black-forest-labs--FLUX.1-Krea-dev.jpg", - "desc": "FLUX.1 Krea [dev] is a 12 billion parameter rectified flow transformer capable of generating images from text descriptions.", - "extras": "sampler: Default, cfg_scale: 4.5", - "size": 31.42, - "date": "2025 July" - }, - "Black Forest Labs FLUX.2 Dev": { - "path": "black-forest-labs/FLUX.2-dev", - "preview": "black-forest-labs--FLUX.2-dev.jpg", - "desc": "FLUX.2 generates high-quality images while maintaining character and style consistency across multiple reference images, following structured prompts, reading and writing complex text, adhering to brand guidelines, and reliably handling lighting, layouts, and logos.", - "size": 105.06, - "date": "2025 November" - }, - "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.", - "extras": "sampler: Default, cfg_scale: 4.0, steps: 50", - "size": 14.87, - "date": "2026 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.", - "extras": "sampler: Default, cfg_scale: 4.0, steps: 50", - "size": 32.32, - "date": "2026 January" - }, - "Owen777 UltraFlux-v1": { - "path": "Owen777/UltraFlux-v1", - "preview": "Owen777--UltraFlux-v1.jpg", - "desc": "UltraFlux-v1 is a FLUX.1-dev based text-to-image model optimized for native 4K and multi-aspect-ratio generation with improved composition consistency.", - "extras": "sampler: Default, cfg_scale: 4.0, steps: 50", - "size": 31.58, - "date": "2025 November" - }, - "Z-Image": { - "path": "Tongyi-MAI/Z-Image", - "preview": "Tongyi-MAI--Z-Image.jpg", - "desc": "Z-Image, an efficient image generation foundation model built on a Single-Stream Diffusion Transformer architecture. It preserves the complete training signal with full CFG support, enabling aesthetic versatility from hyper-realistic photography to anime, enhanced output diversity, and robust negative prompting for artifact suppression. Ideal base for LoRA training, ControlNet, and semantic conditioning.", - "extras": "sampler: Default, cfg_scale: 4.0, steps: 50", - "size": 19.11, - "date": "2026 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 excels in photorealistic image generation, bilingual text rendering (English & Chinese), and robust instruction adherence.", - "extras": "sampler: Default, cfg_scale: 1.0, steps: 9", - "size": 30.58, - "date": "2025 November" - }, - "Ideogram 4": { - "path": "CalamitousFelicitousness/Ideogram-4-bf16-Diffusers", - "preview": "CalamitousFelicitousness--Ideogram-4-bf16-Diffusers.jpg", - "desc": "Ideogram 4 is Ideogram's first open-weight text-to-image model: a two 9.3B flow-matching DiTs that uses a Qwen3-VL vision-language model as its text encoder, with strong in-image text rendering. Requires structured JSON-caption prompts; prompt-enhance (on by default) rewrites a plain prompt into one.", - "extras": "sampler: Default, cfg_scale: 7.0, steps: 20, width: 1024, height: 1024", - "size": 49.9, - "date": "2026 June" - }, - "Krea 2 Base": { - "path": "CalamitousFelicitousness/Krea-2-Base-Diffusers", - "preview": "CalamitousFelicitousness--Krea-2-Base-Diffusers.jpg", - "desc": "Krea 2 (K2) Base is the undistilled foundation model of the Krea 2 family, trained from scratch by Krea. A 12.9B-parameter single-stream flow-matching DiT that uses a Qwen3-VL-4B vision-language model as its text encoder and the Qwen-Image VAE. The base checkpoint is intended for fine-tuning and LoRA training; LoRAs trained on it apply to Krea 2 Turbo.", - "extras": "sampler: Default, cfg_scale: 4.5, steps: 52", - "size": 33.5, - "date": "2026 June" - }, - "Baidu ERNIE-Image": { - "path": "baidu/ERNIE-Image", - "preview": "baidu--ERNIE-Image.jpg", - "desc": "ERNIE-Image is a text-to-image diffusion transformer model that combines a Mistral3 text encoder with a FlowMatch transformer and Flux2-style VAE for 1024px image generation.", - "extras": "sampler: Default, cfg_scale: 4.0, steps: 50", - "size": 22.29, - "date": "2026 April" - }, - "NucleusAI Nucleus-Image": { - "path": "NucleusAI/Nucleus-Image", - "preview": "NucleusAI--Nucleus-Image.jpg", - "desc": "Nucleus-Image is a sparse mixture-of-experts diffusion transformer with 17B total parameters and about 2B active parameters per forward pass, using a Qwen3-VL text encoder and Qwen-Image VAE for 1024px generation.", - "variant": "bf16", - "extras": "sampler: Default, cfg_scale: 8.0, steps: 50", - "size": 48.09, - "date": "2026 March" - }, - "Qwen-Image": { - "path": "Qwen/Qwen-Image", - "preview": "Qwen--Qwen-Image.jpg", - "desc": "Qwen-Image, an image generation foundation model in the Qwen series that achieves significant advances in complex text rendering and precise image editing.", - "size": 53.74, - "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.", - "size": 53.74, - "date": "2025 December" - }, - "Qwen-Image-Edit": { - "path": "Qwen/Qwen-Image-Edit", - "preview": "Qwen--Qwen-Image-Edit.jpg", - "desc": "Qwen-Image-Edit, the image editing version of Qwen-Image. Built upon our 20B Qwen-Image model, Qwen-Image-Edit successfully extends Qwen-Image’s unique text rendering capabilities to image editing tasks, enabling precise text editing.", - "size": 53.74, - "date": "2025 August" - }, - "Qwen-Image-Edit-2509": { - "path": "Qwen/Qwen-Image-Edit-2509", - "preview": "Qwen--Qwen-Image-Edit-2509.jpg", - "desc": "Qwen-Image-Edit, the image editing version of Qwen-Image. Built upon our 20B Qwen-Image model, Qwen-Image-Edit successfully extends Qwen-Image’s unique text rendering capabilities to image editing tasks, enabling precise text editing.", - "size": 53.74, - "date": "2025 September" - }, - "Qwen-Image-Edit-2511": { - "path": "Qwen/Qwen-Image-Edit-2511", - "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.", - "size": 53.74, - "date": "2025 December" - }, - "Qwen-Image-Layered": { - "path": "Qwen/Qwen-Image-Layered", - "preview": "Qwen--Qwen-Image-Layered.jpg", - "desc": "Qwen-Image-Layered, a model capable of decomposing an image into multiple RGBA layers", - "size": 53.74, - "date": "2025 December" - }, - "lodestones Chroma1 HD": { - "path": "lodestones/Chroma1-HD", - "preview": "lodestones--Chroma1-HD.jpg", - "desc": "Chroma is a 8.9B parameter model based on FLUX.1-schnell. It’s 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.", - "size": 25.6, - "date": "2025 August" - }, - "lodestones Chroma1 Base": { - "path": "lodestones/Chroma1-Base", - "preview": "lodestones--Chroma1-Base.jpg", - "desc": "Chroma is a 8.9B parameter model based on FLUX.1-schnell. It’s 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.", - "size": 25.6, - "date": "2025 July" - }, - "lodestones Chroma1 v50 Preview Annealed": { - "path": "vladmandic/chroma-unlocked-v50-annealed", - "preview": "vladmandic--chroma-unlocked-v50-annealed.jpg", - "desc": "Chroma is a 8.9B parameter model based on FLUX.1-schnell. It’s 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.", - "size": 25.6, - "date": "2025 August" - }, - "lodestones Zeta-Chroma": { - "path": "lodestones/Zeta-Chroma", - "preview": "lodestones--Zeta-Chroma.jpg", - "desc": "Zeta-Chroma is a pixel-space diffusion transformer image model from lodestones that generates images directly in RGB space using a NextDiT-style architecture.", - "extras": "sampler: Default, cfg_scale: 3.0, steps: 30", - "size": 12.11, - "date": "2025 December" - }, - "Anima 1.0 Base": { - "path": "vladmandic/Anima-1.0-Base", - "preview": "vladmandic--Anima-1.0-Base.jpg", - "desc": "Anima 1.0 Base with extended 1024-resolution training and expanded dataset coverage for less common artists. A 2B parameter anime-focused text-to-image model based on modified Cosmos-Predict-2B with Qwen3-0.6B text encoder, created by CircleStone Labs and Comfy Org.", - "date": "2026 May", - "size": 4.99 - }, - "Anima 1.0 Aesthetic": { - "path": "CalamitousFelicitousness/Anima-1.0-Aesthetic-Diffusers", - "preview": "CalamitousFelicitousness--Anima-1.0-Aesthetic-Diffusers.jpg", - "desc": "Anima 1.0 Aesthetic, fine-tuned for better consistency and a higher quality default art style. A 2B parameter anime-focused text-to-image model based on modified Cosmos-Predict-2B with Qwen3-0.6B text encoder, created by CircleStone Labs and Comfy Org.", - "extras": "sampler: Default, cfg_scale: 4.5, steps: 30", - "date": "2026 July", - "size": 4.99 - }, - "Meituan LongCat Image": { - "path": "meituan-longcat/LongCat-Image", - "preview": "meituan-longcat--LongCat-Image.jpg", - "desc": "Pioneering open-source and bilingual (Chinese-English) foundation model for image generation, designed to address core challenges in multilingual text rendering, photorealism, deployment efficiency, and developer accessibility prevalent in current leading models.", - "size": 27.28, - "date": "2025 December" - }, - "Meituan LongCat Image-Edit": { - "path": "meituan-longcat/LongCat-Image-Edit", - "preview": "meituan-longcat--LongCat-Image-Edit.jpg", - "desc": "Pioneering open-source and bilingual (Chinese-English) foundation model for image generation, designed to address core challenges in multilingual text rendering, photorealism, deployment efficiency, and developer accessibility prevalent in current leading models.", - "size": 27.28, - "date": "2025 December" - }, - "Ostris Flex.2 Preview": { - "path": "ostris/Flex.2-preview", - "preview": "ostris--Flex.2-preview.jpg", - "desc": "Open Source 8B parameter Text to Image Diffusion Model with universal control and inpainting support built in. Early access preview release. The next version of Flex.1-alpha", - "extras": "sampler: Default, cfg_scale: 3.5", - "size": 24.46, - "date": "2025 April" - }, - "Ostris Flex.1 Alpha": { - "path": "ostris/Flex.1-alpha", - "preview": "ostris--Flex.1-alpha.jpg", - "desc": "Flex.1 alpha is a pre-trained base 8 billion parameter rectified flow transformer capable of generating images from text descriptions. It has a similar architecture to FLUX.1-dev, but with fewer double transformer blocks (8 vs 19)", - "extras": "sampler: Default, cfg_scale: 3.5", - "size": 24.46, - "date": "2025 January" - }, - "Wan-AI Wan2.1 1.3B": { - "path": "Wan-AI/Wan2.1-T2V-1.3B-Diffusers", - "preview": "Wan-AI--Wan2.1-T2V-1.3B-Diffusers.jpg", - "desc": "Wan is an advanced and powerful visual generation model developed by Tongyi Lab of Alibaba Group. It can generate videos based on text, images, and other control signals. The Wan2.1 series models are now fully open-source.", + "DeepFloyd IF Medium": { + "path": "DeepFloyd/IF-I-M-v1.0", + "desc": "DeepFloyd-IF is a pixel-based text-to-image triple-cascaded diffusion model, that can generate pictures with new state-of-the-art for photorealism and language understanding. The result is a highly efficient model that outperforms current state-of-the-art models, achieving a zero-shot FID-30K score of 6.66 on the COCO dataset. It is modular and composed of frozen text mode and three pixel cascaded diffusion modules, each designed to generate images of increasing resolution: 64x64, 256x256, and 1024x1024.", + "preview": "DeepFloyd--IF-I-M-v1.0.jpg", "extras": "sampler: Default", - "size": 26.92, - "date": "2025 March" + "size": 75.87, + "date": "2023 March" }, - "Wan-AI Wan2.1 14B": { - "path": "Wan-AI/Wan2.1-T2V-14B-Diffusers", - "preview": "Wan-AI--Wan2.1-T2V-14B-Diffusers.jpg", - "desc": "Wan is an advanced and powerful visual generation model developed by Tongyi Lab of Alibaba Group. It can generate videos based on text, images, and other control signals. The Wan2.1 series models are now fully open-source.", + "DeepFloyd IF Large": { + "path": "DeepFloyd/IF-I-L-v1.0", + "desc": "DeepFloyd-IF is a pixel-based text-to-image triple-cascaded diffusion model, that can generate pictures with new state-of-the-art for photorealism and language understanding. The result is a highly efficient model that outperforms current state-of-the-art models, achieving a zero-shot FID-30K score of 6.66 on the COCO dataset. It is modular and composed of frozen text mode and three pixel cascaded diffusion modules, each designed to generate images of increasing resolution: 64x64, 256x256, and 1024x1024.", + "preview": "DeepFloyd--IF-I-L-v1.0.jpg", "extras": "sampler: Default", - "size": 74.86, - "date": "2025 March" - }, - "Wan-AI Wan2.2 5B": { - "path": "Wan-AI/Wan2.2-TI2V-5B-Diffusers", - "preview": "Wan-AI--Wan2.2-TI2V-5B-Diffusers.jpg", - "desc": "Wan2.2, offering more powerful capabilities, better performance, and superior visual quality. With Wan2.2, we have focused on incorporating the following technical innovations: MoE Architecture, Data Scalling, Cinematic Aesthetics, Efficient High-Definition Hybrid", - "extras": "sampler: Default", - "size": 31.83, - "date": "2025 July" - }, - "Wan-AI Wan2.2 A14B T2I": { - "path": "Wan-AI/Wan2.2-T2V-A14B-Diffusers", - "preview": "Wan-AI--Wan2.2-T2V-A14B-Diffusers.jpg", - "desc": "Wan2.2, offering more powerful capabilities, better performance, and superior visual quality. With Wan2.2, we have focused on incorporating the following technical innovations: MoE Architecture, Data Scalling, Cinematic Aesthetics, Efficient High-Definition Hybrid", - "extras": "sampler: Default", - "size": 117.51, - "date": "2025 July" - }, - "Wan-AI Wan2.2 A14B I2I": { - "path": "Wan-AI/Wan2.2-I2V-A14B-Diffusers", - "preview": "Wan-AI--Wan2.2-T2V-A14B-Diffusers.jpg", - "desc": "Wan2.2, offering more powerful capabilities, better performance, and superior visual quality. With Wan2.2, we have focused on incorporating the following technical innovations: MoE Architecture, Data Scalling, Cinematic Aesthetics, Efficient High-Definition Hybrid", - "extras": "sampler: Default", - "size": 117.52, - "date": "2025 July" - }, - "Wan-AI Wan2.2 14B VACE": { - "path": "linoyts/Wan2.2-VACE-Fun-14B-diffusers", - "preview": "linoyts--Wan2.2-VACE-Fun-14B-diffusers.jpg", - "desc": "Wan2.2, offering more powerful capabilities, better performance, and superior visual quality. With Wan2.2, we have focused on incorporating the following technical innovations: MoE Architecture, Data Scalling, Cinematic Aesthetics, Efficient High-Definition Hybrid", - "extras": "sampler: Default", - "size": 75.64, - "date": "2025 September" - }, - "MiniMaxAI MiniMax-H3": { - "path": "MiniMaxAI/MiniMax-H3", - "preview": "MiniMaxAI--MiniMax-H3.jpg", - "desc": "MiniMax-H3 generates video with synchronized stereo audio in a single denoising pass through a 33B single-stream transformer with a Qwen3-VL conditioner. In image tabs the model runs in experimental still mode, keeping the first frame of a minimal generation.", - "extras": "sampler: Default", - "size": 134.12, - "date": "2026 August" - }, - "MiniMaxAI MiniMax-H3 Ref2VA": { - "path": "MiniMaxAI/MiniMax-H3", - "subfolder": "ref2va", - "preview": "MiniMaxAI--MiniMax-H3.jpg", - "desc": "The omni-reference variant of MiniMax-H3, sharing one repository with the base model as a separate checkpoint partition. Video with synchronized stereo audio is conditioned on reference images for identity and appearance, with reference rows held clean while video rows denoise.", - "extras": "sampler: Default", - "size": 134.12, - "date": "2026 August" - }, - "Freepik F-Lite": { - "path": "Freepik/F-Lite", - "preview": "Freepik--F-Lite.jpg", - "desc": "F Lite is a 10B parameter diffusion model created by Freepik and Fal, trained exclusively on copyright-safe and SFW content. The model was trained on Freepik's internal dataset comprising approximately 80 million copyright-safe images, making it the first publicly available model of this scale trained exclusively on legally compliant and SFW content.", - "extras": "sampler: Default, cfg_scale: 3.5", - "size": 9.03, - "date": "2025 April" - }, - "Freepik F-Lite Texture": { - "path": "Freepik/F-Lite-Texture", - "preview": "Freepik--F-Lite-Texture.jpg", - "desc": "F Lite is a 10B parameter diffusion model created by Freepik and Fal, trained exclusively on copyright-safe and SFW content. The model was trained on Freepik's internal dataset comprising approximately 80 million copyright-safe images, making it the first publicly available model of this scale trained exclusively on legally compliant and SFW content.", - "extras": "sampler: Default, cfg_scale: 3.5", - "size": 9.03, - "date": "2025 April" - }, - "Freepik F-Lite 7B": { - "path": "Freepik/F-Lite-7B", - "preview": "Freepik--F-Lite-7B.jpg", - "desc": "F Lite is a 10B parameter diffusion model created by Freepik and Fal, trained exclusively on copyright-safe and SFW content. The model was trained on Freepik's internal dataset comprising approximately 80 million copyright-safe images, making it the first publicly available model of this scale trained exclusively on legally compliant and SFW content.", - "extras": "sampler: Default, cfg_scale: 3.5", - "size": 9.03, - "date": "2025 May" - }, - "SDXS DreamShaper 512": { - "path": "IDKiro/sdxs-512-dreamshaper", - "preview": "IDKiro--sdxs-512-dreamshaper.jpg", - "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", - "size": 1.64, - "date": "2024 April" - }, - "NVLabs Sana 1.5 1.6B 1k": { - "path": "Efficient-Large-Model/SANA1.5_1.6B_1024px_diffusers", - "desc": "Sana is an efficient model with scaling of training-time and inference time techniques. SANA-1.5 delivers: efficient model growth from 1.6B Sana-1.0 model to 4.8B, achieving similar or better performance than training from scratch and saving 60% training cost; efficient model depth pruning, slimming any model size as you want; powerful VLM selection based inference scaling, smaller model+inference scaling > larger model.", - "preview": "Efficient-Large-Model--SANA1.5_1.6B_1024px_diffusers.jpg", - "size": 9.02, - "date": "2025 March" - }, - "NVLabs Sana 1.5 4.8B 1k": { - "path": "Efficient-Large-Model/SANA1.5_4.8B_1024px_diffusers", - "desc": "Sana is an efficient model with scaling of training-time and inference time techniques. SANA-1.5 delivers: efficient model growth from 1.6B Sana-1.0 model to 4.8B, achieving similar or better performance than training from scratch and saving 60% training cost; efficient model depth pruning, slimming any model size as you want; powerful VLM selection based inference scaling, smaller model+inference scaling > larger model.", - "preview": "Efficient-Large-Model--SANA1.5_4.8B_1024px_diffusers.jpg", - "size": 14.83, - "date": "2025 March" - }, - "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.", - "preview": "Efficient-Large-Model--Sana_1600M_4Kpx_BF16_diffusers.jpg", - "size": 21.03, - "date": "2025 January" - }, - "NVLabs Sana 1.0 1.6B 2k": { - "path": "Efficient-Large-Model/Sana_1600M_2Kpx_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.", - "preview": "Efficient-Large-Model--Sana_1600M_2Kpx_BF16_diffusers.jpg", - "size": 21.03, - "date": "2024 December" - }, - "NVLabs Sana 1.0 1.6B 1k": { - "path": "Efficient-Large-Model/Sana_1600M_1024px_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.", - "preview": "Efficient-Large-Model--Sana_1600M_1024px_diffusers.jpg", - "size": 24.02, - "date": "2024 November" - }, - "NVLabs Sana 1.0 0.6B 0.5k": { - "path": "Efficient-Large-Model/Sana_600M_512px_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.", - "preview": "Efficient-Large-Model--Sana_600M_512px_diffusers.jpg", - "size": 15.37, - "date": "2024 December" - }, - "nVidia ChronoEdit": { - "path": "nvidia/ChronoEdit-14B-Diffusers", - "preview": "nvidia--ChronoEdit-14B-Diffusers.jpg", - "desc": "ChronoEdit reframes image editing as a video generation task, using input and edited images as start/end frames to leverage pretrained video models with temporal consistency.", - "size": 82.71, - "date": "2025 October" - }, - "nVidia Cosmos-Predict2 T2I 2B": { - "path": "nvidia/Cosmos-Predict2-2B-Text2Image", - "desc": "Cosmos-Predict2: A family of highly performant pre-trained world foundation models purpose-built for generating physics-aware images, videos and world states for physical AI development.", - "preview": "nvidia--Cosmos-Predict2-2B-Text2Image.jpg", - "size": 13.18, - "date": "2025 April" - }, - "nVidia Cosmos-Predict2 T2I 14B": { - "path": "nvidia/Cosmos-Predict2-14B-Text2Image", - "desc": "Cosmos-Predict2: A family of highly performant pre-trained world foundation models purpose-built for generating physics-aware images, videos and world states for physical AI development.", - "preview": "nvidia--Cosmos-Predict2-14B-Text2Image.jpg", - "size": 36.11, - "date": "2025 April" - }, - "X-Omni SFT": { - "path": "X-Omni/X-Omni-SFT", - "desc": "X-Omni: Reinforcement learning makes discrete autoregressive image generative models great again", - "preview": "X-Omni--X-Omni-SFT.jpg", - "size": 23.8, - "date": "2025 August", - "experimental": true - }, - "VectorSpaceLab OmniGen v1": { - "path": "Shitao/OmniGen-v1-diffusers", - "desc": "OmniGen is a unified image generation model that can generate a wide range of images from multi-modal prompts. It is designed to be simple, flexible and easy to use.", - "preview": "Shitao--OmniGen-v1.jpg", - "size": 7.53, - "date": "2024 December" - }, - "VectorSpaceLab OmniGen v2": { - "path": "OmniGen2/OmniGen2", - "desc": "OmniGen2 is a powerful and efficient unified multimodal model. Unlike OmniGen v1, OmniGen2 features two distinct decoding pathways for text and image modalities, utilizing unshared parameters and a decoupled image tokenizer.", - "preview": "OmniGen2--OmniGen2.jpg", - "size": 15.09, - "date": "2025 June" - }, - "AuraFlow 0.3": { - "path": "fal/AuraFlow-v0.3", - "desc": "AuraFlow v0.3 is the fully open-sourced flow-based text-to-image generation model. The model was trained with more compute compared to the previous version, AuraFlow-v0.2. Compared to AuraFlow-v0.2, the model is fine-tuned on more aesthetic datasets and now supports various aspect ratio, (now width and height up to 1536 pixels).", - "preview": "fal--AuraFlow-v0.3.jpg", - "size": 46.1, - "date": "2024 August" - }, - "AuraFlow 0.2": { - "path": "fal/AuraFlow-v0.2", - "desc": "AuraFlow v0.2 is the fully open-sourced largest flow-based text-to-image generation model. The model was trained with more compute compared to the previous version, AuraFlow-v0.1", - "preview": "fal--AuraFlow-v0.2.jpg", - "size": 46.01, - "date": "2024 July" - }, - "Segmind Vega": { - "path": "huggingface/segmind/Segmind-Vega", - "preview": "segmind--Segmind-Vega.jpg", - "desc": "The Segmind-Vega Model is a distilled version of the Stable Diffusion XL (SDXL), offering a remarkable 70% reduction in size and an impressive 100% speedup while retaining high-quality text-to-image generation capabilities. Trained on diverse datasets, including Grit and Midjourney scrape data, it excels at creating a wide range of visual content based on textual prompts. Employing a knowledge distillation strategy, Segmind-Vega leverages the teachings of several expert models, including SDXL, ZavyChromaXL, and JuggernautXL, to combine their strengths and produce compelling visual outputs.", - "variant": "fp16", - "extras": "sampler: Default, cfg_scale: 9.0", - "size": 9.2, - "date": "2023 November" - }, - "Segmind SegMoE SD 4x2": { - "path": "segmind/SegMoE-SD-4x2-v0", - "preview": "segmind--SegMoE-SD-4x2-v0.jpg", - "desc": "SegMoE-SD-4x2-v0 is an untrained Segmind Mixture of Diffusion Experts Model generated using segmoe from 4 Expert SD1.5 models. SegMoE is a powerful framework for dynamically combining Stable Diffusion Models into a Mixture of Experts within minutes without training", - "extras": "width: 512, height: 512, sampler: Default", - "size": 3.04, - "date": "2024 January" - }, - "Segmind SegMoE XL 4x2": { - "path": "segmind/SegMoE-4x2-v0", - "preview": "segmind--SegMoE-4x2-v0.jpg", - "desc": "SegMoE-4x2-v0 is an untrained Segmind Mixture of Diffusion Experts Model generated using segmoe from 4 Expert SDXL models. SegMoE is a powerful framework for dynamically combining Stable Diffusion Models into a Mixture of Experts within minutes without training", - "extras": "sampler: Default", - "size": 15.77, - "date": "2024 January" - }, - "Pixart-α XL 2 Medium": { - "path": "PixArt-alpha/PixArt-XL-2-512x512", - "desc": "PixArt-α is a Transformer-based T2I diffusion model whose image generation quality is competitive with state-of-the-art image generators (e.g., Imagen, SDXL, and even Midjourney), and the training speed markedly surpasses existing large-scale T2I models. Extensive experiments demonstrate that PIXART-α excels in image quality, artistry, and semantic control. It can directly generate 512px images from text prompts within a single sampling process.", - "preview": "PixArt-alpha--PixArt-XL-2-512x512.jpg", - "extras": "width: 512, height: 512, sampler: Default, cfg_scale: 2.0", - "size": 29.36, - "date": "2023 November" - }, - "Pixart-α XL 2 Large": { - "path": "PixArt-alpha/PixArt-XL-2-1024-MS", - "desc": "PixArt-α is a Transformer-based T2I diffusion model whose image generation quality is competitive with state-of-the-art image generators (e.g., Imagen, SDXL, and even Midjourney), and the training speed markedly surpasses existing large-scale T2I models. Extensive experiments demonstrate that PIXART-α excels in image quality, artistry, and semantic control. It can directly generate 1024px images from text prompts within a single sampling process.", - "preview": "PixArt-alpha--PixArt-XL-2-1024-MS.jpg", - "extras": "sampler: Default, cfg_scale: 2.0", - "size": 20.33, - "date": "2023 November" - }, - "Pixart-Σ Small": { - "path": "huggingface/PixArt-alpha/PixArt-Sigma-XL-2-512-MS", - "desc": "PixArt-Σ, a Diffusion Transformer model (DiT) capable of directly generating images at 4K resolution. PixArt-Σ represents a significant advancement over its predecessor, PixArt-α, offering images of markedly higher fidelity and improved alignment with text prompts.", - "preview": "PixArt-alpha--PixArt-Sigma-XL-2-512-MS.jpg", - "extras": "width: 512, height: 512, sampler: Default, cfg_scale: 2.0", - "size": 2.28, - "date": "2024 April" - }, - "Pixart-Σ Medium": { - "path": "huggingface/PixArt-alpha/PixArt-Sigma-XL-2-1024-MS", - "desc": "PixArt-Σ, a Diffusion Transformer model (DiT) capable of directly generating images at 4K resolution. PixArt-Σ represents a significant advancement over its predecessor, PixArt-α, offering images of markedly higher fidelity and improved alignment with text prompts.", - "preview": "PixArt-alpha--PixArt-Sigma-XL-2-1024-MS.jpg", - "extras": "sampler: Default, cfg_scale: 2.0", - "size": 20.33, - "date": "2024 April" - }, - "Pixart-Σ Large": { - "path": "huggingface/PixArt-alpha/PixArt-Sigma-XL-2-2K-MS", - "desc": "PixArt-Σ, a Diffusion Transformer model (DiT) capable of directly generating images at 4K resolution. PixArt-Σ represents a significant advancement over its predecessor, PixArt-α, offering images of markedly higher fidelity and improved alignment with text prompts.", - "preview": "PixArt-alpha--PixArt-Sigma-XL-2-2K-MS.jpg", - "extras": "sampler: Default, cfg_scale: 2.0", - "size": 2.28, - "date": "2024 April" - }, - "Tencent HunyuanImage 2.1": { - "path": "hunyuanvideo-community/HunyuanImage-2.1-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-Diffusers.jpg", - "size": 49.48, - "date": "2025 September" - }, - "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.", - "preview": "hunyuanvideo-community--HunyuanImage-2.1-Diffusers.jpg", - "size": 45.78, - "date": "2025 September" - }, - "Tencent HunyuanDiT 1.2": { - "path": "Tencent-Hunyuan/HunyuanDiT-v1.2-Diffusers", - "desc": "Hunyuan-DiT : A Powerful Multi-Resolution Diffusion Transformer with Fine-Grained Chinese Understanding.", - "preview": "Tencent-Hunyuan--HunyuanDiT-v1.2-Diffusers.jpg", - "extras": "sampler: Default, cfg_scale: 2.0", - "size": 13.43, - "date": "2024 July" - }, - "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", - "size": 13.49, - "date": "2024 June" - }, - "AlphaVLLM Lumina Next SFT": { - "path": "Alpha-VLLM/Lumina-Next-SFT-diffusers", - "desc": "The Lumina-Next-SFT is a Next-DiT model containing 2B parameters and utilizes Gemma-2B as the text encoder, enhanced through high-quality supervised fine-tuning (SFT).", - "preview": "Alpha-VLLM--Lumina-Next-SFT-diffusers.jpg", - "extras": "sampler: Default", - "size": 8.25, - "date": "2024 June" - }, - "AlphaVLLM Lumina 2": { - "path": "Alpha-VLLM/Lumina-Image-2.0", - "desc": "A Unified and Efficient Image Generative Model. Lumina-Image-2.0 is a 2 billion parameter flow-based diffusion transformer capable of generating images from text descriptions.", - "preview": "Alpha-VLLM--Lumina-Image-2.0.jpg", - "extras": "sampler: Default", - "size": 19.77, - "date": "2025 January" - }, - "AlphaVLLM Lumina DiMOO": { - "path": "Alpha-VLLM/Lumina-DiMOO", - "desc": "Lumina-DiMOO is an omni diffusion large language model for multimodal generation and understanding with text-to-image, image editing, and multimodal understanding capabilities.", - "preview": "Alpha-VLLM--Lumina-DiMOO.jpg", - "extras": "sampler: Default", - "size": 0, - "date": "2025 September" - }, - "HiDream-I1 Fast": { - "path": "HiDream-ai/HiDream-I1-Fast", - "desc": "HiDream-I1 is a new open-source image generative foundation model with 17B parameters that achieves state-of-the-art image generation quality within seconds.", - "preview": "HiDream-ai--HiDream-I1-Fast.jpg", - "extras": "sampler: Default", - "size": 43.94, - "date": "2025 April" - }, - "HiDream-I1 Dev": { - "path": "HiDream-ai/HiDream-I1-Dev", - "desc": "HiDream-I1 is a new open-source image generative foundation model with 17B parameters that achieves state-of-the-art image generation quality within seconds.", - "preview": "HiDream-ai--HiDream-I1-Dev.jpg", - "extras": "sampler: Default", - "size": 43.94, - "date": "2025 April" - }, - "HiDream-I1 Full": { - "path": "HiDream-ai/HiDream-I1-Full", - "desc": "HiDream-I1 is a new open-source image generative foundation model with 17B parameters that achieves state-of-the-art image generation quality within seconds.", - "preview": "HiDream-ai--HiDream-I1-Full.jpg", - "extras": "sampler: Default", - "size": 43.94, - "date": "2025 April" - }, - "HiDream-O1 Image": { - "path": "HiDream-ai/HiDream-O1-Image", - "desc": "HiDream-O1-Image is an 8B pixel-level unified transformer model for text-to-image generation, instruction editing, and multi-reference personalization up to 2048x2048.", - "preview": "HiDream-ai--HiDream-O1-Image.jpg", - "extras": "sampler: Default", - "size": 35.2, - "date": "2026 May" - }, - "HiDream-E1 Full": { - "path": "HiDream-ai/HiDream-E1-Full", - "desc": "HiDream-E1 is an image editing model built on HiDream-I1.", - "preview": "HiDream-ai--HiDream-E1-Full.jpg", - "extras": "sampler: Default", - "size": 43.94, - "date": "2025 April" - }, - "HiDream-E1.1": { - "path": "HiDream-ai/HiDream-E1-1", - "desc": "HiDream-E1 is an image editing model built on HiDream-I1.", - "preview": "HiDream-ai--HiDream-E1-1.jpg", - "extras": "sampler: Default", - "size": 43.94, - "date": "2025 July" - }, - "Kwai Kolors": { - "path": "Kwai-Kolors/Kolors-diffusers", - "desc": "Kolors is a large-scale text-to-image generation model based on latent diffusion, developed by the Kuaishou Kolors team. Trained on billions of text-image pairs, Kolors exhibits significant advantages over both open-source and proprietary models in visual quality, complex semantic accuracy, and text rendering for both Chinese and English characters. Furthermore, Kolors supports both Chinese and English inputs", - "preview": "Kwai-Kolors--Kolors-diffusers.jpg", - "extras": "width: 1024, height: 1024", - "size": 16.59, - "date": "2024 July" + "size": 82.18, + "date": "2023 March" }, "Kandinsky 2.1": { "path": "kandinsky-community/kandinsky-2-1", @@ -713,6 +58,53 @@ "size": 9.34, "date": "2023 June" }, + "StabilityAI StableDiffusion XL": { + "path": "stabilityai/stable-diffusion-xl-base-1.0", + "preview": "stabilityai--stable-diffusion-xl-base-1.0.jpg", + "desc": "Stable Diffusion XL (SDXL) is AI image generation model that is tailored towards more photorealistic outputs with more detailed imagery and composition compared to previous SD models, including SD 2.1. It can make realistic faces and better image composition, all while using shorter and simpler prompts at a greatly increased base resolution of 1024x1024. Just like its predecessors, SDXL has the ability to generate image variations using image-to-image prompting, inpainting (reimagining of the selected parts of an image), and outpainting (creating new parts that lie outside the image borders).", + "variant": "fp16", + "size": 32.0, + "date": "2023 July" + }, + "SalesForce BLIP-Diffusion": { + "path": "salesforce/blipdiffusion", + "desc": "BLIP-Diffusion, a new subject-driven image generation model that supports multimodal control which consumes inputs of subject images and text prompts. Unlike other subject-driven generation models, BLIP-Diffusion introduces a new multimodal encoder which is pre-trained to provide subject representation.", + "preview": "salesforce--blipdiffusion.jpg", + "size": 3.97, + "date": "2023 September" + }, + "InstaFlow 0.9B": { + "path": "XCLiu/instaflow_0_9B_from_sd_1_5", + "desc": "InstaFlow is an ultra-fast, one-step image generator that achieves image quality close to Stable Diffusion. This efficiency is made possible through a recent Rectified Flow technique, which trains probability flows with straight trajectories, hence inherently requiring only a single step for fast inference.", + "preview": "XCLiu--instaflow_0_9B_from_sd_1_5.jpg", + "size": 3.97, + "date": "2023 October" + }, + "Segmind Vega": { + "path": "huggingface/segmind/Segmind-Vega", + "preview": "segmind--Segmind-Vega.jpg", + "desc": "The Segmind-Vega Model is a distilled version of the Stable Diffusion XL (SDXL), offering a remarkable 70% reduction in size and an impressive 100% speedup while retaining high-quality text-to-image generation capabilities. Trained on diverse datasets, including Grit and Midjourney scrape data, it excels at creating a wide range of visual content based on textual prompts. Employing a knowledge distillation strategy, Segmind-Vega leverages the teachings of several expert models, including SDXL, ZavyChromaXL, and JuggernautXL, to combine their strengths and produce compelling visual outputs.", + "variant": "fp16", + "extras": "sampler: Default, cfg_scale: 9.0", + "size": 9.2, + "date": "2023 November" + }, + "Pixart-α XL 2 Medium": { + "path": "PixArt-alpha/PixArt-XL-2-512x512", + "desc": "PixArt-α is a Transformer-based T2I diffusion model whose image generation quality is competitive with state-of-the-art image generators (e.g., Imagen, SDXL, and even Midjourney), and the training speed markedly surpasses existing large-scale T2I models. Extensive experiments demonstrate that PIXART-α excels in image quality, artistry, and semantic control. It can directly generate 512px images from text prompts within a single sampling process.", + "preview": "PixArt-alpha--PixArt-XL-2-512x512.jpg", + "extras": "width: 512, height: 512, sampler: Default, cfg_scale: 2.0", + "size": 29.36, + "date": "2023 November" + }, + "Pixart-α XL 2 Large": { + "path": "PixArt-alpha/PixArt-XL-2-1024-MS", + "desc": "PixArt-α is a Transformer-based T2I diffusion model whose image generation quality is competitive with state-of-the-art image generators (e.g., Imagen, SDXL, and even Midjourney), and the training speed markedly surpasses existing large-scale T2I models. Extensive experiments demonstrate that PIXART-α excels in image quality, artistry, and semantic control. It can directly generate 1024px images from text prompts within a single sampling process.", + "preview": "PixArt-alpha--PixArt-XL-2-1024-MS.jpg", + "extras": "sampler: Default, cfg_scale: 2.0", + "size": 20.33, + "date": "2023 November" + }, "Kandinsky 3.0": { "path": "kandinsky-community/kandinsky-3", "desc": "Kandinsky 3.0 is an open-source text-to-image diffusion model built upon the Kandinsky2-x model family. In comparison to its predecessors, Kandinsky 3.0 incorporates more data and specifically related to Russian culture, which allows to generate pictures related to Russin culture. Furthermore, enhancements have been made to the text understanding and visual quality of the model, achieved by increasing the size of the text encoder and Diffusion U-Net models, respectively.", @@ -722,20 +114,6 @@ "size": 25.94, "date": "2023 November" }, - "Kandinsky 5.0 T2I Lite": { - "path": "kandinskylab/Kandinsky-5.0-T2I-Lite-sft-Diffusers", - "desc": "Kandinsky 5.0 Image Lite is a 6B image generation models 1K resulution, high visual quality and strong text-writing", - "preview": "kandinskylab--Kandinsky-5.0-T2I-Lite-sft-Diffusers.jpg", - "size": 30.0, - "date": "2025 November" - }, - "Kandinsky 5.0 I2I Lite": { - "path": "kandinskylab/Kandinsky-5.0-I2I-Lite-sft-Diffusers", - "desc": "Kandinsky 5.0 Image Lite is a 6B image editing models 1K resulution, high visual quality and strong text-writing", - "preview": "kandinskylab--Kandinsky-5.0-T2I-Lite-sft-Diffusers.jpg", - "size": 30.01, - "date": "2025 November" - }, "Playground v1": { "path": "playgroundai/playground-v1", "desc": "Playground v1 is a latent diffusion model that improves the overall HDR quality to get more stunning images.", @@ -768,6 +146,40 @@ "size": 38.77, "date": "2023 December" }, + "Segmind SegMoE SD 4x2": { + "path": "segmind/SegMoE-SD-4x2-v0", + "preview": "segmind--SegMoE-SD-4x2-v0.jpg", + "desc": "SegMoE-SD-4x2-v0 is an untrained Segmind Mixture of Diffusion Experts Model generated using segmoe from 4 Expert SD1.5 models. SegMoE is a powerful framework for dynamically combining Stable Diffusion Models into a Mixture of Experts within minutes without training", + "extras": "width: 512, height: 512, sampler: Default", + "size": 3.04, + "date": "2024 January" + }, + "Segmind SegMoE XL 4x2": { + "path": "segmind/SegMoE-4x2-v0", + "preview": "segmind--SegMoE-4x2-v0.jpg", + "desc": "SegMoE-4x2-v0 is an untrained Segmind Mixture of Diffusion Experts Model generated using segmoe from 4 Expert SDXL models. SegMoE is a powerful framework for dynamically combining Stable Diffusion Models into a Mixture of Experts within minutes without training", + "extras": "sampler: Default", + "size": 15.77, + "date": "2024 January" + }, + "KOALA 700M": { + "path": "huggingface/etri-vilab/koala-700m-llava-cap", + "variant": "fp16", + "desc": "Fast text-to-image model, called KOALA, by compressing SDXL's U-Net and distilling knowledge from SDXL into our model. KOALA-700M can generate a 1024x1024 image in less than 1.5 seconds on an NVIDIA 4090 GPU, which is more than 2x faster than SDXL.", + "preview": "etri-vilab--koala-700m-llava-cap.jpg", + "extras": "sampler: Default", + "size": 12.93, + "date": "2024 January" + }, + "StabilityAI Stable Cascade": { + "path": "huggingface/stabilityai/stable-cascade", + "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.jpg", + "extras": "sampler: Default, cfg_scale: 4.0, cfg_image: 1.0", + "size": 2.59, + "date": "2024 February" + }, "Playground v2.5": { "path": "playgroundai/playground-v2.5-1024px-aesthetic", "desc": "Playground v2.5 is a diffusion-based text-to-image generative model, and a successor to Playground v2. Playground v2.5 is the state-of-the-art open-source model in aesthetic quality.", @@ -777,12 +189,126 @@ "size": 38.77, "date": "2024 February" }, - "CogView 4": { - "path": "zai-org/CogView4-6B", - "desc": "An innovative cascaded framework that enhances the performance of text-to-image diffusion. CogView is the first model implementing relay diffusion in the realm of text-to-image generation, executing the task by first creating low-resolution images and subsequently applying relay-based super-resolution.", - "preview": "THUDM--CogView4-6B.jpg", - "size": 28.97, - "date": "2025 March" + "SDXS DreamShaper 512": { + "path": "IDKiro/sdxs-512-dreamshaper", + "preview": "IDKiro--sdxs-512-dreamshaper.jpg", + "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", + "size": 1.64, + "date": "2024 April" + }, + "Pixart-Σ Small": { + "path": "huggingface/PixArt-alpha/PixArt-Sigma-XL-2-512-MS", + "desc": "PixArt-Σ, a Diffusion Transformer model (DiT) capable of directly generating images at 4K resolution. PixArt-Σ represents a significant advancement over its predecessor, PixArt-α, offering images of markedly higher fidelity and improved alignment with text prompts.", + "preview": "PixArt-alpha--PixArt-Sigma-XL-2-512-MS.jpg", + "extras": "width: 512, height: 512, sampler: Default, cfg_scale: 2.0", + "size": 2.28, + "date": "2024 April" + }, + "Pixart-Σ Medium": { + "path": "huggingface/PixArt-alpha/PixArt-Sigma-XL-2-1024-MS", + "desc": "PixArt-Σ, a Diffusion Transformer model (DiT) capable of directly generating images at 4K resolution. PixArt-Σ represents a significant advancement over its predecessor, PixArt-α, offering images of markedly higher fidelity and improved alignment with text prompts.", + "preview": "PixArt-alpha--PixArt-Sigma-XL-2-1024-MS.jpg", + "extras": "sampler: Default, cfg_scale: 2.0", + "size": 20.33, + "date": "2024 April" + }, + "Pixart-Σ Large": { + "path": "huggingface/PixArt-alpha/PixArt-Sigma-XL-2-2K-MS", + "desc": "PixArt-Σ, a Diffusion Transformer model (DiT) capable of directly generating images at 4K resolution. PixArt-Σ represents a significant advancement over its predecessor, PixArt-α, offering images of markedly higher fidelity and improved alignment with text prompts.", + "preview": "PixArt-alpha--PixArt-Sigma-XL-2-2K-MS.jpg", + "extras": "sampler: Default, cfg_scale: 2.0", + "size": 2.28, + "date": "2024 April" + }, + "StabilityAI Stable Diffusion 3.0 Medium": { + "path": "stabilityai/stable-diffusion-3-medium-diffusers", + "variant": "fp16", + "desc": "Stable Diffusion 3 Medium is a Multimodal Diffusion Transformer (MMDiT) text-to-image model that features greatly improved performance in image quality, typography, complex prompt understanding, and resource-efficiency", + "preview": "stabilityai--stable-diffusion-3.jpg", + "extras": "sampler: Default, cfg_scale: 7.0", + "size": 28.87, + "date": "2024 June" + }, + "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", + "size": 13.49, + "date": "2024 June" + }, + "AlphaVLLM Lumina Next SFT": { + "path": "Alpha-VLLM/Lumina-Next-SFT-diffusers", + "desc": "The Lumina-Next-SFT is a Next-DiT model containing 2B parameters and utilizes Gemma-2B as the text encoder, enhanced through high-quality supervised fine-tuning (SFT).", + "preview": "Alpha-VLLM--Lumina-Next-SFT-diffusers.jpg", + "extras": "sampler: Default", + "size": 8.25, + "date": "2024 June" + }, + "Black Forest Labs FLUX.1 Dev": { + "path": "black-forest-labs/FLUX.1-dev", + "preview": "black-forest-labs--FLUX.1-dev.jpg", + "desc": "FLUX.1 models are based on a hybrid architecture of multimodal and parallel diffusion transformer blocks, scaled to 12B parameters and builing on flow matching", + "extras": "sampler: Default, cfg_scale: 3.5", + "size": 31.42, + "date": "2024 July" + }, + "Black Forest Labs FLUX.1 Schnell": { + "path": "black-forest-labs/FLUX.1-schnell", + "preview": "black-forest-labs--FLUX.1-schnell.jpg", + "desc": "FLUX.1 models are based on a hybrid architecture of multimodal and parallel diffusion transformer blocks, scaled to 12B parameters and builing on flow matching. Trained using latent adversarial diffusion distillation, FLUX.1 [schnell] can generate high-quality images in only 1 to 4 steps", + "extras": "sampler: Default, cfg_scale: 3.5", + "size": 31.41, + "date": "2024 July" + }, + "AuraFlow 0.2": { + "path": "fal/AuraFlow-v0.2", + "desc": "AuraFlow v0.2 is the fully open-sourced largest flow-based text-to-image generation model. The model was trained with more compute compared to the previous version, AuraFlow-v0.1", + "preview": "fal--AuraFlow-v0.2.jpg", + "size": 46.01, + "date": "2024 July" + }, + "Tencent HunyuanDiT 1.2": { + "path": "Tencent-Hunyuan/HunyuanDiT-v1.2-Diffusers", + "desc": "Hunyuan-DiT : A Powerful Multi-Resolution Diffusion Transformer with Fine-Grained Chinese Understanding.", + "preview": "Tencent-Hunyuan--HunyuanDiT-v1.2-Diffusers.jpg", + "extras": "sampler: Default, cfg_scale: 2.0", + "size": 13.43, + "date": "2024 July" + }, + "Kwai Kolors": { + "path": "Kwai-Kolors/Kolors-diffusers", + "desc": "Kolors is a large-scale text-to-image generation model based on latent diffusion, developed by the Kuaishou Kolors team. Trained on billions of text-image pairs, Kolors exhibits significant advantages over both open-source and proprietary models in visual quality, complex semantic accuracy, and text rendering for both Chinese and English characters. Furthermore, Kolors supports both Chinese and English inputs", + "preview": "Kwai-Kolors--Kolors-diffusers.jpg", + "extras": "width: 1024, height: 1024", + "size": 16.59, + "date": "2024 July" + }, + "AuraFlow 0.3": { + "path": "fal/AuraFlow-v0.3", + "desc": "AuraFlow v0.3 is the fully open-sourced flow-based text-to-image generation model. The model was trained with more compute compared to the previous version, AuraFlow-v0.2. Compared to AuraFlow-v0.2, the model is fine-tuned on more aesthetic datasets and now supports various aspect ratio, (now width and height up to 1536 pixels).", + "preview": "fal--AuraFlow-v0.3.jpg", + "size": 46.1, + "date": "2024 August" + }, + "StabilityAI Stable Diffusion 3.5 Medium": { + "path": "stabilityai/stable-diffusion-3.5-medium", + "variant": "fp16", + "desc": "Stable Diffusion 3.5 Medium is a Multimodal Diffusion Transformer with improvements (MMDiT-X) text-to-image model that features improved performance in image quality, typography, complex prompt understanding, and resource-efficiency.", + "preview": "stabilityai--stable-diffusion-3_5-medium.jpg", + "extras": "sampler: Default, cfg_scale: 7.0", + "size": 25.55, + "date": "2024 October" + }, + "StabilityAI Stable Diffusion 3.5 Large": { + "path": "stabilityai/stable-diffusion-3.5-large", + "variant": "fp16", + "desc": "Stable Diffusion 3.5 Large is a Multimodal Diffusion Transformer (MMDiT) text-to-image model that features improved performance in image quality, typography, complex prompt understanding, and resource-efficiency.", + "preview": "stabilityai--stable-diffusion-3_5-large.jpg", + "extras": "sampler: Default, cfg_scale: 7.0", + "size": 36.12, + "date": "2024 October" }, "CogView 3 Plus": { "path": "zai-org/CogView3-Plus-3B", @@ -798,21 +324,276 @@ "size": 7.61, "date": "2024 October" }, - "KOALA 700M": { - "path": "huggingface/etri-vilab/koala-700m-llava-cap", - "variant": "fp16", - "desc": "Fast text-to-image model, called KOALA, by compressing SDXL's U-Net and distilling knowledge from SDXL into our model. KOALA-700M can generate a 1024x1024 image in less than 1.5 seconds on an NVIDIA 4090 GPU, which is more than 2x faster than SDXL.", - "preview": "etri-vilab--koala-700m-llava-cap.jpg", - "extras": "sampler: Default", - "size": 12.93, - "date": "2024 January" + "NVLabs Sana 1.0 1.6B 1k": { + "path": "Efficient-Large-Model/Sana_1600M_1024px_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.", + "preview": "Efficient-Large-Model--Sana_1600M_1024px_diffusers.jpg", + "size": 24.02, + "date": "2024 November" }, - "AIDC Ovis-Image 7B": { - "path": "AIDC-AI/Ovis-Image-7B", - "desc": "Built upon Ovis-U1, Ovis-Image is a 7B text-to-image model specifically optimized for high-quality text rendering, designed to operate efficiently under stringent computational constraints.", - "preview": "AIDC-AI--Ovis-Image-7B.jpg", - "size": 20.29, - "date": "2025 November" + "NVLabs Sana 1.0 1.6B 2k": { + "path": "Efficient-Large-Model/Sana_1600M_2Kpx_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.", + "preview": "Efficient-Large-Model--Sana_1600M_2Kpx_BF16_diffusers.jpg", + "size": 21.03, + "date": "2024 December" + }, + "NVLabs Sana 1.0 0.6B 0.5k": { + "path": "Efficient-Large-Model/Sana_600M_512px_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.", + "preview": "Efficient-Large-Model--Sana_600M_512px_diffusers.jpg", + "size": 15.37, + "date": "2024 December" + }, + "VectorSpaceLab OmniGen v1": { + "path": "Shitao/OmniGen-v1-diffusers", + "desc": "OmniGen is a unified image generation model that can generate a wide range of images from multi-modal prompts. It is designed to be simple, flexible and easy to use.", + "preview": "Shitao--OmniGen-v1.jpg", + "size": 7.53, + "date": "2024 December" + }, + "Ostris Flex.1 Alpha": { + "path": "ostris/Flex.1-alpha", + "preview": "ostris--Flex.1-alpha.jpg", + "desc": "Flex.1 alpha is a pre-trained base 8 billion parameter rectified flow transformer capable of generating images from text descriptions. It has a similar architecture to FLUX.1-dev, but with fewer double transformer blocks (8 vs 19)", + "extras": "sampler: Default, cfg_scale: 3.5", + "size": 24.46, + "date": "2025 January" + }, + "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.", + "preview": "Efficient-Large-Model--Sana_1600M_4Kpx_BF16_diffusers.jpg", + "size": 21.03, + "date": "2025 January" + }, + "AlphaVLLM Lumina 2": { + "path": "Alpha-VLLM/Lumina-Image-2.0", + "desc": "A Unified and Efficient Image Generative Model. Lumina-Image-2.0 is a 2 billion parameter flow-based diffusion transformer capable of generating images from text descriptions.", + "preview": "Alpha-VLLM--Lumina-Image-2.0.jpg", + "extras": "sampler: Default", + "size": 19.77, + "date": "2025 January" + }, + "Wan-AI Wan2.1 1.3B": { + "path": "Wan-AI/Wan2.1-T2V-1.3B-Diffusers", + "preview": "Wan-AI--Wan2.1-T2V-1.3B-Diffusers.jpg", + "desc": "Wan is an advanced and powerful visual generation model developed by Tongyi Lab of Alibaba Group. It can generate videos based on text, images, and other control signals. The Wan2.1 series models are now fully open-source.", + "extras": "sampler: Default", + "size": 26.92, + "date": "2025 March" + }, + "Wan-AI Wan2.1 14B": { + "path": "Wan-AI/Wan2.1-T2V-14B-Diffusers", + "preview": "Wan-AI--Wan2.1-T2V-14B-Diffusers.jpg", + "desc": "Wan is an advanced and powerful visual generation model developed by Tongyi Lab of Alibaba Group. It can generate videos based on text, images, and other control signals. The Wan2.1 series models are now fully open-source.", + "extras": "sampler: Default", + "size": 74.86, + "date": "2025 March" + }, + "NVLabs Sana 1.5 1.6B 1k": { + "path": "Efficient-Large-Model/SANA1.5_1.6B_1024px_diffusers", + "desc": "Sana is an efficient model with scaling of training-time and inference time techniques. SANA-1.5 delivers: efficient model growth from 1.6B Sana-1.0 model to 4.8B, achieving similar or better performance than training from scratch and saving 60% training cost; efficient model depth pruning, slimming any model size as you want; powerful VLM selection based inference scaling, smaller model+inference scaling > larger model.", + "preview": "Efficient-Large-Model--SANA1.5_1.6B_1024px_diffusers.jpg", + "size": 9.02, + "date": "2025 March" + }, + "NVLabs Sana 1.5 4.8B 1k": { + "path": "Efficient-Large-Model/SANA1.5_4.8B_1024px_diffusers", + "desc": "Sana is an efficient model with scaling of training-time and inference time techniques. SANA-1.5 delivers: efficient model growth from 1.6B Sana-1.0 model to 4.8B, achieving similar or better performance than training from scratch and saving 60% training cost; efficient model depth pruning, slimming any model size as you want; powerful VLM selection based inference scaling, smaller model+inference scaling > larger model.", + "preview": "Efficient-Large-Model--SANA1.5_4.8B_1024px_diffusers.jpg", + "size": 14.83, + "date": "2025 March" + }, + "CogView 4": { + "path": "zai-org/CogView4-6B", + "desc": "An innovative cascaded framework that enhances the performance of text-to-image diffusion. CogView is the first model implementing relay diffusion in the realm of text-to-image generation, executing the task by first creating low-resolution images and subsequently applying relay-based super-resolution.", + "preview": "THUDM--CogView4-6B.jpg", + "size": 28.97, + "date": "2025 March" + }, + "Ostris Flex.2 Preview": { + "path": "ostris/Flex.2-preview", + "preview": "ostris--Flex.2-preview.jpg", + "desc": "Open Source 8B parameter Text to Image Diffusion Model with universal control and inpainting support built in. Early access preview release. The next version of Flex.1-alpha", + "extras": "sampler: Default, cfg_scale: 3.5", + "size": 24.46, + "date": "2025 April" + }, + "Freepik F-Lite": { + "path": "Freepik/F-Lite", + "preview": "Freepik--F-Lite.jpg", + "desc": "F Lite is a 10B parameter diffusion model created by Freepik and Fal, trained exclusively on copyright-safe and SFW content. The model was trained on Freepik's internal dataset comprising approximately 80 million copyright-safe images, making it the first publicly available model of this scale trained exclusively on legally compliant and SFW content.", + "extras": "sampler: Default, cfg_scale: 3.5", + "size": 9.03, + "date": "2025 April" + }, + "Freepik F-Lite Texture": { + "path": "Freepik/F-Lite-Texture", + "preview": "Freepik--F-Lite-Texture.jpg", + "desc": "F Lite is a 10B parameter diffusion model created by Freepik and Fal, trained exclusively on copyright-safe and SFW content. The model was trained on Freepik's internal dataset comprising approximately 80 million copyright-safe images, making it the first publicly available model of this scale trained exclusively on legally compliant and SFW content.", + "extras": "sampler: Default, cfg_scale: 3.5", + "size": 9.03, + "date": "2025 April" + }, + "nVidia Cosmos-Predict2 T2I 2B": { + "path": "nvidia/Cosmos-Predict2-2B-Text2Image", + "desc": "Cosmos-Predict2: A family of highly performant pre-trained world foundation models purpose-built for generating physics-aware images, videos and world states for physical AI development.", + "preview": "nvidia--Cosmos-Predict2-2B-Text2Image.jpg", + "size": 13.18, + "date": "2025 April" + }, + "nVidia Cosmos-Predict2 T2I 14B": { + "path": "nvidia/Cosmos-Predict2-14B-Text2Image", + "desc": "Cosmos-Predict2: A family of highly performant pre-trained world foundation models purpose-built for generating physics-aware images, videos and world states for physical AI development.", + "preview": "nvidia--Cosmos-Predict2-14B-Text2Image.jpg", + "size": 36.11, + "date": "2025 April" + }, + "HiDream-I1 Fast": { + "path": "HiDream-ai/HiDream-I1-Fast", + "desc": "HiDream-I1 is a new open-source image generative foundation model with 17B parameters that achieves state-of-the-art image generation quality within seconds.", + "preview": "HiDream-ai--HiDream-I1-Fast.jpg", + "extras": "sampler: Default", + "size": 43.94, + "date": "2025 April" + }, + "HiDream-I1 Dev": { + "path": "HiDream-ai/HiDream-I1-Dev", + "desc": "HiDream-I1 is a new open-source image generative foundation model with 17B parameters that achieves state-of-the-art image generation quality within seconds.", + "preview": "HiDream-ai--HiDream-I1-Dev.jpg", + "extras": "sampler: Default", + "size": 43.94, + "date": "2025 April" + }, + "HiDream-I1 Full": { + "path": "HiDream-ai/HiDream-I1-Full", + "desc": "HiDream-I1 is a new open-source image generative foundation model with 17B parameters that achieves state-of-the-art image generation quality within seconds.", + "preview": "HiDream-ai--HiDream-I1-Full.jpg", + "extras": "sampler: Default", + "size": 43.94, + "date": "2025 April" + }, + "HiDream-E1 Full": { + "path": "HiDream-ai/HiDream-E1-Full", + "desc": "HiDream-E1 is an image editing model built on HiDream-I1.", + "preview": "HiDream-ai--HiDream-E1-Full.jpg", + "extras": "sampler: Default", + "size": 43.94, + "date": "2025 April" + }, + "Black Forest Labs FLUX.1 Kontext Dev": { + "path": "black-forest-labs/FLUX.1-Kontext-dev", + "preview": "black-forest-labs--FLUX.1-Kontext-dev.jpg", + "desc": "FLUX.1 Kontext [dev] is a 12 billion parameter rectified flow transformer capable of editing images based on text instructions.", + "extras": "sampler: Default, cfg_scale: 3.5", + "size": 31.42, + "date": "2025 May" + }, + "Freepik F-Lite 7B": { + "path": "Freepik/F-Lite-7B", + "preview": "Freepik--F-Lite-7B.jpg", + "desc": "F Lite is a 10B parameter diffusion model created by Freepik and Fal, trained exclusively on copyright-safe and SFW content. The model was trained on Freepik's internal dataset comprising approximately 80 million copyright-safe images, making it the first publicly available model of this scale trained exclusively on legally compliant and SFW content.", + "extras": "sampler: Default, cfg_scale: 3.5", + "size": 9.03, + "date": "2025 May" + }, + "VectorSpaceLab OmniGen v2": { + "path": "OmniGen2/OmniGen2", + "desc": "OmniGen2 is a powerful and efficient unified multimodal model. Unlike OmniGen v1, OmniGen2 features two distinct decoding pathways for text and image modalities, utilizing unshared parameters and a decoupled image tokenizer.", + "preview": "OmniGen2--OmniGen2.jpg", + "size": 15.09, + "date": "2025 June" + }, + "Black Forest Labs FLUX.1 Krea Dev": { + "path": "black-forest-labs/FLUX.1-Krea-dev", + "preview": "black-forest-labs--FLUX.1-Krea-dev.jpg", + "desc": "FLUX.1 Krea [dev] is a 12 billion parameter rectified flow transformer capable of generating images from text descriptions.", + "extras": "sampler: Default, cfg_scale: 4.5", + "size": 31.42, + "date": "2025 July" + }, + "lodestones Chroma1 Base": { + "path": "lodestones/Chroma1-Base", + "preview": "lodestones--Chroma1-Base.jpg", + "desc": "Chroma is a 8.9B parameter model based on FLUX.1-schnell. It’s 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.", + "size": 25.6, + "date": "2025 July" + }, + "Wan-AI Wan2.2 5B": { + "path": "Wan-AI/Wan2.2-TI2V-5B-Diffusers", + "preview": "Wan-AI--Wan2.2-TI2V-5B-Diffusers.jpg", + "desc": "Wan2.2, offering more powerful capabilities, better performance, and superior visual quality. With Wan2.2, we have focused on incorporating the following technical innovations: MoE Architecture, Data Scalling, Cinematic Aesthetics, Efficient High-Definition Hybrid", + "extras": "sampler: Default", + "size": 31.83, + "date": "2025 July" + }, + "Wan-AI Wan2.2 A14B T2I": { + "path": "Wan-AI/Wan2.2-T2V-A14B-Diffusers", + "preview": "Wan-AI--Wan2.2-T2V-A14B-Diffusers.jpg", + "desc": "Wan2.2, offering more powerful capabilities, better performance, and superior visual quality. With Wan2.2, we have focused on incorporating the following technical innovations: MoE Architecture, Data Scalling, Cinematic Aesthetics, Efficient High-Definition Hybrid", + "extras": "sampler: Default", + "size": 117.51, + "date": "2025 July" + }, + "Wan-AI Wan2.2 A14B I2I": { + "path": "Wan-AI/Wan2.2-I2V-A14B-Diffusers", + "preview": "Wan-AI--Wan2.2-T2V-A14B-Diffusers.jpg", + "desc": "Wan2.2, offering more powerful capabilities, better performance, and superior visual quality. With Wan2.2, we have focused on incorporating the following technical innovations: MoE Architecture, Data Scalling, Cinematic Aesthetics, Efficient High-Definition Hybrid", + "extras": "sampler: Default", + "size": 117.52, + "date": "2025 July" + }, + "HiDream-E1.1": { + "path": "HiDream-ai/HiDream-E1-1", + "desc": "HiDream-E1 is an image editing model built on HiDream-I1.", + "preview": "HiDream-ai--HiDream-E1-1.jpg", + "extras": "sampler: Default", + "size": 43.94, + "date": "2025 July" + }, + "Bria 3.2": { + "path": "SahilCarterr/BRIA-3.2", + "desc": "Bria 3.2 is the next-generation commercial-ready text-to-image model. With just 4 billion parameters, it provides exceptional aesthetics and text rendering, evaluated to provide on par results to leading open-source models, and outperforming other licensed models.", + "preview": "briaai--BRIA-3.2.jpg", + "size": 18.11, + "date": "2025 July" + }, + "Qwen-Image": { + "path": "Qwen/Qwen-Image", + "preview": "Qwen--Qwen-Image.jpg", + "desc": "Qwen-Image, an image generation foundation model in the Qwen series that achieves significant advances in complex text rendering and precise image editing.", + "size": 53.74, + "date": "2025 August" + }, + "Qwen-Image-Edit": { + "path": "Qwen/Qwen-Image-Edit", + "preview": "Qwen--Qwen-Image-Edit.jpg", + "desc": "Qwen-Image-Edit, the image editing version of Qwen-Image. Built upon our 20B Qwen-Image model, Qwen-Image-Edit successfully extends Qwen-Image’s unique text rendering capabilities to image editing tasks, enabling precise text editing.", + "size": 53.74, + "date": "2025 August" + }, + "lodestones Chroma1 HD": { + "path": "lodestones/Chroma1-HD", + "preview": "lodestones--Chroma1-HD.jpg", + "desc": "Chroma is a 8.9B parameter model based on FLUX.1-schnell. It’s 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.", + "size": 25.6, + "date": "2025 August" + }, + "lodestones Chroma1 v50 Preview Annealed": { + "path": "vladmandic/chroma-unlocked-v50-annealed", + "preview": "vladmandic--chroma-unlocked-v50-annealed.jpg", + "desc": "Chroma is a 8.9B parameter model based on FLUX.1-schnell. It’s 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.", + "size": 25.6, + "date": "2025 August" + }, + "X-Omni SFT": { + "path": "X-Omni/X-Omni-SFT", + "desc": "X-Omni: Reinforcement learning makes discrete autoregressive image generative models great again", + "preview": "X-Omni--X-Omni-SFT.jpg", + "size": 23.8, + "date": "2025 August", + "experimental": true }, "HDM-XUT 340M Anime": { "path": "KBlueLeaf/HDM-xut-340M-anime", @@ -821,35 +602,109 @@ "size": 2.2, "date": "2025 August" }, - "SalesForce BLIP-Diffusion": { - "path": "salesforce/blipdiffusion", - "desc": "BLIP-Diffusion, a new subject-driven image generation model that supports multimodal control which consumes inputs of subject images and text prompts. Unlike other subject-driven generation models, BLIP-Diffusion introduces a new multimodal encoder which is pre-trained to provide subject representation.", - "preview": "salesforce--blipdiffusion.jpg", - "size": 3.97, - "date": "2023 September" - }, - "InstaFlow 0.9B": { - "path": "XCLiu/instaflow_0_9B_from_sd_1_5", - "desc": "InstaFlow is an ultra-fast, one-step image generator that achieves image quality close to Stable Diffusion. This efficiency is made possible through a recent Rectified Flow technique, which trains probability flows with straight trajectories, hence inherently requiring only a single step for fast inference.", - "preview": "XCLiu--instaflow_0_9B_from_sd_1_5.jpg", - "size": 3.97, - "date": "2023 October" - }, - "DeepFloyd IF Medium": { - "path": "DeepFloyd/IF-I-M-v1.0", - "desc": "DeepFloyd-IF is a pixel-based text-to-image triple-cascaded diffusion model, that can generate pictures with new state-of-the-art for photorealism and language understanding. The result is a highly efficient model that outperforms current state-of-the-art models, achieving a zero-shot FID-30K score of 6.66 on the COCO dataset. It is modular and composed of frozen text mode and three pixel cascaded diffusion modules, each designed to generate images of increasing resolution: 64x64, 256x256, and 1024x1024.", - "preview": "DeepFloyd--IF-I-M-v1.0.jpg", + "StepFun Step1X-Edit v1.1": { + "path": "stepfun-ai/Step1X-Edit-v1p1-diffusers", + "preview": "stepfun-ai--Step1X-Edit-v1p1-diffusers.jpg", + "desc": "Multimodal image editing model using Step1X transformer architecture with Qwen2.5-VL text encoding, trained with Flow Matching scheduler for high-quality in-context image edits and refinements.", "extras": "sampler: Default", - "size": 75.87, - "date": "2023 March" + "size": 38.91, + "date": "2025 August" }, - "DeepFloyd IF Large": { - "path": "DeepFloyd/IF-I-L-v1.0", - "desc": "DeepFloyd-IF is a pixel-based text-to-image triple-cascaded diffusion model, that can generate pictures with new state-of-the-art for photorealism and language understanding. The result is a highly efficient model that outperforms current state-of-the-art models, achieving a zero-shot FID-30K score of 6.66 on the COCO dataset. It is modular and composed of frozen text mode and three pixel cascaded diffusion modules, each designed to generate images of increasing resolution: 64x64, 256x256, and 1024x1024.", - "preview": "DeepFloyd--IF-I-L-v1.0.jpg", + "Qwen-Image-Edit-2509": { + "path": "Qwen/Qwen-Image-Edit-2509", + "preview": "Qwen--Qwen-Image-Edit-2509.jpg", + "desc": "Qwen-Image-Edit, the image editing version of Qwen-Image. Built upon our 20B Qwen-Image model, Qwen-Image-Edit successfully extends Qwen-Image’s unique text rendering capabilities to image editing tasks, enabling precise text editing.", + "size": 53.74, + "date": "2025 September" + }, + "Wan-AI Wan2.2 14B VACE": { + "path": "linoyts/Wan2.2-VACE-Fun-14B-diffusers", + "preview": "linoyts--Wan2.2-VACE-Fun-14B-diffusers.jpg", + "desc": "Wan2.2, offering more powerful capabilities, better performance, and superior visual quality. With Wan2.2, we have focused on incorporating the following technical innovations: MoE Architecture, Data Scalling, Cinematic Aesthetics, Efficient High-Definition Hybrid", "extras": "sampler: Default", - "size": 82.18, - "date": "2023 March" + "size": 75.64, + "date": "2025 September" + }, + "Tencent HunyuanImage 2.1": { + "path": "hunyuanvideo-community/HunyuanImage-2.1-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-Diffusers.jpg", + "size": 49.48, + "date": "2025 September" + }, + "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.", + "preview": "hunyuanvideo-community--HunyuanImage-2.1-Diffusers.jpg", + "size": 45.78, + "date": "2025 September" + }, + "AlphaVLLM Lumina DiMOO": { + "path": "Alpha-VLLM/Lumina-DiMOO", + "desc": "Lumina-DiMOO is an omni diffusion large language model for multimodal generation and understanding with text-to-image, image editing, and multimodal understanding capabilities.", + "preview": "Alpha-VLLM--Lumina-DiMOO.jpg", + "extras": "sampler: Default", + "size": 0, + "date": "2025 September" + }, + "nVidia ChronoEdit": { + "path": "nvidia/ChronoEdit-14B-Diffusers", + "preview": "nvidia--ChronoEdit-14B-Diffusers.jpg", + "desc": "ChronoEdit reframes image editing as a video generation task, using input and edited images as start/end frames to leverage pretrained video models with temporal consistency.", + "size": 82.71, + "date": "2025 October" + }, + "Bria FIBO": { + "path": "briaai/FIBO", + "preview": "briaai--FIBO.jpg", + "desc": "BRIA FIBO is an 8-billion parameter text-to-image diffusion model using Flow Matching and featuring a lightweight SmolLM3-3B text encoder. Delivers high-quality, detailed image generation with efficient inference.", + "extras": "sampler: Default, cfg_scale: 3.5", + "size": 23.79, + "date": "2025 October" + }, + "Black Forest Labs FLUX.2 Dev": { + "path": "black-forest-labs/FLUX.2-dev", + "preview": "black-forest-labs--FLUX.2-dev.jpg", + "desc": "FLUX.2 generates high-quality images while maintaining character and style consistency across multiple reference images, following structured prompts, reading and writing complex text, adhering to brand guidelines, and reliably handling lighting, layouts, and logos.", + "size": 105.06, + "date": "2025 November" + }, + "Owen777 UltraFlux-v1": { + "path": "Owen777/UltraFlux-v1", + "preview": "Owen777--UltraFlux-v1.jpg", + "desc": "UltraFlux-v1 is a FLUX.1-dev based text-to-image model optimized for native 4K and multi-aspect-ratio generation with improved composition consistency.", + "extras": "sampler: Default, cfg_scale: 4.0, steps: 50", + "size": 31.58, + "date": "2025 November" + }, + "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 excels in photorealistic image generation, bilingual text rendering (English & Chinese), and robust instruction adherence.", + "extras": "sampler: Default, cfg_scale: 1.0, steps: 9", + "size": 30.58, + "date": "2025 November" + }, + "Kandinsky 5.0 T2I Lite": { + "path": "kandinskylab/Kandinsky-5.0-T2I-Lite-sft-Diffusers", + "desc": "Kandinsky 5.0 Image Lite is a 6B image generation models 1K resulution, high visual quality and strong text-writing", + "preview": "kandinskylab--Kandinsky-5.0-T2I-Lite-sft-Diffusers.jpg", + "size": 30.0, + "date": "2025 November" + }, + "Kandinsky 5.0 I2I Lite": { + "path": "kandinskylab/Kandinsky-5.0-I2I-Lite-sft-Diffusers", + "desc": "Kandinsky 5.0 Image Lite is a 6B image editing models 1K resulution, high visual quality and strong text-writing", + "preview": "kandinskylab--Kandinsky-5.0-T2I-Lite-sft-Diffusers.jpg", + "size": 30.01, + "date": "2025 November" + }, + "AIDC Ovis-Image 7B": { + "path": "AIDC-AI/Ovis-Image-7B", + "desc": "Built upon Ovis-U1, Ovis-Image is a 7B text-to-image model specifically optimized for high-quality text rendering, designed to operate efficiently under stringent computational constraints.", + "preview": "AIDC-AI--Ovis-Image-7B.jpg", + "size": 20.29, + "date": "2025 November" }, "Photoroom PRX 1024": { "path": "Photoroom/prx-1024-t2i-beta", @@ -858,12 +713,72 @@ "size": 19.28, "date": "2025 November" }, - "Photoroom PRXPixel": { - "path": "Photoroom/prxpixel-t2i", - "desc": "PRXPixel is a 7-billion-parameter pixel-space text-to-image model that denoises RGB images directly using a Qwen3-VL text encoder and flow-matching scheduler.", - "preview": "Photoroom--prxpixel-t2i.jpg", - "size": 16.25, - "date": "2026 June" + "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.", + "size": 53.74, + "date": "2025 December" + }, + "Qwen-Image-Edit-2511": { + "path": "Qwen/Qwen-Image-Edit-2511", + "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.", + "size": 53.74, + "date": "2025 December" + }, + "Qwen-Image-Layered": { + "path": "Qwen/Qwen-Image-Layered", + "preview": "Qwen--Qwen-Image-Layered.jpg", + "desc": "Qwen-Image-Layered, a model capable of decomposing an image into multiple RGBA layers", + "size": 53.74, + "date": "2025 December" + }, + "lodestones Zeta-Chroma": { + "path": "lodestones/Zeta-Chroma", + "preview": "lodestones--Zeta-Chroma.jpg", + "desc": "Zeta-Chroma is a pixel-space diffusion transformer image model from lodestones that generates images directly in RGB space using a NextDiT-style architecture.", + "extras": "sampler: Default, cfg_scale: 3.0, steps: 30", + "size": 12.11, + "date": "2025 December" + }, + "Meituan LongCat Image": { + "path": "meituan-longcat/LongCat-Image", + "preview": "meituan-longcat--LongCat-Image.jpg", + "desc": "Pioneering open-source and bilingual (Chinese-English) foundation model for image generation, designed to address core challenges in multilingual text rendering, photorealism, deployment efficiency, and developer accessibility prevalent in current leading models.", + "size": 27.28, + "date": "2025 December" + }, + "Meituan LongCat Image-Edit": { + "path": "meituan-longcat/LongCat-Image-Edit", + "preview": "meituan-longcat--LongCat-Image-Edit.jpg", + "desc": "Pioneering open-source and bilingual (Chinese-English) foundation model for image generation, designed to address core challenges in multilingual text rendering, photorealism, deployment efficiency, and developer accessibility prevalent in current leading models.", + "size": 27.28, + "date": "2025 December" + }, + "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.", + "extras": "sampler: Default, cfg_scale: 4.0, steps: 50", + "size": 14.87, + "date": "2026 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.", + "extras": "sampler: Default, cfg_scale: 4.0, steps: 50", + "size": 32.32, + "date": "2026 January" + }, + "Z-Image": { + "path": "Tongyi-MAI/Z-Image", + "preview": "Tongyi-MAI--Z-Image.jpg", + "desc": "Z-Image, an efficient image generation foundation model built on a Single-Stream Diffusion Transformer architecture. It preserves the complete training signal with full CFG support, enabling aesthetic versatility from hyper-realistic photography to anime, enhanced output diversity, and robust negative prompting for artifact suppression. Ideal base for LoRA training, ControlNet, and semantic conditioning.", + "extras": "sampler: Default, cfg_scale: 4.0, steps: 50", + "size": 19.11, + "date": "2026 January" }, "ZAI GLM-Image": { "path": "zai-org/GLM-Image", @@ -881,14 +796,6 @@ "size": 10.46, "date": "2026 January" }, - "Bria FIBO": { - "path": "briaai/FIBO", - "preview": "briaai--FIBO.jpg", - "desc": "BRIA FIBO is an 8-billion parameter text-to-image diffusion model using Flow Matching and featuring a lightweight SmolLM3-3B text encoder. Delivers high-quality, detailed image generation with efficient inference.", - "extras": "sampler: Default, cfg_scale: 3.5", - "size": 23.79, - "date": "2025 October" - }, "Bria Fibo-Edit": { "path": "briaai/Fibo-Edit", "preview": "briaai--Fibo-Edit.jpg", @@ -897,20 +804,59 @@ "size": 22.47, "date": "2026 January" }, - "Bria 3.2": { - "path": "SahilCarterr/BRIA-3.2", - "desc": "Bria 3.2 is the next-generation commercial-ready text-to-image model. With just 4 billion parameters, it provides exceptional aesthetics and text rendering, evaluated to provide on par results to leading open-source models, and outperforming other licensed models.", - "preview": "briaai--BRIA-3.2.jpg", - "size": 18.11, - "date": "2025 July" + "NucleusAI Nucleus-Image": { + "path": "NucleusAI/Nucleus-Image", + "preview": "NucleusAI--Nucleus-Image.jpg", + "desc": "Nucleus-Image is a sparse mixture-of-experts diffusion transformer with 17B total parameters and about 2B active parameters per forward pass, using a Qwen3-VL text encoder and Qwen-Image VAE for 1024px generation.", + "variant": "bf16", + "extras": "sampler: Default, cfg_scale: 8.0, steps: 50", + "size": 48.09, + "date": "2026 March" }, - "StepFun Step1X-Edit v1.1": { - "path": "stepfun-ai/Step1X-Edit-v1p1-diffusers", - "preview": "stepfun-ai--Step1X-Edit-v1p1-diffusers.jpg", - "desc": "Multimodal image editing model using Step1X transformer architecture with Qwen2.5-VL text encoding, trained with Flow Matching scheduler for high-quality in-context image edits and refinements.", + "Baidu ERNIE-Image": { + "path": "baidu/ERNIE-Image", + "preview": "baidu--ERNIE-Image.jpg", + "desc": "ERNIE-Image is a text-to-image diffusion transformer model that combines a Mistral3 text encoder with a FlowMatch transformer and Flux2-style VAE for 1024px image generation.", + "extras": "sampler: Default, cfg_scale: 4.0, steps: 50", + "size": 22.29, + "date": "2026 April" + }, + "JoyAI Image Edit": { + "path": "jdopensource/JoyAI-Image-Edit-Diffusers", + "preview": "jdopensource--JoyAI-Image-Edit-Diffusers.jpg", + "desc": "JoyAI Image Edit is a Diffusers-native image editing model that combines a JoyImageEdit transformer with Qwen3-VL multimodal conditioning for instruction-guided edits.", + "size": 46.86, "extras": "sampler: Default", - "size": 38.91, - "date": "2025 August" + "date": "2026 April" + }, + "Microsoft Lens": { + "path": "Jinstudio/Lens", + "preview": "microsoft--Lens.jpg", + "desc": "Microsoft Lens is a text-to-image DiT model using GPT-OSS chat-style prompt encoding and Flux2 VAE decoding.", + "size": 28.43, + "date": "2026 May" + }, + "Microsoft Lens Base": { + "path": "Jinstudio/Lens-Base", + "preview": "microsoft--Lens-Base.jpg", + "desc": "Microsoft Lens-Base is the base variant of Lens for text-to-image generation with GPT-OSS prompt features.", + "size": 28.43, + "date": "2026 May" + }, + "Anima 1.0 Base": { + "path": "vladmandic/Anima-1.0-Base", + "preview": "vladmandic--Anima-1.0-Base.jpg", + "desc": "Anima 1.0 Base with extended 1024-resolution training and expanded dataset coverage for less common artists. A 2B parameter anime-focused text-to-image model based on modified Cosmos-Predict-2B with Qwen3-0.6B text encoder, created by CircleStone Labs and Comfy Org.", + "date": "2026 May", + "size": 4.99 + }, + "HiDream-O1 Image": { + "path": "HiDream-ai/HiDream-O1-Image", + "desc": "HiDream-O1-Image is an 8B pixel-level unified transformer model for text-to-image generation, instruction editing, and multi-reference personalization up to 2048x2048.", + "preview": "HiDream-ai--HiDream-O1-Image.jpg", + "extras": "sampler: Default", + "size": 35.2, + "date": "2026 May" }, "VIBE Image Edit": { "path": "vladmandic/VIBE-Image-Edit", @@ -920,13 +866,50 @@ "size": 8.63, "date": "2026 May" }, - "JoyAI Image Edit": { - "path": "jdopensource/JoyAI-Image-Edit-Diffusers", - "preview": "jdopensource--JoyAI-Image-Edit-Diffusers.jpg", - "desc": "JoyAI Image Edit is a Diffusers-native image editing model that combines a JoyImageEdit transformer with Qwen3-VL multimodal conditioning for instruction-guided edits.", - "size": 46.86, - "extras": "sampler: Default", - "date": "2026 April" + "Boogu Image 0.1 Base": { + "path": "Boogu/Boogu-Image-0.1-Base", + "preview": "Boogu--Boogu-Image-0.1-Base.jpg", + "desc": "Boogu Image 0.1 Base is the core Boogu text-to-image model with Qwen3-VL instruction encoding and a mixed single/double-stream diffusion transformer.", + "size": 35.81, + "date": "2026 June" + }, + "Boogu Image 0.1 Edit": { + "path": "Boogu/Boogu-Image-0.1-Edit", + "preview": "Boogu--Boogu-Image-0.1-Edit.jpg", + "desc": "Boogu Image 0.1 Edit is optimized for image editing with the same instruction-aware Boogu transformer and flow-match scheduler.", + "size": 35.81, + "date": "2026 June" + }, + "Ideogram 4": { + "path": "CalamitousFelicitousness/Ideogram-4-bf16-Diffusers", + "preview": "CalamitousFelicitousness--Ideogram-4-bf16-Diffusers.jpg", + "desc": "Ideogram 4 is Ideogram's first open-weight text-to-image model: a two 9.3B flow-matching DiTs that uses a Qwen3-VL vision-language model as its text encoder, with strong in-image text rendering. Requires structured JSON-caption prompts; prompt-enhance (on by default) rewrites a plain prompt into one.", + "extras": "sampler: Default, cfg_scale: 7.0, steps: 20, width: 1024, height: 1024", + "size": 49.9, + "date": "2026 June" + }, + "Krea 2 Base": { + "path": "CalamitousFelicitousness/Krea-2-Base-Diffusers", + "preview": "CalamitousFelicitousness--Krea-2-Base-Diffusers.jpg", + "desc": "Krea 2 (K2) Base is the undistilled foundation model of the Krea 2 family, trained from scratch by Krea. A 12.9B-parameter single-stream flow-matching DiT that uses a Qwen3-VL-4B vision-language model as its text encoder and the Qwen-Image VAE. The base checkpoint is intended for fine-tuning and LoRA training; LoRAs trained on it apply to Krea 2 Turbo.", + "extras": "sampler: Default, cfg_scale: 4.5, steps: 52", + "size": 33.5, + "date": "2026 June" + }, + "Photoroom PRXPixel": { + "path": "Photoroom/prxpixel-t2i", + "desc": "PRXPixel is a 7-billion-parameter pixel-space text-to-image model that denoises RGB images directly using a Qwen3-VL text encoder and flow-matching scheduler.", + "preview": "Photoroom--prxpixel-t2i.jpg", + "size": 16.25, + "date": "2026 June" + }, + "Anima 1.0 Aesthetic": { + "path": "CalamitousFelicitousness/Anima-1.0-Aesthetic-Diffusers", + "preview": "CalamitousFelicitousness--Anima-1.0-Aesthetic-Diffusers.jpg", + "desc": "Anima 1.0 Aesthetic, fine-tuned for better consistency and a higher quality default art style. A 2B parameter anime-focused text-to-image model based on modified Cosmos-Predict-2B with Qwen3-0.6B text encoder, created by CircleStone Labs and Comfy Org.", + "extras": "sampler: Default, cfg_scale: 4.5, steps: 30", + "date": "2026 July", + "size": 4.99 }, "JoyAI Image Edit Plus": { "path": "jdopensource/JoyAI-Image-Edit-Plus-Diffusers", @@ -975,5 +958,38 @@ "extras": "sampler: Default", "size": 17.69, "date": "2026 July" + }, + "Anima 2.9B Preview v1": { + "path": "CalamitousFelicitousness/Anima-2.9B-Preview-v1-Diffusers", + "preview": "CalamitousFelicitousness--Anima-2.9B-Preview-v1-Diffusers.jpg", + "desc": "Anima 2.9B preview v1 by Gazingstars, a depth-expanded fine-tune of Anima 1.0 Base: the transformer is grown from 28 to 40 layers and trained on 1.7M additional anime and illustration samples with mixed tag and natural-language captions. Same Qwen3-0.6B text encoder, LLM adapter and VAE as Anima 1.0.", + "extras": "sampler: Default, cfg_scale: 4.0, steps: 30", + "date": "2026 August", + "size": 7.32 + }, + "MiniMaxAI MiniMax-H3": { + "path": "MiniMaxAI/MiniMax-H3", + "preview": "MiniMaxAI--MiniMax-H3.jpg", + "desc": "MiniMax-H3 generates video with synchronized stereo audio in a single denoising pass through a 33B single-stream transformer with a Qwen3-VL conditioner. In image tabs the model runs in experimental still mode, keeping the first frame of a minimal generation.", + "extras": "sampler: Default", + "size": 134.12, + "date": "2026 August" + }, + "MiniMaxAI MiniMax-H3 Ref2VA": { + "path": "MiniMaxAI/MiniMax-H3", + "subfolder": "ref2va", + "preview": "MiniMaxAI--MiniMax-H3.jpg", + "desc": "The omni-reference variant of MiniMax-H3, sharing one repository with the base model as a separate checkpoint partition. Video with synchronized stereo audio is conditioned on reference images for identity and appearance, with reference rows held clean while video rows denoise.", + "extras": "sampler: Default", + "size": 134.12, + "date": "2026 August" + }, + "inclusionAI LLaDA-Image": { + "path": "inclusionAI/LLaDA-Image", + "preview": "inclusionAI--LLaDA-Image.jpg", + "desc": "LLaDA-Image is a unified 6B image generation and editing model with text, VQ-conditioned, and reference-image workflows.", + "extras": "steps: 50, cfg_scale: 5.0", + "size": 37.15, + "date": "2026 September" } } diff --git a/data/reference-cloud.json b/data/reference-cloud.json index d08526559..59327c848 100644 --- a/data/reference-cloud.json +++ b/data/reference-cloud.json @@ -1,22 +1,26 @@ { - "Nano Banana": { - "path": "gemini-2.5-flash-image", - "desc": "Our best engine for high-velocity visual creation, offering state-of-the-art speed and efficiency. Gemini 2.5 Flash Image, also known as Nano Banana, is best for high-volume generation, conversational image editing, and low-latency creative workflows that require native multimodal understanding. (Knowledge cutoff June 2025)", - "preview": "gemini-2.5-flash-image.jpg" + "Nano Banana lite": { + "path": "gemini-3.1-flash-lite-image", + "desc": "Nano Banana Lite is designed as the efficiency specialist of the image generation family, offering ultra-low latency and cost-effective image generation and editing. By targeting a sub-2 second latency and significantly reduced TPU compute costs, this model enables high-volume interactive developer use cases and real-time consumer applications. (Knowledge cutoff January 2025)", + "preview": "gemini-3.1-flash-lite-image.jpg", + "date": "2026 July" }, "Nano Banana 2": { "path": "gemini-3.1-flash-image", "desc": "Nano Banana 2 provides high-quality image generation and conversational editing at a mainstream price point and low latency. It serves as the high-efficiency counterpart to Gemini 3 Pro Image, optimized for speed and high-volume developer use cases.(Knowledge cutoff January 2025)", - "preview": "gemini-3.1-flash-image.jpg" - }, - "Nano Banana lite": { - "path": "gemini-3.1-flash-lite-image", - "desc": "Nano Banana Lite is designed as the efficiency specialist of the image generation family, offering ultra-low latency and cost-effective image generation and editing. By targeting a sub-2 second latency and significantly reduced TPU compute costs, this model enables high-volume interactive developer use cases and real-time consumer applications. (Knowledge cutoff January 2025)", - "preview": "gemini-3.1-flash-lite-image.jpg" + "preview": "gemini-3.1-flash-image.jpg", + "date": "2026 February" }, "Nano Banana Pro": { "path": "gemini-3-pro-image", "desc": "Nano Banana Pro is a sophisticated reasoning-driven engine for professional-grade image editing and generation, offering studio-quality precision and advanced creative control. Nano Banana Pro is best for complex graphic design, high-fidelity product mockups, and factual data visualizations that require accurate text rendering and real-world grounding via Google Search. (Knowledge cutoff January 2025)", - "preview": "gemini-3-pro-image.jpg" + "preview": "gemini-3-pro-image.jpg", + "date": "2025 November" + }, + "Nano Banana": { + "path": "gemini-2.5-flash-image", + "desc": "Our best engine for high-velocity visual creation, offering state-of-the-art speed and efficiency. Gemini 2.5 Flash Image, also known as Nano Banana, is best for high-volume generation, conversational image editing, and low-latency creative workflows that require native multimodal understanding. (Knowledge cutoff June 2025)", + "preview": "gemini-2.5-flash-image.jpg", + "date": "2025 August" } } diff --git a/data/reference-community.json b/data/reference-community.json index 2fc9d5290..6fa5c68c7 100644 --- a/data/reference-community.json +++ b/data/reference-community.json @@ -1,17 +1,12 @@ { - "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.", - "size": 6.94, - "date": "2025 January" - }, - "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", - "size": 6.94, - "date": "2025 January" + "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, + "extras": "width: 512, height: 512, sampler: DEIS, steps: 20, cfg_scale: 6.0" }, "Juggernaut XL XI": { "path": "juggernautXL_juggXIByRundiffusion.safetensors@https://civitai.com/api/download/models/782002", @@ -29,28 +24,26 @@ "size": 6.94, "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, - "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", + "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": "", "size": 6.94, - "date": "2025 August" + "date": "2024 November" }, - "Pony Realism XL v2.3": { - "path": "ponyRealism_V23.safetensors@https://civitai.com/api/download/models/1763661", - "preview": "ponyRealism_V23.jpg", - "desc": "", - "size": 6.94, - "date": "2025 May" + "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", + "date": "2024 November", + "size": 31.41 + }, + "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-aesthetic.jpg", + "date": "2024 November", + "size": 31.41 }, "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", @@ -59,12 +52,33 @@ "size": 6.94, "date": "2024 December" }, - "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", + "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.", + "size": 6.94, + "date": "2025 January" + }, + "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", + "size": 6.94, + "date": "2025 January" + }, + "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", + "date": "2025 January", + "size": 31.41 + }, + "Pony Realism XL v2.3": { + "path": "ponyRealism_V23.safetensors@https://civitai.com/api/download/models/1763661", + "preview": "ponyRealism_V23.jpg", "desc": "", "size": 6.94, - "date": "2024 November" + "date": "2025 May" }, "WAI-Ani-Pony XL v14": { "path": "waiANIPONYXL_v140.safetensors@https://civitai.com/api/download/models/1767402", @@ -73,6 +87,55 @@ "size": 6.94, "date": "2025 May" }, + "WAI Illustrious XL v15": { + "path": "waiIllustriousSDXL_v150.safetensors@https://civitai.com/api/download/models/2167369", + "preview": "waiIllustriousSDXL_v150.jpg", + "desc": "", + "size": 6.94, + "date": "2025 August" + }, + "Tiwaz CenKreChro": { + "path": "Tiwaz/CenKreChro", + "preview": "Tiwaz--CenKreChro.jpg", + "desc": "Based Centerfold Flux 5, trying to merge in Chroma and Krea.", + "date": "2025 September", + "size": 31.42 + }, + "purplesmartai Pony 7": { + "path": "purplesmartai/pony-v7-base", + "preview": "purplesmartai--pony-v7-base.jpg", + "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.", + "date": "2025 October", + "size": 33.32 + }, + "Skywork UniPic3": { + "path": "Skywork/Unipic3", + "preview": "Skywork--Unipic3.jpg", + "desc": "UniPic3 is an image editing and multi-image composition model based. It is a fine-tune of Qwen-Image-Edit.", + "date": "2026 January", + "size": 53.74 + }, + "Skywork Unipic3-DMD": { + "path": "Skywork/Unipic3-DMD", + "preview": "Skywork--Unipic3-DMD.jpg", + "desc": "UniPic3-DMD-Model is a few-step image editing and multi-image composition model trained using Distribution Matching Distillation (DMD) and is a fine-tune of Qwen-Image-Edit.", + "date": "2026 January", + "size": 53.74 + }, + "FireRed Image Edit 1.0": { + "path": "FireRedTeam/FireRed-Image-Edit-1.0", + "preview": "FireRedTeam--FireRed-Image-Edit-1.0.jpg", + "desc": "FireRed-Image-Edit is a general-purpose image editing model that delivers high-fidelity and consistent editing across a wide range of scenarios. FireRed is a fine-tune of Qwen-Image-Edit.", + "date": "2026 February", + "size": 53.74 + }, + "FireRed Image Edit 1.1": { + "path": "FireRedTeam/FireRed-Image-Edit-1.1", + "preview": "FireRedTeam--FireRed-Image-Edit-1.1.jpg", + "desc": "FireRed-Image-Edit is a general-purpose image editing model that delivers high-fidelity and consistent editing across a wide range of scenarios. FireRed is a fine-tune of Qwen-Image-Edit.", + "date": "2026 March", + "size": 53.74 + }, "Z-Image-Turbo MoodyRealMix": { "path": "resonantsky/MoodyRealMix-SDNQ-int8-svd-r32", "preview": "resonantsky--MoodyRealMix-SDNQ-int8-svd-r32.jpg", @@ -100,69 +163,6 @@ "tags": "community, Z-image", "date": "2026 May" }, - "Tiwaz CenKreChro": { - "path": "Tiwaz/CenKreChro", - "preview": "Tiwaz--CenKreChro.jpg", - "desc": "Based Centerfold Flux 5, trying to merge in Chroma and Krea.", - "date": "2025 September", - "size": 31.42 - }, - "purplesmartai Pony 7": { - "path": "purplesmartai/pony-v7-base", - "preview": "purplesmartai--pony-v7-base.jpg", - "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.", - "date": "2025 October", - "size": 33.32 - }, - "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", - "date": "2024 November", - "size": 31.41 - }, - "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-aesthetic.jpg", - "date": "2024 November", - "size": 31.41 - }, - "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", - "date": "2025 January", - "size": 31.41 - }, - "FireRed Image Edit 1.0": { - "path": "FireRedTeam/FireRed-Image-Edit-1.0", - "preview": "FireRedTeam--FireRed-Image-Edit-1.0.jpg", - "desc": "FireRed-Image-Edit is a general-purpose image editing model that delivers high-fidelity and consistent editing across a wide range of scenarios. FireRed is a fine-tune of Qwen-Image-Edit.", - "date": "2026 February", - "size": 53.74 - }, - "FireRed Image Edit 1.1": { - "path": "FireRedTeam/FireRed-Image-Edit-1.1", - "preview": "FireRedTeam--FireRed-Image-Edit-1.1.jpg", - "desc": "FireRed-Image-Edit is a general-purpose image editing model that delivers high-fidelity and consistent editing across a wide range of scenarios. FireRed is a fine-tune of Qwen-Image-Edit.", - "date": "2026 March", - "size": 53.74 - }, - "Skywork UniPic3": { - "path": "Skywork/Unipic3", - "preview": "Skywork--Unipic3.jpg", - "desc": "UniPic3 is an image editing and multi-image composition model based. It is a fine-tune of Qwen-Image-Edit.", - "date": "2026 January", - "size": 53.74 - }, - "Skywork Unipic3-DMD": { - "path": "Skywork/Unipic3-DMD", - "preview": "Skywork--Unipic3-DMD.jpg", - "desc": "UniPic3-DMD-Model is a few-step image editing and multi-image composition model trained using Distribution Matching Distillation (DMD) and is a fine-tune of Qwen-Image-Edit.", - "date": "2026 January", - "size": 53.74 - }, "Anima 1.0 Base Merge sdnq-hadamard-uint4": { "path": "vladmandic/Anima-1.0-Base-Merge-sdnq-hadamard-uint4", "preview": "vladmandic--Anima-1.0-Base.jpg", diff --git a/data/reference-distilled.json b/data/reference-distilled.json index 96f70d453..9e894dc53 100644 --- a/data/reference-distilled.json +++ b/data/reference-distilled.json @@ -1,17 +1,20 @@ { - "Boogu Image 0.1 Turbo": { - "path": "Boogu/Boogu-Image-0.1-Turbo", - "preview": "Boogu--Boogu-Image-0.1-Turbo.jpg", - "desc": "Boogu Image 0.1 Turbo is the distilled fast inference variant of Boogu Image with the same Qwen3-VL instruction encoder and Boogu transformer architecture.", - "size": 35.81, - "date": "2026 June" + "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": 0.99, + "date": "2023 July" }, - "Boogu Image 0.1 Edit Turbo": { - "path": "Boogu/Boogu-Image-0.1-Edit-Turbo", - "preview": "Boogu--Boogu-Image-0.1-Edit-Turbo.jpg", - "desc": "Boogu Image 0.1 Edit Turbo is the distilled editing variant of Boogu Image with motion-aware instruction encoding and fast flow-match inference.", - "size": 35.81, - "date": "2026 June" + "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", + "extras": "sampler: Default, cfg_scale: 9.0", + "size": 12.48, + "date": "2023 October" }, "StabilityAI StableDiffusion XL Turbo": { "path": "stabilityai/sdxl-turbo", @@ -22,13 +25,29 @@ "size": 19.38, "date": "2023 November" }, - "Krea 2 Turbo": { - "path": "CalamitousFelicitousness/Krea-2-Turbo-Diffusers", - "preview": "CalamitousFelicitousness--Krea-2-Turbo-Diffusers.jpg", - "desc": "Krea 2 (K2) Turbo is the 8-step distilled inference model of the Krea 2 family, trained from scratch by Krea. A 12.9B-parameter single-stream flow-matching DiT that uses a Qwen3-VL-4B vision-language model as its text encoder and the Qwen-Image VAE. Runs without classifier-free guidance; LoRAs trained on Krea 2 Base apply directly.", - "extras": "sampler: Default, cfg_scale: 1.0, steps: 8", - "size": 33.5, - "date": "2026 June" + "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": "sampler: DEIS, steps: 40, cfg_scale: 6.0", + "experimental": true, + "date": "2024 May" + }, + "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", + "extras": "sampler: Default, cfg_scale: 2.0", + "size": 13.49, + "date": "2024 June" + }, + "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", + "extras": "sampler: Default, cfg_scale: 2.0", + "size": 13.43, + "date": "2024 July" }, "StabilityAI Stable Diffusion 3.5 Turbo": { "path": "stabilityai/stable-diffusion-3.5-large-turbo", @@ -39,28 +58,12 @@ "size": 36.12, "date": "2024 October" }, - "Microsoft Lens Turbo": { - "path": "Jinstudio/Lens-Turbo", - "preview": "microsoft--Lens-Turbo.jpg", - "desc": "Microsoft Lens-Turbo is the distilled Lens variant optimized for faster text-to-image generation with fewer steps.", - "size": 28.43, - "date": "2026 May" - }, - "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", - "extras": "sampler: Default, cfg_scale: 4.5", - "size": 31.42, - "date": "2025 September" - }, - "HiDream-O1 Image Dev": { - "path": "HiDream-ai/HiDream-O1-Image-Dev", - "preview": "HiDream-ai--HiDream-O1-Image-Dev.jpg", - "desc": "HiDream-O1-Image-Dev is the distilled 8B HiDream-O1 variant tuned for 28-step fast generation using flash flow scheduling.", - "extras": "sampler: Flash, steps: 28, cfg_scale: 0.0", - "size": 35.2, - "date": "2026 May" + "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", + "size": 9.03, + "date": "2025 March" }, "Qwen-Image-Lightning": { "path": "vladmandic/Qwen-Lightning", @@ -78,13 +81,20 @@ "size": 56.1, "date": "2025 August" }, - "Baidu ERNIE-Image-Turbo": { - "path": "baidu/ERNIE-Image-Turbo", - "preview": "baidu--ERNIE-Image-Turbo.jpg", - "desc": "ERNIE-Image-Turbo is a distilled ERNIE-Image variant optimized for fast generation with fewer denoising steps.", - "extras": "sampler: Default, cfg_scale: 1.0, steps: 8", - "size": 22.29, - "date": "2026 April" + "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. It’s 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.", + "size": 25.6, + "date": "2025 August" + }, + "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", + "extras": "sampler: Default, cfg_scale: 4.5", + "size": 31.42, + "date": "2025 September" }, "Qwen-Image-Lightning-Edit": { "path": "vladmandic/Qwen-Lightning-Edit", @@ -110,6 +120,13 @@ "date": "2025 September", "size": 41.08 }, + "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", + "size": 49.53, + "date": "2025 September" + }, "Qwen-Image-Edit-2509 Pruning-13B": { "path": "OPPOer/Qwen-Image-Edit-2509-Pruning", "subfolder": "Qwen-Image-Edit-2509-13B-4steps", @@ -118,51 +135,6 @@ "date": "2025 October", "size": 42.34 }, - "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. It’s 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.", - "size": 25.6, - "date": "2025 August" - }, - "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": "sampler: DEIS, steps: 40, cfg_scale: 6.0", - "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", - "size": 9.03, - "date": "2025 March" - }, - "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", - "extras": "sampler: Default, cfg_scale: 9.0", - "size": 12.48, - "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": 0.99, - "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", - "size": 49.53, - "date": "2025 September" - }, "Bria Fibo-Lite": { "path": "briaai/Fibo-lite", "preview": "briaai--Fibo-lite.jpg", @@ -171,22 +143,6 @@ "size": 22.47, "date": "2025 November" }, - "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", - "extras": "sampler: Default, cfg_scale: 2.0", - "size": 13.43, - "date": "2024 July" - }, - "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", - "extras": "sampler: Default, cfg_scale: 2.0", - "size": 13.49, - "date": "2024 June" - }, "Black Forest Labs FLUX.2 Klein 4B": { "path": "black-forest-labs/FLUX.2-klein-4B", "preview": "black-forest-labs--FLUX.2-klein-4B.jpg", @@ -203,6 +159,13 @@ "size": 32.32, "date": "2026 January" }, + "Meituan LongCat Image-Edit Turbo": { + "path": "meituan-longcat/LongCat-Image-Edit-Turbo", + "preview": "meituan-longcat--LongCat-Image-Edit.jpg", + "desc": "LongCat-Image-Edit-Turbo, the distilled version of LongCat-Image-Edit. It achieves high-quality image editing with only 8 NFEs (Number of Function Evaluations) , offering extremely low inference latency.", + "size": 27.28, + "date": "2026 February" + }, "Black Forest Labs FLUX.2 Klein 9B KV": { "path": "black-forest-labs/FLUX.2-klein-9b-kv", "preview": "black-forest-labs--FLUX.2-klein-9b-kv.jpg", @@ -211,6 +174,51 @@ "size": 32.32, "date": "2026 March" }, + "Baidu ERNIE-Image-Turbo": { + "path": "baidu/ERNIE-Image-Turbo", + "preview": "baidu--ERNIE-Image-Turbo.jpg", + "desc": "ERNIE-Image-Turbo is a distilled ERNIE-Image variant optimized for fast generation with fewer denoising steps.", + "extras": "sampler: Default, cfg_scale: 1.0, steps: 8", + "size": 22.29, + "date": "2026 April" + }, + "Microsoft Lens Turbo": { + "path": "Jinstudio/Lens-Turbo", + "preview": "microsoft--Lens-Turbo.jpg", + "desc": "Microsoft Lens-Turbo is the distilled Lens variant optimized for faster text-to-image generation with fewer steps.", + "size": 28.43, + "date": "2026 May" + }, + "HiDream-O1 Image Dev": { + "path": "HiDream-ai/HiDream-O1-Image-Dev", + "preview": "HiDream-ai--HiDream-O1-Image-Dev.jpg", + "desc": "HiDream-O1-Image-Dev is the distilled 8B HiDream-O1 variant tuned for 28-step fast generation using flash flow scheduling.", + "extras": "sampler: Flash, steps: 28, cfg_scale: 0.0", + "size": 35.2, + "date": "2026 May" + }, + "Krea 2 Turbo": { + "path": "CalamitousFelicitousness/Krea-2-Turbo-Diffusers", + "preview": "CalamitousFelicitousness--Krea-2-Turbo-Diffusers.jpg", + "desc": "Krea 2 (K2) Turbo is the 8-step distilled inference model of the Krea 2 family, trained from scratch by Krea. A 12.9B-parameter single-stream flow-matching DiT that uses a Qwen3-VL-4B vision-language model as its text encoder and the Qwen-Image VAE. Runs without classifier-free guidance; LoRAs trained on Krea 2 Base apply directly.", + "extras": "sampler: Default, cfg_scale: 1.0, steps: 8", + "size": 33.5, + "date": "2026 June" + }, + "Boogu Image 0.1 Turbo": { + "path": "Boogu/Boogu-Image-0.1-Turbo", + "preview": "Boogu--Boogu-Image-0.1-Turbo.jpg", + "desc": "Boogu Image 0.1 Turbo is the distilled fast inference variant of Boogu Image with the same Qwen3-VL instruction encoder and Boogu transformer architecture.", + "size": 35.81, + "date": "2026 June" + }, + "Boogu Image 0.1 Edit Turbo": { + "path": "Boogu/Boogu-Image-0.1-Edit-Turbo", + "preview": "Boogu--Boogu-Image-0.1-Edit-Turbo.jpg", + "desc": "Boogu Image 0.1 Edit Turbo is the distilled editing variant of Boogu Image with motion-aware instruction encoding and fast flow-match inference.", + "size": 35.81, + "date": "2026 June" + }, "Anima 1.0 Turbo": { "path": "CalamitousFelicitousness/Anima-1.0-Turbo-Diffusers", "preview": "CalamitousFelicitousness--Anima-1.0-Turbo-Diffusers.jpg", @@ -219,13 +227,6 @@ "date": "2026 July", "size": 4.99 }, - "Meituan LongCat Image-Edit Turbo": { - "path": "meituan-longcat/LongCat-Image-Edit-Turbo", - "preview": "meituan-longcat--LongCat-Image-Edit.jpg", - "desc": "LongCat-Image-Edit-Turbo, the distilled version of LongCat-Image-Edit. It achieves high-quality image editing with only 8 NFEs (Number of Function Evaluations) , offering extremely low inference latency.", - "size": 27.28, - "date": "2026 February" - }, "Microsoft Mage-Flow Turbo": { "path": "vladmandic/Mage-Flow-4B-Turbo", "preview": "vladmandic--Mage-Flow-Turbo-4B.jpg", @@ -257,5 +258,13 @@ "extras": "sampler: Default", "size": 17.69, "date": "2026 July" + }, + "inclusionAI LLaDA-Image Turbo": { + "path": "inclusionAI/LLaDA-Image-Turbo", + "preview": "inclusionAI--LLaDA-Image-Turbo.jpg", + "desc": "LLaDA-Image-Turbo is the distilled fast-generation and editing variant of LLaDA-Image.", + "extras": "steps: 4, cfg_scale: 1.0", + "size": 37.15, + "date": "2026 September" } } diff --git a/data/reference-nunchaku.json b/data/reference-nunchaku.json index be4ae4a76..a8c8a4ddb 100644 --- a/data/reference-nunchaku.json +++ b/data/reference-nunchaku.json @@ -1,4 +1,27 @@ { + "SDXL Base Nunchaku SVDQuant": { + "path": "stabilityai/stable-diffusion-xl-base-1.0", + "subfolder": "nunchaku", + "preview": "stabilityai--stable-diffusion-xl-base-1.0.jpg", + "desc": "Nunchaku SVDQuant quantization of SDXL Base 1.0 UNet with INT4 and SVD rank 32", + "nunchaku": [ + "Model" + ], + "size": 32.0, + "date": "2023 July" + }, + "SDXL Turbo Nunchaku SVDQuant": { + "path": "stabilityai/sdxl-turbo", + "subfolder": "nunchaku", + "preview": "stabilityai--sdxl-turbo.jpg", + "desc": "Nunchaku SVDQuant quantization of SDXL Turbo UNet with INT4 and SVD rank 32", + "nunchaku": [ + "Model" + ], + "extras": "sampler: Default, cfg_scale: 1.0, steps: 4", + "size": 19.38, + "date": "2023 November" + }, "FLUX.1-Dev Nunchaku SVDQuant": { "path": "black-forest-labs/FLUX.1-dev", "subfolder": "nunchaku", @@ -24,30 +47,6 @@ "size": 31.41, "date": "2024 July" }, - "FLUX.1-Kontext Nunchaku SVDQuant": { - "path": "black-forest-labs/FLUX.1-Kontext-dev", - "subfolder": "nunchaku", - "preview": "black-forest-labs--FLUX.1-Kontext-dev.jpg", - "desc": "Nunchaku SVDQuant quantization of FLUX.1-Kontext-dev transformer with INT4 and SVD rank 32", - "nunchaku": [ - "Model", - "TE" - ], - "size": 31.42, - "date": "2025 May" - }, - "FLUX.1-Krea Nunchaku SVDQuant": { - "path": "black-forest-labs/FLUX.1-Krea-dev", - "subfolder": "nunchaku", - "preview": "black-forest-labs--FLUX.1-Krea-dev.jpg", - "desc": "Nunchaku SVDQuant quantization of FLUX.1-Krea-dev transformer with INT4 and SVD rank 32", - "nunchaku": [ - "Model", - "TE" - ], - "size": 31.42, - "date": "2025 July" - }, "FLUX.1-Fill Nunchaku SVDQuant": { "path": "black-forest-labs/FLUX.1-Fill-dev", "subfolder": "nunchaku", @@ -74,6 +73,17 @@ "size": 40.68, "date": "2024 November" }, + "Sana 1.6B 1k Nunchaku SVDQuant": { + "path": "Efficient-Large-Model/Sana_1600M_1024px_BF16_diffusers", + "subfolder": "nunchaku", + "preview": "Efficient-Large-Model--Sana_1600M_1024px_diffusers.jpg", + "desc": "Nunchaku SVDQuant quantization of Sana 1.6B 1024px transformer with INT4 and SVD rank 32", + "nunchaku": [ + "Model" + ], + "size": 22.22, + "date": "2024 December" + }, "Shuttle Jaguar Nunchaku SVDQuant": { "path": "shuttleai/shuttle-jaguar", "subfolder": "nunchaku", @@ -86,6 +96,30 @@ "size": 31.41, "date": "2025 January" }, + "FLUX.1-Kontext Nunchaku SVDQuant": { + "path": "black-forest-labs/FLUX.1-Kontext-dev", + "subfolder": "nunchaku", + "preview": "black-forest-labs--FLUX.1-Kontext-dev.jpg", + "desc": "Nunchaku SVDQuant quantization of FLUX.1-Kontext-dev transformer with INT4 and SVD rank 32", + "nunchaku": [ + "Model", + "TE" + ], + "size": 31.42, + "date": "2025 May" + }, + "FLUX.1-Krea Nunchaku SVDQuant": { + "path": "black-forest-labs/FLUX.1-Krea-dev", + "subfolder": "nunchaku", + "preview": "black-forest-labs--FLUX.1-Krea-dev.jpg", + "desc": "Nunchaku SVDQuant quantization of FLUX.1-Krea-dev transformer with INT4 and SVD rank 32", + "nunchaku": [ + "Model", + "TE" + ], + "size": 31.42, + "date": "2025 July" + }, "Qwen-Image Nunchaku SVDQuant": { "path": "Qwen/Qwen-Image", "subfolder": "nunchaku", @@ -167,17 +201,6 @@ "size": 53.74, "date": "2025 September" }, - "Sana 1.6B 1k Nunchaku SVDQuant": { - "path": "Efficient-Large-Model/Sana_1600M_1024px_BF16_diffusers", - "subfolder": "nunchaku", - "preview": "Efficient-Large-Model--Sana_1600M_1024px_diffusers.jpg", - "desc": "Nunchaku SVDQuant quantization of Sana 1.6B 1024px transformer with INT4 and SVD rank 32", - "nunchaku": [ - "Model" - ], - "size": 22.22, - "date": "2024 December" - }, "Z-Image-Turbo Nunchaku SVDQuant": { "path": "Tongyi-MAI/Z-Image-Turbo", "subfolder": "nunchaku", @@ -190,29 +213,6 @@ "size": 30.58, "date": "2025 November" }, - "SDXL Base Nunchaku SVDQuant": { - "path": "stabilityai/stable-diffusion-xl-base-1.0", - "subfolder": "nunchaku", - "preview": "stabilityai--stable-diffusion-xl-base-1.0.jpg", - "desc": "Nunchaku SVDQuant quantization of SDXL Base 1.0 UNet with INT4 and SVD rank 32", - "nunchaku": [ - "Model" - ], - "size": 32.0, - "date": "2023 July" - }, - "SDXL Turbo Nunchaku SVDQuant": { - "path": "stabilityai/sdxl-turbo", - "subfolder": "nunchaku", - "preview": "stabilityai--sdxl-turbo.jpg", - "desc": "Nunchaku SVDQuant quantization of SDXL Turbo UNet with INT4 and SVD rank 32", - "nunchaku": [ - "Model" - ], - "extras": "sampler: Default, cfg_scale: 1.0, steps: 4", - "size": 19.38, - "date": "2023 November" - }, "Z-Image-Turbo Nunchaku-Lite": { "path": "lite-infer/z-image-turbo-nunchaku-lite-int4_r32-bnb4-text-encoder", "preview": "Tongyi-MAI--Z-Image-Turbo.jpg", @@ -295,5 +295,12 @@ "desc": "Nunchaku-Lite quantization using precompiled Kernels", "size": 10.92, "date": "2026 August" + }, + "MiniMaxAI MiniMax-H3 Nunchaku-Lite": { + "path": "rootonchair/MiniMax-H3-nunchaku-lite-int4", + "preview": "MiniMaxAI--MiniMax-H3.jpg", + "desc": "Nunchaku-Lite quantization using precompiled Kernels", + "size": 23.70, + "date": "2026 September" } } diff --git a/data/reference-quantized.json b/data/reference-quantized.json index d9ccfbc70..310a6c0af 100644 --- a/data/reference-quantized.json +++ b/data/reference-quantized.json @@ -27,37 +27,6 @@ "size": 12.6, "date": "2025 October" }, - "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", - "size": 31.89, - "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.", - "extras": "sampler: Default, cfg_scale: 1.0, steps: 4", - "size": 5.09, - "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.", - "extras": "sampler: Default, cfg_scale: 1.0, steps: 4", - "size": 11.73, - "date": "2026 January" - }, - "Black Forest Labs FLUX.2 Klein 9B KV sdnq-uint4-dynamic-svd": { - "path": "vladmandic/Flux.2-Klein-9B-KV-sdnq-hadamard-uint4", - "preview": "black-forest-labs--FLUX.2-klein-9b-kv.jpg", - "desc": "Dynamic 4-bit quantization of black-forest-labs/FLUX.2-klein-9B-KV using SDNQ with Hadamard.", - "extras": "sampler: Default, cfg_scale: 1.0, steps: 4", - "size": 12.26, - "date": "2026 July" - }, "Chroma1-HD sdnq-svd-uint4": { "path": "Disty0/Chroma1-HD-SDNQ-uint4-svd-r32", "preview": "Disty0--Chroma1-HD-SDNQ-uint4-svd-r32.jpg", @@ -79,48 +48,6 @@ "date": "2025 October", "size": 23.53 }, - "MiniMaxAI MiniMax-H3 sdnq-uint4": { - "path": "OzzyGT/MiniMax_H3_sdnq_dynamic_4bit", - "preview": "MiniMaxAI--MiniMax-H3.jpg", - "desc": "Quantization of MiniMaxAI/MiniMax-H3 using SDNQ: dynamic 4-bit uint. Video with synchronized audio; in image tabs the model runs in experimental still mode.", - "extras": "sampler: Default", - "size": 64.80, - "date": "2026 August" - }, - "MiniMaxAI MiniMax-H3 sdnq-uint4 Ref2VA": { - "path": "OzzyGT/MiniMax_H3_sdnq_dynamic_4bit", - "preview": "MiniMaxAI--MiniMax-H3.jpg", - "subfolder": "ref2va", - "desc": "Quantization of MiniMaxAI/MiniMax-H3 using SDNQ: dynamic 4-bit uint. Video with synchronized audio; in image tabs the model runs in experimental still mode.", - "extras": "sampler: Default", - "size": 64.80, - "date": "2026 August" - }, - "MiniMaxAI MiniMax-H3 Pruned sdnq-uint4": { - "path": "OzzyGT/MiniMax_H3_sdnq_4bit_pruned", - "preview": "OzzyGT--MiniMax_H3_sdnq_4bit_pruned.jpg", - "desc": "Quantization of MiniMaxAI/MiniMax-H3 using SDNQ: dynamic 4-bit uint. Video with synchronized audio; in image tabs the model runs in experimental still mode.", - "extras": "sampler: Default", - "size": 23.70, - "date": "2026 August" - }, - "MiniMaxAI MiniMax-H3 Pruned sdnq-uint4 Ref2VA": { - "path": "OzzyGT/MiniMax_H3_sdnq_4bit_pruned", - "preview": "OzzyGT--MiniMax_H3_sdnq_4bit_pruned.jpg", - "subfolder": "ref2va", - "desc": "Quantization of MiniMaxAI/MiniMax-H3 using SDNQ: dynamic 4-bit uint. Video with synchronized audio; in image tabs the model runs in experimental still mode.", - "extras": "sampler: Default", - "size": 23.70, - "date": "2026 August" - }, - "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", - "extras": "sampler: Default, cfg_scale: 1.0, steps: 9", - "size": 6.05, - "date": "2025 November" - }, "Qwen-Image sdnq-svd-uint4": { "path": "Disty0/Qwen-Image-SDNQ-uint4-svd-r32", "preview": "Qwen--Qwen-Image.jpg", @@ -128,13 +55,6 @@ "date": "2025 October", "size": 16.09 }, - "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", - "size": 16.09, - "date": "2026 January" - }, "Qwen-Image-Edit sdnq-svd-uint4": { "path": "Disty0/Qwen-Image-Edit-SDNQ-uint4-svd-r32", "preview": "Qwen--Qwen-Image-Edit.jpg", @@ -149,20 +69,6 @@ "date": "2025 October", "size": 16.09 }, - "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", - "date": "2025 December", - "size": 16.09 - }, - "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", - "date": "2025 December", - "size": 16.09 - }, "nVidia ChronoEdit sdnq-svd-uint4": { "path": "Disty0/ChronoEdit-14B-SDNQ-uint4-svd-r32", "preview": "Disty0--ChronoEdit-14B-SDNQ-uint4-svd-r32.jpg", @@ -198,6 +104,58 @@ "size": 3.37, "date": "2025 October" }, + "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", + "size": 31.89, + "date": "2025 November" + }, + "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", + "extras": "sampler: Default, cfg_scale: 1.0, steps: 9", + "size": 6.05, + "date": "2025 November" + }, + "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", + "date": "2025 December", + "size": 16.09 + }, + "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", + "date": "2025 December", + "size": 16.09 + }, + "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.", + "extras": "sampler: Default, cfg_scale: 1.0, steps: 4", + "size": 5.09, + "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.", + "extras": "sampler: Default, cfg_scale: 1.0, steps: 4", + "size": 11.73, + "date": "2026 January" + }, + "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", + "size": 16.09, + "date": "2026 January" + }, "ZAI GLM-Image sdnq-dynamic-uint4": { "path": "Disty0/GLM-Image-SDNQ-4bit-dynamic", "preview": "zai-org--GLM-Image.jpg", @@ -260,6 +218,22 @@ "size": 17.3, "date": "2026 June" }, + "Krea 2 Base sdnq-hadamard-uint4": { + "path": "vladmandic/Krea-2-Base-sdnq-hadamard-uint4", + "preview": "CalamitousFelicitousness--Krea-2-Base-Diffusers.jpg", + "desc": "Krea 2 (K2) Base is the undistilled foundation model of the Krea 2 family, trained from scratch by Krea. A 12.9B-parameter single-stream flow-matching DiT that uses a Qwen3-VL-4B vision-language model as its text encoder and the Qwen-Image VAE. The base checkpoint is intended for fine-tuning and LoRA training; LoRAs trained on it apply to Krea 2 Turbo.", + "extras": "sampler: Default, cfg_scale: 4.5, steps: 52", + "size": 10.3, + "date": "2026 June" + }, + "Black Forest Labs FLUX.2 Klein 9B KV sdnq-uint4-dynamic-svd": { + "path": "vladmandic/Flux.2-Klein-9B-KV-sdnq-hadamard-uint4", + "preview": "black-forest-labs--FLUX.2-klein-9b-kv.jpg", + "desc": "Dynamic 4-bit quantization of black-forest-labs/FLUX.2-klein-9B-KV using SDNQ with Hadamard.", + "extras": "sampler: Default, cfg_scale: 1.0, steps: 4", + "size": 12.26, + "date": "2026 July" + }, "Krea 2 Turbo sdnq-hadamard-uint4": { "path": "vladmandic/Krea-2-Turbo-sdnq-hadamard-uint4", "preview": "CalamitousFelicitousness--Krea-2-Turbo-Diffusers.jpg", @@ -268,12 +242,72 @@ "size": 10.54, "date": "2026 July" }, - "Krea 2 Base sdnq-hadamard-uint4": { - "path": "vladmandic/Krea-2-Base-sdnq-hadamard-uint4", - "preview": "CalamitousFelicitousness--Krea-2-Base-Diffusers.jpg", - "desc": "Krea 2 (K2) Base is the undistilled foundation model of the Krea 2 family, trained from scratch by Krea. A 12.9B-parameter single-stream flow-matching DiT that uses a Qwen3-VL-4B vision-language model as its text encoder and the Qwen-Image VAE. The base checkpoint is intended for fine-tuning and LoRA training; LoRAs trained on it apply to Krea 2 Turbo.", - "extras": "sampler: Default, cfg_scale: 4.5, steps: 52", - "size": 10.3, - "date": "2026 June" + "MiniMaxAI MiniMax-H3 sdnq-uint4": { + "path": "OzzyGT/MiniMax_H3_sdnq_dynamic_4bit", + "preview": "MiniMaxAI--MiniMax-H3.jpg", + "desc": "Quantization of MiniMaxAI/MiniMax-H3 using SDNQ: dynamic 4-bit uint. Video with synchronized audio; in image tabs the model runs in experimental still mode.", + "extras": "sampler: Default", + "size": 64.80, + "date": "2026 August" + }, + "MiniMaxAI MiniMax-H3 sdnq-uint4 Ref2VA": { + "path": "OzzyGT/MiniMax_H3_sdnq_dynamic_4bit", + "preview": "MiniMaxAI--MiniMax-H3.jpg", + "subfolder": "ref2va", + "desc": "Quantization of MiniMaxAI/MiniMax-H3 using SDNQ: dynamic 4-bit uint. Video with synchronized audio; in image tabs the model runs in experimental still mode.", + "extras": "sampler: Default", + "size": 64.80, + "date": "2026 August" + }, + "MiniMaxAI MiniMax-H3 Pruned sdnq-uint4": { + "path": "OzzyGT/MiniMax_H3_sdnq_4bit_pruned", + "preview": "OzzyGT--MiniMax_H3_sdnq_4bit_pruned.jpg", + "desc": "Quantization of MiniMaxAI/MiniMax-H3 using SDNQ: dynamic 4-bit uint. Video with synchronized audio; in image tabs the model runs in experimental still mode.", + "extras": "sampler: Default", + "size": 23.70, + "date": "2026 August" + }, + "MiniMaxAI MiniMax-H3 Pruned sdnq-uint4 Ref2VA": { + "path": "OzzyGT/MiniMax_H3_sdnq_4bit_pruned", + "preview": "OzzyGT--MiniMax_H3_sdnq_4bit_pruned.jpg", + "subfolder": "ref2va", + "desc": "Quantization of MiniMaxAI/MiniMax-H3 using SDNQ: dynamic 4-bit uint. Video with synchronized audio; in image tabs the model runs in experimental still mode.", + "extras": "sampler: Default", + "size": 23.70, + "date": "2026 August" + }, + "MiniMaxAI MiniMax-H3 sdnq-uint8": { + "path": "OzzyGT/MiniMax_H3_sdnq_dynamic_8bit", + "preview": "MiniMaxAI--MiniMax-H3.jpg", + "desc": "Quantization of MiniMaxAI/MiniMax-H3 using SDNQ: dynamic 8-bit uint. Video with synchronized audio; in image tabs the model runs in experimental still mode.", + "extras": "sampler: Default", + "size": 32.29, + "date": "2026 August" + }, + "MiniMaxAI MiniMax-H3 sdnq-uint8 Ref2VA": { + "path": "OzzyGT/MiniMax_H3_sdnq_dynamic_8bit", + "preview": "MiniMaxAI--MiniMax-H3.jpg", + "subfolder": "ref2va", + "desc": "Quantization of MiniMaxAI/MiniMax-H3 using SDNQ: dynamic 8-bit uint. Video with synchronized audio; in image tabs the model runs in experimental still mode.", + "extras": "sampler: Default", + "size": 32.29, + "date": "2026 August" + }, + "MiniMaxAI MiniMax-H3 Pruned sdnq-uint8": { + "path": "OzzyGT/MiniMax_H3_sdnq_8bit_pruned", + "preview": "MiniMaxAI--MiniMax-H3.jpg", + "desc": "Quantization of MiniMaxAI/MiniMax-H3 using SDNQ: dynamic 8-bit uint. Video with synchronized audio; in image tabs the model runs in experimental still mode.", + "extras": "sampler: Default", + "size": 32.29, + "date": "2026 August" + }, + "MiniMaxAI MiniMax-H3 Pruned sdnq-uint8 Ref2VA": { + "path": "OzzyGT/MiniMax_H3_sdnq_8bit_pruned", + "preview": "MiniMaxAI--MiniMax-H3.jpg", + "subfolder": "ref2va", + "desc": "Quantization of MiniMaxAI/MiniMax-H3 using SDNQ: dynamic 8-bit uint. Video with synchronized audio; in image tabs the model runs in experimental still mode.", + "extras": "sampler: Default", + "size": 32.29, + "date": "2026 August" } } diff --git a/extensions-builtin/sdnext-kanvas b/extensions-builtin/sdnext-kanvas index b5fb2c580..e55743904 160000 --- a/extensions-builtin/sdnext-kanvas +++ b/extensions-builtin/sdnext-kanvas @@ -1 +1 @@ -Subproject commit b5fb2c580ffbaf0b7bd09a26410e698d04205e2a +Subproject commit e5574390433e2311b399dc90ab9d2ae259961c8c diff --git a/extensions-builtin/sdnext-modernui b/extensions-builtin/sdnext-modernui index 70d6dcae3..0bacb152d 160000 --- a/extensions-builtin/sdnext-modernui +++ b/extensions-builtin/sdnext-modernui @@ -1 +1 @@ -Subproject commit 70d6dcae3ef80a543173930a77ad5525d6ef1d9a +Subproject commit 0bacb152d214cddd0bff0477c8629080a1244769 diff --git a/extensions-builtin/sdnq b/extensions-builtin/sdnq index ac7b5ecf4..b9b50e4a5 160000 --- a/extensions-builtin/sdnq +++ b/extensions-builtin/sdnq @@ -1 +1 @@ -Subproject commit ac7b5ecf48f5891efe25dadedfe384f926ee0c5a +Subproject commit b9b50e4a598ddee318e5e48665bbfbecc5ab1d87 diff --git a/installer.py b/installer.py index 141f56e27..f76cf220c 100644 --- a/installer.py +++ b/installer.py @@ -1,5 +1,6 @@ from functools import lru_cache import os +import re import sys import json import time @@ -57,6 +58,7 @@ args = Dot({ 'use_ipex': False, 'use_cuda': False, 'use_rocm': False, + 'use_openvino': False, 'experimental': False, 'test': False, 'tls_selfsign': False, @@ -383,12 +385,11 @@ def git(arg: str, folder: str | None= None, ignore: bool = False, optional: bool # reattach as needed as head can get detached def branch(folder=None): - # if args.experimental: - # return None t_start = time.time() if not os.path.exists(os.path.join(folder or os.curdir, '.git')): return None branches = [] + detached = False try: b = git('branch --show-current', folder, optional=True) if b == '': @@ -397,20 +398,30 @@ def branch(folder=None): if len(branches) > 0 and len(marked) > 0: b = marked[0] if ('detached' in b or 'HEAD' in b) and len(branches) > 1: + detached = True b = branches[1].strip() - log.debug(f'Git detached head detected: folder="{folder}" reattach={b}') + log.debug(f'Submodule: folder="{folder}" reattach={b} git detached head detected') except Exception: b = git('git rev-parse --abbrev-ref HEAD', folder, optional=True) + + if args.experimental or args.skip_git or args.skip_all: + return b + if 'main' in b: - b = 'main' + tgt = 'main' elif 'master' in b: - b = 'master' + tgt = 'master' else: - b = b.split('\n')[0].replace('*', '').strip() - log.debug(f'Git submodule: {folder} / {b}') - git(f'checkout {b}', folder, ignore=True, optional=True) + tgt = b.split('\n')[0].replace('*', '').strip() + if (tgt != b) or detached: + log.debug(f'Submodule: folder="{folder}" branch="{b}" target="{tgt}"') + git(f'checkout {tgt}', folder, ignore=True, optional=True) + git('fetch', folder, ignore=True) + git(f'merge --ff-only origin/{tgt}', folder, ignore=True) + else: + log.debug(f'Submodule: folder="{folder}" branch="{b}"') ts('branch', t_start) - return b + return tgt # restart process @@ -552,33 +563,19 @@ def check_python(supported_minors=None, experimental_minors=None, reason=None): # register sdnq package from github submodule -def register_sdnq(skip=False, devices=None, shared=None): - if not skip: - t_start = time.time() - fn = os.path.join('extensions-builtin', 'sdnq', 'src', 'sdnq', '__init__.py') - name = "sdnq" - spec = importlib.util.spec_from_file_location(name, fn) - module = importlib.util.module_from_spec(spec) - sys.modules[name] = module - spec.loader.exec_module(module) # this is where actual import happens - import sdnq # pylint: disable=unused-import # test import - ts('sdnq', t_start) - if devices is not None: - import sdnq - sdnq.sdnext.devices = devices - sdnq.quantizer.devices = devices - sdnq.dequantizer.devices = devices - sdnq.quant_utils.devices = devices - sdnq.kernel_wrappers.devices = devices - if shared is not None: - import sdnq - sdnq.sdnext.shared = shared - sdnq.quantizer.shared = shared - sdnq.dequantizer.shared = shared - sdnq.quant_utils.shared = shared - sdnq.kernel_wrappers.shared = shared - sdnq.common.shared = shared - sdnq.loader.shared = shared +def register_sdnq(): + t_start = time.time() + os.environ.setdefault('SDNQ_LOGGER_NAME', 'sd') + if not args.use_openvino: + os.environ.setdefault('SDNQ_USE_OPENVINO_MM', '0') + fn = os.path.join('extensions-builtin', 'sdnq', 'src', 'sdnq', '__init__.py') + name = "sdnq" + spec = importlib.util.spec_from_file_location(name, fn) + module = importlib.util.module_from_spec(spec) + sys.modules[name] = module + spec.loader.exec_module(module) # this is where actual import happens + import sdnq # pylint: disable=unused-import # test import + ts('sdnq', t_start) # check diffusers version @@ -653,6 +650,26 @@ def check_onnx(): ts('onnx', t_start) +# check numpy version +def check_numpy(): + t_start = time.time() + if args.skip_all or args.skip_requirements: + return + torch_ver = package_version('torch') or '' + ver_match = re.match(r'^(\d+)\.(\d+)', torch_ver) + if ver_match: + torch_major, torch_minor = map(int, ver_match.groups()) + else: + torch_major, torch_minor = 0, 0 + if (torch_major, torch_minor) < (2, 11): + install('numpy==2.1.2', 'numpy', ignore=True) + install('scipy==1.14.1', 'scipy', ignore=True) + else: + install('numpy==2.4.6', 'numpy', ignore=True) + install('scipy==1.18.1', 'scipy', ignore=True) + ts('numpy', t_start) + + def install_cuda(): t_start = time.time() log.info('CUDA: nVidia toolkit detected') @@ -660,7 +677,7 @@ def install_cuda(): if args.use_nightly: cmd = os.environ.get('TORCH_COMMAND', '--upgrade --pre torch torchvision --index-url https://download.pytorch.org/whl/nightly/cu132 --extra-index-url https://download.pytorch.org/whl/nightly/cu130') else: - cmd = os.environ.get('TORCH_COMMAND', 'torch==2.13.0+cu132 torchvision==0.28.0+cu132 --index-url https://download.pytorch.org/whl/cu132') + cmd = os.environ.get('TORCH_COMMAND', 'torch==2.14.0+cu132 torchvision==0.29.0+cu132 --index-url https://download.pytorch.org/whl/cu132') return cmd @@ -732,7 +749,7 @@ def install_rocm_zluda(): zluda_installer.load() except Exception as e: log.error(f'Load ZLUDA: {e}') - else: # TODO rocm: switch to pytorch source when it becomes available + else: if device is None: log.error('ROCm: no agent found - make sure that graphics driver is installed and up to date') if device is not None and device.therock is not None: @@ -821,10 +838,10 @@ def install_openvino(): if sys.platform == 'darwin': torch_command = os.environ.get('TORCH_COMMAND', 'torch==2.11.0 torchvision==0.26.0') else: - torch_command = os.environ.get('TORCH_COMMAND', 'torch==2.11.0+cpu torchvision==0.26.0 --index-url https://download.pytorch.org/whl/cpu') + torch_command = os.environ.get('TORCH_COMMAND', 'torch==2.13.0+cpu torchvision==0.28.0 --index-url https://download.pytorch.org/whl/cpu') if not (args.skip_all or args.skip_requirements): - install(os.environ.get('OPENVINO_COMMAND', 'openvino==2026.2.1'), 'openvino') + install(os.environ.get('OPENVINO_COMMAND', 'openvino==2026.3.1'), 'openvino') ts('openvino', t_start) return torch_command @@ -1132,7 +1149,7 @@ def list_extensions_folder(folder, quiet=False): disabled_extensions = opts.get('disabled_extensions', []) enabled_extensions = [x for x in os.listdir(folder) if os.path.isdir(os.path.join(folder, x)) and x not in disabled_extensions and not x.startswith('.')] if not quiet: - log.info(f'Extensions: path="{folder}" enabled={enabled_extensions}') + log.info(f'Extensions: path="{folder}" available={enabled_extensions}') return enabled_extensions @@ -1289,13 +1306,6 @@ def install_pydantic(): reload('pydantic', '2.13.4') -def install_scipy(): - if args.new or (sys.version_info >= (3, 14)): - install('scipy==1.17.1', ignore=True, quiet=True) - else: - install('scipy==1.14.1', ignore=True, quiet=True) - - def install_opencv(): install('opencv-python==4.13.0.92', ignore=True, quiet=True) install('opencv-python-headless==4.13.0.92', ignore=True, quiet=True) @@ -1324,7 +1334,6 @@ def install_insightface(): def install_optional(): t_start = time.time() log.info('Installing optional requirements...') - install('pillow-heif') install('addict') install('yapf') install('--no-build-isolation git+https://github.com/Disty0/BasicSR@23c1fb6f5c559ef5ce7ad657f2fa56e41b121754', 'basicsr', ignore=True, quiet=True) @@ -1335,11 +1344,14 @@ def install_optional(): install('Cython', ignore=True, quiet=True) install('gguf', ignore=True, quiet=True) install('hf_transfer', ignore=True, quiet=True) - install('hf_xet', ignore=True, quiet=True) install('nvidia-ml-py', ignore=True, quiet=True) + install('pillow-heif') install('pillow-jxl-plugin==1.3.7', ignore=True, quiet=True) install('ultralytics==8.4.67', ignore=True, quiet=True) install('open-clip-torch', no_deps=True, quiet=True) + install('runai_model_streamer', ignore=True, quiet=True) + install('facexlib', ignore=True, quiet=True) + install('omegaconf', ignore=True, quiet=True) install('git+https://github.com/tencent-ailab/IP-Adapter.git', 'ip_adapter', ignore=True, quiet=True) # install('git+https://github.com/openai/CLIP.git', 'clip', quiet=True, no_build_isolation=True) ts('optional', t_start) @@ -1360,7 +1372,6 @@ def install_requirements(): log.info('Install requirements: this may take a while...') pip('install -r requirements.txt') if args.optional: - quick_allowed = False install_optional() log.info('Install: verifying requirements') if args.new: @@ -1375,7 +1386,6 @@ def install_requirements(): install_compel() install_pydantic() install_opencv() - install_scipy() if args.profile: pr.disable() print_profile(pr, 'Requirements') @@ -1384,7 +1394,10 @@ def install_requirements(): # set environment variables controlling the behavior of various libraries def set_environment(): + log.debug('Setting environment tuning') + from modules.logger import console + log.debug(f'Console: terminal={console.is_terminal} width={console.width} height={console.height} color={console.color_system} legacy={console.legacy_windows}') os.environ.setdefault('ACCELERATE', 'True') os.environ.setdefault('ATTN_PRECISION', 'fp16') os.environ.setdefault('ClDeviceGlobalMemSizeAvailablePercent', '100') @@ -1540,7 +1553,7 @@ def check_ui(ver): return t_start = time.time() if not same(ver): - log.debug(f'Branch mismatch: {ver}') + log.debug(f'Branch mismatch: module=ModernUI {ver}') try: if 'dev' in ver['branch']: target = 'dev' @@ -1567,7 +1580,7 @@ def check_kanvas(ver): return t_start = time.time() if not same(ver): - log.debug(f'Branch mismatch: {ver}') + log.debug(f'Branch mismatch: module=Kanvas {ver}') try: if 'dev' in ver['branch']: target = 'dev' @@ -1702,7 +1715,7 @@ def check_version(reset=True): # pylint: disable=unused-argument else: dt = commits["commit"]["commit"]["author"]["date"] commit = commits["commit"]["sha"][:8] - log.info(f'Version: app=sd.next latest={dt} hash={commit} branch={branch_name}') + log.info(f'Version: app="sd.next" latest={dt} hash={commit} branch={branch_name}') except Exception as e: log.error(f'Repository failed to check version: {e} {commits}') ts('latest', t_start) diff --git a/launch.py b/launch.py index 8583f403b..b90d01be5 100755 --- a/launch.py +++ b/launch.py @@ -238,7 +238,7 @@ def main(): init_args() # setup argparser and default folders installer.args = args installer.setup_logging(debug=args.debug, trace=args.trace, filename=args.log) - log.info('Starting SD.Next') + log.info('Starting: [bold cyan]SD.Next[/]') installer.get_logfile() try: sys.excepthook = installer.custom_excepthook @@ -262,6 +262,7 @@ def main(): installer.install('uv', 'uv') installer.install_gradio() installer.check_torch() + installer.check_numpy() installer.check_onnx() installer.check_transformers() installer.check_diffusers() diff --git a/models/Reference/CalamitousFelicitousness--Anima-2.9B-Preview-v1-Diffusers.jpg b/models/Reference/CalamitousFelicitousness--Anima-2.9B-Preview-v1-Diffusers.jpg new file mode 100644 index 000000000..a403db079 Binary files /dev/null and b/models/Reference/CalamitousFelicitousness--Anima-2.9B-Preview-v1-Diffusers.jpg differ diff --git a/models/Reference/inclusionAI--LLaDA-Image-Turbo.jpg b/models/Reference/inclusionAI--LLaDA-Image-Turbo.jpg new file mode 100644 index 000000000..1d0ad3c74 Binary files /dev/null and b/models/Reference/inclusionAI--LLaDA-Image-Turbo.jpg differ diff --git a/models/Reference/inclusionAI--LLaDA-Image.jpg b/models/Reference/inclusionAI--LLaDA-Image.jpg new file mode 100644 index 000000000..72a93c2af Binary files /dev/null and b/models/Reference/inclusionAI--LLaDA-Image.jpg differ diff --git a/modules/api/api.py b/modules/api/api.py index ee32648d3..2ac4345ce 100644 --- a/modules/api/api.py +++ b/modules/api/api.py @@ -29,7 +29,7 @@ class Api: self.router = APIRouter() if shared.cmd_opts.docs: docs.create_docs(app) - docs.create_redocs(app) + # docs.create_redocs(app) self.app = app self.queue_lock = queue_lock self.generate = generate.APIGenerate(queue_lock) @@ -178,6 +178,11 @@ class Api: from modules.api import upload upload.register_api() + # rate limiter + from modules.api.validate import init_limiter + init_limiter() + + def add_api_route(self, path: str, fn, auth: bool = True, **kwargs): if auth and self.credentials: deps = list(kwargs.get('dependencies', [])) diff --git a/modules/api/docs.py b/modules/api/docs.py index 208bf3a56..584b91b11 100644 --- a/modules/api/docs.py +++ b/modules/api/docs.py @@ -1,8 +1,6 @@ import json from starlette.responses import HTMLResponse from fastapi import FastAPI -from fastapi.openapi.docs import get_redoc_html, swagger_ui_default_parameters -from fastapi.encoders import jsonable_encoder def get_swagger_ui_html(*, @@ -16,6 +14,8 @@ def get_swagger_ui_html(*, init_oauth: dict | None = None, swagger_ui_parameters: dict | None = None, ) -> HTMLResponse: + from fastapi.encoders import jsonable_encoder + from fastapi.openapi.docs import swagger_ui_default_parameters current_swagger_ui_parameters = swagger_ui_default_parameters.copy() if swagger_ui_parameters: current_swagger_ui_parameters.update(swagger_ui_parameters) @@ -79,6 +79,7 @@ def create_docs(app: FastAPI): def create_redocs(app: FastAPI): + from fastapi.openapi.docs import get_redoc_html @app.get("/redocs", include_in_schema=False) # override for the default fastapi redocs route async def custom_redoc_html(): res = get_redoc_html( diff --git a/modules/api/helpers.py b/modules/api/helpers.py index f5087e5e8..f3db5de09 100644 --- a/modules/api/helpers.py +++ b/modules/api/helpers.py @@ -46,6 +46,7 @@ def decode_base64_to_image(encoding, quiet=False): decoded = base64.b64decode(encoding) data = io.BytesIO(decoded) image = Image.open(data) + image = image.convert('RGB') return image except Exception as e: log.warning(f'API cannot decode image: {e}') diff --git a/modules/api/models.py b/modules/api/models.py index eeb36e9ae..fb44567a1 100644 --- a/modules/api/models.py +++ b/modules/api/models.py @@ -366,11 +366,11 @@ class ReqPromptEnhance(BaseModel): repetition_penalty: Optional[float] = Field(title="Repetition penalty", default=None, description="Penalizes repeated tokens to reduce repetition (1.0=no penalty)") top_k: Optional[int] = Field(title="Top K", default=None, description="Limits token selection to the K most likely candidates") top_p: Optional[float] = Field(title="Top P", default=None, description="Nucleus sampling threshold (0-1)") - thinking: bool = Field(title="Thinking", default=False, description="Enable thinking/reasoning mode") - keep_thinking: bool = Field(title="Keep thinking", default=False, description="Keep thinking tokens in output") - use_vision: bool = Field(title="Use vision", default=True, description="Use vision if model supports it") + thinking: Optional[bool] = Field(title="Thinking", default=False, description="Enable thinking/reasoning mode") + keep_thinking: Optional[bool] = Field(title="Keep thinking", default=False, description="Keep thinking tokens in output") + use_vision: Optional[bool] = Field(title="Use vision", default=True, description="Use vision if model supports it") prefill: Optional[str] = Field(title="Prefill", default=None, description="Text to prefill the model response with") - keep_prefill: bool = Field(title="Keep prefill", default=False, description="Keep prefill text in the output") + keep_prefill: Optional[bool] = Field(title="Keep prefill", default=False, description="Keep prefill text in the output") custom_args: Optional[str] = Field(title="Custom args", default=None, description="Custom arguments for the model") process_words: Optional[str] = Field(title="Banned words", default=None, description="List of words to process") semantic_threshold: Optional[float] = Field(title="Semantic threshold", default=None, description="Semantic similarity threshold for processed words") diff --git a/modules/api/process.py b/modules/api/process.py index 19b712ad6..c25da7cca 100644 --- a/modules/api/process.py +++ b/modules/api/process.py @@ -226,6 +226,7 @@ class APIProcess: if len(instance) == 0: raise HTTPException(status_code=500, detail="Prompt enhancement script not found") instance = instance[0] + decoded = decode_base64_to_image(req.image) if req.image else None prompt = instance.enhance( model=model, prompt=req.prompt, @@ -244,7 +245,7 @@ class APIProcess: use_vision=req.use_vision, prefill=req.prefill or '', keep_prefill=req.keep_prefill, - image=decode_base64_to_image(req.image) if req.image else None, + image=decoded, seed=seed, nsfw=req.nsfw, custom_args=req.custom_args, diff --git a/modules/api/validate.py b/modules/api/validate.py index 7de27254a..dc0e20293 100644 --- a/modules/api/validate.py +++ b/modules/api/validate.py @@ -7,35 +7,37 @@ request_cost = { "/file": 0, "/internal/progress": 0, "/run/predict": 0, + "/sdapi/v1/control": 5, + "/sdapi/v1/img2img": 5, + "/sdapi/v1/txt2img": 5, + "/sdapi/v1/video": 5, "/sdapi/v1/browser/thumb": 0, "/sdapi/v1/network/thumb": 0, - "/sdapi/v1/txt2img": 5, - "/sdapi/v1/img2img": 5, - "/sdapi/v1/control": 5, - "/sdapi/v1/video": 5, } log_cost = { "/.well-known/appspecific/com.chrome.devtools.json": -1, - "/info": -1, "/file": -1, - "/token": -1, - "/theme.css": -1, - "/sdapi/v1/browser/thumb": -1, - "/sdapi/v1/network/thumb": -1, - "/run/predict": -1, - "/queue/join": -1, + "/info": -1, + "/icon": -1, "/internal/progress": -1, - "/sdapi/v1/version": -1, - "/sdapi/v1/log": -1, - "/sdapi/v1/torch": -1, + "/queue/join": -1, + "/run/predict": -1, + "/theme.css": -1, + "/token": -1, + "/sdapi/v1/checkpoint": -1, + "/sdapi/v1/gpu-smi": -1, "/sdapi/v1/gpu": -1, + "/sdapi/v1/loaded-loras": -1, + "/sdapi/v1/log": -1, "/sdapi/v1/memory": -1, "/sdapi/v1/platform": -1, - "/sdapi/v1/checkpoint": -1, - "/sdapi/v1/loaded-loras": -1, - "/sdapi/v1/gpu-smi": -1, - "/sdapi/v1/status": 60, "/sdapi/v1/progress": 60, + "/sdapi/v1/start": -1, + "/sdapi/v1/status": 60, + "/sdapi/v1/torch": -1, + "/sdapi/v1/version": -1, + "/sdapi/v1/browser/thumb": -1, + "/sdapi/v1/network/thumb": -1, } log_exclude_suffix = ['.css', '.js', '.ico', '.svg'] log_exclude_prefix = ['/assets'] @@ -99,6 +101,13 @@ def get_api_stats(): limiter.stats() +def init_limiter(): + global limiter # pylint: disable=global-statement + from modules.shared import opts, cmd_opts + if opts.server_rate_limit != limiter.request_limit: + limiter = Limiter(opts.server_rate_limit, cmd_opts.subpath, cmd_opts.profile) + + def validate_request(client, endpoint): global limiter # pylint: disable=global-statement from modules.shared import opts, cmd_opts @@ -114,6 +123,7 @@ def validate_request(client, endpoint): limiter.summary[key] += 1 return limiter.check_request(client, api) + def validate_log(client, endpoint): api = re.match(r"^[^?#&=]+", endpoint).group(0) if (limiter.subpath is not None) and (len(limiter.subpath) > 0) and api.startswith(limiter.subpath): # strip subpath from api for logging diff --git a/modules/api/video.py b/modules/api/video.py index 9afc66385..66dbe9efb 100644 --- a/modules/api/video.py +++ b/modules/api/video.py @@ -22,8 +22,9 @@ class ReqVideo(BaseModel): frames: int = Field(default=17, ge=1, le=1024, title="Frames", description="Number of frames; 1 produces a single still image on workflow models") steps: int = Field(default=50, ge=1, le=200, title="Steps", description="Number of inference steps") sampler_name: str = Field(default="Default", title="Sampler", description="Sampler name; Default keeps the model scheduler") - sampler_shift: float = Field(default=-1.0, title="Sampler shift", description="Scheduler flow shift; -1 keeps the model default") + sampler_shift: float = Field(default=-1.0, title="Sampler shift", description="Scheduler flow shift, the video schedule on models with a separate audio schedule; -1 keeps the model default") dynamic_shift: bool = Field(default=False, title="Dynamic shift", description="Enable dynamic scheduler shifting") + audio_shift: float = Field(default=-1.0, title="Audio shift", description="Audio schedule shift on models with a separate audio scheduler; -1 keeps the model default") seed: int = Field(default=-1, title="Seed", description="Generation seed; -1 for random") guidance_scale: float = Field(default=-1.0, title="Guidance scale", description="CFG scale; -1 keeps the model default") guidance_true: float = Field(default=-1.0, title="True guidance", description="True CFG scale; -1 keeps the model default") @@ -173,6 +174,7 @@ class APIVideo: sampler_name=sampler_name, sampler_shift=req.sampler_shift, dynamic_shift=req.dynamic_shift, + audio_shift=req.audio_shift, seed=req.seed, guidance_scale=req.guidance_scale, guidance_true=req.guidance_true, diff --git a/modules/attention.py b/modules/attention.py deleted file mode 100644 index 4f331a147..000000000 --- a/modules/attention.py +++ /dev/null @@ -1,355 +0,0 @@ -from functools import wraps -import torch -from modules import rocm, errors, devices -from modules.logger import log -from installer import install, installed, torch_info - - -def set_dynamic_attention(): - try: - sdpa_pre_dyanmic_atten = torch.nn.functional.scaled_dot_product_attention - from modules.sd_hijack_dynamic_atten import dynamic_scaled_dot_product_attention - torch.nn.functional.scaled_dot_product_attention = dynamic_scaled_dot_product_attention - torch_info.set(attention='dynamic') - return sdpa_pre_dyanmic_atten - except Exception as err: - log.error(f'Torch attention: type="dynamic attention" {err}') - return None - - -def set_sdnq_attention(): - try: - from modules import shared - from sdnq.kernels.triton_atten import sdnq_triton_atten - sdpa_pre_sdnq_atten = torch.nn.functional.scaled_dot_product_attention - @wraps(sdpa_pre_sdnq_atten) - def sdpa_sdnq_atten(query: torch.FloatTensor, key: torch.FloatTensor, value: torch.FloatTensor, attn_mask: torch.Tensor | None = None, dropout_p: float = 0.0, is_causal: bool = False, scale: float | None = None, enable_gqa: bool = False, **kwargs) -> torch.Tensor: - if ( - query.device.type != "cpu" - and (query.shape[-2] >= 32 and key.shape[-2] >= 32) - and (query.shape[-2] > 512 or key.shape[-2] > 512) # Skip TE - and query.shape[-3] > 1 # Skip VAE - ): - return sdnq_triton_atten( - query=query, key=key, value=value, attn_mask=attn_mask, - is_causal=is_causal, scale=scale, enable_gqa=enable_gqa, - matmul_dtype=shared.opts.sdnq_attention_matmul_type, - pv_matmul_dtype=shared.opts.sdnq_attention_pv_matmul_type, - smooth_k=shared.opts.sdnq_attention_smooth_k, - use_hadamard=shared.opts.sdnq_attention_use_hadamard, - hadamard_group_size=shared.opts.sdnq_attention_hadamard_group_size, - quantize_fp32=shared.opts.sdnq_attention_quantize_fp32, - use_fp16_accum=shared.opts.sdnq_attention_use_fp16_accum, - ) - else: - if enable_gqa: - kwargs["enable_gqa"] = enable_gqa - return sdpa_pre_sdnq_atten(query=query, key=key, value=value, attn_mask=attn_mask, dropout_p=dropout_p, is_causal=is_causal, scale=scale, **kwargs) - torch.nn.functional.scaled_dot_product_attention = sdpa_sdnq_atten - torch_info.set(attention='sdnq') - log.debug(f'Torch attention: type="SDNQ attention" matmul={shared.opts.sdnq_attention_matmul_type}:{shared.opts.sdnq_attention_pv_matmul_type} smooth={shared.opts.sdnq_attention_smooth_k} hadamard={shared.opts.sdnq_attention_use_hadamard} fp16_accum={shared.opts.sdnq_attention_use_fp16_accum}') - except Exception as err: - log.error(f'Torch attention: type="SDNQ attention" {err}') - - -def set_triton_flash_attention(backend: str): - try: - if backend in {"rocm", "zluda"}: # flash_attn_triton_amd only works with AMD - from modules.flash_attn_triton_amd import interface_fa - - sdpa_pre_triton_flash_atten = torch.nn.functional.scaled_dot_product_attention - @wraps(sdpa_pre_triton_flash_atten) - def sdpa_triton_flash_atten(query: torch.FloatTensor, key: torch.FloatTensor, value: torch.FloatTensor, attn_mask: torch.Tensor | None = None, dropout_p: float = 0.0, is_causal: bool = False, scale: float | None = None, enable_gqa: bool = False, **kwargs) -> torch.Tensor: - use_triton = ( - query.shape[-1] <= 128 - and attn_mask is None - and query.device.type != "cpu" - and key.device == query.device - and value.device == query.device - ) - if use_triton: - if scale is None: - scale = query.shape[-1] ** (-0.5) - head_size_og = query.size(3) - if head_size_og % 8 != 0: - query = torch.nn.functional.pad(query, [0, 8 - head_size_og % 8]) - key = torch.nn.functional.pad(key, [0, 8 - head_size_og % 8]) - value = torch.nn.functional.pad(value, [0, 8 - head_size_og % 8]) - query = query.transpose(1, 2) - key = key.transpose(1, 2) - value = value.transpose(1, 2) - out_padded = torch.zeros_like(query) - interface_fa.fwd(query, key, value, out_padded, dropout_p, scale, is_causal) - return out_padded[..., :head_size_og].transpose(1, 2) - else: - if enable_gqa: - kwargs["enable_gqa"] = enable_gqa - return sdpa_pre_triton_flash_atten(query=query, key=key, value=value, attn_mask=attn_mask, dropout_p=dropout_p, is_causal=is_causal, scale=scale, **kwargs) - torch.nn.functional.scaled_dot_product_attention = sdpa_triton_flash_atten - torch_info.set(attention='triton') - log.debug('Torch attention: type="Triton Flash attention"') - except Exception as err: - log.error(f'Torch attention: type="Triton Flash attention" {err}') - - -def set_flex_attention(): - try: - from torch.nn.attention.flex_attention import flex_attention, create_block_mask - def flex_attention_causal_mask(b, h, q_idx, kv_idx): # pylint: disable=unused-argument - return q_idx >= kv_idx - - sdpa_pre_flex_atten = torch.nn.functional.scaled_dot_product_attention - @wraps(sdpa_pre_flex_atten) - def sdpa_flex_atten(query: torch.FloatTensor, key: torch.FloatTensor, value: torch.FloatTensor, attn_mask: torch.Tensor | None = None, dropout_p: float = 0.0, is_causal: bool = False, scale: float | None = None, enable_gqa: bool = False, **kwargs) -> torch.Tensor: # pylint: disable=unused-argument - score_mod = None - block_mask = None - if attn_mask is not None: - batch_size, num_heads = query.shape[:2] - seq_len_q = query.shape[-2] - seq_len_kv = key.shape[-2] - if attn_mask.ndim == 2: - attn_mask = attn_mask.view(attn_mask.shape[0], 1, attn_mask.size[1], 1) - attn_mask = attn_mask.expand(batch_size, num_heads, seq_len_q, seq_len_kv) - if attn_mask.dtype == torch.bool: - def mask_mod(batch_idx, head_idx, q_idx, kv_idx): - return attn_mask[batch_idx, head_idx, q_idx, kv_idx] - block_mask = create_block_mask(mask_mod, batch_size, None, seq_len_q, seq_len_kv, device=query.device) - else: - def score_mod_fn(score, batch_idx, head_idx, q_idx, kv_idx): - return score + attn_mask[batch_idx, head_idx, q_idx, kv_idx] - score_mod = score_mod_fn - elif is_causal: - block_mask = create_block_mask(flex_attention_causal_mask, query.shape[0], query.shape[1], query.shape[-2], key.shape[-2], device=query.device) - return flex_attention(query, key, value, score_mod=score_mod, block_mask=block_mask, scale=scale, enable_gqa=enable_gqa) - - torch.nn.functional.scaled_dot_product_attention = sdpa_flex_atten - torch_info.set(attention="flex") - log.debug('Torch attention: type="Flex attention"') - except Exception as err: - log.error(f'Torch attention: type="Flex attention" {err}') - - -def set_ck_flash_attention(backend: str, device: torch.device): - try: - if backend == "rocm": - if not installed('flash-attn'): - log.info('Torch attention: type="Flash attention" building...') - agent = rocm.Agent(device) - install(rocm.get_flash_attention_command(agent), reinstall=True) - else: - install('flash-attn') - from flash_attn import flash_attn_func - - sdpa_pre_flash_atten = torch.nn.functional.scaled_dot_product_attention - @wraps(sdpa_pre_flash_atten) - def sdpa_flash_atten(query: torch.FloatTensor, key: torch.FloatTensor, value: torch.FloatTensor, attn_mask: torch.Tensor | None = None, dropout_p: float = 0.0, is_causal: bool = False, scale: float | None = None, enable_gqa: bool = False, **kwargs) -> torch.Tensor: - use_flash = ( - query.shape[-1] <= 128 - and attn_mask is None - and query.dtype != torch.float32 - and query.device.type != "cpu" - and key.device == query.device - and value.device == query.device - ) - if use_flash: - is_unsqueezed = False - if query.dim() == 3: - query = query.unsqueeze(0) - is_unsqueezed = True - if key.dim() == 3: - key = key.unsqueeze(0) - if value.dim() == 3: - value = value.unsqueeze(0) - if enable_gqa: - key = key.repeat_interleave(query.size(-3)//key.size(-3), -3) - value = value.repeat_interleave(query.size(-3)//value.size(-3), -3) - query = query.transpose(1, 2) - key = key.transpose(1, 2) - value = value.transpose(1, 2) - attn_output = flash_attn_func(q=query, k=key, v=value, dropout_p=dropout_p, causal=is_causal, softmax_scale=scale).transpose(1, 2) - if is_unsqueezed: - attn_output = attn_output.squeeze(0) - return attn_output - else: - if enable_gqa: - kwargs["enable_gqa"] = enable_gqa - return sdpa_pre_flash_atten(query=query, key=key, value=value, attn_mask=attn_mask, dropout_p=dropout_p, is_causal=is_causal, scale=scale, **kwargs) - torch.nn.functional.scaled_dot_product_attention = sdpa_flash_atten - torch_info.set(attention="flash") - log.debug('Torch attention: type="Flash attention"') - except Exception as err: - log.error(f'Torch attention: type="Flash attention" {err}') - - -def set_sage_attention(backend: str, device: torch.device): - try: - install('sageattention') - - use_cuda_backend = False - if (backend == "cuda") and (torch.cuda.get_device_capability(device) == (8, 6)): - use_cuda_backend = True # Detect GPU architecture - sm86 confirmed to need CUDA backend workaround as Sage Attention + Triton causes NaNs - try: - from sageattention import sageattn_qk_int8_pv_fp16_cuda - except Exception: - use_cuda_backend = False - - if use_cuda_backend: - from sageattention import sageattn_qk_int8_pv_fp16_cuda - def sage_attn_impl(query, key, value, is_causal, scale): - return sageattn_qk_int8_pv_fp16_cuda( - q=query, k=key, v=value, - tensor_layout="HND", - is_causal=is_causal, - sm_scale=scale, - return_lse=False, - pv_accum_dtype="fp32", - ) - else: - from sageattention import sageattn - def sage_attn_impl(query, key, value, is_causal, scale): - return sageattn( - q=query, k=key, v=value, - attn_mask=None, - dropout_p=0.0, - is_causal=is_causal, - scale=scale, - ) - - sdpa_pre_sage_atten = torch.nn.functional.scaled_dot_product_attention - @wraps(sdpa_pre_sage_atten) - def sdpa_sage_atten(query: torch.FloatTensor, key: torch.FloatTensor, value: torch.FloatTensor, attn_mask: torch.Tensor | None = None, dropout_p: float = 0.0, is_causal: bool = False, scale: float | None = None, enable_gqa: bool = False, **kwargs) -> torch.Tensor: - use_sage = ( - query.shape[-1] in {128, 96, 64} - and attn_mask is None - and query.device.type != "cpu" - and key.device == query.device - and value.device == query.device - ) - if use_sage: - if enable_gqa: - key = key.repeat_interleave(query.size(-3)//key.size(-3), -3) - value = value.repeat_interleave(query.size(-3)//value.size(-3), -3) - - # Call preselected sage attention implementation - return sage_attn_impl(query, key, value, is_causal, scale) - else: - if enable_gqa: - kwargs["enable_gqa"] = enable_gqa - return sdpa_pre_sage_atten(query=query, key=key, value=value, attn_mask=attn_mask, dropout_p=dropout_p, is_causal=is_causal, scale=scale, **kwargs) - torch.nn.functional.scaled_dot_product_attention = sdpa_sage_atten - torch_info.set(attention="sage") - log.debug(f'Torch attention: type="Sage attention" backend={"cuda" if use_cuda_backend else "auto"}') - except Exception as err: - log.error(f'Torch attention: type="Sage attention" {err}') - - -def set_diffusers_attention(pipe, quiet = False): - from modules import shared - import diffusers.models.attention_processor as p - - def set_attn(pipe, attention, name: str | None = None): - if attention is None: - return - # other models uses their own attention processor - if getattr(pipe, "unet", None) is not None and hasattr(pipe.unet, "set_attn_processor"): - try: - pipe.unet.set_attn_processor(attention) - except Exception as e: - if 'Nunchaku' in pipe.unet.__class__.__name__: - pass - else: - log.error(f'Torch attention: type="{name}" cls={attention.__class__.__name__} pipe={pipe.__class__.__name__} {e}') - - log.quiet(quiet, f'Setting model: attention="{shared.opts.cross_attention_optimization}"') - if shared.opts.cross_attention_optimization == "Disabled": - torch_info.set(attention="disabled") - elif shared.opts.cross_attention_optimization == "Scaled-Dot-Product": # The default set by Diffusers - devices.set_sdpa_params() - # set_attn(pipe, p.AttnProcessor2_0(), name="Scaled-Dot-Product") - elif shared.opts.cross_attention_optimization == "xFormers": - if hasattr(pipe, 'enable_xformers_memory_efficient_attention'): - torch_info.set(attention="xformers") - pipe.enable_xformers_memory_efficient_attention() - else: - log.warning(f"Attention: xFormers is not compatible with {pipe.__class__.__name__}") - elif shared.opts.cross_attention_optimization == "Batch matrix-matrix": - torch_info.set(attention="bmm") - set_attn(pipe, p.AttnProcessor(), name="Batch matrix-matrix") - elif shared.opts.cross_attention_optimization == "Dynamic Attention BMM": - from modules.sd_hijack_dynamic_atten import DynamicAttnProcessorBMM - torch_info.set(attention="dynamic_bmm") - set_attn(pipe, DynamicAttnProcessorBMM(), name="Dynamic Attention BMM") - - if shared.opts.attention_slicing != "Default" and hasattr(pipe, "enable_attention_slicing") and hasattr(pipe, "disable_attention_slicing"): - if shared.opts.attention_slicing: - pipe.enable_attention_slicing() - else: - pipe.disable_attention_slicing() - log.debug(f"Torch attention: slicing={shared.opts.attention_slicing}") - - pipe.current_attn_name = shared.opts.cross_attention_optimization - - -orig_get_kernel = None -def get_kernel_hijack(repo_id, revision=None, version=None, backend=None, user_agent=None, trust_remote_code: bool | list[str] = False): # pylint: disable=unused-argument - log.debug(f'Attention dispatcher hub: repo="{repo_id}" revision={revision} version={version} backend={backend}') - user_agent = 'kernels/0.16.0' - module = None - try: - module = orig_get_kernel(repo_id, revision=revision, version=version, backend=backend, user_agent=user_agent, trust_remote_code=True) - except Exception as e: - log.error(f'Attention dispatcher hub: {e}') - errors.display(e, 'kernels') - return module - - -def get_hf_api_hijack(user_agent = None): # pylint: disable=unused-argument - from huggingface_hub import HfApi - return HfApi(library_name="kernels", user_agent="donottrack") - - -def hijack_kernels(): - global orig_get_kernel # pylint: disable=global-statement - try: - install('kernels==0.16.0') - import kernels - import kernels.utils - log.debug(f'Attention dispatcher: kernels={kernels.__version__}') - if orig_get_kernel is None: - orig_get_kernel = kernels.get_kernel - kernels.get_kernel = get_kernel_hijack - kernels.utils._get_hf_api = get_hf_api_hijack # pylint: disable=protected-access - from diffusers.utils import import_utils - import_utils._kernels_available = True # pylint: disable=protected-access - import_utils._kernels_version = kernels.__version__ # pylint: disable=protected-access - except Exception as e: - log.error(f'Attention dispatcher kernels: {e}') - return - - -def set_attention_dispatcher(pipe): - from modules import shared - attn = shared.opts.hf_attention.strip().lower() - if pipe is None or not hasattr(pipe, 'transformer') or not hasattr(pipe.transformer, 'set_attention_backend'): - return - - from diffusers.models import attention_dispatch as a - backends = [b.value for b in a._AttentionBackendRegistry.list_backends()] # pylint: disable=protected-access - # https://huggingface.co/docs/kernels/index - # https://huggingface.co/docs/diffusers/optimization/attention_backends#available-backends - - if 'hub' in attn: - hijack_kernels() - - prev = a._AttentionBackendRegistry.get_active_backend() # pylint: disable=protected-access - if attn in backends: - try: - pipe.transformer.set_attention_backend(attn) - except Exception as e: - log.error(f'Attention dispatcher: target={attn} {e}') - current = a._AttentionBackendRegistry.get_active_backend() # pylint: disable=protected-access - log.debug(f'Attention dispatcher: target={attn} previous={prev[0].value} active={current[0]} list={backends}') - elif len(attn) > 0: - log.warning(f'Attention dispatcher: active={prev[0].value} list={backends} target={attn} not found') - else: - log.debug(f'Attention dispatcher: active={prev[0].value} list={backends}') diff --git a/modules/attention/__init__.py b/modules/attention/__init__.py new file mode 100644 index 000000000..8ae75345b --- /dev/null +++ b/modules/attention/__init__.py @@ -0,0 +1,12 @@ +"""Attention backends: one scaled_dot_product_attention router over the registered backends, the per-generation context, and the diffusers-side processor and dispatcher setup.""" +from modules.attention.registry import AttentionBackend, AttentionCall, Constraints, Platform, Registry, registry +from modules.attention.router import Plan, PlanEntry, build_plan, get_plan, install_router, reapply, reapply_options, report +from modules.attention.dispatcher import set_diffusers_attention, set_attention_dispatcher, list_dispatcher_backends, hijack_kernels, get_kernel_hijack, get_hf_api_hijack +from modules.attention import backends, context, debug + +__all__ = [ + 'AttentionBackend', 'AttentionCall', 'Constraints', 'Platform', 'Registry', 'registry', + 'Plan', 'PlanEntry', 'build_plan', 'get_plan', 'install_router', 'reapply', 'reapply_options', 'report', + 'set_diffusers_attention', 'set_attention_dispatcher', 'list_dispatcher_backends', 'hijack_kernels', 'get_kernel_hijack', 'get_hf_api_hijack', + 'backends', 'context', 'debug', +] diff --git a/modules/attention/backends/__init__.py b/modules/attention/backends/__init__.py new file mode 100644 index 000000000..49d166e9c --- /dev/null +++ b/modules/attention/backends/__init__.py @@ -0,0 +1,10 @@ +"""Built-in backends, registered in ascending priority.""" +from modules.attention.registry import registry +from modules.attention.backends import dynamic, flex, triton_amd, flash_ck, sage, sdnq + +registry.register(dynamic.backend) +registry.register(flex.backend) +registry.register(triton_amd.backend) +registry.register(flash_ck.backend) +registry.register(sage.backend) +registry.register(sdnq.backend) diff --git a/modules/attention/backends/dynamic.py b/modules/attention/backends/dynamic.py new file mode 100644 index 000000000..dcbdd8a5a --- /dev/null +++ b/modules/attention/backends/dynamic.py @@ -0,0 +1,11 @@ +from modules.attention.registry import AttentionBackend, Platform + + +def prepare(platform: Platform, original): # pylint: disable=unused-argument + from modules import devices + devices.sdpa_pre_dyanmic_atten = original # the sliced path calls this pin for every slice + from modules.sd_hijack_dynamic_atten import dynamic_scaled_dot_product_attention + return dynamic_scaled_dot_product_attention + + +backend = AttentionBackend(name='dynamic', label='Dynamic attention', priority=10, prepare=prepare, terminal=True) diff --git a/modules/attention/backends/flash_ck.py b/modules/attention/backends/flash_ck.py new file mode 100644 index 000000000..ebd0b27c0 --- /dev/null +++ b/modules/attention/backends/flash_ck.py @@ -0,0 +1,48 @@ +from installer import install, installed +from modules import rocm +from modules.logger import log +from modules.attention.registry import AttentionBackend, Constraints, Platform + + +def prepare(platform: Platform, original): # pylint: disable=unused-argument + try: + import flash_attn # pylint: disable=unused-import + except ImportError: + log.warning('Attention: type="Flash attention" not installed: starting build, this may take a while...') + if platform.backend == 'rocm': + if not installed('flash-attn'): + log.info('Attention: type="Flash attention" building...') + agent = rocm.Agent(platform.device) + install(rocm.get_flash_attention_command(agent), reinstall=True) + else: + install('--no-build-isolation flash-attn') + from flash_attn import flash_attn_func + + def call(query, key, value, attn_mask, dropout_p, is_causal, scale, enable_gqa): # pylint: disable=unused-argument + is_unsqueezed = False + if query.dim() == 3: + query = query.unsqueeze(0) + is_unsqueezed = True + if key.dim() == 3: + key = key.unsqueeze(0) + if value.dim() == 3: + value = value.unsqueeze(0) + if enable_gqa: + key = key.repeat_interleave(query.size(-3)//key.size(-3), -3) + value = value.repeat_interleave(query.size(-3)//value.size(-3), -3) + query = query.transpose(1, 2) + key = key.transpose(1, 2) + value = value.transpose(1, 2) + attn_output = flash_attn_func(q=query, k=key, v=value, dropout_p=dropout_p, causal=is_causal, softmax_scale=scale).transpose(1, 2) + if is_unsqueezed: + attn_output = attn_output.squeeze(0) + return attn_output + + log.debug('Attention: type="Flash attention"') + return call + + +backend = AttentionBackend( + name='flash', label='Flash attention', priority=40, prepare=prepare, + constraints=Constraints(max_head_dim=128, allow_mask=False, allow_float32=False, same_device=True), +) diff --git a/modules/attention/backends/flex.py b/modules/attention/backends/flex.py new file mode 100644 index 000000000..2bf283cea --- /dev/null +++ b/modules/attention/backends/flex.py @@ -0,0 +1,46 @@ +import torch +from modules.logger import log +from modules.attention.registry import AttentionBackend, Constraints, Platform + + +def prepare(platform: Platform, original): # pylint: disable=unused-argument + from torch.nn.attention.flex_attention import create_block_mask + from modules.attention.sparse import flex as sparse_flex + + def causal_mask(b, h, q_idx, kv_idx): # pylint: disable=unused-argument + return q_idx >= kv_idx + + def call(query, key, value, attn_mask, dropout_p, is_causal, scale, enable_gqa, selection=None): # pylint: disable=unused-argument + if selection is not None: + return sparse_flex.attend(query, key, value, selection, scale=scale, enable_gqa=enable_gqa) + # compiled, always: eager flex_attention materializes the whole score matrix, which is + # tens of gigabytes at video sequence lengths and fails in the driver rather than cleanly + flex_attention = sparse_flex.flex_call() + score_mod = None + block_mask = None + if attn_mask is not None: + batch_size, num_heads = query.shape[:2] + seq_len_q = query.shape[-2] + seq_len_kv = key.shape[-2] + attn_mask = attn_mask.expand(batch_size, num_heads, seq_len_q, seq_len_kv) # sdpa masks broadcast over the trailing dims + if attn_mask.dtype == torch.bool: + def mask_mod(batch_idx, head_idx, q_idx, kv_idx): + return attn_mask[batch_idx, head_idx, q_idx, kv_idx] + block_mask = create_block_mask(mask_mod, batch_size, None, seq_len_q, seq_len_kv, device=query.device) + else: + def score_mod_fn(score, batch_idx, head_idx, q_idx, kv_idx): + return score + attn_mask[batch_idx, head_idx, q_idx, kv_idx] + score_mod = score_mod_fn + elif is_causal: + block_mask = create_block_mask(causal_mask, query.shape[0], query.shape[1], query.shape[-2], key.shape[-2], device=query.device) + return flex_attention(query, key, value, score_mod=score_mod, block_mask=block_mask, scale=scale, enable_gqa=enable_gqa) + + log.debug('Attention: type="Flex attention"') + return call + + +backend = AttentionBackend( + name='flex', label='Flex attention', priority=20, prepare=prepare, + constraints=Constraints(min_ndim=4, same_device=True), # flex_attention takes 4d tensors on one device and compiles on cpu + caps=frozenset({'block_mask'}), +) diff --git a/modules/attention/backends/sage.py b/modules/attention/backends/sage.py new file mode 100644 index 000000000..19b01992e --- /dev/null +++ b/modules/attention/backends/sage.py @@ -0,0 +1,55 @@ +import torch +from installer import install, installed +from modules.logger import log +from modules.attention.registry import AttentionBackend, Constraints, Platform + + +def prepare(platform: Platform, original): # pylint: disable=unused-argument + if not installed('sageattention'): + log.warning('Attention: type="Sage attention" not installed: starting build, this may take a while...') + install('--no-build-isolation git+http://github.com/thu-ml/SageAttention.git', 'sageattention') + + use_cuda_backend = False + if platform.backend == 'cuda' and torch.cuda.get_device_capability(platform.device) == (8, 6): + use_cuda_backend = True # sm86 needs the cuda backend, sage attention over triton produces NaNs there + try: + from sageattention import sageattn_qk_int8_pv_fp16_cuda + except Exception: + use_cuda_backend = False + + if use_cuda_backend: + from sageattention import sageattn_qk_int8_pv_fp16_cuda + def sage_attn_impl(query, key, value, is_causal, scale): + return sageattn_qk_int8_pv_fp16_cuda( + q=query, k=key, v=value, + tensor_layout="HND", + is_causal=is_causal, + sm_scale=scale, + return_lse=False, + pv_accum_dtype="fp32", + ) + else: + from sageattention import sageattn + def sage_attn_impl(query, key, value, is_causal, scale): + return sageattn( + q=query, k=key, v=value, + attn_mask=None, + dropout_p=0.0, + is_causal=is_causal, + scale=scale, + ) + + def call(query, key, value, attn_mask, dropout_p, is_causal, scale, enable_gqa): # pylint: disable=unused-argument + if enable_gqa: + key = key.repeat_interleave(query.size(-3)//key.size(-3), -3) + value = value.repeat_interleave(query.size(-3)//value.size(-3), -3) + return sage_attn_impl(query, key, value, is_causal, scale) + + log.debug(f'Attention: type="Sage attention" backend={"cuda" if use_cuda_backend else "auto"}') + return call + + +backend = AttentionBackend( + name='sage', label='Sage attention', priority=50, prepare=prepare, + constraints=Constraints(head_dims=frozenset({64, 96, 128}), allow_mask=False, same_device=True), +) diff --git a/modules/attention/backends/sdnq.py b/modules/attention/backends/sdnq.py new file mode 100644 index 000000000..4422ce6f1 --- /dev/null +++ b/modules/attention/backends/sdnq.py @@ -0,0 +1,45 @@ +import inspect +from modules.logger import log +from modules.attention.registry import AttentionBackend, Constraints, Platform + + +def supports_block_mask(entry) -> bool: + """Whether the installed sdnq takes a block mask; the chain must not promise what the kernel cannot do.""" + try: + return 'block_mask' in inspect.signature(inspect.unwrap(entry)).parameters + except (TypeError, ValueError): + return False + + +def prepare(platform: Platform, original): # pylint: disable=unused-argument + from modules import shared + from sdnq.kernels.triton_atten import sdnq_triton_atten + options = { + 'matmul_dtype': shared.opts.sdnq_attention_matmul_type, + 'pv_matmul_dtype': shared.opts.sdnq_attention_pv_matmul_type, + 'smooth_k': shared.opts.sdnq_attention_smooth_k, + 'use_hadamard': shared.opts.sdnq_attention_use_hadamard, + 'hadamard_group_size': shared.opts.sdnq_attention_hadamard_group_size, + 'quantize_fp32': shared.opts.sdnq_attention_quantize_fp32, + 'use_fp16_accum': shared.opts.sdnq_attention_use_fp16_accum, + } + block_mask = supports_block_mask(sdnq_triton_atten) + + def call(query, key, value, attn_mask, dropout_p, is_causal, scale, enable_gqa, selection=None): # pylint: disable=unused-argument + if selection is not None: + return sdnq_triton_atten(query=query, key=key, value=value, attn_mask=attn_mask, is_causal=is_causal, scale=scale, enable_gqa=enable_gqa, block_mask=selection.keep, block_mask_m=selection.block_q, block_mask_n=selection.block_kv, **options) + return sdnq_triton_atten(query=query, key=key, value=value, attn_mask=attn_mask, is_causal=is_causal, scale=scale, enable_gqa=enable_gqa, **options) + + call.caps = backend.caps if block_mask else frozenset() + if not block_mask and getattr(shared.opts, 'sparse_attention_enabled', False): + log.warning('SDNQ attention: the installed sdnq has no block mask input, sparse attention cannot use it; update the sdnq submodule') + log.debug(f'Attention: type="SDNQ attention" matmul={options["matmul_dtype"]}:{options["pv_matmul_dtype"]} smooth={options["smooth_k"]} hadamard={options["use_hadamard"]} quantize_fp32={options["quantize_fp32"]} fp16_accum={options["use_fp16_accum"]} block_mask={block_mask}') + return call + + +backend = AttentionBackend( + name='sdnq', label='SDNQ attention', priority=60, prepare=prepare, + constraints=Constraints(min_tokens=32, min_long_side=512, min_heads=2), # sequences of 512 or fewer are text encoders, single-head calls the vae + options=('sdnq_attention_matmul_type', 'sdnq_attention_pv_matmul_type', 'sdnq_attention_smooth_k', 'sdnq_attention_use_hadamard', 'sdnq_attention_hadamard_group_size', 'sdnq_attention_quantize_fp32', 'sdnq_attention_use_fp16_accum'), + caps=frozenset({'block_mask', 'masked_block'}), # the kernel takes attn_mask and block_mask together +) diff --git a/modules/attention/backends/triton_amd.py b/modules/attention/backends/triton_amd.py new file mode 100644 index 000000000..45a655ede --- /dev/null +++ b/modules/attention/backends/triton_amd.py @@ -0,0 +1,32 @@ +import torch +from modules.logger import log +from modules.attention.registry import AttentionBackend, Constraints, Platform + + +def prepare(platform: Platform, original): # pylint: disable=unused-argument + from modules.flash_attn_triton_amd import interface_fa + + def call(query, key, value, attn_mask, dropout_p, is_causal, scale, enable_gqa): # pylint: disable=unused-argument + if scale is None: + scale = query.shape[-1] ** (-0.5) + head_size_og = query.size(3) + if head_size_og % 8 != 0: + query = torch.nn.functional.pad(query, [0, 8 - head_size_og % 8]) + key = torch.nn.functional.pad(key, [0, 8 - head_size_og % 8]) + value = torch.nn.functional.pad(value, [0, 8 - head_size_og % 8]) + query = query.transpose(1, 2) + key = key.transpose(1, 2) + value = value.transpose(1, 2) + out_padded = torch.zeros_like(query) + interface_fa.fwd(query, key, value, out_padded, dropout_p, scale, is_causal) + return out_padded[..., :head_size_og].transpose(1, 2) + + log.debug('Attention: type="Triton AMD Flash attention"') + return call + + +backend = AttentionBackend( + name='triton', label='Triton AMD Flash attention', priority=30, prepare=prepare, + constraints=Constraints(max_head_dim=128, allow_mask=False, same_device=True), + platforms=frozenset({'rocm', 'zluda'}), +) diff --git a/modules/attention/context.py b/modules/attention/context.py new file mode 100644 index 000000000..2badc90e2 --- /dev/null +++ b/modules/attention/context.py @@ -0,0 +1,111 @@ +"""Per-generation state for attention consumers: the component running, the denoiser forward about to run, and the model.""" +from contextlib import contextmanager +from dataclasses import dataclass +import torch + + +@dataclass +class GenerationContext: + active: bool = False + role: str | None = None # 'transformer', 'te' or 'vae' while a generation runs, None outside one + step: int = 0 # index of the denoiser forward about to run + steps: int = 0 # forwards in the current pass + forwards: int = 0 + model_key: tuple[str, str | None] | None = None # pipeline class and denoiser class, for telemetry and the sparse exclusion list + step_buffer: torch.Tensor | None = None # the step as a device scalar updated in place, so compiled readers keep their graph + layout: object | None = None # TokenLayout published by whoever knows the packing, None until something does + + +current = GenerationContext() + + +def denoiser_name(pipe) -> str | None: + for name in ('transformer', 'unet'): + module = getattr(pipe, name, None) + if module is not None: + return module.__class__.__name__ + return None + + +# every slot a pipeline can enter once per denoising step, from sd_offload_state.group_offload_main. The aux +# components on that list (decoder, controlnet, prior) are left alone: they pack no attention sequence, and a +# publication from one would clear the layout the denoiser just set +DENOISER_SLOTS = ('transformer', 'unet', 'transformer_2', 'transformer_ref', 'unconditional_transformer') + + +def install_layout_hook(pipe) -> None: + """Let a classic pipeline's denoiser publish its own packing: the modular path has its own hook, this is the rest.""" + from modules import shared + if pipe is None or not getattr(shared.opts, 'sparse_attention_enabled', False): + return + from modules.attention.sparse import layout as sparse_layout + + def publish(denoiser, args, kwargs): # pylint: disable=unused-argument + set_layout(sparse_layout.layout_from_kwargs(kwargs, denoiser.__class__.__name__)) + + for name in DENOISER_SLOTS: + module = getattr(pipe, name, None) + if module is None or getattr(module, 'sdnext_layout_hook', None) is not None or getattr(module, 'sdnext_state_hook', None) is not None: + continue + module.sdnext_layout_hook = module.register_forward_pre_hook(publish, with_kwargs=True) + + +def begin(pipe, steps: int = 0) -> None: + from modules import devices + current.active = True + current.role = 'transformer' + current.layout = None + current.model_key = (pipe.__class__.__name__, denoiser_name(pipe)) if pipe is not None else None + install_layout_hook(pipe) + device = devices.device if devices.device is not None else torch.device('cpu') + if current.step_buffer is None or current.step_buffer.device != device: + current.step_buffer = torch.zeros((), dtype=torch.int64, device=device) + new_pass(steps) + + +def new_pass(steps: int = 0) -> None: + """Restart the step count for a denoising pass: base, hires or refiner.""" + current.steps = int(steps or 0) + current.forwards = 0 + set_step(0) + + +def set_step(step: int) -> None: + current.step = int(step) + if current.step_buffer is not None: + current.step_buffer.fill_(current.step) + + +def tick(step: int | None = None) -> None: + """Advance to the next forward: the classic callback passes the completed step plus one, the modular pre-hook passes nothing and counts forwards.""" + set_step(current.forwards if step is None else step) + current.forwards = current.step + 1 + + +def set_layout(layout) -> None: + """Publish what the packed sequence holds; callers that know the packing set this per forward.""" + current.layout = layout + + +def end() -> None: + from modules.attention import debug + current.active = False + current.role = None + current.model_key = None + current.layout = None + new_pass(0) + debug.end_generation() + + +def set_role(name: str | None) -> None: + current.role = name + + +@contextmanager +def role(name: str): + previous = current.role + current.role = name + try: + yield + finally: + current.role = previous diff --git a/modules/attention/debug.py b/modules/attention/debug.py new file mode 100644 index 000000000..3f200c263 --- /dev/null +++ b/modules/attention/debug.py @@ -0,0 +1,42 @@ +"""Opt-in route tracing for the sdpa router, enabled by SD_ATTN_DEBUG.""" +import os +import torch +from modules.logger import log +from modules.attention import context + +enabled = os.environ.get('SD_ATTN_DEBUG', None) is not None +seen: set[tuple] = set() +counts: dict[tuple, int] = {} + + +def observe(name: str, query: torch.Tensor, key: torch.Tensor, attn_mask: torch.Tensor | None) -> None: + """Log each distinct route once: backend, component role, step, shapes, dtype, mask presence and whether the inputs are contiguous; count every call.""" + contiguous = query.is_contiguous() and key.is_contiguous() + signature = (name, context.current.role, tuple(query.shape), tuple(key.shape), str(query.dtype), attn_mask is not None, contiguous) + counts[signature] = counts.get(signature, 0) + 1 + if signature in seen: + return + seen.add(signature) + log.debug(f'Attention route: backend={name} role={context.current.role} step={context.current.step} q={list(query.shape)} k={list(key.shape)} dtype={query.dtype} mask={attn_mask is not None} contiguous={contiguous}') + + +def summary() -> list[str]: + """One line per route with its call count since the last generation, busiest first.""" + lines = [] + for signature, count in sorted(counts.items(), key=lambda item: -item[1]): + name, role, q_shape, k_shape, dtype, masked, contiguous = signature + lines.append(f'backend={name} role={role} q={list(q_shape)} k={list(k_shape)} dtype={dtype} mask={masked} contiguous={contiguous} calls={count}') + return lines + + +def end_generation() -> None: + """Log the route counts of the generation that just ended and start the next count.""" + if enabled and counts: + for line in summary(): + log.debug(f'Attention routes: {line}') + counts.clear() + + +def reset() -> None: + seen.clear() + counts.clear() diff --git a/modules/attention/dispatcher.py b/modules/attention/dispatcher.py new file mode 100644 index 000000000..6a8912347 --- /dev/null +++ b/modules/attention/dispatcher.py @@ -0,0 +1,126 @@ +from modules import errors +from modules.logger import log +from installer import install, torch_info + + +def set_xformers_attention(pipe): + try: + # install('xformers') + import xformers + log.debug(f'Attention: xFormers={xformers.__version__}') + import diffusers.utils.import_utils + diffusers.utils.import_utils._xformers_available = True # pylint: disable=protected-access + diffusers.utils.import_utils._xformers_version = xformers.__version__ # pylint: disable=protected-access + import diffusers.models.attention_processor + import importlib + importlib.reload(diffusers.models.attention_processor) + # diffusers.models.attention_processor.xformers = xformers + except Exception as e: + log.error(f'Attention: xFormers {e}') + return + if hasattr(pipe, 'enable_xformers_memory_efficient_attention'): + torch_info.set(attention="xformers") + pipe.enable_xformers_memory_efficient_attention() + else: + log.warning(f"Attention: xFormers is not compatible with {pipe.__class__.__name__}") + + +def set_diffusers_attention(pipe, quiet = False): + from modules import shared, attention + log.quiet(quiet, f'Setting model: attention="{shared.opts.cross_attention_optimization}"') + + attention.reapply() + plan = attention.get_plan() + if plan is not None and (plan.entries or plan.terminal): + pass # already set by router + elif shared.opts.cross_attention_optimization == "Scaled-Dot-Product": # The default set by Diffusers + pass # attention.reapply already called devices.set_sdpa_params + elif shared.opts.cross_attention_optimization == "xFormers": + set_xformers_attention(pipe) + elif shared.opts.cross_attention_optimization == "Disabled" or shared.opts.cross_attention_optimization == "Default": + torch_info.set(attention="default") + else: + log.warning(f'Attention: cls={pipe.__class__.__name__} method="{shared.opts.cross_attention_optimization}" not applied') + + if shared.opts.attention_slicing != "Default" and hasattr(pipe, "enable_attention_slicing") and hasattr(pipe, "disable_attention_slicing"): + if shared.opts.attention_slicing == "Enabled": + pipe.enable_attention_slicing() + else: + pipe.disable_attention_slicing() + log.debug(f"Attention: slicing={shared.opts.attention_slicing}") + pipe.current_attn_name = shared.opts.cross_attention_optimization + + +orig_get_kernel = None +def get_kernel_hijack(repo_id, revision=None, version=None, backend=None, user_agent=None, trust_remote_code: bool | list[str] = False): # pylint: disable=unused-argument + log.debug(f'Attention dispatcher hub: repo="{repo_id}" revision={revision} version={version} backend={backend}') + user_agent = 'kernels/0.16.0' + module = None + try: + module = orig_get_kernel(repo_id, revision=revision, version=version, backend=backend, user_agent=user_agent, trust_remote_code=True) + except Exception as e: + log.error(f'Attention dispatcher hub: {e}') + errors.display(e, 'kernels') + return module + + +def get_hf_api_hijack(user_agent = None): # pylint: disable=unused-argument + from huggingface_hub import HfApi + return HfApi(library_name="kernels", user_agent="donottrack") + + +def hijack_kernels(): + global orig_get_kernel # pylint: disable=global-statement + try: + install('kernels==0.16.1') + import kernels + import kernels.utils + log.debug(f'Attention dispatcher: kernels={kernels.__version__}') + if orig_get_kernel is None: + orig_get_kernel = kernels.get_kernel + kernels.get_kernel = get_kernel_hijack + kernels.utils._get_hf_api = get_hf_api_hijack # pylint: disable=protected-access + from diffusers.utils import import_utils + import_utils._kernels_available = True # pylint: disable=protected-access + import_utils._kernels_version = kernels.__version__ # pylint: disable=protected-access + except Exception as e: + log.error(f'Attention dispatcher kernels: {e}') + return + + +def set_attention_dispatcher(pipe): + from modules import shared + attn = shared.opts.hf_attention.strip().lower() + if pipe is None or not hasattr(pipe, 'transformer') or not hasattr(pipe.transformer, 'set_attention_backend'): + return + + from diffusers.models import attention_dispatch as a + backends = [b.value for b in a._AttentionBackendRegistry.list_backends()] # pylint: disable=protected-access + # https://huggingface.co/docs/kernels/index + # https://huggingface.co/docs/diffusers/optimization/attention_backends#available-backends + + if 'hub' in attn: + hijack_kernels() + + prev = a._AttentionBackendRegistry.get_active_backend() # pylint: disable=protected-access + if attn in backends: + try: + pipe.transformer.set_attention_backend(attn) + except Exception as e: + log.error(f'Attention dispatcher: target={attn} {e}') + current = a._AttentionBackendRegistry.get_active_backend() # pylint: disable=protected-access + log.debug(f'Attention dispatcher: target={attn} previous={prev[0].value} active={current[0]} list={backends}') + elif len(attn) > 0: + log.warning(f'Attention dispatcher: active={prev[0].value} kernels={backends} target={attn} not found') + else: + log.debug(f'Attention dispatcher: active={prev[0].value} kernels={backends}') + + +def list_dispatcher_backends() -> list: + """The kernels diffusers can dispatch attention to, for anything that offers hf_attention as a choice.""" + try: + from diffusers.models import attention_dispatch as a + return sorted(b.value for b in a._AttentionBackendRegistry.list_backends()) # pylint: disable=protected-access + except Exception as e: + log.error(f'Attention dispatcher: {e}') + return [] diff --git a/modules/attention/registry.py b/modules/attention/registry.py new file mode 100644 index 000000000..c4455cd99 --- /dev/null +++ b/modules/attention/registry.py @@ -0,0 +1,108 @@ +"""Declarative backend registry behind the scaled_dot_product_attention router.""" +from dataclasses import dataclass, field +from typing import Callable +import torch + + +AttentionCall = Callable[..., torch.Tensor] + + +@dataclass(frozen=True) +class Platform: + """Where the router runs: the devices backend name and the selected device.""" + backend: str + device: torch.device | None = None + + +@dataclass(frozen=True) +class Constraints: + """Shape, dtype and device conditions a backend serves; a call failing any of them moves on to the next entry.""" + allow_cpu: bool = False + allow_mask: bool = True + allow_float32: bool = True + same_device: bool = False + head_dims: frozenset[int] | None = None + max_head_dim: int | None = None + min_tokens: int = 0 # query and key sequences both at least this long + min_long_side: int = 0 # query or key sequence longer than this + min_heads: int = 0 + min_ndim: int = 0 + + def accepts(self, query: torch.Tensor, key: torch.Tensor, value: torch.Tensor, attn_mask: torch.Tensor | None) -> bool: + if not self.allow_cpu and query.device.type == 'cpu': + return False + if self.min_ndim and query.ndim < self.min_ndim: + return False + if not self.allow_mask and attn_mask is not None: + return False + if not self.allow_float32 and query.dtype == torch.float32: + return False + if self.same_device and (key.device != query.device or value.device != query.device): + return False + head_dim = query.shape[-1] + if self.head_dims is not None and head_dim not in self.head_dims: + return False + if self.max_head_dim is not None and head_dim > self.max_head_dim: + return False + if self.min_tokens and (query.shape[-2] < self.min_tokens or key.shape[-2] < self.min_tokens): + return False + if self.min_long_side and query.shape[-2] <= self.min_long_side and key.shape[-2] <= self.min_long_side: + return False + if self.min_heads and query.shape[-3] < self.min_heads: + return False + return True + + +@dataclass(frozen=True) +class AttentionBackend: + """One attention implementation: how to prepare it once and which calls it serves.""" + name: str + label: str # the cross_attention_optimization choice that enables it + priority: int # higher priority entries are tried first + prepare: Callable[[Platform, AttentionCall], AttentionCall | None] # imports and configures the implementation, returns its call or None + constraints: Constraints = field(default_factory=Constraints) + terminal: bool = False # serves every call the entries decline, in place of the original sdpa + platforms: frozenset[str] | None = None # devices backends the implementation exists for, None for all + options: tuple[str, ...] = () # settings the prepared call captures; a change to one rebuilds the chain + caps: frozenset[str] = frozenset() # what the call can consume beyond plain sdpa arguments: 'block_mask', and 'masked_block' when it composes one with a token mask + + def available_on(self, platform: Platform) -> bool: + return self.platforms is None or platform.backend in self.platforms + + def __repr__(self) -> str: + return f'AttentionBackend(name="{self.name}" label="{self.label}" priority={self.priority} terminal={self.terminal} platforms={list(self.platforms) if self.platforms is not None else []} options={self.options} caps={list(self.caps)})' + + +class Registry: + def __init__(self): + self.backends: dict[str, AttentionBackend] = {} + + def register(self, backend: AttentionBackend) -> AttentionBackend: + if backend.name in self.backends: + raise ValueError(f'attention backend registered twice: name={backend.name}') + if self.by_label(backend.label) is not None: + raise ValueError(f'attention backend label registered twice: label="{backend.label}"') + self.backends[backend.name] = backend + return backend + + def by_label(self, label: str) -> AttentionBackend | None: + return next((backend for backend in self.backends.values() if backend.label == label), None) + + def ordered(self) -> list[AttentionBackend]: + """Backends by ascending priority, the order they are prepared in.""" + return sorted(self.backends.values(), key=lambda backend: backend.priority) + + def labels(self) -> list[str]: + return [backend.label for backend in self.ordered()] + + def options(self) -> list[str]: + return sorted({name for backend in self.backends.values() for name in backend.options}) + + def with_cap(self, cap: str) -> list[AttentionBackend]: + return [backend for backend in self.ordered() if cap in backend.caps] + + def __repr__(self) -> str: + return f'Registry(backends={list(self.backends.keys())})' + + +registry = Registry() diff --git a/modules/attention/router.py b/modules/attention/router.py new file mode 100644 index 000000000..cd08ee81c --- /dev/null +++ b/modules/attention/router.py @@ -0,0 +1,167 @@ +"""The single scaled_dot_product_attention entry point over the prepared backends.""" +from dataclasses import dataclass +from functools import wraps +from typing import Callable +import torch +from installer import torch_info +from modules.logger import log +from modules.attention import context, debug +from modules.attention.registry import AttentionBackend, AttentionCall, Platform, Registry, registry as default_registry + + +@dataclass(frozen=True) +class PlanEntry: + backend: AttentionBackend + call: AttentionCall + caps: frozenset[str] = frozenset() # the backend's declared caps, narrowed to what prepare verified in the installed implementation + + +@dataclass(frozen=True) +class Plan: + """The prepared chain for one set of overrides: entries by descending priority, then the terminal or the original sdpa.""" + entries: tuple[PlanEntry, ...] + terminal: PlanEntry | None + original: AttentionCall + platform: Platform + labels: tuple[str, ...] + + def chain(self) -> list[str]: + names = [entry.backend.name for entry in self.entries] + names.append(self.terminal.backend.name if self.terminal is not None else 'sdpa') + return names + + +current_plan: Plan | None = None + + +def build_plan(labels, platform: Platform, original: AttentionCall, reg: Registry | None = None) -> Plan: + reg = reg if reg is not None else default_registry + entries: list[PlanEntry] = [] + terminal: PlanEntry | None = None + for backend in reg.ordered(): # ascending priority: the last prepared backend is tried first + if backend.label not in labels: + continue + if not backend.available_on(platform): + log.warning(f'Attention: type="{backend.label}" not available on backend={platform.backend}') + continue + try: + call = backend.prepare(platform, original) + except Exception as err: + log.error(f'Attention: type="{backend.label}" {err}') + continue + if call is None: + continue + entry = PlanEntry(backend=backend, call=call, caps=backend.caps & frozenset(getattr(call, 'caps', backend.caps))) + if backend.terminal: + terminal = entry + else: + entries.append(entry) + entries.reverse() + return Plan(entries=tuple(entries), terminal=terminal, original=original, platform=platform, labels=tuple(labels)) + + +def make_router(plan: Plan, observer: Callable | None = None, stage: Callable | None = None) -> AttentionCall: + entries = plan.entries + terminal = plan.terminal.call if plan.terminal is not None else None + terminal_name = plan.terminal.backend.name if plan.terminal is not None else 'sdpa' + original = plan.original + + @wraps(original) + def sdpa_router(query, key, value, attn_mask=None, dropout_p=0.0, is_causal=False, scale=None, enable_gqa=False, **kwargs): + for entry in entries: + if entry.backend.constraints.accepts(query, key, value, attn_mask): + if stage is not None and 'block_mask' in entry.caps: + selection = stage(query, key, value, attn_mask, is_causal, entry.caps) + if selection is not None: + if observer is not None: + observer(f'{entry.backend.name}+sparse', query, key, attn_mask) + return entry.call(query, key, value, attn_mask, dropout_p, is_causal, scale, enable_gqa, selection=selection) + if observer is not None: + observer(entry.backend.name, query, key, attn_mask) + return entry.call(query, key, value, attn_mask, dropout_p, is_causal, scale, enable_gqa) + if observer is not None: # pylint: disable=duplicate-code + observer(terminal_name, query, key, attn_mask) + if terminal is not None: + return terminal(query, key, value, attn_mask=attn_mask, dropout_p=dropout_p, is_causal=is_causal, scale=scale, enable_gqa=enable_gqa, **kwargs) + if enable_gqa: # older sdpa signatures and platform wrappers reject the keyword, so it only travels when set + kwargs['enable_gqa'] = enable_gqa + return original(query=query, key=key, value=value, attn_mask=attn_mask, dropout_p=dropout_p, is_causal=is_causal, scale=scale, **kwargs) + + return sdpa_router + + +def install_router(labels, platform: Platform, original: AttentionCall, reg: Registry | None = None) -> Plan: + """Prepare the enabled backends and install the router; an empty plan leaves the original sdpa in place.""" + global current_plan # pylint: disable=global-statement + plan = build_plan(labels, platform, original, reg) + debug.reset() + observer = debug.observe if debug.enabled else None + stage = build_sparse_stage(plan) + torch.nn.functional.scaled_dot_product_attention = make_router(plan, observer, stage) if (plan.entries or plan.terminal is not None) else original + current_plan = plan + torch_info.set(attention='>'.join(plan.chain())) + log.debug(f'Attention: chain={">".join(plan.chain())} backend={platform.backend} sparse={stage is not None}') + return plan + + +def build_sparse_stage(plan: Plan): + """Sparse attention is a stage over the chain rather than a chain member, so it needs a backend in the chain that consumes a block mask.""" + from modules.attention.sparse import stage as sparse_stage + try: + options = sparse_stage.read_options() + except Exception: + return None + if not options.enabled: + return None + capable = [entry.backend.name for entry in plan.entries if 'block_mask' in entry.caps] + if not capable: + names = [backend.label for backend in default_registry.with_cap('block_mask')] + log.warning(f'Attention: sparse=True compatible={names} not set') + return None + built = sparse_stage.make_stage(options) + if built is not None: + log.info(f'Attention: sparse=True type={capable[0]} budget={options.budget:.0%} gate={options.min_tokens} schedule={options.schedule_steps}x+{options.schedule_bump:.0%}') + return built + + +def get_plan() -> Plan | None: + return current_plan + + +def reapply_options(reg: Registry | None = None) -> list[str]: + """Settings whose change rebuilds the chain: the override set, the torch kernel flags, every option a backend captures, and the sparse stage.""" + from modules.attention.sparse import stage as sparse_stage + reg = reg if reg is not None else default_registry + return ['sdp_options', 'cross_attention_optimization', *reg.options(), *sparse_stage.OPTION_NAMES] + + +def reapply() -> None: + """Rebuild the chain from the current settings; a resident compiled model is reset so its graphs trace the new router.""" + from modules import devices, shared + devices.set_sdpa_params() + compiled = getattr(shared, 'compiled_model_state', None) + if compiled is not None and getattr(compiled, 'is_compiled', False): + torch._dynamo.reset() # pylint: disable=protected-access + log.debug('Attention: dynamo=reset compiled model resident') + + +def report() -> dict: + """The active chain, sparse stage and generation context, for the api and the debug log.""" + from modules.attention.sparse import stage as sparse_stage + plan = current_plan + state = context.current + options = sparse_stage.read_options() + layout = state.layout + return { + 'chain': plan.chain() if plan is not None else ['sdpa'], + 'overrides': list(plan.labels) if plan is not None else [], + 'sparse': { + 'enabled': options.enabled, + 'budget': options.budget, + 'gate': options.min_tokens, + 'capable': [entry.backend.name for entry in plan.entries if 'block_mask' in entry.caps] if plan is not None else [], + 'layout': {'source': layout.source, 'kinds': list(layout.kinds()), 'length': layout.length} if layout is not None else None, + }, + 'backend': plan.platform.backend if plan is not None else None, + 'context': {'active': state.active, 'role': state.role, 'step': state.step, 'steps': state.steps, 'model': state.model_key}, + } diff --git a/modules/attention/sparse/__init__.py b/modules/attention/sparse/__init__.py new file mode 100644 index 000000000..741692aa4 --- /dev/null +++ b/modules/attention/sparse/__init__.py @@ -0,0 +1,8 @@ +"""Block-sparse attention: the selector, the token layout it respects, and the consumers that apply it.""" +from modules.attention.sparse.selector import BlockSelection, SparseSpec, block_count, radial_blocks, schedule, select_blocks +from modules.attention.sparse.layout import Span, TokenLayout, block_pins, layout_from_index_kwargs, layout_from_kwargs, layout_from_prefix, layout_from_segments, publish_segments, segments_from_live + +__all__ = [ + 'BlockSelection', 'SparseSpec', 'block_count', 'radial_blocks', 'schedule', 'select_blocks', + 'Span', 'TokenLayout', 'block_pins', 'layout_from_index_kwargs', 'layout_from_kwargs', 'layout_from_prefix', 'layout_from_segments', 'publish_segments', 'segments_from_live', +] diff --git a/modules/attention/sparse/flex.py b/modules/attention/sparse/flex.py new file mode 100644 index 000000000..a9c1f979c --- /dev/null +++ b/modules/attention/sparse/flex.py @@ -0,0 +1,39 @@ +"""Turn a BlockSelection into the BlockMask FlexAttention consumes, and call it so the mask is honored.""" +import torch +from torch.nn.attention.flex_attention import BlockMask, flex_attention, _dense_to_ordered +from modules.attention.sparse.selector import BlockSelection + + +compiled_flex = None + + +def to_block_mask(selection: BlockSelection, device=None) -> BlockMask: + """All selected tiles go in the full slots, so mask_mod is never invoked and no dense S squared mask is built.""" + keep = selection.keep + if device is not None and keep.device != device: + keep = keep.to(device) + if keep.dim() != 4: + raise ValueError(f'block selection must be 4d, got {tuple(keep.shape)}') + # the partial slots stay empty by construction, so build them directly rather than sorting a mask of zeros + empty_num = torch.zeros(keep.shape[:-1], dtype=torch.int32, device=keep.device) + empty_indices = torch.zeros(keep.shape, dtype=torch.int32, device=keep.device) + full_num, full_indices = _dense_to_ordered(keep) + return BlockMask.from_kv_blocks( + empty_num, empty_indices, + full_kv_num_blocks=full_num, full_kv_indices=full_indices, + BLOCK_SIZE=(selection.block_q, selection.block_kv), + seq_lengths=(selection.seq_q, selection.seq_kv), # exact lengths, so a ragged tail is handled rather than rounded up + compute_q_blocks=False, # backward only metadata, and inference never reads it + ) + + +def flex_call(): + """flex_attention reads the block lists only when compiled; called eagerly it evaluates mask_mod instead and a block-only mask is silently dense.""" + global compiled_flex # pylint: disable=global-statement + if compiled_flex is None: + compiled_flex = torch.compile(flex_attention, dynamic=False) + return compiled_flex + + +def attend(query, key, value, selection: BlockSelection, scale=None, enable_gqa=False): + return flex_call()(query, key, value, block_mask=to_block_mask(selection, device=query.device), scale=scale, enable_gqa=enable_gqa) diff --git a/modules/attention/sparse/layout.py b/modules/attention/sparse/layout.py new file mode 100644 index 000000000..1f8eeac2e --- /dev/null +++ b/modules/attention/sparse/layout.py @@ -0,0 +1,172 @@ +"""What each token in a packed sequence is, so the selector knows what it may sparsify.""" +from dataclasses import dataclass +import torch + + +# only the bulk modalities are sparsifiable; everything else is pinned dense, and an unrecognized kind pins too +SPARSIFIABLE = frozenset({'video', 'image'}) +DROPPED = frozenset({'pad'}) + + +@dataclass(frozen=True) +class Span: + kind: str + start: int + end: int + + +@dataclass(frozen=True) +class TokenLayout: + """Ordered spans covering one packed sequence.""" + spans: tuple[Span, ...] + length: int + source: str = 'unknown' # how the layout was obtained, for the log + + def key(self) -> tuple: + return (self.length, self.source, tuple((s.kind, s.start, s.end) for s in self.spans)) + + def kinds(self) -> tuple[str, ...]: + return tuple(dict.fromkeys(s.kind for s in self.spans)) + + def sparsifiable_tokens(self) -> int: + return sum(s.end - s.start for s in self.spans if s.kind in SPARSIFIABLE) + + def token_flags(self, device) -> tuple[torch.Tensor, torch.Tensor]: + """Per token: may this be sparsified, and is it padding.""" + sparse = torch.zeros(self.length, dtype=torch.bool, device=device) + pad = torch.zeros(self.length, dtype=torch.bool, device=device) + for span in self.spans: + if span.kind in SPARSIFIABLE: + sparse[span.start:span.end] = True + elif span.kind in DROPPED: + pad[span.start:span.end] = True + return sparse, pad + + +def runs(indices: torch.Tensor) -> list[tuple[int, int]]: + """Contiguous [start, end) runs in a sorted 1d index tensor.""" + if indices.numel() == 0: + return [] + values = indices.detach().to('cpu', torch.int64).sort().values + breaks = (values[1:] - values[:-1] != 1).nonzero().flatten().tolist() + bounds = [0, *[b + 1 for b in breaks], values.numel()] + return [(int(values[bounds[i]].item()), int(values[bounds[i + 1] - 1].item()) + 1) for i in range(len(bounds) - 1)] + + +def layout_from_index_kwargs(kwargs: dict, length: int | None = None) -> TokenLayout | None: + """Read a layout off the *_indices tensors a pipeline passes its transformer by name.""" + spans: list[Span] = [] + for name, value in kwargs.items(): + if not name.endswith('_indices') or not torch.is_tensor(value) or value.dim() != 1 or value.is_floating_point(): + continue + kind = name[:-len('_indices')].lower() + found = runs(value) + for position, (start, end) in enumerate(found): + # a video run that is not the last one is keyframe conditioning, which stays dense + resolved = 'cond' if (kind == 'video' and position < len(found) - 1) else kind + spans.append(Span(kind=resolved, start=start, end=end)) + if not spans: + return None + spans.sort(key=lambda s: s.start) + return TokenLayout(spans=tuple(spans), length=length if length is not None else spans[-1].end, source='indices') + + +# how an architecture orders its joint sequence, which the call itself does not reveal. Verified against the +# diffusers transformers that take txt_ids and img_ids; HiDream packs image first and is deliberately absent, so +# it falls back rather than being pinned backwards. An unlisted class publishes nothing. +JOINT_TEXT_FIRST = frozenset({ + 'FluxTransformer2DModel', 'Flux2Transformer2DModel', 'ChromaTransformer2DModel', 'BriaTransformer2DModel', + 'BriaFiboTransformer2DModel', 'LongCatImageTransformer2DModel', 'OvisImageTransformer2DModel', +}) + + +def layout_from_stream_ids(kwargs: dict, cls_name: str | None) -> TokenLayout | None: + """Read the stream lengths off the rotary id tensors a joint transformer is given by name.""" + if cls_name not in JOINT_TEXT_FIRST: + return None + text, image = kwargs.get('txt_ids'), kwargs.get('img_ids') + if not torch.is_tensor(text) or not torch.is_tensor(image) or text.dim() < 2 or image.dim() < 2: + return None + return layout_from_segments((('text', text.shape[-2]), ('image', image.shape[-2])), source='stream-ids') + + +def layout_from_kwargs(kwargs: dict, cls_name: str | None = None) -> TokenLayout | None: + """Whatever the denoiser says about its own packing, by whichever convention it uses.""" + return layout_from_index_kwargs(kwargs or {}) or layout_from_stream_ids(kwargs or {}, cls_name) + + +def layout_from_segments(segments, length: int | None = None, source: str = 'segments') -> TokenLayout: + """Build a layout from ordered (kind, count) pairs, the form a transformer knows at its packing site.""" + spans: list[Span] = [] + cursor = 0 + for kind, count in segments: + if count <= 0: + continue + spans.append(Span(kind=kind, start=cursor, end=cursor + count)) + cursor += count + return TokenLayout(spans=tuple(spans), length=length if length is not None else cursor, source=source) + + +def segments_from_live(live: torch.Tensor, kind: str, pad_kind: str = 'pad') -> list[tuple[str, int]]: + """Run length encode a boolean live mask into ordered (kind, count) pairs, the dead runs labelled as padding.""" + values = live.detach().to('cpu').bool() + if values.numel() == 0: + return [] + changes = (values[1:] != values[:-1]).nonzero().flatten().tolist() + bounds = [0, *[c + 1 for c in changes], values.numel()] + return [(kind if bool(values[bounds[i]]) else pad_kind, bounds[i + 1] - bounds[i]) for i in range(len(bounds) - 1)] + + +def publish_segments(segments, length: int | None = None, source: str = 'segments') -> None: + """Publish a layout from the site that packs the sequence, which is the only place the segment lengths are all known.""" + from modules.attention import context + context.set_layout(layout_from_segments(segments, length=length, source=source)) + + +def layout_from_prefix(length: int, prefix: int) -> TokenLayout: + """Fallback when nothing published a layout: treat a leading run as conditioning and sparsify the rest.""" + return layout_from_segments([('text', prefix), ('image', length - prefix)], length=length, source='prefix') + + +def block_flags(flags: torch.Tensor, block: int) -> tuple[torch.Tensor, torch.Tensor]: + """Per block: do all tokens carry the flag, does any token carry it.""" + seq = flags.shape[0] + whole = (seq // block) * block + parts_all, parts_any = [], [] + if whole: + view = flags[:whole].view(whole // block, block) + parts_all.append(view.all(dim=-1)) + parts_any.append(view.any(dim=-1)) + if whole < seq: + parts_all.append(flags[whole:].all(dim=-1, keepdim=True)) + parts_any.append(flags[whole:].any(dim=-1, keepdim=True)) + def join(parts): + return parts[0] if len(parts) == 1 else torch.cat(parts, dim=0) + return join(parts_all), join(parts_any) + + +pin_cache: dict = {} + + +def block_pins(layout: TokenLayout, seq_q: int, seq_kv: int, block_q: int, block_kv: int, device) -> tuple[torch.Tensor, torch.Tensor]: + """Tiles that must stay dense and tiles that can be skipped outright, as (1, 1, NQ, NK) masks.""" + cache_key = (layout.key(), seq_q, seq_kv, block_q, block_kv, str(device)) + hit = pin_cache.get(cache_key) + if hit is not None: + return hit + sparse_tokens, pad_tokens = layout.token_flags(device) + q_sparse = sparse_tokens[:seq_q] if layout.length >= seq_q else torch.nn.functional.pad(sparse_tokens, (0, seq_q - layout.length)) + kv_sparse = sparse_tokens[:seq_kv] if layout.length >= seq_kv else torch.nn.functional.pad(sparse_tokens, (0, seq_kv - layout.length)) + kv_pad = pad_tokens[:seq_kv] if layout.length >= seq_kv else torch.nn.functional.pad(pad_tokens, (0, seq_kv - layout.length)) + q_all_sparse, _ = block_flags(q_sparse, block_q) + kv_all_sparse, _ = block_flags(kv_sparse, block_kv) + kv_all_pad, _ = block_flags(kv_pad, block_kv) + # a tile is pinned when its query tile or its key tile carries anything that is not sparsifiable, boundary tiles included + pins = (~q_all_sparse).unsqueeze(-1) | (~kv_all_sparse).unsqueeze(0) + drops = kv_all_pad.unsqueeze(0).expand_as(pins) + pins = (pins & ~drops).unsqueeze(0).unsqueeze(0).contiguous() + drops = drops.unsqueeze(0).unsqueeze(0).contiguous() + if len(pin_cache) > 32: + pin_cache.clear() + pin_cache[cache_key] = (pins, drops) + return pins, drops diff --git a/modules/attention/sparse/selector.py b/modules/attention/sparse/selector.py new file mode 100644 index 000000000..815494882 --- /dev/null +++ b/modules/attention/sparse/selector.py @@ -0,0 +1,148 @@ +"""Fixed-budget block selection: which KV tiles each query tile attends to.""" +from dataclasses import dataclass +import math +import torch + + +@dataclass(frozen=True) +class SparseSpec: + """How much to keep and at what granularity. Budget is a fraction of the sparsifiable candidates, pins are added on top.""" + budget: float = 0.30 + block_q: int = 128 + block_kv: int = 64 + head_shared: bool = False # score once for all heads, cheaper and coarser + force: bool = False # skip the dense short circuit, so tests can exercise the path at budget 1.0 + score_chunk_bytes: int = 256 << 20 + + +@dataclass(frozen=True) +class BlockSelection: + """int8 keep flags per (query tile, kv tile); the geometry every consumer reads.""" + keep: torch.Tensor # (B, H, NQ, NK), H is the query head count or 1 + block_q: int + block_kv: int + budget: float + seq_q: int + seq_kv: int + + @property + def shape(self) -> tuple[int, int, int, int]: + b, h, nq, nk = self.keep.shape + return (b, h, nq, nk) + + def density(self) -> float: + """Fraction of tiles kept. Reads back from the accelerator, so this is for reporting and tests, never the hot path.""" + return float(self.keep.sum().item()) / max(self.keep.numel(), 1) + + +def block_count(length: int, block: int) -> int: + return (length + block - 1) // block + + +def pool_blocks(x: torch.Tensor, block: int) -> torch.Tensor: + """Mean over each block of tokens, fp32, without materializing a padded copy.""" + seq = x.shape[-2] + whole = (seq // block) * block + parts = [] + if whole: + head = x[..., :whole, :] + parts.append(head.unflatten(-2, (whole // block, block)).mean(dim=-2, dtype=torch.float32)) + if whole < seq: + parts.append(x[..., whole:, :].mean(dim=-2, dtype=torch.float32, keepdim=True)) + return parts[0] if len(parts) == 1 else torch.cat(parts, dim=-2) + + +def diagonal_blocks(nq: int, nk: int, block_q: int, block_kv: int, device) -> torch.Tensor: + """Tiles whose query and key token ranges overlap; keeping them removes the empty-row case.""" + q_index = torch.arange(nq, device=device).unsqueeze(-1) + k_index = torch.arange(nk, device=device).unsqueeze(0) + return (q_index * block_q < (k_index + 1) * block_kv) & (k_index * block_kv < (q_index + 1) * block_q) + + +def score_blocks(query: torch.Tensor, key: torch.Tensor, spec: SparseSpec) -> torch.Tensor: + """Mean-pooled query-key affinity per tile pair. No scale and no softmax: top-k is invariant under both.""" + pooled_q = pool_blocks(query, spec.block_q) # (B, Hq, NQ, D) + pooled_k = pool_blocks(key, spec.block_kv) # (B, Hkv, NK, D) + heads_q, heads_kv = pooled_q.shape[1], pooled_k.shape[1] + if spec.head_shared: + pooled_q = pooled_q.mean(dim=1, keepdim=True) + pooled_k = pooled_k.mean(dim=1, keepdim=True) + elif heads_kv != heads_q: # gqa: score on query heads, the geometry both consumers expect + pooled_k = pooled_k.repeat_interleave(heads_q // heads_kv, dim=1) + heads = pooled_q.shape[1] + per_head = pooled_q.shape[2] * pooled_k.shape[2] * 4 + chunk = max(1, min(heads, spec.score_chunk_bytes // max(per_head, 1))) + if chunk >= heads: + return pooled_q @ pooled_k.transpose(-1, -2) + return torch.cat([pooled_q[:, i:i + chunk] @ pooled_k[:, i:i + chunk].transpose(-1, -2) for i in range(0, heads, chunk)], dim=1) + + +plan_cache: dict = {} + + +def selection_plan(spec: SparseSpec, nq: int, nk: int, pins, drops, device, cache_key=None): + """The parts that depend only on geometry and layout, not on the tensors: what must be kept, what may be chosen, and how many.""" + key = (cache_key, nq, nk, spec.block_q, spec.block_kv, spec.budget, str(device)) + hit = plan_cache.get(key) if cache_key is not None else None + if hit is not None: + return hit + must = diagonal_blocks(nq, nk, spec.block_q, spec.block_kv, device).unsqueeze(0).unsqueeze(0) + if pins is not None: + must = must | pins + forbidden = drops if drops is not None else torch.zeros_like(must) + candidates = ~must & ~forbidden + per_row = candidates.sum(dim=-1, keepdim=True) # (.., NQ, 1) + keep_per_row = torch.ceil(per_row * spec.budget).to(torch.int64) + covers_everything = bool((keep_per_row >= per_row).all()) # one readback, amortized over the generation by the cache + built = (must, forbidden, candidates, keep_per_row, covers_everything) + if cache_key is not None: + if len(plan_cache) > 32: + plan_cache.clear() + plan_cache[key] = built + return built + + +def select_blocks(query: torch.Tensor, key: torch.Tensor, spec: SparseSpec, pins: torch.Tensor | None = None, drops: torch.Tensor | None = None, cache_key=None) -> BlockSelection | None: + """Keep the highest scoring KV tiles per query tile within the budget, plus pins and the diagonal. None means attend densely.""" + seq_q, seq_kv = query.shape[-2], key.shape[-2] + nq, nk = block_count(seq_q, spec.block_q), block_count(seq_kv, spec.block_kv) + device = query.device + must, forbidden, candidates, keep_per_row, covers_everything = selection_plan(spec, nq, nk, pins, drops, device, cache_key) + if covers_everything and not spec.force: + return None # the budget covers every candidate, so the mask would be dense + + scores = score_blocks(query, key, spec) + scores = scores.masked_fill(~candidates.expand_as(scores), float('-inf')) + # rank rather than topk, so the per row budget varies without a host side k + order = scores.argsort(dim=-1, descending=True, stable=True) + rank = torch.empty_like(order) + rank.scatter_(-1, order, torch.arange(nk, device=device).expand_as(order)) + keep = must | ((rank < keep_per_row) & candidates) + keep &= ~forbidden + return BlockSelection(keep=keep.to(torch.int8), block_q=spec.block_q, block_kv=spec.block_kv, budget=spec.budget, seq_q=seq_q, seq_kv=seq_kv) + + +def radial_blocks(seq_q: int, seq_kv: int, density: float, spec: SparseSpec, device) -> BlockSelection: + """A band around the diagonal at the requested density: the static control the selector has to beat.""" + nq, nk = block_count(seq_q, spec.block_q), block_count(seq_kv, spec.block_kv) + q_center = (torch.arange(nq, device=device).unsqueeze(-1) + 0.5) * spec.block_q + k_center = (torch.arange(nk, device=device).unsqueeze(0) + 0.5) * spec.block_kv + distance = (q_center - k_center).abs() + low, high = 0.0, float(max(seq_q, seq_kv)) + for _ in range(40): # bisect the bandwidth, since the band width to density map has no closed form at the edges + mid = (low + high) / 2 + if float((distance <= mid).to(torch.float32).mean().item()) < density: + low = mid + else: + high = mid + keep = (distance <= high).unsqueeze(0).unsqueeze(0).to(torch.int8) + return BlockSelection(keep=keep, block_q=spec.block_q, block_kv=spec.block_kv, budget=density, seq_q=seq_q, seq_kv=seq_kv) + + +def schedule(steps: int, budget: float, bump: float = 0.0, bump_steps: int = 0) -> tuple[float, ...]: + """Per-step budgets, precomputed. At most two distinct values, so a compiled consumer sees at most two specializations.""" + if bump <= 0 or bump_steps <= 0 or steps <= 0: + return tuple([budget] * max(steps, 0)) + raised = min(1.0, budget + bump) + edge = min(bump_steps, math.ceil(steps / 2)) + return tuple([raised if (i < edge or i >= steps - edge) else budget for i in range(steps)]) diff --git a/modules/attention/sparse/stage.py b/modules/attention/sparse/stage.py new file mode 100644 index 000000000..b272ed67a --- /dev/null +++ b/modules/attention/sparse/stage.py @@ -0,0 +1,178 @@ +"""The router stage that turns settings plus a published layout into a per call block selection.""" +import os +from dataclasses import dataclass +import torch +from modules.logger import log +from modules.attention import context +from modules.attention.sparse import layout as layout_mod +from modules.attention.sparse.selector import BlockSelection, SparseSpec, block_count, radial_blocks, schedule, select_blocks + + +debug = os.environ.get('SD_ATTN_DEBUG', None) is not None + +# SD_SPARSE_PATTERN=radial replaces the content aware selection with a static band around the +# diagonal at the same density: the control the selector has to beat, and the fallback if it does not +pattern = os.environ.get('SD_SPARSE_PATTERN', 'adaptive').strip().lower() + + +# measured on a 3090: below roughly this length a 30 percent budget caps under 1.25x per block, +# so the selector cannot pay for itself; see docs/sparse-attention-tracker.md. The settings registry +# carries the same number as the option default, this is the fallback when the option is absent +DEFAULT_MIN_TOKENS = 8192 + +# settings the stage reads, so a change to any of them rebuilds the chain +OPTION_NAMES = ('sparse_attention_enabled', 'sparse_attention_budget', 'sparse_attention_min_tokens', 'sparse_attention_schedule_steps', 'sparse_attention_schedule_bump', 'sparse_attention_head_shared', 'sparse_attention_exclude') + + +@dataclass(frozen=True) +class StageOptions: + enabled: bool = False + budget: float = 0.30 + min_tokens: int = DEFAULT_MIN_TOKENS # 0 sparsifies every sequence that reaches the stage + schedule_steps: int = 0 + schedule_bump: float = 0.0 + head_shared: bool = False + exclude: tuple = () # architectures, pipeline classes or denoiser classes that stay dense + + +def read_options() -> StageOptions: + from modules import shared + opts = shared.opts + return StageOptions( + enabled=bool(getattr(opts, 'sparse_attention_enabled', False)), + budget=float(getattr(opts, 'sparse_attention_budget', 30)) / 100.0, + min_tokens=int(getattr(opts, 'sparse_attention_min_tokens', DEFAULT_MIN_TOKENS)), + schedule_steps=int(getattr(opts, 'sparse_attention_schedule_steps', 0)), + schedule_bump=float(getattr(opts, 'sparse_attention_schedule_bump', 0)) / 100.0, + head_shared=bool(getattr(opts, 'sparse_attention_head_shared', False)), + exclude=parse_exclusions(getattr(opts, 'sparse_attention_exclude', '')), + ) + + +def parse_exclusions(raw) -> tuple: + """The exclusion list as lowercase entries, each naming an architecture, a pipeline class or a denoiser class.""" + return tuple(entry.strip().lower() for entry in str(raw or '').split(',') if len(entry.strip()) > 0) + + +def match_exclusion(model_key, arch, exclude: tuple) -> str: + """The entry the loaded model matches, empty when none of them do.""" + names = {str(name).lower() for name in (*(model_key or ()), arch) if name} + return next((entry for entry in exclude if entry in names), '') + + +def resolve_layout(seq: int, reported: set) -> layout_mod.TokenLayout: + """The published layout when there is one, otherwise sparsify the whole sequence and say so once.""" + published = context.current.layout + if isinstance(published, layout_mod.TokenLayout) and published.length == seq: + return published + if seq not in reported: + reported.add(seq) + detail = 'none published' if published is None else f'published length {getattr(published, "length", None)} does not match {seq}' + log.info(f'Sparse attention: no token layout ({detail}), sparsifying the whole sequence at tokens={seq}') + return layout_mod.layout_from_prefix(seq, 0) + + +def make_stage(options: StageOptions): + """Return the per call selector, or None when the feature is off.""" + if not options.enabled or options.budget >= 1.0: + return None + reported: set = set() + inactive: set = set() + notified: set = set() + cache: dict = {} + static: dict = {} + excluded: dict = {} + + def static_selection(query, key, spec, pins, drops, cache_key): + """A density matched band, built once per geometry, honoring the same layout pins so the control differs from the selector only in how it chooses video tiles.""" + static_key = (cache_key, spec.budget, query.shape[-2], key.shape[-2]) + built = static.get(static_key) + if built is None: + reference = select_blocks(query, key, spec, pins=pins, drops=drops, cache_key=cache_key) + if reference is None: + return None + target = reference.density() + pinned = float(pins.to(torch.float32).mean().item()) if pins is not None else 0.0 + band = radial_blocks(query.shape[-2], key.shape[-2], max(target - pinned, 0.0), spec, query.device) + keep = band.keep.bool() + if pins is not None: + keep = keep | pins + if drops is not None: + keep = keep & ~drops + built = BlockSelection(keep=keep.to(torch.int8), block_q=spec.block_q, block_kv=spec.block_kv, budget=spec.budget, seq_q=query.shape[-2], seq_kv=key.shape[-2]) + static.clear() + static[static_key] = built + log.info(f'Sparse attention: static radial pattern density={built.density():.3f} against selector {target:.3f} at budget={spec.budget:.0%}') + return built + + def budget_for_step() -> float: + state = context.current + if options.schedule_steps <= 0 or options.schedule_bump <= 0 or state.steps <= 0: + return options.budget + key = (state.steps, options.budget, options.schedule_bump, options.schedule_steps) + table = cache.get(key) + if table is None: + table = schedule(state.steps, options.budget, options.schedule_bump, options.schedule_steps) + cache.clear() + cache[key] = table + return table[min(state.step, len(table) - 1)] if table else options.budget + + def on_exclusion_list(state) -> bool: + """Whether the loaded model is excluded, resolved once per model since the answer cannot change within one.""" + if not options.exclude: + return False + hit = excluded.get(state.model_key) + if hit is None: + from modules import shared + hit = match_exclusion(state.model_key, getattr(shared, 'sd_model_type', None), options.exclude) + excluded[state.model_key] = hit + if hit and debug: # an enabled setting that cannot act says so rather than doing nothing quietly + log.trace(f'Sparse attention: "{hit}" is on the exclusion list; attention stays dense') + return len(hit) > 0 + + def decline(reason: str): + stage.last_skip = reason + return None + + def stage(query, key, value, attn_mask, is_causal, caps=frozenset()): # pylint: disable=unused-argument + state = context.current + if state.role != 'transformer' or not state.active: + return decline('not the denoiser') + if on_exclusion_list(state): + return decline('excluded') + if is_causal: # the selection keeps the diagonal but encodes no causality + return decline('causal') + if attn_mask is not None and 'masked_block' not in caps: # flex would need a mask_mod to combine the two + if 'masked' not in notified: # an enabled setting that cannot act says so rather than doing nothing quietly + notified.add('masked') + if debug: + log.trace('Sparse attention: this model passes an attention mask and the serving backend cannot combine it with a block selection; attention stays dense') + return decline('masked') + if query.device.type == 'cpu' or query.dim() != 4: + return decline('unsupported tensor') + seq_q, seq_kv = query.shape[-2], key.shape[-2] + if seq_q != seq_kv: # cross attention is short and already cheap + return decline('cross attention') + if seq_q < options.min_tokens: + if seq_q not in inactive: # an enabled setting that cannot act says so rather than doing nothing quietly + inactive.add(seq_q) + if debug: + log.trace(f'Sparse attention: inactive at tokens={seq_q}, below the minimum sequence of {options.min_tokens}; attention stays dense') + return decline('below the minimum sequence') + budget = budget_for_step() + if budget >= 1.0: + return decline('budget covers everything') + spec = SparseSpec(budget=budget, head_shared=options.head_shared) + token_layout = resolve_layout(seq_q, reported) + nq, nk = block_count(seq_q, spec.block_q), block_count(seq_kv, spec.block_kv) + pins, drops = layout_mod.block_pins(token_layout, seq_q, seq_kv, spec.block_q, spec.block_kv, query.device) + if pins.shape[-2:] != (nq, nk): + return decline('layout geometry mismatch') + stage.last_skip = None + if pattern == 'radial': + return static_selection(query, key, spec, pins, drops, token_layout.key()) + return select_blocks(query, key, spec, pins=pins, drops=drops, cache_key=token_layout.key()) + + stage.options = options + stage.last_skip = None + return stage diff --git a/modules/ben2/__init__.py b/modules/ben2/__init__.py deleted file mode 100644 index f9375a990..000000000 --- a/modules/ben2/__init__.py +++ /dev/null @@ -1,24 +0,0 @@ -model = None - - -def remove(image, refine: bool = True): - global model # pylint: disable=global-statement - from modules import shared, devices - - if model is None: - from huggingface_hub import hf_hub_download - from .ben2_model import BEN_Base - model = BEN_Base() - model_file = hf_hub_download( - repo_id='PramaLLC/BEN2', - filename='BEN2_Base.pth', - cache_dir=shared.opts.hfcache_dir) - model.loadcheckpoints(model_file) - model = model.to(device=devices.device, dtype=devices.dtype).eval() - - model = model.to(device=devices.device) - foreground = model.inference(image, refine_foreground=refine) - model = model.to(device=devices.cpu) - if foreground is None: - return image - return foreground diff --git a/modules/ben2/ben2_model.py b/modules/ben2/ben2_model.py deleted file mode 100644 index c36f40b21..000000000 --- a/modules/ben2/ben2_model.py +++ /dev/null @@ -1,1298 +0,0 @@ -import os -import math -import subprocess -import tempfile -import cv2 -import torch -import torch.nn as nn -import torch.nn.functional as F -import torch.utils.checkpoint as checkpoint -import numpy as np -from timm.models.layers import DropPath, to_2tuple, trunc_normal_ -from PIL import Image -from torchvision import transforms -from einops import rearrange - - -class Mlp(nn.Module): - """ Multilayer perceptron.""" - - def __init__(self, in_features, hidden_features=None, out_features=None, act_layer=nn.GELU, drop=0.): - super().__init__() - out_features = out_features or in_features - hidden_features = hidden_features or in_features - self.fc1 = nn.Linear(in_features, hidden_features) - self.act = act_layer() - self.fc2 = nn.Linear(hidden_features, out_features) - self.drop = nn.Dropout(drop) - - def forward(self, x): - x = self.fc1(x) - x = self.act(x) - x = self.drop(x) - x = self.fc2(x) - x = self.drop(x) - return x - - -def window_partition(x, window_size): - """ - Args: - x: (B, H, W, C) - window_size (int): window size - Returns: - windows: (num_windows*B, window_size, window_size, C) - """ - B, H, W, C = x.shape - x = x.view(B, H // window_size, window_size, W // window_size, window_size, C) - windows = x.permute(0, 1, 3, 2, 4, 5).contiguous().view(-1, window_size, window_size, C) - return windows - - -def window_reverse(windows, window_size, H, W): - """ - Args: - windows: (num_windows*B, window_size, window_size, C) - window_size (int): Window size - H (int): Height of image - W (int): Width of image - Returns: - x: (B, H, W, C) - """ - B = int(windows.shape[0] / (H * W / window_size / window_size)) - x = windows.view(B, H // window_size, W // window_size, window_size, window_size, -1) - x = x.permute(0, 1, 3, 2, 4, 5).contiguous().view(B, H, W, -1) - return x - - -class WindowAttention(nn.Module): - """ Window based multi-head self attention (W-MSA) module with relative position bias. - It supports both of shifted and non-shifted window. - Args: - dim (int): Number of input channels. - window_size (tuple[int]): The height and width of the window. - num_heads (int): Number of attention heads. - qkv_bias (bool, optional): If True, add a learnable bias to query, key, value. Default: True - qk_scale (float | None, optional): Override default qk scale of head_dim ** -0.5 if set - attn_drop (float, optional): Dropout ratio of attention weight. Default: 0.0 - proj_drop (float, optional): Dropout ratio of output. Default: 0.0 - """ - - def __init__(self, dim, window_size, num_heads, qkv_bias=True, qk_scale=None, attn_drop=0., proj_drop=0.): - - super().__init__() - self.dim = dim - self.window_size = window_size # Wh, Ww - self.num_heads = num_heads - head_dim = dim // num_heads - self.scale = qk_scale or head_dim ** -0.5 - - # define a parameter table of relative position bias - self.relative_position_bias_table = nn.Parameter( - torch.zeros((2 * window_size[0] - 1) * (2 * window_size[1] - 1), num_heads)) # 2*Wh-1 * 2*Ww-1, nH - - # get pair-wise relative position index for each token inside the window - coords_h = torch.arange(self.window_size[0]) - coords_w = torch.arange(self.window_size[1]) - coords = torch.stack(torch.meshgrid([coords_h, coords_w])) # 2, Wh, Ww - coords_flatten = torch.flatten(coords, 1) # 2, Wh*Ww - relative_coords = coords_flatten[:, :, None] - coords_flatten[:, None, :] # 2, Wh*Ww, Wh*Ww - relative_coords = relative_coords.permute(1, 2, 0).contiguous() # Wh*Ww, Wh*Ww, 2 - relative_coords[:, :, 0] += self.window_size[0] - 1 # shift to start from 0 - relative_coords[:, :, 1] += self.window_size[1] - 1 - relative_coords[:, :, 0] *= 2 * self.window_size[1] - 1 - relative_position_index = relative_coords.sum(-1) # Wh*Ww, Wh*Ww - self.register_buffer("relative_position_index", relative_position_index) - - self.qkv = nn.Linear(dim, dim * 3, bias=qkv_bias) - self.attn_drop = nn.Dropout(attn_drop) - self.proj = nn.Linear(dim, dim) - self.proj_drop = nn.Dropout(proj_drop) - - trunc_normal_(self.relative_position_bias_table, std=.02) - self.softmax = nn.Softmax(dim=-1) - - def forward(self, x, mask=None): - """ Forward function. - Args: - x: input features with shape of (num_windows*B, N, C) - mask: (0/-inf) mask with shape of (num_windows, Wh*Ww, Wh*Ww) or None - """ - B_, N, C = x.shape - qkv = self.qkv(x).reshape(B_, N, 3, self.num_heads, C // self.num_heads).permute(2, 0, 3, 1, 4) - q, k, v = qkv[0], qkv[1], qkv[2] # make torchscript happy (cannot use tensor as tuple) - - q = q * self.scale - attn = q @ k.transpose(-2, -1) - - relative_position_bias = self.relative_position_bias_table[self.relative_position_index.view(-1)].view( - self.window_size[0] * self.window_size[1], self.window_size[0] * self.window_size[1], -1) # Wh*Ww,Wh*Ww,nH - relative_position_bias = relative_position_bias.permute(2, 0, 1).contiguous() # nH, Wh*Ww, Wh*Ww - attn = attn + relative_position_bias.unsqueeze(0) - - if mask is not None: - nW = mask.shape[0] - attn = attn.view(B_ // nW, nW, self.num_heads, N, N) + mask.unsqueeze(1).unsqueeze(0) - attn = attn.view(-1, self.num_heads, N, N) - attn = self.softmax(attn) - else: - attn = self.softmax(attn) - - attn = self.attn_drop(attn) - - x = (attn @ v).transpose(1, 2).reshape(B_, N, C) - x = self.proj(x) - x = self.proj_drop(x) - return x - - -class SwinTransformerBlock(nn.Module): - """ Swin Transformer Block. - Args: - dim (int): Number of input channels. - num_heads (int): Number of attention heads. - window_size (int): Window size. - shift_size (int): Shift size for SW-MSA. - mlp_ratio (float): Ratio of mlp hidden dim to embedding dim. - qkv_bias (bool, optional): If True, add a learnable bias to query, key, value. Default: True - qk_scale (float | None, optional): Override default qk scale of head_dim ** -0.5 if set. - drop (float, optional): Dropout rate. Default: 0.0 - attn_drop (float, optional): Attention dropout rate. Default: 0.0 - drop_path (float, optional): Stochastic depth rate. Default: 0.0 - act_layer (nn.Module, optional): Activation layer. Default: nn.GELU - norm_layer (nn.Module, optional): Normalization layer. Default: nn.LayerNorm - """ - - def __init__(self, dim, num_heads, window_size=7, shift_size=0, - mlp_ratio=4., qkv_bias=True, qk_scale=None, drop=0., attn_drop=0., drop_path=0., - act_layer=nn.GELU, norm_layer=nn.LayerNorm): - super().__init__() - self.dim = dim - self.num_heads = num_heads - self.window_size = window_size - self.shift_size = shift_size - self.mlp_ratio = mlp_ratio - assert 0 <= self.shift_size < self.window_size, "shift_size must in 0-window_size" - - self.norm1 = norm_layer(dim) - self.attn = WindowAttention( - dim, window_size=to_2tuple(self.window_size), num_heads=num_heads, - qkv_bias=qkv_bias, qk_scale=qk_scale, attn_drop=attn_drop, proj_drop=drop) - - self.drop_path = DropPath(drop_path) if drop_path > 0. else nn.Identity() - self.norm2 = norm_layer(dim) - mlp_hidden_dim = int(dim * mlp_ratio) - self.mlp = Mlp(in_features=dim, hidden_features=mlp_hidden_dim, act_layer=act_layer, drop=drop) - - self.H = None - self.W = None - - def forward(self, x, mask_matrix): - """ Forward function. - Args: - x: Input feature, tensor size (B, H*W, C). - H, W: Spatial resolution of the input feature. - mask_matrix: Attention mask for cyclic shift. - """ - B, L, C = x.shape - H, W = self.H, self.W - assert L == H * W, "input feature has wrong size" - - shortcut = x - x = self.norm1(x) - x = x.view(B, H, W, C) - - # pad feature maps to multiples of window size - pad_l = pad_t = 0 - pad_r = (self.window_size - W % self.window_size) % self.window_size - pad_b = (self.window_size - H % self.window_size) % self.window_size - x = F.pad(x, (0, 0, pad_l, pad_r, pad_t, pad_b)) - _, Hp, Wp, _ = x.shape - - # cyclic shift - if self.shift_size > 0: - shifted_x = torch.roll(x, shifts=(-self.shift_size, -self.shift_size), dims=(1, 2)) - attn_mask = mask_matrix - else: - shifted_x = x - attn_mask = None - - # partition windows - x_windows = window_partition(shifted_x, self.window_size) # nW*B, window_size, window_size, C - x_windows = x_windows.view(-1, self.window_size * self.window_size, C) # nW*B, window_size*window_size, C - - # W-MSA/SW-MSA - attn_windows = self.attn(x_windows, mask=attn_mask) # nW*B, window_size*window_size, C - - # merge windows - attn_windows = attn_windows.view(-1, self.window_size, self.window_size, C) - shifted_x = window_reverse(attn_windows, self.window_size, Hp, Wp) # B H' W' C - - # reverse cyclic shift - if self.shift_size > 0: - x = torch.roll(shifted_x, shifts=(self.shift_size, self.shift_size), dims=(1, 2)) - else: - x = shifted_x - - if pad_r > 0 or pad_b > 0: - x = x[:, :H, :W, :].contiguous() - - x = x.view(B, H * W, C) - - # FFN - x = shortcut + self.drop_path(x) - x = x + self.drop_path(self.mlp(self.norm2(x))) - - return x - - -class PatchMerging(nn.Module): - """ Patch Merging Layer - Args: - dim (int): Number of input channels. - norm_layer (nn.Module, optional): Normalization layer. Default: nn.LayerNorm - """ - def __init__(self, dim, norm_layer=nn.LayerNorm): - super().__init__() - self.dim = dim - self.reduction = nn.Linear(4 * dim, 2 * dim, bias=False) - self.norm = norm_layer(4 * dim) - - def forward(self, x, H, W): - """ Forward function. - Args: - x: Input feature, tensor size (B, H*W, C). - H, W: Spatial resolution of the input feature. - """ - B, L, C = x.shape - assert L == H * W, "input feature has wrong size" - - x = x.view(B, H, W, C) - - # padding - pad_input = (H % 2 == 1) or (W % 2 == 1) - if pad_input: - x = F.pad(x, (0, 0, 0, W % 2, 0, H % 2)) - - x0 = x[:, 0::2, 0::2, :] # B H/2 W/2 C - x1 = x[:, 1::2, 0::2, :] # B H/2 W/2 C - x2 = x[:, 0::2, 1::2, :] # B H/2 W/2 C - x3 = x[:, 1::2, 1::2, :] # B H/2 W/2 C - x = torch.cat([x0, x1, x2, x3], -1) # B H/2 W/2 4*C - x = x.view(B, -1, 4 * C) # B H/2*W/2 4*C - - x = self.norm(x) - x = self.reduction(x) - - return x - - -class BasicLayer(nn.Module): - """ A basic Swin Transformer layer for one stage. - Args: - dim (int): Number of feature channels - depth (int): Depths of this stage. - num_heads (int): Number of attention head. - window_size (int): Local window size. Default: 7. - mlp_ratio (float): Ratio of mlp hidden dim to embedding dim. Default: 4. - qkv_bias (bool, optional): If True, add a learnable bias to query, key, value. Default: True - qk_scale (float | None, optional): Override default qk scale of head_dim ** -0.5 if set. - drop (float, optional): Dropout rate. Default: 0.0 - attn_drop (float, optional): Attention dropout rate. Default: 0.0 - drop_path (float | tuple[float], optional): Stochastic depth rate. Default: 0.0 - norm_layer (nn.Module, optional): Normalization layer. Default: nn.LayerNorm - downsample (nn.Module | None, optional): Downsample layer at the end of the layer. Default: None - use_checkpoint (bool): Whether to use checkpointing to save memory. Default: False. - """ - - def __init__(self, - dim, - depth, - num_heads, - window_size=7, - mlp_ratio=4., - qkv_bias=True, - qk_scale=None, - drop=0., - attn_drop=0., - drop_path=0., - norm_layer=nn.LayerNorm, - downsample=None, - use_checkpoint=False): - super().__init__() - self.window_size = window_size - self.shift_size = window_size // 2 - self.depth = depth - self.use_checkpoint = use_checkpoint - - # build blocks - self.blocks = nn.ModuleList([ - SwinTransformerBlock( - dim=dim, - num_heads=num_heads, - window_size=window_size, - shift_size=0 if (i % 2 == 0) else window_size // 2, - mlp_ratio=mlp_ratio, - qkv_bias=qkv_bias, - qk_scale=qk_scale, - drop=drop, - attn_drop=attn_drop, - drop_path=drop_path[i] if isinstance(drop_path, list) else drop_path, - norm_layer=norm_layer) - for i in range(depth)]) - - # patch merging layer - if downsample is not None: - self.downsample = downsample(dim=dim, norm_layer=norm_layer) - else: - self.downsample = None - - def forward(self, x, H, W): - """ Forward function. - Args: - x: Input feature, tensor size (B, H*W, C). - H, W: Spatial resolution of the input feature. - """ - - # calculate attention mask for SW-MSA - Hp = int(np.ceil(H / self.window_size)) * self.window_size - Wp = int(np.ceil(W / self.window_size)) * self.window_size - img_mask = torch.zeros((1, Hp, Wp, 1), device=x.device) # 1 Hp Wp 1 - h_slices = (slice(0, -self.window_size), - slice(-self.window_size, -self.shift_size), - slice(-self.shift_size, None)) - w_slices = (slice(0, -self.window_size), - slice(-self.window_size, -self.shift_size), - slice(-self.shift_size, None)) - cnt = 0 - for h in h_slices: - for w in w_slices: - img_mask[:, h, w, :] = cnt - cnt += 1 - - mask_windows = window_partition(img_mask, self.window_size) # nW, window_size, window_size, 1 - mask_windows = mask_windows.view(-1, self.window_size * self.window_size) - attn_mask = mask_windows.unsqueeze(1) - mask_windows.unsqueeze(2) - attn_mask = attn_mask.masked_fill(attn_mask != 0, (-100.0)).masked_fill(attn_mask == 0, 0.0) - - for blk in self.blocks: - blk.H, blk.W = H, W - if self.use_checkpoint: - x = checkpoint.checkpoint(blk, x, attn_mask) - else: - x = blk(x, attn_mask) - if self.downsample is not None: - x_down = self.downsample(x, H, W) - Wh, Ww = (H + 1) // 2, (W + 1) // 2 - return x, H, W, x_down, Wh, Ww - else: - return x, H, W, x, H, W - - -class PatchEmbed(nn.Module): - """ Image to Patch Embedding - Args: - patch_size (int): Patch token size. Default: 4. - in_chans (int): Number of input image channels. Default: 3. - embed_dim (int): Number of linear projection output channels. Default: 96. - norm_layer (nn.Module, optional): Normalization layer. Default: None - """ - - def __init__(self, patch_size=4, in_chans=3, embed_dim=96, norm_layer=None): - super().__init__() - patch_size = to_2tuple(patch_size) - self.patch_size = patch_size - - self.in_chans = in_chans - self.embed_dim = embed_dim - - self.proj = nn.Conv2d(in_chans, embed_dim, kernel_size=patch_size, stride=patch_size) - if norm_layer is not None: - self.norm = norm_layer(embed_dim) - else: - self.norm = None - - def forward(self, x): - """Forward function.""" - # padding - _, _, H, W = x.size() - if W % self.patch_size[1] != 0: - x = F.pad(x, (0, self.patch_size[1] - W % self.patch_size[1])) - if H % self.patch_size[0] != 0: - x = F.pad(x, (0, 0, 0, self.patch_size[0] - H % self.patch_size[0])) - - x = self.proj(x) # B C Wh Ww - if self.norm is not None: - Wh, Ww = x.size(2), x.size(3) - x = x.flatten(2).transpose(1, 2) - x = self.norm(x) - x = x.transpose(1, 2).view(-1, self.embed_dim, Wh, Ww) - - return x - - -class SwinTransformer(nn.Module): - """ Swin Transformer backbone. - A PyTorch impl of : `Swin Transformer: Hierarchical Vision Transformer using Shifted Windows` - - https://arxiv.org/pdf/2103.14030 - Args: - pretrain_img_size (int): Input image size for training the pretrained model, - used in absolute position embedding. Default 224. - patch_size (int | tuple(int)): Patch size. Default: 4. - in_chans (int): Number of input image channels. Default: 3. - embed_dim (int): Number of linear projection output channels. Default: 96. - depths (tuple[int]): Depths of each Swin Transformer stage. - num_heads (tuple[int]): Number of attention head of each stage. - window_size (int): Window size. Default: 7. - mlp_ratio (float): Ratio of mlp hidden dim to embedding dim. Default: 4. - qkv_bias (bool): If True, add a learnable bias to query, key, value. Default: True - qk_scale (float): Override default qk scale of head_dim ** -0.5 if set. - drop_rate (float): Dropout rate. - attn_drop_rate (float): Attention dropout rate. Default: 0. - drop_path_rate (float): Stochastic depth rate. Default: 0.2. - norm_layer (nn.Module): Normalization layer. Default: nn.LayerNorm. - ape (bool): If True, add absolute position embedding to the patch embedding. Default: False. - patch_norm (bool): If True, add normalization after patch embedding. Default: True. - out_indices (Sequence[int]): Output from which stages. - frozen_stages (int): Stages to be frozen (stop grad and set eval mode). - -1 means not freezing any parameters. - use_checkpoint (bool): Whether to use checkpointing to save memory. Default: False. - """ - - def __init__(self, - pretrain_img_size=224, - patch_size=4, - in_chans=3, - embed_dim=96, - depths=None, - num_heads=None, - window_size=7, - mlp_ratio=4., - qkv_bias=True, - qk_scale=None, - drop_rate=0., - attn_drop_rate=0., - drop_path_rate=0.2, - norm_layer=nn.LayerNorm, - ape=False, - patch_norm=True, - out_indices=(0, 1, 2, 3), - frozen_stages=-1, - use_checkpoint=False): - if num_heads is None: - num_heads = [3, 6, 12, 24] - if depths is None: - depths = [2, 2, 6, 2] - super().__init__() - - self.pretrain_img_size = pretrain_img_size - self.num_layers = len(depths) - self.embed_dim = embed_dim - self.ape = ape - self.patch_norm = patch_norm - self.out_indices = out_indices - self.frozen_stages = frozen_stages - - # split image into non-overlapping patches - self.patch_embed = PatchEmbed( - patch_size=patch_size, in_chans=in_chans, embed_dim=embed_dim, - norm_layer=norm_layer if self.patch_norm else None) - - # absolute position embedding - if self.ape: - pretrain_img_size = to_2tuple(pretrain_img_size) - patch_size = to_2tuple(patch_size) - patches_resolution = [pretrain_img_size[0] // patch_size[0], pretrain_img_size[1] // patch_size[1]] - - self.absolute_pos_embed = nn.Parameter(torch.zeros(1, embed_dim, patches_resolution[0], patches_resolution[1])) - trunc_normal_(self.absolute_pos_embed, std=.02) - - self.pos_drop = nn.Dropout(p=drop_rate) - - # stochastic depth - dpr = [x.item() for x in torch.linspace(0, drop_path_rate, sum(depths))] # stochastic depth decay rule - - # build layers - self.layers = nn.ModuleList() - for i_layer in range(self.num_layers): - layer = BasicLayer( - dim=int(embed_dim * 2 ** i_layer), - depth=depths[i_layer], - num_heads=num_heads[i_layer], - window_size=window_size, - mlp_ratio=mlp_ratio, - qkv_bias=qkv_bias, - qk_scale=qk_scale, - drop=drop_rate, - attn_drop=attn_drop_rate, - drop_path=dpr[sum(depths[:i_layer]):sum(depths[:i_layer + 1])], - norm_layer=norm_layer, - downsample=PatchMerging if (i_layer < self.num_layers - 1) else None, - use_checkpoint=use_checkpoint) - self.layers.append(layer) - - num_features = [int(embed_dim * 2 ** i) for i in range(self.num_layers)] - self.num_features = num_features - - # add a norm layer for each output - for i_layer in out_indices: - layer = norm_layer(num_features[i_layer]) - layer_name = f'norm{i_layer}' - self.add_module(layer_name, layer) - - self._freeze_stages() - - def _freeze_stages(self): - if self.frozen_stages >= 0: - self.patch_embed.eval() - for param in self.patch_embed.parameters(): - param.requires_grad = False - - if self.frozen_stages >= 1 and self.ape: - self.absolute_pos_embed.requires_grad = False - - if self.frozen_stages >= 2: - self.pos_drop.eval() - for i in range(0, self.frozen_stages - 1): - m = self.layers[i] - m.eval() - for param in m.parameters(): - param.requires_grad = False - - - def forward(self, x): - - x = self.patch_embed(x) - - Wh, Ww = x.size(2), x.size(3) - if self.ape: - # interpolate the position embedding to the corresponding size - absolute_pos_embed = F.interpolate(self.absolute_pos_embed, size=(Wh, Ww), mode='bicubic') - x = x + absolute_pos_embed # B Wh*Ww C - - outs = [x.contiguous()] - x = x.flatten(2).transpose(1, 2) - x = self.pos_drop(x) - - - for i in range(self.num_layers): - layer = self.layers[i] - x_out, H, W, x, Wh, Ww = layer(x, Wh, Ww) - - - if i in self.out_indices: - norm_layer = getattr(self, f'norm{i}') - x_out = norm_layer(x_out) - - out = x_out.view(-1, H, W, self.num_features[i]).permute(0, 3, 1, 2).contiguous() - outs.append(out) - - - - return tuple(outs) - - - - - - - - -def get_activation_fn(activation): - """Return an activation function given a string""" - if activation == "gelu": - return F.gelu - - raise RuntimeError(F"activation should be gelu, not {activation}.") - - -def make_cbr(in_dim, out_dim): - return nn.Sequential(nn.Conv2d(in_dim, out_dim, kernel_size=3, padding=1), nn.InstanceNorm2d(out_dim), nn.GELU()) - - -def make_cbg(in_dim, out_dim): - return nn.Sequential(nn.Conv2d(in_dim, out_dim, kernel_size=3, padding=1), nn.InstanceNorm2d(out_dim), nn.GELU()) - - -def rescale_to(x, scale_factor: float = 2, interpolation='nearest'): - return F.interpolate(x, scale_factor=scale_factor, mode=interpolation) - - -def resize_as(x, y, interpolation='bilinear'): - return F.interpolate(x, size=y.shape[-2:], mode=interpolation) - - -def image2patches(x): - """b c (hg h) (wg w) -> (hg wg b) c h w""" - x = rearrange(x, 'b c (hg h) (wg w) -> (hg wg b) c h w', hg=2, wg=2 ) - return x - - -def patches2image(x): - """(hg wg b) c h w -> b c (hg h) (wg w)""" - x = rearrange(x, '(hg wg b) c h w -> b c (hg h) (wg w)', hg=2, wg=2) - return x - - - -class PositionEmbeddingSine: - def __init__(self, num_pos_feats=64, temperature=10000, normalize=False, scale=None): - super().__init__() - self.num_pos_feats = num_pos_feats - self.temperature = temperature - self.normalize = normalize - if scale is not None and normalize is False: - raise ValueError("normalize should be True if scale is passed") - if scale is None: - scale = 2 * math.pi - self.scale = scale - self.dim_t = torch.arange(0, self.num_pos_feats, dtype=torch.float32) - - def __call__(self, b, h, w): - device = self.dim_t.device - mask = torch.zeros([b, h, w], dtype=torch.bool, device=device) - assert mask is not None - not_mask = ~mask - y_embed = not_mask.cumsum(dim=1, dtype=torch.float32) - x_embed = not_mask.cumsum(dim=2, dtype=torch.float32) - if self.normalize: - eps = 1e-6 - y_embed = (y_embed - 0.5) / (y_embed[:, -1:, :] + eps) * self.scale - x_embed = (x_embed - 0.5) / (x_embed[:, :, -1:] + eps) * self.scale - - dim_t = self.temperature ** (2 * (self.dim_t.to(device) // 2) / self.num_pos_feats) - pos_x = x_embed[:, :, :, None] / dim_t - pos_y = y_embed[:, :, :, None] / dim_t - - pos_x = torch.stack((pos_x[:, :, :, 0::2].sin(), pos_x[:, :, :, 1::2].cos()), dim=4).flatten(3) - pos_y = torch.stack((pos_y[:, :, :, 0::2].sin(), pos_y[:, :, :, 1::2].cos()), dim=4).flatten(3) - - return torch.cat((pos_y, pos_x), dim=3).permute(0, 3, 1, 2) - - - -class MCLM(nn.Module): - def __init__(self, d_model, num_heads, pool_ratios=None): - if pool_ratios is None: - pool_ratios = [1, 4, 8] - super().__init__() - self.attention = nn.ModuleList([ - nn.MultiheadAttention(d_model, num_heads, dropout=0.1), - nn.MultiheadAttention(d_model, num_heads, dropout=0.1), - nn.MultiheadAttention(d_model, num_heads, dropout=0.1), - nn.MultiheadAttention(d_model, num_heads, dropout=0.1), - nn.MultiheadAttention(d_model, num_heads, dropout=0.1) - ]) - - self.linear1 = nn.Linear(d_model, d_model * 2) - self.linear2 = nn.Linear(d_model * 2, d_model) - self.linear3 = nn.Linear(d_model, d_model * 2) - self.linear4 = nn.Linear(d_model * 2, d_model) - self.norm1 = nn.LayerNorm(d_model) - self.norm2 = nn.LayerNorm(d_model) - self.dropout = nn.Dropout(0.1) - self.dropout1 = nn.Dropout(0.1) - self.dropout2 = nn.Dropout(0.1) - self.activation = get_activation_fn('gelu') - self.pool_ratios = pool_ratios - self.p_poses = [] - self.g_pos = None - self.positional_encoding = PositionEmbeddingSine(num_pos_feats=d_model // 2, normalize=True) - - def forward(self, l, g): - """ - l: 4,c,h,w - g: 1,c,h,w - """ - self.p_poses = [] - self.g_pos = None - _b, _c, h, w = l.size() - # 4,c,h,w -> 1,c,2h,2w - concated_locs = rearrange(l, '(hg wg b) c h w -> b c (hg h) (wg w)', hg=2, wg=2) - - pools = [] - for pool_ratio in self.pool_ratios: - # b,c,h,w - tgt_hw = (round(h / pool_ratio), round(w / pool_ratio)) - pool = F.adaptive_avg_pool2d(concated_locs, tgt_hw) - pools.append(rearrange(pool, 'b c h w -> (h w) b c')) - if self.g_pos is None: - pos_emb = self.positional_encoding(pool.shape[0], pool.shape[2], pool.shape[3]) - pos_emb = rearrange(pos_emb, 'b c h w -> (h w) b c') - self.p_poses.append(pos_emb) - pools = torch.cat(pools, 0) - if self.g_pos is None: - self.p_poses = torch.cat(self.p_poses, dim=0) - pos_emb = self.positional_encoding(g.shape[0], g.shape[2], g.shape[3]) - self.g_pos = rearrange(pos_emb, 'b c h w -> (h w) b c') - - device = pools.device - self.p_poses = self.p_poses.to(device) - self.g_pos = self.g_pos.to(device) - - - # attention between glb (q) & multisensory concated-locs (k,v) - g_hw_b_c = rearrange(g, 'b c h w -> (h w) b c') - - - g_hw_b_c = g_hw_b_c + self.dropout1(self.attention[0](g_hw_b_c + self.g_pos, pools + self.p_poses, pools)[0]) - g_hw_b_c = self.norm1(g_hw_b_c) - g_hw_b_c = g_hw_b_c + self.dropout2(self.linear2(self.dropout(self.activation(self.linear1(g_hw_b_c)).clone()))) - g_hw_b_c = self.norm2(g_hw_b_c) - - # attention between origin locs (q) & freashed glb (k,v) - l_hw_b_c = rearrange(l, "b c h w -> (h w) b c") - _g_hw_b_c = rearrange(g_hw_b_c, '(h w) b c -> h w b c', h=h, w=w) - _g_hw_b_c = rearrange(_g_hw_b_c, "(ng h) (nw w) b c -> (h w) (ng nw b) c", ng=2, nw=2) - outputs_re = [] - for i, (_l, _g) in enumerate(zip(l_hw_b_c.chunk(4, dim=1), _g_hw_b_c.chunk(4, dim=1), strict=False)): - outputs_re.append(self.attention[i + 1](_l, _g, _g)[0]) # (h w) 1 c - outputs_re = torch.cat(outputs_re, 1) # (h w) 4 c - - l_hw_b_c = l_hw_b_c + self.dropout1(outputs_re) - l_hw_b_c = self.norm1(l_hw_b_c) - l_hw_b_c = l_hw_b_c + self.dropout2(self.linear4(self.dropout(self.activation(self.linear3(l_hw_b_c)).clone()))) - l_hw_b_c = self.norm2(l_hw_b_c) - - l = torch.cat((l_hw_b_c, g_hw_b_c), 1) # hw,b(5),c - return rearrange(l, "(h w) b c -> b c h w", h=h, w=w) ## (5,c,h*w) - - - - - - - - - -class MCRM(nn.Module): - def __init__(self, d_model, num_heads, pool_ratios=None, h=None): # pylint: disable=unused-argument - if pool_ratios is None: - pool_ratios = [4, 8, 16] - super().__init__() - self.attention = nn.ModuleList([ - nn.MultiheadAttention(d_model, num_heads, dropout=0.1), - nn.MultiheadAttention(d_model, num_heads, dropout=0.1), - nn.MultiheadAttention(d_model, num_heads, dropout=0.1), - nn.MultiheadAttention(d_model, num_heads, dropout=0.1) - ]) - self.linear3 = nn.Linear(d_model, d_model * 2) - self.linear4 = nn.Linear(d_model * 2, d_model) - self.norm1 = nn.LayerNorm(d_model) - self.norm2 = nn.LayerNorm(d_model) - self.dropout = nn.Dropout(0.1) - self.dropout1 = nn.Dropout(0.1) - self.dropout2 = nn.Dropout(0.1) - self.sigmoid = nn.Sigmoid() - self.activation = get_activation_fn('gelu') - self.sal_conv = nn.Conv2d(d_model, 1, 1) - self.pool_ratios = pool_ratios - - def forward(self, x): - # device = x.device - _b, c, h, w = x.size() - loc, glb = x.split([4, 1], dim=0) # 4,c,h,w; 1,c,h,w - - patched_glb = rearrange(glb, 'b c (hg h) (wg w) -> (hg wg b) c h w', hg=2, wg=2) - - token_attention_map = self.sigmoid(self.sal_conv(glb)) - token_attention_map = F.interpolate(token_attention_map, size=patches2image(loc).shape[-2:], mode='nearest') - loc = loc * rearrange(token_attention_map, 'b c (hg h) (wg w) -> (hg wg b) c h w', hg=2, wg=2) - - pools = [] - for pool_ratio in self.pool_ratios: - tgt_hw = (round(h / pool_ratio), round(w / pool_ratio)) - pool = F.adaptive_avg_pool2d(patched_glb, tgt_hw) - pools.append(rearrange(pool, 'nl c h w -> nl c (h w)')) # nl(4),c,hw - - pools = rearrange(torch.cat(pools, 2), "nl c nphw -> nl nphw 1 c") - loc_ = rearrange(loc, 'nl c h w -> nl (h w) 1 c') - - outputs = [] - for i, q in enumerate(loc_.unbind(dim=0)): # traverse all local patches - v = pools[i] - k = v - outputs.append(self.attention[i](q, k, v)[0]) - - outputs = torch.cat(outputs, 1) - src = loc.view(4, c, -1).permute(2, 0, 1) + self.dropout1(outputs) - src = self.norm1(src) - src = src + self.dropout2(self.linear4(self.dropout(self.activation(self.linear3(src)).clone()))) - src = self.norm2(src) - src = src.permute(1, 2, 0).reshape(4, c, h, w) # freshed loc - glb = glb + F.interpolate(patches2image(src), size=glb.shape[-2:], mode='nearest') # freshed glb - - return torch.cat((src, glb), 0), token_attention_map - - - -class BEN_Base(nn.Module): - def __init__(self): - super().__init__() - - self.backbone = SwinTransformer(embed_dim=128, depths=[2, 2, 18, 2], num_heads=[4, 8, 16, 32], window_size=12) - emb_dim = 128 - self.sideout5 = nn.Sequential(nn.Conv2d(emb_dim, 1, kernel_size=3, padding=1)) - self.sideout4 = nn.Sequential(nn.Conv2d(emb_dim, 1, kernel_size=3, padding=1)) - self.sideout3 = nn.Sequential(nn.Conv2d(emb_dim, 1, kernel_size=3, padding=1)) - self.sideout2 = nn.Sequential(nn.Conv2d(emb_dim, 1, kernel_size=3, padding=1)) - self.sideout1 = nn.Sequential(nn.Conv2d(emb_dim, 1, kernel_size=3, padding=1)) - - self.output5 = make_cbr(1024, emb_dim) - self.output4 = make_cbr(512, emb_dim) - self.output3 = make_cbr(256, emb_dim) - self.output2 = make_cbr(128, emb_dim) - self.output1 = make_cbr(128, emb_dim) - - self.multifieldcrossatt = MCLM(emb_dim, 1, [1, 4, 8]) - self.conv1 = make_cbr(emb_dim, emb_dim) - self.conv2 = make_cbr(emb_dim, emb_dim) - self.conv3 = make_cbr(emb_dim, emb_dim) - self.conv4 = make_cbr(emb_dim, emb_dim) - self.dec_blk1 = MCRM(emb_dim, 1, [2, 4, 8]) - self.dec_blk2 = MCRM(emb_dim, 1, [2, 4, 8]) - self.dec_blk3 = MCRM(emb_dim, 1, [2, 4, 8]) - self.dec_blk4 = MCRM(emb_dim, 1, [2, 4, 8]) - - self.insmask_head = nn.Sequential( - nn.Conv2d(emb_dim, 384, kernel_size=3, padding=1), - nn.InstanceNorm2d(384), - nn.GELU(), - nn.Conv2d(384, 384, kernel_size=3, padding=1), - nn.InstanceNorm2d(384), - nn.GELU(), - nn.Conv2d(384, emb_dim, kernel_size=3, padding=1) - ) - - self.shallow = nn.Sequential(nn.Conv2d(3, emb_dim, kernel_size=3, padding=1)) - self.upsample1 = make_cbg(emb_dim, emb_dim) - self.upsample2 = make_cbg(emb_dim, emb_dim) - self.output = nn.Sequential(nn.Conv2d(emb_dim, 1, kernel_size=3, padding=1)) - - for m in self.modules(): - if isinstance(m, nn.GELU) or isinstance(m, nn.Dropout): - m.inplace = True - - - @torch.inference_mode() - @torch.autocast(device_type="cuda",dtype=torch.float16) - def forward(self, x): - real_batch = x.size(0) - - shallow_batch = self.shallow(x) - glb_batch = rescale_to(x, scale_factor=0.5, interpolation='bilinear') - - - - final_input = None - for i in range(real_batch): - start = i * 4 - end = (i + 1) * 4 - loc_batch = image2patches(x[i,:,:,:].unsqueeze(dim=0)) - input_ = torch.cat((loc_batch, glb_batch[i,:,:,:].unsqueeze(dim=0)), dim=0) - if final_input is None: - final_input= input_ - else: - final_input = torch.cat((final_input, input_), dim=0) - - features = self.backbone(final_input) - outputs = [] - for i in range(real_batch): - - start = i * 5 - end = (i + 1) * 5 - f4 = features[4][start:end, :, :, :] # shape: [5, C, H, W] - f3 = features[3][start:end, :, :, :] - f2 = features[2][start:end, :, :, :] - f1 = features[1][start:end, :, :, :] - f0 = features[0][start:end, :, :, :] - e5 = self.output5(f4) - e4 = self.output4(f3) - e3 = self.output3(f2) - e2 = self.output2(f1) - e1 = self.output1(f0) - loc_e5, glb_e5 = e5.split([4, 1], dim=0) - e5 = self.multifieldcrossatt(loc_e5, glb_e5) # (4,128,16,16) - - - e4, _tokenattmap4 = self.dec_blk4(e4 + resize_as(e5, e4)) - e4 = self.conv4(e4) - e3, _tokenattmap3 = self.dec_blk3(e3 + resize_as(e4, e3)) - e3 = self.conv3(e3) - e2, _tokenattmap2 = self.dec_blk2(e2 + resize_as(e3, e2)) - e2 = self.conv2(e2) - e1, _tokenattmap1 = self.dec_blk1(e1 + resize_as(e2, e1)) - e1 = self.conv1(e1) - - loc_e1, glb_e1 = e1.split([4, 1], dim=0) - - output1_cat = patches2image(loc_e1) # (1,128,256,256) - - # add glb feat in - output1_cat = output1_cat + resize_as(glb_e1, output1_cat) - # merge - final_output = self.insmask_head(output1_cat) # (1,128,256,256) - # shallow feature merge - shallow = shallow_batch[i,:,:,:].unsqueeze(dim=0) - final_output = final_output + resize_as(shallow, final_output) - final_output = self.upsample1(rescale_to(final_output)) - final_output = rescale_to(final_output + resize_as(shallow, final_output)) - final_output = self.upsample2(final_output) - final_output = self.output(final_output) - mask = final_output.sigmoid() - outputs.append(mask) - - return torch.cat(outputs, dim=0) - - - def loadcheckpoints(self,model_path): - model_dict = torch.load(model_path, map_location="cpu", weights_only=True) - self.load_state_dict(model_dict['model_state_dict'], strict=True) - del model_path - - def inference(self,image,refine_foreground=False): - # image = ImageOps.exif_transpose(image) - if isinstance(image, Image.Image): - image, h, w,original_image = rgb_loader_refiner(image) - if torch.cuda.is_available(): - - img_tensor = img_transform(image).unsqueeze(0).to(next(self.parameters()).device) - else: - img_tensor = img_transform32(image).unsqueeze(0).to(next(self.parameters()).device) - - with torch.no_grad(): - res = self.forward(img_tensor) - - # Show Results - if refine_foreground: - - pred_pil = transforms.ToPILImage()(res.squeeze()) - image_masked = refine_foreground_process(original_image, pred_pil) - image_masked.putalpha(pred_pil.resize(original_image.size)) - return image_masked - - else: - alpha = postprocess_image(res, im_size=[w,h]) - pred_pil = transforms.ToPILImage()(alpha) - mask = pred_pil.resize(original_image.size) - original_image.putalpha(mask) - # mask = Image.fromarray(alpha) - - return original_image - - - else: - foregrounds = [] - for batch in image: - image, h, w,original_image = rgb_loader_refiner(batch) - if torch.cuda.is_available(): - - img_tensor = img_transform(image).unsqueeze(0).to(next(self.parameters()).device) - else: - img_tensor = img_transform32(image).unsqueeze(0).to(next(self.parameters()).device) - - with torch.no_grad(): - res = self.forward(img_tensor) - - if refine_foreground: - - pred_pil = transforms.ToPILImage()(res.squeeze()) - image_masked = refine_foreground_process(original_image, pred_pil) - image_masked.putalpha(pred_pil.resize(original_image.size)) - - foregrounds.append(image_masked) - else: - alpha = postprocess_image(res, im_size=[w,h]) - pred_pil = transforms.ToPILImage()(alpha) - mask = pred_pil.resize(original_image.size) - original_image.putalpha(mask) - # mask = Image.fromarray(alpha) - foregrounds.append(original_image) - - return foregrounds - - - - - def segment_video(self, video_path, output_path="./", fps=0, refine_foreground=False, batch=1, print_frames_processed=True, webm = False, rgb_value= (0, 255, 0)): - """ - Segments the given video to extract the foreground (with alpha) from each frame - and saves the result as either a WebM video (with alpha channel) or MP4 (with a - color background). - - Args: - video_path (str): - Path to the input video file. - - output_path (str, optional): - Directory (or full path) where the output video and/or files will be saved. - Defaults to "./". - - fps (int, optional): - The frames per second (FPS) to use for the output video. If 0 (default), the - original FPS of the input video is used. Otherwise, overrides it. - - refine_foreground (bool, optional): - Whether to run an additional “refine foreground” process on each frame. - Defaults to False. - - batch (int, optional): - Number of frames to process at once (inference batch size). Large batch sizes - may require more GPU memory. Defaults to 1. - - print_frames_processed (bool, optional): - If True (default), prints progress (how many frames have been processed) to - the console. - - webm (bool, optional): - If True (default), exports a WebM video with alpha channel (VP9 / yuva420p). - If False, exports an MP4 video composited over a solid color background. - - rgb_value (tuple, optional): - The RGB background color (e.g., green screen) used to composite frames when - saving to MP4. Defaults to (0, 255, 0). - - Returns: - None. Writes the output video(s) to disk in the specified format. - """ - cap = cv2.VideoCapture(video_path) - if not cap.isOpened(): - raise OSError(f"Cannot open video: {video_path}") - - original_fps = cap.get(cv2.CAP_PROPFPS) - original_fps = 30 if original_fps == 0 else original_fps - fps = original_fps if fps == 0 else fps - - ret, first_frame = cap.read() - if not ret: - raise ValueError("No frames found in the video.") - _height, _width = first_frame.shape[:2] - cap.set(cv2.CAP_PROP_POSFRAMES, 0) - - foregrounds = [] - frame_idx = 0 - processed_count = 0 - batch_frames = [] - total_frames = int(cap.get(cv2.CAP_PROPFRAME_COUNT)) - - while True: - ret, frame = cap.read() - if not ret: - if batch_frames: - batch_results = self.inference(batch_frames, refine_foreground) - if isinstance(batch_results, Image.Image): - foregrounds.append(batch_results) - else: - foregrounds.extend(batch_results) - if print_frames_processed: - print(f"Processed frames {frame_idx-len(batch_frames)+1} to {frame_idx} of {total_frames}") - break - - # Process every frame instead of using intervals - frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) - pil_frame = Image.fromarray(frame_rgb) - batch_frames.append(pil_frame) - if len(batch_frames) == batch: - batch_results = self.inference(batch_frames, refine_foreground) - if isinstance(batch_results, Image.Image): - foregrounds.append(batch_results) - else: - foregrounds.extend(batch_results) - if print_frames_processed: - print(f"Processed frames {frame_idx-batch+1} to {frame_idx} of {total_frames}") - batch_frames = [] - processed_count += batch - - frame_idx += 1 - - - if webm: - alpha_webm_path = os.path.join(output_path, "foreground.webm") - pil_images_to_webm_alpha(foregrounds, alpha_webm_path, fps=original_fps) - - else: - cap.release() - fg_output = os.path.join(output_path, 'foreground.mp4') - pil_images_to_mp4(foregrounds, fg_output, fps=original_fps,rgb_value=rgb_value) - cv2.destroyAllWindows() - try: - fg_audio_output = os.path.join(output_path, 'foreground_output_with_audio.mp4') - add_audio_to_video(fg_output, video_path, fg_audio_output) - except Exception as e: - print("No audio found in the original video") - print(e) - - -def rgb_loader_refiner( original_image): - h, w = original_image.size - image = original_image - # Convert to RGB if necessary - if image.mode != 'RGB': - image = image.convert('RGB') - # Resize the image - image = image.resize((1024, 1024), resample=Image.Resampling.LANCZOS) - return image.convert('RGB'), h, w,original_image - - -# Define the image transformation -img_transform = transforms.Compose([ - transforms.ToTensor(), - transforms.ConvertImageDtype(torch.float16), - transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]) -]) - -img_transform32 = transforms.Compose([ - transforms.ToTensor(), - transforms.ConvertImageDtype(torch.float32), - transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]) -]) - - -def pil_images_to_mp4(images, output_path, fps=24, rgb_value=(0, 255, 0)): - """ - Converts an array of PIL images to an MP4 video. - Args: - images: List of PIL images - output_path: Path to save the MP4 file - fps: Frames per second (default: 24) - rgb_value: Background RGB color tuple (default: green (0, 255, 0)) - """ - if not images: - raise ValueError("No images provided to convert to MP4.") - - width, height = images[0].size - fourcc = cv2.VideoWriter_fourcc(*'mp4v') - video_writer = cv2.VideoWriter(output_path, fourcc, fps, (width, height)) - - for image in images: - # If image has alpha channel, composite onto the specified background color - if image.mode == 'RGBA': - # Create background image with specified RGB color - background = Image.new('RGB', image.size, rgb_value) - background = background.convert('RGBA') - # Composite the image onto the background - image = Image.alpha_composite(background, image) - image = image.convert('RGB') - else: - # Ensure RGB format for non-alpha images - image = image.convert('RGB') - - # Convert to OpenCV format and write - open_cv_image = cv2.cvtColor(np.array(image), cv2.COLOR_RGB2BGR) - video_writer.write(open_cv_image) - video_writer.release() - -def pil_images_to_webm_alpha(images, output_path, fps=30): - """ - Converts a list of PIL RGBA images to a VP9 .webm video with alpha channel. - - NOTE: Not all players will display alpha in WebM. - Browsers like Chrome/Firefox typically do support VP9 alpha. - """ - if not images: - raise ValueError("No images provided for WebM with alpha.") - - # Ensure output directory exists - os.makedirs(os.path.dirname(output_path), exist_ok=True) - - with tempfile.TemporaryDirectory() as tmpdir: - # Save frames as PNG (with alpha) - for idx, img in enumerate(images): - if img.mode != "RGBA": - img = img.convert("RGBA") - out_path = os.path.join(tmpdir, f"{idx:06d}.png") - img.save(out_path, "PNG") - - # Construct ffmpeg command - # -c:v libvpx-vp9 => VP9 encoder - # -pix_fmt yuva420p => alpha-enabled pixel format - # -auto-alt-ref 0 => helps preserve alpha frames (libvpx quirk) - ffmpeg_cmd = [ - "ffmpeg", "-y", - "-framerate", str(fps), - "-i", os.path.join(tmpdir, "%06d.png"), - "-c:v", "libvpx-vp9", - "-pix_fmt", "yuva420p", - "-auto-alt-ref", "0", - output_path - ] - - subprocess.run(ffmpeg_cmd, check=True) - - print(f"WebM with alpha saved to {output_path}") - -def add_audio_to_video(video_without_audio_path, original_video_path, output_path): - """ - Check if the original video has an audio stream. If yes, add it. If not, skip. - """ - # 1) Probe original video for audio streams - probe_command = [ - 'ffprobe', '-v', 'error', - '-select_streams', 'a:0', - '-show_entries', 'stream=index', - '-of', 'csv=p=0', - original_video_path - ] - result = subprocess.run(probe_command, capture_output=True, text=True, check=False) - - # result.stdout is empty if no audio stream found - if not result.stdout.strip(): - print("No audio track found in original video, skipping audio addition.") - return - print("Audio track detected; proceeding to mux audio.") - # 2) If audio found, run ffmpeg to add it - command = [ - 'ffmpeg', '-y', - '-i', video_without_audio_path, - '-i', original_video_path, - '-c', 'copy', - '-map', '0:v:0', - '-map', '1:a:0', # we know there's an audio track now - output_path - ] - subprocess.run(command, check=True) - print(f"Audio added successfully => {output_path}") - - -### Thanks to the source: https://huggingface.co/ZhengPeng7/BiRefNet/blob/main/handler.py -def refine_foreground_process(image, mask, r=90): - if mask.size != image.size: - mask = mask.resize(image.size) - image = np.array(image) / 255.0 - mask = np.array(mask) / 255.0 - estimated_foreground = FB_blur_fusion_foreground_estimator_2(image, mask, r=r) - image_masked = Image.fromarray((estimated_foreground * 255.0).astype(np.uint8)) - return image_masked - - -def FB_blur_fusion_foreground_estimator_2(image, alpha, r=90): - # Thanks to the source: https://github.com/Photoroom/fast-foreground-estimation - alpha = alpha[:, :, None] - F, blur_B = FB_blur_fusion_foreground_estimator(image, image, image, alpha, r) - return FB_blur_fusion_foreground_estimator(image, F, blur_B, alpha, r=6)[0] - - -def FB_blur_fusion_foreground_estimator(image, F, B, alpha, r=90): - if isinstance(image, Image.Image): - image = np.array(image) / 255.0 - blurred_alpha = cv2.blur(alpha, (r, r))[:, :, None] - - blurredFA = cv2.blur(F * alpha, (r, r)) - blurredF = blurredFA / (blurred_alpha + 1e-5) - - blurred_B1A = cv2.blur(B * (1 - alpha), (r, r)) - blurred_B = blurred_B1A / ((1 - blurred_alpha) + 1e-5) - F = blurredF + alpha * \ - (image - alpha * blurredF - (1 - alpha) * blurred_B) - F = np.clip(F, 0, 1) - return F, blurred_B - - -def postprocess_image(result: torch.Tensor, im_size: list) -> np.ndarray: - result = torch.squeeze(F.interpolate(result, size=im_size, mode='bilinear'), 0) - ma = torch.max(result) - mi = torch.min(result) - result = (result - mi) / (ma - mi) - im_array = (result * 255).permute(1, 2, 0).cpu().data.numpy().astype(np.uint8) - im_array = np.squeeze(im_array) - return im_array diff --git a/modules/caption/gemini.py b/modules/caption/gemini.py index c5a6f8e70..3297bec12 100644 --- a/modules/caption/gemini.py +++ b/modules/caption/gemini.py @@ -3,6 +3,7 @@ import os from modules import shared from modules.logger import log + debug_enabled = os.environ.get('SD_CAPTION_DEBUG', None) is not None debug_log = log.trace if debug_enabled else lambda *args, **kwargs: None @@ -11,7 +12,7 @@ class GoogleGeminiPipeline(): def __init__(self, model_name: str): self.model = model_name.split(' (')[0] from installer import install - install('google-genai==1.52.0') + install('google-genai==2.22.0') from google import genai # pylint: disable=no-name-in-module args = self.get_args() self.client = genai.Client(**args) @@ -63,11 +64,13 @@ class GoogleGeminiPipeline(): config['temperature'] = kwargs['temperature'] if 'max_output_tokens' in kwargs: config['max_output_tokens'] = kwargs['max_output_tokens'] - debug_log(f'Gemini config: {config}') + debug_log(f'LLM config: {config}') + debug_log(f'LLM instructions: "{instructions}"') + debug_log(f'LLM image: {image}') question = question.replace('<', '').replace('>', '').replace('_', ' ') if prefill: question += prefill - debug_log(f'Gemini question: "{question}"') + debug_log(f'LLM question: "{question}"') if image: data = io.BytesIO() @@ -80,9 +83,9 @@ class GoogleGeminiPipeline(): answer = '' try: response = self.client.models.generate_content( - model=model, - contents=contents, - config=config, + model = model, + contents = contents, + config = config, ) debug_log(f'Gemini response: {response}') answer = response.text @@ -94,8 +97,8 @@ class GoogleGeminiPipeline(): ai = None -def predict(question, image, vqa_model, system_prompt, model_name, prefill, thinking, gen_kwargs): +def predict(question, image, model_name, system_prompt, prefill, thinking, gen_kwargs): global ai # pylint: disable=global-statement if ai is None: ai = GoogleGeminiPipeline(model_name) - return ai(question, image, vqa_model, system_prompt, prefill, thinking, gen_kwargs) + return ai(question, image, model_name, system_prompt, prefill, thinking, gen_kwargs) diff --git a/modules/caption/grok.py b/modules/caption/grok.py new file mode 100644 index 000000000..2f7fb9965 --- /dev/null +++ b/modules/caption/grok.py @@ -0,0 +1,99 @@ +import io +import os +import base64 +from modules import shared +from modules.logger import log + + +debug_enabled = os.environ.get('SD_CAPTION_DEBUG', None) is not None +debug_log = log.trace if debug_enabled else lambda *args, **kwargs: None + + +class XAIGrokPipeline(): + def __init__(self, model_name: str): + self.url = 'https://api.x.ai/v1' + self.model = model_name.split(' (')[0].replace('xai/', '') + from installer import install + install('openai') + from openai import OpenAI # pylint: disable=no-name-in-module + args = self.get_args() + if not args: + return + self.client = OpenAI(**args) + log.debug(f'Load model: type=XAIGrok model="{self.model}"') + + def get_args(self): + from modules.shared import opts + # Use UI settings only - env vars are intentionally ignored + api_key = opts.xai_api_key + has_api_key = api_key and len(api_key) > 0 + if not has_api_key: # Gemini Developer API: api_key only + log.error(f'Cloud: model="{self.model}" API key not provided') + return None + args = { + 'api_key': api_key, + 'base_url': self.url, + } + # Debug logging + args_log = args.copy() + if args_log.get('api_key'): + args_log['api_key'] = '...' + args_log['api_key'][-4:] + log.debug(f'Cloud: model="{self.model}" args={args_log}') + return args + + def __call__(self, question, image, model, instructions, prefill, thinking, kwargs): + question = question.replace('<', '').replace('>', '').replace('_', ' ') + if prefill: + question += prefill + debug_log(f'LLM instructions: "{instructions}"') + debug_log(f'LLM question: "{question}"') + debug_log(f'LLM image: {image}') + answer = '' + temperature = kwargs.get('temperature', 0.0) + try: + if image is not None: + image_data = image.convert('RGB') + image_bytes = io.BytesIO() + image_data.save(image_bytes, format='JPEG') + image_bytes.seek(0) + content = [ + { + "type": "image_url", + "image_url": { + "url": f"data:image/jpeg;base64,{base64.b64encode(image_bytes.getvalue()).decode('utf-8')}", + "detail": "high", + }, + }, + { + "type": "text", + "text": question, + }, + ] + else: + content = question + response = self.client.chat.completions.create( + model = self.model, + messages = [ + {"role": "system", "content": instructions or shared.opts.caption_vlm_system}, + {"role": "user", "content": content}, + ], + stream = False, + temperature = temperature, + reasoning_effort = "high" if thinking else "low" + ) + text = (response.choices[0].message.content or "").strip() + debug_log(f'Grok response: {response}') + answer = text + except Exception as e: + log.error(f'Grok: {e}') + answer = f'Error: {e}' + return answer + + +ai = None + +def predict(question, image, model_name, system_prompt, prefill, thinking, gen_kwargs): + global ai # pylint: disable=global-statement + if ai is None: + ai = XAIGrokPipeline(model_name) + return ai(question, image, model_name, system_prompt, prefill, thinking, gen_kwargs) diff --git a/modules/caption/models_def.py b/modules/caption/models_def.py index 82d529616..f325a187b 100644 --- a/modules/caption/models_def.py +++ b/modules/caption/models_def.py @@ -74,13 +74,17 @@ vlm_models = { "AIDC Ovis2 2B": "AIDC-AI/Ovis2-2B", "AIDC Ovis2 1B": "AIDC-AI/Ovis2-1B", # cloud - f"Google Gemini 3.5 Flash {ui_symbols.cloud}": "google/gemini-3.5-flash", - f"Google Gemini 3.1 Pro {ui_symbols.cloud}": "gemini-3.1-pro-preview", + f"Google Gemini 3.8 Flash {ui_symbols.cloud}": "gemini-3.8-flash", + f"Google Gemini 3.7 Flash {ui_symbols.cloud}": "gemini-3.7-flash", + f"Google Gemini 3.6 Flash {ui_symbols.cloud}": "gemini-3.6-flash", + f"Google Gemini 3.5 Flash {ui_symbols.cloud}": "gemini-3.5-flash", + f"Google Gemini 3.5 Flash Lite {ui_symbols.cloud}": "gemini-3.5-flash-lite", f"Google Gemini 3.1 Flash Lite {ui_symbols.cloud}": "gemini-3.1-flash-lite", - f"Google Gemini 3.1 Flash Lite Preview {ui_symbols.cloud}": "gemini-3.1-flash-lite-preview", - f"Google Gemini 2.5 Pro {ui_symbols.cloud}": "gemini-2.5-pro", - f"Google Gemini 2.5 Flash {ui_symbols.cloud}": "gemini-2.5-flash", - f"Google Gemini 2.5 Flash Lite {ui_symbols.cloud}": "gemini-2.5-flash-lite", + f"Google Gemini 3.1 Pro {ui_symbols.cloud}": "gemini-3.1-pro-preview", + f"X.AI Grok 3 {ui_symbols.cloud}": "grok-3-latest", + f"X.AI Grok 3 Fast {ui_symbols.cloud}": "grok-3-fast-latest", + f"X.AI Grok 3 Mini {ui_symbols.cloud}": "grok-3-mini-latest", + f"X.AI Grok 3 Mini Fast {ui_symbols.cloud}": "grok-3-mini-fast-latest", } # Default model @@ -224,5 +228,10 @@ Summary: def get_vlm_repo(display_name: str) -> str: """Look up repo ID from display name, stripping any trailing symbols.""" + from modules.logger import log name = display_name.strip() - return vlm_models.get(name, name) + model = vlm_models.get(name, None) + if model is None: + log.warning(f"Model '{name}' not found") + return name + return model diff --git a/modules/caption/vqa.py b/modules/caption/vqa.py index 784f6d941..6a00e2fa3 100644 --- a/modules/caption/vqa.py +++ b/modules/caption/vqa.py @@ -1597,7 +1597,12 @@ class VQA: handler = 'gemini' gen_kwargs = get_kwargs(self.model) from modules.caption import gemini - answer = gemini.predict(question, image, vqa_model, system_prompt, model_name, prefill, thinking_mode, gen_kwargs) + answer = gemini.predict(question, image, vqa_model, system_prompt, prefill, thinking_mode, gen_kwargs) + elif 'grok' in vqa_model.lower(): + handler = 'grok' + gen_kwargs = get_kwargs(self.model) + from modules.caption import grok + answer = grok.predict(question, image, vqa_model, system_prompt, prefill, thinking_mode, gen_kwargs) else: answer = 'unknown model' except Exception as e: diff --git a/modules/caption/vqa_detection.py b/modules/caption/vqa_detection.py index 8b03e21c9..17cc4e89b 100644 --- a/modules/caption/vqa_detection.py +++ b/modules/caption/vqa_detection.py @@ -313,7 +313,7 @@ def draw_bounding_boxes(image: Image.Image, detections: list, points: list | Non # Try to load a font, fall back to default if unavailable try: font_size = max(12, int(min(width, height) * 0.02)) - font_path = shared.opts.font or os.path.join(script_path, "ui", "fonts", "notosans-nerdfont-regular.ttf") + font_path = shared.opts.font or os.path.join(script_path, "ui", "css", "ubuntu-nerdfont.ttf") font = ImageFont.truetype(font_path, size=font_size) except Exception: font = ImageFont.load_default() diff --git a/modules/civitai/api_civitai.py b/modules/civitai/api_civitai.py index 28705a641..f7c68b761 100644 --- a/modules/civitai/api_civitai.py +++ b/modules/civitai/api_civitai.py @@ -71,6 +71,8 @@ def file_to_legacy_dict(f) -> dict: 'size': int(f.size_kb * 1024), 'name': f.name, 'type': f.type, + 'primary': bool(f.primary), + 'metadata': {'fp': f.metadata.fp, 'format': f.metadata.format, 'size': f.metadata.size, 'quantType': f.metadata.quant_type}, 'hashes': [h for h in [f.hashes.sha256, f.hashes.autov1, f.hashes.autov2, f.hashes.autov3, f.hashes.crc32, f.hashes.blake3] if h], 'url': f.download_url, } @@ -158,6 +160,15 @@ def get_version_by_hash(hash_str: str, token: str | None = None): return version_to_dict(version) +def get_version_mini(version_id: int, token: str | None = None): + """Download-shaped version view carrying permission and early-access flags.""" + from modules.civitai.client_civitai import client + version = client.get_version_mini(version_id, token=token) + if version is None: + return JSONResponse(content={"error": "version not found"}, status_code=404) + return version_to_dict(version) + + def get_options(): """Get valid types, sort, period, base_models from CivitAI API discovery.""" from modules.civitai.client_civitai import client @@ -374,14 +385,14 @@ def post_settings(request: dict): if user is None: return JSONResponse(content={"error": "Invalid API token"}, status_code=400) log.info(f'CivitAI token validated: user={user.get("username", "?")}') - shared.opts.data['civitai_token'] = token.strip() + shared.opts.civitai_token = token.strip() save_subfolder_enabled = request.get('save_subfolder_enabled') if save_subfolder_enabled is not None: - shared.opts.data['civitai_save_subfolder_enabled'] = bool(save_subfolder_enabled) + shared.opts.civitai_save_subfolder_enabled = bool(save_subfolder_enabled) if save_subfolder is not None: - shared.opts.data['civitai_save_subfolder'] = save_subfolder + shared.opts.civitai_save_subfolder = save_subfolder if discard_hash_mismatch is not None: - shared.opts.data['civitai_discard_hash_mismatch'] = discard_hash_mismatch + shared.opts.civitai_discard_hash_mismatch = discard_hash_mismatch shared.opts.save() return get_settings() @@ -415,9 +426,12 @@ def post_metadata_scan(request: dict | None = None): from modules.civitai import metadata_civitai page = (request or {}).get('page', None) results = [] - for batch in metadata_civitai.civit_search_metadata(title=page, raw=True): - if isinstance(batch, list): - results = batch + try: + for batch in metadata_civitai.civit_search_metadata(title=page, raw=True): + if isinstance(batch, list): + results = batch + except metadata_civitai.SweepBusy as e: + return JSONResponse(content={"error": str(e)}, status_code=409) return {"results": results} @@ -425,9 +439,12 @@ def post_metadata_update(): """Update local metadata from CivitAI.""" from modules.civitai import metadata_civitai items = [] - for batch in metadata_civitai.civit_update_metadata(raw=True): - if isinstance(batch, list): - items = batch + try: + for batch in metadata_civitai.civit_update_metadata(raw=True): + if isinstance(batch, list): + items = batch + except metadata_civitai.SweepBusy as e: + return JSONResponse(content={"error": str(e)}, status_code=409) results = [] for item in items: results.append({ @@ -550,7 +567,6 @@ def buildsidecar_index(): continue # Match the companion file to a JSON entry by size (sizeKB) companion_size_kb = os.path.getsize(companion) / 1024.0 - companion_name = os.path.basename(base) best_sha = None best_diff = float('inf') for v in data.get('modelVersions', []): @@ -563,7 +579,7 @@ def buildsidecar_index(): best_sha = sha best_diff = diff if best_sha: - sidecar_index[best_sha.lower()] = {"filename": companion_name, "type": model_type} + sidecar_index[best_sha.lower()] = {"filename": companion, "type": model_type} except Exception: continue log.debug(f'CivitAI sidecar index: {len(sidecar_index)} hashes from sidecar files') @@ -580,54 +596,60 @@ def invalidatesidecar_index(): # --------------------------------------------------------------------------- def post_check_local(request: dict): - """Check which SHA256 hashes correspond to locally downloaded files.""" + """Check which SHA256 hashes correspond to local model files, dropping hash cache entries whose files are gone.""" from modules import hashes as hash_module - input_hashes = request.get('hashes', []) - if not input_hashes: + from modules.civitai.filemanage_civitai import hash_cache_path, prune_hash_cache + requested = [str(h) for h in request.get('hashes', []) if h] + if not requested: return {"found": {}} - # Build reverse lookup: lowercase sha256 -> {filename, type} + prune_hash_cache() + wanted = {h.lower() for h in requested} + titles_by_sha: dict[str, list[str]] = {} + for title, entry in list(hash_module.cache().items()): + sha = (entry.get("sha256") or "").lower() + if sha in wanted: + titles_by_sha.setdefault(sha, []).append(title) found = {} - for title, entry in hash_module.cache().items(): - sha = entry["sha256"] - if not sha: - continue - parts = title.split("/", 1) - file_type = parts[0] if len(parts) > 1 else "unknown" - found[sha.lower()] = {"filename": title, "type": file_type} - # Supplement from in-memory checkpoint registry + gone = [] + for sha, titles in titles_by_sha.items(): + for title in titles: + path = hash_cache_path(title) + if path is None: # no loaded registry names the file + continue + if os.path.exists(path): + found[sha] = {"filename": path, "type": title.split("/", 1)[0]} + break + gone.append(title) + if gone: + for title in gone: + hash_module.cache().pop(title, None) + hash_module.save_cache() + log.debug(f'CivitAI check local: pruned={len(gone)} hash cache entries without files') try: from modules.sd_checkpoint import checkpoints_list - for _title, cp in checkpoints_list.items(): - if cp.sha256: - key = cp.sha256.lower() - if key not in found: - found[key] = {"filename": cp.filename, "type": "checkpoint"} + for cp in checkpoints_list.values(): + key = (cp.sha256 or "").lower() + if key in wanted and key not in found and os.path.exists(cp.filename): + found[key] = {"filename": cp.filename, "type": "checkpoint"} except Exception: pass - # Supplement from in-memory LoRA registry try: from modules.lora.lora_load import available_networks - for _name, net in available_networks.items(): - if net.hash: - key = net.hash.lower() - if key not in found: - found[key] = {"filename": net.filename, "type": "lora"} + for net in available_networks.values(): + key = (net.hash or "").lower() + if key in wanted and key not in found and os.path.isfile(net.filename): + found[key] = {"filename": net.filename, "type": "lora"} except Exception: pass - # Supplement from sidecar index (covers files never hashed locally) sidecar = buildsidecar_index() - for h in input_hashes: - if not h: - continue - key = h.lower() - if key not in found and key in sidecar: - found[key] = sidecar[key] - # Match requested hashes result = {} - for h in input_hashes: - if not h: - continue - match = found.get(h.lower()) + for h in requested: + key = h.lower() + match = found.get(key) + if match is None: + entry = sidecar.get(key) + if entry and os.path.isfile(entry["filename"]): + match = entry if match: result[h] = match return {"found": result} @@ -664,7 +686,7 @@ def legacy_get_civitai( query=query, tag=tag, types=types, sort=sort, period=period, nsfw=nsfw, limit=limit, base=base, token=token, exact=exact, ) - return [model_to_legacy_dict(m) for m in models] + return [model_to_legacy_dict(m) for m in models.items] return JSONResponse(content=[], status_code=200) @@ -672,8 +694,11 @@ def legacy_post_civitai(page: str | None = None): """Legacy POST /sdapi/v1/civitai — scan metadata.""" from modules.civitai import metadata_civitai result = [] - for r in metadata_civitai.civit_search_metadata(title=page, raw=True): - result = r + try: + for r in metadata_civitai.civit_search_metadata(title=page, raw=True): + result = r + except metadata_civitai.SweepBusy as e: + return JSONResponse(content={"error": str(e)}, status_code=409) return result @@ -687,6 +712,7 @@ def register_api(api): api.add_api_route("/sdapi/v2/civitai/model/{model_id}", get_model, methods=["GET"], tags=["CivitAI"]) api.add_api_route("/sdapi/v2/civitai/version/{version_id}", get_version, methods=["GET"], tags=["CivitAI"]) api.add_api_route("/sdapi/v2/civitai/version/by-hash/{hash_str}", get_version_by_hash, methods=["GET"], tags=["CivitAI"]) + api.add_api_route("/sdapi/v2/civitai/version/mini/{version_id}", get_version_mini, methods=["GET"], tags=["CivitAI"]) api.add_api_route("/sdapi/v2/civitai/options", get_options, methods=["GET"], tags=["CivitAI"]) api.add_api_route("/sdapi/v2/civitai/tags", get_tags, methods=["GET"], tags=["CivitAI"]) api.add_api_route("/sdapi/v2/civitai/creators", get_creators, methods=["GET"], tags=["CivitAI"]) diff --git a/modules/civitai/basemodels_civitai.py b/modules/civitai/basemodels_civitai.py deleted file mode 100644 index 4b9a5c072..000000000 --- a/modules/civitai/basemodels_civitai.py +++ /dev/null @@ -1,134 +0,0 @@ -import re -import time -from modules.logger import log - - -# Canonical base-model metadata lives in the civitai/civitai repo. The live -# /images validator is generated from it, so the file has metadata (group, -# ecosystem, engine, hidden) while the validator has the current name list. -# Callers merge both. -github_cache: list[dict] = [] -github_cache_time: float = 0 -GITHUB_TTL = 6 * 3600 # 6 hours -GITHUB_URL = 'https://raw.githubusercontent.com/civitai/civitai/main/src/shared/constants/base-model.constants.ts' - - -def parse_base_model_config(ts_source: str) -> list[dict]: - """Parse the baseModelConfig array from base-model.constants.ts. - - Uses character-by-character bracket walking rather than regex because - entries can span multiple lines. Returns list of dicts with keys - name/type/group/hidden plus optional ecosystem/engine/family. - """ - start_match = re.search(r'const\s+baseModelConfig\s*=\s*\[', ts_source) - if not start_match: - return [] - # Walk to the matching ] respecting string literals - pos = start_match.end() - depth = 1 - in_string: str | None = None - end_pos = -1 - while pos < len(ts_source): - ch = ts_source[pos] - if in_string is not None: - if ch == '\\': - pos += 2 - continue - if ch == in_string: - in_string = None - else: - if ch in ("'", '"', '`'): - in_string = ch - elif ch == '[': - depth += 1 - elif ch == ']': - depth -= 1 - if depth == 0: - end_pos = pos - break - pos += 1 - if end_pos < 0: - return [] - array_body = ts_source[start_match.end():end_pos] - # Extract top-level {...} entries, respecting strings and nested braces - entries: list[str] = [] - brace_start = -1 - brace_depth = 0 - in_string = None - i = 0 - while i < len(array_body): - ch = array_body[i] - if in_string is not None: - if ch == '\\': - i += 2 - continue - if ch == in_string: - in_string = None - else: - if ch in ("'", '"', '`'): - in_string = ch - elif ch == '{': - if brace_depth == 0: - brace_start = i - brace_depth += 1 - elif ch == '}': - brace_depth -= 1 - if brace_depth == 0 and brace_start >= 0: - entries.append(array_body[brace_start:i + 1]) - brace_start = -1 - i += 1 - # Per-entry field extraction (string + bool values only) - field_re = re.compile( - r"(\w+)\s*:\s*(?:'([^'\\]*(?:\\.[^'\\]*)*)'|\"([^\"\\]*(?:\\.[^\"\\]*)*)\"|(true|false))" - ) - parsed: list[dict] = [] - for entry in entries: - fields: dict = {} - for m in field_re.finditer(entry): - key = m.group(1) - if m.group(2) is not None: - fields[key] = m.group(2) - elif m.group(3) is not None: - fields[key] = m.group(3) - elif m.group(4) is not None: - fields[key] = m.group(4) == 'true' - if 'name' in fields and 'type' in fields and 'group' in fields: - item: dict = { - 'name': fields['name'], - 'type': fields['type'], - 'group': fields['group'], - 'hidden': bool(fields.get('hidden', False)), - } - for opt in ('ecosystem', 'engine', 'family'): - if opt in fields: - item[opt] = fields[opt] - parsed.append(item) - return parsed - - -def fetch_github_base_models() -> list[dict]: - """Fetch and parse civitai's base-model constants from GitHub. - - Returns list of metadata dicts (name, type, group, hidden, plus - optional ecosystem/engine/family). Returns [] on any failure; - callers fall back to the live /images probe. Cached with a longer - TTL than discover_options since these constants change rarely. - """ - global github_cache, github_cache_time # pylint: disable=global-statement - now = time.time() - if github_cache and (now - github_cache_time) < GITHUB_TTL: - return github_cache - try: - from modules import shared - r = shared.req(GITHUB_URL) - if r.status_code != 200: - log.debug(f'CivitAI github constants: code={r.status_code}') - return [] - parsed = parse_base_model_config(r.text) - if parsed: - github_cache = parsed - github_cache_time = now - return parsed - except Exception as e: - log.debug(f'CivitAI github constants fetch failed: {e}') - return [] diff --git a/modules/civitai/client_civitai.py b/modules/civitai/client_civitai.py index 3593136e8..1a2f9c499 100644 --- a/modules/civitai/client_civitai.py +++ b/modules/civitai/client_civitai.py @@ -1,8 +1,10 @@ import os +import json import time +import threading +from types import SimpleNamespace from modules.logger import log -from modules.civitai.basemodels_civitai import fetch_github_base_models -from modules.civitai.models_civitai import CivitModel, CivitVersion, CivitImage, CivitSearchResponse, CivitTagResponse, CivitCreatorResponse, CivitUserProfile +from modules.civitai.models_civitai import CivitModel, CivitVersion, CivitVersionMini, CivitImage, CivitSearchResponse, CivitTagResponse, CivitCreatorResponse, CivitUserProfile options_cache: dict = {} @@ -11,6 +13,64 @@ OPTIONS_TTL = 3600 # 1 hour # Civitai nsfwLevel bitmask: 1=PG/None 2=PG-13/Soft 4=R/Mature 8=X 16=XXX 32=Blocked NSFW_LEVEL_SFW = 3 # None + Soft: Civitai's SFW browsing boundary NSFW_LEVEL_ALL = 63 # every level set: disables filtering +BY_HASH_IDS_LIMIT = 10000 # POST /model-versions/by-hash/ids request cap +BY_HASH_LIMIT = 100 # POST /model-versions/by-hash request cap +MODEL_IDS_LIMIT = 100 # GET /models page cap; longer ids lists paginate +RETRY_LIMIT = 4 # retries after HTTP 429 +RETRY_DELAY_MAX = 60 # seconds +request_slots: threading.BoundedSemaphore | None = None +request_slots_lock = threading.Lock() + + +def get_request_slots() -> threading.BoundedSemaphore: + """Process-wide cap on concurrent CivitAI API requests, sized to shared.max_workers.""" + global request_slots # pylint: disable=global-statement + with request_slots_lock: + if request_slots is None: + from modules.shared import max_workers + request_slots = threading.BoundedSemaphore(max_workers) + return request_slots + + +def retry_delay(response, attempt: int) -> float: + """Seconds before retrying a 429: Retry-After when given in seconds, otherwise exponential.""" + headers = getattr(response, 'headers', None) or {} + try: + delay = float(headers.get('Retry-After')) + except (TypeError, ValueError): + delay = 2 ** attempt + return min(max(delay, 0.0), RETRY_DELAY_MAX) + + +def response_message(response) -> str: + """CivitAI error text from a failed response: its error string, ZodError issues, or the HTTP reason.""" + try: + body = response.json() + except Exception: + body = None + error = body.get('error') if isinstance(body, dict) else None + if isinstance(error, dict): + error = error.get('message', '') + try: + error = '; '.join(f"{'.'.join(str(p) for p in issue.get('path', []))}: {issue.get('message', '')}" for issue in json.loads(error)) + except Exception: + pass + message = body.get('message') if isinstance(body, dict) else None + if isinstance(error, str) and isinstance(message, str) and message and message != error: # download refusals carry a short error and a longer message + error = f'{error}: {message}' + if not error: + error = getattr(response, 'reason', '') or getattr(response, 'text', '') + return str(error).strip()[:200] + + +def post_json(url: str, body, headers: dict): + """POST with the timeout, TLS and failure shape of shared.req.""" + import requests + try: + return requests.post(url, json=body, timeout=30, headers=headers, verify=False, allow_redirects=True) + except Exception as e: + log.error(f'HTTP request error: url={url} {e}') + return SimpleNamespace(status_code=500, text=f'HTTP request error: url={url} {e}') class CivitaiClient: @@ -25,7 +85,7 @@ class CivitaiClient: return tok return os.environ.get('CIVITAI_TOKEN', None) - def _get(self, path: str, params: dict | None = None, token: str | None = None, stream: bool = False): + def send(self, method: str, path: str, params: dict | None = None, body=None, token: str | None = None, stream: bool = False): from modules import shared url = f"{self.BASE_URL}{path}" headers = {} @@ -37,7 +97,23 @@ class CivitaiClient: query = urlencode({k: v for k, v in params.items() if v is not None and v != ''}, doseq=True) if query: url = f"{url}?{query}" - return shared.req(url, headers=headers if headers else None, stream=stream) + attempt = 0 + while True: + with get_request_slots(): + if method == 'POST': + r = post_json(url, body, headers) + else: + r = shared.req(url, headers=headers if headers else None, stream=stream) + retry_after = (getattr(r, 'headers', None) or {}).get('Retry-After') + if not (r.status_code == 429 or (r.status_code == 503 and retry_after is not None)) or attempt >= RETRY_LIMIT: # CivitAI sends 503 with Retry-After when search is overloaded + return r + delay = retry_delay(r, attempt) + log.warning(f'CivitAI retry: path={path} code={r.status_code} attempt={attempt + 1} delay={delay:.0f}s message="{response_message(r)}"') + time.sleep(delay) + attempt += 1 + + def _get(self, path: str, params: dict | None = None, token: str | None = None, stream: bool = False): + return self.send('GET', path, params=params, token=token, stream=stream) def search_models(self, *, query: str = "", tag: str = "", types: str = "", sort: str = "", period: str = "", base_models: list[str] | None = None, nsfw: bool | None = None, limit: int = 20, @@ -68,8 +144,9 @@ class CivitaiClient: params['favorites'] = 'true' r = self._get('/models', params=params, token=token) if r.status_code != 200: - log.error(f'CivitAI search: code={r.status_code} reason={getattr(r, "reason", "")}') - return CivitSearchResponse() + message = response_message(r) + log.error(f'CivitAI search: code={r.status_code} message="{message}"') + return CivitSearchResponse(error=message) data = r.json() if 'items' not in data: # single model by numeric query — wrap in search response @@ -82,7 +159,7 @@ class CivitaiClient: response = CivitSearchResponse.parse_obj(data) except Exception as e: log.error(f'CivitAI search parse error: {e}') - return CivitSearchResponse() + return CivitSearchResponse(error='search response could not be parsed') # /models rejects server-side level filtering and its nsfw boolean leaks # Mature+ content, so filter on each model's aggregate nsfwLevel here: # nsfw on keeps every level, nsfw off/unset keeps SFW (None + Soft). @@ -94,7 +171,7 @@ class CivitaiClient: def get_model(self, model_id: int, *, token: str | None = None) -> CivitModel | None: r = self._get(f'/models/{model_id}', token=token) if r.status_code != 200: - log.error(f'CivitAI get model: id={model_id} code={r.status_code}') + log.error(f'CivitAI get model: id={model_id} code={r.status_code} message="{response_message(r)}"') return None try: return CivitModel.parse_obj(r.json()) @@ -105,7 +182,7 @@ class CivitaiClient: def get_version(self, version_id: int, *, token: str | None = None) -> CivitVersion | None: r = self._get(f'/model-versions/{version_id}', token=token) if r.status_code != 200: - log.error(f'CivitAI get version: id={version_id} code={r.status_code}') + log.error(f'CivitAI get version: id={version_id} code={r.status_code} message="{response_message(r)}"') return None try: return CivitVersion.parse_obj(r.json()) @@ -116,6 +193,8 @@ class CivitaiClient: def get_version_by_hash(self, hash_str: str, *, token: str | None = None) -> CivitVersion | None: r = self._get(f'/model-versions/by-hash/{hash_str}', token=token) if r.status_code != 200: + if r.status_code != 404: + log.error(f'CivitAI get version by hash: hash={hash_str} code={r.status_code} message="{response_message(r)}"') return None try: return CivitVersion.parse_obj(r.json()) @@ -123,6 +202,70 @@ class CivitaiClient: log.error(f'CivitAI get version by hash parse error: hash={hash_str} {e}') return None + def get_version_mini(self, version_id: int, *, token: str | None = None) -> CivitVersionMini | None: + r = self._get(f'/model-versions/mini/{version_id}', token=token) + if r.status_code != 200: + log.error(f'CivitAI get version mini: id={version_id} code={r.status_code} message="{response_message(r)}"') + return None + try: + return CivitVersionMini.parse_obj(r.json()) + except Exception as e: + log.error(f'CivitAI get version mini parse error: id={version_id} {e}') + return None + + def get_version_ids_by_hash(self, hashes: list[str], *, token: str | None = None) -> tuple[list[dict], dict[str, int]]: + """{modelVersionId, modelId, hash} rows for SHA256 hashes, plus the status code for each hash whose request failed.""" + rows, failed = [], {} + for i in range(0, len(hashes), BY_HASH_IDS_LIMIT): + chunk = hashes[i:i + BY_HASH_IDS_LIMIT] + r = self.send('POST', '/model-versions/by-hash/ids', body=chunk, token=token) + if r.status_code != 200: + log.error(f'CivitAI version ids by hash: count={len(chunk)} code={r.status_code} message="{response_message(r)}"') + failed.update(dict.fromkeys(chunk, r.status_code)) + continue + try: + rows.extend(r.json()) + except Exception as e: + log.error(f'CivitAI version ids by hash parse error: count={len(chunk)} {e}') + failed.update(dict.fromkeys(chunk, 500)) + return rows, failed + + def get_versions_by_hash(self, hashes: list[str], *, token: str | None = None) -> tuple[list[CivitVersion], dict[str, int]]: + """Full versions for SHA256 hashes, plus the status code for each hash whose request failed.""" + versions, failed = [], {} + for i in range(0, len(hashes), BY_HASH_LIMIT): + chunk = hashes[i:i + BY_HASH_LIMIT] + r = self.send('POST', '/model-versions/by-hash', body=chunk, token=token) + if r.status_code != 200: + log.error(f'CivitAI versions by hash: count={len(chunk)} code={r.status_code} message="{response_message(r)}"') + failed.update(dict.fromkeys(chunk, r.status_code)) + continue + try: + versions.extend([CivitVersion.parse_obj(v) for v in r.json()]) + except Exception as e: + log.error(f'CivitAI versions by hash parse error: count={len(chunk)} {e}') + failed.update(dict.fromkeys(chunk, 500)) + return versions, failed + + def get_models_raw(self, model_ids: list[int], *, token: str | None = None) -> tuple[dict[int, dict], dict[int, int]]: + """Unparsed /models items keyed by id, plus the status code for each id whose request failed.""" + models, failed = {}, {} + for i in range(0, len(model_ids), MODEL_IDS_LIMIT): + chunk = model_ids[i:i + MODEL_IDS_LIMIT] + params = {'ids': ','.join(str(m) for m in chunk), 'limit': MODEL_IDS_LIMIT, 'nsfw': 'true'} # ids query drops NSFW models unless nsfw=true + r = self.send('GET', '/models', params=params, token=token) + if r.status_code != 200: + log.error(f'CivitAI models by id: count={len(chunk)} code={r.status_code} message="{response_message(r)}"') + failed.update(dict.fromkeys(chunk, r.status_code)) + continue + try: + for item in r.json().get('items', []): + models[item['id']] = item + except Exception as e: + log.error(f'CivitAI models by id parse error: count={len(chunk)} {e}') + failed.update(dict.fromkeys(chunk, 500)) + return models, failed + def get_images(self, *, model_version_id: int | None = None, limit: int | None = None, token: str | None = None) -> list[CivitImage]: params: dict = {} if model_version_id is not None: @@ -131,6 +274,7 @@ class CivitaiClient: params['limit'] = limit r = self._get('/images', params=params, token=token) if r.status_code != 200: + log.error(f'CivitAI get images: code={r.status_code} message="{response_message(r)}"') return [] data = r.json() items = data.get('items', []) @@ -152,6 +296,7 @@ class CivitaiClient: params['limit'] = limit r = self._get('/images', params=params, token=token) if r.status_code != 200: + log.error(f'CivitAI get images: code={r.status_code} message="{response_message(r)}"') return [] data = r.json() return data.get('items', []) @@ -166,6 +311,7 @@ class CivitaiClient: params['page'] = page r = self._get('/tags', params=params) if r.status_code != 200: + log.error(f'CivitAI get tags: code={r.status_code} message="{response_message(r)}"') return CivitTagResponse() try: return CivitTagResponse.parse_obj(r.json()) @@ -183,6 +329,7 @@ class CivitaiClient: params['page'] = page r = self._get('/creators', params=params) if r.status_code != 200: + log.error(f'CivitAI get creators: code={r.status_code} message="{response_message(r)}"') return CivitCreatorResponse() try: return CivitCreatorResponse.parse_obj(r.json()) @@ -193,6 +340,8 @@ class CivitaiClient: def get_me(self, token: str | None = None) -> CivitUserProfile | None: r = self._get('/me', token=token) if r.status_code != 200: + if r.status_code != 401: + log.error(f'CivitAI get me: code={r.status_code} message="{response_message(r)}"') return None try: return CivitUserProfile.parse_obj(r.json()) @@ -211,7 +360,7 @@ class CivitaiClient: """Civitai enum lists (ModelType, ModelFileType, BaseModel, ActiveBaseModel, BaseModelType). Public endpoint.""" r = self._get('/enums') if r.status_code != 200: - log.debug(f'CivitAI enums: code={r.status_code}') + log.debug(f'CivitAI enums: code={r.status_code} message="{response_message(r)}"') return {} try: return r.json() @@ -255,11 +404,10 @@ class CivitaiClient: if not isinstance(error, dict): continue # Parse ZodError: error.message is a JSON-encoded array of issues - import json as _json issues = error.get('issues', []) if not issues: try: - issues = _json.loads(error.get('message', '[]')) + issues = json.loads(error.get('message', '[]')) except Exception: issues = [] for issue in issues: @@ -287,20 +435,15 @@ class CivitaiClient: break except Exception as e: log.debug(f'CivitAI discover options: key={key} {e}') - # Enrich base-model names with github metadata (group/hidden/ecosystem). - # github also serves as the name-list fallback when both /enums and the - # probe came back empty. - github_entries = fetch_github_base_models() - github_index: dict = {entry['name']: entry for entry in github_entries} - if not result['base_models'] and github_entries: - result['base_models'] = [entry['name'] for entry in github_entries] + # hidden marks names in BaseModel but not in ActiveBaseModel, the retired set; an empty ActiveBaseModel hides nothing + active = set(enums.get('ActiveBaseModel', []) or []) result['base_models_info'] = [ - github_index.get(name, {'name': name, 'type': 'image', 'group': '', 'hidden': False}) + {'name': name, 'type': 'image', 'group': '', 'hidden': bool(active) and name not in active} for name in result['base_models'] ] options_cache = result options_cache_time = now - log.debug(f'CivitAI options: types={len(result["types"])} sort={len(result["sort"])} period={len(result["period"])} base_models={len(result["base_models"])} (enriched={len(github_index)})') + log.debug(f'CivitAI options: types={len(result["types"])} sort={len(result["sort"])} period={len(result["period"])} base_models={len(result["base_models"])} active={len(active)}') return result diff --git a/modules/civitai/download_civitai.py b/modules/civitai/download_civitai.py index 833270f4c..d28a6a179 100644 --- a/modules/civitai/download_civitai.py +++ b/modules/civitai/download_civitai.py @@ -28,7 +28,7 @@ class DownloadItem: token: str | None = None model_id: int = 0 version_id: int = 0 - status: str = "queued" # queued | downloading | verifying | completed | failed | cancelled + status: str = "queued" # queued | downloading | completed | failed | cancelled progress: float = 0.0 bytes_downloaded: int = 0 bytes_total: int = 0 @@ -167,7 +167,7 @@ class DownloadManager: # Create temp file name from URL hash url_hash = hashlib.sha256(item.url.encode('utf-8')).hexdigest()[:8] temp_file = os.path.join(item.folder, f'{url_hash}.tmp') - final_file = os.path.join(item.folder, item.filename) + final_file = os.path.abspath(os.path.join(item.folder, item.filename)) # Check if already exists if os.path.isfile(final_file): @@ -195,13 +195,17 @@ class DownloadManager: item.status = "downloading" item.bytes_downloaded = starting_pos + digest = hashlib.sha256() try: r = shared.req(item.url, headers=headers if headers else None, stream=True) if r.status_code not in (200, 206): + from modules.civitai.client_civitai import response_message + reason = response_message(r) item.status = "failed" - item.error = f'HTTP {r.status_code}' + item.error = f'HTTP {r.status_code}: {reason}' if reason else f'HTTP {r.status_code}' item.completed_at = datetime.now() + log.error(f'CivitAI download refused: id={item.id} file="{item.filename}" code={r.status_code} message="{reason}"') return # A text/* response is an error or login page served with HTTP 200, @@ -211,7 +215,7 @@ class DownloadManager: item.status = "failed" item.error = f'invalid content-type: {content_type}' item.completed_at = datetime.now() - log.warning(f'CivitAI download invalid content-type: id={item.id} content-type="{content_type}"') + log.warning(f'CivitAI download invalid content-type: id={item.id} file="{item.filename}" content-type="{content_type}"') return # A 200 reply to a Range request means the server ignored the range @@ -222,6 +226,10 @@ class DownloadManager: starting_pos = 0 item.bytes_downloaded = 0 os.truncate(temp_file, 0) + if starting_pos > 0: # a resumed download's digest must include the partial already on disk + with open(temp_file, 'rb') as partial: + for block in iter(lambda: partial.read(1024 * 1024), b''): + digest.update(block) total_size = int(r.headers.get('content-length', 0)) item.bytes_total = starting_pos + total_size @@ -255,6 +263,7 @@ class DownloadManager: return f.write(chunk) + digest.update(chunk) written += len(chunk) item.bytes_downloaded = written if item.bytes_total > 0: @@ -270,7 +279,7 @@ class DownloadManager: item.status = "failed" item.error = f'incomplete: expected={expected} got={written}' item.completed_at = datetime.now() - log.warning(f'CivitAI download incomplete: id={item.id} expected={expected} got={written}') + log.warning(f'CivitAI download incomplete: id={item.id} file="{item.filename}" expected={expected} got={written}') return elif written < 1024: try: @@ -287,30 +296,22 @@ class DownloadManager: item.status = "failed" item.error = str(e) item.completed_at = datetime.now() - log.error(f'CivitAI download error: id={item.id} {e}') + log.error(f'CivitAI download error: id={item.id} file="{item.filename}" {e}') return - # Hash verification - if item.expected_hash: - item.status = "verifying" - try: - from modules import hashes - computed = hashes.calculate_sha256(temp_file, quiet=True) - if computed.upper() != item.expected_hash.upper(): - discard = getattr(shared.opts, 'civitai_discard_hash_mismatch', True) - if discard: - try: - os.remove(temp_file) - except OSError: - pass - item.status = "failed" - item.error = f'hash mismatch: expected={item.expected_hash[:16]}... got={computed[:16]}...' - item.completed_at = datetime.now() - log.error(f'CivitAI download hash mismatch: id={item.id} expected={item.expected_hash[:16]} got={computed[:16]}') - return - log.warning(f'CivitAI download hash mismatch (kept): id={item.id} expected={item.expected_hash[:16]} got={computed[:16]}') - except Exception as e: - log.warning(f'CivitAI download hash check failed: id={item.id} {e}') + computed = digest.hexdigest() + if item.expected_hash and computed != item.expected_hash.lower(): + if getattr(shared.opts, 'civitai_discard_hash_mismatch', True): + try: + os.remove(temp_file) + except OSError: + pass + item.status = "failed" + item.error = f'hash mismatch: expected={item.expected_hash[:16]}... got={computed[:16]}...' + item.completed_at = datetime.now() + log.error(f'CivitAI download hash mismatch: id={item.id} expected={item.expected_hash[:16]} got={computed[:16]}') + return + log.warning(f'CivitAI download hash mismatch (kept): id={item.id} expected={item.expected_hash[:16]} got={computed[:16]}') # Move temp to final try: @@ -319,6 +320,7 @@ class DownloadManager: item.status = "failed" item.error = f'rename failed: {e}' item.completed_at = datetime.now() + log.error(f'CivitAI download rename failed: id={item.id} file="{final_file}" {e}') return item.status = "completed" @@ -326,28 +328,25 @@ class DownloadManager: item.completed_at = datetime.now() log.info(f'CivitAI download complete: id={item.id} file="{final_file}" size={item.bytes_downloaded}') - # Write verified hash to cache so check-local finds it immediately - if item.expected_hash: - try: - from modules import hashes - model_type_map = {'Checkpoint': 'checkpoint', 'LORA': 'lora', 'TextualInversion': 'embedding', 'VAE': 'vae'} - prefix = model_type_map.get(item.model_type, item.model_type.lower()) - name = os.path.splitext(item.filename)[0] - title = f"{prefix}/{name}" - hashes.cache().add_hash(title, os.path.getmtime(final_file), item.expected_hash.lower()) + # the declared hash is cached even on a kept mismatch: it is what CivitAI knows the file by + try: + from modules import hashes + from modules.civitai.filemanage_civitai import loader_kind, hash_cache_title + title = hash_cache_title(loader_kind(final_file), final_file) + if title is not None: + hashes.cache().add_hash(title, os.path.getmtime(final_file), (item.expected_hash or computed).lower()) hashes.save_cache() - except Exception: - pass + except Exception as e: + log.warning(f'CivitAI download hash cache: id={item.id} {e}') # Download metadata and preview self._fetch_sidecar(item, final_file) - # Refresh model list and extra-networks cache try: - from modules.sd_models import list_models - list_models() - except Exception: - pass + from modules.civitai.filemanage_civitai import register_download + register_download(final_file) + except Exception as e: + log.warning(f'CivitAI download register: id={item.id} {e}') try: from modules.api.loras import _invalidate_extra_networks _invalidate_extra_networks() @@ -372,9 +371,9 @@ class DownloadManager: if version and version.images: for img in version.images: if img.url: - code, _size, _note = download_civit_preview(final_file, img.url, meta=img.meta) + code, _size, note = download_civit_preview(final_file, img.url, meta=img.meta) if code == 200: - log.info(f'CivitAI preview saved: id={item.id}') + log.info(f'CivitAI preview saved: id={item.id} file="{note}"') break if code == 304 and backfill_preview_parameters(final_file, img.url, img.meta): log.info(f'CivitAI preview backfilled: id={item.id}') @@ -672,7 +671,7 @@ def backfill_preview_parameters(model_path: str, preview_url: str, meta: dict | ext = os.path.splitext(preview_url)[1].lower() base = os.path.splitext(model_path)[0] if ext in VIDEO_PREVIEW_EXTENSIONS: - if not os.path.exists(base + ext): + if not any(os.path.exists(base + e) for e in VIDEO_PREVIEW_EXTENSIONS): return False preview_file = base + '.thumb.jpg' if not os.path.exists(preview_file): @@ -694,6 +693,13 @@ def backfill_preview_parameters(model_path: str, preview_url: str, meta: dict | # ---- Legacy compatibility functions ---- +def save_civit_meta(model_path: str, data: dict) -> str: + from modules.json_helpers import writefile + fn = os.path.splitext(model_path)[0] + '.json' + writefile(data, filename=fn, mode='w', silent=True) + return fn + + def download_civit_meta(model_path: str, model_id): fn = os.path.splitext(model_path)[0] + '.json' url = f'https://civitai.com/api/v1/models/{model_id}' @@ -701,8 +707,7 @@ def download_civit_meta(model_path: str, model_id): if r.status_code == 200: try: data = r.json() - from modules.json_helpers import writefile - writefile(data, filename=fn, mode='w', silent=True) + save_civit_meta(model_path, data) log.info(f'CivitAI download: id={model_id} url={url} file="{fn}"') return r.status_code, len(data), '' except Exception as e: @@ -713,65 +718,108 @@ def download_civit_meta(model_path: str, model_id): return r.status_code, '', '' +VIDEO_CONTENT_TYPES = {'video/mp4': '.mp4', 'video/webm': '.webm'} + + +def transcoded_video_url(preview_url: str) -> str | None: + """The CDN's H.264 copy of a CivitAI video, or None for any other URL.""" + if '/original=true/' not in preview_url: + return None + return preview_url.replace('/original=true/', '/transcode=true,width=450/', 1) + + def download_civit_preview(model_path: str, preview_url: str, meta: dict | None = None): + """Save the preview behind preview_url beside model_path; on 200 the note is the file the UI shows.""" if model_path is None: return 500, '', '' - ext = os.path.splitext(preview_url)[1] - preview_file = os.path.splitext(model_path)[0] + ext - is_video = preview_file.lower().endswith(VIDEO_PREVIEW_EXTENSIONS) - is_json = preview_file.lower().endswith('.json') - if is_json: + ext = os.path.splitext(preview_url)[1].lower() + base = os.path.splitext(model_path)[0] + if ext == '.json': log.warning(f'CivitAI download: url="{preview_url}" skip json') return 500, '', 'expected preview image got json' - if os.path.exists(preview_file): - return 304, '', 'already exists' - r = shared.req(preview_url, stream=True) - total_size = int(r.headers.get('content-length', 0)) - block_size = 16384 - written = 0 + is_video = ext in VIDEO_PREVIEW_EXTENSIONS + if is_video: + if any(os.path.exists(base + e) for e in VIDEO_PREVIEW_EXTENSIONS): + return 304, '', 'already exists' + candidates = [url for url in (transcoded_video_url(preview_url), preview_url) if url] # the original may be AV1, which OpenCV builds without dav1d cannot decode + else: + if os.path.exists(base + ext): + return 304, '', 'already exists' + candidates = [preview_url] jobid = shared.state.begin('Download CivitAI') try: - with open(preview_file, 'wb') as f: - for data in r.iter_content(block_size): - written += len(data) - f.write(data) - if written < 1024: - os.remove(preview_file) - return 400, '', 'removed invalid download' - if is_video: - from modules.civitai.video_helper import save_video_frame - save_video_frame(preview_file) - if meta: - thumb_file = os.path.splitext(preview_file)[0] + '.thumb.jpg' - if os.path.exists(thumb_file): - try: - parameters = civitai_meta_to_parameters(meta) - if parameters and embed_preview_parameters(thumb_file, parameters): - log.debug(f'CivitAI preview embed: file="{thumb_file}"') - except Exception as e: - log.debug(f'CivitAI preview embed skipped: file="{thumb_file}" {e}') - else: - from PIL import Image - img = Image.open(preview_file) - log.info(f'CivitAI download: url={preview_url} file="{preview_file}" size={total_size} image={img.size}') - img.close() + for url in candidates: + r = shared.req(url, stream=True) + headers = getattr(r, 'headers', None) or {} + if r.status_code != 200: + log.warning(f'CivitAI preview: url="{url}" code={r.status_code}') + continue + if is_video: + content_type = headers.get('content-type', '').split(';')[0].strip().lower() + file_ext = VIDEO_CONTENT_TYPES.get(content_type) + if file_ext is None: + log.warning(f'CivitAI preview: url="{url}" content-type="{content_type}" not a video') + continue + preview_file = base + file_ext # named by content; the URL says .mp4 for webm originals + else: + preview_file = base + ext + total_size = int(headers.get('content-length', 0)) + written = 0 + with open(preview_file, 'wb') as f: + for data in r.iter_content(16384): + written += len(data) + f.write(data) + if written < 1024: + os.remove(preview_file) + log.warning(f'CivitAI preview: url="{url}" file="{preview_file}" removed invalid download') + continue + if is_video: + from modules.civitai.video_helper import save_video_frame + thumb_file = base + '.thumb.jpg' + if save_video_frame(preview_file) is None or not os.path.exists(thumb_file): + os.remove(preview_file) + continue + log.info(f'CivitAI download: url={url} file="{preview_file}" size={total_size} thumb="{thumb_file}"') + shown = thumb_file + else: + from PIL import Image + img = Image.open(preview_file) + log.info(f'CivitAI download: url={url} file="{preview_file}" size={total_size} image={img.size}') + img.close() + shown = preview_file if meta: try: parameters = civitai_meta_to_parameters(meta) - if parameters and embed_preview_parameters(preview_file, parameters): - log.debug(f'CivitAI preview embed: file="{preview_file}"') + if parameters and embed_preview_parameters(shown, parameters): + log.debug(f'CivitAI preview embed: file="{shown}"') except Exception as e: - log.debug(f'CivitAI preview embed skipped: file="{preview_file}" {e}') + log.debug(f'CivitAI preview embed skipped: file="{shown}" {e}') + return 200, str(total_size), shown + return 415, '', 'no usable preview' except Exception as e: - log.error(f'CivitAI download error: url={preview_url} file="{preview_file}" written={written} {e}') - shared.state.end(jobid) + log.error(f'CivitAI preview error: url={preview_url} file="{base}" {e}') return 500, '', str(e) - shared.state.end(jobid) - return 200, str(total_size), '' + finally: + shared.state.end(jobid) + + +def declared_sha256(version_id: int, url: str, filename: str, token: str | None = None) -> str: + """SHA256 CivitAI declares for the version file behind url, matched by download URL, then by file name.""" + if not version_id: + return '' + from modules.civitai.client_civitai import client + version = client.get_version(version_id, token=token) + if version is None: + return '' + for matches in (lambda f: f.download_url == url, lambda f: f.name == filename): + for f in version.files: + if f.hashes.sha256 and matches(f): + return f.hashes.sha256.lower() + return '' def download_civit_model(model_url: str, model_name: str = '', model_path: str = '', model_type: str = '', token: str | None = None, - base_model: str = '', model_id: int = 0, version_id: int = 0): + base_model: str = '', model_id: int = 0, version_id: int = 0, expected_hash: str = ''): """Legacy function — delegates to DownloadManager for non-blocking downloads.""" if not model_url: log.error('Model download: no url provided') @@ -791,20 +839,20 @@ def download_civit_model(model_url: str, model_name: str = '', model_path: str = folder = model_path else: folder = os.path.join(paths.models_path, model_path) + expected_hash = expected_hash or declared_sha256(version_id, model_url, model_name, token=token) item = download_manager.enqueue( url=model_url, folder=folder, filename=model_name or "Unknown", model_type=model_type, + expected_hash=expected_hash, token=token, model_id=model_id, version_id=version_id, ) # Wait for completion (legacy blocking behavior) - while item.status in ("queued", "downloading", "verifying"): + while item.status in ("queued", "downloading"): time.sleep(0.5) if item.status == "completed" and not item.error: - from modules.sd_models import list_models - list_models() return os.path.join(item.folder, item.filename) return None diff --git a/modules/civitai/filemanage_civitai.py b/modules/civitai/filemanage_civitai.py index a7372942e..0c710434e 100644 --- a/modules/civitai/filemanage_civitai.py +++ b/modules/civitai/filemanage_civitai.py @@ -5,11 +5,16 @@ from modules.logger import log # Map CivitAI model types to shared.opts directory settings and fallback subfolder -# names. 'Text Encoder' is a file type, not a model type: versions bundle companion -# files, and clients route those by the file's own type. +# names. 'Text Encoder' is the file type of bundled companion files, 'TextEncoder' +# the model type. Types absent here land in Stable-diffusion. TYPE_MAP = { 'Checkpoint': ('ckpt_dir', 'Stable-diffusion'), 'Text Encoder': ('te_dir', 'Text-encoder'), + 'TextEncoder': ('te_dir', 'Text-encoder'), + 'UNet': ('unet_dir', 'UNET'), + 'CLIP': ('clip_models_path', 'CLIP'), + 'CLIPVision': ('clip_models_path', 'CLIP'), + 'Detection': ('yolo_dir', 'yolo'), 'TextualInversion': ('embeddings_dir', 'embeddings'), 'Hypernetwork': ('hypernetwork_dir', 'hypernetworks'), 'AestheticGradient': ('ckpt_dir', 'Stable-diffusion'), @@ -26,6 +31,9 @@ TYPE_MAP = { 'Other': ('ckpt_dir', 'Stable-diffusion'), } +# unmapped types already logged; one warning each per session +warned_types: set[str] = set() + # CivitAI has no type for a standalone transformer, so DiT finetunes ship as # 'Checkpoint' like full models. Bases listed here are full checkpoints and stay # in Stable-diffusion; any other base is transformer-only in practice and routes @@ -53,6 +61,9 @@ def get_type_folder(model_type: str, base_model: str = '') -> Path: return Path(paths.models_path) / custom[model_type] except Exception as e: log.warning(f'CivitAI type folder override parse error: {e}') + if model_type not in TYPE_MAP and model_type not in warned_types: + warned_types.add(model_type) + log.warning(f'CivitAI type unmapped: type="{model_type}" folder="Stable-diffusion"') opt_attr, fallback_dir = TYPE_MAP.get(model_type, ('ckpt_dir', 'Stable-diffusion')) if model_type == 'Checkpoint' and base_model and not is_full_checkpoint_base(base_model): opt_attr, fallback_dir = 'unet_dir', 'UNET' @@ -82,6 +93,142 @@ def iter_type_roots() -> set[Path]: return {r for r in roots if r.is_dir()} +def path_under(filename: str, root: str | None) -> bool: + if not root: + return False + root = os.path.normcase(os.path.abspath(root)).rstrip(os.sep) + os.sep + return os.path.normcase(os.path.abspath(filename)).startswith(root) + + +def loader_kind(filename: str) -> str | None: + """Model loader that lists this file, judged by the folder it is in.""" + from modules import shared, paths + ckpt_roots = (getattr(shared.opts, 'ckpt_dir', ''), os.path.join(paths.models_path, 'Stable-diffusion')) + if path_under(filename, getattr(shared.opts, 'vae_dir', '')) or path_under(filename, os.path.join(paths.models_path, 'VAE')): + return 'vae' + if filename.endswith('.vae.safetensors') and any(path_under(filename, root) for root in ckpt_roots): + return 'vae' + if path_under(filename, getattr(shared.opts, 'unet_dir', '')): + return 'unet' + if path_under(filename, getattr(shared.cmd_opts, 'lora_dir', '')): + return 'lora' + if any(path_under(filename, root) for root in ckpt_roots): + return 'checkpoint' + return None + + +def register_download(filename: str): + """Add a finished download to its loader's list: one file for lora, a folder scan for unet, vae and checkpoint.""" + kind = loader_kind(filename) + if kind == 'lora': + from modules.lora.lora_load import add_network + add_network(filename) + elif kind == 'unet': + from modules.sd_unet import refresh_unet_list + refresh_unet_list() + elif kind == 'vae': + from modules.sd_vae import refresh_vae_list + refresh_vae_list() + elif kind == 'checkpoint': + from modules.sd_models import list_models + list_models() + + +def hash_cache_title(kind: str | None, filename: str, name: str | None = None) -> str | None: + """Hash cache key the loader of kind reads for filename, or None when it keeps none.""" + from modules import shared, paths + basename = os.path.basename(filename) + stem = os.path.splitext(basename)[0] + if kind == 'lora': # lora_load registers the basename with dots replaced + return 'lora/' + stem.replace('.', '_') + if kind == 'unet': # sd_unet keeps the extension on anything but safetensors + return f"unet/{name or (stem if '.safetensors' in basename else basename)}" + if kind == 'vae': + return f'vae/{os.path.abspath(filename)}' + if kind == 'checkpoint': + if name is None: # CheckpointInfo matches the folder by string prefix, then drops the extension + relname = filename + ckpt_dir = getattr(shared.opts, 'ckpt_dir', '') or '' + model_path = os.path.abspath(os.path.join(paths.models_path, 'Stable-diffusion')) + if ckpt_dir and relname.startswith(ckpt_dir): + relname = os.path.relpath(filename, ckpt_dir) + elif relname.startswith(model_path): + relname = os.path.relpath(filename, model_path) + name = os.path.splitext(relname)[0] + return f'checkpoint/{name}' + return None + + +hash_cache_pruned = False + + +def loader_root(kind: str) -> str | None: + """Folder the loader of kind lists, or None for a kind no loader owns.""" + from modules import shared, paths + if kind == 'vae': + return getattr(shared.opts, 'vae_dir', '') or os.path.join(paths.models_path, 'VAE') + if kind == 'unet': + return getattr(shared.opts, 'unet_dir', '') + if kind == 'lora': + return getattr(shared.cmd_opts, 'lora_dir', '') + if kind == 'checkpoint': + return getattr(shared.opts, 'ckpt_dir', '') or os.path.join(paths.models_path, 'Stable-diffusion') + return None + + +def loader_registry(kind: str) -> dict[str, str] | None: + """Name to path map of the loader that reads the kind's hash cache keys, or None for a kind no loader owns.""" + if kind == 'vae': + from modules.sd_vae import vae_dict + return vae_dict + if kind == 'unet': + from modules.sd_unet import unet_dict + return unet_dict + if kind == 'lora': + from modules.lora.lora_load import available_networks + return {name: entry.filename for name, entry in available_networks.items()} + if kind == 'checkpoint': + from modules.sd_checkpoint import checkpoints_list + return {entry.name: entry.filename for entry in checkpoints_list.values()} + return None + + +def hash_cache_path(title: str) -> str | None: + """Path the loader registry holds for a hash cache key, or None when no loaded registry names it.""" + kind, _, name = title.partition('/') + if kind == 'vae' and os.path.isabs(name): + return name + registry = loader_registry(kind) + return registry.get(name) if registry else None + + +def hash_cache_stale(title: str) -> bool: + """True when the key's loader folder is reachable but the registry no longer lists the file, or lists a path that is gone.""" + kind, _, name = title.partition('/') + if kind == 'vae' and os.path.isabs(name): + return os.path.isdir(os.path.dirname(name)) and not os.path.exists(name) + root = loader_root(kind) + if not root or not os.path.isdir(root): + return False + path = (loader_registry(kind) or {}).get(name) + return path is None or not os.path.exists(path) + + +def prune_hash_cache(): + """Drop hash cache entries for files that are gone, once per process.""" + global hash_cache_pruned # pylint: disable=global-statement + if hash_cache_pruned: + return + hash_cache_pruned = True + from modules import hashes + gone = [title for title in list(hashes.cache()) if hash_cache_stale(title)] + for title in gone: + hashes.cache().pop(title, None) + if gone: + hashes.save_cache() + log.info(f'CivitAI hash cache: pruned={len(gone)} entries without files') + + def resolve_save_path(model_type: str, model_name: str = "", base_model: str = "", nsfw: bool = False, creator: str = "", model_id: int = 0, version_id: int = 0, version_name: str = "") -> Path: @@ -107,7 +254,7 @@ def resolve_save_path(model_type: str, model_name: str = "", base_model: str = " for key, value in replacements.items(): subfolder = subfolder.replace(key, value) # Clean up empty path segments - subfolder = re.sub(r'[/\\]+', os.sep, subfolder) + subfolder = re.sub(r'[/\\]+', lambda _match: os.sep, subfolder) # callable repl: a string repl reads the Windows backslash as an escape subfolder = subfolder.strip(os.sep) return base_folder / subfolder diff --git a/modules/civitai/metadata_civitai.py b/modules/civitai/metadata_civitai.py index 88f50a1da..1b132f162 100644 --- a/modules/civitai/metadata_civitai.py +++ b/modules/civitai/metadata_civitai.py @@ -1,8 +1,19 @@ import os import re import time -from modules.shared import log, opts, readfile, max_workers +import threading +import concurrent.futures +from modules.shared import log, opts, max_workers, state, cmd_opts from modules.civitai.client_civitai import client +from modules.civitai.filemanage_civitai import hash_cache_title + + +GIB = 1024 ** 3 +sweep_lock = threading.Lock() + + +class SweepBusy(Exception): + """A metadata sweep was started while another one was running.""" class CivitModel: @@ -24,6 +35,98 @@ class CivitModel: self.status = 'Not found' +PAGE_KINDS = {'model': 'checkpoint', 'lora': 'lora', 'unet/dit': 'unet', 'vae': 'vae'} + + +def cache_title(page: str, item: dict) -> str | None: + """Hash cache key read by the page's own loader, or None when it keeps no cache entry.""" + kind = PAGE_KINDS.get(page) + return hash_cache_title(kind, item.get('filename') or '', name=item.get('name') if kind in ('checkpoint', 'unet') else None) + + +def resolve_sha256(entries: list[tuple[str, dict]], size_limit: int | None = None) -> tuple[dict[str, str], dict[str, str]]: + """File SHA256 per filename plus a note per unresolved file, from the default hash store or by hashing files below size_limit. + + The hashes-addnet store and sshs_model_hash are kohya tensor hashes, which CivitAI never matches. + """ + from modules import hashes + resolved, notes, todo, seen = {}, {}, [], set() + for page, item in entries: + fn = item.get('filename') or '' + if fn in seen or not os.path.isfile(fn): + continue + seen.add(fn) + title = cache_title(page, item) + sha = hashes.sha256_from_cache(fn, title) if title else None + if sha: + resolved[fn] = sha.lower() + elif size_limit is not None and os.path.getsize(fn) >= size_limit: + notes[fn] = f'not hashed: {size_limit // GIB} GiB or larger' + else: + todo.append((fn, title)) + if len(todo) == 0: + return resolved, notes + if cmd_opts.no_hashing: + log.warning(f'CivitAI metadata: unhashed={len(todo)} hashing disabled') + notes.update({fn: 'not hashed: hashing disabled' for fn, _title in todo}) + return resolved, notes + + def hash_file(fn: str) -> str | None: + return None if state.interrupted else hashes.calculate_sha256(fn, quiet=True) + + log.info(f'CivitAI metadata: hashing files={len(todo)} size={sum(os.path.getsize(fn) for fn, _title in todo) / GIB:.1f}GB') + jobid = state.begin('CivitAI hash') + state.job_count = len(todo) + cached = 0 + try: + with concurrent.futures.ThreadPoolExecutor(max_workers=max_workers) as executor: + futures = {executor.submit(hash_file, fn): (fn, title) for fn, title in todo} + for future in concurrent.futures.as_completed(futures): + fn, title = futures[future] + state.job_no += 1 + state.textinfo = os.path.basename(fn) + try: + sha = future.result() + except Exception as e: + log.error(f'CivitAI metadata hash: file="{fn}" {e}') + notes[fn] = 'not hashed: unreadable' + continue + if sha is None: + notes[fn] = 'not hashed: interrupted' + continue + resolved[fn] = sha.lower() + if title is not None: + hashes.cache().add_hash(title, os.path.getmtime(fn), resolved[fn]) + cached += 1 + finally: + if cached > 0: + hashes.save_cache() + state.end(jobid) + return resolved, notes + + +def apply_update_status(model: CivitModel, sha: str, versions: list[dict], local_hashes: set[str]): + if len(versions) == 0: + return + model.latest = versions[0].get('name', '') + latest_hashes = {str((f.get('hashes') or {}).get('SHA256', '')).upper() for f in versions[0].get('files', [])} - {''} + model.latest_hashes = sorted(latest_hashes) + for ver in versions: + for f in ver.get('files', []): + if str((f.get('hashes') or {}).get('SHA256', '')).upper() != sha.upper(): + continue + model.vername = ver.get('name', '') + model.url = f.get('downloadUrl', None) + model.latest_name = f.get('name', '') + if model.vername == model.latest: + model.status = 'Latest version' + elif len(local_hashes & latest_hashes) > 0: + model.status = 'Update downloaded' + else: + model.status = 'Update available' + return + + def civit_update_metadata(raw: bool = False): def create_update_metadata_table(rows: list[CivitModel]): html = """ @@ -54,132 +157,81 @@ def civit_update_metadata(raw: bool = False): log.error(f'Model list: row={row} {e}') return html.format(tbody=tbody) - log.debug('CivitAI update metadata: models') - from modules import ui_extra_networks - from modules.civitai.download_civitai import download_civit_meta - pages = ui_extra_networks.get_pages('Model') - if len(pages) == 0: - return 'CivitAI update metadata: no models found' - page: ui_extra_networks.ExtraNetworksPage = pages[0] - results = [] - all_hashes = [(item.get('hash', None) or 'XXXXXXXX').upper()[:8] for item in page.list_items()] - for item in page.list_items(): - model = CivitModel(name=item['name'], fn=item['filename'], sha=item.get('hash', None), meta=item.get('metadata', {})) - if model.sha is None or len(model.sha) == 0: - log.debug(f'CivitAI skip search: name="{model.name}" hash=None') - else: - version = client.get_version_by_hash(model.sha) - if version is not None: - model.id = version.model_id - download_civit_meta(model.fn, model.id) - fn = os.path.splitext(item['filename'])[0] + '.json' - model.meta = readfile(fn, silent=True, as_type="dict") - model.name = model.meta.get('name', model.name) - model.versions = len(model.meta.get('modelVersions', [])) - time.sleep(0.25) # rate limiting - versions = model.meta.get('modelVersions', []) - if len(versions) > 0: - model.latest = versions[0].get('name', '') - model.latest_hashes.clear() - for v in versions[0].get('files', []): - for h in v.get('hashes', {}).values(): - model.latest_hashes.append(h[:8].upper()) - for ver in versions: - for f in ver.get('files', []): - for h in f.get('hashes', {}).values(): - if h[:8].upper() == model.sha[:8].upper(): - model.vername = ver.get('name', '') - model.url = f.get('downloadUrl', None) - model.latest_name = f.get('name', '') - if model.vername == model.latest: - model.status = 'Latest version' - elif any(map(lambda v: v in model.latest_hashes, all_hashes)): # pylint: disable=cell-var-from-loop - model.status = 'Update downloaded' - else: - model.status = 'Update available' - break - results.append(model) - yield results if raw else create_update_metadata_table(results) - yield results if raw else create_update_metadata_table(results) - - -def atomic_civit_search_metadata(item, results): - from modules.civitai.download_civitai import download_civit_preview, download_civit_meta, backfill_preview_parameters, preview_has_parameters, resolve_preview_file - if item is None: + if not sweep_lock.acquire(blocking=False): # pylint: disable=consider-using-with + log.warning('CivitAI update metadata: another metadata sweep is running') + if raw: + raise SweepBusy('CivitAI metadata sweep already running') + yield 'CivitAI update metadata: another metadata sweep is running' return try: - meta = os.path.splitext(item['filename'])[0] + '.json' - except Exception: - return - has_meta = os.path.isfile(meta) and os.stat(meta).st_size > 0 - needs_backfill = False - if has_meta and 'missing.png' not in item.get('preview', ''): - actual_preview = resolve_preview_file(item) - if actual_preview and not preview_has_parameters(actual_preview): - needs_backfill = True - if ('missing.png' in item['preview'] or not has_meta or needs_backfill) and os.path.isfile(item['filename']): - sha = item.get('hash', None) - found = False - result = { - 'id': '', - 'name': item['name'], - 'type': '', - 'hash': '', - 'code': '', - 'size': '', - 'note': '', - } - if sha is not None and len(sha) > 0: - version = client.get_version_by_hash(sha) - result['hash'] = sha - if version is not None: - result['code'] = 200 - result['code'], result['size'], result['note'] = download_civit_meta(item['filename'], version.model_id) - result['id'] = version.model_id - result['type'] = 'metadata' - # Create a new dict for each append to avoid mutation bugs - results.append(dict(result)) - for img in version.images: - if img.url: - code, size, note = download_civit_preview(item['filename'], img.url, meta=img.meta) - if code == 200: - results.append({**result, 'code': code, 'size': size, 'note': note, 'type': 'preview'}) - found = True - break - if code == 304 and backfill_preview_parameters(item['filename'], img.url, img.meta): - results.append({**result, 'code': 200, 'size': '', 'note': 'metadata embedded', 'type': 'preview'}) - found = True - break - else: - result['code'] = 404 - time.sleep(0.25) # rate limiting - if not found and os.stat(item['filename']).st_size < (1024 * 1024 * 1024): - from modules import hashes - sha = hashes.calculate_sha256(item['filename'], quiet=True)[:10] - version = client.get_version_by_hash(sha) - result['hash'] = sha - if version is not None: - result['code'] = 200 - result['code'], result['size'], result['note'] = download_civit_meta(item['filename'], version.model_id) - result['id'] = version.model_id - result['type'] = 'metadata' - results.append(dict(result)) - for img in version.images: - if img.url: - code, size, note = download_civit_preview(item['filename'], img.url, meta=img.meta) - if code == 200: - results.append({**result, 'code': code, 'size': size, 'note': note, 'type': 'preview'}) - found = True - break - if code == 304 and backfill_preview_parameters(item['filename'], img.url, img.meta): - results.append({**result, 'code': 200, 'size': '', 'note': 'metadata embedded', 'type': 'preview'}) - found = True - break - else: - result['code'] = 404 - time.sleep(0.25) # rate limiting - if not found: - results.append(dict(result)) + log.debug('CivitAI update metadata: models') + from modules import ui_extra_networks + from modules.civitai.download_civitai import save_civit_meta + pages = ui_extra_networks.get_pages('Model') + if len(pages) == 0: + yield [] if raw else 'CivitAI update metadata: no models found' + return + items = [item for item in pages[0].list_items() if item is not None] + shas, notes = resolve_sha256([('model', item) for item in items]) + rows, failed = client.get_version_ids_by_hash(sorted(set(shas.values()))) + by_hash = {} + for row in rows: # one hash can match several versions; GET /by-hash/{hash} returns the first + by_hash.setdefault(str(row.get('hash', '')).lower(), row) + metas, failed_models = client.get_models_raw(sorted({row['modelId'] for row in by_hash.values() if row.get('modelId')})) + local_hashes = {sha.upper() for sha in shas.values()} + results = [] + for item in items: + fn = item['filename'] + sha = shas.get(fn) + model = CivitModel(name=item['name'], fn=fn, sha=sha[:10] if sha else item.get('hash', None)) + if sha is None: + model.status = 'Not hashed' if fn in notes else 'Not found' + elif sha in failed: + model.status = 'Lookup failed' + elif sha in by_hash: + model.id = by_hash[sha]['modelId'] + meta = metas.get(model.id) + if meta is None: + model.status = 'Lookup failed' if model.id in failed_models else 'Not found' + else: + meta_fn = save_civit_meta(fn, meta) + log.info(f'CivitAI download: id={model.id} file="{meta_fn}"') + model.meta = meta + model.name = meta.get('name', model.name) + model.versions = len(meta.get('modelVersions', [])) + apply_update_status(model, sha, meta.get('modelVersions', []), local_hashes) + results.append(model) + yield results if raw else create_update_metadata_table(results) + yield results if raw else create_update_metadata_table(results) + finally: + sweep_lock.release() + + +def needs_metadata(item: dict) -> bool: + """True when the item's file exists and it lacks a sidecar, a preview, or preview parameters.""" + from modules.civitai.download_civitai import preview_has_parameters, resolve_preview_file + filename = item.get('filename') or '' + if not os.path.isfile(filename): + return False + meta = os.path.splitext(filename)[0] + '.json' + if 'missing.png' in (item.get('preview') or '') or not (os.path.isfile(meta) and os.stat(meta).st_size > 0): + return True + actual_preview = resolve_preview_file(item) + return bool(actual_preview) and not preview_has_parameters(actual_preview) + + +def download_previews(fn: str, version, result: dict) -> list[dict]: + """Preview row for the first version image that downloads or gains embedded parameters.""" + from modules.civitai.download_civitai import download_civit_preview, backfill_preview_parameters + for img in version.images: + if not img.url: + continue + code, size, note = download_civit_preview(fn, img.url, meta=img.meta) + if code == 200: + return [{**result, 'code': code, 'size': size, 'note': note, 'type': 'preview'}] + if code == 304 and backfill_preview_parameters(fn, img.url, img.meta): + return [{**result, 'code': 200, 'size': '', 'note': 'metadata embedded', 'type': 'preview'}] + return [] def civit_search_metadata(title: str | None = None, raw: bool = False): @@ -208,36 +260,74 @@ def civit_search_metadata(title: str | None = None, raw: bool = False): log.error(f'Model list: row={row} {e}') return html.format(tbody=tbody) - from modules.ui_extra_networks import get_pages - results = [] - scanned, skipped = 0, 0 - t0 = time.time() - candidates = [] - re_skip = [r.strip() for r in opts.extra_networks_scan_skip.split(',') if len(r.strip()) > 0] - for page in get_pages(): - if isinstance(title, str): - if page.title.lower() != title.lower(): + if not sweep_lock.acquire(blocking=False): # pylint: disable=consider-using-with + log.warning('CivitAI search metadata: another metadata sweep is running') + if raw: + raise SweepBusy('CivitAI metadata sweep already running') + yield 'CivitAI search metadata: another metadata sweep is running' + return + try: + from modules.ui_extra_networks import get_pages + from modules.civitai.download_civitai import save_civit_meta + results = [] + scanned, skipped = 0, 0 + t0 = time.time() + entries = [] + re_skip = [r.strip() for r in opts.extra_networks_scan_skip.split(',') if len(r.strip()) > 0] + for page in get_pages(): + if isinstance(title, str) and page.title.lower() != title.lower(): continue - if page.name in ('style', 'wildcards'): - continue - for item in page.list_items(): - if item is None: + if page.name in ('style', 'wildcards'): continue - if any(re.search(re_str, item.get('name', '') + item.get('filename', '')) for re_str in re_skip): - skipped += 1 + for item in page.list_items(): + if item is None: + continue + if any(re.search(re_str, item.get('name', '') + item.get('filename', '')) for re_str in re_skip): + skipped += 1 + continue + scanned += 1 + entries.append((page.name, item)) + log.debug(f'CivitAI search metadata: type={title if isinstance(title, str) else "all"} workers={max_workers} skip={len(re_skip)} items={len(entries)}') + with concurrent.futures.ThreadPoolExecutor(max_workers=max_workers) as executor: + flags = list(executor.map(lambda entry: needs_metadata(entry[1]), entries)) + entries = [entry for entry, flag in zip(entries, flags) if flag] + shas, notes = resolve_sha256(entries, size_limit=GIB) + versions, failed = client.get_versions_by_hash(sorted(set(shas.values()))) + by_hash = {} + for version in versions: # one hash can match several versions; GET /by-hash/{hash} returns the first + for f in version.files: + if f.hashes.sha256: + by_hash.setdefault(f.hashes.sha256.lower(), version) + matched = {} + for _page, item in entries: + fn = item['filename'] + sha = shas.get(fn) + result = {'id': '', 'name': item['name'], 'type': '', 'hash': sha[:10] if sha else '', 'code': '', 'size': '', 'note': notes.get(fn, '')} + if sha is None: + results.append(result) + elif sha in failed: + results.append({**result, 'code': failed[sha], 'note': 'lookup failed'}) + elif sha not in by_hash: + results.append({**result, 'code': 404}) + else: + matched[fn] = (by_hash[sha], {**result, 'id': by_hash[sha].model_id}) + metas, failed_models = client.get_models_raw(sorted({version.model_id for version, _result in matched.values()})) + for fn, (version, result) in matched.items(): + meta = metas.get(version.model_id) + if meta is None: + results.append({**result, 'type': 'metadata', 'code': failed_models.get(version.model_id, 404)}) continue - scanned += 1 - candidates.append(item) - log.debug(f'CivitAI search metadata: type={title if isinstance(title, str) else "all"} workers={max_workers} skip={len(re_skip)} items={len(candidates)}') - import concurrent.futures - with concurrent.futures.ThreadPoolExecutor(max_workers=max_workers) as executor: - future_items = {} - for candidate in candidates: - future_items[executor.submit(atomic_civit_search_metadata, candidate, results)] = candidate - for future in concurrent.futures.as_completed(future_items): - future.result() - yield results if raw else create_search_metadata_table(results) - - t1 = time.time() - log.debug(f'CivitAI search metadata: scanned={scanned} skipped={skipped} time={t1 - t0:.2f}') - yield results if raw else create_search_metadata_table(results) + meta_fn = save_civit_meta(fn, meta) + log.info(f'CivitAI download: id={version.model_id} file="{meta_fn}"') + results.append({**result, 'type': 'metadata', 'code': 200, 'size': len(meta)}) + yield results if raw else create_search_metadata_table(results) + with concurrent.futures.ThreadPoolExecutor(max_workers=max_workers) as executor: + futures = [executor.submit(download_previews, fn, version, result) for fn, (version, result) in matched.items()] + for future in concurrent.futures.as_completed(futures): + results.extend(future.result()) + yield results if raw else create_search_metadata_table(results) + t1 = time.time() + log.debug(f'CivitAI search metadata: scanned={scanned} skipped={skipped} pending={len(entries)} hashed={len(shas)} matched={len(matched)} time={t1 - t0:.2f}') + yield results if raw else create_search_metadata_table(results) + finally: + sweep_lock.release() diff --git a/modules/civitai/models_civitai.py b/modules/civitai/models_civitai.py index e709e659f..3a31e0005 100644 --- a/modules/civitai/models_civitai.py +++ b/modules/civitai/models_civitai.py @@ -23,6 +23,7 @@ class CivitFileHashes(BaseModel): autov3: str | None = Field(None, alias="AutoV3") crc32: str | None = Field(None, alias="CRC32") blake3: str | None = Field(None, alias="BLAKE3") + sha256_12: str | None = Field(None, alias="SHA256_12") class CivitFileMetadata(BaseModel): @@ -51,15 +52,14 @@ class CivitFile(BaseModel): class CivitStats(BaseModel): + # counts CivitAI does not report arrive as null, not zero class Config: allow_population_by_field_name = True - download_count: int = Field(0, alias="downloadCount") - favorite_count: int = Field(0, alias="favoriteCount") - thumb_up_count: int = Field(0, alias="thumbsUpCount") - thumb_down_count: int = Field(0, alias="thumbsDownCount") - comment_count: int = Field(0, alias="commentCount") - rating_count: int = Field(0, alias="ratingCount") - rating: float = 0 + download_count: int | None = Field(0, alias="downloadCount") + thumb_up_count: int | None = Field(0, alias="thumbsUpCount") + thumb_down_count: int | None = Field(0, alias="thumbsDownCount") + comment_count: int | None = Field(0, alias="commentCount") + tipped_amount_count: int | None = Field(0, alias="tippedAmountCount") class CivitVersion(BaseModel): @@ -89,6 +89,36 @@ class CivitVersion(BaseModel): return "Unknown" if v in (None, "") else v +class CivitVersionMini(BaseModel): + # primary file flattened onto the version plus permission flags; earlyAccessEndsAt and freeTrialLimit exist only during early access + class Config: + allow_population_by_field_name = True + air: str = "" + version_name: str = Field("", alias="versionName") + model_name: str = Field("", alias="modelName") + user_id: int = Field(0, alias="userId") + base_model: str = Field("Unknown", alias="baseModel") + availability: str = "Unknown" + published_at: str | None = Field(None, alias="publishedAt") + size: float = 0 + file_type: str = Field("", alias="fileType") + file_name: str = Field("", alias="fileName") + format: str = "" + hashes: CivitFileHashes = Field(default_factory=CivitFileHashes) + download_urls: list[str] = Field(default_factory=list, alias="downloadUrls") + can_generate: bool = Field(False, alias="canGenerate") + is_featured: bool = Field(False, alias="isFeatured") + require_auth: bool = Field(False, alias="requireAuth") + check_permission: bool = Field(False, alias="checkPermission") + additional_resource_charge: bool = Field(False, alias="additionalResourceCharge") + payout_enabled: bool = Field(False, alias="payoutEnabled") + minor: bool = False + sfw_only: bool = Field(False, alias="sfwOnly") + fees: list = Field(default_factory=list) + early_access_ends_at: str | None = Field(None, alias="earlyAccessEndsAt") + free_trial_limit: int | None = Field(None, alias="freeTrialLimit") + + class CivitCreator(BaseModel): class Config: allow_population_by_field_name = True @@ -158,6 +188,7 @@ class CivitSearchResponse(BaseModel): items: list[CivitModel] = Field(default_factory=list) metadata: CivitSearchMetadata = Field(default_factory=CivitSearchMetadata) request_url: str | None = Field(None, alias="requestUrl") + error: str | None = None # server or parse failure text; items is empty when set class CivitTag(BaseModel): @@ -192,9 +223,12 @@ class CivitCreatorResponse(BaseModel): class CivitUserProfile(BaseModel): + # tier is omitted for non-members; email, emailVerified and tokenScope are left unmodelled to keep the address out of the API response class Config: allow_population_by_field_name = True id: int = 0 username: str = "" - image: str | None = None - profile_picture: str | None = Field(None, alias="profilePicture") + tier: str | None = None + status: str | None = None + is_member: bool = Field(False, alias="isMember") + subscriptions: list = Field(default_factory=list) diff --git a/modules/civitai/search_civitai.py b/modules/civitai/search_civitai.py index 6c4fd99dc..65653de56 100644 --- a/modules/civitai/search_civitai.py +++ b/modules/civitai/search_civitai.py @@ -1,14 +1,11 @@ import re import time +from html import escape from installer import log from modules.civitai.client_civitai import client from modules.civitai.models_civitai import CivitModel, CivitSearchResponse -# Hardcoded fallback list — used by Gradio UI if discover_options() fails -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'] - - def search_civitai( query: str, tag: str = '', @@ -20,10 +17,10 @@ def search_civitai( base: str = '', token: str | None = None, exact: bool = True, -) -> list[CivitModel]: +) -> CivitSearchResponse: if not query and not tag and not sort: log.error('CivitAI: no search criteria provided') - return [] + return CivitSearchResponse(error='no search criteria provided') t0 = time.time() @@ -39,8 +36,8 @@ def search_civitai( if model: t1 = time.time() log.info(f'CivitAI result: id={query} time={t1 - t0:.2f}') - return [model] - return [] + return CivitSearchResponse(items=[model]) + return CivitSearchResponse(error=f'model {query} not found') response: CivitSearchResponse = client.search_models( query=query, @@ -65,17 +62,20 @@ def search_civitai( if any(q_lower in name for name in names): exact_models.append(model) - result = exact_models if exact_models else all_models + response.items = exact_models if exact_models else all_models t1 = time.time() log.info(f'CivitAI result: exact={len(exact_models)} total={len(all_models)} time={t1 - t0:.2f}') - return result + return response -def create_model_cards(all_models: list[CivitModel]) -> str: - details = """ -
-
- """ +def create_model_cards(response: CivitSearchResponse) -> str: + if response.error: + notice = f'CivitAI: {escape(response.error)}' + elif not response.items: + notice = 'No models found' + else: + notice = '' + details = f'
{notice}
' cards = """
{cards} @@ -89,7 +89,7 @@ def create_model_cards(all_models: list[CivitModel]) -> str:
""" all_cards = '' - for model in all_models: + for model in response.items: previews = [] for version in model.versions: for image in version.images: diff --git a/modules/control/proc/hed.py b/modules/control/proc/hed.py index 06610921e..fb04e24fe 100644 --- a/modules/control/proc/hed.py +++ b/modules/control/proc/hed.py @@ -102,8 +102,8 @@ class HEDdetector: if scribble: detected_map = nms(detected_map, 127, 3.0) detected_map = cv2.GaussianBlur(detected_map, (0, 0), 3.0) - detected_map[detected_map > 4] = 255 - detected_map[detected_map < 255] = 0 + detected_map[detected_map > 4] = 255 # pylint: disable=unsupported-assignment-operation + detected_map[detected_map < 255] = 0 # pylint: disable=unsupported-assignment-operation if opts.control_move_processor: self.model.to('cpu') if output_type == "pil": diff --git a/modules/control/run.py b/modules/control/run.py index f5dae8c2b..83b6bb483 100644 --- a/modules/control/run.py +++ b/modules/control/run.py @@ -350,9 +350,8 @@ def control_run(state: str = '', # pylint: disable=keyword-arg-before-vararg styles: list[str] | None = None, steps: int = 20, sampler_index: int | None = None, seed: int = -1, subseed: int = -1, subseed_strength: float = 0, seed_resize_from_h: int = -1, seed_resize_from_w: int = -1, - guidance_name: str = 'Default', guidance_scale: float = 6.0, guidance_rescale: float = 0.0, guidance_start: float = 0.0, guidance_stop: float = 1.0, - cfg_scale: float = 6.0, clip_skip: float = 1.0, cfg_image: float = 6.0, cfg_rescale: float = 0.7, cfg_true: float = 0.0, cfg_adaptive: float = 0.5, cfg_end: float = 1.0, - vae_type: str = 'Full', tiling: bool = False, hidiffusion: bool = False, + cfg_name: str = 'Default', cfg_scale: float = 6.0, cfg_image: float = 6.0, cfg_rescale: float = 0.0, cfg_start: float = 0.0, cfg_stop: float = 1.0, cfg_true: float = 0.0, cfg_adaptive: float = 0.5, + clip_skip: float = 1.0, vae_type: str = 'Full', tiling: bool = False, hidiffusion: bool = False, detailer_enabled: bool = False, detailer_prompt: str = '', detailer_negative: str = '', detailer_steps: int = 10, detailer_strength: float = 0.3, detailer_resolution: int = 1024, detailer_classes: str = '', hdr_mode: int = 0, hdr_brightness: float = 0, hdr_color: float = 0, hdr_sharpen: float = 0, hdr_clamp: bool = False, hdr_boundary: float = 4.0, hdr_threshold: float = 0.95, hdr_maximize: bool = False, hdr_max_center: float = 0.6, hdr_max_boundary: float = 1.0, hdr_color_picker: str | None = None, hdr_tint_ratio: float = 0, hdr_apply_hires: bool = True, @@ -403,7 +402,7 @@ def control_run(state: str = '', # pylint: disable=keyword-arg-before-vararg sequential_seed: bool | None = None, # prompt/attention overrides prompt_attention: str | None = None, prompt_mean_norm: bool | None = None, diffusers_zeros_prompt_pad: bool | None = None, - te_pooled_embeds: bool | None = None, lora_apply_te: bool | None = None, te_complex_human_instruction: str | None = None, te_use_mask: bool | None = None, + te_pooled_embeds: bool | None = None, te_complex_human_instruction: str | None = None, te_use_mask: bool | None = None, # generation modifier overrides (hijack) freeu_enabled: bool | None = None, freeu_b1: float | None = None, freeu_b2: float | None = None, freeu_s1: float | None = None, freeu_s2: float | None = None, hypertile_unet_enabled: bool | None = None, hypertile_hires_only: bool | None = None, hypertile_unet_tile: int | None = None, hypertile_unet_min_tile: int | None = None, @@ -445,7 +444,7 @@ def control_run(state: str = '', # pylint: disable=keyword-arg-before-vararg if sampler_index is None: log.warning('Sampler: invalid') sampler_index = 0 - if hr_sampler_index is None: + if hr_sampler_index is None or hr_sampler_index == 'Same as primary': hr_sampler_index = sampler_index if isinstance(extra, list): extra = create_override_settings_dict(extra) @@ -465,21 +464,17 @@ def control_run(state: str = '', # pylint: disable=keyword-arg-before-vararg seed_resize_from_w = seed_resize_from_w, denoising_strength = denoising_strength, skip_processing = skip_processing, - # modular guidance - guidance_name = guidance_name, - guidance_scale = guidance_scale, - guidance_rescale = guidance_rescale, - guidance_start = guidance_start, - guidance_stop = guidance_stop, - # legacy guidance + # guidance + cfg_name = cfg_name, cfg_scale = cfg_scale, - cfg_end = cfg_end, - clip_skip = clip_skip, cfg_image = cfg_image, cfg_rescale = cfg_rescale, + cfg_start = cfg_start, + cfg_stop = cfg_stop, cfg_true = cfg_true, cfg_adaptive = cfg_adaptive, # advanced + clip_skip = clip_skip, vae_type = vae_type, tiling = tiling, hidiffusion = hidiffusion, @@ -586,7 +581,7 @@ def control_run(state: str = '', # pylint: disable=keyword-arg-before-vararg # prompt/attention overrides prompt_attention=prompt_attention, prompt_mean_norm=prompt_mean_norm, diffusers_zeros_prompt_pad=diffusers_zeros_prompt_pad, te_pooled_embeds=te_pooled_embeds, - lora_apply_te=lora_apply_te, te_complex_human_instruction=te_complex_human_instruction, te_use_mask=te_use_mask, + te_complex_human_instruction=te_complex_human_instruction, te_use_mask=te_use_mask, # generation modifier overrides (hijack) freeu_enabled=freeu_enabled, freeu_b1=freeu_b1, freeu_b2=freeu_b2, freeu_s1=freeu_s1, freeu_s2=freeu_s2, hypertile_unet_enabled=hypertile_unet_enabled, hypertile_hires_only=hypertile_hires_only, @@ -852,7 +847,7 @@ def control_run(state: str = '', # pylint: disable=keyword-arg-before-vararg debug_log(f'Ready: {image_txt}') html_txt = f'

Ready {image_txt}

' if image_txt != '' else '' - if len(info_txt) > 0: + if (info_txt is not None) and (len(info_txt) > 0): html_txt = html_txt + infotext_to_html(info_txt[0]) result = (output_images, blended_image, html_txt, output_filename) if is_generator: diff --git a/modules/detailer/detailer.py b/modules/detailer/detailer.py index 752e9fbdc..10cb1c999 100644 --- a/modules/detailer/detailer.py +++ b/modules/detailer/detailer.py @@ -1,4 +1,5 @@ import re +import time from copy import copy import numpy as np import gradio as gr @@ -220,6 +221,19 @@ class Detailer(): matched_negative_classes = set() for i, model_val in enumerate(models): + if shared.state.skipped: + shared.state.skipped = False + continue + if shared.state.interrupted: + break + while shared.state.paused: + log.debug('Detail paused') + if shared.state.interrupted: + break + if shared.state.skipped: + continue + time.sleep(0.1) + if ':' in model_val: model_name, model_args = model_val.split(':', 1) else: @@ -309,10 +323,23 @@ class Detailer(): resolved_prompts = assign_prompts(prompt, items) resolved_negatives = assign_prompts(negative, items) for j, item in enumerate(items): + if shared.state.skipped: + shared.state.skipped = False + continue + if shared.state.interrupted: + break + while shared.state.paused: + log.debug('Detail paused') + if shared.state.interrupted: + break + if shared.state.skipped: + continue + time.sleep(0.1) if item.mask is None: continue - pc.keep_prompts = True + shared.sd_model.fail_on_switch_error = True + pc.keep_prompts = True pc.prompt = resolved_prompts[j] pc.negative_prompt = resolved_negatives[j] pc.prompts = [pc.prompt] @@ -321,7 +348,7 @@ class Detailer(): pc.disable_extra_networks = True # disable processing_diffusers from handling network activation since its handled here network_same = len(p.network_data.values()) == len(pc.network_data.values()) and all(x == y for x, y in zip(p.network_data.values(), pc.network_data.values())) if not network_same: - extra_networks.activate_filtered(pc, pc.network_data) + extra_networks.activate(pc, pc.network_data) log.debug(f'Detail: model="{i+1}:{name}" item={j+1}/{len(items)} box={item.box} label="{item.label}" score={item.score:.2f} seg={detailer_opt(p, "detailer_segmentation")} network={network_same} prompt="{pc.prompt}"') pc.init_images = [image] pc.image_mask = [item.mask] @@ -510,12 +537,12 @@ class Detailer(): renoise_end = gr.Slider(minimum=0.0, maximum=1.0, step=0.01, label='Renoise end', value=shared.opts.detailer_sigma_adjust_max, elem_id=f"{tab}_detailer_renoise_end") sampler_block = None if tab == 'extras': # fold the standalone sampler settings into the detailer accordion; values applied per-job in make_processing, never global opts - from modules import sd_samplers - sd_samplers.set_samplers() - sampler_choices = [s.name for s in sd_samplers.visible_samplers() if s.name != 'Same as primary'] + from modules import ui_sections + sampler_choices, default_value, filtered = ui_sections.sampler_choices() with gr.Accordion('Sampler', open=False, elem_id=f"{tab}_detailer_sampler_accordion", elem_classes=["small-accordion"]): with gr.Row(): - d_sampler = gr.Dropdown(label='Sampling method', choices=sampler_choices, value='Default', elem_id=f"{tab}_detailer_sampler") + ui_sections.create_filter_indicator(tab, 'Sampler', filtered) + d_sampler = gr.Dropdown(label='Sampling method', choices=sampler_choices, value=default_value, type='value', elem_id=f"{tab}_detailer_sampler") d_prediction = gr.Dropdown(label='Prediction method', choices=['default', 'epsilon', 'sample', 'v_prediction', 'flow_prediction'], value='default', elem_id=f"{tab}_detailer_prediction") with gr.Row(): d_shift = gr.Slider(label='Flow shift', minimum=0, maximum=10, step=0.1, value=shared.opts.schedulers_shift, elem_id=f"{tab}_detailer_shift") diff --git a/modules/devices.py b/modules/devices.py index 901014505..42ac70840 100644 --- a/modules/devices.py +++ b/modules/devices.py @@ -493,65 +493,60 @@ def override_ipex_math(): log.warning(f'Torch ipex: {e}') +def report_attention(): + from importlib.metadata import version + try: + flash = version('flash-attn') + except Exception: + flash = False + try: + sage = version('sageattention') + except Exception: + sage = False + try: + xformers = version('xformers') + except Exception: + xformers = False + try: + kernels = version('kernels') + except Exception: + kernels = False + from diffusers.models import attention_dispatch as a + try: + import sdnq + sdnq_ver = sdnq.__version__ + except Exception: + sdnq_ver = False + # log.debug(f'Attention available: flash={a._CAN_USE_FLASH_ATTN} flash3={a._CAN_USE_FLASH_ATTN_3} sage={a._CAN_USE_SAGE_ATTN} flex={a._CAN_USE_FLEX_ATTN} npu={a._CAN_USE_NPU_ATTN} xla={a._CAN_USE_XLA_ATTN} xformers={a._CAN_USE_XFORMERS_ATTN} kernels={a.is_kernels_available()} sdnq=True') # pylint: disable=protected-access + log.debug(f'Attention available: sdnq={sdnq_ver} flash={flash} sage={sage} flex={a._CAN_USE_FLEX_ATTN} xformers={xformers} npu={a._CAN_USE_NPU_ATTN} xla={a._CAN_USE_XLA_ATTN} kernels={kernels}') # pylint: disable=protected-access + + def set_sdpa_params(): try: + global sdpa_original # pylint: disable=global-statement + report = sdpa_original is None try: - global sdpa_original # pylint: disable=global-statement if sdpa_original is not None: torch.nn.functional.scaled_dot_product_attention = sdpa_original else: sdpa_original = torch.nn.functional.scaled_dot_product_attention except Exception as err: - log.warning(f'Torch attention: type="sdpa" {err}') - + log.warning(f'Attention: type="SDPA" {err}') try: + options = {} torch.backends.cuda.enable_flash_sdp('Flash' in opts.sdp_options or 'Flash attention' in opts.sdp_options) torch.backends.cuda.enable_mem_efficient_sdp('Memory' in opts.sdp_options or 'Memory attention' in opts.sdp_options) torch.backends.cuda.enable_math_sdp('Math' in opts.sdp_options or 'Math attention' in opts.sdp_options) if hasattr(torch.backends.cuda, "allow_fp16_bf16_reduction_math_sdp"): # only valid for torch >= 2.5 + options['math'] = 'fp16/bf16' torch.backends.cuda.allow_fp16_bf16_reduction_math_sdp(True) torch_info.set(attention="sdpa") - log.debug(f'Torch attention: type="sdpa" kernels={opts.sdp_options} overrides={opts.sdp_overrides}') + log.debug(f'Attention: type="SDPA" kernels={opts.sdp_options} options={options}') except Exception as err: - log.warning(f'Torch attention: type="sdpa" {err}') - - # Stack hijcaks in reverse order. This gives priority to the last added hijack. - # If the last hijack is not compatible, it will use the one before it and so on. - - if 'Dynamic attention' in opts.sdp_overrides: - global sdpa_pre_dyanmic_atten # pylint: disable=global-statement - sdpa_pre_dyanmic_atten = attention.set_dynamic_attention() - - if 'Flex attention' in opts.sdp_overrides: - attention.set_flex_attention() - - if 'Triton Flash attention' in opts.sdp_overrides: - attention.set_triton_flash_attention(backend) - - if 'Flash attention' in opts.sdp_overrides: - attention.set_ck_flash_attention(backend, device) - - if 'Sage attention' in opts.sdp_overrides: - attention.set_sage_attention(backend, device) - - if 'SDNQ attention' in opts.sdp_overrides: - attention.set_sdnq_attention() - - from importlib.metadata import version - try: - flash = version('flash-attn') - except Exception: - flash = False - try: - sage = version('sageattention') - except Exception: - sage = False - if flash or sage: - log.debug(f'Torch attention installed: flashattn={flash} sageattention={sage}') - - from diffusers.models import attention_dispatch as a - log.debug(f'Torch attention available: flash={a._CAN_USE_FLASH_ATTN} flash3={a._CAN_USE_FLASH_ATTN_3} sage={a._CAN_USE_SAGE_ATTN} flex={a._CAN_USE_FLEX_ATTN} npu={a._CAN_USE_NPU_ATTN} xla={a._CAN_USE_XLA_ATTN} xformers={a._CAN_USE_XFORMERS_ATTN} kernels={a.is_kernels_available()} sdnq=True') # pylint: disable=protected-access - + log.warning(f'Attention: type="SDPA" {err}') + attention.install_router([opts.cross_attention_optimization], attention.Platform(backend=backend, device=device), sdpa_original) + if report: + report_attention() except Exception as e: log.warning(f'Torch SDPA: {e}') diff --git a/modules/extensions.py b/modules/extensions.py index b93fe7f81..420adfc68 100644 --- a/modules/extensions.py +++ b/modules/extensions.py @@ -73,22 +73,11 @@ def temp_disable_extensions(): 'sd-extension-nudenet', 'sd-extension-promptgen', ] - disable_themes = [ - 'sd-webui-lobe-theme', - 'cozy-nest', - 'sdnext-modernui', - ] disabled = [] - if shared.cmd_opts.theme is not None: - theme_name = shared.cmd_opts.theme - else: - theme_name = f'{shared.opts.theme_type.lower()}/{shared.opts.gradio_theme}' - if theme_name == 'lobe': - disable_themes.remove('sd-webui-lobe-theme') - elif theme_name == 'cozy-nest' or theme_name == 'cozy': - disable_themes.remove('cozy-nest') - elif '/' not in theme_name: # set default themes per type - if theme_name == 'standard' or theme_name == 'default': + theme_type = shared.cmd_opts.theme if shared.cmd_opts.theme is not None else shared.opts.theme_type + theme_name = f'{theme_type.lower()}/{shared.opts.gradio_theme}' + if '/' not in theme_name: # set default themes per type + if theme_name == 'standard': theme_name = 'standard/black-teal' if theme_name == 'modern': theme_name = 'modern/Default' @@ -97,24 +86,22 @@ def temp_disable_extensions(): if theme_name == 'huggingface': theme_name = 'huggingface/blaaa' - if theme_name.lower().startswith('standard') or theme_name.lower().startswith('default'): + if theme_name.lower().startswith('standard'): shared.opts.data['theme_type'] = 'Standard' shared.opts.data['gradio_theme'] = theme_name[9:] + disabled.append('sdnext-modernui') elif theme_name.lower().startswith('modern'): shared.opts.data['theme_type'] = 'Modern' shared.opts.data['gradio_theme'] = theme_name[7:] - disable_themes.remove('sdnext-modernui') elif theme_name.lower().startswith('huggingface') or theme_name.lower().startswith('gradio') or theme_name.lower().startswith('none'): shared.opts.data['theme_type'] = 'None' shared.opts.data['gradio_theme'] = theme_name + disabled.append('sdnext-modernui') else: log.error(f'UI theme invalid: theme="{theme_name}" available={["standard/*", "modern/*", "none/*"]} fallback="standard/black-teal"') - shared.opts.data['theme_type'] = 'Standard' - shared.opts.data['gradio_theme'] = 'black-teal' + shared.opts.data['theme_type'] = 'Modern' + shared.opts.data['gradio_theme'] = 'Default' - for ext in disable_themes: - if ext.lower() not in shared.opts.disabled_extensions: - disabled.append(ext) if shared.cmd_opts.safe: for ext in disable_safe: if ext.lower() not in shared.opts.disabled_extensions: @@ -271,4 +258,6 @@ def list_extensions(): enabled = dirname.lower() not in disabled_extensions extension = Extension(name=dirname, path=path, enabled=enabled, is_builtin=is_builtin) extensions.append(extension) - log.debug(f'Extensions: disabled={[e.name for e in extensions if not e.enabled]}') + enabled = [e.name for e in extensions if e.enabled] + disabled = [e.name for e in extensions if not e.enabled] + log.debug(f'Extensions: enabled={enabled} disabled={disabled}') diff --git a/modules/extra_networks.py b/modules/extra_networks.py index 0737f68f8..678e21494 100644 --- a/modules/extra_networks.py +++ b/modules/extra_networks.py @@ -121,15 +121,6 @@ def activate(p: StableDiffusionProcessing, extra_network_data: defaultdict[str, p.network_data = extra_network_data -def activate_filtered(p: StableDiffusionProcessing, extra_network_data: defaultdict[str, list[ExtraNetworkParams]] | None = None, step=0): - """activate with text encoder components gated on lora_apply_te; must run before prompt encode so te networks affect embeds""" - apply_te = getattr(p, 'lora_apply_te', None) - if apply_te is None: - apply_te = shared.opts.lora_apply_te - exclude = [] if apply_te else ['text_encoder', 'text_encoder_2', 'text_encoder_3'] - activate(p, extra_network_data, step=step, exclude=exclude) - - def deactivate(p: StableDiffusionProcessing, extra_network_data: defaultdict[str, list[ExtraNetworkParams]] | None = None, force: bool | None = None): """call deactivate for extra networks in extra_network_data in specified order, then call deactivate for all remaining registered networks""" if p.disable_extra_networks: @@ -173,20 +164,24 @@ def parse_prompt(prompt: str | None) -> tuple[str, defaultdict[str, list[ExtraNe return "" updated_prompt = re.sub(re_extra_net, found, prompt) + updated_prompt = updated_prompt.strip(', ') return updated_prompt, res -def parse_prompts(prompts: list[str], extra_data: defaultdict[str, list[ExtraNetworkParams]] | None = None): - updated_prompt_list: list[str] = [] - extra_data = extra_data or defaultdict(list) +def parse_prompts( + prompts: list[str], + extra_data: defaultdict[str, list[ExtraNetworkParams]] | None = None, +): + updated_prompts: list[str] = [] + if extra_data is None: + extra_data = defaultdict(list) for prompt in prompts: updated_prompt, parsed_extra_data = parse_prompt(prompt) - if not extra_data: - extra_data = parsed_extra_data - elif parsed_extra_data: - extra_data = parsed_extra_data - else: - pass - updated_prompt_list.append(updated_prompt) + if parsed_extra_data: + for key, values in parsed_extra_data.items(): + for item in values: + if item not in extra_data[key]: + extra_data[key].append(item) - return updated_prompt_list, extra_data + updated_prompts.append(updated_prompt) + return updated_prompts, extra_data diff --git a/modules/face/faceid.py b/modules/face/faceid.py index 4c63bcd66..b2263d840 100644 --- a/modules/face/faceid.py +++ b/modules/face/faceid.py @@ -216,7 +216,7 @@ def face_id( p.subseeds = p.all_subseeds[n * p.batch_size:(n+1) * p.batch_size] p.prompts, p.network_data = extra_networks.parse_prompts(p.prompts, p.network_data) - extra_networks.activate_filtered(p, p.network_data) + extra_networks.activate(p, p.network_data) ip_model_dict.update({ "prompt": p.prompts[0], "negative_prompt": p.negative_prompts[0], diff --git a/modules/framepack/framepack_api.py b/modules/framepack/framepack_api.py index 9cc2ace1a..74cdbb2f0 100644 --- a/modules/framepack/framepack_api.py +++ b/modules/framepack/framepack_api.py @@ -37,7 +37,6 @@ class ReqFramepack(BaseModel): mp4_opt: str | None = Field(default="crf=16", title="Options", description="Options for the video codec") mp4_ext: str | None = Field(default="mp4", title="Format", description="Format for the video") mp4_interpolate: int | None = Field(default=0, title="Interpolation", description="Interpolation for the video") - attention: str | None = Field(default="Default", title="Attention", description="Attention type for the model") vae_type: str | None = Field(default="Local", title="VAE", description="VAE type for the model") vlm_enhance: bool | None = Field(default=False, title="VLM enhance", description="Enable VLM enhance") vlm_model: str | None = Field(default=None, title="VLM model", description="VLM model to use") @@ -114,7 +113,6 @@ def framepack_post(request: ReqFramepack): mp4_opt=request.mp4_opt, mp4_ext=request.mp4_ext, mp4_interpolate=request.mp4_interpolate, - attention=request.attention, vae_type=request.vae_type, vlm_enhance=request.vlm_enhance, vlm_model=request.vlm_model, diff --git a/modules/framepack/framepack_install.py b/modules/framepack/framepack_install.py index 121b6c680..905010f9d 100644 --- a/modules/framepack/framepack_install.py +++ b/modules/framepack/framepack_install.py @@ -16,17 +16,8 @@ def rename(src:str, dst:str): raise e -def install_requirements(attention:str='SDPA'): +def install_requirements(): install('av') - if attention == 'Xformers': - log.debug('FramePack install: xformers') - install('xformers') - elif attention == 'FlashAttention': - log.debug('FramePack install: flash-attn') - install('flash-attn') - elif attention == 'SageAttention': - log.debug('FramePack install: sageattention') - install('sageattention') def git_clone(git_repo:str, git_dir:str, tmp_dir:str): diff --git a/modules/framepack/framepack_ui.py b/modules/framepack/framepack_ui.py index c9fb51340..c2edbbb0f 100644 --- a/modules/framepack/framepack_ui.py +++ b/modules/framepack/framepack_ui.py @@ -63,7 +63,6 @@ def create_ui(prompt, negative, styles, _overrides, script_inputs, mp4_fps, mp4_ optimized_prompt = gr.Checkbox(label='FP use optimized system prompt', value=True) use_cfgzero = gr.Checkbox(label='FP enable CFGZero', value=False) use_preview = gr.Checkbox(label='FP enable Preview', value=True) - attention = gr.Dropdown(label="FP attention", choices=['Default', 'Xformers', 'FlashAttention', 'SageAttention'], value='Default', type='value') vae_type = gr.Dropdown(label="FP VAE", choices=['Full', 'Tiny', 'Remote'], value='Full', type='value') with gr.Column(elem_id='framepack-output-column', scale=2) as _column_output: @@ -88,7 +87,7 @@ def create_ui(prompt, negative, styles, _overrides, script_inputs, mp4_fps, mp4_ duration.change(fn=change_sections, inputs=[duration, mp4_fps, mp4_interpolate, latent_ws, variant], outputs=[section_html, section_prompt]) mp4_fps.change(fn=change_sections, inputs=[duration, mp4_fps, mp4_interpolate, latent_ws, variant], outputs=[section_html, section_prompt]) mp4_interpolate.change(fn=change_sections, inputs=[duration, mp4_fps, mp4_interpolate, latent_ws, variant], outputs=[section_html, section_prompt]) - btn_load.click(fn=load_model, inputs=[variant, attention], outputs=framepack_outputs) + btn_load.click(fn=load_model, inputs=[variant], outputs=framepack_outputs) btn_unload.click(fn=unload_model, outputs=framepack_outputs) receipe_get.click(fn=framepack_load.get_model, inputs=[], outputs=receipe) receipe_set.click(fn=framepack_load.set_model, inputs=[receipe], outputs=[]) @@ -108,7 +107,7 @@ def create_ui(prompt, negative, styles, _overrides, script_inputs, mp4_fps, mp4_ use_teacache, use_cfgzero, use_preview, mp4_fps, mp4_codec, mp4_sf, mp4_video, mp4_frames, mp4_thumb, mp4_opt, mp4_ext, mp4_interpolate, mp4_scale, mp4_upscaler, - attention, vae_type, variant, + vae_type, variant, vlm_enhance, vlm_model, vlm_system_prompt, ] diff --git a/modules/framepack/framepack_wrappers.py b/modules/framepack/framepack_wrappers.py index 94eb5155d..1ac40aee3 100644 --- a/modules/framepack/framepack_wrappers.py +++ b/modules/framepack/framepack_wrappers.py @@ -91,11 +91,11 @@ def prepare_prompts(p, init_image, prompt:str, section_prompt:str, num_sections: return generated_prompts -def load_model(variant, attention): +def load_model(variant): global loaded_variant # pylint: disable=global-statement if (shared.sd_model_type != 'hunyuanvideo') or (loaded_variant != variant): yield gr.update(), gr.update(), 'Verifying FramePack' - framepack_install.install_requirements(attention) + framepack_install.install_requirements() # framepack_install.git_clone(git_repo=git_repo, git_dir=git_dir, tmp_dir=tmp_dir) # framepack_install.git_update(git_dir=git_dir, git_commit=git_commit) # sys.path.append(git_dir) @@ -114,7 +114,7 @@ def unload_model(): yield gr.update(), gr.update(), 'Model unloaded' -def run_framepack(task_id, _ui_state, init_image, end_image, start_weight, end_weight, vision_weight, prompt, system_prompt, optimized_prompt, section_prompt, negative_prompt, styles, seed, resolution, duration, latent_ws, steps, cfg_scale, cfg_distilled, cfg_rescale, shift, use_teacache, use_cfgzero, use_preview, mp4_fps, mp4_codec, mp4_sf, mp4_video, mp4_frames, mp4_thumb, mp4_opt, mp4_ext, mp4_interpolate, mp4_scale, mp4_upscaler, attention, vae_type, variant, vlm_enhance, vlm_model, vlm_system_prompt, *_args, **_kwargs): +def run_framepack(task_id, _ui_state, init_image, end_image, start_weight, end_weight, vision_weight, prompt, system_prompt, optimized_prompt, section_prompt, negative_prompt, styles, seed, resolution, duration, latent_ws, steps, cfg_scale, cfg_distilled, cfg_rescale, shift, use_teacache, use_cfgzero, use_preview, mp4_fps, mp4_codec, mp4_sf, mp4_video, mp4_frames, mp4_thumb, mp4_opt, mp4_ext, mp4_interpolate, mp4_scale, mp4_upscaler, vae_type, variant, vlm_enhance, vlm_model, vlm_system_prompt, *_args, **_kwargs): variant = variant or 'Bi-Directional' if variant == 'None': log.error('FramePack: no model selected') @@ -137,7 +137,7 @@ def run_framepack(task_id, _ui_state, init_image, end_image, start_weight, end_w with call_queue.get_lock(): progress.start_task(task_id) - yield from load_model(variant, attention) + yield from load_model(variant) if shared.sd_model_type != 'hunyuanvideo': progress.finish_task(task_id) yield gr.update(), gr.update(), 'Model load failed' diff --git a/modules/framepack/pipeline/hunyuan_video_packed.py b/modules/framepack/pipeline/hunyuan_video_packed.py index a5f171b5c..58ae8918a 100644 --- a/modules/framepack/pipeline/hunyuan_video_packed.py +++ b/modules/framepack/pipeline/hunyuan_video_packed.py @@ -74,7 +74,7 @@ def get_cu_seqlens(text_mask, img_len): text_len = text_mask.sum(dim=1) max_len = text_mask.shape[1] + img_len - cu_seqlens = torch.zeros([2 * batch_size + 1], dtype=torch.int32, device="cuda") + cu_seqlens = torch.zeros([2 * batch_size + 1], dtype=torch.int32, device=text_mask.device) for i in range(batch_size): s = text_len[i] + img_len diff --git a/modules/generation_parameters_copypaste.py b/modules/generation_parameters_copypaste.py index 632f3f1aa..f071e2a05 100644 --- a/modules/generation_parameters_copypaste.py +++ b/modules/generation_parameters_copypaste.py @@ -296,6 +296,23 @@ def connect_paste(button, local_paste_fields, input_comp, override_settings_comp res.append(v) applied[key] = v else: + if key in ('Sampler', 'Hires sampler') and isinstance(v, str): + from modules import ui_sections + choices, value, _ = ui_sections.sampler_choices(selected=v, same_as_primary=key == 'Hires sampler') + res.append(gr.update(choices=choices, value=value)) + applied[key] = v + continue + if getattr(output, 'elem_id', '').endswith('_resize_name') and isinstance(v, str): + from modules import modelloader, ui_sections + modelloader.load_upscalers() + choices = [upscaler.name for upscaler in shared.sd_upscalers] + if output.elem_id.startswith(('control_after', 'control_mask')): + choices = [choice for choice in choices if not choice.lower().startswith('latent')] + if v in choices: + choices, _ = ui_sections.upscaler_choices(choices, selected=v) + res.append(gr.update(choices=choices, value=v)) + applied[key] = v + continue if isinstance(v, str) and v.strip() == '' and key in {'Prompt', 'Negative prompt'}: debug(f'Paste skip empty: "{key}"') res.append(gr.update()) diff --git a/modules/gr_hijack.py b/modules/gr_hijack.py index 8b6ac3e08..9b3d3cbee 100644 --- a/modules/gr_hijack.py +++ b/modules/gr_hijack.py @@ -208,13 +208,13 @@ def patch_gradio(): return {"is_generating": False, "data": [], "error": "empty response"} return response except GeneratorExit as e: - log.error(f"Gradio queue: events={len(events)} batch={batch} error: {e}") + log.error(f"Gradio queue: events={len(events)} batch={batch} reason=GeneratorExit {e}") return {"is_generating": False, "data": [None, None, None, None, "cancelled", ""], "error": None} except Exception as e: - log.error(f"Gradio queue: events={len(events)} batch={batch} error: {e}") + log.error(f"Gradio queue: events={len(events)} batch={batch} reason=Exception {e}") raise except BaseException as e: - log.error(f"Gradio queue: events={len(events)} batch={batch} error: {e}") + log.error(f"Gradio queue: events={len(events)} batch={batch} reason=BaseException {e}") raise def wrap_blocks_preprocess_data(self, fn_index: int, inputs: list, state: dict): diff --git a/modules/hashes.py b/modules/hashes.py index 0c6c1021e..d4658c7ae 100644 --- a/modules/hashes.py +++ b/modules/hashes.py @@ -1,5 +1,6 @@ import hashlib import os.path +import threading from collections import defaultdict from typing import Literal, TypeAlias, TypedDict from rich import progress, errors @@ -29,6 +30,7 @@ cache_filename = os.path.join(data_path, "data", "cache.json") progress_ok = True # defaultdict allows for easily using new stores without needing to define them ahead of time _data: defaultdict[str, HashStore] = defaultdict(HashStore) +cache_lock = threading.Lock() def load_cache(): @@ -38,9 +40,9 @@ def load_cache(): def save_cache(): - # Don't include empty hash stores - filtered = filter(lambda item: len(item[1]) > 0, _data.items()) - writefile(dict(filtered), cache_filename) + with cache_lock: # snapshot and write together, so a later save never lands under an earlier snapshot + snapshot = {store: dict(data) for store, data in list(_data.items()) if len(data) > 0} # dict() of a store runs under the GIL, so add_hash from another thread cannot interrupt it + writefile(snapshot, cache_filename) def cache(store: KnownHashStores | str | None = None) -> HashStore: diff --git a/modules/history.py b/modules/history.py index f98fea1b2..797c5a3b2 100644 --- a/modules/history.py +++ b/modules/history.py @@ -36,7 +36,7 @@ class Item: def __str__(self): if self.latent is not None: - return f'Item(ts="{self.name}" ops={self.ops} latent={self.latent.shape} size={self.size})' + return f'Item(ts="{self.name}" ops={self.ops} latent={list(self.latent.shape)} size={self.size})' elif self.images is not None: return f'Item(ts="{self.name}" ops={self.ops} images={len(self.images) if isinstance(self.images, list) else self.images})' else: diff --git a/modules/image/grid.py b/modules/image/grid.py index 455d1c8d1..374fe0ea1 100644 --- a/modules/image/grid.py +++ b/modules/image/grid.py @@ -80,6 +80,7 @@ def image_grid(imgs: list, batch_size=1, rows: int | None = None, cols: int | No for i, img in enumerate(params.imgs): if img is not None: grid.paste(img, box=(i % params.cols * w, i // params.cols * h)) + grid.is_grid = True # flag image as grid return grid except Exception as e: log.error(f'Grid: images={imgs} {e}') @@ -145,15 +146,15 @@ class GridAnnotation: def get_font(fontsize: float): try: - return ImageFont.truetype(shared.opts.font or os.path.join(script_path, "ui", "fonts", "notosans-nerdfont-regular.ttf"), fontsize) + return ImageFont.truetype(shared.opts.font or os.path.join(script_path, "ui", "css", "ubuntu-nerdfont.ttf"), fontsize) except Exception: - return ImageFont.truetype(os.path.join(script_path, "ui", "fonts", "notosans-nerdfont-regular.ttf"), fontsize) + return ImageFont.truetype(os.path.join(script_path, "ui", "css", "ubuntu-nerdfont.ttf"), fontsize) def draw_grid_annotations(im: Image.Image, width: int, height: int, x_texts: list[list[GridAnnotation]], y_texts: list[list[GridAnnotation]], margin=0, title: list[GridAnnotation] | None = None): def wrap(drawing: ImageDraw.ImageDraw, text, font, line_length): lines = [''] - for word in text.split(): + for word in text.split('/\\'): line = f'{lines[-1]} {word}'.strip() if drawing.textlength(line, font=font) <= line_length: lines[-1] = line @@ -161,7 +162,7 @@ def draw_grid_annotations(im: Image.Image, width: int, height: int, x_texts: lis lines.append(word) return lines - def draw_texts(drawing: ImageDraw.ImageDraw, draw_x: float, draw_y: float, lines, initial_fnt: ImageFont.FreeTypeFont, initial_fontsize: int): + def draw_texts(drawing: ImageDraw.ImageDraw, draw_x: float, draw_y: float, lines: list[GridAnnotation], initial_fnt: ImageFont.FreeTypeFont, initial_fontsize: int): for line in lines: font = initial_fnt fontsize = initial_fontsize diff --git a/modules/image/sharpfin.py b/modules/image/sharpfin.py index d8c8ef4e7..dbb1a7ab5 100644 --- a/modules/image/sharpfin.py +++ b/modules/image/sharpfin.py @@ -7,6 +7,7 @@ and Triton GPU acceleration when available. Non-CUDA devices fall back to PIL/torch.nn.functional automatically. """ +import os import sys import torch from PIL import Image @@ -17,6 +18,7 @@ from modules.image.convert import to_tensor, to_pil _sharpfin_checked = False _sharpfin_ok = False _triton_ok = False +debug = log.trace if os.environ.get('SD_PROCESS_DEBUG', None) is not None else lambda *args, **kwargs: None def check_sharpfin(): @@ -104,7 +106,7 @@ def _scale_pil(scale_fn, tensor, out_res, rk, dev, dt, do_linear, src_h, src_w, return scale_fn(tensor, out_res, resize_kernel=rk, device=dev, dtype=dt, do_srgb_conversion=do_linear, use_sparse=True) except Exception: _triton_ok = False - log.info("Sharpfin: Triton sparse disabled, using dense path") + log.debug("Sharpfin: Triton sparse disabled, using dense path") return scale_fn(tensor, out_res, resize_kernel=rk, device=dev, dtype=dt, do_srgb_conversion=do_linear, use_sparse=False) # Mixed axis: split into two single-axis resizes if h > src_h: # H up, W down @@ -115,7 +117,7 @@ def _scale_pil(scale_fn, tensor, out_res, rk, dev, dt, do_linear, src_h, src_w, return scale_fn(intermediate, (h, w), resize_kernel=rk, device=dev, dtype=dt, do_srgb_conversion=do_linear, use_sparse=True) except Exception: _triton_ok = False - log.info("Sharpfin: Triton sparse disabled, using dense path") + log.debug("Sharpfin: Triton sparse disabled, using dense path") return scale_fn(intermediate, (h, w), resize_kernel=rk, device=dev, dtype=dt, do_srgb_conversion=do_linear, use_sparse=False) # H down, W up use_sparse = _want_sparse(dev, rk, True) @@ -125,7 +127,7 @@ def _scale_pil(scale_fn, tensor, out_res, rk, dev, dt, do_linear, src_h, src_w, return scale_fn(intermediate, (h, w), resize_kernel=rk, device=dev, dtype=dt, do_srgb_conversion=do_linear, use_sparse=False) except Exception: _triton_ok = False - log.info("Sharpfin: Triton sparse disabled, using dense path") + log.debug("Sharpfin: Triton sparse disabled, using dense path") intermediate = scale_fn(tensor, (h, src_w), resize_kernel=rk, device=dev, dtype=dt, do_srgb_conversion=do_linear, use_sparse=False) return scale_fn(intermediate, (h, w), resize_kernel=rk, device=dev, dtype=dt, do_srgb_conversion=do_linear, use_sparse=False) @@ -137,24 +139,24 @@ def resize_pil(image: Image.Image, target_size: tuple[int, int], *, kernel=None, is_mask = image.mode == 'L' if (image.width == w) and (image.height == h): - log.debug(f'Resize image: skip={w}x{h} fn={fn}') + # log.debug(f'Resize image: skip={w}x{h} fn={fn}') return image from modules import devices dev = device if device is not None else devices.device if not allow_sharpfin(dev): - log.debug(f'Resize image: method=PIL source={image.width}x{image.height} target={w}x{h} device={dev} fn={fn}') + debug(f'Resize image: method=PIL source={image.width}x{image.height} target={w}x{h} device={dev} fn={fn}') return image.resize((w, h), resample=Image.Resampling.LANCZOS) rk = get_kernel(kernel) if rk is None: - log.debug(f'Resize image: method=PIL source={image.width}x{image.height} target={w}x{h} kernel=None fn={fn}') + debug(f'Resize image: method=PIL source={image.width}x{image.height} target={w}x{h} kernel=None fn={fn}') return image.resize((w, h), resample=Image.Resampling.LANCZOS) from modules.sharpfin.functional import scale dt = dtype or torch.float16 do_linear = get_linearize(linearize, is_mask=is_mask) - log.debug(f'Resize image: method=sharpfin source={image.width}x{image.height} target={w}x{h} kernel={rk} device={dev} linearize={do_linear} fn={fn}') + debug(f'Resize image: method=sharpfin source={image.width}x{image.height} target={w}x{h} kernel={rk} device={dev} linearize={do_linear} fn={fn}') tensor = to_tensor(image) if tensor.dim() == 3: tensor = tensor.unsqueeze(0) @@ -182,14 +184,14 @@ def resize_tensor(tensor: torch.Tensor, target_size: tuple[int, int], *, kernel= dev = devices.device if not allow_sharpfin(dev): mode = 'bilinear' if (target_size[0] * target_size[1]) > (tensor.shape[-2] * tensor.shape[-1]) else 'area' - log.debug(f'Resize tensor: method=torch mode={mode} shape={tensor.shape} target={target_size} fn={fn}') + debug(f'Resize tensor: method=torch mode={mode} shape={tensor.shape} target={target_size} fn={fn}') inp = tensor if tensor.dim() == 4 else tensor.unsqueeze(0) result = torch.nn.functional.interpolate(inp, size=target_size, mode=mode, antialias=mode != 'area') return result.squeeze(0) if tensor.dim() == 3 else result rk = get_kernel(kernel) if rk is None: mode = 'bilinear' if (target_size[0] * target_size[1]) > (tensor.shape[-2] * tensor.shape[-1]) else 'area' - log.debug(f'Resize tensor: method=torch mode={mode} shape={tensor.shape} target={target_size} kernel=None fn={fn}') + debug(f'Resize tensor: method=torch mode={mode} shape={tensor.shape} target={target_size} kernel=None fn={fn}') inp = tensor if tensor.dim() == 4 else tensor.unsqueeze(0) result = torch.nn.functional.interpolate(inp, size=target_size, mode=mode, antialias=mode != 'area') return result.squeeze(0) if tensor.dim() == 3 else result @@ -206,10 +208,10 @@ def resize_tensor(tensor: torch.Tensor, target_size: tuple[int, int], *, kernel= both_up = (th >= src_h and tw >= src_w) if both_down or both_up: use_sparse = _triton_ok and dev.type == 'cuda' and rk.value == 'magic_kernel_sharp_2021' and both_down - log.debug(f'Resize tensor: method=sharpfin shape={tensor.shape} target={target_size} direction={both_up}:{both_down} kernel={rk} sparse={use_sparse} fn={fn}') + debug(f'Resize tensor: method=sharpfin shape={tensor.shape} target={target_size} direction={both_up}:{both_down} kernel={rk} sparse={use_sparse} fn={fn}') result = scale(tensor, target_size, resize_kernel=rk, device=dev, dtype=dt, do_srgb_conversion=linearize, use_sparse=use_sparse) else: - log.debug(f'Resize tensor: method=sharpfin shape={tensor.shape} target={target_size} direction={both_up}:{both_down} kernel={rk} sparse=False fn={fn}') + debug(f'Resize tensor: method=sharpfin shape={tensor.shape} target={target_size} direction={both_up}:{both_down} kernel={rk} sparse=False fn={fn}') intermediate = scale(tensor, (th, src_w), resize_kernel=rk, device=dev, dtype=dt, do_srgb_conversion=linearize, use_sparse=False) result = scale(intermediate, (th, tw), resize_kernel=rk, device=dev, dtype=dt, do_srgb_conversion=linearize, use_sparse=False) if squeezed: diff --git a/modules/img2img.py b/modules/img2img.py index 70d7e48cc..d01992811 100644 --- a/modules/img2img.py +++ b/modules/img2img.py @@ -163,8 +163,7 @@ def img2img(id_task: str, state: str, mode: int, vae_type, tiling, hidiffusion, detailer_enabled, detailer_prompt, detailer_negative, detailer_steps, detailer_strength, detailer_resolution, detailer_classes, n_iter, batch_size, - guidance_name, guidance_scale, guidance_rescale, guidance_start, guidance_stop, - cfg_scale, cfg_image, cfg_rescale, cfg_true, cfg_adaptive, cfg_end, + cfg_name, cfg_scale, cfg_image, cfg_rescale, cfg_start, cfg_stop, cfg_true, cfg_adaptive, refiner_start, clip_skip, denoising_strength, @@ -194,6 +193,8 @@ def img2img(id_task: str, state: str, mode: int, if sampler_index is None: log.warning('Sampler: invalid') sampler_index = 0 + if hr_sampler_index is None or hr_sampler_index == 'Same as primary': + hr_sampler_index = sampler_index mode = int(mode) image = None @@ -261,13 +262,6 @@ def img2img(id_task: str, state: str, mode: int, batch_size=batch_size, n_iter=n_iter, steps=steps, - guidance_name=guidance_name, - guidance_scale=guidance_scale, - guidance_rescale=guidance_rescale, - guidance_start=guidance_start, - guidance_stop=guidance_stop, - cfg_scale=cfg_scale, - cfg_end=cfg_end, clip_skip=clip_skip, width=width, height=height, @@ -289,10 +283,6 @@ def img2img(id_task: str, state: str, mode: int, resize_context=resize_context, scale_by=scale_by, denoising_strength=denoising_strength, - cfg_image=cfg_image, - cfg_rescale=cfg_rescale, - cfg_true=cfg_true, - cfg_adaptive=cfg_adaptive, refiner_start=refiner_start, inpaint_full_res=inpaint_full_res != 0, inpaint_full_res_padding=inpaint_full_res_padding, @@ -306,6 +296,15 @@ def img2img(id_task: str, state: str, mode: int, grading_shadows_tint=grading_shadows_tint, grading_highlights_tint=grading_highlights_tint, grading_split_tone_balance=grading_split_tone_balance, grading_vignette=grading_vignette, grading_grain=grading_grain, grading_lut_file=grading_lut_file.name if grading_lut_file is not None else '', grading_lut_strength=grading_lut_strength, + # guidance + cfg_name=cfg_name, + cfg_scale=cfg_scale, + cfg_image=cfg_image, + cfg_rescale=cfg_rescale, + cfg_start=cfg_start, + cfg_stop=cfg_stop, + cfg_true=cfg_true, + cfg_adaptive=cfg_adaptive, # refiner enable_hr=enable_hr, hr_denoising_strength=hr_denoising_strength, diff --git a/modules/intel/openvino/__init__.py b/modules/intel/openvino/__init__.py index 85f46e78b..f779743ee 100644 --- a/modules/intel/openvino/__init__.py +++ b/modules/intel/openvino/__init__.py @@ -251,14 +251,14 @@ def openvino_compile(gm: GraphModule, *example_inputs, model_hash_str: str | Non hints = {} if shared.opts.openvino_accuracy == "performance": - hints[ov_hints.execution_mode] = ov_hints.ExecutionMode.PERFORMANCE + hints[ov_hints.execution_mode] = ov_hints.ExecutionMode.PERFORMANCE # pylint: disable=c-extension-no-member elif shared.opts.openvino_accuracy == "accuracy": - hints[ov_hints.execution_mode] = ov_hints.ExecutionMode.ACCURACY + hints[ov_hints.execution_mode] = ov_hints.ExecutionMode.ACCURACY # pylint: disable=c-extension-no-member if model_hash_str is not None: hints['CACHE_DIR'] = shared.opts.openvino_cache_path + '/blob' core.set_property(hints) - log.debug(f'OpenVINO compile: device={device} backend={shared.opts.cuda_compile_backend} hints={hints} file="{file_name}"') + log.debug(f'OpenVINO compile cache: device={device} backend={shared.opts.cuda_compile_backend} accuracy={shared.opts.openvino_accuracy} hints={hints} hash={model_hash_str} file="{file_name}"') compiled_model = core.compile_model(om, device) return compiled_model @@ -274,9 +274,9 @@ def openvino_compile_cached_model(cached_model_path, *example_inputs): hints = {'CACHE_DIR': shared.opts.openvino_cache_path + '/blob'} if shared.opts.openvino_accuracy == "performance": - hints[ov_hints.execution_mode] = ov_hints.ExecutionMode.PERFORMANCE + hints[ov_hints.execution_mode] = ov_hints.ExecutionMode.PERFORMANCE # pylint: disable=c-extension-no-member elif shared.opts.openvino_accuracy == "accuracy": - hints[ov_hints.execution_mode] = ov_hints.ExecutionMode.ACCURACY + hints[ov_hints.execution_mode] = ov_hints.ExecutionMode.ACCURACY # pylint: disable=c-extension-no-member core.set_property(hints) device = get_device() diff --git a/modules/json_helpers.py b/modules/json_helpers.py index 4e6c5551a..b780ae45f 100644 --- a/modules/json_helpers.py +++ b/modules/json_helpers.py @@ -1,13 +1,52 @@ import os import sys +import contextlib +import threading import time import json from typing import overload, Literal -import fasteners import orjson from modules.logger import log -locking_available = True # used by file read/write locking +path_locks: dict[str, threading.RLock] = {} +path_locks_guard = threading.Lock() + + +def path_lock(filename: str | os.PathLike[str]) -> threading.RLock: + """One lock per file path; threads of this process serialize on it, other processes are covered by atomic replace.""" + key = os.path.normcase(os.path.realpath(filename)) + with path_locks_guard: + lock = path_locks.get(key) + if lock is None: + lock = path_locks[key] = threading.RLock() + with contextlib.suppress(OSError): + os.remove(f"{key}.lock") # left behind by the file lock this replaces + return lock + + +def read_bytes(filename: str | os.PathLike[str], attempts: int = 5, delay: float = 0.01) -> bytes: + """Read a whole file, waiting out an open that Windows refuses while a replace of the same name is in flight.""" + for attempt in range(attempts): + try: + with open(filename, "rb") as file: + return file.read() + except PermissionError: + if attempt == attempts - 1: + raise + time.sleep(delay) + return b"" + + +def replace_file(source: str, target: str, attempts: int = 10, delay: float = 0.05): + """os.replace that waits out a target another handle holds open, which Windows reports as a permission error.""" + for attempt in range(attempts): + try: + os.replace(source, target) + return + except PermissionError: + if attempt == attempts - 1: + raise + time.sleep(delay) @overload @@ -17,51 +56,28 @@ def readfile(filename: str | os.PathLike[str], silent: bool = False, lock: bool @overload def readfile(filename: str | os.PathLike[str], silent: bool = False, lock: bool = False) -> dict | list: ... def readfile(filename: str | os.PathLike[str], silent: bool = False, lock: bool = False, *, as_type="") -> dict | list: - global locking_available # pylint: disable=global-statement + """Read a JSON file; lock=True serializes with writers of the same path in this process.""" data = {} if as_type == "dict" else [] - lock_file = None - locked = False - if lock and locking_available: + with path_lock(filename) if lock else contextlib.nullcontext(): try: - lock_file = fasteners.InterProcessReaderWriterLock(f"{filename}.lock") - lock_file.logger.disabled = True # type: ignore - False positive. Bad typing in Fasteners. - locked = lock_file.acquire_read_lock(blocking=True, timeout=3) - except Exception as err: - lock_file = None - locking_available = False - log.error(f'File read lock: file="{filename}" {err}') - locked = False - - try: - # if not os.path.exists(filename): - # return {} - t0 = time.time() - with open(filename, "rb") as file: - b = file.read() + t0 = time.time() + b = read_bytes(filename) if len(b) == 0: + if not silent: + log.warning(f'Read: file="{filename}" empty') return {} if as_type == "dict" else [] data = orjson.loads(b) # pylint: disable=no-member - # if type(data) is str: - # data = json.loads(data) - t1 = time.time() - if not silent: - fn = f"{sys._getframe(2).f_code.co_name}:{sys._getframe(1).f_code.co_name}" # pylint: disable=protected-access - log.debug(f'Read: file="{filename}" json={len(data)} bytes={os.path.getsize(filename)} time={t1 - t0:.3f} fn={fn}') - except FileNotFoundError as err: - if not silent: - log.debug(f'Read failed: file="{filename}" {err}') - except Exception as err: - if not silent: - log.error(f'Read failed: file="{filename}" {err}') - - try: - if locking_available and lock_file is not None: - lock_file.release_read_lock() - if locked and os.path.exists(f"{filename}.lock"): - os.remove(f"{filename}.lock") - except Exception: - locking_available = False + t1 = time.time() + if not silent: + fn = f"{sys._getframe(2).f_code.co_name}:{sys._getframe(1).f_code.co_name}" # pylint: disable=protected-access + log.debug(f'Read: file="{filename}" json={len(data)} bytes={os.path.getsize(filename)} time={t1 - t0:.3f} fn={fn}') + except FileNotFoundError as err: + if not silent: + log.debug(f'Read failed: file="{filename}" {err}') + except Exception as err: + if not silent: + log.error(f'Read failed: file="{filename}" {err}') if isinstance(data, list) and as_type == "dict": if not data: @@ -79,65 +95,55 @@ def readfile(filename: str | os.PathLike[str], silent: bool = False, lock: bool return data -def writefile(obj: dict | list, filename: str | os.PathLike[str], mode="w", silent=False, atomic=False): +def writefile(obj: dict | list, filename: str | os.PathLike[str], mode="w", silent=False, atomic=True): + """Write obj as JSON through a temp file and replace; writes to the same path from this process run one at a time, in call order.""" import copy import tempfile - global locking_available # pylint: disable=global-statement - lock_file = None - locked = False - def default(obj): log.error(f'Save: file="{filename}" not a valid object: {obj}') return str(obj) - try: - t0 = time.time() - data = copy.deepcopy(obj) # ensure keys/items aren't added/deleted during json.dumps - for k, v in obj.items() if isinstance(obj, dict) else []: # validate each key-by-key to avoid global exceptions - try: - _tmp = json.dumps(v, indent=2, default=default, allow_nan=False, ensure_ascii=False) - except Exception as err: - if not silent: - log.error(f'Save: file="{filename}" key="{k}" value="{v}" {err}') - del data[k] - output = json.dumps(data, indent=2, default=default) - except Exception as err: - log.error(f'Save failed: file="{filename}" {err}') - return + if mode != "w": + atomic = False # append cannot go through a temp file - try: - if locking_available: - lock_file = fasteners.InterProcessReaderWriterLock(f"{filename}.lock") if locking_available else None - lock_file.logger.disabled = True # type: ignore - False positive. Bad typing in Fasteners. - locked = lock_file.acquire_write_lock(blocking=True, timeout=3) if lock_file is not None else False - except Exception as err: - locking_available = False - lock_file = None - log.error(f'File write lock: file="{filename}" {err}') - locked = False + with path_lock(filename): + try: + t0 = time.time() + snapshot = obj.copy() if isinstance(obj, (dict, list)) else obj # dict.copy and list.copy run under the GIL, so a concurrent insert cannot interrupt them + data = copy.deepcopy(snapshot) + for k, v in list(data.items()) if isinstance(data, dict) else []: # validate each key-by-key to avoid global exceptions + try: + _tmp = json.dumps(v, indent=2, default=default, allow_nan=False, ensure_ascii=False) + except Exception as err: + if not silent: + log.error(f'Save: file="{filename}" key="{k}" value="{v}" {err}') + del data[k] + output = json.dumps(data, indent=2, default=default) + except Exception as err: + log.error(f'Save failed: file="{filename}" {err}') + return - try: - if atomic: - with tempfile.NamedTemporaryFile(mode=mode, encoding="utf8", delete=False, dir=os.path.dirname(filename)) as f: - f.write(output) - f.flush() - os.fsync(f.fileno()) - os.replace(f.name, filename) - else: - with open(filename, mode=mode, encoding="utf8") as file: - file.write(output) - t1 = time.time() - if not silent: - datalength = len(data) - log.debug(f'Save: file="{filename}" json={datalength} bytes={len(output)} time={t1 - t0:.3f}') - except Exception as err: - log.error(f'Save failed: file="{filename}" {err}') - - try: - if locking_available and lock_file is not None: - lock_file.release_write_lock() - if locked and os.path.exists(f"{filename}.lock"): - os.remove(f"{filename}.lock") - except Exception: - locking_available = False + try: + if atomic: + target = os.path.realpath(filename) # replace the file a symlink points at, not the symlink + fd, temp_name = tempfile.mkstemp(dir=os.path.dirname(target), prefix=f"{os.path.basename(target)}.", suffix=".tmp") + try: + with os.fdopen(fd, mode, encoding="utf8") as f: + f.write(output) + f.flush() + os.fsync(f.fileno()) + replace_file(temp_name, target) + except BaseException: + with contextlib.suppress(OSError): + os.remove(temp_name) + raise + else: + with open(filename, mode=mode, encoding="utf8") as file: + file.write(output) + t1 = time.time() + if not silent: + datalength = len(data) + log.debug(f'Save: file="{filename}" json={datalength} bytes={len(output)} time={t1 - t0:.3f}') + except Exception as err: + log.error(f'Save failed: file="{filename}" {err}') diff --git a/modules/loader.py b/modules/loader.py index 275febfae..b0960f7d4 100644 --- a/modules/loader.py +++ b/modules/loader.py @@ -34,7 +34,7 @@ try: import numpy.random # pylint: disable=W0611,C0411 # this causes failure if numpy version changed def obj2sctype(obj): return np.dtype(obj).type - if np.__version__.startswith('2.'): # monkeypatch for np==1.2 compatibility + if str(np.__version__).startswith('2.'): # monkeypatch for np==1.2 compatibility np.obj2sctype = obj2sctype # noqa: NPY201 np.bool8 = np.bool np.float_ = np.float64 # noqa: NPY201 @@ -133,13 +133,6 @@ if ".dev" in torch.__version__ or "+git" in torch.__version__: torch.__version__ = re.search(r'[\d.]+[\d]', torch.__version__).group(0) timer.startup.record("torch") -try: - from modules.sd_hijack_triton import install as install_autotune_report # pylint: disable=ungrouped-imports - install_autotune_report() -except Exception as e: - log.warning(f'Triton logging: {e}') -timer.startup.record("triton") - try: import bitsandbytes # pylint: disable=unused-import _bnb = True @@ -201,8 +194,6 @@ except Exception as e: _onnx = False timer.startup.record("onnx") -timer.startup.record("fastapi") - import gradio # pylint: disable=W0611,C0411 timer.startup.record("gradio") errors.install([gradio]) @@ -237,6 +228,13 @@ diffusers.utils.import_utils._sdnq_available = True # pylint: disable=protected- diffusers.utils.import_utils._sdnq_version = sdnq.__version__ # pylint: disable=protected-access timer.startup.record("sdnq") +try: + from modules.sd_hijack_triton import install as install_autotune_report # pylint: disable=ungrouped-imports + install_autotune_report() +except Exception as e: + log.warning(f'Triton logging: {e}') +timer.startup.record("triton") + try: import pillow_jxl # pylint: disable=W0611,C0411 except Exception: diff --git a/modules/logger.py b/modules/logger.py index a1826b571..4aac7dac3 100644 --- a/modules/logger.py +++ b/modules/logger.py @@ -182,21 +182,14 @@ def setup_logging(debug=None, trace=None, filename=None): render_options = render_options.update_height(height=render_options.height - self.top - self.bottom) lines = console.render_lines(self.renderable, render_options, style=style, pad=False) _Segment = Segment - left = _Segment(" " * self.left, style) if self.left else None right = [_Segment.line()] blank_line: list[Segment] | None = None if self.top: blank_line = [_Segment(f'{" " * width}\\n', style)] yield from blank_line * self.top - if left: - for line in lines: - yield left - yield from line - yield from right - else: - for line in lines: - yield from line - yield from right + for line in lines: # self.left is forced to 0 above, so no left-padding segment is ever emitted + yield from line + yield from right if self.bottom: blank_line = blank_line or [_Segment(f'{" " * width}\\n', style)] yield from blank_line * self.bottom @@ -232,13 +225,26 @@ def setup_logging(debug=None, trace=None, filename=None): log.setLevel(logging.DEBUG) # log to file is always at level debug for facility `sd` log.print = rprint + # use only the 16 standard ANSI color names (+ dim/bold modifiers) so the theme renders correctly on basic 16-color terminals too theme = Theme({ "traceback.border": "black", "inspect.value.border": "black", - "traceback.border.syntax_error": "dark_red", - "logging.level.info": "blue_violet", - "logging.level.debug": "purple4", - "logging.level.trace": "dark_blue", + "traceback.border.syntax_error": "red", + + "logging.level.trace": "dim cyan", + "logging.level.debug": "cyan", + "logging.level.info": "bright_cyan", + "logging.level.warning": "yellow", + "logging.level.error": "red", + "logging.level.critical": "bold bright_red", + + "repr.attrib_name": "bright_white", + "repr.attrib_value": "cyan", + "repr.str": "bright_cyan", + "repr.none": "yellow", + "repr.number": "bright_yellow", + "repr.bool_true": "green", + "repr.bool_false": "bright_red", }) Padding.__rich_console__ = override_padding @@ -263,7 +269,7 @@ def setup_logging(debug=None, trace=None, filename=None): log_filter = LogFilter() # handlers - rh = RichHandler(show_time=True, omit_repeated_times=False, show_level=True, show_path=False, markup=False, rich_tracebacks=True, log_time_format='%H:%M:%S-%f', level=level, console=console) + rh = RichHandler(show_time=True, omit_repeated_times=False, show_level=True, show_path=False, markup=True, rich_tracebacks=True, log_time_format='%H:%M:%S-%f', level=level, console=console) if trace: rh.formatter = logging.Formatter('[%(module)s][%(pathname)s:%(lineno)d] %(message)s') rh.addFilter(log_filter) @@ -312,3 +318,12 @@ def setup_logging(debug=None, trace=None, filename=None): logging.getLogger("torch").setLevel(logging.DEBUG) else: logging.getLogger("torch").setLevel(logging.WARNING) + + +if __name__ == "__main__": + setup_logging(debug=True, trace=False, filename=None) + for l in [logging.TRACE, logging.DEBUG, logging.INFO, logging.WARNING, logging.ERROR, logging.CRITICAL]: + log.log(l, f"Test log level: {logging.getLevelName(l)}") + values = [None, True, False, "yes", "no", "sd.next", 1, 0, 1.0, [1,2,3], {"key": "value"}, (1,2), {1,2}, object()] + for v in values: + log.info(f"Test values: {type(v).__name__}={v}") diff --git a/modules/lora/extra_networks_lora.py b/modules/lora/extra_networks_lora.py index 35605e95e..14e99351f 100644 --- a/modules/lora/extra_networks_lora.py +++ b/modules/lora/extra_networks_lora.py @@ -27,7 +27,7 @@ def get_stepwise(param, step, steps): # from https://github.com/cheald/sd-webui- if m[1][-1] <= 1.0: step = step / (max_steps - step_offset) if max_steps > 0 else 1.0 v = np.interp(step, m[1], m[0]) - debug_log(f"Network load: type=LoRA step={step} steps={max_steps} v={v}") + debug_log(f"LoRA: stepwise step={step} steps={max_steps} v={v}") return v else: return m @@ -54,7 +54,7 @@ def prompt(p): all_tags = list(set(all_tags)) all_tags = [t for t in all_tags if t not in p.prompt] if len(all_tags) > 0: - log.debug(f"Network load: type=LoRA tags={all_tags} max={shared.opts.lora_apply_tags} apply") + log.debug(f"Network tags: type=LoRA tags={all_tags} max={shared.opts.lora_apply_tags} apply") all_tags = ', '.join(all_tags) p.extra_generation_params["LoRA tags"] = all_tags if '_tags_' in p.prompt: @@ -98,6 +98,7 @@ def parse(p, params_list, step=0): unet_multipliers = [] dyn_dims = [] lora_modules = [] + block_specs = [] for params in params_list: name = params.positional[0] @@ -131,6 +132,7 @@ def parse(p, params_list, step=0): te_multipliers.append(te_multiplier) unet_multipliers.append(unet_multiplier) dyn_dims.append(dyn_dim) + block_specs.append(params.named.get('lbw', None)) # per-block strength; resolved per layer by lora_blocks lora_module = [] name_lower = params.positional[0].lower() @@ -150,7 +152,7 @@ def parse(p, params_list, step=0): lora_modules.append(lora_module) - return names, te_multipliers, unet_multipliers, dyn_dims, lora_modules + return names, te_multipliers, unet_multipliers, dyn_dims, lora_modules, block_specs def unload_diffusers(): @@ -161,7 +163,7 @@ def unload_diffusers(): pass if hasattr(shared.sd_model, "unload_lora_weights"): try: - shared.sd_model.unload_lora_weights() # fails for non-CLIP models + shared.sd_model.unload_lora_weights() except Exception: pass @@ -174,12 +176,15 @@ class ExtraNetworkLora(extra_networks.ExtraNetwork): self.model = None self.errors = {} - def signature(self, names: list[str], te_multipliers: list, unet_multipliers: list): - return [f'{name}:{te}:{unet}' for name, te, unet in zip(names, te_multipliers, unet_multipliers, strict=False)] + def signature(self, names: list[str], te_multipliers: list, unet_multipliers: list, block_specs: list | None = None): + specs = block_specs if block_specs else [None] * len(names) + return [f'{name}:{te}:{unet}' + (f':lbw={str(spec).strip().lower()}' if spec else '') for name, te, unet, spec in zip(names, te_multipliers, unet_multipliers, specs, strict=False)] def changed(self, requested: list[str], include: list[str] | None = None, exclude: list[str] | None = None) -> tuple[bool, str]: + from modules.lora import lora_sdnq, lora_stack + requested = requested + [f'stack={lora_stack.signature()}{lora_sdnq.signature()}'] # settings-only stack or mechanism changes must re-trigger activation if shared.opts.lora_force_reload: - debug_log(f'Network check: type=LoRA requested={requested} status="forced"') + debug_log(f'LoRA check requested={requested} status="forced"') return True, "forced" sd_model = shared.sd_model.pipe if hasattr(shared.sd_model, 'pipe') else shared.sd_model if sd_model is None: @@ -195,15 +200,15 @@ class ExtraNetworkLora(extra_networks.ExtraNetwork): if len(requested) != len(loaded): sd_model.loaded_loras.clear() # single-entry cache: any activation invalidates state recorded under other filter keys sd_model.loaded_loras[key] = requested - debug_log(f'Network check: type=LoRA key="{key}" requested={requested} loaded={loaded} status="num changed"') + debug_log(f'LoRA check key="{key}" requested={requested} loaded={loaded} status="num changed"') return True, "num changed" for req, load in zip(requested, loaded, strict=False): if req != load: sd_model.loaded_loras.clear() sd_model.loaded_loras[key] = requested - debug_log(f'Network check: type=LoRA key="{key}" requested={requested} loaded={loaded} status="content changed"') + debug_log(f'LoRA check key="{key}" requested={requested} loaded={loaded} status="content changed"') return True, "content changed" - debug_log(f'Network check: type=LoRA key="{key}" requested={requested} loaded={loaded} status="same"') + debug_log(f'LoRA check key="{key}" requested={requested} loaded={loaded} status="same"') return False, "none" def activate(self, p, params_list, step=0, include=None, exclude=None): # pylint: disable=arguments-differ @@ -218,15 +223,20 @@ class ExtraNetworkLora(extra_networks.ExtraNetwork): if len(params_list) > 0 and not self.active: # activate patches once self.active = True self.model = shared.opts.sd_model_checkpoint - names, te_multipliers, unet_multipliers, dyn_dims, lora_modules = parse(p, params_list, step) - requested = self.signature(names, te_multipliers, unet_multipliers) + names, te_multipliers, unet_multipliers, dyn_dims, lora_modules, block_specs = parse(p, params_list, step) + requested = self.signature(names, te_multipliers, unet_multipliers, block_specs) reason = '' load_method, load_reason = lora_overrides.get_method() + from modules.lora import lora_stack + if load_method != 'native' and lora_stack.mode() != 'sum': + log.warning(f'Network stack: mode={lora_stack.mode()} method={load_method} fallback=sum') + if load_method != 'native' and any(block_specs): + log.warning(f'Network blocks: method={load_method} fallback=none') if debug: import sys fn = f'{sys._getframe(2).f_code.co_name}:{sys._getframe(1).f_code.co_name}' # pylint: disable=protected-access - debug_log(f'Network load: type=LoRA include={include} exclude={exclude} method={load_method} reason="{load_reason}" requested={requested} fn={fn}') + debug_log(f'LoRA load: include={include} exclude={exclude} method={load_method} reason="{load_reason}" requested={requested} fn={fn}') if load_method == 'diffusers': has_changed, reason = self.changed(requested) @@ -238,7 +248,7 @@ class ExtraNetworkLora(extra_networks.ExtraNetwork): if hasattr(sd_model, 'disable_lora'): try: sd_model.disable_lora() - log.info('Network unload: type=LoRA mode=diffusers') + log.info('Network unload: type=LoRA method=diffusers disable') except Exception as e: log.error(f'Network unload: type=LoRA {e}') sd_models.set_diffuser_offload(shared.sd_model, op="model") @@ -249,15 +259,15 @@ class ExtraNetworkLora(extra_networks.ExtraNetwork): has_changed = lora_nunchaku.load_nunchaku(names, unet_multipliers) else: # native - lora_load.network_load(names, te_multipliers, unet_multipliers, dyn_dims, activate=False) # load only, activation below honors include/exclude + lora_load.network_load(names, te_multipliers, unet_multipliers, dyn_dims, block_specs=block_specs, activate=False) # load only, activation below honors include/exclude has_changed, reason = self.changed(requested, include, exclude) if has_changed: jobid = shared.state.begin('LoRA') if len(l.previously_loaded_networks) > 0: - log.info(f'Network unload: type=LoRA networks={[n.name for n in l.previously_loaded_networks]} mode={"fuse" if shared.opts.lora_fuse_native else "backup"}') + log.info(f'Network unload: type=LoRA networks={[n.name for n in l.previously_loaded_networks]} mode={networks.effective_mode()}') networks.network_deactivate(include, exclude) networks.network_activate(include, exclude) - debug_log(f'Network change: type=LoRA previous={[n.name for n in l.previously_loaded_networks]} current={[n.name for n in l.loaded_networks]}') + debug_log(f'LoRA change: previous={[n.name for n in l.previously_loaded_networks]} current={[n.name for n in l.loaded_networks]}') if len(include) == 0: l.previously_loaded_networks = l.loaded_networks.copy() shared.state.end(jobid) @@ -265,12 +275,15 @@ class ExtraNetworkLora(extra_networks.ExtraNetwork): if len(l.loaded_networks) > 0 and (len(networks.applied_layers) > 0 or load_method=='diffusers' or load_method=='nunchaku') and step == 0: infotext(p) prompt(p) - if has_changed and len(include) == 0: # print only once + sd_model = shared.sd_model.pipe if hasattr(shared.sd_model, 'pipe') else shared.sd_model + if len(include) == 0: # print only once actual_method = 'native' if any(len(n.modules) > 0 for n in l.loaded_networks) else load_method - log.info(f'Network load: type=LoRA networks={[n.name for n in l.loaded_networks]} load={load_method}({load_reason}) method={actual_method} mode={"fuse" if shared.opts.lora_fuse_native else "backup"} te={te_multipliers} unet={unet_multipliers} time={l.timer.summary} reason="{reason}"') + stack = lora_stack.signature() if actual_method == 'native' else 'sum' # non-native paths always combine as sum + log.info(f'Network status: type=LoRA networks={[n.name for n in l.loaded_networks]} method={actual_method}({load_reason}) mode={networks.effective_mode()} stack={stack} te={te_multipliers} unet={unet_multipliers} time={l.timer.summary} changed={has_changed} reason="{reason}"') - def deactivate(self, p, force=False): + def deactivate(self, p, force=False): # pylint: disable=unused-argument if len(lora_diffusers.diffuser_loaded) > 0 and (shared.opts.lora_force_reload or force): + log.debug(f'Network unload: type=LoRA method=diffusers loaded={len(lora_diffusers.diffuser_loaded)} opts={shared.opts.lora_force_reload} force={force}') unload_diffusers() if force: networks.network_deactivate() diff --git a/modules/lora/lora_apply.py b/modules/lora/lora_apply.py index c1b46c4ab..11b91d9e9 100644 --- a/modules/lora/lora_apply.py +++ b/modules/lora/lora_apply.py @@ -5,6 +5,7 @@ import time from typing import TYPE_CHECKING import torch from modules.lora import lora_common as l +from modules.lora import lora_stack from modules import shared, devices, errors from modules.logger import log @@ -16,7 +17,7 @@ if TYPE_CHECKING: re_network_name = re.compile(r"(.*)\s*\([0-9a-fA-F]+\)") -def network_backup_weights(self: torch.nn.Conv2d | torch.nn.Linear | torch.nn.GroupNorm | torch.nn.LayerNorm | diffusers.models.lora.LoRACompatibleLinear | diffusers.models.lora.LoRACompatibleConv, network_layer_name: str, wanted_names: tuple): +def network_backup_weights(self: torch.nn.Conv2d | torch.nn.Linear | torch.nn.GroupNorm | torch.nn.LayerNorm | diffusers.models.lora.LoRACompatibleLinear | diffusers.models.lora.LoRACompatibleConv, network_layer_name: str, wanted_names: tuple, fuse: bool): backup_size = 0 if len(l.loaded_networks) > 0 and network_layer_name is not None and any([net.modules.get(network_layer_name, None) for net in l.loaded_networks]): # noqa: C419 # pylint: disable=R1729 t0 = time.time() @@ -24,7 +25,7 @@ def network_backup_weights(self: torch.nn.Conv2d | torch.nn.Linear | torch.nn.Gr weights_backup = getattr(self, "network_weights_backup", None) bias_backup = getattr(self, "network_bias_backup", None) if weights_backup is not None or bias_backup is not None: - if (shared.opts.lora_fuse_native and not isinstance(weights_backup, bool)) or (not shared.opts.lora_fuse_native and isinstance(weights_backup, bool)): # invalidate so we can change direct/backup on-the-fly + if (fuse and not isinstance(weights_backup, bool)) or (not fuse and isinstance(weights_backup, bool)): # invalidate so we can change direct/backup on-the-fly weights_backup = None bias_backup = None self.network_weights_backup = weights_backup @@ -33,7 +34,7 @@ def network_backup_weights(self: torch.nn.Conv2d | torch.nn.Linear | torch.nn.Gr if weights_backup is None and wanted_names != (): # pylint: disable=C1803 weight = getattr(self, 'weight', None) self.network_weights_backup = None - if shared.opts.lora_fuse_native: + if fuse: self.network_weights_backup = True else: self.network_weights_backup = weight.clone().to(devices.cpu) @@ -53,7 +54,7 @@ def network_backup_weights(self: torch.nn.Conv2d | torch.nn.Linear | torch.nn.Gr if bias_backup is None: if getattr(self, 'bias', None) is not None: - if shared.opts.lora_fuse_native: + if fuse: self.network_bias_backup = True else: bias_backup = self.bias.clone() @@ -67,7 +68,7 @@ def network_backup_weights(self: torch.nn.Conv2d | torch.nn.Linear | torch.nn.Gr return backup_size -def network_calc_weights(self: torch.nn.Conv2d | torch.nn.Linear | torch.nn.GroupNorm | torch.nn.LayerNorm | diffusers.models.lora.LoRACompatibleLinear | diffusers.models.lora.LoRACompatibleConv, network_layer_name: str, use_previous: bool = False, *, elimit: Callable[[], None] | None = None): +def network_calc_weights(self: torch.nn.Conv2d | torch.nn.Linear | torch.nn.GroupNorm | torch.nn.LayerNorm | diffusers.models.lora.LoRACompatibleLinear | diffusers.models.lora.LoRACompatibleConv, network_layer_name: str, use_previous: bool = False, *, elimit: Callable[[], None] | None = None, per_net: bool = False): if shared.opts.diffusers_offload_mode == "none": try: self.to(devices.device) @@ -75,6 +76,9 @@ def network_calc_weights(self: torch.nn.Conv2d | torch.nn.Linear | torch.nn.Grou pass batch_updown = None batch_ex_bias = None + stack_deltas = None + if per_net or (lora_stack.mode() in lora_stack.DENSE_MODES and network_layer_name is not None and not network_layer_name.startswith('lora_te')): + stack_deltas = [] # collect per-net deltas; combined after the loop unless the caller wants them separate (bias deltas stay summed) loaded = l.loaded_networks if not use_previous else l.previously_loaded_networks for net in loaded: module = net.modules.get(network_layer_name, None) @@ -107,7 +111,9 @@ def network_calc_weights(self: torch.nn.Conv2d | torch.nn.Linear | torch.nn.Grou del weight if updown is not None: - if batch_updown is not None: + if stack_deltas is not None: + stack_deltas.append((net.name, updown.to(devices.device))) + elif batch_updown is not None: batch_updown += updown.to(batch_updown.device) else: batch_updown = updown.to(devices.device) @@ -136,6 +142,17 @@ def network_calc_weights(self: torch.nn.Conv2d | torch.nn.Linear | torch.nn.Grou if elimit is not None: elimit() continue + if per_net: + return stack_deltas, batch_ex_bias + if stack_deltas is not None and stack_deltas: + if len(stack_deltas) >= 2: + t0 = time.time() + batch_updown = lora_stack.combine(stack_deltas, network_layer_name) + l.timer.calc += time.time() - t0 + else: + batch_updown = stack_deltas[0][1] + if shared.opts.diffusers_offload_mode == "sequential": + batch_updown = batch_updown.to(devices.cpu) return batch_updown, batch_ex_bias diff --git a/modules/lora/lora_blocks.py b/modules/lora/lora_blocks.py new file mode 100644 index 000000000..211f1ac78 --- /dev/null +++ b/modules/lora/lora_blocks.py @@ -0,0 +1,348 @@ +"""Per-block LoRA strength: . + +Each targeted layer maps to one slot of a per-architecture weight vector and +the network's multiplier is scaled by that slot. Slot 0 is BASE: on unet +architectures it covers the text encoder and the unet layers outside the +block chain, on transformer architectures the layers outside the block +chain(s). The remaining slots follow the merge block-weight layout on unet +architectures (26 on sd, 20 on sdxl: input blocks, mid, output blocks) and +the transformer chain(s) in depth order elsewhere, with chain lengths +scanned from the live network_layer_mapping rather than hardcoded. + +VALUE is a preset name (case-insensitive), a single number broadcast to +every slot, or a comma list with one number per slot. Named presets force +BASE to 1.0, since the merge tables carry 0 there with merge semantics, and +stretch onto the block count of the current model; classic segment names +(INS, OUTALL, ...) generate from ranges, so they also work on transformer +chains via thirds, and DOUBLE/SINGLE mute one chain on two-chain +architectures. Explicit vectors are taken verbatim at the slot count, with +the a1111 17-slot (sd) and 12-slot (sdxl) layouts accepted and expanded, +omitted slots neutral. A value that fits nothing is ignored with a warning +and the network applies at its plain strength. +""" + +import re + +from modules import shared +from modules.logger import log +from modules.lora import lora_common as l + + +UNET_ARCHES = ('sd', 'sdxl') +CHAINS = { # arch -> anchored tail prefixes, one per chain, in depth order + 'sd3': ('transformer_blocks_',), + 'anima': ('transformer_blocks_',), + 'f1': ('transformer_blocks_', 'single_transformer_blocks_'), + 'f2': ('transformer_blocks_', 'single_transformer_blocks_'), + 'chroma': ('transformer_blocks_', 'single_transformer_blocks_'), + 'zimage': ('layers_',), + 'ernieimage': ('layers_',), + 'krea2': ('blocks_',), +} +CLASSIC = ('ALL', 'NONE', 'INALL', 'INS', 'IND', 'MIDD', 'OUTALL', 'OUTD', 'OUTS') +CHAIN_NAMES = ('DOUBLE', 'SINGLE') +SD1_17 = (0, 2, 3, 5, 6, 8, 9, 13, 17, 18, 19, 20, 21, 22, 23, 24, 25) # BASE, IN01, IN02, IN04, IN05, IN07, IN08, MID, OUT03..OUT11 +SDXL_12 = (0, 5, 6, 8, 9, 10, 11, 12, 13, 14, 15, 16) # BASE, IN04, IN05, IN07, IN08, MID, OUT00..OUT05 +VECTOR_MEMO_CAP = 64 +MISS = object() + +re_down = re.compile(r'^down_blocks_(\d+)_(resnets|attentions|downsamplers)_(\d+)') +re_up = re.compile(r'^up_blocks_(\d+)_(resnets|attentions|upsamplers)_(\d+)') +re_chain_index = re.compile(r'^(\d+)') + +state: dict = {'stamp': None, 'layout': None, 'index': {}, 'vectors': {}} +warned: set = set() + + +def warn_once(key, message): + if key not in warned: + warned.add(key) + log.warning(message) + + +def build_unet_layout(arch, mapping): + down, up = -1, -1 + for key in mapping: + if not key.startswith('lora_unet_'): + continue + tail = key[len('lora_unet_'):] + m = re_down.match(tail) + if m is not None: + down = max(down, int(m.group(1))) + continue + m = re_up.match(tail) + if m is not None: + up = max(up, int(m.group(1))) + if down < 0 or up < 0: + return None + n_in = 3 * (down + 1) # conv_in plus two pairs and a sampler slot per group: the compvis input_blocks count + n_out = 3 * (up + 1) + n = 2 + n_in + n_out + return { + 'arch': arch, 'kind': 'unet', 'n': n, 'n_in': n_in, + 'ins': list(range(1, 1 + n_in)), + 'mids': [1 + n_in], + 'outs': list(range(2 + n_in, n)), + } + + +def build_dit_layout(arch, mapping): + prefixes = CHAINS.get(arch) + if prefixes is None: + return None + counts = [0 for _ in prefixes] + for key in mapping: + if not key.startswith('lora_transformer_'): + continue + tail = key[len('lora_transformer_'):] + for i, prefix in enumerate(prefixes): + if tail.startswith(prefix): + m = re_chain_index.match(tail[len(prefix):]) + if m is not None: + counts[i] = max(counts[i], int(m.group(1)) + 1) + break + total = sum(counts) + if total == 0: + return None + chains = [] + offset = 0 + for prefix, count in zip(prefixes, counts, strict=False): + chains.append((prefix, count, offset)) + offset += count + n = 1 + total + blocks = list(range(1, n)) + return { + 'arch': arch, 'kind': 'dit', 'n': n, 'chains': chains, + 'ins': [s for i, s in enumerate(blocks) if i * 3 // total == 0], + 'mids': [s for i, s in enumerate(blocks) if i * 3 // total == 1], + 'outs': [s for i, s in enumerate(blocks) if i * 3 // total == 2], + } + + +def layout(): + sd_model = getattr(shared, 'sd_model', None) + mapping = getattr(sd_model, 'network_layer_mapping', None) if sd_model is not None else None + if not mapping: + return None + arch = shared.sd_model_type + stamp = (arch, id(mapping)) + if state['stamp'] == stamp: + return state['layout'] + state['stamp'] = stamp + state['layout'] = build_unet_layout(arch, mapping) if arch in UNET_ARCHES else build_dit_layout(arch, mapping) + state['index'].clear() + state['vectors'].clear() + return state['layout'] + + +def classify(sd_key, lay): + if sd_key.startswith('lora_te'): + return 0 if lay['kind'] == 'unet' else None # BASE covers the TE on unet arches; transformer vectors do not model the TE + if sd_key.startswith('lora_llm_adapter_'): + return None + if lay['kind'] == 'unet': + if not sd_key.startswith('lora_unet_'): + return None + tail = sd_key[len('lora_unet_'):] + m = re_down.match(tail) + if m is not None: + slot = 1 + 3 * int(m.group(1)) + (2 if m.group(2) == 'downsamplers' else int(m.group(3))) + return 1 + slot + m = re_up.match(tail) + if m is not None: + slot = 3 * int(m.group(1)) + (2 if m.group(2) == 'upsamplers' else int(m.group(3))) + return 2 + lay['n_in'] + slot + if tail.startswith('mid_block'): + return 1 + lay['n_in'] + if tail.startswith('conv_in'): + return 1 # IN00 + if tail.startswith('conv_out') or tail.startswith('conv_norm_out'): + return lay['n'] - 1 # the compvis out group belongs to the last output block + return 0 # time_embedding, add_embedding and other non-block leaves + if not sd_key.startswith('lora_transformer_'): + return None + tail = sd_key[len('lora_transformer_'):] + for prefix, count, offset in lay['chains']: + if tail.startswith(prefix): + m = re_chain_index.match(tail[len(prefix):]) + if m is not None and int(m.group(1)) < count: + return 1 + offset + int(m.group(1)) + return 0 + return 0 # embedders, projections, refiners and other non-chain layers + + +def block_index(sd_key): + lay = layout() + if lay is None: + return None + cached = state['index'].get(sd_key, MISS) + if cached is not MISS: + return cached + idx = classify(sd_key, lay) + state['index'][sd_key] = idx + return idx + + +def fill_band(vec, slots, lo, hi): + k = len(slots) + for i, s in enumerate(slots): + if lo * k <= i < hi * k: + vec[s] = 1.0 + + +def classic_vector(name, lay): + if name == 'ALL': + return [1.0] * lay['n'] + vec = [0.0] * lay['n'] + if name == 'NONE': + return vec + vec[0] = 1.0 + if name == 'INALL': + fill_band(vec, lay['ins'], 0.0, 1.0) + elif name == 'INS': # shallow half of the input side + fill_band(vec, lay['ins'], 0.0, 0.5) + elif name == 'IND': # deep half of the input side + fill_band(vec, lay['ins'], 0.5, 1.0) + elif name == 'MIDD': # the middle of the network: deep input half, mid, deep output half + fill_band(vec, lay['ins'], 0.5, 1.0) + fill_band(vec, lay['mids'], 0.0, 1.0) + fill_band(vec, lay['outs'], 0.0, 0.5) + elif name == 'OUTALL': + fill_band(vec, lay['outs'], 0.0, 1.0) + elif name == 'OUTD': # deep half of the output side, nearest the mid + fill_band(vec, lay['outs'], 0.0, 0.5) + elif name == 'OUTS': # shallow half of the output side, nearest the image + fill_band(vec, lay['outs'], 0.5, 1.0) + return vec + + +def chain_vector(name, lay): + chains = lay.get('chains') or [] + if len(chains) != 2: + return None + vec = [1.0] * lay['n'] + keep = 0 if name == 'DOUBLE' else 1 + for i, (_prefix, count, offset) in enumerate(chains): + val = 1.0 if i == keep else 0.0 + for s in range(1 + offset, 1 + offset + count): + vec[s] = val + return vec + + +def stretch(src, k): + if k == len(src): + return [float(v) for v in src] + out = [] + for i in range(k): + x = i * (len(src) - 1) / (k - 1) if k > 1 else 0.0 + lo = int(x) + hi = min(lo + 1, len(src) - 1) + f = x - lo + out.append(float(src[lo]) * (1.0 - f) + float(src[hi]) * f) + return out + + +def preset_vector(name, lay): + from modules.merging.merge_presets import BLOCK_WEIGHTS_PRESETS, SDXL_BLOCK_WEIGHTS_PRESETS + if name in CHAIN_NAMES: + return chain_vector(name, lay) + if name in CLASSIC: + return classic_vector(name, lay) + if lay['arch'] == 'sdxl': + src = SDXL_BLOCK_WEIGHTS_PRESETS.get(name) or SDXL_BLOCK_WEIGHTS_PRESETS.get('SDXL_' + name) + if src is not None: + return [1.0] + [float(v) for v in src[1:]] # merge tables carry 0 in the BASE slot; a preset must leave the TE alone + if name.startswith('SDXL_'): + return None # explicitly arch-tagged, not reinterpreted elsewhere + src = BLOCK_WEIGHTS_PRESETS.get(name) + if src is None: + return None + if lay['arch'] == 'sd': + return [1.0] + [float(v) for v in src[1:]] + return [1.0] + stretch(src[1:], lay['n'] - 1) + + +def parse_vector(parts, lay): + try: + vals = [float(x) for x in parts] + except ValueError: + return None + n = lay['n'] + if len(vals) == n: + return vals + if len(vals) == n - 1: + return [1.0] + vals + legacy = SD1_17 if lay['arch'] == 'sd' else (SDXL_12 if lay['arch'] == 'sdxl' else None) + if legacy is not None and len(vals) == len(legacy): + vec = [1.0] * n # slots the a1111 layouts omit stay neutral + for slot, v in zip(legacy, vals, strict=False): + vec[slot] = v + return vec + return None + + +def resolve(spec): + """Resolve a raw lbw value into a slot vector for the current model, or None when it fits nothing.""" + lay = layout() + if lay is None: + return None + raw = str(spec).strip() + key = raw.lower() + if key in state['vectors']: + return state['vectors'][key] + if len(state['vectors']) > VECTOR_MEMO_CAP: + state['vectors'].clear() + vec = None + if ',' in raw: + vec = parse_vector([x.strip() for x in raw.split(',')], lay) + if vec is None: + warn_once(f'lbw-vector:{key}:{lay["arch"]}', f'Network blocks: value="{raw}" arch={lay["arch"]} expected={lay["n"]} fallback=none') + else: + try: + vec = [float(raw)] * lay['n'] + except ValueError: + vec = preset_vector(raw.upper(), lay) + if vec is None: + warn_once(f'lbw-name:{key}:{lay["arch"]}', f'Network blocks: preset="{raw}" arch={lay["arch"]} fallback=none') + if vec is not None: + log.info(f'Network blocks: value="{raw}" arch={lay["arch"]} slots={lay["n"]} range={min(vec):.2f}-{max(vec):.2f}') + state['vectors'][key] = vec + return vec + + +def factor(sd_key, net): + """Per-layer scale from a network's block vector; 1.0 whenever the vector does not apply.""" + try: + spec = getattr(net, 'block_spec', None) + if not spec: + return 1.0 + vec = resolve(spec) + if vec is None: + return 1.0 + idx = block_index(sd_key) + if idx is None: + return 1.0 + return float(vec[idx]) + except Exception as e: + warn_once('lbw-error', f'Network blocks: {e} fallback=none') + return 1.0 + + +def net_signature(net): + """Normalized spec of one network, or None; joins content identities such as the factor cache signature.""" + spec = getattr(net, 'block_spec', None) + if not spec: + return None + return str(spec).strip().lower() + + +def active(): + return any(getattr(net, 'block_spec', None) for net in l.loaded_networks) + + +def signature(): + """Identity suffix for the per-module apply stamp; empty while no loaded network carries block weights.""" + specs = [f'{net.name}:{net_signature(net)}' for net in l.loaded_networks if getattr(net, 'block_spec', None)] + if len(specs) == 0: + return '' + return '|lbw=' + ','.join(specs) diff --git a/modules/lora/lora_calib.py b/modules/lora/lora_calib.py new file mode 100644 index 000000000..622fa50e9 --- /dev/null +++ b/modules/lora/lora_calib.py @@ -0,0 +1,226 @@ +"""Per-checkpoint activation calibration for svd hosting on quantized layers. + +Plain svd truncation of a hosted delta is optimal in weight space but not in +output space: transformer activations concentrate energy in a few input +channels (per-channel RMS spreads by one to three orders of magnitude), so +the directions that matter most for the output are not the largest in +Frobenius norm. Scaling the delta by per-channel input RMS before the svd +and folding the inverse scale into the down factor spends the same rank +budget on output error instead; measured on real checkpoints this raises +output-delta retention by ~0.05 at rank 256 and ~0.09 at rank 64, most on +MLP down projections whose inputs carry the largest outlier channels. + +Statistics come from the model's own forwards: when a sub-8-bit SDNQ model +loads and no calibration is cached for it, streaming sum-of-squares hooks +attach to its quantized linears, accumulate during normal generations, +persist, and go inert. Persist fires when every layer reaches the token +quota, or at a bounded number of denoiser forwards for models where some +projections take pooled or modulation vectors (a few tokens per forward) +and could never reach an absolute quota; layers still under a small token +floor at the deadline are omitted and stay on plain truncation. Cached +statistics load at model load and sit on each layer as ``sdnq_calib_rms``; +the hosting path reads them through ``rms_for``. Capture is skipped when +the model is compiled (hooks would break the graph) and everything is +gated by the ``lora_sdnq_host_calib`` option. +""" + +import os +from typing import Optional, TypedDict + +import torch + +from modules import paths, shared, script_callbacks +from modules.logger import log + + +class CaptureRecord(TypedDict): + m: torch.nn.Module + ss: Optional[torch.Tensor] + n: int + done: bool + + +class CaptureState(TypedDict): + model: Optional[str] + recs: dict[str, CaptureRecord] + handles: list[torch.utils.hooks.RemovableHandle] + forwards: int + complete: bool + + +TOKENS_DONE = 65536 +FORWARDS_DEADLINE = 48 # ~2 generations; token-rich layers normally finish their quota well inside it +TOKENS_FLOOR = 32 # below this mass the rms estimate is noise; the layer is omitted and stays on plain truncation +calib_root = os.path.join(paths.models_path, 'calibration') +capture: CaptureState = {'model': None, 'recs': {}, 'handles': [], 'forwards': 0, 'complete': False} + + +def enabled(): + return bool(getattr(shared.opts, 'lora_sdnq_host_calib', False)) + + +def calib_file(model_name): + key = model_name.replace('/', '--').replace('\\', '--').replace(':', '-') + return os.path.join(calib_root, f'{key}.safetensors') + + +def checkpoint_name(sd_model): + info = getattr(sd_model, 'sd_checkpoint_info', None) + return getattr(info, 'name', None) + + +def denoiser_root(sd_model): + """The model's denoiser component, transformer first, unet otherwise.""" + root = getattr(sd_model, 'transformer', None) + return root if root is not None else getattr(sd_model, 'unet', None) + + +def eligible_modules(sd_model): + """Sub-8-bit 2-D SDNQ linears of the model's denoiser: the layers hosting applies to.""" + root = denoiser_root(sd_model) + if root is None: + return [] + from sdnq.common import dtype_dict + out = [] + for name, m in root.named_modules(): + deq = getattr(m, 'sdnq_dequantizer', None) + if deq is None or len(deq.original_shape) != 2: + continue + if dtype_dict[deq.weights_dtype]['num_bits'] >= 8: + continue + out.append((name, m)) + return out + + +def detach_capture(): + for h in capture['handles']: + h.remove() + capture['handles'].clear() + capture['recs'].clear() + capture['model'] = None + capture['forwards'] = 0 + capture['complete'] = False + + +def deadline_hook(module, hook_args): # pylint: disable=unused-argument + """Count denoiser forwards and close capture at the deadline. + + Layers taking pooled or modulation vectors see a few tokens per forward + and can never reach the token quota; a global forward count bounds + capture for them and for modules the generation path never runs. + """ + if capture['complete']: + return + capture['forwards'] += 1 + if capture['forwards'] >= FORWARDS_DEADLINE: + persist() + + +def hook_for(rec, in_features): + def hook(module, hook_args): # pylint: disable=unused-argument + if rec['done'] or capture['complete']: + return + x = hook_args[0] if hook_args else None + if not torch.is_tensor(x) or x.shape[-1] != in_features: + return + ss = x.detach().reshape(-1, in_features).float().square().sum(dim=0) + if rec['ss'] is None: + rec['ss'] = ss + else: + if rec['ss'].device != ss.device: # offload moves blocks between devices mid-run + rec['ss'] = rec['ss'].to(ss.device) + rec['ss'] += ss + rec['n'] += x.numel() // in_features + if rec['n'] >= TOKENS_DONE: + rec['done'] = True + if all(r['done'] for r in capture['recs'].values()): + persist() + return hook + + +def persist(): + """Write accumulated statistics and stamp them onto the layers. + + Runs from the last hook to complete its quota or from the forward + deadline, inside a forward; the write is a few MB once per checkpoint + ever. Layers under the token floor are omitted rather than saved with + meaningless statistics. Handles stay registered but inert until the + next safe point removes them (hook removal here would mutate the hook + dict the forward is iterating). + """ + if capture['complete']: + return + capture['complete'] = True + from safetensors.torch import save_file + tensors, min_n = {}, None + for name, rec in capture['recs'].items(): + if rec['ss'] is None or rec['n'] < TOKENS_FLOOR: + continue + rms = (rec['ss'] / rec['n']).sqrt().float().cpu().contiguous().clone() + tensors[name] = rms + rec['m'].sdnq_calib_rms = rms + min_n = rec['n'] if min_n is None else min(min_n, rec['n']) + if not tensors: + log.warning(f'Network calibration: model="{capture["model"]}" no layer reached {TOKENS_FLOOR} tokens; nothing saved') + return + path = calib_file(capture['model']) + try: + os.makedirs(calib_root, exist_ok=True) + save_file(tensors, path, metadata={'version': '1', 'model': capture['model'], 'tokens': str(min_n)}) + log.info(f'Network calibration: model="{capture["model"]}" layers={len(tensors)}/{len(capture["recs"])} tokens={min_n} saved="{path}"') + except Exception as e: + log.warning(f'Network calibration: save failed path="{path}" {e}') + + +def maybe_detach(): + """Remove inert hooks once capture finished; safe only outside a model forward.""" + if capture['complete'] and capture['handles']: + detach_capture() + + +def load_stats(model_name, modules_list): + from safetensors import safe_open + path = calib_file(model_name) + loaded = 0 + with safe_open(path, framework='pt', device='cpu') as f: + keys = set(f.keys()) + for name, m in modules_list: + if name in keys: + m.sdnq_calib_rms = f.get_tensor(name) + loaded += 1 + log.info(f'Network calibration: model="{model_name}" layers={loaded} loaded="{path}"') + + +def on_model_loaded(sd_model): + detach_capture() + if not enabled(): + return + name = checkpoint_name(sd_model) + if name is None: + return + modules_list = eligible_modules(sd_model) + if len(modules_list) == 0: + return + if os.path.isfile(calib_file(name)): + load_stats(name, modules_list) + return + if 'Model' in (getattr(shared.opts, 'cuda_compile', None) or []): + return # hooks inside a compiled module graph-break or misbehave; skip capture entirely + capture['model'] = name + capture['handles'].append(denoiser_root(sd_model).register_forward_pre_hook(deadline_hook)) + for mod_name, m in modules_list: + rec = {'m': m, 'ss': None, 'n': 0, 'done': False} + capture['recs'][mod_name] = rec + capture['handles'].append(m.register_forward_pre_hook(hook_for(rec, int(m.sdnq_dequantizer.original_shape[-1])))) + log.info(f'Network calibration: model="{name}" layers={len(modules_list)} collecting activation statistics') + + +def rms_for(layer): + """Per-channel input RMS for a layer, or None when absent or disabled.""" + maybe_detach() + if not enabled(): + return None + return getattr(layer, 'sdnq_calib_rms', None) + + +script_callbacks.on_model_loaded(on_model_loaded) diff --git a/modules/lora/lora_common.py b/modules/lora/lora_common.py index 7f171846b..51d70fdbf 100644 --- a/modules/lora/lora_common.py +++ b/modules/lora/lora_common.py @@ -1,6 +1,6 @@ import os from modules.lora import lora_timers -from modules.lora import network_lora, network_hada, network_ia3, network_oft, network_lokr, network_full, network_norm, network_glora +from modules.lora import network_lora, network_hada, network_ia3, network_oft, network_boft, network_lokr, network_full, network_norm, network_glora timer = lora_timers.Timer() @@ -9,6 +9,7 @@ module_types = [ network_lora.ModuleTypeLora(), network_hada.ModuleTypeHada(), network_ia3.ModuleTypeIa3(), + network_boft.ModuleTypeBOFT(), # ahead of oft, which claims any oft_blocks key without checking its rank network_oft.ModuleTypeOFT(), network_lokr.ModuleTypeLokr(), network_full.ModuleTypeFull(), @@ -18,3 +19,5 @@ module_types = [ loaded_networks: list = [] # no type due to circular import previously_loaded_networks: list = [] # no type due to circular import extra_network_lora = None # initialized in extra_networks.py +last_backup_size: int = 0 # bytes of weight backups the last activate pass held +last_mode: str = '' # how that pass left the weights: backup, fuse or factor diff --git a/modules/lora/lora_convert.py b/modules/lora/lora_convert.py index 48c1b09b3..2e565b183 100644 --- a/modules/lora/lora_convert.py +++ b/modules/lora/lora_convert.py @@ -136,8 +136,9 @@ class KeyConvert: sd_module = shared.sd_model.network_layer_mapping.get(flat_key, None) if sd_module is not None: key = flat_key - if debug and sd_module is None: - raise RuntimeError(f"LoRA key not found in network_layer_mapping: key={key} mapping={shared.sd_model.network_layer_mapping.keys()}") + if sd_module is None: + if debug: + raise RuntimeError(f"LoRA key not found in network_layer_mapping: key={key} mapping={shared.sd_model.network_layer_mapping.keys()}") return key, sd_module @@ -486,28 +487,35 @@ def assign_network_names_to_compvis_modules(sd_model): sd_model = getattr(shared.sd_model, "pipe", shared.sd_model) # wrapped model compatibility network_layer_mapping = {} if hasattr(sd_model, 'text_encoder') and sd_model.text_encoder is not None: - for name, module in sd_model.text_encoder.named_modules(): + for name, module in sd_model.text_encoder.named_modules() : prefix = "lora_te1_" if hasattr(sd_model, 'text_encoder_2') else "lora_te_" network_name = prefix + name.replace(".", "_") network_layer_mapping[network_name] = module module.network_layer_name = network_name - if hasattr(sd_model, 'text_encoder_2'): + if hasattr(sd_model, 'text_encoder_2') and sd_model.text_encoder_2 is not None: for name, module in sd_model.text_encoder_2.named_modules(): network_name = "lora_te2_" + name.replace(".", "_") network_layer_mapping[network_name] = module module.network_layer_name = network_name - if hasattr(sd_model, 'unet'): + if hasattr(sd_model, 'unet') and sd_model.unet is not None: for name, module in sd_model.unet.named_modules(): network_name = "lora_unet_" + name.replace(".", "_") network_layer_mapping[network_name] = module module.network_layer_name = network_name - if hasattr(sd_model, 'transformer'): + if hasattr(sd_model, 'transformer') and sd_model.transformer is not None: for name, module in sd_model.transformer.named_modules(): network_name = "lora_transformer_" + name.replace(".", "_") network_layer_mapping[network_name] = module if "norm" in network_name and "linear" not in network_name and shared.sd_model_type != "sd3": continue module.network_layer_name = network_name + if hasattr(sd_model, 'transformer_ref') and sd_model.transformer_ref is not None: + for name, module in sd_model.transformer_ref.named_modules(): + network_name = "lora_transformer_" + name.replace(".", "_") + network_layer_mapping[network_name] = module + if "norm" in network_name and "linear" not in network_name and shared.sd_model_type != "sd3": + continue + module.network_layer_name = network_name if hasattr(sd_model, 'llm_adapter') and sd_model.llm_adapter is not None: for name, module in sd_model.llm_adapter.named_modules(): network_name = "lora_llm_adapter_" + name.replace(".", "_") diff --git a/modules/lora/lora_diffusers.py b/modules/lora/lora_diffusers.py index 94ad716c7..96c6d110f 100644 --- a/modules/lora/lora_diffusers.py +++ b/modules/lora/lora_diffusers.py @@ -4,6 +4,7 @@ import diffusers from modules import shared, errors from modules.logger import log from modules.lora import network +from modules.lora import lora_overrides from modules.lora import lora_common as l @@ -53,27 +54,30 @@ def load_per_module(sd_model: diffusers.DiffusionPipeline, filename: str, adapte def load_diffusers(name: str, network_on_disk: network.NetworkOnDisk, lora_scale:float=shared.opts.extra_networks_default_multiplier, lora_module=None, reason: str = '') -> network.Network | None: t0 = time.time() name = name.replace(".", "_") + reason = 'unknown' if reason is None or len(reason) == 0 else reason sd_model: diffusers.DiffusionPipeline = getattr(shared.sd_model, "pipe", shared.sd_model) - log.debug(f'Network load: type=LoRA name="{name}" file="{network_on_disk.filename}" detected={network_on_disk.sd_version} method=diffusers reason={reason or "unknown"} scale={lora_scale} fuse={shared.opts.lora_fuse_native}:{shared.opts.lora_fuse_diffusers}') + log.debug(f'Network load: type=LoRA name="{name}" file="{network_on_disk.filename}" detected={network_on_disk.sd_version} method=diffusers reason="{reason}" scale={lora_scale} fuse={lora_overrides.fuse_native()}:{shared.opts.lora_fuse_diffusers}') if not hasattr(sd_model, 'load_lora_weights'): - log.error(f'Network load: type=LoRA class={sd_model.__class__} does not implement load lora') + log.error(f'Network load: type=LoRA class={sd_model.__class__} method=diffusersdoes not implement load lora') return None try: if lora_module is not None and isinstance(lora_module, list) and len(lora_module) > 0: name = load_per_module(sd_model, network_on_disk.filename, adapter_name=name, lora_modules=lora_module) sd_model._lora_partial = True # pylint: disable=protected-access else: + if shared.sd_model_type in ['sd', 'sdxl']: # skip te to avoid errors when lora does not have te to start with + diffusers.loaders.lora_pipeline._load_lora_into_text_encoder = lambda *args, **kwargs: None # pylint: disable=protected-access sd_model.load_lora_weights(network_on_disk.filename, adapter_name=name) except Exception as e: if 'already in use' in str(e): pass else: if 'following keys have not been correctly renamed' in str(e): - log.error(f'Network load: type=LoRA name="{name}" diffusers unsupported format') + log.error(f'Network load: type=LoRA name="{name}" method=diffusers unsupported format') elif 'object has no attribute' in str(e): - log.error(f'Network load: type=LoRA name="{name}" diffusers empty module') + log.error(f'Network load: type=LoRA name="{name}" method=diffusers empty module') else: - log.error(f'Network load: type=LoRA name="{name}" {e}') + log.error(f'Network load: type=LoRA name="{name}" method=diffusers {e}') if l.debug: errors.display(e, "LoRA") return None @@ -83,7 +87,7 @@ def load_diffusers(name: str, network_on_disk: network.NetworkOnDisk, lora_scale list_adapters = sd_model.get_list_adapters() list_adapters = [adapter for adapters in list_adapters.values() for adapter in adapters] if name not in list_adapters: - log.error(f'Network load: type=LoRA name="{name}" adapters={list_adapters} not loaded') + log.error(f'Network load: type=LoRA name="{name}" method=diffusers adapters={list_adapters} not loaded') else: diffuser_loaded.append(name) diffuser_scales.append(lora_scale) diff --git a/modules/lora/lora_factor_cache.py b/modules/lora/lora_factor_cache.py new file mode 100644 index 000000000..1da7106c6 --- /dev/null +++ b/modules/lora/lora_factor_cache.py @@ -0,0 +1,250 @@ +"""Disk cache for hosted svd factors. + +Hosting a non-factorable adapter set costs one truncated svd per targeted +layer (tens of ms each, seconds per file) every time the set is applied +fresh. The resulting factors are deterministic in the checkpoint, the loaded +set (files, multipliers, dyn_dim), the host rank and the calibration +statistics, so they are cached on disk keyed by exactly that identity and +replayed bit-identically on the next apply of the same configuration. + +One safetensors file per configuration under ``models/lora-factor-cache``, +holding every hosted layer's post-rotation factor pair as rowwise int8 +with fp32 scales (measured fidelity-free in output space, half the bytes +of bf16). Files are named by the model and network set with an +identity-hash suffix, and the exact signature is embedded in the file +metadata. Factors are quantized before first use: ``store`` returns the +dequantized round-trip for the caller to apply, so a fresh compute and a +later cache hit attach bit-identical tensors. The ``lora_sdnq_host_cache`` +option is the size budget in GB (0 disables); least-recently-used entries +are evicted past the budget. Any doubt about identity (unknown checkpoint, +unreadable lora file, signature mismatch) disables caching for the pass +rather than risking a stale hit. +""" + +import os +import json +import hashlib + +import torch + +from modules import paths, shared +from modules.lora import lora_common as l +from modules.logger import log + + +cache_root = os.path.join(paths.models_path, 'lora-factor-cache') +state = {'wn': None, 'sig': None, 'path': None, 'store': {}, 'dirty': False, 'hits': 0, 'misses': 0} +FMT = '5' # bump on entry-layout changes so older files recompute instead of replaying short + + +def budget_gb(): + try: + return float(getattr(shared.opts, 'lora_sdnq_host_cache', 0) or 0) + except Exception: + return 0.0 + + +def signature(wanted_names): + """Content identity of a hosted-apply configuration, or None when caching is unsafe.""" + from modules.lora import lora_calib + model_name = lora_calib.checkpoint_name(getattr(shared, 'sd_model', None)) + if model_name is None: + return None + calib_path = lora_calib.calib_file(model_name) + from modules.lora import lora_stack + parts = { + 'model': model_name, + 'rank': int(getattr(shared.opts, 'lora_sdnq_host_rank', 0) or 0), + 'calib': int(os.path.getmtime(calib_path)) if lora_calib.enabled() and os.path.isfile(calib_path) else None, # the toggle is part of the identity: factors computed under the other setting must not replay + 'stack': lora_stack.signature(), + 'nets': [], + } + from modules.lora import lora_blocks + for name, te, unet, dyn in wanted_names: + net = next((n for n in l.loaded_networks if n.name == name), None) + filename = getattr(getattr(net, 'network_on_disk', None), 'filename', None) + try: + st = os.stat(filename) + except Exception: + return None + entry = [name, repr(te), repr(unet), repr(dyn), filename, int(st.st_mtime), st.st_size] + spec = lora_blocks.net_signature(net) + if spec is not None: # appended only when set so existing cache files stay valid without block weights + entry.append(spec) + parts['nets'].append(entry) + return parts + + +def label(parts): + """Filename prefix from the model and net names, so the cache folder reads without tooling.""" + names = [parts['model'].replace('\\', '/').split('/')[-1]] + [n[0] for n in parts['nets']] + text = '-'.join(names) + text = ''.join(c if c.isalnum() or c in '._-' else '-' for c in text) + return text[:96] + + +def begin_pass(wanted_names): + """Bind the pass to its cache entry; identity-memoized on the wanted_names tuple.""" + if wanted_names is state['wn']: + return + state['wn'] = wanted_names + state.update(sig=None, path=None, dirty=False) + state['store'] = {} + if budget_gb() <= 0 or wanted_names == (): + return + parts = signature(wanted_names) + if parts is None: + return + sig = json.dumps(parts, sort_keys=True) + key = hashlib.sha256(sig.encode()).hexdigest()[:24] + path = os.path.join(cache_root, f'{label(parts)}-{key}.safetensors') + entries = {} + if os.path.isfile(path): + try: + from safetensors import safe_open + with safe_open(path, framework='pt', device='cpu') as f: + meta = f.metadata() or {} + if meta.get('sig') == sig and meta.get('fmt') == FMT: + for k in f.keys(): + entries[k] = f.get_tensor(k) + os.utime(path, None) # freshness for LRU eviction + except Exception as e: + log.debug(f'Network cache: read failed path="{path}" {e}') + entries = {} + state.update(sig=sig, path=path) + state['store'] = entries + log.debug(f'Network cache: entry="{path}" keys={len(entries)}') + + +def quantize_rowwise(t): + t32 = t.detach().to(torch.float32) + scale = t32.abs().amax(dim=1, keepdim=True).clamp(min=1e-12) / 127.0 + q = (t32 / scale).round().clamp(-127, 127).to(torch.int8) + return q, scale + + +def dequantize_rowwise(q, scale): + # int8 * fp32 with a single fp32 rounding: identical on any device, so hit and miss replay the same values + return q.to(torch.float32) * scale + + +def lookup(network_layer_name): + """Cached (up, down, energy, calibrated, rms) for a layer, or None; factors return as fp32. + + Pure lookup with no hit/miss accounting: the fast-path probe uses it so a + layer is only counted once, by whichever caller consumes the answer. + """ + if state['sig'] is None: + return None + st = state['store'] + up_q, up_s = st.get(f'{network_layer_name}.up_q'), st.get(f'{network_layer_name}.up_s') + down_q, down_s = st.get(f'{network_layer_name}.down_q'), st.get(f'{network_layer_name}.down_s') + energy = st.get(f'{network_layer_name}.energy') + calib = st.get(f'{network_layer_name}.calib') + rms = st.get(f'{network_layer_name}.rms') + if up_q is None or up_s is None or down_q is None or down_s is None or energy is None or calib is None or rms is None: + return None + return dequantize_rowwise(up_q, up_s), dequantize_rowwise(down_q, down_s), float(energy), bool(calib), float(rms) + + +def note_hit(): + state['hits'] += 1 + + +def fetch(network_layer_name): + """``lookup`` with accounting: a usable entry counts a hit, anything else a miss.""" + entry = lookup(network_layer_name) + if entry is None: + if state['sig'] is not None: + state['misses'] += 1 + return None + state['hits'] += 1 + return entry + + +def lookup_scores(network_layer_name): + """Cached select scores for a layer as ((s0, s1), (a0, a1)), or None. + + Score records ride the same signature-keyed entry as factors, and the + signature already pins everything the scores depend on (pair, multipliers, + stack mode and params). No hit/miss accounting: a record saves scoring and + delta assembly, not a sketch. + """ + if state['sig'] is None: + return None + t = state['store'].get(f'{network_layer_name}.sel') + if t is None: + return None + return (float(t[0]), float(t[1])), (float(t[2]), float(t[3])) + + +def store_scores(network_layer_name, scores, abs_sums): + """Persist a select-mode score record; additive to the entry, older files upgrade on their next pass.""" + if state['sig'] is None: + return + state['store'][f'{network_layer_name}.sel'] = torch.tensor([scores[0], scores[1], abs_sums[0], abs_sums[1]], dtype=torch.float64) + state['dirty'] = True + + +def store(network_layer_name, up, down, energy, calibrated, rms): + """Quantize-before-use: returns the dequantized round-trip the caller must apply. + + The factors quantize to rowwise int8 whether or not a cache entry can be + written, so the factors applied now, the factors a later hit replays, and a + cache-off apply are the same tensors (the round-trip also zeroes null-tail + columns the attach-side trim relies on). ``rms`` is the assembled delta's + rms, kept so replays can evaluate the requantize routing rule without + assembling the delta. + """ + up_q, up_s = quantize_rowwise(up) + down_q, down_s = quantize_rowwise(down) + if state['sig'] is not None: + st = state['store'] + st[f'{network_layer_name}.up_q'] = up_q.to('cpu').contiguous() + st[f'{network_layer_name}.up_s'] = up_s.to('cpu').contiguous() + st[f'{network_layer_name}.down_q'] = down_q.to('cpu').contiguous() + st[f'{network_layer_name}.down_s'] = down_s.to('cpu').contiguous() + st[f'{network_layer_name}.energy'] = torch.tensor(float(energy)) + st[f'{network_layer_name}.calib'] = torch.tensor(1 if calibrated else 0, dtype=torch.uint8) + st[f'{network_layer_name}.rms'] = torch.tensor(float(rms)) + state['dirty'] = True + return dequantize_rowwise(up_q, up_s).to(up.dtype), dequantize_rowwise(down_q, down_s).to(down.dtype) + + +def evict(): + budget = budget_gb() * 2**30 + try: + files = [os.path.join(cache_root, f) for f in os.listdir(cache_root) if f.endswith('.safetensors')] + sizes = {p: os.path.getsize(p) for p in files} + except Exception: + return + total = sum(sizes.values()) + for p in sorted(files, key=os.path.getmtime): + if total <= budget: + break + if p == state['path']: + continue # never evict the entry of the live pass + try: + os.remove(p) + total -= sizes[p] + except Exception: + pass + + +def flush(): + """Persist a dirty pass store; returns (hits, misses) since the last flush.""" + hits, misses = state['hits'], state['misses'] + state['hits'] = state['misses'] = 0 + if not state['dirty'] or state['path'] is None: + return hits, misses + state['dirty'] = False + try: + from safetensors.torch import save_file + os.makedirs(cache_root, exist_ok=True) + tmp = state['path'] + '.tmp' + save_file(state['store'], tmp, metadata={'sig': state['sig'], 'fmt': FMT}) + os.replace(tmp, state['path']) + evict() + except Exception as e: + log.warning(f'Network cache: write failed path="{state["path"]}" {e}') + return hits, misses diff --git a/modules/lora/lora_load.py b/modules/lora/lora_load.py index 7993ffe9a..0fcc2dc34 100644 --- a/modules/lora/lora_load.py +++ b/modules/lora/lora_load.py @@ -28,6 +28,7 @@ NATIVE_DISPATCH = { 'f2': 'pipelines.flux.flux2_lora', 'anima': 'pipelines.anima.anima_lora', 'krea2': 'pipelines.krea2.krea2_lora', + 'minimaxh3': 'pipelines.minimax.minimax_lora', } @@ -55,12 +56,19 @@ def lora_dump(lora, dct): def load_safetensors(name, network_on_disk: network.NetworkOnDisk) -> network.Network | None: if not shared.sd_loaded: return None - sd_model = getattr(shared.sd_model, "pipe", shared.sd_model) + + # cached cached = lora_cache.get(name, None) if cached is not None: + if l.debug: + log.trace(f'LoRA: load name="{name}" fn="{network_on_disk.filename}" cache=True') return cached + + # native dispatch native_module = NATIVE_DISPATCH.get(shared.sd_model_type) + if l.debug: + log.trace(f'LoRA: load name="{name}" fn="{network_on_disk.filename}" native={native_module}') if native_module is not None: import importlib mod = importlib.import_module(native_module) @@ -68,6 +76,10 @@ def load_safetensors(name, network_on_disk: network.NetworkOnDisk) -> network.Ne if net is not None: lora_cache[name] = net return net + + # fallback to standard network loading + if l.debug: + log.trace(f'LoRA: load name="{name}" network_on_disk="{network_on_disk.filename}" safetensors') net = network.Network(name, network_on_disk) net.mtime = os.path.getmtime(network_on_disk.filename) state_dict = sd_models.read_state_dict(network_on_disk.filename, what='network') @@ -95,7 +107,7 @@ def load_safetensors(name, network_on_disk: network.NetworkOnDisk) -> network.Ne emb_dict[vec_name] = weight bundle_embeddings[emb_name] = emb_dict continue - if parts[0] in ["clip_l","clip_g","t5","unet","transformer"]: + if parts[0] in ["clip_l", "clip_g", "t5", "unet", "transformer", "transformer_2"]: network_part = [] while parts and parts[-1] in ["alpha","weight","lora_up","lora_down"]: network_part.insert(0,parts[-1]) @@ -107,7 +119,6 @@ def load_safetensors(name, network_on_disk: network.NetworkOnDisk) -> network.Ne if key_network_without_network_parts.startswith("unet") or key_network_without_network_parts.startswith("transformer"): key_network_without_network_parts = "lora_" + key_network_without_network_parts key_network_without_network_parts = key_network_without_network_parts.replace("clip_g","lora_te2").replace("clip_l","lora_te") - # TODO lora: add t5 key support for sd35/f1 elif len(parts) > 5: # messy handler for diffusers peft lora key_network_without_network_parts = '_'.join(parts[:-2]) @@ -147,9 +158,9 @@ def load_safetensors(name, network_on_disk: network.NetworkOnDisk) -> network.Ne if len(keys_failed_to_match) > 0: log.warning(f'Network load: type=LoRA name="{name}" type={set(network_types)} unmatched={len(keys_failed_to_match)} matched={len(matched_networks)}') if l.debug: - log.debug(f'Network load: type=LoRA name="{name}" unmatched={keys_failed_to_match}') + log.trace(f'Network load: type=LoRA name="{name}" unmatched={keys_failed_to_match}') else: - log.debug(f'Network load: type=LoRA name="{name}" type={set(network_types)} keys={len(matched_networks)} dtypes={dtypes} fuse={shared.opts.lora_fuse_native}:{shared.opts.lora_fuse_diffusers}') + log.debug(f'Network load: type=LoRA name="{name}" type={set(network_types)} keys={len(matched_networks)} dtypes={dtypes} fuse={lora_overrides.fuse_native()}:{shared.opts.lora_fuse_diffusers}') if len(matched_networks) == 0: return None lora_cache[name] = net @@ -172,26 +183,61 @@ def maybe_recompile_model(names, te_multipliers): if not recompile_model: skip_lora_load = True if len(l.loaded_networks) > 0 and l.debug: - log.debug('Model Compile: Skipping LoRa loading') + log.trace('LoRA: recompile required, skip loading') return recompile_model, skip_lora_load else: recompile_model = True shared.compiled_model_state.lora_model = [] + if l.debug: + log.trace(f'LoRA recompile check: task={sd_models.get_diffusers_task(shared.sd_model)} recompile={recompile_model} load={skip_lora_load}') if recompile_model: current_task = sd_models.get_diffusers_task(shared.sd_model) log.debug(f'Compile: task={current_task} force model reload') backup_cuda_compile = shared.opts.cuda_compile backup_scheduler = getattr(sd_model, "scheduler", None) + backup_loaded_loras = getattr(sd_model, "loaded_loras", None) # reload below replaces shared.sd_model with a new pipe object sd_models.unload_model_weights(op='model') - shared.opts.cuda_compile = [] + shared.opts.cuda_compile = ['LoRA'] # if its empty, it will be overridden by set_openvino_overrides() to ['Model'] which is not what we want sd_models.reload_model_weights(op='model') shared.sd_model = sd_models.set_diffuser_pipe(shared.sd_model, current_task) shared.opts.cuda_compile = backup_cuda_compile + new_sd_model = getattr(shared.sd_model, "pipe", shared.sd_model) # scheduler/cache must be reapplied to the new object, not the discarded one if backup_scheduler is not None: - sd_model.scheduler = backup_scheduler + new_sd_model.scheduler = backup_scheduler + if backup_loaded_loras is not None: + new_sd_model.loaded_loras = backup_loaded_loras + from modules import processing_diffusers # pylint: disable=import-outside-toplevel + processing_diffusers.orig_pipeline = shared.sd_model # otherwise process_diffusers() restores the pre-recompile pipeline once generation ends return recompile_model, skip_lora_load +def add_network(filename): + """Register one network file in the available-network tables.""" + if not os.path.isfile(filename): + return + name = os.path.splitext(os.path.basename(filename))[0] + name = name.replace('.', '_') + try: + entry = network.NetworkOnDisk(name, filename) + available_networks[entry.name] = entry + if entry.alias in available_network_aliases: + forbidden_network_aliases[entry.alias.lower()] = 1 + available_network_aliases[entry.name] = entry + if entry.fullname != entry.name: + available_network_aliases[entry.fullname] = entry + # entry.name mangles dots to underscores for legacy reasons and entry.fullname + # carries any subfolder prefix, so neither matches when the user types the file's + # natural basename. setdefault avoids clobbering an explicit primary entry when + # two files in different subfolders share a basename. + basename_alias = os.path.splitext(os.path.basename(filename))[0] + if basename_alias and basename_alias not in (entry.name, entry.fullname): + available_network_aliases.setdefault(basename_alias, entry) + if entry.shorthash: + available_network_hash_lookup[entry.shorthash] = entry + except OSError as e: # should catch FileNotFoundError and PermissionError etc. + log.error(f'LoRA: filename="{filename}" {e}') + + def list_available_networks(): t0 = time.time() available_networks.clear() @@ -202,31 +248,6 @@ def list_available_networks(): if not os.path.exists(shared.cmd_opts.lora_dir): log.warning(f'LoRA directory not found: path="{shared.cmd_opts.lora_dir}"') - def add_network(filename): - if not os.path.isfile(filename): - return - name = os.path.splitext(os.path.basename(filename))[0] - name = name.replace('.', '_') - try: - entry = network.NetworkOnDisk(name, filename) - available_networks[entry.name] = entry - if entry.alias in available_network_aliases: - forbidden_network_aliases[entry.alias.lower()] = 1 - available_network_aliases[entry.name] = entry - if entry.fullname != entry.name: - available_network_aliases[entry.fullname] = entry - # entry.name mangles dots to underscores for legacy reasons and entry.fullname - # carries any subfolder prefix, so neither matches when the user types the file's - # natural basename. setdefault avoids clobbering an explicit primary entry when - # two files in different subfolders share a basename. - basename_alias = os.path.splitext(os.path.basename(filename))[0] - if basename_alias and basename_alias not in (entry.name, entry.fullname): - available_network_aliases.setdefault(basename_alias, entry) - if entry.shorthash: - available_network_hash_lookup[entry.shorthash] = entry - except OSError as e: # should catch FileNotFoundError and PermissionError etc. - log.error(f'LoRA: filename="{filename}" {e}') - candidates = sorted(files_cache.list_files(shared.cmd_opts.lora_dir, ext_filter=[".pt", ".ckpt", ".safetensors"])) with concurrent.futures.ThreadPoolExecutor(max_workers=shared.max_workers) as executor: for fn in candidates: @@ -261,7 +282,7 @@ def gather_networks(names): return networks_on_disk -def network_load(names, te_multipliers=None, unet_multipliers=None, dyn_dims=None, lora_modules=None, activate=True): +def network_load(names, te_multipliers=None, unet_multipliers=None, dyn_dims=None, lora_modules=None, block_specs=None, activate=True): networks_on_disk = gather_networks(names) failed_to_load_networks = [] recompile_model, skip_lora_load = maybe_recompile_model(names, te_multipliers) @@ -277,7 +298,7 @@ def network_load(names, te_multipliers=None, unet_multipliers=None, dyn_dims=Non if network_on_disk is not None: shorthash = getattr(network_on_disk, 'shorthash', '').lower() if l.debug: - log.debug(f'Network load: type=LoRA name="{name}" file="{network_on_disk.filename}" hash="{shorthash}" cached={name in lora_cache}') + log.trace(f'LoRA: name="{name}" fn="{network_on_disk.filename}" hash="{shorthash}" cached={name in lora_cache}') try: lora_scale = te_multipliers[i] if te_multipliers else shared.opts.extra_networks_default_multiplier lora_module = lora_modules[i] if lora_modules and len(lora_modules) > i else None @@ -301,6 +322,8 @@ def network_load(names, te_multipliers=None, unet_multipliers=None, dyn_dims=Non if net is None: failed_to_load_networks.append(name) lora_ver = network_on_disk.sd_version if network_on_disk is not None else None + if lora_ver is None or len(lora_ver) == 0: + lora_ver = "unknown" log.error(f'Network load: type=LoRA name="{name}" detected={lora_ver} not loaded') continue if hasattr(sd_model, 'embedding_db'): @@ -309,6 +332,7 @@ def network_load(names, te_multipliers=None, unet_multipliers=None, dyn_dims=Non 'te': te_multipliers[i] if te_multipliers else shared.opts.extra_networks_default_multiplier, 'unet': unet_multipliers[i] if unet_multipliers else shared.opts.extra_networks_default_multiplier, 'dyn': dyn_dims[i] if dyn_dims else None, # a multiplier is not a rank; float dyn_dim crashes every consumer that slices with it + 'blocks': block_specs[i] if block_specs and len(block_specs) > i else None, } l.loaded_networks.append(net) @@ -321,8 +345,8 @@ def network_load(names, te_multipliers=None, unet_multipliers=None, dyn_dims=Non try: t1 = time.time() if l.debug: - log.trace(f'Network load: type=LoRA list={sd_model.get_list_adapters()}') - log.trace(f'Network load: type=LoRA active={sd_model.get_active_adapters()}') + log.trace(f'LoRA: list={sd_model.get_list_adapters()}') + log.trace(f'LoRA: active={sd_model.get_active_adapters()}') sd_model.set_adapters(adapter_names=lora_diffusers.diffuser_loaded, adapter_weights=lora_diffusers.diffuser_scales) sd_model.enable_lora() # set_adapters does not clear the disabled flag left by a prior removal except Exception as e: @@ -333,7 +357,7 @@ def network_load(names, te_multipliers=None, unet_multipliers=None, dyn_dims=Non try: if shared.opts.lora_fuse_diffusers and not lora_overrides.disable_fuse(): sd_model.fuse_lora(adapter_names=lora_diffusers.diffuser_loaded, lora_scale=1.0, fuse_unet=True, fuse_text_encoder=True) # diffusers with fuse uses fixed scale since later apply does the scaling - sd_model.unload_lora_weights() + # sd_model.unload_lora_weights() # optionally unload fused lora as we dont need it, but it may cause issues with some models l.timer.activate += time.time() - t1 except Exception as e: log.error(f'Network load: type=LoRA action=fuse {str(e)}') @@ -350,10 +374,10 @@ def network_load(names, te_multipliers=None, unet_multipliers=None, dyn_dims=Non networks.network_activate() if len(l.loaded_networks) > 0 and l.debug: - log.debug(f'Network load: type=LoRA loaded={[n.name for n in l.loaded_networks]} cache={list(lora_cache)} fuse={shared.opts.lora_fuse_native}:{shared.opts.lora_fuse_diffusers}') + log.trace(f'LoRA: loaded={[n.name for n in l.loaded_networks]} cache={list(lora_cache)} fuse={lora_overrides.fuse_native()}:{shared.opts.lora_fuse_diffusers}') if recompile_model: - log.info("Network load: type=LoRA recompiling model") + log.info("Network load: type=LoRA model recompile required") if shared.compiled_model_state is not None: backup_lora_model = shared.compiled_model_state.lora_model else: diff --git a/modules/lora/lora_nunchaku.py b/modules/lora/lora_nunchaku.py index 1fc8ff9b1..b7499387e 100644 --- a/modules/lora/lora_nunchaku.py +++ b/modules/lora/lora_nunchaku.py @@ -1,12 +1,19 @@ import time from modules import shared, errors from modules.logger import log -from modules.lora import lora_load, lora_common +from modules.lora import lora_load, lora_common, network previously_loaded = [] # we maintain private state here +def wrap_network(network_on_disk): + net = network.Network(network_on_disk.name, network_on_disk) + net.mentioned_name = network_on_disk.name + network_on_disk.read_hash() # nothing else on this path fills the hash infotext reads + return net + + def load_nunchaku(names, strengths): global previously_loaded # pylint: disable=global-statement strengths = [s[0] if isinstance(s, list) else s for s in strengths] @@ -26,7 +33,7 @@ def load_nunchaku(names, strengths): from nunchaku.lora.flux.compose import compose_lora composed_lora = compose_lora(loras) shared.sd_model.transformer.update_lora_params(composed_lora) - lora_common.loaded_networks = [n[0] for n in networks] # used by infotext + lora_common.loaded_networks[:] = [wrap_network(n[0]) for n in networks] # read by infotext and the trigger tags t1 = time.time() lora_common.timer.load = t1 - t0 log.debug(f"Network load: type=LoRA method=nunchaku loras={names} strength={strengths} time={t1-t0:.3f}") diff --git a/modules/lora/lora_overrides.py b/modules/lora/lora_overrides.py index 2d27f7b88..cad8b514a 100644 --- a/modules/lora/lora_overrides.py +++ b/modules/lora/lora_overrides.py @@ -1,4 +1,9 @@ +import os from modules import shared +from modules.logger import log + + +debug_log = log.trace if os.environ.get('SD_LORA_DEBUG', None) is not None else lambda *args, **kwargs: None force_hashes_diffusers = [ # forced always @@ -32,6 +37,7 @@ allow_native = [ 'anima', 'ernieimage', 'krea2', + 'minimaxh3', ] @@ -77,13 +83,70 @@ def get_method(shorthash=''): return 'native', 'default' +# Roles a LoRA is fused into; a quantized component in any of them makes fusing unsafe. +fuse_roots = ('transformer', 'unet', 'text_encoder', 'llm_adapter') + + +def fuse_components(sd_model): + """Component names a network fuses into, matched by role prefix so numbered and reference siblings are covered.""" + names = getattr(sd_model, 'components', None) + if not isinstance(names, dict): + names = vars(sd_model) + return [name for name in names if name.startswith(fuse_roots)] + + +def is_quantized(module): + """Return True when ``module`` carries a quantization config. + + ``config.quantization_config`` is read first: SDNQ sets both it and the plain + attribute when it quantizes in place, but a checkpoint that ships pre-quantized + only reaches the plain attribute through the diffusers ConfigMixin name proxy, + which is deprecated for removal. + """ + if module is None: + return False + config = getattr(module, 'config', None) + if config is not None and getattr(config, 'quantization_config', None) is not None: + return True + return getattr(module, 'quantization_config', None) is not None + + def disable_fuse(): - if hasattr(shared.sd_model, 'quantization_config'): + """Return True when fusing a network into model weights is unsafe. + + Fusing keeps no pristine copy of the weight, so each apply and restore + round-trips it through its storage format. On quantized weights that is a + dequantize-add-requantize cycle per network swap whose error compounds. + """ + from modules.lora import lora_common as l + from modules.lora import lora_stack + if lora_stack.select_possible(len(l.loaded_networks)) or lora_stack.select_engaged(): + debug_log('LoRA: fuse=False reason="active select mode"') + return True # select flips per-layer winners against the pristine backup; a dormant select mode leaves fuse alone + sd_model = getattr(shared.sd_model, 'pipe', shared.sd_model) + if is_quantized(sd_model): + debug_log('LoRA: fuse=False reason="model is quantized"') return True - if hasattr(shared.sd_model, 'transformer') and hasattr(shared.sd_model.transformer, 'quantization_config'): + if any(is_quantized(getattr(sd_model, name, None)) for name in fuse_components(sd_model)): + debug_log('LoRA: fuse=False reason="component is quantized"') return True - if hasattr(shared.sd_model, 'transformer_2') and hasattr(shared.sd_model.transformer_2, 'quantization_config'): + if hasattr(sd_model, '_lora_partial'): + debug_log('LoRA: fuse=False reason="partial lora applied"') return True - if hasattr(shared.sd_model, '_lora_partial'): + if shared.sd_model_type in fuse_ignore: + debug_log(f'LoRA: fuse=False reason="model type {shared.sd_model_type} in fuse_ignore"') return True - return shared.sd_model_type in fuse_ignore + return False + + +def fuse_native(): + """Return True when the native apply path may fuse into model weights. + + The single source of truth for the native fuse decision: it must agree across + the backup, activate and deactivate passes, since backup mode restores from a + stored tensor while fuse mode restores by subtracting the delta. + """ + result = shared.opts.lora_fuse_native and not disable_fuse() + force = os.environ.get('SD_LORA_FUSE', None) is not None + debug_log(f'LoRA: native fuse={result} force={force}') + return (result or force) diff --git a/modules/lora/lora_sdnq.py b/modules/lora/lora_sdnq.py new file mode 100644 index 000000000..94a5ab965 --- /dev/null +++ b/modules/lora/lora_sdnq.py @@ -0,0 +1,625 @@ +"""Exact LoRA application for SDNQ-quantized layers. + +Baking a LoRA into a quantized weight requantizes it: dequantize, add the +delta, re-round onto the integer grid. When the per-element delta is smaller +than half a quantization step (a rank-decomposed delta on a uint4 layer sits +at a few percent of a step), rounding erases it; what survives is the two +grid-extrema elements per quantization group (2/group_size of the signal) +plus grid-shift noise of the same norm as the delta. The optimal in-grid +representation provably retains ~0%, so no rewrite of the stored integers +can fix this. + +The exact path instead rides the SDNQ svd side-channel: the dequantizer +computes ``W = dq(q) + svd_up @ svd_down`` in the rotated domain at full +precision, in every forward mode. A LoRA delta ``B @ A`` is appended as +extra columns of ``svd_up`` and rows of ``svd_down``; because the Hadamard +rotation is block-diagonal, symmetric and self-inverse, storing ``A·H`` for +the down factor makes the round trip exact: ``(B @ (A·H)) · H = B @ A``. +Quantized weights are never touched, so apply and remove are exact and no +weight backup is needed. The side-channel storage is lossless; realized +fidelity floors at the compute dtype, because the dequantizer materializes +``base + factors`` in the result dtype and a delta below its ULP of the +base rounds exactly as it would on an unquantized model of that dtype. + +Only additive low-rank modules ride the channel exactly (plain LoRA: no +DoRA, no CP ``mid``, no LyCORIS dense-bias, no ``diff_b``). On sub-8-bit +formats, sets with non-factorable contributions are hosted instead: the +families' own ``calc_updown`` delta is truncated to its top singular +directions and appended the same way, stored at the delta's effective +rank when the spectrum ends in a numerically null tail (dense-combined +plain pairs, low-rank LyCORIS). Truncation keeps the dominant part +of the effect and drops an orthogonal residual, where requantize keeps +only the grid extrema and adds grid-shift noise of the delta's own +magnitude. When activation statistics for the checkpoint exist (see +``lora_calib``), the truncation is channel-weighted to minimize output +error instead of weight error. At 8 bits and above requantize retains +most of the delta, so hosting is skipped there and the requantize path +remains. + +A small tail of deltas inverts the tradeoff: when the delta is large +against the grid step AND the truncation genuinely cuts it, requantize +retains more than hosting drops, and the layer routes back to the +requantize path (``REQUANT_RATIO``/``REQUANT_ENERGY``). Both terms must +agree: a thin delta rounds away on the grid however low its capture, and +a low-rank delta hosts exactly however fat it is. +""" + +import torch + +from modules import devices, shared +from modules.lora import lora_calib, lora_factor_cache, lora_stack # lora_calib registers its model-load hook on import, so this one has to stay eager +from modules.lora import lora_common as l +from modules.logger import log + + +fallback_layers: list[str] = [] +hosted_layers: list[tuple[str, float, bool]] = [] +hosted_ranks: list[int] = [] +factor_layers: list[str] = [] +select_layers: list[str] = [] +routed_layers: list[str] = [] + +REQUANT_RATIO = 0.30 # delta rms over mean grid step above which requantize can retain the delta +REQUANT_ENERGY = 0.90 # sketch capture below which truncation genuinely loses part of it +NULL_TAIL_EPS = 1e-6 # spectrum tail below this fraction of the capture is numerically null; dropping it keeps stored rank at the delta's effective rank + +def rank_bucket(r): + """Fixed rank ladder for compiled-graph reuse: powers of two up to 256, multiples of 64 above (hosted rank plus exact members).""" + if r <= 8: + return 8 + if r <= 256: + return 1 << (r - 1).bit_length() + return -(-r // 64) * 64 + + +def pad_rank(t, dim, bucket): + if t.shape[dim] >= bucket: + return t + shape = list(t.shape) + shape[dim] = bucket - t.shape[dim] + return torch.cat([t, t.new_zeros(shape)], dim=dim) + + +def enabled(): + """True while the exact svd-channel machinery may take quantized layers; the requantize choice routes every layer to the legacy weight-rewrite path.""" + return getattr(shared.opts, 'lora_sdnq_apply', 'exact') != 'requantize' + + +def signature(): + """Identity suffix for the per-module apply stamp; empty on the default exact mechanism.""" + return '' if enabled() else '|quant=requantize' + + +def trim_null_tail(up_h, down_h): + """Cache entries stored before tail slicing carry null ranks as exact zero columns; trim to the effective rank on attach.""" + nz = (up_h != 0).any(dim=0) + if not bool(nz.all()): + k = max(1, int(nz.nonzero().max().item()) + 1) if bool(nz.any()) else 1 + if k < up_h.shape[1]: + return up_h[:, :k].contiguous(), down_h[:k].contiguous() + return up_h, down_h + + +def get_module_factors(module, device, dtype, original_shape=None): + """Return ``(up_eff, down)`` reproducing ``calc_updown`` exactly, or None. + + ``updown = up @ down * calc_scale() * multiplier()`` for a plain linear + LoRA; the scalars fold into the up factor. ``dyn_dim`` slices ranks the + same way ``lyco_helpers.rebuild_conventional`` does. + """ + if module.__class__.__name__ != 'NetworkModuleLora': + return None + if module.dora_scale is not None or module.bias is not None or module.ex_bias is not None: + return None + if getattr(module, 'mid_model', None) is not None: + return None + up = module.up_model.weight + down = module.down_model.weight + if up.ndim != 2 or down.ndim != 2: + return None + if original_shape is not None and (up.shape[0] != original_shape[0] or down.shape[1] != original_shape[-1]): + return None # factor_candidate skips shape checks for layers already in factor mode; recheck here so a malformed stack falls back instead of raising in cat + dyn_dim = module.network.dyn_dim + if dyn_dim is not None and up.shape[1] != dyn_dim: + up = up[:, :dyn_dim] + down = down[:dyn_dim] + scalar = module.calc_scale() * module.multiplier() + up_eff = up.to(device=device, dtype=torch.float32) * scalar + return up_eff.to(dtype=dtype), down.to(device=device, dtype=dtype) + + +def factor_candidate(self, network_layer_name, wanted_names): + """True when this layer should take the exact svd-append path. + + Requires an SDNQ linear layer whose active networks all contribute plain + factorable LoRA modules for this layer. An empty ``wanted_names`` is a + removal request and qualifies whenever factors are currently attached. + """ + if not enabled(): + return False # declined layers with factors still attached are stripped by the activate fallthrough + if getattr(self, 'sdnq_dequantizer', None) is None or self.__class__.__name__ != 'SDNQLinear': + return False + if wanted_names != () and lora_stack.mode() in lora_stack.DENSE_MODES and not network_layer_name.startswith('lora_te'): + if sum(1 for net in l.loaded_networks if net.modules.get(network_layer_name, None) is not None) >= 2: + return False # dense stack modes combine dense deltas; the factor concat would sum + if hasattr(self, 'sdnq_lora_svd_stash'): + return True + if wanted_names == (): # nothing attached, nothing to remove + return False + seen = False + for net in l.loaded_networks: + module = net.modules.get(network_layer_name, None) + if module is None: + continue + seen = True + if module.__class__.__name__ != 'NetworkModuleLora': + return False + if module.dora_scale is not None or module.bias is not None or module.ex_bias is not None or getattr(module, 'mid_model', None) is not None: + return False + if module.up_model.weight.ndim != 2 or module.down_model.weight.ndim != 2: + return False + if module.up_model.weight.shape[0] != self.sdnq_dequantizer.original_shape[0] or module.down_model.weight.shape[1] != self.sdnq_dequantizer.original_shape[-1]: + return False + return seen + + +def remove_factors(self): + """Restore the layer's original svd factors; True when factors were attached.""" + stash = getattr(self, 'sdnq_lora_svd_stash', None) + if stash is None: + return False + svd_up, svd_down = stash + device = self.scale.device # the stash tuple does not follow module device moves; restore onto wherever the layer lives now + if svd_up is not None and svd_up.device != device: + svd_up = torch.nn.Parameter(svd_up.to(device=device), requires_grad=False) + svd_down = torch.nn.Parameter(svd_down.to(device=device), requires_grad=False) + self.svd_up = svd_up + self.svd_down = svd_down + del self.sdnq_lora_svd_stash + lora_stack.drop(getattr(self, 'network_layer_name', None)) # a selection schedule must not outlive the segments it points into + return True + + +def apply_factors(self, network_layer_name, wanted_names): + """Attach the active networks' LoRA factors to this layer's svd side-channel. + + Replaces any previously attached factors (multiplier changes re-enter + here with a new ``wanted_names`` signature). Returns True when the layer + changed. Falls back to the caller's requantize path by returning None + when factor extraction fails at this stage. + """ + from sdnq.quant_utils import rotate_hadamard + + changed = remove_factors(self) + if wanted_names == (): + return changed + + deq = self.sdnq_dequantizer + dtype = deq.result_dtype + + ups, downs = [], [] + for net in l.loaded_networks: + module = net.modules.get(network_layer_name, None) + if module is None: + continue + factors = get_module_factors(module, devices.device, dtype, original_shape=deq.original_shape) + if factors is None: + return None + up_eff, down = factors + if deq.use_hadamard: + down = rotate_hadamard(down.to(dtype=torch.float32), group_size=deq.hadamard_group_size).to(dtype=dtype) + ups.append(up_eff) + downs.append(down) + if not ups: + return changed + append_factors(self, ups, downs) + factor_layers.append(network_layer_name) + return True + + +def append_factors(self, ups, downs): + """Concatenate ``[out, r]`` / ``[r, in]`` factor pairs onto the layer's svd channel and stash the originals. + + Returns the appended parts' rank ranges plus the transposed-layout flag; the + checkpoint's own factors occupy the range before the first entry and bucket + padding lands after the last, so the ranges stay valid on the live buffers. + """ + deq = self.sdnq_dequantizer + device = self.scale.device + dtype = deq.result_dtype + orig_up, orig_down = self.svd_up, self.svd_down + orig_rank = 0 + if orig_up is not None: + orig_rank = orig_up.shape[0] if deq.use_quantized_matmul else orig_up.shape[1] + segments, offset = [], orig_rank + for u in ups: + segments.append((offset, offset + u.shape[1])) + offset += u.shape[1] + if deq.use_quantized_matmul: + # matmul layout stores factors transposed: svd_up [r, out], svd_down [in, r] + parts_up = ([orig_up.to(device=devices.device, dtype=dtype)] if orig_up is not None else []) + [u.t() for u in ups] + parts_down = ([orig_down.to(device=devices.device, dtype=dtype)] if orig_down is not None else []) + [d.t() for d in downs] + new_up = torch.cat(parts_up, dim=0).contiguous() + new_down = torch.cat(parts_down, dim=1).contiguous() + else: + parts_up = ([orig_up.to(device=devices.device, dtype=dtype)] if orig_up is not None else []) + ups + parts_down = ([orig_down.to(device=devices.device, dtype=dtype)] if orig_down is not None else []) + downs + new_up = torch.cat(parts_up, dim=1).contiguous() + new_down = torch.cat(parts_down, dim=0).contiguous() + from sdnq.common import use_torch_compile + if use_torch_compile: + # the compiled dequant specializes per factor rank; pad to a fixed bucket so set switches inside a bucket reuse the graph (zero columns contribute exactly nothing) + dim_up, dim_down = (0, 1) if deq.use_quantized_matmul else (1, 0) + bucket = rank_bucket(new_up.shape[dim_up]) + new_up = pad_rank(new_up, dim_up, bucket) + new_down = pad_rank(new_down, dim_down, bucket) + self.sdnq_lora_svd_stash = (orig_up, orig_down) + self.svd_up = torch.nn.Parameter(new_up.to(device=device), requires_grad=False) + self.svd_down = torch.nn.Parameter(new_down.to(device=device), requires_grad=False) + return segments, deq.use_quantized_matmul + + +def channel_candidate(self, network_layer_name, wanted_names): + """True when this layer can carry a set on the svd channel: quantized, covered, and given a rank to spend.""" + if not enabled(): + return False + if int(getattr(shared.opts, 'lora_sdnq_host_rank', 0) or 0) <= 0: + return False + if getattr(self, 'sdnq_dequantizer', None) is None or self.__class__.__name__ != 'SDNQLinear': + return False + if wanted_names == (): + return False + return any(net.modules.get(network_layer_name, None) is not None for net in l.loaded_networks) + + +def select_candidate(self, network_layer_name, wanted_names): + """True when a select pair can ride this layer's svd channel; pairs ride it at any bit width.""" + return channel_candidate(self, network_layer_name, wanted_names) + + +def host_candidate(self, network_layer_name, wanted_names): + """True when this layer's set should ride the svd channel as a truncated svd: non-factorable sets below 8 bits, dense-combined sets at any width.""" + if not channel_candidate(self, network_layer_name, wanted_names): + return False + if lora_stack.mode() in lora_stack.DENSE_MODES and not network_layer_name.startswith('lora_te'): + if sum(1 for net in l.loaded_networks if net.modules.get(network_layer_name, None) is not None) >= 2: + return True # combined deltas host at any width: requantizing them is checkpoint-fragile, while single-adapter requantize is well retained + from sdnq.common import dtype_dict + if dtype_dict[self.sdnq_dequantizer.weights_dtype]['num_bits'] >= 8: + return False # requantize retains most of a single set's delta at 8 bits and above; truncation would lose more than it saves + return True + + +def grid_step(self): + """Mean grid step in weight units; a codebook layer keeps its Lloyd levels in the scale slot, so its step is their mean adjacent gap.""" + scale = self.scale.detach().float() + if self.sdnq_dequantizer.use_codebook: + return float(scale.diff(dim=-1).mean()) + return float(scale.mean()) + + +def apply_cached(self, network_layer_name, wanted_names): + """Attach a hosted set straight from the factor cache, before the delta exists. + + Probed by the walk ahead of delta assembly: on a usable entry the routing + rule is evaluated from the stored delta rms and the cached factors attach + exactly as a fetch inside ``apply_hosted`` would, so the pass skips + ``calc_updown`` for the layer entirely. Returns True when the layer was + served; None sends the caller down the assemble-and-host path (no entry, + or the rule wants the grid). + """ + from sdnq.quant_utils import rotate_hadamard + + lora_factor_cache.begin_pass(wanted_names) + entry = lora_factor_cache.lookup(network_layer_name) + if entry is None: + return None + up_h, down_h, energy, calibrated, rms = entry + up_h, down_h = trim_null_tail(up_h, down_h) + deq = self.sdnq_dequantizer + dtype = deq.result_dtype + remove_factors(self) # before the rule: the svd-channel check must see the checkpoint's own state, and a declined layer must fall through pristine + stack_dense = lora_stack.mode() in lora_stack.DENSE_MODES and not network_layer_name.startswith('lora_te') + members = [] + if not stack_dense: + for net in l.loaded_networks: + module = net.modules.get(network_layer_name, None) + if module is None: + continue + factors = get_module_factors(module, devices.device, dtype, original_shape=deq.original_shape) + if factors is not None: + members.append(factors) + if not stack_dense and len(members) == 0 and self.svd_up is None: + step = grid_step(self) + if step > 0 and rms / step > REQUANT_RATIO and energy < REQUANT_ENERGY: + return None # routed to the grid: the caller assembles the delta and requantizes + ups, downs = [], [] + for up_eff, down in members: + if deq.use_hadamard: + down = rotate_hadamard(down.to(dtype=torch.float32), group_size=deq.hadamard_group_size).to(dtype=dtype) + ups.append(up_eff) + downs.append(down) + lora_factor_cache.note_hit() + append_factors(self, ups + [up_h.to(device=devices.device, dtype=dtype)], downs + [down_h.to(device=devices.device, dtype=dtype)]) + hosted_layers.append((network_layer_name, energy, calibrated)) + hosted_ranks.append(int(up_h.shape[1])) + return True + + +def apply_hosted(self, network_layer_name, updown, wanted_names): + """Host a set's delta on the svd channel: exact factors for factorable + members, the top-k singular directions of the remainder for the rest. + + The delta comes from the families' own ``calc_updown``, so every family + and scaling quirk is included; factorable members are subtracted out and + appended exactly so they never compete with the hosted remainder for + rank. When per-checkpoint activation statistics exist (``lora_calib``), + input channels are weighted by their RMS before truncation so the kept + directions minimize output error rather than weight error. Computed + factors are disk-cached per configuration (``lora_factor_cache``) and + replayed bit-identically on later applies. Returns None when the delta + cannot ride the channel (wrong shape) or when the routing rule prefers + the grid for it; the caller falls back to requantize. + """ + from sdnq.quant_utils import rotate_hadamard + + deq = self.sdnq_dequantizer + changed = remove_factors(self) + if wanted_names == (): + return changed + if updown is None or updown.ndim != 2 or tuple(updown.shape) != tuple(deq.original_shape): + return None + dtype = deq.result_dtype + + members = [] + stack_dense = lora_stack.mode() in lora_stack.DENSE_MODES and not network_layer_name.startswith('lora_te') + if not stack_dense: # dense stack modes host the combined delta wholesale; the members' content is already inside it + for net in l.loaded_networks: + module = net.modules.get(network_layer_name, None) + if module is None: + continue + factors = get_module_factors(module, devices.device, dtype, original_shape=deq.original_shape) + if factors is not None: + members.append(factors) + + # requantize keeps a delta the grid can resolve and that truncation would genuinely + # cut: both terms must agree, since a thin delta rounds away on the grid however + # low its capture, and a low-rank delta hosts exactly however fat it is. Scoped to + # sets the side-channel would otherwise carry whole: factorable members ride + # exactly and dense-combined deltas stay hosted at any magnitude. + delta_rms = float(updown.detach().float().square().mean().sqrt()) + maybe_requant = not stack_dense and len(members) == 0 and self.svd_up is None + if maybe_requant: + step = grid_step(self) + maybe_requant = step > 0 and delta_rms / step > REQUANT_RATIO + + lora_factor_cache.begin_pass(wanted_names) + cached = lora_factor_cache.fetch(network_layer_name) + D = None if cached is not None else updown.detach().to(devices.device, torch.float32) + + ups, downs = [], [] + for up_eff, down in members: + if D is not None: + D = D.sub_(up_eff.to(torch.float32) @ down.to(torch.float32)) # factorable members ride exactly; host only the remainder + if deq.use_hadamard: + down = rotate_hadamard(down.to(dtype=torch.float32), group_size=deq.hadamard_group_size).to(dtype=dtype) + ups.append(up_eff) + downs.append(down) + + if cached is not None: + up_h, down_h, energy, calibrated, _cached_rms = cached + if maybe_requant and energy < REQUANT_ENERGY: + routed_layers.append(network_layer_name) + return None + up_h, down_h = trim_null_tail(up_h, down_h) + append_factors(self, ups + [up_h.to(device=devices.device, dtype=dtype)], downs + [down_h.to(device=devices.device, dtype=dtype)]) + hosted_layers.append((network_layer_name, energy, calibrated)) + hosted_ranks.append(int(up_h.shape[1])) + return True + + up_h, down_h, energy, calibrated = truncate_delta(self, D, dtype) + up_h, down_h = lora_factor_cache.store(network_layer_name, up_h, down_h, energy, calibrated, delta_rms) + if maybe_requant and energy < REQUANT_ENERGY: + routed_layers.append(network_layer_name) # the stored entry memoizes the routing; replays skip the sketch + return None + up_h, down_h = trim_null_tail(up_h, down_h) # the int8 roundtrip zeroes the numeric tail the eps slice keeps; fresh and replayed attaches must trim alike + append_factors(self, ups + [up_h], downs + [down_h]) + hosted_layers.append((network_layer_name, energy, calibrated)) + hosted_ranks.append(int(up_h.shape[1])) + return True + + +def truncate_delta(self, D, dtype): + """Truncate one dense fp32 delta to hosted factors in the layer's channel layout; consumes ``D``. + + Calibration-weighted when statistics exist; the sketch is oversampled past + the kept rank so the truncation sits within noise of exact svd. Returns + ``(up_h, down_h, energy, calibrated)`` with the down factor rotated into the + layer's hadamard domain. + """ + from sdnq.quant_utils import rotate_hadamard + deq = self.sdnq_dequantizer + cap = int(shared.opts.lora_sdnq_host_rank) + q = min(cap, *D.shape) + rms = lora_calib.rms_for(self) + if rms is not None and rms.shape[-1] == D.shape[-1]: + # scale input channels by their activation RMS so truncation minimizes output error rather than weight error + rms = rms.to(device=D.device, dtype=torch.float32).clamp(min=1e-8) + D = D.mul_(rms) + else: + rms = None + # svd_lowrank draws random projections; fork so user generation seeds are untouched and re-applies are deterministic + with torch.random.fork_rng(devices=[D.device] if D.device.type == 'cuda' else []): + torch.manual_seed(0) + # oversampled sketch with extra power iterations lands within noise of exact svd; only the top q columns are kept + U, S, V = torch.svd_lowrank(D, q=min(q + 64, *D.shape), niter=8) + U, S, V = U[:, :q], S[:q], V[:, :q] + e = S.square() + total_e = e.sum() + if float(total_e) > 0: + # an exactly low-rank delta (dense-combined plain pairs, low-rank LyCORIS) fills the tail with + # numerical zeros; storing them would pad the channel to the cap for nothing + k = int((torch.cumsum(e, 0) < (1.0 - NULL_TAIL_EPS) * total_e).sum().item()) + 1 + if k < q: + U, S, V = U[:, :k], S[:k], V[:, :k] + energy = float(S.square().sum() / D.square().sum().clamp(min=1e-30)) # captured fraction, in the weighted domain when calibrated + up_h = (U * S).to(dtype=dtype) + down_h = V.t() + if rms is not None: + down_h = down_h / rms # unscale in the original input basis, before any rotation + if deq.use_hadamard: + down_h = rotate_hadamard(down_h, group_size=deq.hadamard_group_size) + down_h = down_h.to(dtype=dtype) + return up_h, down_h, energy, rms is not None + + +def apply_select_cached(self, network_layer_name, wanted_names): + """Serve a select pair from cache and live factors before the walk assembles deltas. + + A cached score record plus a factor pair per network (exact factors for + factorable members, cached truncations otherwise) rebuild the segments and + the selection registration without any ``calc_updown``. Returns None when + any piece is missing; the caller assembles and ``apply_select`` recomputes + and stores. + """ + from sdnq.quant_utils import rotate_hadamard + deq = self.sdnq_dequantizer + changed = remove_factors(self) + if wanted_names == (): + return changed + if len(l.loaded_networks) != 2: + return None + dtype = deq.result_dtype + lora_factor_cache.begin_pass(wanted_names) + rec = lora_factor_cache.lookup_scores(network_layer_name) + if rec is None: + return None + pairs, notes = [], [] + for i, net in enumerate(l.loaded_networks): + module = net.modules.get(network_layer_name, None) + if module is None: + return None + factors = get_module_factors(module, devices.device, dtype, original_shape=deq.original_shape) + if factors is not None: + up_i, down_i = factors + if deq.use_hadamard: + down_i = rotate_hadamard(down_i.to(dtype=torch.float32), group_size=deq.hadamard_group_size).to(dtype=dtype) + else: + cached = lora_factor_cache.lookup(f'{network_layer_name}#{i}') + if cached is None: + return None + up_i, down_i = cached[0].to(device=devices.device, dtype=dtype), cached[1].to(device=devices.device, dtype=dtype) + notes.append((f'{network_layer_name}#{i}', cached[2], cached[3])) + pairs.append((up_i, down_i)) + scores, abs_sums = rec + segments, transposed = append_factors(self, [pairs[0][0], pairs[1][0]], [pairs[0][1], pairs[1][1]]) + lora_stack.register(network_layer_name, self, 'factor', scores, segments=(segments[0], segments[1], transposed), abs_sums=abs_sums) + for note in notes: + lora_factor_cache.note_hit() + hosted_layers.append(note) + select_layers.append(network_layer_name) + return True + + +def apply_select(self, network_layer_name, per_net, wanted_names): + """Attach two networks' contributions as separate side-channel segments for per-layer selection. + + Factorable members ride exactly; the rest host as their own truncated svd + with per-net cache entries. Segment ranges and selection scores register + with ``lora_stack``; the flip schedule executes from the step callback. + Returns None when the pair cannot ride the channel; the caller falls back. + """ + from sdnq.quant_utils import rotate_hadamard + deq = self.sdnq_dequantizer + changed = remove_factors(self) + if wanted_names == (): + return changed + if per_net is None or len(per_net) != 2: + return None + dtype = deq.result_dtype + lora_factor_cache.begin_pass(wanted_names) + pairs, ranks = [], [] + for i, (net_name, D) in enumerate(per_net): + if D is None or D.ndim != 2 or tuple(D.shape) != tuple(deq.original_shape): + return None + net = next((n for n in l.loaded_networks if n.name == net_name), None) + module = net.modules.get(network_layer_name, None) if net is not None else None + if module is None: + return None + ranks.append(int(getattr(module, 'dim', 0) or 0) or min(int(shared.opts.lora_sdnq_host_rank), *deq.original_shape)) + factors = get_module_factors(module, devices.device, dtype, original_shape=deq.original_shape) + if factors is not None: + up_i, down_i = factors + if deq.use_hadamard: + down_i = rotate_hadamard(down_i.to(dtype=torch.float32), group_size=deq.hadamard_group_size).to(dtype=dtype) + else: + key = f'{network_layer_name}#{i}' + cached = lora_factor_cache.fetch(key) + if cached is not None: + up_i, down_i = cached[0].to(device=devices.device, dtype=dtype), cached[1].to(device=devices.device, dtype=dtype) + hosted_layers.append((key, cached[2], cached[3])) + else: + up_i, down_i, energy, calibrated = truncate_delta(self, D.detach().to(devices.device, torch.float32), dtype) + up_i, down_i = lora_factor_cache.store(key, up_i, down_i, energy, calibrated, float(D.detach().float().square().mean().sqrt())) + hosted_layers.append((key, energy, calibrated)) + pairs.append((up_i, down_i)) + scores, abs_sums = lora_stack.score_pair(per_net[0][1].detach(), per_net[1][1].detach(), ranks[0], ranks[1]) + lora_factor_cache.store_scores(network_layer_name, scores, abs_sums) + segments, transposed = append_factors(self, [pairs[0][0], pairs[1][0]], [pairs[0][1], pairs[1][1]]) + lora_stack.register(network_layer_name, self, 'factor', scores, segments=(segments[0], segments[1], transposed), abs_sums=abs_sums) + select_layers.append(network_layer_name) # counted apart from the plain concat: both ride the svd channel but only one is a summed set + return True + + +def note_fallback(self, network_layer_name): + """Record a quantized layer taking the requantize path (summary-logged per pass); layers the routing rule sent there are counted apart.""" + if getattr(self, 'sdnq_dequantizer', None) is not None and network_layer_name not in routed_layers: + fallback_layers.append(network_layer_name) + + +def reset_pass(): + """Clear every per-pass accumulator, so a pass that raised leaves nothing behind for the next one.""" + fallback_layers.clear() + hosted_layers.clear() + hosted_ranks.clear() + factor_layers.clear() + select_layers.clear() + routed_layers.clear() # note_fallback reads this to suppress double counting, so a stale entry silences a real fallback + + +def report_fallbacks(): + hits, misses = lora_factor_cache.flush() + if hits > 0 or misses > 0: + log.info(f'Network load: type=LoRA quant=sdnq cache hits={hits} misses={misses}') + if len(factor_layers) > 0: + log.info(f'Network load: type=LoRA quant=sdnq apply=exact layers={len(factor_layers)}') + factor_layers.clear() + if len(select_layers) > 0: + log.info(f'Network load: type=LoRA quant=sdnq apply=select layers={len(select_layers)} mode={lora_stack.mode()}') + select_layers.clear() + if len(hosted_layers) > 0: + energies = sorted(e for _name, e, _c in hosted_layers) + median = energies[len(energies) // 2] + calibrated = sum(1 for _name, _e, c in hosted_layers if c) + ranks = '' + if len(hosted_ranks) > 0 and min(hosted_ranks) < int(shared.opts.lora_sdnq_host_rank): + rs = sorted(hosted_ranks) + ranks = f' k={rs[0]}-{rs[len(rs) // 2]}-{rs[-1]}' # realized rank spread; shown only when a spectrum collapsed below the cap + log.info(f'Network load: type=LoRA quant=sdnq apply=hosted layers={len(hosted_layers)} rank={int(shared.opts.lora_sdnq_host_rank)}{ranks}{f" calib={calibrated}" if calibrated else ""} energy={median:.2f} min={energies[0]:.2f}') + if l.debug: + log.debug(f'Network load: type=LoRA quant=sdnq hosted={[(n, round(e, 3)) for n, e, _c in hosted_layers[:8]]}{"..." if len(hosted_layers) > 8 else ""}') + hosted_layers.clear() + hosted_ranks.clear() + if len(routed_layers) > 0: + log.info(f'Network load: type=LoRA quant=sdnq apply=requantize layers={len(routed_layers)} routed=fat-delta') + if l.debug: + log.debug(f'Network load: type=LoRA quant=sdnq routed={routed_layers[:8]}{"..." if len(routed_layers) > 8 else ""}') + routed_layers.clear() + if len(fallback_layers) > 0: + if enabled(): + log.warning(f'Network load: type=LoRA quant=sdnq apply=requantize layers={len(fallback_layers)} fidelity=reduced') + else: + log.info(f'Network load: type=LoRA quant=sdnq apply=requantize layers={len(fallback_layers)} reason=setting') + if l.debug: + log.debug(f'Network load: type=LoRA quant=sdnq requantized={fallback_layers[:8]}{"..." if len(fallback_layers) > 8 else ""}') + fallback_layers.clear() diff --git a/modules/lora/lora_stack.py b/modules/lora/lora_stack.py new file mode 100644 index 000000000..d5c0001c7 --- /dev/null +++ b/modules/lora/lora_stack.py @@ -0,0 +1,418 @@ +"""Stack modes for combining multiple LoRA networks beyond plain summation. + +Dense modes (ties, dare_ties, dare_linear, magnitude_prune) combine the +networks' dense deltas elementwise; the result rides the normal apply tail +(side-channel hosting on sub-8-bit SDNQ, requantize at int8 and above, +direct add on unquantized layers). Select modes (klora, estlora) keep both +networks' contributions separate and choose a per-layer winner, shifting +from the first loaded network (subject) toward the second (style) across +the sampling steps. Selection scores depend only on the weights, so the +shift reduces to at most one flip per layer per generation, executed from +the step callback against a schedule finalized at apply time. + +TIES arXiv:2306.01708, DARE arXiv:2311.03099, K-LoRA arXiv:2502.18461, +EST-LoRA arXiv:2508.02165 (its measured style-discrepancy estimate is +exposed as an option instead of being derived from probe generations). +""" + +import time +import weakref +import hashlib + +import torch + +from modules import shared +from modules.logger import log + + +DENSE_MODES = ('ties', 'dare_ties', 'dare_linear', 'magnitude_prune') +SELECT_MODES = ('klora', 'estlora') +KLORA_BETA = 0.5 # the paper's fixed ramp offset; only the slope is user-tunable +ROW_CHUNK = 512 # fp32 interiors run in first-dim slices; also fixes the DARE draw sequence +SAMPLE_CAP = 1 << 22 # strided subsample bound for magnitude quantiles (full-size quantile exceeds torch limits) + +state: dict = {'entries': {}, 'flips': {}, 'gamma': 1.0, 'gamma_e': 1.0, 'total_steps': 0, 'finalized': False, 'reported': None} +warned: set = set() +warned_context = None + + +def mode(): + return getattr(shared.opts, 'lora_stack_mode', 'sum') or 'sum' + + +def density(): + return float(getattr(shared.opts, 'lora_stack_density', 0.5)) + + +def ramp_alpha(): + return float(getattr(shared.opts, 'lora_stack_alpha', 0.0)) + + +def manual_discrepancy(): + return float(getattr(shared.opts, 'lora_stack_discrepancy', 0.5)) + + +def signature(): + m = mode() + if m in DENSE_MODES: + return f'{m}:{density():.2f}' + if m in SELECT_MODES: + return f'{m}:{ramp_alpha():.2f}:{manual_discrepancy():.2f}' + return 'sum' + + +def warn_context(): + """Settings the degradation warnings below speak about.""" + return (signature(), getattr(shared.opts, 'diffusers_offload_mode', ''), int(getattr(shared.opts, 'lora_sdnq_host_rank', 0) or 0), getattr(shared.opts, 'sd_model_checkpoint', '')) + + +def warn_once(key, message): + global warned_context # pylint: disable=global-statement + context = warn_context() + if context != warned_context: + warned.clear() # what was reported under the old settings says nothing about the new ones + warned_context = context + if key not in warned: + warned.add(key) + log.warning(message) + + +def select_blocked(): + return 'Model' in (getattr(shared.opts, 'cuda_compile', None) or []) + + +def active_dense(n_contrib): + return mode() in DENSE_MODES and n_contrib >= 2 + + +def select_possible(n_loaded): + """True when the loaded set could engage a select mode; silent, for the fuse gate.""" + return mode() in SELECT_MODES and n_loaded == 2 and not select_blocked() + + +def select_engaged(): + """True while selection schedules are live on model layers.""" + return bool(state['entries']) + + +def active_select(n_loaded): + m = mode() + if m not in SELECT_MODES: + return False + if n_loaded != 2: + log.warning(f'Network stack: mode={m} networks={n_loaded} required=2 fallback=sum') + return False + if select_blocked(): + log.warning(f'Network stack: mode={m} compile=model fallback=sum') + return False + return True + + +def seed_for(layer_name, net_name): + payload = f'{layer_name}|{net_name}|{mode()}|{round(density(), 6)}' + return int.from_bytes(hashlib.sha256(payload.encode()).digest()[:8], 'little') + + +def magnitude_threshold(delta, dens): + flat = delta.abs().flatten() + step = max(1, flat.numel() // SAMPLE_CAP) + return torch.quantile(flat[::step].float(), 1.0 - dens) + + +def dare_generator(device, layer_name, net_name): + gen = torch.Generator(device=device) + gen.manual_seed(seed_for(layer_name, net_name)) + return gen + + +def combine(named_deltas, layer_name): + """Combine per-network dense deltas under the active dense mode; returns a tensor in the first delta's dtype.""" + m = mode() + dens = density() + deltas = [d for _, d in named_deltas] + out_dtype = deltas[0].dtype + result = torch.zeros_like(deltas[0], dtype=torch.float32) + thresholds = [magnitude_threshold(d, dens) for d in deltas] if m in ('ties', 'magnitude_prune') else [None] * len(deltas) + gens = [dare_generator(deltas[0].device, layer_name, name) for name, _ in named_deltas] if m in ('dare_ties', 'dare_linear') else [None] * len(deltas) + for start in range(0, deltas[0].shape[0], ROW_CHUNK): + stop = min(start + ROW_CHUNK, deltas[0].shape[0]) + chunks = [] + for i, d in enumerate(deltas): + c = d[start:stop].to(torch.float32) + if thresholds[i] is not None: + c = c * (c.abs() >= thresholds[i]) + if gens[i] is not None: + keep = torch.rand(c.shape, generator=gens[i], device=c.device, dtype=torch.float32) < dens + c = c * keep / dens + chunks.append(c) + if m in ('ties', 'dare_ties'): + total = torch.stack(chunks).sum(dim=0) + elected = torch.sign(total) + agree = [c * ((torch.sign(c) == elected) & (c != 0)) for c in chunks] + count = torch.stack([(a != 0).to(torch.float32) for a in agree]).sum(dim=0).clamp(min=1.0) + result[start:stop] = torch.stack(agree).sum(dim=0) / count + else: # dare_linear, magnitude_prune: independent per-delta edits, plain sum + result[start:stop] = torch.stack(chunks).sum(dim=0) + return result.to(out_dtype) + + +def score_pair(d0, d1, rank0, rank1): + """Selection scores for a dense delta pair: klora top-K sums (K = rank product) or est energies; plus abs-sums for the global balance. + + Row-chunked fp32 interiors with fp64 accumulators and one device sync for + all four reductions. Full-tensor staging (fp32 copy, abs copy, top-k + workspace) peaks hundreds of MB per large layer, which collides with block + swapping on offloaded denoisers; chunking bounds the transient to the + chunk. The global top-K over per-chunk top-K candidates selects the same + element set as a whole-tensor top-K. + """ + k = max(1, int(rank0) * int(rank1)) if mode() == 'klora' else 0 + accs = [] + for d in (d0, d1): + score = torch.zeros((), device=d.device, dtype=torch.float64) + abs_sum = torch.zeros((), device=d.device, dtype=torch.float64) + cands = [] + for start in range(0, d.shape[0], ROW_CHUNK): + c = d[start:start + ROW_CHUNK].to(torch.float32).abs() # out-of-place abs: to() may alias a caller-owned fp32 tensor + abs_sum += c.sum(dtype=torch.float64) + if k: + flat = c.flatten() + cands.append(torch.topk(flat, min(k, flat.numel()), sorted=False).values) + else: + score += c.square().sum(dtype=torch.float64) + if k and cands: + allc = torch.cat(cands) if len(cands) > 1 else cands[0] + score = torch.topk(allc, min(k, allc.numel()), sorted=False).values.sum(dtype=torch.float64) + accs.append((score, abs_sum)) + packed = torch.stack([accs[0][0], accs[0][1], accs[1][0], accs[1][1]]).cpu() + return (float(packed[0]), float(packed[2])), (float(packed[1]), float(packed[3])) + + +def register_weight_pair(layer_name, module, per_net, wanted_names=None): + """Score and register a weight-kind selection pair; True when the layer is scheduled. + + The scores persist in the factor cache when a pass identity is given, so a + later apply of the same configuration registers from the record alone. + """ + from modules.lora import lora_common as l + if per_net is None or len(per_net) != 2: + return False + ranks, names = [], [] + for net_name, d in per_net: + if d is None: + return False + net = next((n for n in l.loaded_networks if n.name == net_name), None) + net_module = net.modules.get(layer_name, None) if net is not None else None + if net_module is None: + return False + names.append(net_name) + ranks.append(int(getattr(net_module, 'dim', 0) or 0) or 64) + scores, abs_sums = score_pair(per_net[0][1], per_net[1][1], ranks[0], ranks[1]) + if wanted_names is not None: + from modules.lora import lora_factor_cache + lora_factor_cache.begin_pass(wanted_names) + lora_factor_cache.store_scores(layer_name, scores, abs_sums) + register(layer_name, module, 'weight', scores, nets=tuple(names), abs_sums=abs_sums) + return True + + +def register_weight_pair_cached(layer_name, module, wanted_names): + """Register a weight-kind pair from its cached score record; True when served. + + The record was stored under the same configuration signature, which pins + the loaded pair, multipliers and stack settings, so both networks are known + to target the layer and the prompt-order roles are unchanged. + """ + from modules.lora import lora_common as l + from modules.lora import lora_factor_cache + if len(l.loaded_networks) != 2: + return False + lora_factor_cache.begin_pass(wanted_names) + rec = lora_factor_cache.lookup_scores(layer_name) + if rec is None: + return False + scores, abs_sums = rec + register(layer_name, module, 'weight', scores, nets=tuple(n.name for n in l.loaded_networks), abs_sums=abs_sums) + return True + + +def drop(layer_name): + """Forget a layer's selection entry (its factors were removed or restored).""" + if layer_name is not None and state['entries'].pop(layer_name, None) is not None: + state['finalized'] = False + + +def score_energy(up, down): + """EST layer score: squared Frobenius norm of up@down via the Gram identity, no materialization.""" + u = up.to(torch.float32) + dn = down.to(torch.float32) + return float(((u.t() @ u) * (dn @ dn.t())).sum()) + + +def clear(): + state['entries'] = {} + state['flips'] = {} + state['gamma'] = 1.0 + state['gamma_e'] = 1.0 + state['total_steps'] = 0 + state['finalized'] = False + state['reported'] = None + + +def register(layer_name, module, kind, scores, segments: tuple[tuple[int, int], tuple[int, int], bool] | None = None, nets=None, abs_sums=None): + """Record a select-mode layer for schedule finalization. + + kind 'factor': segments = ((s0, s1), (t0, t1), transposed) column ranges on the svd + channel; both segments' pristine values are stashed for flips. kind 'weight': nets = + the two network names; the winner delta is recomputed from the layer backup at + selection time. abs_sums feeds the global magnitude balance (klora gamma). + """ + entry = {'layer': layer_name, 'module': weakref.ref(module), 'kind': kind, 'segments': segments, 'scores': scores, 'nets': nets, 'abs_sums': abs_sums, 'stash': None} + if kind == 'factor': + if segments is None: + raise ValueError("segments is required when kind='factor'") + (s0, s1), (t0, t1), transposed = segments + up = module.svd_up.data + entry['stash'] = (segment_view(up, s0, s1, transposed).clone(), segment_view(up, t0, t1, transposed).clone()) + state['entries'][layer_name] = entry + state['finalized'] = False + + +def segment_view(up, start, stop, transposed): + return up[start:stop] if transposed else up[:, start:stop] + + +def layer_flip_step(scores, total_steps): + """First step index at which the style side wins; total_steps when it never does, 0 when style wins from the start.""" + m = mode() + sc, ss = scores + for step in range(total_steps): + t = step / max(1, total_steps - 1) + if m == 'klora': + ramp = state['gamma'] * (ramp_alpha() * t + KLORA_BETA) + if ss * ramp > sc: + return step + else: # estlora: content keeps the layer while sc >= gamma_t * ss + # est energies are ||dW||^2, so a magnitude gap enters squared; balance the style side by + # the total-energy ratio (mirrors klora's gamma) so the louder adapter cannot win on scale alone + ramp = ramp_alpha() * t + (1.0 - manual_discrepancy()) + if sc < ramp * ss * state['gamma_e']: + return step + return total_steps + + +def materialize_model(): + """Weight-kind selection rewrites module weights outside the activation walk; rebuild balanced-offload modules real first (mirrors network_activate).""" + from modules import sd_models + if getattr(shared.opts, 'diffusers_offload_mode', None) == 'balanced' and getattr(shared, 'sd_model', None) is not None: + sd_models.apply_balanced_offload(shared.sd_model, force=True, silent=True) + + +def finalize(total_steps): + """Build the inverted flip map for the pass; select-mode layers start at their step-0 winner.""" + state['total_steps'] = int(total_steps) + # both balances derive from the live entries every time, so drops and re-registrations stay consistent by construction + num = sum(e['abs_sums'][0] for e in state['entries'].values() if e['abs_sums'] is not None) + den = sum(e['abs_sums'][1] for e in state['entries'].values() if e['abs_sums'] is not None) + state['gamma'] = (num / den) if den > 0 else 1.0 + e_num = sum(e['scores'][0] for e in state['entries'].values()) # est scores ARE the per-layer energies; their totals give the scale-invariant balance + e_den = sum(e['scores'][1] for e in state['entries'].values()) + state['gamma_e'] = (e_num / e_den) if e_den > 0 else 1.0 + state['flips'] = {} + stats = {'weight_n': 0, 'factor_n': 0, 'materialize': 0.0, 'select': 0.0, 'w_move': 0.0, 'w_calc': 0.0, 'w_apply': 0.0} + state['stats'] = stats + stats['weight_n'] = sum(1 for e in state['entries'].values() if e['kind'] == 'weight') + stats['factor_n'] = len(state['entries']) - stats['weight_n'] + if stats['weight_n'] > 0: + t0 = time.time() + materialize_model() + stats['materialize'] = time.time() - t0 + style_first = 0 + t0 = time.time() + for layer_name, entry in list(state['entries'].items()): # snapshot: apply_selection drops entries whose module died + flip_at = layer_flip_step(entry['scores'], state['total_steps']) + initial = 1 if flip_at == 0 else 0 + style_first += initial + apply_selection(layer_name, entry, initial) + if 0 < flip_at < state['total_steps']: + state['flips'].setdefault(flip_at - 1, []).append(layer_name) # step callbacks fire after the denoise, so the flip runs one step early to be live during the crossover step's forward + stats['select'] = time.time() - t0 + state['finalized'] = True + if len(state['entries']) > 0: # only a built schedule can carry a flip count, so this is the line that shows selection is live rather than requested + gamma = state['gamma_e'] if mode() == 'estlora' else state['gamma'] + report = (mode(), len(state['entries']), style_first, sum(len(v) for v in state['flips'].values()), state['total_steps'], round(gamma, 3)) + if report != state['reported']: # rebuilt every pass, so a batch would otherwise repeat one line per image + state['reported'] = report + log.info(f'Network load: type=LoRA stack={report[0]} layers={report[1]} style={report[2]} flips={report[3]} steps={report[4]} gamma={report[5]:.3f}') + # logged every pass: the reset runs outside the activate walk, so its cost is invisible to the load timers + log.debug(f'Network select: type=LoRA reset weight={stats["weight_n"]} factor={stats["factor_n"]} time={{materialize: {stats["materialize"]:.2f}, select: {stats["select"]:.2f}, move: {stats["w_move"]:.2f}, calc: {stats["w_calc"]:.2f}, apply: {stats["w_apply"]:.2f}}}') + + +def reset(total_steps): + """Per-pass reset from set_callbacks_p: restore initial selections and reschedule for this pass's step count.""" + if mode() not in SELECT_MODES or not state['entries'] or int(total_steps) <= 0: + return + finalize(total_steps) + + +def on_step(step): + """Flip the layers whose crossover is this step; non-flip steps are a dict miss.""" + if not state['finalized']: + return + layers = state['flips'].get(int(step), ()) + if not layers: + return + t0 = time.time() + for layer_name in layers: + entry = state['entries'].get(layer_name) + if entry is not None: + apply_selection(layer_name, entry, 1) + log.debug(f'Network select: type=LoRA flip step={int(step)} layers={len(layers)} time={time.time() - t0:.2f}') + + +def apply_selection(layer_name, entry, winner): + module = entry['module']() + if module is None: + state['entries'].pop(layer_name, None) + return + if entry['kind'] == 'factor': + (s0, s1), (t0, t1), transposed = entry['segments'] + up = module.svd_up.data + keep_seg, drop_seg = ((t0, t1), (s0, s1)) if winner == 1 else ((s0, s1), (t0, t1)) + stash = entry['stash'][winner] + segment_view(up, keep_seg[0], keep_seg[1], transposed).copy_(stash.to(device=up.device, dtype=up.dtype)) + segment_view(up, drop_seg[0], drop_seg[1], transposed).zero_() + else: + weight_selection(module, entry, winner) + + +def weight_selection(module, entry, winner): + from modules.lora import lora_common as l + from modules.lora.lora_apply import network_apply_weights + if getattr(module, 'sdnq_dequantizer', None) is not None: + warn_once('select-sdnq-weight', 'Network stack: flip=skipped layer=quantized') # quantized backups are packed tensors; only the segment path can flip them + return + backup = getattr(module, 'network_weights_backup', None) + if not isinstance(backup, torch.Tensor): # fuse mode keeps a bool sentinel, not a pristine copy + warn_once('select-nobackup', 'Network stack: flip=skipped backup=none') + return + net = next((n for n in l.loaded_networks if n.name == entry['nets'][winner]), None) + net_module = net.modules.get(entry['layer'], None) if net is not None else None + if net_module is None: + return + weight = getattr(module, 'weight', None) + if weight is None or weight.is_meta: + warn_once('select-offloaded', 'Network stack: flip=skipped weight=offloaded') + return + from modules import devices + stats = state.get('stats') or {} + device = weight.device + t0 = time.time() + base = backup.to(devices.device) # a swapped-out layer keeps its weight on cpu; the delta matmul belongs on the accelerator regardless + t1 = time.time() + updown = net_module.calc_updown(base)[0].to(device) + t2 = time.time() + network_apply_weights(module, updown, None, device=device) # recomputes from the pristine backup, requantizing where the layer needs it + stats['w_move'] = stats.get('w_move', 0.0) + (t1 - t0) + stats['w_calc'] = stats.get('w_calc', 0.0) + (t2 - t1) + stats['w_apply'] = stats.get('w_apply', 0.0) + (time.time() - t2) diff --git a/modules/lora/lora_timers.py b/modules/lora/lora_timers.py index 6f3e48c33..34a77b03b 100644 --- a/modules/lora/lora_timers.py +++ b/modules/lora/lora_timers.py @@ -5,7 +5,6 @@ class Timer: calc: float = 0 apply: float = 0 move: float = 0 - restore: float = 0 activate: float = 0 deactivate: float = 0 @@ -26,13 +25,9 @@ class Timer: self.calc = 0 self.apply = 0 self.move = 0 - self.restore = 0 if complete: self.activate = 0 self.deactivate = 0 - def add(self, name, t): - self.__dict__[name] += t - def __str__(self): return f'{self.__class__.__name__}({self.summary})' diff --git a/modules/lora/native_adapter.py b/modules/lora/native_adapter.py index ba44cd27e..10582447b 100644 --- a/modules/lora/native_adapter.py +++ b/modules/lora/native_adapter.py @@ -22,9 +22,8 @@ of a fused weight is described) and the per-arch ``resolve_targets`` callable each loader passes in (how a parsed ``(prefix, base)`` maps to one or more diffusers paths plus optional chunk descriptors). -Per-arch loader modules import this module and pass their own ``prefixes``, -``bare_prefixes``, ``bare_diffusers_prefixes``, and ``resolve_targets`` to the -generic helpers. +Per-arch loader modules import this module and pass their own ``prefixes`` +and ``resolve_targets`` to the generic helpers. """ import os @@ -33,7 +32,7 @@ from dataclasses import dataclass import torch -from modules import shared, sd_models, sd_models_utils +from modules.sd_models import read_state_dict # pylint: disable=unused-import from modules.logger import log from modules.lora import ( lora_convert, network, network_boft, network_full, network_glora, @@ -55,10 +54,11 @@ from modules.lora import lora_common as l KNOWN_PREFIXES_DEFAULT = ("diffusion_model.", "transformer.", "lora_unet_", "lora_transformer_", "lycoris_") -# Sentinel ``prefix_used`` value emitted by :func:`parse_key` when a bare path -# starting with a member of ``bare_diffusers_prefixes`` matches. A loader -# ``resolve_targets`` may dispatch on this string to rewrite the base path; -# when it declines, :func:`resolve_group_targets` binds the path verbatim. +# Sentinel ``prefix_used`` value emitted by :func:`parse_key` for a bare path, +# one that matched no arch prefix. A loader ``resolve_targets`` may dispatch on +# this string to rewrite the base path; when it declines, +# :func:`resolve_group_targets` binds the path verbatim, and a path naming no +# live module counts as unmapped instead of vanishing. BARE_DIFFUSERS_PREFIX_USED = "bare_diffusers" @@ -92,6 +92,11 @@ def _resolve_prefix(network_prefix, prefix_used): SUFFIX_NORMALIZE = { "lora_A.weight": "lora_down.weight", "lora_B.weight": "lora_up.weight", + # bare parameter names, saved by wrappers that hold the factors as nn.Parameter (alibaba-pai PDD files) + "lora_down": "lora_down.weight", + "lora_a": "lora_down.weight", + "lora_b": "lora_up.weight", + "lora_up": "lora_up.weight", } @@ -103,6 +108,8 @@ SUFFIX_NORMALIZE = { LORA_SUFFIXES = ( ".lora_down.weight", ".lora_up.weight", ".lora_mid.weight", ".lora_A.weight", ".lora_B.weight", + ".lora_down", ".lora_up", + ".lora_a", ".lora_b", # lowercase peft factor names without .weight (TaoLive adapters) # diff_b: bias delta some saves pair with the weight LoRA, applied as ex_bias. # magnitude / lora_magnitude_vector: DoRA row norms (ai-toolkit / PEFT key # names); converted onto the dora_scale path by try_load_lora. @@ -154,7 +161,7 @@ FULL_SUFFIXES = ( # on accidental overlaps with other families. LORA_MARKERS = ( - ".lora_down.weight", ".lora_up.weight", + ".lora_down", ".lora_up", ".lora_a", ".lora_b", # bare and .weight forms alike ".lora_A.weight", ".lora_B.weight", # PEFT named-adapter saves embed the slot name as ``.lora_A..weight``; # the trailing-dot forms catch every variant. @@ -174,9 +181,9 @@ FULL_MARKERS = (".diff",) @dataclass(frozen=True) class ChunkSpec: - """How to slice a fused weight along dim 0 for one target module. + """How to take a fused weight's rows along dim 0 for one target module. - Two forms supported: + Three forms; the reorder composes with either slice: - Equal chunks (``idx`` + ``total``): fused QKV split into Q/K/V via ``torch.chunk(up, total, dim=0)[idx]``. Used by flux2 / z-image where @@ -185,6 +192,11 @@ class ChunkSpec: ``up[start:end]``. Used by chroma's single-block ``linear1`` which fuses Q / K / V / proj_mlp at unequal sizes (``[3072, 3072, 3072, 12288]``). + - Row reorder (``reorder``): the module lays out equal row blocks in a + different order from the save; ``(1, 0)`` swaps the halves of a fused + SwiGLU projection saved ``[gate; value]`` onto a ``[value; gate]`` + module. Applied to the rows the slice selects. Only the LoRA family + permutes rows; the others skip a reordered target. Generic loaders check :attr:`is_equal_chunks` to decide between the two forms and select the appropriate ``NetworkModule*Chunk`` / @@ -194,11 +206,16 @@ class ChunkSpec: total: int | None = None start: int | None = None end: int | None = None + reorder: tuple[int, ...] | None = None @property def is_equal_chunks(self) -> bool: return self.idx is not None and self.total is not None + @property + def is_slice(self) -> bool: + return self.is_equal_chunks or self.start is not None + # === Key normalizations (applied universally by parse_key) === @@ -248,6 +265,7 @@ def has_marker(state_dict, markers): def resolve_mapping(): + from modules import shared """Ensure ``network_layer_mapping`` is populated, return it (or empty dict).""" sd_model = getattr(shared.sd_model, "pipe", shared.sd_model) lora_convert.assign_network_names_to_compvis_modules(sd_model) @@ -288,19 +306,19 @@ def finalize_network(net, name, family, lora_scale, t0, unmapped=0, mismatch=0, return net -def shapes_match(sd_module, down_w: torch.Tensor, up_w: torch.Tensor) -> bool: - """LoRA-style rank-and-dim sanity check against the live module weight. - - Honors SDNQ-quantized modules by reading the original shape from the - dequantizer rather than the packed weight tensor. - """ +def module_shape(sd_module): + """The live weight shape of a module, read from the dequantizer for SDNQ-quantized layers; None without a weight.""" if not hasattr(sd_module, "weight"): - return False + return None if hasattr(sd_module, "sdnq_dequantizer"): - mod_shape = sd_module.sdnq_dequantizer.original_shape - else: - mod_shape = sd_module.weight.shape - if len(mod_shape) < 2 or len(down_w.shape) < 2 or len(up_w.shape) < 2: + return tuple(sd_module.sdnq_dequantizer.original_shape) + return tuple(sd_module.weight.shape) + + +def shapes_match(sd_module, down_w: torch.Tensor, up_w: torch.Tensor) -> bool: + """LoRA-style rank-and-dim sanity check against the live module weight.""" + mod_shape = module_shape(sd_module) + if mod_shape is None or len(mod_shape) < 2 or len(down_w.shape) < 2 or len(up_w.shape) < 2: return False return down_w.shape[1] == mod_shape[1] and up_w.shape[0] == mod_shape[0] @@ -368,7 +386,7 @@ def lokr_shapes_match(sd_module, kron_shape, chunk: ChunkSpec | None) -> bool: kron_out, kron_in_flat = kron_shape if kron_in_flat != mod_in_flat: return False - if chunk is None: + if chunk is None or not chunk.is_slice: return kron_out == mod_shape[0] if chunk.is_equal_chunks: return kron_out == mod_shape[0] * chunk.total @@ -378,15 +396,15 @@ def lokr_shapes_match(sd_module, kron_shape, chunk: ChunkSpec | None) -> bool: # === Parsing primitives === -def parse_key(key, suffixes, *, prefixes=KNOWN_PREFIXES_DEFAULT, bare_prefixes=(), bare_diffusers_prefixes=()): +def parse_key(key, suffixes, *, prefixes=KNOWN_PREFIXES_DEFAULT): """Return ``(prefix_used, base, suffix_normalized)`` or ``None``. - ``prefix_used`` is the matched element of ``prefixes``, ``BARE_DIFFUSERS_PREFIX_USED`` - if a member of ``bare_diffusers_prefixes`` matched, or ``None`` for a key - that matched a member of ``bare_prefixes``. ``base`` is the path with prefix - and suffix removed. ``suffix_normalized`` is the suffix (without the leading - dot) after applying :data:`SUFFIX_NORMALIZE` (e.g. ``lora_A.weight`` becomes - ``lora_down.weight``). + ``prefix_used`` is the matched element of ``prefixes``, or + ``BARE_DIFFUSERS_PREFIX_USED`` for a bare key, which the loader offers to + the resolver and counts as unmapped when nothing binds. ``base`` is the + path with prefix and suffix removed. ``suffix_normalized`` is the suffix + (without the leading dot) after applying :data:`SUFFIX_NORMALIZE` (e.g. + ``lora_A.weight`` becomes ``lora_down.weight``). Always applies :func:`unwrap_peft_wrapper` and :func:`strip_peft_adapter_name` to the raw key before format detection so callers do not have to opt in. @@ -401,10 +419,7 @@ def parse_key(key, suffixes, *, prefixes=KNOWN_PREFIXES_DEFAULT, bare_prefixes=( stripped = key[len(p):] break if prefix_used is None: - if any(key.startswith(p) for p in bare_diffusers_prefixes): - prefix_used = BARE_DIFFUSERS_PREFIX_USED - elif not any(key.startswith(p) for p in bare_prefixes): - return None + prefix_used = BARE_DIFFUSERS_PREFIX_USED matched_suffix = None split_at = -1 @@ -424,7 +439,7 @@ def parse_key(key, suffixes, *, prefixes=KNOWN_PREFIXES_DEFAULT, bare_prefixes=( return prefix_used, base, suffix -def group_by_suffixes(state_dict, suffixes, *, prefixes=KNOWN_PREFIXES_DEFAULT, bare_prefixes=(), bare_diffusers_prefixes=()): +def group_by_suffixes(state_dict, suffixes, *, prefixes=KNOWN_PREFIXES_DEFAULT): """Group state-dict entries by ``(prefix_used, base)``. Returns ``{(prefix_used, base): {suffix: tensor, ...}}`` where each suffix @@ -434,12 +449,7 @@ def group_by_suffixes(state_dict, suffixes, *, prefixes=KNOWN_PREFIXES_DEFAULT, """ groups: dict[tuple, dict[str, torch.Tensor]] = {} for key, value in state_dict.items(): - parsed = parse_key( - key, suffixes, - prefixes=prefixes, - bare_prefixes=bare_prefixes, - bare_diffusers_prefixes=bare_diffusers_prefixes, - ) + parsed = parse_key(key, suffixes, prefixes=prefixes) if parsed is None: continue prefix_used, base, suffix = parsed @@ -451,11 +461,6 @@ def group_by_suffixes(state_dict, suffixes, *, prefixes=KNOWN_PREFIXES_DEFAULT, return groups -# Surface ``sd_models.read_state_dict`` here so loader modules don't have to -# import ``sd_models`` directly; keeps the per-arch wrapper imports compact. -read_state_dict = sd_models.read_state_dict - - def resolve_group_targets(resolve_targets, prefix_used, base): """Map a parsed ``(prefix_used, base)`` group to ``[(diffusers_path, chunk), ...]``. @@ -508,20 +513,27 @@ def resolve_group_targets(resolve_targets, prefix_used, base): def slice_chunk_rows(t, chunk: ChunkSpec): - """Slice dim 0 of ``t`` per ``chunk``. + """Slice dim 0 of ``t`` per ``chunk``, then lay the selected rows out in the chunk's order. Equal-chunks form uses ``torch.chunk`` (faster for the symmetric case); row-range form uses tensor slicing for arbitrary partitions. """ if chunk.is_equal_chunks: - return torch.chunk(t, chunk.total, dim=0)[chunk.idx].contiguous() - return t[chunk.start:chunk.end].contiguous() + t = torch.chunk(t, chunk.total, dim=0)[chunk.idx] + elif chunk.start is not None: + t = t[chunk.start:chunk.end] + if chunk.reorder is not None: + blocks = torch.chunk(t, len(chunk.reorder), dim=0) + t = torch.cat([blocks[i] for i in chunk.reorder], dim=0) + return t.contiguous() -def _slice_lora_chunk(w, chunk: ChunkSpec): - """Return a shallow copy of ``w`` with ``lora_up.weight`` sliced per ``chunk``.""" +def slice_lora_chunk(w, chunk: ChunkSpec): + """Return a shallow copy of ``w`` with ``lora_up.weight`` sliced per ``chunk``; a dense bias follows a pure reorder.""" out = dict(w) out["lora_up.weight"] = slice_chunk_rows(w["lora_up.weight"], chunk) + if "bias" in w and not chunk.is_slice: + out["bias"] = slice_chunk_rows(w["bias"], chunk) return out @@ -564,13 +576,22 @@ def slice_bias_delta(w, chunk: ChunkSpec, fused_out): def try_load_lora(name, network_on_disk, lora_scale, *, resolve_targets, prefixes=KNOWN_PREFIXES_DEFAULT, - bare_prefixes=(), bare_diffusers_prefixes=(), network_prefix=NETWORK_PREFIX_DEFAULT, + group_by_suffixes_fn=group_by_suffixes, + network_alpha=None, + adapt_weights=None, arch_name="generic"): """Generic LoRA loader (handles DoRA via the universal ``finalize_updown`` hook). Fused targets are chunked at load time by slicing ``lora_up`` along dim 0; the down-side is shared across the resolved targets. + + ``network_alpha`` is a file-level alpha for files without alpha tensors; + a file carrying any alpha of its own keeps those and ignores it. + + ``adapt_weights(sd_module, network_key, w)`` lets an arch refit a delta onto + a module whose live layout differs from the trained one (a pruned AdaLN + basis, for instance) before the shape check; returning None keeps ``w``. """ t0 = time.time() state_dict = read_state_dict(network_on_disk.filename, what="network") @@ -579,12 +600,12 @@ def try_load_lora(name, network_on_disk, lora_scale, *, mapping = resolve_mapping() net = new_network(name, network_on_disk) - groups = group_by_suffixes( + groups = group_by_suffixes_fn( state_dict, LORA_SUFFIXES, prefixes=prefixes, - bare_prefixes=bare_prefixes, - bare_diffusers_prefixes=bare_diffusers_prefixes, ) + if network_alpha is not None and any("alpha" in w for w in groups.values()): + network_alpha = None unmapped = 0 mismatch = 0 @@ -592,6 +613,9 @@ def try_load_lora(name, network_on_disk, lora_scale, *, for (prefix, base), w in groups.items(): if "lora_down.weight" not in w or "lora_up.weight" not in w: continue + if network_alpha is not None: + w = dict(w) + w["alpha"] = torch.tensor(float(network_alpha)) # DoRA magnitude vectors: ai-toolkit saves `magnitude`, PEFT/diffusers # `lora_magnitude_vector`. Both are 1-D per-output row norms with # dora_scale semantics; reshape to (out, 1) so the apply-time @@ -612,14 +636,14 @@ def try_load_lora(name, network_on_disk, lora_scale, *, target_w = w if chunk is not None: - if "bias" in w or "bias_indices" in w: + if "bias_indices" in w or ("bias" in w and chunk.is_slice): # Weight-shaped bias residuals (dense or LyCORIS sparse # triplet) are not partitioned onto fused targets. log.warning(f'Network load: type=LoRA name="{name}" arch={arch_name} key={network_key} weight-shaped bias on fused target skipped (unsupported)') skipped += 1 continue fused_out = w["lora_up.weight"].shape[0] - target_w = _slice_lora_chunk(w, chunk) + target_w = slice_lora_chunk(w, chunk) target_w = slice_dora_scale(target_w, chunk, fused_out) if target_w is None: log.warning(f'Network load: type=LoRA name="{name}" arch={arch_name} key={network_key} per-input DoRA on fused target skipped (unsupported)') @@ -631,22 +655,20 @@ def try_load_lora(name, network_on_disk, lora_scale, *, skipped += 1 continue + if adapt_weights is not None: + target_w = adapt_weights(sd_module, network_key, target_w) or target_w + if not shapes_match(sd_module, target_w["lora_down.weight"], target_w["lora_up.weight"]): - log.warning( - f'Network load: type=LoRA name="{name}" arch={arch_name} key={network_key}' - f' lora={target_w["lora_down.weight"].shape[1]}x{target_w["lora_up.weight"].shape[0]}' - f' module={getattr(sd_module, "weight", None).shape if hasattr(sd_module, "weight") else "?"}' - f' shape mismatch' - ) + if l.debug: + _module = f'{getattr(sd_module, "weight", None).shape if hasattr(sd_module, "weight") else "?"}' + log.warning(f'Network load: type=LoRA name="{name}" arch={arch_name} key={network_key} lora={target_w["lora_down.weight"].shape[1]}x{target_w["lora_up.weight"].shape[0]} module={_module} shape mismatch') mismatch += 1 continue if "diff_b" in target_w and not bias_delta_fits(sd_module, target_w["diff_b"]): - log.warning( - f'Network load: type=LoRA name="{name}" arch={arch_name} key={network_key}' - f' bias={tuple(target_w["diff_b"].shape)} module={tuple(sd_module.bias.shape)}' - f' bias shape mismatch' - ) + if l.debug: + _bias = f'bias={tuple(target_w["diff_b"].shape)} module={tuple(sd_module.bias.shape)}' + log.warning(f'Network load: type=LoRA name="{name}" arch={arch_name} key={network_key} {_bias} bias shape mismatch') mismatch += 1 continue @@ -658,8 +680,8 @@ def try_load_lora(name, network_on_disk, lora_scale, *, def try_load_lokr(name, network_on_disk, lora_scale, *, resolve_targets, prefixes=KNOWN_PREFIXES_DEFAULT, - bare_prefixes=(), bare_diffusers_prefixes=(), network_prefix=NETWORK_PREFIX_DEFAULT, + group_by_suffixes_fn=group_by_suffixes, arch_name="generic"): """Generic LoKR loader. @@ -677,11 +699,9 @@ def try_load_lokr(name, network_on_disk, lora_scale, *, mapping = resolve_mapping() net = new_network(name, network_on_disk) - groups = group_by_suffixes( + groups = group_by_suffixes_fn( state_dict, LOKR_SUFFIXES, prefixes=prefixes, - bare_prefixes=bare_prefixes, - bare_diffusers_prefixes=bare_diffusers_prefixes, ) unmapped = 0 @@ -711,6 +731,10 @@ def try_load_lokr(name, network_on_disk, lora_scale, *, continue target_w = w if chunk is not None: + if chunk.reorder is not None: + log.warning(f'Network load: type=LoKR name="{name}" arch={arch_name} key={network_key} row reorder on fused target skipped (unsupported)') + skipped += 1 + continue if "bias" in w: log.warning(f'Network load: type=LoKR name="{name}" arch={arch_name} key={network_key} weight-shaped bias on fused target skipped (unsupported)') skipped += 1 @@ -739,8 +763,8 @@ def try_load_lokr(name, network_on_disk, lora_scale, *, def try_load_loha(name, network_on_disk, lora_scale, *, resolve_targets, prefixes=KNOWN_PREFIXES_DEFAULT, - bare_prefixes=(), bare_diffusers_prefixes=(), network_prefix=NETWORK_PREFIX_DEFAULT, + group_by_suffixes_fn=group_by_suffixes, arch_name="generic"): """Generic LoHA (Hadamard product) loader. @@ -757,11 +781,9 @@ def try_load_loha(name, network_on_disk, lora_scale, *, mapping = resolve_mapping() net = new_network(name, network_on_disk) - groups = group_by_suffixes( + groups = group_by_suffixes_fn( state_dict, LOHA_SUFFIXES, prefixes=prefixes, - bare_prefixes=bare_prefixes, - bare_diffusers_prefixes=bare_diffusers_prefixes, ) unmapped = 0 @@ -773,7 +795,7 @@ def try_load_loha(name, network_on_disk, lora_scale, *, targets = resolve_group_targets(resolve_targets, prefix, base) is_fused = any(t[1] is not None for t in targets) if is_fused and is_tucker: - log.warning(f'Network load: type=LoHA name="{name}" arch={arch_name} key={base} Tucker fused QKV skipped (unsupported)') + log.warning(f'Network load: type=LoHA name="{name}" arch={arch_name} key={base} Tucker fused target skipped (unsupported)') skipped += 1 continue arch_prefix = _resolve_prefix(network_prefix, prefix) @@ -785,6 +807,10 @@ def try_load_loha(name, network_on_disk, lora_scale, *, continue target_w = w if chunk is not None: + if chunk.reorder is not None: + log.warning(f'Network load: type=LoHA name="{name}" arch={arch_name} key={network_key} row reorder on fused target skipped (unsupported)') + skipped += 1 + continue if "bias" in w: log.warning(f'Network load: type=LoHA name="{name}" arch={arch_name} key={network_key} weight-shaped bias on fused target skipped (unsupported)') skipped += 1 @@ -808,8 +834,8 @@ def try_load_loha(name, network_on_disk, lora_scale, *, def try_load_oft(name, network_on_disk, lora_scale, *, resolve_targets, prefixes=KNOWN_PREFIXES_DEFAULT, - bare_prefixes=(), bare_diffusers_prefixes=(), network_prefix=NETWORK_PREFIX_DEFAULT, + group_by_suffixes_fn=group_by_suffixes, arch_name="generic"): """Generic OFT/BOFT loader. @@ -832,11 +858,9 @@ def try_load_oft(name, network_on_disk, lora_scale, *, mapping = resolve_mapping() net = new_network(name, network_on_disk) - groups = group_by_suffixes( + groups = group_by_suffixes_fn( state_dict, OFT_SUFFIXES, prefixes=prefixes, - bare_prefixes=bare_prefixes, - bare_diffusers_prefixes=bare_diffusers_prefixes, ) unmapped = 0 @@ -847,7 +871,7 @@ def try_load_oft(name, network_on_disk, lora_scale, *, is_boft = "oft_blocks" in w and w["oft_blocks"].ndim == 4 targets = resolve_group_targets(resolve_targets, prefix, base) if any(t[1] is not None for t in targets): - log.warning(f'Network load: type={"BOFT" if is_boft else "OFT"} name="{name}" arch={arch_name} key={base} fused QKV skipped (unsupported)') + log.warning(f'Network load: type={"BOFT" if is_boft else "OFT"} name="{name}" arch={arch_name} key={base} fused target skipped (unsupported)') skipped += 1 continue arch_prefix = _resolve_prefix(network_prefix, prefix) @@ -868,8 +892,8 @@ def try_load_oft(name, network_on_disk, lora_scale, *, def try_load_ia3(name, network_on_disk, lora_scale, *, resolve_targets, prefixes=KNOWN_PREFIXES_DEFAULT, - bare_prefixes=(), bare_diffusers_prefixes=(), network_prefix=NETWORK_PREFIX_DEFAULT, + group_by_suffixes_fn=group_by_suffixes, arch_name="generic"): """Generic IA3 loader. @@ -891,11 +915,9 @@ def try_load_ia3(name, network_on_disk, lora_scale, *, mapping = resolve_mapping() net = new_network(name, network_on_disk) - groups = group_by_suffixes( + groups = group_by_suffixes_fn( state_dict, IA3_SUFFIXES, prefixes=prefixes, - bare_prefixes=bare_prefixes, - bare_diffusers_prefixes=bare_diffusers_prefixes, ) unmapped = 0 @@ -905,7 +927,7 @@ def try_load_ia3(name, network_on_disk, lora_scale, *, continue targets = resolve_group_targets(resolve_targets, prefix, base) if any(t[1] is not None for t in targets): - log.warning(f'Network load: type=IA3 name="{name}" arch={arch_name} key={base} fused QKV skipped (unsupported)') + log.warning(f'Network load: type=IA3 name="{name}" arch={arch_name} key={base} fused target skipped (unsupported)') skipped += 1 continue arch_prefix = _resolve_prefix(network_prefix, prefix) @@ -923,8 +945,8 @@ def try_load_ia3(name, network_on_disk, lora_scale, *, def try_load_glora(name, network_on_disk, lora_scale, *, resolve_targets, prefixes=KNOWN_PREFIXES_DEFAULT, - bare_prefixes=(), bare_diffusers_prefixes=(), network_prefix=NETWORK_PREFIX_DEFAULT, + group_by_suffixes_fn=group_by_suffixes, arch_name="generic"): """Generic GLoRA loader. @@ -942,11 +964,9 @@ def try_load_glora(name, network_on_disk, lora_scale, *, mapping = resolve_mapping() net = new_network(name, network_on_disk) - groups = group_by_suffixes( + groups = group_by_suffixes_fn( state_dict, GLORA_SUFFIXES, prefixes=prefixes, - bare_prefixes=bare_prefixes, - bare_diffusers_prefixes=bare_diffusers_prefixes, ) unmapped = 0 @@ -956,7 +976,7 @@ def try_load_glora(name, network_on_disk, lora_scale, *, continue targets = resolve_group_targets(resolve_targets, prefix, base) if any(t[1] is not None for t in targets): - log.warning(f'Network load: type=GLoRA name="{name}" arch={arch_name} key={base} fused QKV skipped (unsupported)') + log.warning(f'Network load: type=GLoRA name="{name}" arch={arch_name} key={base} fused target skipped (unsupported)') skipped += 1 continue arch_prefix = _resolve_prefix(network_prefix, prefix) @@ -974,8 +994,8 @@ def try_load_glora(name, network_on_disk, lora_scale, *, def try_load_norm(name, network_on_disk, lora_scale, *, resolve_targets, prefixes=KNOWN_PREFIXES_DEFAULT, - bare_prefixes=(), bare_diffusers_prefixes=(), network_prefix=NETWORK_PREFIX_DEFAULT, + group_by_suffixes_fn=group_by_suffixes, arch_name="generic"): # pylint: disable=unused-argument """Generic Norm (LayerNorm / RMSNorm weight + bias delta) loader. @@ -996,11 +1016,9 @@ def try_load_norm(name, network_on_disk, lora_scale, *, mapping = resolve_mapping() net = new_network(name, network_on_disk) - groups = group_by_suffixes( + groups = group_by_suffixes_fn( state_dict, NORM_SUFFIXES, prefixes=prefixes, - bare_prefixes=bare_prefixes, - bare_diffusers_prefixes=bare_diffusers_prefixes, ) unmapped = 0 @@ -1039,8 +1057,8 @@ def try_load_norm(name, network_on_disk, lora_scale, *, def try_load_full(name, network_on_disk, lora_scale, *, resolve_targets, prefixes=KNOWN_PREFIXES_DEFAULT, - bare_prefixes=(), bare_diffusers_prefixes=(), network_prefix=NETWORK_PREFIX_DEFAULT, + group_by_suffixes_fn=group_by_suffixes, arch_name="generic"): """Generic Full (full-rank weight delta) loader. @@ -1057,11 +1075,9 @@ def try_load_full(name, network_on_disk, lora_scale, *, mapping = resolve_mapping() net = new_network(name, network_on_disk) - groups = group_by_suffixes( + groups = group_by_suffixes_fn( state_dict, FULL_SUFFIXES, prefixes=prefixes, - bare_prefixes=bare_prefixes, - bare_diffusers_prefixes=bare_diffusers_prefixes, ) unmapped = 0 @@ -1072,7 +1088,7 @@ def try_load_full(name, network_on_disk, lora_scale, *, continue targets = resolve_group_targets(resolve_targets, prefix, base) if any(t[1] is not None for t in targets): - log.warning(f'Network load: type=Full name="{name}" arch={arch_name} key={base} fused QKV skipped (unsupported)') + log.warning(f'Network load: type=Full name="{name}" arch={arch_name} key={base} fused target skipped (unsupported)') skipped += 1 continue arch_prefix = _resolve_prefix(network_prefix, prefix) @@ -1114,6 +1130,7 @@ def try_load_chain(name, network_on_disk, lora_scale, family_loaders): tuple of partial-applied generic loaders, each already bound to the arch's ``resolve_targets`` and prefix tuples. """ + from modules import sd_models_utils sd_models_utils.state_dict_cache.enable() net = None mismatch = 0 @@ -1126,6 +1143,7 @@ def try_load_chain(name, network_on_disk, lora_scale, family_loaders): net = sub else: net.modules.update(sub.modules) + net.extras.update(sub.extras) sd_models_utils.state_dict_cache.disable() if net is not None and mismatch > 0: # applying only the layers that fit leaves the model in a state nothing was trained for log.error(f'Network load: type=LoRA name="{name}" modules={len(net.modules)} mismatch={mismatch} shapes do not match the loaded model') diff --git a/modules/lora/network.py b/modules/lora/network.py index b16060563..5f23407ca 100644 --- a/modules/lora/network.py +++ b/modules/lora/network.py @@ -22,11 +22,11 @@ class SdVersion(enum.Enum): class NetworkOnDisk: - def __init__(self, name, filename): + def __init__(self, name: str, filename: str): self.shorthash = None self.hash = None - self.name = name - self.filename = filename + self.name: str = name + self.filename: str = filename if filename.startswith(shared.cmd_opts.lora_dir): # strip("/") missed Windows's leading backslash after the slice; normalize separators # so the registry key is one canonical form on every OS. @@ -76,6 +76,10 @@ class NetworkOnDisk: return 'anima' if base.startswith('qwen'): return 'qwen' + if base.startswith('krea2'): + return 'krea2' + if base.startswith('minimax'): + return 'minimax' if arch.startswith("stable-diffusion-v1"): return 'sd1' @@ -83,7 +87,7 @@ class NetworkOnDisk: return 'xl' if arch.startswith("stable-cascade"): return 'sc' - if arch.startswith("flux2") or "klein" in arch: + if arch.startswith("flux2") or arch.startswith("flux-2") or ("klein" in arch): return 'f2' if arch.startswith("flux"): return 'f1' @@ -91,12 +95,18 @@ class NetworkOnDisk: return 'hv' if arch.startswith("chroma"): return 'chroma' + if arch.startswith('wan'): + return 'wan' + if arch.startswith('anima'): + return 'anima' + if arch.startswith('krea2'): + return 'krea2' if "v1-5" in str(self.metadata.get('ss_sd_model_name', "")): return 'sd1' if str(self.metadata.get('ss_v2', "")) == "True": return 'sd2' - if 'klein' in self.name.lower() or 'klein' in self.fullname.lower(): + if 'klein' in self.name.lower() or ('klein' in self.fullname.lower()): return 'f2' if 'flux' in self.name.lower(): return 'f1' @@ -148,8 +158,10 @@ class Network: # LoraModule self.te_multiplier = 1.0 self.unet_multiplier = [1.0] * 3 self.dyn_dim = None + self.block_spec = None # raw lbw= value; per-layer factors resolve through lora_blocks self.pending_config = None # staged multipliers; network_activate promotes them after the removal pass so fuse removal subtracts the delta that was applied self.modules = {} + self.extras = {} # non-delta payloads a family carries, e.g. parallel heads self.mismatch = 0 # deltas dropped for not fitting their target module; try_load_chain refuses the file when non-zero self.bundle_embeddings = {} self.mtime = None @@ -195,15 +207,19 @@ class NetworkModule: def multiplier(self): unet_multiplier = 3 * [self.network.unet_multiplier] if not isinstance(self.network.unet_multiplier, list) else self.network.unet_multiplier if self.sd_key.startswith('lora_te') or 'transformer' in self.sd_key[:20]: - return self.network.te_multiplier - if "down_blocks" in self.sd_key: - return unet_multiplier[0] - if "mid_block" in self.sd_key: - return unet_multiplier[1] - if "up_blocks" in self.sd_key: - return unet_multiplier[2] + base = self.network.te_multiplier + elif "down_blocks" in self.sd_key: + base = unet_multiplier[0] + elif "mid_block" in self.sd_key: + base = unet_multiplier[1] + elif "up_blocks" in self.sd_key: + base = unet_multiplier[2] else: - return unet_multiplier[0] + base = unet_multiplier[0] + if getattr(self.network, 'block_spec', None) is None: # per-block strength is off for this network; no shared access on this path + return base + from modules.lora import lora_blocks + return base * lora_blocks.factor(self.sd_key, self.network) def calc_scale(self): if self.scale is not None: diff --git a/modules/lora/network_lokr.py b/modules/lora/network_lokr.py index 096d7f568..0f2328a9e 100644 --- a/modules/lora/network_lokr.py +++ b/modules/lora/network_lokr.py @@ -32,7 +32,8 @@ class NetworkModuleLokr(network.NetworkModule): # pylint: disable=abstract-metho self.dim = self.w2b.shape[0] if self.w2b is not None else self.dim self.t2 = weights.w.get("lokr_t2") - def calc_updown(self, target): + def rebuild_operands(self, target): + """The two Kronecker operands on the target's device and dtype, each either stored whole or rebuilt from its factors.""" if self.w1 is not None: w1 = self.w1.to(target.device, dtype=target.dtype) else: @@ -50,8 +51,12 @@ class NetworkModuleLokr(network.NetworkModule): # pylint: disable=abstract-metho w2a = self.w2a.to(target.device, dtype=target.dtype) w2b = self.w2b.to(target.device, dtype=target.dtype) w2 = lyco_helpers.make_weight_cp(t2, w2a, w2b) + return w1, w2 + + def calc_updown(self, target): + w1, w2 = self.rebuild_operands(target) output_shape = [w1.size(0) * w2.size(0), w1.size(1) * w2.size(1)] - if len(target.shape) == 4: + if len(target.shape) == 4: # a conv target keeps its own shape; the chunk variants below only ever address 2-d fused weights output_shape = target.shape updown = make_kron(output_shape, w1, w2) return self.finalize_updown(updown, target, output_shape) @@ -70,23 +75,7 @@ class NetworkModuleLokrChunk(NetworkModuleLokr): self.num_chunks = num_chunks def calc_updown(self, target): - if self.w1 is not None: - w1 = self.w1.to(target.device, dtype=target.dtype) - else: - w1a = self.w1a.to(target.device, dtype=target.dtype) - w1b = self.w1b.to(target.device, dtype=target.dtype) - w1 = w1a @ w1b - if self.w2 is not None: - w2 = self.w2.to(target.device, dtype=target.dtype) - elif self.t2 is None: - w2a = self.w2a.to(target.device, dtype=target.dtype) - w2b = self.w2b.to(target.device, dtype=target.dtype) - w2 = w2a @ w2b - else: - t2 = self.t2.to(target.device, dtype=target.dtype) - w2a = self.w2a.to(target.device, dtype=target.dtype) - w2b = self.w2b.to(target.device, dtype=target.dtype) - w2 = lyco_helpers.make_weight_cp(t2, w2a, w2b) + w1, w2 = self.rebuild_operands(target) full_shape = [w1.size(0) * w2.size(0), w1.size(1) * w2.size(1)] updown = make_kron(full_shape, w1, w2) updown = torch.chunk(updown, self.num_chunks, dim=0)[self.chunk_index] @@ -109,23 +98,7 @@ class NetworkModuleLokrSliceChunk(NetworkModuleLokr): self.end_row = end_row def calc_updown(self, target): - if self.w1 is not None: - w1 = self.w1.to(target.device, dtype=target.dtype) - else: - w1a = self.w1a.to(target.device, dtype=target.dtype) - w1b = self.w1b.to(target.device, dtype=target.dtype) - w1 = w1a @ w1b - if self.w2 is not None: - w2 = self.w2.to(target.device, dtype=target.dtype) - elif self.t2 is None: - w2a = self.w2a.to(target.device, dtype=target.dtype) - w2b = self.w2b.to(target.device, dtype=target.dtype) - w2 = w2a @ w2b - else: - t2 = self.t2.to(target.device, dtype=target.dtype) - w2a = self.w2a.to(target.device, dtype=target.dtype) - w2b = self.w2b.to(target.device, dtype=target.dtype) - w2 = lyco_helpers.make_weight_cp(t2, w2a, w2b) + w1, w2 = self.rebuild_operands(target) full_shape = [w1.size(0) * w2.size(0), w1.size(1) * w2.size(1)] updown = make_kron(full_shape, w1, w2) updown = updown[self.start_row:self.end_row] diff --git a/modules/lora/network_pdd.py b/modules/lora/network_pdd.py new file mode 100644 index 000000000..f84dcf098 --- /dev/null +++ b/modules/lora/network_pdd.py @@ -0,0 +1,336 @@ +"""Parallel decoding distillation heads carried by a native network. + +A PDD file pairs a backbone LoRA with the output projections repeated once per interval of an N-step +training grid; each step fuses the heads of its block into one projection, so N / block_size evaluations +walk the trajectory. Heads ride on ``Network.extras['pdd']``: ``reconcile`` installs and removes them with +the loaded set, ``pin`` holds the step count and schedule the file was distilled for. +""" + +import os +import copy +import weakref +import torch +from modules.logger import log + + +debug_log = log.trace if os.environ.get('SD_LORA_DEBUG', None) is not None else lambda *args, **kwargs: None + + +METADATA_STEPS = 'pdd_num_steps' +METADATA_BLOCK = 'pdd_block_size' +EXTRAS_KEY = 'pdd' + + +class ArchSpec: + """How an architecture hosts parallel heads: the scheduler behind each head and how interval counts map onto its num_inference_steps.""" + + def __init__(self, schedulers=None, default_scheduler='scheduler', steps_for=None, shift_keys=None): + self.schedulers = schedulers or {} # head path -> attribute of the scheduler the head was trained on + self.default_scheduler = default_scheduler + self.steps_for = steps_for or (lambda intervals: intervals) # num_inference_steps that yields this many grid intervals + self.shift_keys = shift_keys or {} # scheduler attribute -> infotext key the pinned shift is recorded under + + def scheduler_name(self, head): + return self.schedulers.get(head, self.default_scheduler) + + +class ParallelHeads: + """The head tensors of one file and the grid they were trained on.""" + + def __init__(self, num_steps, block_size, heads): + self.num_steps = num_steps + self.block_size = block_size + self.heads = heads # head path -> (weight [N, out, in], bias [N, out] or None) + self.nfe = num_steps // block_size + + +class Installed: + """Bookkeeping for the heads currently swapped into a pipeline.""" + + def __init__(self, name, strength, component, modules, heads, spec): + self.name = name + self.strength = strength + self.component = component + self.modules = modules # head path -> (parent, attribute, original module) + self.heads = heads + self.spec = spec + self.steps = spec.steps_for(heads.nfe) + + +def detect(metadata): + """The (num_steps, block_size) grid a file declares; None without PDD metadata, ValueError for an unusable grid.""" + metadata = metadata or {} + if METADATA_STEPS not in metadata: + return None + num_steps = int(metadata[METADATA_STEPS]) + block_size = int(metadata.get(METADATA_BLOCK, 1)) + if num_steps < 1 or block_size < 1 or num_steps % block_size != 0: + raise ValueError(f'grid={num_steps} block={block_size}') + return num_steps, block_size + + +def load(name, metadata, state_dict): + """Collect the per-interval head tensors of a file, or None when the file carries no PDD grid.""" + try: + grid = detect(metadata) + except ValueError as e: + log.error(f'Network load: type=PDD name="{name}" {e} block size must divide the grid') + return None + if grid is None: + return None + num_steps, block_size = grid + heads = {} + for key, tensor in state_dict.items(): + if key.endswith('.weight') and tensor.ndim == 3 and tensor.shape[0] == num_steps: + path = key[:-len('.weight')] + heads[path] = (tensor, state_dict.get(f'{path}.bias', None)) + if len(heads) == 0: + log.error(f'Network load: type=PDD name="{name}" grid={num_steps} block={block_size} no head tensors') + return None + log.debug(f'Network load: type=PDD name="{name}" grid={num_steps} block={block_size} nfe={num_steps // block_size} heads={list(heads)}') + return ParallelHeads(num_steps, block_size, heads) + + +def header_metadata(filename, name): + """The metadata read from the file itself, for when the cached metadata lacks the grid; warns when head-shaped tensors have no grid.""" + from safetensors import safe_open + try: + with safe_open(filename, framework='pt', device='cpu') as f: + metadata = f.metadata() or {} + if METADATA_STEPS in metadata: + log.debug(f'Network load: type=PDD name="{name}" grid read from the file header') + else: + heads = sum(1 for key in f.keys() if key.endswith('.weight') and len(f.get_slice(key).get_shape()) == 3) + if heads > 0: + log.warning(f'Network load: type=PDD name="{name}" heads={heads} no {METADATA_STEPS} metadata: heads ignored') + return metadata + except Exception as e: + log.warning(f'Network load: type=PDD name="{name}" header {e}') + return {} + + +def try_load(name, network_on_disk, lora_scale): # pylint: disable=unused-argument + """Family loader for the native chain: a network carrying only the heads.""" + metadata = getattr(network_on_disk, 'metadata', None) or {} + if METADATA_STEPS not in metadata: + metadata = header_metadata(network_on_disk.filename, name) # the metadata cache keeps a failed read forever and --no-metadata returns nothing + if METADATA_STEPS not in metadata: + return None + from modules.lora import native_adapter + state_dict = native_adapter.read_state_dict(network_on_disk.filename, what='network') + heads = load(name, metadata, state_dict) + if heads is None: + return None + net = native_adapter.new_network(name, network_on_disk) + net.extras[EXTRAS_KEY] = heads + return net + + +def base_tensors(module): + """Float copies of a projection's weight and bias for the strength blend; None when the weight is not a plain tensor.""" + weight = getattr(module, 'weight', None) + if weight is None or getattr(module, 'sdnq_dequantizer', None) is not None or not torch.is_floating_point(weight) or weight.ndim != 2: + return None, None + bias = getattr(module, 'bias', None) + return weight.detach().to(dtype=torch.float32), None if bias is None else bias.detach().to(dtype=torch.float32) + + +class ParallelHead(torch.nn.Module): + """An output projection replaced by its per-interval heads, fused per step for the block the scheduler is about to take.""" + + def __init__(self, base, weight, bias, strength, get_scheduler, block_size, intervals): + super().__init__() + object.__setattr__(self, 'base', base) # kept out of the module tree so nothing walks, offloads or serializes it + object.__setattr__(self, 'get_scheduler', get_scheduler) + self.weight = torch.nn.Parameter(weight.to(dtype=torch.float32), requires_grad=False) # float32 like the projection it replaces + self.bias = None if bias is None else torch.nn.Parameter(bias.to(dtype=torch.float32), requires_grad=False) + self.register_buffer('intervals', intervals.to(dtype=torch.float32)) + self.in_features = weight.shape[2] + self.out_features = weight.shape[1] + self.num_steps = weight.shape[0] + self.block_size = block_size + self.strength = strength + self.base_weight, self.base_bias = base_tensors(base) if strength != 1.0 else (None, None) + self.fused_index = None + self.fused_weight = None + self.fused_bias = None + self.overflow_warned = False + + def step_index(self): + scheduler = self.get_scheduler() + index = getattr(scheduler, 'step_index', None) if scheduler is not None else None + index = 0 if index is None else int(index) + nfe = self.num_steps // self.block_size + if index >= nfe: + if not self.overflow_warned: + self.overflow_warned = True + log.warning(f'Network: type=PDD step={index} nfe={nfe} schedule longer than the distilled grid') + index = nfe - 1 + return index + + def fuse(self, index): + start = index * self.block_size + stop = start + self.block_size + plan = torch.zeros(self.num_steps, dtype=torch.float32, device=self.weight.device) + span = self.intervals[start:stop] + plan[start:stop] = (span / span.sum()).to(device=plan.device) + weight = torch.tensordot(plan, self.weight.detach(), dims=1) + bias = None if self.bias is None else plan @ self.bias.detach() + if self.base_weight is not None: + base_weight = self.base_weight.to(device=weight.device) + weight = base_weight + self.strength * (weight - base_weight) + if bias is not None and self.base_bias is not None: + base_bias = self.base_bias.to(device=bias.device) + bias = base_bias + self.strength * (bias - base_bias) + self.fused_index, self.fused_weight, self.fused_bias = index, weight, bias + debug_log(f'Network: type=PDD fuse block={index} heads={start}:{stop} out={self.out_features} strength={self.strength}') + + def forward(self, hidden_states): + index = self.step_index() + if index != self.fused_index or self.fused_weight is None or self.fused_weight.device != self.weight.device: + self.fuse(index) + weight = self.fused_weight.to(device=hidden_states.device, dtype=hidden_states.dtype) + bias = None if self.fused_bias is None else self.fused_bias.to(device=hidden_states.device, dtype=hidden_states.dtype) + return torch.nn.functional.linear(hidden_states, weight, bias) + + +def grid_intervals(scheduler, num_steps, spec): + """Interval lengths of the training grid in ascending time, from a pristine scheduler copy immune to a live shift override.""" + probe = scheduler.__class__.from_config(scheduler.config) if hasattr(scheduler, 'from_config') else copy.deepcopy(scheduler) + probe.set_timesteps(spec.steps_for(num_steps)) + sigmas = probe.sigmas.detach().to(device='cpu', dtype=torch.float64) + if sigmas.numel() != num_steps + 1: + return None + return (1.0 - sigmas).diff() + + +def submodule(component, path): + try: + return component.get_submodule(path) + except AttributeError: + return None + + +def owner(pipe, heads, components): + """The component holding every head projection, as (name, module); (None, None) when no component has them all.""" + for name in components: + component = getattr(pipe, name, None) + if component is not None and hasattr(component, 'get_submodule') and all(submodule(component, path) is not None for path in heads.heads): + return name, component + return None, None + + +def target_shape(module): + dequantizer = getattr(module, 'sdnq_dequantizer', None) + if dequantizer is not None and getattr(dequantizer, 'original_shape', None) is not None: + return tuple(dequantizer.original_shape) + weight = getattr(module, 'weight', None) + return tuple(weight.shape) if weight is not None else None + + +def install(pipe, net, heads, spec, components): + """Swap the heads into the component that owns their projections; True when the module tree changed.""" + component_name, component = owner(pipe, heads, components) + if component is None: + log.error(f'Network load: type=PDD name="{net.name}" heads={list(heads.heads)} no loaded component holds these projections') + return False + strength = float(net.te_multiplier) # transformer-keyed layers scale by the te multiplier, see network.NetworkModule.multiplier + pipe_ref = weakref.ref(pipe) + modules = {} + for path, (weight, bias) in heads.heads.items(): + module = submodule(component, path) + shape = target_shape(module) + if shape != tuple(weight.shape[1:]): + log.error(f'Network load: type=PDD name="{net.name}" head={path} shape={list(weight.shape[1:])} module={list(shape) if shape else None} shape mismatch') + for parent, attr, original in modules.values(): + setattr(parent, attr, original) + return False + scheduler_name = spec.scheduler_name(path) + scheduler = getattr(pipe, scheduler_name, None) + intervals = grid_intervals(scheduler, heads.num_steps, spec) if scheduler is not None else None + if intervals is None: + log.error(f'Network load: type=PDD name="{net.name}" head={path} scheduler={scheduler.__class__.__name__} cannot build a {heads.num_steps}-interval grid') + for parent, attr, original in modules.values(): + setattr(parent, attr, original) + return False + def get_scheduler(name=scheduler_name): + owner_pipe = pipe_ref() + return getattr(owner_pipe, name, None) if owner_pipe is not None else None + for tensor in list(module.parameters()) + list(module.buffers()): + tensor.data = tensor.data.clone() # nothing moves the stashed projection, and a shard view would keep the whole shard mapped + head = ParallelHead(module, weight, bias, strength, get_scheduler, heads.block_size, intervals) + parent_path, _, attr = path.rpartition('.') + parent = component.get_submodule(parent_path) if parent_path else component + setattr(parent, attr, head) + modules[path] = (parent, attr, module) + pipe.sdnext_pdd = Installed(net.name, strength, component_name, modules, heads, spec) + log.info(f'Network load: type=PDD name="{net.name}" component={component_name} heads={list(modules)} grid={heads.num_steps} block={heads.block_size} nfe={heads.nfe} steps={pipe.sdnext_pdd.steps} strength={strength}') + return True + + +def restore(pipe): + """Put the original projections back; True when heads were installed.""" + state = getattr(pipe, 'sdnext_pdd', None) + if state is None: + return False + for parent, attr, original in state.modules.values(): + setattr(parent, attr, original) + del pipe.sdnext_pdd + log.info(f'Network unload: type=PDD name="{state.name}" component={state.component} heads={list(state.modules)}') + return True + + +def arch_spec(): + """The parallel-head spec of the loaded architecture's native loader module, or None.""" + import importlib + from modules import shared + from modules.lora import lora_load + module_name = lora_load.NATIVE_DISPATCH.get(shared.sd_model_type) + if module_name is None: + return None + return getattr(importlib.import_module(module_name), 'PDD', None) + + +def reconcile(pipe, loaded, components): + """Match the installed heads to the loaded networks; True when the module tree changed.""" + carriers = [net for net in loaded if EXTRAS_KEY in getattr(net, 'extras', {})] + if len(carriers) == 0: + return restore(pipe) + if len(carriers) > 1: + log.warning(f'Network load: type=PDD networks={[net.name for net in carriers]} one grid per model, using first') + net = carriers[0] + current = getattr(pipe, 'sdnext_pdd', None) + if current is not None and current.name == net.name and current.strength == float(net.te_multiplier): + return False + spec = arch_spec() + if spec is None: + from modules import shared + log.error(f'Network load: type=PDD name="{net.name}" type={shared.sd_model_type} architecture has no parallel head support') + return restore(pipe) + changed = restore(pipe) + return install(pipe, net, net.extras[EXTRAS_KEY], spec, components) or changed + + +def pin(p, model): + """Hold a generation on the distilled evaluation count and shipped schedule while heads are installed; returns the scheduler step argument or None.""" + state = getattr(model, 'sdnext_pdd', None) + if state is None: + return None + shifts = {} + for path in state.modules: + name = state.spec.scheduler_name(path) + scheduler = getattr(model, name, None) + if scheduler is not None and hasattr(scheduler, 'set_shift') and getattr(scheduler, 'config', None) is not None and 'shift' in scheduler.config: + scheduler.set_shift(scheduler.config['shift']) + shifts[name] = scheduler.config['shift'] + requested = p.steps + p.steps = state.heads.nfe # what the user-facing step count means: transformer evaluations + if getattr(p, 'task_args', None) is not None: + p.task_args['num_inference_steps'] = state.steps # the scheduler argument that yields that many grid intervals + if getattr(model, 'num_timesteps', None) is not None: + model.num_timesteps = state.heads.nfe # the progress total counts transformer evaluations + extra = getattr(p, 'extra_generation_params', None) + if extra is not None: + extra.update({state.spec.shift_keys[name]: shift for name, shift in shifts.items() if name in state.spec.shift_keys}) + log.info(f'Network: type=PDD name="{state.name}" steps={state.heads.nfe} requested={requested} grid_steps={state.steps} shift={shifts}') + return state.steps diff --git a/modules/lora/networks.py b/modules/lora/networks.py index 31945c27d..cab987fdf 100644 --- a/modules/lora/networks.py +++ b/modules/lora/networks.py @@ -1,17 +1,121 @@ +"""Applies the loaded networks to the model and takes them off again. + +One walk visits every module of every component and offers each layer to +the mechanisms in a fixed order: a selection schedule, exact factors on the +quantized side channel, a truncated host on that channel, and the weight +path, which takes whatever the others declined. Order is semantics, not +preference: each mechanism is more faithful than the one after it, and only +the weight path can take any layer. + +Contracts the walk depends on: + +- The wanted-name tuple is built once per pass and handed to every layer as + the same object. The factor cache memoizes its pass entry on that + identity, so an equal tuple rebuilt per component makes every lookup + reread the entry from disk. +- Mechanism apply functions answer with three states: applied, took the + layer without changing it, or declined. Only a decline falls through. +- A layer is offered to a mechanism on its checkpoint weights, so factors + attach to a clean base and deltas are measured against one. `apply_cached` + can strip factors and still decline, which is why the weight path strips + again before it writes. +- The fuse decision is resolved once per pass and shared by backup, apply + and restore. Backup mode keeps a tensor and restores in the walk itself; + fuse mode keeps a marker and subtracts the delta in network_deactivate. +- Selection registration reads the factors it schedules, so it follows the + attach that produced them. + +State the walk keeps on the model's own modules: + +- network_layer_name: written by lora_convert and native_adapter. +- network_current_names and network_current_stack: written here, always + together, and read together as the skip key. +- network_weights_backup, network_bias_backup and the sdnq_*_backup set: + written by lora_apply, a tensor in backup mode and True as the fuse marker. +- sdnq_lora_svd_stash: written by lora_sdnq, holding the checkpoint's own + factors while a set is attached. +- sdnq_calib_rms: written by lora_calib. +- svd_up and svd_down: owned by sdnq, attached by lora_sdnq, restored by + lora_apply, and written in segments by lora_stack at flip time. +""" + from contextlib import nullcontext import time import rich.progress as rp from modules.errorlimiter import limit_errors +from modules.lora import lora_blocks from modules.lora import lora_common as l +from modules.lora import lora_overrides +from modules.lora import lora_sdnq +from modules.lora import lora_stack +from modules.lora import network_pdd from modules.lora.lora_apply import network_apply_weights, network_apply_direct, network_backup_weights, network_calc_weights -from modules import shared, devices, sd_models +from modules import shared, devices, sd_models, errors from modules.logger import log, console applied_layers: list[str] = [] refused_writes: int = 0 # deltas the modules would not take on the last activate pass; infotext reports the network as partial native_active: bool = False -default_components = ['text_encoder', 'text_encoder_2', 'text_encoder_3', 'text_encoder_4', 'unet', 'transformer', 'transformer_2', 'llm_adapter'] +default_components = ['text_encoder', 'text_encoder_2', 'text_encoder_3', 'text_encoder_4', 'unet', 'transformer', 'transformer_2', 'transformer_ref', 'llm_adapter'] + + +class ActivationPass: + """State of one activation walk, built before the walk so a pass that raises still has it. + + `wanted_names` is built once here and reaches every layer as + `component_wanted`, either this tuple or the empty one. The factor cache + keys its pass entry on that object's identity, so an equal tuple rebuilt + per component would send every lookup back to disk. + """ + + def __init__(self, fuse): + self.sd_model = getattr(shared.sd_model, "pipe", shared.sd_model) + self.fuse = fuse + self.elimit = None # the error limiter, bound for the duration of the walk + self.wanted_names: tuple[tuple[str, float, list, int | None], ...] = tuple((x.name, x.te_multiplier, x.unet_multiplier, x.dyn_dim) for x in l.loaded_networks) if len(l.loaded_networks) > 0 else () + self.stack_sig = lora_stack.signature() + lora_blocks.signature() + lora_sdnq.signature() # tracked beside network_current_names so stack-setting, block-weight and mechanism changes re-apply + self.select_active = len(l.loaded_networks) > 0 and lora_stack.active_select(len(l.loaded_networks)) # restore-only walks have nothing to stack; the count warning would fire on every network-free generation + self.component_wanted: tuple[tuple[str, float, list, int | None], ...] = () + self.device = None + self.group_offload = shared.opts.diffusers_offload_mode == "group" + self.group_stripped = {} + self.pbar = nullcontext() + self.task = None + self.total = 0 + self.active_components = [] + self.applied_weight = 0 + self.applied_bias = 0 + self.refused = 0 + self.backup_size = 0 + + def stamp(self, module): + """Mark the layer as carrying this set under these settings; the pair is the skip key.""" + module.network_current_names = self.component_wanted + module.network_current_stack = self.stack_sig + + def tick(self, description=None): + if self.task is None: + return + if description is None: + self.pbar.update(self.task, advance=1) + else: + self.pbar.update(self.task, advance=1, description=description) + + def claim(self, module, network_layer_name, changed): + """Accept a layer one of the mechanisms took; only a layer whose weights changed counts as applied.""" + if changed and self.component_wanted: + applied_layers.append(network_layer_name) + self.applied_weight += 1 + self.stamp(module) + self.tick() + + def keep_selected(self, module, network_layer_name, sel_backup): + """Hold a scheduled weight-kind layer on its pristine tensor until the schedule applies the winner.""" + self.backup_size += sel_backup # counted only where this branch keeps the layer; the weight path below re-enters the shared backup call, which counts it then + network_apply_weights(module, None, None, device=self.device) + self.claim(module, network_layer_name, True) + return True def group_will_mutate(module, network_layer_name: str, loaded) -> bool: @@ -41,104 +145,259 @@ def group_offload_strip(sd_model, component_name: str, stripped: dict): return stripped[component_name] -def network_activate(include=None, exclude=None): - if exclude is None: - exclude = [] - if include is None: - include = [] - for net in l.loaded_networks: # promote staged multipliers only now: the deactivate pass ran against the previous values, which fuse-mode removal recomputes with +def promote_pending(): + """Promote staged multipliers onto the loaded networks; the deactivate pass ran against the previous values, which fuse-mode removal recomputes with.""" + for net in l.loaded_networks: pending = getattr(net, 'pending_config', None) if pending is not None: net.te_multiplier = pending['te'] net.unet_multiplier = pending['unet'] net.dyn_dim = pending['dyn'] - t0 = time.time() - with limit_errors("network_activate") as elimit: - sd_model = getattr(shared.sd_model, "pipe", shared.sd_model) - if shared.opts.diffusers_offload_mode == "sequential": - sd_models.disable_offload(sd_model) - sd_models.move_model(sd_model, device=devices.cpu) - elif shared.opts.diffusers_offload_mode == "balanced": - sd_model = sd_models.apply_balanced_offload(sd_model, force=True) # dispatched modules hold meta tensors backed by the offload map; rebuild them real on cpu with hooks intact before touching weights - group_offload = shared.opts.diffusers_offload_mode == "group" - group_stripped = {} - device = None - modules = {} - components = include if len(include) > 0 else default_components - components = [x for x in components if x not in exclude] - filtered_components = [x for x in default_components if x not in components] # filtered components restore to backup so a filter means detached, not frozen with stale weights - active_components = [] - for name in components + filtered_components: - component = getattr(sd_model, name, None) - if component is not None and hasattr(component, 'named_modules'): - if name in components: - active_components.append(name) - modules[name] = list(component.named_modules()) - total = sum(len(x) for x in modules.values()) - if len(l.loaded_networks) > 0: - pbar = rp.Progress(rp.TextColumn('[cyan]Network: type=LoRA action=activate'), rp.BarColumn(), rp.TaskProgressColumn(), rp.TimeRemainingColumn(), rp.TimeElapsedColumn(), rp.TextColumn('[cyan]{task.description}'), console=console) - task = pbar.add_task(description='' , total=total) - else: - task = None - pbar = nullcontext() - applied_weight = 0 - applied_bias = 0 - refused = 0 - with devices.inference_context(), pbar: - wanted_names = tuple((x.name, x.te_multiplier, x.unet_multiplier, x.dyn_dim) for x in l.loaded_networks) if len(l.loaded_networks) > 0 else () - applied_layers.clear() - backup_size = 0 - for component in modules.keys(): - component_wanted = wanted_names if component in components else () - device = getattr(sd_model, component, None).device - for _, module in modules[component]: - network_layer_name = getattr(module, 'network_layer_name', None) - current_names = getattr(module, "network_current_names", ()) - if getattr(module, 'weight', None) is None or shared.state.interrupted or (network_layer_name is None) or (current_names == component_wanted): - if task is not None: - pbar.update(task, advance=1) - continue - if group_offload and component not in group_stripped and group_will_mutate(module, network_layer_name, l.loaded_networks): - device = group_offload_strip(sd_model, component, group_stripped) - backup_size += network_backup_weights(module, network_layer_name, component_wanted) - if not component_wanted: - weights_backup = getattr(module, "network_weights_backup", None) - if weights_backup is None or isinstance(weights_backup, bool): # fuse mode has no tensor backup, restore stays with network_deactivate - if task is not None: - pbar.update(task, advance=1) - continue - batch_updown, batch_ex_bias = None, None # restore-only pass, apply with no weights reverts to backup - else: - batch_updown, batch_ex_bias = network_calc_weights(module, network_layer_name, elimit=elimit) - if shared.opts.lora_fuse_native: - weight_written, bias_written = network_apply_direct(module, batch_updown, batch_ex_bias, device=device) - else: - weight_written, bias_written = network_apply_weights(module, batch_updown, batch_ex_bias, device=device) - if batch_updown is not None or batch_ex_bias is not None: - applied_layers.append(network_layer_name) - applied_weight += 1 if weight_written else 0 - applied_bias += 1 if bias_written else 0 - refused += (batch_updown is not None and not weight_written) + (batch_ex_bias is not None and not bias_written) # a delta the module would not take leaves that layer on its base value - batch_updown, batch_ex_bias = None, None - del batch_updown, batch_ex_bias - module.network_current_names = component_wanted - if task is not None: - bs = round(backup_size/1024/1024/1024, 2) if backup_size > 0 else None - pbar.update(task, advance=1, description=f'networks={len(l.loaded_networks)} modules={active_components} layers={total} weights={applied_weight} bias={applied_bias} backup={bs} device={device}') + net.block_spec = pending.get('blocks', None) + net.pending_config = None # promotion is one-shot - if task is not None and len(applied_layers) == 0: - pbar.remove_task(task) # hide progress bar for no action + +def prepare_model_for_write(sd_model): + """Bring the model into a state where weight writes land; balanced offload returns a rebuilt model.""" + if shared.opts.diffusers_offload_mode == "sequential": + sd_models.disable_offload(sd_model) + sd_models.move_model(sd_model, device=devices.cpu) + elif shared.opts.diffusers_offload_mode == "balanced": + sd_model = sd_models.apply_balanced_offload(sd_model, force=True, silent=True) # dispatched modules hold meta tensors backed by the offload map; rebuild them real on cpu with hooks intact before touching weights + return sd_model + + +def collect_components(sd_model, include, exclude, defaults, restore_filtered): + """Modules to walk, as (modules, wanted components, walked component names, module count). + + With restore_filtered the walk also covers the components a filter left + out, so they restore to backup instead of freezing with stale weights; + those names stay out of the reported list because nothing applies to them. + """ + components = include if len(include) > 0 else defaults + components = [x for x in components if x not in exclude] + filtered = [x for x in defaults if x not in components] if restore_filtered else [] + modules = {} + active_components = [] + for name in components + filtered: + component = getattr(sd_model, name, None) + if component is not None and hasattr(component, 'named_modules'): + if name in components: + active_components.append(name) + modules[name] = list(component.named_modules()) + return modules, components, active_components, sum(len(x) for x in modules.values()) + + +def pass_progress(action, total, show): + """Progress bar for one pass, or a nullcontext with no task when there is nothing to show.""" + if not show: + return nullcontext(), None + pbar = rp.Progress(rp.TextColumn(f'[cyan]Network: type=LoRA action={action}'), rp.BarColumn(), rp.TaskProgressColumn(), rp.TimeRemainingColumn(), rp.TimeElapsedColumn(), rp.TextColumn('[cyan]{task.description}'), console=console) + return pbar, pbar.add_task(description='', total=total) + + +def tensor_backup(module): + """The module's weight backup when it holds real tensors; None in fuse mode, where the backup is a marker.""" + weights_backup = getattr(module, 'network_weights_backup', None) + return None if isinstance(weights_backup, bool) else weights_backup + + +def restore_pristine(module, device): + """Put a backed-up layer back on its checkpoint weights, so a mechanism sees the pristine base.""" + if tensor_backup(module) is not None: + network_apply_weights(module, None, None, device=device) + + +def should_skip(module, network_layer_name, wanted, stack_sig): + """True when the pass has nothing to do here: no weight, interrupted, unnamed, or already carrying this set under these settings.""" + if getattr(module, 'weight', None) is None or shared.state.interrupted or network_layer_name is None: + return True + return getattr(module, 'network_current_names', ()) == wanted and getattr(module, 'network_current_stack', 'sum') == stack_sig + + +def try_select(ctx, module, network_layer_name): + """Put the layer under a selection schedule; True when it took the layer. + + The three arms are mutually exclusive and their warnings are keyed, so a + layer that cannot be scheduled reports one reason and falls through. + """ + if not ctx.select_active or not ctx.component_wanted or network_layer_name.startswith('lora_te'): + return False + if lora_sdnq.select_candidate(module, network_layer_name, ctx.component_wanted): # SDNQ pairs ride the channel as separate segments at any bit width; weight rewrites cannot flip a quantized layer + restore_pristine(module, ctx.device) + applied = lora_sdnq.apply_select_cached(module, network_layer_name, ctx.component_wanted) # a stored score record and factor pair serve before the deltas are assembled + if applied is None: + per_net, sel_bias = network_calc_weights(module, network_layer_name, elimit=ctx.elimit, per_net=True) + if sel_bias is None: + applied = lora_sdnq.apply_select(module, network_layer_name, per_net, ctx.component_wanted) + if applied is not None: + ctx.claim(module, network_layer_name, applied) + return True + lora_stack.warn_once('select-unridable', f'Network stack: mode={lora_stack.mode()} layer="{network_layer_name}" fallback=sum') # a pair the channel cannot carry (bias delta or malformed member) sums like any unsupported set + elif getattr(module, 'sdnq_dequantizer', None) is not None: # hosting disabled: quantized layers have no side-channel to carry segments and packed backups cannot flip, so the sum paths below take the layer + if any(net.modules.get(network_layer_name, None) is not None for net in l.loaded_networks): + lora_stack.warn_once('select-host-disabled', f'Network stack: mode={lora_stack.mode()} quant=sdnq host=disabled fallback=sum') + else: # other layers select by recomputing the winner from the pristine backup at schedule time + sel_backup = network_backup_weights(module, network_layer_name, ctx.component_wanted, ctx.fuse) + if tensor_backup(module) is not None: # a flip recomputes the winner from the pristine tensor, which fuse mode does not keep + if lora_stack.register_weight_pair_cached(network_layer_name, module, ctx.component_wanted): # a stored score record registers without assembling the pair + return ctx.keep_selected(module, network_layer_name, sel_backup) + per_net, sel_bias = network_calc_weights(module, network_layer_name, elimit=ctx.elimit, per_net=True) + if sel_bias is None and lora_stack.register_weight_pair(network_layer_name, module, per_net, ctx.component_wanted): + return ctx.keep_selected(module, network_layer_name, sel_backup) + return False + + +def try_factors(ctx, module, network_layer_name): + """Attach the set to the quantized side channel as exact factors; True when it took the layer.""" + if not lora_sdnq.factor_candidate(module, network_layer_name, ctx.component_wanted): + return False + restore_pristine(module, ctx.device) # an earlier non-factorable set may have requantized this layer + applied = lora_sdnq.apply_factors(module, network_layer_name, ctx.component_wanted) + if applied is None: # the exact path declined; hosting or the weight path takes the layer + return False + ctx.claim(module, network_layer_name, applied) + return True + + +def try_hosted(ctx, module, network_layer_name): + """Host the combined delta on the side channel as truncated factors. + + Returns whether it took the layer and, when it declined after assembling + the delta, that delta, so the weight path applies it without a second + calc. A returned pair of Nones still counts as assembled. + """ + if not lora_sdnq.host_candidate(module, network_layer_name, ctx.component_wanted): + return False, None + restore_pristine(module, ctx.device) # the hosted delta is measured against the pristine base + batch = None + hosted = lora_sdnq.apply_cached(module, network_layer_name, ctx.component_wanted) # a stored entry serves the layer before the delta is assembled + if hosted is None: + batch_updown, batch_ex_bias = network_calc_weights(module, network_layer_name, elimit=ctx.elimit) + batch = (batch_updown, batch_ex_bias) + if batch_ex_bias is None: # bias deltas need the plain path; weight-only sets ride the side-channel without a weight backup + hosted = lora_sdnq.apply_hosted(module, network_layer_name, batch_updown, ctx.component_wanted) + if hosted is not None: + batch = None # hosting took the delta + if hosted is None: + return False, batch + ctx.claim(module, network_layer_name, hosted) + return True, None + + +def apply_generic(ctx, module, network_layer_name, batch): + """The weight path, which takes any layer the mechanisms above declined.""" + stripped = lora_sdnq.remove_factors(module) # the mechanism gate can decline a layer still carrying attached factors; the weight path must start from the pristine channel + if stripped and not ctx.component_wanted: # factor-mode layers have no tensor backup, dropping the factors is the whole restore + ctx.stamp(module) + ctx.tick() + return + ctx.backup_size += network_backup_weights(module, network_layer_name, ctx.component_wanted, ctx.fuse) + if not ctx.component_wanted: + lora_stack.drop(network_layer_name) # a restored layer must leave the selection schedule + if tensor_backup(module) is None: # fuse mode has no tensor backup, restore stays with network_deactivate + ctx.tick() + return + batch_updown, batch_ex_bias = None, None # restore-only pass, apply with no weights reverts to backup + else: + batch_updown, batch_ex_bias = batch if batch is not None else network_calc_weights(module, network_layer_name, elimit=ctx.elimit) + if batch_updown is not None: + lora_sdnq.note_fallback(module, network_layer_name) # only layers whose quantized weight actually takes a delta + if ctx.fuse: + weight_written, bias_written = network_apply_direct(module, batch_updown, batch_ex_bias, device=ctx.device) + else: + weight_written, bias_written = network_apply_weights(module, batch_updown, batch_ex_bias, device=ctx.device) + if batch_updown is not None or batch_ex_bias is not None: + applied_layers.append(network_layer_name) + ctx.applied_weight += 1 if weight_written else 0 + ctx.applied_bias += 1 if bias_written else 0 + ctx.refused += (batch_updown is not None and not weight_written) + (batch_ex_bias is not None and not bias_written) # a delta the module would not take leaves that layer on its base value + ctx.stamp(module) + bs = round(ctx.backup_size/1024/1024/1024, 2) if ctx.backup_size > 0 else None + ctx.tick(f'networks={len(l.loaded_networks)} modules={ctx.active_components} layers={ctx.total} weights={ctx.applied_weight} bias={ctx.applied_bias} backup={bs} device={ctx.device}') + + +def finish_pass(ctx, t0): + """Publish what the pass did and put the model back under its offload mode. + + Runs even when the error limiter aborts the walk: the hooks it stripped + and the offload it disabled have to come back, and the counters other + modules read have to describe this pass. + """ global native_active, refused_writes # pylint: disable=global-statement + lora_sdnq.report_fallbacks() native_active = len(l.loaded_networks) > 0 - refused_writes = refused + refused_writes = ctx.refused + l.last_backup_size = ctx.backup_size + l.last_mode = 'backup' if ctx.backup_size > 0 else ('fuse' if ctx.fuse else 'factor') l.timer.activate += time.time() - t0 - if refused > 0: - log.error(f'Network load: type=LoRA networks={[n.name for n in l.loaded_networks]} weights={applied_weight} bias={applied_bias} refused={refused} network partially applied') + if ctx.refused > 0: + log.error(f'Network load: type=LoRA networks={[n.name for n in l.loaded_networks]} weights={ctx.applied_weight} bias={ctx.applied_bias} refused={ctx.refused} network partially applied') if l.debug and len(l.loaded_networks) > 0: - log.debug(f'Network load: type=LoRA networks={[n.name for n in l.loaded_networks]} modules={active_components} layers={total} weights={applied_weight} bias={applied_bias} refused={refused} backup={round(backup_size/1024/1024/1024, 2)} fuse={shared.opts.lora_fuse_native}:{shared.opts.lora_fuse_diffusers} device={device} time={l.timer.summary}') - modules.clear() - if len(applied_layers) > 0 or shared.opts.diffusers_offload_mode == "sequential" or len(group_stripped) > 0: - sd_models.set_diffuser_offload(sd_model, op="model") + log.debug(f'Network load: type=LoRA networks={[n.name for n in l.loaded_networks]} modules={ctx.active_components} layers={ctx.total} weights={ctx.applied_weight} bias={ctx.applied_bias} refused={ctx.refused} backup={round(ctx.backup_size/1024/1024/1024, 2)} fuse={ctx.fuse}:{shared.opts.lora_fuse_diffusers} device={ctx.device} time={l.timer.summary}') + try: + heads_changed = network_pdd.reconcile(ctx.sd_model, l.loaded_networks, default_components) # carried projections swap with the loaded set before the offload snapshot below + except Exception as e: + heads_changed = False + errors.display(e, 'Network load: type=PDD') + if len(applied_layers) > 0 or shared.opts.diffusers_offload_mode == "sequential" or len(ctx.group_stripped) > 0 or heads_changed: + sd_models.set_diffuser_offload(ctx.sd_model, op="model") + + +def network_activate(include=None, exclude=None): + if exclude is None: + exclude = [] + if include is None: + include = [] + promote_pending() + t0 = time.time() + ctx = ActivationPass(lora_overrides.fuse_native()) # fuse resolved once: the backup, apply and restore paths must agree + applied_layers.clear() + lora_sdnq.reset_pass() + modules = {} + try: + with limit_errors("network_activate") as elimit: + ctx.elimit = elimit + ctx.sd_model = prepare_model_for_write(ctx.sd_model) + modules, components, ctx.active_components, ctx.total = collect_components(ctx.sd_model, include, exclude, default_components, restore_filtered=True) + ctx.pbar, ctx.task = pass_progress('activate', ctx.total, len(l.loaded_networks) > 0) + with devices.inference_context(), ctx.pbar: + for component in modules.keys(): + ctx.component_wanted = ctx.wanted_names if component in components else () # the pass tuple itself, never a copy + ctx.device = getattr(ctx.sd_model, component, None).device + for _, module in modules[component]: + network_layer_name = getattr(module, 'network_layer_name', None) + if should_skip(module, network_layer_name, ctx.component_wanted, ctx.stack_sig): + ctx.tick() + continue + lora_stack.drop(network_layer_name) # re-application invalidates any live selection schedule; the select branch re-registers + if ctx.group_offload and component not in ctx.group_stripped and group_will_mutate(module, network_layer_name, l.loaded_networks): + ctx.device = group_offload_strip(ctx.sd_model, component, ctx.group_stripped) + if try_select(ctx, module, network_layer_name): + continue + if try_factors(ctx, module, network_layer_name): + continue + hosted, batch = try_hosted(ctx, module, network_layer_name) + if hosted: + continue + apply_generic(ctx, module, network_layer_name, batch) + if ctx.task is not None and len(applied_layers) == 0: + ctx.pbar.remove_task(ctx.task) # hide progress bar for no action + finally: + finish_pass(ctx, t0) + modules.clear() + + +def effective_mode(): + """Weight-state label for load logs: backup and fuse say how touched weights restore, factor means the whole load rode the svd channel and unload just drops factors. + + Recorded by the pass rather than derived here, so the unload line + describes the pass being unloaded even when the settings it ran under + have since changed. + """ + if l.last_mode: + return l.last_mode + return 'fuse' if lora_overrides.fuse_native() else 'factor' def network_deactivate(include=None, exclude=None): @@ -146,37 +405,18 @@ def network_deactivate(include=None, exclude=None): exclude = [] if include is None: include = [] - if not shared.opts.lora_fuse_native or shared.opts.lora_force_diffusers: + fuse = lora_overrides.fuse_native() # must match network_activate: backup mode restores in its restore-only pass instead + if not fuse or shared.opts.lora_force_diffusers: return if len(l.previously_loaded_networks) == 0: return t0 = time.time() with limit_errors("network_deactivate") as elimit: - sd_model = getattr(shared.sd_model, "pipe", shared.sd_model) - if shared.opts.diffusers_offload_mode == "sequential": - sd_models.disable_offload(sd_model) - sd_models.move_model(sd_model, device=devices.cpu) - elif shared.opts.diffusers_offload_mode == "balanced": - sd_model = sd_models.apply_balanced_offload(sd_model, force=True) # dispatched modules hold meta tensors backed by the offload map; rebuild them real on cpu with hooks intact before touching weights + sd_model = prepare_model_for_write(getattr(shared.sd_model, "pipe", shared.sd_model)) group_offload = shared.opts.diffusers_offload_mode == "group" group_stripped = {} - modules = {} - - components = include if len(include) > 0 else ['text_encoder', 'text_encoder_2', 'text_encoder_3', 'unet', 'transformer', 'llm_adapter'] - components = [x for x in components if x not in exclude] - active_components = [] - for name in components: - component = getattr(sd_model, name, None) - if component is not None and hasattr(component, 'named_modules'): - modules[name] = list(component.named_modules()) - active_components.append(name) - total = sum(len(x) for x in modules.values()) - if len(l.previously_loaded_networks) > 0 and l.debug: - pbar = rp.Progress(rp.TextColumn('[cyan]Network: type=LoRA action=deactivate'), rp.BarColumn(), rp.TaskProgressColumn(), rp.TimeRemainingColumn(), rp.TimeElapsedColumn(), rp.TextColumn('[cyan]{task.description}'), console=console) - task = pbar.add_task(description='', total=total) - else: - task = None - pbar = nullcontext() + modules, _components, active_components, total = collect_components(sd_model, include, exclude, default_components, restore_filtered=False) + pbar, task = pass_progress('deactivate', total, len(l.previously_loaded_networks) > 0 and l.debug) refused = 0 with devices.inference_context(), pbar: applied_layers.clear() @@ -190,8 +430,14 @@ def network_deactivate(include=None, exclude=None): continue if group_offload and component not in group_stripped and group_will_mutate(module, network_layer_name, l.previously_loaded_networks): device = group_offload_strip(sd_model, component, group_stripped) + if lora_sdnq.remove_factors(module): # exact inverse for factor-mode layers, weights were never touched + applied_layers.append(network_layer_name) + module.network_current_names = () + if task is not None: + pbar.update(task, advance=1) + continue batch_updown, batch_ex_bias = network_calc_weights(module, network_layer_name, use_previous=True, elimit=elimit) - if shared.opts.lora_fuse_native: + if fuse: weight_written, bias_written = network_apply_direct(module, batch_updown, batch_ex_bias, device=device, deactivate=True) else: weight_written, bias_written = network_apply_weights(module, batch_updown, batch_ex_bias, device=device, deactivate=True) @@ -202,11 +448,11 @@ def network_deactivate(include=None, exclude=None): module.network_current_names = () if task is not None: pbar.update(task, advance=1, description=f'networks={len(l.previously_loaded_networks)} modules={active_components} layers={total} unapply={len(applied_layers)}') - l.timer.deactivate = time.time() - t0 + l.timer.deactivate += time.time() - t0 if refused > 0: log.error(f'Network unload: type=LoRA networks={[n.name for n in l.previously_loaded_networks]} unapply={len(applied_layers)} refused={refused} network partially removed') if l.debug and len(l.previously_loaded_networks) > 0: - log.debug(f'Network deactivate: type=LoRA networks={[n.name for n in l.previously_loaded_networks]} modules={active_components} layers={total} apply={len(applied_layers)} refused={refused} fuse={shared.opts.lora_fuse_native}:{shared.opts.lora_fuse_diffusers} time={l.timer.summary}') + log.debug(f'Network deactivate: type=LoRA networks={[n.name for n in l.previously_loaded_networks]} modules={active_components} layers={total} apply={len(applied_layers)} refused={refused} fuse={fuse}:{shared.opts.lora_fuse_diffusers} time={l.timer.summary}') modules.clear() if len(applied_layers) > 0 or shared.opts.diffusers_offload_mode == "sequential" or len(group_stripped) > 0: sd_models.set_diffuser_offload(sd_model, op="model") diff --git a/modules/ltx/ltx_util.py b/modules/ltx/ltx_util.py index 74f07f52e..76f8ec9d7 100644 --- a/modules/ltx/ltx_util.py +++ b/modules/ltx/ltx_util.py @@ -59,11 +59,13 @@ def load_upsample(upsample_pipe, upsample_repo_id): t0 = time.time() from diffusers.pipelines.ltx.pipeline_ltx_latent_upsample import LTXLatentUpsamplePipeline log.info(f'Load video: cls={LTXLatentUpsamplePipeline.__name__} repo="{upsample_repo_id}"') + offline_args = {'local_files_only': True} if shared.opts.offline_mode else {} upsample_pipe = LTXLatentUpsamplePipeline.from_pretrained( upsample_repo_id, vae=shared.sd_model.vae, cache_dir=shared.opts.hfcache_dir, torch_dtype=devices.dtype, + **offline_args, ) # only the upsampler, since the pipe borrows the model's vae and moving the whole pipe # would drag that along into the meta tensors the caller's offload exclude avoids @@ -85,11 +87,13 @@ def load_upsample_2x(upsample_pipe, upsample_repo_id, variant: str = '2.x'): from diffusers.pipelines.ltx2.latent_upsampler import LTX2LatentUpsamplerModel from modules import sd_checkpoint log.info(f'Load video: cls={LTX2LatentUpsamplePipeline.__name__} repo="{upsample_repo_id}"') + offline_args = {'local_files_only': True} if shared.opts.offline_mode else {} latent_upsampler = LTX2LatentUpsamplerModel.from_pretrained( upsample_repo_id, subfolder='latent_upsampler', cache_dir=shared.opts.hfcache_dir, torch_dtype=devices.dtype, + **offline_args, ).to(devices.device) upsample_pipe = LTX2LatentUpsamplePipeline( vae=shared.sd_model.vae, @@ -245,7 +249,7 @@ def get_conditions(width, height, condition_strength, condition_images, conditio def get_prompts(p): prompt = shared.prompt_styles.apply_styles_to_prompt(p.prompt, p.styles) negative = shared.prompt_styles.apply_negative_styles_to_prompt(p.negative_prompt, p.styles) - prompts, networks = extra_networks.parse_prompts([prompt]) + prompts, networks = extra_networks.parse_prompts([prompt], p.network_data) prompt = prompts[0] if len(prompts) > 0 else prompt return prompt, negative, networks diff --git a/modules/masking.py b/modules/masking.py index eafafe311..0767f79a7 100644 --- a/modules/masking.py +++ b/modules/masking.py @@ -117,16 +117,6 @@ def fill(image, mask): return image_mod.convert("RGB") -""" -[docs](https://huggingface.co/docs/transformers/v4.36.1/en/model_doc/sam#overview) -TODO: additional masking algorithms -- PerSAM -- REMBG -- https://huggingface.co/docs/transformers/tasks/semantic_segmentation -- transformers.pipeline.MaskGenerationPipeline: https://huggingface.co/models?pipeline_tag=mask-generation -- transformers.pipeline.ImageSegmentationPipeline: https://huggingface.co/models?pipeline_tag=image-segmentation -""" - MODELS = { 'None': None, 'Facebook SAM ViT Base': 'facebook/sam-vit-base', @@ -273,7 +263,7 @@ def run_rembg(input_image: Image.Image, input_mask: np.ndarray): if "U2NET_HOME" not in os.environ: os.environ["U2NET_HOME"] = os.path.join(paths.models_path, "Rembg") if opts.model == 'ben2': - from modules import ben2 + from modules.rembg import ben2 args = { 'image': input_image, 'refine': True, diff --git a/modules/minimax/minimax_ui.py b/modules/minimax/minimax_ui.py index 314628b06..69890ceeb 100644 --- a/modules/minimax/minimax_ui.py +++ b/modules/minimax/minimax_ui.py @@ -24,17 +24,20 @@ def create_ui(prompt, _negative, styles, overrides, script_inputs, mp4_fps, mp4_ with gr.Accordion(open=True, label='Parameters', elem_id='minimax_param_accordion') as _param_accordion: with gr.Row(): width, height = ui_sections.create_resolution_inputs('minimax', default_width=1024, default_height=576, step=32) + btn_detect_image_size = ToolButton(value=ui_symbols.detect, elem_id="minimax_resize_detect_size") with gr.Row(): - steps = gr.Slider(minimum=2, maximum=100, step=1, label="MiniMax Steps", elem_id='minimax_steps', value=30) - frames = gr.Slider(label='MiniMax Frames', minimum=22, maximum=362, step=17, value=124, elem_id='minimax_frames') + steps = gr.Slider(minimum=1, maximum=100, step=1, label="MiniMax steps", elem_id='minimax_steps', value=30) + frames = gr.Slider(label='MiniMax frames', minimum=22, maximum=362, step=17, value=124, elem_id='minimax_frames') with gr.Row(): - video_shift = gr.Slider(minimum=8.0, maximum=16.0, step=0.1, label="MiniMax Video Shift", elem_id='minimax_video_shift', value=12) - audio_shift = gr.Slider(minimum=1.5, maximum=6.0, step=0.1, label="MiniMax Audio Shift", elem_id='minimax_audio_shift', value=3) + video_shift = gr.Slider(minimum=0.5, maximum=20.0, step=0.1, value=12.0, label="MiniMax video shift", elem_id='minimax_video_shift') + audio_shift = gr.Slider(minimum=0.5, maximum=10.0, step=0.1, value=3.0, label="MiniMax audio shift", elem_id='minimax_audio_shift') with gr.Row(): seed = gr.Number(label='Seed', value=-1, elem_id='minimax_seed', container=True) random_seed = ToolButton(ui_symbols.random, elem_id='minimax_seed_random') random_seed.click(fn=lambda: -1, show_progress='hidden', inputs=[], outputs=[seed]) - audio_enable = gr.Checkbox(label='Audio Enabled', value=True, elem_id="minimax_audio_enable") + with gr.Row(): + enable_audio = gr.Checkbox(label='Enable audio', value=True, elem_id="minimax_audio_enable") + enable_preview = gr.Checkbox(label='Enable preview', value=True, elem_id="minimax_preview_enable") with gr.Accordion(open=False, label="Input media", elem_id='minimax_input_media_accordion', visible=True) as input_accordion: with gr.Row(): init_image = gr.Image(label='Image', elem_id='minimax_init_image', type='pil', image_mode='RGB', width=256, height=256) @@ -56,19 +59,29 @@ def create_ui(prompt, _negative, styles, overrides, script_inputs, mp4_fps, mp4_ model_info = next((m for m in models['MiniMax'] if m.name == model_name), None) if model_info is None or model_info.name is None or model_info.name == '' or model_info.name == 'None': return gr.update(value='none'), gr.update(visible=False), gr.update(visible=False) - log.debug(f'Selected: name="{model_info.name}" repo="{model_info.repo}" cls={model_info.repo_cls}') if model_info.workflow == 'fl2va': workflow = 'fl2va' if init_image is not None else 't2va' else: workflow = model_info.workflow + log.debug(f'Video: workflow={workflow} name="{model_info.name}" repo="{model_info.repo}" cls={model_info.repo_cls} image={init_image} selected') return gr.update(value=f'Workflow: {workflow}'), gr.update(visible=workflow != 'ref2va'), gr.update(visible=workflow == 'ref2va') def on_load(model_name: str): model_info = next((m for m in models['MiniMax'] if m.name == model_name), None) minimax_video.load_model(model_info.name if model_info is not None else None) + def on_image_size(init_image): + if init_image is not None: + try: + width, height = init_image.size + return gr.update(value=width), gr.update(value=height) + except Exception: + pass + return gr.update(), gr.update() + model.change(fn=on_change, inputs=[model, init_image], outputs=[workflow, input_accordion, reference_accordion], show_progress='hidden') init_image.change(fn=on_change, inputs=[model, init_image], outputs=[workflow, input_accordion, reference_accordion], show_progress='hidden') + btn_detect_image_size.click(fn=on_image_size, inputs=[init_image], outputs=[width, height]) btn_load.click(fn=on_load, inputs=[model], outputs=[]) task_id = gr.Textbox(visible=False, value='') @@ -85,7 +98,8 @@ def create_ui(prompt, _negative, styles, overrides, script_inputs, mp4_fps, mp4_ mp4_fps, mp4_interpolate, mp4_codec, mp4_ext, mp4_opt, mp4_video, mp4_frames, mp4_sf, mp4_thumb, mp4_scale, mp4_upscaler, - audio_enable, + enable_audio, + enable_preview, overrides, ] video_outputs = [ diff --git a/modules/minimax/minimax_vdn.py b/modules/minimax/minimax_vdn.py new file mode 100644 index 000000000..47b4aac95 --- /dev/null +++ b/modules/minimax/minimax_vdn.py @@ -0,0 +1,211 @@ +import types +import torch +import torch.nn as nn +import torch.nn.functional as F +import torch.utils.checkpoint + +from modules import devices +from modules.logger import log + + +class VectorizedGatedDeltaBranch(nn.Module): + def __init__(self, d_model: int, num_heads: int, init_gamma: float = 1.0): + super().__init__() + self.num_heads = num_heads + self.head_dim = d_model // num_heads + self.proj_beta = nn.Linear(d_model, num_heads, bias=False) + nn.init.zeros_(self.proj_beta.weight) + self.gamma = nn.Parameter(torch.full((1,), float(init_gamma))) + self.compute_dtype = devices.dtype + + def get_sliding_window_mask(self, num_frames: int, window_size: int, device: torch.device) -> torch.Tensor: + grid = torch.arange(num_frames, device=device) + diff = torch.abs(grid.unsqueeze(0) - grid.unsqueeze(1)) + return (diff <= (window_size // 2)).unsqueeze(0).unsqueeze(0) + + def forward(self, q: torch.Tensor, k: torch.Tensor, v: torch.Tensor) -> torch.Tensor: + B, F_len, S, H, D = q.shape + + if self.proj_beta.weight.device != q.device or self.proj_beta.weight.dtype != self.compute_dtype: + self.to(device=q.device, dtype=self.compute_dtype) + + q_t = q.to(dtype=self.compute_dtype).permute(0, 2, 3, 1, 4).reshape(B * S, H, F_len, D) + k_t = k.to(dtype=self.compute_dtype).permute(0, 2, 3, 1, 4).reshape(B * S, H, F_len, D) + v_t = v.to(dtype=self.compute_dtype).permute(0, 2, 3, 1, 4).reshape(B * S, H, F_len, D) + + q_in = q.reshape(B, F_len, S, -1).to(dtype=self.proj_beta.weight.dtype) + beta = torch.sigmoid(self.proj_beta(q_in)) + beta = beta.to(dtype=self.compute_dtype).permute(0, 2, 3, 1).reshape(B * S, H, F_len, 1, 1) + + state = torch.zeros((B * S, H, D, D), dtype=self.compute_dtype, device=q.device) + out_buf = torch.empty((B * S, H, F_len, D), dtype=self.compute_dtype, device=q.device) + + gamma_comp = self.gamma.to(dtype=self.compute_dtype, device=q.device) + + for t in range(F_len): + q_f = q_t[:, :, t] + k_f = k_t[:, :, t] + v_f = v_t[:, :, t] + b_f = beta[:, :, t] + + pred_v = torch.matmul(state, k_f.unsqueeze(-1)).squeeze(-1) + error = v_f - pred_v + + # In-place state update avoids intermediate 5D tensor allocations + state.mul_(1.0 - b_f).addcmul_(b_f, error.unsqueeze(-1), k_f.unsqueeze(-2)) # ty: ignore[too-many-positional-arguments] + + frame_out = torch.matmul(q_f.unsqueeze(-2), state).squeeze(-2) + + # upcast to fp32 before squaring to prevent fp16 overflow + v_rms = torch.rsqrt(torch.mean(v_f.float().pow(2), dim=-1, keepdim=True) + 1e-6).to(self.compute_dtype) + out_rms = torch.rsqrt(torch.mean(frame_out.float().pow(2), dim=-1, keepdim=True) + 1e-6).to(self.compute_dtype) + + out_buf[:, :, t] = frame_out * (out_rms / v_rms) + + out = out_buf.reshape(B, S, H, F_len, D).permute(0, 3, 1, 2, 4) + return (gamma_comp * out).to(dtype=q.dtype) + + +def vdn_attention_forward(self, hidden_states, *args, **kwargs): + encoder_hidden_states = kwargs.get("encoder_hidden_states", args[0] if len(args) > 0 else None) + + if encoder_hidden_states is not None or hidden_states.ndim != 3: + if hasattr(self, "orig_forward"): + return self.orig_forward(hidden_states, *args, **kwargs) + + B, SeqLen, C = hidden_states.shape + default_frames = getattr(self, "num_frames", 22) + num_frames = kwargs.get("num_frames", None) or getattr(self, "num_frames", None) + + if num_frames is None or SeqLen % num_frames != 0: + if SeqLen % default_frames == 0: + num_frames = default_frames + else: + possible_factors = [f for f in (16, 24, 32, 48, 64) if SeqLen % f == 0] + if possible_factors: + num_frames = possible_factors[0] + else: + if hasattr(self, "orig_forward"): + return self.orig_forward(hidden_states, *args, **kwargs) + raise ValueError(f"Sequence length {SeqLen} cannot be factorized by frame count.") + + window_size = kwargs.get("window_size", None) or getattr(self, "window_size", 16) + S = SeqLen // num_frames + + q = self.to_q(hidden_states) + k = self.to_k(hidden_states) + v = self.to_v(hidden_states) + + inner_dim = getattr(self, "inner_dim", C) + head_dim = getattr(self, "slice_able_head_dim", getattr(self, "head_dim", 64)) + num_heads = getattr(self, "heads", inner_dim // head_dim) + + q_5d = q.contiguous().view(B, num_frames, S, num_heads, head_dim) + k_5d = k.contiguous().view(B, num_frames, S, num_heads, head_dim) + v_5d = v.contiguous().view(B, num_frames, S, num_heads, head_dim) + + q_loc = q_5d.permute(0, 2, 3, 1, 4).reshape(B * S, num_heads, num_frames, head_dim) + k_loc = k_5d.permute(0, 2, 3, 1, 4).reshape(B * S, num_heads, num_frames, head_dim) + v_loc = v_5d.permute(0, 2, 3, 1, 4).reshape(B * S, num_heads, num_frames, head_dim) + + attention_mask = kwargs.get("attention_mask", None) + if window_size >= num_frames: + combined_mask = attention_mask + else: + window_mask = self.get_sliding_window_mask(num_frames, window_size, hidden_states.device) + if attention_mask is not None and attention_mask.dtype == torch.bool and attention_mask.shape == window_mask.shape: + combined_mask = attention_mask & window_mask + else: + combined_mask = window_mask + + if self.delta_branch.proj_beta.weight.device != hidden_states.device or self.delta_branch.proj_beta.weight.dtype != devices.dtype: + self.delta_branch.to(device=hidden_states.device, dtype=devices.dtype) + + try: + out_local = F.scaled_dot_product_attention(q_loc, k_loc, v_loc, attn_mask=combined_mask, is_causal=False) + except (RuntimeError, TypeError): + if combined_mask is not None and combined_mask.dtype == torch.bool: + mask_val = -1e4 if q_loc.dtype == torch.float16 else -1e9 + float_mask = torch.zeros(combined_mask.shape, device=hidden_states.device, dtype=q_loc.dtype) + float_mask.masked_fill_(~combined_mask, mask_val) + out_local = F.scaled_dot_product_attention(q_loc, k_loc, v_loc, attn_mask=float_mask, is_causal=False) + else: + raise + + out_local = out_local.reshape(B, S, num_heads, num_frames, head_dim).permute(0, 3, 1, 2, 4) + out_delta = self.delta_branch(q_5d, k_5d, v_5d) + out_hybrid = (out_local + out_delta).reshape(B, SeqLen, C) + + to_out = getattr(self, "to_out", None) + if to_out is not None: + if isinstance(to_out, (nn.ModuleList, list)): + for proj in to_out: + out_hybrid = proj(out_hybrid) + return out_hybrid + return to_out(out_hybrid) + + return out_hybrid + + +def apply_vdn(pipe, window_size=16, num_frames=22, init_gamma=1.0): + if pipe is None or getattr(pipe, "transformer", None) is None: + return + count = 0 + for _, module in pipe.transformer.named_modules(): + if module.__class__.__name__ == "MiniMaxH3Attention": + if hasattr(module, "delta_branch"): + # already patched, just update the num_frames and window_size + module.num_frames = num_frames + module.window_size = window_size + continue + if not hasattr(module, "orig_forward"): + # backup the original forward method + module.orig_forward = module.forward + + to_q = getattr(module, "to_q", None) + if to_q is not None: + if hasattr(to_q, "out_features"): + default_dim = to_q.out_features + elif hasattr(to_q, "orig_out_features"): + default_dim = to_q.orig_out_features + elif hasattr(to_q, "weight"): + default_dim = to_q.weight.shape[0] + else: + default_dim = 1024 + else: + default_dim = 1024 + + inner_dim = getattr(module, "inner_dim", default_dim) + head_dim = getattr(module, "slice_able_head_dim", getattr(module, "head_dim", 64)) + num_heads = getattr(module, "heads", inner_dim // head_dim) + + delta_branch = VectorizedGatedDeltaBranch(inner_dim, num_heads, init_gamma=init_gamma) + delta_branch = delta_branch.to(device=devices.device, dtype=devices.dtype) + + module.add_module("delta_branch", delta_branch) + module.num_frames = num_frames + module.window_size = window_size + + module.forward = types.MethodType(vdn_attention_forward, module) + count += 1 + + log.info(f'Pipeline: cls={pipe.__class__.__name__} gate={VectorizedGatedDeltaBranch.__name__} patched={count} window={window_size} gamma={init_gamma} frames={num_frames}') + + +def unapply_vdn(pipe): + if pipe is None or getattr(pipe, "transformer", None) is None: + return + count = 0 + for _, module in pipe.transformer.named_modules(): + if module.__class__.__name__ == "MiniMaxH3Attention": + if hasattr(module, "orig_forward"): + count += 1 + module.forward = module.orig_forward + delattr(module, "orig_forward") + if hasattr(module, "delta_branch"): + delattr(module, "delta_branch") + if hasattr(module, "num_frames"): + delattr(module, "num_frames") + if hasattr(module, "window_size"): + delattr(module, "window_size") + log.info(f'Pipeline: cls={pipe.__class__.__name__} gate={VectorizedGatedDeltaBranch.__name__} restored={count}') diff --git a/modules/minimax/minimax_video.py b/modules/minimax/minimax_video.py index 5e4592328..492e0cc8d 100644 --- a/modules/minimax/minimax_video.py +++ b/modules/minimax/minimax_video.py @@ -49,23 +49,28 @@ def unwrap_file(entry): return entry -def prepare_inputs(workflow: str | None, init_image: Image.Image | None, last_image: Image.Image | None, reference_media: list | None) -> dict: +def prepare_inputs(workflow: str | None, init_image: Image.Image | None, last_image: Image.Image | None, reference_media: list | None, width: int | None = None, height: int | None = None) -> dict: """The task args a workflow conditions on, resolved before the model load so a rejected request costs nothing.""" t_inputs = time.time() + from modules.image.resize import resize_image from modules.minimax import minimax_references if minimax_references.get_reference_caps(workflow) is not None: entries = [unwrap_file(entry) for entry in (reference_media or [])] references = minimax_references.resolve(workflow, entries, init_image) - log.debug(f'Prepare inputs: workflow={workflow} references={len(references)}') + log.debug(f'Video inputs: workflow={workflow} references={len(references)}') return {'references': references} task_args = {} if init_image is not None: + if width is not None and height is not None: + init_image = resize_image(2, init_image, width, height) # crop to aspect ratio task_args['image'] = init_image if last_image is not None: + if width is not None and height is not None: + last_image = resize_image(2, last_image, width, height) # crop to aspect ratio task_args['last_image'] = last_image if reference_media: log.warning(f'Video: op=reference workflow={workflow} references not supported, ignoring: count={len(reference_media)}') - log.debug(f'Prepare inputs: workflow={workflow} first={init_image} last={last_image}') + log.debug(f'Video inputs: workflow={workflow} first={init_image} last={last_image}') timer.video.ts('inputs', t_inputs) return task_args @@ -83,7 +88,7 @@ def generate(task_id, _ui_state, mp4_fps, mp4_interpolate, mp4_codec, mp4_ext, mp4_opt, mp4_video, mp4_frames, mp4_sf, mp4_thumb, mp4_scale, mp4_upscaler, - audio_enable, + enable_audio, enable_preview, _overrides, *args, **_kwargs, @@ -111,18 +116,24 @@ def generate(task_id, _ui_state, # resolved off the registry row so a bad reference is rejected before the load, the same as on the api path selected = models_def.find(engine, model) workflow = getattr(selected, 'workflow', None) - task_args = prepare_inputs(workflow, init_image, last_image, reference_media) + task_args = prepare_inputs(workflow, init_image, last_image, reference_media, width=width, height=height) workflow = load_model(model) # override workflow based on loaded model if not workflow: progress.finish_task(task_id) log.error('Video: model not loaded') return None, 'Model not loaded' + init_images = [] # only so they are available for inspection by rest of the processing + if init_image is not None: + init_images.append(init_image) + if last_image is not None: + init_images.append(last_image) p = processing.StableDiffusionProcessingVideo( sd_model=shared.sd_model, video_engine=engine, video_model=model, prompt=prompt, styles=styles, + init_images=init_images, seed=int(seed) if seed is not None else -1, steps=int(steps), width=width, @@ -133,9 +144,8 @@ def generate(task_id, _ui_state, outpath_samples=paths.resolve_output_path(shared.opts.outdir_samples, shared.opts.outdir_video), ops=['video'], ) - video_minimax.apply_overrides(p, shared.sd_model, still=False, audio=audio_enable) - video_minimax.set_sampler_shift(shared.sd_model, video_shift=video_shift, audio_shift=audio_shift) - log.debug(f'Video: engine="{engine}" model="{model}" workflow={workflow} cls={shared.sd_model.__class__.__name__} shift={video_shift}:{audio_shift} kwargs={p.task_args}') + video_minimax.apply_overrides(p, shared.sd_model, still=False, audio=enable_audio, preview=enable_preview, video_shift=video_shift, audio_shift=audio_shift) + log.debug(f'Video: engine="{engine}" model="{model}" workflow={workflow} cls={shared.sd_model.__class__.__name__} audio={enable_audio} preview={enable_preview} kwargs={p.task_args}') processing.fix_seed(p) p.ops.append('video') p.scripts = scripts_manager.scripts_video @@ -145,6 +155,10 @@ def generate(task_id, _ui_state, _processed: processing.Processed = scripts_manager.scripts_video.run(p, *args) + if os.environ.get("SD_MINIMAX_VDN", None) is not None: + from modules.minimax.minimax_vdn import apply_vdn + apply_vdn(shared.sd_model, window_size=12, num_frames=frames, init_gamma=1.0) + if os.environ.get("SD_MINIMAX_CHUNK", None) is not None: from modules.minimax.minimax_chunking import minimax_attention chunk_size = int(os.environ.get("SD_MINIMAX_CHUNK", 0)) @@ -157,7 +171,7 @@ def generate(task_id, _ui_state, sd_models.offload_ondemand(shared.sd_model, reason='finish', force=True) # force offload all loaded modules to cpu devices.torch_gc(force=True) # free gpu memory before saving video - audio = getattr(processed, 'audio', None) if audio_enable else None + audio = getattr(processed, 'audio', None) if enable_audio else None if audio is not None: audio = audio[0].float().cpu() if audio.ndim == 3 else audio.float().cpu() aac_sample_rate = getattr(shared.sd_model, 'audio_sampling_rate', 32000) diff --git a/modules/model_te.py b/modules/model_te.py index 11d5a0087..76f8f10c9 100644 --- a/modules/model_te.py +++ b/modules/model_te.py @@ -17,6 +17,7 @@ def load_t5(name=None, cache_dir=None): if name is None: return None cache_dir = cache_dir or shared.opts.hfcache_dir + offline_args = {'local_files_only': True} if shared.opts.offline_mode else {} from modules import modelloader modelloader.hf_login() repo_id = 'stabilityai/stable-diffusion-3-medium-diffusers' @@ -60,25 +61,25 @@ def load_t5(name=None, cache_dir=None): t5 = transformers.T5EncoderModel.from_pretrained(None, state_dict=state_dict, config=t5_config, cache_dir=cache_dir, torch_dtype=devices.dtype) elif 'fp16' in name.lower(): - t5 = transformers.T5EncoderModel.from_pretrained(repo_id, subfolder='text_encoder_3', cache_dir=cache_dir, torch_dtype=devices.dtype) + t5 = transformers.T5EncoderModel.from_pretrained(repo_id, subfolder='text_encoder_3', cache_dir=cache_dir, torch_dtype=devices.dtype, **offline_args) elif 'int8' in name.lower(): from modules.model_quant import create_sdnq_config quantization_config = create_sdnq_config(kwargs=None, allow=True, module='any', weights_dtype='int8') if quantization_config is not None: - t5 = transformers.T5EncoderModel.from_pretrained(repo_id, subfolder='text_encoder_3', quantization_config=quantization_config, cache_dir=cache_dir, torch_dtype=devices.dtype) + t5 = transformers.T5EncoderModel.from_pretrained(repo_id, subfolder='text_encoder_3', quantization_config=quantization_config, cache_dir=cache_dir, torch_dtype=devices.dtype, **offline_args) elif 'uint4' in name.lower(): from modules.model_quant import create_sdnq_config quantization_config = create_sdnq_config(kwargs=None, allow=True, module='any', weights_dtype='uint4') if quantization_config is not None: - t5 = transformers.T5EncoderModel.from_pretrained(repo_id, subfolder='text_encoder_3', quantization_config=quantization_config, cache_dir=cache_dir, torch_dtype=devices.dtype) + t5 = transformers.T5EncoderModel.from_pretrained(repo_id, subfolder='text_encoder_3', quantization_config=quantization_config, cache_dir=cache_dir, torch_dtype=devices.dtype, **offline_args) elif '/' in name: log.debug(f'Load model: type=T5 repo={name}') quant_config = model_quant.create_config(module='TE') if quant_config is not None: - t5 = transformers.T5EncoderModel.from_pretrained(name, cache_dir=cache_dir, torch_dtype=devices.dtype, **quant_config) + t5 = transformers.T5EncoderModel.from_pretrained(name, cache_dir=cache_dir, torch_dtype=devices.dtype, **quant_config, **offline_args) else: t5 = None diff --git a/modules/modeldata.py b/modules/modeldata.py index ee8122b15..4e7568436 100644 --- a/modules/modeldata.py +++ b/modules/modeldata.py @@ -119,6 +119,8 @@ def get_model_type(pipe): model_type = 'longcat' elif 'GlmImage' in name: model_type = 'glmimage' + elif 'LLaDAImage' in name: + model_type = 'lladaimage' elif 'Step1XEdit' in name: model_type = 'step1x_edit' elif 'JoyImageEdit' in name: diff --git a/modules/modelloader.py b/modules/modelloader.py index 9fcb85b65..a6eb625a4 100644 --- a/modules/modelloader.py +++ b/modules/modelloader.py @@ -490,5 +490,5 @@ def load_upscalers(quiet=False): shared.sd_upscalers = upscalers t1 = time.time() if not quiet: - log.info(f"Available Upscalers: items={len(shared.sd_upscalers)} downloaded={len([x for x in shared.sd_upscalers if x.data_path is not None and os.path.isfile(x.data_path)])} user={len([x for x in shared.sd_upscalers if x.custom])} time={t1-t0:.2f} types={upscaler_types}") + log.info(f"Available Upscalers: items={len(shared.sd_upscalers)} downloaded={len([x for x in shared.sd_upscalers if x.data_path is not None and os.path.isfile(x.data_path)])} user={len([x for x in shared.sd_upscalers if x.custom])} time={t1-t0:.2f}") return [x.name for x in shared.sd_upscalers] diff --git a/modules/modular.py b/modules/modular.py index c4c8d3ebf..5e8eeb9c6 100644 --- a/modules/modular.py +++ b/modules/modular.py @@ -1,65 +1,67 @@ -import time +import os import diffusers -from modules import shared +from modules import shared, sd_hijack_modular, sd_models from modules.logger import log -modular_map= { - 'StableDiffusionXLPipeline': 'StableDiffusionXLAutoBlocks', - 'StableDiffusionXLImg2ImgPipeline': 'StableDiffusionXLAutoBlocks', - 'StableDiffusionXLInpaintPipeline': 'StableDiffusionXLAutoBlocks', - 'FluxPipeline': 'FluxAutoBlocks', - 'FluxImg2ImgPipeline': 'FluxAutoBlocks', - 'FluxInpaintPipeline': 'FluxAutoBlocks', - 'WanPipeline': 'WanAutoBlocks', - 'WanImageToVideoPipeline': 'WanAutoBlocks', - 'QwenImagePipeline': 'QwenImageAutoBlocks', - 'QwenImageEditPipeline': 'QwenImageEditAutoBlocks', -} +debug = os.environ.get('SD_MODULAR_DEBUG', None) is not None +exclude = ['Krea2'] + + +def get_modular_class(diffusion_pipeline: diffusers.DiffusionPipeline): + name = diffusion_pipeline.__class__.__name__ + name = name.replace('Pipeline', '').replace('Img2Img', '').replace('Inpaint', '').replace('ImageToVideo', '') + if name in exclude: + if debug: + log.trace(f'Modular lookup: key={name} source={diffusion_pipeline.__class__.__name__} excluded') + return None + name = f'{name}AutoBlocks' + modular_cls = getattr(diffusers, name, None) + if debug: + log.trace(f'Modular lookup: key={name} source={diffusion_pipeline.__class__.__name__} target={modular_cls.__name__ if modular_cls else None}') + return modular_cls def is_compatible(diffusion_pipeline: diffusers.DiffusionPipeline) -> bool: if not shared.opts.model_modular_enable: return False - compatible = diffusion_pipeline.__class__.__name__ in modular_map + compatible = get_modular_class(diffusion_pipeline) is not None if not compatible: - log.debug(f'Modular: source={diffusion_pipeline.__class__.__name__} incompatible pipeline') + log.warning(f'Modular: source={diffusion_pipeline.__class__.__name__} incompatible pipeline') return compatible +def is_modular(diffusion_pipeline: diffusers.DiffusionPipeline) -> bool: + if diffusion_pipeline is None: + return False + return isinstance(diffusion_pipeline, diffusers.ModularPipeline) or 'Modular' in diffusion_pipeline.__class__.__name__ + + def is_guider(diffusion_pipeline: diffusers.DiffusionPipeline) -> bool: guider = getattr(diffusion_pipeline, 'guider', None) return guider is not None -def convert_to_modular(diffusion_pipeline: diffusers.DiffusionPipeline) -> diffusers.ModularPipeline: +def convert_to_modular(diffusion_pipeline: diffusers.DiffusionPipeline | diffusers.ModularPipeline): + if is_modular(diffusion_pipeline): + return diffusion_pipeline modular_pipe = None try: - t0 = time.time() - modular_cls = modular_map.get(diffusion_pipeline.__class__.__name__, None) + modular_cls = get_modular_class(diffusion_pipeline) if modular_cls is None: raise ValueError(f'unknown: cls={diffusion_pipeline.__class__.__name__}') - modular_cls = getattr(diffusers, modular_cls, None) - if modular_cls is None: - raise ValueError(f'invalid: cls={diffusion_pipeline.__class__.__name__}') modular_blocks = modular_cls() - modular_pipe = modular_blocks.init_pipeline() + modular_pipe: diffusers.ModularPipeline = modular_blocks.init_pipeline() components_dct = {k: v for k, v in diffusion_pipeline.components.items() if v is not None} modular_pipe.update_components(**components_dct, **diffusion_pipeline.parameters) modular_pipe.original_pipe = diffusion_pipeline - t1 = time.time() - log.debug(f'Modular: source={diffusion_pipeline.__class__.__name__} target={modular_pipe.__class__.__name__} time={t1 - t0:.2f}') - """ - for expected_input_param in modular_pipe.blocks.inputs: - name = expected_input_param.name - default = expected_input_param.default - kwargs_type = expected_input_param.kwargs_type - log.trace(f'Modular input: name={name} type={kwargs_type} default={default}') - """ - + log.debug(f'Modular: convert={diffusion_pipeline.__class__.__name__} target={modular_pipe.__class__.__name__}') except Exception as e: log.error(f'Modular: {e}') raise e + sd_models.copy_diffuser_options(modular_pipe, diffusion_pipeline) + sd_hijack_modular.install_state_hook(modular_pipe) + sd_hijack_modular.register_callbacks(modular_pipe) return modular_pipe diff --git a/modules/modular_guiders.py b/modules/modular_guiders.py index 00e45f83b..3228bcabd 100644 --- a/modules/modular_guiders.py +++ b/modules/modular_guiders.py @@ -1,96 +1,130 @@ +import inspect import diffusers -from modules import shared, errors, processing +from modules import errors, shared, processing from modules.logger import log -# ['Default', 'CFG', 'Zero', 'PAG', 'APG', 'SLG', 'SEG', 'TCFG', 'FDG'] guiders = { # 'None': { 'cls': None, 'args': {}, }, 'Default': { 'cls': None, 'args': {}, }, 'CFG: ClassifierFreeGuidance': { 'cls': diffusers.ClassifierFreeGuidance, 'args': {} }, - 'Auto: AutoGuidance': { 'cls': diffusers.AutoGuidance, 'args': { 'dropout': 1.0, 'auto_guidance_layers': [7, 8, 9], 'auto_guidance_config': None } }, - 'Zero: ClassifierFreeZeroStar': { 'cls': diffusers.ClassifierFreeZeroStarGuidance, 'args': { 'zero_init_steps': 1 } }, - 'PAG: PerturbedAttentionGuidance': { 'cls': diffusers.PerturbedAttentionGuidance, 'args': { 'perturbed_guidance_scale': 2.8, 'perturbed_guidance_start': 0.01, 'perturbed_guidance_stop': 0.2, 'perturbed_guidance_layers': [7, 8, 9], 'perturbed_guidance_config': None } }, - 'APG: AdaptiveProjectedGuidance': { 'cls': diffusers.AdaptiveProjectedGuidance, 'args': { 'adaptive_projected_guidance_momentum': -1, 'adaptive_projected_guidance_rescale': 15.0 } }, - 'SLG: SkipLayerGuidance': { 'cls': diffusers.SkipLayerGuidance, 'args': { 'skip_layer_guidance_scale': 2.8, 'skip_layer_guidance_start': 0.01, 'skip_layer_guidance_stop': 0.2, 'skip_layer_guidance_layers': [7, 8, 9], 'skip_layer_config': None } }, - 'SEG: SmoothedEnergyGuidance': { 'cls': diffusers.SmoothedEnergyGuidance, 'args': { 'seg_guidance_scale': 3.0, 'seg_blur_sigma': 9999999.0, 'seg_blur_threshold_inf': 9999.0, 'seg_guidance_start': 0.0, 'seg_guidance_stop': 1.0, 'seg_guidance_layers': [7, 8, 9], 'seg_guidance_config': None } }, + 'Auto: AutoGuidance': { 'cls': diffusers.AutoGuidance, 'args': {} }, + 'Zero: ClassifierFreeZeroStar': { 'cls': diffusers.ClassifierFreeZeroStarGuidance, 'args': {} }, + 'PAG: PerturbedAttentionGuidance': { 'cls': diffusers.PerturbedAttentionGuidance, 'args': {} }, + 'APG: AdaptiveProjectedGuidance': { 'cls': diffusers.AdaptiveProjectedGuidance, 'args': {} }, + 'SLG: SkipLayerGuidance': { 'cls': diffusers.SkipLayerGuidance, 'args': {} }, + 'SEG: SmoothedEnergyGuidance': { 'cls': diffusers.SmoothedEnergyGuidance, 'args': {} }, 'TCFG: TangentialClassifierFreeGuidance': { 'cls': diffusers.TangentialClassifierFreeGuidance, 'args': {} }, - 'FDG: FrequencyDecoupledGuidance': { 'cls': diffusers.FrequencyDecoupledGuidance, 'args': { 'guidance_scales': [10.0, 5.0], 'parallel_weights': 1.0, 'guidance_rescale_space': "data" } }, -} -base_args = { - 'guidance_scale': 6.0, - 'guidance_rescale': 0.0, - 'start': 0.0, - 'stop': 1.0, + 'FDG: FrequencyDecoupledGuidance': { 'cls': diffusers.FrequencyDecoupledGuidance, 'args': {} }, } -def set_guider(p: processing.StableDiffusionProcessing): - guidance_name = p.guidance_name or 'Default' +def get_layers(layer_str: str): + if not layer_str: + return [] + try: + # layers can be comma separated, e.g. "7, 8, 9" or range "7-9" or mixed "7, 8-10, 12" + layers = [] + for part in layer_str.split(','): + part = part.strip() + if '-' in part: + start, end = part.split('-') + layers.extend(range(int(start), int(end) + 1)) + elif part.isdigit(): + layers.append(int(part)) + layers = sorted(set(layers)) # remove duplicates and sort + return layers + except Exception as e: + log.error(f'Guiders layers: {e}') + return [] + + +def set_args(guidance_name: str): + args = {} + import modules.ui_guidance + inputs = modules.ui_guidance.get_modular_args() + # for k, v in inputs.items(): + # log.trace(f'Guiders: arg={k} value={v}') + if guidance_name.startswith('Default'): + pass + if guidance_name.startswith('CFG:'): + pass + if guidance_name.startswith('Auto:'): + args['dropout'] = float(inputs.get('autoguidance_dropout', 1.0)) + args['auto_guidance_layers'] = get_layers(inputs.get('autoguidance_layers', [])) + if guidance_name.startswith('Zero:'): + args['zero_init_steps'] = int(inputs.get('zerostar_init_steps', 1)) + if guidance_name.startswith('PAG:'): + args['perturbed_guidance_scale'] = float(inputs.get('pag_scale', 1.0)) + args['perturbed_guidance_start'] = float(inputs.get('pag_start', 0.01)) + args['perturbed_guidance_stop'] = float(inputs.get('pag_stop', 0.2)) + args['perturbed_guidance_layers'] = get_layers(inputs.get('pag_layers', [])) + if guidance_name.startswith('APG:'): + args['adaptive_projected_guidance_momentum'] = float(inputs.get('apg_momentum', None)) if inputs.get('apg_momentum', -1) >= 0 else None + args['adaptive_projected_guidance_rescale'] = float(inputs.get('apg_rescale', 15.0)) + if guidance_name.startswith('SLG:'): + args['skip_layer_guidance_scale'] = float(inputs.get('slg_scale', 1.0)) + args['skip_layer_guidance_start'] = float(inputs.get('slg_start', 0.01)) + args['skip_layer_guidance_stop'] = float(inputs.get('slg_stop', 0.2)) + args['skip_layer_guidance_layers'] = get_layers(inputs.get('slg_layers', [])) + if guidance_name.startswith('SEG:'): + args['seg_guidance_scale'] = float(inputs.get('seg_scale', 3.0)) + args['seg_blur_sigma'] = float(inputs.get('seg_blur_sigma', 9999999.0)) + args['seg_blur_threshold_inf'] = float(inputs.get('seg_blur_threshold_inf', 9999.0)) + args['seg_guidance_start'] = float(inputs.get('seg_start', 0.0)) + args['seg_guidance_stop'] = float(inputs.get('seg_stop', 1.0)) + args['seg_guidance_layers'] = get_layers(inputs.get('seg_layers', [])) + if guidance_name.startswith('TCFG:'): + pass + if guidance_name.startswith('FDG:'): + args['guidance_scales'] = [float(x.strip()) for x in inputs.get('fdg_scales', '5.0').split(',')] + args['parallel_weights'] = float(inputs.get('fdg_weights', 1.0)) + args['guidance_rescale_space'] = inputs.get('fdg_rescale_space', 'data') + return args + + +def set_guider(p: processing.StableDiffusionProcessing, phase: str | None = None): + guidance_name = p.cfg_name or 'Default' if guidance_name not in guiders: return - if guidance_name == 'Default': - if hasattr(shared.sd_model, 'default_guider'): - guider_info = shared.sd_model.default_guider - guider_cls = guider_info.type_hint if hasattr(guider_info, 'type_hint') else type(guider_info) - shared.sd_model.update_components(guider=guider_info) - elif hasattr(shared.sd_model, 'get_component_spec'): - guider_info = shared.sd_model.get_component_spec("guider") - guider_cls = guider_info.type_hint if hasattr(guider_info, 'type_hint') else type(guider_info) - shared.sd_model.default_guider = guider_info - elif hasattr(shared.sd_model, 'guider') and hasattr(shared.sd_model.guider, 'config'): - guider_info = shared.sd_model.guider - guider_cls = type(shared.sd_model.guider) - # shared.sd_model.default_guider = guider_info - else: - guider_info = None - guider_cls = None - if guider_info is not None and guider_cls is not None and guider_info.config is not None: - guider_args = {k: v for k, v in guider_info.config.items() if not k.startswith('_') and v is not None} - else: - guider_args = {} - log.info(f'Guider: name={guidance_name} cls={guider_cls.__name__ if guider_cls is not None else None} args={guider_args}') - return + if not hasattr(shared.sd_model, 'default_guider'): # store default guider + guider_info = shared.sd_model.get_component_spec("guider") + guider_cls = guider_info.type_hint if hasattr(guider_info, 'type_hint') else type(guider_info) + shared.sd_model.default_guider = guider_cls + if guidance_name == 'None': shared.sd_model.update_components(guider=None) # breaks the pipeline - log.info(f'Guider: name={guidance_name}') + log.info(f'Pipeline: guidance="{guidance_name}"') return + elif guidance_name == 'Default': + guider_cls = shared.sd_model.default_guider + else: + guider_info = guiders[guidance_name] + guider_cls = guider_info['cls'] + + guider_args = set_args(guidance_name) + possible = inspect.signature(guider_cls.__init__).parameters if guider_cls is not None else [] + if 'guidance_scale' in list(possible): + if (phase == 'hires' or phase == 'refine') and p.cfg_image >= 0.0: + guider_args['guidance_scale'] = float(p.cfg_image) + elif p.cfg_scale >= 0.0: + guider_args['guidance_scale'] = float(p.cfg_scale) + if p.cfg_rescale >= 0.0 and 'guidance_rescale' in list(possible): + guider_args['guidance_rescale'] = float(p.cfg_rescale) + if p.cfg_start >= 0.0 and 'start' in list(possible): + guider_args['start'] = float(p.cfg_start) + if p.cfg_stop >= 0.0 and 'stop' in list(possible): + guider_args['stop'] = float(p.cfg_stop) - guider_info = guiders[guidance_name] - guider_cls = guider_info['cls'] - guider_args = {} - for k, v in base_args.items(): - if v is not None and v >= 0.0: - guider_args[k] = v - log.warning('Guiders: partially implemented') # TODO: guiders - for k, v in guider_info['args'].items(): - try: - if k is None: - pass - elif k.endswith('_layers') and isinstance(v, str): - guider_args[k] = [int(x.strip()) for x in v.split(',') if x.strip().isdigit()] - elif k.endswith('_config'): - # if lsc_enabled - # guider_args[k] = diffusers.LayerSkipConfig(...) - pass - elif isinstance(v, list) and len(v) > 0: - guider_args[k] = v - elif isinstance(v, int) and (v >= 0): - guider_args[k] = int(v) - elif isinstance(v, float) and (v >= 0.0): - guider_args[k] = float(v) - elif isinstance(v, str) and (len(v) > 0): - guider_args[k] = v - except Exception as e: - log.error(f'Guiders: arg={k} value={v} error={e}') - errors.display(e, 'Guiders') - # guider_args.update(guider_info['args']) if guider_cls is not None: try: - guider_instance = guider_cls(**guider_args) - log.info(f'Guider: name={guidance_name} cls={guider_cls.__name__} args={guider_args}') + guider_instance: diffusers.BaseGuidance = guider_cls(**guider_args) + log.info(f'Pipeline: guidance="{guidance_name}" cls={guider_cls.__name__} args={guider_args}') shared.sd_model.update_components(guider=guider_instance) except Exception as e: - log.error(f'Guider: name={guidance_name} cls={guider_cls.__name__} args={guider_args} {e}') + log.error(f'Pipeline: guidance="{guidance_name}" cls={guider_cls.__name__} args={guider_args} {e}') + errors.display(e, 'Guiders') return + else: + log.warning(f'Pipeline: guidance="{guidance_name}" cls=None args={guider_args}') diff --git a/modules/modular_load.py b/modules/modular_load.py index 66d6de771..97ac13a12 100644 --- a/modules/modular_load.py +++ b/modules/modular_load.py @@ -1,16 +1,9 @@ import time -import logging import torch -from modules import shared, errors, devices, sd_offload +from modules import shared, errors, devices, sd_hijack_modular from modules.logger import log -class InterruptLogFilter(logging.Filter): - """Drops the per-block error dumps the modular runner logs when an interrupt raises through it.""" - def filter(self, record): - return 'Interrupted...' not in record.msg - - def apply_progress_bar_config(block): kwargs = { "ncols": 120, @@ -31,82 +24,6 @@ def trace_modules(pipe): log.trace(f'Module: name={module_name} cls={module.__class__.__name__} device={next(module.parameters()).device} dtype={next(module.parameters()).dtype}') -def install_state_hook(pipe): - runner_log = logging.getLogger('diffusers.modular_pipelines.modular_pipeline') - if not any(isinstance(f, InterruptLogFilter) for f in runner_log.filters): - runner_log.addFilter(InterruptLogFilter()) - - def set_phase(phase: str, module: torch.nn.Module | None = None): - # every stage runs inside one pipeline call, so the forward hooks are the only place the current stage is visible - if getattr(pipe, 'sdnext_phase', None) != phase: - pipe.sdnext_phase = phase - jobid = getattr(pipe, 'sdnext_phaseid', None) # previous jobid if any - shared.state.end(jobid) # clear the previous job if exists - pipe.sdnext_phaseid = shared.state.begin(phase) # start a new job for the current phase - log.debug(f'Pipeline: phase={phase.replace(" ", "")} cls={pipe.__class__.__name__} module={module.__class__.__name__ if module is not None else None}') - return True - return False - - def _pre_transformer_hook(module, args): # pylint: disable=unused-argument - new_phase = set_phase('Generate', module) - if new_phase: - sd_offload.offload_ondemand(pipe, exclude=['transformer', 'transformer_ref'], reason='generate', force=hasattr(pipe, 'sdnext_force_offload')) - if shared.state.sampling_steps == 0 and getattr(pipe, 'num_timesteps', 0) > 0: - shared.state.sampling_steps = pipe.num_timesteps - if shared.state.paused: - log.debug('Sampling paused') - while shared.state.paused: - if shared.state.interrupted or shared.state.skipped: - raise AssertionError('Interrupted...') - time.sleep(0.1) - shared.state.step() - if shared.state.interrupted or shared.state.skipped: - raise AssertionError('Interrupted...') - - def _pre_text_encode_hook(module, args): # pylint: disable=unused-argument - new_phase = set_phase('Text Encode', module) - if new_phase: - sd_offload.offload_ondemand(pipe, exclude=['text_encoder'], reason='text encode', force=hasattr(pipe, 'sdnext_force_offload')) - if shared.state.interrupted or shared.state.skipped: - raise AssertionError('Interrupted...') - - def _pre_vae_decode_hook(module, args): # pylint: disable=unused-argument - new_phase = set_phase('Decode', module) - if new_phase: - sd_offload.offload_ondemand(pipe, exclude=['vae', 'audio_vae'], reason='vae decode', force=hasattr(pipe, 'sdnext_force_offload')) - if shared.state.interrupted or shared.state.skipped: # fires per tile, so tiled decodes abort promptly - raise AssertionError('Interrupted...') - - def _pre_vae_encode_hook(module, args): # pylint: disable=unused-argument - new_phase = set_phase('Encode', module) - if new_phase: - sd_offload.offload_ondemand(pipe, exclude=['vae', 'audio_vae'], reason='vae encode', force=hasattr(pipe, 'sdnext_force_offload')) - if shared.state.interrupted or shared.state.skipped: # fires per tile, so tiled encodes abort promptly - raise AssertionError('Interrupted...') - - for name in ('transformer', 'transformer_ref'): - module = getattr(pipe, name, None) - if module is not None: - target = getattr(module, 'model', module) # conditioning calls the inner model directly - if isinstance(target, torch.nn.Module) and getattr(target, 'sdnext_state_hook', None) is None: - target.sdnext_state_hook = target.register_forward_pre_hook(_pre_transformer_hook) - - for name in ('text_encoder', 'text_encoder_2'): - module = getattr(pipe, name, None) - if module is not None: - target = getattr(module, 'model', module) # conditioning calls the inner model directly - if isinstance(target, torch.nn.Module) and getattr(target, 'sdnext_state_hook', None) is None: - target.sdnext_state_hook = target.register_forward_pre_hook(_pre_text_encode_hook) - - for name in ('vae', 'audio_vae'): - decoder = getattr(getattr(pipe, name, None), 'decoder', None) # decode entry points bypass forward, the inner decoder does not - if isinstance(decoder, torch.nn.Module) and getattr(decoder, 'sdnext_state_hook', None) is None: - decoder.sdnext_state_hook = decoder.register_forward_pre_hook(_pre_vae_decode_hook) - encoder = getattr(getattr(pipe, name, None), 'encoder', None) # decode entry points bypass forward, the inner encoder does not - if isinstance(encoder, torch.nn.Module) and getattr(encoder, 'sdnext_state_hook', None) is None: - encoder.sdnext_state_hook = encoder.register_forward_pre_hook(_pre_vae_encode_hook) - - def is_modular(obj) -> bool: if obj is None: return False @@ -121,7 +38,7 @@ def is_modular(obj) -> bool: return 'Modular' in cls.__name__ -def preload_components(pipe, workflow: str | None, load_config: dict | None = None) -> dict: +def preload_components(pipe, workflow: str | None, load_config: dict | None = None, loaded: dict | None = None) -> dict: """Load the denoiser and text encoder through the shared loaders rather than the pipeline's own. `load_components` fetches every component into the pipeline's cache directory with no @@ -136,24 +53,29 @@ def preload_components(pipe, workflow: str | None, load_config: dict | None = No """ from pipelines import generic specs = getattr(pipe, '_component_specs', {}) # pylint: disable=protected-access - loaded = {} + loaded = loaded or {} for name in missing_components(pipe, workflow): + if name in loaded: + continue spec = specs.get(name) if spec is None or getattr(spec, 'default_creation_method', None) != 'from_pretrained': continue repo = getattr(spec, 'pretrained_model_name_or_path', None) - cls = getattr(spec, 'type_hint', None) + cls = getattr(spec, 'type_hint', None) or {} if not repo or cls is None: continue origin = getattr(cls, '__module__', '') or '' - cls_name = getattr(cls, '__name__', '') or '' # TODO preload: components with remote code resolve to cls none + cls_name = getattr(cls, '__name__', '') or '' subfolder = getattr(spec, 'subfolder', None) or name component = None if origin.startswith('diffusers') and ('Transformer' in cls_name or 'UNet' in cls_name): component = generic.load_transformer(repo, cls_name=cls, load_config=load_config, subfolder=subfolder, trust_remote_code=True) - elif origin.startswith('transformers') and 'text_encoder' in name: + elif origin.startswith('transformers') and ('text_encoder' in name): # shared substitution is on: the map matches class plus a substring of the repo name, so its entries have to run narrow before broad component = generic.load_text_encoder(repo, cls_name=cls, load_config=load_config, subfolder=subfolder) + if ('transformer' in name) and (component is None): + # fallback for component with remote-code as it does not have resolvable cls + component = generic.load_transformer(repo, cls_name=None, load_config=load_config, subfolder=subfolder, trust_remote_code=True) if component is not None: loaded[name] = component return loaded @@ -176,7 +98,15 @@ def missing_components(pipe, workflow: str | None) -> list: return [name for name in names if getattr(pipe, name, None) is None] -def load_modular_pipe(repo_cls, repo: str, workflow: str | None = None, revision: str | None = None, offline_args: dict | None = None, base: bool = False, load_config: dict | None = None): +def load_modular_pipe(repo_cls, + repo: str, + workflow: str | None = None, + revision: str | None = None, + offline_args: dict | None = None, + base: bool = False, + load_config: dict | None = None, + loaded: dict | None = None, + ): if repo_cls is None or isinstance(repo_cls, str): log.error(f'Load modular: repo="{repo}" cls="{repo_cls}" pipeline class not found: diffusers too old') return None @@ -192,7 +122,7 @@ def load_modular_pipe(repo_cls, repo: str, workflow: str | None = None, revision **offline_args, ) # the workflow restricts the component fetch only: passing it to from_pretrained instead would prune the blocks tree to one task and disable runtime dispatch between them - preloaded = preload_components(pipe, workflow, load_config=load_config) + preloaded = preload_components(pipe, workflow, load_config=load_config, loaded=loaded) if preloaded: pipe.update_components(**preloaded) # registered before the rest, which load_components then skips log.debug(f'Load modular: cls={pipe.__class__.__name__} preloaded={list(preloaded)}') @@ -214,7 +144,9 @@ def load_modular_pipe(repo_cls, repo: str, workflow: str | None = None, revision # diffusers logger, so the reason is in the log above this line rather than in the exception path log.error(f'Load modular: cls={pipe.__class__.__name__} workflow={workflow} missing={missing} components the workflow requires did not load') - install_state_hook(pipe) + sd_hijack_modular.install_state_hook(pipe) + sd_hijack_modular.register_callbacks(pipe) + apply_progress_bar_config(pipe._blocks) # pylint: disable=protected-access return pipe except Exception as e: diff --git a/modules/options_handler.py b/modules/options_handler.py index 9006673f6..8b7818994 100644 --- a/modules/options_handler.py +++ b/modules/options_handler.py @@ -17,10 +17,23 @@ if TYPE_CHECKING: import builtins cmd_opts = cmd_args.parse_args() -compatibility_opts = ['clip_skip', 'uni_pc_lower_order_final', 'uni_pc_order'] +compatibility_opts = ['clip_skip', 'uni_pc_lower_order_final', 'uni_pc_order', 'xformers_options', 'lora_apply_te'] +removed_values = { # a stored choice that no longer exists is kept by validate, so it has to be rewritten or it selects nothing + 'cross_attention_optimization': (['Batch matrix-matrix', 'Dynamic Attention BMM'], 'Scaled-Dot-Product'), +} secrets_pattern = ['_version', '_token', '_key', '_secret', '_password'] +def migrate_removed_values(data: dict) -> list: + """Rewrite stored settings whose choice was removed, returning what changed.""" + migrated = [] + for key, (removed, replacement) in removed_values.items(): + if data.get(key, None) in removed: + migrated.append(f'{key}={data[key]} replaced={replacement}') + data[key] = replacement + return migrated + + class Options: data_labels: dict[str, OptionInfo | LegacyOption] data: dict[str, Any] @@ -203,6 +216,9 @@ class Options: self.secrets = readfile(secretsfn, lock=True, as_type="dict") if self.data.get('quicksettings') is not None and self.data.get('quicksettings_list') is None: self.data['quicksettings_list'] = [i.strip() for i in self.data.get('quicksettings', '').split(',')] + migrated = migrate_removed_values(self.data) + if len(migrated) > 0: + log.warning(f"Setting migration: {migrated}") unknown_settings = [] for k, v in self.data.items(): info = self.data_labels.get(k, None) diff --git a/modules/postprocess/seedvr_model.py b/modules/postprocess/seedvr_model.py index 6fc51531c..eef97df10 100644 --- a/modules/postprocess/seedvr_model.py +++ b/modules/postprocess/seedvr_model.py @@ -340,9 +340,9 @@ class UpscalerSeedVR(Upscaler): images=tensor, cfg_scale=cfg_scale, cfg_rescale=cfg_rescale, - steps=steps, # TODO SeedVR steps - batch_size=batch_size, # TODO SeedVR batch size - temporal_overlap=batch_overlap, # TODO SeedVR temporal overlap + steps=steps, + batch_size=batch_size, + temporal_overlap=batch_overlap, seed=seed, res_w=width, device=devices.device, diff --git a/modules/processing.py b/modules/processing.py index 90f8015df..3adb1a721 100644 --- a/modules/processing.py +++ b/modules/processing.py @@ -5,6 +5,7 @@ import numpy as np from PIL import Image, ImageOps from modules import shared, devices, errors, images, scripts_manager, memstats, script_callbacks, extra_networks, sd_models, sd_checkpoint, sd_vae, processing_helpers, processing_grading, timer, masking from modules.logger import log +from modules.attention import context as attention_context from modules.sd_hijack_hypertile import context_hypertile_vae, context_hypertile_unet from modules.processing_info import create_infotext from modules.processing_class import ( # pylint: disable=unused-import @@ -52,9 +53,14 @@ class Processed: self.height = p.height if hasattr(p, 'height') else (self.images[0].height if len(self.images) > 0 else 0) self.sampler_name = p.sampler_name or '' + + self.cfg_name = p.cfg_name if (p.cfg_name is not None and p.cfg_name != 'Default') else None self.cfg_scale = p.cfg_scale if (p.cfg_scale is not None and p.cfg_scale > -1) else None - self.cfg_end = p.cfg_end if p.cfg_end < 1 else None + self.cfg_rescale = p.cfg_rescale if (p.cfg_rescale is not None and p.cfg_rescale > -1) else None self.cfg_image = p.cfg_image if (p.cfg_image is not None and p.cfg_image > -1) else None + self.cfg_start = p.cfg_start if p.cfg_start > 0 else None + self.cfg_stop = p.cfg_stop if p.cfg_stop < 1 else None + self.steps = p.steps or 0 self.batch_size = max(1, p.batch_size) self.denoising_strength = p.denoising_strength @@ -102,8 +108,12 @@ class Processed: "width": self.width, "height": self.height, "sampler_name": self.sampler_name, + "cfg_name": self.cfg_name, "cfg_scale": self.cfg_scale, - "cfg_end": self.cfg_end, + "cfg_rescale": self.cfg_rescale, + "cfg_image": self.cfg_image, + "cfg_start": self.cfg_start, + "cfg_stop": self.cfg_stop, "steps": self.steps, "batch_size": self.batch_size, "detailer": self.detailer, @@ -198,6 +208,7 @@ def process_images(p: StableDiffusionProcessing) -> Processed | None: script_callbacks.before_process_callback(p) timer.process.record('pre') + attention_context.begin(shared.sd_model, p.steps) if shared.cmd_opts.profile: timer.startup.profile = True @@ -231,6 +242,7 @@ def process_images(p: StableDiffusionProcessing) -> Processed | None: results = process_images_inner(p) finally: + attention_context.end() script_callbacks.after_process_callback(p) if p.override_settings_restore_afterwards: # restore opts to original state @@ -340,11 +352,18 @@ def process_samples(p: StableDiffusionProcessing, samples): method = p.color_correction_method if p.color_correction_method is not None else getattr(shared.opts, 'color_correction_method', 'histogram') image = apply_color_correction(p.color_corrections[i], image, method=method) - if p.scripts is not None and isinstance(p.scripts, scripts_manager.ScriptRunner): + if p.scripts is not None and isinstance(p.scripts, scripts_manager.ScriptRunner) and not getattr(p, 'is_grid', False): pp = scripts_manager.PostprocessImageArgs(image) p.scripts.postprocess_image(p, pp) if pp.image is not None: - image = pp.image + if isinstance(pp.image, list) and len(pp.image) > 0: # post process image can return original+processed + for i, img in enumerate(pp.image): + if i+1 < len(pp.image): + out_images.append(img) + out_infotexts.append(f"Postprocess image {i+1}") + image = pp.image[-1] + else: + image = pp.image grading_params = processing_grading.GradingParams( brightness=getattr(p, 'grading_brightness', 0.0), @@ -437,6 +456,10 @@ def print_stats(): if dynamo_dct: log.debug(f'Processed: dynamo={dynamo_dct}') + if timer.blocks.get_total() > 0.1: + log.debug(f'Processed: blocks={timer.blocks.dct(min_time=0.1, no_total=True)}') + timer.blocks.reset() + def process_images_inner(p: StableDiffusionProcessing) -> Processed: t0 = time.time() @@ -487,8 +510,7 @@ def process_images_inner(p: StableDiffusionProcessing) -> Processed: p.scripts.before_process_batch(p, batch_number=n, prompts=p.prompts, seeds=p.seeds, subseeds=p.subseeds) if not p.prompts: break - p.prompts, p.network_data = extra_networks.parse_prompts(p.prompts) - + p.prompts, p.network_data = extra_networks.parse_prompts(p.prompts, p.network_data) if p.scripts is not None and isinstance(p.scripts, scripts_manager.ScriptRunner): p.scripts.process_batch(p, batch_number=n, prompts=p.prompts, seeds=p.seeds, subseeds=p.subseeds) @@ -525,7 +547,7 @@ def process_images_inner(p: StableDiffusionProcessing) -> Processed: if p.scripts is not None and isinstance(p.scripts, scripts_manager.ScriptRunner): p.scripts.postprocess_batch(p, samples, batch_number=n) - if p.scripts is not None and isinstance(p.scripts, scripts_manager.ScriptRunner): + if p.scripts is not None and isinstance(p.scripts, scripts_manager.ScriptRunner) and isinstance(samples, list): p.prompts = p.all_prompts[(n * p.batch_size):((n+1) * p.batch_size)] p.negative_prompts = p.all_negative_prompts[(n * p.batch_size):((n+1) * p.batch_size)] batch_params = scripts_manager.PostprocessBatchListArgs(list(samples)) @@ -593,7 +615,9 @@ def process_images_inner(p: StableDiffusionProcessing) -> Processed: audio=audio, ) if p.scripts is not None and isinstance(p.scripts, scripts_manager.ScriptRunner) and not (shared.state.interrupted or shared.state.skipped): - p.scripts.postprocess(p, results) + _results = p.scripts.postprocess(p, results) + if _results is not None: + results = _results timer.process.record('post') p.ops = list(set(p.ops)) t3 = time.time() diff --git a/modules/processing_args.py b/modules/processing_args.py index 94a66153f..2833f4f82 100644 --- a/modules/processing_args.py +++ b/modules/processing_args.py @@ -8,9 +8,11 @@ import numpy as np from PIL import Image from modules import shared, sd_models, processing, processing_vae, processing_helpers, sd_hijack_hypertile, sd_vae from modules.logger import log +from modules.attention import context as attention_context from modules.processing_callbacks import diffusers_callback_legacy, diffusers_callback, set_callbacks_p from modules.processing_helpers import get_generator, apply_circular # pylint: disable=unused-import from modules.processing_prompt import set_prompt +from modules.lora import network_pdd from modules.api import helpers @@ -30,6 +32,9 @@ def task_modular_kwargs(p, model): if len(getattr(p, 'init_images', [])) > 0: task_args['image'] = p.init_images task_args['strength'] = p.denoising_strength + if (shared.sd_model_type == 'sdxl') and hasattr(model, 'register_to_config') and (model_cls not in sd_models.i2i_pipes): + model.register_to_config(requires_aesthetics_score = False) + mask_image = p.task_args.get('image_mask', None) or getattr(p, 'image_mask', None) or getattr(p, 'mask', None) if mask_image is not None: task_args['mask_image'] = mask_image @@ -67,8 +72,8 @@ def task_specific_kwargs(p, model): 'width': width, 'height': height, } - elif (task_type == sd_models.DiffusersTaskType.IMAGE_2_IMAGE or is_img2img_model) and len(getattr(p, 'init_images', [])) > 0: - if shared.sd_model_type == 'sdxl' and hasattr(model, 'register_to_config'): + elif (task_type == sd_models.DiffusersTaskType.IMAGE_2_IMAGE or task_type == sd_models.DiffusersTaskType.MODULAR or is_img2img_model) and (len(getattr(p, 'init_images', [])) > 0): + if (shared.sd_model_type == 'sdxl') and hasattr(model, 'register_to_config'): if model_cls in sd_models.i2i_pipes: pass else: @@ -106,6 +111,11 @@ def task_specific_kwargs(p, model): 'height': p.height, 'input_images': [p.init_images], # omnigen expects list-of-lists } + elif model_cls == 'LLaDAImagePipeline': + task_args = { + 'generation_mode': 'editing', + 'image': p.init_images[0], + } elif task_type == sd_models.DiffusersTaskType.INSTRUCT and len(getattr(p, 'init_images', [])) > 0: p.ops.append('instruct') task_args = { @@ -114,7 +124,7 @@ def task_specific_kwargs(p, model): 'image': p.init_images, 'strength': p.denoising_strength, } - elif (task_type == sd_models.DiffusersTaskType.INPAINTING or is_img2img_model) and len(getattr(p, 'init_images', [])) > 0: + elif (task_type == sd_models.DiffusersTaskType.INPAINTING or task_type == sd_models.DiffusersTaskType.MODULAR or is_img2img_model) and len(getattr(p, 'init_images', [])) > 0: if shared.sd_model_type == 'sdxl' and hasattr(model, 'register_to_config'): if model_cls in [sd_models.i2i_pipes]: pass @@ -254,7 +264,11 @@ def set_pipeline_args(p, model, prompts:list, negative_prompts:list, prompts_2:l possible = get_params(model) - log.debug(f'Pipeline: cls={cls} possible={possible}') + pinned = network_pdd.pin(p, model) # installed parallel-decoding heads fix the step count and schedule + if pinned is not None and 'num_inference_steps' in possible: + kwargs['num_inference_steps'] = pinned + + debug_log(f'Pipeline: cls={cls} possible={possible}') steps = kwargs.get("num_inference_steps", None) or len(getattr(p, 'timesteps', ['1'])) clip_skip = kwargs.pop("clip_skip", 1) @@ -366,6 +380,7 @@ def set_pipeline_args(p, model, prompts:list, negative_prompts:list, prompts_2:l args['callback_steps'] = 1 set_callbacks_p(p) + attention_context.new_pass(steps) if 'prior_callback_on_step_end' in possible: # Wuerstchen / Cascade args['prior_callback_on_step_end'] = diffusers_callback if 'prior_callback_on_step_end_tensor_inputs' in possible: @@ -434,7 +449,7 @@ def set_pipeline_args(p, model, prompts:list, negative_prompts:list, prompts_2:l # handle missing resolution if args.get('image', None) is not None and ('width' not in args or 'height' not in args): if 'width' in possible and 'height' in possible: - vae_scale_factor = sd_vae.get_vae_scale_factor(model) + vae_scale_factor = sd_vae.get_vae_scale_factor(model, init_image=True) if isinstance(args['image'], torch.Tensor) or isinstance(args['image'], np.ndarray): if args['image'].shape[-1] == 3: # nhwc args['width'] = args['image'].shape[-2] diff --git a/modules/processing_callbacks.py b/modules/processing_callbacks.py index 48ac6e75b..919e089c5 100644 --- a/modules/processing_callbacks.py +++ b/modules/processing_callbacks.py @@ -4,6 +4,7 @@ import torch import numpy as np from modules import shared, devices, processing_correction, timer, prompt_parser_diffusers from modules.logger import log +from modules.attention import context as attention_context p = None @@ -16,6 +17,8 @@ def set_callbacks_p(processing): global p, warned # pylint: disable=global-statement p = processing warned = False + from modules.lora import lora_stack + lora_stack.reset(int(getattr(processing, 'steps', 0) or 0)) # per-pass: restore initial selections and reschedule flips before any step runs def prompt_callback(step, kwargs): @@ -36,6 +39,8 @@ def prompt_callback(step, kwargs): def diffusers_callback_legacy(step: int, timestep: int, latents: torch.FloatTensor | np.ndarray): if p is None: return + from modules.lora import lora_stack + lora_stack.on_step(step) if isinstance(latents, np.ndarray): # latents from Onnx pipelines is ndarray. latents = torch.from_numpy(latents) shared.state.sampling_step = step @@ -51,11 +56,7 @@ def diffusers_callback_legacy(step: int, timestep: int, latents: torch.FloatTens time.sleep(0.1) -def diffusers_callback(pipe, step: int = 0, timestep: int = 0, kwargs: dict | None = None): - if kwargs is None: - kwargs = {} - t0 = time.time() - +def torch_sync(): if shared.opts.torch_sync: if devices.backend == "ipex": torch.xpu.synchronize(devices.device) @@ -63,6 +64,15 @@ def diffusers_callback(pipe, step: int = 0, timestep: int = 0, kwargs: dict | No torch.cuda.synchronize(devices.device) time.sleep(0.001) # 1ms yield frees GIL for the preview thread + +def diffusers_callback(pipe, step: int = 0, timestep: int = 0, kwargs: dict | None = None): + if kwargs is None: + kwargs = {} + t0 = time.time() + from modules.lora import lora_stack + lora_stack.on_step(step) + torch_sync() + t1 = time.time() if shared.state.paused: @@ -87,6 +97,7 @@ def diffusers_callback(pipe, step: int = 0, timestep: int = 0, kwargs: dict | No if shared.state.sampling_steps == 0 and getattr(pipe, 'num_timesteps', 0) > 0: shared.state.sampling_steps = pipe.num_timesteps shared.state.step() + attention_context.tick(step + 1) if shared.state.interrupted or shared.state.skipped: raise AssertionError('Interrupted...') if latents is None or p is None: @@ -112,11 +123,11 @@ def diffusers_callback(pipe, step: int = 0, timestep: int = 0, kwargs: dict | No if step == 0: pipe._cfg_end_applied = False # pylint: disable=protected-access - cfg_end = getattr(p, "cfg_end", 1.0) or 1.0 + cfg_stop = getattr(p, "cfg_stop", None) or getattr(p, "cfg_end", None) or 1.0 total_steps = getattr(pipe, "num_timesteps", 0) - target_step = int(total_steps * cfg_end) if total_steps else 0 + target_step = int(total_steps * cfg_stop) if total_steps else 0 - if (cfg_end < 1.0) and not getattr(pipe, "_cfg_end_applied", False) and (step >= target_step): + if (cfg_stop < 1.0) and not getattr(pipe, "_cfg_end_applied", False) and (step >= target_step): pipe._cfg_end_applied = True # pylint: disable=protected-access if "PAG" in shared.sd_model.__class__.__name__: pipe._guidance_scale = 1.001 if pipe._guidance_scale > 1 else pipe._guidance_scale # pylint: disable=protected-access diff --git a/modules/processing_class.py b/modules/processing_class.py index b5f567379..d55a36147 100644 --- a/modules/processing_class.py +++ b/modules/processing_class.py @@ -45,15 +45,11 @@ class StableDiffusionProcessing: sampler_name: str | None = None, hr_sampler_name: str | None = None, eta: float | None = None, - # modular guidance - guidance_name: str = 'Default', - guidance_scale: float = 6.0, - guidance_rescale: float = 0.0, - guidance_start: float = 0.0, - guidance_stop: float = 1.0, - # legacy guidance + # guidance + cfg_name: str = 'Default', cfg_scale: float = 6.0, - cfg_end: float = 1, + cfg_start: float = 0.0, + cfg_stop: float = 1, cfg_rescale: float = 0.0, cfg_true: float = 0.0, cfg_adaptive: float = 0.5, @@ -254,7 +250,6 @@ class StableDiffusionProcessing: prompt_mean_norm: bool | None = None, diffusers_zeros_prompt_pad: bool | None = None, te_pooled_embeds: bool | None = None, - lora_apply_te: bool | None = None, te_complex_human_instruction: str | None = None, te_use_mask: bool | None = None, # generation modifier overrides (hijack) @@ -458,16 +453,6 @@ class StableDiffusionProcessing: self.do_not_save_grid = do_not_save_grid self.override_settings_restore_afterwards = override_settings_restore_afterwards self.eta = eta - self.guidance_name = guidance_name - self.guidance_scale = guidance_scale - self.guidance_rescale = guidance_rescale - self.guidance_start = guidance_start - self.guidance_stop = guidance_stop - self.cfg_scale = cfg_scale - self.cfg_end = cfg_end - self.cfg_rescale = cfg_rescale - self.cfg_true = cfg_true - self.cfg_adaptive = cfg_adaptive self.selected_scale_tab = selected_scale_tab self.mask_for_overlay = mask_for_overlay self.paste_to = paste_to @@ -511,6 +496,15 @@ class StableDiffusionProcessing: log.error(f'Override: {override_settings} {e}') self.override_settings = {} + # guidance + self.cfg_name = cfg_name + self.cfg_scale = cfg_scale + self.cfg_start = cfg_start + self.cfg_stop = cfg_stop + self.cfg_rescale = cfg_rescale + self.cfg_true = cfg_true + self.cfg_adaptive = cfg_adaptive + # scheduler/noise overrides self.schedulers_prediction_type = schedulers_prediction_type self.schedulers_beta_schedule = schedulers_beta_schedule @@ -543,7 +537,6 @@ class StableDiffusionProcessing: self.prompt_mean_norm = prompt_mean_norm self.diffusers_zeros_prompt_pad = diffusers_zeros_prompt_pad self.te_pooled_embeds = te_pooled_embeds - self.lora_apply_te = lora_apply_te self.te_complex_human_instruction = te_complex_human_instruction self.te_use_mask = te_use_mask # generation modifier overrides (hijack) @@ -745,7 +738,7 @@ class StableDiffusionProcessingImg2Img(StableDiffusionProcessing): def init(self, all_prompts=None, all_seeds=None, all_subseeds=None): if self.init_images is not None and len(self.init_images) > 0: - vae_scale_factor = sd_vae.get_vae_scale_factor() + vae_scale_factor = sd_vae.get_vae_scale_factor(init_image=True) if self.width is None or self.width == 0: self.width = int(vae_scale_factor * (self.init_images[0].width * self.scale_by // vae_scale_factor)) if self.height is None or self.height == 0: diff --git a/modules/processing_diffusers.py b/modules/processing_diffusers.py index 0efbc4904..3b8d5e129 100644 --- a/modules/processing_diffusers.py +++ b/modules/processing_diffusers.py @@ -3,10 +3,11 @@ import os import time import numpy as np import torch +import diffusers from PIL import Image -from modules import shared, processing, sd_models, errors, sd_hijack_hypertile, processing_vae, sd_models_compile, timer, modelstats, extra_networks, attention +from modules import shared, processing, sd_models, errors, sd_hijack_hypertile, processing_vae, sd_models_compile, timer, modelstats, extra_networks, attention, modular from modules.logger import log -from modules.processing_helpers import resize_hires, calculate_base_steps, calculate_hires_steps, calculate_refiner_steps, save_intermediate, update_sampler, is_txt2img, is_refiner_enabled, get_job_name +from modules.processing_helpers import resize_hires, calculate_base_steps, calculate_hires_steps, calculate_refiner_steps, save_intermediate, update_sampler, is_txt2img, is_refiner_enabled, get_job_name, is_modular from modules.processing_args import set_pipeline_args from modules.onnx_impl import preprocess_pipeline as preprocess_onnx_pipeline, check_parameters_changed as olive_check_parameters_changed from modules.lora import lora_common @@ -14,6 +15,7 @@ from modules.image import convert debug = os.environ.get('SD_DIFFUSERS_DEBUG', None) is not None +modular_debug = os.environ.get('SD_MODULAR_DEBUG', None) is not None output_type = 'np' if os.environ.get('SD_VAE_DEFAULT', None) is not None else 'latent' last_p = None orig_pipeline = shared.sd_model @@ -68,69 +70,61 @@ def restore_state(p: processing.StableDiffusionProcessing): return p -def process_pre(p: processing.StableDiffusionProcessing): - from modules import ipadapter, sd_hijack_freeu, para_attention, teacache, hidiffusion, ras, pag, cfgzero, transformer_cache, token_merge, linfusion, cachedit - if shared.sd_model is None: - log.warning('Processing modifiers: model not loaded') +def process_pre(p: processing.StableDiffusionProcessing, phase: str | None = None): + if not shared.sd_loaded: return - log.info('Processing modifiers: apply') - try: - # apply-with-unapply - # sd_hijack_compile.install() - sd_models_compile.check_deepcache(enable=True) - ipadapter.apply(shared.sd_model, p) - token_merge.apply_token_merging(shared.sd_model) - hidiffusion.apply(p, shared.sd_model_type) - ras.apply(shared.sd_model, p) - pag.apply(p) - cfgzero.apply(p) - linfusion.apply(shared.sd_model) - cachedit.apply_cache_dit(shared.sd_model) - - # apply-only - sd_hijack_freeu.apply_freeu(p) - transformer_cache.set_cache() - para_attention.apply_first_block_cache() - teacache.apply_teacache(p) - except Exception as e: - log.error(f'Processing apply: {e}') - errors.display(e, 'apply') - + if is_modular(shared.sd_model): + if modular.is_guider(shared.sd_model): + from modules import modular_guiders + modular_guiders.set_guider(p, phase) + else: + try: + log.info(f'Processing: modifiers=apply phase={phase}') + from modules import ipadapter, sd_hijack_freeu, para_attention, teacache, hidiffusion, ras, pag, cfgzero, transformer_cache, token_merge, linfusion, cachedit + # apply-with-unapply + # sd_hijack_compile.install() + sd_models_compile.check_deepcache(enable=True) + token_merge.apply_token_merging(shared.sd_model) + hidiffusion.apply(p, shared.sd_model_type) + ras.apply(shared.sd_model, p) + pag.apply(p) + cfgzero.apply(p) + linfusion.apply(shared.sd_model) + cachedit.apply_cache_dit(shared.sd_model) + ipadapter.apply(shared.sd_model, p) + # apply-only + sd_hijack_freeu.apply_freeu(p) + transformer_cache.set_cache(p) + para_attention.apply_first_block_cache() + teacache.apply_teacache(p) + except Exception as e: + log.error(f'Processing apply: {e}') + errors.display(e, 'apply') shared.sd_model = sd_models.apply_balanced_offload(shared.sd_model) - # if hasattr(shared.sd_model, 'unet'): - # sd_models.move_model(shared.sd_model.unet, devices.device) - # if hasattr(shared.sd_model, 'transformer'): - # sd_models.move_model(shared.sd_model.transformer, devices.device) - - from modules import modular - if modular.is_compatible(shared.sd_model): - modular_pipe = modular.convert_to_modular(shared.sd_model) - if modular_pipe is not None: - shared.sd_model = modular_pipe - if modular.is_guider(shared.sd_model): - from modules import modular_guiders - modular_guiders.set_guider(p) - timer.process.record('pre') def process_post(p: processing.StableDiffusionProcessing): - from modules import ipadapter, hidiffusion, ras, pag, cfgzero, token_merge, linfusion, cachedit - log.info('Processing modifiers: unapply') - - try: - sd_models_compile.check_deepcache(enable=False) - ipadapter.unapply(shared.sd_model, unload=getattr(p, 'ip_adapter_unload', False)) - token_merge.remove_token_merging(shared.sd_model) - hidiffusion.unapply() - ras.unapply(shared.sd_model) - pag.unapply() - cfgzero.unapply() - linfusion.unapply(shared.sd_model) - cachedit.unapply_cache_dir(shared.sd_model) - except Exception as e: - log.error(f'Processing unapply: {e}') - errors.display(e, 'unapply') + if not shared.sd_loaded: + return + if is_modular(shared.sd_model): + pass + else: + try: + from modules import ipadapter, hidiffusion, ras, pag, cfgzero, token_merge, linfusion, cachedit + log.info('Processing: modifiers=unapply') + sd_models_compile.check_deepcache(enable=False) + ipadapter.unapply(shared.sd_model, unload=getattr(p, 'ip_adapter_unload', False)) + token_merge.remove_token_merging(shared.sd_model) + hidiffusion.unapply() + ras.unapply(shared.sd_model) + pag.unapply() + cfgzero.unapply() + linfusion.unapply(shared.sd_model) + cachedit.unapply_cache_dir(shared.sd_model) + except Exception as e: + log.error(f'Processing unapply: {e}') + errors.display(e, 'unapply') timer.process.record('post') @@ -143,13 +137,13 @@ def process_base(p: processing.StableDiffusionProcessing): shared.sd_model = update_pipeline(shared.sd_model, p) update_sampler(p, shared.sd_model) timer.process.record('prepare') - process_pre(p) + process_pre(p, 'base') sched_eta = p.scheduler_eta if p.scheduler_eta is not None else shared.opts.scheduler_eta desc = 'Base' if 'detailer' in p.ops: desc = 'Detail' p.prompts, p.network_data = extra_networks.parse_prompts(p.prompts, p.network_data) - extra_networks.activate_filtered(p) # networks must patch weights before prompt encode so te loras affect embeds + extra_networks.activate(p) # networks must patch weights before prompt encode so te loras affect embeds base_args = set_pipeline_args( p=p, model=shared.sd_model, @@ -186,6 +180,8 @@ def process_base(p: processing.StableDiffusionProcessing): taskid = shared.state.begin('Inference') output = shared.sd_model(**base_args) shared.state.end(taskid) + if isinstance(output, diffusers.modular_pipelines.PipelineState) and modular_debug: + log.trace(f'Pipeline: output={output}') if isinstance(output, dict): output = SimpleNamespace(**output) if isinstance(output, list): @@ -194,7 +190,7 @@ def process_base(p: processing.StableDiffusionProcessing): output = SimpleNamespace(images=[output]) if not hasattr(output, 'frames') and hasattr(output, 'videos'): output.frames = output.videos # modular video pipelines emit videos, not frames - if hasattr(output, 'image'): + if hasattr(output, 'image') and getattr(output, 'images', None) is None: # for modular output.image may be input and output.images may be output so we dont want to overwrite output output.images = output.image if hasattr(output, 'images'): shared.history.add(output.images, info=processing.create_infotext(p), ops=p.ops) @@ -224,7 +220,8 @@ def process_base(p: processing.StableDiffusionProcessing): for k, v in base_args.items(): if isinstance(v, torch.Tensor): err_args[k] = f'{v.device}:{v.dtype}:{v.shape}' - log.error(f'Processing: step=base args={err_args} {e}') + log.error(f'Processing: step=base args={err_args}') + log.error(f'Processing: {e}') errors.display(e, 'Processing') modelstats.analyze() finally: @@ -303,17 +300,17 @@ def process_hires(p: processing.StableDiffusionProcessing, output): orig_denoise = p.denoising_strength p.denoising_strength = strength orig_image = p.task_args.pop('image', None) # remove image override from hires - process_pre(p) + process_pre(p, 'hires') prompts = p.prompts reset_prompts = False sched_eta = p.scheduler_eta if p.scheduler_eta is not None else shared.opts.scheduler_eta if len(p.refiner_prompt) > 0: prompts = len(output.images)* [p.refiner_prompt] - prompts, p.network_data = extra_networks.parse_prompts(prompts) + prompts, p.network_data = extra_networks.parse_prompts(prompts, p.network_data) reset_prompts = True if reset_prompts or ('base' in p.skip): - extra_networks.activate_filtered(p) + extra_networks.activate(p) hires_args = set_pipeline_args( p=p, @@ -469,9 +466,11 @@ def process_decode(p: processing.StableDiffusionProcessing, output): if not hasattr(output, 'images') and hasattr(output, 'frames'): log.debug(f'Generated: frames={len(output.frames[0])}') output.images = output.frames[0] - if getattr(p, 'video_still', False) and hasattr(output, 'images') and output.images is not None: + if hasattr(output, 'latents') and hasattr(output, 'images') and (output.images is None): + output.images = output.latents # modular pipelines may return latents instead of images + if getattr(p, 'video_still', False) and hasattr(output, 'images') and (output.images is not None): output.images = output.images[:1] # only the first frame derives from real latents; the rest decode from padding - if output.images is not None and len(output.images) > 0 and isinstance(output.images[0], Image.Image): + if (output.images is not None) and (len(output.images) > 0) and isinstance(output.images[0], Image.Image): sd_models.offload_ondemand(shared.sd_model) # in-pipe decode paths return materialized frames; the vae seam in processing_vae never runs return attach_audio(output.images, audio) model = shared.sd_model if not is_refiner_enabled(p) else shared.sd_refiner @@ -546,8 +545,8 @@ def update_pipeline(sd_model, p: processing.StableDiffusionProcessing): global orig_pipeline # pylint: disable=global-statement orig_pipeline = updated_model # processed ONNX pipeline should not be replaced with original pipeline. current_attn = getattr(updated_model, "current_attn_name", None) - if (current_attn != shared.opts.cross_attention_optimization) and (current_attn != shared.opts.sdp_overrides): - log.info(f"Setting attention optimization: {shared.opts.cross_attention_optimization}") + if current_attn != shared.opts.cross_attention_optimization: + # log.info(f"Setting attention optimization: {shared.opts.cross_attention_optimization}") attention.set_diffusers_attention(updated_model) return updated_model @@ -622,7 +621,7 @@ def process_diffusers(p: processing.StableDiffusionProcessing): images = shared.history.last_latent output = SimpleNamespace(images=images) if images is not None else None - if (output is None or (hasattr(output, 'images') and len(output.images) == 0)) and has_images: + if (output is None or (hasattr(output, 'images') and (output.images is None or len(output.images) == 0))) and has_images: if output is not None: log.debug('Processing: using input as base output') output.images = p.init_images diff --git a/modules/processing_helpers.py b/modules/processing_helpers.py index c31adc4c3..d89b05f86 100644 --- a/modules/processing_helpers.py +++ b/modules/processing_helpers.py @@ -17,12 +17,16 @@ debug_steps = log.trace if os.environ.get('SD_STEPS_DEBUG', None) is not None el debug_steps('Trace: STEPS') -def is_modular(): - return sd_models.get_diffusers_task(shared.sd_model) == sd_models.DiffusersTaskType.MODULAR +def is_modular(pipe = None): + if not shared.sd_loaded: + return False + pipe = pipe or shared.sd_model + return sd_models.get_diffusers_task(pipe) == sd_models.DiffusersTaskType.MODULAR -def is_txt2img(): - return sd_models.get_diffusers_task(shared.sd_model) == sd_models.DiffusersTaskType.TEXT_2_IMAGE +def is_txt2img(pipe = None): + pipe = pipe or shared.sd_model + return sd_models.get_diffusers_task(pipe) == sd_models.DiffusersTaskType.TEXT_2_IMAGE def is_refiner_enabled(p): @@ -155,9 +159,11 @@ def images_tensor_to_samples(image, approximation=None, model=None): # pylint: d return x_latent -def get_sampler_name(sampler_index: int | None = None, img: bool = False) -> str: +def get_sampler_name(sampler_index: int | str | None = None, img: bool = False) -> str: sampler_index = sampler_index or 0 - if len(sd_samplers.samplers) > sampler_index: + if isinstance(sampler_index, str) and any(sampler.name == sampler_index for sampler in sd_samplers.samplers): + sampler_name = sampler_index + elif isinstance(sampler_index, int) and 0 <= sampler_index < len(sd_samplers.samplers): sampler_name = sd_samplers.samplers[sampler_index].name else: sampler_name = "Default" @@ -391,7 +397,7 @@ def resize_init_images(p): p.init_images = [p.image] if getattr(p, 'init_images', None) is not None and len(p.init_images) > 0: p.init_images = decode_images(p.init_images) - vae_scale_factor = sd_vae.get_vae_scale_factor() + vae_scale_factor = sd_vae.get_vae_scale_factor(init_image=True) tgt_width = vae_scale_factor * math.ceil(p.init_images[0].width / vae_scale_factor) tgt_height = vae_scale_factor * math.ceil(p.init_images[0].height / vae_scale_factor) if p.init_images[0].size != (tgt_width, tgt_height): diff --git a/modules/processing_info.py b/modules/processing_info.py index ad87e6177..54544ae84 100644 --- a/modules/processing_info.py +++ b/modules/processing_info.py @@ -59,9 +59,11 @@ def create_infotext(p: StableDiffusionProcessing, all_prompts=None, all_seeds=No "Scheduler": shared.sd_model.scheduler.__class__.__name__ if getattr(shared.sd_model, 'scheduler', None) is not None else None, "Seed": all_seeds[index], "Seed resize from": None if p.seed_resize_from_w <= 0 or p.seed_resize_from_h <= 0 else f"{p.seed_resize_from_w}x{p.seed_resize_from_h}", + "CFG name": p.cfg_name if p.cfg_name != 'Default' else None, "CFG scale": p.cfg_scale if p.cfg_scale > -1 else None, "CFG rescale": p.cfg_rescale if p.cfg_rescale > -1 else None, - "CFG end": p.cfg_end if p.cfg_end < 1.0 else None, + "CFG start": p.cfg_start if p.cfg_start > 0.0 else None, + "CFG stop": p.cfg_stop if p.cfg_stop < 1.0 else None, "CFG true": p.cfg_true if p.cfg_true > 0 else None, "CFG adaptive": p.cfg_adaptive if p.cfg_adaptive != 0.5 else None, "CLiP-skip": p.clip_skip if p.clip_skip > 1 else None, @@ -183,7 +185,7 @@ def create_infotext(p: StableDiffusionProcessing, all_prompts=None, all_seeds=No args['ToMe'] = _tome if _tome != 0 else None elif _token_method == 'ToDo': args['ToDo'] = _todo if _todo != 0 else None - if hasattr(shared.sd_model, 'embedding_db') and len(shared.sd_model.embedding_db.embeddings_used) > 0: # register used embeddings + if hasattr(shared.sd_model, 'embedding_db') and (shared.sd_model.embedding_db is not None) and len(shared.sd_model.embedding_db.embeddings_used) > 0: # register used embeddings args['Embeddings'] = ', '.join(shared.sd_model.embedding_db.embeddings_used) # samplers @@ -206,11 +208,6 @@ def create_infotext(p: StableDiffusionProcessing, all_prompts=None, all_seeds=No args['Sampler shift'] = get_opt('schedulers_shift') if get_opt('schedulers_shift') != shared.opts.data_labels.get('schedulers_shift').default else None args['Sampler dynamic shift'] = get_opt('schedulers_dynamic_shift') if get_opt('schedulers_dynamic_shift') != shared.opts.data_labels.get('schedulers_dynamic_shift').default else None - # model specific - if shared.sd_model_type == 'h1': - args['LLM'] = None if shared.opts.model_h1_llama_repo == 'Default' else shared.opts.model_h1_llama_repo - - # args.update(p.extra_generation_params) for k, v in p.extra_generation_params.items(): if isinstance(v, (list, tuple)) and (job_size > index) and (len(v) > 1) and (len(v) == job_size): # likely a per-job param args[k] = v[index] diff --git a/modules/processing_prompt.py b/modules/processing_prompt.py index cab96ce23..4151b213c 100644 --- a/modules/processing_prompt.py +++ b/modules/processing_prompt.py @@ -3,7 +3,7 @@ from __future__ import annotations import os from typing import TYPE_CHECKING import torch -from modules import shared, errors, timer, prompt_parser_diffusers +from modules import shared, errors, timer, prompt_parser_diffusers, processing_helpers from modules.logger import log if TYPE_CHECKING: @@ -68,11 +68,13 @@ def set_fallback_prompt(args: dict, possible: list[str], prompts, negative_promp debug_log(f'Prompt fallback: negative_prompt={negative_prompts}') args['negative_prompt'] = negative_prompts if ('prompt_2' in possible) and ('prompt_2' not in args) and (prompts_2 is not None) and len(prompts_2) > 0: - debug_log(f'Prompt fallback: prompt_2={prompts_2}') - args['prompt_2'] = prompts_2 + if (prompts_2 != prompts) and (prompts_2 != args.get('prompt', None)): + debug_log(f'Prompt fallback: prompt_2={prompts_2}') + args['prompt_2'] = prompts_2 if ('negative_prompt_2' in possible) and ('negative_prompt_2' not in args) and (negative_prompts_2 is not None) and len(negative_prompts_2) > 0: - debug_log(f'Prompt fallback: negative_prompt_2={negative_prompts_2}') - args['negative_prompt_2'] = negative_prompts_2 + if (negative_prompts_2 != negative_prompts) and (negative_prompts_2 != args.get('negative_prompt', None)): + debug_log(f'Prompt fallback: negative_prompt_2={negative_prompts_2}') + args['negative_prompt_2'] = negative_prompts_2 return args @@ -117,7 +119,10 @@ def set_prompt(p: StableDiffusionProcessing, prompt_attention = 'fixed' if not hasattr(shared.sd_model, 'orig_encode_prompt'): - log.debug(f'Encode: prompt="{prompts}" negative="{negative_prompts}" embedder={prompt_parser_diffusers.embedder is not None} attention={prompt_attention}') + if isinstance(prompts, list): + log.debug(f'Encode: prompt={prompts} negative={negative_prompts} embedder={prompt_parser_diffusers.embedder is not None} attention={prompt_attention}') + else: + log.debug(f'Encode: prompt="{prompts}" negative="{negative_prompts}" embedder={prompt_parser_diffusers.embedder is not None} attention={prompt_attention}') prompts, negative_prompts, prompts_2, negative_prompts_2 = fix_prompt_batch(p, prompts, negative_prompts, prompts_2, negative_prompts_2) prompts, negative_prompts, prompts_2, negative_prompts_2 = fix_prompt_model(cls, prompts, negative_prompts, prompts_2, negative_prompts_2) @@ -189,6 +194,9 @@ def set_prompt(p: StableDiffusionProcessing, args = set_fallback_prompt(args, possible, prompts=prompts, negative_prompts=negative_prompts, prompts_2=None, negative_prompts_2=None) prompt_attention = 'fixed' + if processing_helpers.is_modular(): + return prompt_attention, args + if 'prompt_embeds' not in args and 'negative_prompt_embeds' not in args: # pass secondary prompts as-in args = set_fallback_prompt(args, possible, prompts=None, negative_prompts=None, prompts_2=prompts_2, negative_prompts_2=negative_prompts_2) diff --git a/modules/processing_vae.py b/modules/processing_vae.py index 778407fd6..34f13c405 100644 --- a/modules/processing_vae.py +++ b/modules/processing_vae.py @@ -82,6 +82,8 @@ def full_vqgan_decode(latents, model): def full_vae_decode(latents, model): t0 = time.time() + if latents.ndim == 4 and latents.shape[1] == 3: # already decoded + return latents if not hasattr(model, 'vae') and hasattr(model, 'pipe'): model = model.pipe if model is None or not hasattr(model, 'vae'): @@ -394,7 +396,7 @@ def reprocess(gallery): latent, index = shared.history.selected if latent is None or gallery is None: return None - log.info(f'Reprocessing: latent={latent.shape}') + log.info(f'Reprocessing: latent={list(latent.shape)}') reprocessed = vae_decode(latent, shared.sd_model, output_type='pil') outputs = [] for i0, i1 in zip(gallery, reprocessed, strict=False): diff --git a/modules/prompt_parser_diffusers.py b/modules/prompt_parser_diffusers.py index 0b073baa8..d02817733 100644 --- a/modules/prompt_parser_diffusers.py +++ b/modules/prompt_parser_diffusers.py @@ -130,11 +130,8 @@ class PromptEmbedder: # unpack EN data in case of TE LoRA en_data = p.network_data en_data = [idx.items for item in en_data.values() for idx in item] - apply_te = getattr(p, 'lora_apply_te', None) - if apply_te is None: - apply_te = shared.opts.lora_apply_te effective_batch = 1 if self.allsame else self.batchsize - key = str([self.prompts, self.negative_prompts, effective_batch, self.clip_skip, self.steps, en_data, apply_te]) + key = str([self.prompts, self.negative_prompts, effective_batch, self.clip_skip, self.steps, en_data]) item = cache.get(key) if not item: if not any(flatten(emb) for emb in [self.prompt_embeds, diff --git a/modules/rembg/rembg_api.py b/modules/rembg/rembg_api.py index 0bb30f4dd..c100377b7 100644 --- a/modules/rembg/rembg_api.py +++ b/modules/rembg/rembg_api.py @@ -3,7 +3,7 @@ from fastapi import Body def dependencies(): from installer import install - for pkg in ["dctorch==0.1.2", "pymatting", "pooch", "rembg", "numba"]: + for pkg in ["dctorch==0.1.2", "pymatting", "pooch", "rembg", "numba", "kornia", "kornia-rs"]: install(pkg, no_deps=True, ignore=False) @@ -25,6 +25,7 @@ async def post_rembg( if input_image is None: return {} + dependencies() if model == "ben2": from modules.rembg import ben2 image = ben2.remove(input_image, refine=refine) @@ -32,7 +33,6 @@ async def post_rembg( from modules.rembg import lucida image = lucida.remove(input_image) else: - dependencies() import rembg image = rembg.remove( # pylint: disable=c-extension-no-member input_image, diff --git a/modules/rife/loss.py b/modules/rife/loss.py deleted file mode 100644 index f525ff443..000000000 --- a/modules/rife/loss.py +++ /dev/null @@ -1,121 +0,0 @@ -import numpy as np -import torch -import torch.nn as nn -import torch.nn.functional as F -import torchvision.models as models -from modules import devices - - -class EPE(nn.Module): - def __init__(self): - super().__init__() - - def forward(self, flow, gt, loss_mask): - loss_map = (flow - gt.detach()) ** 2 - loss_map = (loss_map.sum(1, True) + 1e-6) ** 0.5 - return loss_map * loss_mask - - -class Ternary(nn.Module): - def __init__(self): - super().__init__() - patch_size = 7 - out_channels = patch_size * patch_size - self.w = np.eye(out_channels).reshape( - (patch_size, patch_size, 1, out_channels)) - self.w = np.transpose(self.w, (3, 2, 0, 1)) - self.w = torch.tensor(self.w).float().to(devices.device) - - def transform(self, img): - patches = F.conv2d(img, self.w, padding=3, bias=None) - transf = patches - img - transf_norm = transf / torch.sqrt(0.81 + transf**2) - return transf_norm - - def rgb2gray(self, rgb): - r, g, b = rgb[:, 0:1, :, :], rgb[:, 1:2, :, :], rgb[:, 2:3, :, :] - gray = 0.2989 * r + 0.5870 * g + 0.1140 * b - return gray - - def hamming(self, t1, t2): - dist = (t1 - t2) ** 2 - dist_norm = torch.mean(dist / (0.1 + dist), 1, True) - return dist_norm - - def valid_mask(self, t, padding): - n, _, h, w = t.size() - inner = torch.ones(n, 1, h - 2 * padding, w - 2 * padding).type_as(t) - mask = F.pad(inner, [padding] * 4) - return mask - - def forward(self, img0, img1): - img0 = self.transform(self.rgb2gray(img0)) - img1 = self.transform(self.rgb2gray(img1)) - return self.hamming(img0, img1) * self.valid_mask(img0, 1) - - -class SOBEL(nn.Module): - def __init__(self): - super().__init__() - self.kernelX = torch.tensor([ - [1, 0, -1], - [2, 0, -2], - [1, 0, -1], - ]).float() - self.kernelY = self.kernelX.clone().T - self.kernelX = self.kernelX.unsqueeze(0).unsqueeze(0).to(devices.device) - self.kernelY = self.kernelY.unsqueeze(0).unsqueeze(0).to(devices.device) - - def forward(self, pred, gt): - N, C, H, W = pred.shape[0], pred.shape[1], pred.shape[2], pred.shape[3] - img_stack = torch.cat( - [pred.reshape(N*C, 1, H, W), gt.reshape(N*C, 1, H, W)], 0) - sobel_stack_x = F.conv2d(img_stack, self.kernelX, padding=1) - sobel_stack_y = F.conv2d(img_stack, self.kernelY, padding=1) - pred_X, gt_X = sobel_stack_x[:N*C], sobel_stack_x[N*C:] - pred_Y, gt_Y = sobel_stack_y[:N*C], sobel_stack_y[N*C:] - L1X, L1Y = torch.abs(pred_X-gt_X), torch.abs(pred_Y-gt_Y) - loss = L1X+L1Y - return loss - - -class MeanShift(nn.Conv2d): - def __init__(self, data_mean, data_std, data_range=1, norm=True): - c = len(data_mean) - super().__init__(c, c, kernel_size=1) - std = torch.Tensor(data_std) - self.weight.data = torch.eye(c).view(c, c, 1, 1) - if norm: - self.weight.data.div_(std.view(c, 1, 1, 1)) - self.bias.data = -1 * data_range * torch.Tensor(data_mean) - self.bias.data.div_(std) - else: - self.weight.data.mul_(std.view(c, 1, 1, 1)) - self.bias.data = data_range * torch.Tensor(data_mean) - self.requires_grad = False - - -class VGGPerceptualLoss(torch.nn.Module): - def __init__(self, rank=0): # pylint: disable=unused-argument - super().__init__() - pretrained = True - self.vgg_pretrained_features = models.vgg19( - pretrained=pretrained).features - self.normalize = MeanShift([0.485, 0.456, 0.406], [0.229, 0.224, 0.225], norm=True).to(device=devices.device) - for param in self.parameters(): - param.requires_grad = False - - def forward(self, X, Y, indices=None): - X = self.normalize(X) - Y = self.normalize(Y) - indices = [2, 7, 12, 21, 30] - weights = [1.0/2.6, 1.0/4.8, 1.0/3.7, 1.0/5.6, 10/1.5] - k = 0 - loss = 0 - for i in range(indices[-1]): - X = self.vgg_pretrained_features[i](X) - Y = self.vgg_pretrained_features[i](Y) - if i+1 in indices: - loss += weights[k] * (X - Y.detach()).abs().mean() * 0.1 - k += 1 - return loss diff --git a/modules/rife/refine.py b/modules/rife/refine.py deleted file mode 100644 index 9ea076d1f..000000000 --- a/modules/rife/refine.py +++ /dev/null @@ -1,90 +0,0 @@ -import torch -import torch.nn as nn -import torch.nn.functional as F -from modules.rife.warplayer import warp - - -c = 16 - - -def conv(in_planes, out_planes, kernel_size=3, stride=1, padding=1, dilation=1): - return nn.Sequential( - nn.Conv2d(in_planes, out_planes, kernel_size=kernel_size, stride=stride, padding=padding, dilation=dilation, bias=True), - nn.LeakyReLU(0.2, True) - ) - - -def conv_woact(in_planes, out_planes, kernel_size=3, stride=1, padding=1, dilation=1): - return nn.Sequential( - nn.Conv2d(in_planes, out_planes, kernel_size=kernel_size, stride=stride, padding=padding, dilation=dilation, bias=True), - ) - - -def deconv(in_planes, out_planes, kernel_size=4, stride=2, padding=1): # pylint: disable=unused-argument - return nn.Sequential( - torch.nn.ConvTranspose2d(in_channels=in_planes, out_channels=out_planes, kernel_size=4, stride=2, padding=1, bias=True), - nn.LeakyReLU(0.2, True) - ) - - -class Conv2(nn.Module): - def __init__(self, in_planes, out_planes, stride=2): - super().__init__() - self.conv1 = conv(in_planes, out_planes, 3, stride, 1) - self.conv2 = conv(out_planes, out_planes, 3, 1, 1) - - def forward(self, x): - x = self.conv1(x) - x = self.conv2(x) - return x - - -class Contextnet(nn.Module): - def __init__(self): - super().__init__() - self.conv1 = Conv2(3, c) - self.conv2 = Conv2(c, 2*c) - self.conv3 = Conv2(2*c, 4*c) - self.conv4 = Conv2(4*c, 8*c) - - def forward(self, x, flow): - x = self.conv1(x) - flow = F.interpolate(flow, scale_factor=0.5, mode="bilinear", align_corners=False) * 0.5 - f1 = warp(x, flow) - x = self.conv2(x) - flow = F.interpolate(flow, scale_factor=0.5, mode="bilinear", align_corners=False) * 0.5 - f2 = warp(x, flow) - x = self.conv3(x) - flow = F.interpolate(flow, scale_factor=0.5, mode="bilinear", align_corners=False) * 0.5 - f3 = warp(x, flow) - x = self.conv4(x) - flow = F.interpolate(flow, scale_factor=0.5, mode="bilinear", align_corners=False) * 0.5 - f4 = warp(x, flow) - return [f1, f2, f3, f4] - - -class Unet(nn.Module): - def __init__(self): - super().__init__() - self.down0 = Conv2(17, 2*c) - self.down1 = Conv2(4*c, 4*c) - self.down2 = Conv2(8*c, 8*c) - self.down3 = Conv2(16*c, 16*c) - self.up0 = deconv(32*c, 8*c) - self.up1 = deconv(16*c, 4*c) - self.up2 = deconv(8*c, 2*c) - self.up3 = deconv(4*c, c) - self.conv = nn.Conv2d(c, 3, 3, 1, 1) - - def forward(self, img0, img1, warped_img0, warped_img1, mask, flow, c0, c1): - s0 = self.down0( - torch.cat((img0, img1, warped_img0, warped_img1, mask, flow), 1)) - s1 = self.down1(torch.cat((s0, c0[0], c1[0]), 1)) - s2 = self.down2(torch.cat((s1, c0[1], c1[1]), 1)) - s3 = self.down3(torch.cat((s2, c0[2], c1[2]), 1)) - x = self.up0(torch.cat((s3, c0[3], c1[3]), 1)) - x = self.up1(torch.cat((x, s2), 1)) - x = self.up2(torch.cat((x, s1), 1)) - x = self.up3(torch.cat((x, s0), 1)) - x = self.conv(x) - return torch.sigmoid(x) diff --git a/modules/rocm.py b/modules/rocm.py index 8966cddbe..9a3299b4f 100644 --- a/modules/rocm.py +++ b/modules/rocm.py @@ -215,7 +215,7 @@ def get_version() -> str | None: return f'{arr[0]}.{arr[1]}' if len(arr) >= 2 else None elif isinstance(environment, PythonPackageEnvironment): # If rocm-sdk package is installed, the hip library may be used by PyTorch. - ver = ctypes.c_int() + ver = ctypes.c_int(0) environment.hip.hipRuntimeGetVersion(ctypes.byref(ver)) major = ver.value // 10000000 minor = (ver.value // 100000) % 100 diff --git a/modules/safe.py b/modules/safe.py index d97721bf6..89b14ee45 100644 --- a/modules/safe.py +++ b/modules/safe.py @@ -5,9 +5,9 @@ import collections import zipfile import re +import _codecs import torch import numpy as np -import _codecs # PyTorch 1.13 and later have _TypedStorage renamed to TypedStorage TypedStorage = torch.storage.TypedStorage if hasattr(torch.storage, 'TypedStorage') else torch.storage._TypedStorage # pylint: disable=protected-access diff --git a/modules/schedulers/scheduler_vdm.py b/modules/schedulers/scheduler_vdm.py index 8afc3ae80..6e27304e9 100644 --- a/modules/schedulers/scheduler_vdm.py +++ b/modules/schedulers/scheduler_vdm.py @@ -191,7 +191,7 @@ class VDMScheduler(SchedulerMixin, ConfigMixin): if self.config.timestep_spacing in ["linspace", "leading"]: timesteps = np.linspace(0, 1, num_steps, endpoint=self.config.timestep_spacing == "linspace")[::-1] elif self.config.timestep_spacing == "trailing": - timesteps = np.arange(1, 0, -1 / num_steps) - 1 / num_steps + timesteps = np.linspace(1, 0, num_steps, endpoint=False) else: raise ValueError( f"`{self.config.timestep_spacing}` timestep spacing is not supported." diff --git a/modules/scripts_manager.py b/modules/scripts_manager.py index f66d4516a..8598fd839 100644 --- a/modules/scripts_manager.py +++ b/modules/scripts_manager.py @@ -743,15 +743,19 @@ class ScriptRunner: def postprocess(self, p: StableDiffusionProcessing, processed): s = ScriptSummary('postprocess') + _processed = processed for script in self.alwayson_scripts: try: args = resolve_script_args(script, p.script_args, p.per_script_args) if args is not None: - script.postprocess(p, processed, *args) + result = script.postprocess(p, _processed, *args) + if result is not None: # allow postprocessing script to optionally modify results + _processed = result except Exception as e: errors.display(e, f'Running script postprocess: {script.filename}') s.record(script.title()) s.report() + return _processed def postprocess_batch(self, p: StableDiffusionProcessing, images, **kwargs): s = ScriptSummary('postprocess-batch') diff --git a/modules/sd_checkpoint.py b/modules/sd_checkpoint.py index 1b961e5f9..9831befd2 100644 --- a/modules/sd_checkpoint.py +++ b/modules/sd_checkpoint.py @@ -27,11 +27,11 @@ warn_once = False class CheckpointInfo: def __init__(self, filename: str, name: str | None = None, sha: str | None = None, subfolder: str | None = None, model_type: str = 'checkpoint', folder: str | None = None): - self.name = name - self.hash = sha - self.filename = filename if filename is not None else 'none' - self.type = '' - self.subfolder = subfolder + self.filename: str = filename if filename is not None else 'none' + self.name: str = name if name is not None else '' + self.hash: str | None = sha + self.type: str = '' + self.subfolder: str | None = subfolder relname = self.filename app_path = os.path.abspath(paths.script_path) @@ -122,7 +122,7 @@ def setup_model(): # sd_hijack_accelerate.hijack_torch_conv() -def checkpoint_titles(use_short=False): +def checkpoint_titles(use_short=False) -> list[str]: def convert(name): return int(name) if name.isdigit() else name.lower() diff --git a/modules/sd_detect.py b/modules/sd_detect.py index bf3327be1..a133c8e21 100644 --- a/modules/sd_detect.py +++ b/modules/sd_detect.py @@ -167,6 +167,8 @@ def guess_by_name(fn, current_guess): new_guess = 'OvisImage' elif 'glm-image' in fn.lower(): new_guess = 'GLMImage' + elif 'llada' in fn.lower(): + new_guess = 'LLaDAImage' elif 'sdxs-1b' in fn.lower(): new_guess = 'SDXS' elif 'step1x-edit' in fn.lower(): diff --git a/modules/sd_hijack_accelerate.py b/modules/sd_hijack_accelerate.py index f7e625543..6ffd83e91 100644 --- a/modules/sd_hijack_accelerate.py +++ b/modules/sd_hijack_accelerate.py @@ -60,8 +60,10 @@ def torch_conv_forward(self, input, weight, bias): # pylint: disable=redefined-b bias = bias.to(weight.dtype) return F.conv2d(input, weight, bias, self.stride, self.padding, self.dilation, self.groups) + def hijack_torch_conv(): torch.nn.modules.conv.Conv2d._conv_forward = torch_conv_forward # pylint: disable=protected-access + def restore_torch_conv(): torch.nn.modules.conv.Conv2d._conv_forward = orig_torch_conv # pylint: disable=protected-access diff --git a/modules/sd_hijack_dynamic_atten.py b/modules/sd_hijack_dynamic_atten.py index 0c0c4771d..cf932496d 100644 --- a/modules/sd_hijack_dynamic_atten.py +++ b/modules/sd_hijack_dynamic_atten.py @@ -113,160 +113,3 @@ def dynamic_scaled_dot_product_attention(query: torch.FloatTensor, key: torch.Fl if is_unsqueezed: hidden_states = hidden_states.squeeze(0) return hidden_states - - -@cache -def find_bmm_slice_sizes(query_shape, query_element_size, slice_rate=2, trigger_rate=4): - if len(query_shape) == 3: - batch_size_attention, query_tokens, shape_three = query_shape - shape_four = 1 - else: - batch_size_attention, query_tokens, shape_three, shape_four = query_shape - - slice_block_size = query_tokens * shape_three * shape_four / 1024 / 1024 * query_element_size - block_size = batch_size_attention * slice_block_size - - split_slice_size = batch_size_attention - split_2_slice_size = query_tokens - split_3_slice_size = shape_three - - do_split = False - do_split_2 = False - do_split_3 = False - - if block_size > trigger_rate: - do_split = True - split_slice_size = find_split_size(split_slice_size, slice_block_size, slice_rate=slice_rate) - if split_slice_size * slice_block_size > slice_rate: - slice_2_block_size = split_slice_size * shape_three * shape_four / 1024 / 1024 * query_element_size - do_split_2 = True - split_2_slice_size = find_split_size(split_2_slice_size, slice_2_block_size, slice_rate=slice_rate) - if split_2_slice_size * slice_2_block_size > slice_rate: - slice_3_block_size = split_slice_size * split_2_slice_size * shape_four / 1024 / 1024 * query_element_size - do_split_3 = True - split_3_slice_size = find_split_size(split_3_slice_size, slice_3_block_size, slice_rate=slice_rate) - - return do_split, do_split_2, do_split_3, split_slice_size, split_2_slice_size, split_3_slice_size - - -class DynamicAttnProcessorBMM: - r""" - dynamically slices attention queries in order to keep them under the slice rate - slicing will not get triggered if the query size is smaller than the slice rate to gain performance - - slice rate is in GB - based on AttnProcessor V1 - """ - - def __call__(self, attn, hidden_states: torch.Tensor, encoder_hidden_states=None, attention_mask=None, temb=None, *args, **kwargs) -> torch.Tensor: # pylint: disable=too-many-statements, too-many-locals, too-many-branches, keyword-arg-before-vararg - - residual = hidden_states - - if attn.spatial_norm is not None: - hidden_states = attn.spatial_norm(hidden_states, temb) - - input_ndim = hidden_states.ndim - - if input_ndim == 4: - batch_size, channel, height, width = hidden_states.shape - hidden_states = hidden_states.view(batch_size, channel, height * width).transpose(1, 2) - - batch_size, sequence_length, _ = ( - hidden_states.shape if encoder_hidden_states is None else encoder_hidden_states.shape - ) - attention_mask = attn.prepare_attention_mask(attention_mask, sequence_length, batch_size) - - if attn.group_norm is not None: - hidden_states = attn.group_norm(hidden_states.transpose(1, 2)).transpose(1, 2) - - query = attn.to_q(hidden_states) - - if encoder_hidden_states is None: - encoder_hidden_states = hidden_states - elif attn.norm_cross: - encoder_hidden_states = attn.norm_encoder_hidden_states(encoder_hidden_states) - - key = attn.to_k(encoder_hidden_states) - value = attn.to_v(encoder_hidden_states) - - query = attn.head_to_batch_dim(query) - key = attn.head_to_batch_dim(key) - value = attn.head_to_batch_dim(value) - - #################################################################### - # Slicing parts: - batch_size_attention, query_tokens, shape_three = query.shape[0], query.shape[1], query.shape[2] - hidden_states = torch.zeros(query.shape, device=query.device, dtype=query.dtype) - do_split, do_split_2, do_split_3, split_slice_size, split_2_slice_size, split_3_slice_size = find_bmm_slice_sizes(query.shape, query.element_size(), slice_rate=shared.opts.dynamic_attention_slice_rate*4, trigger_rate=shared.opts.dynamic_attention_trigger_rate*4) - - if do_split: - for i in range(batch_size_attention // split_slice_size): - start_idx = i * split_slice_size - end_idx = (i + 1) * split_slice_size - if do_split_2: - for i2 in range(query_tokens // split_2_slice_size): # pylint: disable=invalid-name - start_idx_2 = i2 * split_2_slice_size - end_idx_2 = (i2 + 1) * split_2_slice_size - if do_split_3: - for i3 in range(shape_three // split_3_slice_size): # pylint: disable=invalid-name - start_idx_3 = i3 * split_3_slice_size - end_idx_3 = (i3 + 1) * split_3_slice_size - - query_slice = query[start_idx:end_idx, start_idx_2:end_idx_2, start_idx_3:end_idx_3] - key_slice = key[start_idx:end_idx, start_idx_2:end_idx_2, start_idx_3:end_idx_3] - attn_mask_slice = attention_mask[start_idx:end_idx, start_idx_2:end_idx_2, start_idx_3:end_idx_3] if attention_mask is not None else None - - attn_slice = attn.get_attention_scores(query_slice, key_slice, attn_mask_slice) - del query_slice - del key_slice - del attn_mask_slice - attn_slice = torch.bmm(attn_slice, value[start_idx:end_idx, start_idx_2:end_idx_2, start_idx_3:end_idx_3]) - - hidden_states[start_idx:end_idx, start_idx_2:end_idx_2, start_idx_3:end_idx_3] = attn_slice - del attn_slice - else: - query_slice = query[start_idx:end_idx, start_idx_2:end_idx_2] - key_slice = key[start_idx:end_idx, start_idx_2:end_idx_2] - attn_mask_slice = attention_mask[start_idx:end_idx, start_idx_2:end_idx_2] if attention_mask is not None else None - - attn_slice = attn.get_attention_scores(query_slice, key_slice, attn_mask_slice) - del query_slice - del key_slice - del attn_mask_slice - attn_slice = torch.bmm(attn_slice, value[start_idx:end_idx, start_idx_2:end_idx_2]) - - hidden_states[start_idx:end_idx, start_idx_2:end_idx_2] = attn_slice - del attn_slice - else: - query_slice = query[start_idx:end_idx] - key_slice = key[start_idx:end_idx] - attn_mask_slice = attention_mask[start_idx:end_idx] if attention_mask is not None else None - - attn_slice = attn.get_attention_scores(query_slice, key_slice, attn_mask_slice) - del query_slice - del key_slice - del attn_mask_slice - attn_slice = torch.bmm(attn_slice, value[start_idx:end_idx]) - - hidden_states[start_idx:end_idx] = attn_slice - del attn_slice - else: - attention_probs = attn.get_attention_scores(query, key, attention_mask) - hidden_states = torch.bmm(attention_probs, value) - #################################################################### - hidden_states = attn.batch_to_head_dim(hidden_states) - - # linear proj - hidden_states = attn.to_out[0](hidden_states) - # dropout - hidden_states = attn.to_out[1](hidden_states) - - if input_ndim == 4: - hidden_states = hidden_states.transpose(-1, -2).reshape(batch_size, channel, height, width) - - if attn.residual_connection: - hidden_states = hidden_states + residual - - hidden_states = hidden_states / attn.rescale_output_factor - - return hidden_states diff --git a/modules/sd_hijack_hypertile.py b/modules/sd_hijack_hypertile.py index eead36266..0cfe4e220 100644 --- a/modules/sd_hijack_hypertile.py +++ b/modules/sd_hijack_hypertile.py @@ -186,12 +186,8 @@ def context_hypertile_vae(p): from modules import shared if shared.sd_model is None or not get_opt(p, 'hypertile_vae_enabled'): return nullcontext() - if shared.opts.cross_attention_optimization == 'Sub-quadratic': - log.warning('Hypertile UNet is not compatible with Sub-quadratic cross-attention optimization') - return nullcontext() global max_h, max_w, error_reported # pylint: disable=global-statement error_reported = False - error_reported = False set_resolution(p) max_h, max_w = 0, 0 vae = getattr(shared.sd_model, "vae", None) @@ -217,9 +213,6 @@ def context_hypertile_unet(p): from modules import shared if shared.sd_model is None or not get_opt(p, 'hypertile_unet_enabled'): return nullcontext() - if shared.opts.cross_attention_optimization == 'Sub-quadratic' and not shared.cmd_opts.experimental: - log.warning('Hypertile UNet is not compatible with Sub-quadratic cross-attention optimization') - return nullcontext() global max_h, max_w, error_reported # pylint: disable=global-statement error_reported = False set_resolution(p) diff --git a/modules/sd_hijack_modular.py b/modules/sd_hijack_modular.py new file mode 100644 index 000000000..59651deab --- /dev/null +++ b/modules/sd_hijack_modular.py @@ -0,0 +1,197 @@ +import os +import time +import logging +import torch +import diffusers +from modules.logger import log +from modules import shared, sd_offload, timer +from modules.processing_callbacks import torch_sync +from modules.attention import context as attention_context +from modules.lora import lora_stack + + +debug = os.environ.get('SD_MODULAR_DEBUG', None) is not None +intercepted = set() + + +def modular_step(components: diffusers.modular_pipelines.ModularPipeline, state: diffusers.modular_pipelines.BlockState): + keys = state if isinstance(state, list) else list(state.__dict__.keys()) + if 'num_inference_steps' in keys: + shared.state.sampling_steps = state.num_inference_steps + if 'latents' in keys and state.latents.ndim > 1: + torch_sync() + shared.state.step() + if hasattr(components, 'custom_unpack_latents'): + shared.state.current_latent = components.custom_unpack_latents(state.latents, components, state) + else: + shared.state.current_latent = state.latents + lora_stack.on_step(shared.state.sampling_step) + if debug: + log.trace(f'Modular step: step={shared.state.sampling_step} latent={list(state.latents.shape)}') + if shared.state.interrupted or shared.state.skipped: + raise AssertionError('Interrupted...') + if shared.state.paused: + log.debug('Sampling paused') + while shared.state.paused: + if shared.state.interrupted or shared.state.skipped: + raise AssertionError('Interrupted...') + time.sleep(0.1) + + +def modular_intercept(self, components, state: diffusers.modular_pipelines.modular_pipeline.BlockState, *args, **kwargs): + if shared.state.interrupted or shared.state.skipped: + raise AssertionError('Interrupted...') + t0 = time.time() + block = type(self).__name__ + # run code before block call + result = self.__orig_call__(components, state, *args, **kwargs) + t1 = time.time() + timer.blocks.add(block, t1 - t0) + # run code after block call + if 'LoopDenoiser' in block: # BeforeDenoiser/AfterDenoiser are not used by all pipelines + modular_step(components, state) + t2 = time.time() + timer.blocks.add('callback', t2 - t1) + if debug: + keys = state if isinstance(state, list) else list(state.__dict__.keys()) + log.trace(f'Modular intercept: block={block} keys={keys} time={t1 - t0:.4f}') + return result + + +def patch_blocks(blocks: diffusers.ModularPipelineBlocks): + """recursively walks the block tree and patches the CLS __call__ method""" + def _patch_recursive(current_block): + block_cls = type(current_block) + if (block_cls not in intercepted) and (block_cls != diffusers.ModularPipelineBlocks): + if callable(block_cls) and not getattr(block_cls, "_is_patched", False): + block_cls.__orig_call__ = block_cls.__call__ # store original call for reference + block_cls.__call__ = modular_intercept + block_cls._is_patched = True # pylint: disable=protected-access + intercepted.add(block_cls) + if debug: + log.trace(f'Modular hijack: block={block_cls.__name__}') + for attr in ("sub_blocks", "blocks"): # recurse into child blocks if containers exist + sub = getattr(current_block, attr, None) + if isinstance(sub, dict): + for child in sub.values(): + if isinstance(child, diffusers.ModularPipelineBlocks): + _patch_recursive(child) + elif isinstance(sub, (list, tuple)): + for child in sub: + if isinstance(child, diffusers.ModularPipelineBlocks): + _patch_recursive(child) + + _patch_recursive(blocks) + + +def register_callbacks(pipe: diffusers.ModularPipeline): + intercepted.clear() + if not isinstance(pipe, diffusers.ModularPipeline): + return + try: + patch_blocks(pipe._blocks) # pylint: disable=protected-access + except Exception as e: + log.error(f'Modular intercept: {e}') + + +class InterruptLogFilter(logging.Filter): + """Drops the per-block error dumps the modular runner logs when an interrupt raises through it.""" + def filter(self, record): + filtered = 'Interrupted...' in record.msg + if not debug: + filtered = filtered or ('Error in block:' in record.msg) + return not filtered + + +def publish_layout(kwargs): + """Hand the attention router whatever the pipeline says about its packed sequence, keyed on the *_indices tensors rather than the model.""" + try: + from modules.attention.sparse import layout as sparse_layout + attention_context.set_layout(sparse_layout.layout_from_index_kwargs(kwargs or {})) + except Exception as e: + log.debug(f'Pipeline: token layout {e}') + + +def install_state_hook(pipe): + runner_log = logging.getLogger('diffusers.modular_pipelines.modular_pipeline') + if not any(isinstance(f, InterruptLogFilter) for f in runner_log.filters): + runner_log.addFilter(InterruptLogFilter()) + + def set_phase(phase: str, module: torch.nn.Module | None = None): + # every stage runs inside one pipeline call, so the forward hooks are the only place the current stage is visible + if shared.state.interrupted or shared.state.skipped: + raise AssertionError('Interrupted...') + if getattr(pipe, 'sdnext_phase', None) != phase: + pipe.sdnext_phase = phase + jobid = getattr(pipe, 'sdnext_phaseid', None) # previous jobid if any + shared.state.end(jobid) # clear the previous job if exists + pipe.sdnext_phaseid = shared.state.begin(phase) # start a new job for the current phase + log.debug(f'Pipeline: phase={phase.replace(" ", "")} cls={pipe.__class__.__name__} module={module.__class__.__name__ if module is not None else None}') + return True + return False + + def _pre_transformer_hook(module, args, kwargs): # pylint: disable=unused-argument + new_phase = set_phase('Generate', module) + attention_context.set_role('transformer') + publish_layout(kwargs) + if new_phase: + sd_offload.offload_ondemand(pipe, exclude=['transformer', 'transformer_ref', 'unet'], reason='generate', force=hasattr(pipe, 'sdnext_force_offload')) + if shared.state.sampling_steps == 0 and getattr(pipe, 'num_timesteps', 0) > 0: + shared.state.sampling_steps = pipe.num_timesteps + if shared.state.paused: + log.debug('Sampling paused') + while shared.state.paused: + if shared.state.interrupted or shared.state.skipped: + raise AssertionError('Interrupted...') + time.sleep(0.1) + # shared.state.step() + attention_context.tick() + if shared.state.interrupted or shared.state.skipped: + raise AssertionError('Interrupted...') + + def _pre_text_encode_hook(module, args): # pylint: disable=unused-argument + new_phase = set_phase('Text Encode', module) + attention_context.set_role('te') + if new_phase: + sd_offload.offload_ondemand(pipe, exclude=['text_encoder'], reason='text encode', force=hasattr(pipe, 'sdnext_force_offload')) + if shared.state.interrupted or shared.state.skipped: + raise AssertionError('Interrupted...') + + def _pre_vae_decode_hook(module, args): # pylint: disable=unused-argument + new_phase = set_phase('Decode', module) + attention_context.set_role('vae') + if new_phase: + sd_offload.offload_ondemand(pipe, exclude=['vae', 'audio_vae'], reason='vae decode', force=hasattr(pipe, 'sdnext_force_offload')) + if shared.state.interrupted or shared.state.skipped: # fires per tile, so tiled decodes abort promptly + raise AssertionError('Interrupted...') + + def _pre_vae_encode_hook(module, args): # pylint: disable=unused-argument + new_phase = set_phase('Encode', module) + attention_context.set_role('vae') + if new_phase: + sd_offload.offload_ondemand(pipe, exclude=['vae', 'audio_vae'], reason='vae encode', force=hasattr(pipe, 'sdnext_force_offload')) + if shared.state.interrupted or shared.state.skipped: # fires per tile, so tiled encodes abort promptly + raise AssertionError('Interrupted...') + + for name in ('unet', 'transformer', 'transformer_2', 'transformer_ref'): + module = getattr(pipe, name, None) + if module is not None: + target = getattr(module, 'model', module) # conditioning calls the inner model directly + if isinstance(target, torch.nn.Module) and getattr(target, 'sdnext_state_hook', None) is None: + # with_kwargs, because the blocks call the transformer entirely by keyword and the token layout rides in those kwargs + target.sdnext_state_hook = target.register_forward_pre_hook(_pre_transformer_hook, with_kwargs=True) + + for name in ('text_encoder', 'text_encoder_2'): + module = getattr(pipe, name, None) + if module is not None: + target = getattr(module, 'model', module) # conditioning calls the inner model directly + if isinstance(target, torch.nn.Module) and getattr(target, 'sdnext_state_hook', None) is None: + target.sdnext_state_hook = target.register_forward_pre_hook(_pre_text_encode_hook) + + for name in ('vae', 'audio_vae'): + decoder = getattr(getattr(pipe, name, None), 'decoder', None) # decode entry points bypass forward, the inner decoder does not + if isinstance(decoder, torch.nn.Module) and getattr(decoder, 'sdnext_state_hook', None) is None: + decoder.sdnext_state_hook = decoder.register_forward_pre_hook(_pre_vae_decode_hook) + encoder = getattr(getattr(pipe, name, None), 'encoder', None) # decode entry points bypass forward, the inner encoder does not + if isinstance(encoder, torch.nn.Module) and getattr(encoder, 'sdnext_state_hook', None) is None: + encoder.sdnext_state_hook = encoder.register_forward_pre_hook(_pre_vae_encode_hook) diff --git a/modules/sd_hijack_te.py b/modules/sd_hijack_te.py index 0e9111c09..1732db1e7 100644 --- a/modules/sd_hijack_te.py +++ b/modules/sd_hijack_te.py @@ -2,6 +2,7 @@ import os import time from modules import shared, errors, timer, sd_models from modules.logger import log +from modules.attention import context as attention_context class PromptCache: @@ -10,29 +11,41 @@ class PromptCache: self.id = None self.max = 16 - def get(self, prompt): - if self.id != id(shared.sd_model): + @staticmethod + def _hashable(val): + if isinstance(val, list): + return tuple(val) + return val + + def get(self, prompt, negative_prompt=None, cfg_enabled=None): + current_id = id(shared.sd_model.sd_checkpoint_info) if hasattr(shared.sd_model, 'sd_checkpoint_info') else id(shared.sd_model) + if self.id != current_id: self.cache.clear() - self.id = id(shared.sd_model) + self.id = current_id log.debug(f'Encode: prompt cache activate id={self.id} depth={len(self.cache)}') + negative_prompt = self._hashable(negative_prompt) if (isinstance(prompt, list) and len(prompt) == 1 and isinstance(prompt[0], str)): - cached = self.cache.get(prompt[0], None) + cached = self.cache.get((prompt[0], negative_prompt, cfg_enabled), None) elif isinstance(prompt, str): - cached = self.cache.get(prompt, None) + cached = self.cache.get((prompt, negative_prompt, cfg_enabled), None) else: cached = None if cached: - log.debug(f'Encode: prompt="{prompt}" cache={len(self.cache)} hit') + if isinstance(prompt, list): + log.debug(f'Encode: prompt={prompt} cache={len(self.cache)} hit') + else: + log.debug(f'Encode: prompt="{prompt}" cache={len(self.cache)} hit') return cached - def set(self, prompt, encoded): + def set(self, prompt, encoded, negative_prompt=None, cfg_enabled=None): if len(self.cache) >= self.max: oldest_key = next(iter(self.cache)) del self.cache[oldest_key] + negative_prompt = self._hashable(negative_prompt) if (isinstance(prompt, list) and len(prompt) == 1 and isinstance(prompt[0], str)): - self.cache[prompt[0]] = encoded + self.cache[(prompt[0], negative_prompt, cfg_enabled)] = encoded elif isinstance(prompt, str): - self.cache[prompt] = encoded + self.cache[(prompt, negative_prompt, cfg_enabled)] = encoded prompt_cache = PromptCache() @@ -55,24 +68,31 @@ def hijack_encode_prompt(*args, **kwargs): res = prompt if hasattr(shared.sd_model, 'before_prompt_encode'): - log.debug(f'Encode: prompt="{prompt}" op=before') + log.debug('Encode: op=before') res = shared.sd_model.before_prompt_encode(prompt) if patch_prompt: args_copy[0] = res - cached = prompt_cache.get(prompt) + # cache key must include cfg-affecting kwargs since encode_prompt output (e.g. negative_prompt_embeds) depends on them + negative_prompt = kwargs.get('negative_prompt', None) + cfg_enabled = kwargs.get('do_classifier_free_guidance', None) + cached = prompt_cache.get(prompt, negative_prompt, cfg_enabled) if cached is not None: res = cached else: - log.debug(f'Encode: prompt="{prompt}" hijack=True') - if hasattr(shared.sd_model, 'orig_encode_prompt'): - res = shared.sd_model.orig_encode_prompt(*args_copy, **kwargs) + if isinstance(prompt, list): + log.debug(f'Encode: prompt={prompt} hijack=True') else: - res = shared.sd_model.encode_prompt(*args_copy, **kwargs) - prompt_cache.set(prompt, res) + log.debug(f'Encode: prompt="{prompt}" hijack=True') + with attention_context.role('te'): + if hasattr(shared.sd_model, 'orig_encode_prompt'): + res = shared.sd_model.orig_encode_prompt(*args_copy, **kwargs) + else: + res = shared.sd_model.encode_prompt(*args_copy, **kwargs) + prompt_cache.set(prompt, res, negative_prompt, cfg_enabled) if hasattr(shared.sd_model, 'after_prompt_encode'): - log.debug(f'Encode: prompt="{prompt}" op=after') + log.debug('Encode: op=after') res = shared.sd_model.after_prompt_encode(res) except Exception as e: diff --git a/modules/sd_hijack_triton.py b/modules/sd_hijack_triton.py index 28bb6530a..cdd66f8c7 100644 --- a/modules/sd_hijack_triton.py +++ b/modules/sd_hijack_triton.py @@ -1,3 +1,4 @@ +import os import time import math from typing import Any @@ -155,6 +156,7 @@ def run_hook(orig): """Report the register use of the config a sweep just chose. n_regs and n_spills are filled in when the driver loads the binary, so they exist only once the kernel has run, not at compile.""" def wrapped(self, *args, **kwargs): + from modules import shared session = status['session'] if session is not None: stop_progress(session) @@ -171,6 +173,10 @@ def run_hook(orig): if hasattr(arg, 'dtype'): key += (str(arg.dtype),) needs_benchmark = len(self.configs) > 1 and key not in self.cache + skip_autotune = (os.environ.get('SD_SKIP_AUTOTUNE', None) is not None) or shared.opts.triton_skip_autotune + if needs_benchmark and skip_autotune: + self.cache[key] = self.configs[0] # pre-seed the cache so orig() takes its cache-hit path and skips the sweep + needs_benchmark = False if needs_benchmark: try: total = len(self.prune_configs(kwargs)) diff --git a/modules/sd_hijack_vae.py b/modules/sd_hijack_vae.py index cc6b83919..990495782 100644 --- a/modules/sd_hijack_vae.py +++ b/modules/sd_hijack_vae.py @@ -3,6 +3,7 @@ import time import torch from modules import shared, sd_models, devices, timer, errors from modules.logger import log +from modules.attention import context as attention_context debug = log.trace if os.environ.get('SD_VIDEO_DEBUG', None) is not None else lambda *args, **kwargs: None @@ -25,20 +26,22 @@ def hijack_vae_decode(*args, **kwargs): sd_models.move_model(shared.sd_model.vae, devices.device) if torch.is_tensor(args[0]): latents = args[0].to(device=devices.device, dtype=shared.sd_model.vae.dtype) # upcast to vae dtype - if hasattr(shared.sd_model.vae, '_asymmetric_upscale_vae'): - res = hijack_vae_upscale(latents, *args[1:], **kwargs) - elif getattr(shared.sd_model, 'sdnext_vae_type', None) == 'Tiny': - from modules.video_models import video_vae - res = video_vae.vae_decode_tiny(latents) # None when the model has no tiny counterpart, and it says so - if res is None: - res = shared.sd_model.vae.orig_decode(latents, *args[1:], **kwargs) + with attention_context.role('vae'): + if hasattr(shared.sd_model.vae, '_asymmetric_upscale_vae'): + res = hijack_vae_upscale(latents, *args[1:], **kwargs) + elif getattr(shared.sd_model, 'sdnext_vae_type', None) == 'Tiny': + from modules.video_models import video_vae + res = video_vae.vae_decode_tiny(latents) # None when the model has no tiny counterpart, and it says so + if res is None: + res = shared.sd_model.vae.orig_decode(latents, *args[1:], **kwargs) t1 = time.time() try: log.debug(f'Decode: vae={shared.sd_model.vae.__class__.__name__} dtype={latents.dtype} latents={list(latents.shape)}:{latents.device} decoded={list(res[0].shape)} slicing={getattr(shared.sd_model.vae, "use_slicing", None)} tiling={getattr(shared.sd_model.vae, "use_tiling", None)} time={t1-t0:.3f}') except Exception: pass else: - res = shared.sd_model.vae.orig_decode(*args, **kwargs) + with attention_context.role('vae'): + res = shared.sd_model.vae.orig_decode(*args, **kwargs) except Exception as e: log.error(f'Decode: vae={shared.sd_model.vae.__class__.__name__} {e}') errors.display(e, 'vae') @@ -58,11 +61,13 @@ def hijack_vae_encode(*args, **kwargs): sd_models.move_model(shared.sd_model.vae, devices.device) if torch.is_tensor(args[0]): latents = args[0].to(device=devices.device, dtype=shared.sd_model.vae.dtype) # upcast to vae dtype - res = shared.sd_model.vae.orig_encode(latents, *args[1:], **kwargs) + with attention_context.role('vae'): + res = shared.sd_model.vae.orig_encode(latents, *args[1:], **kwargs) t1 = time.time() log.debug(f'Encode: vae={shared.sd_model.vae.__class__.__name__} slicing={getattr(shared.sd_model.vae, "use_slicing", None)} tiling={getattr(shared.sd_model.vae, "use_tiling", None)} latents={list(latents.shape)}:{latents.device}:{latents.dtype} time={t1-t0:.3f}') else: - res = shared.sd_model.vae.orig_encode(*args, **kwargs) + with attention_context.role('vae'): + res = shared.sd_model.vae.orig_encode(*args, **kwargs) except Exception as e: log.error(f'Encode: vae={shared.sd_model.vae.__class__.__name__} {e}') errors.display(e, 'vae') diff --git a/modules/sd_models.py b/modules/sd_models.py index a21877dc8..5e06d03fd 100644 --- a/modules/sd_models.py +++ b/modules/sd_models.py @@ -55,6 +55,7 @@ pipe_switch_task_exclude = [ 'Kandinsky5I2IPipeline', 'GoogleNanoBananaPipeline', 'Step1XEditPipeline', + 'LLaDAImagePipeline', 'BooguImagePipeline', 'BooguImageTurboPipeline', ] @@ -610,6 +611,10 @@ def load_diffuser_force(detected_model_type: str, checkpoint_info: CheckpointInf from pipelines.model_glm import load_glm_image sd_model = load_glm_image(checkpoint_info, diffusers_load_config) allow_post_quant = False + elif model_type in ['LLaDAImage']: + from pipelines.model_llada import load_llada_image + sd_model = load_llada_image(checkpoint_info, diffusers_load_config) + allow_post_quant = False elif model_type in ['SDXS']: from pipelines.model_sdxs import load_sdxs sd_model = load_sdxs(checkpoint_info, diffusers_load_config) @@ -1034,6 +1039,12 @@ def load_diffuser(checkpoint_info: CheckpointInfo | None = None, op='model', rev if debug_load: log.trace(f'Model components: {list(get_signature(sd_model).values())}') + from modules import modular + if modular.is_compatible(shared.sd_model): + modular_pipe = modular.convert_to_modular(shared.sd_model) + if modular_pipe is not None: + shared.sd_model = modular_pipe + from modules import textual_inversion sd_model.embedding_db = textual_inversion.EmbeddingDatabase() sd_model.embedding_db.add_embedding_dir(shared.opts.embeddings_dir) @@ -1064,6 +1075,8 @@ def load_diffuser(checkpoint_info: CheckpointInfo | None = None, op='model', rev try: if shared.opts.ipex_optimize: sd_model = sd_models_compile.ipex_optimize(sd_model) + if shared.cmd_opts.use_openvino or devices.backend == 'openvino': + sd_models_compile.set_openvino_overrides() if (shared.opts.cuda_compile_backend != 'none') and len(shared.opts.cuda_compile) > 0: if 'components' in shared.opts.cuda_compile_options: @@ -1134,6 +1147,17 @@ def get_diffusers_task(pipe: diffusers.DiffusionPipeline) -> DiffusersTaskType: return DiffusersTaskType.TEXT_2_IMAGE +def pipe_serves_task(pipe: diffusers.DiffusionPipeline, task_type: DiffusersTaskType) -> bool: + """True when the pipeline class is registered for the task in the diffusers auto-pipeline tables.""" + mappings = { + DiffusersTaskType.TEXT_2_IMAGE: diffusers.pipelines.auto_pipeline.AUTO_TEXT2IMAGE_PIPELINES_MAPPING, + DiffusersTaskType.IMAGE_2_IMAGE: diffusers.pipelines.auto_pipeline.AUTO_IMAGE2IMAGE_PIPELINES_MAPPING, + DiffusersTaskType.INPAINTING: diffusers.pipelines.auto_pipeline.AUTO_INPAINT_PIPELINES_MAPPING, + } + mapping = mappings.get(task_type) + return mapping is not None and pipe.__class__ in mapping.values() + + def switch_pipe(cls: type[diffusers.DiffusionPipeline] | str, pipeline: diffusers.DiffusionPipeline | None = None, force = False, args: dict | None = None): """ args: @@ -1244,7 +1268,7 @@ def switch_pipe(cls: type[diffusers.DiffusionPipeline] | str, pipeline: diffuser def clean_diffuser_pipe(pipe): - if pipe is not None and shared.sd_model_type == 'sdxl' and hasattr(pipe, 'config') and 'requires_aesthetics_score' in pipe.config and hasattr(pipe, '_internal_dict'): + if (pipe is not None) and (shared.sd_model_type == 'sdxl') and hasattr(pipe, 'config') and ('requires_aesthetics_score' in pipe.config) and hasattr(pipe, '_internal_dict'): debug_process(f'Pipeline clean: {pipe.__class__.__name__}') # diffusers adds requires_aesthetics_score with img2img and complains if requires_aesthetics_score exist in txt2img internal_dict = dict(pipe._internal_dict) # pylint: disable=protected-access @@ -1341,6 +1365,8 @@ def set_diffuser_pipe(pipe, new_pipe_type): return pipe if get_diffusers_task(pipe) == new_pipe_type: return pipe + if pipe_serves_task(pipe, new_pipe_type): # a class registered for several tasks classifies as one of them + return pipe if get_diffusers_task(pipe) == DiffusersTaskType.MODULAR: return pipe @@ -1552,7 +1578,6 @@ def reload_model_weights(sd_model=None, info: CheckpointInfo | None = None, op=' unload_model_weights(op=op) sd_model = None timer.load = timer.Timer() - # TODO model load: implement model in-memory caching timer.load.record("config") if sd_model is None or force: sd_model = None @@ -1591,6 +1616,7 @@ def unload_model_weights(op='model'): shared.compiled_model_state.compiled_cache.clear() shared.compiled_model_state.req_cache.clear() shared.compiled_model_state.partitioned_modules.clear() + # shared.compiled_model_state = None if (op == 'model' or op == 'dict') and model_data.sd_model: log.debug(f'Current {op}: {memory_stats()}') if not ('Model' in shared.opts.cuda_compile and (shared.opts.cuda_compile_backend == "openvino_fx" or shared.opts.cuda_compile_backend == "openvino")): diff --git a/modules/sd_models_compile.py b/modules/sd_models_compile.py index a6c4acf54..594b77449 100644 --- a/modules/sd_models_compile.py +++ b/modules/sd_models_compile.py @@ -8,10 +8,11 @@ from installer import setup_logging debug = os.environ.get('SD_COMPILE_DEBUG', None) is not None debug_log = log.trace if debug else lambda *args, **kwargs: None +deepcache_worker = None +log_once = False -#Used by OpenVINO, can be used with TensorRT or Olive -class CompiledModelState: +class CompiledModelState: # Used by OpenVINO, can be used with TensorRT or Olive def __init__(self): self.is_compiled = False self.model_hash_str = "" @@ -29,9 +30,6 @@ class CompiledModelState: self.partitioned_modules = {} -deepcache_worker = None - - def ipex_optimize(sd_model, apply_to_components=True, op="Model"): try: t0 = time.time() @@ -205,19 +203,25 @@ def compile_stablefast(sd_model): def compile_torch(sd_model, apply_to_components=True, op="Model"): try: - t0 = time.time() + global log_once # pylint: disable=global-statement + t0 = time.perf_counter() import torch._dynamo # pylint: disable=unused-import,redefined-outer-name torch._dynamo.reset() # pylint: disable=protected-access - log.debug(f"{op} compile: task=torch available={torch._dynamo.list_backends()}") # pylint: disable=protected-access is_repeated = hasattr(sd_model, 'compile_repeated_blocks') and 'repeated' in shared.opts.cuda_compile_options and not sd_model.__class__.__name__.startswith("Autoencoder") - log.debug(f"{op} compile: options={shared.opts.cuda_compile_options} mode={shared.opts.cuda_compile_mode} backend={shared.opts.cuda_compile_backend} repeated={is_repeated} components={apply_to_components} targets={shared.opts.cuda_compile}") + if not log_once: + log_once = True + log.debug(f"{op} compile: task=torch available={torch._dynamo.list_backends()}") # pylint: disable=protected-access + log.debug(f"{op} compile: options={shared.opts.cuda_compile_options} mode={shared.opts.cuda_compile_mode} backend={shared.opts.cuda_compile_backend} repeated={is_repeated} components={apply_to_components} targets={shared.opts.cuda_compile}") compiled_components = [] def torch_compile_model(model, op=None, sd_model=None): # pylint: disable=unused-argument - setup_logging() # compile messes with logging so reset is needed - log.debug(f"Compile: cls={sd_model.__class__.__name__} apply") name = model.__class__.__name__ if callable(model) else model.__name__ + if 'OptimizedModule' in name: + log.warning('Model compile: task=torch model is already compiled') + return model + log.debug(f"Model compile: cls={name} apply") + setup_logging() # compile messes with logging so reset is needed compiled_components.append(name) if is_repeated: model.compile_repeated_blocks( @@ -228,14 +232,17 @@ def compile_torch(sd_model, apply_to_components=True, op="Model"): ) elif hasattr(model, 'device') and model.device.type != "meta": return_device = model.device - model = torch.compile(model.to(devices.device), + model = model.to(devices.device) + model = torch.compile( + model, mode=shared.opts.cuda_compile_mode, backend=shared.opts.cuda_compile_backend, fullgraph='fullgraph' in shared.opts.cuda_compile_options, dynamic='dynamic' in shared.opts.cuda_compile_options, ).to(return_device) else: - model = torch.compile(model, + model = torch.compile( + model, mode=shared.opts.cuda_compile_mode, backend=shared.opts.cuda_compile_backend, fullgraph='fullgraph' in shared.opts.cuda_compile_options, @@ -287,7 +294,8 @@ def compile_torch(sd_model, apply_to_components=True, op="Model"): sd_model("dummy prompt") except Exception: pass - t1 = time.time() + + t1 = time.perf_counter() log.info(f"{op} compile: task=torch components={compiled_components} time={t1-t0:.2f}") except Exception as e: log.warning(f"{op} compile: task=torch {e}") @@ -329,23 +337,50 @@ def compile_diffusers(sd_model, apply_to_components=True, op="Model"): log.warning(f'{op} compile enabled but no backend specified') return sd_model t0 = time.time() - log.info(f"{op} compile: pipeline={sd_model.__class__.__name__} backend={shared.opts.cuda_compile_backend} options={shared.opts.cuda_compile_options}") + log.info(f"{op} compile: component={sd_model.__class__.__name__} backend={shared.opts.cuda_compile_backend} options={shared.opts.cuda_compile_options}") if shared.opts.cuda_compile_backend == 'onediff': sd_model = compile_onediff(sd_model) + log.debug(f"{op} compile: task=onediff time={time.time()-t0:.2f}") elif shared.opts.cuda_compile_backend == 'stable-fast': sd_model = compile_stablefast(sd_model) + log.debug(f"{op} compile: task=stablefast time={time.time()-t0:.2f}") elif shared.opts.cuda_compile_backend == 'deep-cache': sd_model = compile_deepcache(sd_model) + log.debug(f"{op} compile: task=deepcache time={time.time()-t0:.2f}") elif shared.opts.cuda_compile_backend == 'pruna': sd_model = compile_pruna(sd_model) + log.debug(f"{op} compile: task=pruna time={time.time()-t0:.2f}") else: check_deepcache(False) sd_model = compile_torch(sd_model, apply_to_components=apply_to_components, op=op) - t1 = time.time() - log.debug(f"{op} compile: time={t1-t0:.2f}") return sd_model +def set_openvino_overrides(): + overrides = [] + if "Model" not in shared.opts.cuda_compile: + if 'LoRA' in shared.opts.cuda_compile: + shared.opts.cuda_compile = [] + else: + shared.opts.cuda_compile.append("Model") + overrides.append("compile=model") + if shared.opts.cuda_compile_backend != shared.opts.openvino_compile_backend: + shared.opts.cuda_compile_backend = shared.opts.openvino_compile_backend + overrides.append(f"backend={shared.opts.openvino_compile_backend}") + if shared.opts.diffusers_offload_mode != "none": + shared.opts.diffusers_offload_mode = "none" + overrides.append("offload=none") + if not shared.opts.lora_force_diffusers: + shared.opts.lora_force_diffusers = True + overrides.append("lora=diffusers") + if not shared.opts.lora_fuse_diffusers: + shared.opts.lora_fuse_native = False + shared.opts.lora_fuse_diffusers = True + overrides.append("lora=fuse") + if len(overrides) > 0: + log.warning(f"OpenVINO setting override: {overrides}") + + def openvino_recompile_model(p, hires=False, refiner=False): # recompile if a parameter changes # pylint: disable=unused-argument if (shared.opts.cuda_compile_backend == "openvino_fx" or shared.opts.cuda_compile_backend == "openvino") and ('Model' in shared.opts.cuda_compile): compile_height = p.height if not hires and hasattr(p, 'height') else p.hr_upscale_to_y diff --git a/modules/sd_offload.py b/modules/sd_offload.py index 95e4fc261..a6f1bcafb 100644 --- a/modules/sd_offload.py +++ b/modules/sd_offload.py @@ -106,7 +106,7 @@ def set_diffuser_offload(sd_model, op:str='model', quiet:bool=False, force:bool= process_timer.add('offload', time.time() - t0) return - if shared.opts.diffusers_offload_mode == "none": + if shared.opts.diffusers_offload_mode == "none" and devices.backend != "openvino": log.warning('Offload: type=none "use balanced offload with model type set not to offload"') apply_none_offload(sd_model, quiet=quiet) diff --git a/modules/sd_offload_balanced.py b/modules/sd_offload_balanced.py index 589ff3522..23a7017c6 100644 --- a/modules/sd_offload_balanced.py +++ b/modules/sd_offload_balanced.py @@ -14,7 +14,7 @@ import modules.sd_offload_state as s class OffloadHook(accelerate.hooks.ModelHook): - def __init__(self, checkpoint_name): + def __init__(self, checkpoint_name, silent=False): if shared.opts.diffusers_offload_max_gpu_memory > 1: shared.opts.diffusers_offload_max_gpu_memory = 0.75 if shared.opts.diffusers_offload_max_cpu_memory > 1: @@ -32,8 +32,9 @@ class OffloadHook(accelerate.hooks.ModelHook): self.last_pre = None self.last_post = None self.last_cls = None - gpu = f'{(shared.gpu_memory * shared.opts.diffusers_offload_min_gpu_memory):.2f}-{(shared.gpu_memory * shared.opts.diffusers_offload_max_gpu_memory):.2f}:{shared.gpu_memory:.2f}' - log.info(f'Offload: type=balanced op=init watermark={self.min_watermark}-{self.max_watermark} gpu={gpu} cpu={shared.cpu_memory:.3f} limit={shared.opts.cuda_mem_fraction:.2f} always={self.offload_always} never={self.offload_never} pre={shared.opts.diffusers_offload_pre} streams={shared.opts.diffusers_offload_streams}') + if not silent: + gpu = f'{(shared.gpu_memory * shared.opts.diffusers_offload_min_gpu_memory):.2f}-{(shared.gpu_memory * shared.opts.diffusers_offload_max_gpu_memory):.2f}:{shared.gpu_memory:.2f}' + log.info(f'Offload: type=balanced op=init watermark={self.min_watermark}-{self.max_watermark} gpu={gpu} cpu={shared.cpu_memory:.3f} limit={shared.opts.cuda_mem_fraction:.2f} always={self.offload_always} never={self.offload_never} pre={shared.opts.diffusers_offload_pre} streams={shared.opts.diffusers_offload_streams}') self.validate() super().__init__() @@ -255,7 +256,7 @@ def apply_balanced_offload(sd_model=None, exclude: list[str] | None = None, forc checkpoint_name = sd_model.sd_checkpoint_info.name if getattr(sd_model, "sd_checkpoint_info", None) is not None else sd_model.__class__.__name__ if force or (s.offload_hook_instance is None) or (s.offload_hook_instance.min_watermark != shared.opts.diffusers_offload_min_gpu_memory) or (s.offload_hook_instance.max_watermark != shared.opts.diffusers_offload_max_gpu_memory) or (checkpoint_name != s.offload_hook_instance.checkpoint_name): cached = False - s.offload_hook_instance = OffloadHook(checkpoint_name) + s.offload_hook_instance = OffloadHook(checkpoint_name, silent=silent) if cached and shared.opts.diffusers_offload_pre: s.debug_move('Offload: type=balanced op=apply skip') @@ -277,6 +278,6 @@ def apply_balanced_offload(sd_model=None, exclude: list[str] | None = None, forc process_timer.add('offload', t1 - t0) fn = f'{sys._getframe(2).f_code.co_name}:{sys._getframe(1).f_code.co_name}' # pylint: disable=protected-access s.debug_move(f'Apply offload: time={t1 - t0:.2f} type=balanced fn={fn}') - if not cached: + if not cached and not silent: log.info(f'Model class={sd_model.__class__.__name__} modules={len(s.offload_hook_instance.offload_map)} size={s.offload_hook_instance.model_size():.3f}') return sd_model diff --git a/modules/sd_offload_group.py b/modules/sd_offload_group.py index 07776596b..96bfeffa6 100644 --- a/modules/sd_offload_group.py +++ b/modules/sd_offload_group.py @@ -1,4 +1,5 @@ import time +import types import itertools import torch import accelerate.hooks @@ -28,6 +29,59 @@ def group_offload_config(main: bool) -> dict: } +def group_tensors(group) -> list: + """Every parameter and buffer a diffusers group moves, read at call time so a tensor replaced while offloaded is seen.""" + tensors = [] + for module in group.modules: + tensors.extend(module.parameters()) + tensors.extend(module.buffers()) + tensors.extend(group.parameters) + tensors.extend(group.buffers) + return tensors + + +def loaded_tensors(tensors) -> dict: + """The cpu tensors held right now, keyed by parameter, to hand back on offload in place of a fresh copy.""" + return {t: t.data for t in tensors if t.data.device.type == 'cpu'} + + +def restore_tensors(tensors, loaded: dict | None, non_blocking: bool = False): + """Return tensors to cpu: the tensor each was onloaded from where known, a copy otherwise.""" + for t in tensors: + if t.data.device.type == 'cpu': + continue + source = loaded.get(t) if loaded else None + t.data = source if source is not None else t.data.to(devices.cpu, non_blocking=non_blocking) + + +def onload_remember(group): + group.sdnext_loaded = loaded_tensors(group_tensors(group)) + group.sdnext_onload() + + +def offload_restore(group): + restore_tensors(group_tensors(group), getattr(group, 'sdnext_loaded', None)) + group.sdnext_loaded = None # a record lives from one onload to its offload + + +def keep_loaded_tensors(module) -> int: + """Groups on the no-stream path copy their weights to fresh cpu memory on every offload; record the cpu + tensors at onload and hand them back at offload instead. Returns the number of groups patched.""" + from diffusers.hooks.group_offloading import _GROUP_OFFLOADING + count = 0 + for sub in module.modules(): + registry = getattr(sub, '_diffusers_hook', None) + hook = registry.get_hook(_GROUP_OFFLOADING) if registry is not None else None + group = getattr(hook, 'group', None) + if group is None or group.stream is not None or getattr(group, 'offload_to_disk_path', None) or hasattr(group, 'sdnext_onload'): + continue + group.sdnext_onload = group._onload_from_memory # pylint: disable=protected-access + group._onload_from_memory = types.MethodType(onload_remember, group) # pylint: disable=protected-access + group._offload_to_memory = types.MethodType(offload_restore, group) # pylint: disable=protected-access + count += 1 + return count + + def remove_group_offload_component(module) -> bool: if getattr(module, 'sdnext_group_offload_sig', None) is None: module = getattr(module, 'model', None) # wrapper components carry the hooks on the inner model @@ -91,6 +145,9 @@ def apply_group_offload_component(module, module_name: str, main: bool) -> bool: sig = f'{devices.device}:{main}:' + ':'.join(str(v) for v in cfg.values()) if getattr(module, 'sdnext_group_offload_sig', None) == sig: return False + requested_blocks = int(shared.opts.group_offload_blocks) + if cfg['use_stream'] and requested_blocks > 1: + log.warning(f'Offload: type=group module={module_name} blocks={requested_blocks} streams=True clamped=1') if hasattr(module, '_hf_hook'): # leftover accelerate hooks from a previous offload mode abort the group apply upstream module = accelerate.hooks.remove_hook_from_module(module, recurse=True) module.sdnext_ondemand = False # group placement replaces any on-demand hook @@ -99,6 +156,8 @@ def apply_group_offload_component(module, module_name: str, main: bool) -> bool: s.debug_move(f'Offload: type=group op=apply type={shared.opts.group_offload_type} module={module_name} pin={cfg["use_stream"] and not cfg["low_cpu_mem_usage"]}') # before the apply: pinning large components takes a while and would otherwise run silently module.sdnext_group_offload_sig = 'partial' # a raise below leaves hooks that only a non-empty signature will remove apply_group_offloading(module, onload_device=devices.device, offload_device=devices.cpu, **cfg) + if not cfg['use_stream']: + s.debug_move(f'Offload: type=group op=keep module={module_name} groups={keep_loaded_tensors(module)}') module.sdnext_group_offload_sig = sig return True @@ -153,6 +212,7 @@ class OnDemandHook(accelerate.hooks.ModelHook): param = next(module.parameters(), None) if param is not None and not devices.same_device(param.device, devices.device): t0 = time.time() + module.sdnext_loaded = loaded_tensors(list(module.parameters()) + list(module.buffers())) module.to(devices.device, non_blocking=shared.opts.diffusers_offload_nonblocking) t1 = time.time() process_timer.add('onload', t1 - t0) @@ -194,7 +254,12 @@ def offload_ondemand(sd_model, include=[], exclude=[], reason='', force=False): continue try: t0 = time.time() - module.to(devices.cpu, non_blocking=shared.opts.diffusers_offload_nonblocking) + loaded = getattr(module, 'sdnext_loaded', None) + if loaded: + restore_tensors(list(module.parameters()) + list(module.buffers()), loaded, non_blocking=shared.opts.diffusers_offload_nonblocking) + module.sdnext_loaded = None # a record lives from one onload to its offload + else: + module.to(devices.cpu, non_blocking=shared.opts.diffusers_offload_nonblocking) dt = time.time() - t0 process_timer.add('offload', dt) moved.append(module_name) @@ -206,20 +271,17 @@ def offload_ondemand(sd_model, include=[], exclude=[], reason='', force=False): def report_group_stats(sd_model, module_names): - """Per-component stats block once per loaded model; balanced mode prints its own from the hook map.""" - checkpoint_name = sd_model.sd_checkpoint_info.name if getattr(sd_model, "sd_checkpoint_info", None) is not None else sd_model.__class__.__name__ - if checkpoint_name in s.group_stats_reported: # keyed by checkpoint since a task switch rebuilds the pipe object + """Per-component stats block once per loaded component; balanced mode prints its own from the hook map.""" + modules = {name: getattr(sd_model, name, None) for name in module_names} + modules = {name: module for name, module in modules.items() if isinstance(module, torch.nn.Module)} + pending = {name: module for name, module in modules.items() if not getattr(module, 'sdnext_stats_reported', False)} # a task switch reuses the modules, a reload brings new ones + if not pending: return - s.group_stats_reported.add(checkpoint_name) - total = 0.0 - counted = [] - for module_name in module_names: - module = getattr(sd_model, module_name, None) - if isinstance(module, torch.nn.Module): - total += get_module_size(module)[0] - counted.append(module_name) - report_model_stats(module_name, module) - log.info(f'Model class={sd_model.__class__.__name__} modules={len(counted)} size={total:.3f}') + for module_name, module in pending.items(): + module.sdnext_stats_reported = True + report_model_stats(module_name, module) + total = sum(get_module_size(module)[0] for module in modules.values()) + log.info(f'Model class={sd_model.__class__.__name__} modules={len(modules)} size={total:.3f}') def apply_group_offload(sd_model): diff --git a/modules/sd_offload_state.py b/modules/sd_offload_state.py index 2c1297675..375340a02 100644 --- a/modules/sd_offload_state.py +++ b/modules/sd_offload_state.py @@ -30,5 +30,4 @@ no_split_module_classes = [ ] accelerate_dtype_byte_size = None # monkey-patch accelerate.utils.modeling.dtype_byte_size -group_stats_reported = set() move_stream = None diff --git a/modules/sd_offload_utils.py b/modules/sd_offload_utils.py index eb43dc781..3ff2f4173 100644 --- a/modules/sd_offload_utils.py +++ b/modules/sd_offload_utils.py @@ -174,7 +174,11 @@ def report_model_stats(module_name, module): size, _params = get_module_size(module) quant = getattr(module, "quantization_method", None) params = sum(p.numel() for p in module.parameters(recurse=True)) + try: + dtype = next(module.parameters(), torch.tensor([])).dtype + except Exception: + dtype = None logical = get_logical_param_count(module) - log.debug(f'Module: name={module_name} cls={module.__class__.__name__} size={size:.3f} params={params} logical={logical} quant={quant}') + log.debug(f'Module: name={module_name} cls={module.__class__.__name__} size={size:.3f} params={params} logical={logical} quant={quant} dtype={dtype}') except Exception as e: log.error(f'Module stats: name={module_name} {e}') diff --git a/modules/sd_samplers.py b/modules/sd_samplers.py index e205ee9c8..d086bb8c8 100644 --- a/modules/sd_samplers.py +++ b/modules/sd_samplers.py @@ -46,6 +46,10 @@ def list_samplers(): return all_samplers +def get_samplers(): + return all_samplers + + def find_sampler_config(name): if name is not None and name != 'None': config = all_samplers_map.get(name, None) diff --git a/modules/sd_vae.py b/modules/sd_vae.py index 75dad5592..ec5f7053d 100644 --- a/modules/sd_vae.py +++ b/modules/sd_vae.py @@ -28,7 +28,7 @@ vae_scale_override = { } -def get_vae_scale_factor(model: DiffusionPipeline | None = None): +def get_vae_scale_factor(model: DiffusionPipeline | None = None, init_image: bool = False): if not shared.sd_loaded: vae_scale_factor = 8 return vae_scale_factor @@ -49,6 +49,8 @@ def get_vae_scale_factor(model: DiffusionPipeline | None = None): vae_scale_factor = model.pipe.vae_scale_factor elif hasattr(model, 'config') and hasattr(model.config, 'vae_scale_factor'): vae_scale_factor = model.config.vae_scale_factor + elif hasattr(model, 'vae') and hasattr(model.vae, 'spatial_compression_ratio'): + vae_scale_factor = model.vae.spatial_compression_ratio # video autoencoders carry the ratio on the instance, which also covers subclasses the name table misses else: # log.warning(f'VAE: cls={model.__class__.__name__ if model else "None"} scale=unknown') vae_scale_factor = 8 @@ -56,9 +58,12 @@ def get_vae_scale_factor(model: DiffusionPipeline | None = None): patch_size = model.patch_size if isinstance(patch_size, (tuple, list)): # 3d patch sizes are (t, h, w); spatial term is last patch_size = patch_size[-1] + multiple = vae_scale_factor * patch_size + if init_image and model is not None and hasattr(model, 'init_image_multiple'): # a pipeline that downsamples its source image needs a larger multiple than its output + multiple = max(multiple, int(model.init_image_multiple)) if debug: - log.trace(f'VAE: cls={model.__class__.__name__ if model else "None"} scale={vae_scale_factor} patch={patch_size}') - return vae_scale_factor * patch_size + log.trace(f'VAE: cls={model.__class__.__name__ if model else "None"} scale={vae_scale_factor} patch={patch_size} multiple={multiple}') + return multiple def load_vae_dict(filename: str): diff --git a/modules/shared.py b/modules/shared.py index b08e1d44e..ca6606d68 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -10,15 +10,18 @@ from typing import TYPE_CHECKING import gradio as gr from installer import print_dict # pylint: disable=unused-import from modules.logger import log -log.debug('Initializing: shared module') +log.debug('Initializing: shared module') import modules.memmon import modules.paths as paths from modules.json_helpers import readfile # pylint: disable=W0611 from modules.shared_helpers import listdir, req # pylint: disable=W0611 -from modules import errors, devices, shared_state, cmd_args, theme, history, files_cache # pylint: disable=unused-import +from modules import errors, devices, shared_state, cmd_args, history, files_cache # pylint: disable=unused-import from modules.memstats import memory_stats # pylint: disable=unused-import +# main entry point that triggers package imports +from modules import loader # pylint: disable=unused-import + log.debug('Initializing: pipelines') from modules import shared_items # pylint: disable=unused-import from modules.caption.openclip import get_clip_models, refresh_clip_models # pylint: disable=unused-import @@ -108,8 +111,12 @@ if not files_cache.do_cache_folders: def list_checkpoint_titles(): - import modules.sd_models # pylint: disable=W0621 - return modules.sd_models.checkpoint_titles() + try: + from modules.sd_models import checkpoint_titles # pylint: disable=W0621 + return checkpoint_titles() + except Exception as err: + log.error(f'Checkpoints: {err}') + return [] list_checkpoint_tiles = list_checkpoint_titles # alias for legacy typo @@ -124,24 +131,24 @@ def is_url(string): def refresh_checkpoints(): - import modules.sd_models # pylint: disable=W0621 - return modules.sd_models.list_models() + from modules.sd_models import list_models # pylint: disable=W0621 + return list_models() def refresh_vaes(): - import modules.sd_vae # pylint: disable=W0621 - modules.sd_vae.refresh_vae_list() + from modules.sd_vae import refresh_vae_list # pylint: disable=W0621 + refresh_vae_list() def refresh_upscalers(): - import modules.modelloader # pylint: disable=W0621 - modules.modelloader.load_upscalers() + from modules.modelloader import load_upscalers # pylint: disable=W0621 + load_upscalers() def list_samplers(): - import modules.sd_samplers # pylint: disable=W0621 - modules.sd_samplers.set_samplers() - return modules.sd_samplers.all_samplers + from modules.sd_samplers import set_samplers, get_samplers # pylint: disable=W0621 + set_samplers() + return get_samplers() log.debug('Initializing: settings') @@ -204,7 +211,7 @@ def restart_server(restart=True): demo.server.should_exit = True demo.server.force_exit = True demo.close(verbose=False) - demo.server.close() + # demo.server.close() demo.fns = [] time.sleep(1) sys.tracebacklimit = 100 diff --git a/modules/shared_defaults.py b/modules/shared_defaults.py index 0530fb6a3..b15077190 100644 --- a/modules/shared_defaults.py +++ b/modules/shared_defaults.py @@ -44,23 +44,18 @@ def get_default_modes(cmd_opts, mem_stat): default_sdp_choices = ['Flash', 'Memory', 'Math'] default_sdp_options = ['Flash', 'Memory', 'Math'] - default_sdp_override_choices = ['Dynamic attention', 'Flex attention', 'Flash attention', 'Sage attention', 'SDNQ attention'] - default_sdp_override_options = [] - if devices.backend == "zluda": default_sdp_options = ['Math'] - default_sdp_override_options = ['Dynamic attention'] - default_sdp_override_choices.append('Triton Flash attention') + default_cross_attention = 'Dynamic attention' elif devices.backend == "rocm": - default_sdp_override_choices.append('Triton Flash attention') agent = devices.get_hip_agent() if agent.gfx_version < 0x1100: - default_sdp_override_options = ['Dynamic attention'] # only RDNA2 and older GPUs needs this + default_cross_attention = 'Dynamic attention' # only RDNA2 and older GPUs needs this elif devices.backend in {"cpu", "mps"}: - default_sdp_override_options = ['Dynamic attention'] + default_cross_attention = 'Dynamic attention' if devices.get_optimal_device_name() != "cpu": - os.environ.setdefault('SDNQ_USE_OPENVINO_MM', '0') # TODO sdnq openvino: this is too late as sdnq already initialized it + os.environ.setdefault('SDNQ_USE_OPENVINO_MM', '0') return ( default_offload_mode, @@ -69,8 +64,6 @@ def get_default_modes(cmd_opts, mem_stat): default_cross_attention, default_sdp_options, default_sdp_choices, - default_sdp_override_options, - default_sdp_override_choices, default_diffusers_offload_always, default_diffusers_offload_never, ) diff --git a/modules/shared_items.py b/modules/shared_items.py index e7d8dab8e..75efe9dba 100644 --- a/modules/shared_items.py +++ b/modules/shared_items.py @@ -139,14 +139,17 @@ def refresh_te_list(): def list_crossattention(): return [ - "Disabled", - "Scaled-Dot-Product", - "xFormers", - "Batch matrix-matrix", - "Dynamic Attention BMM" + 'Default', + 'Scaled-Dot-Product', + 'SDNQ attention', + 'xFormers', + 'Flex attention', + 'Flash attention', + 'Sage attention', + 'Dynamic attention', + 'Triton AMD Flash attention' ] - def get_pipelines(): from modules.logger import log """ diff --git a/modules/shared_state.py b/modules/shared_state.py index 34fd0172f..0eaa6c68b 100644 --- a/modules/shared_state.py +++ b/modules/shared_state.py @@ -63,7 +63,7 @@ class State: status += 'oom ' if self.oom else '' status += 'api ' if self.api else '' fn = f'{sys._getframe(3).f_code.co_name}:{sys._getframe(2).f_code.co_name}' # pylint: disable=protected-access - return f'State: ts={self.job_timestamp} job={self.job} jobs={self.job_no+1}/{self.job_count}/{self.total_jobs} step={self.sampling_step}/{self.sampling_steps} preview={self.preview_job}/{self.id_live_preview}/{self.current_image_sampling_step} status="{status.strip()}" fn={fn}' + return f'State: ts={self.job_timestamp} job={self.job} jobs={self.job_no+1}/{self.job_count}/{self.total_jobs} step={self.sampling_step}/{self.sampling_steps} preview={self.preview_job}/{self.id_live_preview}/{self.current_image_sampling_step} status="{status.strip()}" image={self.current_image} latent={list(self.current_latent.shape) if self.current_latent is not None else None} fn={fn}' @property def sampling_step(self): @@ -293,7 +293,6 @@ class State: elif self.prediction_type == "v_prediction": sample = self.current_noise_pred * (-self.current_sigma / (self.current_sigma**2 + 1) ** 0.5) + (original_sample / (self.current_sigma**2 + 1)) # pylint: disable=invalid-unary-operand-type except Exception: - # log.error(f'State image sigma: last={self.id_live_preview} step={self.sampling_step} {e}') pass # ignore sigma errors image = sd_samplers_common.samples_to_image_grid(sample, fast=self.sampling_step > 1) self.assign_current_image(image) diff --git a/modules/styles.py b/modules/styles.py index 6fdbb672d..9eb4bb284 100644 --- a/modules/styles.py +++ b/modules/styles.py @@ -200,14 +200,18 @@ def apply_wildcards_to_prompt(prompt, all_wildcards, seed=-1, silent=False, p: S except Exception as e: log.error(f'Wildcards: wildcard="{wildcard}" error={e}') t1 = time.time() - prompt, replaced_file, not_found = apply_file_wildcards(prompt, [], [], recursion=0, seed=seed, p=p) + prompt, replaced_files, missing_files = apply_file_wildcards(prompt, [], [], recursion=0, seed=seed, p=p) t2 = time.time() if replaced and not silent: log.debug(f'Apply wildcards: {replaced} path="{shared.opts.wildcards_dir}" type=style time={t1-t0:.2f}') - if (len(replaced_file) > 0 or len(not_found) > 0) and not silent: - log.debug(f'Apply wildcards: found={replaced_file} missing={not_found} path="{shared.opts.wildcards_dir}" type=file seed={seed} time={t2-t2:.2f}') + if (len(replaced_files) > 0 or len(missing_files) > 0) and not silent: + log.debug(f'Apply wildcards: found={replaced_files} missing={missing_files} path="{shared.opts.wildcards_dir}" type=file seed={seed} time={t2-t1:.2f}') if p is not None: - p.extra_generation_params['Wildcards'] = p.extra_generation_params.get('Wildcards', []) + [replaced_file] + existing_wildcards = p.extra_generation_params.get('Wildcards', []) + if p.batch_size > 1 and existing_wildcards == replaced_files: + pass + else: + p.extra_generation_params['Wildcards'] = existing_wildcards + replaced_files if old_state is not None: random.setstate(old_state) return prompt @@ -243,12 +247,15 @@ def apply_styles_to_extra(p, style: Style): 'size', ] reference_style = get_reference_style() - extra = infotext.parse(reference_style) if shared.opts.extra_network_reference_values else {} + reference = infotext.parse(reference_style) if shared.opts.extra_network_reference_values else {} + extra = reference.copy() style_extra = apply_wildcards_to_prompt(style.extra, [style.wildcards], silent=True, p=p) style_extra = ' ' + style_extra.lower() extra.update(infotext.parse(style_extra)) extra.pop('Prompt', None) extra.pop('Negative prompt', None) + has_prompt = (style.prompt is not None) and len(style.prompt) > 2 + has_negative = (style.negative_prompt is not None) and len(style.negative_prompt) > 2 if debug_enabled: log.trace(f'Apply style extra: {extra}') @@ -284,7 +291,7 @@ def apply_styles_to_extra(p, style: Style): if debug_enabled: log.trace(f'Apply style skip: {k}={v}') skipped.append(f'{k}={v}') - log.debug(f'Apply style: name="{style.name}" params={params} settings={settings} unknown={skipped} reference={True if reference_style else False}') + log.debug(f'Apply style: name="{style.name}" prompt={has_prompt} negative={has_negative} params={params} settings={settings} unknown={skipped} reference={reference}') class StyleDatabase: diff --git a/modules/taesd/taehv.py b/modules/taesd/taehv.py index 4e974deae..8b65e41cd 100644 --- a/modules/taesd/taehv.py +++ b/modules/taesd/taehv.py @@ -9,7 +9,6 @@ import torch.nn as nn import torch.nn.functional as F from tqdm.auto import tqdm -DecoderResult = namedtuple("DecoderResult", ("frame", "memory")) TWorkItem = namedtuple("TWorkItem", ("input_tensor", "block_index")) def conv(n_in, n_out, **kwargs): @@ -28,6 +27,18 @@ class MemBlock(nn.Module): def forward(self, x, past): return self.act(self.conv(torch.cat([x, past], 1)) + self.skip(x)) +class SuperMemBlock(nn.Module): + """MemBlock variant used by the Super decoder (ConvNeXt-style: 7x7 depthwise conv + inverted bottleneck).""" + def __init__(self, n_f): + super().__init__() + self.conv = nn.Sequential( + nn.Conv2d(n_f*2, n_f*2, 7, padding=3, groups=n_f*2, bias=False), + nn.Conv2d(n_f*2, n_f*4, 1), nn.ReLU(inplace=True), + nn.Conv2d(n_f*4, n_f, 1, bias=False), + ) + def forward(self, x, past): + return self.conv(torch.cat([x, past], 1)) + x + class TPool(nn.Module): def __init__(self, n_f, stride): super().__init__() @@ -47,6 +58,106 @@ class TGrow(nn.Module): x = self.conv(x) return x.reshape(-1, C, H, W) +def apply_model_with_memblocks_parallel(model, x, show_progress_bar): + """ + Apply a sequential model with memblocks to the given input, + with parallelization over the time axis and iteration over blocks. + + Args: + - model: nn.Sequential of blocks to apply + - x: input data, of dimensions NTCHW + - show_progress_bar: if True, enables tqdm progressbar display + + Returns NTCHW tensor of output data. + """ + assert x.ndim == 5, f"TAEHV operates on NTCHW tensors, but got {x.ndim}-dim tensor" + N, T, C, H, W = x.shape + x = x.reshape(N*T, C, H, W) + + # parallel over input timesteps, iterate over blocks + for b in tqdm(model, disable=not show_progress_bar): + if isinstance(b, (MemBlock, SuperMemBlock)): + NT, C, H, W = x.shape + T = NT // N + _x = x.reshape(N, T, C, H, W) + # pad with zeros along time axis (i.e. empty memory), slice + block_memory = F.pad(_x, (0,0,0,0,0,0,1,0), value=0)[:,:T].reshape(x.shape) + x = b(x, block_memory) + else: + x = b(x) + NT, C, H, W = x.shape + T = NT // N + return x.view(N, T, C, H, W) + +def apply_model_with_memblocks_sequential_single_step(model, memory, work_queue, progress_bar=None): + """ + Process the work queue (a graph traversal over blocks and timesteps) + until an output frame is produced or the queue is empty. + Mutates memory and work_queue in place. + + Returns N1CHW output tensor, or None if the queue needs more input. + """ + while work_queue: + xt, i = work_queue.pop(0) + if progress_bar is not None and i == 0: + progress_bar.update(1) + if i == len(model): + return xt.unsqueeze(1) + b = model[i] + if isinstance(b, (MemBlock, SuperMemBlock)): + # mem blocks are simple since we're visiting the graph in causal order + if memory[i] is None: + xt_new = b(xt, xt * 0) + else: + xt_new = b(xt, memory[i]) + memory[i] = xt + work_queue.insert(0, TWorkItem(xt_new, i+1)) + elif isinstance(b, TPool): + # pool blocks accumulate inputs until they have enough to pool + if memory[i] is None: + memory[i] = [] + memory[i].append(xt) + if len(memory[i]) > b.stride: + raise ValueError(f"TPool memory overflow: {len(memory[i])} items for stride {b.stride}") + elif len(memory[i]) == b.stride: + N, C, H, W = xt.shape + xt = b(torch.cat(memory[i], 1).view(N*b.stride, C, H, W)) + memory[i] = [] + work_queue.insert(0, TWorkItem(xt, i+1)) + elif isinstance(b, TGrow): + xt = b(xt) + NT, C, H, W = xt.shape + for xt_next in reversed(xt.view(NT//b.stride, b.stride*C, H, W).chunk(b.stride, 1)): + work_queue.insert(0, TWorkItem(xt_next, i+1)) + else: + xt = b(xt) + work_queue.insert(0, TWorkItem(xt, i+1)) + return None + +def apply_model_with_memblocks_sequential(model, x, show_progress_bar): + """ + Apply a sequential model with memblocks to the given input, + with iteration over timesteps as well as blocks. + + Args: + - model: nn.Sequential of blocks to apply + - x: input data, of dimensions NTCHW + - show_progress_bar: if True, enables tqdm progressbar display + + Returns NTCHW tensor of output data. + """ + assert x.ndim == 5, f"TAEHV operates on NTCHW tensors, but got {x.ndim}-dim tensor" + work_queue = [TWorkItem(xt, 0) for xt in x.unbind(1)] + memory = [None] * len(model) + progress_bar = tqdm(range(len(work_queue)), disable=not show_progress_bar) + out = [] + while work_queue: + xt = apply_model_with_memblocks_sequential_single_step(model, memory, work_queue, progress_bar) + if xt is not None: + out.append(xt) + progress_bar.close() + return torch.cat(out, 1) + def apply_model_with_memblocks(model, x, parallel, show_progress_bar): """ Apply a sequential model with memblocks to the given input. @@ -59,141 +170,72 @@ def apply_model_with_memblocks(model, x, parallel, show_progress_bar): Returns NTCHW tensor of output data. """ - if x.ndim == 4: - x = x.unsqueeze(0) - assert x.ndim == 5, f"TAEHV operates on NTCHW tensors, but got {x.ndim}-dim tensor" - if x.shape[1] == 16 and x.shape[2] != 16: - x = x.transpose(1,2) # NCTHW to NTCHW - N, T, C, H, W = x.shape if parallel: - x = x.reshape(N*T, C, H, W) - # parallel over input timesteps, iterate over blocks - for b in tqdm(model, disable=not show_progress_bar): - if isinstance(b, MemBlock): - NT, C, H, W = x.shape - T = NT // N - _x = x.reshape(N, T, C, H, W) - mem = F.pad(_x, (0,0,0,0,0,0,1,0), value=0)[:,:T].reshape(x.shape) - x = b(x, mem) - else: - x = b(x) - NT, C, H, W = x.shape - T = NT // N - x = x.view(N, T, C, H, W) + return apply_model_with_memblocks_parallel(model, x, show_progress_bar) else: - out = [] - # iterate over input timesteps and also iterate over blocks. - # because of the cursed TPool/TGrow blocks, this is not a nested loop, - # it's actually a ***graph traversal*** problem! so let's make a queue - work_queue = [TWorkItem(xt, 0) for t, xt in enumerate(x.reshape(N, T * C, H, W).chunk(T, dim=1))] - # in addition to manually managing our queue, we also need to manually manage our progressbar. - # we'll update it for every source node that we consume. - progress_bar = tqdm(range(T), disable=not show_progress_bar) - # we'll also need a separate addressable memory per node as well - mem = [None] * len(model) - while work_queue: - xt, i = work_queue.pop(0) - if i == 0: - # new source node consumed - progress_bar.update(1) - if i == len(model): - # reached end of the graph, append result to output list - out.append(xt) - else: - # fetch the block to process - b = model[i] - if isinstance(b, MemBlock): - # mem blocks are simple since we're visiting the graph in causal order - if mem[i] is None: - xt_new = b(xt, xt * 0) - mem[i] = xt - else: - xt_new = b(xt, mem[i]) - mem[i].copy_(xt) # inplace might reduce mysterious pytorch memory allocations? doesn't help though - # add successor to work queue - work_queue.insert(0, TWorkItem(xt_new, i+1)) - elif isinstance(b, TPool): - # pool blocks are miserable - if mem[i] is None: - mem[i] = [] # pool memory is itself a queue of inputs to pool - mem[i].append(xt) - if len(mem[i]) > b.stride: - # pool mem is in invalid state, we should have pooled before this - raise ValueError("???") - elif len(mem[i]) < b.stride: - # pool mem is not yet full, go back to processing the work queue - pass - else: - # pool mem is ready, run the pool block - N, C, H, W = xt.shape - xt = b(torch.cat(mem[i], 1).view(N*b.stride, C, H, W)) - # reset the pool mem - mem[i] = [] - # add successor to work queue - work_queue.insert(0, TWorkItem(xt, i+1)) - elif isinstance(b, TGrow): - xt = b(xt) - NT, C, H, W = xt.shape - # each tgrow has multiple successor nodes - for xt_next in reversed(xt.view(N, b.stride*C, H, W).chunk(b.stride, 1)): - # add successor to work queue - work_queue.insert(0, TWorkItem(xt_next, i+1)) - else: - # normal block with no funny business - xt = b(xt) - # add successor to work queue - work_queue.insert(0, TWorkItem(xt, i+1)) - progress_bar.close() - x = torch.stack(out, 1) - return x + return apply_model_with_memblocks_sequential(model, x, show_progress_bar) class TAEHV(nn.Module): - latent_channels = 16 - image_channels = 3 - def __init__(self, checkpoint_path="taehv.pth", decoder_time_upscale=(True, True), decoder_space_upscale=(True, True, True)): + def __init__(self, checkpoint_path="taehv.pth", encoder_time_downscale=(True, True, False), decoder_time_upscale=(False, True, True), decoder_space_upscale=(True, True, True), patch_size=1, latent_channels=16, arch_variant=None): """Initialize pretrained TAEHV from the given checkpoint. Arg: checkpoint_path: path to weight file to load. taehv.pth for Hunyuan, taew2_1.pth for Wan 2.1. + encoder_time_downscale: whether temporal downsampling is enabled for each block. decoder_time_upscale: whether temporal upsampling is enabled for each block. upsampling can be disabled for a cheaper preview. decoder_space_upscale: whether spatial upsampling is enabled for each block. upsampling can be disabled for a cheaper preview. + patch_size: input/output pixelshuffle patch-size for this model. + latent_channels: number of latent channels (z dim) for this model. + arch_variant: decoder architecture variant. None (base) or "super" (higher-quality, ~2x decoder params). Autodetected from filename if None. """ super().__init__() - from modules import shared + self.patch_size = patch_size + self.latent_channels = latent_channels + self.image_channels = 3 + if len(decoder_time_upscale) == 2: + decoder_time_upscale = (False, *decoder_time_upscale) + self.is_cogvideox = checkpoint_path is not None and "taecvx" in checkpoint_path + self.is_h3 = checkpoint_path is not None and "taeh3" in checkpoint_path + if checkpoint_path is not None and "taew2_2" in checkpoint_path: + self.patch_size, self.latent_channels = 2, 48 + if checkpoint_path is not None and "taehv1_5" in checkpoint_path: + self.patch_size, self.latent_channels = 2, 32 + if self.is_h3: + self.patch_size, self.latent_channels, encoder_time_downscale = 2, 24, (True, True, False) + if checkpoint_path is not None and "taeltx" in checkpoint_path: # same for both 2 and 2.3 + self.patch_size, self.latent_channels, encoder_time_downscale, decoder_time_upscale = 4, 128, (True, True, True), (True, True, True) + if arch_variant is None and checkpoint_path is not None and "_super" in checkpoint_path: + arch_variant = "super" + assert arch_variant in (None, "super"), f"unrecognized arch_variant {arch_variant!r}" self.encoder = nn.Sequential( - conv(TAEHV.image_channels, 64), nn.ReLU(inplace=True), - TPool(64, 2), conv(64, 64, stride=2, bias=False), MemBlock(64, 64), MemBlock(64, 64), MemBlock(64, 64), - TPool(64, 2), conv(64, 64, stride=2, bias=False), MemBlock(64, 64), MemBlock(64, 64), MemBlock(64, 64), - TPool(64, 1), conv(64, 64, stride=2, bias=False), MemBlock(64, 64), MemBlock(64, 64), MemBlock(64, 64), - conv(64, TAEHV.latent_channels), + conv(self.image_channels*self.patch_size**2, 64), nn.ReLU(inplace=True), + TPool(64, 2 if encoder_time_downscale[0] else 1), conv(64, 64, stride=2, bias=False), MemBlock(64, 64), MemBlock(64, 64), MemBlock(64, 64), + TPool(64, 2 if encoder_time_downscale[1] else 1), conv(64, 64, stride=2, bias=False), MemBlock(64, 64), MemBlock(64, 64), MemBlock(64, 64), + TPool(64, 2 if encoder_time_downscale[2] else 1), conv(64, 64, stride=2, bias=False), MemBlock(64, 64), MemBlock(64, 64), MemBlock(64, 64), + conv(64, self.latent_channels), ) - n_f = [256, 128, 64, 64] - self.frames_to_trim = 2**sum(decoder_time_upscale) - 1 - - if shared.opts.taesd_layers == 1: + if arch_variant == "super": + n_f = [512, 256, 128, 64] self.decoder = nn.Sequential( - Clamp(), conv(TAEHV.latent_channels, n_f[0]), nn.ReLU(inplace=True), - MemBlock(n_f[0], n_f[0]), MemBlock(n_f[0], n_f[0]), MemBlock(n_f[0], n_f[0]), nn.Upsample(scale_factor=2 if decoder_space_upscale[0] else 1), TGrow(n_f[0], 1), conv(n_f[0], n_f[1], bias=False), - MemBlock(n_f[1], n_f[1]), MemBlock(n_f[1], n_f[1]), MemBlock(n_f[1], n_f[1]), nn.Identity(), TGrow(n_f[1], 2 if decoder_time_upscale[0] else 1), conv(n_f[1], n_f[2], bias=False), - MemBlock(n_f[2], n_f[2]), MemBlock(n_f[2], n_f[2]), MemBlock(n_f[2], n_f[2]), nn.Identity(), TGrow(n_f[2], 2 if decoder_time_upscale[1] else 1), conv(n_f[2], n_f[3], bias=False), - nn.ReLU(inplace=True), conv(n_f[3], TAEHV.image_channels), - ) - elif shared.opts.taesd_layers == 2: - self.decoder = nn.Sequential( - Clamp(), conv(TAEHV.latent_channels, n_f[0]), nn.ReLU(inplace=True), - MemBlock(n_f[0], n_f[0]), MemBlock(n_f[0], n_f[0]), MemBlock(n_f[0], n_f[0]), nn.Upsample(scale_factor=2 if decoder_space_upscale[0] else 1), TGrow(n_f[0], 1), conv(n_f[0], n_f[1], bias=False), - MemBlock(n_f[1], n_f[1]), MemBlock(n_f[1], n_f[1]), MemBlock(n_f[1], n_f[1]), nn.Upsample(scale_factor=2 if decoder_space_upscale[1] else 1), TGrow(n_f[1], 2 if decoder_time_upscale[0] else 1), conv(n_f[1], n_f[2], bias=False), - MemBlock(n_f[2], n_f[2]), MemBlock(n_f[2], n_f[2]), MemBlock(n_f[2], n_f[2]), nn.Identity(), TGrow(n_f[2], 2 if decoder_time_upscale[1] else 1), conv(n_f[2], n_f[3], bias=False), - nn.ReLU(inplace=True), conv(n_f[3], TAEHV.image_channels), + nn.Conv2d(self.latent_channels, n_f[0], 1, bias=False), + SuperMemBlock(n_f[0]), SuperMemBlock(n_f[0]), SuperMemBlock(n_f[0]), conv(n_f[0], n_f[1]*(2 if decoder_space_upscale[0] else 1)**2), nn.ReLU(inplace=True), nn.PixelShuffle(2 if decoder_space_upscale[0] else 1), TGrow(n_f[1], 2 if decoder_time_upscale[0] else 1), + SuperMemBlock(n_f[1]), SuperMemBlock(n_f[1]), SuperMemBlock(n_f[1]), conv(n_f[1], n_f[2]*(2 if decoder_space_upscale[1] else 1)**2), nn.ReLU(inplace=True), nn.PixelShuffle(2 if decoder_space_upscale[1] else 1), TGrow(n_f[2], 2 if decoder_time_upscale[1] else 1), + SuperMemBlock(n_f[2]), SuperMemBlock(n_f[2]), SuperMemBlock(n_f[2]), conv(n_f[2], n_f[3]*(2 if decoder_space_upscale[2] else 1)**2), nn.ReLU(inplace=True), nn.PixelShuffle(2 if decoder_space_upscale[2] else 1), TGrow(n_f[3], 2 if decoder_time_upscale[2] else 1), + conv(n_f[3], self.image_channels*self.patch_size**2), ) else: + n_f = [256, 128, 64, 64] self.decoder = nn.Sequential( - Clamp(), conv(TAEHV.latent_channels, n_f[0]), nn.ReLU(inplace=True), - MemBlock(n_f[0], n_f[0]), MemBlock(n_f[0], n_f[0]), MemBlock(n_f[0], n_f[0]), nn.Upsample(scale_factor=2 if decoder_space_upscale[0] else 1), TGrow(n_f[0], 1), conv(n_f[0], n_f[1], bias=False), - MemBlock(n_f[1], n_f[1]), MemBlock(n_f[1], n_f[1]), MemBlock(n_f[1], n_f[1]), nn.Upsample(scale_factor=2 if decoder_space_upscale[1] else 1), TGrow(n_f[1], 2 if decoder_time_upscale[0] else 1), conv(n_f[1], n_f[2], bias=False), - MemBlock(n_f[2], n_f[2]), MemBlock(n_f[2], n_f[2]), MemBlock(n_f[2], n_f[2]), nn.Upsample(scale_factor=2 if decoder_space_upscale[2] else 1), TGrow(n_f[2], 2 if decoder_time_upscale[1] else 1), conv(n_f[2], n_f[3], bias=False), - nn.ReLU(inplace=True), conv(n_f[3], TAEHV.image_channels), + Clamp(), conv(self.latent_channels, n_f[0]), nn.ReLU(inplace=True), + MemBlock(n_f[0], n_f[0]), MemBlock(n_f[0], n_f[0]), MemBlock(n_f[0], n_f[0]), nn.Upsample(scale_factor=2 if decoder_space_upscale[0] else 1), TGrow(n_f[0], 2 if decoder_time_upscale[0] else 1), conv(n_f[0], n_f[1], bias=False), + MemBlock(n_f[1], n_f[1]), MemBlock(n_f[1], n_f[1]), MemBlock(n_f[1], n_f[1]), nn.Upsample(scale_factor=2 if decoder_space_upscale[1] else 1), TGrow(n_f[1], 2 if decoder_time_upscale[1] else 1), conv(n_f[1], n_f[2], bias=False), + MemBlock(n_f[2], n_f[2]), MemBlock(n_f[2], n_f[2]), MemBlock(n_f[2], n_f[2]), nn.Upsample(scale_factor=2 if decoder_space_upscale[2] else 1), TGrow(n_f[2], 2 if decoder_time_upscale[2] else 1), conv(n_f[2], n_f[3], bias=False), + nn.ReLU(inplace=True), conv(n_f[3], self.image_channels*self.patch_size**2), ) + # computed properties + self.t_downscale = 2**sum(t.stride == 2 for t in self.encoder if isinstance(t, TPool)) + self.t_upscale = 2**sum(t.stride == 2 for t in self.decoder if isinstance(t, TGrow)) + self.frames_to_trim = self.t_upscale - 1 if checkpoint_path is not None: self.load_state_dict(self.patch_tgrow_layers(torch.load(checkpoint_path, map_location="cpu", weights_only=True))) @@ -213,6 +255,38 @@ class TAEHV(nn.Module): sd[key] = sd[key][-new_sd[key].shape[0]:] return sd + def preprocess_input_frames(self, x): + """Preprocess RGB input frames prior to the main encoder sequence.""" + if self.patch_size > 1: + x = F.pixel_unshuffle(x, self.patch_size) + return x + + def _encode_h3_video(self, x, parallel, show_progress_bar): + """Match H3's 17-frame chunks and three-token drop. + https://huggingface.co/MiniMaxAI/MiniMax-H3/blob/fa9c8ab1eaa21c8ae25e7e40b83b2e6002f340af/FL2VA/video_vae/klvae.py#L461-L503 + """ + batch = x.shape[0] + x = torch.cat([x, x[:, -1:].expand(-1, -x.shape[1] % 17, -1, -1, -1)], dim=1) + x = F.pad(x.reshape(batch, -1, 17, *x.shape[2:]), (0, 0, 0, 0, 0, 0, 3, 0)) + x = self.preprocess_input_frames(x) + if parallel: + x = apply_model_with_memblocks(self.encoder, x.flatten(0, 1), True, show_progress_bar) + x = x.reshape(batch, -1, *x.shape[2:]) + else: + x = torch.cat([apply_model_with_memblocks(self.encoder, chunk, False, False) + for chunk in tqdm(x.unbind(1), disable=not show_progress_bar)], dim=1) + return x[:, :-3] + + def _decode_h3_video(self, x, parallel, show_progress_bar): + """Match H3's five-token chunks and per-chunk prefix trim. + https://huggingface.co/MiniMaxAI/MiniMax-H3/blob/fa9c8ab1eaa21c8ae25e7e40b83b2e6002f340af/FL2VA/video_vae/klvae.py#L678-L786 + """ + x = apply_model_with_memblocks(self.decoder, x, parallel, show_progress_bar) + chunk_frames = 5 * self.t_upscale + x = F.pad(x, (0, 0, 0, 0, 0, 0, 0, -x.shape[1] % chunk_frames)) + x = x.unflatten(1, (-1, chunk_frames))[:, :, self.frames_to_trim:].flatten(1, 2) + return self.postprocess_output_frames(x[:, :-3 * self.t_upscale]) + def encode_video(self, x, parallel=True, show_progress_bar=True): """Encode a sequence of frames. @@ -223,28 +297,240 @@ class TAEHV(nn.Module): if False, frames will be processed sequentially. Returns NTCHW latent tensor with ~Gaussian values. """ + if self.is_h3: + return self._encode_h3_video(x, parallel, show_progress_bar) + x = self.preprocess_input_frames(x) + if x.shape[1] % self.t_downscale != 0: + # pad at end to multiple of self.t_downscale + n_pad = self.t_downscale - x.shape[1] % self.t_downscale + padding = x[:, -1:].repeat_interleave(n_pad, dim=1) + x = torch.cat([x, padding], 1) return apply_model_with_memblocks(self.encoder, x, parallel, show_progress_bar) + def postprocess_output_frames(self, x): + """Postprocess RGB frames after the main decoder sequence.""" + if self.patch_size > 1: + x = F.pixel_shuffle(x, self.patch_size) + return x.clamp_(0, 1) + def decode_video(self, x, parallel=True, show_progress_bar=True): """Decode a sequence of frames. Args: - x: input NTCHW latent (C=12) tensor with ~Gaussian values. + x: input NTCHW latent (C=self.latent_channels) tensor with ~Gaussian values. parallel: if True, all frames will be processed at once. (this is faster but may require more memory). if False, frames will be processed sequentially. Returns NTCHW RGB tensor with ~[0, 1] values. """ + if self.is_h3: + return self._decode_h3_video(x, parallel, show_progress_bar) + skip_trim = self.is_cogvideox and x.shape[1] % 2 == 0 x = apply_model_with_memblocks(self.decoder, x, parallel, show_progress_bar) - return x[:, self.frames_to_trim:] * 2.0 - 1.0 - - def forward(self, x): - return self.c(x) + x = self.postprocess_output_frames(x) + if skip_trim: + # skip trimming for cogvideox to make frame counts match. + # this still doesn't have correct temporal alignment for certain frame counts + # (cogvideox seems to pad at the start?), but for multiple-of-4 it's fine. + return x + return x[:, self.frames_to_trim:] def decode(self, x, parallel=True, show_progress_bar=False, return_dict=False): # pylint: disable=unused-argument """Decode a sequence of frames.""" + if x.ndim == 4: + x = x.unsqueeze(0) return self.decode_video(x, parallel=False, show_progress_bar=False) def encode(self, x, parallel=True, show_progress_bar=False, return_dict=False): # pylint: disable=unused-argument """Encode a sequence of frames.""" return self.encode_video(x, parallel=False, show_progress_bar=False) + +class StreamingTAEHV(nn.Module): + def __init__(self, taehv): + """Streaming wrapper around TAEHV for real-time use-cases (where not all inputs are available immediately). + + Encode-decode (video-to-video) usage: + streaming = StreamingTAEHV(taehv) + for frame in video_frames: + latent = streaming.encode(frame_tensor) + decoded = streaming.decode(latent) # feeds latent if not None, then returns next frame + if decoded is not None: + display(decoded) + for frame in streaming.flush(): + display(frame) + + Decode-only (world model) usage: + streaming = StreamingTAEHV(taehv) + while running: + latent = world_model.step() # latent represents t_upscale frames + frame = streaming.decode(latent) # returns first frame immediately + while frame is not None: # retrieve remaining frames from this latent + display(frame) + frame = streaming.decode() + """ + super().__init__() + self.taehv = taehv + self.reset() + + def reset(self): + """Reset all internal state. Call this to start encoding/decoding a new stream.""" + self.encoder_work_queue, self.encoder_memory = [], [None] * len(self.taehv.encoder) + self.decoder_work_queue, self.decoder_memory = [], [None] * len(self.taehv.decoder) + self.n_frames_encoded, self.n_frames_decoded = 0, 0 + self._last_encoder_input_frame = None + + def encode(self, x=None): + """Feed an input frame (optional) and try to produce an encoder output. + + The encoder accumulates t_downscale input frames before producing one latent, + so most calls will return None. Use flush_encoder() at end-of-stream to pad and + drain any remaining latents. + + Args: + x: NTCHW RGB frame tensor with values in [0, 1], or None to just process pending work. + Returns: N1CHW latent tensor, or None if not enough input has been accumulated. + """ + if x is not None: + assert x.ndim == 5 and x.shape[2] == self.taehv.image_channels, f"Expected NTCHW frames but got {x.shape=}" + self._last_encoder_input_frame = x[:, -1:] # pylint: disable=attribute-defined-outside-init + x = self.taehv.preprocess_input_frames(x) + self.encoder_work_queue.extend(TWorkItem(xt, 0) for xt in x.unbind(1)) + self.n_frames_encoded += x.shape[1] + xt = apply_model_with_memblocks_sequential_single_step( + self.taehv.encoder, self.encoder_memory, self.encoder_work_queue) + return xt + + def decode(self, x=None): + """Feed a latent (optional) and try to produce a decoded frame. + + Each latent produces t_upscale output frames due to temporal upscaling. The first + decode(latent) call returns the first of these frames; call decode() with no argument + to retrieve the rest, one at a time. Each call does the minimum decoder work needed to + produce one frame. + + Startup frames (the first frames_to_trim raw decoder outputs, used for causal alignment + with the reference VAE) are consumed internally and never returned. + + Args: + x: NTCHW latent tensor, or None to retrieve the next pending frame. + Returns: N1CHW decoded RGB frame tensor, or None if the queue needs more input. + """ + if x is not None: + assert x.ndim == 5 and x.shape[2] == self.taehv.latent_channels, f"Expected NTCHW latents but got {x.shape=}" + self.decoder_work_queue.extend(TWorkItem(xt, 0) for xt in x.unbind(1)) + while True: + xt = apply_model_with_memblocks_sequential_single_step( + self.taehv.decoder, self.decoder_memory, self.decoder_work_queue) + if xt is None: + return None + self.n_frames_decoded += 1 + # skip startup frames (to match decode_video trim behavior) + if not self.taehv.is_cogvideox and self.n_frames_decoded <= self.taehv.frames_to_trim: + continue + return self.taehv.postprocess_output_frames(xt) + + def flush_encoder(self): + """Pad (if needed) and drain all remaining latents from the encoder. + + Returns list of N1CHW latent tensors. + """ + latents = [] + if self._last_encoder_input_frame is not None and self.n_frames_encoded % self.taehv.t_downscale != 0: + n_pad = self.taehv.t_downscale - self.n_frames_encoded % self.taehv.t_downscale + for _ in range(n_pad): + lat = self.encode(self._last_encoder_input_frame) + if lat is not None: + latents.append(lat) + while (lat := self.encode()) is not None: + latents.append(lat) + return latents + + def flush_decoder(self): + """Drain all remaining decoded frames from the decoder. + + Returns list of N1CHW decoded RGB frame tensors. + """ + frames = [] + while (frame := self.decode()) is not None: + frames.append(frame) + return frames + + def flush(self): + """Flush encoder (with padding) and decoder, returning all remaining decoded frames. + + Returns list of N1CHW decoded RGB frame tensors. + """ + frames = [] + for latent in self.flush_encoder(): + frame = self.decode(latent) + if frame is not None: + frames.append(frame) + frames.extend(self.flush_decoder()) + return frames + +@torch.no_grad() +def main(): + """Run TAEHV roundtrip reconstruction on the given video paths.""" + import os + import sys + import cv2 # no highly esteemed deed is commemorated here + + class VideoTensorReader: + def __init__(self, video_file_path): + self.cap = cv2.VideoCapture(video_file_path) + assert self.cap.isOpened(), f"Could not load {video_file_path}" + self.fps = self.cap.get(cv2.CAP_PROP_FPS) + def __iter__(self): + return self + def __next__(self): + ret, frame = self.cap.read() + if not ret: + self.cap.release() + raise StopIteration # End of video or error + return torch.from_numpy(cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)).permute(2, 0, 1) # BGR HWC -> RGB CHW + + class VideoTensorWriter: + def __init__(self, video_file_path, width_height, fps=30): + self.writer = cv2.VideoWriter(video_file_path, cv2.VideoWriter_fourcc(*'mp4v'), fps, width_height) + assert self.writer.isOpened(), f"Could not create writer for {video_file_path}" + def write(self, frame_tensor): + assert frame_tensor.ndim == 3 and frame_tensor.shape[0] == 3, f"{frame_tensor.shape}??" + self.writer.write(cv2.cvtColor(frame_tensor.permute(1, 2, 0).numpy(), cv2.COLOR_RGB2BGR)) # RGB CHW -> BGR HWC + def __del__(self): + if hasattr(self, 'writer'): + self.writer.release() + + dev = torch.device("cuda" if torch.cuda.is_available() else "mps" if torch.backends.mps.is_available() else "cpu") + dtype = torch.float16 + checkpoint_path = os.getenv("TAEHV_CHECKPOINT_PATH", "taehv.pth") + checkpoint_name = os.path.splitext(os.path.basename(checkpoint_path))[0] + print(f"Using device \033[31m{dev}\033[0m, dtype \033[32m{dtype}\033[0m, checkpoint \033[34m{checkpoint_name}\033[0m ({checkpoint_path})") + taehv = TAEHV(checkpoint_path=checkpoint_path).to(dev, dtype) + for video_path in sys.argv[1:]: + print(f"Processing {video_path}...") + video_in = VideoTensorReader(video_path) + video = torch.stack(list(video_in), 0)[None] + vid_dev = video.to(dev, dtype).div_(255.0) + # convert to device tensor + if video.numel() < 100_000_000: + print(f" {video_path} seems small enough, will process all frames in parallel") + # convert to device tensor + vid_enc = taehv.encode_video(vid_dev) + print(f" Encoded {video_path} -> {vid_enc.shape}. Decoding...") + vid_dec = taehv.decode_video(vid_enc) + print(f" Decoded {video_path} -> {vid_dec.shape}") + else: + print(f" {video_path} seems large, will process each frame sequentially") + # convert to device tensor + vid_enc = taehv.encode_video(vid_dev, parallel=False) + print(f" Encoded {video_path} -> {vid_enc.shape}. Decoding...") + vid_dec = taehv.decode_video(vid_enc, parallel=False) + print(f" Decoded {video_path} -> {vid_dec.shape}") + video_out_path = video_path + f".reconstructed_by_{checkpoint_name}.mp4" + video_out = VideoTensorWriter(video_out_path, (vid_dec.shape[-1], vid_dec.shape[-2]), fps=int(round(video_in.fps))) + for frame in vid_dec.clamp_(0, 1).mul_(255).round_().byte().cpu()[0]: + video_out.write(frame) + print(f" Saved to {video_out_path}") + +if __name__ == "__main__": + main() diff --git a/modules/theme.py b/modules/theme.py index 81907953a..7f6043f23 100644 --- a/modules/theme.py +++ b/modules/theme.py @@ -1,13 +1,15 @@ +from functools import lru_cache import json import os +from types import SimpleNamespace from typing import TYPE_CHECKING, TypedDict import gradio as gr -import modules.extensions -import modules.shared -from modules.json_helpers import writefile from modules.logger import log +from modules.json_helpers import readfile, writefile +from modules.shared_helpers import req + if TYPE_CHECKING: class FontParams(TypedDict): @@ -16,6 +18,16 @@ if TYPE_CHECKING: gradio_theme = gr.themes.Base() +dct: dict = readfile('config.json', as_type='dict') +opts = SimpleNamespace(**dct) +if 'theme_type' not in opts.__dict__: + opts.theme_type = 'Modern' +if 'gradio_theme' not in opts.__dict__: + opts.gradio_theme = 'Default' +if 'theme_style' not in opts.__dict__: + opts.theme_style = 'Auto' +if 'ui_locale' not in opts.__dict__: + opts.ui_locale = 'Auto' def list_builtin_themes(): @@ -38,7 +50,7 @@ def refresh_themes(no_update=False): if not no_update: try: log.info('Refreshing UI themes') - r = modules.shared.req('https://huggingface.co/datasets/freddyaboulton/gradio-theme-subdomains/resolve/main/subdomains.json') + r = req('https://huggingface.co/datasets/freddyaboulton/gradio-theme-subdomains/resolve/main/subdomains.json') if r.status_code == 200: res = r.json() writefile(res, themes_file) @@ -49,40 +61,26 @@ def refresh_themes(no_update=False): return res +@lru_cache(maxsize=1024) def list_locales(): return ['Auto', 'en: English', 'hr: Croatian', 'de: German', 'es: Spanish', 'fr: French', 'it: Italian', 'pt: Portuguese', 'zh: Chinese', 'ja: Japanese', 'ko: Korean', 'ru: Russian'] +@lru_cache(maxsize=1024) def list_themes(): - extensions = [e.name for e in modules.extensions.extensions if e.enabled] - if 'sd-webui-lobe-theme' in extensions and modules.shared.opts.gradio_theme == 'lobe': - themes = ['lobe'] - modules.shared.opts.data['gradio_theme'] = themes[0] - modules.shared.opts.data['theme_type'] = 'None' - log.info('UI theme: extension="lobe"') - elif 'Cozy-Nest' in extensions and modules.shared.opts.gradio_theme == 'cozy-nest': - themes = ['cozy-nest'] - modules.shared.opts.data['gradio_theme'] = themes[0] - modules.shared.opts.data['theme_type'] = 'None' - log.info('UI theme: extension="cozy-nest"') - elif modules.shared.opts.theme_type == 'None': + if opts.theme_type.lower() == 'none': gradio = ["gradio/default", "gradio/base", "gradio/glass", "gradio/monochrome", "gradio/soft"] huggingface = refresh_themes(no_update=True) huggingface = {x['id'] for x in huggingface if x['status'] == 'RUNNING' and 'test' not in x['id'].lower()} huggingface = [f'huggingface/{x}' for x in huggingface] themes = sorted(gradio) + sorted(huggingface, key=str.casefold) - elif modules.shared.opts.theme_type == 'Standard': + elif opts.theme_type.lower() == 'standard': builtin = list_builtin_themes() themes = sorted(builtin) - elif modules.shared.opts.theme_type == 'Modern': - ext = next((e for e in modules.extensions.extensions if e.name == 'sdnext-modernui'), None) - if ext is None: - log.error('UI themes: ModernUI not found') - builtin = list_builtin_themes() - themes = sorted(builtin) - modules.shared.opts.theme_type = 'Standard' - return themes - folder = os.path.join(ext.path, 'themes') + elif opts.theme_type.lower() == 'modern': + # ext = next((e for e in modules.extensions.extensions if e.name == 'sdnext-modernui'), None) + # folder = os.path.join(ext.path, 'themes') + folder = os.path.join('extensions-builtin', 'sdnext-modernui', 'themes') themes = [] if os.path.exists(folder): for f in os.listdir(folder): @@ -92,14 +90,22 @@ def list_themes(): themes.append('modern/Default') themes = sorted(themes) else: - log.error(f'UI themes: type={modules.shared.opts.theme_type} unknown') + log.error(f'UI themes: type={opts.theme_type} unknown') themes = [] return themes -def reload_gradio_theme(): - global gradio_theme # pylint: disable=global-statement - theme_name = modules.shared.opts.gradio_theme +def reload_gradio_theme(_opts, _cmd_opts): + global opts, gradio_theme # pylint: disable=global-statement + if _opts is not None: + opts = _opts + if _cmd_opts is not None: + if _cmd_opts.theme is not None: + if '/' in _cmd_opts.theme: + opts.theme_type, opts.gradio_theme = _cmd_opts.theme.split('/', 1) + else: + opts.theme_type = _cmd_opts.theme + theme_name = opts.gradio_theme default_font_params: FontParams = { 'font':['Helvetica', 'ui-sans-serif', 'system-ui', 'sans-serif'], 'font_mono':['IBM Plex Mono', 'ui-monospace', 'Consolas', 'monospace'] @@ -107,33 +113,30 @@ def reload_gradio_theme(): gradio_theme = gr.themes.Base(**default_font_params) available_themes = list_themes() if theme_name not in available_themes: - # log.error(f'UI theme invalid: type={modules.shared.opts.theme_type} theme="{theme_name}"') - if modules.shared.opts.theme_type == 'Standard': + # log.error(f'UI theme invalid: type={opts.theme_type} theme="{theme_name}"') + if opts.theme_type.lower() == 'standard': theme_name = 'black-teal' - elif modules.shared.opts.theme_type == 'Modern': - theme_name = 'Default' - elif modules.shared.opts.theme_type == 'None': + elif opts.theme_type.lower() == 'none': theme_name = 'gradio/default' else: - modules.shared.opts.theme_type = 'Standard' - theme_name = 'black-teal' + opts.theme_type = 'modern' + theme_name = 'Default' - modules.shared.opts.data['gradio_theme'] = theme_name - log.info(f'UI locale: name="{modules.shared.opts.ui_locale}"') + opts.gradio_theme = theme_name + log.info(f'UI locale: name="{opts.ui_locale}"') - if theme_name.lower() in ['lobe', 'cozy-nest']: - log.info(f'UI theme extension: name="{theme_name}"') - return None - elif modules.shared.opts.theme_type == 'Standard': + if opts.theme_type.lower() == 'standard': gradio_theme = gr.themes.Base(**default_font_params) - log.info(f'UI theme: type={modules.shared.opts.theme_type} name="{theme_name}" available={len(available_themes)}') + log.debug(f'UI theme: type={opts.theme_type} available={len(available_themes)}') log.warning('UI theme: please switch to ModernUI for best experience') return 'sdnext.css' - elif modules.shared.opts.theme_type == 'Modern': + + if opts.theme_type.lower() == 'modern': gradio_theme = gr.themes.Base(**default_font_params) - log.info(f'UI theme: type={modules.shared.opts.theme_type} name="{theme_name}" available={len(available_themes)}') + log.debug(f'UI theme: type={opts.theme_type} available={len(available_themes)}') return 'base.css' - elif modules.shared.opts.theme_type == 'None': + + if opts.theme_type.lower() == 'none': if theme_name.startswith('gradio/'): log.warning('UI theme: using Gradio default theme which is not optimized for SD.Next') if theme_name == "gradio/default": @@ -158,8 +161,9 @@ def reload_gradio_theme(): except Exception as e: log.error(f"UI theme: download error accessing HuggingFace {e}") gradio_theme = gr.themes.Default(**default_font_params) - log.info(f'UI theme: type={modules.shared.opts.theme_type} name="{theme_name}" style={modules.shared.opts.theme_style}') + log.debug(f'UI theme: type={opts.theme_type} style={opts.theme_style}') log.warning('UI theme: please switch to ModernUI for best experience') return 'base.css' - log.error(f'UI theme: type={modules.shared.opts.theme_type} unknown') + + log.error(f'UI theme: type={opts.theme_type} unknown') return None diff --git a/modules/timer.py b/modules/timer.py index 2cdecc87e..daacd1e7d 100644 --- a/modules/timer.py +++ b/modules/timer.py @@ -106,4 +106,5 @@ launch = Timer() init = Timer() load = Timer() dynamo = Timer() +blocks = Timer() autotune = Timer(profile=True) diff --git a/modules/todo/todo_merge.py b/modules/todo/todo_merge.py index 158bc36b1..c866f1391 100644 --- a/modules/todo/todo_merge.py +++ b/modules/todo/todo_merge.py @@ -29,8 +29,6 @@ def init_generator(device: torch.device, fallback: torch.Generator = None): return torch.Generator(device="cpu").set_state(torch.get_rng_state()) elif device.type == "cuda": return torch.Generator(device=device).set_state(torch.cuda.get_rng_state()) - elif device.type == "cuda": - return torch.Generator(device=device).set_state(torch.mps.get_rng_state()) else: if fallback is None: return init_generator(torch.device("cpu")) diff --git a/modules/transformer_cache.py b/modules/transformer_cache.py index 0c204ff9f..0fa1a1bc4 100644 --- a/modules/transformer_cache.py +++ b/modules/transformer_cache.py @@ -1,52 +1,132 @@ import os import diffusers -from modules import shared, errors +from modules import shared, errors, processing, devices +from modules.sd_offload_utils import get_module_names from modules.logger import log debug = log.trace if os.environ.get('SD_PROCESS_DEBUG', None) is not None else lambda *args, **kwargs: None -def set_cache(faster_cache=None, pyramid_attention_broadcast=None): - if not shared.sd_loaded or not hasattr(shared.sd_model, 'transformer'): +def get_transformers(): + if not shared.sd_loaded: + return [] + modules = [] + for module_name in get_module_names(shared.sd_model): + module = getattr(shared.sd_model, module_name, None) + if (module is not None) and ('transformer' in module_name or 'Transformer' in module.__class__.__name__): + modules.append(module) + return modules + + +def set_cache(p: processing.StableDiffusionProcessing): + if not shared.sd_loaded: return - faster_cache = faster_cache if faster_cache is not None else shared.opts.faster_cache_enabled - pyramid_attention_broadcast = pyramid_attention_broadcast if pyramid_attention_broadcast is not None else shared.opts.pab_enabled - if (not faster_cache) and (not pyramid_attention_broadcast): - return - if (not hasattr(shared.sd_model.transformer, 'enable_cache')) or (not hasattr(shared.sd_model.transformer, 'disable_cache')): - log.debug(f'Transformer cache: cls={shared.sd_model.transformer.__class__.__name__} fc={faster_cache} pab={pyramid_attention_broadcast} not supported') - return - try: - if faster_cache: # https://github.com/huggingface/diffusers/pull/10163 - distilled = shared.opts.fc_guidance_distilled - config = diffusers.FasterCacheConfig( - spatial_attention_block_skip_range=shared.opts.fc_spacial_skip_range, - spatial_attention_timestep_skip_range=(int(shared.opts.fc_spacial_skip_start), int(shared.opts.fc_spacial_skip_end)), - unconditional_batch_skip_range=shared.opts.fc_uncond_skip_range, - unconditional_batch_timestep_skip_range=(int(shared.opts.fc_uncond_skip_start), int(shared.opts.fc_uncond_skip_end)), - attention_weight_callback=lambda _: shared.opts.fc_attention_weight, - tensor_format=shared.opts.fc_tensor_format, - is_guidance_distilled=distilled, - current_timestep_callback=lambda: shared.sd_model.current_timestep, - ) - shared.sd_model.transformer.disable_cache() - shared.sd_model.transformer.enable_cache(config) - log.debug(f'Transformer cache: type={config.__class__.__name__}') - debug(f'Transformer cache: {vars(config)}') - elif pyramid_attention_broadcast: # https://github.com/huggingface/diffusers/pull/9562 - config = diffusers.PyramidAttentionBroadcastConfig( - spatial_attention_block_skip_range=shared.opts.pab_spacial_skip_range, - spatial_attention_timestep_skip_range=(int(shared.opts.pab_spacial_skip_start), int(shared.opts.pab_spacial_skip_end)), - current_timestep_callback=lambda: shared.sd_model.current_timestep, - ) - shared.sd_model.transformer.disable_cache() - shared.sd_model.transformer.enable_cache(config) - log.debug(f'Transformer cache: type={config.__class__.__name__}') - debug(f'Transformer cache: {vars(config)}') - else: - debug('Transformer cache: not enabled') - shared.sd_model.transformer.disable_cache() - except Exception as e: - log.error(f'Transformer cache: {e}') - errors.display(e, 'Transformer cache') + for module in get_transformers(): + try: + + if shared.opts.fc_enabled: + config = diffusers.hooks.FasterCacheConfig( + spatial_attention_block_skip_range=int(shared.opts.fc_spacial_skip_range), + spatial_attention_timestep_skip_range=(int(shared.opts.fc_spacial_skip_start), int(shared.opts.fc_spacial_skip_end)), + unconditional_batch_skip_range=int(shared.opts.fc_uncond_skip_range), + unconditional_batch_timestep_skip_range=(int(shared.opts.fc_uncond_skip_start), int(shared.opts.fc_uncond_skip_end)), + attention_weight_callback=lambda _: float(shared.opts.fc_attention_weight), + tensor_format=str(shared.opts.fc_tensor_format), + is_guidance_distilled=bool(shared.opts.fc_guidance_distilled), + current_timestep_callback=lambda: shared.sd_model.current_timestep, + ) + if getattr(shared.sd_model, 'cache_applied', None) == config: + return + if hasattr(module, 'disable_cache'): + module.disable_cache() + shared.sd_model.cache_applied = config + if not hasattr(shared.sd_model, 'current_timestep'): + log.warning(f'Transformer cache: method=FasterCache cls={shared.sd_model.__class__.__name__} not compatible') + else: + diffusers.hooks.apply_faster_cache(module, config) + log.debug(f'Transformer cache: method=FasterCache module={module.__class__.__name__} config={config}') + + if shared.opts.pab_enabled: + config = diffusers.hooks.PyramidAttentionBroadcastConfig( + spatial_attention_block_skip_range=int(shared.opts.pab_spacial_skip_range) if shared.opts.pab_spacial_skip_range > 0 else None, + spatial_attention_timestep_skip_range=(int(shared.opts.pab_spacial_skip_start), int(shared.opts.pab_spacial_skip_end)), + current_timestep_callback=lambda: shared.sd_model.current_timestep, + ) + if getattr(shared.sd_model, 'cache_applied', None) == config: + return + if hasattr(module, 'disable_cache'): + module.disable_cache() + shared.sd_model.cache_applied = config + if not hasattr(shared.sd_model, 'current_timestep'): + log.warning(f'Transformer cache: method=PyramidAttentionBroadcast cls={shared.sd_model.__class__.__name__} not compatible') + else: + diffusers.hooks.apply_pyramid_attention_broadcast(module, config) + log.debug(f'Transformer cache: method=PyramidAttentionBroadcast module={module.__class__.__name__} config={config}') + + if shared.opts.ls_enabled: + config = diffusers.hooks.LayerSkipConfig( + indices=[int(i.strip()) for i in shared.opts.ls_indices.split(',') if i.strip().isnumeric()], + fqn=str(shared.opts.ls_fqn), + skip_attention=bool(shared.opts.ls_skip_attention), + skip_attention_scores=bool(shared.opts.ls_skip_attention_scores), + skip_ff=bool(shared.opts.ls_skip_ff), + dropout=float(shared.opts.ls_dropout), + ) + if getattr(shared.sd_model, 'cache_applied', None) == config: + return + if hasattr(module, 'disable_cache'): + module.disable_cache() + shared.sd_model.cache_applied = config + diffusers.hooks.apply_layer_skip(module, config) + log.debug(f'Transformer cache: method=LayerSkip module={module.__class__.__name__} config={config}') + + if shared.opts.mc_enabled: + config = diffusers.hooks.MagCacheConfig( + threshold=float(shared.opts.mc_threshold), + max_skip_steps=int(shared.opts.mc_max_skip_steps), + retention_ratio=float(shared.opts.mc_retention_ratio), + num_inference_steps=int(p.steps) + ) + if getattr(shared.sd_model, 'cache_applied', None) == config: + return + if hasattr(module, 'disable_cache'): + module.disable_cache() + shared.sd_model.cache_applied = config + diffusers.hooks.apply_mag_cache(module, config) + log.debug(f'Transformer cache: method=MagCache module={module.__class__.__name__} config={config}') + + if shared.opts.ts_enabled: + config = diffusers.hooks.TaylorSeerCacheConfig( + cache_interval=int(shared.opts.ts_cache_interval), + disable_cache_before_step=int(shared.opts.ts_disable_cache_before_step), + disable_cache_after_step=int(shared.opts.ts_disable_cache_after_step), + max_order=int(shared.opts.ts_max_order), + taylor_factors_dtype=devices.dtype, + skip_predict_identifiers=[i.strip() for i in shared.opts.ts_skip_predict_identifiers.split(',') if i.strip()], + cache_identifiers=[i.strip() for i in shared.opts.ts_cache_identifiers.split(',') if i.strip()], + use_lite_mode=bool(shared.opts.ts_use_lite_mode), + ) + if getattr(shared.sd_model, 'cache_applied', None) == config: + return + if hasattr(module, 'disable_cache'): + module.disable_cache() + shared.sd_model.cache_applied = config + diffusers.hooks.apply_taylorseer_cache(module, config) + log.debug(f'Transformer cache: method=TaylorSeerCache module={module.__class__.__name__} config={config}') + + if shared.opts.fb_enabled: + config = diffusers.hooks.FirstBlockCacheConfig( + threshold=float(shared.opts.fb_threshold), + ) + if getattr(shared.sd_model, 'cache_applied', None) == config: + return + if hasattr(module, 'disable_cache'): + module.disable_cache() + shared.sd_model.cache_applied = config + diffusers.hooks.apply_first_block_cache(module, config) + log.debug(f'Transformer cache: method=FirstBlockCache module={module.__class__.__name__} config={config}') + + except Exception as e: + log.error(f'Transformer cache: {e}') + errors.display(e, 'Transformer cache') diff --git a/modules/txt2img.py b/modules/txt2img.py index c79433443..4c333f0fa 100644 --- a/modules/txt2img.py +++ b/modules/txt2img.py @@ -16,8 +16,7 @@ def txt2img(id_task, state, vae_type, tiling, hidiffusion, detailer_enabled, detailer_prompt, detailer_negative, detailer_steps, detailer_strength, detailer_resolution, detailer_classes, n_iter, batch_size, - guidance_name, guidance_scale, guidance_rescale, guidance_start, guidance_stop, - cfg_scale, cfg_image, cfg_rescale, cfg_true, cfg_adaptive, cfg_end, + cfg_name, cfg_scale, cfg_image, cfg_rescale, cfg_start, cfg_stop, cfg_true, cfg_adaptive, clip_skip, seed, subseed, subseed_strength, seed_resize_from_h, seed_resize_from_w, height, width, @@ -42,7 +41,7 @@ def txt2img(id_task, state, if sampler_index is None: log.warning('Sampler: invalid') sampler_index = 0 - if hr_sampler_index is None: + if hr_sampler_index is None or hr_sampler_index == 'Same as primary': hr_sampler_index = sampler_index p = processing.StableDiffusionProcessingTxt2Img( @@ -62,17 +61,14 @@ def txt2img(id_task, state, batch_size=batch_size, n_iter=n_iter, steps=steps, - guidance_name=guidance_name, - guidance_scale=guidance_scale, - guidance_rescale=guidance_rescale, - guidance_start=guidance_start, - guidance_stop=guidance_stop, + cfg_name=cfg_name, cfg_scale=cfg_scale, cfg_image=cfg_image, cfg_rescale=cfg_rescale, + cfg_start=cfg_start, + cfg_stop=cfg_stop, cfg_true=cfg_true, cfg_adaptive=cfg_adaptive, - cfg_end=cfg_end, clip_skip=clip_skip, width=width, height=height, diff --git a/modules/ui_common.py b/modules/ui_common.py index ad2612868..000194773 100644 --- a/modules/ui_common.py +++ b/modules/ui_common.py @@ -18,6 +18,21 @@ debug('Trace: PASTE') warn_once_set = WeakSet() +def filter_ui_choices(choices: list[str], preferences: list[str] | None = None, selected: str | None = None) -> tuple[list[str], bool]: + """Return display choices while preserving the current selection.""" + available = list(dict.fromkeys(choices)) + preferred = set(preferences or []) + filtered = [choice for choice in available if choice in preferred] + if not filtered: + return available, False + if selected in available and selected not in filtered: + filtered.append(selected) + if 'None' in filtered: + filtered.remove('None') + filtered.insert(0, 'None') + return filtered, len(filtered) < len(available) + + def gr_show(visible=True): return {"visible": visible, "__type__": "update"} diff --git a/modules/ui_control.py b/modules/ui_control.py index 11bda73bf..269e00aad 100644 --- a/modules/ui_control.py +++ b/modules/ui_control.py @@ -201,7 +201,7 @@ def create_ui(_blocks: gr.Blocks=None): mask_controls = masking.create_segment_ui() - guidance_name, guidance_scale, guidance_rescale, guidance_start, guidance_stop, cfg_scale, cfg_image, cfg_rescale, cfg_true, cfg_adaptive, cfg_end = ui_guidance.create_guidance_inputs('control') + cfg_name, cfg_scale, cfg_image, cfg_rescale, cfg_start, cfg_stop, cfg_true, cfg_adaptive = ui_guidance.create_guidance_inputs('control') vae_type, tiling, hidiffusion, clip_skip = ui_sections.create_advanced_inputs('control') grading_brightness, grading_contrast, grading_saturation, grading_hue, grading_gamma, grading_sharpness, grading_color_temp, grading_shadows, grading_midtones, grading_highlights, grading_clahe_clip, grading_clahe_grid, grading_shadows_tint, grading_highlights_tint, grading_split_tone_balance, grading_vignette, grading_grain, grading_lut_file, grading_lut_strength = ui_sections.create_color_inputs('control') hdr_mode, hdr_brightness, hdr_color, hdr_sharpen, hdr_clamp, hdr_boundary, hdr_threshold, hdr_maximize, hdr_max_center, hdr_max_boundary, hdr_color_picker, hdr_tint_ratio, hdr_apply_hires = ui_sections.create_latent_inputs('control') @@ -316,8 +316,8 @@ def create_ui(_blocks: gr.Blocks=None): prompt, negative, styles, steps, sampler_index, seed, subseed, subseed_strength, seed_resize_from_h, seed_resize_from_w, - guidance_name, guidance_scale, guidance_rescale, guidance_start, guidance_stop, - cfg_scale, clip_skip, cfg_image, cfg_rescale, cfg_true, cfg_adaptive, cfg_end, vae_type, tiling, hidiffusion, + cfg_name, cfg_scale, cfg_image, cfg_rescale, cfg_start, cfg_stop, cfg_true, cfg_adaptive, + clip_skip, vae_type, tiling, hidiffusion, detailer_enabled, detailer_prompt, detailer_negative, detailer_steps, detailer_strength, detailer_resolution, detailer_classes, hdr_mode, hdr_brightness, hdr_color, hdr_sharpen, hdr_clamp, hdr_boundary, hdr_threshold, hdr_maximize, hdr_max_center, hdr_max_boundary, hdr_color_picker, hdr_tint_ratio, hdr_apply_hires, grading_brightness, grading_contrast, grading_saturation, grading_hue, grading_gamma, grading_sharpness, grading_color_temp, @@ -411,18 +411,17 @@ def create_ui(_blocks: gr.Blocks=None): (mask_controls[5], "Mask dilate"), (mask_controls[6], "Mask auto"), # guidance - (guidance_name, "Guidance"), - (guidance_scale, "Guidance scale"), - (guidance_rescale, "Guidance rescale"), - (guidance_start, "Guidance start"), - (guidance_stop, "Guidance stop"), - # advanced + (cfg_name, "CFG name"), (cfg_scale, "CFG scale"), - (cfg_end, "CFG end"), - (clip_skip, "CLiP-skip"), + (cfg_start, "CFG start"), + (cfg_stop, "CFG stop"), + (cfg_stop, "CFG end"), + (cfg_image, "CFG image"), (cfg_image, "Image CFG scale"), (cfg_image, "Hires CFG scale"), (cfg_rescale, "CFG rescale"), + # other + (clip_skip, "CLiP-skip"), (vae_type, "VAE type"), (tiling, "Tiling"), (hidiffusion, "HiDiffusion"), diff --git a/modules/ui_definitions.py b/modules/ui_definitions.py index 8f8a6be97..464c1935e 100644 --- a/modules/ui_definitions.py +++ b/modules/ui_definitions.py @@ -26,23 +26,23 @@ def list_onnx_providers(): def list_checkpoint_titles(): - import modules.sd_models # pylint: disable=redefined-outer-name - return modules.sd_models.checkpoint_titles() + from modules.sd_models import checkpoint_titles # pylint: disable=redefined-outer-name + return checkpoint_titles() def refresh_checkpoints(): - import modules.sd_models # pylint: disable=redefined-outer-name - return modules.sd_models.list_models() + from modules.sd_models import list_models # pylint: disable=redefined-outer-name + return list_models() def refresh_vaes(): - import modules.sd_vae # pylint: disable=redefined-outer-name - modules.sd_vae.refresh_vae_list() + from modules.sd_vae import refresh_vae_list # pylint: disable=redefined-outer-name + refresh_vae_list() def refresh_upscalers(): - import modules.modelloader # pylint: disable=redefined-outer-name - modules.modelloader.load_upscalers() + from modules.modelloader import load_upscalers # pylint: disable=redefined-outer-name + load_upscalers() def list_samplers(): @@ -51,6 +51,11 @@ def list_samplers(): return modules.sd_samplers.all_samplers +def list_upscalers(): + from modules import shared # pylint: disable=redefined-outer-name + return [upscaler.name for upscaler in shared.sd_upscalers] + + def get_openvino_device_list(): try: import modules.intel.openvino # pylint: disable=redefined-outer-name @@ -63,7 +68,7 @@ def create_settings(cmd_opts): # Calculate default modes mem_stat = memory_stats() - startup_offload_mode, startup_offload_min_gpu, startup_offload_max_gpu, startup_cross_attention, startup_sdp_options, startup_sdp_choices, startup_sdp_override_options, startup_sdp_override_choices, startup_offload_always, startup_offload_never = get_default_modes(cmd_opts=cmd_opts, mem_stat=mem_stat) + startup_offload_mode, startup_offload_min_gpu, startup_offload_max_gpu, startup_cross_attention, startup_sdp_options, startup_sdp_choices, startup_offload_always, startup_offload_never = get_default_modes(cmd_opts=cmd_opts, mem_stat=mem_stat) # System variables gpu_memory = round(mem_stat['gpu']['total'] if "gpu" in mem_stat else 0) @@ -72,7 +77,7 @@ def create_settings(cmd_opts): default_hfcache_dir = os.environ.get("SD_HFCACHEDIR", None) or os.path.join(paths.models_path, 'huggingface') default_checkpoint = list_checkpoint_titles()[0] if len(list_checkpoint_titles()) > 0 else "model.safetensors" - default_xetcache_dir = os.environ.get("HF_XET_CACHE ", None) or os.path.join(paths.models_path, 'xet') + default_xetcache_dir = os.environ.get("HF_XET_CACHE", None) or os.path.join(paths.models_path, 'xet') default_onnx_execution_provider, default_onnx_execution_providers = list_onnx_providers() @@ -90,6 +95,7 @@ def create_settings(cmd_opts): "advanced_sep": OptionInfo("

Advanced Options

", "", gr.HTML), "sd_checkpoint_autoload": OptionInfo(True, "Model auto-load on start"), + "model_modular_enable": OptionInfo(False, "Model convert to modular pipelines"), "sd_parallel_load": OptionInfo(True, "Model load using multiple threads"), "sd_checkpoint_autodownload": OptionInfo(True, "Model auto-download on demand"), "stream_load": OptionInfo(False, "Model load using streams", gr.Checkbox), @@ -107,12 +113,13 @@ def create_settings(cmd_opts): # --- Model Options --- options_templates.update(options_section(('model_options', "Model Options"), { "model_modular_sep": OptionInfo("

Modular Pipelines

", "", gr.HTML), - "model_modular_enable": OptionInfo(False, "Enable modular pipelines (experimental)"), "model_google_sep": OptionInfo("

Google GenAI

", "", gr.HTML), "google_use_vertexai": OptionInfo(False, "Google cloud use VertexAI endpoints"), "google_api_key": OptionInfo("", "Google cloud API key", gr.Textbox, secret=True, env_var='GOOGLE_API_KEY'), "google_project_id": OptionInfo("", "Google Cloud project ID", gr.Textbox, secret=True, env_var='GOOGLE_PROJECT_ID'), "google_location_id": OptionInfo("", "Google Cloud location ID", gr.Textbox), + "model_xai_sep": OptionInfo("

XAI Grok

", "", gr.HTML), + "xai_api_key": OptionInfo("", "XAI Grok API key", gr.Textbox, secret=True, env_var='XAI_API_KEY'), "model_krea2_sep": OptionInfo("

Krea 2

", "", gr.HTML), "model_krea2_dense": OptionInfo(False, "Use dense masking"), "model_sd3_sep": OptionInfo("

Stable Diffusion 3.x

", "", gr.HTML), @@ -155,7 +162,7 @@ def create_settings(cmd_opts): "group_offload_type": OptionInfo("leaf_level", "Group offload type", gr.Radio, {"choices": ['leaf_level', 'block_level']}), "group_offload_stream": OptionInfo(False, "Prefetch with streams", gr.Checkbox), 'group_offload_record': OptionInfo(False, "Overlap stream transfers", gr.Checkbox), - 'group_offload_pin': OptionInfo(True, "Pin offload memory", gr.Checkbox), + 'group_offload_pin': OptionInfo(False, "Pin offload memory", gr.Checkbox), 'group_offload_blocks': OptionInfo(1, "Group offload blocks", gr.Number), "caption_offload_sep": OptionInfo("

Caption Model Offloading

", "", gr.HTML), "caption_offload": OptionInfo(True, "Offload caption models"), @@ -194,8 +201,8 @@ def create_settings(cmd_opts): "sdnq_quantize_shuffle_weights": OptionInfo(False, "Shuffle weights in post mode", gr.Checkbox), "nunchaku_sep": OptionInfo("

Nunchaku Engine

", "", gr.HTML), - "nunchaku_attention": OptionInfo(False, "Nunchaku attention", gr.Checkbox), - "nunchaku_offload": OptionInfo(False, "Nunchaku offloading", gr.Checkbox), + "nunchaku_attention": OptionInfo(True, "Nunchaku attention", gr.Checkbox), + "nunchaku_offload": OptionInfo(True, "Nunchaku offloading", gr.Checkbox), "layerwise_quantization_sep": OptionInfo("

Layerwise Casting

", "", gr.HTML), "layerwise_quantization": OptionInfo([], "Layerwise casting enabled", gr.CheckboxGroup, {"choices": ["Model", "TE"]}), @@ -206,6 +213,7 @@ def create_settings(cmd_opts): "trt_quantization": OptionInfo([], "Quantization enabled", gr.CheckboxGroup, {"choices": ["Model"]}), "trt_quantization_type": OptionInfo("int8", "Quantization type", gr.Dropdown, {"choices": ["int8", "int4", "fp8", "nf4", "nvfp4"]}), })) + # --- VAE & Text Encoder --- options_templates.update(options_section(('vae_encoder', "Variational Auto Encoder"), { "sd_vae": OptionInfo("Automatic", "VAE model", gr.Dropdown, lambda: {"choices": shared_items.sd_vae_items()}, refresh=shared_items.refresh_vae_list), @@ -234,26 +242,18 @@ def create_settings(cmd_opts): })) # --- Compute Settings --- - options_templates.update(options_section(('cuda', "Compute Settings"), { - "math_sep": OptionInfo("

Execution Precision

", "", gr.HTML), - "precision": OptionInfo("Autocast", "Precision type", gr.Radio, {"choices": ["Autocast", "Full"], "visible": False}), - "cuda_dtype": OptionInfo("Auto", "Device precision type", gr.Radio, {"choices": ["Auto", "FP32", "FP16", "BF16"]}), - "force_dtype": OptionInfo(False, "Force dtype on load", None, None, None), - "no_half": OptionInfo(False, "Force full precision (--no-half)", None, None, None), - "upcast_sampling": OptionInfo(False if sys.platform != "darwin" else True, "Upcast sampling", gr.Checkbox, {"visible": False}), - - "generator_sep": OptionInfo("

Noise Options

", "", gr.HTML), - "diffusers_generator_device": OptionInfo("GPU", "Generator device", gr.Radio, {"choices": ["GPU", "CPU", "Unset"]}), - - "cross_attention_sep": OptionInfo("

Cross Attention

", "", gr.HTML), + options_templates.update(options_section(('cuda', "Cross Attention"), { "cross_attention_optimization": OptionInfo(startup_cross_attention, "Attention method", gr.Radio, lambda: {"choices": shared_items.list_crossattention()}), - "sdp_options": OptionInfo(startup_sdp_options, "SDP kernels", gr.CheckboxGroup, {"choices": startup_sdp_choices}), - "sdp_overrides": OptionInfo(startup_sdp_override_options, "SDP overrides", gr.CheckboxGroup, {"choices": startup_sdp_override_choices}), + # "sdp_overrides": OptionInfo(startup_sdp_override_options, "SDP overrides", gr.CheckboxGroup, {"choices": startup_sdp_override_choices}), + + "attention_slicing_sep": OptionInfo("

Attention Slicing

", "", gr.HTML), "attention_slicing": OptionInfo('Default', "Attention slicing", gr.Radio, {"choices": ['Default', 'Enabled', 'Disabled']}), - "xformers_options": OptionInfo(['Flash attention'], "xFormers options", gr.CheckboxGroup, {"choices": ['Flash attention'] }), "dynamic_attention_slice_rate": OptionInfo(0.5, "Dynamic Attention slicing rate", gr.Slider, {"minimum": 0.01, "maximum": max(gpu_memory,4), "step": 0.01}), "dynamic_attention_trigger_rate": OptionInfo(1, "Dynamic Attention trigger rate", gr.Slider, {"minimum": 0.01, "maximum": max(gpu_memory,4)*2, "step": 0.01}), + "sdp_attention_sep": OptionInfo("

SDP Attention

", "", gr.HTML), + "sdp_options": OptionInfo(startup_sdp_options, "SDP kernels", gr.CheckboxGroup, {"choices": startup_sdp_choices}), + "sdnq_attention_sep": OptionInfo("

SDNQ Attention

", "", gr.HTML), "sdnq_attention_smooth_k": OptionInfo(True, "SDNQ Attention use Smooth K", gr.Checkbox), "sdnq_attention_use_hadamard": OptionInfo(False, "SDNQ Attention use Hadamard", gr.Checkbox), @@ -263,26 +263,38 @@ def create_settings(cmd_opts): "sdnq_attention_pv_matmul_type": OptionInfo("disabled", "SDNQ Attention PV MatMul type", gr.Radio, {"choices": sdnq_matmul_modes}), "sdnq_attention_hadamard_group_size": OptionInfo(256, "SDNQ Attention Hadamard Group Size", gr.Slider, {"minimum": 4, "maximum": 1024, "step": 1}), + "sparse_attention_sep": OptionInfo("

Sparse Attention

", "", gr.HTML), + "sparse_attention_enabled": OptionInfo(False, "Sparse Attention", gr.Checkbox), + "sparse_attention_budget": OptionInfo(30, "Sparse Attention KV budget", gr.Slider, {"minimum": 5, "maximum": 100, "step": 5}), + "sparse_attention_min_tokens": OptionInfo(8192, "Sparse Attention minimum sequence", gr.Slider, {"minimum": 0, "maximum": 32768, "step": 1024}), + "sparse_attention_schedule_steps": OptionInfo(0, "Sparse Attention dense steps", gr.Slider, {"minimum": 0, "maximum": 10, "step": 1}), + "sparse_attention_schedule_bump": OptionInfo(30, "Sparse Attention dense step bonus", gr.Slider, {"minimum": 0, "maximum": 70, "step": 5}), + "sparse_attention_head_shared": OptionInfo(False, "Sparse Attention share selection across heads", gr.Checkbox), + "sparse_attention_exclude": OptionInfo("CosmosTransformer3DModel", "Sparse Attention excluded models", gr.Textbox), + "hf_attention_sep": OptionInfo("

Attention Dispatcher

", "", gr.HTML), "hf_attention": OptionInfo('', "Attention dispatcher kernel", gr.Textbox), })) - # --- Server Settings --- - options_templates.update(options_section(('server', "Server Settings"), { - "server_listen": OptionInfo(False, "Listen on all interfaces", gr.Checkbox), - "server_status": OptionInfo(120, "Automatic server status monitor rate", gr.Number, {"minimum": 0, "maximum": 1000, "step": 1}), - "server_monitor": OptionInfo(0, "Automatic server memory monitor rate", gr.Number, {"minimum": 0, "maximum": 1000, "step": 1}), - "server_rate_limit": OptionInfo(300, "API base rate limit rate", gr.Number, {"minimum": 0, "maximum": 1000, "step": 1}), - })) - # --- Backend Settings --- - options_templates.update(options_section(('backends', "Backend Settings"), { + options_templates.update(options_section(('backends', "Compute Settings"), { + "math_sep": OptionInfo("

Execution Precision

", "", gr.HTML), + "precision": OptionInfo("Autocast", "Precision type", gr.Radio, {"choices": ["Autocast", "Full"], "visible": False}), + "cuda_dtype": OptionInfo("Auto", "Device precision type", gr.Radio, {"choices": ["Auto", "FP32", "FP16", "BF16"]}), + "force_dtype": OptionInfo(False, "Force dtype on load", None, None, None), + "no_half": OptionInfo(False, "Force full precision (--no-half)", None, None, None), + "upcast_sampling": OptionInfo(False if sys.platform != "darwin" else True, "Upcast sampling", gr.Checkbox, {"visible": False}), + + "generator_sep": OptionInfo("

Noise Options

", "", gr.HTML), + "diffusers_generator_device": OptionInfo("GPU", "Generator device", gr.Radio, {"choices": ["GPU", "CPU", "Unset"]}), + "other_sep": OptionInfo("

Torch Options

", "", gr.HTML), "opt_channelslast": OptionInfo(False, "Channels last "), "cudnn_deterministic": OptionInfo(False, "Deterministic mode"), "diffusers_fuse_projections": OptionInfo(False, "Fused projections"), "torch_expandable_segments": OptionInfo(False, "Expandable segments"), "torch_sync": OptionInfo(True, "Force synchronize"), + "triton_skip_autotune": OptionInfo(False, "Skip Triton autotune", gr.Checkbox), "cudnn_enabled": OptionInfo("default", "cuDNN enabled", gr.Radio, {"choices": ["default", "true", "false"]}), "cudnn_benchmark": OptionInfo(devices.backend != "rocm", "cuDNN full-depth benchmark"), "cudnn_benchmark_limit": OptionInfo(10, "cuDNN benchmark limit", gr.Slider, {"minimum": 0, "maximum": 100, "step": 1}), @@ -297,7 +309,7 @@ def create_settings(cmd_opts): "onnx_execution_provider": OptionInfo(default_onnx_execution_provider, 'ONNX Execution Provider', gr.Dropdown, lambda: {"choices": default_onnx_execution_providers}), "onnx_cpu_fallback": OptionInfo(True, 'ONNX allow fallback to CPU'), "onnx_cache_converted": OptionInfo(True, 'ONNX cache converted models'), - "onnx_unload_base": OptionInfo(False, 'ONNX unload base model when processing refiner'), + "onnx_unload_base": OptionInfo(False, 'ONNX unload base model when processing refiner', gr.Checkbox, {"visible": False}), "olive_sep": OptionInfo("

Olive

", "", gr.HTML), "olive_float16": OptionInfo(True, 'Olive use FP16 on optimization'), @@ -316,8 +328,8 @@ def create_settings(cmd_opts): "openvino_disable_memory_cleanup": OptionInfo(True, "OpenVINO disable memory cleanup", gr.Checkbox, {"visible": cmd_opts.use_openvino}), })) - # --- Pipeline Modifiers --- - options_templates.update(options_section(('advanced', "Pipeline Modifiers"), { + # --- Compute Add-ons --- + options_templates.update(options_section(('advanced', "Compute Add-ons"), { "clip_skip_sep": OptionInfo("

CLiP Skip

", "", gr.HTML), "clip_skip_enabled": OptionInfo(False, "CLiP skip enabled"), @@ -338,20 +350,16 @@ def create_settings(cmd_opts): "pab_sep": OptionInfo("

PAB: Pyramid attention broadcast

", "", gr.HTML), "pab_enabled": OptionInfo(False, "PAB cache enabled"), - "pab_spacial_skip_range": OptionInfo(2, "PAB spacial skip range", gr.Slider, {"minimum": 1, "maximum": 4, "step": 1}), + "pab_spacial_skip_range": OptionInfo(0, "PAB spacial skip range", gr.Slider, {"minimum": 0, "maximum": 4, "step": 1}), "pab_spacial_skip_start": OptionInfo(100, "PAB spacial skip start", gr.Slider, {"minimum": 0, "maximum": 1000, "step": 1}), "pab_spacial_skip_end": OptionInfo(800, "PAB spacial skip end", gr.Slider, {"minimum": 0, "maximum": 1000, "step": 1}), - "cache_dit_sep": OptionInfo("

Cache-DiT

", "", gr.HTML), - "cache_dit_enabled": OptionInfo(False, "Cache-DiT enabled"), - "cache_dit_calibrator": OptionInfo("None", "Cache-DiT calibrator", gr.Radio, {"choices": ["None", "TaylorSeer", "FoCa"]}), - "cache_dit_fcompute": OptionInfo(-1, "Cache-DiT F-compute blocks", gr.Slider, {"minimum": -1, "maximum": 32, "step": 1}), - "cache_dit_bcompute": OptionInfo(-1, "Cache-DiT B-compute blocks", gr.Slider, {"minimum": -1, "maximum": 32, "step": 1}), - "cache_dit_threshold": OptionInfo(-1, "Cache-DiT residual diff threshold", gr.Slider, {"minimum": -1.0, "maximum": 1.0, "step": 0.01}), - "cache_dit_warmup": OptionInfo(-1, "Cache-DiT warmup steps", gr.Slider, {"minimum": -1, "maximum": 50, "step": 1}), + "fb_sep": OptionInfo("

FBC: First Block Cache

", "", gr.HTML), + "fb_enabled": OptionInfo(False, "First Block cache enabled"), + "fb_threshold": OptionInfo(0.05, "First Block cache threshold", gr.Slider, {"minimum": 0.0, "maximum": 1.0, "step": 0.01}), - "faster_cache__sep": OptionInfo("

Faster Cache

", "", gr.HTML), - "faster_cache_enabled": OptionInfo(False, "FasterCache cache enabled"), + "fc_sep": OptionInfo("

FC: Faster Cache

", "", gr.HTML), + "fc_enabled": OptionInfo(False, "FasterCache cache enabled"), "fc_spacial_skip_range": OptionInfo(2, "FasterCache spacial skip range", gr.Slider, {"minimum": 1, "maximum": 4, "step": 1}), "fc_spacial_skip_start": OptionInfo(0, "FasterCache spacial skip start", gr.Slider, {"minimum": 0, "maximum": 1000, "step": 1}), "fc_spacial_skip_end": OptionInfo(681, "FasterCache spacial skip end", gr.Slider, {"minimum": 0, "maximum": 1.0, "step": 0.01}), @@ -362,6 +370,39 @@ def create_settings(cmd_opts): "fc_tensor_format": OptionInfo("BCFHW", "FasterCache tensor format", gr.Radio, {"choices": ["BCFHW", "BFCHW", "BCHW"]}), "fc_guidance_distilled": OptionInfo(False, "FasterCache guidance distilled", gr.Checkbox), + "ls_sep": OptionInfo("

LS: Layer Skip

", "", gr.HTML), + "ls_enabled": OptionInfo(False, "Layer Skip enabled"), + "ls_indices": OptionInfo('', "Layer Skip indices", gr.Textbox, {"placeholder": "e.g. 0,1,2-5"}), + "ls_fqn": OptionInfo("auto", "Layer Skip FQN", gr.Textbox, {"placeholder": "e.g. model.diffusion_model.input_blocks.0"}), + "ls_skip_attention": OptionInfo(True, "Layer Skip skip attention", gr.Checkbox), + "ls_skip_attention_scores": OptionInfo(False, "Layer Skip skip attention scores", gr.Checkbox), + "ls_skip_ff": OptionInfo(True, "Layer Skip skip feedforward", gr.Checkbox), + "ls_dropout": OptionInfo(1.0, "Layer Skip dropout", gr.Slider, {"minimum": 0.0, "maximum": 1.0, "step": 0.01}), + + "mc_sep": OptionInfo("

MC: Mag Cache

", "", gr.HTML), + "mc_enabled": OptionInfo(False, "Mag Cache enabled"), + "mc_threshold": OptionInfo(0.06, "Mag Cache threshold", gr.Slider, {"minimum": 0.0, "maximum": 1.0, "step": 0.01}), + "mc_max_skip_steps": OptionInfo(3, "Mag Cache max skip steps", gr.Slider, {"minimum": 1, "maximum": 10, "step": 1}), + "mc_retention_ratio": OptionInfo(0.2, "Mag Cache retention ratio", gr.Slider, {"minimum": 0.0, "maximum": 1.0, "step": 0.01}), + + "ts_sep": OptionInfo("

TS: TaylorSeer

", "", gr.HTML), + "ts_enabled": OptionInfo(False, "TaylorSeer enabled"), + "ts_cache_interval": OptionInfo(5, "TaylorSeer cache interval", gr.Slider, {"minimum": 1, "maximum": 20, "step": 1}), + "ts_disable_cache_before_step": OptionInfo(3, "TaylorSeer disable cache before step", gr.Slider, {"minimum": 0, "maximum": 20, "step": 1}), + "ts_disable_cache_after_step": OptionInfo(-1, "TaylorSeer disable cache after step", gr.Slider, {"minimum": -1, "maximum": 20, "step": 1}), + "ts_max_order": OptionInfo(1, "TaylorSeer max order", gr.Slider, {"minimum": 1, "maximum": 5, "step": 1}), + "ts_skip_predict_identifiers": OptionInfo("", "TaylorSeer skip predict identifiers", gr.Textbox, {"placeholder": "e.g. model.diffusion_model.input_blocks.0,model.diffusion_model.middle_block"}), + "ts_cache_identifiers": OptionInfo("", "TaylorSeer cache identifiers", gr.Textbox, {"placeholder": "e.g. model.diffusion_model.input_blocks.0,model.diffusion_model.middle_block"}), + "ts_use_lite_mode": OptionInfo(False, "TaylorSeer use lite mode", gr.Checkbox), + + "cache_dit_sep": OptionInfo("

Cache-DiT

", "", gr.HTML), + "cache_dit_enabled": OptionInfo(False, "Cache-DiT enabled"), + "cache_dit_calibrator": OptionInfo("None", "Cache-DiT calibrator", gr.Radio, {"choices": ["None", "TaylorSeer", "FoCa"]}), + "cache_dit_fcompute": OptionInfo(-1, "Cache-DiT F-compute blocks", gr.Slider, {"minimum": -1, "maximum": 32, "step": 1}), + "cache_dit_bcompute": OptionInfo(-1, "Cache-DiT B-compute blocks", gr.Slider, {"minimum": -1, "maximum": 32, "step": 1}), + "cache_dit_threshold": OptionInfo(-1, "Cache-DiT residual diff threshold", gr.Slider, {"minimum": -1.0, "maximum": 1.0, "step": 0.01}), + "cache_dit_warmup": OptionInfo(-1, "Cache-DiT warmup steps", gr.Slider, {"minimum": -1, "maximum": 50, "step": 1}), + "para_sep": OptionInfo("

Para-attention

", "", gr.HTML), "para_cache_enabled": OptionInfo(False, "ParaAttention first-block cache enabled"), "para_diff_threshold": OptionInfo(0.1, "ParaAttention residual diff threshold", gr.Slider, {"minimum": 0.0, "maximum": 1.0, "step": 0.01}), @@ -422,6 +463,14 @@ def create_settings(cmd_opts): "pruna_pruners": OptionInfo([], "Pruna pruners", gr.CheckboxGroup, {"choices": ["kvpress", "padding_pruning", "token_merging", "torch_structured", "torch_unstructured"]}), })) + # --- Server Settings --- + options_templates.update(options_section(('server', "Server Settings"), { + "server_listen": OptionInfo(False, "Listen on all interfaces", gr.Checkbox), + "server_status": OptionInfo(120, "Automatic server status monitor rate", gr.Number, {"minimum": 0, "maximum": 1000, "step": 1}), + "server_monitor": OptionInfo(0, "Automatic server memory monitor rate", gr.Number, {"minimum": 0, "maximum": 1000, "step": 1}), + "server_rate_limit": OptionInfo(300, "API base rate limit rate", gr.Number, {"minimum": 0, "maximum": 1000, "step": 1}), + })) + # --- System Paths --- options_templates.update(options_section(('system-paths', "System Paths"), { "models_paths_sep_options": OptionInfo("

Models Paths

", "", gr.HTML), @@ -455,6 +504,7 @@ def create_settings(cmd_opts): "openvino_cache_path": OptionInfo('cache', "Folder for OpenVINO cache", folder=True), "onnx_cached_models_path": OptionInfo(os.path.join(paths.models_path, 'ONNX', 'cache'), "Folder for ONNX cached models", folder=True), "onnx_temp_dir": OptionInfo(os.path.join(paths.models_path, 'ONNX', 'temp'), "Folder for ONNX conversion", folder=True), + "dlss_pkg_path": OptionInfo('', "Folder with DLSS package", gr.Textbox, { "visible": False}), })) # --- Image Options --- @@ -542,11 +592,15 @@ def create_settings(cmd_opts): "themes_sep_ui": OptionInfo("

Theme options

", "", gr.HTML), "theme_type": OptionInfo("Modern", "Theme type", gr.Radio, {"choices": ["Modern", "Standard", "None"]}), "theme_style": OptionInfo("Auto", "Theme mode", gr.Radio, {"choices": ["Auto", "Dark", "Light"]}), - "gradio_theme": OptionInfo("black-teal", "UI theme", gr.Dropdown, lambda: {"choices": theme.list_themes()}, refresh=theme.refresh_themes), + "gradio_theme": OptionInfo("Default", "UI theme", gr.Dropdown, lambda: {"choices": theme.list_themes()}, refresh=theme.refresh_themes), "quicksetting_sep_images": OptionInfo("

Quicksettings

", "", gr.HTML), "quicksettings_list": OptionInfo(["sd_model_checkpoint"], "Quicksettings list", gr.Dropdown, lambda: {"multiselect":True, "choices": list(options_templates.keys())}), + "selections_sep_ui": OptionInfo("

Selections

", "", gr.HTML), + "show_samplers": OptionInfo([], "Show samplers in user interface", gr.Dropdown, lambda: {"multiselect": True, "choices": [x.name for x in list_samplers()]}, refresh=list_samplers), + "show_upscalers": OptionInfo([], "Show upscalers in user interface", gr.Dropdown, lambda: {"multiselect": True, "choices": list_upscalers()}, refresh=refresh_upscalers), + "server_sep_ui": OptionInfo("

Startup & Server Options

", "", gr.HTML), "autolaunch": OptionInfo(False, "Autolaunch browser upon startup"), "motd": OptionInfo(False, "Show MOTD"), @@ -557,7 +611,7 @@ def create_settings(cmd_opts): "ui_disabled": OptionInfo([], "Disabled UI tabs", gr.Dropdown, { 'visible': False }), "cards_sep_ui": OptionInfo("

Networks panel

", "", gr.HTML), - "extra_networks_card_size": OptionInfo(140, "Network card size (px)", gr.Slider, {"minimum": 20, "maximum": 2000, "step": 1}), + "extra_networks_card_size": OptionInfo(130, "Network card size (px)", gr.Slider, {"minimum": 20, "maximum": 2000, "step": 1}), "extra_networks_card_cover": OptionInfo("sidebar", "Network panel position", gr.Radio, {"choices": ["cover", "inline", "sidebar"]}), "extra_networks_card_square": OptionInfo(True, "Disable variable aspect ratio"), @@ -602,6 +656,7 @@ def create_settings(cmd_opts): "live_preview_refresh_period": OptionInfo(500, "Progress update period", gr.Slider, {"minimum": 0, "maximum": 5000, "step": 25}), "taesd_variant": OptionInfo(shared_items.sd_taesd_items()[0], "TAESD variant", gr.Dropdown, {"choices": shared_items.sd_taesd_items()}), "taesd_layers": OptionInfo(3, "TAESD decode layers", gr.Slider, {"minimum": 1, "maximum": 3, "step": 1}), + "taesd_frames": OptionInfo(4, "TAESD video frames", gr.Slider, {"minimum": -1, "maximum": 32, "step": 1, "visible": False}), "live_preview_require_focus": OptionInfo(True, "Pause live previews when tab is not focused"), "live_preview_downscale": OptionInfo(True, "Downscale high resolution live previews"), @@ -676,18 +731,6 @@ def create_settings(cmd_opts): "extra_network_reference_enable": OptionInfo(True, "Enable use of reference models", gr.Checkbox), "extra_network_reference_values": OptionInfo(False, "Use reference values when available", gr.Checkbox), - "extra_networks_lora_sep": OptionInfo("

LoRA

", "", gr.HTML), - "extra_networks_default_multiplier": OptionInfo(1.0, "Default strength", gr.Slider, {"minimum": 0.0, "maximum": 2.0, "step": 0.01}), - "lora_force_reload": OptionInfo(False, "LoRA force reload always"), - "lora_force_diffusers": OptionInfo(False if not cmd_opts.use_openvino else True, "LoRA load using Diffusers method"), - - "lora_apply_te": OptionInfo(False, "LoRA native apply to text encoder"), - "lora_fuse_native": OptionInfo(True, "LoRA native fuse with model"), - "lora_fuse_diffusers": OptionInfo(False, "LoRA diffusers fuse with model"), - "lora_apply_tags": OptionInfo(0, "LoRA auto-apply tags", gr.Slider, {"minimum": -1, "maximum": 32, "step": 1}), - "lora_in_memory_limit": OptionInfo(1, "LoRA memory cache", gr.Slider, {"minimum": 0, "maximum": 32, "step": 1}), - "lora_add_hashes_to_infotext": OptionInfo(False, "LoRA add hash info to metadata"), - "extra_networks_styles_sep": OptionInfo("

Styles

", "", gr.HTML), "extra_networks_styles": OptionInfo(True, "Show reference styles"), "extra_networks_apply_unparsed": OptionInfo(True, "Restore unparsed prompt"), @@ -700,6 +743,37 @@ def create_settings(cmd_opts): "wildcards_enabled": OptionInfo(True, "Enable file wildcards support"), })) + # --- LoRA --- + options_templates.update(options_section(('lora', "LoRA"), { + "lora_load_sep": OptionInfo("

Load options

", "", gr.HTML), + "lora_force_reload": OptionInfo(False, "LoRA force reload always"), + "lora_force_diffusers": OptionInfo(False if not cmd_opts.use_openvino else True, "LoRA load using Diffusers method"), + "lora_in_memory_limit": OptionInfo(1, "LoRA memory cache", gr.Slider, {"minimum": 0, "maximum": 32, "step": 1}), + + "lora_prompt_sep": OptionInfo("

Prompt helpers

", "", gr.HTML), + "extra_networks_default_multiplier": OptionInfo(1.0, "Default strength", gr.Slider, {"minimum": 0.0, "maximum": 2.0, "step": 0.01}), + "lora_apply_tags": OptionInfo(0, "LoRA auto-apply tags", gr.Slider, {"minimum": -1, "maximum": 32, "step": 1}), + + "lora_apply_sep": OptionInfo("

Apply method

", "", gr.HTML), + "lora_fuse_native": OptionInfo(True, "LoRA native fuse with model"), + "lora_fuse_diffusers": OptionInfo(False, "LoRA diffusers fuse with model"), + + "lora_quant_sep": OptionInfo("

Quantization options

", "", gr.HTML), + "lora_sdnq_apply": OptionInfo("exact", "LoRA quantized apply method", gr.Radio, {"choices": ["exact", "requantize"]}), + "lora_sdnq_host_rank": OptionInfo(256, "LoRA quantized host rank", gr.Slider, {"minimum": 0, "maximum": 1024, "step": 32}), + "lora_sdnq_host_calib": OptionInfo(True, "LoRA quantized host calibration"), + "lora_sdnq_host_cache": OptionInfo(10, "LoRA quantized host cache", gr.Slider, {"minimum": 0, "maximum": 100, "step": 1}), + + "lora_stack_sep": OptionInfo("

Stacking options

", "", gr.HTML), + "lora_stack_mode": OptionInfo("sum", "LoRA stack mode", gr.Dropdown, {"choices": ["sum", "ties", "dare_ties", "dare_linear", "magnitude_prune", "klora", "estlora"]}), + "lora_stack_density": OptionInfo(0.5, "LoRA stack density", gr.Slider, {"minimum": 0.05, "maximum": 1.0, "step": 0.05}), + "lora_stack_alpha": OptionInfo(0.0, "LoRA stack ramp", gr.Slider, {"minimum": 0.0, "maximum": 3.0, "step": 0.1}), + "lora_stack_discrepancy": OptionInfo(0.5, "LoRA stack discrepancy", gr.Slider, {"minimum": 0.0, "maximum": 1.0, "step": 0.05}), + + "lora_meta_sep": OptionInfo("

Metadata

", "", gr.HTML), + "lora_add_hashes_to_infotext": OptionInfo(False, "LoRA add hash info to metadata"), + })) + # --- Extensions --- options_templates.update(options_section(('extensions', "Extensions"), { "disable_all_extensions": OptionInfo("none", "Disable all extensions", gr.Radio, {"choices": ["none", "user", "all"]}), @@ -766,7 +840,6 @@ def create_settings(cmd_opts): "control_move_processor": OptionInfo(False, "Processor move to CPU when complete", gr.Checkbox, {"visible": False}), "control_unload_processor": OptionInfo(False, "Processor unload after use", gr.Checkbox, {"visible": False}), # sampler settings are handled separately - "show_samplers": OptionInfo([], "Show samplers in user interface", gr.CheckboxGroup, lambda: {"choices": [x.name for x in list_samplers()], "visible": False}), "eta_noise_seed_delta": OptionInfo(0, "Noise seed delta (eta)", gr.Number, {"precision": 0, "visible": False}), "scheduler_eta": OptionInfo(1.0, "Noise multiplier (eta)", gr.Slider, {"minimum": 0.0, "maximum": 1.0, "step": 0.01, "visible": False}), "schedulers_solver_order": OptionInfo(0, "Solver order (where", gr.Slider, {"minimum": 0, "maximum": 5, "step": 1, "visible": False}), diff --git a/modules/ui_extra_networks.py b/modules/ui_extra_networks.py index 45ac9d01b..09f1f3356 100644 --- a/modules/ui_extra_networks.py +++ b/modules/ui_extra_networks.py @@ -27,6 +27,8 @@ refresh_time = 0 extra_pages = shared.extra_networks debug = log.trace if os.environ.get('SD_EN_DEBUG', None) is not None else lambda *args, **kwargs: None debug('Trace: EN') + +card_empty = '
' card_full = '''
diff --git a/modules/ui_extra_networks_checkpoints.py b/modules/ui_extra_networks_checkpoints.py index d90cbcfbb..a7db53fbc 100644 --- a/modules/ui_extra_networks_checkpoints.py +++ b/modules/ui_extra_networks_checkpoints.py @@ -17,11 +17,14 @@ version_map = { "SDXL 1.0": "SD XL", "SDXL Hyper": "SD XL", "StableDiffusion": "SD 1.5", + "StableDiffusion2": "SD 2.1", + "SD-v21": "SD 2.1", "StableDiffusion3": "SD 3", "StableDiffusionXL": "SD XL", "WanToVideo": "Wan", "WanVACE": "Wan", - "Z": "Z-Image", + "ZImage": "Z-Image", + "Z-Image": "Z-Image", "Glm": "GLM-Image", "Krea2": "Krea 2", "AnimaTextTo": "Anima", @@ -29,6 +32,8 @@ version_map = { "Flux2": "Flux 2", "Flux2Klein": "Flux 2 Klein", "Flux2KleinKV": "Flux 2 Klein", + "MiniMaxH3": "MiniMax H3", + "MiniMax_H3": "MiniMax H3", } class ExtraNetworksPageCheckpoints(ui_extra_networks.ExtraNetworksPage): @@ -106,6 +111,7 @@ class ExtraNetworksPageCheckpoints(ui_extra_networks.ExtraNetworksPage): primary = tag.split(',')[0].strip() if len(tag) > 0 else '' else: primary = '' + primary = primary.lower() if ('nunchaku' in tag) and (devices.backend != 'cuda' and not shared.cmd_opts.experimental): count['hidden'] += 1 @@ -148,6 +154,25 @@ class ExtraNetworksPageCheckpoints(ui_extra_networks.ExtraNetworksPage): log.debug(f'Networks: type="reference" {count}') return models + def get_version(self, checkpoint, record): + info = self.find_version(checkpoint, record['info']) + if 'baseModel' in info: + version = info.get("baseModel", "") + elif '_class_name' in record['info']: + cls = record['info']['_class_name'] + if isinstance(cls, list): + cls = cls[-1] + version = cls.replace('Pipeline', '').replace('Image', '').replace('Modular', '') + else: + version = '' + version = version_map.get(version, version) + if len(version.strip()) == 0: # no match => check if version is part of the key in version_map + for key in version_map.keys(): + if key.lower() in record['name'].lower(): + version = version_map[key] + break + return version + def create_item(self, name): record = None try: @@ -166,18 +191,7 @@ class ExtraNetworksPageCheckpoints(ui_extra_networks.ExtraNetworksPage): } record['info'] = self.find_info(checkpoint.filename) record['description'] = self.find_description(checkpoint.filename, record['info']) - version = self.find_version(checkpoint, record['info']) - if 'baseModel' in version: - record['version'] = version.get("baseModel", "") - elif '_class_name' in record['info']: - cls = record['info']['_class_name'] - if isinstance(cls, list): - cls = cls[-1] - record['version'] = cls.replace('Pipeline', '').replace('Image', '').replace('Modular', '') - else: - record['version'] = '' - record['version'] = version_map.get(record['version'], record['version']) - + record['version'] = self.get_version(checkpoint, record) except Exception as e: log.error(f'Networks error: type=model file="{name}" {e}') if os.environ.get('SD_EN_DEBUG', None) is not None: diff --git a/modules/ui_extra_networks_lora.py b/modules/ui_extra_networks_lora.py index 8a1c11c98..0052217e6 100644 --- a/modules/ui_extra_networks_lora.py +++ b/modules/ui_extra_networks_lora.py @@ -55,9 +55,20 @@ class ExtraNetworksPageLora(ui_extra_networks.ExtraNetworksPage): tags[tag] = 0 except Exception: pass + + # cleanup tags: remove model names, bad words, and special characters + model_words = ['ltx', 'minimax', 'h3', 'sdxl', 'klein', 'wan', 'flux', 'qwen', 'vace', 'lcm', 'slider'] + bad_words = ['concept', 'style', 'styles', 'base model', 'video', 'audio', 'turbo', 'distill', 'assets', 'action', 'enhancer', 'detail', 'tool', 'dir', 'all'] + bad_parts = ['lora', 'comfyui', 't2i', 'i2i', 't2v', 'i2v', 'steps'] bad_chars = [';', ':', '<', ">", "*", '?', '\'', '\"', '(', ')', '[', ']', '{', '}', '\\', '/'] clean_tags = {} for k, v in tags.items(): + if k in bad_words: + continue + if any(k.startswith(s) for s in model_words): + continue + if any(s in k for s in bad_parts): + continue tag = ''.join(i for i in k if i not in bad_chars).strip() clean_tags[tag] = v @@ -80,7 +91,7 @@ class ExtraNetworksPageLora(ui_extra_networks.ExtraNetworksPage): return ver def create_item(self, name): - l = lora_load.available_networks.get(name) + l = lora_load.available_networks.get(name) or lora_load.available_network_aliases.get(name) # that table mangles dots in the stem to underscores; the aliases carry the natural basename and the subfolder path if l is None: log.warning(f'Networks: type=lora registered={len(list(lora_load.available_networks))} file="{name}" not registered') return None diff --git a/modules/ui_guidance.py b/modules/ui_guidance.py index c451d2863..5aa41e794 100644 --- a/modules/ui_guidance.py +++ b/modules/ui_guidance.py @@ -1,81 +1,69 @@ +from functools import partial import gradio as gr from modules import shared from modules import ui_symbols, ui_components +from modules.modular_guiders import guiders -guiders = ['Default', 'CFG', 'Zero', 'PAG', 'APG', 'SLG', 'SEG', 'TCFG', 'FDG'] +_stored_args = {} + + +def get_modular_args(): + return _stored_args def create_guidance_inputs(tab): with gr.Accordion(open=False, label='Guidance', elem_id=f"{tab}_guidance", elem_classes=["small-accordion"]): with gr.Group(): - with gr.Row(elem_id=f"{tab}_guider_row", elem_classes=['flexbox'], visible=shared.opts.model_modular_enable): - guidance_name = gr.Dropdown(choices=guiders, value='Default', label='Guider', elem_id=f"{tab}_guider") - guidance_btn = ui_components.ToolButton(value=ui_symbols.book, elem_id=f"{tab}_guider_docs") - guidance_btn.click(fn=None, _js='getGuidanceDocs', inputs=[guidance_name], outputs=[]) - with gr.Row(visible=shared.opts.model_modular_enable): - guidance_scale = gr.Slider(minimum=-1.0, maximum=30.0, step=0.1, label='_Guidance scale', value=-1.0, elem_id=f"{tab}_guidance_scale") - guidance_rescale = gr.Slider(minimum=-1.0, maximum=1.0, step=0.05, label='_Guidance rescale', value=-1.0, elem_id=f"{tab}_guidance_rescale") - with gr.Row(visible=shared.opts.model_modular_enable): - guidance_start = gr.Slider(minimum=0.0, maximum=1.0, step=0.05, label='_Guidance start', value=0.0, elem_id=f"{tab}_guidance_start") - guidance_stop = gr.Slider(minimum=0.0, maximum=1.0, step=0.1, label='_Guidance stop', value=1.0, elem_id=f"{tab}_guidance_stop") - guidance_args = [guidance_name, guidance_scale, guidance_rescale, guidance_start, guidance_stop] + cfg_name = gr.Dropdown(choices=guiders.keys(), value='Default', label='Guider', elem_id=f"{tab}_guider") + cfg_name_btn = ui_components.ToolButton(value=ui_symbols.info, elem_id=f"{tab}_guider_docs") + cfg_name_btn.click(fn=None, _js='getGuidanceDocs', inputs=[cfg_name], outputs=[]) - lsc_group = gr.Accordion(open=False, label='Layer skip guidance', elem_classes=["small-accordion"], visible=shared.opts.model_modular_enable) - with lsc_group: + base_group = gr.Group() + with base_group: with gr.Row(): - guidance_lsc_enabled = gr.Checkbox(label='Enable LayerSkipConfig', value=False) - guidance_lsc_label = gr.Label(value='LSC: LayerSkipConfig', elem_id=f"{tab}_lsc_label", visible=False) - guidance_lsc_btn = ui_components.ToolButton(value=ui_symbols.book, elem_id=f"{tab}_lsc_docs", elem_classes=["guidance-docs"]) - guidance_lsc_btn.click(fn=None, _js='getGuidanceDocs', inputs=[guidance_lsc_label], outputs=[]) + cfg_scale = gr.Slider(minimum=-1.0, maximum=30.0, step=0.1, label='Guidance scale', value=-1.0, elem_id=f"{tab}_guidance_scale") + cfg_image = gr.Slider(minimum=-1.0, maximum=30.0, step=0.1, label='Guidance image', value=-1.0, elem_id=f"{tab}_guidance_image") with gr.Row(): - guidance_lsc_indices = gr.Textbox(label='LSC layer indices', value='1, 2, 3', placeholder='Comma-separated layer indices to skip') + cfg_rescale = gr.Slider(minimum=-1.0, maximum=1.0, step=0.05, label='Guidance rescale', value=-1.0, elem_id=f"{tab}_guidance_rescale") with gr.Row(): - guidance_lsc_fqn = gr.Textbox(label='LSC fully qualified name', value='transformer_blocks', placeholder='Fully qualified name of the layer stack') - with gr.Row(): - guidance_lsc_skip_attention = gr.Checkbox(label='LSC skip attention blocks', value=True) - guidance_lsc_skip_ff = gr.Checkbox(label='LSC skip feed-forward blocks', value=True) - guidance_lsc_skip_attention_scores = gr.Checkbox(label='LSC skip attention scores', value=False) - with gr.Row(): - guidance_lsc_dropout = gr.Slider(minimum=0.0, maximum=1.0, step=0.05, label='LSC dropout rate', value=1.0) - lsc_args = [guidance_lsc_enabled, guidance_lsc_indices, guidance_lsc_fqn, guidance_lsc_skip_attention, guidance_lsc_skip_ff, guidance_lsc_skip_attention_scores, guidance_lsc_dropout] + cfg_start = gr.Slider(minimum=0.0, maximum=1.0, step=0.05, label='Guidance start', value=0.0, elem_id=f"{tab}_guidance_start") + cfg_stop = gr.Slider(minimum=0.0, maximum=1.0, step=0.1, label='Guidance stop', value=1.0, elem_id=f"{tab}_guidance_stop") + args_base = [cfg_name, cfg_scale, cfg_image, cfg_rescale, cfg_start, cfg_stop] auto_group = gr.Accordion(open=True, label='Advanced guidance params', elem_classes=["small-accordion"], visible=False) with auto_group: - guidance_auto_dropout = gr.Slider(minimum=0.0, maximum=1.0, step=0.05, label='AutoGuidance dropout', value=0.1) - guidance_auto_layers = gr.Textbox(label='AutoGuidance layers', value='7, 8, 9', placeholder='Comma-separated layer indices, e.g. 7,8,9') - guidance_auto_config = gr.Dropdown(choices=[None, 'config1', 'config2'], value=None, label='AutoGuidance config') - guidance_auto_args = [guidance_auto_dropout, guidance_auto_layers, guidance_auto_config] + guidance_auto_dropout = gr.Slider(minimum=0.0, maximum=1.0, step=0.05, label='AutoGuidance dropout', value=1.0) + guidance_auto_layers = gr.Textbox(label='AutoGuidance layers', value='', placeholder='layer indices, e.g. 7,8,9 or ranges, e.g. 7-9') + args_auto = [guidance_auto_dropout, guidance_auto_layers] zero_group = gr.Accordion(open=True, label='Advanced guidance params', elem_classes=["small-accordion"], visible=False) with zero_group: guidance_zero_init_steps = gr.Slider(minimum=0, maximum=10, step=1, label='ZeroStar init steps', value=1) - guidance_zero_args = [guidance_zero_init_steps] + args_zero = [guidance_zero_init_steps] pag_group = gr.Accordion(open=True, label='Advanced guidance params', elem_classes=["small-accordion"], visible=False) with pag_group: - guidance_cfg_true = gr.Slider(minimum=0.0, maximum=30.0, step=0.05, label='PAG scale', value=2.8) + guidance_pag_scale = gr.Slider(minimum=0.0, maximum=30.0, step=0.05, label='PAG scale', value=7.5) guidance_pag_start = gr.Slider(minimum=0.0, maximum=1.0, step=0.01, label='PAG start', value=0.01) guidance_pag_stop = gr.Slider(minimum=0.0, maximum=1.0, step=0.01, label='PAG stop', value=0.2) - guidance_pag_layers = gr.Textbox(label='PAG layers', value='7, 8, 9', placeholder='Comma-separated layer indices, e.g. 7,8,9') - guidance_pag_config = gr.Dropdown(choices=[None, 'config1', 'config2'], value=None, label='PAG config') - guidance_pag_args = [guidance_cfg_true, guidance_pag_start, guidance_pag_stop, guidance_pag_layers, guidance_pag_config] + guidance_pag_layers = gr.Textbox(label='PAG layers', value='', placeholder='layer indices, e.g. 7,8,9 or ranges, e.g. 7-9') + args_pag = [guidance_pag_scale, guidance_pag_start, guidance_pag_stop, guidance_pag_layers] apg_group = gr.Accordion(open=True, label='Advanced guidance params', elem_classes=["small-accordion"], visible=False) with apg_group: guidance_apg_momentum = gr.Slider(minimum=-1.0, maximum=1.0, step=0.05, label='APG momentum', value=-1.0) guidance_apg_rescale = gr.Slider(minimum=0.0, maximum=30.0, step=0.1, label='APG rescale', value=15.0) - guidance_apg_args = [guidance_apg_momentum, guidance_apg_rescale] + args_apg = [guidance_apg_momentum, guidance_apg_rescale] slg_group = gr.Accordion(open=True, label='Advanced guidance params', elem_classes=["small-accordion"], visible=False) with slg_group: guidance_slg_scale = gr.Slider(minimum=0.0, maximum=30.0, step=0.1, label='SLG scale', value=2.8) guidance_slg_start = gr.Slider(minimum=0.0, maximum=1.0, step=0.1, label='SLG start', value=0.01) guidance_slg_stop = gr.Slider(minimum=0.0, maximum=1.0, step=0.1, label='SLG stop', value=0.2) - guidance_slg_layers = gr.Textbox(label='SLG layers', value='7, 8, 9', placeholder='Comma-separated layer indices, e.g. 7,8,9') - guidance_slg_config = gr.Dropdown(choices=[None, 'config1', 'config2'], value=None, label='SLG config') - guidance_slg_args = [guidance_slg_scale, guidance_slg_start, guidance_slg_stop, guidance_slg_layers, guidance_slg_config] + guidance_slg_layers = gr.Textbox(label='SLG layers', value='', placeholder='layer indices, e.g. 7,8,9 or ranges, e.g. 7-9') + args_slg = [guidance_slg_scale, guidance_slg_start, guidance_slg_stop, guidance_slg_layers] seg_group = gr.Accordion(open=True, label='Advanced guidance params', elem_classes=["small-accordion"], visible=False) with seg_group: @@ -84,23 +72,23 @@ def create_guidance_inputs(tab): guidance_seg_blur_threshold_inf = gr.Number(label='SEG blur threshold inf', value=9999.0) guidance_seg_start = gr.Slider(minimum=0.0, maximum=1.0, step=0.1, label='SEG start', value=0.0) guidance_seg_stop = gr.Slider(minimum=0.0, maximum=1.0, step=0.1, label='SEG stop', value=1.0) - guidance_seg_layers = gr.Textbox(label='SEG layers', value='7, 8, 9', placeholder='Comma-separated layer indices, e.g. 7,8,9') - guidance_seg_config = gr.Dropdown(choices=[None, 'config1', 'config2'], value=None, label='SEG config') - guidance_seg_args = [guidance_seg_scale, guidance_seg_blur_sigma, guidance_seg_blur_threshold_inf, guidance_seg_start, guidance_seg_stop, guidance_seg_layers, guidance_seg_config] + guidance_seg_layers = gr.Textbox(label='SEG layers', value='', placeholder='layer indices, e.g. 7,8,9 or ranges, e.g. 7-9') + args_seg = [guidance_seg_scale, guidance_seg_blur_sigma, guidance_seg_blur_threshold_inf, guidance_seg_start, guidance_seg_stop, guidance_seg_layers] tcfg_group = gr.Accordion(open=True, label='Advanced guidance params', elem_classes=["small-accordion"], visible=False) with tcfg_group: - pass + args_tcfg = [] fdg_group = gr.Accordion(open=True, label='Advanced guidance params', elem_classes=["small-accordion"], visible=False) with fdg_group: - guidance_fdg_scales = gr.Textbox(label='FDG scales', value='10.0, 5.0', placeholder='Comma-separated scales, e.g. 10.0,5.0') - guidance_fdg_weights = gr.Textbox(label='FDG weights', value='1.0', placeholder='Single float or comma-separated weights, e.g. 1.0 or 1.0,0.5') + guidance_fdg_scales = gr.Textbox(label='FDG scales', value='10.0, 5.0', placeholder='descending scales, e.g. 10.0,5.0') + guidance_fdg_weights = gr.Slider(minimum=0.0, maximum=1.0, step=0.01, label='FDG weights', value=1.0) guidance_fdg_rescale_space = gr.Dropdown(choices=['data', 'freq'], value='data', label='FDG rescale space') - guidance_fdg_args = [guidance_fdg_scales, guidance_fdg_weights, guidance_fdg_rescale_space] + args_fdg = [guidance_fdg_scales, guidance_fdg_weights, guidance_fdg_rescale_space] def adv_visibility(guidance_name): return [ + gr.update(visible=True), gr.update(visible=guidance_name.startswith('Auto')), gr.update(visible=guidance_name.startswith('Zero')), gr.update(visible=guidance_name.startswith('PAG')), @@ -110,19 +98,27 @@ def create_guidance_inputs(tab): gr.update(visible=guidance_name.startswith('TCFG')), gr.update(visible=guidance_name.startswith('FDG')), ] - guidance_name.change(fn=adv_visibility, inputs=[guidance_name], outputs=[auto_group, zero_group, pag_group, apg_group, slg_group, seg_group, tcfg_group, fdg_group]) + cfg_name.change(fn=adv_visibility, inputs=[cfg_name], outputs=[base_group, auto_group, zero_group, pag_group, apg_group, slg_group, seg_group, tcfg_group, fdg_group]) - gr.HTML(value='

Fallback guidance

', visible=shared.opts.model_modular_enable, elem_id=f"{tab}_guidance_note") - with gr.Row(elem_id=f"{tab}_cfg_row", elem_classes=['flexbox']): - cfg_scale = gr.Slider(minimum=-1.0, maximum=30.0, step=0.1, label='Guidance scale', value=-1.0, elem_id=f"{tab}_cfg_scale") - cfg_end = gr.Slider(minimum=0.0, maximum=1.0, step=0.1, label='Guidance end', value=1.0, elem_id=f"{tab}_cfg_end") - with gr.Row(): - cfg_rescale = gr.Slider(minimum=-1.0, maximum=1.0, step=0.05, label='Guidance rescale', value=-1.0, elem_id=f"{tab}_image_cfg_rescale") - cfg_image = gr.Slider(minimum=-1.0, maximum=30.0, step=0.1, label='Refine guidance', value=-1.0, elem_id=f"{tab}_cfg_image") - with gr.Row(): + legacy_group = gr.Row(visible=not shared.opts.model_modular_enable) + with legacy_group: cfg_true = gr.Slider(minimum=-1.0, maximum=30.0, step=0.05, label='Attention guidance', value=-1.0, elem_id=f"{tab}_cfg_true") cfg_adaptive = gr.Slider(minimum=0.0, maximum=1.0, step=0.05, label='Adaptive scaling', value=0.5, elem_id=f"{tab}_cfg_adaptive") + args_legacy = [cfg_true, cfg_adaptive] - _modular_args = guidance_args + lsc_args + guidance_auto_args + guidance_zero_args + guidance_pag_args + guidance_apg_args + guidance_slg_args + guidance_seg_args + guidance_fdg_args - standard_args = [cfg_scale, cfg_image, cfg_rescale, cfg_true, cfg_adaptive, cfg_end] - return guidance_args + standard_args + modular_args = args_auto + args_zero + args_pag + args_apg + args_slg + args_seg + args_tcfg + args_fdg + standard_args = args_base + args_legacy + + def update_stored(component, name): + if component is None or name is None: + return + _stored_args[name] = component + + for component in modular_args: + label = getattr(component, 'label', None) + value = getattr(component, 'value', None) + name = label.lower().replace(' ', '_') if label is not None else None + _stored_args[name] = value + component.change(fn=partial(update_stored, name=name), inputs=[component], outputs=[]) + + return standard_args diff --git a/modules/ui_img2img.py b/modules/ui_img2img.py index 20890ed18..a1dd1d04d 100644 --- a/modules/ui_img2img.py +++ b/modules/ui_img2img.py @@ -137,7 +137,7 @@ def create_ui(): denoising_strength = gr.Slider(minimum=0.00, maximum=0.99, step=0.01, label='Denoising strength', value=0.30, elem_id="img2img_denoising_strength") refiner_start = gr.Slider(minimum=0.0, maximum=1.0, step=0.05, label='Denoise start', value=0.0, elem_id="img2img_refiner_start") - guidance_name, guidance_scale, guidance_rescale, guidance_start, guidance_stop, cfg_scale, cfg_image, cfg_rescale, cfg_true, cfg_adaptive, cfg_end = ui_guidance.create_guidance_inputs('img2img') + cfg_name, cfg_scale, cfg_image, cfg_rescale, cfg_start, cfg_stop, cfg_true, cfg_adaptive = ui_guidance.create_guidance_inputs('img2img') vae_type, tiling, hidiffusion, clip_skip = ui_sections.create_advanced_inputs('img2img') grading_brightness, grading_contrast, grading_saturation, grading_hue, grading_gamma, grading_sharpness, grading_color_temp, grading_shadows, grading_midtones, grading_highlights, grading_clahe_clip, grading_clahe_grid, grading_shadows_tint, grading_highlights_tint, grading_split_tone_balance, grading_vignette, grading_grain, grading_lut_file, grading_lut_strength = ui_sections.create_color_inputs('img2img') hdr_mode, hdr_brightness, hdr_color, hdr_sharpen, hdr_clamp, hdr_boundary, hdr_threshold, hdr_maximize, hdr_max_center, hdr_max_boundary, hdr_color_picker, hdr_tint_ratio, hdr_apply_hires = ui_sections.create_latent_inputs('img2img') @@ -183,8 +183,7 @@ def create_ui(): vae_type, tiling, hidiffusion, detailer_enabled, detailer_prompt, detailer_negative, detailer_steps, detailer_strength, detailer_resolution, detailer_classes, batch_count, batch_size, - guidance_name, guidance_scale, guidance_rescale, guidance_start, guidance_stop, - cfg_scale, cfg_image, cfg_rescale, cfg_true, cfg_adaptive, cfg_end, + cfg_name, cfg_scale, cfg_image, cfg_rescale, cfg_start, cfg_stop, cfg_true, cfg_adaptive, refiner_start, clip_skip, denoising_strength, @@ -266,19 +265,8 @@ def create_ui(): (seed, "Seed"), (subseed, "Variation seed"), (subseed_strength, "Variation strength"), - # guidance - (guidance_name, "Guidance"), - (guidance_scale, "Guidance scale"), - (guidance_rescale, "Guidance rescale"), - (guidance_start, "Guidance start"), - (guidance_stop, "Guidance stop"), # advanced - (cfg_scale, "CFG scale"), - (cfg_end, "CFG end"), - (cfg_image, "Image CFG scale"), - (cfg_image, "Hires CFG scale"), (clip_skip, "CLiP-skip"), - (cfg_rescale, "CFG rescale"), (vae_type, "VAE type"), (tiling, "Tiling"), (hidiffusion, "HiDiffusion"), @@ -309,7 +297,15 @@ def create_ui(): (refiner_steps, "Refiner steps"), (refiner_prompt, "refiner prompt"), (refiner_negative, "Refiner negative"), - # pag + # guidance + (cfg_name, "CFG name"), + (cfg_scale, "CFG scale"), + (cfg_image, "CFG image"), + (cfg_image, "Image CFG scale"), + (cfg_image, "Hires CFG scale"), + (cfg_rescale, "CFG rescale"), + (cfg_start, "CFG start"), + (cfg_stop, "CFG stop"), (cfg_true, "CFG true"), (cfg_adaptive, "CFG adaptive"), # inpaint diff --git a/modules/ui_javascript.py b/modules/ui_javascript.py index af638c5ae..786b4e25e 100644 --- a/modules/ui_javascript.py +++ b/modules/ui_javascript.py @@ -65,7 +65,7 @@ def html_login(): def html_css(css: list[str]): def stylesheet(fn): - return f'' + return f'\n' head = '' for cssfile in css: @@ -79,24 +79,41 @@ def html_css(css: list[str]): head += stylesheet(cssfile) usercss = os.path.join(data_path, "user.css") if os.path.exists(os.path.join(data_path, "user.css")) else None - if shared.opts.theme_type == 'Standard': - # themecss = os.path.join(script_path, 'javascript', f"{shared.opts.gradio_theme}.css") - themecss = os.path.join(script_path, 'ui', 'css', f"{shared.opts.gradio_theme}.css") - if os.path.exists(themecss): - head += stylesheet(themecss) - log.debug(f'UI theme: css="{themecss}" base="{css}" user="{usercss}"') + + if shared.cmd_opts.theme is not None: + if shared.cmd_opts.theme.lower().startswith('standard'): + shared.opts.theme_type = 'Standard' + elif shared.cmd_opts.theme.lower().startswith('modern'): + shared.opts.theme_type = 'Modern' else: - log.error(f'UI theme: css="{themecss}" path="{os.getcwd()}" not found') + shared.opts.theme_type = 'None' + + if shared.opts.theme_type == 'Standard': + if shared.opts.gradio_theme == 'Default': + shared.opts.gradio_theme = 'black-teal' + themecss = os.path.join(script_path, 'ui', 'css', f"{shared.opts.gradio_theme}.css") + if not os.path.exists(themecss): + log.error(f'UI theme: type={shared.opts.theme_type} css="{themecss}" path="{os.getcwd()}" not found') + shared.opts.gradio_theme = 'black-teal' + themecss = os.path.join(script_path, 'ui', 'css', f"{shared.opts.gradio_theme}.css") + head += stylesheet(themecss) + log.info(f'UI theme: type={shared.opts.theme_type} css="{themecss}" base="{css}" user="{usercss}"') + elif shared.opts.theme_type == 'Modern': + if shared.opts.gradio_theme == 'black-teal': + shared.opts.gradio_theme = 'Default' theme_folder = next((e.path for e in extensions.extensions if e.name == 'sdnext-modernui'), None) themecss = os.path.join(theme_folder or '', 'themes', f'{shared.opts.gradio_theme}.css') - if os.path.exists(themecss): - head += stylesheet(themecss) - log.debug(f'UI theme: css="{themecss}" base="{css}" user="{usercss}"') - else: - log.error(f'UI theme: css="{themecss}" not found') + if not os.path.exists(themecss): + log.error(f'UI theme: type={shared.opts.theme_type} css="{themecss}" not found') + shared.opts.gradio_theme = 'Default' + themecss = os.path.join(theme_folder or '', 'themes', f'{shared.opts.gradio_theme}.css') + head += stylesheet(themecss) + log.info(f'UI theme: type={shared.opts.theme_type} css="{themecss}" base="{css}" user="{usercss}"') + if usercss is not None: head += stylesheet(usercss) + return head @@ -108,7 +125,7 @@ def reload_javascript(): js = html_head() css_files: list[str] = [] - if (css_base := theme.reload_gradio_theme()) is not None: + if (css_base := theme.reload_gradio_theme(shared.opts, shared.cmd_opts)) is not None: css_files.append(css_base) css_files.append("timesheet.css") diff --git a/modules/ui_models.py b/modules/ui_models.py index b3b4b6839..1aab89bba 100644 --- a/modules/ui_models.py +++ b/modules/ui_models.py @@ -521,7 +521,7 @@ def create_ui(): ) with gr.Tab(label="CivitAI", elem_id="models_civitai_tab") as civitai_tab: - from modules.civitai.search_civitai import search_civitai, create_model_cards, base_models + from modules.civitai.search_civitai import search_civitai, create_model_cards sort_fallback = ['', 'Most Downloaded', 'Highest Rated', 'Most Liked', 'Most Discussed', 'Most Collected', 'Most Images', 'Newest', 'Oldest'] @@ -572,7 +572,7 @@ def create_ui(): civit_download_btn = gr.Button(value="Download model", variant='primary', elem_id="civitai_download_btn", visible=False) with gr.Row(): civit_type = gr.Dropdown(choices=type_fallback, label='CivitAI model type', value='', elem_id='civit_type') - civit_base = gr.Dropdown(choices=base_models, label='CivitAI base model', value='') + civit_base = gr.Dropdown(choices=[''], label='CivitAI base model', value='') with gr.Row(): civit_sort = gr.Dropdown(choices=sort_fallback, label='CivitAI sort', value='', elem_id='civit_sort') civit_period = gr.Dropdown( @@ -628,14 +628,15 @@ def create_ui(): def civitai_on_tab_enter(): nonlocal _civitai_loaded - if _civitai_loaded: - return [gr.update(), gr.update(), gr.update(), gr.update(), gr.update()] - _civitai_loaded = True from modules.civitai.client_civitai import client - options = client.discover_options() + options = client.discover_options() # cached, so every visit can refresh the choices type_choices = [''] + (options.get('types', []) or type_fallback[1:]) sort_choices = [''] + (options.get('sort', []) or sort_fallback[1:]) - base_choices = [''] + (options.get('base_models', []) or base_models[1:]) + hidden_bases = {entry.get('name') for entry in options.get('base_models_info', []) if entry.get('hidden')} # retired bases, which the site's own filter omits too + base_choices = [''] + [base for base in options.get('base_models', []) if base not in hidden_bases] + if _civitai_loaded: + return [gr.update(choices=type_choices), gr.update(choices=sort_choices), gr.update(choices=base_choices), gr.update(), gr.update()] + _civitai_loaded = True results = search_civitai(query='', sort='Most Downloaded', period='AllTime', limit=20) html = create_model_cards(results) return [ diff --git a/modules/ui_sections.py b/modules/ui_sections.py index a57a99074..19ca8c127 100644 --- a/modules/ui_sections.py +++ b/modules/ui_sections.py @@ -213,13 +213,41 @@ def create_color_inputs(tab): return grading_brightness, grading_contrast, grading_saturation, grading_hue, grading_gamma, grading_sharpness, grading_color_temp, grading_shadows, grading_midtones, grading_highlights, grading_clahe_clip, grading_clahe_grid, grading_shadows_tint, grading_highlights_tint, grading_split_tone_balance, grading_vignette, grading_grain, grading_lut_cube_file, grading_lut_strength +def sampler_choices(choices=None, selected='Default', same_as_primary=False): + """Build display-only sampler choices without changing the sampler catalog.""" + if choices is None: + sd_samplers.set_samplers() + choices = [sampler for sampler in sd_samplers.samplers if sampler.name != 'Same as primary'] + names = [choice.name if hasattr(choice, 'name') else choice for choice in choices] + visible, filtered = ui_common.filter_ui_choices(names, shared.opts.show_samplers, selected) + if same_as_primary: + visible.insert(0, 'Same as primary') + value = selected if selected in visible else visible[0] + return visible, value, filtered + + +def upscaler_choices(choices, selected=None): + """Build display-only upscaler choices without changing available upscalers.""" + return ui_common.filter_ui_choices(choices, shared.opts.show_upscalers, selected) + + +def create_filter_indicator(tabname, kind, filtered): + if not filtered: + return None + indicator = ToolButton(value=ui_symbols.info, tooltip=f'{kind} list filtered', elem_id=f'{tabname}_{kind.lower()}_filter_indicator', elem_classes=['filter-indicator']) + indicator.click(fn=None, _js="() => openSettingsSection('ui')", inputs=[], outputs=[], show_progress='hidden') + return indicator + + def create_sampler_and_steps_selection(choices, tabname, default_steps:int=20): if choices is None: sd_samplers.set_samplers() choices = [x for x in sd_samplers.samplers if not x.name == 'Same as primary'] + dropdown_choices, default_value, filtered = sampler_choices(choices) with gr.Row(elem_id=f"{tabname}_sampler_row", elem_classes=['flex-break', 'flexbox']): steps = gr.Slider(minimum=1, maximum=100, step=1, label="Steps", elem_id=f"{tabname}_steps", value=default_steps) - sampler_index = gr.Dropdown(label='Sampling method', elem_id=f"{tabname}_sampling", choices=[x.name for x in choices], value='Default', type="index") + sampler_index = gr.Dropdown(label='Sampling method', elem_id=f"{tabname}_sampling", choices=dropdown_choices, value=default_value, type="value") + create_filter_indicator(tabname, 'Sampler', filtered) return steps, sampler_index @@ -342,7 +370,9 @@ def create_hires_inputs(tab): with gr.Row(elem_id=f"{tab}_hires_fix_row2"): hr_force = gr.Checkbox(label='Force HiRes', value=False, elem_id=f"{tab}_hr_force") with gr.Row(elem_id=f"{tab}_hires_fix_row2"): - hr_sampler_index = gr.Dropdown(label='Refine sampler', elem_id=f"{tab}_sampling_alt", choices=[x.name for x in sd_samplers.samplers], value='Same as primary', type="index") + dropdown_choices, _default_value, filtered = sampler_choices(selected='Same as primary', same_as_primary=True) + hr_sampler_index = gr.Dropdown(label='Refine sampler', elem_id=f"{tab}_sampling_alt", choices=dropdown_choices, value='Same as primary', type="value") + create_filter_indicator(tab, 'Sampler', filtered) with gr.Row(elem_id=f"{tab}_hires_row2"): hr_second_pass_steps = gr.Slider(minimum=0, maximum=99, step=1, label='HiRes steps', elem_id=f"{tab}_steps_alt", value=20) denoising_strength = gr.Slider(minimum=0.0, maximum=0.99, step=0.01, label='Strength', value=0.3, elem_id=f"{tab}_denoising_strength") @@ -365,11 +395,24 @@ def create_resize_inputs(tab, images, accordion=True, latent=False, non_zero=Tru available_upscalers = ['None'] if not latent: available_upscalers = [x for x in available_upscalers if not x.lower().startswith('latent')] + available_upscalers, filtered = upscaler_choices(available_upscalers, available_upscalers[0]) resize_mode = gr.Dropdown(label=f"Mode{prefix}" if non_zero else "Resize mode", elem_id=f"{tab}_resize_mode", choices=shared.resize_modes, type="index", value='Fixed') resize_name = gr.Dropdown(label=f"Method{prefix}" if non_zero else "Resize method", elem_id=f"{tab}_resize_name", choices=available_upscalers, value=available_upscalers[0], visible=True) + create_filter_indicator(tab, 'Upscaler', filtered) resize_context_choices = ["Add with forward", "Remove with forward", "Add with backward", "Remove with backward"] resize_context = gr.Dropdown(label=f"Context{prefix}", elem_id=f"{tab}_resize_context", choices=resize_context_choices, value=resize_context_choices[0], visible=False) - resize_refresh_btn = ui_common.create_refresh_button(resize_name, modelloader.load_upscalers, lambda: {"choices": modelloader.load_upscalers()}, f'{tab}_upscalers_refresh') + + def refresh_upscaler_choices(selected): + modelloader.load_upscalers() + refreshed = [upscaler.name for upscaler in shared.sd_upscalers] + if not latent: + refreshed = [name for name in refreshed if not name.lower().startswith('latent')] + refreshed, _ = upscaler_choices(refreshed, selected) + value = selected if selected in refreshed else refreshed[0] + return gr.update(choices=refreshed, value=value) + + resize_refresh_btn = ToolButton(value=ui_symbols.refresh, elem_id=f'{tab}_upscalers_refresh') + resize_refresh_btn.click(fn=refresh_upscaler_choices, inputs=[resize_name], outputs=[resize_name], show_progress='hidden') def resize_mode_change(mode): if mode is None or mode == 0: diff --git a/modules/ui_settings.py b/modules/ui_settings.py index c1f8938a7..4d793eece 100644 --- a/modules/ui_settings.py +++ b/modules/ui_settings.py @@ -135,16 +135,6 @@ def run_settings(*args): from modules.onnx_impl import install_olive, initialize_onnx_pipelines install_olive() initialize_onnx_pipelines() - if shared.cmd_opts.use_openvino: - if "Model" not in shared.opts.cuda_compile: - log.warning("OpenVINO: Overriding Torch Compile Model") - shared.opts.cuda_compile.append("Model") - if shared.opts.cuda_compile_backend != shared.opts.openvino_compile_backend: - log.warning(f"OpenVINO: Overriding Torch Compile backend={shared.opts.openvino_compile_backend}") - shared.opts.cuda_compile_backend = shared.opts.openvino_compile_backend - if shared.opts.diffusers_offload_mode != "none": - log.warning("OpenVINO: Overriding diffusers_offload_mode=none") - shared.opts.diffusers_offload_mode = "none" if shared.opts.sd_backend != "diffusers": log.error('Legacy option: backend=original is no longer supported') shared.opts.sd_backend = "diffusers" @@ -268,8 +258,9 @@ def create_ui(disabled_tabs=None): item for item in shared.opts.data_labels.items() if item[1].section is not None and item[1].section[0] == section_id ] # find all items in this section - hidden = section_id is None or 'hidden' in section_id.lower() or 'hidden' in section_text.lower() - # log.trace(f'Settings: section="{section_id}" title="{section_text}" items={len(items)} hidden={hidden}') + hidden = (section_id is None) or ('hidden' in section_id.lower()) or ('hidden' in section_text.lower()) or ('legacy' in section_id.lower()) or ('legacy' in section_text.lower()) + # for (key, _item) in items: + # log.trace(f'Settings: id={section_id} text={section_text} key={key} hidden={hidden}') if hidden: for (key, _item) in items: hidden_list.append(key) @@ -282,7 +273,7 @@ def create_ui(disabled_tabs=None): quicksettings_list.append((key, item)) components.append(dummy_component) else: - with gr.Row(elem_id=f"settings_section_row_{section_id}", elem_classes=["settings_section"]): # only so we can add dirty indicator at the start of the row + with gr.Row(elem_id=f"settings_section_row_{section_id}", elem_classes=["settings_section"]): component = create_setting_component(key) shared.settings_components[key] = component current_items.append(key) diff --git a/modules/ui_symbols.py b/modules/ui_symbols.py index 1a82cfc31..01d21a454 100644 --- a/modules/ui_symbols.py +++ b/modules/ui_symbols.py @@ -23,13 +23,13 @@ sort = '⇕' detect = '📐' folder = '📂' random = '🎲️' -reuse = '♻️' info = 'ℹ' # noqa reset = '🔄' upload = '⬆️' loading = '↺' reuse = '⬅️' search = '🔍' +tools = '🛠' preview = '🖼️' image = '🖌️' resize = '⁜' diff --git a/modules/ui_txt2img.py b/modules/ui_txt2img.py index d639eb356..8988ead64 100644 --- a/modules/ui_txt2img.py +++ b/modules/ui_txt2img.py @@ -33,7 +33,7 @@ def create_ui(): with gr.Accordion(open=False, label="Samplers", elem_classes=["small-accordion"], elem_id="txt2img_sampler_group"): ui_sections.create_sampler_options('txt2img') seed, reuse_seed, subseed, reuse_subseed, subseed_strength, seed_resize_from_h, seed_resize_from_w = ui_sections.create_seed_inputs('txt2img') - guidance_name, guidance_scale, guidance_rescale, guidance_start, guidance_stop, cfg_scale, cfg_image, cfg_rescale, cfg_true, cfg_adaptive, cfg_end = ui_guidance.create_guidance_inputs('txt2img') + cfg_name, cfg_scale, cfg_image, cfg_rescale, cfg_start, cfg_stop, cfg_true, cfg_adaptive = ui_guidance.create_guidance_inputs('txt2img') vae_type, tiling, hidiffusion, clip_skip = ui_sections.create_advanced_inputs('txt2img') grading_brightness, grading_contrast, grading_saturation, grading_hue, grading_gamma, grading_sharpness, grading_color_temp, grading_shadows, grading_midtones, grading_highlights, grading_clahe_clip, grading_clahe_grid, grading_shadows_tint, grading_highlights_tint, grading_split_tone_balance, grading_vignette, grading_grain, grading_lut_file, grading_lut_strength = ui_sections.create_color_inputs('txt2img') hdr_mode, hdr_brightness, hdr_color, hdr_sharpen, hdr_clamp, hdr_boundary, hdr_threshold, hdr_maximize, hdr_max_center, hdr_max_boundary, hdr_color_picker, hdr_tint_ratio, hdr_apply_hires = ui_sections.create_latent_inputs('txt2img') @@ -58,8 +58,7 @@ def create_ui(): vae_type, tiling, hidiffusion, detailer_enabled, detailer_prompt, detailer_negative, detailer_steps, detailer_strength, detailer_resolution, detailer_classes, batch_count, batch_size, - guidance_name, guidance_scale, guidance_rescale, guidance_start, guidance_stop, - cfg_scale, cfg_image, cfg_rescale, cfg_true, cfg_adaptive, cfg_end, + cfg_name, cfg_scale, cfg_image, cfg_rescale, cfg_start, cfg_stop, cfg_true, cfg_adaptive, clip_skip, seed, subseed, subseed_strength, seed_resize_from_h, seed_resize_from_w, height, width, @@ -114,19 +113,8 @@ def create_ui(): (seed, "Seed"), (subseed, "Variation seed"), (subseed_strength, "Variation strength"), - # guidance - (guidance_name, "Guidance"), - (guidance_scale, "Guidance scale"), - (guidance_rescale, "Guidance rescale"), - (guidance_start, "Guidance start"), - (guidance_stop, "Guidance stop"), # advanced - (cfg_scale, "CFG scale"), - (cfg_end, "CFG end"), (clip_skip, "CLiP-skip"), - (cfg_image, "Image CFG scale"), - (cfg_image, "Hires CFG scale"), - (cfg_rescale, "CFG rescale"), (vae_type, "VAE type"), (tiling, "Tiling"), (hidiffusion, "HiDiffusion"), @@ -156,7 +144,15 @@ def create_ui(): (refiner_steps, "Refiner steps"), (refiner_prompt, "refiner prompt"), (refiner_negative, "Refiner negative"), - # pag + # guidance + (cfg_name, "CFG name"), + (cfg_scale, "CFG scale"), + (cfg_image, "CFG image"), + (cfg_image, "Image CFG scale"), + (cfg_image, "Hires CFG scale"), + (cfg_rescale, "CFG rescale"), + (cfg_start, "CFG start"), + (cfg_stop, "CFG stop"), (cfg_true, "CFG true"), (cfg_adaptive, "CFG adaptive"), # hidden diff --git a/modules/update.py b/modules/update.py index d958f3e7d..92f8693e9 100644 --- a/modules/update.py +++ b/modules/update.py @@ -6,6 +6,7 @@ import installer as i version = SimpleNamespace(**{ 'url': '', 'branch': '', + 'origin': '', 'current': '0000-00-00', 'chash': '0000000', 'latest': '0000-00-00', @@ -14,34 +15,50 @@ version = SimpleNamespace(**{ def get_version(): - # try: - origin = i.git('remote get-url origin') - origin = origin.splitlines()[0] - version.branch = i.git('rev-parse --abbrev-ref HEAD') - version.branch = version.branch.splitlines()[0] - version.url = origin.removesuffix('.git') + '/tree/' + version.branch + try: + origin = i.git('remote get-url origin') + origin = origin.splitlines() + if len(origin) > 0: + version.origin = origin[0] + version.url = version.origin.removesuffix('.git') + '/tree/' + version.branch + else: + version.origin = 'unknown' + i.log.warning('Version: origin URL not found') - ver = i.git('log --pretty=format:"%h %ad" -1 --date=short') - ver = ver.splitlines()[0] - version.chash, version.current = ver.split(' ') + branch = i.git('rev-parse --abbrev-ref HEAD') + branch = branch.splitlines() + if len(branch) > 0: + version.branch = branch[0] + else: + version.branch = 'unknown' + i.log.warning('Version: branch not found') - i.git('fetch') - ver = i.git(f'log origin/{version.branch} --pretty=format:"%h %ad" -1 --date=short') - ver = ver.splitlines()[0] - version.lhash, version.latest = ver.split(' ') + gitlog = i.git('log --pretty=format:"%h %ad" -1 --date=short') + gitlog = gitlog.splitlines() + if len(gitlog) > 0: + version.chash, version.current = gitlog[0].split(' ') - # except Exception as e: - # i.log.error(f'Version check failed: {e}') - i.log.info(f'Version: {vars(version)}') - latest = '
You\'re up to date!
' if version.chash == version.lhash else '
Update available!
' - html = f''' - -
Current branch: {version.branch}
-
Current version: {version.current} hash {version.chash}
-
Latest version: {version.latest} hash {version.lhash}
- {latest} - ''' - return html + i.git('fetch') + ver = i.git(f'log origin/{version.branch} --pretty=format:"%h %ad" -1 --date=short') + ver = ver.splitlines() + if len(ver) > 0 and ' ' in ver[0]: + version.lhash, version.latest = ver[0].split(' ') + + i.log.info(f'Version: {vars(version)}') + latest = '
You\'re up to date!
' if version.chash == version.lhash else '
Update available!
' + html = f''' + +
Origin: {version.origin}
+
Current branch: {version.branch}
+
Current version: {version.current} hash {version.chash}
+
Latest version: {version.latest} hash {version.lhash}
+ {latest} + ''' + return html + except Exception as e: + i.log.error(f'Version: {e}') + html = f'
Error while detecting version
{str(e)}
' + return html def apply_update(update_rebase, update_submodules, update_extensions): diff --git a/modules/vae/sd_vae_remote.py b/modules/vae/sd_vae_remote.py index 835b37f69..ae98ac081 100644 --- a/modules/vae/sd_vae_remote.py +++ b/modules/vae/sd_vae_remote.py @@ -180,5 +180,5 @@ def remote_encode(images: list[Image.Image], model_type: str | None = None): else: return images t1 = time.time() - log.debug(f'Encode: type="remote" model={model_type} mode={shared.opts.remote_vae_type} image={images} latent={tensors.shape} time={t1-t0:.3f}s') + log.debug(f'Encode: type="remote" model={model_type} mode={shared.opts.remote_vae_type} image={images} latent={list(tensors.shape)} time={t1-t0:.3f}s') return tensors diff --git a/modules/vae/sd_vae_taesd.py b/modules/vae/sd_vae_taesd.py index f40d3b8cc..2cffe6041 100644 --- a/modules/vae/sd_vae_taesd.py +++ b/modules/vae/sd_vae_taesd.py @@ -27,6 +27,7 @@ TAESD_MODELS = { 'TAE HunyuanVideo': { 'fn': 'taehv.pth', 'uri': 'https://github.com/madebyollin/taehv/raw/refs/heads/main/taehv.pth', 'model': None }, 'TAE WanVideo': { 'fn': 'taew1.pth', 'uri': 'https://github.com/madebyollin/taehv/raw/refs/heads/main/taew2_1.pth', 'model': None }, 'TAE MochiVideo': { 'fn': 'taem1.pth', 'uri': 'https://github.com/madebyollin/taem1/raw/refs/heads/main/taem1.pth', 'model': None }, + 'TAE MiniMax-H3': { 'fn': 'taeh3.pth', 'uri': 'https://github.com/madebyollin/taehv/raw/refs/heads/main/taeh3.pth', 'model': None }, } CQYAN_MODELS = { 'Hybrid-Tiny SD': { @@ -72,13 +73,15 @@ def get_model(model_cls, variant=None): elif model_cls in {'f1', 'h1', 'zimage', 'lumina2', 'chroma', 'longcat', 'omnigen2', 'flite', 'ovis', 'kandinsky5', 'glmimage', 'cogview3', 'cogview4', 'ultraflux'}: model_cls = 'f1' variant = 'TAE FLUX.1' - elif model_cls in {'f2', 'ernieimage', 'lens', 'ideogram4'}: + elif model_cls in {'f2', 'ernieimage', 'lens', 'ideogram4', 'lladaimage'}: model_cls = 'f2' variant = 'TAE FLUX.2' elif model_cls in {'sd3'}: variant = 'TAE SD3' elif model_cls in {'wanai', 'qwen', 'chrono', 'cosmos', 'anima', 'fibo', 'joy', 'krea2'}: variant = 'TAE WanVideo' + elif model_cls in {'minimaxh3'}: + variant = 'TAE MiniMax-H3' else: warn_once(f'cls={shared.sd_model.__class__.__name__} type={shared.sd_model_type} unsuppported', variant=variant) return model_cls, None @@ -122,10 +125,7 @@ def load_model(model_type = 'decoder', variant = None, vae_file: str | None = No log.print() # new line log.debug(f'Decode: type="taesd" variant="{variant}" fn="{fn}" layers={shared.opts.taesd_layers} load') vae = None - if 'TAE HunyuanVideo' in variant: - from modules.taesd.taehv import TAEHV - vae = TAEHV(checkpoint_path=fn) - elif 'TAE WanVideo' in variant: + if ('TAE HunyuanVideo' in variant) or ('TAE WanVideo' in variant) or ('TAE MiniMax-H3' in variant): from modules.taesd.taehv import TAEHV vae = TAEHV(checkpoint_path=fn) elif 'TAE MochiVideo' in variant: @@ -185,6 +185,23 @@ def restore_preview_size(image, vae): return image +def tile_video_frames(tensor): + frame_count = tensor.shape[0] + requested = shared.opts.taesd_frames + if (frame_count <= 1) or (requested == 1): + return tensor[0] + if (requested == -1) or (requested >= frame_count): + indices = list(range(frame_count)) + else: + indices = [round(i * (frame_count - 1) / (requested - 1)) for i in range(requested)] + selected = tensor[indices] + try: + tiled = torch.cat([selected[i] for i in range(selected.shape[0])], dim=-1) + return tiled + except Exception: + return tensor[0] + + def decode(latents, fast=False): global first_run, prev_model, prev_variant # pylint: disable=global-statement with lock: @@ -194,7 +211,7 @@ def decode(latents, fast=False): variant = prev_variant else: vae, variant = load_model(model_type='decoder') - if vae is None or max(latents.shape) > 256: # safety check of large tensors + if vae is None or max(latents.shape) > 384: # safety check of large tensors return latents prev_model = vae prev_variant = variant @@ -220,7 +237,11 @@ def decode(latents, fast=False): image = image[0] else: image = vae.decode(tensor, return_dict=False)[0] - image = (image / 2.0 + 0.5).clamp(0, 1).detach() + # image = (image / 2.0 + 0.5).clamp(0, 1).detach() + image = image.clamp(0, 1).detach() + if image.ndim == 4 and image.shape[0] > 1 and image.shape[1] == 3: # likely a video latent + # image = tile_video_frames(image) + image = image[0] # just take the first frame for now image = restore_preview_size(image, vae) t1 = time.time() if (t1 - t0) > 5.0 and not first_run: diff --git a/modules/video.py b/modules/video.py index f94324a0b..4fde8fa14 100644 --- a/modules/video.py +++ b/modules/video.py @@ -7,6 +7,8 @@ from modules.logger import log from modules.image.namegen import FilenameGenerator # pylint: disable=unused-import from modules.paths import resolve_output_path +os.environ.setdefault('OPENCV_FFMPEG_LOGLEVEL', '8') # fatal only; OpenCV reads it once, at its first capture + def interpolate_frames(images, count: int = 0, scale: float = 1.0, pad: int = 1, change: float = 0.3): if images is None: @@ -113,9 +115,9 @@ def get_video_params(filepath: str, capture: bool = False): codec = decode_fourcc(video.get(cv2.CAP_PROP_FOURCC)) frame = None if capture: - _status, frame = video.read() - frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) - frame = Image.fromarray(frame) + ok, raw = video.read() + if ok and raw is not None: + frame = Image.fromarray(cv2.cvtColor(raw, cv2.COLOR_BGR2RGB)) video.release() return frames, fps, duration, w, h, codec, frame diff --git a/modules/video_models/google_omni.py b/modules/video_models/google_omni.py new file mode 100644 index 000000000..33989eec6 --- /dev/null +++ b/modules/video_models/google_omni.py @@ -0,0 +1,137 @@ +import io +import os +import base64 +import time + +import sys +sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..'))) + +from PIL import Image +from modules.logger import log + + +image_size_buckets = { + '360p': 640*360, + '720p': 1280*720, + '1080p': 1920*1080, + '4k': 3840*2160, +} +aspect_ratios_buckets = { + '16:9': 16/9, + '9:16': 9/16, +} + + +def google_requirements(): + from installer import install + install('google-genai==2.22.0') + # install('pydantic==2.11.7', ignore=True, quiet=True) + # reload('pydantic', '2.11.7') + + +def get_size_buckets(width: int, height: int) -> tuple[str, str]: + aspect_ratio = width / height + pixel_count = width * height + closest_size = min(image_size_buckets.items(), key=lambda x: abs(x[1] - pixel_count))[0] + closest_aspect_ratio = min(aspect_ratios_buckets.items(), key=lambda x: abs(x[1] - aspect_ratio))[0] + return closest_size, closest_aspect_ratio + + +class GoogleOmniVideoPipeline: + def __init__(self, model_name: str): + self.model = model_name + self.client = None + google_requirements() + log.debug(f'Load model: type=GoogleOmni model="{model_name}"') + + def get_args(self): + from modules.shared import opts + # Use UI settings only - env vars are intentionally ignored + api_key = opts.google_api_key + project_id = opts.google_project_id + location_id = opts.google_location_id + use_vertexai = opts.google_use_vertexai + + has_api_key = api_key and len(api_key) > 0 + has_project = project_id and len(project_id) > 0 + has_location = location_id and len(location_id) > 0 + + if use_vertexai: + if has_api_key and (has_project or has_location): + # Invalid: can't have both api_key AND project/location + log.error(f'Cloud: model="{self.model}" API key and project/location are mutually exclusive') + return None + elif has_api_key: + # Vertex AI Express Mode: api_key + vertexai, no project/location + args = {'api_key': api_key, 'vertexai': True} + elif has_project and has_location: + # Standard Vertex AI: project/location, no api_key + args = {'vertexai': True, 'project': project_id, 'location': location_id} + else: + log.error(f'Cloud: model="{self.model}" Vertex AI requires either API key (Express Mode) or project ID + location ID') + return None + else: + # Gemini Developer API: api_key only + if not has_api_key: + log.error(f'Cloud: model="{self.model}" API key not provided') + return None + args = {'api_key': api_key} + + # Debug logging + args_log = args.copy() + if args_log.get('api_key'): + args_log['api_key'] = '...' + args_log['api_key'][-4:] + log.debug(f'Cloud: model="{self.model}" args={args_log}') + return args + + def __call__(self, prompt: list[str], width: int, height: int, image: Image.Image = None): + if isinstance(prompt, list) and len(prompt) > 0: + prompt = prompt[0] + if self.client is None: + args = self.get_args() + if args is None: + return None + from google import genai # pylint: disable=no-name-in-module + self.client = genai.Client(**args) + + resolution, aspect_ratio = get_size_buckets(width, height) + response_format = { + 'type': 'video', + 'aspect_ratio': aspect_ratio, + 'resolution': resolution, + } + if image is not None: + image_bytes = io.BytesIO() + image.save(image_bytes, format='JPEG') + input_content = [ + {'type': 'image', 'data': base64.b64encode(image_bytes.getvalue()).decode('utf-8'), 'mime_type': 'image/jpeg'}, + {'type': 'text', 'text': prompt}, + ] + else: + input_content = prompt + log.debug(f'Cloud: prompt="{prompt}" size={resolution} ar={aspect_ratio} image={image} model="{self.model}" genai={genai.__version__}') + + t0 = time.time() + try: + interaction = self.client.interactions.create( + model=self.model, + input=input_content, + response_format=response_format, + ) + except Exception as e: + log.error(f'Cloud video: model="{self.model}" {e}') + return None + t1 = time.time() + log.debug(f'Cloud processing: model="{self.model}" elapsed={t1-t0:.2f}') + + try: + video_bytes = base64.b64decode(interaction.output_video.data) + return { 'bytes': video_bytes, 'images': [] } + except Exception as e: + log.error(f'Cloud download: model="{self.model}" {e}') + return None + + +def load_omni(model_name): # pylint: disable=unused-argument + pipe = GoogleOmniVideoPipeline(model_name = model_name) + return pipe diff --git a/modules/video_models/google_veo.py b/modules/video_models/google_veo.py index d0c5b3666..7c7941a9a 100644 --- a/modules/video_models/google_veo.py +++ b/modules/video_models/google_veo.py @@ -6,13 +6,13 @@ import sys sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..'))) from PIL import Image -from installer import install from modules.logger import log image_size_buckets = { '720p': 1280*720, '1080p': 1920*1080, + '4k': 3840*2160, } aspect_ratios_buckets = { '1:1': 1/1, @@ -30,7 +30,9 @@ aspect_ratios_buckets = { def google_requirements(): - install('google-genai==1.52.0') + from installer import install + install('google-genai==2.22.0') + # install('google-genai==1.75.0') # install('pydantic==2.11.7', ignore=True, quiet=True) # reload('pydantic', '2.11.7') @@ -110,7 +112,7 @@ class GoogleVeoVideoPipeline: log.debug(f'Cloud: model="{self.model}" args={args_log}') return args - def __call__(self, prompt: list[str], width: int, height: int, image: Image.Image = None, num_frames: int = 4*24): + def __call__(self, prompt: list[str], width: int = 1280, height: int = 720, image: Image.Image = None, num_frames: int = 4*24): from google import genai # pylint: disable=no-name-in-module if isinstance(prompt, list) and len(prompt) > 0: @@ -127,28 +129,30 @@ class GoogleVeoVideoPipeline: duration = 4 if duration > 8: duration = 8 - self.config=genai.types.GenerateVideosConfig( - # seed=42, - # fps=24, + self.config = genai.types.GenerateVideosConfig( duration_seconds=duration, aspect_ratio=aspect_ratio, resolution=resolution, - # person_generation='ALLOW_ALL', + person_generation='ALLOW_ALL', + # negative_prompt=negative_prompt, + # seed=42, + # fps=24, # safety_filter_level='BLOCK_NONE', - # negative_prompt=None, # enhance_prompt=True, # generate_audio=True, ) - log.debug(f'Cloud: prompt="{prompt}" size={resolution} ar={aspect_ratio} image={image} model="{self.model}" frames={num_frames} duration={duration}') + log.debug(f'Cloud: prompt="{prompt}" size={resolution} ar={aspect_ratio} image={image} model="{self.model}" duration={duration} genai={genai.__version__}') operation = None try: + t0 = time.time() if image is not None: operation = self.img2vid(prompt, image) else: operation = self.txt2vid(prompt) while not operation.done: - log.debug(f"Cloud processing: {operation}") + t1 = time.time() + log.debug(f"Cloud processing: {operation} elapsed={t1-t0:.2f}") time.sleep(10) operation = self.client.operations.get(operation) except Exception as e: @@ -172,15 +176,3 @@ class GoogleVeoVideoPipeline: def load_veo(model_name): # pylint: disable=unused-argument pipe = GoogleVeoVideoPipeline(model_name = model_name) return pipe - - -if __name__ == "__main__": - from installer import setup_logging # pylint: disable=ungrouped-imports - setup_logging() - log.info('test') - model = GoogleVeoVideoPipeline('veo-3.1-generate-preview') - img = Image.open('C:\\Users\\mandi\\OneDrive\\Generative\\Samples\\cartoon.png') - vid = model(['A beautiful young woman walking through the fantasy city'], 1280, 720, image=img) - if vid is not None: - with open("veo.mp4", "wb") as f: - f.write(vid['video']) diff --git a/modules/video_models/models_def.py b/modules/video_models/models_def.py index 9bd08ff88..cbf37b192 100644 --- a/modules/video_models/models_def.py +++ b/modules/video_models/models_def.py @@ -723,6 +723,30 @@ try: image_hijack=False, vae_hijack=False, vae_remote=False), + Model(name='MiniMax H3 Pruned SDNQ uint8', + url='https://huggingface.co/MiniMaxAI/MiniMax-H3', + repo='OzzyGT/MiniMax_H3_sdnq_8bit_pruned', + repo_cls='MiniMaxH3ModularPipeline', + workflow='fl2va', + base=True, + te_cls=None, + dit_cls=None, + te_hijack=False, + image_hijack=False, + vae_hijack=False, + vae_remote=False), + Model(name='MiniMax H3 Pruned SDNQ uint8 Ref2VA', + url='https://huggingface.co/MiniMaxAI/MiniMax-H3', + repo='OzzyGT/MiniMax_H3_sdnq_8bit_pruned', + repo_cls='MiniMaxH3ModularPipeline', + workflow='ref2va', + base=True, + te_cls=None, + dit_cls=None, + te_hijack=False, + image_hijack=False, + vae_hijack=False, + vae_remote=False), Model(name='MiniMax H3', url='https://huggingface.co/MiniMaxAI/MiniMax-H3', repo='MiniMaxAI/MiniMax-H3', @@ -747,22 +771,90 @@ try: image_hijack=False, vae_hijack=False, vae_remote=False), + Model(name='MiniMax H3 Nunchaku-Lite', + url='https://huggingface.co/rootonchair/MiniMax-H3-nunchaku-lite-int4', + repo='rootonchair/MiniMax-H3-nunchaku-lite-int4', + repo_cls='MiniMaxH3ModularPipeline', + workflow='fl2va', + base=True, + te_cls=None, + dit_cls=None, + te_hijack=False, + image_hijack=False, + vae_hijack=False, + vae_remote=False), + Model(name='MiniMax H3 VDN', + url='https://huggingface.co/OpenVDN/vdn-minimax-h3', + repo='OpenVDN/vdn-minimax-h3', + repo_cls='MiniMaxH3ModularPipeline', + workflow='fl2va', + base=True, + te_cls=None, + dit_cls=None, + te_hijack=False, + image_hijack=False, + vae_hijack=False, + vae_remote=False), ], 'Google Veo': [ Model(name='Google Veo 3.1 T2V', - url='https://gemini.google/overview/video-generation/', + url='https://ai.google.dev/gemini-api/docs/veo', repo='veo-3.1-generate-preview', custom='GoogleVeoVideoPipeline', repo_cls=None, te_cls=None, dit_cls=None), Model(name='Google Veo 3.1 I2V', - url='https://gemini.google/overview/video-generation/', + url='https://ai.google.dev/gemini-api/docs/veo', repo='veo-3.1-generate-preview', custom='GoogleVeoVideoPipeline', repo_cls=None, te_cls=None, dit_cls=None), + Model(name='Google Veo 3.1 Fast T2V', + url='https://ai.google.dev/gemini-api/docs/veo', + repo='veo-3.1-fast-generate-preview', + custom='GoogleVeoVideoPipeline', + repo_cls=None, + te_cls=None, + dit_cls=None), + Model(name='Google Veo 3.1 Fast I2V', + url='https://ai.google.dev/gemini-api/docs/veo', + repo='veo-3.1-fast-generate-preview', + custom='GoogleVeoVideoPipeline', + repo_cls=None, + te_cls=None, + dit_cls=None), + Model(name='Google Veo 3.1 Lite T2V', + url='https://ai.google.dev/gemini-api/docs/veo', + repo='veo-3.1-lite-generate-preview', + custom='GoogleVeoVideoPipeline', + repo_cls=None, + te_cls=None, + dit_cls=None), + Model(name='Google Veo 3.1 Lite I2V', + url='https://ai.google.dev/gemini-api/docs/veo', + repo='veo-3.1-lite-generate-preview', + custom='GoogleVeoVideoPipeline', + repo_cls=None, + te_cls=None, + dit_cls=None), + ], + 'Google Omni': [ + Model(name='Google Omni 1.1 Flash T2V', + url='https://ai.google.dev/gemini-api/docs/omni', + repo='gemini-omni-1.1-flash', + custom='GoogleOmniVideoPipeline', + repo_cls=None, + te_cls=None, + dit_cls=None), + Model(name='Google Omni 1.1 Flash I2V', + url='https://ai.google.dev/gemini-api/docs/omni', + repo='gemini-omni-1.1-flash', + custom='GoogleOmniVideoPipeline', + repo_cls=None, + te_cls=None, + dit_cls=None), ], } t1 = time.time() @@ -866,6 +958,7 @@ CLASS_MODES = { # the mode a pipeline class implies, for rows whose name declare 'Kandinsky5I2VPipeline': 'i2v', 'MiniMaxH3ModularPipeline': 'workflow', 'GoogleVeoVideoPipeline': 't2v', + 'GoogleOmniVideoPipeline': 't2v', } diff --git a/modules/video_models/video_load.py b/modules/video_models/video_load.py index 9fcae71d1..17844f6e1 100644 --- a/modules/video_models/video_load.py +++ b/modules/video_models/video_load.py @@ -5,7 +5,7 @@ import time import torch import transformers import diffusers -from modules import shared, errors, sd_models, sd_checkpoint, model_quant, devices, sd_hijack_te, sd_hijack_vae, modular_load +from modules import shared, errors, sd_models, sd_checkpoint, model_quant, devices, modular_load, sd_hijack_te, sd_hijack_vae, sd_hijack_modular from modules.logger import log from modules.video_models import models_def, video_utils, video_overrides, video_cache from pipelines import generic @@ -50,6 +50,10 @@ def load_custom(model_name: str): from modules.video_models.google_veo import load_veo pipe = load_veo(model_name) return pipe + if 'gemini-omni' in model_name: + from modules.video_models.google_omni import load_omni + pipe = load_omni(model_name) + return pipe return None @@ -196,7 +200,7 @@ def load_model(selected: models_def.Model): shared.sd_model = model_quant.do_post_load_quant(shared.sd_model, allow=False) sd_models.set_diffuser_offload(shared.sd_model) if modular_load.is_modular(shared.sd_model): - modular_load.install_state_hook(shared.sd_model) + sd_hijack_modular.install_state_hook(shared.sd_model) loaded_model = selected.name msg = f'Load video: cls={shared.sd_model.__class__.__name__} model="{selected.name}" time={t1-t0:.2f}' @@ -217,7 +221,8 @@ def load_upscale_vae(): repo_id = 'spacepxl/Wan2.1-VAE-upscale2x' subfolder = "diffusers/Wan2.1_VAE_upscale2x_imageonly_real_v1" - vae_decode = diffusers.AutoencoderKLWan.from_pretrained(repo_id, subfolder=subfolder, cache_dir=shared.opts.hfcache_dir) + offline_args = {'local_files_only': True} if shared.opts.offline_mode else {} + vae_decode = diffusers.AutoencoderKLWan.from_pretrained(repo_id, subfolder=subfolder, cache_dir=shared.opts.hfcache_dir, **offline_args) vae_decode.requires_grad_(False) vae_decode = vae_decode.to(device=devices.device, dtype=devices.dtype) vae_decode.eval() diff --git a/modules/video_models/video_minimax.py b/modules/video_models/video_minimax.py index 0f69af878..6841ce0f1 100644 --- a/modules/video_models/video_minimax.py +++ b/modules/video_models/video_minimax.py @@ -3,11 +3,12 @@ from modules.logger import log MIN_LATENT_FRAMES = 7 # decoder floor: fewer latent frames leave the chunked decode with nothing to emit +SHIFT_KEYS = {'scheduler': 'Video shift', 'audio_scheduler': 'Audio shift'} # infotext key per schedule -def apply_overrides(p, pipe, still: bool = False, audio: bool = True): - """Per-generation constraints shared by the video tab and the image path: canvas and frame - alignment, the bespoke scheduler guard, tiling, and the audio/still toggles.""" +def apply_overrides(p, pipe, still: bool = False, audio: bool = True, preview: bool = False, video_shift: float | None = None, audio_shift: float | None = None): + """Per-generation constraints shared by the video tab, the api and the image path: canvas and frame + alignment, the bespoke scheduler guard, the schedule shifts, tiling, and the audio/still toggles.""" if still: audio = False # a sub-second soundtrack is pure waste on a kept single frame multiple = pipe.canvas_multiple @@ -25,21 +26,29 @@ def apply_overrides(p, pipe, still: bool = False, audio: bool = True): while frames > max_frames: frames -= pipe.vae_frames_per_chunk if frames != getattr(p, 'frames', None): - log.debug(f'Pipeline: cls={pipe.__class__.__name__} frames={getattr(p, "frames", None)} aligned={frames}') + log.debug(f'Pipeline: cls={pipe.__class__.__name__} frames requested={getattr(p, "frames", None)} aligned={frames}') p.frames = frames p.task_args['num_frames'] = frames - p.steps = max(2, p.steps) - p.task_args['num_inference_steps'] = p.steps - pipe.num_timesteps = p.steps - 1 # sigma grid includes the terminal point; feeds the progress total + p.steps = max(1, p.steps) # transformer evaluations, as on every other model + p.task_args['num_inference_steps'] = p.steps + 1 # the scheduler counts the terminal sigma as a grid point + pipe.num_timesteps = p.steps # feeds the progress total if p.sampler_name not in ('None', 'Default'): log.warning(f'Pipeline: cls={pipe.__class__.__name__} sampler={p.sampler_name} unsupported: using model default') p.sampler_name = 'Default' # the model default is the bespoke scheduler pair, which discrete samplers must not replace + p.extra_generation_params.update(set_sampler_shift(pipe, video_shift=video_shift, audio_shift=audio_shift)) pipe.vae.enable_tiling() # model always tiles; the shared vae params path may have disabled it set_audio(pipe, audio) p.task_args['output'] = ['videos', 'audio', 'sampling_rate'] if audio else ['videos'] p.task_args['output_type'] = 'pil' if still else 'np' p.video_still = still + if preview: + from pipelines.minimax.minimax_latents import unpack_latents + pipe.custom_unpack_latents = unpack_latents # add a helper to unpack the video latents from the block state + else: + if hasattr(pipe, 'custom_unpack_latents'): + del pipe.custom_unpack_latents + def set_still(pipe, enabled: bool = True): """Toggle sub-floor generation for single-frame output. The duration floor is lifted only @@ -84,8 +93,27 @@ def set_audio(pipe, enabled: bool): log.debug(f'Pipeline: cls={pipe.__class__.__name__} audio=disabled') -def set_sampler_shift(pipe, video_shift: float = 12.0, audio_shift: float = 3.0): - if getattr(pipe, 'scheduler', None) is not None and getattr(pipe.scheduler, 'config', None) is not None: - pipe.scheduler.config.shift = video_shift - if getattr(pipe, 'audio_scheduler', None) is not None and getattr(pipe.audio_scheduler, 'config', None) is not None: - pipe.audio_scheduler.config.shift = audio_shift +def resolve_shift(scheduler, requested: float | None = None) -> float: + """The shift one request lands on: a positive request value, else the value the scheduler config ships.""" + if requested is not None and requested > 0: + return float(requested) + return float(scheduler.config['shift']) + + +def set_sampler_shift(pipe, video_shift: float | None = None, audio_shift: float | None = None) -> dict: + """Apply the video and audio schedule shift for one request; returns the applied values keyed for infotext. + Non-positive values resolve to the shipped schedule; default_scheduler is written too, since the Default + sampler restore copies it over scheduler each generation.""" + scheduler = getattr(pipe, 'scheduler', None) + audio_scheduler = getattr(pipe, 'audio_scheduler', None) + if any(not hasattr(s, 'set_shift') or 'shift' not in getattr(s, 'config', {}) for s in (scheduler, audio_scheduler)): + log.warning(f'Pipeline: cls={pipe.__class__.__name__} scheduler={scheduler.__class__.__name__} audio={audio_scheduler.__class__.__name__} shift unsupported') + return {} + video = resolve_shift(scheduler, video_shift) + audio = resolve_shift(audio_scheduler, audio_shift) + for target in (scheduler, getattr(pipe, 'default_scheduler', None)): + if hasattr(target, 'set_shift'): + target.set_shift(video) + audio_scheduler.set_shift(audio) + log.debug(f'Pipeline: cls={pipe.__class__.__name__} shift video={video} audio={audio} requested={video_shift}/{audio_shift}') + return {SHIFT_KEYS['scheduler']: video, SHIFT_KEYS['audio_scheduler']: audio} diff --git a/modules/video_models/video_overrides.py b/modules/video_models/video_overrides.py index f0e760896..a52e2d2f9 100644 --- a/modules/video_models/video_overrides.py +++ b/modules/video_models/video_overrides.py @@ -114,4 +114,4 @@ def set_overrides(p: processing.StableDiffusionProcessingVideo, selected: Model) # MiniMax H3 if 'MiniMaxH3' in cls: from modules.video_models import video_minimax - video_minimax.apply_overrides(p, shared.sd_model, still=getattr(p, 'video_still', False), audio=getattr(p, 'video_audio', True)) + video_minimax.apply_overrides(p, shared.sd_model, still=getattr(p, 'video_still', False), audio=getattr(p, 'video_audio', True), video_shift=getattr(p, 'sampler_shift', None), audio_shift=getattr(p, 'audio_shift', None)) diff --git a/modules/video_models/video_run.py b/modules/video_models/video_run.py index db9ee06b8..870dd47f0 100644 --- a/modules/video_models/video_run.py +++ b/modules/video_models/video_run.py @@ -106,6 +106,7 @@ def run(selected: models_def.Model, *, sampler_name: str = 'Default', sampler_shift: float = -1.0, dynamic_shift: bool = False, + audio_shift: float = -1.0, seed: int = -1, guidance_scale: float = -1.0, guidance_true: float = -1.0, @@ -162,6 +163,7 @@ def run(selected: models_def.Model, *, seed=int(seed), sampler_name=sampler_name, sampler_shift=float(sampler_shift), + audio_shift=float(audio_shift), steps=int(steps), width=16 * int(width // 16), height=16 * int(height // 16), diff --git a/modules/video_models/video_ui.py b/modules/video_models/video_ui.py index 74af572aa..07dafb2e5 100644 --- a/modules/video_models/video_ui.py +++ b/modules/video_models/video_ui.py @@ -60,8 +60,15 @@ def refresh_upscalers(): from modules import shared, modelloader modelloader.load_upscalers() # refresh upscalers = [u for u in shared.sd_upscalers if 'output_type' in inspect.signature(u.scaler.do_upscale).parameters.keys()] - upscaler_names = ['None'] + [u.name for u in upscalers] - return upscaler_names + return ['None'] + [u.name for u in upscalers] + + +def video_upscaler_choices(selected='None', refresh=False): + from modules import shared, modelloader + if refresh: + modelloader.load_upscalers() + upscalers = [upscaler for upscaler in shared.sd_upscalers if 'output_type' in inspect.signature(upscaler.scaler.do_upscale).parameters.keys()] + return ui_sections.upscaler_choices(['None'] + [upscaler.name for upscaler in upscalers], selected) def create_ui_outputs(): @@ -96,8 +103,17 @@ def create_ui_outputs(): with gr.Row(): upscale_scale = gr.Slider(label="Video scale", minimum=1, maximum=4, value=1, step=0.1, elem_id="video_outputs_upscale_scale") with gr.Row(): - upscale_upscaler = gr.Dropdown(label="Video Upscaler", choices=['None'], value='None', type='value', elem_id="video_outputs_upscale_upscaler") - _upscale_upscaler_btn = ui_common.create_refresh_button(upscale_upscaler, refresh_upscalers) + upscaler_names, filtered = video_upscaler_choices() + ui_sections.create_filter_indicator('video', 'Upscaler', filtered) + upscale_upscaler = gr.Dropdown(label="Video Upscaler", choices=upscaler_names, value='None', type='value', elem_id="video_outputs_upscale_upscaler") + + def refresh_video_upscalers(selected): + choices, _ = video_upscaler_choices(selected, refresh=True) + value = selected if selected in choices else choices[0] + return gr.update(choices=choices, value=value) + + _upscale_upscaler_btn = ToolButton(value=ui_symbols.refresh, elem_id='video_upscalers_refresh') + _upscale_upscaler_btn.click(fn=refresh_video_upscalers, inputs=[upscale_upscaler], outputs=[upscale_upscaler], show_progress='hidden') return mp4_fps, mp4_interpolate, mp4_codec, mp4_ext, mp4_opt, mp4_video, mp4_frames, mp4_sf, mp4_thumb, upscale_scale, upscale_upscaler diff --git a/package.json b/package.json index 6331b09ea..f8ed01a75 100644 --- a/package.json +++ b/package.json @@ -44,7 +44,7 @@ "dev:kanvas": "cd extensions-builtin/sdnext-kanvas && build --profile development", "dev:core": "build --profile development --config ui/.build.json", "ruff": ". venv/bin/activate && ruff check", - "pylint": ". venv/bin/activate && pylint --disable fixme *.py modules/ pipelines/ scripts/ extensions-builtin/ | grep -v '^*'", + "pylint": ". venv/bin/activate && pylint --disable fixme *.py modules pipelines scripts extensions-builtin", "pyright": ". venv/bin/activate && pyright --threads 4", "ty": ". venv/bin/activate && ty check --force-exclude", "codespell": ". venv/bin/activate && codespell", diff --git a/pipelines/anima/__init__.py b/pipelines/anima/__init__.py index 6d7953090..4dc2b339e 100644 --- a/pipelines/anima/__init__.py +++ b/pipelines/anima/__init__.py @@ -12,16 +12,31 @@ knobs that differ from the native-loader defaults: - Cosmos 1.0 structural marker: any community file whose state dict contains a Cosmos 1.0 nested key (``net.blocks.block1.*``) is rejected with a clear error since Anima is Cosmos 2.0 only. +- ``num_layers`` comes from the block indices in the file, so depth-expanded + finetunes (Anima-2.9B: 40 blocks) load against the 28-layer base config. - All other knobs (prefixes, ``acceptable_missing`` buffers) use the defaults from :mod:`pipelines.native_transformer`. """ +import re + import diffusers from diffusers.loaders.single_file_utils import convert_cosmos_transformer_checkpoint_to_diffusers from pipelines.native_transformer import TransformerSpec, SiblingSpec +BLOCK_INDEX = re.compile(r'^(?:transformer_)?blocks\.(\d+)\.') + + +def infer_config(state_dict: dict) -> dict: + """Derive ``num_layers`` from the highest transformer block index in the file.""" + indices = [int(m.group(1)) for key in state_dict if (m := BLOCK_INDEX.match(key))] + if not indices: + return {} + return {'num_layers': max(indices) + 1} + + ANIMA_SPEC = TransformerSpec( cls=diffusers.CosmosTransformer3DModel, converter=convert_cosmos_transformer_checkpoint_to_diffusers, @@ -37,4 +52,5 @@ ANIMA_SPEC = TransformerSpec( 'unsupported Cosmos 1.0 structure', ), ), + infer_config=infer_config, ) diff --git a/pipelines/anima/anima_lora.py b/pipelines/anima/anima_lora.py index cea98faa8..bc7d9c7ab 100644 --- a/pipelines/anima/anima_lora.py +++ b/pipelines/anima/anima_lora.py @@ -33,8 +33,10 @@ the standard ``NetworkWeights.w`` slots rather than being baked into the factor weights at load time. """ +import re from collections import OrderedDict +from modules.logger import log from modules.lora import native_adapter @@ -178,12 +180,78 @@ def network_prefix_for(prefix_used): return "lora_transformer_" +# === Depth-expanded checkpoint block remap === +# +# Anima 2.9B grows the 28-block DiT to 40 by interleaving new blocks among the +# originals, so a block index trained against 1.0 no longer names the same +# block. Keyed by (base depth, expanded depth) rather than by model name, so +# any Anima transformer of a listed depth picks up the table. + +BLOCK_EXPANSIONS = { + (28, 40): (2, 5, 8, 11, 14, 17, 21, 24, 27, 30, 33, 36), +} + +BLOCK_INDEX = re.compile(r"^blocks([._])(\d+)(?=[._])") + + +def expansion_map(base_depth, expanded_depth): + """Map each base-model block index to its position in the expanded model.""" + inserted = set(BLOCK_EXPANSIONS[(base_depth, expanded_depth)]) + return dict(enumerate(n for n in range(expanded_depth) if n not in inserted)) + + +def transformer_depth(): + """Block count of the loaded transformer, or 0 when there is nothing to read.""" + from modules import shared + pipe = getattr(shared.sd_model, "pipe", shared.sd_model) + blocks = getattr(getattr(pipe, "transformer", None), "transformer_blocks", None) + return len(blocks) if blocks is not None else 0 + + +def block_index(base): + """Leading ``blocks.N`` / ``blocks_N`` index of a parsed key, else None.""" + m = BLOCK_INDEX.match(base) + return int(m.group(2)) if m is not None else None + + +def remap_blocks(groups): + """Shift base-depth block indices onto the blocks that carry those weights. + + A LoRA whose highest block index fits inside the base depth was trained on + the unexpanded model. Only transformer keys move: llm_adapter and text + encoder keys carry their own unrelated numbering. + """ + indices = [i for (prefix, base) in groups + if network_prefix_for(prefix) == "lora_transformer_" and (i := block_index(base)) is not None] + if not indices: + return groups + depth = transformer_depth() + match = next(((b, e) for (b, e) in BLOCK_EXPANSIONS if e == depth and max(indices) < b), None) + if match is None: + return groups + table = expansion_map(*match) + out = {} + for (prefix, base), w in groups.items(): + i = block_index(base) if network_prefix_for(prefix) == "lora_transformer_" else None + if i is not None: + base = BLOCK_INDEX.sub(rf"blocks\g<1>{table[i]}", base) + out[(prefix, base)] = w + log.info(f'Network load: arch=anima block remap {match[0]}->{match[1]} keys={len(indices)}') + return out + + +def group_by_suffixes_remapped(state_dict, suffixes, **kwargs): + """Group by suffix, then remap block indices for depth-expanded transformers.""" + return remap_blocks(native_adapter.group_by_suffixes(state_dict, suffixes, **kwargs)) + + # === Native loaders (thin wrappers over native_adapter generics) === _BIND_KWARGS = dict( resolve_targets=resolve_targets, prefixes=ANIMA_PREFIXES, network_prefix=network_prefix_for, + group_by_suffixes_fn=group_by_suffixes_remapped, arch_name="anima", ) diff --git a/pipelines/chroma/chroma_lora.py b/pipelines/chroma/chroma_lora.py index 3cd0395a6..c84faf036 100644 --- a/pipelines/chroma/chroma_lora.py +++ b/pipelines/chroma/chroma_lora.py @@ -44,19 +44,6 @@ from modules.lora.native_adapter import ChunkSpec KNOWN_PREFIXES = native_adapter.KNOWN_PREFIXES_DEFAULT -# distilled_guidance_layer. is deliberately a bare-BFL prefix, not a -# bare-diffusers one: the resolver renames BFL MLP leaves (in_layer/out_layer) -# and passes diffusers-named leaves (linear_1/linear_2, in_proj, out_proj, -# norms.N) through verbatim, so both namings route correctly. -BARE_FLUX_PREFIXES = ( - "double_blocks.", "single_blocks.", - "img_in.", "txt_in.", "final_layer.", "distilled_guidance_layer.", -) - -BARE_DIFFUSERS_PREFIXES = ( - "transformer_blocks.", "single_transformer_blocks.", -) - # === Fused weight dims === # Defaults match Chroma1-HD (``inner_dim = num_attention_heads * @@ -97,8 +84,6 @@ def parse_key(key, suffixes): return native_adapter.parse_key( key, suffixes, prefixes=KNOWN_PREFIXES, - bare_prefixes=BARE_FLUX_PREFIXES, - bare_diffusers_prefixes=BARE_DIFFUSERS_PREFIXES, ) @@ -107,8 +92,6 @@ def group_by_suffixes(state_dict, suffixes): return native_adapter.group_by_suffixes( state_dict, suffixes, prefixes=KNOWN_PREFIXES, - bare_prefixes=BARE_FLUX_PREFIXES, - bare_diffusers_prefixes=BARE_DIFFUSERS_PREFIXES, ) @@ -122,14 +105,16 @@ def resolve_targets(prefix_used, base): - ``lora_unet_``: kohya underscore-flat Flux path; parse block type/index and module suffix, rename to diffusers. - - ``diffusion_model.`` or bare BFL (None): dotted Flux path; same rewrite. + - ``diffusion_model.`` or bare (the sentinel): dotted Flux path; same + rewrite. BFL MLP leaves under ``distilled_guidance_layer`` rename and + diffusers-named leaves pass through verbatim, so both namings route. Universal passthrough prefixes are handled upstream by :func:`native_adapter.resolve_group_targets`. """ if prefix_used == "lora_unet_": return _kohya_to_diffusers(base) - if prefix_used in (None, "diffusion_model."): + if prefix_used in (BARE_DIFFUSERS_PREFIX_USED, "diffusion_model."): return _bfl_to_diffusers(base) return [] @@ -262,8 +247,6 @@ def _split_single_linear1(block_idx): _BIND_KWARGS = dict( resolve_targets=resolve_targets, prefixes=KNOWN_PREFIXES, - bare_prefixes=BARE_FLUX_PREFIXES, - bare_diffusers_prefixes=BARE_DIFFUSERS_PREFIXES, arch_name="chroma", ) diff --git a/pipelines/ernie/ernie_lora.py b/pipelines/ernie/ernie_lora.py index b0b072be3..2255851f3 100644 --- a/pipelines/ernie/ernie_lora.py +++ b/pipelines/ernie/ernie_lora.py @@ -25,10 +25,6 @@ from modules.lora import native_adapter KNOWN_PREFIXES = native_adapter.KNOWN_PREFIXES_DEFAULT -BARE_DIFFUSERS_PREFIXES = ( - "layers.", "adaLN_modulation.", "final_norm.", "final_linear.", -) - # === Re-exports for test/back-compat === @@ -60,7 +56,6 @@ def parse_key(key, suffixes): return native_adapter.parse_key( key, suffixes, prefixes=KNOWN_PREFIXES, - bare_diffusers_prefixes=BARE_DIFFUSERS_PREFIXES, ) @@ -69,7 +64,6 @@ def group_by_suffixes(state_dict, suffixes): return native_adapter.group_by_suffixes( state_dict, suffixes, prefixes=KNOWN_PREFIXES, - bare_diffusers_prefixes=BARE_DIFFUSERS_PREFIXES, ) @@ -95,7 +89,6 @@ def resolve_targets(prefix_used, base): _BIND_KWARGS = dict( resolve_targets=resolve_targets, prefixes=KNOWN_PREFIXES, - bare_diffusers_prefixes=BARE_DIFFUSERS_PREFIXES, arch_name="ernieimage", ) diff --git a/pipelines/flux/flux2_lora.py b/pipelines/flux/flux2_lora.py index 681c65087..95651d859 100644 --- a/pipelines/flux/flux2_lora.py +++ b/pipelines/flux/flux2_lora.py @@ -64,8 +64,6 @@ BARE_FLUX_PREFIXES = ( "double_stream_modulation_", ) -BARE_DIFFUSERS_PREFIXES = ("single_transformer_blocks.", "transformer_blocks.") - # === BFL to diffusers mapping === @@ -161,8 +159,6 @@ def parse_key(key, suffixes): return native_adapter.parse_key( key, suffixes, prefixes=KNOWN_PREFIXES, - bare_prefixes=BARE_FLUX_PREFIXES, - bare_diffusers_prefixes=BARE_DIFFUSERS_PREFIXES, ) @@ -171,8 +167,6 @@ def group_by_suffixes(state_dict, suffixes): return native_adapter.group_by_suffixes( state_dict, suffixes, prefixes=KNOWN_PREFIXES, - bare_prefixes=BARE_FLUX_PREFIXES, - bare_diffusers_prefixes=BARE_DIFFUSERS_PREFIXES, ) @@ -183,15 +177,16 @@ def resolve_targets(prefix_used, base): """Return ``[(diffusers_path, ChunkSpec | None), ...]`` for a parsed group key. For ``lora_unet_`` prefix, applies ``KOHYA_SUFFIX_MAP`` then ``F2_*_MAP``. - For BFL / bare-BFL, applies ``F2_*_MAP`` directly. Unrecognized prefixes - return an empty list. + For BFL and bare keys, applies ``F2_*_MAP`` directly; a bare path the maps + do not know binds verbatim upstream. Unrecognized prefixes return an empty + list. Universal passthrough prefixes (including ``lycoris_``) are handled upstream by :func:`native_adapter.resolve_group_targets`. """ if prefix_used == "lora_unet_": return _kohya_to_diffusers_targets(base) - if prefix_used in (None, "diffusion_model."): + if prefix_used in (BARE_DIFFUSERS_PREFIX_USED, "diffusion_model."): return _bfl_to_diffusers_targets(base) return [] @@ -256,8 +251,6 @@ def _bfl_to_diffusers_targets(base): _BIND_KWARGS = dict( resolve_targets=resolve_targets, prefixes=KNOWN_PREFIXES, - bare_prefixes=BARE_FLUX_PREFIXES, - bare_diffusers_prefixes=BARE_DIFFUSERS_PREFIXES, arch_name="f2", ) diff --git a/pipelines/generic_text_encoder.py b/pipelines/generic_text_encoder.py index e03c32dec..1c2662c11 100644 --- a/pipelines/generic_text_encoder.py +++ b/pipelines/generic_text_encoder.py @@ -21,6 +21,8 @@ def get_shared(cls, repo_id, subfolder=None, variant=None, shared_id: str | None identifiers = [] if isinstance(identifiers, str): identifiers = [identifiers] + if not isinstance(identifiers, list): + identifiers = [] identifiers = [identifier.lower() for identifier in identifiers if identifier is not None] shared_id = shared_id or repo_id.lower() if item['cls'] == cls and (not identifiers or any(identifier in shared_id for identifier in identifiers)): @@ -64,6 +66,8 @@ def load_local_file(local_file, cls_name, quant_type, repo_id=None, dtype=None, cfg_args = {'cache_dir': shared.opts.hfcache_dir} if extra.get('subfolder') is not None: cfg_args['subfolder'] = extra['subfolder'] + if shared.opts.offline_mode: + cfg_args['local_files_only'] = True log.debug(f'Load model: text_encoder="{local_file}" cls={cls_name.__name__} config="{config_repo}" quant="{quant_type}" loader={get_loader("transformers")} file=safetensors') config = transformers.AutoConfig.from_pretrained(config_repo, **cfg_args) state_dict = load_file(local_file) @@ -120,6 +124,8 @@ def load_text_encoder( load_args['use_safetensors'] = True if trust_remote_code: load_args['trust_remote_code'] = True + if shared.opts.offline_mode: + load_args['local_files_only'] = True # 1. load override from local file local_file = None diff --git a/pipelines/generic_transformer.py b/pipelines/generic_transformer.py index 198bf3483..a33b1192c 100644 --- a/pipelines/generic_transformer.py +++ b/pipelines/generic_transformer.py @@ -24,7 +24,6 @@ def load_transformer( override_slot='primary', trust_remote_code=False, **kwargs): - """Load a DiT transformer from the base repo, or from a user-selected single file when the slot's UNET override dropdown is set. @@ -48,6 +47,10 @@ def load_transformer( modules_to_not_convert = [] if modules_dtype_dict is None: modules_dtype_dict = {} + if cls_name is None: + from diffusers import AutoModel + cls_name = AutoModel + offline_args = {'local_files_only': True} if shared.opts.offline_mode else {} jobid = shared.state.begin('Load DiT') try: load_args, quant_args = model_quant.get_dit_args(load_config, module='Model', device_map=True, allow_quant=allow_quant, modules_to_not_convert=modules_to_not_convert, modules_dtype_dict=modules_dtype_dict) @@ -73,13 +76,15 @@ def load_transformer( load_args['use_safetensors'] = True if trust_remote_code: load_args['trust_remote_code'] = True - return cls_name.from_pretrained( + load_kwargs = {**load_args, **quant_args, **offline_args, **kwargs} + module = cls_name.from_pretrained( repo_id, cache_dir=shared.opts.hfcache_dir, - **load_args, - **quant_args, - **kwargs, + **load_kwargs, ) + if cls_name.__name__ == 'AutoModel': + log.debug(f'Load model: transformer="{repo_id}" cls={module.__class__.__name__}') + return module local_file = None override_name = None @@ -151,29 +156,26 @@ def load_transformer( load_args.pop('device_map', None) # single-file uses different syntax loader = cls_name.from_single_file if hasattr(cls_name, 'from_single_file') else cls_name.from_pretrained log.debug(f'Load model: transformer="{local_file}" cls={cls_name.__name__} quant="{quant_type}" loader={get_loader("diffusers")} method={loader.__name__} args={load_args}') + load_kwargs = {**load_args, **quant_args, **offline_args, **kwargs} transformer = loader( local_file, cache_dir=shared.opts.hfcache_dir, - **load_args, - **quant_args, - **kwargs, + **load_kwargs, ) - # 4. default loading from diffusers repo (also the fallback when an - # incompatible override is dropped above) + # 4. default loading from diffusers repo (also the fallback when an incompatible override is dropped above) else: transformer = load_from_repo() - # mark the dropdown selection as loaded so the slot's onchange callback - # does not force a redundant full reload for an already-consumed override - if transformer is not None and override_name is not None and getattr(shared.opts, override_opt, None) == override_name: + # mark the dropdown selection as loaded so the slot's onchange callback, does not force a redundant full reload for an already-consumed override + if (transformer is not None) and (override_name is not None) and getattr(shared.opts, override_opt, None) == override_name: setattr(sd_unet, tracker_attr, override_name) sd_models.allow_post_quant = False # we already handled it if shared.opts.diffusers_offload_mode != 'none' and transformer is not None: sd_models.move_model(transformer, devices.cpu) - if transformer is not None and not hasattr(transformer, 'quantization_config'): # attach quantization_config + if (transformer is not None) and not hasattr(transformer, 'quantization_config'): # attach quantization_config if hasattr(transformer, 'config') and hasattr(transformer.config, 'quantization_config'): transformer.quantization_config = transformer.config.quantization_config elif (quant_type is not None) and (quant_args.get('quantization_config', None) is not None): @@ -193,8 +195,7 @@ def load_transformer( log.debug(f'Load model: transformer="{repo_id}" quant="{quant_type}" size={module_size:.3f} params={param_num:.3f} memory={module_memory}') try: - # quantized models legitimately report the storage dtype (e.g. fp8 comfy_quant - # adopted via SDNQ); the compute dtype lives in the dequantizers, not the params + # quantized models legitimately report the storage dtype (e.g. fp8 comfy_quant adopted via SDNQ); the compute dtype lives in the dequantizers, not the params if getattr(transformer, 'quantization_config', None) is None: actual_dtype = transformer.dtype if isinstance(actual_dtype, torch.dtype) and isinstance(dtype, torch.dtype) and actual_dtype != dtype: diff --git a/pipelines/krea2/krea2_lora.py b/pipelines/krea2/krea2_lora.py index af3e54681..30d5df0e4 100644 --- a/pipelines/krea2/krea2_lora.py +++ b/pipelines/krea2/krea2_lora.py @@ -23,10 +23,6 @@ KNOWN_PREFIXES = native_adapter.KNOWN_PREFIXES_DEFAULT # Top-level module names that a bare LoRA key can start with: the transformer's own # checkpoint-style names plus the upstream-diffusers names (as saved by # ``Krea2Transformer2DModel.save_lora_adapter()``). -BARE_DIFFUSERS_PREFIXES = ( - "blocks.", "txtfusion.", "first.", "last.", "tmlp.", "tproj.", "txtmlp.", - "transformer_blocks.", "text_fusion.", "img_in.", "txt_in.", "time_embed.", "time_mod_proj.", "final_layer.", -) # Upstream-diffusers attention/ff leaves -> checkpoint leaves (block-level modules). DIFFUSERS_LEAF_MAP = { @@ -83,7 +79,6 @@ def parse_key(key, suffixes): return native_adapter.parse_key( key, suffixes, prefixes=KNOWN_PREFIXES, - bare_diffusers_prefixes=BARE_DIFFUSERS_PREFIXES, ) @@ -92,7 +87,6 @@ def group_by_suffixes(state_dict, suffixes): return native_adapter.group_by_suffixes( state_dict, suffixes, prefixes=KNOWN_PREFIXES, - bare_diffusers_prefixes=BARE_DIFFUSERS_PREFIXES, ) @@ -145,7 +139,6 @@ def _underscore_to_dotted(base): _BIND_KWARGS = dict( resolve_targets=resolve_targets, prefixes=KNOWN_PREFIXES, - bare_diffusers_prefixes=BARE_DIFFUSERS_PREFIXES, arch_name="krea2", ) diff --git a/pipelines/krea2/transformer_krea2.py b/pipelines/krea2/transformer_krea2.py index 643d926ba..c09e4be84 100644 --- a/pipelines/krea2/transformer_krea2.py +++ b/pipelines/krea2/transformer_krea2.py @@ -342,6 +342,16 @@ class Krea2Transformer2DModel(ModelMixin, ConfigMixin, PeftAdapterMixin, FromOri else: mask = None + from modules.attention.sparse import layout as sparse_layout # delayed, this module is also importable without the webui + if attention_mask is not None: + # the text stream is padded to a fixed length and the joint sequence to a multiple of 256, so the live + # runs are what the layout must report; a wholly padded key block is dropped rather than pinned + live = attention_mask.any(dim=0) + segments = sparse_layout.segments_from_live(live[:txtlen], "text") + sparse_layout.segments_from_live(live[txtlen:], "image") + else: + segments = [("text", txtlen), ("image", imglen)] + sparse_layout.publish_segments(segments, source="krea2") + freqs = self.posemb(position_ids) for block in self.blocks: diff --git a/pipelines/llada/__init__.py b/pipelines/llada/__init__.py new file mode 100644 index 000000000..af8b8951d --- /dev/null +++ b/pipelines/llada/__init__.py @@ -0,0 +1,8 @@ +from .pipeline_llada_image import LLaDAImagePipeline +from .pipeline_output import LLaDAImagePipelineOutput +from .transformer_llada_image import LLaDAImageQueryFormerModel +from .transformer_llada_image import LLaDAImageSigVQModel +from .transformer_llada_image import LLaDAImageTextProjectionModel +from .transformer_llada_image import LLaDAImageTransformer2DModel + +__all__ = ['LLaDAImagePipeline', 'LLaDAImagePipelineOutput', 'LLaDAImageQueryFormerModel', 'LLaDAImageSigVQModel', 'LLaDAImageTextProjectionModel', 'LLaDAImageTransformer2DModel'] diff --git a/pipelines/llada/configuration_llada2uni_moe.py b/pipelines/llada/configuration_llada2uni_moe.py new file mode 100644 index 000000000..fdd7a8845 --- /dev/null +++ b/pipelines/llada/configuration_llada2uni_moe.py @@ -0,0 +1,133 @@ +# Copyright 2025 Antgroup and The HuggingFace Inc. team. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +"""LLaDA2 MoE model configuration.""" + +from transformers.configuration_utils import PretrainedConfig + + +class LLaDA2MoeConfig(PretrainedConfig): + r""" + Configuration class for the LLaDA2 MoE model. + + ```python + >>> from configuration_llada2uni_moe import LLaDA2MoeConfig + >>> config = LLaDA2MoeConfig() + ``` + """ + + # Keep the original value because it selects the fused-expert implementation. + model_type = "llada2_moe_veomni" + + def __init__( + self, + vocab_size=30592, + hidden_size=1024, + intermediate_size=None, + num_hidden_layers=24, + num_attention_heads=16, + num_key_value_heads=0, + head_dim=None, + hidden_act="silu", + use_qkv_bias=False, + use_qk_norm=True, + use_bias=True, + rms_norm_eps=1e-05, + tie_word_embeddings=False, + attention_dropout=0.1, + initializer_range=0.02, + max_position_embeddings=16384, + rope_theta=10000.0, + rope_parameters=None, + rope_scaling=None, + partial_rotary_factor=0.5, + use_cache=True, + sliding_window=None, + pad_token_id=126081, + # Image + image_token_offset=157184, + # MoE + num_experts=16, + num_shared_experts=0, + num_experts_per_tok=2, + n_group=8, + topk_group=4, + routed_scaling_factor=2.5, + moe_router_enable_expert_bias=True, + norm_topk_prob=True, + router_dtype="fp32", + score_function="sigmoid", + moe_intermediate_size=None, + first_k_dense_replace=0, + output_router_logits=False, + **kwargs, + ): + self.vocab_size = vocab_size + self.hidden_size = hidden_size + self.intermediate_size = intermediate_size + self.num_hidden_layers = num_hidden_layers + self.num_attention_heads = num_attention_heads + self.num_key_value_heads = num_key_value_heads + self.head_dim = head_dim or hidden_size // num_attention_heads + self.hidden_act = hidden_act + self.use_qkv_bias = use_qkv_bias + self.use_qk_norm = use_qk_norm + self.use_bias = use_bias + self.rms_norm_eps = rms_norm_eps + self.attention_dropout = attention_dropout + self.initializer_range = initializer_range + self.max_position_embeddings = max_position_embeddings + self.rope_theta = rope_theta + self.rope_scaling = rope_scaling + self.partial_rotary_factor = partial_rotary_factor + self.use_cache = use_cache + self.sliding_window = sliding_window + + # Image token offset: VQ codebook indices are shifted by this amount in the vocabulary + self.image_token_offset = image_token_offset + + # RoPE parameters dict — used by LLaDA2MoeRotaryEmbedding + if rope_parameters is None: + rope_parameters = { + "rope_type": "default", + "rope_theta": rope_theta, + "partial_rotary_factor": partial_rotary_factor, + } + self.rope_parameters = rope_parameters + + # MoE + self.num_experts = num_experts + self.num_shared_experts = num_shared_experts + self.num_experts_per_tok = num_experts_per_tok + self.n_group = n_group + self.topk_group = topk_group + self.routed_scaling_factor = routed_scaling_factor + self.moe_router_enable_expert_bias = moe_router_enable_expert_bias + self.norm_topk_prob = norm_topk_prob + self.router_dtype = router_dtype + self.score_function = score_function + self.moe_intermediate_size = moe_intermediate_size + self.first_k_dense_replace = first_k_dense_replace + self.output_router_logits = output_router_logits + + # FP8 quantization flag — set to True to use FP8Linear for experts + self.use_fp8_experts = kwargs.pop("use_fp8_experts", False) + + super().__init__( + pad_token_id=pad_token_id, + tie_word_embeddings=tie_word_embeddings, + **kwargs, + ) + + +__all__ = ["LLaDA2MoeConfig"] diff --git a/pipelines/llada/fused_moe_ops.py b/pipelines/llada/fused_moe_ops.py new file mode 100644 index 000000000..30296fcbe --- /dev/null +++ b/pipelines/llada/fused_moe_ops.py @@ -0,0 +1,375 @@ +# Copyright 2025 Bytedance Ltd. and/or its affiliates +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Standalone, inference-only VeOmni v0.1.0 fused-MoE compatibility shim. + +This module preserves the ``veomni.ops.fused_moe_forward`` call signature used +by VeOmni v0.1.0 while removing VeOmni's training, Expert Parallelism (EP), NPU, +and Seed-kernel dependencies. It is intended for single-device inference only. + +The CUDA fast path uses a small Triton grouped-linear kernel. If Triton is not +available, the tensors are not on CUDA, or ``LLADA_MOE_BACKEND=eager`` is set, +the implementation falls back to ordinary PyTorch operations. + +Replace the original model-code import with, for example, +``from .fused_moe_v010 import fused_moe_forward``. + +Derived from ByteDance-Seed/VeOmni v0.1.0.post1: +https://github.com/ByteDance-Seed/VeOmni/tree/v0.1.0.post1 +""" + +from __future__ import annotations + +import os + +import torch +import torch.nn.functional as F + +try: + import triton + import triton.language as tl +except ImportError: # The eager fallback does not require Triton. + triton = None + tl = None + + +_SUPPORTED_TRITON_DTYPES = (torch.float16, torch.bfloat16) + + +if triton is not None: + + @triton.jit + def _grouped_linear_kernel( + input_ptr, + weight_ptr, + output_ptr, + expert_cumsum_ptr, + N: tl.constexpr, + K: tl.constexpr, + BLOCK_M: tl.constexpr, + BLOCK_N: tl.constexpr, + BLOCK_K: tl.constexpr, + ): + """Compute per-expert ``input @ weight.T`` for contiguous tensors.""" + block_m = tl.program_id(axis=0) + block_n = tl.program_id(axis=1) + expert = tl.program_id(axis=2) + + expert_start = tl.load(expert_cumsum_ptr + expert - 1, mask=expert > 0, other=0) + expert_end = tl.load(expert_cumsum_ptr + expert) + expert_tokens = expert_end - expert_start + + if block_m * BLOCK_M >= expert_tokens: + return + + row_offsets = block_m * BLOCK_M + tl.arange(0, BLOCK_M) + col_offsets = block_n * BLOCK_N + tl.arange(0, BLOCK_N) + k_offsets = tl.arange(0, BLOCK_K) + + input_ptrs = ( + input_ptr + + (expert_start + row_offsets[:, None]) * K + + k_offsets[None, :] + ) + weight_ptrs = ( + weight_ptr + + expert * N * K + + col_offsets[None, :] * K + + k_offsets[:, None] + ) + + accumulator = tl.zeros((BLOCK_M, BLOCK_N), dtype=tl.float32) + for k_block in range(0, tl.cdiv(K, BLOCK_K)): + remaining_k = K - k_block * BLOCK_K + inputs = tl.load( + input_ptrs, + mask=(row_offsets[:, None] < expert_tokens) & (k_offsets[None, :] < remaining_k), + other=0.0, + ) + weights = tl.load( + weight_ptrs, + mask=(col_offsets[None, :] < N) & (k_offsets[:, None] < remaining_k), + other=0.0, + ) + accumulator += tl.dot(inputs, weights) + input_ptrs += BLOCK_K + weight_ptrs += BLOCK_K + + output_ptrs = ( + output_ptr + + (expert_start + row_offsets[:, None]) * N + + col_offsets[None, :] + ) + tl.store( + output_ptrs, + accumulator, + mask=(row_offsets[:, None] < expert_tokens) & (col_offsets[None, :] < N), + ) + + +def _validate_inputs( + num_experts: int, + routing_weights: torch.Tensor, + selected_experts: torch.Tensor, + hidden_states: torch.Tensor, + fc1_1_weight: torch.Tensor, + fc1_2_weight: torch.Tensor, + fc2_weight: torch.Tensor, +) -> None: + if num_experts <= 0: + raise ValueError(f"num_experts must be positive, got {num_experts}") + if torch.is_grad_enabled(): + raise RuntimeError( + "This standalone fused_moe_forward is inference-only. Call it under " + "torch.no_grad() or torch.inference_mode()." + ) + if hidden_states.ndim != 2: + raise ValueError(f"hidden_states must have shape [tokens, hidden], got {tuple(hidden_states.shape)}") + if routing_weights.ndim != 2 or selected_experts.shape != routing_weights.shape: + raise ValueError( + "routing_weights and selected_experts must have the same [tokens, top_k] shape, got " + f"{tuple(routing_weights.shape)} and {tuple(selected_experts.shape)}" + ) + if routing_weights.shape[1] == 0: + raise ValueError("top_k must be positive") + if routing_weights.shape[0] != hidden_states.shape[0]: + raise ValueError("routing_weights and hidden_states must contain the same number of tokens") + if selected_experts.dtype not in (torch.int32, torch.int64): + raise TypeError(f"selected_experts must be int32 or int64, got {selected_experts.dtype}") + if fc1_1_weight.ndim != 3 or fc1_2_weight.ndim != 3 or fc2_weight.ndim != 3: + raise ValueError("expert weights must be rank-3 tensors") + if fc1_1_weight.shape != fc1_2_weight.shape: + raise ValueError("fc1_1_weight and fc1_2_weight must have identical shapes") + + experts, intermediate_size, hidden_size = fc1_1_weight.shape + expected_fc2_shape = (experts, hidden_size, intermediate_size) + if experts != num_experts: + raise ValueError(f"num_experts={num_experts}, but the weights contain {experts} experts") + if hidden_states.shape[1] != hidden_size: + raise ValueError(f"hidden size is {hidden_states.shape[1]}, but the weights expect {hidden_size}") + if tuple(fc2_weight.shape) != expected_fc2_shape: + raise ValueError(f"fc2_weight must have shape {expected_fc2_shape}, got {tuple(fc2_weight.shape)}") + if selected_experts.numel(): + # These scalar checks synchronize CUDA once, before launching harder-to-debug kernels. + min_expert = int(selected_experts.min().item()) + max_expert = int(selected_experts.max().item()) + if min_expert < 0 or max_expert >= num_experts: + raise ValueError(f"selected expert IDs must be in [0, {num_experts}), got [{min_expert}, {max_expert}]") + + devices = { + hidden_states.device, + routing_weights.device, + selected_experts.device, + fc1_1_weight.device, + fc1_2_weight.device, + fc2_weight.device, + } + if len(devices) != 1: + raise ValueError(f"all inputs and weights must be on one device, got {sorted(map(str, devices))}") + + +def _route_tokens( + num_experts: int, + routing_weights: torch.Tensor, + selected_experts: torch.Tensor, + hidden_states: torch.Tensor, +) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor, torch.Tensor]: + """Sort routed token copies by expert and return the inverse permutation.""" + top_k = selected_experts.shape[1] + flat_experts = selected_experts.reshape(-1).to(torch.int64) + order = torch.argsort(flat_experts, stable=True) + sorted_hidden_states = hidden_states[torch.div(order, top_k, rounding_mode="floor")].contiguous() + sorted_routing_weights = routing_weights.reshape(-1)[order].contiguous() + tokens_per_expert = torch.bincount(flat_experts, minlength=num_experts) + expert_cumsum = torch.cumsum(tokens_per_expert, dim=0, dtype=torch.int32).contiguous() + return sorted_hidden_states, sorted_routing_weights, expert_cumsum, order + + +def _unroute_tokens( + sorted_outputs: torch.Tensor, + order: torch.Tensor, + num_tokens: int, + top_k: int, +) -> torch.Tensor: + restored = torch.empty_like(sorted_outputs) + restored[order] = sorted_outputs + # VeOmni's v0.1.0 gather kernel accumulates the top-k outputs in FP32. + return restored.view(num_tokens, top_k, -1).sum(dim=1, dtype=torch.float32).to(sorted_outputs.dtype) + + +def _grouped_linear_triton( + inputs: torch.Tensor, + weights: torch.Tensor, + expert_cumsum: torch.Tensor, +) -> torch.Tensor: + if triton is None: # pragma: no cover - guarded by the caller + raise RuntimeError("Triton is not available") + if not inputs.is_contiguous() or not weights.is_contiguous(): + raise ValueError("the Triton path requires contiguous inputs and expert weights") + + num_experts, output_size, input_size = weights.shape + if inputs.shape[1] != input_size: + raise ValueError(f"input width is {inputs.shape[1]}, but the weights expect {input_size}") + + output = torch.empty((inputs.shape[0], output_size), dtype=inputs.dtype, device=inputs.device) + block_m, block_n, block_k = 128, 128, 32 + grid = ( + triton.cdiv(inputs.shape[0], block_m), + triton.cdiv(output_size, block_n), + num_experts, + ) + with torch.cuda.device(inputs.device): + _grouped_linear_kernel[grid]( + inputs, + weights, + output, + expert_cumsum, + N=output_size, + K=input_size, + BLOCK_M=block_m, + BLOCK_N=block_n, + BLOCK_K=block_k, + num_warps=8, + num_stages=3, + ) + return output + + +def _triton_moe_forward( + num_experts: int, + routing_weights: torch.Tensor, + selected_experts: torch.Tensor, + hidden_states: torch.Tensor, + fc1_1_weight: torch.Tensor, + fc1_2_weight: torch.Tensor, + fc2_weight: torch.Tensor, +) -> torch.Tensor: + sorted_hidden, sorted_routing, expert_cumsum, order = _route_tokens( + num_experts, routing_weights, selected_experts, hidden_states + ) + gate = _grouped_linear_triton(sorted_hidden, fc1_1_weight, expert_cumsum) + up = _grouped_linear_triton(sorted_hidden, fc1_2_weight, expert_cumsum) + intermediate = F.silu(gate) * up + intermediate.mul_(sorted_routing.unsqueeze(-1)) + sorted_outputs = _grouped_linear_triton(intermediate.contiguous(), fc2_weight, expert_cumsum) + return _unroute_tokens(sorted_outputs, order, hidden_states.shape[0], selected_experts.shape[1]) + + +def _eager_moe_forward( + num_experts: int, + routing_weights: torch.Tensor, + selected_experts: torch.Tensor, + hidden_states: torch.Tensor, + fc1_1_weight: torch.Tensor, + fc1_2_weight: torch.Tensor, + fc2_weight: torch.Tensor, +) -> torch.Tensor: + sorted_hidden, sorted_routing, expert_cumsum, order = _route_tokens( + num_experts, routing_weights, selected_experts, hidden_states + ) + expert_ends = expert_cumsum.to(device="cpu", dtype=torch.int64).tolist() + outputs: list[torch.Tensor] = [] + start = 0 + for expert, end in enumerate(expert_ends): + if end > start: + expert_inputs = sorted_hidden[start:end] + gate = F.linear(expert_inputs, fc1_1_weight[expert]) + up = F.linear(expert_inputs, fc1_2_weight[expert]) + intermediate = F.silu(gate) * up + intermediate.mul_(sorted_routing[start:end].unsqueeze(-1)) + outputs.append(F.linear(intermediate, fc2_weight[expert])) + start = end + + sorted_outputs = torch.cat(outputs, dim=0) if outputs else hidden_states.new_empty((0, hidden_states.shape[1])) + return _unroute_tokens(sorted_outputs, order, hidden_states.shape[0], selected_experts.shape[1]) + + +def fused_moe_forward( + module: torch.nn.Module, + num_experts: int, + routing_weights: torch.Tensor, + selected_experts: torch.Tensor, + hidden_states: torch.Tensor, + fc1_1_weight: torch.Tensor, + fc1_2_weight: torch.Tensor, + fc2_weight: torch.Tensor, +) -> torch.Tensor: + """Run the VeOmni v0.1.0 split-weight MoE operation for inference. + + ``module`` is retained for call-site compatibility. Like VeOmni's original + non-EP implementation, this function does not use it. + + Set ``LLADA_MOE_BACKEND`` to ``auto`` (default), ``triton``, or ``eager``. + The ``triton`` setting fails loudly if its requirements are not met; + ``auto`` falls back to the PyTorch implementation. + """ + del module + _validate_inputs( + num_experts, + routing_weights, + selected_experts, + hidden_states, + fc1_1_weight, + fc1_2_weight, + fc2_weight, + ) + + backend = os.getenv("LLADA_MOE_BACKEND", "auto").lower() + if backend not in {"auto", "triton", "eager"}: + raise ValueError(f"LLADA_MOE_BACKEND must be auto, triton, or eager; got {backend!r}") + + compute_dtype = fc1_1_weight.dtype + if fc1_2_weight.dtype != compute_dtype or fc2_weight.dtype != compute_dtype: + raise TypeError("all expert weights must have the same dtype") + hidden_states = hidden_states.to(dtype=compute_dtype) + routing_weights = routing_weights.to(dtype=compute_dtype) + + if hidden_states.shape[0] == 0: + return hidden_states + + can_use_triton = ( + triton is not None + and hidden_states.is_cuda + and compute_dtype in _SUPPORTED_TRITON_DTYPES + and fc1_1_weight.is_contiguous() + and fc1_2_weight.is_contiguous() + and fc2_weight.is_contiguous() + ) + if backend == "triton" and not can_use_triton: + raise RuntimeError( + "The Triton backend requires Triton, CUDA tensors, contiguous expert weights, " + "and float16 or bfloat16 weights." + ) + if backend != "eager" and can_use_triton: + return _triton_moe_forward( + num_experts, + routing_weights, + selected_experts, + hidden_states, + fc1_1_weight, + fc1_2_weight, + fc2_weight, + ) + return _eager_moe_forward( + num_experts, + routing_weights, + selected_experts, + hidden_states, + fc1_1_weight, + fc1_2_weight, + fc2_weight, + ) + + +__all__ = ["fused_moe_forward"] diff --git a/pipelines/llada/modeling_llada2uni_moe.py b/pipelines/llada/modeling_llada2uni_moe.py new file mode 100644 index 000000000..ad2cb6621 --- /dev/null +++ b/pipelines/llada/modeling_llada2uni_moe.py @@ -0,0 +1,1288 @@ +# coding=utf-8 +# Copyright 2025 Antgroup and The HuggingFace Inc. team. All rights reserved. +# +# This code is based on EleutherAI's GPT-NeoX library and the GPT-NeoX +# and OPT implementations in this library. It has been modified from its +# original forms to accommodate minor architectural differences compared +# to GPT-NeoX and OPT used by the Meta AI team that trained the model. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +"""PyTorch implementation of the fused LLaDA2 MoE model.""" + +from dataclasses import dataclass +import math +from typing import List, Optional, Tuple, Union + +import torch +import torch.nn as nn +import torch.nn.functional as F + +from transformers.activations import ACT2FN +from transformers.cache_utils import Cache +from transformers.generation import GenerationMixin +from transformers.modeling_attn_mask_utils import ( + _prepare_4d_attention_mask, + _prepare_4d_causal_attention_mask, + _prepare_4d_causal_attention_mask_for_sdpa, +) +from transformers.modeling_outputs import ModelOutput, MoeModelOutputWithPast +from transformers.modeling_rope_utils import ROPE_INIT_FUNCTIONS, dynamic_rope_update +from transformers.modeling_utils import PreTrainedModel +from transformers.pytorch_utils import ALL_LAYERNORM_LAYERS +from transformers.utils import logging +from .fused_moe_ops import fused_moe_forward + +from .configuration_llada2uni_moe import LLaDA2MoeConfig + +logger = logging.get_logger(__name__) + + +class LLaDA2MoeRMSNorm(nn.Module): + """RMSNorm used by the LLaDA2 model.""" + + def __init__(self, hidden_size, eps=1e-6): + super().__init__() + self.weight = nn.Parameter(torch.ones(hidden_size)) + self.variance_epsilon = eps + + def forward(self, hidden_states): + input_dtype = hidden_states.dtype + hidden_states = hidden_states.to(torch.float32) + variance = hidden_states.pow(2).mean(-1, keepdim=True) + hidden_states = hidden_states * torch.rsqrt(variance + self.variance_epsilon) + return self.weight * hidden_states.to(input_dtype) + + +# Preserve the historical spelling used by the original implementation. +LLaDA2MoERMSNorm = LLaDA2MoeRMSNorm +ALL_LAYERNORM_LAYERS.append(LLaDA2MoeRMSNorm) + + +class LLaDA2MoePreTrainedModel(PreTrainedModel): + config_class = LLaDA2MoeConfig + base_model_prefix = "model" + supports_gradient_checkpointing = True + _no_split_modules = ["LLaDA2MoeDecoderLayer"] + _skip_keys_device_placement = "past_key_values" + _supports_flash_attn_2 = True + _supports_sdpa = True + _supports_cache_class = True + _supports_flash_attn = True + _can_compile_fullgraph = True + _supports_attention_backend = True + + def _init_weights(self, module): + std = self.config.initializer_range + if isinstance(module, nn.Linear): + module.weight.data.normal_(mean=0.0, std=std) + if module.bias is not None: + module.bias.data.zero_() + elif isinstance(module, nn.Embedding): + module.weight.data.normal_(mean=0.0, std=std) + if module.padding_idx is not None: + module.weight.data[module.padding_idx].zero_() + elif isinstance(module, LLaDA2MoeRotaryEmbedding): # non-persistent buffers come back uninitialized from the meta-device load + inv_freq, module.attention_scaling = module.rope_init_fn(module.config, module.inv_freq.device) + module.inv_freq.copy_(inv_freq) + module.original_inv_freq = module.inv_freq + + +def rotate_half(hidden_states): + first, second = hidden_states.chunk(2, dim=-1) + return torch.cat((-second, first), dim=-1) + + +def apply_rotary_pos_emb(query, key, cos, sin, position_ids=None, unsqueeze_dim=1): # pylint: disable=unused-argument + """Apply RoPE to the rotary part of query and key states.""" + cos = cos.unsqueeze(unsqueeze_dim) + sin = sin.unsqueeze(unsqueeze_dim) + rotary_dim = cos.shape[-1] + query_rotary, query_pass = query[..., :rotary_dim], query[..., rotary_dim:] + key_rotary, key_pass = key[..., :rotary_dim], key[..., rotary_dim:] + query_rotary = query_rotary * cos + rotate_half(query_rotary) * sin + key_rotary = key_rotary * cos + rotate_half(key_rotary) * sin + return torch.cat((query_rotary, query_pass), dim=-1), torch.cat( + (key_rotary, key_pass), dim=-1 + ) + + +def _compute_default_rope_parameters(config, device=None, **kwargs): # pylint: disable=unused-argument + """Compute the unscaled RoPE frequencies removed from Transformers 5.x.""" + head_dim = getattr(config, "head_dim", None) or config.hidden_size // config.num_attention_heads + partial_rotary_factor = getattr(config, "partial_rotary_factor", 1.0) + dim = int(head_dim * partial_rotary_factor) + base = getattr(config, "rope_theta", 10000.0) + inv_freq = 1.0 / ( + base ** (torch.arange(0, dim, 2, dtype=torch.int64, device=device).float() / dim) + ) + return inv_freq, 1.0 + + +class LLaDA2MoeRotaryEmbedding(nn.Module): + def __init__(self, config: LLaDA2MoeConfig, device=None): + super().__init__() + # BC: "rope_type" was originally "type" + if hasattr(config, "rope_scaling") and config.rope_scaling is not None: + self.rope_type = config.rope_scaling.get( + "rope_type", config.rope_scaling.get("type") + ) + else: + self.rope_type = "default" + self.max_seq_len_cached = config.max_position_embeddings + self.original_max_seq_len = config.max_position_embeddings + + self.config = config + self.rope_init_fn = ROPE_INIT_FUNCTIONS.get(self.rope_type) + if self.rope_init_fn is None and self.rope_type == "default": + self.rope_init_fn = _compute_default_rope_parameters + if self.rope_init_fn is None: + raise KeyError(f"Unsupported RoPE type: {self.rope_type}") + + inv_freq, self.attention_scaling = self.rope_init_fn(self.config, device) + self.register_buffer("inv_freq", inv_freq, persistent=False) + self.original_inv_freq = self.inv_freq + + @torch.no_grad() + @dynamic_rope_update # power user: used with advanced RoPE types (e.g. dynamic rope) + def forward(self, x, position_ids): + inv_freq_expanded = ( + self.inv_freq[None, :, None] + .float() + .expand(position_ids.shape[0], -1, 1) + .to(x.device) + ) + position_ids_expanded = position_ids[:, None, :].float() + + device_type = ( + x.device.type + if isinstance(x.device.type, str) and x.device.type != "mps" + else "cpu" + ) + with torch.autocast(device_type=device_type, enabled=False): # Force float32 + freqs = ( + inv_freq_expanded.float() @ position_ids_expanded.float() + ).transpose(1, 2) + emb = torch.cat((freqs, freqs), dim=-1) + cos = emb.cos() * self.attention_scaling + sin = emb.sin() * self.attention_scaling + + return cos.to(dtype=x.dtype), sin.to(dtype=x.dtype) + + +class LLaDA2MoeMLP(nn.Module): + def __init__(self, config: LLaDA2MoeConfig, intermediate_size: int): + super().__init__() + self.config = config + self.hidden_size = config.hidden_size + self.intermediate_size = intermediate_size + + self.gate_proj = nn.Linear(self.hidden_size, self.intermediate_size, bias=False) + self.up_proj = nn.Linear(self.hidden_size, self.intermediate_size, bias=False) + self.down_proj = nn.Linear(self.intermediate_size, self.hidden_size, bias=False) + self.act_fn = ACT2FN[config.hidden_act] + + def forward(self, x): + return self.down_proj(self.act_fn(self.gate_proj(x)) * self.up_proj(x)) + + +class LLaDA2MoeGate(nn.Module): + def __init__(self, config): + super().__init__() + self.config = config + self.top_k = config.num_experts_per_tok + self.num_experts = config.num_experts + + self.n_group = config.n_group + self.topk_group = config.topk_group + + self.gating_dim = config.hidden_size + self.weight = nn.Parameter(torch.empty((self.num_experts, self.gating_dim))) + self.routed_scaling_factor = config.routed_scaling_factor + + self.register_buffer("expert_bias", torch.zeros((self.num_experts))) + self.reset_parameters() + + def reset_parameters(self) -> None: + import torch.nn.init as init + + init.kaiming_uniform_(self.weight, a=math.sqrt(5)) + + def group_limited_topk( + self, + scores: torch.Tensor, + ): + num_tokens, _ = scores.size() + group_scores = ( + scores.view(num_tokens, self.n_group, -1).topk(2, dim=-1)[0].sum(dim=-1) + ) + group_idx = torch.topk(group_scores, k=self.topk_group, dim=-1, sorted=False)[1] + group_mask = torch.zeros_like(group_scores) + group_mask.scatter_(1, group_idx, 1) + + score_mask = ( + group_mask.unsqueeze(-1) + .expand(num_tokens, self.n_group, self.num_experts // self.n_group) + .reshape(num_tokens, -1) + ) + + masked_scores = scores.masked_fill(~score_mask.bool(), float("-inf")) + probs, top_indices = torch.topk(masked_scores, k=self.top_k, dim=-1) + + return probs, top_indices + + def forward(self, hidden_states): + hidden_states = hidden_states.view(-1, hidden_states.shape[-1]) + logits = F.linear( + hidden_states.type(torch.float32), self.weight.type(torch.float32) + ) + + scores = torch.sigmoid(logits.float()).type_as(logits) + + scores_for_routing = scores + self.expert_bias + _, topk_idx = self.group_limited_topk(scores_for_routing) + + scores = torch.gather(scores, dim=1, index=topk_idx).type_as(logits) + + topk_weight = ( + scores / (scores.sum(dim=-1, keepdim=True) + 1e-20) + if self.top_k > 1 + else scores + ) + topk_weight = topk_weight * self.routed_scaling_factor + + return topk_idx, topk_weight, logits + + +class LLaDA2MoeExperts(nn.Module): + def __init__(self, config): + super().__init__() + self.num_experts = config.num_experts + self.hidden_dim = config.hidden_size + self.intermediate_size = config.moe_intermediate_size + self.gate_proj = torch.nn.Parameter( + torch.empty(self.num_experts, self.intermediate_size, self.hidden_dim), + requires_grad=True, + ) + self.up_proj = torch.nn.Parameter( + torch.empty(self.num_experts, self.intermediate_size, self.hidden_dim), + requires_grad=True, + ) + self.down_proj = torch.nn.Parameter( + torch.empty(self.num_experts, self.hidden_dim, self.intermediate_size), + requires_grad=True, + ) + + def forward(self, hidden_states, routing_weights, selected_experts): + return fused_moe_forward( + module=self, + num_experts=self.num_experts, + routing_weights=routing_weights, + selected_experts=selected_experts, + hidden_states=hidden_states, + fc1_1_weight=self.gate_proj, + fc1_2_weight=self.up_proj, + fc2_weight=self.down_proj, + ) + + def reset_parameters(self): + """ + Initialize the parameters of all expert networks. + Uses different initialization strategies for different projection layers. + """ + for expert_id in range(self.num_experts): + nn.init.kaiming_uniform_(self.gate_proj[expert_id], a=math.sqrt(5)) + nn.init.kaiming_uniform_(self.up_proj[expert_id], a=math.sqrt(5)) + nn.init.xavier_uniform_(self.down_proj[expert_id]) + + +class LLaDA2MoeSparseMoeBlock(nn.Module): + """Fused routed experts plus a shared expert.""" + + def __init__(self, config: LLaDA2MoeConfig): + super().__init__() + self.config = config + self.experts = LLaDA2MoeExperts(config) + self.gate = LLaDA2MoeGate(config) + if config.num_shared_experts is not None: + self.shared_experts = LLaDA2MoeMLP( + config=config, + intermediate_size=config.moe_intermediate_size + * config.num_shared_experts, + ) + + def forward(self, hidden_states): + identity = hidden_states + bsz, seq_len, h = hidden_states.shape + topk_idx, topk_weight, router_logits = self.gate(hidden_states) + hidden_states = hidden_states.view(-1, hidden_states.shape[-1]) + y = self.experts( + hidden_states, routing_weights=topk_weight, selected_experts=topk_idx + ).reshape(bsz, seq_len, h) + if self.config.num_shared_experts is not None: + y = y + self.shared_experts(identity) + return y, ( + router_logits.view(bsz, seq_len, -1), + topk_idx.view(bsz, seq_len, -1), + ) + + +def repeat_kv(hidden_states: torch.Tensor, n_rep: int) -> torch.Tensor: + """ + This is the equivalent of torch.repeat_interleave(x, dim=1, repeats=n_rep). The hidden states go from (batch, + num_key_value_heads, seqlen, head_dim) to (batch, num_attention_heads, seqlen, head_dim) + """ + batch, num_key_value_heads, slen, head_dim = hidden_states.shape + if n_rep == 1: + return hidden_states + hidden_states = hidden_states[:, :, None, :, :].expand( + batch, num_key_value_heads, n_rep, slen, head_dim + ) + return hidden_states.reshape(batch, num_key_value_heads * n_rep, slen, head_dim) + + +class LLaDA2MoeAttention(nn.Module): + """Multi-headed attention from 'Attention Is All You Need' paper""" + + def __init__(self, config: LLaDA2MoeConfig, layer_idx: Optional[int] = None): + super().__init__() + self.config = config + self.layer_idx = layer_idx + if layer_idx is None: + logger.warning_once( + f"Instantiating {self.__class__.__name__} without passing `layer_idx` is not recommended and will " + "to errors during the forward call, if caching is used. Please make sure to provide a `layer_idx` " + "when creating this class." + ) + + self.attention_dropout = config.attention_dropout + self.hidden_size = config.hidden_size + self.num_heads = config.num_attention_heads + self.head_dim = config.head_dim or self.hidden_size // self.num_heads + partial_rotary_factor = ( + config.partial_rotary_factor + if hasattr(config, "partial_rotary_factor") + else 1.0 + ) + self.rope_dim = int(self.head_dim * partial_rotary_factor) + self.num_key_value_heads = config.num_key_value_heads + self.num_key_value_groups = self.num_heads // self.num_key_value_heads + self.max_position_embeddings = config.max_position_embeddings + self.rope_theta = config.rope_theta + self.is_causal = False + + self.query_key_value = nn.Linear( + self.hidden_size, + (self.num_heads + 2 * self.num_key_value_heads) * self.head_dim, + bias=config.use_qkv_bias, + ) + + self.query_layernorm = LLaDA2MoERMSNorm(self.head_dim, eps=config.rms_norm_eps) + self.key_layernorm = LLaDA2MoERMSNorm(self.head_dim, eps=config.rms_norm_eps) + self.dense = nn.Linear( + self.num_heads * self.head_dim, self.hidden_size, bias=config.use_bias + ) + + def forward( # pylint: disable=unused-argument + self, + hidden_states: torch.Tensor, + attention_mask: Optional[torch.Tensor] = None, + position_ids: Optional[torch.LongTensor] = None, + past_key_value: Optional[Cache] = None, + output_attentions: bool = False, + use_cache: bool = False, + position_embeddings: Optional[ + Tuple[torch.Tensor, torch.Tensor] + ] = None, # necessary, but kept here for BC + **kwargs, + ) -> Tuple[torch.Tensor, Optional[torch.Tensor], Optional[Tuple[torch.Tensor]]]: + bsz, q_len, _ = hidden_states.size() + + qkv = self.query_key_value(hidden_states) + qkv = qkv.view( + bsz, q_len, self.num_heads + 2 * self.num_key_value_heads, self.head_dim + ) + + query_states, key_states, value_states = qkv.split( + [self.num_heads, self.num_key_value_heads, self.num_key_value_heads], dim=-2 + ) + query_states = query_states.transpose(1, 2) + key_states = key_states.transpose(1, 2) + value_states = value_states.transpose(1, 2) + + query_states = self.query_layernorm(query_states) + key_states = self.key_layernorm(key_states) + + kv_seq_len = key_states.shape[-2] + if past_key_value is not None: + if self.layer_idx is None: + raise ValueError( + f"The cache structure has changed since version v4.36. If you are using {self.__class__.__name__} " + "for auto-regressive decoding with k/v caching, please make sure to initialize the attention class " + "with a layer index." + ) + kv_seq_len += past_key_value.get_seq_length(self.layer_idx) + cos, sin = position_embeddings + query_states, key_states = apply_rotary_pos_emb( + query_states, key_states, cos, sin, position_ids + ) + + if past_key_value is not None: + cache_kwargs = {"sin": sin, "cos": cos} # Specific to RoPE models + key_states, value_states = past_key_value.update( + key_states, value_states, self.layer_idx, cache_kwargs + ) + + key_states = repeat_kv(key_states, self.num_key_value_groups) + value_states = repeat_kv(value_states, self.num_key_value_groups) + + attn_weights = torch.matmul( + query_states, key_states.transpose(2, 3) + ) / math.sqrt(self.head_dim) + + if attn_weights.size() != (bsz, self.num_heads, q_len, kv_seq_len): + raise ValueError( + f"Attention weights should be of size {(bsz, self.num_heads, q_len, kv_seq_len)}, but is" + f" {attn_weights.size()}" + ) + if attention_mask is not None: + if attention_mask.size() != (bsz, 1, q_len, kv_seq_len): + raise ValueError( + f"Attention mask should be of size {(bsz, 1, q_len, kv_seq_len)}, but is {attention_mask.size()}" + ) + attn_weights = attn_weights + attention_mask + + attn_weights = nn.functional.softmax( + attn_weights, dim=-1, dtype=torch.float32 + ).to(query_states.dtype) + attn_weights = nn.functional.dropout( + attn_weights, p=self.attention_dropout, training=self.training + ) + attn_output = torch.matmul(attn_weights, value_states) + + if attn_output.size() != (bsz, self.num_heads, q_len, self.head_dim): + raise ValueError( + f"`attn_output` should be of size {(bsz, self.num_heads, q_len, self.head_dim)}, but is" + f" {attn_output.size()}" + ) + + attn_output = attn_output.transpose(1, 2).contiguous() + + attn_output = attn_output.reshape(bsz, q_len, -1) + + attn_output = self.dense(attn_output) + + if not output_attentions: + attn_weights = None + + return attn_output, attn_weights, past_key_value + + +class LLaDA2MoeSdpaAttention(LLaDA2MoeAttention): + """ + LLaDA2Moe attention module using torch.nn.functional.scaled_dot_product_attention. This module inherits from + `LLaDA2MoeAttention` as the weights of the module stays untouched. The only changes are on the forward pass to adapt to + SDPA API. + """ + + def forward( + self, + hidden_states: torch.Tensor, + attention_mask: Optional[torch.Tensor] = None, + position_ids: Optional[torch.LongTensor] = None, + past_key_value: Optional[Cache] = None, + output_attentions: bool = False, + use_cache: bool = False, + position_embeddings: Optional[ + Tuple[torch.Tensor, torch.Tensor] + ] = None, # necessary, but kept here for BC + **kwargs, + ) -> Tuple[torch.Tensor, Optional[torch.Tensor], Optional[Tuple[torch.Tensor]]]: + if output_attentions: + logger.warning_once( + "LLaDA2MoeModel is using LLaDA2MoeSdpaAttention, but `torch.nn.functional.scaled_dot_product_attention` does not support `output_attentions=True`. Falling back to the manual attention implementation, " + 'but specifying the manual implementation will be required from Transformers version v5.0.0 onwards. This warning can be removed using the argument `attn_implementation="eager"` when loading the model.' + ) + return super().forward( + hidden_states=hidden_states, + attention_mask=attention_mask, + position_ids=position_ids, + past_key_value=past_key_value, + output_attentions=output_attentions, + use_cache=use_cache, + ) + + bsz, q_len, _ = hidden_states.size() + + qkv = self.query_key_value(hidden_states) + qkv = qkv.view( + bsz, q_len, self.num_heads + 2 * self.num_key_value_heads, self.head_dim + ) + + query_states, key_states, value_states = qkv.split( + [self.num_heads, self.num_key_value_heads, self.num_key_value_heads], dim=-2 + ) + query_states = query_states.transpose(1, 2) + key_states = key_states.transpose(1, 2) + value_states = value_states.transpose(1, 2) + + query_states = self.query_layernorm(query_states) + key_states = self.key_layernorm(key_states) + + kv_seq_len = key_states.shape[-2] + if past_key_value is not None: + kv_seq_len += past_key_value.get_seq_length(self.layer_idx) + cos, sin = position_embeddings + + query_states, key_states = apply_rotary_pos_emb( + query_states, key_states, cos, sin, position_ids + ) + + if past_key_value is not None: + cache_kwargs = {"sin": sin, "cos": cos} # Specific to RoPE models + key_states, value_states = past_key_value.update( + key_states, value_states, self.layer_idx, cache_kwargs + ) + + key_states = repeat_kv(key_states, self.num_key_value_groups) + value_states = repeat_kv(value_states, self.num_key_value_groups) + + if attention_mask is not None: + if attention_mask.size() != (bsz, 1, q_len, kv_seq_len): + raise ValueError( + f"Attention mask should be of size {(bsz, 1, q_len, kv_seq_len)}, but is {attention_mask.size()}" + ) + + # SDPA with memory-efficient backend is currently (torch==2.1.2) bugged with non-contiguous inputs with custom attn_mask, + # Reference: https://github.com/pytorch/pytorch/issues/112577. + if query_states.device.type == "cuda" and attention_mask is not None: + query_states = query_states.contiguous() + key_states = key_states.contiguous() + value_states = value_states.contiguous() + + attn_output = torch.nn.functional.scaled_dot_product_attention( + query_states, + key_states, + value_states, + attn_mask=attention_mask, + dropout_p=self.attention_dropout if self.training else 0.0, + # The q_len > 1 is necessary to match with AttentionMaskConverter.to_causal_4d that does not create a causal mask in case q_len == 1. + is_causal=self.is_causal and attention_mask is None and q_len > 1, + ) + + attn_output = attn_output.transpose(1, 2).contiguous() + attn_output = attn_output.reshape(bsz, q_len, -1) + + attn_output = self.dense(attn_output) + + return attn_output, None, past_key_value + + +ATTENTION_CLASSES = { + "eager": LLaDA2MoeSdpaAttention, + "flash_attention_2": LLaDA2MoeSdpaAttention, + "sdpa": LLaDA2MoeSdpaAttention, +} + + +class LLaDA2MoeDecoderLayer(nn.Module): + def __init__(self, config: LLaDA2MoeConfig, layer_idx: int): + super().__init__() + self.hidden_size = config.hidden_size + + self.attention = ATTENTION_CLASSES[config._attn_implementation]( + config=config, layer_idx=layer_idx + ) + + self.mlp = ( + LLaDA2MoeSparseMoeBlock(config) + if ( + config.num_experts is not None + and layer_idx >= config.first_k_dense_replace + ) + else LLaDA2MoeMLP(config=config, intermediate_size=config.intermediate_size) + ) + self.input_layernorm = LLaDA2MoERMSNorm( + config.hidden_size, eps=config.rms_norm_eps + ) + self.post_attention_layernorm = LLaDA2MoERMSNorm( + config.hidden_size, eps=config.rms_norm_eps + ) + + def forward( + self, # pylint: disable=unused-argument + hidden_states: torch.Tensor, + attention_mask: Optional[torch.Tensor] = None, + position_ids: Optional[torch.LongTensor] = None, + past_key_value: Optional[Tuple[torch.Tensor]] = None, + output_attentions: Optional[bool] = False, + output_router_logits: Optional[bool] = False, + use_cache: Optional[bool] = False, + position_embeddings: Optional[ + Tuple[torch.Tensor, torch.Tensor] + ] = None, # necessary, but kept here for BC + **kwargs, + ) -> Tuple[ + torch.FloatTensor, Optional[Tuple[torch.FloatTensor, torch.FloatTensor]] + ]: + """ + Args: + hidden_states (`torch.FloatTensor`): input to the layer of shape `(batch, seq_len, embed_dim)` + attention_mask (`torch.FloatTensor`, *optional*): + attention mask of size `(batch_size, sequence_length)` if flash attention is used or `(batch_size, 1, + query_sequence_length, key_sequence_length)` if default attention is used. + position_ids (`torch.LongTensor` of shape `(batch_size, sequence_length)`, *optional*): + Indices of positions of each input sequence tokens in the position embeddings. Selected in the range `[0, + config.n_positions - 1]`. + past_key_value (`Tuple(torch.FloatTensor)`, *optional*): + cached past key and value projection states + output_attentions (`bool`, *optional*): + Whether to return the attentions tensors of all attention layers. See `attentions` under + returned tensors for more detail. + output_router_logits (`bool`, *optional*): + Whether or not to return the logits of all the routers. They are useful for computing the router loss, + and should not be returned during inference. + use_cache (`bool`, *optional*): + If set to `True`, `past_key_values` key value states are returned and can be used to speed up decoding + (see `past_key_values`). + """ + residual = hidden_states + + hidden_states = self.input_layernorm(hidden_states) + + hidden_states, self_attn_weights, present_key_value = self.attention( + hidden_states=hidden_states, + attention_mask=attention_mask, + position_ids=position_ids, + past_key_value=past_key_value, + output_attentions=output_attentions, + position_embeddings=position_embeddings, + use_cache=use_cache, + ) + hidden_states = residual + hidden_states + + residual = hidden_states + hidden_states = self.post_attention_layernorm(hidden_states) + hidden_states = self.mlp(hidden_states) + if isinstance(hidden_states, tuple): + hidden_states, router_logits = hidden_states + else: + router_logits = None + hidden_states = residual + hidden_states.to(residual.device) + + outputs = (hidden_states,) + + if output_attentions: + outputs += (self_attn_weights,) + + if use_cache: + outputs += (present_key_value,) + + if output_router_logits: + outputs += (router_logits,) + + return outputs + + +def calculate_pack_position_ids( + input_ids: Optional[torch.Tensor] = None, + inputs_embeds: Optional[torch.Tensor] = None, + position_ids: Optional[torch.Tensor] = None, + past_key_values_length: int = 0, + cu_lengths_list: Optional[List[torch.Tensor]] = None, +): + """Build continuous or per-sequence packed position IDs.""" + if position_ids is not None: + return position_ids + + if input_ids is not None: + device = input_ids.device + batch_size, seq_length = input_ids.shape + elif inputs_embeds is not None: + device = inputs_embeds.device + batch_size, seq_length, _ = inputs_embeds.shape + else: + raise ValueError("You have to specify either input_ids or inputs_embeds") + + if cu_lengths_list is not None: + all_position_ids = [] + + for i in range(batch_size): + cu_seqlens = cu_lengths_list[i].to(device) + starts = cu_seqlens[:-1] + lengths = cu_seqlens[1:] - cu_seqlens[:-1] + total_len = cu_seqlens[-1].item() + global_positions = torch.arange(total_len, device=device, dtype=torch.long) + subtraction_mask = torch.repeat_interleave(starts, lengths) + current_pos_ids = global_positions - subtraction_mask + all_position_ids.append(current_pos_ids) + + position_ids = torch.nn.utils.rnn.pad_sequence( + all_position_ids, + batch_first=True, + padding_value=0, + ) + + if position_ids.shape[1] < seq_length: + pad_right = seq_length - position_ids.shape[1] + position_ids = F.pad(position_ids, (0, pad_right), "constant", 0) + else: + position_ids = torch.arange( + past_key_values_length, + seq_length + past_key_values_length, + dtype=torch.long, + device=device, + ) + position_ids = position_ids.unsqueeze(0).expand(batch_size, -1) + + return position_ids + + +class LLaDA2MoeModel(LLaDA2MoePreTrainedModel): + """ + Transformer decoder consisting of *config.num_hidden_layers* layers. Each layer is a [`LLaDA2MoeDecoderLayer`] + Args: + config: LLaDA2MoeConfig + """ + + def __init__(self, config: LLaDA2MoeConfig): + super().__init__(config) + self.padding_idx = config.pad_token_id + self.vocab_size = config.vocab_size + + self.word_embeddings = nn.Embedding( + config.vocab_size, config.hidden_size, self.padding_idx + ) + self.layers = nn.ModuleList( + [ + LLaDA2MoeDecoderLayer(config, layer_idx) + for layer_idx in range(config.num_hidden_layers) + ] + ) + + self._use_sdpa = config._attn_implementation == "sdpa" + self._use_flash_attention_2 = config._attn_implementation == "flash_attention_2" + self.norm = LLaDA2MoERMSNorm(config.hidden_size, eps=config.rms_norm_eps) + self.rotary_emb = LLaDA2MoeRotaryEmbedding(config=config) + self.gradient_checkpointing = False + + self.post_init() + + def get_input_embeddings(self): + return self.word_embeddings + + def set_input_embeddings(self, value): + self.word_embeddings = value + + def forward( + self, # pylint: disable=unused-argument + input_ids: torch.LongTensor = None, + attention_mask: Optional[torch.Tensor] = None, + position_ids: Optional[torch.LongTensor] = None, + past_key_values: Optional[List[torch.FloatTensor]] = None, + inputs_embeds: Optional[torch.FloatTensor] = None, + use_cache: Optional[bool] = None, + output_attentions: Optional[bool] = None, + output_hidden_states: Optional[bool] = None, + output_router_logits: Optional[bool] = None, + cu_lengths_list: Optional[List] = None, + return_dict: Optional[bool] = None, + **kwargs, + ) -> Union[Tuple, MoeModelOutputWithPast]: + output_attentions = ( + output_attentions + if output_attentions is not None + else self.config.output_attentions + ) + output_hidden_states = ( + output_hidden_states + if output_hidden_states is not None + else self.config.output_hidden_states + ) + output_router_logits = ( + output_router_logits + if output_router_logits is not None + else self.config.output_router_logits + ) + use_cache = use_cache if use_cache is not None else self.config.use_cache + + return_dict = ( + return_dict if return_dict is not None else self.config.use_return_dict + ) + + if input_ids is not None and inputs_embeds is not None: + raise ValueError( + "You cannot specify both input_ids and inputs_embeds at the same time" + ) + elif input_ids is not None: + batch_size, seq_length = input_ids.shape[:2] + elif inputs_embeds is not None: + batch_size, seq_length = inputs_embeds.shape[:2] + else: + raise ValueError("You have to specify either input_ids or inputs_embeds") + + if self.gradient_checkpointing and self.training: + if use_cache: + logger.warning_once( + "`use_cache=True` is incompatible with gradient checkpointing. Setting `use_cache=False`transformers." + ) + use_cache = False + + past_key_values_length = past_key_values.get_seq_length() if use_cache and past_key_values is not None else 0 + + if position_ids is None: + position_ids = calculate_pack_position_ids( + input_ids, + inputs_embeds, + position_ids, + past_key_values_length, + cu_lengths_list, + ) + + if inputs_embeds is None: + inputs_embeds = self.word_embeddings(input_ids) + + if hasattr(attention_mask, "dim") and attention_mask.dim() == 2: + if self._use_sdpa and not output_attentions: + # output_attentions=True can not be supported when using SDPA, and we fall back on + # the manual implementation that requires a 4D causal mask in all cases. + attention_mask = _prepare_4d_causal_attention_mask_for_sdpa( + attention_mask, + (batch_size, seq_length), + inputs_embeds, + past_key_values_length, + ) + else: + if attention_mask is not None: + attention_mask = _prepare_4d_attention_mask( + attention_mask, inputs_embeds.dtype + ) + else: + attention_mask = _prepare_4d_causal_attention_mask( + attention_mask, + (batch_size, seq_length), + inputs_embeds, + past_key_values_length, + ) + hidden_states = inputs_embeds + + position_embeddings = self.rotary_emb(hidden_states, position_ids) + + all_hidden_states = () if output_hidden_states else None + all_self_attns = () if output_attentions else None + all_router_logits = () if output_router_logits else None + next_decoder_cache = None + + for decoder_layer in self.layers: + if output_hidden_states: + all_hidden_states += (hidden_states,) + + if self.gradient_checkpointing and self.training: + layer_outputs = self._gradient_checkpointing_func( + decoder_layer.__call__, + hidden_states, + attention_mask, + position_ids, + past_key_values, + output_attentions, + output_router_logits, + use_cache, + position_embeddings, + ) + else: + layer_outputs = decoder_layer( + hidden_states, + attention_mask=attention_mask, + position_ids=position_ids, + past_key_value=past_key_values, + output_attentions=output_attentions, + output_router_logits=output_router_logits, + use_cache=use_cache, + position_embeddings=position_embeddings, + ) + hidden_states = layer_outputs[0] + + if use_cache: + next_decoder_cache = layer_outputs[2 if output_attentions else 1] + + if output_attentions: + all_self_attns += (layer_outputs[1],) + + if output_router_logits and layer_outputs[-1] is not None: + all_router_logits += (layer_outputs[-1],) + + hidden_states = self.norm(hidden_states) + + if output_hidden_states: + all_hidden_states += (hidden_states,) + + next_cache = next_decoder_cache if use_cache else None + if not return_dict: + return tuple( + v + for v in [ + hidden_states, + next_cache, + all_hidden_states, + all_self_attns, + all_router_logits, + ] + if v is not None + ) + return MoeModelOutputWithPast( + last_hidden_state=hidden_states, + past_key_values=next_cache, + hidden_states=all_hidden_states, + attentions=all_self_attns, + router_logits=all_router_logits, + ) + + +@dataclass +class LLaDA2MoeCausalLMOutputWithPast(ModelOutput): + r""" + loss (`torch.FloatTensor` of shape `(1,)`, *optional*, returned when `labels` is provided): + Training loss. + logits (`torch.FloatTensor` of shape `(batch_size, sequence_length, config.vocab_size)`): + Prediction scores for each vocabulary token before SoftMax. + past_key_values (`Cache`, *optional*, returned when `use_cache=True` is passed or when `config.use_cache=True`): + It is a [`~cache_utils.Cache`] instance. For more details, see our [kv cache guide](https://huggingface.co/docs/transformers/en/kv_cache). + + Contains pre-computed hidden-states (key and values in the self-attention blocks) that can be used (see + `past_key_values` input) to speed up sequential decoding. + rope_deltas (`torch.LongTensor` of shape `(batch_size, )`, *optional*): + The offset between the sequence length and rotary position indices. + """ + + loss: Optional[torch.FloatTensor] = None + z_loss: Optional[torch.FloatTensor] = None + logits: Optional[torch.FloatTensor] = None + past_key_values: Optional[Cache] = None + hidden_states: Optional[tuple[torch.FloatTensor]] = None + attentions: Optional[tuple[torch.FloatTensor]] = None + rope_deltas: Optional[torch.LongTensor] = None + + +class LLaDA2MoeBackbone(nn.Module): + """Container for the model backbone and output head.""" + + def __init__(self, config: LLaDA2MoeConfig): + super().__init__() + self.language_model = LLaDA2MoeModel(config) + self.lm_head = nn.Linear(config.hidden_size, config.vocab_size, bias=False) + + def get_input_embeddings(self): + return self.language_model.get_input_embeddings() + + def set_input_embeddings(self, value): + self.language_model.set_input_embeddings(value) + + def forward(self, *args, **kwargs): + return self.language_model(*args, **kwargs) + + +class LLaDA2MoeModelLM(LLaDA2MoePreTrainedModel, GenerationMixin): + """Fused LLaDA2 MoE model.""" + + accepts_loss_kwargs = False + + def __init__(self, config: LLaDA2MoeConfig): + super().__init__(config) + self.model = LLaDA2MoeBackbone(config) + self.img_token_id = 157184 + self.img_start_id = 157185 + self.img_end_id = 157186 + self.img_pad_id = 157187 + self.post_init() + + @property + def language_model(self): + return self.model.language_model + + def get_input_embeddings(self): + return self.model.get_input_embeddings() + + def set_input_embeddings(self, value): + self.model.set_input_embeddings(value) + + def get_output_embeddings(self): + return self.model.lm_head + + def set_output_embeddings(self, value): + self.model.lm_head = value + + def get_decoder(self): + return self.model.language_model + + def set_decoder(self, decoder): + self.model.language_model = decoder + + def forward( + self, + input_ids: Optional[torch.LongTensor] = None, + attention_mask: Optional[torch.Tensor] = None, + position_ids: Optional[torch.LongTensor] = None, + past_key_values: Optional[Cache] = None, + inputs_embeds: Optional[torch.FloatTensor] = None, + labels: Optional[torch.LongTensor] = None, + use_cache: Optional[bool] = None, + output_attentions: Optional[bool] = None, + output_router_logits: Optional[bool] = None, + output_hidden_states: Optional[bool] = None, + return_dict: Optional[bool] = None, + logits_to_keep: Union[int, torch.Tensor] = 0, + cu_lengths_list: Optional[List] = None, + **kwargs, + ) -> Union[tuple, LLaDA2MoeCausalLMOutputWithPast]: + return_dict = ( + return_dict if return_dict is not None else self.config.use_return_dict + ) + if inputs_embeds is None: + if input_ids is None: + raise ValueError("Provide either input_ids or inputs_embeds") + inputs_embeds = self.get_input_embeddings()(input_ids) + + outputs = self.model( + input_ids=None, + attention_mask=attention_mask, + position_ids=position_ids, + past_key_values=past_key_values, + inputs_embeds=inputs_embeds, + use_cache=use_cache, + output_attentions=output_attentions, + output_router_logits=output_router_logits, + output_hidden_states=output_hidden_states, + return_dict=True, + cu_lengths_list=cu_lengths_list, + **kwargs, + ) + hidden_states = outputs.last_hidden_state + indices = ( + slice(-logits_to_keep, None) + if isinstance(logits_to_keep, int) + else logits_to_keep + ) + logits = self.model.lm_head(hidden_states[:, indices, :]) + + loss = None + if labels is not None: + loss = F.cross_entropy( + logits.reshape(-1, logits.shape[-1]), labels.reshape(-1) + ) + + if not return_dict: + result = ( + logits, + outputs.past_key_values, + outputs.hidden_states, + outputs.attentions, + ) + return ((loss,) + result) if loss is not None else result + return LLaDA2MoeCausalLMOutputWithPast( + loss=loss, + z_loss=None, + logits=logits, + past_key_values=outputs.past_key_values, + hidden_states=outputs.hidden_states, + attentions=outputs.attentions, + rope_deltas=None, + ) + + @staticmethod + def _top_k_logits(logits, k): + if k is None or k <= 0: + return logits + values, _ = torch.topk(logits, min(k, logits.shape[-1])) + return torch.where(logits < values[..., -1, None], -torch.inf, logits) + + @staticmethod + def _top_p_logits(logits, p): + if p is None or p >= 1.0: + return logits + sorted_logits, sorted_indices = torch.sort(logits, descending=True) + cumulative_probs = torch.cumsum(F.softmax(sorted_logits, dim=-1), dim=-1) + sorted_mask = cumulative_probs > p + sorted_mask[..., 1:] = sorted_mask[..., :-1].clone() + sorted_mask[..., 0] = False + mask = torch.zeros_like(sorted_mask).scatter(-1, sorted_indices, sorted_mask) + return logits.masked_fill(mask, -torch.inf) + + def _sample_with_temperature_topk_topp( + self, logits, temperature=1.0, top_k=0, top_p=1.0 + ): + original_shape = logits.shape[:-1] + logits = logits.reshape(-1, logits.shape[-1]) + if ( + temperature == 0.0 + and (top_k in (None, 0)) + and (top_p is None or top_p >= 1.0) + ): + probs = F.softmax(logits, dim=-1) + token = logits.argmax(dim=-1, keepdim=True) + token_prob = probs.gather(-1, token) + return token.view(*original_shape), token_prob.view(*original_shape) + if temperature > 0 and temperature != 1.0: + logits = logits / temperature + logits = self._top_k_logits(logits, top_k) + logits = self._top_p_logits(logits, top_p) + probs = F.softmax(logits, dim=-1) + token = torch.multinomial(probs, num_samples=1) + token_prob = probs.gather(-1, token) + return token.view(*original_shape), token_prob.view(*original_shape) + + @staticmethod + def _get_num_transfer_tokens(block_length, steps): + if steps == 0: + return torch.empty(0, dtype=torch.int64) + schedule = torch.full((steps,), block_length // steps, dtype=torch.int64) + schedule[: block_length % steps] += 1 + return schedule + + @torch.no_grad() + def generate_bd_image_logic( + self, + data: Optional[dict] = None, + temperature: float = 0.0, + block_length: int = 32, + steps: int = 32, + gen_length: int = 2048, + top_p: Optional[float] = None, + top_k: Optional[int] = None, + eos_early_stop: bool = True, + minimal_topk: int = 1, + threshold: float = 0.95, + eos_id: int = 156892, + mask_id: int = 156895, + cfg_scale: float = 1.0, + mode: str = "eoi", + ): + """Generate discrete image tokens with the original block-diffusion logic.""" + if data is None or "input_ids" not in data: + raise ValueError("data must contain input_ids") + steps = min(steps, gen_length // minimal_topk) + input_ids = data["input_ids"] + eoi_id = 156902 + prompt_length = input_ids.shape[1] + num_blocks = (prompt_length + gen_length + block_length - 1) // block_length + total_length = num_blocks * block_length + + block_mask = torch.tril(torch.ones(num_blocks, num_blocks, device=self.device)) + full_attention_mask = ( + block_mask.repeat_interleave(block_length, 0) + .repeat_interleave(block_length, 1)[None, None] + .bool() + ) + position_ids = torch.arange(total_length, device=self.device).unsqueeze(0) + x = torch.full((1, total_length), mask_id, dtype=torch.long, device=self.device) + x[:, :prompt_length] = input_ids + prefill_blocks = prompt_length // block_length + schedule = self._get_num_transfer_tokens(block_length, steps) + use_cfg = cfg_scale != 1.0 + + if use_cfg: + uncond_ids = data.get("uncond_ids", [27, 411, 19483, 29]) + if torch.is_tensor(uncond_ids): + uncond_ids = uncond_ids.flatten().tolist() + pad_len = prompt_length - len(uncond_ids) + if pad_len < 0: + raise ValueError( + "The unconditional prompt is longer than the conditional prompt" + ) + uncond_input = torch.full( + (1, prompt_length), mask_id, dtype=torch.long, device=self.device + ) + uncond_input[0, -len(uncond_ids) :] = torch.tensor( + uncond_ids, device=self.device + ) + uncond_attention_mask = full_attention_mask.clone() + uncond_attention_mask[:, :, :, :pad_len] = False + uncond_position_ids = torch.cat( + [ + torch.zeros(pad_len, device=self.device, dtype=torch.long), + torch.arange(total_length - pad_len, device=self.device), + ] + ).unsqueeze(0) + + for block_index in range(prefill_blocks, num_blocks): + window_end = (block_index + 1) * block_length + current = x[:, :window_end] + current_mask = full_attention_mask[:, :, :window_end, :window_end] + current_positions = position_ids[:, :window_end] + + for step_index in range(steps): + active = current[:, -block_length:] == mask_id + if not active.any(): + break + if use_cfg: + unconditional = current.clone() + unconditional[:, :prompt_length] = uncond_input + combined_ids = torch.cat([current, unconditional], dim=0) + combined_positions = torch.cat( + [current_positions, uncond_position_ids[:, :window_end]], dim=0 + ) + combined_mask = torch.cat( + [ + current_mask, + uncond_attention_mask[:, :, :window_end, :window_end], + ], + dim=0, + ) + logits = self( + input_ids=combined_ids, + attention_mask=combined_mask, + position_ids=combined_positions, + ).logits + conditional_logits, unconditional_logits = logits.chunk(2, dim=0) + active_logits = unconditional_logits[ + :, -block_length: + ] + cfg_scale * ( + conditional_logits[:, -block_length:] + - unconditional_logits[:, -block_length:] + ) + else: + active_logits = self( + input_ids=current, + attention_mask=current_mask, + position_ids=current_positions, + ).logits[:, -block_length:] + + tokens, confidence = self._sample_with_temperature_topk_topp( + active_logits, temperature=temperature, top_k=top_k, top_p=top_p + ) + count = schedule[step_index].item() + scores = torch.where(active, confidence, -torch.inf) + selected = torch.zeros_like(tokens, dtype=torch.bool) + high_confidence = scores[0] > threshold + if high_confidence.sum().item() >= count: + selected[0] = high_confidence + else: + _, indices = torch.topk( + scores[0], k=min(count, active.sum().item()) + ) + selected[0, indices] = True + current[:, -block_length:][selected] = tokens[selected] + + stop_token = eoi_id if mode == "eoi" else eos_id + positions = (current[0, prompt_length:] == stop_token).nonzero( + as_tuple=True + )[0] + if eos_early_stop and len(positions) > 0: + stop_position = positions[0].item() + prompt_length + if (current[0, prompt_length:stop_position] != mask_id).all(): + x[:, :window_end] = current + return x[:, : stop_position + 1] + + x[:, :window_end] = current + return x[:, : prompt_length + gen_length] + + +__all__ = ["LLaDA2MoeModelLM", "LLaDA2MoeModel", "LLaDA2MoePreTrainedModel"] diff --git a/pipelines/llada/pipeline_llada_image.py b/pipelines/llada/pipeline_llada_image.py new file mode 100644 index 000000000..7010dfadd --- /dev/null +++ b/pipelines/llada/pipeline_llada_image.py @@ -0,0 +1,689 @@ +# Copyright 2026 The HuggingFace Team. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from collections.abc import Callable +from pathlib import Path + +import torch +import torch.nn.functional as F +from transformers import AutoModel, AutoTokenizer, PreTrainedModel, PreTrainedTokenizerBase + +from diffusers.image_processor import PipelineImageInput, VaeImageProcessor +from diffusers.models import AutoencoderKLFlux2 +from diffusers.pipelines.pipeline_utils import DiffusionPipeline +from diffusers.schedulers import FlowMatchEulerDiscreteScheduler +from diffusers.utils import logging +from diffusers.utils.torch_utils import randn_tensor + +from .transformer_llada_image import ( + LLaDAImageQueryFormerModel, + LLaDAImageSigVQModel, + LLaDAImageTextProjectionModel, + LLaDAImageTransformer2DModel, +) +from .pipeline_output import LLaDAImagePipelineOutput + + +logger = logging.get_logger(__name__) + + +class LLaDAImagePipeline(DiffusionPipeline): + r""" + Pipeline for LLaDA-Image text-to-image generation, VQ-conditioned generation, and single-image editing. + + Args: + scheduler ([`FlowMatchEulerDiscreteScheduler`]): + Flow-matching scheduler used for denoising. + vae ([`AutoencoderKLFlux2`]): + Flux2 VAE used to encode reference images and decode generated latents. + text_encoder (`transformers.PreTrainedModel`): + LLaDA2 conditional-generation model. It must expose `get_input_embeddings()` and its language backbone as + `model`. + tokenizer (`transformers.PreTrainedTokenizerBase`): + Tokenizer paired with the LLaDA2 text encoder. + queryformer ([`LLaDAImageQueryFormerModel`]): + QueryFormer that refines the learnable generation queries. + text_projection ([`LLaDAImageTextProjectionModel`]): + Connector and projector that map LLaDA2 hidden states to denoiser caption features. + sigvq ([`LLaDAImageSigVQModel`]): + GLM SigVQ component that embeds MLLM-generated VQ tokens and encodes editing reference images. + transformer ([`LLaDAImageTransformer2DModel`]): + Denoising transformer. + """ + + model_cpu_offload_seq = "text_encoder->queryformer->text_projection->sigvq->transformer->vae" + _callback_tensor_inputs = ["latents", "noise_pred"] + + def __init__( + self, + scheduler: FlowMatchEulerDiscreteScheduler, + vae: AutoencoderKLFlux2, + text_encoder: PreTrainedModel, + tokenizer: PreTrainedTokenizerBase, + queryformer: LLaDAImageQueryFormerModel, + text_projection: LLaDAImageTextProjectionModel, + sigvq: LLaDAImageSigVQModel, + transformer: LLaDAImageTransformer2DModel, + ): + super().__init__() + self.register_modules( + scheduler=scheduler, + vae=vae, + text_encoder=text_encoder, + tokenizer=tokenizer, + queryformer=queryformer, + text_projection=text_projection, + sigvq=sigvq, + transformer=transformer, + ) + + self.vae_scale_factor = 2 ** (len(self.vae.config.block_out_channels) - 1) if self.vae is not None else 8 + self.latent_scale_factor = self.vae_scale_factor * 2 + self.patch_size = 2 # transformer patch size, read by the host to round sizes to the latent multiple + self.init_image_multiple = self.latent_scale_factor * 2 # editing feeds a half-resolution copy of the source image to the semantic encoder + self.image_processor = VaeImageProcessor(vae_scale_factor=self.latent_scale_factor) + + @classmethod + def from_pretrained( # pylint: disable=arguments-differ + cls, + pretrained_model_name_or_path: str | Path, + *, + torch_dtype: torch.dtype | None = None, + device: torch.device | str | None = None, + cache_dir: str | None = None, + scheduler=None, + vae=None, + text_encoder=None, + tokenizer=None, + queryformer=None, + text_projection=None, + sigvq=None, + transformer=None, + **kwargs, + ) -> "LLaDAImagePipeline": + """Load all LLaDA-Image components from a converted model directory or Hugging Face repository. + + This model stores a LLaDA2 text encoder that requires `trust_remote_code=True`, so its components are loaded + explicitly instead of relying on the generic Diffusers pipeline resolver. + """ + model_path = Path(pretrained_model_name_or_path) + if not model_path.is_dir(): + from huggingface_hub import snapshot_download + + ignore_patterns = ["assets/**"] + if text_encoder is not None: + ignore_patterns.append("text_encoder/**") + if transformer is not None: + ignore_patterns.append("transformer/**") + model_path = Path( + snapshot_download( + repo_id=str(pretrained_model_name_or_path), + cache_dir=cache_dir, + ignore_patterns=ignore_patterns or None, + ) + ) + + if not (model_path / "model_index.json").is_file(): + raise ValueError( + "Expected a converted LLaDA-Image model directory containing `model_index.json`, got " + f"{model_path}." + ) + + if scheduler is None: + scheduler = FlowMatchEulerDiscreteScheduler.from_pretrained(model_path / "scheduler", cache_dir=cache_dir) + if vae is None: + vae = AutoencoderKLFlux2.from_pretrained(model_path / "vae", torch_dtype=torch_dtype, cache_dir=cache_dir) + if text_encoder is None: + text_encoder_kwargs = {"dtype": torch_dtype, "trust_remote_code": True, "cache_dir": cache_dir} + if device is not None: + text_encoder_kwargs["device_map"] = {"": device} + text_encoder = AutoModel.from_pretrained(model_path / "text_encoder", **text_encoder_kwargs) + if tokenizer is None: + tokenizer = AutoTokenizer.from_pretrained(model_path / "tokenizer", cache_dir=cache_dir) + if queryformer is None: + queryformer = LLaDAImageQueryFormerModel.from_pretrained( + model_path / "queryformer", torch_dtype=torch_dtype, cache_dir=cache_dir + ) + if text_projection is None: + text_projection = LLaDAImageTextProjectionModel.from_pretrained( + model_path / "text_projection", torch_dtype=torch_dtype, cache_dir=cache_dir + ) + if sigvq is None: + sigvq = LLaDAImageSigVQModel.from_pretrained( + model_path / "sigvq", torch_dtype=torch_dtype, cache_dir=cache_dir + ) + if transformer is None: + transformer = LLaDAImageTransformer2DModel.from_pretrained( + model_path / "transformer", torch_dtype=torch_dtype, cache_dir=cache_dir + ) + + if device is not None: + vae = vae.to(device) + queryformer = queryformer.to(device) + text_projection = text_projection.to(device) + sigvq = sigvq.to(device) + transformer = transformer.to(device) + + return cls( + scheduler=scheduler, + vae=vae, + text_encoder=text_encoder, + tokenizer=tokenizer, + queryformer=queryformer, + text_projection=text_projection, + sigvq=sigvq, + transformer=transformer, + ) + + @property + def guidance_scale(self) -> float: + return self._guidance_scale + + @property + def num_timesteps(self) -> int: + return self._num_timesteps + + @staticmethod + def _patchify_latents(latents: torch.Tensor) -> torch.Tensor: + batch_size, channels, height, width = latents.shape + latents = latents.reshape(batch_size, channels, height // 2, 2, width // 2, 2) + latents = latents.permute(0, 1, 3, 5, 2, 4) + return latents.reshape(batch_size, channels * 4, height // 2, width // 2) + + @staticmethod + def _unpatchify_latents(latents: torch.Tensor) -> torch.Tensor: + batch_size, channels, height, width = latents.shape + latents = latents.reshape(batch_size, channels // 4, 2, 2, height, width) + latents = latents.permute(0, 1, 4, 2, 5, 3) + return latents.reshape(batch_size, channels // 4, height * 2, width * 2) + + def _encode_text( + self, + prompts: list[str], + max_sequence_length: int, + ) -> tuple[torch.Tensor, torch.Tensor]: + formatted_prompts = [ + "HUMAN Generate an image.\nASSISTANT\n" + if prompt is None + else f"HUMAN Generate an image: {prompt.strip()}\nASSISTANT\n" + for prompt in prompts + ] + text_inputs = self.tokenizer( + formatted_prompts, + add_special_tokens=True, + padding=True, + truncation=True, + max_length=max_sequence_length, + return_tensors="pt", + ) + input_ids = text_inputs.input_ids.to(self.text_encoder.device) + attention_mask = text_inputs.attention_mask.to(input_ids.device).bool() + inputs_embeds = self.text_encoder.get_input_embeddings()(input_ids) + text_encoder_device = inputs_embeds.device + attention_mask = attention_mask.to(text_encoder_device) + + query_embeds = self.queryformer( + inputs_embeds.to(device=self.queryformer.device, dtype=self.queryformer.dtype), + attention_mask.to(self.queryformer.device), + ).query_embeds.to(device=text_encoder_device, dtype=inputs_embeds.dtype) + text_length = inputs_embeds.shape[1] + inputs_embeds = torch.cat([inputs_embeds, query_embeds], dim=1) + attention_mask = torch.cat( + [attention_mask, attention_mask.new_ones(attention_mask.shape[0], query_embeds.shape[1])], + dim=1, + ) + position_ids = attention_mask.long().cumsum(dim=1) - 1 + position_ids.masked_fill_(position_ids < 0, 0) + + mask_value = torch.finfo(inputs_embeds.dtype).min + backbone_attention_mask = attention_mask[:, None, None, :].expand(-1, 1, attention_mask.shape[1], -1) + backbone_attention_mask = torch.where( + backbone_attention_mask, + torch.zeros((), dtype=inputs_embeds.dtype, device=text_encoder_device), + torch.full((), mask_value, dtype=inputs_embeds.dtype, device=text_encoder_device), + ) + backbone_attention_mask[:, :, :text_length, text_length:] = mask_value + + hidden_states = self.text_encoder.model( + inputs_embeds=inputs_embeds, + attention_mask=backbone_attention_mask, + position_ids=position_ids, + return_dict=True, + ).last_hidden_state + prompt_embeds = self.text_projection( + hidden_states.to(device=self.text_projection.device, dtype=self.text_projection.dtype) + ).hidden_states + return prompt_embeds, attention_mask.to(prompt_embeds.device) + + def encode_prompt( + self, + prompt: str | list[str] | None, + negative_prompt: str | list[str] | None = None, + do_classifier_free_guidance: bool = True, + num_images_per_prompt: int = 1, + prompt_embeds: torch.Tensor | None = None, + prompt_attention_mask: torch.Tensor | None = None, + negative_prompt_embeds: torch.Tensor | None = None, + negative_prompt_attention_mask: torch.Tensor | None = None, + max_sequence_length: int = 2048, + device: torch.device | None = None, + ) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor | None, torch.Tensor | None]: + device = device or self._execution_device + + if prompt_embeds is None: + prompt = [prompt] if isinstance(prompt, str) else prompt + prompt_embeds, prompt_attention_mask = self._encode_text(prompt, max_sequence_length) + else: + prompt_embeds = prompt_embeds.to(device) + prompt_attention_mask = prompt_attention_mask.to(device).bool() + + batch_size = prompt_embeds.shape[0] + if do_classifier_free_guidance and negative_prompt_embeds is None: + if negative_prompt is None: + negative_prompt = [None] * batch_size + elif isinstance(negative_prompt, str): + negative_prompt = [negative_prompt] * batch_size + negative_prompt_embeds, negative_prompt_attention_mask = self._encode_text( + negative_prompt, max_sequence_length + ) + elif do_classifier_free_guidance: + negative_prompt_embeds = negative_prompt_embeds.to(device) + negative_prompt_attention_mask = negative_prompt_attention_mask.to(device).bool() + + prompt_embeds = prompt_embeds.repeat_interleave(num_images_per_prompt, dim=0) + prompt_attention_mask = prompt_attention_mask.repeat_interleave(num_images_per_prompt, dim=0) + if do_classifier_free_guidance: + negative_prompt_embeds = negative_prompt_embeds.repeat_interleave(num_images_per_prompt, dim=0) + negative_prompt_attention_mask = negative_prompt_attention_mask.repeat_interleave( + num_images_per_prompt, dim=0 + ) + + return prompt_embeds, prompt_attention_mask, negative_prompt_embeds, negative_prompt_attention_mask + + def generate_vq_tokens( + self, + prompt: str | list[str], + height: int, + width: int, + ) -> torch.Tensor: + prompts = [prompt] if isinstance(prompt, str) else prompt + image_token_offset = 157184 + frontend_scale = max(max(height, width) / 512, 1.0) + frontend_height = int(height / frontend_scale) + frontend_width = int(width / frontend_scale) + vq_height = frontend_height // 16 + vq_width = frontend_width // 16 + image_token_count = vq_height * vq_width + system_prompt = "You are a text-to-image generation assistant." + generated_tokens = [] + + for prompt in prompts: + text_prompt = f"SYSTEM {system_prompt} HUMAN{prompt}ASSISTANT" + text_ids = self.tokenizer(text_prompt).input_ids + image_info_ids = self.tokenizer( + f"<|image|><|reserved_token_{vq_height}|><|reserved_token_{vq_width}|><|/image|>" + ).input_ids + input_ids = text_ids + image_info_ids[:-1] + + uncond_prompt = ( + f"SYSTEM {system_prompt} HUMANASSISTANT" + ) + uncond_ids = self.tokenizer(uncond_prompt).input_ids + image_info_ids[:-1] + output_ids = self.text_encoder.generate_bd_image_logic( + data={ + "input_ids": torch.tensor(input_ids, device=self.text_encoder.device).unsqueeze(0), + "uncond_ids": uncond_ids, + }, + block_length=32, + steps=8, + gen_length=image_token_count, + cfg_scale=2.0, + ) + token_ids = output_ids[0, len(input_ids) : len(input_ids) + image_token_count] - image_token_offset + if len(token_ids) != image_token_count: + raise ValueError(f"The MLLM generated {len(token_ids)} VQ tokens, expected {image_token_count}.") + if torch.any((token_ids < 0) | (token_ids >= self.sigvq.config.codebook_size)): + raise ValueError("The MLLM generated token IDs outside the SigVQ codebook.") + generated_tokens.append(token_ids) + + return torch.stack(generated_tokens) + + def check_inputs( + self, + prompt: str | list[str] | None, + image: PipelineImageInput | None, + generation_mode: str, + height: int, + width: int, + num_images_per_prompt: int, + prompt_embeds: torch.Tensor | None, + prompt_attention_mask: torch.Tensor | None, + negative_prompt_embeds: torch.Tensor | None, + negative_prompt_attention_mask: torch.Tensor | None, + callback_on_step_end_tensor_inputs: list[str], + num_inference_steps: int, + ) -> None: + if generation_mode not in {"text", "vq", "editing"}: + raise ValueError("`generation_mode` must be one of 'text', 'vq', or 'editing'.") + if generation_mode in {"text", "vq"} and image is not None: + raise ValueError(f"`image` must be omitted when `generation_mode='{generation_mode}'`.") + if generation_mode == "vq" and prompt is None: + raise ValueError("`prompt` is required when `generation_mode='vq'`.") + if generation_mode == "editing" and image is None: + raise ValueError("`image` is required when `generation_mode='editing'`.") + if generation_mode == "vq" and (height % 16 != 0 or width % 16 != 0): + raise ValueError("`height` and `width` must be divisible by 16 in VQ mode.") + + required_multiple = self.init_image_multiple if generation_mode == "editing" else self.latent_scale_factor + if height <= 0 or width <= 0 or height % required_multiple != 0 or width % required_multiple != 0: + raise ValueError(f"`height` and `width` must be divisible by {required_multiple}.") + if num_inference_steps < 1: + raise ValueError("`num_inference_steps` must be at least 1.") + if prompt is None and prompt_embeds is None: + raise ValueError("Provide either `prompt` or `prompt_embeds`.") + if prompt is not None and prompt_embeds is not None: + raise ValueError("Provide only one of `prompt` or `prompt_embeds`.") + if prompt_embeds is not None and prompt_attention_mask is None: + raise ValueError("`prompt_attention_mask` is required with `prompt_embeds`.") + if negative_prompt_embeds is not None and negative_prompt_attention_mask is None: + raise ValueError("`negative_prompt_attention_mask` is required with `negative_prompt_embeds`.") + if num_images_per_prompt < 1: + raise ValueError("`num_images_per_prompt` must be at least 1.") + if not all(name in self._callback_tensor_inputs for name in callback_on_step_end_tensor_inputs): + raise ValueError( + f"`callback_on_step_end_tensor_inputs` must be chosen from {self._callback_tensor_inputs}." + ) + + def _encode_source_image( + self, + image: PipelineImageInput, + height: int, + width: int, + batch_size: int, + num_images_per_prompt: int, + ) -> tuple[torch.Tensor, torch.Tensor]: + image = self.image_processor.preprocess(image, height=height, width=width) + if image.shape[0] == 1 and batch_size > 1: + image = image.repeat(batch_size, 1, 1, 1) + if image.shape[0] != batch_size: + raise ValueError(f"The image batch size must be 1 or {batch_size}, but is {image.shape[0]}.") + image = image.repeat_interleave(num_images_per_prompt, dim=0) + + sigvq_pixel_values = F.interpolate( + image.float(), + size=(height // 2, width // 2), + mode="bilinear", + align_corners=False, + ) + semantic_features = self.sigvq( + sigvq_pixel_values.to(device=self.sigvq.device, dtype=self.sigvq.dtype) + ).semantic_features + + source_latents = self.vae.encode(image.to(device=self.vae.device, dtype=self.vae.dtype)).latent_dist.mode() + source_latents = self._patchify_latents(source_latents) + latent_mean = self.vae.bn.running_mean.view(1, -1, 1, 1).to(source_latents) + latent_std = torch.sqrt(self.vae.bn.running_var.view(1, -1, 1, 1) + self.vae.config.batch_norm_eps).to( + source_latents + ) + source_latents = (source_latents - latent_mean) / latent_std + return source_latents, semantic_features + + @torch.no_grad() + def __call__( + self, + prompt: str | list[str] | None = None, + image: PipelineImageInput | None = None, + generation_mode: str = "text", + negative_prompt: str | list[str] | None = None, + height: int = 1024, + width: int = 1024, + num_inference_steps: int = 20, + guidance_scale: float = 4.5, + num_images_per_prompt: int = 1, + generator: torch.Generator | list[torch.Generator] | None = None, + latents: torch.Tensor | None = None, + prompt_embeds: torch.Tensor | None = None, + prompt_attention_mask: torch.Tensor | None = None, + negative_prompt_embeds: torch.Tensor | None = None, + negative_prompt_attention_mask: torch.Tensor | None = None, + max_sequence_length: int = 2048, + output_type: str = "pil", + return_dict: bool = True, + callback_on_step_end: Callable[["LLaDAImagePipeline", int, torch.Tensor, dict], dict] | None = None, + callback_on_step_end_tensor_inputs: list[str] = ["latents"], + ) -> LLaDAImagePipelineOutput | tuple: + r""" + Generate images using text-only, VQ-conditioned, or editing inference. + + The timestep schedule is selected by the scheduler configuration. `use_uniform_sigmas=True` uses a uniform + pre-shift grid; otherwise the source Kumaraswamy schedule is used. + + Args: + prompt (`str` or `list[str]`, *optional*): + Text prompts that describe the generated image or requested edit. + image (`PipelineImageInput`, *optional*): + Reference image or image batch. Required in `"editing"` mode and rejected in other modes. + generation_mode (`str`, defaults to `"text"`): + Inference path. `"text"` uses only the text prompt. `"vq"` uses the MLLM to generate VQ tokens from + the prompt at a maximum frontend resolution of 512 before diffusion. `"editing"` uses both + reference-image SigVQ features and source-image latents. + negative_prompt (`str` or `list[str]`, *optional*): + Text excluded from generation. The checkpoint's empty CFG prompt is used by default. + height (`int`, defaults to `1024`): + Output image height. + width (`int`, defaults to `1024`): + Output image width. + num_inference_steps (`int`, defaults to `20`): + Number of flow-matching denoising steps. + guidance_scale (`float`, defaults to `4.5`): + Classifier-free guidance scale. Guidance is disabled at values up to `1.0`. + num_images_per_prompt (`int`, defaults to `1`): + Number of images generated per prompt. + generator (`torch.Generator` or `list[torch.Generator]`, *optional*): + Random generator or generator batch used to create the initial latents. + latents (`torch.Tensor`, *optional*): + Pre-generated patchified Flux2 latents. + prompt_embeds (`torch.Tensor`, *optional*): + Precomputed, projected positive prompt embeddings. + prompt_attention_mask (`torch.Tensor`, *optional*): + Valid-token mask for `prompt_embeds`. + negative_prompt_embeds (`torch.Tensor`, *optional*): + Precomputed, projected negative prompt embeddings. + negative_prompt_attention_mask (`torch.Tensor`, *optional*): + Valid-token mask for `negative_prompt_embeds`. + max_sequence_length (`int`, defaults to `2048`): + Maximum text sequence length before the QueryFormer tokens are appended. + output_type (`str`, defaults to `"pil"`): + Output format. Choose `"pil"`, `"np"`, `"pt"`, or `"latent"`. + return_dict (`bool`, defaults to `True`): + Whether to return [`LLaDAImagePipelineOutput`] instead of a tuple. + callback_on_step_end (`Callable`, *optional*): + Function called after each denoising step. + callback_on_step_end_tensor_inputs (`list[str]`, defaults to `["latents"]`): + Tensor names forwarded to `callback_on_step_end`. + + Returns: + [`LLaDAImagePipelineOutput`] or `tuple`: + Generated images or final patchified latents. + """ + self.check_inputs( + prompt, + image, + generation_mode, + height, + width, + num_images_per_prompt, + prompt_embeds, + prompt_attention_mask, + negative_prompt_embeds, + negative_prompt_attention_mask, + callback_on_step_end_tensor_inputs, + num_inference_steps, + ) + + if prompt_embeds is not None: + batch_size = prompt_embeds.shape[0] + elif isinstance(prompt, str): + batch_size = 1 + else: + batch_size = len(prompt) + device = self.transformer.device + self._guidance_scale = guidance_scale # pylint: disable=attribute-defined-outside-init + do_classifier_free_guidance = guidance_scale > 1.0 + + prompt_embeds, prompt_attention_mask, negative_prompt_embeds, negative_prompt_attention_mask = ( + self.encode_prompt( + prompt, + negative_prompt, + do_classifier_free_guidance, + num_images_per_prompt, + prompt_embeds, + prompt_attention_mask, + negative_prompt_embeds, + negative_prompt_attention_mask, + max_sequence_length, + device, + ) + ) + effective_batch_size = batch_size * num_images_per_prompt + + source_latents = None + semantic_features = None + if generation_mode == "vq": + vq_token_ids = self.generate_vq_tokens(prompt, height, width) + vq_token_ids = vq_token_ids.repeat_interleave(num_images_per_prompt, dim=0) + semantic_features = self.sigvq(token_ids=vq_token_ids.to(self.sigvq.device)).semantic_features + elif generation_mode == "editing": + source_latents, semantic_features = self._encode_source_image( + image, + height, + width, + batch_size, + num_images_per_prompt, + ) + + latent_shape = ( + effective_batch_size, + self.transformer.config.in_channels, + height // self.latent_scale_factor, + width // self.latent_scale_factor, + ) + if latents is None: + latents = randn_tensor(latent_shape, generator=generator, device=device, dtype=torch.float32) + latents = latents.to(self.transformer.dtype).float() + else: + if latents.shape != latent_shape: + raise ValueError(f"Expected `latents` to have shape {latent_shape}, got {tuple(latents.shape)}.") + latents = latents.to(device=device, dtype=torch.float32) + + if self.scheduler.config.get("use_uniform_sigmas", False): + # diffusers 0.39.0 does not natively support this scheduler option. Supplying the pre-shift grid + # explicitly preserves the behavior of the patched scheduler used by LLaDA-Image-SGLang. + sigmas = torch.linspace(1.0, 0.0, num_inference_steps + 1, dtype=torch.float32)[:-1].tolist() + self.scheduler.set_timesteps(sigmas=sigmas, device=device) + else: + schedule_steps = num_inference_steps + 1 + schedule = torch.linspace(0.001, 1.0, schedule_steps, dtype=torch.float64)[:-1] + schedule = (1 - (1 - schedule**1.17) ** 0.8) ** 1.1 + sigmas = (1 - schedule).tolist() + self.scheduler.set_timesteps(sigmas=sigmas, device=device) + timesteps = self.scheduler.timesteps + self._num_timesteps = len(timesteps) # pylint: disable=attribute-defined-outside-init + + cond_cap_feats = [ + embeds[mask].to(device=self.transformer.device, dtype=self.transformer.dtype) + for embeds, mask in zip(prompt_embeds, prompt_attention_mask.bool()) + ] + if do_classifier_free_guidance: + uncond_cap_feats = [ + embeds[mask].to(device=self.transformer.device, dtype=self.transformer.dtype) + for embeds, mask in zip(negative_prompt_embeds, negative_prompt_attention_mask.bool()) + ] + cap_feats = cond_cap_feats + uncond_cap_feats + else: + cap_feats = cond_cap_feats + + glm_cap_feats = None + source_latent_list = None + if semantic_features is not None: + cond_glm_cap_feats = [ + features.to(device=self.transformer.device, dtype=self.transformer.dtype) + for features in semantic_features + ] + if source_latents is not None: + source_latent_list = [ + latent.unsqueeze(1).to(device=self.transformer.device, dtype=self.transformer.dtype) + for latent in source_latents + ] + if do_classifier_free_guidance: + empty_glm = semantic_features.new_zeros((0, semantic_features.shape[-1])).to( + device=self.transformer.device, dtype=self.transformer.dtype + ) + glm_cap_feats = cond_glm_cap_feats + [empty_glm] * effective_batch_size + if source_latent_list is not None: + source_latent_list = source_latent_list + source_latent_list + else: + glm_cap_feats = cond_glm_cap_feats + + with self.progress_bar(total=num_inference_steps) as progress_bar: + for step_index, timestep in enumerate(timesteps): + latent_model_input = torch.cat([latents, latents], dim=0) if do_classifier_free_guidance else latents + latent_list = [latent.unsqueeze(1).to(self.transformer.dtype) for latent in latent_model_input] + model_timestep = (timestep / self.scheduler.config.num_train_timesteps).expand( + latent_model_input.shape[0] + ) + + noise_pred = self.transformer( + x=latent_list, + t=model_timestep.to(self.transformer.dtype), + cap_feats=cap_feats, + glm_cap_feats=glm_cap_feats, + source_latents=source_latent_list, + ).sample + noise_pred = -torch.stack(noise_pred, dim=0).squeeze(2).float() + + if do_classifier_free_guidance: + conditional_output, unconditional_output = noise_pred.chunk(2) + noise_pred = unconditional_output + self.guidance_scale * ( + conditional_output - unconditional_output + ) + + latents = self.scheduler.step(noise_pred, timestep, latents, return_dict=False)[0] + + if callback_on_step_end is not None: + callback_kwargs = {} + for name in callback_on_step_end_tensor_inputs: + callback_kwargs[name] = locals()[name] + callback_outputs = callback_on_step_end(self, step_index, timestep, callback_kwargs) + latents = callback_outputs.pop("latents", latents) + + progress_bar.update() + + if output_type == "latent": + images = latents + else: + latents = latents.to(device=self.vae.device, dtype=self.vae.dtype) + latent_mean = self.vae.bn.running_mean.view(1, -1, 1, 1).to(latents) + latent_std = torch.sqrt(self.vae.bn.running_var.view(1, -1, 1, 1) + self.vae.config.batch_norm_eps).to( + latents + ) + latents = latents * latent_std + latent_mean + latents = self._unpatchify_latents(latents) + images = self.vae.decode(latents, return_dict=False)[0] + images = self.image_processor.postprocess(images, output_type=output_type) + + self.maybe_free_model_hooks() + if not return_dict: + return (images,) + return LLaDAImagePipelineOutput(images=images) diff --git a/pipelines/llada/pipeline_output.py b/pipelines/llada/pipeline_output.py new file mode 100644 index 000000000..f79efaa72 --- /dev/null +++ b/pipelines/llada/pipeline_output.py @@ -0,0 +1,34 @@ +# Copyright 2026 The HuggingFace Team. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from dataclasses import dataclass + +import numpy as np +import PIL.Image +import torch + +from diffusers.utils import BaseOutput + + +@dataclass +class LLaDAImagePipelineOutput(BaseOutput): + """ + Output class for the LLaDA-Image pipeline. + + Args: + images (`list[PIL.Image.Image]`, `np.ndarray`, or `torch.Tensor`): + Generated images. The format is controlled by the pipeline's `output_type` argument. + """ + + images: list[PIL.Image.Image] | np.ndarray | torch.Tensor diff --git a/pipelines/llada/transformer_llada_image.py b/pipelines/llada/transformer_llada_image.py new file mode 100644 index 000000000..29cb06d00 --- /dev/null +++ b/pipelines/llada/transformer_llada_image.py @@ -0,0 +1,1880 @@ +# Copyright 2026 The HuggingFace Team. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import math +from dataclasses import dataclass + +import torch +import torch.nn as nn +import torch.nn.functional as F +from torch.nn.utils.rnn import pad_sequence + +from diffusers.configuration_utils import ConfigMixin, register_to_config +from diffusers.models.attention import AttentionMixin, AttentionModuleMixin, FeedForward +from diffusers.models.attention_dispatch import dispatch_attention_fn +from diffusers.models.modeling_outputs import Transformer2DModelOutput +from diffusers.models.modeling_utils import ModelMixin +from diffusers.models.normalization import RMSNorm +from diffusers.utils import BaseOutput +from diffusers.utils.torch_utils import maybe_allow_in_graph + + +ADALN_EMBED_DIM = 256 +SEQUENCE_MULTIPLE = 32 + + +@dataclass +class _LLaDAImageSequence: + features: list[torch.Tensor] + position_ids: list[torch.Tensor] + padding_masks: list[torch.Tensor] + noise_masks: list[list[int]] | None = None + + +class LLaDAImageTimestepEmbedder(nn.Module): + def __init__(self, output_dim: int, hidden_dim: int = 1024, frequency_embedding_dim: int = 256): + super().__init__() + self.mlp = nn.Sequential( + nn.Linear(frequency_embedding_dim, hidden_dim, bias=True), + nn.SiLU(), + nn.Linear(hidden_dim, output_dim, bias=True), + ) + self.frequency_embedding_dim = frequency_embedding_dim + + def forward(self, timestep: torch.Tensor, hidden_dtype: torch.dtype) -> torch.Tensor: + half_dim = self.frequency_embedding_dim // 2 + frequencies = torch.exp( + -math.log(10000) * torch.arange(half_dim, dtype=torch.float32, device=timestep.device) / half_dim + ) + arguments = timestep[:, None].float() * frequencies[None] + embedding = torch.cat([torch.cos(arguments), torch.sin(arguments)], dim=-1) + if self.frequency_embedding_dim % 2: + embedding = torch.cat([embedding, torch.zeros_like(embedding[:, :1])], dim=-1) + return self.mlp(embedding.to(dtype=hidden_dtype)) + + +class LLaDAImageRopeEmbedder(nn.Module): + def __init__(self, theta: float, axes_dims: tuple[int, ...], axes_lens: tuple[int, ...]): + super().__init__() + self.theta = theta + self.axes_dims = axes_dims + self.axes_lens = axes_lens + self.freqs_cis = None + + def _create_frequencies(self, device: torch.device) -> list[torch.Tensor]: + frequencies = [] + for axis_dim, axis_len in zip(self.axes_dims, self.axes_lens): + inverse_frequencies = 1.0 / ( + self.theta ** (torch.arange(0, axis_dim, 2, dtype=torch.float32, device=device) / axis_dim) + ) + positions = torch.arange(axis_len, dtype=torch.float32, device=device) + angles = torch.outer(positions, inverse_frequencies) + frequencies.append(torch.complex(torch.cos(angles), torch.sin(angles))) + return frequencies + + def forward(self, position_ids: torch.Tensor) -> torch.Tensor: + if self.freqs_cis is None or self.freqs_cis[0].device != position_ids.device: + self.freqs_cis = self._create_frequencies(position_ids.device) + + frequencies = [] + for axis, axis_frequencies in enumerate(self.freqs_cis): + frequencies.append(axis_frequencies[position_ids[:, axis]]) + return torch.cat(frequencies, dim=-1) + + +class LLaDAImageAttnProcessor: + _attention_backend = None + _parallel_config = None + + def __call__( + self, + attn: "LLaDAImageAttention", + hidden_states: torch.Tensor, + attention_mask: torch.Tensor | None = None, + freqs_cis: torch.Tensor | None = None, + ) -> torch.Tensor: + query = attn.to_q(hidden_states).unflatten(-1, (attn.heads, attn.head_dim)) + key = attn.to_k(hidden_states).unflatten(-1, (attn.heads, attn.head_dim)) + value = attn.to_v(hidden_states).unflatten(-1, (attn.heads, attn.head_dim)) + + if attn.norm_q is not None: + query = attn.norm_q(query) + key = attn.norm_k(key) + + if freqs_cis is not None: + with torch.autocast(device_type=hidden_states.device.type, enabled=False): + query_complex = torch.view_as_complex(query.float().reshape(*query.shape[:-1], -1, 2)) + key_complex = torch.view_as_complex(key.float().reshape(*key.shape[:-1], -1, 2)) + frequencies = freqs_cis.unsqueeze(2) + query = torch.view_as_real(query_complex * frequencies).flatten(3).to(dtype=query.dtype) + key = torch.view_as_real(key_complex * frequencies).flatten(3).to(dtype=key.dtype) + + if attention_mask is not None and attention_mask.ndim == 2: + attention_mask = attention_mask[:, None, None, :] + + hidden_states = dispatch_attention_fn( + query, + key, + value, + attn_mask=attention_mask, + dropout_p=0.0, + is_causal=False, + backend=self._attention_backend, + parallel_config=self._parallel_config, + ) + hidden_states = hidden_states.flatten(2, 3) + return attn.to_out[0](hidden_states) + + +class LLaDAImageAttention(nn.Module, AttentionModuleMixin): + _default_processor_cls = LLaDAImageAttnProcessor + _available_processors = [LLaDAImageAttnProcessor] + _supports_qkv_fusion = False + + def __init__(self, dim: int, num_heads: int, norm_eps: float, qk_norm: bool): + super().__init__() + self.heads = num_heads + self.head_dim = dim // num_heads + self.to_q = nn.Linear(dim, dim, bias=False) + self.to_k = nn.Linear(dim, dim, bias=False) + self.to_v = nn.Linear(dim, dim, bias=False) + self.norm_q = RMSNorm(self.head_dim, eps=norm_eps, elementwise_affine=False) if qk_norm else None + self.norm_k = RMSNorm(self.head_dim, eps=norm_eps, elementwise_affine=False) if qk_norm else None + self.to_out = nn.ModuleList([nn.Linear(dim, dim, bias=False), nn.Dropout(0.0)]) + self.set_processor(self._default_processor_cls()) + + def forward( + self, + hidden_states: torch.Tensor, + attention_mask: torch.Tensor | None, + freqs_cis: torch.Tensor, + ) -> torch.Tensor: + return self.processor(self, hidden_states, attention_mask, freqs_cis) + + +class LLaDAImageFeedForward(nn.Module): + def __init__(self, dim: int): + super().__init__() + hidden_dim = int(dim / 3 * 8) + self.w1 = nn.Linear(dim, hidden_dim, bias=False) + self.w2 = nn.Linear(hidden_dim, dim, bias=False) + self.w3 = nn.Linear(dim, hidden_dim, bias=False) + + def forward(self, hidden_states: torch.Tensor) -> torch.Tensor: + return self.w2(F.silu(self.w1(hidden_states)) * self.w3(hidden_states)) + + +def _select_per_token( + noisy_value: torch.Tensor, + clean_value: torch.Tensor, + noise_mask: torch.Tensor, + sequence_length: int, +) -> torch.Tensor: + noise_mask = noise_mask.unsqueeze(-1) + return torch.where( + noise_mask == 1, + noisy_value.unsqueeze(1).expand(-1, sequence_length, -1), + clean_value.unsqueeze(1).expand(-1, sequence_length, -1), + ) + + +@maybe_allow_in_graph +class LLaDAImageTransformerBlock(nn.Module): + def __init__(self, dim: int, num_heads: int, norm_eps: float, qk_norm: bool, modulation: bool): + super().__init__() + self.modulation = modulation + self.attention = LLaDAImageAttention(dim, num_heads, norm_eps, qk_norm) + self.feed_forward = LLaDAImageFeedForward(dim) + self.attention_norm1 = RMSNorm(dim, eps=norm_eps, elementwise_affine=False) + self.ffn_norm1 = RMSNorm(dim, eps=norm_eps, elementwise_affine=False) + self.attention_norm2 = RMSNorm(dim, eps=norm_eps, elementwise_affine=False) + self.ffn_norm2 = RMSNorm(dim, eps=norm_eps, elementwise_affine=False) + if modulation: + self.adaLN_modulation = nn.Sequential(nn.Linear(min(dim, ADALN_EMBED_DIM), 4 * dim, bias=True)) + + def forward( + self, + hidden_states: torch.Tensor, + attention_mask: torch.Tensor | None, + freqs_cis: torch.Tensor, + adaln_input: torch.Tensor | None = None, + noise_mask: torch.Tensor | None = None, + adaln_noisy: torch.Tensor | None = None, + adaln_clean: torch.Tensor | None = None, + ) -> torch.Tensor: + if self.modulation: + sequence_length = hidden_states.shape[1] + if noise_mask is None: + scale_msa, gate_msa, scale_mlp, gate_mlp = ( + self.adaLN_modulation(adaln_input).unsqueeze(1).chunk(4, dim=2) + ) + gate_msa = gate_msa.tanh() + gate_mlp = gate_mlp.tanh() + scale_msa = 1.0 + scale_msa + scale_mlp = 1.0 + scale_mlp + else: + noisy_modulation = self.adaLN_modulation(adaln_noisy) + clean_modulation = self.adaLN_modulation(adaln_clean) + noisy_scale_msa, noisy_gate_msa, noisy_scale_mlp, noisy_gate_mlp = noisy_modulation.chunk(4, dim=1) + clean_scale_msa, clean_gate_msa, clean_scale_mlp, clean_gate_mlp = clean_modulation.chunk(4, dim=1) + scale_msa = _select_per_token( + 1.0 + noisy_scale_msa, 1.0 + clean_scale_msa, noise_mask, sequence_length + ) + scale_mlp = _select_per_token( + 1.0 + noisy_scale_mlp, 1.0 + clean_scale_mlp, noise_mask, sequence_length + ) + gate_msa = _select_per_token(noisy_gate_msa.tanh(), clean_gate_msa.tanh(), noise_mask, sequence_length) + gate_mlp = _select_per_token(noisy_gate_mlp.tanh(), clean_gate_mlp.tanh(), noise_mask, sequence_length) + + attention_output = self.attention( + self.attention_norm1(hidden_states) * scale_msa, + attention_mask, + freqs_cis, + ) + hidden_states = hidden_states + gate_msa * self.attention_norm2(attention_output) + hidden_states = hidden_states + gate_mlp * self.ffn_norm2( + self.feed_forward(self.ffn_norm1(hidden_states) * scale_mlp) + ) + else: + attention_output = self.attention( + self.attention_norm1(hidden_states), + attention_mask, + freqs_cis, + ) + hidden_states = hidden_states + self.attention_norm2(attention_output) + hidden_states = hidden_states + self.ffn_norm2(self.feed_forward(self.ffn_norm1(hidden_states))) + return hidden_states + + +class LLaDAImageFinalLayer(nn.Module): + def __init__(self, dim: int, out_channels: int): + super().__init__() + self.norm_final = nn.LayerNorm(dim, elementwise_affine=False, eps=1e-6) + self.linear = nn.Linear(dim, out_channels, bias=True) + self.adaLN_modulation = nn.Sequential( + nn.SiLU(), + nn.Linear(min(dim, ADALN_EMBED_DIM), dim, bias=True), + ) + + def forward( + self, + hidden_states: torch.Tensor, + adaln_input: torch.Tensor | None = None, + noise_mask: torch.Tensor | None = None, + adaln_noisy: torch.Tensor | None = None, + adaln_clean: torch.Tensor | None = None, + ) -> torch.Tensor: + if noise_mask is None: + scale = 1.0 + self.adaLN_modulation(adaln_input) + scale = scale.unsqueeze(1) + else: + sequence_length = hidden_states.shape[1] + noisy_scale = 1.0 + self.adaLN_modulation(adaln_noisy) + clean_scale = 1.0 + self.adaLN_modulation(adaln_clean) + scale = _select_per_token(noisy_scale, clean_scale, noise_mask, sequence_length) + hidden_states = self.norm_final(hidden_states) * scale + return self.linear(hidden_states) + + +class LLaDAImageTransformer2DModel(ModelMixin, ConfigMixin, AttentionMixin): + r""" + The denoising transformer used by LLaDAImage for text-to-image generation and single-image editing. + + This component consumes caption features that have already passed through LLaDAImage's QueryFormer, connector, and + projector. For editing, it additionally consumes GLM/SigVQ features and source-image latents. + + Args: + all_patch_size (`tuple[int, ...]`, defaults to `(1,)`): + Supported spatial patch sizes. + all_f_patch_size (`tuple[int, ...]`, defaults to `(1,)`): + Supported temporal patch sizes paired with `all_patch_size`. + in_channels (`int`, defaults to `128`): + Number of channels in the patchified Flux2 VAE latents. + dim (`int`, defaults to `3840`): + Transformer hidden dimension. + n_layers (`int`, defaults to `30`): + Number of main transformer blocks. + n_refiner_layers (`int`, defaults to `2`): + Number of noise, caption, and SigVQ refiner blocks. + n_heads (`int`, defaults to `30`): + Number of attention heads. + norm_eps (`float`, defaults to `1e-5`): + Epsilon used by RMS normalization layers. + qk_norm (`bool`, defaults to `True`): + Whether to apply RMS normalization to query and key tensors. + cap_feat_dim (`int`, defaults to `2560`): + Dimension of projected QueryFormer caption features. + semantic_feat_dim (`int`, defaults to `4096`): + Dimension of GLM/SigVQ semantic features. + rope_theta (`float`, defaults to `256.0`): + RoPE frequency base. + t_scale (`float`, defaults to `1000.0`): + Scale applied to diffusion timesteps. + axes_dims (`tuple[int, ...]`, defaults to `(32, 48, 48)`): + RoPE dimensions for sequence, height, and width axes. + axes_lens (`tuple[int, ...]`, defaults to `(32768, 1024, 1024)`): + Maximum RoPE positions for sequence, height, and width axes. + """ + + _supports_gradient_checkpointing = True + _no_split_modules = ["LLaDAImageTransformerBlock"] + _repeated_blocks = ["LLaDAImageTransformerBlock"] + _skip_layerwise_casting_patterns = [ + "t_embedder", + "cap_embedder", + "semantic_embedder", + "sigvq_embedder", + ] + + @register_to_config + def __init__( + self, + all_patch_size: tuple[int, ...] = (1,), + all_f_patch_size: tuple[int, ...] = (1,), + in_channels: int = 128, + dim: int = 3840, + n_layers: int = 30, + n_refiner_layers: int = 2, + n_heads: int = 30, + norm_eps: float = 1e-5, + qk_norm: bool = True, + cap_feat_dim: int = 2560, + semantic_feat_dim: int = 4096, + rope_theta: float = 256.0, + t_scale: float = 1000.0, + axes_dims: tuple[int, ...] = (32, 48, 48), + axes_lens: tuple[int, ...] = (32768, 1024, 1024), + ): + super().__init__() + if len(all_patch_size) != len(all_f_patch_size): + raise ValueError("`all_patch_size` and `all_f_patch_size` must have the same length.") + if dim % n_heads != 0: + raise ValueError(f"`dim` ({dim}) must be divisible by `n_heads` ({n_heads}).") + if dim // n_heads != sum(axes_dims): + raise ValueError("The attention head dimension must equal the sum of `axes_dims`.") + + self.in_channels = in_channels + self.out_channels = in_channels + self.all_patch_size = all_patch_size + self.all_f_patch_size = all_f_patch_size + self.t_scale = t_scale + self.gradient_checkpointing = False + + self.all_x_embedder = nn.ModuleDict() + self.all_final_layer = nn.ModuleDict() + for patch_size, f_patch_size in zip(all_patch_size, all_f_patch_size): + patch_key = f"{patch_size}-{f_patch_size}" + patch_dim = f_patch_size * patch_size * patch_size * in_channels + self.all_x_embedder[patch_key] = nn.Linear(patch_dim, dim, bias=True) + self.all_final_layer[patch_key] = LLaDAImageFinalLayer(dim, patch_dim) + + self.noise_refiner = nn.ModuleList( + [ + LLaDAImageTransformerBlock(dim, n_heads, norm_eps, qk_norm, modulation=True) + for _ in range(n_refiner_layers) + ] + ) + self.context_refiner = nn.ModuleList( + [ + LLaDAImageTransformerBlock(dim, n_heads, norm_eps, qk_norm, modulation=False) + for _ in range(n_refiner_layers) + ] + ) + self.sigvq_refiner = nn.ModuleList( + [ + LLaDAImageTransformerBlock(dim, n_heads, norm_eps, qk_norm, modulation=False) + for _ in range(n_refiner_layers) + ] + ) + self.layers = nn.ModuleList( + [LLaDAImageTransformerBlock(dim, n_heads, norm_eps, qk_norm, modulation=True) for _ in range(n_layers)] + ) + + self.t_embedder = LLaDAImageTimestepEmbedder(min(dim, ADALN_EMBED_DIM)) + self.cap_embedder = nn.Sequential( + RMSNorm(cap_feat_dim, eps=norm_eps, elementwise_affine=False), + nn.Linear(cap_feat_dim, dim, bias=True), + ) + self.semantic_embedder = nn.Sequential( + RMSNorm(semantic_feat_dim, eps=norm_eps, elementwise_affine=False), + nn.Linear(semantic_feat_dim, dim, bias=True), + ) + self.sigvq_embedder = nn.Sequential( + RMSNorm(semantic_feat_dim, eps=norm_eps, elementwise_affine=False), + nn.Linear(semantic_feat_dim, dim, bias=True), + ) + + nn.init.normal_(self.semantic_embedder[1].weight, mean=0.0, std=0.02) + nn.init.zeros_(self.semantic_embedder[1].bias) + nn.init.normal_(self.sigvq_embedder[1].weight, mean=0.0, std=0.02) + nn.init.zeros_(self.sigvq_embedder[1].bias) + + self.x_pad_token = nn.Parameter(torch.zeros(1, dim)) + self.cap_pad_token = nn.Parameter(torch.zeros(1, dim)) + self.sigvq_pad_token = nn.Parameter(torch.zeros(1, dim)) + nn.init.normal_(self.sigvq_pad_token, mean=0.0, std=0.02) + + self.rope_embedder = LLaDAImageRopeEmbedder(rope_theta, axes_dims, axes_lens) + + @staticmethod + def _create_coordinate_grid( + size: tuple[int, int, int], + start: tuple[int, int, int], + device: torch.device, + ) -> torch.Tensor: + axes = [ + torch.arange(start_value, start_value + span, dtype=torch.int32, device=device) + for start_value, span in zip(start, size) + ] + return torch.stack(torch.meshgrid(axes, indexing="ij"), dim=-1) + + def _patchify_image( + self, + image: torch.Tensor, + patch_size: int, + f_patch_size: int, + ) -> tuple[torch.Tensor, tuple[int, int, int], tuple[int, int, int]]: + channels, frames, height, width = image.shape + frame_tokens = frames // f_patch_size + height_tokens = height // patch_size + width_tokens = width // patch_size + image = image.view( + channels, + frame_tokens, + f_patch_size, + height_tokens, + patch_size, + width_tokens, + patch_size, + ) + image = image.permute(1, 3, 5, 2, 4, 6, 0).reshape( + frame_tokens * height_tokens * width_tokens, + f_patch_size * patch_size * patch_size * channels, + ) + return image, (frames, height, width), (frame_tokens, height_tokens, width_tokens) + + def _pad_with_ids( + self, + features: torch.Tensor, + position_grid_size: tuple[int, int, int], + position_start: tuple[int, int, int], + noise_value: int | None = None, + ) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor, int, list[int] | None]: + original_length = len(features) + padding_length = (-original_length) % SEQUENCE_MULTIPLE + padded_length = original_length + padding_length + device = features.device + + position_ids = self._create_coordinate_grid( + position_grid_size, + position_start, + device, + ).flatten(0, 2) + if padding_length > 0: + padding_position_ids = ( + self._create_coordinate_grid( + (1, 1, 1), + (0, 0, 0), + device, + ) + .flatten(0, 2) + .repeat(padding_length, 1) + ) + position_ids = torch.cat([position_ids, padding_position_ids], dim=0) + features = torch.cat([features, features[-1:].repeat(padding_length, 1)], dim=0) + padding_mask = torch.cat( + [ + torch.zeros(original_length, dtype=torch.bool, device=device), + torch.ones(padding_length, dtype=torch.bool, device=device), + ] + ) + else: + padding_mask = torch.zeros(original_length, dtype=torch.bool, device=device) + + noise_mask = [noise_value] * padded_length if noise_value is not None else None + return features, position_ids, padding_mask, padded_length, noise_mask + + @staticmethod + def _batch_sequences( + features: list[torch.Tensor], + frequencies: list[torch.Tensor], + inner_padding_masks: list[torch.Tensor], + pad_token: torch.Tensor, + noise_masks: list[list[int]] | None = None, + ) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor | None, list[int], torch.Tensor | None]: + sequence_lengths = [len(item) for item in features] + max_sequence_length = max(sequence_lengths) + features = torch.cat(features, dim=0) + inner_padding_mask = torch.cat(inner_padding_masks).unsqueeze(-1) + features = torch.where( + inner_padding_mask.to(device=features.device), + pad_token.to(device=features.device, dtype=features.dtype), + features, + ) + features = list(features.split(sequence_lengths, dim=0)) + + features = pad_sequence(features, batch_first=True, padding_value=0.0) + frequencies = pad_sequence(frequencies, batch_first=True, padding_value=0.0)[:, : features.shape[1]] + + attention_mask = None + if not all(length == max_sequence_length for length in sequence_lengths): + attention_mask = torch.zeros( + (len(sequence_lengths), max_sequence_length), + dtype=torch.bool, + device=features.device, + ) + for batch_index, sequence_length in enumerate(sequence_lengths): + attention_mask[batch_index, :sequence_length] = True + + noise_mask = None + if noise_masks is not None: + noise_mask = pad_sequence( + [torch.tensor(mask, dtype=torch.long, device=features.device) for mask in noise_masks], + batch_first=True, + padding_value=0, + )[:, : features.shape[1]] + + return features, frequencies, attention_mask, sequence_lengths, noise_mask + + def _unpatchify( + self, + hidden_states: list[torch.Tensor], + sizes: list[tuple[int, int, int] | list[tuple[int, int, int]]], + patch_size: int, + f_patch_size: int, + image_offsets: list[tuple[int, int]] | None = None, + ) -> list[torch.Tensor]: + outputs = [] + for batch_index, batch_hidden_states in enumerate(hidden_states): + if image_offsets is None: + batch_sizes = [sizes[batch_index]] + image_hidden_states = batch_hidden_states + else: + batch_sizes = sizes[batch_index] + start, end = image_offsets[batch_index] + image_hidden_states = batch_hidden_states[start:end] + + current_offset = 0 + output = None + for frames, height, width in batch_sizes: + original_length = (frames // f_patch_size) * (height // patch_size) * (width // patch_size) + padding_length = (-original_length) % SEQUENCE_MULTIPLE + output = ( + image_hidden_states[current_offset : current_offset + original_length] + .view( + frames // f_patch_size, + height // patch_size, + width // patch_size, + f_patch_size, + patch_size, + patch_size, + self.out_channels, + ) + .permute(6, 0, 3, 1, 4, 2, 5) + .reshape(self.out_channels, frames, height, width) + ) + current_offset += original_length + padding_length + outputs.append(output) + return outputs + + def _prepare_t2i_sequences( + self, + x: list[torch.Tensor], + cap_feats: list[torch.Tensor] | None, + glm_features: list[torch.Tensor] | None, + patch_size: int, + f_patch_size: int, + ) -> tuple[ + _LLaDAImageSequence, + _LLaDAImageSequence | None, + _LLaDAImageSequence | None, + list[tuple[int, int, int]], + ]: + image_sequence = _LLaDAImageSequence([], [], []) + cap_sequence = _LLaDAImageSequence([], [], []) if cap_feats is not None else None + glm_sequence = _LLaDAImageSequence([], [], []) if glm_features is not None else None + image_sizes = [] + + for batch_index, latent in enumerate(x): + position_cursor = 1 + if cap_sequence is not None: + padded_features, position_ids, padding_mask, sequence_length, _ = self._pad_with_ids( + cap_feats[batch_index], + (len(cap_feats[batch_index]), 1, 1), + (position_cursor, 0, 0), + ) + cap_sequence.features.append(padded_features) + cap_sequence.position_ids.append(position_ids) + cap_sequence.padding_masks.append(padding_mask) + position_cursor += sequence_length + + if glm_sequence is not None: + padded_features, position_ids, padding_mask, sequence_length, _ = self._pad_with_ids( + glm_features[batch_index], + (len(glm_features[batch_index]), 1, 1), + (position_cursor, 0, 0), + ) + glm_sequence.features.append(padded_features) + glm_sequence.position_ids.append(position_ids) + glm_sequence.padding_masks.append(padding_mask) + position_cursor += sequence_length + + patches, image_size, token_grid_size = self._patchify_image(latent, patch_size, f_patch_size) + padded_features, position_ids, padding_mask, _, _ = self._pad_with_ids( + patches, + token_grid_size, + (position_cursor, 0, 0), + ) + image_sequence.features.append(padded_features) + image_sequence.position_ids.append(position_ids) + image_sequence.padding_masks.append(padding_mask) + image_sizes.append(image_size) + + return image_sequence, cap_sequence, glm_sequence, image_sizes + + def _prepare_editing_sequences( + self, + x: list[torch.Tensor], + cap_feats: list[torch.Tensor], + glm_cap_feats: list[torch.Tensor], + source_latents: list[torch.Tensor], + patch_size: int, + f_patch_size: int, + ) -> tuple[ + _LLaDAImageSequence, + _LLaDAImageSequence, + _LLaDAImageSequence, + list[list[tuple[int, int, int]]], + list[tuple[int, int]], + ]: + image_sequence = _LLaDAImageSequence([], [], [], []) + cap_sequence = _LLaDAImageSequence([], [], [], []) + sigvq_sequence = _LLaDAImageSequence([], [], [], []) + image_sizes = [] + image_offsets = [] + + for batch_index, latent in enumerate(x): + cap_end_positions = [] + position_cursor = 1 + batch_cap_features = [] + batch_cap_positions = [] + batch_cap_padding = [] + batch_cap_noise = [] + for noise_value in (0, 1): + padded_features, position_ids, padding_mask, _, noise_mask = self._pad_with_ids( + cap_feats[batch_index], + (len(cap_feats[batch_index]), 1, 1), + (position_cursor, 0, 0), + noise_value, + ) + batch_cap_features.append(padded_features) + batch_cap_positions.append(position_ids) + batch_cap_padding.append(padding_mask) + batch_cap_noise.extend(noise_mask) + position_cursor += len(cap_feats[batch_index]) + cap_end_positions.append(position_cursor) + position_cursor += 2 + + batch_image_features = [] + batch_image_sizes = [] + batch_image_positions = [] + batch_image_padding = [] + batch_image_noise = [] + for image, position_start, noise_value in zip( + (source_latents[batch_index], latent), + cap_end_positions, + (0, 1), + ): + patches, image_size, token_grid_size = self._patchify_image(image, patch_size, f_patch_size) + padded_features, position_ids, padding_mask, _, noise_mask = self._pad_with_ids( + patches, + token_grid_size, + (position_start, 0, 0), + noise_value, + ) + batch_image_features.append(padded_features) + batch_image_sizes.append(image_size) + batch_image_positions.append(position_ids) + batch_image_padding.append(padding_mask) + batch_image_noise.extend(noise_mask) + + batch_cap_features = torch.cat(batch_cap_features, dim=0) + batch_image_features = torch.cat(batch_image_features, dim=0) + cap_sequence.features.append(batch_cap_features) + cap_sequence.position_ids.append(torch.cat(batch_cap_positions, dim=0)) + cap_sequence.padding_masks.append(torch.cat(batch_cap_padding, dim=0)) + cap_sequence.noise_masks.append(batch_cap_noise) + image_sequence.features.append(batch_image_features) + image_sequence.position_ids.append(torch.cat(batch_image_positions, dim=0)) + image_sequence.padding_masks.append(torch.cat(batch_image_padding, dim=0)) + image_sequence.noise_masks.append(batch_image_noise) + image_sizes.append(batch_image_sizes) + image_offsets.append( + ( + len(batch_cap_features), + len(batch_cap_features) + len(batch_image_features), + ) + ) + + padded_features, position_ids, padding_mask, _, noise_mask = self._pad_with_ids( + glm_cap_feats[batch_index], + (len(glm_cap_feats[batch_index]), 1, 1), + (len(batch_cap_features) + len(batch_image_features) + 1, 0, 0), + 0, + ) + sigvq_sequence.features.append(padded_features) + sigvq_sequence.position_ids.append(position_ids) + sigvq_sequence.padding_masks.append(padding_mask) + sigvq_sequence.noise_masks.append(noise_mask) + + return image_sequence, cap_sequence, sigvq_sequence, image_sizes, image_offsets + + @staticmethod + def _merge_padded_sequences( + feature_groups: tuple[torch.Tensor, ...], + frequency_groups: tuple[torch.Tensor, ...], + length_groups: tuple[list[int], ...], + noise_mask_groups: tuple[torch.Tensor, ...] | None = None, + ) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor | None, list[int], torch.Tensor | None]: + batch_size = feature_groups[0].shape[0] + merged_features = [] + merged_frequencies = [] + merged_noise_masks = [] if noise_mask_groups is not None else None + + for batch_index in range(batch_size): + device = feature_groups[0].device + merged_features.append( + torch.cat( + [ + features[batch_index, : lengths[batch_index]].to(device) + for features, lengths in zip(feature_groups, length_groups) + ], + dim=0, + ) + ) + merged_frequencies.append( + torch.cat( + [ + frequencies[batch_index, : lengths[batch_index]].to(device) + for frequencies, lengths in zip(frequency_groups, length_groups) + ], + dim=0, + ) + ) + if merged_noise_masks is not None: + merged_noise_masks.append( + torch.cat( + [ + noise_masks[batch_index, : lengths[batch_index]].to(device) + for noise_masks, lengths in zip(noise_mask_groups, length_groups) + ], + dim=0, + ) + ) + + merged_lengths = [len(features) for features in merged_features] + merged_features = pad_sequence(merged_features, batch_first=True, padding_value=0.0) + merged_frequencies = pad_sequence(merged_frequencies, batch_first=True, padding_value=0.0) + + attention_mask = None + max_length = max(merged_lengths) + if not all(length == max_length for length in merged_lengths): + attention_mask = torch.zeros( + (batch_size, max_length), + dtype=torch.bool, + device=merged_features.device, + ) + for batch_index, sequence_length in enumerate(merged_lengths): + attention_mask[batch_index, :sequence_length] = True + + noise_mask = None + if merged_noise_masks is not None: + noise_mask = pad_sequence(merged_noise_masks, batch_first=True, padding_value=0)[ + :, : merged_features.shape[1] + ] + + return merged_features, merged_frequencies, attention_mask, merged_lengths, noise_mask + + def forward( + self, + x: list[torch.Tensor], + t: torch.Tensor, + cap_feats: list[torch.Tensor] | None, + glm_cap_feats: list[torch.Tensor] | None = None, + source_latents: list[torch.Tensor] | None = None, + patch_size: int = 1, + f_patch_size: int = 1, + return_dict: bool = True, + ) -> Transformer2DModelOutput | tuple[list[torch.Tensor]]: + r""" + Args: + x (`list[torch.Tensor]`): + Target latents. Each tensor has shape `(channels, frames, height, width)`. + t (`torch.Tensor`): + Denoising timestep for each batch item. + cap_feats (`list[torch.Tensor]`, *optional*): + Projected QueryFormer features, each with shape `(sequence_length, cap_feat_dim)`. + glm_cap_feats (`list[torch.Tensor]`, *optional*): + GLM/SigVQ features, each with shape `(sequence_length, semantic_feat_dim)`. + source_latents (`list[torch.Tensor]`, *optional*): + Source-image latents for editing. When provided, `cap_feats` and `glm_cap_feats` are required. + patch_size (`int`, defaults to `1`): + Spatial patch size. + f_patch_size (`int`, defaults to `1`): + Temporal patch size. + return_dict (`bool`, defaults to `True`): + Whether to return a [`~models.modeling_outputs.Transformer2DModelOutput`]. + + Returns: + [`~models.modeling_outputs.Transformer2DModelOutput`] or `tuple`: + The denoised target latents. + """ + patch_key = f"{patch_size}-{f_patch_size}" + if patch_key not in self.all_x_embedder: + raise ValueError(f"Unsupported patch sizes: patch_size={patch_size}, f_patch_size={f_patch_size}.") + if source_latents is None and cap_feats is None and glm_cap_feats is None: + raise ValueError("Text-to-image inference requires `cap_feats` or `glm_cap_feats`.") + if source_latents is not None and (cap_feats is None or glm_cap_feats is None): + raise ValueError("Editing requires `cap_feats`, `glm_cap_feats`, and `source_latents`.") + + batch_size = len(x) + is_editing = source_latents is not None + adaln_input = None + noisy_embedding = None + clean_embedding = None + image_offsets = None + + if is_editing: + if t.shape[0] == 1: + t = t.repeat(batch_size) + dual_timestep = torch.cat([t, torch.zeros_like(t)], dim=0) + dual_embedding = self.t_embedder(dual_timestep.abs() * self.t_scale, x[0].dtype) + noisy_embedding = dual_embedding[:batch_size] + clean_embedding = dual_embedding[batch_size:] + image_sequence, cap_sequence, sigvq_sequence, image_sizes, image_offsets = self._prepare_editing_sequences( + x, + cap_feats, + glm_cap_feats, + source_latents, + patch_size, + f_patch_size, + ) + else: + adaln_input = self.t_embedder(t * self.t_scale, x[0].dtype) + glm_features = ( + [self.semantic_embedder(batch_features) for batch_features in glm_cap_feats] + if glm_cap_feats is not None + else None + ) + image_sequence, cap_sequence, glm_sequence, image_sizes = self._prepare_t2i_sequences( + x, + cap_feats, + glm_features, + patch_size, + f_patch_size, + ) + + image_lengths = [len(features) for features in image_sequence.features] + image_features = self.all_x_embedder[patch_key](torch.cat(image_sequence.features, dim=0)) + image_frequencies = list( + self.rope_embedder(torch.cat(image_sequence.position_ids, dim=0)).split( + [len(position_ids) for position_ids in image_sequence.position_ids], + dim=0, + ) + ) + image_features, image_frequencies, image_attention_mask, image_lengths, image_noise_mask = ( + self._batch_sequences( + list(image_features.split(image_lengths, dim=0)), + image_frequencies, + image_sequence.padding_masks, + self.x_pad_token, + image_sequence.noise_masks, + ) + ) + + for layer in self.noise_refiner: + if torch.is_grad_enabled() and self.gradient_checkpointing: + if is_editing: + image_features = self._gradient_checkpointing_func( + layer, + image_features, + image_attention_mask, + image_frequencies, + None, + image_noise_mask, + noisy_embedding, + clean_embedding, + ) + else: + image_features = self._gradient_checkpointing_func( + layer, + image_features, + image_attention_mask, + image_frequencies, + adaln_input, + ) + elif is_editing: + image_features = layer( + image_features, + image_attention_mask, + image_frequencies, + noise_mask=image_noise_mask, + adaln_noisy=noisy_embedding, + adaln_clean=clean_embedding, + ) + else: + image_features = layer( + image_features, + image_attention_mask, + image_frequencies, + adaln_input, + ) + + if is_editing: + cap_lengths = [len(features) for features in cap_sequence.features] + cap_features = self.cap_embedder(torch.cat(cap_sequence.features, dim=0)) + cap_frequencies = list( + self.rope_embedder(torch.cat(cap_sequence.position_ids, dim=0)).split( + [len(position_ids) for position_ids in cap_sequence.position_ids], + dim=0, + ) + ) + cap_features, cap_frequencies, cap_attention_mask, cap_lengths, cap_noise_mask = self._batch_sequences( + list(cap_features.split(cap_lengths, dim=0)), + cap_frequencies, + cap_sequence.padding_masks, + self.cap_pad_token, + cap_sequence.noise_masks, + ) + + for layer in self.context_refiner: + if torch.is_grad_enabled() and self.gradient_checkpointing: + cap_features = self._gradient_checkpointing_func( + layer, + cap_features, + cap_attention_mask, + cap_frequencies, + ) + else: + cap_features = layer( + cap_features, + cap_attention_mask, + cap_frequencies, + ) + + sigvq_lengths = [len(features) for features in sigvq_sequence.features] + sigvq_features = self.sigvq_embedder(torch.cat(sigvq_sequence.features, dim=0)) + sigvq_frequencies = list( + self.rope_embedder(torch.cat(sigvq_sequence.position_ids, dim=0)).split( + [len(position_ids) for position_ids in sigvq_sequence.position_ids], + dim=0, + ) + ) + ( + sigvq_features, + sigvq_frequencies, + sigvq_attention_mask, + sigvq_lengths, + sigvq_noise_mask, + ) = self._batch_sequences( + list(sigvq_features.split(sigvq_lengths, dim=0)), + sigvq_frequencies, + sigvq_sequence.padding_masks, + self.sigvq_pad_token, + sigvq_sequence.noise_masks, + ) + + for layer in self.sigvq_refiner: + if torch.is_grad_enabled() and self.gradient_checkpointing: + sigvq_features = self._gradient_checkpointing_func( + layer, + sigvq_features, + sigvq_attention_mask, + sigvq_frequencies, + ) + else: + sigvq_features = layer( + sigvq_features, + sigvq_attention_mask, + sigvq_frequencies, + ) + + ( + unified_features, + unified_frequencies, + unified_attention_mask, + _, + unified_noise_mask, + ) = self._merge_padded_sequences( + (cap_features, image_features, sigvq_features), + (cap_frequencies, image_frequencies, sigvq_frequencies), + (cap_lengths, image_lengths, sigvq_lengths), + (cap_noise_mask, image_noise_mask, sigvq_noise_mask), + ) + else: + condition_feature_groups = [] + condition_frequency_groups = [] + condition_length_groups = [] + + if cap_sequence is not None: + cap_lengths = [len(features) for features in cap_sequence.features] + cap_features = self.cap_embedder(torch.cat(cap_sequence.features, dim=0)) + cap_padding_mask = torch.cat(cap_sequence.padding_masks).unsqueeze(-1).to(cap_features.device) + cap_features = torch.where( + cap_padding_mask, + self.cap_pad_token.to(device=cap_features.device, dtype=cap_features.dtype), + cap_features, + ) + cap_features = pad_sequence( + list(cap_features.split(cap_lengths, dim=0)), + batch_first=True, + padding_value=0.0, + ) + cap_frequencies = list( + self.rope_embedder(torch.cat(cap_sequence.position_ids, dim=0)).split( + [len(position_ids) for position_ids in cap_sequence.position_ids], + dim=0, + ) + ) + cap_frequencies = pad_sequence(cap_frequencies, batch_first=True, padding_value=0.0) + condition_feature_groups.append(cap_features) + condition_frequency_groups.append(cap_frequencies) + condition_length_groups.append(cap_lengths) + + if glm_sequence is not None: + glm_lengths = [len(features) for features in glm_sequence.features] + glm_features = torch.cat(glm_sequence.features, dim=0) + glm_padding_mask = torch.cat(glm_sequence.padding_masks).unsqueeze(-1).to(glm_features.device) + glm_features = torch.where( + glm_padding_mask, + self.cap_pad_token.to(device=glm_features.device, dtype=glm_features.dtype), + glm_features, + ) + glm_features = pad_sequence( + list(glm_features.split(glm_lengths, dim=0)), + batch_first=True, + padding_value=0.0, + ) + glm_frequencies = list( + self.rope_embedder(torch.cat(glm_sequence.position_ids, dim=0)).split( + [len(position_ids) for position_ids in glm_sequence.position_ids], + dim=0, + ) + ) + glm_frequencies = pad_sequence(glm_frequencies, batch_first=True, padding_value=0.0) + condition_feature_groups.append(glm_features) + condition_frequency_groups.append(glm_frequencies) + condition_length_groups.append(glm_lengths) + + condition_features, condition_frequencies, condition_attention_mask, condition_lengths, _ = ( + self._merge_padded_sequences( + tuple(condition_feature_groups), + tuple(condition_frequency_groups), + tuple(condition_length_groups), + ) + ) + + for layer in self.context_refiner: + if torch.is_grad_enabled() and self.gradient_checkpointing: + condition_features = self._gradient_checkpointing_func( + layer, + condition_features, + condition_attention_mask, + condition_frequencies, + ) + else: + condition_features = layer( + condition_features, + condition_attention_mask, + condition_frequencies, + ) + + unified_features, unified_frequencies, unified_attention_mask, _, unified_noise_mask = ( + self._merge_padded_sequences( + (image_features, condition_features), + (image_frequencies, condition_frequencies), + (image_lengths, condition_lengths), + ) + ) + + for layer in self.layers: + if torch.is_grad_enabled() and self.gradient_checkpointing: + if is_editing: + unified_features = self._gradient_checkpointing_func( + layer, + unified_features, + unified_attention_mask, + unified_frequencies, + None, + unified_noise_mask, + noisy_embedding, + clean_embedding, + ) + else: + unified_features = self._gradient_checkpointing_func( + layer, + unified_features, + unified_attention_mask, + unified_frequencies, + adaln_input, + ) + elif is_editing: + unified_features = layer( + unified_features, + unified_attention_mask, + unified_frequencies, + noise_mask=unified_noise_mask, + adaln_noisy=noisy_embedding, + adaln_clean=clean_embedding, + ) + else: + unified_features = layer( + unified_features, + unified_attention_mask, + unified_frequencies, + adaln_input, + ) + + if is_editing: + unified_features = self.all_final_layer[patch_key]( + unified_features, + noise_mask=unified_noise_mask, + adaln_noisy=noisy_embedding, + adaln_clean=clean_embedding, + ) + else: + unified_features = self.all_final_layer[patch_key]( + unified_features, + adaln_input=adaln_input, + ) + + output = self._unpatchify( + list(unified_features.unbind(dim=0)), + image_sizes, + patch_size, + f_patch_size, + image_offsets, + ) + if not return_dict: + return (output,) + return Transformer2DModelOutput(sample=output) + + +@dataclass +class LLaDAImageQueryFormerOutput(BaseOutput): + query_embeds: torch.Tensor + + +class LLaDAImageQueryAttnProcessor: + _attention_backend = None + _parallel_config = None + + def __call__( + self, + attn: "LLaDAImageQueryAttention", + hidden_states: torch.Tensor, + encoder_hidden_states: torch.Tensor, + attention_mask: torch.Tensor | None = None, + ) -> torch.Tensor: + query = F.linear( + hidden_states, + attn.in_proj_weight[: attn.inner_dim], + attn.in_proj_bias[: attn.inner_dim], + ) + key = F.linear( + encoder_hidden_states, + attn.in_proj_weight[attn.inner_dim : 2 * attn.inner_dim], + attn.in_proj_bias[attn.inner_dim : 2 * attn.inner_dim], + ) + value = F.linear( + encoder_hidden_states, + attn.in_proj_weight[2 * attn.inner_dim :], + attn.in_proj_bias[2 * attn.inner_dim :], + ) + + query = query.unflatten(-1, (attn.heads, attn.head_dim)) + key = key.unflatten(-1, (attn.heads, attn.head_dim)) + value = value.unflatten(-1, (attn.heads, attn.head_dim)) + + if attention_mask is not None: + attention_mask = attention_mask[:, None, None, :] + + hidden_states = dispatch_attention_fn( + query, + key, + value, + attn_mask=attention_mask, + dropout_p=attn.dropout if attn.training else 0.0, + is_causal=False, + backend=self._attention_backend, + parallel_config=self._parallel_config, + ) + hidden_states = hidden_states.flatten(2, 3) + return attn.out_proj(hidden_states) + + +class LLaDAImageQueryAttention(nn.Module, AttentionModuleMixin): + _default_processor_cls = LLaDAImageQueryAttnProcessor + _available_processors = [LLaDAImageQueryAttnProcessor] + _supports_qkv_fusion = False + + def __init__(self, hidden_size: int, num_heads: int, dropout: float): + super().__init__() + self.inner_dim = hidden_size + self.heads = num_heads + self.head_dim = hidden_size // num_heads + self.dropout = dropout + + self.in_proj_weight = nn.Parameter(torch.zeros(3 * hidden_size, hidden_size)) + self.in_proj_bias = nn.Parameter(torch.zeros(3 * hidden_size)) + self.out_proj = nn.Linear(hidden_size, hidden_size, bias=True) + self.set_processor(self._default_processor_cls()) + + nn.init.xavier_uniform_(self.in_proj_weight) + nn.init.zeros_(self.in_proj_bias) + + def forward( + self, + hidden_states: torch.Tensor, + encoder_hidden_states: torch.Tensor, + attention_mask: torch.Tensor | None = None, + ) -> torch.Tensor: + return self.processor(self, hidden_states, encoder_hidden_states, attention_mask) + + +@maybe_allow_in_graph +class LLaDAImageQueryFormerBlock(nn.Module): + def __init__( + self, + hidden_size: int, + num_heads: int, + intermediate_size: int, + dropout: float, + norm_eps: float, + ): + super().__init__() + self.norm_q = nn.LayerNorm(hidden_size, elementwise_affine=False, eps=norm_eps) + self.norm_k = nn.LayerNorm(hidden_size, elementwise_affine=False, eps=norm_eps) + self.cross_attn = LLaDAImageQueryAttention(hidden_size, num_heads, dropout) + self.dropout = nn.Dropout(dropout) + self.norm1 = nn.LayerNorm(hidden_size, elementwise_affine=False, eps=norm_eps) + self.mlp = nn.Module() + self.mlp.fc1 = nn.Linear(hidden_size, intermediate_size, bias=True) + self.mlp.fc2 = nn.Linear(intermediate_size, hidden_size, bias=True) + + def forward( + self, + query_embeds: torch.Tensor, + encoder_hidden_states: torch.Tensor, + attention_mask: torch.Tensor | None = None, + ) -> torch.Tensor: + query_embeds = self.norm_q(query_embeds) + encoder_hidden_states = self.norm_k(encoder_hidden_states) + attention_output = self.cross_attn(query_embeds, encoder_hidden_states, attention_mask) + query_embeds = query_embeds + self.dropout(attention_output) + query_embeds = self.norm1(query_embeds) + mlp_output = self.mlp.fc2(F.gelu(self.mlp.fc1(query_embeds), approximate="tanh")) + return query_embeds + self.dropout(mlp_output) + + +class LLaDAImageQueryFormerModel(ModelMixin, ConfigMixin, AttentionMixin): + r""" + QueryFormer used by LLaDA-Image to derive learnable image-generation queries from LLaDA token embeddings. + + This model is independent from the LLaDA text encoder. It returns refined query embeddings; the pipeline appends + them to the text embeddings and invokes the text encoder backbone. + + Args: + num_queries (`int`, defaults to `256`): + Number of learnable query tokens. + hidden_size (`int`, defaults to `2048`): + Query and LLaDA token embedding dimension. + num_hidden_layers (`int`, defaults to `1`): + Number of QueryFormer blocks. + num_attention_heads (`int`, defaults to `16`): + Number of cross-attention heads. + intermediate_size (`int`, defaults to `8192`): + Hidden dimension of the QueryFormer MLP. + dropout (`float`, defaults to `0.0`): + Dropout probability. + norm_eps (`float`, defaults to `1e-6`): + Epsilon used by parameter-free layer normalization. + """ + + _supports_gradient_checkpointing = True + _no_split_modules = ["LLaDAImageQueryFormerBlock"] + _repeated_blocks = ["LLaDAImageQueryFormerBlock"] + _skip_layerwise_casting_patterns = ["norm"] + + @register_to_config + def __init__( + self, + num_queries: int = 256, + hidden_size: int = 2048, + num_hidden_layers: int = 1, + num_attention_heads: int = 16, + intermediate_size: int = 8192, + dropout: float = 0.0, + norm_eps: float = 1e-6, + ): + super().__init__() + if hidden_size % num_attention_heads != 0: + raise ValueError( + f"`hidden_size` ({hidden_size}) must be divisible by `num_attention_heads` ({num_attention_heads})." + ) + + self.meta_queries = nn.Parameter(torch.zeros(num_queries, hidden_size)) + nn.init.normal_(self.meta_queries, std=1 / math.sqrt(hidden_size)) + self.query_blocks = nn.ModuleList( + [ + LLaDAImageQueryFormerBlock( + hidden_size, + num_attention_heads, + intermediate_size, + dropout, + norm_eps, + ) + for _ in range(num_hidden_layers) + ] + ) + self.gradient_checkpointing = False + + def forward( + self, + inputs_embeds: torch.Tensor, + attention_mask: torch.Tensor, + return_dict: bool = True, + ) -> LLaDAImageQueryFormerOutput | tuple[torch.Tensor]: + r""" + Args: + inputs_embeds (`torch.Tensor` of shape `(batch_size, sequence_length, hidden_size)`): + LLaDA input token embeddings. + attention_mask (`torch.Tensor` of shape `(batch_size, sequence_length)`): + Mask whose nonzero entries identify valid text tokens. + return_dict (`bool`, defaults to `True`): + Whether to return [`LLaDAImageQueryFormerOutput`] instead of a tuple. + + Returns: + [`LLaDAImageQueryFormerOutput`] or `tuple`: + The refined query embeddings. + """ + batch_size = inputs_embeds.shape[0] + query_embeds = self.meta_queries.unsqueeze(0).expand(batch_size, -1, -1) + attention_mask = attention_mask.bool() + + for query_block in self.query_blocks: + if torch.is_grad_enabled() and self.gradient_checkpointing: + query_embeds = self._gradient_checkpointing_func( + query_block, + query_embeds, + inputs_embeds, + attention_mask, + ) + else: + query_embeds = query_block(query_embeds, inputs_embeds, attention_mask) + + if not return_dict: + return (query_embeds,) + return LLaDAImageQueryFormerOutput(query_embeds=query_embeds) + + +@dataclass +class LLaDAImageTextProjectionOutput(BaseOutput): + hidden_states: torch.Tensor + + +class LLaDAImageTextProjectionAttnProcessor: + _attention_backend = None + _parallel_config = None + + def __call__( + self, + attn: "LLaDAImageTextProjectionAttention", + hidden_states: torch.Tensor, + ) -> torch.Tensor: + query = attn.q_proj(hidden_states).unflatten(-1, (attn.heads, attn.head_dim)) + key = attn.k_proj(hidden_states).unflatten(-1, (attn.heads, attn.head_dim)) + value = attn.v_proj(hidden_states).unflatten(-1, (attn.heads, attn.head_dim)) + + query = attn.q_norm(query) + key = attn.k_norm(key) + + hidden_states = dispatch_attention_fn( + query, + key, + value, + attn_mask=None, + dropout_p=attn.dropout if attn.training else 0.0, + is_causal=False, + backend=self._attention_backend, + parallel_config=self._parallel_config, + ) + hidden_states = hidden_states.flatten(2, 3) + return attn.out_proj(hidden_states) + + +class LLaDAImageTextProjectionAttention(nn.Module, AttentionModuleMixin): + _default_processor_cls = LLaDAImageTextProjectionAttnProcessor + _available_processors = [LLaDAImageTextProjectionAttnProcessor] + _supports_qkv_fusion = False + + def __init__(self, hidden_size: int, num_attention_heads: int, attention_dropout: float, norm_eps: float): + super().__init__() + self.heads = num_attention_heads + self.head_dim = hidden_size // num_attention_heads + self.dropout = attention_dropout + + self.k_proj = nn.Linear(hidden_size, hidden_size, bias=True) + self.v_proj = nn.Linear(hidden_size, hidden_size, bias=True) + self.q_proj = nn.Linear(hidden_size, hidden_size, bias=True) + self.out_proj = nn.Linear(hidden_size, hidden_size, bias=True) + self.q_norm = RMSNorm(self.head_dim, eps=norm_eps, elementwise_affine=False) + self.k_norm = RMSNorm(self.head_dim, eps=norm_eps, elementwise_affine=False) + self.set_processor(self._default_processor_cls()) + + def forward(self, hidden_states: torch.Tensor) -> torch.Tensor: + return self.processor(self, hidden_states) + + +class LLaDAImageTextProjectionMLP(nn.Module): + def __init__(self, hidden_size: int, intermediate_size: int): + super().__init__() + self.fc1 = nn.Linear(hidden_size, intermediate_size, bias=True) + self.fc2 = nn.Linear(intermediate_size, hidden_size, bias=True) + + def forward(self, hidden_states: torch.Tensor) -> torch.Tensor: + hidden_states = self.fc1(hidden_states) + hidden_states = F.gelu(hidden_states, approximate="tanh") + return self.fc2(hidden_states) + + +@maybe_allow_in_graph +class LLaDAImageTextProjectionBlock(nn.Module): + def __init__( + self, + hidden_size: int, + intermediate_size: int, + num_attention_heads: int, + attention_dropout: float, + norm_eps: float, + ): + super().__init__() + self.self_attn = LLaDAImageTextProjectionAttention( + hidden_size, + num_attention_heads, + attention_dropout, + norm_eps, + ) + self.layer_norm1 = RMSNorm(hidden_size, eps=norm_eps, elementwise_affine=False) + self.mlp = LLaDAImageTextProjectionMLP(hidden_size, intermediate_size) + self.layer_norm2 = RMSNorm(hidden_size, eps=norm_eps, elementwise_affine=False) + + def forward(self, hidden_states: torch.Tensor) -> torch.Tensor: + hidden_states = hidden_states + self.self_attn(self.layer_norm1(hidden_states)) + hidden_states = hidden_states + self.mlp(self.layer_norm2(hidden_states)) + return hidden_states + + +class LLaDAImageTextProjectionModel(ModelMixin, ConfigMixin, AttentionMixin): + r""" + Connector and output projection used to map LLaDA hidden states to the LLaDA-Image denoiser context dimension. + + Args: + hidden_size (`int`, defaults to `2048`): + Input and connector hidden dimension. + intermediate_size (`int`, defaults to `8960`): + Connector MLP hidden dimension. + num_hidden_layers (`int`, defaults to `6`): + Number of connector layers. + num_attention_heads (`int`, defaults to `32`): + Number of connector self-attention heads. + projection_dim (`int`, defaults to `2560`): + Output dimension expected by the denoising transformer. + attention_dropout (`float`, defaults to `0.0`): + Attention dropout probability. + norm_eps (`float`, defaults to `1e-6`): + Epsilon used by parameter-free RMS normalization. + """ + + _supports_gradient_checkpointing = True + _no_split_modules = ["LLaDAImageTextProjectionBlock"] + _repeated_blocks = ["LLaDAImageTextProjectionBlock"] + _skip_layerwise_casting_patterns = ["layer_norm", "q_norm", "k_norm"] + + @register_to_config + def __init__( + self, + hidden_size: int = 2048, + intermediate_size: int = 8960, + num_hidden_layers: int = 6, + num_attention_heads: int = 32, + projection_dim: int = 2560, + attention_dropout: float = 0.0, + norm_eps: float = 1e-6, + ): + super().__init__() + if hidden_size % num_attention_heads != 0: + raise ValueError( + f"`hidden_size` ({hidden_size}) must be divisible by `num_attention_heads` ({num_attention_heads})." + ) + + self.layers = nn.ModuleList( + [ + LLaDAImageTextProjectionBlock( + hidden_size, + intermediate_size, + num_attention_heads, + attention_dropout, + norm_eps, + ) + for _ in range(num_hidden_layers) + ] + ) + self.projector = nn.Linear(hidden_size, projection_dim, bias=True) + self.gradient_checkpointing = False + + def forward( + self, + hidden_states: torch.Tensor, + return_dict: bool = True, + ) -> LLaDAImageTextProjectionOutput | tuple[torch.Tensor]: + r""" + Args: + hidden_states (`torch.Tensor` of shape `(batch_size, sequence_length, hidden_size)`): + Hidden states produced by the LLaDA text backbone. + return_dict (`bool`, defaults to `True`): + Whether to return [`LLaDAImageTextProjectionOutput`] instead of a tuple. + + Returns: + [`LLaDAImageTextProjectionOutput`] or `tuple`: + Hidden states projected to the denoiser caption dimension. + """ + for layer in self.layers: + if torch.is_grad_enabled() and self.gradient_checkpointing: + hidden_states = self._gradient_checkpointing_func(layer, hidden_states) + else: + hidden_states = layer(hidden_states) + + hidden_states = self.projector(hidden_states) + if not return_dict: + return (hidden_states,) + return LLaDAImageTextProjectionOutput(hidden_states=hidden_states) + + +@dataclass +class LLaDAImageSigVQOutput(BaseOutput): + semantic_features: torch.Tensor + token_ids: torch.Tensor + + +class LLaDAImageSigVQAttnProcessor: + _attention_backend = None + _parallel_config = None + + def __call__(self, attn: "LLaDAImageSigVQAttention", hidden_states: torch.Tensor) -> torch.Tensor: + query, key, value = attn.qkv(hidden_states).chunk(3, dim=-1) + query = query.unflatten(-1, (attn.heads, attn.head_dim)) + key = key.unflatten(-1, (attn.heads, attn.head_dim)) + value = value.unflatten(-1, (attn.heads, attn.head_dim)) + + hidden_states = dispatch_attention_fn( + query, + key, + value, + attn_mask=None, + dropout_p=attn.dropout if attn.training else 0.0, + is_causal=False, + backend=self._attention_backend, + parallel_config=self._parallel_config, + ) + hidden_states = hidden_states.flatten(2, 3) + return attn.proj(hidden_states) + + +class LLaDAImageSigVQAttention(nn.Module, AttentionModuleMixin): + _default_processor_cls = LLaDAImageSigVQAttnProcessor + _available_processors = [LLaDAImageSigVQAttnProcessor] + _supports_qkv_fusion = False + + def __init__( + self, + hidden_size: int, + num_attention_heads: int, + attention_bias: bool, + attention_dropout: float, + ): + super().__init__() + self.heads = num_attention_heads + self.head_dim = hidden_size // num_attention_heads + self.dropout = attention_dropout + self.qkv = nn.Linear(hidden_size, 3 * hidden_size, bias=attention_bias) + self.proj = nn.Linear(hidden_size, hidden_size, bias=attention_bias) + self.set_processor(self._default_processor_cls()) + + def forward(self, hidden_states: torch.Tensor) -> torch.Tensor: + return self.processor(self, hidden_states) + + +class LLaDAImageSigVQMLP(nn.Module): + def __init__(self, hidden_size: int, intermediate_size: int): + super().__init__() + self.fc1 = nn.Linear(hidden_size, intermediate_size, bias=True) + self.fc2 = nn.Linear(intermediate_size, hidden_size, bias=True) + + def forward(self, hidden_states: torch.Tensor) -> torch.Tensor: + return self.fc2(F.gelu(self.fc1(hidden_states))) + + +@maybe_allow_in_graph +class LLaDAImageSigVQVisionBlock(nn.Module): + def __init__( + self, + hidden_size: int, + intermediate_size: int, + num_attention_heads: int, + attention_bias: bool, + attention_dropout: float, + norm_eps: float, + ): + super().__init__() + self.norm1 = nn.LayerNorm(hidden_size, eps=norm_eps) + self.norm2 = nn.LayerNorm(hidden_size, eps=norm_eps) + self.attn = LLaDAImageSigVQAttention( + hidden_size, + num_attention_heads, + attention_bias, + attention_dropout, + ) + self.mlp = LLaDAImageSigVQMLP(hidden_size, intermediate_size) + + def forward(self, hidden_states: torch.Tensor) -> torch.Tensor: + hidden_states = hidden_states + self.attn(self.norm1(hidden_states)) + hidden_states = hidden_states + self.mlp(self.norm2(hidden_states)) + return hidden_states + + +class LLaDAImageSigVQPatchEmbed(nn.Module): + def __init__(self, in_channels: int, hidden_size: int, patch_size: int): + super().__init__() + self.in_channels = in_channels + self.patch_size = patch_size + self.proj = nn.Conv2d(in_channels, hidden_size, kernel_size=patch_size, stride=patch_size) + + def forward(self, pixel_values: torch.Tensor) -> torch.Tensor: + batch_size, channels, height, width = pixel_values.shape + grid_height = height // self.patch_size + grid_width = width // self.patch_size + patches = pixel_values.reshape( + batch_size, + channels, + grid_height, + self.patch_size, + grid_width, + self.patch_size, + ) + patches = patches.permute(0, 2, 4, 1, 3, 5).reshape( + batch_size * grid_height * grid_width, + channels, + self.patch_size, + self.patch_size, + ) + hidden_states = self.proj(patches).flatten(1) + return hidden_states.reshape(batch_size, grid_height * grid_width, -1) + + +class LLaDAImageSigVQEmbeddings(nn.Module): + def __init__(self, image_size: int, patch_size: int, hidden_size: int): + super().__init__() + num_positions = (image_size // patch_size) ** 2 + self.position_embedding = nn.Embedding(num_positions, hidden_size) + + def forward(self, hidden_states: torch.Tensor, grid_height: int, grid_width: int) -> torch.Tensor: + batch_size = hidden_states.shape[0] + position_embedding = self.position_embedding.weight + hidden_size = position_embedding.shape[1] + original_size = int(position_embedding.shape[0] ** 0.5) + position_embedding = position_embedding.reshape(original_size, original_size, hidden_size) + position_embedding = position_embedding.permute(2, 0, 1).unsqueeze(0).to( + device=hidden_states.device, + dtype=torch.float32, + ) + + height_coordinates = torch.arange(grid_height, device=hidden_states.device, dtype=torch.float32) + width_coordinates = torch.arange(grid_width, device=hidden_states.device, dtype=torch.float32) + height_coordinates, width_coordinates = torch.meshgrid( + height_coordinates, + width_coordinates, + indexing="ij", + ) + normalized_width = ((width_coordinates.flatten() + 0.5) / grid_width) * 2 - 1 + normalized_height = ((height_coordinates.flatten() + 0.5) / grid_height) * 2 - 1 + grid = torch.stack((normalized_width, normalized_height), dim=-1) + grid = grid.reshape(1, grid_height * grid_width, 1, 2).expand(batch_size, -1, -1, -1) + + position_embedding = F.grid_sample( + position_embedding.expand(batch_size, -1, -1, -1), + grid, + mode="bilinear", + align_corners=False, + padding_mode="border", + ) + position_embedding = position_embedding.squeeze(-1).transpose(1, 2).to(hidden_states.dtype) + return hidden_states + position_embedding + + +class LLaDAImageSigVQQuantizer(nn.Module): + def __init__(self, num_embeddings: int, embedding_dim: int): + super().__init__() + self.embedding = nn.Embedding(num_embeddings, embedding_dim) + + def forward(self, hidden_states: torch.Tensor) -> torch.Tensor: + hidden_states = hidden_states.permute(0, 2, 3, 1).contiguous() + hidden_states = F.normalize(hidden_states.reshape(-1, hidden_states.shape[-1]), p=2, dim=-1) + embedding = F.normalize(self.embedding.weight, p=2, dim=-1).to( + device=hidden_states.device, + dtype=hidden_states.dtype, + ) + distances = ( + torch.sum(hidden_states**2, dim=1, keepdim=True) + + torch.sum(embedding**2, dim=1) + - 2 * torch.matmul(hidden_states, embedding.t()) + ) + return torch.argmin(distances, dim=1) + + +class LLaDAImageSigVQModel(ModelMixin, ConfigMixin, AttentionMixin): + r""" + Minimal GLM SigVQ image encoder used by LLaDA-Image editing. + + The model contains only the GLM vision encoder, VQ quantizer, and prior token projection used during inference. + Input images must already be RGB tensors normalized to `[-1, 1]`, have one common size, and be divisible by + `patch_size`. + """ + + _supports_gradient_checkpointing = True + _no_split_modules = ["LLaDAImageSigVQVisionBlock"] + _repeated_blocks = ["LLaDAImageSigVQVisionBlock"] + _skip_layerwise_casting_patterns = ["patch_embed", "position_embedding", "norm", "quantize"] + + @register_to_config + def __init__( + self, + image_size: int = 2048, + patch_size: int = 16, + in_channels: int = 3, + hidden_size: int = 1536, + intermediate_size: int = 6144, + num_hidden_layers: int = 40, + num_attention_heads: int = 16, + attention_bias: bool = True, + attention_dropout: float = 0.0, + norm_eps: float = 1e-6, + codebook_size: int = 16384, + codebook_embed_dim: int = 2048, + semantic_embed_dim: int = 4096, + ): + super().__init__() + if hidden_size % num_attention_heads != 0: + raise ValueError( + f"`hidden_size` ({hidden_size}) must be divisible by `num_attention_heads` ({num_attention_heads})." + ) + + self.visual = nn.Module() + self.visual.patch_embed = LLaDAImageSigVQPatchEmbed(in_channels, hidden_size, patch_size) + self.visual.embeddings = LLaDAImageSigVQEmbeddings(image_size, patch_size, hidden_size) + self.visual.blocks = nn.ModuleList( + [ + LLaDAImageSigVQVisionBlock( + hidden_size, + intermediate_size, + num_attention_heads, + attention_bias, + attention_dropout, + norm_eps, + ) + for _ in range(num_hidden_layers) + ] + ) + + self.vqmodel = nn.Module() + self.vqmodel.quant_conv = nn.Conv2d(hidden_size, codebook_embed_dim, kernel_size=1) + self.vqmodel.quantize = LLaDAImageSigVQQuantizer(codebook_size, codebook_embed_dim) + + self.prior_token_embedding = nn.Embedding(codebook_size, semantic_embed_dim) + self.prior_projector = FeedForward( + semantic_embed_dim, + semantic_embed_dim, + inner_dim=semantic_embed_dim, + activation_fn="linear-silu", + ) + self.gradient_checkpointing = False + + def forward( + self, + pixel_values: torch.Tensor | None = None, + token_ids: torch.Tensor | None = None, + return_dict: bool = True, + ) -> LLaDAImageSigVQOutput | tuple[torch.Tensor, torch.Tensor]: + r""" + Args: + pixel_values (`torch.Tensor` of shape `(batch_size, 3, height, width)`, *optional*): + RGB images normalized to `[-1, 1]`. Mutually exclusive with `token_ids`. + token_ids (`torch.Tensor` of shape `(batch_size, sequence_length)`, *optional*): + Precomputed VQ codebook IDs. Mutually exclusive with `pixel_values`. + return_dict (`bool`, defaults to `True`): + Whether to return [`LLaDAImageSigVQOutput`] instead of a tuple. + + Returns: + [`LLaDAImageSigVQOutput`] or `tuple`: + The projected semantic features and their discrete token IDs. + """ + if (pixel_values is None) == (token_ids is None): + raise ValueError("Provide exactly one of `pixel_values` or `token_ids`.") + + if pixel_values is not None: + if pixel_values.ndim != 4: + raise ValueError(f"`pixel_values` must have 4 dimensions, got shape {tuple(pixel_values.shape)}.") + height, width = pixel_values.shape[-2:] + if height % self.config.patch_size != 0 or width % self.config.patch_size != 0: + raise ValueError( + f"Image height and width must be divisible by {self.config.patch_size}, got {height}x{width}." + ) + + grid_height = height // self.config.patch_size + grid_width = width // self.config.patch_size + hidden_states = self.visual.patch_embed(pixel_values) + hidden_states = self.visual.embeddings(hidden_states, grid_height, grid_width) + + for block in self.visual.blocks: + if torch.is_grad_enabled() and self.gradient_checkpointing: + hidden_states = self._gradient_checkpointing_func(block, hidden_states) + else: + hidden_states = block(hidden_states) + + hidden_states = hidden_states.transpose(1, 2).reshape( + pixel_values.shape[0], + self.config.hidden_size, + grid_height, + grid_width, + ) + hidden_states = self.vqmodel.quant_conv(hidden_states) + token_ids = self.vqmodel.quantize(hidden_states).reshape(pixel_values.shape[0], -1) + elif token_ids.ndim != 2: + raise ValueError(f"`token_ids` must have 2 dimensions, got shape {tuple(token_ids.shape)}.") + + semantic_features = self.prior_projector(self.prior_token_embedding(token_ids)) + + if not return_dict: + return semantic_features, token_ids + return LLaDAImageSigVQOutput(semantic_features=semantic_features, token_ids=token_ids) diff --git a/pipelines/lumina_dimmo/lumina_dimoo.py b/pipelines/lumina_dimmo/lumina_dimoo.py index d16ca17ef..9a4b90898 100644 --- a/pipelines/lumina_dimmo/lumina_dimoo.py +++ b/pipelines/lumina_dimmo/lumina_dimoo.py @@ -874,10 +874,10 @@ class LLaDASequentialBlock(LLaDABlock): if self._activation_checkpoint_fn is not None: att, cache = self._activation_checkpoint_fn( # type: ignore - self.attention, q, k, v, attention_bias, layer_past=layer_past, use_cache=use_cache + self.attention, q, k, v, attention_bias, layer_past=layer_past ) else: - att, cache = self.attention(q, k, v, attention_bias, layer_past=layer_past, use_cache=use_cache) + att, cache = self.attention(q, k, v, attention_bias, layer_past=layer_past) x = x + self.dropout(att) @@ -967,7 +967,7 @@ class LLaDALlamaBlock(LLaDABlock): if self._activation_checkpoint_fn is not None: att, cache = self._activation_checkpoint_fn( # type: ignore - self.attention, q, k, v, attention_bias, layer_past=layer_past, use_cache=use_cache + self.attention, q, k, v, attention_bias, layer_past=layer_past, to_compute_mask=to_compute_mask ) else: att, cache = self.attention(q, k, v, attention_bias, layer_past=layer_past, to_compute_mask=to_compute_mask) diff --git a/pipelines/minimax/__init__.py b/pipelines/minimax/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/pipelines/minimax/minimax_latents.py b/pipelines/minimax/minimax_latents.py new file mode 100644 index 000000000..fe146fa90 --- /dev/null +++ b/pipelines/minimax/minimax_latents.py @@ -0,0 +1,50 @@ +import diffusers +from modules.logger import log + + +warned = False + + +def unpack_latents(latents, components: diffusers.modular_pipelines.ModularPipeline, state: diffusers.modular_pipelines.BlockState): + global warned # pylint: disable=global-statement + if warned: + return latents + from diffusers.modular_pipelines.minimax_h3.modular_pipeline import align_num_frames, video_latent_num_frames + from modules import processing_callbacks + frames = getattr(processing_callbacks.p, 'frames', 1) + width = getattr(processing_callbacks.p, 'width', 1024) + height = getattr(processing_callbacks.p, 'height', 1024) + if frames <= 0 or width <= 0 or height <= 0: + return latents + try: + num_frames = align_num_frames(frames, components.vae_frames_per_chunk, components.vae_latents_per_chunk) + num_latent_frames = video_latent_num_frames(num_frames, components.vae_frames_per_chunk, components.vae_latents_per_chunk) + latent_height = height // components.vae_spatial_compression_ratio + latent_width = width // components.vae_spatial_compression_ratio + patch_t, patch_h, patch_w = components.patch_size + channels = components.vae_latent_channels + rows = state.latents[state.num_condition_video_rows :] + rows = rows.reshape( + -1, + num_latent_frames // patch_t, + latent_height // patch_h, + latent_width // patch_w, + channels, + patch_t, + patch_h, + patch_w, + ) + rows = rows.permute(0, 4, 1, 5, 2, 6, 3, 7) + latents = rows.reshape( + -1, + channels, + num_latent_frames, + latent_height, + latent_width, + ).contiguous() + except Exception as e: + # fails with sliced attention due to shape mismatch as state.latents only contains a subset of the full video latents + if not warned: + warned = True + log.warning(f'Video unpack latents: {e}') + return latents diff --git a/pipelines/minimax/minimax_lora.py b/pipelines/minimax/minimax_lora.py new file mode 100644 index 000000000..9ea9332a5 --- /dev/null +++ b/pipelines/minimax/minimax_lora.py @@ -0,0 +1,307 @@ +"""MiniMax H3 native adapter loader. + +MiniMax H3 is a modular video pipeline with a transformer and a text encoder. +This loader routes transformer keys to ``lora_transformer_`` and text-encoder +keys to ``lora_te_`` when native LoRAs are applied. + +Published LoRAs target the reference module names. The mapping onto +``diffusers.MiniMaxH3Transformer3DModel`` follows the diffusers LoRA converter: +fused ``attn.qkv_proj`` splits into ``to_q``/``to_k``/``to_v``, and ``mlp.fc1`` +lands on the fused SwiGLU projection with its two output halves swapped. +""" + +import os +import re + +import torch + +from modules.logger import log +from modules.lora import native_adapter, network_pdd +from modules.video_models.video_minimax import SHIFT_KEYS + + +debug_log = log.trace if os.environ.get('SD_LORA_DEBUG', None) is not None else lambda *args, **kwargs: None + + +# Parallel decoding heads: the audio projection follows the audio schedule, and MiniMaxH3Scheduler counts the terminal sigma in num_inference_steps. +PDD = network_pdd.ArchSpec(schedulers={"audio_proj_out": "audio_scheduler"}, steps_for=lambda intervals: intervals + 1, shift_keys=SHIFT_KEYS) + + +KNOWN_PREFIXES = ( + "diffusion_model.text_encoders.", + "diffusion_model.text_encoder.", + "diffusion_model.transformer.", + "diffusion_model.blocks.", + "diffusion_model.transformer_blocks.", + "diffusion_model.token_refiner.refiner_blocks.", + "diffusion_model.token_refiner.", + "diffusion_model.model.language_model.", + "text_encoders.", + "text_encoder.", + "model.language_model.", + "transformer.", + "transformer_blocks.", + "blocks.", + "token_refiner.refiner_blocks.", + "token_refiner.", +) + native_adapter.KNOWN_PREFIXES_DEFAULT + + +STANDALONE_RENAMES = { + "video_patch_proj": "proj_in", + "audio_patch_proj": "audio_proj_in", + "condition_proj": "context_embedder", + "time_embedder.proj_in": "time_embedder.linear_1", + "time_embedder.proj_out": "time_embedder.linear_2", + "final_layer.adaln_proj.linear": "norm_out.linear", + "final_layer.norm": "norm_out.norm", + "final_layer.video_out": "proj_out", + "final_layer.audio_out": "audio_proj_out", +} + +# Reference block leaves and where each lands in a diffusers block; a leaf not listed here binds verbatim. +BLOCK_LEAF_TARGETS = { + "attn.qkv_proj": tuple((f"attn.{k}", native_adapter.ChunkSpec(idx=i, total=3)) for i, k in enumerate(("to_q", "to_k", "to_v"))), + "attn.out_proj": (("attn.to_out.0", None),), + "mlp.fc1": (("ff.net.0.proj", native_adapter.ChunkSpec(reorder=(1, 0))),), # reference [gate; value] onto the diffusers SwiGLU [value; gate] + "mlp.fc2": (("ff.net.2", None),), + "adaln_proj.linear": (("adaln_proj.linear", None),), +} + +BLOCK_STACKS = { + "blocks": "transformer_blocks", + "token_refiner.blocks": "token_refiner.refiner_blocks", +} + + +# Re-export for tests / compatibility +LORA_SUFFIXES = native_adapter.LORA_SUFFIXES +LOKR_SUFFIXES = native_adapter.LOKR_SUFFIXES +LOHA_SUFFIXES = native_adapter.LOHA_SUFFIXES +OFT_SUFFIXES = native_adapter.OFT_SUFFIXES +IA3_SUFFIXES = native_adapter.IA3_SUFFIXES +GLORA_SUFFIXES = native_adapter.GLORA_SUFFIXES +NORM_SUFFIXES = native_adapter.NORM_SUFFIXES +FULL_SUFFIXES = native_adapter.FULL_SUFFIXES + +LORA_MARKERS = native_adapter.LORA_MARKERS +LOKR_MARKERS = native_adapter.LOKR_MARKERS +LOHA_MARKERS = native_adapter.LOHA_MARKERS +OFT_MARKERS = native_adapter.OFT_MARKERS +IA3_MARKERS = native_adapter.IA3_MARKERS +GLORA_MARKERS = native_adapter.GLORA_MARKERS +NORM_MARKERS = native_adapter.NORM_MARKERS +FULL_MARKERS = native_adapter.FULL_MARKERS + +SUFFIX_NORMALIZE = native_adapter.SUFFIX_NORMALIZE +BARE_DIFFUSERS_PREFIX_USED = native_adapter.BARE_DIFFUSERS_PREFIX_USED +has_marker = native_adapter.has_marker + + +def _flattened(dotted): + return re.escape(dotted.replace(".", "_")) + + +# musubi-tuner flattens every "." to "_" under a lora_unet_ prefix; the reference module names carry underscores +# of their own, so the dotted path is recovered by matching the whole flattened name against the vocabulary above. +_FLATTENED_MODULES = [(re.compile(_flattened(name)), name) for name in STANDALONE_RENAMES] + [ + (re.compile(rf"{_flattened(stack)}_(\d+)_{_flattened(leaf)}"), f"{stack}.{{}}.{leaf}") + for stack in BLOCK_STACKS for leaf in BLOCK_LEAF_TARGETS +] + + +def _unflatten_lora_unet_key(key: str) -> str | None: + if not key.startswith("lora_unet_"): + return None + module_key, _, suffix = key[len("lora_unet_"):].partition(".") + if not suffix: + return None + for pattern, dotted in _FLATTENED_MODULES: + match = pattern.fullmatch(module_key) + if match: + return f"{dotted.format(*match.groups())}.{suffix}" + return None + + +def parse_key(key, suffixes): + """MiniMax-bound :func:`native_adapter.parse_key`.""" + unflattened = _unflatten_lora_unet_key(key) + if unflattened is not None: + key = unflattened + key = native_adapter.unwrap_peft_wrapper(key) + if key.startswith("dit."): + key = "diffusion_model." + key[len("dit."):] + return native_adapter.parse_key(key, suffixes, prefixes=KNOWN_PREFIXES) + + +def group_by_suffixes(state_dict, suffixes, *, prefixes=None): # pylint: disable=unused-argument + """MiniMax-bound :func:`native_adapter.group_by_suffixes`.""" + groups: dict[tuple, dict[str, object]] = {} + for key, value in state_dict.items(): + parsed = parse_key(key, suffixes) + if parsed is None: + continue + prefix_used, base, suffix = parsed + slot = groups.get((prefix_used, base)) + if slot is None: + slot = {} + groups[(prefix_used, base)] = slot + slot[suffix] = value + return groups + + +def _block_targets(target_stack, base): + """Targets for ``.`` inside a reference block stack.""" + idx, _, leaf = base.partition(".") + targets = BLOCK_LEAF_TARGETS.get(leaf) + if targets is None: + return [(f"{target_stack}.{base}", None)] + return [(f"{target_stack}.{idx}.{path}", chunk) for path, chunk in targets] + + +def resolve_targets(prefix_used, base): + """Return ``[(diffusers_path, ChunkSpec | None), ...]`` for MiniMax keys.""" + if prefix_used in ("diffusion_model.", BARE_DIFFUSERS_PREFIX_USED): + if base.startswith("transformer."): + return [(base[len("transformer."):], None)] + if base.startswith("text_encoder."): + return [(base[len("text_encoder."):], None)] + if base.startswith("text_encoders."): + return [(base[len("text_encoders."):], None)] + return [(STANDALONE_RENAMES.get(base, base), None)] + if prefix_used in ("diffusion_model.transformer.", "transformer.", "lora_transformer_"): + return [(base, None)] + if prefix_used in ("diffusion_model.transformer_blocks.", "transformer_blocks."): + return [(f"transformer_blocks.{base}", None)] + if prefix_used in ("diffusion_model.blocks.", "blocks."): + return _block_targets(BLOCK_STACKS["blocks"], base) + if prefix_used in ("diffusion_model.token_refiner.refiner_blocks.", "token_refiner.refiner_blocks."): + return [(f"token_refiner.refiner_blocks.{base}", None)] + if prefix_used in ("diffusion_model.token_refiner.", "token_refiner."): + if base.startswith("blocks."): + return _block_targets(BLOCK_STACKS["token_refiner.blocks"], base[len("blocks."):]) + return [(f"token_refiner.refiner_{base}", None)] + if prefix_used in ( + "diffusion_model.text_encoder.", + "diffusion_model.text_encoders.", + "text_encoder.", + "text_encoders.", + "lora_te_", + ): + return [(base, None)] + if prefix_used in ("lora_unet_", "lycoris_"): + return [(base, None)] + return [] + + +def network_prefix_for(prefix_used): + """Choose the network prefix for a parsed MiniMax group.""" + if prefix_used == "lora_te_": + return "lora_te_" + if prefix_used in ( + "text_encoder.", + "text_encoders.", + "diffusion_model.text_encoder.", + "diffusion_model.text_encoders.", + ): + return "lora_te_" + return "lora_transformer_" + + +def file_alpha(network_on_disk): + """The file-level training alpha from the safetensors metadata (alpha, or lora_alpha in PDD files), or None.""" + metadata = getattr(network_on_disk, "metadata", None) or {} + alpha = metadata.get("alpha", metadata.get("lora_alpha")) + if alpha is None: + return None + try: + return float(alpha) + except (TypeError, ValueError): + return None + + +_BIND_KWARGS = dict( + resolve_targets=resolve_targets, + prefixes=KNOWN_PREFIXES, + network_prefix=network_prefix_for, + group_by_suffixes_fn=group_by_suffixes, + arch_name="minimaxh3", +) + + +def pruned_basis(sd_module, rank, width, transformers=None): + """The AdaLN curve basis of the transformer owning ``sd_module``, or None on an unpruned model.""" + if transformers is None: + from modules import shared + pipe = getattr(shared.sd_model, "pipe", shared.sd_model) + transformers = [getattr(pipe, component, None) for component in ("transformer", "transformer_ref")] + for transformer in transformers: + basis = getattr(getattr(transformer, "time_embedder", None), "basis", None) + if basis is None or tuple(basis.shape) != (rank, width): + continue + if any(module is sd_module for module in transformer.modules()): + return basis + return None + + +def project_pruned_adaln(sd_module, network_key, w, transformers=None): + """Refit an AdaLN delta trained on the released time embedding onto the pruned curve basis: the pruned class + stores ``W @ P``, so ``up @ down`` lands exactly as ``up @ (down @ P)``.""" + down = w.get("lora_down.weight") + shape = native_adapter.module_shape(sd_module) + if down is None or down.ndim != 2 or shape is None or len(shape) != 2 or down.shape[1] == shape[1]: + return None + basis = pruned_basis(sd_module, shape[1], down.shape[1], transformers) + if basis is None: + return None + projected = dict(w) + projected["lora_down.weight"] = (down.to(dtype=torch.float32, device=basis.device) @ basis.to(dtype=torch.float32).T).to(dtype=down.dtype, device=down.device) + debug_log(f'Network load: type=LoRA arch=minimaxh3 key={network_key} adaln projected {down.shape[1]}->{shape[1]}') + return projected + + +adapt_weights = project_pruned_adaln # offline tools refit deltas through the same hook the loader binds + + +def try_load_lora(name, network_on_disk, lora_scale): + return native_adapter.try_load_lora(name, network_on_disk, lora_scale, network_alpha=file_alpha(network_on_disk), adapt_weights=project_pruned_adaln, **_BIND_KWARGS) + + +def try_load_lokr(name, network_on_disk, lora_scale): + return native_adapter.try_load_lokr(name, network_on_disk, lora_scale, **_BIND_KWARGS) + + +def try_load_loha(name, network_on_disk, lora_scale): + return native_adapter.try_load_loha(name, network_on_disk, lora_scale, **_BIND_KWARGS) + + +def try_load_oft(name, network_on_disk, lora_scale): + return native_adapter.try_load_oft(name, network_on_disk, lora_scale, **_BIND_KWARGS) + + +def try_load_ia3(name, network_on_disk, lora_scale): + return native_adapter.try_load_ia3(name, network_on_disk, lora_scale, **_BIND_KWARGS) + + +def try_load_glora(name, network_on_disk, lora_scale): + return native_adapter.try_load_glora(name, network_on_disk, lora_scale, **_BIND_KWARGS) + + +def try_load_norm(name, network_on_disk, lora_scale): + return native_adapter.try_load_norm(name, network_on_disk, lora_scale, **_BIND_KWARGS) + + +def try_load_full(name, network_on_disk, lora_scale): + return native_adapter.try_load_full(name, network_on_disk, lora_scale, **_BIND_KWARGS) + + +def try_load(name, network_on_disk, lora_scale): + """Run every MiniMax family loader, merge any that match.""" + return native_adapter.try_load_chain( + name, network_on_disk, lora_scale, + family_loaders=( + try_load_lora, try_load_lokr, try_load_loha, try_load_oft, + try_load_ia3, try_load_glora, try_load_norm, try_load_full, + network_pdd.try_load, + ), + ) diff --git a/pipelines/minimax/minimax_nunchaku.py b/pipelines/minimax/minimax_nunchaku.py new file mode 100644 index 000000000..bb3baf248 --- /dev/null +++ b/pipelines/minimax/minimax_nunchaku.py @@ -0,0 +1,61 @@ +import diffusers +from modules import shared, devices +from modules.logger import log + + +def load_nunchaku(repo_id, load_config=None): + load_config = load_config or {} + + from modules.attention import hijack_kernels + hijack_kernels() + + ## naive approach using diffusers class + cls_name = diffusers.MiniMaxH3Transformer3DModel + log.debug(f'Load model: transformer="{repo_id}" subfolder="calibrated-8x20" cls={cls_name.__name__} loader="nunchaku-lite" patch=False args={load_config}') + transformer = cls_name.from_pretrained( + repo_id, + subfolder="calibrated-8x20", + cache_dir=shared.opts.hfcache_dir, + **load_config, + ) + return transformer + + +def load_nunchaku_patched(repo_id, load_config=None): # pylint: disable=unused-argument + import torch + from huggingface_hub import hf_hub_download + from diffusers.models.transformers.transformer_minimax_h3 import MiniMaxH3RotaryPosEmbed + + from modules.attention import hijack_kernels + hijack_kernels() + + from installer import install + install('git+https://github.com/rootonchair/nunchaku-lite', 'nunchaku-lite') + from nunchaku_lite import core + + filename = "svdq-int4_r32-minimax-h3-t2va.safetensors" + orig_repo = "MiniMaxAI/MiniMax-H3" + cls_name = diffusers.MiniMaxH3Transformer3DModel + + log.debug(f'Load model: transformer="{repo_id}" fn="{filename}" cls={cls_name.__name__} loader="nunchaku-lite" patch=True args={load_config}') + ckpt = hf_hub_download(repo_id, + filename=filename, + cache_dir=shared.opts.diffusers_dir + ) + config = diffusers.MiniMaxH3Transformer3DModel.load_config(orig_repo, subfolder="transformer") + with torch.device("meta"): + transformer: diffusers.MiniMaxH3Transformer3DModel = diffusers.MiniMaxH3Transformer3DModel.from_config(config) + + # rope.inv_freq is a non-persistent buffer (absent from the checkpoint), so the meta-assign load would leave it on the meta device — rebuild it off-meta first. + transformer.rope.inv_freq = MiniMaxH3RotaryPosEmbed(rope_freq_dim=transformer.config.rope_freq_dim, rope_theta=transformer.config.rope_theta).inv_freq # pylint: disable=no-member + core._patch_component(transformer, # pylint: disable=protected-access + ckpt, + target="manifest", + precision="int4", + torch_dtype=devices.dtype, + device=devices.device, + strict=True, + adapter_options=None, + assign=True, + ) + return transformer diff --git a/pipelines/model_anima.py b/pipelines/model_anima.py index cbf10885c..c3e20dc66 100644 --- a/pipelines/model_anima.py +++ b/pipelines/model_anima.py @@ -1,9 +1,11 @@ +import os import importlib.util import transformers import diffusers from modules import shared, devices, sd_models, model_quant, sd_hijack_te, sd_hijack_vae, errors from modules.logger import log from pipelines import generic +from pipelines.generic_map import transformers_map def _import_from_file(module_name, file_path): @@ -13,17 +15,18 @@ def _import_from_file(module_name, file_path): return mod -def init_transformer_component(repo_id, diffusers_load_config, adapter_cls): +def init_transformer_component(repo_id, diffusers_load_config, adapter_cls, local_file=None): """Load (transformer, llm_adapter_or_none). - If the UNET dropdown points at a valid safetensors, route through - :mod:`pipelines.native_transformer` with :data:`pipelines.anima.ANIMA_SPEC`, - which extracts any bundled ``llm_adapter`` weights inline with the - transformer. Otherwise fall back to :func:`generic.load_transformer` and - return ``None`` for the adapter so the caller loads it from the base repo. + A UNET dropdown selection, else ``local_file`` (a single-file checkpoint), + goes through :mod:`pipelines.native_transformer`, which also extracts a + bundled ``llm_adapter``. Without either, the transformer comes from the base + repo and the adapter is ``None`` for the caller to load. """ + from modules import sd_unet from pipelines import native_transformer - local_file = native_transformer.resolve_path() + override = native_transformer.resolve_path() + local_file = override or local_file if local_file is not None: from pipelines.anima import ANIMA_SPEC try: @@ -31,11 +34,13 @@ def init_transformer_component(repo_id, diffusers_load_config, adapter_cls): local_file, repo_id, ANIMA_SPEC, diffusers_load_config, sibling_classes={'llm_adapter': adapter_cls}, ) - return transformer, siblings.get('llm_adapter') except Exception as e: log.error(f'Load model: type=Anima custom transformer="{local_file}": {e}') errors.display(e, 'Load') return None, None + if override is not None: + sd_unet.loaded_unet = shared.opts.sd_unet + return transformer, siblings.get('llm_adapter') transformer = generic.load_transformer( repo_id, cls_name=diffusers.CosmosTransformer3DModel, @@ -51,9 +56,15 @@ def load_anima(checkpoint_info, diffusers_load_config=None): repo_id = sd_models.path_to_repo(checkpoint_info) sd_models.hf_auth_check(checkpoint_info) + # single-file checkpoint: transformer (and bundled llm_adapter) from the file, everything else from the base repo + local_file = None + if repo_id is not None and os.path.isfile(repo_id) and repo_id.lower().endswith('.safetensors'): + local_file = repo_id + repo_id = transformers_map['AnimaTextToImagePipeline'] + load_args, _quant_args = model_quant.get_dit_args(diffusers_load_config, allow_quant=False) load_args.pop('cache_dir', None) - log.debug(f'Load model: type=Anima repo="{repo_id}" config={diffusers_load_config} offload={shared.opts.diffusers_offload_mode} dtype={devices.dtype} args={load_args}') + log.debug(f'Load model: type=Anima repo="{repo_id}" file="{local_file}" config={diffusers_load_config} offload={shared.opts.diffusers_offload_mode} dtype={devices.dtype} args={load_args}') if repo_id is None or repo_id.lower() == 'none': return None @@ -69,9 +80,8 @@ def load_anima(checkpoint_info, diffusers_load_config=None): diffusers.pipelines.auto_pipeline.AUTO_INPAINT_PIPELINES_MAPPING["anima"] = AnimaInpaintPipeline generic.set_pipeline('Anima', AnimaTextToImagePipeline) - # UNET dropdown (shared.opts.sd_unet) may redirect the transformer to a - # community file that bundles both the transformer and the llm_adapter. - transformer, llm_adapter = init_transformer_component(repo_id, diffusers_load_config, modeling_llm_adapter.AnimaLLMAdapter) + # UNET dropdown or single-file checkpoint may bundle transformer and llm_adapter + transformer, llm_adapter = init_transformer_component(repo_id, diffusers_load_config, modeling_llm_adapter.AnimaLLMAdapter, local_file=local_file) if transformer is None: return None text_encoder = generic.load_text_encoder( diff --git a/pipelines/model_google.py b/pipelines/model_google.py index 7048cc365..b19163962 100644 --- a/pipelines/model_google.py +++ b/pipelines/model_google.py @@ -27,7 +27,7 @@ aspect_ratios_buckets = { def google_requirements(): from installer import install # , reload - install('google-genai==1.52.0') + install('google-genai==2.22.0') def get_size_buckets(width: int, height: int) -> tuple[str, str]: diff --git a/pipelines/model_lens.py b/pipelines/model_lens.py index 57f764976..98a17789c 100644 --- a/pipelines/model_lens.py +++ b/pipelines/model_lens.py @@ -12,9 +12,9 @@ def load_lens(checkpoint_info, diffusers_load_config=None): sd_models.hf_auth_check(checkpoint_info) from pipelines import lens - load_args, _quant_args = model_quant.get_dit_args(diffusers_load_config, allow_quant=False) log.debug(f'Load model: type=Lens repo="{repo_id}" config={diffusers_load_config} offload={shared.opts.diffusers_offload_mode} dtype={devices.dtype} reasoner={shared.opts.model_lens_enable_pe} args={load_args}') + generic.set_pipeline('Lens', diffusers.Krea2Pipeline) if repo_id is None or repo_id.lower() == 'none': return None @@ -27,7 +27,6 @@ def load_lens(checkpoint_info, diffusers_load_config=None): diffusers.pipelines.auto_pipeline.AUTO_TEXT2IMAGE_PIPELINES_MAPPING["lens"] = lens.LensPipeline diffusers.pipelines.auto_pipeline.AUTO_IMAGE2IMAGE_PIPELINES_MAPPING["lens"] = lens.LensImg2ImgPipeline diffusers.pipelines.auto_pipeline.AUTO_INPAINT_PIPELINES_MAPPING["lens"] = lens.LensInpaintPipeline - generic.set_pipeline('Lens', lens.LensPipeline) pipe = lens.LensPipeline.from_pretrained( repo_id, transformer=transformer, diff --git a/pipelines/model_llada.py b/pipelines/model_llada.py new file mode 100644 index 000000000..4a0f65f60 --- /dev/null +++ b/pipelines/model_llada.py @@ -0,0 +1,93 @@ +import diffusers +from modules import shared, devices, sd_models, sd_hijack_te, sd_hijack_vae +from modules.logger import log +from pipelines import generic + + +def load_llada_image(checkpoint_info, diffusers_load_config=None): + if diffusers_load_config is None: + diffusers_load_config = {} + repo_id = sd_models.path_to_repo(checkpoint_info) + sd_models.hf_auth_check(checkpoint_info) + log.debug(f'Load model: type=LLaDAImage repo="{repo_id}" config={diffusers_load_config} offload={shared.opts.diffusers_offload_mode} dtype={devices.dtype}') + + from pipelines.llada import LLaDAImagePipeline + from pipelines.llada.transformer_llada_image import LLaDAImageTransformer2DModel + from pipelines.llada.modeling_llada2uni_moe import LLaDA2MoeModelLM + + generic.set_pipeline('LLaDAImage', LLaDAImagePipeline) + if repo_id is None or repo_id.lower() == 'none': + return None + + sdnq_quantize_weights_mode = None + sdnq_quantize_weights_mode_te = None + sdnq_quantize_matmul_mode_te = None + if 'Model' in shared.opts.sdnq_quantize_weights: + if any(x in shared.opts.sdnq_quantize_weights_mode for x in ['2', '3', '4', '5', '6']): + sdnq_quantize_weights_mode = shared.opts.sdnq_quantize_weights_mode + shared.opts.sdnq_quantize_weights_mode = 'uint8' + log.warning('LLaDAImage: cls=LLaDAImageTransformer2DModel quant=uint8 override') + if 'TE' in shared.opts.sdnq_quantize_weights: + if any(x in shared.opts.sdnq_quantize_weights_mode_te for x in ['2', '3', '4', '5', '6']): + sdnq_quantize_weights_mode_te = shared.opts.sdnq_quantize_weights_mode_te + shared.opts.sdnq_quantize_weights_mode_te = 'uint8' + log.warning('LLaDAImage: cls=LLaDA2MoeModelLM quant=uint8 override') + if shared.opts.sdnq_quantize_matmul_mode_te != 'disabled': + sdnq_quantize_matmul_mode_te = shared.opts.sdnq_quantize_matmul_mode_te + shared.opts.sdnq_quantize_matmul_mode_te = 'disabled' + log.warning('LLaDAImage: cls=LLaDA2MoeModelLM matmul=disabled override') + + transformer = generic.load_transformer( + repo_id, + cls_name=LLaDAImageTransformer2DModel, + load_config=diffusers_load_config, + modules_to_not_convert=[ + 'all_x_embedder', + 'all_final_layer', + 't_embedder', + 'cap_embedder', + 'semantic_embedder', + 'sigvq_embedder', + ], + ) + text_encoder = generic.load_text_encoder( + repo_id, + cls_name=LLaDA2MoeModelLM, + load_config=diffusers_load_config, + allow_shared=False, + trust_remote_code=True, + modules_to_not_convert=[ + '.model.language_model.word_embeddings', + '.model.language_model.norm', + '.model.lm_head', + ], + ) + + diffusers.pipelines.auto_pipeline.AUTO_TEXT2IMAGE_PIPELINES_MAPPING['llada-image'] = LLaDAImagePipeline + diffusers.pipelines.auto_pipeline.AUTO_IMAGE2IMAGE_PIPELINES_MAPPING['llada-image'] = LLaDAImagePipeline + + pipe = LLaDAImagePipeline.from_pretrained( + repo_id, + cache_dir=shared.opts.diffusers_dir, + torch_dtype=devices.dtype, + transformer=transformer, + text_encoder=text_encoder, + ) + pipe.task_args = { + 'output_type': 'np', + } + # generation_mode = "text", "vq", "editing" + + # restore settings post-load + if sdnq_quantize_weights_mode is not None: + shared.opts.sdnq_quantize_weights_mode = sdnq_quantize_weights_mode + if sdnq_quantize_weights_mode_te is not None: + shared.opts.sdnq_quantize_weights_mode_te = sdnq_quantize_weights_mode_te + if sdnq_quantize_matmul_mode_te is not None: + shared.opts.sdnq_quantize_matmul_mode_te = sdnq_quantize_matmul_mode_te + + del transformer, text_encoder + sd_hijack_te.init_hijack(pipe) + sd_hijack_vae.init_hijack(pipe) + devices.torch_gc(force=True, reason='load') + return pipe diff --git a/pipelines/model_minimax.py b/pipelines/model_minimax.py index 8a60a774f..720d0313c 100644 --- a/pipelines/model_minimax.py +++ b/pipelines/model_minimax.py @@ -15,6 +15,14 @@ def load_minimax(checkpoint_info, diffusers_load_config = None, workflow: str | workflow = (workflow or getattr(checkpoint_info, 'subfolder', None) or 'fl2va').lower() # one repo holds both checkpoint partitions; reference entries select ref2va via the subfolder tag log.debug(f'Load model: type=MiniMaxH3 repo="{repo_id}" workflow={workflow} offload={shared.opts.diffusers_offload_mode} dtype={devices.dtype}') + loaded = {} + if 'nunchaku-lite' in repo_id.lower(): + from pipelines.minimax.minimax_nunchaku import load_nunchaku + transformer = load_nunchaku(repo_id, load_config=diffusers_load_config) + if transformer is not None: + loaded['transformer'] = transformer + repo_id = 'OzzyGT/MiniMax_H3_sdnq_dynamic_4bit' # nunchaku repo does not contain non-transformer modules + sd_models.warn_group_offload(min_vram=20) repo_cls = diffusers.MiniMaxH3ModularPipeline pipe = load_modular_pipe( @@ -24,6 +32,7 @@ def load_minimax(checkpoint_info, diffusers_load_config = None, workflow: str | offline_args=offline_args, base=True, load_config=diffusers_load_config, + loaded=loaded, ) if pipe is None: return None @@ -34,10 +43,13 @@ def load_minimax(checkpoint_info, diffusers_load_config = None, workflow: str | pipe.sdnext_supported_min_frames = int(pipe.min_duration * pipe.fps) # fresh pipes report the true floor; still mode gates per instance video_load.loaded_model = None # image-path load invalidates the video tab's name cache - # if hasattr(pipe, 'vae'): - # pipe.vae = pipe.vae.to(torch.float16) # minimax loads vae in float32 + if hasattr(pipe, 'vae'): + import torch + pipe.vae = pipe.vae.to(torch.float16) # minimax loads vae in float32 if hasattr(pipe, 'vae') and hasattr(pipe.vae, 'enable_tiling'): pipe.vae.enable_tiling() + from pipelines.minimax.minimax_latents import unpack_latents + pipe.custom_unpack_latents = unpack_latents # add a helper to unpack the video latents from the block state devices.torch_gc() return pipe diff --git a/pipelines/native_transformer.py b/pipelines/native_transformer.py index fc844bf5e..b282f92e4 100644 --- a/pipelines/native_transformer.py +++ b/pipelines/native_transformer.py @@ -28,9 +28,10 @@ Algorithm: in a Cosmos 2.0 loader). 5. Partition off sibling component keys (e.g. Anima's bundled ``llm_adapter.*``). 6. Run the spec's converter if present (else pass through unchanged). -7. Fetch ``/config.json`` from the base repo, instantiate via - ``cls.from_config``, ``load_state_dict(strict=False)``, validate, dtype-cast, - quantize, and offload-place. +7. Fetch ``/config.json`` from the base repo, apply the spec's + ``infer_config`` overrides, instantiate via ``cls.from_config``, + ``load_state_dict(strict=False)``, validate, dtype-cast, quantize, and + offload-place. 8. Repeat the build for each populated sibling (no converter, no quant by default; sibling weights are read raw from the bundled file). @@ -44,7 +45,7 @@ import os import json import time from dataclasses import dataclass, field -from typing import Callable +from typing import Callable, cast import huggingface_hub as hf import torch @@ -134,6 +135,11 @@ class TransformerSpec: ``converter_handles_quant`` runs the converter before comfy_quant detection; such converters must translate marker/scale sidecar keys along with the weights. Float-oriented converters keep the default. + + ``infer_config`` receives the transformer state dict after prefix strip and + sibling partition, before the converter, and returns config overrides + merged over the base repo config (e.g. ``num_layers`` of a depth-expanded + finetune). """ cls: type @@ -146,6 +152,7 @@ class TransformerSpec: acceptable_missing: tuple[str, ...] = DEFAULT_ACCEPTABLE_MISSING zero_init_missing: tuple[str, ...] = () forbidden_markers: tuple[tuple[str, str], ...] = () + infer_config: Callable[[dict], dict] | None = None def make_default_spec(cls: type) -> TransformerSpec: @@ -178,7 +185,7 @@ def auto_pickup_converter(cls: type) -> Callable[[dict], dict] | None: fn = entry.get("checkpoint_mapping_fn") if fn is None or is_noop_converter(fn): return None - return fn + return cast('Callable[[dict], dict]', fn) # diffusers' mapping fns vary in signature (extra kwargs/config), all compatible at call sites def is_noop_converter(fn: Callable) -> bool: @@ -296,6 +303,12 @@ def load( effective_dtype = dtype if dtype is not None else devices.dtype transformer_cfg = fetch_component_config(repo_id, spec.subfolder) + if spec.infer_config is not None: + inferred = spec.infer_config(transformer_sd) + overrides = {k: v for k, v in inferred.items() if transformer_cfg.get(k) != v} + if overrides: + log.info(f'Load model: type={spec.cls.__name__} native_transformer config={overrides}') + transformer_cfg = {**transformer_cfg, **overrides} transformer = build_component( component_name="transformer", state_dict=transformer_sd, @@ -684,8 +697,9 @@ def partition_siblings( def fetch_component_config(repo_id: str, subfolder: str) -> dict: """Download and parse ``/config.json`` from the base repo.""" relative_path = f"{subfolder}/config.json" + offline_args = {'local_files_only': True} if shared.opts.offline_mode else {} try: - local = hf.hf_hub_download(repo_id, filename=relative_path, cache_dir=shared.opts.diffusers_dir) + local = hf.hf_hub_download(repo_id, filename=relative_path, cache_dir=shared.opts.diffusers_dir, **offline_args) except Exception as e: log.error(f' path="{relative_path}" repo="{repo_id}" failed to download: {e}') raise RuntimeError('') from e diff --git a/pipelines/z_image/zimage_lora.py b/pipelines/z_image/zimage_lora.py index e8c6d7ec4..534a09551 100644 --- a/pipelines/z_image/zimage_lora.py +++ b/pipelines/z_image/zimage_lora.py @@ -40,7 +40,6 @@ from modules.lora.native_adapter import ChunkSpec KNOWN_PREFIXES = native_adapter.KNOWN_PREFIXES_DEFAULT -BARE_DIFFUSERS_PREFIXES = ("layers.", "noise_refiner.", "context_refiner.") # Checkpoint qk-norm names vs the diffusers attention module names. ZIMAGE_NORM_ALIASES = { @@ -109,7 +108,6 @@ def parse_key(key, suffixes): return native_adapter.parse_key( key, suffixes, prefixes=KNOWN_PREFIXES, - bare_diffusers_prefixes=BARE_DIFFUSERS_PREFIXES, ) @@ -118,7 +116,6 @@ def group_by_suffixes(state_dict, suffixes): return native_adapter.group_by_suffixes( state_dict, suffixes, prefixes=KNOWN_PREFIXES, - bare_diffusers_prefixes=BARE_DIFFUSERS_PREFIXES, ) @@ -199,7 +196,6 @@ def _underscore_to_diffusers_targets(base): _BIND_KWARGS = dict( resolve_targets=resolve_targets, prefixes=KNOWN_PREFIXES, - bare_diffusers_prefixes=BARE_DIFFUSERS_PREFIXES, arch_name="zimage", ) diff --git a/pyproject.toml b/pyproject.toml index eb2da6328..dac6feae9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -113,7 +113,6 @@ main.ignore-paths=[ "modules/flash_attn_triton_amd", "modules/ggml", "modules/hidiffusion", - "modules/hijack/ddpm_edit.py", "modules/intel", "modules/intel/ipex", "modules/framepack/pipeline", @@ -136,6 +135,7 @@ main.ignore-paths=[ "pipelines/flex2", "pipelines/hdm", "pipelines/hidream", + "pipelines/llada", "pipelines/lumina_dimmo", "pipelines/mageflow", "pipelines/meissonic", @@ -149,7 +149,6 @@ main.ignore-paths=[ "scripts/consistory", "scripts/ctrlx", "scripts/daam", - "scripts/demofusion", "scripts/differential_diffusion.py", "scripts/freescale", "scripts/infiniteyou", @@ -159,16 +158,18 @@ main.ignore-paths=[ "scripts/mod", "scripts/pixelsmith", "scripts/pulid", - "scripts/xadapter", "extensions-builtin/sd-extension-chainner/nodes", "extensions-builtin/sdnq", ] main.ignore-patterns=[ + "/usr/lib/.*", ".*test*.py$", ".*_model.py$", ".*_arch.py$", ".*_model_arch.py*", ".*_model_arch_v2.py$", + ".*\\.pyi$", + ".*/site-packages/.*", ] main.ignored-modules="" main.jobs=4 @@ -351,7 +352,7 @@ variables.init-import=false variables.redefining-builtins-modules=["six.moves","past.builtins","future.builtins","builtins","io"] [tool.pyright] -pythonVersion = "3.10" +pythonVersion = "3.11" pythonPlatform = "All" typeCheckingMode = "off" venvPath = "./venv" @@ -382,9 +383,10 @@ python-version = "3.10" [tool.ty.src] include = [ "*.py", + "modules/*.py", + "pipelines/*.py", + "scripts/*.py", "modules/**/*.py", - "pipelines/**/*.py", - "scripts/**/*.py", "extensions-builtin/**/*.py" ] exclude = [ @@ -410,8 +412,8 @@ exclude = [ "modules/teacache", "modules/face/*.py", "modules/sub_quadratic_attention.py", - "pipelines/**/*.py", - "scripts/**/*.py", + "pipelines/*/**/*.py", + "scripts/*/**/*.py", ] [tool.ty.rules] diff --git a/requirements.txt b/requirements.txt index 0e99da630..5d69f2256 100644 --- a/requirements.txt +++ b/requirements.txt @@ -14,7 +14,6 @@ psutil pyyaml toml voluptuous -fasteners limits orjson ftfy @@ -26,21 +25,20 @@ fastapi==0.124.4 uvicorn==0.52.4 rich==15.0.0 safetensors==0.8.0 -peft==0.20.0 +peft==0.21.0 httpx==0.28.1 requests==2.34.2 -tqdm==4.70.0 -accelerate==1.14.0 +tqdm==4.70.1 +accelerate==1.15.0 einops==0.8.2 -huggingface_hub==1.28.0 +huggingface_hub==1.31.0 hf_xet==1.6.0 -numpy==2.1.2 pandas==2.3.1 -protobuf==7.36.0 -pytorch_lightning==2.6.5 +protobuf==7.36.1 +pytorch_lightning==2.6.6 urllib3==1.26.19 Pillow==12.2.0 -timm==1.0.28 +timm==1.0.29 pyparsing==3.3.2 typing-extensions==4.16.0 sentencepiece==0.2.1 diff --git a/scripts/autocomplete.py b/scripts/autocomplete.py index cea4dd92a..8cdc29b19 100644 --- a/scripts/autocomplete.py +++ b/scripts/autocomplete.py @@ -152,13 +152,13 @@ def on_update(selected): class AutocompleteScript(scripts_manager.Script): video_capable = scripts_manager.AlwaysVisible - def show(self, is_img2img): + def show(self, is_img2img): # pylint: disable=unused-argument return scripts_manager.AlwaysVisible def title(self): return "Tag Autocomplete" - def ui(self, is_img2img): + def ui(self, is_img2img): # pylint: disable=unused-argument initial_names = get_all_names() initial_enabled = list(shared.opts.data.get('autocomplete_enabled', [])) diff --git a/scripts/demofusion.py b/scripts/demofusion.py index 534dbd4fa..b0f686ea3 100644 --- a/scripts/demofusion.py +++ b/scripts/demofusion.py @@ -146,7 +146,7 @@ class DemoFusionSDXLPipeline(DiffusionPipeline, FromSingleFileMixin, LoraLoaderM # textual inversion: procecss multi-vector tokens if necessary prompt_embeds_list = [] prompts = [prompt, prompt_2] - for prompt, tokenizer, text_encoder in zip(prompts, tokenizers, text_encoders): + for prompt, tokenizer, text_encoder in zip(prompts, tokenizers, text_encoders): # pylint: disable=redefined-argument-from-local if isinstance(self, TextualInversionLoaderMixin): prompt = self.maybe_convert_prompt(prompt, tokenizer) @@ -207,7 +207,7 @@ class DemoFusionSDXLPipeline(DiffusionPipeline, FromSingleFileMixin, LoraLoaderM uncond_tokens = [negative_prompt, negative_prompt_2] negative_prompt_embeds_list = [] - for negative_prompt, tokenizer, text_encoder in zip(uncond_tokens, tokenizers, text_encoders): + for negative_prompt, tokenizer, text_encoder in zip(uncond_tokens, tokenizers, text_encoders): # pylint: disable=redefined-argument-from-local if isinstance(self, TextualInversionLoaderMixin): negative_prompt = self.maybe_convert_prompt(negative_prompt, tokenizer) @@ -348,7 +348,7 @@ class DemoFusionSDXLPipeline(DiffusionPipeline, FromSingleFileMixin, LoraLoaderM # DemoFusion specific checks if max(height, width) % 1024 != 0: log.error(f'DemoFusion: resolution={width}x{height} long side must be divisible by 1024') - return None + return if num_images_per_prompt != 1: log.warning('DemoFusion: number of images per prompt is not support and will be ignored') diff --git a/scripts/differential_diffusion.py b/scripts/differential_diffusion.py index 11eb177af..b5bc5cb1a 100644 --- a/scripts/differential_diffusion.py +++ b/scripts/differential_diffusion.py @@ -869,7 +869,7 @@ class StableDiffusionXLDiffImg2ImgPipeline(DiffusionPipeline, FromSingleFileMixi total_time_steps = num_inference_steps #end diff diff change timesteps, num_inference_steps = self.get_timesteps( - num_inference_steps, strength, device, denoising_start=denoising_start if denoising_value_valid else None # pylint: disable=missing-parentheses-for-call-in-test, using-constant-test + num_inference_steps, strength, device, denoising_start=denoising_start if denoising_value_valid(denoising_start) else None ) latent_timestep = timesteps[:1].repeat(batch_size * num_images_per_prompt) diff --git a/scripts/dlss/__init__.py b/scripts/dlss/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/scripts/dlss/controller_cli.py b/scripts/dlss/controller_cli.py new file mode 100644 index 000000000..368c664a7 --- /dev/null +++ b/scripts/dlss/controller_cli.py @@ -0,0 +1,229 @@ +import os +import json +import shutil +import base64 +import select +import threading +import subprocess +import time +import uuid +import numpy as np +from PIL import Image +from modules.logger import log +from modules.errors import display + + +debug = os.environ.get('SD_DLSS_DEBUG', None) is not None + + +def image_to_nchw(image: Image.Image) -> np.ndarray: + arr = np.array(image.convert('RGB'), dtype=np.uint8) # HWC + return np.ascontiguousarray(arr.transpose(2, 0, 1))[np.newaxis, ...] # 1CHW + + +def images_to_nchw(images: list) -> np.ndarray: + # last image is reference, skip all images that do not have same dimensions as the last image + if len(images) > 1: + ref_size = images[-1].size + images = [image for image in images if image.size == ref_size] + return np.concatenate([image_to_nchw(image) for image in images], axis=0) + + +def nchw_to_images(arr) -> list: + arr = np.asarray(arr) + return [Image.fromarray(arr[i].transpose(1, 2, 0), 'RGB') for i in range(arr.shape[0])] + + +def _encode_value(value): + if isinstance(value, np.ndarray): + arr = np.ascontiguousarray(value) + return { '__ndarray__': True, 'dtype': str(arr.dtype), 'shape': list(arr.shape), 'data': base64.b64encode(arr.tobytes()).decode('ascii') } + return value + + +def _decode_value(value): + if isinstance(value, dict) and value.get('__ndarray__'): + data = base64.b64decode(value['data']) + return np.frombuffer(data, dtype=value['dtype']).reshape(value['shape']) + if isinstance(value, dict): + return { k: _decode_value(v) for k, v in value.items() } + if isinstance(value, list): + return [_decode_value(v) for v in value] + return value + + +class DLSSController: + """Persistent stdio bridge to the DLSS package's long-lived controller worker (app/controller.py).""" + + def __init__(self): + self.process: subprocess.Popen | None = None + self.pkg_path: str | None = None + self.lock = threading.Lock() + + def get_python(self, pkg_path: str): + python_exe = os.path.join(pkg_path, 'bin', 'python-3.13.15-embed-amd64', 'python.exe') + if not os.path.exists(python_exe): + log.error(f'DLSS: path={pkg_path} python={python_exe} not found') + return None + return python_exe + + def is_alive(self) -> bool: + return self.process is not None and self.process.poll() is None + + def stop(self): + process = self.process + self.process = None + if process is None: + return + try: + if process.poll() is None and process.stdin is not None: + line = json.dumps({ 'request_id': str(uuid.uuid4()), 'command': 'shutdown', 'args': [], 'kwargs': {} }) + '\n' + process.stdin.write(line.encode('utf-8')) + process.stdin.flush() + except Exception: + pass + try: + if process.poll() is None: + process.terminate() + process.wait(timeout=5.0) + except Exception: + pass + + def ensure_installed(self, pkg_path: str) -> bool: + if self.is_alive() and self.pkg_path == pkg_path: + return True + self.stop() + python_exe = self.get_python(pkg_path) + if not python_exe: + return False + # create _sdnext directory if it doesn't exist + sdnext_path = os.path.join(pkg_path, '_sdnext') + if not os.path.exists(sdnext_path): + if debug: + log.trace(f'DLSS install: create folder="{sdnext_path}"') + try: + os.makedirs(sdnext_path, exist_ok=True) + except Exception as e: + log.error(f'DLSS install: failed to create folder: {e}') + display(e, 'DLSS') + return False + files_to_copy = ['__init__.py', 'controller_srv.py', 'utils.py', 'verify.py', 'render.py', 'supersample.py', 'framegen.py'] + for file_name in files_to_copy: + # src path is current path of this file + src = os.path.join(os.path.dirname(__file__), file_name) + dst = os.path.join(sdnext_path, file_name) + # not exist or newer + if not os.path.exists(dst) or os.path.getmtime(src) > os.path.getmtime(dst): + if debug: + log.trace(f'DLSS install: copy src="{src}" "{dst}"') + try: + shutil.copy2(src, dst) + except Exception as e: + log.error(f'DLSS install: failed to copy {file_name}: {e}') + display(e, 'DLSS') + return False + return True + + def ensure_started(self, pkg_path: str) -> bool: + if self.is_alive() and self.pkg_path == pkg_path: + return True + self.stop() + python_exe = self.get_python(pkg_path) + if not python_exe: + return False + env = { + 'GRADIO_ANALYTICS_ENABLED': 'False', + 'PYTHONNOUSERSITE': '1', + 'PYTHONIOENCODING': 'utf-8' + } + if debug: + env['SD_DLSS_DEBUG'] = 'True' + log.trace(f'DLSS controller start: env={env}') + try: + self.process = subprocess.Popen( # pylint: disable=consider-using-with + [python_exe, '-m', '_sdnext.controller_srv'], + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + cwd=pkg_path, + env=env, + bufsize=0, + ) + except Exception as e: + log.error(f'DLSS controller start: {e}') + display(e, 'DLSS') + self.process = None + return False + self.pkg_path = pkg_path + response = self._send({ 'request_id': str(uuid.uuid4()), 'command': 'status', 'args': [], 'kwargs': {} }, timeout=30.0) + if response is None or response.get('status') != 'ok': + log.error(f'DLSS controller start: response={response}') + self.stop() + return False + if debug: + log.trace(f'DLSS controller start: result={response.get("result")}') + return True + + def _send(self, request: dict, timeout: float = 300.0): + process = self.process + if process is None or process.stdin is None or process.stdout is None: + return None + try: + process.stdin.write((json.dumps(request) + '\n').encode('utf-8')) + process.stdin.flush() + except Exception as e: + log.error(f'DLSS: failed to send request: {e}') + display(e, 'DLSS') + self.process = None + return None + deadline = time.time() + timeout + while True: + remaining = deadline - time.time() + if remaining <= 0: + log.error(f'DLSS controller: timeout={timeout}') + return None + try: + ready, _, _ = select.select([process.stdout], [], [], remaining) + except Exception: + ready = [process.stdout] # select() is not supported on pipes on some platforms: fall back to a blocking read + if not ready: + log.error(f'DLSS controller: timeout={timeout}') + return None + try: + raw = process.stdout.readline() + except Exception as e: + log.error(f'DLSS controller read: {e}') + display(e, 'DLSS') + self.process = None + return None + if not raw: + stderr = process.stderr.read().decode('utf-8', errors='ignore') if process.stderr else '' + log.error(f'DLSS controller process: stderr="{stderr.strip()}"') + self.process = None + return None + try: + return json.loads(raw.decode('utf-8')) + except Exception: + if debug: + log.trace(f'DLSS controller stray output: {raw!r}') + continue # skip any non-JSON noise emitted before the JSON response line + + def call(self, pkg_path: str, command: str, kwargs: dict, timeout: float = 600.0) -> dict: + with self.lock: + if not self.ensure_installed(pkg_path): + return { 'status': 'error', 'result': None, 'error': { 'code': 'not_installed', 'message': 'controller is not installed' } } + if not self.ensure_started(pkg_path): + return { 'status': 'error', 'result': None, 'error': { 'code': 'not_ready', 'message': 'controller failed to start' } } + encoded_kwargs = { key: _encode_value(value) for key, value in kwargs.items() } + request = { 'request_id': str(uuid.uuid4()), 'command': command, 'args': [], 'kwargs': encoded_kwargs } + if debug: + log.trace(f'DLSS controller request: command={command} timeout={timeout}') + response = self._send(request, timeout=timeout) + if response is None: + return { 'status': 'error', 'result': None, 'error': { 'code': 'not_ready', 'message': 'controller is not responding' } } + if isinstance(response.get('result'), (dict, list)): + response['result'] = _decode_value(response['result']) + return response + + +controller = DLSSController() diff --git a/scripts/dlss/controller_srv.py b/scripts/dlss/controller_srv.py new file mode 100644 index 000000000..fc920030c --- /dev/null +++ b/scripts/dlss/controller_srv.py @@ -0,0 +1,400 @@ +from __future__ import annotations + +import sys +from pathlib import Path + +_ROOT = Path(__file__).resolve().parents[1] +if str(_ROOT) not in sys.path: + sys.path.insert(0, str(_ROOT)) + +# when launched directly as the stdio bridge subprocess, keep the real stdout clean of stray +# prints from native imports/libraries below so only explicit JSON response lines reach the pipe +_stdio_stdout = None +if __name__ == "__main__": + _stdio_stdout = sys.stdout + sys.stdout = sys.stderr + +import base64 +import ctypes +import dataclasses +import json +import multiprocessing as mp +import os +import threading +import uuid +from queue import Empty +from typing import Any + +import numpy as np + +from .utils import StandaloneError, log +from .framegen import DLSSFrameGen, InterpolationOptions +from .render import DLSSNeuralRenderer, RenderOptions +from .supersample import DLSSSuperSample, UpscaleOptions +from .verify import DLSSVerify, VerifyOptions + +_SUPPORTED_COMMANDS = { + "status", + "verify", + "render", + "upscale", + "framegen", + "cancel", + "reset", + "shutdown", +} + + +def _response(request_id: str, *, status: str, result: Any = None, error: dict[str, str] | None = None, diagnostics: dict[str, Any] | None = None) -> dict[str, Any]: + return { + "request_id": request_id, + "status": status, + "result": result, + "error": error, + "diagnostics": diagnostics or {}, + } + + +def _coerce_options(options: Any, *, default: Any, option_type: type[Any]) -> Any: + if options is None: + return default + if isinstance(options, option_type): + return options + if isinstance(options, dict): + return option_type(**options) + raise TypeError(f"Expected {option_type.__name__} or dict, got {type(options).__name__}") + + +def _set_shared_text(buffer: Any, value: str) -> None: + with buffer.get_lock(): + for index in range(len(buffer)): + buffer[index] = "\0" + for index, character in enumerate(value[: len(buffer) - 1]): + buffer[index] = character + + +def _get_shared_text(buffer: Any) -> str: + with buffer.get_lock(): + return "".join(buffer).split("\0", 1)[0] + + +def _dispatch_command(command: str, request_id: str, args: tuple[Any, ...], kwargs: dict[str, Any], *, busy: Any = None, current_request_id: Any = None, current_command: Any = None) -> dict[str, Any]: # pylint: disable=unused-argument + log.debug(f'DLSSController dispatch: command={command} id={request_id}') + if command == "status": + is_busy = bool(busy.value) if busy is not None else False + active_request_id = _get_shared_text(current_request_id) if current_request_id is not None else "" + active_command = _get_shared_text(current_command) if current_command is not None else "" + return _response( + request_id, + status="ok", + result={ + "ready": True, + "busy": is_busy, + "pid": os.getpid(), + "id": active_request_id if is_busy else "", + "job": active_command if is_busy else "idle", + }, + diagnostics={"controller": "ready"}, + ) + + if command == "reset": + return _response(request_id, status="ok", result={"reset": True}, diagnostics={"controller": "reset"}) + + if command == "cancel": + target_id = str(kwargs.get("request_id") or "") + return _response(request_id, status="ok", result={"cancelled": bool(target_id), "target_request_id": target_id}, diagnostics={"controller": "cancelled"}) + + if command == "verify": + gpu_uuid = str(kwargs.get("gpu_uuid", "auto")) + options = _coerce_options(kwargs.get("options"), default=VerifyOptions(), option_type=VerifyOptions) + result = DLSSVerify()(gpu_uuid, options) + return _response(request_id, status="ok", result={"ok": result.ok, "report": result.to_dict()}, diagnostics={"gpu": result.gpu or {}}) + + if command == "render": + images = kwargs.get("images") + if images is None: + raise StandaloneError("invalid_arguments", "NeuralRender: missing required images") + options = _coerce_options(kwargs.get("options"), default=RenderOptions(), option_type=RenderOptions) + result = DLSSNeuralRenderer()(np.asarray(images), options) + return _response(request_id, status="ok", result=result, diagnostics={"shape": list(result.shape)}) + + if command == "upscale": + images = kwargs.get("images") + if images is None: + raise StandaloneError("invalid_arguments", "SuperSample: missing required images") + options = _coerce_options(kwargs.get("options"), default=UpscaleOptions(), option_type=UpscaleOptions) + result = DLSSSuperSample()(np.asarray(images), options) + return _response(request_id, status="ok", result=result, diagnostics={"shape": list(result.shape)}) + + if command == "framegen": + frames = kwargs.get("frames") + if frames is None: + raise StandaloneError("invalid_arguments", "FrameGen: missing required frames") + source_fps = kwargs.get("source_fps") + target_fps = kwargs.get("target_fps") + if source_fps is None or target_fps is None: + raise StandaloneError("invalid_arguments", "FrameGen: missing source/target FPS") + options = _coerce_options(kwargs.get("options"), default=InterpolationOptions(), option_type=InterpolationOptions) + result = DLSSFrameGen()(np.asarray(frames), source_fps, target_fps, options) + return _response(request_id, status="ok", result=result, diagnostics={"shape": list(result.shape)}) + + raise StandaloneError("invalid_arguments", f"Controller: unsupported command: {command!r}") + + +def _controller_worker(request_queue: mp.Queue, response_queue: mp.Queue, busy: Any, current_request_id: Any, current_command: Any) -> None: + worker_lock = threading.Lock() + while True: + try: + request = request_queue.get(timeout=0.25) + except Empty: + continue + + if not isinstance(request, dict): + response_queue.put(_response(str(uuid.uuid4()), status="error", error={"code": "invalid_arguments", "message": "Controller request must be a dict."})) + continue + + request_id = str(request.get("request_id") or uuid.uuid4()) + command = str(request.get("command") or "").strip().lower() + args = tuple(request.get("args", ())) + kwargs = dict(request.get("kwargs", {})) + + if command == "shutdown": + log.debug(f'DLSSController shutdown: id={request_id}') + response_queue.put(_response(request_id, status="ok", result={"shutdown": True}, diagnostics={"controller": "shutdown"})) + return + + if command not in _SUPPORTED_COMMANDS: + log.warning(f'DLSSController: command={command} id={request_id} unsupported') + response_queue.put(_response(request_id, status="error", error={"code": "invalid_arguments", "message": f"Unsupported command: {command!r}"}, diagnostics={"controller": "invalid_command"})) + continue + + try: + if command != "status": + busy.value = True + _set_shared_text(current_request_id, request_id) + _set_shared_text(current_command, command) + with worker_lock: + response = _dispatch_command(command, request_id, args, kwargs, busy=busy, current_request_id=current_request_id, current_command=current_command) + response_queue.put(response) + except StandaloneError as exc: + log.error(f'DLSSController: StandaloneError command={command} id={request_id} code={exc.code} message={exc.message}') + response_queue.put(_response(request_id, status="error", error={"code": exc.code, "message": exc.message}, diagnostics={"controller": "error"})) + except Exception as exc: # pragma: no cover - defensive catch for controller safety + log.error(f'DLSSController: unexpected exception command={command} id={request_id} error={exc}') + response_queue.put(_response(request_id, status="error", error={"code": "processing_failed", "message": str(exc)}, diagnostics={"controller": "error"})) + finally: + if command != "status": + busy.value = False + _set_shared_text(current_request_id, "") + _set_shared_text(current_command, "") + + +class ControllerProcess(mp.Process): + def __init__(self, request_queue: mp.Queue | None = None, response_queue: mp.Queue | None = None, *, busy: Any = None, current_request_id: Any = None, current_command: Any = None, ctx: mp.context.BaseContext | None = None) -> None: + self.ctx = ctx or mp.get_context("spawn") + self.request_queue = request_queue or self.ctx.Queue() + self.response_queue = response_queue or self.ctx.Queue() + self.busy = busy or self.ctx.Value("b", False) + self.current_request_id = current_request_id or self.ctx.Array(ctypes.c_wchar, 256) + self.current_command = current_command or self.ctx.Array(ctypes.c_wchar, 64) + super().__init__(target=_controller_worker, args=(self.request_queue, self.response_queue, self.busy, self.current_request_id, self.current_command)) + + +class ControllerClient: + """Simple client wrapper for callers that want a long-lived controller process.""" + + def __init__(self, request_queue: mp.Queue | None = None, response_queue: mp.Queue | None = None, *, process: ControllerProcess | None = None, timeout: float = 30.0, ctx: mp.context.BaseContext | None = None) -> None: + self.ctx = ctx or mp.get_context("spawn") + self.request_queue = request_queue or self.ctx.Queue() + self.response_queue = response_queue or self.ctx.Queue() + self.timeout = timeout + self.process = process + self.busy = process.busy if process is not None else self.ctx.Value("b", False) + self.current_request_id = process.current_request_id if process is not None else self.ctx.Array(ctypes.c_wchar, 256) + self.current_command = process.current_command if process is not None else self.ctx.Array(ctypes.c_wchar, 64) + self._pending: dict[str, dict[str, Any]] = {} + + def start(self) -> "ControllerClient": + if self.process is None or not self.process.is_alive(): + self.process = ControllerProcess(self.request_queue, self.response_queue, busy=self.busy, current_request_id=self.current_request_id, current_command=self.current_command, ctx=self.ctx) + self.process.start() + log.info(f'DLSSController: pid={self.process.pid} started') + return self + + def _send_and_wait(self, command: str, *args: Any, **kwargs: Any) -> dict[str, Any]: + if self.process is None or not self.process.is_alive(): + self.start() + request_id = str(uuid.uuid4()) + request = {"request_id": request_id, "command": command, "args": list(args), "kwargs": kwargs} + self.request_queue.put(request) + + while True: + try: + response = self.response_queue.get(timeout=self.timeout) + except Empty as exc: + raise TimeoutError(f"Controller request timed out for command {command!r}.") from exc + if response.get("request_id") == request_id: + return response + self._pending[response.get("request_id", str(uuid.uuid4()))] = response + + def status(self) -> dict[str, Any]: + if self.process is None or not self.process.is_alive(): + self.start() + is_busy = bool(self.busy.value) + active_request_id = _get_shared_text(self.current_request_id) + active_command = _get_shared_text(self.current_command) + return _response( + str(uuid.uuid4()), + status="ok", + result={ + "ready": self.process.is_alive(), + "busy": is_busy, + "pid": self.process.pid, + "id": active_request_id if is_busy else "", + "job": active_command if is_busy else "idle", + }, + diagnostics={"controller": "busy" if is_busy else "ready"}, + ) + + def verify(self, *, gpu_uuid: str = "auto", options: VerifyOptions | dict[str, Any] | None = None) -> dict[str, Any]: + return self._send_and_wait("verify", gpu_uuid=gpu_uuid, options=options) + + def render(self, *, images: np.ndarray, options: RenderOptions | dict[str, Any] | None = None) -> dict[str, Any]: + return self._send_and_wait("render", images=images, options=options) + + def upscale(self, *, images: np.ndarray, options: UpscaleOptions | dict[str, Any] | None = None) -> dict[str, Any]: + return self._send_and_wait("upscale", images=images, options=options) + + def framegen(self, *, frames: np.ndarray, source_fps: float | str, target_fps: float | str, options: InterpolationOptions | dict[str, Any] | None = None) -> dict[str, Any]: + return self._send_and_wait("framegen", frames=frames, source_fps=source_fps, target_fps=target_fps, options=options) + + def cancel(self, request_id: str) -> dict[str, Any]: + return self._send_and_wait("cancel", request_id=request_id) + + def reset(self) -> dict[str, Any]: + return self._send_and_wait("reset") + + def shutdown(self) -> dict[str, Any]: + if self.process is None or not self.process.is_alive(): + return {"request_id": "shutdown", "status": "ok", "result": {"shutdown": True}, "error": None, "diagnostics": {}} + response = self._send_and_wait("shutdown") + if self.process.is_alive(): + self.process.join(timeout=10.0) + return response + + def close(self) -> None: + try: + self.shutdown() + except Exception: + pass + if self.process is not None and self.process.is_alive(): + self.process.terminate() + self.process.join(timeout=10.0) + + def __enter__(self) -> "ControllerClient": + return self.start() + + def __exit__(self, exc_type: Any, exc: Any, tb: Any) -> None: + self.close() + + +def start_controller(*, request_queue: mp.Queue | None = None, response_queue: mp.Queue | None = None, timeout: float = 30.0, ctx: mp.context.BaseContext | None = None) -> ControllerClient: + client = ControllerClient(request_queue=request_queue, response_queue=response_queue, timeout=timeout, ctx=ctx) + return client.start() + + +# ---- stdio bridge ----------------------------------------------------------------- +# Used only when this module is launched directly as a subprocess, e.g. +# `python.exe app/controller.py`, to drive the same dispatch logic over a single +# stdin/stdout JSON-lines protocol instead of multiprocessing queues. This allows an +# external caller running a different Python interpreter (for example WSL/Linux Python +# invoking the packaged Windows embedded python.exe) to reuse one long-lived worker. + + +def _stdio_encode(value: Any) -> Any: + if isinstance(value, np.ndarray): + arr = np.ascontiguousarray(value) + return {"__ndarray__": True, "dtype": str(arr.dtype), "shape": list(arr.shape), "data": base64.b64encode(arr.tobytes()).decode("ascii")} + if hasattr(value, "to_dict") and callable(value.to_dict): + return _stdio_encode(value.to_dict()) + if dataclasses.is_dataclass(value) and not isinstance(value, type): + return {k: _stdio_encode(v) for k, v in dataclasses.asdict(value).items()} + if isinstance(value, dict): + return {k: _stdio_encode(v) for k, v in value.items()} + if isinstance(value, (list, tuple)): + return [_stdio_encode(v) for v in value] + return value + + +def _stdio_decode(value: Any) -> Any: + if isinstance(value, dict) and value.get("__ndarray__"): + data = base64.b64decode(value["data"]) + return np.frombuffer(data, dtype=value["dtype"]).reshape(value["shape"]) + if isinstance(value, dict): + return {k: _stdio_decode(v) for k, v in value.items()} + if isinstance(value, list): + return [_stdio_decode(v) for v in value] + return value + + +def _stdio_write(payload: dict[str, Any]) -> None: + _stdio_stdout.write(json.dumps(payload) + "\n") + _stdio_stdout.flush() + + +def _stdio_error(request_id: str, code: str, message: str) -> dict[str, Any]: + return {"request_id": request_id, "status": "error", "result": None, "error": {"code": code, "message": message}, "diagnostics": {}} + + +def _stdio_main() -> None: + # long-lived worker: one JSON request per line on stdin, one JSON response per line on the real stdout + for raw_line in sys.stdin: + line = raw_line.strip() + if not line: + continue + try: + request = json.loads(line) + except json.JSONDecodeError as exc: + _stdio_write(_stdio_error("", "invalid_arguments", f"Malformed request: {exc}")) + continue + + request_id = str(request.get("request_id") or "") + command = str(request.get("command") or "").strip().lower() + args = tuple(request.get("args", ())) + try: + kwargs = _stdio_decode(dict(request.get("kwargs", {}))) + except Exception as exc: + _stdio_write(_stdio_error(request_id, "invalid_arguments", f"Failed to decode request payload: {exc}")) + continue + + if command == "shutdown": + _stdio_write({"request_id": request_id, "status": "ok", "result": {"shutdown": True}, "error": None, "diagnostics": {}}) + return + if command not in _SUPPORTED_COMMANDS: + _stdio_write(_stdio_error(request_id, "invalid_arguments", f"Unsupported command: {command!r}")) + continue + + try: + response = _dispatch_command(command, request_id, args, kwargs) + except StandaloneError as exc: + response = _stdio_error(request_id, exc.code, exc.message) + except Exception as exc: # pragma: no cover - defensive catch for controller safety + response = _stdio_error(request_id, "processing_failed", str(exc)) + _stdio_write(_stdio_encode(response)) + + +if __name__ == "__main__": + _stdio_main() + + def __enter__(self) -> "ControllerClient": + return self.start() + + def __exit__(self, exc_type: Any, exc: Any, tb: Any) -> None: # pylint: disable=unused-argument + self.close() + + +__all__ = [ + "ControllerClient", + "ControllerProcess", + "start_controller", +] diff --git a/scripts/dlss/framegen.py b/scripts/dlss/framegen.py new file mode 100644 index 000000000..4df99f04c --- /dev/null +++ b/scripts/dlss/framegen.py @@ -0,0 +1,207 @@ +from __future__ import annotations + +from dataclasses import dataclass +from fractions import Fraction +from typing import Any + +import numpy as np + +from src.core.jobs import JobController, active_job +from src.frame_interpolation.capabilities import probe_frame_interpolation_capabilities +from src.frame_interpolation.guides import DLSSGGuideGenerator +from src.frame_interpolation.models import ENGINE_CHOICES, resolve_target_rate +from src.frame_interpolation.native import DirectDLSSGSession +from src.frame_interpolation.scheduler import choose_interpolation_plan, output_frame_count + +from .utils import StandaloneError, nchw_image_to_hwc, rgba_to_rgb_nchw, validate_nchw, rgb_to_rgba, log + + +@dataclass(frozen=True, slots=True) +class InterpolationOptions: + ai_gpu_uuid: str = "auto" + engine: str = "Auto" + + def validate(self) -> None: + if self.engine not in ENGINE_CHOICES: + raise ValueError(f"Unknown frame interpolation engine: {self.engine!r}.") + + +@dataclass(frozen=True, slots=True) +class _TimedFrame: + rgba: np.ndarray + timestamp: Fraction + + +class _Stage: + def __init__(self, session: DirectDLSSGSession, width: int, height: int) -> None: + self.session = session + self.guides = DLSSGGuideGenerator(width, height) + self.previous: _TimedFrame | None = None + + def push(self, frame: _TimedFrame) -> list[_TimedFrame]: + previous = self.previous + guide = self.guides.process(frame.rgba, force_reset=previous is not None and frame.timestamp <= previous.timestamp) + self.previous = frame + generated = self.session.process_frame( + frame.rgba, + guide.motion, + frame.timestamp, + reset=previous is None or guide.reset, + ) + result: list[_TimedFrame] = [] + if previous is not None and not guide.reset: + interval = frame.timestamp - previous.timestamp + count = len(generated) + for index, rgba in enumerate(generated, start=1): + result.append(_TimedFrame( + rgba, + previous.timestamp + interval * Fraction(index, count + 1), + )) + result.append(frame) + return result + + +class DLSSFrameGen: + """In-memory RGB NCHW constant-frame-rate DLSS frame interpolation.""" + + def __init__(self) -> None: + log.info('DLSSFrameGen: init') + self.diagnostics: dict[str, Any] = {} + self.last_report: dict[str, Any] = {} + + def __call__( + self, + frames: np.ndarray, + source_fps: str | int | float | Fraction, + target_fps: str | int | float | Fraction, + options: InterpolationOptions | None = None, + *, + controller: JobController | None = None, + ) -> np.ndarray: + log.info('DLSSFrameGen: call') + options = options or InterpolationOptions() + options.validate() + batch, _, height, width = validate_nchw(frames, name="frames") + if width < 64 or height < 64: + raise StandaloneError("invalid_dimensions", "FrameGen: invalid resolution") + source_rate = resolve_target_rate(source_fps) + target_rate = resolve_target_rate(target_fps) + own_controller = controller or JobController() + log.debug(f'DLSSFrameGen: controller={own_controller}') + try: + with active_job(own_controller) as active_controller: + capabilities = probe_frame_interpolation_capabilities(options.ai_gpu_uuid) + log.debug(f'DLSSFrameGen: capabilities={capabilities}') + if not capabilities.available: + raise StandaloneError("feature_unavailable", "FrameGen: unavailable. " + capabilities.detail) + plan = choose_interpolation_plan( + source_rate, + target_rate, + options.engine, + capabilities.native_multiplier, + cfr=True, + ) + log.debug(f'DLSSFrameGen: plan={plan}') + source_frames = [ + _TimedFrame(rgb_to_rgba(nchw_image_to_hwc(frames, index, name="frames")), Fraction(index, 1) / source_rate) + for index in range(batch) + ] + if plan.generated_per_interval == 0: + result = self._resample_source(source_frames, target_rate, source_rate) + else: + result = self._generate(source_frames, plan, active_controller, width, height) + expected = output_frame_count(Fraction(batch, 1) / source_rate, target_rate) + if len(result) != expected: + log.error(f'DLSSFrameGen: result length={len(result)} expected={expected}') + raise StandaloneError("invalid_native_output", f"FrameGen: interpolation produced {len(result)} frames; expected {expected}.") + output = np.stack([rgba_to_rgb_nchw(item.rgba)[0] for item in result], axis=0) + log.debug(f'DLSSFrameGen: output={output.shape}') + self.diagnostics = { + "gpu": capabilities.gpu, + "driver": capabilities.driver, + "runtime_version": capabilities.runtime_version, + "worker_version": capabilities.worker_version, + "selected_path": plan.path, + "native_multiplier": plan.native_multiplier, + "cascade_stages": plan.cascade_stages, + } + except StandaloneError: + raise + except Exception as exc: + log.error(f'DLSSFrameGen: unexpected exception {exc}') + raise StandaloneError("processing_failed", f"FrameGen: failed: {exc}") from exc + self.last_report = { + "input_shape": tuple(frames.shape), + "output_shape": tuple(output.shape), + "source_fps": str(source_rate), + "target_fps": str(target_rate), + } + return np.ascontiguousarray(output) + + @staticmethod + def _resample_source(frames: list[_TimedFrame], target_rate: Fraction, source_rate: Fraction) -> list[_TimedFrame]: + count = output_frame_count(Fraction(len(frames), 1) / source_rate, target_rate) + result: list[_TimedFrame] = [] + for index in range(count): + ideal = Fraction(index, 1) / target_rate + selected = min(frames, key=lambda frame, target=ideal: abs(frame.timestamp - target)) + result.append(_TimedFrame(selected.rgba.copy(), ideal)) + log.debug(f'DLSSFrameGen: input={len(frames)} resampled={len(result)}') + return result + + @staticmethod + def _generate(source_frames, plan, controller, width, height) -> list[_TimedFrame]: + sessions: list[DirectDLSSGSession] = [] + stages: list[_Stage] = [] + try: + stage_count = plan.cascade_stages or 1 + for stage_index in range(stage_count): + log.debug(f'DirectDLSSGSession: index={stage_index + 1} count={stage_count} stage create') + generated_count = ( + plan.generated_per_interval + if plan.path == "Native DLSSG" + else 1 + ) + expected_frames = ( + len(source_frames) + if stage_index == 0 + else max(1, (len(source_frames) - 1) * (1 << stage_index) + 1) + ) + session = DirectDLSSGSession( + width, + height, + expected_frames, + generated_count, + controller, + ) + sessions.append(session) + stages.append(_Stage(session, width, height)) + candidates: list[_TimedFrame] = [] + for source in source_frames: + if controller.cancel.is_set(): + raise StandaloneError("cancelled", "FrameGen: cancelled") + items = [source] + for stage in stages: + next_items: list[_TimedFrame] = [] + for item in items: + next_items.extend(stage.push(item)) + items = next_items + candidates.extend(items) + duration = Fraction(len(source_frames), 1) / plan.source_rate + count = output_frame_count(duration, plan.target_rate) + result: list[_TimedFrame] = [] + for index in range(count): + ideal = Fraction(index, 1) / plan.target_rate + selected = min(candidates, key=lambda frame, target=ideal: abs(frame.timestamp - target)) + result.append(_TimedFrame(selected.rgba.copy(), ideal)) + return result + finally: + for session in reversed(sessions): + log.debug(f'DirectDLSSGSession: session={session} close') + try: + session.close() + except (OSError, RuntimeError, ValueError): + session.abort() + + +__all__ = ["DLSSFrameGen", "InterpolationOptions"] diff --git a/scripts/dlss/render.py b/scripts/dlss/render.py new file mode 100644 index 000000000..faa548a02 --- /dev/null +++ b/scripts/dlss/render.py @@ -0,0 +1,164 @@ +from __future__ import annotations + +from dataclasses import dataclass +from typing import Any + +import numpy as np + +from src.core.jobs import JobController, active_job +from src.core.runtime import ( + DLSSFrameSession, + prepare_runtime, + resolve_native_settings, + resolve_output_size, + resolve_runtime_ai_gpu, + resolve_upscaling_mode, + resize_fit, +) +from src.neural_rendering.image.models import ImageConversionOptions + +from .utils import StandaloneError, nchw_image_to_hwc, rgba_to_rgb_nchw, validate_nchw, rgb_to_rgba, log + + +@dataclass(frozen=True, slots=True) +class RenderOptions: + ai_gpu_uuid: str = "auto" + nr_style: str = "Default" + nr_intensity: float = 1.0 + local_tone_strength: float = 1.0 + local_structure_strength: float = 1.0 + skin_structure_strength: float = -1.0 + upscaling_factor: float = 1.0 + warmup_frames: int = 0 + nr_preset: str = "Default" + automatic_mask: bool = False + dlss_model_preset: str = "Default" + + def source_options(self) -> ImageConversionOptions: + return ImageConversionOptions( + ai_gpu_uuid=self.ai_gpu_uuid, + nr_style=self.nr_style, + nr_intensity=self.nr_intensity, + local_tone_strength=self.local_tone_strength, + local_structure_strength=self.local_structure_strength, + skin_structure_strength=self.skin_structure_strength, + upscaling_factor=self.upscaling_factor, + warmup_frames=self.warmup_frames, + nr_preset=self.nr_preset, + automatic_mask=self.automatic_mask, + dlss_model_preset=self.dlss_model_preset, + ) + + def validate(self) -> None: + if isinstance(self.warmup_frames, bool) or not isinstance(self.warmup_frames, int) or self.warmup_frames < 0: + raise ValueError("warmup_frames must be a non-negative integer.") + if not isinstance(self.automatic_mask, bool): + raise ValueError("automatic_mask must be a boolean.") + options = self.source_options() + resolve_upscaling_mode(options.upscaling_factor) + resolve_native_settings(options) + + +class DLSSNeuralRenderer: + """RGB NCHW adapter for still-image DLSS Neural Rendering.""" + + def __init__(self) -> None: + log.info('DLSSNeuralRenderer: init') + self.diagnostics: dict[str, Any] = {} + self.last_report: dict[str, Any] = {} + + def __call__( + self, + images: np.ndarray, + options: RenderOptions | None = None, + *, + controller: JobController | None = None, + ) -> np.ndarray: + log.info('DLSSNeuralRenderer: call') + options = options or RenderOptions() + options.validate() + batch, _channels, height, width = validate_nchw(images, name="images") + log.debug(f'DLSSNeuralRenderer: input={images.shape}') + if width < 64 or height < 64: + raise StandaloneError("invalid_dimensions", "NeuralRender: invalid resolution") + output_width, output_height = resolve_output_size(width, height, options.upscaling_factor) + own_controller = controller or JobController() + log.debug(f'DLSSNeuralRenderer: controller={own_controller}') + outputs: list[np.ndarray] = [] + try: + with active_job(own_controller) as active_controller: + prepared = prepare_runtime() + log.debug(f'DLSSNeuralRenderer: runtime={prepared}') + gpu = resolve_runtime_ai_gpu(prepared.gpus, prepared.runtime_bundle, options.ai_gpu_uuid) + log.debug(f'DLSSNeuralRenderer: gpu={gpu}') + factor, mode = resolve_upscaling_mode(options.upscaling_factor) + native_settings = resolve_native_settings(options.source_options()) + session_diagnostics: list[dict[str, Any]] = [] + session = DLSSFrameSession( + input_width=width, + input_height=height, + output_width=output_width, + output_height=output_height, + frame_count=batch, + warmup_frames=options.warmup_frames, + factor=factor, + mode=mode, + native_settings=native_settings, + gpu=gpu, + runtime_bundle=prepared.runtime_bundle, + controller=active_controller, + ) + log.debug(f'DLSSNeuralRenderer: session={session}') + for index in range(batch): + if active_controller.cancel.is_set(): + raise StandaloneError("cancelled", "NeuralRender: cancelled.") + try: + rgb = nchw_image_to_hwc(images, index, name="images") + rgba = rgb_to_rgba(rgb) + render_input = resize_fit(rgba, session.render_width, session.render_height) + motion = np.zeros((session.render_height, session.render_width, 2), dtype=np.float16) + log.debug(f'DLSSNeuralRenderer: index={index} processes={render_input.shape}') + processed, _ = session.process( + index=index, + rgba=render_input, + motion=motion, + reset=True, + pts=0, + ) + log.debug(f'DLSSNeuralRenderer: index={index} processed={processed.shape}') + outputs.append(rgba_to_rgb_nchw(processed)[0]) + session_diagnostics.append({ + "render_width": session.render_width, + "render_height": session.render_height, + "applied_dlss_model_preset": session.applied_dlss_model_preset, + "worker_logs": session.worker_logs, + "completed_frames": session.completed_frames, + }) + for l in session.worker_logs or []: + log.debug(f'DLSSNeuralRenderer worker: {l}') + except Exception as e: + log.error(f'DLSSNeuralRenderer: exception {e}') + if session is not None and not session.closed: + session.abort() + raise + session.close() + self.diagnostics = { + "gpu": dict(gpu), + "runtime_bundle": prepared.runtime_bundle, + "sessions": session_diagnostics, + } + except StandaloneError: + raise + except Exception as exc: + log.error(f'DLSSNeuralRenderer: unexpected exception {exc}') + raise StandaloneError("processing_failed", f"NeuralRender failed: {exc}") from exc + result = np.ascontiguousarray(np.stack(outputs, axis=0)) + self.last_report = { + "input_shape": tuple(images.shape), + "output_shape": tuple(result.shape), + "completed_images": batch, + } + return result + + +__all__ = ["DLSSNeuralRenderer", "RenderOptions"] diff --git a/scripts/dlss/supersample.py b/scripts/dlss/supersample.py new file mode 100644 index 000000000..6feac58a6 --- /dev/null +++ b/scripts/dlss/supersample.py @@ -0,0 +1,117 @@ +from __future__ import annotations + +from dataclasses import dataclass +from typing import Any + +import numpy as np + +from src.core.jobs import JobController, active_job +from src.upscale.image.models import ImageUpscaleOptions, output_size as source_output_size +from src.upscale.video.models import UpscaleOptions as NativeUpscaleOptions +from src.upscale.video.native import RTXVideoSession, probe_capabilities + +from .utils import StandaloneError, nchw_image_to_hwc, hwc_to_nchw, validate_nchw, srgb_to_worker, worker_to_srgb_rgb, log + + +@dataclass(frozen=True, slots=True) +class UpscaleOptions: + vsr_quality: int = 4 + size_mode: str = "Scale factor" + scale_factor: float = 2.0 + width: int = 3840 + height: int = 2160 + aspect_lock: bool = True + ai_gpu_uuid: str = "auto" + + def source_options(self) -> ImageUpscaleOptions: + return ImageUpscaleOptions( + vsr_quality=self.vsr_quality, + size_mode=self.size_mode, + scale_factor=self.scale_factor, + width=self.width, + height=self.height, + aspect_lock=self.aspect_lock, + ai_gpu_uuid=self.ai_gpu_uuid, + ) + + def validate(self) -> None: + source = self.source_options() + source.validate() + + +class DLSSSuperSample: + """RGB NCHW adapter for the native RTX Video Super Resolution worker.""" + + def __init__(self) -> None: + log.info('DLSSSuperSample: init') + self.diagnostics: dict[str, Any] = {} + self.last_report: dict[str, Any] = {} + + def __call__( + self, + images: np.ndarray, + options: UpscaleOptions | None = None, + *, + controller: JobController | None = None, + ) -> np.ndarray: + log.info('DLSSSuperSample: call') + options = options or UpscaleOptions() + options.validate() + batch, _, height, width = validate_nchw(images, name="images") + source = options.source_options() + output_width, output_height = source_output_size(width, height, source) + own_controller = controller or JobController() + log.debug(f'DLSSSuperSample: controller={own_controller}') + outputs: list[np.ndarray] = [] + try: + with active_job(own_controller) as active_controller: + capabilities = probe_capabilities(options.ai_gpu_uuid, controller=active_controller) + log.debug(f'DLSSSuperSample: capabilities={capabilities}') + native_options = NativeUpscaleOptions( + vsr_enabled=True, + vsr_quality=int(options.vsr_quality), + ai_gpu_uuid=options.ai_gpu_uuid, + ) + native_options.validate(for_render=False) + with RTXVideoSession( + width, + height, + output_width, + output_height, + native_options, + 1, + capabilities, + active_controller, + ) as session: + log.debug(f'DLSSSuperSample: session={session}') + for index in range(batch): + if active_controller.cancel.is_set(): + raise StandaloneError("cancelled", "SuperSample: cancelled.") + frame = nchw_image_to_hwc(images, index, name="images") + worker_input = srgb_to_worker(frame) + worker_output = session.process_frame(worker_input) + rgb = worker_to_srgb_rgb(worker_output, output_width, output_height) + log.debug(f'DLSSSuperSample: processed={rgb.shape}') + outputs.append(hwc_to_nchw(rgb, name="upscaled RGB output")[0]) + self.diagnostics = { + "gpu": dict(capabilities.gpu), + "sdk_version": capabilities.sdk_version, + "worker_version": capabilities.worker_version, + "completed_frames": session.completed_frames, + "last_results": session.last_results, + } + except StandaloneError: + raise + except Exception as exc: + log.error(f'DLSSSuperSample: unexpected exception {exc}') + raise StandaloneError("processing_failed", f"SuperSample: failed: {exc}") from exc + result = np.ascontiguousarray(np.stack(outputs, axis=0)) + self.last_report = { + "input_shape": tuple(images.shape), + "output_shape": tuple(result.shape), + "completed_images": batch, + } + return result + + +__all__ = ["DLSSSuperSample", "UpscaleOptions"] diff --git a/scripts/dlss/utils.py b/scripts/dlss/utils.py new file mode 100644 index 000000000..19c749048 --- /dev/null +++ b/scripts/dlss/utils.py @@ -0,0 +1,118 @@ +from __future__ import annotations +import logging +import numpy as np + + +MAX_DIMENSION = 16_384 + +logging.getLogger().handlers.clear() +logging.basicConfig( + level=logging.DEBUG, + filename='dlss.log', + encoding='utf-8', + filemode='a', + format='%(asctime)s %(levelname)s %(message)s', + # datefmt='%Y-%m-%d %H:%M:%S-%f', + force=True, +) +log = logging.getLogger(__name__) +log.debug('DLSSInit') + + +class StandaloneError(RuntimeError): + """Base error with a stable machine-readable code.""" + + def __init__(self, code: str, message: str) -> None: + super().__init__(message) + self.code = code + self.message = message + + +class InvalidArrayError(StandaloneError): + def __init__(self, message: str) -> None: + super().__init__("invalid_array", message) + + +class VerificationError(StandaloneError): + def __init__(self, message: str) -> None: + super().__init__("verification_failed", message) + + +class ProcessingError(StandaloneError): + def __init__(self, message: str, *, code: str = "processing_failed") -> None: + super().__init__(code, message) + + +def validate_nchw(array: np.ndarray, *, name: str = "array") -> tuple[int, int, int, int]: + if not isinstance(array, np.ndarray): + raise InvalidArrayError(f"{name} must be a NumPy array.") + if array.ndim != 4: + raise InvalidArrayError(f"{name} must have shape (N, 3, H, W); got {array.shape}.") + batch, channels, height, width = array.shape + if batch < 1: + raise InvalidArrayError(f"{name} must contain at least one image.") + if channels != 3: + raise InvalidArrayError(f"{name} must contain RGB data with C=3; got C={channels}.") + if not 1 <= height <= MAX_DIMENSION or not 1 <= width <= MAX_DIMENSION: + raise InvalidArrayError( + f"{name} dimensions must be between 1 and {MAX_DIMENSION}; got {width}x{height}." + ) + if array.dtype != np.uint8: + raise InvalidArrayError(f"{name} must use dtype uint8; got {array.dtype}.") + return batch, channels, height, width + + +def copy_nchw(array: np.ndarray, *, name: str = "array") -> np.ndarray: + validate_nchw(array, name=name) + return np.ascontiguousarray(array.copy()) + + +def nchw_image_to_hwc(array: np.ndarray, index: int = 0, *, name: str = "array") -> np.ndarray: + batch, _, _, _ = validate_nchw(array, name=name) + if not 0 <= index < batch: + raise InvalidArrayError(f"{name} image index {index} is outside batch size {batch}.") + return np.ascontiguousarray(array[index].transpose(1, 2, 0)) + + +def hwc_to_nchw(array: np.ndarray, *, name: str = "image") -> np.ndarray: + if not isinstance(array, np.ndarray) or array.ndim != 3 or array.shape[2] != 3: + raise InvalidArrayError(f"{name} must have HWC RGB shape (H, W, 3); got {getattr(array, 'shape', None)}.") + if array.dtype != np.uint8: + raise InvalidArrayError(f"{name} must use dtype uint8; got {array.dtype}.") + return np.ascontiguousarray(array.transpose(2, 0, 1)[None, ...]) + + +def rgb_to_rgba(array: np.ndarray) -> np.ndarray: + """Add opaque alpha only at the private native-worker boundary.""" + if array.ndim != 3 or array.shape[2] != 3 or array.dtype != np.uint8: + raise InvalidArrayError("Native RGB input must have HWC uint8 shape with three channels.") + result = np.empty((*array.shape[:2], 4), dtype=np.uint8) + result[..., :3] = array + result[..., 3] = 255 + return np.ascontiguousarray(result) + + +def rgba_to_rgb_nchw(array: np.ndarray) -> np.ndarray: + if array.ndim != 3 or array.shape[2] != 4 or array.dtype != np.uint8: + raise InvalidArrayError("Native RGBA output must have HWC uint8 shape with four channels.") + return hwc_to_nchw(np.ascontiguousarray(array[..., :3]), name="native RGB output") + + +def srgb_to_worker(rgb: np.ndarray) -> np.ndarray: + """Convert HWC sRGB RGB data to the RTX Video worker's gamma-2.2 RGBA data.""" + if rgb.ndim != 3 or rgb.shape[2] != 3 or rgb.dtype != np.uint8: + raise InvalidArrayError("RGB input must have HWC uint8 shape with three channels.") + rgba = rgb_to_rgba(rgb) + values = rgba[..., :3].astype(np.float32) / 255.0 + linear = np.where(values <= 0.04045, values / 12.92, ((values + 0.055) / 1.055) ** 2.4) + rgba[..., :3] = np.rint(np.clip(linear, 0.0, 1.0) ** (1.0 / 2.2) * 255.0).astype(np.uint8) # pylint: disable=unsupported-assignment-operation + return np.ascontiguousarray(rgba) + + +def worker_to_srgb_rgb(data: bytes | bytearray | memoryview, width: int, height: int) -> np.ndarray: + """Convert packed worker RGBA output to an HWC sRGB RGB array.""" + rgba = np.frombuffer(data, dtype=np.uint8).reshape(height, width, 4).copy() + values = (rgba[..., :3].astype(np.float32) / 255.0) ** 2.2 + rgb = np.where(values <= 0.0031308, values * 12.92, 1.055 * values ** (1.0 / 2.4) - 0.055) + rgba[..., :3] = np.rint(np.clip(rgb, 0.0, 1.0) * 255.0).astype(np.uint8) + return np.ascontiguousarray(rgba[..., :3]) diff --git a/scripts/dlss/verify.py b/scripts/dlss/verify.py new file mode 100644 index 000000000..22ee46b12 --- /dev/null +++ b/scripts/dlss/verify.py @@ -0,0 +1,201 @@ +from __future__ import annotations + +import importlib.util +import platform +import sys +from dataclasses import dataclass, field +from typing import Any + +from src.core.gpu_selection import resolve_ai_gpu +from src.core.gpu_detection import detect_gpus +from src.core.paths import ADDON, DLSS_SUPERRES, FFMPEG, FFPROBE, HOST_DXGI, NEURAL_RUNTIME, WORKER +from src.core.runtime import validate_runtime_files + +from .utils import log + + +@dataclass(frozen=True, slots=True) +class VerifyOptions: + level: str = "basic" + check_neural: bool = True + check_upscale: bool = True + check_interpolation: bool = True + + def validate(self) -> None: + if self.level not in {"basic", "deep"}: + raise ValueError("Verification level must be 'basic' or 'deep'.") + for name in ("check_neural", "check_upscale", "check_interpolation"): + if not isinstance(getattr(self, name), bool): + raise ValueError(f"{name} must be a boolean.") + + +@dataclass(frozen=True, slots=True) +class VerificationCheck: + name: str + passed: bool + detail: str = "" + + def to_dict(self) -> dict[str, Any]: + log.debug(f'DLSSVerify: check="{self.name}" passed={self.passed} detail="{self.detail}"') + result = {"name": self.name, "passed": self.passed, "detail": self.detail} + return result + + +@dataclass(frozen=True, slots=True) +class VerificationReport: + ok: bool + level: str + python: str + platform: str + gpu: dict[str, Any] | None + paths: dict[str, str] + checks: tuple[VerificationCheck, ...] + diagnostics: tuple[str, ...] = field(default_factory=tuple) + + @property + def failed(self) -> tuple[VerificationCheck, ...]: + return tuple(check for check in self.checks if not check.passed) + + def to_dict(self) -> dict[str, Any]: + log.info(f'DLSSVerify: level="{self.level}" python="{self.python}" platform="{self.platform}"') + log.info(f'DLSSVerify: paths={self.paths}') + log.info(f'DLSSVerify: gpu={self.gpu}') + log.debug(f'DLSSVerify: diagnostics={self.diagnostics}') + return { + "ok": self.ok, + "python": self.python, + "platform": self.platform, + "gpu": self.gpu, + "paths": self.paths, + "checks": [check.to_dict() for check in self.checks], + "diagnostics": self.diagnostics, + } + + +_RUNTIME_PATHS = { + "ffmpeg": FFMPEG, + "ffprobe": FFPROBE, + "worker": WORKER, + "host_dxgi": HOST_DXGI, + "dlss_addon": ADDON, + "dlss_superres": DLSS_SUPERRES, + "dlss_neural": NEURAL_RUNTIME, +} + + +class DLSSVerify: + """Perform side-effect-free runtime preflight checks by default.""" + + def __init__(self) -> None: + self.last_report: VerificationReport | None = None + + def __call__(self, gpu_uuid: str = "auto", options: VerifyOptions | None = None) -> VerificationReport: + options = options or VerifyOptions() + options.validate() + checks: list[VerificationCheck] = [] + diagnostics: list[str] = [] + selected_gpu: dict[str, Any] | None = None + + checks.extend(self._check_files()) + checks.append(self._check_import("numpy")) + checks.append(self._check_import("PIL")) + checks.append(self._check_import("cv2")) + checks.append(self._check_import("av")) + + try: + gpus = detect_gpus() + selected_gpu = resolve_ai_gpu(gpus, gpu_uuid) + checks.append(VerificationCheck("gpu", True, self._gpu_detail(selected_gpu))) + except (OSError, RuntimeError, ValueError) as exc: + checks.append(VerificationCheck("gpu", False, str(exc))) + diagnostics.append(str(exc)) + + try: + validate_runtime_files() + checks.append(VerificationCheck("runtime", True, "Required runtime files are present.")) + except (OSError, RuntimeError, ValueError) as exc: + checks.append(VerificationCheck("runtime", False, str(exc))) + diagnostics.append(str(exc)) + + if options.level == "deep": + checks.extend(self._deep_checks(options, gpu_uuid, selected_gpu)) + else: + checks.append(VerificationCheck("deep_capabilities", True, "Deep capability checks were not requested.")) + + filtered = tuple(check for check in checks if self._feature_enabled(check.name, options)) + report = VerificationReport( + ok=all(check.passed or check.status == "not_run" for check in filtered), + level=options.level, + python=platform.python_version(), + platform=sys.platform, + gpu=selected_gpu, + paths={name: str(path) for name, path in _RUNTIME_PATHS.items()}, + checks=filtered, + diagnostics=tuple(diagnostics), + ) + self.last_report = report + return report + + @staticmethod + def _check_files() -> list[VerificationCheck]: + return [ + VerificationCheck( + name=f"file:{name}", + passed=path.is_file(), + detail=str(path), + ) + for name, path in _RUNTIME_PATHS.items() + ] + + @staticmethod + def _check_import(name: str) -> VerificationCheck: + available = importlib.util.find_spec(name) is not None + return VerificationCheck( + name=f"dependency:{name}", + passed=available, + detail="available" if available else "not installed", + ) + + @staticmethod + def _gpu_detail(gpu: dict[str, Any]) -> str: + return f"{gpu.get('name', 'NVIDIA GPU')} driver={gpu.get('driver', 'unknown')} uuid={gpu.get('uuid', 'unknown')}" + + @staticmethod + def _feature_enabled(name: str, options: VerifyOptions) -> bool: + if name.startswith("neural:"): + return options.check_neural + if name.startswith("upscale:"): + return options.check_upscale + if name.startswith("interpolation:"): + return options.check_interpolation + return True + + @staticmethod + def _deep_checks(options: VerifyOptions, gpu_uuid: str, selected_gpu: dict[str, Any] | None) -> list[VerificationCheck]: + del selected_gpu + checks: list[VerificationCheck] = [] + if options.check_neural: + try: + from src.core.runtime import prepare_runtime + + prepared = prepare_runtime() + checks.append(VerificationCheck("neural:runtime", True, f"Prepared {len(prepared.warmed_files)} runtime components.")) + except (ImportError, OSError, RuntimeError, ValueError) as exc: + checks.append(VerificationCheck("neural:runtime", False, str(exc))) + if options.check_upscale: + try: + from src.upscale.video.native import probe_capabilities + + capabilities = probe_capabilities(gpu_uuid) + checks.append(VerificationCheck("upscale:capability", bool(capabilities.vsr.get("available")), str(capabilities.vsr))) + except (ImportError, OSError, RuntimeError, ValueError) as exc: + checks.append(VerificationCheck("upscale:capability", False, str(exc))) + if options.check_interpolation: + try: + from src.frame_interpolation.capabilities import probe_frame_interpolation_capabilities + + capabilities = probe_frame_interpolation_capabilities(gpu_uuid) + checks.append(VerificationCheck("interpolation:capability", capabilities.available, capabilities.detail or f"native_multiplier={capabilities.native_multiplier}")) + except (ImportError, OSError, RuntimeError, ValueError) as exc: + checks.append(VerificationCheck("interpolation:capability", False, str(exc))) + return checks diff --git a/scripts/dlss_ext.py b/scripts/dlss_ext.py new file mode 100644 index 000000000..bc042d6b1 --- /dev/null +++ b/scripts/dlss_ext.py @@ -0,0 +1,468 @@ +import os +import time +import textwrap +import gradio as gr +from modules.logger import log +from modules import shared, devices, processing, timer, errors, scripts_manager, scripts_postprocessing +from scripts.dlss import controller_cli as c + + +registered = False +debug = os.environ.get('SD_DLSS_DEBUG', None) is not None +FPS_CHOICES = ['23.976', '25', '29.97', '30', '50', '59.94', '60', '90', '119.88', '120', '144', '165', '180', '240', '360', '480'] +NR_STYLES = ['None', 'Default', 'Natural', 'Cinematic'] +NR_MODELS = ['None','Default', 'J', 'K', 'L', 'M'] +NR_PRESETS = ['Default', 'Preset #1', 'Preset #2', 'Preset #3'] + + +def create_ui(parent): + with gr.Accordion('nVidia DLSS', open=False, elem_id=f'{parent}_dlss_accordion'): + with gr.Row(): + btn_install = gr.Button(value="Install", elem_id='dlss_install') + btn_verify = gr.Button(value="Verify", elem_id='dlss_verify') + btn_status = gr.Button(value="Status", elem_id='dlss_status_btn') + btn_reset = gr.Button(value="Reset", elem_id='dlss_reset') + btn_shutdown = gr.Button(value="Shutdown", elem_id='dlss_shutdown') + with gr.Row(): + install_note = gr.Markdown("", elem_id='dlss_install_note', visible=False) + + with gr.Accordion('DLSS NeuralRender', open=False, elem_id='dlss_nn'): + with gr.Row(): + nr_enabled = gr.Checkbox(label='NR enable', value=False, elem_id='dlss_nr_enabled') + nr_append = gr.Checkbox(label='NR append result', value=False, elem_id='dlss_nr_append') + with gr.Row(): + nr_style = gr.Dropdown(label='NR style', choices=NR_STYLES, value='Default', elem_id='dlss_nr_style') + nr_preset = gr.Dropdown(label='NR preset', choices=NR_PRESETS, value='Default', elem_id='dlss_nr_preset') + nr_model_preset = gr.Dropdown(label='NR model', choices=NR_MODELS, value='Default', elem_id='dlss_nr_model_preset') + with gr.Row(): + nr_intensity = gr.Slider(label='NR intensity', minimum=0.0, maximum=2.0, step=0.05, value=1.0, elem_id='dlss_nr_intensity') + nr_local_tone = gr.Slider(label='NR tone strength', minimum=0.0, maximum=2.0, step=0.05, value=1.0, elem_id='dlss_nr_local_tone') + with gr.Row(): + nr_local_structure = gr.Slider(label='NR local structure', minimum=0.0, maximum=2.0, step=0.05, value=1.0, elem_id='dlss_nr_local_structure') + nr_skin_structure = gr.Slider(label='NR skin structure', minimum=-1.0, maximum=2.0, step=0.05, value=-1.0, elem_id='dlss_nr_skin_structure') + with gr.Row(): + nr_upscaling_factor = gr.Dropdown(label='NR upscaling factor', choices=["1.0", "1.5", "1.724", "2.0", "3.0"], value="1.0", elem_id='dlss_nr_upscaling_factor') + nr_automatic_mask = gr.Checkbox(label='NR automatic mask', value=False, elem_id='dlss_nr_automatic_mask') + + with gr.Accordion('DLSS SuperSample', open=False, elem_id='dlss_ss'): + with gr.Row(): + ss_enabled = gr.Checkbox(label='SS enable', value=False, elem_id='dlss_ss_enabled') + ss_append = gr.Checkbox(label='SS append result', value=False, elem_id='dlss_ss_append') + with gr.Row(): + ss_vsr_quality = gr.Dropdown(label='SS VSR quality', choices=["1: Low", "2: Medium", "3: High", "4: Ultra"], value="4: Ultra", type='value', elem_id='dlss_ss_vsr_quality') + with gr.Row(): + ss_size_mode = gr.Dropdown(label='SS size mode', choices=['Scale factor', 'Target size'], value='Scale factor', elem_id='dlss_ss_size_mode') + with gr.Row(): + ss_scale_factor = gr.Slider(label='SS scale factor', minimum=1.0, maximum=8.0, step=0.05, value=2.0, elem_id='dlss_ss_scale_factor') + with gr.Row(): + ss_width = gr.Number(label='SS width', minimum=64, maximum=16384, step=8, value=3840, elem_id='dlss_ss_width') + ss_height = gr.Number(label='SS height', minimum=64, maximum=16384, step=8, value=2160, elem_id='dlss_ss_height') + + with gr.Accordion('DLSS FrameGen', open=False, elem_id='dlss_fg'): + with gr.Row(): + fg_enabled = gr.Checkbox(label='FG enable', value=False, elem_id='dlss_fg_enabled') + with gr.Row(): + fg_source_fps = gr.Dropdown(label='FG source FPS', choices=FPS_CHOICES, value='23.976', elem_id='dlss_fg_source_fps') + fg_target_fps = gr.Dropdown(label='FG target FPS', choices=FPS_CHOICES, value='60', elem_id='dlss_fg_target_fps') + with gr.Row(): + fg_engine = gr.Dropdown(label='FG engine', choices=['Auto', 'Native DLSSG', 'Cascade'], value='Auto', elem_id='dlss_fg_engine') + + with gr.Accordion('DLSS Status', open=True, elem_id='dlss_status'): + ss_status = gr.JSON({ 'Status': 'unknown' if len(shared.opts.dlss_pkg_path) < 4 else 'stored'}) + + with gr.Row(): + pkg_path = gr.Textbox(label='DLSS Package path', value=shared.opts.dlss_pkg_path, placeholder='path to dlss 5 visual enhancer', elem_id='dlss_pkg_path') + + btn_install.click(install, inputs=[], outputs=[install_note]) + btn_verify.click(verify, inputs=[pkg_path], outputs=[ss_status]) + btn_status.click(status, inputs=[pkg_path], outputs=[ss_status]) + btn_reset.click(reset, inputs=[pkg_path], outputs=[ss_status]) + btn_shutdown.click(shutdown, inputs=[pkg_path], outputs=[ss_status]) + + return [nr_enabled, nr_append, nr_style, nr_intensity, nr_local_tone, nr_local_structure, nr_skin_structure, nr_upscaling_factor, nr_preset, nr_automatic_mask, nr_model_preset, ss_enabled, ss_append, ss_vsr_quality, ss_size_mode, ss_scale_factor, ss_width, ss_height, fg_enabled, fg_source_fps, fg_target_fps, fg_engine] + + +def install(): + note = textwrap.dedent("""\ + ### Install + 1. Download and unpack: [DLSS 5 Visual Enhancer](https://github.com/Merserk/dlss5-visual-enhancer/releases/tag/v7.0) + 2. Enter the path to the unpacked package + 3. Press verify + ### Notes + - Package info is stored for future use on successful verification + - DLSS controller process is started on first use + - Use status to check the current state of the DLSS controller + - Use reset to restore the DLSS controller to its default state + - Use shutdown to stop the DLSS controller process + """) + return gr.update(value=note, visible=True) + + +def verify(pkg_path): + log.info(f'DLSS verify: path="{pkg_path}"') + if not os.path.exists(pkg_path) or not os.path.isdir(pkg_path): + log.error(f'DLSS: path="{pkg_path}" not found') + return { 'error': 'package path not found' } + if not c.controller.get_python(pkg_path): + return { 'error': 'python not found in package path' } + response = c.controller.call(pkg_path, 'verify', { 'gpu_uuid': 'auto', 'options': { 'level': 'deep' } }) + if response.get('status') != 'ok': + error = response.get('error') or {} + log.error(f'DLSS: {error.get("message")}') + return { 'error': error.get('message', 'unknown error') } + report = (response.get('result') or {}).get('report', {}) + if debug: + log.trace(f'DLSS raw: {report}') + checks = { 'passed': 0, 'failed': 0 } + for check in report.get('checks', []): + if check.get('passed', False): + checks['passed'] += 1 + else: + checks['failed'] += 1 + log.error(f'DLSS : {check}') + shared.opts.dlss_pkg_path = pkg_path + shared.opts.save() + log.debug(f'DLSS: gpu={report.get("gpu", "unknown")} checks={checks}') + return report + + +def status(pkg_path): + log.info(f'DLSS status: path="{pkg_path}"') + response = c.controller.call(pkg_path, 'status', {}) + if response.get('status') != 'ok': + error = response.get('error') or {} + log.error(f'DLSS: {error.get("message")}') + return { 'error': error.get('message', 'unknown error') } + return response.get('result', {}) + + +def reset(pkg_path): + log.info(f'DLSS reset: path="{pkg_path}"') + response = c.controller.call(pkg_path, 'reset', {}) + if response.get('status') != 'ok': + error = response.get('error') or {} + log.error(f'DLSS: {error.get("message")}') + return { 'error': error.get('message', 'unknown error') } + return response.get('result', {}) + + +def shutdown(pkg_path): + log.info(f'DLSS shutdown: path="{pkg_path}"') + if not c.controller.is_alive(): + return { 'shutdown': True, 'note': 'controller was not running' } + c.controller.stop() + return { 'shutdown': True } + + +def supersample(pkg_path, images, ss_vsr_quality, ss_size_mode, ss_scale_factor, ss_width, ss_height): + try: + options = { + 'vsr_quality': int(ss_vsr_quality[0]), + 'size_mode': ss_size_mode, + 'scale_factor': float(ss_scale_factor), + 'width': int(ss_width), + 'height': int(ss_height), + 'aspect_lock': False, + } + frames = c.images_to_nchw(images) + if debug: + log.trace(f'DLSS: method=SuperSample input={frames.shape} options={options}') + response = c.controller.call( + pkg_path, + 'upscale', + { 'images': frames, 'options': options }, + timeout=300.0, + ) + if response.get('status') != 'ok': + error = response.get('error') or {} + log.error(f'DLSS: {error.get("message")}') + return images + return c.nchw_to_images(response.get('result')) + except Exception as e: + log.error(f'DLSS: {e}') + errors.display(e, 'DLSS') + return images + + +def neuralrender(pkg_path, images, nr_style, nr_intensity, nr_local_tone, nr_local_structure, nr_skin_structure, nr_upscaling_factor, nr_preset, nr_automatic_mask, nr_model_preset): + try: + options = { + 'nr_style': nr_style, + 'nr_intensity': float(nr_intensity), + 'local_tone_strength': float(nr_local_tone), + 'local_structure_strength': float(nr_local_structure), + 'skin_structure_strength': float(nr_skin_structure), + 'upscaling_factor': float(nr_upscaling_factor), + 'warmup_frames': 0, + 'nr_preset': nr_preset, + 'automatic_mask': bool(nr_automatic_mask), + 'dlss_model_preset': nr_model_preset, + } + frames = c.images_to_nchw(images) + if debug: + log.trace(f'DLSS: method=NeuralRender input={frames.shape} options={options}') + response = c.controller.call( + pkg_path, + 'render', + { 'images': frames, 'options': options }, + timeout=600.0, + ) + if response.get('status') != 'ok': + error = response.get('error') or {} + log.error(f'DLSS: {error.get("message")}') + return None + return c.nchw_to_images(response.get('result')) + except Exception as e: + log.error(f'DLSS: {e}') + errors.display(e, 'DLSS') + return images + + +def framegen(pkg_path, images, fg_source_fps, fg_target_fps, fg_engine): + # source and target fps need to be aligned to closest item from FPS_CHOICES + fg_source_fps = min(FPS_CHOICES, key=lambda x: abs(float(x) - float(fg_source_fps))) + fg_target_fps = min(FPS_CHOICES, key=lambda x: abs(float(x) - float(fg_target_fps))) + try: + if len(images) < 2: + log.warning('DLSS: FrameGen requires at least two frames, skipping') + return images + options = { 'ai_gpu_uuid': 'auto', 'engine': fg_engine } + frames = c.images_to_nchw(images) + if debug: + log.trace(f'DLSS: method=FrameGen input={frames.shape} options={options}') + response = c.controller.call( + pkg_path, + 'framegen', + { 'frames': frames, 'source_fps': fg_source_fps, 'target_fps': fg_target_fps, 'options': options }, + timeout=600.0, + ) + if response.get('status') != 'ok': + error = response.get('error') or {} + log.error(f'DLSS: {error.get("message")}') + return images + return c.nchw_to_images(response.get('result')) + except Exception as e: + log.error(f'DLSS: {e}') + errors.display(e, 'DLSS') + return images + + +def dlss(p: processing.StableDiffusionProcessing | None, pp: processing.Processed | scripts_postprocessing.PostprocessedImage, + nr_enabled, nr_append, nr_style, nr_intensity, nr_local_tone, nr_local_structure, nr_skin_structure, nr_upscaling_factor, nr_preset,nr_automatic_mask, nr_model_preset, + ss_enabled, ss_append, ss_vsr_quality, ss_size_mode, ss_scale_factor, ss_width, ss_height, + fg_enabled, fg_source_fps, fg_target_fps, fg_engine, + *args, **kwargs + ): + if not (ss_enabled or nr_enabled or fg_enabled): + return None + pkg_path = shared.opts.dlss_pkg_path + if not pkg_path or not c.controller.get_python(pkg_path): + log.error('DLSS: package path not configured') + return None + if debug: + log.trace(f'DLSS: path="{pkg_path}" args={args} kwargs={kwargs}') + + update = 'none' + if hasattr(pp, 'images') and pp.images is not None and len(pp.images) > 0: + update = 'images' + inputs = pp.images + elif hasattr(pp, 'image') and pp.image is not None: + update = 'image' + inputs = [pp.image] + else: + return None + + # cast to appropriate types + nr_style = str(getattr(p, 'nr_style', nr_style)) + nr_preset = str(getattr(p, 'nr_preset', nr_preset)) + nr_model_preset = str(getattr(p, 'nr_model_preset', nr_model_preset)) + nr_intensity = float(getattr(p, 'nr_intensity', nr_intensity)) + nr_local_tone = float(getattr(p, 'nr_local_tone', nr_local_tone)) + nr_local_structure = float(getattr(p, 'nr_local_structure', nr_local_structure)) + nr_skin_structure = float(getattr(p, 'nr_skin_structure', nr_skin_structure)) + nr_upscaling_factor = float(getattr(p, 'nr_upscaling_factor', nr_upscaling_factor)) + ss_width = int(getattr(p, 'ss_width', ss_width)) + ss_height = int(getattr(p, 'ss_height', ss_height)) + ss_scale_factor = float(getattr(p, 'ss_scale_factor', ss_scale_factor)) + fg_source_fps = str(getattr(p, 'fg_source_fps', fg_source_fps)) + fg_target_fps = str(getattr(p, 'fg_target_fps', fg_target_fps)) + if (p is not None) and ('video' in p.ops): # should not add video frames + nr_append = False + ss_append = False + + images = [] + originals = [] + current_images = inputs + t = timer.Timer() + + jobid = shared.state.begin('DLSS') + t_start = time.time() + + if ss_enabled: + t0 = time.time() + if p: + p.extra_generation_params["DLSSSuperSample"] = True + log.info(f'DLSS: method=SuperSample quality="{ss_vsr_quality}" mode="{ss_size_mode}" scale={ss_scale_factor} width={ss_width} height={ss_height}') + if ss_append: + originals.extend(current_images) + output = supersample(pkg_path, current_images, ss_vsr_quality, ss_size_mode, ss_scale_factor, ss_width, ss_height) + if debug: + log.trace(f'DLSS: method=SuperSample images={len(output) if output else 0} time={time.time() - t0:.3f}') + if output: + images = output + current_images = output + t.ts('supersample', t0) + + if nr_style == 'None' or nr_model_preset == 'None': + nr_enabled = False + if nr_enabled: + t0 = time.time() + if p: + p.extra_generation_params["DLSSNeuralRender"] = True + log.info(f'DLSS: method=NeuralRender style={nr_style} intensity={nr_intensity} tone={nr_local_tone} structure={nr_local_structure} skin={nr_skin_structure} scale={nr_upscaling_factor} preset={nr_preset} mask={nr_automatic_mask} model={nr_model_preset}') + if nr_append: + originals.extend(current_images) + output = neuralrender(pkg_path, current_images, nr_style, nr_intensity, nr_local_tone, nr_local_structure, nr_skin_structure, nr_upscaling_factor, nr_preset, nr_automatic_mask, nr_model_preset) + if debug: + log.trace(f'DLSS: method=NeuralRender images={len(output) if output else 0} time={time.time() - t0:.3f}') + if output: + images = output + current_images = output + t.ts('neuralrender', t0) + + if fg_enabled: + t0 = time.time() + if p: + p.extra_generation_params["DLSSFrameGen"] = True + log.info(f'DLSS: method=FrameGen source={fg_source_fps} target={fg_target_fps} engine="{fg_engine}"') + output = framegen(pkg_path, current_images, fg_source_fps, fg_target_fps, fg_engine) + if debug: + t1 = time.time() + log.trace(f'DLSS: method=FrameGen frames={len(output) if output else 0} time={t1 - t0:.3f}') + if output: + images = output + current_images = output + t.ts('framegen', t0) + + shared.state.end(jobid) + timer.process.ts('dlss', t_start) + + log.debug(f'DLSS: frames={len(images)} {t.summary(min_time=0)}') + if update == 'images': + pp.images = images + elif update == 'image' and len(images) > 0: + pp.image = images[-1] + pp.originals = originals + return pp + + +class DLSSScript(scripts_manager.Script): + def __init__(self): + super().__init__() + self.video_capable = scripts_manager.AlwaysVisible + self.register() + + def title(self): + return 'nVidia DLSS' + + def show(self, _is_img2img): + if devices.backend != 'cuda': + return False + return scripts_manager.AlwaysVisible + + def ui(self, _is_img2img): + return create_ui(self.parent) + + def register(self): # register xyz grid elements + global registered # pylint: disable=global-statement + if registered: + return + registered = True + def apply_field(field): + def fun(p, x, xs): # pylint: disable=unused-argument + setattr(p, field, x) + self.run(p) + return fun + + import sys + xyz_classes = [v for k, v in sys.modules.items() if 'xyz_grid_classes' in k] + if xyz_classes and len(xyz_classes) > 0: + xyz_classes = xyz_classes[0] + options = [ + xyz_classes.AxisOption("[DLSS] NR style", str, apply_field("nr_style"), choices=lambda: NR_STYLES), + xyz_classes.AxisOption("[DLSS] NR preset", str, apply_field("nr_preset"), choices=lambda: NR_PRESETS), + xyz_classes.AxisOption("[DLSS] NR model", str, apply_field("nr_model_preset"), choices=lambda: NR_MODELS), + xyz_classes.AxisOption("[DLSS] NR intensity", float, apply_field("nr_intensity")), + xyz_classes.AxisOption("[DLSS] NR local tone", float, apply_field("nr_local_tone")), + xyz_classes.AxisOption("[DLSS] NR local structure", float, apply_field("nr_local_structure")), + xyz_classes.AxisOption("[DLSS] NR skin structure", float, apply_field("nr_skin_structure")), + ] + for option in options: + if option not in xyz_classes.axis_options: + xyz_classes.axis_options.append(option) + + def postprocess_image(self, p: processing.StableDiffusionProcessing, pp: scripts_manager.PostprocessImageArgs, *args, **kwargs): + if p.xyz: + pp = dlss(p, pp, *args, **kwargs) + + def postprocess(self, p: processing.StableDiffusionProcessing, pp: processing.Processed, *args, **kwargs): # pylint: disable=arguments-differ,unused-argument + if p.xyz: # do not postprocessing when running in xyz mode + return pp + _pp = dlss(p, pp, *args, **kwargs) + # postprocess triggers after initial images have already been saved + if _pp is not None and hasattr(_pp, 'images') and _pp.images is not None: + pp = _pp + orig_infos = pp.infotexts if hasattr(pp, 'infotexts') else [] + out_images, out_infos = processing.process_samples(p, pp.images) + pp.images = out_images + pp.infotexts = out_infos + if hasattr(pp, 'originals') and pp.originals is not None and len(pp.originals) > 0: + pp.infotexts = orig_infos + pp.infotexts + pp.images = pp.originals + pp.images + return pp + + +class DLSSPostprocessingScript(scripts_postprocessing.ScriptPostprocessing): + name = "nVidia DLSS" + order = 30000 + + def ui(self): + nr_enabled, nr_append, nr_style, nr_intensity, nr_local_tone, nr_local_structure, nr_skin_structure, nr_upscaling_factor, nr_preset, nr_automatic_mask, nr_model_preset, ss_enabled, ss_append, ss_vsr_quality, ss_size_mode, ss_scale_factor, ss_width, ss_height, fg_enabled, fg_source_fps, fg_target_fps, fg_engine = create_ui('postprocess') + return { + "nr_enabled": nr_enabled, + "nr_append": nr_append, + "nr_style": nr_style, + "nr_intensity": nr_intensity, + "nr_local_tone": nr_local_tone, + "nr_local_structure": nr_local_structure, + "nr_skin_structure": nr_skin_structure, + "nr_upscaling_factor": nr_upscaling_factor, + "nr_preset": nr_preset, + "nr_automatic_mask": nr_automatic_mask, + "nr_model_preset": nr_model_preset, + "ss_enabled": ss_enabled, + "ss_append": ss_append, + "ss_vsr_quality": ss_vsr_quality, + "ss_size_mode": ss_size_mode, + "ss_scale_factor": ss_scale_factor, + "ss_width": ss_width, + "ss_height": ss_height, + "fg_enabled": fg_enabled, + "fg_source_fps": fg_source_fps, + "fg_target_fps": fg_target_fps, + "fg_engine": fg_engine, + } + + def process(self, pp: scripts_postprocessing.PostprocessedImage, *args, **kwargs): + nr_enabled = kwargs.get("nr_enabled", False) + ss_enabled = kwargs.get("ss_enabled", False) + fg_enabled = kwargs.get("fg_enabled", False) + if not (nr_enabled or ss_enabled or fg_enabled): + return + if pp.image is None: + return + result = dlss(None, pp, *args, **kwargs) + if result is None or not hasattr(result, "images") or len(result.images) == 0: + return + pp.image = result.images[0] + pp.info["DLSS"] = f'NR: {nr_enabled} SS: {ss_enabled} FG: {fg_enabled}' diff --git a/scripts/postprocessing_rembg.py b/scripts/postprocessing_rembg.py index 4068f958b..61825e5db 100644 --- a/scripts/postprocessing_rembg.py +++ b/scripts/postprocessing_rembg.py @@ -20,7 +20,7 @@ models = [ def dependencies(): from installer import install - for pkg in ["dctorch==0.1.2", "pymatting", "pooch", "rembg", "numba"]: + for pkg in ["dctorch==0.1.2", "pymatting", "pooch", "rembg", "numba", "kornia", "kornia-rs"]: install(pkg, no_deps=True, ignore=False) @@ -78,6 +78,7 @@ class ScriptPostprocessingRembg(scripts_postprocessing.ScriptPostprocessing): if image is None: return pp log.info(f'RemoveBackground: model={model} merge_alpha={merge_alpha} refine={refine} mask_only={mask_only} postprocess_mask={postprocess_mask} alpha_matting={alpha_matting} alpha_matting_foreground_threshold={alpha_matting_foreground_threshold} alpha_matting_background_threshold={alpha_matting_background_threshold} alpha_matting_erode_size={alpha_matting_erode_size}') + dependencies() if model == 'ben2': try: from modules.rembg import ben2 @@ -96,7 +97,6 @@ class ScriptPostprocessingRembg(scripts_postprocessing.ScriptPostprocessing): return pp else: try: - dependencies() import rembg if "U2NET_HOME" not in os.environ: from modules.paths import models_path diff --git a/scripts/prompt_enhance/options.py b/scripts/prompt_enhance/options.py index 1913de1bb..933782fc4 100644 --- a/scripts/prompt_enhance/options.py +++ b/scripts/prompt_enhance/options.py @@ -36,13 +36,17 @@ class Options: 'trohrbaugh/Qwen3.5-9B-heretic-v2', ] cloud = [ + 'google/gemini-3.8-flash', + 'google/gemini-3.7-flash', + 'google/gemini-3.6-flash', 'google/gemini-3.5-flash', - 'google/gemini-3.1-pro-preview', + 'google/gemini-3.5-flash-lite', 'google/gemini-3.1-flash-lite', - 'google/gemini-3.1-flash-lite-preview', - 'google/gemini-2.5-flash', - 'google/gemini-2.5-flash-lite', - 'google/gemini-2.5-pro', + 'google/gemini-3.1-pro-preview', + 'xai/grok-3-latest', + 'xai/grok-3-fast-latest', + 'xai/grok-3-mini-latest', + 'xai/grok-3-mini-fast-latest', ] models = { # Gemma @@ -83,13 +87,18 @@ class Options: 'cognitivecomputations/Dolphin3.0-Llama3.2-1B': {}, 'cognitivecomputations/Dolphin3.0-Llama3.2-3B': {}, # Gemini + 'google/gemini-3.8-flash': {}, + 'google/gemini-3.7-flash': {}, + 'google/gemini-3.6-flash': {}, 'google/gemini-3.5-flash': {}, - 'google/gemini-3.1-pro-preview': {}, + 'google/gemini-3.5-flash-lite': {}, 'google/gemini-3.1-flash-lite': {}, - 'google/gemini-3.1-flash-lite-preview': {}, - 'google/gemini-2.5-flash': {}, - 'google/gemini-2.5-flash-lite': {}, - 'google/gemini-2.5-pro': {}, + 'google/gemini-3.1-pro-preview': {}, + # Grok + 'xai/grok-3-latest': {}, + 'xai/grok-3-fast-latest': {}, + 'xai/grok-3-mini-latest': {}, + 'xai/grok-3-mini-fast-latest': {}, # SmolLM 'HuggingFaceTB/SmolLM2-135M-Instruct': {}, 'HuggingFaceTB/SmolLM2-360M-Instruct': {}, @@ -135,6 +144,12 @@ class Options: Keep the result faithful to the original prompt and the intended image. Do not add unrelated concepts, non-visual commentary, or fluff. ''') + t2i_noprompt: str = textwrap.dedent('''\ + You are an expert AI image prompt engineer. + Create an original, imaginative and visually rich prompt for image generation. + Be Creative! + Use concrete, image-generation language and avoid unrelated fluff or commentary. + ''') i2i_prompt: str = textwrap.dedent('''\ You are an expert AI image prompt engineer. You will receive an image and a user prompt for editing or refinement. @@ -150,6 +165,7 @@ class Options: Base the prompt on what is present in the image, its style, and its atmosphere. Use concrete, image-generation language and avoid unrelated fluff or commentary. ''') + t2v_prompt: str = textwrap.dedent('''\ You are an expert AI video prompt engineer. You will receive a user prompt for video generation. @@ -176,6 +192,7 @@ class Options: Specify subject and camera movement, scene transitions, and temporal dynamics. Use concrete, video-generation language and avoid unrelated fluff or commentary. ''') + nsfw_ok: str = textwrap.dedent('''\ NSFW, nudity and explicit content and language are allowed. ''') @@ -202,10 +219,10 @@ class Options: max_delim_index: int = 60 min_tokens: int = 0 - max_tokens: int = 256 + max_tokens: int = 512 do_sample: bool = True - temperature: float = 0.6 - repetition_penalty: float = 1.2 + temperature: float = 0.75 + repetition_penalty: float = 1.05 top_k: int = 0 top_p: float = 0.0 thinking_mode: bool = False diff --git a/scripts/prompt_enhance/template.py b/scripts/prompt_enhance/template.py index e0b6e7c4c..e800cd834 100644 --- a/scripts/prompt_enhance/template.py +++ b/scripts/prompt_enhance/template.py @@ -9,13 +9,24 @@ debug_enabled = os.environ.get('SD_LLM_DEBUG', None) is not None debug_log = log.trace if debug_enabled else lambda *args, **kwargs: None -def get_text_template(system, prompt, options, nsfw, has_system, has_prompt, has_processor, is_video, _image) -> list[dict]: - if not has_system: - system = options.t2v_prompt if is_video else options.t2i_prompt - system += options.nsfw_ok if nsfw else options.nsfw_no - system += options.details_prompt - system += options.details_format - debug_log(f'Prompt enhance: system="{system}"') +def get_system_prompt(system: str | None, options: Options, nsfw: bool, has_prompt: bool, is_video: bool, is_image: bool) -> str: + if system is not None and len(system) > 4: + return system + if is_video: + system = options.t2v_prompt if has_prompt else options.t2v_noprompt + elif is_image: + system = options.i2i_prompt if has_prompt else options.i2i_noprompt + else: + system = options.t2i_prompt if has_prompt else options.t2i_noprompt + system += options.nsfw_ok if nsfw else options.nsfw_no + system += options.details_prompt + system += options.details_format + debug_log(f'Prompt enhance: system="{system}"') + return system + + +def get_text_template(system, prompt, options, nsfw, has_prompt, has_processor, is_video, _image) -> list[dict]: + system = get_system_prompt(system, options, nsfw, has_prompt, is_video, is_image=False) if not has_prompt: prompt = 'be creative!' if not has_processor: @@ -35,16 +46,8 @@ def get_text_template(system, prompt, options, nsfw, has_system, has_prompt, has return chat_template -def get_image_template(system, prompt, options, nsfw, has_system, has_prompt, _has_processor, is_video, image) -> list[dict]: - if not has_system: - if is_video: - system = options.i2v_prompt if has_prompt else options.i2v_noprompt - else: - system = options.i2i_prompt if has_prompt else options.i2i_noprompt - system += options.nsfw_ok if nsfw else options.nsfw_no - system += options.details_prompt - system += options.details_format - debug_log(f'Prompt enhance: system="{system}"') +def get_image_template(system, prompt, options, nsfw, has_prompt, _has_processor, is_video, image) -> list[dict]: + system = get_system_prompt(system, options, nsfw, has_prompt, is_video, is_image=True) if has_prompt: chat_template = [ { "role": "system", "content": [ @@ -78,23 +81,23 @@ def set_template( module: str | None = None, ) -> list[dict] | str: chat_template = [] - has_system = system is not None and len(system) > 4 has_prompt = prompt is not None and len(prompt) > 4 has_image = image is not None and isinstance(image, Image.Image) is_video = module == 'video' - debug_log(f'Prompt enhance template: module={module} system={has_system} prompt={has_prompt} image={has_image} video={is_video} model="{model}" nsfw={nsfw} processor={has_processor}') + debug_log(f'Prompt enhance template: module={module} prompt={has_prompt} image={has_image} video={is_video} model="{model}" nsfw={nsfw} processor={has_processor} cloud={is_cloud_model(model)}') + """ if has_image: if is_cloud_model(model): pass - elif options.processor is None: + elif not has_processor: log.error('Prompt enhance: image not supported by model') return prompt if prompt is not None else '' # Return original text part if image cannot be processed - + """ if has_image: - chat_template = get_image_template(system, prompt, options, nsfw, has_system, has_prompt, has_processor, is_video, image) + chat_template = get_image_template(system, prompt, options, nsfw, has_prompt, has_processor, is_video, image) else: - chat_template = get_text_template(system, prompt, options, nsfw, has_system, has_prompt, has_processor, is_video, image) + chat_template = get_text_template(system, prompt, options, nsfw, has_prompt, has_processor, is_video, image) return chat_template diff --git a/scripts/prompt_enhance_ext.py b/scripts/prompt_enhance_ext.py index 14d801359..105c7fe8b 100644 --- a/scripts/prompt_enhance_ext.py +++ b/scripts/prompt_enhance_ext.py @@ -6,7 +6,7 @@ import torch import transformers import gradio as gr from PIL import Image -from modules import scripts_manager, shared, devices, errors, processing, sd_models, sd_modules, timer +from modules import scripts_manager, shared, devices, errors, processing, sd_models, sd_modules, timer, extra_networks from modules import ui_control_helpers from modules.sd_offload_aux import register_aux, deregister_aux, move_aux_to_gpu, offload_aux from modules.logger import log @@ -14,7 +14,7 @@ from modules.caption.logits import LogitsParser from modules.caption import helpers from scripts.prompt_enhance.options import Options from scripts.prompt_enhance.helpers import is_cloud_model, is_vision_model, is_thinking_model, get_model_repo_from_display -from scripts.prompt_enhance.template import set_template +from scripts.prompt_enhance.template import set_template, get_system_prompt debug_enabled = os.environ.get('SD_LLM_DEBUG', None) is not None @@ -279,14 +279,16 @@ class PromptEnhanceScript(scripts_manager.Script): def get_image(self, image): current_image = None try: - if image is not None and isinstance(image, gr.Image): + if (image is not None) and isinstance(image, list) and len(image) > 0: + current_image = image[0] + if (image is not None) and isinstance(image, gr.Image): current_image = image.value - elif image is not None and isinstance(image, Image.Image): # if image is already a PIL image + elif (image is not None) and isinstance(image, Image.Image): # if image is already a PIL image current_image = image - if current_image is not None and (current_image.width <= 64 or current_image.height <= 64): + if (current_image is not None) and (current_image.width <= 64 or current_image.height <= 64): current_image = None # Fallback to Kanvas/Control input if no image from Gradio component (e.g., when Kanvas is active) - if current_image is None and ui_control_helpers.input_source is not None: + if (current_image is None) and (ui_control_helpers.input_source is not None): if isinstance(ui_control_helpers.input_source, list) and len(ui_control_helpers.input_source) > 0: current_image = ui_control_helpers.input_source[0] elif isinstance(ui_control_helpers.input_source, Image.Image): @@ -325,11 +327,10 @@ class PromptEnhanceScript(scripts_manager.Script): # Strip symbols from model name if present model = get_model_repo_from_display(model) if model else self.options.default prompt = prompt or (self.prompt.value if self.prompt else "") # Check if self.prompt is None - image = None if use_vision and is_vision_model(model): # handle vision toggle image = image or self.image - if image is None: - use_vision = False + else: + image = None prefix = prefix or '' suffix = suffix or '' min_tokens = min_tokens or self.options.min_tokens @@ -341,7 +342,7 @@ class PromptEnhanceScript(scripts_manager.Script): thinking = thinking or self.options.thinking_mode sample = sample if sample is not None else self.options.do_sample nsfw = nsfw if nsfw is not None else True # Default nsfw to True if not provided - debug_log(f'Prompt enhance: model="{model}" model_class="{self.llm.__class__.__name__ if self.llm is not None else "not loaded"}" nsfw={nsfw} thinking={thinking} prefill="{prefill[:30] if prefill else ""}" use_vision={use_vision} image={image is not None}') + debug_log(f'Prompt enhance: model="{model}" model_class="{self.llm.__class__.__name__ if self.llm is not None else "not loaded"}" nsfw={nsfw} thinking={thinking} prefill="{prefill[:30] if prefill else ""}" vision={use_vision} image={image}') while self.busy: time.sleep(0.1) @@ -363,7 +364,9 @@ class PromptEnhanceScript(scripts_manager.Script): # Only process images if vision is enabled and model supports it if use_vision and is_vision_model(model): current_image = self.get_image(image) - debug_log(f'Prompt enhance: image={current_image}') + if current_image is None: + use_vision = False + debug_log(f'Prompt enhance: image={current_image} use_vision={use_vision}') # Check if vision was requested but no image is available if use_vision and is_vision_model(model) and current_image is None: @@ -389,6 +392,47 @@ class PromptEnhanceScript(scripts_manager.Script): current_image = current_image.convert('RGB') debug_log('Prompt enhance: Converted image to RGB mode') + # Prepare prefill (VQA approach: string concatenation, not assistant message) + prefill_text = (prefill or '').strip() + + t0 = time.time() + self.busy = True + + if is_cloud_model(model): + has_prompt = (prompt_text is not None) and (len(prompt_text) > 4) + has_prefill = (prefill_text is not None) and (len(prefill_text) > 4) + system = get_system_prompt(system, self.options, nsfw, has_prompt=has_prompt, is_video=self.parent=='video', is_image=current_image is not None) + debug_log(f'Prompt enhance: prompt="{prompt_text}"') + if 'gemini' in model: + from modules.caption import gemini + kwargs = { + 'temperature': temperature, + 'min_output_tokens': min_tokens, + 'max_output_tokens': max_tokens, + } + model_name = model.replace('google/', '') + response = gemini.predict(prompt_text, current_image, model_name, system, prefill_text, thinking, kwargs) + t1 = time.time() + log.info(f'Prompt enhance: model="{model}" nsfw={nsfw} time={t1-t0:.2f} prompt={has_prompt} prefill={has_prefill} image={current_image} thinking={thinking} response={len(response)}') + debug_log(f'Prompt enhance: response="{response}"') + self.busy = False + return response + elif 'grok' in model: + from modules.caption import grok + kwargs = { + 'temperature': temperature, + } + model_name = model.replace('xai/', '') + response = grok.predict(prompt_text, current_image, model_name, system, prefill_text, thinking, kwargs) + t1 = time.time() + log.info(f'Prompt enhance: model="{model}" nsfw={nsfw} time={t1-t0:.2f} prompt={has_prompt} prefill={has_prefill} image={current_image} thinking={thinking} response={len(response)}') + debug_log(f'Prompt enhance: response="{response}"') + self.busy = False + return response + else: + self.busy = False + return 'Model not recognized' + chat_template = set_template( system=system, prompt=prompt_text, @@ -400,35 +444,11 @@ class PromptEnhanceScript(scripts_manager.Script): module=self.parent, ) - # Prepare prefill (VQA approach: string concatenation, not assistant message) - prefill_text = (prefill or '').strip() use_prefill = len(prefill_text) > 0 is_thinking = is_thinking_model(model) - debug_log(f'Prompt enhance: system="{system}"') debug_log(f'Prompt enhance: prompt="{prompt_text}"') debug_log(f'Prompt template: roles={[msg["role"] for msg in chat_template]} thinking={is_thinking}:{thinking} prefill={use_prefill}') - t0 = time.time() - self.busy = True - - if is_cloud_model(model): - if 'gemini' in model: - from modules.caption import gemini - kwargs = { - 'temperature': temperature, - 'min_output_tokens': min_tokens, - 'max_output_tokens': max_tokens, - } - model_name = model.replace('google/', '') - response = gemini.predict(prompt_text, current_image, model_name, system, model, prefill_text, thinking, kwargs) - t1 = time.time() - log.info(f'Prompt enhance: model="{model}" nsfw={nsfw} time={t1-t0:.2f} prefill="{prefill_text[:20] if prefill_text else None}" response={len(response)}') - debug_log(f'Prompt enhance: response="{response}"') - self.busy = False - return response - - else: - return 'Model not recognized' try: # Qwen3.5 uses native enable_thinking parameter in the chat template @@ -712,14 +732,17 @@ class PromptEnhanceScript(scripts_manager.Script): p.prompt = shared.prompt_styles.apply_styles_to_prompt(p.prompt, p.styles) p.negative_prompt = shared.prompt_styles.apply_negative_styles_to_prompt(p.negative_prompt, p.styles) shared.prompt_styles.apply_styles_to_extra(p) + prompts, p.network_data = extra_networks.parse_prompts([p.prompt], p.network_data) + p.prompt = prompts[0] p.styles = [] jobid = shared.state.begin('LLM') p.extra_generation_params['LLM'] = get_model_repo_from_display(llm_model) p.extra_generation_params['Original'] = p.prompt + image = self_image or p.init_images p.prompt = self.enhance( prompt=p.prompt, seed=p.seed, - image=self_image, + image=image, prefix=prompt_prefix, suffix=prompt_suffix, model=llm_model, diff --git a/scripts/pulid/pulid_sdxl.py b/scripts/pulid/pulid_sdxl.py index a36283be3..6e3561bfb 100644 --- a/scripts/pulid/pulid_sdxl.py +++ b/scripts/pulid/pulid_sdxl.py @@ -327,7 +327,7 @@ class StableDiffusionXLPuLIDPipeline: return_image_latents=False, ) latents = latents[0] - debug(f'PulID noise: op=inpaint latent={latents.shape} image={image} mask={mask_image} dtype={latents.dtype}') + debug(f'PulID noise: op=inpaint latent={list(latents.shape)} image={image} mask={mask_image} dtype={latents.dtype}') else: # img2img latents = self.pipe.prepare_latents(image, None, # timestep (not needed) @@ -338,10 +338,10 @@ class StableDiffusionXLPuLIDPipeline: None, # generator False, # add_noise ) - debug(f'PulID noise: op=img2img latent={latents.shape} image={image} dtype={latents.dtype}') + debug(f'PulID noise: op=img2img latent={list(latents.shape)} image={image} dtype={latents.dtype}') else: latents = torch.zeros_like(noise) - debug(f'PulID noise: op=txt2img latent={latents.shape} dtype={latents.dtype}') + debug(f'PulID noise: op=txt2img latent={list(latents.shape)} dtype={latents.dtype}') return latents, noise def __call__( @@ -379,7 +379,7 @@ class StableDiffusionXLPuLIDPipeline: # latents latent, noise = self.init_latent(seed, size, image, mask_image, strength, width, height) noisy_latent = latent + noise * sigmas[0].to(noise) - debug(f'PulID noisy: latent={noisy_latent.shape} dtype={noisy_latent.dtype}') + debug(f'PulID noisy: latent={list(noisy_latent.shape)} dtype={noisy_latent.dtype}') ( prompt_embeds, @@ -425,7 +425,7 @@ class StableDiffusionXLPuLIDPipeline: # process output latents = latents.to(dtype=self.pipe.vae.dtype, device=self.device) - debug(f'PulID output: latent={latents.shape} dtype={latents.dtype}') + debug(f'PulID output: latent={list(latents.shape)} dtype={latents.dtype}') if output_type == 'latent': images = self.pipe.image_processor.postprocess(latents, output_type='latent') elif output_type == 'np': diff --git a/scripts/rocm/rocm_log.py b/scripts/rocm/rocm_log.py new file mode 100644 index 000000000..559b82442 --- /dev/null +++ b/scripts/rocm/rocm_log.py @@ -0,0 +1,198 @@ +"""Capture and report native MIOpen convolution selections.""" + +import atexit +import os +import re +import sys +import threading +import time + +from modules.logger import log + + +_ALGORITHM_PATTERN = re.compile(r"FW Chosen Algorithm:\s*([^,\s]+)") +_CHOSEN_PATTERN = re.compile(r"FW Chosen Algorithm:\s*([^,\s]+)\s*,\s*[^,]*,\s*([0-9.eE+-]+)") +_MIOPEN_PREFIX = "MIOpen(HIP):" +_logging_capture = None + + +def _forward_stderr(fd, line): + data = line if line.endswith(b"\n") else line + b"\n" + while data: + written = os.write(fd, data) + data = data[written:] + + +def _process_line(line, saved_stderr): + text = line.decode(errors="replace").rstrip("\r\n") + if not text.lstrip().startswith(_MIOPEN_PREFIX): + _forward_stderr(saved_stderr, line) + return + match = _CHOSEN_PATTERN.search(text) + if match: + log.info(f'MIOpen: algorithm={match.group(1)} time={float(match.group(2)):.3f}') + + +class MIOpenLogRedirect: + """Redirect native MIOpen diagnostics into structured informational logs.""" + + def __init__(self): + self.read_fd = -1 + self.saved_stderr = -1 + self.saved_python_stderr = sys.stderr + self.safe_stderr = None + self.reader = None + + def __enter__(self): + write_fd = -1 + try: + self.read_fd, write_fd = os.pipe() + self.saved_stderr = os.dup(2) + self.saved_python_stderr = sys.stderr + self.safe_stderr = os.fdopen(os.dup(self.saved_stderr), "w", encoding=getattr(sys.stderr, "encoding", None) or "utf-8", buffering=1) + os.dup2(write_fd, 2) + os.close(write_fd) + write_fd = -1 + sys.stderr = self.safe_stderr + + def read_output(): + pending = b"" + while True: + chunk = os.read(self.read_fd, 4096) + if not chunk: + break + pending += chunk + while b"\n" in pending: + line, pending = pending.split(b"\n", 1) + _process_line(line + b"\n", self.saved_stderr) + if pending: + _process_line(pending, self.saved_stderr) + + self.reader = threading.Thread(target=read_output, daemon=True) + self.reader.start() + return self + except Exception: + if write_fd >= 0: + os.close(write_fd) + if self.saved_stderr >= 0: + os.dup2(self.saved_stderr, 2) + sys.stderr = self.saved_python_stderr + if self.safe_stderr is not None: + self.safe_stderr.close() + if self.reader is not None: + self.reader.join() + if self.saved_stderr >= 0: + os.close(self.saved_stderr) + if self.read_fd >= 0: + os.close(self.read_fd) + raise + + def __exit__(self, _exc_type, _exc_value, _traceback): + os.dup2(self.saved_stderr, 2) + sys.stderr = self.saved_python_stderr + self.safe_stderr.close() + self.reader.join() + os.close(self.saved_stderr) + os.close(self.read_fd) + return False + + +def start_miopen_logging(): + """Start filtering native MIOpen diagnostics without changing the environment.""" + global _logging_capture # pylint: disable=global-statement + if _logging_capture is None: + try: + _logging_capture = MIOpenLogRedirect() + _logging_capture.__enter__() + except Exception as err: + log.warning(f'MIOpen logging: failed to start: {err}') + _logging_capture = None + + +def stop_miopen_logging(): + """Stop filtering native MIOpen diagnostics and restore stderr.""" + global _logging_capture # pylint: disable=global-statement + if _logging_capture is not None: + _logging_capture.__exit__(None, None, None) + _logging_capture = None + +atexit.register(stop_miopen_logging) + + +class MIOpenLogCapture: + """Capture one native MIOpen operation and log its selected algorithm and time.""" + + def __init__(self, operation: str = "convolution", repeats: int = 1): + self.operation = operation + self.repeats = max(1, repeats) + self.lines: list[str] = [] + self.elapsed_ms = 0.0 + self.algorithms: list[str] = [] + self.read_fd = -1 + self.saved_stderr = -1 + self.saved_python_stderr = sys.stderr + self.safe_stderr = None + self.start = 0.0 + self.reader = None + + def __enter__(self): + write_fd = -1 + try: + self.read_fd, write_fd = os.pipe() + self.saved_stderr = os.dup(2) + self.saved_python_stderr = sys.stderr + self.safe_stderr = os.fdopen( + os.dup(self.saved_stderr), + "w", + encoding=getattr(sys.stderr, "encoding", None) or "utf-8", + buffering=1, + ) + os.dup2(write_fd, 2) + os.close(write_fd) + write_fd = -1 + sys.stderr = self.safe_stderr + self.lines = [] + self.start = time.perf_counter() + + def read_output(): + chunks = [] + while True: + chunk = os.read(self.read_fd, 4096) + if not chunk: + break + chunks.append(chunk) + self.lines.extend(b"".join(chunks).decode(errors="replace").splitlines()) + + self.reader = threading.Thread(target=read_output, daemon=True) + self.reader.start() + return self + except Exception: + if write_fd >= 0: + os.close(write_fd) + if self.saved_stderr >= 0: + os.dup2(self.saved_stderr, 2) + sys.stderr = self.saved_python_stderr + if self.safe_stderr is not None: + self.safe_stderr.close() + if self.reader is not None: + self.reader.join() + if self.saved_stderr >= 0: + os.close(self.saved_stderr) + if self.read_fd >= 0: + os.close(self.read_fd) + raise + + def __exit__(self, _exc_type, _exc_value, _traceback): + os.dup2(self.saved_stderr, 2) + sys.stderr = self.saved_python_stderr + self.safe_stderr.close() + os.close(self.saved_stderr) + + self.reader.join() + os.close(self.read_fd) + return False + + +def capture_miopen(operation: str = "convolution", repeats: int = 1): + """Return a side-effect-free context manager for one MIOpen operation.""" + return MIOpenLogCapture(operation=operation, repeats=repeats) diff --git a/scripts/rocm/rocm_mgr.py b/scripts/rocm/rocm_mgr.py index feb7e925b..aef5b6ae0 100644 --- a/scripts/rocm/rocm_mgr.py +++ b/scripts/rocm/rocm_mgr.py @@ -11,6 +11,7 @@ from modules.shared import opts from scripts.rocm.rocm_vars import ROCM_ENV_VARS # pylint: disable=no-name-in-module from scripts.rocm import rocm_profiles # pylint: disable=no-name-in-module +from scripts.rocm import rocm_log # pylint: disable=no-name-in-module CONFIG = Path(os.path.abspath(os.path.join('data', 'rocm.json'))) @@ -269,10 +270,16 @@ def apply_env(config: Optional[Dict[str, str]] = None) -> None: if unavailable: for var in unavailable: os.environ[var] = "0" - dtype_str = _resolve_dtype() - if dtype_str in ('FP16', 'BF16'): - for var in _FP32_ONLY_SOLVERS: - os.environ[var] = "0" + + +def start_miopen_logging() -> None: + """Start explicit MIOpen diagnostic capture for a scoped operation.""" + rocm_log.start_miopen_logging() + + +def stop_miopen_logging() -> None: + """Stop explicit MIOpen diagnostic capture and restore stderr.""" + rocm_log.stop_miopen_logging() def apply_all(names: list, values: list) -> None: @@ -333,6 +340,17 @@ def clear_env() -> None: log.info(f'ROCm clear_env: cleared={cleared}') +def _miopen_user_db_path() -> Path: + """Resolve the MIOpen user DB path for the current platform.""" + configured = os.environ.get("MIOPEN_USER_DB_PATH", "") + if configured: + return Path(os.path.expandvars(os.path.expanduser(configured))) + if sys.platform == "win32": + return Path.home() / ".miopen" / "db" + cache_home = os.environ.get("XDG_CACHE_HOME", str(Path.home() / ".cache")) + return Path(cache_home) / "miopen" + + def delete_config() -> None: """Delete the saved config file, clear all vars, and wipe the MIOpen user DB cache.""" import shutil # pylint: disable=import-outside-toplevel @@ -342,8 +360,8 @@ def delete_config() -> None: CONFIG.unlink() log.info(f'ROCm delete_config: deleted {CONFIG}') _cache = None - # Delete the MIOpen user DB (~/.miopen/db) - stale entries can cause solver mismatches - miopen_db = Path(os.path.expanduser('~')) / '.miopen' / 'db' + # Delete the MIOpen user DB - stale entries can cause solver mismatches. + miopen_db = _miopen_user_db_path() if miopen_db.exists(): shutil.rmtree(miopen_db, ignore_errors=True) log.info(f'ROCm delete_config: wiped MIOpen user DB at {miopen_db}') @@ -492,8 +510,8 @@ def info() -> dict: else: sdb["exists"] = False - # --- User DB (~/.miopen/db) --- - user_db_path = Path.home() / ".miopen" / "db" + # --- User DB --- + user_db_path = _miopen_user_db_path() udb = {"path": str(user_db_path), "exists": user_db_path.exists()} if user_db_path.exists(): ufiles = _user_db_summary(user_db_path) @@ -520,9 +538,21 @@ def info() -> dict: } -# Apply saved config to os.environ at import time (only when ROCm is present) -if installer.torch_info.get('type', None) == 'rocm' and CONFIG.exists(): +def _is_rocm_runtime() -> bool: + if installer.torch_info.get('type', None) == 'rocm': + return True try: - apply_env() + import torch # pylint: disable=import-outside-toplevel + return bool(getattr(torch.version, 'hip', None)) + except Exception: + return False + + +# Apply saved config to os.environ at import time (only when ROCm is present). +if _is_rocm_runtime(): + try: + if CONFIG.exists(): + apply_env() + rocm_log.start_miopen_logging() except Exception as _e: log.debug(f"[rocm_mgr] Warning: failed to apply env at import: {_e}") diff --git a/scripts/rocm/rocm_vars.py b/scripts/rocm/rocm_vars.py index c40e343b0..13bf66b89 100644 --- a/scripts/rocm/rocm_vars.py +++ b/scripts/rocm/rocm_vars.py @@ -288,63 +288,12 @@ SOLVER_DTYPE_TAGS: Dict[str, str] = { "MIOPEN_DEBUG_CK_DEFAULT_KERNELS": "FP16/BF16/FP32", } -# Build full merged var registry +# Solver controls are currently hidden. Keep their metadata above for reference, but do not +# expose or apply it through the active ROCm configuration registry. ROCM_ENV_VARS: Dict[str, Dict[str, Any]] = {} ROCM_ENV_VARS.update(GENERAL_VARS) -for _var, _desc in _SOLVER_DESCS.items(): - ROCM_ENV_VARS[_var] = { - "default": "0" if _var in SOLVER_DISABLED_BY_DEFAULT else "1", - "desc": _desc, - "widget": "checkbox", - "options": None, - "dtype": SOLVER_DTYPE_TAGS.get(_var), - "restart_required": False, - } -# UI group ordering for solver sections -SOLVER_GROUPS: List[Tuple[str, List[str]]] = [ - ("Algorithm/Solver Group Enables", [ - "MIOPEN_DEBUG_CONV_FFT", "MIOPEN_DEBUG_CONV_DIRECT", "MIOPEN_DEBUG_CONV_GEMM", - "MIOPEN_DEBUG_CONV_WINOGRAD", "MIOPEN_DEBUG_CONV_IMPLICIT_GEMM", - ]), - ("Immediate Fallback Mode", [ - "MIOPEN_DEBUG_CONV_IMMED_FALLBACK", "MIOPEN_DEBUG_ENABLE_AI_IMMED_MODE_FALLBACK", - "MIOPEN_DEBUG_FORCE_IMMED_MODE_FALLBACK", - ]), - ("Build Method Toggles", [ - "MIOPEN_DEBUG_GCN_ASM_KERNELS", "MIOPEN_DEBUG_HIP_KERNELS", - "MIOPEN_DEBUG_OPENCL_CONVOLUTIONS", "MIOPEN_DEBUG_OPENCL_WAVE64_NOWGP", - "MIOPEN_DEBUG_ATTN_SOFTMAX", - ]), - ("Direct ASM Solver Toggles", [ - "MIOPEN_DEBUG_CONV_DIRECT_ASM_3X3U", "MIOPEN_DEBUG_CONV_DIRECT_ASM_1X1U", - "MIOPEN_DEBUG_CONV_DIRECT_ASM_1X1UV2", - "MIOPEN_DEBUG_CONV_DIRECT_ASM_1X1U_SEARCH_OPTIMIZED", "MIOPEN_DEBUG_CONV_DIRECT_ASM_1X1U_AI_HEUR", - ]), - ("Direct OpenCL Solver Toggles", [ - "MIOPEN_DEBUG_CONV_DIRECT_OCL_FWD", "MIOPEN_DEBUG_CONV_DIRECT_OCL_FWD1X1", - ]), - ("Winograd Solver Toggles", [ - "MIOPEN_DEBUG_AMD_WINOGRAD_3X3", "MIOPEN_DEBUG_AMD_WINOGRAD_RXS", - "MIOPEN_DEBUG_AMD_WINOGRAD_RXS_FWD_BWD", - "MIOPEN_DEBUG_AMD_WINOGRAD_RXS_F3X2", "MIOPEN_DEBUG_AMD_WINOGRAD_RXS_F2X3", - "MIOPEN_DEBUG_AMD_WINOGRAD_RXS_F2X3_G1", "MIOPEN_DEBUG_AMD_FUSED_WINOGRAD", - "MIOPEN_DEBUG_AMD_WINOGRAD_FURY_RXS_F2X3", - "MIOPEN_DEBUG_AMD_WINOGRAD_FURY_RXS_F3X2", "MIOPEN_DEBUG_AMD_WINOGRAD_RAGE_RXS_F2X3", - ]), - ("Multi-pass Winograd Toggles", [ - "MIOPEN_DEBUG_AMD_WINOGRAD_MPASS_F3X2", "MIOPEN_DEBUG_AMD_WINOGRAD_MPASS_F3X3", - ]), - ("Implicit GEMM Toggles", [ - "MIOPEN_DEBUG_CONV_IMPLICIT_GEMM_ASM_FWD_V4R1", "MIOPEN_DEBUG_CONV_IMPLICIT_GEMM_ASM_FWD_V4R1_1X1", - "MIOPEN_DEBUG_CONV_IMPLICIT_GEMM_HIP_FWD_V4R1", "MIOPEN_DEBUG_CONV_IMPLICIT_GEMM_HIP_FWD_V4R4", - ]), - ("Group Conv / CK Toggles (RDNA3/4+)", [ - "MIOPEN_DEBUG_GROUP_CONV_IMPLICIT_GEMM_HIP_FWD_XDLOPS", - "MIOPEN_DEBUG_GROUP_CONV_IMPLICIT_GEMM_HIP_FWD_XDLOPS_AI_HEUR", - "MIOPEN_DEBUG_CK_DEFAULT_KERNELS", - ]), -] +SOLVER_GROUPS: List[Tuple[str, List[str]]] = [] # Variables that are relevant only when hipBLASLt is the active GEMM backend. # These are visually greyed-out in the UI when rocBLAS (MIOPEN_GEMM_ENFORCE_BACKEND="1") is selected. diff --git a/scripts/rocm_ext.py b/scripts/rocm_ext.py index 463b186b2..f306e2a12 100644 --- a/scripts/rocm_ext.py +++ b/scripts/rocm_ext.py @@ -47,8 +47,8 @@ class ROCmScript(scripts_manager.Script): section("ROCm / HIP") for k, v in d.get("rocm", {}).items(): row(k, v) - section("User DB (~/.miopen/db)") udb = d.get("user_db", {}) + section("User DB") row("path", udb.get("path", "")) for fname, finfo in udb.get("files", {}).items(): row(fname, finfo) @@ -72,10 +72,6 @@ class ROCmScript(scripts_manager.Script): btn_reset = gr.Button("Defaults", elem_id="rocm_btn_reset", size="sm") btn_clear = gr.Button("Clear Run Vars", elem_id="rocm_btn_clear", size="sm") btn_delete = gr.Button("Delete UserDb", variant="stop", elem_id="rocm_btn_delete", size="sm") - with gr.Row(): - btn_rdna2 = gr.Button("RDNA2 (RX 6000)", elem_id="rocm_btn_rdna2") - btn_rdna3 = gr.Button("RDNA3 (RX 7000)", elem_id="rocm_btn_rdna3") - btn_rdna4 = gr.Button("RDNA4 (RX 9000)", elem_id="rocm_btn_rdna4") _init_gemm = config.get("MIOPEN_GEMM_ENFORCE_BACKEND", "1") _init_arch = config.get(rocm_mgr._ARCH_KEY, "") _init_unavailable = rocm_profiles.UNAVAILABLE.get(_init_arch, set()) if _init_arch else set() @@ -91,15 +87,15 @@ class ROCmScript(scripts_manager.Script): components.append(comp) # Solver groups (all checkboxes, grouped by section) - for group_name, varlist in rocm_vars.SOLVER_GROUPS: - with gr.Group(): - gr.HTML(f"

{group_name}


") - for name in varlist: - meta = rocm_vars.ROCM_ENV_VARS[name] - comp = _make_component(name, meta, config) - var_names.append(name) - components.append(comp) - gr.HTML("

") + # for group_name, varlist in rocm_vars.SOLVER_GROUPS: + # with gr.Group(): + # gr.HTML(f"

{group_name}


") + # for name in varlist: + # meta = rocm_vars.ROCM_ENV_VARS[name] + # comp = _make_component(name, meta, config) + # var_names.append(name) + # components.append(comp) + # gr.HTML("

") def _autosave_field(name, value): meta = rocm_vars.ROCM_ENV_VARS[name] @@ -209,30 +205,10 @@ class ROCmScript(scripts_manager.Script): result.append(gr.update(value="")) return result - def profile_fn(arch): - rocm_mgr.apply_profile(arch) - updated = rocm_mgr.load_config() - unavailable = rocm_profiles.UNAVAILABLE.get(arch, set()) - gemm_val = updated.get("MIOPEN_GEMM_ENFORCE_BACKEND", "1") - result = [gr.update(value=_build_style(unavailable, gemm_val == "1"))] - for pname in var_names: - meta = rocm_vars.ROCM_ENV_VARS[pname] - val = updated.get(pname, meta["default"]) - if meta["widget"] == "checkbox": - result.append(gr.update(value=val == "1")) - elif meta["widget"] == "dropdown": - result.append(gr.update(value=rocm_mgr._dropdown_display(val, meta["options"]))) - else: - result.append(gr.update(value=rocm_mgr._expand_venv(val))) - return result - btn_info.click(fn=_info_html, inputs=[], outputs=[info_out], show_progress='hidden') btn_apply.click(fn=apply_fn, inputs=components, outputs=[style_out] + components, show_progress='hidden') btn_reset.click(fn=reset_fn, inputs=[], outputs=[style_out] + components, show_progress='hidden') btn_clear.click(fn=clear_fn, inputs=[], outputs=[style_out] + components, show_progress='hidden') btn_delete.click(fn=delete_fn, inputs=[], outputs=[style_out] + components, show_progress='hidden') - btn_rdna2.click(fn=lambda: profile_fn("RDNA2"), inputs=[], outputs=[style_out] + components, show_progress='hidden') - btn_rdna3.click(fn=lambda: profile_fn("RDNA3"), inputs=[], outputs=[style_out] + components, show_progress='hidden') - btn_rdna4.click(fn=lambda: profile_fn("RDNA4"), inputs=[], outputs=[style_out] + components, show_progress='hidden') return components diff --git a/scripts/softfill.py b/scripts/softfill.py index 35b2348e9..ac99afa9f 100644 --- a/scripts/softfill.py +++ b/scripts/softfill.py @@ -964,7 +964,7 @@ class StableDiffusionXLSoftFillPipeline( aesthetic_score: float = 6.0, negative_aesthetic_score: float = 2.5, clip_skip: Optional[int] = None, - callback_on_step_end: Optional[Callable[[int, int, Dict], None]] = None, + callback_on_step_end: Optional[Callable[..., Dict]] = None, # invoked as (self, step_index, timestep, callback_kwargs) -> dict callback_on_step_end_tensor_inputs: List[str] = ["latents"], **kwargs, ): diff --git a/scripts/ultimate-upscale.py b/scripts/ultimate-upscale.py index f620945f7..b87eb2f2a 100644 --- a/scripts/ultimate-upscale.py +++ b/scripts/ultimate-upscale.py @@ -409,7 +409,7 @@ class UltimateSDUpscaleScript(scripts_manager.Script): def title(self): return "SD Ultimate Upscale" - def show(self, is_img2img): + def show(self, is_img2img): # pylint: disable=unused-argument return True def ui(self, is_img2img): # pylint: disable=unused-argument diff --git a/scripts/xyz/xyz_grid_classes.py b/scripts/xyz/xyz_grid_classes.py index 2da29d7b3..ba7b0ccd1 100644 --- a/scripts/xyz/xyz_grid_classes.py +++ b/scripts/xyz/xyz_grid_classes.py @@ -3,6 +3,10 @@ from scripts.xyz.xyz_grid_shared import ( # pylint: disable=no-name-in-module, u apply_task_arg, apply_task_args, apply_setting, + apply_attention, + apply_attention_dispatcher, + save_attention, + restore_attention, apply_prompt_primary, apply_prompt_refine, apply_prompt_detailer, @@ -19,6 +23,9 @@ from scripts.xyz.xyz_grid_shared import ( # pylint: disable=no-name-in-module, u list_lora, apply_lora, apply_lora_strength, + list_lora_blocks, + apply_lora_blocks, + format_value_trim, apply_te, apply_guidance, apply_styles, @@ -40,7 +47,7 @@ from scripts.xyz.xyz_grid_shared import ( # pylint: disable=no-name-in-module, u format_nothing, str_permutations, ) -from modules import shared, shared_items, sd_samplers, ipadapter, sd_models, sd_vae, sd_unet +from modules import shared, shared_items, sd_samplers, ipadapter, sd_models, sd_vae, sd_unet, attention, modular_guiders from modules.control.units import controlnet, t2iadapter from modules.control import processor @@ -104,9 +111,15 @@ class SharedSettingsStackHelper(): todo_ratio = None teacache_thresh = None extra_networks_default_multiplier = None + lora_force_diffusers = None + lora_stack_mode = None + lora_stack_density = None + lora_stack_alpha = None + lora_stack_discrepancy = None disable_apply_metadata = None disable_apply_params = None sdnq_quant_mode = None + attention_settings = None def __enter__(self): # Save overridden settings so they can be restored later @@ -136,10 +149,16 @@ class SharedSettingsStackHelper(): self.sd_unet = shared.opts.sd_unet self.sd_text_encoder = shared.opts.sd_text_encoder self.extra_networks_default_multiplier = shared.opts.extra_networks_default_multiplier + self.lora_force_diffusers = shared.opts.lora_force_diffusers + self.lora_stack_mode = shared.opts.lora_stack_mode + self.lora_stack_density = shared.opts.lora_stack_density + self.lora_stack_alpha = shared.opts.lora_stack_alpha + self.lora_stack_discrepancy = shared.opts.lora_stack_discrepancy self.teacache_thresh = shared.opts.teacache_thresh self.disable_apply_metadata = shared.opts.disable_apply_metadata self.disable_apply_params = shared.opts.disable_apply_params self.sdnq_quant_mode = shared.opts.sdnq_quantize_weights_mode + self.attention_settings = save_attention() shared.opts.data["disable_apply_metadata"] = [] shared.opts.data["disable_apply_params"] = '' @@ -148,6 +167,11 @@ class SharedSettingsStackHelper(): shared.opts.data["disable_apply_metadata"] = self.disable_apply_metadata shared.opts.data["disable_apply_params"] = self.disable_apply_params shared.opts.data["extra_networks_default_multiplier"] = self.extra_networks_default_multiplier + shared.opts.data["lora_force_diffusers"] = self.lora_force_diffusers + shared.opts.data["lora_stack_mode"] = self.lora_stack_mode + shared.opts.data["lora_stack_density"] = self.lora_stack_density + shared.opts.data["lora_stack_alpha"] = self.lora_stack_alpha + shared.opts.data["lora_stack_discrepancy"] = self.lora_stack_discrepancy shared.opts.data["prompt_attention"] = self.prompt_attention shared.opts.data["schedulers_solver_order"] = self.schedulers_solver_order shared.opts.data["schedulers_sigma_adjust"] = self.schedulers_sigma_adjust @@ -188,6 +212,7 @@ class SharedSettingsStackHelper(): if self.sdnq_quant_mode != shared.opts.sdnq_quantize_weights_mode: shared.opts.data["sdnq_quantize_weights_mode"] = self.sdnq_quant_mode sd_models.reload_model_weights(op='model') + restore_attention(self.attention_settings) axis_options = [ @@ -195,7 +220,7 @@ axis_options = [ AxisOption("[Model] Model", str, apply_checkpoint, cost=1.0, fmt=format_value_add_label, choices=lambda: sorted(sd_models.checkpoints_list)), AxisOption("[Model] UNET", str, apply_unet, cost=0.8, choices=lambda: ['None'] + list(sd_unet.unet_dict)), AxisOption("[Model] VAE", str, apply_vae, cost=0.6, choices=lambda: ['None'] + list(sd_vae.vae_dict)), - AxisOption("[Model] Refiner", str, apply_refiner, cost=0.8, fmt=format_value_add_label, choices=lambda: ['None'] + sorted(sd_models.checkpoints_list)), + AxisOption("[Model] Refiner", str, apply_refiner, cost=0.9, fmt=format_value_add_label, choices=lambda: ['None'] + sorted(sd_models.checkpoints_list)), AxisOption("[Model] Text encoder", str, apply_te, cost=0.7, choices=shared_items.sd_te_items), AxisOption("[Prompt] Search & replace", str, apply_prompt_primary, fmt=format_value_add_label), AxisOption("[Prompt] Search & replace refine", str, apply_prompt_refine, fmt=format_value_add_label), @@ -203,8 +228,14 @@ axis_options = [ AxisOption("[Prompt] Search & replace all", str, apply_prompt_all, fmt=format_value_add_label), AxisOption("[Prompt] Prompt order", str_permutations, apply_order, fmt=format_value_join_list), AxisOption("[Prompt] Prompt parser", str, apply_setting("prompt_attention"), choices=lambda: ["native", "compel", "xhinker", "a1111", "fixed"]), - AxisOption("[Network] LoRA", str, apply_lora, cost=0.5, choices=list_lora), - AxisOption("[Network] LoRA strength", float, apply_lora_strength, cost=0.6), + AxisOption("[Network] LoRA", str, apply_lora, cost=0.6, choices=list_lora), + AxisOption("[Network] LoRA strength", float, apply_lora_strength, cost=0.5), + AxisOption("[Network] LoRA block weight", str, apply_lora_blocks, cost=0.5, fmt=format_value_trim, choices=list_lora_blocks), + AxisOption("[Network] LoRA stack mode", str, apply_setting("lora_stack_mode"), cost=0.5, choices=lambda: ["sum", "ties", "dare_ties", "dare_linear", "magnitude_prune", "klora", "estlora"]), + AxisOption("[Network] LoRA stack density", float, apply_setting("lora_stack_density"), cost=0.5), + AxisOption("[Network] LoRA stack ramp", float, apply_setting("lora_stack_alpha"), cost=0.5), + AxisOption("[Network] LoRA stack discrepancy", float, apply_setting("lora_stack_discrepancy"), cost=0.5), + AxisOption("[Network] LoRA force diffusers", bool, apply_setting("lora_force_diffusers"), cost=0.65, choices=lambda: [False, True]), AxisOption("[Network] Styles", str, apply_styles, choices=lambda: [s.name for s in shared.prompt_styles.styles.values()]), AxisOption("[Param] Width", int, apply_field("width")), AxisOption("[Param] Height", int, apply_field("height")), @@ -233,12 +264,13 @@ axis_options = [ AxisOption("[Sampler] Max shift", float, apply_setting("schedulers_max_shift")), AxisOption("[Sampler] ETA delta", float, apply_setting("eta_noise_seed_delta")), AxisOption("[Sampler] ETA multiplier", float, apply_setting("scheduler_eta")), + AxisOption("[Guidance] Name", str, apply_field("cfg_name"), cost=0.2, choices=lambda: list(modular_guiders.guiders.keys())), AxisOption("[Guidance] Scale", float, apply_field("cfg_scale")), - AxisOption("[Guidance] End", float, apply_field("cfg_end")), - AxisOption("[Guidance] Image scale", float, apply_field("cfg_image")), AxisOption("[Guidance] Rescale", float, apply_field("cfg_rescale")), - AxisOption("[Guidance] Modular name", str, apply_guidance, choices=lambda: ['Default', 'CFG', 'Auto', 'Zero', 'PAG', 'APG', 'SLG', 'SEG', 'TCFG', 'FDG']), - AxisOption("[Refine] Upscaler", str, apply_field("hr_upscaler"), cost=0.3, choices=lambda: [x.name for x in shared.sd_upscalers]), + AxisOption("[Guidance] Start", float, apply_field("cfg_start")), + AxisOption("[Guidance] Stop", float, apply_field("cfg_stop")), + AxisOption("[Guidance] Image scale", float, apply_field("cfg_image")), + AxisOption("[Refine] Upscaler", str, apply_field("hr_upscaler"), cost=0.4, choices=lambda: [x.name for x in shared.sd_upscalers]), AxisOption("[Refine] Sampler", str, apply_hr_sampler_name, fmt=format_value_add_label, confirm=confirm_samplers, choices=lambda: [x.name for x in sd_samplers.visible_samplers()]), AxisOption("[Refine] Denoising strength", float, apply_field("denoising_strength")), AxisOption("[Refine] Hires steps", int, apply_field("hr_second_pass_steps")), @@ -248,8 +280,21 @@ axis_options = [ AxisOption("[Postprocess] Context", str, apply_context, choices=lambda: ["Add with forward", "Remove with forward", "Add with backward", "Remove with backward"]), AxisOption("[Postprocess] Detailer", bool, apply_detailer, fmt=format_bool, choices=lambda: [False, True]), AxisOption("[Postprocess] Detailer strength", str, apply_field("detailer_strength")), - AxisOption("[Quant] SDNQ quant mode", str, apply_sdnq_quant, cost=0.9, fmt=format_value_add_label, choices=lambda: ['none'] + sorted(shared_items.sdnq_quant_modes)), - AxisOption("[Quant] SDNQ quant mode TE", str, apply_sdnq_quant_te, cost=0.9, fmt=format_value_add_label, choices=lambda: ['none'] + sorted(shared_items.sdnq_quant_modes)), + AxisOption("[Quant] SDNQ quant mode", str, apply_sdnq_quant, cost=0.85, fmt=format_value_add_label, choices=lambda: ['none'] + sorted(shared_items.sdnq_quant_modes)), + AxisOption("[Quant] SDNQ quant mode TE", str, apply_sdnq_quant_te, cost=0.85, fmt=format_value_add_label, choices=lambda: ['none'] + sorted(shared_items.sdnq_quant_modes)), + AxisOption("[Attention] Method", str, apply_setting('cross_attention_optimization'), cost=0.4, choices=shared_items.list_crossattention), + AxisOption("[Attention] Dispatcher", str, apply_attention_dispatcher, cost=0.4, choices=lambda: ['None'] + attention.list_dispatcher_backends()), + AxisOption("[Attention] SDNQ matmul", str, apply_attention('sdnq_attention_matmul_type'), cost=0.4, choices=lambda: list(shared_items.sdnq_matmul_modes)), + AxisOption("[Attention] SDNQ PV matmul", str, apply_attention('sdnq_attention_pv_matmul_type'), cost=0.4, choices=lambda: list(shared_items.sdnq_matmul_modes)), + AxisOption("[Attention] SDNQ smooth K", str, apply_attention('sdnq_attention_smooth_k'), cost=0.4, choices=lambda: ['False', 'True']), + AxisOption("[Attention] SDNQ hadamard", str, apply_attention('sdnq_attention_use_hadamard'), cost=0.4, choices=lambda: ['False', 'True']), + AxisOption("[Attention] SDNQ fp16 accumulation", str, apply_attention('sdnq_attention_use_fp16_accum'), cost=0.4, choices=lambda: ['False', 'True']), + AxisOption("[Sparse] Enabled", str, apply_attention('sparse_attention_enabled'), cost=0.3, choices=lambda: ['False', 'True']), + AxisOption("[Sparse] KV budget", int, apply_attention('sparse_attention_budget'), cost=0.3), + AxisOption("[Sparse] Minimum sequence", int, apply_attention('sparse_attention_min_tokens'), cost=0.3), + AxisOption("[Sparse] Dense steps", int, apply_attention('sparse_attention_schedule_steps'), cost=0.3), + AxisOption("[Sparse] Dense step bonus", int, apply_attention('sparse_attention_schedule_bump'), cost=0.3), + AxisOption("[Sparse] Shared heads", str, apply_attention('sparse_attention_head_shared'), cost=0.3, choices=lambda: ['False', 'True']), AxisOption("[HDR] Mode", int, apply_field("hdr_mode")), AxisOption("[HDR] Brightness", float, apply_field("hdr_brightness")), AxisOption("[HDR] Color", float, apply_field("hdr_color")), @@ -266,13 +311,13 @@ axis_options = [ AxisOption("[FreeU] 2nd stage backbone factor", float, apply_setting('freeu_b2')), AxisOption("[FreeU] 1st stage skip factor", float, apply_setting('freeu_s1')), AxisOption("[FreeU] 2nd stage skip factor", float, apply_setting('freeu_s2')), - AxisOption("[IP adapter] Name", str, apply_field('ip_adapter_names'), cost=1.0, choices=lambda: list(ipadapter.ADAPTERS)), + AxisOption("[IP adapter] Name", str, apply_field('ip_adapter_names'), cost=0.6, choices=lambda: list(ipadapter.ADAPTERS)), AxisOption("[IP adapter] Scale", float, apply_field('ip_adapter_scales')), AxisOption("[IP adapter] Starts", float, apply_field('ip_adapter_starts')), AxisOption("[IP adapter] Ends", float, apply_field('ip_adapter_ends')), - AxisOption("[Control] ControlNet", str, apply_control('controlnet'), cost=0.9, choices=lambda: list(controlnet.all_models)), - AxisOption("[Control] T2IAdapter", str, apply_control('t2i adapter'), cost=0.9, choices=lambda: list(t2iadapter.all_models)), - AxisOption("[Control] Processor", str, apply_control('processor'), cost=0.6, choices=lambda: processor.processors), + AxisOption("[Control] ControlNet", str, apply_control('controlnet'), cost=0.7, choices=lambda: list(controlnet.all_models)), + AxisOption("[Control] T2IAdapter", str, apply_control('t2i adapter'), cost=0.7, choices=lambda: list(t2iadapter.all_models)), + AxisOption("[Control] Processor", str, apply_control('processor'), cost=0.4, choices=lambda: processor.processors), AxisOption("[Control] Strength", float, apply_control('control_strength')), AxisOption("[Control] Start", float, apply_control('control_start')), AxisOption("[Control] End", float, apply_control('control_end')), diff --git a/scripts/xyz/xyz_grid_draw.py b/scripts/xyz/xyz_grid_draw.py index 10477fc7c..2f6271bbc 100644 --- a/scripts/xyz/xyz_grid_draw.py +++ b/scripts/xyz/xyz_grid_draw.py @@ -117,6 +117,7 @@ def draw_xyz_grid(p, xs, ys, zs, x_labels, y_labels, z_labels, cell, draw_legend continue if (not no_grid or include_sub_grids) and images.check_grid_size(to_process): grid = images.image_grid(to_process, rows=len(ys)) + p.is_grid = True if draw_legend: grid = images.draw_grid_annotations(grid, w, h, x_texts, y_texts, margin_size, title=z_texts[i]) processed_result.images.insert(i, grid) @@ -124,6 +125,7 @@ def draw_xyz_grid(p, xs, ys, zs, x_labels, y_labels, z_labels, cell, draw_legend processed_result.all_seeds.insert(i, processed_result.all_seeds[idx0]) processed_result.infotexts.insert(i, processed_result.infotexts[idx0]) if len(zs) > 1 and not no_grid and images.check_grid_size(processed_result.images[:len(zs)]): # create grid-of-grids + p.is_grid = True grid = images.image_grid(processed_result.images[:len(zs)], rows=1) processed_result.images.insert(0, grid) processed_result.all_prompts.insert(0, processed_result.all_prompts[0]) diff --git a/scripts/xyz/xyz_grid_shared.py b/scripts/xyz/xyz_grid_shared.py index b90d37848..fb90d4258 100644 --- a/scripts/xyz/xyz_grid_shared.py +++ b/scripts/xyz/xyz_grid_shared.py @@ -72,15 +72,76 @@ def apply_setting(field): def fun(p, x, xs): t = type(shared.opts.get(field)) if t == bool: - if isinstance(x, str): - x = x.lower() in ['true', 't', 'yes', 'y'] - if isinstance(x, int) or isinstance(x, float): + if isinstance(x, bool): + x = bool(x) + elif isinstance(x, str): + x = x.lower() in ['true', 't', 'yes', 'y', 'on'] + elif isinstance(x, int) or isinstance(x, float): x = x > 0 + else: + x = False + elif t == int: + x = int(x) + elif t == float: + x = float(x) + elif t == str: + x = str(x) log.debug(f'XYZ grid apply setting: {field}={t}:{x}') shared.opts.data[field] = x return fun +def attention_options() -> list: + """Attention settings an axis can change; the stack helper restores exactly this set.""" + from modules import attention + return ['cross_attention_optimization', 'hf_attention', *attention.reapply_options()] + + +def apply_attention(field): + def fun(p, x, xs): + from modules import attention + apply_setting(field)(p, x, xs) + attention.reapply() # backends read their settings when the chain is built, so a write on its own changes nothing + owner = next((backend for backend in attention.registry.backends.values() if field in backend.options), None) + plan = attention.get_plan() + if owner is not None and plan is not None and owner.name not in plan.chain(): + log.warning(f'XYZ grid apply attention: {field} is read by "{owner.label}" which is not in the active chain={plan.chain()}') + return fun + + +def apply_attention_dispatcher(p, x, xs): + from modules import attention + value = '' if str(x).strip().lower() in ['none', 'default'] else str(x).strip() + shared.opts.data['hf_attention'] = value + if shared.sd_loaded: + attention.set_attention_dispatcher(shared.sd_model) + log.debug(f'XYZ grid apply attention: dispatcher="{value}"') + + +def save_attention() -> dict: + return {field: shared.opts.data[field] for field in attention_options() if field in shared.opts.data} + + +def restore_attention(saved: dict): + """Put back whatever an attention axis changed, keys it introduced included, then rebuild what reads them.""" + from modules import attention + changed = [] + for field in attention_options(): + if (field in saved) == (field in shared.opts.data) and saved.get(field, None) == shared.opts.data.get(field, None): + continue + changed.append(field) + if field in saved: + shared.opts.data[field] = saved[field] + else: + shared.opts.data.pop(field, None) + if len(changed) == 0: + return + attention.reapply() + if 'hf_attention' in changed and shared.sd_loaded: + attention.set_attention_dispatcher(shared.sd_model) + log.debug(f'XYZ grid restore attention: {changed}') + + def apply_seed(p, x, xs): p.seed = x p.all_seeds = None @@ -260,6 +321,31 @@ def apply_lora_strength(p, x, xs): shared.opts.data['extra_networks_default_multiplier'] = x +def list_lora_blocks(): + from modules.lora import lora_blocks + from modules.merging.merge_presets import BLOCK_WEIGHTS_PRESETS, SDXL_BLOCK_WEIGHTS_PRESETS + return ['None'] + list(lora_blocks.CLASSIC) + list(lora_blocks.CHAIN_NAMES) + sorted(BLOCK_WEIGHTS_PRESETS) + sorted(SDXL_BLOCK_WEIGHTS_PRESETS) + + +re_lora_tag = re.compile(r']+)>') + + +def apply_lora_blocks(p, x, xs): + x = str(x or '').strip() + if ':' in x or '>' in x: + log.error(f'XYZ grid apply LoRA block weight: value="{x}" invalid characters') + return + def rewrite(m): + items = [i for i in m.group(1).split(':') if not i.lower().startswith('lbw=')] + if x and x.lower() != 'none': + items.append(f'lbw={x}') + return '' + p.prompt = re_lora_tag.sub(rewrite, p.prompt) + p.all_prompts = None # a populated list would shadow the edited prompt in processing + p.all_negative_prompts = None + log.debug(f'XYZ grid apply LoRA block weight: "{x}"') + + def apply_te(p, x, xs): shared.opts.data["sd_text_encoder"] = x sd_models.reload_text_encoder() @@ -383,6 +469,13 @@ def format_value_join_list(p, opt, x): return ", ".join(x) +def format_value_trim(p, opt, x): + x = str(x) + if len(x) > 40: + x = x[:37] + '...' # block-weight vectors would flood the grid legend + return f"{opt.label}: {x}" + + def do_nothing(p, x, xs): pass diff --git a/scripts/xyz_grid.py b/scripts/xyz_grid.py index 83b8db79d..1a79b5ec8 100644 --- a/scripts/xyz_grid.py +++ b/scripts/xyz_grid.py @@ -220,13 +220,18 @@ class XYZGridScript(scripts_manager.Script): valslist = [x for x in valslist_ext if x not in valslist] elif opt.type == str_permutations: # pylint: disable=comparison-with-callable valslist = list(permutations(valslist)) - valslist = [opt.type(x) for x in valslist] + elif opt.type == bool: + valslist = [str(x).strip().lower() in ['true', 't', 'yes', 'y', '1', 'on'] for x in valslist] + else: + valslist = [opt.type(x) for x in valslist] # Confirm options are valid before starting if opt.confirm: opt.confirm(p, valslist) return valslist def parse_axis(x_type, x_values, x_values_dropdown): + if x_type is None: + x_type = 0 x_opt = None if isinstance(x_type, str): x_opt = [o for o in self.current_axis_options if o.label.lower() == x_type.lower()] @@ -325,6 +330,7 @@ class XYZGridScript(scripts_manager.Script): return processing.Processed(p, [], p.seed, ""), 0 p.xyz = True pc = copy(p) + pc.network_data = None pc.override_settings_restore_afterwards = False pc.styles = pc.styles[:] x_opt.apply(pc, x, xs) diff --git a/scripts/xyz_grid_on.py b/scripts/xyz_grid_on.py index 12260e003..c45271e23 100644 --- a/scripts/xyz_grid_on.py +++ b/scripts/xyz_grid_on.py @@ -236,13 +236,18 @@ class XYZGridScript(scripts_manager.Script): valslist = [x for x in valslist_ext if x not in valslist] elif opt.type == str_permutations: # pylint: disable=comparison-with-callable valslist = list(permutations(valslist)) - valslist = [opt.type(x) for x in valslist] + elif opt.type == bool: + valslist = [str(x).strip().lower() in ['true', 't', 'yes', 'y', '1', 'on'] for x in valslist] + else: + valslist = [opt.type(x) for x in valslist] # Confirm options are valid before starting if opt.confirm: opt.confirm(p, valslist) return valslist def parse_axis(x_type, x_values, x_values_dropdown): + if x_type is None: + x_type = 0 x_opt = None if isinstance(x_type, str): x_opt = [o for o in self.current_axis_options if o.label.lower() == x_type.lower()] @@ -347,6 +352,7 @@ class XYZGridScript(scripts_manager.Script): return processing.Processed(p, [], p.seed, ""), 0 p.xyz = True pc = copy(p) + pc.network_data = None pc.override_settings_restore_afterwards = False pc.styles = pc.styles[:] if no_fixed_seeds: @@ -382,6 +388,7 @@ class XYZGridScript(scripts_manager.Script): pc.extra_generation_params["Fixed Y Values"] = ", ".join([str(y) for y in ys]) info = processing.create_infotext(pc, pc.all_prompts, pc.all_seeds, pc.all_subseeds, grid=f'{len(xs)}x{len(ys)}') grid_infotext.append(info) + if ix == 0 and iy == 0 and iz == 0 and len(zs) > 1: # create main grid info text pc.extra_generation_params = copy(pc.extra_generation_params) if z_opt.label != 'Nothing': @@ -391,6 +398,7 @@ class XYZGridScript(scripts_manager.Script): pc.extra_generation_params["Fixed Z Values"] = ", ".join([str(z) for z in zs]) info = processing.create_infotext(pc, pc.all_prompts, pc.all_seeds, pc.all_subseeds, grid=f'{len(zs)}x{len(xs)}x{len(ys)}') grid_infotext.insert(0, info) + t1 = time.time() return processed, t1-t0 diff --git a/test/test-anima-native-adapters.py b/test/test-anima-native-adapters.py index e2923ad32..dcdff5059 100644 --- a/test/test-anima-native-adapters.py +++ b/test/test-anima-native-adapters.py @@ -205,10 +205,10 @@ def build_cosmos_block(): return block -def build_mock_transformer(): +def build_mock_transformer(n_blocks=N_BLOCKS): """Mirror diffusers' Cosmos2TransformerModel top-level layout.""" transformer = _Holder() - transformer.transformer_blocks = torch.nn.ModuleList([build_cosmos_block() for _ in range(N_BLOCKS)]) + transformer.transformer_blocks = torch.nn.ModuleList([build_cosmos_block() for _ in range(n_blocks)]) # Time embedding transformer.time_embed = _Holder() @@ -338,13 +338,14 @@ class _MockAnimaSdModel: self.__class__.__name__ = 'AnimaTextToImagePipeline' -def install_mock_pipe(): +def install_mock_pipe(n_blocks=N_BLOCKS): """Set shared.sd_model to a mock exposing an Anima-shaped 3-component pipeline. Each test re-installs so stamped ``network_layer_name`` attributes from - prior tests do not leak across runs. + prior tests do not leak across runs. ``n_blocks`` sizes the DiT, which the + depth-expansion block remap reads. """ - transformer = build_mock_transformer() + transformer = build_mock_transformer(n_blocks) llm_adapter = build_mock_llm_adapter() text_encoder = build_mock_text_encoder() pipe = _MockAnimaPipeline(transformer, llm_adapter, text_encoder) @@ -821,6 +822,10 @@ def test_cosmos_rename_full_coverage(): ('blocks_0_adaln_modulation_cross_attn_2', 'transformer_blocks_0_norm2_linear_2'), ('blocks_0_adaln_modulation_mlp_1', 'transformer_blocks_0_norm3_linear_1'), ('blocks_0_adaln_modulation_mlp_2', 'transformer_blocks_0_norm3_linear_2'), + # Depth-expanded checkpoints (Anima-2.9B carries 40 blocks) + ('blocks_39_self_attn_q_proj', 'transformer_blocks_39_attn1_to_q'), + ('blocks_39_cross_attn_output_proj', 'transformer_blocks_39_attn2_to_out_0'), + ('blocks_39_mlp_layer2', 'transformer_blocks_39_ff_net_2'), ] for src, expected in cases: got = A.cosmos_rename_flat(src) @@ -837,6 +842,9 @@ def test_resolve_targets_per_prefix(): assert A.resolve_targets('diffusion_model.', 'blocks.0.self_attn.q_proj') == [ ('transformer_blocks_0_attn1_to_q', None), ] + assert A.resolve_targets('diffusion_model.', 'blocks.39.cross_attn.k_proj') == [ + ('transformer_blocks_39_attn2_to_k', None), + ] assert A.resolve_targets('diffusion_model.llm_adapter.', 'input_proj') == [ ('input_proj', None), ] @@ -1335,6 +1343,107 @@ def test_dora_square_weight_1d_defaults_to_per_input(): return True +# ============================================================ +# Tests - depth-expanded checkpoint block remap +# ============================================================ + +CAT_REMAP = category('remap') + +BASE_DEPTH = 28 +EXPANDED_DEPTH = 40 + + +def sd_lora_kohya_block(index): + """Kohya transformer LoRA on self_attn.q_proj at an arbitrary block index.""" + stem = f'lora_unet_blocks_{index}_self_attn_q_proj' + return { + f'{stem}.lora_down.weight': torch.randn(RANK, HIDDEN), + f'{stem}.lora_up.weight': torch.randn(HIDDEN, RANK), + f'{stem}.alpha': torch.tensor(float(RANK)), + } + + +def _load_at_depth(try_fn, state_dict, n_blocks, name='test'): + install_mock_pipe(n_blocks) + with TempLora(state_dict, name=name) as nod: + return try_fn(name, nod, lora_scale=1.0) + + +def test_expansion_map_matches_manifest(): + """The 28->40 table skips the author's insertion positions in order.""" + table = A.expansion_map(BASE_DEPTH, EXPANDED_DEPTH) + inserted = set(A.BLOCK_EXPANSIONS[(BASE_DEPTH, EXPANDED_DEPTH)]) + assert len(table) == BASE_DEPTH + assert set(table.values()).isdisjoint(inserted), 'no base block may land on an inserted block' + assert (table[0], table[1], table[2], table[27]) == (0, 1, 3, 39) + assert list(table.values()) == sorted(table.values()), 'order must be preserved' + return True + + +def test_expansion_map_covers_every_base_block_uniquely(): + """All base indices land on distinct blocks inside the expanded depth.""" + table = A.expansion_map(BASE_DEPTH, EXPANDED_DEPTH) + assert len(set(table.values())) == BASE_DEPTH + assert max(table.values()) < EXPANDED_DEPTH + return True + + +def test_remap_binds_last_base_block_to_top_of_expanded(): + """A 1.0 LoRA on block 27 binds to block 39 of a 40-block transformer.""" + net = _load_at_depth(A.try_load_lora, sd_lora_kohya_block(27), EXPANDED_DEPTH) + assert net is not None and len(net.modules) == 1, f'got {net.modules if net else None}' + assert 'lora_transformer_transformer_blocks_39_attn1_to_q' in net.modules + return True + + +def test_remap_leaves_blocks_before_first_insertion(): + """Blocks 0 and 1 precede the first insertion, so they do not move.""" + for i in (0, 1): + net = _load_at_depth(A.try_load_lora, sd_lora_kohya_block(i), EXPANDED_DEPTH) + assert f'lora_transformer_transformer_blocks_{i}_attn1_to_q' in net.modules + return True + + +def test_no_remap_on_base_depth_model(): + """A 28-block transformer matches no expansion entry, so indices pass through.""" + net = _load_at_depth(A.try_load_lora, sd_lora_kohya_block(1), BASE_DEPTH) + assert 'lora_transformer_transformer_blocks_1_attn1_to_q' in net.modules + return True + + +def test_no_remap_when_lora_is_native_to_expanded_depth(): + """A LoRA reaching past the base depth was trained on the expanded model.""" + sd = sd_lora_kohya_block(5) + sd.update(sd_lora_kohya_block(39)) + net = _load_at_depth(A.try_load_lora, sd, EXPANDED_DEPTH) + assert 'lora_transformer_transformer_blocks_5_attn1_to_q' in net.modules + assert 'lora_transformer_transformer_blocks_39_attn1_to_q' in net.modules + return True + + +def test_remap_leaves_adapter_and_te_indices_alone(): + """llm_adapter blocks and text encoder layers carry unrelated numbering.""" + install_mock_pipe(EXPANDED_DEPTH) + out = A.remap_blocks({ + ('lora_unet_', 'blocks_27_self_attn_q_proj'): {}, + ('diffusion_model.llm_adapter.', 'blocks.1.self_attn.q_proj'): {}, + ('lora_te_', 'layers_1_self_attn_q_proj'): {}, + }) + assert ('lora_unet_', 'blocks_39_self_attn_q_proj') in out + assert ('diffusion_model.llm_adapter.', 'blocks.1.self_attn.q_proj') in out + assert ('lora_te_', 'layers_1_self_attn_q_proj') in out + return True + + +def test_remap_handles_dotted_bfl_keys(): + """BFL keys arrive dotted rather than underscore-flattened.""" + install_mock_pipe(EXPANDED_DEPTH) + out = A.remap_blocks({('diffusion_model.', 'blocks.27.self_attn.q_proj'): {}}) + assert ('diffusion_model.', 'blocks.39.self_attn.q_proj') in out + return True + + + # ============================================================ # Test runner # ============================================================ @@ -1410,6 +1519,19 @@ def run_tests(): ]: run_test(CAT_MATH, fn) + log.warning('=== depth-expanded block remap ===') + for fn in [ + test_expansion_map_matches_manifest, + test_expansion_map_covers_every_base_block_uniquely, + test_remap_binds_last_base_block_to_top_of_expanded, + test_remap_leaves_blocks_before_first_insertion, + test_no_remap_on_base_depth_model, + test_no_remap_when_lora_is_native_to_expanded_depth, + test_remap_leaves_adapter_and_te_indices_alone, + test_remap_handles_dotted_bfl_keys, + ]: + run_test(CAT_REMAP, fn) + elapsed = time.time() - t0 log.warning('=== Results ===') total_pass = 0 diff --git a/test/test-attention-router.py b/test/test-attention-router.py new file mode 100644 index 000000000..f51b4898c --- /dev/null +++ b/test/test-attention-router.py @@ -0,0 +1,602 @@ +#!/usr/bin/env python +""" +Offline unit tests for the attention router in modules.attention. + +Covers: + +- plan construction over every subset of the sdp_overrides choices on cuda, rocm, zluda and cpu + against an oracle of the stacking order the closure hijacks used: priority, terminal selection, + platform gating +- gate parity: every backend's declared constraints against a literal transcription of the + predicate its closure carried, over a grid of shapes, dtypes, devices and masks +- every sdp_overrides choice maps to a registered backend and every backend to a choice +- router dispatch: the first accepting entry wins, the terminal receives declined calls, the + original sdpa only receives enable_gqa when it is set +- a backend whose prepare raises is skipped without disturbing the rest +- install_router leaves the original sdpa in place for an empty plan +- the dynamic backend pins the pre-dynamic sdpa the sliced path reads +- the generation context: step normalized to the forward about to run on both the classic + callback and the modular pre-hook, per-pass resets, the in-place step buffer, role scopes +- telemetry: the route observer, the chain string recorded in torch_info, report(), and the + SD_ATTN_DEBUG route log deduplication +- the escape hatches captioners and detailers depend on: bypass_sdpa_hijacks and llm_context + restore the original sdpa over the router, and put the router back even when the body raises + +No running server required. Nothing is moved to the accelerator. + +Usage: + python test/test-attention-router.py +""" + +import itertools +import logging +import os +import sys +from dataclasses import replace + +import torch + +script_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) +sys.path.insert(0, script_dir) +os.chdir(script_dir) + +os.environ['SD_INSTALL_QUIET'] = '1' + +# Bootstrap cmd_args before any module that pulls in shared.py. +import modules.cmd_args # pylint: disable=wrong-import-position +import installer # pylint: disable=wrong-import-position +orig_argv = sys.argv +sys.argv = [sys.argv[0]] +try: + modules.cmd_args.parse_args() +finally: + sys.argv = orig_argv +installer.add_args(modules.cmd_args.parser) +modules.cmd_args.parsed, _ = modules.cmd_args.parser.parse_known_args([]) + +stock_sdpa = torch.nn.functional.scaled_dot_product_attention # importing shared installs the configured hijacks in-process + +from modules.errors import log # pylint: disable=wrong-import-position +from modules import attention # pylint: disable=wrong-import-position +from modules.attention import router as attention_router # pylint: disable=wrong-import-position + + +# ============================================================ +# Test infrastructure +# ============================================================ + +results: dict[str, dict] = {} + + +def category(name: str): + if name not in results: + results[name] = {'passed': 0, 'failed': 0, 'tests': []} + return name + + +def record(cat: str, passed: bool, name: str, detail: str = ''): + status = 'PASS' if passed else 'FAIL' + results[cat]['passed' if passed else 'failed'] += 1 + results[cat]['tests'].append((status, name)) + msg = f' {status}: {name}' + if detail: + msg += f' ({detail})' + if passed: + log.info(msg) + else: + log.error(msg) + + +def run_test(cat: str, fn): + name = fn.__name__ + try: + ok = fn() + if ok is False: + record(cat, False, name) + else: + record(cat, True, name) + except AssertionError as e: + record(cat, False, name, str(e)) + except Exception as e: # pylint: disable=broad-except + record(cat, False, name, f'exception: {e}') + import traceback + traceback.print_exc() + + +# ============================================================ +# The closure hijacks this router replaces, transcribed +# ============================================================ + +# devices.set_sdpa_params applied the hijacks in this order; each wrapped the previous, so the +# last applied was tried first. Dynamic replaced the chain end instead of wrapping it; flex did +# too, which left everything stacked before it unreachable, so it is an ordinary entry now. +OLD_ORDER = ['Dynamic attention', 'Flex attention', 'Triton AMD Flash attention', 'Flash attention', 'Sage attention', 'SDNQ attention'] +OLD_TERMINALS = {'Dynamic attention'} +OLD_NAMES = { + 'Dynamic attention': 'dynamic', + 'Flex attention': 'flex', + 'Triton AMD Flash attention': 'triton', + 'Flash attention': 'flash', + 'Sage attention': 'sage', + 'SDNQ attention': 'sdnq', +} +# mirrors shared_defaults.get_default_modes: five choices everywhere, Triton AMD Flash attention added on rocm and zluda +CHOICES = OLD_ORDER +TRITON_PLATFORMS = {'rocm', 'zluda'} + +# the four closure predicates transcribed literally, plus the contract flex_attention itself enforces +GATES = { + 'sdnq': lambda q, k, v, m: q.device.type != "cpu" and (q.shape[-2] >= 32 and k.shape[-2] >= 32) and (q.shape[-2] > 512 or k.shape[-2] > 512) and q.shape[-3] > 1, + 'triton': lambda q, k, v, m: q.shape[-1] <= 128 and m is None and q.device.type != "cpu" and k.device == q.device and v.device == q.device, + 'flash': lambda q, k, v, m: q.shape[-1] <= 128 and m is None and q.dtype != torch.float32 and q.device.type != "cpu" and k.device == q.device and v.device == q.device, + 'sage': lambda q, k, v, m: q.shape[-1] in {128, 96, 64} and m is None and q.device.type != "cpu" and k.device == q.device and v.device == q.device, + 'flex': lambda q, k, v, m: q.ndim == 4 and q.device.type != "cpu" and k.device == q.device and v.device == q.device, +} + + +def oracle_chain(labels, platform_backend): + enabled = [label for label in OLD_ORDER if label in labels] + if platform_backend not in TRITON_PLATFORMS: + enabled = [label for label in enabled if label != 'Triton AMD Flash attention'] + terminal = None + entries = [] + for label in enabled: + if label in OLD_TERMINALS: + terminal = label + else: + entries.append(label) + entries.reverse() + return [OLD_NAMES[label] for label in entries], (OLD_NAMES[terminal] if terminal else None) + + +def stub_registry(failing=()): + """The registered backends with prepares that return a tagged call instead of importing anything.""" + reg = attention.Registry() + for backend in attention.registry.ordered(): + def prepare(platform, original, name=backend.name): # pylint: disable=unused-argument + if name in failing: + raise RuntimeError(f'{name} unavailable') + def call(*args, **kwargs): # pylint: disable=unused-argument + return name + return call + reg.register(replace(backend, prepare=prepare)) + return reg + + +def shaped(shape, dtype=torch.float16, device='meta'): + """A tensor of the given shape without allocating it.""" + return torch.empty(1, dtype=dtype, device=device).expand(*shape) + + +def sdpa_stub(**kwargs): # pylint: disable=unused-argument + return 'sdpa' + + +# ============================================================ +# Tests +# ============================================================ + +def test_plan_matches_stacking_oracle(): + level = log.level + log.setLevel(logging.ERROR) # platform gating warns per plan + try: + plans = 0 + for platform_backend in ('cuda', 'rocm', 'zluda', 'cpu'): + reg = stub_registry() + platform = attention.Platform(backend=platform_backend) + for count in range(len(OLD_ORDER) + 1): + for labels in itertools.combinations(OLD_ORDER, count): + plan = attention.build_plan(list(labels), platform, sdpa_stub, reg) + expected_entries, expected_terminal = oracle_chain(labels, platform_backend) + got_entries = [entry.backend.name for entry in plan.entries] + got_terminal = plan.terminal.backend.name if plan.terminal is not None else None + assert got_entries == expected_entries, f'{platform_backend} {labels}: entries {got_entries} != {expected_entries}' + assert got_terminal == expected_terminal, f'{platform_backend} {labels}: terminal {got_terminal} != {expected_terminal}' + assert plan.chain() == got_entries + [got_terminal or 'sdpa'] + plans += 1 + finally: + log.setLevel(level) + log.info(f' {plans} plans match the stacking oracle') + return True + + +def test_gates_match_transcribed_predicates(): + cases = 0 + lengths = (16, 32, 512, 513, 4096) + for q_device, kv_device, dtype, heads, q_len, k_len, head_dim, masked, batched in itertools.product(('cpu', 'meta'), ('cpu', 'meta'), (torch.float16, torch.float32), (1, 8), lengths, lengths, (40, 64, 96, 128, 256), (False, True), (False, True)): + lead = (1,) if batched else () + q = shaped((*lead, heads, q_len, head_dim), dtype, q_device) + k = shaped((*lead, heads, k_len, head_dim), dtype, kv_device) + v = shaped((*lead, heads, k_len, head_dim), dtype, kv_device) + m = shaped((*lead, 1, q_len, k_len), torch.bool, q_device) if masked else None + for name, gate in GATES.items(): + expected = bool(gate(q, k, v, m)) + got = attention.registry.backends[name].constraints.accepts(q, k, v, m) + assert got == expected, f'{name}: q={tuple(q.shape)} k={tuple(k.shape)} dtype={dtype} devices={q_device}/{kv_device} mask={masked} got={got} expected={expected}' + cases += 1 + log.info(f' {cases} gate cases match the transcribed predicates') + return True + + +def test_only_dynamic_is_terminal(): + for name, backend in attention.registry.backends.items(): + assert backend.terminal == (name == 'dynamic'), name + assert attention.registry.backends['dynamic'].constraints == attention.Constraints() + return True + + +def test_choices_match_backends(): + labels = attention.registry.labels() + assert sorted(labels) == sorted(CHOICES), f'registered={labels} choices={CHOICES}' + for label in CHOICES: + assert attention.registry.by_label(label) is not None, label + triton = attention.registry.backends['triton'] + assert triton.platforms == frozenset(TRITON_PLATFORMS), triton.platforms + for name, backend in attention.registry.backends.items(): + if name != 'triton': + assert backend.platforms is None, name + return True + + +def test_router_dispatch_prefers_priority_then_terminal_then_original(): + calls = [] + + def original(**kwargs): + calls.append(('sdpa', kwargs)) + return 'sdpa' + + reg = attention.Registry() + + def add(name, constraints, priority, terminal=False): + def prepare(platform, orig): # pylint: disable=unused-argument + def call(*args, **kwargs): # pylint: disable=unused-argument + calls.append((name, kwargs)) + return name + return call + reg.register(attention.AttentionBackend(name=name, label=f'{name} attention', priority=priority, prepare=prepare, constraints=constraints, terminal=terminal)) + + add('narrow', attention.Constraints(head_dims=frozenset({64})), priority=20) + add('wide', attention.Constraints(), priority=10) + platform = attention.Platform(backend='cuda') + router = attention_router.make_router(attention.build_plan(['narrow attention', 'wide attention'], platform, original, reg)) + q64 = shaped((1, 8, 128, 64)) + q128 = shaped((1, 8, 128, 128)) + cpu = shaped((1, 8, 128, 64), device='cpu') + assert router(q64, q64, q64) == 'narrow' + assert router(q128, q128, q128) == 'wide' + assert router(cpu, cpu, cpu) == 'sdpa' + assert 'enable_gqa' not in calls[-1][1], calls[-1] + assert router(cpu, cpu, cpu, enable_gqa=True) == 'sdpa' + assert calls[-1][1].get('enable_gqa') is True, calls[-1] + + add('term', attention.Constraints(), priority=5, terminal=True) + router = attention_router.make_router(attention.build_plan(['narrow attention', 'term attention'], platform, original, reg)) + assert router(q64, q64, q64) == 'narrow' + assert router(cpu, cpu, cpu, extra=1) == 'term' + assert calls[-1][1].get('extra') == 1 and calls[-1][1].get('enable_gqa') is False, calls[-1] + return True + + +def test_prepare_failure_skips_backend(): + reg = stub_registry(failing=('sage',)) + plan = attention.build_plan(['Sage attention', 'SDNQ attention', 'Flash attention'], attention.Platform(backend='cuda'), sdpa_stub, reg) + assert [entry.backend.name for entry in plan.entries] == ['sdnq', 'flash'], plan.chain() + return True + + +def test_prepared_call_narrows_caps(): + # a backend declares what it can consume; prepare may narrow that to what the installed + # implementation verified, never widen it, and the router hands a selection only to survivors + reg = attention.Registry() + + def add(name, declared, verified=None): + def prepare(platform, original): # pylint: disable=unused-argument + def call(*args, **kwargs): # pylint: disable=unused-argument + return name + if verified is not None: + call.caps = verified + return call + reg.register(attention.AttentionBackend(name=name, label=f'{name} attention', priority=10, prepare=prepare, caps=declared)) + + add('declared', frozenset({'block_mask'})) + add('narrowed', frozenset({'block_mask'}), frozenset()) + add('widened', frozenset(), frozenset({'block_mask'})) + platform = attention.Platform(backend='cuda') + plan = attention.build_plan(['declared attention', 'narrowed attention', 'widened attention'], platform, sdpa_stub, reg) + caps = {entry.backend.name: entry.caps for entry in plan.entries} + assert caps == {'declared': frozenset({'block_mask'}), 'narrowed': frozenset(), 'widened': frozenset()}, caps + q = shaped((1, 8, 1024, 64)) + calls = [] + + def stage(*args): # pylint: disable=unused-argument + calls.append('stage') + return 'selection' + router = attention_router.make_router(attention.build_plan(['narrowed attention'], platform, sdpa_stub, reg), stage=stage) + assert router(q, q, q) == 'narrowed' and not calls, calls + router = attention_router.make_router(attention.build_plan(['declared attention'], platform, sdpa_stub, reg), stage=stage) + assert router(q, q, q) == 'declared' and calls == ['stage'], calls + return True + + +def test_install_router_keeps_original_for_empty_plan(): + saved = torch.nn.functional.scaled_dot_product_attention + saved_plan = attention_router.current_plan + try: + platform = attention.Platform(backend='cuda') + plan = attention.install_router([], platform, sdpa_stub, stub_registry()) + assert torch.nn.functional.scaled_dot_product_attention is sdpa_stub + assert plan.chain() == ['sdpa'], plan.chain() + plan = attention.install_router(['SDNQ attention', 'Sage attention'], platform, sdpa_stub, stub_registry()) + assert torch.nn.functional.scaled_dot_product_attention is not sdpa_stub + assert plan.chain() == ['sdnq', 'sage', 'sdpa'], plan.chain() + assert attention.get_plan() is plan + finally: + torch.nn.functional.scaled_dot_product_attention = saved + attention_router.current_plan = saved_plan + return True + + +def test_dynamic_backend_pins_pre_dynamic_sdpa(): + from modules import devices + saved = devices.sdpa_pre_dyanmic_atten + try: + call = attention.registry.backends['dynamic'].prepare(attention.Platform(backend='cuda'), sdpa_stub) + from modules.sd_hijack_dynamic_atten import dynamic_scaled_dot_product_attention + assert call is dynamic_scaled_dot_product_attention + assert devices.sdpa_pre_dyanmic_atten is sdpa_stub + finally: + devices.sdpa_pre_dyanmic_atten = saved + return True + + +def test_context_classic_ticks_follow_the_callback(): + ctx = attention.context + + class Denoiser(torch.nn.Module): # begin installs the layout pre-hook, so the stand-in has to accept one + pass + + class Pipe: + transformer = Denoiser() + + ctx.begin(Pipe(), steps=4) + assert ctx.current.active and ctx.current.role == 'transformer' and ctx.current.step == 0 and ctx.current.steps == 4 + assert ctx.current.model_key == ('Pipe', 'Denoiser'), ctx.current.model_key + buffer = ctx.current.step_buffer + for completed in range(4): + ctx.tick(completed + 1) # the diffusers callback reports the step just completed + assert ctx.current.step == completed + 1 + assert ctx.current.step_buffer is buffer and int(buffer.item()) == completed + 1 + ctx.new_pass(2) # hires or refiner pass + assert ctx.current.step == 0 and ctx.current.steps == 2 and int(buffer.item()) == 0 + ctx.end() + assert not ctx.current.active and ctx.current.role is None and ctx.current.model_key is None and ctx.current.step == 0 + return True + + +def test_context_modular_ticks_count_forwards(): + ctx = attention.context + ctx.begin(None, steps=3) + assert ctx.current.model_key is None + for expected in range(3): + ctx.tick() # the modular pre-hook fires before each forward + assert ctx.current.step == expected, ctx.current.step + ctx.end() + return True + + +def test_context_roles_nest_and_stick(): + ctx = attention.context + ctx.begin(None) + with ctx.role('te'): + assert ctx.current.role == 'te' + with ctx.role('vae'): + assert ctx.current.role == 'vae' + assert ctx.current.role == 'te' + assert ctx.current.role == 'transformer' + ctx.set_role('vae') + assert ctx.current.role == 'vae' + ctx.end() + assert ctx.current.role is None + with ctx.role('te'): # outside a generation the scope still restores what it found + assert ctx.current.role == 'te' + assert ctx.current.role is None + return True + + +def test_router_observer_sees_each_route(): + routes = [] + reg = attention.Registry() + + def prepare(platform, original): # pylint: disable=unused-argument + return lambda *args, **kwargs: 'narrow' + + reg.register(attention.AttentionBackend(name='narrow', label='narrow attention', priority=20, prepare=prepare, constraints=attention.Constraints(head_dims=frozenset({64})))) + plan = attention.build_plan(['narrow attention'], attention.Platform(backend='cuda'), sdpa_stub, reg) + router = attention_router.make_router(plan, observer=lambda name, q, k, m: routes.append(name)) + q64 = shaped((1, 8, 128, 64)) + q128 = shaped((1, 8, 128, 128)) + router(q64, q64, q64) + router(q128, q128, q128) + assert routes == ['narrow', 'sdpa'], routes + return True + + +def test_install_router_records_the_chain(): + saved = torch.nn.functional.scaled_dot_product_attention + saved_plan = attention_router.current_plan + saved_info = installer.torch_info.get('attention') + try: + attention.install_router(['SDNQ attention', 'Dynamic attention'], attention.Platform(backend='cuda'), sdpa_stub, stub_registry()) + assert installer.torch_info.get('attention') == 'sdnq>dynamic', installer.torch_info.get('attention') + info = attention.report() + assert info['chain'] == ['sdnq', 'dynamic'] and info['overrides'] == ['SDNQ attention', 'Dynamic attention'] and info['backend'] == 'cuda', info + assert info['context']['active'] is False and info['context']['role'] is None, info + finally: + torch.nn.functional.scaled_dot_product_attention = saved + attention_router.current_plan = saved_plan + installer.torch_info.set(attention=saved_info) + return True + + +def test_debug_observe_logs_each_route_once(): + attention.debug.reset() + q = shaped((1, 8, 128, 64)) + attention.debug.observe('sdnq', q, q, None) + attention.debug.observe('sdnq', q, q, None) + attention.debug.observe('sdnq', q, q, shaped((1, 1, 128, 128), torch.bool)) + assert len(attention.debug.seen) == 2, attention.debug.seen + attention.debug.reset() + assert not attention.debug.seen + return True + + +def test_attention_slicing_follows_the_choice(): + from modules import shared + + class Pipe: + def __init__(self): + self.calls = [] + + def enable_attention_slicing(self): + self.calls.append('enable') + + def disable_attention_slicing(self): + self.calls.append('disable') + + saved = {key: shared.opts.data.get(key, None) for key in ['attention_slicing', 'cross_attention_optimization']} + try: + shared.opts.data['cross_attention_optimization'] = 'Default' # the branch under test is the only one that should act + for choice, expected in [('Default', []), ('Enabled', ['enable']), ('Disabled', ['disable'])]: + shared.opts.data['attention_slicing'] = choice + pipe = Pipe() + attention.set_diffusers_attention(pipe, quiet=True) + assert pipe.calls == expected, f'{choice} produced {pipe.calls}' + finally: + for key, value in saved.items(): + if value is None: + shared.opts.data.pop(key, None) + else: + shared.opts.data[key] = value + return True + + +def test_removed_attention_methods_are_gone(): + from modules import shared_items + from modules import options_handler + from modules import sd_hijack_dynamic_atten + + removed = ['Batch matrix-matrix', 'Dynamic Attention BMM'] + choices = shared_items.list_crossattention() + assert not [name for name in removed if name in choices], choices + for name in removed: + data = {'cross_attention_optimization': name} + migrated = options_handler.migrate_removed_values(data) + assert data['cross_attention_optimization'] == 'Scaled-Dot-Product', data + assert len(migrated) == 1, migrated + kept = {'cross_attention_optimization': 'xFormers'} + assert options_handler.migrate_removed_values(kept) == [], 'a live choice is left alone' + assert kept['cross_attention_optimization'] == 'xFormers', kept + assert not hasattr(sd_hijack_dynamic_atten, 'DynamicAttnProcessorBMM'), 'the bmm processor is removed' + assert hasattr(sd_hijack_dynamic_atten, 'dynamic_scaled_dot_product_attention'), 'the sliced sdpa path stays' + return True + + +def test_escape_hatch_bypasses_the_router(): + from modules import devices + saved_sdpa = torch.nn.functional.scaled_dot_product_attention + saved_plan = attention_router.current_plan + saved_original = devices.sdpa_original + try: + devices.sdpa_original = sdpa_stub # what set_sdpa_params pinned before building the chain + attention.install_router(['SDNQ attention'], attention.Platform(backend='cuda'), sdpa_stub, stub_registry()) + router = torch.nn.functional.scaled_dot_product_attention + assert router is not sdpa_stub + with devices.bypass_sdpa_hijacks(): + assert torch.nn.functional.scaled_dot_product_attention is sdpa_stub # captioners and detailers run here + assert torch.nn.functional.scaled_dot_product_attention is router + with devices.llm_context(): + assert torch.nn.functional.scaled_dot_product_attention is sdpa_stub + assert torch.nn.functional.scaled_dot_product_attention is router + try: + with devices.bypass_sdpa_hijacks(): + raise RuntimeError('captioner failed') + except RuntimeError: + pass + assert torch.nn.functional.scaled_dot_product_attention is router, 'the chain must survive a failure inside the bypass' + finally: + devices.sdpa_original = saved_original + torch.nn.functional.scaled_dot_product_attention = saved_sdpa + attention_router.current_plan = saved_plan + return True + + +def test_reapply_options_cover_declared_backend_options(): + from modules import shared + names = attention.reapply_options() + assert names[:2] == ['sdp_options'], names + declared = attention.registry.options() + assert set(declared) <= set(names), (declared, names) + assert attention.registry.backends['sdnq'].options and set(attention.registry.backends['sdnq'].options) <= set(declared) + for name in names: + assert name in shared.opts.data_labels, name + return True + + +def run_all(): + log.warning('=== attention router ===') + cat = category('router') + for fn in [ + test_plan_matches_stacking_oracle, + test_gates_match_transcribed_predicates, + test_only_dynamic_is_terminal, + test_choices_match_backends, + test_router_dispatch_prefers_priority_then_terminal_then_original, + test_prepare_failure_skips_backend, + test_prepared_call_narrows_caps, + test_install_router_keeps_original_for_empty_plan, + test_dynamic_backend_pins_pre_dynamic_sdpa, + ]: + run_test(cat, fn) + + log.warning('=== generation context ===') + cat = category('context') + for fn in [ + test_context_classic_ticks_follow_the_callback, + test_context_modular_ticks_count_forwards, + test_context_roles_nest_and_stick, + ]: + run_test(cat, fn) + + log.warning('=== telemetry ===') + cat = category('telemetry') + for fn in [ + test_router_observer_sees_each_route, + test_install_router_records_the_chain, + test_debug_observe_logs_each_route_once, + test_reapply_options_cover_declared_backend_options, + test_attention_slicing_follows_the_choice, + test_removed_attention_methods_are_gone, + test_escape_hatch_bypasses_the_router, + ]: + run_test(cat, fn) + + log.warning('=== Results ===') + total_passed = 0 + total_failed = 0 + for cat_name, info in results.items(): + ok = info['failed'] == 0 + status = 'PASS' if ok else 'FAIL' + log.info(f" {cat_name}: {info['passed']} passed, {info['failed']} failed [{status}]") + total_passed += info['passed'] + total_failed += info['failed'] + log.warning(f'Total: {total_passed} passed, {total_failed} failed') + return total_failed == 0 + + +if __name__ == '__main__': + import time + t0 = time.time() + ok = run_all() + torch.nn.functional.scaled_dot_product_attention = stock_sdpa + log.warning(f'Total time: {time.time() - t0:.2f}s') + sys.exit(0 if ok else 1) diff --git a/test/test-attention-sdnq-sparse.py b/test/test-attention-sdnq-sparse.py new file mode 100644 index 000000000..35d30fbd3 --- /dev/null +++ b/test/test-attention-sdnq-sparse.py @@ -0,0 +1,688 @@ +#!/usr/bin/env python +""" +Offline tests for the block mask input of the sdnq Triton attention kernel. + +Covers: + +- the kernel contract through the raw triton op, which takes the per query block count and + ascending index list of kept kv blocks that get_block_mask_input builds from the int8 mask: a + block mask is within one ulp of the same kernel fed the token-expanded dense mask, over a ragged + tail with sub tiles past the end of the sequence, GQA, batch and head broadcasts, the contiguous padded list contract + and an empty block row; bitwise against no mask with every block kept, and bitwise against the + token mask when both arms carry one. The token-mask path has its own -inf-safe softmax + update, which the compiler rounds differently by up to one ulp depending on tile and dtype; the + block path shares the dense arithmetic, which the all-ones row proves +- the launcher's validation of the block mask +- the nesting filter: prune_configs keeps only tiles that sit inside one mask block and raises, + naming the env vars, when none do +- the public entry: sdnq_triton_atten(block_mask=...) on the quantized paths, under the same one + ulp and all-ones rules, bool and 3d masks normalized, and the backward entry refusing a block + mask; these rows skip until the entry accepts block_mask +- the flex consumer and the kernel fed one BlockSelection both sit within tolerance of fp32 sdpa + on the same tiles + +Bitwise rows need the autotuner pinned to one config: the two arms have different autotune keys, +and a different tile changes the accumulation order. A single run pins 64x32 unless the +SDNQ_TRITON_ATTEN_*_LIST env says otherwise, and the last row asserts the pin left the autotuner +exactly one config. --tiles runs the file once per tile pair in a subprocess, which is also what +proves every candidate tile nests the 128x64 block: a tile that did not would fail the kernel's +static_assert at compile time. + +Usage: + python test/test-attention-sdnq-sparse.py + python test/test-attention-sdnq-sparse.py --tiles +""" + +import os +import sys +import inspect + +TILES = [(32, 16), (32, 32), (32, 64), (64, 16), (64, 32), (64, 64), (128, 16), (128, 32), (128, 64)] +PIN = { + 'SDNQ_TRITON_ATTEN_BLOCK_SIZE_M_LIST': '64', + 'SDNQ_TRITON_ATTEN_BLOCK_SIZE_N_LIST': '32', + 'SDNQ_TRITON_ATTEN_NUM_WARPS_LIST': '4', + 'SDNQ_TRITON_ATTEN_NUM_STAGES_LIST': '1', +} + + +def run_tiles() -> bool: + import subprocess + ok = True + for block_m, block_n in TILES: + env = dict(os.environ, **PIN) + env['SDNQ_TRITON_ATTEN_BLOCK_SIZE_M_LIST'] = str(block_m) + env['SDNQ_TRITON_ATTEN_BLOCK_SIZE_N_LIST'] = str(block_n) + print(f'=== tile {block_m}x{block_n} ===', flush=True) + code = subprocess.call([sys.executable, os.path.abspath(__file__)], env=env) + print(f'=== tile {block_m}x{block_n}: {"PASS" if code == 0 else "FAIL"} ===', flush=True) + ok = ok and code == 0 + return ok + + +if __name__ == '__main__' and '--tiles' in sys.argv: + sys.exit(0 if run_tiles() else 1) + +for pin_name, pin_value in PIN.items(): + os.environ.setdefault(pin_name, pin_value) + + +def env_list(name: str) -> list[int]: + return [int(x) for x in os.environ[name].replace(' ', '').split(',')] + + +pinned = {name: env_list(name) for name in PIN} +if any(len(values) != 1 for values in pinned.values()): + print('this test needs the attention autotuner pinned to one config: set each SDNQ_TRITON_ATTEN_*_LIST to a single value', flush=True) + sys.exit(2) +block_size_m = pinned['SDNQ_TRITON_ATTEN_BLOCK_SIZE_M_LIST'][0] +block_size_n = pinned['SDNQ_TRITON_ATTEN_BLOCK_SIZE_N_LIST'][0] + +import torch # pylint: disable=wrong-import-position + +script_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) +sys.path.insert(0, script_dir) +os.chdir(script_dir) + +os.environ['SD_INSTALL_QUIET'] = '1' + +# Bootstrap cmd_args before any module that pulls in shared.py. +import modules.cmd_args # pylint: disable=wrong-import-position +import installer # pylint: disable=wrong-import-position +orig_argv = sys.argv +sys.argv = [sys.argv[0]] +try: + modules.cmd_args.parse_args() +finally: + sys.argv = orig_argv +installer.add_args(modules.cmd_args.parser) +modules.cmd_args.parsed, _ = modules.cmd_args.parser.parse_known_args([]) + +stock_sdpa = torch.nn.functional.scaled_dot_product_attention # captured before shared installs the configured hijacks + +from modules.errors import log # pylint: disable=wrong-import-position +from modules import shared # pylint: disable=wrong-import-position,unused-import +from modules.attention import sparse # pylint: disable=wrong-import-position +from modules.attention.sparse import flex as sparse_flex # pylint: disable=wrong-import-position +from sdnq.kernels import triton_atten as atten_module # pylint: disable=wrong-import-position +from sdnq.kernels import triton_atten_backward as backward_module # pylint: disable=wrong-import-position + + +results: dict[str, dict] = {} +device = torch.device('cuda') if torch.cuda.is_available() else torch.device('cpu') +kernel_available = device.type == 'cuda' +int8_ok = block_size_n >= 32 # the int8 paths prune tiles narrower than 32, so a narrower pin cannot exercise them +BLOCK_M, BLOCK_N = 128, 64 + + +def category(name: str): + if name not in results: + results[name] = {'passed': 0, 'failed': 0, 'skipped': 0, 'tests': []} + return name + + +def record(cat: str, passed, name: str, detail: str = ''): + status = 'SKIP' if passed is None else ('PASS' if passed else 'FAIL') + key = {'SKIP': 'skipped', 'PASS': 'passed', 'FAIL': 'failed'}[status] + results[cat][key] += 1 + results[cat]['tests'].append((status, name)) + msg = f' {status}: {name}' + if detail: + msg += f' ({detail})' + (log.info if status != 'FAIL' else log.error)(msg) + + +def run_test(cat: str, fn): + name = fn.__name__ + try: + outcome = fn() + record(cat, None if outcome is None else bool(outcome), name) + except AssertionError as e: + record(cat, False, name, str(e)) + except Exception as e: # pylint: disable=broad-except + record(cat, False, name, f'exception: {e}') + import traceback + traceback.print_exc() + + +generator = torch.Generator(device=device).manual_seed(4321) + + +def randn(*shape, dtype=torch.bfloat16): + return torch.randn(*shape, generator=generator, device=device, dtype=torch.float32).to(dtype).contiguous() + + +def qkv(batch=2, heads=4, kv_heads=None, seq=1000, dim=64, dtype=torch.bfloat16): + kv_heads = kv_heads or heads + return randn(batch, heads, seq, dim, dtype=dtype), randn(batch, kv_heads, seq, dim, dtype=dtype), randn(batch, kv_heads, seq, dim, dtype=dtype) + + +def blocks(seq_q: int, seq_kv: int): + return sparse.selector.block_count(seq_q, BLOCK_M), sparse.selector.block_count(seq_kv, BLOCK_N) + + +def random_keep(batch: int, heads: int, seq_q: int, seq_kv: int, density: float = 0.4): + """A random block mask with the diagonal kept, so no row is empty unless a test empties it.""" + nq, nk = blocks(seq_q, seq_kv) + keep = torch.rand(batch, heads, nq, nk, generator=generator, device=device) < density + keep |= sparse.selector.diagonal_blocks(nq, nk, BLOCK_M, BLOCK_N, device) + return keep.to(torch.int8) + + +def expand(keep: torch.Tensor, seq_q: int, seq_kv: int): + """The token-granular int8 mask a block mask stands for.""" + return keep.repeat_interleave(BLOCK_M, dim=-2).repeat_interleave(BLOCK_N, dim=-1)[..., :seq_q, :seq_kv].contiguous() + + +def ordered(keep: torch.Tensor): + """The count and ascending index list per query block that the kernel walks, built the way the entry builds them: left-padded to 4d, size-1 batch and head dims kept, padded to the descriptor chunks.""" + while keep.ndim < 4: + keep = keep.unsqueeze(0) + return atten_module.get_block_mask_input(keep) + + +def raw(q, k, v, attn_mask=None, block_mask=None, block_count=None, block_index=None): + """The triton op without the input prep: nothing is quantized, so the mask path is the only difference between arms.""" + if block_mask is not None: + block_count, block_index = ordered(block_mask) + sparse = block_count is not None + return atten_module.sdnq_triton_atten_fwd( + q, k, v, None, None, None, + attn_mask=attn_mask, is_causal=False, sm_scale=q.shape[-1] ** -0.5, use_fp16_accum=False, out_dtype=q.dtype, + block_count=block_count, block_index=block_index, block_mask_m=BLOCK_M if sparse else 0, block_mask_n=BLOCK_N if sparse else 0, + ) + + +def entry_accepts_block_mask() -> bool: + return 'block_mask' in inspect.signature(inspect.unwrap(atten_module.sdnq_triton_atten)).parameters + + +def entry(q, k, v, **kwargs): + return atten_module.sdnq_triton_atten(q, k, v, **kwargs) + + +def configs_for(sizes_m, sizes_n): + import triton + return [triton.Config({'BLOCK_SIZE_M': m, 'BLOCK_SIZE_N': n}, num_warps=4, num_stages=1) for m in sizes_m for n in sizes_n] + + +def nests(conf) -> bool: + return BLOCK_M % conf.kwargs['BLOCK_SIZE_M'] == 0 and BLOCK_N % conf.kwargs['BLOCK_SIZE_N'] == 0 + + +def assert_one_ulp(got: torch.Tensor, want: torch.Tensor, label: str = ''): + """Within one unit in the last place at each element, plus an absolute floor for the drift between the two rounding sequences (a straddled rounding of one p before the pv dot, amplified on rows with few keys), two orders below what a mis-skipped tile moves.""" + if torch.equal(got, want): + return + eps = torch.finfo(got.dtype).eps + atol = want.float().abs().max().item() * 2**-10 + if not torch.allclose(got.float(), want.float(), rtol=eps, atol=atol): + gap = (got.float() - want.float()).abs() + raise AssertionError(f'{label} max diff {gap.max().item():.3e} over {int((got != want).sum().item())} elements, bound one ulp plus {atol:.1e}') + + +# ============================================================ +# Kernel contract +# ============================================================ + +def test_block_mask_matches_the_expanded_token_mask(): + if not kernel_available: + return None + for seq in (1000, 970): # 970 leaves the last block with sub tiles past the end of the sequence under the narrower tiles + q, k, v = qkv(seq=seq) + keep = random_keep(2, 4, seq, seq) + got = raw(q, k, v, block_mask=keep) + assert_one_ulp(got, raw(q, k, v, attn_mask=expand(keep, seq, seq)), f'seq {seq}') + assert torch.isfinite(got).all() + assert not torch.equal(got, raw(q, k, v)), 'a 40 percent block mask left the output identical to dense: the mask is not applied' + return True + + +def test_gqa_block_mask_indexes_query_heads(): + if not kernel_available: + return None + q, k, v = qkv(heads=8, kv_heads=2) + for heads in (8, 1): + keep = random_keep(2, heads, 1000, 1000) + assert_one_ulp(raw(q, k, v, block_mask=keep), raw(q, k, v, attn_mask=expand(keep, 1000, 1000)), f'mask heads {heads}') + return True + + +def test_block_mask_broadcasts_over_batch_and_heads(): + if not kernel_available: + return None + q, k, v = qkv(batch=3, heads=4) + for batch, heads in ((1, 1), (1, 4), (3, 1)): + keep = random_keep(batch, heads, 1000, 1000) + assert_one_ulp(raw(q, k, v, block_mask=keep), raw(q, k, v, attn_mask=expand(keep, 1000, 1000)), f'mask shape {tuple(keep.shape)}') + return True + + +def test_block_lists_must_be_contiguous_and_padded(): + """The kernel reads the lists through descriptors from shapes alone, so the launcher takes only what the entry builds.""" + if not kernel_available: + return None + q, k, v = qkv(seq=1100) # 9 query blocks and 18 kv blocks, so both lists get padded (to 12 and 32) + keep = random_keep(2, 4, 1100, 1100) + count, index = ordered(keep) + nq, nk = blocks(1100, 1100) + assert count.is_contiguous() and index.is_contiguous() + assert count.shape[-1] % atten_module.block_count_chunk == 0 and index.shape[-1] % atten_module.block_index_chunk == 0 + assert count.shape[-1] > nq and index.shape[-2] == nq and index.shape[-1] > nk, 'this geometry should pad both lists' + assert torch.equal(count[..., :nq], keep.sum(-1, dtype=torch.int32)), 'padding changed the counts' + reference = raw(q, k, v, block_count=count, block_index=index) + count_view = count.transpose(-1, -2).contiguous().transpose(-1, -2) + index_view = index.transpose(-1, -2).contiguous().transpose(-1, -2) + unpadded_count = count[..., :nq].contiguous() + unpadded_index = index[..., :nk].contiguous() + rejected = ( + ('a strided count', {'block_count': count_view, 'block_index': index}), + ('a strided index', {'block_count': count, 'block_index': index_view}), + ('an unpadded count', {'block_count': unpadded_count, 'block_index': index}), + ('an unpadded index', {'block_count': count, 'block_index': unpadded_index}), + ) + for label, lists in rejected: + try: + raw(q, k, v, **lists) + except ValueError: + continue + raise AssertionError(f'{label} was accepted') + assert torch.equal(raw(q, k, v, block_mask=keep), reference) + shared_keep = keep[:1, :1] + shared_count, shared_index = ordered(shared_keep) + assert tuple(shared_count.shape[:2]) == (1, 1) and tuple(shared_index.shape[:2]) == (1, 1), 'size-1 batch and head dims stay as given, the kernel broadcasts by shape' + assert torch.equal(raw(q, k, v, block_count=shared_count, block_index=shared_index), raw(q, k, v, block_mask=shared_keep.expand(2, 4, -1, -1).contiguous())) + return True + + +def test_empty_block_row_gives_zeros_without_nan(): + if not kernel_available: + return None + q, k, v = qkv() + keep = random_keep(2, 4, 1000, 1000) + keep[..., 2, :] = 0 + got = raw(q, k, v, block_mask=keep) + assert_one_ulp(got, raw(q, k, v, attn_mask=expand(keep, 1000, 1000))) + assert torch.isfinite(got).all() + assert got[..., 256:384, :].abs().max().item() == 0.0, 'an empty block row should give zeros' + assert got[..., :256, :].abs().max().item() > 0.0 + return True + + +def test_block_mask_composes_with_a_token_mask(): + if not kernel_available: + return None + q, k, v = qkv() + keep = random_keep(2, 4, 1000, 1000) + padding = torch.ones(2, 1, 1000, 1000, dtype=torch.int8, device=device) + padding[..., -37:] = 0 # the last keys are padding, as a packed sequence with a tail would have + got = raw(q, k, v, attn_mask=padding, block_mask=keep) + want = raw(q, k, v, attn_mask=(padding.bool() & expand(keep, 1000, 1000).bool()).to(torch.int8)) + assert torch.equal(got, want), 'both arms carry a token mask, so this one is bitwise' # pylint: disable=line-too-long + assert not torch.equal(got, raw(q, k, v, block_mask=keep)), 'the token mask was ignored beside the block mask' + return True + + +def same_arithmetic(got: torch.Tensor, want: torch.Tensor, label: str): + """Every block kept against no mask: the same tiles in the same order, so any gap is compiler scheduling of a loop with a runtime trip count; report whether it was bitwise and bound it either way.""" + bitwise = torch.equal(got, want) + if not bitwise: + gap = (got.float() - want.float()).abs() + log.info(f' {label}: all-ones differs from dense by {gap.max().item():.3e} over {int((got != want).sum().item())} elements (compiler scheduling, not tiles)') + assert_one_ulp(got, want, label) + return bitwise + + +def test_all_ones_block_mask_matches_no_mask(): + if not kernel_available: + return None + q, k, v = qkv() + nq, nk = blocks(1000, 1000) + ones = torch.ones(1, 1, nq, nk, dtype=torch.int8, device=device) + same_arithmetic(raw(q, k, v, block_mask=ones), raw(q, k, v), 'raw bf16') + return True + + +def test_sub_tile_past_the_sequence_is_masked(): + """992 divides every kernel tile but not the 64-wide mask block, so the last block's trailing sub tile sits entirely past the keys. + + Without a tail rule that knows the block geometry it loads zeros, scores them as zero and inflates the softmax denominator. + """ + if not kernel_available: + return None + seq = 992 + assert seq % block_size_n == 0 or seq % BLOCK_N != 0, 'this row needs a sequence the tile divides and the mask block does not' + q, k, v = qkv(seq=seq) + nq, nk = blocks(seq, seq) + assert nk * BLOCK_N > seq, 'the last mask block should run past the sequence' + ones = torch.ones(1, 1, nq, nk, dtype=torch.int8, device=device) + assert_one_ulp(raw(q, k, v, block_mask=ones), raw(q, k, v), f'seq {seq}, every block kept') + keep = random_keep(2, 4, seq, seq) + assert_one_ulp(raw(q, k, v, block_mask=keep), raw(q, k, v, attn_mask=expand(keep, seq, seq)), f'seq {seq}, 40 percent kept') + return True + + +def test_launcher_validates_the_block_lists(): + if not kernel_available: + return None + q, k, v = qkv() + ones = torch.ones(1, 1, *blocks(1000, 1000), dtype=torch.int8, device=device) + count, index = ordered(ones) + wide_count, wide_index = ordered(ones.expand(5, 4, -1, -1).contiguous()) + bad = ( + ('a count without an index', {'block_count': count}), + ('an index without a count', {'block_index': index}), + ('an int8 index', {'block_count': count, 'block_index': index.to(torch.int8)}), + ('a 3d index', {'block_count': count, 'block_index': index[0]}), + ('a short index', {'block_count': count, 'block_index': index[..., :-1].contiguous()}), + ('a wrong batch', {'block_count': wide_count, 'block_index': wide_index}), + ) + for label, lists in bad: + try: + raw(q, k, v, **lists) + except ValueError: + continue + raise AssertionError(f'{label} was accepted') + try: + atten_module.sdnq_triton_atten_fwd(q, k, v, None, None, None, sm_scale=0.125, out_dtype=q.dtype, block_count=count, block_index=index, block_mask_m=0, block_mask_n=0) + except ValueError: + return True + raise AssertionError('block lists without block sizes were accepted') + + +# ============================================================ +# Autotune nesting +# ============================================================ + +def test_prune_configs_applies_the_filter(): + """The nesting filter keeps exactly the tiles a mask block divides by, leaves a dense launch alone, and raises rather than letting a tile list that cannot nest run.""" + if not kernel_available: + return None + q, k, v = qkv() + args = { + 'q_ptr': q, 'k_ptr': k, 'v_ptr': v, 'out_ptr': q, + 'QN': 1000, 'KN': 1000, 'QHD': 64, 'KHD': 64, 'VHD': 64, + 'is_causal': 0, 'do_block_mask': 1, 'BLOCK_MASK_M': BLOCK_M, 'BLOCK_MASK_N': BLOCK_N, + } + with_mask = atten_module.prune_configs(configs_for((32, 64, 128, 256), (16, 32, 64, 128)), args) + without = atten_module.prune_configs(configs_for((32, 64, 128, 256), (16, 32, 64, 128)), dict(args, do_block_mask=0)) + assert with_mask, 'nothing survived' + assert [c.kwargs for c in with_mask] == [c.kwargs for c in without if nests(c)], ([c.kwargs for c in with_mask], [c.kwargs for c in without]) + try: # from_small is the terminal arm, so the fallback to the small configs cannot refill the list before the filter reaches it + atten_module.prune_configs(configs_for((256,), (128,)), args, from_small=True) + except ValueError as e: + assert 'SDNQ_TRITON_ATTEN_BLOCK_SIZE_M_LIST' in str(e), e + return True + raise AssertionError('a tile list with nothing nesting did not raise') + + +# ============================================================ +# Public entry +# ============================================================ + +def entry_rows_ready() -> bool: + return kernel_available and entry_accepts_block_mask() + + +def entry_rows(q, k, v, keep, **kwargs) -> bool: + """The block arm within one ulp of the token mask, applied at all, and bitwise the dense path with every block kept.""" + seq_q, seq_kv = q.shape[-2], k.shape[-2] + got = entry(q, k, v, block_mask=keep, block_mask_m=BLOCK_M, block_mask_n=BLOCK_N, **kwargs) + assert_one_ulp(got, entry(q, k, v, attn_mask=expand(keep, seq_q, seq_kv).bool(), **kwargs)) + dense = entry(q, k, v, **kwargs) + assert not torch.equal(got, dense), 'the block mask is not applied' + nq, nk = blocks(seq_q, seq_kv) + ones = torch.ones(1, 1, nq, nk, dtype=torch.int8, device=device) + same_arithmetic(entry(q, k, v, block_mask=ones, block_mask_m=BLOCK_M, block_mask_n=BLOCK_N, **kwargs), dense, f'entry {kwargs.get("matmul_dtype", "int8")}') + return True + + +def test_entry_int8_block_mask(): + if not entry_rows_ready() or not int8_ok: + return None + q, k, v = qkv() + return entry_rows(q, k, v, random_keep(2, 4, 1000, 1000), matmul_dtype='int8') + + +def test_entry_int8_pv_block_mask(): + if not entry_rows_ready() or not int8_ok: + return None + q, k, v = qkv() + return entry_rows(q, k, v, random_keep(2, 4, 1000, 1000), matmul_dtype='int8', pv_matmul_dtype='int8') + + +def test_entry_fp16_accum_block_mask(): + if not entry_rows_ready(): + return None + q, k, v = qkv(dtype=torch.float16) + return entry_rows(q, k, v, random_keep(2, 4, 1000, 1000), matmul_dtype='float16', pv_matmul_dtype='float16', use_fp16_accum=True) + + +def test_entry_normalizes_bool_and_3d_block_masks(): + if not entry_rows_ready(): + return None + q, k, v = qkv(batch=1) + keep = random_keep(1, 4, 1000, 1000) + want = entry(q, k, v, block_mask=keep, block_mask_m=BLOCK_M, block_mask_n=BLOCK_N, do_quantize=False) + assert torch.equal(entry(q, k, v, block_mask=keep.bool(), block_mask_m=BLOCK_M, block_mask_n=BLOCK_N, do_quantize=False), want), 'bool' + assert torch.equal(entry(q, k, v, block_mask=keep[0], block_mask_m=BLOCK_M, block_mask_n=BLOCK_N, do_quantize=False), want), '3d' + return True + + +# ============================================================ +# Backward +# ============================================================ + +def backward_available() -> bool: + return kernel_available and 'block_mask' in inspect.signature(backward_module.sdnq_triton_atten_with_backward).parameters + + +def upstream_grad(shape, seed=17): + """The same upstream gradient for every arm: two arms fed different ones are not comparable at all.""" + return torch.randn(shape, generator=torch.Generator(device=device).manual_seed(seed), device=device, dtype=torch.float32) + + +def grads(q, k, v, upstream=None, **kwargs): + """dq, dk and dv for one attention call through the kernel's autograd function.""" + q, k, v = q.detach().clone().requires_grad_(True), k.detach().clone().requires_grad_(True), v.detach().clone().requires_grad_(True) + out = backward_module.sdnq_triton_atten_with_backward(q, k, v, **kwargs) + if upstream is None: + upstream = upstream_grad(out.shape) + out.backward(upstream.to(out.dtype)) + return q.grad, k.grad, v.grad + + +def test_backward_matches_the_expanded_token_mask(): + """The load-bearing row: the same selection through the block lists and through a token mask has to give the same gradients.""" + if not backward_available(): + return None + seq = 1000 + q, k, v = qkv(seq=seq) + keep = random_keep(2, 4, seq, seq) + block = grads(q, k, v, block_mask=keep, block_mask_m=BLOCK_M, block_mask_n=BLOCK_N, do_quantize=False) + token = grads(q, k, v, attn_mask=expand(keep, seq, seq).bool(), do_quantize=False) + dense = grads(q, k, v, do_quantize=False) + for name, got, want, other in zip(('dq', 'dk', 'dv'), block, token, dense): + assert got is not None and torch.isfinite(got).all(), f'{name} is not finite' + assert_one_ulp(got, want, name) + assert not torch.equal(got, other), f'{name} matches the dense gradient, so the mask never reached the backward' + return True + + +def test_backward_gqa_and_int8(): + """GQA sends every query head's selection into one kv head's gradient, and the quantized path is the one that ships.""" + if not backward_available(): + return None + seq = 1000 + q, k, v = qkv(heads=4, kv_heads=2, seq=seq) + keep = random_keep(2, 4, seq, seq) + for label, kwargs in (('bf16', {'do_quantize': False}), ('int8', {'matmul_dtype': 'int8'})): + if label == 'int8' and not int8_ok: + continue + block = grads(q, k, v, block_mask=keep, block_mask_m=BLOCK_M, block_mask_n=BLOCK_N, **kwargs) + token = grads(q, k, v, attn_mask=expand(keep, seq, seq).bool(), **kwargs) + for name, got, want in zip(('dq', 'dk', 'dv'), block, token): + assert_one_ulp(got, want, f'{label} {name}') + return True + + +def test_backward_zeroes_dropped_blocks(): + """A query block that keeps nothing gets no gradient, and a kv block no query block kept gets none either.""" + if not backward_available(): + return None + seq = 1000 + q, k, v = qkv(seq=seq) + keep = random_keep(2, 4, seq, seq) + keep[..., 2, :] = 0 # query block 2 attends to nothing + keep[..., :, 5] = 0 # kv block 5 is attended by nothing + dq, dk, dv = grads(q, k, v, block_mask=keep, block_mask_m=BLOCK_M, block_mask_n=BLOCK_N, do_quantize=False) + assert torch.isfinite(dq).all() and torch.isfinite(dk).all() and torch.isfinite(dv).all() + assert dq[..., 2 * BLOCK_M:3 * BLOCK_M, :].abs().max().item() == 0.0, 'an empty query block still got a gradient' + assert dq[..., :BLOCK_M, :].abs().max().item() > 0.0 + assert dk[..., 5 * BLOCK_N:6 * BLOCK_N, :].abs().max().item() == 0.0, 'a dropped kv block still got a key gradient' + assert dv[..., 5 * BLOCK_N:6 * BLOCK_N, :].abs().max().item() == 0.0, 'a dropped kv block still got a value gradient' + assert dk[..., :BLOCK_N, :].abs().max().item() > 0.0 + return True + + +def test_backward_matches_fp32_autograd(): + """Against truth rather than against the other masked path: torch's own gradients through fp32 sdpa on the same selection. + + Run in fp32, where the kernel sits within 0.1 percent of autograd; in bf16 the dense backward is already 1.8 percent + out, so a bf16 arm could only carry a bound too loose to catch a mis-walked block. Head dim 32 keeps fp32 inside the + shared memory the widest pinned tile has, which fp32 at head dim 64 exceeds on the dense backward too. + """ + if not backward_available(): + return None + seq, dim = 1000, 32 + q, k, v = (t.float().contiguous() for t in qkv(batch=1, heads=4, seq=seq, dim=dim)) + keep = random_keep(1, 4, seq, seq) + upstream = upstream_grad((1, 4, seq, dim)) + reference = [t.detach().clone().requires_grad_(True) for t in (q, k, v)] + stock_sdpa(*reference, attn_mask=expand(keep, seq, seq).bool()).backward(upstream) + got = grads(q, k, v, upstream=upstream, block_mask=keep, block_mask_m=BLOCK_M, block_mask_n=BLOCK_N, do_quantize=False) + for name, mine, want in zip(('dq', 'dk', 'dv'), got, reference): + scale = want.grad.abs().max().item() + gap = (mine.float() - want.grad).abs().max().item() + log.info(f' {name}: {100 * gap / scale:.3f} percent of the gradient scale against fp32 autograd') + assert gap < 5e-3 * scale, f'{name} is {gap:.3e} off fp32 autograd, more than 0.5 percent of {scale:.3e}' + return True + + +def test_backward_ragged_sub_tile(): + """The transposed lists have the same ragged tail as the forward's: 992 divides the tile and not the mask block.""" + if not backward_available(): + return None + seq = 992 + q, k, v = qkv(seq=seq) + keep = random_keep(2, 4, seq, seq) + block = grads(q, k, v, block_mask=keep, block_mask_m=BLOCK_M, block_mask_n=BLOCK_N, do_quantize=False) + token = grads(q, k, v, attn_mask=expand(keep, seq, seq).bool(), do_quantize=False) + for name, got, want in zip(('dq', 'dk', 'dv'), block, token): + assert torch.isfinite(got).all(), f'{name} is not finite' + assert_one_ulp(got, want, f'seq {seq} {name}') + return True + + +# ============================================================ +# Consumers +# ============================================================ + +def test_kernel_and_flex_agree_on_one_selection(): + if not entry_rows_ready(): + return None + seq = 2048 + q, k, v = qkv(batch=1, heads=4, seq=seq) + selection = sparse.select_blocks(q, k, sparse.SparseSpec(budget=0.25)) + assert selection is not None + reference = stock_sdpa(q.float(), k.float(), v.float(), attn_mask=expand(selection.keep, seq, seq).bool()) + flex_gap = (sparse_flex.attend(q, k, v, selection).float() - reference).abs().max().item() + kernel_gap = (entry(q, k, v, block_mask=selection.keep, block_mask_m=selection.block_q, block_mask_n=selection.block_kv, do_quantize=False).float() - reference).abs().max().item() + log.info(f' gaps against fp32 sdpa on the same tiles: flex {flex_gap:.5f} kernel {kernel_gap:.5f}') + assert flex_gap < 1e-2 and kernel_gap < 1e-2, (flex_gap, kernel_gap) + return True + + +def test_the_pin_left_the_autotuner_one_config(): + # with one config the autotuner benchmarks nothing and prunes nothing, so both arms of every + # bitwise row compiled the same tile; the in-kernel static_assert is the nesting guard there + configs = [conf.kwargs for conf in atten_module.autotune_configs] + assert configs == [{'BLOCK_SIZE_M': block_size_m, 'BLOCK_SIZE_N': block_size_n}], f'the pin did not take: {configs}' + tuner_configs = [conf.kwargs for conf in getattr(atten_module.sdnq_attn_kernel, 'configs', [])] + assert tuner_configs == configs, f'the autotuner holds {tuner_configs}' + return True + + +def run_all(): + log.warning(f'Running sdnq block mask tests on {device}, tile pinned to {block_size_m}x{block_size_n}') + + log.warning('=== kernel contract ===') + cat = category('contract') + for fn in [ + test_block_mask_matches_the_expanded_token_mask, + test_gqa_block_mask_indexes_query_heads, + test_block_mask_broadcasts_over_batch_and_heads, + test_block_lists_must_be_contiguous_and_padded, + test_empty_block_row_gives_zeros_without_nan, + test_block_mask_composes_with_a_token_mask, + test_all_ones_block_mask_matches_no_mask, + test_sub_tile_past_the_sequence_is_masked, + test_launcher_validates_the_block_lists, + ]: + run_test(cat, fn) + + log.warning('=== autotune nesting ===') + cat = category('autotune') + for fn in [ + test_prune_configs_applies_the_filter, + ]: + run_test(cat, fn) + + log.warning('=== public entry ===') + cat = category('entry') + for fn in [ + test_entry_int8_block_mask, + test_entry_int8_pv_block_mask, + test_entry_fp16_accum_block_mask, + test_entry_normalizes_bool_and_3d_block_masks, + ]: + run_test(cat, fn) + + log.warning('=== backward ===') + cat = category('backward') + for fn in [ + test_backward_matches_the_expanded_token_mask, + test_backward_gqa_and_int8, + test_backward_zeroes_dropped_blocks, + test_backward_matches_fp32_autograd, + test_backward_ragged_sub_tile, + ]: + run_test(cat, fn) + + log.warning('=== consumers ===') + cat = category('consumers') + for fn in [ + test_kernel_and_flex_agree_on_one_selection, + test_the_pin_left_the_autotuner_one_config, + ]: + run_test(cat, fn) + + log.warning('=== Results ===') + total_passed = total_failed = total_skipped = 0 + for cat_name, info in results.items(): + ok = info['failed'] == 0 + log.info(f" {cat_name}: {info['passed']} passed, {info['failed']} failed, {info['skipped']} skipped [{'PASS' if ok else 'FAIL'}]") + total_passed += info['passed'] + total_failed += info['failed'] + total_skipped += info['skipped'] + log.warning(f'Total: {total_passed} passed, {total_failed} failed, {total_skipped} skipped') + return total_failed == 0 + + +if __name__ == '__main__': + import time + t0 = time.time() + ok = run_all() + torch.nn.functional.scaled_dot_product_attention = stock_sdpa + log.warning(f'Total time: {time.time() - t0:.2f}s') + sys.exit(0 if ok else 1) diff --git a/test/test-attention-sparse.py b/test/test-attention-sparse.py new file mode 100644 index 000000000..5a51e1e63 --- /dev/null +++ b/test/test-attention-sparse.py @@ -0,0 +1,635 @@ +#!/usr/bin/env python +""" +Offline unit tests for block-sparse attention in modules.attention.sparse. + +Covers: + +- block pooling, including the ragged tail, against a per-block reference +- the diagonal invariant: every query tile keeps the key tiles its tokens overlap +- budget semantics: density tracks the budget over the candidates, pins survive, drops never do +- the dense short circuit, and the force flag that suppresses it for tests +- determinism of the selection for identical inputs +- layout reading: the *_indices form a pipeline passes by name, with a non-final video run + relabelled as conditioning, and the segment form a transformer knows at its packing site +- pins and drops derived from a layout: pinned columns, dropped padding, pinned boundary tiles +- the flex consumer: a full-keep selection through flex_attention reproduces dense sdpa, and a + selection with dropped tiles reproduces sdpa given the same tiles masked out +- the density matched radial control and the step schedule +- the router stage: the gates it applies (component role, mask, causal, cross attention, minimum + sequence), the per step budget schedule, and layout resolution with and without a publisher + +The flex rows need a cuda device and compile the flex kernel; they skip on cpu. + +Usage: + python test/test-attention-sparse.py +""" + +import os +import sys + +import torch + +script_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) +sys.path.insert(0, script_dir) +os.chdir(script_dir) + +os.environ['SD_INSTALL_QUIET'] = '1' + +# Bootstrap cmd_args before any module that pulls in shared.py. +import modules.cmd_args # pylint: disable=wrong-import-position +import installer # pylint: disable=wrong-import-position +orig_argv = sys.argv +sys.argv = [sys.argv[0]] +try: + modules.cmd_args.parse_args() +finally: + sys.argv = orig_argv +installer.add_args(modules.cmd_args.parser) +modules.cmd_args.parsed, _ = modules.cmd_args.parser.parse_known_args([]) + +stock_sdpa = torch.nn.functional.scaled_dot_product_attention # captured before shared installs the configured hijacks + +from modules.errors import log # pylint: disable=wrong-import-position +from modules import shared # pylint: disable=wrong-import-position,unused-import +from modules.attention import sparse # pylint: disable=wrong-import-position +from modules.attention.sparse import flex as sparse_flex # pylint: disable=wrong-import-position + + +results: dict[str, dict] = {} +device = torch.device('cuda') if torch.cuda.is_available() else torch.device('cpu') + + +def category(name: str): + if name not in results: + results[name] = {'passed': 0, 'failed': 0, 'skipped': 0, 'tests': []} + return name + + +def record(cat: str, passed, name: str, detail: str = ''): + status = 'SKIP' if passed is None else ('PASS' if passed else 'FAIL') + key = {'SKIP': 'skipped', 'PASS': 'passed', 'FAIL': 'failed'}[status] + results[cat][key] += 1 + results[cat]['tests'].append((status, name)) + msg = f' {status}: {name}' + if detail: + msg += f' ({detail})' + (log.info if status != 'FAIL' else log.error)(msg) + + +def run_test(cat: str, fn): + name = fn.__name__ + try: + outcome = fn() + record(cat, None if outcome is None else bool(outcome), name) + except AssertionError as e: + record(cat, False, name, str(e)) + except Exception as e: # pylint: disable=broad-except + record(cat, False, name, f'exception: {e}') + import traceback + traceback.print_exc() + + +generator = torch.Generator(device=device).manual_seed(1234) + + +def randn(*shape, dtype=torch.float32): + return torch.randn(*shape, generator=generator, device=device, dtype=dtype) + + +def qkv(heads=4, seq=1024, dim=64): + return randn(1, heads, seq, dim), randn(1, heads, seq, dim), randn(1, heads, seq, dim) + + +# ============================================================ +# Selector +# ============================================================ + +def test_pooling_matches_a_per_block_reference(): + x = randn(1, 2, 300, 8) + pooled = sparse.selector.pool_blocks(x, 128) + assert pooled.shape == (1, 2, 3, 8), pooled.shape + for index, (start, end) in enumerate([(0, 128), (128, 256), (256, 300)]): + expected = x[..., start:end, :].to(torch.float32).mean(dim=-2) + assert torch.allclose(pooled[..., index, :], expected, atol=1e-5), index + return True + + +def test_diagonal_covers_every_overlapping_tile(): + nq, nk, bq, bk = 4, 8, 128, 64 + diagonal = sparse.selector.diagonal_blocks(nq, nk, bq, bk, device) + for i in range(nq): + for j in range(nk): + overlaps = (i * bq < (j + 1) * bk) and (j * bk < (i + 1) * bq) + assert bool(diagonal[i, j]) == overlaps, (i, j) + assert int(diagonal.sum().item()) == nq * (bq // bk) # two kv tiles per query tile at 128 over 64 + return True + + +def test_budget_sets_density_over_the_candidates(): + q, k = randn(1, 4, 1024, 32), randn(1, 4, 1024, 32) + for budget in (0.15, 0.30, 0.50): + spec = sparse.SparseSpec(budget=budget) + selection = sparse.select_blocks(q, k, spec) + assert selection is not None, budget + keep = selection.keep + diagonal = sparse.selector.diagonal_blocks(keep.shape[-2], keep.shape[-1], spec.block_q, spec.block_kv, device) + candidates = int((~diagonal).sum().item()) + chosen = int((keep.bool() & ~diagonal).sum().item()) / keep.shape[1] + expected = candidates * budget + assert abs(chosen - expected) <= keep.shape[-2], f'budget={budget} chose {chosen} of {candidates}, expected about {expected}' + assert bool((keep.bool() | ~diagonal).all()), 'a diagonal tile was dropped' + return True + + +def test_pins_survive_and_drops_never_appear(): + q, k = randn(1, 2, 512, 32), randn(1, 2, 512, 32) + spec = sparse.SparseSpec(budget=0.10) + nq = sparse.block_count(512, spec.block_q) + nk = sparse.block_count(512, spec.block_kv) + pins = torch.zeros(1, 1, nq, nk, dtype=torch.bool, device=device) + drops = torch.zeros_like(pins) + pins[..., 0] = True # a pinned column, as a text prefix produces + drops[..., -1] = True # a padding column + selection = sparse.select_blocks(q, k, spec, pins=pins, drops=drops) + assert selection is not None + assert bool(selection.keep[..., 0].all()), 'pinned column not kept' + assert not bool(selection.keep[..., -1].any()), 'dropped column kept' + return True + + +def test_dense_short_circuit_and_force(): + q, k = randn(1, 2, 512, 32), randn(1, 2, 512, 32) + assert sparse.select_blocks(q, k, sparse.SparseSpec(budget=1.0)) is None, 'full budget must report dense' + forced = sparse.select_blocks(q, k, sparse.SparseSpec(budget=1.0, force=True)) + assert forced is not None and bool(forced.keep.all()), 'forced full budget must keep every tile' + return True + + +def test_selection_is_deterministic(): + q, k = randn(1, 4, 1024, 32), randn(1, 4, 1024, 32) + spec = sparse.SparseSpec(budget=0.25) + first = sparse.select_blocks(q, k, spec) + second = sparse.select_blocks(q, k, spec) + assert torch.equal(first.keep, second.keep) + return True + + +def test_head_shared_collapses_the_head_dimension(): + q, k = randn(1, 8, 1024, 32), randn(1, 8, 1024, 32) + selection = sparse.select_blocks(q, k, sparse.SparseSpec(budget=0.25, head_shared=True)) + assert selection.keep.shape[1] == 1, selection.keep.shape + return True + + +def test_gqa_scores_on_query_heads(): + q, k = randn(1, 8, 1024, 32), randn(1, 2, 1024, 32) + selection = sparse.select_blocks(q, k, sparse.SparseSpec(budget=0.25)) + assert selection.keep.shape[1] == 8, selection.keep.shape # both consumers need the mask head dim to be Hq or 1 + return True + + +# ============================================================ +# Layout +# ============================================================ + +def test_layout_from_index_kwargs_relabels_the_conditioning_video_run(): + kwargs = { # the shape MiniMax H3 passes its transformer: text, a keyframe video run, audio, then the generated video + 'text_indices': torch.arange(0, 8, device=device), + 'video_indices': torch.cat([torch.arange(8, 12, device=device), torch.arange(20, 40, device=device)]), + 'audio_indices': torch.arange(12, 20, device=device), + 'hidden_states': torch.zeros(1, device=device), # not an index tensor, must be ignored + } + layout = sparse.layout_from_index_kwargs(kwargs, length=40) + kinds = [(s.kind, s.start, s.end) for s in layout.spans] + assert kinds == [('text', 0, 8), ('cond', 8, 12), ('audio', 12, 20), ('video', 20, 40)], kinds + assert layout.sparsifiable_tokens() == 20 + return True + + +def test_layout_from_index_kwargs_returns_none_without_indices(): + assert sparse.layout_from_index_kwargs({'hidden_states': torch.zeros(4, device=device)}, length=4) is None + return True + + +def test_layout_from_segments_and_prefix(): + layout = sparse.layout_from_segments([('text', 128), ('image', 4096), ('pad', 128)]) + assert layout.length == 4352 and layout.sparsifiable_tokens() == 4096 + prefix = sparse.layout_from_prefix(1024, 64) + assert prefix.sparsifiable_tokens() == 960 and prefix.source == 'prefix' + return True + + +def test_block_pins_pin_conditioning_and_drop_padding(): + block_q, block_kv = 128, 64 + layout = sparse.layout_from_segments([('text', 128), ('video', 1024), ('pad', 128)]) + pins, drops = sparse.block_pins(layout, 1280, 1280, block_q, block_kv, device) + assert pins.shape == (1, 1, 10, 20) and drops.shape == pins.shape, (pins.shape, drops.shape) + assert bool(pins[0, 0, :, 0:2].all()), 'the text columns must be pinned' + assert bool(drops[0, 0, :, 18:20].all()), 'the padding columns must be dropped' + assert not bool(drops[0, 0, :, 0:18].any()), 'only padding may be dropped' + assert bool(pins[0, 0, 0, 0:18].all()), 'the query tile holding text must stay dense over every column that is not padding' + assert not bool(pins[0, 0, :, 18:20].any()), 'a dropped column is skipped, never pinned' + assert not bool(pins[0, 0, 1:9, 2:18].any()), 'video against video must remain sparsifiable' + return True + + +def test_block_pins_pin_a_boundary_tile(): + layout = sparse.layout_from_segments([('text', 100), ('video', 1180)]) # the boundary falls inside the first tile + pins, drops = sparse.block_pins(layout, 1280, 1280, 128, 64, device) + assert not bool(drops.any()), 'nothing is padding here' + assert bool(pins[0, 0, 0, :].all()), 'a query tile straddling a boundary must stay dense' + assert bool(pins[0, 0, :, 0:2].all()), 'a key tile straddling a boundary must stay dense' + return True + + +def test_segments_from_live_splits_interior_padding(): + from modules.attention.sparse import layout as layout_mod + live = torch.zeros(512, dtype=torch.bool, device=device) + live[:40] = True + live[-8:] = True + segments = layout_mod.segments_from_live(live, 'text') + assert segments == [('text', 40), ('pad', 464), ('text', 8)], segments + token_layout = layout_mod.layout_from_segments(segments + [('image', 1024)]) + assert token_layout.length == 1536, token_layout.length + _, drops = layout_mod.block_pins(token_layout, 1536, 1536, 128, 64, device) + # only a key block that is padding all the way through is dropped, so the two straddling blocks survive + assert drops[..., 1:7].all(), 'whole padded key blocks are dropped' + assert not drops[..., 0].any() and not drops[..., 7].any(), 'a straddling block keeps its live tokens' + return True + + +def test_layout_from_stream_ids_reads_the_joint_convention(): + from modules.attention.sparse import layout as layout_mod + flat = (torch.zeros(512, 3, device=device), torch.zeros(4096, 3, device=device)) # flux1 passes 2d ids + batched = (torch.zeros(1, 512, 4, device=device), torch.zeros(1, 4096, 4, device=device)) # flux2 passes 3d + for text, image in (flat, batched): + token_layout = layout_mod.layout_from_stream_ids({'txt_ids': text, 'img_ids': image}, 'FluxTransformer2DModel') + assert token_layout is not None and token_layout.length == 4608, token_layout + assert [(s.kind, s.start, s.end) for s in token_layout.spans] == [('text', 0, 512), ('image', 512, 4608)], token_layout.spans + # an architecture whose packing order is not verified publishes nothing rather than pinning the wrong half dense + assert layout_mod.layout_from_stream_ids({'txt_ids': flat[0], 'img_ids': flat[1]}, 'HiDreamImageTransformer2DModel') is None + assert layout_mod.layout_from_stream_ids({'txt_ids': flat[0], 'img_ids': flat[1]}, None) is None + assert layout_mod.layout_from_stream_ids({}, 'FluxTransformer2DModel') is None + indices = {'video_indices': torch.arange(0, 64, device=device), 'txt_ids': flat[0], 'img_ids': flat[1]} + assert layout_mod.layout_from_kwargs(indices, 'FluxTransformer2DModel').source == 'indices', 'the index form wins when both are present' + return True + + +def test_layout_hook_publishes_from_the_denoiser_kwargs(): + from modules.attention import context as ctx + + class FluxTransformer2DModel(torch.nn.Module): # the reader keys on the class name, so the fake carries a real one + def forward(self, hidden_states=None, txt_ids=None, img_ids=None): # pylint: disable=unused-argument + return hidden_states + + class Pipe: + def __init__(self, transformer, second): + self.transformer = transformer + self.unconditional_transformer = second # ideogram runs a second denoiser, wan a14b a transformer_2 + + denoiser = FluxTransformer2DModel() + second = FluxTransformer2DModel() + pipe = Pipe(denoiser, second) + previous = getattr(shared.opts, 'sparse_attention_enabled', False) + try: + shared.opts.data['sparse_attention_enabled'] = False + ctx.install_layout_hook(pipe) + assert getattr(denoiser, 'sdnext_layout_hook', None) is None, 'nothing is hooked while the feature is off' + shared.opts.data['sparse_attention_enabled'] = True + ctx.install_layout_hook(pipe) + ctx.install_layout_hook(pipe) + assert getattr(denoiser, 'sdnext_layout_hook', None) is not None, 'the denoiser is hooked once' + assert getattr(second, 'sdnext_layout_hook', None) is not None, 'every denoiser slot is hooked, not just the first' + ctx.set_layout(None) + denoiser(hidden_states=torch.zeros(1, 4096, 4, device=device), txt_ids=torch.zeros(512, 3, device=device), img_ids=torch.zeros(4096, 3, device=device)) + published = ctx.current.layout + assert published is not None and published.length == 4608 and published.source == 'stream-ids', published + finally: + shared.opts.data['sparse_attention_enabled'] = previous + ctx.set_layout(None) + return True + + +def test_block_pins_are_cached_per_geometry(): + layout = sparse.layout_from_segments([('text', 128), ('video', 1024)]) + first = sparse.block_pins(layout, 1152, 1152, 128, 64, device) + second = sparse.block_pins(layout, 1152, 1152, 128, 64, device) + assert first[0] is second[0] and first[1] is second[1], 'identical geometry should hit the cache' + return True + + +# ============================================================ +# Consumers and controls +# ============================================================ + +def test_radial_control_matches_the_requested_density(): + spec = sparse.SparseSpec() + for density in (0.15, 0.30): + control = sparse.radial_blocks(4096, 4096, density, spec, device) + assert abs(control.density() - density) < 0.05, f'requested {density}, got {control.density()}' + return True + + +def test_schedule_has_at_most_two_budgets(): + flat = sparse.schedule(20, 0.3) + assert set(flat) == {0.3} and len(flat) == 20 + bumped = sparse.schedule(20, 0.3, bump=0.3, bump_steps=2) + assert len(set(bumped)) == 2, set(bumped) + assert bumped[0] == bumped[1] == 0.6 and bumped[-1] == bumped[-2] == 0.6 and bumped[10] == 0.3 + return True + + +def flex_available(): + return device.type == 'cuda' + + +def kernel_floor(q, k, v): + """How far the flex kernel sits from sdpa on the same dense problem, which bounds what any sparse row can prove.""" + full = sparse.select_blocks(q, k, sparse.SparseSpec(budget=1.0, force=True)) + return (sparse_flex.attend(q, k, v, full) - stock_sdpa(q, k, v)).abs().max().item() + + +def test_flex_full_selection_reproduces_dense_sdpa(): + if not flex_available(): + return None + q, k, v = qkv() + floor = kernel_floor(q, k, v) + assert floor < 5e-3, f'a full selection should reproduce dense sdpa, differs by {floor}' + log.info(f' flex kernel floor vs sdpa: {floor:.6f}') + return True + + +def test_flex_sparse_selection_matches_the_same_tiles_under_sdpa(): + if not flex_available(): + return None + q, k, v = qkv() + spec = sparse.SparseSpec(budget=0.25) + selection = sparse.select_blocks(q, k, spec) + got = sparse_flex.attend(q, k, v, selection) + # expand the tile selection to tokens and hand sdpa the same thing + token_mask = selection.keep.bool().repeat_interleave(spec.block_q, dim=-2).repeat_interleave(spec.block_kv, dim=-1) + expected = stock_sdpa(q, k, v, attn_mask=token_mask[..., :q.shape[-2], :k.shape[-2]]) + delta = (got - expected).abs().max().item() + floor = kernel_floor(q, k, v) + assert delta <= max(4 * floor, 2e-3), f'sparse selection differs from the same tiles under sdpa by {delta}, floor {floor}' + return True + + +def test_flex_applies_the_selection_at_all(): + if not flex_available(): + return None + # flex reads the block lists only when compiled; eager evaluates mask_mod instead, so a + # block only mask silently attends densely. this row fails if the consumer stops compiling. + q, k, v = qkv() + selection = sparse.select_blocks(q, k, sparse.SparseSpec(budget=0.25)) + delta = (sparse_flex.attend(q, k, v, selection) - stock_sdpa(q, k, v)).abs().max().item() + floor = kernel_floor(q, k, v) + assert delta > 20 * max(floor, 1e-6), f'a 25 percent selection changed the output by only {delta}, floor {floor}: the mask is not being applied' + return True + + +def test_flex_handles_a_ragged_tail(): + if not flex_available(): + return None + seq = 1000 # neither block size divides this + q, k, v = qkv(heads=2, seq=seq) + selection = sparse.select_blocks(q, k, sparse.SparseSpec(budget=1.0, force=True)) + delta = (sparse_flex.attend(q, k, v, selection) - stock_sdpa(q, k, v)).abs().max().item() + assert delta < 5e-3, f'ragged tail differs by {delta}' + return True + + +# ============================================================ +# Router stage +# ============================================================ + +def stage_options(**kwargs): + from modules.attention.sparse import stage as stage_mod + base = dict(enabled=True, budget=0.30, min_tokens=1024) + base.update(kwargs) + return stage_mod.StageOptions(**base) + + +def with_context(fn): + from modules.attention import context as ctx + ctx.begin(None, steps=10) + try: + return fn() + finally: + ctx.end() + + +def test_stage_is_none_when_disabled_or_at_full_budget(): + from modules.attention.sparse import stage as stage_mod + assert stage_mod.make_stage(stage_options(enabled=False)) is None + assert stage_mod.make_stage(stage_options(budget=1.0)) is None + assert stage_mod.make_stage(stage_options()) is not None + return True + + +def test_stage_gates(): + from modules.attention.sparse import stage as stage_mod + stage = stage_mod.make_stage(stage_options()) + q, k, v = qkv(heads=2, seq=2048) + short_q, short_k, short_v = qkv(heads=2, seq=512) + cross_k, cross_v = randn(1, 2, 77, 64), randn(1, 2, 77, 64) + + def checks(): + from modules.attention import context as ctx + assert stage(q, k, v, None, False) is not None, 'an eligible call must be selected' + mask = torch.zeros(1, 1, 2048, 2048, dtype=torch.bool, device=device) + assert stage(q, k, v, mask, False) is None, 'a masked call needs a backend that composes the two' + assert stage(q, k, v, mask, False, frozenset({'masked_block'})) is not None, 'a composing backend takes the masked call' + assert stage(q, k, v, None, True) is None, 'a causal call is not eligible' + assert stage(q, cross_k, cross_v, None, False) is None, 'cross attention is not eligible' + assert stage(short_q, short_k, short_v, None, False) is None, 'below the gate attention stays dense' + assert stage.last_skip == 'below the minimum sequence', stage.last_skip + ctx.set_role('vae') + assert stage(q, k, v, None, False) is None, 'only the denoiser is sparsified' + ctx.set_role('transformer') + return True + return with_context(checks) + + +def test_minimum_sequence_of_zero_sparsifies_everything(): + from modules.attention.sparse import stage as stage_mod + floored = stage_mod.make_stage(stage_options()) + unfloored = stage_mod.make_stage(stage_options(min_tokens=0)) + short_q, short_k, short_v = qkv(heads=2, seq=512) + + def checks(): + assert floored(short_q, short_k, short_v, None, False) is None, 'the default floor keeps a short sequence dense' + assert unfloored(short_q, short_k, short_v, None, False) is not None, 'a floor of zero sparsifies every eligible call' + return True + return with_context(checks) + + +def test_exclusion_list_parsing(): + from modules.attention.sparse import stage as stage_mod + assert stage_mod.parse_exclusions(' Anima , CosmosTransformer3DModel ,, ') == ('anima', 'cosmostransformer3dmodel') + assert stage_mod.parse_exclusions('') == () + assert stage_mod.parse_exclusions(None) == () + return True + + +def test_an_exclusion_entry_matches_any_of_the_three_names(): + """One entry, matched against whichever of the architecture, pipeline class or denoiser class the user knew.""" + from modules.attention.sparse import stage as stage_mod + key = ('AnimaTextToImagePipeline', 'CosmosTransformer3DModel') + for entry in ('cosmostransformer3dmodel', 'animatexttoimagepipeline', 'anima'): + assert stage_mod.match_exclusion(key, 'anima', (entry,)) == entry, entry + assert stage_mod.match_exclusion(key, 'anima', ('krea2',)) == '', 'an unlisted model matches nothing' + assert stage_mod.match_exclusion(None, 'anima', ('anima',)) == 'anima', 'the architecture stands in when no model key is published' + assert stage_mod.match_exclusion(('Pipe', None), None, ('pipe',)) == 'pipe', 'an absent denoiser class is skipped, not matched' + return True + + +def test_an_excluded_model_stays_dense(): + from modules.attention import context as ctx + from modules.attention.sparse import stage as stage_mod + listed = stage_mod.make_stage(stage_options(exclude=('cosmostransformer3dmodel',))) + unlisted = stage_mod.make_stage(stage_options(exclude=('somethingelse',))) + q, k, v = qkv(heads=2, seq=2048) + + def checks(): + ctx.current.model_key = ('AnimaTextToImagePipeline', 'CosmosTransformer3DModel') + assert listed(q, k, v, None, False) is None, 'a listed denoiser class stays dense' + assert listed.last_skip == 'excluded', listed.last_skip + assert unlisted(q, k, v, None, False) is not None, 'a list that matches nothing changes nothing' + ctx.current.model_key = ('Krea2Pipeline', 'Krea2Transformer2DModel') + assert listed(q, k, v, None, False) is not None, 'the exclusion applies to the listed model, not to every model' + return True + return with_context(checks) + + +def test_published_segments_reach_the_stage(): + from modules.attention.sparse import layout as layout_mod + from modules.attention.sparse import stage as stage_mod + from modules.attention import context as ctx + stage = stage_mod.make_stage(stage_options(budget=0.30)) + q, k, v = qkv(heads=2, seq=2048) + + def checks(): + layout_mod.publish_segments((('text', 256), ('image', 1536), ('pad', 256)), source='test') + published = ctx.current.layout + assert published.length == 2048 and published.source == 'test', published + assert published.kinds() == ('text', 'image', 'pad'), published.kinds() + selection = stage(q, k, v, None, False) + keep, block_kv = selection.keep, selection.block_kv + assert keep[..., :256 // block_kv].all(), 'conditioning key tiles stay dense' + assert not keep[..., 1792 // block_kv:].any(), 'padding key tiles are dropped' + return True + return with_context(checks) + + +def test_stage_follows_the_step_schedule(): + from modules.attention.sparse import stage as stage_mod + from modules.attention import context as ctx + stage = stage_mod.make_stage(stage_options(budget=0.30, schedule_steps=2, schedule_bump=0.40)) + q, k, v = qkv(heads=2, seq=2048) + + def checks(): + densities = [] + for step in range(10): + ctx.set_step(step) + selection = stage(q, k, v, None, False) + densities.append(selection.budget) + assert densities[0] == densities[1] > densities[5], densities + assert densities[-1] == densities[-2] > densities[5], densities + assert len(set(densities)) == 2, set(densities) + return True + return with_context(checks) + + +def test_stage_uses_a_published_layout_and_falls_back_without_one(): + from modules.attention.sparse import stage as stage_mod + from modules.attention import context as ctx + stage = stage_mod.make_stage(stage_options(budget=0.20)) + q, k, v = qkv(heads=2, seq=2048) + + def checks(): + loose = stage(q, k, v, None, False) + ctx.set_layout(sparse.layout_from_segments([('text', 256), ('video', 1792)])) + pinned = stage(q, k, v, None, False) + assert pinned.density() > loose.density(), f'pinning conditioning must keep more tiles: {pinned.density()} vs {loose.density()}' + assert bool(pinned.keep[..., 0:4].all()), 'the pinned text columns must survive' + return True + return with_context(checks) + + +def run_all(): + log.warning(f'=== selector (device={device}) ===') + cat = category('selector') + for fn in [ + test_pooling_matches_a_per_block_reference, + test_diagonal_covers_every_overlapping_tile, + test_budget_sets_density_over_the_candidates, + test_pins_survive_and_drops_never_appear, + test_dense_short_circuit_and_force, + test_selection_is_deterministic, + test_head_shared_collapses_the_head_dimension, + test_gqa_scores_on_query_heads, + ]: + run_test(cat, fn) + + log.warning('=== layout ===') + cat = category('layout') + for fn in [ + test_layout_from_index_kwargs_relabels_the_conditioning_video_run, + test_layout_from_index_kwargs_returns_none_without_indices, + test_layout_from_segments_and_prefix, + test_block_pins_pin_conditioning_and_drop_padding, + test_block_pins_pin_a_boundary_tile, + test_block_pins_are_cached_per_geometry, + test_segments_from_live_splits_interior_padding, + test_layout_from_stream_ids_reads_the_joint_convention, + test_layout_hook_publishes_from_the_denoiser_kwargs, + ]: + run_test(cat, fn) + + log.warning('=== consumers ===') + cat = category('consumers') + for fn in [ + test_radial_control_matches_the_requested_density, + test_schedule_has_at_most_two_budgets, + test_flex_full_selection_reproduces_dense_sdpa, + test_flex_sparse_selection_matches_the_same_tiles_under_sdpa, + test_flex_applies_the_selection_at_all, + test_flex_handles_a_ragged_tail, + ]: + run_test(cat, fn) + + log.warning('=== stage ===') + cat = category('stage') + for fn in [ + test_stage_is_none_when_disabled_or_at_full_budget, + test_stage_gates, + test_exclusion_list_parsing, + test_an_exclusion_entry_matches_any_of_the_three_names, + test_an_excluded_model_stays_dense, + test_minimum_sequence_of_zero_sparsifies_everything, + test_stage_follows_the_step_schedule, + test_published_segments_reach_the_stage, + test_stage_uses_a_published_layout_and_falls_back_without_one, + ]: + run_test(cat, fn) + + log.warning('=== Results ===') + total_passed = total_failed = total_skipped = 0 + for cat_name, info in results.items(): + ok = info['failed'] == 0 + log.info(f" {cat_name}: {info['passed']} passed, {info['failed']} failed, {info['skipped']} skipped [{'PASS' if ok else 'FAIL'}]") + total_passed += info['passed'] + total_failed += info['failed'] + total_skipped += info['skipped'] + log.warning(f'Total: {total_passed} passed, {total_failed} failed, {total_skipped} skipped') + return total_failed == 0 + + +if __name__ == '__main__': + import time + t0 = time.time() + ok = run_all() + torch.nn.functional.scaled_dot_product_attention = stock_sdpa + log.warning(f'Total time: {time.time() - t0:.2f}s') + sys.exit(0 if ok else 1) diff --git a/test/test-chroma-native-adapters.py b/test/test-chroma-native-adapters.py index 696746694..b21114a8f 100644 --- a/test/test-chroma-native-adapters.py +++ b/test/test-chroma-native-adapters.py @@ -591,7 +591,7 @@ def test_parse_key_all_prefixes(): # Bare BFL path (no prefix) ('double_blocks.0.img_attn.proj.lora_A.weight', C.LORA_SUFFIXES, - (None, 'double_blocks.0.img_attn.proj', 'lora_down.weight')), + (C.BARE_DIFFUSERS_PREFIX_USED, 'double_blocks.0.img_attn.proj', 'lora_down.weight')), ('random.unrelated.key', C.LORA_SUFFIXES, None), ] for key, suffixes, expected in cases: @@ -649,7 +649,7 @@ def test_resolve_targets_extra_and_guidance(): for bfl_base, diffusers_path in C.CHROMA_EXTRA_MAP.items(): for prefix, base in [ ('diffusion_model.', bfl_base), - (None, bfl_base), + (C.BARE_DIFFUSERS_PREFIX_USED, bfl_base), ('lora_unet_', bfl_base.replace('.', '_')), ]: targets = C.resolve_targets(prefix, base) @@ -657,12 +657,12 @@ def test_resolve_targets_extra_and_guidance(): cases = [ # BFL MLP leaves rename to the PixArt projection names. (('diffusion_model.', 'distilled_guidance_layer.layers.0.in_layer'), 'distilled_guidance_layer.layers.0.linear_1'), - ((None, 'distilled_guidance_layer.layers.1.out_layer'), 'distilled_guidance_layer.layers.1.linear_2'), + ((C.BARE_DIFFUSERS_PREFIX_USED, 'distilled_guidance_layer.layers.1.out_layer'), 'distilled_guidance_layer.layers.1.linear_2'), (('lora_unet_', 'distilled_guidance_layer_layers_0_in_layer'), 'distilled_guidance_layer_layers_0_linear_1'), (('lora_unet_', 'distilled_guidance_layer_layers_1_out_layer'), 'distilled_guidance_layer_layers_1_linear_2'), # Verbatim leaves are untouched in either naming. (('diffusion_model.', 'distilled_guidance_layer.in_proj'), 'distilled_guidance_layer.in_proj'), - ((None, 'distilled_guidance_layer.layers.0.linear_1'), 'distilled_guidance_layer.layers.0.linear_1'), + ((C.BARE_DIFFUSERS_PREFIX_USED, 'distilled_guidance_layer.layers.0.linear_1'), 'distilled_guidance_layer.layers.0.linear_1'), ] for (prefix, base), expected in cases: targets = C.resolve_targets(prefix, base) diff --git a/test/test-flux2-native-adapters.py b/test/test-flux2-native-adapters.py index 1375e25a1..816573570 100644 --- a/test/test-flux2-native-adapters.py +++ b/test/test-flux2-native-adapters.py @@ -670,7 +670,7 @@ def test_parse_key_all_prefixes(): ('transformer.', 'transformer_blocks.0.attn.to_q', 'lora_up.weight')), ('double_blocks.10.img_mlp.0.lora_A.weight', F.LORA_SUFFIXES, - (None, 'double_blocks.10.img_mlp.0', 'lora_down.weight')), + (F.BARE_DIFFUSERS_PREFIX_USED, 'double_blocks.10.img_mlp.0', 'lora_down.weight')), ('random.unrelated.key', F.LORA_SUFFIXES, None), ] for key, suffixes, expected in cases: @@ -712,13 +712,13 @@ def test_resolve_targets_extra_modules(): for bfl_base, diffusers_path in F.F2_EXTRA_MAP.items(): targets = F.resolve_targets('diffusion_model.', bfl_base) assert targets == [(diffusers_path, None)], f'{bfl_base} -> {targets}' - targets = F.resolve_targets(None, bfl_base) + targets = F.resolve_targets(F.BARE_DIFFUSERS_PREFIX_USED, bfl_base) assert targets == [(diffusers_path, None)], f'bare {bfl_base} -> {targets}' targets = F.resolve_targets('lora_unet_', bfl_base.replace('.', '_')) assert targets == [(diffusers_path, None)], f'kohya {bfl_base} -> {targets}' - # guidance_in is a bare BFL prefix in its own right. + # guidance_in is a bare BFL path. got = F.parse_key('guidance_in.in_layer.lora_A.weight', F.LORA_SUFFIXES) - assert got == (None, 'guidance_in.in_layer', 'lora_down.weight'), f'bare guidance_in parse -> {got}' + assert got == (F.BARE_DIFFUSERS_PREFIX_USED, 'guidance_in.in_layer', 'lora_down.weight'), f'bare guidance_in parse -> {got}' return True @@ -734,7 +734,7 @@ def test_parse_key_peft_wrapper_unwrap(): cases = [ ('base_model.model.double_blocks.1.img_attn.proj.lora_A.weight', F.LORA_SUFFIXES, - (None, 'double_blocks.1.img_attn.proj', 'lora_down.weight')), + (F.BARE_DIFFUSERS_PREFIX_USED, 'double_blocks.1.img_attn.proj', 'lora_down.weight')), ('base_model.model.transformer.transformer_blocks.0.attn.to_q.lora_A.weight', F.LORA_SUFFIXES, ('transformer.', 'transformer_blocks.0.attn.to_q', 'lora_down.weight')), diff --git a/test/test-json-helpers.py b/test/test-json-helpers.py new file mode 100644 index 000000000..22a677970 --- /dev/null +++ b/test/test-json-helpers.py @@ -0,0 +1,378 @@ +#!/usr/bin/env python +""" +Offline tests for modules.json_helpers on Linux and Windows. + +Covers: + +- atomic saves replace a fresh or existing target and leave no temp file, including when the save fails +- an atomic save waits out a target another thread briefly holds open, which Windows otherwise refuses +- overlapping locked reads and atomic writes never fail or read a torn file, and no lock file is created +- locked readers never see a torn file while unlocked writers rewrite it in place +- a lock file left behind by the former file lock is removed +- concurrent inserts into a shared dict never drop a save +- default writes are atomic, so unlocked readers never see a torn file either +- an atomic write through a symlink replaces the file it points at and keeps the link +- a read waits out an open that is refused while a replace is in flight +- an empty file reads as empty and is reported unless the read is silent +- readfile returns what writefile wrote, as dict and as list +- the hash cache saves cleanly while other threads keep adding hashes + +No running server required. + +Usage: + python test/test-json-helpers.py +""" + +import importlib +import json +import os +import shutil +import sys +import tempfile +import threading +import time + +script_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) +sys.path.insert(0, script_dir) +os.chdir(script_dir) +sys.argv = [sys.argv[0]] + +from modules.logger import log # pylint: disable=wrong-import-position +from modules import json_helpers # pylint: disable=wrong-import-position + + +class ErrorLog: + """Counts error and warning lines from json_helpers while passing everything else to the real logger.""" + + def __init__(self, inner): + self.inner = inner + self.errors = [] + self.warnings = [] + self.lock = threading.Lock() + + def error(self, message, *args, **kwargs): + with self.lock: + self.errors.append(str(message)) + + def warning(self, message, *args, **kwargs): + with self.lock: + self.warnings.append(str(message)) + + def count(self, needle): + return sum(1 for m in self.errors if needle in m) + + def __getattr__(self, name): + return getattr(self.inner, name) + + +def fresh_helper(): + importlib.reload(json_helpers) + json_helpers.log = ErrorLog(log) + return json_helpers + + +def run_threads(worker, count): + pool = [threading.Thread(target=worker, args=(n,)) for n in range(count)] + for t in pool: + t.start() + for t in pool: + t.join() + + +def leftovers(folder, target): + keep = {os.path.basename(target), os.path.basename(target) + '.lock'} + return sorted(set(os.listdir(folder)) - keep) + + +def test_atomic_save_replaces_target(folder): + jh = fresh_helper() + target = os.path.join(folder, 'atomic.json') + jh.writefile({'first': 1}, target, silent=True, atomic=True) + assert jh.readfile(target, silent=True, as_type='dict') == {'first': 1}, 'fresh target not written' + jh.writefile({'second': 2}, target, silent=True, atomic=True) + assert jh.readfile(target, silent=True, as_type='dict') == {'second': 2}, 'existing target not replaced' + assert leftovers(folder, target) == [], f'temp files left: {leftovers(folder, target)}' + assert jh.log.errors == [], jh.log.errors + + +def test_failed_atomic_save_leaves_no_temp(folder): + jh = fresh_helper() + target = os.path.join(folder, 'blocked.json') + os.mkdir(target) # a directory cannot be replaced by a file + jh.writefile({'x': 1}, target, silent=True, atomic=True) + assert jh.log.count('Save failed') == 1, jh.log.errors + assert os.path.isdir(target), 'target directory was replaced' + assert leftovers(folder, target) == [], f'temp files left: {leftovers(folder, target)}' + + +def test_atomic_save_waits_for_open_target(folder): + jh = fresh_helper() + target = os.path.join(folder, 'open.json') + jh.writefile({'v': 0}, target, silent=True) + opened = threading.Event() + release = threading.Event() + + def holder(_n): + with open(target, 'rb') as f: + f.read(1) + opened.set() + release.wait(5) + + thread = threading.Thread(target=holder, args=(0,)) + thread.start() + opened.wait(5) + threading.Timer(0.2, release.set).start() + jh.writefile({'v': 1}, target, silent=True, atomic=True) + thread.join() + assert jh.readfile(target, silent=True, as_type='dict') == {'v': 1}, 'save did not wait for the open target' + assert jh.log.errors == [], jh.log.errors + assert leftovers(folder, target) == [], f'temp files left: {leftovers(folder, target)}' + + +def test_overlapping_locked_access(folder, threads=8, iterations=25): + jh = fresh_helper() + target = os.path.join(folder, 'locked.json') + jh.writefile({'seed': 0}, target, silent=True) + torn = [] + + def worker(n): + for i in range(iterations): + if (n + i) % 2: + jh.writefile({'n': n, 'i': i}, target, silent=True, atomic=True) + elif not jh.readfile(target, silent=True, lock=True, as_type='dict'): + torn.append((n, i)) + + run_threads(worker, threads) + assert jh.log.errors == [], jh.log.errors + assert torn == [], f'{len(torn)} reads returned nothing' + assert not os.path.exists(target + '.lock'), 'a lock file was created' + assert leftovers(folder, target) == [], f'temp files left: {leftovers(folder, target)}' + + +def test_locked_readers_never_see_torn_writes(folder, writers=8, per_writer=15, readers=2): + jh = fresh_helper() + target = os.path.join(folder, 'config.json') + jh.writefile({'seed': 0}, target, silent=True) + stop = threading.Event() + torn = [] + + def reader(_n): + while not stop.is_set(): + if not jh.readfile(target, silent=True, lock=True, as_type='dict'): + torn.append(1) + + def writer(n): + for i in range(per_writer): + jh.writefile({'writer': n, 'i': i, 'blob': 'x' * (40000 + 1000 * n)}, target, silent=True, atomic=False) + + pool = [threading.Thread(target=reader, args=(r,)) for r in range(readers)] + for t in pool: + t.start() + run_threads(writer, writers) + stop.set() + for t in pool: + t.join() + assert torn == [], f'{len(torn)} reads returned nothing' + with open(target, encoding='utf8') as f: + json.load(f) + assert jh.log.errors == [], jh.log.errors + + +def test_legacy_lock_file_removed(folder): + jh = fresh_helper() + target = os.path.join(folder, 'legacy.json') + with open(target + '.lock', 'w', encoding='utf8'): + pass + jh.writefile({'x': 1}, target, silent=True) + assert not os.path.exists(target + '.lock'), 'legacy lock file kept' + assert jh.log.errors == [], jh.log.errors + + +def test_concurrent_inserts_keep_every_save(folder, threads=4, per_thread=40): + jh = fresh_helper() + target = os.path.join(folder, 'cache.json') + cache = {} + payload = {'metadata': {f'k{i}': 'x' * 64 for i in range(200)}, 'tensors': list(range(500))} + + def worker(n): + for i in range(per_thread): + cache[f'{n}-{i}'] = payload + jh.writefile(cache, target, silent=True, atomic=True) + + run_threads(worker, threads) + assert jh.log.count('changed size') == 0, f'{jh.log.count("changed size")} saves dropped' + assert jh.log.errors == [], jh.log.errors + with open(target, encoding='utf8') as f: + assert len(json.load(f)) == threads * per_thread, 'last save is incomplete' + + +def test_default_writes_never_tear(folder, writers=4, per_writer=20, readers=2): + jh = fresh_helper() + target = os.path.join(folder, 'default.json') + jh.writefile({'seed': 0}, target, silent=True) + stop = threading.Event() + torn = [] + + def reader(_n): + while not stop.is_set(): + if not jh.readfile(target, silent=True, as_type='dict'): + torn.append(1) + time.sleep(0.001) # real readers do not spin; a spinning reader starves the writer's retry on Windows + + def writer(n): + for i in range(per_writer): + jh.writefile({'writer': n, 'i': i, 'blob': 'x' * (40000 + 1000 * n)}, target, silent=True) + + pool = [threading.Thread(target=reader, args=(r,)) for r in range(readers)] + for t in pool: + t.start() + run_threads(writer, writers) + stop.set() + for t in pool: + t.join() + assert torn == [], f'{len(torn)} unlocked reads returned nothing' + assert jh.log.errors == [], jh.log.errors + assert leftovers(folder, target) == [], f'temp files left: {leftovers(folder, target)}' + + +def test_atomic_write_keeps_symlink(folder): + jh = fresh_helper() + real = os.path.join(folder, 'real.json') + link = os.path.join(folder, 'link.json') + jh.writefile({'v': 0}, real, silent=True) + try: + os.symlink(real, link) + except OSError as e: + log.info(f' SKIP symlink not available: {e}') + return + jh.writefile({'v': 1}, link, silent=True) + assert os.path.islink(link), 'symlink was replaced by a file' + assert jh.readfile(real, silent=True, as_type='dict') == {'v': 1}, 'target of the symlink not updated' + assert sorted(os.listdir(folder)) == ['link.json', 'real.json'], os.listdir(folder) + assert jh.log.errors == [], jh.log.errors + + +def test_read_waits_out_refused_open(folder): + jh = fresh_helper() + target = os.path.join(folder, 'refused.json') + jh.writefile({'x': 1}, target, silent=True) + calls = [] + real_open = open + + def refuse_twice(*args, **kwargs): + calls.append(1) + if len(calls) <= 2: + raise PermissionError(13, 'replace in flight') + return real_open(*args, **kwargs) + + jh.open = refuse_twice # module globals shadow the builtin inside read_bytes + try: + assert jh.readfile(target, silent=True, as_type='dict') == {'x': 1} + finally: + del jh.open + assert len(calls) == 3, f'{len(calls)} open attempts' + assert jh.log.errors == [], jh.log.errors + + +def test_empty_file_is_reported(folder): + jh = fresh_helper() + target = os.path.join(folder, 'empty.json') + with open(target, 'w', encoding='utf8'): + pass + assert jh.readfile(target, as_type='dict') == {} + assert jh.readfile(target, silent=True, as_type='list') == [] + assert len(jh.log.warnings) == 1 and 'empty' in jh.log.warnings[0], jh.log.warnings + assert jh.log.errors == [], jh.log.errors + + +def test_hash_cache_saves_under_concurrent_adds(folder, adders=4, per_adder=200): + jh = fresh_helper() + from modules import hashes # pylint: disable=import-outside-toplevel + saved_filename = hashes.cache_filename + hashes.cache_filename = os.path.join(folder, 'cache.json') + hashes.cache('hashes').clear() + hashes.cache('hashes-addnet').clear() + stop = threading.Event() + + def adder(n): + for i in range(per_adder): + hashes.cache('hashes').add_hash(f'checkpoint/{n}-{i}', 1.0, 'a' * 64) + if i % 10 == 9: + hashes.save_cache() + + def churn(_n): # a second store whose size keeps changing while the saves run, bounded so the snapshots stay small + i = 0 + while not stop.is_set(): + store = hashes.cache('hashes-addnet') + if i % 500 == 499: + store.clear() + else: + store.add_hash(f'lora/{i % 500}', 1.0, 'b' * 64) + i += 1 + + thread = threading.Thread(target=churn, args=(0,)) + thread.start() + try: + run_threads(adder, adders) + finally: + stop.set() + thread.join() + hashes.cache_filename = saved_filename + assert jh.log.errors == [], jh.log.errors + with open(os.path.join(folder, 'cache.json'), encoding='utf8') as f: + on_disk = json.load(f) + assert len(on_disk['hashes']) == adders * per_adder, f'{len(on_disk["hashes"])} of {adders * per_adder} hashes on disk' + hashes.cache('hashes').clear() + hashes.cache('hashes-addnet').clear() + + +def test_roundtrip(folder): + jh = fresh_helper() + target = os.path.join(folder, 'roundtrip.json') + data = {'a': 1, 'b': [1, 2, 3], 'c': {'d': 'e'}, 'f': None} + jh.writefile(data, target, silent=True) + assert jh.readfile(target, silent=True, as_type='dict') == data + jh.writefile([1, 'two', {'three': 3}], target, silent=True, atomic=True) + assert jh.readfile(target, silent=True, as_type='list') == [1, 'two', {'three': 3}] + assert jh.readfile(os.path.join(folder, 'missing.json'), silent=True, as_type='dict') == {} + assert jh.log.errors == [], jh.log.errors + + +def run_all(): + tests = [ + test_atomic_save_replaces_target, + test_failed_atomic_save_leaves_no_temp, + test_atomic_save_waits_for_open_target, + test_overlapping_locked_access, + test_locked_readers_never_see_torn_writes, + test_legacy_lock_file_removed, + test_concurrent_inserts_keep_every_save, + test_default_writes_never_tear, + test_atomic_write_keeps_symlink, + test_read_waits_out_refused_open, + test_empty_file_is_reported, + test_hash_cache_saves_under_concurrent_adds, + test_roundtrip, + ] + passed = 0 + failed = 0 + for fn in tests: + folder = tempfile.mkdtemp(prefix='sdnext-json-') + try: + fn(folder) + log.info(f' PASS {fn.__name__}') + passed += 1 + except Exception as e: + log.error(f' FAIL {fn.__name__}: {type(e).__name__}: {e}') + failed += 1 + finally: + shutil.rmtree(folder, ignore_errors=True) + log.warning(f'Total: {passed} passed, {failed} failed') + return failed == 0 + + +if __name__ == '__main__': + t0 = time.time() + ok = run_all() + log.warning(f'Total time: {time.time() - t0:.2f}s') + sys.exit(0 if ok else 1) diff --git a/test/test-minimax-native-adapters.py b/test/test-minimax-native-adapters.py new file mode 100644 index 000000000..1c03bb605 --- /dev/null +++ b/test/test-minimax-native-adapters.py @@ -0,0 +1,761 @@ +#!/usr/bin/env python +""" +Offline unit tests for the MiniMax H3 native adapter loader. + +Published MiniMax H3 LoRAs target the reference module names (fused +``attn.qkv_proj``, fused SwiGLU ``mlp.fc1``, ``token_refiner.blocks``), while +sdnext loads upstream ``diffusers.MiniMaxH3Transformer3DModel``. The reference +fc1 is ``[gate; value]`` and diffusers' SwiGLU is ``[value; gate]``, so the +native mapping has to permute fc1 output rows the same way the diffusers LoRA +converter does. These tests pin ``pipelines.minimax.minimax_lora`` against that +converter: same targets, same per-module deltas. + +Save formats exercised, each seen in a published LoRA: + +- comfy / ai-toolkit (``diffusion_model.blocks.0.attn.qkv_proj.lora_A.weight``): + the CivitAI ecosystem and the larryvrh turbo files. +- bare reference names (``blocks.0.attn.qkv_proj.lora_A.weight``): the + unpruned larryvrh saves. +- musubi-tuner (``lora_unet_blocks_0_mlp_fc1.lora_down.weight`` + ``alpha``). +- comfy with block-diagonal fused qkv and tripled alpha: lightx2v's ComfyUI + exports. +- peft dump (``transformer_blocks.0.attn.to_q.lora_A.default.weight``) with the + training alpha in the file metadata: lightx2v's diffusers exports. +- diffusers names with kohya suffixes: the alibaba-pai Acc LoRAs. +- peft wrapper around a ``dit`` attribute (``base_model.model.dit.blocks.0...``): + the mvp-lab RAVEN LoRA. +- pruned checkpoints (``MiniMaxH3PrunedTransformer3DModel``): AdaLN deltas + trained at the released width refit onto the rank-k curve basis. + +The reference module tree is the real ``MiniMaxH3Transformer3DModel`` at tiny +dims, so module names and target shapes are authoritative. Every LoRA file +under the MiniMax H3 LoRA folder is also mapped through both paths and compared +per target, exactly when the file carries no alpha and through random probes +when the converter folds an alpha into the weights. + +No running server required. + +Usage: + python test/test-minimax-native-adapters.py +""" + +import glob +import os +import sys +import tempfile +import time + +import torch +import torch.nn as nn +import safetensors +import safetensors.torch + +script_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) +sys.path.insert(0, script_dir) +os.chdir(script_dir) + +os.environ['SD_INSTALL_QUIET'] = '1' + +# Bootstrap cmd_args before any module that pulls in shared.py. +import modules.cmd_args # pylint: disable=wrong-import-position +import installer # pylint: disable=wrong-import-position +_orig_argv = sys.argv +sys.argv = [sys.argv[0]] +try: + modules.cmd_args.parse_args() +finally: + sys.argv = _orig_argv +installer.add_args(modules.cmd_args.parser) +modules.cmd_args.parsed, _ = modules.cmd_args.parser.parse_known_args([]) + +from modules.errors import log # pylint: disable=wrong-import-position +from modules import shared # pylint: disable=wrong-import-position +from modules.lora import native_adapter # pylint: disable=wrong-import-position +from pipelines.minimax import minimax_lora as M # pylint: disable=wrong-import-position +from diffusers import MiniMaxH3Transformer3DModel # pylint: disable=wrong-import-position +from diffusers.loaders.lora_conversion_utils import _convert_non_diffusers_minimax_h3_lora_to_diffusers as convert_diffusers # pylint: disable=wrong-import-position + + +# ============================================================ +# Test infrastructure +# ============================================================ + +results: dict[str, dict] = {} + + +def category(name: str): + if name not in results: + results[name] = {'passed': 0, 'failed': 0, 'tests': []} + return name + + +def record(cat: str, passed: bool, name: str, detail: str = ''): + status = 'PASS' if passed else 'FAIL' + results[cat]['passed' if passed else 'failed'] += 1 + results[cat]['tests'].append((status, name)) + msg = f' {status}: {name}' + if detail: + msg += f' ({detail})' + if passed: + log.info(msg) + else: + log.error(msg) + + +def run_test(cat: str, fn): + name = fn.__name__ + try: + ok = fn() + if ok is False: + record(cat, False, name) + else: + record(cat, True, name) + except AssertionError as e: + record(cat, False, name, str(e)) + except Exception as e: # pylint: disable=broad-except + record(cat, False, name, f'exception: {e}') + import traceback + traceback.print_exc() + + +# ============================================================ +# Reference MiniMax H3 transformer (real class, tiny dims) +# ============================================================ +# Upstream: heads=56, head_dim=128, hidden=5376, layers=50, refiner=2, ffn=14336. +# The attention inner dim exceeds the hidden size upstream; the test dims keep that. + +NUM_LAYERS = 2 +NUM_REFINER = 1 + +REF = MiniMaxH3Transformer3DModel( + num_attention_heads=2, attention_head_dim=8, hidden_size=12, num_layers=NUM_LAYERS, num_refiner_layers=NUM_REFINER, + ffn_dim=16, in_channels=4, audio_in_channels=4, patch_size=(1, 2, 2), text_dim=10, freq_dim=8, + time_embed_hidden_dim=12, time_embed_dim=6, rope_freq_dim=1, +) + +# {diffusers dotted name: (out, in)} for every Linear. +LINEAR_SHAPES = {name: tuple(m.weight.shape) for name, m in REF.named_modules() if isinstance(m, nn.Linear)} +# {network key: module} exactly as assign_network_names_to_compvis_modules stamps it. +LINEAR_NETKEYS = {'lora_transformer_' + name.replace('.', '_') for name in LINEAR_SHAPES} + +# Reference module names and where they land, used only to size synthetic tensors; +# correctness is judged against the diffusers converter, not this table. +STANDALONE = { + 'video_patch_proj': 'proj_in', + 'audio_patch_proj': 'audio_proj_in', + 'condition_proj': 'context_embedder', + 'time_embedder.proj_in': 'time_embedder.linear_1', + 'time_embedder.proj_out': 'time_embedder.linear_2', + 'final_layer.adaln_proj.linear': 'norm_out.linear', + 'final_layer.video_out': 'proj_out', + 'final_layer.audio_out': 'audio_proj_out', +} +BLOCK_LEAVES = { + 'attn.qkv_proj': 'attn.to_q', + 'attn.out_proj': 'attn.to_out.0', + 'mlp.fc1': 'ff.net.0.proj', + 'mlp.fc2': 'ff.net.2', + 'adaln_proj.linear': 'adaln_proj.linear', +} + + +def ref_shape(ref_path: str): + """(out, in) of the reference Linear a LoRA key names, read from the diffusers module it maps to.""" + if ref_path in STANDALONE: + return LINEAR_SHAPES[STANDALONE[ref_path]] + if ref_path.startswith('blocks.'): + _, idx, leaf = ref_path.split('.', 2) + stack = 'transformer_blocks' + else: + _, _, idx, leaf = ref_path.split('.', 3) + stack = 'token_refiner.refiner_blocks' + out, inp = LINEAR_SHAPES[f'{stack}.{idx}.{BLOCK_LEAVES[leaf]}'] + if leaf == 'attn.qkv_proj': + out *= 3 + return out, inp + + +def all_ref_paths(): + paths = list(STANDALONE) + for i in range(NUM_LAYERS): + paths += [f'blocks.{i}.{leaf}' for leaf in BLOCK_LEAVES] + for i in range(NUM_REFINER): + paths += [f'token_refiner.blocks.{i}.{leaf}' for leaf in BLOCK_LEAVES if leaf != 'adaln_proj.linear'] + return paths + + +# ============================================================ +# Mock pipeline wrapping the real transformer +# ============================================================ + + +class _MockPipeline: + def __init__(self, transformer): + self.transformer = transformer + self.text_encoder = None + + +class _MockSdModel: + def __init__(self, pipe): + self.pipe = pipe + self.network_layer_mapping = {} + self.embedding_db = None + self.__class__.__name__ = 'MiniMaxH3ModularPipeline' + + +def install_mock_pipe(transformer=REF): + """Point shared.sd_model at a mock exposing the reference transformer; re-installed per load so stamps do not leak.""" + sd_model = _MockSdModel(_MockPipeline(transformer)) + from modules.modeldata import model_data + model_data.sd_model = sd_model + return sd_model + + +CURVE_RANK = 2 + + +class _CurveTimeEmbedder(nn.Module): + """The pruned class's table lookup, reduced to the basis buffer the loader reads.""" + + def __init__(self, rank, width): + super().__init__() + self.register_buffer('basis', torch.randn(rank, width)) + + +def pruned_reference(): + """REF with every AdaLN projection folded onto a rank-2 curve basis, the layout of MiniMaxH3PrunedTransformer3DModel.""" + import copy + pruned = copy.deepcopy(REF) + pruned.time_embedder = _CurveTimeEmbedder(CURVE_RANK, pruned.transformer_blocks[0].adaln_proj.linear.in_features) + for block in pruned.transformer_blocks: + block.adaln_proj.linear = nn.Linear(CURVE_RANK, block.adaln_proj.linear.out_features) + pruned.norm_out.linear = nn.Linear(CURVE_RANK, pruned.norm_out.linear.out_features) + return pruned + + +# ============================================================ +# Synthesizers and helpers +# ============================================================ + +RANK = 4 +PEFT = ('lora_A.weight', 'lora_B.weight') +KOHYA = ('lora_down.weight', 'lora_up.weight') + + +def lora_pair(key_base, shape, suffix=PEFT, alpha=None, rank=RANK): + out, inp = shape + sd = { + f'{key_base}.{suffix[0]}': torch.randn(rank, inp), + f'{key_base}.{suffix[1]}': torch.randn(out, rank), + } + if alpha is not None: + sd[f'{key_base}.alpha'] = torch.tensor(float(alpha)) + return sd + + +def synth(prefix='diffusion_model.', suffix=PEFT, alpha=None, flatten=False): + """One LoRA pair for every reference Linear, in the requested reference-name layout.""" + sd = {} + for path in all_ref_paths(): + key = f'lora_unet_{path.replace(".", "_")}' if flatten else f'{prefix}{path}' + sd.update(lora_pair(key, ref_shape(path), suffix, alpha)) + return sd + + +def synth_diffusers(prefix='', suffix=PEFT, infix='', alpha=None): + """One LoRA pair for every Linear, keyed by its diffusers name; ``infix`` inserts a peft adapter slot.""" + sd = {} + for path, shape in LINEAR_SHAPES.items(): + pair = lora_pair(f'{prefix}{path}', shape, suffix, alpha) + for key, value in pair.items(): + for marker in ('lora_A', 'lora_B', 'lora_down', 'lora_up'): + key = key.replace(f'.{marker}.weight', f'.{marker}{infix}.weight') + sd[key] = value + return sd + + +class TempLora: + """Context manager: writes a state dict to a temp safetensors file.""" + + def __init__(self, state_dict, name='test', metadata=None): + self.state_dict = state_dict + self.name = name + self.metadata = metadata + self.path = None + + def __enter__(self): + sd = {k: v.contiguous() for k, v in self.state_dict.items()} + fd, self.path = tempfile.mkstemp(suffix='.safetensors', prefix=f'{self.name}_') + os.close(fd) + safetensors.torch.save_file(sd, self.path) + return _MockNetworkOnDisk(self.path, self.name, self.metadata) + + def __exit__(self, exc_type, exc_val, exc_tb): + if self.path and os.path.exists(self.path): + os.unlink(self.path) + + +class _MockNetworkOnDisk: + def __init__(self, filename, name, metadata=None): + self.filename = filename + self.name = name + self.shorthash = '' + self.sd_version = 'unknown' + self.metadata = metadata or {} + + +def load_native(state_dict, name='test', metadata=None, transformer=REF): + install_mock_pipe(transformer) + with TempLora(state_dict, name=name, metadata=metadata) as nod: + return M.try_load(name, nod, lora_scale=1.0) + + +def native_deltas(net): + """{network key: full delta} as the apply pass would compute it at multiplier 1.""" + out = {} + for key, module in net.modules.items(): + module.network.te_multiplier = 1.0 + module.network.unet_multiplier = 1.0 + up = module.up_model.weight.float() + down = module.down_model.weight.float() + out[key] = (up @ down) * module.calc_scale() + return out + + +def diffusers_deltas(state_dict, rewrite=None): + """{network key: full delta} from the diffusers converter's output.""" + if rewrite is not None: + state_dict = {k.replace(rewrite[0], rewrite[1], 1) if k.startswith(rewrite[0]) else k: v for k, v in state_dict.items()} + converted = convert_diffusers(dict(state_dict)) + out = {} + for key, value in converted.items(): + if not key.endswith('.lora_A.weight'): + continue + path = key[len('transformer.'):-len('.lora_A.weight')] + down = value.float() + up = converted[f'transformer.{path}.lora_B.weight'].float() + out['lora_transformer_' + path.replace('.', '_')] = up @ down + return out + + +def identity_deltas(state_dict, scale=1.0): + """{network key: full delta} for a file already on diffusers names, at a uniform scale.""" + out = {} + for key, value in state_dict.items(): + for marker in ('lora_A', 'lora_down'): + idx = key.find(f'.{marker}') + if idx == -1: + continue + path = key[:idx].removeprefix('transformer.') + up_key = key.replace(marker, 'lora_B' if marker == 'lora_A' else 'lora_up', 1) + out['lora_transformer_' + path.replace('.', '_')] = (state_dict[up_key].float() @ value.float()) * scale + return out + + +def assert_same_deltas(native, reference): + assert set(native) == set(reference), f'targets differ: native-only={sorted(set(native) - set(reference))} reference-only={sorted(set(reference) - set(native))}' + for key, ref in reference.items(): + got = native[key] + assert got.shape == ref.shape, f'{key}: shape {tuple(got.shape)} vs {tuple(ref.shape)}' + assert torch.allclose(got, ref, rtol=1e-5, atol=1e-5), f'{key}: delta differs, max abs {float((got - ref).abs().max()):.3e}' + + +def native_mapping(state_dict, network_alpha=None): + """{diffusers path: (down, up, scale)} the native loader would bind, without a model: parse, resolve, chunk, file alpha.""" + groups = M.group_by_suffixes(state_dict, M.LORA_SUFFIXES) + if network_alpha is not None and any('alpha' in w for w in groups.values()): + network_alpha = None + out = {} + for (prefix, base), w in groups.items(): + if 'lora_down.weight' not in w or 'lora_up.weight' not in w: + continue + for path, chunk in native_adapter.resolve_group_targets(M.resolve_targets, prefix, base): + target = native_adapter.slice_lora_chunk(w, chunk) if chunk is not None else w + alpha = network_alpha if 'alpha' not in target else float(target['alpha']) + scale = 1.0 if alpha is None else alpha / target['lora_down.weight'].shape[0] + out[path] = (target['lora_down.weight'], target['lora_up.weight'], scale) + return out + + +REFERENCE_PREFIXES = ('diffusion_model.', 'blocks.', 'token_refiner.blocks.', 'final_layer.', 'lora_unet_', 'base_model.model.dit.', + 'video_patch_proj.', 'audio_patch_proj.', 'condition_proj.', 'time_embedder.proj_') + + +def oracle_mapping(state_dict, network_alpha=None): + """{diffusers path: (down, up, scale)} plus the keys no LoRA pair claims, from the layout's reference loader. + + Reference-name layouts go through the diffusers converter, which folds any + alpha into the weights. Files already on diffusers names bind verbatim, with + a per-key alpha or else the file-level one applied as ``alpha / rank``. + """ + if any(k.startswith(REFERENCE_PREFIXES) for k in state_dict): + ignored = [k for k in state_dict if k.endswith(('.diff', '.diff_b'))] # weight and bias residuals of an extraction: not pairs, the converter rejects them + sd = {k.replace('base_model.model.dit.', 'diffusion_model.', 1) if k.startswith('base_model.model.dit.') else k: v for k, v in state_dict.items() if k not in ignored} + sd = {k[:-len('.lora_a')] + ('.lora_A.weight' if k.endswith('.lora_a') else '.lora_B.weight') if k.endswith(('.lora_a', '.lora_b')) else k: v for k, v in sd.items()} # lowercase peft names the converter does not read + converted = convert_diffusers(sd) + out = {} + for key, value in converted.items(): + if key.endswith('.lora_A.weight'): + path = key[len('transformer.'):-len('.lora_A.weight')] + out[path] = (value, converted[f'transformer.{path}.lora_B.weight'], 1.0) + return out, ignored + has_alpha = any(k.endswith('.alpha') for k in state_dict) + out, ignored = {}, [] + for key, value in state_dict.items(): + marker = next((m for m in ('lora_A', 'lora_down') if f'.{m}' in key), None) + if marker is None: + if not any(f'.{m}' in key for m in ('lora_B', 'lora_up', 'alpha')): + ignored.append(key) + continue + path = key[:key.find(f'.{marker}')].removeprefix('transformer.') + up = state_dict[key.replace(marker, 'lora_B' if marker == 'lora_A' else 'lora_up', 1)] + alpha = state_dict.get(f'{path}.alpha', state_dict.get(f'transformer.{path}.alpha')) + if alpha is not None: + scale = float(alpha) / value.shape[0] + elif network_alpha is not None and not has_alpha: + scale = network_alpha / value.shape[0] + else: + scale = 1.0 + out[path] = (value, up, scale) + return out, ignored + + +def assert_same_factors(native, oracle, label): + """Exact when neither side scales; probe-equal on the effective delta otherwise.""" + assert set(native) == set(oracle), f'{label}: targets differ: native-only={sorted(set(native) - set(oracle))[:4]} oracle-only={sorted(set(oracle) - set(native))[:4]}' + probes = 0 + for path, (down_o, up_o, scale_o) in oracle.items(): + down_n, up_n, scale_n = native[path] + if scale_n == 1.0 and scale_o == 1.0: + assert torch.equal(down_n, down_o), f'{label}: {path} down differs' + assert torch.equal(up_n, up_o), f'{label}: {path} up differs' + continue + probes += 1 + x = torch.randn(4, down_o.shape[1]) + got = (x @ down_n.float().t() @ up_n.float().t()) * scale_n + ref = (x @ down_o.float().t() @ up_o.float().t()) * scale_o + err = float((got - ref).abs().max() / ref.abs().max().clamp(min=1e-12)) + assert err < 1e-4, f'{label}: {path} effective delta differs, relative error {err:.2e}' + return probes + + +# ============================================================ +# Tests - resolution +# ============================================================ + +CAT_RESOLVE = category('resolve') +CAT_LOADER = category('loader') +CAT_REAL = category('real-files') + + +def test_every_reference_module_resolves_to_a_real_linear(): + """Every reference key layout resolves onto a Linear that exists in the diffusers model.""" + for layout in ({'prefix': 'diffusion_model.'}, {'prefix': ''}, {'flatten': True, 'suffix': KOHYA}, {'prefix': 'base_model.model.dit.'}): + sd = synth(**layout) + got = set(native_mapping(sd)) + expected = set(oracle_mapping(sd)[0]) + assert got == expected, f'{layout}: native={sorted(got - expected)} missing={sorted(expected - got)}' + assert got <= set(LINEAR_SHAPES), f'{layout}: not real modules: {sorted(got - set(LINEAR_SHAPES))}' + return True + + +def test_fc1_output_halves_swapped(): + """fc1 gate rows land on the second half of ff.net.0.proj and value rows on the first.""" + sd = lora_pair('diffusion_model.blocks.0.mlp.fc1', ref_shape('blocks.0.mlp.fc1')) + up = sd['diffusion_model.blocks.0.mlp.fc1.lora_B.weight'] + down, bound_up, _scale = native_mapping(sd)['transformer_blocks.0.ff.net.0.proj'] + half = up.shape[0] // 2 + assert torch.equal(bound_up[:half], up[half:]), 'value rows must lead' + assert torch.equal(bound_up[half:], up[:half]), 'gate rows must trail' + assert torch.equal(down, sd['diffusion_model.blocks.0.mlp.fc1.lora_A.weight']), 'down is untouched' + return True + + +def test_fc1_row_extras_follow_the_swap(): + """Per-output extras on fc1 (bias delta, DoRA magnitude) are permuted with the up rows.""" + sd = lora_pair('diffusion_model.blocks.0.mlp.fc1', ref_shape('blocks.0.mlp.fc1')) + out = ref_shape('blocks.0.mlp.fc1')[0] + sd['diffusion_model.blocks.0.mlp.fc1.diff_b'] = torch.arange(out, dtype=torch.float32) + sd['diffusion_model.blocks.0.mlp.fc1.dora_scale'] = torch.arange(out, dtype=torch.float32).reshape(out, 1) + net = load_native(sd, name='fc1extras') + module = net.modules['lora_transformer_transformer_blocks_0_ff_net_0_proj'] + half = out // 2 + assert torch.equal(module.ex_bias[:half], torch.arange(half, out, dtype=torch.float32)) + assert torch.equal(module.dora_scale[:half, 0], torch.arange(half, out, dtype=torch.float32)) + return True + + +def test_chunk_reorder_composes_with_slice(): + """A ChunkSpec reorder applies to the rows its slice selects.""" + t = torch.arange(8).reshape(8, 1) + got = native_adapter.slice_chunk_rows(t, native_adapter.ChunkSpec(idx=1, total=2, reorder=(1, 0))) + assert got.flatten().tolist() == [6, 7, 4, 5], got.flatten().tolist() + got = native_adapter.slice_chunk_rows(t, native_adapter.ChunkSpec(reorder=(1, 0))) + assert got.flatten().tolist() == [4, 5, 6, 7, 0, 1, 2, 3], got.flatten().tolist() + return True + + +def test_qkv_split_order(): + """Fused qkv rows split as [q; k; v] onto to_q / to_k / to_v.""" + sd = lora_pair('diffusion_model.blocks.1.attn.qkv_proj', ref_shape('blocks.1.attn.qkv_proj')) + up = sd['diffusion_model.blocks.1.attn.qkv_proj.lora_B.weight'] + mapping = native_mapping(sd) + for i, proj in enumerate(('to_q', 'to_k', 'to_v')): + _down, bound_up, _scale = mapping[f'transformer_blocks.1.attn.{proj}'] + assert torch.equal(bound_up, torch.chunk(up, 3, dim=0)[i]), f'{proj} rows' + return True + + +def test_diffusers_peft_keys_bind_verbatim(): + """A diffusers-PEFT save is already on diffusers names and gets no permutation.""" + sd = lora_pair('transformer.transformer_blocks.0.ff.net.0.proj', ref_shape('blocks.0.mlp.fc1')) + down, up, _scale = native_mapping(sd)['transformer_blocks.0.ff.net.0.proj'] + assert torch.equal(up, sd['transformer.transformer_blocks.0.ff.net.0.proj.lora_B.weight']) + assert torch.equal(down, sd['transformer.transformer_blocks.0.ff.net.0.proj.lora_A.weight']) + return True + + +def test_unknown_bare_key_reaches_the_resolver(): + """A bare key that names no module is offered verbatim and left unbound, not dropped at parse time.""" + sd = lora_pair('transformer_blocks.0.attn.to_q', LINEAR_SHAPES['transformer_blocks.0.attn.to_q']) + sd.update(lora_pair('nowhere.proj', (4, 4))) + mapping = native_mapping(sd) + assert set(mapping) == {'transformer_blocks.0.attn.to_q', 'nowhere.proj'}, sorted(mapping) + net = load_native(sd, name='stray') + assert set(net.modules) == {'lora_transformer_transformer_blocks_0_attn_to_q'}, sorted(net.modules) + assert net.mismatch == 0 + return True + + +# ============================================================ +# Tests - loader against the reference loaders +# ============================================================ + + +def _loader_matches_converter(layout, name, rewrite=None): + sd = synth(**layout) + net = load_native(sd, name=name) + assert net is not None, 'nothing bound' + assert net.mismatch == 0, f'mismatch={net.mismatch}' + reference = diffusers_deltas(sd, rewrite=rewrite) + assert set(net.modules) <= LINEAR_NETKEYS, f'bound to non-linear keys: {sorted(set(net.modules) - LINEAR_NETKEYS)}' + assert_same_deltas(native_deltas(net), reference) + assert len(net.modules) == len(reference), f'bound {len(net.modules)} modules, converter has {len(reference)}' + return True + + +def test_comfy_layout_matches_converter(): + """diffusion_model.* keys with PEFT suffixes: the published turbo LoRA layout.""" + return _loader_matches_converter({'prefix': 'diffusion_model.'}, 'comfy') + + +def test_bare_reference_layout_matches_converter(): + """Bare reference names, as the reference generate.py saves them.""" + return _loader_matches_converter({'prefix': ''}, 'bare') + + +def test_musubi_kohya_alpha_matches_converter(): + """Flattened lora_unet_ names with kohya suffixes and a non-trivial alpha.""" + return _loader_matches_converter({'flatten': True, 'suffix': KOHYA, 'alpha': RANK / 2}, 'musubi') + + +def test_peft_wrapped_dit_layout_matches_converter(): + """A peft dump wrapping the reference model under a dit attribute maps like diffusion_model.""" + return _loader_matches_converter({'prefix': 'base_model.model.dit.'}, 'dit', rewrite=('base_model.model.dit.', 'diffusion_model.')) + + +def test_block_diagonal_qkv_with_tripled_alpha_matches_converter(): + """A fused qkv stored as stacked A and block-diagonal B with alpha tripled applies each projection at alpha / rank.""" + out_q, inp = LINEAR_SHAPES['transformer_blocks.0.attn.to_q'] + alpha = RANK / 2 + downs = [torch.randn(RANK, inp) for _ in range(3)] + ups = [torch.randn(out_q, RANK) for _ in range(3)] + sd = { + 'diffusion_model.blocks.0.attn.qkv_proj.lora_A.weight': torch.cat(downs, dim=0), + 'diffusion_model.blocks.0.attn.qkv_proj.lora_B.weight': torch.block_diag(*ups), + 'diffusion_model.blocks.0.attn.qkv_proj.alpha': torch.tensor(3 * alpha), + } + net = load_native(sd, name='blockdiag') + got = native_deltas(net) + assert_same_deltas(got, diffusers_deltas(sd)) + for i, proj in enumerate(('to_q', 'to_k', 'to_v')): + expected = (ups[i] @ downs[i]) * (alpha / RANK) + assert torch.allclose(got[f'lora_transformer_transformer_blocks_0_attn_{proj}'], expected, rtol=1e-5, atol=1e-5), f'{proj} is not its own projection at alpha / rank' + return True + + +def test_peft_dump_layout_binds_verbatim(): + """Diffusers names carrying peft's .default. slot and no component prefix bind one to one.""" + sd = synth_diffusers(infix='.default') + net = load_native(sd, name='peftdump') + assert net is not None and net.mismatch == 0 + assert_same_deltas(native_deltas(net), identity_deltas({k.replace('.default.', '.'): v for k, v in sd.items()})) + assert len(net.modules) == len(LINEAR_SHAPES) + return True + + +def test_diffusers_names_with_kohya_suffixes_bind(): + """Diffusers names with lora_down / lora_up suffixes and no alpha bind at scale 1.""" + sd = synth_diffusers(suffix=KOHYA) + net = load_native(sd, name='kohyadiff') + assert net is not None and net.mismatch == 0 + assert_same_deltas(native_deltas(net), identity_deltas(sd)) + return True + + +def test_metadata_alpha_scales_an_alphaless_file(): + """A file-level alpha in the safetensors metadata scales every module by alpha / rank.""" + sd = synth_diffusers(infix='.default') + net = load_native(sd, name='metaalpha', metadata={'alpha': '2'}) + assert_same_deltas(native_deltas(net), identity_deltas({k.replace('.default.', '.'): v for k, v in sd.items()}, scale=2 / RANK)) + return True + + +def test_metadata_alpha_yields_to_alpha_tensors(): + """A file carrying any alpha tensor keeps its own scaling and ignores the metadata alpha.""" + sd = synth_diffusers() + sd['proj_out.alpha'] = torch.tensor(RANK / 2) + net = load_native(sd, name='mixedalpha', metadata={'alpha': '2'}) + got = native_deltas(net) + expected = identity_deltas({k: v for k, v in sd.items() if not k.endswith('.alpha')}) + expected['lora_transformer_proj_out'] = expected['lora_transformer_proj_out'] * 0.5 + assert_same_deltas(got, expected) + return True + + +def test_non_numeric_metadata_alpha_is_ignored(): + """A metadata alpha that is not a number leaves the file at alpha == rank.""" + sd = synth_diffusers() + net = load_native(sd, name='badalpha', metadata={'alpha': 'n/a'}) + assert_same_deltas(native_deltas(net), identity_deltas(sd)) + return True + + +def test_adaln_deltas_project_onto_the_pruned_basis(): + """On a pruned transformer an AdaLN delta trained at the released width binds as up @ (down @ basis.T); every other layer binds verbatim.""" + pruned = pruned_reference() + basis = pruned.time_embedder.basis + sd = {k: v for k, v in synth_diffusers(suffix=KOHYA).items() if not k.startswith('time_embedder.')} # the pruned class drops the time embedder MLP + net = load_native(sd, name='pruned', transformer=pruned) + assert net is not None and net.mismatch == 0, f'mismatch={None if net is None else net.mismatch}' + expected = identity_deltas(sd) + curve_keys = [k for k in expected if k.endswith('_adaln_proj_linear') and '_refiner_' not in k] + ['lora_transformer_norm_out_linear'] + for key in curve_keys: + expected[key] = expected[key] @ basis.T + assert_same_deltas(native_deltas(net), expected) + assert tuple(net.modules['lora_transformer_norm_out_linear'].down_model.weight.shape) == (RANK, CURVE_RANK) + return True + + +def test_extraction_residuals_bind(): + """Bias residuals ride their pair as ex_bias, norm weight residuals bind through the full family, and the final norm resolves.""" + out_proj = REF.transformer_blocks[0].attn.to_out[0] + linear_1 = REF.time_embedder.linear_1 + sd = { + 'blocks.0.attn.out_proj.lora_A.weight': torch.randn(RANK, out_proj.in_features), + 'blocks.0.attn.out_proj.lora_B.weight': torch.randn(out_proj.out_features, RANK), + 'blocks.0.attn.out_proj.diff_b': torch.randn(out_proj.out_features), + 'time_embedder.proj_in.lora_A.weight': torch.randn(RANK, linear_1.in_features), + 'time_embedder.proj_in.lora_B.weight': torch.randn(linear_1.out_features, RANK), + 'time_embedder.proj_in.diff_b': torch.randn(linear_1.out_features), + 'blocks.0.norm1.diff': torch.randn(REF.transformer_blocks[0].norm1.weight.shape[0]), + 'final_layer.norm.diff': torch.randn(REF.norm_out.norm.weight.shape[0]), + } + net = load_native(sd, name='residuals') + assert net is not None, 'chain returned nothing' + mods = net.modules + assert torch.equal(mods['lora_transformer_transformer_blocks_0_attn_to_out_0'].ex_bias, sd['blocks.0.attn.out_proj.diff_b']) + assert torch.equal(mods['lora_transformer_time_embedder_linear_1'].ex_bias, sd['time_embedder.proj_in.diff_b']) + assert torch.equal(mods['lora_transformer_transformer_blocks_0_norm1'].weight, sd['blocks.0.norm1.diff']) + assert torch.equal(mods['lora_transformer_norm_out_norm'].weight, sd['final_layer.norm.diff']) + return True + + +# ============================================================ +# Tests - real files +# ============================================================ + +REAL_FILES = sorted(glob.glob(os.path.join(shared.opts.lora_dir, 'MiniMax H3', '*.safetensors'))) + + +def test_real_files_match_reference_loaders(): + """Every local MiniMax H3 LoRA maps onto the same targets as its reference loader, with the same factors.""" + if not REAL_FILES: + log.warning(' no local MiniMax H3 LoRA files, skipped') + return True + for path in REAL_FILES: + name = os.path.basename(path) + try: + with safetensors.safe_open(path, framework='pt') as f: + metadata = f.metadata() or {} + sd = safetensors.torch.load_file(path) + except safetensors.SafetensorError as e: # a malformed file the loader cannot open either + log.warning(f' {name}: unreadable, skipped: {e}') + continue + network_alpha = M.file_alpha(_MockNetworkOnDisk(path, name, metadata)) + native = native_mapping(sd, network_alpha) + oracle, ignored = oracle_mapping(sd, network_alpha) + probes = assert_same_factors(native, oracle, name) + note = f' alpha=file:{network_alpha}' if network_alpha is not None else (' alpha=keys' if probes else '') + note += f' ignored={len(ignored)}' if ignored else '' + log.info(f' {name}: targets={len(native)} {"probed" if probes else "identical"}{note}') + del sd, native, oracle + return True + + +# ============================================================ +# Runner +# ============================================================ + + +def run_tests(): + t0 = time.time() + log.warning('=== MiniMax H3 native adapter tests ===') + log.warning('=== Resolution ===') + for fn in [ + test_every_reference_module_resolves_to_a_real_linear, + test_fc1_output_halves_swapped, + test_fc1_row_extras_follow_the_swap, + test_chunk_reorder_composes_with_slice, + test_qkv_split_order, + test_diffusers_peft_keys_bind_verbatim, + test_unknown_bare_key_reaches_the_resolver, + ]: + run_test(CAT_RESOLVE, fn) + + log.warning('=== Loader vs reference loaders ===') + for fn in [ + test_comfy_layout_matches_converter, + test_bare_reference_layout_matches_converter, + test_musubi_kohya_alpha_matches_converter, + test_peft_wrapped_dit_layout_matches_converter, + test_block_diagonal_qkv_with_tripled_alpha_matches_converter, + test_peft_dump_layout_binds_verbatim, + test_diffusers_names_with_kohya_suffixes_bind, + test_metadata_alpha_scales_an_alphaless_file, + test_metadata_alpha_yields_to_alpha_tensors, + test_non_numeric_metadata_alpha_is_ignored, + test_adaln_deltas_project_onto_the_pruned_basis, + test_extraction_residuals_bind, + ]: + run_test(CAT_LOADER, fn) + + log.warning('=== Real files ===') + run_test(CAT_REAL, test_real_files_match_reference_loaders) + + elapsed = time.time() - t0 + log.warning('=== Results ===') + total_pass = 0 + total_fail = 0 + for cat, info in results.items(): + status = 'PASS' if info['failed'] == 0 else 'FAIL' + log.info(f' {cat}: {info["passed"]} passed, {info["failed"]} failed [{status}]') + total_pass += info['passed'] + total_fail += info['failed'] + log.warning(f'Total: {total_pass} passed, {total_fail} failed in {elapsed:.2f}s') + return total_fail == 0 + + +if __name__ == '__main__': + ok = run_tests() + sys.exit(0 if ok else 1) diff --git a/test/test-minimax-shift.py b/test/test-minimax-shift.py new file mode 100644 index 000000000..3af160c00 --- /dev/null +++ b/test/test-minimax-shift.py @@ -0,0 +1,224 @@ +#!/usr/bin/env python +""" +Offline unit tests for the MiniMax schedule shift in modules.video_models.video_minimax. + +- ``resolve_shift`` takes a positive request value and falls back to the scheduler config otherwise +- ``set_sampler_shift`` writes scheduler, default_scheduler and audio_scheduler and keys the result for infotext +- a request without values resets what the previous request set +- the Default sampler restore, a deepcopy of default_scheduler, carries the shift into the sigma grid +- ``apply_overrides`` records the applied values on the processing object and hands the scheduler one grid point more than the step count + +No running server required. + +Usage: + python test/test-minimax-shift.py +""" + +import os +import sys +import copy +import types + +import torch + +script_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) +sys.path.insert(0, script_dir) +os.chdir(script_dir) + +os.environ['SD_INSTALL_QUIET'] = '1' + +# Bootstrap cmd_args before any module that pulls in shared.py. +import modules.cmd_args # pylint: disable=wrong-import-position +import installer # pylint: disable=wrong-import-position +_orig_argv = sys.argv +sys.argv = [sys.argv[0]] +try: + modules.cmd_args.parse_args() +finally: + sys.argv = _orig_argv +installer.add_args(modules.cmd_args.parser) +modules.cmd_args.parsed, _ = modules.cmd_args.parser.parse_known_args([]) + +import diffusers # pylint: disable=wrong-import-position +from modules.errors import log # pylint: disable=wrong-import-position +from modules.video_models import video_minimax # pylint: disable=wrong-import-position + + +VIDEO_SHIFT = 12.0 +AUDIO_SHIFT = 3.0 +STEPS = 5 + + +results = {} + + +def category(name: str): + if name not in results: + results[name] = {'passed': 0, 'failed': 0, 'tests': []} + return name + + +def record(cat: str, passed: bool, name: str, detail: str = ''): + status = 'PASS' if passed else 'FAIL' + results[cat]['passed' if passed else 'failed'] += 1 + results[cat]['tests'].append((status, name)) + msg = f' {status}: {name}' + if detail: + msg += f' ({detail})' + if passed: + log.info(msg) + else: + log.error(msg) + + +def run_test(cat: str, fn): + name = fn.__name__ + try: + ok = fn() + record(cat, ok is not False, name) + except AssertionError as e: + record(cat, False, name, str(e)) + except Exception as e: # pylint: disable=broad-except + record(cat, False, name, f'{type(e).__name__}: {e}') + + +# ============================================================ +# Fixtures +# ============================================================ + +class StubVae: + def enable_tiling(self): + pass + + def decode(self, z, *args, **kwargs): # still mode wraps it with the latent-frame padding + return z + + +class StubPipe: + """The parts of the modular pipeline the shim touches: the scheduler pair with the shipped copy, and the canvas and frame constants.""" + + canvas_multiple = 32 + vae_frames_per_chunk = 17 + vae_latents_per_chunk = 5 + max_duration = 15.0 + fps = 24 + sdnext_supported_min_frames = 120 + + def __init__(self): + self.scheduler = diffusers.MiniMaxH3Scheduler(shift=VIDEO_SHIFT) + self.audio_scheduler = diffusers.MiniMaxH3Scheduler(shift=AUDIO_SHIFT) + self.default_scheduler = copy.deepcopy(self.scheduler) + self.vae = StubVae() + + @property + def min_duration(self): + return 5.0 + + +def make_p(): + return types.SimpleNamespace(width=1024, height=576, steps=STEPS, frames=124, sampler_name='Default', task_args={}, extra_generation_params={}) + + +def sigmas(shift: float): + scheduler = diffusers.MiniMaxH3Scheduler(shift=shift) + scheduler.set_timesteps(STEPS) + return scheduler.sigmas.detach().cpu() + + +def shifts(pipe): + return (pipe.scheduler.shift, pipe.default_scheduler.shift, pipe.audio_scheduler.shift) + + +# ============================================================ +# Tests +# ============================================================ + +def test_resolve_prefers_positive_request(): + scheduler = diffusers.MiniMaxH3Scheduler(shift=VIDEO_SHIFT) + assert video_minimax.resolve_shift(scheduler, 6.0) == 6.0 + assert video_minimax.resolve_shift(scheduler, 0.5) == 0.5 + for absent in (None, -1.0, 0.0): + assert video_minimax.resolve_shift(scheduler, absent) == VIDEO_SHIFT, f'requested={absent}' + + +def test_resolve_reads_the_shipped_value_not_the_live_one(): + scheduler = diffusers.MiniMaxH3Scheduler(shift=VIDEO_SHIFT) + scheduler.set_shift(4.0) + assert video_minimax.resolve_shift(scheduler, None) == VIDEO_SHIFT + + +def test_set_writes_every_copy_and_keys_the_result(): + pipe = StubPipe() + applied = video_minimax.set_sampler_shift(pipe, video_shift=6.0, audio_shift=4.0) + assert applied == {'Video shift': 6.0, 'Audio shift': 4.0}, f'applied={applied}' + assert shifts(pipe) == (6.0, 6.0, 4.0), f'shifts={shifts(pipe)}' + assert pipe.scheduler.config['shift'] == VIDEO_SHIFT and pipe.audio_scheduler.config['shift'] == AUDIO_SHIFT + + +def test_next_request_without_values_resets(): + pipe = StubPipe() + video_minimax.set_sampler_shift(pipe, video_shift=6.0, audio_shift=4.0) + applied = video_minimax.set_sampler_shift(pipe) + assert applied == {'Video shift': VIDEO_SHIFT, 'Audio shift': AUDIO_SHIFT}, f'applied={applied}' + assert shifts(pipe) == (VIDEO_SHIFT, VIDEO_SHIFT, AUDIO_SHIFT), f'shifts={shifts(pipe)}' + applied = video_minimax.set_sampler_shift(pipe, video_shift=-1.0, audio_shift=-1.0) + assert applied == {'Video shift': VIDEO_SHIFT, 'Audio shift': AUDIO_SHIFT}, f'applied={applied}' + + +def test_default_sampler_restore_carries_the_shift(): + pipe = StubPipe() + video_minimax.set_sampler_shift(pipe, video_shift=6.0) + pipe.scheduler = copy.deepcopy(pipe.default_scheduler) # sd_samplers.restore_default + pipe.scheduler.set_timesteps(STEPS) + assert torch.allclose(pipe.scheduler.sigmas.detach().cpu(), sigmas(6.0)), 'restored scheduler does not follow the requested shift' + assert not torch.allclose(pipe.scheduler.sigmas.detach().cpu(), sigmas(VIDEO_SHIFT)), 'requested shift did not change the grid' + + +def test_unsupported_scheduler_is_skipped(): + pipe = StubPipe() + pipe.scheduler = diffusers.EulerDiscreteScheduler() # no set_shift and no shift in its config + assert video_minimax.set_sampler_shift(pipe, video_shift=6.0) == {} + assert pipe.audio_scheduler.shift == AUDIO_SHIFT + + +def test_apply_overrides_records_the_applied_values(): + pipe = StubPipe() + p = make_p() + video_minimax.apply_overrides(p, pipe, still=False, audio=True, video_shift=6.0, audio_shift=-1.0) + assert p.extra_generation_params == {'Video shift': 6.0, 'Audio shift': AUDIO_SHIFT}, f'recorded={p.extra_generation_params}' + assert shifts(pipe) == (6.0, 6.0, AUDIO_SHIFT), f'shifts={shifts(pipe)}' + assert p.sampler_name == 'Default' + assert p.steps == STEPS and p.task_args['num_inference_steps'] == STEPS + 1 and pipe.num_timesteps == STEPS, f'steps={p.steps} grid_steps={p.task_args["num_inference_steps"]} total={pipe.num_timesteps}' + + +def test_apply_overrides_without_values_uses_the_shipped_schedule(): + pipe = StubPipe() + video_minimax.set_sampler_shift(pipe, video_shift=6.0, audio_shift=4.0) # an earlier request on the same pipe + p = make_p() + video_minimax.apply_overrides(p, pipe, still=True, audio=False) + assert p.extra_generation_params == {'Video shift': VIDEO_SHIFT, 'Audio shift': AUDIO_SHIFT}, f'recorded={p.extra_generation_params}' + assert shifts(pipe) == (VIDEO_SHIFT, VIDEO_SHIFT, AUDIO_SHIFT), f'shifts={shifts(pipe)}' + + +# ============================================================ +# Main +# ============================================================ + +def main(): + cat = category('resolve') + for fn in (test_resolve_prefers_positive_request, test_resolve_reads_the_shipped_value_not_the_live_one): + run_test(cat, fn) + cat = category('apply') + for fn in (test_set_writes_every_copy_and_keys_the_result, test_next_request_without_values_resets, test_default_sampler_restore_carries_the_shift, test_unsupported_scheduler_is_skipped): + run_test(cat, fn) + cat = category('overrides') + for fn in (test_apply_overrides_records_the_applied_values, test_apply_overrides_without_values_uses_the_shipped_schedule): + run_test(cat, fn) + failed = sum(r['failed'] for r in results.values()) + passed = sum(r['passed'] for r in results.values()) + log.info(f'MiniMax shift tests: passed={passed} failed={failed}') + return 1 if failed else 0 + + +if __name__ == '__main__': + sys.exit(main()) diff --git a/test/test-native-transformer.py b/test/test-native-transformer.py index 84775b51e..d45cac649 100644 --- a/test/test-native-transformer.py +++ b/test/test-native-transformer.py @@ -843,6 +843,7 @@ def test_transformer_spec_defaults(): assert spec.acceptable_missing == ('rope.', 'pos_embedder.', 'learnable_pos_embed.') assert spec.ignored_prefixes == ('cond_stage_model.', 'conditioner.', 'first_stage_model.', 'text_encoders.', 'vae.') assert spec.forbidden_markers == () + assert spec.infer_config is None def test_sibling_spec_defaults(): @@ -903,6 +904,23 @@ class MockKwargsTransformer(MockMiniTransformer): return cls(dim=config['dim']) +class MockLayeredTransformer(torch.nn.Module): + """Depth comes from config, mirroring ``num_layers`` on real DiTs.""" + + @classmethod + def from_config(cls, config: dict) -> 'MockLayeredTransformer': + return cls(dim=config['dim'], num_layers=config['num_layers']) + + def __init__(self, dim: int, num_layers: int): + super().__init__() + self.blocks = torch.nn.ModuleList([torch.nn.Linear(dim, dim) for _ in range(num_layers)]) + + +def infer_num_layers(state_dict: dict) -> dict: + indices = [int(k.split('.')[1]) for k in state_dict if k.startswith('blocks.')] + return {'num_layers': max(indices) + 1} if indices else {} + + def write_fixture(state_dict_keys: dict, fd: int, path: str, metadata: dict | None = None) -> str: os.close(fd) safetensors.torch.save_file(state_dict_keys, path, metadata=metadata) @@ -1012,6 +1030,51 @@ def test_load_forwards_kwargs_to_from_config(): os.unlink(path) +def test_load_infer_config_sizes_module_to_file(): + """A file deeper than the base config loads only with the hook; without it + the extra block is an arch mismatch.""" + fd, path = tempfile.mkstemp(suffix='.safetensors') + try: + dim = 8 + file_layers = 3 + raw = {} + for i in range(file_layers): + raw[f'model.diffusion_model.blocks.{i}.weight'] = torch.randn(dim, dim) + raw[f'model.diffusion_model.blocks.{i}.bias'] = torch.zeros(dim) + write_fixture(raw, fd, path) + + orig_fetch = nt.fetch_component_config + nt.fetch_component_config = lambda repo, sub: {'dim': dim, 'num_layers': 2} + from modules import model_quant + orig_get_dit = model_quant.get_dit_args + orig_get_qtype = model_quant.get_quant_type + orig_do_post = model_quant.do_post_load_quant + model_quant.get_dit_args = lambda *a, **k: ({}, {}) + model_quant.get_quant_type = lambda *a, **k: None + model_quant.do_post_load_quant = lambda *a, **k: None + + try: + try: + nt.load(local_file=path, repo_id='fake/repo', spec=nt.TransformerSpec(cls=MockLayeredTransformer), diffusers_cfg={}) + raise AssertionError('expected OverrideArchMismatch without infer_config') + except nt.OverrideArchMismatch: + pass + spec = nt.TransformerSpec(cls=MockLayeredTransformer, infer_config=infer_num_layers) + transformer, _ = nt.load(local_file=path, repo_id='fake/repo', spec=spec, diffusers_cfg={}) + finally: + nt.fetch_component_config = orig_fetch + model_quant.get_dit_args = orig_get_dit + model_quant.get_quant_type = orig_get_qtype + model_quant.do_post_load_quant = orig_do_post + + assert len(transformer.blocks) == file_layers + loaded_w = transformer.blocks[2].weight.detach().cpu() + assert torch.allclose(loaded_w, raw['model.diffusion_model.blocks.2.weight'].to(loaded_w.dtype)) + finally: + if os.path.exists(path): + os.unlink(path) + + def test_load_end_to_end_with_sibling_partition(): """Bundled-sibling case: file carries both transformer and sibling weights, sibling_classes supplies the runtime sibling class, partition routes each @@ -2204,6 +2267,61 @@ def test_build_component_comfy_preempts_sdnq_fresh_quant(): assert component.in_proj.weight.dtype == torch.int8 +# ============================================================ +# anima config inference (depth-expanded checkpoints) +# ============================================================ + +def anima_block_keys(count: int, prefix: str = 'blocks') -> dict: + sd = {} + for i in range(count): + sd[f'{prefix}.{i}.self_attn.q_proj.weight'] = torch.zeros(2, 2) + sd[f'{prefix}.{i}.mlp.layer2.weight'] = torch.zeros(2, 2) + return sd + + +def test_anima_infer_config_counts_cosmos_blocks(): + """40-block file reports num_layers=40; adapter ``blocks.N`` keys and + top-level tensors do not count.""" + from pipelines import anima + sd = anima_block_keys(40) + sd['llm_adapter.blocks.5.self_attn.q_proj.weight'] = torch.zeros(2, 2) + sd['x_embedder.proj.1.weight'] = torch.zeros(2, 2) + sd['final_layer.linear.weight'] = torch.zeros(2, 2) + assert anima.infer_config(sd) == {'num_layers': 40} + + +def test_anima_infer_config_matches_base_depth(): + from pipelines import anima + assert anima.infer_config(anima_block_keys(28)) == {'num_layers': 28} + + +def test_anima_infer_config_diffusers_layout(): + """Files already in diffusers key layout count ``transformer_blocks.N``.""" + from pipelines import anima + assert anima.infer_config(anima_block_keys(40, prefix='transformer_blocks')) == {'num_layers': 40} + + +def test_anima_infer_config_comfy_sidecars_do_not_inflate(): + """Per-block quant sidecars share the block index and do not change the count.""" + from pipelines import anima + sd = anima_block_keys(40) + for i in range(40): + sd[f'blocks.{i}.self_attn.q_proj.weight_scale'] = torch.zeros(2, 1) + sd[f'blocks.{i}.self_attn.q_proj.comfy_quant'] = torch.zeros(8, dtype=torch.uint8) + assert anima.infer_config(sd) == {'num_layers': 40} + + +def test_anima_infer_config_no_blocks_returns_empty(): + from pipelines import anima + assert anima.infer_config({'x_embedder.proj.1.weight': torch.zeros(2, 2)}) == {} + assert anima.infer_config({}) == {} + + +def test_anima_spec_registers_infer_config(): + from pipelines import anima + assert anima.ANIMA_SPEC.infer_config is anima.infer_config + + # ============================================================ # Run # ============================================================ @@ -2353,6 +2471,7 @@ def run_all(): for fn in [ test_load_end_to_end_with_bfl_prefix_no_converter, test_load_forwards_kwargs_to_from_config, + test_load_infer_config_sizes_module_to_file, test_load_end_to_end_with_sibling_partition, test_load_raises_on_missing_sibling_class, test_load_rejects_non_safetensors, @@ -2401,6 +2520,18 @@ def run_all(): ]: run_test(cat, fn) + log.warning('=== anima config inference ===') + cat = category('anima') + for fn in [ + test_anima_infer_config_counts_cosmos_blocks, + test_anima_infer_config_matches_base_depth, + test_anima_infer_config_diffusers_layout, + test_anima_infer_config_comfy_sidecars_do_not_inflate, + test_anima_infer_config_no_blocks_returns_empty, + test_anima_spec_registers_infer_config, + ]: + run_test(cat, fn) + log.warning('=== Results ===') total_passed = 0 total_failed = 0 diff --git a/test/test-offload-roles.py b/test/test-offload-roles.py index ba97fd3ca..8af4bfe56 100644 --- a/test/test-offload-roles.py +++ b/test/test-offload-roles.py @@ -1,6 +1,6 @@ #!/usr/bin/env python """ -Offline unit tests for group offload placement in modules.sd_offload. +Offline unit tests for group offload placement in modules.sd_offload_group. Every component takes exactly one role, derived from the component itself: @@ -59,7 +59,7 @@ modules.cmd_args.parsed, _ = modules.cmd_args.parser.parse_known_args([]) from diffusers.utils.accelerate_utils import apply_forward_hook # pylint: disable=wrong-import-position from modules.errors import log # pylint: disable=wrong-import-position from modules import shared # pylint: disable=wrong-import-position,unused-import -from modules import sd_offload # pylint: disable=wrong-import-position +from modules import sd_offload_group, sd_offload_state, sd_offload_utils # pylint: disable=wrong-import-position # ============================================================ @@ -246,28 +246,28 @@ ROLE_CASES = [ def test_role_table(): wrong = [] for module_name, cls, expected in ROLE_CASES: - role = sd_offload.group_offload_role(module_name, cls()) + role = sd_offload_group.group_offload_role(module_name, cls()) if role != expected: wrong.append(f'{module_name}/{cls.__name__}: {role} != {expected}') assert not wrong, '; '.join(wrong) def test_role_bridge_overrides_denoiser_slot_name(): - assert sd_offload.group_offload_role('decoder', BridgeModule()) == 'ondemand' + assert sd_offload_group.group_offload_role('decoder', BridgeModule()) == 'ondemand' def test_role_upstream_optout_overrides_denoiser_slot_name(): - assert sd_offload.group_offload_role('transformer', UnsupportedModule()) == 'ondemand' + assert sd_offload_group.group_offload_role('transformer', UnsupportedModule()) == 'ondemand' def test_role_undecorated_entry_points_stay_resident(): # neither group hooks nor the on-demand hook fire for a plain method call, so residency is the only safe placement - assert sd_offload.group_offload_role('vae', NoBridgeModule()) == 'resident' + assert sd_offload_group.group_offload_role('vae', NoBridgeModule()) == 'resident' def test_role_unknown_component_is_aux(): # aux is the direction that stays correct when the guess is wrong - assert sd_offload.group_offload_role('some_future_head', PlainModule()) == 'aux' + assert sd_offload_group.group_offload_role('some_future_head', PlainModule()) == 'aux' def role_with_opts(module_name, module, **opts): @@ -275,7 +275,7 @@ def role_with_opts(module_name, module, **opts): for key, value in opts.items(): setattr(shared.opts, key, value) try: - return sd_offload.group_offload_role(module_name, module) + return sd_offload_group.group_offload_role(module_name, module) finally: for key, value in saved.items(): setattr(shared.opts, key, value) @@ -303,7 +303,7 @@ def test_role_empty_exclusions_match_nothing(): def test_role_main_list_has_no_encoder_names(): - encoders = [n for n in sd_offload.group_offload_main if 'encoder' in n or 'vae' in n] + encoders = [n for n in sd_offload_state.group_offload_main if 'encoder' in n or 'vae' in n] assert not encoders, f'encoder-shaped names in the per-step list: {encoders}' @@ -317,28 +317,28 @@ def dispatch_calls(pipe): seen: dict[str, object] = {} def name_of(module): - return next((n for n in sd_offload.get_module_names(pipe) if getattr(pipe, n, None) is module), module.__class__.__name__) + return next((n for n in sd_offload_utils.get_module_names(pipe) if getattr(pipe, n, None) is module), module.__class__.__name__) def record(name, role, module): calls.setdefault(name, []).append(role) seen[name] = module return True - orig_component = sd_offload.apply_group_offload_component - orig_ondemand = sd_offload.apply_group_offload_ondemand - orig_resident = sd_offload.set_group_resident - orig_stats = sd_offload.report_group_stats - sd_offload.apply_group_offload_component = lambda module, module_name, main: record(module_name, 'main' if main else 'aux', module) - sd_offload.apply_group_offload_ondemand = lambda module: record(name_of(module), 'ondemand', module) - sd_offload.set_group_resident = lambda module: record(name_of(module), 'resident', module) - sd_offload.report_group_stats = lambda sd_model, module_names: None + orig_component = sd_offload_group.apply_group_offload_component + orig_ondemand = sd_offload_group.apply_group_offload_ondemand + orig_resident = sd_offload_group.set_group_resident + orig_stats = sd_offload_group.report_group_stats + sd_offload_group.apply_group_offload_component = lambda module, module_name, main: record(module_name, 'main' if main else 'aux', module) + sd_offload_group.apply_group_offload_ondemand = lambda module: record(name_of(module), 'ondemand', module) + sd_offload_group.set_group_resident = lambda module: record(name_of(module), 'resident', module) + sd_offload_group.report_group_stats = lambda sd_model, module_names: None try: - sd_offload.apply_group_offload(pipe) + sd_offload_group.apply_group_offload(pipe) finally: - sd_offload.apply_group_offload_component = orig_component - sd_offload.apply_group_offload_ondemand = orig_ondemand - sd_offload.set_group_resident = orig_resident - sd_offload.report_group_stats = orig_stats + sd_offload_group.apply_group_offload_component = orig_component + sd_offload_group.apply_group_offload_ondemand = orig_ondemand + sd_offload_group.set_group_resident = orig_resident + sd_offload_group.report_group_stats = orig_stats return calls, seen @@ -364,12 +364,34 @@ def test_dispatch_skips_non_modules(): assert list(calls) == ['transformer'], f'dispatched {list(calls)}' +def test_stats_report_once_per_component(): + seen = [] + orig_stats = sd_offload_group.report_model_stats + sd_offload_group.report_model_stats = lambda module_name, module: seen.append(module_name) + try: + transformer, vae = PlainModule(), BridgeModule() + pipe = FakePipe({'transformer': transformer, 'vae': vae}) + names = sd_offload_utils.get_module_names(pipe) + sd_offload_group.report_group_stats(pipe, names) + assert sorted(seen) == ['transformer', 'vae'], f'first report covered {seen}' + sd_offload_group.report_group_stats(pipe, names) + assert len(seen) == 2, f'a reapply reported again: {seen}' + switched = FakePipe({'transformer': transformer, 'vae': vae}) # a task switch rebuilds the pipe around the same components + sd_offload_group.report_group_stats(switched, names) + assert len(seen) == 2, f'a task switch reported again: {seen}' + reloaded = FakePipe({'transformer': PlainModule(), 'vae': vae}) # a reload or a component swap brings a new module + sd_offload_group.report_group_stats(reloaded, names) + assert seen[2:] == ['transformer'], f'a new component was not reported on its own: {seen}' + finally: + sd_offload_group.report_model_stats = orig_stats + + def test_force_sweep_moves_only_stamped_components(): stamped = SweepModule() stamped.sdnext_ondemand = True unstamped = SweepModule() pipe = FakePipe({'vae': stamped, 'transformer': unstamped}) - sd_offload.offload_ondemand(pipe, reason='test', force=True) + sd_offload_group.offload_ondemand(pipe, reason='test', force=True) assert stamped.moved, 'the stamped component must be swept to cpu' assert not unstamped.moved, 'a component with no onload path must not be swept' @@ -378,34 +400,34 @@ def test_reapply_after_clearing_the_never_list_restores_hooks(): module = PlainModule() pipe = FakePipe({'text_encoder': module}) saved_never = shared.opts.diffusers_offload_never - orig_device = sd_offload.devices.device - orig_stats = sd_offload.report_group_stats - sd_offload.devices.device = torch.device('cpu') # residency moves to the accelerator, so pin the target to cpu - sd_offload.report_group_stats = lambda sd_model, module_names: None + orig_device = sd_offload_group.devices.device + orig_stats = sd_offload_group.report_group_stats + sd_offload_group.devices.device = torch.device('cpu') # residency moves to the accelerator, so pin the target to cpu + sd_offload_group.report_group_stats = lambda sd_model, module_names: None try: shared.opts.diffusers_offload_never = 'text_encoder' - sd_offload.apply_group_offload(pipe) + sd_offload_group.apply_group_offload(pipe) assert getattr(module, 'sdnext_group_offload_sig', None) is None, 'a resident component must carry no group signature' shared.opts.diffusers_offload_never = '' - sd_offload.apply_group_offload(pipe) + sd_offload_group.apply_group_offload(pipe) assert getattr(module, 'sdnext_group_offload_sig', None) not in (None, 'partial'), 'clearing the exclusion must re-place the component' finally: shared.opts.diffusers_offload_never = saved_never - sd_offload.devices.device = orig_device - sd_offload.report_group_stats = orig_stats + sd_offload_group.devices.device = orig_device + sd_offload_group.report_group_stats = orig_stats def test_ondemand_list_tracks_the_stamps(): pipe = FakePipe({'transformer': PlainModule(), 'vae': BridgeModule()}) - orig_component = sd_offload.apply_group_offload_component - orig_stats = sd_offload.report_group_stats - sd_offload.apply_group_offload_component = lambda module, module_name, main: True - sd_offload.report_group_stats = lambda sd_model, module_names: None + orig_component = sd_offload_group.apply_group_offload_component + orig_stats = sd_offload_group.report_group_stats + sd_offload_group.apply_group_offload_component = lambda module, module_name, main: True + sd_offload_group.report_group_stats = lambda sd_model, module_names: None try: - sd_offload.apply_group_offload(pipe) + sd_offload_group.apply_group_offload(pipe) finally: - sd_offload.apply_group_offload_component = orig_component - sd_offload.report_group_stats = orig_stats + sd_offload_group.apply_group_offload_component = orig_component + sd_offload_group.report_group_stats = orig_stats assert pipe.sdnext_ondemand_modules == ['vae'], f'on-demand list is {pipe.sdnext_ondemand_modules}' assert getattr(pipe.vae, 'sdnext_ondemand', False), 'the vae must carry the on-demand stamp' @@ -416,8 +438,8 @@ def test_ondemand_list_tracks_the_stamps(): def test_ondemand_apply_returns_bool_and_is_idempotent(): module = BridgeModule() - first = sd_offload.apply_group_offload_ondemand(module) - second = sd_offload.apply_group_offload_ondemand(module) + first = sd_offload_group.apply_group_offload_ondemand(module) + second = sd_offload_group.apply_group_offload_ondemand(module) assert isinstance(first, bool) and isinstance(second, bool), 'placement must report a bool' assert first is True, 'the first placement changes the component' assert second is False, 'an unchanged component must report no change' @@ -426,24 +448,77 @@ def test_ondemand_apply_returns_bool_and_is_idempotent(): def test_ondemand_apply_leaves_weights_on_cpu(): module = BridgeModule() - sd_offload.apply_group_offload_ondemand(module) + sd_offload_group.apply_group_offload_ondemand(module) assert next(module.parameters()).device.type == 'cpu', 'on-demand components rest on cpu' def test_resident_placement_clears_the_ondemand_stamp(): module = BridgeModule() - sd_offload.apply_group_offload_ondemand(module) - orig_device = sd_offload.devices.device - sd_offload.devices.device = torch.device('cpu') # residency moves to the accelerator, so pin the target to cpu + sd_offload_group.apply_group_offload_ondemand(module) + orig_device = sd_offload_group.devices.device + sd_offload_group.devices.device = torch.device('cpu') # residency moves to the accelerator, so pin the target to cpu try: - changed = sd_offload.set_group_resident(module) + changed = sd_offload_group.set_group_resident(module) finally: - sd_offload.devices.device = orig_device + sd_offload_group.devices.device = orig_device assert isinstance(changed, bool) and changed is True, 'moving off the on-demand hook is a change' assert not getattr(module, 'sdnext_ondemand', False), 'the on-demand stamp must not survive' assert not hasattr(module, '_hf_hook'), 'the on-demand hook must be removed' +def accelerator(): + """The restore round trip needs a device that swaps tensor data with cpu both ways; meta cannot, so these two tests take a real accelerator or skip.""" + if torch.cuda.is_available(): + return torch.device('cuda') + log.warning(' SKIP: no accelerator for the round trip') + return None + + +def test_ondemand_offload_hands_back_the_loaded_tensors(): + device = accelerator() + if device is None: + return True + module = BridgeModule() + sd_offload_group.apply_group_offload_ondemand(module) + loaded = {name: p.data for name, p in module.named_parameters()} + pipe = FakePipe({'vae': module}) + orig_device = sd_offload_group.devices.device + sd_offload_group.devices.device = device + try: + module._hf_hook.pre_forward(module, torch.zeros(1, 4)) # pylint: disable=protected-access + assert next(module.parameters()).device.type == device.type, 'the entry hook must onload the whole module' + sd_offload_group.offload_ondemand(pipe, force=True) + finally: + sd_offload_group.devices.device = orig_device + for name, param in module.named_parameters(): + assert param.data.data_ptr() == loaded[name].data_ptr(), f'{name} came back as a copy rather than the loaded tensor' + return True + + +def test_group_offload_hands_back_the_loaded_tensors(): + from diffusers.hooks.group_offloading import _GROUP_OFFLOADING + device = accelerator() + if device is None: + return True + module = PlainModule() + orig_device = sd_offload_group.devices.device + sd_offload_group.devices.device = device + try: + assert sd_offload_group.apply_group_offload_component(module, 'text_encoder', main=False) is True + loaded = {name: p.data for name, p in module.named_parameters()} + group = module.proj._diffusers_hook.get_hook(_GROUP_OFFLOADING).group # pylint: disable=protected-access + assert group.stream is None and hasattr(group, 'sdnext_onload'), 'aux components take the no-stream path and must carry the restore patch' + group.onload_() + assert next(module.parameters()).device.type == device.type, 'onload must still move the group' + group.offload_() + finally: + sd_offload_group.devices.device = orig_device + for name, param in module.named_parameters(): + assert param.data.data_ptr() == loaded[name].data_ptr(), f'{name} came back as a copy rather than the loaded tensor' + assert sd_offload_group.keep_loaded_tensors(module) == 0, 'a second pass must not patch the same groups again' + return True + + # ============================================================ # get_module_names # ============================================================ @@ -451,7 +526,7 @@ def test_resident_placement_clears_the_ondemand_stamp(): def test_module_names_reads_specs_on_modular_pipelines(): # transformer_2 exists only in the specs, so only the specs branch can find it pipe = FakeModularPipe({'transformer': PlainModule(), 'vae': BridgeModule(), 'scheduler': object()}, spec_only={'transformer_2': PlainModule()}) - names = sd_offload.get_module_names(pipe) + names = sd_offload_utils.get_module_names(pipe) assert names == ['transformer', 'transformer_2', 'vae'], f'got {names}' assert 'canvas_short_edge' not in names, 'config scalars must not be enumerated' @@ -464,7 +539,7 @@ def test_module_names_ignores_the_component_registry_on_classic_pipelines(): raise ValueError('config and signature disagree') pipe = RaisingPipe({'transformer': PlainModule(), 'vae': BridgeModule()}) - names = sd_offload.get_module_names(pipe) + names = sd_offload_utils.get_module_names(pipe) assert names == ['transformer', 'vae'], f'got {names}' @@ -474,13 +549,13 @@ def test_module_names_ignores_the_component_registry_on_classic_pipelines(): def test_autoencoders_carry_the_entry_bridge(): from diffusers import AutoencoderKL, VQModel - missing = [cls.__name__ for cls in (AutoencoderKL, VQModel) if not sd_offload.has_entry_bridge(cls)] + missing = [cls.__name__ for cls in (AutoencoderKL, VQModel) if not sd_offload_group.has_entry_bridge(cls)] assert not missing, f'no entry bridge detected on {missing}' def test_denoisers_do_not_carry_the_entry_bridge(): from diffusers import SD3Transformer2DModel, UNet2DConditionModel - bridged = [cls.__name__ for cls in (UNet2DConditionModel, SD3Transformer2DModel) if sd_offload.has_entry_bridge(cls)] + bridged = [cls.__name__ for cls in (UNet2DConditionModel, SD3Transformer2DModel) if sd_offload_group.has_entry_bridge(cls)] assert not bridged, f'entry bridge detected on denoisers {bridged}' @@ -492,7 +567,7 @@ def test_upstream_still_opts_hunyuandit_out_of_group_offload(): def test_mageflow_vae_carries_the_entry_bridge(): from pipelines.mageflow.autoencoder_mage_vae import AutoencoderMageVAE - assert sd_offload.has_entry_bridge(AutoencoderMageVAE), 'the mageflow vae lost its entry decorators' + assert sd_offload_group.has_entry_bridge(AutoencoderMageVAE), 'the mageflow vae lost its entry decorators' # ============================================================ @@ -597,7 +672,7 @@ def inventory_roles(never=''): shared.opts.diffusers_offload_never = never shared.opts.models_not_to_offload = '' try: - return {(pipe, slot, comp.__name__): sd_offload.group_offload_role(slot, weightless(comp)) for pipe, slot, comp in rows} + return {(pipe, slot, comp.__name__): sd_offload_group.group_offload_role(slot, weightless(comp)) for pipe, slot, comp in rows} finally: shared.opts.diffusers_offload_never, shared.opts.models_not_to_offload = saved @@ -671,6 +746,7 @@ def run_all(): for fn in [ test_dispatch_is_one_arm_per_component, test_dispatch_skips_non_modules, + test_stats_report_once_per_component, test_ondemand_list_tracks_the_stamps, test_force_sweep_moves_only_stamped_components, test_reapply_after_clearing_the_never_list_restores_hooks, @@ -683,6 +759,8 @@ def run_all(): test_ondemand_apply_returns_bool_and_is_idempotent, test_ondemand_apply_leaves_weights_on_cpu, test_resident_placement_clears_the_ondemand_stamp, + test_ondemand_offload_hands_back_the_loaded_tensors, + test_group_offload_hands_back_the_loaded_tensors, ]: run_test(cat, fn) diff --git a/test/test-pdd.py b/test/test-pdd.py new file mode 100644 index 000000000..de5e3d04b --- /dev/null +++ b/test/test-pdd.py @@ -0,0 +1,393 @@ +#!/usr/bin/env python +""" +Offline unit tests for modules.lora.network_pdd. + +Checks the parallel decoding head mechanics against the reference formulas +shipped with alibaba-pai/MiniMax-H3-Acc-LoRAs (minimax_h3_pdd.py): + +- ``detect`` / ``load`` metadata and head-tensor discovery +- ``grid_intervals`` against ``pdd_time_grid`` for the video and audio shifts +- ``ParallelHead`` against ``MiniMaxH3ParallelHead`` on every block, plus the strength blend +- ``install`` / ``restore`` / ``reconcile`` round trips on a stub pipeline +- ``pin`` step and shift override + +No running server required. + +Usage: + python test/test-pdd.py +""" + +import os +import sys +import types + +import torch + +script_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) +sys.path.insert(0, script_dir) +os.chdir(script_dir) + +os.environ['SD_INSTALL_QUIET'] = '1' + +# Bootstrap cmd_args before any module that pulls in shared.py. +import modules.cmd_args # pylint: disable=wrong-import-position +import installer # pylint: disable=wrong-import-position +_orig_argv = sys.argv +sys.argv = [sys.argv[0]] +try: + modules.cmd_args.parse_args() +finally: + sys.argv = _orig_argv +installer.add_args(modules.cmd_args.parser) +modules.cmd_args.parsed, _ = modules.cmd_args.parser.parse_known_args([]) + +import diffusers # pylint: disable=wrong-import-position +from modules import shared # pylint: disable=wrong-import-position,unused-import # shared must initialize before sd_models, which imports back into it +from modules.errors import log # pylint: disable=wrong-import-position +from modules.lora import network_pdd # pylint: disable=wrong-import-position +from pipelines.minimax import minimax_lora # pylint: disable=wrong-import-position + + +NUM_STEPS = 32 +BLOCK = 4 +HIDDEN = 16 +VIDEO_OUT = 8 +AUDIO_OUT = 6 +METADATA = {'pdd_num_steps': '32', 'pdd_block_size': '4', 'lora_rank': '64', 'lora_alpha': '64.0'} + + +# ============================================================ +# Reference implementation (minimax_h3_pdd.py) +# ============================================================ + +def reference_time_grid(shift, num_steps): + sigma = torch.linspace(1.0, 0.0, num_steps + 1, dtype=torch.float64) + return 1.0 - shift * sigma / (1 + (shift - 1) * sigma) + + +def reference_plan(step_sizes, start, block_size): + plan = torch.zeros(1, step_sizes.shape[0], dtype=step_sizes.dtype) + span = step_sizes[start:start + block_size].sum() + plan[0, start:start + block_size] = step_sizes[start:start + block_size] / span + return plan + + +class ReferenceHead(torch.nn.Module): + def __init__(self, weight, bias): + super().__init__() + self.num_steps = weight.shape[0] + self.weight = torch.nn.Parameter(weight.clone()) + self.bias = torch.nn.Parameter(bias.clone()) + self.plan = torch.zeros(1, self.num_steps) + + def forward(self, hidden_states): + plan = self.plan.to(device=self.weight.device, dtype=self.weight.dtype) + weight = torch.einsum('pn,noi->poi', plan, self.weight).flatten(0, 1) + bias = torch.einsum('pn,no->po', plan, self.bias).flatten() + return torch.nn.functional.linear(hidden_states, weight, bias) + + +# ============================================================ +# Test infrastructure +# ============================================================ + +results: dict[str, dict] = {} + + +def category(name: str): + if name not in results: + results[name] = {'passed': 0, 'failed': 0, 'tests': []} + return name + + +def record(cat: str, passed: bool, name: str, detail: str = ''): + status = 'PASS' if passed else 'FAIL' + results[cat]['passed' if passed else 'failed'] += 1 + results[cat]['tests'].append((status, name)) + msg = f' {status}: {name}' + if detail: + msg += f' ({detail})' + if passed: + log.info(msg) + else: + log.error(msg) + + +def run_test(cat: str, fn): + name = fn.__name__ + try: + ok = fn() + record(cat, ok is not False, name) + except AssertionError as e: + record(cat, False, name, str(e)) + except Exception as e: # pylint: disable=broad-except + record(cat, False, name, f'{type(e).__name__}: {e}') + + +# ============================================================ +# Fixtures +# ============================================================ + +class StubPipe: + """The parts of a modular pipeline the engine touches: components and two schedulers.""" + + def __init__(self): + self.transformer = torch.nn.Module() + self.transformer.proj_out = torch.nn.Linear(HIDDEN, VIDEO_OUT) + self.transformer.audio_proj_out = torch.nn.Linear(HIDDEN, AUDIO_OUT) + self.scheduler = diffusers.MiniMaxH3Scheduler(shift=12.0) + self.audio_scheduler = diffusers.MiniMaxH3Scheduler(shift=3.0) + self.num_timesteps = 29 + + +def make_heads(): + torch.manual_seed(0) + return network_pdd.ParallelHeads(NUM_STEPS, BLOCK, { + 'proj_out': (torch.randn(NUM_STEPS, VIDEO_OUT, HIDDEN), torch.randn(NUM_STEPS, VIDEO_OUT)), + 'audio_proj_out': (torch.randn(NUM_STEPS, AUDIO_OUT, HIDDEN), torch.randn(NUM_STEPS, AUDIO_OUT)), + }) + + +def make_net(heads, strength=1.0): + return types.SimpleNamespace(name='pdd-test', te_multiplier=strength, extras={network_pdd.EXTRAS_KEY: heads}) + + +# ============================================================ +# Tests: detection and loading +# ============================================================ + +def test_detect_grid(): + assert network_pdd.detect(METADATA) == (32, 4) + assert network_pdd.detect({'pdd_num_steps': '16'}) == (16, 1) + assert network_pdd.detect({}) is None + assert network_pdd.detect(None) is None + + +def test_detect_rejects_bad_block(): + try: + network_pdd.detect({'pdd_num_steps': '32', 'pdd_block_size': '5'}) + except ValueError: + return True + raise AssertionError('block size 5 accepted for a 32 grid') + + +def test_load_collects_heads(): + state_dict = { + 'proj_out.weight': torch.zeros(NUM_STEPS, VIDEO_OUT, HIDDEN), + 'proj_out.bias': torch.zeros(NUM_STEPS, VIDEO_OUT), + 'audio_proj_out.weight': torch.zeros(NUM_STEPS, AUDIO_OUT, HIDDEN), + 'audio_proj_out.bias': torch.zeros(NUM_STEPS, AUDIO_OUT), + 'transformer_blocks.0.attn.to_q.lora_down': torch.zeros(64, HIDDEN), + 'transformer_blocks.0.attn.to_q.lora_up': torch.zeros(HIDDEN, 64), + } + heads = network_pdd.load('x', METADATA, state_dict) + assert heads is not None and set(heads.heads) == {'proj_out', 'audio_proj_out'}, f'heads={None if heads is None else list(heads.heads)}' + assert heads.nfe == 8 and heads.block_size == 4 + assert heads.heads['proj_out'][1] is not None, 'bias not paired' + + +def test_load_without_metadata_is_none(): + assert network_pdd.load('x', {'alpha': '1'}, {'proj_out.weight': torch.zeros(NUM_STEPS, VIDEO_OUT, HIDDEN)}) is None + + +def test_load_without_heads_is_none(): + assert network_pdd.load('x', METADATA, {'transformer_blocks.0.attn.to_q.lora_down': torch.zeros(64, HIDDEN)}) is None + + +def write_pdd_file(folder, metadata): + from safetensors.torch import save_file + path = os.path.join(folder, 'pdd.safetensors') + save_file({'proj_out.weight': torch.zeros(NUM_STEPS, VIDEO_OUT, HIDDEN), 'proj_out.bias': torch.zeros(NUM_STEPS, VIDEO_OUT)}, path, metadata=metadata) + return path + + +def test_try_load_reads_the_grid_from_the_file_header(): + import tempfile + with tempfile.TemporaryDirectory() as folder: + disk = types.SimpleNamespace(name='pdd', filename=write_pdd_file(folder, METADATA), metadata={}) # the cached metadata lacks the grid + net = network_pdd.try_load('pdd', disk, 1.0) + assert net is not None and network_pdd.EXTRAS_KEY in net.extras, 'the grid in the file header must be enough' + assert net.extras[network_pdd.EXTRAS_KEY].nfe == NUM_STEPS // BLOCK + + +def test_try_load_without_grid_metadata_is_none(): + import tempfile + with tempfile.TemporaryDirectory() as folder: + disk = types.SimpleNamespace(name='pdd', filename=write_pdd_file(folder, {'alpha': '1'}), metadata={}) + assert network_pdd.try_load('pdd', disk, 1.0) is None + + +# ============================================================ +# Tests: grid and fusion math +# ============================================================ + +def test_grid_intervals_match_reference(): + for shift in (12.0, 3.0): + scheduler = diffusers.MiniMaxH3Scheduler(shift=shift) + scheduler.set_shift(4.0) # a live override must not leak into the training grid + intervals = network_pdd.grid_intervals(scheduler, NUM_STEPS, minimax_lora.PDD) + reference = reference_time_grid(shift, NUM_STEPS).diff() + assert intervals is not None and intervals.shape == reference.shape, f'shift={shift} shape={None if intervals is None else intervals.shape}' + assert torch.allclose(intervals, reference, atol=1e-6), f'shift={shift} maxdiff={(intervals - reference).abs().max().item()}' + + +def test_steps_for_counts_terminal_sigma(): + assert minimax_lora.PDD.steps_for(8) == 9 + assert minimax_lora.PDD.scheduler_name('audio_proj_out') == 'audio_scheduler' + assert minimax_lora.PDD.scheduler_name('proj_out') == 'scheduler' + + +def test_parallel_head_matches_reference_per_block(): + heads = make_heads() + weight, bias = heads.heads['proj_out'] + base = torch.nn.Linear(HIDDEN, VIDEO_OUT) + scheduler = diffusers.MiniMaxH3Scheduler(shift=12.0) + intervals = network_pdd.grid_intervals(scheduler, NUM_STEPS, minimax_lora.PDD) + stub = types.SimpleNamespace(step_index=None) + head = network_pdd.ParallelHead(base, weight, bias, 1.0, lambda: stub, BLOCK, intervals) + reference = ReferenceHead(weight, bias) + step_sizes = reference_time_grid(12.0, NUM_STEPS).diff() + x = torch.randn(2, 5, HIDDEN) + for index in range(NUM_STEPS // BLOCK): + stub.step_index = None if index == 0 else index + reference.plan = reference_plan(step_sizes, index * BLOCK, BLOCK).float() + out = head(x) + ref = reference(x) + assert torch.allclose(out, ref, rtol=1e-4, atol=1e-4), f'block={index} maxdiff={(out - ref).abs().max().item()}' # float32 reduction order differs between tensordot and einsum + assert head.fused_index == index + + +def test_parallel_head_strength_blend(): + heads = make_heads() + weight, bias = heads.heads['proj_out'] + base = torch.nn.Linear(HIDDEN, VIDEO_OUT) + intervals = network_pdd.grid_intervals(diffusers.MiniMaxH3Scheduler(shift=12.0), NUM_STEPS, minimax_lora.PDD) + stub = types.SimpleNamespace(step_index=3) + x = torch.randn(3, HIDDEN) + full = network_pdd.ParallelHead(base, weight, bias, 1.0, lambda: stub, BLOCK, intervals)(x) + off = network_pdd.ParallelHead(base, weight, bias, 0.0, lambda: stub, BLOCK, intervals)(x) + half = network_pdd.ParallelHead(base, weight, bias, 0.5, lambda: stub, BLOCK, intervals)(x) + assert torch.allclose(off, base(x), atol=1e-6), 'strength 0 is not the base projection' + assert torch.allclose(half, 0.5 * (full + base(x)), atol=1e-5), 'strength 0.5 is not the midpoint' + + +def test_parallel_head_clamps_overflow(): + heads = make_heads() + weight, bias = heads.heads['proj_out'] + intervals = network_pdd.grid_intervals(diffusers.MiniMaxH3Scheduler(shift=12.0), NUM_STEPS, minimax_lora.PDD) + stub = types.SimpleNamespace(step_index=11) + head = network_pdd.ParallelHead(torch.nn.Linear(HIDDEN, VIDEO_OUT), weight, bias, 1.0, lambda: stub, BLOCK, intervals) + head(torch.randn(1, HIDDEN)) + assert head.fused_index == 7 and head.overflow_warned + + +def test_parallel_head_keeps_base_out_of_tree(): + heads = make_heads() + weight, bias = heads.heads['proj_out'] + intervals = network_pdd.grid_intervals(diffusers.MiniMaxH3Scheduler(shift=12.0), NUM_STEPS, minimax_lora.PDD) + head = network_pdd.ParallelHead(torch.nn.Linear(HIDDEN, VIDEO_OUT), weight, bias, 1.0, lambda: None, BLOCK, intervals) + assert set(dict(head.named_parameters())) == {'weight', 'bias'}, list(dict(head.named_parameters())) + assert len(list(head.children())) == 0 + assert next(head.parameters()).dtype == torch.float32 + + +# ============================================================ +# Tests: install, restore, reconcile, pin +# ============================================================ + +def test_install_and_restore_round_trip(): + pipe = StubPipe() + original_video, original_audio = pipe.transformer.proj_out, pipe.transformer.audio_proj_out + before = original_video.weight.detach().clone() + before_ptr = original_video.weight.data_ptr() + heads = make_heads() + assert network_pdd.install(pipe, make_net(heads), heads, minimax_lora.PDD, ['unet', 'transformer']) is True + assert isinstance(pipe.transformer.proj_out, network_pdd.ParallelHead) + assert isinstance(pipe.transformer.audio_proj_out, network_pdd.ParallelHead) + assert original_video.weight.data_ptr() != before_ptr and torch.equal(original_video.weight, before), 'the stashed projection must own its memory and keep its values' + assert pipe.sdnext_pdd.steps == 9 and pipe.sdnext_pdd.component == 'transformer' + pipe.audio_scheduler.set_shift(3.0) + pipe.scheduler.set_timesteps(9) + pipe.audio_scheduler.set_timesteps(9) + out = pipe.transformer.audio_proj_out(torch.randn(2, HIDDEN)) + assert out.shape == (2, AUDIO_OUT) + assert network_pdd.restore(pipe) is True + assert pipe.transformer.proj_out is original_video and pipe.transformer.audio_proj_out is original_audio + assert not hasattr(pipe, 'sdnext_pdd') + assert network_pdd.restore(pipe) is False + + +def test_install_refuses_shape_mismatch(): + pipe = StubPipe() + original = pipe.transformer.proj_out + heads = make_heads() + heads.heads['audio_proj_out'] = (torch.randn(NUM_STEPS, AUDIO_OUT + 1, HIDDEN), None) + assert network_pdd.install(pipe, make_net(heads), heads, minimax_lora.PDD, ['transformer']) is False + assert pipe.transformer.proj_out is original, 'partial install left a head behind' + assert not hasattr(pipe, 'sdnext_pdd') + + +def test_install_needs_an_owner(): + pipe = StubPipe() + heads = make_heads() + heads.heads['norm_out.linear'] = (torch.randn(NUM_STEPS, VIDEO_OUT, HIDDEN), None) + assert network_pdd.install(pipe, make_net(heads), heads, minimax_lora.PDD, ['transformer']) is False + + +def test_reconcile_follows_loaded_set(): + pipe = StubPipe() + heads = make_heads() + net = make_net(heads) + saved = network_pdd.arch_spec + network_pdd.arch_spec = lambda: minimax_lora.PDD + try: + assert network_pdd.reconcile(pipe, [net], ['transformer']) is True + assert network_pdd.reconcile(pipe, [net], ['transformer']) is False, 'unchanged set reinstalled' + stronger = make_net(heads, strength=0.5) + assert network_pdd.reconcile(pipe, [stronger], ['transformer']) is True, 'strength change not applied' + assert pipe.sdnext_pdd.strength == 0.5 + assert network_pdd.reconcile(pipe, [types.SimpleNamespace(name='plain', te_multiplier=1.0, extras={})], ['transformer']) is True + assert not hasattr(pipe, 'sdnext_pdd') + assert network_pdd.reconcile(pipe, [], ['transformer']) is False + finally: + network_pdd.arch_spec = saved + + +def test_pin_overrides_steps_and_shift(): + pipe = StubPipe() + heads = make_heads() + assert network_pdd.install(pipe, make_net(heads), heads, minimax_lora.PDD, ['transformer']) is True + pipe.scheduler.set_shift(4.0) + pipe.audio_scheduler.set_shift(2.0) + p = types.SimpleNamespace(steps=30, task_args={'num_inference_steps': 30}, extra_generation_params={'Video shift': 4.0, 'Audio shift': 2.0}) + assert network_pdd.pin(p, pipe) == 9 + assert p.steps == 8 and p.task_args['num_inference_steps'] == 9, f'steps={p.steps} grid_steps={p.task_args["num_inference_steps"]}' + assert pipe.num_timesteps == 8 + assert pipe.scheduler.shift == 12.0 and pipe.audio_scheduler.shift == 3.0 + assert p.extra_generation_params == {'Video shift': 12.0, 'Audio shift': 3.0}, f'recorded={p.extra_generation_params}' + network_pdd.restore(pipe) + assert network_pdd.pin(p, pipe) is None + + +# ============================================================ +# Main +# ============================================================ + +def main(): + cat = category('detect') + for fn in (test_detect_grid, test_detect_rejects_bad_block, test_load_collects_heads, test_load_without_metadata_is_none, test_load_without_heads_is_none, test_try_load_reads_the_grid_from_the_file_header, test_try_load_without_grid_metadata_is_none): + run_test(cat, fn) + cat = category('math') + for fn in (test_grid_intervals_match_reference, test_steps_for_counts_terminal_sigma, test_parallel_head_matches_reference_per_block, test_parallel_head_strength_blend, test_parallel_head_clamps_overflow, test_parallel_head_keeps_base_out_of_tree): + run_test(cat, fn) + cat = category('lifecycle') + for fn in (test_install_and_restore_round_trip, test_install_refuses_shape_mismatch, test_install_needs_an_owner, test_reconcile_follows_loaded_set, test_pin_overrides_steps_and_shift): + run_test(cat, fn) + failed = sum(r['failed'] for r in results.values()) + passed = sum(r['passed'] for r in results.values()) + log.info(f'PDD tests: passed={passed} failed={failed}') + return 1 if failed else 0 + + +if __name__ == '__main__': + sys.exit(main()) diff --git a/test/test-sdnq-lora-factors.py b/test/test-sdnq-lora-factors.py new file mode 100644 index 000000000..f6ffa00b7 --- /dev/null +++ b/test/test-sdnq-lora-factors.py @@ -0,0 +1,3078 @@ +#!/usr/bin/env python +""" +Offline unit tests for LoRA application on SDNQ-quantized layers. + +Pins two facts established on real checkpoints (see cli/lora-quant-fidelity.py +for the per-model analyzer): + +- The requantize path (dequantize + add + requantize) erases sub-step deltas + on low-bit formats: retention collapses to the ~2/group_size grid-extrema + floor on uint4, while int8 retains most of the delta. Guards against the + erasure law silently changing. +- The factor path (modules/lora/lora_sdnq.py) applies plain LoRA deltas + through the svd side-channel exactly, in both svd layouts and across + quantization configs (hadamard on/off, checkpoint svd correction present + or absent), with exact stacking, multiplier scaling and bit-exact + removal, wired through the real networks.network_activate / + network_deactivate control flow. +- Multi-LoRA set transitions keep the base pristine: a layer that fell back + to requantize (mixed factorable/non-factorable set) restores from backup + before re-entering the factor path, layers targeted by only some of the + loaded networks stay independent, and untargeted quantized layers are not + flagged as requantized. +- Robustness: factor removal restores onto the layer's current device after + an offload-style move, and a shape-mismatched network stacked onto a + factor-mode layer downgrades to the legacy path instead of raising. +- Hosting: on sub-8-bit layers, non-factorable sets ride the side-channel as + a truncated svd of their calc_updown delta: low-rank content survives + whole, dense content beats the requantize floor by a wide margin, int8 + and rank 0 keep the requantize path, removal stays bit-exact, and the + svd's random projections never touch the generation rng stream. +- Calibration: per-channel activation statistics weight the hosted + truncation toward loud input channels for better output-space retention; + low-rank content still survives whole, disabling the option reproduces + plain truncation bit-exact, and the capture hooks accumulate, persist + and reload statistics correctly, gated by option, format width and + model compile. +- Factor cache: hosted factors replay bit-identically from the disk cache + without re-running the svd, a configuration change (multiplier) misses + and writes a separate entry, and budget 0 writes nothing. +- Compile: the factor add runs inside the single compiled dequant graph + (fullgraph, no breaks) and matches the eager result; factor ranks pad to + a fixed bucket ladder so set switches inside a bucket reuse the compiled + graph while a novel bucket compiles exactly once, and padding changes + the dequantized weight by nothing beyond reduction-order ulp. + +All tensors are synthetic; no model files or running server required. + +Usage: + python test/test-sdnq-lora-factors.py +""" + +import os +import sys +import time +from contextlib import contextmanager + +import torch + +script_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) +sys.path.insert(0, script_dir) +os.chdir(script_dir) + +os.environ['SD_INSTALL_QUIET'] = '1' + +# Bootstrap cmd_args before any module that pulls in shared.py. +import modules.cmd_args # pylint: disable=wrong-import-position +import installer # pylint: disable=wrong-import-position +_orig_argv = sys.argv +sys.argv = [sys.argv[0]] +try: + modules.cmd_args.parse_args() +finally: + sys.argv = _orig_argv +installer.add_args(modules.cmd_args.parser) +modules.cmd_args.parsed, _ = modules.cmd_args.parser.parse_known_args([]) + +from modules.errors import log # pylint: disable=wrong-import-position +from modules import shared, sd_models # pylint: disable=wrong-import-position +from modules.lora import network, network_lora, lora_blocks, lora_sdnq, lora_stack, networks # pylint: disable=wrong-import-position +from modules.lora import lora_common as l_common # pylint: disable=wrong-import-position +from sdnq.quantizer import sdnq_quantize_layer, SDNQConfig # pylint: disable=wrong-import-position + +DEVICE = torch.device('cuda' if torch.cuda.is_available() else 'cpu') +OUT_F, IN_F, RANK = 512, 512, 8 +shared.opts.lora_stack_mode = 'sum' # suite baseline regardless of user config; stack tests set modes via their own context managers + +results: dict[str, dict] = {} + + +def category(name: str): + if name not in results: + results[name] = {'passed': 0, 'failed': 0, 'tests': []} + return name + + +def record(cat: str, passed: bool, name: str, detail: str = ''): + status = 'PASS' if passed else 'FAIL' + results[cat]['passed' if passed else 'failed'] += 1 + results[cat]['tests'].append((status, name)) + msg = f' {status}: {name}' + if detail: + msg += f' ({detail})' + if passed: + log.info(msg) + else: + log.error(msg) + + +def run_test(cat: str, fn): + name = fn.__name__ + try: + ok = fn() + record(cat, ok is not False, name) + except AssertionError as e: + record(cat, False, name, str(e)) + except Exception as e: # pylint: disable=broad-except + record(cat, False, name, f'exception: {e}') + import traceback + traceback.print_exc() + + +def build_layer(weights_dtype='uint4', use_quantized_matmul=False, seed=0, use_hadamard=True, use_svd=False, use_codebook=False): + torch.manual_seed(seed) + lin = torch.nn.Linear(IN_F, OUT_F, bias=False, dtype=torch.bfloat16, device=DEVICE) + with torch.no_grad(): + lin.weight.copy_(torch.randn(OUT_F, IN_F, device=DEVICE) * 0.04) + cfg = SDNQConfig(weights_dtype=weights_dtype, group_size=0, hadamard_group_size=256, use_hadamard=use_hadamard, + use_svd=use_svd, svd_rank=32, use_quantized_matmul=use_quantized_matmul, dequantize_fp32=False, use_codebook=use_codebook, + quantization_device=str(DEVICE), return_device=str(DEVICE)) + layer, _ = sdnq_quantize_layer(lin, cfg, torch_dtype=torch.bfloat16, param_name='test.weight') + layer.network_layer_name = 'lora_transformer_test' + layer.network_current_names = () + return layer + + +def dq(layer): + return layer.sdnq_dequantizer(layer.weight, layer.scale, zero_point=layer.zero_point, + svd_up=layer.svd_up, svd_down=layer.svd_down, + skip_quantized_matmul=layer.sdnq_dequantizer.use_quantized_matmul, + dtype=torch.float32, skip_compile=True) + + +def make_delta(seed=1, sigma=3e-4): + torch.manual_seed(seed) + A = torch.randn(RANK, IN_F, device=DEVICE) * (sigma ** 0.5) + B = torch.randn(OUT_F, RANK, device=DEVICE) * (sigma ** 0.5) + return A, B, B @ A + + +class MockNOD: + def __init__(self, name): + self.filename = f'/tmp/{name}.safetensors' + self.name = name + self.shorthash = '' + self.sd_version = 'unknown' + + def read_hash(self): + pass + + +def make_net(name, layer, A, B, te_mult=1.0, alpha=None, dora=False): + net = network.Network(name, MockNOD(name)) + net.te_multiplier = te_mult + net.unet_multiplier = [te_mult] * 3 + w = {'lora_up.weight': B.cpu(), 'lora_down.weight': A.cpu()} + if alpha is not None: + w['alpha'] = torch.tensor(float(alpha)) + if dora: + w['dora_scale'] = torch.ones(B.shape[0], 1) + nw = network.NetworkWeights(network_key=layer.network_layer_name, sd_key=layer.network_layer_name, w=w, sd_module=layer) + mod = network_lora.NetworkModuleLora(net, nw) + net.modules[layer.network_layer_name] = mod + return net + + +def rho_of(E, D): + return float(E.flatten() @ D.flatten() / D.flatten().square().sum()) + + +def requant_effective(layer, D): + """The lossy fallback path: quantize(W_dq + D) fresh with the layer's own params.""" + from sdnq.quantizer import sdnq_quantize_layer_weight + deq = layer.sdnq_dequantizer + Wdq = dq(layer) + deq2, data2 = sdnq_quantize_layer_weight(Wdq + D, layer_class_name='Linear', weights_dtype=deq.weights_dtype, + group_size=deq.group_size, hadamard_group_size=deq.hadamard_group_size, + use_hadamard=deq.use_hadamard, use_svd=False, use_quantized_matmul=False, + dequantize_fp32=False, torch_dtype=torch.bfloat16) + W2 = deq2(data2['weight'], data2['scale'], zero_point=data2['zero_point'], svd_up=None, svd_down=None, dtype=torch.float32, skip_compile=True) + return W2 - Wdq + + +# ============================================================ +# Tests - the erasure law (why the factor path exists) +# ============================================================ + +CAT_LAW = category('erasure-law') + + +def test_uint4_erases_substep_delta(): + layer = build_layer('uint4') + _A, _B, D = make_delta(sigma=2e-4) + rho = rho_of(requant_effective(layer, D), D) + group = layer.sdnq_dequantizer.group_size + floor = 2.0 / group + assert rho < 4 * floor, f'rho={rho:.4f} expected near extrema floor {floor:.4f}' + return True + + +def test_int8_retains_delta(): + layer = build_layer('int8') + _A, _B, D = make_delta(sigma=2e-4) + rho = rho_of(requant_effective(layer, D), D) + assert rho > 0.5, f'rho={rho:.4f} expected int8 to retain most of the delta' + return True + + +# ============================================================ +# Tests - factor path exactness +# ============================================================ + +CAT_FACTOR = category('factor-path') + + +def test_apply_exact_and_remove_bitexact(): + layer = build_layer('uint4') + A, B, D = make_delta() + net = make_net('one', layer, A, B) + l_common.loaded_networks.clear() + l_common.loaded_networks.append(net) + wanted = (('one', 1.0, 1.0, None),) + assert lora_sdnq.factor_candidate(layer, layer.network_layer_name, wanted) is True + Wdq0 = dq(layer) + assert lora_sdnq.apply_factors(layer, layer.network_layer_name, wanted) is True + rho = rho_of(dq(layer) - Wdq0, D) + assert rho > 0.99, f'rho={rho:.4f}' + assert lora_sdnq.remove_factors(layer) is True + assert torch.equal(dq(layer), Wdq0), 'remove must be bit-exact' + assert layer.svd_up is None and not hasattr(layer, 'sdnq_lora_svd_stash') + l_common.loaded_networks.clear() + return True + + +def test_multiplier_and_alpha_scaling(): + layer = build_layer('uint4') + A, B, D = make_delta() + net = make_net('one', layer, A, B, te_mult=0.5, alpha=RANK // 2) # alpha/rank = 0.5 + l_common.loaded_networks.clear() + l_common.loaded_networks.append(net) + Wdq0 = dq(layer) + lora_sdnq.apply_factors(layer, layer.network_layer_name, (('one', 0.5, 0.5, None),)) + rho = rho_of(dq(layer) - Wdq0, D) + assert abs(rho - 0.25) < 0.01, f'expected 0.5*0.5 scaling, rho={rho:.4f}' + lora_sdnq.remove_factors(layer) + l_common.loaded_networks.clear() + return True + + +def test_stacking_two_networks(): + layer = build_layer('uint4') + A1, B1, D1 = make_delta(seed=1) + A2, B2, D2 = make_delta(seed=2) + l_common.loaded_networks.clear() + l_common.loaded_networks.extend([make_net('a', layer, A1, B1), make_net('b', layer, A2, B2)]) + Wdq0 = dq(layer) + lora_sdnq.apply_factors(layer, layer.network_layer_name, (('a', 1.0, 1.0, None), ('b', 1.0, 1.0, None))) + rho = rho_of(dq(layer) - Wdq0, D1 + D2) + assert rho > 0.99, f'rho={rho:.4f}' + lora_sdnq.remove_factors(layer) + l_common.loaded_networks.clear() + return True + + +def test_matmul_layout_transposed(): + layer = build_layer('uint4', use_quantized_matmul=True) + A, B, D = make_delta() + l_common.loaded_networks.clear() + l_common.loaded_networks.append(make_net('one', layer, A, B)) + Wdq0 = dq(layer) + res = lora_sdnq.apply_factors(layer, layer.network_layer_name, (('one', 1.0, 1.0, None),)) + rho = rho_of(dq(layer) - Wdq0, D) + assert res is True and rho > 0.99, f'rho={rho:.4f}' + lora_sdnq.remove_factors(layer) + assert torch.equal(dq(layer), Wdq0) + l_common.loaded_networks.clear() + return True + + +def test_dora_falls_back(): + layer = build_layer('uint4') + A, B, _D = make_delta() + l_common.loaded_networks.clear() + l_common.loaded_networks.append(make_net('dora', layer, A, B, dora=True)) + assert lora_sdnq.factor_candidate(layer, layer.network_layer_name, (('dora', 1.0, 1.0, None),)) is False + l_common.loaded_networks.clear() + return True + + +def assert_factor_roundtrip(layer, tag): + """Apply-exact plus bit-exact removal on the given layer, whatever its quantization config.""" + A, B, D = make_delta() + Wdq0 = dq(layer) + orig_up = layer.svd_up + l_common.loaded_networks.clear() + l_common.loaded_networks.append(make_net('one', layer, A, B)) + wanted = (('one', 1.0, 1.0, None),) + assert lora_sdnq.factor_candidate(layer, layer.network_layer_name, wanted) is True, f'{tag}: not a factor candidate' + assert lora_sdnq.apply_factors(layer, layer.network_layer_name, wanted) is True, f'{tag}: apply failed' + E = dq(layer) - Wdq0 + rho = rho_of(E, D) + resid = float((E - D).norm() / D.norm()) + assert rho > 0.99 and resid < 0.2, f'{tag}: rho={rho:.4f} resid={resid:.4f}' + assert lora_sdnq.remove_factors(layer) and torch.equal(dq(layer), Wdq0), f'{tag}: remove not bit-exact' + assert layer.svd_up is orig_up, f'{tag}: original svd factors not restored' + l_common.loaded_networks.clear() + + +def test_no_hadamard_checkpoint(): + """Checkpoints quantized without hadamard: factors attach unrotated.""" + assert_factor_roundtrip(build_layer('uint4', use_hadamard=False), 'plain') + assert_factor_roundtrip(build_layer('uint4', use_hadamard=False, use_quantized_matmul=True), 'matmul') + return True + + +def test_checkpoint_svd_factors_preserved(): + """Checkpoints quantized with their own svd correction keep it under apply/remove.""" + layer = build_layer('uint4', use_svd=True) + assert layer.svd_up is not None, 'quantizer produced no svd correction' + assert_factor_roundtrip(layer, 'plain') + assert_factor_roundtrip(build_layer('uint4', use_svd=True, use_quantized_matmul=True), 'matmul') + return True + + +# ============================================================ +# Tests - memory accounting across apply modes +# ============================================================ + +CAT_MEM = category('memory') + + +def tensor_bytes(t): + return t.numel() * t.element_size() if isinstance(t, torch.Tensor) else 0 + + +def test_factor_path_memory_is_factors_only(): + """Factor path: no weight/quant-state backups; added memory = the factor tensors.""" + layer = build_layer('uint4') + A, B, _D = make_delta() + l_common.loaded_networks.clear() + l_common.loaded_networks.append(make_net('one', layer, A, B)) + lora_sdnq.apply_factors(layer, layer.network_layer_name, (('one', 1.0, 1.0, None),)) + assert getattr(layer, 'network_weights_backup', None) is None + assert not hasattr(layer, 'sdnq_dequantizer_backup') and not hasattr(layer, 'sdnq_scale_backup') + added = tensor_bytes(layer.svd_up) + tensor_bytes(layer.svd_down) + expected = RANK * (OUT_F + IN_F) * 2 # bf16 factors + assert added == expected, f'factor bytes {added} != expected {expected}' + would_be_backup = tensor_bytes(layer.weight) + tensor_bytes(layer.scale) + tensor_bytes(layer.zero_point) + assert added < would_be_backup / 4, f'factors {added}B should undercut the {would_be_backup}B backup this layer would otherwise clone' + lora_sdnq.remove_factors(layer) + assert layer.svd_up is None and layer.svd_down is None + l_common.loaded_networks.clear() + return True + + +def test_backup_mode_clones_full_quant_state(): + """Fallback in backup mode: packed weight + scale + zero_point are cloned to cpu.""" + from modules.lora.lora_apply import network_backup_weights + layer = build_layer('uint4') + A, B, _D = make_delta() + l_common.loaded_networks.clear() + l_common.loaded_networks.append(make_net('dora', layer, A, B, dora=True)) # non-factorable + reported = network_backup_weights(layer, layer.network_layer_name, (('dora', 1.0, 1.0, None),), fuse=False) + assert isinstance(layer.network_weights_backup, torch.Tensor) and layer.network_weights_backup.device.type == 'cpu' + assert hasattr(layer, 'sdnq_dequantizer_backup') and isinstance(layer.sdnq_scale_backup, torch.Tensor) + assert reported == tensor_bytes(layer.weight), f'reported {reported} != packed weight bytes {tensor_bytes(layer.weight)}' + total = reported + tensor_bytes(layer.sdnq_scale_backup) + tensor_bytes(layer.sdnq_zero_point_backup) + expected_min = OUT_F * IN_F // 2 # uint4 packs two weights per byte + assert total >= expected_min, f'backup {total}B below packed-weight floor {expected_min}B' + l_common.loaded_networks.clear() + return True + + +def test_fuse_mode_marker_takes_no_memory(): + """Fuse mode stores a boolean marker instead of tensors; guard forces backup on quantized models.""" + from modules.lora.lora_apply import network_backup_weights + from modules.lora import lora_overrides + layer = build_layer('uint4') + A, B, _D = make_delta() + l_common.loaded_networks.clear() + l_common.loaded_networks.append(make_net('dora', layer, A, B, dora=True)) + reported = network_backup_weights(layer, layer.network_layer_name, (('dora', 1.0, 1.0, None),), fuse=True) + assert layer.network_weights_backup is True and reported == 0 + assert not hasattr(layer, 'sdnq_dequantizer_backup') + + # the guard: a quantized component forces fuse off model-wide regardless of the option + class MockCfg: + quantization_config = {'quant_method': 'sdnq'} + class MockSd: + pass + sd = MockSd() + sd.transformer = torch.nn.Linear(4, 4) + sd.transformer.config = MockCfg() + from modules.modeldata import model_data + prev_model = model_data.sd_model + old_fuse = shared.opts.lora_fuse_native + try: + model_data.sd_model = sd + shared.opts.lora_fuse_native = True + assert lora_overrides.disable_fuse() is True + assert lora_overrides.fuse_native() is False + finally: + shared.opts.lora_fuse_native = old_fuse + model_data.sd_model = prev_model + l_common.loaded_networks.clear() + return True + + +# ============================================================ +# Tests - integration through networks.network_activate +# ============================================================ + +CAT_E2E = category('activate-e2e') + + +class MockHolder(torch.nn.Module): + @property + def device(self): + return DEVICE + + +@contextmanager +def mock_model(**layers): + """Install a one-component mock pipeline holding the given layers as shared.sd_model.""" + class MockPipe: + pass + class MockSd: + pass + holder = MockHolder() + for attr, lyr in layers.items(): + setattr(holder, attr, lyr) + pipe = MockPipe() + pipe.transformer = holder + sd = MockSd() + sd.pipe = pipe + from modules.modeldata import model_data + model_data.sd_model = sd + real_offload = sd_models.set_diffuser_offload + sd_models.set_diffuser_offload = lambda *a, **k: None + old_fuse = shared.opts.lora_fuse_native + shared.opts.lora_fuse_native = False # a real quantized model forces backup mode; the mock carries no quantization config, so pin it instead of inheriting the running config + try: + yield + finally: + shared.opts.lora_fuse_native = old_fuse + sd_models.set_diffuser_offload = real_offload + l_common.loaded_networks.clear() + l_common.previously_loaded_networks.clear() + + +def activate(*nets): + l_common.loaded_networks.clear() + l_common.loaded_networks.extend(nets) + networks.network_activate() + + +def test_network_activate_roundtrip(): + layer = build_layer('uint4') + A, B, D = make_delta() + net = make_net('one', layer, A, B) + + with mock_model(lin=layer): + Wdq0 = dq(layer) + activate(net) + rho = rho_of(dq(layer) - Wdq0, D) + assert rho > 0.99, f'rho={rho:.4f}' + assert getattr(layer, 'network_weights_backup', None) is None, 'factor path must not take weight backups' + + activate() # restore pass + assert torch.equal(dq(layer), Wdq0), 'unload must restore bit-exact' + + # fuse-mode deactivate route + layer.network_current_names = () + activate(net) + l_common.previously_loaded_networks[:] = l_common.loaded_networks + shared.opts.lora_fuse_native = True + networks.network_deactivate() + assert torch.equal(dq(layer), Wdq0), 'fuse-mode deactivate must restore bit-exact' + return True + + +# ============================================================ +# Tests - multi-LoRA set transitions between the two paths +# ============================================================ + +CAT_TRANS = category('transitions') + + +def test_mixed_family_transition_restores_base(): + layer = build_layer('uint4') + bystander = build_layer('uint4', seed=7) + bystander.network_layer_name = 'lora_transformer_bystander' + A, B, D = make_delta() + net_plain = make_net('plain', layer, A, B) + A2, B2, _ = make_delta(seed=5, sigma=3e-3) + net_dora = make_net('doranet', layer, A2, B2, dora=True) + + noted = [] + real_report = lora_sdnq.report_fallbacks + def capture_report(): + noted.append(len(lora_sdnq.fallback_layers)) + real_report() + lora_sdnq.report_fallbacks = capture_report + try: + with host_rank(0), mock_model(lin=layer, bystander=bystander): # pins the requantize fallback; hosted transitions are covered in the hosting category + Wdq0 = dq(layer) + activate(net_plain) + assert hasattr(layer, 'sdnq_lora_svd_stash'), 'plain set must take the factor path' + assert noted[-1] == 0, f'untargeted quantized layers must not be flagged as requantized: noted={noted[-1]}' + + activate(net_plain, net_dora) + assert not hasattr(layer, 'sdnq_lora_svd_stash') and isinstance(layer.network_weights_backup, torch.Tensor), 'mixed set must fall back with a tensor backup' + assert not torch.equal(dq(layer), Wdq0), 'fallback must have requantized the weights' + assert noted[-1] == 1, f'exactly the requantized layer must be flagged: noted={noted[-1]}' + + activate(net_plain) + assert hasattr(layer, 'sdnq_lora_svd_stash'), 'plain-only set must re-enter the factor path' + rho = rho_of(dq(layer) - Wdq0, D) + assert rho > 0.99, f'rho={rho:.4f}' + stash, up, down = layer.sdnq_lora_svd_stash, layer.svd_up, layer.svd_down + lora_sdnq.remove_factors(layer) + base_clean = torch.equal(dq(layer), Wdq0) + layer.sdnq_lora_svd_stash, layer.svd_up, layer.svd_down = stash, up, down + assert base_clean, 'base under factors must be restored from backup on mixed-set exit' + + activate() + assert torch.equal(dq(layer), Wdq0), 'unload must return bit-exact pristine' + finally: + lora_sdnq.report_fallbacks = real_report + return True + + +def test_partial_coverage_layers_stay_independent(): + layer_plain = build_layer('uint4') + layer_dora = build_layer('uint4', seed=7) + layer_dora.network_layer_name = 'lora_transformer_other' + A, B, D = make_delta() + net_plain = make_net('plain', layer_plain, A, B) + A2, B2, _ = make_delta(seed=5, sigma=3e-3) + net_dora = make_net('dorafar', layer_dora, A2, B2, dora=True) + + with host_rank(0), mock_model(lin=layer_plain, other=layer_dora): # pins the requantize fallback for the non-factorable layer + Wdq0, Wdq0_dora = dq(layer_plain), dq(layer_dora) + activate(net_plain, net_dora) + assert hasattr(layer_plain, 'sdnq_lora_svd_stash') and getattr(layer_plain, 'network_weights_backup', None) is None, 'plain layer must stay on the factor path' + assert isinstance(getattr(layer_dora, 'network_weights_backup', None), torch.Tensor), 'dora layer must take the backup fallback' + rho = rho_of(dq(layer_plain) - Wdq0, D) + assert rho > 0.99, f'rho={rho:.4f}' + activate() + assert torch.equal(dq(layer_plain), Wdq0), 'factor layer must restore bit-exact' + assert torch.equal(dq(layer_dora), Wdq0_dora), 'fallback layer must restore bit-exact' + return True + + +def test_apply_restore_preserves_weight_storage(): + """Apply and restore write into the existing parameter storage: kernel selection is + placement-sensitive, so a swapped-in Parameter shifts deterministic outputs bitwise.""" + lin = torch.nn.Linear(IN_F, OUT_F, bias=True, dtype=torch.bfloat16, device=DEVICE) + with torch.no_grad(): + lin.weight.copy_(torch.randn(OUT_F, IN_F, device=DEVICE) * 0.02) + lin.bias.copy_(torch.randn(OUT_F, device=DEVICE) * 0.01) + lin.network_layer_name = 'lora_transformer_storage' + lin.network_current_names = () + W0 = lin.weight.detach().clone() + B0 = lin.bias.detach().clone() + wptr, bptr = lin.weight.data_ptr(), lin.bias.data_ptr() + A, B, _D = make_delta(seed=91, sigma=1e-2) + net = make_net('storage', lin, A, B) + with mock_model(lin=lin): + activate(net) + assert not torch.equal(lin.weight.detach(), W0), 'apply must change the weight' + assert lin.weight.data_ptr() == wptr, 'apply must write into the existing weight storage' + assert lin.bias.data_ptr() == bptr, 'apply must keep the bias storage' + activate() + assert torch.equal(lin.weight.detach(), W0), 'restore must be bit-exact' + assert torch.equal(lin.bias.detach(), B0), 'restore must be bit-exact on bias' + assert lin.weight.data_ptr() == wptr, 'restore must write into the existing weight storage' + assert lin.bias.data_ptr() == bptr, 'restore must write into the existing bias storage' + return True + + +def fuse_fixture(te0): + """A plain bf16 Linear (unquantized, so fuse stays allowed) with one attached net at strength te0.""" + lin = torch.nn.Linear(IN_F, OUT_F, bias=False, dtype=torch.bfloat16, device=DEVICE) + with torch.no_grad(): + lin.weight.copy_(torch.randn(OUT_F, IN_F, device=DEVICE) * 0.02) + lin.network_layer_name = 'lora_transformer_fusefix' + lin.network_current_names = () + A, B, D = make_delta(seed=17, sigma=1e-2) + net = make_net('fusefix', lin, A, B, te_mult=te0) + return lin, net, D + + +def edit_strength(net, te): + """The production order for a strength edit: network_load stages the new values on the + shared net object, deactivate runs against the applied ones, activate promotes.""" + l_common.previously_loaded_networks[:] = l_common.loaded_networks + net.pending_config = {'te': te, 'unet': [te] * 3, 'dyn': None} + networks.network_deactivate() + networks.network_activate() + + +def test_fuse_promote_applies_new_multiplier(): + """Fuse removal subtracts a recomputed delta, so the multipliers it reads must be the + applied ones: staged values promote only in network_activate, after the removal pass.""" + lin, net, D = fuse_fixture(te0=0.5) + with mock_model(lin=lin): + shared.opts.lora_fuse_native = True + W0 = lin.weight.detach().float().clone() + activate(net) + assert isinstance(getattr(lin, 'network_weights_backup', None), bool), 'fuse mode must not take a tensor backup' + rho0 = rho_of(lin.weight.detach().float() - W0, D) + assert abs(rho0 - 0.5) < 0.05, f'rho={rho0:.3f} expected the initial strength' + edit_strength(net, 1.0) + assert net.te_multiplier == 1.0, 'activate must promote the staged multiplier' + rho1 = rho_of(lin.weight.detach().float() - W0, D) + assert abs(rho1 - 1.0) < 0.05, f'rho={rho1:.3f} expected the edited strength to apply, not the first one' + return True + + +def test_fuse_change_then_remove_restores_pristine(): + """Apply, edit, remove: the final subtraction must use the strength that was applied. + Pins the promote-after-deactivate ordering; a promote that runs before the removal + pass leaves half the delta baked into the weights.""" + lin, net, D = fuse_fixture(te0=0.5) + with mock_model(lin=lin): + shared.opts.lora_fuse_native = True + W0 = lin.weight.detach().float().clone() + activate(net) + edit_strength(net, 1.0) + l_common.previously_loaded_networks[:] = l_common.loaded_networks + l_common.loaded_networks.clear() + networks.network_deactivate() + networks.network_activate() + resid = lin.weight.detach().float() - W0 + rho2 = rho_of(resid, D) + assert abs(rho2) < 0.05, f'rho={rho2:.3f} removal must subtract the strength that was applied' + assert float(resid.abs().max()) < 2e-3, f'max={float(resid.abs().max()):.2e} removal must leave only rounding residue' + return True + + +@contextmanager +def apply_method(value): + old = getattr(shared.opts, 'lora_sdnq_apply', 'exact') + shared.opts.lora_sdnq_apply = value + try: + yield + finally: + shared.opts.lora_sdnq_apply = old + + +def test_mechanism_gate_declines_candidates(): + """The requantize option must gate every svd-channel entry point and flip the apply-stamp token.""" + layer = build_layer('uint4') + A, B, _D = make_delta() + l_common.loaded_networks.clear() + l_common.loaded_networks.append(make_net('one', layer, A, B)) + wanted = (('one', 1.0, 1.0, None),) + try: + assert lora_sdnq.factor_candidate(layer, layer.network_layer_name, wanted) + with host_rank(64): + assert lora_sdnq.select_candidate(layer, layer.network_layer_name, wanted) + assert lora_sdnq.signature() == '' + with apply_method('requantize'): + assert not lora_sdnq.factor_candidate(layer, layer.network_layer_name, wanted) + with host_rank(64): + assert not lora_sdnq.select_candidate(layer, layer.network_layer_name, wanted) + assert not lora_sdnq.host_candidate(layer, layer.network_layer_name, wanted) + assert lora_sdnq.signature() == '|quant=requantize' + finally: + l_common.loaded_networks.clear() + return True + + +def test_requantize_option_routes_to_legacy_path(): + """With the option set, a factorable set must take the classic backup-and-requantize path end to end.""" + layer = build_layer('uint4') + A, B, _D = make_delta(sigma=3e-3) + net = make_net('one', layer, A, B) + with apply_method('requantize'), mock_model(lin=layer): + shared.opts.lora_fuse_native = False # a real quantized model forces backup mode; the mock carries no quantization config + Wdq0 = dq(layer) + activate(net) + assert not hasattr(layer, 'sdnq_lora_svd_stash'), 'legacy path must not touch the svd channel' + assert layer.svd_up is None, 'legacy path must leave the channel empty' + assert isinstance(layer.network_weights_backup, torch.Tensor), 'legacy path must take a tensor backup' + assert not torch.equal(dq(layer), Wdq0), 'legacy path must requantize the weights' + activate() + assert torch.equal(dq(layer), Wdq0), 'legacy restore must be bit-exact from backup' + return True + + +def test_mechanism_flip_strips_attached_factors(): + """Flipping to requantize with factors attached must strip them before the weight path takes the layer; flipping back must re-enter the factor path.""" + layer = build_layer('uint4') + A, B, _D = make_delta(sigma=3e-3) + net = make_net('one', layer, A, B) + with mock_model(lin=layer): + shared.opts.lora_fuse_native = False # a real quantized model forces backup mode; the mock carries no quantization config + Wdq0 = dq(layer) + activate(net) + assert hasattr(layer, 'sdnq_lora_svd_stash'), 'default mechanism must take the factor path' + E_exact = dq(layer) - Wdq0 + with apply_method('requantize'): + activate(net) # same set; the mechanism token in the apply stamp must force re-processing + assert not hasattr(layer, 'sdnq_lora_svd_stash'), 'flip must strip the attached factors' + assert layer.svd_up is None, 'stripped channel must be empty, or the requantized delta double-applies' + assert isinstance(layer.network_weights_backup, torch.Tensor), 'flipped layer must continue on the backup path' + activate(net) # flip back within the same loaded set + assert hasattr(layer, 'sdnq_lora_svd_stash'), 'flip back must re-enter the factor path' + assert torch.equal(dq(layer) - Wdq0, E_exact), 'exact re-apply must restore the base from backup before attaching' + activate() + assert torch.equal(dq(layer), Wdq0), 'unload must return bit-exact pristine' + return True + + +def test_mechanism_flip_restore_pass_strips(): + """A restore-only pass under the requantize option must still drop attached factors.""" + layer = build_layer('uint4') + A, B, _D = make_delta(sigma=3e-3) + net = make_net('one', layer, A, B) + with mock_model(lin=layer): + Wdq0 = dq(layer) + activate(net) + assert hasattr(layer, 'sdnq_lora_svd_stash') + with apply_method('requantize'): + activate() # unload with the gate closed: the fallthrough strip is the only removal route + assert not hasattr(layer, 'sdnq_lora_svd_stash'), 'restore pass must strip the factors' + assert torch.equal(dq(layer), Wdq0), 'strip must restore bit-exact' + assert layer.network_current_names == (), 'stripped layer must be stamped restored' + return True + + +CAT_HOST = category('hosting') + + +@contextmanager +def host_rank(rank): + old = getattr(shared.opts, 'lora_sdnq_host_rank', 0) + shared.opts.lora_sdnq_host_rank = rank + try: + yield + finally: + shared.opts.lora_sdnq_host_rank = old + + +def make_dense_net(name, layer, D): + """A full-family (dense diff) network module: non-factorable by construction.""" + from modules.lora import network_full + net = network.Network(name, MockNOD(name)) + net.te_multiplier = 1.0 + net.unet_multiplier = [1.0] * 3 + nw = network.NetworkWeights(network_key=layer.network_layer_name, sd_key=layer.network_layer_name, + w={'diff': D.cpu()}, sd_module=layer) + net.modules[layer.network_layer_name] = network_full.NetworkModuleFull(net, nw) + return net + + +def test_hosted_low_rank_delta_is_kept(): + layer = build_layer('uint4') + _A, _B, D = make_delta(sigma=3e-3) + net = make_dense_net('densenet', layer, D) # low-rank content in a non-factorable container + with host_rank(64), mock_model(lin=layer): + Wdq0 = dq(layer) + activate(net) + assert hasattr(layer, 'sdnq_lora_svd_stash'), 'hosted set must ride the side-channel' + assert getattr(layer, 'network_weights_backup', None) is None, 'hosted layers must not take a weight backup' + rho = rho_of(dq(layer) - Wdq0, D) + assert rho > 0.95, f'rank-8 delta under cap 64 must be kept nearly whole: rho={rho:.4f}' + activate() + assert torch.equal(dq(layer), Wdq0), 'unload must restore bit-exact' + return True + + +def test_hosted_dense_delta_beats_requant(): + layer = build_layer('uint4') + torch.manual_seed(3) + D = torch.randn(OUT_F, IN_F, device=DEVICE) * 3e-4 # full-rank, sub-step: requant erases it + requant_rho = rho_of(requant_effective(layer, D), D) + net = make_dense_net('densefull', layer, D) + with host_rank(256), mock_model(lin=layer): + Wdq0 = dq(layer) + activate(net) + hosted_rho = rho_of(dq(layer) - Wdq0, D) + assert hosted_rho > 0.4, f'hosted rho={hosted_rho:.3f}' + assert hosted_rho > requant_rho + 0.3, f'hosting must beat requant by a wide margin: {hosted_rho:.3f} vs {requant_rho:.3f}' + activate() + assert torch.equal(dq(layer), Wdq0) + return True + + +def test_hosted_null_tail_collapses_to_effective_rank(): + layer = build_layer('uint4') + _A, _B, D = make_delta(sigma=3e-3) # exact rank-8 content in a non-factorable container + net = make_dense_net('nulltail', layer, D) + with host_rank(256), mock_model(lin=layer): + Wdq0 = dq(layer) + activate(net) + assert layer.svd_up.shape[1] == 8, f'rank-8 delta under cap 256 must store 8 ranks, got {layer.svd_up.shape[1]}' + assert layer.svd_down.shape[0] == 8, f'down factor must slice with the up factor, got {layer.svd_down.shape[0]}' + rho = rho_of(dq(layer) - Wdq0, D) + assert rho > 0.95, f'collapsing the null tail must not cost fidelity: rho={rho:.4f}' + activate() + assert torch.equal(dq(layer), Wdq0), 'unload must restore bit-exact' + return True + + +def test_hosted_flat_spectrum_keeps_cap(): + layer = build_layer('uint4') + torch.manual_seed(13) + D = torch.randn(OUT_F, IN_F, device=DEVICE) * 3e-4 # full-rank gaussian: no null tail inside the cap + net = make_dense_net('flattail', layer, D) + with host_rank(64), mock_model(lin=layer): + activate(net) + assert layer.svd_up.shape[1] == 64, f'a flat spectrum must keep the full cap, got {layer.svd_up.shape[1]}' + activate() + return True + + +def test_hosted_skips_int8(): + layer = build_layer('int8') + _A, _B, D = make_delta(sigma=3e-3) + net = make_dense_net('int8net', layer, D) + with host_rank(256), mock_model(lin=layer): + activate(net) + assert not hasattr(layer, 'sdnq_lora_svd_stash'), 'int8 must keep the requantize path' + assert isinstance(getattr(layer, 'network_weights_backup', None), torch.Tensor), 'int8 fallback must take the backup' + activate() + return True + + +def test_hosted_disabled_by_option(): + layer = build_layer('uint4') + _A, _B, D = make_delta(sigma=3e-3) + net = make_dense_net('offnet', layer, D) + with host_rank(0), mock_model(lin=layer): + activate(net) + assert not hasattr(layer, 'sdnq_lora_svd_stash'), 'rank 0 must disable hosting' + activate() + return True + + +def test_hosted_transitions_and_rng_isolation(): + layer = build_layer('uint4') + A, B, D = make_delta() + net_plain = make_net('plainh', layer, A, B) + _A2, _B2, D2 = make_delta(seed=9, sigma=3e-3) + net_dense = make_dense_net('denseh', layer, D2) + with host_rank(256), mock_model(lin=layer): + Wdq0 = dq(layer) + rng0 = torch.cuda.get_rng_state() if DEVICE.type == 'cuda' else torch.get_rng_state() + activate(net_dense) # hosted + rng1 = torch.cuda.get_rng_state() if DEVICE.type == 'cuda' else torch.get_rng_state() + assert torch.equal(rng0, rng1), 'hosting must not consume the generation rng stream' + assert hasattr(layer, 'sdnq_lora_svd_stash') + activate(net_plain) # exact replaces hosted + rho = rho_of(dq(layer) - Wdq0, D) + assert rho > 0.99, f'exact set after hosted set: rho={rho:.4f}' + activate(net_plain, net_dense) # mixed set hosts the combined delta + rho_mix = rho_of(dq(layer) - Wdq0, D + D2) + assert rho_mix > 0.9, f'mixed hosted rho={rho_mix:.4f}' + activate() + assert torch.equal(dq(layer), Wdq0), 'unload must restore bit-exact' + return True + + +@contextmanager +def requant_rule(ratio, energy): + old_r, old_e = lora_sdnq.REQUANT_RATIO, lora_sdnq.REQUANT_ENERGY + lora_sdnq.REQUANT_RATIO, lora_sdnq.REQUANT_ENERGY = ratio, energy + try: + yield + finally: + lora_sdnq.REQUANT_RATIO, lora_sdnq.REQUANT_ENERGY = old_r, old_e + + +def test_route_fat_dense_delta_requantizes(): + layer = build_layer('uint4') + torch.manual_seed(21) + D = torch.randn(OUT_F, IN_F, device=DEVICE) * 1e-2 # full-rank and well above the grid step: the grid retains it, truncation would cut it + net = make_dense_net('fatnet', layer, D) + with host_rank(256), mock_model(lin=layer): + Wdq0 = dq(layer) + activate(net) + assert not hasattr(layer, 'sdnq_lora_svd_stash'), 'a fat full-rank delta must route to requantize' + assert isinstance(getattr(layer, 'network_weights_backup', None), torch.Tensor), 'the routed layer takes the requantize backup' + rho = rho_of(dq(layer) - Wdq0, D) + assert rho > 0.7, f'the grid must retain the routed delta: rho={rho:.3f}' + activate() + assert torch.equal(dq(layer), Wdq0), 'restore from backup must be bit-exact' + return True + + +def test_declined_host_delta_is_not_recomputed(): + layer = build_layer('uint4') + torch.manual_seed(21) + D = torch.randn(OUT_F, IN_F, device=DEVICE) * 1e-2 # fat and full-rank: hosting assembles the delta and then routes it to the grid + net = make_dense_net('recompute', layer, D) + with host_rank(256), mock_model(lin=layer), counting_calc() as calls: + activate(net) + assert not hasattr(layer, 'sdnq_lora_svd_stash'), 'the fixture must reach the weight path, not the side channel' + assert calls['n'] == 1, f'a declined host hands its delta on instead of assembling it twice, got {calls["n"]}' + return True + + +def test_pass_presents_one_wanted_names_tuple(): + from modules.lora import lora_factor_cache as fc + layer = build_layer('uint4') + _A, _B, D = make_delta(sigma=3e-3) + net = make_dense_net('identity', layer, D) + seen = [] # holds the objects, so a freed tuple cannot lend its address to the next one + real = fc.begin_pass + + def recording(wanted_names): + seen.append(wanted_names) + return real(wanted_names) + + fc.begin_pass = recording + try: + with host_rank(64), mock_model(lin=layer): + activate(net) + finally: + fc.begin_pass = real + assert len(seen) >= 2, f'the hosted path must consult the cache more than once for this to prove anything, got {len(seen)}' + assert all(x is seen[0] for x in seen), 'one walk must present one tuple: the cache memoizes its entry on identity, and an equal rebuild rereads it from disk' + return True + + +def test_route_rule_terms_gate_both_ways(): + layer = build_layer('uint4') + torch.manual_seed(23) + D = torch.randn(OUT_F, IN_F, device=DEVICE) * 1e-2 # sr about 0.8, capture about 0.8 at cap 256: each term alone can hold it hosted + net = make_dense_net('gatenet', layer, D) + with host_rank(256), mock_model(lin=layer): + with requant_rule(ratio=10.0, energy=0.90): + activate(net) + assert hasattr(layer, 'sdnq_lora_svd_stash'), 'sr below the ratio must host regardless of capture' + activate() + with requant_rule(ratio=0.30, energy=0.0): + activate(net) + assert hasattr(layer, 'sdnq_lora_svd_stash'), 'capture above the energy floor must host regardless of sr' + activate() + with requant_rule(ratio=0.30, energy=0.90): + activate(net) + assert not hasattr(layer, 'sdnq_lora_svd_stash'), 'both terms crossed must requantize' + activate() + return True + + +def test_route_codebook_layer_uses_level_gap(): + layer = build_layer('uint4', use_codebook=True) + scale = layer.scale.detach().float() + assert layer.sdnq_dequantizer.use_codebook and scale.shape[-1] == 16, f'the fixture must keep its lloyd levels in the scale slot, got {tuple(scale.shape)}' + step = lora_sdnq.grid_step(layer) + gap = float(scale.diff(dim=-1).mean()) + assert step > 0 and abs(step - gap) <= 1e-6 * gap, f'a codebook layer routes on the mean adjacent-level gap: step={step:.3e} gap={gap:.3e}' + affine = lora_sdnq.grid_step(build_layer('uint4')) + assert 0.5 < step / affine < 2.0, f'codebook and affine steps on the same weights must agree in magnitude: cb={step:.3e} affine={affine:.3e}' + torch.manual_seed(31) + D = torch.randn(OUT_F, IN_F, device=DEVICE) * 3e-3 # dense and below the true step: hosted on the affine fixture, while the level mean misreads it as fat and requantizes it away + net = make_dense_net('cbmid', layer, D) + with host_rank(256), mock_model(lin=layer): + Wdq0 = dq(layer) + activate(net) + assert hasattr(layer, 'sdnq_lora_svd_stash'), 'a sub-step dense delta must stay hosted on a codebook layer' + rho = rho_of(dq(layer) - Wdq0, D) + assert rho > 0.7, f'hosting must retain the sub-step delta the grid would erase: rho={rho:.3f}' + activate() + assert torch.equal(dq(layer), Wdq0), 'removing the hosted set must restore the codebook layer bit-exactly' + return True + + +def test_route_low_rank_fat_delta_stays_hosted(): + layer = build_layer('uint4') + _A, _B, D = make_delta(seed=22, sigma=3e-3) # rank-8: fat against the grid, exact under the cap + net = make_dense_net('fatlow', layer, D) + with host_rank(64), mock_model(lin=layer): + Wdq0 = dq(layer) + activate(net) + assert hasattr(layer, 'sdnq_lora_svd_stash'), 'a low-rank delta hosts exactly at any magnitude' + rho = rho_of(dq(layer) - Wdq0, D) + assert rho > 0.95, f'rho={rho:.4f}' + activate() + return True + + +def test_route_mixed_set_keeps_hosting(): + layer = build_layer('uint4') + A, B, _D1 = make_delta(seed=24) + torch.manual_seed(25) + D2 = torch.randn(OUT_F, IN_F, device=DEVICE) * 1e-2 + net1 = make_net('mixp', layer, A, B) + net2 = make_dense_net('mixf', layer, D2) + with host_rank(256), mock_model(lin=layer): + Wdq0 = dq(layer) + activate(net1, net2) + assert hasattr(layer, 'sdnq_lora_svd_stash'), 'a set with factorable members keeps the side-channel' + activate() + assert torch.equal(dq(layer), Wdq0) + return True + + +def test_route_svd_checkpoint_keeps_hosting(): + layer = build_layer('uint4', use_svd=True) + torch.manual_seed(26) + D = torch.randn(OUT_F, IN_F, device=DEVICE) * 1e-2 + net = make_dense_net('svdfat', layer, D) + with host_rank(256), mock_model(lin=layer): + activate(net) + assert hasattr(layer, 'sdnq_lora_svd_stash'), 'svd checkpoints keep hosting; the rule is not grounded there' + activate() + return True + + +def test_route_dense_stack_keeps_hosting(): + layer = build_layer('uint4') + torch.manual_seed(27) + D1 = torch.randn(OUT_F, IN_F, device=DEVICE) * 1e-2 + D2 = torch.randn(OUT_F, IN_F, device=DEVICE) * 1e-2 + net1, net2 = make_dense_net('df1', layer, D1), make_dense_net('df2', layer, D2) + with host_rank(256), stack_mode('ties'), mock_model(lin=layer): + activate(net1, net2) + assert hasattr(layer, 'sdnq_lora_svd_stash'), 'dense-combined deltas host at any magnitude' + activate() + return True + + +def test_route_replay_from_cache(): + import tempfile + layer = build_layer('uint4') + with tempfile.TemporaryDirectory() as tmp: + with host_rank(256), host_cache(10, os.path.join(tmp, 'cache')), mock_model(lin=layer): + net, _D = cache_fixture(tmp, layer, name='fatcache', sigma=1e-2, seed=28) + activate(net) + assert not hasattr(layer, 'sdnq_lora_svd_stash'), 'fat delta must route on the fresh-sketch path' + activate() + real_svd = torch.svd_lowrank + torch.svd_lowrank = raise_no_svd + try: + activate(net) # the stored entry memoizes the routing: same decision, no sketch + finally: + torch.svd_lowrank = real_svd + assert not hasattr(layer, 'sdnq_lora_svd_stash'), 'cache replay must route the same way' + activate() + return True + + +CAT_CALIB = category('calibration') + + +@contextmanager +def host_calib(value): + old = getattr(shared.opts, 'lora_sdnq_host_calib', False) + shared.opts.lora_sdnq_host_calib = value + try: + yield + finally: + shared.opts.lora_sdnq_host_calib = old + + +def test_calibrated_hosting_beats_plain(): + layer = build_layer('uint4') + torch.manual_seed(11) + scale = torch.ones(IN_F, device=DEVICE) + scale[:32] = 40.0 # a few loud input channels, the shape real activations have + D = torch.randn(OUT_F, IN_F, device=DEVICE) * 3e-4 + X = torch.randn(1024, IN_F, device=DEVICE) * scale + Y = X @ D.t() + net = make_dense_net('calnet', layer, D) + + def out_rho(E): + return float((X @ E.t()).flatten() @ Y.flatten() / Y.square().sum()) + + with host_rank(32), host_calib(True), mock_model(lin=layer): + Wdq0 = dq(layer) + activate(net) + plain = out_rho(dq(layer) - Wdq0) + activate() + layer.sdnq_calib_rms = scale.cpu() # statistics as the capture leaves them + activate(net) + weighted = out_rho(dq(layer) - Wdq0) + activate() + del layer.sdnq_calib_rms + assert torch.equal(dq(layer), Wdq0), 'unload must restore bit-exact' + assert weighted > plain + 0.2, f'calibrated hosting must beat plain in output space: {weighted:.3f} vs {plain:.3f}' + return True + + +def test_calibrated_low_rank_delta_survives(): + layer = build_layer('uint4') + _A, _B, D = make_delta(sigma=3e-3) + net = make_dense_net('calfull', layer, D) + with host_rank(64), host_calib(True), mock_model(lin=layer): + Wdq0 = dq(layer) + torch.manual_seed(21) + layer.sdnq_calib_rms = torch.rand(IN_F) * 10 + 0.1 # arbitrary positive statistics: unscale must round-trip + activate(net) + rho = rho_of(dq(layer) - Wdq0, D) + activate() + del layer.sdnq_calib_rms + assert rho > 0.95, f'rank-8 delta under weighted cap 64 must be kept nearly whole: rho={rho:.4f}' + assert torch.equal(dq(layer), Wdq0) + return True + + +def test_calib_option_off_matches_plain(): + layer = build_layer('uint4') + torch.manual_seed(31) + D = torch.randn(OUT_F, IN_F, device=DEVICE) * 3e-4 + net = make_dense_net('caloff', layer, D) + with host_rank(64), mock_model(lin=layer): + Wdq0 = dq(layer) + with host_calib(False): + layer.sdnq_calib_rms = torch.rand(IN_F) + 0.5 + activate(net) + off = dq(layer) + activate() + del layer.sdnq_calib_rms + with host_calib(True): + activate(net) # no statistics attribute: plain truncation + plain = dq(layer) + activate() + assert torch.equal(off, plain), 'option off must reproduce the uncalibrated truncation bit-exact' + assert torch.equal(dq(layer), Wdq0) + return True + + +class MockCheckpointInfo: + def __init__(self, name): + self.name = name + + +class MockCalibSd: + def __init__(self, name, **layers): + self.transformer = MockHolder() + for attr, lyr in layers.items(): + setattr(self.transformer, attr, lyr) + self.sd_checkpoint_info = MockCheckpointInfo(name) + + +def test_calib_capture_persist_roundtrip(): + import tempfile + from modules.lora import lora_calib + layer_a = build_layer('uint4', seed=41) + layer_b = build_layer('uint4', seed=42) + sd = MockCalibSd('test/calib-model', la=layer_a, lb=layer_b) + old_root, old_tokens = lora_calib.calib_root, lora_calib.TOKENS_DONE + with tempfile.TemporaryDirectory() as tmp, host_calib(True): + try: + lora_calib.calib_root = tmp + lora_calib.TOKENS_DONE = 2048 + lora_calib.on_model_loaded(sd) + assert len(lora_calib.capture['handles']) == 3, 'both sub-8-bit linears plus the root forward counter must hook' + torch.manual_seed(51) + scale = torch.linspace(0.1, 4.0, IN_F, device=DEVICE) + xs = [] + for _ in range(2): # exactly the completion threshold, so statistics cover every forward + x = (torch.randn(1024, IN_F, device=DEVICE) * scale).to(torch.bfloat16) + xs.append(x.float()) + layer_a(x) + layer_b(x) + assert lora_calib.capture['complete'], 'capture must complete once enough tokens are seen' + path = lora_calib.calib_file('test/calib-model') + assert os.path.isfile(path), f'statistics must persist to {path}' + expected = torch.cat(xs).square().mean(dim=0).sqrt().cpu() + assert torch.allclose(layer_a.sdnq_calib_rms, expected, rtol=1e-3, atol=1e-5), 'streamed rms must match the seen activations' + del layer_a.sdnq_calib_rms, layer_b.sdnq_calib_rms + lora_calib.on_model_loaded(sd) # second load takes the cached path + assert len(lora_calib.capture['handles']) == 0, 'cached statistics must not re-attach capture hooks' + assert torch.allclose(layer_a.sdnq_calib_rms, expected, rtol=1e-3, atol=1e-5), 'reload must restore the persisted rms' + del layer_a.sdnq_calib_rms, layer_b.sdnq_calib_rms + finally: + lora_calib.calib_root, lora_calib.TOKENS_DONE = old_root, old_tokens + lora_calib.detach_capture() + return True + + +def test_calib_capture_gates(): + from modules.lora import lora_calib + sd_int8 = MockCalibSd('test/calib-int8', lin=build_layer('int8', seed=43)) + with host_calib(True): + lora_calib.on_model_loaded(sd_int8) + assert len(lora_calib.capture['handles']) == 0, 'int8-only models have nothing to calibrate' + sd_u4 = MockCalibSd('test/calib-gates', lin=build_layer('uint4', seed=44)) + with host_calib(False): + lora_calib.on_model_loaded(sd_u4) + assert len(lora_calib.capture['handles']) == 0, 'option off must disable capture' + old_compile = getattr(shared.opts, 'cuda_compile', None) + with host_calib(True): + shared.opts.cuda_compile = ['Model'] + try: + lora_calib.on_model_loaded(sd_u4) + assert len(lora_calib.capture['handles']) == 0, 'model compile must disable capture' + finally: + shared.opts.cuda_compile = old_compile + lora_calib.detach_capture() + return True + + +class MockCalibDenoiser(torch.nn.Module): + """Denoiser whose forward feeds one token-rich linear and one token-starved one, like a DiT block beside its modulation projection.""" + def __init__(self, rich, starved, starved_tokens): + super().__init__() + self.rich = rich + self.starved = starved + self.starved_tokens = starved_tokens + + def forward(self, x): + self.rich(x) + self.starved(x[:self.starved_tokens]) + return x + + +def test_calib_deadline_persists_starved_layers(): + import tempfile + from safetensors import safe_open + from modules.lora import lora_calib + rich = build_layer('uint4', seed=45) + starved = build_layer('uint4', seed=46) + root = MockCalibDenoiser(rich, starved, starved_tokens=8) + sd = MockCalibSd('test/calib-deadline') + sd.transformer = root + old = (lora_calib.calib_root, lora_calib.TOKENS_DONE, lora_calib.FORWARDS_DEADLINE) + with tempfile.TemporaryDirectory() as tmp, host_calib(True): + try: + lora_calib.calib_root = tmp + lora_calib.TOKENS_DONE = 2048 + lora_calib.FORWARDS_DEADLINE = 6 + lora_calib.on_model_loaded(sd) + assert len(lora_calib.capture['handles']) == 3, 'two layer hooks plus the root forward counter must attach' + torch.manual_seed(52) + xs = [] + for i in range(6): + x = torch.randn(1024, IN_F, device=DEVICE).to(torch.bfloat16) + if i < 5: # the deadline fires at the start of the sixth forward, before its layer hooks run + xs.append(x[:8].float()) + root(x) + assert lora_calib.capture['complete'], 'the forward deadline must close capture' + assert lora_calib.capture['forwards'] == 6, f'root counter must track denoiser forwards, got {lora_calib.capture["forwards"]}' + path = lora_calib.calib_file('test/calib-deadline') + assert os.path.isfile(path), 'deadline persist must write the statistics file' + assert getattr(starved, 'sdnq_calib_rms', None) is not None, 'the starved layer must carry statistics' + expected = torch.cat(xs).square().mean(dim=0).sqrt().cpu() + assert torch.allclose(starved.sdnq_calib_rms, expected, rtol=1e-3, atol=1e-5), 'starved rms must match exactly the tokens it saw' + with safe_open(path, framework='pt', device='cpu') as f: + assert set(f.keys()) == {'rich', 'starved'}, f'both layers must persist, got {sorted(f.keys())}' + assert f.metadata()['tokens'] == '40', f'metadata must report the weakest saved layer, got {f.metadata()["tokens"]}' + finally: + lora_calib.calib_root, lora_calib.TOKENS_DONE, lora_calib.FORWARDS_DEADLINE = old + lora_calib.detach_capture() + return True + + +def test_calib_deadline_omits_subfloor_layers(): + import tempfile + from safetensors import safe_open + from modules.lora import lora_calib + rich = build_layer('uint4', seed=48) + starved = build_layer('uint4', seed=49) + root = MockCalibDenoiser(rich, starved, starved_tokens=2) # 2 tokens x 5 counted forwards = 10, under the floor of 32 + sd = MockCalibSd('test/calib-subfloor') + sd.transformer = root + old = (lora_calib.calib_root, lora_calib.TOKENS_DONE, lora_calib.FORWARDS_DEADLINE) + with tempfile.TemporaryDirectory() as tmp, host_calib(True): + try: + lora_calib.calib_root = tmp + lora_calib.TOKENS_DONE = 2048 + lora_calib.FORWARDS_DEADLINE = 6 + lora_calib.on_model_loaded(sd) + torch.manual_seed(53) + for _ in range(6): + root(torch.randn(1024, IN_F, device=DEVICE).to(torch.bfloat16)) + assert lora_calib.capture['complete'], 'the forward deadline must close capture' + path = lora_calib.calib_file('test/calib-subfloor') + with safe_open(path, framework='pt', device='cpu') as f: + assert set(f.keys()) == {'rich'}, f'a layer under the token floor must be omitted, got {sorted(f.keys())}' + assert getattr(starved, 'sdnq_calib_rms', None) is None, 'an omitted layer must not carry statistics' + del rich.sdnq_calib_rms + lora_calib.on_model_loaded(sd) # second load takes the cached path with the partial file + assert len(lora_calib.capture['handles']) == 0, 'a partial file still counts as cached; capture must not re-attach' + assert getattr(rich, 'sdnq_calib_rms', None) is not None, 'the saved layer must reload from the partial file' + assert getattr(starved, 'sdnq_calib_rms', None) is None, 'the omitted layer must stay on plain truncation after reload' + finally: + lora_calib.calib_root, lora_calib.TOKENS_DONE, lora_calib.FORWARDS_DEADLINE = old + lora_calib.detach_capture() + return True + + +def test_calib_unet_root_walk(): + import tempfile + from modules.lora import lora_calib + layer = build_layer('uint4', seed=47) + sd = MockCalibSd('test/calib-unet', lin=layer) + sd.unet = sd.transformer + sd.transformer = None + mods = lora_calib.eligible_modules(sd) + assert [n for n, _ in mods] == ['lin'], f'the unet root must be walked when no transformer exists, got {[n for n, _ in mods]}' + both = MockCalibSd('test/calib-both') + both.unet = sd.unet + assert lora_calib.eligible_modules(both) == [], 'a transformer root wins even when it holds no eligible linears' + old_root = lora_calib.calib_root + with tempfile.TemporaryDirectory() as tmp, host_calib(True): + try: + lora_calib.calib_root = tmp + lora_calib.on_model_loaded(sd) + assert len(lora_calib.capture['handles']) == 2, 'the layer hook plus the root counter must attach on a unet model' + finally: + lora_calib.calib_root = old_root + lora_calib.detach_capture() + return True + + +CAT_FCACHE = category('factor-cache') + + +@contextmanager +def host_cache(gb, root): + from modules.lora import lora_factor_cache + old_gb = getattr(shared.opts, 'lora_sdnq_host_cache', 0) + old_root = lora_factor_cache.cache_root + shared.opts.lora_sdnq_host_cache = gb + lora_factor_cache.cache_root = root + lora_factor_cache.state.update(wn=None, sig=None, path=None, dirty=False, hits=0, misses=0) + lora_factor_cache.state['store'] = {} + try: + yield lora_factor_cache + finally: + shared.opts.lora_sdnq_host_cache = old_gb + lora_factor_cache.cache_root = old_root + lora_factor_cache.state.update(wn=None, sig=None, path=None, dirty=False, hits=0, misses=0) + lora_factor_cache.state['store'] = {} + + +def cache_fixture(tmp, layer, name='cachenet', sigma=3e-4, seed=61): + """Dense net whose on-disk file exists (signature needs a stat-able path) plus a mock checkpoint identity.""" + torch.manual_seed(seed) + D = torch.randn(OUT_F, IN_F, device=DEVICE) * sigma + net = make_dense_net(name, layer, D) + lora_file = os.path.join(tmp, f'{name}.safetensors') + with open(lora_file, 'wb') as f: + f.write(b'0' * 64) + net.network_on_disk.filename = lora_file + from modules.modeldata import model_data + model_data.sd_model.sd_checkpoint_info = MockCheckpointInfo('test/cache-model') + return net, D + + +def raise_no_svd(*_args, **_kwargs): + raise AssertionError('svd must not run on a cache hit') + + +def test_factor_cache_roundtrip_bitexact(): + import tempfile + layer = build_layer('uint4') + with tempfile.TemporaryDirectory() as tmp: + with host_rank(64), host_cache(10, os.path.join(tmp, 'cache')), mock_model(lin=layer): + net, _D = cache_fixture(tmp, layer) + Wdq0 = dq(layer) + activate(net) + first_up = layer.svd_up.detach().clone() + first_down = layer.svd_down.detach().clone() + activate() # pass end flushed the entry; unload restores the base + files = os.listdir(os.path.join(tmp, 'cache')) + assert len(files) == 1, f'one cache entry expected, got {files}' + bf16_bytes = (first_up.numel() + first_down.numel()) * 2 + entry_bytes = os.path.getsize(os.path.join(tmp, 'cache', files[0])) + assert entry_bytes < bf16_bytes * 0.62 + 8192, f'int8 entry must be about half the bf16 factor bytes: {entry_bytes} vs {bf16_bytes}' + real_svd = torch.svd_lowrank + torch.svd_lowrank = raise_no_svd + try: + activate(net) # same configuration: must replay from disk without touching the svd + finally: + torch.svd_lowrank = real_svd + assert torch.equal(layer.svd_up, first_up), 'cache hit must replay bit-identical up factors' + assert torch.equal(layer.svd_down, first_down), 'cache hit must replay bit-identical down factors' + activate() + assert torch.equal(dq(layer), Wdq0), 'unload must restore bit-exact' + return True + + +def test_factor_cache_invalidates_on_multiplier(): + import tempfile + layer = build_layer('uint4') + with tempfile.TemporaryDirectory() as tmp: + with host_rank(64), host_cache(10, os.path.join(tmp, 'cache')), mock_model(lin=layer): + net, _D = cache_fixture(tmp, layer) + activate(net) + up_full = layer.svd_up.detach().clone() + activate() + net.te_multiplier = 0.7 + net.unet_multiplier = [0.7] * 3 + activate(net) # different multiplier: different signature, fresh svd, second entry + assert not torch.equal(layer.svd_up, up_full), 'multiplier change must produce different factors' + activate() + files = os.listdir(os.path.join(tmp, 'cache')) + assert len(files) == 2, f'two cache entries expected, got {files}' + return True + + +def test_attach_trims_stored_null_tail(): + """Entries written before tail slicing pad the channel with null ranks: zero up + columns (and junk down rows behind them). Attach must trim to the effective rank + and replay the same resident tensors and weights as the unpadded entry.""" + import tempfile + layer = build_layer('uint4') + with tempfile.TemporaryDirectory() as tmp: + with host_rank(64), host_cache(10, os.path.join(tmp, 'cache')), mock_model(lin=layer): + net, _D = cache_fixture(tmp, layer, name='padnet') + activate(net) + up0 = layer.svd_up.detach().clone() + down0 = layer.svd_down.detach().clone() + Wl0 = dq(layer) + activate() + cache_dir = os.path.join(tmp, 'cache') + entry = os.path.join(cache_dir, os.listdir(cache_dir)[0]) + from safetensors import safe_open + from safetensors.torch import save_file + with safe_open(entry, framework='pt', device='cpu') as f: + meta = dict(f.metadata()) + tensors = {k: f.get_tensor(k) for k in f.keys()} + for k in [k for k in tensors if k.endswith('.up_q')]: + base = k[: -len('.up_q')] + torch.manual_seed(5) + tensors[f'{base}.up_q'] = torch.cat([tensors[k], torch.zeros(tensors[k].shape[0], 64, dtype=torch.int8)], dim=1) + tensors[f'{base}.down_q'] = torch.cat([tensors[f'{base}.down_q'], torch.randint(-127, 128, (64, IN_F), dtype=torch.int8)], dim=0) + tensors[f'{base}.down_s'] = torch.cat([tensors[f'{base}.down_s'], torch.ones(64, 1)], dim=0) + save_file(tensors, entry, metadata=meta) + real_svd = torch.svd_lowrank + torch.svd_lowrank = raise_no_svd + try: + activate(net) + finally: + torch.svd_lowrank = real_svd + assert layer.svd_up.shape[1] == 64, f'attach must trim the padded tail back to the effective rank, got {layer.svd_up.shape[1]}' + assert torch.equal(layer.svd_up, up0) and torch.equal(layer.svd_down, down0), 'trimmed factors must match the unpadded entry' + assert torch.equal(dq(layer), Wl0), 'trimmed attach must materialize the same weight' + activate() + return True + + +def test_factor_cache_int8_quantization(): + from modules.lora import lora_factor_cache as fc + torch.manual_seed(71) + t = torch.randn(64, 128, device=DEVICE) * torch.logspace(-3, 0, 64, device=DEVICE)[:, None] # rows spanning magnitudes + q, s = fc.quantize_rowwise(t) + assert q.dtype == torch.int8 + dq = fc.dequantize_rowwise(q, s) + err = (dq - t).abs().max(dim=1).values + assert bool((err <= s.squeeze(1) * 0.51).all()), 'rowwise int8 error must stay within half a step' + cos = torch.nn.functional.cosine_similarity(dq.flatten(), t.flatten(), dim=0) + assert float(cos) > 0.99995, f'int8 roundtrip cosine {float(cos):.6f}' + return True + + +def test_factor_cache_disabled_at_zero(): + import tempfile + layer = build_layer('uint4') + with tempfile.TemporaryDirectory() as tmp: + with host_rank(64), host_cache(0, os.path.join(tmp, 'cache')), mock_model(lin=layer): + net, _D = cache_fixture(tmp, layer) + activate(net) + activate() + assert not os.path.isdir(os.path.join(tmp, 'cache')), 'budget 0 must write nothing' + return True + + +def test_factor_cache_invalidates_on_calib_toggle(): + import tempfile + from modules.lora import lora_calib + layer = build_layer('uint4') + with tempfile.TemporaryDirectory() as tmp: + with host_rank(64), host_cache(10, os.path.join(tmp, 'cache')), mock_model(lin=layer): + net, _D = cache_fixture(tmp, layer) + old_root = lora_calib.calib_root + lora_calib.calib_root = os.path.join(tmp, 'calib') + os.makedirs(lora_calib.calib_root, exist_ok=True) + with open(lora_calib.calib_file('test/cache-model'), 'wb') as f: + f.write(b'0' * 64) # the signature stats this file; its content is never read here + torch.manual_seed(77) + layer.sdnq_calib_rms = torch.rand(IN_F) * 4 + 0.1 + try: + with host_calib(True): + activate(net) + up_cal = layer.svd_up.detach().clone() + activate() + with host_calib(False): + activate(net) # same set with calibration off: the entry keyed under the other setting must miss + up_plain = layer.svd_up.detach().clone() + activate() + assert not torch.equal(up_cal, up_plain), 'toggling calibration must not replay factors computed under the other setting' + assert len(os.listdir(os.path.join(tmp, 'cache'))) == 2, 'the two settings must key separate cache entries' + finally: + del layer.sdnq_calib_rms + lora_calib.calib_root = old_root + return True + + +@contextmanager +def counting_calc(): + """Count NetworkModuleFull.calc_updown calls: zero on a pass proves the walk skipped delta assembly.""" + from modules.lora import network_full + calls = {'n': 0} + real = network_full.NetworkModuleFull.calc_updown + def wrapper(self, *args, **kwargs): + calls['n'] += 1 + return real(self, *args, **kwargs) + network_full.NetworkModuleFull.calc_updown = wrapper + try: + yield calls + finally: + network_full.NetworkModuleFull.calc_updown = real + + +def test_cache_fastpath_skips_calc(): + import tempfile + layer = build_layer('uint4') + with tempfile.TemporaryDirectory() as tmp: + with host_rank(64), host_cache(10, os.path.join(tmp, 'cache')), mock_model(lin=layer): + net, _D = cache_fixture(tmp, layer) + Wdq0 = dq(layer) + with counting_calc() as calls: + activate(net) + assert calls['n'] > 0, 'a fresh apply must assemble the delta' + first = dq(layer) + activate() + calls['n'] = 0 + activate(net) + assert calls['n'] == 0, f'a cache replay must not assemble the delta: calc_updown ran {calls["n"]} times' + assert hasattr(layer, 'sdnq_lora_svd_stash'), 'the fast path must attach the cached factors' + assert torch.equal(dq(layer), first), 'fast-path replay must be bit-identical to the fresh apply' + activate() + assert torch.equal(dq(layer), Wdq0) + return True + + +def test_cache_fastpath_serves_mixed_set(): + import tempfile + layer = build_layer('uint4') + A, B, _D1 = make_delta(seed=63) + with tempfile.TemporaryDirectory() as tmp: + with host_rank(64), host_cache(10, os.path.join(tmp, 'cache')), mock_model(lin=layer): + net_full, _D2 = cache_fixture(tmp, layer, name='mixfull', seed=64) + net_plain = make_net('mixlora', layer, A, B) + lora_file = os.path.join(tmp, 'mixlora.safetensors') + with open(lora_file, 'wb') as f: + f.write(b'0' * 64) + net_plain.network_on_disk.filename = lora_file + activate(net_plain, net_full) + first = dq(layer) + activate() + with counting_calc() as calls: + activate(net_plain, net_full) # the factorable member re-extracts from its own weights; the hosted remainder replays + assert calls['n'] == 0, 'a mixed-set replay must not assemble the delta' + assert hasattr(layer, 'sdnq_lora_svd_stash') + assert torch.equal(dq(layer), first), 'mixed-set replay must be bit-identical to the fresh apply' + activate() + return True + + +def test_cache_fastpath_serves_dense_pair(): + import tempfile + layer = build_layer('uint4') + with tempfile.TemporaryDirectory() as tmp: + with host_rank(64), host_cache(10, os.path.join(tmp, 'cache')), stack_mode('ties'), mock_model(lin=layer): + net1, _D1 = cache_fixture(tmp, layer, name='densea', seed=65) + net2, _D2 = cache_fixture(tmp, layer, name='denseb', seed=66) + activate(net1, net2) + first = dq(layer) + activate() + with counting_calc() as calls: + activate(net1, net2) # the dense combine lives inside delta assembly; the replay skips both + assert calls['n'] == 0, 'a dense-pair replay must not assemble or combine deltas' + assert hasattr(layer, 'sdnq_lora_svd_stash') + assert torch.equal(dq(layer), first), 'dense-pair replay must be bit-identical to the fresh apply' + activate() + return True + + +CAT_STACK = category('stack-dense') + + +@contextmanager +def stack_mode(name, dens=None): + old_m = getattr(shared.opts, 'lora_stack_mode', 'sum') + old_d = getattr(shared.opts, 'lora_stack_density', 0.5) + shared.opts.lora_stack_mode = name + if dens is not None: + shared.opts.lora_stack_density = dens + try: + yield + finally: + shared.opts.lora_stack_mode = old_m + shared.opts.lora_stack_density = old_d + + +def test_ties_sign_consensus_drops_conflicts(): + with stack_mode('ties', dens=1.0): # density 1 disables the trim, isolating sign election + d1 = torch.tensor([[1.0, 1.0, -1.0]], device=DEVICE) + d2 = torch.tensor([[2.0, -0.5, -2.0]], device=DEVICE) + out = lora_stack.combine([('a', d1), ('b', d2)], 'lora_transformer_test') + expected = torch.tensor([[1.5, 1.0, -1.5]], device=DEVICE) # agree: mean; conflict: majority-mass side only + assert torch.allclose(out, expected), f'{out.tolist()}' + return True + + +def test_dare_mask_is_deterministic_across_calls(): + torch.manual_seed(21) + d1 = torch.randn(64, 96, device=DEVICE) * 1e-2 + d2 = torch.randn(64, 96, device=DEVICE) * 1e-2 + with stack_mode('dare_linear', dens=0.5): + out1 = lora_stack.combine([('a', d1), ('b', d2)], 'lora_transformer_test') + out2 = lora_stack.combine([('a', d1), ('b', d2)], 'lora_transformer_test') + other = lora_stack.combine([('a', d1), ('b', d2)], 'lora_transformer_other') + assert torch.equal(out1, out2), 'same layer and nets must draw the same masks' + assert not torch.equal(out1, other), 'a different layer must draw different masks' + return True + + +def test_dare_rescales_by_inverse_density(): + torch.manual_seed(22) + d1 = torch.randn(64, 96, device=DEVICE) + d2 = torch.randn(64, 96, device=DEVICE) + with stack_mode('dare_linear', dens=0.5): + out = lora_stack.combine([('a', d1), ('b', d2)], 'lora_transformer_test') + cands = torch.stack([torch.zeros_like(d1), 2 * d1, 2 * d2, 2 * d1 + 2 * d2]) + nearest = (cands - out.unsqueeze(0)).abs().min(dim=0).values + assert float(nearest.max()) < 1e-5, 'every element must be a 1/density-rescaled subset sum' + zero_frac = float((out == 0).float().mean()) + assert 0.1 < zero_frac < 0.45, f'both-dropped fraction {zero_frac} should sit near 0.25' + return True + + +def test_magnitude_prune_keeps_top_density(): + torch.manual_seed(23) + d1 = torch.randn(128, 64, device=DEVICE) + d2 = torch.zeros_like(d1) # inert second delta isolates the trim + with stack_mode('magnitude_prune', dens=0.25): + out = lora_stack.combine([('a', d1), ('b', d2)], 'lora_transformer_test') + kept = out != 0 + frac = float(kept.float().mean()) + assert 0.2 < frac < 0.3, f'kept fraction {frac}' + assert torch.equal(out[kept], d1[kept]), 'kept elements must pass through unchanged' + assert float(d1.abs()[~kept].max()) <= float(d1.abs()[kept].min()) + 1e-6, 'kept set must be the top magnitudes' + return True + + +def test_dense_two_plain_loras_hosted_not_summed(): + layer = build_layer('uint4') + A1, B1, D1 = make_delta(seed=31, sigma=1e-2) + A2, B2, D2 = make_delta(seed=32, sigma=1e-2) + n1 = make_net('td1', layer, A1, B1) + n2 = make_net('td2', layer, A2, B2) + with host_rank(64), mock_model(lin=layer): + Wdq0 = dq(layer) + with stack_mode('ties', dens=0.5): + activate(n1, n2) + # hosted at rank 64 leaves a rank-64 factor bucket; the exact concat of two rank-8 nets would leave 16 + assert layer.svd_up.shape[1] == 64, f'dense mode must route a factorable pair to hosting, rank={layer.svd_up.shape[1]}' + eff = dq(layer) - Wdq0 + activate() + assert torch.equal(dq(layer), Wdq0), 'removal must restore bit-exact' + with stack_mode('ties', dens=0.5): + ref = lora_stack.combine([('td1', D1), ('td2', D2)], 'lora_transformer_test') + s = D1 + D2 + assert float((eff - s).norm() / s.norm()) > 0.05, 'ties result must differ from the plain sum' + assert rho_of(eff, ref) > 0.8, f'hosted ties delta must track the ties reference, rho={rho_of(eff, ref):.3f}' # rank-64 truncation of the densified delta keeps ~0.89 + assert float((eff - ref).norm()) < float((eff - s).norm()), 'hosted result must sit closer to the ties reference than to the plain sum' + return True + + +def test_dense_pair_hosts_at_int8(): + layer = build_layer('int8') + A1, B1, D1 = make_delta(seed=41, sigma=1e-2) + A2, B2, D2 = make_delta(seed=42, sigma=1e-2) + n1 = make_net('ti1', layer, A1, B1) + n2 = make_net('ti2', layer, A2, B2) + with host_rank(64), mock_model(lin=layer): + Wdq0 = dq(layer) + with stack_mode('ties', dens=0.5): + activate(n1, n2) + assert hasattr(layer, 'sdnq_lora_svd_stash'), 'dense pair at int8 must host, not requantize' + assert getattr(layer, 'network_weights_backup', None) is None, 'hosted dense pair must not take a weight backup' + eff = dq(layer) - Wdq0 + activate() + assert torch.equal(dq(layer), Wdq0), 'removal must restore bit-exact' + with stack_mode('ties', dens=0.5): + ref = lora_stack.combine([('ti1', D1), ('ti2', D2)], 'lora_transformer_test') + assert rho_of(eff, ref) > 0.8, f'hosted int8 ties delta must track the ties reference, rho={rho_of(eff, ref):.3f}' + return True + + +def test_dense_single_nonfactorable_int8_keeps_requantize(): + layer = build_layer('int8') + _A, _B, D = make_delta(sigma=3e-3) + net = make_dense_net('ti8solo', layer, D) + with host_rank(256), mock_model(lin=layer), stack_mode('ties', dens=0.5): + activate(net) + assert not hasattr(layer, 'sdnq_lora_svd_stash'), 'a single non-factorable set at int8 must keep the requantize path even under a dense mode' + assert isinstance(getattr(layer, 'network_weights_backup', None), torch.Tensor), 'the requantize fallback must take the backup' + activate() + return True + + +def test_single_net_ignores_dense_mode(): + layer = build_layer('uint4') + A, B, D = make_delta(seed=33) + net = make_net('solo', layer, A, B) + with mock_model(lin=layer), stack_mode('ties', dens=0.5): + Wdq0 = dq(layer) + activate(net) + assert hasattr(layer, 'sdnq_lora_svd_stash'), 'single net must stay on the exact factor path' + assert rho_of(dq(layer) - Wdq0, D) > 0.99 + activate() + assert torch.equal(dq(layer), Wdq0) + return True + + +def test_te_layer_stays_plain_sum(): + layer = build_layer('uint4') + layer.network_layer_name = 'lora_te_test' + A1, B1, D1 = make_delta(seed=34) + A2, B2, D2 = make_delta(seed=35) + n1 = make_net('te1', layer, A1, B1) + n2 = make_net('te2', layer, A2, B2) + with mock_model(lin=layer), stack_mode('ties', dens=0.5): + Wdq0 = dq(layer) + activate(n1, n2) + assert hasattr(layer, 'sdnq_lora_svd_stash'), 'te layers must stay on the exact concat path' + assert rho_of(dq(layer) - Wdq0, D1 + D2) > 0.99 + activate() + assert torch.equal(dq(layer), Wdq0) + return True + + +def test_sum_mode_keeps_exact_stacking(): + layer = build_layer('uint4') + A1, B1, D1 = make_delta(seed=36) + A2, B2, D2 = make_delta(seed=37) + n1 = make_net('s1', layer, A1, B1) + n2 = make_net('s2', layer, A2, B2) + with mock_model(lin=layer), stack_mode('sum'): + Wdq0 = dq(layer) + activate(n1, n2) + assert hasattr(layer, 'sdnq_lora_svd_stash'), 'sum mode must keep the exact concat path' + assert layer.svd_up.shape[1] == 16, f'sum mode must concat exactly, rank={layer.svd_up.shape[1]}' + assert rho_of(dq(layer) - Wdq0, D1 + D2) > 0.99 + activate() + assert torch.equal(dq(layer), Wdq0) + return True + + +CAT_SELECT = category('stack-select') + + +@contextmanager +def select_mode(name, alpha=None, disc=None): + old = {k: getattr(shared.opts, k, None) for k in ('lora_stack_mode', 'lora_stack_alpha', 'lora_stack_discrepancy')} + shared.opts.lora_stack_mode = name + if alpha is not None: + shared.opts.lora_stack_alpha = alpha + if disc is not None: + shared.opts.lora_stack_discrepancy = disc + lora_stack.clear() + lora_stack.warned.clear() + try: + yield + finally: + for k, v in old.items(): + setattr(shared.opts, k, v) + lora_stack.clear() + + +def select_pair(layer, seed0=41, seed1=42, scale1=1.0): + A1, B1, D1 = make_delta(seed=seed0, sigma=1e-2) + A2, B2, D2 = make_delta(seed=seed1, sigma=1e-2) + if scale1 != 1.0: + A2, D2 = A2 * scale1, D2 * scale1 + n1 = make_net('subject', layer, A1, B1) + n2 = make_net('style', layer, A2, B2) + return n1, n2, D1, D2 + + +def test_select_flip_schedule_end_to_end(): + layer = build_layer('uint4') + n1, n2, D1, D2 = select_pair(layer) + with mock_model(lin=layer), select_mode('klora', alpha=1.5): + Wdq0 = dq(layer) + activate(n1, n2) + entry = lora_stack.state['entries'].get('lora_transformer_test') + assert entry is not None and entry['kind'] == 'factor', 'a factorable pair must register factor segments' + assert entry['segments'][0] == (0, 8) and entry['segments'][1] == (8, 16), f'segments {entry["segments"]}' + total = 20 + lora_stack.reset(total) + flips = [s for s, layers in lora_stack.state['flips'].items() for _ in layers] + assert len(flips) <= 1, 'a monotone ramp allows at most one flip per layer' + eff0 = dq(layer) - Wdq0 + winner0 = 0 if rho_of(eff0, D1) > rho_of(eff0, D2) else 1 + for s in range(total): + lora_stack.on_step(s) + eff1 = dq(layer) - Wdq0 + if flips: + assert rho_of(eff1, D2) > 0.99, 'after the flip the style delta must be selected' + assert rho_of(eff0, D1) > 0.99, 'before the flip the subject delta must be selected' + else: + assert rho_of(eff1, [D1, D2][winner0]) > 0.99 + activate() + assert torch.equal(dq(layer), Wdq0), 'removal from an end-of-schedule state must restore bit-exact' + return True + + +def test_select_initial_style_when_ramp_starts_won(): + # scale-invariant selection means no single isolated layer starts style-won on magnitude alone + # (that is the balance working), so force flip_step 0 directly and assert the initial selection honors it + layer = build_layer('uint4') + n1, n2, _D1, D2 = select_pair(seed0=43, seed1=44, layer=layer) + with mock_model(lin=layer), select_mode('estlora', alpha=1.0, disc=0.5): + Wdq0 = dq(layer) + activate(n1, n2) + orig = lora_stack.layer_flip_step + lora_stack.layer_flip_step = lambda scores, total: 0 # this layer's crossover is step 0 + try: + lora_stack.reset(20) + finally: + lora_stack.layer_flip_step = orig + eff = dq(layer) - Wdq0 + assert rho_of(eff, D2) > 0.99, 'a layer whose flip step is 0 must start style-selected' + return True + + +def test_estlora_energy_balance_defeats_magnitude(): + layer = build_layer('uint4') + n1, n2, _D1, D2 = select_pair(layer, seed0=51, seed1=52, scale1=0.33) # content ~3x louder than style + with mock_model(lin=layer), select_mode('estlora', alpha=1.5, disc=0.5): + Wdq0 = dq(layer) + activate(n1, n2) + lora_stack.reset(20) + entry = lora_stack.state['entries']['lora_transformer_test'] + assert lora_stack.state['gamma_e'] > 1.5, f'content-louder pair must give gamma_e>1: {lora_stack.state["gamma_e"]:.2f}' + balanced = lora_stack.layer_flip_step(entry['scores'], 20) + saved = lora_stack.state['gamma_e'] + lora_stack.state['gamma_e'] = 1.0 # paper-faithful est: energies compared raw + raw = lora_stack.layer_flip_step(entry['scores'], 20) + lora_stack.state['gamma_e'] = saved + assert raw == 20, f'without balance the squared magnitude gap keeps content the whole schedule, got {raw}' + assert 0 < balanced < 20, f'the energy balance must let the quieter style win mid-schedule, got {balanced}' + for s in range(20): + lora_stack.on_step(s) + assert rho_of(dq(layer) - Wdq0, D2) > 0.99, 'after the balanced flip the style delta must be selected' + activate() + assert torch.equal(dq(layer), Wdq0) + return True + + +def test_select_flip_is_inplace_and_shape_stable(): + layer = build_layer('uint4') + n1, n2, _D1, _D2 = select_pair(layer, seed0=45, seed1=46) + with mock_model(lin=layer), select_mode('klora'): + activate(n1, n2) + param_id = id(layer.svd_up) + shape = tuple(layer.svd_up.shape) + lora_stack.reset(20) + entry = lora_stack.state['entries']['lora_transformer_test'] + (s0, s1), (t0, t1), transposed = entry['segments'] + zeroed = lora_stack.segment_view(layer.svd_up.data, t0, t1, transposed) + kept = lora_stack.segment_view(layer.svd_up.data, s0, s1, transposed) + assert float(zeroed.abs().sum()) == 0.0 or float(kept.abs().sum()) == 0.0, 'exactly one segment must be zeroed initially' + for s in range(20): + lora_stack.on_step(s) + assert id(layer.svd_up) == param_id and tuple(layer.svd_up.shape) == shape, 'flips must mutate in place, never reassign' + return True + + +def test_select_matmul_transposed_layout(): + layer = build_layer('uint4', use_quantized_matmul=True) + n1, n2, D1, D2 = select_pair(layer, seed0=47, seed1=48) + with mock_model(lin=layer), select_mode('klora'): + Wdq0 = dq(layer) + activate(n1, n2) + entry = lora_stack.state['entries']['lora_transformer_test'] + assert entry['segments'][2] is True, 'quantized-matmul layout must register as transposed' + lora_stack.reset(20) + eff = dq(layer) - Wdq0 + assert max(rho_of(eff, D1), rho_of(eff, D2)) > 0.99, 'initial selection must realize one delta exactly' + activate() + assert torch.equal(dq(layer), Wdq0) + return True + + +def test_select_per_net_hosted_pair(): + layer = build_layer('uint4') + torch.manual_seed(49) + Dd1 = (torch.randn(OUT_F, 24, device=DEVICE) @ torch.randn(24, IN_F, device=DEVICE)) * 1e-3 # rank inside the host cap so truncation is near-lossless + Dd2 = (torch.randn(OUT_F, 24, device=DEVICE) @ torch.randn(24, IN_F, device=DEVICE)) * 1e-3 + n1 = make_dense_net('lk1', layer, Dd1) + n2 = make_dense_net('lk2', layer, Dd2) + with host_rank(32), mock_model(lin=layer), select_mode('klora'): + Wdq0 = dq(layer) + activate(n1, n2) + entry = lora_stack.state['entries'].get('lora_transformer_test') + assert entry is not None, 'non-factorable pairs must register through per-net hosting' + assert entry['segments'][0] == (0, 24) and entry['segments'][1] == (24, 48), f'segments {entry["segments"]}' # hosting stores the effective rank (24), not the cap + lora_stack.reset(20) + eff = dq(layer) - Wdq0 + best = max(rho_of(eff, Dd1), rho_of(eff, Dd2)) + assert best > 0.9, f'initial selection must realize one hosted delta, rho={best:.3f}' + activate() + assert torch.equal(dq(layer), Wdq0) + return True + + +def test_select_reset_restores_initial_state(): + layer = build_layer('uint4') + n1, n2, _D1, _D2 = select_pair(layer, seed0=51, seed1=52) + with mock_model(lin=layer), select_mode('klora'): + activate(n1, n2) + lora_stack.reset(20) + initial = dq(layer) + for s in range(20): + lora_stack.on_step(s) + lora_stack.reset(20) + assert torch.equal(dq(layer), initial), 'a fresh pass must restore the initial selection without re-activation' + return True + + +def test_select_deactivate_from_midflip(): + layer = build_layer('uint4') + n1, n2, _D1, _D2 = select_pair(layer, seed0=53, seed1=54) + with mock_model(lin=layer), select_mode('klora'): + Wdq0 = dq(layer) + activate(n1, n2) + lora_stack.reset(20) + for s in range(10): + lora_stack.on_step(s) + activate() + assert torch.equal(dq(layer), Wdq0), 'removal mid-schedule must restore bit-exact' + assert not lora_stack.state['entries'], 'removal must drop the selection entry' + return True + + +def test_select_requires_exactly_two_nets(): + layer = build_layer('uint4') + A3, B3, _D3 = make_delta(seed=55) + n1, n2, _D1, _D2 = select_pair(layer, seed0=56, seed1=57) + n3 = make_net('third', layer, A3, B3) + with mock_model(lin=layer), select_mode('klora'): + activate(n1, n2, n3) + assert hasattr(layer, 'sdnq_lora_svd_stash'), 'three nets must fall back to the exact concat path' + assert not lora_stack.state['entries'], 'no selection entries outside the two-net case' + activate() + return True + + +def test_select_gated_off_when_compiled(): + layer = build_layer('uint4') + n1, n2, _D1, _D2 = select_pair(layer, seed0=58, seed1=59) + old_compile = getattr(shared.opts, 'cuda_compile', None) + try: + shared.opts.cuda_compile = ['Model'] + with mock_model(lin=layer), select_mode('klora'): + activate(n1, n2) + assert not lora_stack.state['entries'], 'select must gate off under model compile' + assert hasattr(layer, 'sdnq_lora_svd_stash'), 'gated select behaves as sum' + activate() + finally: + shared.opts.cuda_compile = old_compile + return True + + +def test_select_finalize_drops_dead_module(): + import weakref + layer = build_layer('uint4') + n1, n2, _D1, _D2 = select_pair(layer, seed0=61, seed1=62) + with mock_model(lin=layer), select_mode('klora'): + activate(n1, n2) + entry = lora_stack.state['entries'].get('lora_transformer_test') + assert entry is not None, 'pair must register before the module dies' + entry['module'] = weakref.ref(torch.nn.Linear(2, 2)) # referent dies immediately: simulates offload re-wraps replacing a registered module + assert entry['module']() is None + lora_stack.reset(12) + assert 'lora_transformer_test' not in lora_stack.state['entries'], 'a dead module must drop its entry without breaking finalize' + activate() + return True + + +def test_select_int8_pair_rides_segments(): + layer = build_layer('int8') + n1, n2, D1, D2 = select_pair(layer, seed0=63, seed1=64) + with mock_model(lin=layer), select_mode('klora'): + Wdq0 = dq(layer) + activate(n1, n2) + entry = lora_stack.state['entries'].get('lora_transformer_test') + assert entry is not None and entry['kind'] == 'factor', 'an int8 pair must ride svd segments, not weight rewrites' + lora_stack.reset(16) + eff = dq(layer) - Wdq0 + assert max(rho_of(eff, D1), rho_of(eff, D2)) > 0.99, 'initial selection must deliver one exact per-net delta' + activate() + assert torch.equal(dq(layer), Wdq0), 'removal must restore bit-exact' + return True + + +def test_select_gate_dormant_without_pair(): + with select_mode('klora'): + assert lora_stack.select_possible(1) is False, 'a single network must leave the fuse gate alone' + assert lora_stack.select_possible(2) is True + assert lora_stack.select_possible(3) is False + old_compile = getattr(shared.opts, 'cuda_compile', None) + try: + shared.opts.cuda_compile = ['Model'] + assert lora_stack.select_possible(2) is False, 'compile block must keep the gate down' + finally: + shared.opts.cuda_compile = old_compile + assert lora_stack.select_engaged() is False + with select_mode('sum'): + assert lora_stack.select_possible(2) is False + return True + + +def test_stale_schedule_dropped_on_reapply(): + layer = build_layer('uint4') + n1, n2, D1, _D2 = select_pair(layer, seed0=64, seed1=65) + with mock_model(lin=layer), select_mode('klora'): + Wdq0 = dq(layer) + activate(n1, n2) + assert lora_stack.select_engaged(), 'the pair must register schedules' + lora_stack.reset(20) + activate(n1) # same mode still set, but a single net cannot select + assert not lora_stack.select_engaged(), 're-application must drop the stale schedule' + w_single = dq(layer) + assert rho_of(w_single - Wdq0, D1) > 0.99, 'the single net must apply exactly' + lora_stack.reset(20) # a later pass reset must find nothing to replay + assert torch.equal(dq(layer), w_single), 'a stale schedule must never overwrite a fresh apply' + activate() + assert torch.equal(dq(layer), Wdq0) + return True + + +def test_est_energy_matches_full_frobenius(): + torch.manual_seed(60) + up = torch.randn(64, 8, device=DEVICE) + down = torch.randn(8, 96, device=DEVICE) + gram = lora_stack.score_energy(up, down) + full = float((up @ down).square().sum()) + assert abs(gram - full) / full < 1e-5, f'{gram} vs {full}' + return True + + +def test_select_weight_kind_plain_layer(): + lin = torch.nn.Linear(IN_F, OUT_F, bias=False, dtype=torch.bfloat16, device=DEVICE) + with torch.no_grad(): + lin.weight.copy_(torch.randn(OUT_F, IN_F, device=DEVICE) * 0.02) + lin.network_layer_name = 'lora_transformer_plain' + lin.network_current_names = () + A1, B1, D1 = make_delta(seed=61, sigma=1e-2) + A2, B2, D2 = make_delta(seed=62, sigma=1e-2) + n1 = make_net('w1', lin, A1, B1) + n2 = make_net('w2', lin, A2, B2) + W0 = lin.weight.detach().float().clone() + with mock_model(lin=lin), select_mode('klora'): + activate(n1, n2) + entry = lora_stack.state['entries'].get('lora_transformer_plain') + assert entry is not None and entry['kind'] == 'weight', 'plain layers must register weight-kind selection' + assert torch.equal(lin.weight.detach().float(), W0), 'weights stay pristine until the schedule applies a winner' + lora_stack.reset(20) + eff = lin.weight.detach().float() - W0 + assert max(rho_of(eff, D1), rho_of(eff, D2)) > 0.95, 'initial selection must apply one delta from backup' + for s in range(20): + lora_stack.on_step(s) + activate() + assert torch.equal(lin.weight.detach().float(), W0), 'restore-only pass must return the pristine weight' + return True + + +def test_select_gamma_tracks_live_entries(): + layer = build_layer('uint4') + n1, n2, _D1, _D2 = select_pair(layer, seed0=57, seed1=58) + with mock_model(lin=layer), select_mode('klora'): + activate(n1, n2) + lora_stack.reset(20) + entry = lora_stack.state['entries']['lora_transformer_test'] + live = entry['abs_sums'][0] / entry['abs_sums'][1] + assert abs(lora_stack.state['gamma'] - live) < 1e-9, f'gamma {lora_stack.state["gamma"]} vs live ratio {live}' + n2.te_multiplier = 0.5 + n2.unet_multiplier = [0.5] * 3 + activate(n1, n2) # multiplier change re-applies the pair through the drop/re-register walk + lora_stack.reset(20) + entry = lora_stack.state['entries']['lora_transformer_test'] + live2 = entry['abs_sums'][0] / entry['abs_sums'][1] + assert live2 > live * 1.5, f'halving the style multiplier must move the live ratio: {live} -> {live2}' + assert abs(lora_stack.state['gamma'] - live2) < 1e-9, f'gamma must equal the live-entry ratio, not blend with the previous registration: {lora_stack.state["gamma"]} vs {live2}' + activate() + with mock_model(lin=layer), select_mode('estlora'): + activate(n1, n2) + lora_stack.reset(20) + entry = lora_stack.state['entries']['lora_transformer_test'] + live_e = entry['scores'][0] / entry['scores'][1] + assert abs(lora_stack.state['gamma_e'] - live_e) < 1e-9 + n2.te_multiplier = 1.0 + n2.unet_multiplier = [1.0] * 3 + activate(n1, n2) + lora_stack.reset(20) + entry = lora_stack.state['entries']['lora_transformer_test'] + live_e2 = entry['scores'][0] / entry['scores'][1] + assert abs(lora_stack.state['gamma_e'] - live_e2) < 1e-9, f'energy balance must track the live registration: {lora_stack.state["gamma_e"]} vs {live_e2}' + activate() + return True + + +def test_select_host_disabled_falls_back_to_sum(): + layer = build_layer('uint4') + n1, n2, D1, D2 = select_pair(layer, seed0=53, seed1=54) + with mock_model(lin=layer), select_mode('klora'), host_rank(0): + Wdq0 = dq(layer) + activate(n1, n2) + assert not lora_stack.select_engaged(), 'hosting disabled: quantized layers cannot carry segments, nothing must schedule' + assert 'select-host-disabled' in lora_stack.warned, 'the degradation must be said once' + eff = dq(layer) - Wdq0 + assert rho_of(eff, D1 + D2) > 0.99, 'the pair must land as plain summation, not a pristine no-op' + activate() + assert torch.equal(dq(layer), Wdq0) + return True + + +def test_degradation_warning_rearms_on_settings_change(): + class CountingLog: + def __init__(self): + self.warnings = 0 + + def warning(self, _message): + self.warnings += 1 + + counter = CountingLog() + real_log = lora_stack.log + saved = {k: getattr(shared.opts, k, None) for k in ('lora_stack_mode', 'lora_sdnq_host_rank')} + lora_stack.log = counter + lora_stack.warned.clear() + lora_stack.warned_context = None + try: + shared.opts.lora_stack_mode = 'klora' + lora_stack.warn_once('probe', 'Network stack: probe') + lora_stack.warn_once('probe', 'Network stack: probe') + assert counter.warnings == 1, f'one degradation under one settings context says it once, got {counter.warnings}' + shared.opts.lora_stack_mode = 'estlora' + lora_stack.warn_once('probe', 'Network stack: probe') + assert counter.warnings == 2, 'changing the stack mode must let the degradation be said again' + shared.opts.lora_sdnq_host_rank = 0 + lora_stack.warn_once('probe', 'Network stack: probe') + assert counter.warnings == 3, 'the host rank belongs to that context too' + finally: + lora_stack.log = real_log + for k, v in saved.items(): + setattr(shared.opts, k, v) + lora_stack.warned.clear() + lora_stack.warned_context = None + return True + + +def test_flip_lands_before_crossover_step(): + layer = build_layer('uint4') + n1, n2, D1, D2 = select_pair(layer, seed0=55, seed1=56) + with mock_model(lin=layer), select_mode('klora'): + Wdq0 = dq(layer) + activate(n1, n2) + total = 20 + orig = lora_stack.layer_flip_step + lora_stack.layer_flip_step = lambda scores, t: t - 1 # crossover on the final step + try: + lora_stack.reset(total) + finally: + lora_stack.layer_flip_step = orig + assert list(lora_stack.state['flips'].keys()) == [total - 2], f'end-of-step callbacks: a crossover at step k must execute at the end of step k-1, got {list(lora_stack.state["flips"].keys())}' + assert rho_of(dq(layer) - Wdq0, D1) > 0.99, 'the subject holds the layer before the flip' + for s in range(total - 1): # the callback after the second-to-last denoise is the last one that can matter + lora_stack.on_step(s) + assert rho_of(dq(layer) - Wdq0, D2) > 0.99, 'the style side must be live for the final denoise' + activate() + assert torch.equal(dq(layer), Wdq0) + return True + + +def test_score_pair_chunked_precision(): + torch.manual_seed(71) + shapes = [(700, 460), (OUT_F, IN_F), (64,)] # off-chunk rows, square, and a 1-D norm delta + for shape in shapes: + d0 = (torch.randn(*shape, device=DEVICE) * 1e-2).to(torch.bfloat16) + d1 = (torch.randn(*shape, device=DEVICE) * 1e-2).to(torch.bfloat16) + for mode_name in ('klora', 'estlora'): + with select_mode(mode_name): + (s0, s1), (a0, a1) = lora_stack.score_pair(d0, d1, 8, 8) + f0, f1 = d0.to(torch.float64), d1.to(torch.float64) + ra0, ra1 = float(f0.abs().sum()), float(f1.abs().sum()) + if mode_name == 'klora': + k = 64 + rs0 = float(torch.topk(f0.abs().flatten(), min(k, f0.numel()), sorted=False).values.sum()) + rs1 = float(torch.topk(f1.abs().flatten(), min(k, f1.numel()), sorted=False).values.sum()) + else: + rs0, rs1 = float(f0.square().sum()), float(f1.square().sum()) + for got, ref, label in ((s0, rs0, 'score0'), (s1, rs1, 'score1'), (a0, ra0, 'abs0'), (a1, ra1, 'abs1')): + assert abs(got - ref) <= 1e-9 * max(abs(ref), 1e-12), f'{mode_name} {label} shape={shape}: got {got!r} ref {ref!r}' + frozen = torch.randn(300, 200, device=DEVICE, dtype=torch.float32) * 1e-2 # fp32 input aliases through to(); abs must stay out-of-place + pristine = frozen.clone() + with select_mode('klora'): + lora_stack.score_pair(frozen, frozen, 4, 4) + assert torch.equal(frozen, pristine), 'score_pair must not mutate a caller-owned fp32 delta' + return True + + +def test_select_replay_from_cache_skips_calc(): + import tempfile + layer = build_layer('uint4') + torch.manual_seed(73) + Dd1 = (torch.randn(OUT_F, 24, device=DEVICE) @ torch.randn(24, IN_F, device=DEVICE)) * 1e-3 + Dd2 = (torch.randn(OUT_F, 24, device=DEVICE) @ torch.randn(24, IN_F, device=DEVICE)) * 1e-3 + with tempfile.TemporaryDirectory() as tmp: + with host_rank(32), host_cache(10, os.path.join(tmp, 'cache')), mock_model(lin=layer), select_mode('klora'): + n1 = make_dense_net('selk1', layer, Dd1) + n2 = make_dense_net('selk2', layer, Dd2) + for net in (n1, n2): + lora_file = os.path.join(tmp, f'{net.name}.safetensors') + with open(lora_file, 'wb') as f: + f.write(b'0' * 64) + net.network_on_disk.filename = lora_file + from modules.modeldata import model_data + model_data.sd_model.sd_checkpoint_info = MockCheckpointInfo('test/cache-model') + Wdq0 = dq(layer) + with counting_calc() as calls: + activate(n1, n2) + assert calls['n'] > 0, 'a fresh select apply must assemble both deltas' + entry = lora_stack.state['entries'].get('lora_transformer_test') + assert entry is not None and entry['kind'] == 'factor' + fresh_scores, fresh_abs = entry['scores'], entry['abs_sums'] + first = dq(layer) + activate() + calls['n'] = 0 + real_svd = torch.svd_lowrank + torch.svd_lowrank = raise_no_svd + try: + activate(n1, n2) + finally: + torch.svd_lowrank = real_svd + assert calls['n'] == 0, f'a select replay must not assemble deltas: calc_updown ran {calls["n"]} times' + entry = lora_stack.state['entries'].get('lora_transformer_test') + assert entry is not None and entry['kind'] == 'factor', 'the replay must re-register the selection' + assert entry['scores'] == fresh_scores and entry['abs_sums'] == fresh_abs, 'cached scores must replay exactly' + assert torch.equal(dq(layer), first), 'select replay must be bit-identical to the fresh apply' + activate() + assert torch.equal(dq(layer), Wdq0) + return True + + +def test_select_weight_replay_from_cache_skips_calc(): + import tempfile + lin = torch.nn.Linear(IN_F, OUT_F, bias=False, dtype=torch.bfloat16, device=DEVICE) + with torch.no_grad(): + lin.weight.copy_(torch.randn(OUT_F, IN_F, device=DEVICE) * 0.02) + lin.network_layer_name = 'lora_transformer_plainsel' + lin.network_current_names = () + torch.manual_seed(75) + Dd1 = (torch.randn(OUT_F, 24, device=DEVICE) @ torch.randn(24, IN_F, device=DEVICE)) * 1e-3 + Dd2 = (torch.randn(OUT_F, 24, device=DEVICE) @ torch.randn(24, IN_F, device=DEVICE)) * 1e-3 + W0 = lin.weight.detach().float().clone() + with tempfile.TemporaryDirectory() as tmp: + with host_cache(10, os.path.join(tmp, 'cache')), mock_model(lin=lin), select_mode('klora'): + n1 = make_dense_net('selw1', lin, Dd1) + n2 = make_dense_net('selw2', lin, Dd2) + for net in (n1, n2): + lora_file = os.path.join(tmp, f'{net.name}.safetensors') + with open(lora_file, 'wb') as f: + f.write(b'0' * 64) + net.network_on_disk.filename = lora_file + from modules.modeldata import model_data + model_data.sd_model.sd_checkpoint_info = MockCheckpointInfo('test/cache-model') + with counting_calc() as calls: + activate(n1, n2) + assert calls['n'] > 0, 'a fresh weight-kind select apply must assemble the pair' + entry = lora_stack.state['entries'].get('lora_transformer_plainsel') + assert entry is not None and entry['kind'] == 'weight' + fresh_scores = entry['scores'] + assert torch.equal(lin.weight.detach().float(), W0), 'weights stay pristine until the schedule applies a winner' + lora_stack.reset(20) + fresh_selected = lin.weight.detach().float().clone() + activate() + assert torch.equal(lin.weight.detach().float(), W0) + calls['n'] = 0 + activate(n1, n2) + assert calls['n'] == 0, f'a weight-kind select replay must not assemble the pair: calc_updown ran {calls["n"]} times' + entry = lora_stack.state['entries'].get('lora_transformer_plainsel') + assert entry is not None and entry['kind'] == 'weight', 'the replay must register from the score record' + assert entry['scores'] == fresh_scores, 'cached scores must replay exactly' + lora_stack.reset(20) # the winner recompute at schedule time still assembles its own delta, by design + assert torch.equal(lin.weight.detach().float(), fresh_selected), 'the replayed schedule must select the same winner' + activate() + assert torch.equal(lin.weight.detach().float(), W0) + return True + + +def test_select_reset_reports_timing(): + lin = torch.nn.Linear(IN_F, OUT_F, bias=False, dtype=torch.bfloat16, device=DEVICE) + with torch.no_grad(): + lin.weight.copy_(torch.randn(OUT_F, IN_F, device=DEVICE) * 0.02) + lin.network_layer_name = 'lora_transformer_timed' + lin.network_current_names = () + A1, B1, _D1 = make_delta(seed=77, sigma=1e-2) + A2, B2, _D2 = make_delta(seed=78, sigma=1e-2) + n1 = make_net('t1', lin, A1, B1) + n2 = make_net('t2', lin, A2, B2) + with mock_model(lin=lin), select_mode('klora'): + activate(n1, n2) + lora_stack.reset(20) + stats = lora_stack.state.get('stats') + assert stats is not None, 'a reset must publish its timing stats' + assert stats['weight_n'] == 1 and stats['factor_n'] == 0, f'weight-kind counts wrong: {stats}' + assert stats['w_calc'] > 0.0, 'the weight-kind winner apply must account its calc time' + assert stats['select'] > 0.0 + activate() + layer = build_layer('uint4') + f1, f2, _Df1, _Df2 = select_pair(layer, seed0=79, seed1=80) + with mock_model(lin=layer), select_mode('klora'): + activate(f1, f2) + lora_stack.reset(20) + stats = lora_stack.state.get('stats') + assert stats is not None and stats['factor_n'] == 1 and stats['weight_n'] == 0, f'factor-kind counts wrong: {stats}' + assert stats['w_calc'] == 0.0, 'factor-kind resets flip segments and must not touch the weight path' + activate() + return True + + +def test_select_weight_flip_calcs_on_accelerator(): + from modules.lora import network_lora + lin = torch.nn.Linear(IN_F, OUT_F, bias=False, dtype=torch.bfloat16, device='cpu') # a swapped-out layer: weight lives on cpu + with torch.no_grad(): + lin.weight.copy_(torch.randn(OUT_F, IN_F) * 0.02) + lin.network_layer_name = 'lora_transformer_swapped' + lin.network_current_names = () + A1, B1, _D1 = make_delta(seed=81, sigma=1e-2) + A2, B2, _D2 = make_delta(seed=82, sigma=1e-2) + n1 = make_net('s1', lin, A1, B1) + n2 = make_net('s2', lin, A2, B2) + seen = [] + real = network_lora.NetworkModuleLora.calc_updown + def spy(self, target, *args, **kwargs): + seen.append(target.device.type) + return real(self, target, *args, **kwargs) + with mock_model(lin=lin), select_mode('klora'): + activate(n1, n2) + lin.to('cpu') # the offload dispatch swaps blocks back out after the walk; the reset must not follow the weight onto the cpu + network_lora.NetworkModuleLora.calc_updown = spy + try: + lora_stack.reset(20) + finally: + network_lora.NetworkModuleLora.calc_updown = real + assert seen and all(d == DEVICE.type for d in seen), f'winner materialization must calc on the accelerator, saw {seen}' + activate() + return True + + +CAT_COMPILE = category('compile') + + +def dq_compiled(layer): + # the production entry: skip_compile left at its default so the shared compiled dequant runs + return layer.sdnq_dequantizer(layer.weight, layer.scale, zero_point=layer.zero_point, + svd_up=layer.svd_up, svd_down=layer.svd_down, + skip_quantized_matmul=layer.sdnq_dequantizer.use_quantized_matmul, + dtype=torch.float32) + + +def graph_stats(): + from torch._dynamo.utils import counters + return int(counters['stats']['unique_graphs']), sum(counters['graph_break'].values()) + + +def test_factor_add_inside_compiled_graph(): + from sdnq.common import use_torch_compile + if not use_torch_compile: + return True # compile disabled at sdnq import (no triton); nothing to pin + import torch._dynamo + from torch._dynamo.utils import counters + layer = build_layer('uint4') + A, B, _D = make_delta() + dtype = layer.sdnq_dequantizer.result_dtype + torch._dynamo.reset() + counters.clear() + lora_sdnq.append_factors(layer, [B.to(dtype)], [A.to(dtype)]) + W_c = dq_compiled(layer) + graphs, breaks = graph_stats() + assert breaks == 0, f'graph breaks in the compiled dequant: {breaks}' + assert graphs == 1, f'factor-bearing dequant must be one compiled region, got {graphs} graphs' + W_e = dq(layer) + assert torch.allclose(W_c, W_e, rtol=1e-3, atol=1e-4), f'compiled vs eager dequant diverged, max {float((W_c - W_e).abs().max()):.3e}' + lora_sdnq.remove_factors(layer) + return True + + +def test_rank_bucket_graph_reuse(): + from sdnq.common import use_torch_compile + if not use_torch_compile: + return True + import torch._dynamo + from torch._dynamo.utils import counters + import sdnq.common as sdnq_common + layer = build_layer('uint4', use_hadamard=False) + dtype = layer.sdnq_dequantizer.result_dtype + torch.manual_seed(13) + mk = lambda r: (torch.randn(OUT_F, r, device=DEVICE, dtype=dtype) * 0.01, torch.randn(r, IN_F, device=DEVICE, dtype=dtype) * 0.01) + B8, A8 = mk(8) + B6, A6 = mk(6) + B24, A24 = mk(24) + + torch._dynamo.reset() + counters.clear() + lora_sdnq.append_factors(layer, [B8], [A8]) + assert layer.svd_up.shape[1] == 8, f'rank 8 must bucket to 8, got {layer.svd_up.shape[1]}' + dq_compiled(layer) + g_first, _ = graph_stats() + + lora_sdnq.remove_factors(layer) + lora_sdnq.append_factors(layer, [B6], [A6]) + assert layer.svd_up.shape[1] == 8, f'rank 6 must pad to bucket 8, got {layer.svd_up.shape[1]}' + assert float(layer.svd_up[:, 6:].abs().sum()) == 0.0, 'pad columns must be exact zeros' + dq_compiled(layer) + g_same, _ = graph_stats() + assert g_same == g_first, f'same bucket must reuse the graph: {g_first} -> {g_same}' + + lora_sdnq.remove_factors(layer) + lora_sdnq.append_factors(layer, [B24], [A24]) + assert layer.svd_up.shape[1] == 32, f'rank 24 must pad to bucket 32, got {layer.svd_up.shape[1]}' + dq_compiled(layer) + g_novel, _ = graph_stats() + assert g_novel == g_first + 1, f'novel bucket must compile exactly one new graph: {g_first} -> {g_novel}' + + lora_sdnq.remove_factors(layer) + lora_sdnq.append_factors(layer, [B8], [A8]) + dq_compiled(layer) + g_back, _ = graph_stats() + assert g_back == g_novel, f'returning to a seen bucket must be free: {g_novel} -> {g_back}' + + W_padded = dq(layer) + lora_sdnq.remove_factors(layer) + old_flag = sdnq_common.use_torch_compile + sdnq_common.use_torch_compile = False + try: + lora_sdnq.append_factors(layer, [B8], [A8]) + assert layer.svd_up.shape[1] == 8 + W_unpadded = dq(layer) + finally: + sdnq_common.use_torch_compile = old_flag + lora_sdnq.remove_factors(layer) + assert torch.allclose(W_padded, W_unpadded, rtol=0.0, atol=1e-6), f'padding must be inert beyond reduction-order ulp, max {float((W_padded - W_unpadded).abs().max()):.3e}' + return True + + +def test_recompile_wall_resets_on_unload(): + import sdnq.common as sdnq_common + if not sdnq_common.use_torch_compile: + return True + import torch._dynamo + import torch._dynamo.config as dcfg + from torch._dynamo.exc import FailOnRecompileLimitHit + old_acc = dcfg.accumulated_recompile_limit + dcfg.accumulated_recompile_limit = 4 + try: + fn = sdnq_common.compile_func(lambda w, s: w.to(torch.float32) * s) + hit = False + for i in range(8): # fresh shapes stand in for model switches: the lifetime counter climbs even when old guards are dead + try: + fn(torch.randint(0, 255, (32 + 16 * i, 8), dtype=torch.uint8, device=DEVICE), torch.rand(32 + 16 * i, 1, device=DEVICE)) + except FailOnRecompileLimitHit: + hit = True + break + assert hit, 'the lowered lifetime wall must trip on fullgraph recompiles' + sdnq_common.reset_compile_caches() # the unload-seam hook: counters and dead graphs cleared + fn(torch.randint(0, 255, (1024, 8), dtype=torch.uint8, device=DEVICE), torch.rand(1024, 1, device=DEVICE)) + finally: + dcfg.accumulated_recompile_limit = old_acc + torch._dynamo.reset() # leave no wall residue for later tests + return True + + +CAT_ROBUST = category('robustness') + + +def test_remove_factors_after_device_move(): + layer = build_layer('uint4', use_svd=True) # checkpoint svd correction so the stash holds real tensors + A, B, _D = make_delta() + net = make_net('mover', layer, A, B) + with mock_model(lin=layer): + Wdq0 = dq(layer) + orig_up = layer.svd_up.detach().clone() + activate(net) + assert hasattr(layer, 'sdnq_lora_svd_stash') + layer.to('cpu') # offload moves registered params, never the stash tuple + activate() + assert layer.svd_up.device == layer.scale.device, f'restored svd must live on the layer device, got {layer.svd_up.device} vs {layer.scale.device}' + assert torch.equal(layer.svd_up, orig_up.to('cpu')), 'restored svd values must match the original factors' + layer.to(DEVICE) + assert torch.equal(dq(layer), Wdq0), 'round trip must restore bit-exact' + return True + + +def dispatch_module_type(w): + """Pick a module type the way the generic loader does.""" + host = torch.nn.Linear(IN_F, OUT_F) + net = network.Network('typed', MockNOD('typed')) + nw = network.NetworkWeights(network_key='lora_unet_x', sd_key='lora_unet_x', w=w, sd_module=host) + for nettype in l_common.module_types: + mod = nettype.create_module(net, nw) + if mod is not None: + return mod + return None + + +def test_four_dim_oft_blocks_load_as_boft(): + blocks4 = torch.zeros(2, 8, 64, 64) # (boft_m, block_num, block_size, block_size) + mod = dispatch_module_type({'oft_blocks': blocks4, 'alpha': torch.tensor(1.0)}) + assert type(mod).__name__ == 'NetworkModuleBOFT', f'4-d oft_blocks must bind to boft, got {type(mod).__name__}' + blocks3 = torch.zeros(8, 64, 64) # (num_blocks, block_size, block_size) + mod = dispatch_module_type({'oft_blocks': blocks3, 'alpha': torch.tensor(1.0)}) + assert type(mod).__name__ == 'NetworkModuleOFT', f'3-d oft_blocks must stay on oft, got {type(mod).__name__}' + return True + + +def test_nunchaku_entries_carry_the_network_interface(): + from modules.lora import lora_nunchaku + nod = MockNOD('composed') + net = lora_nunchaku.wrap_network(nod) + assert len(net.modules) == 0, 'a composed set owns no modules: the reported method probes this to tell native from nunchaku' + assert net.network_on_disk is nod, 'infotext reads the hash through network_on_disk' + assert net.name == nod.name + return True + + +def test_native_dispatch_archs_are_native_eligible(): + from modules.lora import lora_load, lora_overrides + missing = sorted(set(lora_load.NATIVE_DISPATCH) - set(lora_overrides.allow_native)) + assert not missing, f'an arch with a native loader that the method choice sends elsewhere never reaches it: {missing}' + return True + + +def test_aborted_pass_still_publishes_its_state(): + layer = build_layer('uint4') + _A, _B, D = make_delta() + net = make_dense_net('aborted', layer, D) + reported = {'n': 0} + real_prepare = networks.prepare_model_for_write + real_report = lora_sdnq.report_fallbacks + + def exploding(_sd_model): + raise RuntimeError('offload rebuild failed') # a raise before the walk binds anything the epilogue reads + + def counting_report(): + reported['n'] += 1 + real_report() + + networks.prepare_model_for_write = exploding + lora_sdnq.report_fallbacks = counting_report + try: + with mock_model(lin=layer): + raised = None + try: + activate(net) + except RuntimeError as e: + raised = e + assert raised is not None and 'offload rebuild failed' in str(raised), f'the original failure must reach the caller, got {raised!r}' + assert reported['n'] == 1, 'an aborted pass must still publish its counters and put the model back under its offload mode' + finally: + networks.prepare_model_for_write = real_prepare + lora_sdnq.report_fallbacks = real_report + return True + + +def test_stacked_shape_mismatch_falls_back(): + from types import SimpleNamespace + layer = build_layer('uint4') + A, B, _D = make_delta() + net_good = make_net('good', layer, A, B) + torch.manual_seed(9) + A_bad = torch.randn(RANK, IN_F, device=DEVICE) * 0.01 + B_bad = torch.randn(OUT_F // 2, RANK, device=DEVICE) * 0.01 # wrong out_features for this layer + net_bad = make_net('badshape', layer, A_bad, B_bad) + prev_enl = l_common.extra_network_lora + l_common.extra_network_lora = SimpleNamespace(errors={}) # the error path reports through the extra-networks registry + try: + with host_rank(0), mock_model(lin=layer): + Wdq0 = dq(layer) + activate(net_good) + assert hasattr(layer, 'sdnq_lora_svd_stash') + activate(net_good, net_bad) # must not raise: a malformed stack downgrades the layer to the legacy path + assert not hasattr(layer, 'sdnq_lora_svd_stash'), 'shape-mismatched stack must leave factor mode' + activate() + assert torch.equal(dq(layer), Wdq0), 'unload must restore bit-exact pristine' + finally: + l_common.extra_network_lora = prev_enl + return True + + +# ============================================================ +# Tests - per-block strength (lbw) +# ============================================================ + +CAT_BLOCKS = category('block-weights') + + +def block_fixture_keys(arch): + """Sparse network_layer_mapping keys per arch: the layout scan only needs each chain's max index.""" + if arch == 'sd': + return ['lora_unet_down_blocks_3_resnets_1_conv1', 'lora_unet_up_blocks_3_resnets_2_conv1'] + if arch == 'sdxl': + return ['lora_unet_down_blocks_2_resnets_1_conv1', 'lora_unet_up_blocks_2_resnets_2_conv1'] + if arch in ('f1', 'chroma'): + return ['lora_transformer_transformer_blocks_18_attn_to_q', 'lora_transformer_single_transformer_blocks_37_attn_to_q'] + if arch == 'krea2': + return ['lora_transformer_blocks_27_attn_wq', 'lora_transformer_txtfusion_layerwise_blocks_1_attn_wq', 'lora_transformer_txtfusion_refiner_blocks_1_mlp_down'] + if arch == 'anima': + return ['lora_transformer_transformer_blocks_27_attn1_to_q', 'lora_llm_adapter_blocks_5_self_attn_q_proj', 'lora_te_layers_3_mlp_gate_proj'] + if arch == 'zimage': + return ['lora_transformer_layers_29_attention_to_q', 'lora_transformer_noise_refiner_1_attention_to_q'] + if arch == 'sd3': + return ['lora_transformer_transformer_blocks_23_attn_to_q'] + return [] + + +@contextmanager +def block_model(arch, keys=None, **layers): + """mock_model plus a synthetic arch and network_layer_mapping for block classification.""" + from modules import modeldata + real_type = modeldata.get_model_type + modeldata.get_model_type = lambda _pipe: arch + try: + with mock_model(**layers): + shared.sd_model.network_layer_mapping = {k: None for k in (keys or block_fixture_keys(arch))} + lora_blocks.state.update(stamp=None, layout=None) + lora_blocks.state['index'].clear() + lora_blocks.state['vectors'].clear() + lora_blocks.warned.clear() + yield + finally: + modeldata.get_model_type = real_type + lora_blocks.state.update(stamp=None, layout=None) + lora_blocks.state['index'].clear() + lora_blocks.state['vectors'].clear() + lora_blocks.warned.clear() + + +def sd3_spec(n=25, **slots): + """A 25-slot sd3 vector as a spec string with named slot overrides.""" + vals = [1.0] * n + for slot, v in slots.items(): + vals[int(slot[1:])] = v + return ','.join(str(v) for v in vals) + + +def test_block_index_sd_unet_layout(): + with block_model('sd'): + lay = lora_blocks.layout() + assert lay is not None and lay['n'] == 26 and lay['kind'] == 'unet', f'layout={lay}' + cases = { + 'lora_unet_conv_in': 1, + 'lora_unet_down_blocks_0_attentions_0_transformer_blocks_0_attn1_to_q': 2, + 'lora_unet_down_blocks_0_resnets_1_conv1': 3, + 'lora_unet_down_blocks_0_downsamplers_0_conv': 4, + 'lora_unet_down_blocks_2_downsamplers_0_conv': 10, + 'lora_unet_down_blocks_3_resnets_1_conv1': 12, + 'lora_unet_mid_block_attentions_0_transformer_blocks_0_attn2_to_k': 13, + 'lora_unet_up_blocks_0_resnets_0_conv1': 14, + 'lora_unet_up_blocks_1_attentions_2_transformer_blocks_0_ff_net_0_proj': 19, + 'lora_unet_up_blocks_2_upsamplers_0_conv': 22, + 'lora_unet_up_blocks_3_resnets_2_conv1': 25, + 'lora_unet_conv_out': 25, + 'lora_unet_conv_norm_out': 25, + 'lora_unet_time_embedding_linear_1': 0, + 'lora_te_text_model_encoder_layers_0_self_attn_q_proj': 0, + } + for key, expected in cases.items(): + got = lora_blocks.block_index(key) + assert got == expected, f'{key}: got {got} expected {expected}' + return True + + +def test_block_index_sdxl_unet_layout(): + with block_model('sdxl'): + lay = lora_blocks.layout() + assert lay is not None and lay['n'] == 20, f'layout={lay}' + cases = { + 'lora_unet_down_blocks_1_attentions_0_transformer_blocks_3_attn1_to_v': 5, + 'lora_unet_mid_block_attentions_0_transformer_blocks_9_norm3': 10, + 'lora_unet_up_blocks_0_resnets_0_conv1': 11, + 'lora_unet_up_blocks_2_resnets_2_conv1': 19, + 'lora_unet_add_embedding_linear_1': 0, + 'lora_te1_text_model_encoder_layers_0_self_attn_k_proj': 0, + 'lora_te2_text_projection': 0, + } + for key, expected in cases.items(): + got = lora_blocks.block_index(key) + assert got == expected, f'{key}: got {got} expected {expected}' + return True + + +def test_block_index_flux_chains_concatenate(): + with block_model('f1'): + lay = lora_blocks.layout() + assert lay is not None and lay['n'] == 58, f'layout={lay}' # 19 double + 38 single + BASE + cases = { + 'lora_transformer_transformer_blocks_0_attn_to_q': 1, + 'lora_transformer_transformer_blocks_18_ff_net_0_proj': 19, + 'lora_transformer_single_transformer_blocks_0_attn_to_q': 20, + 'lora_transformer_single_transformer_blocks_37_proj_out': 57, + 'lora_transformer_x_embedder': 0, + 'lora_transformer_proj_out': 0, + } + for key, expected in cases.items(): + got = lora_blocks.block_index(key) + assert got == expected, f'{key}: got {got} expected {expected}' + return True + + +def test_block_index_anchoring_krea2_and_chroma(): + with block_model('krea2'): + lay = lora_blocks.layout() + assert lay is not None and lay['n'] == 29, f'layout={lay}' # txtfusion chains stay uncounted + assert lora_blocks.block_index('lora_transformer_blocks_5_attn_wq') == 6 + assert lora_blocks.block_index('lora_transformer_txtfusion_layerwise_blocks_0_attn_wq') == 0 + assert lora_blocks.block_index('lora_transformer_txtfusion_refiner_blocks_1_mlp_down') == 0 + with block_model('chroma'): + assert lora_blocks.block_index('lora_transformer_transformer_blocks_0_attn_to_q') == 1 + assert lora_blocks.block_index('lora_transformer_single_transformer_blocks_0_attn_to_q') == 20 # anchored: not the double chain's slot + assert lora_blocks.block_index('lora_transformer_distilled_guidance_layer_layers_0_linear_1') == 0 + return True + + +def test_block_index_namespace_collisions(): + with block_model('anima'): + assert lora_blocks.block_index('lora_transformer_transformer_blocks_5_attn1_to_q') == 6 + assert lora_blocks.block_index('lora_te_layers_0_self_attn_q_proj') is None, 'anima TE strips to the zimage pattern; the namespace must win' + assert lora_blocks.block_index('lora_llm_adapter_blocks_0_self_attn_q_proj') is None, 'anima llm_adapter strips to the krea2 pattern; the namespace must win' + from types import SimpleNamespace + muted = SimpleNamespace(name='m', block_spec='NONE') + assert lora_blocks.factor('lora_te_layers_0_self_attn_q_proj', muted) == 1.0, 'namespaces outside the vector stay neutral even under an all-zero spec' + return True + + +def test_unet_arithmetic_matches_conversion_map(): + from modules.lora import lora_convert + with block_model('sd'): + n_in = lora_blocks.layout()['n_in'] + checked = 0 + for sd_key, hf_key in lora_convert.make_unet_conversion_map().items(): + if sd_key.startswith('input_blocks'): + expected = 1 + int(sd_key.split('_')[2]) + elif sd_key.startswith('output_blocks'): + expected = 2 + n_in + int(sd_key.split('_')[2]) + elif sd_key.startswith('middle_block'): + expected = 1 + n_in + elif sd_key.startswith('time_embed') or sd_key.startswith('label_emb'): + expected = 0 + elif sd_key.startswith('out_'): + expected = 25 + else: + continue + got = lora_blocks.block_index('lora_unet_' + hf_key) + assert got == expected, f'{sd_key} -> {hf_key}: got {got} expected {expected}' + checked += 1 + assert checked > 60, f'the map cross-check covered only {checked} entries' + return True + + +def test_resolve_preset_case_and_arch_guard(): + from modules.merging.merge_presets import BLOCK_WEIGHTS_PRESETS, SDXL_BLOCK_WEIGHTS_PRESETS + with block_model('sd'): + v = lora_blocks.resolve('grad_v') + assert v is not None and len(v) == 26 and v[0] == 1.0, 'preset BASE must be forced neutral' + assert v[1:] == [float(x) for x in BLOCK_WEIGHTS_PRESETS['GRAD_V'][1:]] + assert lora_blocks.resolve('SDXL_GRAD_V') is None, 'arch-tagged presets must not resolve elsewhere' + with block_model('sdxl'): + v = lora_blocks.resolve('GRAD_V') + assert v is not None and len(v) == 20 and v[0] == 1.0 + assert v[1:] == [float(x) for x in SDXL_BLOCK_WEIGHTS_PRESETS['SDXL_GRAD_V'][1:]], 'the SDXL_ table must serve the unprefixed name' + v = lora_blocks.resolve('RING08_5') + assert v is not None and len(v) == 20 and v[0] == 1.0, 'a 26-slot preset must resample onto the sdxl layout' + return True + + +def test_resolve_dit_resample_drops_base(): + from modules.merging.merge_presets import BLOCK_WEIGHTS_PRESETS + src = BLOCK_WEIGHTS_PRESETS['GRAD_A'] + with block_model('f1'): + v = lora_blocks.resolve('GRAD_A') + assert v is not None and len(v) == 58 + assert v[0] == 1.0, 'BASE is a unet concept and must not inherit the merge slot' + assert v[1] == float(src[1]) and v[-1] == float(src[-1]), 'resampling must keep the endpoints' + assert min(v[1:]) >= min(src[1:]) - 1e-9 and max(v[1:]) <= max(src[1:]) + 1e-9 + return True + + +def test_resolve_vector_length_policy(): + with block_model('sd'): + full = [round(0.01 * i, 2) for i in range(26)] + v = lora_blocks.resolve(','.join(str(x) for x in full)) + assert v == full, 'a canonical-length vector must pass through verbatim' + v = lora_blocks.resolve(','.join(str(x) for x in full[1:])) + assert v == [1.0] + full[1:], 'a base-less vector must gain a neutral BASE' + v = lora_blocks.resolve(','.join(['0.5'] * 17)) + assert v is not None and len(v) == 26 and v[0] == 0.5 and v[2] == 0.5 and v[13] == 0.5 and v[25] == 0.5, 'the a1111 17-slot layout must expand' + assert v[1] == 1.0 and v[14] == 1.0, 'slots the a1111 layout omits stay neutral' + assert lora_blocks.resolve(','.join(['1'] * 24)) is None, 'an unmatched length must be rejected' + with block_model('sdxl'): + v = lora_blocks.resolve(','.join(['0.25'] * 12)) + assert v is not None and len(v) == 20 and v[0] == 0.25 and v[5] == 0.25 and v[10] == 0.25 and v[16] == 0.25 + assert v[1] == 1.0 and v[7] == 1.0 and v[17] == 1.0 + return True + + +def test_resolve_scalar_and_classic(): + with block_model('sd'): + assert lora_blocks.resolve('0.5') == [0.5] * 26, 'a scalar must broadcast to every slot' + v = lora_blocks.resolve('INS') + assert v[0] == 1.0 and all(x == 1.0 for x in v[1:7]) and all(x == 0.0 for x in v[7:]), f'INS must cover the shallow input half: {v}' + v = lora_blocks.resolve('OUTALL') + assert v[0] == 1.0 and all(x == 0.0 for x in v[1:14]) and all(x == 1.0 for x in v[14:]), f'OUTALL must cover the output side: {v}' + assert lora_blocks.resolve('NONE') == [0.0] * 26 + assert lora_blocks.resolve('DOUBLE') is None, 'chain names need a two-chain arch' + with block_model('f1'): + v = lora_blocks.resolve('DOUBLE') + assert v[0] == 1.0 and all(x == 1.0 for x in v[1:20]) and all(x == 0.0 for x in v[20:]), 'DOUBLE must keep the double chain only' + v = lora_blocks.resolve('SINGLE') + assert all(x == 0.0 for x in v[1:20]) and all(x == 1.0 for x in v[20:]), 'SINGLE must keep the single chain only' + return True + + +def test_bad_value_warns_once_and_ignores(): + from types import SimpleNamespace + with block_model('sd'): + assert lora_blocks.resolve('bogus') is None + assert lora_blocks.resolve('1,2,3') is None + warned_n = len(lora_blocks.warned) + lora_blocks.resolve('bogus') + assert len(lora_blocks.warned) == warned_n, 'a repeated bad value must not warn again' + net = SimpleNamespace(name='b', block_spec='bogus') + assert lora_blocks.factor('lora_unet_conv_in', net) == 1.0, 'an unresolvable spec must leave the plain strength' + return True + + +def test_multiplier_folds_block_weight(): + layer = build_layer('uint4') + layer.network_layer_name = 'lora_transformer_transformer_blocks_3_attn_to_q' + A, B, D = make_delta() + net = make_net('blocky', layer, A, B, te_mult=0.5) + with block_model('sd3', lin=layer): + net.block_spec = sd3_spec(s4=0.5) # block 3 sits in slot 4 + Wdq0 = dq(layer) + activate(net) + rho = rho_of(dq(layer) - Wdq0, D) + assert abs(rho - 0.25) < 0.01, f'expected multiplier 0.5 x block 0.5, rho={rho:.4f}' + activate() + assert torch.equal(dq(layer), Wdq0), 'unload must restore bit-exact' + return True + + +def test_block_weight_zero_kills_layer_delta(): + layer_a = build_layer('uint4') + layer_a.network_layer_name = 'lora_transformer_transformer_blocks_3_attn_to_q' + layer_b = build_layer('uint4', seed=7) + layer_b.network_layer_name = 'lora_transformer_transformer_blocks_5_attn_to_q' + A1, B1, D1 = make_delta(seed=1) + A2, B2, D2 = make_delta(seed=2) + net = make_net('zeroed', layer_a, A1, B1) + nw = network.NetworkWeights(network_key=layer_b.network_layer_name, sd_key=layer_b.network_layer_name, + w={'lora_up.weight': B2.cpu(), 'lora_down.weight': A2.cpu()}, sd_module=layer_b) + net.modules[layer_b.network_layer_name] = network_lora.NetworkModuleLora(net, nw) + with block_model('sd3', a=layer_a, b=layer_b): + net.block_spec = sd3_spec(s4=0.0) # zero the slot of block 3; block 5 stays at 1 + Wa0, Wb0 = dq(layer_a), dq(layer_b) + activate(net) + rho_a = rho_of(dq(layer_a) - Wa0, D1) + rho_b = rho_of(dq(layer_b) - Wb0, D2) + assert abs(rho_a) < 0.01, f'a zero slot must null the layer delta, rho={rho_a:.4f}' + assert rho_b > 0.99, f'a neutral slot must apply in full, rho={rho_b:.4f}' + activate() + assert torch.equal(dq(layer_a), Wa0) and torch.equal(dq(layer_b), Wb0), 'restore must be bit-exact' + return True + + +def test_signature_suffix_inactive_and_changes(): + from modules.lora import extra_networks_lora + layer = build_layer('uint4') + A, B, _D = make_delta() + net = make_net('siggy', layer, A, B) + l_common.loaded_networks.clear() + l_common.loaded_networks.append(net) + try: + assert lora_blocks.signature() == '', 'no spec must leave the stamp signature untouched' + net.block_spec = 'GRAD_V' + s1 = lora_blocks.signature() + assert s1 == '|lbw=siggy:grad_v', f's1={s1}' + net.block_spec = ' Grad_A ' + assert lora_blocks.signature() == '|lbw=siggy:grad_a', 'the spec must normalize' + en = extra_networks_lora.ExtraNetworkLora() + plain = en.signature(['a'], [1.0], [[1.0] * 3]) + with_spec = en.signature(['a'], [1.0], [[1.0] * 3], ['GRAD_V']) + assert plain == [f'a:1.0:{[1.0] * 3}'], 'legacy signature strings must stay byte-identical without specs' + assert with_spec[0] == plain[0] + ':lbw=grad_v' + finally: + l_common.loaded_networks.clear() + return True + + +def test_factor_cache_invalidates_on_block_weight(): + import tempfile + layer = build_layer('uint4') + layer.network_layer_name = 'lora_transformer_transformer_blocks_3_attn_to_q' + with tempfile.TemporaryDirectory() as tmp: + with host_rank(64), host_cache(10, os.path.join(tmp, 'cache')), block_model('sd3', lin=layer): + net, _D = cache_fixture(tmp, layer) + activate(net) + up_full = layer.svd_up.detach().clone() + activate() + net.block_spec = sd3_spec(s4=0.5) + activate(net) # different block vector: different signature, fresh svd, second entry + assert not torch.equal(layer.svd_up, up_full), 'a block-weight change must produce different factors' + activate() + files = os.listdir(os.path.join(tmp, 'cache')) + assert len(files) == 2, f'two cache entries expected, got {files}' + return True + + +def test_stack_ties_respects_per_net_blocks(): + layer = build_layer('uint4') + layer.network_layer_name = 'lora_transformer_transformer_blocks_3_attn_to_q' + torch.manual_seed(31) + Da = torch.randn(OUT_F, IN_F, device=DEVICE) * 3e-4 + Db = torch.randn(OUT_F, IN_F, device=DEVICE) * 3e-4 + net_a = make_dense_net('tiesa', layer, Da) + net_b = make_dense_net('tiesb', layer, Db) + with host_rank(64), stack_mode('ties', dens=0.5), block_model('sd3', lin=layer): + Wdq0 = dq(layer) + activate(net_a, net_b) + d_both = (dq(layer) - Wdq0).clone() + activate() + net_b.block_spec = 'NONE' + activate(net_a, net_b) + d_muted = (dq(layer) - Wdq0).clone() + activate() + assert not torch.allclose(d_both, d_muted), 'muting one member must change the combined delta' + assert rho_of(d_muted, Db) < 0.1, f'the muted member must not contribute: rho={rho_of(d_muted, Db):.3f}' + assert rho_of(d_muted, Da) > 0.3, f'the live member must survive the trim: rho={rho_of(d_muted, Da):.3f}' + return True + + +def test_pending_promote_updates_block_spec(): + layer = build_layer('uint4') + layer.network_layer_name = 'lora_transformer_transformer_blocks_3_attn_to_q' + A, B, D = make_delta() + net = make_net('promoted', layer, A, B) + with block_model('sd3', lin=layer): + Wdq0 = dq(layer) + net.pending_config = {'te': 1.0, 'unet': [1.0] * 3, 'dyn': None, 'blocks': 'NONE'} + activate(net) + assert net.block_spec == 'NONE', 'network_activate must promote the staged spec' + rho = rho_of(dq(layer) - Wdq0, D) + assert abs(rho) < 0.01, f'the promoted all-zero vector must null the delta, rho={rho:.4f}' + activate() + net.pending_config = {'te': 1.0, 'unet': [1.0] * 3, 'dyn': None, 'blocks': None} + activate(net) + assert net.block_spec is None, 'a spec-less reload must clear the previous spec' + rho = rho_of(dq(layer) - Wdq0, D) + assert rho > 0.99, f'without a spec the delta must apply in full, rho={rho:.4f}' + activate() + assert torch.equal(dq(layer), Wdq0) + return True + + +def test_layout_recomputes_on_mapping_change(): + with block_model('f1'): + assert lora_blocks.layout()['n'] == 58 + assert lora_blocks.block_index('lora_transformer_transformer_blocks_18_attn_to_q') == 19 + shared.sd_model.network_layer_mapping = {'lora_transformer_transformer_blocks_9_attn_to_q': None} # new object: the stamp must miss + assert lora_blocks.layout()['n'] == 11 + assert lora_blocks.block_index('lora_transformer_transformer_blocks_9_attn_to_q') == 10 + assert lora_blocks.block_index('lora_transformer_transformer_blocks_18_attn_to_q') == 0, 'an index past the scanned chain folds to BASE' + return True + + +def run_tests(): + t0 = time.time() + log.warning('=== Erasure law ===') + for fn in [test_uint4_erases_substep_delta, test_int8_retains_delta]: + run_test(CAT_LAW, fn) + log.warning('=== Factor path ===') + for fn in [test_apply_exact_and_remove_bitexact, test_multiplier_and_alpha_scaling, test_stacking_two_networks, test_matmul_layout_transposed, test_dora_falls_back, test_no_hadamard_checkpoint, test_checkpoint_svd_factors_preserved]: + run_test(CAT_FACTOR, fn) + log.warning('=== Memory accounting ===') + for fn in [test_factor_path_memory_is_factors_only, test_backup_mode_clones_full_quant_state, test_fuse_mode_marker_takes_no_memory]: + run_test(CAT_MEM, fn) + log.warning('=== Activate integration ===') + for fn in [test_network_activate_roundtrip]: + run_test(CAT_E2E, fn) + log.warning('=== Set transitions ===') + for fn in [test_mixed_family_transition_restores_base, test_partial_coverage_layers_stay_independent, + test_apply_restore_preserves_weight_storage, test_fuse_promote_applies_new_multiplier, test_fuse_change_then_remove_restores_pristine, + test_mechanism_gate_declines_candidates, test_requantize_option_routes_to_legacy_path, + test_mechanism_flip_strips_attached_factors, test_mechanism_flip_restore_pass_strips]: + run_test(CAT_TRANS, fn) + log.warning('=== Hosting ===') + for fn in [test_hosted_low_rank_delta_is_kept, test_hosted_dense_delta_beats_requant, test_hosted_skips_int8, + test_hosted_disabled_by_option, test_hosted_transitions_and_rng_isolation, + test_route_fat_dense_delta_requantizes, test_declined_host_delta_is_not_recomputed, test_pass_presents_one_wanted_names_tuple, + test_route_rule_terms_gate_both_ways, test_route_codebook_layer_uses_level_gap, test_route_low_rank_fat_delta_stays_hosted, + test_route_mixed_set_keeps_hosting, test_route_svd_checkpoint_keeps_hosting, test_route_dense_stack_keeps_hosting, + test_route_replay_from_cache, test_hosted_null_tail_collapses_to_effective_rank, test_hosted_flat_spectrum_keeps_cap]: + run_test(CAT_HOST, fn) + log.warning('=== Calibration ===') + for fn in [test_calibrated_hosting_beats_plain, test_calibrated_low_rank_delta_survives, test_calib_option_off_matches_plain, + test_calib_capture_persist_roundtrip, test_calib_capture_gates, test_calib_deadline_persists_starved_layers, + test_calib_deadline_omits_subfloor_layers, test_calib_unet_root_walk]: + run_test(CAT_CALIB, fn) + log.warning('=== Factor cache ===') + for fn in [test_factor_cache_roundtrip_bitexact, test_factor_cache_invalidates_on_multiplier, + test_factor_cache_int8_quantization, test_factor_cache_disabled_at_zero, test_factor_cache_invalidates_on_calib_toggle, + test_cache_fastpath_skips_calc, test_cache_fastpath_serves_mixed_set, test_cache_fastpath_serves_dense_pair, + test_attach_trims_stored_null_tail]: + run_test(CAT_FCACHE, fn) + log.warning('=== Stack modes: dense ===') + for fn in [test_ties_sign_consensus_drops_conflicts, test_dare_mask_is_deterministic_across_calls, test_dare_rescales_by_inverse_density, + test_magnitude_prune_keeps_top_density, test_dense_two_plain_loras_hosted_not_summed, + test_dense_pair_hosts_at_int8, test_dense_single_nonfactorable_int8_keeps_requantize, test_single_net_ignores_dense_mode, + test_te_layer_stays_plain_sum, test_sum_mode_keeps_exact_stacking]: + run_test(CAT_STACK, fn) + log.warning('=== Stack modes: select ===') + for fn in [test_select_flip_schedule_end_to_end, test_select_initial_style_when_ramp_starts_won, test_estlora_energy_balance_defeats_magnitude, test_select_flip_is_inplace_and_shape_stable, + test_select_matmul_transposed_layout, test_select_per_net_hosted_pair, test_select_reset_restores_initial_state, + test_select_deactivate_from_midflip, test_select_requires_exactly_two_nets, test_select_gated_off_when_compiled, + test_select_finalize_drops_dead_module, test_select_int8_pair_rides_segments, test_select_gate_dormant_without_pair, test_stale_schedule_dropped_on_reapply, + test_est_energy_matches_full_frobenius, test_select_weight_kind_plain_layer, + test_select_gamma_tracks_live_entries, test_select_host_disabled_falls_back_to_sum, test_degradation_warning_rearms_on_settings_change, test_flip_lands_before_crossover_step, + test_score_pair_chunked_precision, test_select_replay_from_cache_skips_calc, test_select_weight_replay_from_cache_skips_calc, + test_select_reset_reports_timing, test_select_weight_flip_calcs_on_accelerator]: + run_test(CAT_SELECT, fn) + log.warning('=== Compile ===') + for fn in [test_factor_add_inside_compiled_graph, test_rank_bucket_graph_reuse, test_recompile_wall_resets_on_unload]: + run_test(CAT_COMPILE, fn) + log.warning('=== Robustness ===') + for fn in [test_remove_factors_after_device_move, test_stacked_shape_mismatch_falls_back, test_nunchaku_entries_carry_the_network_interface, + test_four_dim_oft_blocks_load_as_boft, test_aborted_pass_still_publishes_its_state, + test_native_dispatch_archs_are_native_eligible]: + run_test(CAT_ROBUST, fn) + log.warning('=== Block weights ===') + for fn in [test_block_index_sd_unet_layout, test_block_index_sdxl_unet_layout, test_block_index_flux_chains_concatenate, + test_block_index_anchoring_krea2_and_chroma, test_block_index_namespace_collisions, test_unet_arithmetic_matches_conversion_map, + test_resolve_preset_case_and_arch_guard, test_resolve_dit_resample_drops_base, test_resolve_vector_length_policy, + test_resolve_scalar_and_classic, test_bad_value_warns_once_and_ignores, test_multiplier_folds_block_weight, + test_block_weight_zero_kills_layer_delta, test_signature_suffix_inactive_and_changes, test_factor_cache_invalidates_on_block_weight, + test_stack_ties_respects_per_net_blocks, test_pending_promote_updates_block_spec, test_layout_recomputes_on_mapping_change]: + run_test(CAT_BLOCKS, fn) + + elapsed = time.time() - t0 + log.warning('=== Results ===') + total_pass = total_fail = 0 + for cat, info in results.items(): + status = 'PASS' if info['failed'] == 0 else 'FAIL' + log.info(f' {cat}: {info["passed"]} passed, {info["failed"]} failed [{status}]') + total_pass += info['passed'] + total_fail += info['failed'] + log.warning(f'Total: {total_pass} passed, {total_fail} failed in {elapsed:.2f}s') + return total_fail == 0 + + +if __name__ == '__main__': + with torch.inference_mode(): + ok = run_tests() + sys.exit(0 if ok else 1) diff --git a/test/test-ui-choice-filters.py b/test/test-ui-choice-filters.py new file mode 100644 index 000000000..fa5600aff --- /dev/null +++ b/test/test-ui-choice-filters.py @@ -0,0 +1,42 @@ +"""CPU-only regression coverage for display-only sampler and upscaler filters.""" + +import pathlib +import sys +import unittest + +sys.path.insert(0, str(pathlib.Path(__file__).resolve().parents[1])) +from modules.ui_common import filter_ui_choices + + +class TestUiChoiceFilters(unittest.TestCase): + def setUp(self): + self.choices = ['Default', 'Euler', 'DPM++ 2M', 'Lanczos'] + + def test_empty_preferences_leave_choices_unfiltered(self): + visible, filtered = filter_ui_choices(self.choices, []) + self.assertEqual(visible, self.choices) + self.assertFalse(filtered) + + def test_preferences_filter_only_current_catalog_choices(self): + visible, filtered = filter_ui_choices(self.choices, ['Euler', 'Lanczos']) + self.assertEqual(visible, ['Euler', 'Lanczos']) + self.assertTrue(filtered) + + def test_stale_preferences_do_not_hide_the_catalog(self): + visible, filtered = filter_ui_choices(self.choices, ['Removed sampler']) + self.assertEqual(visible, self.choices) + self.assertFalse(filtered) + + def test_saved_selection_remains_available_when_not_preferred(self): + visible, filtered = filter_ui_choices(self.choices, ['Euler'], selected='DPM++ 2M') + self.assertEqual(visible, ['Euler', 'DPM++ 2M']) + self.assertTrue(filtered) + + def test_none_remains_the_first_choice(self): + visible, filtered = filter_ui_choices(['Lanczos', 'None', 'Nearest'], ['Lanczos'], selected='None') + self.assertEqual(visible, ['None', 'Lanczos']) + self.assertTrue(filtered) + + +if __name__ == '__main__': + unittest.main() diff --git a/test/test-vdm-scheduler.py b/test/test-vdm-scheduler.py new file mode 100644 index 000000000..413c20ee7 --- /dev/null +++ b/test/test-vdm-scheduler.py @@ -0,0 +1,39 @@ +import os +import sys + +import pytest +import torch + + +sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "../"))) + +from modules.schedulers.scheduler_vdm import VDMScheduler + + +def _assert_timestep_spacing(spacing: str, num_steps: int) -> None: + scheduler = VDMScheduler(timestep_spacing=spacing) + scheduler.set_timesteps(num_steps) + timesteps = scheduler.timesteps + + if spacing == "leading": + expected = torch.arange(num_steps - 1, -1, -1, dtype=timesteps.dtype) / num_steps + else: + expected = torch.arange(num_steps, 0, -1, dtype=timesteps.dtype) / num_steps + + assert len(timesteps) == num_steps + assert torch.all((0 <= timesteps) & (timesteps <= 1)) + if num_steps > 1: + assert torch.all(timesteps[1:] < timesteps[:-1]) + torch.testing.assert_close(timesteps, expected, rtol=0, atol=1e-7) + + +@pytest.mark.parametrize("spacing", ["leading", "trailing"]) +@pytest.mark.parametrize("num_steps", [1, 2, 4, 49, 1000]) +def test_timestep_spacing(spacing: str, num_steps: int) -> None: + _assert_timestep_spacing(spacing, num_steps) + + +if __name__ == "__main__": + for test_spacing in ("leading", "trailing"): + for test_num_steps in (1, 2, 4, 49, 1000): + _assert_timestep_spacing(test_spacing, test_num_steps) diff --git a/test/test-xyz-attention.py b/test/test-xyz-attention.py new file mode 100644 index 000000000..2f3f65914 --- /dev/null +++ b/test/test-xyz-attention.py @@ -0,0 +1,224 @@ +#!/usr/bin/env python +""" +Offline unit tests for the attention and sparse axes of the xyz grid. + +Covers: + +- every [Attention] and [Sparse] axis resolves its choices and targets a registered option +- applying an axis and then leaving the grid restores shared.opts.data exactly, keys the axis + introduced included, so a grid never leaks its last cell into the session +- the axes backed by boolean options take the string the dropdown hands them +- the sdp override axis turns a label, a plus joined pair or None into the option's list +- an override axis apply reaches the router: the rebuilt chain contains the backend it named +- the restore set covers every setting the sparse stage reads + +No running server required. Nothing is moved to the accelerator, and no axis value that would +install a package is used. + +Usage: + python test/test-xyz-attention.py +""" + +import os +import sys + +import torch + +script_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) +sys.path.insert(0, script_dir) +os.chdir(script_dir) + +os.environ['SD_INSTALL_QUIET'] = '1' + +# Bootstrap cmd_args before any module that pulls in shared.py. +import modules.cmd_args # pylint: disable=wrong-import-position +import installer # pylint: disable=wrong-import-position +orig_argv = sys.argv +sys.argv = [sys.argv[0]] +try: + modules.cmd_args.parse_args() +finally: + sys.argv = orig_argv +installer.add_args(modules.cmd_args.parser) +modules.cmd_args.parsed, _ = modules.cmd_args.parser.parse_known_args([]) + +stock_sdpa = torch.nn.functional.scaled_dot_product_attention # importing shared installs the configured hijacks in-process + +from modules.errors import log # pylint: disable=wrong-import-position +from modules import attention, shared # pylint: disable=wrong-import-position +from modules.attention.sparse import stage as sparse_stage # pylint: disable=wrong-import-position +from scripts.xyz import xyz_grid_shared as xyz # pylint: disable=wrong-import-position +from scripts.xyz.xyz_grid_classes import axis_options # pylint: disable=wrong-import-position + + +results: dict[str, dict] = {} + + +def category(name: str): + if name not in results: + results[name] = {'passed': 0, 'failed': 0, 'tests': []} + return name + + +def record(cat: str, passed: bool, name: str, detail: str = ''): + status = 'PASS' if passed else 'FAIL' + results[cat]['passed' if passed else 'failed'] += 1 + results[cat]['tests'].append((status, name)) + msg = f' {status}: {name}' + if detail: + msg += f' ({detail})' + if passed: + log.info(msg) + else: + log.error(msg) + + +def run_test(cat: str, fn): + try: + ok = fn() + record(cat, ok is not False, fn.__name__) + except AssertionError as e: + record(cat, False, fn.__name__, str(e)) + except Exception as e: # pylint: disable=broad-except + record(cat, False, fn.__name__, f'exception: {e}') + import traceback + traceback.print_exc() + + +def attention_axes(): + return [axis for axis in axis_options if axis.label.startswith('[Attention]') or axis.label.startswith('[Sparse]')] + + +def sample_value(axis): + """A value the axis accepts that is not the current one, avoiding backends whose prepare installs a package.""" + if axis.choices is None: + return int(shared.opts.get(option_of(axis) or 'sparse_attention_budget') or 0) + 5 + choices = [choice for choice in axis.choices() if choice not in ['Sage attention', 'Flash attention', 'Triton AMD Flash attention']] + current = str(shared.opts.get(option_of(axis)) if option_of(axis) else '') + return next((choice for choice in choices if str(choice) != current), choices[0]) + + +def option_of(axis): + """The option an axis writes, read back from the closure the axis factory built.""" + closure = getattr(axis.apply, '__closure__', None) or () + for cell in closure: + if isinstance(cell.cell_contents, str) and cell.cell_contents in shared.opts.data_labels: + return cell.cell_contents + return {'[Attention] SDP override': 'sdp_overrides', '[Attention] Dispatcher': 'hf_attention'}.get(axis.label, None) + + +def bool_axes(): + return [axis for axis in attention_axes() if isinstance(shared.opts.get(option_of(axis) or ''), bool)] + + +# ============================================================ +# Tests +# ============================================================ + +def test_axes_are_registered(): + axes = attention_axes() + assert len(axes) >= 10, f'only {len(axes)} attention axes' + for axis in axes: + option = option_of(axis) + assert option is not None, f'{axis.label} names no option' + assert option in shared.opts.data_labels, f'{axis.label} targets unknown option {option}' + return True + + +def test_axis_choices_resolve(): + for axis in attention_axes(): + if axis.choices is None: + assert axis.type is int, f'{axis.label} has no choices and is not numeric' + continue + choices = axis.choices() + assert isinstance(choices, list) and len(choices) > 0, f'{axis.label} resolved {choices}' + return True + + +def test_axes_write_and_restore_exactly(): + for axis in attention_axes(): + before = dict(shared.opts.data) + saved = xyz.save_attention() + axis.apply(None, sample_value(axis), []) + assert dict(shared.opts.data) != before, f'{axis.label} wrote nothing' + xyz.restore_attention(saved) + after = dict(shared.opts.data) + leaked = {key for key in set(before) | set(after) if before.get(key, '') != after.get(key, '')} + assert not leaked, f'{axis.label} leaked {sorted(leaked)}' + return True + + +def test_bool_axes_coerce_the_string_the_dropdown_sends(): + axes = bool_axes() + assert len(axes) >= 3, f'only {len(axes)} boolean axes' + for axis in axes: + option = option_of(axis) + saved = xyz.save_attention() + axis.apply(None, 'True', []) + assert shared.opts.data[option] is True, f'{axis.label} took "True" as {shared.opts.data[option]!r}' + axis.apply(None, 'False', []) + assert shared.opts.data[option] is False, f'{axis.label} took "False" as {shared.opts.data[option]!r}' + xyz.restore_attention(saved) + return True + + +def test_dispatcher_axis_clears_on_none(): + saved = xyz.save_attention() + try: + xyz.apply_attention_dispatcher(None, 'native', []) + assert shared.opts.data['hf_attention'] == 'native', shared.opts.data['hf_attention'] + xyz.apply_attention_dispatcher(None, 'None', []) + assert shared.opts.data['hf_attention'] == '', repr(shared.opts.data['hf_attention']) + finally: + xyz.restore_attention(saved) + return True + + +def test_restore_set_covers_every_attention_setting(): + covered = set(xyz.attention_options()) + missing = set(sparse_stage.OPTION_NAMES) - covered + assert not missing, f'sparse settings outside the restore set: {sorted(missing)}' + for backend in attention.registry.backends.values(): + outside = set(backend.options) - covered + assert not outside, f'{backend.label} settings outside the restore set: {sorted(outside)}' + return True + + +def run_all(): + log.warning('=== xyz attention axes ===') + cat = category('axes') + for fn in [ + test_axes_are_registered, + test_axis_choices_resolve, + ]: + run_test(cat, fn) + + log.warning('=== apply and restore ===') + cat = category('apply') + for fn in [ + test_axes_write_and_restore_exactly, + test_bool_axes_coerce_the_string_the_dropdown_sends, + test_dispatcher_axis_clears_on_none, + test_restore_set_covers_every_attention_setting, + ]: + run_test(cat, fn) + + log.warning('=== Results ===') + total_passed = 0 + total_failed = 0 + for cat_name, info in results.items(): + status = 'PASS' if info['failed'] == 0 else 'FAIL' + log.info(f" {cat_name}: {info['passed']} passed, {info['failed']} failed [{status}]") + total_passed += info['passed'] + total_failed += info['failed'] + log.warning(f'Total: {total_passed} passed, {total_failed} failed') + return total_failed == 0 + + +if __name__ == '__main__': + import time + t0 = time.time() + ok = run_all() + torch.nn.functional.scaled_dot_product_attention = stock_sdpa + log.warning(f'Total time: {time.time() - t0:.2f}s') + sys.exit(0 if ok else 1) diff --git a/test/test-zimage-native-adapters.py b/test/test-zimage-native-adapters.py index 77004d18e..d7d799694 100644 --- a/test/test-zimage-native-adapters.py +++ b/test/test-zimage-native-adapters.py @@ -456,8 +456,8 @@ def test_parse_key_all_prefixes(): """parse_key recognizes BFL, PEFT, kohya, and bare-diffusers keys. Returns (prefix_used, base, suffix) - prefix_used is the matched - KNOWN_PREFIXES element, BARE_DIFFUSERS_PREFIX_USED for bare paths - matching BARE_DIFFUSERS_PREFIXES, or None when no prefix is recognized. + KNOWN_PREFIXES element, BARE_DIFFUSERS_PREFIX_USED for any other bare + path, or None when no suffix is recognized. """ bd = Z.BARE_DIFFUSERS_PREFIX_USED cases = [ diff --git a/ui/autocomplete.ts b/ui/autocomplete.ts index 51f7338e2..e96068e95 100644 --- a/ui/autocomplete.ts +++ b/ui/autocomplete.ts @@ -239,7 +239,7 @@ const engine = { await Promise.all(toLoad.map(async (name) => { try { const resp = await authFetch(`${window.api}/autocomplete/${name}`); - if (!resp.ok) throw new Error(`${resp.status}`); + if (!resp?.ok) throw new Error(`${resp?.status}`); const data = await resp.json(); this.indices.set(name, new TagIndex(data)); // Extract category colors from first loaded file diff --git a/ui/autocomplete_xn.ts b/ui/autocomplete_xn.ts index 78d38fe36..1b6c77af4 100644 --- a/ui/autocomplete_xn.ts +++ b/ui/autocomplete_xn.ts @@ -88,7 +88,7 @@ export const xnEngine: XnEngine = { try { // const resp = await fetch(`${window.api}${path}`, { credentials: 'include' }); const resp = await authFetch(`${window.api}${path}`); - if (!resp.ok) throw new Error(`${resp.status}`); + if (!resp?.ok) throw new Error(`${resp?.status}`); return await resp.json(); } catch (e) { log('autoComplete', { xnFetchFailed: path, error: String(e) }); @@ -108,19 +108,27 @@ export const xnEngine: XnEngine = { this.lora = new XnIndex(items); } // Embeddings: {loaded: [...], skipped: [...]} - const embData = await this.fetchJson('/embeddings') as Record | null; - if (embData && typeof embData === 'object') { - const loaded = Array.isArray(embData.loaded) ? embData.loaded : []; - this.embed = new XnIndex(loaded.map((name) => ({ name: String(name) }))); + if (window.opts.diffusers_enable_embed) { + const embData = await this.fetchJson('/embeddings') as Record | null; + if (embData && typeof embData === 'object') { + const loaded = Array.isArray(embData.loaded) ? embData.loaded : []; + this.embed = new XnIndex(loaded.map((name) => ({ name: String(name) }))); + } + } else { + this.embed = new XnIndex([]); } // Wildcards: [{name}, ...] - const wcData = await this.fetchJson('/wildcards'); - if (Array.isArray(wcData)) { - this.wildcard = new XnIndex( - wcData - .filter((w) => typeof w === 'object' && w && 'name' in w && typeof w.name === 'string') - .map((w) => ({ name: w.name })), - ); + if (window.opts.wildcards_enabled) { + const wcData = await this.fetchJson('/wildcards'); + if (Array.isArray(wcData)) { + this.wildcard = new XnIndex( + wcData + .filter((w) => typeof w === 'object' && w && 'name' in w && typeof w.name === 'string') + .map((w) => ({ name: w.name })), + ); + } + } else { + this.wildcard = new XnIndex([]); } log('autoComplete', { xnLoaded: true, diff --git a/ui/civitai.ts b/ui/civitai.ts index 5c1933a5c..82f376a84 100644 --- a/ui/civitai.ts +++ b/ui/civitai.ts @@ -2,11 +2,21 @@ import { gradioApp, onUiLoaded } from './script'; import { log, error } from './logger'; import { authFetch } from './authWrap'; +interface CivitFileMetadata { + fp?: string | null; + format?: string | null; + size?: string | null; + quantType?: string | null; +} + interface CivitFile { + id: number; url?: string; name?: string; type?: string; size?: number; + primary?: boolean; + metadata?: CivitFileMetadata; } interface CivitImage { @@ -39,6 +49,11 @@ interface CivitModel { versions: CivitVersion[]; } +interface QueuedFile { + version: CivitVersion; + file: CivitFile; +} + // eslint-disable-next-line no-extend-native String.prototype.format = function format(this: string, args: Record): string { let thisString = ''; @@ -56,6 +71,10 @@ let selectedType: string[] = []; let selectedBase: string[] = []; let selectedModelId: number[] = []; let selectedVersionId: number[] = []; +let currentModel: CivitModel | null = null; + +const precisionOrder = ['fp32', 'bf16', 'fp16', 'fp8', 'int8', 'int4']; +const companionTypes = ['VAE', 'Text Encoder']; export function clearModelDetails() { const el = gradioApp().getElementById('model-details') || gradioApp().getElementById('civitai_models_output') || gradioApp().getElementById('models_outcome'); @@ -88,6 +107,7 @@ const modelDetailsHTML = ` Type Base File + Variant Updated Size Availability @@ -101,19 +121,72 @@ const modelDetailsHTML = `
`; -const modelVersionsHTML = ` - - {url} - {name} - {type} - {base} - {file} - {mtime} - {size} - {availability} -
{desc}
- -`; +function fileVariant(file: CivitFile): string | null { + return file.metadata?.fp || file.metadata?.quantType || null; +} + +// Model files before companions, then by precision, then larger first +function sortFiles(files: CivitFile[]): CivitFile[] { + const isModel = (f: CivitFile) => f.type === 'Model' || f.type === 'Pruned Model'; + const rank = (f: CivitFile) => { + const index = precisionOrder.indexOf((fileVariant(f) || '').toLowerCase()); + return index < 0 ? precisionOrder.length : index; + }; + return [...files].sort((a, b) => Number(isModel(b)) - Number(isModel(a)) || rank(a) - rank(b) || (b.size || 0) - (a.size || 0)); +} + +function insertNameSuffix(name: string, suffix: string): string { + const dot = name.lastIndexOf('.'); + return dot > 0 ? `${name.slice(0, dot)}-${suffix}${name.slice(dot)}` : `${name}-${suffix}`; +} + +// Precision suffix, then full/pruned and the file id only as far as needed to stay unique within the version +function fileSaveName(file: CivitFile, siblings: CivitFile[]): string { + const tier1 = (f: CivitFile) => { + const variant = fileVariant(f); + return variant ? insertNameSuffix(f.name || '', variant) : f.name || ''; + }; + const tier2 = (f: CivitFile) => (f.metadata?.size ? insertNameSuffix(tier1(f), f.metadata.size) : tier1(f)); + const others = siblings.filter((s) => s.id !== file.id); + const name = tier1(file); + if (!others.some((s) => tier1(s) === name)) return name; + const sized = tier2(file); + if (!others.some((s) => tier2(s) === sized)) return sized; + return insertNameSuffix(name, String(file.id)); +} + +function escapeHTML(text: string): string { + return text.replace(/[&<>"']/g, (c) => `&#${c.charCodeAt(0)};`); +} + +function versionRows(version: CivitVersion, divider: boolean): string { + const files = sortFiles(version.files); + const entries: (CivitFile | null)[] = files.length > 0 ? files : [null]; + const border = divider ? ' style="border-top: 1px solid var(--sd-panel-border-color, #555)"' : ''; + const span = entries.length > 1 ? ` rowspan="${entries.length}"` : ''; + const versionCell = (content: string) => `${content}`; + return entries.map((file, i) => { + const first = i === 0; + const cell = (content: string) => `${content}`; + const link = file ? `` : ''; + const name = file ? `${escapeHTML(file.name || 'unknown')}${file.primary ? ' ' : ''}` : 'unknown'; + const variant = file ? [fileVariant(file), file.metadata?.size].filter(Boolean).join(' · ') : ''; + const size = file?.size ? `${(file.size / 1024 / 1024 / 1024).toFixed(2)} GB` : 'unknown'; + const cells = [ + cell(link), + first ? versionCell(escapeHTML(version.name || 'unknown')) : '', + cell(escapeHTML(file?.type || 'unknown')), + first ? versionCell(escapeHTML(version.base || 'unknown')) : '', + cell(name), + cell(escapeHTML(variant || '-')), + first ? versionCell((new Date(version.mtime)).toLocaleDateString()) : '', + cell(size), + first ? versionCell(escapeHTML(version.availability || 'unknown')) : '', + first ? versionCell(`
${version.desc || 'no description available'}
`) : '', + ]; + return `${cells.join('')}`; + }).join(''); +} export async function modelCardClick(id) { log('modelCardClick id', id); @@ -128,18 +201,9 @@ export async function modelCardClick(id) { log('modelCardClick data', dataArray); if (!dataArray || dataArray.length === 0) return; const data: any = dataArray[0]; // assuming the first item is the one we want + currentModel = data; - const versionsHTML = data.versions.map((v: CivitVersion) => modelVersionsHTML.format({ - url: ``, - name: v.name || 'unknown', - type: v.files[0]?.type || 'unknown', - base: v.base || 'unknown', - mtime: (new Date(v.mtime)).toLocaleDateString(), - availability: v.availability || 'unknown', - size: v.files[0]?.size ? `${(v.files[0].size / 1024 / 1024).toFixed(2)} MB` : 'unknown', - file: `${v.files[0]?.name || 'unknown'}`, - desc: v.desc || 'no description available', - })).join(''); + const versionsHTML = data.versions.map((v: CivitVersion, i: number) => versionRows(v, i > 0)).join(''); const url = `${data.name || 'unknown'}`; const creator = `${data.creator || 'unknown'}`; const images = data.versions.map((v: CivitVersion) => v.images).flat().map((i: CivitImage) => i.url); // TODO image gallery @@ -160,42 +224,33 @@ export async function modelCardClick(id) { } window.modelCardClick = modelCardClick; -export function startCivitDownload(url, name, type, base, modelId, versionId) { - log('startCivitDownload', { url, name, type, base, modelId, versionId }); - selectedURL = [url]; - selectedName = [name]; - selectedType = [type]; - selectedBase = [base || '']; - selectedModelId = [modelId || 0]; - selectedVersionId = [versionId || 0]; +function queueFiles(model: CivitModel, queued: QueuedFile[]) { + selectedURL = queued.map(({ file }) => file.url || ''); + selectedName = queued.map(({ version, file }) => fileSaveName(file, version.files)); + selectedType = queued.map(({ file }) => (companionTypes.includes(file.type || '') ? file.type : model.type) || ''); + selectedBase = queued.map(({ version }) => version.base || ''); + selectedModelId = queued.map(() => model.id || 0); + selectedVersionId = queued.map(({ version }) => version.id || 0); const civitDownloadBtn = gradioApp().getElementById('civitai_download_btn'); if (civitDownloadBtn) civitDownloadBtn.click(); } -window.startCivitDownload = startCivitDownload; + +export function startCivitFileDownload(versionId: number, fileId: number) { + log('startCivitFileDownload', { versionId, fileId }); + const version = currentModel?.versions.find((v) => v.id === versionId); + const file = version?.files.find((f) => f.id === fileId); + if (!currentModel || !version || !file) return; + queueFiles(currentModel, [{ version, file }]); +} +window.startCivitFileDownload = startCivitFileDownload; export function startCivitAllDownload(evt) { log('startCivitAllDownload', evt); - const table = gradioApp().getElementById('model-versions-table'); - if (!table) return; - const versions = table.querySelectorAll('tr'); - selectedURL = []; - selectedName = []; - selectedType = []; - selectedBase = []; - selectedModelId = []; - selectedVersionId = []; - for (const version of versions) { - const parsed = version.querySelector('td:nth-child(1) div')?.getAttribute('onclick')?.match(/startCivitDownload\('([^']+)', '([^']+)', '([^']+)', '([^']*)', (\d+), (\d+)\)/); - if (!parsed || parsed.length < 7) continue; - selectedURL.push(parsed[1]); - selectedName.push(parsed[2]); - selectedType.push(parsed[3]); - selectedBase.push(parsed[4]); - selectedModelId.push(parseInt(parsed[5], 10)); - selectedVersionId.push(parseInt(parsed[6], 10)); - } - const civitDownloadBtn = gradioApp().getElementById('civitai_download_btn'); - if (civitDownloadBtn) civitDownloadBtn.click(); + if (!currentModel) return; + const queued = currentModel.versions + .map((version) => ({ version, file: version.files.find((f) => f.primary) || version.files[0] })) + .filter((entry): entry is QueuedFile => !!entry.file); + queueFiles(currentModel, queued); } window.startCivitAllDownload = startCivitAllDownload; diff --git a/ui/css/base.css b/ui/css/base.css index 3a0e0e9c1..213d297b3 100644 --- a/ui/css/base.css +++ b/ui/css/base.css @@ -1,4 +1,5 @@ -@font-face { font-family: 'NotoSans'; font-display: swap; font-style: normal; font-weight: 100; src: local('NotoSansNerd'), url('fonts/notosans-nerdfont-regular.ttf') } +@font-face { font-family: 'NotoSans'; font-display: swap; font-style: normal; font-weight: 100; src: local('NotoSansNerd'), url('notosans-nerdfont-regular.ttf') } +@font-face { font-family: 'Ubuntu'; font-display: swap; font-style: normal; font-weight: 100; src: local('Ubuntu'), url('ubuntu-nerdfont.ttf') } /* toolbutton */ .gradio-button.tool { max-width: min-content; min-width: min-content !important; align-self: end; font-size: 1.4em; color: var(--body-text-color) !important; } @@ -32,7 +33,7 @@ /* fullpage image viewer */ #lightboxModal { display: none; position: fixed; z-index: 1001; left: 0; top: 0; width: 100%; height: 100%; overflow: auto; background-color: rgba(20, 20, 20, 0.75); backdrop-filter: blur(6px); - user-select: none; -webkit-user-select: none; flex-direction: row; font-family: 'NotoSans'; } + user-select: none; -webkit-user-select: none; flex-direction: row; font-family: 'Ubuntu'; } .modalControls { display: flex; justify-content: space-evenly; background-color: transparent; position: absolute; width: 99%; z-index: 1; } .modalControls:hover { background-color: #50505050; } .modalControls span { color: white; font-size: 2em; font-weight: bold; cursor: pointer; filter: grayscale(100%); } diff --git a/ui/css/black-gray.css b/ui/css/black-gray.css index de4e78530..b8a5a439d 100644 --- a/ui/css/black-gray.css +++ b/ui/css/black-gray.css @@ -1,5 +1,5 @@ /* generic html tags */ -@font-face { font-family: 'NotoSans'; font-display: swap; font-style: normal; font-weight: 100; src: local('NotoSansNerd'), url('fonts/notosans-nerdfont-regular.ttf') } +@font-face { font-family: 'NotoSans'; font-display: swap; font-style: normal; font-weight: 100; src: local('NotoSansNerd'), url('notosans-nerdfont-regular.ttf') } :root, .light, .dark { --font: 'NotoSans'; --font-mono: 'ui-monospace', 'Consolas', monospace; diff --git a/ui/css/black-orange.css b/ui/css/black-orange.css index e257268a1..0acb59696 100644 --- a/ui/css/black-orange.css +++ b/ui/css/black-orange.css @@ -1,5 +1,5 @@ /* generic html tags */ -@font-face { font-family: 'NotoSans'; font-display: swap; font-style: normal; font-weight: 100; src: local('NotoSansNerd'), url('fonts/notosans-nerdfont-regular.ttf') } +@font-face { font-family: 'NotoSans'; font-display: swap; font-style: normal; font-weight: 100; src: local('NotoSansNerd'), url('notosans-nerdfont-regular.ttf') } :root, .light, .dark { --font: 'NotoSans'; --font-mono: 'ui-monospace', 'Consolas', monospace; diff --git a/ui/css/black-teal-reimagined.css b/ui/css/black-teal-reimagined.css index 3965c8a70..2ecb386c9 100644 --- a/ui/css/black-teal-reimagined.css +++ b/ui/css/black-teal-reimagined.css @@ -4,7 +4,7 @@ font-display: swap; font-style: normal; font-weight: 100; - src: local('NotoSansNerd'), url('fonts/notosans-nerdfont-regular.ttf'); + src: local('NotoSansNerd'), url('notosans-nerdfont-regular.ttf'); } html { diff --git a/ui/css/black-teal.css b/ui/css/black-teal.css index aadb8f2b8..469115388 100644 --- a/ui/css/black-teal.css +++ b/ui/css/black-teal.css @@ -1,5 +1,5 @@ /* generic html tags */ -@font-face { font-family: 'NotoSans'; font-display: swap; font-style: normal; font-weight: 100; src: local('NotoSansNerd'), url('fonts/notosans-nerdfont-regular.ttf') } +@font-face { font-family: 'NotoSans'; font-display: swap; font-style: normal; font-weight: 100; src: local('NotoSansNerd'), url('notosans-nerdfont-regular.ttf') } :root, .light, .dark { --font: 'NotoSans'; --font-mono: 'ui-monospace', 'Consolas', monospace; diff --git a/ui/fonts/ibmplexmono-nerdfont-medium.ttf b/ui/css/ibmplexmono-nerdfont-medium.ttf similarity index 100% rename from ui/fonts/ibmplexmono-nerdfont-medium.ttf rename to ui/css/ibmplexmono-nerdfont-medium.ttf diff --git a/ui/css/light-teal.css b/ui/css/light-teal.css index 393211fec..fb24a909f 100644 --- a/ui/css/light-teal.css +++ b/ui/css/light-teal.css @@ -1,5 +1,5 @@ /* generic html tags */ -@font-face { font-family: 'NotoSans'; font-display: swap; font-style: normal; font-weight: 100; src: local('NotoSansNerd'), url('fonts/notosans-nerdfont-regular.ttf') } +@font-face { font-family: 'NotoSans'; font-display: swap; font-style: normal; font-weight: 100; src: local('NotoSansNerd'), url('notosans-nerdfont-regular.ttf') } :root, .light, .dark { --font: 'NotoSans'; --font-mono: 'ui-monospace', 'Consolas', monospace; diff --git a/ui/fonts/notosans-nerdfont-regular.ttf b/ui/css/notosans-nerdfont-regular.ttf similarity index 100% rename from ui/fonts/notosans-nerdfont-regular.ttf rename to ui/css/notosans-nerdfont-regular.ttf diff --git a/ui/fonts/roboto.ttf b/ui/css/roboto.ttf similarity index 100% rename from ui/fonts/roboto.ttf rename to ui/css/roboto.ttf diff --git a/ui/css/sdnext.css b/ui/css/sdnext.css index 5975c4771..51c8a5d1b 100644 --- a/ui/css/sdnext.css +++ b/ui/css/sdnext.css @@ -3,7 +3,14 @@ font-family: 'NotoSans'; font-style: normal; font-weight: 100; - src: local('NotoSansNerd'), url('fonts/notosans-nerdfont-regular.ttf'); + src: local('NotoSansNerd'), url('notosans-nerdfont-regular.ttf'); +} +@font-face { + font-display: swap; + font-family: 'Ubuntu'; + font-style: normal; + font-weight: 100; + src: local('Ubuntu'), url('ubuntu-nerdfont.ttf'); } :root { @@ -72,7 +79,7 @@ --sd-tooltip-text-color: var(--sd-input-background-color); --sd-body-font: 'IBM Plex Mono', monospace; --sd-text-font: 'IBM Plex Mono', monospace; - --sd-button-font: 'NotoSans', sans-serif; + --sd-button-font: 'Ubuntu', sans-serif; --sd-image-fit: scale-down; --sd-panel-min-width: 256px; --sd-grid-image-size: 150px; @@ -289,12 +296,12 @@ input::-webkit-outer-spin-button, input::-webkit-inner-spin-button { .gradio-dropdown .token { overflow-x: hidden; padding: var(--spacing-xs) !important; - font-family: 'NotoSans', var(--font); + font-family: 'Ubuntu', var(--font); } .gradio-dropdown .wrap input, .gradio-dropdown input { - font-family: 'NotoSans', var(--font); + font-family: 'Ubuntu', var(--font); } .gradio-html { diff --git a/ui/css/simple-dark.css b/ui/css/simple-dark.css index 2f9b806d1..e2d88f098 100644 --- a/ui/css/simple-dark.css +++ b/ui/css/simple-dark.css @@ -1,5 +1,5 @@ /* generic html tags */ -@font-face { font-family: 'NotoSans'; font-display: swap; font-style: normal; font-weight: 100; src: local('NotoSansNerd'), url('fonts/notosans-nerdfont-regular.ttf') } +@font-face { font-family: 'NotoSans'; font-display: swap; font-style: normal; font-weight: 100; src: local('NotoSansNerd'), url('notosans-nerdfont-regular.ttf') } :root, .light, .dark { --font: 'NotoSans'; --font-mono: 'ui-monospace', 'Consolas', monospace; diff --git a/ui/css/simple-light.css b/ui/css/simple-light.css index cfc9fa3dd..9fc84c4a6 100644 --- a/ui/css/simple-light.css +++ b/ui/css/simple-light.css @@ -1,5 +1,5 @@ /* generic html tags */ -@font-face { font-family: 'NotoSans'; font-display: swap; font-style: normal; font-weight: 100; src: local('NotoSansNerd'), url('fonts/notosans-nerdfont-regular.ttf') } +@font-face { font-family: 'NotoSans'; font-display: swap; font-style: normal; font-weight: 100; src: local('NotoSansNerd'), url('notosans-nerdfont-regular.ttf') } :root, .light, .dark { --font: 'NotoSans'; --font-mono: 'ui-monospace', 'Consolas', monospace; diff --git a/ui/css/ubuntu-nerdfont.ttf b/ui/css/ubuntu-nerdfont.ttf new file mode 100644 index 000000000..90212194a Binary files /dev/null and b/ui/css/ubuntu-nerdfont.ttf differ diff --git a/ui/dist/sdnext.mjs b/ui/dist/sdnext.mjs index f33d9f5bd..2d70ac64b 100644 --- a/ui/dist/sdnext.mjs +++ b/ui/dist/sdnext.mjs @@ -10051,6 +10051,7 @@ var ignoreElements = ["logMonitorData", "logWarnings", "logErrors", "tooltip-con var ignoreElementsSet = new Set(ignoreElements); var ignoreClasses = ["wrap"]; var mutationTimer; +var mutationTS; var validMutations = []; async function mutationCallback(mutations) { if (mutations.length <= 0) return; @@ -10064,7 +10065,10 @@ async function mutationCallback(mutations) { if (validMutations.length < 1) return; if (mutationTimer) clearTimeout(mutationTimer); mutationTimer = setTimeout(async () => { + const ts = Date.now() - mutationTS; + if (!executedOnLoaded && ts > 1e3) log("onUiLoaded delayed", { ts, prompts: anyPromptExists() }); if (!executedOnLoaded && anyPromptExists()) { + log("onUiLoaded", ts); executedOnLoaded = true; executeCallbacks(uiLoadedCallbacks); } @@ -10083,6 +10087,7 @@ async function mutationCallback(mutations) { } document.addEventListener("DOMContentLoaded", () => { log("DOMContentLoaded"); + mutationTS = Date.now(); gradioObserver = new MutationObserver(mutationCallback); gradioObserver.observe(gradioApp(), { childList: true, subtree: true, attributes: false }); }); @@ -10403,7 +10408,7 @@ function readCardTags(el2, tags) { textarea.value = new_prompt; updateInput(textarea); }; - if (tags.length === 0) return; + if (!tags || tags.length === 0) return; const cardTags = tags.split("|"); if (!cardTags || cardTags.length === 0) return; const tagsEl = el2.getElementsByClassName("tags")[0]; @@ -10992,7 +10997,7 @@ async function sendNotification() { // ui/progressBar.ts var lastState = {}; var refreshInterval = 1e4; -var progressTimeout = 180; +var progressTimeout = 600; var startTimeout = 5; function setRefreshInterval() { refreshInterval = window.opts.live_preview_refresh_period || 500; @@ -11102,6 +11107,7 @@ function requestProgress(id_task = "undefined", progressEl = null, galleryEl = n let img; const initLivePreview = () => { if (!parentGallery) return; + debug("initLivePreview", { el: galleryEl, parent: parentGallery }); const footers = Array.from(gradioApp().querySelectorAll(".gallery_footer")); for (const footer of footers) { if (footer.id !== "gallery_footer") footer.style.display = "none"; @@ -11152,7 +11158,7 @@ function requestProgress(id_task = "undefined", progressEl = null, galleryEl = n }; const previewVisible = () => { try { - return !galleryEl?.closest(".section")?.classList.contains("minimize"); + return galleryEl ? !galleryEl.closest(".section")?.classList.contains("minimize") : true; } catch { return true; } @@ -11231,7 +11237,7 @@ async function updateUI(model) { } async function updateModel() { const req = await authFetch2(`${window.api}/checkpoint`); - if (req.ok) { + if (req && req.ok) { const model = await req.json(); if (model?.type?.length > 0) updateUI(model); } @@ -11348,7 +11354,7 @@ async function setTheme(val, old) { for (const link of links) { const href = link.href.replace(old, val); const res = await authFetch2(href); - if (res.ok) { + if (res?.ok) { log("setTheme", old, val); link.href = link.href.replace(old, val); } else { @@ -11528,7 +11534,7 @@ function submit_framepack(...args) { function submit_ltx(...args) { const id = randomId(); log("submitFramepack", id); - requestProgress(id, null, null); + requestProgress(id, null, gradioApp().getElementById("ltx_output_video")); window.submit_state = ""; args[0] = id; return args; @@ -11536,7 +11542,7 @@ function submit_ltx(...args) { function submit_minimax(...args) { const id = randomId(); log("submitMiniMax", id); - requestProgress(id, null, null); + requestProgress(id, null, gradioApp().getElementById("minimax_output_video")); window.submit_state = ""; args[0] = id; return args; @@ -12335,6 +12341,16 @@ function showAllSettings() { elem.style.display = "block"; }); } +function openSettingsSection(sectionId) { + const settingsTab = gradioApp().getElementById("tab_settings"); + const settingsButton = settingsTab ? gradioApp().querySelector(`button[aria-controls="${settingsTab.id}"]`) : null; + settingsButton?.click(); + const section = gradioApp().getElementById(`settings_section_tab_${sectionId}`); + const sectionButton = section ? gradioApp().querySelector(`button[aria-controls="${section.id}"]`) : null; + sectionButton?.click(); + section?.scrollIntoView({ behavior: "smooth", block: "start" }); +} +window.openSettingsSection = openSettingsSection; function markIfModified(setting_name, value) { if (!opts_metadata[setting_name]) return; const elem = gradioApp().getElementById(`modification_indicator_${setting_name}`); @@ -12445,7 +12461,7 @@ async function initModels() { const en = gradioApp().getElementById("txt2img_extra_networks"); if (!el2 || !en) return; const req = await authFetch2(`${window.api}/sd-models`); - const res = req.ok ? await req.json() : []; + const res = req && req.ok ? await req.json() : []; log("initModels", res.length); const ready = () => `

Ready

@@ -12555,7 +12571,7 @@ var ConnectionMonitorState = class _ConnectionMonitorState { else return; } this.element.dataset.hint = this.toHTML(); - this.element.style.backgroundColor = this.online ? "var(--sd-main-accent-color)" : "var(--color-error)"; + this.element.style.background = this.online ? "var(--sd-main-accent-color)" : "var(--color-error)"; } }; async function updateIndicator(online, data = {}, msg) { @@ -13493,7 +13509,7 @@ async function delayFetchThumb(fn, signal) { outstanding++; const ts = t0.toString(); const res = await authFetch2(`${window.api}/browser/thumb?file=${encodeURI(fn)}&ts=${ts}&exif=false`, { priority: "low" }); - if (!res.ok) { + if (!res?.ok) { error(`fetchThumb: ${res.statusText}`); return void 0; } @@ -13568,7 +13584,7 @@ Resolution: ${this.width} x ${this.height}`; } } }; - let ok2 = true; + let ok = true; if (cachedData?.img) { img.src = cachedData.img; this.exif = cachedData.exif; @@ -13581,7 +13597,7 @@ Resolution: ${this.width} x ${this.height}`; try { const json = await delayFetchThumb(this.src, this.#signal); if (!json) { - ok2 = false; + ok = false; pb.stats.failed = (pb.stats.failed || 0) + 1; } else { img.src = json.data; @@ -13616,7 +13632,7 @@ Resolution: ${this.width} x ${this.height}`; pb.stats.callback = (pb.stats.callback || 0) + Math.round(performance.now() - t0); if (this.#signal.aborted) return; galleryHashes.add(this.hash); - if (!ok2) return; + if (!ok) return; img.onclick = () => { setGallerySelectionByElement(this, { send: true }); }; @@ -14260,6 +14276,7 @@ async function observeImageError(img) { img.src = loadingSvg; const { default: heic2any } = await import("https://esm.sh/heic2any@0.0.4"); const res = await authFetch2(origSrc); + if (!res || res.status !== 200) return; const imageBlob = await res.blob(); if (!imageBlob || imageBlob.size <= 1024) { error("imageHEIC", { src: origSrc, res, blob: imageBlob }); @@ -14735,7 +14752,7 @@ var xnEngine = { async fetchJson(path) { try { const resp = await authFetch(`${window.api}${path}`); - if (!resp.ok) throw new Error(`${resp.status}`); + if (!resp?.ok) throw new Error(`${resp?.status}`); return await resp.json(); } catch (e) { log("autoComplete", { xnFetchFailed: path, error: String(e) }); @@ -14752,16 +14769,24 @@ var xnEngine = { } this.lora = new XnIndex(items); } - const embData = await this.fetchJson("/embeddings"); - if (embData && typeof embData === "object") { - const loaded = Array.isArray(embData.loaded) ? embData.loaded : []; - this.embed = new XnIndex(loaded.map((name) => ({ name: String(name) }))); + if (window.opts.diffusers_enable_embed) { + const embData = await this.fetchJson("/embeddings"); + if (embData && typeof embData === "object") { + const loaded = Array.isArray(embData.loaded) ? embData.loaded : []; + this.embed = new XnIndex(loaded.map((name) => ({ name: String(name) }))); + } + } else { + this.embed = new XnIndex([]); } - const wcData = await this.fetchJson("/wildcards"); - if (Array.isArray(wcData)) { - this.wildcard = new XnIndex( - wcData.filter((w) => typeof w === "object" && w && "name" in w && typeof w.name === "string").map((w) => ({ name: w.name })) - ); + if (window.opts.wildcards_enabled) { + const wcData = await this.fetchJson("/wildcards"); + if (Array.isArray(wcData)) { + this.wildcard = new XnIndex( + wcData.filter((w) => typeof w === "object" && w && "name" in w && typeof w.name === "string").map((w) => ({ name: w.name })) + ); + } + } else { + this.wildcard = new XnIndex([]); } log("autoComplete", { xnLoaded: true, @@ -14984,7 +15009,7 @@ var engine = { await Promise.all(toLoad.map(async (name) => { try { const resp = await authFetch(`${window.api}/autocomplete/${name}`); - if (!resp.ok) throw new Error(`${resp.status}`); + if (!resp?.ok) throw new Error(`${resp?.status}`); const data = await resp.json(); this.indices.set(name, new TagIndex(data)); if (data.categories) { @@ -16084,8 +16109,8 @@ async function createSplash() {
`; document.body.insertAdjacentHTML("beforeend", splash); - const ok2 = await preloadImages(); - if (!ok2) { + const ok = await preloadImages(); + if (!ok) { removeSplash(); return; } @@ -16104,6 +16129,15 @@ async function createSplash() { if (motdEl) motdEl.innerHTML = clean; }).catch((err) => error(`getMOTD: ${err}`)); log("loadGradioUi"); + const splashMonitor = setInterval(() => { + const splashVisible = !!document.getElementById("splash"); + if (splashVisible) { + log("splashVisible", { visible: true, elapsed: Math.round(performance.now() - appStartTime) }); + } else { + log("splashVisible", { visible: false, elapsed: Math.round(performance.now() - appStartTime) }); + clearInterval(splashMonitor); + } + }, 5e3); } window.onload = createSplash; @@ -16122,23 +16156,27 @@ function addLegacyNotice() { window.api = "/sdapi/v1"; window.subpath = ""; var startupPromises = []; -var ok = false; +var optsReady = false; +var initialized = false; async function waitForOpts() { const t0 = performance.now(); let t1 = performance.now(); while (true) { - if (t1 - t0 > 12e4) { + if (t1 - t0 > 6e4) { log("waitForOpts timeout"); break; } if (window.opts && Object.keys(window.opts).length > 0) { - ok = window.opts.theme_type === "Modern" ? "uiux_separator_appearance" in window.opts : true; - if (ok) { + optsReady = window.opts.theme_type === "Modern" ? "uiux_separator_appearance" in window.opts : true; + if (optsReady) { log("waitForOpts", Math.round(t1 - t0)); timer("waitForOpts", t1 - t0); break; } } + if (t1 - t0 > 15e3) { + log("waitForOpts delayed", Math.round(t1 - t0)); + } await sleep(100); t1 = performance.now(); } @@ -16157,6 +16195,8 @@ async function updateSubpath() { log("API", { url: window.api }); } async function initStartup() { + if (initialized) return; + initialized = true; const t0 = performance.now(); log("initGradio", Math.round(t0 - appStartTime)); timer("initGradio", t0 - appStartTime); @@ -16178,7 +16218,7 @@ async function initStartup() { await waitForOpts(); await updateSubpath(); executeCallbacks(uiReadyCallbacks); - if (window.waitForUiReady) await window.waitForUiReady(); + if (window.opts.theme_type.toLowerCase().startsWith("modern") && window.waitForUiReady) await window.waitForUiReady(); startupPromises.push(Promise.resolve(initLogMonitor())); startupPromises.push(Promise.resolve(setRefreshInterval())); startupPromises.push(Promise.resolve(setupExtraNetworks())); @@ -16200,6 +16240,9 @@ async function initStartup() { } onUiLoaded(initStartup); onUiReady(() => log("uiReady")); +window.initStartup = initStartup; +window.addEventListener("pageshow", (evt) => log("pageShow", evt)); +window.addEventListener("pagehide", (evt) => log("pageHide", evt)); // ui/extensions.ts function extensions_apply(_extensionsDisabledList, _extensionsUpdateList, disableAll) { @@ -16356,6 +16399,9 @@ var selectedType = []; var selectedBase = []; var selectedModelId = []; var selectedVersionId = []; +var currentModel = null; +var precisionOrder = ["fp32", "bf16", "fp16", "fp8", "int8", "int4"]; +var companionTypes = ["VAE", "Text Encoder"]; function clearModelDetails() { const el2 = gradioApp().getElementById("model-details") || gradioApp().getElementById("civitai_models_output") || gradioApp().getElementById("models_outcome"); if (!el2) return; @@ -16386,6 +16432,7 @@ var modelDetailsHTML = ` Type Base File + Variant Updated Size Availability @@ -16398,19 +16445,65 @@ var modelDetailsHTML = ` `; -var modelVersionsHTML = ` - - {url} - {name} - {type} - {base} - {file} - {mtime} - {size} - {availability} -
{desc}
- -`; +function fileVariant(file) { + return file.metadata?.fp || file.metadata?.quantType || null; +} +function sortFiles(files) { + const isModel = (f) => f.type === "Model" || f.type === "Pruned Model"; + const rank = (f) => { + const index = precisionOrder.indexOf((fileVariant(f) || "").toLowerCase()); + return index < 0 ? precisionOrder.length : index; + }; + return [...files].sort((a, b) => Number(isModel(b)) - Number(isModel(a)) || rank(a) - rank(b) || (b.size || 0) - (a.size || 0)); +} +function insertNameSuffix(name, suffix) { + const dot = name.lastIndexOf("."); + return dot > 0 ? `${name.slice(0, dot)}-${suffix}${name.slice(dot)}` : `${name}-${suffix}`; +} +function fileSaveName(file, siblings) { + const tier1 = (f) => { + const variant = fileVariant(f); + return variant ? insertNameSuffix(f.name || "", variant) : f.name || ""; + }; + const tier2 = (f) => f.metadata?.size ? insertNameSuffix(tier1(f), f.metadata.size) : tier1(f); + const others = siblings.filter((s) => s.id !== file.id); + const name = tier1(file); + if (!others.some((s) => tier1(s) === name)) return name; + const sized = tier2(file); + if (!others.some((s) => tier2(s) === sized)) return sized; + return insertNameSuffix(name, String(file.id)); +} +function escapeHTML(text) { + return text.replace(/[&<>"']/g, (c) => `&#${c.charCodeAt(0)};`); +} +function versionRows(version, divider) { + const files = sortFiles(version.files); + const entries = files.length > 0 ? files : [null]; + const border = divider ? ' style="border-top: 1px solid var(--sd-panel-border-color, #555)"' : ""; + const span = entries.length > 1 ? ` rowspan="${entries.length}"` : ""; + const versionCell = (content) => `${content}`; + return entries.map((file, i) => { + const first = i === 0; + const cell = (content) => `${content}`; + const link = file ? `` : ""; + const name = file ? `${escapeHTML(file.name || "unknown")}${file.primary ? ' \u2605' : ""}` : "unknown"; + const variant = file ? [fileVariant(file), file.metadata?.size].filter(Boolean).join(" \xB7 ") : ""; + const size = file?.size ? `${(file.size / 1024 / 1024 / 1024).toFixed(2)} GB` : "unknown"; + const cells = [ + cell(link), + first ? versionCell(escapeHTML(version.name || "unknown")) : "", + cell(escapeHTML(file?.type || "unknown")), + first ? versionCell(escapeHTML(version.base || "unknown")) : "", + cell(name), + cell(escapeHTML(variant || "-")), + first ? versionCell(new Date(version.mtime).toLocaleDateString()) : "", + cell(size), + first ? versionCell(escapeHTML(version.availability || "unknown")) : "", + first ? versionCell(`
${version.desc || "no description available"}
`) : "" + ]; + return `${cells.join("")}`; + }).join(""); +} async function modelCardClick(id) { log("modelCardClick id", id); const el2 = gradioApp().getElementById("model-details") || gradioApp().getElementById("civitai_models_output") || gradioApp().getElementById("models_outcome"); @@ -16424,17 +16517,8 @@ async function modelCardClick(id) { log("modelCardClick data", dataArray); if (!dataArray || dataArray.length === 0) return; const data = dataArray[0]; - const versionsHTML = data.versions.map((v) => modelVersionsHTML.format({ - url: ``, - name: v.name || "unknown", - type: v.files[0]?.type || "unknown", - base: v.base || "unknown", - mtime: new Date(v.mtime).toLocaleDateString(), - availability: v.availability || "unknown", - size: v.files[0]?.size ? `${(v.files[0].size / 1024 / 1024).toFixed(2)} MB` : "unknown", - file: `${v.files[0]?.name || "unknown"}`, - desc: v.desc || "no description available" - })).join(""); + currentModel = data; + const versionsHTML = data.versions.map((v, i) => versionRows(v, i > 0)).join(""); const url2 = `${data.name || "unknown"}`; const creator = `${data.creator || "unknown"}`; const images = data.versions.map((v) => v.images).flat().map((i) => i.url); @@ -16454,41 +16538,29 @@ async function modelCardClick(id) { el2.innerHTML = modelHTML; } window.modelCardClick = modelCardClick; -function startCivitDownload(url2, name, type, base, modelId, versionId) { - log("startCivitDownload", { url: url2, name, type, base, modelId, versionId }); - selectedURL = [url2]; - selectedName = [name]; - selectedType = [type]; - selectedBase = [base || ""]; - selectedModelId = [modelId || 0]; - selectedVersionId = [versionId || 0]; +function queueFiles(model, queued) { + selectedURL = queued.map(({ file }) => file.url || ""); + selectedName = queued.map(({ version, file }) => fileSaveName(file, version.files)); + selectedType = queued.map(({ file }) => (companionTypes.includes(file.type || "") ? file.type : model.type) || ""); + selectedBase = queued.map(({ version }) => version.base || ""); + selectedModelId = queued.map(() => model.id || 0); + selectedVersionId = queued.map(({ version }) => version.id || 0); const civitDownloadBtn = gradioApp().getElementById("civitai_download_btn"); if (civitDownloadBtn) civitDownloadBtn.click(); } -window.startCivitDownload = startCivitDownload; +function startCivitFileDownload(versionId, fileId) { + log("startCivitFileDownload", { versionId, fileId }); + const version = currentModel?.versions.find((v) => v.id === versionId); + const file = version?.files.find((f) => f.id === fileId); + if (!currentModel || !version || !file) return; + queueFiles(currentModel, [{ version, file }]); +} +window.startCivitFileDownload = startCivitFileDownload; function startCivitAllDownload(evt) { log("startCivitAllDownload", evt); - const table = gradioApp().getElementById("model-versions-table"); - if (!table) return; - const versions = table.querySelectorAll("tr"); - selectedURL = []; - selectedName = []; - selectedType = []; - selectedBase = []; - selectedModelId = []; - selectedVersionId = []; - for (const version of versions) { - const parsed = version.querySelector("td:nth-child(1) div")?.getAttribute("onclick")?.match(/startCivitDownload\('([^']+)', '([^']+)', '([^']+)', '([^']*)', (\d+), (\d+)\)/); - if (!parsed || parsed.length < 7) continue; - selectedURL.push(parsed[1]); - selectedName.push(parsed[2]); - selectedType.push(parsed[3]); - selectedBase.push(parsed[4]); - selectedModelId.push(parseInt(parsed[5], 10)); - selectedVersionId.push(parseInt(parsed[6], 10)); - } - const civitDownloadBtn = gradioApp().getElementById("civitai_download_btn"); - if (civitDownloadBtn) civitDownloadBtn.click(); + if (!currentModel) return; + const queued = currentModel.versions.map((version) => ({ version, file: version.files.find((f) => f.primary) || version.files[0] })).filter((entry) => !!entry.file); + queueFiles(currentModel, queued); } window.startCivitAllDownload = startCivitAllDownload; function downloadCivitModel(modelUrl, modelName, modelType, modelBase, mId, vId, modelPath, civitToken, innerHTML) { diff --git a/ui/dist/sdnext.mjs.map b/ui/dist/sdnext.mjs.map index 0e5482d30..abf3df5d9 100644 --- a/ui/dist/sdnext.mjs.map +++ b/ui/dist/sdnext.mjs.map @@ -1,7 +1,7 @@ { "version": 3, "sources": ["../../node_modules/.pnpm/jquery@4.0.0/node_modules/jquery/dist/jquery.js", "../js/iframeResizer.js", "../../node_modules/.pnpm/exifr@7.1.3/node_modules/exifr/dist/full.umd.js", "../../node_modules/.pnpm/wheel@1.0.0/node_modules/wheel/index.js", "../../node_modules/.pnpm/bezier-easing@2.1.0/node_modules/bezier-easing/src/index.js", "../../node_modules/.pnpm/amator@1.1.0/node_modules/amator/index.js", "../../node_modules/.pnpm/ngraph.events@1.4.0/node_modules/ngraph.events/index.js", "../../node_modules/.pnpm/panzoom@9.4.4/node_modules/panzoom/lib/kinetic.js", "../../node_modules/.pnpm/panzoom@9.4.4/node_modules/panzoom/lib/makeTextSelectionInterceptor.js", "../../node_modules/.pnpm/panzoom@9.4.4/node_modules/panzoom/lib/transform.js", "../../node_modules/.pnpm/panzoom@9.4.4/node_modules/panzoom/lib/makeSvgController.js", "../../node_modules/.pnpm/panzoom@9.4.4/node_modules/panzoom/lib/makeDomController.js", "../../node_modules/.pnpm/panzoom@9.4.4/node_modules/panzoom/index.js", "../../node_modules/.pnpm/jquery@4.0.0/node_modules/jquery/dist-module/wrappers/jquery.node-module-wrapper.js", "../vendor.ts", "../logger.ts", "../authWrap.ts", "../timers.ts", "../script.ts", "../changelog.ts", "../control.ts", "../extraNetworks.ts", "../generationParams.ts", "../imageParams.ts", "../notification.ts", "../progressBar.ts", "../dynamicUI.ts", "../ui.ts", "../inputAccordion.ts", "../indexdb.ts", "../logMonitor.ts", "../settings.ts", "../monitor.ts", "../promptChecker.ts", "../js/sha256.ts", "../gallery.ts", "../imageViewer.ts", "../autocomplete_xn.ts", "../autocomplete.ts", "../setHints.ts", "../contextMenus.ts", "../uiConfig.ts", "../loader.ts", "../legacy.ts", "../startup.ts", "../extensions.ts", "../dragDrop.ts", "../civitai.ts", "../guidance.ts", "../timesheet.ts", "../history.ts", "../storage.ts", "../aspectRatioOverlay.ts", "../resolutionLock.ts", "../editAttention.ts", "../../node_modules/.pnpm/jquery-sparkline@2.4.0/node_modules/jquery-sparkline/jquery.sparkline.js", "../gpu.ts"], - "sourcesContent": ["/*!\n * jQuery JavaScript Library v4.0.0\n * https://jquery.com/\n *\n * Copyright OpenJS Foundation and other contributors\n * Released under the MIT license\n * https://jquery.com/license/\n *\n * Date: 2026-01-18T00:20Z\n */\n( function( global, factory ) {\n\n\t\"use strict\";\n\n\tif ( typeof module === \"object\" && typeof module.exports === \"object\" ) {\n\n\t\t// For CommonJS and CommonJS-like environments where a proper `window`\n\t\t// is present, execute the factory and get jQuery.\n\t\tmodule.exports = factory( global, true );\n\t} else {\n\t\tfactory( global );\n\t}\n\n// Pass this if window is not defined yet\n} )( typeof window !== \"undefined\" ? window : this, function( window, noGlobal ) {\n\n\"use strict\";\n\nif ( !window.document ) {\n\tthrow new Error( \"jQuery requires a window with a document\" );\n}\n\nvar arr = [];\n\nvar getProto = Object.getPrototypeOf;\n\nvar slice = arr.slice;\n\n// Support: IE 11+\n// IE doesn't have Array#flat; provide a fallback.\nvar flat = arr.flat ? function( array ) {\n\treturn arr.flat.call( array );\n} : function( array ) {\n\treturn arr.concat.apply( [], array );\n};\n\nvar push = arr.push;\n\nvar indexOf = arr.indexOf;\n\n// [[Class]] -> type pairs\nvar class2type = {};\n\nvar toString = class2type.toString;\n\nvar hasOwn = class2type.hasOwnProperty;\n\nvar fnToString = hasOwn.toString;\n\nvar ObjectFunctionString = fnToString.call( Object );\n\n// All support tests are defined in their respective modules.\nvar support = {};\n\nfunction toType( obj ) {\n\tif ( obj == null ) {\n\t\treturn obj + \"\";\n\t}\n\n\treturn typeof obj === \"object\" ?\n\t\tclass2type[ toString.call( obj ) ] || \"object\" :\n\t\ttypeof obj;\n}\n\nfunction isWindow( obj ) {\n\treturn obj != null && obj === obj.window;\n}\n\nfunction isArrayLike( obj ) {\n\n\tvar length = !!obj && obj.length,\n\t\ttype = toType( obj );\n\n\tif ( typeof obj === \"function\" || isWindow( obj ) ) {\n\t\treturn false;\n\t}\n\n\treturn type === \"array\" || length === 0 ||\n\t\ttypeof length === \"number\" && length > 0 && ( length - 1 ) in obj;\n}\n\nvar document$1 = window.document;\n\nvar preservedScriptAttributes = {\n\ttype: true,\n\tsrc: true,\n\tnonce: true,\n\tnoModule: true\n};\n\nfunction DOMEval( code, node, doc ) {\n\tdoc = doc || document$1;\n\n\tvar i,\n\t\tscript = doc.createElement( \"script\" );\n\n\tscript.text = code;\n\tfor ( i in preservedScriptAttributes ) {\n\t\tif ( node && node[ i ] ) {\n\t\t\tscript[ i ] = node[ i ];\n\t\t}\n\t}\n\n\tif ( doc.head.appendChild( script ).parentNode ) {\n\t\tscript.parentNode.removeChild( script );\n\t}\n}\n\nvar version = \"4.0.0\",\n\n\trhtmlSuffix = /HTML$/i,\n\n\t// Define a local copy of jQuery\n\tjQuery = function( selector, context ) {\n\n\t\t// The jQuery object is actually just the init constructor 'enhanced'\n\t\t// Need init if jQuery is called (just allow error to be thrown if not included)\n\t\treturn new jQuery.fn.init( selector, context );\n\t};\n\njQuery.fn = jQuery.prototype = {\n\n\t// The current version of jQuery being used\n\tjquery: version,\n\n\tconstructor: jQuery,\n\n\t// The default length of a jQuery object is 0\n\tlength: 0,\n\n\ttoArray: function() {\n\t\treturn slice.call( this );\n\t},\n\n\t// Get the Nth element in the matched element set OR\n\t// Get the whole matched element set as a clean array\n\tget: function( num ) {\n\n\t\t// Return all the elements in a clean array\n\t\tif ( num == null ) {\n\t\t\treturn slice.call( this );\n\t\t}\n\n\t\t// Return just the one element from the set\n\t\treturn num < 0 ? this[ num + this.length ] : this[ num ];\n\t},\n\n\t// Take an array of elements and push it onto the stack\n\t// (returning the new matched element set)\n\tpushStack: function( elems ) {\n\n\t\t// Build a new jQuery matched element set\n\t\tvar ret = jQuery.merge( this.constructor(), elems );\n\n\t\t// Add the old object onto the stack (as a reference)\n\t\tret.prevObject = this;\n\n\t\t// Return the newly-formed element set\n\t\treturn ret;\n\t},\n\n\t// Execute a callback for every element in the matched set.\n\teach: function( callback ) {\n\t\treturn jQuery.each( this, callback );\n\t},\n\n\tmap: function( callback ) {\n\t\treturn this.pushStack( jQuery.map( this, function( elem, i ) {\n\t\t\treturn callback.call( elem, i, elem );\n\t\t} ) );\n\t},\n\n\tslice: function() {\n\t\treturn this.pushStack( slice.apply( this, arguments ) );\n\t},\n\n\tfirst: function() {\n\t\treturn this.eq( 0 );\n\t},\n\n\tlast: function() {\n\t\treturn this.eq( -1 );\n\t},\n\n\teven: function() {\n\t\treturn this.pushStack( jQuery.grep( this, function( _elem, i ) {\n\t\t\treturn ( i + 1 ) % 2;\n\t\t} ) );\n\t},\n\n\todd: function() {\n\t\treturn this.pushStack( jQuery.grep( this, function( _elem, i ) {\n\t\t\treturn i % 2;\n\t\t} ) );\n\t},\n\n\teq: function( i ) {\n\t\tvar len = this.length,\n\t\t\tj = +i + ( i < 0 ? len : 0 );\n\t\treturn this.pushStack( j >= 0 && j < len ? [ this[ j ] ] : [] );\n\t},\n\n\tend: function() {\n\t\treturn this.prevObject || this.constructor();\n\t}\n};\n\njQuery.extend = jQuery.fn.extend = function() {\n\tvar options, name, src, copy, copyIsArray, clone,\n\t\ttarget = arguments[ 0 ] || {},\n\t\ti = 1,\n\t\tlength = arguments.length,\n\t\tdeep = false;\n\n\t// Handle a deep copy situation\n\tif ( typeof target === \"boolean\" ) {\n\t\tdeep = target;\n\n\t\t// Skip the boolean and the target\n\t\ttarget = arguments[ i ] || {};\n\t\ti++;\n\t}\n\n\t// Handle case when target is a string or something (possible in deep copy)\n\tif ( typeof target !== \"object\" && typeof target !== \"function\" ) {\n\t\ttarget = {};\n\t}\n\n\t// Extend jQuery itself if only one argument is passed\n\tif ( i === length ) {\n\t\ttarget = this;\n\t\ti--;\n\t}\n\n\tfor ( ; i < length; i++ ) {\n\n\t\t// Only deal with non-null/undefined values\n\t\tif ( ( options = arguments[ i ] ) != null ) {\n\n\t\t\t// Extend the base object\n\t\t\tfor ( name in options ) {\n\t\t\t\tcopy = options[ name ];\n\n\t\t\t\t// Prevent Object.prototype pollution\n\t\t\t\t// Prevent never-ending loop\n\t\t\t\tif ( name === \"__proto__\" || target === copy ) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\t// Recurse if we're merging plain objects or arrays\n\t\t\t\tif ( deep && copy && ( jQuery.isPlainObject( copy ) ||\n\t\t\t\t\t( copyIsArray = Array.isArray( copy ) ) ) ) {\n\t\t\t\t\tsrc = target[ name ];\n\n\t\t\t\t\t// Ensure proper type for the source value\n\t\t\t\t\tif ( copyIsArray && !Array.isArray( src ) ) {\n\t\t\t\t\t\tclone = [];\n\t\t\t\t\t} else if ( !copyIsArray && !jQuery.isPlainObject( src ) ) {\n\t\t\t\t\t\tclone = {};\n\t\t\t\t\t} else {\n\t\t\t\t\t\tclone = src;\n\t\t\t\t\t}\n\t\t\t\t\tcopyIsArray = false;\n\n\t\t\t\t\t// Never move original objects, clone them\n\t\t\t\t\ttarget[ name ] = jQuery.extend( deep, clone, copy );\n\n\t\t\t\t// Don't bring in undefined values\n\t\t\t\t} else if ( copy !== undefined ) {\n\t\t\t\t\ttarget[ name ] = copy;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// Return the modified object\n\treturn target;\n};\n\njQuery.extend( {\n\n\t// Unique for each copy of jQuery on the page\n\texpando: \"jQuery\" + ( version + Math.random() ).replace( /\\D/g, \"\" ),\n\n\t// Assume jQuery is ready without the ready module\n\tisReady: true,\n\n\terror: function( msg ) {\n\t\tthrow new Error( msg );\n\t},\n\n\tnoop: function() {},\n\n\tisPlainObject: function( obj ) {\n\t\tvar proto, Ctor;\n\n\t\t// Detect obvious negatives\n\t\t// Use toString instead of jQuery.type to catch host objects\n\t\tif ( !obj || toString.call( obj ) !== \"[object Object]\" ) {\n\t\t\treturn false;\n\t\t}\n\n\t\tproto = getProto( obj );\n\n\t\t// Objects with no prototype (e.g., `Object.create( null )`) are plain\n\t\tif ( !proto ) {\n\t\t\treturn true;\n\t\t}\n\n\t\t// Objects with prototype are plain iff they were constructed by a global Object function\n\t\tCtor = hasOwn.call( proto, \"constructor\" ) && proto.constructor;\n\t\treturn typeof Ctor === \"function\" && fnToString.call( Ctor ) === ObjectFunctionString;\n\t},\n\n\tisEmptyObject: function( obj ) {\n\t\tvar name;\n\n\t\tfor ( name in obj ) {\n\t\t\treturn false;\n\t\t}\n\t\treturn true;\n\t},\n\n\t// Evaluates a script in a provided context; falls back to the global one\n\t// if not specified.\n\tglobalEval: function( code, options, doc ) {\n\t\tDOMEval( code, { nonce: options && options.nonce }, doc );\n\t},\n\n\teach: function( obj, callback ) {\n\t\tvar length, i = 0;\n\n\t\tif ( isArrayLike( obj ) ) {\n\t\t\tlength = obj.length;\n\t\t\tfor ( ; i < length; i++ ) {\n\t\t\t\tif ( callback.call( obj[ i ], i, obj[ i ] ) === false ) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tfor ( i in obj ) {\n\t\t\t\tif ( callback.call( obj[ i ], i, obj[ i ] ) === false ) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn obj;\n\t},\n\n\n\t// Retrieve the text value of an array of DOM nodes\n\ttext: function( elem ) {\n\t\tvar node,\n\t\t\tret = \"\",\n\t\t\ti = 0,\n\t\t\tnodeType = elem.nodeType;\n\n\t\tif ( !nodeType ) {\n\n\t\t\t// If no nodeType, this is expected to be an array\n\t\t\twhile ( ( node = elem[ i++ ] ) ) {\n\n\t\t\t\t// Do not traverse comment nodes\n\t\t\t\tret += jQuery.text( node );\n\t\t\t}\n\t\t}\n\t\tif ( nodeType === 1 || nodeType === 11 ) {\n\t\t\treturn elem.textContent;\n\t\t}\n\t\tif ( nodeType === 9 ) {\n\t\t\treturn elem.documentElement.textContent;\n\t\t}\n\t\tif ( nodeType === 3 || nodeType === 4 ) {\n\t\t\treturn elem.nodeValue;\n\t\t}\n\n\t\t// Do not include comment or processing instruction nodes\n\n\t\treturn ret;\n\t},\n\n\n\t// results is for internal usage only\n\tmakeArray: function( arr, results ) {\n\t\tvar ret = results || [];\n\n\t\tif ( arr != null ) {\n\t\t\tif ( isArrayLike( Object( arr ) ) ) {\n\t\t\t\tjQuery.merge( ret,\n\t\t\t\t\ttypeof arr === \"string\" ?\n\t\t\t\t\t\t[ arr ] : arr\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\tpush.call( ret, arr );\n\t\t\t}\n\t\t}\n\n\t\treturn ret;\n\t},\n\n\tinArray: function( elem, arr, i ) {\n\t\treturn arr == null ? -1 : indexOf.call( arr, elem, i );\n\t},\n\n\tisXMLDoc: function( elem ) {\n\t\tvar namespace = elem && elem.namespaceURI,\n\t\t\tdocElem = elem && ( elem.ownerDocument || elem ).documentElement;\n\n\t\t// Assume HTML when documentElement doesn't yet exist, such as inside\n\t\t// document fragments.\n\t\treturn !rhtmlSuffix.test( namespace || docElem && docElem.nodeName || \"HTML\" );\n\t},\n\n\t// Note: an element does not contain itself\n\tcontains: function( a, b ) {\n\t\tvar bup = b && b.parentNode;\n\n\t\treturn a === bup || !!( bup && bup.nodeType === 1 && (\n\n\t\t\t// Support: IE 9 - 11+\n\t\t\t// IE doesn't have `contains` on SVG.\n\t\t\ta.contains ?\n\t\t\t\ta.contains( bup ) :\n\t\t\t\ta.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16\n\t\t) );\n\t},\n\n\tmerge: function( first, second ) {\n\t\tvar len = +second.length,\n\t\t\tj = 0,\n\t\t\ti = first.length;\n\n\t\tfor ( ; j < len; j++ ) {\n\t\t\tfirst[ i++ ] = second[ j ];\n\t\t}\n\n\t\tfirst.length = i;\n\n\t\treturn first;\n\t},\n\n\tgrep: function( elems, callback, invert ) {\n\t\tvar callbackInverse,\n\t\t\tmatches = [],\n\t\t\ti = 0,\n\t\t\tlength = elems.length,\n\t\t\tcallbackExpect = !invert;\n\n\t\t// Go through the array, only saving the items\n\t\t// that pass the validator function\n\t\tfor ( ; i < length; i++ ) {\n\t\t\tcallbackInverse = !callback( elems[ i ], i );\n\t\t\tif ( callbackInverse !== callbackExpect ) {\n\t\t\t\tmatches.push( elems[ i ] );\n\t\t\t}\n\t\t}\n\n\t\treturn matches;\n\t},\n\n\t// arg is for internal usage only\n\tmap: function( elems, callback, arg ) {\n\t\tvar length, value,\n\t\t\ti = 0,\n\t\t\tret = [];\n\n\t\t// Go through the array, translating each of the items to their new values\n\t\tif ( isArrayLike( elems ) ) {\n\t\t\tlength = elems.length;\n\t\t\tfor ( ; i < length; i++ ) {\n\t\t\t\tvalue = callback( elems[ i ], i, arg );\n\n\t\t\t\tif ( value != null ) {\n\t\t\t\t\tret.push( value );\n\t\t\t\t}\n\t\t\t}\n\n\t\t// Go through every key on the object,\n\t\t} else {\n\t\t\tfor ( i in elems ) {\n\t\t\t\tvalue = callback( elems[ i ], i, arg );\n\n\t\t\t\tif ( value != null ) {\n\t\t\t\t\tret.push( value );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Flatten any nested arrays\n\t\treturn flat( ret );\n\t},\n\n\t// A global GUID counter for objects\n\tguid: 1,\n\n\t// jQuery.support is not used in Core but other projects attach their\n\t// properties to it so it needs to exist.\n\tsupport: support\n} );\n\nif ( typeof Symbol === \"function\" ) {\n\tjQuery.fn[ Symbol.iterator ] = arr[ Symbol.iterator ];\n}\n\n// Populate the class2type map\njQuery.each( \"Boolean Number String Function Array Date RegExp Object Error Symbol\".split( \" \" ),\n\tfunction( _i, name ) {\n\t\tclass2type[ \"[object \" + name + \"]\" ] = name.toLowerCase();\n\t} );\n\nfunction nodeName( elem, name ) {\n\treturn elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase();\n}\n\nvar pop = arr.pop;\n\n// https://www.w3.org/TR/css3-selectors/#whitespace\nvar whitespace = \"[\\\\x20\\\\t\\\\r\\\\n\\\\f]\";\n\nvar isIE = document$1.documentMode;\n\nvar rbuggyQSA = isIE && new RegExp(\n\n\t// Support: IE 9 - 11+\n\t// IE's :disabled selector does not pick up the children of disabled fieldsets\n\t\":enabled|:disabled|\" +\n\n\t// Support: IE 11+\n\t// IE 11 doesn't find elements on a `[name='']` query in some cases.\n\t// Adding a temporary attribute to the document before the selection works\n\t// around the issue.\n\t\"\\\\[\" + whitespace + \"*name\" + whitespace + \"*=\" +\n\twhitespace + \"*(?:''|\\\"\\\")\"\n\n);\n\nvar rtrimCSS = new RegExp(\n\t\"^\" + whitespace + \"+|((?:^|[^\\\\\\\\])(?:\\\\\\\\.)*)\" + whitespace + \"+$\",\n\t\"g\"\n);\n\n// https://www.w3.org/TR/css-syntax-3/#ident-token-diagram\nvar identifier = \"(?:\\\\\\\\[\\\\da-fA-F]{1,6}\" + whitespace +\n\t\"?|\\\\\\\\[^\\\\r\\\\n\\\\f]|[\\\\w-]|[^\\0-\\\\x7f])+\";\n\nvar rleadingCombinator = new RegExp( \"^\" + whitespace + \"*([>+~]|\" +\n\twhitespace + \")\" + whitespace + \"*\" );\n\nvar rdescend = new RegExp( whitespace + \"|>\" );\n\nvar rsibling = /[+~]/;\n\nvar documentElement$1 = document$1.documentElement;\n\n// Support: IE 9 - 11+\n// IE requires a prefix.\nvar matches = documentElement$1.matches || documentElement$1.msMatchesSelector;\n\n/**\n * Create key-value caches of limited size\n * @returns {function(string, object)} Returns the Object data after storing it on itself with\n *\tproperty name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength)\n *\tdeleting the oldest entry\n */\nfunction createCache() {\n\tvar keys = [];\n\n\tfunction cache( key, value ) {\n\n\t\t// Use (key + \" \") to avoid collision with native prototype properties\n\t\t// (see https://github.com/jquery/sizzle/issues/157)\n\t\tif ( keys.push( key + \" \" ) > jQuery.expr.cacheLength ) {\n\n\t\t\t// Only keep the most recent entries\n\t\t\tdelete cache[ keys.shift() ];\n\t\t}\n\t\treturn ( cache[ key + \" \" ] = value );\n\t}\n\treturn cache;\n}\n\n/**\n * Checks a node for validity as a jQuery selector context\n * @param {Element|Object=} context\n * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value\n */\nfunction testContext( context ) {\n\treturn context && typeof context.getElementsByTagName !== \"undefined\" && context;\n}\n\n// Attribute selectors: https://www.w3.org/TR/selectors/#attribute-selectors\nvar attributes = \"\\\\[\" + whitespace + \"*(\" + identifier + \")(?:\" + whitespace +\n\n\t// Operator (capture 2)\n\t\"*([*^$|!~]?=)\" + whitespace +\n\n\t// \"Attribute values must be CSS identifiers [capture 5] or strings [capture 3 or capture 4]\"\n\t\"*(?:'((?:\\\\\\\\.|[^\\\\\\\\'])*)'|\\\"((?:\\\\\\\\.|[^\\\\\\\\\\\"])*)\\\"|(\" + identifier + \"))|)\" +\n\twhitespace + \"*\\\\]\";\n\nvar pseudos = \":(\" + identifier + \")(?:\\\\((\" +\n\n\t// To reduce the number of selectors needing tokenize in the preFilter, prefer arguments:\n\t// 1. quoted (capture 3; capture 4 or capture 5)\n\t\"('((?:\\\\\\\\.|[^\\\\\\\\'])*)'|\\\"((?:\\\\\\\\.|[^\\\\\\\\\\\"])*)\\\")|\" +\n\n\t// 2. simple (capture 6)\n\t\"((?:\\\\\\\\.|[^\\\\\\\\()[\\\\]]|\" + attributes + \")*)|\" +\n\n\t// 3. anything else (capture 2)\n\t\".*\" +\n\t\")\\\\)|)\";\n\nvar filterMatchExpr = {\n\tID: new RegExp( \"^#(\" + identifier + \")\" ),\n\tCLASS: new RegExp( \"^\\\\.(\" + identifier + \")\" ),\n\tTAG: new RegExp( \"^(\" + identifier + \"|[*])\" ),\n\tATTR: new RegExp( \"^\" + attributes ),\n\tPSEUDO: new RegExp( \"^\" + pseudos ),\n\tCHILD: new RegExp(\n\t\t\"^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\\\(\" +\n\t\twhitespace + \"*(even|odd|(([+-]|)(\\\\d*)n|)\" + whitespace + \"*(?:([+-]|)\" +\n\t\twhitespace + \"*(\\\\d+)|))\" + whitespace + \"*\\\\)|)\", \"i\" )\n};\n\nvar rpseudo = new RegExp( pseudos );\n\n// CSS escapes\n// https://www.w3.org/TR/CSS21/syndata.html#escaped-characters\n\nvar runescape = new RegExp( \"\\\\\\\\[\\\\da-fA-F]{1,6}\" + whitespace +\n\t\"?|\\\\\\\\([^\\\\r\\\\n\\\\f])\", \"g\" ),\n\tfunescape = function( escape, nonHex ) {\n\t\tvar high = \"0x\" + escape.slice( 1 ) - 0x10000;\n\n\t\tif ( nonHex ) {\n\n\t\t\t// Strip the backslash prefix from a non-hex escape sequence\n\t\t\treturn nonHex;\n\t\t}\n\n\t\t// Replace a hexadecimal escape sequence with the encoded Unicode code point\n\t\t// Support: IE <=11+\n\t\t// For values outside the Basic Multilingual Plane (BMP), manually construct a\n\t\t// surrogate pair\n\t\treturn high < 0 ?\n\t\t\tString.fromCharCode( high + 0x10000 ) :\n\t\t\tString.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 );\n\t};\n\nfunction unescapeSelector( sel ) {\n\treturn sel.replace( runescape, funescape );\n}\n\nfunction selectorError( msg ) {\n\tjQuery.error( \"Syntax error, unrecognized expression: \" + msg );\n}\n\nvar rcomma = new RegExp( \"^\" + whitespace + \"*,\" + whitespace + \"*\" );\n\nvar tokenCache = createCache();\n\nfunction tokenize( selector, parseOnly ) {\n\tvar matched, match, tokens, type,\n\t\tsoFar, groups, preFilters,\n\t\tcached = tokenCache[ selector + \" \" ];\n\n\tif ( cached ) {\n\t\treturn parseOnly ? 0 : cached.slice( 0 );\n\t}\n\n\tsoFar = selector;\n\tgroups = [];\n\tpreFilters = jQuery.expr.preFilter;\n\n\twhile ( soFar ) {\n\n\t\t// Comma and first run\n\t\tif ( !matched || ( match = rcomma.exec( soFar ) ) ) {\n\t\t\tif ( match ) {\n\n\t\t\t\t// Don't consume trailing commas as valid\n\t\t\t\tsoFar = soFar.slice( match[ 0 ].length ) || soFar;\n\t\t\t}\n\t\t\tgroups.push( ( tokens = [] ) );\n\t\t}\n\n\t\tmatched = false;\n\n\t\t// Combinators\n\t\tif ( ( match = rleadingCombinator.exec( soFar ) ) ) {\n\t\t\tmatched = match.shift();\n\t\t\ttokens.push( {\n\t\t\t\tvalue: matched,\n\n\t\t\t\t// Cast descendant combinators to space\n\t\t\t\ttype: match[ 0 ].replace( rtrimCSS, \" \" )\n\t\t\t} );\n\t\t\tsoFar = soFar.slice( matched.length );\n\t\t}\n\n\t\t// Filters\n\t\tfor ( type in filterMatchExpr ) {\n\t\t\tif ( ( match = jQuery.expr.match[ type ].exec( soFar ) ) && ( !preFilters[ type ] ||\n\t\t\t\t( match = preFilters[ type ]( match ) ) ) ) {\n\t\t\t\tmatched = match.shift();\n\t\t\t\ttokens.push( {\n\t\t\t\t\tvalue: matched,\n\t\t\t\t\ttype: type,\n\t\t\t\t\tmatches: match\n\t\t\t\t} );\n\t\t\t\tsoFar = soFar.slice( matched.length );\n\t\t\t}\n\t\t}\n\n\t\tif ( !matched ) {\n\t\t\tbreak;\n\t\t}\n\t}\n\n\t// Return the length of the invalid excess\n\t// if we're just parsing\n\t// Otherwise, throw an error or return tokens\n\tif ( parseOnly ) {\n\t\treturn soFar.length;\n\t}\n\n\treturn soFar ?\n\t\tselectorError( selector ) :\n\n\t\t// Cache the tokens\n\t\ttokenCache( selector, groups ).slice( 0 );\n}\n\nvar preFilter = {\n\tATTR: function( match ) {\n\t\tmatch[ 1 ] = unescapeSelector( match[ 1 ] );\n\n\t\t// Move the given value to match[3] whether quoted or unquoted\n\t\tmatch[ 3 ] = unescapeSelector( match[ 3 ] || match[ 4 ] || match[ 5 ] || \"\" );\n\n\t\tif ( match[ 2 ] === \"~=\" ) {\n\t\t\tmatch[ 3 ] = \" \" + match[ 3 ] + \" \";\n\t\t}\n\n\t\treturn match.slice( 0, 4 );\n\t},\n\n\tCHILD: function( match ) {\n\n\t\t/* matches from filterMatchExpr[\"CHILD\"]\n\t\t\t1 type (only|nth|...)\n\t\t\t2 what (child|of-type)\n\t\t\t3 argument (even|odd|\\d*|\\d*n([+-]\\d+)?|...)\n\t\t\t4 xn-component of xn+y argument ([+-]?\\d*n|)\n\t\t\t5 sign of xn-component\n\t\t\t6 x of xn-component\n\t\t\t7 sign of y-component\n\t\t\t8 y of y-component\n\t\t*/\n\t\tmatch[ 1 ] = match[ 1 ].toLowerCase();\n\n\t\tif ( match[ 1 ].slice( 0, 3 ) === \"nth\" ) {\n\n\t\t\t// nth-* requires argument\n\t\t\tif ( !match[ 3 ] ) {\n\t\t\t\tselectorError( match[ 0 ] );\n\t\t\t}\n\n\t\t\t// numeric x and y parameters for jQuery.expr.filter.CHILD\n\t\t\t// remember that false/true cast respectively to 0/1\n\t\t\tmatch[ 4 ] = +( match[ 4 ] ?\n\t\t\t\tmatch[ 5 ] + ( match[ 6 ] || 1 ) :\n\t\t\t\t2 * ( match[ 3 ] === \"even\" || match[ 3 ] === \"odd\" )\n\t\t\t);\n\t\t\tmatch[ 5 ] = +( ( match[ 7 ] + match[ 8 ] ) || match[ 3 ] === \"odd\" );\n\n\t\t// other types prohibit arguments\n\t\t} else if ( match[ 3 ] ) {\n\t\t\tselectorError( match[ 0 ] );\n\t\t}\n\n\t\treturn match;\n\t},\n\n\tPSEUDO: function( match ) {\n\t\tvar excess,\n\t\t\tunquoted = !match[ 6 ] && match[ 2 ];\n\n\t\tif ( filterMatchExpr.CHILD.test( match[ 0 ] ) ) {\n\t\t\treturn null;\n\t\t}\n\n\t\t// Accept quoted arguments as-is\n\t\tif ( match[ 3 ] ) {\n\t\t\tmatch[ 2 ] = match[ 4 ] || match[ 5 ] || \"\";\n\n\t\t// Strip excess characters from unquoted arguments\n\t\t} else if ( unquoted && rpseudo.test( unquoted ) &&\n\n\t\t\t// Get excess from tokenize (recursively)\n\t\t\t( excess = tokenize( unquoted, true ) ) &&\n\n\t\t\t// advance to the next closing parenthesis\n\t\t\t( excess = unquoted.indexOf( \")\", unquoted.length - excess ) -\n\t\t\t\tunquoted.length ) ) {\n\n\t\t\t// excess is a negative index\n\t\t\tmatch[ 0 ] = match[ 0 ].slice( 0, excess );\n\t\t\tmatch[ 2 ] = unquoted.slice( 0, excess );\n\t\t}\n\n\t\t// Return only captures needed by the pseudo filter method (type and argument)\n\t\treturn match.slice( 0, 3 );\n\t}\n};\n\nfunction toSelector( tokens ) {\n\tvar i = 0,\n\t\tlen = tokens.length,\n\t\tselector = \"\";\n\tfor ( ; i < len; i++ ) {\n\t\tselector += tokens[ i ].value;\n\t}\n\treturn selector;\n}\n\n// Multifunctional method to get and set values of a collection\n// The value/s can optionally be executed if it's a function\nfunction access( elems, fn, key, value, chainable, emptyGet, raw ) {\n\tvar i = 0,\n\t\tlen = elems.length,\n\t\tbulk = key == null;\n\n\t// Sets many values\n\tif ( toType( key ) === \"object\" ) {\n\t\tchainable = true;\n\t\tfor ( i in key ) {\n\t\t\taccess( elems, fn, i, key[ i ], true, emptyGet, raw );\n\t\t}\n\n\t// Sets one value\n\t} else if ( value !== undefined ) {\n\t\tchainable = true;\n\n\t\tif ( typeof value !== \"function\" ) {\n\t\t\traw = true;\n\t\t}\n\n\t\tif ( bulk ) {\n\n\t\t\t// Bulk operations run against the entire set\n\t\t\tif ( raw ) {\n\t\t\t\tfn.call( elems, value );\n\t\t\t\tfn = null;\n\n\t\t\t// ...except when executing function values\n\t\t\t} else {\n\t\t\t\tbulk = fn;\n\t\t\t\tfn = function( elem, _key, value ) {\n\t\t\t\t\treturn bulk.call( jQuery( elem ), value );\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\n\t\tif ( fn ) {\n\t\t\tfor ( ; i < len; i++ ) {\n\t\t\t\tfn(\n\t\t\t\t\telems[ i ], key, raw ?\n\t\t\t\t\t\tvalue :\n\t\t\t\t\t\tvalue.call( elems[ i ], i, fn( elems[ i ], key ) )\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\tif ( chainable ) {\n\t\treturn elems;\n\t}\n\n\t// Gets\n\tif ( bulk ) {\n\t\treturn fn.call( elems );\n\t}\n\n\treturn len ? fn( elems[ 0 ], key ) : emptyGet;\n}\n\n// Only count HTML whitespace\n// Other whitespace should count in values\n// https://infra.spec.whatwg.org/#ascii-whitespace\nvar rnothtmlwhite = /[^\\x20\\t\\r\\n\\f]+/g;\n\njQuery.fn.extend( {\n\tattr: function( name, value ) {\n\t\treturn access( this, jQuery.attr, name, value, arguments.length > 1 );\n\t},\n\n\tremoveAttr: function( name ) {\n\t\treturn this.each( function() {\n\t\t\tjQuery.removeAttr( this, name );\n\t\t} );\n\t}\n} );\n\njQuery.extend( {\n\tattr: function( elem, name, value ) {\n\t\tvar ret, hooks,\n\t\t\tnType = elem.nodeType;\n\n\t\t// Don't get/set attributes on text, comment and attribute nodes\n\t\tif ( nType === 3 || nType === 8 || nType === 2 ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Fallback to prop when attributes are not supported\n\t\tif ( typeof elem.getAttribute === \"undefined\" ) {\n\t\t\treturn jQuery.prop( elem, name, value );\n\t\t}\n\n\t\t// Attribute hooks are determined by the lowercase version\n\t\t// Grab necessary hook if one is defined\n\t\tif ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) {\n\t\t\thooks = jQuery.attrHooks[ name.toLowerCase() ];\n\t\t}\n\n\t\tif ( value !== undefined ) {\n\t\t\tif ( value === null ||\n\n\t\t\t\t// For compat with previous handling of boolean attributes,\n\t\t\t\t// remove when `false` passed. For ARIA attributes -\n\t\t\t\t// many of which recognize a `\"false\"` value - continue to\n\t\t\t\t// set the `\"false\"` value as jQuery <4 did.\n\t\t\t\t( value === false && name.toLowerCase().indexOf( \"aria-\" ) !== 0 ) ) {\n\n\t\t\t\tjQuery.removeAttr( elem, name );\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif ( hooks && \"set\" in hooks &&\n\t\t\t\t( ret = hooks.set( elem, value, name ) ) !== undefined ) {\n\t\t\t\treturn ret;\n\t\t\t}\n\n\t\t\telem.setAttribute( name, value );\n\t\t\treturn value;\n\t\t}\n\n\t\tif ( hooks && \"get\" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) {\n\t\t\treturn ret;\n\t\t}\n\n\t\tret = elem.getAttribute( name );\n\n\t\t// Non-existent attributes return null, we normalize to undefined\n\t\treturn ret == null ? undefined : ret;\n\t},\n\n\tattrHooks: {},\n\n\tremoveAttr: function( elem, value ) {\n\t\tvar name,\n\t\t\ti = 0,\n\n\t\t\t// Attribute names can contain non-HTML whitespace characters\n\t\t\t// https://html.spec.whatwg.org/multipage/syntax.html#attributes-2\n\t\t\tattrNames = value && value.match( rnothtmlwhite );\n\n\t\tif ( attrNames && elem.nodeType === 1 ) {\n\t\t\twhile ( ( name = attrNames[ i++ ] ) ) {\n\t\t\t\telem.removeAttribute( name );\n\t\t\t}\n\t\t}\n\t}\n} );\n\n// Support: IE <=11+\n// An input loses its value after becoming a radio\nif ( isIE ) {\n\tjQuery.attrHooks.type = {\n\t\tset: function( elem, value ) {\n\t\t\tif ( value === \"radio\" && nodeName( elem, \"input\" ) ) {\n\t\t\t\tvar val = elem.value;\n\t\t\t\telem.setAttribute( \"type\", value );\n\t\t\t\tif ( val ) {\n\t\t\t\t\telem.value = val;\n\t\t\t\t}\n\t\t\t\treturn value;\n\t\t\t}\n\t\t}\n\t};\n}\n\n// CSS string/identifier serialization\n// https://drafts.csswg.org/cssom/#common-serializing-idioms\nvar rcssescape = /([\\0-\\x1f\\x7f]|^-?\\d)|^-$|[^\\x80-\\uFFFF\\w-]/g;\n\nfunction fcssescape( ch, asCodePoint ) {\n\tif ( asCodePoint ) {\n\n\t\t// U+0000 NULL becomes U+FFFD REPLACEMENT CHARACTER\n\t\tif ( ch === \"\\0\" ) {\n\t\t\treturn \"\\uFFFD\";\n\t\t}\n\n\t\t// Control characters and (dependent upon position) numbers get escaped as code points\n\t\treturn ch.slice( 0, -1 ) + \"\\\\\" + ch.charCodeAt( ch.length - 1 ).toString( 16 ) + \" \";\n\t}\n\n\t// Other potentially-special ASCII characters get backslash-escaped\n\treturn \"\\\\\" + ch;\n}\n\njQuery.escapeSelector = function( sel ) {\n\treturn ( sel + \"\" ).replace( rcssescape, fcssescape );\n};\n\nvar sort = arr.sort;\n\nvar splice = arr.splice;\n\nvar hasDuplicate;\n\n// Document order sorting\nfunction sortOrder( a, b ) {\n\n\t// Flag for duplicate removal\n\tif ( a === b ) {\n\t\thasDuplicate = true;\n\t\treturn 0;\n\t}\n\n\t// Sort on method existence if only one input has compareDocumentPosition\n\tvar compare = !a.compareDocumentPosition - !b.compareDocumentPosition;\n\tif ( compare ) {\n\t\treturn compare;\n\t}\n\n\t// Calculate position if both inputs belong to the same document\n\t// Support: IE 11+\n\t// IE sometimes throws a \"Permission denied\" error when strict-comparing\n\t// two documents; shallow comparisons work.\n\t// eslint-disable-next-line eqeqeq\n\tcompare = ( a.ownerDocument || a ) == ( b.ownerDocument || b ) ?\n\t\ta.compareDocumentPosition( b ) :\n\n\t\t// Otherwise we know they are disconnected\n\t\t1;\n\n\t// Disconnected nodes\n\tif ( compare & 1 ) {\n\n\t\t// Choose the first element that is related to the document\n\t\t// Support: IE 11+\n\t\t// IE sometimes throws a \"Permission denied\" error when strict-comparing\n\t\t// two documents; shallow comparisons work.\n\t\t// eslint-disable-next-line eqeqeq\n\t\tif ( a == document$1 || a.ownerDocument == document$1 &&\n\t\t\tjQuery.contains( document$1, a ) ) {\n\t\t\treturn -1;\n\t\t}\n\n\t\t// Support: IE 11+\n\t\t// IE sometimes throws a \"Permission denied\" error when strict-comparing\n\t\t// two documents; shallow comparisons work.\n\t\t// eslint-disable-next-line eqeqeq\n\t\tif ( b == document$1 || b.ownerDocument == document$1 &&\n\t\t\tjQuery.contains( document$1, b ) ) {\n\t\t\treturn 1;\n\t\t}\n\n\t\t// Maintain original order\n\t\treturn 0;\n\t}\n\n\treturn compare & 4 ? -1 : 1;\n}\n\n/**\n * Document sorting and removing duplicates\n * @param {ArrayLike} results\n */\njQuery.uniqueSort = function( results ) {\n\tvar elem,\n\t\tduplicates = [],\n\t\tj = 0,\n\t\ti = 0;\n\n\thasDuplicate = false;\n\n\tsort.call( results, sortOrder );\n\n\tif ( hasDuplicate ) {\n\t\twhile ( ( elem = results[ i++ ] ) ) {\n\t\t\tif ( elem === results[ i ] ) {\n\t\t\t\tj = duplicates.push( i );\n\t\t\t}\n\t\t}\n\t\twhile ( j-- ) {\n\t\t\tsplice.call( results, duplicates[ j ], 1 );\n\t\t}\n\t}\n\n\treturn results;\n};\n\njQuery.fn.uniqueSort = function() {\n\treturn this.pushStack( jQuery.uniqueSort( slice.apply( this ) ) );\n};\n\nvar i,\n\toutermostContext,\n\n\t// Local document vars\n\tdocument,\n\tdocumentElement,\n\tdocumentIsHTML,\n\n\t// Instance-specific data\n\tdirruns = 0,\n\tdone = 0,\n\tclassCache = createCache(),\n\tcompilerCache = createCache(),\n\tnonnativeSelectorCache = createCache(),\n\n\t// Regular expressions\n\n\t// Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter\n\trwhitespace = new RegExp( whitespace + \"+\", \"g\" ),\n\n\tridentifier = new RegExp( \"^\" + identifier + \"$\" ),\n\n\tmatchExpr = jQuery.extend( {\n\n\t\t// For use in libraries implementing .is()\n\t\t// We use this for POS matching in `select`\n\t\tneedsContext: new RegExp( \"^\" + whitespace +\n\t\t\t\"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\\\(\" + whitespace +\n\t\t\t\"*((?:-\\\\d)?\\\\d*)\" + whitespace + \"*\\\\)|)(?=[^-]|$)\", \"i\" )\n\t}, filterMatchExpr ),\n\n\trinputs = /^(?:input|select|textarea|button)$/i,\n\trheader = /^h\\d$/i,\n\n\t// Easily-parseable/retrievable ID or TAG or CLASS selectors\n\trquickExpr$1 = /^(?:#([\\w-]+)|(\\w+)|\\.([\\w-]+))$/,\n\n\t// Used for iframes; see `setDocument`.\n\t// Support: IE 9 - 11+\n\t// Removing the function wrapper causes a \"Permission Denied\"\n\t// error in IE.\n\tunloadHandler = function() {\n\t\tsetDocument();\n\t},\n\n\tinDisabledFieldset = addCombinator(\n\t\tfunction( elem ) {\n\t\t\treturn elem.disabled === true && nodeName( elem, \"fieldset\" );\n\t\t},\n\t\t{ dir: \"parentNode\", next: \"legend\" }\n\t);\n\nfunction find( selector, context, results, seed ) {\n\tvar m, i, elem, nid, match, groups, newSelector,\n\t\tnewContext = context && context.ownerDocument,\n\n\t\t// nodeType defaults to 9, since context defaults to document\n\t\tnodeType = context ? context.nodeType : 9;\n\n\tresults = results || [];\n\n\t// Return early from calls with invalid selector or context\n\tif ( typeof selector !== \"string\" || !selector ||\n\t\tnodeType !== 1 && nodeType !== 9 && nodeType !== 11 ) {\n\n\t\treturn results;\n\t}\n\n\t// Try to shortcut find operations (as opposed to filters) in HTML documents\n\tif ( !seed ) {\n\t\tsetDocument( context );\n\t\tcontext = context || document;\n\n\t\tif ( documentIsHTML ) {\n\n\t\t\t// If the selector is sufficiently simple, try using a \"get*By*\" DOM method\n\t\t\t// (excepting DocumentFragment context, where the methods don't exist)\n\t\t\tif ( nodeType !== 11 && ( match = rquickExpr$1.exec( selector ) ) ) {\n\n\t\t\t\t// ID selector\n\t\t\t\tif ( ( m = match[ 1 ] ) ) {\n\n\t\t\t\t\t// Document context\n\t\t\t\t\tif ( nodeType === 9 ) {\n\t\t\t\t\t\tif ( ( elem = context.getElementById( m ) ) ) {\n\t\t\t\t\t\t\tpush.call( results, elem );\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn results;\n\n\t\t\t\t\t// Element context\n\t\t\t\t\t} else {\n\t\t\t\t\t\tif ( newContext && ( elem = newContext.getElementById( m ) ) &&\n\t\t\t\t\t\t\tjQuery.contains( context, elem ) ) {\n\n\t\t\t\t\t\t\tpush.call( results, elem );\n\t\t\t\t\t\t\treturn results;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t// Type selector\n\t\t\t\t} else if ( match[ 2 ] ) {\n\t\t\t\t\tpush.apply( results, context.getElementsByTagName( selector ) );\n\t\t\t\t\treturn results;\n\n\t\t\t\t// Class selector\n\t\t\t\t} else if ( ( m = match[ 3 ] ) && context.getElementsByClassName ) {\n\t\t\t\t\tpush.apply( results, context.getElementsByClassName( m ) );\n\t\t\t\t\treturn results;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Take advantage of querySelectorAll\n\t\t\tif ( !nonnativeSelectorCache[ selector + \" \" ] &&\n\t\t\t\t( !rbuggyQSA || !rbuggyQSA.test( selector ) ) ) {\n\n\t\t\t\tnewSelector = selector;\n\t\t\t\tnewContext = context;\n\n\t\t\t\t// qSA considers elements outside a scoping root when evaluating child or\n\t\t\t\t// descendant combinators, which is not what we want.\n\t\t\t\t// In such cases, we work around the behavior by prefixing every selector in the\n\t\t\t\t// list with an ID selector referencing the scope context.\n\t\t\t\t// The technique has to be used as well when a leading combinator is used\n\t\t\t\t// as such selectors are not recognized by querySelectorAll.\n\t\t\t\t// Thanks to Andrew Dupont for this technique.\n\t\t\t\tif ( nodeType === 1 &&\n\t\t\t\t\t( rdescend.test( selector ) || rleadingCombinator.test( selector ) ) ) {\n\n\t\t\t\t\t// Expand context for sibling selectors\n\t\t\t\t\tnewContext = rsibling.test( selector ) &&\n\t\t\t\t\t\ttestContext( context.parentNode ) ||\n\t\t\t\t\t\tcontext;\n\n\t\t\t\t\t// Outside of IE, if we're not changing the context we can\n\t\t\t\t\t// use :scope instead of an ID.\n\t\t\t\t\t// Support: IE 11+\n\t\t\t\t\t// IE sometimes throws a \"Permission denied\" error when strict-comparing\n\t\t\t\t\t// two documents; shallow comparisons work.\n\t\t\t\t\t// eslint-disable-next-line eqeqeq\n\t\t\t\t\tif ( newContext != context || isIE ) {\n\n\t\t\t\t\t\t// Capture the context ID, setting it first if necessary\n\t\t\t\t\t\tif ( ( nid = context.getAttribute( \"id\" ) ) ) {\n\t\t\t\t\t\t\tnid = jQuery.escapeSelector( nid );\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tcontext.setAttribute( \"id\", ( nid = jQuery.expando ) );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// Prefix every selector in the list\n\t\t\t\t\tgroups = tokenize( selector );\n\t\t\t\t\ti = groups.length;\n\t\t\t\t\twhile ( i-- ) {\n\t\t\t\t\t\tgroups[ i ] = ( nid ? \"#\" + nid : \":scope\" ) + \" \" +\n\t\t\t\t\t\t\ttoSelector( groups[ i ] );\n\t\t\t\t\t}\n\t\t\t\t\tnewSelector = groups.join( \",\" );\n\t\t\t\t}\n\n\t\t\t\ttry {\n\t\t\t\t\tpush.apply( results,\n\t\t\t\t\t\tnewContext.querySelectorAll( newSelector )\n\t\t\t\t\t);\n\t\t\t\t\treturn results;\n\t\t\t\t} catch ( qsaError ) {\n\t\t\t\t\tnonnativeSelectorCache( selector, true );\n\t\t\t\t} finally {\n\t\t\t\t\tif ( nid === jQuery.expando ) {\n\t\t\t\t\t\tcontext.removeAttribute( \"id\" );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// All others\n\treturn select( selector.replace( rtrimCSS, \"$1\" ), context, results, seed );\n}\n\n/**\n * Mark a function for special use by jQuery selector module\n * @param {Function} fn The function to mark\n */\nfunction markFunction( fn ) {\n\tfn[ jQuery.expando ] = true;\n\treturn fn;\n}\n\n/**\n * Returns a function to use in pseudos for input types\n * @param {String} type\n */\nfunction createInputPseudo( type ) {\n\treturn function( elem ) {\n\t\treturn nodeName( elem, \"input\" ) && elem.type === type;\n\t};\n}\n\n/**\n * Returns a function to use in pseudos for buttons\n * @param {String} type\n */\nfunction createButtonPseudo( type ) {\n\treturn function( elem ) {\n\t\treturn ( nodeName( elem, \"input\" ) || nodeName( elem, \"button\" ) ) &&\n\t\t\telem.type === type;\n\t};\n}\n\n/**\n * Returns a function to use in pseudos for :enabled/:disabled\n * @param {Boolean} disabled true for :disabled; false for :enabled\n */\nfunction createDisabledPseudo( disabled ) {\n\n\t// Known :disabled false positives: fieldset[disabled] > legend:nth-of-type(n+2) :can-disable\n\treturn function( elem ) {\n\n\t\t// Only certain elements can match :enabled or :disabled\n\t\t// https://html.spec.whatwg.org/multipage/scripting.html#selector-enabled\n\t\t// https://html.spec.whatwg.org/multipage/scripting.html#selector-disabled\n\t\tif ( \"form\" in elem ) {\n\n\t\t\t// Check for inherited disabledness on relevant non-disabled elements:\n\t\t\t// * listed form-associated elements in a disabled fieldset\n\t\t\t// https://html.spec.whatwg.org/multipage/forms.html#category-listed\n\t\t\t// https://html.spec.whatwg.org/multipage/forms.html#concept-fe-disabled\n\t\t\t// * option elements in a disabled optgroup\n\t\t\t// https://html.spec.whatwg.org/multipage/forms.html#concept-option-disabled\n\t\t\t// All such elements have a \"form\" property.\n\t\t\tif ( elem.parentNode && elem.disabled === false ) {\n\n\t\t\t\t// Option elements defer to a parent optgroup if present\n\t\t\t\tif ( \"label\" in elem ) {\n\t\t\t\t\tif ( \"label\" in elem.parentNode ) {\n\t\t\t\t\t\treturn elem.parentNode.disabled === disabled;\n\t\t\t\t\t} else {\n\t\t\t\t\t\treturn elem.disabled === disabled;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Support: IE 6 - 11+\n\t\t\t\t// Use the isDisabled shortcut property to check for disabled fieldset ancestors\n\t\t\t\treturn elem.isDisabled === disabled ||\n\n\t\t\t\t\t// Where there is no isDisabled, check manually\n\t\t\t\t\telem.isDisabled !== !disabled &&\n\t\t\t\t\t\tinDisabledFieldset( elem ) === disabled;\n\t\t\t}\n\n\t\t\treturn elem.disabled === disabled;\n\n\t\t// Try to winnow out elements that can't be disabled before trusting the disabled property.\n\t\t// Some victims get caught in our net (label, legend, menu, track), but it shouldn't\n\t\t// even exist on them, let alone have a boolean value.\n\t\t} else if ( \"label\" in elem ) {\n\t\t\treturn elem.disabled === disabled;\n\t\t}\n\n\t\t// Remaining elements are neither :enabled nor :disabled\n\t\treturn false;\n\t};\n}\n\n/**\n * Returns a function to use in pseudos for positionals\n * @param {Function} fn\n */\nfunction createPositionalPseudo( fn ) {\n\treturn markFunction( function( argument ) {\n\t\targument = +argument;\n\t\treturn markFunction( function( seed, matches ) {\n\t\t\tvar j,\n\t\t\t\tmatchIndexes = fn( [], seed.length, argument ),\n\t\t\t\ti = matchIndexes.length;\n\n\t\t\t// Match elements found at the specified indexes\n\t\t\twhile ( i-- ) {\n\t\t\t\tif ( seed[ ( j = matchIndexes[ i ] ) ] ) {\n\t\t\t\t\tseed[ j ] = !( matches[ j ] = seed[ j ] );\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\t} );\n}\n\n/**\n * Sets document-related variables once based on the current document\n * @param {Element|Object} [node] An element or document object to use to set the document\n */\nfunction setDocument( node ) {\n\tvar subWindow,\n\t\tdoc = node ? node.ownerDocument || node : document$1;\n\n\t// Return early if doc is invalid or already selected\n\t// Support: IE 11+\n\t// IE sometimes throws a \"Permission denied\" error when strict-comparing\n\t// two documents; shallow comparisons work.\n\t// eslint-disable-next-line eqeqeq\n\tif ( doc == document || doc.nodeType !== 9 ) {\n\t\treturn;\n\t}\n\n\t// Update global variables\n\tdocument = doc;\n\tdocumentElement = document.documentElement;\n\tdocumentIsHTML = !jQuery.isXMLDoc( document );\n\n\t// Support: IE 9 - 11+\n\t// Accessing iframe documents after unload throws \"permission denied\" errors (see trac-13936)\n\t// Support: IE 11+\n\t// IE sometimes throws a \"Permission denied\" error when strict-comparing\n\t// two documents; shallow comparisons work.\n\t// eslint-disable-next-line eqeqeq\n\tif ( isIE && document$1 != document &&\n\t\t( subWindow = document.defaultView ) && subWindow.top !== subWindow ) {\n\t\tsubWindow.addEventListener( \"unload\", unloadHandler );\n\t}\n}\n\nfind.matches = function( expr, elements ) {\n\treturn find( expr, null, null, elements );\n};\n\nfind.matchesSelector = function( elem, expr ) {\n\tsetDocument( elem );\n\n\tif ( documentIsHTML &&\n\t\t!nonnativeSelectorCache[ expr + \" \" ] &&\n\t\t( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) {\n\n\t\ttry {\n\t\t\treturn matches.call( elem, expr );\n\t\t} catch ( e ) {\n\t\t\tnonnativeSelectorCache( expr, true );\n\t\t}\n\t}\n\n\treturn find( expr, document, null, [ elem ] ).length > 0;\n};\n\njQuery.expr = {\n\n\t// Can be adjusted by the user\n\tcacheLength: 50,\n\n\tcreatePseudo: markFunction,\n\n\tmatch: matchExpr,\n\n\tfind: {\n\t\tID: function( id, context ) {\n\t\t\tif ( typeof context.getElementById !== \"undefined\" && documentIsHTML ) {\n\t\t\t\tvar elem = context.getElementById( id );\n\t\t\t\treturn elem ? [ elem ] : [];\n\t\t\t}\n\t\t},\n\n\t\tTAG: function( tag, context ) {\n\t\t\tif ( typeof context.getElementsByTagName !== \"undefined\" ) {\n\t\t\t\treturn context.getElementsByTagName( tag );\n\n\t\t\t\t// DocumentFragment nodes don't have gEBTN\n\t\t\t} else {\n\t\t\t\treturn context.querySelectorAll( tag );\n\t\t\t}\n\t\t},\n\n\t\tCLASS: function( className, context ) {\n\t\t\tif ( typeof context.getElementsByClassName !== \"undefined\" && documentIsHTML ) {\n\t\t\t\treturn context.getElementsByClassName( className );\n\t\t\t}\n\t\t}\n\t},\n\n\trelative: {\n\t\t\">\": { dir: \"parentNode\", first: true },\n\t\t\" \": { dir: \"parentNode\" },\n\t\t\"+\": { dir: \"previousSibling\", first: true },\n\t\t\"~\": { dir: \"previousSibling\" }\n\t},\n\n\tpreFilter: preFilter,\n\n\tfilter: {\n\t\tID: function( id ) {\n\t\t\tvar attrId = unescapeSelector( id );\n\t\t\treturn function( elem ) {\n\t\t\t\treturn elem.getAttribute( \"id\" ) === attrId;\n\t\t\t};\n\t\t},\n\n\t\tTAG: function( nodeNameSelector ) {\n\t\t\tvar expectedNodeName = unescapeSelector( nodeNameSelector ).toLowerCase();\n\t\t\treturn nodeNameSelector === \"*\" ?\n\n\t\t\t\tfunction() {\n\t\t\t\t\treturn true;\n\t\t\t\t} :\n\n\t\t\t\tfunction( elem ) {\n\t\t\t\t\treturn nodeName( elem, expectedNodeName );\n\t\t\t\t};\n\t\t},\n\n\t\tCLASS: function( className ) {\n\t\t\tvar pattern = classCache[ className + \" \" ];\n\n\t\t\treturn pattern ||\n\t\t\t\t( pattern = new RegExp( \"(^|\" + whitespace + \")\" + className +\n\t\t\t\t\t\"(\" + whitespace + \"|$)\" ) ) &&\n\t\t\t\tclassCache( className, function( elem ) {\n\t\t\t\t\treturn pattern.test(\n\t\t\t\t\t\ttypeof elem.className === \"string\" && elem.className ||\n\t\t\t\t\t\t\ttypeof elem.getAttribute !== \"undefined\" &&\n\t\t\t\t\t\t\t\telem.getAttribute( \"class\" ) ||\n\t\t\t\t\t\t\t\"\"\n\t\t\t\t\t);\n\t\t\t\t} );\n\t\t},\n\n\t\tATTR: function( name, operator, check ) {\n\t\t\treturn function( elem ) {\n\t\t\t\tvar result = jQuery.attr( elem, name );\n\n\t\t\t\tif ( result == null ) {\n\t\t\t\t\treturn operator === \"!=\";\n\t\t\t\t}\n\t\t\t\tif ( !operator ) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\n\t\t\t\tresult += \"\";\n\n\t\t\t\tif ( operator === \"=\" ) {\n\t\t\t\t\treturn result === check;\n\t\t\t\t}\n\t\t\t\tif ( operator === \"!=\" ) {\n\t\t\t\t\treturn result !== check;\n\t\t\t\t}\n\t\t\t\tif ( operator === \"^=\" ) {\n\t\t\t\t\treturn check && result.indexOf( check ) === 0;\n\t\t\t\t}\n\t\t\t\tif ( operator === \"*=\" ) {\n\t\t\t\t\treturn check && result.indexOf( check ) > -1;\n\t\t\t\t}\n\t\t\t\tif ( operator === \"$=\" ) {\n\t\t\t\t\treturn check && result.slice( -check.length ) === check;\n\t\t\t\t}\n\t\t\t\tif ( operator === \"~=\" ) {\n\t\t\t\t\treturn ( \" \" + result.replace( rwhitespace, \" \" ) + \" \" )\n\t\t\t\t\t\t.indexOf( check ) > -1;\n\t\t\t\t}\n\t\t\t\tif ( operator === \"|=\" ) {\n\t\t\t\t\treturn result === check || result.slice( 0, check.length + 1 ) === check + \"-\";\n\t\t\t\t}\n\n\t\t\t\treturn false;\n\t\t\t};\n\t\t},\n\n\t\tCHILD: function( type, what, _argument, first, last ) {\n\t\t\tvar simple = type.slice( 0, 3 ) !== \"nth\",\n\t\t\t\tforward = type.slice( -4 ) !== \"last\",\n\t\t\t\tofType = what === \"of-type\";\n\n\t\t\treturn first === 1 && last === 0 ?\n\n\t\t\t\t// Shortcut for :nth-*(n)\n\t\t\t\tfunction( elem ) {\n\t\t\t\t\treturn !!elem.parentNode;\n\t\t\t\t} :\n\n\t\t\t\tfunction( elem, _context, xml ) {\n\t\t\t\t\tvar cache, outerCache, node, nodeIndex, start,\n\t\t\t\t\t\tdir = simple !== forward ? \"nextSibling\" : \"previousSibling\",\n\t\t\t\t\t\tparent = elem.parentNode,\n\t\t\t\t\t\tname = ofType && elem.nodeName.toLowerCase(),\n\t\t\t\t\t\tuseCache = !xml && !ofType,\n\t\t\t\t\t\tdiff = false;\n\n\t\t\t\t\tif ( parent ) {\n\n\t\t\t\t\t\t// :(first|last|only)-(child|of-type)\n\t\t\t\t\t\tif ( simple ) {\n\t\t\t\t\t\t\twhile ( dir ) {\n\t\t\t\t\t\t\t\tnode = elem;\n\t\t\t\t\t\t\t\twhile ( ( node = node[ dir ] ) ) {\n\t\t\t\t\t\t\t\t\tif ( ofType ?\n\t\t\t\t\t\t\t\t\t\tnodeName( node, name ) :\n\t\t\t\t\t\t\t\t\t\tnode.nodeType === 1 ) {\n\n\t\t\t\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t// Reverse direction for :only-* (if we haven't yet done so)\n\t\t\t\t\t\t\t\tstart = dir = type === \"only\" && !start && \"nextSibling\";\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tstart = [ forward ? parent.firstChild : parent.lastChild ];\n\n\t\t\t\t\t\t// non-xml :nth-child(...) stores cache data on `parent`\n\t\t\t\t\t\tif ( forward && useCache ) {\n\n\t\t\t\t\t\t\t// Seek `elem` from a previously-cached index\n\t\t\t\t\t\t\touterCache = parent[ jQuery.expando ] ||\n\t\t\t\t\t\t\t\t( parent[ jQuery.expando ] = {} );\n\t\t\t\t\t\t\tcache = outerCache[ type ] || [];\n\t\t\t\t\t\t\tnodeIndex = cache[ 0 ] === dirruns && cache[ 1 ];\n\t\t\t\t\t\t\tdiff = nodeIndex && cache[ 2 ];\n\t\t\t\t\t\t\tnode = nodeIndex && parent.childNodes[ nodeIndex ];\n\n\t\t\t\t\t\t\twhile ( ( node = ++nodeIndex && node && node[ dir ] ||\n\n\t\t\t\t\t\t\t\t// Fallback to seeking `elem` from the start\n\t\t\t\t\t\t\t\t( diff = nodeIndex = 0 ) || start.pop() ) ) {\n\n\t\t\t\t\t\t\t\t// When found, cache indexes on `parent` and break\n\t\t\t\t\t\t\t\tif ( node.nodeType === 1 && ++diff && node === elem ) {\n\t\t\t\t\t\t\t\t\touterCache[ type ] = [ dirruns, nodeIndex, diff ];\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t// Use previously-cached element index if available\n\t\t\t\t\t\t\tif ( useCache ) {\n\t\t\t\t\t\t\t\touterCache = elem[ jQuery.expando ] ||\n\t\t\t\t\t\t\t\t\t( elem[ jQuery.expando ] = {} );\n\t\t\t\t\t\t\t\tcache = outerCache[ type ] || [];\n\t\t\t\t\t\t\t\tnodeIndex = cache[ 0 ] === dirruns && cache[ 1 ];\n\t\t\t\t\t\t\t\tdiff = nodeIndex;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// xml :nth-child(...)\n\t\t\t\t\t\t\t// or :nth-last-child(...) or :nth(-last)?-of-type(...)\n\t\t\t\t\t\t\tif ( diff === false ) {\n\n\t\t\t\t\t\t\t\t// Use the same loop as above to seek `elem` from the start\n\t\t\t\t\t\t\t\twhile ( ( node = ++nodeIndex && node && node[ dir ] ||\n\t\t\t\t\t\t\t\t\t( diff = nodeIndex = 0 ) || start.pop() ) ) {\n\n\t\t\t\t\t\t\t\t\tif ( ( ofType ?\n\t\t\t\t\t\t\t\t\t\tnodeName( node, name ) :\n\t\t\t\t\t\t\t\t\t\tnode.nodeType === 1 ) &&\n\t\t\t\t\t\t\t\t\t\t++diff ) {\n\n\t\t\t\t\t\t\t\t\t\t// Cache the index of each encountered element\n\t\t\t\t\t\t\t\t\t\tif ( useCache ) {\n\t\t\t\t\t\t\t\t\t\t\touterCache = node[ jQuery.expando ] ||\n\t\t\t\t\t\t\t\t\t\t\t\t( node[ jQuery.expando ] = {} );\n\t\t\t\t\t\t\t\t\t\t\touterCache[ type ] = [ dirruns, diff ];\n\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t\tif ( node === elem ) {\n\t\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Incorporate the offset, then check against cycle size\n\t\t\t\t\t\tdiff -= last;\n\t\t\t\t\t\treturn diff === first || ( diff % first === 0 && diff / first >= 0 );\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t},\n\n\t\tPSEUDO: function( pseudo, argument ) {\n\n\t\t\t// pseudo-class names are case-insensitive\n\t\t\t// https://www.w3.org/TR/selectors/#pseudo-classes\n\t\t\t// Prioritize by case sensitivity in case custom pseudos are added with uppercase letters\n\t\t\t// Remember that setFilters inherits from pseudos\n\t\t\tvar fn = jQuery.expr.pseudos[ pseudo ] ||\n\t\t\t\tjQuery.expr.setFilters[ pseudo.toLowerCase() ] ||\n\t\t\t\tselectorError( \"unsupported pseudo: \" + pseudo );\n\n\t\t\t// The user may use createPseudo to indicate that\n\t\t\t// arguments are needed to create the filter function\n\t\t\t// just as jQuery does\n\t\t\tif ( fn[ jQuery.expando ] ) {\n\t\t\t\treturn fn( argument );\n\t\t\t}\n\n\t\t\treturn fn;\n\t\t}\n\t},\n\n\tpseudos: {\n\n\t\t// Potentially complex pseudos\n\t\tnot: markFunction( function( selector ) {\n\n\t\t\t// Trim the selector passed to compile\n\t\t\t// to avoid treating leading and trailing\n\t\t\t// spaces as combinators\n\t\t\tvar input = [],\n\t\t\t\tresults = [],\n\t\t\t\tmatcher = compile( selector.replace( rtrimCSS, \"$1\" ) );\n\n\t\t\treturn matcher[ jQuery.expando ] ?\n\t\t\t\tmarkFunction( function( seed, matches, _context, xml ) {\n\t\t\t\t\tvar elem,\n\t\t\t\t\t\tunmatched = matcher( seed, null, xml, [] ),\n\t\t\t\t\t\ti = seed.length;\n\n\t\t\t\t\t// Match elements unmatched by `matcher`\n\t\t\t\t\twhile ( i-- ) {\n\t\t\t\t\t\tif ( ( elem = unmatched[ i ] ) ) {\n\t\t\t\t\t\t\tseed[ i ] = !( matches[ i ] = elem );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} ) :\n\t\t\t\tfunction( elem, _context, xml ) {\n\t\t\t\t\tinput[ 0 ] = elem;\n\t\t\t\t\tmatcher( input, null, xml, results );\n\n\t\t\t\t\t// Don't keep the element\n\t\t\t\t\t// (see https://github.com/jquery/sizzle/issues/299)\n\t\t\t\t\tinput[ 0 ] = null;\n\t\t\t\t\treturn !results.pop();\n\t\t\t\t};\n\t\t} ),\n\n\t\thas: markFunction( function( selector ) {\n\t\t\treturn function( elem ) {\n\t\t\t\treturn find( selector, elem ).length > 0;\n\t\t\t};\n\t\t} ),\n\n\t\tcontains: markFunction( function( text ) {\n\t\t\ttext = unescapeSelector( text );\n\t\t\treturn function( elem ) {\n\t\t\t\treturn ( elem.textContent || jQuery.text( elem ) ).indexOf( text ) > -1;\n\t\t\t};\n\t\t} ),\n\n\t\t// \"Whether an element is represented by a :lang() selector\n\t\t// is based solely on the element's language value\n\t\t// being equal to the identifier C,\n\t\t// or beginning with the identifier C immediately followed by \"-\".\n\t\t// The matching of C against the element's language value is performed case-insensitively.\n\t\t// The identifier C does not have to be a valid language name.\"\n\t\t// https://www.w3.org/TR/selectors/#lang-pseudo\n\t\tlang: markFunction( function( lang ) {\n\n\t\t\t// lang value must be a valid identifier\n\t\t\tif ( !ridentifier.test( lang || \"\" ) ) {\n\t\t\t\tselectorError( \"unsupported lang: \" + lang );\n\t\t\t}\n\t\t\tlang = unescapeSelector( lang ).toLowerCase();\n\t\t\treturn function( elem ) {\n\t\t\t\tvar elemLang;\n\t\t\t\tdo {\n\t\t\t\t\tif ( ( elemLang = documentIsHTML ?\n\t\t\t\t\t\telem.lang :\n\t\t\t\t\t\telem.getAttribute( \"xml:lang\" ) || elem.getAttribute( \"lang\" ) ) ) {\n\n\t\t\t\t\t\telemLang = elemLang.toLowerCase();\n\t\t\t\t\t\treturn elemLang === lang || elemLang.indexOf( lang + \"-\" ) === 0;\n\t\t\t\t\t}\n\t\t\t\t} while ( ( elem = elem.parentNode ) && elem.nodeType === 1 );\n\t\t\t\treturn false;\n\t\t\t};\n\t\t} ),\n\n\t\t// Miscellaneous\n\t\ttarget: function( elem ) {\n\t\t\tvar hash = window.location && window.location.hash;\n\t\t\treturn hash && hash.slice( 1 ) === elem.id;\n\t\t},\n\n\t\troot: function( elem ) {\n\t\t\treturn elem === documentElement;\n\t\t},\n\n\t\tfocus: function( elem ) {\n\t\t\treturn elem === document.activeElement &&\n\t\t\t\tdocument.hasFocus() &&\n\t\t\t\t!!( elem.type || elem.href || ~elem.tabIndex );\n\t\t},\n\n\t\t// Boolean properties\n\t\tenabled: createDisabledPseudo( false ),\n\t\tdisabled: createDisabledPseudo( true ),\n\n\t\tchecked: function( elem ) {\n\n\t\t\t// In CSS3, :checked should return both checked and selected elements\n\t\t\t// https://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked\n\t\t\treturn ( nodeName( elem, \"input\" ) && !!elem.checked ) ||\n\t\t\t\t( nodeName( elem, \"option\" ) && !!elem.selected );\n\t\t},\n\n\t\tselected: function( elem ) {\n\n\t\t\t// Support: IE <=11+\n\t\t\t// Accessing the selectedIndex property\n\t\t\t// forces the browser to treat the default option as\n\t\t\t// selected when in an optgroup.\n\t\t\tif ( isIE && elem.parentNode ) {\n\t\t\t\t// eslint-disable-next-line no-unused-expressions\n\t\t\t\telem.parentNode.selectedIndex;\n\t\t\t}\n\n\t\t\treturn elem.selected === true;\n\t\t},\n\n\t\t// Contents\n\t\tempty: function( elem ) {\n\n\t\t\t// https://www.w3.org/TR/selectors/#empty-pseudo\n\t\t\t// :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5),\n\t\t\t// but not by others (comment: 8; processing instruction: 7; etc.)\n\t\t\t// nodeType < 6 works because attributes (2) do not appear as children\n\t\t\tfor ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {\n\t\t\t\tif ( elem.nodeType < 6 ) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn true;\n\t\t},\n\n\t\tparent: function( elem ) {\n\t\t\treturn !jQuery.expr.pseudos.empty( elem );\n\t\t},\n\n\t\t// Element/input types\n\t\theader: function( elem ) {\n\t\t\treturn rheader.test( elem.nodeName );\n\t\t},\n\n\t\tinput: function( elem ) {\n\t\t\treturn rinputs.test( elem.nodeName );\n\t\t},\n\n\t\tbutton: function( elem ) {\n\t\t\treturn nodeName( elem, \"input\" ) && elem.type === \"button\" ||\n\t\t\t\tnodeName( elem, \"button\" );\n\t\t},\n\n\t\ttext: function( elem ) {\n\t\t\treturn nodeName( elem, \"input\" ) && elem.type === \"text\";\n\t\t},\n\n\t\t// Position-in-collection\n\t\tfirst: createPositionalPseudo( function() {\n\t\t\treturn [ 0 ];\n\t\t} ),\n\n\t\tlast: createPositionalPseudo( function( _matchIndexes, length ) {\n\t\t\treturn [ length - 1 ];\n\t\t} ),\n\n\t\teq: createPositionalPseudo( function( _matchIndexes, length, argument ) {\n\t\t\treturn [ argument < 0 ? argument + length : argument ];\n\t\t} ),\n\n\t\teven: createPositionalPseudo( function( matchIndexes, length ) {\n\t\t\tvar i = 0;\n\t\t\tfor ( ; i < length; i += 2 ) {\n\t\t\t\tmatchIndexes.push( i );\n\t\t\t}\n\t\t\treturn matchIndexes;\n\t\t} ),\n\n\t\todd: createPositionalPseudo( function( matchIndexes, length ) {\n\t\t\tvar i = 1;\n\t\t\tfor ( ; i < length; i += 2 ) {\n\t\t\t\tmatchIndexes.push( i );\n\t\t\t}\n\t\t\treturn matchIndexes;\n\t\t} ),\n\n\t\tlt: createPositionalPseudo( function( matchIndexes, length, argument ) {\n\t\t\tvar i;\n\n\t\t\tif ( argument < 0 ) {\n\t\t\t\ti = argument + length;\n\t\t\t} else if ( argument > length ) {\n\t\t\t\ti = length;\n\t\t\t} else {\n\t\t\t\ti = argument;\n\t\t\t}\n\n\t\t\tfor ( ; --i >= 0; ) {\n\t\t\t\tmatchIndexes.push( i );\n\t\t\t}\n\t\t\treturn matchIndexes;\n\t\t} ),\n\n\t\tgt: createPositionalPseudo( function( matchIndexes, length, argument ) {\n\t\t\tvar i = argument < 0 ? argument + length : argument;\n\t\t\tfor ( ; ++i < length; ) {\n\t\t\t\tmatchIndexes.push( i );\n\t\t\t}\n\t\t\treturn matchIndexes;\n\t\t} )\n\t}\n};\n\njQuery.expr.pseudos.nth = jQuery.expr.pseudos.eq;\n\n// Add button/input type pseudos\nfor ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) {\n\tjQuery.expr.pseudos[ i ] = createInputPseudo( i );\n}\nfor ( i in { submit: true, reset: true } ) {\n\tjQuery.expr.pseudos[ i ] = createButtonPseudo( i );\n}\n\n// Easy API for creating new setFilters\nfunction setFilters() {}\nsetFilters.prototype = jQuery.expr.pseudos;\njQuery.expr.setFilters = new setFilters();\n\nfunction addCombinator( matcher, combinator, base ) {\n\tvar dir = combinator.dir,\n\t\tskip = combinator.next,\n\t\tkey = skip || dir,\n\t\tcheckNonElements = base && key === \"parentNode\",\n\t\tdoneName = done++;\n\n\treturn combinator.first ?\n\n\t\t// Check against closest ancestor/preceding element\n\t\tfunction( elem, context, xml ) {\n\t\t\twhile ( ( elem = elem[ dir ] ) ) {\n\t\t\t\tif ( elem.nodeType === 1 || checkNonElements ) {\n\t\t\t\t\treturn matcher( elem, context, xml );\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn false;\n\t\t} :\n\n\t\t// Check against all ancestor/preceding elements\n\t\tfunction( elem, context, xml ) {\n\t\t\tvar oldCache, outerCache,\n\t\t\t\tnewCache = [ dirruns, doneName ];\n\n\t\t\t// We can't set arbitrary data on XML nodes, so they don't benefit from combinator caching\n\t\t\tif ( xml ) {\n\t\t\t\twhile ( ( elem = elem[ dir ] ) ) {\n\t\t\t\t\tif ( elem.nodeType === 1 || checkNonElements ) {\n\t\t\t\t\t\tif ( matcher( elem, context, xml ) ) {\n\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\twhile ( ( elem = elem[ dir ] ) ) {\n\t\t\t\t\tif ( elem.nodeType === 1 || checkNonElements ) {\n\t\t\t\t\t\touterCache = elem[ jQuery.expando ] || ( elem[ jQuery.expando ] = {} );\n\n\t\t\t\t\t\tif ( skip && nodeName( elem, skip ) ) {\n\t\t\t\t\t\t\telem = elem[ dir ] || elem;\n\t\t\t\t\t\t} else if ( ( oldCache = outerCache[ key ] ) &&\n\t\t\t\t\t\t\toldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) {\n\n\t\t\t\t\t\t\t// Assign to newCache so results back-propagate to previous elements\n\t\t\t\t\t\t\treturn ( newCache[ 2 ] = oldCache[ 2 ] );\n\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t// Reuse newcache so results back-propagate to previous elements\n\t\t\t\t\t\t\touterCache[ key ] = newCache;\n\n\t\t\t\t\t\t\t// A match means we're done; a fail means we have to keep checking\n\t\t\t\t\t\t\tif ( ( newCache[ 2 ] = matcher( elem, context, xml ) ) ) {\n\t\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn false;\n\t\t};\n}\n\nfunction elementMatcher( matchers ) {\n\treturn matchers.length > 1 ?\n\t\tfunction( elem, context, xml ) {\n\t\t\tvar i = matchers.length;\n\t\t\twhile ( i-- ) {\n\t\t\t\tif ( !matchers[ i ]( elem, context, xml ) ) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn true;\n\t\t} :\n\t\tmatchers[ 0 ];\n}\n\nfunction multipleContexts( selector, contexts, results ) {\n\tvar i = 0,\n\t\tlen = contexts.length;\n\tfor ( ; i < len; i++ ) {\n\t\tfind( selector, contexts[ i ], results );\n\t}\n\treturn results;\n}\n\nfunction condense( unmatched, map, filter, context, xml ) {\n\tvar elem,\n\t\tnewUnmatched = [],\n\t\ti = 0,\n\t\tlen = unmatched.length,\n\t\tmapped = map != null;\n\n\tfor ( ; i < len; i++ ) {\n\t\tif ( ( elem = unmatched[ i ] ) ) {\n\t\t\tif ( !filter || filter( elem, context, xml ) ) {\n\t\t\t\tnewUnmatched.push( elem );\n\t\t\t\tif ( mapped ) {\n\t\t\t\t\tmap.push( i );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn newUnmatched;\n}\n\nfunction setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) {\n\tif ( postFilter && !postFilter[ jQuery.expando ] ) {\n\t\tpostFilter = setMatcher( postFilter );\n\t}\n\tif ( postFinder && !postFinder[ jQuery.expando ] ) {\n\t\tpostFinder = setMatcher( postFinder, postSelector );\n\t}\n\treturn markFunction( function( seed, results, context, xml ) {\n\t\tvar temp, i, elem, matcherOut,\n\t\t\tpreMap = [],\n\t\t\tpostMap = [],\n\t\t\tpreexisting = results.length,\n\n\t\t\t// Get initial elements from seed or context\n\t\t\telems = seed ||\n\t\t\t\tmultipleContexts( selector || \"*\",\n\t\t\t\t\tcontext.nodeType ? [ context ] : context, [] ),\n\n\t\t\t// Prefilter to get matcher input, preserving a map for seed-results synchronization\n\t\t\tmatcherIn = preFilter && ( seed || !selector ) ?\n\t\t\t\tcondense( elems, preMap, preFilter, context, xml ) :\n\t\t\t\telems;\n\n\t\tif ( matcher ) {\n\n\t\t\t// If we have a postFinder, or filtered seed, or non-seed postFilter\n\t\t\t// or preexisting results,\n\t\t\tmatcherOut = postFinder || ( seed ? preFilter : preexisting || postFilter ) ?\n\n\t\t\t\t// ...intermediate processing is necessary\n\t\t\t\t[] :\n\n\t\t\t\t// ...otherwise use results directly\n\t\t\t\tresults;\n\n\t\t\t// Find primary matches\n\t\t\tmatcher( matcherIn, matcherOut, context, xml );\n\t\t} else {\n\t\t\tmatcherOut = matcherIn;\n\t\t}\n\n\t\t// Apply postFilter\n\t\tif ( postFilter ) {\n\t\t\ttemp = condense( matcherOut, postMap );\n\t\t\tpostFilter( temp, [], context, xml );\n\n\t\t\t// Un-match failing elements by moving them back to matcherIn\n\t\t\ti = temp.length;\n\t\t\twhile ( i-- ) {\n\t\t\t\tif ( ( elem = temp[ i ] ) ) {\n\t\t\t\t\tmatcherOut[ postMap[ i ] ] = !( matcherIn[ postMap[ i ] ] = elem );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif ( seed ) {\n\t\t\tif ( postFinder || preFilter ) {\n\t\t\t\tif ( postFinder ) {\n\n\t\t\t\t\t// Get the final matcherOut by condensing this intermediate into postFinder contexts\n\t\t\t\t\ttemp = [];\n\t\t\t\t\ti = matcherOut.length;\n\t\t\t\t\twhile ( i-- ) {\n\t\t\t\t\t\tif ( ( elem = matcherOut[ i ] ) ) {\n\n\t\t\t\t\t\t\t// Restore matcherIn since elem is not yet a final match\n\t\t\t\t\t\t\ttemp.push( ( matcherIn[ i ] = elem ) );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tpostFinder( null, ( matcherOut = [] ), temp, xml );\n\t\t\t\t}\n\n\t\t\t\t// Move matched elements from seed to results to keep them synchronized\n\t\t\t\ti = matcherOut.length;\n\t\t\t\twhile ( i-- ) {\n\t\t\t\t\tif ( ( elem = matcherOut[ i ] ) &&\n\t\t\t\t\t\t( temp = postFinder ? indexOf.call( seed, elem ) : preMap[ i ] ) > -1 ) {\n\n\t\t\t\t\t\tseed[ temp ] = !( results[ temp ] = elem );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t// Add elements to results, through postFinder if defined\n\t\t} else {\n\t\t\tmatcherOut = condense(\n\t\t\t\tmatcherOut === results ?\n\t\t\t\t\tmatcherOut.splice( preexisting, matcherOut.length ) :\n\t\t\t\t\tmatcherOut\n\t\t\t);\n\t\t\tif ( postFinder ) {\n\t\t\t\tpostFinder( null, results, matcherOut, xml );\n\t\t\t} else {\n\t\t\t\tpush.apply( results, matcherOut );\n\t\t\t}\n\t\t}\n\t} );\n}\n\nfunction matcherFromTokens( tokens ) {\n\tvar checkContext, matcher, j,\n\t\tlen = tokens.length,\n\t\tleadingRelative = jQuery.expr.relative[ tokens[ 0 ].type ],\n\t\timplicitRelative = leadingRelative || jQuery.expr.relative[ \" \" ],\n\t\ti = leadingRelative ? 1 : 0,\n\n\t\t// The foundational matcher ensures that elements are reachable from top-level context(s)\n\t\tmatchContext = addCombinator( function( elem ) {\n\t\t\treturn elem === checkContext;\n\t\t}, implicitRelative, true ),\n\t\tmatchAnyContext = addCombinator( function( elem ) {\n\t\t\treturn indexOf.call( checkContext, elem ) > -1;\n\t\t}, implicitRelative, true ),\n\t\tmatchers = [ function( elem, context, xml ) {\n\n\t\t\t// Support: IE 11+\n\t\t\t// IE sometimes throws a \"Permission denied\" error when strict-comparing\n\t\t\t// two documents; shallow comparisons work.\n\t\t\t// eslint-disable-next-line eqeqeq\n\t\t\tvar ret = ( !leadingRelative && ( xml || context != outermostContext ) ) || (\n\t\t\t\t( checkContext = context ).nodeType ?\n\t\t\t\t\tmatchContext( elem, context, xml ) :\n\t\t\t\t\tmatchAnyContext( elem, context, xml ) );\n\n\t\t\t// Avoid hanging onto element\n\t\t\t// (see https://github.com/jquery/sizzle/issues/299)\n\t\t\tcheckContext = null;\n\t\t\treturn ret;\n\t\t} ];\n\n\tfor ( ; i < len; i++ ) {\n\t\tif ( ( matcher = jQuery.expr.relative[ tokens[ i ].type ] ) ) {\n\t\t\tmatchers = [ addCombinator( elementMatcher( matchers ), matcher ) ];\n\t\t} else {\n\t\t\tmatcher = jQuery.expr.filter[ tokens[ i ].type ].apply( null, tokens[ i ].matches );\n\n\t\t\t// Return special upon seeing a positional matcher\n\t\t\tif ( matcher[ jQuery.expando ] ) {\n\n\t\t\t\t// Find the next relative operator (if any) for proper handling\n\t\t\t\tj = ++i;\n\t\t\t\tfor ( ; j < len; j++ ) {\n\t\t\t\t\tif ( jQuery.expr.relative[ tokens[ j ].type ] ) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn setMatcher(\n\t\t\t\t\ti > 1 && elementMatcher( matchers ),\n\t\t\t\t\ti > 1 && toSelector(\n\n\t\t\t\t\t\t// If the preceding token was a descendant combinator, insert an implicit any-element `*`\n\t\t\t\t\t\ttokens.slice( 0, i - 1 )\n\t\t\t\t\t\t\t.concat( { value: tokens[ i - 2 ].type === \" \" ? \"*\" : \"\" } )\n\t\t\t\t\t).replace( rtrimCSS, \"$1\" ),\n\t\t\t\t\tmatcher,\n\t\t\t\t\ti < j && matcherFromTokens( tokens.slice( i, j ) ),\n\t\t\t\t\tj < len && matcherFromTokens( ( tokens = tokens.slice( j ) ) ),\n\t\t\t\t\tj < len && toSelector( tokens )\n\t\t\t\t);\n\t\t\t}\n\t\t\tmatchers.push( matcher );\n\t\t}\n\t}\n\n\treturn elementMatcher( matchers );\n}\n\nfunction matcherFromGroupMatchers( elementMatchers, setMatchers ) {\n\tvar bySet = setMatchers.length > 0,\n\t\tbyElement = elementMatchers.length > 0,\n\t\tsuperMatcher = function( seed, context, xml, results, outermost ) {\n\t\t\tvar elem, j, matcher,\n\t\t\t\tmatchedCount = 0,\n\t\t\t\ti = \"0\",\n\t\t\t\tunmatched = seed && [],\n\t\t\t\tsetMatched = [],\n\t\t\t\tcontextBackup = outermostContext,\n\n\t\t\t\t// We must always have either seed elements or outermost context\n\t\t\t\telems = seed || byElement && jQuery.expr.find.TAG( \"*\", outermost ),\n\n\t\t\t\t// Use integer dirruns iff this is the outermost matcher\n\t\t\t\tdirrunsUnique = ( dirruns += contextBackup == null ? 1 : Math.random() || 0.1 );\n\n\t\t\tif ( outermost ) {\n\n\t\t\t\t// Support: IE 11+\n\t\t\t\t// IE sometimes throws a \"Permission denied\" error when strict-comparing\n\t\t\t\t// two documents; shallow comparisons work.\n\t\t\t\t// eslint-disable-next-line eqeqeq\n\t\t\t\toutermostContext = context == document || context || outermost;\n\t\t\t}\n\n\t\t\t// Add elements passing elementMatchers directly to results\n\t\t\tfor ( ; ( elem = elems[ i ] ) != null; i++ ) {\n\t\t\t\tif ( byElement && elem ) {\n\t\t\t\t\tj = 0;\n\n\t\t\t\t\t// Support: IE 11+\n\t\t\t\t\t// IE sometimes throws a \"Permission denied\" error when strict-comparing\n\t\t\t\t\t// two documents; shallow comparisons work.\n\t\t\t\t\t// eslint-disable-next-line eqeqeq\n\t\t\t\t\tif ( !context && elem.ownerDocument != document ) {\n\t\t\t\t\t\tsetDocument( elem );\n\t\t\t\t\t\txml = !documentIsHTML;\n\t\t\t\t\t}\n\t\t\t\t\twhile ( ( matcher = elementMatchers[ j++ ] ) ) {\n\t\t\t\t\t\tif ( matcher( elem, context || document, xml ) ) {\n\t\t\t\t\t\t\tpush.call( results, elem );\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif ( outermost ) {\n\t\t\t\t\t\tdirruns = dirrunsUnique;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Track unmatched elements for set filters\n\t\t\t\tif ( bySet ) {\n\n\t\t\t\t\t// They will have gone through all possible matchers\n\t\t\t\t\tif ( ( elem = !matcher && elem ) ) {\n\t\t\t\t\t\tmatchedCount--;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Lengthen the array for every element, matched or not\n\t\t\t\t\tif ( seed ) {\n\t\t\t\t\t\tunmatched.push( elem );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// `i` is now the count of elements visited above, and adding it to `matchedCount`\n\t\t\t// makes the latter nonnegative.\n\t\t\tmatchedCount += i;\n\n\t\t\t// Apply set filters to unmatched elements\n\t\t\t// NOTE: This can be skipped if there are no unmatched elements (i.e., `matchedCount`\n\t\t\t// equals `i`), unless we didn't visit _any_ elements in the above loop because we have\n\t\t\t// no element matchers and no seed.\n\t\t\t// Incrementing an initially-string \"0\" `i` allows `i` to remain a string only in that\n\t\t\t// case, which will result in a \"00\" `matchedCount` that differs from `i` but is also\n\t\t\t// numerically zero.\n\t\t\tif ( bySet && i !== matchedCount ) {\n\t\t\t\tj = 0;\n\t\t\t\twhile ( ( matcher = setMatchers[ j++ ] ) ) {\n\t\t\t\t\tmatcher( unmatched, setMatched, context, xml );\n\t\t\t\t}\n\n\t\t\t\tif ( seed ) {\n\n\t\t\t\t\t// Reintegrate element matches to eliminate the need for sorting\n\t\t\t\t\tif ( matchedCount > 0 ) {\n\t\t\t\t\t\twhile ( i-- ) {\n\t\t\t\t\t\t\tif ( !( unmatched[ i ] || setMatched[ i ] ) ) {\n\t\t\t\t\t\t\t\tsetMatched[ i ] = pop.call( results );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// Discard index placeholder values to get only actual matches\n\t\t\t\t\tsetMatched = condense( setMatched );\n\t\t\t\t}\n\n\t\t\t\t// Add matches to results\n\t\t\t\tpush.apply( results, setMatched );\n\n\t\t\t\t// Seedless set matches succeeding multiple successful matchers stipulate sorting\n\t\t\t\tif ( outermost && !seed && setMatched.length > 0 &&\n\t\t\t\t\t( matchedCount + setMatchers.length ) > 1 ) {\n\n\t\t\t\t\tjQuery.uniqueSort( results );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Override manipulation of globals by nested matchers\n\t\t\tif ( outermost ) {\n\t\t\t\tdirruns = dirrunsUnique;\n\t\t\t\toutermostContext = contextBackup;\n\t\t\t}\n\n\t\t\treturn unmatched;\n\t\t};\n\n\treturn bySet ?\n\t\tmarkFunction( superMatcher ) :\n\t\tsuperMatcher;\n}\n\nfunction compile( selector, match /* Internal Use Only */ ) {\n\tvar i,\n\t\tsetMatchers = [],\n\t\telementMatchers = [],\n\t\tcached = compilerCache[ selector + \" \" ];\n\n\tif ( !cached ) {\n\n\t\t// Generate a function of recursive functions that can be used to check each element\n\t\tif ( !match ) {\n\t\t\tmatch = tokenize( selector );\n\t\t}\n\t\ti = match.length;\n\t\twhile ( i-- ) {\n\t\t\tcached = matcherFromTokens( match[ i ] );\n\t\t\tif ( cached[ jQuery.expando ] ) {\n\t\t\t\tsetMatchers.push( cached );\n\t\t\t} else {\n\t\t\t\telementMatchers.push( cached );\n\t\t\t}\n\t\t}\n\n\t\t// Cache the compiled function\n\t\tcached = compilerCache( selector,\n\t\t\tmatcherFromGroupMatchers( elementMatchers, setMatchers ) );\n\n\t\t// Save selector and tokenization\n\t\tcached.selector = selector;\n\t}\n\treturn cached;\n}\n\n/**\n * A low-level selection function that works with jQuery's compiled\n * selector functions\n * @param {String|Function} selector A selector or a pre-compiled\n * selector function built with jQuery selector compile\n * @param {Element} context\n * @param {Array} [results]\n * @param {Array} [seed] A set of elements to match against\n */\nfunction select( selector, context, results, seed ) {\n\tvar i, tokens, token, type, find,\n\t\tcompiled = typeof selector === \"function\" && selector,\n\t\tmatch = !seed && tokenize( ( selector = compiled.selector || selector ) );\n\n\tresults = results || [];\n\n\t// Try to minimize operations if there is only one selector in the list and no seed\n\t// (the latter of which guarantees us context)\n\tif ( match.length === 1 ) {\n\n\t\t// Reduce context if the leading compound selector is an ID\n\t\ttokens = match[ 0 ] = match[ 0 ].slice( 0 );\n\t\tif ( tokens.length > 2 && ( token = tokens[ 0 ] ).type === \"ID\" &&\n\t\t\t\tcontext.nodeType === 9 && documentIsHTML &&\n\t\t\t\tjQuery.expr.relative[ tokens[ 1 ].type ] ) {\n\n\t\t\tcontext = ( jQuery.expr.find.ID(\n\t\t\t\tunescapeSelector( token.matches[ 0 ] ),\n\t\t\t\tcontext\n\t\t\t) || [] )[ 0 ];\n\t\t\tif ( !context ) {\n\t\t\t\treturn results;\n\n\t\t\t// Precompiled matchers will still verify ancestry, so step up a level\n\t\t\t} else if ( compiled ) {\n\t\t\t\tcontext = context.parentNode;\n\t\t\t}\n\n\t\t\tselector = selector.slice( tokens.shift().value.length );\n\t\t}\n\n\t\t// Fetch a seed set for right-to-left matching\n\t\ti = matchExpr.needsContext.test( selector ) ? 0 : tokens.length;\n\t\twhile ( i-- ) {\n\t\t\ttoken = tokens[ i ];\n\n\t\t\t// Abort if we hit a combinator\n\t\t\tif ( jQuery.expr.relative[ ( type = token.type ) ] ) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif ( ( find = jQuery.expr.find[ type ] ) ) {\n\n\t\t\t\t// Search, expanding context for leading sibling combinators\n\t\t\t\tif ( ( seed = find(\n\t\t\t\t\tunescapeSelector( token.matches[ 0 ] ),\n\t\t\t\t\trsibling.test( tokens[ 0 ].type ) &&\n\t\t\t\t\t\ttestContext( context.parentNode ) || context\n\t\t\t\t) ) ) {\n\n\t\t\t\t\t// If seed is empty or no tokens remain, we can return early\n\t\t\t\t\ttokens.splice( i, 1 );\n\t\t\t\t\tselector = seed.length && toSelector( tokens );\n\t\t\t\t\tif ( !selector ) {\n\t\t\t\t\t\tpush.apply( results, seed );\n\t\t\t\t\t\treturn results;\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// Compile and execute a filtering function if one is not provided\n\t// Provide `match` to avoid retokenization if we modified the selector above\n\t( compiled || compile( selector, match ) )(\n\t\tseed,\n\t\tcontext,\n\t\t!documentIsHTML,\n\t\tresults,\n\t\t!context || rsibling.test( selector ) && testContext( context.parentNode ) || context\n\t);\n\treturn results;\n}\n\n// Initialize against the default document\nsetDocument();\n\njQuery.find = find;\n\n// These have always been private, but they used to be documented as part of\n// Sizzle so let's maintain them for now for backwards compatibility purposes.\nfind.compile = compile;\nfind.select = select;\nfind.setDocument = setDocument;\nfind.tokenize = tokenize;\n\nfunction dir( elem, dir, until ) {\n\tvar matched = [],\n\t\ttruncate = until !== undefined;\n\n\twhile ( ( elem = elem[ dir ] ) && elem.nodeType !== 9 ) {\n\t\tif ( elem.nodeType === 1 ) {\n\t\t\tif ( truncate && jQuery( elem ).is( until ) ) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tmatched.push( elem );\n\t\t}\n\t}\n\treturn matched;\n}\n\nfunction siblings( n, elem ) {\n\tvar matched = [];\n\n\tfor ( ; n; n = n.nextSibling ) {\n\t\tif ( n.nodeType === 1 && n !== elem ) {\n\t\t\tmatched.push( n );\n\t\t}\n\t}\n\n\treturn matched;\n}\n\nvar rneedsContext = jQuery.expr.match.needsContext;\n\n// rsingleTag matches a string consisting of a single HTML element with no attributes\n// and captures the element's name\nvar rsingleTag = /^<([a-z][^\\/\\0>:\\x20\\t\\r\\n\\f]*)[\\x20\\t\\r\\n\\f]*\\/?>(?:<\\/\\1>|)$/i;\n\nfunction isObviousHtml( input ) {\n\treturn input[ 0 ] === \"<\" &&\n\t\tinput[ input.length - 1 ] === \">\" &&\n\t\tinput.length >= 3;\n}\n\n// Implement the identical functionality for filter and not\nfunction winnow( elements, qualifier, not ) {\n\tif ( typeof qualifier === \"function\" ) {\n\t\treturn jQuery.grep( elements, function( elem, i ) {\n\t\t\treturn !!qualifier.call( elem, i, elem ) !== not;\n\t\t} );\n\t}\n\n\t// Single element\n\tif ( qualifier.nodeType ) {\n\t\treturn jQuery.grep( elements, function( elem ) {\n\t\t\treturn ( elem === qualifier ) !== not;\n\t\t} );\n\t}\n\n\t// Arraylike of elements (jQuery, arguments, Array)\n\tif ( typeof qualifier !== \"string\" ) {\n\t\treturn jQuery.grep( elements, function( elem ) {\n\t\t\treturn ( indexOf.call( qualifier, elem ) > -1 ) !== not;\n\t\t} );\n\t}\n\n\t// Filtered directly for both simple and complex selectors\n\treturn jQuery.filter( qualifier, elements, not );\n}\n\njQuery.filter = function( expr, elems, not ) {\n\tvar elem = elems[ 0 ];\n\n\tif ( not ) {\n\t\texpr = \":not(\" + expr + \")\";\n\t}\n\n\tif ( elems.length === 1 && elem.nodeType === 1 ) {\n\t\treturn jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : [];\n\t}\n\n\treturn jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) {\n\t\treturn elem.nodeType === 1;\n\t} ) );\n};\n\njQuery.fn.extend( {\n\tfind: function( selector ) {\n\t\tvar i, ret,\n\t\t\tlen = this.length,\n\t\t\tself = this;\n\n\t\tif ( typeof selector !== \"string\" ) {\n\t\t\treturn this.pushStack( jQuery( selector ).filter( function() {\n\t\t\t\tfor ( i = 0; i < len; i++ ) {\n\t\t\t\t\tif ( jQuery.contains( self[ i ], this ) ) {\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} ) );\n\t\t}\n\n\t\tret = this.pushStack( [] );\n\n\t\tfor ( i = 0; i < len; i++ ) {\n\t\t\tjQuery.find( selector, self[ i ], ret );\n\t\t}\n\n\t\treturn len > 1 ? jQuery.uniqueSort( ret ) : ret;\n\t},\n\tfilter: function( selector ) {\n\t\treturn this.pushStack( winnow( this, selector || [], false ) );\n\t},\n\tnot: function( selector ) {\n\t\treturn this.pushStack( winnow( this, selector || [], true ) );\n\t},\n\tis: function( selector ) {\n\t\treturn !!winnow(\n\t\t\tthis,\n\n\t\t\t// If this is a positional/relative selector, check membership in the returned set\n\t\t\t// so $(\"p:first\").is(\"p:last\") won't return true for a doc with two \"p\".\n\t\t\ttypeof selector === \"string\" && rneedsContext.test( selector ) ?\n\t\t\t\tjQuery( selector ) :\n\t\t\t\tselector || [],\n\t\t\tfalse\n\t\t).length;\n\t}\n} );\n\n// Initialize a jQuery object\n\n// A central reference to the root jQuery(document)\nvar rootjQuery,\n\n\t// A simple way to check for HTML strings\n\t// Prioritize #id over to avoid XSS via location.hash (trac-9521)\n\t// Strict HTML recognition (trac-11290: must start with <)\n\t// Shortcut simple #id case for speed\n\trquickExpr = /^(?:\\s*(<[\\w\\W]+>)[^>]*|#([\\w-]+))$/,\n\n\tinit = jQuery.fn.init = function( selector, context ) {\n\t\tvar match, elem;\n\n\t\t// HANDLE: $(\"\"), $(null), $(undefined), $(false)\n\t\tif ( !selector ) {\n\t\t\treturn this;\n\t\t}\n\n\t\t// HANDLE: $(DOMElement)\n\t\tif ( selector.nodeType ) {\n\t\t\tthis[ 0 ] = selector;\n\t\t\tthis.length = 1;\n\t\t\treturn this;\n\n\t\t// HANDLE: $(function)\n\t\t// Shortcut for document ready\n\t\t} else if ( typeof selector === \"function\" ) {\n\t\t\treturn rootjQuery.ready !== undefined ?\n\t\t\t\trootjQuery.ready( selector ) :\n\n\t\t\t\t// Execute immediately if ready is not present\n\t\t\t\tselector( jQuery );\n\n\t\t} else {\n\n\t\t\t// Handle obvious HTML strings\n\t\t\tmatch = selector + \"\";\n\t\t\tif ( isObviousHtml( match ) ) {\n\n\t\t\t\t// Assume that strings that start and end with <> are HTML and skip\n\t\t\t\t// the regex check. This also handles browser-supported HTML wrappers\n\t\t\t\t// like TrustedHTML.\n\t\t\t\tmatch = [ null, selector, null ];\n\n\t\t\t// Handle HTML strings or selectors\n\t\t\t} else if ( typeof selector === \"string\" ) {\n\t\t\t\tmatch = rquickExpr.exec( selector );\n\t\t\t} else {\n\t\t\t\treturn jQuery.makeArray( selector, this );\n\t\t\t}\n\n\t\t\t// Match html or make sure no context is specified for #id\n\t\t\t// Note: match[1] may be a string or a TrustedHTML wrapper\n\t\t\tif ( match && ( match[ 1 ] || !context ) ) {\n\n\t\t\t\t// HANDLE: $(html) -> $(array)\n\t\t\t\tif ( match[ 1 ] ) {\n\t\t\t\t\tcontext = context instanceof jQuery ? context[ 0 ] : context;\n\n\t\t\t\t\t// Option to run scripts is true for back-compat\n\t\t\t\t\t// Intentionally let the error be thrown if parseHTML is not present\n\t\t\t\t\tjQuery.merge( this, jQuery.parseHTML(\n\t\t\t\t\t\tmatch[ 1 ],\n\t\t\t\t\t\tcontext && context.nodeType ? context.ownerDocument || context : document$1,\n\t\t\t\t\t\ttrue\n\t\t\t\t\t) );\n\n\t\t\t\t\t// HANDLE: $(html, props)\n\t\t\t\t\tif ( rsingleTag.test( match[ 1 ] ) && jQuery.isPlainObject( context ) ) {\n\t\t\t\t\t\tfor ( match in context ) {\n\n\t\t\t\t\t\t\t// Properties of context are called as methods if possible\n\t\t\t\t\t\t\tif ( typeof this[ match ] === \"function\" ) {\n\t\t\t\t\t\t\t\tthis[ match ]( context[ match ] );\n\n\t\t\t\t\t\t\t// ...and otherwise set as attributes\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tthis.attr( match, context[ match ] );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\treturn this;\n\n\t\t\t\t// HANDLE: $(#id)\n\t\t\t\t} else {\n\t\t\t\t\telem = document$1.getElementById( match[ 2 ] );\n\n\t\t\t\t\tif ( elem ) {\n\n\t\t\t\t\t\t// Inject the element directly into the jQuery object\n\t\t\t\t\t\tthis[ 0 ] = elem;\n\t\t\t\t\t\tthis.length = 1;\n\t\t\t\t\t}\n\t\t\t\t\treturn this;\n\t\t\t\t}\n\n\t\t\t// HANDLE: $(expr) & $(expr, $(...))\n\t\t\t} else if ( !context || context.jquery ) {\n\t\t\t\treturn ( context || rootjQuery ).find( selector );\n\n\t\t\t// HANDLE: $(expr, context)\n\t\t\t// (which is just equivalent to: $(context).find(expr)\n\t\t\t} else {\n\t\t\t\treturn this.constructor( context ).find( selector );\n\t\t\t}\n\t\t}\n\n\t};\n\n// Give the init function the jQuery prototype for later instantiation\ninit.prototype = jQuery.fn;\n\n// Initialize central reference\nrootjQuery = jQuery( document$1 );\n\nvar rparentsprev = /^(?:parents|prev(?:Until|All))/,\n\n\t// Methods guaranteed to produce a unique set when starting from a unique set\n\tguaranteedUnique = {\n\t\tchildren: true,\n\t\tcontents: true,\n\t\tnext: true,\n\t\tprev: true\n\t};\n\njQuery.fn.extend( {\n\thas: function( target ) {\n\t\tvar targets = jQuery( target, this ),\n\t\t\tl = targets.length;\n\n\t\treturn this.filter( function() {\n\t\t\tvar i = 0;\n\t\t\tfor ( ; i < l; i++ ) {\n\t\t\t\tif ( jQuery.contains( this, targets[ i ] ) ) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\t},\n\n\tclosest: function( selectors, context ) {\n\t\tvar cur,\n\t\t\ti = 0,\n\t\t\tl = this.length,\n\t\t\tmatched = [],\n\t\t\ttargets = typeof selectors !== \"string\" && jQuery( selectors );\n\n\t\t// Positional selectors never match, since there's no _selection_ context\n\t\tif ( !rneedsContext.test( selectors ) ) {\n\t\t\tfor ( ; i < l; i++ ) {\n\t\t\t\tfor ( cur = this[ i ]; cur && cur !== context; cur = cur.parentNode ) {\n\n\t\t\t\t\t// Always skip document fragments\n\t\t\t\t\tif ( cur.nodeType < 11 && ( targets ?\n\t\t\t\t\t\ttargets.index( cur ) > -1 :\n\n\t\t\t\t\t\t// Don't pass non-elements to jQuery#find\n\t\t\t\t\t\tcur.nodeType === 1 &&\n\t\t\t\t\t\t\tjQuery.find.matchesSelector( cur, selectors ) ) ) {\n\n\t\t\t\t\t\tmatched.push( cur );\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn this.pushStack( matched.length > 1 ? jQuery.uniqueSort( matched ) : matched );\n\t},\n\n\t// Determine the position of an element within the set\n\tindex: function( elem ) {\n\n\t\t// No argument, return index in parent\n\t\tif ( !elem ) {\n\t\t\treturn ( this[ 0 ] && this[ 0 ].parentNode ) ? this.first().prevAll().length : -1;\n\t\t}\n\n\t\t// Index in selector\n\t\tif ( typeof elem === \"string\" ) {\n\t\t\treturn indexOf.call( jQuery( elem ), this[ 0 ] );\n\t\t}\n\n\t\t// Locate the position of the desired element\n\t\treturn indexOf.call( this,\n\n\t\t\t// If it receives a jQuery object, the first element is used\n\t\t\telem.jquery ? elem[ 0 ] : elem\n\t\t);\n\t},\n\n\tadd: function( selector, context ) {\n\t\treturn this.pushStack(\n\t\t\tjQuery.uniqueSort(\n\t\t\t\tjQuery.merge( this.get(), jQuery( selector, context ) )\n\t\t\t)\n\t\t);\n\t},\n\n\taddBack: function( selector ) {\n\t\treturn this.add( selector == null ?\n\t\t\tthis.prevObject : this.prevObject.filter( selector )\n\t\t);\n\t}\n} );\n\nfunction sibling( cur, dir ) {\n\twhile ( ( cur = cur[ dir ] ) && cur.nodeType !== 1 ) {}\n\treturn cur;\n}\n\njQuery.each( {\n\tparent: function( elem ) {\n\t\tvar parent = elem.parentNode;\n\t\treturn parent && parent.nodeType !== 11 ? parent : null;\n\t},\n\tparents: function( elem ) {\n\t\treturn dir( elem, \"parentNode\" );\n\t},\n\tparentsUntil: function( elem, _i, until ) {\n\t\treturn dir( elem, \"parentNode\", until );\n\t},\n\tnext: function( elem ) {\n\t\treturn sibling( elem, \"nextSibling\" );\n\t},\n\tprev: function( elem ) {\n\t\treturn sibling( elem, \"previousSibling\" );\n\t},\n\tnextAll: function( elem ) {\n\t\treturn dir( elem, \"nextSibling\" );\n\t},\n\tprevAll: function( elem ) {\n\t\treturn dir( elem, \"previousSibling\" );\n\t},\n\tnextUntil: function( elem, _i, until ) {\n\t\treturn dir( elem, \"nextSibling\", until );\n\t},\n\tprevUntil: function( elem, _i, until ) {\n\t\treturn dir( elem, \"previousSibling\", until );\n\t},\n\tsiblings: function( elem ) {\n\t\treturn siblings( ( elem.parentNode || {} ).firstChild, elem );\n\t},\n\tchildren: function( elem ) {\n\t\treturn siblings( elem.firstChild );\n\t},\n\tcontents: function( elem ) {\n\t\tif ( elem.contentDocument != null &&\n\n\t\t\t// Support: IE 11+\n\t\t\t// elements with no `data` attribute has an object\n\t\t\t// `contentDocument` with a `null` prototype.\n\t\t\tgetProto( elem.contentDocument ) ) {\n\n\t\t\treturn elem.contentDocument;\n\t\t}\n\n\t\t// Support: IE 9 - 11+\n\t\t// Treat the template element as a regular one in browsers that\n\t\t// don't support it.\n\t\tif ( nodeName( elem, \"template\" ) ) {\n\t\t\telem = elem.content || elem;\n\t\t}\n\n\t\treturn jQuery.merge( [], elem.childNodes );\n\t}\n}, function( name, fn ) {\n\tjQuery.fn[ name ] = function( until, selector ) {\n\t\tvar matched = jQuery.map( this, fn, until );\n\n\t\tif ( name.slice( -5 ) !== \"Until\" ) {\n\t\t\tselector = until;\n\t\t}\n\n\t\tif ( selector && typeof selector === \"string\" ) {\n\t\t\tmatched = jQuery.filter( selector, matched );\n\t\t}\n\n\t\tif ( this.length > 1 ) {\n\n\t\t\t// Remove duplicates\n\t\t\tif ( !guaranteedUnique[ name ] ) {\n\t\t\t\tjQuery.uniqueSort( matched );\n\t\t\t}\n\n\t\t\t// Reverse order for parents* and prev-derivatives\n\t\t\tif ( rparentsprev.test( name ) ) {\n\t\t\t\tmatched.reverse();\n\t\t\t}\n\t\t}\n\n\t\treturn this.pushStack( matched );\n\t};\n} );\n\n// Convert String-formatted options into Object-formatted ones\nfunction createOptions( options ) {\n\tvar object = {};\n\tjQuery.each( options.match( rnothtmlwhite ) || [], function( _, flag ) {\n\t\tobject[ flag ] = true;\n\t} );\n\treturn object;\n}\n\n/*\n * Create a callback list using the following parameters:\n *\n *\toptions: an optional list of space-separated options that will change how\n *\t\t\tthe callback list behaves or a more traditional option object\n *\n * By default a callback list will act like an event callback list and can be\n * \"fired\" multiple times.\n *\n * Possible options:\n *\n *\tonce:\t\t\twill ensure the callback list can only be fired once (like a Deferred)\n *\n *\tmemory:\t\t\twill keep track of previous values and will call any callback added\n *\t\t\t\t\tafter the list has been fired right away with the latest \"memorized\"\n *\t\t\t\t\tvalues (like a Deferred)\n *\n *\tunique:\t\t\twill ensure a callback can only be added once (no duplicate in the list)\n *\n *\tstopOnFalse:\tinterrupt callings when a callback returns false\n *\n */\njQuery.Callbacks = function( options ) {\n\n\t// Convert options from String-formatted to Object-formatted if needed\n\t// (we check in cache first)\n\toptions = typeof options === \"string\" ?\n\t\tcreateOptions( options ) :\n\t\tjQuery.extend( {}, options );\n\n\tvar // Flag to know if list is currently firing\n\t\tfiring,\n\n\t\t// Last fire value for non-forgettable lists\n\t\tmemory,\n\n\t\t// Flag to know if list was already fired\n\t\tfired,\n\n\t\t// Flag to prevent firing\n\t\tlocked,\n\n\t\t// Actual callback list\n\t\tlist = [],\n\n\t\t// Queue of execution data for repeatable lists\n\t\tqueue = [],\n\n\t\t// Index of currently firing callback (modified by add/remove as needed)\n\t\tfiringIndex = -1,\n\n\t\t// Fire callbacks\n\t\tfire = function() {\n\n\t\t\t// Enforce single-firing\n\t\t\tlocked = locked || options.once;\n\n\t\t\t// Execute callbacks for all pending executions,\n\t\t\t// respecting firingIndex overrides and runtime changes\n\t\t\tfired = firing = true;\n\t\t\tfor ( ; queue.length; firingIndex = -1 ) {\n\t\t\t\tmemory = queue.shift();\n\t\t\t\twhile ( ++firingIndex < list.length ) {\n\n\t\t\t\t\t// Run callback and check for early termination\n\t\t\t\t\tif ( list[ firingIndex ].apply( memory[ 0 ], memory[ 1 ] ) === false &&\n\t\t\t\t\t\toptions.stopOnFalse ) {\n\n\t\t\t\t\t\t// Jump to end and forget the data so .add doesn't re-fire\n\t\t\t\t\t\tfiringIndex = list.length;\n\t\t\t\t\t\tmemory = false;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Forget the data if we're done with it\n\t\t\tif ( !options.memory ) {\n\t\t\t\tmemory = false;\n\t\t\t}\n\n\t\t\tfiring = false;\n\n\t\t\t// Clean up if we're done firing for good\n\t\t\tif ( locked ) {\n\n\t\t\t\t// Keep an empty list if we have data for future add calls\n\t\t\t\tif ( memory ) {\n\t\t\t\t\tlist = [];\n\n\t\t\t\t// Otherwise, this object is spent\n\t\t\t\t} else {\n\t\t\t\t\tlist = \"\";\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\n\t\t// Actual Callbacks object\n\t\tself = {\n\n\t\t\t// Add a callback or a collection of callbacks to the list\n\t\t\tadd: function() {\n\t\t\t\tif ( list ) {\n\n\t\t\t\t\t// If we have memory from a past run, we should fire after adding\n\t\t\t\t\tif ( memory && !firing ) {\n\t\t\t\t\t\tfiringIndex = list.length - 1;\n\t\t\t\t\t\tqueue.push( memory );\n\t\t\t\t\t}\n\n\t\t\t\t\t( function add( args ) {\n\t\t\t\t\t\tjQuery.each( args, function( _, arg ) {\n\t\t\t\t\t\t\tif ( typeof arg === \"function\" ) {\n\t\t\t\t\t\t\t\tif ( !options.unique || !self.has( arg ) ) {\n\t\t\t\t\t\t\t\t\tlist.push( arg );\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t} else if ( arg && arg.length && toType( arg ) !== \"string\" ) {\n\n\t\t\t\t\t\t\t\t// Inspect recursively\n\t\t\t\t\t\t\t\tadd( arg );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} );\n\t\t\t\t\t} )( arguments );\n\n\t\t\t\t\tif ( memory && !firing ) {\n\t\t\t\t\t\tfire();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn this;\n\t\t\t},\n\n\t\t\t// Remove a callback from the list\n\t\t\tremove: function() {\n\t\t\t\tjQuery.each( arguments, function( _, arg ) {\n\t\t\t\t\tvar index;\n\t\t\t\t\twhile ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) {\n\t\t\t\t\t\tlist.splice( index, 1 );\n\n\t\t\t\t\t\t// Handle firing indexes\n\t\t\t\t\t\tif ( index <= firingIndex ) {\n\t\t\t\t\t\t\tfiringIndex--;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} );\n\t\t\t\treturn this;\n\t\t\t},\n\n\t\t\t// Check if a given callback is in the list.\n\t\t\t// If no argument is given, return whether or not list has callbacks attached.\n\t\t\thas: function( fn ) {\n\t\t\t\treturn fn ?\n\t\t\t\t\tjQuery.inArray( fn, list ) > -1 :\n\t\t\t\t\tlist.length > 0;\n\t\t\t},\n\n\t\t\t// Remove all callbacks from the list\n\t\t\tempty: function() {\n\t\t\t\tif ( list ) {\n\t\t\t\t\tlist = [];\n\t\t\t\t}\n\t\t\t\treturn this;\n\t\t\t},\n\n\t\t\t// Disable .fire and .add\n\t\t\t// Abort any current/pending executions\n\t\t\t// Clear all callbacks and values\n\t\t\tdisable: function() {\n\t\t\t\tlocked = queue = [];\n\t\t\t\tlist = memory = \"\";\n\t\t\t\treturn this;\n\t\t\t},\n\t\t\tdisabled: function() {\n\t\t\t\treturn !list;\n\t\t\t},\n\n\t\t\t// Disable .fire\n\t\t\t// Also disable .add unless we have memory (since it would have no effect)\n\t\t\t// Abort any pending executions\n\t\t\tlock: function() {\n\t\t\t\tlocked = queue = [];\n\t\t\t\tif ( !memory && !firing ) {\n\t\t\t\t\tlist = memory = \"\";\n\t\t\t\t}\n\t\t\t\treturn this;\n\t\t\t},\n\t\t\tlocked: function() {\n\t\t\t\treturn !!locked;\n\t\t\t},\n\n\t\t\t// Call all callbacks with the given context and arguments\n\t\t\tfireWith: function( context, args ) {\n\t\t\t\tif ( !locked ) {\n\t\t\t\t\targs = args || [];\n\t\t\t\t\targs = [ context, args.slice ? args.slice() : args ];\n\t\t\t\t\tqueue.push( args );\n\t\t\t\t\tif ( !firing ) {\n\t\t\t\t\t\tfire();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn this;\n\t\t\t},\n\n\t\t\t// Call all the callbacks with the given arguments\n\t\t\tfire: function() {\n\t\t\t\tself.fireWith( this, arguments );\n\t\t\t\treturn this;\n\t\t\t},\n\n\t\t\t// To know if the callbacks have already been called at least once\n\t\t\tfired: function() {\n\t\t\t\treturn !!fired;\n\t\t\t}\n\t\t};\n\n\treturn self;\n};\n\nfunction Identity( v ) {\n\treturn v;\n}\nfunction Thrower( ex ) {\n\tthrow ex;\n}\n\nfunction adoptValue( value, resolve, reject, noValue ) {\n\tvar method;\n\n\ttry {\n\n\t\t// Check for promise aspect first to privilege synchronous behavior\n\t\tif ( value && typeof( method = value.promise ) === \"function\" ) {\n\t\t\tmethod.call( value ).done( resolve ).fail( reject );\n\n\t\t// Other thenables\n\t\t} else if ( value && typeof( method = value.then ) === \"function\" ) {\n\t\t\tmethod.call( value, resolve, reject );\n\n\t\t// Other non-thenables\n\t\t} else {\n\n\t\t\t// Control `resolve` arguments by letting Array#slice cast boolean `noValue` to integer:\n\t\t\t// * false: [ value ].slice( 0 ) => resolve( value )\n\t\t\t// * true: [ value ].slice( 1 ) => resolve()\n\t\t\tresolve.apply( undefined, [ value ].slice( noValue ) );\n\t\t}\n\n\t// For Promises/A+, convert exceptions into rejections\n\t// Since jQuery.when doesn't unwrap thenables, we can skip the extra checks appearing in\n\t// Deferred#then to conditionally suppress rejection.\n\t} catch ( value ) {\n\t\treject( value );\n\t}\n}\n\njQuery.extend( {\n\n\tDeferred: function( func ) {\n\t\tvar tuples = [\n\n\t\t\t\t// action, add listener, callbacks,\n\t\t\t\t// ... .then handlers, argument index, [final state]\n\t\t\t\t[ \"notify\", \"progress\", jQuery.Callbacks( \"memory\" ),\n\t\t\t\t\tjQuery.Callbacks( \"memory\" ), 2 ],\n\t\t\t\t[ \"resolve\", \"done\", jQuery.Callbacks( \"once memory\" ),\n\t\t\t\t\tjQuery.Callbacks( \"once memory\" ), 0, \"resolved\" ],\n\t\t\t\t[ \"reject\", \"fail\", jQuery.Callbacks( \"once memory\" ),\n\t\t\t\t\tjQuery.Callbacks( \"once memory\" ), 1, \"rejected\" ]\n\t\t\t],\n\t\t\tstate = \"pending\",\n\t\t\tpromise = {\n\t\t\t\tstate: function() {\n\t\t\t\t\treturn state;\n\t\t\t\t},\n\t\t\t\talways: function() {\n\t\t\t\t\tdeferred.done( arguments ).fail( arguments );\n\t\t\t\t\treturn this;\n\t\t\t\t},\n\t\t\t\tcatch: function( fn ) {\n\t\t\t\t\treturn promise.then( null, fn );\n\t\t\t\t},\n\n\t\t\t\t// Keep pipe for back-compat\n\t\t\t\tpipe: function( /* fnDone, fnFail, fnProgress */ ) {\n\t\t\t\t\tvar fns = arguments;\n\n\t\t\t\t\treturn jQuery.Deferred( function( newDefer ) {\n\t\t\t\t\t\tjQuery.each( tuples, function( _i, tuple ) {\n\n\t\t\t\t\t\t\t// Map tuples (progress, done, fail) to arguments (done, fail, progress)\n\t\t\t\t\t\t\tvar fn = typeof fns[ tuple[ 4 ] ] === \"function\" &&\n\t\t\t\t\t\t\t\tfns[ tuple[ 4 ] ];\n\n\t\t\t\t\t\t\t// deferred.progress(function() { bind to newDefer or newDefer.notify })\n\t\t\t\t\t\t\t// deferred.done(function() { bind to newDefer or newDefer.resolve })\n\t\t\t\t\t\t\t// deferred.fail(function() { bind to newDefer or newDefer.reject })\n\t\t\t\t\t\t\tdeferred[ tuple[ 1 ] ]( function() {\n\t\t\t\t\t\t\t\tvar returned = fn && fn.apply( this, arguments );\n\t\t\t\t\t\t\t\tif ( returned && typeof returned.promise === \"function\" ) {\n\t\t\t\t\t\t\t\t\treturned.promise()\n\t\t\t\t\t\t\t\t\t\t.progress( newDefer.notify )\n\t\t\t\t\t\t\t\t\t\t.done( newDefer.resolve )\n\t\t\t\t\t\t\t\t\t\t.fail( newDefer.reject );\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tnewDefer[ tuple[ 0 ] + \"With\" ](\n\t\t\t\t\t\t\t\t\t\tthis,\n\t\t\t\t\t\t\t\t\t\tfn ? [ returned ] : arguments\n\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t} );\n\t\t\t\t\t\t} );\n\t\t\t\t\t\tfns = null;\n\t\t\t\t\t} ).promise();\n\t\t\t\t},\n\t\t\t\tthen: function( onFulfilled, onRejected, onProgress ) {\n\t\t\t\t\tvar maxDepth = 0;\n\t\t\t\t\tfunction resolve( depth, deferred, handler, special ) {\n\t\t\t\t\t\treturn function() {\n\t\t\t\t\t\t\tvar that = this,\n\t\t\t\t\t\t\t\targs = arguments,\n\t\t\t\t\t\t\t\tmightThrow = function() {\n\t\t\t\t\t\t\t\t\tvar returned, then;\n\n\t\t\t\t\t\t\t\t\t// Support: Promises/A+ section 2.3.3.3.3\n\t\t\t\t\t\t\t\t\t// https://promisesaplus.com/#point-59\n\t\t\t\t\t\t\t\t\t// Ignore double-resolution attempts\n\t\t\t\t\t\t\t\t\tif ( depth < maxDepth ) {\n\t\t\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\treturned = handler.apply( that, args );\n\n\t\t\t\t\t\t\t\t\t// Support: Promises/A+ section 2.3.1\n\t\t\t\t\t\t\t\t\t// https://promisesaplus.com/#point-48\n\t\t\t\t\t\t\t\t\tif ( returned === deferred.promise() ) {\n\t\t\t\t\t\t\t\t\t\tthrow new TypeError( \"Thenable self-resolution\" );\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t// Support: Promises/A+ sections 2.3.3.1, 3.5\n\t\t\t\t\t\t\t\t\t// https://promisesaplus.com/#point-54\n\t\t\t\t\t\t\t\t\t// https://promisesaplus.com/#point-75\n\t\t\t\t\t\t\t\t\t// Retrieve `then` only once\n\t\t\t\t\t\t\t\t\tthen = returned &&\n\n\t\t\t\t\t\t\t\t\t\t// Support: Promises/A+ section 2.3.4\n\t\t\t\t\t\t\t\t\t\t// https://promisesaplus.com/#point-64\n\t\t\t\t\t\t\t\t\t\t// Only check objects and functions for thenability\n\t\t\t\t\t\t\t\t\t\t( typeof returned === \"object\" ||\n\t\t\t\t\t\t\t\t\t\t\ttypeof returned === \"function\" ) &&\n\t\t\t\t\t\t\t\t\t\treturned.then;\n\n\t\t\t\t\t\t\t\t\t// Handle a returned thenable\n\t\t\t\t\t\t\t\t\tif ( typeof then === \"function\" ) {\n\n\t\t\t\t\t\t\t\t\t\t// Special processors (notify) just wait for resolution\n\t\t\t\t\t\t\t\t\t\tif ( special ) {\n\t\t\t\t\t\t\t\t\t\t\tthen.call(\n\t\t\t\t\t\t\t\t\t\t\t\treturned,\n\t\t\t\t\t\t\t\t\t\t\t\tresolve( maxDepth, deferred, Identity, special ),\n\t\t\t\t\t\t\t\t\t\t\t\tresolve( maxDepth, deferred, Thrower, special )\n\t\t\t\t\t\t\t\t\t\t\t);\n\n\t\t\t\t\t\t\t\t\t\t// Normal processors (resolve) also hook into progress\n\t\t\t\t\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t\t\t\t\t// ...and disregard older resolution values\n\t\t\t\t\t\t\t\t\t\t\tmaxDepth++;\n\n\t\t\t\t\t\t\t\t\t\t\tthen.call(\n\t\t\t\t\t\t\t\t\t\t\t\treturned,\n\t\t\t\t\t\t\t\t\t\t\t\tresolve( maxDepth, deferred, Identity, special ),\n\t\t\t\t\t\t\t\t\t\t\t\tresolve( maxDepth, deferred, Thrower, special ),\n\t\t\t\t\t\t\t\t\t\t\t\tresolve( maxDepth, deferred, Identity,\n\t\t\t\t\t\t\t\t\t\t\t\t\tdeferred.notifyWith )\n\t\t\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t// Handle all other returned values\n\t\t\t\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t\t\t\t// Only substitute handlers pass on context\n\t\t\t\t\t\t\t\t\t\t// and multiple values (non-spec behavior)\n\t\t\t\t\t\t\t\t\t\tif ( handler !== Identity ) {\n\t\t\t\t\t\t\t\t\t\t\tthat = undefined;\n\t\t\t\t\t\t\t\t\t\t\targs = [ returned ];\n\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t\t// Process the value(s)\n\t\t\t\t\t\t\t\t\t\t// Default process is resolve\n\t\t\t\t\t\t\t\t\t\t( special || deferred.resolveWith )( that, args );\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t},\n\n\t\t\t\t\t\t\t\t// Only normal processors (resolve) catch and reject exceptions\n\t\t\t\t\t\t\t\tprocess = special ?\n\t\t\t\t\t\t\t\t\tmightThrow :\n\t\t\t\t\t\t\t\t\tfunction() {\n\t\t\t\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t\t\t\tmightThrow();\n\t\t\t\t\t\t\t\t\t\t} catch ( e ) {\n\n\t\t\t\t\t\t\t\t\t\t\tif ( jQuery.Deferred.exceptionHook ) {\n\t\t\t\t\t\t\t\t\t\t\t\tjQuery.Deferred.exceptionHook( e,\n\t\t\t\t\t\t\t\t\t\t\t\t\tprocess.error );\n\t\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t\t\t// Support: Promises/A+ section 2.3.3.3.4.1\n\t\t\t\t\t\t\t\t\t\t\t// https://promisesaplus.com/#point-61\n\t\t\t\t\t\t\t\t\t\t\t// Ignore post-resolution exceptions\n\t\t\t\t\t\t\t\t\t\t\tif ( depth + 1 >= maxDepth ) {\n\n\t\t\t\t\t\t\t\t\t\t\t\t// Only substitute handlers pass on context\n\t\t\t\t\t\t\t\t\t\t\t\t// and multiple values (non-spec behavior)\n\t\t\t\t\t\t\t\t\t\t\t\tif ( handler !== Thrower ) {\n\t\t\t\t\t\t\t\t\t\t\t\t\tthat = undefined;\n\t\t\t\t\t\t\t\t\t\t\t\t\targs = [ e ];\n\t\t\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t\t\t\tdeferred.rejectWith( that, args );\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t};\n\n\t\t\t\t\t\t\t// Support: Promises/A+ section 2.3.3.3.1\n\t\t\t\t\t\t\t// https://promisesaplus.com/#point-57\n\t\t\t\t\t\t\t// Re-resolve promises immediately to dodge false rejection from\n\t\t\t\t\t\t\t// subsequent errors\n\t\t\t\t\t\t\tif ( depth ) {\n\t\t\t\t\t\t\t\tprocess();\n\t\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t\t// Call an optional hook to record the error, in case of exception\n\t\t\t\t\t\t\t\t// since it's otherwise lost when execution goes async\n\t\t\t\t\t\t\t\tif ( jQuery.Deferred.getErrorHook ) {\n\t\t\t\t\t\t\t\t\tprocess.error = jQuery.Deferred.getErrorHook();\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\twindow.setTimeout( process );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\n\t\t\t\t\treturn jQuery.Deferred( function( newDefer ) {\n\n\t\t\t\t\t\t// progress_handlers.add( ... )\n\t\t\t\t\t\ttuples[ 0 ][ 3 ].add(\n\t\t\t\t\t\t\tresolve(\n\t\t\t\t\t\t\t\t0,\n\t\t\t\t\t\t\t\tnewDefer,\n\t\t\t\t\t\t\t\ttypeof onProgress === \"function\" ?\n\t\t\t\t\t\t\t\t\tonProgress :\n\t\t\t\t\t\t\t\t\tIdentity,\n\t\t\t\t\t\t\t\tnewDefer.notifyWith\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\t// fulfilled_handlers.add( ... )\n\t\t\t\t\t\ttuples[ 1 ][ 3 ].add(\n\t\t\t\t\t\t\tresolve(\n\t\t\t\t\t\t\t\t0,\n\t\t\t\t\t\t\t\tnewDefer,\n\t\t\t\t\t\t\t\ttypeof onFulfilled === \"function\" ?\n\t\t\t\t\t\t\t\t\tonFulfilled :\n\t\t\t\t\t\t\t\t\tIdentity\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\t// rejected_handlers.add( ... )\n\t\t\t\t\t\ttuples[ 2 ][ 3 ].add(\n\t\t\t\t\t\t\tresolve(\n\t\t\t\t\t\t\t\t0,\n\t\t\t\t\t\t\t\tnewDefer,\n\t\t\t\t\t\t\t\ttypeof onRejected === \"function\" ?\n\t\t\t\t\t\t\t\t\tonRejected :\n\t\t\t\t\t\t\t\t\tThrower\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t);\n\t\t\t\t\t} ).promise();\n\t\t\t\t},\n\n\t\t\t\t// Get a promise for this deferred\n\t\t\t\t// If obj is provided, the promise aspect is added to the object\n\t\t\t\tpromise: function( obj ) {\n\t\t\t\t\treturn obj != null ? jQuery.extend( obj, promise ) : promise;\n\t\t\t\t}\n\t\t\t},\n\t\t\tdeferred = {};\n\n\t\t// Add list-specific methods\n\t\tjQuery.each( tuples, function( i, tuple ) {\n\t\t\tvar list = tuple[ 2 ],\n\t\t\t\tstateString = tuple[ 5 ];\n\n\t\t\t// promise.progress = list.add\n\t\t\t// promise.done = list.add\n\t\t\t// promise.fail = list.add\n\t\t\tpromise[ tuple[ 1 ] ] = list.add;\n\n\t\t\t// Handle state\n\t\t\tif ( stateString ) {\n\t\t\t\tlist.add(\n\t\t\t\t\tfunction() {\n\n\t\t\t\t\t\t// state = \"resolved\" (i.e., fulfilled)\n\t\t\t\t\t\t// state = \"rejected\"\n\t\t\t\t\t\tstate = stateString;\n\t\t\t\t\t},\n\n\t\t\t\t\t// rejected_callbacks.disable\n\t\t\t\t\t// fulfilled_callbacks.disable\n\t\t\t\t\ttuples[ 3 - i ][ 2 ].disable,\n\n\t\t\t\t\t// rejected_handlers.disable\n\t\t\t\t\t// fulfilled_handlers.disable\n\t\t\t\t\ttuples[ 3 - i ][ 3 ].disable,\n\n\t\t\t\t\t// progress_callbacks.lock\n\t\t\t\t\ttuples[ 0 ][ 2 ].lock,\n\n\t\t\t\t\t// progress_handlers.lock\n\t\t\t\t\ttuples[ 0 ][ 3 ].lock\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t// progress_handlers.fire\n\t\t\t// fulfilled_handlers.fire\n\t\t\t// rejected_handlers.fire\n\t\t\tlist.add( tuple[ 3 ].fire );\n\n\t\t\t// deferred.notify = function() { deferred.notifyWith(...) }\n\t\t\t// deferred.resolve = function() { deferred.resolveWith(...) }\n\t\t\t// deferred.reject = function() { deferred.rejectWith(...) }\n\t\t\tdeferred[ tuple[ 0 ] ] = function() {\n\t\t\t\tdeferred[ tuple[ 0 ] + \"With\" ]( this === deferred ? undefined : this, arguments );\n\t\t\t\treturn this;\n\t\t\t};\n\n\t\t\t// deferred.notifyWith = list.fireWith\n\t\t\t// deferred.resolveWith = list.fireWith\n\t\t\t// deferred.rejectWith = list.fireWith\n\t\t\tdeferred[ tuple[ 0 ] + \"With\" ] = list.fireWith;\n\t\t} );\n\n\t\t// Make the deferred a promise\n\t\tpromise.promise( deferred );\n\n\t\t// Call given func if any\n\t\tif ( func ) {\n\t\t\tfunc.call( deferred, deferred );\n\t\t}\n\n\t\t// All done!\n\t\treturn deferred;\n\t},\n\n\t// Deferred helper\n\twhen: function( singleValue ) {\n\t\tvar\n\n\t\t\t// count of uncompleted subordinates\n\t\t\tremaining = arguments.length,\n\n\t\t\t// count of unprocessed arguments\n\t\t\ti = remaining,\n\n\t\t\t// subordinate fulfillment data\n\t\t\tresolveContexts = Array( i ),\n\t\t\tresolveValues = slice.call( arguments ),\n\n\t\t\t// the primary Deferred\n\t\t\tprimary = jQuery.Deferred(),\n\n\t\t\t// subordinate callback factory\n\t\t\tupdateFunc = function( i ) {\n\t\t\t\treturn function( value ) {\n\t\t\t\t\tresolveContexts[ i ] = this;\n\t\t\t\t\tresolveValues[ i ] = arguments.length > 1 ? slice.call( arguments ) : value;\n\t\t\t\t\tif ( !( --remaining ) ) {\n\t\t\t\t\t\tprimary.resolveWith( resolveContexts, resolveValues );\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t};\n\n\t\t// Single- and empty arguments are adopted like Promise.resolve\n\t\tif ( remaining <= 1 ) {\n\t\t\tadoptValue( singleValue, primary.done( updateFunc( i ) ).resolve, primary.reject,\n\t\t\t\t!remaining );\n\n\t\t\t// Use .then() to unwrap secondary thenables (cf. gh-3000)\n\t\t\tif ( primary.state() === \"pending\" ||\n\t\t\t\ttypeof( resolveValues[ i ] && resolveValues[ i ].then ) === \"function\" ) {\n\n\t\t\t\treturn primary.then();\n\t\t\t}\n\t\t}\n\n\t\t// Multiple arguments are aggregated like Promise.all array elements\n\t\twhile ( i-- ) {\n\t\t\tadoptValue( resolveValues[ i ], updateFunc( i ), primary.reject );\n\t\t}\n\n\t\treturn primary.promise();\n\t}\n} );\n\n// These usually indicate a programmer mistake during development,\n// warn about them ASAP rather than swallowing them by default.\nvar rerrorNames = /^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/;\n\n// If `jQuery.Deferred.getErrorHook` is defined, `asyncError` is an error\n// captured before the async barrier to get the original error cause\n// which may otherwise be hidden.\njQuery.Deferred.exceptionHook = function( error, asyncError ) {\n\n\tif ( error && rerrorNames.test( error.name ) ) {\n\t\twindow.console.warn(\n\t\t\t\"jQuery.Deferred exception\",\n\t\t\terror,\n\t\t\tasyncError\n\t\t);\n\t}\n};\n\njQuery.readyException = function( error ) {\n\twindow.setTimeout( function() {\n\t\tthrow error;\n\t} );\n};\n\n// The deferred used on DOM ready\nvar readyList = jQuery.Deferred();\n\njQuery.fn.ready = function( fn ) {\n\n\treadyList\n\t\t.then( fn )\n\n\t\t// Wrap jQuery.readyException in a function so that the lookup\n\t\t// happens at the time of error handling instead of callback\n\t\t// registration.\n\t\t.catch( function( error ) {\n\t\t\tjQuery.readyException( error );\n\t\t} );\n\n\treturn this;\n};\n\njQuery.extend( {\n\n\t// Is the DOM ready to be used? Set to true once it occurs.\n\tisReady: false,\n\n\t// A counter to track how many items to wait for before\n\t// the ready event fires. See trac-6781\n\treadyWait: 1,\n\n\t// Handle when the DOM is ready\n\tready: function( wait ) {\n\n\t\t// Abort if there are pending holds or we're already ready\n\t\tif ( wait === true ? --jQuery.readyWait : jQuery.isReady ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Remember that the DOM is ready\n\t\tjQuery.isReady = true;\n\n\t\t// If a normal DOM Ready event fired, decrement, and wait if need be\n\t\tif ( wait !== true && --jQuery.readyWait > 0 ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// If there are functions bound, to execute\n\t\treadyList.resolveWith( document$1, [ jQuery ] );\n\t}\n} );\n\njQuery.ready.then = readyList.then;\n\n// The ready event handler and self cleanup method\nfunction completed() {\n\tdocument$1.removeEventListener( \"DOMContentLoaded\", completed );\n\twindow.removeEventListener( \"load\", completed );\n\tjQuery.ready();\n}\n\n// Catch cases where $(document).ready() is called\n// after the browser event has already occurred.\nif ( document$1.readyState !== \"loading\" ) {\n\n\t// Handle it asynchronously to allow scripts the opportunity to delay ready\n\twindow.setTimeout( jQuery.ready );\n\n} else {\n\n\t// Use the handy event callback\n\tdocument$1.addEventListener( \"DOMContentLoaded\", completed );\n\n\t// A fallback to window.onload, that will always work\n\twindow.addEventListener( \"load\", completed );\n}\n\n// Matches dashed string for camelizing\nvar rdashAlpha = /-([a-z])/g;\n\n// Used by camelCase as callback to replace()\nfunction fcamelCase( _all, letter ) {\n\treturn letter.toUpperCase();\n}\n\n// Convert dashed to camelCase\nfunction camelCase( string ) {\n\treturn string.replace( rdashAlpha, fcamelCase );\n}\n\n/**\n * Determines whether an object can have data\n */\nfunction acceptData( owner ) {\n\n\t// Accepts only:\n\t// - Node\n\t// - Node.ELEMENT_NODE\n\t// - Node.DOCUMENT_NODE\n\t// - Object\n\t// - Any\n\treturn owner.nodeType === 1 || owner.nodeType === 9 || !( +owner.nodeType );\n}\n\nfunction Data() {\n\tthis.expando = jQuery.expando + Data.uid++;\n}\n\nData.uid = 1;\n\nData.prototype = {\n\n\tcache: function( owner ) {\n\n\t\t// Check if the owner object already has a cache\n\t\tvar value = owner[ this.expando ];\n\n\t\t// If not, create one\n\t\tif ( !value ) {\n\t\t\tvalue = Object.create( null );\n\n\t\t\t// We can accept data for non-element nodes in modern browsers,\n\t\t\t// but we should not, see trac-8335.\n\t\t\t// Always return an empty object.\n\t\t\tif ( acceptData( owner ) ) {\n\n\t\t\t\t// If it is a node unlikely to be stringify-ed or looped over\n\t\t\t\t// use plain assignment\n\t\t\t\tif ( owner.nodeType ) {\n\t\t\t\t\towner[ this.expando ] = value;\n\n\t\t\t\t// Otherwise secure it in a non-enumerable property\n\t\t\t\t// configurable must be true to allow the property to be\n\t\t\t\t// deleted when data is removed\n\t\t\t\t} else {\n\t\t\t\t\tObject.defineProperty( owner, this.expando, {\n\t\t\t\t\t\tvalue: value,\n\t\t\t\t\t\tconfigurable: true\n\t\t\t\t\t} );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn value;\n\t},\n\tset: function( owner, data, value ) {\n\t\tvar prop,\n\t\t\tcache = this.cache( owner );\n\n\t\t// Handle: [ owner, key, value ] args\n\t\t// Always use camelCase key (gh-2257)\n\t\tif ( typeof data === \"string\" ) {\n\t\t\tcache[ camelCase( data ) ] = value;\n\n\t\t// Handle: [ owner, { properties } ] args\n\t\t} else {\n\n\t\t\t// Copy the properties one-by-one to the cache object\n\t\t\tfor ( prop in data ) {\n\t\t\t\tcache[ camelCase( prop ) ] = data[ prop ];\n\t\t\t}\n\t\t}\n\t\treturn value;\n\t},\n\tget: function( owner, key ) {\n\t\treturn key === undefined ?\n\t\t\tthis.cache( owner ) :\n\n\t\t\t// Always use camelCase key (gh-2257)\n\t\t\towner[ this.expando ] && owner[ this.expando ][ camelCase( key ) ];\n\t},\n\taccess: function( owner, key, value ) {\n\n\t\t// In cases where either:\n\t\t//\n\t\t// 1. No key was specified\n\t\t// 2. A string key was specified, but no value provided\n\t\t//\n\t\t// Take the \"read\" path and allow the get method to determine\n\t\t// which value to return, respectively either:\n\t\t//\n\t\t// 1. The entire cache object\n\t\t// 2. The data stored at the key\n\t\t//\n\t\tif ( key === undefined ||\n\t\t\t\t( ( key && typeof key === \"string\" ) && value === undefined ) ) {\n\n\t\t\treturn this.get( owner, key );\n\t\t}\n\n\t\t// When the key is not a string, or both a key and value\n\t\t// are specified, set or extend (existing objects) with either:\n\t\t//\n\t\t// 1. An object of properties\n\t\t// 2. A key and value\n\t\t//\n\t\tthis.set( owner, key, value );\n\n\t\t// Since the \"set\" path can have two possible entry points\n\t\t// return the expected data based on which path was taken[*]\n\t\treturn value !== undefined ? value : key;\n\t},\n\tremove: function( owner, key ) {\n\t\tvar i,\n\t\t\tcache = owner[ this.expando ];\n\n\t\tif ( cache === undefined ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( key !== undefined ) {\n\n\t\t\t// Support array or space separated string of keys\n\t\t\tif ( Array.isArray( key ) ) {\n\n\t\t\t\t// If key is an array of keys...\n\t\t\t\t// We always set camelCase keys, so remove that.\n\t\t\t\tkey = key.map( camelCase );\n\t\t\t} else {\n\t\t\t\tkey = camelCase( key );\n\n\t\t\t\t// If a key with the spaces exists, use it.\n\t\t\t\t// Otherwise, create an array by matching non-whitespace\n\t\t\t\tkey = key in cache ?\n\t\t\t\t\t[ key ] :\n\t\t\t\t\t( key.match( rnothtmlwhite ) || [] );\n\t\t\t}\n\n\t\t\ti = key.length;\n\n\t\t\twhile ( i-- ) {\n\t\t\t\tdelete cache[ key[ i ] ];\n\t\t\t}\n\t\t}\n\n\t\t// Remove the expando if there's no more data\n\t\tif ( key === undefined || jQuery.isEmptyObject( cache ) ) {\n\n\t\t\t// Support: Chrome <=35 - 45+\n\t\t\t// Webkit & Blink performance suffers when deleting properties\n\t\t\t// from DOM nodes, so set to undefined instead\n\t\t\t// https://bugs.chromium.org/p/chromium/issues/detail?id=378607 (bug restricted)\n\t\t\tif ( owner.nodeType ) {\n\t\t\t\towner[ this.expando ] = undefined;\n\t\t\t} else {\n\t\t\t\tdelete owner[ this.expando ];\n\t\t\t}\n\t\t}\n\t},\n\thasData: function( owner ) {\n\t\tvar cache = owner[ this.expando ];\n\t\treturn cache !== undefined && !jQuery.isEmptyObject( cache );\n\t}\n};\n\nvar dataPriv = new Data();\n\nvar dataUser = new Data();\n\n//\tImplementation Summary\n//\n//\t1. Enforce API surface and semantic compatibility with 1.9.x branch\n//\t2. Improve the module's maintainability by reducing the storage\n//\t\tpaths to a single mechanism.\n//\t3. Use the same single mechanism to support \"private\" and \"user\" data.\n//\t4. _Never_ expose \"private\" data to user code (TODO: Drop _data, _removeData)\n//\t5. Avoid exposing implementation details on user objects (eg. expando properties)\n//\t6. Provide a clear path for implementation upgrade to WeakMap in 2014\n\nvar rbrace = /^(?:\\{[\\w\\W]*\\}|\\[[\\w\\W]*\\])$/,\n\trmultiDash = /[A-Z]/g;\n\nfunction getData( data ) {\n\tif ( data === \"true\" ) {\n\t\treturn true;\n\t}\n\n\tif ( data === \"false\" ) {\n\t\treturn false;\n\t}\n\n\tif ( data === \"null\" ) {\n\t\treturn null;\n\t}\n\n\t// Only convert to a number if it doesn't change the string\n\tif ( data === +data + \"\" ) {\n\t\treturn +data;\n\t}\n\n\tif ( rbrace.test( data ) ) {\n\t\treturn JSON.parse( data );\n\t}\n\n\treturn data;\n}\n\nfunction dataAttr( elem, key, data ) {\n\tvar name;\n\n\t// If nothing was found internally, try to fetch any\n\t// data from the HTML5 data-* attribute\n\tif ( data === undefined && elem.nodeType === 1 ) {\n\t\tname = \"data-\" + key.replace( rmultiDash, \"-$&\" ).toLowerCase();\n\t\tdata = elem.getAttribute( name );\n\n\t\tif ( typeof data === \"string\" ) {\n\t\t\ttry {\n\t\t\t\tdata = getData( data );\n\t\t\t} catch ( e ) {}\n\n\t\t\t// Make sure we set the data so it isn't changed later\n\t\t\tdataUser.set( elem, key, data );\n\t\t} else {\n\t\t\tdata = undefined;\n\t\t}\n\t}\n\treturn data;\n}\n\njQuery.extend( {\n\thasData: function( elem ) {\n\t\treturn dataUser.hasData( elem ) || dataPriv.hasData( elem );\n\t},\n\n\tdata: function( elem, name, data ) {\n\t\treturn dataUser.access( elem, name, data );\n\t},\n\n\tremoveData: function( elem, name ) {\n\t\tdataUser.remove( elem, name );\n\t},\n\n\t// TODO: Now that all calls to _data and _removeData have been replaced\n\t// with direct calls to dataPriv methods, these can be deprecated.\n\t_data: function( elem, name, data ) {\n\t\treturn dataPriv.access( elem, name, data );\n\t},\n\n\t_removeData: function( elem, name ) {\n\t\tdataPriv.remove( elem, name );\n\t}\n} );\n\njQuery.fn.extend( {\n\tdata: function( key, value ) {\n\t\tvar i, name, data,\n\t\t\telem = this[ 0 ],\n\t\t\tattrs = elem && elem.attributes;\n\n\t\t// Gets all values\n\t\tif ( key === undefined ) {\n\t\t\tif ( this.length ) {\n\t\t\t\tdata = dataUser.get( elem );\n\n\t\t\t\tif ( elem.nodeType === 1 && !dataPriv.get( elem, \"hasDataAttrs\" ) ) {\n\t\t\t\t\ti = attrs.length;\n\t\t\t\t\twhile ( i-- ) {\n\n\t\t\t\t\t\t// Support: IE 11+\n\t\t\t\t\t\t// The attrs elements can be null (trac-14894)\n\t\t\t\t\t\tif ( attrs[ i ] ) {\n\t\t\t\t\t\t\tname = attrs[ i ].name;\n\t\t\t\t\t\t\tif ( name.indexOf( \"data-\" ) === 0 ) {\n\t\t\t\t\t\t\t\tname = camelCase( name.slice( 5 ) );\n\t\t\t\t\t\t\t\tdataAttr( elem, name, data[ name ] );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tdataPriv.set( elem, \"hasDataAttrs\", true );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn data;\n\t\t}\n\n\t\t// Sets multiple values\n\t\tif ( typeof key === \"object\" ) {\n\t\t\treturn this.each( function() {\n\t\t\t\tdataUser.set( this, key );\n\t\t\t} );\n\t\t}\n\n\t\treturn access( this, function( value ) {\n\t\t\tvar data;\n\n\t\t\t// The calling jQuery object (element matches) is not empty\n\t\t\t// (and therefore has an element appears at this[ 0 ]) and the\n\t\t\t// `value` parameter was not undefined. An empty jQuery object\n\t\t\t// will result in `undefined` for elem = this[ 0 ] which will\n\t\t\t// throw an exception if an attempt to read a data cache is made.\n\t\t\tif ( elem && value === undefined ) {\n\n\t\t\t\t// Attempt to get data from the cache\n\t\t\t\t// The key will always be camelCased in Data\n\t\t\t\tdata = dataUser.get( elem, key );\n\t\t\t\tif ( data !== undefined ) {\n\t\t\t\t\treturn data;\n\t\t\t\t}\n\n\t\t\t\t// Attempt to \"discover\" the data in\n\t\t\t\t// HTML5 custom data-* attrs\n\t\t\t\tdata = dataAttr( elem, key );\n\t\t\t\tif ( data !== undefined ) {\n\t\t\t\t\treturn data;\n\t\t\t\t}\n\n\t\t\t\t// We tried really hard, but the data doesn't exist.\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Set the data...\n\t\t\tthis.each( function() {\n\n\t\t\t\t// We always store the camelCased key\n\t\t\t\tdataUser.set( this, key, value );\n\t\t\t} );\n\t\t}, null, value, arguments.length > 1, null, true );\n\t},\n\n\tremoveData: function( key ) {\n\t\treturn this.each( function() {\n\t\t\tdataUser.remove( this, key );\n\t\t} );\n\t}\n} );\n\njQuery.extend( {\n\tqueue: function( elem, type, data ) {\n\t\tvar queue;\n\n\t\tif ( elem ) {\n\t\t\ttype = ( type || \"fx\" ) + \"queue\";\n\t\t\tqueue = dataPriv.get( elem, type );\n\n\t\t\t// Speed up dequeue by getting out quickly if this is just a lookup\n\t\t\tif ( data ) {\n\t\t\t\tif ( !queue || Array.isArray( data ) ) {\n\t\t\t\t\tqueue = dataPriv.set( elem, type, jQuery.makeArray( data ) );\n\t\t\t\t} else {\n\t\t\t\t\tqueue.push( data );\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn queue || [];\n\t\t}\n\t},\n\n\tdequeue: function( elem, type ) {\n\t\ttype = type || \"fx\";\n\n\t\tvar queue = jQuery.queue( elem, type ),\n\t\t\tstartLength = queue.length,\n\t\t\tfn = queue.shift(),\n\t\t\thooks = jQuery._queueHooks( elem, type ),\n\t\t\tnext = function() {\n\t\t\t\tjQuery.dequeue( elem, type );\n\t\t\t};\n\n\t\t// If the fx queue is dequeued, always remove the progress sentinel\n\t\tif ( fn === \"inprogress\" ) {\n\t\t\tfn = queue.shift();\n\t\t\tstartLength--;\n\t\t}\n\n\t\tif ( fn ) {\n\n\t\t\t// Add a progress sentinel to prevent the fx queue from being\n\t\t\t// automatically dequeued\n\t\t\tif ( type === \"fx\" ) {\n\t\t\t\tqueue.unshift( \"inprogress\" );\n\t\t\t}\n\n\t\t\t// Clear up the last queue stop function\n\t\t\tdelete hooks.stop;\n\t\t\tfn.call( elem, next, hooks );\n\t\t}\n\n\t\tif ( !startLength && hooks ) {\n\t\t\thooks.empty.fire();\n\t\t}\n\t},\n\n\t// Not public - generate a queueHooks object, or return the current one\n\t_queueHooks: function( elem, type ) {\n\t\tvar key = type + \"queueHooks\";\n\t\treturn dataPriv.get( elem, key ) || dataPriv.set( elem, key, {\n\t\t\tempty: jQuery.Callbacks( \"once memory\" ).add( function() {\n\t\t\t\tdataPriv.remove( elem, [ type + \"queue\", key ] );\n\t\t\t} )\n\t\t} );\n\t}\n} );\n\njQuery.fn.extend( {\n\tqueue: function( type, data ) {\n\t\tvar setter = 2;\n\n\t\tif ( typeof type !== \"string\" ) {\n\t\t\tdata = type;\n\t\t\ttype = \"fx\";\n\t\t\tsetter--;\n\t\t}\n\n\t\tif ( arguments.length < setter ) {\n\t\t\treturn jQuery.queue( this[ 0 ], type );\n\t\t}\n\n\t\treturn data === undefined ?\n\t\t\tthis :\n\t\t\tthis.each( function() {\n\t\t\t\tvar queue = jQuery.queue( this, type, data );\n\n\t\t\t\t// Ensure a hooks for this queue\n\t\t\t\tjQuery._queueHooks( this, type );\n\n\t\t\t\tif ( type === \"fx\" && queue[ 0 ] !== \"inprogress\" ) {\n\t\t\t\t\tjQuery.dequeue( this, type );\n\t\t\t\t}\n\t\t\t} );\n\t},\n\tdequeue: function( type ) {\n\t\treturn this.each( function() {\n\t\t\tjQuery.dequeue( this, type );\n\t\t} );\n\t},\n\tclearQueue: function( type ) {\n\t\treturn this.queue( type || \"fx\", [] );\n\t},\n\n\t// Get a promise resolved when queues of a certain type\n\t// are emptied (fx is the type by default)\n\tpromise: function( type, obj ) {\n\t\tvar tmp,\n\t\t\tcount = 1,\n\t\t\tdefer = jQuery.Deferred(),\n\t\t\telements = this,\n\t\t\ti = this.length,\n\t\t\tresolve = function() {\n\t\t\t\tif ( !( --count ) ) {\n\t\t\t\t\tdefer.resolveWith( elements, [ elements ] );\n\t\t\t\t}\n\t\t\t};\n\n\t\tif ( typeof type !== \"string\" ) {\n\t\t\tobj = type;\n\t\t\ttype = undefined;\n\t\t}\n\t\ttype = type || \"fx\";\n\n\t\twhile ( i-- ) {\n\t\t\ttmp = dataPriv.get( elements[ i ], type + \"queueHooks\" );\n\t\t\tif ( tmp && tmp.empty ) {\n\t\t\t\tcount++;\n\t\t\t\ttmp.empty.add( resolve );\n\t\t\t}\n\t\t}\n\t\tresolve();\n\t\treturn defer.promise( obj );\n\t}\n} );\n\nvar pnum = /[+-]?(?:\\d*\\.|)\\d+(?:[eE][+-]?\\d+|)/.source;\n\nvar rcssNum = new RegExp( \"^(?:([+-])=|)(\" + pnum + \")([a-z%]*)$\", \"i\" );\n\nvar cssExpand = [ \"Top\", \"Right\", \"Bottom\", \"Left\" ];\n\n// isHiddenWithinTree reports if an element has a non-\"none\" display style (inline and/or\n// through the CSS cascade), which is useful in deciding whether or not to make it visible.\n// It differs from the :hidden selector (jQuery.expr.pseudos.hidden) in two important ways:\n// * A hidden ancestor does not force an element to be classified as hidden.\n// * Being disconnected from the document does not force an element to be classified as hidden.\n// These differences improve the behavior of .toggle() et al. when applied to elements that are\n// detached or contained within hidden ancestors (gh-2404, gh-2863).\nfunction isHiddenWithinTree( elem, el ) {\n\n\t// isHiddenWithinTree might be called from jQuery#filter function;\n\t// in that case, element will be second argument\n\telem = el || elem;\n\n\t// Inline style trumps all\n\treturn elem.style.display === \"none\" ||\n\t\telem.style.display === \"\" &&\n\t\tjQuery.css( elem, \"display\" ) === \"none\";\n}\n\nvar ralphaStart = /^[a-z]/,\n\n\t// The regex visualized:\n\t//\n\t// /----------\\\n\t// | | /-------\\\n\t// | / Top \\ | | |\n\t// /--- Border ---+-| Right |-+---+- Width -+---\\\n\t// | | Bottom | |\n\t// | \\ Left / |\n\t// | |\n\t// | /----------\\ |\n\t// | /-------------\\ | | |- END\n\t// | | | | / Top \\ | |\n\t// | | / Margin \\ | | | Right | | |\n\t// |---------+-| |-+---+-| Bottom |-+----|\n\t// | \\ Padding / \\ Left / |\n\t// BEGIN -| |\n\t// | /---------\\ |\n\t// | | | |\n\t// | | / Min \\ | / Width \\ |\n\t// \\--------------+-| |-+---| |---/\n\t// \\ Max / \\ Height /\n\trautoPx = /^(?:Border(?:Top|Right|Bottom|Left)?(?:Width|)|(?:Margin|Padding)?(?:Top|Right|Bottom|Left)?|(?:Min|Max)?(?:Width|Height))$/;\n\nfunction isAutoPx( prop ) {\n\n\t// The first test is used to ensure that:\n\t// 1. The prop starts with a lowercase letter (as we uppercase it for the second regex).\n\t// 2. The prop is not empty.\n\treturn ralphaStart.test( prop ) &&\n\t\trautoPx.test( prop[ 0 ].toUpperCase() + prop.slice( 1 ) );\n}\n\nfunction adjustCSS( elem, prop, valueParts, tween ) {\n\tvar adjusted, scale,\n\t\tmaxIterations = 20,\n\t\tcurrentValue = tween ?\n\t\t\tfunction() {\n\t\t\t\treturn tween.cur();\n\t\t\t} :\n\t\t\tfunction() {\n\t\t\t\treturn jQuery.css( elem, prop, \"\" );\n\t\t\t},\n\t\tinitial = currentValue(),\n\t\tunit = valueParts && valueParts[ 3 ] || ( isAutoPx( prop ) ? \"px\" : \"\" ),\n\n\t\t// Starting value computation is required for potential unit mismatches\n\t\tinitialInUnit = elem.nodeType &&\n\t\t\t( !isAutoPx( prop ) || unit !== \"px\" && +initial ) &&\n\t\t\trcssNum.exec( jQuery.css( elem, prop ) );\n\n\tif ( initialInUnit && initialInUnit[ 3 ] !== unit ) {\n\n\t\t// Support: Firefox <=54 - 66+\n\t\t// Halve the iteration target value to prevent interference from CSS upper bounds (gh-2144)\n\t\tinitial = initial / 2;\n\n\t\t// Trust units reported by jQuery.css\n\t\tunit = unit || initialInUnit[ 3 ];\n\n\t\t// Iteratively approximate from a nonzero starting point\n\t\tinitialInUnit = +initial || 1;\n\n\t\twhile ( maxIterations-- ) {\n\n\t\t\t// Evaluate and update our best guess (doubling guesses that zero out).\n\t\t\t// Finish if the scale equals or crosses 1 (making the old*new product non-positive).\n\t\t\tjQuery.style( elem, prop, initialInUnit + unit );\n\t\t\tif ( ( 1 - scale ) * ( 1 - ( scale = currentValue() / initial || 0.5 ) ) <= 0 ) {\n\t\t\t\tmaxIterations = 0;\n\t\t\t}\n\t\t\tinitialInUnit = initialInUnit / scale;\n\n\t\t}\n\n\t\tinitialInUnit = initialInUnit * 2;\n\t\tjQuery.style( elem, prop, initialInUnit + unit );\n\n\t\t// Make sure we update the tween properties later on\n\t\tvalueParts = valueParts || [];\n\t}\n\n\tif ( valueParts ) {\n\t\tinitialInUnit = +initialInUnit || +initial || 0;\n\n\t\t// Apply relative offset (+=/-=) if specified\n\t\tadjusted = valueParts[ 1 ] ?\n\t\t\tinitialInUnit + ( valueParts[ 1 ] + 1 ) * valueParts[ 2 ] :\n\t\t\t+valueParts[ 2 ];\n\t\tif ( tween ) {\n\t\t\ttween.unit = unit;\n\t\t\ttween.start = initialInUnit;\n\t\t\ttween.end = adjusted;\n\t\t}\n\t}\n\treturn adjusted;\n}\n\n// Matches dashed string for camelizing\nvar rmsPrefix = /^-ms-/;\n\n// Convert dashed to camelCase, handle vendor prefixes.\n// Used by the css & effects modules.\n// Support: IE <=9 - 11+\n// Microsoft forgot to hump their vendor prefix (trac-9572)\nfunction cssCamelCase( string ) {\n\treturn camelCase( string.replace( rmsPrefix, \"ms-\" ) );\n}\n\nvar defaultDisplayMap = {};\n\nfunction getDefaultDisplay( elem ) {\n\tvar temp,\n\t\tdoc = elem.ownerDocument,\n\t\tnodeName = elem.nodeName,\n\t\tdisplay = defaultDisplayMap[ nodeName ];\n\n\tif ( display ) {\n\t\treturn display;\n\t}\n\n\ttemp = doc.body.appendChild( doc.createElement( nodeName ) );\n\tdisplay = jQuery.css( temp, \"display\" );\n\n\ttemp.parentNode.removeChild( temp );\n\n\tif ( display === \"none\" ) {\n\t\tdisplay = \"block\";\n\t}\n\tdefaultDisplayMap[ nodeName ] = display;\n\n\treturn display;\n}\n\nfunction showHide( elements, show ) {\n\tvar display, elem,\n\t\tvalues = [],\n\t\tindex = 0,\n\t\tlength = elements.length;\n\n\t// Determine new display value for elements that need to change\n\tfor ( ; index < length; index++ ) {\n\t\telem = elements[ index ];\n\t\tif ( !elem.style ) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tdisplay = elem.style.display;\n\t\tif ( show ) {\n\n\t\t\t// Since we force visibility upon cascade-hidden elements, an immediate (and slow)\n\t\t\t// check is required in this first loop unless we have a nonempty display value (either\n\t\t\t// inline or about-to-be-restored)\n\t\t\tif ( display === \"none\" ) {\n\t\t\t\tvalues[ index ] = dataPriv.get( elem, \"display\" ) || null;\n\t\t\t\tif ( !values[ index ] ) {\n\t\t\t\t\telem.style.display = \"\";\n\t\t\t\t}\n\t\t\t}\n\t\t\tif ( elem.style.display === \"\" && isHiddenWithinTree( elem ) ) {\n\t\t\t\tvalues[ index ] = getDefaultDisplay( elem );\n\t\t\t}\n\t\t} else {\n\t\t\tif ( display !== \"none\" ) {\n\t\t\t\tvalues[ index ] = \"none\";\n\n\t\t\t\t// Remember what we're overwriting\n\t\t\t\tdataPriv.set( elem, \"display\", display );\n\t\t\t}\n\t\t}\n\t}\n\n\t// Set the display of the elements in a second loop to avoid constant reflow\n\tfor ( index = 0; index < length; index++ ) {\n\t\tif ( values[ index ] != null ) {\n\t\t\telements[ index ].style.display = values[ index ];\n\t\t}\n\t}\n\n\treturn elements;\n}\n\njQuery.fn.extend( {\n\tshow: function() {\n\t\treturn showHide( this, true );\n\t},\n\thide: function() {\n\t\treturn showHide( this );\n\t},\n\ttoggle: function( state ) {\n\t\tif ( typeof state === \"boolean\" ) {\n\t\t\treturn state ? this.show() : this.hide();\n\t\t}\n\n\t\treturn this.each( function() {\n\t\t\tif ( isHiddenWithinTree( this ) ) {\n\t\t\t\tjQuery( this ).show();\n\t\t\t} else {\n\t\t\t\tjQuery( this ).hide();\n\t\t\t}\n\t\t} );\n\t}\n} );\n\nvar isAttached = function( elem ) {\n\t\treturn jQuery.contains( elem.ownerDocument, elem ) ||\n\t\t\telem.getRootNode( composed ) === elem.ownerDocument;\n\t},\n\tcomposed = { composed: true };\n\n// Support: IE 9 - 11+\n// Check attachment across shadow DOM boundaries when possible (gh-3504).\n// Provide a fallback for browsers without Shadow DOM v1 support.\nif ( !documentElement$1.getRootNode ) {\n\tisAttached = function( elem ) {\n\t\treturn jQuery.contains( elem.ownerDocument, elem );\n\t};\n}\n\n// rtagName captures the name from the first start tag in a string of HTML\n// https://html.spec.whatwg.org/multipage/syntax.html#tag-open-state\n// https://html.spec.whatwg.org/multipage/syntax.html#tag-name-state\nvar rtagName = /<([a-z][^\\/\\0>\\x20\\t\\r\\n\\f]*)/i;\n\nvar wrapMap = {\n\n\t// Table parts need to be wrapped with `` or they're\n\t// stripped to their contents when put in a div.\n\t// XHTML parsers do not magically insert elements in the\n\t// same way that tag soup parsers do, so we cannot shorten\n\t// this by omitting or other required elements.\n\tthead: [ \"table\" ],\n\tcol: [ \"colgroup\", \"table\" ],\n\ttr: [ \"tbody\", \"table\" ],\n\ttd: [ \"tr\", \"tbody\", \"table\" ]\n};\n\nwrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;\nwrapMap.th = wrapMap.td;\n\nfunction getAll( context, tag ) {\n\n\t// Support: IE <=9 - 11+\n\t// Use typeof to avoid zero-argument method invocation on host objects (trac-15151)\n\tvar ret;\n\n\tif ( typeof context.getElementsByTagName !== \"undefined\" ) {\n\n\t\t// Use slice to snapshot the live collection from gEBTN\n\t\tret = arr.slice.call( context.getElementsByTagName( tag || \"*\" ) );\n\n\t} else if ( typeof context.querySelectorAll !== \"undefined\" ) {\n\t\tret = context.querySelectorAll( tag || \"*\" );\n\n\t} else {\n\t\tret = [];\n\t}\n\n\tif ( tag === undefined || tag && nodeName( context, tag ) ) {\n\t\treturn jQuery.merge( [ context ], ret );\n\t}\n\n\treturn ret;\n}\n\nvar rscriptType = /^$|^module$|\\/(?:java|ecma)script/i;\n\n// Mark scripts as having already been evaluated\nfunction setGlobalEval( elems, refElements ) {\n\tvar i = 0,\n\t\tl = elems.length;\n\n\tfor ( ; i < l; i++ ) {\n\t\tdataPriv.set(\n\t\t\telems[ i ],\n\t\t\t\"globalEval\",\n\t\t\t!refElements || dataPriv.get( refElements[ i ], \"globalEval\" )\n\t\t);\n\t}\n}\n\nvar rhtml = /<|&#?\\w+;/;\n\nfunction buildFragment( elems, context, scripts, selection, ignored ) {\n\tvar elem, tmp, tag, wrap, attached, j,\n\t\tfragment = context.createDocumentFragment(),\n\t\tnodes = [],\n\t\ti = 0,\n\t\tl = elems.length;\n\n\tfor ( ; i < l; i++ ) {\n\t\telem = elems[ i ];\n\n\t\tif ( elem || elem === 0 ) {\n\n\t\t\t// Add nodes directly\n\t\t\tif ( toType( elem ) === \"object\" && ( elem.nodeType || isArrayLike( elem ) ) ) {\n\t\t\t\tjQuery.merge( nodes, elem.nodeType ? [ elem ] : elem );\n\n\t\t\t// Convert non-html into a text node\n\t\t\t} else if ( !rhtml.test( elem ) ) {\n\t\t\t\tnodes.push( context.createTextNode( elem ) );\n\n\t\t\t// Convert html into DOM nodes\n\t\t\t} else {\n\t\t\t\ttmp = tmp || fragment.appendChild( context.createElement( \"div\" ) );\n\n\t\t\t\t// Deserialize a standard representation\n\t\t\t\ttag = ( rtagName.exec( elem ) || [ \"\", \"\" ] )[ 1 ].toLowerCase();\n\t\t\t\twrap = wrapMap[ tag ] || arr;\n\n\t\t\t\t// Create wrappers & descend into them.\n\t\t\t\tj = wrap.length;\n\t\t\t\twhile ( --j > -1 ) {\n\t\t\t\t\ttmp = tmp.appendChild( context.createElement( wrap[ j ] ) );\n\t\t\t\t}\n\n\t\t\t\ttmp.innerHTML = jQuery.htmlPrefilter( elem );\n\n\t\t\t\tjQuery.merge( nodes, tmp.childNodes );\n\n\t\t\t\t// Remember the top-level container\n\t\t\t\ttmp = fragment.firstChild;\n\n\t\t\t\t// Ensure the created nodes are orphaned (trac-12392)\n\t\t\t\ttmp.textContent = \"\";\n\t\t\t}\n\t\t}\n\t}\n\n\t// Remove wrapper from fragment\n\tfragment.textContent = \"\";\n\n\ti = 0;\n\twhile ( ( elem = nodes[ i++ ] ) ) {\n\n\t\t// Skip elements already in the context collection (trac-4087)\n\t\tif ( selection && jQuery.inArray( elem, selection ) > -1 ) {\n\t\t\tif ( ignored ) {\n\t\t\t\tignored.push( elem );\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\n\t\tattached = isAttached( elem );\n\n\t\t// Append to fragment\n\t\ttmp = getAll( fragment.appendChild( elem ), \"script\" );\n\n\t\t// Preserve script evaluation history\n\t\tif ( attached ) {\n\t\t\tsetGlobalEval( tmp );\n\t\t}\n\n\t\t// Capture executables\n\t\tif ( scripts ) {\n\t\t\tj = 0;\n\t\t\twhile ( ( elem = tmp[ j++ ] ) ) {\n\t\t\t\tif ( rscriptType.test( elem.type || \"\" ) ) {\n\t\t\t\t\tscripts.push( elem );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn fragment;\n}\n\n// Replace/restore the type attribute of script elements for safe DOM manipulation\nfunction disableScript( elem ) {\n\telem.type = ( elem.getAttribute( \"type\" ) !== null ) + \"/\" + elem.type;\n\treturn elem;\n}\nfunction restoreScript( elem ) {\n\tif ( ( elem.type || \"\" ).slice( 0, 5 ) === \"true/\" ) {\n\t\telem.type = elem.type.slice( 5 );\n\t} else {\n\t\telem.removeAttribute( \"type\" );\n\t}\n\n\treturn elem;\n}\n\nfunction domManip( collection, args, callback, ignored ) {\n\n\t// Flatten any nested arrays\n\targs = flat( args );\n\n\tvar fragment, first, scripts, hasScripts, node, doc,\n\t\ti = 0,\n\t\tl = collection.length,\n\t\tiNoClone = l - 1,\n\t\tvalue = args[ 0 ],\n\t\tvalueIsFunction = typeof value === \"function\";\n\n\tif ( valueIsFunction ) {\n\t\treturn collection.each( function( index ) {\n\t\t\tvar self = collection.eq( index );\n\t\t\targs[ 0 ] = value.call( this, index, self.html() );\n\t\t\tdomManip( self, args, callback, ignored );\n\t\t} );\n\t}\n\n\tif ( l ) {\n\t\tfragment = buildFragment( args, collection[ 0 ].ownerDocument, false, collection, ignored );\n\t\tfirst = fragment.firstChild;\n\n\t\tif ( fragment.childNodes.length === 1 ) {\n\t\t\tfragment = first;\n\t\t}\n\n\t\t// Require either new content or an interest in ignored elements to invoke the callback\n\t\tif ( first || ignored ) {\n\t\t\tscripts = jQuery.map( getAll( fragment, \"script\" ), disableScript );\n\t\t\thasScripts = scripts.length;\n\n\t\t\t// Use the original fragment for the last item\n\t\t\t// instead of the first because it can end up\n\t\t\t// being emptied incorrectly in certain situations (trac-8070).\n\t\t\tfor ( ; i < l; i++ ) {\n\t\t\t\tnode = fragment;\n\n\t\t\t\tif ( i !== iNoClone ) {\n\t\t\t\t\tnode = jQuery.clone( node, true, true );\n\n\t\t\t\t\t// Keep references to cloned scripts for later restoration\n\t\t\t\t\tif ( hasScripts ) {\n\t\t\t\t\t\tjQuery.merge( scripts, getAll( node, \"script\" ) );\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tcallback.call( collection[ i ], node, i );\n\t\t\t}\n\n\t\t\tif ( hasScripts ) {\n\t\t\t\tdoc = scripts[ scripts.length - 1 ].ownerDocument;\n\n\t\t\t\t// Re-enable scripts\n\t\t\t\tjQuery.map( scripts, restoreScript );\n\n\t\t\t\t// Evaluate executable scripts on first document insertion\n\t\t\t\tfor ( i = 0; i < hasScripts; i++ ) {\n\t\t\t\t\tnode = scripts[ i ];\n\t\t\t\t\tif ( rscriptType.test( node.type || \"\" ) &&\n\t\t\t\t\t\t!dataPriv.get( node, \"globalEval\" ) &&\n\t\t\t\t\t\tjQuery.contains( doc, node ) ) {\n\n\t\t\t\t\t\tif ( node.src && ( node.type || \"\" ).toLowerCase() !== \"module\" ) {\n\n\t\t\t\t\t\t\t// Optional AJAX dependency, but won't run scripts if not present\n\t\t\t\t\t\t\tif ( jQuery._evalUrl && !node.noModule ) {\n\t\t\t\t\t\t\t\tjQuery._evalUrl( node.src, {\n\t\t\t\t\t\t\t\t\tnonce: node.nonce,\n\t\t\t\t\t\t\t\t\tcrossOrigin: node.crossOrigin\n\t\t\t\t\t\t\t\t}, doc );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tDOMEval( node.textContent, node, doc );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn collection;\n}\n\nvar rcheckableType = /^(?:checkbox|radio)$/i;\n\nvar rtypenamespace = /^([^.]*)(?:\\.(.+)|)/;\n\nfunction returnTrue() {\n\treturn true;\n}\n\nfunction returnFalse() {\n\treturn false;\n}\n\nfunction on( elem, types, selector, data, fn, one ) {\n\tvar origFn, type;\n\n\t// Types can be a map of types/handlers\n\tif ( typeof types === \"object\" ) {\n\n\t\t// ( types-Object, selector, data )\n\t\tif ( typeof selector !== \"string\" ) {\n\n\t\t\t// ( types-Object, data )\n\t\t\tdata = data || selector;\n\t\t\tselector = undefined;\n\t\t}\n\t\tfor ( type in types ) {\n\t\t\ton( elem, type, selector, data, types[ type ], one );\n\t\t}\n\t\treturn elem;\n\t}\n\n\tif ( data == null && fn == null ) {\n\n\t\t// ( types, fn )\n\t\tfn = selector;\n\t\tdata = selector = undefined;\n\t} else if ( fn == null ) {\n\t\tif ( typeof selector === \"string\" ) {\n\n\t\t\t// ( types, selector, fn )\n\t\t\tfn = data;\n\t\t\tdata = undefined;\n\t\t} else {\n\n\t\t\t// ( types, data, fn )\n\t\t\tfn = data;\n\t\t\tdata = selector;\n\t\t\tselector = undefined;\n\t\t}\n\t}\n\tif ( fn === false ) {\n\t\tfn = returnFalse;\n\t} else if ( !fn ) {\n\t\treturn elem;\n\t}\n\n\tif ( one === 1 ) {\n\t\torigFn = fn;\n\t\tfn = function( event ) {\n\n\t\t\t// Can use an empty set, since event contains the info\n\t\t\tjQuery().off( event );\n\t\t\treturn origFn.apply( this, arguments );\n\t\t};\n\n\t\t// Use same guid so caller can remove using origFn\n\t\tfn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ );\n\t}\n\treturn elem.each( function() {\n\t\tjQuery.event.add( this, types, fn, data, selector );\n\t} );\n}\n\n/*\n * Helper functions for managing events -- not part of the public interface.\n * Props to Dean Edwards' addEvent library for many of the ideas.\n */\njQuery.event = {\n\n\tadd: function( elem, types, handler, data, selector ) {\n\n\t\tvar handleObjIn, eventHandle, tmp,\n\t\t\tevents, t, handleObj,\n\t\t\tspecial, handlers, type, namespaces, origType,\n\t\t\telemData = dataPriv.get( elem );\n\n\t\t// Only attach events to objects that accept data\n\t\tif ( !acceptData( elem ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Caller can pass in an object of custom data in lieu of the handler\n\t\tif ( handler.handler ) {\n\t\t\thandleObjIn = handler;\n\t\t\thandler = handleObjIn.handler;\n\t\t\tselector = handleObjIn.selector;\n\t\t}\n\n\t\t// Ensure that invalid selectors throw exceptions at attach time\n\t\t// Evaluate against documentElement in case elem is a non-element node (e.g., document)\n\t\tif ( selector ) {\n\t\t\tjQuery.find.matchesSelector( documentElement$1, selector );\n\t\t}\n\n\t\t// Make sure that the handler has a unique ID, used to find/remove it later\n\t\tif ( !handler.guid ) {\n\t\t\thandler.guid = jQuery.guid++;\n\t\t}\n\n\t\t// Init the element's event structure and main handler, if this is the first\n\t\tif ( !( events = elemData.events ) ) {\n\t\t\tevents = elemData.events = Object.create( null );\n\t\t}\n\t\tif ( !( eventHandle = elemData.handle ) ) {\n\t\t\teventHandle = elemData.handle = function( e ) {\n\n\t\t\t\t// Discard the second event of a jQuery.event.trigger() and\n\t\t\t\t// when an event is called after a page has unloaded\n\t\t\t\treturn typeof jQuery !== \"undefined\" && jQuery.event.triggered !== e.type ?\n\t\t\t\t\tjQuery.event.dispatch.apply( elem, arguments ) : undefined;\n\t\t\t};\n\t\t}\n\n\t\t// Handle multiple events separated by a space\n\t\ttypes = ( types || \"\" ).match( rnothtmlwhite ) || [ \"\" ];\n\t\tt = types.length;\n\t\twhile ( t-- ) {\n\t\t\ttmp = rtypenamespace.exec( types[ t ] ) || [];\n\t\t\ttype = origType = tmp[ 1 ];\n\t\t\tnamespaces = ( tmp[ 2 ] || \"\" ).split( \".\" ).sort();\n\n\t\t\t// There *must* be a type, no attaching namespace-only handlers\n\t\t\tif ( !type ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// If event changes its type, use the special event handlers for the changed type\n\t\t\tspecial = jQuery.event.special[ type ] || {};\n\n\t\t\t// If selector defined, determine special event api type, otherwise given type\n\t\t\ttype = ( selector ? special.delegateType : special.bindType ) || type;\n\n\t\t\t// Update special based on newly reset type\n\t\t\tspecial = jQuery.event.special[ type ] || {};\n\n\t\t\t// handleObj is passed to all event handlers\n\t\t\thandleObj = jQuery.extend( {\n\t\t\t\ttype: type,\n\t\t\t\torigType: origType,\n\t\t\t\tdata: data,\n\t\t\t\thandler: handler,\n\t\t\t\tguid: handler.guid,\n\t\t\t\tselector: selector,\n\t\t\t\tneedsContext: selector && jQuery.expr.match.needsContext.test( selector ),\n\t\t\t\tnamespace: namespaces.join( \".\" )\n\t\t\t}, handleObjIn );\n\n\t\t\t// Init the event handler queue if we're the first\n\t\t\tif ( !( handlers = events[ type ] ) ) {\n\t\t\t\thandlers = events[ type ] = [];\n\t\t\t\thandlers.delegateCount = 0;\n\n\t\t\t\t// Only use addEventListener if the special events handler returns false\n\t\t\t\tif ( !special.setup ||\n\t\t\t\t\tspecial.setup.call( elem, data, namespaces, eventHandle ) === false ) {\n\n\t\t\t\t\tif ( elem.addEventListener ) {\n\t\t\t\t\t\telem.addEventListener( type, eventHandle );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif ( special.add ) {\n\t\t\t\tspecial.add.call( elem, handleObj );\n\n\t\t\t\tif ( !handleObj.handler.guid ) {\n\t\t\t\t\thandleObj.handler.guid = handler.guid;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Add to the element's handler list, delegates in front\n\t\t\tif ( selector ) {\n\t\t\t\thandlers.splice( handlers.delegateCount++, 0, handleObj );\n\t\t\t} else {\n\t\t\t\thandlers.push( handleObj );\n\t\t\t}\n\t\t}\n\n\t},\n\n\t// Detach an event or set of events from an element\n\tremove: function( elem, types, handler, selector, mappedTypes ) {\n\n\t\tvar j, origCount, tmp,\n\t\t\tevents, t, handleObj,\n\t\t\tspecial, handlers, type, namespaces, origType,\n\t\t\telemData = dataPriv.hasData( elem ) && dataPriv.get( elem );\n\n\t\tif ( !elemData || !( events = elemData.events ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Once for each type.namespace in types; type may be omitted\n\t\ttypes = ( types || \"\" ).match( rnothtmlwhite ) || [ \"\" ];\n\t\tt = types.length;\n\t\twhile ( t-- ) {\n\t\t\ttmp = rtypenamespace.exec( types[ t ] ) || [];\n\t\t\ttype = origType = tmp[ 1 ];\n\t\t\tnamespaces = ( tmp[ 2 ] || \"\" ).split( \".\" ).sort();\n\n\t\t\t// Unbind all events (on this namespace, if provided) for the element\n\t\t\tif ( !type ) {\n\t\t\t\tfor ( type in events ) {\n\t\t\t\t\tjQuery.event.remove( elem, type + types[ t ], handler, selector, true );\n\t\t\t\t}\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tspecial = jQuery.event.special[ type ] || {};\n\t\t\ttype = ( selector ? special.delegateType : special.bindType ) || type;\n\t\t\thandlers = events[ type ] || [];\n\t\t\ttmp = tmp[ 2 ] &&\n\t\t\t\tnew RegExp( \"(^|\\\\.)\" + namespaces.join( \"\\\\.(?:.*\\\\.|)\" ) + \"(\\\\.|$)\" );\n\n\t\t\t// Remove matching events\n\t\t\torigCount = j = handlers.length;\n\t\t\twhile ( j-- ) {\n\t\t\t\thandleObj = handlers[ j ];\n\n\t\t\t\tif ( ( mappedTypes || origType === handleObj.origType ) &&\n\t\t\t\t\t( !handler || handler.guid === handleObj.guid ) &&\n\t\t\t\t\t( !tmp || tmp.test( handleObj.namespace ) ) &&\n\t\t\t\t\t( !selector || selector === handleObj.selector ||\n\t\t\t\t\t\tselector === \"**\" && handleObj.selector ) ) {\n\t\t\t\t\thandlers.splice( j, 1 );\n\n\t\t\t\t\tif ( handleObj.selector ) {\n\t\t\t\t\t\thandlers.delegateCount--;\n\t\t\t\t\t}\n\t\t\t\t\tif ( special.remove ) {\n\t\t\t\t\t\tspecial.remove.call( elem, handleObj );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Remove generic event handler if we removed something and no more handlers exist\n\t\t\t// (avoids potential for endless recursion during removal of special event handlers)\n\t\t\tif ( origCount && !handlers.length ) {\n\t\t\t\tif ( !special.teardown ||\n\t\t\t\t\tspecial.teardown.call( elem, namespaces, elemData.handle ) === false ) {\n\n\t\t\t\t\tjQuery.removeEvent( elem, type, elemData.handle );\n\t\t\t\t}\n\n\t\t\t\tdelete events[ type ];\n\t\t\t}\n\t\t}\n\n\t\t// Remove data and the expando if it's no longer used\n\t\tif ( jQuery.isEmptyObject( events ) ) {\n\t\t\tdataPriv.remove( elem, \"handle events\" );\n\t\t}\n\t},\n\n\tdispatch: function( nativeEvent ) {\n\n\t\tvar i, j, ret, matched, handleObj, handlerQueue,\n\t\t\targs = new Array( arguments.length ),\n\n\t\t\t// Make a writable jQuery.Event from the native event object\n\t\t\tevent = jQuery.event.fix( nativeEvent ),\n\n\t\t\thandlers = (\n\t\t\t\tdataPriv.get( this, \"events\" ) || Object.create( null )\n\t\t\t)[ event.type ] || [],\n\t\t\tspecial = jQuery.event.special[ event.type ] || {};\n\n\t\t// Use the fix-ed jQuery.Event rather than the (read-only) native event\n\t\targs[ 0 ] = event;\n\n\t\tfor ( i = 1; i < arguments.length; i++ ) {\n\t\t\targs[ i ] = arguments[ i ];\n\t\t}\n\n\t\tevent.delegateTarget = this;\n\n\t\t// Call the preDispatch hook for the mapped type, and let it bail if desired\n\t\tif ( special.preDispatch && special.preDispatch.call( this, event ) === false ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Determine handlers\n\t\thandlerQueue = jQuery.event.handlers.call( this, event, handlers );\n\n\t\t// Run delegates first; they may want to stop propagation beneath us\n\t\ti = 0;\n\t\twhile ( ( matched = handlerQueue[ i++ ] ) && !event.isPropagationStopped() ) {\n\t\t\tevent.currentTarget = matched.elem;\n\n\t\t\tj = 0;\n\t\t\twhile ( ( handleObj = matched.handlers[ j++ ] ) &&\n\t\t\t\t!event.isImmediatePropagationStopped() ) {\n\n\t\t\t\t// If the event is namespaced, then each handler is only invoked if it is\n\t\t\t\t// specially universal or its namespaces are a superset of the event's.\n\t\t\t\tif ( !event.rnamespace || handleObj.namespace === false ||\n\t\t\t\t\tevent.rnamespace.test( handleObj.namespace ) ) {\n\n\t\t\t\t\tevent.handleObj = handleObj;\n\t\t\t\t\tevent.data = handleObj.data;\n\n\t\t\t\t\tret = ( ( jQuery.event.special[ handleObj.origType ] || {} ).handle ||\n\t\t\t\t\t\thandleObj.handler ).apply( matched.elem, args );\n\n\t\t\t\t\tif ( ret !== undefined ) {\n\t\t\t\t\t\tif ( ( event.result = ret ) === false ) {\n\t\t\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\t\t\tevent.stopPropagation();\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Call the postDispatch hook for the mapped type\n\t\tif ( special.postDispatch ) {\n\t\t\tspecial.postDispatch.call( this, event );\n\t\t}\n\n\t\treturn event.result;\n\t},\n\n\thandlers: function( event, handlers ) {\n\t\tvar i, handleObj, sel, matchedHandlers, matchedSelectors,\n\t\t\thandlerQueue = [],\n\t\t\tdelegateCount = handlers.delegateCount,\n\t\t\tcur = event.target;\n\n\t\t// Find delegate handlers\n\t\tif ( delegateCount &&\n\n\t\t\t// Support: Firefox <=42 - 66+\n\t\t\t// Suppress spec-violating clicks indicating a non-primary pointer button (trac-3861)\n\t\t\t// https://www.w3.org/TR/DOM-Level-3-Events/#event-type-click\n\t\t\t// Support: IE 11+\n\t\t\t// ...but not arrow key \"clicks\" of radio inputs, which can have `button` -1 (gh-2343)\n\t\t\t!( event.type === \"click\" && event.button >= 1 ) ) {\n\n\t\t\tfor ( ; cur !== this; cur = cur.parentNode || this ) {\n\n\t\t\t\t// Don't check non-elements (trac-13208)\n\t\t\t\t// Don't process clicks on disabled elements (trac-6911, trac-8165, trac-11382, trac-11764)\n\t\t\t\tif ( cur.nodeType === 1 && !( event.type === \"click\" && cur.disabled === true ) ) {\n\t\t\t\t\tmatchedHandlers = [];\n\t\t\t\t\tmatchedSelectors = {};\n\t\t\t\t\tfor ( i = 0; i < delegateCount; i++ ) {\n\t\t\t\t\t\thandleObj = handlers[ i ];\n\n\t\t\t\t\t\t// Don't conflict with Object.prototype properties (trac-13203)\n\t\t\t\t\t\tsel = handleObj.selector + \" \";\n\n\t\t\t\t\t\tif ( matchedSelectors[ sel ] === undefined ) {\n\t\t\t\t\t\t\tmatchedSelectors[ sel ] = handleObj.needsContext ?\n\t\t\t\t\t\t\t\tjQuery( sel, this ).index( cur ) > -1 :\n\t\t\t\t\t\t\t\tjQuery.find( sel, this, null, [ cur ] ).length;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif ( matchedSelectors[ sel ] ) {\n\t\t\t\t\t\t\tmatchedHandlers.push( handleObj );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif ( matchedHandlers.length ) {\n\t\t\t\t\t\thandlerQueue.push( { elem: cur, handlers: matchedHandlers } );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Add the remaining (directly-bound) handlers\n\t\tcur = this;\n\t\tif ( delegateCount < handlers.length ) {\n\t\t\thandlerQueue.push( { elem: cur, handlers: handlers.slice( delegateCount ) } );\n\t\t}\n\n\t\treturn handlerQueue;\n\t},\n\n\taddProp: function( name, hook ) {\n\t\tObject.defineProperty( jQuery.Event.prototype, name, {\n\t\t\tenumerable: true,\n\t\t\tconfigurable: true,\n\n\t\t\tget: typeof hook === \"function\" ?\n\t\t\t\tfunction() {\n\t\t\t\t\tif ( this.originalEvent ) {\n\t\t\t\t\t\treturn hook( this.originalEvent );\n\t\t\t\t\t}\n\t\t\t\t} :\n\t\t\t\tfunction() {\n\t\t\t\t\tif ( this.originalEvent ) {\n\t\t\t\t\t\treturn this.originalEvent[ name ];\n\t\t\t\t\t}\n\t\t\t\t},\n\n\t\t\tset: function( value ) {\n\t\t\t\tObject.defineProperty( this, name, {\n\t\t\t\t\tenumerable: true,\n\t\t\t\t\tconfigurable: true,\n\t\t\t\t\twritable: true,\n\t\t\t\t\tvalue: value\n\t\t\t\t} );\n\t\t\t}\n\t\t} );\n\t},\n\n\tfix: function( originalEvent ) {\n\t\treturn originalEvent[ jQuery.expando ] ?\n\t\t\toriginalEvent :\n\t\t\tnew jQuery.Event( originalEvent );\n\t},\n\n\tspecial: jQuery.extend( Object.create( null ), {\n\t\tload: {\n\n\t\t\t// Prevent triggered image.load events from bubbling to window.load\n\t\t\tnoBubble: true\n\t\t},\n\t\tclick: {\n\n\t\t\t// Utilize native event to ensure correct state for checkable inputs\n\t\t\tsetup: function( data ) {\n\n\t\t\t\t// For mutual compressibility with _default, replace `this` access with a local var.\n\t\t\t\t// `|| data` is dead code meant only to preserve the variable through minification.\n\t\t\t\tvar el = this || data;\n\n\t\t\t\t// Claim the first handler\n\t\t\t\tif ( rcheckableType.test( el.type ) &&\n\t\t\t\t\tel.click && nodeName( el, \"input\" ) ) {\n\n\t\t\t\t\t// dataPriv.set( el, \"click\", ... )\n\t\t\t\t\tleverageNative( el, \"click\", true );\n\t\t\t\t}\n\n\t\t\t\t// Return false to allow normal processing in the caller\n\t\t\t\treturn false;\n\t\t\t},\n\t\t\ttrigger: function( data ) {\n\n\t\t\t\t// For mutual compressibility with _default, replace `this` access with a local var.\n\t\t\t\t// `|| data` is dead code meant only to preserve the variable through minification.\n\t\t\t\tvar el = this || data;\n\n\t\t\t\t// Force setup before triggering a click\n\t\t\t\tif ( rcheckableType.test( el.type ) &&\n\t\t\t\t\tel.click && nodeName( el, \"input\" ) ) {\n\n\t\t\t\t\tleverageNative( el, \"click\" );\n\t\t\t\t}\n\n\t\t\t\t// Return non-false to allow normal event-path propagation\n\t\t\t\treturn true;\n\t\t\t},\n\n\t\t\t// For cross-browser consistency, suppress native .click() on links\n\t\t\t// Also prevent it if we're currently inside a leveraged native-event stack\n\t\t\t_default: function( event ) {\n\t\t\t\tvar target = event.target;\n\t\t\t\treturn rcheckableType.test( target.type ) &&\n\t\t\t\t\ttarget.click && nodeName( target, \"input\" ) &&\n\t\t\t\t\tdataPriv.get( target, \"click\" ) ||\n\t\t\t\t\tnodeName( target, \"a\" );\n\t\t\t}\n\t\t},\n\n\t\tbeforeunload: {\n\t\t\tpostDispatch: function( event ) {\n\t\t\t\tif ( event.result !== undefined ) {\n\n\t\t\t\t\t// Setting `event.originalEvent.returnValue` in modern\n\t\t\t\t\t// browsers does the same as just calling `preventDefault()`,\n\t\t\t\t\t// the browsers ignore the value anyway.\n\t\t\t\t\t// Incidentally, IE 11 is the only browser from our supported\n\t\t\t\t\t// ones which respects the value returned from a `beforeunload`\n\t\t\t\t\t// handler attached by `addEventListener`; other browsers do\n\t\t\t\t\t// so only for inline handlers, so not setting the value\n\t\t\t\t\t// directly shouldn't reduce any functionality.\n\t\t\t\t\tevent.preventDefault();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t} )\n};\n\n// Ensure the presence of an event listener that handles manually-triggered\n// synthetic events by interrupting progress until reinvoked in response to\n// *native* events that it fires directly, ensuring that state changes have\n// already occurred before other listeners are invoked.\nfunction leverageNative( el, type, isSetup ) {\n\n\t// Missing `isSetup` indicates a trigger call, which must force setup through jQuery.event.add\n\tif ( !isSetup ) {\n\t\tif ( dataPriv.get( el, type ) === undefined ) {\n\t\t\tjQuery.event.add( el, type, returnTrue );\n\t\t}\n\t\treturn;\n\t}\n\n\t// Register the controller as a special universal handler for all event namespaces\n\tdataPriv.set( el, type, false );\n\tjQuery.event.add( el, type, {\n\t\tnamespace: false,\n\t\thandler: function( event ) {\n\t\t\tvar result,\n\t\t\t\tsaved = dataPriv.get( this, type );\n\n\t\t\t// This controller function is invoked under multiple circumstances,\n\t\t\t// differentiated by the stored value in `saved`:\n\t\t\t// 1. For an outer synthetic `.trigger()`ed event (detected by\n\t\t\t// `event.isTrigger & 1` and non-array `saved`), it records arguments\n\t\t\t// as an array and fires an [inner] native event to prompt state\n\t\t\t// changes that should be observed by registered listeners (such as\n\t\t\t// checkbox toggling and focus updating), then clears the stored value.\n\t\t\t// 2. For an [inner] native event (detected by `saved` being\n\t\t\t// an array), it triggers an inner synthetic event, records the\n\t\t\t// result, and preempts propagation to further jQuery listeners.\n\t\t\t// 3. For an inner synthetic event (detected by `event.isTrigger & 1` and\n\t\t\t// array `saved`), it prevents double-propagation of surrogate events\n\t\t\t// but otherwise allows everything to proceed (particularly including\n\t\t\t// further listeners).\n\t\t\t// Possible `saved` data shapes: `[...], `{ value }`, `false`.\n\t\t\tif ( ( event.isTrigger & 1 ) && this[ type ] ) {\n\n\t\t\t\t// Interrupt processing of the outer synthetic .trigger()ed event\n\t\t\t\tif ( !saved.length ) {\n\n\t\t\t\t\t// Store arguments for use when handling the inner native event\n\t\t\t\t\t// There will always be at least one argument (an event object),\n\t\t\t\t\t// so this array will not be confused with a leftover capture object.\n\t\t\t\t\tsaved = slice.call( arguments );\n\t\t\t\t\tdataPriv.set( this, type, saved );\n\n\t\t\t\t\t// Trigger the native event and capture its result\n\t\t\t\t\tthis[ type ]();\n\t\t\t\t\tresult = dataPriv.get( this, type );\n\t\t\t\t\tdataPriv.set( this, type, false );\n\n\t\t\t\t\tif ( saved !== result ) {\n\n\t\t\t\t\t\t// Cancel the outer synthetic event\n\t\t\t\t\t\tevent.stopImmediatePropagation();\n\t\t\t\t\t\tevent.preventDefault();\n\n\t\t\t\t\t\t// Support: Chrome 86+\n\t\t\t\t\t\t// In Chrome, if an element having a focusout handler is\n\t\t\t\t\t\t// blurred by clicking outside of it, it invokes the handler\n\t\t\t\t\t\t// synchronously. If that handler calls `.remove()` on\n\t\t\t\t\t\t// the element, the data is cleared, leaving `result`\n\t\t\t\t\t\t// undefined. We need to guard against this.\n\t\t\t\t\t\treturn result && result.value;\n\t\t\t\t\t}\n\n\t\t\t\t// If this is an inner synthetic event for an event with a bubbling\n\t\t\t\t// surrogate (focus or blur), assume that the surrogate already\n\t\t\t\t// propagated from triggering the native event and prevent that\n\t\t\t\t// from happening again here.\n\t\t\t\t} else if ( ( jQuery.event.special[ type ] || {} ).delegateType ) {\n\t\t\t\t\tevent.stopPropagation();\n\t\t\t\t}\n\n\t\t\t// If this is a native event triggered above, everything is now in order.\n\t\t\t// Fire an inner synthetic event with the original arguments.\n\t\t\t} else if ( saved.length ) {\n\n\t\t\t\t// ...and capture the result\n\t\t\t\tdataPriv.set( this, type, {\n\t\t\t\t\tvalue: jQuery.event.trigger(\n\t\t\t\t\t\tsaved[ 0 ],\n\t\t\t\t\t\tsaved.slice( 1 ),\n\t\t\t\t\t\tthis\n\t\t\t\t\t)\n\t\t\t\t} );\n\n\t\t\t\t// Abort handling of the native event by all jQuery handlers while allowing\n\t\t\t\t// native handlers on the same element to run. On target, this is achieved\n\t\t\t\t// by stopping immediate propagation just on the jQuery event. However,\n\t\t\t\t// the native event is re-wrapped by a jQuery one on each level of the\n\t\t\t\t// propagation so the only way to stop it for jQuery is to stop it for\n\t\t\t\t// everyone via native `stopPropagation()`. This is not a problem for\n\t\t\t\t// focus/blur which don't bubble, but it does also stop click on checkboxes\n\t\t\t\t// and radios. We accept this limitation.\n\t\t\t\tevent.stopPropagation();\n\t\t\t\tevent.isImmediatePropagationStopped = returnTrue;\n\t\t\t}\n\t\t}\n\t} );\n}\n\njQuery.removeEvent = function( elem, type, handle ) {\n\n\t// This \"if\" is needed for plain objects\n\tif ( elem.removeEventListener ) {\n\t\telem.removeEventListener( type, handle );\n\t}\n};\n\njQuery.Event = function( src, props ) {\n\n\t// Allow instantiation without the 'new' keyword\n\tif ( !( this instanceof jQuery.Event ) ) {\n\t\treturn new jQuery.Event( src, props );\n\t}\n\n\t// Event object\n\tif ( src && src.type ) {\n\t\tthis.originalEvent = src;\n\t\tthis.type = src.type;\n\n\t\t// Events bubbling up the document may have been marked as prevented\n\t\t// by a handler lower down the tree; reflect the correct value.\n\t\tthis.isDefaultPrevented = src.defaultPrevented ?\n\t\t\treturnTrue :\n\t\t\treturnFalse;\n\n\t\t// Create target properties\n\t\tthis.target = src.target;\n\t\tthis.currentTarget = src.currentTarget;\n\t\tthis.relatedTarget = src.relatedTarget;\n\n\t// Event type\n\t} else {\n\t\tthis.type = src;\n\t}\n\n\t// Put explicitly provided properties onto the event object\n\tif ( props ) {\n\t\tjQuery.extend( this, props );\n\t}\n\n\t// Create a timestamp if incoming event doesn't have one\n\tthis.timeStamp = src && src.timeStamp || Date.now();\n\n\t// Mark it as fixed\n\tthis[ jQuery.expando ] = true;\n};\n\n// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding\n// https://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html\njQuery.Event.prototype = {\n\tconstructor: jQuery.Event,\n\tisDefaultPrevented: returnFalse,\n\tisPropagationStopped: returnFalse,\n\tisImmediatePropagationStopped: returnFalse,\n\tisSimulated: false,\n\n\tpreventDefault: function() {\n\t\tvar e = this.originalEvent;\n\n\t\tthis.isDefaultPrevented = returnTrue;\n\n\t\tif ( e && !this.isSimulated ) {\n\t\t\te.preventDefault();\n\t\t}\n\t},\n\tstopPropagation: function() {\n\t\tvar e = this.originalEvent;\n\n\t\tthis.isPropagationStopped = returnTrue;\n\n\t\tif ( e && !this.isSimulated ) {\n\t\t\te.stopPropagation();\n\t\t}\n\t},\n\tstopImmediatePropagation: function() {\n\t\tvar e = this.originalEvent;\n\n\t\tthis.isImmediatePropagationStopped = returnTrue;\n\n\t\tif ( e && !this.isSimulated ) {\n\t\t\te.stopImmediatePropagation();\n\t\t}\n\n\t\tthis.stopPropagation();\n\t}\n};\n\n// Includes all common event props including KeyEvent and MouseEvent specific props\njQuery.each( {\n\taltKey: true,\n\tbubbles: true,\n\tcancelable: true,\n\tchangedTouches: true,\n\tctrlKey: true,\n\tdetail: true,\n\teventPhase: true,\n\tmetaKey: true,\n\tpageX: true,\n\tpageY: true,\n\tshiftKey: true,\n\tview: true,\n\t\"char\": true,\n\tcode: true,\n\tcharCode: true,\n\tkey: true,\n\tkeyCode: true,\n\tbutton: true,\n\tbuttons: true,\n\tclientX: true,\n\tclientY: true,\n\toffsetX: true,\n\toffsetY: true,\n\tpointerId: true,\n\tpointerType: true,\n\tscreenX: true,\n\tscreenY: true,\n\ttargetTouches: true,\n\ttoElement: true,\n\ttouches: true,\n\twhich: true\n}, jQuery.event.addProp );\n\njQuery.each( { focus: \"focusin\", blur: \"focusout\" }, function( type, delegateType ) {\n\n\t// Support: IE 11+\n\t// Attach a single focusin/focusout handler on the document while someone wants focus/blur.\n\t// This is because the former are synchronous in IE while the latter are async. In other\n\t// browsers, all those handlers are invoked synchronously.\n\tfunction focusMappedHandler( nativeEvent ) {\n\n\t\t// `eventHandle` would already wrap the event, but we need to change the `type` here.\n\t\tvar event = jQuery.event.fix( nativeEvent );\n\t\tevent.type = nativeEvent.type === \"focusin\" ? \"focus\" : \"blur\";\n\t\tevent.isSimulated = true;\n\n\t\t// focus/blur don't bubble while focusin/focusout do; simulate the former by only\n\t\t// invoking the handler at the lower level.\n\t\tif ( event.target === event.currentTarget ) {\n\n\t\t\t// The setup part calls `leverageNative`, which, in turn, calls\n\t\t\t// `jQuery.event.add`, so event handle will already have been set\n\t\t\t// by this point.\n\t\t\tdataPriv.get( this, \"handle\" )( event );\n\t\t}\n\t}\n\n\tjQuery.event.special[ type ] = {\n\n\t\t// Utilize native event if possible so blur/focus sequence is correct\n\t\tsetup: function() {\n\n\t\t\t// Claim the first handler\n\t\t\t// dataPriv.set( this, \"focus\", ... )\n\t\t\t// dataPriv.set( this, \"blur\", ... )\n\t\t\tleverageNative( this, type, true );\n\n\t\t\tif ( isIE ) {\n\t\t\t\tthis.addEventListener( delegateType, focusMappedHandler );\n\t\t\t} else {\n\n\t\t\t\t// Return false to allow normal processing in the caller\n\t\t\t\treturn false;\n\t\t\t}\n\t\t},\n\t\ttrigger: function() {\n\n\t\t\t// Force setup before trigger\n\t\t\tleverageNative( this, type );\n\n\t\t\t// Return non-false to allow normal event-path propagation\n\t\t\treturn true;\n\t\t},\n\n\t\tteardown: function() {\n\t\t\tif ( isIE ) {\n\t\t\t\tthis.removeEventListener( delegateType, focusMappedHandler );\n\t\t\t} else {\n\n\t\t\t\t// Return false to indicate standard teardown should be applied\n\t\t\t\treturn false;\n\t\t\t}\n\t\t},\n\n\t\t// Suppress native focus or blur if we're currently inside\n\t\t// a leveraged native-event stack\n\t\t_default: function( event ) {\n\t\t\treturn dataPriv.get( event.target, type );\n\t\t},\n\n\t\tdelegateType: delegateType\n\t};\n} );\n\n// Create mouseenter/leave events using mouseover/out and event-time checks\n// so that event delegation works in jQuery.\n// Do the same for pointerenter/pointerleave and pointerover/pointerout\njQuery.each( {\n\tmouseenter: \"mouseover\",\n\tmouseleave: \"mouseout\",\n\tpointerenter: \"pointerover\",\n\tpointerleave: \"pointerout\"\n}, function( orig, fix ) {\n\tjQuery.event.special[ orig ] = {\n\t\tdelegateType: fix,\n\t\tbindType: fix,\n\n\t\thandle: function( event ) {\n\t\t\tvar ret,\n\t\t\t\ttarget = this,\n\t\t\t\trelated = event.relatedTarget,\n\t\t\t\thandleObj = event.handleObj;\n\n\t\t\t// For mouseenter/leave call the handler if related is outside the target.\n\t\t\t// NB: No relatedTarget if the mouse left/entered the browser window\n\t\t\tif ( !related || ( related !== target && !jQuery.contains( target, related ) ) ) {\n\t\t\t\tevent.type = handleObj.origType;\n\t\t\t\tret = handleObj.handler.apply( this, arguments );\n\t\t\t\tevent.type = fix;\n\t\t\t}\n\t\t\treturn ret;\n\t\t}\n\t};\n} );\n\njQuery.fn.extend( {\n\n\ton: function( types, selector, data, fn ) {\n\t\treturn on( this, types, selector, data, fn );\n\t},\n\tone: function( types, selector, data, fn ) {\n\t\treturn on( this, types, selector, data, fn, 1 );\n\t},\n\toff: function( types, selector, fn ) {\n\t\tvar handleObj, type;\n\t\tif ( types && types.preventDefault && types.handleObj ) {\n\n\t\t\t// ( event ) dispatched jQuery.Event\n\t\t\thandleObj = types.handleObj;\n\t\t\tjQuery( types.delegateTarget ).off(\n\t\t\t\thandleObj.namespace ?\n\t\t\t\t\thandleObj.origType + \".\" + handleObj.namespace :\n\t\t\t\t\thandleObj.origType,\n\t\t\t\thandleObj.selector,\n\t\t\t\thandleObj.handler\n\t\t\t);\n\t\t\treturn this;\n\t\t}\n\t\tif ( typeof types === \"object\" ) {\n\n\t\t\t// ( types-object [, selector] )\n\t\t\tfor ( type in types ) {\n\t\t\t\tthis.off( type, selector, types[ type ] );\n\t\t\t}\n\t\t\treturn this;\n\t\t}\n\t\tif ( selector === false || typeof selector === \"function\" ) {\n\n\t\t\t// ( types [, fn] )\n\t\t\tfn = selector;\n\t\t\tselector = undefined;\n\t\t}\n\t\tif ( fn === false ) {\n\t\t\tfn = returnFalse;\n\t\t}\n\t\treturn this.each( function() {\n\t\t\tjQuery.event.remove( this, types, fn, selector );\n\t\t} );\n\t}\n} );\n\nvar\n\n\t// Support: IE <=10 - 11+\n\t// In IE using regex groups here causes severe slowdowns.\n\trnoInnerhtml = / 0 ) {\n\t\t\tsetGlobalEval( destElements, !inPage && getAll( elem, \"script\" ) );\n\t\t}\n\n\t\t// Return the cloned set\n\t\treturn clone;\n\t},\n\n\tcleanData: function( elems ) {\n\t\tvar data, elem, type,\n\t\t\tspecial = jQuery.event.special,\n\t\t\ti = 0;\n\n\t\tfor ( ; ( elem = elems[ i ] ) !== undefined; i++ ) {\n\t\t\tif ( acceptData( elem ) ) {\n\t\t\t\tif ( ( data = elem[ dataPriv.expando ] ) ) {\n\t\t\t\t\tif ( data.events ) {\n\t\t\t\t\t\tfor ( type in data.events ) {\n\t\t\t\t\t\t\tif ( special[ type ] ) {\n\t\t\t\t\t\t\t\tjQuery.event.remove( elem, type );\n\n\t\t\t\t\t\t\t// This is a shortcut to avoid jQuery.event.remove's overhead\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tjQuery.removeEvent( elem, type, data.handle );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// Support: Chrome <=35 - 45+\n\t\t\t\t\t// Assign undefined instead of using delete, see Data#remove\n\t\t\t\t\telem[ dataPriv.expando ] = undefined;\n\t\t\t\t}\n\t\t\t\tif ( elem[ dataUser.expando ] ) {\n\n\t\t\t\t\t// Support: Chrome <=35 - 45+\n\t\t\t\t\t// Assign undefined instead of using delete, see Data#remove\n\t\t\t\t\telem[ dataUser.expando ] = undefined;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n} );\n\njQuery.fn.extend( {\n\tdetach: function( selector ) {\n\t\treturn remove( this, selector, true );\n\t},\n\n\tremove: function( selector ) {\n\t\treturn remove( this, selector );\n\t},\n\n\ttext: function( value ) {\n\t\treturn access( this, function( value ) {\n\t\t\treturn value === undefined ?\n\t\t\t\tjQuery.text( this ) :\n\t\t\t\tthis.empty().each( function() {\n\t\t\t\t\tif ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {\n\t\t\t\t\t\tthis.textContent = value;\n\t\t\t\t\t}\n\t\t\t\t} );\n\t\t}, null, value, arguments.length );\n\t},\n\n\tappend: function() {\n\t\treturn domManip( this, arguments, function( elem ) {\n\t\t\tif ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {\n\t\t\t\tvar target = manipulationTarget( this, elem );\n\t\t\t\ttarget.appendChild( elem );\n\t\t\t}\n\t\t} );\n\t},\n\n\tprepend: function() {\n\t\treturn domManip( this, arguments, function( elem ) {\n\t\t\tif ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {\n\t\t\t\tvar target = manipulationTarget( this, elem );\n\t\t\t\ttarget.insertBefore( elem, target.firstChild );\n\t\t\t}\n\t\t} );\n\t},\n\n\tbefore: function() {\n\t\treturn domManip( this, arguments, function( elem ) {\n\t\t\tif ( this.parentNode ) {\n\t\t\t\tthis.parentNode.insertBefore( elem, this );\n\t\t\t}\n\t\t} );\n\t},\n\n\tafter: function() {\n\t\treturn domManip( this, arguments, function( elem ) {\n\t\t\tif ( this.parentNode ) {\n\t\t\t\tthis.parentNode.insertBefore( elem, this.nextSibling );\n\t\t\t}\n\t\t} );\n\t},\n\n\tempty: function() {\n\t\tvar elem,\n\t\t\ti = 0;\n\n\t\tfor ( ; ( elem = this[ i ] ) != null; i++ ) {\n\t\t\tif ( elem.nodeType === 1 ) {\n\n\t\t\t\t// Prevent memory leaks\n\t\t\t\tjQuery.cleanData( getAll( elem, false ) );\n\n\t\t\t\t// Remove any remaining nodes\n\t\t\t\telem.textContent = \"\";\n\t\t\t}\n\t\t}\n\n\t\treturn this;\n\t},\n\n\tclone: function( dataAndEvents, deepDataAndEvents ) {\n\t\tdataAndEvents = dataAndEvents == null ? false : dataAndEvents;\n\t\tdeepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents;\n\n\t\treturn this.map( function() {\n\t\t\treturn jQuery.clone( this, dataAndEvents, deepDataAndEvents );\n\t\t} );\n\t},\n\n\thtml: function( value ) {\n\t\treturn access( this, function( value ) {\n\t\t\tvar elem = this[ 0 ] || {},\n\t\t\t\ti = 0,\n\t\t\t\tl = this.length;\n\n\t\t\tif ( value === undefined && elem.nodeType === 1 ) {\n\t\t\t\treturn elem.innerHTML;\n\t\t\t}\n\n\t\t\t// See if we can take a shortcut and just use innerHTML\n\t\t\tif ( typeof value === \"string\" && !rnoInnerhtml.test( value ) &&\n\t\t\t\t!wrapMap[ ( rtagName.exec( value ) || [ \"\", \"\" ] )[ 1 ].toLowerCase() ] ) {\n\n\t\t\t\tvalue = jQuery.htmlPrefilter( value );\n\n\t\t\t\ttry {\n\t\t\t\t\tfor ( ; i < l; i++ ) {\n\t\t\t\t\t\telem = this[ i ] || {};\n\n\t\t\t\t\t\t// Remove element nodes and prevent memory leaks\n\t\t\t\t\t\tif ( elem.nodeType === 1 ) {\n\t\t\t\t\t\t\tjQuery.cleanData( getAll( elem, false ) );\n\t\t\t\t\t\t\telem.innerHTML = value;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\telem = 0;\n\n\t\t\t\t// If using innerHTML throws an exception, use the fallback method\n\t\t\t\t} catch ( e ) {}\n\t\t\t}\n\n\t\t\tif ( elem ) {\n\t\t\t\tthis.empty().append( value );\n\t\t\t}\n\t\t}, null, value, arguments.length );\n\t},\n\n\treplaceWith: function() {\n\t\tvar ignored = [];\n\n\t\t// Make the changes, replacing each non-ignored context element with the new content\n\t\treturn domManip( this, arguments, function( elem ) {\n\t\t\tvar parent = this.parentNode;\n\n\t\t\tif ( jQuery.inArray( this, ignored ) < 0 ) {\n\t\t\t\tjQuery.cleanData( getAll( this ) );\n\t\t\t\tif ( parent ) {\n\t\t\t\t\tparent.replaceChild( elem, this );\n\t\t\t\t}\n\t\t\t}\n\n\t\t// Force callback invocation\n\t\t}, ignored );\n\t}\n} );\n\njQuery.each( {\n\tappendTo: \"append\",\n\tprependTo: \"prepend\",\n\tinsertBefore: \"before\",\n\tinsertAfter: \"after\",\n\treplaceAll: \"replaceWith\"\n}, function( name, original ) {\n\tjQuery.fn[ name ] = function( selector ) {\n\t\tvar elems,\n\t\t\tret = [],\n\t\t\tinsert = jQuery( selector ),\n\t\t\tlast = insert.length - 1,\n\t\t\ti = 0;\n\n\t\tfor ( ; i <= last; i++ ) {\n\t\t\telems = i === last ? this : this.clone( true );\n\t\t\tjQuery( insert[ i ] )[ original ]( elems );\n\t\t\tpush.apply( ret, elems );\n\t\t}\n\n\t\treturn this.pushStack( ret );\n\t};\n} );\n\nvar rnumnonpx = new RegExp( \"^(\" + pnum + \")(?!px)[a-z%]+$\", \"i\" );\n\nvar rcustomProp = /^--/;\n\nfunction getStyles( elem ) {\n\n\t// Support: IE <=11+ (trac-14150)\n\t// In IE popup's `window` is the opener window which makes `window.getComputedStyle( elem )`\n\t// break. Using `elem.ownerDocument.defaultView` avoids the issue.\n\tvar view = elem.ownerDocument.defaultView;\n\n\t// `document.implementation.createHTMLDocument( \"\" )` has a `null` `defaultView`\n\t// property; check `defaultView` truthiness to fallback to window in such a case.\n\tif ( !view ) {\n\t\tview = window;\n\t}\n\n\treturn view.getComputedStyle( elem );\n}\n\n// A method for quickly swapping in/out CSS properties to get correct calculations.\nfunction swap( elem, options, callback ) {\n\tvar ret, name,\n\t\told = {};\n\n\t// Remember the old values, and insert the new ones\n\tfor ( name in options ) {\n\t\told[ name ] = elem.style[ name ];\n\t\telem.style[ name ] = options[ name ];\n\t}\n\n\tret = callback.call( elem );\n\n\t// Revert the old values\n\tfor ( name in options ) {\n\t\telem.style[ name ] = old[ name ];\n\t}\n\n\treturn ret;\n}\n\nfunction curCSS( elem, name, computed ) {\n\tvar ret,\n\t\tisCustomProp = rcustomProp.test( name );\n\n\tcomputed = computed || getStyles( elem );\n\n\t// getPropertyValue is needed for `.css('--customProperty')` (gh-3144)\n\tif ( computed ) {\n\n\t\t// A fallback to direct property access is needed as `computed`, being\n\t\t// the output of `getComputedStyle`, contains camelCased keys and\n\t\t// `getPropertyValue` requires kebab-case ones.\n\t\t//\n\t\t// Support: IE <=9 - 11+\n\t\t// IE only supports `\"float\"` in `getPropertyValue`; in computed styles\n\t\t// it's only available as `\"cssFloat\"`. We no longer modify properties\n\t\t// sent to `.css()` apart from camelCasing, so we need to check both.\n\t\t// Normally, this would create difference in behavior: if\n\t\t// `getPropertyValue` returns an empty string, the value returned\n\t\t// by `.css()` would be `undefined`. This is usually the case for\n\t\t// disconnected elements. However, in IE even disconnected elements\n\t\t// with no styles return `\"none\"` for `getPropertyValue( \"float\" )`\n\t\tret = computed.getPropertyValue( name ) || computed[ name ];\n\n\t\tif ( isCustomProp && ret ) {\n\n\t\t\t// Support: Firefox 105 - 135+\n\t\t\t// Spec requires trimming whitespace for custom properties (gh-4926).\n\t\t\t// Firefox only trims leading whitespace.\n\t\t\t//\n\t\t\t// Fall back to `undefined` if empty string returned.\n\t\t\t// This collapses a missing definition with property defined\n\t\t\t// and set to an empty string but there's no standard API\n\t\t\t// allowing us to differentiate them without a performance penalty\n\t\t\t// and returning `undefined` aligns with older jQuery.\n\t\t\t//\n\t\t\t// rtrimCSS treats U+000D CARRIAGE RETURN and U+000C FORM FEED\n\t\t\t// as whitespace while CSS does not, but this is not a problem\n\t\t\t// because CSS preprocessing replaces them with U+000A LINE FEED\n\t\t\t// (which *is* CSS whitespace)\n\t\t\t// https://www.w3.org/TR/css-syntax-3/#input-preprocessing\n\t\t\tret = ret.replace( rtrimCSS, \"$1\" ) || undefined;\n\t\t}\n\n\t\tif ( ret === \"\" && !isAttached( elem ) ) {\n\t\t\tret = jQuery.style( elem, name );\n\t\t}\n\t}\n\n\treturn ret !== undefined ?\n\n\t\t// Support: IE <=9 - 11+\n\t\t// IE returns zIndex value as an integer.\n\t\tret + \"\" :\n\t\tret;\n}\n\nvar cssPrefixes = [ \"Webkit\", \"Moz\", \"ms\" ],\n\temptyStyle = document$1.createElement( \"div\" ).style;\n\n// Return a vendor-prefixed property or undefined\nfunction vendorPropName( name ) {\n\n\t// Check for vendor prefixed names\n\tvar capName = name[ 0 ].toUpperCase() + name.slice( 1 ),\n\t\ti = cssPrefixes.length;\n\n\twhile ( i-- ) {\n\t\tname = cssPrefixes[ i ] + capName;\n\t\tif ( name in emptyStyle ) {\n\t\t\treturn name;\n\t\t}\n\t}\n}\n\n// Return a potentially-mapped vendor prefixed property\nfunction finalPropName( name ) {\n\tif ( name in emptyStyle ) {\n\t\treturn name;\n\t}\n\treturn vendorPropName( name ) || name;\n}\n\nvar reliableTrDimensionsVal, reliableColDimensionsVal,\n\ttable = document$1.createElement( \"table\" );\n\n// Executing table tests requires only one layout, so they're executed\n// at the same time to save the second computation.\nfunction computeTableStyleTests() {\n\tif (\n\n\t\t// This is a singleton, we need to execute it only once\n\t\t!table ||\n\n\t\t// Finish early in limited (non-browser) environments\n\t\t!table.style\n\t) {\n\t\treturn;\n\t}\n\n\tvar trStyle,\n\t\tcol = document$1.createElement( \"col\" ),\n\t\ttr = document$1.createElement( \"tr\" ),\n\t\ttd = document$1.createElement( \"td\" );\n\n\ttable.style.cssText = \"position:absolute;left:-11111px;\" +\n\t\t\"border-collapse:separate;border-spacing:0\";\n\ttr.style.cssText = \"box-sizing:content-box;border:1px solid;height:1px\";\n\ttd.style.cssText = \"height:9px;width:9px;padding:0\";\n\n\tcol.span = 2;\n\n\tdocumentElement$1\n\t\t.appendChild( table )\n\t\t.appendChild( col )\n\t\t.parentNode\n\t\t.appendChild( tr )\n\t\t.appendChild( td )\n\t\t.parentNode\n\t\t.appendChild( td.cloneNode( true ) );\n\n\t// Don't run until window is visible\n\tif ( table.offsetWidth === 0 ) {\n\t\tdocumentElement$1.removeChild( table );\n\t\treturn;\n\t}\n\n\ttrStyle = window.getComputedStyle( tr );\n\n\t// Support: Firefox 135+\n\t// Firefox always reports computed width as if `span` was 1.\n\t// Support: Safari 18.3+\n\t// In Safari, computed width for columns is always 0.\n\t// In both these browsers, using `offsetWidth` solves the issue.\n\t// Support: IE 11+\n\t// In IE, `` computed width is `\"auto\"` unless `width` is set\n\t// explicitly via CSS so measurements there remain incorrect. Because of\n\t// the lack of a proper workaround, we accept this limitation, treating\n\t// IE as passing the test.\n\treliableColDimensionsVal = isIE || Math.round( parseFloat(\n\t\twindow.getComputedStyle( col ).width )\n\t) === 18;\n\n\t// Support: IE 10 - 11+\n\t// IE misreports `getComputedStyle` of table rows with width/height\n\t// set in CSS while `offset*` properties report correct values.\n\t// Support: Firefox 70 - 135+\n\t// Only Firefox includes border widths\n\t// in computed dimensions for table rows. (gh-4529)\n\treliableTrDimensionsVal = Math.round( parseFloat( trStyle.height ) +\n\t\tparseFloat( trStyle.borderTopWidth ) +\n\t\tparseFloat( trStyle.borderBottomWidth ) ) === tr.offsetHeight;\n\n\tdocumentElement$1.removeChild( table );\n\n\t// Nullify the table so it wouldn't be stored in the memory;\n\t// it will also be a sign that checks were already performed.\n\ttable = null;\n}\n\njQuery.extend( support, {\n\treliableTrDimensions: function() {\n\t\tcomputeTableStyleTests();\n\t\treturn reliableTrDimensionsVal;\n\t},\n\n\treliableColDimensions: function() {\n\t\tcomputeTableStyleTests();\n\t\treturn reliableColDimensionsVal;\n\t}\n} );\n\nvar cssShow = { position: \"absolute\", visibility: \"hidden\", display: \"block\" },\n\tcssNormalTransform = {\n\t\tletterSpacing: \"0\",\n\t\tfontWeight: \"400\"\n\t};\n\nfunction setPositiveNumber( _elem, value, subtract ) {\n\n\t// Any relative (+/-) values have already been\n\t// normalized at this point\n\tvar matches = rcssNum.exec( value );\n\treturn matches ?\n\n\t\t// Guard against undefined \"subtract\", e.g., when used as in cssHooks\n\t\tMath.max( 0, matches[ 2 ] - ( subtract || 0 ) ) + ( matches[ 3 ] || \"px\" ) :\n\t\tvalue;\n}\n\nfunction boxModelAdjustment( elem, dimension, box, isBorderBox, styles, computedVal ) {\n\tvar i = dimension === \"width\" ? 1 : 0,\n\t\textra = 0,\n\t\tdelta = 0,\n\t\tmarginDelta = 0;\n\n\t// Adjustment may not be necessary\n\tif ( box === ( isBorderBox ? \"border\" : \"content\" ) ) {\n\t\treturn 0;\n\t}\n\n\tfor ( ; i < 4; i += 2 ) {\n\n\t\t// Both box models exclude margin\n\t\t// Count margin delta separately to only add it after scroll gutter adjustment.\n\t\t// This is needed to make negative margins work with `outerHeight( true )` (gh-3982).\n\t\tif ( box === \"margin\" ) {\n\t\t\tmarginDelta += jQuery.css( elem, box + cssExpand[ i ], true, styles );\n\t\t}\n\n\t\t// If we get here with a content-box, we're seeking \"padding\" or \"border\" or \"margin\"\n\t\tif ( !isBorderBox ) {\n\n\t\t\t// Add padding\n\t\t\tdelta += jQuery.css( elem, \"padding\" + cssExpand[ i ], true, styles );\n\n\t\t\t// For \"border\" or \"margin\", add border\n\t\t\tif ( box !== \"padding\" ) {\n\t\t\t\tdelta += jQuery.css( elem, \"border\" + cssExpand[ i ] + \"Width\", true, styles );\n\n\t\t\t// But still keep track of it otherwise\n\t\t\t} else {\n\t\t\t\textra += jQuery.css( elem, \"border\" + cssExpand[ i ] + \"Width\", true, styles );\n\t\t\t}\n\n\t\t// If we get here with a border-box (content + padding + border), we're seeking \"content\" or\n\t\t// \"padding\" or \"margin\"\n\t\t} else {\n\n\t\t\t// For \"content\", subtract padding\n\t\t\tif ( box === \"content\" ) {\n\t\t\t\tdelta -= jQuery.css( elem, \"padding\" + cssExpand[ i ], true, styles );\n\t\t\t}\n\n\t\t\t// For \"content\" or \"padding\", subtract border\n\t\t\tif ( box !== \"margin\" ) {\n\t\t\t\tdelta -= jQuery.css( elem, \"border\" + cssExpand[ i ] + \"Width\", true, styles );\n\t\t\t}\n\t\t}\n\t}\n\n\t// Account for positive content-box scroll gutter when requested by providing computedVal\n\tif ( !isBorderBox && computedVal >= 0 ) {\n\n\t\t// offsetWidth/offsetHeight is a rounded sum of content, padding, scroll gutter, and border\n\t\t// Assuming integer scroll gutter, subtract the rest and round down\n\t\tdelta += Math.max( 0, Math.ceil(\n\t\t\telem[ \"offset\" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] -\n\t\t\tcomputedVal -\n\t\t\tdelta -\n\t\t\textra -\n\t\t\t0.5\n\n\t\t// If offsetWidth/offsetHeight is unknown, then we can't determine content-box scroll gutter\n\t\t// Use an explicit zero to avoid NaN (gh-3964)\n\t\t) ) || 0;\n\t}\n\n\treturn delta + marginDelta;\n}\n\nfunction getWidthOrHeight( elem, dimension, extra ) {\n\n\t// Start with computed style\n\tvar styles = getStyles( elem ),\n\n\t\t// To avoid forcing a reflow, only fetch boxSizing if we need it (gh-4322).\n\t\t// Fake content-box until we know it's needed to know the true value.\n\t\tboxSizingNeeded = isIE || extra,\n\t\tisBorderBox = boxSizingNeeded &&\n\t\t\tjQuery.css( elem, \"boxSizing\", false, styles ) === \"border-box\",\n\t\tvalueIsBorderBox = isBorderBox,\n\n\t\tval = curCSS( elem, dimension, styles ),\n\t\toffsetProp = \"offset\" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 );\n\n\t// Return a confounding non-pixel value or feign ignorance, as appropriate.\n\tif ( rnumnonpx.test( val ) ) {\n\t\tif ( !extra ) {\n\t\t\treturn val;\n\t\t}\n\t\tval = \"auto\";\n\t}\n\n\n\tif (\n\t\t(\n\n\t\t\t// Fall back to offsetWidth/offsetHeight when value is \"auto\"\n\t\t\t// This happens for inline elements with no explicit setting (gh-3571)\n\t\t\tval === \"auto\" ||\n\n\t\t\t// Support: IE 9 - 11+\n\t\t\t// Use offsetWidth/offsetHeight for when box sizing is unreliable.\n\t\t\t// In those cases, the computed value can be trusted to be border-box.\n\t\t\t( isIE && isBorderBox ) ||\n\n\t\t\t( !support.reliableColDimensions() && nodeName( elem, \"col\" ) ) ||\n\n\t\t\t( !support.reliableTrDimensions() && nodeName( elem, \"tr\" ) )\n\t\t) &&\n\n\t\t// Make sure the element is visible & connected\n\t\telem.getClientRects().length ) {\n\n\t\tisBorderBox = jQuery.css( elem, \"boxSizing\", false, styles ) === \"border-box\";\n\n\t\t// Where available, offsetWidth/offsetHeight approximate border box dimensions.\n\t\t// Where not available (e.g., SVG), assume unreliable box-sizing and interpret the\n\t\t// retrieved value as a content box dimension.\n\t\tvalueIsBorderBox = offsetProp in elem;\n\t\tif ( valueIsBorderBox ) {\n\t\t\tval = elem[ offsetProp ];\n\t\t}\n\t}\n\n\t// Normalize \"\" and auto\n\tval = parseFloat( val ) || 0;\n\n\t// Adjust for the element's box model\n\treturn ( val +\n\t\tboxModelAdjustment(\n\t\t\telem,\n\t\t\tdimension,\n\t\t\textra || ( isBorderBox ? \"border\" : \"content\" ),\n\t\t\tvalueIsBorderBox,\n\t\t\tstyles,\n\n\t\t\t// Provide the current computed size to request scroll gutter calculation (gh-3589)\n\t\t\tval\n\t\t)\n\t) + \"px\";\n}\n\njQuery.extend( {\n\n\t// Add in style property hooks for overriding the default\n\t// behavior of getting and setting a style property\n\tcssHooks: {},\n\n\t// Get and set the style property on a DOM Node\n\tstyle: function( elem, name, value, extra ) {\n\n\t\t// Don't set styles on text and comment nodes\n\t\tif ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Make sure that we're working with the right name\n\t\tvar ret, type, hooks,\n\t\t\torigName = cssCamelCase( name ),\n\t\t\tisCustomProp = rcustomProp.test( name ),\n\t\t\tstyle = elem.style;\n\n\t\t// Make sure that we're working with the right name. We don't\n\t\t// want to query the value if it is a CSS custom property\n\t\t// since they are user-defined.\n\t\tif ( !isCustomProp ) {\n\t\t\tname = finalPropName( origName );\n\t\t}\n\n\t\t// Gets hook for the prefixed version, then unprefixed version\n\t\thooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];\n\n\t\t// Check if we're setting a value\n\t\tif ( value !== undefined ) {\n\t\t\ttype = typeof value;\n\n\t\t\t// Convert \"+=\" or \"-=\" to relative numbers (trac-7345)\n\t\t\tif ( type === \"string\" && ( ret = rcssNum.exec( value ) ) && ret[ 1 ] ) {\n\t\t\t\tvalue = adjustCSS( elem, name, ret );\n\n\t\t\t\t// Fixes bug trac-9237\n\t\t\t\ttype = \"number\";\n\t\t\t}\n\n\t\t\t// Make sure that null and NaN values aren't set (trac-7116)\n\t\t\tif ( value == null || value !== value ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// If the value is a number, add `px` for certain CSS properties\n\t\t\tif ( type === \"number\" ) {\n\t\t\t\tvalue += ret && ret[ 3 ] || ( isAutoPx( origName ) ? \"px\" : \"\" );\n\t\t\t}\n\n\t\t\t// Support: IE <=9 - 11+\n\t\t\t// background-* props of a cloned element affect the source element (trac-8908)\n\t\t\tif ( isIE && value === \"\" && name.indexOf( \"background\" ) === 0 ) {\n\t\t\t\tstyle[ name ] = \"inherit\";\n\t\t\t}\n\n\t\t\t// If a hook was provided, use that value, otherwise just set the specified value\n\t\t\tif ( !hooks || !( \"set\" in hooks ) ||\n\t\t\t\t( value = hooks.set( elem, value, extra ) ) !== undefined ) {\n\n\t\t\t\tif ( isCustomProp ) {\n\t\t\t\t\tstyle.setProperty( name, value );\n\t\t\t\t} else {\n\t\t\t\t\tstyle[ name ] = value;\n\t\t\t\t}\n\t\t\t}\n\n\t\t} else {\n\n\t\t\t// If a hook was provided get the non-computed value from there\n\t\t\tif ( hooks && \"get\" in hooks &&\n\t\t\t\t( ret = hooks.get( elem, false, extra ) ) !== undefined ) {\n\n\t\t\t\treturn ret;\n\t\t\t}\n\n\t\t\t// Otherwise just get the value from the style object\n\t\t\treturn style[ name ];\n\t\t}\n\t},\n\n\tcss: function( elem, name, extra, styles ) {\n\t\tvar val, num, hooks,\n\t\t\torigName = cssCamelCase( name ),\n\t\t\tisCustomProp = rcustomProp.test( name );\n\n\t\t// Make sure that we're working with the right name. We don't\n\t\t// want to modify the value if it is a CSS custom property\n\t\t// since they are user-defined.\n\t\tif ( !isCustomProp ) {\n\t\t\tname = finalPropName( origName );\n\t\t}\n\n\t\t// Try prefixed name followed by the unprefixed name\n\t\thooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];\n\n\t\t// If a hook was provided get the computed value from there\n\t\tif ( hooks && \"get\" in hooks ) {\n\t\t\tval = hooks.get( elem, true, extra );\n\t\t}\n\n\t\t// Otherwise, if a way to get the computed value exists, use that\n\t\tif ( val === undefined ) {\n\t\t\tval = curCSS( elem, name, styles );\n\t\t}\n\n\t\t// Convert \"normal\" to computed value\n\t\tif ( val === \"normal\" && name in cssNormalTransform ) {\n\t\t\tval = cssNormalTransform[ name ];\n\t\t}\n\n\t\t// Make numeric if forced or a qualifier was provided and val looks numeric\n\t\tif ( extra === \"\" || extra ) {\n\t\t\tnum = parseFloat( val );\n\t\t\treturn extra === true || isFinite( num ) ? num || 0 : val;\n\t\t}\n\n\t\treturn val;\n\t}\n} );\n\njQuery.each( [ \"height\", \"width\" ], function( _i, dimension ) {\n\tjQuery.cssHooks[ dimension ] = {\n\t\tget: function( elem, computed, extra ) {\n\t\t\tif ( computed ) {\n\n\t\t\t\t// Elements with `display: none` can have dimension info if\n\t\t\t\t// we invisibly show them.\n\t\t\t\treturn jQuery.css( elem, \"display\" ) === \"none\" ?\n\t\t\t\t\tswap( elem, cssShow, function() {\n\t\t\t\t\t\treturn getWidthOrHeight( elem, dimension, extra );\n\t\t\t\t\t} ) :\n\t\t\t\t\tgetWidthOrHeight( elem, dimension, extra );\n\t\t\t}\n\t\t},\n\n\t\tset: function( elem, value, extra ) {\n\t\t\tvar matches,\n\t\t\t\tstyles = getStyles( elem ),\n\n\t\t\t\t// To avoid forcing a reflow, only fetch boxSizing if we need it (gh-3991)\n\t\t\t\tisBorderBox = extra &&\n\t\t\t\t\tjQuery.css( elem, \"boxSizing\", false, styles ) === \"border-box\",\n\t\t\t\tsubtract = extra ?\n\t\t\t\t\tboxModelAdjustment(\n\t\t\t\t\t\telem,\n\t\t\t\t\t\tdimension,\n\t\t\t\t\t\textra,\n\t\t\t\t\t\tisBorderBox,\n\t\t\t\t\t\tstyles\n\t\t\t\t\t) :\n\t\t\t\t\t0;\n\n\t\t\t// Convert to pixels if value adjustment is needed\n\t\t\tif ( subtract && ( matches = rcssNum.exec( value ) ) &&\n\t\t\t\t( matches[ 3 ] || \"px\" ) !== \"px\" ) {\n\n\t\t\t\telem.style[ dimension ] = value;\n\t\t\t\tvalue = jQuery.css( elem, dimension );\n\t\t\t}\n\n\t\t\treturn setPositiveNumber( elem, value, subtract );\n\t\t}\n\t};\n} );\n\n// These hooks are used by animate to expand properties\njQuery.each( {\n\tmargin: \"\",\n\tpadding: \"\",\n\tborder: \"Width\"\n}, function( prefix, suffix ) {\n\tjQuery.cssHooks[ prefix + suffix ] = {\n\t\texpand: function( value ) {\n\t\t\tvar i = 0,\n\t\t\t\texpanded = {},\n\n\t\t\t\t// Assumes a single number if not a string\n\t\t\t\tparts = typeof value === \"string\" ? value.split( \" \" ) : [ value ];\n\n\t\t\tfor ( ; i < 4; i++ ) {\n\t\t\t\texpanded[ prefix + cssExpand[ i ] + suffix ] =\n\t\t\t\t\tparts[ i ] || parts[ i - 2 ] || parts[ 0 ];\n\t\t\t}\n\n\t\t\treturn expanded;\n\t\t}\n\t};\n\n\tif ( prefix !== \"margin\" ) {\n\t\tjQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber;\n\t}\n} );\n\njQuery.fn.extend( {\n\tcss: function( name, value ) {\n\t\treturn access( this, function( elem, name, value ) {\n\t\t\tvar styles, len,\n\t\t\t\tmap = {},\n\t\t\t\ti = 0;\n\n\t\t\tif ( Array.isArray( name ) ) {\n\t\t\t\tstyles = getStyles( elem );\n\t\t\t\tlen = name.length;\n\n\t\t\t\tfor ( ; i < len; i++ ) {\n\t\t\t\t\tmap[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles );\n\t\t\t\t}\n\n\t\t\t\treturn map;\n\t\t\t}\n\n\t\t\treturn value !== undefined ?\n\t\t\t\tjQuery.style( elem, name, value ) :\n\t\t\t\tjQuery.css( elem, name );\n\t\t}, name, value, arguments.length > 1 );\n\t}\n} );\n\nfunction Tween( elem, options, prop, end, easing ) {\n\treturn new Tween.prototype.init( elem, options, prop, end, easing );\n}\njQuery.Tween = Tween;\n\nTween.prototype = {\n\tconstructor: Tween,\n\tinit: function( elem, options, prop, end, easing, unit ) {\n\t\tthis.elem = elem;\n\t\tthis.prop = prop;\n\t\tthis.easing = easing || jQuery.easing._default;\n\t\tthis.options = options;\n\t\tthis.start = this.now = this.cur();\n\t\tthis.end = end;\n\t\tthis.unit = unit || ( isAutoPx( prop ) ? \"px\" : \"\" );\n\t},\n\tcur: function() {\n\t\tvar hooks = Tween.propHooks[ this.prop ];\n\n\t\treturn hooks && hooks.get ?\n\t\t\thooks.get( this ) :\n\t\t\tTween.propHooks._default.get( this );\n\t},\n\trun: function( percent ) {\n\t\tvar eased,\n\t\t\thooks = Tween.propHooks[ this.prop ];\n\n\t\tif ( this.options.duration ) {\n\t\t\tthis.pos = eased = jQuery.easing[ this.easing ](\n\t\t\t\tpercent, this.options.duration * percent, 0, 1, this.options.duration\n\t\t\t);\n\t\t} else {\n\t\t\tthis.pos = eased = percent;\n\t\t}\n\t\tthis.now = ( this.end - this.start ) * eased + this.start;\n\n\t\tif ( this.options.step ) {\n\t\t\tthis.options.step.call( this.elem, this.now, this );\n\t\t}\n\n\t\tif ( hooks && hooks.set ) {\n\t\t\thooks.set( this );\n\t\t} else {\n\t\t\tTween.propHooks._default.set( this );\n\t\t}\n\t\treturn this;\n\t}\n};\n\nTween.prototype.init.prototype = Tween.prototype;\n\nTween.propHooks = {\n\t_default: {\n\t\tget: function( tween ) {\n\t\t\tvar result;\n\n\t\t\t// Use a property on the element directly when it is not a DOM element,\n\t\t\t// or when there is no matching style property that exists.\n\t\t\tif ( tween.elem.nodeType !== 1 ||\n\t\t\t\ttween.elem[ tween.prop ] != null && tween.elem.style[ tween.prop ] == null ) {\n\t\t\t\treturn tween.elem[ tween.prop ];\n\t\t\t}\n\n\t\t\t// Passing an empty string as a 3rd parameter to .css will automatically\n\t\t\t// attempt a parseFloat and fallback to a string if the parse fails.\n\t\t\t// Simple values such as \"10px\" are parsed to Float;\n\t\t\t// complex values such as \"rotate(1rad)\" are returned as-is.\n\t\t\tresult = jQuery.css( tween.elem, tween.prop, \"\" );\n\n\t\t\t// Empty strings, null, undefined and \"auto\" are converted to 0.\n\t\t\treturn !result || result === \"auto\" ? 0 : result;\n\t\t},\n\t\tset: function( tween ) {\n\n\t\t\t// Use step hook for back compat.\n\t\t\t// Use cssHook if its there.\n\t\t\t// Use .style if available and use plain properties where available.\n\t\t\tif ( jQuery.fx.step[ tween.prop ] ) {\n\t\t\t\tjQuery.fx.step[ tween.prop ]( tween );\n\t\t\t} else if ( tween.elem.nodeType === 1 && (\n\t\t\t\tjQuery.cssHooks[ tween.prop ] ||\n\t\t\t\t\ttween.elem.style[ finalPropName( tween.prop ) ] != null ) ) {\n\t\t\t\tjQuery.style( tween.elem, tween.prop, tween.now + tween.unit );\n\t\t\t} else {\n\t\t\t\ttween.elem[ tween.prop ] = tween.now;\n\t\t\t}\n\t\t}\n\t}\n};\n\njQuery.easing = {\n\tlinear: function( p ) {\n\t\treturn p;\n\t},\n\tswing: function( p ) {\n\t\treturn 0.5 - Math.cos( p * Math.PI ) / 2;\n\t},\n\t_default: \"swing\"\n};\n\njQuery.fx = Tween.prototype.init;\n\n// Back compat <1.8 extension point\njQuery.fx.step = {};\n\nvar\n\tfxNow, inProgress,\n\trfxtypes = /^(?:toggle|show|hide)$/,\n\trrun = /queueHooks$/;\n\nfunction schedule() {\n\tif ( inProgress ) {\n\t\tif ( document$1.hidden === false && window.requestAnimationFrame ) {\n\t\t\twindow.requestAnimationFrame( schedule );\n\t\t} else {\n\t\t\twindow.setTimeout( schedule, 13 );\n\t\t}\n\n\t\tjQuery.fx.tick();\n\t}\n}\n\n// Animations created synchronously will run synchronously\nfunction createFxNow() {\n\twindow.setTimeout( function() {\n\t\tfxNow = undefined;\n\t} );\n\treturn ( fxNow = Date.now() );\n}\n\n// Generate parameters to create a standard animation\nfunction genFx( type, includeWidth ) {\n\tvar which,\n\t\ti = 0,\n\t\tattrs = { height: type };\n\n\t// If we include width, step value is 1 to do all cssExpand values,\n\t// otherwise step value is 2 to skip over Left and Right\n\tincludeWidth = includeWidth ? 1 : 0;\n\tfor ( ; i < 4; i += 2 - includeWidth ) {\n\t\twhich = cssExpand[ i ];\n\t\tattrs[ \"margin\" + which ] = attrs[ \"padding\" + which ] = type;\n\t}\n\n\tif ( includeWidth ) {\n\t\tattrs.opacity = attrs.width = type;\n\t}\n\n\treturn attrs;\n}\n\nfunction createTween( value, prop, animation ) {\n\tvar tween,\n\t\tcollection = ( Animation.tweeners[ prop ] || [] ).concat( Animation.tweeners[ \"*\" ] ),\n\t\tindex = 0,\n\t\tlength = collection.length;\n\tfor ( ; index < length; index++ ) {\n\t\tif ( ( tween = collection[ index ].call( animation, prop, value ) ) ) {\n\n\t\t\t// We're done with this property\n\t\t\treturn tween;\n\t\t}\n\t}\n}\n\nfunction defaultPrefilter( elem, props, opts ) {\n\tvar prop, value, toggle, hooks, oldfire, propTween, restoreDisplay, display,\n\t\tisBox = \"width\" in props || \"height\" in props,\n\t\tanim = this,\n\t\torig = {},\n\t\tstyle = elem.style,\n\t\thidden = elem.nodeType && isHiddenWithinTree( elem ),\n\t\tdataShow = dataPriv.get( elem, \"fxshow\" );\n\n\t// Queue-skipping animations hijack the fx hooks\n\tif ( !opts.queue ) {\n\t\thooks = jQuery._queueHooks( elem, \"fx\" );\n\t\tif ( hooks.unqueued == null ) {\n\t\t\thooks.unqueued = 0;\n\t\t\toldfire = hooks.empty.fire;\n\t\t\thooks.empty.fire = function() {\n\t\t\t\tif ( !hooks.unqueued ) {\n\t\t\t\t\toldfire();\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\t\thooks.unqueued++;\n\n\t\tanim.always( function() {\n\n\t\t\t// Ensure the complete handler is called before this completes\n\t\t\tanim.always( function() {\n\t\t\t\thooks.unqueued--;\n\t\t\t\tif ( !jQuery.queue( elem, \"fx\" ).length ) {\n\t\t\t\t\thooks.empty.fire();\n\t\t\t\t}\n\t\t\t} );\n\t\t} );\n\t}\n\n\t// Detect show/hide animations\n\tfor ( prop in props ) {\n\t\tvalue = props[ prop ];\n\t\tif ( rfxtypes.test( value ) ) {\n\t\t\tdelete props[ prop ];\n\t\t\ttoggle = toggle || value === \"toggle\";\n\t\t\tif ( value === ( hidden ? \"hide\" : \"show\" ) ) {\n\n\t\t\t\t// Pretend to be hidden if this is a \"show\" and\n\t\t\t\t// there is still data from a stopped show/hide\n\t\t\t\tif ( value === \"show\" && dataShow && dataShow[ prop ] !== undefined ) {\n\t\t\t\t\thidden = true;\n\n\t\t\t\t// Ignore all other no-op show/hide data\n\t\t\t\t} else {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\t\t\torig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop );\n\t\t}\n\t}\n\n\t// Bail out if this is a no-op like .hide().hide()\n\tpropTween = !jQuery.isEmptyObject( props );\n\tif ( !propTween && jQuery.isEmptyObject( orig ) ) {\n\t\treturn;\n\t}\n\n\t// Restrict \"overflow\" and \"display\" styles during box animations\n\tif ( isBox && elem.nodeType === 1 ) {\n\n\t\t// Support: IE <=9 - 11+\n\t\t// Record all 3 overflow attributes because IE does not infer the shorthand\n\t\t// from identically-valued overflowX and overflowY.\n\t\topts.overflow = [ style.overflow, style.overflowX, style.overflowY ];\n\n\t\t// Identify a display type, preferring old show/hide data over the CSS cascade\n\t\trestoreDisplay = dataShow && dataShow.display;\n\t\tif ( restoreDisplay == null ) {\n\t\t\trestoreDisplay = dataPriv.get( elem, \"display\" );\n\t\t}\n\t\tdisplay = jQuery.css( elem, \"display\" );\n\t\tif ( display === \"none\" ) {\n\t\t\tif ( restoreDisplay ) {\n\t\t\t\tdisplay = restoreDisplay;\n\t\t\t} else {\n\n\t\t\t\t// Get nonempty value(s) by temporarily forcing visibility\n\t\t\t\tshowHide( [ elem ], true );\n\t\t\t\trestoreDisplay = elem.style.display || restoreDisplay;\n\t\t\t\tdisplay = jQuery.css( elem, \"display\" );\n\t\t\t\tshowHide( [ elem ] );\n\t\t\t}\n\t\t}\n\n\t\t// Animate inline elements as inline-block\n\t\tif ( display === \"inline\" || display === \"inline-block\" && restoreDisplay != null ) {\n\t\t\tif ( jQuery.css( elem, \"float\" ) === \"none\" ) {\n\n\t\t\t\t// Restore the original display value at the end of pure show/hide animations\n\t\t\t\tif ( !propTween ) {\n\t\t\t\t\tanim.done( function() {\n\t\t\t\t\t\tstyle.display = restoreDisplay;\n\t\t\t\t\t} );\n\t\t\t\t\tif ( restoreDisplay == null ) {\n\t\t\t\t\t\tdisplay = style.display;\n\t\t\t\t\t\trestoreDisplay = display === \"none\" ? \"\" : display;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tstyle.display = \"inline-block\";\n\t\t\t}\n\t\t}\n\t}\n\n\tif ( opts.overflow ) {\n\t\tstyle.overflow = \"hidden\";\n\t\tanim.always( function() {\n\t\t\tstyle.overflow = opts.overflow[ 0 ];\n\t\t\tstyle.overflowX = opts.overflow[ 1 ];\n\t\t\tstyle.overflowY = opts.overflow[ 2 ];\n\t\t} );\n\t}\n\n\t// Implement show/hide animations\n\tpropTween = false;\n\tfor ( prop in orig ) {\n\n\t\t// General show/hide setup for this element animation\n\t\tif ( !propTween ) {\n\t\t\tif ( dataShow ) {\n\t\t\t\tif ( \"hidden\" in dataShow ) {\n\t\t\t\t\thidden = dataShow.hidden;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tdataShow = dataPriv.set( elem, \"fxshow\", { display: restoreDisplay } );\n\t\t\t}\n\n\t\t\t// Store hidden/visible for toggle so `.stop().toggle()` \"reverses\"\n\t\t\tif ( toggle ) {\n\t\t\t\tdataShow.hidden = !hidden;\n\t\t\t}\n\n\t\t\t// Show elements before animating them\n\t\t\tif ( hidden ) {\n\t\t\t\tshowHide( [ elem ], true );\n\t\t\t}\n\n\t\t\t// eslint-disable-next-line no-loop-func\n\t\t\tanim.done( function() {\n\n\t\t\t\t// The final step of a \"hide\" animation is actually hiding the element\n\t\t\t\tif ( !hidden ) {\n\t\t\t\t\tshowHide( [ elem ] );\n\t\t\t\t}\n\t\t\t\tdataPriv.remove( elem, \"fxshow\" );\n\t\t\t\tfor ( prop in orig ) {\n\t\t\t\t\tjQuery.style( elem, prop, orig[ prop ] );\n\t\t\t\t}\n\t\t\t} );\n\t\t}\n\n\t\t// Per-property setup\n\t\tpropTween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim );\n\t\tif ( !( prop in dataShow ) ) {\n\t\t\tdataShow[ prop ] = propTween.start;\n\t\t\tif ( hidden ) {\n\t\t\t\tpropTween.end = propTween.start;\n\t\t\t\tpropTween.start = 0;\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunction propFilter( props, specialEasing ) {\n\tvar index, name, easing, value, hooks;\n\n\t// camelCase, specialEasing and expand cssHook pass\n\tfor ( index in props ) {\n\t\tname = cssCamelCase( index );\n\t\teasing = specialEasing[ name ];\n\t\tvalue = props[ index ];\n\t\tif ( Array.isArray( value ) ) {\n\t\t\teasing = value[ 1 ];\n\t\t\tvalue = props[ index ] = value[ 0 ];\n\t\t}\n\n\t\tif ( index !== name ) {\n\t\t\tprops[ name ] = value;\n\t\t\tdelete props[ index ];\n\t\t}\n\n\t\thooks = jQuery.cssHooks[ name ];\n\t\tif ( hooks && \"expand\" in hooks ) {\n\t\t\tvalue = hooks.expand( value );\n\t\t\tdelete props[ name ];\n\n\t\t\t// Not quite $.extend, this won't overwrite existing keys.\n\t\t\t// Reusing 'index' because we have the correct \"name\"\n\t\t\tfor ( index in value ) {\n\t\t\t\tif ( !( index in props ) ) {\n\t\t\t\t\tprops[ index ] = value[ index ];\n\t\t\t\t\tspecialEasing[ index ] = easing;\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tspecialEasing[ name ] = easing;\n\t\t}\n\t}\n}\n\nfunction Animation( elem, properties, options ) {\n\tvar result,\n\t\tstopped,\n\t\tindex = 0,\n\t\tlength = Animation.prefilters.length,\n\t\tdeferred = jQuery.Deferred().always( function() {\n\n\t\t\t// Don't match elem in the :animated selector\n\t\t\tdelete tick.elem;\n\t\t} ),\n\t\ttick = function() {\n\t\t\tif ( stopped ) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tvar currentTime = fxNow || createFxNow(),\n\t\t\t\tremaining = Math.max( 0, animation.startTime + animation.duration - currentTime ),\n\n\t\t\t\tpercent = 1 - ( remaining / animation.duration || 0 ),\n\t\t\t\tindex = 0,\n\t\t\t\tlength = animation.tweens.length;\n\n\t\t\tfor ( ; index < length; index++ ) {\n\t\t\t\tanimation.tweens[ index ].run( percent );\n\t\t\t}\n\n\t\t\tdeferred.notifyWith( elem, [ animation, percent, remaining ] );\n\n\t\t\t// If there's more to do, yield\n\t\t\tif ( percent < 1 && length ) {\n\t\t\t\treturn remaining;\n\t\t\t}\n\n\t\t\t// If this was an empty animation, synthesize a final progress notification\n\t\t\tif ( !length ) {\n\t\t\t\tdeferred.notifyWith( elem, [ animation, 1, 0 ] );\n\t\t\t}\n\n\t\t\t// Resolve the animation and report its conclusion\n\t\t\tdeferred.resolveWith( elem, [ animation ] );\n\t\t\treturn false;\n\t\t},\n\t\tanimation = deferred.promise( {\n\t\t\telem: elem,\n\t\t\tprops: jQuery.extend( {}, properties ),\n\t\t\topts: jQuery.extend( true, {\n\t\t\t\tspecialEasing: {},\n\t\t\t\teasing: jQuery.easing._default\n\t\t\t}, options ),\n\t\t\toriginalProperties: properties,\n\t\t\toriginalOptions: options,\n\t\t\tstartTime: fxNow || createFxNow(),\n\t\t\tduration: options.duration,\n\t\t\ttweens: [],\n\t\t\tcreateTween: function( prop, end ) {\n\t\t\t\tvar tween = jQuery.Tween( elem, animation.opts, prop, end,\n\t\t\t\t\tanimation.opts.specialEasing[ prop ] || animation.opts.easing );\n\t\t\t\tanimation.tweens.push( tween );\n\t\t\t\treturn tween;\n\t\t\t},\n\t\t\tstop: function( gotoEnd ) {\n\t\t\t\tvar index = 0,\n\n\t\t\t\t\t// If we are going to the end, we want to run all the tweens\n\t\t\t\t\t// otherwise we skip this part\n\t\t\t\t\tlength = gotoEnd ? animation.tweens.length : 0;\n\t\t\t\tif ( stopped ) {\n\t\t\t\t\treturn this;\n\t\t\t\t}\n\t\t\t\tstopped = true;\n\t\t\t\tfor ( ; index < length; index++ ) {\n\t\t\t\t\tanimation.tweens[ index ].run( 1 );\n\t\t\t\t}\n\n\t\t\t\t// Resolve when we played the last frame; otherwise, reject\n\t\t\t\tif ( gotoEnd ) {\n\t\t\t\t\tdeferred.notifyWith( elem, [ animation, 1, 0 ] );\n\t\t\t\t\tdeferred.resolveWith( elem, [ animation, gotoEnd ] );\n\t\t\t\t} else {\n\t\t\t\t\tdeferred.rejectWith( elem, [ animation, gotoEnd ] );\n\t\t\t\t}\n\t\t\t\treturn this;\n\t\t\t}\n\t\t} ),\n\t\tprops = animation.props;\n\n\tpropFilter( props, animation.opts.specialEasing );\n\n\tfor ( ; index < length; index++ ) {\n\t\tresult = Animation.prefilters[ index ].call( animation, elem, props, animation.opts );\n\t\tif ( result ) {\n\t\t\tif ( typeof result.stop === \"function\" ) {\n\t\t\t\tjQuery._queueHooks( animation.elem, animation.opts.queue ).stop =\n\t\t\t\t\tresult.stop.bind( result );\n\t\t\t}\n\t\t\treturn result;\n\t\t}\n\t}\n\n\tjQuery.map( props, createTween, animation );\n\n\tif ( typeof animation.opts.start === \"function\" ) {\n\t\tanimation.opts.start.call( elem, animation );\n\t}\n\n\t// Attach callbacks from options\n\tanimation\n\t\t.progress( animation.opts.progress )\n\t\t.done( animation.opts.done, animation.opts.complete )\n\t\t.fail( animation.opts.fail )\n\t\t.always( animation.opts.always );\n\n\tjQuery.fx.timer(\n\t\tjQuery.extend( tick, {\n\t\t\telem: elem,\n\t\t\tanim: animation,\n\t\t\tqueue: animation.opts.queue\n\t\t} )\n\t);\n\n\treturn animation;\n}\n\njQuery.Animation = jQuery.extend( Animation, {\n\n\ttweeners: {\n\t\t\"*\": [ function( prop, value ) {\n\t\t\tvar tween = this.createTween( prop, value );\n\t\t\tadjustCSS( tween.elem, prop, rcssNum.exec( value ), tween );\n\t\t\treturn tween;\n\t\t} ]\n\t},\n\n\ttweener: function( props, callback ) {\n\t\tif ( typeof props === \"function\" ) {\n\t\t\tcallback = props;\n\t\t\tprops = [ \"*\" ];\n\t\t} else {\n\t\t\tprops = props.match( rnothtmlwhite );\n\t\t}\n\n\t\tvar prop,\n\t\t\tindex = 0,\n\t\t\tlength = props.length;\n\n\t\tfor ( ; index < length; index++ ) {\n\t\t\tprop = props[ index ];\n\t\t\tAnimation.tweeners[ prop ] = Animation.tweeners[ prop ] || [];\n\t\t\tAnimation.tweeners[ prop ].unshift( callback );\n\t\t}\n\t},\n\n\tprefilters: [ defaultPrefilter ],\n\n\tprefilter: function( callback, prepend ) {\n\t\tif ( prepend ) {\n\t\t\tAnimation.prefilters.unshift( callback );\n\t\t} else {\n\t\t\tAnimation.prefilters.push( callback );\n\t\t}\n\t}\n} );\n\njQuery.speed = function( speed, easing, fn ) {\n\tvar opt = speed && typeof speed === \"object\" ? jQuery.extend( {}, speed ) : {\n\t\tcomplete: fn || easing ||\n\t\t\ttypeof speed === \"function\" && speed,\n\t\tduration: speed,\n\t\teasing: fn && easing || easing && typeof easing !== \"function\" && easing\n\t};\n\n\t// Go to the end state if fx are off\n\tif ( jQuery.fx.off ) {\n\t\topt.duration = 0;\n\n\t} else {\n\t\tif ( typeof opt.duration !== \"number\" ) {\n\t\t\tif ( opt.duration in jQuery.fx.speeds ) {\n\t\t\t\topt.duration = jQuery.fx.speeds[ opt.duration ];\n\n\t\t\t} else {\n\t\t\t\topt.duration = jQuery.fx.speeds._default;\n\t\t\t}\n\t\t}\n\t}\n\n\t// Normalize opt.queue - true/undefined/null -> \"fx\"\n\tif ( opt.queue == null || opt.queue === true ) {\n\t\topt.queue = \"fx\";\n\t}\n\n\t// Queueing\n\topt.old = opt.complete;\n\n\topt.complete = function() {\n\t\tif ( typeof opt.old === \"function\" ) {\n\t\t\topt.old.call( this );\n\t\t}\n\n\t\tif ( opt.queue ) {\n\t\t\tjQuery.dequeue( this, opt.queue );\n\t\t}\n\t};\n\n\treturn opt;\n};\n\njQuery.fn.extend( {\n\tfadeTo: function( speed, to, easing, callback ) {\n\n\t\t// Show any hidden elements after setting opacity to 0\n\t\treturn this.filter( isHiddenWithinTree ).css( \"opacity\", 0 ).show()\n\n\t\t\t// Animate to the value specified\n\t\t\t.end().animate( { opacity: to }, speed, easing, callback );\n\t},\n\tanimate: function( prop, speed, easing, callback ) {\n\t\tvar empty = jQuery.isEmptyObject( prop ),\n\t\t\toptall = jQuery.speed( speed, easing, callback ),\n\t\t\tdoAnimation = function() {\n\n\t\t\t\t// Operate on a copy of prop so per-property easing won't be lost\n\t\t\t\tvar anim = Animation( this, jQuery.extend( {}, prop ), optall );\n\n\t\t\t\t// Empty animations, or finishing resolves immediately\n\t\t\t\tif ( empty || dataPriv.get( this, \"finish\" ) ) {\n\t\t\t\t\tanim.stop( true );\n\t\t\t\t}\n\t\t\t};\n\n\t\tdoAnimation.finish = doAnimation;\n\n\t\treturn empty || optall.queue === false ?\n\t\t\tthis.each( doAnimation ) :\n\t\t\tthis.queue( optall.queue, doAnimation );\n\t},\n\tstop: function( type, clearQueue, gotoEnd ) {\n\t\tvar stopQueue = function( hooks ) {\n\t\t\tvar stop = hooks.stop;\n\t\t\tdelete hooks.stop;\n\t\t\tstop( gotoEnd );\n\t\t};\n\n\t\tif ( typeof type !== \"string\" ) {\n\t\t\tgotoEnd = clearQueue;\n\t\t\tclearQueue = type;\n\t\t\ttype = undefined;\n\t\t}\n\t\tif ( clearQueue ) {\n\t\t\tthis.queue( type || \"fx\", [] );\n\t\t}\n\n\t\treturn this.each( function() {\n\t\t\tvar dequeue = true,\n\t\t\t\tindex = type != null && type + \"queueHooks\",\n\t\t\t\ttimers = jQuery.timers,\n\t\t\t\tdata = dataPriv.get( this );\n\n\t\t\tif ( index ) {\n\t\t\t\tif ( data[ index ] && data[ index ].stop ) {\n\t\t\t\t\tstopQueue( data[ index ] );\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tfor ( index in data ) {\n\t\t\t\t\tif ( data[ index ] && data[ index ].stop && rrun.test( index ) ) {\n\t\t\t\t\t\tstopQueue( data[ index ] );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfor ( index = timers.length; index--; ) {\n\t\t\t\tif ( timers[ index ].elem === this &&\n\t\t\t\t\t( type == null || timers[ index ].queue === type ) ) {\n\n\t\t\t\t\ttimers[ index ].anim.stop( gotoEnd );\n\t\t\t\t\tdequeue = false;\n\t\t\t\t\ttimers.splice( index, 1 );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Start the next in the queue if the last step wasn't forced.\n\t\t\t// Timers currently will call their complete callbacks, which\n\t\t\t// will dequeue but only if they were gotoEnd.\n\t\t\tif ( dequeue || !gotoEnd ) {\n\t\t\t\tjQuery.dequeue( this, type );\n\t\t\t}\n\t\t} );\n\t},\n\tfinish: function( type ) {\n\t\tif ( type !== false ) {\n\t\t\ttype = type || \"fx\";\n\t\t}\n\t\treturn this.each( function() {\n\t\t\tvar index,\n\t\t\t\tdata = dataPriv.get( this ),\n\t\t\t\tqueue = data[ type + \"queue\" ],\n\t\t\t\thooks = data[ type + \"queueHooks\" ],\n\t\t\t\ttimers = jQuery.timers,\n\t\t\t\tlength = queue ? queue.length : 0;\n\n\t\t\t// Enable finishing flag on private data\n\t\t\tdata.finish = true;\n\n\t\t\t// Empty the queue first\n\t\t\tjQuery.queue( this, type, [] );\n\n\t\t\tif ( hooks && hooks.stop ) {\n\t\t\t\thooks.stop.call( this, true );\n\t\t\t}\n\n\t\t\t// Look for any active animations, and finish them\n\t\t\tfor ( index = timers.length; index--; ) {\n\t\t\t\tif ( timers[ index ].elem === this && timers[ index ].queue === type ) {\n\t\t\t\t\ttimers[ index ].anim.stop( true );\n\t\t\t\t\ttimers.splice( index, 1 );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Look for any animations in the old queue and finish them\n\t\t\tfor ( index = 0; index < length; index++ ) {\n\t\t\t\tif ( queue[ index ] && queue[ index ].finish ) {\n\t\t\t\t\tqueue[ index ].finish.call( this );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Turn off finishing flag\n\t\t\tdelete data.finish;\n\t\t} );\n\t}\n} );\n\njQuery.each( [ \"toggle\", \"show\", \"hide\" ], function( _i, name ) {\n\tvar cssFn = jQuery.fn[ name ];\n\tjQuery.fn[ name ] = function( speed, easing, callback ) {\n\t\treturn speed == null || typeof speed === \"boolean\" ?\n\t\t\tcssFn.apply( this, arguments ) :\n\t\t\tthis.animate( genFx( name, true ), speed, easing, callback );\n\t};\n} );\n\n// Generate shortcuts for custom animations\njQuery.each( {\n\tslideDown: genFx( \"show\" ),\n\tslideUp: genFx( \"hide\" ),\n\tslideToggle: genFx( \"toggle\" ),\n\tfadeIn: { opacity: \"show\" },\n\tfadeOut: { opacity: \"hide\" },\n\tfadeToggle: { opacity: \"toggle\" }\n}, function( name, props ) {\n\tjQuery.fn[ name ] = function( speed, easing, callback ) {\n\t\treturn this.animate( props, speed, easing, callback );\n\t};\n} );\n\njQuery.timers = [];\njQuery.fx.tick = function() {\n\tvar timer,\n\t\ti = 0,\n\t\ttimers = jQuery.timers;\n\n\tfxNow = Date.now();\n\n\tfor ( ; i < timers.length; i++ ) {\n\t\ttimer = timers[ i ];\n\n\t\t// Run the timer and safely remove it when done (allowing for external removal)\n\t\tif ( !timer() && timers[ i ] === timer ) {\n\t\t\ttimers.splice( i--, 1 );\n\t\t}\n\t}\n\n\tif ( !timers.length ) {\n\t\tjQuery.fx.stop();\n\t}\n\tfxNow = undefined;\n};\n\njQuery.fx.timer = function( timer ) {\n\tjQuery.timers.push( timer );\n\tjQuery.fx.start();\n};\n\njQuery.fx.start = function() {\n\tif ( inProgress ) {\n\t\treturn;\n\t}\n\n\tinProgress = true;\n\tschedule();\n};\n\njQuery.fx.stop = function() {\n\tinProgress = null;\n};\n\njQuery.fx.speeds = {\n\tslow: 600,\n\tfast: 200,\n\n\t// Default speed\n\t_default: 400\n};\n\n// Based off of the plugin by Clint Helfers, with permission.\njQuery.fn.delay = function( time, type ) {\n\ttime = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time;\n\ttype = type || \"fx\";\n\n\treturn this.queue( type, function( next, hooks ) {\n\t\tvar timeout = window.setTimeout( next, time );\n\t\thooks.stop = function() {\n\t\t\twindow.clearTimeout( timeout );\n\t\t};\n\t} );\n};\n\nvar rfocusable = /^(?:input|select|textarea|button)$/i,\n\trclickable = /^(?:a|area)$/i;\n\njQuery.fn.extend( {\n\tprop: function( name, value ) {\n\t\treturn access( this, jQuery.prop, name, value, arguments.length > 1 );\n\t},\n\n\tremoveProp: function( name ) {\n\t\treturn this.each( function() {\n\t\t\tdelete this[ jQuery.propFix[ name ] || name ];\n\t\t} );\n\t}\n} );\n\njQuery.extend( {\n\tprop: function( elem, name, value ) {\n\t\tvar ret, hooks,\n\t\t\tnType = elem.nodeType;\n\n\t\t// Don't get/set properties on text, comment and attribute nodes\n\t\tif ( nType === 3 || nType === 8 || nType === 2 ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) {\n\n\t\t\t// Fix name and attach hooks\n\t\t\tname = jQuery.propFix[ name ] || name;\n\t\t\thooks = jQuery.propHooks[ name ];\n\t\t}\n\n\t\tif ( value !== undefined ) {\n\t\t\tif ( hooks && \"set\" in hooks &&\n\t\t\t\t( ret = hooks.set( elem, value, name ) ) !== undefined ) {\n\t\t\t\treturn ret;\n\t\t\t}\n\n\t\t\treturn ( elem[ name ] = value );\n\t\t}\n\n\t\tif ( hooks && \"get\" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) {\n\t\t\treturn ret;\n\t\t}\n\n\t\treturn elem[ name ];\n\t},\n\n\tpropHooks: {\n\t\ttabIndex: {\n\t\t\tget: function( elem ) {\n\n\t\t\t\t// Support: IE <=9 - 11+\n\t\t\t\t// elem.tabIndex doesn't always return the\n\t\t\t\t// correct value when it hasn't been explicitly set\n\t\t\t\t// Use proper attribute retrieval (trac-12072)\n\t\t\t\tvar tabindex = elem.getAttribute( \"tabindex\" );\n\n\t\t\t\tif ( tabindex ) {\n\t\t\t\t\treturn parseInt( tabindex, 10 );\n\t\t\t\t}\n\n\t\t\t\tif (\n\t\t\t\t\trfocusable.test( elem.nodeName ) ||\n\n\t\t\t\t\t// href-less anchor's `tabIndex` property value is `0` and\n\t\t\t\t\t// the `tabindex` attribute value: `null`. We want `-1`.\n\t\t\t\t\trclickable.test( elem.nodeName ) && elem.href\n\t\t\t\t) {\n\t\t\t\t\treturn 0;\n\t\t\t\t}\n\n\t\t\t\treturn -1;\n\t\t\t}\n\t\t}\n\t},\n\n\tpropFix: {\n\t\t\"for\": \"htmlFor\",\n\t\t\"class\": \"className\"\n\t}\n} );\n\n// Support: IE <=11+\n// Accessing the selectedIndex property forces the browser to respect\n// setting selected on the option. The getter ensures a default option\n// is selected when in an optgroup. ESLint rule \"no-unused-expressions\"\n// is disabled for this code since it considers such accessions noop.\nif ( isIE ) {\n\tjQuery.propHooks.selected = {\n\t\tget: function( elem ) {\n\n\t\t\tvar parent = elem.parentNode;\n\t\t\tif ( parent && parent.parentNode ) {\n\t\t\t\t// eslint-disable-next-line no-unused-expressions\n\t\t\t\tparent.parentNode.selectedIndex;\n\t\t\t}\n\t\t\treturn null;\n\t\t},\n\t\tset: function( elem ) {\n\n\n\t\t\tvar parent = elem.parentNode;\n\t\t\tif ( parent ) {\n\t\t\t\t// eslint-disable-next-line no-unused-expressions\n\t\t\t\tparent.selectedIndex;\n\n\t\t\t\tif ( parent.parentNode ) {\n\t\t\t\t\t// eslint-disable-next-line no-unused-expressions\n\t\t\t\t\tparent.parentNode.selectedIndex;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t};\n}\n\njQuery.each( [\n\t\"tabIndex\",\n\t\"readOnly\",\n\t\"maxLength\",\n\t\"cellSpacing\",\n\t\"cellPadding\",\n\t\"rowSpan\",\n\t\"colSpan\",\n\t\"useMap\",\n\t\"frameBorder\",\n\t\"contentEditable\"\n], function() {\n\tjQuery.propFix[ this.toLowerCase() ] = this;\n} );\n\n// Strip and collapse whitespace according to HTML spec\n// https://infra.spec.whatwg.org/#strip-and-collapse-ascii-whitespace\nfunction stripAndCollapse( value ) {\n\tvar tokens = value.match( rnothtmlwhite ) || [];\n\treturn tokens.join( \" \" );\n}\n\nfunction getClass( elem ) {\n\treturn elem.getAttribute && elem.getAttribute( \"class\" ) || \"\";\n}\n\nfunction classesToArray( value ) {\n\tif ( Array.isArray( value ) ) {\n\t\treturn value;\n\t}\n\tif ( typeof value === \"string\" ) {\n\t\treturn value.match( rnothtmlwhite ) || [];\n\t}\n\treturn [];\n}\n\njQuery.fn.extend( {\n\taddClass: function( value ) {\n\t\tvar classNames, cur, curValue, className, i, finalValue;\n\n\t\tif ( typeof value === \"function\" ) {\n\t\t\treturn this.each( function( j ) {\n\t\t\t\tjQuery( this ).addClass( value.call( this, j, getClass( this ) ) );\n\t\t\t} );\n\t\t}\n\n\t\tclassNames = classesToArray( value );\n\n\t\tif ( classNames.length ) {\n\t\t\treturn this.each( function() {\n\t\t\t\tcurValue = getClass( this );\n\t\t\t\tcur = this.nodeType === 1 && ( \" \" + stripAndCollapse( curValue ) + \" \" );\n\n\t\t\t\tif ( cur ) {\n\t\t\t\t\tfor ( i = 0; i < classNames.length; i++ ) {\n\t\t\t\t\t\tclassName = classNames[ i ];\n\t\t\t\t\t\tif ( cur.indexOf( \" \" + className + \" \" ) < 0 ) {\n\t\t\t\t\t\t\tcur += className + \" \";\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// Only assign if different to avoid unneeded rendering.\n\t\t\t\t\tfinalValue = stripAndCollapse( cur );\n\t\t\t\t\tif ( curValue !== finalValue ) {\n\t\t\t\t\t\tthis.setAttribute( \"class\", finalValue );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} );\n\t\t}\n\n\t\treturn this;\n\t},\n\n\tremoveClass: function( value ) {\n\t\tvar classNames, cur, curValue, className, i, finalValue;\n\n\t\tif ( typeof value === \"function\" ) {\n\t\t\treturn this.each( function( j ) {\n\t\t\t\tjQuery( this ).removeClass( value.call( this, j, getClass( this ) ) );\n\t\t\t} );\n\t\t}\n\n\t\tif ( !arguments.length ) {\n\t\t\treturn this.attr( \"class\", \"\" );\n\t\t}\n\n\t\tclassNames = classesToArray( value );\n\n\t\tif ( classNames.length ) {\n\t\t\treturn this.each( function() {\n\t\t\t\tcurValue = getClass( this );\n\n\t\t\t\t// This expression is here for better compressibility (see addClass)\n\t\t\t\tcur = this.nodeType === 1 && ( \" \" + stripAndCollapse( curValue ) + \" \" );\n\n\t\t\t\tif ( cur ) {\n\t\t\t\t\tfor ( i = 0; i < classNames.length; i++ ) {\n\t\t\t\t\t\tclassName = classNames[ i ];\n\n\t\t\t\t\t\t// Remove *all* instances\n\t\t\t\t\t\twhile ( cur.indexOf( \" \" + className + \" \" ) > -1 ) {\n\t\t\t\t\t\t\tcur = cur.replace( \" \" + className + \" \", \" \" );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// Only assign if different to avoid unneeded rendering.\n\t\t\t\t\tfinalValue = stripAndCollapse( cur );\n\t\t\t\t\tif ( curValue !== finalValue ) {\n\t\t\t\t\t\tthis.setAttribute( \"class\", finalValue );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} );\n\t\t}\n\n\t\treturn this;\n\t},\n\n\ttoggleClass: function( value, stateVal ) {\n\t\tvar classNames, className, i, self;\n\n\t\tif ( typeof value === \"function\" ) {\n\t\t\treturn this.each( function( i ) {\n\t\t\t\tjQuery( this ).toggleClass(\n\t\t\t\t\tvalue.call( this, i, getClass( this ), stateVal ),\n\t\t\t\t\tstateVal\n\t\t\t\t);\n\t\t\t} );\n\t\t}\n\n\t\tif ( typeof stateVal === \"boolean\" ) {\n\t\t\treturn stateVal ? this.addClass( value ) : this.removeClass( value );\n\t\t}\n\n\t\tclassNames = classesToArray( value );\n\n\t\tif ( classNames.length ) {\n\t\t\treturn this.each( function() {\n\n\t\t\t\t// Toggle individual class names\n\t\t\t\tself = jQuery( this );\n\n\t\t\t\tfor ( i = 0; i < classNames.length; i++ ) {\n\t\t\t\t\tclassName = classNames[ i ];\n\n\t\t\t\t\t// Check each className given, space separated list\n\t\t\t\t\tif ( self.hasClass( className ) ) {\n\t\t\t\t\t\tself.removeClass( className );\n\t\t\t\t\t} else {\n\t\t\t\t\t\tself.addClass( className );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} );\n\t\t}\n\n\t\treturn this;\n\t},\n\n\thasClass: function( selector ) {\n\t\tvar className, elem,\n\t\t\ti = 0;\n\n\t\tclassName = \" \" + selector + \" \";\n\t\twhile ( ( elem = this[ i++ ] ) ) {\n\t\t\tif ( elem.nodeType === 1 &&\n\t\t\t\t( \" \" + stripAndCollapse( getClass( elem ) ) + \" \" ).indexOf( className ) > -1 ) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\n\t\treturn false;\n\t}\n} );\n\njQuery.fn.extend( {\n\tval: function( value ) {\n\t\tvar hooks, ret, valueIsFunction,\n\t\t\telem = this[ 0 ];\n\n\t\tif ( !arguments.length ) {\n\t\t\tif ( elem ) {\n\t\t\t\thooks = jQuery.valHooks[ elem.type ] ||\n\t\t\t\t\tjQuery.valHooks[ elem.nodeName.toLowerCase() ];\n\n\t\t\t\tif ( hooks &&\n\t\t\t\t\t\"get\" in hooks &&\n\t\t\t\t\t( ret = hooks.get( elem, \"value\" ) ) !== undefined\n\t\t\t\t) {\n\t\t\t\t\treturn ret;\n\t\t\t\t}\n\n\t\t\t\tret = elem.value;\n\n\t\t\t\t// Handle cases where value is null/undef or number\n\t\t\t\treturn ret == null ? \"\" : ret;\n\t\t\t}\n\n\t\t\treturn;\n\t\t}\n\n\t\tvalueIsFunction = typeof value === \"function\";\n\n\t\treturn this.each( function( i ) {\n\t\t\tvar val;\n\n\t\t\tif ( this.nodeType !== 1 ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif ( valueIsFunction ) {\n\t\t\t\tval = value.call( this, i, jQuery( this ).val() );\n\t\t\t} else {\n\t\t\t\tval = value;\n\t\t\t}\n\n\t\t\t// Treat null/undefined as \"\"; convert numbers to string\n\t\t\tif ( val == null ) {\n\t\t\t\tval = \"\";\n\n\t\t\t} else if ( typeof val === \"number\" ) {\n\t\t\t\tval += \"\";\n\n\t\t\t} else if ( Array.isArray( val ) ) {\n\t\t\t\tval = jQuery.map( val, function( value ) {\n\t\t\t\t\treturn value == null ? \"\" : value + \"\";\n\t\t\t\t} );\n\t\t\t}\n\n\t\t\thooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ];\n\n\t\t\t// If set returns undefined, fall back to normal setting\n\t\t\tif ( !hooks || !( \"set\" in hooks ) || hooks.set( this, val, \"value\" ) === undefined ) {\n\t\t\t\tthis.value = val;\n\t\t\t}\n\t\t} );\n\t}\n} );\n\njQuery.extend( {\n\tvalHooks: {\n\t\tselect: {\n\t\t\tget: function( elem ) {\n\t\t\t\tvar value, option, i,\n\t\t\t\t\toptions = elem.options,\n\t\t\t\t\tindex = elem.selectedIndex,\n\t\t\t\t\tone = elem.type === \"select-one\",\n\t\t\t\t\tvalues = one ? null : [],\n\t\t\t\t\tmax = one ? index + 1 : options.length;\n\n\t\t\t\tif ( index < 0 ) {\n\t\t\t\t\ti = max;\n\n\t\t\t\t} else {\n\t\t\t\t\ti = one ? index : 0;\n\t\t\t\t}\n\n\t\t\t\t// Loop through all the selected options\n\t\t\t\tfor ( ; i < max; i++ ) {\n\t\t\t\t\toption = options[ i ];\n\n\t\t\t\t\tif ( option.selected &&\n\n\t\t\t\t\t\t\t// Don't return options that are disabled or in a disabled optgroup\n\t\t\t\t\t\t\t!option.disabled &&\n\t\t\t\t\t\t\t( !option.parentNode.disabled ||\n\t\t\t\t\t\t\t\t!nodeName( option.parentNode, \"optgroup\" ) ) ) {\n\n\t\t\t\t\t\t// Get the specific value for the option\n\t\t\t\t\t\tvalue = jQuery( option ).val();\n\n\t\t\t\t\t\t// We don't need an array for one selects\n\t\t\t\t\t\tif ( one ) {\n\t\t\t\t\t\t\treturn value;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Multi-Selects return an array\n\t\t\t\t\t\tvalues.push( value );\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn values;\n\t\t\t},\n\n\t\t\tset: function( elem, value ) {\n\t\t\t\tvar optionSet, option,\n\t\t\t\t\toptions = elem.options,\n\t\t\t\t\tvalues = jQuery.makeArray( value ),\n\t\t\t\t\ti = options.length;\n\n\t\t\t\twhile ( i-- ) {\n\t\t\t\t\toption = options[ i ];\n\n\t\t\t\t\tif ( ( option.selected =\n\t\t\t\t\t\tjQuery.inArray( jQuery( option ).val(), values ) > -1\n\t\t\t\t\t) ) {\n\t\t\t\t\t\toptionSet = true;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Force browsers to behave consistently when non-matching value is set\n\t\t\t\tif ( !optionSet ) {\n\t\t\t\t\telem.selectedIndex = -1;\n\t\t\t\t}\n\t\t\t\treturn values;\n\t\t\t}\n\t\t}\n\t}\n} );\n\nif ( isIE ) {\n\tjQuery.valHooks.option = {\n\t\tget: function( elem ) {\n\n\t\t\tvar val = elem.getAttribute( \"value\" );\n\t\t\treturn val != null ?\n\t\t\t\tval :\n\n\t\t\t\t// Support: IE <=10 - 11+\n\t\t\t\t// option.text throws exceptions (trac-14686, trac-14858)\n\t\t\t\t// Strip and collapse whitespace\n\t\t\t\t// https://html.spec.whatwg.org/#strip-and-collapse-whitespace\n\t\t\t\tstripAndCollapse( jQuery.text( elem ) );\n\t\t}\n\t};\n}\n\n// Radios and checkboxes getter/setter\njQuery.each( [ \"radio\", \"checkbox\" ], function() {\n\tjQuery.valHooks[ this ] = {\n\t\tset: function( elem, value ) {\n\t\t\tif ( Array.isArray( value ) ) {\n\t\t\t\treturn ( elem.checked = jQuery.inArray( jQuery( elem ).val(), value ) > -1 );\n\t\t\t}\n\t\t}\n\t};\n} );\n\nvar rfocusMorph = /^(?:focusinfocus|focusoutblur)$/,\n\tstopPropagationCallback = function( e ) {\n\t\te.stopPropagation();\n\t};\n\njQuery.extend( jQuery.event, {\n\n\ttrigger: function( event, data, elem, onlyHandlers ) {\n\n\t\tvar i, cur, tmp, bubbleType, ontype, handle, special, lastElement,\n\t\t\teventPath = [ elem || document$1 ],\n\t\t\ttype = hasOwn.call( event, \"type\" ) ? event.type : event,\n\t\t\tnamespaces = hasOwn.call( event, \"namespace\" ) ? event.namespace.split( \".\" ) : [];\n\n\t\tcur = lastElement = tmp = elem = elem || document$1;\n\n\t\t// Don't do events on text and comment nodes\n\t\tif ( elem.nodeType === 3 || elem.nodeType === 8 ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// focus/blur morphs to focusin/out; ensure we're not firing them right now\n\t\tif ( rfocusMorph.test( type + jQuery.event.triggered ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( type.indexOf( \".\" ) > -1 ) {\n\n\t\t\t// Namespaced trigger; create a regexp to match event type in handle()\n\t\t\tnamespaces = type.split( \".\" );\n\t\t\ttype = namespaces.shift();\n\t\t\tnamespaces.sort();\n\t\t}\n\t\tontype = type.indexOf( \":\" ) < 0 && \"on\" + type;\n\n\t\t// Caller can pass in a jQuery.Event object, Object, or just an event type string\n\t\tevent = event[ jQuery.expando ] ?\n\t\t\tevent :\n\t\t\tnew jQuery.Event( type, typeof event === \"object\" && event );\n\n\t\t// Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true)\n\t\tevent.isTrigger = onlyHandlers ? 2 : 3;\n\t\tevent.namespace = namespaces.join( \".\" );\n\t\tevent.rnamespace = event.namespace ?\n\t\t\tnew RegExp( \"(^|\\\\.)\" + namespaces.join( \"\\\\.(?:.*\\\\.|)\" ) + \"(\\\\.|$)\" ) :\n\t\t\tnull;\n\n\t\t// Clean up the event in case it is being reused\n\t\tevent.result = undefined;\n\t\tif ( !event.target ) {\n\t\t\tevent.target = elem;\n\t\t}\n\n\t\t// Clone any incoming data and prepend the event, creating the handler arg list\n\t\tdata = data == null ?\n\t\t\t[ event ] :\n\t\t\tjQuery.makeArray( data, [ event ] );\n\n\t\t// Allow special events to draw outside the lines\n\t\tspecial = jQuery.event.special[ type ] || {};\n\t\tif ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Determine event propagation path in advance, per W3C events spec (trac-9951)\n\t\t// Bubble up to document, then to window; watch for a global ownerDocument var (trac-9724)\n\t\tif ( !onlyHandlers && !special.noBubble && !isWindow( elem ) ) {\n\n\t\t\tbubbleType = special.delegateType || type;\n\t\t\tif ( !rfocusMorph.test( bubbleType + type ) ) {\n\t\t\t\tcur = cur.parentNode;\n\t\t\t}\n\t\t\tfor ( ; cur; cur = cur.parentNode ) {\n\t\t\t\teventPath.push( cur );\n\t\t\t\ttmp = cur;\n\t\t\t}\n\n\t\t\t// Only add window if we got to document (e.g., not plain obj or detached DOM)\n\t\t\tif ( tmp === ( elem.ownerDocument || document$1 ) ) {\n\t\t\t\teventPath.push( tmp.defaultView || tmp.parentWindow || window );\n\t\t\t}\n\t\t}\n\n\t\t// Fire handlers on the event path\n\t\ti = 0;\n\t\twhile ( ( cur = eventPath[ i++ ] ) && !event.isPropagationStopped() ) {\n\t\t\tlastElement = cur;\n\t\t\tevent.type = i > 1 ?\n\t\t\t\tbubbleType :\n\t\t\t\tspecial.bindType || type;\n\n\t\t\t// jQuery handler\n\t\t\thandle = ( dataPriv.get( cur, \"events\" ) || Object.create( null ) )[ event.type ] &&\n\t\t\t\tdataPriv.get( cur, \"handle\" );\n\t\t\tif ( handle ) {\n\t\t\t\thandle.apply( cur, data );\n\t\t\t}\n\n\t\t\t// Native handler\n\t\t\thandle = ontype && cur[ ontype ];\n\t\t\tif ( handle && handle.apply && acceptData( cur ) ) {\n\t\t\t\tevent.result = handle.apply( cur, data );\n\t\t\t\tif ( event.result === false ) {\n\t\t\t\t\tevent.preventDefault();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tevent.type = type;\n\n\t\t// If nobody prevented the default action, do it now\n\t\tif ( !onlyHandlers && !event.isDefaultPrevented() ) {\n\n\t\t\tif ( ( !special._default ||\n\t\t\t\tspecial._default.apply( eventPath.pop(), data ) === false ) &&\n\t\t\t\tacceptData( elem ) ) {\n\n\t\t\t\t// Call a native DOM method on the target with the same name as the event.\n\t\t\t\t// Don't do default actions on window, that's where global variables be (trac-6170)\n\t\t\t\tif ( ontype && typeof elem[ type ] === \"function\" && !isWindow( elem ) ) {\n\n\t\t\t\t\t// Don't re-trigger an onFOO event when we call its FOO() method\n\t\t\t\t\ttmp = elem[ ontype ];\n\n\t\t\t\t\tif ( tmp ) {\n\t\t\t\t\t\telem[ ontype ] = null;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Prevent re-triggering of the same event, since we already bubbled it above\n\t\t\t\t\tjQuery.event.triggered = type;\n\n\t\t\t\t\tif ( event.isPropagationStopped() ) {\n\t\t\t\t\t\tlastElement.addEventListener( type, stopPropagationCallback );\n\t\t\t\t\t}\n\n\t\t\t\t\telem[ type ]();\n\n\t\t\t\t\tif ( event.isPropagationStopped() ) {\n\t\t\t\t\t\tlastElement.removeEventListener( type, stopPropagationCallback );\n\t\t\t\t\t}\n\n\t\t\t\t\tjQuery.event.triggered = undefined;\n\n\t\t\t\t\tif ( tmp ) {\n\t\t\t\t\t\telem[ ontype ] = tmp;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn event.result;\n\t},\n\n\t// Piggyback on a donor event to simulate a different one\n\t// Used only for `focus(in | out)` events\n\tsimulate: function( type, elem, event ) {\n\t\tvar e = jQuery.extend(\n\t\t\tnew jQuery.Event(),\n\t\t\tevent,\n\t\t\t{\n\t\t\t\ttype: type,\n\t\t\t\tisSimulated: true\n\t\t\t}\n\t\t);\n\n\t\tjQuery.event.trigger( e, null, elem );\n\t}\n\n} );\n\njQuery.fn.extend( {\n\n\ttrigger: function( type, data ) {\n\t\treturn this.each( function() {\n\t\t\tjQuery.event.trigger( type, data, this );\n\t\t} );\n\t},\n\ttriggerHandler: function( type, data ) {\n\t\tvar elem = this[ 0 ];\n\t\tif ( elem ) {\n\t\t\treturn jQuery.event.trigger( type, data, elem, true );\n\t\t}\n\t}\n} );\n\nvar location = window.location;\n\nvar nonce = { guid: Date.now() };\n\nvar rquery = /\\?/;\n\n// Cross-browser xml parsing\njQuery.parseXML = function( data ) {\n\tvar xml, parserErrorElem;\n\tif ( !data || typeof data !== \"string\" ) {\n\t\treturn null;\n\t}\n\n\t// Support: IE 9 - 11+\n\t// IE throws on parseFromString with invalid input.\n\ttry {\n\t\txml = ( new window.DOMParser() ).parseFromString( data, \"text/xml\" );\n\t} catch ( e ) {}\n\n\tparserErrorElem = xml && xml.getElementsByTagName( \"parsererror\" )[ 0 ];\n\tif ( !xml || parserErrorElem ) {\n\t\tjQuery.error( \"Invalid XML: \" + (\n\t\t\tparserErrorElem ?\n\t\t\t\tjQuery.map( parserErrorElem.childNodes, function( el ) {\n\t\t\t\t\treturn el.textContent;\n\t\t\t\t} ).join( \"\\n\" ) :\n\t\t\t\tdata\n\t\t) );\n\t}\n\treturn xml;\n};\n\nvar\n\trbracket = /\\[\\]$/,\n\trCRLF = /\\r?\\n/g,\n\trsubmitterTypes = /^(?:submit|button|image|reset|file)$/i,\n\trsubmittable = /^(?:input|select|textarea|keygen)/i;\n\nfunction buildParams( prefix, obj, traditional, add ) {\n\tvar name;\n\n\tif ( Array.isArray( obj ) ) {\n\n\t\t// Serialize array item.\n\t\tjQuery.each( obj, function( i, v ) {\n\t\t\tif ( traditional || rbracket.test( prefix ) ) {\n\n\t\t\t\t// Treat each array item as a scalar.\n\t\t\t\tadd( prefix, v );\n\n\t\t\t} else {\n\n\t\t\t\t// Item is non-scalar (array or object), encode its numeric index.\n\t\t\t\tbuildParams(\n\t\t\t\t\tprefix + \"[\" + ( typeof v === \"object\" && v != null ? i : \"\" ) + \"]\",\n\t\t\t\t\tv,\n\t\t\t\t\ttraditional,\n\t\t\t\t\tadd\n\t\t\t\t);\n\t\t\t}\n\t\t} );\n\n\t} else if ( !traditional && toType( obj ) === \"object\" ) {\n\n\t\t// Serialize object item.\n\t\tfor ( name in obj ) {\n\t\t\tbuildParams( prefix + \"[\" + name + \"]\", obj[ name ], traditional, add );\n\t\t}\n\n\t} else {\n\n\t\t// Serialize scalar item.\n\t\tadd( prefix, obj );\n\t}\n}\n\n// Serialize an array of form elements or a set of\n// key/values into a query string\njQuery.param = function( a, traditional ) {\n\tvar prefix,\n\t\ts = [],\n\t\tadd = function( key, valueOrFunction ) {\n\n\t\t\t// If value is a function, invoke it and use its return value\n\t\t\tvar value = typeof valueOrFunction === \"function\" ?\n\t\t\t\tvalueOrFunction() :\n\t\t\t\tvalueOrFunction;\n\n\t\t\ts[ s.length ] = encodeURIComponent( key ) + \"=\" +\n\t\t\t\tencodeURIComponent( value == null ? \"\" : value );\n\t\t};\n\n\tif ( a == null ) {\n\t\treturn \"\";\n\t}\n\n\t// If an array was passed in, assume that it is an array of form elements.\n\tif ( Array.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) {\n\n\t\t// Serialize the form elements\n\t\tjQuery.each( a, function() {\n\t\t\tadd( this.name, this.value );\n\t\t} );\n\n\t} else {\n\n\t\t// If traditional, encode the \"old\" way (the way 1.3.2 or older\n\t\t// did it), otherwise encode params recursively.\n\t\tfor ( prefix in a ) {\n\t\t\tbuildParams( prefix, a[ prefix ], traditional, add );\n\t\t}\n\t}\n\n\t// Return the resulting serialization\n\treturn s.join( \"&\" );\n};\n\njQuery.fn.extend( {\n\tserialize: function() {\n\t\treturn jQuery.param( this.serializeArray() );\n\t},\n\tserializeArray: function() {\n\t\treturn this.map( function() {\n\n\t\t\t// Can add propHook for \"elements\" to filter or add form elements\n\t\t\tvar elements = jQuery.prop( this, \"elements\" );\n\t\t\treturn elements ? jQuery.makeArray( elements ) : this;\n\t\t} ).filter( function() {\n\t\t\tvar type = this.type;\n\n\t\t\t// Use .is( \":disabled\" ) so that fieldset[disabled] works\n\t\t\treturn this.name && !jQuery( this ).is( \":disabled\" ) &&\n\t\t\t\trsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) &&\n\t\t\t\t( this.checked || !rcheckableType.test( type ) );\n\t\t} ).map( function( _i, elem ) {\n\t\t\tvar val = jQuery( this ).val();\n\n\t\t\tif ( val == null ) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tif ( Array.isArray( val ) ) {\n\t\t\t\treturn jQuery.map( val, function( val ) {\n\t\t\t\t\treturn { name: elem.name, value: val.replace( rCRLF, \"\\r\\n\" ) };\n\t\t\t\t} );\n\t\t\t}\n\n\t\t\treturn { name: elem.name, value: val.replace( rCRLF, \"\\r\\n\" ) };\n\t\t} ).get();\n\t}\n} );\n\nvar\n\tr20 = /%20/g,\n\trhash = /#.*$/,\n\trantiCache = /([?&])_=[^&]*/,\n\trheaders = /^(.*?):[ \\t]*([^\\r\\n]*)$/mg,\n\n\t// trac-7653, trac-8125, trac-8152: local protocol detection\n\trlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/,\n\trnoContent = /^(?:GET|HEAD)$/,\n\trprotocol = /^\\/\\//,\n\n\t/* Prefilters\n\t * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example)\n\t * 2) These are called:\n\t * - BEFORE asking for a transport\n\t * - AFTER param serialization (s.data is a string if s.processData is true)\n\t * 3) key is the dataType\n\t * 4) the catchall symbol \"*\" can be used\n\t * 5) execution will start with transport dataType and THEN continue down to \"*\" if needed\n\t */\n\tprefilters = {},\n\n\t/* Transports bindings\n\t * 1) key is the dataType\n\t * 2) the catchall symbol \"*\" can be used\n\t * 3) selection will start with transport dataType and THEN go to \"*\" if needed\n\t */\n\ttransports = {},\n\n\t// Avoid comment-prolog char sequence (trac-10098); must appease lint and evade compression\n\tallTypes = \"*/\".concat( \"*\" ),\n\n\t// Anchor tag for parsing the document origin\n\toriginAnchor = document$1.createElement( \"a\" );\n\noriginAnchor.href = location.href;\n\n// Base \"constructor\" for jQuery.ajaxPrefilter and jQuery.ajaxTransport\nfunction addToPrefiltersOrTransports( structure ) {\n\n\t// dataTypeExpression is optional and defaults to \"*\"\n\treturn function( dataTypeExpression, func ) {\n\n\t\tif ( typeof dataTypeExpression !== \"string\" ) {\n\t\t\tfunc = dataTypeExpression;\n\t\t\tdataTypeExpression = \"*\";\n\t\t}\n\n\t\tvar dataType,\n\t\t\ti = 0,\n\t\t\tdataTypes = dataTypeExpression.toLowerCase().match( rnothtmlwhite ) || [];\n\n\t\tif ( typeof func === \"function\" ) {\n\n\t\t\t// For each dataType in the dataTypeExpression\n\t\t\twhile ( ( dataType = dataTypes[ i++ ] ) ) {\n\n\t\t\t\t// Prepend if requested\n\t\t\t\tif ( dataType[ 0 ] === \"+\" ) {\n\t\t\t\t\tdataType = dataType.slice( 1 ) || \"*\";\n\t\t\t\t\t( structure[ dataType ] = structure[ dataType ] || [] ).unshift( func );\n\n\t\t\t\t// Otherwise append\n\t\t\t\t} else {\n\t\t\t\t\t( structure[ dataType ] = structure[ dataType ] || [] ).push( func );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t};\n}\n\n// Base inspection function for prefilters and transports\nfunction inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) {\n\n\tvar inspected = {},\n\t\tseekingTransport = ( structure === transports );\n\n\tfunction inspect( dataType ) {\n\t\tvar selected;\n\t\tinspected[ dataType ] = true;\n\t\tjQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) {\n\t\t\tvar dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR );\n\t\t\tif ( typeof dataTypeOrTransport === \"string\" &&\n\t\t\t\t!seekingTransport && !inspected[ dataTypeOrTransport ] ) {\n\n\t\t\t\toptions.dataTypes.unshift( dataTypeOrTransport );\n\t\t\t\tinspect( dataTypeOrTransport );\n\t\t\t\treturn false;\n\t\t\t} else if ( seekingTransport ) {\n\t\t\t\treturn !( selected = dataTypeOrTransport );\n\t\t\t}\n\t\t} );\n\t\treturn selected;\n\t}\n\n\treturn inspect( options.dataTypes[ 0 ] ) || !inspected[ \"*\" ] && inspect( \"*\" );\n}\n\n// A special extend for ajax options\n// that takes \"flat\" options (not to be deep extended)\n// Fixes trac-9887\nfunction ajaxExtend( target, src ) {\n\tvar key, deep,\n\t\tflatOptions = jQuery.ajaxSettings.flatOptions || {};\n\n\tfor ( key in src ) {\n\t\tif ( src[ key ] !== undefined ) {\n\t\t\t( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ];\n\t\t}\n\t}\n\tif ( deep ) {\n\t\tjQuery.extend( true, target, deep );\n\t}\n\n\treturn target;\n}\n\n/* Handles responses to an ajax request:\n * - finds the right dataType (mediates between content-type and expected dataType)\n * - returns the corresponding response\n */\nfunction ajaxHandleResponses( s, jqXHR, responses ) {\n\n\tvar ct, type, finalDataType, firstDataType,\n\t\tcontents = s.contents,\n\t\tdataTypes = s.dataTypes;\n\n\t// Remove auto dataType and get content-type in the process\n\twhile ( dataTypes[ 0 ] === \"*\" ) {\n\t\tdataTypes.shift();\n\t\tif ( ct === undefined ) {\n\t\t\tct = s.mimeType || jqXHR.getResponseHeader( \"Content-Type\" );\n\t\t}\n\t}\n\n\t// Check if we're dealing with a known content-type\n\tif ( ct ) {\n\t\tfor ( type in contents ) {\n\t\t\tif ( contents[ type ] && contents[ type ].test( ct ) ) {\n\t\t\t\tdataTypes.unshift( type );\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\t// Check to see if we have a response for the expected dataType\n\tif ( dataTypes[ 0 ] in responses ) {\n\t\tfinalDataType = dataTypes[ 0 ];\n\t} else {\n\n\t\t// Try convertible dataTypes\n\t\tfor ( type in responses ) {\n\t\t\tif ( !dataTypes[ 0 ] || s.converters[ type + \" \" + dataTypes[ 0 ] ] ) {\n\t\t\t\tfinalDataType = type;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif ( !firstDataType ) {\n\t\t\t\tfirstDataType = type;\n\t\t\t}\n\t\t}\n\n\t\t// Or just use first one\n\t\tfinalDataType = finalDataType || firstDataType;\n\t}\n\n\t// If we found a dataType\n\t// We add the dataType to the list if needed\n\t// and return the corresponding response\n\tif ( finalDataType ) {\n\t\tif ( finalDataType !== dataTypes[ 0 ] ) {\n\t\t\tdataTypes.unshift( finalDataType );\n\t\t}\n\t\treturn responses[ finalDataType ];\n\t}\n}\n\n/* Chain conversions given the request and the original response\n * Also sets the responseXXX fields on the jqXHR instance\n */\nfunction ajaxConvert( s, response, jqXHR, isSuccess ) {\n\tvar conv2, current, conv, tmp, prev,\n\t\tconverters = {},\n\n\t\t// Work with a copy of dataTypes in case we need to modify it for conversion\n\t\tdataTypes = s.dataTypes.slice();\n\n\t// Create converters map with lowercased keys\n\tif ( dataTypes[ 1 ] ) {\n\t\tfor ( conv in s.converters ) {\n\t\t\tconverters[ conv.toLowerCase() ] = s.converters[ conv ];\n\t\t}\n\t}\n\n\tcurrent = dataTypes.shift();\n\n\t// Convert to each sequential dataType\n\twhile ( current ) {\n\n\t\tif ( s.responseFields[ current ] ) {\n\t\t\tjqXHR[ s.responseFields[ current ] ] = response;\n\t\t}\n\n\t\t// Apply the dataFilter if provided\n\t\tif ( !prev && isSuccess && s.dataFilter ) {\n\t\t\tresponse = s.dataFilter( response, s.dataType );\n\t\t}\n\n\t\tprev = current;\n\t\tcurrent = dataTypes.shift();\n\n\t\tif ( current ) {\n\n\t\t\t// There's only work to do if current dataType is non-auto\n\t\t\tif ( current === \"*\" ) {\n\n\t\t\t\tcurrent = prev;\n\n\t\t\t// Convert response if prev dataType is non-auto and differs from current\n\t\t\t} else if ( prev !== \"*\" && prev !== current ) {\n\n\t\t\t\t// Seek a direct converter\n\t\t\t\tconv = converters[ prev + \" \" + current ] || converters[ \"* \" + current ];\n\n\t\t\t\t// If none found, seek a pair\n\t\t\t\tif ( !conv ) {\n\t\t\t\t\tfor ( conv2 in converters ) {\n\n\t\t\t\t\t\t// If conv2 outputs current\n\t\t\t\t\t\ttmp = conv2.split( \" \" );\n\t\t\t\t\t\tif ( tmp[ 1 ] === current ) {\n\n\t\t\t\t\t\t\t// If prev can be converted to accepted input\n\t\t\t\t\t\t\tconv = converters[ prev + \" \" + tmp[ 0 ] ] ||\n\t\t\t\t\t\t\t\tconverters[ \"* \" + tmp[ 0 ] ];\n\t\t\t\t\t\t\tif ( conv ) {\n\n\t\t\t\t\t\t\t\t// Condense equivalence converters\n\t\t\t\t\t\t\t\tif ( conv === true ) {\n\t\t\t\t\t\t\t\t\tconv = converters[ conv2 ];\n\n\t\t\t\t\t\t\t\t// Otherwise, insert the intermediate dataType\n\t\t\t\t\t\t\t\t} else if ( converters[ conv2 ] !== true ) {\n\t\t\t\t\t\t\t\t\tcurrent = tmp[ 0 ];\n\t\t\t\t\t\t\t\t\tdataTypes.unshift( tmp[ 1 ] );\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Apply converter (if not an equivalence)\n\t\t\t\tif ( conv !== true ) {\n\n\t\t\t\t\t// Unless errors are allowed to bubble, catch and return them\n\t\t\t\t\tif ( conv && s.throws ) {\n\t\t\t\t\t\tresponse = conv( response );\n\t\t\t\t\t} else {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tresponse = conv( response );\n\t\t\t\t\t\t} catch ( e ) {\n\t\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t\tstate: \"parsererror\",\n\t\t\t\t\t\t\t\terror: conv ? e : \"No conversion from \" + prev + \" to \" + current\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn { state: \"success\", data: response };\n}\n\njQuery.extend( {\n\n\t// Counter for holding the number of active queries\n\tactive: 0,\n\n\t// Last-Modified header cache for next request\n\tlastModified: {},\n\tetag: {},\n\n\tajaxSettings: {\n\t\turl: location.href,\n\t\ttype: \"GET\",\n\t\tisLocal: rlocalProtocol.test( location.protocol ),\n\t\tglobal: true,\n\t\tprocessData: true,\n\t\tasync: true,\n\t\tcontentType: \"application/x-www-form-urlencoded; charset=UTF-8\",\n\n\t\t/*\n\t\ttimeout: 0,\n\t\tdata: null,\n\t\tdataType: null,\n\t\tusername: null,\n\t\tpassword: null,\n\t\tcache: null,\n\t\tthrows: false,\n\t\ttraditional: false,\n\t\theaders: {},\n\t\t*/\n\n\t\taccepts: {\n\t\t\t\"*\": allTypes,\n\t\t\ttext: \"text/plain\",\n\t\t\thtml: \"text/html\",\n\t\t\txml: \"application/xml, text/xml\",\n\t\t\tjson: \"application/json, text/javascript\"\n\t\t},\n\n\t\tcontents: {\n\t\t\txml: /\\bxml\\b/,\n\t\t\thtml: /\\bhtml/,\n\t\t\tjson: /\\bjson\\b/\n\t\t},\n\n\t\tresponseFields: {\n\t\t\txml: \"responseXML\",\n\t\t\ttext: \"responseText\",\n\t\t\tjson: \"responseJSON\"\n\t\t},\n\n\t\t// Data converters\n\t\t// Keys separate source (or catchall \"*\") and destination types with a single space\n\t\tconverters: {\n\n\t\t\t// Convert anything to text\n\t\t\t\"* text\": String,\n\n\t\t\t// Text to html (true = no transformation)\n\t\t\t\"text html\": true,\n\n\t\t\t// Evaluate text as a json expression\n\t\t\t\"text json\": JSON.parse,\n\n\t\t\t// Parse text as xml\n\t\t\t\"text xml\": jQuery.parseXML\n\t\t},\n\n\t\t// For options that shouldn't be deep extended:\n\t\t// you can add your own custom options here if\n\t\t// and when you create one that shouldn't be\n\t\t// deep extended (see ajaxExtend)\n\t\tflatOptions: {\n\t\t\turl: true,\n\t\t\tcontext: true\n\t\t}\n\t},\n\n\t// Creates a full fledged settings object into target\n\t// with both ajaxSettings and settings fields.\n\t// If target is omitted, writes into ajaxSettings.\n\tajaxSetup: function( target, settings ) {\n\t\treturn settings ?\n\n\t\t\t// Building a settings object\n\t\t\tajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) :\n\n\t\t\t// Extending ajaxSettings\n\t\t\tajaxExtend( jQuery.ajaxSettings, target );\n\t},\n\n\tajaxPrefilter: addToPrefiltersOrTransports( prefilters ),\n\tajaxTransport: addToPrefiltersOrTransports( transports ),\n\n\t// Main method\n\tajax: function( url, options ) {\n\n\t\t// If url is an object, simulate pre-1.5 signature\n\t\tif ( typeof url === \"object\" ) {\n\t\t\toptions = url;\n\t\t\turl = undefined;\n\t\t}\n\n\t\t// Force options to be an object\n\t\toptions = options || {};\n\n\t\tvar transport,\n\n\t\t\t// URL without anti-cache param\n\t\t\tcacheURL,\n\n\t\t\t// Response headers\n\t\t\tresponseHeadersString,\n\t\t\tresponseHeaders,\n\n\t\t\t// timeout handle\n\t\t\ttimeoutTimer,\n\n\t\t\t// Url cleanup var\n\t\t\turlAnchor,\n\n\t\t\t// Request state (becomes false upon send and true upon completion)\n\t\t\tcompleted,\n\n\t\t\t// To know if global events are to be dispatched\n\t\t\tfireGlobals,\n\n\t\t\t// Loop variable\n\t\t\ti,\n\n\t\t\t// uncached part of the url\n\t\t\tuncached,\n\n\t\t\t// Create the final options object\n\t\t\ts = jQuery.ajaxSetup( {}, options ),\n\n\t\t\t// Callbacks context\n\t\t\tcallbackContext = s.context || s,\n\n\t\t\t// Context for global events is callbackContext if it is a DOM node or jQuery collection\n\t\t\tglobalEventContext = s.context &&\n\t\t\t\t( callbackContext.nodeType || callbackContext.jquery ) ?\n\t\t\t\tjQuery( callbackContext ) :\n\t\t\t\tjQuery.event,\n\n\t\t\t// Deferreds\n\t\t\tdeferred = jQuery.Deferred(),\n\t\t\tcompleteDeferred = jQuery.Callbacks( \"once memory\" ),\n\n\t\t\t// Status-dependent callbacks\n\t\t\tstatusCode = s.statusCode || {},\n\n\t\t\t// Headers (they are sent all at once)\n\t\t\trequestHeaders = {},\n\t\t\trequestHeadersNames = {},\n\n\t\t\t// Default abort message\n\t\t\tstrAbort = \"canceled\",\n\n\t\t\t// Fake xhr\n\t\t\tjqXHR = {\n\t\t\t\treadyState: 0,\n\n\t\t\t\t// Builds headers hashtable if needed\n\t\t\t\tgetResponseHeader: function( key ) {\n\t\t\t\t\tvar match;\n\t\t\t\t\tif ( completed ) {\n\t\t\t\t\t\tif ( !responseHeaders ) {\n\t\t\t\t\t\t\tresponseHeaders = {};\n\t\t\t\t\t\t\twhile ( ( match = rheaders.exec( responseHeadersString ) ) ) {\n\n\t\t\t\t\t\t\t\t// Support: IE 11+\n\t\t\t\t\t\t\t\t// `getResponseHeader( key )` in IE doesn't combine all header\n\t\t\t\t\t\t\t\t// values for the provided key into a single result with values\n\t\t\t\t\t\t\t\t// joined by commas as other browsers do. Instead, it returns\n\t\t\t\t\t\t\t\t// them on separate lines.\n\t\t\t\t\t\t\t\tresponseHeaders[ match[ 1 ].toLowerCase() + \" \" ] =\n\t\t\t\t\t\t\t\t\t( responseHeaders[ match[ 1 ].toLowerCase() + \" \" ] || [] )\n\t\t\t\t\t\t\t\t\t\t.concat( match[ 2 ] );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tmatch = responseHeaders[ key.toLowerCase() + \" \" ];\n\t\t\t\t\t}\n\t\t\t\t\treturn match == null ? null : match.join( \", \" );\n\t\t\t\t},\n\n\t\t\t\t// Raw string\n\t\t\t\tgetAllResponseHeaders: function() {\n\t\t\t\t\treturn completed ? responseHeadersString : null;\n\t\t\t\t},\n\n\t\t\t\t// Caches the header\n\t\t\t\tsetRequestHeader: function( name, value ) {\n\t\t\t\t\tif ( completed == null ) {\n\t\t\t\t\t\tname = requestHeadersNames[ name.toLowerCase() ] =\n\t\t\t\t\t\t\trequestHeadersNames[ name.toLowerCase() ] || name;\n\t\t\t\t\t\trequestHeaders[ name ] = value;\n\t\t\t\t\t}\n\t\t\t\t\treturn this;\n\t\t\t\t},\n\n\t\t\t\t// Overrides response content-type header\n\t\t\t\toverrideMimeType: function( type ) {\n\t\t\t\t\tif ( completed == null ) {\n\t\t\t\t\t\ts.mimeType = type;\n\t\t\t\t\t}\n\t\t\t\t\treturn this;\n\t\t\t\t},\n\n\t\t\t\t// Status-dependent callbacks\n\t\t\t\tstatusCode: function( map ) {\n\t\t\t\t\tvar code;\n\t\t\t\t\tif ( map ) {\n\t\t\t\t\t\tif ( completed ) {\n\n\t\t\t\t\t\t\t// Execute the appropriate callbacks\n\t\t\t\t\t\t\tjqXHR.always( map[ jqXHR.status ] );\n\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t// Lazy-add the new callbacks in a way that preserves old ones\n\t\t\t\t\t\t\tfor ( code in map ) {\n\t\t\t\t\t\t\t\tstatusCode[ code ] = [ statusCode[ code ], map[ code ] ];\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\treturn this;\n\t\t\t\t},\n\n\t\t\t\t// Cancel the request\n\t\t\t\tabort: function( statusText ) {\n\t\t\t\t\tvar finalText = statusText || strAbort;\n\t\t\t\t\tif ( transport ) {\n\t\t\t\t\t\ttransport.abort( finalText );\n\t\t\t\t\t}\n\t\t\t\t\tdone( 0, finalText );\n\t\t\t\t\treturn this;\n\t\t\t\t}\n\t\t\t};\n\n\t\t// Attach deferreds\n\t\tdeferred.promise( jqXHR );\n\n\t\t// Add protocol if not provided (prefilters might expect it)\n\t\t// Handle falsy url in the settings object (trac-10093: consistency with old signature)\n\t\t// We also use the url parameter if available\n\t\ts.url = ( ( url || s.url || location.href ) + \"\" )\n\t\t\t.replace( rprotocol, location.protocol + \"//\" );\n\n\t\t// Alias method option to type as per ticket trac-12004\n\t\ts.type = options.method || options.type || s.method || s.type;\n\n\t\t// Extract dataTypes list\n\t\ts.dataTypes = ( s.dataType || \"*\" ).toLowerCase().match( rnothtmlwhite ) || [ \"\" ];\n\n\t\t// A cross-domain request is in order when the origin doesn't match the current origin.\n\t\tif ( s.crossDomain == null ) {\n\t\t\turlAnchor = document$1.createElement( \"a\" );\n\n\t\t\t// Support: IE <=8 - 11+\n\t\t\t// IE throws exception on accessing the href property if url is malformed,\n\t\t\t// e.g. http://example.com:80x/\n\t\t\ttry {\n\t\t\t\turlAnchor.href = s.url;\n\n\t\t\t\t// Support: IE <=8 - 11+\n\t\t\t\t// Anchor's host property isn't correctly set when s.url is relative\n\t\t\t\turlAnchor.href = urlAnchor.href;\n\t\t\t\ts.crossDomain = originAnchor.protocol + \"//\" + originAnchor.host !==\n\t\t\t\t\turlAnchor.protocol + \"//\" + urlAnchor.host;\n\t\t\t} catch ( e ) {\n\n\t\t\t\t// If there is an error parsing the URL, assume it is crossDomain,\n\t\t\t\t// it can be rejected by the transport if it is invalid\n\t\t\t\ts.crossDomain = true;\n\t\t\t}\n\t\t}\n\n\t\t// Apply prefilters\n\t\tinspectPrefiltersOrTransports( prefilters, s, options, jqXHR );\n\n\t\t// Convert data if not already a string\n\t\tif ( s.data && s.processData && typeof s.data !== \"string\" ) {\n\t\t\ts.data = jQuery.param( s.data, s.traditional );\n\t\t}\n\n\t\t// If request was aborted inside a prefilter, stop there\n\t\tif ( completed ) {\n\t\t\treturn jqXHR;\n\t\t}\n\n\t\t// We can fire global events as of now if asked to\n\t\t// Don't fire events if jQuery.event is undefined in an ESM-usage scenario (trac-15118)\n\t\tfireGlobals = jQuery.event && s.global;\n\n\t\t// Watch for a new set of requests\n\t\tif ( fireGlobals && jQuery.active++ === 0 ) {\n\t\t\tjQuery.event.trigger( \"ajaxStart\" );\n\t\t}\n\n\t\t// Uppercase the type\n\t\ts.type = s.type.toUpperCase();\n\n\t\t// Determine if request has content\n\t\ts.hasContent = !rnoContent.test( s.type );\n\n\t\t// Save the URL in case we're toying with the If-Modified-Since\n\t\t// and/or If-None-Match header later on\n\t\t// Remove hash to simplify url manipulation\n\t\tcacheURL = s.url.replace( rhash, \"\" );\n\n\t\t// More options handling for requests with no content\n\t\tif ( !s.hasContent ) {\n\n\t\t\t// Remember the hash so we can put it back\n\t\t\tuncached = s.url.slice( cacheURL.length );\n\n\t\t\t// If data is available and should be processed, append data to url\n\t\t\tif ( s.data && ( s.processData || typeof s.data === \"string\" ) ) {\n\t\t\t\tcacheURL += ( rquery.test( cacheURL ) ? \"&\" : \"?\" ) + s.data;\n\n\t\t\t\t// trac-9682: remove data so that it's not used in an eventual retry\n\t\t\t\tdelete s.data;\n\t\t\t}\n\n\t\t\t// Add or update anti-cache param if needed\n\t\t\tif ( s.cache === false ) {\n\t\t\t\tcacheURL = cacheURL.replace( rantiCache, \"$1\" );\n\t\t\t\tuncached = ( rquery.test( cacheURL ) ? \"&\" : \"?\" ) + \"_=\" +\n\t\t\t\t\t( nonce.guid++ ) + uncached;\n\t\t\t}\n\n\t\t\t// Put hash and anti-cache on the URL that will be requested (gh-1732)\n\t\t\ts.url = cacheURL + uncached;\n\n\t\t// Change '%20' to '+' if this is encoded form body content (gh-2658)\n\t\t} else if ( s.data && s.processData &&\n\t\t\t( s.contentType || \"\" ).indexOf( \"application/x-www-form-urlencoded\" ) === 0 ) {\n\t\t\ts.data = s.data.replace( r20, \"+\" );\n\t\t}\n\n\t\t// Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.\n\t\tif ( s.ifModified ) {\n\t\t\tif ( jQuery.lastModified[ cacheURL ] ) {\n\t\t\t\tjqXHR.setRequestHeader( \"If-Modified-Since\", jQuery.lastModified[ cacheURL ] );\n\t\t\t}\n\t\t\tif ( jQuery.etag[ cacheURL ] ) {\n\t\t\t\tjqXHR.setRequestHeader( \"If-None-Match\", jQuery.etag[ cacheURL ] );\n\t\t\t}\n\t\t}\n\n\t\t// Set the correct header, if data is being sent\n\t\tif ( s.data && s.hasContent && s.contentType !== false || options.contentType ) {\n\t\t\tjqXHR.setRequestHeader( \"Content-Type\", s.contentType );\n\t\t}\n\n\t\t// Set the Accepts header for the server, depending on the dataType\n\t\tjqXHR.setRequestHeader(\n\t\t\t\"Accept\",\n\t\t\ts.dataTypes[ 0 ] && s.accepts[ s.dataTypes[ 0 ] ] ?\n\t\t\t\ts.accepts[ s.dataTypes[ 0 ] ] +\n\t\t\t\t\t( s.dataTypes[ 0 ] !== \"*\" ? \", \" + allTypes + \"; q=0.01\" : \"\" ) :\n\t\t\t\ts.accepts[ \"*\" ]\n\t\t);\n\n\t\t// Check for headers option\n\t\tfor ( i in s.headers ) {\n\t\t\tjqXHR.setRequestHeader( i, s.headers[ i ] );\n\t\t}\n\n\t\t// Allow custom headers/mimetypes and early abort\n\t\tif ( s.beforeSend &&\n\t\t\t( s.beforeSend.call( callbackContext, jqXHR, s ) === false || completed ) ) {\n\n\t\t\t// Abort if not done already and return\n\t\t\treturn jqXHR.abort();\n\t\t}\n\n\t\t// Aborting is no longer a cancellation\n\t\tstrAbort = \"abort\";\n\n\t\t// Install callbacks on deferreds\n\t\tcompleteDeferred.add( s.complete );\n\t\tjqXHR.done( s.success );\n\t\tjqXHR.fail( s.error );\n\n\t\t// Get transport\n\t\ttransport = inspectPrefiltersOrTransports( transports, s, options, jqXHR );\n\n\t\t// If no transport, we auto-abort\n\t\tif ( !transport ) {\n\t\t\tdone( -1, \"No Transport\" );\n\t\t} else {\n\t\t\tjqXHR.readyState = 1;\n\n\t\t\t// Send global event\n\t\t\tif ( fireGlobals ) {\n\t\t\t\tglobalEventContext.trigger( \"ajaxSend\", [ jqXHR, s ] );\n\t\t\t}\n\n\t\t\t// If request was aborted inside ajaxSend, stop there\n\t\t\tif ( completed ) {\n\t\t\t\treturn jqXHR;\n\t\t\t}\n\n\t\t\t// Timeout\n\t\t\tif ( s.async && s.timeout > 0 ) {\n\t\t\t\ttimeoutTimer = window.setTimeout( function() {\n\t\t\t\t\tjqXHR.abort( \"timeout\" );\n\t\t\t\t}, s.timeout );\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tcompleted = false;\n\t\t\t\ttransport.send( requestHeaders, done );\n\t\t\t} catch ( e ) {\n\n\t\t\t\t// Rethrow post-completion exceptions\n\t\t\t\tif ( completed ) {\n\t\t\t\t\tthrow e;\n\t\t\t\t}\n\n\t\t\t\t// Propagate others as results\n\t\t\t\tdone( -1, e );\n\t\t\t}\n\t\t}\n\n\t\t// Callback for when everything is done\n\t\tfunction done( status, nativeStatusText, responses, headers ) {\n\t\t\tvar isSuccess, success, error, response, modified,\n\t\t\t\tstatusText = nativeStatusText;\n\n\t\t\t// Ignore repeat invocations\n\t\t\tif ( completed ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tcompleted = true;\n\n\t\t\t// Clear timeout if it exists\n\t\t\tif ( timeoutTimer ) {\n\t\t\t\twindow.clearTimeout( timeoutTimer );\n\t\t\t}\n\n\t\t\t// Dereference transport for early garbage collection\n\t\t\t// (no matter how long the jqXHR object will be used)\n\t\t\ttransport = undefined;\n\n\t\t\t// Cache response headers\n\t\t\tresponseHeadersString = headers || \"\";\n\n\t\t\t// Set readyState\n\t\t\tjqXHR.readyState = status > 0 ? 4 : 0;\n\n\t\t\t// Determine if successful\n\t\t\tisSuccess = status >= 200 && status < 300 || status === 304;\n\n\t\t\t// Get response data\n\t\t\tif ( responses ) {\n\t\t\t\tresponse = ajaxHandleResponses( s, jqXHR, responses );\n\t\t\t}\n\n\t\t\t// Use a noop converter for missing script but not if jsonp\n\t\t\tif ( !isSuccess &&\n\t\t\t\tjQuery.inArray( \"script\", s.dataTypes ) > -1 &&\n\t\t\t\tjQuery.inArray( \"json\", s.dataTypes ) < 0 ) {\n\t\t\t\ts.converters[ \"text script\" ] = function() {};\n\t\t\t}\n\n\t\t\t// Convert no matter what (that way responseXXX fields are always set)\n\t\t\tresponse = ajaxConvert( s, response, jqXHR, isSuccess );\n\n\t\t\t// If successful, handle type chaining\n\t\t\tif ( isSuccess ) {\n\n\t\t\t\t// Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.\n\t\t\t\tif ( s.ifModified ) {\n\t\t\t\t\tmodified = jqXHR.getResponseHeader( \"Last-Modified\" );\n\t\t\t\t\tif ( modified ) {\n\t\t\t\t\t\tjQuery.lastModified[ cacheURL ] = modified;\n\t\t\t\t\t}\n\t\t\t\t\tmodified = jqXHR.getResponseHeader( \"etag\" );\n\t\t\t\t\tif ( modified ) {\n\t\t\t\t\t\tjQuery.etag[ cacheURL ] = modified;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// if no content\n\t\t\t\tif ( status === 204 || s.type === \"HEAD\" ) {\n\t\t\t\t\tstatusText = \"nocontent\";\n\n\t\t\t\t// if not modified\n\t\t\t\t} else if ( status === 304 ) {\n\t\t\t\t\tstatusText = \"notmodified\";\n\n\t\t\t\t// If we have data, let's convert it\n\t\t\t\t} else {\n\t\t\t\t\tstatusText = response.state;\n\t\t\t\t\tsuccess = response.data;\n\t\t\t\t\terror = response.error;\n\t\t\t\t\tisSuccess = !error;\n\t\t\t\t}\n\t\t\t} else {\n\n\t\t\t\t// Extract error from statusText and normalize for non-aborts\n\t\t\t\terror = statusText;\n\t\t\t\tif ( status || !statusText ) {\n\t\t\t\t\tstatusText = \"error\";\n\t\t\t\t\tif ( status < 0 ) {\n\t\t\t\t\t\tstatus = 0;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Set data for the fake xhr object\n\t\t\tjqXHR.status = status;\n\t\t\tjqXHR.statusText = ( nativeStatusText || statusText ) + \"\";\n\n\t\t\t// Success/Error\n\t\t\tif ( isSuccess ) {\n\t\t\t\tdeferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] );\n\t\t\t} else {\n\t\t\t\tdeferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] );\n\t\t\t}\n\n\t\t\t// Status-dependent callbacks\n\t\t\tjqXHR.statusCode( statusCode );\n\t\t\tstatusCode = undefined;\n\n\t\t\tif ( fireGlobals ) {\n\t\t\t\tglobalEventContext.trigger( isSuccess ? \"ajaxSuccess\" : \"ajaxError\",\n\t\t\t\t\t[ jqXHR, s, isSuccess ? success : error ] );\n\t\t\t}\n\n\t\t\t// Complete\n\t\t\tcompleteDeferred.fireWith( callbackContext, [ jqXHR, statusText ] );\n\n\t\t\tif ( fireGlobals ) {\n\t\t\t\tglobalEventContext.trigger( \"ajaxComplete\", [ jqXHR, s ] );\n\n\t\t\t\t// Handle the global AJAX counter\n\t\t\t\tif ( !( --jQuery.active ) ) {\n\t\t\t\t\tjQuery.event.trigger( \"ajaxStop\" );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn jqXHR;\n\t},\n\n\tgetJSON: function( url, data, callback ) {\n\t\treturn jQuery.get( url, data, callback, \"json\" );\n\t},\n\n\tgetScript: function( url, callback ) {\n\t\treturn jQuery.get( url, undefined, callback, \"script\" );\n\t}\n} );\n\njQuery.each( [ \"get\", \"post\" ], function( _i, method ) {\n\tjQuery[ method ] = function( url, data, callback, type ) {\n\n\t\t// Shift arguments if data argument was omitted.\n\t\t// Handle the null callback placeholder.\n\t\tif ( typeof data === \"function\" || data === null ) {\n\t\t\ttype = type || callback;\n\t\t\tcallback = data;\n\t\t\tdata = undefined;\n\t\t}\n\n\t\t// The url can be an options object (which then must have .url)\n\t\treturn jQuery.ajax( jQuery.extend( {\n\t\t\turl: url,\n\t\t\ttype: method,\n\t\t\tdataType: type,\n\t\t\tdata: data,\n\t\t\tsuccess: callback\n\t\t}, jQuery.isPlainObject( url ) && url ) );\n\t};\n} );\n\njQuery.ajaxPrefilter( function( s ) {\n\tvar i;\n\tfor ( i in s.headers ) {\n\t\tif ( i.toLowerCase() === \"content-type\" ) {\n\t\t\ts.contentType = s.headers[ i ] || \"\";\n\t\t}\n\t}\n} );\n\njQuery._evalUrl = function( url, options, doc ) {\n\treturn jQuery.ajax( {\n\t\turl: url,\n\n\t\t// Make this explicit, since user can override this through ajaxSetup (trac-11264)\n\t\ttype: \"GET\",\n\t\tdataType: \"script\",\n\t\tcache: true,\n\t\tasync: false,\n\t\tglobal: false,\n\t\tscriptAttrs: options.crossOrigin ? { \"crossOrigin\": options.crossOrigin } : undefined,\n\n\t\t// Only evaluate the response if it is successful (gh-4126)\n\t\t// dataFilter is not invoked for failure responses, so using it instead\n\t\t// of the default converter is kludgy but it works.\n\t\tconverters: {\n\t\t\t\"text script\": function() {}\n\t\t},\n\t\tdataFilter: function( response ) {\n\t\t\tjQuery.globalEval( response, options, doc );\n\t\t}\n\t} );\n};\n\njQuery.fn.extend( {\n\twrapAll: function( html ) {\n\t\tvar wrap;\n\n\t\tif ( this[ 0 ] ) {\n\t\t\tif ( typeof html === \"function\" ) {\n\t\t\t\thtml = html.call( this[ 0 ] );\n\t\t\t}\n\n\t\t\t// The elements to wrap the target around\n\t\t\twrap = jQuery( html, this[ 0 ].ownerDocument ).eq( 0 ).clone( true );\n\n\t\t\tif ( this[ 0 ].parentNode ) {\n\t\t\t\twrap.insertBefore( this[ 0 ] );\n\t\t\t}\n\n\t\t\twrap.map( function() {\n\t\t\t\tvar elem = this;\n\n\t\t\t\twhile ( elem.firstElementChild ) {\n\t\t\t\t\telem = elem.firstElementChild;\n\t\t\t\t}\n\n\t\t\t\treturn elem;\n\t\t\t} ).append( this );\n\t\t}\n\n\t\treturn this;\n\t},\n\n\twrapInner: function( html ) {\n\t\tif ( typeof html === \"function\" ) {\n\t\t\treturn this.each( function( i ) {\n\t\t\t\tjQuery( this ).wrapInner( html.call( this, i ) );\n\t\t\t} );\n\t\t}\n\n\t\treturn this.each( function() {\n\t\t\tvar self = jQuery( this ),\n\t\t\t\tcontents = self.contents();\n\n\t\t\tif ( contents.length ) {\n\t\t\t\tcontents.wrapAll( html );\n\n\t\t\t} else {\n\t\t\t\tself.append( html );\n\t\t\t}\n\t\t} );\n\t},\n\n\twrap: function( html ) {\n\t\tvar htmlIsFunction = typeof html === \"function\";\n\n\t\treturn this.each( function( i ) {\n\t\t\tjQuery( this ).wrapAll( htmlIsFunction ? html.call( this, i ) : html );\n\t\t} );\n\t},\n\n\tunwrap: function( selector ) {\n\t\tthis.parent( selector ).not( \"body\" ).each( function() {\n\t\t\tjQuery( this ).replaceWith( this.childNodes );\n\t\t} );\n\t\treturn this;\n\t}\n} );\n\njQuery.expr.pseudos.hidden = function( elem ) {\n\treturn !jQuery.expr.pseudos.visible( elem );\n};\njQuery.expr.pseudos.visible = function( elem ) {\n\treturn !!( elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length );\n};\n\njQuery.ajaxSettings.xhr = function() {\n\treturn new window.XMLHttpRequest();\n};\n\nvar xhrSuccessStatus = {\n\n\t// File protocol always yields status code 0, assume 200\n\t0: 200\n};\n\njQuery.ajaxTransport( function( options ) {\n\tvar callback;\n\n\treturn {\n\t\tsend: function( headers, complete ) {\n\t\t\tvar i,\n\t\t\t\txhr = options.xhr();\n\n\t\t\txhr.open(\n\t\t\t\toptions.type,\n\t\t\t\toptions.url,\n\t\t\t\toptions.async,\n\t\t\t\toptions.username,\n\t\t\t\toptions.password\n\t\t\t);\n\n\t\t\t// Apply custom fields if provided\n\t\t\tif ( options.xhrFields ) {\n\t\t\t\tfor ( i in options.xhrFields ) {\n\t\t\t\t\txhr[ i ] = options.xhrFields[ i ];\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Override mime type if needed\n\t\t\tif ( options.mimeType && xhr.overrideMimeType ) {\n\t\t\t\txhr.overrideMimeType( options.mimeType );\n\t\t\t}\n\n\t\t\t// X-Requested-With header\n\t\t\t// For cross-domain requests, seeing as conditions for a preflight are\n\t\t\t// akin to a jigsaw puzzle, we simply never set it to be sure.\n\t\t\t// (it can always be set on a per-request basis or even using ajaxSetup)\n\t\t\t// For same-domain requests, won't change header if already provided.\n\t\t\tif ( !options.crossDomain && !headers[ \"X-Requested-With\" ] ) {\n\t\t\t\theaders[ \"X-Requested-With\" ] = \"XMLHttpRequest\";\n\t\t\t}\n\n\t\t\t// Set headers\n\t\t\tfor ( i in headers ) {\n\t\t\t\txhr.setRequestHeader( i, headers[ i ] );\n\t\t\t}\n\n\t\t\t// Callback\n\t\t\tcallback = function( type ) {\n\t\t\t\treturn function() {\n\t\t\t\t\tif ( callback ) {\n\t\t\t\t\t\tcallback = xhr.onload = xhr.onerror = xhr.onabort = xhr.ontimeout = null;\n\n\t\t\t\t\t\tif ( type === \"abort\" ) {\n\t\t\t\t\t\t\txhr.abort();\n\t\t\t\t\t\t} else if ( type === \"error\" ) {\n\t\t\t\t\t\t\tcomplete(\n\n\t\t\t\t\t\t\t\t// File: protocol always yields status 0; see trac-8605, trac-14207\n\t\t\t\t\t\t\t\txhr.status,\n\t\t\t\t\t\t\t\txhr.statusText\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tcomplete(\n\t\t\t\t\t\t\t\txhrSuccessStatus[ xhr.status ] || xhr.status,\n\t\t\t\t\t\t\t\txhr.statusText,\n\n\t\t\t\t\t\t\t\t// For XHR2 non-text, let the caller handle it (gh-2498)\n\t\t\t\t\t\t\t\t( xhr.responseType || \"text\" ) === \"text\" ?\n\t\t\t\t\t\t\t\t\t{ text: xhr.responseText } :\n\t\t\t\t\t\t\t\t\t{ binary: xhr.response },\n\t\t\t\t\t\t\t\txhr.getAllResponseHeaders()\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t};\n\n\t\t\t// Listen to events\n\t\t\txhr.onload = callback();\n\t\t\txhr.onabort = xhr.onerror = xhr.ontimeout = callback( \"error\" );\n\n\t\t\t// Create the abort callback\n\t\t\tcallback = callback( \"abort\" );\n\n\t\t\ttry {\n\n\t\t\t\t// Do send the request (this may raise an exception)\n\t\t\t\txhr.send( options.hasContent && options.data || null );\n\t\t\t} catch ( e ) {\n\n\t\t\t\t// trac-14683: Only rethrow if this hasn't been notified as an error yet\n\t\t\t\tif ( callback ) {\n\t\t\t\t\tthrow e;\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\n\t\tabort: function() {\n\t\t\tif ( callback ) {\n\t\t\t\tcallback();\n\t\t\t}\n\t\t}\n\t};\n} );\n\nfunction canUseScriptTag( s ) {\n\n\t// A script tag can only be used for async, cross domain or forced-by-attrs requests.\n\t// Requests with headers cannot use a script tag. However, when both `scriptAttrs` &\n\t// `headers` options are specified, both are impossible to satisfy together; we\n\t// prefer `scriptAttrs` then.\n\t// Sync requests remain handled differently to preserve strict script ordering.\n\treturn s.scriptAttrs || (\n\t\t!s.headers &&\n\t\t(\n\t\t\ts.crossDomain ||\n\n\t\t\t// When dealing with JSONP (`s.dataTypes` include \"json\" then)\n\t\t\t// don't use a script tag so that error responses still may have\n\t\t\t// `responseJSON` set. Continue using a script tag for JSONP requests that:\n\t\t\t// * are cross-domain as AJAX requests won't work without a CORS setup\n\t\t\t// * have `scriptAttrs` set as that's a script-only functionality\n\t\t\t// Note that this means JSONP requests violate strict CSP script-src settings.\n\t\t\t// A proper solution is to migrate from using JSONP to a CORS setup.\n\t\t\t( s.async && jQuery.inArray( \"json\", s.dataTypes ) < 0 )\n\t\t)\n\t);\n}\n\n// Install script dataType. Don't specify `contents.script` so that an explicit\n// `dataType: \"script\"` is required (see gh-2432, gh-4822)\njQuery.ajaxSetup( {\n\taccepts: {\n\t\tscript: \"text/javascript, application/javascript, \" +\n\t\t\t\"application/ecmascript, application/x-ecmascript\"\n\t},\n\tconverters: {\n\t\t\"text script\": function( text ) {\n\t\t\tjQuery.globalEval( text );\n\t\t\treturn text;\n\t\t}\n\t}\n} );\n\n// Handle cache's special case and crossDomain\njQuery.ajaxPrefilter( \"script\", function( s ) {\n\tif ( s.cache === undefined ) {\n\t\ts.cache = false;\n\t}\n\n\t// These types of requests are handled via a script tag\n\t// so force their methods to GET.\n\tif ( canUseScriptTag( s ) ) {\n\t\ts.type = \"GET\";\n\t}\n} );\n\n// Bind script tag hack transport\njQuery.ajaxTransport( \"script\", function( s ) {\n\tif ( canUseScriptTag( s ) ) {\n\t\tvar script, callback;\n\t\treturn {\n\t\t\tsend: function( _, complete ) {\n\t\t\t\tscript = jQuery( \"\n \n \n `);\n document.close();\n}\n\nconst delay = (ms: number) => new Promise((resolve) => { setTimeout(resolve, ms); });\n\nexport async function restartReload(initial = true) {\n document.body.style = 'background: #222222; font-size: 1rem; font-family:monospace; margin-top:20%; color:lightgray; text-align:center';\n document.body.innerHTML = '

Server shutdown in progress...

';\n if (initial) await delay(10000);\n try {\n const res = await authFetch(`${window.api}/progress?skip_current_image=true`);\n console.log('restartReload', res);\n if (res?.ok) {\n document.body.innerHTML = '

Server restart in progress...

';\n setTimeout(() => location.reload(), 10000);\n } else {\n setTimeout(() => restartReload(false), 2500);\n }\n } catch {\n setTimeout(() => restartReload(false), 2500);\n }\n return [];\n}\n\nexport function updateInput(target) {\n const e = new Event('input', { bubbles: true });\n Object.defineProperty(e, 'target', { value: target });\n target.dispatchEvent(e);\n}\n\nlet desiredCheckpointName = null;\nexport function selectCheckpoint(name) {\n desiredCheckpointName = name;\n const tabName = getENActiveTab();\n const btnModel = gradioApp().getElementById(`${tabName}_extra_model`);\n const isRefiner = btnModel && btnModel.classList.contains('toolbutton-selected');\n if (isRefiner) gradioApp().getElementById('change_refiner').click();\n else gradioApp().getElementById('change_checkpoint').click();\n log(`selectCheckpoint ${isRefiner ? 'refiner' : 'model'}: ${desiredCheckpointName}`);\n markSelectedCards([desiredCheckpointName], 'model');\n setTimeout(requestProgress, 250);\n}\n\nlet desiredVAEName = null;\nexport function selectVAE(name) {\n desiredVAEName = name;\n gradioApp().getElementById('change_vae').click();\n log(`selectVAE: ${desiredVAEName}`);\n markSelectedCards([desiredVAEName], 'vae');\n}\n\nlet desiredUNetName = null;\n\nfunction consumeDesiredCheckpointName(v) {\n const res = desiredCheckpointName;\n desiredCheckpointName = null;\n return [res || v, null];\n}\n\nfunction consumeDesiredVAEName(v) {\n const res = desiredVAEName;\n desiredVAEName = null;\n return [res || v, null];\n}\n\nfunction consumeDesiredUNetName(v) {\n const res = desiredUNetName;\n desiredUNetName = null;\n return [res || v, null];\n}\n\nfunction getDesiredCheckpointName() {\n return desiredCheckpointName;\n}\n\nexport function selectUNet(name) {\n desiredUNetName = name;\n const tabName = getENActiveTab();\n const btnModel = gradioApp().getElementById(`${tabName}_extra_model`);\n const isSecondary = btnModel && btnModel.classList.contains('toolbutton-selected');\n if (isSecondary) gradioApp().getElementById('change_unet_secondary').click();\n else gradioApp().getElementById('change_unet').click();\n log(`selectUNet ${isSecondary ? 'secondary' : 'primary'}: ${desiredUNetName}`);\n markSelectedCards([desiredUNetName], 'unet');\n}\n\nexport function selectReference(name) {\n log(`selectReference: ${name}`);\n desiredCheckpointName = name;\n gradioApp().getElementById('change_reference').click();\n markSelectedCards([desiredCheckpointName], 'model');\n setTimeout(requestProgress, 250);\n}\n\nfunction currentImageResolutionimg2img(_a, _b, scaleBy) {\n const img = gradioApp().querySelector('#mode_img2img > div[style=\"display: block;\"] img');\n return img ? [img.naturalWidth, img.naturalHeight, scaleBy] : [0, 0, scaleBy];\n}\n\nfunction currentImageResolutioncontrol(_a, _b, scaleBy) {\n if (window.kanvas) {\n const active = window.kanvas.stages?.getActiveStage();\n return [active?.width || 0, active?.height || 0, scaleBy];\n }\n const img = gradioApp().querySelector('#control-tab-input > div[style=\"display: block;\"] img');\n return img ? [img.naturalWidth, img.naturalHeight, scaleBy] : [0, 0, scaleBy];\n}\n\nfunction updateImg2imgResizeToTextAfterChangingImage() {\n const el = gradioApp().getElementById('img2img_update_resize_to');\n if (el) setTimeout(() => gradioApp().getElementById('img2img_update_resize_to').click(), 500);\n return [];\n}\n\nfunction createThemeElement(): HTMLImageElement {\n const el = document.createElement('img');\n el.id = 'theme-preview';\n el.className = 'theme-preview';\n el.onclick = () => { el.style.display = 'none'; };\n document.body.appendChild(el);\n return el;\n}\n\nexport async function toggleCompact(val, old) {\n if (val === old) return;\n log('toggleCompact', val);\n if (val) {\n gradioApp().style.setProperty('--layout-gap', 'var(--spacing-md)');\n gradioApp().querySelectorAll('input[type=range]').forEach((el) => el.classList.add('hidden'));\n gradioApp().querySelectorAll('div .form').forEach((el) => el.classList.add('form-compact'));\n gradioApp().querySelectorAll('.small-accordion .label-wrap').forEach((el) => el.classList.add('accordion-compact'));\n } else {\n gradioApp().style.setProperty('--layout-gap', 'var(--spacing-xxl)');\n gradioApp().querySelectorAll('input[type=range]').forEach((el) => el.classList.remove('hidden'));\n gradioApp().querySelectorAll('div .form').forEach((el) => el.classList.remove('form-compact'));\n gradioApp().querySelectorAll('.small-accordion .label-wrap').forEach((el) => el.classList.remove('accordion-compact'));\n }\n}\n\nfunction previewTheme() {\n let name = gradioApp().getElementById('setting_gradio_theme').querySelectorAll('input')?.[0].value || '';\n authFetch(`${window.subpath}/file=data/themes.json`)\n .then((res) => {\n res.json()\n .then((themes) => {\n const theme = Array.isArray(themes) ? themes.find((t) => t.id === name) : null;\n if (theme) {\n window.open(theme.subdomain, '_blank');\n } else {\n const el = document.getElementById('theme-preview') as HTMLImageElement | null || createThemeElement();\n el.style.display = el.style.display === 'block' ? 'none' : 'block';\n name = name.replace('/', '-');\n el.src = `/file=ui/css/${name}.jpg`;\n }\n })\n .catch((e) => error(`previewTheme: ${e}`));\n })\n .catch((e) => error(`previewTheme: ${e}`));\n}\n\nasync function browseFolder() {\n const picker = window.showDirectoryPicker?.();\n if (!picker) return null;\n const f = await picker;\n if (f && f.kind === 'directory') return f.name;\n return null;\n}\n\nlet kanvasNotifyTimer: ReturnType | undefined;\n// Notify kanvas to resize its stage when the resize-panel width/height change. Wired through gradio's\n// .change so it also fires on programmatic updates (detect-size, paste params, swap, send-to) that the\n// client-side resolutionLock input listeners never see. Writes nothing back, so it cannot loop.\nexport function notifyKanvasResize(width: number, height: number) {\n if (window.resizeStage) {\n const w = Number(width);\n const h = Number(height);\n clearTimeout(kanvasNotifyTimer);\n kanvasNotifyTimer = setTimeout(() => window.resizeStage?.(w, h), 250);\n }\n}\n\nexport async function reconnectUI() {\n const t0 = performance.now();\n const gallery = gradioApp().getElementById('txt2img_gallery');\n const task_id = localStorage.getItem('task');\n const api_logo = Array.from(gradioApp().querySelectorAll('img')).filter((el) => el.src.endsWith('api-logo.svg'));\n if (api_logo.length > 0) api_logo[0].remove();\n if (task_id) {\n debug('task check:', task_id);\n requestProgress(task_id, null, gallery, null, null, true);\n }\n uiLoaded = true;\n\n const sd_model = gradioApp().getElementById('setting_sd_model_checkpoint');\n let loadingStarted = 0;\n let loadingMonitor: ReturnType | null = null;\n\n const sd_model_callback = async () => {\n const loading = sd_model.querySelector('.eta-bar');\n if (!loading) {\n loadingStarted = 0;\n clearInterval(loadingMonitor);\n updateModel();\n } else if (loadingStarted === 0) {\n loadingStarted = Date.now();\n loadingMonitor = setInterval(() => {\n const elapsed = Date.now() - loadingStarted;\n if (elapsed > 3000 && loading) loading.style.display = 'none';\n }, 5000);\n }\n };\n const sd_model_observer = new MutationObserver(sd_model_callback);\n sd_model_observer.observe(sd_model, { attributes: true, childList: true, subtree: true });\n const t1 = performance.now();\n log('reconnectUI', Math.round(t1 - t0));\n timer('reconnectUI', t1 - t0);\n}\n\nwindow.restartReload = restartReload;\nwindow.updateInput = updateInput;\nwindow.notifyKanvasResize = notifyKanvasResize;\nwindow.clip_gallery_urls = clip_gallery_urls;\nwindow.extract_image_from_gallery = extract_image_from_gallery;\nwindow.getCaptionActiveTab = getCaptionActiveTab;\nwindow.get_img2img_tab_index = get_img2img_tab_index;\nwindow.modelmerger = modelmerger;\nwindow.selected_gallery_index = selected_gallery_index;\nwindow.selected_gallery_files = selected_gallery_files;\nwindow.send_to_kanvas = send_to_kanvas;\nwindow.submit_control = submit_control;\nwindow.submit_framepack = submit_framepack;\nwindow.submit_img2img = submit_img2img;\nwindow.submit_ltx = submit_ltx;\nwindow.submit_minimax = submit_minimax;\nwindow.submit_postprocessing = submit_postprocessing;\nwindow.submit = submit_txt2img; // compatibility alias\nwindow.submit_txt2img = submit_txt2img;\nwindow.submit_video = submit_video;\nwindow.submit_video_wrapper = submit_video_wrapper;\nwindow.switch_to_txt2img = switch_to_txt2img;\nwindow.switch_to_img2img_tab = switch_to_img2img_tab;\nwindow.switch_to_img2img = switch_to_img2img;\nwindow.switch_to_inpaint = switch_to_inpaint;\nwindow.switch_to_sketch = switch_to_sketch;\nwindow.switch_to_composite = switch_to_composite;\nwindow.switch_to_extras = switch_to_extras;\nwindow.switch_to_control = switch_to_control;\nwindow.switch_to_video = switch_to_video;\nwindow.switch_to_caption = switch_to_caption;\nwindow.recalculate_prompts_txt2img = recalculate_prompts_txt2img;\nwindow.recalculate_prompts_img2img = recalculate_prompts_img2img;\nwindow.recalculate_prompts_inpaint = recalculate_prompts_inpaint;\nwindow.recalculate_prompts_control = recalculate_prompts_control;\nwindow.selectCheckpoint = selectCheckpoint;\nwindow.selectVAE = selectVAE;\nwindow.selectUNet = selectUNet;\nwindow.selectReference = selectReference;\nwindow.consumeDesiredCheckpointName = consumeDesiredCheckpointName;\nwindow.consumeDesiredVAEName = consumeDesiredVAEName;\nwindow.consumeDesiredUNetName = consumeDesiredUNetName;\nwindow.getDesiredCheckpointName = getDesiredCheckpointName;\nwindow.currentImageResolutionimg2img = currentImageResolutionimg2img;\nwindow.currentImageResolutioncontrol = currentImageResolutioncontrol;\nwindow.updateImg2imgResizeToTextAfterChangingImage = updateImg2imgResizeToTextAfterChangingImage;\nwindow.create_submit_args = create_submit_args;\nwindow.set_theme = set_theme;\n", "import { gradioApp } from './script';\nimport { updateInput } from './ui';\n\ntype AccordionElement = HTMLElement & {\n visibleCheckbox: HTMLInputElement;\n onVisibleCheckboxChange: () => void;\n onChecked: (checked: boolean) => void;\n};\n\nexport function inputAccordionChecked(id: string, checked: boolean): void {\n const accordion = gradioApp().getElementById(id);\n if (!(accordion instanceof HTMLElement)) return;\n const acc = accordion as AccordionElement;\n acc.visibleCheckbox.checked = checked;\n acc.onVisibleCheckboxChange();\n}\n\nfunction setupAccordion(accordion: Element): void {\n if (!(accordion instanceof HTMLElement)) return;\n const acc = accordion as AccordionElement;\n const labelWrap = accordion.querySelector('.label-wrap');\n const gradioCheckbox = gradioApp().querySelector(`#${accordion.id}-checkbox input`);\n const extra = gradioApp().querySelector(`#${accordion.id}-extra`);\n if (!(labelWrap instanceof HTMLElement) || !(gradioCheckbox instanceof HTMLInputElement)) return;\n const span = labelWrap.querySelector('span');\n if (!(span instanceof HTMLElement)) return;\n let linked = true;\n const isOpen = () => labelWrap.classList.contains('open');\n const observerAccordionOpen = new MutationObserver((mutations) => {\n mutations.forEach((mutationRecord) => {\n accordion.classList.toggle('input-accordion-open', isOpen());\n if (linked) {\n acc.visibleCheckbox.checked = isOpen();\n acc.onVisibleCheckboxChange();\n }\n });\n });\n observerAccordionOpen.observe(labelWrap, { attributes: true, attributeFilter: ['class'] });\n if (extra instanceof Node) labelWrap.insertBefore(extra, labelWrap.lastElementChild);\n acc.onChecked = (checked: boolean) => {\n if (isOpen() !== checked) labelWrap.click();\n };\n\n const visibleCheckbox = document.createElement('INPUT');\n visibleCheckbox.type = 'checkbox';\n visibleCheckbox.checked = isOpen();\n visibleCheckbox.id = `${accordion.id}-visible-checkbox`;\n visibleCheckbox.className = `${gradioCheckbox.className} input-accordion-checkbox`;\n span.insertBefore(visibleCheckbox, span.firstChild);\n acc.visibleCheckbox = visibleCheckbox as any;\n acc.onVisibleCheckboxChange = () => {\n if (linked && isOpen() !== visibleCheckbox.checked) labelWrap.click();\n gradioCheckbox.checked = visibleCheckbox.checked;\n updateInput(gradioCheckbox);\n };\n\n visibleCheckbox.addEventListener('click', (event) => {\n linked = false;\n event.stopPropagation();\n });\n visibleCheckbox.addEventListener('input', acc.onVisibleCheckboxChange);\n}\n\nwindow.inputAccordionChecked = inputAccordionChecked;\n\n// onUiLoaded(() => {\n// for (const accordion of gradioApp().querySelectorAll('.input-accordion')) setupAccordion(accordion);\n// });\n\nexport function initAccordions() {\n for (const accordion of gradioApp().querySelectorAll('.input-accordion')) setupAccordion(accordion);\n}\n", "/**\n * @type {?IDBDatabase}\n */\nimport { log } from './logger';\n\nlet db = null;\n\ninterface ThumbRecord {\n hash: string;\n folder?: string;\n [key: string]: unknown;\n}\n\nexport async function initIndexDB(): Promise {\n async function createDB(): Promise {\n return new Promise((resolve, reject) => {\n const request = indexedDB.open('SDNext', 2);\n request.onerror = (evt: Event) => reject(evt);\n request.onsuccess = (evt: Event) => {\n db = (evt.target as IDBOpenDBRequest).result;\n const countAll = db\n .transaction(['thumbs'], 'readwrite')\n .objectStore('thumbs')\n .count();\n countAll.onsuccess = () => log('initIndexDB', countAll.result);\n resolve();\n };\n request.onupgradeneeded = (evt: IDBVersionChangeEvent) => {\n db = (evt.target as IDBOpenDBRequest).result;\n const oldver = evt.oldVersion;\n if (oldver < 1) {\n const store = db.createObjectStore('thumbs', { keyPath: 'hash' });\n store.createIndex('hash', 'hash', { unique: true });\n }\n if (oldver < 2) {\n const existingStore = request.transaction.objectStore('thumbs');\n existingStore.createIndex('folder', 'folder', { unique: false });\n }\n resolve();\n };\n });\n }\n\n if (!db) await createDB();\n}\n\nexport function idbIsReady(): boolean {\n return db !== null;\n}\n\n/**\n * Reusable setup for handling IDB transactions.\n * @param {Object} resources - Required resources for implementation\n * @param {IDBTransaction} resources.transaction\n * @param {AbortSignal} resources.signal\n * @param {Function} resources.resolve\n * @param {Function} resources.reject\n * @param {*} resolveValue - Value to resolve the outer Promise with\n * @returns {() => void} - Function for manually aborting the transaction\n */\nfunction configureTransactionAbort({\n transaction,\n signal,\n resolve,\n reject,\n}: {\n transaction: IDBTransaction;\n signal: AbortSignal;\n resolve: (value: T) => void;\n reject: (reason?: unknown) => void;\n}, resolveValue: T): () => void {\n function abortTransaction() {\n signal.removeEventListener('abort', abortTransaction);\n transaction.abort();\n }\n signal.addEventListener('abort', abortTransaction);\n transaction.onabort = () => {\n signal.removeEventListener('abort', abortTransaction);\n reject(new DOMException(`Aborting database transaction. ${signal.reason}`, 'AbortError'));\n };\n transaction.onerror = (e) => {\n signal.removeEventListener('abort', abortTransaction);\n reject(new Error('Database transaction error.'));\n };\n transaction.oncomplete = () => {\n signal.removeEventListener('abort', abortTransaction);\n resolve(resolveValue);\n };\n return abortTransaction;\n}\n\nasync function add(record: ThumbRecord): Promise {\n if (!db) return null;\n return new Promise((resolve, reject) => {\n const request = db\n .transaction(['thumbs'], 'readwrite')\n .objectStore('thumbs')\n .add(record);\n request.onsuccess = (evt) => resolve(evt);\n request.onerror = (evt) => reject(evt);\n });\n}\n\nasync function del(hash: string): Promise {\n if (!db) return null;\n return new Promise((resolve, reject) => {\n const request = db\n .transaction(['thumbs'], 'readwrite')\n .objectStore('thumbs')\n .delete(hash);\n request.onsuccess = (evt) => resolve(evt);\n request.onerror = (evt) => reject(evt);\n });\n}\n\nasync function get(hash: string): Promise {\n if (!db) return null;\n return new Promise((resolve, reject) => {\n const request = db\n .transaction(['thumbs'], 'readonly')\n .objectStore('thumbs')\n .index('hash')\n .get(hash);\n request.onsuccess = () => resolve(request.result);\n request.onerror = (evt) => reject(evt);\n });\n}\n\nasync function getKeys(hash: string): Promise {\n if (!db) return null;\n return new Promise((resolve, reject) => {\n const request = db\n .transaction(['thumbs'], 'readonly')\n .objectStore('thumbs')\n .index('hash')\n .getAllKeys();\n request.onsuccess = () => resolve(request.result);\n request.onerror = (evt) => reject(evt);\n });\n}\n\nasync function put(record: ThumbRecord): Promise {\n if (!db) return null;\n return new Promise((resolve, reject) => {\n const request = db\n .transaction(['thumbs'], 'readwrite')\n .objectStore('thumbs')\n .put(record);\n request.onsuccess = (evt) => resolve(evt);\n request.onerror = (evt) => reject(evt);\n });\n}\n\nexport async function idbGetAllKeys(index: string | null = null, query: IDBValidKey | IDBKeyRange | null = null): Promise {\n if (!db) return null;\n return new Promise((resolve, reject) => {\n try {\n let request;\n const transaction = db.transaction('thumbs', 'readonly');\n transaction.onabort = (e) => reject(e);\n const store = transaction.objectStore('thumbs');\n if (index) request = store.index(index).getAllKeys(query);\n else request = store.getAllKeys(query);\n request.onsuccess = () => resolve(request.result);\n request.onerror = (e) => reject(e);\n } catch (err) {\n reject(err);\n }\n });\n}\n\n/**\n * Get the number of entries in the IndexedDB thumbnail cache.\n * @global\n * @param {IDBValidKey | IDBKeyRange | undefined} folder - If specified, get the count for this gallery folder. Otherwise get the total count.\n * @returns {Promise}\n */\nexport async function idbCount(folder?: IDBValidKey | IDBKeyRange): Promise {\n if (!db) return null;\n return new Promise((resolve, reject) => {\n try {\n let request;\n const transaction = db.transaction('thumbs', 'readonly');\n transaction.onabort = (e) => reject(e);\n const store = transaction.objectStore('thumbs');\n if (folder) request = store.index('folder').count(folder);\n else request = store.count();\n request.onsuccess = () => resolve(request.result);\n request.onerror = (e) => reject(e);\n } catch (err) {\n reject(err);\n }\n });\n}\n\n/**\n * Cleanup function for IndexedDB thumbnail cache.\n * @global\n * @param {Set} keepSet - Set containing the hashes of the current files in the folder\n * @param {IDBValidKey | IDBKeyRange} folder - Folder name/path or range\n * @param {AbortSignal} signal - Signal from the AbortController for thumbCacheCleanup()\n */\nexport async function idbFolderCleanup(keepSet: Set, folder: IDBValidKey | IDBKeyRange, signal: AbortSignal): Promise {\n if (!db) return null;\n const existing = await idbGetAllKeys('folder', folder);\n const removals = new Set((existing ?? []).map((entry) => String(entry)).filter((entry) => !keepSet.has(entry))); // Don't need to keep full set in memory\n const totalRemovals = removals.size;\n if (signal.aborted) {\n throw new Error(`Aborting. ${String(signal.reason)}`);\n }\n return new Promise((resolve, reject) => {\n const transaction = db.transaction('thumbs', 'readwrite');\n const props = { transaction, signal, resolve, reject };\n configureTransactionAbort(props, totalRemovals);\n const store = transaction.objectStore('thumbs');\n removals.forEach((entry) => { store.delete(entry); });\n });\n}\n\nexport async function idbClearAll(signal: AbortSignal): Promise {\n if (!db) return null;\n return new Promise((resolve, reject) => {\n const transaction = db.transaction(['thumbs'], 'readwrite');\n const props = { transaction, signal, resolve, reject };\n configureTransactionAbort(props, null);\n transaction.objectStore('thumbs').clear();\n });\n}\n\nexport const idbAdd = add;\nexport const idbDel = del;\nexport const idbGet = get;\nexport const idbPut = put;\nexport const idbKeys = getKeys;\n", "import { authFetch } from './authWrap';\nimport { log, error, xhrPost } from './logger';\nimport { timer } from './timers';\n\ninterface LogLine {\n created: number;\n level: string;\n module: string;\n facility: string;\n msg: string;\n}\n\nlet logMonitorEl: HTMLElement | null = null;\nlet logMonitorStatus = true;\nlet logWarnings = 0;\nlet logErrors = 0;\nlet logConnected = false;\n\nfunction dateToStr(ts: number): string {\n const dt = new Date(1000 * ts);\n // const year = dt.getFullYear();\n // const mo = String(dt.getMonth() + 1).padStart(2, '0');\n // const day = String(dt.getDate()).padStart(2, '0');\n const hour = String(dt.getHours()).padStart(2, '0');\n const min = String(dt.getMinutes()).padStart(2, '0');\n const sec = String(dt.getSeconds()).padStart(2, '0');\n const ms = String(dt.getMilliseconds()).padStart(3, '0');\n // const s = `${year}-${mo}-${day} ${hour}:${min}:${sec}.${ms}`;\n const s = `${hour}:${min}:${sec}.${ms}`;\n return s;\n}\n\nfunction htmlEscape(text: string): string {\n return text.replaceAll('&', '&').replaceAll('<', '<').replaceAll('>', '>');\n}\n\nfunction parseLogLine(line: string): LogLine {\n let str = line.replaceAll('\\n', ' ').replaceAll('\\\\', '\\\\\\\\');\n const tracebackIndex = str.indexOf('Traceback');\n if (tracebackIndex !== -1) str = str.substring(0, tracebackIndex);\n const parsed = JSON.parse(str) as Partial;\n return {\n created: Number(parsed.created ?? Date.now()),\n level: String(parsed.level ?? 'INFO'),\n module: String(parsed.module ?? 'logMonitor'),\n facility: String(parsed.facility ?? 'ui'),\n msg: String(parsed.msg ?? ''),\n };\n}\n\nasync function clearErrors(): Promise {\n logWarnings = 0;\n logErrors = 0;\n log('clearErrors');\n}\n\nexport async function initClearErrorsButton() {\n const btnServerClear = document.getElementById('btn_console_log_server_clear');\n if (btnServerClear) {\n btnServerClear.onclick = async (evt) => {\n evt.preventDefault();\n evt.stopPropagation();\n clearErrors();\n };\n }\n}\n\nasync function logMonitor() {\n const addLogLine = (line: string): void => {\n if (!logMonitorEl) logMonitorEl = document.getElementById('logMonitorData');\n if (!logMonitorEl) return;\n try {\n const l = parseLogLine(line);\n const row = document.createElement('tr');\n // row.style = 'padding: 10px; margin: 0;';\n const level = ``;\n if (l.level === 'WARNING') logWarnings++;\n if (l.level === 'ERROR') logErrors++;\n const module = ``;\n const facilityText = l.facility.length > 20 ? `${l.facility.substring(0, 20)}...` : l.facility;\n const facility = l.facility !== 'sd' ? `` : '';\n row.innerHTML = `${level}${facility}${module}`;\n logMonitorEl.appendChild(row);\n } catch (err) {\n error('logMonitor', { error: String(err), line });\n }\n };\n\n const cleanupLog = (atBottom: boolean): void => {\n if (!logMonitorEl) return;\n while (logMonitorEl.childElementCount > 100 && logMonitorEl.firstElementChild) {\n logMonitorEl.removeChild(logMonitorEl.firstElementChild);\n }\n if (atBottom) logMonitorEl.scrollTop = logMonitorEl.scrollHeight;\n else if (logMonitorEl.parentElement) logMonitorEl.parentElement.style.cssText = 'border-bottom: 2px solid var(--highlight-color);';\n const elWarn = document.getElementById('logWarnings');\n const elErr = document.getElementById('logErrors');\n const modenUIBtn = document.getElementById('btn_console');\n if (elWarn) elWarn.innerText = String(logWarnings);\n if (elErr) elErr.innerText = String(logErrors);\n if (modenUIBtn) {\n modenUIBtn.setAttribute('error-count', logErrors > 0 ? String(logErrors) : '');\n modenUIBtn.style.backgroundColor = logErrors > 0 ? 'var(--color-error)' : '';\n modenUIBtn.title = `Log\\nErrors ${logErrors}\\nWarnings ${logWarnings}`;\n }\n };\n\n const txtGallery = document.getElementById('txt2img_gallery');\n if (txtGallery) txtGallery.style.height = window.opts.logmonitor_show ? '50vh' : '55vh';\n const imgGallery = document.getElementById('img2img_gallery');\n if (imgGallery) imgGallery.style.height = window.opts.logmonitor_show ? '50vh' : '55vh';\n\n if (!window.opts.logmonitor_show) {\n Array.from(document.getElementsByClassName('log-monitor')).forEach((el) => {\n if (el instanceof HTMLElement) el.style.display = 'none';\n });\n return;\n }\n\n if (logMonitorStatus) setTimeout(logMonitor, window.opts.logmonitor_refresh_period);\n else setTimeout(logMonitor, 10 * 1000); // on failure try to reconnect every 10sec\n\n logMonitorStatus = false;\n if (!logMonitorEl) {\n logMonitorEl = document.getElementById('logMonitorData');\n if (logMonitorEl) {\n logMonitorEl.addEventListener('scroll', () => {\n const atBottom = logMonitorEl.scrollHeight <= (logMonitorEl.scrollTop + logMonitorEl.clientHeight);\n if (atBottom && logMonitorEl.parentElement) logMonitorEl.parentElement.style.cssText = '';\n });\n }\n }\n if (!logMonitorEl) return;\n const atBottom = logMonitorEl.scrollHeight <= (logMonitorEl.scrollTop + logMonitorEl.clientHeight);\n\n try {\n const res = await authFetch(`${window.api}/log?clear=True`);\n if (res?.ok) {\n logMonitorStatus = true;\n const lines = (await res.json()) as string[];\n if (logMonitorEl && lines?.length > 0 && logMonitorEl.parentElement?.parentElement instanceof HTMLElement) {\n logMonitorEl.parentElement.parentElement.style.display = window.opts.logmonitor_show ? 'block' : 'none';\n }\n if (!logConnected) {\n logConnected = true;\n xhrPost(`${window.api}/log`, { debug: 'connected' });\n logErrors = 0; // reset error count on reconnect\n }\n for (const line of lines) addLogLine(line);\n } else {\n logConnected = false;\n logErrors++;\n if (res) addLogLine(`{ \"created\": ${Date.now()}, \"level\":\"ERROR\", \"module\":\"logMonitor\", \"facility\":\"ui\", \"msg\":\"Failed to fetch log: ${res?.status} ${res?.statusText}\" }`);\n else addLogLine(`{ \"created\": ${Date.now()}, \"level\":\"ERROR\", \"module\":\"logMonitor\", \"facility\":\"ui\", \"msg\":\"Server unreachable\" }`);\n }\n cleanupLog(atBottom);\n } catch {\n logConnected = false;\n logErrors++;\n addLogLine(`{ \"created\": ${Date.now()}, \"level\":\"ERROR\", \"module\":\"logMonitor\", \"facility\":\"ui\", \"msg\":\"Server unreachable\" }`);\n cleanupLog(atBottom);\n }\n}\n\nexport async function initLogMonitor() {\n let el = document.getElementById('logMonitorPlaceholder');\n const modernUi = Boolean(el);\n if (!el) el = document.getElementsByTagName('footer')[0];\n if (!el) return;\n const t0 = performance.now();\n el.classList.add('log-monitor');\n const uiDisabled = Array.isArray(window.opts.ui_disabled) ? window.opts.ui_disabled : [];\n if (uiDisabled.includes('logs')) return;\n if (modernUi) {\n el.style.overflow = 'auto';\n el.innerHTML = `\n
${l.level}${l.module}${facilityText}${dateToStr(l.created)}${htmlEscape(l.msg)}
\n \n \n
\n `;\n } else {\n el.innerHTML = `\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
TimeLevelModuleMessageWarnings 0Errors 0
\n `;\n }\n el.style.display = 'none';\n authFetch(`${window.api}/start?agent=${encodeURI(navigator.userAgent)}`);\n logMonitor();\n initClearErrorsButton();\n const t1 = performance.now();\n log('initLogMonitor', { show: window.opts.logmonitor_show, time: Math.round(t1 - t0) });\n timer('initLogMonitor', t1 - t0);\n}\n", "import { authFetch } from './authWrap';\nimport { gradioApp, onAfterUiUpdate, onOptionsChanged, executeCallbacks, optionsChangedCallbacks } from './script';\nimport { log, debug, error } from './logger';\nimport { getENActiveTab } from './extraNetworks';\nimport { registerDragDrop, toggleCompact, setTheme, setFontSize, updateInput } from './ui';\nimport { timer } from './timers';\n\nlet settingsInitialized = false;\nlet opts_metadata = {};\nconst opts_tabs = {};\n\nfunction getSettingsTabs() {\n let nodes = gradioApp().querySelectorAll('#tab_settings .tabitem');\n if (!nodes || nodes.length === 0) nodes = gradioApp().querySelectorAll('.tab-content .tabitem');\n return nodes;\n}\n\nconst monitoredOpts: Record[] = [\n { sd_model_checkpoint: null },\n { sd_backend: () => gradioApp().getElementById('refresh_sd_model_checkpoint')?.click() },\n];\n\nexport function monitorOption(option, callback) {\n monitoredOpts.push({ [option]: callback });\n}\n\nconst AppyOpts = [ // monitored opts\n { compact_view: (val, old) => toggleCompact(val, old) },\n { gradio_theme: (val, old) => setTheme(val, old) },\n { font_size: (val, old) => setFontSize(val, old) },\n];\n\nasync function updateOpts(json_string) {\n const t0 = performance.now();\n const settings_data = JSON.parse(json_string);\n const new_opts = settings_data.values;\n opts_metadata = settings_data.metadata;\n\n const t1 = performance.now();\n for (const op of monitoredOpts) {\n const [key, callback] = Object.entries(op)[0];\n if (Object.hasOwn(opts, key) && opts[key] !== new_opts[key]) {\n log('updateOpt', { key, val: new_opts[key] });\n if (callback) callback(new_opts[key], opts[key]);\n }\n }\n\n for (const op of AppyOpts) {\n const [key, callback] = Object.entries(op)[0];\n if (callback) {\n const t3 = performance.now();\n callback(new_opts[key], opts[key]);\n const t4 = performance.now();\n if (t4 - t3 > 100) debug('AppyOptSlow', key, `time=${Math.round(t4 - t3)}`);\n }\n }\n\n window.opts = new_opts;\n Object.entries(opts_metadata as Record).forEach(([opt, meta]: [string, any]) => {\n if (!opts_tabs[meta.tab_name]) opts_tabs[meta.tab_name] = {};\n if (!opts_tabs[meta.tab_name].unsaved_keys) opts_tabs[meta.tab_name].unsaved_keys = new Set();\n if (!opts_tabs[meta.tab_name].saved_keys) opts_tabs[meta.tab_name].saved_keys = new Set();\n if (!meta.is_stored) opts_tabs[meta.tab_name].unsaved_keys.add(opt);\n else opts_tabs[meta.tab_name].saved_keys.add(opt);\n });\n const t2 = performance.now();\n log('updateOpts', { settings: Object.keys(new_opts).length, callbacks: Math.round(t2 - t1), apply: Math.round(t1 - t0) });\n timer('updateOpts', t2 - t0);\n}\n\nfunction showAllSettings() {\n // Try to ensure that the show all settings tab is opened by clicking on its tab button\n // const tab_dirty_indicator = gradioApp().getElementById('modification_indicator_show_all_pages');\n // if (tab_dirty_indicator && tab_dirty_indicator.nextSibling) tab_dirty_indicator.nextSibling.click();\n getSettingsTabs().forEach((elem) => {\n if (elem.id === 'settings_tab_licenses' || elem.id === 'settings_show_all_pages') return;\n elem.style.display = 'block';\n });\n}\n\nfunction markIfModified(setting_name, value) {\n if (!opts_metadata[setting_name]) return;\n const elem = gradioApp().getElementById(`modification_indicator_${setting_name}`);\n if (!elem) return;\n const previous_value = JSON.stringify(opts[setting_name]);\n const current_value = JSON.stringify(value);\n const changed_value = previous_value !== current_value;\n if (changed_value) elem.title = `click to revert to previous value: ${previous_value}`;\n const { is_stored } = opts_metadata[setting_name];\n if (is_stored) elem.title = 'custom value';\n elem.disabled = !changed_value && !is_stored;\n elem.classList.toggle('changed', changed_value);\n elem.classList.toggle('saved', is_stored);\n\n const { tab_name } = opts_metadata[setting_name];\n if (!opts_tabs[tab_name].changed) opts_tabs[tab_name].changed = new Set();\n const changed_items = opts_tabs[tab_name].changed;\n if (changed_value) changed_items.add(setting_name);\n else changed_items.delete(setting_name);\n const unsaved = opts_tabs[tab_name].unsaved_keys;\n const saved = opts_tabs[tab_name].saved_keys;\n\n // Set the indicator on the tab nav element\n const tab_nav_indicator = gradioApp().getElementById(`modification_indicator_${tab_name}`);\n tab_nav_indicator.disabled = (changed_items.size === 0) && (unsaved.size === 0);\n tab_nav_indicator.title = '';\n tab_nav_indicator.classList.toggle('changed', changed_items.size > 0);\n tab_nav_indicator.classList.toggle('saved', saved.size > 0);\n if (changed_items.size > 0) tab_nav_indicator.title += `click to reset ${changed_items.size} unapplied changes in this tab\\n`;\n if (saved.size > 0) tab_nav_indicator.title += `${saved.size} custom values\\n${unsaved.size} default values`;\n // TODO why is scroll happening on every change if all pages are visible?\n // elem.scrollIntoView({ behavior: 'smooth', block: 'center' });\n}\nwindow.markIfModified = markIfModified;\n\nfunction updateAllOpts() {\n if (Object.keys(opts).length !== 0) return false;\n const json_elem = gradioApp().getElementById('settings_json');\n log('updateAllOpts', !!json_elem);\n if (!json_elem) return false;\n json_elem.parentElement.style.display = 'none';\n const textarea = json_elem.querySelector('textarea');\n const jsdata = textarea.value;\n updateOpts(jsdata);\n return true;\n}\n\nasync function onAfterUiUpdateCallback() {\n if (!updateAllOpts()) return;\n const json_elem = gradioApp().getElementById('settings_json');\n const textarea = json_elem.querySelector('textarea');\n executeCallbacks(optionsChangedCallbacks);\n registerDragDrop();\n\n Object.defineProperty(textarea, 'value', {\n set(newValue) {\n const valueProp = Object.getOwnPropertyDescriptor(HTMLTextAreaElement.prototype, 'value');\n const oldValue = valueProp.get.call(textarea);\n valueProp.set.call(textarea, newValue);\n if (oldValue !== newValue) updateOpts(textarea.value);\n executeCallbacks(optionsChangedCallbacks);\n },\n get() {\n const valueProp = Object.getOwnPropertyDescriptor(HTMLTextAreaElement.prototype, 'value');\n return valueProp.get.call(textarea);\n },\n });\n\n const settingsSearch = gradioApp().querySelectorAll('#settings_search > label > textarea')[0];\n let settingsTimer: ReturnType | undefined;\n let settingSearchValue = '';\n\n function doSettingsSearch() {\n if (settingSearchValue === settingsSearch.value.trim().toLowerCase()) return;\n showAllSettings();\n const value = settingsSearch.value.trim().toLowerCase();\n log('doSettingsSearch', value);\n settingSearchValue = value;\n getSettingsTabs().forEach((section) => {\n section.querySelectorAll('.dirtyable').forEach((setting) => {\n const visible = setting.innerText.toLowerCase().includes(value) || setting.id.toLowerCase().includes(value);\n const parent = setting.closest('.settings_section');\n if (!visible) parent.style.display = 'none';\n else parent.style.removeProperty('display');\n });\n });\n }\n\n settingsSearch.oninput = (e) => {\n if (settingsTimer) clearTimeout(settingsTimer);\n settingsTimer = setTimeout(doSettingsSearch, 250);\n };\n settingsSearch.onkeypress = (e) => {\n if (e.key === 'Enter') {\n if (settingsTimer) clearTimeout(settingsTimer);\n doSettingsSearch();\n }\n };\n}\n\nonAfterUiUpdate(onAfterUiUpdateCallback);\n\nasync function onOptionsChangedCallback() {\n const setting_elems = gradioApp().querySelectorAll('#settings [id^=\"setting_\"]');\n setting_elems.forEach((elem) => {\n const setting_name = elem.id.replace('setting_', '');\n markIfModified(setting_name, opts[setting_name]);\n });\n}\n\nonOptionsChanged(onOptionsChangedCallback);\n\nexport async function initModels() {\n const warn = () => `\n

No models available

\n - Select a model from reference list to download or
\n - Set model path to a folder containing your models
\n Current model path: ${opts.ckpt_dir}
\n `;\n const el = gradioApp().getElementById('main_info');\n const en = gradioApp().getElementById('txt2img_extra_networks');\n if (!el || !en) return;\n const req = await authFetch(`${window.api}/sd-models`);\n const res = req.ok ? await req.json() : [];\n log('initModels', res.length);\n const ready = () => `\n

Ready

\n ${res.length} models available
\n `;\n el.innerHTML = res.length > 0 ? ready() : warn();\n el.style.display = 'block';\n setTimeout(() => { el.style.display = 'none'; }, res.length === 0 ? 30000 : 1500);\n if (res.length === 0) {\n if (en.classList.contains('hide')) gradioApp().getElementById('txt2img_extra_networks_btn').click();\n const repeat = setInterval(() => {\n const buttons = Array.from(gradioApp().querySelectorAll('#txt2img_model_subdirs > button')) || [];\n const reference = buttons.find((b) => (b.innerText === 'Reference') || (b.innerText === 'Distilled') || (b.innerText === 'Community') || (b.innerText === 'Quantized') || (b.innerText === 'Cloud'));\n if (reference) {\n clearInterval(repeat);\n reference.click();\n log('enReferenceSelect');\n }\n }, 100);\n }\n}\n\nexport async function initSettings() {\n if (settingsInitialized) return;\n const t0 = performance.now();\n settingsInitialized = true;\n const tabNavElements = gradioApp().querySelector('#settings > .tab-nav');\n if (!tabNavElements) {\n error('initSettings', 'No tab nav elements found');\n return;\n }\n const tabNavButtons = gradioApp().querySelectorAll('#settings > .tab-nav > button');\n const tabElements = gradioApp().querySelectorAll('#settings > div:not(.tab-nav)');\n const observer = new MutationObserver((mutations) => {\n const showAllPages = gradioApp().getElementById('settings_show_all_pages');\n if (showAllPages.style.display === 'none') return;\n const mutation = (mut) => mut.type === 'attributes' && mut.attributeName === 'style';\n if (mutations.some(mutation)) showAllSettings();\n });\n const tabContentWrapper = document.createElement('div');\n tabContentWrapper.className = 'tab-content';\n tabNavElements.parentElement.insertBefore(tabContentWrapper, tabNavElements.nextSibling);\n tabElements.forEach((elem, index) => {\n const tabName = elem.id.replace('settings_section_tab_', '');\n const indicator = gradioApp().getElementById(`modification_indicator_${tabName}`);\n if (indicator) {\n tabNavElements.insertBefore(document.createElement('br'), tabNavButtons[index]);\n tabNavElements.insertBefore(indicator, tabNavButtons[index]);\n }\n tabContentWrapper.appendChild(elem);\n observer.observe(elem, { attributes: true, attributeFilter: ['style'] });\n });\n const t1 = performance.now();\n log('initSettings', Math.round(t1 - t0));\n timer('initSettings', t1 - t0);\n}\n", "import { debug, log } from './logger';\nimport { authFetch } from './authWrap';\nimport { monitorOption } from './settings';\n\ninterface VersionInfo {\n updated?: string;\n commit?: string;\n branch?: string;\n model?: string;\n}\n\nlet monitorActive = false;\nlet wsTimer: ReturnType | undefined;\n\nexport class ConnectionMonitorState {\n static ws: WebSocket | undefined;\n static url = '';\n static delay = 2000;\n static element: HTMLElement | undefined;\n static version = '';\n static commit = '';\n static branch = '';\n static model = '';\n static startup: Date = new Date();\n static online = false;\n static ts: Date = new Date();\n\n static getModel(): string {\n const cp = window.opts?.sd_model_checkpoint || '';\n return cp ? this.trimModelName(cp) : 'unknown model';\n }\n\n static trimModelName(name: string): string {\n return name.replace(/\\s*\\[.*\\]\\s*$/, '').split(/[\\\\/]/).pop().trim() || 'unknown model';\n }\n\n static setData({ online, data }: { online: boolean; data: VersionInfo }) {\n if (online !== this.online) {\n this.online = online;\n this.ts = new Date();\n debug('monitorState', { online: ConnectionMonitorState.online, ts: ConnectionMonitorState.ts?.toLocaleTimeString() });\n }\n if (data?.updated) this.version = data.updated;\n if (data?.commit) this.commit = data.commit;\n if (data?.branch) this.branch = data.branch;\n if (data?.model) this.model = this.trimModelName(data.model);\n }\n\n static toHTML(): string {\n if (!this.model) this.model = this.getModel();\n return `\n Version: ${this.version}
\n Commit: ${this.commit}
\n Branch: ${this.branch}
\n Status: ${this.online ? 'online' : 'offline'}
\n Model: ${this.model}
\n Since: ${this.startup.toLocaleString()}
\n `;\n }\n\n static updateState() {\n if (!this.element) {\n const el = document.getElementById('logo_nav');\n if (el) this.element = el;\n else return;\n }\n this.element.dataset.hint = this.toHTML();\n this.element.style.backgroundColor = this.online ? 'var(--sd-main-accent-color)' : 'var(--color-error)';\n }\n}\n\nasync function updateIndicator(online: boolean, data: VersionInfo = {}, msg?: string): Promise {\n ConnectionMonitorState.setData({ online, data });\n ConnectionMonitorState.updateState();\n if (msg) log('monitorConnection:', { online, data, msg });\n}\n\nfunction scheduleNextLoop() {\n if (wsTimer) {\n clearTimeout(wsTimer);\n wsTimer = undefined;\n }\n const offlineDurationMs = Date.now() - ConnectionMonitorState.ts.getTime();\n if (!ConnectionMonitorState.online && offlineDurationMs > (60 * 60 * 1000)) ConnectionMonitorState.delay = 10000;\n else if (!ConnectionMonitorState.online && offlineDurationMs > (5 * 60 * 1000)) ConnectionMonitorState.delay = 5000;\n else ConnectionMonitorState.delay = 1000;\n wsTimer = setTimeout(wsMonitorLoop, ConnectionMonitorState.delay); // eslint-disable-line @typescript-eslint/no-use-before-define\n}\n\nasync function wsMonitorLoop() {\n // Tear down any existing socket before creating a new one\n if (ConnectionMonitorState.ws) {\n ConnectionMonitorState.ws.onopen = null;\n ConnectionMonitorState.ws.onmessage = null;\n ConnectionMonitorState.ws.onclose = null;\n ConnectionMonitorState.ws.onerror = null;\n try {\n ConnectionMonitorState.ws.close();\n } catch {\n // Ignore cleanup errors on stale sockets\n }\n ConnectionMonitorState.ws = undefined;\n }\n\n try {\n ConnectionMonitorState.ws = new WebSocket(`${ConnectionMonitorState.url}/internal/monitor`);\n ConnectionMonitorState.ws.onopen = () => updateIndicator(true);\n ConnectionMonitorState.ws.onmessage = (msg: MessageEvent) => updateIndicator(true, msg.data ? JSON.parse(msg.data) : {});\n ConnectionMonitorState.ws.onclose = () => {\n updateIndicator(false);\n scheduleNextLoop();\n };\n ConnectionMonitorState.ws.onerror = (e: Event) => updateIndicator(false, {}, String((e as ErrorEvent).message || 'unknown error'));\n } catch (e) {\n updateIndicator(false, {}, String((e as Error).message || e));\n scheduleNextLoop();\n }\n}\n\nexport async function monitorConnection() {\n if (!monitorActive) { // start monitor loop only once on startup\n monitorActive = true;\n monitorOption('sd_model_checkpoint', (newVal) => { // runs before opt actually changes\n ConnectionMonitorState.model = newVal;\n ConnectionMonitorState.updateState();\n });\n }\n ConnectionMonitorState.startup = new Date();\n\n let data: VersionInfo = {};\n try {\n const res = await authFetch(`${window.api}/version`);\n if (!res) throw new Error('No response');\n data = await res.json();\n log('monitorConnection:', { data });\n ConnectionMonitorState.startup = new Date();\n ConnectionMonitorState.url = res.url.split('/sdapi')[0].replace('https:', 'wss:').replace('http:', 'ws:'); // update global url as ws need fqdn\n updateIndicator(true, data);\n wsMonitorLoop();\n } catch {\n updateIndicator(false, data);\n scheduleNextLoop();\n }\n}\n", "// Stable Diffusion WebUI - Bracket checker\n// By Hingashi no Florin/Bwin4L & @akx\n// Counts open and closed brackets (round, square, curly) in the prompt and negative prompt text boxes in the txt2img and img2img tabs.\n// If there's a mismatch, the keyword counter turns red and if you hover on it, a tooltip tells you what's wrong.\n\nimport { gradioApp } from './script';\nimport { log } from './logger';\nimport { timer } from './timers';\n\nfunction checkBrackets(textArea: HTMLTextAreaElement, counterElt: HTMLElement): void {\n const counts: Record = {};\n const errors: string[] = [];\n\n function checkPair(open: string, close: string, kind: string): void {\n if (counts[open] !== counts[close]) errors.push(`${open}...${close} - Detected ${counts[open] || 0} opening and ${counts[close] || 0} closing ${kind}.`);\n }\n\n (textArea.value.match(/[(){}[\\]]/g) || []).forEach((bracket) => { counts[bracket] = (counts[bracket] || 0) + 1; });\n checkPair('(', ')', 'round brackets');\n checkPair('[', ']', 'square brackets');\n checkPair('{', '}', 'curly brackets');\n counterElt.title = errors.join('\\n');\n counterElt.classList.toggle('error', errors.length !== 0);\n}\n\nfunction setupBracketChecking(idPrompt: string, idCounter: string): void {\n const textarea = gradioApp().querySelector(`#${idPrompt} > label > textarea`);\n const counter = gradioApp().getElementById(idCounter);\n if (!(textarea instanceof HTMLTextAreaElement) || !counter) return;\n textarea.addEventListener('input', () => checkBrackets(textarea, counter));\n}\n\nexport async function initPromptChecker() {\n const t0 = performance.now();\n setupBracketChecking('txt2img_prompt', 'txt2img_token_counter');\n setupBracketChecking('txt2img_neg_prompt', 'txt2img_negative_token_counter');\n setupBracketChecking('img2img_prompt', 'img2img_token_counter');\n setupBracketChecking('img2img_neg_prompt', 'img2img_negative_token_counter');\n setupBracketChecking('control_prompt', 'control_token_counter');\n setupBracketChecking('control_neg_prompt', 'control_negative_token_counter');\n setupBracketChecking('video_prompt', 'video_token_counter');\n setupBracketChecking('video_neg_prompt', 'video_negative_token_counter');\n const t1 = performance.now();\n log('initPromptChecker', Math.round(t1 - t0));\n timer('initPromptChecker', t1 - t0);\n}\n", "// @ts-nocheck\n\n// SHA-256 (+ HMAC and PBKDF2) for JavaScript.\n//\n// Written in 2014-2016 by Dmitry Chestnykh.\n// Public domain, no warranty.\n//\n// Functions (accept and return Uint8Arrays):\n//\n// sha256(message) -> hash\n// sha256.hmac(key, message) -> mac\n// sha256.pbkdf2(password, salt, rounds, dkLen) -> dk\n//\n// Classes:\n//\n// new sha256.Hash()\n// new sha256.HMAC(key)\n//\n\n\nconst digestLength = 32;\nconst blockSize = 64;\n\n// SHA-256 constants\n\nconst K = new Uint32Array([\n 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b,\n 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01,\n 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7,\n 0xc19bf174, 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,\n 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 0x983e5152,\n 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147,\n 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc,\n 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,\n 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819,\n 0xd6990624, 0xf40e3585, 0x106aa070, 0x19a4c116, 0x1e376c08,\n 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f,\n 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,\n 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2,\n]);\nfunction hashBlocks(w, v, p, pos, len) {\n let a; let b; let c; let d; let e; let f; let g; let h; let u; let i; let j; let t1; let\n t2;\n while (len >= 64) {\n a = v[0];\n b = v[1];\n c = v[2];\n d = v[3];\n e = v[4];\n f = v[5];\n g = v[6];\n h = v[7];\n for (i = 0; i < 16; i++) {\n j = pos + i * 4;\n w[i] = (((p[j] & 0xff) << 24) | ((p[j + 1] & 0xff) << 16)\n | ((p[j + 2] & 0xff) << 8) | (p[j + 3] & 0xff));\n }\n for (i = 16; i < 64; i++) {\n u = w[i - 2];\n t1 = (u >>> 17 | u << (32 - 17)) ^ (u >>> 19 | u << (32 - 19)) ^ (u >>> 10);\n u = w[i - 15];\n t2 = (u >>> 7 | u << (32 - 7)) ^ (u >>> 18 | u << (32 - 18)) ^ (u >>> 3);\n w[i] = (t1 + w[i - 7] | 0) + (t2 + w[i - 16] | 0);\n }\n for (i = 0; i < 64; i++) {\n t1 = (((((e >>> 6 | e << (32 - 6)) ^ (e >>> 11 | e << (32 - 11))\n ^ (e >>> 25 | e << (32 - 25))) + ((e & f) ^ (~e & g))) | 0)\n + ((h + ((K[i] + w[i]) | 0)) | 0)) | 0;\n t2 = (((a >>> 2 | a << (32 - 2)) ^ (a >>> 13 | a << (32 - 13))\n ^ (a >>> 22 | a << (32 - 22))) + ((a & b) ^ (a & c) ^ (b & c))) | 0;\n h = g;\n g = f;\n f = e;\n e = (d + t1) | 0;\n d = c;\n c = b;\n b = a;\n a = (t1 + t2) | 0;\n }\n v[0] += a;\n v[1] += b;\n v[2] += c;\n v[3] += d;\n v[4] += e;\n v[5] += f;\n v[6] += g;\n v[7] += h;\n pos += 64;\n len -= 64;\n }\n return pos;\n}\n// Hash implements SHA256 hash algorithm.\nconst Hash = /** @class */ (function () {\n function Hash() {\n this.digestLength = digestLength;\n this.blockSize = blockSize;\n // Note: Int32Array is used instead of Uint32Array for performance reasons.\n this.state = new Int32Array(8); // hash state\n this.temp = new Int32Array(64); // temporary state\n this.buffer = new Uint8Array(128); // buffer for data to hash\n this.bufferLength = 0; // number of bytes in buffer\n this.bytesHashed = 0; // number of total bytes hashed\n this.finished = false; // indicates whether the hash was finalized\n this.reset();\n }\n // Resets hash state making it possible\n // to reuse this instance to hash other data.\n Hash.prototype.reset = function () {\n this.state[0] = 0x6a09e667;\n this.state[1] = 0xbb67ae85;\n this.state[2] = 0x3c6ef372;\n this.state[3] = 0xa54ff53a;\n this.state[4] = 0x510e527f;\n this.state[5] = 0x9b05688c;\n this.state[6] = 0x1f83d9ab;\n this.state[7] = 0x5be0cd19;\n this.bufferLength = 0;\n this.bytesHashed = 0;\n this.finished = false;\n return this;\n };\n // Cleans internal buffers and re-initializes hash state.\n Hash.prototype.clean = function () {\n for (var i = 0; i < this.buffer.length; i++) {\n this.buffer[i] = 0;\n }\n for (var i = 0; i < this.temp.length; i++) {\n this.temp[i] = 0;\n }\n this.reset();\n };\n // Updates hash state with the given data.\n //\n // Optionally, length of the data can be specified to hash\n // fewer bytes than data.length.\n //\n // Throws error when trying to update already finalized hash:\n // instance must be reset to use it again.\n Hash.prototype.update = function (data, dataLength) {\n if (dataLength === void 0) { dataLength = data.length; }\n if (this.finished) {\n throw new Error(\"SHA256: can't update because hash was finished.\");\n }\n let dataPos = 0;\n this.bytesHashed += dataLength;\n if (this.bufferLength > 0) {\n while (this.bufferLength < 64 && dataLength > 0) {\n this.buffer[this.bufferLength++] = data[dataPos++];\n dataLength--;\n }\n if (this.bufferLength === 64) {\n hashBlocks(this.temp, this.state, this.buffer, 0, 64);\n this.bufferLength = 0;\n }\n }\n if (dataLength >= 64) {\n dataPos = hashBlocks(this.temp, this.state, data, dataPos, dataLength);\n dataLength %= 64;\n }\n while (dataLength > 0) {\n this.buffer[this.bufferLength++] = data[dataPos++];\n dataLength--;\n }\n return this;\n };\n // Finalizes hash state and puts hash into out.\n //\n // If hash was already finalized, puts the same value.\n Hash.prototype.finish = function (out) {\n if (!this.finished) {\n const bytesHashed = this.bytesHashed;\n const left = this.bufferLength;\n const bitLenHi = (bytesHashed / 0x20000000) | 0;\n const bitLenLo = bytesHashed << 3;\n const padLength = (bytesHashed % 64 < 56) ? 64 : 128;\n this.buffer[left] = 0x80;\n for (let i = left + 1; i < padLength - 8; i++) {\n this.buffer[i] = 0;\n }\n this.buffer[padLength - 8] = (bitLenHi >>> 24) & 0xff;\n this.buffer[padLength - 7] = (bitLenHi >>> 16) & 0xff;\n this.buffer[padLength - 6] = (bitLenHi >>> 8) & 0xff;\n this.buffer[padLength - 5] = (bitLenHi >>> 0) & 0xff;\n this.buffer[padLength - 4] = (bitLenLo >>> 24) & 0xff;\n this.buffer[padLength - 3] = (bitLenLo >>> 16) & 0xff;\n this.buffer[padLength - 2] = (bitLenLo >>> 8) & 0xff;\n this.buffer[padLength - 1] = (bitLenLo >>> 0) & 0xff;\n hashBlocks(this.temp, this.state, this.buffer, 0, padLength);\n this.finished = true;\n }\n for (let i = 0; i < 8; i++) {\n out[i * 4 + 0] = (this.state[i] >>> 24) & 0xff;\n out[i * 4 + 1] = (this.state[i] >>> 16) & 0xff;\n out[i * 4 + 2] = (this.state[i] >>> 8) & 0xff;\n out[i * 4 + 3] = (this.state[i] >>> 0) & 0xff;\n }\n return this;\n };\n // Returns the final hash digest.\n Hash.prototype.digest = function () {\n const out = new Uint8Array(this.digestLength);\n this.finish(out);\n return out;\n };\n // Internal function for use in HMAC for optimization.\n Hash.prototype._saveState = function (out) {\n for (let i = 0; i < this.state.length; i++) {\n out[i] = this.state[i];\n }\n };\n // Internal function for use in HMAC for optimization.\n Hash.prototype._restoreState = function (from, bytesHashed) {\n for (let i = 0; i < this.state.length; i++) {\n this.state[i] = from[i];\n }\n this.bytesHashed = bytesHashed;\n this.finished = false;\n this.bufferLength = 0;\n };\n return Hash;\n}());\nwindow.Hash = Hash;\n// HMAC implements HMAC-SHA256 message authentication algorithm.\nconst HMAC = /** @class */ (function () {\n function HMAC(key) {\n this.inner = new Hash();\n this.outer = new Hash();\n this.blockSize = this.inner.blockSize;\n this.digestLength = this.inner.digestLength;\n const pad = new Uint8Array(this.blockSize);\n if (key.length > this.blockSize) {\n (new Hash()).update(key).finish(pad).clean();\n } else {\n for (let i = 0; i < key.length; i++) {\n pad[i] = key[i];\n }\n }\n for (let i = 0; i < pad.length; i++) {\n pad[i] ^= 0x36;\n }\n this.inner.update(pad);\n for (let i = 0; i < pad.length; i++) {\n pad[i] ^= 0x36 ^ 0x5c;\n }\n this.outer.update(pad);\n this.istate = new Uint32Array(8);\n this.ostate = new Uint32Array(8);\n this.inner._saveState(this.istate);\n this.outer._saveState(this.ostate);\n for (let i = 0; i < pad.length; i++) {\n pad[i] = 0;\n }\n }\n // Returns HMAC state to the state initialized with key\n // to make it possible to run HMAC over the other data with the same\n // key without creating a new instance.\n HMAC.prototype.reset = function () {\n this.inner._restoreState(this.istate, this.inner.blockSize);\n this.outer._restoreState(this.ostate, this.outer.blockSize);\n return this;\n };\n // Cleans HMAC state.\n HMAC.prototype.clean = function () {\n for (let i = 0; i < this.istate.length; i++) {\n this.ostate[i] = this.istate[i] = 0;\n }\n this.inner.clean();\n this.outer.clean();\n };\n // Updates state with provided data.\n HMAC.prototype.update = function (data) {\n this.inner.update(data);\n return this;\n };\n // Finalizes HMAC and puts the result in out.\n HMAC.prototype.finish = function (out) {\n if (this.outer.finished) {\n this.outer.finish(out);\n } else {\n this.inner.finish(out);\n this.outer.update(out, this.digestLength).finish(out);\n }\n return this;\n };\n // Returns message authentication code.\n HMAC.prototype.digest = function () {\n const out = new Uint8Array(this.digestLength);\n this.finish(out);\n return out;\n };\n return HMAC;\n}());\nwindow.HMAC = HMAC;\n// Returns SHA256 hash of data.\nfunction hash(data) {\n const h = (new Hash()).update(data);\n const digest = h.digest();\n h.clean();\n return digest;\n}\nwindow.hash = hash;\n// Function hash is both available as module.hash and as default export.\n// Returns HMAC-SHA256 of data under the key.\nfunction hmac(key, data) {\n const h = (new HMAC(key)).update(data);\n const digest = h.digest();\n h.clean();\n return digest;\n}\nwindow.hmac = hmac;\n// Fills hkdf buffer like this:\n// T(1) = HMAC-Hash(PRK, T(0) | info | 0x01)\nfunction fillBuffer(buffer, hmac, info, counter) {\n // Counter is a byte value: check if it overflowed.\n const num = counter[0];\n if (num === 0) {\n throw new Error('hkdf: cannot expand more');\n }\n // Prepare HMAC instance for new data with old key.\n hmac.reset();\n // Hash in previous output if it was generated\n // (i.e. counter is greater than 1).\n if (num > 1) {\n hmac.update(buffer);\n }\n // Hash in info if it exists.\n if (info) {\n hmac.update(info);\n }\n // Hash in the counter.\n hmac.update(counter);\n // Output result to buffer and clean HMAC instance.\n hmac.finish(buffer);\n // Increment counter inside typed array, this works properly.\n counter[0]++;\n}\nconst hkdfSalt = new Uint8Array(digestLength); // Filled with zeroes.\nfunction hkdf(key, salt, info, length) {\n if (salt === void 0) { salt = hkdfSalt; }\n if (length === void 0) { length = 32; }\n const counter = new Uint8Array([1]);\n // HKDF-Extract uses salt as HMAC key, and key as data.\n const okm = hmac(salt, key);\n // Initialize HMAC for expanding with extracted key.\n // Ensure no collisions with `hmac` function.\n const hmac_ = new HMAC(okm);\n // Allocate buffer.\n const buffer = new Uint8Array(hmac_.digestLength);\n let bufpos = buffer.length;\n const out = new Uint8Array(length);\n for (let i = 0; i < length; i++) {\n if (bufpos === buffer.length) {\n fillBuffer(buffer, hmac_, info, counter);\n bufpos = 0;\n }\n out[i] = buffer[bufpos++];\n }\n hmac_.clean();\n buffer.fill(0);\n counter.fill(0);\n return out;\n}\nwindow.hkdf = hkdf;\n// Derives a key from password and salt using PBKDF2-HMAC-SHA256\n// with the given number of iterations.\n//\n// The number of bytes returned is equal to dkLen.\n//\n// (For better security, avoid dkLen greater than hash length - 32 bytes).\nfunction pbkdf2(password, salt, iterations, dkLen) {\n const prf = new HMAC(password);\n const len = prf.digestLength;\n const ctr = new Uint8Array(4);\n const t = new Uint8Array(len);\n const u = new Uint8Array(len);\n const dk = new Uint8Array(dkLen);\n for (var i = 0; i * len < dkLen; i++) {\n const c = i + 1;\n ctr[0] = (c >>> 24) & 0xff;\n ctr[1] = (c >>> 16) & 0xff;\n ctr[2] = (c >>> 8) & 0xff;\n ctr[3] = (c >>> 0) & 0xff;\n prf.reset();\n prf.update(salt);\n prf.update(ctr);\n prf.finish(u);\n for (var j = 0; j < len; j++) {\n t[j] = u[j];\n }\n for (var j = 2; j <= iterations; j++) {\n prf.reset();\n prf.update(u).finish(u);\n for (let k = 0; k < len; k++) {\n t[k] ^= u[k];\n }\n }\n for (var j = 0; j < len && i * len + j < dkLen; j++) {\n dk[i * len + j] = t[j];\n }\n }\n for (var i = 0; i < len; i++) {\n t[i] = u[i] = 0;\n }\n for (var i = 0; i < 4; i++) {\n ctr[i] = 0;\n }\n prf.clean();\n return dk;\n}\nwindow.pbkdf2 = pbkdf2;\n", "/* eslint-disable max-classes-per-file, @typescript-eslint/no-use-before-define */\nimport './js/sha256';\nimport { log, debug, error } from './logger';\nimport { authFetch } from './authWrap';\nimport { gradioApp, onAfterUiUpdate } from './script';\nimport { timer } from './timers';\nimport { monitorOption } from './settings';\n\nimport {\n idbAdd,\n idbCount,\n idbFolderCleanup,\n idbClearAll,\n idbGet,\n idbKeys,\n idbIsReady,\n} from './indexdb';\n\nlet ws;\nlet url;\nlet currentSize = 0;\nlet currentSort = 'none';\nlet currentName = '';\nlet currentImage = null;\nlet currentTitle = '';\nlet currentGalleryFolder = null;\nlet pruneImagesTimer;\nlet outstanding = 0;\nlet gallerySelection = { files: [], index: -1 };\nlet maintenanceController = new AbortController();\nconst maxFetchRequests = 32;\nconst fragmentSize = 100;\nconst minCleanupCount = 1000;\nconst minCleanupTime = 1000 * 60 * 60; // 1 hour\nconst folderStylesheet = new CSSStyleSheet();\nconst fileStylesheet = new CSSStyleSheet();\nlet galleryInitialized = false;\n// Store separator states for the session\nconst separatorStates = new Map();\nconst el = {\n folders: undefined,\n files: undefined,\n search: undefined,\n status: undefined,\n btnSend: undefined,\n overlay: undefined,\n size: undefined,\n};\nconst cleanupTimers = {};\nconst maintenanceTimers = {};\nconst fetchQueue = [];\nconst icons = {\n Time: String.fromCodePoint(9201),\n Folder: String.fromCodePoint(128448), // or 128449;\n Sort: String.fromCodePoint(8645),\n Images: String.fromCodePoint(128461),\n};\n// eslint-disable-next-line @stylistic/max-len, @stylistic/quotes\nconst loadingSvg = `data:image/svg+xml;utf8,`;\n\nconst SUPPORTED_EXTENSIONS = ['jpg', 'jpeg', 'png', 'webp', 'tiff', 'jp2', 'jxl', 'gif', 'mp4', 'mkv', 'avi', 'mjpeg', 'mpg', 'avr', 'heif', 'heic', 'mov', 'ts'];\n\nconst gallerySorter = {\n nameA: { name: 'Name Ascending', func: (a, b) => a.name.localeCompare(b.name) },\n nameD: { name: 'Name Descending', func: (b, a) => a.name.localeCompare(b.name) },\n sizeD: { name: 'Size Ascending', func: (a, b) => a.size - b.size },\n sizeA: { name: 'Size Descending', func: (b, a) => a.size - b.size },\n resD: { name: 'Resolution Ascending', func: (a, b) => a.width * a.height - b.width * b.height },\n resA: { name: 'Resolution Descending', func: (b, a) => a.width * a.height - b.width * b.height },\n modD: { name: 'Modified Ascending', func: (a, b) => a.mtime - b.mtime },\n modA: { name: 'Modified Descending', func: (b, a) => a.mtime - b.mtime },\n none: { name: 'None', func: undefined },\n};\nconst folderSorter = {\n nameA: { name: 'Name Ascending', func: (a, b) => a.name.localeCompare(b.name) },\n nameD: { name: 'Name Descending', func: (b, a) => a.name.localeCompare(b.name) },\n sizeD: { name: 'Size Ascending', func: (a, b) => a.size - b.size },\n sizeA: { name: 'Size Descending', func: (b, a) => a.size - b.size },\n resD: { name: 'Resolution Ascending', func: (a, b) => a.width * a.height - b.width * b.height },\n resA: { name: 'Resolution Descending', func: (b, a) => a.width * a.height - b.width * b.height },\n modD: { name: 'Modified Ascending', func: (a, b) => a.mtime - b.mtime },\n modA: { name: 'Modified Descending', func: (b, a) => a.mtime - b.mtime },\n none: { name: 'None', func: undefined },\n};\n\nlet sortMode = gallerySorter.none;\n\nasync function getHash(str) {\n let hex = '';\n const strBuf = new TextEncoder().encode(str);\n let hashBuf;\n if (crypto?.subtle?.digest) {\n hashBuf = await crypto.subtle.digest('SHA-256', strBuf);\n } else {\n const hashResult: any = hash(strBuf);\n hashBuf = hashResult.buffer; // from sha256.js\n }\n const view = new DataView(hashBuf);\n for (let i = 0; i < hashBuf.byteLength; i += 4) hex += (`00000000${view.getUint32(i).toString(16)}`).slice(-8);\n return hex;\n}\n\nfunction getVisibleGalleryFiles() {\n if (!el.files) return [];\n return Array.from(el.files.children).filter((node) => node.name && node.offsetParent);\n}\n\nfunction updateGallerySelectionClasses(files = gallerySelection.files, index = gallerySelection.index) {\n files.forEach((file, i) => {\n file.classList.toggle('gallery-file-selected', i === index);\n });\n}\n\nfunction refreshGallerySelection() {\n updateGallerySelectionClasses(gallerySelection.files, -1);\n const files = getVisibleGalleryFiles();\n const index = files.findIndex((file) => file.src === currentImage);\n gallerySelection = { files, index };\n updateGallerySelectionClasses(files, index);\n}\n\nfunction resetGallerySelection() {\n updateGallerySelectionClasses(gallerySelection.files, -1);\n gallerySelection = { files: [], index: -1 };\n currentImage = null;\n currentName = '';\n currentTitle = '';\n}\n\nfunction applyGallerySelection(index, { send = true } = {}) {\n if (!gallerySelection.files.length) refreshGallerySelection();\n const { files } = gallerySelection;\n if (!files.length) return;\n if (!Number.isInteger(index) || index < 0 || index >= files.length) {\n log('gallery selection index out of range', index, files.length);\n resetGallerySelection();\n return;\n }\n gallerySelection.index = index;\n currentImage = files[index].src;\n currentName = files[index].name;\n currentTitle = files[index].title;\n updateGallerySelectionClasses(files, index);\n if (send && el.btnSend) el.btnSend.click();\n}\n\nfunction setGallerySelectionByElement(element, options) {\n if (!gallerySelection.files.length) refreshGallerySelection();\n let index = gallerySelection.files.findIndex((file) => file === element);\n if (index < 0) {\n refreshGallerySelection();\n index = gallerySelection.files.findIndex((file) => file === element);\n }\n if (index >= 0) applyGallerySelection(index, options);\n}\n\nfunction buildGalleryFileUrl(path) {\n return new URL(`/file=${encodeURI(path)}`, window.location.origin).toString();\n}\n\nwindow.getGallerySelection = () => ({ index: gallerySelection.index, files: gallerySelection.files });\nwindow.setGallerySelection = (index, options) => applyGallerySelection(index, options);\nwindow.getGallerySelectedUrl = () => (currentImage ? buildGalleryFileUrl(currentImage) : null);\n\n/**\n * Wait for gallery to finish populating\n * @param {number} expectedSize - Expected gallery size\n * @param {AbortSignal} signal - AbortController signal\n */\nasync function awaitForGallery(expectedSize, signal) {\n while (Math.max(galleryHashes.size, galleryHashes.fallback) < expectedSize && !signal.aborted) await new Promise((resolve) => { setTimeout(resolve, 500); }); // longer interval because it's a low priority check\n signal.throwIfAborted();\n}\n\nfunction updateGalleryStyles() {\n if (opts.theme_type?.toLowerCase() === 'modern') {\n folderStylesheet.replace(`\n .gallery-folder {\n cursor: pointer;\n padding: 8px 6px 8px 6px;\n background-color: var(--sd-button-normal-color);\n border-radius: var(--sd-border-radius);\n text-align: left;\n direction: rtl; /* Used to overflow the beginning instead of the end */\n min-width: 12em;\n max-width: 100%;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n transition-duration: 0.2s;\n transition-property: color, opacity, background-color, border-color;\n transition-timing-function: ease-out;\n }\n .gallery-folder:hover {\n background-color: var(--button-primary-background-fill-hover, var(--sd-button-hover-color));\n }\n .gallery-folder-selected {\n background-color: var(--sd-button-selected-color);\n color: var(--sd-button-selected-text-color);\n }\n .gallery-folder-icon {\n font-size: 1.2em;\n color: var(--sd-button-icon-color);\n margin-right: 1em;\n filter: drop-shadow(1px 1px 2px black);\n float: left;\n }\n `);\n } else {\n folderStylesheet.replace(`\n .gallery-folder {\n cursor: pointer;\n padding: 8px 6px 8px 6px;\n max-width: 200px;\n overflow-x: hidden;\n text-wrap: nowrap;\n text-overflow: ellipsis;\n }\n .gallery-folder:hover {\n background-color: var(--button-primary-background-fill-hover);\n }\n .gallery-folder-selected {\n background-color: var(--button-primary-background-fill);\n }\n `);\n }\n const size = el.size ? el.size.value : opts.extra_networks_card_size;\n fileStylesheet.replace(`\n .gallery-file {\n object-fit: contain;\n cursor: pointer;\n height: ${size}px;\n width: ${opts.browser_fixed_width ? `${size}px` : 'unset'};\n }\n .gallery-file:hover {\n filter: grayscale(100%);\n }\n .gallery-overlay {\n position: absolute;\n height: 24px;\n background-color: rgba(0,0,0,0.7);\n display: block;\n text-align: right;\n padding: 4px;\n font-size: 1.2em;\n letter-spacing: 0.5em;\n margin-top: calc(140px - 32px);\n opacity: 75%;\n border-radius: var(--sd-border-radius);\n }\n :host(.gallery-file-selected) .gallery-file {\n box-shadow: 0 0 0 2px var(--sd-button-selected-color);\n }\n `);\n}\n\n// Classes\n\nclass HashSet extends Set {\n fallback = 0;\n constructor(val?: any) {\n super(val);\n this.fallback = 0;\n }\n\n override add(value: any): this {\n ++this.fallback;\n super.add(value);\n return this;\n }\n\n override clear(): void {\n this.fallback = 0;\n super.clear();\n }\n}\n\nconst galleryHashes = new HashSet();\n\nclass SimpleProgressBar {\n #container = document.createElement('div');\n #progress = document.createElement('div');\n #textDiv = document.createElement('div');\n #text = document.createElement('span');\n #visible = false;\n #interval: ReturnType | undefined;\n #max = 0;\n defaultStats = { queue: 0, fetch: 0, hash: 0, db: 0, cached: 0, fetched: 0, failed: 0, error: 0, callback: 0, elapsed: 0, count: 0 };\n stats = { ...this.defaultStats };\n /** @type {Set} */\n #monitoredSet;\n\n constructor(monitoredSet) {\n this.#monitoredSet = monitoredSet; // This is required because incrementing a variable with a class method turned out to not be an atomic operation\n 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;';\n this.#progress.style.cssText = 'position:absolute; left:0; height:100%; width:0; transition:width 200ms;';\n this.#progress.style.backgroundColor = 'var(--sd-main-accent-color)';\n this.#textDiv.style.cssText = 'position:relative; margin:auto; width:max-content; height:100%;';\n this.#text.style.cssText = 'user-select:none; color:white;';\n this.#textDiv.append(this.#text);\n this.#container.append(this.#progress, this.#textDiv);\n }\n\n start(total) {\n if (total <= 0) return;\n this.hide();\n this.#max = total;\n if (this.#monitoredSet.size >= this.#max) {\n this.stop();\n return;\n }\n this.#interval = setInterval(() => this.update(this.#monitoredSet.size, this.#max), 100);\n }\n\n attachTo(element) {\n if (element.hasChildNodes) element.innerHTML = '';\n element.appendChild(this.#container);\n }\n\n hide() {\n this.#container.style.display = 'none';\n this.#visible = false;\n this.#progress.style.width = '0';\n this.#text.textContent = '';\n }\n\n update(loaded, max) {\n this.#progress.style.width = `${Math.floor((loaded / max) * 100)}%`;\n this.#text.textContent = `${loaded}/${max}`;\n if (!this.#visible) {\n this.#container.style.display = 'block';\n this.#visible = true;\n }\n if (loaded >= max) this.stop();\n }\n\n stop() {\n clearInterval(this.#interval);\n // this.#interval = undefined;\n if (this.stats.count) {\n debug('gallery: thumbnail stats', this.stats);\n this.stats = { ...this.defaultStats };\n }\n setTimeout(() => this.hide(), 100);\n }\n}\n\nconst pb = new SimpleProgressBar(galleryHashes);\n\n/* This isn't as robust as the Web Locks API, but it will at least work if accessing a remote machine without HTTPS */\nclass SimpleFunctionQueue {\n #id;\n #running;\n #queue;\n\n constructor(id) {\n this.#id = id;\n this.#running = false;\n this.#queue = [];\n }\n\n static abortLogger(identifier, result) {\n if (typeof result === 'string' || (result instanceof DOMException && result.name === 'AbortError')) {\n log(identifier, typeof result === 'object' && result !== null ? (result as any).message || result : result);\n } else {\n error(identifier, result.message);\n }\n }\n\n /**\n * @param {{\n * signal: AbortSignal,\n * callback: Function\n * }} config\n */\n enqueue(config) {\n if (!(config.signal instanceof AbortSignal) || typeof config.callback !== 'function') {\n throw new Error('Invalid configuration. Object must contain an AbortSignal and a function');\n }\n if (config.signal.aborted) {\n debug(`${this.#id} Queue: Skipping addition to queue due to \"${config.signal.reason}\"`);\n return;\n }\n this.#queue.push(config);\n this.#tryRunNext();\n }\n\n async #tryRunNext() {\n if (this.#running || !this.#queue.length) return;\n try {\n const { signal, callback } = this.#queue.shift();\n if (signal.aborted) {\n return;\n }\n this.#running = true;\n if (callback.constructor.name.toLowerCase() === 'asyncfunction') {\n await callback();\n } else {\n callback();\n }\n } catch (err) {\n error(`${this.#id} Queue:`, err);\n } finally {\n this.#running = false;\n this.#tryRunNext();\n }\n }\n}\n\n// HTML Elements\n\nclass GalleryFolder extends HTMLElement {\n static folders = new Set();\n /** @type {GalleryFolder | null} */\n static #active = null;\n\n constructor(folder) {\n super();\n // Support both old format (string) and new format (object with path and label)\n if (typeof folder === 'object' && folder !== null) {\n this.name = decodeURI(folder.path || '');\n this.label = decodeURI(folder.label || folder.path || '');\n } else {\n this.name = decodeURI(folder);\n this.label = this.name;\n }\n this.style.overflowX = 'hidden';\n this.shadow = this.attachShadow({ mode: 'open' });\n this.shadow.adoptedStyleSheets = [folderStylesheet];\n\n this.div = document.createElement('div');\n }\n\n connectedCallback() {\n if (GalleryFolder.folders.has(this)) return; // Element is just being moved\n this.div.className = 'gallery-folder';\n this.div.innerHTML = `\\uf03e ${this.label}`;\n this.div.title = this.name; // Show full path on hover\n this.addEventListener('click', this.updateSelected);\n this.addEventListener('click', fetchFilesWS);\n this.shadow.appendChild(this.div);\n GalleryFolder.folders.add(this);\n if (this.name === currentGalleryFolder) {\n this.updateSelected();\n }\n }\n\n async disconnectedCallback() {\n await Promise.resolve(); // Wait for other microtasks (such as element moving)\n if (this.isConnected) return;\n GalleryFolder.folders.delete(this);\n if (GalleryFolder.#active === this) {\n GalleryFolder.#active = null;\n }\n }\n\n static getActive() {\n return GalleryFolder.#active;\n }\n\n updateSelected() {\n this.div.classList.add('gallery-folder-selected');\n GalleryFolder.#active = this;\n for (const folder of GalleryFolder.folders as any) {\n if (folder !== this) folder.div.classList.remove('gallery-folder-selected');\n }\n }\n}\n\n/**\n * Event-driven wait mechanism replacing the 50ms polling loop\n * @param {AbortSignal} signal - AbortController signal\n */\nasync function awaitForOutstanding(signal) {\n if (signal?.aborted) throw new DOMException('Aborted', 'AbortError');\n if (outstanding < maxFetchRequests) return; // if we are under the limit, proceed immediately\n await new Promise((resolve, reject) => { // otherwise, register a promise and wait for the queue to resolve us\n const onResolve = () => { // define what happens when this item gets its turn or gets aborted\n signal?.removeEventListener('abort', onAbort);\n resolve(true);\n };\n const onAbort = () => {\n const idx = fetchQueue.findIndex((item) => item.resolve === onResolve); // remove this specific request from the waiting queue if aborted\n if (idx !== -1) fetchQueue.splice(idx, 1);\n reject(new DOMException('Aborted', 'AbortError'));\n };\n fetchQueue.push({ resolve: onResolve });\n signal?.addEventListener('abort', onAbort);\n });\n}\n\nasync function delayFetchThumb(fn, signal) {\n const t0 = performance.now();\n try {\n await awaitForOutstanding(signal);\n } catch (err) {\n if ((err as DOMException).name === 'AbortError') return undefined;\n throw err;\n }\n pb.stats.queue = (pb.stats.queue || 0) + Math.round(performance.now() - t0);\n const t1 = performance.now();\n try {\n outstanding++;\n const ts = t0.toString();\n const res = await authFetch(`${window.api}/browser/thumb?file=${encodeURI(fn)}&ts=${ts}&exif=false`, { priority: 'low' });\n if (!res.ok) {\n error(`fetchThumb: ${res.statusText}`);\n return undefined;\n }\n const json = await res.json();\n if (!res || !json || json.error || Object.keys(json).length === 0) {\n if (json.error) error(`fetchThumb: ${json.error}`);\n return undefined;\n }\n return json;\n } finally {\n outstanding--;\n pb.stats.fetch = (pb.stats.fetch || 0) + Math.round(performance.now() - t1);\n if (fetchQueue.length > 0 && outstanding < maxFetchRequests) { // queue magic: trigger the next waiting fetch immediately\n const nextRequest = fetchQueue.shift();\n nextRequest.resolve(); // This wakes up the next awaitForOutstanding()\n }\n }\n}\n\nclass GalleryFile extends HTMLElement {\n /** @type {AbortSignal} */\n #signal;\n\n constructor(folder, file, signal) {\n super();\n this.folder = folder;\n this.name = file;\n this.#signal = signal;\n this.src = `${this.folder}/${this.name}`.replace(/\\/+/g, '/'); // Ensure no //, ///, etc...\n this.fullFolder = this.src.replace(/\\/[^/]+$/, '');\n this.size = 0;\n this.mtime = 0;\n this.hash = undefined;\n this.exif = '';\n this.width = 0;\n this.height = 0;\n this.shadow = this.attachShadow({ mode: 'open' });\n this.shadow.adoptedStyleSheets = [fileStylesheet];\n this.firstRun = true;\n }\n\n async connectedCallback() {\n if (!this.firstRun) return; // Element is just being moved\n this.firstRun = false;\n const t0 = performance.now();\n pb.stats.count = (pb.stats.count || 0) + 1;\n // Check separator state early to hide the element immediately\n const dir = this.name.match(/(.*)[/\\\\]/);\n if (dir && dir[1]) {\n const dirPath = dir[1];\n const isOpen = separatorStates.get(dirPath);\n if (isOpen === false) this.style.display = 'none';\n }\n\n this.hash = await getHash(`${this.src}/${this.size}/${this.mtime}`)\n .catch((err) => {\n error('getHash:', err);\n return null;\n });\n pb.stats.hash = (pb.stats.hash || 0) + Math.round(performance.now() - t0);\n let cachedData;\n if (opts.browser_cache) {\n const t1 = performance.now();\n // if (!pb.stats.keys) pb.stats.keys = await idbKeys();\n // if (pb.stats.keys && this.hash && pb.stats.keys.includes(this.hash)) cachedData = await idbGet(this.hash).catch(() => undefined);\n cachedData = await idbGet(this.hash).catch(() => undefined);\n pb.stats.db = (pb.stats.db || 0) + Math.round(performance.now() - t1);\n }\n const img = document.createElement('img');\n img.className = 'gallery-file';\n img.loading = 'lazy';\n img.onload = async () => {\n img.title += `\\nResolution: ${this.width} x ${this.height}`;\n this.title = img.title;\n if (!cachedData && opts.browser_cache) {\n if ((this.width === 0) || (this.height === 0)) { // fetch thumb failed so we use actual image\n this.width = img.naturalWidth;\n this.height = img.naturalHeight;\n }\n }\n };\n let ok = true;\n if (cachedData?.img) {\n img.src = cachedData.img;\n this.exif = cachedData.exif;\n this.width = cachedData.width;\n this.height = cachedData.height;\n this.size = cachedData.size;\n this.mtime = new Date(cachedData.mtime);\n pb.stats.cached = (pb.stats.cached || 0) + 1;\n } else {\n try {\n const json = await delayFetchThumb(this.src, this.#signal);\n if (!json) {\n ok = false;\n pb.stats.failed = (pb.stats.failed || 0) + 1;\n } else {\n img.src = json.data;\n this.exif = json.exif;\n this.width = json.width;\n this.height = json.height;\n this.size = json.size;\n this.mtime = new Date(json.mtime);\n pb.stats.fetched = (pb.stats.fetched || 0) + 1;\n if (opts.browser_cache && this.hash) {\n idbAdd({\n hash: this.hash,\n folder: this.fullFolder,\n file: this.name,\n size: this.size,\n mtime: this.mtime,\n width: this.width,\n height: this.height,\n src: this.src,\n exif: this.exif,\n img: img.src,\n // exif: await getExif(img), // alternative client-side exif\n // img: await createThumb(img), // alternative client-side thumb\n });\n }\n }\n } catch (err) { // thumb fetch failed so assign actual image\n img.src = `file=${this.src}`;\n pb.stats.error = (pb.stats.error || 0) + 1;\n }\n }\n pb.stats.callback = (pb.stats.callback || 0) + Math.round(performance.now() - t0);\n if (this.#signal.aborted) return;\n galleryHashes.add(this.hash);\n if (!ok) return;\n\n img.onclick = () => {\n setGallerySelectionByElement(this, { send: true });\n };\n img.onpointerenter = () => {\n el.overlay.display = 'block';\n this.shadow.appendChild(el.overlay);\n currentImage = this.src;\n currentName = this.name;\n currentTitle = this.title;\n };\n img.onpointerleave = () => {\n el.overlay.display = 'none';\n };\n img.title = `Folder: ${this.folder}\\nFile: ${this.name}\\nSize: ${this.size.toLocaleString()} bytes\\nModified: ${this.mtime.toLocaleString()}`;\n this.title = img.title;\n const shouldDisplayBasedOnSearch = this.title.toLowerCase().includes(el.search.value.toLowerCase()); // Final visibility check based on search term.\n if (this.style.display !== 'none') this.style.display = shouldDisplayBasedOnSearch ? '' : 'none'; // Only proceed if not already hidden by a closed separator\n this.shadow.appendChild(img);\n pb.stats.elapsed = (pb.stats.elapsed || 0) + Math.round(performance.now() - t0);\n }\n}\n\nasync function createThumb(img) {\n const sizeEl = document.getElementById('gallery-thumb-size');\n currentSize = sizeEl ? parseInt(sizeEl.value, 10) : opts.extra_networks_card_size;\n const height = currentSize;\n const width = opts.browser_fixed_width ? currentSize : 0;\n const canvas = document.createElement('canvas');\n const scaleY = height / img.height;\n const scaleX = width > 0 ? width / img.width : scaleY;\n const scale = Math.min(scaleX, scaleY);\n const scaledWidth = img.width * scale;\n const scaledHeight = img.height * scale;\n canvas.width = scaledWidth;\n canvas.height = scaledHeight;\n const ctx = canvas.getContext('2d');\n ctx.drawImage(img, 0, 0, scaledWidth, scaledHeight);\n const dataURL = canvas.toDataURL('image/jpeg', 0.5);\n return dataURL;\n}\n\nasync function handleSeparator(separator) {\n separator.classList.toggle('gallery-separator-hidden');\n const nowHidden = separator.classList.contains('gallery-separator-hidden');\n\n // Store the state (true = open, false = closed)\n separatorStates.set(separator.title, !nowHidden);\n\n // Update arrow and count\n const arrow = separator.querySelector('.gallery-separator-arrow');\n arrow.style.transform = nowHidden ? 'rotate(0deg)' : 'rotate(90deg)';\n\n const all = Array.from(el.files.children);\n for (const f of all) {\n if (!f.name) continue; // Skip separators\n\n // Check if file belongs to this exact directory\n const fileDir = f.name.match(/(.*)[/\\\\]/);\n const fileDirPath = fileDir ? fileDir[1] : '';\n\n if (separator.title.length > 0 && fileDirPath === separator.title) {\n f.style.display = nowHidden ? 'none' : '';\n }\n }\n // Note: Count is not updated here on manual toggle, as it reflects the total.\n // If I end up implementing it, the search function will handle dynamic count updates.\n}\n\nasync function addSeparators() {\n document.querySelectorAll('.gallery-separator').forEach((node) => { el.files.removeChild(node); });\n const all = Array.from(el.files.children);\n let lastDir;\n\n // Count root files (files without a directory path)\n const hasRootFiles = all.some((f) => f.name && !f.name.match(/[/\\\\]/));\n // Only auto-open first separator if there are no root files to display\n let isFirstSeparator = !hasRootFiles;\n\n // First pass: create separators\n for (const f of all) {\n let dir = f.name?.match(/(.*)[/\\\\]/);\n if (!dir) dir = '';\n else dir = dir[1];\n if (dir !== lastDir) {\n lastDir = dir;\n if (dir.length > 0) {\n // Count files in this directory\n let fileCount = 0;\n for (const file of all) {\n if (!file.name) continue;\n const fileDir = file.name.match(/(.*)[/\\\\]/);\n const fileDirPath = fileDir ? fileDir[1] : '';\n if (fileDirPath === dir) fileCount++;\n }\n\n const sep = document.createElement('div');\n sep.className = 'gallery-separator';\n sep.title = dir;\n\n // Default to open for the first separator if no state is saved, otherwise closed.\n const isOpen = separatorStates.has(dir) ? separatorStates.get(dir) : isFirstSeparator;\n separatorStates.set(dir, isOpen); // Ensure it's in the map\n if (isFirstSeparator) isFirstSeparator = false; // Subsequent separators will default to closed\n\n if (!isOpen) {\n sep.classList.add('gallery-separator-hidden');\n }\n\n // Create arrow span\n const arrow = document.createElement('span');\n arrow.className = 'gallery-separator-arrow';\n arrow.textContent = '\u25B6';\n arrow.style.transform = isOpen ? 'rotate(90deg)' : 'rotate(0deg)';\n\n // Create directory name span\n const dirName = document.createElement('span');\n dirName.className = 'gallery-separator-name';\n dirName.textContent = dir;\n dirName.title = dir; // Show full path on hover\n\n // Create count span\n const count = document.createElement('span');\n count.className = 'gallery-separator-count';\n count.textContent = `${fileCount} files`;\n sep.dataset.totalFiles = String(fileCount); // Store total count for search filtering\n\n sep.appendChild(arrow);\n sep.appendChild(dirName);\n sep.appendChild(count);\n\n sep.onclick = () => handleSeparator(sep);\n el.files.insertBefore(sep, f);\n }\n }\n }\n\n // Second pass: hide files in closed directories\n for (const f of all) {\n if (!f.name) continue; // Skip separators\n\n const dir = f.name.match(/(.*)[/\\\\]/);\n if (dir && dir[1]) {\n const dirPath = dir[1];\n const isOpen = separatorStates.get(dirPath);\n if (isOpen === false) {\n f.style.display = 'none';\n }\n }\n }\n}\n\n// methods\n\nconst gallerySendImage = (_images) => [currentImage]; // invoked by gradio button\nwindow.gallerySendImage = gallerySendImage;\n\n/**\n * Helper function to update status with sort mode\n * @param {...string|[string, string]} messages - Each can be either a string to use as-is, or an array of a string label and value\n * @returns {void}\n */\nfunction updateStatusLine(...messages) {\n if (!el.status) return;\n messages.unshift(['Sort', sortMode.name]);\n const fragment = document.createDocumentFragment();\n for (let i = 0; i < messages.length; i++) {\n const div = document.createElement('div');\n if (Array.isArray(messages[i])) {\n const [k, v] = messages[i];\n const tDiv = document.createElement('div');\n const ico = icons[k] || `${k}:`;\n tDiv.innerText = `${ico} ${v}`;\n div.append(tDiv);\n } else {\n const tDiv = document.createElement('div');\n tDiv.innerText = messages[i];\n div.append(tDiv);\n }\n fragment.append(div);\n }\n if (el.status.hasChildNodes()) el.status.innerHTML = '';\n el.status.append(fragment);\n}\n\nasync function injectGalleryStatusCSS() {\n const style = document.createElement('style');\n style.textContent = `\n #tab-gallery-status {\n display: inline-flex;\n flex-flow: row wrap;\n justify-content: ${opts.theme_type?.toLowerCase() === 'modern' ? 'flex-start' : 'flex-end'};\n }\n #tab-gallery-status > div {\n display: flex;\n max-width: 100%;\n white-space: nowrap;\n & div {\n &:first-child {\n flex-shrink: 0;\n margin-right: 4px;\n }\n &:last-child:not(:first-child) {\n flex-shrink: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n direction: rtl;\n text-align: left;\n }\n }\n }\n #tab-gallery-status > div:not(:last-child)::after {\n content: '|';\n margin-inline: 6px;\n }`;\n document.head.append(style);\n}\n\nasync function wsConnect(socket, timeout = 5000) {\n const intrasleep = 100;\n const ttl = timeout / intrasleep;\n const isOpened = () => (socket.readyState === WebSocket.OPEN);\n if (socket.readyState !== WebSocket.CONNECTING) return isOpened();\n\n let loop = 0;\n while (socket.readyState === WebSocket.CONNECTING && loop < ttl) {\n await new Promise((resolve) => { setTimeout(resolve, intrasleep); });\n loop++;\n }\n return isOpened();\n}\n\nasync function gallerySearch() {\n if (el.search.busy) clearTimeout(el.search.busy);\n el.search.busy = setTimeout(async () => {\n const t0 = performance.now();\n const str = el.search.value.toLowerCase();\n const allFiles = Array.from(el.files.children).filter((node) => node.name);\n const allSeparators = Array.from(el.files.children).filter((node) => node.classList.contains('gallery-separator'));\n\n // If search is cleared, restore original view\n if (str === '') {\n allSeparators.forEach((sep) => {\n sep.style.display = 'flex';\n const isOpen = separatorStates.has(sep.title) ? separatorStates.get(sep.title) : false;\n\n const countSpan = sep.querySelector('.gallery-separator-count');\n if (countSpan && sep.dataset.totalFiles) {\n countSpan.textContent = `${sep.dataset.totalFiles} files`;\n }\n\n const arrow = sep.querySelector('.gallery-separator-arrow');\n sep.classList.toggle('gallery-separator-hidden', !isOpen);\n if (arrow) arrow.style.transform = isOpen ? 'rotate(90deg)' : 'rotate(0deg)';\n });\n\n allFiles.forEach((f) => {\n const dir = f.name.match(/(.*)[/\\\\]/);\n const dirPath = (dir && dir[1]) ? dir[1] : '';\n const isOpen = separatorStates.get(dirPath);\n f.style.display = (!dirPath || isOpen) ? 'unset' : 'none';\n });\n\n updateStatusLine('Filter', 'Cleared', ['Images', allFiles.length.toLocaleString()]);\n return;\n }\n\n // --- Search logic ---\n let totalFound = 0;\n const directoryMatches = new Map();\n const fileMatches = new WeakSet();\n const r = /^(.+)([=<>])(.*)/;\n\n for (const f of allFiles) {\n let isMatch = false;\n if (r.test(str)) {\n const match = str.match(r);\n const key = match[1].trim();\n const op = match[2].trim();\n let val = match[3].trim();\n if (key === 'mtime') val = new Date(val);\n if (((op === '=') && (f[key] === val)) || ((op === '>') && (f[key] > val)) || ((op === '<') && (f[key] < val))) {\n isMatch = true;\n }\n } else if (f.title?.toLowerCase().includes(str) || f.exif?.toLowerCase().includes(str)) {\n isMatch = true;\n }\n\n if (isMatch) {\n fileMatches.add(f);\n totalFound++;\n const dir = f.name.match(/(.*)[/\\\\]/);\n const dirPath = (dir && dir[1]) ? dir[1] : '';\n directoryMatches.set(dirPath, (directoryMatches.get(dirPath) || 0) + 1);\n }\n }\n\n // Update separators based on search results\n for (const sep of allSeparators) {\n const dirPath = sep.title;\n const foundCount = directoryMatches.get(dirPath) || 0;\n\n if (foundCount > 0) {\n sep.style.display = 'flex'; // Show separator\n sep.classList.remove('gallery-separator-hidden'); // Force open\n\n const arrow = sep.querySelector('.gallery-separator-arrow');\n if (arrow) arrow.style.transform = 'rotate(90deg)';\n\n // Removed file count update during search as it was buggy.\n } else {\n sep.style.display = 'none'; // Hide separator\n }\n }\n\n // Update file visibility\n for (const f of allFiles) {\n f.style.display = fileMatches.has(f) ? 'unset' : 'none';\n }\n\n const t1 = performance.now();\n updateStatusLine('Filter', ['Images', `${totalFound.toLocaleString()} / ${allFiles.length.toLocaleString()}`], ['Time', `${Math.round(t1 - t0).toLocaleString()}ms`]);\n timer(`galleryFilter:${str}`, t1 - t0);\n refreshGallerySelection();\n }, 250);\n}\n\nconst findDuplicates = (arr, key) => {\n const map = new Map();\n return arr.filter((item) => {\n const value = item[key];\n if (map.has(value)) return true;\n map.set(value, true);\n return false;\n });\n};\n\nexport async function gallerySort(key) {\n // if currentSort does not start with key, default to key+A\n // else if currentSort ends with A change to D and vice versa for toggling sort order\n if (currentSort.startsWith(key)) currentSort = currentSort.endsWith('A') ? `${key}D` : `${key}A`;\n else currentSort = `${key}A`;\n\n if (!Object.hasOwn(gallerySorter, currentSort)) {\n error(`Gallery: \"${currentSort}\" is not a valid gallery sorting key`);\n return;\n }\n const t0 = performance.now();\n const arr = Array.from(el.files.children).filter((node) => node.name); // filter out separators\n if (arr.length === 0) return; // no files to sort\n const fragment = document.createDocumentFragment();\n\n // Helper to get directory path from a file node\n const getDirPath = (node) => {\n const match = node.name.match(/(.*)[/\\\\]/);\n return match ? match[1] : '';\n };\n\n // Partition into root files and subfolder files - root files always stay at top\n const rootFiles = arr.filter((node) => !getDirPath(node));\n const subfolderFiles = arr.filter((node) => getDirPath(node));\n\n // Group subfolder files by directory\n const folderGroups = new Map();\n for (const file of subfolderFiles) {\n const dir = getDirPath(file);\n if (!folderGroups.has(dir)) folderGroups.set(dir, []);\n folderGroups.get(dir).push(file);\n }\n\n sortMode = gallerySorter[currentSort];\n\n // Sort root files\n rootFiles.sort(sortMode.func);\n rootFiles.forEach((node) => fragment.appendChild(node));\n\n // Sort folder names alphabetically, then sort files within each folder\n // const sortedFolderNames = Array.from(folderGroups.keys()).sort((a, b) => a.localeCompare(b));\n const folderNames = Array.from(folderGroups.keys());\n const sortedFolderNames = currentSort.endsWith('A') ? folderNames.sort((a, b) => a.localeCompare(b)) : folderNames.sort((a, b) => b.localeCompare(a));\n\n for (const folderName of sortedFolderNames) {\n const files = folderGroups.get(folderName);\n files.sort(sortMode.func);\n files.forEach((node) => fragment.appendChild(node));\n }\n\n if (fragment.children.length === 0) return;\n el.files.innerHTML = '';\n el.files.appendChild(fragment);\n addSeparators();\n\n // After sorting and adding separators, ensure files respect separator states\n const all = Array.from(el.files.children);\n for (const f of all) {\n if (!f.name) continue; // Skip separators\n\n const dir = f.name.match(/(.*)[/\\\\]/);\n if (dir && dir[1]) {\n const dirPath = dir[1];\n const isOpen = separatorStates.get(dirPath);\n if (isOpen === false) {\n f.style.display = 'none';\n }\n }\n }\n\n const t1 = performance.now();\n log(`gallerySort: sort=${sortMode.name} len=${arr.length} time=${Math.floor(t1 - t0)}`);\n updateStatusLine(['Images', arr.length.toLocaleString()], ['Time', `${Math.round(t1 - t0).toLocaleString()}ms`]);\n timer(`gallerySort:${sortMode.name}`, t1 - t0);\n refreshGallerySelection();\n}\nwindow.gallerySort = gallerySort;\n\n/**\n * Function for removing the cleaning overlay\n * @callback ClearMsgCallback\n * @returns {void}\n */\n\n/**\n * Generate and display the overlay to announce cleanup is in progress.\n * @param {number} count - Number of entries being cleaned up\n * @param {boolean} all - Indicate that all thumbnails are being cleared\n * @returns {ClearMsgCallback}\n */\nfunction showCleaningMsg(count, all = false) {\n // Rendering performance isn't a priority since this doesn't run often\n const parent = el.folders.parentElement;\n const cleaningOverlay = document.createElement('div');\n const msgDiv = document.createElement('div');\n const msgText = document.createElement('div');\n const msgInfo = document.createElement('div');\n const anim = document.createElement('span');\n\n parent.style.position = 'relative';\n cleaningOverlay.style.cssText = 'position: absolute; height: 100%; width: 100%; background-color: var(--sd-main-accent-color); display: flex; align-items: center; justify-content: center; align-content: center; flex-wrap: wrap; opacity: 0.8; border-radius: var(--sd-border-radius);';\n msgDiv.style.cssText = 'display: block; color: var(--sd-button-normal-color); padding: 12px; border-radius: 8px; border-radius: var(--sd-border-radius);';\n msgText.style.cssText = 'font-size: 1.2em';\n msgInfo.style.cssText = 'font-size: 0.9em; text-align: center;';\n msgText.innerText = 'Thumbnail cleanup...';\n msgInfo.innerText = all ? 'Clearing all entries' : `Found ${count} old entries`;\n anim.classList.add('idbBusyAnim');\n\n msgDiv.append(msgText, msgInfo);\n cleaningOverlay.append(msgDiv, anim);\n parent.append(cleaningOverlay);\n return () => { cleaningOverlay.remove(); };\n}\n\nconst maintenanceQueue = new SimpleFunctionQueue('Gallery Maintenance');\n\n/**\n * Handles calling the cleanup function for the thumbnail cache\n * @param {string} folder - Folder to clean\n * @param {number} imgCount - Expected number of images in gallery\n * @param {AbortController} controller - AbortController that's handling this task\n * @param {boolean} force - Force full cleanup of the folder\n */\nasync function thumbCacheCleanup(folder, imgCount, controller, force = false) {\n if (!opts.browser_cache && !force) return;\n if (!folder || !imgCount) return;\n if (Date.now() - cleanupTimers[folder] < minCleanupTime) return; // Prevents multiple calls in quick succession\n cleanupTimers[folder] = Date.now();\n try {\n if (typeof folder !== 'string' || typeof imgCount !== 'number') {\n throw new Error('Function called with invalid arguments');\n }\n debug('thumbCacheCleanup', { folder, imgCount });\n await awaitForGallery(imgCount, controller.signal);\n } catch (err) {\n error('thumbCacheCleanup', { folder, error: err });\n return;\n }\n\n maintenanceQueue.enqueue({\n signal: controller.signal,\n callback: async () => {\n if (Date.now() - maintenanceTimers[folder] < minCleanupTime) return;\n maintenanceTimers[folder] = Date.now();\n const t0 = performance.now();\n const keptGalleryHashes = force ? new Set() : new Set(galleryHashes.values()); // External context should be safe since this function run is guarded by AbortController/AbortSignal in the SimpleFunctionQueue\n const folderNormalized = folder.replace(/\\/+/g, '/').replace(/\\/$/, '');\n const recursiveFolder = IDBKeyRange.bound(folderNormalized, `${folderNormalized}\\uffff`, false, true);\n const cachedHashesCount = await idbCount(recursiveFolder)\n .catch((e) => {\n error('maintenanceQueue', { folder, error: e });\n return Infinity; // Forces next check to fail if something went wrong\n });\n const cleanupCount = cachedHashesCount - keptGalleryHashes.size;\n if (!force && (cleanupCount < minCleanupCount || !Number.isFinite(cleanupCount))) return; // Don't run when there aren't many excess entries\n log('galleryMaintenance', { folder });\n\n if (controller.signal.aborted) {\n debug('maintenanceQueue', { folder, reason: controller.signal.reason });\n return;\n }\n const cb_clearMsg = showCleaningMsg(cleanupCount);\n await idbFolderCleanup(keptGalleryHashes, recursiveFolder, controller.signal)\n .then((delcount) => {\n const t1 = performance.now();\n log('galleryMaintenance', { folder, kept: keptGalleryHashes.size, deleted: delcount, time: Math.round(t1 - t0) });\n timer(`thumbnailDBCleanup:${folder}`, t1 - t0);\n currentGalleryFolder = null;\n updateStatusLine('Thumbnail cache cleared');\n })\n .catch((reason) => {\n SimpleFunctionQueue.abortLogger('thumbCacheCleanup', reason);\n })\n .finally(async () => {\n await new Promise((resolve) => { setTimeout(resolve, 1000); }); // Delay removal by 1 second to ensure at least minimum visibility\n cb_clearMsg();\n });\n },\n });\n}\n\nfunction resetGalleryState(reason) {\n maintenanceController.abort(reason);\n const controller = new AbortController();\n maintenanceController = controller;\n\n galleryHashes.clear(); // Must happen AFTER the AbortController steps\n pb.hide();\n resetGallerySelection();\n return controller;\n}\n\nfunction clearCacheIfDisabled(browser_cache) {\n if (browser_cache === false) {\n log('thumbCacheCleanup', { disabled: true });\n const controller = resetGalleryState('Clearing all thumbnails from cache');\n maintenanceQueue.enqueue({\n signal: controller.signal,\n callback: async () => {\n const t0 = performance.now();\n const cb_clearMsg = showCleaningMsg(0, true);\n await idbClearAll(controller.signal)\n .then(() => {\n log('thumbCacheCleanup', { time: Math.floor(performance.now() - t0) });\n currentGalleryFolder = null;\n updateStatusLine('Thumbnail cache cleared');\n })\n .catch((e) => {\n SimpleFunctionQueue.abortLogger('thumbCacheCleanup', e);\n })\n .finally(async () => {\n await new Promise((resolve) => { setTimeout(resolve, 1000); });\n cb_clearMsg();\n });\n },\n });\n }\n}\n\nexport function clearCache() {\n if (!currentGalleryFolder) return;\n const controller = resetGalleryState('Clearing folder thumbnails cache');\n el.files.innerHTML = '';\n log('clearCache', { folder: currentGalleryFolder });\n thumbCacheCleanup(currentGalleryFolder, 0, controller, true);\n}\nwindow.clearCache = clearCache;\n\nasync function fetchFilesHT(evt, controller) {\n const t0 = performance.now();\n const fragment = document.createDocumentFragment();\n updateStatusLine(['Folder', evt.target.name], 'in-progress');\n let numFiles = 0;\n\n const res = await authFetch(`${window.api}/browser/files?folder=${encodeURI(evt.target.name)}`);\n if (!res || res.status !== 200) {\n updateStatusLine(['Folder', evt.target.name], ['Failed', res?.statusText || 'No response']);\n return;\n }\n const jsonData = await res.json();\n for (const line of jsonData) {\n const data = decodeURI(line).split('##F##');\n const fileName = data[1];\n const ext = fileName.split('.').pop().toLowerCase();\n if (SUPPORTED_EXTENSIONS.includes(ext)) {\n numFiles++;\n const f = new GalleryFile(data[0], fileName, controller.signal);\n fragment.appendChild(f);\n }\n }\n\n if (controller.signal.aborted) return;\n el.files.appendChild(fragment);\n\n const t1 = performance.now();\n log(`gallery: folder=${evt.target.name} num=${numFiles} method=http time=${Math.floor(t1 - t0)}ms`);\n timer(`galleryFetch:${evt.target.name}`, t1 - t0);\n updateStatusLine(['Folder', evt.target.name], ['Images', numFiles.toLocaleString()], ['Time', `${Math.floor(t1 - t0).toLocaleString()}ms`]);\n pb.start(numFiles);\n addSeparators();\n refreshGallerySelection();\n thumbCacheCleanup(evt.target.name, numFiles, controller);\n}\n\nasync function fetchFilesWS(evt) { // fetch file-by-file list over websockets\n if (!url) return;\n // Abort previous controller and point to new controller for next time\n const controller = resetGalleryState('Gallery update'); // Called here because fetchFilesHT isn't called directly\n\n el.files.innerHTML = '';\n updateGalleryStyles();\n if (ws && ws.readyState === WebSocket.OPEN) ws.close(); // abort previous request\n let wsConnected = false;\n try {\n ws = new WebSocket(`${url}/sdapi/v1/browser/files`);\n wsConnected = await wsConnect(ws);\n } catch (err) {\n log('gallery: ws connect error', err);\n return;\n }\n log(`gallery: connected=${wsConnected} state=${ws?.readyState} url=${ws?.url}`);\n currentGalleryFolder = evt.target.name;\n if (!wsConnected) {\n await fetchFilesHT(evt, controller); // fallback to http\n return;\n }\n updateStatusLine(['Folder', evt.target.name]);\n const t0 = performance.now();\n let numFiles = 0;\n let t1 = performance.now();\n let fragment = document.createDocumentFragment();\n\n ws.onmessage = (event) => {\n t1 = performance.now();\n const data = decodeURI(event.data).split('##F##');\n if (data[0] === '#END#') {\n ws.close();\n } else {\n const fileName = data[1];\n const ext = fileName.split('.').pop().toLowerCase();\n if (SUPPORTED_EXTENSIONS.includes(ext)) {\n const file = new GalleryFile(data[0], fileName, controller.signal);\n numFiles++;\n fragment.appendChild(file);\n if (numFiles % fragmentSize === 0) {\n updateStatusLine(['Folder', evt.target.name], ['Images', numFiles.toLocaleString()], ['Status', 'in-progress'], ['Time', `${Math.floor(t1 - t0).toLocaleString()}ms`]);\n el.files.appendChild(fragment);\n fragment = document.createDocumentFragment();\n }\n }\n }\n };\n ws.onclose = (event) => {\n if (controller.signal.aborted) return;\n el.files.appendChild(fragment);\n // gallerySort();\n log(`gallery: folder=${evt.target.name} num=${numFiles} method=ws time=${Math.floor(t1 - t0)}ms`);\n updateStatusLine(['Folder', evt.target.name], ['Images', numFiles.toLocaleString()], ['Time', `${Math.floor(t1 - t0).toLocaleString()}ms`]);\n pb.start(numFiles);\n addSeparators();\n refreshGallerySelection();\n thumbCacheCleanup(evt.target.name, numFiles, controller);\n };\n ws.onerror = (event) => {\n log('gallery ws error', event);\n };\n ws.send(encodeURI(evt.target.name));\n}\n\nasync function updateFolders() {\n // if (el.folders.children.length > 0) return;\n const res = await authFetch(`${window.api}/browser/folders`);\n if (!res || res.status !== 200) return;\n url = res.url.split('/sdapi')[0].replace('http', 'ws'); // update global url as ws need fqdn\n const folders = await res.json();\n el.folders.innerHTML = '';\n for (const folder of folders) {\n const f = new GalleryFolder(folder);\n el.folders.appendChild(f);\n }\n}\n\nasync function monitorGalleries() {\n async function galleryMutation(mutations) {\n const galleries = mutations.filter((m) => m.target?.classList?.contains('preview'));\n for (const gallery of galleries) {\n const links = gallery.target.querySelectorAll('a');\n for (const link of links) {\n const href = link.getAttribute('href');\n if (!href) continue;\n const fn = href.split('/').pop().split('\\\\').pop();\n link.setAttribute('download', fn);\n }\n }\n }\n\n const galleryElements = gradioApp().querySelectorAll('.gradio-gallery');\n for (const gallery of galleryElements) {\n const galleryObserver = new MutationObserver(galleryMutation);\n galleryObserver.observe(gallery, { childList: true, subtree: true, attributes: true });\n }\n}\n\nasync function setOverlayAnimation() {\n const busyAnimation = document.createElement('style');\n\n // eslint-disable-next-line @stylistic/max-len\n busyAnimation.textContent = '.idbBusyAnim{width:16px;height:16px;border-radius:50%;display:block;margin:40px;position:relative;background:#aa3d00;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)}}';\n document.head.append(busyAnimation);\n}\n\nasync function initGalleryAutoRefresh() {\n const isModern = opts.theme_type?.toLowerCase() === 'modern';\n let galleryTab = isModern ? document.getElementById('gallery_tabitem') : document.getElementById('tab_gallery');\n let timeout = 0;\n while (!galleryTab && timeout++ < 60) {\n await new Promise((resolve) => { setTimeout(resolve, 2500); });\n galleryTab = isModern ? document.getElementById('gallery_tabitem') : document.getElementById('tab_gallery');\n }\n if (!galleryTab) {\n error('Gallery: timeout');\n return;\n }\n const displayNoneRegEx = /display:\\s*none/;\n async function galleryAutoRefresh(mutations) {\n if (!opts.browser_gallery_autoupdate) return;\n for (const mutation of mutations) {\n switch (mutation.attributeName) {\n case 'class':\n if (mutation.oldValue.includes('hidden') && !mutation.target.classList.contains('hidden')) {\n await updateFolders();\n GalleryFolder.getActive()?.click();\n }\n break;\n case 'style':\n if (displayNoneRegEx.test(mutation.oldValue) && !displayNoneRegEx.test(mutation.target.style.display)) {\n await updateFolders();\n GalleryFolder.getActive()?.click();\n }\n break;\n default:\n break;\n }\n }\n }\n const galleryVisObserver = new MutationObserver(galleryAutoRefresh);\n galleryVisObserver.observe(galleryTab, { attributeFilter: ['class', 'style'], attributeOldValue: true });\n}\n\nasync function overlayDelete(evt) {\n const res = await authFetch(`${window.api}/delete-image?file=${encodeURIComponent(currentImage)}`, { method: 'DELETE' });\n evt.stopPropagation();\n if (!res || res.status !== 200) {\n error('galleryDelete', { file: currentImage, status: res?.status, statusText: res?.statusText });\n return;\n }\n const data = await res.json();\n log('galleryDelete', data);\n GalleryFolder.getActive()?.click();\n}\n\nasync function overlayDownload(evt) {\n log('galleryDownload', currentImage);\n const link = document.createElement('a');\n link.href = `/file=${encodeURIComponent(currentImage)}`;\n link.download = currentName;\n document.body.appendChild(link);\n link.click();\n document.body.removeChild(link);\n evt.stopPropagation();\n}\n\nasync function overlayInfo(evt) {\n evt.stopPropagation();\n const tgt = document.getElementById('html_info_formatted_gallery');\n if (!tgt) return;\n const res = await authFetch(`${window.api}/png-info?file=${encodeURI(currentImage)}`);\n if (!res || res.status !== 200) return;\n const data = await res.json();\n log('galleryInfo res', data);\n const prompt = data?.parameters?.Prompt || '';\n const negative = data?.parameters?.Negative || data?.parameters?.['Negative prompt'] || '';\n const raw = data?.info || '';\n const params = data?.parameters || {};\n delete params.Prompt;\n delete params.Negative;\n delete params['Negative prompt'];\n const paramsFormatted = Object.entries(params).map(([key, value]) => `${key}: ${value}`).join(' | ');\n tgt.innerHTML = `\n
File: ${currentImage}
\n
Prompt: ${prompt}
\n
Negative: ${negative}
\n
${paramsFormatted}
\n
Raw:
${raw}
\n `;\n const img = document.querySelector('#gallery_gallery img');\n if (img) img.src = `/file=${encodeURIComponent(currentImage)}?t=${Date.now()}`; // Force refresh in case info endpoint is faster than cache update\n const status = document.querySelector('#html_log_gallery p');\n if (status) status.innerText = currentTitle;\n}\n\nasync function createOverlay() {\n if (el.overlay) return;\n el.overlay = document.createElement('div');\n el.overlay.className = 'gallery-overlay';\n const btnDownload = document.createElement('span');\n btnDownload.innerHTML = '\\udb85\\udc64';\n btnDownload.title = 'Download image';\n btnDownload.style.cursor = 'pointer';\n btnDownload.addEventListener('click', overlayDownload);\n const btnDelete = document.createElement('span');\n btnDelete.innerHTML = '\\uf05c';\n btnDelete.title = 'Delete image';\n btnDelete.style.cursor = 'pointer';\n btnDelete.addEventListener('click', overlayDelete);\n const btnInfo = document.createElement('span');\n btnInfo.innerHTML = '\\uf05a';\n btnInfo.title = 'Image metadata';\n btnInfo.style.cursor = 'pointer';\n btnInfo.addEventListener('click', overlayInfo);\n el.overlay.append(btnInfo, btnDelete, btnDownload);\n}\n\nasync function observeImageError(img: HTMLImageElement) {\n if (!img || !img.src) return;\n if (!img.src.toLowerCase().includes('.heic') && !img.src.toLowerCase().includes('.heif')) return;\n const origSrc = img.src;\n try {\n const t0 = performance.now();\n img.src = loadingSvg; // Use a loading spinner or placeholder image\n // @ts-ignore: external CDN module with no local types\n // eslint-disable-next-line import-x/no-unresolved\n const { default: heic2any } = await import('https://esm.sh/heic2any@0.0.4');\n const res = await authFetch(origSrc);\n const imageBlob = await res.blob();\n if (!imageBlob || imageBlob.size <= 1024) {\n error('imageHEIC', { src: origSrc, res, blob: imageBlob });\n return;\n }\n const convertedBlob = await heic2any({\n blob: imageBlob,\n toType: 'image/jpeg',\n quality: 0.9,\n });\n img.src = URL.createObjectURL(convertedBlob);\n const t1 = performance.now();\n log('imageHEIC', { time: Math.round(t1 - t0), originalSize: imageBlob.size, convertedSize: convertedBlob.size });\n } catch (err) {\n error('imageHEIC:', { src: origSrc, err });\n }\n}\n\nasync function observeGalleryMutations() {\n const galleryContainers = document.querySelectorAll('.gradio-gallery');\n for (const galleryContainer of galleryContainers) {\n if (!galleryContainer) return;\n const galleryObserver = new MutationObserver((mutations) => {\n for (const mutation of mutations) {\n if (mutation.type === 'childList' && mutation.addedNodes.length > 0) {\n const img = galleryContainer.querySelector('img');\n if (img && !galleryContainer.dataset.errorObserved) {\n galleryContainer.dataset.errorObserved = 'true';\n log('imageErrorHandler', { gallery: galleryContainer.id });\n img.addEventListener('error', () => observeImageError(img)); // late attach error handler as el may not be present\n galleryObserver.disconnect(); // stop observing after attaching the error handler\n }\n }\n }\n });\n galleryObserver.observe(galleryContainer, { childList: true, subtree: true });\n }\n}\n\nasync function blockQueueUntilReady() {\n // Add block to maintenanceQueue until cache is ready\n maintenanceQueue.enqueue({\n signal: new AbortController().signal, // Use standalone AbortSignal that can't be aborted\n callback: async () => {\n let timeout = 0;\n while (!idbIsReady() && timeout++ < 60) {\n await new Promise((resolve) => { setTimeout(resolve, 1000); });\n }\n if (!idbIsReady()) {\n throw new Error('Timed out waiting for thumbnail cache');\n }\n },\n });\n}\n\nexport async function initGallery() { // triggered on gradio change to monitor when ui gets sufficiently constructed\n const t0 = performance.now();\n el.folders = gradioApp().getElementById('tab-gallery-folders');\n el.files = gradioApp().getElementById('tab-gallery-files');\n el.status = gradioApp().getElementById('tab-gallery-status');\n el.search = gradioApp().querySelector('#tab-gallery-search textarea');\n el.size = document.getElementById('tab-gallery-thumb-size');\n if (!el.folders || !el.files || !el.status || !el.search) {\n error('initGallery', 'Missing gallery elements');\n return;\n }\n\n if (el.size) {\n el.size.value = opts.extra_networks_card_size;\n el.size.addEventListener('input', updateGalleryStyles);\n }\n blockQueueUntilReady(); // Run first\n createOverlay();\n updateGalleryStyles();\n injectGalleryStatusCSS();\n setOverlayAnimation();\n\n const progress = gradioApp().getElementById('tab-gallery-progress');\n if (progress) pb.attachTo(progress);\n else log('initGallery', 'Failed to attach loading progress bar');\n\n if (galleryInitialized) {\n log('initGallery', 'already initialized');\n return;\n }\n galleryInitialized = true;\n\n el.search.addEventListener('input', gallerySearch);\n el.btnSend = gradioApp().getElementById('tab-gallery-send-image');\n document.getElementById('tab-gallery-files').style.height = opts.logmonitor_show ? '75vh' : '85vh';\n\n monitorGalleries();\n updateFolders();\n initGalleryAutoRefresh();\n observeGalleryMutations();\n [\n 'browser_folders',\n 'outdir_samples',\n 'outdir_txt2img_samples',\n 'outdir_img2img_samples',\n 'outdir_control_samples',\n 'outdir_extras_samples',\n 'outdir_save',\n 'outdir_video',\n 'outdir_init_images',\n 'outdir_grids',\n 'outdir_txt2img_grids',\n 'outdir_img2img_grids',\n 'outdir_control_grids',\n ].forEach((op) => { monitorOption(op, updateFolders); });\n const t1 = performance.now();\n log('initGallery', Math.round(t1 - t0));\n timer('initGallery', t1 - t0);\n}\n\n// register on startup\n\ncustomElements.define('gallery-folder', GalleryFolder);\ncustomElements.define('gallery-file', GalleryFile);\n", "import exifr from 'exifr';\nimport Panzoom from 'panzoom';\nimport { log, debug } from './logger';\nimport { gradioApp, onAfterUiUpdate } from './script';\nimport { getENActiveTab } from './extraNetworks';\nimport { all_gallery_buttons, selected_gallery_button } from './ui';\nimport { timer } from './timers';\n\n// A full size 'lightbox' preview modal shown when left clicking on gallery previews\nlet previewDrag = false;\nlet modalPreviewZone;\nlet previewInstance;\n\nfunction cycleImageFit() {\n const root = document.documentElement;\n const current = getComputedStyle(root).getPropertyValue('--sd-image-fit').trim();\n let next = 'contain';\n if (current === 'contain') next = 'cover';\n else if (current === 'cover') next = 'fill';\n else if (current === 'fill') next = 'scale-down';\n else if (current === 'scale-down') next = 'none';\n root.style.setProperty('--sd-image-fit', next);\n log('cycleImageFit', current, next);\n}\n\nwindow.cycleImageFit = cycleImageFit;\n\nfunction isInViewport(element) {\n const rect = element.getBoundingClientRect();\n return rect.top >= 0 && rect.left >= 0 && rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) && rect.right <= (window.innerWidth || document.documentElement.clientWidth);\n}\n\nfunction closeModal(evt, force = false) {\n if (force) gradioApp().getElementById('lightboxModal').style.display = 'none';\n if (previewDrag) return;\n if (evt?.button !== 0) return;\n gradioApp().getElementById('lightboxModal').style.display = 'none';\n let thumbnails = Array.from(gradioApp().querySelectorAll('.thumbnails .thumbnail-item'));\n thumbnails = thumbnails.filter((el) => el.checkVisibility());\n if (thumbnails.length === 0) return;\n thumbnails[0].focus();\n}\n\nfunction modalImageSwitch(offset) {\n const negmod = (n, m) => ((n % m) + m) % m;\n const galleryButtons = all_gallery_buttons();\n if (galleryButtons.length > 1) {\n const currentButton = selected_gallery_button();\n let result = -1;\n galleryButtons.forEach((v, i) => {\n if (v === currentButton) result = i;\n });\n if (result !== -1) {\n const nextButton = galleryButtons[negmod((result + offset), galleryButtons.length)];\n nextButton.click();\n const modalImage = gradioApp().getElementById('modalImage');\n const modal = gradioApp().getElementById('lightboxModal');\n modalImage.src = nextButton.children[0].src;\n if (modalImage.style.display === 'none') modal.style.setProperty('background-image', `url(${modalImage.src})`);\n return;\n }\n }\n\n const galleryFilesContainer = gradioApp().getElementById('tab-gallery-files');\n if (!galleryFilesContainer || !galleryFilesContainer.offsetParent) return;\n const gallerySelection = window.getGallerySelection();\n if (!gallerySelection.files.length || gallerySelection.files.length <= 1) return;\n const baseIndex = gallerySelection.index >= 0 ? gallerySelection.index : 0;\n const nextIndex = negmod((baseIndex + offset), gallerySelection.files.length);\n window.setGallerySelection(nextIndex, { send: true });\n const modalImage = gradioApp().getElementById('modalImage');\n const modal = gradioApp().getElementById('lightboxModal');\n const directSrc = window.getGallerySelectedUrl();\n if (modalImage && modal && directSrc) {\n modalImage.src = directSrc;\n if (modalImage.style.display === 'none') modal.style.setProperty('background-image', `url(${directSrc})`);\n }\n}\n\nfunction modalSaveImage(event?: any) {\n const tabName = getENActiveTab();\n const saveBtn = gradioApp().getElementById(`save_${tabName}`);\n log('modalSaveImage', tabName, saveBtn);\n if (saveBtn) saveBtn.click();\n modalImageSwitch(0);\n}\n\nfunction modalKeyHandler(event) {\n log('modalKeyHandler', event.key);\n switch (event.key) {\n case 's':\n modalSaveImage();\n break;\n case 'ArrowLeft':\n modalImageSwitch(-1);\n break;\n case 'ArrowRight':\n modalImageSwitch(1);\n break;\n case 'Escape':\n closeModal(null, true);\n break;\n }\n event.stopPropagation();\n}\n\nfunction decodeBytes(bytes: Uint8Array): string {\n if (!bytes || bytes.length < 8) return '';\n const prefix = new TextDecoder('ascii').decode(bytes.slice(0, 8));\n const data = bytes.slice(8);\n if (prefix.startsWith('ASCII')) return new TextDecoder('ascii').decode(data).replace(/\\0+$/, '');\n if (prefix.startsWith('UNICODE')) return new TextDecoder('utf-16be').decode(data).replace(/\\0+$/, '');\n if (prefix.startsWith('JIS')) return new TextDecoder('shift-jis').decode(data).replace(/\\0+$/, '');\n return new TextDecoder().decode(bytes).replace(/\\0+$/, '');\n}\n\nexport async function getExif(el) {\n let exif: any = '';\n try {\n exif = await exifr.parse(el, { userComment: true });\n } catch (e) {\n log('getExif', el, e);\n return exif;\n }\n // let html = `Image ${el.src} Size ${el.naturalWidth}x${el.naturalHeight}
`;\n let html = '';\n let params;\n if (!exif) {\n log('getExif', 'exif is none');\n return html;\n }\n if (exif.parameters) params = exif.parameters;\n else if (exif.userComment) params = decodeBytes(exif.userComment);\n else params = '';\n // debug('getExif', params);\n if (params.length > 0) html += `Prompt ${params || ''}
`;\n html = html.replace('Negative prompt:', '
Negative');\n html = html.replace('Steps:', '
Params Steps:');\n html = html.replaceAll('\\n', '
');\n html = html.replaceAll('

', '
');\n return html;\n}\n\nasync function displayExif(el) {\n const modalExif = gradioApp().getElementById('modalExif');\n const html = await getExif(el);\n modalExif.innerHTML = html;\n}\n\nfunction showModal(event) {\n const source = event.target || event.srcElement;\n const modalImage = gradioApp().getElementById('modalImage');\n const lb = gradioApp().getElementById('lightboxModal');\n lb.ownerSVGElement = modalImage;\n modalImage.onload = () => {\n previewInstance.moveTo(0, 0);\n modalPreviewZone.focus();\n if (opts.viewer_show_metadata) displayExif(modalImage);\n };\n modalImage.src = source.src;\n if (modalImage.style.display === 'none') lb.style.setProperty('background-image', `url(${source.src})`);\n lb.style.display = 'flex';\n lb.onkeydown = modalKeyHandler;\n event.stopPropagation();\n}\n\nfunction modalDownloadImage() {\n const link = document.createElement('a');\n link.style.display = 'none';\n link.href = gradioApp().getElementById('modalImage').src;\n link.download = 'image';\n document.body.appendChild(link);\n link.click();\n setTimeout(() => {\n URL.revokeObjectURL(link.href);\n link.parentNode.removeChild(link);\n }, 0);\n}\n\nfunction modalZoomSet(modalImage, enable) {\n localStorage.setItem('modalZoom', enable ? 'yes' : 'no');\n if (modalImage) modalImage.classList.toggle('modalImageFullscreen', !!enable);\n}\n\nfunction setupImageForLightbox(image) {\n if (image.dataset.modded) return;\n image.dataset.modded = 'true';\n image.style.cursor = 'pointer';\n image.style.userSelect = 'none';\n}\n\nfunction modalZoomToggle(event) {\n const modalImage = gradioApp().getElementById('modalImage');\n modalZoomSet(modalImage, !modalImage.classList.contains('modalImageFullscreen'));\n event.stopPropagation();\n modalImageSwitch(0);\n}\n\nfunction modalTileToggle(event) {\n const modalImage = gradioApp().getElementById('modalImage');\n const modal = gradioApp().getElementById('lightboxModal');\n const isTiling = modalImage.style.display === 'none';\n if (isTiling) {\n modalImage.style.display = 'block';\n modal.style.setProperty('background-image', 'none');\n } else {\n modalImage.style.display = 'none';\n modal.style.setProperty('background-image', `url(${modalImage.src})`);\n }\n event.stopPropagation();\n modalImageSwitch(0);\n}\n\nfunction modalResetInstance(event) {\n const modalImage = document.getElementById('modalImage');\n previewInstance.dispose();\n previewInstance = Panzoom(modalImage, { zoomSpeed: 0.05, minZoom: 0.1, maxZoom: 5.0, filterKey: (/* e, dx, dy, dz */) => true });\n event.stopPropagation();\n modalImageSwitch(0);\n}\n\nfunction modalToggleParams(event) {\n const modalExif = gradioApp().getElementById('modalExif');\n if (modalExif.style.display === 'none' || modalExif.style.display === '') {\n modalExif.style.display = 'block';\n } else {\n modalExif.style.display = 'none';\n }\n event.stopPropagation();\n modalImageSwitch(0);\n}\n\nfunction galleryClickEventHandler(event) {\n if (event.button !== 0) return;\n if (event.target.nodeName === 'IMG' && !event.target.parentNode.classList.contains('thumbnail-item')) {\n const initialZoom = (localStorage.getItem('modalZoom') || true) === 'yes';\n modalZoomSet(gradioApp().getElementById('modalImage'), initialZoom);\n event.preventDefault();\n showModal(event);\n }\n}\n\nasync function bindImageViewer() {\n // Each tab has its own gradio-gallery\n const galleryPreviews = gradioApp().querySelectorAll('.gradio-gallery > div.preview');\n for (const galleryPreview of galleryPreviews) {\n if (!galleryPreview.hasAttribute('data-listener')) galleryPreview.addEventListener('click', galleryClickEventHandler, true);\n galleryPreview.setAttribute('data-listener', 'true');\n galleryPreview.querySelectorAll('img').forEach(setupImageForLightbox);\n }\n}\n\nexport async function initImageViewer() {\n const t0 = performance.now();\n // main elements\n const modal = document.createElement('div');\n modal.id = 'lightboxModal';\n\n modalPreviewZone = document.createElement('div');\n modalPreviewZone.className = 'lightboxModalPreviewZone';\n\n const modalImage = document.createElement('img');\n modalImage.id = 'modalImage';\n modalPreviewZone.appendChild(modalImage);\n previewInstance = Panzoom(modalImage, { zoomSpeed: 0.05, minZoom: 0.1, maxZoom: 5.0, filterKey: (/* e, dx, dy, dz */) => true });\n\n // toolbar\n const modalZoom = document.createElement('span');\n modalZoom.id = 'modal_zoom';\n modalZoom.className = 'cursor';\n modalZoom.innerHTML = '\\uf531';\n modalZoom.title = 'Toggle zoomed view';\n modalZoom.addEventListener('click', modalZoomToggle, true);\n\n const modalReset = document.createElement('span');\n modalReset.id = 'modal_reset';\n modalReset.className = 'cursor';\n modalReset.innerHTML = '\\uf532';\n modalReset.title = 'Reset zoomed view';\n modalReset.addEventListener('click', modalResetInstance, true);\n\n const modalTile = document.createElement('span');\n modalTile.id = 'modal_tile';\n modalTile.className = 'cursor';\n modalTile.innerHTML = '\\udb81\\udd70';\n modalTile.title = 'Preview tiling';\n modalTile.addEventListener('click', modalTileToggle, true);\n\n const modalSave = document.createElement('span');\n modalSave.id = 'modal_save';\n modalSave.className = 'cursor';\n modalSave.innerHTML = '\\udb80\\udd93';\n modalSave.title = 'Save Image';\n modalSave.addEventListener('click', modalSaveImage, true);\n\n const modalDownload = document.createElement('span');\n modalDownload.id = 'modal_download';\n modalDownload.className = 'cursor';\n modalDownload.innerHTML = '\\udb85\\udc62';\n modalDownload.title = 'Download Image';\n modalDownload.addEventListener('click', modalDownloadImage, true);\n\n const modalClose = document.createElement('span');\n modalClose.id = 'modal_close';\n modalClose.className = 'cursor';\n modalClose.innerHTML = '\\udb80\\udd57';\n modalClose.title = 'Close';\n modalClose.addEventListener('click', (evt) => closeModal(evt, true), true);\n\n const modalToggleParamsBtn = document.createElement('span');\n modalToggleParamsBtn.id = 'modal_toggle_params';\n modalToggleParamsBtn.className = 'cursor';\n modalToggleParamsBtn.innerHTML = '\\uf05a';\n modalToggleParamsBtn.title = 'Toggle Parameters';\n modalToggleParamsBtn.addEventListener('click', modalToggleParams, true);\n\n // exif\n const modalExif = document.createElement('div');\n modalExif.id = 'modalExif';\n modalExif.style = 'position: absolute; bottom: 0px; width: 100%; background-color: rgba(0, 0, 0, 0.5); color: var(--neutral-300); padding: 1em; font-size: small; line-height: 1.2em; z-index: 1; display: none;';\n\n // handlers\n modalPreviewZone.addEventListener('mousedown', () => { previewDrag = false; });\n modalPreviewZone.addEventListener('touchstart', () => { previewDrag = false; }, { passive: true });\n modalPreviewZone.addEventListener('mousemove', () => { previewDrag = true; });\n modalPreviewZone.addEventListener('touchmove', () => { previewDrag = true; }, { passive: true });\n modalPreviewZone.addEventListener('scroll', () => { previewDrag = true; });\n modalPreviewZone.addEventListener('mouseup', (evt) => closeModal(evt));\n modalPreviewZone.addEventListener('touchend', (evt) => closeModal(evt));\n\n const modalPrev = document.createElement('a');\n modalPrev.className = 'modalPrev';\n modalPrev.innerHTML = '❮';\n modalPrev.addEventListener('click', () => modalImageSwitch(-1), true);\n // modalPrev.addEventListener('keydown', modalKeyHandler, true);\n\n const modalNext = document.createElement('a');\n modalNext.className = 'modalNext';\n modalNext.innerHTML = '❯';\n modalNext.addEventListener('click', () => modalImageSwitch(1), true);\n // modalNext.addEventListener('keydown', modalKeyHandler, true);\n\n const modalControls = document.createElement('div');\n modalControls.className = 'modalControls gradio-container';\n\n // build interface\n modal.appendChild(modalPrev);\n modal.appendChild(modalPreviewZone);\n modal.appendChild(modalNext);\n modal.append(modalControls);\n modalControls.appendChild(modalZoom);\n modalControls.appendChild(modalReset);\n modalControls.appendChild(modalTile);\n modalControls.appendChild(modalSave);\n modalControls.appendChild(modalDownload);\n modalControls.appendChild(modalToggleParamsBtn);\n modalControls.appendChild(modalClose);\n modal.append(modalExif);\n\n gradioApp().appendChild(modal);\n const t1 = performance.now();\n log('initImageViewer', Math.round(t1 - t0));\n timer('initImageViewer', t1 - t0);\n}\n\nonAfterUiUpdate(bindImageViewer);\n", "import { log } from './logger';\n\n/*\n * Extra-networks completion for SD.Next prompt textareas.\n *\n * Companion to autocomplete.js: exposes sorted indices for LoRAs, embeddings, and wildcards,\n * each backed by an existing enumeration endpoint. Dispatch and insertion are driven from\n * autocomplete.js via the mode returned by getCurrentWord().\n */\n\ninterface XnItem {\n name: string;\n display?: string;\n}\n\ninterface SearchItem {\n name: string;\n display: string;\n}\n\ntype SearchResult = SearchItem & { kind: 'lora' | 'embed' | 'wildcard' };\n\n/** Binary search for the first item where item.name >= query. */\nexport function lowerBound(items: { name: string }[], query: string): number {\n let lo = 0;\n let hi = items.length;\n while (lo < hi) {\n const mid = (lo + hi) >>> 1;\n if (items[mid].name < query) lo = mid + 1;\n else hi = mid;\n }\n return lo;\n}\n\ninterface XnEngine {\n lora: XnIndex;\n embed: XnIndex;\n wildcard: XnIndex;\n fetchJson(path: string): Promise;\n loadAll(): Promise;\n searchLoras(prefix: string, limit?: number): SearchResult[];\n searchEmbeddings(prefix: string, limit?: number): SearchResult[];\n searchWildcards(prefix: string, limit?: number): SearchResult[];\n}\n\n// -- Indices --\n\nclass XnIndex {\n items: SearchItem[];\n\n constructor(items: XnItem[]) {\n // items: [{ name, display }]. Sorted in-place by lowercase name.\n this.items = items.map(({ name, display }) => ({\n name: String(name).toLowerCase(),\n display: display ?? name,\n }));\n this.items.sort((a, b) => a.name.localeCompare(b.name));\n }\n\n search(prefix: string, limit = 20): SearchItem[] {\n const query = String(prefix).toLowerCase();\n // Empty query returns the first `limit` items so `= 3) {\n for (let i = 0; i < this.items.length && matches.length < limit; i++) {\n if (this.items[i].name.includes(query)) matches.push(this.items[i]);\n }\n }\n return matches.slice(0, limit);\n }\n}\n\n// -- Engine --\n\nexport const xnEngine: XnEngine = {\n lora: new XnIndex([]),\n embed: new XnIndex([]),\n wildcard: new XnIndex([]),\n\n async fetchJson(path) {\n try {\n // const resp = await fetch(`${window.api}${path}`, { credentials: 'include' });\n const resp = await authFetch(`${window.api}${path}`);\n if (!resp.ok) throw new Error(`${resp.status}`);\n return await resp.json();\n } catch (e) {\n log('autoComplete', { xnFetchFailed: path, error: String(e) });\n return null;\n }\n },\n\n async loadAll() {\n // LoRAs: [{name, alias, path, metadata}, ...]\n const loraData = await this.fetchJson('/loras');\n if (Array.isArray(loraData)) {\n const items: XnItem[] = [];\n for (const lo of loraData) {\n if (typeof lo === 'object' && lo && 'name' in lo && typeof lo.name === 'string') items.push({ name: lo.name });\n if (typeof lo === 'object' && lo && 'alias' in lo && typeof lo.alias === 'string' && lo.alias !== (lo as { name?: string }).name) items.push({ name: lo.alias });\n }\n this.lora = new XnIndex(items);\n }\n // Embeddings: {loaded: [...], skipped: [...]}\n const embData = await this.fetchJson('/embeddings') as Record | null;\n if (embData && typeof embData === 'object') {\n const loaded = Array.isArray(embData.loaded) ? embData.loaded : [];\n this.embed = new XnIndex(loaded.map((name) => ({ name: String(name) })));\n }\n // Wildcards: [{name}, ...]\n const wcData = await this.fetchJson('/wildcards');\n if (Array.isArray(wcData)) {\n this.wildcard = new XnIndex(\n wcData\n .filter((w) => typeof w === 'object' && w && 'name' in w && typeof w.name === 'string')\n .map((w) => ({ name: w.name })),\n );\n }\n log('autoComplete', {\n xnLoaded: true,\n lora: this.lora.items.length,\n embed: this.embed.items.length,\n wildcard: this.wildcard.items.length,\n });\n },\n\n searchLoras(prefix, limit = 20) {\n return this.lora.search(prefix, limit).map((item) => ({ ...item, kind: 'lora' as const }));\n },\n\n searchEmbeddings(prefix, limit = 20) {\n return this.embed.search(prefix, limit).map((item) => ({ ...item, kind: 'embed' as const }));\n },\n\n searchWildcards(prefix, limit = 20) {\n return this.wildcard.search(prefix, limit).map((item) => ({ ...item, kind: 'wildcard' as const }));\n },\n};\n", "import { xnEngine, lowerBound } from './autocomplete_xn';\nimport { log } from './logger';\nimport { gradioApp, onAfterUiUpdate, onOptionsChanged, executeCallbacks, optionsChangedCallbacks } from './script';\nimport { timer } from './timers';\nimport { updateInput } from './ui';\n\n/*\n * Tag autocomplete for SD.Next prompt textareas.\n *\n * Ported from Enso's CodeMirror-based autocomplete (autocomplete.ts).\n * Uses binary search on sorted tag arrays for O(log n) prefix lookup,\n * with substring fallback for 4+ char queries.\n */\n\n// -- Category colors (unified 14-category scheme) --\n\nconst CATEGORY_COLORS = {\n 0: '#0075f8', // general\n 1: '#cc0000', // artist\n 2: '#ff4500', // studio\n 3: '#9900ff', // copyright\n 4: '#00ab2c', // character\n 5: '#ed5d1f', // species\n 6: '#8a66ff', // genre\n 7: '#00cccc', // medium\n 8: '#6b7280', // meta\n 9: '#228b22', // lore\n 10: '#e67e22', // lens\n 11: '#f1c40f', // lighting\n 12: '#1abc9c', // composition\n 13: '#e84393', // color\n};\n\nconst CATEGORY_NAMES = {\n 0: 'general',\n 1: 'artist',\n 2: 'studio',\n 3: 'copyright',\n 4: 'character',\n 5: 'species',\n 6: 'genre',\n 7: 'medium',\n 8: 'meta',\n 9: 'lore',\n 10: 'lens',\n 11: 'lighting',\n 12: 'composition',\n 13: 'color',\n};\n\n// Glyph + color per result kind. Renders in place of the category dot for non-tag results.\nconst KIND_GLYPHS = {\n tag: { glyph: '\u25CF', color: null }, // color pulled from tag category\n lora: { glyph: '\u25C6', color: '#8a66ff' },\n embed: { glyph: '\u25B2', color: '#1abc9c' },\n wildcard: { glyph: '\u2605', color: '#f1c40f' },\n};\n\nlet active = false;\n\ninterface TagResult {\n name: string;\n display: string;\n category: number | string;\n count: number;\n aliases?: string[];\n matchedVia?: 'alias' | 'translation';\n matchedAlias?: string;\n matchedTerm?: string;\n}\n\n// -- Utilities (ported from Enso) --\n\n/** Format post count as abbreviated string. */\nfunction formatCount(count: number): string {\n if (count >= 1_000_000) return `${(count / 1_000_000).toFixed(1)}M`;\n if (count >= 1_000) return `${Math.round(count / 1_000)}k`;\n return String(count);\n}\n\n/**\n * Estimate viewport Y of the bottom of the caret line using a persistent\n * offscreen mirror div. Styles and width are re-read from the textarea on\n * every call so resized textareas are handled correctly.\n */\nlet caretMirror: HTMLDivElement | null = null;\nlet caretMarker: HTMLSpanElement | null = null;\nconst MIRROR_PROPS = ['fontFamily', 'fontSize', 'fontWeight', 'fontStyle',\n 'lineHeight', 'letterSpacing', 'wordSpacing', 'textTransform',\n 'padding', 'border', 'boxSizing'];\n\nfunction caretViewportY(textarea: HTMLTextAreaElement): number {\n if (!caretMirror) {\n caretMirror = document.createElement('div');\n caretMirror.className = 'autocomplete-mirror';\n caretMirror.style.whiteSpace = 'pre-wrap';\n caretMirror.style.wordWrap = 'break-word';\n caretMirror.style.position = 'absolute';\n caretMirror.style.left = '-9999px';\n caretMirror.style.overflow = 'hidden';\n caretMarker = document.createElement('span');\n caretMarker.textContent = '\\u200b';\n document.body.appendChild(caretMirror);\n }\n const cs = getComputedStyle(textarea);\n for (const p of MIRROR_PROPS) caretMirror.style[p] = cs[p];\n caretMirror.style.width = `${textarea.offsetWidth}px`;\n caretMirror.textContent = textarea.value.substring(0, textarea.selectionStart);\n caretMirror.appendChild(caretMarker);\n const offset = caretMarker.offsetTop + caretMarker.offsetHeight;\n return textarea.getBoundingClientRect().top + offset - textarea.scrollTop;\n}\n\n// -- TagIndex --\n\nclass TagIndex {\n categories: Record;\n tags: TagResult[];\n aliasEntries: { name: string; display: string; tag: TagResult }[];\n translations: Map;\n tagByName: Map;\n translationEntries: { name: string; foreign: string; canonical: string }[];\n\n constructor(data: any) {\n this.categories = data.categories || {};\n // Tuples are [name, catId, count] or [name, catId, count, aliases]. Default `aliases = []`\n // keeps legacy 3-tuple dictionaries working unchanged.\n this.tags = data.tags.map(([name, category, count, aliases = []]) => ({\n name: name.toLowerCase(),\n display: name,\n category,\n count,\n aliases,\n }));\n this.tags.sort((a, b) => a.name.localeCompare(b.name));\n // Alias index parallel to this.tags. Each entry has .name so lowerBound works on both.\n this.aliasEntries = [];\n for (const tag of this.tags) {\n if (!tag.aliases || tag.aliases.length === 0) continue;\n for (const alias of tag.aliases) {\n this.aliasEntries.push({ name: alias.toLowerCase(), display: alias, tag });\n }\n }\n this.aliasEntries.sort((a, b) => a.name.localeCompare(b.name));\n // Optional translations companion: foreign_term -> canonical_tag_name.\n // tagByName is keyed on canonical lowercased name for O(1) resolution from a translation hit.\n this.translations = new Map();\n this.tagByName = new Map(this.tags.map((t) => [t.name, t]));\n if (data.translations && typeof data.translations === 'object') {\n for (const [foreign, canonical] of Object.entries(data.translations)) {\n if (typeof foreign !== 'string' || typeof canonical !== 'string') continue;\n this.translations.set(foreign.toLowerCase(), { canonical: canonical.toLowerCase(), foreign });\n }\n }\n // Sorted translation keys for prefix+substring scan via lowerBound.\n this.translationEntries = [...this.translations.entries()]\n .map(([foreignLower, { canonical, foreign }]) => ({ name: foreignLower, foreign, canonical }))\n .sort((a, b) => a.name.localeCompare(b.name));\n }\n\n /** Prefix search with binary search across canonical names and aliases. Returns matches sorted by count descending. */\n search(prefix: string, limit = 20): TagResult[] {\n const query = prefix.toLowerCase().replace(/ /g, '_');\n if (!query) return [];\n // Canonical prefix matches\n const matches = [];\n const start = lowerBound(this.tags, query);\n for (let i = start; i < this.tags.length && matches.length < limit * 5; i++) {\n if (!this.tags[i].name.startsWith(query)) break;\n matches.push(this.tags[i]);\n }\n // Alias prefix matches. Annotate so render can show \"canonical (alias)\".\n const aliasStart = lowerBound(this.aliasEntries, query);\n for (let i = aliasStart; i < this.aliasEntries.length && matches.length < limit * 10; i++) {\n const entry = this.aliasEntries[i];\n if (!entry.name.startsWith(query)) break;\n matches.push({ ...entry.tag, matchedVia: 'alias', matchedAlias: entry.display });\n }\n // Substring fallback (canonical + aliases) for 4+ char queries when prefix matching returned nothing.\n if (matches.length === 0 && query.length >= 4) {\n for (let i = 0; i < this.tags.length && matches.length < limit * 5; i++) {\n if (this.tags[i].name.includes(query)) matches.push(this.tags[i]);\n }\n for (let i = 0; i < this.aliasEntries.length && matches.length < limit * 10; i++) {\n const entry = this.aliasEntries[i];\n if (entry.name.includes(query)) matches.push({ ...entry.tag, matchedVia: 'alias', matchedAlias: entry.display });\n }\n }\n // Translation lookup. Prefix scan over foreign terms, resolving to canonical tags when present.\n if (this.translationEntries.length > 0) {\n const tStart = lowerBound(this.translationEntries, query);\n for (let i = tStart; i < this.translationEntries.length && matches.length < limit * 10; i++) {\n const entry = this.translationEntries[i];\n if (!entry.name.startsWith(query)) break;\n const canonicalTag = this.tagByName.get(entry.canonical);\n if (canonicalTag) matches.push({ ...canonicalTag, matchedVia: 'translation', matchedTerm: entry.foreign });\n }\n // Substring fallback over translation keys (CJK/short foreign terms benefit from 2-char threshold)\n if (query.length >= 2) {\n for (let i = 0; i < this.translationEntries.length && matches.length < limit * 10; i++) {\n const entry = this.translationEntries[i];\n if (entry.name.includes(query) && !entry.name.startsWith(query)) {\n const canonicalTag = this.tagByName.get(entry.canonical);\n if (canonicalTag) matches.push({ ...canonicalTag, matchedVia: 'translation', matchedTerm: entry.foreign });\n }\n }\n }\n }\n // Dedupe by canonical name; prefer canonical (no matchedVia) over alias/translation matches.\n const seen = new Map();\n for (const tag of matches) {\n const existing = seen.get(tag.name);\n if (!existing || (existing.matchedVia && !tag.matchedVia)) seen.set(tag.name, tag);\n }\n const result = [...seen.values()];\n result.sort((a, b) => b.count - a.count);\n return result.slice(0, limit);\n }\n}\n\n// -- Engine --\n\nconst engine = {\n indices: new Map(), // name -> TagIndex\n categoryColors: { ...CATEGORY_COLORS },\n categoryNames: { ...CATEGORY_NAMES },\n\n async loadEnabled() {\n const enabled = window.opts?.autocomplete_enabled || [];\n active = window.opts?.autocomplete_active || false;\n if (!active) {\n this.indices.clear();\n return;\n }\n const t0 = performance.now();\n const toLoad = enabled.filter((n) => !this.indices.has(n));\n const toRemove = [...this.indices.keys()].filter((n) => !enabled.includes(n));\n toRemove.forEach((n) => this.indices.delete(n));\n await Promise.all(toLoad.map(async (name) => {\n try {\n const resp = await authFetch(`${window.api}/autocomplete/${name}`);\n if (!resp.ok) throw new Error(`${resp.status}`);\n const data = await resp.json();\n this.indices.set(name, new TagIndex(data));\n // Extract category colors from first loaded file\n if (data.categories) {\n Object.entries(data.categories).forEach(([id, cat]) => {\n const category: any = cat;\n if (category.color) this.categoryColors[id] = category.color;\n if (category.name) this.categoryNames[id] = category.name;\n });\n }\n const t1 = performance.now();\n log('autoComplete', { loaded: name, tags: data.tags?.length || 0, time: Math.round(t1 - t0) });\n timer(`autocompleteLoad:${name}`, t1 - t0);\n } catch (e) {\n log('autoComplete', { failed: name, error: e });\n }\n }));\n },\n\n searchAll(prefix, limit = 20) {\n if (this.indices.size === 0) return [];\n const all = [];\n this.indices.forEach((index) => {\n all.push(...index.search(prefix, limit));\n });\n // Deduplicate by name, keeping highest count\n const seen = new Map();\n all.forEach((tag) => {\n const existing = seen.get(tag.name);\n if (!existing || tag.count > existing.count) seen.set(tag.name, tag);\n });\n const results = [...seen.values()];\n results.sort((a, b) => b.count - a.count);\n return results.slice(0, limit);\n },\n};\n\n// -- Textarea integration --\n\n/**\n * Extract the current completion context at the cursor position.\n *\n * Returns { word, start, end, mode } where:\n * mode === 'tag': ordinary tag completion\n * mode === 'artist': leading `@` trigger; results filtered to artist category and inserted with `@` preserved\n * mode === 'lora': inside an unclosed ` 0) {\n const ch = value[wordStart - 1];\n if (ch === ',' || ch === '\\n') break;\n wordStart--;\n }\n // Skip leading whitespace between the separator and the typed word\n while (wordStart < selectionStart && value[wordStart] === ' ') wordStart++;\n const segment = value.slice(wordStart, selectionStart);\n // LoRA / extra-network trigger: unclosed `<` with `kind:` prefix\n const before = value.slice(0, selectionStart);\n const lastOpen = before.lastIndexOf('<');\n const lastClose = before.lastIndexOf('>');\n if (lastOpen > lastClose && lastOpen >= wordStart) {\n const inside = before.slice(lastOpen + 1); // e.g. \"lora:foo\", \"lora:\", \"lor\", or \"\"\n const colon = inside.indexOf(':');\n if (colon < 0) {\n // Bare `<` (or `` kind we ship,\n // so browse-all-loras; whatever the user typed gets overwritten on accept.\n return { word: '', start: lastOpen, end: selectionStart, mode: 'lora' };\n }\n if (inside.slice(0, colon).toLowerCase() === 'lora') {\n return { word: inside.slice(colon + 1), start: lastOpen, end: selectionStart, mode: 'lora' };\n }\n // Recognized colon but unknown kind, suppress completion.\n return null;\n }\n // Wildcard trigger: unclosed `__` that doesn't close within the current word\n if (segment.startsWith('__') && !segment.slice(2).includes('__')) {\n return { word: segment.slice(2), start: wordStart, end: selectionStart, mode: 'wildcard' };\n }\n // Artist trigger: leading `@` filters tag results to the artist category.\n if (segment.startsWith('@')) {\n return { word: segment.slice(1), start: wordStart, end: selectionStart, mode: 'artist' };\n }\n // Ordinary tag\n if (!segment) return null;\n return { word: segment, start: wordStart, end: selectionStart, mode: 'tag' };\n}\n\n// Booru schemas (danbooru/e621/sankaku) all assign category id 1 to artist tags.\nconst ARTIST_CATEGORY_ID = 1;\n\n/** Escape bare parens so tag names like `fate_(series)` aren't parsed as attention syntax. */\nfunction escapeParensForPrompt(name) {\n return name.replace(/([()])/g, '\\\\$1');\n}\n\n/**\n * Insert an extra-network reference at the current trigger position.\n * kind === 'lora': inserts `` over the range including the leading `<`\n * kind === 'wildcard': inserts `__name__` over the range including the leading `__`\n * Embeddings use insertTag directly so they go through comma-separator and paren-escape logic.\n */\nfunction insertExtraNetwork(textarea, item, kind) {\n const info = getCurrentWord(textarea);\n if (!info || info.mode !== kind) return;\n const { value } = textarea;\n const before = value.slice(0, info.start);\n const after = value.slice(info.end);\n let insertion;\n if (kind === 'lora') {\n insertion = ``;\n } else if (kind === 'wildcard') {\n insertion = `__${item.display ?? item.name}__`;\n } else {\n return;\n }\n textarea.value = before + insertion + after;\n const cursorPos = before.length + insertion.length;\n textarea.selectionStart = cursorPos;\n textarea.selectionEnd = cursorPos;\n if (typeof updateInput === 'function') updateInput(textarea);\n}\n\n/** Insert a tag at the current word position, replacing the typed prefix. */\nfunction insertTag(textarea, tagName, kind = 'tag') {\n const info = getCurrentWord(textarea);\n if (!info || (info.mode !== 'tag' && info.mode !== 'artist')) return;\n const { value } = textarea;\n const before = value.slice(0, info.start);\n const after = value.slice(info.end);\n // Build insertion: tag + separator. Parens in tag names are escaped so the prompt parser doesn't read them as attention syntax.\n const useComma = window.opts?.autocomplete_append_comma ?? true;\n const sep = useComma ? ',' : '';\n const needsSepBefore = before.length > 0 && before.trimEnd().length > 0 && !before.trimEnd().endsWith(',');\n const prefix = needsSepBefore ? `${sep} ` : '';\n let suffix = `${sep} `;\n if (after.length > 0 && after.trimStart().startsWith(',')) suffix = ' ';\n // Embedding names are file-system identifiers, so underscores must be preserved regardless of the user setting.\n // Tags and artists honor `autocomplete_keep_underscores`; default is to swap `_` for space.\n const keepUnderscores = window.opts?.autocomplete_keep_underscores ?? false;\n let body = tagName;\n if (kind !== 'embed' && !keepUnderscores) body = body.replace(/_/g, ' ');\n // Artist mode optionally keeps the `@` prefix (Anima syntax). The `@` is consumed for non-Anima models.\n if (info.mode === 'artist' && window.opts?.autocomplete_at_prefix_artist) body = `@${body}`;\n const insertion = `${prefix}${escapeParensForPrompt(body)}${suffix}`;\n textarea.value = before.trimEnd() + (before.trimEnd().length > 0 ? ' ' : '') + insertion + after.trimStart();\n // Position cursor after the inserted tag + separator\n const cursorPos = before.trimEnd().length + (before.trimEnd().length > 0 ? 1 : 0) + insertion.length;\n textarea.selectionStart = cursorPos;\n textarea.selectionEnd = cursorPos;\n // Sync with Gradio\n if (typeof updateInput === 'function') updateInput(textarea);\n}\n\n// -- Dropdown --\n\nconst dropdown = {\n el: null,\n listEl: null,\n selectedIndex: -1,\n results: [],\n textarea: null,\n query: '',\n visible: false,\n resizeObserver: null as ResizeObserver | null,\n\n init() {\n this.el = document.createElement('div');\n this.el.className = 'autocompleteResults';\n this.el.style.display = 'none';\n this.listEl = document.createElement('ul');\n this.listEl.className = 'autocompleteResultsList';\n this.el.appendChild(this.listEl);\n document.body.appendChild(this.el);\n this.el.addEventListener('mousedown', (e) => e.preventDefault()); // prevent blur on click\n this.el.addEventListener('click', (e) => {\n const li = e.target.closest('li');\n if (!li) return;\n const idx = [...this.listEl.children].indexOf(li);\n if (idx >= 0 && idx < this.results.length) {\n this.selectedIndex = idx;\n this.accept();\n }\n });\n this.resizeObserver = new ResizeObserver(() => {\n if (this.visible) this.position();\n });\n },\n\n show(results, textarea, query) {\n if (results.length === 0) { this.hide(); return; }\n // Switching textareas: clear prior state so a stale render can't leak across.\n if (this.textarea && this.textarea !== textarea) this.hide();\n if (this.textarea !== textarea) this.resizeObserver?.observe(textarea);\n this.results = results;\n this.textarea = textarea;\n this.query = query || '';\n this.selectedIndex = -1;\n this.render();\n this.position();\n this.el.style.display = '';\n this.visible = true;\n },\n\n hide() {\n if (this.textarea) this.resizeObserver?.unobserve(this.textarea);\n this.textarea = null;\n this.el.style.display = 'none';\n this.visible = false;\n this.results = [];\n this.selectedIndex = -1;\n },\n\n render() {\n const keepUnderscores = window.opts?.autocomplete_keep_underscores ?? false;\n const queryNorm = this.query.toLowerCase().replace(/ /g, '_');\n this.listEl.replaceChildren();\n this.results.forEach((tag, i) => {\n const li = document.createElement('li');\n if (i === this.selectedIndex) li.classList.add('selected');\n const dot = document.createElement('span');\n dot.className = 'autocomplete-category';\n const kind = tag.kind || 'tag';\n const kindStyle = KIND_GLYPHS[kind] || KIND_GLYPHS.tag;\n dot.style.color = kindStyle.color || engine.categoryColors[tag.category] || '#888';\n dot.textContent = kindStyle.glyph;\n dot.title = kind === 'tag' ? (engine.categoryNames[tag.category] || '') : kind;\n const name = document.createElement('span');\n name.className = 'autocomplete-tag';\n // Embeddings are file-name identifiers, so they always render as-is to match how they get inserted.\n const swapForKind = kind !== 'embed';\n const tagText = (swapForKind && !keepUnderscores) ? tag.display.replace(/_/g, ' ') : tag.display;\n const canonicalMatch = tag.name.indexOf(queryNorm);\n if (canonicalMatch >= 0 && queryNorm.length > 0) {\n const mark = document.createElement('mark');\n mark.textContent = tagText.slice(canonicalMatch, canonicalMatch + queryNorm.length);\n name.append(\n document.createTextNode(tagText.slice(0, canonicalMatch)),\n mark,\n document.createTextNode(tagText.slice(canonicalMatch + queryNorm.length)),\n );\n } else {\n name.textContent = tagText;\n }\n // Alias/translation-matched rows append \" (foreign)\" with the query fragment highlighted.\n let annotationTerm = null;\n if (tag.matchedVia === 'alias') annotationTerm = tag.matchedAlias;\n else if (tag.matchedVia === 'translation') annotationTerm = tag.matchedTerm;\n if (annotationTerm) {\n const annotationDisplay = (swapForKind && !keepUnderscores) ? annotationTerm.replace(/_/g, ' ') : annotationTerm;\n const annotationLower = annotationTerm.toLowerCase();\n const annotationMatch = annotationLower.indexOf(queryNorm);\n const prefix = tag.matchedVia === 'translation' ? ' \\u{1F310} ' : ' (';\n const suffix = tag.matchedVia === 'translation' ? '' : ')';\n name.appendChild(document.createTextNode(prefix));\n if (annotationMatch >= 0 && queryNorm.length > 0) {\n const mark = document.createElement('mark');\n mark.textContent = annotationDisplay.slice(annotationMatch, annotationMatch + queryNorm.length);\n name.append(\n document.createTextNode(annotationDisplay.slice(0, annotationMatch)),\n mark,\n document.createTextNode(annotationDisplay.slice(annotationMatch + queryNorm.length)),\n );\n } else {\n name.appendChild(document.createTextNode(annotationDisplay));\n }\n if (suffix) name.appendChild(document.createTextNode(suffix));\n }\n const count = document.createElement('span');\n count.className = 'autocomplete-count';\n count.textContent = tag.count > 0 ? formatCount(tag.count) : '';\n li.append(dot, name, count);\n li.addEventListener('mouseenter', () => {\n this.selectedIndex = i;\n this.updateSelection();\n });\n this.listEl.appendChild(li);\n });\n },\n\n position() {\n if (!this.textarea) return;\n const rect = this.textarea.getBoundingClientRect();\n // Position near the caret line instead of the textarea bottom\n const cursorBottom = caretViewportY(this.textarea);\n const anchorY = Math.max(rect.top, Math.min(cursorBottom, rect.bottom));\n const spaceBelow = window.innerHeight - anchorY;\n const dropHeight = Math.min(this.el.scrollHeight, 300);\n if (spaceBelow >= dropHeight || spaceBelow >= anchorY - rect.top) {\n this.el.style.top = `${anchorY + 2}px`;\n } else {\n this.el.style.top = `${anchorY - dropHeight - 2}px`;\n }\n this.el.style.left = `${rect.left}px`;\n this.el.style.width = `${rect.width}px`;\n },\n\n updateSelection() {\n [...this.listEl.children].forEach((li, i) => {\n li.classList.toggle('selected', i === this.selectedIndex);\n });\n const selected = this.listEl.children[this.selectedIndex];\n if (selected) selected.scrollIntoView({ block: 'nearest' });\n },\n\n navigate(dir) {\n if (this.results.length === 0) return;\n if (this.selectedIndex === -1) {\n this.selectedIndex = dir > 0 ? 0 : this.results.length - 1;\n } else {\n this.selectedIndex = (this.selectedIndex + dir + this.results.length) % this.results.length;\n }\n this.updateSelection();\n },\n\n accept() {\n if (this.selectedIndex < 0 || this.selectedIndex >= this.results.length) {\n // Tab with no selection: select first\n if (this.results.length > 0) {\n this.selectedIndex = 0;\n this.updateSelection();\n }\n return;\n }\n const result = this.results[this.selectedIndex];\n if (this.textarea) {\n if (result.kind === 'lora' || result.kind === 'wildcard') {\n insertExtraNetwork(this.textarea, result, result.kind);\n } else {\n // 'embed' kind and untagged tag results both go through insertTag (comma-aware, paren-escaped).\n insertTag(this.textarea, result.display ?? result.name, result.kind);\n }\n }\n this.hide();\n },\n};\n\n// -- Event handlers --\n\nlet debounceInput: ReturnType | undefined;\nlet debounceFocus: ReturnType | undefined;\n\nfunction onInput(textarea) {\n if (!active) return;\n // IME candidate window open: value isn't committed, and Enter would race with tag accept.\n if (textarea.dataset.imeActive === '1') return;\n const minChars = window.opts?.autocomplete_min_chars ?? 3;\n const info = getCurrentWord(textarea);\n if (!info) {\n dropdown.hide();\n return;\n }\n // Threshold by mode. Trigger characters carry their own signal so we can lower (or zero) the bar.\n let threshold = minChars;\n if (info.mode === 'lora' || info.mode === 'wildcard') threshold = 0;\n else if (info.mode === 'artist') threshold = 1;\n if (info.word.length < threshold) {\n dropdown.hide();\n return;\n }\n clearTimeout(debounceInput);\n debounceInput = setTimeout(() => {\n let results;\n if (info.mode === 'lora') {\n results = xnEngine.searchLoras(info.word);\n } else if (info.mode === 'wildcard') {\n results = xnEngine.searchWildcards(info.word);\n } else if (info.mode === 'artist') {\n // `@` trigger: tag-search filtered to the artist category. The category-1 color carries the visual cue.\n results = engine.searchAll(info.word).filter((t) => t.category === ARTIST_CATEGORY_ID);\n } else {\n const tagResults = engine.searchAll(info.word);\n const embedResults = xnEngine.searchEmbeddings(info.word);\n // Embeddings fold into tag-mode results (a1111 tagcomplete parity).\n results = [...embedResults, ...tagResults];\n }\n dropdown.show(results, textarea, info.word);\n }, 150);\n}\n\nfunction onKeyDown(e) {\n if (!dropdown.visible) return;\n if (e.isComposing) return; // IME candidate selection, let the browser commit the candidate\n // Modifier + nav/accept keys belong to other handlers (editAttention.js on Ctrl+Arrow,\n // generate hotkey on Ctrl+Enter). Let them through even with the dropdown open.\n const hasModifier = e.ctrlKey || e.metaKey || e.altKey;\n switch (e.key) {\n case 'ArrowDown':\n if (hasModifier) return;\n e.preventDefault();\n e.stopPropagation();\n dropdown.navigate(1);\n break;\n case 'ArrowUp':\n if (hasModifier) return;\n e.preventDefault();\n e.stopPropagation();\n dropdown.navigate(-1);\n break;\n case 'Enter':\n if (hasModifier) return;\n if (dropdown.selectedIndex >= 0) {\n e.preventDefault();\n e.stopPropagation();\n dropdown.accept();\n }\n break;\n case 'Tab':\n if (hasModifier) return;\n e.preventDefault();\n e.stopPropagation();\n dropdown.accept();\n break;\n case 'Escape':\n e.preventDefault();\n e.stopPropagation();\n dropdown.hide();\n break;\n default:\n break;\n }\n}\n\n/** Attach autocomplete to a single textarea. */\nfunction attachAutocomplete(textarea) {\n textarea.addEventListener('input', () => onInput(textarea));\n textarea.addEventListener('keydown', onKeyDown);\n textarea.addEventListener('compositionstart', () => { textarea.dataset.imeActive = '1'; });\n textarea.addEventListener('compositionend', () => { delete textarea.dataset.imeActive; });\n textarea.addEventListener('focusin', () => {\n if (dropdown.visible && dropdown.textarea && dropdown.textarea !== textarea) dropdown.hide();\n // Cancel any pending hide from a recent blur so refocusing within 200ms doesn't close the dropdown.\n clearTimeout(debounceFocus);\n debounceFocus = undefined;\n // Re-fire input handling so a partial tag at the cursor reopens the dropdown.\n onInput(textarea);\n });\n textarea.addEventListener('focusout', () => {\n // Cancel any in-flight debounced dropdown.show; otherwise it fires against a stale textarea.\n clearTimeout(debounceInput);\n debounceFocus = setTimeout(() => dropdown.hide(), 200);\n });\n}\n\n// -- Prompt textarea IDs --\n\nconst PROMPT_IDS = [\n 'txt2img_prompt', 'txt2img_neg_prompt',\n 'img2img_prompt', 'img2img_neg_prompt',\n 'control_prompt', 'control_neg_prompt',\n 'video_prompt', 'video_neg_prompt',\n];\n\n// -- Active button --\n\nfunction patchActiveButton() {\n const buttons = [...gradioApp().querySelectorAll('.autocomplete-active')];\n active = window.opts?.autocomplete_active || false;\n buttons.forEach((btn) => {\n btn.classList.toggle('autocomplete-active', active);\n btn.classList.toggle('autocomplete-inactive', !active);\n btn.parentElement.onclick = () => {\n active = !active;\n window.opts.autocomplete_active = !active;\n btn.classList.toggle('autocomplete-active', active);\n btn.classList.toggle('autocomplete-inactive', !active);\n };\n });\n}\n\n// -- Config bridge --\n\n/** Monkey-patch script config bridge textboxes to push autocomplete config changes to window.opts immediately. */\nlet bridgeWarnedMissingDescriptor = false;\nfunction patchConfigBridge() {\n const proto = Object.getOwnPropertyDescriptor(HTMLTextAreaElement.prototype, 'value');\n if (!proto?.get || !proto?.set) {\n if (!bridgeWarnedMissingDescriptor) {\n log('autoComplete', { bridge: 'skipped', reason: 'HTMLTextAreaElement.prototype.value descriptor missing' });\n bridgeWarnedMissingDescriptor = true;\n }\n return;\n }\n const elements = gradioApp().querySelectorAll('[id$=\"_tag_autocomplete_config_json\"]');\n for (const el of elements) {\n const textarea = el.querySelector('textarea');\n if (!textarea || textarea.acBridgePatched) continue;\n textarea.acBridgePatched = true;\n Object.defineProperty(textarea, 'value', {\n set(newValue) {\n const oldValue = proto.get.call(textarea);\n proto.set.call(textarea, newValue);\n if (oldValue !== newValue && newValue) {\n try {\n const cfg = JSON.parse(newValue);\n for (const [key, val] of Object.entries(cfg)) window.opts[key] = val;\n executeCallbacks(optionsChangedCallbacks);\n } catch { /* ignore parse errors; the bridge is best-effort */ }\n }\n },\n get() { return proto.get.call(textarea); },\n });\n }\n}\n\n// -- Initialization --\n\nexport async function initAutocomplete() {\n const t0 = performance.now();\n const enabled = window.opts?.autocomplete_enabled || [];\n active = window.opts?.autocomplete_active || false;\n log('autoComplete', { active, enabled });\n // Inject styles (CSS files in javascript/ are not auto-loaded)\n const style = document.createElement('style');\n style.textContent = `\n .autocompleteResults { position: fixed; z-index: 9999; max-height: 300px; overflow-y: auto;\n background: var(--sd-main-background-color, var(--background-fill-primary, #1f2937));\n border: 1px solid var(--sd-input-border-color, var(--border-color-primary, #374151));\n border-radius: var(--sd-border-radius, 6px); box-shadow: 0 4px 16px rgba(0,0,0,0.4);\n font-size: 13px; scrollbar-width: thin; color: var(--body-text-color-subdued); }\n .autocompleteResultsList { list-style: none; margin: 0; padding: 4px 0; }\n .autocompleteResultsList > li { display: flex; align-items: center; padding: 6px 12px; cursor: pointer;\n gap: 8px; line-height: 1.4; transition: background 0.1s ease; border-bottom: 1px solid rgba(255,255,255,0.03); }\n .autocompleteResultsList > li:last-child { border-bottom: none; }\n .autocompleteResultsList > li:hover { background: var(--sd-panel-background-color, var(--input-background-fill-focus, #374151)); }\n .autocompleteResultsList > li.selected { background: var(--sd-main-accent-color, var(--button-primary-background-fill, #4b5563)); }\n .autocomplete-category { font-size: 10px; flex-shrink: 0; width: 10px; text-align: center; cursor: help; }\n .autocomplete-tag { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n .autocomplete-tag mark { background: transparent; color: inherit; font-weight: 700; }\n .autocomplete-count { font-size: 0.75em; opacity: 0.45; flex-shrink: 0; font-variant-numeric: tabular-nums;\n background: rgba(255,255,255,0.06); padding: 1px 6px; border-radius: 8px; min-width: 28px; text-align: right; }\n `;\n document.head.appendChild(style);\n dropdown.init();\n await engine.loadEnabled();\n xnEngine.loadAll();\n // Attach to all prompt textareas; even if no dictionaries loaded yet, they may be enabled later via script UI\n let attached = 0;\n PROMPT_IDS.forEach((id) => {\n const textarea = gradioApp().querySelector(`#${id} > label > textarea`);\n if (textarea) {\n attachAutocomplete(textarea);\n attached++;\n }\n });\n // Reload when settings change\n\n async function optionsChangedCallback() {\n const newActive = window.opts?.autocomplete_active || false;\n const newEnabled = window.opts?.autocomplete_enabled || [];\n const currentKeys = [...engine.indices.keys()].sort().join(',');\n const newKeys = [...newEnabled].sort().join(',');\n if ((currentKeys !== newKeys) || (active !== newActive)) {\n log('autoComplete', { reload: newEnabled });\n await engine.loadEnabled();\n active = newActive;\n patchActiveButton();\n }\n xnEngine.loadAll();\n }\n onOptionsChanged(optionsChangedCallback);\n // Watch for config updates from the script UI bridge\n patchConfigBridge();\n patchActiveButton();\n onAfterUiUpdate(patchConfigBridge);\n const t1 = performance.now();\n log('autoComplete', { attached, dicts: engine.indices.size, time: Math.round(t1 - t0) });\n timer('autocompleteInit', t1 - t0);\n}\n", "/* eslint-disable @typescript-eslint/no-use-before-define */\nimport { log } from './logger';\nimport { gradioApp } from './script';\nimport { timer } from './timers';\n\nlet hintsObserver: MutationObserver | null = null;\nconst allLocales = ['en', 'tb', 'nb', 'hr', 'es', 'it', 'fr', 'de', 'pt', 'ru', 'zh', 'ja', 'ko', 'hi', 'ar', 'bn', 'ur', 'id', 'vi', 'tr', 'sr', 'po', 'he', 'xx', 'qq', 'tlh'];\nconst localeData = {\n prev: null,\n locale: null,\n data: [],\n timeout: null,\n finished: false,\n initial: true,\n type: 2,\n hint: null,\n btn: null,\n expandTimeout: undefined, // Property for expansion timeout\n currentElement: null, // Track current element for expansion\n};\nlet localeTimeout: ReturnType | undefined;\nconst isTouchDevice = 'ontouchstart' in window;\n\nasync function cycleLocale() {\n clearTimeout(localeTimeout);\n localeTimeout = setTimeout(() => {\n log('cycleLocale', localeData.prev, localeData.locale);\n const index = allLocales.indexOf(localeData.prev);\n localeData.locale = allLocales[(index + 1) % allLocales.length];\n localeData.btn.innerText = localeData.locale;\n // localeData.btn.style.backgroundColor = localeData.locale !== 'en' ? 'var(--primary-500)' : '';\n localeData.finished = false;\n localeData.data = [];\n localeData.prev = localeData.locale;\n window.opts.ui_locale = localeData.locale;\n setHints();\n }, 250);\n}\n\nasync function resetLocale() {\n clearTimeout(localeTimeout); // Prevent the single click logic\n localeData.locale = 'en';\n log('resetLocale', localeData.locale);\n const index = allLocales.indexOf(localeData.locale);\n localeData.locale = allLocales[(index) % allLocales.length];\n localeData.btn.innerText = localeData.locale;\n localeData.finished = false;\n localeData.data = [];\n window.opts.ui_locale = localeData.locale;\n setHints();\n}\n\nasync function tooltipCreate() {\n localeData.hint = document.createElement('div');\n localeData.hint.className = 'tooltip';\n localeData.hint.id = 'tooltip-container';\n localeData.hint.innerText = 'this is a hint';\n gradioApp().appendChild(localeData.hint);\n localeData.btn = gradioApp().getElementById('locale-container');\n if (!localeData.btn) {\n localeData.btn = document.createElement('div');\n localeData.btn.className = 'locale';\n localeData.btn.id = 'locale-container';\n gradioApp().appendChild(localeData.btn);\n }\n localeData.btn.innerText = localeData.locale;\n localeData.btn.ondblclick = resetLocale;\n localeData.btn.onclick = cycleLocale;\n if (window.opts.tooltips === 'None') localeData.type = 0;\n if (window.opts.tooltips === 'Browser default') localeData.type = 1;\n if (window.opts.tooltips === 'UI tooltips') localeData.type = 2;\n\n if (localeData.type === 2) { // setup event delegation for tooltips instead of individual listeners\n if (isTouchDevice) {\n gradioApp().addEventListener('touchstart', tooltipShowDelegated);\n gradioApp().addEventListener('touchend', tooltipHideDelegated);\n }\n gradioApp().addEventListener('pointerover', tooltipShowDelegated);\n gradioApp().addEventListener('pointerout', tooltipHideDelegated);\n }\n if (!hintsObserver) initializeDOMObserver();\n}\n\nasync function expandTooltip(element, longHint) {\n if (localeData.currentElement === element && localeData.hint.classList.contains('tooltip-show')) {\n const ring = localeData.hint.querySelector('.tooltip-progress-ring');\n if (ring) ring.style.opacity = '0';\n localeData.hint.classList.add('tooltip-expanded');\n setTimeout(() => {\n const longContent = localeData.hint.querySelector('.long-content');\n if (longContent) longContent.classList.add('show');\n }, 100);\n }\n}\n\nasync function tooltipShowDelegated(e) { // use event delegation to handle dynamically created elements\n if (e.target.dataset && e.target.dataset.hint) tooltipShow(e);\n}\n\nasync function tooltipHideDelegated(e) {\n if (e.target.dataset && e.target.dataset.hint) tooltipHide(e);\n}\n\nasync function tooltipShow(e) {\n if (localeData.expandTimeout) { // clear any existing expansion timeout\n clearTimeout(localeData.expandTimeout);\n localeData.expandTimeout = undefined;\n }\n\n localeData.hint.classList.remove('tooltip-expanded'); // remove expanded class and reset current element\n localeData.currentElement = e.target;\n\n if (e.target.dataset.hint) {\n const progressRing = ` // create progress ring SVG\n
\n \n \n \n \n
\n `;\n // set up the complete content structure from the start\n let content = `\n
\n ${e.target.textContent}\n ${e.target.dataset.longHint ? progressRing : ''}\n
\n
\n ${e.target.dataset.hint}\n `;\n if (e.target.dataset.longHint) content += `
${e.target.dataset.longHint}
`; // add long content if available, but keep it hidden\n if (e.target.dataset.reload) { // add reload notice if needed\n const reloadType = e.target.dataset.reload;\n let reloadText = '';\n if (reloadType === 'model') reloadText = 'Requires model reload';\n else if (reloadType === 'server') reloadText = 'Requires server restart';\n if (reloadText) {\n content += `\n
\n
\n ${reloadText}\n
\n `;\n }\n }\n\n localeData.hint.innerHTML = content;\n localeData.hint.classList.add('tooltip-show');\n\n if (e.clientX > window.innerWidth / 2) localeData.hint.classList.add('tooltip-left');\n else localeData.hint.classList.remove('tooltip-left');\n\n if (e.target.dataset.longHint) { // set up expansion timer if long hint is available\n const ring = localeData.hint.querySelector('.tooltip-progress-ring'); // start progress ring animation\n const ringProgress = localeData.hint.querySelector('.ring-progress');\n if (ring && ringProgress) {\n setTimeout(() => {\n ring.classList.add('active');\n ringProgress.classList.add('animate');\n }, 100);\n }\n localeData.expandTimeout = setTimeout(() => expandTooltip(e.target, e.target.dataset.longHint), 3000);\n }\n }\n}\n\nasync function tooltipHide(e) {\n if (localeData.expandTimeout) {\n clearTimeout(localeData.expandTimeout);\n localeData.expandTimeout = undefined;\n }\n localeData.hint.classList.remove('tooltip-show', 'tooltip-expanded');\n localeData.currentElement = null;\n}\n\nasync function replaceButtonText(el) {\n // https://www.nerdfonts.com/cheat-sheet\n // use unicode of icon with format nf-md-_circle\n const textIcons = {\n Generate: '\\uf144',\n Enqueue: '\\udb81\\udc17',\n Stop: '\\udb81\\ude66',\n Skip: '\\udb81\\ude61',\n Pause: '\\udb80\\udfe5',\n Restore: '\\udb82\\udd9b',\n Clear: '\\udb80\\udd59',\n Networks: '\\uf261',\n };\n if (textIcons[el.innerText]) {\n el.classList.add('button-icon');\n el.innerText = textIcons[el.innerText];\n }\n}\n\nasync function getLocaleData(desiredLocale = null) {\n if (desiredLocale) desiredLocale = desiredLocale.split(':')[0];\n if (desiredLocale === 'Auto') {\n try {\n localeData.locale = navigator.languages && navigator.languages.length ? navigator.languages[0] : navigator.language;\n localeData.locale = localeData.locale.split('-')[0];\n localeData.prev = localeData.locale;\n } catch (e) {\n localeData.locale = 'en';\n log('getLocale', e);\n }\n } else {\n localeData.locale = desiredLocale || 'en';\n localeData.prev = localeData.locale;\n }\n log('getLocale', { lang: desiredLocale, locale: localeData.locale });\n // primary\n let json: any = {};\n try {\n let res = await authFetch(`${window.subpath}/file=ui/locale/locale_${localeData.locale}.json`);\n if (!res || !res.ok) {\n localeData.locale = 'en';\n res = await authFetch(`${window.subpath}/file=ui/locale/locale_${localeData.locale}.json`);\n }\n json = await res.json();\n } catch { /**/ }\n\n try {\n const res = await authFetch(`${window.subpath}/file=ui/locale/override_${localeData.locale}.json`);\n if (res && res.ok) json.override = await res.json();\n } catch { /**/ }\n\n return json;\n}\n\nasync function replaceTextContent(el, text) {\n if (el.children.length === 1 && el.firstElementChild.classList.contains('mask-icon')) return;\n if (el.querySelector('span')) el = el.querySelector('span');\n if (el.querySelector('div')) el = el.querySelector('div');\n if (el.classList.contains('mask-icon')) return; // skip icon buttons\n if (el.dataset.selector) { // replace on rehosted child if exists\n el = el.firstElementChild || el.querySelector(el.dataset.selector);\n replaceTextContent(el, text);\n return;\n }\n el.textContent = text;\n}\n\nasync function setHint(el, entry) {\n if (localeData.type === 1) {\n el.title = entry.hint;\n } else if (localeData.type === 2) {\n el.dataset.hint = entry.hint;\n if (entry.longHint && entry.longHint.length > 0) el.dataset.longHint = entry.longHint;\n if (entry.reload && entry.reload.length > 0) el.dataset.reload = entry.reload;\n } else {\n // tooltips disabled\n }\n}\n\nfunction createLocaleJSON() {\n const excludeText = ['\u25BC']; // add any common non-label elements to exclude\n const ecxcludeIds = ['logo_nav']; // add any specific element IDs to exclude\n const elements = [...new Set([\n ...Array.from(gradioApp().querySelectorAll('button')),\n ...Array.from(gradioApp().querySelectorAll('h1')),\n ...Array.from(gradioApp().querySelectorAll('h2')),\n ...Array.from(gradioApp().querySelectorAll('h3')),\n ...Array.from(gradioApp().querySelectorAll('.hint')),\n ...Array.from(gradioApp().querySelectorAll('label > span')),\n ...Array.from(gradioApp().querySelectorAll('.label-wrap > span')),\n ...Array.from(gradioApp().querySelectorAll('span[data-testid=\"block-info\"]')),\n ])];\n const json = {};\n const allSeen = {};\n for (const el of elements) {\n const label = el.textContent.trim();\n if (!label || label.length < 1 || label.length > 1024) continue; // likely not UI element\n if (excludeText.includes(label)) continue; // skip common non-label elements\n if (ecxcludeIds.includes(el.id)) continue; // skip specific element IDs\n\n let hint = el.dataset.hint || '';\n if (hint.toLowerCase() === label.toLowerCase()) hint = ''; // skip if hint is same as label\n if (Object.keys(allSeen).includes(label.toLowerCase())) {\n if (hint.length === 0 || allSeen[label.toLowerCase()] === hint) continue; // seen this label and hint is empty or same as before\n hint = allSeen[label.toLowerCase()]; // use existing hint for this label\n }\n allSeen[label.toLowerCase()] = hint; // track seen labels\n\n let section = label[0].toLowerCase();\n if (section >= '0' && section <= '9') section = '0';\n if ((section < 'a' || section > 'z') && section !== '0') section = '_';\n\n let ui = el.closest('.group-extension')\n || el.closest('.group-scripts')\n || el.closest('.main-tab')\n || el.closest('.settings_section')\n || el.closest('.tabitem')\n || 'other';\n ui = ui?.id?.replace('_tabitem_parent', '').replace('_section_row', '');\n if (ui?.includes('_script')) ui = ui?.split('_').slice(1).join('_').split(':')[0];\n\n if (!json[section]) json[section] = [];\n const entry = { id: el.id || '', label, localized: '', hint, ui };\n json[section].push(entry); // add new entry\n }\n const sorted = Object.keys(json).sort().reduce((obj, key) => {\n obj[key] = json[key];\n return obj;\n }, {});\n console.log('localeJSON', sorted);\n}\n\nexport async function setHints() {\n let json: any;\n let overrideData: any[] = [];\n if (localeData.finished) return;\n if (Object.keys(opts).length === 0) return;\n const elements = [...new Set([\n ...Array.from(gradioApp().querySelectorAll('button')),\n ...Array.from(gradioApp().querySelectorAll('h2')),\n ...Array.from(gradioApp().querySelectorAll('label > span')),\n ...Array.from(gradioApp().querySelectorAll('.label-wrap > span')),\n ...Array.from(gradioApp().querySelectorAll('span[data-testid=\"block-info\"]')), // radio/checkboxgroup titles render as a bare block-info span, not under a label\n ])];\n if (elements.length === 0) return;\n if (localeData.data.length === 0) {\n json = await getLocaleData(window.opts.ui_locale);\n overrideData = Object.values(json.override || {}).flat().filter((e: any) => e.hint.length > 0);\n const jsonData = Object.values(json).flat().filter((e: any) => e.hint.length > 0);\n localeData.data = [...overrideData, ...jsonData];\n }\n if (!localeData.hint) tooltipCreate();\n let localized = 0;\n let hints = 0;\n const t0 = performance.now();\n\n for (const el of elements) {\n // localize elements text\n let found;\n if (el.id) found = localeData.data.find((l) => l.id && (l.id === el.id || el.id.endsWith(l.id))); // prefer id match for disambiguation\n if (!found) {\n if (el.dataset.original) found = localeData.data.find((l) => l.label.toLowerCase().trim() === el.dataset.original.toLowerCase().trim());\n else found = localeData.data.find((l) => l.label.toLowerCase().trim() === el.textContent.toLowerCase().trim());\n }\n if (found?.localized?.length > 0) {\n if (!el.dataset.original) el.dataset.original = el.textContent;\n replaceTextContent(el, found.localized);\n localized++;\n } else if (found?.label && !localeData.initial && (localeData.locale === 'en')) { // reset to english\n replaceTextContent(el, found.label);\n }\n // set hints\n if (found?.hint?.length > 0) {\n hints++;\n setHint(el, found);\n }\n }\n localeData.finished = true;\n localeData.initial = false;\n const t1 = performance.now();\n timer('setHints', t1 - t0);\n // localeData.btn.style.backgroundColor = localeData.locale !== 'en' ? 'var(--primary-500)' : '';\n log('touchDevice', isTouchDevice);\n log('setHints', { type: localeData.type, locale: localeData.locale, elements: elements.length, localized, hints, data: localeData.data.length, override: overrideData.length, time: Math.round(t1 - t0) });\n // sortUIElements();\n}\n\n// Apply hints to a single element immediately\nasync function applyHintToElement(el) {\n if (!localeData.data || localeData.data.length === 0) return;\n // if (!el.textContent) return;\n\n // check if element matches our selector criteria\n const isValidElement = el.tagName === 'BUTTON'\n || el.tagName === 'H2'\n || el.classList.contains('hint')\n || (el.tagName === 'SPAN' && (el.parentElement?.tagName === 'LABEL' || el.parentElement?.classList.contains('label-wrap') || el.dataset.testid === 'block-info'));\n if (!isValidElement) return;\n\n let found; // find matching hint data - prefer id match for disambiguation\n if (el.id) found = localeData.data.find((l) => l.id && (l.id === el.id || el.id.endsWith(l.id)));\n if (!found) {\n if (el.dataset.original) found = localeData.data.find((l) => l.label.toLowerCase().trim() === el.dataset.original.toLowerCase().trim());\n else found = localeData.data.find((l) => l.label.toLowerCase().trim() === el.textContent.toLowerCase().trim());\n }\n\n if (el.textContent && el.textContent.length > 0 && found?.localized?.length > 0) { // apply localization if found\n if (!el.dataset.original) el.dataset.original = el.textContent;\n replaceTextContent(el, found.localized);\n }\n\n if (found?.hint?.length > 0) setHint(el, found); // apply hint if found\n}\n\n// Initialize MutationObserver for immediate hint application\nfunction initializeDOMObserver() {\n if (hintsObserver) hintsObserver.disconnect();\n\n hintsObserver = new MutationObserver((mutations) => {\n // Process added nodes immediately\n for (const mutation of mutations) {\n if (mutation.type === 'childList') {\n for (const node of mutation.addedNodes) {\n if (node.nodeType === Node.ELEMENT_NODE) {\n // Apply hints to the node itself\n applyHintToElement(node);\n\n // Apply hints to all relevant children\n const elements = [\n ...Array.from(node.querySelectorAll('button')),\n ...Array.from(gradioApp().querySelectorAll('h1')),\n ...Array.from(gradioApp().querySelectorAll('h2')),\n ...Array.from(gradioApp().querySelectorAll('h3')),\n ...Array.from(gradioApp().querySelectorAll('.hint')),\n ...Array.from(node.querySelectorAll('label > span')),\n ...Array.from(node.querySelectorAll('.label-wrap > span')),\n ...Array.from(node.querySelectorAll('span[data-testid=\"block-info\"]')),\n ];\n\n // Include the node itself if it matches\n if (node.matches && (\n node.matches('button')\n || node.matches('h1')\n || node.matches('h2')\n || node.matches('h3')\n || node.matches('label > span')\n || node.matches('.hint')\n || node.matches('.label-wrap > span')\n || node.matches('span[data-testid=\"block-info\"]')\n )) {\n elements.push(node);\n }\n\n // Apply hints immediately to all found elements\n elements.forEach((el) => applyHintToElement(el));\n }\n }\n }\n }\n });\n\n // Start observing the entire gradio app for changes\n const targetNode = gradioApp();\n if (targetNode) {\n hintsObserver.observe(targetNode, {\n childList: true,\n subtree: true,\n });\n }\n}\n\nexport function disconnectHintsObserver() {\n if (hintsObserver) {\n hintsObserver.disconnect();\n hintsObserver = null;\n }\n}\n\n// Export for external use if needed\nconst forceReapplyHints = () => setHints();\n", "import { gradioApp, getUICurrentTabContent } from './script';\nimport { log } from './logger';\nimport { authFetch } from './authWrap';\nimport { quickApplyStyle, quickSaveStyle } from './extraNetworks';\n\ninterface ContextMenuItem {\n id: string;\n name: string;\n func: () => void;\n primary: boolean;\n}\n\nconst contextMenuInit = () => {\n let eventListenerApplied = false;\n const menuSpecs = new Map();\n\n const uid = () => Date.now().toString(36) + Math.random().toString(36).substring(2);\n\n function showContextMenu(event: MouseEvent, _element: Element, menuEntries: ContextMenuItem[]): void {\n const posx = event.clientX + document.body.scrollLeft + document.documentElement.scrollLeft;\n const posy = event.clientY + document.body.scrollTop + document.documentElement.scrollTop;\n const oldMenu = gradioApp().querySelector('#context-menu');\n if (oldMenu) oldMenu.remove();\n const contextMenu = document.createElement('nav');\n contextMenu.id = 'context-menu';\n contextMenu.style.top = `${posy}px`;\n contextMenu.style.left = `${posx}px`;\n const contextMenuList = document.createElement('ul');\n contextMenuList.className = 'context-menu-items';\n contextMenu.append(contextMenuList);\n menuEntries.forEach((entry) => {\n const contextMenuEntry = document.createElement('a');\n contextMenuEntry.innerHTML = entry.name;\n contextMenuEntry.addEventListener('click', () => entry.func());\n contextMenuList.append(contextMenuEntry);\n });\n gradioApp().appendChild(contextMenu);\n const menuWidth = contextMenu.offsetWidth + 4;\n const menuHeight = contextMenu.offsetHeight + 4;\n const windowWidth = window.innerWidth;\n const windowHeight = window.innerHeight;\n if ((windowWidth - posx) < menuWidth) contextMenu.style.left = `${windowWidth - menuWidth}px`;\n if ((windowHeight - posy) < menuHeight) contextMenu.style.top = `${windowHeight - menuHeight}px`;\n }\n\n function appendContextMenuOption(targetElementSelector: string, entryName: string, entryFunction: () => void, primary = false): string {\n let currentItems = menuSpecs.get(targetElementSelector);\n if (!currentItems) {\n currentItems = [];\n menuSpecs.set(targetElementSelector, currentItems);\n }\n const newItem = {\n id: `${targetElementSelector}_${uid()}`,\n name: entryName,\n func: entryFunction,\n primary,\n // isNew: true,\n };\n currentItems.push(newItem);\n return newItem.id;\n }\n\n function removeContextMenuOption(id: string): void {\n menuSpecs.forEach((v, k) => {\n let index = -1;\n v.forEach((e, ei) => {\n if (e.id === id) { index = ei; }\n });\n if (index >= 0) v.splice(index, 1);\n });\n }\n\n window.appendContextMenuOption = appendContextMenuOption;\n window.removeContextMenuOption = removeContextMenuOption;\n\n async function addContextMenuEventListener(): Promise {\n if (eventListenerApplied) return;\n log('initContextMenu');\n gradioApp().addEventListener('click', (e: Event) => {\n const mouseEvent = e as MouseEvent;\n if (!mouseEvent.isTrusted) return;\n const oldMenu = gradioApp().querySelector('#context-menu');\n if (oldMenu) oldMenu.remove();\n menuSpecs.forEach((v, k) => {\n const items = v.filter((item) => item.primary);\n const target = mouseEvent.target as Element | null;\n if (!target) return;\n const matched = target.closest(k);\n if (items.length > 0 && matched) {\n showContextMenu(mouseEvent, matched, items);\n mouseEvent.preventDefault();\n }\n });\n });\n gradioApp().addEventListener('contextmenu', (e: Event) => {\n const mouseEvent = e as MouseEvent;\n const oldMenu = gradioApp().querySelector('#context-menu');\n if (oldMenu) oldMenu.remove();\n menuSpecs.forEach((v, k) => {\n const items = v.filter((item) => !item.primary);\n const target = mouseEvent.target as Element | null;\n if (!target) return;\n const matched = target.closest(k);\n if (items.length > 0 && matched) {\n showContextMenu(mouseEvent, matched, items);\n mouseEvent.preventDefault();\n }\n });\n });\n eventListenerApplied = true;\n }\n return [appendContextMenuOption, removeContextMenuOption, addContextMenuEventListener];\n};\n\nconst initContextResponse = contextMenuInit();\nconst appendContextMenuOption = initContextResponse[0];\nconst removeContextMenuOption = initContextResponse[1];\nconst addContextMenuEventListener = initContextResponse[2] as () => void;\n\nlet generateOnRepeatInterval: ReturnType | null = null;\n\nexport const generateForever = (genbuttonid: string): void => {\n if (generateOnRepeatInterval) {\n log('generateForever: cancel');\n clearInterval(generateOnRepeatInterval);\n generateOnRepeatInterval = null;\n } else {\n const genbutton = gradioApp().querySelector(genbuttonid);\n if (!(genbutton instanceof HTMLElement)) return;\n const isBusy = () => {\n let busy = document.getElementById('progressbar')?.style.display === 'block';\n if (!busy) {\n // Also check in Modern UI\n const outerButton = genbutton.parentElement.closest('button');\n busy = outerButton?.classList.contains('generate') && outerButton?.classList.contains('active');\n }\n return busy;\n };\n log('generateForever: start');\n if (!isBusy()) genbutton.click();\n generateOnRepeatInterval = setInterval(() => {\n if (!isBusy()) genbutton.click();\n }, 500);\n }\n};\nwindow.generateForever = generateForever;\n\nconst reprocessClick = (tabId: string, state: string): void => {\n const btn = document.getElementById(`${tabId}_${state}`);\n window.submit_state = state;\n if (btn) btn.click();\n};\n\nconst getStatus = async () => {\n const headers = new Headers();\n const body = JSON.stringify({ id_task: -1, id_live_preview: false });\n headers.set('Content-Type', 'application/json');\n const tab = getUICurrentTabContent()?.id.replace('tab_', '') || '';\n const el = gradioApp().querySelector(`#html_log_${tab} .performance p`);\n\n let res;\n let data;\n res = await fetch('./internal/progress', { method: 'POST', headers, body });\n if (res?.ok) {\n data = await res.json();\n log('progressInternal:', data);\n if (el) el.innerText += `\\nProgress internal:\\n${JSON.stringify(data, null, 2)}`;\n }\n res = await authFetch('./sdapi/v1/progress?skip_current_image=true', { method: 'GET', headers });\n if (res?.ok) {\n data = await res.json();\n log('progressAPI:', data);\n if (el) el.innerText += `\\nProgress API:\\n${JSON.stringify(data, null, 2)}`;\n }\n};\n\nexport async function initContextMenu() {\n for (const tab of ['txt2img', 'img2img', 'control', 'video']) {\n appendContextMenuOption(`#${tab}_generate`, 'Get server status', getStatus);\n appendContextMenuOption(`#${tab}_generate`, 'Copy prompt to clipboard', () => navigator.clipboard.writeText(document.querySelector(`#${tab}_prompt > label > textarea`).value));\n appendContextMenuOption(`#${tab}_generate`, 'Generate forever', () => generateForever(`#${tab}_generate`));\n appendContextMenuOption(`#${tab}_generate`, 'Apply selected style', quickApplyStyle);\n appendContextMenuOption(`#${tab}_generate`, 'Quick save style', quickSaveStyle);\n appendContextMenuOption(`#${tab}_reprocess`, 'Decode full quality', () => reprocessClick(tab, 'reprocess_decode'), true);\n appendContextMenuOption(`#${tab}_reprocess`, 'Refine & HiRes pass', () => reprocessClick(tab, 'reprocess_refine'), true);\n appendContextMenuOption(`#${tab}_reprocess`, 'Detailer pass', () => reprocessClick(tab, 'reprocess_detail'), true);\n }\n // Right-click send-to-control button for prompt/params-only transfer.\n for (const tab of ['gallery', 'txt2img', 'img2img', 'extras']) {\n appendContextMenuOption(`#${tab}_tabitem #control_tab`, 'Transfer only prompt to Images tab', () => {\n document.querySelector(`#image_buttons_${tab} #control_tab_prompt`)?.click();\n document.getElementById('control_nav')?.click();\n });\n appendContextMenuOption(`#${tab}_tabitem #control_tab`, 'Transfer all parameters to Images tab', () => {\n document.querySelector(`#image_buttons_${tab} #control_tab_params`)?.click();\n document.getElementById('control_nav')?.click();\n });\n }\n addContextMenuEventListener();\n}\n", "import { gradioApp } from './script';\n\nexport function uiOpenSubmenus() {\n const accordions = Array.from(gradioApp().querySelectorAll('.gradio-accordion'));\n const states: Record = {};\n accordions.forEach((el) => {\n const labelEl = el.querySelector('.label-wrap > span:not(.icon)');\n const name = labelEl instanceof HTMLElement ? labelEl.innerText.trim() : '';\n if (!name) return;\n const children = Array.from(el.childNodes);\n const open = children.filter((c) => c instanceof HTMLElement && c.style.display === 'block');\n if (states[name] === undefined) states[name] = open.length > 0;\n });\n return states;\n}\n\nexport async function getUIDefaults() {\n const btn = gradioApp().getElementById('ui_defaults_view');\n if (!btn) return;\n const intersectionObserver = new IntersectionObserver((entries) => {\n if (entries[0].intersectionRatio <= 0) { /* Pass */ }\n if (entries[0].intersectionRatio > 0) btn.click();\n });\n intersectionObserver.observe(btn); // monitor visibility of tab\n}\n\nwindow.uiOpenSubmenus = uiOpenSubmenus;\n", "import { error, log, xhrPost } from './logger';\nimport { authFetch } from './authWrap';\nimport { timer } from './timers';\n\nexport const appStartTime = performance.now();\nlet monitorLogActive = false;\n\nasync function preloadImages(): Promise {\n const dark = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches;\n const imagePromises: Promise[] = [];\n const num = Math.floor(9.99 * Math.random());\n const imageUrls = [\n `file=ui/assets/logo-bg-${dark ? 'dark' : 'light'}.jpg`,\n `file=ui/assets/logo-bg-${num}.jpg`,\n ];\n for (const url of imageUrls) {\n const img = new Image();\n const promise = new Promise((resolve, reject) => {\n img.onload = () => resolve();\n img.onerror = () => reject(new Error(`failed to preload image: ${url}`));\n });\n img.src = url;\n imagePromises.push(promise);\n }\n try {\n await Promise.all(imagePromises);\n return true;\n } catch (err) {\n error(`preloadImages: ${err}`);\n return false;\n }\n}\n\nfunction joinArgs(messages: unknown[]): string {\n let output = '';\n for (let i = 0; i < messages.length; i++) {\n let arg = messages[i];\n if (arg === undefined) arg = 'undefined';\n if (arg === null) arg = 'null';\n output += ' ';\n if (typeof arg === 'object') output += JSON.stringify(arg).replace(/[\"]+/g, '');\n else output += arg;\n }\n return output;\n}\n\nfunction monitorLog(): void {\n if (window.logBufferDirty) {\n window.logBufferDirty = false;\n const maxLines = 100; // print last n logs from ring buffer to splash-log\n const lines: string[] = [];\n // print last n logs from ring buffer in time order\n for (let i = Math.max(0, window.logRingBuffer.length - maxLines); i < window.logRingBuffer.length; i++) {\n const logEntry = window.logRingBuffer[i];\n let color = 'white';\n if (logEntry.type === 'error') color = 'palevioletred';\n else if (logEntry.type === 'debug') color = 'gray';\n const html = `
${logEntry.ts}   ${joinArgs(logEntry.msg)}
`;\n lines.push(html);\n }\n const splashLogEl = document.getElementById('splashLog');\n if (splashLogEl) splashLogEl.innerHTML = lines.join('');\n }\n if (monitorLogActive) setTimeout(monitorLog, 250);\n}\n\nexport async function removeSplash() {\n const splash = document.getElementById('splash');\n if (splash) splash.remove();\n log('removeSplash');\n const t = Math.round(performance.now() - appStartTime);\n log('startupTime', t);\n timer('splashVisible', t);\n xhrPost(`${window.api}/log`, { message: `ready time=${t}` });\n monitorLogActive = false;\n}\n\nasync function createSplash() {\n const dark = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches;\n log('createSplash', { theme: dark ? 'dark' : 'light' });\n const num = Math.floor(9.99 * Math.random());\n const splash = `\n
\n
\n
\n
\n
`;\n document.body.insertAdjacentHTML('beforeend', splash);\n const ok = await preloadImages();\n if (!ok) {\n removeSplash();\n return;\n }\n const imgEl = `
`;\n const splashEl = document.getElementById('splash');\n if (splashEl) splashEl.insertAdjacentHTML('afterbegin', imgEl);\n\n monitorLogActive = true;\n monitorLog();\n\n await authFetch(`${window.api}/motd`)\n .then((res) => res.text())\n .then((text) => {\n const clean = text.replace(/[\"]+/g, '');\n const boldMatch = clean.match(/(.*?)<\\/b>/);\n const boldText = boldMatch ? boldMatch[1] : clean;\n if (boldMatch) log('getMOTD', { version: boldText });\n else log('getMOTD', { text: clean });\n const motdEl = document.getElementById('motd');\n if (motdEl) motdEl.innerHTML = clean;\n })\n .catch((err) => error(`getMOTD: ${err}`));\n\n log('loadGradioUi');\n}\n\nwindow.onload = createSplash;\n", "import { log } from './logger';\n\nexport function addLegacyNotice() {\n log('legacyNotice');\n const notice = document.createElement('div');\n notice.id = 'legacy-notice';\n notice.className = 'legacy-standard';\n notice.textContent = 'Legacy';\n notice.title = 'Standard UI is a legacy interface that is no longer maintained and will be removed in the future. Please switch to ModernUI for best experience.';\n document.body.appendChild(notice);\n}\n", "import { initChangelog } from './changelog';\nimport { setupControlUI } from './control';\nimport { initiGenerationParams } from './generationParams';\nimport { initDragDrop } from './imageParams';\nimport { initAccordions } from './inputAccordion';\nimport { initIndexDB } from './indexdb';\nimport { initLogMonitor } from './logMonitor';\nimport { monitorConnection } from './monitor';\nimport { setRefreshInterval } from './progressBar';\nimport { initPromptChecker } from './promptChecker';\nimport { initModels, initSettings } from './settings';\nimport { initGallery } from './gallery';\nimport { initImageViewer } from './imageViewer';\nimport { reconnectUI } from './ui';\nimport { setupExtraNetworks, showNetworks, applyStyles } from './extraNetworks';\nimport { initAutocomplete } from './autocomplete';\nimport { setHints, disconnectHintsObserver } from './setHints';\nimport { initContextMenu } from './contextMenus';\nimport { executeCallbacks, onUiLoaded, onUiReady, sleep, uiReadyCallbacks, initTableSorter } from './script';\nimport { timer, logTimers } from './timers';\nimport { getUIDefaults } from './uiConfig';\nimport { log } from './logger';\nimport { appStartTime, removeSplash } from './loader';\nimport { addLegacyNotice } from './legacy';\n\nwindow.api = '/sdapi/v1';\nwindow.subpath = '';\n\nconst startupPromises: Promise[] = [];\nlet ok = false;\n\nasync function waitForOpts() {\n // make sure all of the ui is ready and options are loaded\n const t0 = performance.now();\n let t1 = performance.now();\n while (true) {\n if (t1 - t0 > 120000) {\n log('waitForOpts timeout');\n break;\n }\n if (window.opts && Object.keys(window.opts).length > 0) {\n ok = window.opts.theme_type === 'Modern' ? 'uiux_separator_appearance' in window.opts : true;\n if (ok) {\n log('waitForOpts', Math.round(t1 - t0));\n timer('waitForOpts', t1 - t0);\n break;\n }\n }\n await sleep(100);\n t1 = performance.now();\n }\n}\n\nasync function postStartup() {\n log('postStartup');\n disconnectHintsObserver();\n logTimers();\n}\n\nasync function updateSubpath() {\n log('mountURL', window.opts.subpath);\n if (window.opts.subpath?.length > 0) {\n window.subpath = window.opts.subpath;\n window.api = `${window.subpath}/sdapi/v1`;\n }\n log('API', { url: window.api });\n}\n\nasync function initStartup() {\n const t0 = performance.now();\n log('initGradio', Math.round(t0 - appStartTime));\n timer('initGradio', t0 - appStartTime);\n log('initUi');\n if (window.setupLogger) await window.setupLogger();\n\n // all items here are non-blocking async calls\n\n startupPromises.push(initModels());\n startupPromises.push(getUIDefaults());\n startupPromises.push(initPromptChecker());\n startupPromises.push(initContextMenu());\n startupPromises.push(initDragDrop());\n startupPromises.push(Promise.resolve(initAccordions()));\n startupPromises.push(Promise.resolve(initSettings()));\n startupPromises.push(Promise.resolve(initImageViewer()));\n startupPromises.push(Promise.resolve(initGallery()));\n startupPromises.push(Promise.resolve(initiGenerationParams()));\n startupPromises.push(Promise.resolve(initChangelog()));\n startupPromises.push(Promise.resolve(setupControlUI()));\n\n // reconnect server session\n await reconnectUI();\n await waitForOpts();\n await updateSubpath();\n\n executeCallbacks(uiReadyCallbacks);\n\n // optionally wait for modern ui\n if (window.waitForUiReady) await window.waitForUiReady();\n\n // post startup tasks that may take longer but are not critical\n startupPromises.push(Promise.resolve(initLogMonitor()));\n startupPromises.push(Promise.resolve(setRefreshInterval()));\n startupPromises.push(Promise.resolve(setupExtraNetworks()));\n startupPromises.push(Promise.resolve(initAutocomplete()));\n startupPromises.push(Promise.resolve(monitorConnection()));\n startupPromises.push(Promise.resolve(showNetworks()));\n startupPromises.push(Promise.resolve(setHints()));\n startupPromises.push(Promise.resolve(applyStyles()));\n startupPromises.push(Promise.resolve(initIndexDB()));\n startupPromises.push(Promise.resolve(initTableSorter()));\n\n if (window.opts.theme_type !== 'Modern') addLegacyNotice();\n\n const t1 = performance.now();\n log('initStartup', Math.round(1000 * (t1 - t0) / 1000000));\n\n removeSplash();\n\n await Promise.all(startupPromises);\n const t2 = performance.now();\n log('initComplete', Math.round(1000 * (t2 - t0) / 1000000));\n postStartup();\n}\n\nonUiLoaded(initStartup);\nonUiReady(() => log('uiReady'));\n\n// onAfterUiUpdate(() => log('evt onAfterUiUpdate'));\n// onUiLoaded(() => log('evt onUiLoaded'));\n// onOptionsChanged(() => log('evt onOptionsChanged'));\n// onUiTabChange(() => log('evt onUiTabChange'));\n// onUiUpdate(() => log('evt onUiUpdate'));\n", "import { randomId } from './progressBar';\n\nimport { log } from './logger';\nimport { gradioApp } from './script';\nimport { restartReload, updateInput } from './ui';\n\nexport function extensions_apply(_extensionsDisabledList: unknown, _extensionsUpdateList: unknown, disableAll: unknown): [string, string, unknown] {\n const disable = [];\n const update = [];\n gradioApp().querySelectorAll('#extensions input[type=\"checkbox\"]').forEach((x) => {\n if (!(x instanceof HTMLInputElement)) return;\n if (x.name.startsWith('enable_') && !x.checked) disable.push(x.name.substring(7));\n if (x.name.startsWith('update_') && x.checked) update.push(x.name.substring(7));\n });\n restartReload();\n log('Extensions apply:', { disable, update });\n return [JSON.stringify(disable), JSON.stringify(update), disableAll];\n}\n\nexport function extensions_check(_info: unknown, _extensionsDisabledList: unknown, searchText: unknown, sortColumn: unknown): [string, string, unknown, unknown] {\n const disable = [];\n gradioApp().querySelectorAll('#extensions input[type=\"checkbox\"]').forEach((x) => {\n if (!(x instanceof HTMLInputElement)) return;\n if (x.name.startsWith('enable_') && !x.checked) disable.push(x.name.substring(7));\n });\n const id = randomId();\n log('Extensions check:', { disable });\n return [id, JSON.stringify(disable), searchText, sortColumn];\n}\n\nexport function install_extension(button: HTMLButtonElement | HTMLInputElement, url: string): void {\n button.disabled = true;\n button.value = 'Installing...';\n button.innerHTML = 'installing';\n const textarea = gradioApp().querySelector('#extension_to_install textarea');\n if (!(textarea instanceof HTMLTextAreaElement)) return;\n textarea.value = url;\n updateInput(textarea);\n log('Extension install:', { url });\n const installBtn = gradioApp().querySelector('#install_extension_button');\n if (installBtn instanceof HTMLElement) installBtn.click();\n}\n\nexport function uninstall_extension(button: HTMLButtonElement | HTMLInputElement, url: string): void {\n button.disabled = true;\n button.value = 'Uninstalling...';\n button.innerHTML = 'uninstalling';\n const textarea = gradioApp().querySelector('#extension_to_install textarea');\n if (!(textarea instanceof HTMLTextAreaElement)) return;\n textarea.value = url;\n updateInput(textarea);\n log('Extension uninstall:', { url });\n const uninstallBtn = gradioApp().querySelector('#uninstall_extension_button');\n if (uninstallBtn instanceof HTMLElement) uninstallBtn.click();\n}\n\nexport function update_extension(button: HTMLButtonElement | HTMLInputElement, url: string): void {\n button.value = 'Updating...';\n button.innerHTML = 'updating';\n const textarea = gradioApp().querySelector('#extension_to_install textarea');\n if (!(textarea instanceof HTMLTextAreaElement)) return;\n textarea.value = url;\n updateInput(textarea);\n log('Extension update:', { url });\n const updateBtn = gradioApp().querySelector('#update_extension_button');\n if (updateBtn instanceof HTMLInputElement) updateBtn.click();\n}\n\nwindow.extensions_apply = extensions_apply;\nwindow.extensions_check = extensions_check;\nwindow.uninstall_extension = uninstall_extension;\nwindow.install_extension = install_extension;\nwindow.update_extension = update_extension;\n", "import { log } from './logger';\nimport { gradioApp, uiElementIsVisible, uiElementInSight } from './script';\n\ntype PromptDropTarget = EventTarget & {\n placeholder?: string;\n closest: (selector: string) => Element | null;\n};\n\nfunction isValidImageList(files: FileList | null | undefined): files is FileList {\n return files && files?.length === 1 && ['image/png', 'image/gif', 'image/jpeg'].includes(files[0].type);\n}\n\nfunction dropReplaceImage(imgWrap: Element, files: FileList): void {\n log('dropReplaceImage', imgWrap, files);\n if (!isValidImageList(files)) return;\n const tmpFile = files[0];\n imgWrap.querySelector('.modify-upload button + button, .touch-none + div button + button')?.click();\n const callback = () => {\n const fileInput = imgWrap.querySelector('input[type=\"file\"]');\n if (fileInput instanceof HTMLInputElement) {\n if (files.length === 0) {\n const dt = new DataTransfer();\n dt.items.add(tmpFile);\n fileInput.files = dt.files;\n } else {\n fileInput.files = files;\n }\n fileInput.dispatchEvent(new Event('change'));\n }\n };\n\n if (imgWrap.closest('#pnginfo_image')) {\n const oldFetch = window.fetch;\n window.fetch = async (input: RequestInfo | URL, options?: RequestInit) => {\n const response = await oldFetch(input, options);\n if (input === 'api/predict/') {\n const content = await response.text();\n window.fetch = oldFetch;\n window.requestAnimationFrame(() => callback());\n return new Response(content, {\n status: response.status,\n statusText: response.statusText,\n headers: response.headers,\n });\n }\n return response;\n };\n } else {\n window.requestAnimationFrame(() => callback());\n }\n}\n\nwindow.document.addEventListener('dragover', (e) => {\n const target = e.composedPath()[0] as PromptDropTarget;\n const imgWrap = target.closest('[data-testid=\"image\"]');\n if (!imgWrap && target.placeholder && target.placeholder.indexOf('Prompt') === -1) return;\n if ((e.dataTransfer?.files?.length || 0) > 0) {\n e.stopPropagation();\n e.preventDefault();\n e.dataTransfer.dropEffect = 'copy';\n }\n});\n\nwindow.document.addEventListener('drop', (e) => {\n const target = e.composedPath()[0] as PromptDropTarget;\n log('dropEvent', e, target);\n if (!target.placeholder) return;\n if (target.placeholder.indexOf('Prompt') === -1) return;\n const imgWrap = target.closest('[data-testid=\"image\"]');\n if (!imgWrap) return;\n if ((e.dataTransfer?.files?.length || 0) > 0) {\n e.stopPropagation();\n e.preventDefault();\n dropReplaceImage(imgWrap, e.dataTransfer.files);\n }\n});\n\nwindow.addEventListener('paste', (e) => {\n log('pasteEvent', e);\n const files = e.clipboardData?.files;\n if (!isValidImageList(files)) return;\n const visibleImageFields = [...gradioApp().querySelectorAll('[data-testid=\"image\"]')]\n .filter((el) => uiElementIsVisible(el))\n .sort((a, b) => Number(uiElementInSight(b)) - Number(uiElementInSight(a)));\n if (!visibleImageFields.length) return;\n const firstFreeImageField = visibleImageFields.filter((el) => el.querySelector('input[type=file]'))?.[0];\n dropReplaceImage(firstFreeImageField || visibleImageFields[visibleImageFields.length - 1], files);\n});\n", "import { gradioApp, onUiLoaded } from './script';\nimport { log, error } from './logger';\nimport { authFetch } from './authWrap';\n\ninterface CivitFile {\n url?: string;\n name?: string;\n type?: string;\n size?: number;\n}\n\ninterface CivitImage {\n url: string;\n}\n\ninterface CivitVersion {\n id: number;\n name?: string;\n base?: string;\n mtime: string;\n availability?: string;\n desc?: string;\n files: CivitFile[];\n images: CivitImage[];\n}\n\ninterface CivitModel {\n id: number;\n url: string;\n name?: string;\n type?: string;\n tags?: string[];\n nsfw?: boolean;\n level?: number;\n availability?: string;\n downloads?: number;\n creator?: string;\n desc?: string;\n versions: CivitVersion[];\n}\n\n// eslint-disable-next-line no-extend-native\nString.prototype.format = function format(this: string, args: Record): string {\n let thisString = '';\n for (let charPos = 0; charPos < this.length; charPos++) thisString += this[charPos];\n for (const key in args) {\n const stringKey = `{${key}}`;\n thisString = thisString.replace(new RegExp(stringKey, 'g'), String(args[key]));\n }\n return thisString;\n};\n\nlet selectedURL: string[] = [];\nlet selectedName: string[] = [];\nlet selectedType: string[] = [];\nlet selectedBase: string[] = [];\nlet selectedModelId: number[] = [];\nlet selectedVersionId: number[] = [];\n\nexport function clearModelDetails() {\n const el = gradioApp().getElementById('model-details') || gradioApp().getElementById('civitai_models_output') || gradioApp().getElementById('models_outcome');\n if (!el) return;\n el.innerHTML = '';\n}\nwindow.clearModelDetails = clearModelDetails;\n\nconst modelDetailsHTML = `\n
\n \"model\n \n \n \n \n \n \n \n \n \n \n \n
Name{name}
Type{type}
Tags
{tags}
NSFW{nsfw} | {level}
Availability{availability}
Downloads{downloads}
Author{creator}
Description
{desc}
Download
All variants
\n
\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n {versions}\n \n
VersionTypeBaseFileUpdatedSizeAvailabilityDescription
\n
\n`;\n\nconst modelVersionsHTML = `\n \n {url}\n {name}\n {type}\n {base}\n {file}\n {mtime}\n {size}\n {availability}\n
{desc}
\n \n`;\n\nexport async function modelCardClick(id) {\n log('modelCardClick id', id);\n const el = gradioApp().getElementById('model-details') || gradioApp().getElementById('civitai_models_output') || gradioApp().getElementById('models_outcome');\n if (!el) return;\n const res = await authFetch(`${window.api}/civitai?model_id=${encodeURI(id)}`);\n if (!res || res.status !== 200) {\n error(`modelCardClick: id=${id} status=${res ? res.status : 'unknown'}`);\n return;\n }\n const dataArray = await res.json();\n log('modelCardClick data', dataArray);\n if (!dataArray || dataArray.length === 0) return;\n const data: any = dataArray[0]; // assuming the first item is the one we want\n\n const versionsHTML = data.versions.map((v: CivitVersion) => modelVersionsHTML.format({\n url: `
\\udb80\\uddda
`,\n name: v.name || 'unknown',\n type: v.files[0]?.type || 'unknown',\n base: v.base || 'unknown',\n mtime: (new Date(v.mtime)).toLocaleDateString(),\n availability: v.availability || 'unknown',\n size: v.files[0]?.size ? `${(v.files[0].size / 1024 / 1024).toFixed(2)} MB` : 'unknown',\n file: `${v.files[0]?.name || 'unknown'}`,\n desc: v.desc || 'no description available',\n })).join('');\n const url = `${data.name || 'unknown'}`;\n const creator = `${data.creator || 'unknown'}`;\n const images = data.versions.map((v: CivitVersion) => v.images).flat().map((i: CivitImage) => i.url); // TODO image gallery\n const modelHTML = modelDetailsHTML.format({\n name: url,\n type: data.type || 'unknown',\n tags: data.tags?.join(', ') || '',\n nsfw: data.nsfw ? 'yes' : 'no',\n level: data.level?.toString() || '',\n availability: data.availability || 'unknown',\n downloads: data.downloads?.toString() || '',\n creator,\n desc: data.desc || 'no description available',\n image: images.length > 0 ? images[0] : '/sdapi/v1/network/thumb?filename=ui/assets/missing.png',\n versions: versionsHTML || '',\n });\n el.innerHTML = modelHTML;\n}\nwindow.modelCardClick = modelCardClick;\n\nexport function startCivitDownload(url, name, type, base, modelId, versionId) {\n log('startCivitDownload', { url, name, type, base, modelId, versionId });\n selectedURL = [url];\n selectedName = [name];\n selectedType = [type];\n selectedBase = [base || ''];\n selectedModelId = [modelId || 0];\n selectedVersionId = [versionId || 0];\n const civitDownloadBtn = gradioApp().getElementById('civitai_download_btn');\n if (civitDownloadBtn) civitDownloadBtn.click();\n}\nwindow.startCivitDownload = startCivitDownload;\n\nexport function startCivitAllDownload(evt) {\n log('startCivitAllDownload', evt);\n const table = gradioApp().getElementById('model-versions-table');\n if (!table) return;\n const versions = table.querySelectorAll('tr');\n selectedURL = [];\n selectedName = [];\n selectedType = [];\n selectedBase = [];\n selectedModelId = [];\n selectedVersionId = [];\n for (const version of versions) {\n const parsed = version.querySelector('td:nth-child(1) div')?.getAttribute('onclick')?.match(/startCivitDownload\\('([^']+)', '([^']+)', '([^']+)', '([^']*)', (\\d+), (\\d+)\\)/);\n if (!parsed || parsed.length < 7) continue;\n selectedURL.push(parsed[1]);\n selectedName.push(parsed[2]);\n selectedType.push(parsed[3]);\n selectedBase.push(parsed[4]);\n selectedModelId.push(parseInt(parsed[5], 10));\n selectedVersionId.push(parseInt(parsed[6], 10));\n }\n const civitDownloadBtn = gradioApp().getElementById('civitai_download_btn');\n if (civitDownloadBtn) civitDownloadBtn.click();\n}\nwindow.startCivitAllDownload = startCivitAllDownload;\n\nexport function downloadCivitModel(modelUrl, modelName, modelType, modelBase, mId, vId, modelPath, civitToken, innerHTML) {\n log('downloadCivitModel', { modelUrl, modelName, modelType, modelBase, mId, vId, modelPath, civitToken });\n const el = gradioApp().getElementById('civitai_models_output') || gradioApp().getElementById('models_outcome');\n const currentHTML = el?.innerHTML || '';\n return [selectedURL, selectedName, selectedType, selectedBase, selectedModelId, selectedVersionId, modelPath, civitToken, currentHTML];\n}\nwindow.downloadCivitModel = downloadCivitModel;\n\nlet civitMutualExcludeBound = false;\n\nexport function civitaiMutualExclude() {\n if (civitMutualExcludeBound) return;\n const searchEl = gradioApp().querySelector('#civit_search_text textarea');\n const tagEl = gradioApp().querySelector('#civit_search_tag textarea');\n if (!searchEl || !tagEl) return;\n civitMutualExcludeBound = true;\n searchEl.addEventListener('input', () => {\n tagEl.closest('.gradio-textbox')?.classList.toggle('disabled-look', !!searchEl.value.trim());\n });\n tagEl.addEventListener('input', () => {\n searchEl.closest('.gradio-textbox')?.classList.toggle('disabled-look', !!tagEl.value.trim());\n });\n}\n\nonUiLoaded(civitaiMutualExclude);\n", "import { log } from './logger';\n\ntype GuiderLike = string | { label?: string };\n\nconst guiders: Record = {\n None: '',\n 'LSC: LayerSkipConfig': 'https://github.com/huggingface/diffusers/blob/041501aea92919c9c7f36e189fc9cf7d865ebb96/src/diffusers/hooks/layer_skip.py#L41',\n 'CFG: ClassifierFreeGuidance': 'https://huggingface.co/docs/diffusers/v0.35.1/en/api/modular_diffusers/guiders#diffusers.ClassifierFreeGuidance',\n 'Auto: AutoGuidance': 'https://huggingface.co/docs/diffusers/v0.35.1/en/api/modular_diffusers/guiders#diffusers.AutoGuidance',\n 'Zero: ClassifierFreeZeroStar': 'https://huggingface.co/docs/diffusers/v0.35.1/en/api/modular_diffusers/guiders#diffusers.ClassifierFreeZeroStarGuidance',\n 'PAG: PerturbedAttentionGuidance': 'https://huggingface.co/docs/diffusers/v0.35.1/en/api/modular_diffusers/guiders#diffusers.PerturbedAttentionGuidance',\n 'APG: AdaptiveProjectedGuidance': 'https://huggingface.co/docs/diffusers/v0.35.1/en/api/modular_diffusers/guiders#diffusers.AdaptiveProjectedGuidance',\n 'SLG: SkipLayerGuidance': 'https://huggingface.co/docs/diffusers/v0.35.1/en/api/modular_diffusers/guiders#diffusers.SkipLayerGuidance',\n 'SEG: SmoothedEnergyGuidance': 'https://huggingface.co/docs/diffusers/v0.35.1/en/api/modular_diffusers/guiders#diffusers.SmoothedEnergyGuidance',\n 'TCFG: TangentialClassifierFreeGuidance': 'https://huggingface.co/docs/diffusers/v0.35.1/en/api/modular_diffusers/guiders#diffusers.TangentialClassifierFreeGuidance',\n 'FDG: FrequencyDecoupledGuidance': 'https://huggingface.co/docs/diffusers/v0.35.1/en/api/modular_diffusers/guiders#diffusers.FrequencyDecoupledGuidance',\n};\n\nexport function getGuidanceDocs(guider: GuiderLike): void {\n const key = typeof guider === 'object' && guider?.label ? guider.label : guider;\n const url = guiders[key as string];\n log('getGuidanceDocs', guider, url);\n if (url) window.open(url, '_blank');\n}\n\nwindow.getGuidanceDocs = getGuidanceDocs;\n", "/* eslint max-classes-per-file: [\"error\", 2] */\n\ninterface TimesheetItem {\n start: number;\n end: number;\n label: string;\n type: string;\n}\n\nclass Bubble {\n type: string;\n label: string;\n min: number;\n start: number;\n end: number;\n scale: number;\n offset: number;\n width: number;\n duration: number;\n title: string;\n\n constructor(min: number, start: number, end: number, label: string, scale: number, type: string) {\n this.type = type;\n this.label = label;\n this.min = min;\n this.start = start;\n this.end = end;\n this.scale = scale;\n this.offset = Math.round(this.scale * (this.start - this.min));\n this.width = Math.round(this.scale * (this.end - this.start));\n this.duration = Math.round(1000 * (this.end - this.start)) / 1000;\n this.title = `Job: ${this.label}\\nDuration: ${this.duration}s\\nStart: ${new Date(1000 * this.start).toLocaleString()}\\nEnd: ${new Date(1000 * this.end).toLocaleString()}`;\n }\n\n getDateLabel(): number {\n return Math.round(1000 * (this.end - this.start)) / 1000;\n }\n}\n\nexport class Timesheet {\n min: number;\n max: number;\n data: TimesheetItem[];\n container: HTMLElement;\n scale: number;\n\n constructor(container: HTMLElement, data: TimesheetItem[]) {\n this.min = Math.floor(data[0].start);\n this.max = Math.round(data[data.length - 1].end + 0.5);\n this.data = data;\n this.container = container;\n const box = container.getBoundingClientRect();\n const width = box.width - 140;\n this.scale = width / (this.max - this.min);\n\n // draw sections\n let html: string[] = [];\n for (let c = 0; c <= this.max - this.min; c++) html.push(`
`);\n container.className = 'timesheet color-scheme-default';\n container.innerHTML = `
${html.join('')}
`;\n\n // insert data\n html = [];\n for (let n = 0, m = this.data.length; n < m; n++) {\n const cur = this.data[n];\n const bubble = new Bubble(this.min, cur.start, cur.end, cur.label, this.scale, cur.type);\n const line = [\n ``,\n `${bubble.duration} `,\n `${bubble.label}`,\n ].join('');\n html.push(`
  • ${line}
  • `);\n }\n this.container.innerHTML += `
      ${html.join('')}
    `;\n }\n}\n", "import { Timesheet } from './timesheet';\nimport { log } from './logger';\nimport { authFetch } from './authWrap';\n\ninterface HistoryEntry {\n timestamp: number;\n id: string;\n job: string;\n op: string;\n duration?: number;\n outputs: string[];\n type?: 'inference' | 'io' | 'default';\n}\n\ninterface TimelineEntry {\n start: number;\n end: number;\n label: string;\n type: 'inference' | 'io' | 'default';\n}\n\nconst inferenceTypes = ['inference', 'vae', 'te'];\nconst ioTypes = ['load', 'save'];\n\nexport async function refreshHistory() {\n log('refreshHistory');\n authFetch(`${window.api}/history`, { priority: 'low' }).then((res) => {\n if (!res) return;\n const timeline = document.getElementById('history_timeline');\n const table = document.getElementById('history_table');\n if (!timeline || !table) return;\n timeline.innerHTML = '';\n res.json().then((rawData) => {\n let data = rawData as HistoryEntry[];\n if (!data || !data.length) {\n table.innerHTML = '

    No history data available.

    ';\n return;\n }\n\n // build table\n let html = '';\n for (const entry of data) {\n const ts = new Date(1000 * entry.timestamp).toLocaleString();\n const duration = entry.duration ? (entry.duration).toFixed(3) : '';\n const outputs = entry.outputs.join(', ');\n html += ``;\n }\n html += '
    TimeIDJobActionDurationOutputs
    ${ts}${entry.id}${entry.job}${entry.op}${duration}${outputs}
    ';\n table.innerHTML = html;\n\n // crop data to last processing session\n let startIdx = -1;\n for (let i = data.length - 1; i >= 0; --i) {\n const e = data[i];\n if ((e.job === 'control' || e.job === 'text' || e.job === 'control' || e.job === 'image') && (e.op === 'begin')) {\n startIdx = i;\n break;\n }\n }\n if (startIdx >= 0) data = data.slice(startIdx);\n\n // build timeline\n const ts: TimelineEntry[] = [];\n for (const entry of data) {\n if (entry.op === 'begin') {\n const start = entry.timestamp;\n const endEntry = data.find((e) => (e.id === entry.id && e.op === 'end'));\n const end = endEntry?.timestamp ?? data[data.length - 1].timestamp;\n if (end - start < 0.02) continue; // skip very short entries\n if (inferenceTypes.some((type) => entry.job.toLowerCase().startsWith(type))) entry.type = 'inference';\n else if (ioTypes.some((type) => entry.job.toLowerCase().startsWith(type))) entry.type = 'io';\n else entry.type = 'default';\n if (start && end) ts.push({ start, end, label: entry.job, type: entry.type });\n }\n }\n if (!ts.length) return;\n // eslint-disable-next-line no-new\n new Timesheet(timeline, ts);\n });\n });\n}\n\nwindow.refreshHistory = refreshHistory;\n", "import { Timesheet } from './timesheet';\nimport { log } from './logger';\nimport { authFetch } from './authWrap';\n\nconst types = ['Images', 'Videos', 'Models', 'Data', 'Cache', 'Code', 'Other'];\n\ninterface LocationEntry {\n name: string;\n type: 'Images' | 'Videos' | 'Models' | 'Data' | 'Cache' | 'Code' | 'Other';\n folders: string[];\n paths: string[];\n size: number;\n mtime: number;\n nfiles: number;\n nfolders: number;\n nsymlinks: number;\n nerrors: number;\n time: number;\n}\n\ninterface TimelineEntry {\n start: number;\n end: number;\n label: string;\n type: 'inference' | 'io' | 'default';\n}\n\nfunction buildTable(type: string, data: LocationEntry[]) {\n // let html = `

    ${type}

    `;\n const totalSize = data.reduce((acc, entry) => acc + entry.size, 0);\n const totalLoc = data.length;\n const totalFiles = data.reduce((acc, entry) => acc + entry.nfiles, 0);\n const totalFolders = data.reduce((acc, entry) => acc + entry.nfolders, 0);\n let title = `Locations: ${totalLoc}\\nTotal Size: ${(totalSize / (1024 * 1024)).toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })} MB\\nTotal Files: ${totalFiles}\\nTotal Folders: ${totalFolders}\\n`;\n let html = `

    ${type}

    LocationSizeMTime
    `;\n for (const entry of data) {\n if (entry.size === 0) continue;\n const size = (entry.size / (1024 * 1024)).toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 }) + ' MB';\n const mtime = entry.mtime > 0 ? new Date(entry.mtime * 1000).toLocaleString() : '';\n title = `Type: ${entry.type}\\nName: ${entry.name}\\nSize: ${size}\\nLast modified: ${mtime}\\n`;\n title += `Folders: ${entry.folders.join(', ')}\\nResolved paths: ${entry.paths.join(', ')}\\n`;\n title += `Subfolders: ${entry.nfolders}\\nFiles: ${entry.nfiles}\\nSymlinks: ${entry.nsymlinks}\\nErrors: ${entry.nerrors}\\n`;\n title += `Time to scan: ${entry.time.toFixed(3)} seconds`;\n const perc = Math.round((entry.size / totalSize) * 100);\n const color = `rgb(${perc}, 50, 80)`;\n const css = `background: linear-gradient(to right, ${color} ${perc}%, transparent ${perc}%);`;\n html += ``;\n }\n html += '
    ${entry.name}${size}${mtime}
    ';\n return html;\n}\n\nexport async function refreshStorage(storageTypes: string[]) {\n log('refreshStorage', storageTypes);\n authFetch(`${window.api}/storage?types=${storageTypes.join(',')}`, { priority: 'low' }).then((res) => {\n if (!res) return;\n const timeline = document.getElementById('storage_timeline');\n const table = document.getElementById('storage_table');\n if (!timeline || !table) return;\n timeline.innerHTML = '';\n res.json().then((rawData) => {\n const data = rawData as LocationEntry[];\n if (!data || !data.length) {\n table.innerHTML = '

    No storage data available.

    ';\n return;\n }\n table.innerHTML = '';\n if (storageTypes.includes('All')) storageTypes = types;\n for (const type of storageTypes) {\n const typeData = data.filter((entry) => entry.type === type);\n if (typeData.length > 0) table.innerHTML += buildTable(type, typeData);\n }\n\n /*\n // build timeline\n const ts: TimelineEntry[] = [];\n for (const entry of data) {\n if (entry.op === 'begin') {\n const start = entry.timestamp;\n const endEntry = data.find((e) => (e.id === entry.id && e.op === 'end'));\n const end = endEntry?.timestamp ?? data[data.length - 1].timestamp;\n if (end - start < 0.02) continue; // skip very short entries\n if (inferenceTypes.some((type) => entry.job.toLowerCase().startsWith(type))) entry.type = 'inference';\n else if (ioTypes.some((type) => entry.job.toLowerCase().startsWith(type))) entry.type = 'io';\n else entry.type = 'default';\n if (start && end) ts.push({ start, end, label: entry.job, type: entry.type });\n }\n }\n if (!ts.length) return;\n // eslint-disable-next-line no-new\n new Timesheet(timeline, ts);\n */\n });\n });\n}\n\nwindow.refreshStorage = refreshStorage;\n", "import { gradioApp, onAfterUiUpdate } from './script';\nimport { get_tab_index } from './ui';\n\nlet currentWidth: number | null = null;\nlet currentHeight: number | null = null;\nlet arFrameTimeout: ReturnType | undefined;\n\nfunction dimensionChange(e: Event, isWidth: boolean, isHeight: boolean): void {\n const { target } = e;\n if (!(target instanceof HTMLInputElement)) return;\n if (isWidth) currentWidth = Number(target.value);\n if (isHeight) currentHeight = Number(target.value);\n const tabImg2img = gradioApp().querySelector('#tab_img2img');\n if (!(tabImg2img instanceof HTMLElement)) return;\n const inImg2img = tabImg2img.style.display === 'block';\n if (!inImg2img) return;\n let targetElement: HTMLImageElement | null = null;\n const tabIndex = get_tab_index('mode_img2img');\n if (tabIndex === 0) targetElement = gradioApp().querySelector('#img2img_image div[data-testid=image] img'); // img2img\n else if (tabIndex === 1) targetElement = gradioApp().querySelector('#img2img_sketch div[data-testid=image] img'); // Sketch\n else if (tabIndex === 2) targetElement = gradioApp().querySelector('#img2maskimg div[data-testid=image] img'); // Inpaint\n else if (tabIndex === 3) targetElement = gradioApp().querySelector('#composite div[data-testid=image] img'); // Inpaint sketch\n\n if (targetElement && currentWidth && currentHeight) {\n let arPreviewRect = gradioApp().querySelector('#imageARPreview');\n if (!arPreviewRect) {\n arPreviewRect = document.createElement('div');\n arPreviewRect.id = 'imageARPreview';\n gradioApp().appendChild(arPreviewRect);\n }\n\n const viewportOffset = targetElement.getBoundingClientRect();\n const viewportscale = Math.min(targetElement.clientWidth / targetElement.naturalWidth, targetElement.clientHeight / targetElement.naturalHeight);\n const scaledx = targetElement.naturalWidth * viewportscale;\n const scaledy = targetElement.naturalHeight * viewportscale;\n const cleintRectTop = (viewportOffset.top + window.scrollY);\n const cleintRectLeft = (viewportOffset.left + window.scrollX);\n const cleintRectCentreY = cleintRectTop + (targetElement.clientHeight / 2);\n const cleintRectCentreX = cleintRectLeft + (targetElement.clientWidth / 2);\n const arscale = Math.min(scaledx / currentWidth, scaledy / currentHeight);\n const arscaledx = currentWidth * arscale;\n const arscaledy = currentHeight * arscale;\n const arRectTop = cleintRectCentreY - (arscaledy / 2);\n const arRectLeft = cleintRectCentreX - (arscaledx / 2);\n const arRectWidth = arscaledx;\n const arRectHeight = arscaledy;\n arPreviewRect.style.top = `${arRectTop}px`;\n arPreviewRect.style.left = `${arRectLeft}px`;\n arPreviewRect.style.width = `${arRectWidth}px`;\n arPreviewRect.style.height = `${arRectHeight}px`;\n\n if (arFrameTimeout) clearTimeout(arFrameTimeout);\n arFrameTimeout = setTimeout(() => { arPreviewRect.style.display = 'none'; }, 2000);\n arPreviewRect.style.display = 'block';\n }\n}\n\nexport function aspectRatioCallback(): void {\n const arPreviewRect = gradioApp().querySelector('#imageARPreview');\n if (arPreviewRect instanceof HTMLElement) arPreviewRect.style.display = 'none';\n const tabImg2img = gradioApp().querySelector('#tab_img2img');\n if (tabImg2img instanceof HTMLElement) {\n const inImg2img = tabImg2img.style.display === 'block';\n if (inImg2img) {\n const inputs = gradioApp().querySelectorAll('input');\n inputs.forEach((e) => {\n if (!(e instanceof HTMLInputElement) || !(e.parentElement instanceof HTMLElement)) return;\n const isWidth = e.parentElement.id === 'img2img_width';\n const isHeight = e.parentElement.id === 'img2img_height';\n if ((isWidth || isHeight) && !e.classList.contains('scrollwatch')) {\n e.addEventListener('input', (evt) => { dimensionChange(evt, isWidth, isHeight); });\n e.classList.add('scrollwatch');\n }\n if (isWidth) currentWidth = Number(e.value);\n if (isHeight) currentHeight = Number(e.value);\n });\n }\n }\n}\n\nonAfterUiUpdate(aspectRatioCallback);\n", "import { gradioApp, onAfterUiUpdate } from './script';\n\n// Aspect-ratio lock for the paired width/height sliders. The math runs client-side and debounced,\n// and only the partner axis is ever written, never the field being edited; writing the edited field\n// back is what yanked the value mid-type when this went through a gradio round-trip. Programmatic\n// updates dispatch a synthetic input event so gradio's store stays in sync. State is keyed per\n// dropdown element so duplicate elem ids across tabs stay isolated.\n\nconst RES_DEBOUNCE = 350;\nconst AR_DEBOUNCE = 120;\nconst timers = new WeakMap>();\nconst busy = new WeakSet();\n\nfunction parseAR(ar: string): [number, number] | null {\n if (!ar || ar === 'AR') return null;\n const parts = ar.split(':');\n if (parts.length !== 2) return null;\n const w = parseInt(parts[0], 10);\n const h = parseInt(parts[1], 10);\n return (w > 0 && h > 0) ? [w, h] : null;\n}\n\nfunction numberInput(group: Element): HTMLInputElement | null {\n const inp = group.querySelector('input[type=number]') || group.querySelector('input');\n return inp instanceof HTMLInputElement ? inp : null;\n}\n\nfunction readValue(group: Element): number {\n const inp = numberInput(group);\n return inp ? Number(inp.value) : 0;\n}\n\nfunction writeValue(group: Element, raw: number): void {\n const inp = numberInput(group);\n if (!inp) return;\n const step = Number(inp.step) || 8;\n const min = inp.min !== '' ? Number(inp.min) : 0;\n const max = inp.max !== '' ? Number(inp.max) : 8192;\n const value = Math.max(min, Math.min(max, Math.round(raw / step) * step));\n if (value === Number(inp.value)) return; // unchanged: skip so the listeners do not refire\n group.querySelectorAll('input').forEach((el) => {\n if (!(el instanceof HTMLInputElement)) return;\n el.value = String(value);\n const e = new Event('input', { bubbles: true });\n Object.defineProperty(e, 'target', { value: el });\n el.dispatchEvent(e);\n });\n}\n\nfunction arValue(arEl: Element): string {\n const inp = arEl.querySelector('input');\n return inp instanceof HTMLInputElement ? inp.value : 'AR';\n}\n\nfunction pairOf(arEl: Element): { width: Element; height: Element } | null {\n let container: Element | null = arEl.parentElement;\n for (let i = 0; i < 6 && container; i++) {\n const width = container.querySelector('[id$=\"_width\"]');\n const height = container.querySelector('[id$=\"_height\"]');\n if (width && height) return { width, height };\n container = container.parentElement;\n }\n return null;\n}\n\nfunction getNearestAspectRatio(width: number, height: number, maxPixelTolerance = 8): string | null {\n const STANDARD_RATIOS = [\n { label: '1:1', ratio: 1 / 1 },\n { label: '4:3', ratio: 4 / 3 },\n { label: '3:2', ratio: 3 / 2 },\n { label: '16:9', ratio: 16 / 9 },\n { label: '16:10', ratio: 16 / 10 },\n { label: '21:9', ratio: 64 / 27 }, // standard cinematic 21:9 ratio is actually 64/27\n { label: '2:3', ratio: 2 / 3 },\n { label: '3:4', ratio: 3 / 4 },\n { label: '9:16', ratio: 9 / 16 },\n { label: '10:16', ratio: 10 / 16 },\n { label: '9:21', ratio: 27 / 64 },\n ];\n const targetRatio = width / height;\n const closest = STANDARD_RATIOS.reduce((prev, curr) => (Math.abs(curr.ratio - targetRatio) < Math.abs(prev.ratio - targetRatio) ? curr : prev));\n const expectedWidth = height * closest.ratio;\n const expectedHeight = width / closest.ratio;\n const widthDiff = Math.abs(width - expectedWidth);\n const heightDiff = Math.abs(height - expectedHeight);\n if (widthDiff <= maxPixelTolerance || heightDiff <= maxPixelTolerance) return closest.label;\n const ratio = (width / height).toFixed(2);\n return `${ratio}:1`;\n}\n\nfunction settle(arEl: Element, source: 'width' | 'height'): void {\n const ar = parseAR(arValue(arEl));\n const pair = pairOf(arEl);\n if (!pair) return;\n if (ar) { // ar is set\n const [rw, rh] = ar;\n busy.add(arEl);\n if (source === 'height') writeValue(pair.width, (readValue(pair.height) * rw) / rh);\n else writeValue(pair.height, (readValue(pair.width) * rh) / rw);\n }\n const span = arEl.querySelector('span');\n if (span) span.innerText = getNearestAspectRatio(readValue(pair.width), readValue(pair.height));\n busy.delete(arEl);\n}\n\nfunction schedule(arEl: Element, source: 'width' | 'height', delay: number): void {\n if (busy.has(arEl)) return; // ignore the input events our own writes dispatch\n clearTimeout(timers.get(arEl));\n timers.set(arEl, setTimeout(() => settle(arEl, source), delay));\n}\n\nfunction flush(arEl: Element, source: 'width' | 'height'): void {\n if (busy.has(arEl)) return;\n clearTimeout(timers.get(arEl));\n settle(arEl, source);\n}\n\nfunction bind(arEl: Element, group: Element, source: 'width' | 'height'): void {\n group.querySelectorAll('input').forEach((el) => {\n if (!(el instanceof HTMLInputElement) || el.classList.contains('ar-lock-bound')) return;\n el.classList.add('ar-lock-bound');\n el.addEventListener('input', () => schedule(arEl, source, RES_DEBOUNCE));\n el.addEventListener('change', () => flush(arEl, source)); // commit on blur, enter, or slider release\n });\n}\n\nexport function setupResolutionLock(): void {\n gradioApp().querySelectorAll('.ar-dropdown').forEach((arEl) => {\n const pair = pairOf(arEl);\n if (!pair) return;\n bind(arEl, pair.width, 'width');\n bind(arEl, pair.height, 'height');\n arEl.querySelectorAll('span').forEach((el) => {\n if (el) el.innerText = '';\n });\n arEl.querySelectorAll('input').forEach((el) => {\n if (!(el instanceof HTMLInputElement) || el.classList.contains('ar-lock-bound')) return;\n el.classList.add('ar-lock-bound');\n el.addEventListener('change', () => flush(arEl, 'width')); // new ratio: keep width, derive height\n el.addEventListener('input', () => schedule(arEl, 'width', AR_DEBOUNCE));\n });\n });\n}\n\nonAfterUiUpdate(setupResolutionLock);\n", "import { updateInput } from './ui';\n\nexport function keyupEditAttention(event: KeyboardEvent): void {\n const target = (event as any).originalTarget || event.composedPath()[0];\n if (!(target instanceof HTMLTextAreaElement)) return;\n if (!target.matches(\"*:is([id*='_toprow'] [id*='_prompt'], .prompt) textarea\")) return;\n if (!(event.metaKey || event.ctrlKey)) return;\n const isPlus = event.key === 'ArrowUp';\n const isMinus = event.key === 'ArrowDown';\n if (!isPlus && !isMinus) return;\n let { selectionStart } = target;\n let { selectionEnd } = target;\n let text = target.value;\n\n function selectCurrentParenthesisBlock(OPEN: string, CLOSE: string): boolean {\n if (selectionStart !== selectionEnd) return false;\n\n // Find opening parenthesis around current cursor\n const before = text.substring(0, selectionStart);\n let beforeParen = before.lastIndexOf(OPEN);\n if (beforeParen === -1) return false;\n let beforeParenClose = before.lastIndexOf(CLOSE);\n while (beforeParenClose !== -1 && beforeParenClose > beforeParen) {\n beforeParen = before.lastIndexOf(OPEN, beforeParen - 1);\n beforeParenClose = before.lastIndexOf(CLOSE, beforeParenClose - 1);\n }\n\n // Find closing parenthesis around current cursor\n const after = text.substring(selectionStart);\n let afterParen = after.indexOf(CLOSE);\n if (afterParen === -1) return false;\n let afterParenOpen = after.indexOf(OPEN);\n while (afterParenOpen !== -1 && afterParen > afterParenOpen) {\n afterParen = after.indexOf(CLOSE, afterParen + 1);\n afterParenOpen = after.indexOf(OPEN, afterParenOpen + 1);\n }\n if (beforeParen === -1 || afterParen === -1) return false;\n\n // Set the selection to the text between the parenthesis\n const parenContent = text.substring(beforeParen + 1, selectionStart + afterParen);\n const lastColon = parenContent.lastIndexOf(':');\n selectionStart = beforeParen + 1;\n selectionEnd = selectionStart + lastColon;\n target.setSelectionRange(selectionStart, selectionEnd);\n return true;\n }\n\n function selectCurrentWord(): boolean {\n if (selectionStart !== selectionEnd) return false;\n const delimiters = `${window.opts.keyedit_delimiters} \\r\\n\\t`;\n // seek backward until to find beginning\n while (!delimiters.includes(text[selectionStart - 1]) && selectionStart > 0) selectionStart--;\n // seek forward to find end\n while (!delimiters.includes(text[selectionEnd]) && selectionEnd < text.length) selectionEnd++;\n target.setSelectionRange(selectionStart, selectionEnd);\n return true;\n }\n\n // If the user hasn't selected anything, let's select their current parenthesis block or word\n if (!selectCurrentParenthesisBlock('<', '>') && !selectCurrentParenthesisBlock('(', ')')) selectCurrentWord();\n event.preventDefault();\n\n let closeCharacter = ')';\n let delta = window.opts.keyedit_precision_attention;\n\n if (selectionStart > 0 && text[selectionStart - 1] === '<') {\n closeCharacter = '>';\n delta = window.opts.keyedit_precision_extra;\n } else if (selectionStart === 0 || text[selectionStart - 1] !== '(') {\n while (selectionEnd > selectionStart && text[selectionEnd - 1] === ' ') selectionEnd -= 1;\n if (selectionStart === selectionEnd) return;\n text = `${text.slice(0, selectionStart)}(${text.slice(selectionStart, selectionEnd)}:1.0)${text.slice(selectionEnd)}`;\n selectionStart += 1;\n selectionEnd += 1;\n }\n const end = text.slice(selectionEnd + 1).indexOf(closeCharacter) + 1;\n let weight: any = parseFloat(text.slice(selectionEnd + 1, selectionEnd + 1 + end));\n if (Number.isNaN(weight)) return;\n weight += isPlus ? delta : -delta;\n weight = parseFloat(weight.toPrecision(12));\n if (String(weight).length === 1) weight += '.0';\n if (closeCharacter === ')' && weight === 1) {\n text = text.slice(0, selectionStart - 1) + text.slice(selectionStart, selectionEnd) + text.slice(selectionEnd + 5);\n selectionStart--;\n selectionEnd--;\n } else {\n text = text.slice(0, selectionEnd + 1) + weight + text.slice(selectionEnd + 1 + end - 1);\n }\n target.focus();\n target.value = text;\n target.selectionStart = selectionStart;\n target.selectionEnd = selectionEnd;\n updateInput(target);\n}\n\naddEventListener('keydown', (event) => keyupEditAttention(event));\n", "/**\n*\n* jquery.sparkline.js\n*\n* v2.4.1\n* (c) Splunk, Inc\n* Contact: Gareth Watts (gareth@splunk.com)\n* http://omnipotent.net/jquery.sparkline/\n*\n* Generates inline sparkline charts from data supplied either to the method\n* or inline in HTML\n*\n* Compatible with Internet Explorer 6.0+ and modern browsers equipped with the canvas tag\n* (Firefox 2.0+, Safari, Opera, etc)\n*\n* License: New BSD License\n*\n* Copyright (c) 2012, Splunk Inc.\n* All rights reserved.\n*\n* Redistribution and use in source and binary forms, with or without modification,\n* are permitted provided that the following conditions are met:\n*\n* * Redistributions of source code must retain the above copyright notice,\n* this list of conditions and the following disclaimer.\n* * Redistributions in binary form must reproduce the above copyright notice,\n* this list of conditions and the following disclaimer in the documentation\n* and/or other materials provided with the distribution.\n* * Neither the name of Splunk Inc nor the names of its contributors may\n* be used to endorse or promote products derived from this software without\n* specific prior written permission.\n*\n* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY\n* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\n* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\n* SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\n* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\n* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*\n*\n* Usage:\n* $(selector).sparkline(values, options)\n*\n* If values is undefined or set to 'html' then the data values are read from the specified tag:\n*

    Sparkline: 1,4,6,6,8,5,3,5

    \n* $('.sparkline').sparkline();\n* There must be no spaces in the enclosed data set\n*\n* Otherwise values must be an array of numbers or null values\n*

    Sparkline: This text replaced if the browser is compatible

    \n* $('#sparkline1').sparkline([1,4,6,6,8,5,3,5])\n* $('#sparkline2').sparkline([1,4,6,null,null,5,3,5])\n*\n* Values can also be specified in an HTML comment, or as a values attribute:\n*

    Sparkline:

    \n*

    Sparkline:

    \n* $('.sparkline').sparkline();\n*\n* For line charts, x values can also be specified:\n*

    Sparkline: 1:1,2.7:4,3.4:6,5:6,6:8,8.7:5,9:3,10:5

    \n* $('#sparkline1').sparkline([ [1,1], [2.7,4], [3.4,6], [5,6], [6,8], [8.7,5], [9,3], [10,5] ])\n*\n* By default, options should be passed in as the second argument to the sparkline function:\n* $('.sparkline').sparkline([1,2,3,4], {type: 'bar'})\n*\n* Options can also be set by passing them on the tag itself. This feature is disabled by default though\n* as there's a slight performance overhead:\n* $('.sparkline').sparkline([1,2,3,4], {enableTagOptions: true})\n*

    Sparkline: loading

    \n* Prefix all options supplied as tag attribute with \"spark\" (configurable by setting tagOptionsPrefix)\n*\n* Supported options:\n* lineColor - Color of the line used for the chart\n* fillColor - Color used to fill in the chart - Set to '' or false for a transparent chart\n* width - Width of the chart - Defaults to 3 times the number of values in pixels\n* height - Height of the chart - Defaults to the height of the containing element\n* chartRangeMin - Specify the minimum value to use for the Y range of the chart - Defaults to the minimum value supplied\n* chartRangeMax - Specify the maximum value to use for the Y range of the chart - Defaults to the maximum value supplied\n* chartRangeClip - Clip out of range values to the max/min specified by chartRangeMin and chartRangeMax\n* chartRangeMinX - Specify the minimum value to use for the X range of the chart - Defaults to the minimum value supplied\n* chartRangeMaxX - Specify the maximum value to use for the X range of the chart - Defaults to the maximum value supplied\n* composite - If true then don't erase any existing chart attached to the tag, but draw\n* another chart over the top - Note that width and height are ignored if an\n* existing chart is detected.\n* tagValuesAttribute - Name of tag attribute to check for data values - Defaults to 'values'\n* enableTagOptions - Whether to check tags for sparkline options\n* tagOptionsPrefix - Prefix used for options supplied as tag attributes - Defaults to 'spark'\n* disableHiddenCheck - If set to true, then the plugin will assume that charts will never be drawn into a\n* hidden dom element, avoding a browser reflow\n* disableInteraction - If set to true then all mouseover/click interaction behaviour will be disabled,\n* making the plugin perform much like it did in 1.x\n* disableTooltips - If set to true then tooltips will be disabled - Defaults to false (tooltips enabled)\n* disableHighlight - If set to true then highlighting of selected chart elements on mouseover will be disabled\n* defaults to false (highlights enabled)\n* highlightLighten - Factor to lighten/darken highlighted chart values by - Defaults to 1.4 for a 40% increase\n* tooltipContainer - Specify which DOM element the tooltip should be rendered into - defaults to document.body\n* tooltipClassname - Optional CSS classname to apply to tooltips - If not specified then a default style will be applied\n* tooltipOffsetX - How many pixels away from the mouse pointer to render the tooltip on the X axis\n* tooltipOffsetY - How many pixels away from the mouse pointer to render the tooltip on the r axis\n* tooltipFormatter - Optional callback that allows you to override the HTML displayed in the tooltip\n* callback is given arguments of (sparkline, options, fields)\n* tooltipChartTitle - If specified then the tooltip uses the string specified by this setting as a title\n* tooltipFormat - A format string or SPFormat object (or an array thereof for multiple entries)\n* to control the format of the tooltip\n* tooltipPrefix - A string to prepend to each field displayed in a tooltip\n* tooltipSuffix - A string to append to each field displayed in a tooltip\n* tooltipSkipNull - If true then null values will not have a tooltip displayed (defaults to true)\n* tooltipValueLookups - An object or range map to map field values to tooltip strings\n* (eg. to map -1 to \"Lost\", 0 to \"Draw\", and 1 to \"Win\")\n* numberFormatter - Optional callback for formatting numbers in tooltips\n* numberDigitGroupSep - Character to use for group separator in numbers \"1,234\" - Defaults to \",\"\n* numberDecimalMark - Character to use for the decimal point when formatting numbers - Defaults to \".\"\n* numberDigitGroupCount - Number of digits between group separator - Defaults to 3\n*\n* There are 7 types of sparkline, selected by supplying a \"type\" option of 'line' (default),\n* 'bar', 'tristate', 'bullet', 'discrete', 'pie' or 'box'\n* line - Line chart. Options:\n* spotColor - Set to '' to not end each line in a circular spot\n* minSpotColor - If set, color of spot at minimum value\n* maxSpotColor - If set, color of spot at maximum value\n* spotRadius - Radius in pixels\n* lineWidth - Width of line in pixels\n* normalRangeMin\n* normalRangeMax - If set draws a filled horizontal bar between these two values marking the \"normal\"\n* or expected range of values\n* normalRangeColor - Color to use for the above bar\n* drawNormalOnTop - Draw the normal range above the chart fill color if true\n* defaultPixelsPerValue - Defaults to 3 pixels of width for each value in the chart\n* highlightSpotColor - The color to use for drawing a highlight spot on mouseover - Set to null to disable\n* highlightLineColor - The color to use for drawing a highlight line on mouseover - Set to null to disable\n* valueSpots - Specify which points to draw spots on, and in which color. Accepts a range map\n*\n* bar - Bar chart. Options:\n* barColor - Color of bars for postive values\n* negBarColor - Color of bars for negative values\n* zeroColor - Color of bars with zero values\n* nullColor - Color of bars with null values - Defaults to omitting the bar entirely\n* barWidth - Width of bars in pixels\n* colorMap - Optional mappnig of values to colors to override the *BarColor values above\n* can be an Array of values to control the color of individual bars or a range map\n* to specify colors for individual ranges of values\n* barSpacing - Gap between bars in pixels\n* zeroAxis - Centers the y-axis around zero if true\n*\n* tristate - Charts values of win (>0), lose (<0) or draw (=0)\n* posBarColor - Color of win values\n* negBarColor - Color of lose values\n* zeroBarColor - Color of draw values\n* barWidth - Width of bars in pixels\n* barSpacing - Gap between bars in pixels\n* colorMap - Optional mappnig of values to colors to override the *BarColor values above\n* can be an Array of values to control the color of individual bars or a range map\n* to specify colors for individual ranges of values\n*\n* discrete - Options:\n* lineHeight - Height of each line in pixels - Defaults to 30% of the graph height\n* thesholdValue - Values less than this value will be drawn using thresholdColor instead of lineColor\n* thresholdColor\n*\n* bullet - Values for bullet graphs msut be in the order: target, performance, range1, range2, range3, ...\n* options:\n* targetColor - The color of the vertical target marker\n* targetWidth - The width of the target marker in pixels\n* performanceColor - The color of the performance measure horizontal bar\n* rangeColors - Colors to use for each qualitative range background color\n*\n* pie - Pie chart. Options:\n* sliceColors - An array of colors to use for pie slices\n* offset - Angle in degrees to offset the first slice - Try -90 or +90\n* borderWidth - Width of border to draw around the pie chart, in pixels - Defaults to 0 (no border)\n* borderColor - Color to use for the pie chart border - Defaults to #000\n*\n* box - Box plot. Options:\n* raw - Set to true to supply pre-computed plot points as values\n* values should be: low_outlier, low_whisker, q1, median, q3, high_whisker, high_outlier\n* When set to false you can supply any number of values and the box plot will\n* be computed for you. Default is false.\n* showOutliers - Set to true (default) to display outliers as circles\n* outlierIQR - Interquartile range used to determine outliers. Default 1.5\n* boxLineColor - Outline color of the box\n* boxFillColor - Fill color for the box\n* whiskerColor - Line color used for whiskers\n* outlierLineColor - Outline color of outlier circles\n* outlierFillColor - Fill color of the outlier circles\n* spotRadius - Radius of outlier circles\n* medianColor - Line color of the median line\n* target - Draw a target cross hair at the supplied value (default undefined)\n*\n*\n*\n* Examples:\n* $('#sparkline1').sparkline(myvalues, { lineColor: '#f00', fillColor: false });\n* $('.barsparks').sparkline('html', { type:'bar', height:'40px', barWidth:5 });\n* $('#tristate').sparkline([1,1,-1,1,0,0,-1], { type:'tristate' }):\n* $('#discrete').sparkline([1,3,4,5,5,3,4,5], { type:'discrete' });\n* $('#bullet').sparkline([10,12,12,9,7], { type:'bullet' });\n* $('#pie').sparkline([1,1,2], { type:'pie' });\n*/\n\n/*jslint regexp: true, browser: true, jquery: true, white: true, nomen: false, plusplus: false, maxerr: 500, indent: 4 */\n\n(function(document, Math, undefined) { // performance/minified-size optimization\n(function(factory) {\n if(typeof define === 'function' && define.amd) {\n define(['jquery'], factory);\n } else if (jQuery && !jQuery.fn.sparkline) {\n factory(jQuery);\n }\n}\n(function($) {\n 'use strict';\n\n var UNSET_OPTION = {},\n getDefaults, createClass, SPFormat, clipval, quartile, normalizeValue, normalizeValues,\n remove, isNumber, all, sum, addCSS, ensureArray, formatNumber, RangeMap,\n MouseHandler, Tooltip, barHighlightMixin,\n line, bar, tristate, discrete, bullet, pie, box, defaultStyles, initStyles,\n VShape, VCanvas_base, VCanvas_canvas, VCanvas_vml, pending, shapeCount = 0;\n\n /**\n * Default configuration settings\n */\n getDefaults = function () {\n return {\n // Settings common to most/all chart types\n common: {\n type: 'line',\n lineColor: '#00f',\n fillColor: '#cdf',\n defaultPixelsPerValue: 3,\n width: 'auto',\n height: 'auto',\n composite: false,\n tagValuesAttribute: 'values',\n tagOptionsPrefix: 'spark',\n enableTagOptions: false,\n enableHighlight: true,\n highlightLighten: 1.4,\n tooltipSkipNull: true,\n tooltipPrefix: '',\n tooltipSuffix: '',\n disableHiddenCheck: false,\n numberFormatter: false,\n numberDigitGroupCount: 3,\n numberDigitGroupSep: ',',\n numberDecimalMark: '.',\n disableTooltips: false,\n disableInteraction: false\n },\n // Defaults for line charts\n line: {\n spotColor: '#f80',\n highlightSpotColor: '#5f5',\n highlightLineColor: '#f22',\n spotRadius: 1.5,\n minSpotColor: '#f80',\n maxSpotColor: '#f80',\n lineWidth: 1,\n normalRangeMin: undefined,\n normalRangeMax: undefined,\n normalRangeColor: '#ccc',\n drawNormalOnTop: false,\n chartRangeMin: undefined,\n chartRangeMax: undefined,\n chartRangeMinX: undefined,\n chartRangeMaxX: undefined,\n tooltipFormat: new SPFormat(' {{prefix}}{{y}}{{suffix}}')\n },\n // Defaults for bar charts\n bar: {\n barColor: '#3366cc',\n negBarColor: '#f44',\n stackedBarColor: ['#3366cc', '#dc3912', '#ff9900', '#109618', '#66aa00',\n '#dd4477', '#0099c6', '#990099'],\n zeroColor: undefined,\n nullColor: undefined,\n zeroAxis: true,\n barWidth: 4,\n barSpacing: 1,\n chartRangeMax: undefined,\n chartRangeMin: undefined,\n chartRangeClip: false,\n colorMap: undefined,\n tooltipFormat: new SPFormat(' {{prefix}}{{value}}{{suffix}}')\n },\n // Defaults for tristate charts\n tristate: {\n barWidth: 4,\n barSpacing: 1,\n posBarColor: '#6f6',\n negBarColor: '#f44',\n zeroBarColor: '#999',\n colorMap: {},\n tooltipFormat: new SPFormat(' {{value:map}}'),\n tooltipValueLookups: { map: { '-1': 'Loss', '0': 'Draw', '1': 'Win' } }\n },\n // Defaults for discrete charts\n discrete: {\n lineHeight: 'auto',\n thresholdColor: undefined,\n thresholdValue: 0,\n chartRangeMax: undefined,\n chartRangeMin: undefined,\n chartRangeClip: false,\n tooltipFormat: new SPFormat('{{prefix}}{{value}}{{suffix}}')\n },\n // Defaults for bullet charts\n bullet: {\n targetColor: '#f33',\n targetWidth: 3, // width of the target bar in pixels\n performanceColor: '#33f',\n rangeColors: ['#d3dafe', '#a8b6ff', '#7f94ff'],\n base: undefined, // set this to a number to change the base start number\n tooltipFormat: new SPFormat('{{fieldkey:fields}} - {{value}}'),\n tooltipValueLookups: { fields: {r: 'Range', p: 'Performance', t: 'Target'} }\n },\n // Defaults for pie charts\n pie: {\n offset: 0,\n sliceColors: ['#3366cc', '#dc3912', '#ff9900', '#109618', '#66aa00',\n '#dd4477', '#0099c6', '#990099'],\n borderWidth: 0,\n borderColor: '#000',\n tooltipFormat: new SPFormat(' {{value}} ({{percent.1}}%)')\n },\n // Defaults for box plots\n box: {\n raw: false,\n boxLineColor: '#000',\n boxFillColor: '#cdf',\n whiskerColor: '#000',\n outlierLineColor: '#333',\n outlierFillColor: '#fff',\n medianColor: '#f00',\n showOutliers: true,\n outlierIQR: 1.5,\n spotRadius: 1.5,\n target: undefined,\n targetColor: '#4a2',\n chartRangeMax: undefined,\n chartRangeMin: undefined,\n tooltipFormat: new SPFormat('{{field:fields}}: {{value}}'),\n tooltipFormatFieldlistKey: 'field',\n tooltipValueLookups: { fields: { lq: 'Lower Quartile', med: 'Median',\n uq: 'Upper Quartile', lo: 'Left Outlier', ro: 'Right Outlier',\n lw: 'Left Whisker', rw: 'Right Whisker'} }\n }\n };\n };\n\n // You can have tooltips use a css class other than jqstooltip by specifying tooltipClassname\n defaultStyles = '.jqstooltip { ' +\n 'position: absolute;' +\n 'left: 0px;' +\n 'top: 0px;' +\n 'visibility: hidden;' +\n 'background: rgb(0, 0, 0) transparent;' +\n 'background-color: rgba(0,0,0,0.6);' +\n 'filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=#99000000, endColorstr=#99000000);' +\n '-ms-filter: \"progid:DXImageTransform.Microsoft.gradient(startColorstr=#99000000, endColorstr=#99000000)\";' +\n 'color: white;' +\n 'font: 10px arial, san serif;' +\n 'text-align: left;' +\n 'white-space: nowrap;' +\n 'padding: 5px;' +\n 'border: 1px solid white;' +\n 'box-sizing: content-box;' +\n 'z-index: 10000;' +\n '}' +\n '.jqsfield { ' +\n 'color: white;' +\n 'font: 10px arial, san serif;' +\n 'text-align: left;' +\n '}';\n\n /**\n * Utilities\n */\n\n createClass = function (/* [baseclass, [mixin, ...]], definition */) {\n var Class, args;\n Class = function () {\n this.init.apply(this, arguments);\n };\n if (arguments.length > 1) {\n if (arguments[0]) {\n Class.prototype = $.extend(new arguments[0](), arguments[arguments.length - 1]);\n Class._super = arguments[0].prototype;\n } else {\n Class.prototype = arguments[arguments.length - 1];\n }\n if (arguments.length > 2) {\n args = Array.prototype.slice.call(arguments, 1, -1);\n args.unshift(Class.prototype);\n $.extend.apply($, args);\n }\n } else {\n Class.prototype = arguments[0];\n }\n Class.prototype.cls = Class;\n return Class;\n };\n\n /**\n * Wraps a format string for tooltips\n * {{x}}\n * {{x.2}\n * {{x:months}}\n */\n $.SPFormatClass = SPFormat = createClass({\n fre: /\\{\\{([\\w.]+?)(:(.+?))?\\}\\}/g,\n precre: /(\\w+)\\.(\\d+)/,\n\n init: function (format, fclass) {\n this.format = format;\n this.fclass = fclass;\n },\n\n render: function (fieldset, lookups, options) {\n var self = this,\n fields = fieldset,\n match, token, lookupkey, fieldvalue, prec;\n return this.format.replace(this.fre, function () {\n var lookup;\n token = arguments[1];\n lookupkey = arguments[3];\n match = self.precre.exec(token);\n if (match) {\n prec = match[2];\n token = match[1];\n } else {\n prec = false;\n }\n fieldvalue = fields[token];\n if (fieldvalue === undefined) {\n return '';\n }\n if (lookupkey && lookups && lookups[lookupkey]) {\n lookup = lookups[lookupkey];\n if (lookup.get) { // RangeMap\n return lookups[lookupkey].get(fieldvalue) || fieldvalue;\n } else {\n return lookups[lookupkey][fieldvalue] || fieldvalue;\n }\n }\n if (isNumber(fieldvalue)) {\n if (options.get('numberFormatter')) {\n fieldvalue = options.get('numberFormatter')(fieldvalue);\n } else {\n fieldvalue = formatNumber(fieldvalue, prec,\n options.get('numberDigitGroupCount'),\n options.get('numberDigitGroupSep'),\n options.get('numberDecimalMark'));\n }\n }\n return fieldvalue;\n });\n }\n });\n\n // convience method to avoid needing the new operator\n $.spformat = function(format, fclass) {\n return new SPFormat(format, fclass);\n };\n\n clipval = function (val, min, max) {\n if (val < min) {\n return min;\n }\n if (val > max) {\n return max;\n }\n return val;\n };\n\n quartile = function (values, q) {\n var vl;\n if (q === 2) {\n vl = Math.floor(values.length / 2);\n return values.length % 2 ? values[vl] : (values[vl-1] + values[vl]) / 2;\n } else {\n if (values.length % 2 ) { // odd\n vl = (values.length * q + q) / 4;\n return vl % 1 ? (values[Math.floor(vl)] + values[Math.floor(vl) - 1]) / 2 : values[vl-1];\n } else { //even\n vl = (values.length * q + 2) / 4;\n return vl % 1 ? (values[Math.floor(vl)] + values[Math.floor(vl) - 1]) / 2 : values[vl-1];\n\n }\n }\n };\n\n normalizeValue = function (val) {\n var nf;\n switch (val) {\n case 'undefined':\n val = undefined;\n break;\n case 'null':\n val = null;\n break;\n case 'true':\n val = true;\n break;\n case 'false':\n val = false;\n break;\n default:\n nf = parseFloat(val);\n if (val == nf) {\n val = nf;\n }\n }\n return val;\n };\n\n normalizeValues = function (vals) {\n var i, result = [];\n for (i = vals.length; i--;) {\n result[i] = normalizeValue(vals[i]);\n }\n return result;\n };\n\n remove = function (vals, filter) {\n var i, vl, result = [];\n for (i = 0, vl = vals.length; i < vl; i++) {\n if (vals[i] !== filter) {\n result.push(vals[i]);\n }\n }\n return result;\n };\n\n isNumber = function (num) {\n return !isNaN(parseFloat(num)) && isFinite(num);\n };\n\n formatNumber = function (num, prec, groupsize, groupsep, decsep) {\n var p, i;\n num = (prec === false ? parseFloat(num).toString() : num.toFixed(prec)).split('');\n p = (p = $.inArray('.', num)) < 0 ? num.length : p;\n if (p < num.length) {\n num[p] = decsep;\n }\n for (i = p - groupsize; i > 0; i -= groupsize) {\n num.splice(i, 0, groupsep);\n }\n return num.join('');\n };\n\n // determine if all values of an array match a value\n // returns true if the array is empty\n all = function (val, arr, ignoreNull) {\n var i;\n for (i = arr.length; i--; ) {\n if (ignoreNull && arr[i] === null) continue;\n if (arr[i] !== val) {\n return false;\n }\n }\n return true;\n };\n\n // sums the numeric values in an array, ignoring other values\n sum = function (vals) {\n var total = 0, i;\n for (i = vals.length; i--;) {\n total += typeof vals[i] === 'number' ? vals[i] : 0;\n }\n return total;\n };\n\n ensureArray = function (val) {\n return $.isArray(val) ? val : [val];\n };\n\n // http://paulirish.com/2008/bookmarklet-inject-new-css-rules/\n addCSS = function(css) {\n var tag, iefail;\n if (document.createStyleSheet) {\n try {\n document.createStyleSheet().cssText = css;\n return;\n } catch (e) {\n // IE <= 9 maxes out at 31 stylesheets; inject into page instead.\n iefail = true;\n }\n }\n tag = document.createElement('style');\n tag.type = 'text/css';\n document.getElementsByTagName('head')[0].appendChild(tag);\n if (iefail) {\n document.styleSheets[document.styleSheets.length - 1].cssText = css;\n } else {\n tag[(typeof document.body.style.WebkitAppearance == 'string') /* webkit only */ ? 'innerText' : 'innerHTML'] = css;\n }\n };\n\n // Provide a cross-browser interface to a few simple drawing primitives\n $.fn.simpledraw = function (width, height, useExisting, interact) {\n var target, mhandler;\n if (useExisting && (target = this.data('_jqs_vcanvas'))) {\n return target;\n }\n\n if ($.fn.sparkline.canvas === false) {\n // We've already determined that neither Canvas nor VML are available\n return false;\n\n } else if ($.fn.sparkline.canvas === undefined) {\n // No function defined yet -- need to see if we support Canvas or VML\n var el = document.createElement('canvas');\n if (!!(el.getContext && el.getContext('2d'))) {\n // Canvas is available\n $.fn.sparkline.canvas = function(width, height, target, interact) {\n return new VCanvas_canvas(width, height, target, interact);\n };\n } else if (document.namespaces && !document.namespaces.v) {\n // VML is available\n document.namespaces.add('v', 'urn:schemas-microsoft-com:vml', '#default#VML');\n $.fn.sparkline.canvas = function(width, height, target, interact) {\n return new VCanvas_vml(width, height, target);\n };\n } else {\n // Neither Canvas nor VML are available\n $.fn.sparkline.canvas = false;\n return false;\n }\n }\n\n if (width === undefined) {\n width = $(this).innerWidth();\n }\n if (height === undefined) {\n height = $(this).innerHeight();\n }\n\n target = $.fn.sparkline.canvas(width, height, this, interact);\n\n mhandler = $(this).data('_jqs_mhandler');\n if (mhandler) {\n mhandler.registerCanvas(target);\n }\n return target;\n };\n\n $.fn.cleardraw = function () {\n var target = this.data('_jqs_vcanvas');\n if (target) {\n target.reset();\n }\n };\n\n $.RangeMapClass = RangeMap = createClass({\n init: function (map) {\n var key, range, rangelist = [];\n for (key in map) {\n if (map.hasOwnProperty(key) && typeof key === 'string' && key.indexOf(':') > -1) {\n range = key.split(':');\n range[0] = range[0].length === 0 ? -Infinity : parseFloat(range[0]);\n range[1] = range[1].length === 0 ? Infinity : parseFloat(range[1]);\n range[2] = map[key];\n rangelist.push(range);\n }\n }\n this.map = map;\n this.rangelist = rangelist || false;\n },\n\n get: function (value) {\n var rangelist = this.rangelist,\n i, range, result;\n if ((result = this.map[value]) !== undefined) {\n return result;\n }\n if (rangelist) {\n for (i = rangelist.length; i--;) {\n range = rangelist[i];\n if (range[0] <= value && range[1] >= value) {\n return range[2];\n }\n }\n }\n return undefined;\n }\n });\n\n // Convenience function\n $.range_map = function(map) {\n return new RangeMap(map);\n };\n\n MouseHandler = createClass({\n init: function (el, options) {\n var $el = $(el);\n this.$el = $el;\n this.options = options;\n this.currentPageX = 0;\n this.currentPageY = 0;\n this.el = el;\n this.splist = [];\n this.tooltip = null;\n this.over = false;\n this.displayTooltips = !options.get('disableTooltips');\n this.highlightEnabled = !options.get('disableHighlight');\n },\n\n registerSparkline: function (sp) {\n this.splist.push(sp);\n if (this.over) {\n this.updateDisplay();\n }\n },\n\n registerCanvas: function (canvas) {\n var $canvas = $(canvas.canvas);\n this.canvas = canvas;\n this.$canvas = $canvas;\n $canvas.mouseenter($.proxy(this.mouseenter, this));\n $canvas.mouseleave($.proxy(this.mouseleave, this));\n $canvas.click($.proxy(this.mouseclick, this));\n },\n\n reset: function (removeTooltip) {\n this.splist = [];\n if (this.tooltip && removeTooltip) {\n this.tooltip.remove();\n this.tooltip = undefined;\n }\n },\n\n mouseclick: function (e) {\n var clickEvent = $.Event('sparklineClick');\n clickEvent.originalEvent = e;\n clickEvent.sparklines = this.splist;\n this.$el.trigger(clickEvent);\n },\n\n mouseenter: function (e) {\n $(document.body).unbind('mousemove.jqs');\n $(document.body).bind('mousemove.jqs', $.proxy(this.mousemove, this));\n this.over = true;\n this.currentPageX = e.pageX;\n this.currentPageY = e.pageY;\n this.currentEl = e.target;\n if (!this.tooltip && this.displayTooltips) {\n this.tooltip = new Tooltip(this.options);\n this.tooltip.updatePosition(e.pageX, e.pageY);\n }\n this.updateDisplay();\n },\n\n mouseleave: function () {\n $(document.body).unbind('mousemove.jqs');\n var splist = this.splist,\n spcount = splist.length,\n needsRefresh = false,\n sp, i;\n this.over = false;\n this.currentEl = null;\n\n if (this.tooltip) {\n this.tooltip.remove();\n this.tooltip = null;\n }\n\n for (i = 0; i < spcount; i++) {\n sp = splist[i];\n if (sp.clearRegionHighlight()) {\n needsRefresh = true;\n }\n }\n\n if (needsRefresh) {\n this.canvas.render();\n }\n },\n\n mousemove: function (e) {\n this.currentPageX = e.pageX;\n this.currentPageY = e.pageY;\n this.currentEl = e.target;\n if (this.tooltip) {\n this.tooltip.updatePosition(e.pageX, e.pageY);\n }\n this.updateDisplay();\n },\n\n updateDisplay: function () {\n var splist = this.splist,\n spcount = splist.length,\n needsRefresh = false,\n offset = this.$canvas.offset(),\n localX = this.currentPageX - offset.left,\n localY = this.currentPageY - offset.top,\n tooltiphtml, sp, i, result, changeEvent;\n if (!this.over) {\n return;\n }\n for (i = 0; i < spcount; i++) {\n sp = splist[i];\n result = sp.setRegionHighlight(this.currentEl, localX, localY);\n if (result) {\n needsRefresh = true;\n }\n }\n if (needsRefresh) {\n changeEvent = $.Event('sparklineRegionChange');\n changeEvent.sparklines = this.splist;\n this.$el.trigger(changeEvent);\n if (this.tooltip) {\n tooltiphtml = '';\n for (i = 0; i < spcount; i++) {\n sp = splist[i];\n tooltiphtml += sp.getCurrentRegionTooltip();\n }\n this.tooltip.setContent(tooltiphtml);\n }\n if (!this.disableHighlight) {\n this.canvas.render();\n }\n }\n if (result === null) {\n this.mouseleave();\n }\n }\n });\n\n\n Tooltip = createClass({\n sizeStyle: 'position: static !important;' +\n 'display: block !important;' +\n 'visibility: hidden !important;' +\n 'float: left !important;',\n\n init: function (options) {\n var tooltipClassname = options.get('tooltipClassname', 'jqstooltip'),\n sizetipStyle = this.sizeStyle,\n offset;\n this.container = options.get('tooltipContainer') || document.body;\n this.tooltipOffsetX = options.get('tooltipOffsetX', 10);\n this.tooltipOffsetY = options.get('tooltipOffsetY', 12);\n // remove any previous lingering tooltip\n $('#jqssizetip').remove();\n $('#jqstooltip').remove();\n this.sizetip = $('
    ', {\n id: 'jqssizetip',\n style: sizetipStyle,\n 'class': tooltipClassname\n });\n this.tooltip = $('
    ', {\n id: 'jqstooltip',\n 'class': tooltipClassname\n }).appendTo(this.container);\n // account for the container's location\n offset = this.tooltip.offset();\n this.offsetLeft = offset.left;\n this.offsetTop = offset.top;\n this.hidden = true;\n $(window).unbind('resize.jqs scroll.jqs');\n $(window).bind('resize.jqs scroll.jqs', $.proxy(this.updateWindowDims, this));\n this.updateWindowDims();\n },\n\n updateWindowDims: function () {\n this.scrollTop = $(window).scrollTop();\n this.scrollLeft = $(window).scrollLeft();\n this.scrollRight = this.scrollLeft + $(window).width();\n this.updatePosition();\n },\n\n getSize: function (content) {\n this.sizetip.html(content).appendTo(this.container);\n this.width = this.sizetip.width() + 1;\n this.height = this.sizetip.height();\n this.sizetip.remove();\n },\n\n setContent: function (content) {\n if (!content) {\n this.tooltip.css('visibility', 'hidden');\n this.hidden = true;\n return;\n }\n this.getSize(content);\n this.tooltip.html(content)\n .css({\n 'width': this.width,\n 'height': this.height,\n 'visibility': 'visible'\n });\n if (this.hidden) {\n this.hidden = false;\n this.updatePosition();\n }\n },\n\n updatePosition: function (x, y) {\n if (x === undefined) {\n if (this.mousex === undefined) {\n return;\n }\n x = this.mousex - this.offsetLeft;\n y = this.mousey - this.offsetTop;\n\n } else {\n this.mousex = x = x - this.offsetLeft;\n this.mousey = y = y - this.offsetTop;\n }\n if (!this.height || !this.width || this.hidden) {\n return;\n }\n\n y -= this.height + this.tooltipOffsetY;\n x += this.tooltipOffsetX;\n\n if (y < this.scrollTop) {\n y = this.scrollTop;\n }\n if (x < this.scrollLeft) {\n x = this.scrollLeft;\n } else if (x + this.width > this.scrollRight) {\n x = this.scrollRight - this.width;\n }\n\n this.tooltip.css({\n 'left': x,\n 'top': y\n });\n },\n\n remove: function () {\n this.tooltip.remove();\n this.sizetip.remove();\n this.sizetip = this.tooltip = undefined;\n $(window).unbind('resize.jqs scroll.jqs');\n }\n });\n\n initStyles = function() {\n addCSS(defaultStyles);\n };\n\n $(initStyles);\n\n pending = [];\n $.fn.sparkline = function (userValues, userOptions) {\n return this.each(function () {\n var options = new $.fn.sparkline.options(this, userOptions),\n $this = $(this),\n render, i;\n render = function () {\n var values, width, height, tmp, mhandler, sp, vals;\n if (userValues === 'html' || userValues === undefined) {\n vals = this.getAttribute(options.get('tagValuesAttribute'));\n if (vals === undefined || vals === null) {\n vals = $this.html();\n }\n values = vals.replace(/(^\\s*\\s*$)|\\s+/g, '').split(',');\n } else {\n values = userValues;\n }\n\n width = options.get('width') === 'auto' ? values.length * options.get('defaultPixelsPerValue') : options.get('width');\n if (options.get('height') === 'auto') {\n if (!options.get('composite') || !$.data(this, '_jqs_vcanvas')) {\n // must be a better way to get the line height\n tmp = document.createElement('span');\n tmp.innerHTML = 'a';\n $this.html(tmp);\n height = $(tmp).innerHeight() || $(tmp).height();\n $(tmp).remove();\n tmp = null;\n }\n } else {\n height = options.get('height');\n }\n\n if (!options.get('disableInteraction')) {\n mhandler = $.data(this, '_jqs_mhandler');\n if (!mhandler) {\n mhandler = new MouseHandler(this, options);\n $.data(this, '_jqs_mhandler', mhandler);\n } else if (!options.get('composite')) {\n mhandler.reset();\n }\n } else {\n mhandler = false;\n }\n\n if (options.get('composite') && !$.data(this, '_jqs_vcanvas')) {\n if (!$.data(this, '_jqs_errnotify')) {\n alert('Attempted to attach a composite sparkline to an element with no existing sparkline');\n $.data(this, '_jqs_errnotify', true);\n }\n return;\n }\n\n sp = new $.fn.sparkline[options.get('type')](this, values, options, width, height);\n\n sp.render();\n\n if (mhandler) {\n mhandler.registerSparkline(sp);\n }\n };\n if (($(this).html() && !options.get('disableHiddenCheck') && $(this).is(':hidden')) || !$(this).parents('body').length) {\n if (!options.get('composite') && $.data(this, '_jqs_pending')) {\n // remove any existing references to the element\n for (i = pending.length; i; i--) {\n if (pending[i - 1][0] == this) {\n pending.splice(i - 1, 1);\n }\n }\n }\n pending.push([this, render]);\n $.data(this, '_jqs_pending', true);\n } else {\n render.call(this);\n }\n });\n };\n\n $.fn.sparkline.defaults = getDefaults();\n\n\n $.sparkline_display_visible = function () {\n var el, i, pl;\n var done = [];\n for (i = 0, pl = pending.length; i < pl; i++) {\n el = pending[i][0];\n if ($(el).is(':visible') && !$(el).parents().is(':hidden')) {\n pending[i][1].call(el);\n $.data(pending[i][0], '_jqs_pending', false);\n done.push(i);\n } else if (!$(el).closest('html').length && !$.data(el, '_jqs_pending')) {\n // element has been inserted and removed from the DOM\n // If it was not yet inserted into the dom then the .data request\n // will return true.\n // removing from the dom causes the data to be removed.\n $.data(pending[i][0], '_jqs_pending', false);\n done.push(i);\n }\n }\n for (i = done.length; i; i--) {\n pending.splice(done[i - 1], 1);\n }\n };\n\n\n /**\n * User option handler\n */\n $.fn.sparkline.options = createClass({\n init: function (tag, userOptions) {\n var extendedOptions, defaults, base, tagOptionType;\n this.userOptions = userOptions = userOptions || {};\n this.tag = tag;\n this.tagValCache = {};\n defaults = $.fn.sparkline.defaults;\n base = defaults.common;\n this.tagOptionsPrefix = userOptions.enableTagOptions && (userOptions.tagOptionsPrefix || base.tagOptionsPrefix);\n\n tagOptionType = this.getTagSetting('type');\n if (tagOptionType === UNSET_OPTION) {\n extendedOptions = defaults[userOptions.type || base.type];\n } else {\n extendedOptions = defaults[tagOptionType];\n }\n this.mergedOptions = $.extend({}, base, extendedOptions, userOptions);\n },\n\n\n getTagSetting: function (key) {\n var prefix = this.tagOptionsPrefix,\n val, i, pairs, keyval;\n if (prefix === false || prefix === undefined) {\n return UNSET_OPTION;\n }\n if (this.tagValCache.hasOwnProperty(key)) {\n val = this.tagValCache.key;\n } else {\n val = this.tag.getAttribute(prefix + key);\n if (val === undefined || val === null) {\n val = UNSET_OPTION;\n } else if (val.substr(0, 1) === '[') {\n val = val.substr(1, val.length - 2).split(',');\n for (i = val.length; i--;) {\n val[i] = normalizeValue(val[i].replace(/(^\\s*)|(\\s*$)/g, ''));\n }\n } else if (val.substr(0, 1) === '{') {\n pairs = val.substr(1, val.length - 2).split(',');\n val = {};\n for (i = pairs.length; i--;) {\n keyval = pairs[i].split(':', 2);\n val[keyval[0].replace(/(^\\s*)|(\\s*$)/g, '')] = normalizeValue(keyval[1].replace(/(^\\s*)|(\\s*$)/g, ''));\n }\n } else {\n val = normalizeValue(val);\n }\n this.tagValCache.key = val;\n }\n return val;\n },\n\n get: function (key, defaultval) {\n var tagOption = this.getTagSetting(key),\n result;\n if (tagOption !== UNSET_OPTION) {\n return tagOption;\n }\n return (result = this.mergedOptions[key]) === undefined ? defaultval : result;\n }\n });\n\n\n $.fn.sparkline._base = createClass({\n disabled: false,\n\n init: function (el, values, options, width, height) {\n this.el = el;\n this.$el = $(el);\n this.values = values;\n this.options = options;\n this.width = width;\n this.height = height;\n this.currentRegion = undefined;\n },\n\n /**\n * Setup the canvas\n */\n initTarget: function () {\n var interactive = !this.options.get('disableInteraction');\n if (!(this.target = this.$el.simpledraw(this.width, this.height, this.options.get('composite'), interactive))) {\n this.disabled = true;\n } else {\n this.canvasWidth = this.target.pixelWidth;\n this.canvasHeight = this.target.pixelHeight;\n }\n },\n\n /**\n * Actually render the chart to the canvas\n */\n render: function () {\n if (this.disabled) {\n this.el.innerHTML = '';\n return false;\n }\n return true;\n },\n\n /**\n * Return a region id for a given x/y co-ordinate\n */\n getRegion: function (x, y) {\n },\n\n /**\n * Highlight an item based on the moused-over x,y co-ordinate\n */\n setRegionHighlight: function (el, x, y) {\n var currentRegion = this.currentRegion,\n highlightEnabled = !this.options.get('disableHighlight'),\n newRegion;\n if (x > this.canvasWidth || y > this.canvasHeight || x < 0 || y < 0) {\n return null;\n }\n newRegion = this.getRegion(el, x, y);\n if (currentRegion !== newRegion) {\n if (currentRegion !== undefined && highlightEnabled) {\n this.removeHighlight();\n }\n this.currentRegion = newRegion;\n if (newRegion !== undefined && highlightEnabled) {\n this.renderHighlight();\n }\n return true;\n }\n return false;\n },\n\n /**\n * Reset any currently highlighted item\n */\n clearRegionHighlight: function () {\n if (this.currentRegion !== undefined) {\n this.removeHighlight();\n this.currentRegion = undefined;\n return true;\n }\n return false;\n },\n\n renderHighlight: function () {\n this.changeHighlight(true);\n },\n\n removeHighlight: function () {\n this.changeHighlight(false);\n },\n\n changeHighlight: function (highlight) {},\n\n /**\n * Fetch the HTML to display as a tooltip\n */\n getCurrentRegionTooltip: function () {\n var options = this.options,\n header = '',\n entries = [],\n fields, formats, formatlen, fclass, text, i,\n showFields, showFieldsKey, newFields, fv,\n formatter, format, fieldlen, j;\n if (this.currentRegion === undefined) {\n return '';\n }\n fields = this.getCurrentRegionFields();\n formatter = options.get('tooltipFormatter');\n if (formatter) {\n return formatter(this, options, fields);\n }\n if (options.get('tooltipChartTitle')) {\n header += '
    ' + options.get('tooltipChartTitle') + '
    \\n';\n }\n formats = this.options.get('tooltipFormat');\n if (!formats) {\n return '';\n }\n if (!$.isArray(formats)) {\n formats = [formats];\n }\n if (!$.isArray(fields)) {\n fields = [fields];\n }\n showFields = this.options.get('tooltipFormatFieldlist');\n showFieldsKey = this.options.get('tooltipFormatFieldlistKey');\n if (showFields && showFieldsKey) {\n // user-selected ordering of fields\n newFields = [];\n for (i = fields.length; i--;) {\n fv = fields[i][showFieldsKey];\n if ((j = $.inArray(fv, showFields)) != -1) {\n newFields[j] = fields[i];\n }\n }\n fields = newFields;\n }\n formatlen = formats.length;\n fieldlen = fields.length;\n for (i = 0; i < formatlen; i++) {\n format = formats[i];\n if (typeof format === 'string') {\n format = new SPFormat(format);\n }\n fclass = format.fclass || 'jqsfield';\n for (j = 0; j < fieldlen; j++) {\n if (!fields[j].isNull || !options.get('tooltipSkipNull')) {\n $.extend(fields[j], {\n prefix: options.get('tooltipPrefix'),\n suffix: options.get('tooltipSuffix')\n });\n text = format.render(fields[j], options.get('tooltipValueLookups'), options);\n entries.push('
    ' + text + '
    ');\n }\n }\n }\n if (entries.length) {\n return header + entries.join('\\n');\n }\n return '';\n },\n\n getCurrentRegionFields: function () {},\n\n calcHighlightColor: function (color, options) {\n var highlightColor = options.get('highlightColor'),\n lighten = options.get('highlightLighten'),\n parse, mult, rgbnew, i;\n if (highlightColor) {\n return highlightColor;\n }\n if (lighten) {\n // extract RGB values\n parse = /^#([0-9a-f])([0-9a-f])([0-9a-f])$/i.exec(color) || /^#([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})$/i.exec(color);\n if (parse) {\n rgbnew = [];\n mult = color.length === 4 ? 16 : 1;\n for (i = 0; i < 3; i++) {\n rgbnew[i] = clipval(Math.round(parseInt(parse[i + 1], 16) * mult * lighten), 0, 255);\n }\n return 'rgb(' + rgbnew.join(',') + ')';\n }\n\n }\n return color;\n }\n\n });\n\n barHighlightMixin = {\n changeHighlight: function (highlight) {\n var currentRegion = this.currentRegion,\n target = this.target,\n shapeids = this.regionShapes[currentRegion],\n newShapes;\n // will be null if the region value was null\n if (shapeids) {\n newShapes = this.renderRegion(currentRegion, highlight);\n if ($.isArray(newShapes) || $.isArray(shapeids)) {\n target.replaceWithShapes(shapeids, newShapes);\n this.regionShapes[currentRegion] = $.map(newShapes, function (newShape) {\n return newShape.id;\n });\n } else {\n target.replaceWithShape(shapeids, newShapes);\n this.regionShapes[currentRegion] = newShapes.id;\n }\n }\n },\n\n render: function () {\n var values = this.values,\n target = this.target,\n regionShapes = this.regionShapes,\n shapes, ids, i, j;\n\n if (!this.cls._super.render.call(this)) {\n return;\n }\n for (i = values.length; i--;) {\n shapes = this.renderRegion(i);\n if (shapes) {\n if ($.isArray(shapes)) {\n ids = [];\n for (j = shapes.length; j--;) {\n shapes[j].append();\n ids.push(shapes[j].id);\n }\n regionShapes[i] = ids;\n } else {\n shapes.append();\n regionShapes[i] = shapes.id; // store just the shapeid\n }\n } else {\n // null value\n regionShapes[i] = null;\n }\n }\n target.render();\n }\n };\n\n /**\n * Line charts\n */\n $.fn.sparkline.line = line = createClass($.fn.sparkline._base, {\n type: 'line',\n\n init: function (el, values, options, width, height) {\n line._super.init.call(this, el, values, options, width, height);\n this.vertices = [];\n this.regionMap = [];\n this.xvalues = [];\n this.yvalues = [];\n this.yminmax = [];\n this.hightlightSpotId = null;\n this.lastShapeId = null;\n this.initTarget();\n },\n\n getRegion: function (el, x, y) {\n var i,\n regionMap = this.regionMap; // maps regions to value positions\n for (i = regionMap.length; i--;) {\n if (regionMap[i] !== null && x >= regionMap[i][0] && x <= regionMap[i][1]) {\n return regionMap[i][2];\n }\n }\n return undefined;\n },\n\n getCurrentRegionFields: function () {\n var currentRegion = this.currentRegion;\n return {\n isNull: this.yvalues[currentRegion] === null,\n x: this.xvalues[currentRegion],\n y: this.yvalues[currentRegion],\n color: this.options.get('lineColor'),\n fillColor: this.options.get('fillColor'),\n offset: currentRegion\n };\n },\n\n renderHighlight: function () {\n var currentRegion = this.currentRegion,\n target = this.target,\n vertex = this.vertices[currentRegion],\n options = this.options,\n spotRadius = options.get('spotRadius'),\n highlightSpotColor = options.get('highlightSpotColor'),\n highlightLineColor = options.get('highlightLineColor'),\n highlightSpot, highlightLine;\n\n if (!vertex) {\n return;\n }\n if (spotRadius && highlightSpotColor) {\n highlightSpot = target.drawCircle(vertex[0], vertex[1],\n spotRadius, undefined, highlightSpotColor);\n this.highlightSpotId = highlightSpot.id;\n target.insertAfterShape(this.lastShapeId, highlightSpot);\n }\n if (highlightLineColor) {\n highlightLine = target.drawLine(vertex[0], this.canvasTop, vertex[0],\n this.canvasTop + this.canvasHeight, highlightLineColor);\n this.highlightLineId = highlightLine.id;\n target.insertAfterShape(this.lastShapeId, highlightLine);\n }\n },\n\n removeHighlight: function () {\n var target = this.target;\n if (this.highlightSpotId) {\n target.removeShapeId(this.highlightSpotId);\n this.highlightSpotId = null;\n }\n if (this.highlightLineId) {\n target.removeShapeId(this.highlightLineId);\n this.highlightLineId = null;\n }\n },\n\n scanValues: function () {\n var values = this.values,\n valcount = values.length,\n xvalues = this.xvalues,\n yvalues = this.yvalues,\n yminmax = this.yminmax,\n i, val, isStr, isArray, sp;\n for (i = 0; i < valcount; i++) {\n val = values[i];\n isStr = typeof(values[i]) === 'string';\n isArray = typeof(values[i]) === 'object' && values[i] instanceof Array;\n sp = isStr && values[i].split(':');\n if (isStr && sp.length === 2) { // x:y\n xvalues.push(Number(sp[0]));\n yvalues.push(Number(sp[1]));\n yminmax.push(Number(sp[1]));\n } else if (isArray) {\n xvalues.push(val[0]);\n yvalues.push(val[1]);\n yminmax.push(val[1]);\n } else {\n xvalues.push(i);\n if (values[i] === null || values[i] === 'null') {\n yvalues.push(null);\n } else {\n yvalues.push(Number(val));\n yminmax.push(Number(val));\n }\n }\n }\n if (this.options.get('xvalues')) {\n xvalues = this.options.get('xvalues');\n }\n\n this.maxy = this.maxyorg = Math.max.apply(Math, yminmax);\n this.miny = this.minyorg = Math.min.apply(Math, yminmax);\n\n this.maxx = Math.max.apply(Math, xvalues);\n this.minx = Math.min.apply(Math, xvalues);\n\n this.xvalues = xvalues;\n this.yvalues = yvalues;\n this.yminmax = yminmax;\n\n },\n\n processRangeOptions: function () {\n var options = this.options,\n normalRangeMin = options.get('normalRangeMin'),\n normalRangeMax = options.get('normalRangeMax');\n\n if (normalRangeMin !== undefined) {\n if (normalRangeMin < this.miny) {\n this.miny = normalRangeMin;\n }\n if (normalRangeMax > this.maxy) {\n this.maxy = normalRangeMax;\n }\n }\n if (options.get('chartRangeMin') !== undefined && (options.get('chartRangeClip') || options.get('chartRangeMin') < this.miny)) {\n this.miny = options.get('chartRangeMin');\n }\n if (options.get('chartRangeMax') !== undefined && (options.get('chartRangeClip') || options.get('chartRangeMax') > this.maxy)) {\n this.maxy = options.get('chartRangeMax');\n }\n if (options.get('chartRangeMinX') !== undefined && (options.get('chartRangeClipX') || options.get('chartRangeMinX') < this.minx)) {\n this.minx = options.get('chartRangeMinX');\n }\n if (options.get('chartRangeMaxX') !== undefined && (options.get('chartRangeClipX') || options.get('chartRangeMaxX') > this.maxx)) {\n this.maxx = options.get('chartRangeMaxX');\n }\n\n },\n\n drawNormalRange: function (canvasLeft, canvasTop, canvasHeight, canvasWidth, rangey) {\n var normalRangeMin = this.options.get('normalRangeMin'),\n normalRangeMax = this.options.get('normalRangeMax'),\n ytop = canvasTop + Math.round(canvasHeight - (canvasHeight * ((normalRangeMax - this.miny) / rangey))),\n height = Math.round((canvasHeight * (normalRangeMax - normalRangeMin)) / rangey);\n this.target.drawRect(canvasLeft, ytop, canvasWidth, height, undefined, this.options.get('normalRangeColor')).append();\n },\n\n render: function () {\n var options = this.options,\n target = this.target,\n canvasWidth = this.canvasWidth,\n canvasHeight = this.canvasHeight,\n vertices = this.vertices,\n spotRadius = options.get('spotRadius'),\n regionMap = this.regionMap,\n rangex, rangey, yvallast,\n canvasTop, canvasLeft,\n vertex, path, paths, x, y, xnext, xpos, xposnext,\n last, next, yvalcount, lineShapes, fillShapes, plen,\n valueSpots, hlSpotsEnabled, color, xvalues, yvalues, i;\n\n if (!line._super.render.call(this)) {\n return;\n }\n\n this.scanValues();\n this.processRangeOptions();\n\n xvalues = this.xvalues;\n yvalues = this.yvalues;\n\n if (!this.yminmax.length || this.yvalues.length < 2) {\n // empty or all null valuess\n return;\n }\n\n canvasTop = canvasLeft = 0;\n\n rangex = this.maxx - this.minx === 0 ? 1 : this.maxx - this.minx;\n rangey = this.maxy - this.miny === 0 ? 1 : this.maxy - this.miny;\n yvallast = this.yvalues.length - 1;\n\n if (spotRadius && (canvasWidth < (spotRadius * 4) || canvasHeight < (spotRadius * 4))) {\n spotRadius = 0;\n }\n if (spotRadius) {\n // adjust the canvas size as required so that spots will fit\n hlSpotsEnabled = options.get('highlightSpotColor') && !options.get('disableInteraction');\n if (hlSpotsEnabled || options.get('minSpotColor') || (options.get('spotColor') && yvalues[yvallast] === this.miny)) {\n canvasHeight -= Math.ceil(spotRadius);\n }\n if (hlSpotsEnabled || options.get('maxSpotColor') || (options.get('spotColor') && yvalues[yvallast] === this.maxy)) {\n canvasHeight -= Math.ceil(spotRadius);\n canvasTop += Math.ceil(spotRadius);\n }\n if (hlSpotsEnabled ||\n ((options.get('minSpotColor') || options.get('maxSpotColor')) && (yvalues[0] === this.miny || yvalues[0] === this.maxy))) {\n canvasLeft += Math.ceil(spotRadius);\n canvasWidth -= Math.ceil(spotRadius);\n }\n if (hlSpotsEnabled || options.get('spotColor') ||\n (options.get('minSpotColor') || options.get('maxSpotColor') &&\n (yvalues[yvallast] === this.miny || yvalues[yvallast] === this.maxy))) {\n canvasWidth -= Math.ceil(spotRadius);\n }\n }\n\n\n canvasHeight--;\n\n if (options.get('normalRangeMin') !== undefined && !options.get('drawNormalOnTop')) {\n this.drawNormalRange(canvasLeft, canvasTop, canvasHeight, canvasWidth, rangey);\n }\n\n path = [];\n paths = [path];\n last = next = null;\n yvalcount = yvalues.length;\n for (i = 0; i < yvalcount; i++) {\n x = xvalues[i];\n xnext = xvalues[i + 1];\n y = yvalues[i];\n xpos = canvasLeft + Math.round((x - this.minx) * (canvasWidth / rangex));\n xposnext = i < yvalcount - 1 ? canvasLeft + Math.round((xnext - this.minx) * (canvasWidth / rangex)) : canvasWidth;\n next = xpos + ((xposnext - xpos) / 2);\n regionMap[i] = [last || 0, next, i];\n last = next;\n if (y === null) {\n if (i) {\n if (yvalues[i - 1] !== null) {\n path = [];\n paths.push(path);\n }\n vertices.push(null);\n }\n } else {\n if (y < this.miny) {\n y = this.miny;\n }\n if (y > this.maxy) {\n y = this.maxy;\n }\n if (!path.length) {\n // previous value was null\n path.push([xpos, canvasTop + canvasHeight]);\n }\n vertex = [xpos, canvasTop + Math.round(canvasHeight - (canvasHeight * ((y - this.miny) / rangey)))];\n path.push(vertex);\n vertices.push(vertex);\n }\n }\n\n lineShapes = [];\n fillShapes = [];\n plen = paths.length;\n for (i = 0; i < plen; i++) {\n path = paths[i];\n if (path.length) {\n if (options.get('fillColor')) {\n path.push([path[path.length - 1][0], (canvasTop + canvasHeight)]);\n fillShapes.push(path.slice(0));\n path.pop();\n }\n // if there's only a single point in this path, then we want to display it\n // as a vertical line which means we keep path[0] as is\n if (path.length > 2) {\n // else we want the first value\n path[0] = [path[0][0], path[1][1]];\n }\n lineShapes.push(path);\n }\n }\n\n // draw the fill first, then optionally the normal range, then the line on top of that\n plen = fillShapes.length;\n for (i = 0; i < plen; i++) {\n target.drawShape(fillShapes[i],\n options.get('fillColor'), options.get('fillColor')).append();\n }\n\n if (options.get('normalRangeMin') !== undefined && options.get('drawNormalOnTop')) {\n this.drawNormalRange(canvasLeft, canvasTop, canvasHeight, canvasWidth, rangey);\n }\n\n plen = lineShapes.length;\n for (i = 0; i < plen; i++) {\n target.drawShape(lineShapes[i], options.get('lineColor'), undefined,\n options.get('lineWidth')).append();\n }\n\n if (spotRadius && options.get('valueSpots')) {\n valueSpots = options.get('valueSpots');\n if (valueSpots.get === undefined) {\n valueSpots = new RangeMap(valueSpots);\n }\n for (i = 0; i < yvalcount; i++) {\n color = valueSpots.get(yvalues[i]);\n if (color) {\n target.drawCircle(canvasLeft + Math.round((xvalues[i] - this.minx) * (canvasWidth / rangex)),\n canvasTop + Math.round(canvasHeight - (canvasHeight * ((yvalues[i] - this.miny) / rangey))),\n spotRadius, undefined,\n color).append();\n }\n }\n\n }\n if (spotRadius && options.get('spotColor') && yvalues[yvallast] !== null) {\n target.drawCircle(canvasLeft + Math.round((xvalues[xvalues.length - 1] - this.minx) * (canvasWidth / rangex)),\n canvasTop + Math.round(canvasHeight - (canvasHeight * ((yvalues[yvallast] - this.miny) / rangey))),\n spotRadius, undefined,\n options.get('spotColor')).append();\n }\n if (this.maxy !== this.minyorg) {\n if (spotRadius && options.get('minSpotColor')) {\n x = xvalues[$.inArray(this.minyorg, yvalues)];\n target.drawCircle(canvasLeft + Math.round((x - this.minx) * (canvasWidth / rangex)),\n canvasTop + Math.round(canvasHeight - (canvasHeight * ((this.minyorg - this.miny) / rangey))),\n spotRadius, undefined,\n options.get('minSpotColor')).append();\n }\n if (spotRadius && options.get('maxSpotColor')) {\n x = xvalues[$.inArray(this.maxyorg, yvalues)];\n target.drawCircle(canvasLeft + Math.round((x - this.minx) * (canvasWidth / rangex)),\n canvasTop + Math.round(canvasHeight - (canvasHeight * ((this.maxyorg - this.miny) / rangey))),\n spotRadius, undefined,\n options.get('maxSpotColor')).append();\n }\n }\n\n this.lastShapeId = target.getLastShapeId();\n this.canvasTop = canvasTop;\n target.render();\n }\n });\n\n /**\n * Bar charts\n */\n $.fn.sparkline.bar = bar = createClass($.fn.sparkline._base, barHighlightMixin, {\n type: 'bar',\n\n init: function (el, values, options, width, height) {\n var barWidth = parseInt(options.get('barWidth'), 10),\n barSpacing = parseInt(options.get('barSpacing'), 10),\n chartRangeMin = options.get('chartRangeMin'),\n chartRangeMax = options.get('chartRangeMax'),\n chartRangeClip = options.get('chartRangeClip'),\n stackMin = Infinity,\n stackMax = -Infinity,\n isStackString, groupMin, groupMax, stackRanges,\n numValues, i, vlen, range, zeroAxis, xaxisOffset, min, max, clipMin, clipMax,\n stacked, vlist, j, slen, svals, val, yoffset, yMaxCalc, canvasHeightEf;\n bar._super.init.call(this, el, values, options, width, height);\n\n // scan values to determine whether to stack bars\n for (i = 0, vlen = values.length; i < vlen; i++) {\n val = values[i];\n isStackString = typeof(val) === 'string' && val.indexOf(':') > -1;\n if (isStackString || $.isArray(val)) {\n stacked = true;\n if (isStackString) {\n val = values[i] = normalizeValues(val.split(':'));\n }\n val = remove(val, null); // min/max will treat null as zero\n groupMin = Math.min.apply(Math, val);\n groupMax = Math.max.apply(Math, val);\n if (groupMin < stackMin) {\n stackMin = groupMin;\n }\n if (groupMax > stackMax) {\n stackMax = groupMax;\n }\n }\n }\n\n this.stacked = stacked;\n this.regionShapes = {};\n this.barWidth = barWidth;\n this.barSpacing = barSpacing;\n this.totalBarWidth = barWidth + barSpacing;\n this.width = width = (values.length * barWidth) + ((values.length - 1) * barSpacing);\n\n this.initTarget();\n\n if (chartRangeClip) {\n clipMin = chartRangeMin === undefined ? -Infinity : chartRangeMin;\n clipMax = chartRangeMax === undefined ? Infinity : chartRangeMax;\n }\n\n numValues = [];\n stackRanges = stacked ? [] : numValues;\n var stackTotals = [];\n var stackRangesNeg = [];\n for (i = 0, vlen = values.length; i < vlen; i++) {\n if (stacked) {\n vlist = values[i];\n values[i] = svals = [];\n stackTotals[i] = 0;\n stackRanges[i] = stackRangesNeg[i] = 0;\n for (j = 0, slen = vlist.length; j < slen; j++) {\n val = svals[j] = chartRangeClip ? clipval(vlist[j], clipMin, clipMax) : vlist[j];\n if (val !== null) {\n if (val > 0) {\n stackTotals[i] += val;\n }\n if (stackMin < 0 && stackMax > 0) {\n if (val < 0) {\n stackRangesNeg[i] += Math.abs(val);\n } else {\n stackRanges[i] += val;\n }\n } else {\n stackRanges[i] += Math.abs(val - (val < 0 ? stackMax : stackMin));\n }\n numValues.push(val);\n }\n }\n } else {\n val = chartRangeClip ? clipval(values[i], clipMin, clipMax) : values[i];\n val = values[i] = normalizeValue(val);\n if (val !== null) {\n numValues.push(val);\n }\n }\n }\n this.max = max = Math.max.apply(Math, numValues);\n this.min = min = Math.min.apply(Math, numValues);\n this.stackMax = stackMax = stacked ? Math.max.apply(Math, stackTotals) : max;\n this.stackMin = stackMin = stacked ? Math.min.apply(Math, numValues) : min;\n\n if (options.get('chartRangeMin') !== undefined && (options.get('chartRangeClip') || options.get('chartRangeMin') < min)) {\n min = options.get('chartRangeMin');\n }\n if (options.get('chartRangeMax') !== undefined && (options.get('chartRangeClip') || options.get('chartRangeMax') > max)) {\n max = options.get('chartRangeMax');\n }\n\n this.zeroAxis = zeroAxis = options.get('zeroAxis', true);\n if (min <= 0 && max >= 0 && zeroAxis) {\n xaxisOffset = 0;\n } else if (zeroAxis == false) {\n xaxisOffset = min;\n } else if (min > 0) {\n xaxisOffset = min;\n } else {\n xaxisOffset = max;\n }\n this.xaxisOffset = xaxisOffset;\n\n range = stacked ? (Math.max.apply(Math, stackRanges) + Math.max.apply(Math, stackRangesNeg)) : max - min;\n\n // as we plot zero/min values a single pixel line, we add a pixel to all other\n // values - Reduce the effective canvas size to suit\n this.canvasHeightEf = (zeroAxis && min < 0) ? this.canvasHeight - 2 : this.canvasHeight - 1;\n\n if (min < xaxisOffset) {\n yMaxCalc = (stacked && max >= 0) ? stackMax : max;\n yoffset = (yMaxCalc - xaxisOffset) / range * this.canvasHeight;\n if (yoffset !== Math.ceil(yoffset)) {\n this.canvasHeightEf -= 2;\n yoffset = Math.ceil(yoffset);\n }\n } else {\n yoffset = this.canvasHeight;\n }\n this.yoffset = yoffset;\n\n if ($.isArray(options.get('colorMap'))) {\n this.colorMapByIndex = options.get('colorMap');\n this.colorMapByValue = null;\n } else {\n this.colorMapByIndex = null;\n this.colorMapByValue = options.get('colorMap');\n if (this.colorMapByValue && this.colorMapByValue.get === undefined) {\n this.colorMapByValue = new RangeMap(this.colorMapByValue);\n }\n }\n\n this.range = range;\n },\n\n getRegion: function (el, x, y) {\n var result = Math.floor(x / this.totalBarWidth);\n return (result < 0 || result >= this.values.length) ? undefined : result;\n },\n\n getCurrentRegionFields: function () {\n var currentRegion = this.currentRegion,\n values = ensureArray(this.values[currentRegion]),\n result = [],\n value, i;\n for (i = values.length; i--;) {\n value = values[i];\n result.push({\n isNull: value === null,\n value: value,\n color: this.calcColor(i, value, currentRegion),\n offset: currentRegion\n });\n }\n return result;\n },\n\n calcColor: function (stacknum, value, valuenum) {\n var colorMapByIndex = this.colorMapByIndex,\n colorMapByValue = this.colorMapByValue,\n options = this.options,\n color, newColor;\n if (this.stacked) {\n color = options.get('stackedBarColor');\n } else {\n color = (value < 0) ? options.get('negBarColor') : options.get('barColor');\n }\n if (value === 0 && options.get('zeroColor') !== undefined) {\n color = options.get('zeroColor');\n }\n if (colorMapByValue && (newColor = colorMapByValue.get(value))) {\n color = newColor;\n } else if (colorMapByIndex && colorMapByIndex.length > valuenum) {\n color = colorMapByIndex[valuenum];\n }\n return $.isArray(color) ? color[stacknum % color.length] : color;\n },\n\n /**\n * Render bar(s) for a region\n */\n renderRegion: function (valuenum, highlight) {\n var vals = this.values[valuenum],\n options = this.options,\n xaxisOffset = this.xaxisOffset,\n result = [],\n range = this.range,\n stacked = this.stacked,\n target = this.target,\n x = valuenum * this.totalBarWidth,\n canvasHeightEf = this.canvasHeightEf,\n yoffset = this.yoffset,\n y, height, color, isNull, yoffsetNeg, i, valcount, val, minPlotted, allMin;\n\n vals = $.isArray(vals) ? vals : [vals];\n valcount = vals.length;\n val = vals[0];\n isNull = all(null, vals);\n allMin = all(xaxisOffset, vals, true);\n\n if (isNull) {\n if (options.get('nullColor')) {\n color = highlight ? options.get('nullColor') : this.calcHighlightColor(options.get('nullColor'), options);\n y = (yoffset > 0) ? yoffset - 1 : yoffset;\n return target.drawRect(x, y, this.barWidth - 1, 0, color, color);\n } else {\n return undefined;\n }\n }\n yoffsetNeg = yoffset;\n for (i = 0; i < valcount; i++) {\n val = vals[i];\n\n if (stacked && val === xaxisOffset) {\n if (!allMin || minPlotted) {\n continue;\n }\n minPlotted = true;\n }\n\n if (range > 0) {\n height = Math.floor(canvasHeightEf * ((Math.abs(val - xaxisOffset) / range))) + 1;\n } else {\n height = 1;\n }\n if (val < xaxisOffset || (val === xaxisOffset && yoffset === 0)) {\n y = yoffsetNeg;\n yoffsetNeg += height;\n } else {\n y = yoffset - height;\n yoffset -= height;\n }\n color = this.calcColor(i, val, valuenum);\n if (highlight) {\n color = this.calcHighlightColor(color, options);\n }\n result.push(target.drawRect(x, y, this.barWidth - 1, height - 1, color, color));\n }\n if (result.length === 1) {\n return result[0];\n }\n return result;\n }\n });\n\n /**\n * Tristate charts\n */\n $.fn.sparkline.tristate = tristate = createClass($.fn.sparkline._base, barHighlightMixin, {\n type: 'tristate',\n\n init: function (el, values, options, width, height) {\n var barWidth = parseInt(options.get('barWidth'), 10),\n barSpacing = parseInt(options.get('barSpacing'), 10);\n tristate._super.init.call(this, el, values, options, width, height);\n\n this.regionShapes = {};\n this.barWidth = barWidth;\n this.barSpacing = barSpacing;\n this.totalBarWidth = barWidth + barSpacing;\n this.values = $.map(values, Number);\n this.width = width = (values.length * barWidth) + ((values.length - 1) * barSpacing);\n\n if ($.isArray(options.get('colorMap'))) {\n this.colorMapByIndex = options.get('colorMap');\n this.colorMapByValue = null;\n } else {\n this.colorMapByIndex = null;\n this.colorMapByValue = options.get('colorMap');\n if (this.colorMapByValue && this.colorMapByValue.get === undefined) {\n this.colorMapByValue = new RangeMap(this.colorMapByValue);\n }\n }\n this.initTarget();\n },\n\n getRegion: function (el, x, y) {\n return Math.floor(x / this.totalBarWidth);\n },\n\n getCurrentRegionFields: function () {\n var currentRegion = this.currentRegion;\n return {\n isNull: this.values[currentRegion] === undefined,\n value: this.values[currentRegion],\n color: this.calcColor(this.values[currentRegion], currentRegion),\n offset: currentRegion\n };\n },\n\n calcColor: function (value, valuenum) {\n var values = this.values,\n options = this.options,\n colorMapByIndex = this.colorMapByIndex,\n colorMapByValue = this.colorMapByValue,\n color, newColor;\n\n if (colorMapByValue && (newColor = colorMapByValue.get(value))) {\n color = newColor;\n } else if (colorMapByIndex && colorMapByIndex.length > valuenum) {\n color = colorMapByIndex[valuenum];\n } else if (values[valuenum] < 0) {\n color = options.get('negBarColor');\n } else if (values[valuenum] > 0) {\n color = options.get('posBarColor');\n } else {\n color = options.get('zeroBarColor');\n }\n return color;\n },\n\n renderRegion: function (valuenum, highlight) {\n var values = this.values,\n options = this.options,\n target = this.target,\n canvasHeight, height, halfHeight,\n x, y, color;\n\n canvasHeight = target.pixelHeight;\n halfHeight = Math.round(canvasHeight / 2);\n\n x = valuenum * this.totalBarWidth;\n if (values[valuenum] < 0) {\n y = halfHeight;\n height = halfHeight - 1;\n } else if (values[valuenum] > 0) {\n y = 0;\n height = halfHeight - 1;\n } else {\n y = halfHeight - 1;\n height = 2;\n }\n color = this.calcColor(values[valuenum], valuenum);\n if (color === null) {\n return;\n }\n if (highlight) {\n color = this.calcHighlightColor(color, options);\n }\n return target.drawRect(x, y, this.barWidth - 1, height - 1, color, color);\n }\n });\n\n /**\n * Discrete charts\n */\n $.fn.sparkline.discrete = discrete = createClass($.fn.sparkline._base, barHighlightMixin, {\n type: 'discrete',\n\n init: function (el, values, options, width, height) {\n discrete._super.init.call(this, el, values, options, width, height);\n\n this.regionShapes = {};\n this.values = values = $.map(values, Number);\n this.min = Math.min.apply(Math, values);\n this.max = Math.max.apply(Math, values);\n this.range = this.max - this.min;\n this.width = width = options.get('width') === 'auto' ? values.length * 2 : this.width;\n this.interval = Math.floor(width / values.length);\n this.itemWidth = width / values.length;\n if (options.get('chartRangeMin') !== undefined && (options.get('chartRangeClip') || options.get('chartRangeMin') < this.min)) {\n this.min = options.get('chartRangeMin');\n }\n if (options.get('chartRangeMax') !== undefined && (options.get('chartRangeClip') || options.get('chartRangeMax') > this.max)) {\n this.max = options.get('chartRangeMax');\n }\n this.initTarget();\n if (this.target) {\n this.lineHeight = options.get('lineHeight') === 'auto' ? Math.round(this.canvasHeight * 0.3) : options.get('lineHeight');\n }\n },\n\n getRegion: function (el, x, y) {\n return Math.floor(x / this.itemWidth);\n },\n\n getCurrentRegionFields: function () {\n var currentRegion = this.currentRegion;\n return {\n isNull: this.values[currentRegion] === undefined,\n value: this.values[currentRegion],\n offset: currentRegion\n };\n },\n\n renderRegion: function (valuenum, highlight) {\n var values = this.values,\n options = this.options,\n min = this.min,\n max = this.max,\n range = this.range,\n interval = this.interval,\n target = this.target,\n canvasHeight = this.canvasHeight,\n lineHeight = this.lineHeight,\n pheight = canvasHeight - lineHeight,\n ytop, val, color, x;\n\n val = clipval(values[valuenum], min, max);\n x = valuenum * interval;\n ytop = Math.round(pheight - pheight * ((val - min) / range));\n color = (options.get('thresholdColor') && val < options.get('thresholdValue')) ? options.get('thresholdColor') : options.get('lineColor');\n if (highlight) {\n color = this.calcHighlightColor(color, options);\n }\n return target.drawLine(x, ytop, x, ytop + lineHeight, color);\n }\n });\n\n /**\n * Bullet charts\n */\n $.fn.sparkline.bullet = bullet = createClass($.fn.sparkline._base, {\n type: 'bullet',\n\n init: function (el, values, options, width, height) {\n var min, max, vals;\n bullet._super.init.call(this, el, values, options, width, height);\n\n // values: target, performance, range1, range2, range3\n this.values = values = normalizeValues(values);\n // target or performance could be null\n vals = values.slice();\n vals[0] = vals[0] === null ? vals[2] : vals[0];\n vals[1] = values[1] === null ? vals[2] : vals[1];\n min = Math.min.apply(Math, values);\n max = Math.max.apply(Math, values);\n if (options.get('base') === undefined) {\n min = min < 0 ? min : 0;\n } else {\n min = options.get('base');\n }\n this.min = min;\n this.max = max;\n this.range = max - min;\n this.shapes = {};\n this.valueShapes = {};\n this.regiondata = {};\n this.width = width = options.get('width') === 'auto' ? '4.0em' : width;\n this.target = this.$el.simpledraw(width, height, options.get('composite'));\n if (!values.length) {\n this.disabled = true;\n }\n this.initTarget();\n },\n\n getRegion: function (el, x, y) {\n var shapeid = this.target.getShapeAt(el, x, y);\n return (shapeid !== undefined && this.shapes[shapeid] !== undefined) ? this.shapes[shapeid] : undefined;\n },\n\n getCurrentRegionFields: function () {\n var currentRegion = this.currentRegion;\n return {\n fieldkey: currentRegion.substr(0, 1),\n value: this.values[currentRegion.substr(1)],\n region: currentRegion\n };\n },\n\n changeHighlight: function (highlight) {\n var currentRegion = this.currentRegion,\n shapeid = this.valueShapes[currentRegion],\n shape;\n delete this.shapes[shapeid];\n switch (currentRegion.substr(0, 1)) {\n case 'r':\n shape = this.renderRange(currentRegion.substr(1), highlight);\n break;\n case 'p':\n shape = this.renderPerformance(highlight);\n break;\n case 't':\n shape = this.renderTarget(highlight);\n break;\n }\n this.valueShapes[currentRegion] = shape.id;\n this.shapes[shape.id] = currentRegion;\n this.target.replaceWithShape(shapeid, shape);\n },\n\n renderRange: function (rn, highlight) {\n var rangeval = this.values[rn],\n rangewidth = Math.round(this.canvasWidth * ((rangeval - this.min) / this.range)),\n color = this.options.get('rangeColors')[rn - 2];\n if (highlight) {\n color = this.calcHighlightColor(color, this.options);\n }\n return this.target.drawRect(0, 0, rangewidth - 1, this.canvasHeight - 1, color, color);\n },\n\n renderPerformance: function (highlight) {\n var perfval = this.values[1],\n perfwidth = Math.round(this.canvasWidth * ((perfval - this.min) / this.range)),\n color = this.options.get('performanceColor');\n if (highlight) {\n color = this.calcHighlightColor(color, this.options);\n }\n return this.target.drawRect(0, Math.round(this.canvasHeight * 0.3), perfwidth - 1,\n Math.round(this.canvasHeight * 0.4) - 1, color, color);\n },\n\n renderTarget: function (highlight) {\n var targetval = this.values[0],\n x = Math.round(this.canvasWidth * ((targetval - this.min) / this.range) - (this.options.get('targetWidth') / 2)),\n targettop = Math.round(this.canvasHeight * 0.10),\n targetheight = this.canvasHeight - (targettop * 2),\n color = this.options.get('targetColor');\n if (highlight) {\n color = this.calcHighlightColor(color, this.options);\n }\n return this.target.drawRect(x, targettop, this.options.get('targetWidth') - 1, targetheight - 1, color, color);\n },\n\n render: function () {\n var vlen = this.values.length,\n target = this.target,\n i, shape;\n if (!bullet._super.render.call(this)) {\n return;\n }\n for (i = 2; i < vlen; i++) {\n shape = this.renderRange(i).append();\n this.shapes[shape.id] = 'r' + i;\n this.valueShapes['r' + i] = shape.id;\n }\n if (this.values[1] !== null) {\n shape = this.renderPerformance().append();\n this.shapes[shape.id] = 'p1';\n this.valueShapes.p1 = shape.id;\n }\n if (this.values[0] !== null) {\n shape = this.renderTarget().append();\n this.shapes[shape.id] = 't0';\n this.valueShapes.t0 = shape.id;\n }\n target.render();\n }\n });\n\n /**\n * Pie charts\n */\n $.fn.sparkline.pie = pie = createClass($.fn.sparkline._base, {\n type: 'pie',\n\n init: function (el, values, options, width, height) {\n var total = 0, i;\n\n pie._super.init.call(this, el, values, options, width, height);\n\n this.shapes = {}; // map shape ids to value offsets\n this.valueShapes = {}; // maps value offsets to shape ids\n this.values = values = $.map(values, Number);\n\n if (options.get('width') === 'auto') {\n this.width = this.height;\n }\n\n if (values.length > 0) {\n for (i = values.length; i--;) {\n total += values[i];\n }\n }\n this.total = total;\n this.initTarget();\n this.radius = Math.floor(Math.min(this.canvasWidth, this.canvasHeight) / 2);\n },\n\n getRegion: function (el, x, y) {\n var shapeid = this.target.getShapeAt(el, x, y);\n return (shapeid !== undefined && this.shapes[shapeid] !== undefined) ? this.shapes[shapeid] : undefined;\n },\n\n getCurrentRegionFields: function () {\n var currentRegion = this.currentRegion;\n return {\n isNull: this.values[currentRegion] === undefined,\n value: this.values[currentRegion],\n percent: this.values[currentRegion] / this.total * 100,\n color: this.options.get('sliceColors')[currentRegion % this.options.get('sliceColors').length],\n offset: currentRegion\n };\n },\n\n changeHighlight: function (highlight) {\n var currentRegion = this.currentRegion,\n newslice = this.renderSlice(currentRegion, highlight),\n shapeid = this.valueShapes[currentRegion];\n delete this.shapes[shapeid];\n this.target.replaceWithShape(shapeid, newslice);\n this.valueShapes[currentRegion] = newslice.id;\n this.shapes[newslice.id] = currentRegion;\n },\n\n renderSlice: function (valuenum, highlight) {\n var target = this.target,\n options = this.options,\n radius = this.radius,\n borderWidth = options.get('borderWidth'),\n offset = options.get('offset'),\n circle = 2 * Math.PI,\n values = this.values,\n total = this.total,\n next = offset ? (2*Math.PI)*(offset/360) : 0,\n start, end, i, vlen, color;\n\n vlen = values.length;\n for (i = 0; i < vlen; i++) {\n start = next;\n end = next;\n if (total > 0) { // avoid divide by zero\n end = next + (circle * (values[i] / total));\n }\n if (valuenum === i) {\n color = options.get('sliceColors')[i % options.get('sliceColors').length];\n if (highlight) {\n color = this.calcHighlightColor(color, options);\n }\n\n return target.drawPieSlice(radius, radius, radius - borderWidth, start, end, undefined, color);\n }\n next = end;\n }\n },\n\n render: function () {\n var target = this.target,\n values = this.values,\n options = this.options,\n radius = this.radius,\n borderWidth = options.get('borderWidth'),\n donutWidth = options.get('donutWidth'),\n shape, i;\n\n if (!pie._super.render.call(this)) {\n return;\n }\n if (borderWidth) {\n target.drawCircle(radius, radius, Math.floor(radius - (borderWidth / 2)),\n options.get('borderColor'), undefined, borderWidth).append();\n }\n for (i = values.length; i--;) {\n if (values[i]) { // don't render zero values\n shape = this.renderSlice(i).append();\n this.valueShapes[i] = shape.id; // store just the shapeid\n this.shapes[shape.id] = i;\n }\n }\n if (donutWidth) {\n target.drawCircle(radius, radius, radius - donutWidth, options.get('donutColor'), \n options.get('donutColor'), 0).append();\n }\n target.render();\n }\n });\n\n /**\n * Box plots\n */\n $.fn.sparkline.box = box = createClass($.fn.sparkline._base, {\n type: 'box',\n\n init: function (el, values, options, width, height) {\n box._super.init.call(this, el, values, options, width, height);\n this.values = $.map(values, Number);\n this.width = options.get('width') === 'auto' ? '4.0em' : width;\n this.initTarget();\n if (!this.values.length) {\n this.disabled = 1;\n }\n },\n\n /**\n * Simulate a single region\n */\n getRegion: function () {\n return 1;\n },\n\n getCurrentRegionFields: function () {\n var result = [\n { field: 'lq', value: this.quartiles[0] },\n { field: 'med', value: this.quartiles[1] },\n { field: 'uq', value: this.quartiles[2] }\n ];\n if (this.loutlier !== undefined) {\n result.push({ field: 'lo', value: this.loutlier});\n }\n if (this.routlier !== undefined) {\n result.push({ field: 'ro', value: this.routlier});\n }\n if (this.lwhisker !== undefined) {\n result.push({ field: 'lw', value: this.lwhisker});\n }\n if (this.rwhisker !== undefined) {\n result.push({ field: 'rw', value: this.rwhisker});\n }\n return result;\n },\n\n render: function () {\n var target = this.target,\n values = this.values,\n vlen = values.length,\n options = this.options,\n canvasWidth = this.canvasWidth,\n canvasHeight = this.canvasHeight,\n minValue = options.get('chartRangeMin') === undefined ? Math.min.apply(Math, values) : options.get('chartRangeMin'),\n maxValue = options.get('chartRangeMax') === undefined ? Math.max.apply(Math, values) : options.get('chartRangeMax'),\n canvasLeft = 0,\n lwhisker, loutlier, iqr, q1, q2, q3, rwhisker, routlier, i,\n size, unitSize;\n\n if (!box._super.render.call(this)) {\n return;\n }\n\n if (options.get('raw')) {\n if (options.get('showOutliers') && values.length > 5) {\n loutlier = values[0];\n lwhisker = values[1];\n q1 = values[2];\n q2 = values[3];\n q3 = values[4];\n rwhisker = values[5];\n routlier = values[6];\n } else {\n lwhisker = values[0];\n q1 = values[1];\n q2 = values[2];\n q3 = values[3];\n rwhisker = values[4];\n }\n } else {\n values.sort(function (a, b) { return a - b; });\n q1 = quartile(values, 1);\n q2 = quartile(values, 2);\n q3 = quartile(values, 3);\n iqr = q3 - q1;\n if (options.get('showOutliers')) {\n lwhisker = rwhisker = undefined;\n for (i = 0; i < vlen; i++) {\n if (lwhisker === undefined && values[i] > q1 - (iqr * options.get('outlierIQR'))) {\n lwhisker = values[i];\n }\n if (values[i] < q3 + (iqr * options.get('outlierIQR'))) {\n rwhisker = values[i];\n }\n }\n loutlier = values[0];\n routlier = values[vlen - 1];\n } else {\n lwhisker = values[0];\n rwhisker = values[vlen - 1];\n }\n }\n this.quartiles = [q1, q2, q3];\n this.lwhisker = lwhisker;\n this.rwhisker = rwhisker;\n this.loutlier = loutlier;\n this.routlier = routlier;\n\n unitSize = canvasWidth / (maxValue - minValue + 1);\n if (options.get('showOutliers')) {\n canvasLeft = Math.ceil(options.get('spotRadius'));\n canvasWidth -= 2 * Math.ceil(options.get('spotRadius'));\n unitSize = canvasWidth / (maxValue - minValue + 1);\n if (loutlier < lwhisker) {\n target.drawCircle((loutlier - minValue) * unitSize + canvasLeft,\n canvasHeight / 2,\n options.get('spotRadius'),\n options.get('outlierLineColor'),\n options.get('outlierFillColor')).append();\n }\n if (routlier > rwhisker) {\n target.drawCircle((routlier - minValue) * unitSize + canvasLeft,\n canvasHeight / 2,\n options.get('spotRadius'),\n options.get('outlierLineColor'),\n options.get('outlierFillColor')).append();\n }\n }\n\n // box\n target.drawRect(\n Math.round((q1 - minValue) * unitSize + canvasLeft),\n Math.round(canvasHeight * 0.1),\n Math.round((q3 - q1) * unitSize),\n Math.round(canvasHeight * 0.8),\n options.get('boxLineColor'),\n options.get('boxFillColor')).append();\n // left whisker\n target.drawLine(\n Math.round((lwhisker - minValue) * unitSize + canvasLeft),\n Math.round(canvasHeight / 2),\n Math.round((q1 - minValue) * unitSize + canvasLeft),\n Math.round(canvasHeight / 2),\n options.get('lineColor')).append();\n target.drawLine(\n Math.round((lwhisker - minValue) * unitSize + canvasLeft),\n Math.round(canvasHeight / 4),\n Math.round((lwhisker - minValue) * unitSize + canvasLeft),\n Math.round(canvasHeight - canvasHeight / 4),\n options.get('whiskerColor')).append();\n // right whisker\n target.drawLine(Math.round((rwhisker - minValue) * unitSize + canvasLeft),\n Math.round(canvasHeight / 2),\n Math.round((q3 - minValue) * unitSize + canvasLeft),\n Math.round(canvasHeight / 2),\n options.get('lineColor')).append();\n target.drawLine(\n Math.round((rwhisker - minValue) * unitSize + canvasLeft),\n Math.round(canvasHeight / 4),\n Math.round((rwhisker - minValue) * unitSize + canvasLeft),\n Math.round(canvasHeight - canvasHeight / 4),\n options.get('whiskerColor')).append();\n // median line\n target.drawLine(\n Math.round((q2 - minValue) * unitSize + canvasLeft),\n Math.round(canvasHeight * 0.1),\n Math.round((q2 - minValue) * unitSize + canvasLeft),\n Math.round(canvasHeight * 0.9),\n options.get('medianColor')).append();\n if (options.get('target')) {\n size = Math.ceil(options.get('spotRadius'));\n target.drawLine(\n Math.round((options.get('target') - minValue) * unitSize + canvasLeft),\n Math.round((canvasHeight / 2) - size),\n Math.round((options.get('target') - minValue) * unitSize + canvasLeft),\n Math.round((canvasHeight / 2) + size),\n options.get('targetColor')).append();\n target.drawLine(\n Math.round((options.get('target') - minValue) * unitSize + canvasLeft - size),\n Math.round(canvasHeight / 2),\n Math.round((options.get('target') - minValue) * unitSize + canvasLeft + size),\n Math.round(canvasHeight / 2),\n options.get('targetColor')).append();\n }\n target.render();\n }\n });\n\n // Setup a very simple \"virtual canvas\" to make drawing the few shapes we need easier\n // This is accessible as $(foo).simpledraw()\n\n VShape = createClass({\n init: function (target, id, type, args) {\n this.target = target;\n this.id = id;\n this.type = type;\n this.args = args;\n },\n append: function () {\n this.target.appendShape(this);\n return this;\n }\n });\n\n VCanvas_base = createClass({\n _pxregex: /(\\d+)(px)?\\s*$/i,\n\n init: function (width, height, target) {\n if (!width) {\n return;\n }\n this.width = width;\n this.height = height;\n this.target = target;\n this.lastShapeId = null;\n if (target[0]) {\n target = target[0];\n }\n $.data(target, '_jqs_vcanvas', this);\n },\n\n drawLine: function (x1, y1, x2, y2, lineColor, lineWidth) {\n return this.drawShape([[x1, y1], [x2, y2]], lineColor, lineWidth);\n },\n\n drawShape: function (path, lineColor, fillColor, lineWidth) {\n return this._genShape('Shape', [path, lineColor, fillColor, lineWidth]);\n },\n\n drawCircle: function (x, y, radius, lineColor, fillColor, lineWidth) {\n return this._genShape('Circle', [x, y, radius, lineColor, fillColor, lineWidth]);\n },\n\n drawPieSlice: function (x, y, radius, startAngle, endAngle, lineColor, fillColor) {\n return this._genShape('PieSlice', [x, y, radius, startAngle, endAngle, lineColor, fillColor]);\n },\n\n drawRect: function (x, y, width, height, lineColor, fillColor) {\n return this._genShape('Rect', [x, y, width, height, lineColor, fillColor]);\n },\n\n getElement: function () {\n return this.canvas;\n },\n\n /**\n * Return the most recently inserted shape id\n */\n getLastShapeId: function () {\n return this.lastShapeId;\n },\n\n /**\n * Clear and reset the canvas\n */\n reset: function () {\n alert('reset not implemented');\n },\n\n _insert: function (el, target) {\n $(target).html(el);\n },\n\n /**\n * Calculate the pixel dimensions of the canvas\n */\n _calculatePixelDims: function (width, height, canvas) {\n // XXX This should probably be a configurable option\n var match;\n match = this._pxregex.exec(height);\n if (match) {\n this.pixelHeight = match[1];\n } else {\n this.pixelHeight = $(canvas).height();\n }\n match = this._pxregex.exec(width);\n if (match) {\n this.pixelWidth = match[1];\n } else {\n this.pixelWidth = $(canvas).width();\n }\n },\n\n /**\n * Generate a shape object and id for later rendering\n */\n _genShape: function (shapetype, shapeargs) {\n var id = shapeCount++;\n shapeargs.unshift(id);\n return new VShape(this, id, shapetype, shapeargs);\n },\n\n /**\n * Add a shape to the end of the render queue\n */\n appendShape: function (shape) {\n alert('appendShape not implemented');\n },\n\n /**\n * Replace one shape with another\n */\n replaceWithShape: function (shapeid, shape) {\n alert('replaceWithShape not implemented');\n },\n\n /**\n * Insert one shape after another in the render queue\n */\n insertAfterShape: function (shapeid, shape) {\n alert('insertAfterShape not implemented');\n },\n\n /**\n * Remove a shape from the queue\n */\n removeShapeId: function (shapeid) {\n alert('removeShapeId not implemented');\n },\n\n /**\n * Find a shape at the specified x/y co-ordinates\n */\n getShapeAt: function (el, x, y) {\n alert('getShapeAt not implemented');\n },\n\n /**\n * Render all queued shapes onto the canvas\n */\n render: function () {\n alert('render not implemented');\n }\n });\n\n VCanvas_canvas = createClass(VCanvas_base, {\n init: function (width, height, target, interact) {\n VCanvas_canvas._super.init.call(this, width, height, target);\n this.canvas = document.createElement('canvas');\n if (target[0]) {\n target = target[0];\n }\n $.data(target, '_jqs_vcanvas', this);\n $(this.canvas).css({ display: 'inline-block', width: width, height: height, verticalAlign: 'top' });\n this._insert(this.canvas, target);\n this._calculatePixelDims(width, height, this.canvas);\n this.canvas.width = this.pixelWidth;\n this.canvas.height = this.pixelHeight;\n this.interact = interact;\n this.shapes = {};\n this.shapeseq = [];\n this.currentTargetShapeId = undefined;\n $(this.canvas).css({width: this.pixelWidth, height: this.pixelHeight});\n },\n\n _getContext: function (lineColor, fillColor, lineWidth) {\n var context = this.canvas.getContext('2d');\n if (lineColor !== undefined) {\n context.strokeStyle = lineColor;\n }\n context.lineWidth = lineWidth === undefined ? 1 : lineWidth;\n if (fillColor !== undefined) {\n context.fillStyle = fillColor;\n }\n return context;\n },\n\n reset: function () {\n var context = this._getContext();\n context.clearRect(0, 0, this.pixelWidth, this.pixelHeight);\n this.shapes = {};\n this.shapeseq = [];\n this.currentTargetShapeId = undefined;\n },\n\n _drawShape: function (shapeid, path, lineColor, fillColor, lineWidth) {\n var context = this._getContext(lineColor, fillColor, lineWidth),\n i, plen;\n context.beginPath();\n context.moveTo(path[0][0] + 0.5, path[0][1] + 0.5);\n for (i = 1, plen = path.length; i < plen; i++) {\n context.lineTo(path[i][0] + 0.5, path[i][1] + 0.5); // the 0.5 offset gives us crisp pixel-width lines\n }\n if (lineColor !== undefined) {\n context.stroke();\n }\n if (fillColor !== undefined) {\n context.fill();\n }\n if (this.targetX !== undefined && this.targetY !== undefined &&\n context.isPointInPath(this.targetX, this.targetY)) {\n this.currentTargetShapeId = shapeid;\n }\n },\n\n _drawCircle: function (shapeid, x, y, radius, lineColor, fillColor, lineWidth) {\n var context = this._getContext(lineColor, fillColor, lineWidth);\n context.beginPath();\n context.arc(x, y, radius, 0, 2 * Math.PI, false);\n if (this.targetX !== undefined && this.targetY !== undefined &&\n context.isPointInPath(this.targetX, this.targetY)) {\n this.currentTargetShapeId = shapeid;\n }\n if (lineColor !== undefined) {\n context.stroke();\n }\n if (fillColor !== undefined) {\n context.fill();\n }\n },\n\n _drawPieSlice: function (shapeid, x, y, radius, startAngle, endAngle, lineColor, fillColor) {\n var context = this._getContext(lineColor, fillColor);\n context.beginPath();\n context.moveTo(x, y);\n context.arc(x, y, radius, startAngle, endAngle, false);\n context.lineTo(x, y);\n context.closePath();\n if (lineColor !== undefined) {\n context.stroke();\n }\n if (fillColor) {\n context.fill();\n }\n if (this.targetX !== undefined && this.targetY !== undefined &&\n context.isPointInPath(this.targetX, this.targetY)) {\n this.currentTargetShapeId = shapeid;\n }\n },\n\n _drawRect: function (shapeid, x, y, width, height, lineColor, fillColor) {\n return this._drawShape(shapeid, [[x, y], [x + width, y], [x + width, y + height], [x, y + height], [x, y]], lineColor, fillColor);\n },\n\n appendShape: function (shape) {\n this.shapes[shape.id] = shape;\n this.shapeseq.push(shape.id);\n this.lastShapeId = shape.id;\n return shape.id;\n },\n\n replaceWithShape: function (shapeid, shape) {\n var shapeseq = this.shapeseq,\n i;\n this.shapes[shape.id] = shape;\n for (i = shapeseq.length; i--;) {\n if (shapeseq[i] == shapeid) {\n shapeseq[i] = shape.id;\n }\n }\n delete this.shapes[shapeid];\n },\n\n replaceWithShapes: function (shapeids, shapes) {\n var shapeseq = this.shapeseq,\n shapemap = {},\n sid, i, first;\n\n for (i = shapeids.length; i--;) {\n shapemap[shapeids[i]] = true;\n }\n for (i = shapeseq.length; i--;) {\n sid = shapeseq[i];\n if (shapemap[sid]) {\n shapeseq.splice(i, 1);\n delete this.shapes[sid];\n first = i;\n }\n }\n for (i = shapes.length; i--;) {\n shapeseq.splice(first, 0, shapes[i].id);\n this.shapes[shapes[i].id] = shapes[i];\n }\n\n },\n\n insertAfterShape: function (shapeid, shape) {\n var shapeseq = this.shapeseq,\n i;\n for (i = shapeseq.length; i--;) {\n if (shapeseq[i] === shapeid) {\n shapeseq.splice(i + 1, 0, shape.id);\n this.shapes[shape.id] = shape;\n return;\n }\n }\n },\n\n removeShapeId: function (shapeid) {\n var shapeseq = this.shapeseq,\n i;\n for (i = shapeseq.length; i--;) {\n if (shapeseq[i] === shapeid) {\n shapeseq.splice(i, 1);\n break;\n }\n }\n delete this.shapes[shapeid];\n },\n\n getShapeAt: function (el, x, y) {\n this.targetX = x;\n this.targetY = y;\n this.render();\n return this.currentTargetShapeId;\n },\n\n render: function () {\n var shapeseq = this.shapeseq,\n shapes = this.shapes,\n shapeCount = shapeseq.length,\n context = this._getContext(),\n shapeid, shape, i;\n context.clearRect(0, 0, this.pixelWidth, this.pixelHeight);\n for (i = 0; i < shapeCount; i++) {\n shapeid = shapeseq[i];\n shape = shapes[shapeid];\n this['_draw' + shape.type].apply(this, shape.args);\n }\n if (!this.interact) {\n // not interactive so no need to keep the shapes array\n this.shapes = {};\n this.shapeseq = [];\n }\n }\n\n });\n\n VCanvas_vml = createClass(VCanvas_base, {\n init: function (width, height, target) {\n var groupel;\n VCanvas_vml._super.init.call(this, width, height, target);\n if (target[0]) {\n target = target[0];\n }\n $.data(target, '_jqs_vcanvas', this);\n this.canvas = document.createElement('span');\n $(this.canvas).css({ display: 'inline-block', position: 'relative', overflow: 'hidden', width: width, height: height, margin: '0px', padding: '0px', verticalAlign: 'top'});\n this._insert(this.canvas, target);\n this._calculatePixelDims(width, height, this.canvas);\n this.canvas.width = this.pixelWidth;\n this.canvas.height = this.pixelHeight;\n groupel = '';\n this.canvas.insertAdjacentHTML('beforeEnd', groupel);\n this.group = $(this.canvas).children()[0];\n this.rendered = false;\n this.prerender = '';\n },\n\n _drawShape: function (shapeid, path, lineColor, fillColor, lineWidth) {\n var vpath = [],\n initial, stroke, fill, closed, vel, plen, i;\n for (i = 0, plen = path.length; i < plen; i++) {\n vpath[i] = '' + (path[i][0]) + ',' + (path[i][1]);\n }\n initial = vpath.splice(0, 1);\n lineWidth = lineWidth === undefined ? 1 : lineWidth;\n stroke = lineColor === undefined ? ' stroked=\"false\" ' : ' strokeWeight=\"' + lineWidth + 'px\" strokeColor=\"' + lineColor + '\" ';\n fill = fillColor === undefined ? ' filled=\"false\"' : ' fillColor=\"' + fillColor + '\" filled=\"true\" ';\n closed = vpath[0] === vpath[vpath.length - 1] ? 'x ' : '';\n vel = '' +\n ' ';\n return vel;\n },\n\n _drawCircle: function (shapeid, x, y, radius, lineColor, fillColor, lineWidth) {\n var stroke, fill, vel;\n x -= radius;\n y -= radius;\n stroke = lineColor === undefined ? ' stroked=\"false\" ' : ' strokeWeight=\"' + lineWidth + 'px\" strokeColor=\"' + lineColor + '\" ';\n fill = fillColor === undefined ? ' filled=\"false\"' : ' fillColor=\"' + fillColor + '\" filled=\"true\" ';\n vel = '';\n return vel;\n\n },\n\n _drawPieSlice: function (shapeid, x, y, radius, startAngle, endAngle, lineColor, fillColor) {\n var vpath, startx, starty, endx, endy, stroke, fill, vel;\n if (startAngle === endAngle) {\n return ''; // VML seems to have problem when start angle equals end angle.\n }\n if ((endAngle - startAngle) === (2 * Math.PI)) {\n startAngle = 0.0; // VML seems to have a problem when drawing a full circle that doesn't start 0\n endAngle = (2 * Math.PI);\n }\n\n startx = x + Math.round(Math.cos(startAngle) * radius);\n starty = y + Math.round(Math.sin(startAngle) * radius);\n endx = x + Math.round(Math.cos(endAngle) * radius);\n endy = y + Math.round(Math.sin(endAngle) * radius);\n\n if (startx === endx && starty === endy) {\n if ((endAngle - startAngle) < Math.PI) {\n // Prevent very small slices from being mistaken as a whole pie\n return '';\n }\n // essentially going to be the entire circle, so ignore startAngle\n startx = endx = x + radius;\n starty = endy = y;\n }\n\n if (startx === endx && starty === endy && (endAngle - startAngle) < Math.PI) {\n return '';\n }\n\n vpath = [x - radius, y - radius, x + radius, y + radius, startx, starty, endx, endy];\n stroke = lineColor === undefined ? ' stroked=\"false\" ' : ' strokeWeight=\"1px\" strokeColor=\"' + lineColor + '\" ';\n fill = fillColor === undefined ? ' filled=\"false\"' : ' fillColor=\"' + fillColor + '\" filled=\"true\" ';\n vel = '' +\n ' ';\n return vel;\n },\n\n _drawRect: function (shapeid, x, y, width, height, lineColor, fillColor) {\n return this._drawShape(shapeid, [[x, y], [x, y + height], [x + width, y + height], [x + width, y], [x, y]], lineColor, fillColor);\n },\n\n reset: function () {\n this.group.innerHTML = '';\n },\n\n appendShape: function (shape) {\n var vel = this['_draw' + shape.type].apply(this, shape.args);\n if (this.rendered) {\n this.group.insertAdjacentHTML('beforeEnd', vel);\n } else {\n this.prerender += vel;\n }\n this.lastShapeId = shape.id;\n return shape.id;\n },\n\n replaceWithShape: function (shapeid, shape) {\n var existing = $('#jqsshape' + shapeid),\n vel = this['_draw' + shape.type].apply(this, shape.args);\n existing[0].outerHTML = vel;\n },\n\n replaceWithShapes: function (shapeids, shapes) {\n // replace the first shapeid with all the new shapes then toast the remaining old shapes\n var existing = $('#jqsshape' + shapeids[0]),\n replace = '',\n slen = shapes.length,\n i;\n for (i = 0; i < slen; i++) {\n replace += this['_draw' + shapes[i].type].apply(this, shapes[i].args);\n }\n existing[0].outerHTML = replace;\n for (i = 1; i < shapeids.length; i++) {\n $('#jqsshape' + shapeids[i]).remove();\n }\n },\n\n insertAfterShape: function (shapeid, shape) {\n var existing = $('#jqsshape' + shapeid),\n vel = this['_draw' + shape.type].apply(this, shape.args);\n existing[0].insertAdjacentHTML('afterEnd', vel);\n },\n\n removeShapeId: function (shapeid) {\n var existing = $('#jqsshape' + shapeid);\n this.group.removeChild(existing[0]);\n },\n\n getShapeAt: function (el, x, y) {\n var shapeid = el.id.substr(8);\n return shapeid;\n },\n\n render: function () {\n if (!this.rendered) {\n // batch the intial render into a single repaint\n this.group.innerHTML = this.prerender;\n this.rendered = true;\n }\n }\n });\n\n}))}(document, Math));\n", "import './vendor';\nimport 'jquery-sparkline';\nimport { authFetch } from './authWrap';\nimport { error, log } from './logger';\n\ninterface GpuInfo {\n name: string;\n data: Record;\n chart?: [number, number];\n}\n\nlet gpuInterval: ReturnType | null = null;\nconst chartData: { mem: number[]; load: number[] } = { mem: [], load: [] };\n\nasync function updateGPUChart(mem: number, load: number): Promise {\n const maxLen = 120;\n const colorRangeMap = $.range_map({\n '0:5': '#fffafa',\n '6:10': '#fff7ed',\n '11:20': '#fed7aa',\n '21:30': '#fdba74',\n '31:40': '#fb923c',\n '41:50': '#f97316',\n '51:60': '#ea580c',\n '61:70': '#c2410c',\n '71:80': '#9a3412',\n '81:90': '#7c2d12',\n '91:100': '#6c2e12',\n });\n const sparklineConfigLOAD = { type: 'bar', height: '128px', barWidth: '3px', barSpacing: '1px', chartRangeMin: 0, chartRangeMax: 100, barColor: '#89007D' };\n const sparklineConfigMEM = { type: 'bar', height: '128px', barWidth: '3px', barSpacing: '1px', chartRangeMin: 0, chartRangeMax: 100, colorMap: colorRangeMap, composite: true };\n if (chartData.load.length > maxLen) chartData.load.shift();\n chartData.load.push(load);\n if (chartData.mem.length > maxLen) chartData.mem.shift();\n chartData.mem.push(mem);\n $('#gpuChart').sparkline(chartData.load, sparklineConfigLOAD);\n $('#gpuChart').sparkline(chartData.mem, sparklineConfigMEM);\n}\n\nasync function updateGPU(): Promise {\n const gpuEl = document.getElementById('gpu');\n const gpuTable = document.getElementById('gpu-table');\n if (!gpuEl || !gpuTable) return;\n try {\n const res = await authFetch(`${window.api}/gpu-smi`);\n if (!res || !res.ok) {\n clearInterval(gpuInterval);\n gpuEl.style.display = 'none';\n return;\n }\n const data = (await res.json()) as GpuInfo[];\n if (!data) {\n clearInterval(gpuInterval);\n gpuEl.style.display = 'none';\n return;\n }\n const gpuTbody = gpuTable.querySelector('tbody');\n if (!gpuTbody) return;\n let gpu = { data: {} } as GpuInfo;\n if (Array.isArray(data) && data.length >= 1) gpu = data[0];\n let rows = `GPU${gpu.name || 'unknown'}`;\n for (const item of Object.entries(gpu.data)) rows += `${item[0]}${item[1]}`;\n gpuTbody.innerHTML = rows;\n if (gpu.chart && gpu.chart.length === 2) updateGPUChart(gpu.chart[0], gpu.chart[1]);\n gpuEl.style.display = 'block';\n } catch (e) {\n error('updateGPU', e);\n clearInterval(gpuInterval);\n gpuEl.style.display = 'none';\n }\n}\n\nexport async function startGPU(): Promise {\n const gpuEl = document.getElementById('gpu');\n if (!gpuEl) return;\n gpuEl.style.display = 'block';\n if (gpuInterval) clearInterval(gpuInterval);\n const interval = window.opts?.gpu_monitor || 3000;\n log('startGPUmonitor', interval);\n gpuInterval = setInterval(updateGPU, interval);\n updateGPU();\n}\n\nwindow.startGPU = startGPU;\n\nexport async function disableGPU(): Promise {\n clearInterval(gpuInterval);\n const gpuEl = document.getElementById('gpu');\n if (gpuEl) gpuEl.style.display = 'none';\n}\n\nwindow.disableGPU = disableGPU;\n"], - "mappings": "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", - "names": ["global", "window", "i", "jQuery", "arr", "matches", "escape", "value", "document", "dir", "parent", "hash", "preFilter", "token", "find", "elem", "self", "add", "deferred", "process", "error", "data", "el", "nodeName", "types", "event", "name", "schedule", "opts", "index", "length", "timers", "timer", "location", "val", "url", "completed", "done", "method", "type", "undefined", "requestAnimationFrame", "timer", "addEventListener", "el", "log", "event", "iframeId", "location", "hash", "error", "MutationObserver", "options", "isVisible", "$", "e", "t", "i", "n", "s", "r", "a", "o", "l", "h", "u", "c", "f", "d", "K", "$", "eventify", "subject", "validateSubject", "eventsStorage", "createEventsStorage", "registeredEvents", "eventName", "callback", "ctx", "handlers", "callbacks", "fireArguments", "i", "callbackInfo", "reservedWords", "cancelAnimationFrame", "requestAnimationFrame", "isNaN", "parent", "onKeyDown", "el", "jQuery", "el", "url", "user", "token", "authFetch", "url", "event", "authFetch", "el", "isVisible", "el", "el", "el", "event", "el", "el", "event", "el", "el", "authFetch", "el", "gallerySelection", "authFetch", "authFetch", "updateInput", "active", "el", "el", "el", "updateInput", "updateInput", "event", "hash", "atBottom", "el", "authFetch", "parent", "el", "authFetch", "el", "authFetch", "Hash", "HMAC", "hash", "hmac", "authFetch", "ok", "parent", "authFetch", "event", "el", "modalImage", "modal", "gallerySelection", "event", "exifr", "Panzoom", "updateInput", "el", "el", "el", "event", "appendContextMenuOption", "removeContextMenuOption", "addContextMenuEventListener", "busy", "el", "authFetch", "el", "url", "ok", "authFetch", "url", "updateInput", "el", "el", "authFetch", "url", "url", "authFetch", "ts", "authFetch", "el", "delay", "event", "updateInput", "document", "Math", "undefined", "$", "format", "self", "token", "el", "width", "height", "target", "interact", "shapeCount", "authFetch"] + "sourcesContent": ["/*!\n * jQuery JavaScript Library v4.0.0\n * https://jquery.com/\n *\n * Copyright OpenJS Foundation and other contributors\n * Released under the MIT license\n * https://jquery.com/license/\n *\n * Date: 2026-01-18T00:20Z\n */\n( function( global, factory ) {\n\n\t\"use strict\";\n\n\tif ( typeof module === \"object\" && typeof module.exports === \"object\" ) {\n\n\t\t// For CommonJS and CommonJS-like environments where a proper `window`\n\t\t// is present, execute the factory and get jQuery.\n\t\tmodule.exports = factory( global, true );\n\t} else {\n\t\tfactory( global );\n\t}\n\n// Pass this if window is not defined yet\n} )( typeof window !== \"undefined\" ? window : this, function( window, noGlobal ) {\n\n\"use strict\";\n\nif ( !window.document ) {\n\tthrow new Error( \"jQuery requires a window with a document\" );\n}\n\nvar arr = [];\n\nvar getProto = Object.getPrototypeOf;\n\nvar slice = arr.slice;\n\n// Support: IE 11+\n// IE doesn't have Array#flat; provide a fallback.\nvar flat = arr.flat ? function( array ) {\n\treturn arr.flat.call( array );\n} : function( array ) {\n\treturn arr.concat.apply( [], array );\n};\n\nvar push = arr.push;\n\nvar indexOf = arr.indexOf;\n\n// [[Class]] -> type pairs\nvar class2type = {};\n\nvar toString = class2type.toString;\n\nvar hasOwn = class2type.hasOwnProperty;\n\nvar fnToString = hasOwn.toString;\n\nvar ObjectFunctionString = fnToString.call( Object );\n\n// All support tests are defined in their respective modules.\nvar support = {};\n\nfunction toType( obj ) {\n\tif ( obj == null ) {\n\t\treturn obj + \"\";\n\t}\n\n\treturn typeof obj === \"object\" ?\n\t\tclass2type[ toString.call( obj ) ] || \"object\" :\n\t\ttypeof obj;\n}\n\nfunction isWindow( obj ) {\n\treturn obj != null && obj === obj.window;\n}\n\nfunction isArrayLike( obj ) {\n\n\tvar length = !!obj && obj.length,\n\t\ttype = toType( obj );\n\n\tif ( typeof obj === \"function\" || isWindow( obj ) ) {\n\t\treturn false;\n\t}\n\n\treturn type === \"array\" || length === 0 ||\n\t\ttypeof length === \"number\" && length > 0 && ( length - 1 ) in obj;\n}\n\nvar document$1 = window.document;\n\nvar preservedScriptAttributes = {\n\ttype: true,\n\tsrc: true,\n\tnonce: true,\n\tnoModule: true\n};\n\nfunction DOMEval( code, node, doc ) {\n\tdoc = doc || document$1;\n\n\tvar i,\n\t\tscript = doc.createElement( \"script\" );\n\n\tscript.text = code;\n\tfor ( i in preservedScriptAttributes ) {\n\t\tif ( node && node[ i ] ) {\n\t\t\tscript[ i ] = node[ i ];\n\t\t}\n\t}\n\n\tif ( doc.head.appendChild( script ).parentNode ) {\n\t\tscript.parentNode.removeChild( script );\n\t}\n}\n\nvar version = \"4.0.0\",\n\n\trhtmlSuffix = /HTML$/i,\n\n\t// Define a local copy of jQuery\n\tjQuery = function( selector, context ) {\n\n\t\t// The jQuery object is actually just the init constructor 'enhanced'\n\t\t// Need init if jQuery is called (just allow error to be thrown if not included)\n\t\treturn new jQuery.fn.init( selector, context );\n\t};\n\njQuery.fn = jQuery.prototype = {\n\n\t// The current version of jQuery being used\n\tjquery: version,\n\n\tconstructor: jQuery,\n\n\t// The default length of a jQuery object is 0\n\tlength: 0,\n\n\ttoArray: function() {\n\t\treturn slice.call( this );\n\t},\n\n\t// Get the Nth element in the matched element set OR\n\t// Get the whole matched element set as a clean array\n\tget: function( num ) {\n\n\t\t// Return all the elements in a clean array\n\t\tif ( num == null ) {\n\t\t\treturn slice.call( this );\n\t\t}\n\n\t\t// Return just the one element from the set\n\t\treturn num < 0 ? this[ num + this.length ] : this[ num ];\n\t},\n\n\t// Take an array of elements and push it onto the stack\n\t// (returning the new matched element set)\n\tpushStack: function( elems ) {\n\n\t\t// Build a new jQuery matched element set\n\t\tvar ret = jQuery.merge( this.constructor(), elems );\n\n\t\t// Add the old object onto the stack (as a reference)\n\t\tret.prevObject = this;\n\n\t\t// Return the newly-formed element set\n\t\treturn ret;\n\t},\n\n\t// Execute a callback for every element in the matched set.\n\teach: function( callback ) {\n\t\treturn jQuery.each( this, callback );\n\t},\n\n\tmap: function( callback ) {\n\t\treturn this.pushStack( jQuery.map( this, function( elem, i ) {\n\t\t\treturn callback.call( elem, i, elem );\n\t\t} ) );\n\t},\n\n\tslice: function() {\n\t\treturn this.pushStack( slice.apply( this, arguments ) );\n\t},\n\n\tfirst: function() {\n\t\treturn this.eq( 0 );\n\t},\n\n\tlast: function() {\n\t\treturn this.eq( -1 );\n\t},\n\n\teven: function() {\n\t\treturn this.pushStack( jQuery.grep( this, function( _elem, i ) {\n\t\t\treturn ( i + 1 ) % 2;\n\t\t} ) );\n\t},\n\n\todd: function() {\n\t\treturn this.pushStack( jQuery.grep( this, function( _elem, i ) {\n\t\t\treturn i % 2;\n\t\t} ) );\n\t},\n\n\teq: function( i ) {\n\t\tvar len = this.length,\n\t\t\tj = +i + ( i < 0 ? len : 0 );\n\t\treturn this.pushStack( j >= 0 && j < len ? [ this[ j ] ] : [] );\n\t},\n\n\tend: function() {\n\t\treturn this.prevObject || this.constructor();\n\t}\n};\n\njQuery.extend = jQuery.fn.extend = function() {\n\tvar options, name, src, copy, copyIsArray, clone,\n\t\ttarget = arguments[ 0 ] || {},\n\t\ti = 1,\n\t\tlength = arguments.length,\n\t\tdeep = false;\n\n\t// Handle a deep copy situation\n\tif ( typeof target === \"boolean\" ) {\n\t\tdeep = target;\n\n\t\t// Skip the boolean and the target\n\t\ttarget = arguments[ i ] || {};\n\t\ti++;\n\t}\n\n\t// Handle case when target is a string or something (possible in deep copy)\n\tif ( typeof target !== \"object\" && typeof target !== \"function\" ) {\n\t\ttarget = {};\n\t}\n\n\t// Extend jQuery itself if only one argument is passed\n\tif ( i === length ) {\n\t\ttarget = this;\n\t\ti--;\n\t}\n\n\tfor ( ; i < length; i++ ) {\n\n\t\t// Only deal with non-null/undefined values\n\t\tif ( ( options = arguments[ i ] ) != null ) {\n\n\t\t\t// Extend the base object\n\t\t\tfor ( name in options ) {\n\t\t\t\tcopy = options[ name ];\n\n\t\t\t\t// Prevent Object.prototype pollution\n\t\t\t\t// Prevent never-ending loop\n\t\t\t\tif ( name === \"__proto__\" || target === copy ) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\t// Recurse if we're merging plain objects or arrays\n\t\t\t\tif ( deep && copy && ( jQuery.isPlainObject( copy ) ||\n\t\t\t\t\t( copyIsArray = Array.isArray( copy ) ) ) ) {\n\t\t\t\t\tsrc = target[ name ];\n\n\t\t\t\t\t// Ensure proper type for the source value\n\t\t\t\t\tif ( copyIsArray && !Array.isArray( src ) ) {\n\t\t\t\t\t\tclone = [];\n\t\t\t\t\t} else if ( !copyIsArray && !jQuery.isPlainObject( src ) ) {\n\t\t\t\t\t\tclone = {};\n\t\t\t\t\t} else {\n\t\t\t\t\t\tclone = src;\n\t\t\t\t\t}\n\t\t\t\t\tcopyIsArray = false;\n\n\t\t\t\t\t// Never move original objects, clone them\n\t\t\t\t\ttarget[ name ] = jQuery.extend( deep, clone, copy );\n\n\t\t\t\t// Don't bring in undefined values\n\t\t\t\t} else if ( copy !== undefined ) {\n\t\t\t\t\ttarget[ name ] = copy;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// Return the modified object\n\treturn target;\n};\n\njQuery.extend( {\n\n\t// Unique for each copy of jQuery on the page\n\texpando: \"jQuery\" + ( version + Math.random() ).replace( /\\D/g, \"\" ),\n\n\t// Assume jQuery is ready without the ready module\n\tisReady: true,\n\n\terror: function( msg ) {\n\t\tthrow new Error( msg );\n\t},\n\n\tnoop: function() {},\n\n\tisPlainObject: function( obj ) {\n\t\tvar proto, Ctor;\n\n\t\t// Detect obvious negatives\n\t\t// Use toString instead of jQuery.type to catch host objects\n\t\tif ( !obj || toString.call( obj ) !== \"[object Object]\" ) {\n\t\t\treturn false;\n\t\t}\n\n\t\tproto = getProto( obj );\n\n\t\t// Objects with no prototype (e.g., `Object.create( null )`) are plain\n\t\tif ( !proto ) {\n\t\t\treturn true;\n\t\t}\n\n\t\t// Objects with prototype are plain iff they were constructed by a global Object function\n\t\tCtor = hasOwn.call( proto, \"constructor\" ) && proto.constructor;\n\t\treturn typeof Ctor === \"function\" && fnToString.call( Ctor ) === ObjectFunctionString;\n\t},\n\n\tisEmptyObject: function( obj ) {\n\t\tvar name;\n\n\t\tfor ( name in obj ) {\n\t\t\treturn false;\n\t\t}\n\t\treturn true;\n\t},\n\n\t// Evaluates a script in a provided context; falls back to the global one\n\t// if not specified.\n\tglobalEval: function( code, options, doc ) {\n\t\tDOMEval( code, { nonce: options && options.nonce }, doc );\n\t},\n\n\teach: function( obj, callback ) {\n\t\tvar length, i = 0;\n\n\t\tif ( isArrayLike( obj ) ) {\n\t\t\tlength = obj.length;\n\t\t\tfor ( ; i < length; i++ ) {\n\t\t\t\tif ( callback.call( obj[ i ], i, obj[ i ] ) === false ) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tfor ( i in obj ) {\n\t\t\t\tif ( callback.call( obj[ i ], i, obj[ i ] ) === false ) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn obj;\n\t},\n\n\n\t// Retrieve the text value of an array of DOM nodes\n\ttext: function( elem ) {\n\t\tvar node,\n\t\t\tret = \"\",\n\t\t\ti = 0,\n\t\t\tnodeType = elem.nodeType;\n\n\t\tif ( !nodeType ) {\n\n\t\t\t// If no nodeType, this is expected to be an array\n\t\t\twhile ( ( node = elem[ i++ ] ) ) {\n\n\t\t\t\t// Do not traverse comment nodes\n\t\t\t\tret += jQuery.text( node );\n\t\t\t}\n\t\t}\n\t\tif ( nodeType === 1 || nodeType === 11 ) {\n\t\t\treturn elem.textContent;\n\t\t}\n\t\tif ( nodeType === 9 ) {\n\t\t\treturn elem.documentElement.textContent;\n\t\t}\n\t\tif ( nodeType === 3 || nodeType === 4 ) {\n\t\t\treturn elem.nodeValue;\n\t\t}\n\n\t\t// Do not include comment or processing instruction nodes\n\n\t\treturn ret;\n\t},\n\n\n\t// results is for internal usage only\n\tmakeArray: function( arr, results ) {\n\t\tvar ret = results || [];\n\n\t\tif ( arr != null ) {\n\t\t\tif ( isArrayLike( Object( arr ) ) ) {\n\t\t\t\tjQuery.merge( ret,\n\t\t\t\t\ttypeof arr === \"string\" ?\n\t\t\t\t\t\t[ arr ] : arr\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\tpush.call( ret, arr );\n\t\t\t}\n\t\t}\n\n\t\treturn ret;\n\t},\n\n\tinArray: function( elem, arr, i ) {\n\t\treturn arr == null ? -1 : indexOf.call( arr, elem, i );\n\t},\n\n\tisXMLDoc: function( elem ) {\n\t\tvar namespace = elem && elem.namespaceURI,\n\t\t\tdocElem = elem && ( elem.ownerDocument || elem ).documentElement;\n\n\t\t// Assume HTML when documentElement doesn't yet exist, such as inside\n\t\t// document fragments.\n\t\treturn !rhtmlSuffix.test( namespace || docElem && docElem.nodeName || \"HTML\" );\n\t},\n\n\t// Note: an element does not contain itself\n\tcontains: function( a, b ) {\n\t\tvar bup = b && b.parentNode;\n\n\t\treturn a === bup || !!( bup && bup.nodeType === 1 && (\n\n\t\t\t// Support: IE 9 - 11+\n\t\t\t// IE doesn't have `contains` on SVG.\n\t\t\ta.contains ?\n\t\t\t\ta.contains( bup ) :\n\t\t\t\ta.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16\n\t\t) );\n\t},\n\n\tmerge: function( first, second ) {\n\t\tvar len = +second.length,\n\t\t\tj = 0,\n\t\t\ti = first.length;\n\n\t\tfor ( ; j < len; j++ ) {\n\t\t\tfirst[ i++ ] = second[ j ];\n\t\t}\n\n\t\tfirst.length = i;\n\n\t\treturn first;\n\t},\n\n\tgrep: function( elems, callback, invert ) {\n\t\tvar callbackInverse,\n\t\t\tmatches = [],\n\t\t\ti = 0,\n\t\t\tlength = elems.length,\n\t\t\tcallbackExpect = !invert;\n\n\t\t// Go through the array, only saving the items\n\t\t// that pass the validator function\n\t\tfor ( ; i < length; i++ ) {\n\t\t\tcallbackInverse = !callback( elems[ i ], i );\n\t\t\tif ( callbackInverse !== callbackExpect ) {\n\t\t\t\tmatches.push( elems[ i ] );\n\t\t\t}\n\t\t}\n\n\t\treturn matches;\n\t},\n\n\t// arg is for internal usage only\n\tmap: function( elems, callback, arg ) {\n\t\tvar length, value,\n\t\t\ti = 0,\n\t\t\tret = [];\n\n\t\t// Go through the array, translating each of the items to their new values\n\t\tif ( isArrayLike( elems ) ) {\n\t\t\tlength = elems.length;\n\t\t\tfor ( ; i < length; i++ ) {\n\t\t\t\tvalue = callback( elems[ i ], i, arg );\n\n\t\t\t\tif ( value != null ) {\n\t\t\t\t\tret.push( value );\n\t\t\t\t}\n\t\t\t}\n\n\t\t// Go through every key on the object,\n\t\t} else {\n\t\t\tfor ( i in elems ) {\n\t\t\t\tvalue = callback( elems[ i ], i, arg );\n\n\t\t\t\tif ( value != null ) {\n\t\t\t\t\tret.push( value );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Flatten any nested arrays\n\t\treturn flat( ret );\n\t},\n\n\t// A global GUID counter for objects\n\tguid: 1,\n\n\t// jQuery.support is not used in Core but other projects attach their\n\t// properties to it so it needs to exist.\n\tsupport: support\n} );\n\nif ( typeof Symbol === \"function\" ) {\n\tjQuery.fn[ Symbol.iterator ] = arr[ Symbol.iterator ];\n}\n\n// Populate the class2type map\njQuery.each( \"Boolean Number String Function Array Date RegExp Object Error Symbol\".split( \" \" ),\n\tfunction( _i, name ) {\n\t\tclass2type[ \"[object \" + name + \"]\" ] = name.toLowerCase();\n\t} );\n\nfunction nodeName( elem, name ) {\n\treturn elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase();\n}\n\nvar pop = arr.pop;\n\n// https://www.w3.org/TR/css3-selectors/#whitespace\nvar whitespace = \"[\\\\x20\\\\t\\\\r\\\\n\\\\f]\";\n\nvar isIE = document$1.documentMode;\n\nvar rbuggyQSA = isIE && new RegExp(\n\n\t// Support: IE 9 - 11+\n\t// IE's :disabled selector does not pick up the children of disabled fieldsets\n\t\":enabled|:disabled|\" +\n\n\t// Support: IE 11+\n\t// IE 11 doesn't find elements on a `[name='']` query in some cases.\n\t// Adding a temporary attribute to the document before the selection works\n\t// around the issue.\n\t\"\\\\[\" + whitespace + \"*name\" + whitespace + \"*=\" +\n\twhitespace + \"*(?:''|\\\"\\\")\"\n\n);\n\nvar rtrimCSS = new RegExp(\n\t\"^\" + whitespace + \"+|((?:^|[^\\\\\\\\])(?:\\\\\\\\.)*)\" + whitespace + \"+$\",\n\t\"g\"\n);\n\n// https://www.w3.org/TR/css-syntax-3/#ident-token-diagram\nvar identifier = \"(?:\\\\\\\\[\\\\da-fA-F]{1,6}\" + whitespace +\n\t\"?|\\\\\\\\[^\\\\r\\\\n\\\\f]|[\\\\w-]|[^\\0-\\\\x7f])+\";\n\nvar rleadingCombinator = new RegExp( \"^\" + whitespace + \"*([>+~]|\" +\n\twhitespace + \")\" + whitespace + \"*\" );\n\nvar rdescend = new RegExp( whitespace + \"|>\" );\n\nvar rsibling = /[+~]/;\n\nvar documentElement$1 = document$1.documentElement;\n\n// Support: IE 9 - 11+\n// IE requires a prefix.\nvar matches = documentElement$1.matches || documentElement$1.msMatchesSelector;\n\n/**\n * Create key-value caches of limited size\n * @returns {function(string, object)} Returns the Object data after storing it on itself with\n *\tproperty name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength)\n *\tdeleting the oldest entry\n */\nfunction createCache() {\n\tvar keys = [];\n\n\tfunction cache( key, value ) {\n\n\t\t// Use (key + \" \") to avoid collision with native prototype properties\n\t\t// (see https://github.com/jquery/sizzle/issues/157)\n\t\tif ( keys.push( key + \" \" ) > jQuery.expr.cacheLength ) {\n\n\t\t\t// Only keep the most recent entries\n\t\t\tdelete cache[ keys.shift() ];\n\t\t}\n\t\treturn ( cache[ key + \" \" ] = value );\n\t}\n\treturn cache;\n}\n\n/**\n * Checks a node for validity as a jQuery selector context\n * @param {Element|Object=} context\n * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value\n */\nfunction testContext( context ) {\n\treturn context && typeof context.getElementsByTagName !== \"undefined\" && context;\n}\n\n// Attribute selectors: https://www.w3.org/TR/selectors/#attribute-selectors\nvar attributes = \"\\\\[\" + whitespace + \"*(\" + identifier + \")(?:\" + whitespace +\n\n\t// Operator (capture 2)\n\t\"*([*^$|!~]?=)\" + whitespace +\n\n\t// \"Attribute values must be CSS identifiers [capture 5] or strings [capture 3 or capture 4]\"\n\t\"*(?:'((?:\\\\\\\\.|[^\\\\\\\\'])*)'|\\\"((?:\\\\\\\\.|[^\\\\\\\\\\\"])*)\\\"|(\" + identifier + \"))|)\" +\n\twhitespace + \"*\\\\]\";\n\nvar pseudos = \":(\" + identifier + \")(?:\\\\((\" +\n\n\t// To reduce the number of selectors needing tokenize in the preFilter, prefer arguments:\n\t// 1. quoted (capture 3; capture 4 or capture 5)\n\t\"('((?:\\\\\\\\.|[^\\\\\\\\'])*)'|\\\"((?:\\\\\\\\.|[^\\\\\\\\\\\"])*)\\\")|\" +\n\n\t// 2. simple (capture 6)\n\t\"((?:\\\\\\\\.|[^\\\\\\\\()[\\\\]]|\" + attributes + \")*)|\" +\n\n\t// 3. anything else (capture 2)\n\t\".*\" +\n\t\")\\\\)|)\";\n\nvar filterMatchExpr = {\n\tID: new RegExp( \"^#(\" + identifier + \")\" ),\n\tCLASS: new RegExp( \"^\\\\.(\" + identifier + \")\" ),\n\tTAG: new RegExp( \"^(\" + identifier + \"|[*])\" ),\n\tATTR: new RegExp( \"^\" + attributes ),\n\tPSEUDO: new RegExp( \"^\" + pseudos ),\n\tCHILD: new RegExp(\n\t\t\"^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\\\(\" +\n\t\twhitespace + \"*(even|odd|(([+-]|)(\\\\d*)n|)\" + whitespace + \"*(?:([+-]|)\" +\n\t\twhitespace + \"*(\\\\d+)|))\" + whitespace + \"*\\\\)|)\", \"i\" )\n};\n\nvar rpseudo = new RegExp( pseudos );\n\n// CSS escapes\n// https://www.w3.org/TR/CSS21/syndata.html#escaped-characters\n\nvar runescape = new RegExp( \"\\\\\\\\[\\\\da-fA-F]{1,6}\" + whitespace +\n\t\"?|\\\\\\\\([^\\\\r\\\\n\\\\f])\", \"g\" ),\n\tfunescape = function( escape, nonHex ) {\n\t\tvar high = \"0x\" + escape.slice( 1 ) - 0x10000;\n\n\t\tif ( nonHex ) {\n\n\t\t\t// Strip the backslash prefix from a non-hex escape sequence\n\t\t\treturn nonHex;\n\t\t}\n\n\t\t// Replace a hexadecimal escape sequence with the encoded Unicode code point\n\t\t// Support: IE <=11+\n\t\t// For values outside the Basic Multilingual Plane (BMP), manually construct a\n\t\t// surrogate pair\n\t\treturn high < 0 ?\n\t\t\tString.fromCharCode( high + 0x10000 ) :\n\t\t\tString.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 );\n\t};\n\nfunction unescapeSelector( sel ) {\n\treturn sel.replace( runescape, funescape );\n}\n\nfunction selectorError( msg ) {\n\tjQuery.error( \"Syntax error, unrecognized expression: \" + msg );\n}\n\nvar rcomma = new RegExp( \"^\" + whitespace + \"*,\" + whitespace + \"*\" );\n\nvar tokenCache = createCache();\n\nfunction tokenize( selector, parseOnly ) {\n\tvar matched, match, tokens, type,\n\t\tsoFar, groups, preFilters,\n\t\tcached = tokenCache[ selector + \" \" ];\n\n\tif ( cached ) {\n\t\treturn parseOnly ? 0 : cached.slice( 0 );\n\t}\n\n\tsoFar = selector;\n\tgroups = [];\n\tpreFilters = jQuery.expr.preFilter;\n\n\twhile ( soFar ) {\n\n\t\t// Comma and first run\n\t\tif ( !matched || ( match = rcomma.exec( soFar ) ) ) {\n\t\t\tif ( match ) {\n\n\t\t\t\t// Don't consume trailing commas as valid\n\t\t\t\tsoFar = soFar.slice( match[ 0 ].length ) || soFar;\n\t\t\t}\n\t\t\tgroups.push( ( tokens = [] ) );\n\t\t}\n\n\t\tmatched = false;\n\n\t\t// Combinators\n\t\tif ( ( match = rleadingCombinator.exec( soFar ) ) ) {\n\t\t\tmatched = match.shift();\n\t\t\ttokens.push( {\n\t\t\t\tvalue: matched,\n\n\t\t\t\t// Cast descendant combinators to space\n\t\t\t\ttype: match[ 0 ].replace( rtrimCSS, \" \" )\n\t\t\t} );\n\t\t\tsoFar = soFar.slice( matched.length );\n\t\t}\n\n\t\t// Filters\n\t\tfor ( type in filterMatchExpr ) {\n\t\t\tif ( ( match = jQuery.expr.match[ type ].exec( soFar ) ) && ( !preFilters[ type ] ||\n\t\t\t\t( match = preFilters[ type ]( match ) ) ) ) {\n\t\t\t\tmatched = match.shift();\n\t\t\t\ttokens.push( {\n\t\t\t\t\tvalue: matched,\n\t\t\t\t\ttype: type,\n\t\t\t\t\tmatches: match\n\t\t\t\t} );\n\t\t\t\tsoFar = soFar.slice( matched.length );\n\t\t\t}\n\t\t}\n\n\t\tif ( !matched ) {\n\t\t\tbreak;\n\t\t}\n\t}\n\n\t// Return the length of the invalid excess\n\t// if we're just parsing\n\t// Otherwise, throw an error or return tokens\n\tif ( parseOnly ) {\n\t\treturn soFar.length;\n\t}\n\n\treturn soFar ?\n\t\tselectorError( selector ) :\n\n\t\t// Cache the tokens\n\t\ttokenCache( selector, groups ).slice( 0 );\n}\n\nvar preFilter = {\n\tATTR: function( match ) {\n\t\tmatch[ 1 ] = unescapeSelector( match[ 1 ] );\n\n\t\t// Move the given value to match[3] whether quoted or unquoted\n\t\tmatch[ 3 ] = unescapeSelector( match[ 3 ] || match[ 4 ] || match[ 5 ] || \"\" );\n\n\t\tif ( match[ 2 ] === \"~=\" ) {\n\t\t\tmatch[ 3 ] = \" \" + match[ 3 ] + \" \";\n\t\t}\n\n\t\treturn match.slice( 0, 4 );\n\t},\n\n\tCHILD: function( match ) {\n\n\t\t/* matches from filterMatchExpr[\"CHILD\"]\n\t\t\t1 type (only|nth|...)\n\t\t\t2 what (child|of-type)\n\t\t\t3 argument (even|odd|\\d*|\\d*n([+-]\\d+)?|...)\n\t\t\t4 xn-component of xn+y argument ([+-]?\\d*n|)\n\t\t\t5 sign of xn-component\n\t\t\t6 x of xn-component\n\t\t\t7 sign of y-component\n\t\t\t8 y of y-component\n\t\t*/\n\t\tmatch[ 1 ] = match[ 1 ].toLowerCase();\n\n\t\tif ( match[ 1 ].slice( 0, 3 ) === \"nth\" ) {\n\n\t\t\t// nth-* requires argument\n\t\t\tif ( !match[ 3 ] ) {\n\t\t\t\tselectorError( match[ 0 ] );\n\t\t\t}\n\n\t\t\t// numeric x and y parameters for jQuery.expr.filter.CHILD\n\t\t\t// remember that false/true cast respectively to 0/1\n\t\t\tmatch[ 4 ] = +( match[ 4 ] ?\n\t\t\t\tmatch[ 5 ] + ( match[ 6 ] || 1 ) :\n\t\t\t\t2 * ( match[ 3 ] === \"even\" || match[ 3 ] === \"odd\" )\n\t\t\t);\n\t\t\tmatch[ 5 ] = +( ( match[ 7 ] + match[ 8 ] ) || match[ 3 ] === \"odd\" );\n\n\t\t// other types prohibit arguments\n\t\t} else if ( match[ 3 ] ) {\n\t\t\tselectorError( match[ 0 ] );\n\t\t}\n\n\t\treturn match;\n\t},\n\n\tPSEUDO: function( match ) {\n\t\tvar excess,\n\t\t\tunquoted = !match[ 6 ] && match[ 2 ];\n\n\t\tif ( filterMatchExpr.CHILD.test( match[ 0 ] ) ) {\n\t\t\treturn null;\n\t\t}\n\n\t\t// Accept quoted arguments as-is\n\t\tif ( match[ 3 ] ) {\n\t\t\tmatch[ 2 ] = match[ 4 ] || match[ 5 ] || \"\";\n\n\t\t// Strip excess characters from unquoted arguments\n\t\t} else if ( unquoted && rpseudo.test( unquoted ) &&\n\n\t\t\t// Get excess from tokenize (recursively)\n\t\t\t( excess = tokenize( unquoted, true ) ) &&\n\n\t\t\t// advance to the next closing parenthesis\n\t\t\t( excess = unquoted.indexOf( \")\", unquoted.length - excess ) -\n\t\t\t\tunquoted.length ) ) {\n\n\t\t\t// excess is a negative index\n\t\t\tmatch[ 0 ] = match[ 0 ].slice( 0, excess );\n\t\t\tmatch[ 2 ] = unquoted.slice( 0, excess );\n\t\t}\n\n\t\t// Return only captures needed by the pseudo filter method (type and argument)\n\t\treturn match.slice( 0, 3 );\n\t}\n};\n\nfunction toSelector( tokens ) {\n\tvar i = 0,\n\t\tlen = tokens.length,\n\t\tselector = \"\";\n\tfor ( ; i < len; i++ ) {\n\t\tselector += tokens[ i ].value;\n\t}\n\treturn selector;\n}\n\n// Multifunctional method to get and set values of a collection\n// The value/s can optionally be executed if it's a function\nfunction access( elems, fn, key, value, chainable, emptyGet, raw ) {\n\tvar i = 0,\n\t\tlen = elems.length,\n\t\tbulk = key == null;\n\n\t// Sets many values\n\tif ( toType( key ) === \"object\" ) {\n\t\tchainable = true;\n\t\tfor ( i in key ) {\n\t\t\taccess( elems, fn, i, key[ i ], true, emptyGet, raw );\n\t\t}\n\n\t// Sets one value\n\t} else if ( value !== undefined ) {\n\t\tchainable = true;\n\n\t\tif ( typeof value !== \"function\" ) {\n\t\t\traw = true;\n\t\t}\n\n\t\tif ( bulk ) {\n\n\t\t\t// Bulk operations run against the entire set\n\t\t\tif ( raw ) {\n\t\t\t\tfn.call( elems, value );\n\t\t\t\tfn = null;\n\n\t\t\t// ...except when executing function values\n\t\t\t} else {\n\t\t\t\tbulk = fn;\n\t\t\t\tfn = function( elem, _key, value ) {\n\t\t\t\t\treturn bulk.call( jQuery( elem ), value );\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\n\t\tif ( fn ) {\n\t\t\tfor ( ; i < len; i++ ) {\n\t\t\t\tfn(\n\t\t\t\t\telems[ i ], key, raw ?\n\t\t\t\t\t\tvalue :\n\t\t\t\t\t\tvalue.call( elems[ i ], i, fn( elems[ i ], key ) )\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\tif ( chainable ) {\n\t\treturn elems;\n\t}\n\n\t// Gets\n\tif ( bulk ) {\n\t\treturn fn.call( elems );\n\t}\n\n\treturn len ? fn( elems[ 0 ], key ) : emptyGet;\n}\n\n// Only count HTML whitespace\n// Other whitespace should count in values\n// https://infra.spec.whatwg.org/#ascii-whitespace\nvar rnothtmlwhite = /[^\\x20\\t\\r\\n\\f]+/g;\n\njQuery.fn.extend( {\n\tattr: function( name, value ) {\n\t\treturn access( this, jQuery.attr, name, value, arguments.length > 1 );\n\t},\n\n\tremoveAttr: function( name ) {\n\t\treturn this.each( function() {\n\t\t\tjQuery.removeAttr( this, name );\n\t\t} );\n\t}\n} );\n\njQuery.extend( {\n\tattr: function( elem, name, value ) {\n\t\tvar ret, hooks,\n\t\t\tnType = elem.nodeType;\n\n\t\t// Don't get/set attributes on text, comment and attribute nodes\n\t\tif ( nType === 3 || nType === 8 || nType === 2 ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Fallback to prop when attributes are not supported\n\t\tif ( typeof elem.getAttribute === \"undefined\" ) {\n\t\t\treturn jQuery.prop( elem, name, value );\n\t\t}\n\n\t\t// Attribute hooks are determined by the lowercase version\n\t\t// Grab necessary hook if one is defined\n\t\tif ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) {\n\t\t\thooks = jQuery.attrHooks[ name.toLowerCase() ];\n\t\t}\n\n\t\tif ( value !== undefined ) {\n\t\t\tif ( value === null ||\n\n\t\t\t\t// For compat with previous handling of boolean attributes,\n\t\t\t\t// remove when `false` passed. For ARIA attributes -\n\t\t\t\t// many of which recognize a `\"false\"` value - continue to\n\t\t\t\t// set the `\"false\"` value as jQuery <4 did.\n\t\t\t\t( value === false && name.toLowerCase().indexOf( \"aria-\" ) !== 0 ) ) {\n\n\t\t\t\tjQuery.removeAttr( elem, name );\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif ( hooks && \"set\" in hooks &&\n\t\t\t\t( ret = hooks.set( elem, value, name ) ) !== undefined ) {\n\t\t\t\treturn ret;\n\t\t\t}\n\n\t\t\telem.setAttribute( name, value );\n\t\t\treturn value;\n\t\t}\n\n\t\tif ( hooks && \"get\" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) {\n\t\t\treturn ret;\n\t\t}\n\n\t\tret = elem.getAttribute( name );\n\n\t\t// Non-existent attributes return null, we normalize to undefined\n\t\treturn ret == null ? undefined : ret;\n\t},\n\n\tattrHooks: {},\n\n\tremoveAttr: function( elem, value ) {\n\t\tvar name,\n\t\t\ti = 0,\n\n\t\t\t// Attribute names can contain non-HTML whitespace characters\n\t\t\t// https://html.spec.whatwg.org/multipage/syntax.html#attributes-2\n\t\t\tattrNames = value && value.match( rnothtmlwhite );\n\n\t\tif ( attrNames && elem.nodeType === 1 ) {\n\t\t\twhile ( ( name = attrNames[ i++ ] ) ) {\n\t\t\t\telem.removeAttribute( name );\n\t\t\t}\n\t\t}\n\t}\n} );\n\n// Support: IE <=11+\n// An input loses its value after becoming a radio\nif ( isIE ) {\n\tjQuery.attrHooks.type = {\n\t\tset: function( elem, value ) {\n\t\t\tif ( value === \"radio\" && nodeName( elem, \"input\" ) ) {\n\t\t\t\tvar val = elem.value;\n\t\t\t\telem.setAttribute( \"type\", value );\n\t\t\t\tif ( val ) {\n\t\t\t\t\telem.value = val;\n\t\t\t\t}\n\t\t\t\treturn value;\n\t\t\t}\n\t\t}\n\t};\n}\n\n// CSS string/identifier serialization\n// https://drafts.csswg.org/cssom/#common-serializing-idioms\nvar rcssescape = /([\\0-\\x1f\\x7f]|^-?\\d)|^-$|[^\\x80-\\uFFFF\\w-]/g;\n\nfunction fcssescape( ch, asCodePoint ) {\n\tif ( asCodePoint ) {\n\n\t\t// U+0000 NULL becomes U+FFFD REPLACEMENT CHARACTER\n\t\tif ( ch === \"\\0\" ) {\n\t\t\treturn \"\\uFFFD\";\n\t\t}\n\n\t\t// Control characters and (dependent upon position) numbers get escaped as code points\n\t\treturn ch.slice( 0, -1 ) + \"\\\\\" + ch.charCodeAt( ch.length - 1 ).toString( 16 ) + \" \";\n\t}\n\n\t// Other potentially-special ASCII characters get backslash-escaped\n\treturn \"\\\\\" + ch;\n}\n\njQuery.escapeSelector = function( sel ) {\n\treturn ( sel + \"\" ).replace( rcssescape, fcssescape );\n};\n\nvar sort = arr.sort;\n\nvar splice = arr.splice;\n\nvar hasDuplicate;\n\n// Document order sorting\nfunction sortOrder( a, b ) {\n\n\t// Flag for duplicate removal\n\tif ( a === b ) {\n\t\thasDuplicate = true;\n\t\treturn 0;\n\t}\n\n\t// Sort on method existence if only one input has compareDocumentPosition\n\tvar compare = !a.compareDocumentPosition - !b.compareDocumentPosition;\n\tif ( compare ) {\n\t\treturn compare;\n\t}\n\n\t// Calculate position if both inputs belong to the same document\n\t// Support: IE 11+\n\t// IE sometimes throws a \"Permission denied\" error when strict-comparing\n\t// two documents; shallow comparisons work.\n\t// eslint-disable-next-line eqeqeq\n\tcompare = ( a.ownerDocument || a ) == ( b.ownerDocument || b ) ?\n\t\ta.compareDocumentPosition( b ) :\n\n\t\t// Otherwise we know they are disconnected\n\t\t1;\n\n\t// Disconnected nodes\n\tif ( compare & 1 ) {\n\n\t\t// Choose the first element that is related to the document\n\t\t// Support: IE 11+\n\t\t// IE sometimes throws a \"Permission denied\" error when strict-comparing\n\t\t// two documents; shallow comparisons work.\n\t\t// eslint-disable-next-line eqeqeq\n\t\tif ( a == document$1 || a.ownerDocument == document$1 &&\n\t\t\tjQuery.contains( document$1, a ) ) {\n\t\t\treturn -1;\n\t\t}\n\n\t\t// Support: IE 11+\n\t\t// IE sometimes throws a \"Permission denied\" error when strict-comparing\n\t\t// two documents; shallow comparisons work.\n\t\t// eslint-disable-next-line eqeqeq\n\t\tif ( b == document$1 || b.ownerDocument == document$1 &&\n\t\t\tjQuery.contains( document$1, b ) ) {\n\t\t\treturn 1;\n\t\t}\n\n\t\t// Maintain original order\n\t\treturn 0;\n\t}\n\n\treturn compare & 4 ? -1 : 1;\n}\n\n/**\n * Document sorting and removing duplicates\n * @param {ArrayLike} results\n */\njQuery.uniqueSort = function( results ) {\n\tvar elem,\n\t\tduplicates = [],\n\t\tj = 0,\n\t\ti = 0;\n\n\thasDuplicate = false;\n\n\tsort.call( results, sortOrder );\n\n\tif ( hasDuplicate ) {\n\t\twhile ( ( elem = results[ i++ ] ) ) {\n\t\t\tif ( elem === results[ i ] ) {\n\t\t\t\tj = duplicates.push( i );\n\t\t\t}\n\t\t}\n\t\twhile ( j-- ) {\n\t\t\tsplice.call( results, duplicates[ j ], 1 );\n\t\t}\n\t}\n\n\treturn results;\n};\n\njQuery.fn.uniqueSort = function() {\n\treturn this.pushStack( jQuery.uniqueSort( slice.apply( this ) ) );\n};\n\nvar i,\n\toutermostContext,\n\n\t// Local document vars\n\tdocument,\n\tdocumentElement,\n\tdocumentIsHTML,\n\n\t// Instance-specific data\n\tdirruns = 0,\n\tdone = 0,\n\tclassCache = createCache(),\n\tcompilerCache = createCache(),\n\tnonnativeSelectorCache = createCache(),\n\n\t// Regular expressions\n\n\t// Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter\n\trwhitespace = new RegExp( whitespace + \"+\", \"g\" ),\n\n\tridentifier = new RegExp( \"^\" + identifier + \"$\" ),\n\n\tmatchExpr = jQuery.extend( {\n\n\t\t// For use in libraries implementing .is()\n\t\t// We use this for POS matching in `select`\n\t\tneedsContext: new RegExp( \"^\" + whitespace +\n\t\t\t\"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\\\(\" + whitespace +\n\t\t\t\"*((?:-\\\\d)?\\\\d*)\" + whitespace + \"*\\\\)|)(?=[^-]|$)\", \"i\" )\n\t}, filterMatchExpr ),\n\n\trinputs = /^(?:input|select|textarea|button)$/i,\n\trheader = /^h\\d$/i,\n\n\t// Easily-parseable/retrievable ID or TAG or CLASS selectors\n\trquickExpr$1 = /^(?:#([\\w-]+)|(\\w+)|\\.([\\w-]+))$/,\n\n\t// Used for iframes; see `setDocument`.\n\t// Support: IE 9 - 11+\n\t// Removing the function wrapper causes a \"Permission Denied\"\n\t// error in IE.\n\tunloadHandler = function() {\n\t\tsetDocument();\n\t},\n\n\tinDisabledFieldset = addCombinator(\n\t\tfunction( elem ) {\n\t\t\treturn elem.disabled === true && nodeName( elem, \"fieldset\" );\n\t\t},\n\t\t{ dir: \"parentNode\", next: \"legend\" }\n\t);\n\nfunction find( selector, context, results, seed ) {\n\tvar m, i, elem, nid, match, groups, newSelector,\n\t\tnewContext = context && context.ownerDocument,\n\n\t\t// nodeType defaults to 9, since context defaults to document\n\t\tnodeType = context ? context.nodeType : 9;\n\n\tresults = results || [];\n\n\t// Return early from calls with invalid selector or context\n\tif ( typeof selector !== \"string\" || !selector ||\n\t\tnodeType !== 1 && nodeType !== 9 && nodeType !== 11 ) {\n\n\t\treturn results;\n\t}\n\n\t// Try to shortcut find operations (as opposed to filters) in HTML documents\n\tif ( !seed ) {\n\t\tsetDocument( context );\n\t\tcontext = context || document;\n\n\t\tif ( documentIsHTML ) {\n\n\t\t\t// If the selector is sufficiently simple, try using a \"get*By*\" DOM method\n\t\t\t// (excepting DocumentFragment context, where the methods don't exist)\n\t\t\tif ( nodeType !== 11 && ( match = rquickExpr$1.exec( selector ) ) ) {\n\n\t\t\t\t// ID selector\n\t\t\t\tif ( ( m = match[ 1 ] ) ) {\n\n\t\t\t\t\t// Document context\n\t\t\t\t\tif ( nodeType === 9 ) {\n\t\t\t\t\t\tif ( ( elem = context.getElementById( m ) ) ) {\n\t\t\t\t\t\t\tpush.call( results, elem );\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn results;\n\n\t\t\t\t\t// Element context\n\t\t\t\t\t} else {\n\t\t\t\t\t\tif ( newContext && ( elem = newContext.getElementById( m ) ) &&\n\t\t\t\t\t\t\tjQuery.contains( context, elem ) ) {\n\n\t\t\t\t\t\t\tpush.call( results, elem );\n\t\t\t\t\t\t\treturn results;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t// Type selector\n\t\t\t\t} else if ( match[ 2 ] ) {\n\t\t\t\t\tpush.apply( results, context.getElementsByTagName( selector ) );\n\t\t\t\t\treturn results;\n\n\t\t\t\t// Class selector\n\t\t\t\t} else if ( ( m = match[ 3 ] ) && context.getElementsByClassName ) {\n\t\t\t\t\tpush.apply( results, context.getElementsByClassName( m ) );\n\t\t\t\t\treturn results;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Take advantage of querySelectorAll\n\t\t\tif ( !nonnativeSelectorCache[ selector + \" \" ] &&\n\t\t\t\t( !rbuggyQSA || !rbuggyQSA.test( selector ) ) ) {\n\n\t\t\t\tnewSelector = selector;\n\t\t\t\tnewContext = context;\n\n\t\t\t\t// qSA considers elements outside a scoping root when evaluating child or\n\t\t\t\t// descendant combinators, which is not what we want.\n\t\t\t\t// In such cases, we work around the behavior by prefixing every selector in the\n\t\t\t\t// list with an ID selector referencing the scope context.\n\t\t\t\t// The technique has to be used as well when a leading combinator is used\n\t\t\t\t// as such selectors are not recognized by querySelectorAll.\n\t\t\t\t// Thanks to Andrew Dupont for this technique.\n\t\t\t\tif ( nodeType === 1 &&\n\t\t\t\t\t( rdescend.test( selector ) || rleadingCombinator.test( selector ) ) ) {\n\n\t\t\t\t\t// Expand context for sibling selectors\n\t\t\t\t\tnewContext = rsibling.test( selector ) &&\n\t\t\t\t\t\ttestContext( context.parentNode ) ||\n\t\t\t\t\t\tcontext;\n\n\t\t\t\t\t// Outside of IE, if we're not changing the context we can\n\t\t\t\t\t// use :scope instead of an ID.\n\t\t\t\t\t// Support: IE 11+\n\t\t\t\t\t// IE sometimes throws a \"Permission denied\" error when strict-comparing\n\t\t\t\t\t// two documents; shallow comparisons work.\n\t\t\t\t\t// eslint-disable-next-line eqeqeq\n\t\t\t\t\tif ( newContext != context || isIE ) {\n\n\t\t\t\t\t\t// Capture the context ID, setting it first if necessary\n\t\t\t\t\t\tif ( ( nid = context.getAttribute( \"id\" ) ) ) {\n\t\t\t\t\t\t\tnid = jQuery.escapeSelector( nid );\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tcontext.setAttribute( \"id\", ( nid = jQuery.expando ) );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// Prefix every selector in the list\n\t\t\t\t\tgroups = tokenize( selector );\n\t\t\t\t\ti = groups.length;\n\t\t\t\t\twhile ( i-- ) {\n\t\t\t\t\t\tgroups[ i ] = ( nid ? \"#\" + nid : \":scope\" ) + \" \" +\n\t\t\t\t\t\t\ttoSelector( groups[ i ] );\n\t\t\t\t\t}\n\t\t\t\t\tnewSelector = groups.join( \",\" );\n\t\t\t\t}\n\n\t\t\t\ttry {\n\t\t\t\t\tpush.apply( results,\n\t\t\t\t\t\tnewContext.querySelectorAll( newSelector )\n\t\t\t\t\t);\n\t\t\t\t\treturn results;\n\t\t\t\t} catch ( qsaError ) {\n\t\t\t\t\tnonnativeSelectorCache( selector, true );\n\t\t\t\t} finally {\n\t\t\t\t\tif ( nid === jQuery.expando ) {\n\t\t\t\t\t\tcontext.removeAttribute( \"id\" );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// All others\n\treturn select( selector.replace( rtrimCSS, \"$1\" ), context, results, seed );\n}\n\n/**\n * Mark a function for special use by jQuery selector module\n * @param {Function} fn The function to mark\n */\nfunction markFunction( fn ) {\n\tfn[ jQuery.expando ] = true;\n\treturn fn;\n}\n\n/**\n * Returns a function to use in pseudos for input types\n * @param {String} type\n */\nfunction createInputPseudo( type ) {\n\treturn function( elem ) {\n\t\treturn nodeName( elem, \"input\" ) && elem.type === type;\n\t};\n}\n\n/**\n * Returns a function to use in pseudos for buttons\n * @param {String} type\n */\nfunction createButtonPseudo( type ) {\n\treturn function( elem ) {\n\t\treturn ( nodeName( elem, \"input\" ) || nodeName( elem, \"button\" ) ) &&\n\t\t\telem.type === type;\n\t};\n}\n\n/**\n * Returns a function to use in pseudos for :enabled/:disabled\n * @param {Boolean} disabled true for :disabled; false for :enabled\n */\nfunction createDisabledPseudo( disabled ) {\n\n\t// Known :disabled false positives: fieldset[disabled] > legend:nth-of-type(n+2) :can-disable\n\treturn function( elem ) {\n\n\t\t// Only certain elements can match :enabled or :disabled\n\t\t// https://html.spec.whatwg.org/multipage/scripting.html#selector-enabled\n\t\t// https://html.spec.whatwg.org/multipage/scripting.html#selector-disabled\n\t\tif ( \"form\" in elem ) {\n\n\t\t\t// Check for inherited disabledness on relevant non-disabled elements:\n\t\t\t// * listed form-associated elements in a disabled fieldset\n\t\t\t// https://html.spec.whatwg.org/multipage/forms.html#category-listed\n\t\t\t// https://html.spec.whatwg.org/multipage/forms.html#concept-fe-disabled\n\t\t\t// * option elements in a disabled optgroup\n\t\t\t// https://html.spec.whatwg.org/multipage/forms.html#concept-option-disabled\n\t\t\t// All such elements have a \"form\" property.\n\t\t\tif ( elem.parentNode && elem.disabled === false ) {\n\n\t\t\t\t// Option elements defer to a parent optgroup if present\n\t\t\t\tif ( \"label\" in elem ) {\n\t\t\t\t\tif ( \"label\" in elem.parentNode ) {\n\t\t\t\t\t\treturn elem.parentNode.disabled === disabled;\n\t\t\t\t\t} else {\n\t\t\t\t\t\treturn elem.disabled === disabled;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Support: IE 6 - 11+\n\t\t\t\t// Use the isDisabled shortcut property to check for disabled fieldset ancestors\n\t\t\t\treturn elem.isDisabled === disabled ||\n\n\t\t\t\t\t// Where there is no isDisabled, check manually\n\t\t\t\t\telem.isDisabled !== !disabled &&\n\t\t\t\t\t\tinDisabledFieldset( elem ) === disabled;\n\t\t\t}\n\n\t\t\treturn elem.disabled === disabled;\n\n\t\t// Try to winnow out elements that can't be disabled before trusting the disabled property.\n\t\t// Some victims get caught in our net (label, legend, menu, track), but it shouldn't\n\t\t// even exist on them, let alone have a boolean value.\n\t\t} else if ( \"label\" in elem ) {\n\t\t\treturn elem.disabled === disabled;\n\t\t}\n\n\t\t// Remaining elements are neither :enabled nor :disabled\n\t\treturn false;\n\t};\n}\n\n/**\n * Returns a function to use in pseudos for positionals\n * @param {Function} fn\n */\nfunction createPositionalPseudo( fn ) {\n\treturn markFunction( function( argument ) {\n\t\targument = +argument;\n\t\treturn markFunction( function( seed, matches ) {\n\t\t\tvar j,\n\t\t\t\tmatchIndexes = fn( [], seed.length, argument ),\n\t\t\t\ti = matchIndexes.length;\n\n\t\t\t// Match elements found at the specified indexes\n\t\t\twhile ( i-- ) {\n\t\t\t\tif ( seed[ ( j = matchIndexes[ i ] ) ] ) {\n\t\t\t\t\tseed[ j ] = !( matches[ j ] = seed[ j ] );\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\t} );\n}\n\n/**\n * Sets document-related variables once based on the current document\n * @param {Element|Object} [node] An element or document object to use to set the document\n */\nfunction setDocument( node ) {\n\tvar subWindow,\n\t\tdoc = node ? node.ownerDocument || node : document$1;\n\n\t// Return early if doc is invalid or already selected\n\t// Support: IE 11+\n\t// IE sometimes throws a \"Permission denied\" error when strict-comparing\n\t// two documents; shallow comparisons work.\n\t// eslint-disable-next-line eqeqeq\n\tif ( doc == document || doc.nodeType !== 9 ) {\n\t\treturn;\n\t}\n\n\t// Update global variables\n\tdocument = doc;\n\tdocumentElement = document.documentElement;\n\tdocumentIsHTML = !jQuery.isXMLDoc( document );\n\n\t// Support: IE 9 - 11+\n\t// Accessing iframe documents after unload throws \"permission denied\" errors (see trac-13936)\n\t// Support: IE 11+\n\t// IE sometimes throws a \"Permission denied\" error when strict-comparing\n\t// two documents; shallow comparisons work.\n\t// eslint-disable-next-line eqeqeq\n\tif ( isIE && document$1 != document &&\n\t\t( subWindow = document.defaultView ) && subWindow.top !== subWindow ) {\n\t\tsubWindow.addEventListener( \"unload\", unloadHandler );\n\t}\n}\n\nfind.matches = function( expr, elements ) {\n\treturn find( expr, null, null, elements );\n};\n\nfind.matchesSelector = function( elem, expr ) {\n\tsetDocument( elem );\n\n\tif ( documentIsHTML &&\n\t\t!nonnativeSelectorCache[ expr + \" \" ] &&\n\t\t( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) {\n\n\t\ttry {\n\t\t\treturn matches.call( elem, expr );\n\t\t} catch ( e ) {\n\t\t\tnonnativeSelectorCache( expr, true );\n\t\t}\n\t}\n\n\treturn find( expr, document, null, [ elem ] ).length > 0;\n};\n\njQuery.expr = {\n\n\t// Can be adjusted by the user\n\tcacheLength: 50,\n\n\tcreatePseudo: markFunction,\n\n\tmatch: matchExpr,\n\n\tfind: {\n\t\tID: function( id, context ) {\n\t\t\tif ( typeof context.getElementById !== \"undefined\" && documentIsHTML ) {\n\t\t\t\tvar elem = context.getElementById( id );\n\t\t\t\treturn elem ? [ elem ] : [];\n\t\t\t}\n\t\t},\n\n\t\tTAG: function( tag, context ) {\n\t\t\tif ( typeof context.getElementsByTagName !== \"undefined\" ) {\n\t\t\t\treturn context.getElementsByTagName( tag );\n\n\t\t\t\t// DocumentFragment nodes don't have gEBTN\n\t\t\t} else {\n\t\t\t\treturn context.querySelectorAll( tag );\n\t\t\t}\n\t\t},\n\n\t\tCLASS: function( className, context ) {\n\t\t\tif ( typeof context.getElementsByClassName !== \"undefined\" && documentIsHTML ) {\n\t\t\t\treturn context.getElementsByClassName( className );\n\t\t\t}\n\t\t}\n\t},\n\n\trelative: {\n\t\t\">\": { dir: \"parentNode\", first: true },\n\t\t\" \": { dir: \"parentNode\" },\n\t\t\"+\": { dir: \"previousSibling\", first: true },\n\t\t\"~\": { dir: \"previousSibling\" }\n\t},\n\n\tpreFilter: preFilter,\n\n\tfilter: {\n\t\tID: function( id ) {\n\t\t\tvar attrId = unescapeSelector( id );\n\t\t\treturn function( elem ) {\n\t\t\t\treturn elem.getAttribute( \"id\" ) === attrId;\n\t\t\t};\n\t\t},\n\n\t\tTAG: function( nodeNameSelector ) {\n\t\t\tvar expectedNodeName = unescapeSelector( nodeNameSelector ).toLowerCase();\n\t\t\treturn nodeNameSelector === \"*\" ?\n\n\t\t\t\tfunction() {\n\t\t\t\t\treturn true;\n\t\t\t\t} :\n\n\t\t\t\tfunction( elem ) {\n\t\t\t\t\treturn nodeName( elem, expectedNodeName );\n\t\t\t\t};\n\t\t},\n\n\t\tCLASS: function( className ) {\n\t\t\tvar pattern = classCache[ className + \" \" ];\n\n\t\t\treturn pattern ||\n\t\t\t\t( pattern = new RegExp( \"(^|\" + whitespace + \")\" + className +\n\t\t\t\t\t\"(\" + whitespace + \"|$)\" ) ) &&\n\t\t\t\tclassCache( className, function( elem ) {\n\t\t\t\t\treturn pattern.test(\n\t\t\t\t\t\ttypeof elem.className === \"string\" && elem.className ||\n\t\t\t\t\t\t\ttypeof elem.getAttribute !== \"undefined\" &&\n\t\t\t\t\t\t\t\telem.getAttribute( \"class\" ) ||\n\t\t\t\t\t\t\t\"\"\n\t\t\t\t\t);\n\t\t\t\t} );\n\t\t},\n\n\t\tATTR: function( name, operator, check ) {\n\t\t\treturn function( elem ) {\n\t\t\t\tvar result = jQuery.attr( elem, name );\n\n\t\t\t\tif ( result == null ) {\n\t\t\t\t\treturn operator === \"!=\";\n\t\t\t\t}\n\t\t\t\tif ( !operator ) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\n\t\t\t\tresult += \"\";\n\n\t\t\t\tif ( operator === \"=\" ) {\n\t\t\t\t\treturn result === check;\n\t\t\t\t}\n\t\t\t\tif ( operator === \"!=\" ) {\n\t\t\t\t\treturn result !== check;\n\t\t\t\t}\n\t\t\t\tif ( operator === \"^=\" ) {\n\t\t\t\t\treturn check && result.indexOf( check ) === 0;\n\t\t\t\t}\n\t\t\t\tif ( operator === \"*=\" ) {\n\t\t\t\t\treturn check && result.indexOf( check ) > -1;\n\t\t\t\t}\n\t\t\t\tif ( operator === \"$=\" ) {\n\t\t\t\t\treturn check && result.slice( -check.length ) === check;\n\t\t\t\t}\n\t\t\t\tif ( operator === \"~=\" ) {\n\t\t\t\t\treturn ( \" \" + result.replace( rwhitespace, \" \" ) + \" \" )\n\t\t\t\t\t\t.indexOf( check ) > -1;\n\t\t\t\t}\n\t\t\t\tif ( operator === \"|=\" ) {\n\t\t\t\t\treturn result === check || result.slice( 0, check.length + 1 ) === check + \"-\";\n\t\t\t\t}\n\n\t\t\t\treturn false;\n\t\t\t};\n\t\t},\n\n\t\tCHILD: function( type, what, _argument, first, last ) {\n\t\t\tvar simple = type.slice( 0, 3 ) !== \"nth\",\n\t\t\t\tforward = type.slice( -4 ) !== \"last\",\n\t\t\t\tofType = what === \"of-type\";\n\n\t\t\treturn first === 1 && last === 0 ?\n\n\t\t\t\t// Shortcut for :nth-*(n)\n\t\t\t\tfunction( elem ) {\n\t\t\t\t\treturn !!elem.parentNode;\n\t\t\t\t} :\n\n\t\t\t\tfunction( elem, _context, xml ) {\n\t\t\t\t\tvar cache, outerCache, node, nodeIndex, start,\n\t\t\t\t\t\tdir = simple !== forward ? \"nextSibling\" : \"previousSibling\",\n\t\t\t\t\t\tparent = elem.parentNode,\n\t\t\t\t\t\tname = ofType && elem.nodeName.toLowerCase(),\n\t\t\t\t\t\tuseCache = !xml && !ofType,\n\t\t\t\t\t\tdiff = false;\n\n\t\t\t\t\tif ( parent ) {\n\n\t\t\t\t\t\t// :(first|last|only)-(child|of-type)\n\t\t\t\t\t\tif ( simple ) {\n\t\t\t\t\t\t\twhile ( dir ) {\n\t\t\t\t\t\t\t\tnode = elem;\n\t\t\t\t\t\t\t\twhile ( ( node = node[ dir ] ) ) {\n\t\t\t\t\t\t\t\t\tif ( ofType ?\n\t\t\t\t\t\t\t\t\t\tnodeName( node, name ) :\n\t\t\t\t\t\t\t\t\t\tnode.nodeType === 1 ) {\n\n\t\t\t\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t// Reverse direction for :only-* (if we haven't yet done so)\n\t\t\t\t\t\t\t\tstart = dir = type === \"only\" && !start && \"nextSibling\";\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tstart = [ forward ? parent.firstChild : parent.lastChild ];\n\n\t\t\t\t\t\t// non-xml :nth-child(...) stores cache data on `parent`\n\t\t\t\t\t\tif ( forward && useCache ) {\n\n\t\t\t\t\t\t\t// Seek `elem` from a previously-cached index\n\t\t\t\t\t\t\touterCache = parent[ jQuery.expando ] ||\n\t\t\t\t\t\t\t\t( parent[ jQuery.expando ] = {} );\n\t\t\t\t\t\t\tcache = outerCache[ type ] || [];\n\t\t\t\t\t\t\tnodeIndex = cache[ 0 ] === dirruns && cache[ 1 ];\n\t\t\t\t\t\t\tdiff = nodeIndex && cache[ 2 ];\n\t\t\t\t\t\t\tnode = nodeIndex && parent.childNodes[ nodeIndex ];\n\n\t\t\t\t\t\t\twhile ( ( node = ++nodeIndex && node && node[ dir ] ||\n\n\t\t\t\t\t\t\t\t// Fallback to seeking `elem` from the start\n\t\t\t\t\t\t\t\t( diff = nodeIndex = 0 ) || start.pop() ) ) {\n\n\t\t\t\t\t\t\t\t// When found, cache indexes on `parent` and break\n\t\t\t\t\t\t\t\tif ( node.nodeType === 1 && ++diff && node === elem ) {\n\t\t\t\t\t\t\t\t\touterCache[ type ] = [ dirruns, nodeIndex, diff ];\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t// Use previously-cached element index if available\n\t\t\t\t\t\t\tif ( useCache ) {\n\t\t\t\t\t\t\t\touterCache = elem[ jQuery.expando ] ||\n\t\t\t\t\t\t\t\t\t( elem[ jQuery.expando ] = {} );\n\t\t\t\t\t\t\t\tcache = outerCache[ type ] || [];\n\t\t\t\t\t\t\t\tnodeIndex = cache[ 0 ] === dirruns && cache[ 1 ];\n\t\t\t\t\t\t\t\tdiff = nodeIndex;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// xml :nth-child(...)\n\t\t\t\t\t\t\t// or :nth-last-child(...) or :nth(-last)?-of-type(...)\n\t\t\t\t\t\t\tif ( diff === false ) {\n\n\t\t\t\t\t\t\t\t// Use the same loop as above to seek `elem` from the start\n\t\t\t\t\t\t\t\twhile ( ( node = ++nodeIndex && node && node[ dir ] ||\n\t\t\t\t\t\t\t\t\t( diff = nodeIndex = 0 ) || start.pop() ) ) {\n\n\t\t\t\t\t\t\t\t\tif ( ( ofType ?\n\t\t\t\t\t\t\t\t\t\tnodeName( node, name ) :\n\t\t\t\t\t\t\t\t\t\tnode.nodeType === 1 ) &&\n\t\t\t\t\t\t\t\t\t\t++diff ) {\n\n\t\t\t\t\t\t\t\t\t\t// Cache the index of each encountered element\n\t\t\t\t\t\t\t\t\t\tif ( useCache ) {\n\t\t\t\t\t\t\t\t\t\t\touterCache = node[ jQuery.expando ] ||\n\t\t\t\t\t\t\t\t\t\t\t\t( node[ jQuery.expando ] = {} );\n\t\t\t\t\t\t\t\t\t\t\touterCache[ type ] = [ dirruns, diff ];\n\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t\tif ( node === elem ) {\n\t\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Incorporate the offset, then check against cycle size\n\t\t\t\t\t\tdiff -= last;\n\t\t\t\t\t\treturn diff === first || ( diff % first === 0 && diff / first >= 0 );\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t},\n\n\t\tPSEUDO: function( pseudo, argument ) {\n\n\t\t\t// pseudo-class names are case-insensitive\n\t\t\t// https://www.w3.org/TR/selectors/#pseudo-classes\n\t\t\t// Prioritize by case sensitivity in case custom pseudos are added with uppercase letters\n\t\t\t// Remember that setFilters inherits from pseudos\n\t\t\tvar fn = jQuery.expr.pseudos[ pseudo ] ||\n\t\t\t\tjQuery.expr.setFilters[ pseudo.toLowerCase() ] ||\n\t\t\t\tselectorError( \"unsupported pseudo: \" + pseudo );\n\n\t\t\t// The user may use createPseudo to indicate that\n\t\t\t// arguments are needed to create the filter function\n\t\t\t// just as jQuery does\n\t\t\tif ( fn[ jQuery.expando ] ) {\n\t\t\t\treturn fn( argument );\n\t\t\t}\n\n\t\t\treturn fn;\n\t\t}\n\t},\n\n\tpseudos: {\n\n\t\t// Potentially complex pseudos\n\t\tnot: markFunction( function( selector ) {\n\n\t\t\t// Trim the selector passed to compile\n\t\t\t// to avoid treating leading and trailing\n\t\t\t// spaces as combinators\n\t\t\tvar input = [],\n\t\t\t\tresults = [],\n\t\t\t\tmatcher = compile( selector.replace( rtrimCSS, \"$1\" ) );\n\n\t\t\treturn matcher[ jQuery.expando ] ?\n\t\t\t\tmarkFunction( function( seed, matches, _context, xml ) {\n\t\t\t\t\tvar elem,\n\t\t\t\t\t\tunmatched = matcher( seed, null, xml, [] ),\n\t\t\t\t\t\ti = seed.length;\n\n\t\t\t\t\t// Match elements unmatched by `matcher`\n\t\t\t\t\twhile ( i-- ) {\n\t\t\t\t\t\tif ( ( elem = unmatched[ i ] ) ) {\n\t\t\t\t\t\t\tseed[ i ] = !( matches[ i ] = elem );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} ) :\n\t\t\t\tfunction( elem, _context, xml ) {\n\t\t\t\t\tinput[ 0 ] = elem;\n\t\t\t\t\tmatcher( input, null, xml, results );\n\n\t\t\t\t\t// Don't keep the element\n\t\t\t\t\t// (see https://github.com/jquery/sizzle/issues/299)\n\t\t\t\t\tinput[ 0 ] = null;\n\t\t\t\t\treturn !results.pop();\n\t\t\t\t};\n\t\t} ),\n\n\t\thas: markFunction( function( selector ) {\n\t\t\treturn function( elem ) {\n\t\t\t\treturn find( selector, elem ).length > 0;\n\t\t\t};\n\t\t} ),\n\n\t\tcontains: markFunction( function( text ) {\n\t\t\ttext = unescapeSelector( text );\n\t\t\treturn function( elem ) {\n\t\t\t\treturn ( elem.textContent || jQuery.text( elem ) ).indexOf( text ) > -1;\n\t\t\t};\n\t\t} ),\n\n\t\t// \"Whether an element is represented by a :lang() selector\n\t\t// is based solely on the element's language value\n\t\t// being equal to the identifier C,\n\t\t// or beginning with the identifier C immediately followed by \"-\".\n\t\t// The matching of C against the element's language value is performed case-insensitively.\n\t\t// The identifier C does not have to be a valid language name.\"\n\t\t// https://www.w3.org/TR/selectors/#lang-pseudo\n\t\tlang: markFunction( function( lang ) {\n\n\t\t\t// lang value must be a valid identifier\n\t\t\tif ( !ridentifier.test( lang || \"\" ) ) {\n\t\t\t\tselectorError( \"unsupported lang: \" + lang );\n\t\t\t}\n\t\t\tlang = unescapeSelector( lang ).toLowerCase();\n\t\t\treturn function( elem ) {\n\t\t\t\tvar elemLang;\n\t\t\t\tdo {\n\t\t\t\t\tif ( ( elemLang = documentIsHTML ?\n\t\t\t\t\t\telem.lang :\n\t\t\t\t\t\telem.getAttribute( \"xml:lang\" ) || elem.getAttribute( \"lang\" ) ) ) {\n\n\t\t\t\t\t\telemLang = elemLang.toLowerCase();\n\t\t\t\t\t\treturn elemLang === lang || elemLang.indexOf( lang + \"-\" ) === 0;\n\t\t\t\t\t}\n\t\t\t\t} while ( ( elem = elem.parentNode ) && elem.nodeType === 1 );\n\t\t\t\treturn false;\n\t\t\t};\n\t\t} ),\n\n\t\t// Miscellaneous\n\t\ttarget: function( elem ) {\n\t\t\tvar hash = window.location && window.location.hash;\n\t\t\treturn hash && hash.slice( 1 ) === elem.id;\n\t\t},\n\n\t\troot: function( elem ) {\n\t\t\treturn elem === documentElement;\n\t\t},\n\n\t\tfocus: function( elem ) {\n\t\t\treturn elem === document.activeElement &&\n\t\t\t\tdocument.hasFocus() &&\n\t\t\t\t!!( elem.type || elem.href || ~elem.tabIndex );\n\t\t},\n\n\t\t// Boolean properties\n\t\tenabled: createDisabledPseudo( false ),\n\t\tdisabled: createDisabledPseudo( true ),\n\n\t\tchecked: function( elem ) {\n\n\t\t\t// In CSS3, :checked should return both checked and selected elements\n\t\t\t// https://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked\n\t\t\treturn ( nodeName( elem, \"input\" ) && !!elem.checked ) ||\n\t\t\t\t( nodeName( elem, \"option\" ) && !!elem.selected );\n\t\t},\n\n\t\tselected: function( elem ) {\n\n\t\t\t// Support: IE <=11+\n\t\t\t// Accessing the selectedIndex property\n\t\t\t// forces the browser to treat the default option as\n\t\t\t// selected when in an optgroup.\n\t\t\tif ( isIE && elem.parentNode ) {\n\t\t\t\t// eslint-disable-next-line no-unused-expressions\n\t\t\t\telem.parentNode.selectedIndex;\n\t\t\t}\n\n\t\t\treturn elem.selected === true;\n\t\t},\n\n\t\t// Contents\n\t\tempty: function( elem ) {\n\n\t\t\t// https://www.w3.org/TR/selectors/#empty-pseudo\n\t\t\t// :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5),\n\t\t\t// but not by others (comment: 8; processing instruction: 7; etc.)\n\t\t\t// nodeType < 6 works because attributes (2) do not appear as children\n\t\t\tfor ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {\n\t\t\t\tif ( elem.nodeType < 6 ) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn true;\n\t\t},\n\n\t\tparent: function( elem ) {\n\t\t\treturn !jQuery.expr.pseudos.empty( elem );\n\t\t},\n\n\t\t// Element/input types\n\t\theader: function( elem ) {\n\t\t\treturn rheader.test( elem.nodeName );\n\t\t},\n\n\t\tinput: function( elem ) {\n\t\t\treturn rinputs.test( elem.nodeName );\n\t\t},\n\n\t\tbutton: function( elem ) {\n\t\t\treturn nodeName( elem, \"input\" ) && elem.type === \"button\" ||\n\t\t\t\tnodeName( elem, \"button\" );\n\t\t},\n\n\t\ttext: function( elem ) {\n\t\t\treturn nodeName( elem, \"input\" ) && elem.type === \"text\";\n\t\t},\n\n\t\t// Position-in-collection\n\t\tfirst: createPositionalPseudo( function() {\n\t\t\treturn [ 0 ];\n\t\t} ),\n\n\t\tlast: createPositionalPseudo( function( _matchIndexes, length ) {\n\t\t\treturn [ length - 1 ];\n\t\t} ),\n\n\t\teq: createPositionalPseudo( function( _matchIndexes, length, argument ) {\n\t\t\treturn [ argument < 0 ? argument + length : argument ];\n\t\t} ),\n\n\t\teven: createPositionalPseudo( function( matchIndexes, length ) {\n\t\t\tvar i = 0;\n\t\t\tfor ( ; i < length; i += 2 ) {\n\t\t\t\tmatchIndexes.push( i );\n\t\t\t}\n\t\t\treturn matchIndexes;\n\t\t} ),\n\n\t\todd: createPositionalPseudo( function( matchIndexes, length ) {\n\t\t\tvar i = 1;\n\t\t\tfor ( ; i < length; i += 2 ) {\n\t\t\t\tmatchIndexes.push( i );\n\t\t\t}\n\t\t\treturn matchIndexes;\n\t\t} ),\n\n\t\tlt: createPositionalPseudo( function( matchIndexes, length, argument ) {\n\t\t\tvar i;\n\n\t\t\tif ( argument < 0 ) {\n\t\t\t\ti = argument + length;\n\t\t\t} else if ( argument > length ) {\n\t\t\t\ti = length;\n\t\t\t} else {\n\t\t\t\ti = argument;\n\t\t\t}\n\n\t\t\tfor ( ; --i >= 0; ) {\n\t\t\t\tmatchIndexes.push( i );\n\t\t\t}\n\t\t\treturn matchIndexes;\n\t\t} ),\n\n\t\tgt: createPositionalPseudo( function( matchIndexes, length, argument ) {\n\t\t\tvar i = argument < 0 ? argument + length : argument;\n\t\t\tfor ( ; ++i < length; ) {\n\t\t\t\tmatchIndexes.push( i );\n\t\t\t}\n\t\t\treturn matchIndexes;\n\t\t} )\n\t}\n};\n\njQuery.expr.pseudos.nth = jQuery.expr.pseudos.eq;\n\n// Add button/input type pseudos\nfor ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) {\n\tjQuery.expr.pseudos[ i ] = createInputPseudo( i );\n}\nfor ( i in { submit: true, reset: true } ) {\n\tjQuery.expr.pseudos[ i ] = createButtonPseudo( i );\n}\n\n// Easy API for creating new setFilters\nfunction setFilters() {}\nsetFilters.prototype = jQuery.expr.pseudos;\njQuery.expr.setFilters = new setFilters();\n\nfunction addCombinator( matcher, combinator, base ) {\n\tvar dir = combinator.dir,\n\t\tskip = combinator.next,\n\t\tkey = skip || dir,\n\t\tcheckNonElements = base && key === \"parentNode\",\n\t\tdoneName = done++;\n\n\treturn combinator.first ?\n\n\t\t// Check against closest ancestor/preceding element\n\t\tfunction( elem, context, xml ) {\n\t\t\twhile ( ( elem = elem[ dir ] ) ) {\n\t\t\t\tif ( elem.nodeType === 1 || checkNonElements ) {\n\t\t\t\t\treturn matcher( elem, context, xml );\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn false;\n\t\t} :\n\n\t\t// Check against all ancestor/preceding elements\n\t\tfunction( elem, context, xml ) {\n\t\t\tvar oldCache, outerCache,\n\t\t\t\tnewCache = [ dirruns, doneName ];\n\n\t\t\t// We can't set arbitrary data on XML nodes, so they don't benefit from combinator caching\n\t\t\tif ( xml ) {\n\t\t\t\twhile ( ( elem = elem[ dir ] ) ) {\n\t\t\t\t\tif ( elem.nodeType === 1 || checkNonElements ) {\n\t\t\t\t\t\tif ( matcher( elem, context, xml ) ) {\n\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\twhile ( ( elem = elem[ dir ] ) ) {\n\t\t\t\t\tif ( elem.nodeType === 1 || checkNonElements ) {\n\t\t\t\t\t\touterCache = elem[ jQuery.expando ] || ( elem[ jQuery.expando ] = {} );\n\n\t\t\t\t\t\tif ( skip && nodeName( elem, skip ) ) {\n\t\t\t\t\t\t\telem = elem[ dir ] || elem;\n\t\t\t\t\t\t} else if ( ( oldCache = outerCache[ key ] ) &&\n\t\t\t\t\t\t\toldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) {\n\n\t\t\t\t\t\t\t// Assign to newCache so results back-propagate to previous elements\n\t\t\t\t\t\t\treturn ( newCache[ 2 ] = oldCache[ 2 ] );\n\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t// Reuse newcache so results back-propagate to previous elements\n\t\t\t\t\t\t\touterCache[ key ] = newCache;\n\n\t\t\t\t\t\t\t// A match means we're done; a fail means we have to keep checking\n\t\t\t\t\t\t\tif ( ( newCache[ 2 ] = matcher( elem, context, xml ) ) ) {\n\t\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn false;\n\t\t};\n}\n\nfunction elementMatcher( matchers ) {\n\treturn matchers.length > 1 ?\n\t\tfunction( elem, context, xml ) {\n\t\t\tvar i = matchers.length;\n\t\t\twhile ( i-- ) {\n\t\t\t\tif ( !matchers[ i ]( elem, context, xml ) ) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn true;\n\t\t} :\n\t\tmatchers[ 0 ];\n}\n\nfunction multipleContexts( selector, contexts, results ) {\n\tvar i = 0,\n\t\tlen = contexts.length;\n\tfor ( ; i < len; i++ ) {\n\t\tfind( selector, contexts[ i ], results );\n\t}\n\treturn results;\n}\n\nfunction condense( unmatched, map, filter, context, xml ) {\n\tvar elem,\n\t\tnewUnmatched = [],\n\t\ti = 0,\n\t\tlen = unmatched.length,\n\t\tmapped = map != null;\n\n\tfor ( ; i < len; i++ ) {\n\t\tif ( ( elem = unmatched[ i ] ) ) {\n\t\t\tif ( !filter || filter( elem, context, xml ) ) {\n\t\t\t\tnewUnmatched.push( elem );\n\t\t\t\tif ( mapped ) {\n\t\t\t\t\tmap.push( i );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn newUnmatched;\n}\n\nfunction setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) {\n\tif ( postFilter && !postFilter[ jQuery.expando ] ) {\n\t\tpostFilter = setMatcher( postFilter );\n\t}\n\tif ( postFinder && !postFinder[ jQuery.expando ] ) {\n\t\tpostFinder = setMatcher( postFinder, postSelector );\n\t}\n\treturn markFunction( function( seed, results, context, xml ) {\n\t\tvar temp, i, elem, matcherOut,\n\t\t\tpreMap = [],\n\t\t\tpostMap = [],\n\t\t\tpreexisting = results.length,\n\n\t\t\t// Get initial elements from seed or context\n\t\t\telems = seed ||\n\t\t\t\tmultipleContexts( selector || \"*\",\n\t\t\t\t\tcontext.nodeType ? [ context ] : context, [] ),\n\n\t\t\t// Prefilter to get matcher input, preserving a map for seed-results synchronization\n\t\t\tmatcherIn = preFilter && ( seed || !selector ) ?\n\t\t\t\tcondense( elems, preMap, preFilter, context, xml ) :\n\t\t\t\telems;\n\n\t\tif ( matcher ) {\n\n\t\t\t// If we have a postFinder, or filtered seed, or non-seed postFilter\n\t\t\t// or preexisting results,\n\t\t\tmatcherOut = postFinder || ( seed ? preFilter : preexisting || postFilter ) ?\n\n\t\t\t\t// ...intermediate processing is necessary\n\t\t\t\t[] :\n\n\t\t\t\t// ...otherwise use results directly\n\t\t\t\tresults;\n\n\t\t\t// Find primary matches\n\t\t\tmatcher( matcherIn, matcherOut, context, xml );\n\t\t} else {\n\t\t\tmatcherOut = matcherIn;\n\t\t}\n\n\t\t// Apply postFilter\n\t\tif ( postFilter ) {\n\t\t\ttemp = condense( matcherOut, postMap );\n\t\t\tpostFilter( temp, [], context, xml );\n\n\t\t\t// Un-match failing elements by moving them back to matcherIn\n\t\t\ti = temp.length;\n\t\t\twhile ( i-- ) {\n\t\t\t\tif ( ( elem = temp[ i ] ) ) {\n\t\t\t\t\tmatcherOut[ postMap[ i ] ] = !( matcherIn[ postMap[ i ] ] = elem );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif ( seed ) {\n\t\t\tif ( postFinder || preFilter ) {\n\t\t\t\tif ( postFinder ) {\n\n\t\t\t\t\t// Get the final matcherOut by condensing this intermediate into postFinder contexts\n\t\t\t\t\ttemp = [];\n\t\t\t\t\ti = matcherOut.length;\n\t\t\t\t\twhile ( i-- ) {\n\t\t\t\t\t\tif ( ( elem = matcherOut[ i ] ) ) {\n\n\t\t\t\t\t\t\t// Restore matcherIn since elem is not yet a final match\n\t\t\t\t\t\t\ttemp.push( ( matcherIn[ i ] = elem ) );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tpostFinder( null, ( matcherOut = [] ), temp, xml );\n\t\t\t\t}\n\n\t\t\t\t// Move matched elements from seed to results to keep them synchronized\n\t\t\t\ti = matcherOut.length;\n\t\t\t\twhile ( i-- ) {\n\t\t\t\t\tif ( ( elem = matcherOut[ i ] ) &&\n\t\t\t\t\t\t( temp = postFinder ? indexOf.call( seed, elem ) : preMap[ i ] ) > -1 ) {\n\n\t\t\t\t\t\tseed[ temp ] = !( results[ temp ] = elem );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t// Add elements to results, through postFinder if defined\n\t\t} else {\n\t\t\tmatcherOut = condense(\n\t\t\t\tmatcherOut === results ?\n\t\t\t\t\tmatcherOut.splice( preexisting, matcherOut.length ) :\n\t\t\t\t\tmatcherOut\n\t\t\t);\n\t\t\tif ( postFinder ) {\n\t\t\t\tpostFinder( null, results, matcherOut, xml );\n\t\t\t} else {\n\t\t\t\tpush.apply( results, matcherOut );\n\t\t\t}\n\t\t}\n\t} );\n}\n\nfunction matcherFromTokens( tokens ) {\n\tvar checkContext, matcher, j,\n\t\tlen = tokens.length,\n\t\tleadingRelative = jQuery.expr.relative[ tokens[ 0 ].type ],\n\t\timplicitRelative = leadingRelative || jQuery.expr.relative[ \" \" ],\n\t\ti = leadingRelative ? 1 : 0,\n\n\t\t// The foundational matcher ensures that elements are reachable from top-level context(s)\n\t\tmatchContext = addCombinator( function( elem ) {\n\t\t\treturn elem === checkContext;\n\t\t}, implicitRelative, true ),\n\t\tmatchAnyContext = addCombinator( function( elem ) {\n\t\t\treturn indexOf.call( checkContext, elem ) > -1;\n\t\t}, implicitRelative, true ),\n\t\tmatchers = [ function( elem, context, xml ) {\n\n\t\t\t// Support: IE 11+\n\t\t\t// IE sometimes throws a \"Permission denied\" error when strict-comparing\n\t\t\t// two documents; shallow comparisons work.\n\t\t\t// eslint-disable-next-line eqeqeq\n\t\t\tvar ret = ( !leadingRelative && ( xml || context != outermostContext ) ) || (\n\t\t\t\t( checkContext = context ).nodeType ?\n\t\t\t\t\tmatchContext( elem, context, xml ) :\n\t\t\t\t\tmatchAnyContext( elem, context, xml ) );\n\n\t\t\t// Avoid hanging onto element\n\t\t\t// (see https://github.com/jquery/sizzle/issues/299)\n\t\t\tcheckContext = null;\n\t\t\treturn ret;\n\t\t} ];\n\n\tfor ( ; i < len; i++ ) {\n\t\tif ( ( matcher = jQuery.expr.relative[ tokens[ i ].type ] ) ) {\n\t\t\tmatchers = [ addCombinator( elementMatcher( matchers ), matcher ) ];\n\t\t} else {\n\t\t\tmatcher = jQuery.expr.filter[ tokens[ i ].type ].apply( null, tokens[ i ].matches );\n\n\t\t\t// Return special upon seeing a positional matcher\n\t\t\tif ( matcher[ jQuery.expando ] ) {\n\n\t\t\t\t// Find the next relative operator (if any) for proper handling\n\t\t\t\tj = ++i;\n\t\t\t\tfor ( ; j < len; j++ ) {\n\t\t\t\t\tif ( jQuery.expr.relative[ tokens[ j ].type ] ) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn setMatcher(\n\t\t\t\t\ti > 1 && elementMatcher( matchers ),\n\t\t\t\t\ti > 1 && toSelector(\n\n\t\t\t\t\t\t// If the preceding token was a descendant combinator, insert an implicit any-element `*`\n\t\t\t\t\t\ttokens.slice( 0, i - 1 )\n\t\t\t\t\t\t\t.concat( { value: tokens[ i - 2 ].type === \" \" ? \"*\" : \"\" } )\n\t\t\t\t\t).replace( rtrimCSS, \"$1\" ),\n\t\t\t\t\tmatcher,\n\t\t\t\t\ti < j && matcherFromTokens( tokens.slice( i, j ) ),\n\t\t\t\t\tj < len && matcherFromTokens( ( tokens = tokens.slice( j ) ) ),\n\t\t\t\t\tj < len && toSelector( tokens )\n\t\t\t\t);\n\t\t\t}\n\t\t\tmatchers.push( matcher );\n\t\t}\n\t}\n\n\treturn elementMatcher( matchers );\n}\n\nfunction matcherFromGroupMatchers( elementMatchers, setMatchers ) {\n\tvar bySet = setMatchers.length > 0,\n\t\tbyElement = elementMatchers.length > 0,\n\t\tsuperMatcher = function( seed, context, xml, results, outermost ) {\n\t\t\tvar elem, j, matcher,\n\t\t\t\tmatchedCount = 0,\n\t\t\t\ti = \"0\",\n\t\t\t\tunmatched = seed && [],\n\t\t\t\tsetMatched = [],\n\t\t\t\tcontextBackup = outermostContext,\n\n\t\t\t\t// We must always have either seed elements or outermost context\n\t\t\t\telems = seed || byElement && jQuery.expr.find.TAG( \"*\", outermost ),\n\n\t\t\t\t// Use integer dirruns iff this is the outermost matcher\n\t\t\t\tdirrunsUnique = ( dirruns += contextBackup == null ? 1 : Math.random() || 0.1 );\n\n\t\t\tif ( outermost ) {\n\n\t\t\t\t// Support: IE 11+\n\t\t\t\t// IE sometimes throws a \"Permission denied\" error when strict-comparing\n\t\t\t\t// two documents; shallow comparisons work.\n\t\t\t\t// eslint-disable-next-line eqeqeq\n\t\t\t\toutermostContext = context == document || context || outermost;\n\t\t\t}\n\n\t\t\t// Add elements passing elementMatchers directly to results\n\t\t\tfor ( ; ( elem = elems[ i ] ) != null; i++ ) {\n\t\t\t\tif ( byElement && elem ) {\n\t\t\t\t\tj = 0;\n\n\t\t\t\t\t// Support: IE 11+\n\t\t\t\t\t// IE sometimes throws a \"Permission denied\" error when strict-comparing\n\t\t\t\t\t// two documents; shallow comparisons work.\n\t\t\t\t\t// eslint-disable-next-line eqeqeq\n\t\t\t\t\tif ( !context && elem.ownerDocument != document ) {\n\t\t\t\t\t\tsetDocument( elem );\n\t\t\t\t\t\txml = !documentIsHTML;\n\t\t\t\t\t}\n\t\t\t\t\twhile ( ( matcher = elementMatchers[ j++ ] ) ) {\n\t\t\t\t\t\tif ( matcher( elem, context || document, xml ) ) {\n\t\t\t\t\t\t\tpush.call( results, elem );\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif ( outermost ) {\n\t\t\t\t\t\tdirruns = dirrunsUnique;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Track unmatched elements for set filters\n\t\t\t\tif ( bySet ) {\n\n\t\t\t\t\t// They will have gone through all possible matchers\n\t\t\t\t\tif ( ( elem = !matcher && elem ) ) {\n\t\t\t\t\t\tmatchedCount--;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Lengthen the array for every element, matched or not\n\t\t\t\t\tif ( seed ) {\n\t\t\t\t\t\tunmatched.push( elem );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// `i` is now the count of elements visited above, and adding it to `matchedCount`\n\t\t\t// makes the latter nonnegative.\n\t\t\tmatchedCount += i;\n\n\t\t\t// Apply set filters to unmatched elements\n\t\t\t// NOTE: This can be skipped if there are no unmatched elements (i.e., `matchedCount`\n\t\t\t// equals `i`), unless we didn't visit _any_ elements in the above loop because we have\n\t\t\t// no element matchers and no seed.\n\t\t\t// Incrementing an initially-string \"0\" `i` allows `i` to remain a string only in that\n\t\t\t// case, which will result in a \"00\" `matchedCount` that differs from `i` but is also\n\t\t\t// numerically zero.\n\t\t\tif ( bySet && i !== matchedCount ) {\n\t\t\t\tj = 0;\n\t\t\t\twhile ( ( matcher = setMatchers[ j++ ] ) ) {\n\t\t\t\t\tmatcher( unmatched, setMatched, context, xml );\n\t\t\t\t}\n\n\t\t\t\tif ( seed ) {\n\n\t\t\t\t\t// Reintegrate element matches to eliminate the need for sorting\n\t\t\t\t\tif ( matchedCount > 0 ) {\n\t\t\t\t\t\twhile ( i-- ) {\n\t\t\t\t\t\t\tif ( !( unmatched[ i ] || setMatched[ i ] ) ) {\n\t\t\t\t\t\t\t\tsetMatched[ i ] = pop.call( results );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// Discard index placeholder values to get only actual matches\n\t\t\t\t\tsetMatched = condense( setMatched );\n\t\t\t\t}\n\n\t\t\t\t// Add matches to results\n\t\t\t\tpush.apply( results, setMatched );\n\n\t\t\t\t// Seedless set matches succeeding multiple successful matchers stipulate sorting\n\t\t\t\tif ( outermost && !seed && setMatched.length > 0 &&\n\t\t\t\t\t( matchedCount + setMatchers.length ) > 1 ) {\n\n\t\t\t\t\tjQuery.uniqueSort( results );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Override manipulation of globals by nested matchers\n\t\t\tif ( outermost ) {\n\t\t\t\tdirruns = dirrunsUnique;\n\t\t\t\toutermostContext = contextBackup;\n\t\t\t}\n\n\t\t\treturn unmatched;\n\t\t};\n\n\treturn bySet ?\n\t\tmarkFunction( superMatcher ) :\n\t\tsuperMatcher;\n}\n\nfunction compile( selector, match /* Internal Use Only */ ) {\n\tvar i,\n\t\tsetMatchers = [],\n\t\telementMatchers = [],\n\t\tcached = compilerCache[ selector + \" \" ];\n\n\tif ( !cached ) {\n\n\t\t// Generate a function of recursive functions that can be used to check each element\n\t\tif ( !match ) {\n\t\t\tmatch = tokenize( selector );\n\t\t}\n\t\ti = match.length;\n\t\twhile ( i-- ) {\n\t\t\tcached = matcherFromTokens( match[ i ] );\n\t\t\tif ( cached[ jQuery.expando ] ) {\n\t\t\t\tsetMatchers.push( cached );\n\t\t\t} else {\n\t\t\t\telementMatchers.push( cached );\n\t\t\t}\n\t\t}\n\n\t\t// Cache the compiled function\n\t\tcached = compilerCache( selector,\n\t\t\tmatcherFromGroupMatchers( elementMatchers, setMatchers ) );\n\n\t\t// Save selector and tokenization\n\t\tcached.selector = selector;\n\t}\n\treturn cached;\n}\n\n/**\n * A low-level selection function that works with jQuery's compiled\n * selector functions\n * @param {String|Function} selector A selector or a pre-compiled\n * selector function built with jQuery selector compile\n * @param {Element} context\n * @param {Array} [results]\n * @param {Array} [seed] A set of elements to match against\n */\nfunction select( selector, context, results, seed ) {\n\tvar i, tokens, token, type, find,\n\t\tcompiled = typeof selector === \"function\" && selector,\n\t\tmatch = !seed && tokenize( ( selector = compiled.selector || selector ) );\n\n\tresults = results || [];\n\n\t// Try to minimize operations if there is only one selector in the list and no seed\n\t// (the latter of which guarantees us context)\n\tif ( match.length === 1 ) {\n\n\t\t// Reduce context if the leading compound selector is an ID\n\t\ttokens = match[ 0 ] = match[ 0 ].slice( 0 );\n\t\tif ( tokens.length > 2 && ( token = tokens[ 0 ] ).type === \"ID\" &&\n\t\t\t\tcontext.nodeType === 9 && documentIsHTML &&\n\t\t\t\tjQuery.expr.relative[ tokens[ 1 ].type ] ) {\n\n\t\t\tcontext = ( jQuery.expr.find.ID(\n\t\t\t\tunescapeSelector( token.matches[ 0 ] ),\n\t\t\t\tcontext\n\t\t\t) || [] )[ 0 ];\n\t\t\tif ( !context ) {\n\t\t\t\treturn results;\n\n\t\t\t// Precompiled matchers will still verify ancestry, so step up a level\n\t\t\t} else if ( compiled ) {\n\t\t\t\tcontext = context.parentNode;\n\t\t\t}\n\n\t\t\tselector = selector.slice( tokens.shift().value.length );\n\t\t}\n\n\t\t// Fetch a seed set for right-to-left matching\n\t\ti = matchExpr.needsContext.test( selector ) ? 0 : tokens.length;\n\t\twhile ( i-- ) {\n\t\t\ttoken = tokens[ i ];\n\n\t\t\t// Abort if we hit a combinator\n\t\t\tif ( jQuery.expr.relative[ ( type = token.type ) ] ) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif ( ( find = jQuery.expr.find[ type ] ) ) {\n\n\t\t\t\t// Search, expanding context for leading sibling combinators\n\t\t\t\tif ( ( seed = find(\n\t\t\t\t\tunescapeSelector( token.matches[ 0 ] ),\n\t\t\t\t\trsibling.test( tokens[ 0 ].type ) &&\n\t\t\t\t\t\ttestContext( context.parentNode ) || context\n\t\t\t\t) ) ) {\n\n\t\t\t\t\t// If seed is empty or no tokens remain, we can return early\n\t\t\t\t\ttokens.splice( i, 1 );\n\t\t\t\t\tselector = seed.length && toSelector( tokens );\n\t\t\t\t\tif ( !selector ) {\n\t\t\t\t\t\tpush.apply( results, seed );\n\t\t\t\t\t\treturn results;\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// Compile and execute a filtering function if one is not provided\n\t// Provide `match` to avoid retokenization if we modified the selector above\n\t( compiled || compile( selector, match ) )(\n\t\tseed,\n\t\tcontext,\n\t\t!documentIsHTML,\n\t\tresults,\n\t\t!context || rsibling.test( selector ) && testContext( context.parentNode ) || context\n\t);\n\treturn results;\n}\n\n// Initialize against the default document\nsetDocument();\n\njQuery.find = find;\n\n// These have always been private, but they used to be documented as part of\n// Sizzle so let's maintain them for now for backwards compatibility purposes.\nfind.compile = compile;\nfind.select = select;\nfind.setDocument = setDocument;\nfind.tokenize = tokenize;\n\nfunction dir( elem, dir, until ) {\n\tvar matched = [],\n\t\ttruncate = until !== undefined;\n\n\twhile ( ( elem = elem[ dir ] ) && elem.nodeType !== 9 ) {\n\t\tif ( elem.nodeType === 1 ) {\n\t\t\tif ( truncate && jQuery( elem ).is( until ) ) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tmatched.push( elem );\n\t\t}\n\t}\n\treturn matched;\n}\n\nfunction siblings( n, elem ) {\n\tvar matched = [];\n\n\tfor ( ; n; n = n.nextSibling ) {\n\t\tif ( n.nodeType === 1 && n !== elem ) {\n\t\t\tmatched.push( n );\n\t\t}\n\t}\n\n\treturn matched;\n}\n\nvar rneedsContext = jQuery.expr.match.needsContext;\n\n// rsingleTag matches a string consisting of a single HTML element with no attributes\n// and captures the element's name\nvar rsingleTag = /^<([a-z][^\\/\\0>:\\x20\\t\\r\\n\\f]*)[\\x20\\t\\r\\n\\f]*\\/?>(?:<\\/\\1>|)$/i;\n\nfunction isObviousHtml( input ) {\n\treturn input[ 0 ] === \"<\" &&\n\t\tinput[ input.length - 1 ] === \">\" &&\n\t\tinput.length >= 3;\n}\n\n// Implement the identical functionality for filter and not\nfunction winnow( elements, qualifier, not ) {\n\tif ( typeof qualifier === \"function\" ) {\n\t\treturn jQuery.grep( elements, function( elem, i ) {\n\t\t\treturn !!qualifier.call( elem, i, elem ) !== not;\n\t\t} );\n\t}\n\n\t// Single element\n\tif ( qualifier.nodeType ) {\n\t\treturn jQuery.grep( elements, function( elem ) {\n\t\t\treturn ( elem === qualifier ) !== not;\n\t\t} );\n\t}\n\n\t// Arraylike of elements (jQuery, arguments, Array)\n\tif ( typeof qualifier !== \"string\" ) {\n\t\treturn jQuery.grep( elements, function( elem ) {\n\t\t\treturn ( indexOf.call( qualifier, elem ) > -1 ) !== not;\n\t\t} );\n\t}\n\n\t// Filtered directly for both simple and complex selectors\n\treturn jQuery.filter( qualifier, elements, not );\n}\n\njQuery.filter = function( expr, elems, not ) {\n\tvar elem = elems[ 0 ];\n\n\tif ( not ) {\n\t\texpr = \":not(\" + expr + \")\";\n\t}\n\n\tif ( elems.length === 1 && elem.nodeType === 1 ) {\n\t\treturn jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : [];\n\t}\n\n\treturn jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) {\n\t\treturn elem.nodeType === 1;\n\t} ) );\n};\n\njQuery.fn.extend( {\n\tfind: function( selector ) {\n\t\tvar i, ret,\n\t\t\tlen = this.length,\n\t\t\tself = this;\n\n\t\tif ( typeof selector !== \"string\" ) {\n\t\t\treturn this.pushStack( jQuery( selector ).filter( function() {\n\t\t\t\tfor ( i = 0; i < len; i++ ) {\n\t\t\t\t\tif ( jQuery.contains( self[ i ], this ) ) {\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} ) );\n\t\t}\n\n\t\tret = this.pushStack( [] );\n\n\t\tfor ( i = 0; i < len; i++ ) {\n\t\t\tjQuery.find( selector, self[ i ], ret );\n\t\t}\n\n\t\treturn len > 1 ? jQuery.uniqueSort( ret ) : ret;\n\t},\n\tfilter: function( selector ) {\n\t\treturn this.pushStack( winnow( this, selector || [], false ) );\n\t},\n\tnot: function( selector ) {\n\t\treturn this.pushStack( winnow( this, selector || [], true ) );\n\t},\n\tis: function( selector ) {\n\t\treturn !!winnow(\n\t\t\tthis,\n\n\t\t\t// If this is a positional/relative selector, check membership in the returned set\n\t\t\t// so $(\"p:first\").is(\"p:last\") won't return true for a doc with two \"p\".\n\t\t\ttypeof selector === \"string\" && rneedsContext.test( selector ) ?\n\t\t\t\tjQuery( selector ) :\n\t\t\t\tselector || [],\n\t\t\tfalse\n\t\t).length;\n\t}\n} );\n\n// Initialize a jQuery object\n\n// A central reference to the root jQuery(document)\nvar rootjQuery,\n\n\t// A simple way to check for HTML strings\n\t// Prioritize #id over to avoid XSS via location.hash (trac-9521)\n\t// Strict HTML recognition (trac-11290: must start with <)\n\t// Shortcut simple #id case for speed\n\trquickExpr = /^(?:\\s*(<[\\w\\W]+>)[^>]*|#([\\w-]+))$/,\n\n\tinit = jQuery.fn.init = function( selector, context ) {\n\t\tvar match, elem;\n\n\t\t// HANDLE: $(\"\"), $(null), $(undefined), $(false)\n\t\tif ( !selector ) {\n\t\t\treturn this;\n\t\t}\n\n\t\t// HANDLE: $(DOMElement)\n\t\tif ( selector.nodeType ) {\n\t\t\tthis[ 0 ] = selector;\n\t\t\tthis.length = 1;\n\t\t\treturn this;\n\n\t\t// HANDLE: $(function)\n\t\t// Shortcut for document ready\n\t\t} else if ( typeof selector === \"function\" ) {\n\t\t\treturn rootjQuery.ready !== undefined ?\n\t\t\t\trootjQuery.ready( selector ) :\n\n\t\t\t\t// Execute immediately if ready is not present\n\t\t\t\tselector( jQuery );\n\n\t\t} else {\n\n\t\t\t// Handle obvious HTML strings\n\t\t\tmatch = selector + \"\";\n\t\t\tif ( isObviousHtml( match ) ) {\n\n\t\t\t\t// Assume that strings that start and end with <> are HTML and skip\n\t\t\t\t// the regex check. This also handles browser-supported HTML wrappers\n\t\t\t\t// like TrustedHTML.\n\t\t\t\tmatch = [ null, selector, null ];\n\n\t\t\t// Handle HTML strings or selectors\n\t\t\t} else if ( typeof selector === \"string\" ) {\n\t\t\t\tmatch = rquickExpr.exec( selector );\n\t\t\t} else {\n\t\t\t\treturn jQuery.makeArray( selector, this );\n\t\t\t}\n\n\t\t\t// Match html or make sure no context is specified for #id\n\t\t\t// Note: match[1] may be a string or a TrustedHTML wrapper\n\t\t\tif ( match && ( match[ 1 ] || !context ) ) {\n\n\t\t\t\t// HANDLE: $(html) -> $(array)\n\t\t\t\tif ( match[ 1 ] ) {\n\t\t\t\t\tcontext = context instanceof jQuery ? context[ 0 ] : context;\n\n\t\t\t\t\t// Option to run scripts is true for back-compat\n\t\t\t\t\t// Intentionally let the error be thrown if parseHTML is not present\n\t\t\t\t\tjQuery.merge( this, jQuery.parseHTML(\n\t\t\t\t\t\tmatch[ 1 ],\n\t\t\t\t\t\tcontext && context.nodeType ? context.ownerDocument || context : document$1,\n\t\t\t\t\t\ttrue\n\t\t\t\t\t) );\n\n\t\t\t\t\t// HANDLE: $(html, props)\n\t\t\t\t\tif ( rsingleTag.test( match[ 1 ] ) && jQuery.isPlainObject( context ) ) {\n\t\t\t\t\t\tfor ( match in context ) {\n\n\t\t\t\t\t\t\t// Properties of context are called as methods if possible\n\t\t\t\t\t\t\tif ( typeof this[ match ] === \"function\" ) {\n\t\t\t\t\t\t\t\tthis[ match ]( context[ match ] );\n\n\t\t\t\t\t\t\t// ...and otherwise set as attributes\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tthis.attr( match, context[ match ] );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\treturn this;\n\n\t\t\t\t// HANDLE: $(#id)\n\t\t\t\t} else {\n\t\t\t\t\telem = document$1.getElementById( match[ 2 ] );\n\n\t\t\t\t\tif ( elem ) {\n\n\t\t\t\t\t\t// Inject the element directly into the jQuery object\n\t\t\t\t\t\tthis[ 0 ] = elem;\n\t\t\t\t\t\tthis.length = 1;\n\t\t\t\t\t}\n\t\t\t\t\treturn this;\n\t\t\t\t}\n\n\t\t\t// HANDLE: $(expr) & $(expr, $(...))\n\t\t\t} else if ( !context || context.jquery ) {\n\t\t\t\treturn ( context || rootjQuery ).find( selector );\n\n\t\t\t// HANDLE: $(expr, context)\n\t\t\t// (which is just equivalent to: $(context).find(expr)\n\t\t\t} else {\n\t\t\t\treturn this.constructor( context ).find( selector );\n\t\t\t}\n\t\t}\n\n\t};\n\n// Give the init function the jQuery prototype for later instantiation\ninit.prototype = jQuery.fn;\n\n// Initialize central reference\nrootjQuery = jQuery( document$1 );\n\nvar rparentsprev = /^(?:parents|prev(?:Until|All))/,\n\n\t// Methods guaranteed to produce a unique set when starting from a unique set\n\tguaranteedUnique = {\n\t\tchildren: true,\n\t\tcontents: true,\n\t\tnext: true,\n\t\tprev: true\n\t};\n\njQuery.fn.extend( {\n\thas: function( target ) {\n\t\tvar targets = jQuery( target, this ),\n\t\t\tl = targets.length;\n\n\t\treturn this.filter( function() {\n\t\t\tvar i = 0;\n\t\t\tfor ( ; i < l; i++ ) {\n\t\t\t\tif ( jQuery.contains( this, targets[ i ] ) ) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\t},\n\n\tclosest: function( selectors, context ) {\n\t\tvar cur,\n\t\t\ti = 0,\n\t\t\tl = this.length,\n\t\t\tmatched = [],\n\t\t\ttargets = typeof selectors !== \"string\" && jQuery( selectors );\n\n\t\t// Positional selectors never match, since there's no _selection_ context\n\t\tif ( !rneedsContext.test( selectors ) ) {\n\t\t\tfor ( ; i < l; i++ ) {\n\t\t\t\tfor ( cur = this[ i ]; cur && cur !== context; cur = cur.parentNode ) {\n\n\t\t\t\t\t// Always skip document fragments\n\t\t\t\t\tif ( cur.nodeType < 11 && ( targets ?\n\t\t\t\t\t\ttargets.index( cur ) > -1 :\n\n\t\t\t\t\t\t// Don't pass non-elements to jQuery#find\n\t\t\t\t\t\tcur.nodeType === 1 &&\n\t\t\t\t\t\t\tjQuery.find.matchesSelector( cur, selectors ) ) ) {\n\n\t\t\t\t\t\tmatched.push( cur );\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn this.pushStack( matched.length > 1 ? jQuery.uniqueSort( matched ) : matched );\n\t},\n\n\t// Determine the position of an element within the set\n\tindex: function( elem ) {\n\n\t\t// No argument, return index in parent\n\t\tif ( !elem ) {\n\t\t\treturn ( this[ 0 ] && this[ 0 ].parentNode ) ? this.first().prevAll().length : -1;\n\t\t}\n\n\t\t// Index in selector\n\t\tif ( typeof elem === \"string\" ) {\n\t\t\treturn indexOf.call( jQuery( elem ), this[ 0 ] );\n\t\t}\n\n\t\t// Locate the position of the desired element\n\t\treturn indexOf.call( this,\n\n\t\t\t// If it receives a jQuery object, the first element is used\n\t\t\telem.jquery ? elem[ 0 ] : elem\n\t\t);\n\t},\n\n\tadd: function( selector, context ) {\n\t\treturn this.pushStack(\n\t\t\tjQuery.uniqueSort(\n\t\t\t\tjQuery.merge( this.get(), jQuery( selector, context ) )\n\t\t\t)\n\t\t);\n\t},\n\n\taddBack: function( selector ) {\n\t\treturn this.add( selector == null ?\n\t\t\tthis.prevObject : this.prevObject.filter( selector )\n\t\t);\n\t}\n} );\n\nfunction sibling( cur, dir ) {\n\twhile ( ( cur = cur[ dir ] ) && cur.nodeType !== 1 ) {}\n\treturn cur;\n}\n\njQuery.each( {\n\tparent: function( elem ) {\n\t\tvar parent = elem.parentNode;\n\t\treturn parent && parent.nodeType !== 11 ? parent : null;\n\t},\n\tparents: function( elem ) {\n\t\treturn dir( elem, \"parentNode\" );\n\t},\n\tparentsUntil: function( elem, _i, until ) {\n\t\treturn dir( elem, \"parentNode\", until );\n\t},\n\tnext: function( elem ) {\n\t\treturn sibling( elem, \"nextSibling\" );\n\t},\n\tprev: function( elem ) {\n\t\treturn sibling( elem, \"previousSibling\" );\n\t},\n\tnextAll: function( elem ) {\n\t\treturn dir( elem, \"nextSibling\" );\n\t},\n\tprevAll: function( elem ) {\n\t\treturn dir( elem, \"previousSibling\" );\n\t},\n\tnextUntil: function( elem, _i, until ) {\n\t\treturn dir( elem, \"nextSibling\", until );\n\t},\n\tprevUntil: function( elem, _i, until ) {\n\t\treturn dir( elem, \"previousSibling\", until );\n\t},\n\tsiblings: function( elem ) {\n\t\treturn siblings( ( elem.parentNode || {} ).firstChild, elem );\n\t},\n\tchildren: function( elem ) {\n\t\treturn siblings( elem.firstChild );\n\t},\n\tcontents: function( elem ) {\n\t\tif ( elem.contentDocument != null &&\n\n\t\t\t// Support: IE 11+\n\t\t\t// elements with no `data` attribute has an object\n\t\t\t// `contentDocument` with a `null` prototype.\n\t\t\tgetProto( elem.contentDocument ) ) {\n\n\t\t\treturn elem.contentDocument;\n\t\t}\n\n\t\t// Support: IE 9 - 11+\n\t\t// Treat the template element as a regular one in browsers that\n\t\t// don't support it.\n\t\tif ( nodeName( elem, \"template\" ) ) {\n\t\t\telem = elem.content || elem;\n\t\t}\n\n\t\treturn jQuery.merge( [], elem.childNodes );\n\t}\n}, function( name, fn ) {\n\tjQuery.fn[ name ] = function( until, selector ) {\n\t\tvar matched = jQuery.map( this, fn, until );\n\n\t\tif ( name.slice( -5 ) !== \"Until\" ) {\n\t\t\tselector = until;\n\t\t}\n\n\t\tif ( selector && typeof selector === \"string\" ) {\n\t\t\tmatched = jQuery.filter( selector, matched );\n\t\t}\n\n\t\tif ( this.length > 1 ) {\n\n\t\t\t// Remove duplicates\n\t\t\tif ( !guaranteedUnique[ name ] ) {\n\t\t\t\tjQuery.uniqueSort( matched );\n\t\t\t}\n\n\t\t\t// Reverse order for parents* and prev-derivatives\n\t\t\tif ( rparentsprev.test( name ) ) {\n\t\t\t\tmatched.reverse();\n\t\t\t}\n\t\t}\n\n\t\treturn this.pushStack( matched );\n\t};\n} );\n\n// Convert String-formatted options into Object-formatted ones\nfunction createOptions( options ) {\n\tvar object = {};\n\tjQuery.each( options.match( rnothtmlwhite ) || [], function( _, flag ) {\n\t\tobject[ flag ] = true;\n\t} );\n\treturn object;\n}\n\n/*\n * Create a callback list using the following parameters:\n *\n *\toptions: an optional list of space-separated options that will change how\n *\t\t\tthe callback list behaves or a more traditional option object\n *\n * By default a callback list will act like an event callback list and can be\n * \"fired\" multiple times.\n *\n * Possible options:\n *\n *\tonce:\t\t\twill ensure the callback list can only be fired once (like a Deferred)\n *\n *\tmemory:\t\t\twill keep track of previous values and will call any callback added\n *\t\t\t\t\tafter the list has been fired right away with the latest \"memorized\"\n *\t\t\t\t\tvalues (like a Deferred)\n *\n *\tunique:\t\t\twill ensure a callback can only be added once (no duplicate in the list)\n *\n *\tstopOnFalse:\tinterrupt callings when a callback returns false\n *\n */\njQuery.Callbacks = function( options ) {\n\n\t// Convert options from String-formatted to Object-formatted if needed\n\t// (we check in cache first)\n\toptions = typeof options === \"string\" ?\n\t\tcreateOptions( options ) :\n\t\tjQuery.extend( {}, options );\n\n\tvar // Flag to know if list is currently firing\n\t\tfiring,\n\n\t\t// Last fire value for non-forgettable lists\n\t\tmemory,\n\n\t\t// Flag to know if list was already fired\n\t\tfired,\n\n\t\t// Flag to prevent firing\n\t\tlocked,\n\n\t\t// Actual callback list\n\t\tlist = [],\n\n\t\t// Queue of execution data for repeatable lists\n\t\tqueue = [],\n\n\t\t// Index of currently firing callback (modified by add/remove as needed)\n\t\tfiringIndex = -1,\n\n\t\t// Fire callbacks\n\t\tfire = function() {\n\n\t\t\t// Enforce single-firing\n\t\t\tlocked = locked || options.once;\n\n\t\t\t// Execute callbacks for all pending executions,\n\t\t\t// respecting firingIndex overrides and runtime changes\n\t\t\tfired = firing = true;\n\t\t\tfor ( ; queue.length; firingIndex = -1 ) {\n\t\t\t\tmemory = queue.shift();\n\t\t\t\twhile ( ++firingIndex < list.length ) {\n\n\t\t\t\t\t// Run callback and check for early termination\n\t\t\t\t\tif ( list[ firingIndex ].apply( memory[ 0 ], memory[ 1 ] ) === false &&\n\t\t\t\t\t\toptions.stopOnFalse ) {\n\n\t\t\t\t\t\t// Jump to end and forget the data so .add doesn't re-fire\n\t\t\t\t\t\tfiringIndex = list.length;\n\t\t\t\t\t\tmemory = false;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Forget the data if we're done with it\n\t\t\tif ( !options.memory ) {\n\t\t\t\tmemory = false;\n\t\t\t}\n\n\t\t\tfiring = false;\n\n\t\t\t// Clean up if we're done firing for good\n\t\t\tif ( locked ) {\n\n\t\t\t\t// Keep an empty list if we have data for future add calls\n\t\t\t\tif ( memory ) {\n\t\t\t\t\tlist = [];\n\n\t\t\t\t// Otherwise, this object is spent\n\t\t\t\t} else {\n\t\t\t\t\tlist = \"\";\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\n\t\t// Actual Callbacks object\n\t\tself = {\n\n\t\t\t// Add a callback or a collection of callbacks to the list\n\t\t\tadd: function() {\n\t\t\t\tif ( list ) {\n\n\t\t\t\t\t// If we have memory from a past run, we should fire after adding\n\t\t\t\t\tif ( memory && !firing ) {\n\t\t\t\t\t\tfiringIndex = list.length - 1;\n\t\t\t\t\t\tqueue.push( memory );\n\t\t\t\t\t}\n\n\t\t\t\t\t( function add( args ) {\n\t\t\t\t\t\tjQuery.each( args, function( _, arg ) {\n\t\t\t\t\t\t\tif ( typeof arg === \"function\" ) {\n\t\t\t\t\t\t\t\tif ( !options.unique || !self.has( arg ) ) {\n\t\t\t\t\t\t\t\t\tlist.push( arg );\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t} else if ( arg && arg.length && toType( arg ) !== \"string\" ) {\n\n\t\t\t\t\t\t\t\t// Inspect recursively\n\t\t\t\t\t\t\t\tadd( arg );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} );\n\t\t\t\t\t} )( arguments );\n\n\t\t\t\t\tif ( memory && !firing ) {\n\t\t\t\t\t\tfire();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn this;\n\t\t\t},\n\n\t\t\t// Remove a callback from the list\n\t\t\tremove: function() {\n\t\t\t\tjQuery.each( arguments, function( _, arg ) {\n\t\t\t\t\tvar index;\n\t\t\t\t\twhile ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) {\n\t\t\t\t\t\tlist.splice( index, 1 );\n\n\t\t\t\t\t\t// Handle firing indexes\n\t\t\t\t\t\tif ( index <= firingIndex ) {\n\t\t\t\t\t\t\tfiringIndex--;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} );\n\t\t\t\treturn this;\n\t\t\t},\n\n\t\t\t// Check if a given callback is in the list.\n\t\t\t// If no argument is given, return whether or not list has callbacks attached.\n\t\t\thas: function( fn ) {\n\t\t\t\treturn fn ?\n\t\t\t\t\tjQuery.inArray( fn, list ) > -1 :\n\t\t\t\t\tlist.length > 0;\n\t\t\t},\n\n\t\t\t// Remove all callbacks from the list\n\t\t\tempty: function() {\n\t\t\t\tif ( list ) {\n\t\t\t\t\tlist = [];\n\t\t\t\t}\n\t\t\t\treturn this;\n\t\t\t},\n\n\t\t\t// Disable .fire and .add\n\t\t\t// Abort any current/pending executions\n\t\t\t// Clear all callbacks and values\n\t\t\tdisable: function() {\n\t\t\t\tlocked = queue = [];\n\t\t\t\tlist = memory = \"\";\n\t\t\t\treturn this;\n\t\t\t},\n\t\t\tdisabled: function() {\n\t\t\t\treturn !list;\n\t\t\t},\n\n\t\t\t// Disable .fire\n\t\t\t// Also disable .add unless we have memory (since it would have no effect)\n\t\t\t// Abort any pending executions\n\t\t\tlock: function() {\n\t\t\t\tlocked = queue = [];\n\t\t\t\tif ( !memory && !firing ) {\n\t\t\t\t\tlist = memory = \"\";\n\t\t\t\t}\n\t\t\t\treturn this;\n\t\t\t},\n\t\t\tlocked: function() {\n\t\t\t\treturn !!locked;\n\t\t\t},\n\n\t\t\t// Call all callbacks with the given context and arguments\n\t\t\tfireWith: function( context, args ) {\n\t\t\t\tif ( !locked ) {\n\t\t\t\t\targs = args || [];\n\t\t\t\t\targs = [ context, args.slice ? args.slice() : args ];\n\t\t\t\t\tqueue.push( args );\n\t\t\t\t\tif ( !firing ) {\n\t\t\t\t\t\tfire();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn this;\n\t\t\t},\n\n\t\t\t// Call all the callbacks with the given arguments\n\t\t\tfire: function() {\n\t\t\t\tself.fireWith( this, arguments );\n\t\t\t\treturn this;\n\t\t\t},\n\n\t\t\t// To know if the callbacks have already been called at least once\n\t\t\tfired: function() {\n\t\t\t\treturn !!fired;\n\t\t\t}\n\t\t};\n\n\treturn self;\n};\n\nfunction Identity( v ) {\n\treturn v;\n}\nfunction Thrower( ex ) {\n\tthrow ex;\n}\n\nfunction adoptValue( value, resolve, reject, noValue ) {\n\tvar method;\n\n\ttry {\n\n\t\t// Check for promise aspect first to privilege synchronous behavior\n\t\tif ( value && typeof( method = value.promise ) === \"function\" ) {\n\t\t\tmethod.call( value ).done( resolve ).fail( reject );\n\n\t\t// Other thenables\n\t\t} else if ( value && typeof( method = value.then ) === \"function\" ) {\n\t\t\tmethod.call( value, resolve, reject );\n\n\t\t// Other non-thenables\n\t\t} else {\n\n\t\t\t// Control `resolve` arguments by letting Array#slice cast boolean `noValue` to integer:\n\t\t\t// * false: [ value ].slice( 0 ) => resolve( value )\n\t\t\t// * true: [ value ].slice( 1 ) => resolve()\n\t\t\tresolve.apply( undefined, [ value ].slice( noValue ) );\n\t\t}\n\n\t// For Promises/A+, convert exceptions into rejections\n\t// Since jQuery.when doesn't unwrap thenables, we can skip the extra checks appearing in\n\t// Deferred#then to conditionally suppress rejection.\n\t} catch ( value ) {\n\t\treject( value );\n\t}\n}\n\njQuery.extend( {\n\n\tDeferred: function( func ) {\n\t\tvar tuples = [\n\n\t\t\t\t// action, add listener, callbacks,\n\t\t\t\t// ... .then handlers, argument index, [final state]\n\t\t\t\t[ \"notify\", \"progress\", jQuery.Callbacks( \"memory\" ),\n\t\t\t\t\tjQuery.Callbacks( \"memory\" ), 2 ],\n\t\t\t\t[ \"resolve\", \"done\", jQuery.Callbacks( \"once memory\" ),\n\t\t\t\t\tjQuery.Callbacks( \"once memory\" ), 0, \"resolved\" ],\n\t\t\t\t[ \"reject\", \"fail\", jQuery.Callbacks( \"once memory\" ),\n\t\t\t\t\tjQuery.Callbacks( \"once memory\" ), 1, \"rejected\" ]\n\t\t\t],\n\t\t\tstate = \"pending\",\n\t\t\tpromise = {\n\t\t\t\tstate: function() {\n\t\t\t\t\treturn state;\n\t\t\t\t},\n\t\t\t\talways: function() {\n\t\t\t\t\tdeferred.done( arguments ).fail( arguments );\n\t\t\t\t\treturn this;\n\t\t\t\t},\n\t\t\t\tcatch: function( fn ) {\n\t\t\t\t\treturn promise.then( null, fn );\n\t\t\t\t},\n\n\t\t\t\t// Keep pipe for back-compat\n\t\t\t\tpipe: function( /* fnDone, fnFail, fnProgress */ ) {\n\t\t\t\t\tvar fns = arguments;\n\n\t\t\t\t\treturn jQuery.Deferred( function( newDefer ) {\n\t\t\t\t\t\tjQuery.each( tuples, function( _i, tuple ) {\n\n\t\t\t\t\t\t\t// Map tuples (progress, done, fail) to arguments (done, fail, progress)\n\t\t\t\t\t\t\tvar fn = typeof fns[ tuple[ 4 ] ] === \"function\" &&\n\t\t\t\t\t\t\t\tfns[ tuple[ 4 ] ];\n\n\t\t\t\t\t\t\t// deferred.progress(function() { bind to newDefer or newDefer.notify })\n\t\t\t\t\t\t\t// deferred.done(function() { bind to newDefer or newDefer.resolve })\n\t\t\t\t\t\t\t// deferred.fail(function() { bind to newDefer or newDefer.reject })\n\t\t\t\t\t\t\tdeferred[ tuple[ 1 ] ]( function() {\n\t\t\t\t\t\t\t\tvar returned = fn && fn.apply( this, arguments );\n\t\t\t\t\t\t\t\tif ( returned && typeof returned.promise === \"function\" ) {\n\t\t\t\t\t\t\t\t\treturned.promise()\n\t\t\t\t\t\t\t\t\t\t.progress( newDefer.notify )\n\t\t\t\t\t\t\t\t\t\t.done( newDefer.resolve )\n\t\t\t\t\t\t\t\t\t\t.fail( newDefer.reject );\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tnewDefer[ tuple[ 0 ] + \"With\" ](\n\t\t\t\t\t\t\t\t\t\tthis,\n\t\t\t\t\t\t\t\t\t\tfn ? [ returned ] : arguments\n\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t} );\n\t\t\t\t\t\t} );\n\t\t\t\t\t\tfns = null;\n\t\t\t\t\t} ).promise();\n\t\t\t\t},\n\t\t\t\tthen: function( onFulfilled, onRejected, onProgress ) {\n\t\t\t\t\tvar maxDepth = 0;\n\t\t\t\t\tfunction resolve( depth, deferred, handler, special ) {\n\t\t\t\t\t\treturn function() {\n\t\t\t\t\t\t\tvar that = this,\n\t\t\t\t\t\t\t\targs = arguments,\n\t\t\t\t\t\t\t\tmightThrow = function() {\n\t\t\t\t\t\t\t\t\tvar returned, then;\n\n\t\t\t\t\t\t\t\t\t// Support: Promises/A+ section 2.3.3.3.3\n\t\t\t\t\t\t\t\t\t// https://promisesaplus.com/#point-59\n\t\t\t\t\t\t\t\t\t// Ignore double-resolution attempts\n\t\t\t\t\t\t\t\t\tif ( depth < maxDepth ) {\n\t\t\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\treturned = handler.apply( that, args );\n\n\t\t\t\t\t\t\t\t\t// Support: Promises/A+ section 2.3.1\n\t\t\t\t\t\t\t\t\t// https://promisesaplus.com/#point-48\n\t\t\t\t\t\t\t\t\tif ( returned === deferred.promise() ) {\n\t\t\t\t\t\t\t\t\t\tthrow new TypeError( \"Thenable self-resolution\" );\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t// Support: Promises/A+ sections 2.3.3.1, 3.5\n\t\t\t\t\t\t\t\t\t// https://promisesaplus.com/#point-54\n\t\t\t\t\t\t\t\t\t// https://promisesaplus.com/#point-75\n\t\t\t\t\t\t\t\t\t// Retrieve `then` only once\n\t\t\t\t\t\t\t\t\tthen = returned &&\n\n\t\t\t\t\t\t\t\t\t\t// Support: Promises/A+ section 2.3.4\n\t\t\t\t\t\t\t\t\t\t// https://promisesaplus.com/#point-64\n\t\t\t\t\t\t\t\t\t\t// Only check objects and functions for thenability\n\t\t\t\t\t\t\t\t\t\t( typeof returned === \"object\" ||\n\t\t\t\t\t\t\t\t\t\t\ttypeof returned === \"function\" ) &&\n\t\t\t\t\t\t\t\t\t\treturned.then;\n\n\t\t\t\t\t\t\t\t\t// Handle a returned thenable\n\t\t\t\t\t\t\t\t\tif ( typeof then === \"function\" ) {\n\n\t\t\t\t\t\t\t\t\t\t// Special processors (notify) just wait for resolution\n\t\t\t\t\t\t\t\t\t\tif ( special ) {\n\t\t\t\t\t\t\t\t\t\t\tthen.call(\n\t\t\t\t\t\t\t\t\t\t\t\treturned,\n\t\t\t\t\t\t\t\t\t\t\t\tresolve( maxDepth, deferred, Identity, special ),\n\t\t\t\t\t\t\t\t\t\t\t\tresolve( maxDepth, deferred, Thrower, special )\n\t\t\t\t\t\t\t\t\t\t\t);\n\n\t\t\t\t\t\t\t\t\t\t// Normal processors (resolve) also hook into progress\n\t\t\t\t\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t\t\t\t\t// ...and disregard older resolution values\n\t\t\t\t\t\t\t\t\t\t\tmaxDepth++;\n\n\t\t\t\t\t\t\t\t\t\t\tthen.call(\n\t\t\t\t\t\t\t\t\t\t\t\treturned,\n\t\t\t\t\t\t\t\t\t\t\t\tresolve( maxDepth, deferred, Identity, special ),\n\t\t\t\t\t\t\t\t\t\t\t\tresolve( maxDepth, deferred, Thrower, special ),\n\t\t\t\t\t\t\t\t\t\t\t\tresolve( maxDepth, deferred, Identity,\n\t\t\t\t\t\t\t\t\t\t\t\t\tdeferred.notifyWith )\n\t\t\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t// Handle all other returned values\n\t\t\t\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t\t\t\t// Only substitute handlers pass on context\n\t\t\t\t\t\t\t\t\t\t// and multiple values (non-spec behavior)\n\t\t\t\t\t\t\t\t\t\tif ( handler !== Identity ) {\n\t\t\t\t\t\t\t\t\t\t\tthat = undefined;\n\t\t\t\t\t\t\t\t\t\t\targs = [ returned ];\n\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t\t// Process the value(s)\n\t\t\t\t\t\t\t\t\t\t// Default process is resolve\n\t\t\t\t\t\t\t\t\t\t( special || deferred.resolveWith )( that, args );\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t},\n\n\t\t\t\t\t\t\t\t// Only normal processors (resolve) catch and reject exceptions\n\t\t\t\t\t\t\t\tprocess = special ?\n\t\t\t\t\t\t\t\t\tmightThrow :\n\t\t\t\t\t\t\t\t\tfunction() {\n\t\t\t\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t\t\t\tmightThrow();\n\t\t\t\t\t\t\t\t\t\t} catch ( e ) {\n\n\t\t\t\t\t\t\t\t\t\t\tif ( jQuery.Deferred.exceptionHook ) {\n\t\t\t\t\t\t\t\t\t\t\t\tjQuery.Deferred.exceptionHook( e,\n\t\t\t\t\t\t\t\t\t\t\t\t\tprocess.error );\n\t\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t\t\t// Support: Promises/A+ section 2.3.3.3.4.1\n\t\t\t\t\t\t\t\t\t\t\t// https://promisesaplus.com/#point-61\n\t\t\t\t\t\t\t\t\t\t\t// Ignore post-resolution exceptions\n\t\t\t\t\t\t\t\t\t\t\tif ( depth + 1 >= maxDepth ) {\n\n\t\t\t\t\t\t\t\t\t\t\t\t// Only substitute handlers pass on context\n\t\t\t\t\t\t\t\t\t\t\t\t// and multiple values (non-spec behavior)\n\t\t\t\t\t\t\t\t\t\t\t\tif ( handler !== Thrower ) {\n\t\t\t\t\t\t\t\t\t\t\t\t\tthat = undefined;\n\t\t\t\t\t\t\t\t\t\t\t\t\targs = [ e ];\n\t\t\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t\t\t\tdeferred.rejectWith( that, args );\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t};\n\n\t\t\t\t\t\t\t// Support: Promises/A+ section 2.3.3.3.1\n\t\t\t\t\t\t\t// https://promisesaplus.com/#point-57\n\t\t\t\t\t\t\t// Re-resolve promises immediately to dodge false rejection from\n\t\t\t\t\t\t\t// subsequent errors\n\t\t\t\t\t\t\tif ( depth ) {\n\t\t\t\t\t\t\t\tprocess();\n\t\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t\t// Call an optional hook to record the error, in case of exception\n\t\t\t\t\t\t\t\t// since it's otherwise lost when execution goes async\n\t\t\t\t\t\t\t\tif ( jQuery.Deferred.getErrorHook ) {\n\t\t\t\t\t\t\t\t\tprocess.error = jQuery.Deferred.getErrorHook();\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\twindow.setTimeout( process );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\n\t\t\t\t\treturn jQuery.Deferred( function( newDefer ) {\n\n\t\t\t\t\t\t// progress_handlers.add( ... )\n\t\t\t\t\t\ttuples[ 0 ][ 3 ].add(\n\t\t\t\t\t\t\tresolve(\n\t\t\t\t\t\t\t\t0,\n\t\t\t\t\t\t\t\tnewDefer,\n\t\t\t\t\t\t\t\ttypeof onProgress === \"function\" ?\n\t\t\t\t\t\t\t\t\tonProgress :\n\t\t\t\t\t\t\t\t\tIdentity,\n\t\t\t\t\t\t\t\tnewDefer.notifyWith\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\t// fulfilled_handlers.add( ... )\n\t\t\t\t\t\ttuples[ 1 ][ 3 ].add(\n\t\t\t\t\t\t\tresolve(\n\t\t\t\t\t\t\t\t0,\n\t\t\t\t\t\t\t\tnewDefer,\n\t\t\t\t\t\t\t\ttypeof onFulfilled === \"function\" ?\n\t\t\t\t\t\t\t\t\tonFulfilled :\n\t\t\t\t\t\t\t\t\tIdentity\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\t// rejected_handlers.add( ... )\n\t\t\t\t\t\ttuples[ 2 ][ 3 ].add(\n\t\t\t\t\t\t\tresolve(\n\t\t\t\t\t\t\t\t0,\n\t\t\t\t\t\t\t\tnewDefer,\n\t\t\t\t\t\t\t\ttypeof onRejected === \"function\" ?\n\t\t\t\t\t\t\t\t\tonRejected :\n\t\t\t\t\t\t\t\t\tThrower\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t);\n\t\t\t\t\t} ).promise();\n\t\t\t\t},\n\n\t\t\t\t// Get a promise for this deferred\n\t\t\t\t// If obj is provided, the promise aspect is added to the object\n\t\t\t\tpromise: function( obj ) {\n\t\t\t\t\treturn obj != null ? jQuery.extend( obj, promise ) : promise;\n\t\t\t\t}\n\t\t\t},\n\t\t\tdeferred = {};\n\n\t\t// Add list-specific methods\n\t\tjQuery.each( tuples, function( i, tuple ) {\n\t\t\tvar list = tuple[ 2 ],\n\t\t\t\tstateString = tuple[ 5 ];\n\n\t\t\t// promise.progress = list.add\n\t\t\t// promise.done = list.add\n\t\t\t// promise.fail = list.add\n\t\t\tpromise[ tuple[ 1 ] ] = list.add;\n\n\t\t\t// Handle state\n\t\t\tif ( stateString ) {\n\t\t\t\tlist.add(\n\t\t\t\t\tfunction() {\n\n\t\t\t\t\t\t// state = \"resolved\" (i.e., fulfilled)\n\t\t\t\t\t\t// state = \"rejected\"\n\t\t\t\t\t\tstate = stateString;\n\t\t\t\t\t},\n\n\t\t\t\t\t// rejected_callbacks.disable\n\t\t\t\t\t// fulfilled_callbacks.disable\n\t\t\t\t\ttuples[ 3 - i ][ 2 ].disable,\n\n\t\t\t\t\t// rejected_handlers.disable\n\t\t\t\t\t// fulfilled_handlers.disable\n\t\t\t\t\ttuples[ 3 - i ][ 3 ].disable,\n\n\t\t\t\t\t// progress_callbacks.lock\n\t\t\t\t\ttuples[ 0 ][ 2 ].lock,\n\n\t\t\t\t\t// progress_handlers.lock\n\t\t\t\t\ttuples[ 0 ][ 3 ].lock\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t// progress_handlers.fire\n\t\t\t// fulfilled_handlers.fire\n\t\t\t// rejected_handlers.fire\n\t\t\tlist.add( tuple[ 3 ].fire );\n\n\t\t\t// deferred.notify = function() { deferred.notifyWith(...) }\n\t\t\t// deferred.resolve = function() { deferred.resolveWith(...) }\n\t\t\t// deferred.reject = function() { deferred.rejectWith(...) }\n\t\t\tdeferred[ tuple[ 0 ] ] = function() {\n\t\t\t\tdeferred[ tuple[ 0 ] + \"With\" ]( this === deferred ? undefined : this, arguments );\n\t\t\t\treturn this;\n\t\t\t};\n\n\t\t\t// deferred.notifyWith = list.fireWith\n\t\t\t// deferred.resolveWith = list.fireWith\n\t\t\t// deferred.rejectWith = list.fireWith\n\t\t\tdeferred[ tuple[ 0 ] + \"With\" ] = list.fireWith;\n\t\t} );\n\n\t\t// Make the deferred a promise\n\t\tpromise.promise( deferred );\n\n\t\t// Call given func if any\n\t\tif ( func ) {\n\t\t\tfunc.call( deferred, deferred );\n\t\t}\n\n\t\t// All done!\n\t\treturn deferred;\n\t},\n\n\t// Deferred helper\n\twhen: function( singleValue ) {\n\t\tvar\n\n\t\t\t// count of uncompleted subordinates\n\t\t\tremaining = arguments.length,\n\n\t\t\t// count of unprocessed arguments\n\t\t\ti = remaining,\n\n\t\t\t// subordinate fulfillment data\n\t\t\tresolveContexts = Array( i ),\n\t\t\tresolveValues = slice.call( arguments ),\n\n\t\t\t// the primary Deferred\n\t\t\tprimary = jQuery.Deferred(),\n\n\t\t\t// subordinate callback factory\n\t\t\tupdateFunc = function( i ) {\n\t\t\t\treturn function( value ) {\n\t\t\t\t\tresolveContexts[ i ] = this;\n\t\t\t\t\tresolveValues[ i ] = arguments.length > 1 ? slice.call( arguments ) : value;\n\t\t\t\t\tif ( !( --remaining ) ) {\n\t\t\t\t\t\tprimary.resolveWith( resolveContexts, resolveValues );\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t};\n\n\t\t// Single- and empty arguments are adopted like Promise.resolve\n\t\tif ( remaining <= 1 ) {\n\t\t\tadoptValue( singleValue, primary.done( updateFunc( i ) ).resolve, primary.reject,\n\t\t\t\t!remaining );\n\n\t\t\t// Use .then() to unwrap secondary thenables (cf. gh-3000)\n\t\t\tif ( primary.state() === \"pending\" ||\n\t\t\t\ttypeof( resolveValues[ i ] && resolveValues[ i ].then ) === \"function\" ) {\n\n\t\t\t\treturn primary.then();\n\t\t\t}\n\t\t}\n\n\t\t// Multiple arguments are aggregated like Promise.all array elements\n\t\twhile ( i-- ) {\n\t\t\tadoptValue( resolveValues[ i ], updateFunc( i ), primary.reject );\n\t\t}\n\n\t\treturn primary.promise();\n\t}\n} );\n\n// These usually indicate a programmer mistake during development,\n// warn about them ASAP rather than swallowing them by default.\nvar rerrorNames = /^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/;\n\n// If `jQuery.Deferred.getErrorHook` is defined, `asyncError` is an error\n// captured before the async barrier to get the original error cause\n// which may otherwise be hidden.\njQuery.Deferred.exceptionHook = function( error, asyncError ) {\n\n\tif ( error && rerrorNames.test( error.name ) ) {\n\t\twindow.console.warn(\n\t\t\t\"jQuery.Deferred exception\",\n\t\t\terror,\n\t\t\tasyncError\n\t\t);\n\t}\n};\n\njQuery.readyException = function( error ) {\n\twindow.setTimeout( function() {\n\t\tthrow error;\n\t} );\n};\n\n// The deferred used on DOM ready\nvar readyList = jQuery.Deferred();\n\njQuery.fn.ready = function( fn ) {\n\n\treadyList\n\t\t.then( fn )\n\n\t\t// Wrap jQuery.readyException in a function so that the lookup\n\t\t// happens at the time of error handling instead of callback\n\t\t// registration.\n\t\t.catch( function( error ) {\n\t\t\tjQuery.readyException( error );\n\t\t} );\n\n\treturn this;\n};\n\njQuery.extend( {\n\n\t// Is the DOM ready to be used? Set to true once it occurs.\n\tisReady: false,\n\n\t// A counter to track how many items to wait for before\n\t// the ready event fires. See trac-6781\n\treadyWait: 1,\n\n\t// Handle when the DOM is ready\n\tready: function( wait ) {\n\n\t\t// Abort if there are pending holds or we're already ready\n\t\tif ( wait === true ? --jQuery.readyWait : jQuery.isReady ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Remember that the DOM is ready\n\t\tjQuery.isReady = true;\n\n\t\t// If a normal DOM Ready event fired, decrement, and wait if need be\n\t\tif ( wait !== true && --jQuery.readyWait > 0 ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// If there are functions bound, to execute\n\t\treadyList.resolveWith( document$1, [ jQuery ] );\n\t}\n} );\n\njQuery.ready.then = readyList.then;\n\n// The ready event handler and self cleanup method\nfunction completed() {\n\tdocument$1.removeEventListener( \"DOMContentLoaded\", completed );\n\twindow.removeEventListener( \"load\", completed );\n\tjQuery.ready();\n}\n\n// Catch cases where $(document).ready() is called\n// after the browser event has already occurred.\nif ( document$1.readyState !== \"loading\" ) {\n\n\t// Handle it asynchronously to allow scripts the opportunity to delay ready\n\twindow.setTimeout( jQuery.ready );\n\n} else {\n\n\t// Use the handy event callback\n\tdocument$1.addEventListener( \"DOMContentLoaded\", completed );\n\n\t// A fallback to window.onload, that will always work\n\twindow.addEventListener( \"load\", completed );\n}\n\n// Matches dashed string for camelizing\nvar rdashAlpha = /-([a-z])/g;\n\n// Used by camelCase as callback to replace()\nfunction fcamelCase( _all, letter ) {\n\treturn letter.toUpperCase();\n}\n\n// Convert dashed to camelCase\nfunction camelCase( string ) {\n\treturn string.replace( rdashAlpha, fcamelCase );\n}\n\n/**\n * Determines whether an object can have data\n */\nfunction acceptData( owner ) {\n\n\t// Accepts only:\n\t// - Node\n\t// - Node.ELEMENT_NODE\n\t// - Node.DOCUMENT_NODE\n\t// - Object\n\t// - Any\n\treturn owner.nodeType === 1 || owner.nodeType === 9 || !( +owner.nodeType );\n}\n\nfunction Data() {\n\tthis.expando = jQuery.expando + Data.uid++;\n}\n\nData.uid = 1;\n\nData.prototype = {\n\n\tcache: function( owner ) {\n\n\t\t// Check if the owner object already has a cache\n\t\tvar value = owner[ this.expando ];\n\n\t\t// If not, create one\n\t\tif ( !value ) {\n\t\t\tvalue = Object.create( null );\n\n\t\t\t// We can accept data for non-element nodes in modern browsers,\n\t\t\t// but we should not, see trac-8335.\n\t\t\t// Always return an empty object.\n\t\t\tif ( acceptData( owner ) ) {\n\n\t\t\t\t// If it is a node unlikely to be stringify-ed or looped over\n\t\t\t\t// use plain assignment\n\t\t\t\tif ( owner.nodeType ) {\n\t\t\t\t\towner[ this.expando ] = value;\n\n\t\t\t\t// Otherwise secure it in a non-enumerable property\n\t\t\t\t// configurable must be true to allow the property to be\n\t\t\t\t// deleted when data is removed\n\t\t\t\t} else {\n\t\t\t\t\tObject.defineProperty( owner, this.expando, {\n\t\t\t\t\t\tvalue: value,\n\t\t\t\t\t\tconfigurable: true\n\t\t\t\t\t} );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn value;\n\t},\n\tset: function( owner, data, value ) {\n\t\tvar prop,\n\t\t\tcache = this.cache( owner );\n\n\t\t// Handle: [ owner, key, value ] args\n\t\t// Always use camelCase key (gh-2257)\n\t\tif ( typeof data === \"string\" ) {\n\t\t\tcache[ camelCase( data ) ] = value;\n\n\t\t// Handle: [ owner, { properties } ] args\n\t\t} else {\n\n\t\t\t// Copy the properties one-by-one to the cache object\n\t\t\tfor ( prop in data ) {\n\t\t\t\tcache[ camelCase( prop ) ] = data[ prop ];\n\t\t\t}\n\t\t}\n\t\treturn value;\n\t},\n\tget: function( owner, key ) {\n\t\treturn key === undefined ?\n\t\t\tthis.cache( owner ) :\n\n\t\t\t// Always use camelCase key (gh-2257)\n\t\t\towner[ this.expando ] && owner[ this.expando ][ camelCase( key ) ];\n\t},\n\taccess: function( owner, key, value ) {\n\n\t\t// In cases where either:\n\t\t//\n\t\t// 1. No key was specified\n\t\t// 2. A string key was specified, but no value provided\n\t\t//\n\t\t// Take the \"read\" path and allow the get method to determine\n\t\t// which value to return, respectively either:\n\t\t//\n\t\t// 1. The entire cache object\n\t\t// 2. The data stored at the key\n\t\t//\n\t\tif ( key === undefined ||\n\t\t\t\t( ( key && typeof key === \"string\" ) && value === undefined ) ) {\n\n\t\t\treturn this.get( owner, key );\n\t\t}\n\n\t\t// When the key is not a string, or both a key and value\n\t\t// are specified, set or extend (existing objects) with either:\n\t\t//\n\t\t// 1. An object of properties\n\t\t// 2. A key and value\n\t\t//\n\t\tthis.set( owner, key, value );\n\n\t\t// Since the \"set\" path can have two possible entry points\n\t\t// return the expected data based on which path was taken[*]\n\t\treturn value !== undefined ? value : key;\n\t},\n\tremove: function( owner, key ) {\n\t\tvar i,\n\t\t\tcache = owner[ this.expando ];\n\n\t\tif ( cache === undefined ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( key !== undefined ) {\n\n\t\t\t// Support array or space separated string of keys\n\t\t\tif ( Array.isArray( key ) ) {\n\n\t\t\t\t// If key is an array of keys...\n\t\t\t\t// We always set camelCase keys, so remove that.\n\t\t\t\tkey = key.map( camelCase );\n\t\t\t} else {\n\t\t\t\tkey = camelCase( key );\n\n\t\t\t\t// If a key with the spaces exists, use it.\n\t\t\t\t// Otherwise, create an array by matching non-whitespace\n\t\t\t\tkey = key in cache ?\n\t\t\t\t\t[ key ] :\n\t\t\t\t\t( key.match( rnothtmlwhite ) || [] );\n\t\t\t}\n\n\t\t\ti = key.length;\n\n\t\t\twhile ( i-- ) {\n\t\t\t\tdelete cache[ key[ i ] ];\n\t\t\t}\n\t\t}\n\n\t\t// Remove the expando if there's no more data\n\t\tif ( key === undefined || jQuery.isEmptyObject( cache ) ) {\n\n\t\t\t// Support: Chrome <=35 - 45+\n\t\t\t// Webkit & Blink performance suffers when deleting properties\n\t\t\t// from DOM nodes, so set to undefined instead\n\t\t\t// https://bugs.chromium.org/p/chromium/issues/detail?id=378607 (bug restricted)\n\t\t\tif ( owner.nodeType ) {\n\t\t\t\towner[ this.expando ] = undefined;\n\t\t\t} else {\n\t\t\t\tdelete owner[ this.expando ];\n\t\t\t}\n\t\t}\n\t},\n\thasData: function( owner ) {\n\t\tvar cache = owner[ this.expando ];\n\t\treturn cache !== undefined && !jQuery.isEmptyObject( cache );\n\t}\n};\n\nvar dataPriv = new Data();\n\nvar dataUser = new Data();\n\n//\tImplementation Summary\n//\n//\t1. Enforce API surface and semantic compatibility with 1.9.x branch\n//\t2. Improve the module's maintainability by reducing the storage\n//\t\tpaths to a single mechanism.\n//\t3. Use the same single mechanism to support \"private\" and \"user\" data.\n//\t4. _Never_ expose \"private\" data to user code (TODO: Drop _data, _removeData)\n//\t5. Avoid exposing implementation details on user objects (eg. expando properties)\n//\t6. Provide a clear path for implementation upgrade to WeakMap in 2014\n\nvar rbrace = /^(?:\\{[\\w\\W]*\\}|\\[[\\w\\W]*\\])$/,\n\trmultiDash = /[A-Z]/g;\n\nfunction getData( data ) {\n\tif ( data === \"true\" ) {\n\t\treturn true;\n\t}\n\n\tif ( data === \"false\" ) {\n\t\treturn false;\n\t}\n\n\tif ( data === \"null\" ) {\n\t\treturn null;\n\t}\n\n\t// Only convert to a number if it doesn't change the string\n\tif ( data === +data + \"\" ) {\n\t\treturn +data;\n\t}\n\n\tif ( rbrace.test( data ) ) {\n\t\treturn JSON.parse( data );\n\t}\n\n\treturn data;\n}\n\nfunction dataAttr( elem, key, data ) {\n\tvar name;\n\n\t// If nothing was found internally, try to fetch any\n\t// data from the HTML5 data-* attribute\n\tif ( data === undefined && elem.nodeType === 1 ) {\n\t\tname = \"data-\" + key.replace( rmultiDash, \"-$&\" ).toLowerCase();\n\t\tdata = elem.getAttribute( name );\n\n\t\tif ( typeof data === \"string\" ) {\n\t\t\ttry {\n\t\t\t\tdata = getData( data );\n\t\t\t} catch ( e ) {}\n\n\t\t\t// Make sure we set the data so it isn't changed later\n\t\t\tdataUser.set( elem, key, data );\n\t\t} else {\n\t\t\tdata = undefined;\n\t\t}\n\t}\n\treturn data;\n}\n\njQuery.extend( {\n\thasData: function( elem ) {\n\t\treturn dataUser.hasData( elem ) || dataPriv.hasData( elem );\n\t},\n\n\tdata: function( elem, name, data ) {\n\t\treturn dataUser.access( elem, name, data );\n\t},\n\n\tremoveData: function( elem, name ) {\n\t\tdataUser.remove( elem, name );\n\t},\n\n\t// TODO: Now that all calls to _data and _removeData have been replaced\n\t// with direct calls to dataPriv methods, these can be deprecated.\n\t_data: function( elem, name, data ) {\n\t\treturn dataPriv.access( elem, name, data );\n\t},\n\n\t_removeData: function( elem, name ) {\n\t\tdataPriv.remove( elem, name );\n\t}\n} );\n\njQuery.fn.extend( {\n\tdata: function( key, value ) {\n\t\tvar i, name, data,\n\t\t\telem = this[ 0 ],\n\t\t\tattrs = elem && elem.attributes;\n\n\t\t// Gets all values\n\t\tif ( key === undefined ) {\n\t\t\tif ( this.length ) {\n\t\t\t\tdata = dataUser.get( elem );\n\n\t\t\t\tif ( elem.nodeType === 1 && !dataPriv.get( elem, \"hasDataAttrs\" ) ) {\n\t\t\t\t\ti = attrs.length;\n\t\t\t\t\twhile ( i-- ) {\n\n\t\t\t\t\t\t// Support: IE 11+\n\t\t\t\t\t\t// The attrs elements can be null (trac-14894)\n\t\t\t\t\t\tif ( attrs[ i ] ) {\n\t\t\t\t\t\t\tname = attrs[ i ].name;\n\t\t\t\t\t\t\tif ( name.indexOf( \"data-\" ) === 0 ) {\n\t\t\t\t\t\t\t\tname = camelCase( name.slice( 5 ) );\n\t\t\t\t\t\t\t\tdataAttr( elem, name, data[ name ] );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tdataPriv.set( elem, \"hasDataAttrs\", true );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn data;\n\t\t}\n\n\t\t// Sets multiple values\n\t\tif ( typeof key === \"object\" ) {\n\t\t\treturn this.each( function() {\n\t\t\t\tdataUser.set( this, key );\n\t\t\t} );\n\t\t}\n\n\t\treturn access( this, function( value ) {\n\t\t\tvar data;\n\n\t\t\t// The calling jQuery object (element matches) is not empty\n\t\t\t// (and therefore has an element appears at this[ 0 ]) and the\n\t\t\t// `value` parameter was not undefined. An empty jQuery object\n\t\t\t// will result in `undefined` for elem = this[ 0 ] which will\n\t\t\t// throw an exception if an attempt to read a data cache is made.\n\t\t\tif ( elem && value === undefined ) {\n\n\t\t\t\t// Attempt to get data from the cache\n\t\t\t\t// The key will always be camelCased in Data\n\t\t\t\tdata = dataUser.get( elem, key );\n\t\t\t\tif ( data !== undefined ) {\n\t\t\t\t\treturn data;\n\t\t\t\t}\n\n\t\t\t\t// Attempt to \"discover\" the data in\n\t\t\t\t// HTML5 custom data-* attrs\n\t\t\t\tdata = dataAttr( elem, key );\n\t\t\t\tif ( data !== undefined ) {\n\t\t\t\t\treturn data;\n\t\t\t\t}\n\n\t\t\t\t// We tried really hard, but the data doesn't exist.\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Set the data...\n\t\t\tthis.each( function() {\n\n\t\t\t\t// We always store the camelCased key\n\t\t\t\tdataUser.set( this, key, value );\n\t\t\t} );\n\t\t}, null, value, arguments.length > 1, null, true );\n\t},\n\n\tremoveData: function( key ) {\n\t\treturn this.each( function() {\n\t\t\tdataUser.remove( this, key );\n\t\t} );\n\t}\n} );\n\njQuery.extend( {\n\tqueue: function( elem, type, data ) {\n\t\tvar queue;\n\n\t\tif ( elem ) {\n\t\t\ttype = ( type || \"fx\" ) + \"queue\";\n\t\t\tqueue = dataPriv.get( elem, type );\n\n\t\t\t// Speed up dequeue by getting out quickly if this is just a lookup\n\t\t\tif ( data ) {\n\t\t\t\tif ( !queue || Array.isArray( data ) ) {\n\t\t\t\t\tqueue = dataPriv.set( elem, type, jQuery.makeArray( data ) );\n\t\t\t\t} else {\n\t\t\t\t\tqueue.push( data );\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn queue || [];\n\t\t}\n\t},\n\n\tdequeue: function( elem, type ) {\n\t\ttype = type || \"fx\";\n\n\t\tvar queue = jQuery.queue( elem, type ),\n\t\t\tstartLength = queue.length,\n\t\t\tfn = queue.shift(),\n\t\t\thooks = jQuery._queueHooks( elem, type ),\n\t\t\tnext = function() {\n\t\t\t\tjQuery.dequeue( elem, type );\n\t\t\t};\n\n\t\t// If the fx queue is dequeued, always remove the progress sentinel\n\t\tif ( fn === \"inprogress\" ) {\n\t\t\tfn = queue.shift();\n\t\t\tstartLength--;\n\t\t}\n\n\t\tif ( fn ) {\n\n\t\t\t// Add a progress sentinel to prevent the fx queue from being\n\t\t\t// automatically dequeued\n\t\t\tif ( type === \"fx\" ) {\n\t\t\t\tqueue.unshift( \"inprogress\" );\n\t\t\t}\n\n\t\t\t// Clear up the last queue stop function\n\t\t\tdelete hooks.stop;\n\t\t\tfn.call( elem, next, hooks );\n\t\t}\n\n\t\tif ( !startLength && hooks ) {\n\t\t\thooks.empty.fire();\n\t\t}\n\t},\n\n\t// Not public - generate a queueHooks object, or return the current one\n\t_queueHooks: function( elem, type ) {\n\t\tvar key = type + \"queueHooks\";\n\t\treturn dataPriv.get( elem, key ) || dataPriv.set( elem, key, {\n\t\t\tempty: jQuery.Callbacks( \"once memory\" ).add( function() {\n\t\t\t\tdataPriv.remove( elem, [ type + \"queue\", key ] );\n\t\t\t} )\n\t\t} );\n\t}\n} );\n\njQuery.fn.extend( {\n\tqueue: function( type, data ) {\n\t\tvar setter = 2;\n\n\t\tif ( typeof type !== \"string\" ) {\n\t\t\tdata = type;\n\t\t\ttype = \"fx\";\n\t\t\tsetter--;\n\t\t}\n\n\t\tif ( arguments.length < setter ) {\n\t\t\treturn jQuery.queue( this[ 0 ], type );\n\t\t}\n\n\t\treturn data === undefined ?\n\t\t\tthis :\n\t\t\tthis.each( function() {\n\t\t\t\tvar queue = jQuery.queue( this, type, data );\n\n\t\t\t\t// Ensure a hooks for this queue\n\t\t\t\tjQuery._queueHooks( this, type );\n\n\t\t\t\tif ( type === \"fx\" && queue[ 0 ] !== \"inprogress\" ) {\n\t\t\t\t\tjQuery.dequeue( this, type );\n\t\t\t\t}\n\t\t\t} );\n\t},\n\tdequeue: function( type ) {\n\t\treturn this.each( function() {\n\t\t\tjQuery.dequeue( this, type );\n\t\t} );\n\t},\n\tclearQueue: function( type ) {\n\t\treturn this.queue( type || \"fx\", [] );\n\t},\n\n\t// Get a promise resolved when queues of a certain type\n\t// are emptied (fx is the type by default)\n\tpromise: function( type, obj ) {\n\t\tvar tmp,\n\t\t\tcount = 1,\n\t\t\tdefer = jQuery.Deferred(),\n\t\t\telements = this,\n\t\t\ti = this.length,\n\t\t\tresolve = function() {\n\t\t\t\tif ( !( --count ) ) {\n\t\t\t\t\tdefer.resolveWith( elements, [ elements ] );\n\t\t\t\t}\n\t\t\t};\n\n\t\tif ( typeof type !== \"string\" ) {\n\t\t\tobj = type;\n\t\t\ttype = undefined;\n\t\t}\n\t\ttype = type || \"fx\";\n\n\t\twhile ( i-- ) {\n\t\t\ttmp = dataPriv.get( elements[ i ], type + \"queueHooks\" );\n\t\t\tif ( tmp && tmp.empty ) {\n\t\t\t\tcount++;\n\t\t\t\ttmp.empty.add( resolve );\n\t\t\t}\n\t\t}\n\t\tresolve();\n\t\treturn defer.promise( obj );\n\t}\n} );\n\nvar pnum = /[+-]?(?:\\d*\\.|)\\d+(?:[eE][+-]?\\d+|)/.source;\n\nvar rcssNum = new RegExp( \"^(?:([+-])=|)(\" + pnum + \")([a-z%]*)$\", \"i\" );\n\nvar cssExpand = [ \"Top\", \"Right\", \"Bottom\", \"Left\" ];\n\n// isHiddenWithinTree reports if an element has a non-\"none\" display style (inline and/or\n// through the CSS cascade), which is useful in deciding whether or not to make it visible.\n// It differs from the :hidden selector (jQuery.expr.pseudos.hidden) in two important ways:\n// * A hidden ancestor does not force an element to be classified as hidden.\n// * Being disconnected from the document does not force an element to be classified as hidden.\n// These differences improve the behavior of .toggle() et al. when applied to elements that are\n// detached or contained within hidden ancestors (gh-2404, gh-2863).\nfunction isHiddenWithinTree( elem, el ) {\n\n\t// isHiddenWithinTree might be called from jQuery#filter function;\n\t// in that case, element will be second argument\n\telem = el || elem;\n\n\t// Inline style trumps all\n\treturn elem.style.display === \"none\" ||\n\t\telem.style.display === \"\" &&\n\t\tjQuery.css( elem, \"display\" ) === \"none\";\n}\n\nvar ralphaStart = /^[a-z]/,\n\n\t// The regex visualized:\n\t//\n\t// /----------\\\n\t// | | /-------\\\n\t// | / Top \\ | | |\n\t// /--- Border ---+-| Right |-+---+- Width -+---\\\n\t// | | Bottom | |\n\t// | \\ Left / |\n\t// | |\n\t// | /----------\\ |\n\t// | /-------------\\ | | |- END\n\t// | | | | / Top \\ | |\n\t// | | / Margin \\ | | | Right | | |\n\t// |---------+-| |-+---+-| Bottom |-+----|\n\t// | \\ Padding / \\ Left / |\n\t// BEGIN -| |\n\t// | /---------\\ |\n\t// | | | |\n\t// | | / Min \\ | / Width \\ |\n\t// \\--------------+-| |-+---| |---/\n\t// \\ Max / \\ Height /\n\trautoPx = /^(?:Border(?:Top|Right|Bottom|Left)?(?:Width|)|(?:Margin|Padding)?(?:Top|Right|Bottom|Left)?|(?:Min|Max)?(?:Width|Height))$/;\n\nfunction isAutoPx( prop ) {\n\n\t// The first test is used to ensure that:\n\t// 1. The prop starts with a lowercase letter (as we uppercase it for the second regex).\n\t// 2. The prop is not empty.\n\treturn ralphaStart.test( prop ) &&\n\t\trautoPx.test( prop[ 0 ].toUpperCase() + prop.slice( 1 ) );\n}\n\nfunction adjustCSS( elem, prop, valueParts, tween ) {\n\tvar adjusted, scale,\n\t\tmaxIterations = 20,\n\t\tcurrentValue = tween ?\n\t\t\tfunction() {\n\t\t\t\treturn tween.cur();\n\t\t\t} :\n\t\t\tfunction() {\n\t\t\t\treturn jQuery.css( elem, prop, \"\" );\n\t\t\t},\n\t\tinitial = currentValue(),\n\t\tunit = valueParts && valueParts[ 3 ] || ( isAutoPx( prop ) ? \"px\" : \"\" ),\n\n\t\t// Starting value computation is required for potential unit mismatches\n\t\tinitialInUnit = elem.nodeType &&\n\t\t\t( !isAutoPx( prop ) || unit !== \"px\" && +initial ) &&\n\t\t\trcssNum.exec( jQuery.css( elem, prop ) );\n\n\tif ( initialInUnit && initialInUnit[ 3 ] !== unit ) {\n\n\t\t// Support: Firefox <=54 - 66+\n\t\t// Halve the iteration target value to prevent interference from CSS upper bounds (gh-2144)\n\t\tinitial = initial / 2;\n\n\t\t// Trust units reported by jQuery.css\n\t\tunit = unit || initialInUnit[ 3 ];\n\n\t\t// Iteratively approximate from a nonzero starting point\n\t\tinitialInUnit = +initial || 1;\n\n\t\twhile ( maxIterations-- ) {\n\n\t\t\t// Evaluate and update our best guess (doubling guesses that zero out).\n\t\t\t// Finish if the scale equals or crosses 1 (making the old*new product non-positive).\n\t\t\tjQuery.style( elem, prop, initialInUnit + unit );\n\t\t\tif ( ( 1 - scale ) * ( 1 - ( scale = currentValue() / initial || 0.5 ) ) <= 0 ) {\n\t\t\t\tmaxIterations = 0;\n\t\t\t}\n\t\t\tinitialInUnit = initialInUnit / scale;\n\n\t\t}\n\n\t\tinitialInUnit = initialInUnit * 2;\n\t\tjQuery.style( elem, prop, initialInUnit + unit );\n\n\t\t// Make sure we update the tween properties later on\n\t\tvalueParts = valueParts || [];\n\t}\n\n\tif ( valueParts ) {\n\t\tinitialInUnit = +initialInUnit || +initial || 0;\n\n\t\t// Apply relative offset (+=/-=) if specified\n\t\tadjusted = valueParts[ 1 ] ?\n\t\t\tinitialInUnit + ( valueParts[ 1 ] + 1 ) * valueParts[ 2 ] :\n\t\t\t+valueParts[ 2 ];\n\t\tif ( tween ) {\n\t\t\ttween.unit = unit;\n\t\t\ttween.start = initialInUnit;\n\t\t\ttween.end = adjusted;\n\t\t}\n\t}\n\treturn adjusted;\n}\n\n// Matches dashed string for camelizing\nvar rmsPrefix = /^-ms-/;\n\n// Convert dashed to camelCase, handle vendor prefixes.\n// Used by the css & effects modules.\n// Support: IE <=9 - 11+\n// Microsoft forgot to hump their vendor prefix (trac-9572)\nfunction cssCamelCase( string ) {\n\treturn camelCase( string.replace( rmsPrefix, \"ms-\" ) );\n}\n\nvar defaultDisplayMap = {};\n\nfunction getDefaultDisplay( elem ) {\n\tvar temp,\n\t\tdoc = elem.ownerDocument,\n\t\tnodeName = elem.nodeName,\n\t\tdisplay = defaultDisplayMap[ nodeName ];\n\n\tif ( display ) {\n\t\treturn display;\n\t}\n\n\ttemp = doc.body.appendChild( doc.createElement( nodeName ) );\n\tdisplay = jQuery.css( temp, \"display\" );\n\n\ttemp.parentNode.removeChild( temp );\n\n\tif ( display === \"none\" ) {\n\t\tdisplay = \"block\";\n\t}\n\tdefaultDisplayMap[ nodeName ] = display;\n\n\treturn display;\n}\n\nfunction showHide( elements, show ) {\n\tvar display, elem,\n\t\tvalues = [],\n\t\tindex = 0,\n\t\tlength = elements.length;\n\n\t// Determine new display value for elements that need to change\n\tfor ( ; index < length; index++ ) {\n\t\telem = elements[ index ];\n\t\tif ( !elem.style ) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tdisplay = elem.style.display;\n\t\tif ( show ) {\n\n\t\t\t// Since we force visibility upon cascade-hidden elements, an immediate (and slow)\n\t\t\t// check is required in this first loop unless we have a nonempty display value (either\n\t\t\t// inline or about-to-be-restored)\n\t\t\tif ( display === \"none\" ) {\n\t\t\t\tvalues[ index ] = dataPriv.get( elem, \"display\" ) || null;\n\t\t\t\tif ( !values[ index ] ) {\n\t\t\t\t\telem.style.display = \"\";\n\t\t\t\t}\n\t\t\t}\n\t\t\tif ( elem.style.display === \"\" && isHiddenWithinTree( elem ) ) {\n\t\t\t\tvalues[ index ] = getDefaultDisplay( elem );\n\t\t\t}\n\t\t} else {\n\t\t\tif ( display !== \"none\" ) {\n\t\t\t\tvalues[ index ] = \"none\";\n\n\t\t\t\t// Remember what we're overwriting\n\t\t\t\tdataPriv.set( elem, \"display\", display );\n\t\t\t}\n\t\t}\n\t}\n\n\t// Set the display of the elements in a second loop to avoid constant reflow\n\tfor ( index = 0; index < length; index++ ) {\n\t\tif ( values[ index ] != null ) {\n\t\t\telements[ index ].style.display = values[ index ];\n\t\t}\n\t}\n\n\treturn elements;\n}\n\njQuery.fn.extend( {\n\tshow: function() {\n\t\treturn showHide( this, true );\n\t},\n\thide: function() {\n\t\treturn showHide( this );\n\t},\n\ttoggle: function( state ) {\n\t\tif ( typeof state === \"boolean\" ) {\n\t\t\treturn state ? this.show() : this.hide();\n\t\t}\n\n\t\treturn this.each( function() {\n\t\t\tif ( isHiddenWithinTree( this ) ) {\n\t\t\t\tjQuery( this ).show();\n\t\t\t} else {\n\t\t\t\tjQuery( this ).hide();\n\t\t\t}\n\t\t} );\n\t}\n} );\n\nvar isAttached = function( elem ) {\n\t\treturn jQuery.contains( elem.ownerDocument, elem ) ||\n\t\t\telem.getRootNode( composed ) === elem.ownerDocument;\n\t},\n\tcomposed = { composed: true };\n\n// Support: IE 9 - 11+\n// Check attachment across shadow DOM boundaries when possible (gh-3504).\n// Provide a fallback for browsers without Shadow DOM v1 support.\nif ( !documentElement$1.getRootNode ) {\n\tisAttached = function( elem ) {\n\t\treturn jQuery.contains( elem.ownerDocument, elem );\n\t};\n}\n\n// rtagName captures the name from the first start tag in a string of HTML\n// https://html.spec.whatwg.org/multipage/syntax.html#tag-open-state\n// https://html.spec.whatwg.org/multipage/syntax.html#tag-name-state\nvar rtagName = /<([a-z][^\\/\\0>\\x20\\t\\r\\n\\f]*)/i;\n\nvar wrapMap = {\n\n\t// Table parts need to be wrapped with `` or they're\n\t// stripped to their contents when put in a div.\n\t// XHTML parsers do not magically insert elements in the\n\t// same way that tag soup parsers do, so we cannot shorten\n\t// this by omitting or other required elements.\n\tthead: [ \"table\" ],\n\tcol: [ \"colgroup\", \"table\" ],\n\ttr: [ \"tbody\", \"table\" ],\n\ttd: [ \"tr\", \"tbody\", \"table\" ]\n};\n\nwrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;\nwrapMap.th = wrapMap.td;\n\nfunction getAll( context, tag ) {\n\n\t// Support: IE <=9 - 11+\n\t// Use typeof to avoid zero-argument method invocation on host objects (trac-15151)\n\tvar ret;\n\n\tif ( typeof context.getElementsByTagName !== \"undefined\" ) {\n\n\t\t// Use slice to snapshot the live collection from gEBTN\n\t\tret = arr.slice.call( context.getElementsByTagName( tag || \"*\" ) );\n\n\t} else if ( typeof context.querySelectorAll !== \"undefined\" ) {\n\t\tret = context.querySelectorAll( tag || \"*\" );\n\n\t} else {\n\t\tret = [];\n\t}\n\n\tif ( tag === undefined || tag && nodeName( context, tag ) ) {\n\t\treturn jQuery.merge( [ context ], ret );\n\t}\n\n\treturn ret;\n}\n\nvar rscriptType = /^$|^module$|\\/(?:java|ecma)script/i;\n\n// Mark scripts as having already been evaluated\nfunction setGlobalEval( elems, refElements ) {\n\tvar i = 0,\n\t\tl = elems.length;\n\n\tfor ( ; i < l; i++ ) {\n\t\tdataPriv.set(\n\t\t\telems[ i ],\n\t\t\t\"globalEval\",\n\t\t\t!refElements || dataPriv.get( refElements[ i ], \"globalEval\" )\n\t\t);\n\t}\n}\n\nvar rhtml = /<|&#?\\w+;/;\n\nfunction buildFragment( elems, context, scripts, selection, ignored ) {\n\tvar elem, tmp, tag, wrap, attached, j,\n\t\tfragment = context.createDocumentFragment(),\n\t\tnodes = [],\n\t\ti = 0,\n\t\tl = elems.length;\n\n\tfor ( ; i < l; i++ ) {\n\t\telem = elems[ i ];\n\n\t\tif ( elem || elem === 0 ) {\n\n\t\t\t// Add nodes directly\n\t\t\tif ( toType( elem ) === \"object\" && ( elem.nodeType || isArrayLike( elem ) ) ) {\n\t\t\t\tjQuery.merge( nodes, elem.nodeType ? [ elem ] : elem );\n\n\t\t\t// Convert non-html into a text node\n\t\t\t} else if ( !rhtml.test( elem ) ) {\n\t\t\t\tnodes.push( context.createTextNode( elem ) );\n\n\t\t\t// Convert html into DOM nodes\n\t\t\t} else {\n\t\t\t\ttmp = tmp || fragment.appendChild( context.createElement( \"div\" ) );\n\n\t\t\t\t// Deserialize a standard representation\n\t\t\t\ttag = ( rtagName.exec( elem ) || [ \"\", \"\" ] )[ 1 ].toLowerCase();\n\t\t\t\twrap = wrapMap[ tag ] || arr;\n\n\t\t\t\t// Create wrappers & descend into them.\n\t\t\t\tj = wrap.length;\n\t\t\t\twhile ( --j > -1 ) {\n\t\t\t\t\ttmp = tmp.appendChild( context.createElement( wrap[ j ] ) );\n\t\t\t\t}\n\n\t\t\t\ttmp.innerHTML = jQuery.htmlPrefilter( elem );\n\n\t\t\t\tjQuery.merge( nodes, tmp.childNodes );\n\n\t\t\t\t// Remember the top-level container\n\t\t\t\ttmp = fragment.firstChild;\n\n\t\t\t\t// Ensure the created nodes are orphaned (trac-12392)\n\t\t\t\ttmp.textContent = \"\";\n\t\t\t}\n\t\t}\n\t}\n\n\t// Remove wrapper from fragment\n\tfragment.textContent = \"\";\n\n\ti = 0;\n\twhile ( ( elem = nodes[ i++ ] ) ) {\n\n\t\t// Skip elements already in the context collection (trac-4087)\n\t\tif ( selection && jQuery.inArray( elem, selection ) > -1 ) {\n\t\t\tif ( ignored ) {\n\t\t\t\tignored.push( elem );\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\n\t\tattached = isAttached( elem );\n\n\t\t// Append to fragment\n\t\ttmp = getAll( fragment.appendChild( elem ), \"script\" );\n\n\t\t// Preserve script evaluation history\n\t\tif ( attached ) {\n\t\t\tsetGlobalEval( tmp );\n\t\t}\n\n\t\t// Capture executables\n\t\tif ( scripts ) {\n\t\t\tj = 0;\n\t\t\twhile ( ( elem = tmp[ j++ ] ) ) {\n\t\t\t\tif ( rscriptType.test( elem.type || \"\" ) ) {\n\t\t\t\t\tscripts.push( elem );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn fragment;\n}\n\n// Replace/restore the type attribute of script elements for safe DOM manipulation\nfunction disableScript( elem ) {\n\telem.type = ( elem.getAttribute( \"type\" ) !== null ) + \"/\" + elem.type;\n\treturn elem;\n}\nfunction restoreScript( elem ) {\n\tif ( ( elem.type || \"\" ).slice( 0, 5 ) === \"true/\" ) {\n\t\telem.type = elem.type.slice( 5 );\n\t} else {\n\t\telem.removeAttribute( \"type\" );\n\t}\n\n\treturn elem;\n}\n\nfunction domManip( collection, args, callback, ignored ) {\n\n\t// Flatten any nested arrays\n\targs = flat( args );\n\n\tvar fragment, first, scripts, hasScripts, node, doc,\n\t\ti = 0,\n\t\tl = collection.length,\n\t\tiNoClone = l - 1,\n\t\tvalue = args[ 0 ],\n\t\tvalueIsFunction = typeof value === \"function\";\n\n\tif ( valueIsFunction ) {\n\t\treturn collection.each( function( index ) {\n\t\t\tvar self = collection.eq( index );\n\t\t\targs[ 0 ] = value.call( this, index, self.html() );\n\t\t\tdomManip( self, args, callback, ignored );\n\t\t} );\n\t}\n\n\tif ( l ) {\n\t\tfragment = buildFragment( args, collection[ 0 ].ownerDocument, false, collection, ignored );\n\t\tfirst = fragment.firstChild;\n\n\t\tif ( fragment.childNodes.length === 1 ) {\n\t\t\tfragment = first;\n\t\t}\n\n\t\t// Require either new content or an interest in ignored elements to invoke the callback\n\t\tif ( first || ignored ) {\n\t\t\tscripts = jQuery.map( getAll( fragment, \"script\" ), disableScript );\n\t\t\thasScripts = scripts.length;\n\n\t\t\t// Use the original fragment for the last item\n\t\t\t// instead of the first because it can end up\n\t\t\t// being emptied incorrectly in certain situations (trac-8070).\n\t\t\tfor ( ; i < l; i++ ) {\n\t\t\t\tnode = fragment;\n\n\t\t\t\tif ( i !== iNoClone ) {\n\t\t\t\t\tnode = jQuery.clone( node, true, true );\n\n\t\t\t\t\t// Keep references to cloned scripts for later restoration\n\t\t\t\t\tif ( hasScripts ) {\n\t\t\t\t\t\tjQuery.merge( scripts, getAll( node, \"script\" ) );\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tcallback.call( collection[ i ], node, i );\n\t\t\t}\n\n\t\t\tif ( hasScripts ) {\n\t\t\t\tdoc = scripts[ scripts.length - 1 ].ownerDocument;\n\n\t\t\t\t// Re-enable scripts\n\t\t\t\tjQuery.map( scripts, restoreScript );\n\n\t\t\t\t// Evaluate executable scripts on first document insertion\n\t\t\t\tfor ( i = 0; i < hasScripts; i++ ) {\n\t\t\t\t\tnode = scripts[ i ];\n\t\t\t\t\tif ( rscriptType.test( node.type || \"\" ) &&\n\t\t\t\t\t\t!dataPriv.get( node, \"globalEval\" ) &&\n\t\t\t\t\t\tjQuery.contains( doc, node ) ) {\n\n\t\t\t\t\t\tif ( node.src && ( node.type || \"\" ).toLowerCase() !== \"module\" ) {\n\n\t\t\t\t\t\t\t// Optional AJAX dependency, but won't run scripts if not present\n\t\t\t\t\t\t\tif ( jQuery._evalUrl && !node.noModule ) {\n\t\t\t\t\t\t\t\tjQuery._evalUrl( node.src, {\n\t\t\t\t\t\t\t\t\tnonce: node.nonce,\n\t\t\t\t\t\t\t\t\tcrossOrigin: node.crossOrigin\n\t\t\t\t\t\t\t\t}, doc );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tDOMEval( node.textContent, node, doc );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn collection;\n}\n\nvar rcheckableType = /^(?:checkbox|radio)$/i;\n\nvar rtypenamespace = /^([^.]*)(?:\\.(.+)|)/;\n\nfunction returnTrue() {\n\treturn true;\n}\n\nfunction returnFalse() {\n\treturn false;\n}\n\nfunction on( elem, types, selector, data, fn, one ) {\n\tvar origFn, type;\n\n\t// Types can be a map of types/handlers\n\tif ( typeof types === \"object\" ) {\n\n\t\t// ( types-Object, selector, data )\n\t\tif ( typeof selector !== \"string\" ) {\n\n\t\t\t// ( types-Object, data )\n\t\t\tdata = data || selector;\n\t\t\tselector = undefined;\n\t\t}\n\t\tfor ( type in types ) {\n\t\t\ton( elem, type, selector, data, types[ type ], one );\n\t\t}\n\t\treturn elem;\n\t}\n\n\tif ( data == null && fn == null ) {\n\n\t\t// ( types, fn )\n\t\tfn = selector;\n\t\tdata = selector = undefined;\n\t} else if ( fn == null ) {\n\t\tif ( typeof selector === \"string\" ) {\n\n\t\t\t// ( types, selector, fn )\n\t\t\tfn = data;\n\t\t\tdata = undefined;\n\t\t} else {\n\n\t\t\t// ( types, data, fn )\n\t\t\tfn = data;\n\t\t\tdata = selector;\n\t\t\tselector = undefined;\n\t\t}\n\t}\n\tif ( fn === false ) {\n\t\tfn = returnFalse;\n\t} else if ( !fn ) {\n\t\treturn elem;\n\t}\n\n\tif ( one === 1 ) {\n\t\torigFn = fn;\n\t\tfn = function( event ) {\n\n\t\t\t// Can use an empty set, since event contains the info\n\t\t\tjQuery().off( event );\n\t\t\treturn origFn.apply( this, arguments );\n\t\t};\n\n\t\t// Use same guid so caller can remove using origFn\n\t\tfn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ );\n\t}\n\treturn elem.each( function() {\n\t\tjQuery.event.add( this, types, fn, data, selector );\n\t} );\n}\n\n/*\n * Helper functions for managing events -- not part of the public interface.\n * Props to Dean Edwards' addEvent library for many of the ideas.\n */\njQuery.event = {\n\n\tadd: function( elem, types, handler, data, selector ) {\n\n\t\tvar handleObjIn, eventHandle, tmp,\n\t\t\tevents, t, handleObj,\n\t\t\tspecial, handlers, type, namespaces, origType,\n\t\t\telemData = dataPriv.get( elem );\n\n\t\t// Only attach events to objects that accept data\n\t\tif ( !acceptData( elem ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Caller can pass in an object of custom data in lieu of the handler\n\t\tif ( handler.handler ) {\n\t\t\thandleObjIn = handler;\n\t\t\thandler = handleObjIn.handler;\n\t\t\tselector = handleObjIn.selector;\n\t\t}\n\n\t\t// Ensure that invalid selectors throw exceptions at attach time\n\t\t// Evaluate against documentElement in case elem is a non-element node (e.g., document)\n\t\tif ( selector ) {\n\t\t\tjQuery.find.matchesSelector( documentElement$1, selector );\n\t\t}\n\n\t\t// Make sure that the handler has a unique ID, used to find/remove it later\n\t\tif ( !handler.guid ) {\n\t\t\thandler.guid = jQuery.guid++;\n\t\t}\n\n\t\t// Init the element's event structure and main handler, if this is the first\n\t\tif ( !( events = elemData.events ) ) {\n\t\t\tevents = elemData.events = Object.create( null );\n\t\t}\n\t\tif ( !( eventHandle = elemData.handle ) ) {\n\t\t\teventHandle = elemData.handle = function( e ) {\n\n\t\t\t\t// Discard the second event of a jQuery.event.trigger() and\n\t\t\t\t// when an event is called after a page has unloaded\n\t\t\t\treturn typeof jQuery !== \"undefined\" && jQuery.event.triggered !== e.type ?\n\t\t\t\t\tjQuery.event.dispatch.apply( elem, arguments ) : undefined;\n\t\t\t};\n\t\t}\n\n\t\t// Handle multiple events separated by a space\n\t\ttypes = ( types || \"\" ).match( rnothtmlwhite ) || [ \"\" ];\n\t\tt = types.length;\n\t\twhile ( t-- ) {\n\t\t\ttmp = rtypenamespace.exec( types[ t ] ) || [];\n\t\t\ttype = origType = tmp[ 1 ];\n\t\t\tnamespaces = ( tmp[ 2 ] || \"\" ).split( \".\" ).sort();\n\n\t\t\t// There *must* be a type, no attaching namespace-only handlers\n\t\t\tif ( !type ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// If event changes its type, use the special event handlers for the changed type\n\t\t\tspecial = jQuery.event.special[ type ] || {};\n\n\t\t\t// If selector defined, determine special event api type, otherwise given type\n\t\t\ttype = ( selector ? special.delegateType : special.bindType ) || type;\n\n\t\t\t// Update special based on newly reset type\n\t\t\tspecial = jQuery.event.special[ type ] || {};\n\n\t\t\t// handleObj is passed to all event handlers\n\t\t\thandleObj = jQuery.extend( {\n\t\t\t\ttype: type,\n\t\t\t\torigType: origType,\n\t\t\t\tdata: data,\n\t\t\t\thandler: handler,\n\t\t\t\tguid: handler.guid,\n\t\t\t\tselector: selector,\n\t\t\t\tneedsContext: selector && jQuery.expr.match.needsContext.test( selector ),\n\t\t\t\tnamespace: namespaces.join( \".\" )\n\t\t\t}, handleObjIn );\n\n\t\t\t// Init the event handler queue if we're the first\n\t\t\tif ( !( handlers = events[ type ] ) ) {\n\t\t\t\thandlers = events[ type ] = [];\n\t\t\t\thandlers.delegateCount = 0;\n\n\t\t\t\t// Only use addEventListener if the special events handler returns false\n\t\t\t\tif ( !special.setup ||\n\t\t\t\t\tspecial.setup.call( elem, data, namespaces, eventHandle ) === false ) {\n\n\t\t\t\t\tif ( elem.addEventListener ) {\n\t\t\t\t\t\telem.addEventListener( type, eventHandle );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif ( special.add ) {\n\t\t\t\tspecial.add.call( elem, handleObj );\n\n\t\t\t\tif ( !handleObj.handler.guid ) {\n\t\t\t\t\thandleObj.handler.guid = handler.guid;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Add to the element's handler list, delegates in front\n\t\t\tif ( selector ) {\n\t\t\t\thandlers.splice( handlers.delegateCount++, 0, handleObj );\n\t\t\t} else {\n\t\t\t\thandlers.push( handleObj );\n\t\t\t}\n\t\t}\n\n\t},\n\n\t// Detach an event or set of events from an element\n\tremove: function( elem, types, handler, selector, mappedTypes ) {\n\n\t\tvar j, origCount, tmp,\n\t\t\tevents, t, handleObj,\n\t\t\tspecial, handlers, type, namespaces, origType,\n\t\t\telemData = dataPriv.hasData( elem ) && dataPriv.get( elem );\n\n\t\tif ( !elemData || !( events = elemData.events ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Once for each type.namespace in types; type may be omitted\n\t\ttypes = ( types || \"\" ).match( rnothtmlwhite ) || [ \"\" ];\n\t\tt = types.length;\n\t\twhile ( t-- ) {\n\t\t\ttmp = rtypenamespace.exec( types[ t ] ) || [];\n\t\t\ttype = origType = tmp[ 1 ];\n\t\t\tnamespaces = ( tmp[ 2 ] || \"\" ).split( \".\" ).sort();\n\n\t\t\t// Unbind all events (on this namespace, if provided) for the element\n\t\t\tif ( !type ) {\n\t\t\t\tfor ( type in events ) {\n\t\t\t\t\tjQuery.event.remove( elem, type + types[ t ], handler, selector, true );\n\t\t\t\t}\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tspecial = jQuery.event.special[ type ] || {};\n\t\t\ttype = ( selector ? special.delegateType : special.bindType ) || type;\n\t\t\thandlers = events[ type ] || [];\n\t\t\ttmp = tmp[ 2 ] &&\n\t\t\t\tnew RegExp( \"(^|\\\\.)\" + namespaces.join( \"\\\\.(?:.*\\\\.|)\" ) + \"(\\\\.|$)\" );\n\n\t\t\t// Remove matching events\n\t\t\torigCount = j = handlers.length;\n\t\t\twhile ( j-- ) {\n\t\t\t\thandleObj = handlers[ j ];\n\n\t\t\t\tif ( ( mappedTypes || origType === handleObj.origType ) &&\n\t\t\t\t\t( !handler || handler.guid === handleObj.guid ) &&\n\t\t\t\t\t( !tmp || tmp.test( handleObj.namespace ) ) &&\n\t\t\t\t\t( !selector || selector === handleObj.selector ||\n\t\t\t\t\t\tselector === \"**\" && handleObj.selector ) ) {\n\t\t\t\t\thandlers.splice( j, 1 );\n\n\t\t\t\t\tif ( handleObj.selector ) {\n\t\t\t\t\t\thandlers.delegateCount--;\n\t\t\t\t\t}\n\t\t\t\t\tif ( special.remove ) {\n\t\t\t\t\t\tspecial.remove.call( elem, handleObj );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Remove generic event handler if we removed something and no more handlers exist\n\t\t\t// (avoids potential for endless recursion during removal of special event handlers)\n\t\t\tif ( origCount && !handlers.length ) {\n\t\t\t\tif ( !special.teardown ||\n\t\t\t\t\tspecial.teardown.call( elem, namespaces, elemData.handle ) === false ) {\n\n\t\t\t\t\tjQuery.removeEvent( elem, type, elemData.handle );\n\t\t\t\t}\n\n\t\t\t\tdelete events[ type ];\n\t\t\t}\n\t\t}\n\n\t\t// Remove data and the expando if it's no longer used\n\t\tif ( jQuery.isEmptyObject( events ) ) {\n\t\t\tdataPriv.remove( elem, \"handle events\" );\n\t\t}\n\t},\n\n\tdispatch: function( nativeEvent ) {\n\n\t\tvar i, j, ret, matched, handleObj, handlerQueue,\n\t\t\targs = new Array( arguments.length ),\n\n\t\t\t// Make a writable jQuery.Event from the native event object\n\t\t\tevent = jQuery.event.fix( nativeEvent ),\n\n\t\t\thandlers = (\n\t\t\t\tdataPriv.get( this, \"events\" ) || Object.create( null )\n\t\t\t)[ event.type ] || [],\n\t\t\tspecial = jQuery.event.special[ event.type ] || {};\n\n\t\t// Use the fix-ed jQuery.Event rather than the (read-only) native event\n\t\targs[ 0 ] = event;\n\n\t\tfor ( i = 1; i < arguments.length; i++ ) {\n\t\t\targs[ i ] = arguments[ i ];\n\t\t}\n\n\t\tevent.delegateTarget = this;\n\n\t\t// Call the preDispatch hook for the mapped type, and let it bail if desired\n\t\tif ( special.preDispatch && special.preDispatch.call( this, event ) === false ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Determine handlers\n\t\thandlerQueue = jQuery.event.handlers.call( this, event, handlers );\n\n\t\t// Run delegates first; they may want to stop propagation beneath us\n\t\ti = 0;\n\t\twhile ( ( matched = handlerQueue[ i++ ] ) && !event.isPropagationStopped() ) {\n\t\t\tevent.currentTarget = matched.elem;\n\n\t\t\tj = 0;\n\t\t\twhile ( ( handleObj = matched.handlers[ j++ ] ) &&\n\t\t\t\t!event.isImmediatePropagationStopped() ) {\n\n\t\t\t\t// If the event is namespaced, then each handler is only invoked if it is\n\t\t\t\t// specially universal or its namespaces are a superset of the event's.\n\t\t\t\tif ( !event.rnamespace || handleObj.namespace === false ||\n\t\t\t\t\tevent.rnamespace.test( handleObj.namespace ) ) {\n\n\t\t\t\t\tevent.handleObj = handleObj;\n\t\t\t\t\tevent.data = handleObj.data;\n\n\t\t\t\t\tret = ( ( jQuery.event.special[ handleObj.origType ] || {} ).handle ||\n\t\t\t\t\t\thandleObj.handler ).apply( matched.elem, args );\n\n\t\t\t\t\tif ( ret !== undefined ) {\n\t\t\t\t\t\tif ( ( event.result = ret ) === false ) {\n\t\t\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\t\t\tevent.stopPropagation();\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Call the postDispatch hook for the mapped type\n\t\tif ( special.postDispatch ) {\n\t\t\tspecial.postDispatch.call( this, event );\n\t\t}\n\n\t\treturn event.result;\n\t},\n\n\thandlers: function( event, handlers ) {\n\t\tvar i, handleObj, sel, matchedHandlers, matchedSelectors,\n\t\t\thandlerQueue = [],\n\t\t\tdelegateCount = handlers.delegateCount,\n\t\t\tcur = event.target;\n\n\t\t// Find delegate handlers\n\t\tif ( delegateCount &&\n\n\t\t\t// Support: Firefox <=42 - 66+\n\t\t\t// Suppress spec-violating clicks indicating a non-primary pointer button (trac-3861)\n\t\t\t// https://www.w3.org/TR/DOM-Level-3-Events/#event-type-click\n\t\t\t// Support: IE 11+\n\t\t\t// ...but not arrow key \"clicks\" of radio inputs, which can have `button` -1 (gh-2343)\n\t\t\t!( event.type === \"click\" && event.button >= 1 ) ) {\n\n\t\t\tfor ( ; cur !== this; cur = cur.parentNode || this ) {\n\n\t\t\t\t// Don't check non-elements (trac-13208)\n\t\t\t\t// Don't process clicks on disabled elements (trac-6911, trac-8165, trac-11382, trac-11764)\n\t\t\t\tif ( cur.nodeType === 1 && !( event.type === \"click\" && cur.disabled === true ) ) {\n\t\t\t\t\tmatchedHandlers = [];\n\t\t\t\t\tmatchedSelectors = {};\n\t\t\t\t\tfor ( i = 0; i < delegateCount; i++ ) {\n\t\t\t\t\t\thandleObj = handlers[ i ];\n\n\t\t\t\t\t\t// Don't conflict with Object.prototype properties (trac-13203)\n\t\t\t\t\t\tsel = handleObj.selector + \" \";\n\n\t\t\t\t\t\tif ( matchedSelectors[ sel ] === undefined ) {\n\t\t\t\t\t\t\tmatchedSelectors[ sel ] = handleObj.needsContext ?\n\t\t\t\t\t\t\t\tjQuery( sel, this ).index( cur ) > -1 :\n\t\t\t\t\t\t\t\tjQuery.find( sel, this, null, [ cur ] ).length;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif ( matchedSelectors[ sel ] ) {\n\t\t\t\t\t\t\tmatchedHandlers.push( handleObj );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif ( matchedHandlers.length ) {\n\t\t\t\t\t\thandlerQueue.push( { elem: cur, handlers: matchedHandlers } );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Add the remaining (directly-bound) handlers\n\t\tcur = this;\n\t\tif ( delegateCount < handlers.length ) {\n\t\t\thandlerQueue.push( { elem: cur, handlers: handlers.slice( delegateCount ) } );\n\t\t}\n\n\t\treturn handlerQueue;\n\t},\n\n\taddProp: function( name, hook ) {\n\t\tObject.defineProperty( jQuery.Event.prototype, name, {\n\t\t\tenumerable: true,\n\t\t\tconfigurable: true,\n\n\t\t\tget: typeof hook === \"function\" ?\n\t\t\t\tfunction() {\n\t\t\t\t\tif ( this.originalEvent ) {\n\t\t\t\t\t\treturn hook( this.originalEvent );\n\t\t\t\t\t}\n\t\t\t\t} :\n\t\t\t\tfunction() {\n\t\t\t\t\tif ( this.originalEvent ) {\n\t\t\t\t\t\treturn this.originalEvent[ name ];\n\t\t\t\t\t}\n\t\t\t\t},\n\n\t\t\tset: function( value ) {\n\t\t\t\tObject.defineProperty( this, name, {\n\t\t\t\t\tenumerable: true,\n\t\t\t\t\tconfigurable: true,\n\t\t\t\t\twritable: true,\n\t\t\t\t\tvalue: value\n\t\t\t\t} );\n\t\t\t}\n\t\t} );\n\t},\n\n\tfix: function( originalEvent ) {\n\t\treturn originalEvent[ jQuery.expando ] ?\n\t\t\toriginalEvent :\n\t\t\tnew jQuery.Event( originalEvent );\n\t},\n\n\tspecial: jQuery.extend( Object.create( null ), {\n\t\tload: {\n\n\t\t\t// Prevent triggered image.load events from bubbling to window.load\n\t\t\tnoBubble: true\n\t\t},\n\t\tclick: {\n\n\t\t\t// Utilize native event to ensure correct state for checkable inputs\n\t\t\tsetup: function( data ) {\n\n\t\t\t\t// For mutual compressibility with _default, replace `this` access with a local var.\n\t\t\t\t// `|| data` is dead code meant only to preserve the variable through minification.\n\t\t\t\tvar el = this || data;\n\n\t\t\t\t// Claim the first handler\n\t\t\t\tif ( rcheckableType.test( el.type ) &&\n\t\t\t\t\tel.click && nodeName( el, \"input\" ) ) {\n\n\t\t\t\t\t// dataPriv.set( el, \"click\", ... )\n\t\t\t\t\tleverageNative( el, \"click\", true );\n\t\t\t\t}\n\n\t\t\t\t// Return false to allow normal processing in the caller\n\t\t\t\treturn false;\n\t\t\t},\n\t\t\ttrigger: function( data ) {\n\n\t\t\t\t// For mutual compressibility with _default, replace `this` access with a local var.\n\t\t\t\t// `|| data` is dead code meant only to preserve the variable through minification.\n\t\t\t\tvar el = this || data;\n\n\t\t\t\t// Force setup before triggering a click\n\t\t\t\tif ( rcheckableType.test( el.type ) &&\n\t\t\t\t\tel.click && nodeName( el, \"input\" ) ) {\n\n\t\t\t\t\tleverageNative( el, \"click\" );\n\t\t\t\t}\n\n\t\t\t\t// Return non-false to allow normal event-path propagation\n\t\t\t\treturn true;\n\t\t\t},\n\n\t\t\t// For cross-browser consistency, suppress native .click() on links\n\t\t\t// Also prevent it if we're currently inside a leveraged native-event stack\n\t\t\t_default: function( event ) {\n\t\t\t\tvar target = event.target;\n\t\t\t\treturn rcheckableType.test( target.type ) &&\n\t\t\t\t\ttarget.click && nodeName( target, \"input\" ) &&\n\t\t\t\t\tdataPriv.get( target, \"click\" ) ||\n\t\t\t\t\tnodeName( target, \"a\" );\n\t\t\t}\n\t\t},\n\n\t\tbeforeunload: {\n\t\t\tpostDispatch: function( event ) {\n\t\t\t\tif ( event.result !== undefined ) {\n\n\t\t\t\t\t// Setting `event.originalEvent.returnValue` in modern\n\t\t\t\t\t// browsers does the same as just calling `preventDefault()`,\n\t\t\t\t\t// the browsers ignore the value anyway.\n\t\t\t\t\t// Incidentally, IE 11 is the only browser from our supported\n\t\t\t\t\t// ones which respects the value returned from a `beforeunload`\n\t\t\t\t\t// handler attached by `addEventListener`; other browsers do\n\t\t\t\t\t// so only for inline handlers, so not setting the value\n\t\t\t\t\t// directly shouldn't reduce any functionality.\n\t\t\t\t\tevent.preventDefault();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t} )\n};\n\n// Ensure the presence of an event listener that handles manually-triggered\n// synthetic events by interrupting progress until reinvoked in response to\n// *native* events that it fires directly, ensuring that state changes have\n// already occurred before other listeners are invoked.\nfunction leverageNative( el, type, isSetup ) {\n\n\t// Missing `isSetup` indicates a trigger call, which must force setup through jQuery.event.add\n\tif ( !isSetup ) {\n\t\tif ( dataPriv.get( el, type ) === undefined ) {\n\t\t\tjQuery.event.add( el, type, returnTrue );\n\t\t}\n\t\treturn;\n\t}\n\n\t// Register the controller as a special universal handler for all event namespaces\n\tdataPriv.set( el, type, false );\n\tjQuery.event.add( el, type, {\n\t\tnamespace: false,\n\t\thandler: function( event ) {\n\t\t\tvar result,\n\t\t\t\tsaved = dataPriv.get( this, type );\n\n\t\t\t// This controller function is invoked under multiple circumstances,\n\t\t\t// differentiated by the stored value in `saved`:\n\t\t\t// 1. For an outer synthetic `.trigger()`ed event (detected by\n\t\t\t// `event.isTrigger & 1` and non-array `saved`), it records arguments\n\t\t\t// as an array and fires an [inner] native event to prompt state\n\t\t\t// changes that should be observed by registered listeners (such as\n\t\t\t// checkbox toggling and focus updating), then clears the stored value.\n\t\t\t// 2. For an [inner] native event (detected by `saved` being\n\t\t\t// an array), it triggers an inner synthetic event, records the\n\t\t\t// result, and preempts propagation to further jQuery listeners.\n\t\t\t// 3. For an inner synthetic event (detected by `event.isTrigger & 1` and\n\t\t\t// array `saved`), it prevents double-propagation of surrogate events\n\t\t\t// but otherwise allows everything to proceed (particularly including\n\t\t\t// further listeners).\n\t\t\t// Possible `saved` data shapes: `[...], `{ value }`, `false`.\n\t\t\tif ( ( event.isTrigger & 1 ) && this[ type ] ) {\n\n\t\t\t\t// Interrupt processing of the outer synthetic .trigger()ed event\n\t\t\t\tif ( !saved.length ) {\n\n\t\t\t\t\t// Store arguments for use when handling the inner native event\n\t\t\t\t\t// There will always be at least one argument (an event object),\n\t\t\t\t\t// so this array will not be confused with a leftover capture object.\n\t\t\t\t\tsaved = slice.call( arguments );\n\t\t\t\t\tdataPriv.set( this, type, saved );\n\n\t\t\t\t\t// Trigger the native event and capture its result\n\t\t\t\t\tthis[ type ]();\n\t\t\t\t\tresult = dataPriv.get( this, type );\n\t\t\t\t\tdataPriv.set( this, type, false );\n\n\t\t\t\t\tif ( saved !== result ) {\n\n\t\t\t\t\t\t// Cancel the outer synthetic event\n\t\t\t\t\t\tevent.stopImmediatePropagation();\n\t\t\t\t\t\tevent.preventDefault();\n\n\t\t\t\t\t\t// Support: Chrome 86+\n\t\t\t\t\t\t// In Chrome, if an element having a focusout handler is\n\t\t\t\t\t\t// blurred by clicking outside of it, it invokes the handler\n\t\t\t\t\t\t// synchronously. If that handler calls `.remove()` on\n\t\t\t\t\t\t// the element, the data is cleared, leaving `result`\n\t\t\t\t\t\t// undefined. We need to guard against this.\n\t\t\t\t\t\treturn result && result.value;\n\t\t\t\t\t}\n\n\t\t\t\t// If this is an inner synthetic event for an event with a bubbling\n\t\t\t\t// surrogate (focus or blur), assume that the surrogate already\n\t\t\t\t// propagated from triggering the native event and prevent that\n\t\t\t\t// from happening again here.\n\t\t\t\t} else if ( ( jQuery.event.special[ type ] || {} ).delegateType ) {\n\t\t\t\t\tevent.stopPropagation();\n\t\t\t\t}\n\n\t\t\t// If this is a native event triggered above, everything is now in order.\n\t\t\t// Fire an inner synthetic event with the original arguments.\n\t\t\t} else if ( saved.length ) {\n\n\t\t\t\t// ...and capture the result\n\t\t\t\tdataPriv.set( this, type, {\n\t\t\t\t\tvalue: jQuery.event.trigger(\n\t\t\t\t\t\tsaved[ 0 ],\n\t\t\t\t\t\tsaved.slice( 1 ),\n\t\t\t\t\t\tthis\n\t\t\t\t\t)\n\t\t\t\t} );\n\n\t\t\t\t// Abort handling of the native event by all jQuery handlers while allowing\n\t\t\t\t// native handlers on the same element to run. On target, this is achieved\n\t\t\t\t// by stopping immediate propagation just on the jQuery event. However,\n\t\t\t\t// the native event is re-wrapped by a jQuery one on each level of the\n\t\t\t\t// propagation so the only way to stop it for jQuery is to stop it for\n\t\t\t\t// everyone via native `stopPropagation()`. This is not a problem for\n\t\t\t\t// focus/blur which don't bubble, but it does also stop click on checkboxes\n\t\t\t\t// and radios. We accept this limitation.\n\t\t\t\tevent.stopPropagation();\n\t\t\t\tevent.isImmediatePropagationStopped = returnTrue;\n\t\t\t}\n\t\t}\n\t} );\n}\n\njQuery.removeEvent = function( elem, type, handle ) {\n\n\t// This \"if\" is needed for plain objects\n\tif ( elem.removeEventListener ) {\n\t\telem.removeEventListener( type, handle );\n\t}\n};\n\njQuery.Event = function( src, props ) {\n\n\t// Allow instantiation without the 'new' keyword\n\tif ( !( this instanceof jQuery.Event ) ) {\n\t\treturn new jQuery.Event( src, props );\n\t}\n\n\t// Event object\n\tif ( src && src.type ) {\n\t\tthis.originalEvent = src;\n\t\tthis.type = src.type;\n\n\t\t// Events bubbling up the document may have been marked as prevented\n\t\t// by a handler lower down the tree; reflect the correct value.\n\t\tthis.isDefaultPrevented = src.defaultPrevented ?\n\t\t\treturnTrue :\n\t\t\treturnFalse;\n\n\t\t// Create target properties\n\t\tthis.target = src.target;\n\t\tthis.currentTarget = src.currentTarget;\n\t\tthis.relatedTarget = src.relatedTarget;\n\n\t// Event type\n\t} else {\n\t\tthis.type = src;\n\t}\n\n\t// Put explicitly provided properties onto the event object\n\tif ( props ) {\n\t\tjQuery.extend( this, props );\n\t}\n\n\t// Create a timestamp if incoming event doesn't have one\n\tthis.timeStamp = src && src.timeStamp || Date.now();\n\n\t// Mark it as fixed\n\tthis[ jQuery.expando ] = true;\n};\n\n// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding\n// https://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html\njQuery.Event.prototype = {\n\tconstructor: jQuery.Event,\n\tisDefaultPrevented: returnFalse,\n\tisPropagationStopped: returnFalse,\n\tisImmediatePropagationStopped: returnFalse,\n\tisSimulated: false,\n\n\tpreventDefault: function() {\n\t\tvar e = this.originalEvent;\n\n\t\tthis.isDefaultPrevented = returnTrue;\n\n\t\tif ( e && !this.isSimulated ) {\n\t\t\te.preventDefault();\n\t\t}\n\t},\n\tstopPropagation: function() {\n\t\tvar e = this.originalEvent;\n\n\t\tthis.isPropagationStopped = returnTrue;\n\n\t\tif ( e && !this.isSimulated ) {\n\t\t\te.stopPropagation();\n\t\t}\n\t},\n\tstopImmediatePropagation: function() {\n\t\tvar e = this.originalEvent;\n\n\t\tthis.isImmediatePropagationStopped = returnTrue;\n\n\t\tif ( e && !this.isSimulated ) {\n\t\t\te.stopImmediatePropagation();\n\t\t}\n\n\t\tthis.stopPropagation();\n\t}\n};\n\n// Includes all common event props including KeyEvent and MouseEvent specific props\njQuery.each( {\n\taltKey: true,\n\tbubbles: true,\n\tcancelable: true,\n\tchangedTouches: true,\n\tctrlKey: true,\n\tdetail: true,\n\teventPhase: true,\n\tmetaKey: true,\n\tpageX: true,\n\tpageY: true,\n\tshiftKey: true,\n\tview: true,\n\t\"char\": true,\n\tcode: true,\n\tcharCode: true,\n\tkey: true,\n\tkeyCode: true,\n\tbutton: true,\n\tbuttons: true,\n\tclientX: true,\n\tclientY: true,\n\toffsetX: true,\n\toffsetY: true,\n\tpointerId: true,\n\tpointerType: true,\n\tscreenX: true,\n\tscreenY: true,\n\ttargetTouches: true,\n\ttoElement: true,\n\ttouches: true,\n\twhich: true\n}, jQuery.event.addProp );\n\njQuery.each( { focus: \"focusin\", blur: \"focusout\" }, function( type, delegateType ) {\n\n\t// Support: IE 11+\n\t// Attach a single focusin/focusout handler on the document while someone wants focus/blur.\n\t// This is because the former are synchronous in IE while the latter are async. In other\n\t// browsers, all those handlers are invoked synchronously.\n\tfunction focusMappedHandler( nativeEvent ) {\n\n\t\t// `eventHandle` would already wrap the event, but we need to change the `type` here.\n\t\tvar event = jQuery.event.fix( nativeEvent );\n\t\tevent.type = nativeEvent.type === \"focusin\" ? \"focus\" : \"blur\";\n\t\tevent.isSimulated = true;\n\n\t\t// focus/blur don't bubble while focusin/focusout do; simulate the former by only\n\t\t// invoking the handler at the lower level.\n\t\tif ( event.target === event.currentTarget ) {\n\n\t\t\t// The setup part calls `leverageNative`, which, in turn, calls\n\t\t\t// `jQuery.event.add`, so event handle will already have been set\n\t\t\t// by this point.\n\t\t\tdataPriv.get( this, \"handle\" )( event );\n\t\t}\n\t}\n\n\tjQuery.event.special[ type ] = {\n\n\t\t// Utilize native event if possible so blur/focus sequence is correct\n\t\tsetup: function() {\n\n\t\t\t// Claim the first handler\n\t\t\t// dataPriv.set( this, \"focus\", ... )\n\t\t\t// dataPriv.set( this, \"blur\", ... )\n\t\t\tleverageNative( this, type, true );\n\n\t\t\tif ( isIE ) {\n\t\t\t\tthis.addEventListener( delegateType, focusMappedHandler );\n\t\t\t} else {\n\n\t\t\t\t// Return false to allow normal processing in the caller\n\t\t\t\treturn false;\n\t\t\t}\n\t\t},\n\t\ttrigger: function() {\n\n\t\t\t// Force setup before trigger\n\t\t\tleverageNative( this, type );\n\n\t\t\t// Return non-false to allow normal event-path propagation\n\t\t\treturn true;\n\t\t},\n\n\t\tteardown: function() {\n\t\t\tif ( isIE ) {\n\t\t\t\tthis.removeEventListener( delegateType, focusMappedHandler );\n\t\t\t} else {\n\n\t\t\t\t// Return false to indicate standard teardown should be applied\n\t\t\t\treturn false;\n\t\t\t}\n\t\t},\n\n\t\t// Suppress native focus or blur if we're currently inside\n\t\t// a leveraged native-event stack\n\t\t_default: function( event ) {\n\t\t\treturn dataPriv.get( event.target, type );\n\t\t},\n\n\t\tdelegateType: delegateType\n\t};\n} );\n\n// Create mouseenter/leave events using mouseover/out and event-time checks\n// so that event delegation works in jQuery.\n// Do the same for pointerenter/pointerleave and pointerover/pointerout\njQuery.each( {\n\tmouseenter: \"mouseover\",\n\tmouseleave: \"mouseout\",\n\tpointerenter: \"pointerover\",\n\tpointerleave: \"pointerout\"\n}, function( orig, fix ) {\n\tjQuery.event.special[ orig ] = {\n\t\tdelegateType: fix,\n\t\tbindType: fix,\n\n\t\thandle: function( event ) {\n\t\t\tvar ret,\n\t\t\t\ttarget = this,\n\t\t\t\trelated = event.relatedTarget,\n\t\t\t\thandleObj = event.handleObj;\n\n\t\t\t// For mouseenter/leave call the handler if related is outside the target.\n\t\t\t// NB: No relatedTarget if the mouse left/entered the browser window\n\t\t\tif ( !related || ( related !== target && !jQuery.contains( target, related ) ) ) {\n\t\t\t\tevent.type = handleObj.origType;\n\t\t\t\tret = handleObj.handler.apply( this, arguments );\n\t\t\t\tevent.type = fix;\n\t\t\t}\n\t\t\treturn ret;\n\t\t}\n\t};\n} );\n\njQuery.fn.extend( {\n\n\ton: function( types, selector, data, fn ) {\n\t\treturn on( this, types, selector, data, fn );\n\t},\n\tone: function( types, selector, data, fn ) {\n\t\treturn on( this, types, selector, data, fn, 1 );\n\t},\n\toff: function( types, selector, fn ) {\n\t\tvar handleObj, type;\n\t\tif ( types && types.preventDefault && types.handleObj ) {\n\n\t\t\t// ( event ) dispatched jQuery.Event\n\t\t\thandleObj = types.handleObj;\n\t\t\tjQuery( types.delegateTarget ).off(\n\t\t\t\thandleObj.namespace ?\n\t\t\t\t\thandleObj.origType + \".\" + handleObj.namespace :\n\t\t\t\t\thandleObj.origType,\n\t\t\t\thandleObj.selector,\n\t\t\t\thandleObj.handler\n\t\t\t);\n\t\t\treturn this;\n\t\t}\n\t\tif ( typeof types === \"object\" ) {\n\n\t\t\t// ( types-object [, selector] )\n\t\t\tfor ( type in types ) {\n\t\t\t\tthis.off( type, selector, types[ type ] );\n\t\t\t}\n\t\t\treturn this;\n\t\t}\n\t\tif ( selector === false || typeof selector === \"function\" ) {\n\n\t\t\t// ( types [, fn] )\n\t\t\tfn = selector;\n\t\t\tselector = undefined;\n\t\t}\n\t\tif ( fn === false ) {\n\t\t\tfn = returnFalse;\n\t\t}\n\t\treturn this.each( function() {\n\t\t\tjQuery.event.remove( this, types, fn, selector );\n\t\t} );\n\t}\n} );\n\nvar\n\n\t// Support: IE <=10 - 11+\n\t// In IE using regex groups here causes severe slowdowns.\n\trnoInnerhtml = / 0 ) {\n\t\t\tsetGlobalEval( destElements, !inPage && getAll( elem, \"script\" ) );\n\t\t}\n\n\t\t// Return the cloned set\n\t\treturn clone;\n\t},\n\n\tcleanData: function( elems ) {\n\t\tvar data, elem, type,\n\t\t\tspecial = jQuery.event.special,\n\t\t\ti = 0;\n\n\t\tfor ( ; ( elem = elems[ i ] ) !== undefined; i++ ) {\n\t\t\tif ( acceptData( elem ) ) {\n\t\t\t\tif ( ( data = elem[ dataPriv.expando ] ) ) {\n\t\t\t\t\tif ( data.events ) {\n\t\t\t\t\t\tfor ( type in data.events ) {\n\t\t\t\t\t\t\tif ( special[ type ] ) {\n\t\t\t\t\t\t\t\tjQuery.event.remove( elem, type );\n\n\t\t\t\t\t\t\t// This is a shortcut to avoid jQuery.event.remove's overhead\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tjQuery.removeEvent( elem, type, data.handle );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// Support: Chrome <=35 - 45+\n\t\t\t\t\t// Assign undefined instead of using delete, see Data#remove\n\t\t\t\t\telem[ dataPriv.expando ] = undefined;\n\t\t\t\t}\n\t\t\t\tif ( elem[ dataUser.expando ] ) {\n\n\t\t\t\t\t// Support: Chrome <=35 - 45+\n\t\t\t\t\t// Assign undefined instead of using delete, see Data#remove\n\t\t\t\t\telem[ dataUser.expando ] = undefined;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n} );\n\njQuery.fn.extend( {\n\tdetach: function( selector ) {\n\t\treturn remove( this, selector, true );\n\t},\n\n\tremove: function( selector ) {\n\t\treturn remove( this, selector );\n\t},\n\n\ttext: function( value ) {\n\t\treturn access( this, function( value ) {\n\t\t\treturn value === undefined ?\n\t\t\t\tjQuery.text( this ) :\n\t\t\t\tthis.empty().each( function() {\n\t\t\t\t\tif ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {\n\t\t\t\t\t\tthis.textContent = value;\n\t\t\t\t\t}\n\t\t\t\t} );\n\t\t}, null, value, arguments.length );\n\t},\n\n\tappend: function() {\n\t\treturn domManip( this, arguments, function( elem ) {\n\t\t\tif ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {\n\t\t\t\tvar target = manipulationTarget( this, elem );\n\t\t\t\ttarget.appendChild( elem );\n\t\t\t}\n\t\t} );\n\t},\n\n\tprepend: function() {\n\t\treturn domManip( this, arguments, function( elem ) {\n\t\t\tif ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {\n\t\t\t\tvar target = manipulationTarget( this, elem );\n\t\t\t\ttarget.insertBefore( elem, target.firstChild );\n\t\t\t}\n\t\t} );\n\t},\n\n\tbefore: function() {\n\t\treturn domManip( this, arguments, function( elem ) {\n\t\t\tif ( this.parentNode ) {\n\t\t\t\tthis.parentNode.insertBefore( elem, this );\n\t\t\t}\n\t\t} );\n\t},\n\n\tafter: function() {\n\t\treturn domManip( this, arguments, function( elem ) {\n\t\t\tif ( this.parentNode ) {\n\t\t\t\tthis.parentNode.insertBefore( elem, this.nextSibling );\n\t\t\t}\n\t\t} );\n\t},\n\n\tempty: function() {\n\t\tvar elem,\n\t\t\ti = 0;\n\n\t\tfor ( ; ( elem = this[ i ] ) != null; i++ ) {\n\t\t\tif ( elem.nodeType === 1 ) {\n\n\t\t\t\t// Prevent memory leaks\n\t\t\t\tjQuery.cleanData( getAll( elem, false ) );\n\n\t\t\t\t// Remove any remaining nodes\n\t\t\t\telem.textContent = \"\";\n\t\t\t}\n\t\t}\n\n\t\treturn this;\n\t},\n\n\tclone: function( dataAndEvents, deepDataAndEvents ) {\n\t\tdataAndEvents = dataAndEvents == null ? false : dataAndEvents;\n\t\tdeepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents;\n\n\t\treturn this.map( function() {\n\t\t\treturn jQuery.clone( this, dataAndEvents, deepDataAndEvents );\n\t\t} );\n\t},\n\n\thtml: function( value ) {\n\t\treturn access( this, function( value ) {\n\t\t\tvar elem = this[ 0 ] || {},\n\t\t\t\ti = 0,\n\t\t\t\tl = this.length;\n\n\t\t\tif ( value === undefined && elem.nodeType === 1 ) {\n\t\t\t\treturn elem.innerHTML;\n\t\t\t}\n\n\t\t\t// See if we can take a shortcut and just use innerHTML\n\t\t\tif ( typeof value === \"string\" && !rnoInnerhtml.test( value ) &&\n\t\t\t\t!wrapMap[ ( rtagName.exec( value ) || [ \"\", \"\" ] )[ 1 ].toLowerCase() ] ) {\n\n\t\t\t\tvalue = jQuery.htmlPrefilter( value );\n\n\t\t\t\ttry {\n\t\t\t\t\tfor ( ; i < l; i++ ) {\n\t\t\t\t\t\telem = this[ i ] || {};\n\n\t\t\t\t\t\t// Remove element nodes and prevent memory leaks\n\t\t\t\t\t\tif ( elem.nodeType === 1 ) {\n\t\t\t\t\t\t\tjQuery.cleanData( getAll( elem, false ) );\n\t\t\t\t\t\t\telem.innerHTML = value;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\telem = 0;\n\n\t\t\t\t// If using innerHTML throws an exception, use the fallback method\n\t\t\t\t} catch ( e ) {}\n\t\t\t}\n\n\t\t\tif ( elem ) {\n\t\t\t\tthis.empty().append( value );\n\t\t\t}\n\t\t}, null, value, arguments.length );\n\t},\n\n\treplaceWith: function() {\n\t\tvar ignored = [];\n\n\t\t// Make the changes, replacing each non-ignored context element with the new content\n\t\treturn domManip( this, arguments, function( elem ) {\n\t\t\tvar parent = this.parentNode;\n\n\t\t\tif ( jQuery.inArray( this, ignored ) < 0 ) {\n\t\t\t\tjQuery.cleanData( getAll( this ) );\n\t\t\t\tif ( parent ) {\n\t\t\t\t\tparent.replaceChild( elem, this );\n\t\t\t\t}\n\t\t\t}\n\n\t\t// Force callback invocation\n\t\t}, ignored );\n\t}\n} );\n\njQuery.each( {\n\tappendTo: \"append\",\n\tprependTo: \"prepend\",\n\tinsertBefore: \"before\",\n\tinsertAfter: \"after\",\n\treplaceAll: \"replaceWith\"\n}, function( name, original ) {\n\tjQuery.fn[ name ] = function( selector ) {\n\t\tvar elems,\n\t\t\tret = [],\n\t\t\tinsert = jQuery( selector ),\n\t\t\tlast = insert.length - 1,\n\t\t\ti = 0;\n\n\t\tfor ( ; i <= last; i++ ) {\n\t\t\telems = i === last ? this : this.clone( true );\n\t\t\tjQuery( insert[ i ] )[ original ]( elems );\n\t\t\tpush.apply( ret, elems );\n\t\t}\n\n\t\treturn this.pushStack( ret );\n\t};\n} );\n\nvar rnumnonpx = new RegExp( \"^(\" + pnum + \")(?!px)[a-z%]+$\", \"i\" );\n\nvar rcustomProp = /^--/;\n\nfunction getStyles( elem ) {\n\n\t// Support: IE <=11+ (trac-14150)\n\t// In IE popup's `window` is the opener window which makes `window.getComputedStyle( elem )`\n\t// break. Using `elem.ownerDocument.defaultView` avoids the issue.\n\tvar view = elem.ownerDocument.defaultView;\n\n\t// `document.implementation.createHTMLDocument( \"\" )` has a `null` `defaultView`\n\t// property; check `defaultView` truthiness to fallback to window in such a case.\n\tif ( !view ) {\n\t\tview = window;\n\t}\n\n\treturn view.getComputedStyle( elem );\n}\n\n// A method for quickly swapping in/out CSS properties to get correct calculations.\nfunction swap( elem, options, callback ) {\n\tvar ret, name,\n\t\told = {};\n\n\t// Remember the old values, and insert the new ones\n\tfor ( name in options ) {\n\t\told[ name ] = elem.style[ name ];\n\t\telem.style[ name ] = options[ name ];\n\t}\n\n\tret = callback.call( elem );\n\n\t// Revert the old values\n\tfor ( name in options ) {\n\t\telem.style[ name ] = old[ name ];\n\t}\n\n\treturn ret;\n}\n\nfunction curCSS( elem, name, computed ) {\n\tvar ret,\n\t\tisCustomProp = rcustomProp.test( name );\n\n\tcomputed = computed || getStyles( elem );\n\n\t// getPropertyValue is needed for `.css('--customProperty')` (gh-3144)\n\tif ( computed ) {\n\n\t\t// A fallback to direct property access is needed as `computed`, being\n\t\t// the output of `getComputedStyle`, contains camelCased keys and\n\t\t// `getPropertyValue` requires kebab-case ones.\n\t\t//\n\t\t// Support: IE <=9 - 11+\n\t\t// IE only supports `\"float\"` in `getPropertyValue`; in computed styles\n\t\t// it's only available as `\"cssFloat\"`. We no longer modify properties\n\t\t// sent to `.css()` apart from camelCasing, so we need to check both.\n\t\t// Normally, this would create difference in behavior: if\n\t\t// `getPropertyValue` returns an empty string, the value returned\n\t\t// by `.css()` would be `undefined`. This is usually the case for\n\t\t// disconnected elements. However, in IE even disconnected elements\n\t\t// with no styles return `\"none\"` for `getPropertyValue( \"float\" )`\n\t\tret = computed.getPropertyValue( name ) || computed[ name ];\n\n\t\tif ( isCustomProp && ret ) {\n\n\t\t\t// Support: Firefox 105 - 135+\n\t\t\t// Spec requires trimming whitespace for custom properties (gh-4926).\n\t\t\t// Firefox only trims leading whitespace.\n\t\t\t//\n\t\t\t// Fall back to `undefined` if empty string returned.\n\t\t\t// This collapses a missing definition with property defined\n\t\t\t// and set to an empty string but there's no standard API\n\t\t\t// allowing us to differentiate them without a performance penalty\n\t\t\t// and returning `undefined` aligns with older jQuery.\n\t\t\t//\n\t\t\t// rtrimCSS treats U+000D CARRIAGE RETURN and U+000C FORM FEED\n\t\t\t// as whitespace while CSS does not, but this is not a problem\n\t\t\t// because CSS preprocessing replaces them with U+000A LINE FEED\n\t\t\t// (which *is* CSS whitespace)\n\t\t\t// https://www.w3.org/TR/css-syntax-3/#input-preprocessing\n\t\t\tret = ret.replace( rtrimCSS, \"$1\" ) || undefined;\n\t\t}\n\n\t\tif ( ret === \"\" && !isAttached( elem ) ) {\n\t\t\tret = jQuery.style( elem, name );\n\t\t}\n\t}\n\n\treturn ret !== undefined ?\n\n\t\t// Support: IE <=9 - 11+\n\t\t// IE returns zIndex value as an integer.\n\t\tret + \"\" :\n\t\tret;\n}\n\nvar cssPrefixes = [ \"Webkit\", \"Moz\", \"ms\" ],\n\temptyStyle = document$1.createElement( \"div\" ).style;\n\n// Return a vendor-prefixed property or undefined\nfunction vendorPropName( name ) {\n\n\t// Check for vendor prefixed names\n\tvar capName = name[ 0 ].toUpperCase() + name.slice( 1 ),\n\t\ti = cssPrefixes.length;\n\n\twhile ( i-- ) {\n\t\tname = cssPrefixes[ i ] + capName;\n\t\tif ( name in emptyStyle ) {\n\t\t\treturn name;\n\t\t}\n\t}\n}\n\n// Return a potentially-mapped vendor prefixed property\nfunction finalPropName( name ) {\n\tif ( name in emptyStyle ) {\n\t\treturn name;\n\t}\n\treturn vendorPropName( name ) || name;\n}\n\nvar reliableTrDimensionsVal, reliableColDimensionsVal,\n\ttable = document$1.createElement( \"table\" );\n\n// Executing table tests requires only one layout, so they're executed\n// at the same time to save the second computation.\nfunction computeTableStyleTests() {\n\tif (\n\n\t\t// This is a singleton, we need to execute it only once\n\t\t!table ||\n\n\t\t// Finish early in limited (non-browser) environments\n\t\t!table.style\n\t) {\n\t\treturn;\n\t}\n\n\tvar trStyle,\n\t\tcol = document$1.createElement( \"col\" ),\n\t\ttr = document$1.createElement( \"tr\" ),\n\t\ttd = document$1.createElement( \"td\" );\n\n\ttable.style.cssText = \"position:absolute;left:-11111px;\" +\n\t\t\"border-collapse:separate;border-spacing:0\";\n\ttr.style.cssText = \"box-sizing:content-box;border:1px solid;height:1px\";\n\ttd.style.cssText = \"height:9px;width:9px;padding:0\";\n\n\tcol.span = 2;\n\n\tdocumentElement$1\n\t\t.appendChild( table )\n\t\t.appendChild( col )\n\t\t.parentNode\n\t\t.appendChild( tr )\n\t\t.appendChild( td )\n\t\t.parentNode\n\t\t.appendChild( td.cloneNode( true ) );\n\n\t// Don't run until window is visible\n\tif ( table.offsetWidth === 0 ) {\n\t\tdocumentElement$1.removeChild( table );\n\t\treturn;\n\t}\n\n\ttrStyle = window.getComputedStyle( tr );\n\n\t// Support: Firefox 135+\n\t// Firefox always reports computed width as if `span` was 1.\n\t// Support: Safari 18.3+\n\t// In Safari, computed width for columns is always 0.\n\t// In both these browsers, using `offsetWidth` solves the issue.\n\t// Support: IE 11+\n\t// In IE, `` computed width is `\"auto\"` unless `width` is set\n\t// explicitly via CSS so measurements there remain incorrect. Because of\n\t// the lack of a proper workaround, we accept this limitation, treating\n\t// IE as passing the test.\n\treliableColDimensionsVal = isIE || Math.round( parseFloat(\n\t\twindow.getComputedStyle( col ).width )\n\t) === 18;\n\n\t// Support: IE 10 - 11+\n\t// IE misreports `getComputedStyle` of table rows with width/height\n\t// set in CSS while `offset*` properties report correct values.\n\t// Support: Firefox 70 - 135+\n\t// Only Firefox includes border widths\n\t// in computed dimensions for table rows. (gh-4529)\n\treliableTrDimensionsVal = Math.round( parseFloat( trStyle.height ) +\n\t\tparseFloat( trStyle.borderTopWidth ) +\n\t\tparseFloat( trStyle.borderBottomWidth ) ) === tr.offsetHeight;\n\n\tdocumentElement$1.removeChild( table );\n\n\t// Nullify the table so it wouldn't be stored in the memory;\n\t// it will also be a sign that checks were already performed.\n\ttable = null;\n}\n\njQuery.extend( support, {\n\treliableTrDimensions: function() {\n\t\tcomputeTableStyleTests();\n\t\treturn reliableTrDimensionsVal;\n\t},\n\n\treliableColDimensions: function() {\n\t\tcomputeTableStyleTests();\n\t\treturn reliableColDimensionsVal;\n\t}\n} );\n\nvar cssShow = { position: \"absolute\", visibility: \"hidden\", display: \"block\" },\n\tcssNormalTransform = {\n\t\tletterSpacing: \"0\",\n\t\tfontWeight: \"400\"\n\t};\n\nfunction setPositiveNumber( _elem, value, subtract ) {\n\n\t// Any relative (+/-) values have already been\n\t// normalized at this point\n\tvar matches = rcssNum.exec( value );\n\treturn matches ?\n\n\t\t// Guard against undefined \"subtract\", e.g., when used as in cssHooks\n\t\tMath.max( 0, matches[ 2 ] - ( subtract || 0 ) ) + ( matches[ 3 ] || \"px\" ) :\n\t\tvalue;\n}\n\nfunction boxModelAdjustment( elem, dimension, box, isBorderBox, styles, computedVal ) {\n\tvar i = dimension === \"width\" ? 1 : 0,\n\t\textra = 0,\n\t\tdelta = 0,\n\t\tmarginDelta = 0;\n\n\t// Adjustment may not be necessary\n\tif ( box === ( isBorderBox ? \"border\" : \"content\" ) ) {\n\t\treturn 0;\n\t}\n\n\tfor ( ; i < 4; i += 2 ) {\n\n\t\t// Both box models exclude margin\n\t\t// Count margin delta separately to only add it after scroll gutter adjustment.\n\t\t// This is needed to make negative margins work with `outerHeight( true )` (gh-3982).\n\t\tif ( box === \"margin\" ) {\n\t\t\tmarginDelta += jQuery.css( elem, box + cssExpand[ i ], true, styles );\n\t\t}\n\n\t\t// If we get here with a content-box, we're seeking \"padding\" or \"border\" or \"margin\"\n\t\tif ( !isBorderBox ) {\n\n\t\t\t// Add padding\n\t\t\tdelta += jQuery.css( elem, \"padding\" + cssExpand[ i ], true, styles );\n\n\t\t\t// For \"border\" or \"margin\", add border\n\t\t\tif ( box !== \"padding\" ) {\n\t\t\t\tdelta += jQuery.css( elem, \"border\" + cssExpand[ i ] + \"Width\", true, styles );\n\n\t\t\t// But still keep track of it otherwise\n\t\t\t} else {\n\t\t\t\textra += jQuery.css( elem, \"border\" + cssExpand[ i ] + \"Width\", true, styles );\n\t\t\t}\n\n\t\t// If we get here with a border-box (content + padding + border), we're seeking \"content\" or\n\t\t// \"padding\" or \"margin\"\n\t\t} else {\n\n\t\t\t// For \"content\", subtract padding\n\t\t\tif ( box === \"content\" ) {\n\t\t\t\tdelta -= jQuery.css( elem, \"padding\" + cssExpand[ i ], true, styles );\n\t\t\t}\n\n\t\t\t// For \"content\" or \"padding\", subtract border\n\t\t\tif ( box !== \"margin\" ) {\n\t\t\t\tdelta -= jQuery.css( elem, \"border\" + cssExpand[ i ] + \"Width\", true, styles );\n\t\t\t}\n\t\t}\n\t}\n\n\t// Account for positive content-box scroll gutter when requested by providing computedVal\n\tif ( !isBorderBox && computedVal >= 0 ) {\n\n\t\t// offsetWidth/offsetHeight is a rounded sum of content, padding, scroll gutter, and border\n\t\t// Assuming integer scroll gutter, subtract the rest and round down\n\t\tdelta += Math.max( 0, Math.ceil(\n\t\t\telem[ \"offset\" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] -\n\t\t\tcomputedVal -\n\t\t\tdelta -\n\t\t\textra -\n\t\t\t0.5\n\n\t\t// If offsetWidth/offsetHeight is unknown, then we can't determine content-box scroll gutter\n\t\t// Use an explicit zero to avoid NaN (gh-3964)\n\t\t) ) || 0;\n\t}\n\n\treturn delta + marginDelta;\n}\n\nfunction getWidthOrHeight( elem, dimension, extra ) {\n\n\t// Start with computed style\n\tvar styles = getStyles( elem ),\n\n\t\t// To avoid forcing a reflow, only fetch boxSizing if we need it (gh-4322).\n\t\t// Fake content-box until we know it's needed to know the true value.\n\t\tboxSizingNeeded = isIE || extra,\n\t\tisBorderBox = boxSizingNeeded &&\n\t\t\tjQuery.css( elem, \"boxSizing\", false, styles ) === \"border-box\",\n\t\tvalueIsBorderBox = isBorderBox,\n\n\t\tval = curCSS( elem, dimension, styles ),\n\t\toffsetProp = \"offset\" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 );\n\n\t// Return a confounding non-pixel value or feign ignorance, as appropriate.\n\tif ( rnumnonpx.test( val ) ) {\n\t\tif ( !extra ) {\n\t\t\treturn val;\n\t\t}\n\t\tval = \"auto\";\n\t}\n\n\n\tif (\n\t\t(\n\n\t\t\t// Fall back to offsetWidth/offsetHeight when value is \"auto\"\n\t\t\t// This happens for inline elements with no explicit setting (gh-3571)\n\t\t\tval === \"auto\" ||\n\n\t\t\t// Support: IE 9 - 11+\n\t\t\t// Use offsetWidth/offsetHeight for when box sizing is unreliable.\n\t\t\t// In those cases, the computed value can be trusted to be border-box.\n\t\t\t( isIE && isBorderBox ) ||\n\n\t\t\t( !support.reliableColDimensions() && nodeName( elem, \"col\" ) ) ||\n\n\t\t\t( !support.reliableTrDimensions() && nodeName( elem, \"tr\" ) )\n\t\t) &&\n\n\t\t// Make sure the element is visible & connected\n\t\telem.getClientRects().length ) {\n\n\t\tisBorderBox = jQuery.css( elem, \"boxSizing\", false, styles ) === \"border-box\";\n\n\t\t// Where available, offsetWidth/offsetHeight approximate border box dimensions.\n\t\t// Where not available (e.g., SVG), assume unreliable box-sizing and interpret the\n\t\t// retrieved value as a content box dimension.\n\t\tvalueIsBorderBox = offsetProp in elem;\n\t\tif ( valueIsBorderBox ) {\n\t\t\tval = elem[ offsetProp ];\n\t\t}\n\t}\n\n\t// Normalize \"\" and auto\n\tval = parseFloat( val ) || 0;\n\n\t// Adjust for the element's box model\n\treturn ( val +\n\t\tboxModelAdjustment(\n\t\t\telem,\n\t\t\tdimension,\n\t\t\textra || ( isBorderBox ? \"border\" : \"content\" ),\n\t\t\tvalueIsBorderBox,\n\t\t\tstyles,\n\n\t\t\t// Provide the current computed size to request scroll gutter calculation (gh-3589)\n\t\t\tval\n\t\t)\n\t) + \"px\";\n}\n\njQuery.extend( {\n\n\t// Add in style property hooks for overriding the default\n\t// behavior of getting and setting a style property\n\tcssHooks: {},\n\n\t// Get and set the style property on a DOM Node\n\tstyle: function( elem, name, value, extra ) {\n\n\t\t// Don't set styles on text and comment nodes\n\t\tif ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Make sure that we're working with the right name\n\t\tvar ret, type, hooks,\n\t\t\torigName = cssCamelCase( name ),\n\t\t\tisCustomProp = rcustomProp.test( name ),\n\t\t\tstyle = elem.style;\n\n\t\t// Make sure that we're working with the right name. We don't\n\t\t// want to query the value if it is a CSS custom property\n\t\t// since they are user-defined.\n\t\tif ( !isCustomProp ) {\n\t\t\tname = finalPropName( origName );\n\t\t}\n\n\t\t// Gets hook for the prefixed version, then unprefixed version\n\t\thooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];\n\n\t\t// Check if we're setting a value\n\t\tif ( value !== undefined ) {\n\t\t\ttype = typeof value;\n\n\t\t\t// Convert \"+=\" or \"-=\" to relative numbers (trac-7345)\n\t\t\tif ( type === \"string\" && ( ret = rcssNum.exec( value ) ) && ret[ 1 ] ) {\n\t\t\t\tvalue = adjustCSS( elem, name, ret );\n\n\t\t\t\t// Fixes bug trac-9237\n\t\t\t\ttype = \"number\";\n\t\t\t}\n\n\t\t\t// Make sure that null and NaN values aren't set (trac-7116)\n\t\t\tif ( value == null || value !== value ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// If the value is a number, add `px` for certain CSS properties\n\t\t\tif ( type === \"number\" ) {\n\t\t\t\tvalue += ret && ret[ 3 ] || ( isAutoPx( origName ) ? \"px\" : \"\" );\n\t\t\t}\n\n\t\t\t// Support: IE <=9 - 11+\n\t\t\t// background-* props of a cloned element affect the source element (trac-8908)\n\t\t\tif ( isIE && value === \"\" && name.indexOf( \"background\" ) === 0 ) {\n\t\t\t\tstyle[ name ] = \"inherit\";\n\t\t\t}\n\n\t\t\t// If a hook was provided, use that value, otherwise just set the specified value\n\t\t\tif ( !hooks || !( \"set\" in hooks ) ||\n\t\t\t\t( value = hooks.set( elem, value, extra ) ) !== undefined ) {\n\n\t\t\t\tif ( isCustomProp ) {\n\t\t\t\t\tstyle.setProperty( name, value );\n\t\t\t\t} else {\n\t\t\t\t\tstyle[ name ] = value;\n\t\t\t\t}\n\t\t\t}\n\n\t\t} else {\n\n\t\t\t// If a hook was provided get the non-computed value from there\n\t\t\tif ( hooks && \"get\" in hooks &&\n\t\t\t\t( ret = hooks.get( elem, false, extra ) ) !== undefined ) {\n\n\t\t\t\treturn ret;\n\t\t\t}\n\n\t\t\t// Otherwise just get the value from the style object\n\t\t\treturn style[ name ];\n\t\t}\n\t},\n\n\tcss: function( elem, name, extra, styles ) {\n\t\tvar val, num, hooks,\n\t\t\torigName = cssCamelCase( name ),\n\t\t\tisCustomProp = rcustomProp.test( name );\n\n\t\t// Make sure that we're working with the right name. We don't\n\t\t// want to modify the value if it is a CSS custom property\n\t\t// since they are user-defined.\n\t\tif ( !isCustomProp ) {\n\t\t\tname = finalPropName( origName );\n\t\t}\n\n\t\t// Try prefixed name followed by the unprefixed name\n\t\thooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];\n\n\t\t// If a hook was provided get the computed value from there\n\t\tif ( hooks && \"get\" in hooks ) {\n\t\t\tval = hooks.get( elem, true, extra );\n\t\t}\n\n\t\t// Otherwise, if a way to get the computed value exists, use that\n\t\tif ( val === undefined ) {\n\t\t\tval = curCSS( elem, name, styles );\n\t\t}\n\n\t\t// Convert \"normal\" to computed value\n\t\tif ( val === \"normal\" && name in cssNormalTransform ) {\n\t\t\tval = cssNormalTransform[ name ];\n\t\t}\n\n\t\t// Make numeric if forced or a qualifier was provided and val looks numeric\n\t\tif ( extra === \"\" || extra ) {\n\t\t\tnum = parseFloat( val );\n\t\t\treturn extra === true || isFinite( num ) ? num || 0 : val;\n\t\t}\n\n\t\treturn val;\n\t}\n} );\n\njQuery.each( [ \"height\", \"width\" ], function( _i, dimension ) {\n\tjQuery.cssHooks[ dimension ] = {\n\t\tget: function( elem, computed, extra ) {\n\t\t\tif ( computed ) {\n\n\t\t\t\t// Elements with `display: none` can have dimension info if\n\t\t\t\t// we invisibly show them.\n\t\t\t\treturn jQuery.css( elem, \"display\" ) === \"none\" ?\n\t\t\t\t\tswap( elem, cssShow, function() {\n\t\t\t\t\t\treturn getWidthOrHeight( elem, dimension, extra );\n\t\t\t\t\t} ) :\n\t\t\t\t\tgetWidthOrHeight( elem, dimension, extra );\n\t\t\t}\n\t\t},\n\n\t\tset: function( elem, value, extra ) {\n\t\t\tvar matches,\n\t\t\t\tstyles = getStyles( elem ),\n\n\t\t\t\t// To avoid forcing a reflow, only fetch boxSizing if we need it (gh-3991)\n\t\t\t\tisBorderBox = extra &&\n\t\t\t\t\tjQuery.css( elem, \"boxSizing\", false, styles ) === \"border-box\",\n\t\t\t\tsubtract = extra ?\n\t\t\t\t\tboxModelAdjustment(\n\t\t\t\t\t\telem,\n\t\t\t\t\t\tdimension,\n\t\t\t\t\t\textra,\n\t\t\t\t\t\tisBorderBox,\n\t\t\t\t\t\tstyles\n\t\t\t\t\t) :\n\t\t\t\t\t0;\n\n\t\t\t// Convert to pixels if value adjustment is needed\n\t\t\tif ( subtract && ( matches = rcssNum.exec( value ) ) &&\n\t\t\t\t( matches[ 3 ] || \"px\" ) !== \"px\" ) {\n\n\t\t\t\telem.style[ dimension ] = value;\n\t\t\t\tvalue = jQuery.css( elem, dimension );\n\t\t\t}\n\n\t\t\treturn setPositiveNumber( elem, value, subtract );\n\t\t}\n\t};\n} );\n\n// These hooks are used by animate to expand properties\njQuery.each( {\n\tmargin: \"\",\n\tpadding: \"\",\n\tborder: \"Width\"\n}, function( prefix, suffix ) {\n\tjQuery.cssHooks[ prefix + suffix ] = {\n\t\texpand: function( value ) {\n\t\t\tvar i = 0,\n\t\t\t\texpanded = {},\n\n\t\t\t\t// Assumes a single number if not a string\n\t\t\t\tparts = typeof value === \"string\" ? value.split( \" \" ) : [ value ];\n\n\t\t\tfor ( ; i < 4; i++ ) {\n\t\t\t\texpanded[ prefix + cssExpand[ i ] + suffix ] =\n\t\t\t\t\tparts[ i ] || parts[ i - 2 ] || parts[ 0 ];\n\t\t\t}\n\n\t\t\treturn expanded;\n\t\t}\n\t};\n\n\tif ( prefix !== \"margin\" ) {\n\t\tjQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber;\n\t}\n} );\n\njQuery.fn.extend( {\n\tcss: function( name, value ) {\n\t\treturn access( this, function( elem, name, value ) {\n\t\t\tvar styles, len,\n\t\t\t\tmap = {},\n\t\t\t\ti = 0;\n\n\t\t\tif ( Array.isArray( name ) ) {\n\t\t\t\tstyles = getStyles( elem );\n\t\t\t\tlen = name.length;\n\n\t\t\t\tfor ( ; i < len; i++ ) {\n\t\t\t\t\tmap[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles );\n\t\t\t\t}\n\n\t\t\t\treturn map;\n\t\t\t}\n\n\t\t\treturn value !== undefined ?\n\t\t\t\tjQuery.style( elem, name, value ) :\n\t\t\t\tjQuery.css( elem, name );\n\t\t}, name, value, arguments.length > 1 );\n\t}\n} );\n\nfunction Tween( elem, options, prop, end, easing ) {\n\treturn new Tween.prototype.init( elem, options, prop, end, easing );\n}\njQuery.Tween = Tween;\n\nTween.prototype = {\n\tconstructor: Tween,\n\tinit: function( elem, options, prop, end, easing, unit ) {\n\t\tthis.elem = elem;\n\t\tthis.prop = prop;\n\t\tthis.easing = easing || jQuery.easing._default;\n\t\tthis.options = options;\n\t\tthis.start = this.now = this.cur();\n\t\tthis.end = end;\n\t\tthis.unit = unit || ( isAutoPx( prop ) ? \"px\" : \"\" );\n\t},\n\tcur: function() {\n\t\tvar hooks = Tween.propHooks[ this.prop ];\n\n\t\treturn hooks && hooks.get ?\n\t\t\thooks.get( this ) :\n\t\t\tTween.propHooks._default.get( this );\n\t},\n\trun: function( percent ) {\n\t\tvar eased,\n\t\t\thooks = Tween.propHooks[ this.prop ];\n\n\t\tif ( this.options.duration ) {\n\t\t\tthis.pos = eased = jQuery.easing[ this.easing ](\n\t\t\t\tpercent, this.options.duration * percent, 0, 1, this.options.duration\n\t\t\t);\n\t\t} else {\n\t\t\tthis.pos = eased = percent;\n\t\t}\n\t\tthis.now = ( this.end - this.start ) * eased + this.start;\n\n\t\tif ( this.options.step ) {\n\t\t\tthis.options.step.call( this.elem, this.now, this );\n\t\t}\n\n\t\tif ( hooks && hooks.set ) {\n\t\t\thooks.set( this );\n\t\t} else {\n\t\t\tTween.propHooks._default.set( this );\n\t\t}\n\t\treturn this;\n\t}\n};\n\nTween.prototype.init.prototype = Tween.prototype;\n\nTween.propHooks = {\n\t_default: {\n\t\tget: function( tween ) {\n\t\t\tvar result;\n\n\t\t\t// Use a property on the element directly when it is not a DOM element,\n\t\t\t// or when there is no matching style property that exists.\n\t\t\tif ( tween.elem.nodeType !== 1 ||\n\t\t\t\ttween.elem[ tween.prop ] != null && tween.elem.style[ tween.prop ] == null ) {\n\t\t\t\treturn tween.elem[ tween.prop ];\n\t\t\t}\n\n\t\t\t// Passing an empty string as a 3rd parameter to .css will automatically\n\t\t\t// attempt a parseFloat and fallback to a string if the parse fails.\n\t\t\t// Simple values such as \"10px\" are parsed to Float;\n\t\t\t// complex values such as \"rotate(1rad)\" are returned as-is.\n\t\t\tresult = jQuery.css( tween.elem, tween.prop, \"\" );\n\n\t\t\t// Empty strings, null, undefined and \"auto\" are converted to 0.\n\t\t\treturn !result || result === \"auto\" ? 0 : result;\n\t\t},\n\t\tset: function( tween ) {\n\n\t\t\t// Use step hook for back compat.\n\t\t\t// Use cssHook if its there.\n\t\t\t// Use .style if available and use plain properties where available.\n\t\t\tif ( jQuery.fx.step[ tween.prop ] ) {\n\t\t\t\tjQuery.fx.step[ tween.prop ]( tween );\n\t\t\t} else if ( tween.elem.nodeType === 1 && (\n\t\t\t\tjQuery.cssHooks[ tween.prop ] ||\n\t\t\t\t\ttween.elem.style[ finalPropName( tween.prop ) ] != null ) ) {\n\t\t\t\tjQuery.style( tween.elem, tween.prop, tween.now + tween.unit );\n\t\t\t} else {\n\t\t\t\ttween.elem[ tween.prop ] = tween.now;\n\t\t\t}\n\t\t}\n\t}\n};\n\njQuery.easing = {\n\tlinear: function( p ) {\n\t\treturn p;\n\t},\n\tswing: function( p ) {\n\t\treturn 0.5 - Math.cos( p * Math.PI ) / 2;\n\t},\n\t_default: \"swing\"\n};\n\njQuery.fx = Tween.prototype.init;\n\n// Back compat <1.8 extension point\njQuery.fx.step = {};\n\nvar\n\tfxNow, inProgress,\n\trfxtypes = /^(?:toggle|show|hide)$/,\n\trrun = /queueHooks$/;\n\nfunction schedule() {\n\tif ( inProgress ) {\n\t\tif ( document$1.hidden === false && window.requestAnimationFrame ) {\n\t\t\twindow.requestAnimationFrame( schedule );\n\t\t} else {\n\t\t\twindow.setTimeout( schedule, 13 );\n\t\t}\n\n\t\tjQuery.fx.tick();\n\t}\n}\n\n// Animations created synchronously will run synchronously\nfunction createFxNow() {\n\twindow.setTimeout( function() {\n\t\tfxNow = undefined;\n\t} );\n\treturn ( fxNow = Date.now() );\n}\n\n// Generate parameters to create a standard animation\nfunction genFx( type, includeWidth ) {\n\tvar which,\n\t\ti = 0,\n\t\tattrs = { height: type };\n\n\t// If we include width, step value is 1 to do all cssExpand values,\n\t// otherwise step value is 2 to skip over Left and Right\n\tincludeWidth = includeWidth ? 1 : 0;\n\tfor ( ; i < 4; i += 2 - includeWidth ) {\n\t\twhich = cssExpand[ i ];\n\t\tattrs[ \"margin\" + which ] = attrs[ \"padding\" + which ] = type;\n\t}\n\n\tif ( includeWidth ) {\n\t\tattrs.opacity = attrs.width = type;\n\t}\n\n\treturn attrs;\n}\n\nfunction createTween( value, prop, animation ) {\n\tvar tween,\n\t\tcollection = ( Animation.tweeners[ prop ] || [] ).concat( Animation.tweeners[ \"*\" ] ),\n\t\tindex = 0,\n\t\tlength = collection.length;\n\tfor ( ; index < length; index++ ) {\n\t\tif ( ( tween = collection[ index ].call( animation, prop, value ) ) ) {\n\n\t\t\t// We're done with this property\n\t\t\treturn tween;\n\t\t}\n\t}\n}\n\nfunction defaultPrefilter( elem, props, opts ) {\n\tvar prop, value, toggle, hooks, oldfire, propTween, restoreDisplay, display,\n\t\tisBox = \"width\" in props || \"height\" in props,\n\t\tanim = this,\n\t\torig = {},\n\t\tstyle = elem.style,\n\t\thidden = elem.nodeType && isHiddenWithinTree( elem ),\n\t\tdataShow = dataPriv.get( elem, \"fxshow\" );\n\n\t// Queue-skipping animations hijack the fx hooks\n\tif ( !opts.queue ) {\n\t\thooks = jQuery._queueHooks( elem, \"fx\" );\n\t\tif ( hooks.unqueued == null ) {\n\t\t\thooks.unqueued = 0;\n\t\t\toldfire = hooks.empty.fire;\n\t\t\thooks.empty.fire = function() {\n\t\t\t\tif ( !hooks.unqueued ) {\n\t\t\t\t\toldfire();\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\t\thooks.unqueued++;\n\n\t\tanim.always( function() {\n\n\t\t\t// Ensure the complete handler is called before this completes\n\t\t\tanim.always( function() {\n\t\t\t\thooks.unqueued--;\n\t\t\t\tif ( !jQuery.queue( elem, \"fx\" ).length ) {\n\t\t\t\t\thooks.empty.fire();\n\t\t\t\t}\n\t\t\t} );\n\t\t} );\n\t}\n\n\t// Detect show/hide animations\n\tfor ( prop in props ) {\n\t\tvalue = props[ prop ];\n\t\tif ( rfxtypes.test( value ) ) {\n\t\t\tdelete props[ prop ];\n\t\t\ttoggle = toggle || value === \"toggle\";\n\t\t\tif ( value === ( hidden ? \"hide\" : \"show\" ) ) {\n\n\t\t\t\t// Pretend to be hidden if this is a \"show\" and\n\t\t\t\t// there is still data from a stopped show/hide\n\t\t\t\tif ( value === \"show\" && dataShow && dataShow[ prop ] !== undefined ) {\n\t\t\t\t\thidden = true;\n\n\t\t\t\t// Ignore all other no-op show/hide data\n\t\t\t\t} else {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\t\t\torig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop );\n\t\t}\n\t}\n\n\t// Bail out if this is a no-op like .hide().hide()\n\tpropTween = !jQuery.isEmptyObject( props );\n\tif ( !propTween && jQuery.isEmptyObject( orig ) ) {\n\t\treturn;\n\t}\n\n\t// Restrict \"overflow\" and \"display\" styles during box animations\n\tif ( isBox && elem.nodeType === 1 ) {\n\n\t\t// Support: IE <=9 - 11+\n\t\t// Record all 3 overflow attributes because IE does not infer the shorthand\n\t\t// from identically-valued overflowX and overflowY.\n\t\topts.overflow = [ style.overflow, style.overflowX, style.overflowY ];\n\n\t\t// Identify a display type, preferring old show/hide data over the CSS cascade\n\t\trestoreDisplay = dataShow && dataShow.display;\n\t\tif ( restoreDisplay == null ) {\n\t\t\trestoreDisplay = dataPriv.get( elem, \"display\" );\n\t\t}\n\t\tdisplay = jQuery.css( elem, \"display\" );\n\t\tif ( display === \"none\" ) {\n\t\t\tif ( restoreDisplay ) {\n\t\t\t\tdisplay = restoreDisplay;\n\t\t\t} else {\n\n\t\t\t\t// Get nonempty value(s) by temporarily forcing visibility\n\t\t\t\tshowHide( [ elem ], true );\n\t\t\t\trestoreDisplay = elem.style.display || restoreDisplay;\n\t\t\t\tdisplay = jQuery.css( elem, \"display\" );\n\t\t\t\tshowHide( [ elem ] );\n\t\t\t}\n\t\t}\n\n\t\t// Animate inline elements as inline-block\n\t\tif ( display === \"inline\" || display === \"inline-block\" && restoreDisplay != null ) {\n\t\t\tif ( jQuery.css( elem, \"float\" ) === \"none\" ) {\n\n\t\t\t\t// Restore the original display value at the end of pure show/hide animations\n\t\t\t\tif ( !propTween ) {\n\t\t\t\t\tanim.done( function() {\n\t\t\t\t\t\tstyle.display = restoreDisplay;\n\t\t\t\t\t} );\n\t\t\t\t\tif ( restoreDisplay == null ) {\n\t\t\t\t\t\tdisplay = style.display;\n\t\t\t\t\t\trestoreDisplay = display === \"none\" ? \"\" : display;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tstyle.display = \"inline-block\";\n\t\t\t}\n\t\t}\n\t}\n\n\tif ( opts.overflow ) {\n\t\tstyle.overflow = \"hidden\";\n\t\tanim.always( function() {\n\t\t\tstyle.overflow = opts.overflow[ 0 ];\n\t\t\tstyle.overflowX = opts.overflow[ 1 ];\n\t\t\tstyle.overflowY = opts.overflow[ 2 ];\n\t\t} );\n\t}\n\n\t// Implement show/hide animations\n\tpropTween = false;\n\tfor ( prop in orig ) {\n\n\t\t// General show/hide setup for this element animation\n\t\tif ( !propTween ) {\n\t\t\tif ( dataShow ) {\n\t\t\t\tif ( \"hidden\" in dataShow ) {\n\t\t\t\t\thidden = dataShow.hidden;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tdataShow = dataPriv.set( elem, \"fxshow\", { display: restoreDisplay } );\n\t\t\t}\n\n\t\t\t// Store hidden/visible for toggle so `.stop().toggle()` \"reverses\"\n\t\t\tif ( toggle ) {\n\t\t\t\tdataShow.hidden = !hidden;\n\t\t\t}\n\n\t\t\t// Show elements before animating them\n\t\t\tif ( hidden ) {\n\t\t\t\tshowHide( [ elem ], true );\n\t\t\t}\n\n\t\t\t// eslint-disable-next-line no-loop-func\n\t\t\tanim.done( function() {\n\n\t\t\t\t// The final step of a \"hide\" animation is actually hiding the element\n\t\t\t\tif ( !hidden ) {\n\t\t\t\t\tshowHide( [ elem ] );\n\t\t\t\t}\n\t\t\t\tdataPriv.remove( elem, \"fxshow\" );\n\t\t\t\tfor ( prop in orig ) {\n\t\t\t\t\tjQuery.style( elem, prop, orig[ prop ] );\n\t\t\t\t}\n\t\t\t} );\n\t\t}\n\n\t\t// Per-property setup\n\t\tpropTween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim );\n\t\tif ( !( prop in dataShow ) ) {\n\t\t\tdataShow[ prop ] = propTween.start;\n\t\t\tif ( hidden ) {\n\t\t\t\tpropTween.end = propTween.start;\n\t\t\t\tpropTween.start = 0;\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunction propFilter( props, specialEasing ) {\n\tvar index, name, easing, value, hooks;\n\n\t// camelCase, specialEasing and expand cssHook pass\n\tfor ( index in props ) {\n\t\tname = cssCamelCase( index );\n\t\teasing = specialEasing[ name ];\n\t\tvalue = props[ index ];\n\t\tif ( Array.isArray( value ) ) {\n\t\t\teasing = value[ 1 ];\n\t\t\tvalue = props[ index ] = value[ 0 ];\n\t\t}\n\n\t\tif ( index !== name ) {\n\t\t\tprops[ name ] = value;\n\t\t\tdelete props[ index ];\n\t\t}\n\n\t\thooks = jQuery.cssHooks[ name ];\n\t\tif ( hooks && \"expand\" in hooks ) {\n\t\t\tvalue = hooks.expand( value );\n\t\t\tdelete props[ name ];\n\n\t\t\t// Not quite $.extend, this won't overwrite existing keys.\n\t\t\t// Reusing 'index' because we have the correct \"name\"\n\t\t\tfor ( index in value ) {\n\t\t\t\tif ( !( index in props ) ) {\n\t\t\t\t\tprops[ index ] = value[ index ];\n\t\t\t\t\tspecialEasing[ index ] = easing;\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tspecialEasing[ name ] = easing;\n\t\t}\n\t}\n}\n\nfunction Animation( elem, properties, options ) {\n\tvar result,\n\t\tstopped,\n\t\tindex = 0,\n\t\tlength = Animation.prefilters.length,\n\t\tdeferred = jQuery.Deferred().always( function() {\n\n\t\t\t// Don't match elem in the :animated selector\n\t\t\tdelete tick.elem;\n\t\t} ),\n\t\ttick = function() {\n\t\t\tif ( stopped ) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tvar currentTime = fxNow || createFxNow(),\n\t\t\t\tremaining = Math.max( 0, animation.startTime + animation.duration - currentTime ),\n\n\t\t\t\tpercent = 1 - ( remaining / animation.duration || 0 ),\n\t\t\t\tindex = 0,\n\t\t\t\tlength = animation.tweens.length;\n\n\t\t\tfor ( ; index < length; index++ ) {\n\t\t\t\tanimation.tweens[ index ].run( percent );\n\t\t\t}\n\n\t\t\tdeferred.notifyWith( elem, [ animation, percent, remaining ] );\n\n\t\t\t// If there's more to do, yield\n\t\t\tif ( percent < 1 && length ) {\n\t\t\t\treturn remaining;\n\t\t\t}\n\n\t\t\t// If this was an empty animation, synthesize a final progress notification\n\t\t\tif ( !length ) {\n\t\t\t\tdeferred.notifyWith( elem, [ animation, 1, 0 ] );\n\t\t\t}\n\n\t\t\t// Resolve the animation and report its conclusion\n\t\t\tdeferred.resolveWith( elem, [ animation ] );\n\t\t\treturn false;\n\t\t},\n\t\tanimation = deferred.promise( {\n\t\t\telem: elem,\n\t\t\tprops: jQuery.extend( {}, properties ),\n\t\t\topts: jQuery.extend( true, {\n\t\t\t\tspecialEasing: {},\n\t\t\t\teasing: jQuery.easing._default\n\t\t\t}, options ),\n\t\t\toriginalProperties: properties,\n\t\t\toriginalOptions: options,\n\t\t\tstartTime: fxNow || createFxNow(),\n\t\t\tduration: options.duration,\n\t\t\ttweens: [],\n\t\t\tcreateTween: function( prop, end ) {\n\t\t\t\tvar tween = jQuery.Tween( elem, animation.opts, prop, end,\n\t\t\t\t\tanimation.opts.specialEasing[ prop ] || animation.opts.easing );\n\t\t\t\tanimation.tweens.push( tween );\n\t\t\t\treturn tween;\n\t\t\t},\n\t\t\tstop: function( gotoEnd ) {\n\t\t\t\tvar index = 0,\n\n\t\t\t\t\t// If we are going to the end, we want to run all the tweens\n\t\t\t\t\t// otherwise we skip this part\n\t\t\t\t\tlength = gotoEnd ? animation.tweens.length : 0;\n\t\t\t\tif ( stopped ) {\n\t\t\t\t\treturn this;\n\t\t\t\t}\n\t\t\t\tstopped = true;\n\t\t\t\tfor ( ; index < length; index++ ) {\n\t\t\t\t\tanimation.tweens[ index ].run( 1 );\n\t\t\t\t}\n\n\t\t\t\t// Resolve when we played the last frame; otherwise, reject\n\t\t\t\tif ( gotoEnd ) {\n\t\t\t\t\tdeferred.notifyWith( elem, [ animation, 1, 0 ] );\n\t\t\t\t\tdeferred.resolveWith( elem, [ animation, gotoEnd ] );\n\t\t\t\t} else {\n\t\t\t\t\tdeferred.rejectWith( elem, [ animation, gotoEnd ] );\n\t\t\t\t}\n\t\t\t\treturn this;\n\t\t\t}\n\t\t} ),\n\t\tprops = animation.props;\n\n\tpropFilter( props, animation.opts.specialEasing );\n\n\tfor ( ; index < length; index++ ) {\n\t\tresult = Animation.prefilters[ index ].call( animation, elem, props, animation.opts );\n\t\tif ( result ) {\n\t\t\tif ( typeof result.stop === \"function\" ) {\n\t\t\t\tjQuery._queueHooks( animation.elem, animation.opts.queue ).stop =\n\t\t\t\t\tresult.stop.bind( result );\n\t\t\t}\n\t\t\treturn result;\n\t\t}\n\t}\n\n\tjQuery.map( props, createTween, animation );\n\n\tif ( typeof animation.opts.start === \"function\" ) {\n\t\tanimation.opts.start.call( elem, animation );\n\t}\n\n\t// Attach callbacks from options\n\tanimation\n\t\t.progress( animation.opts.progress )\n\t\t.done( animation.opts.done, animation.opts.complete )\n\t\t.fail( animation.opts.fail )\n\t\t.always( animation.opts.always );\n\n\tjQuery.fx.timer(\n\t\tjQuery.extend( tick, {\n\t\t\telem: elem,\n\t\t\tanim: animation,\n\t\t\tqueue: animation.opts.queue\n\t\t} )\n\t);\n\n\treturn animation;\n}\n\njQuery.Animation = jQuery.extend( Animation, {\n\n\ttweeners: {\n\t\t\"*\": [ function( prop, value ) {\n\t\t\tvar tween = this.createTween( prop, value );\n\t\t\tadjustCSS( tween.elem, prop, rcssNum.exec( value ), tween );\n\t\t\treturn tween;\n\t\t} ]\n\t},\n\n\ttweener: function( props, callback ) {\n\t\tif ( typeof props === \"function\" ) {\n\t\t\tcallback = props;\n\t\t\tprops = [ \"*\" ];\n\t\t} else {\n\t\t\tprops = props.match( rnothtmlwhite );\n\t\t}\n\n\t\tvar prop,\n\t\t\tindex = 0,\n\t\t\tlength = props.length;\n\n\t\tfor ( ; index < length; index++ ) {\n\t\t\tprop = props[ index ];\n\t\t\tAnimation.tweeners[ prop ] = Animation.tweeners[ prop ] || [];\n\t\t\tAnimation.tweeners[ prop ].unshift( callback );\n\t\t}\n\t},\n\n\tprefilters: [ defaultPrefilter ],\n\n\tprefilter: function( callback, prepend ) {\n\t\tif ( prepend ) {\n\t\t\tAnimation.prefilters.unshift( callback );\n\t\t} else {\n\t\t\tAnimation.prefilters.push( callback );\n\t\t}\n\t}\n} );\n\njQuery.speed = function( speed, easing, fn ) {\n\tvar opt = speed && typeof speed === \"object\" ? jQuery.extend( {}, speed ) : {\n\t\tcomplete: fn || easing ||\n\t\t\ttypeof speed === \"function\" && speed,\n\t\tduration: speed,\n\t\teasing: fn && easing || easing && typeof easing !== \"function\" && easing\n\t};\n\n\t// Go to the end state if fx are off\n\tif ( jQuery.fx.off ) {\n\t\topt.duration = 0;\n\n\t} else {\n\t\tif ( typeof opt.duration !== \"number\" ) {\n\t\t\tif ( opt.duration in jQuery.fx.speeds ) {\n\t\t\t\topt.duration = jQuery.fx.speeds[ opt.duration ];\n\n\t\t\t} else {\n\t\t\t\topt.duration = jQuery.fx.speeds._default;\n\t\t\t}\n\t\t}\n\t}\n\n\t// Normalize opt.queue - true/undefined/null -> \"fx\"\n\tif ( opt.queue == null || opt.queue === true ) {\n\t\topt.queue = \"fx\";\n\t}\n\n\t// Queueing\n\topt.old = opt.complete;\n\n\topt.complete = function() {\n\t\tif ( typeof opt.old === \"function\" ) {\n\t\t\topt.old.call( this );\n\t\t}\n\n\t\tif ( opt.queue ) {\n\t\t\tjQuery.dequeue( this, opt.queue );\n\t\t}\n\t};\n\n\treturn opt;\n};\n\njQuery.fn.extend( {\n\tfadeTo: function( speed, to, easing, callback ) {\n\n\t\t// Show any hidden elements after setting opacity to 0\n\t\treturn this.filter( isHiddenWithinTree ).css( \"opacity\", 0 ).show()\n\n\t\t\t// Animate to the value specified\n\t\t\t.end().animate( { opacity: to }, speed, easing, callback );\n\t},\n\tanimate: function( prop, speed, easing, callback ) {\n\t\tvar empty = jQuery.isEmptyObject( prop ),\n\t\t\toptall = jQuery.speed( speed, easing, callback ),\n\t\t\tdoAnimation = function() {\n\n\t\t\t\t// Operate on a copy of prop so per-property easing won't be lost\n\t\t\t\tvar anim = Animation( this, jQuery.extend( {}, prop ), optall );\n\n\t\t\t\t// Empty animations, or finishing resolves immediately\n\t\t\t\tif ( empty || dataPriv.get( this, \"finish\" ) ) {\n\t\t\t\t\tanim.stop( true );\n\t\t\t\t}\n\t\t\t};\n\n\t\tdoAnimation.finish = doAnimation;\n\n\t\treturn empty || optall.queue === false ?\n\t\t\tthis.each( doAnimation ) :\n\t\t\tthis.queue( optall.queue, doAnimation );\n\t},\n\tstop: function( type, clearQueue, gotoEnd ) {\n\t\tvar stopQueue = function( hooks ) {\n\t\t\tvar stop = hooks.stop;\n\t\t\tdelete hooks.stop;\n\t\t\tstop( gotoEnd );\n\t\t};\n\n\t\tif ( typeof type !== \"string\" ) {\n\t\t\tgotoEnd = clearQueue;\n\t\t\tclearQueue = type;\n\t\t\ttype = undefined;\n\t\t}\n\t\tif ( clearQueue ) {\n\t\t\tthis.queue( type || \"fx\", [] );\n\t\t}\n\n\t\treturn this.each( function() {\n\t\t\tvar dequeue = true,\n\t\t\t\tindex = type != null && type + \"queueHooks\",\n\t\t\t\ttimers = jQuery.timers,\n\t\t\t\tdata = dataPriv.get( this );\n\n\t\t\tif ( index ) {\n\t\t\t\tif ( data[ index ] && data[ index ].stop ) {\n\t\t\t\t\tstopQueue( data[ index ] );\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tfor ( index in data ) {\n\t\t\t\t\tif ( data[ index ] && data[ index ].stop && rrun.test( index ) ) {\n\t\t\t\t\t\tstopQueue( data[ index ] );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfor ( index = timers.length; index--; ) {\n\t\t\t\tif ( timers[ index ].elem === this &&\n\t\t\t\t\t( type == null || timers[ index ].queue === type ) ) {\n\n\t\t\t\t\ttimers[ index ].anim.stop( gotoEnd );\n\t\t\t\t\tdequeue = false;\n\t\t\t\t\ttimers.splice( index, 1 );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Start the next in the queue if the last step wasn't forced.\n\t\t\t// Timers currently will call their complete callbacks, which\n\t\t\t// will dequeue but only if they were gotoEnd.\n\t\t\tif ( dequeue || !gotoEnd ) {\n\t\t\t\tjQuery.dequeue( this, type );\n\t\t\t}\n\t\t} );\n\t},\n\tfinish: function( type ) {\n\t\tif ( type !== false ) {\n\t\t\ttype = type || \"fx\";\n\t\t}\n\t\treturn this.each( function() {\n\t\t\tvar index,\n\t\t\t\tdata = dataPriv.get( this ),\n\t\t\t\tqueue = data[ type + \"queue\" ],\n\t\t\t\thooks = data[ type + \"queueHooks\" ],\n\t\t\t\ttimers = jQuery.timers,\n\t\t\t\tlength = queue ? queue.length : 0;\n\n\t\t\t// Enable finishing flag on private data\n\t\t\tdata.finish = true;\n\n\t\t\t// Empty the queue first\n\t\t\tjQuery.queue( this, type, [] );\n\n\t\t\tif ( hooks && hooks.stop ) {\n\t\t\t\thooks.stop.call( this, true );\n\t\t\t}\n\n\t\t\t// Look for any active animations, and finish them\n\t\t\tfor ( index = timers.length; index--; ) {\n\t\t\t\tif ( timers[ index ].elem === this && timers[ index ].queue === type ) {\n\t\t\t\t\ttimers[ index ].anim.stop( true );\n\t\t\t\t\ttimers.splice( index, 1 );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Look for any animations in the old queue and finish them\n\t\t\tfor ( index = 0; index < length; index++ ) {\n\t\t\t\tif ( queue[ index ] && queue[ index ].finish ) {\n\t\t\t\t\tqueue[ index ].finish.call( this );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Turn off finishing flag\n\t\t\tdelete data.finish;\n\t\t} );\n\t}\n} );\n\njQuery.each( [ \"toggle\", \"show\", \"hide\" ], function( _i, name ) {\n\tvar cssFn = jQuery.fn[ name ];\n\tjQuery.fn[ name ] = function( speed, easing, callback ) {\n\t\treturn speed == null || typeof speed === \"boolean\" ?\n\t\t\tcssFn.apply( this, arguments ) :\n\t\t\tthis.animate( genFx( name, true ), speed, easing, callback );\n\t};\n} );\n\n// Generate shortcuts for custom animations\njQuery.each( {\n\tslideDown: genFx( \"show\" ),\n\tslideUp: genFx( \"hide\" ),\n\tslideToggle: genFx( \"toggle\" ),\n\tfadeIn: { opacity: \"show\" },\n\tfadeOut: { opacity: \"hide\" },\n\tfadeToggle: { opacity: \"toggle\" }\n}, function( name, props ) {\n\tjQuery.fn[ name ] = function( speed, easing, callback ) {\n\t\treturn this.animate( props, speed, easing, callback );\n\t};\n} );\n\njQuery.timers = [];\njQuery.fx.tick = function() {\n\tvar timer,\n\t\ti = 0,\n\t\ttimers = jQuery.timers;\n\n\tfxNow = Date.now();\n\n\tfor ( ; i < timers.length; i++ ) {\n\t\ttimer = timers[ i ];\n\n\t\t// Run the timer and safely remove it when done (allowing for external removal)\n\t\tif ( !timer() && timers[ i ] === timer ) {\n\t\t\ttimers.splice( i--, 1 );\n\t\t}\n\t}\n\n\tif ( !timers.length ) {\n\t\tjQuery.fx.stop();\n\t}\n\tfxNow = undefined;\n};\n\njQuery.fx.timer = function( timer ) {\n\tjQuery.timers.push( timer );\n\tjQuery.fx.start();\n};\n\njQuery.fx.start = function() {\n\tif ( inProgress ) {\n\t\treturn;\n\t}\n\n\tinProgress = true;\n\tschedule();\n};\n\njQuery.fx.stop = function() {\n\tinProgress = null;\n};\n\njQuery.fx.speeds = {\n\tslow: 600,\n\tfast: 200,\n\n\t// Default speed\n\t_default: 400\n};\n\n// Based off of the plugin by Clint Helfers, with permission.\njQuery.fn.delay = function( time, type ) {\n\ttime = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time;\n\ttype = type || \"fx\";\n\n\treturn this.queue( type, function( next, hooks ) {\n\t\tvar timeout = window.setTimeout( next, time );\n\t\thooks.stop = function() {\n\t\t\twindow.clearTimeout( timeout );\n\t\t};\n\t} );\n};\n\nvar rfocusable = /^(?:input|select|textarea|button)$/i,\n\trclickable = /^(?:a|area)$/i;\n\njQuery.fn.extend( {\n\tprop: function( name, value ) {\n\t\treturn access( this, jQuery.prop, name, value, arguments.length > 1 );\n\t},\n\n\tremoveProp: function( name ) {\n\t\treturn this.each( function() {\n\t\t\tdelete this[ jQuery.propFix[ name ] || name ];\n\t\t} );\n\t}\n} );\n\njQuery.extend( {\n\tprop: function( elem, name, value ) {\n\t\tvar ret, hooks,\n\t\t\tnType = elem.nodeType;\n\n\t\t// Don't get/set properties on text, comment and attribute nodes\n\t\tif ( nType === 3 || nType === 8 || nType === 2 ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) {\n\n\t\t\t// Fix name and attach hooks\n\t\t\tname = jQuery.propFix[ name ] || name;\n\t\t\thooks = jQuery.propHooks[ name ];\n\t\t}\n\n\t\tif ( value !== undefined ) {\n\t\t\tif ( hooks && \"set\" in hooks &&\n\t\t\t\t( ret = hooks.set( elem, value, name ) ) !== undefined ) {\n\t\t\t\treturn ret;\n\t\t\t}\n\n\t\t\treturn ( elem[ name ] = value );\n\t\t}\n\n\t\tif ( hooks && \"get\" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) {\n\t\t\treturn ret;\n\t\t}\n\n\t\treturn elem[ name ];\n\t},\n\n\tpropHooks: {\n\t\ttabIndex: {\n\t\t\tget: function( elem ) {\n\n\t\t\t\t// Support: IE <=9 - 11+\n\t\t\t\t// elem.tabIndex doesn't always return the\n\t\t\t\t// correct value when it hasn't been explicitly set\n\t\t\t\t// Use proper attribute retrieval (trac-12072)\n\t\t\t\tvar tabindex = elem.getAttribute( \"tabindex\" );\n\n\t\t\t\tif ( tabindex ) {\n\t\t\t\t\treturn parseInt( tabindex, 10 );\n\t\t\t\t}\n\n\t\t\t\tif (\n\t\t\t\t\trfocusable.test( elem.nodeName ) ||\n\n\t\t\t\t\t// href-less anchor's `tabIndex` property value is `0` and\n\t\t\t\t\t// the `tabindex` attribute value: `null`. We want `-1`.\n\t\t\t\t\trclickable.test( elem.nodeName ) && elem.href\n\t\t\t\t) {\n\t\t\t\t\treturn 0;\n\t\t\t\t}\n\n\t\t\t\treturn -1;\n\t\t\t}\n\t\t}\n\t},\n\n\tpropFix: {\n\t\t\"for\": \"htmlFor\",\n\t\t\"class\": \"className\"\n\t}\n} );\n\n// Support: IE <=11+\n// Accessing the selectedIndex property forces the browser to respect\n// setting selected on the option. The getter ensures a default option\n// is selected when in an optgroup. ESLint rule \"no-unused-expressions\"\n// is disabled for this code since it considers such accessions noop.\nif ( isIE ) {\n\tjQuery.propHooks.selected = {\n\t\tget: function( elem ) {\n\n\t\t\tvar parent = elem.parentNode;\n\t\t\tif ( parent && parent.parentNode ) {\n\t\t\t\t// eslint-disable-next-line no-unused-expressions\n\t\t\t\tparent.parentNode.selectedIndex;\n\t\t\t}\n\t\t\treturn null;\n\t\t},\n\t\tset: function( elem ) {\n\n\n\t\t\tvar parent = elem.parentNode;\n\t\t\tif ( parent ) {\n\t\t\t\t// eslint-disable-next-line no-unused-expressions\n\t\t\t\tparent.selectedIndex;\n\n\t\t\t\tif ( parent.parentNode ) {\n\t\t\t\t\t// eslint-disable-next-line no-unused-expressions\n\t\t\t\t\tparent.parentNode.selectedIndex;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t};\n}\n\njQuery.each( [\n\t\"tabIndex\",\n\t\"readOnly\",\n\t\"maxLength\",\n\t\"cellSpacing\",\n\t\"cellPadding\",\n\t\"rowSpan\",\n\t\"colSpan\",\n\t\"useMap\",\n\t\"frameBorder\",\n\t\"contentEditable\"\n], function() {\n\tjQuery.propFix[ this.toLowerCase() ] = this;\n} );\n\n// Strip and collapse whitespace according to HTML spec\n// https://infra.spec.whatwg.org/#strip-and-collapse-ascii-whitespace\nfunction stripAndCollapse( value ) {\n\tvar tokens = value.match( rnothtmlwhite ) || [];\n\treturn tokens.join( \" \" );\n}\n\nfunction getClass( elem ) {\n\treturn elem.getAttribute && elem.getAttribute( \"class\" ) || \"\";\n}\n\nfunction classesToArray( value ) {\n\tif ( Array.isArray( value ) ) {\n\t\treturn value;\n\t}\n\tif ( typeof value === \"string\" ) {\n\t\treturn value.match( rnothtmlwhite ) || [];\n\t}\n\treturn [];\n}\n\njQuery.fn.extend( {\n\taddClass: function( value ) {\n\t\tvar classNames, cur, curValue, className, i, finalValue;\n\n\t\tif ( typeof value === \"function\" ) {\n\t\t\treturn this.each( function( j ) {\n\t\t\t\tjQuery( this ).addClass( value.call( this, j, getClass( this ) ) );\n\t\t\t} );\n\t\t}\n\n\t\tclassNames = classesToArray( value );\n\n\t\tif ( classNames.length ) {\n\t\t\treturn this.each( function() {\n\t\t\t\tcurValue = getClass( this );\n\t\t\t\tcur = this.nodeType === 1 && ( \" \" + stripAndCollapse( curValue ) + \" \" );\n\n\t\t\t\tif ( cur ) {\n\t\t\t\t\tfor ( i = 0; i < classNames.length; i++ ) {\n\t\t\t\t\t\tclassName = classNames[ i ];\n\t\t\t\t\t\tif ( cur.indexOf( \" \" + className + \" \" ) < 0 ) {\n\t\t\t\t\t\t\tcur += className + \" \";\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// Only assign if different to avoid unneeded rendering.\n\t\t\t\t\tfinalValue = stripAndCollapse( cur );\n\t\t\t\t\tif ( curValue !== finalValue ) {\n\t\t\t\t\t\tthis.setAttribute( \"class\", finalValue );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} );\n\t\t}\n\n\t\treturn this;\n\t},\n\n\tremoveClass: function( value ) {\n\t\tvar classNames, cur, curValue, className, i, finalValue;\n\n\t\tif ( typeof value === \"function\" ) {\n\t\t\treturn this.each( function( j ) {\n\t\t\t\tjQuery( this ).removeClass( value.call( this, j, getClass( this ) ) );\n\t\t\t} );\n\t\t}\n\n\t\tif ( !arguments.length ) {\n\t\t\treturn this.attr( \"class\", \"\" );\n\t\t}\n\n\t\tclassNames = classesToArray( value );\n\n\t\tif ( classNames.length ) {\n\t\t\treturn this.each( function() {\n\t\t\t\tcurValue = getClass( this );\n\n\t\t\t\t// This expression is here for better compressibility (see addClass)\n\t\t\t\tcur = this.nodeType === 1 && ( \" \" + stripAndCollapse( curValue ) + \" \" );\n\n\t\t\t\tif ( cur ) {\n\t\t\t\t\tfor ( i = 0; i < classNames.length; i++ ) {\n\t\t\t\t\t\tclassName = classNames[ i ];\n\n\t\t\t\t\t\t// Remove *all* instances\n\t\t\t\t\t\twhile ( cur.indexOf( \" \" + className + \" \" ) > -1 ) {\n\t\t\t\t\t\t\tcur = cur.replace( \" \" + className + \" \", \" \" );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// Only assign if different to avoid unneeded rendering.\n\t\t\t\t\tfinalValue = stripAndCollapse( cur );\n\t\t\t\t\tif ( curValue !== finalValue ) {\n\t\t\t\t\t\tthis.setAttribute( \"class\", finalValue );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} );\n\t\t}\n\n\t\treturn this;\n\t},\n\n\ttoggleClass: function( value, stateVal ) {\n\t\tvar classNames, className, i, self;\n\n\t\tif ( typeof value === \"function\" ) {\n\t\t\treturn this.each( function( i ) {\n\t\t\t\tjQuery( this ).toggleClass(\n\t\t\t\t\tvalue.call( this, i, getClass( this ), stateVal ),\n\t\t\t\t\tstateVal\n\t\t\t\t);\n\t\t\t} );\n\t\t}\n\n\t\tif ( typeof stateVal === \"boolean\" ) {\n\t\t\treturn stateVal ? this.addClass( value ) : this.removeClass( value );\n\t\t}\n\n\t\tclassNames = classesToArray( value );\n\n\t\tif ( classNames.length ) {\n\t\t\treturn this.each( function() {\n\n\t\t\t\t// Toggle individual class names\n\t\t\t\tself = jQuery( this );\n\n\t\t\t\tfor ( i = 0; i < classNames.length; i++ ) {\n\t\t\t\t\tclassName = classNames[ i ];\n\n\t\t\t\t\t// Check each className given, space separated list\n\t\t\t\t\tif ( self.hasClass( className ) ) {\n\t\t\t\t\t\tself.removeClass( className );\n\t\t\t\t\t} else {\n\t\t\t\t\t\tself.addClass( className );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} );\n\t\t}\n\n\t\treturn this;\n\t},\n\n\thasClass: function( selector ) {\n\t\tvar className, elem,\n\t\t\ti = 0;\n\n\t\tclassName = \" \" + selector + \" \";\n\t\twhile ( ( elem = this[ i++ ] ) ) {\n\t\t\tif ( elem.nodeType === 1 &&\n\t\t\t\t( \" \" + stripAndCollapse( getClass( elem ) ) + \" \" ).indexOf( className ) > -1 ) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\n\t\treturn false;\n\t}\n} );\n\njQuery.fn.extend( {\n\tval: function( value ) {\n\t\tvar hooks, ret, valueIsFunction,\n\t\t\telem = this[ 0 ];\n\n\t\tif ( !arguments.length ) {\n\t\t\tif ( elem ) {\n\t\t\t\thooks = jQuery.valHooks[ elem.type ] ||\n\t\t\t\t\tjQuery.valHooks[ elem.nodeName.toLowerCase() ];\n\n\t\t\t\tif ( hooks &&\n\t\t\t\t\t\"get\" in hooks &&\n\t\t\t\t\t( ret = hooks.get( elem, \"value\" ) ) !== undefined\n\t\t\t\t) {\n\t\t\t\t\treturn ret;\n\t\t\t\t}\n\n\t\t\t\tret = elem.value;\n\n\t\t\t\t// Handle cases where value is null/undef or number\n\t\t\t\treturn ret == null ? \"\" : ret;\n\t\t\t}\n\n\t\t\treturn;\n\t\t}\n\n\t\tvalueIsFunction = typeof value === \"function\";\n\n\t\treturn this.each( function( i ) {\n\t\t\tvar val;\n\n\t\t\tif ( this.nodeType !== 1 ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif ( valueIsFunction ) {\n\t\t\t\tval = value.call( this, i, jQuery( this ).val() );\n\t\t\t} else {\n\t\t\t\tval = value;\n\t\t\t}\n\n\t\t\t// Treat null/undefined as \"\"; convert numbers to string\n\t\t\tif ( val == null ) {\n\t\t\t\tval = \"\";\n\n\t\t\t} else if ( typeof val === \"number\" ) {\n\t\t\t\tval += \"\";\n\n\t\t\t} else if ( Array.isArray( val ) ) {\n\t\t\t\tval = jQuery.map( val, function( value ) {\n\t\t\t\t\treturn value == null ? \"\" : value + \"\";\n\t\t\t\t} );\n\t\t\t}\n\n\t\t\thooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ];\n\n\t\t\t// If set returns undefined, fall back to normal setting\n\t\t\tif ( !hooks || !( \"set\" in hooks ) || hooks.set( this, val, \"value\" ) === undefined ) {\n\t\t\t\tthis.value = val;\n\t\t\t}\n\t\t} );\n\t}\n} );\n\njQuery.extend( {\n\tvalHooks: {\n\t\tselect: {\n\t\t\tget: function( elem ) {\n\t\t\t\tvar value, option, i,\n\t\t\t\t\toptions = elem.options,\n\t\t\t\t\tindex = elem.selectedIndex,\n\t\t\t\t\tone = elem.type === \"select-one\",\n\t\t\t\t\tvalues = one ? null : [],\n\t\t\t\t\tmax = one ? index + 1 : options.length;\n\n\t\t\t\tif ( index < 0 ) {\n\t\t\t\t\ti = max;\n\n\t\t\t\t} else {\n\t\t\t\t\ti = one ? index : 0;\n\t\t\t\t}\n\n\t\t\t\t// Loop through all the selected options\n\t\t\t\tfor ( ; i < max; i++ ) {\n\t\t\t\t\toption = options[ i ];\n\n\t\t\t\t\tif ( option.selected &&\n\n\t\t\t\t\t\t\t// Don't return options that are disabled or in a disabled optgroup\n\t\t\t\t\t\t\t!option.disabled &&\n\t\t\t\t\t\t\t( !option.parentNode.disabled ||\n\t\t\t\t\t\t\t\t!nodeName( option.parentNode, \"optgroup\" ) ) ) {\n\n\t\t\t\t\t\t// Get the specific value for the option\n\t\t\t\t\t\tvalue = jQuery( option ).val();\n\n\t\t\t\t\t\t// We don't need an array for one selects\n\t\t\t\t\t\tif ( one ) {\n\t\t\t\t\t\t\treturn value;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Multi-Selects return an array\n\t\t\t\t\t\tvalues.push( value );\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn values;\n\t\t\t},\n\n\t\t\tset: function( elem, value ) {\n\t\t\t\tvar optionSet, option,\n\t\t\t\t\toptions = elem.options,\n\t\t\t\t\tvalues = jQuery.makeArray( value ),\n\t\t\t\t\ti = options.length;\n\n\t\t\t\twhile ( i-- ) {\n\t\t\t\t\toption = options[ i ];\n\n\t\t\t\t\tif ( ( option.selected =\n\t\t\t\t\t\tjQuery.inArray( jQuery( option ).val(), values ) > -1\n\t\t\t\t\t) ) {\n\t\t\t\t\t\toptionSet = true;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Force browsers to behave consistently when non-matching value is set\n\t\t\t\tif ( !optionSet ) {\n\t\t\t\t\telem.selectedIndex = -1;\n\t\t\t\t}\n\t\t\t\treturn values;\n\t\t\t}\n\t\t}\n\t}\n} );\n\nif ( isIE ) {\n\tjQuery.valHooks.option = {\n\t\tget: function( elem ) {\n\n\t\t\tvar val = elem.getAttribute( \"value\" );\n\t\t\treturn val != null ?\n\t\t\t\tval :\n\n\t\t\t\t// Support: IE <=10 - 11+\n\t\t\t\t// option.text throws exceptions (trac-14686, trac-14858)\n\t\t\t\t// Strip and collapse whitespace\n\t\t\t\t// https://html.spec.whatwg.org/#strip-and-collapse-whitespace\n\t\t\t\tstripAndCollapse( jQuery.text( elem ) );\n\t\t}\n\t};\n}\n\n// Radios and checkboxes getter/setter\njQuery.each( [ \"radio\", \"checkbox\" ], function() {\n\tjQuery.valHooks[ this ] = {\n\t\tset: function( elem, value ) {\n\t\t\tif ( Array.isArray( value ) ) {\n\t\t\t\treturn ( elem.checked = jQuery.inArray( jQuery( elem ).val(), value ) > -1 );\n\t\t\t}\n\t\t}\n\t};\n} );\n\nvar rfocusMorph = /^(?:focusinfocus|focusoutblur)$/,\n\tstopPropagationCallback = function( e ) {\n\t\te.stopPropagation();\n\t};\n\njQuery.extend( jQuery.event, {\n\n\ttrigger: function( event, data, elem, onlyHandlers ) {\n\n\t\tvar i, cur, tmp, bubbleType, ontype, handle, special, lastElement,\n\t\t\teventPath = [ elem || document$1 ],\n\t\t\ttype = hasOwn.call( event, \"type\" ) ? event.type : event,\n\t\t\tnamespaces = hasOwn.call( event, \"namespace\" ) ? event.namespace.split( \".\" ) : [];\n\n\t\tcur = lastElement = tmp = elem = elem || document$1;\n\n\t\t// Don't do events on text and comment nodes\n\t\tif ( elem.nodeType === 3 || elem.nodeType === 8 ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// focus/blur morphs to focusin/out; ensure we're not firing them right now\n\t\tif ( rfocusMorph.test( type + jQuery.event.triggered ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( type.indexOf( \".\" ) > -1 ) {\n\n\t\t\t// Namespaced trigger; create a regexp to match event type in handle()\n\t\t\tnamespaces = type.split( \".\" );\n\t\t\ttype = namespaces.shift();\n\t\t\tnamespaces.sort();\n\t\t}\n\t\tontype = type.indexOf( \":\" ) < 0 && \"on\" + type;\n\n\t\t// Caller can pass in a jQuery.Event object, Object, or just an event type string\n\t\tevent = event[ jQuery.expando ] ?\n\t\t\tevent :\n\t\t\tnew jQuery.Event( type, typeof event === \"object\" && event );\n\n\t\t// Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true)\n\t\tevent.isTrigger = onlyHandlers ? 2 : 3;\n\t\tevent.namespace = namespaces.join( \".\" );\n\t\tevent.rnamespace = event.namespace ?\n\t\t\tnew RegExp( \"(^|\\\\.)\" + namespaces.join( \"\\\\.(?:.*\\\\.|)\" ) + \"(\\\\.|$)\" ) :\n\t\t\tnull;\n\n\t\t// Clean up the event in case it is being reused\n\t\tevent.result = undefined;\n\t\tif ( !event.target ) {\n\t\t\tevent.target = elem;\n\t\t}\n\n\t\t// Clone any incoming data and prepend the event, creating the handler arg list\n\t\tdata = data == null ?\n\t\t\t[ event ] :\n\t\t\tjQuery.makeArray( data, [ event ] );\n\n\t\t// Allow special events to draw outside the lines\n\t\tspecial = jQuery.event.special[ type ] || {};\n\t\tif ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Determine event propagation path in advance, per W3C events spec (trac-9951)\n\t\t// Bubble up to document, then to window; watch for a global ownerDocument var (trac-9724)\n\t\tif ( !onlyHandlers && !special.noBubble && !isWindow( elem ) ) {\n\n\t\t\tbubbleType = special.delegateType || type;\n\t\t\tif ( !rfocusMorph.test( bubbleType + type ) ) {\n\t\t\t\tcur = cur.parentNode;\n\t\t\t}\n\t\t\tfor ( ; cur; cur = cur.parentNode ) {\n\t\t\t\teventPath.push( cur );\n\t\t\t\ttmp = cur;\n\t\t\t}\n\n\t\t\t// Only add window if we got to document (e.g., not plain obj or detached DOM)\n\t\t\tif ( tmp === ( elem.ownerDocument || document$1 ) ) {\n\t\t\t\teventPath.push( tmp.defaultView || tmp.parentWindow || window );\n\t\t\t}\n\t\t}\n\n\t\t// Fire handlers on the event path\n\t\ti = 0;\n\t\twhile ( ( cur = eventPath[ i++ ] ) && !event.isPropagationStopped() ) {\n\t\t\tlastElement = cur;\n\t\t\tevent.type = i > 1 ?\n\t\t\t\tbubbleType :\n\t\t\t\tspecial.bindType || type;\n\n\t\t\t// jQuery handler\n\t\t\thandle = ( dataPriv.get( cur, \"events\" ) || Object.create( null ) )[ event.type ] &&\n\t\t\t\tdataPriv.get( cur, \"handle\" );\n\t\t\tif ( handle ) {\n\t\t\t\thandle.apply( cur, data );\n\t\t\t}\n\n\t\t\t// Native handler\n\t\t\thandle = ontype && cur[ ontype ];\n\t\t\tif ( handle && handle.apply && acceptData( cur ) ) {\n\t\t\t\tevent.result = handle.apply( cur, data );\n\t\t\t\tif ( event.result === false ) {\n\t\t\t\t\tevent.preventDefault();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tevent.type = type;\n\n\t\t// If nobody prevented the default action, do it now\n\t\tif ( !onlyHandlers && !event.isDefaultPrevented() ) {\n\n\t\t\tif ( ( !special._default ||\n\t\t\t\tspecial._default.apply( eventPath.pop(), data ) === false ) &&\n\t\t\t\tacceptData( elem ) ) {\n\n\t\t\t\t// Call a native DOM method on the target with the same name as the event.\n\t\t\t\t// Don't do default actions on window, that's where global variables be (trac-6170)\n\t\t\t\tif ( ontype && typeof elem[ type ] === \"function\" && !isWindow( elem ) ) {\n\n\t\t\t\t\t// Don't re-trigger an onFOO event when we call its FOO() method\n\t\t\t\t\ttmp = elem[ ontype ];\n\n\t\t\t\t\tif ( tmp ) {\n\t\t\t\t\t\telem[ ontype ] = null;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Prevent re-triggering of the same event, since we already bubbled it above\n\t\t\t\t\tjQuery.event.triggered = type;\n\n\t\t\t\t\tif ( event.isPropagationStopped() ) {\n\t\t\t\t\t\tlastElement.addEventListener( type, stopPropagationCallback );\n\t\t\t\t\t}\n\n\t\t\t\t\telem[ type ]();\n\n\t\t\t\t\tif ( event.isPropagationStopped() ) {\n\t\t\t\t\t\tlastElement.removeEventListener( type, stopPropagationCallback );\n\t\t\t\t\t}\n\n\t\t\t\t\tjQuery.event.triggered = undefined;\n\n\t\t\t\t\tif ( tmp ) {\n\t\t\t\t\t\telem[ ontype ] = tmp;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn event.result;\n\t},\n\n\t// Piggyback on a donor event to simulate a different one\n\t// Used only for `focus(in | out)` events\n\tsimulate: function( type, elem, event ) {\n\t\tvar e = jQuery.extend(\n\t\t\tnew jQuery.Event(),\n\t\t\tevent,\n\t\t\t{\n\t\t\t\ttype: type,\n\t\t\t\tisSimulated: true\n\t\t\t}\n\t\t);\n\n\t\tjQuery.event.trigger( e, null, elem );\n\t}\n\n} );\n\njQuery.fn.extend( {\n\n\ttrigger: function( type, data ) {\n\t\treturn this.each( function() {\n\t\t\tjQuery.event.trigger( type, data, this );\n\t\t} );\n\t},\n\ttriggerHandler: function( type, data ) {\n\t\tvar elem = this[ 0 ];\n\t\tif ( elem ) {\n\t\t\treturn jQuery.event.trigger( type, data, elem, true );\n\t\t}\n\t}\n} );\n\nvar location = window.location;\n\nvar nonce = { guid: Date.now() };\n\nvar rquery = /\\?/;\n\n// Cross-browser xml parsing\njQuery.parseXML = function( data ) {\n\tvar xml, parserErrorElem;\n\tif ( !data || typeof data !== \"string\" ) {\n\t\treturn null;\n\t}\n\n\t// Support: IE 9 - 11+\n\t// IE throws on parseFromString with invalid input.\n\ttry {\n\t\txml = ( new window.DOMParser() ).parseFromString( data, \"text/xml\" );\n\t} catch ( e ) {}\n\n\tparserErrorElem = xml && xml.getElementsByTagName( \"parsererror\" )[ 0 ];\n\tif ( !xml || parserErrorElem ) {\n\t\tjQuery.error( \"Invalid XML: \" + (\n\t\t\tparserErrorElem ?\n\t\t\t\tjQuery.map( parserErrorElem.childNodes, function( el ) {\n\t\t\t\t\treturn el.textContent;\n\t\t\t\t} ).join( \"\\n\" ) :\n\t\t\t\tdata\n\t\t) );\n\t}\n\treturn xml;\n};\n\nvar\n\trbracket = /\\[\\]$/,\n\trCRLF = /\\r?\\n/g,\n\trsubmitterTypes = /^(?:submit|button|image|reset|file)$/i,\n\trsubmittable = /^(?:input|select|textarea|keygen)/i;\n\nfunction buildParams( prefix, obj, traditional, add ) {\n\tvar name;\n\n\tif ( Array.isArray( obj ) ) {\n\n\t\t// Serialize array item.\n\t\tjQuery.each( obj, function( i, v ) {\n\t\t\tif ( traditional || rbracket.test( prefix ) ) {\n\n\t\t\t\t// Treat each array item as a scalar.\n\t\t\t\tadd( prefix, v );\n\n\t\t\t} else {\n\n\t\t\t\t// Item is non-scalar (array or object), encode its numeric index.\n\t\t\t\tbuildParams(\n\t\t\t\t\tprefix + \"[\" + ( typeof v === \"object\" && v != null ? i : \"\" ) + \"]\",\n\t\t\t\t\tv,\n\t\t\t\t\ttraditional,\n\t\t\t\t\tadd\n\t\t\t\t);\n\t\t\t}\n\t\t} );\n\n\t} else if ( !traditional && toType( obj ) === \"object\" ) {\n\n\t\t// Serialize object item.\n\t\tfor ( name in obj ) {\n\t\t\tbuildParams( prefix + \"[\" + name + \"]\", obj[ name ], traditional, add );\n\t\t}\n\n\t} else {\n\n\t\t// Serialize scalar item.\n\t\tadd( prefix, obj );\n\t}\n}\n\n// Serialize an array of form elements or a set of\n// key/values into a query string\njQuery.param = function( a, traditional ) {\n\tvar prefix,\n\t\ts = [],\n\t\tadd = function( key, valueOrFunction ) {\n\n\t\t\t// If value is a function, invoke it and use its return value\n\t\t\tvar value = typeof valueOrFunction === \"function\" ?\n\t\t\t\tvalueOrFunction() :\n\t\t\t\tvalueOrFunction;\n\n\t\t\ts[ s.length ] = encodeURIComponent( key ) + \"=\" +\n\t\t\t\tencodeURIComponent( value == null ? \"\" : value );\n\t\t};\n\n\tif ( a == null ) {\n\t\treturn \"\";\n\t}\n\n\t// If an array was passed in, assume that it is an array of form elements.\n\tif ( Array.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) {\n\n\t\t// Serialize the form elements\n\t\tjQuery.each( a, function() {\n\t\t\tadd( this.name, this.value );\n\t\t} );\n\n\t} else {\n\n\t\t// If traditional, encode the \"old\" way (the way 1.3.2 or older\n\t\t// did it), otherwise encode params recursively.\n\t\tfor ( prefix in a ) {\n\t\t\tbuildParams( prefix, a[ prefix ], traditional, add );\n\t\t}\n\t}\n\n\t// Return the resulting serialization\n\treturn s.join( \"&\" );\n};\n\njQuery.fn.extend( {\n\tserialize: function() {\n\t\treturn jQuery.param( this.serializeArray() );\n\t},\n\tserializeArray: function() {\n\t\treturn this.map( function() {\n\n\t\t\t// Can add propHook for \"elements\" to filter or add form elements\n\t\t\tvar elements = jQuery.prop( this, \"elements\" );\n\t\t\treturn elements ? jQuery.makeArray( elements ) : this;\n\t\t} ).filter( function() {\n\t\t\tvar type = this.type;\n\n\t\t\t// Use .is( \":disabled\" ) so that fieldset[disabled] works\n\t\t\treturn this.name && !jQuery( this ).is( \":disabled\" ) &&\n\t\t\t\trsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) &&\n\t\t\t\t( this.checked || !rcheckableType.test( type ) );\n\t\t} ).map( function( _i, elem ) {\n\t\t\tvar val = jQuery( this ).val();\n\n\t\t\tif ( val == null ) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tif ( Array.isArray( val ) ) {\n\t\t\t\treturn jQuery.map( val, function( val ) {\n\t\t\t\t\treturn { name: elem.name, value: val.replace( rCRLF, \"\\r\\n\" ) };\n\t\t\t\t} );\n\t\t\t}\n\n\t\t\treturn { name: elem.name, value: val.replace( rCRLF, \"\\r\\n\" ) };\n\t\t} ).get();\n\t}\n} );\n\nvar\n\tr20 = /%20/g,\n\trhash = /#.*$/,\n\trantiCache = /([?&])_=[^&]*/,\n\trheaders = /^(.*?):[ \\t]*([^\\r\\n]*)$/mg,\n\n\t// trac-7653, trac-8125, trac-8152: local protocol detection\n\trlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/,\n\trnoContent = /^(?:GET|HEAD)$/,\n\trprotocol = /^\\/\\//,\n\n\t/* Prefilters\n\t * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example)\n\t * 2) These are called:\n\t * - BEFORE asking for a transport\n\t * - AFTER param serialization (s.data is a string if s.processData is true)\n\t * 3) key is the dataType\n\t * 4) the catchall symbol \"*\" can be used\n\t * 5) execution will start with transport dataType and THEN continue down to \"*\" if needed\n\t */\n\tprefilters = {},\n\n\t/* Transports bindings\n\t * 1) key is the dataType\n\t * 2) the catchall symbol \"*\" can be used\n\t * 3) selection will start with transport dataType and THEN go to \"*\" if needed\n\t */\n\ttransports = {},\n\n\t// Avoid comment-prolog char sequence (trac-10098); must appease lint and evade compression\n\tallTypes = \"*/\".concat( \"*\" ),\n\n\t// Anchor tag for parsing the document origin\n\toriginAnchor = document$1.createElement( \"a\" );\n\noriginAnchor.href = location.href;\n\n// Base \"constructor\" for jQuery.ajaxPrefilter and jQuery.ajaxTransport\nfunction addToPrefiltersOrTransports( structure ) {\n\n\t// dataTypeExpression is optional and defaults to \"*\"\n\treturn function( dataTypeExpression, func ) {\n\n\t\tif ( typeof dataTypeExpression !== \"string\" ) {\n\t\t\tfunc = dataTypeExpression;\n\t\t\tdataTypeExpression = \"*\";\n\t\t}\n\n\t\tvar dataType,\n\t\t\ti = 0,\n\t\t\tdataTypes = dataTypeExpression.toLowerCase().match( rnothtmlwhite ) || [];\n\n\t\tif ( typeof func === \"function\" ) {\n\n\t\t\t// For each dataType in the dataTypeExpression\n\t\t\twhile ( ( dataType = dataTypes[ i++ ] ) ) {\n\n\t\t\t\t// Prepend if requested\n\t\t\t\tif ( dataType[ 0 ] === \"+\" ) {\n\t\t\t\t\tdataType = dataType.slice( 1 ) || \"*\";\n\t\t\t\t\t( structure[ dataType ] = structure[ dataType ] || [] ).unshift( func );\n\n\t\t\t\t// Otherwise append\n\t\t\t\t} else {\n\t\t\t\t\t( structure[ dataType ] = structure[ dataType ] || [] ).push( func );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t};\n}\n\n// Base inspection function for prefilters and transports\nfunction inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) {\n\n\tvar inspected = {},\n\t\tseekingTransport = ( structure === transports );\n\n\tfunction inspect( dataType ) {\n\t\tvar selected;\n\t\tinspected[ dataType ] = true;\n\t\tjQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) {\n\t\t\tvar dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR );\n\t\t\tif ( typeof dataTypeOrTransport === \"string\" &&\n\t\t\t\t!seekingTransport && !inspected[ dataTypeOrTransport ] ) {\n\n\t\t\t\toptions.dataTypes.unshift( dataTypeOrTransport );\n\t\t\t\tinspect( dataTypeOrTransport );\n\t\t\t\treturn false;\n\t\t\t} else if ( seekingTransport ) {\n\t\t\t\treturn !( selected = dataTypeOrTransport );\n\t\t\t}\n\t\t} );\n\t\treturn selected;\n\t}\n\n\treturn inspect( options.dataTypes[ 0 ] ) || !inspected[ \"*\" ] && inspect( \"*\" );\n}\n\n// A special extend for ajax options\n// that takes \"flat\" options (not to be deep extended)\n// Fixes trac-9887\nfunction ajaxExtend( target, src ) {\n\tvar key, deep,\n\t\tflatOptions = jQuery.ajaxSettings.flatOptions || {};\n\n\tfor ( key in src ) {\n\t\tif ( src[ key ] !== undefined ) {\n\t\t\t( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ];\n\t\t}\n\t}\n\tif ( deep ) {\n\t\tjQuery.extend( true, target, deep );\n\t}\n\n\treturn target;\n}\n\n/* Handles responses to an ajax request:\n * - finds the right dataType (mediates between content-type and expected dataType)\n * - returns the corresponding response\n */\nfunction ajaxHandleResponses( s, jqXHR, responses ) {\n\n\tvar ct, type, finalDataType, firstDataType,\n\t\tcontents = s.contents,\n\t\tdataTypes = s.dataTypes;\n\n\t// Remove auto dataType and get content-type in the process\n\twhile ( dataTypes[ 0 ] === \"*\" ) {\n\t\tdataTypes.shift();\n\t\tif ( ct === undefined ) {\n\t\t\tct = s.mimeType || jqXHR.getResponseHeader( \"Content-Type\" );\n\t\t}\n\t}\n\n\t// Check if we're dealing with a known content-type\n\tif ( ct ) {\n\t\tfor ( type in contents ) {\n\t\t\tif ( contents[ type ] && contents[ type ].test( ct ) ) {\n\t\t\t\tdataTypes.unshift( type );\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\t// Check to see if we have a response for the expected dataType\n\tif ( dataTypes[ 0 ] in responses ) {\n\t\tfinalDataType = dataTypes[ 0 ];\n\t} else {\n\n\t\t// Try convertible dataTypes\n\t\tfor ( type in responses ) {\n\t\t\tif ( !dataTypes[ 0 ] || s.converters[ type + \" \" + dataTypes[ 0 ] ] ) {\n\t\t\t\tfinalDataType = type;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif ( !firstDataType ) {\n\t\t\t\tfirstDataType = type;\n\t\t\t}\n\t\t}\n\n\t\t// Or just use first one\n\t\tfinalDataType = finalDataType || firstDataType;\n\t}\n\n\t// If we found a dataType\n\t// We add the dataType to the list if needed\n\t// and return the corresponding response\n\tif ( finalDataType ) {\n\t\tif ( finalDataType !== dataTypes[ 0 ] ) {\n\t\t\tdataTypes.unshift( finalDataType );\n\t\t}\n\t\treturn responses[ finalDataType ];\n\t}\n}\n\n/* Chain conversions given the request and the original response\n * Also sets the responseXXX fields on the jqXHR instance\n */\nfunction ajaxConvert( s, response, jqXHR, isSuccess ) {\n\tvar conv2, current, conv, tmp, prev,\n\t\tconverters = {},\n\n\t\t// Work with a copy of dataTypes in case we need to modify it for conversion\n\t\tdataTypes = s.dataTypes.slice();\n\n\t// Create converters map with lowercased keys\n\tif ( dataTypes[ 1 ] ) {\n\t\tfor ( conv in s.converters ) {\n\t\t\tconverters[ conv.toLowerCase() ] = s.converters[ conv ];\n\t\t}\n\t}\n\n\tcurrent = dataTypes.shift();\n\n\t// Convert to each sequential dataType\n\twhile ( current ) {\n\n\t\tif ( s.responseFields[ current ] ) {\n\t\t\tjqXHR[ s.responseFields[ current ] ] = response;\n\t\t}\n\n\t\t// Apply the dataFilter if provided\n\t\tif ( !prev && isSuccess && s.dataFilter ) {\n\t\t\tresponse = s.dataFilter( response, s.dataType );\n\t\t}\n\n\t\tprev = current;\n\t\tcurrent = dataTypes.shift();\n\n\t\tif ( current ) {\n\n\t\t\t// There's only work to do if current dataType is non-auto\n\t\t\tif ( current === \"*\" ) {\n\n\t\t\t\tcurrent = prev;\n\n\t\t\t// Convert response if prev dataType is non-auto and differs from current\n\t\t\t} else if ( prev !== \"*\" && prev !== current ) {\n\n\t\t\t\t// Seek a direct converter\n\t\t\t\tconv = converters[ prev + \" \" + current ] || converters[ \"* \" + current ];\n\n\t\t\t\t// If none found, seek a pair\n\t\t\t\tif ( !conv ) {\n\t\t\t\t\tfor ( conv2 in converters ) {\n\n\t\t\t\t\t\t// If conv2 outputs current\n\t\t\t\t\t\ttmp = conv2.split( \" \" );\n\t\t\t\t\t\tif ( tmp[ 1 ] === current ) {\n\n\t\t\t\t\t\t\t// If prev can be converted to accepted input\n\t\t\t\t\t\t\tconv = converters[ prev + \" \" + tmp[ 0 ] ] ||\n\t\t\t\t\t\t\t\tconverters[ \"* \" + tmp[ 0 ] ];\n\t\t\t\t\t\t\tif ( conv ) {\n\n\t\t\t\t\t\t\t\t// Condense equivalence converters\n\t\t\t\t\t\t\t\tif ( conv === true ) {\n\t\t\t\t\t\t\t\t\tconv = converters[ conv2 ];\n\n\t\t\t\t\t\t\t\t// Otherwise, insert the intermediate dataType\n\t\t\t\t\t\t\t\t} else if ( converters[ conv2 ] !== true ) {\n\t\t\t\t\t\t\t\t\tcurrent = tmp[ 0 ];\n\t\t\t\t\t\t\t\t\tdataTypes.unshift( tmp[ 1 ] );\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Apply converter (if not an equivalence)\n\t\t\t\tif ( conv !== true ) {\n\n\t\t\t\t\t// Unless errors are allowed to bubble, catch and return them\n\t\t\t\t\tif ( conv && s.throws ) {\n\t\t\t\t\t\tresponse = conv( response );\n\t\t\t\t\t} else {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tresponse = conv( response );\n\t\t\t\t\t\t} catch ( e ) {\n\t\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t\tstate: \"parsererror\",\n\t\t\t\t\t\t\t\terror: conv ? e : \"No conversion from \" + prev + \" to \" + current\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn { state: \"success\", data: response };\n}\n\njQuery.extend( {\n\n\t// Counter for holding the number of active queries\n\tactive: 0,\n\n\t// Last-Modified header cache for next request\n\tlastModified: {},\n\tetag: {},\n\n\tajaxSettings: {\n\t\turl: location.href,\n\t\ttype: \"GET\",\n\t\tisLocal: rlocalProtocol.test( location.protocol ),\n\t\tglobal: true,\n\t\tprocessData: true,\n\t\tasync: true,\n\t\tcontentType: \"application/x-www-form-urlencoded; charset=UTF-8\",\n\n\t\t/*\n\t\ttimeout: 0,\n\t\tdata: null,\n\t\tdataType: null,\n\t\tusername: null,\n\t\tpassword: null,\n\t\tcache: null,\n\t\tthrows: false,\n\t\ttraditional: false,\n\t\theaders: {},\n\t\t*/\n\n\t\taccepts: {\n\t\t\t\"*\": allTypes,\n\t\t\ttext: \"text/plain\",\n\t\t\thtml: \"text/html\",\n\t\t\txml: \"application/xml, text/xml\",\n\t\t\tjson: \"application/json, text/javascript\"\n\t\t},\n\n\t\tcontents: {\n\t\t\txml: /\\bxml\\b/,\n\t\t\thtml: /\\bhtml/,\n\t\t\tjson: /\\bjson\\b/\n\t\t},\n\n\t\tresponseFields: {\n\t\t\txml: \"responseXML\",\n\t\t\ttext: \"responseText\",\n\t\t\tjson: \"responseJSON\"\n\t\t},\n\n\t\t// Data converters\n\t\t// Keys separate source (or catchall \"*\") and destination types with a single space\n\t\tconverters: {\n\n\t\t\t// Convert anything to text\n\t\t\t\"* text\": String,\n\n\t\t\t// Text to html (true = no transformation)\n\t\t\t\"text html\": true,\n\n\t\t\t// Evaluate text as a json expression\n\t\t\t\"text json\": JSON.parse,\n\n\t\t\t// Parse text as xml\n\t\t\t\"text xml\": jQuery.parseXML\n\t\t},\n\n\t\t// For options that shouldn't be deep extended:\n\t\t// you can add your own custom options here if\n\t\t// and when you create one that shouldn't be\n\t\t// deep extended (see ajaxExtend)\n\t\tflatOptions: {\n\t\t\turl: true,\n\t\t\tcontext: true\n\t\t}\n\t},\n\n\t// Creates a full fledged settings object into target\n\t// with both ajaxSettings and settings fields.\n\t// If target is omitted, writes into ajaxSettings.\n\tajaxSetup: function( target, settings ) {\n\t\treturn settings ?\n\n\t\t\t// Building a settings object\n\t\t\tajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) :\n\n\t\t\t// Extending ajaxSettings\n\t\t\tajaxExtend( jQuery.ajaxSettings, target );\n\t},\n\n\tajaxPrefilter: addToPrefiltersOrTransports( prefilters ),\n\tajaxTransport: addToPrefiltersOrTransports( transports ),\n\n\t// Main method\n\tajax: function( url, options ) {\n\n\t\t// If url is an object, simulate pre-1.5 signature\n\t\tif ( typeof url === \"object\" ) {\n\t\t\toptions = url;\n\t\t\turl = undefined;\n\t\t}\n\n\t\t// Force options to be an object\n\t\toptions = options || {};\n\n\t\tvar transport,\n\n\t\t\t// URL without anti-cache param\n\t\t\tcacheURL,\n\n\t\t\t// Response headers\n\t\t\tresponseHeadersString,\n\t\t\tresponseHeaders,\n\n\t\t\t// timeout handle\n\t\t\ttimeoutTimer,\n\n\t\t\t// Url cleanup var\n\t\t\turlAnchor,\n\n\t\t\t// Request state (becomes false upon send and true upon completion)\n\t\t\tcompleted,\n\n\t\t\t// To know if global events are to be dispatched\n\t\t\tfireGlobals,\n\n\t\t\t// Loop variable\n\t\t\ti,\n\n\t\t\t// uncached part of the url\n\t\t\tuncached,\n\n\t\t\t// Create the final options object\n\t\t\ts = jQuery.ajaxSetup( {}, options ),\n\n\t\t\t// Callbacks context\n\t\t\tcallbackContext = s.context || s,\n\n\t\t\t// Context for global events is callbackContext if it is a DOM node or jQuery collection\n\t\t\tglobalEventContext = s.context &&\n\t\t\t\t( callbackContext.nodeType || callbackContext.jquery ) ?\n\t\t\t\tjQuery( callbackContext ) :\n\t\t\t\tjQuery.event,\n\n\t\t\t// Deferreds\n\t\t\tdeferred = jQuery.Deferred(),\n\t\t\tcompleteDeferred = jQuery.Callbacks( \"once memory\" ),\n\n\t\t\t// Status-dependent callbacks\n\t\t\tstatusCode = s.statusCode || {},\n\n\t\t\t// Headers (they are sent all at once)\n\t\t\trequestHeaders = {},\n\t\t\trequestHeadersNames = {},\n\n\t\t\t// Default abort message\n\t\t\tstrAbort = \"canceled\",\n\n\t\t\t// Fake xhr\n\t\t\tjqXHR = {\n\t\t\t\treadyState: 0,\n\n\t\t\t\t// Builds headers hashtable if needed\n\t\t\t\tgetResponseHeader: function( key ) {\n\t\t\t\t\tvar match;\n\t\t\t\t\tif ( completed ) {\n\t\t\t\t\t\tif ( !responseHeaders ) {\n\t\t\t\t\t\t\tresponseHeaders = {};\n\t\t\t\t\t\t\twhile ( ( match = rheaders.exec( responseHeadersString ) ) ) {\n\n\t\t\t\t\t\t\t\t// Support: IE 11+\n\t\t\t\t\t\t\t\t// `getResponseHeader( key )` in IE doesn't combine all header\n\t\t\t\t\t\t\t\t// values for the provided key into a single result with values\n\t\t\t\t\t\t\t\t// joined by commas as other browsers do. Instead, it returns\n\t\t\t\t\t\t\t\t// them on separate lines.\n\t\t\t\t\t\t\t\tresponseHeaders[ match[ 1 ].toLowerCase() + \" \" ] =\n\t\t\t\t\t\t\t\t\t( responseHeaders[ match[ 1 ].toLowerCase() + \" \" ] || [] )\n\t\t\t\t\t\t\t\t\t\t.concat( match[ 2 ] );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tmatch = responseHeaders[ key.toLowerCase() + \" \" ];\n\t\t\t\t\t}\n\t\t\t\t\treturn match == null ? null : match.join( \", \" );\n\t\t\t\t},\n\n\t\t\t\t// Raw string\n\t\t\t\tgetAllResponseHeaders: function() {\n\t\t\t\t\treturn completed ? responseHeadersString : null;\n\t\t\t\t},\n\n\t\t\t\t// Caches the header\n\t\t\t\tsetRequestHeader: function( name, value ) {\n\t\t\t\t\tif ( completed == null ) {\n\t\t\t\t\t\tname = requestHeadersNames[ name.toLowerCase() ] =\n\t\t\t\t\t\t\trequestHeadersNames[ name.toLowerCase() ] || name;\n\t\t\t\t\t\trequestHeaders[ name ] = value;\n\t\t\t\t\t}\n\t\t\t\t\treturn this;\n\t\t\t\t},\n\n\t\t\t\t// Overrides response content-type header\n\t\t\t\toverrideMimeType: function( type ) {\n\t\t\t\t\tif ( completed == null ) {\n\t\t\t\t\t\ts.mimeType = type;\n\t\t\t\t\t}\n\t\t\t\t\treturn this;\n\t\t\t\t},\n\n\t\t\t\t// Status-dependent callbacks\n\t\t\t\tstatusCode: function( map ) {\n\t\t\t\t\tvar code;\n\t\t\t\t\tif ( map ) {\n\t\t\t\t\t\tif ( completed ) {\n\n\t\t\t\t\t\t\t// Execute the appropriate callbacks\n\t\t\t\t\t\t\tjqXHR.always( map[ jqXHR.status ] );\n\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t// Lazy-add the new callbacks in a way that preserves old ones\n\t\t\t\t\t\t\tfor ( code in map ) {\n\t\t\t\t\t\t\t\tstatusCode[ code ] = [ statusCode[ code ], map[ code ] ];\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\treturn this;\n\t\t\t\t},\n\n\t\t\t\t// Cancel the request\n\t\t\t\tabort: function( statusText ) {\n\t\t\t\t\tvar finalText = statusText || strAbort;\n\t\t\t\t\tif ( transport ) {\n\t\t\t\t\t\ttransport.abort( finalText );\n\t\t\t\t\t}\n\t\t\t\t\tdone( 0, finalText );\n\t\t\t\t\treturn this;\n\t\t\t\t}\n\t\t\t};\n\n\t\t// Attach deferreds\n\t\tdeferred.promise( jqXHR );\n\n\t\t// Add protocol if not provided (prefilters might expect it)\n\t\t// Handle falsy url in the settings object (trac-10093: consistency with old signature)\n\t\t// We also use the url parameter if available\n\t\ts.url = ( ( url || s.url || location.href ) + \"\" )\n\t\t\t.replace( rprotocol, location.protocol + \"//\" );\n\n\t\t// Alias method option to type as per ticket trac-12004\n\t\ts.type = options.method || options.type || s.method || s.type;\n\n\t\t// Extract dataTypes list\n\t\ts.dataTypes = ( s.dataType || \"*\" ).toLowerCase().match( rnothtmlwhite ) || [ \"\" ];\n\n\t\t// A cross-domain request is in order when the origin doesn't match the current origin.\n\t\tif ( s.crossDomain == null ) {\n\t\t\turlAnchor = document$1.createElement( \"a\" );\n\n\t\t\t// Support: IE <=8 - 11+\n\t\t\t// IE throws exception on accessing the href property if url is malformed,\n\t\t\t// e.g. http://example.com:80x/\n\t\t\ttry {\n\t\t\t\turlAnchor.href = s.url;\n\n\t\t\t\t// Support: IE <=8 - 11+\n\t\t\t\t// Anchor's host property isn't correctly set when s.url is relative\n\t\t\t\turlAnchor.href = urlAnchor.href;\n\t\t\t\ts.crossDomain = originAnchor.protocol + \"//\" + originAnchor.host !==\n\t\t\t\t\turlAnchor.protocol + \"//\" + urlAnchor.host;\n\t\t\t} catch ( e ) {\n\n\t\t\t\t// If there is an error parsing the URL, assume it is crossDomain,\n\t\t\t\t// it can be rejected by the transport if it is invalid\n\t\t\t\ts.crossDomain = true;\n\t\t\t}\n\t\t}\n\n\t\t// Apply prefilters\n\t\tinspectPrefiltersOrTransports( prefilters, s, options, jqXHR );\n\n\t\t// Convert data if not already a string\n\t\tif ( s.data && s.processData && typeof s.data !== \"string\" ) {\n\t\t\ts.data = jQuery.param( s.data, s.traditional );\n\t\t}\n\n\t\t// If request was aborted inside a prefilter, stop there\n\t\tif ( completed ) {\n\t\t\treturn jqXHR;\n\t\t}\n\n\t\t// We can fire global events as of now if asked to\n\t\t// Don't fire events if jQuery.event is undefined in an ESM-usage scenario (trac-15118)\n\t\tfireGlobals = jQuery.event && s.global;\n\n\t\t// Watch for a new set of requests\n\t\tif ( fireGlobals && jQuery.active++ === 0 ) {\n\t\t\tjQuery.event.trigger( \"ajaxStart\" );\n\t\t}\n\n\t\t// Uppercase the type\n\t\ts.type = s.type.toUpperCase();\n\n\t\t// Determine if request has content\n\t\ts.hasContent = !rnoContent.test( s.type );\n\n\t\t// Save the URL in case we're toying with the If-Modified-Since\n\t\t// and/or If-None-Match header later on\n\t\t// Remove hash to simplify url manipulation\n\t\tcacheURL = s.url.replace( rhash, \"\" );\n\n\t\t// More options handling for requests with no content\n\t\tif ( !s.hasContent ) {\n\n\t\t\t// Remember the hash so we can put it back\n\t\t\tuncached = s.url.slice( cacheURL.length );\n\n\t\t\t// If data is available and should be processed, append data to url\n\t\t\tif ( s.data && ( s.processData || typeof s.data === \"string\" ) ) {\n\t\t\t\tcacheURL += ( rquery.test( cacheURL ) ? \"&\" : \"?\" ) + s.data;\n\n\t\t\t\t// trac-9682: remove data so that it's not used in an eventual retry\n\t\t\t\tdelete s.data;\n\t\t\t}\n\n\t\t\t// Add or update anti-cache param if needed\n\t\t\tif ( s.cache === false ) {\n\t\t\t\tcacheURL = cacheURL.replace( rantiCache, \"$1\" );\n\t\t\t\tuncached = ( rquery.test( cacheURL ) ? \"&\" : \"?\" ) + \"_=\" +\n\t\t\t\t\t( nonce.guid++ ) + uncached;\n\t\t\t}\n\n\t\t\t// Put hash and anti-cache on the URL that will be requested (gh-1732)\n\t\t\ts.url = cacheURL + uncached;\n\n\t\t// Change '%20' to '+' if this is encoded form body content (gh-2658)\n\t\t} else if ( s.data && s.processData &&\n\t\t\t( s.contentType || \"\" ).indexOf( \"application/x-www-form-urlencoded\" ) === 0 ) {\n\t\t\ts.data = s.data.replace( r20, \"+\" );\n\t\t}\n\n\t\t// Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.\n\t\tif ( s.ifModified ) {\n\t\t\tif ( jQuery.lastModified[ cacheURL ] ) {\n\t\t\t\tjqXHR.setRequestHeader( \"If-Modified-Since\", jQuery.lastModified[ cacheURL ] );\n\t\t\t}\n\t\t\tif ( jQuery.etag[ cacheURL ] ) {\n\t\t\t\tjqXHR.setRequestHeader( \"If-None-Match\", jQuery.etag[ cacheURL ] );\n\t\t\t}\n\t\t}\n\n\t\t// Set the correct header, if data is being sent\n\t\tif ( s.data && s.hasContent && s.contentType !== false || options.contentType ) {\n\t\t\tjqXHR.setRequestHeader( \"Content-Type\", s.contentType );\n\t\t}\n\n\t\t// Set the Accepts header for the server, depending on the dataType\n\t\tjqXHR.setRequestHeader(\n\t\t\t\"Accept\",\n\t\t\ts.dataTypes[ 0 ] && s.accepts[ s.dataTypes[ 0 ] ] ?\n\t\t\t\ts.accepts[ s.dataTypes[ 0 ] ] +\n\t\t\t\t\t( s.dataTypes[ 0 ] !== \"*\" ? \", \" + allTypes + \"; q=0.01\" : \"\" ) :\n\t\t\t\ts.accepts[ \"*\" ]\n\t\t);\n\n\t\t// Check for headers option\n\t\tfor ( i in s.headers ) {\n\t\t\tjqXHR.setRequestHeader( i, s.headers[ i ] );\n\t\t}\n\n\t\t// Allow custom headers/mimetypes and early abort\n\t\tif ( s.beforeSend &&\n\t\t\t( s.beforeSend.call( callbackContext, jqXHR, s ) === false || completed ) ) {\n\n\t\t\t// Abort if not done already and return\n\t\t\treturn jqXHR.abort();\n\t\t}\n\n\t\t// Aborting is no longer a cancellation\n\t\tstrAbort = \"abort\";\n\n\t\t// Install callbacks on deferreds\n\t\tcompleteDeferred.add( s.complete );\n\t\tjqXHR.done( s.success );\n\t\tjqXHR.fail( s.error );\n\n\t\t// Get transport\n\t\ttransport = inspectPrefiltersOrTransports( transports, s, options, jqXHR );\n\n\t\t// If no transport, we auto-abort\n\t\tif ( !transport ) {\n\t\t\tdone( -1, \"No Transport\" );\n\t\t} else {\n\t\t\tjqXHR.readyState = 1;\n\n\t\t\t// Send global event\n\t\t\tif ( fireGlobals ) {\n\t\t\t\tglobalEventContext.trigger( \"ajaxSend\", [ jqXHR, s ] );\n\t\t\t}\n\n\t\t\t// If request was aborted inside ajaxSend, stop there\n\t\t\tif ( completed ) {\n\t\t\t\treturn jqXHR;\n\t\t\t}\n\n\t\t\t// Timeout\n\t\t\tif ( s.async && s.timeout > 0 ) {\n\t\t\t\ttimeoutTimer = window.setTimeout( function() {\n\t\t\t\t\tjqXHR.abort( \"timeout\" );\n\t\t\t\t}, s.timeout );\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tcompleted = false;\n\t\t\t\ttransport.send( requestHeaders, done );\n\t\t\t} catch ( e ) {\n\n\t\t\t\t// Rethrow post-completion exceptions\n\t\t\t\tif ( completed ) {\n\t\t\t\t\tthrow e;\n\t\t\t\t}\n\n\t\t\t\t// Propagate others as results\n\t\t\t\tdone( -1, e );\n\t\t\t}\n\t\t}\n\n\t\t// Callback for when everything is done\n\t\tfunction done( status, nativeStatusText, responses, headers ) {\n\t\t\tvar isSuccess, success, error, response, modified,\n\t\t\t\tstatusText = nativeStatusText;\n\n\t\t\t// Ignore repeat invocations\n\t\t\tif ( completed ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tcompleted = true;\n\n\t\t\t// Clear timeout if it exists\n\t\t\tif ( timeoutTimer ) {\n\t\t\t\twindow.clearTimeout( timeoutTimer );\n\t\t\t}\n\n\t\t\t// Dereference transport for early garbage collection\n\t\t\t// (no matter how long the jqXHR object will be used)\n\t\t\ttransport = undefined;\n\n\t\t\t// Cache response headers\n\t\t\tresponseHeadersString = headers || \"\";\n\n\t\t\t// Set readyState\n\t\t\tjqXHR.readyState = status > 0 ? 4 : 0;\n\n\t\t\t// Determine if successful\n\t\t\tisSuccess = status >= 200 && status < 300 || status === 304;\n\n\t\t\t// Get response data\n\t\t\tif ( responses ) {\n\t\t\t\tresponse = ajaxHandleResponses( s, jqXHR, responses );\n\t\t\t}\n\n\t\t\t// Use a noop converter for missing script but not if jsonp\n\t\t\tif ( !isSuccess &&\n\t\t\t\tjQuery.inArray( \"script\", s.dataTypes ) > -1 &&\n\t\t\t\tjQuery.inArray( \"json\", s.dataTypes ) < 0 ) {\n\t\t\t\ts.converters[ \"text script\" ] = function() {};\n\t\t\t}\n\n\t\t\t// Convert no matter what (that way responseXXX fields are always set)\n\t\t\tresponse = ajaxConvert( s, response, jqXHR, isSuccess );\n\n\t\t\t// If successful, handle type chaining\n\t\t\tif ( isSuccess ) {\n\n\t\t\t\t// Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.\n\t\t\t\tif ( s.ifModified ) {\n\t\t\t\t\tmodified = jqXHR.getResponseHeader( \"Last-Modified\" );\n\t\t\t\t\tif ( modified ) {\n\t\t\t\t\t\tjQuery.lastModified[ cacheURL ] = modified;\n\t\t\t\t\t}\n\t\t\t\t\tmodified = jqXHR.getResponseHeader( \"etag\" );\n\t\t\t\t\tif ( modified ) {\n\t\t\t\t\t\tjQuery.etag[ cacheURL ] = modified;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// if no content\n\t\t\t\tif ( status === 204 || s.type === \"HEAD\" ) {\n\t\t\t\t\tstatusText = \"nocontent\";\n\n\t\t\t\t// if not modified\n\t\t\t\t} else if ( status === 304 ) {\n\t\t\t\t\tstatusText = \"notmodified\";\n\n\t\t\t\t// If we have data, let's convert it\n\t\t\t\t} else {\n\t\t\t\t\tstatusText = response.state;\n\t\t\t\t\tsuccess = response.data;\n\t\t\t\t\terror = response.error;\n\t\t\t\t\tisSuccess = !error;\n\t\t\t\t}\n\t\t\t} else {\n\n\t\t\t\t// Extract error from statusText and normalize for non-aborts\n\t\t\t\terror = statusText;\n\t\t\t\tif ( status || !statusText ) {\n\t\t\t\t\tstatusText = \"error\";\n\t\t\t\t\tif ( status < 0 ) {\n\t\t\t\t\t\tstatus = 0;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Set data for the fake xhr object\n\t\t\tjqXHR.status = status;\n\t\t\tjqXHR.statusText = ( nativeStatusText || statusText ) + \"\";\n\n\t\t\t// Success/Error\n\t\t\tif ( isSuccess ) {\n\t\t\t\tdeferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] );\n\t\t\t} else {\n\t\t\t\tdeferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] );\n\t\t\t}\n\n\t\t\t// Status-dependent callbacks\n\t\t\tjqXHR.statusCode( statusCode );\n\t\t\tstatusCode = undefined;\n\n\t\t\tif ( fireGlobals ) {\n\t\t\t\tglobalEventContext.trigger( isSuccess ? \"ajaxSuccess\" : \"ajaxError\",\n\t\t\t\t\t[ jqXHR, s, isSuccess ? success : error ] );\n\t\t\t}\n\n\t\t\t// Complete\n\t\t\tcompleteDeferred.fireWith( callbackContext, [ jqXHR, statusText ] );\n\n\t\t\tif ( fireGlobals ) {\n\t\t\t\tglobalEventContext.trigger( \"ajaxComplete\", [ jqXHR, s ] );\n\n\t\t\t\t// Handle the global AJAX counter\n\t\t\t\tif ( !( --jQuery.active ) ) {\n\t\t\t\t\tjQuery.event.trigger( \"ajaxStop\" );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn jqXHR;\n\t},\n\n\tgetJSON: function( url, data, callback ) {\n\t\treturn jQuery.get( url, data, callback, \"json\" );\n\t},\n\n\tgetScript: function( url, callback ) {\n\t\treturn jQuery.get( url, undefined, callback, \"script\" );\n\t}\n} );\n\njQuery.each( [ \"get\", \"post\" ], function( _i, method ) {\n\tjQuery[ method ] = function( url, data, callback, type ) {\n\n\t\t// Shift arguments if data argument was omitted.\n\t\t// Handle the null callback placeholder.\n\t\tif ( typeof data === \"function\" || data === null ) {\n\t\t\ttype = type || callback;\n\t\t\tcallback = data;\n\t\t\tdata = undefined;\n\t\t}\n\n\t\t// The url can be an options object (which then must have .url)\n\t\treturn jQuery.ajax( jQuery.extend( {\n\t\t\turl: url,\n\t\t\ttype: method,\n\t\t\tdataType: type,\n\t\t\tdata: data,\n\t\t\tsuccess: callback\n\t\t}, jQuery.isPlainObject( url ) && url ) );\n\t};\n} );\n\njQuery.ajaxPrefilter( function( s ) {\n\tvar i;\n\tfor ( i in s.headers ) {\n\t\tif ( i.toLowerCase() === \"content-type\" ) {\n\t\t\ts.contentType = s.headers[ i ] || \"\";\n\t\t}\n\t}\n} );\n\njQuery._evalUrl = function( url, options, doc ) {\n\treturn jQuery.ajax( {\n\t\turl: url,\n\n\t\t// Make this explicit, since user can override this through ajaxSetup (trac-11264)\n\t\ttype: \"GET\",\n\t\tdataType: \"script\",\n\t\tcache: true,\n\t\tasync: false,\n\t\tglobal: false,\n\t\tscriptAttrs: options.crossOrigin ? { \"crossOrigin\": options.crossOrigin } : undefined,\n\n\t\t// Only evaluate the response if it is successful (gh-4126)\n\t\t// dataFilter is not invoked for failure responses, so using it instead\n\t\t// of the default converter is kludgy but it works.\n\t\tconverters: {\n\t\t\t\"text script\": function() {}\n\t\t},\n\t\tdataFilter: function( response ) {\n\t\t\tjQuery.globalEval( response, options, doc );\n\t\t}\n\t} );\n};\n\njQuery.fn.extend( {\n\twrapAll: function( html ) {\n\t\tvar wrap;\n\n\t\tif ( this[ 0 ] ) {\n\t\t\tif ( typeof html === \"function\" ) {\n\t\t\t\thtml = html.call( this[ 0 ] );\n\t\t\t}\n\n\t\t\t// The elements to wrap the target around\n\t\t\twrap = jQuery( html, this[ 0 ].ownerDocument ).eq( 0 ).clone( true );\n\n\t\t\tif ( this[ 0 ].parentNode ) {\n\t\t\t\twrap.insertBefore( this[ 0 ] );\n\t\t\t}\n\n\t\t\twrap.map( function() {\n\t\t\t\tvar elem = this;\n\n\t\t\t\twhile ( elem.firstElementChild ) {\n\t\t\t\t\telem = elem.firstElementChild;\n\t\t\t\t}\n\n\t\t\t\treturn elem;\n\t\t\t} ).append( this );\n\t\t}\n\n\t\treturn this;\n\t},\n\n\twrapInner: function( html ) {\n\t\tif ( typeof html === \"function\" ) {\n\t\t\treturn this.each( function( i ) {\n\t\t\t\tjQuery( this ).wrapInner( html.call( this, i ) );\n\t\t\t} );\n\t\t}\n\n\t\treturn this.each( function() {\n\t\t\tvar self = jQuery( this ),\n\t\t\t\tcontents = self.contents();\n\n\t\t\tif ( contents.length ) {\n\t\t\t\tcontents.wrapAll( html );\n\n\t\t\t} else {\n\t\t\t\tself.append( html );\n\t\t\t}\n\t\t} );\n\t},\n\n\twrap: function( html ) {\n\t\tvar htmlIsFunction = typeof html === \"function\";\n\n\t\treturn this.each( function( i ) {\n\t\t\tjQuery( this ).wrapAll( htmlIsFunction ? html.call( this, i ) : html );\n\t\t} );\n\t},\n\n\tunwrap: function( selector ) {\n\t\tthis.parent( selector ).not( \"body\" ).each( function() {\n\t\t\tjQuery( this ).replaceWith( this.childNodes );\n\t\t} );\n\t\treturn this;\n\t}\n} );\n\njQuery.expr.pseudos.hidden = function( elem ) {\n\treturn !jQuery.expr.pseudos.visible( elem );\n};\njQuery.expr.pseudos.visible = function( elem ) {\n\treturn !!( elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length );\n};\n\njQuery.ajaxSettings.xhr = function() {\n\treturn new window.XMLHttpRequest();\n};\n\nvar xhrSuccessStatus = {\n\n\t// File protocol always yields status code 0, assume 200\n\t0: 200\n};\n\njQuery.ajaxTransport( function( options ) {\n\tvar callback;\n\n\treturn {\n\t\tsend: function( headers, complete ) {\n\t\t\tvar i,\n\t\t\t\txhr = options.xhr();\n\n\t\t\txhr.open(\n\t\t\t\toptions.type,\n\t\t\t\toptions.url,\n\t\t\t\toptions.async,\n\t\t\t\toptions.username,\n\t\t\t\toptions.password\n\t\t\t);\n\n\t\t\t// Apply custom fields if provided\n\t\t\tif ( options.xhrFields ) {\n\t\t\t\tfor ( i in options.xhrFields ) {\n\t\t\t\t\txhr[ i ] = options.xhrFields[ i ];\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Override mime type if needed\n\t\t\tif ( options.mimeType && xhr.overrideMimeType ) {\n\t\t\t\txhr.overrideMimeType( options.mimeType );\n\t\t\t}\n\n\t\t\t// X-Requested-With header\n\t\t\t// For cross-domain requests, seeing as conditions for a preflight are\n\t\t\t// akin to a jigsaw puzzle, we simply never set it to be sure.\n\t\t\t// (it can always be set on a per-request basis or even using ajaxSetup)\n\t\t\t// For same-domain requests, won't change header if already provided.\n\t\t\tif ( !options.crossDomain && !headers[ \"X-Requested-With\" ] ) {\n\t\t\t\theaders[ \"X-Requested-With\" ] = \"XMLHttpRequest\";\n\t\t\t}\n\n\t\t\t// Set headers\n\t\t\tfor ( i in headers ) {\n\t\t\t\txhr.setRequestHeader( i, headers[ i ] );\n\t\t\t}\n\n\t\t\t// Callback\n\t\t\tcallback = function( type ) {\n\t\t\t\treturn function() {\n\t\t\t\t\tif ( callback ) {\n\t\t\t\t\t\tcallback = xhr.onload = xhr.onerror = xhr.onabort = xhr.ontimeout = null;\n\n\t\t\t\t\t\tif ( type === \"abort\" ) {\n\t\t\t\t\t\t\txhr.abort();\n\t\t\t\t\t\t} else if ( type === \"error\" ) {\n\t\t\t\t\t\t\tcomplete(\n\n\t\t\t\t\t\t\t\t// File: protocol always yields status 0; see trac-8605, trac-14207\n\t\t\t\t\t\t\t\txhr.status,\n\t\t\t\t\t\t\t\txhr.statusText\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tcomplete(\n\t\t\t\t\t\t\t\txhrSuccessStatus[ xhr.status ] || xhr.status,\n\t\t\t\t\t\t\t\txhr.statusText,\n\n\t\t\t\t\t\t\t\t// For XHR2 non-text, let the caller handle it (gh-2498)\n\t\t\t\t\t\t\t\t( xhr.responseType || \"text\" ) === \"text\" ?\n\t\t\t\t\t\t\t\t\t{ text: xhr.responseText } :\n\t\t\t\t\t\t\t\t\t{ binary: xhr.response },\n\t\t\t\t\t\t\t\txhr.getAllResponseHeaders()\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t};\n\n\t\t\t// Listen to events\n\t\t\txhr.onload = callback();\n\t\t\txhr.onabort = xhr.onerror = xhr.ontimeout = callback( \"error\" );\n\n\t\t\t// Create the abort callback\n\t\t\tcallback = callback( \"abort\" );\n\n\t\t\ttry {\n\n\t\t\t\t// Do send the request (this may raise an exception)\n\t\t\t\txhr.send( options.hasContent && options.data || null );\n\t\t\t} catch ( e ) {\n\n\t\t\t\t// trac-14683: Only rethrow if this hasn't been notified as an error yet\n\t\t\t\tif ( callback ) {\n\t\t\t\t\tthrow e;\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\n\t\tabort: function() {\n\t\t\tif ( callback ) {\n\t\t\t\tcallback();\n\t\t\t}\n\t\t}\n\t};\n} );\n\nfunction canUseScriptTag( s ) {\n\n\t// A script tag can only be used for async, cross domain or forced-by-attrs requests.\n\t// Requests with headers cannot use a script tag. However, when both `scriptAttrs` &\n\t// `headers` options are specified, both are impossible to satisfy together; we\n\t// prefer `scriptAttrs` then.\n\t// Sync requests remain handled differently to preserve strict script ordering.\n\treturn s.scriptAttrs || (\n\t\t!s.headers &&\n\t\t(\n\t\t\ts.crossDomain ||\n\n\t\t\t// When dealing with JSONP (`s.dataTypes` include \"json\" then)\n\t\t\t// don't use a script tag so that error responses still may have\n\t\t\t// `responseJSON` set. Continue using a script tag for JSONP requests that:\n\t\t\t// * are cross-domain as AJAX requests won't work without a CORS setup\n\t\t\t// * have `scriptAttrs` set as that's a script-only functionality\n\t\t\t// Note that this means JSONP requests violate strict CSP script-src settings.\n\t\t\t// A proper solution is to migrate from using JSONP to a CORS setup.\n\t\t\t( s.async && jQuery.inArray( \"json\", s.dataTypes ) < 0 )\n\t\t)\n\t);\n}\n\n// Install script dataType. Don't specify `contents.script` so that an explicit\n// `dataType: \"script\"` is required (see gh-2432, gh-4822)\njQuery.ajaxSetup( {\n\taccepts: {\n\t\tscript: \"text/javascript, application/javascript, \" +\n\t\t\t\"application/ecmascript, application/x-ecmascript\"\n\t},\n\tconverters: {\n\t\t\"text script\": function( text ) {\n\t\t\tjQuery.globalEval( text );\n\t\t\treturn text;\n\t\t}\n\t}\n} );\n\n// Handle cache's special case and crossDomain\njQuery.ajaxPrefilter( \"script\", function( s ) {\n\tif ( s.cache === undefined ) {\n\t\ts.cache = false;\n\t}\n\n\t// These types of requests are handled via a script tag\n\t// so force their methods to GET.\n\tif ( canUseScriptTag( s ) ) {\n\t\ts.type = \"GET\";\n\t}\n} );\n\n// Bind script tag hack transport\njQuery.ajaxTransport( \"script\", function( s ) {\n\tif ( canUseScriptTag( s ) ) {\n\t\tvar script, callback;\n\t\treturn {\n\t\t\tsend: function( _, complete ) {\n\t\t\t\tscript = jQuery( \"\n \n \n `);\n document.close();\n}\n\nconst delay = (ms: number) => new Promise((resolve) => { setTimeout(resolve, ms); });\n\nexport async function restartReload(initial = true) {\n document.body.style = 'background: #222222; font-size: 1rem; font-family:monospace; margin-top:20%; color:lightgray; text-align:center';\n document.body.innerHTML = '

    Server shutdown in progress...

    ';\n if (initial) await delay(10000);\n try {\n const res = await authFetch(`${window.api}/progress?skip_current_image=true`);\n console.log('restartReload', res);\n if (res?.ok) {\n document.body.innerHTML = '

    Server restart in progress...

    ';\n setTimeout(() => location.reload(), 10000);\n } else {\n setTimeout(() => restartReload(false), 2500);\n }\n } catch {\n setTimeout(() => restartReload(false), 2500);\n }\n return [];\n}\n\nexport function updateInput(target) {\n const e = new Event('input', { bubbles: true });\n Object.defineProperty(e, 'target', { value: target });\n target.dispatchEvent(e);\n}\n\nlet desiredCheckpointName = null;\nexport function selectCheckpoint(name) {\n desiredCheckpointName = name;\n const tabName = getENActiveTab();\n const btnModel = gradioApp().getElementById(`${tabName}_extra_model`);\n const isRefiner = btnModel && btnModel.classList.contains('toolbutton-selected');\n if (isRefiner) gradioApp().getElementById('change_refiner').click();\n else gradioApp().getElementById('change_checkpoint').click();\n log(`selectCheckpoint ${isRefiner ? 'refiner' : 'model'}: ${desiredCheckpointName}`);\n markSelectedCards([desiredCheckpointName], 'model');\n setTimeout(requestProgress, 250);\n}\n\nlet desiredVAEName = null;\nexport function selectVAE(name) {\n desiredVAEName = name;\n gradioApp().getElementById('change_vae').click();\n log(`selectVAE: ${desiredVAEName}`);\n markSelectedCards([desiredVAEName], 'vae');\n}\n\nlet desiredUNetName = null;\n\nfunction consumeDesiredCheckpointName(v) {\n const res = desiredCheckpointName;\n desiredCheckpointName = null;\n return [res || v, null];\n}\n\nfunction consumeDesiredVAEName(v) {\n const res = desiredVAEName;\n desiredVAEName = null;\n return [res || v, null];\n}\n\nfunction consumeDesiredUNetName(v) {\n const res = desiredUNetName;\n desiredUNetName = null;\n return [res || v, null];\n}\n\nfunction getDesiredCheckpointName() {\n return desiredCheckpointName;\n}\n\nexport function selectUNet(name) {\n desiredUNetName = name;\n const tabName = getENActiveTab();\n const btnModel = gradioApp().getElementById(`${tabName}_extra_model`);\n const isSecondary = btnModel && btnModel.classList.contains('toolbutton-selected');\n if (isSecondary) gradioApp().getElementById('change_unet_secondary').click();\n else gradioApp().getElementById('change_unet').click();\n log(`selectUNet ${isSecondary ? 'secondary' : 'primary'}: ${desiredUNetName}`);\n markSelectedCards([desiredUNetName], 'unet');\n}\n\nexport function selectReference(name) {\n log(`selectReference: ${name}`);\n desiredCheckpointName = name;\n gradioApp().getElementById('change_reference').click();\n markSelectedCards([desiredCheckpointName], 'model');\n setTimeout(requestProgress, 250);\n}\n\nfunction currentImageResolutionimg2img(_a, _b, scaleBy) {\n const img = gradioApp().querySelector('#mode_img2img > div[style=\"display: block;\"] img');\n return img ? [img.naturalWidth, img.naturalHeight, scaleBy] : [0, 0, scaleBy];\n}\n\nfunction currentImageResolutioncontrol(_a, _b, scaleBy) {\n if (window.kanvas) {\n const active = window.kanvas.stages?.getActiveStage();\n return [active?.width || 0, active?.height || 0, scaleBy];\n }\n const img = gradioApp().querySelector('#control-tab-input > div[style=\"display: block;\"] img');\n return img ? [img.naturalWidth, img.naturalHeight, scaleBy] : [0, 0, scaleBy];\n}\n\nfunction updateImg2imgResizeToTextAfterChangingImage() {\n const el = gradioApp().getElementById('img2img_update_resize_to');\n if (el) setTimeout(() => gradioApp().getElementById('img2img_update_resize_to').click(), 500);\n return [];\n}\n\nfunction createThemeElement(): HTMLImageElement {\n const el = document.createElement('img');\n el.id = 'theme-preview';\n el.className = 'theme-preview';\n el.onclick = () => { el.style.display = 'none'; };\n document.body.appendChild(el);\n return el;\n}\n\nexport async function toggleCompact(val, old) {\n if (val === old) return;\n log('toggleCompact', val);\n if (val) {\n gradioApp().style.setProperty('--layout-gap', 'var(--spacing-md)');\n gradioApp().querySelectorAll('input[type=range]').forEach((el) => el.classList.add('hidden'));\n gradioApp().querySelectorAll('div .form').forEach((el) => el.classList.add('form-compact'));\n gradioApp().querySelectorAll('.small-accordion .label-wrap').forEach((el) => el.classList.add('accordion-compact'));\n } else {\n gradioApp().style.setProperty('--layout-gap', 'var(--spacing-xxl)');\n gradioApp().querySelectorAll('input[type=range]').forEach((el) => el.classList.remove('hidden'));\n gradioApp().querySelectorAll('div .form').forEach((el) => el.classList.remove('form-compact'));\n gradioApp().querySelectorAll('.small-accordion .label-wrap').forEach((el) => el.classList.remove('accordion-compact'));\n }\n}\n\nfunction previewTheme() {\n let name = gradioApp().getElementById('setting_gradio_theme').querySelectorAll('input')?.[0].value || '';\n authFetch(`${window.subpath}/file=data/themes.json`)\n .then((res) => {\n res.json()\n .then((themes) => {\n const theme = Array.isArray(themes) ? themes.find((t) => t.id === name) : null;\n if (theme) {\n window.open(theme.subdomain, '_blank');\n } else {\n const el = document.getElementById('theme-preview') as HTMLImageElement | null || createThemeElement();\n el.style.display = el.style.display === 'block' ? 'none' : 'block';\n name = name.replace('/', '-');\n el.src = `/file=ui/css/${name}.jpg`;\n }\n })\n .catch((e) => error(`previewTheme: ${e}`));\n })\n .catch((e) => error(`previewTheme: ${e}`));\n}\n\nasync function browseFolder() {\n const picker = window.showDirectoryPicker?.();\n if (!picker) return null;\n const f = await picker;\n if (f && f.kind === 'directory') return f.name;\n return null;\n}\n\nlet kanvasNotifyTimer: ReturnType | undefined;\n// Notify kanvas to resize its stage when the resize-panel width/height change. Wired through gradio's\n// .change so it also fires on programmatic updates (detect-size, paste params, swap, send-to) that the\n// client-side resolutionLock input listeners never see. Writes nothing back, so it cannot loop.\nexport function notifyKanvasResize(width: number, height: number) {\n if (window.resizeStage) {\n const w = Number(width);\n const h = Number(height);\n clearTimeout(kanvasNotifyTimer);\n kanvasNotifyTimer = setTimeout(() => window.resizeStage?.(w, h), 250);\n }\n}\n\nexport async function reconnectUI() {\n const t0 = performance.now();\n const gallery = gradioApp().getElementById('txt2img_gallery');\n const task_id = localStorage.getItem('task');\n const api_logo = Array.from(gradioApp().querySelectorAll('img')).filter((el) => el.src.endsWith('api-logo.svg'));\n if (api_logo.length > 0) api_logo[0].remove();\n if (task_id) {\n debug('task check:', task_id);\n requestProgress(task_id, null, gallery, null, null, true);\n }\n uiLoaded = true;\n\n const sd_model = gradioApp().getElementById('setting_sd_model_checkpoint');\n let loadingStarted = 0;\n let loadingMonitor: ReturnType | null = null;\n\n const sd_model_callback = async () => {\n const loading = sd_model.querySelector('.eta-bar');\n if (!loading) {\n loadingStarted = 0;\n clearInterval(loadingMonitor);\n updateModel();\n } else if (loadingStarted === 0) {\n loadingStarted = Date.now();\n loadingMonitor = setInterval(() => {\n const elapsed = Date.now() - loadingStarted;\n if (elapsed > 3000 && loading) loading.style.display = 'none';\n }, 5000);\n }\n };\n const sd_model_observer = new MutationObserver(sd_model_callback);\n sd_model_observer.observe(sd_model, { attributes: true, childList: true, subtree: true });\n const t1 = performance.now();\n log('reconnectUI', Math.round(t1 - t0));\n timer('reconnectUI', t1 - t0);\n}\n\nwindow.restartReload = restartReload;\nwindow.updateInput = updateInput;\nwindow.notifyKanvasResize = notifyKanvasResize;\nwindow.clip_gallery_urls = clip_gallery_urls;\nwindow.extract_image_from_gallery = extract_image_from_gallery;\nwindow.getCaptionActiveTab = getCaptionActiveTab;\nwindow.get_img2img_tab_index = get_img2img_tab_index;\nwindow.modelmerger = modelmerger;\nwindow.selected_gallery_index = selected_gallery_index;\nwindow.selected_gallery_files = selected_gallery_files;\nwindow.send_to_kanvas = send_to_kanvas;\nwindow.submit_control = submit_control;\nwindow.submit_framepack = submit_framepack;\nwindow.submit_img2img = submit_img2img;\nwindow.submit_ltx = submit_ltx;\nwindow.submit_minimax = submit_minimax;\nwindow.submit_postprocessing = submit_postprocessing;\nwindow.submit = submit_txt2img; // compatibility alias\nwindow.submit_txt2img = submit_txt2img;\nwindow.submit_video = submit_video;\nwindow.submit_video_wrapper = submit_video_wrapper;\nwindow.switch_to_txt2img = switch_to_txt2img;\nwindow.switch_to_img2img_tab = switch_to_img2img_tab;\nwindow.switch_to_img2img = switch_to_img2img;\nwindow.switch_to_inpaint = switch_to_inpaint;\nwindow.switch_to_sketch = switch_to_sketch;\nwindow.switch_to_composite = switch_to_composite;\nwindow.switch_to_extras = switch_to_extras;\nwindow.switch_to_control = switch_to_control;\nwindow.switch_to_video = switch_to_video;\nwindow.switch_to_caption = switch_to_caption;\nwindow.recalculate_prompts_txt2img = recalculate_prompts_txt2img;\nwindow.recalculate_prompts_img2img = recalculate_prompts_img2img;\nwindow.recalculate_prompts_inpaint = recalculate_prompts_inpaint;\nwindow.recalculate_prompts_control = recalculate_prompts_control;\nwindow.selectCheckpoint = selectCheckpoint;\nwindow.selectVAE = selectVAE;\nwindow.selectUNet = selectUNet;\nwindow.selectReference = selectReference;\nwindow.consumeDesiredCheckpointName = consumeDesiredCheckpointName;\nwindow.consumeDesiredVAEName = consumeDesiredVAEName;\nwindow.consumeDesiredUNetName = consumeDesiredUNetName;\nwindow.getDesiredCheckpointName = getDesiredCheckpointName;\nwindow.currentImageResolutionimg2img = currentImageResolutionimg2img;\nwindow.currentImageResolutioncontrol = currentImageResolutioncontrol;\nwindow.updateImg2imgResizeToTextAfterChangingImage = updateImg2imgResizeToTextAfterChangingImage;\nwindow.create_submit_args = create_submit_args;\nwindow.set_theme = set_theme;\n", "import { gradioApp } from './script';\nimport { updateInput } from './ui';\n\ntype AccordionElement = HTMLElement & {\n visibleCheckbox: HTMLInputElement;\n onVisibleCheckboxChange: () => void;\n onChecked: (checked: boolean) => void;\n};\n\nexport function inputAccordionChecked(id: string, checked: boolean): void {\n const accordion = gradioApp().getElementById(id);\n if (!(accordion instanceof HTMLElement)) return;\n const acc = accordion as AccordionElement;\n acc.visibleCheckbox.checked = checked;\n acc.onVisibleCheckboxChange();\n}\n\nfunction setupAccordion(accordion: Element): void {\n if (!(accordion instanceof HTMLElement)) return;\n const acc = accordion as AccordionElement;\n const labelWrap = accordion.querySelector('.label-wrap');\n const gradioCheckbox = gradioApp().querySelector(`#${accordion.id}-checkbox input`);\n const extra = gradioApp().querySelector(`#${accordion.id}-extra`);\n if (!(labelWrap instanceof HTMLElement) || !(gradioCheckbox instanceof HTMLInputElement)) return;\n const span = labelWrap.querySelector('span');\n if (!(span instanceof HTMLElement)) return;\n let linked = true;\n const isOpen = () => labelWrap.classList.contains('open');\n const observerAccordionOpen = new MutationObserver((mutations) => {\n mutations.forEach((mutationRecord) => {\n accordion.classList.toggle('input-accordion-open', isOpen());\n if (linked) {\n acc.visibleCheckbox.checked = isOpen();\n acc.onVisibleCheckboxChange();\n }\n });\n });\n observerAccordionOpen.observe(labelWrap, { attributes: true, attributeFilter: ['class'] });\n if (extra instanceof Node) labelWrap.insertBefore(extra, labelWrap.lastElementChild);\n acc.onChecked = (checked: boolean) => {\n if (isOpen() !== checked) labelWrap.click();\n };\n\n const visibleCheckbox = document.createElement('INPUT');\n visibleCheckbox.type = 'checkbox';\n visibleCheckbox.checked = isOpen();\n visibleCheckbox.id = `${accordion.id}-visible-checkbox`;\n visibleCheckbox.className = `${gradioCheckbox.className} input-accordion-checkbox`;\n span.insertBefore(visibleCheckbox, span.firstChild);\n acc.visibleCheckbox = visibleCheckbox as any;\n acc.onVisibleCheckboxChange = () => {\n if (linked && isOpen() !== visibleCheckbox.checked) labelWrap.click();\n gradioCheckbox.checked = visibleCheckbox.checked;\n updateInput(gradioCheckbox);\n };\n\n visibleCheckbox.addEventListener('click', (event) => {\n linked = false;\n event.stopPropagation();\n });\n visibleCheckbox.addEventListener('input', acc.onVisibleCheckboxChange);\n}\n\nwindow.inputAccordionChecked = inputAccordionChecked;\n\n// onUiLoaded(() => {\n// for (const accordion of gradioApp().querySelectorAll('.input-accordion')) setupAccordion(accordion);\n// });\n\nexport function initAccordions() {\n for (const accordion of gradioApp().querySelectorAll('.input-accordion')) setupAccordion(accordion);\n}\n", "/**\n * @type {?IDBDatabase}\n */\nimport { log } from './logger';\n\nlet db = null;\n\ninterface ThumbRecord {\n hash: string;\n folder?: string;\n [key: string]: unknown;\n}\n\nexport async function initIndexDB(): Promise {\n async function createDB(): Promise {\n return new Promise((resolve, reject) => {\n const request = indexedDB.open('SDNext', 2);\n request.onerror = (evt: Event) => reject(evt);\n request.onsuccess = (evt: Event) => {\n db = (evt.target as IDBOpenDBRequest).result;\n const countAll = db\n .transaction(['thumbs'], 'readwrite')\n .objectStore('thumbs')\n .count();\n countAll.onsuccess = () => log('initIndexDB', countAll.result);\n resolve();\n };\n request.onupgradeneeded = (evt: IDBVersionChangeEvent) => {\n db = (evt.target as IDBOpenDBRequest).result;\n const oldver = evt.oldVersion;\n if (oldver < 1) {\n const store = db.createObjectStore('thumbs', { keyPath: 'hash' });\n store.createIndex('hash', 'hash', { unique: true });\n }\n if (oldver < 2) {\n const existingStore = request.transaction.objectStore('thumbs');\n existingStore.createIndex('folder', 'folder', { unique: false });\n }\n resolve();\n };\n });\n }\n\n if (!db) await createDB();\n}\n\nexport function idbIsReady(): boolean {\n return db !== null;\n}\n\n/**\n * Reusable setup for handling IDB transactions.\n * @param {Object} resources - Required resources for implementation\n * @param {IDBTransaction} resources.transaction\n * @param {AbortSignal} resources.signal\n * @param {Function} resources.resolve\n * @param {Function} resources.reject\n * @param {*} resolveValue - Value to resolve the outer Promise with\n * @returns {() => void} - Function for manually aborting the transaction\n */\nfunction configureTransactionAbort({\n transaction,\n signal,\n resolve,\n reject,\n}: {\n transaction: IDBTransaction;\n signal: AbortSignal;\n resolve: (value: T) => void;\n reject: (reason?: unknown) => void;\n}, resolveValue: T): () => void {\n function abortTransaction() {\n signal.removeEventListener('abort', abortTransaction);\n transaction.abort();\n }\n signal.addEventListener('abort', abortTransaction);\n transaction.onabort = () => {\n signal.removeEventListener('abort', abortTransaction);\n reject(new DOMException(`Aborting database transaction. ${signal.reason}`, 'AbortError'));\n };\n transaction.onerror = (e) => {\n signal.removeEventListener('abort', abortTransaction);\n reject(new Error('Database transaction error.'));\n };\n transaction.oncomplete = () => {\n signal.removeEventListener('abort', abortTransaction);\n resolve(resolveValue);\n };\n return abortTransaction;\n}\n\nasync function add(record: ThumbRecord): Promise {\n if (!db) return null;\n return new Promise((resolve, reject) => {\n const request = db\n .transaction(['thumbs'], 'readwrite')\n .objectStore('thumbs')\n .add(record);\n request.onsuccess = (evt) => resolve(evt);\n request.onerror = (evt) => reject(evt);\n });\n}\n\nasync function del(hash: string): Promise {\n if (!db) return null;\n return new Promise((resolve, reject) => {\n const request = db\n .transaction(['thumbs'], 'readwrite')\n .objectStore('thumbs')\n .delete(hash);\n request.onsuccess = (evt) => resolve(evt);\n request.onerror = (evt) => reject(evt);\n });\n}\n\nasync function get(hash: string): Promise {\n if (!db) return null;\n return new Promise((resolve, reject) => {\n const request = db\n .transaction(['thumbs'], 'readonly')\n .objectStore('thumbs')\n .index('hash')\n .get(hash);\n request.onsuccess = () => resolve(request.result);\n request.onerror = (evt) => reject(evt);\n });\n}\n\nasync function getKeys(hash: string): Promise {\n if (!db) return null;\n return new Promise((resolve, reject) => {\n const request = db\n .transaction(['thumbs'], 'readonly')\n .objectStore('thumbs')\n .index('hash')\n .getAllKeys();\n request.onsuccess = () => resolve(request.result);\n request.onerror = (evt) => reject(evt);\n });\n}\n\nasync function put(record: ThumbRecord): Promise {\n if (!db) return null;\n return new Promise((resolve, reject) => {\n const request = db\n .transaction(['thumbs'], 'readwrite')\n .objectStore('thumbs')\n .put(record);\n request.onsuccess = (evt) => resolve(evt);\n request.onerror = (evt) => reject(evt);\n });\n}\n\nexport async function idbGetAllKeys(index: string | null = null, query: IDBValidKey | IDBKeyRange | null = null): Promise {\n if (!db) return null;\n return new Promise((resolve, reject) => {\n try {\n let request;\n const transaction = db.transaction('thumbs', 'readonly');\n transaction.onabort = (e) => reject(e);\n const store = transaction.objectStore('thumbs');\n if (index) request = store.index(index).getAllKeys(query);\n else request = store.getAllKeys(query);\n request.onsuccess = () => resolve(request.result);\n request.onerror = (e) => reject(e);\n } catch (err) {\n reject(err);\n }\n });\n}\n\n/**\n * Get the number of entries in the IndexedDB thumbnail cache.\n * @global\n * @param {IDBValidKey | IDBKeyRange | undefined} folder - If specified, get the count for this gallery folder. Otherwise get the total count.\n * @returns {Promise}\n */\nexport async function idbCount(folder?: IDBValidKey | IDBKeyRange): Promise {\n if (!db) return null;\n return new Promise((resolve, reject) => {\n try {\n let request;\n const transaction = db.transaction('thumbs', 'readonly');\n transaction.onabort = (e) => reject(e);\n const store = transaction.objectStore('thumbs');\n if (folder) request = store.index('folder').count(folder);\n else request = store.count();\n request.onsuccess = () => resolve(request.result);\n request.onerror = (e) => reject(e);\n } catch (err) {\n reject(err);\n }\n });\n}\n\n/**\n * Cleanup function for IndexedDB thumbnail cache.\n * @global\n * @param {Set} keepSet - Set containing the hashes of the current files in the folder\n * @param {IDBValidKey | IDBKeyRange} folder - Folder name/path or range\n * @param {AbortSignal} signal - Signal from the AbortController for thumbCacheCleanup()\n */\nexport async function idbFolderCleanup(keepSet: Set, folder: IDBValidKey | IDBKeyRange, signal: AbortSignal): Promise {\n if (!db) return null;\n const existing = await idbGetAllKeys('folder', folder);\n const removals = new Set((existing ?? []).map((entry) => String(entry)).filter((entry) => !keepSet.has(entry))); // Don't need to keep full set in memory\n const totalRemovals = removals.size;\n if (signal.aborted) {\n throw new Error(`Aborting. ${String(signal.reason)}`);\n }\n return new Promise((resolve, reject) => {\n const transaction = db.transaction('thumbs', 'readwrite');\n const props = { transaction, signal, resolve, reject };\n configureTransactionAbort(props, totalRemovals);\n const store = transaction.objectStore('thumbs');\n removals.forEach((entry) => { store.delete(entry); });\n });\n}\n\nexport async function idbClearAll(signal: AbortSignal): Promise {\n if (!db) return null;\n return new Promise((resolve, reject) => {\n const transaction = db.transaction(['thumbs'], 'readwrite');\n const props = { transaction, signal, resolve, reject };\n configureTransactionAbort(props, null);\n transaction.objectStore('thumbs').clear();\n });\n}\n\nexport const idbAdd = add;\nexport const idbDel = del;\nexport const idbGet = get;\nexport const idbPut = put;\nexport const idbKeys = getKeys;\n", "import { authFetch } from './authWrap';\nimport { log, error, xhrPost } from './logger';\nimport { timer } from './timers';\n\ninterface LogLine {\n created: number;\n level: string;\n module: string;\n facility: string;\n msg: string;\n}\n\nlet logMonitorEl: HTMLElement | null = null;\nlet logMonitorStatus = true;\nlet logWarnings = 0;\nlet logErrors = 0;\nlet logConnected = false;\n\nfunction dateToStr(ts: number): string {\n const dt = new Date(1000 * ts);\n // const year = dt.getFullYear();\n // const mo = String(dt.getMonth() + 1).padStart(2, '0');\n // const day = String(dt.getDate()).padStart(2, '0');\n const hour = String(dt.getHours()).padStart(2, '0');\n const min = String(dt.getMinutes()).padStart(2, '0');\n const sec = String(dt.getSeconds()).padStart(2, '0');\n const ms = String(dt.getMilliseconds()).padStart(3, '0');\n // const s = `${year}-${mo}-${day} ${hour}:${min}:${sec}.${ms}`;\n const s = `${hour}:${min}:${sec}.${ms}`;\n return s;\n}\n\nfunction htmlEscape(text: string): string {\n return text.replaceAll('&', '&').replaceAll('<', '<').replaceAll('>', '>');\n}\n\nfunction parseLogLine(line: string): LogLine {\n let str = line.replaceAll('\\n', ' ').replaceAll('\\\\', '\\\\\\\\');\n const tracebackIndex = str.indexOf('Traceback');\n if (tracebackIndex !== -1) str = str.substring(0, tracebackIndex);\n const parsed = JSON.parse(str) as Partial;\n return {\n created: Number(parsed.created ?? Date.now()),\n level: String(parsed.level ?? 'INFO'),\n module: String(parsed.module ?? 'logMonitor'),\n facility: String(parsed.facility ?? 'ui'),\n msg: String(parsed.msg ?? ''),\n };\n}\n\nasync function clearErrors(): Promise {\n logWarnings = 0;\n logErrors = 0;\n log('clearErrors');\n}\n\nexport async function initClearErrorsButton() {\n const btnServerClear = document.getElementById('btn_console_log_server_clear');\n if (btnServerClear) {\n btnServerClear.onclick = async (evt) => {\n evt.preventDefault();\n evt.stopPropagation();\n clearErrors();\n };\n }\n}\n\nasync function logMonitor() {\n const addLogLine = (line: string): void => {\n if (!logMonitorEl) logMonitorEl = document.getElementById('logMonitorData');\n if (!logMonitorEl) return;\n try {\n const l = parseLogLine(line);\n const row = document.createElement('tr');\n // row.style = 'padding: 10px; margin: 0;';\n const level = ``;\n if (l.level === 'WARNING') logWarnings++;\n if (l.level === 'ERROR') logErrors++;\n const module = ``;\n const facilityText = l.facility.length > 20 ? `${l.facility.substring(0, 20)}...` : l.facility;\n const facility = l.facility !== 'sd' ? `` : '';\n row.innerHTML = `${level}${facility}${module}`;\n logMonitorEl.appendChild(row);\n } catch (err) {\n error('logMonitor', { error: String(err), line });\n }\n };\n\n const cleanupLog = (atBottom: boolean): void => {\n if (!logMonitorEl) return;\n while (logMonitorEl.childElementCount > 100 && logMonitorEl.firstElementChild) {\n logMonitorEl.removeChild(logMonitorEl.firstElementChild);\n }\n if (atBottom) logMonitorEl.scrollTop = logMonitorEl.scrollHeight;\n else if (logMonitorEl.parentElement) logMonitorEl.parentElement.style.cssText = 'border-bottom: 2px solid var(--highlight-color);';\n const elWarn = document.getElementById('logWarnings');\n const elErr = document.getElementById('logErrors');\n const modenUIBtn = document.getElementById('btn_console');\n if (elWarn) elWarn.innerText = String(logWarnings);\n if (elErr) elErr.innerText = String(logErrors);\n if (modenUIBtn) {\n modenUIBtn.setAttribute('error-count', logErrors > 0 ? String(logErrors) : '');\n modenUIBtn.style.backgroundColor = logErrors > 0 ? 'var(--color-error)' : '';\n modenUIBtn.title = `Log\\nErrors ${logErrors}\\nWarnings ${logWarnings}`;\n }\n };\n\n const txtGallery = document.getElementById('txt2img_gallery');\n if (txtGallery) txtGallery.style.height = window.opts.logmonitor_show ? '50vh' : '55vh';\n const imgGallery = document.getElementById('img2img_gallery');\n if (imgGallery) imgGallery.style.height = window.opts.logmonitor_show ? '50vh' : '55vh';\n\n if (!window.opts.logmonitor_show) {\n Array.from(document.getElementsByClassName('log-monitor')).forEach((el) => {\n if (el instanceof HTMLElement) el.style.display = 'none';\n });\n return;\n }\n\n if (logMonitorStatus) setTimeout(logMonitor, window.opts.logmonitor_refresh_period);\n else setTimeout(logMonitor, 10 * 1000); // on failure try to reconnect every 10sec\n\n logMonitorStatus = false;\n if (!logMonitorEl) {\n logMonitorEl = document.getElementById('logMonitorData');\n if (logMonitorEl) {\n logMonitorEl.addEventListener('scroll', () => {\n const atBottom = logMonitorEl.scrollHeight <= (logMonitorEl.scrollTop + logMonitorEl.clientHeight);\n if (atBottom && logMonitorEl.parentElement) logMonitorEl.parentElement.style.cssText = '';\n });\n }\n }\n if (!logMonitorEl) return;\n const atBottom = logMonitorEl.scrollHeight <= (logMonitorEl.scrollTop + logMonitorEl.clientHeight);\n\n try {\n const res = await authFetch(`${window.api}/log?clear=True`);\n if (res?.ok) {\n logMonitorStatus = true;\n const lines = (await res.json()) as string[];\n if (logMonitorEl && lines?.length > 0 && logMonitorEl.parentElement?.parentElement instanceof HTMLElement) {\n logMonitorEl.parentElement.parentElement.style.display = window.opts.logmonitor_show ? 'block' : 'none';\n }\n if (!logConnected) {\n logConnected = true;\n xhrPost(`${window.api}/log`, { debug: 'connected' });\n logErrors = 0; // reset error count on reconnect\n }\n for (const line of lines) addLogLine(line);\n } else {\n logConnected = false;\n logErrors++;\n if (res) addLogLine(`{ \"created\": ${Date.now()}, \"level\":\"ERROR\", \"module\":\"logMonitor\", \"facility\":\"ui\", \"msg\":\"Failed to fetch log: ${res?.status} ${res?.statusText}\" }`);\n else addLogLine(`{ \"created\": ${Date.now()}, \"level\":\"ERROR\", \"module\":\"logMonitor\", \"facility\":\"ui\", \"msg\":\"Server unreachable\" }`);\n }\n cleanupLog(atBottom);\n } catch {\n logConnected = false;\n logErrors++;\n addLogLine(`{ \"created\": ${Date.now()}, \"level\":\"ERROR\", \"module\":\"logMonitor\", \"facility\":\"ui\", \"msg\":\"Server unreachable\" }`);\n cleanupLog(atBottom);\n }\n}\n\nexport async function initLogMonitor() {\n let el = document.getElementById('logMonitorPlaceholder');\n const modernUi = Boolean(el);\n if (!el) el = document.getElementsByTagName('footer')[0];\n if (!el) return;\n const t0 = performance.now();\n el.classList.add('log-monitor');\n const uiDisabled = Array.isArray(window.opts.ui_disabled) ? window.opts.ui_disabled : [];\n if (uiDisabled.includes('logs')) return;\n if (modernUi) {\n el.style.overflow = 'auto';\n el.innerHTML = `\n
    ${l.level}${l.module}${facilityText}${dateToStr(l.created)}${htmlEscape(l.msg)}
    \n \n \n
    \n `;\n } else {\n el.innerHTML = `\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
    TimeLevelModuleMessageWarnings 0Errors 0
    \n `;\n }\n el.style.display = 'none';\n authFetch(`${window.api}/start?agent=${encodeURI(navigator.userAgent)}`);\n logMonitor();\n initClearErrorsButton();\n const t1 = performance.now();\n log('initLogMonitor', { show: window.opts.logmonitor_show, time: Math.round(t1 - t0) });\n timer('initLogMonitor', t1 - t0);\n}\n", "import { authFetch } from './authWrap';\nimport { gradioApp, onAfterUiUpdate, onOptionsChanged, executeCallbacks, optionsChangedCallbacks } from './script';\nimport { log, debug, error } from './logger';\nimport { getENActiveTab } from './extraNetworks';\nimport { registerDragDrop, toggleCompact, setTheme, setFontSize, updateInput } from './ui';\nimport { timer } from './timers';\n\nlet settingsInitialized = false;\nlet opts_metadata = {};\nconst opts_tabs = {};\n\nfunction getSettingsTabs() {\n let nodes = gradioApp().querySelectorAll('#tab_settings .tabitem');\n if (!nodes || nodes.length === 0) nodes = gradioApp().querySelectorAll('.tab-content .tabitem');\n return nodes;\n}\n\nconst monitoredOpts: Record[] = [\n { sd_model_checkpoint: null },\n { sd_backend: () => gradioApp().getElementById('refresh_sd_model_checkpoint')?.click() },\n];\n\nexport function monitorOption(option, callback) {\n monitoredOpts.push({ [option]: callback });\n}\n\nconst AppyOpts = [ // monitored opts\n { compact_view: (val, old) => toggleCompact(val, old) },\n { gradio_theme: (val, old) => setTheme(val, old) },\n { font_size: (val, old) => setFontSize(val, old) },\n];\n\nasync function updateOpts(json_string) {\n const t0 = performance.now();\n const settings_data = JSON.parse(json_string);\n const new_opts = settings_data.values;\n opts_metadata = settings_data.metadata;\n\n const t1 = performance.now();\n for (const op of monitoredOpts) {\n const [key, callback] = Object.entries(op)[0];\n if (Object.hasOwn(opts, key) && opts[key] !== new_opts[key]) {\n log('updateOpt', { key, val: new_opts[key] });\n if (callback) callback(new_opts[key], opts[key]);\n }\n }\n\n for (const op of AppyOpts) {\n const [key, callback] = Object.entries(op)[0];\n if (callback) {\n const t3 = performance.now();\n callback(new_opts[key], opts[key]);\n const t4 = performance.now();\n if (t4 - t3 > 100) debug('AppyOptSlow', key, `time=${Math.round(t4 - t3)}`);\n }\n }\n\n window.opts = new_opts;\n Object.entries(opts_metadata as Record).forEach(([opt, meta]: [string, any]) => {\n if (!opts_tabs[meta.tab_name]) opts_tabs[meta.tab_name] = {};\n if (!opts_tabs[meta.tab_name].unsaved_keys) opts_tabs[meta.tab_name].unsaved_keys = new Set();\n if (!opts_tabs[meta.tab_name].saved_keys) opts_tabs[meta.tab_name].saved_keys = new Set();\n if (!meta.is_stored) opts_tabs[meta.tab_name].unsaved_keys.add(opt);\n else opts_tabs[meta.tab_name].saved_keys.add(opt);\n });\n const t2 = performance.now();\n log('updateOpts', { settings: Object.keys(new_opts).length, callbacks: Math.round(t2 - t1), apply: Math.round(t1 - t0) });\n timer('updateOpts', t2 - t0);\n}\n\nfunction showAllSettings() {\n // Try to ensure that the show all settings tab is opened by clicking on its tab button\n // const tab_dirty_indicator = gradioApp().getElementById('modification_indicator_show_all_pages');\n // if (tab_dirty_indicator && tab_dirty_indicator.nextSibling) tab_dirty_indicator.nextSibling.click();\n getSettingsTabs().forEach((elem) => {\n if (elem.id === 'settings_tab_licenses' || elem.id === 'settings_show_all_pages') return;\n elem.style.display = 'block';\n });\n}\n\nfunction openSettingsSection(sectionId: string) {\n const settingsTab = gradioApp().getElementById('tab_settings');\n const settingsButton = settingsTab ? gradioApp().querySelector(`button[aria-controls=\"${settingsTab.id}\"]`) : null;\n settingsButton?.click();\n const section = gradioApp().getElementById(`settings_section_tab_${sectionId}`);\n const sectionButton = section ? gradioApp().querySelector(`button[aria-controls=\"${section.id}\"]`) : null;\n sectionButton?.click();\n section?.scrollIntoView({ behavior: 'smooth', block: 'start' });\n}\nwindow.openSettingsSection = openSettingsSection;\n\nfunction markIfModified(setting_name, value) {\n if (!opts_metadata[setting_name]) return;\n const elem = gradioApp().getElementById(`modification_indicator_${setting_name}`);\n if (!elem) return;\n const previous_value = JSON.stringify(opts[setting_name]);\n const current_value = JSON.stringify(value);\n const changed_value = previous_value !== current_value;\n if (changed_value) elem.title = `click to revert to previous value: ${previous_value}`;\n const { is_stored } = opts_metadata[setting_name];\n if (is_stored) elem.title = 'custom value';\n elem.disabled = !changed_value && !is_stored;\n elem.classList.toggle('changed', changed_value);\n elem.classList.toggle('saved', is_stored);\n\n const { tab_name } = opts_metadata[setting_name];\n if (!opts_tabs[tab_name].changed) opts_tabs[tab_name].changed = new Set();\n const changed_items = opts_tabs[tab_name].changed;\n if (changed_value) changed_items.add(setting_name);\n else changed_items.delete(setting_name);\n const unsaved = opts_tabs[tab_name].unsaved_keys;\n const saved = opts_tabs[tab_name].saved_keys;\n\n // Set the indicator on the tab nav element\n const tab_nav_indicator = gradioApp().getElementById(`modification_indicator_${tab_name}`);\n tab_nav_indicator.disabled = (changed_items.size === 0) && (unsaved.size === 0);\n tab_nav_indicator.title = '';\n tab_nav_indicator.classList.toggle('changed', changed_items.size > 0);\n tab_nav_indicator.classList.toggle('saved', saved.size > 0);\n if (changed_items.size > 0) tab_nav_indicator.title += `click to reset ${changed_items.size} unapplied changes in this tab\\n`;\n if (saved.size > 0) tab_nav_indicator.title += `${saved.size} custom values\\n${unsaved.size} default values`;\n // TODO why is scroll happening on every change if all pages are visible?\n // elem.scrollIntoView({ behavior: 'smooth', block: 'center' });\n}\nwindow.markIfModified = markIfModified;\n\nfunction updateAllOpts() {\n if (Object.keys(opts).length !== 0) return false;\n const json_elem = gradioApp().getElementById('settings_json');\n log('updateAllOpts', !!json_elem);\n if (!json_elem) return false;\n json_elem.parentElement.style.display = 'none';\n const textarea = json_elem.querySelector('textarea');\n const jsdata = textarea.value;\n updateOpts(jsdata);\n return true;\n}\n\nasync function onAfterUiUpdateCallback() {\n if (!updateAllOpts()) return;\n const json_elem = gradioApp().getElementById('settings_json');\n const textarea = json_elem.querySelector('textarea');\n executeCallbacks(optionsChangedCallbacks);\n registerDragDrop();\n\n Object.defineProperty(textarea, 'value', {\n set(newValue) {\n const valueProp = Object.getOwnPropertyDescriptor(HTMLTextAreaElement.prototype, 'value');\n const oldValue = valueProp.get.call(textarea);\n valueProp.set.call(textarea, newValue);\n if (oldValue !== newValue) updateOpts(textarea.value);\n executeCallbacks(optionsChangedCallbacks);\n },\n get() {\n const valueProp = Object.getOwnPropertyDescriptor(HTMLTextAreaElement.prototype, 'value');\n return valueProp.get.call(textarea);\n },\n });\n\n const settingsSearch = gradioApp().querySelectorAll('#settings_search > label > textarea')[0];\n let settingsTimer: ReturnType | undefined;\n let settingSearchValue = '';\n\n function doSettingsSearch() {\n if (settingSearchValue === settingsSearch.value.trim().toLowerCase()) return;\n showAllSettings();\n const value = settingsSearch.value.trim().toLowerCase();\n log('doSettingsSearch', value);\n settingSearchValue = value;\n getSettingsTabs().forEach((section) => {\n section.querySelectorAll('.dirtyable').forEach((setting) => {\n const visible = setting.innerText.toLowerCase().includes(value) || setting.id.toLowerCase().includes(value);\n const parent = setting.closest('.settings_section');\n if (!visible) parent.style.display = 'none';\n else parent.style.removeProperty('display');\n });\n });\n }\n\n settingsSearch.oninput = (e) => {\n if (settingsTimer) clearTimeout(settingsTimer);\n settingsTimer = setTimeout(doSettingsSearch, 250);\n };\n settingsSearch.onkeypress = (e) => {\n if (e.key === 'Enter') {\n if (settingsTimer) clearTimeout(settingsTimer);\n doSettingsSearch();\n }\n };\n}\n\nonAfterUiUpdate(onAfterUiUpdateCallback);\n\nasync function onOptionsChangedCallback() {\n const setting_elems = gradioApp().querySelectorAll('#settings [id^=\"setting_\"]');\n setting_elems.forEach((elem) => {\n const setting_name = elem.id.replace('setting_', '');\n markIfModified(setting_name, opts[setting_name]);\n });\n}\n\nonOptionsChanged(onOptionsChangedCallback);\n\nexport async function initModels() {\n const warn = () => `\n

    No models available

    \n - Select a model from reference list to download or
    \n - Set model path to a folder containing your models
    \n Current model path: ${opts.ckpt_dir}
    \n `;\n const el = gradioApp().getElementById('main_info');\n const en = gradioApp().getElementById('txt2img_extra_networks');\n if (!el || !en) return;\n const req = await authFetch(`${window.api}/sd-models`);\n const res = (req && req.ok) ? await req.json() : [];\n log('initModels', res.length);\n const ready = () => `\n

    Ready

    \n ${res.length} models available
    \n `;\n el.innerHTML = res.length > 0 ? ready() : warn();\n el.style.display = 'block';\n setTimeout(() => { el.style.display = 'none'; }, res.length === 0 ? 30000 : 1500);\n if (res.length === 0) {\n if (en.classList.contains('hide')) gradioApp().getElementById('txt2img_extra_networks_btn').click();\n const repeat = setInterval(() => {\n const buttons = Array.from(gradioApp().querySelectorAll('#txt2img_model_subdirs > button')) || [];\n const reference = buttons.find((b) => (b.innerText === 'Reference') || (b.innerText === 'Distilled') || (b.innerText === 'Community') || (b.innerText === 'Quantized') || (b.innerText === 'Cloud'));\n if (reference) {\n clearInterval(repeat);\n reference.click();\n log('enReferenceSelect');\n }\n }, 100);\n }\n}\n\nexport async function initSettings() {\n if (settingsInitialized) return;\n const t0 = performance.now();\n settingsInitialized = true;\n const tabNavElements = gradioApp().querySelector('#settings > .tab-nav');\n if (!tabNavElements) {\n error('initSettings', 'No tab nav elements found');\n return;\n }\n const tabNavButtons = gradioApp().querySelectorAll('#settings > .tab-nav > button');\n const tabElements = gradioApp().querySelectorAll('#settings > div:not(.tab-nav)');\n const observer = new MutationObserver((mutations) => {\n const showAllPages = gradioApp().getElementById('settings_show_all_pages');\n if (showAllPages.style.display === 'none') return;\n const mutation = (mut) => mut.type === 'attributes' && mut.attributeName === 'style';\n if (mutations.some(mutation)) showAllSettings();\n });\n const tabContentWrapper = document.createElement('div');\n tabContentWrapper.className = 'tab-content';\n tabNavElements.parentElement.insertBefore(tabContentWrapper, tabNavElements.nextSibling);\n tabElements.forEach((elem, index) => {\n const tabName = elem.id.replace('settings_section_tab_', '');\n const indicator = gradioApp().getElementById(`modification_indicator_${tabName}`);\n if (indicator) {\n tabNavElements.insertBefore(document.createElement('br'), tabNavButtons[index]);\n tabNavElements.insertBefore(indicator, tabNavButtons[index]);\n }\n tabContentWrapper.appendChild(elem);\n observer.observe(elem, { attributes: true, attributeFilter: ['style'] });\n });\n const t1 = performance.now();\n log('initSettings', Math.round(t1 - t0));\n timer('initSettings', t1 - t0);\n}\n", "import { debug, log } from './logger';\nimport { authFetch } from './authWrap';\nimport { monitorOption } from './settings';\n\ninterface VersionInfo {\n updated?: string;\n commit?: string;\n branch?: string;\n model?: string;\n}\n\nlet monitorActive = false;\nlet wsTimer: ReturnType | undefined;\n\nexport class ConnectionMonitorState {\n static ws: WebSocket | undefined;\n static url = '';\n static delay = 2000;\n static element: HTMLElement | undefined;\n static version = '';\n static commit = '';\n static branch = '';\n static model = '';\n static startup: Date = new Date();\n static online = false;\n static ts: Date = new Date();\n\n static getModel(): string {\n const cp = window.opts?.sd_model_checkpoint || '';\n return cp ? this.trimModelName(cp) : 'unknown model';\n }\n\n static trimModelName(name: string): string {\n return name.replace(/\\s*\\[.*\\]\\s*$/, '').split(/[\\\\/]/).pop().trim() || 'unknown model';\n }\n\n static setData({ online, data }: { online: boolean; data: VersionInfo }) {\n if (online !== this.online) {\n this.online = online;\n this.ts = new Date();\n debug('monitorState', { online: ConnectionMonitorState.online, ts: ConnectionMonitorState.ts?.toLocaleTimeString() });\n }\n if (data?.updated) this.version = data.updated;\n if (data?.commit) this.commit = data.commit;\n if (data?.branch) this.branch = data.branch;\n if (data?.model) this.model = this.trimModelName(data.model);\n }\n\n static toHTML(): string {\n if (!this.model) this.model = this.getModel();\n return `\n Version: ${this.version}
    \n Commit: ${this.commit}
    \n Branch: ${this.branch}
    \n Status: ${this.online ? 'online' : 'offline'}
    \n Model: ${this.model}
    \n Since: ${this.startup.toLocaleString()}
    \n `;\n }\n\n static updateState() {\n if (!this.element) {\n const el = document.getElementById('logo_nav');\n if (el) this.element = el;\n else return;\n }\n this.element.dataset.hint = this.toHTML();\n this.element.style.background = this.online ? 'var(--sd-main-accent-color)' : 'var(--color-error)';\n }\n}\n\nasync function updateIndicator(online: boolean, data: VersionInfo = {}, msg?: string): Promise {\n ConnectionMonitorState.setData({ online, data });\n ConnectionMonitorState.updateState();\n if (msg) log('monitorConnection:', { online, data, msg });\n}\n\nfunction scheduleNextLoop() {\n if (wsTimer) {\n clearTimeout(wsTimer);\n wsTimer = undefined;\n }\n const offlineDurationMs = Date.now() - ConnectionMonitorState.ts.getTime();\n if (!ConnectionMonitorState.online && offlineDurationMs > (60 * 60 * 1000)) ConnectionMonitorState.delay = 10000;\n else if (!ConnectionMonitorState.online && offlineDurationMs > (5 * 60 * 1000)) ConnectionMonitorState.delay = 5000;\n else ConnectionMonitorState.delay = 1000;\n wsTimer = setTimeout(wsMonitorLoop, ConnectionMonitorState.delay); // eslint-disable-line @typescript-eslint/no-use-before-define\n}\n\nasync function wsMonitorLoop() {\n // Tear down any existing socket before creating a new one\n if (ConnectionMonitorState.ws) {\n ConnectionMonitorState.ws.onopen = null;\n ConnectionMonitorState.ws.onmessage = null;\n ConnectionMonitorState.ws.onclose = null;\n ConnectionMonitorState.ws.onerror = null;\n try {\n ConnectionMonitorState.ws.close();\n } catch {\n // Ignore cleanup errors on stale sockets\n }\n ConnectionMonitorState.ws = undefined;\n }\n\n try {\n ConnectionMonitorState.ws = new WebSocket(`${ConnectionMonitorState.url}/internal/monitor`);\n ConnectionMonitorState.ws.onopen = () => updateIndicator(true);\n ConnectionMonitorState.ws.onmessage = (msg: MessageEvent) => updateIndicator(true, msg.data ? JSON.parse(msg.data) : {});\n ConnectionMonitorState.ws.onclose = () => {\n updateIndicator(false);\n scheduleNextLoop();\n };\n ConnectionMonitorState.ws.onerror = (e: Event) => updateIndicator(false, {}, String((e as ErrorEvent).message || 'unknown error'));\n } catch (e) {\n updateIndicator(false, {}, String((e as Error).message || e));\n scheduleNextLoop();\n }\n}\n\nexport async function monitorConnection() {\n if (!monitorActive) { // start monitor loop only once on startup\n monitorActive = true;\n monitorOption('sd_model_checkpoint', (newVal) => { // runs before opt actually changes\n ConnectionMonitorState.model = newVal;\n ConnectionMonitorState.updateState();\n });\n }\n ConnectionMonitorState.startup = new Date();\n\n let data: VersionInfo = {};\n try {\n const res = await authFetch(`${window.api}/version`);\n if (!res) throw new Error('No response');\n data = await res.json();\n log('monitorConnection:', { data });\n ConnectionMonitorState.startup = new Date();\n ConnectionMonitorState.url = res.url.split('/sdapi')[0].replace('https:', 'wss:').replace('http:', 'ws:'); // update global url as ws need fqdn\n updateIndicator(true, data);\n wsMonitorLoop();\n } catch {\n updateIndicator(false, data);\n scheduleNextLoop();\n }\n}\n", "// Stable Diffusion WebUI - Bracket checker\n// By Hingashi no Florin/Bwin4L & @akx\n// Counts open and closed brackets (round, square, curly) in the prompt and negative prompt text boxes in the txt2img and img2img tabs.\n// If there's a mismatch, the keyword counter turns red and if you hover on it, a tooltip tells you what's wrong.\n\nimport { gradioApp } from './script';\nimport { log } from './logger';\nimport { timer } from './timers';\n\nfunction checkBrackets(textArea: HTMLTextAreaElement, counterElt: HTMLElement): void {\n const counts: Record = {};\n const errors: string[] = [];\n\n function checkPair(open: string, close: string, kind: string): void {\n if (counts[open] !== counts[close]) errors.push(`${open}...${close} - Detected ${counts[open] || 0} opening and ${counts[close] || 0} closing ${kind}.`);\n }\n\n (textArea.value.match(/[(){}[\\]]/g) || []).forEach((bracket) => { counts[bracket] = (counts[bracket] || 0) + 1; });\n checkPair('(', ')', 'round brackets');\n checkPair('[', ']', 'square brackets');\n checkPair('{', '}', 'curly brackets');\n counterElt.title = errors.join('\\n');\n counterElt.classList.toggle('error', errors.length !== 0);\n}\n\nfunction setupBracketChecking(idPrompt: string, idCounter: string): void {\n const textarea = gradioApp().querySelector(`#${idPrompt} > label > textarea`);\n const counter = gradioApp().getElementById(idCounter);\n if (!(textarea instanceof HTMLTextAreaElement) || !counter) return;\n textarea.addEventListener('input', () => checkBrackets(textarea, counter));\n}\n\nexport async function initPromptChecker() {\n const t0 = performance.now();\n setupBracketChecking('txt2img_prompt', 'txt2img_token_counter');\n setupBracketChecking('txt2img_neg_prompt', 'txt2img_negative_token_counter');\n setupBracketChecking('img2img_prompt', 'img2img_token_counter');\n setupBracketChecking('img2img_neg_prompt', 'img2img_negative_token_counter');\n setupBracketChecking('control_prompt', 'control_token_counter');\n setupBracketChecking('control_neg_prompt', 'control_negative_token_counter');\n setupBracketChecking('video_prompt', 'video_token_counter');\n setupBracketChecking('video_neg_prompt', 'video_negative_token_counter');\n const t1 = performance.now();\n log('initPromptChecker', Math.round(t1 - t0));\n timer('initPromptChecker', t1 - t0);\n}\n", "// @ts-nocheck\n\n// SHA-256 (+ HMAC and PBKDF2) for JavaScript.\n//\n// Written in 2014-2016 by Dmitry Chestnykh.\n// Public domain, no warranty.\n//\n// Functions (accept and return Uint8Arrays):\n//\n// sha256(message) -> hash\n// sha256.hmac(key, message) -> mac\n// sha256.pbkdf2(password, salt, rounds, dkLen) -> dk\n//\n// Classes:\n//\n// new sha256.Hash()\n// new sha256.HMAC(key)\n//\n\n\nconst digestLength = 32;\nconst blockSize = 64;\n\n// SHA-256 constants\n\nconst K = new Uint32Array([\n 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b,\n 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01,\n 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7,\n 0xc19bf174, 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,\n 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 0x983e5152,\n 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147,\n 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc,\n 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,\n 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819,\n 0xd6990624, 0xf40e3585, 0x106aa070, 0x19a4c116, 0x1e376c08,\n 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f,\n 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,\n 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2,\n]);\nfunction hashBlocks(w, v, p, pos, len) {\n let a; let b; let c; let d; let e; let f; let g; let h; let u; let i; let j; let t1; let\n t2;\n while (len >= 64) {\n a = v[0];\n b = v[1];\n c = v[2];\n d = v[3];\n e = v[4];\n f = v[5];\n g = v[6];\n h = v[7];\n for (i = 0; i < 16; i++) {\n j = pos + i * 4;\n w[i] = (((p[j] & 0xff) << 24) | ((p[j + 1] & 0xff) << 16)\n | ((p[j + 2] & 0xff) << 8) | (p[j + 3] & 0xff));\n }\n for (i = 16; i < 64; i++) {\n u = w[i - 2];\n t1 = (u >>> 17 | u << (32 - 17)) ^ (u >>> 19 | u << (32 - 19)) ^ (u >>> 10);\n u = w[i - 15];\n t2 = (u >>> 7 | u << (32 - 7)) ^ (u >>> 18 | u << (32 - 18)) ^ (u >>> 3);\n w[i] = (t1 + w[i - 7] | 0) + (t2 + w[i - 16] | 0);\n }\n for (i = 0; i < 64; i++) {\n t1 = (((((e >>> 6 | e << (32 - 6)) ^ (e >>> 11 | e << (32 - 11))\n ^ (e >>> 25 | e << (32 - 25))) + ((e & f) ^ (~e & g))) | 0)\n + ((h + ((K[i] + w[i]) | 0)) | 0)) | 0;\n t2 = (((a >>> 2 | a << (32 - 2)) ^ (a >>> 13 | a << (32 - 13))\n ^ (a >>> 22 | a << (32 - 22))) + ((a & b) ^ (a & c) ^ (b & c))) | 0;\n h = g;\n g = f;\n f = e;\n e = (d + t1) | 0;\n d = c;\n c = b;\n b = a;\n a = (t1 + t2) | 0;\n }\n v[0] += a;\n v[1] += b;\n v[2] += c;\n v[3] += d;\n v[4] += e;\n v[5] += f;\n v[6] += g;\n v[7] += h;\n pos += 64;\n len -= 64;\n }\n return pos;\n}\n// Hash implements SHA256 hash algorithm.\nconst Hash = /** @class */ (function () {\n function Hash() {\n this.digestLength = digestLength;\n this.blockSize = blockSize;\n // Note: Int32Array is used instead of Uint32Array for performance reasons.\n this.state = new Int32Array(8); // hash state\n this.temp = new Int32Array(64); // temporary state\n this.buffer = new Uint8Array(128); // buffer for data to hash\n this.bufferLength = 0; // number of bytes in buffer\n this.bytesHashed = 0; // number of total bytes hashed\n this.finished = false; // indicates whether the hash was finalized\n this.reset();\n }\n // Resets hash state making it possible\n // to reuse this instance to hash other data.\n Hash.prototype.reset = function () {\n this.state[0] = 0x6a09e667;\n this.state[1] = 0xbb67ae85;\n this.state[2] = 0x3c6ef372;\n this.state[3] = 0xa54ff53a;\n this.state[4] = 0x510e527f;\n this.state[5] = 0x9b05688c;\n this.state[6] = 0x1f83d9ab;\n this.state[7] = 0x5be0cd19;\n this.bufferLength = 0;\n this.bytesHashed = 0;\n this.finished = false;\n return this;\n };\n // Cleans internal buffers and re-initializes hash state.\n Hash.prototype.clean = function () {\n for (var i = 0; i < this.buffer.length; i++) {\n this.buffer[i] = 0;\n }\n for (var i = 0; i < this.temp.length; i++) {\n this.temp[i] = 0;\n }\n this.reset();\n };\n // Updates hash state with the given data.\n //\n // Optionally, length of the data can be specified to hash\n // fewer bytes than data.length.\n //\n // Throws error when trying to update already finalized hash:\n // instance must be reset to use it again.\n Hash.prototype.update = function (data, dataLength) {\n if (dataLength === void 0) { dataLength = data.length; }\n if (this.finished) {\n throw new Error(\"SHA256: can't update because hash was finished.\");\n }\n let dataPos = 0;\n this.bytesHashed += dataLength;\n if (this.bufferLength > 0) {\n while (this.bufferLength < 64 && dataLength > 0) {\n this.buffer[this.bufferLength++] = data[dataPos++];\n dataLength--;\n }\n if (this.bufferLength === 64) {\n hashBlocks(this.temp, this.state, this.buffer, 0, 64);\n this.bufferLength = 0;\n }\n }\n if (dataLength >= 64) {\n dataPos = hashBlocks(this.temp, this.state, data, dataPos, dataLength);\n dataLength %= 64;\n }\n while (dataLength > 0) {\n this.buffer[this.bufferLength++] = data[dataPos++];\n dataLength--;\n }\n return this;\n };\n // Finalizes hash state and puts hash into out.\n //\n // If hash was already finalized, puts the same value.\n Hash.prototype.finish = function (out) {\n if (!this.finished) {\n const bytesHashed = this.bytesHashed;\n const left = this.bufferLength;\n const bitLenHi = (bytesHashed / 0x20000000) | 0;\n const bitLenLo = bytesHashed << 3;\n const padLength = (bytesHashed % 64 < 56) ? 64 : 128;\n this.buffer[left] = 0x80;\n for (let i = left + 1; i < padLength - 8; i++) {\n this.buffer[i] = 0;\n }\n this.buffer[padLength - 8] = (bitLenHi >>> 24) & 0xff;\n this.buffer[padLength - 7] = (bitLenHi >>> 16) & 0xff;\n this.buffer[padLength - 6] = (bitLenHi >>> 8) & 0xff;\n this.buffer[padLength - 5] = (bitLenHi >>> 0) & 0xff;\n this.buffer[padLength - 4] = (bitLenLo >>> 24) & 0xff;\n this.buffer[padLength - 3] = (bitLenLo >>> 16) & 0xff;\n this.buffer[padLength - 2] = (bitLenLo >>> 8) & 0xff;\n this.buffer[padLength - 1] = (bitLenLo >>> 0) & 0xff;\n hashBlocks(this.temp, this.state, this.buffer, 0, padLength);\n this.finished = true;\n }\n for (let i = 0; i < 8; i++) {\n out[i * 4 + 0] = (this.state[i] >>> 24) & 0xff;\n out[i * 4 + 1] = (this.state[i] >>> 16) & 0xff;\n out[i * 4 + 2] = (this.state[i] >>> 8) & 0xff;\n out[i * 4 + 3] = (this.state[i] >>> 0) & 0xff;\n }\n return this;\n };\n // Returns the final hash digest.\n Hash.prototype.digest = function () {\n const out = new Uint8Array(this.digestLength);\n this.finish(out);\n return out;\n };\n // Internal function for use in HMAC for optimization.\n Hash.prototype._saveState = function (out) {\n for (let i = 0; i < this.state.length; i++) {\n out[i] = this.state[i];\n }\n };\n // Internal function for use in HMAC for optimization.\n Hash.prototype._restoreState = function (from, bytesHashed) {\n for (let i = 0; i < this.state.length; i++) {\n this.state[i] = from[i];\n }\n this.bytesHashed = bytesHashed;\n this.finished = false;\n this.bufferLength = 0;\n };\n return Hash;\n}());\nwindow.Hash = Hash;\n// HMAC implements HMAC-SHA256 message authentication algorithm.\nconst HMAC = /** @class */ (function () {\n function HMAC(key) {\n this.inner = new Hash();\n this.outer = new Hash();\n this.blockSize = this.inner.blockSize;\n this.digestLength = this.inner.digestLength;\n const pad = new Uint8Array(this.blockSize);\n if (key.length > this.blockSize) {\n (new Hash()).update(key).finish(pad).clean();\n } else {\n for (let i = 0; i < key.length; i++) {\n pad[i] = key[i];\n }\n }\n for (let i = 0; i < pad.length; i++) {\n pad[i] ^= 0x36;\n }\n this.inner.update(pad);\n for (let i = 0; i < pad.length; i++) {\n pad[i] ^= 0x36 ^ 0x5c;\n }\n this.outer.update(pad);\n this.istate = new Uint32Array(8);\n this.ostate = new Uint32Array(8);\n this.inner._saveState(this.istate);\n this.outer._saveState(this.ostate);\n for (let i = 0; i < pad.length; i++) {\n pad[i] = 0;\n }\n }\n // Returns HMAC state to the state initialized with key\n // to make it possible to run HMAC over the other data with the same\n // key without creating a new instance.\n HMAC.prototype.reset = function () {\n this.inner._restoreState(this.istate, this.inner.blockSize);\n this.outer._restoreState(this.ostate, this.outer.blockSize);\n return this;\n };\n // Cleans HMAC state.\n HMAC.prototype.clean = function () {\n for (let i = 0; i < this.istate.length; i++) {\n this.ostate[i] = this.istate[i] = 0;\n }\n this.inner.clean();\n this.outer.clean();\n };\n // Updates state with provided data.\n HMAC.prototype.update = function (data) {\n this.inner.update(data);\n return this;\n };\n // Finalizes HMAC and puts the result in out.\n HMAC.prototype.finish = function (out) {\n if (this.outer.finished) {\n this.outer.finish(out);\n } else {\n this.inner.finish(out);\n this.outer.update(out, this.digestLength).finish(out);\n }\n return this;\n };\n // Returns message authentication code.\n HMAC.prototype.digest = function () {\n const out = new Uint8Array(this.digestLength);\n this.finish(out);\n return out;\n };\n return HMAC;\n}());\nwindow.HMAC = HMAC;\n// Returns SHA256 hash of data.\nfunction hash(data) {\n const h = (new Hash()).update(data);\n const digest = h.digest();\n h.clean();\n return digest;\n}\nwindow.hash = hash;\n// Function hash is both available as module.hash and as default export.\n// Returns HMAC-SHA256 of data under the key.\nfunction hmac(key, data) {\n const h = (new HMAC(key)).update(data);\n const digest = h.digest();\n h.clean();\n return digest;\n}\nwindow.hmac = hmac;\n// Fills hkdf buffer like this:\n// T(1) = HMAC-Hash(PRK, T(0) | info | 0x01)\nfunction fillBuffer(buffer, hmac, info, counter) {\n // Counter is a byte value: check if it overflowed.\n const num = counter[0];\n if (num === 0) {\n throw new Error('hkdf: cannot expand more');\n }\n // Prepare HMAC instance for new data with old key.\n hmac.reset();\n // Hash in previous output if it was generated\n // (i.e. counter is greater than 1).\n if (num > 1) {\n hmac.update(buffer);\n }\n // Hash in info if it exists.\n if (info) {\n hmac.update(info);\n }\n // Hash in the counter.\n hmac.update(counter);\n // Output result to buffer and clean HMAC instance.\n hmac.finish(buffer);\n // Increment counter inside typed array, this works properly.\n counter[0]++;\n}\nconst hkdfSalt = new Uint8Array(digestLength); // Filled with zeroes.\nfunction hkdf(key, salt, info, length) {\n if (salt === void 0) { salt = hkdfSalt; }\n if (length === void 0) { length = 32; }\n const counter = new Uint8Array([1]);\n // HKDF-Extract uses salt as HMAC key, and key as data.\n const okm = hmac(salt, key);\n // Initialize HMAC for expanding with extracted key.\n // Ensure no collisions with `hmac` function.\n const hmac_ = new HMAC(okm);\n // Allocate buffer.\n const buffer = new Uint8Array(hmac_.digestLength);\n let bufpos = buffer.length;\n const out = new Uint8Array(length);\n for (let i = 0; i < length; i++) {\n if (bufpos === buffer.length) {\n fillBuffer(buffer, hmac_, info, counter);\n bufpos = 0;\n }\n out[i] = buffer[bufpos++];\n }\n hmac_.clean();\n buffer.fill(0);\n counter.fill(0);\n return out;\n}\nwindow.hkdf = hkdf;\n// Derives a key from password and salt using PBKDF2-HMAC-SHA256\n// with the given number of iterations.\n//\n// The number of bytes returned is equal to dkLen.\n//\n// (For better security, avoid dkLen greater than hash length - 32 bytes).\nfunction pbkdf2(password, salt, iterations, dkLen) {\n const prf = new HMAC(password);\n const len = prf.digestLength;\n const ctr = new Uint8Array(4);\n const t = new Uint8Array(len);\n const u = new Uint8Array(len);\n const dk = new Uint8Array(dkLen);\n for (var i = 0; i * len < dkLen; i++) {\n const c = i + 1;\n ctr[0] = (c >>> 24) & 0xff;\n ctr[1] = (c >>> 16) & 0xff;\n ctr[2] = (c >>> 8) & 0xff;\n ctr[3] = (c >>> 0) & 0xff;\n prf.reset();\n prf.update(salt);\n prf.update(ctr);\n prf.finish(u);\n for (var j = 0; j < len; j++) {\n t[j] = u[j];\n }\n for (var j = 2; j <= iterations; j++) {\n prf.reset();\n prf.update(u).finish(u);\n for (let k = 0; k < len; k++) {\n t[k] ^= u[k];\n }\n }\n for (var j = 0; j < len && i * len + j < dkLen; j++) {\n dk[i * len + j] = t[j];\n }\n }\n for (var i = 0; i < len; i++) {\n t[i] = u[i] = 0;\n }\n for (var i = 0; i < 4; i++) {\n ctr[i] = 0;\n }\n prf.clean();\n return dk;\n}\nwindow.pbkdf2 = pbkdf2;\n", "/* eslint-disable max-classes-per-file, @typescript-eslint/no-use-before-define */\nimport './js/sha256';\nimport { log, debug, error } from './logger';\nimport { authFetch } from './authWrap';\nimport { gradioApp, onAfterUiUpdate } from './script';\nimport { timer } from './timers';\nimport { monitorOption } from './settings';\n\nimport {\n idbAdd,\n idbCount,\n idbFolderCleanup,\n idbClearAll,\n idbGet,\n idbKeys,\n idbIsReady,\n} from './indexdb';\n\nlet ws;\nlet url;\nlet currentSize = 0;\nlet currentSort = 'none';\nlet currentName = '';\nlet currentImage = null;\nlet currentTitle = '';\nlet currentGalleryFolder = null;\nlet pruneImagesTimer;\nlet outstanding = 0;\nlet gallerySelection = { files: [], index: -1 };\nlet maintenanceController = new AbortController();\nconst maxFetchRequests = 32;\nconst fragmentSize = 100;\nconst minCleanupCount = 1000;\nconst minCleanupTime = 1000 * 60 * 60; // 1 hour\nconst folderStylesheet = new CSSStyleSheet();\nconst fileStylesheet = new CSSStyleSheet();\nlet galleryInitialized = false;\n// Store separator states for the session\nconst separatorStates = new Map();\nconst el = {\n folders: undefined,\n files: undefined,\n search: undefined,\n status: undefined,\n btnSend: undefined,\n overlay: undefined,\n size: undefined,\n};\nconst cleanupTimers = {};\nconst maintenanceTimers = {};\nconst fetchQueue = [];\nconst icons = {\n Time: String.fromCodePoint(9201),\n Folder: String.fromCodePoint(128448), // or 128449;\n Sort: String.fromCodePoint(8645),\n Images: String.fromCodePoint(128461),\n};\n// eslint-disable-next-line @stylistic/max-len, @stylistic/quotes\nconst loadingSvg = `data:image/svg+xml;utf8,`;\n\nconst SUPPORTED_EXTENSIONS = ['jpg', 'jpeg', 'png', 'webp', 'tiff', 'jp2', 'jxl', 'gif', 'mp4', 'mkv', 'avi', 'mjpeg', 'mpg', 'avr', 'heif', 'heic', 'mov', 'ts'];\n\nconst gallerySorter = {\n nameA: { name: 'Name Ascending', func: (a, b) => a.name.localeCompare(b.name) },\n nameD: { name: 'Name Descending', func: (b, a) => a.name.localeCompare(b.name) },\n sizeD: { name: 'Size Ascending', func: (a, b) => a.size - b.size },\n sizeA: { name: 'Size Descending', func: (b, a) => a.size - b.size },\n resD: { name: 'Resolution Ascending', func: (a, b) => a.width * a.height - b.width * b.height },\n resA: { name: 'Resolution Descending', func: (b, a) => a.width * a.height - b.width * b.height },\n modD: { name: 'Modified Ascending', func: (a, b) => a.mtime - b.mtime },\n modA: { name: 'Modified Descending', func: (b, a) => a.mtime - b.mtime },\n none: { name: 'None', func: undefined },\n};\nconst folderSorter = {\n nameA: { name: 'Name Ascending', func: (a, b) => a.name.localeCompare(b.name) },\n nameD: { name: 'Name Descending', func: (b, a) => a.name.localeCompare(b.name) },\n sizeD: { name: 'Size Ascending', func: (a, b) => a.size - b.size },\n sizeA: { name: 'Size Descending', func: (b, a) => a.size - b.size },\n resD: { name: 'Resolution Ascending', func: (a, b) => a.width * a.height - b.width * b.height },\n resA: { name: 'Resolution Descending', func: (b, a) => a.width * a.height - b.width * b.height },\n modD: { name: 'Modified Ascending', func: (a, b) => a.mtime - b.mtime },\n modA: { name: 'Modified Descending', func: (b, a) => a.mtime - b.mtime },\n none: { name: 'None', func: undefined },\n};\n\nlet sortMode = gallerySorter.none;\n\nasync function getHash(str) {\n let hex = '';\n const strBuf = new TextEncoder().encode(str);\n let hashBuf;\n if (crypto?.subtle?.digest) {\n hashBuf = await crypto.subtle.digest('SHA-256', strBuf);\n } else {\n const hashResult: any = hash(strBuf);\n hashBuf = hashResult.buffer; // from sha256.js\n }\n const view = new DataView(hashBuf);\n for (let i = 0; i < hashBuf.byteLength; i += 4) hex += (`00000000${view.getUint32(i).toString(16)}`).slice(-8);\n return hex;\n}\n\nfunction getVisibleGalleryFiles() {\n if (!el.files) return [];\n return Array.from(el.files.children).filter((node) => node.name && node.offsetParent);\n}\n\nfunction updateGallerySelectionClasses(files = gallerySelection.files, index = gallerySelection.index) {\n files.forEach((file, i) => {\n file.classList.toggle('gallery-file-selected', i === index);\n });\n}\n\nfunction refreshGallerySelection() {\n updateGallerySelectionClasses(gallerySelection.files, -1);\n const files = getVisibleGalleryFiles();\n const index = files.findIndex((file) => file.src === currentImage);\n gallerySelection = { files, index };\n updateGallerySelectionClasses(files, index);\n}\n\nfunction resetGallerySelection() {\n updateGallerySelectionClasses(gallerySelection.files, -1);\n gallerySelection = { files: [], index: -1 };\n currentImage = null;\n currentName = '';\n currentTitle = '';\n}\n\nfunction applyGallerySelection(index, { send = true } = {}) {\n if (!gallerySelection.files.length) refreshGallerySelection();\n const { files } = gallerySelection;\n if (!files.length) return;\n if (!Number.isInteger(index) || index < 0 || index >= files.length) {\n log('gallery selection index out of range', index, files.length);\n resetGallerySelection();\n return;\n }\n gallerySelection.index = index;\n currentImage = files[index].src;\n currentName = files[index].name;\n currentTitle = files[index].title;\n updateGallerySelectionClasses(files, index);\n if (send && el.btnSend) el.btnSend.click();\n}\n\nfunction setGallerySelectionByElement(element, options) {\n if (!gallerySelection.files.length) refreshGallerySelection();\n let index = gallerySelection.files.findIndex((file) => file === element);\n if (index < 0) {\n refreshGallerySelection();\n index = gallerySelection.files.findIndex((file) => file === element);\n }\n if (index >= 0) applyGallerySelection(index, options);\n}\n\nfunction buildGalleryFileUrl(path) {\n return new URL(`/file=${encodeURI(path)}`, window.location.origin).toString();\n}\n\nwindow.getGallerySelection = () => ({ index: gallerySelection.index, files: gallerySelection.files });\nwindow.setGallerySelection = (index, options) => applyGallerySelection(index, options);\nwindow.getGallerySelectedUrl = () => (currentImage ? buildGalleryFileUrl(currentImage) : null);\n\n/**\n * Wait for gallery to finish populating\n * @param {number} expectedSize - Expected gallery size\n * @param {AbortSignal} signal - AbortController signal\n */\nasync function awaitForGallery(expectedSize, signal) {\n while (Math.max(galleryHashes.size, galleryHashes.fallback) < expectedSize && !signal.aborted) await new Promise((resolve) => { setTimeout(resolve, 500); }); // longer interval because it's a low priority check\n signal.throwIfAborted();\n}\n\nfunction updateGalleryStyles() {\n if (opts.theme_type?.toLowerCase() === 'modern') {\n folderStylesheet.replace(`\n .gallery-folder {\n cursor: pointer;\n padding: 8px 6px 8px 6px;\n background-color: var(--sd-button-normal-color);\n border-radius: var(--sd-border-radius);\n text-align: left;\n direction: rtl; /* Used to overflow the beginning instead of the end */\n min-width: 12em;\n max-width: 100%;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n transition-duration: 0.2s;\n transition-property: color, opacity, background-color, border-color;\n transition-timing-function: ease-out;\n }\n .gallery-folder:hover {\n background-color: var(--button-primary-background-fill-hover, var(--sd-button-hover-color));\n }\n .gallery-folder-selected {\n background-color: var(--sd-button-selected-color);\n color: var(--sd-button-selected-text-color);\n }\n .gallery-folder-icon {\n font-size: 1.2em;\n color: var(--sd-button-icon-color);\n margin-right: 1em;\n filter: drop-shadow(1px 1px 2px black);\n float: left;\n }\n `);\n } else {\n folderStylesheet.replace(`\n .gallery-folder {\n cursor: pointer;\n padding: 8px 6px 8px 6px;\n max-width: 200px;\n overflow-x: hidden;\n text-wrap: nowrap;\n text-overflow: ellipsis;\n }\n .gallery-folder:hover {\n background-color: var(--button-primary-background-fill-hover);\n }\n .gallery-folder-selected {\n background-color: var(--button-primary-background-fill);\n }\n `);\n }\n const size = el.size ? el.size.value : opts.extra_networks_card_size;\n fileStylesheet.replace(`\n .gallery-file {\n object-fit: contain;\n cursor: pointer;\n height: ${size}px;\n width: ${opts.browser_fixed_width ? `${size}px` : 'unset'};\n }\n .gallery-file:hover {\n filter: grayscale(100%);\n }\n .gallery-overlay {\n position: absolute;\n height: 24px;\n background-color: rgba(0,0,0,0.7);\n display: block;\n text-align: right;\n padding: 4px;\n font-size: 1.2em;\n letter-spacing: 0.5em;\n margin-top: calc(140px - 32px);\n opacity: 75%;\n border-radius: var(--sd-border-radius);\n }\n :host(.gallery-file-selected) .gallery-file {\n box-shadow: 0 0 0 2px var(--sd-button-selected-color);\n }\n `);\n}\n\n// Classes\n\nclass HashSet extends Set {\n fallback = 0;\n constructor(val?: any) {\n super(val);\n this.fallback = 0;\n }\n\n override add(value: any): this {\n ++this.fallback;\n super.add(value);\n return this;\n }\n\n override clear(): void {\n this.fallback = 0;\n super.clear();\n }\n}\n\nconst galleryHashes = new HashSet();\n\nclass SimpleProgressBar {\n #container = document.createElement('div');\n #progress = document.createElement('div');\n #textDiv = document.createElement('div');\n #text = document.createElement('span');\n #visible = false;\n #interval: ReturnType | undefined;\n #max = 0;\n defaultStats = { queue: 0, fetch: 0, hash: 0, db: 0, cached: 0, fetched: 0, failed: 0, error: 0, callback: 0, elapsed: 0, count: 0 };\n stats = { ...this.defaultStats };\n /** @type {Set} */\n #monitoredSet;\n\n constructor(monitoredSet) {\n this.#monitoredSet = monitoredSet; // This is required because incrementing a variable with a class method turned out to not be an atomic operation\n 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;';\n this.#progress.style.cssText = 'position:absolute; left:0; height:100%; width:0; transition:width 200ms;';\n this.#progress.style.backgroundColor = 'var(--sd-main-accent-color)';\n this.#textDiv.style.cssText = 'position:relative; margin:auto; width:max-content; height:100%;';\n this.#text.style.cssText = 'user-select:none; color:white;';\n this.#textDiv.append(this.#text);\n this.#container.append(this.#progress, this.#textDiv);\n }\n\n start(total) {\n if (total <= 0) return;\n this.hide();\n this.#max = total;\n if (this.#monitoredSet.size >= this.#max) {\n this.stop();\n return;\n }\n this.#interval = setInterval(() => this.update(this.#monitoredSet.size, this.#max), 100);\n }\n\n attachTo(element) {\n if (element.hasChildNodes) element.innerHTML = '';\n element.appendChild(this.#container);\n }\n\n hide() {\n this.#container.style.display = 'none';\n this.#visible = false;\n this.#progress.style.width = '0';\n this.#text.textContent = '';\n }\n\n update(loaded, max) {\n // log('galleryUpdate', { loaded, max });\n this.#progress.style.width = `${Math.floor((loaded / max) * 100)}%`;\n this.#text.textContent = `${loaded}/${max}`;\n if (!this.#visible) {\n this.#container.style.display = 'block';\n this.#visible = true;\n }\n if (loaded >= max) this.stop();\n }\n\n stop() {\n clearInterval(this.#interval);\n // this.#interval = undefined;\n if (this.stats.count) {\n debug('gallery: thumbnail stats', this.stats);\n this.stats = { ...this.defaultStats };\n }\n setTimeout(() => this.hide(), 100);\n }\n}\n\nconst pb = new SimpleProgressBar(galleryHashes);\n\n/* This isn't as robust as the Web Locks API, but it will at least work if accessing a remote machine without HTTPS */\nclass SimpleFunctionQueue {\n #id;\n #running;\n #queue;\n\n constructor(id) {\n this.#id = id;\n this.#running = false;\n this.#queue = [];\n }\n\n static abortLogger(identifier, result) {\n if (typeof result === 'string' || (result instanceof DOMException && result.name === 'AbortError')) {\n log(identifier, typeof result === 'object' && result !== null ? (result as any).message || result : result);\n } else {\n error(identifier, result.message);\n }\n }\n\n /**\n * @param {{\n * signal: AbortSignal,\n * callback: Function\n * }} config\n */\n enqueue(config) {\n if (!(config.signal instanceof AbortSignal) || typeof config.callback !== 'function') {\n throw new Error('Invalid configuration. Object must contain an AbortSignal and a function');\n }\n if (config.signal.aborted) {\n debug(`${this.#id} Queue: Skipping addition to queue due to \"${config.signal.reason}\"`);\n return;\n }\n this.#queue.push(config);\n this.#tryRunNext();\n }\n\n async #tryRunNext() {\n if (this.#running || !this.#queue.length) return;\n try {\n const { signal, callback } = this.#queue.shift();\n if (signal.aborted) {\n return;\n }\n this.#running = true;\n if (callback.constructor.name.toLowerCase() === 'asyncfunction') {\n await callback();\n } else {\n callback();\n }\n } catch (err) {\n error(`${this.#id} Queue:`, err);\n } finally {\n this.#running = false;\n this.#tryRunNext();\n }\n }\n}\n\n// HTML Elements\n\nclass GalleryFolder extends HTMLElement {\n static folders = new Set();\n /** @type {GalleryFolder | null} */\n static #active = null;\n\n constructor(folder) {\n super();\n // Support both old format (string) and new format (object with path and label)\n if (typeof folder === 'object' && folder !== null) {\n this.name = decodeURI(folder.path || '');\n this.label = decodeURI(folder.label || folder.path || '');\n } else {\n this.name = decodeURI(folder);\n this.label = this.name;\n }\n this.style.overflowX = 'hidden';\n this.shadow = this.attachShadow({ mode: 'open' });\n this.shadow.adoptedStyleSheets = [folderStylesheet];\n\n this.div = document.createElement('div');\n }\n\n connectedCallback() {\n if (GalleryFolder.folders.has(this)) return; // Element is just being moved\n this.div.className = 'gallery-folder';\n this.div.innerHTML = `\\uf03e ${this.label}`;\n this.div.title = this.name; // Show full path on hover\n this.addEventListener('click', this.updateSelected);\n this.addEventListener('click', fetchFilesWS);\n this.shadow.appendChild(this.div);\n GalleryFolder.folders.add(this);\n if (this.name === currentGalleryFolder) {\n this.updateSelected();\n }\n }\n\n async disconnectedCallback() {\n await Promise.resolve(); // Wait for other microtasks (such as element moving)\n if (this.isConnected) return;\n GalleryFolder.folders.delete(this);\n if (GalleryFolder.#active === this) {\n GalleryFolder.#active = null;\n }\n }\n\n static getActive() {\n return GalleryFolder.#active;\n }\n\n updateSelected() {\n this.div.classList.add('gallery-folder-selected');\n GalleryFolder.#active = this;\n for (const folder of GalleryFolder.folders as any) {\n if (folder !== this) folder.div.classList.remove('gallery-folder-selected');\n }\n }\n}\n\n/**\n * Event-driven wait mechanism replacing the 50ms polling loop\n * @param {AbortSignal} signal - AbortController signal\n */\nasync function awaitForOutstanding(signal) {\n if (signal?.aborted) throw new DOMException('Aborted', 'AbortError');\n if (outstanding < maxFetchRequests) return; // if we are under the limit, proceed immediately\n await new Promise((resolve, reject) => { // otherwise, register a promise and wait for the queue to resolve us\n const onResolve = () => { // define what happens when this item gets its turn or gets aborted\n signal?.removeEventListener('abort', onAbort);\n resolve(true);\n };\n const onAbort = () => {\n const idx = fetchQueue.findIndex((item) => item.resolve === onResolve); // remove this specific request from the waiting queue if aborted\n if (idx !== -1) fetchQueue.splice(idx, 1);\n reject(new DOMException('Aborted', 'AbortError'));\n };\n fetchQueue.push({ resolve: onResolve });\n signal?.addEventListener('abort', onAbort);\n });\n}\n\nasync function delayFetchThumb(fn, signal) {\n const t0 = performance.now();\n try {\n await awaitForOutstanding(signal);\n } catch (err) {\n if ((err as DOMException).name === 'AbortError') return undefined;\n throw err;\n }\n pb.stats.queue = (pb.stats.queue || 0) + Math.round(performance.now() - t0);\n const t1 = performance.now();\n try {\n outstanding++;\n const ts = t0.toString();\n const res = await authFetch(`${window.api}/browser/thumb?file=${encodeURI(fn)}&ts=${ts}&exif=false`, { priority: 'low' });\n if (!res?.ok) {\n error(`fetchThumb: ${res.statusText}`);\n return undefined;\n }\n const json = await res.json();\n if (!res || !json || json.error || Object.keys(json).length === 0) {\n if (json.error) error(`fetchThumb: ${json.error}`);\n return undefined;\n }\n return json;\n } finally {\n outstanding--;\n pb.stats.fetch = (pb.stats.fetch || 0) + Math.round(performance.now() - t1);\n if (fetchQueue.length > 0 && outstanding < maxFetchRequests) { // queue magic: trigger the next waiting fetch immediately\n const nextRequest = fetchQueue.shift();\n nextRequest.resolve(); // This wakes up the next awaitForOutstanding()\n }\n }\n}\n\nclass GalleryFile extends HTMLElement {\n /** @type {AbortSignal} */\n #signal;\n\n constructor(folder, file, signal) {\n super();\n this.folder = folder;\n this.name = file;\n this.#signal = signal;\n this.src = `${this.folder}/${this.name}`.replace(/\\/+/g, '/'); // Ensure no //, ///, etc...\n this.fullFolder = this.src.replace(/\\/[^/]+$/, '');\n this.size = 0;\n this.mtime = 0;\n this.hash = undefined;\n this.exif = '';\n this.width = 0;\n this.height = 0;\n this.shadow = this.attachShadow({ mode: 'open' });\n this.shadow.adoptedStyleSheets = [fileStylesheet];\n this.firstRun = true;\n }\n\n async connectedCallback() {\n if (!this.firstRun) return; // Element is just being moved\n this.firstRun = false;\n const t0 = performance.now();\n pb.stats.count = (pb.stats.count || 0) + 1;\n // Check separator state early to hide the element immediately\n const dir = this.name.match(/(.*)[/\\\\]/);\n if (dir && dir[1]) {\n const dirPath = dir[1];\n const isOpen = separatorStates.get(dirPath);\n if (isOpen === false) this.style.display = 'none';\n }\n\n this.hash = await getHash(`${this.src}/${this.size}/${this.mtime}`)\n .catch((err) => {\n error('getHash:', err);\n return null;\n });\n pb.stats.hash = (pb.stats.hash || 0) + Math.round(performance.now() - t0);\n let cachedData;\n if (opts.browser_cache) {\n const t1 = performance.now();\n // if (!pb.stats.keys) pb.stats.keys = await idbKeys();\n // if (pb.stats.keys && this.hash && pb.stats.keys.includes(this.hash)) cachedData = await idbGet(this.hash).catch(() => undefined);\n cachedData = await idbGet(this.hash).catch(() => undefined);\n pb.stats.db = (pb.stats.db || 0) + Math.round(performance.now() - t1);\n }\n const img = document.createElement('img');\n img.className = 'gallery-file';\n img.loading = 'lazy';\n img.onload = async () => {\n img.title += `\\nResolution: ${this.width} x ${this.height}`;\n this.title = img.title;\n if (!cachedData && opts.browser_cache) {\n if ((this.width === 0) || (this.height === 0)) { // fetch thumb failed so we use actual image\n this.width = img.naturalWidth;\n this.height = img.naturalHeight;\n }\n }\n };\n let ok = true;\n if (cachedData?.img) {\n img.src = cachedData.img;\n this.exif = cachedData.exif;\n this.width = cachedData.width;\n this.height = cachedData.height;\n this.size = cachedData.size;\n this.mtime = new Date(cachedData.mtime);\n pb.stats.cached = (pb.stats.cached || 0) + 1;\n } else {\n try {\n const json = await delayFetchThumb(this.src, this.#signal);\n if (!json) {\n ok = false;\n pb.stats.failed = (pb.stats.failed || 0) + 1;\n } else {\n img.src = json.data;\n this.exif = json.exif;\n this.width = json.width;\n this.height = json.height;\n this.size = json.size;\n this.mtime = new Date(json.mtime);\n pb.stats.fetched = (pb.stats.fetched || 0) + 1;\n if (opts.browser_cache && this.hash) {\n idbAdd({\n hash: this.hash,\n folder: this.fullFolder,\n file: this.name,\n size: this.size,\n mtime: this.mtime,\n width: this.width,\n height: this.height,\n src: this.src,\n exif: this.exif,\n img: img.src,\n // exif: await getExif(img), // alternative client-side exif\n // img: await createThumb(img), // alternative client-side thumb\n });\n }\n }\n } catch (err) { // thumb fetch failed so assign actual image\n img.src = `file=${this.src}`;\n pb.stats.error = (pb.stats.error || 0) + 1;\n }\n }\n pb.stats.callback = (pb.stats.callback || 0) + Math.round(performance.now() - t0);\n if (this.#signal.aborted) return;\n galleryHashes.add(this.hash);\n if (!ok) return;\n\n img.onclick = () => {\n setGallerySelectionByElement(this, { send: true });\n };\n img.onpointerenter = () => {\n el.overlay.display = 'block';\n this.shadow.appendChild(el.overlay);\n currentImage = this.src;\n currentName = this.name;\n currentTitle = this.title;\n };\n img.onpointerleave = () => {\n el.overlay.display = 'none';\n };\n img.title = `Folder: ${this.folder}\\nFile: ${this.name}\\nSize: ${this.size.toLocaleString()} bytes\\nModified: ${this.mtime.toLocaleString()}`;\n this.title = img.title;\n const shouldDisplayBasedOnSearch = this.title.toLowerCase().includes(el.search.value.toLowerCase()); // Final visibility check based on search term.\n if (this.style.display !== 'none') this.style.display = shouldDisplayBasedOnSearch ? '' : 'none'; // Only proceed if not already hidden by a closed separator\n this.shadow.appendChild(img);\n pb.stats.elapsed = (pb.stats.elapsed || 0) + Math.round(performance.now() - t0);\n }\n}\n\nasync function createThumb(img) {\n const sizeEl = document.getElementById('gallery-thumb-size');\n currentSize = sizeEl ? parseInt(sizeEl.value, 10) : opts.extra_networks_card_size;\n const height = currentSize;\n const width = opts.browser_fixed_width ? currentSize : 0;\n const canvas = document.createElement('canvas');\n const scaleY = height / img.height;\n const scaleX = width > 0 ? width / img.width : scaleY;\n const scale = Math.min(scaleX, scaleY);\n const scaledWidth = img.width * scale;\n const scaledHeight = img.height * scale;\n canvas.width = scaledWidth;\n canvas.height = scaledHeight;\n const ctx = canvas.getContext('2d');\n ctx.drawImage(img, 0, 0, scaledWidth, scaledHeight);\n const dataURL = canvas.toDataURL('image/jpeg', 0.5);\n return dataURL;\n}\n\nasync function handleSeparator(separator) {\n separator.classList.toggle('gallery-separator-hidden');\n const nowHidden = separator.classList.contains('gallery-separator-hidden');\n\n // Store the state (true = open, false = closed)\n separatorStates.set(separator.title, !nowHidden);\n\n // Update arrow and count\n const arrow = separator.querySelector('.gallery-separator-arrow');\n arrow.style.transform = nowHidden ? 'rotate(0deg)' : 'rotate(90deg)';\n\n const all = Array.from(el.files.children);\n for (const f of all) {\n if (!f.name) continue; // Skip separators\n\n // Check if file belongs to this exact directory\n const fileDir = f.name.match(/(.*)[/\\\\]/);\n const fileDirPath = fileDir ? fileDir[1] : '';\n\n if (separator.title.length > 0 && fileDirPath === separator.title) {\n f.style.display = nowHidden ? 'none' : '';\n }\n }\n // Note: Count is not updated here on manual toggle, as it reflects the total.\n // If I end up implementing it, the search function will handle dynamic count updates.\n}\n\nasync function addSeparators() {\n document.querySelectorAll('.gallery-separator').forEach((node) => { el.files.removeChild(node); });\n const all = Array.from(el.files.children);\n let lastDir;\n\n // Count root files (files without a directory path)\n const hasRootFiles = all.some((f) => f.name && !f.name.match(/[/\\\\]/));\n // Only auto-open first separator if there are no root files to display\n let isFirstSeparator = !hasRootFiles;\n\n // First pass: create separators\n for (const f of all) {\n let dir = f.name?.match(/(.*)[/\\\\]/);\n if (!dir) dir = '';\n else dir = dir[1];\n if (dir !== lastDir) {\n lastDir = dir;\n if (dir.length > 0) {\n // Count files in this directory\n let fileCount = 0;\n for (const file of all) {\n if (!file.name) continue;\n const fileDir = file.name.match(/(.*)[/\\\\]/);\n const fileDirPath = fileDir ? fileDir[1] : '';\n if (fileDirPath === dir) fileCount++;\n }\n\n const sep = document.createElement('div');\n sep.className = 'gallery-separator';\n sep.title = dir;\n\n // Default to open for the first separator if no state is saved, otherwise closed.\n const isOpen = separatorStates.has(dir) ? separatorStates.get(dir) : isFirstSeparator;\n separatorStates.set(dir, isOpen); // Ensure it's in the map\n if (isFirstSeparator) isFirstSeparator = false; // Subsequent separators will default to closed\n\n if (!isOpen) {\n sep.classList.add('gallery-separator-hidden');\n }\n\n // Create arrow span\n const arrow = document.createElement('span');\n arrow.className = 'gallery-separator-arrow';\n arrow.textContent = '\u25B6';\n arrow.style.transform = isOpen ? 'rotate(90deg)' : 'rotate(0deg)';\n\n // Create directory name span\n const dirName = document.createElement('span');\n dirName.className = 'gallery-separator-name';\n dirName.textContent = dir;\n dirName.title = dir; // Show full path on hover\n\n // Create count span\n const count = document.createElement('span');\n count.className = 'gallery-separator-count';\n count.textContent = `${fileCount} files`;\n sep.dataset.totalFiles = String(fileCount); // Store total count for search filtering\n\n sep.appendChild(arrow);\n sep.appendChild(dirName);\n sep.appendChild(count);\n\n sep.onclick = () => handleSeparator(sep);\n el.files.insertBefore(sep, f);\n }\n }\n }\n\n // Second pass: hide files in closed directories\n for (const f of all) {\n if (!f.name) continue; // Skip separators\n\n const dir = f.name.match(/(.*)[/\\\\]/);\n if (dir && dir[1]) {\n const dirPath = dir[1];\n const isOpen = separatorStates.get(dirPath);\n if (isOpen === false) {\n f.style.display = 'none';\n }\n }\n }\n}\n\n// methods\n\nconst gallerySendImage = (_images) => [currentImage]; // invoked by gradio button\nwindow.gallerySendImage = gallerySendImage;\n\n/**\n * Helper function to update status with sort mode\n * @param {...string|[string, string]} messages - Each can be either a string to use as-is, or an array of a string label and value\n * @returns {void}\n */\nfunction updateStatusLine(...messages) {\n if (!el.status) return;\n messages.unshift(['Sort', sortMode.name]);\n const fragment = document.createDocumentFragment();\n for (let i = 0; i < messages.length; i++) {\n const div = document.createElement('div');\n if (Array.isArray(messages[i])) {\n const [k, v] = messages[i];\n const tDiv = document.createElement('div');\n const ico = icons[k] || `${k}:`;\n tDiv.innerText = `${ico} ${v}`;\n div.append(tDiv);\n } else {\n const tDiv = document.createElement('div');\n tDiv.innerText = messages[i];\n div.append(tDiv);\n }\n fragment.append(div);\n }\n if (el.status.hasChildNodes()) el.status.innerHTML = '';\n el.status.append(fragment);\n}\n\nasync function injectGalleryStatusCSS() {\n const style = document.createElement('style');\n style.textContent = `\n #tab-gallery-status {\n display: inline-flex;\n flex-flow: row wrap;\n justify-content: ${opts.theme_type?.toLowerCase() === 'modern' ? 'flex-start' : 'flex-end'};\n }\n #tab-gallery-status > div {\n display: flex;\n max-width: 100%;\n white-space: nowrap;\n & div {\n &:first-child {\n flex-shrink: 0;\n margin-right: 4px;\n }\n &:last-child:not(:first-child) {\n flex-shrink: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n direction: rtl;\n text-align: left;\n }\n }\n }\n #tab-gallery-status > div:not(:last-child)::after {\n content: '|';\n margin-inline: 6px;\n }`;\n document.head.append(style);\n}\n\nasync function wsConnect(socket, timeout = 5000) {\n const intrasleep = 100;\n const ttl = timeout / intrasleep;\n const isOpened = () => (socket.readyState === WebSocket.OPEN);\n if (socket.readyState !== WebSocket.CONNECTING) return isOpened();\n\n let loop = 0;\n while (socket.readyState === WebSocket.CONNECTING && loop < ttl) {\n await new Promise((resolve) => { setTimeout(resolve, intrasleep); });\n loop++;\n }\n return isOpened();\n}\n\nasync function gallerySearch() {\n if (el.search.busy) clearTimeout(el.search.busy);\n el.search.busy = setTimeout(async () => {\n const t0 = performance.now();\n const str = el.search.value.toLowerCase();\n const allFiles = Array.from(el.files.children).filter((node) => node.name);\n const allSeparators = Array.from(el.files.children).filter((node) => node.classList.contains('gallery-separator'));\n\n // If search is cleared, restore original view\n if (str === '') {\n allSeparators.forEach((sep) => {\n sep.style.display = 'flex';\n const isOpen = separatorStates.has(sep.title) ? separatorStates.get(sep.title) : false;\n\n const countSpan = sep.querySelector('.gallery-separator-count');\n if (countSpan && sep.dataset.totalFiles) {\n countSpan.textContent = `${sep.dataset.totalFiles} files`;\n }\n\n const arrow = sep.querySelector('.gallery-separator-arrow');\n sep.classList.toggle('gallery-separator-hidden', !isOpen);\n if (arrow) arrow.style.transform = isOpen ? 'rotate(90deg)' : 'rotate(0deg)';\n });\n\n allFiles.forEach((f) => {\n const dir = f.name.match(/(.*)[/\\\\]/);\n const dirPath = (dir && dir[1]) ? dir[1] : '';\n const isOpen = separatorStates.get(dirPath);\n f.style.display = (!dirPath || isOpen) ? 'unset' : 'none';\n });\n\n updateStatusLine('Filter', 'Cleared', ['Images', allFiles.length.toLocaleString()]);\n return;\n }\n\n // --- Search logic ---\n let totalFound = 0;\n const directoryMatches = new Map();\n const fileMatches = new WeakSet();\n const r = /^(.+)([=<>])(.*)/;\n\n for (const f of allFiles) {\n let isMatch = false;\n if (r.test(str)) {\n const match = str.match(r);\n const key = match[1].trim();\n const op = match[2].trim();\n let val = match[3].trim();\n if (key === 'mtime') val = new Date(val);\n if (((op === '=') && (f[key] === val)) || ((op === '>') && (f[key] > val)) || ((op === '<') && (f[key] < val))) {\n isMatch = true;\n }\n } else if (f.title?.toLowerCase().includes(str) || f.exif?.toLowerCase().includes(str)) {\n isMatch = true;\n }\n\n if (isMatch) {\n fileMatches.add(f);\n totalFound++;\n const dir = f.name.match(/(.*)[/\\\\]/);\n const dirPath = (dir && dir[1]) ? dir[1] : '';\n directoryMatches.set(dirPath, (directoryMatches.get(dirPath) || 0) + 1);\n }\n }\n\n // Update separators based on search results\n for (const sep of allSeparators) {\n const dirPath = sep.title;\n const foundCount = directoryMatches.get(dirPath) || 0;\n\n if (foundCount > 0) {\n sep.style.display = 'flex'; // Show separator\n sep.classList.remove('gallery-separator-hidden'); // Force open\n\n const arrow = sep.querySelector('.gallery-separator-arrow');\n if (arrow) arrow.style.transform = 'rotate(90deg)';\n\n // Removed file count update during search as it was buggy.\n } else {\n sep.style.display = 'none'; // Hide separator\n }\n }\n\n // Update file visibility\n for (const f of allFiles) {\n f.style.display = fileMatches.has(f) ? 'unset' : 'none';\n }\n\n const t1 = performance.now();\n updateStatusLine('Filter', ['Images', `${totalFound.toLocaleString()} / ${allFiles.length.toLocaleString()}`], ['Time', `${Math.round(t1 - t0).toLocaleString()}ms`]);\n timer(`galleryFilter:${str}`, t1 - t0);\n refreshGallerySelection();\n }, 250);\n}\n\nconst findDuplicates = (arr, key) => {\n const map = new Map();\n return arr.filter((item) => {\n const value = item[key];\n if (map.has(value)) return true;\n map.set(value, true);\n return false;\n });\n};\n\nexport async function gallerySort(key) {\n // if currentSort does not start with key, default to key+A\n // else if currentSort ends with A change to D and vice versa for toggling sort order\n if (currentSort.startsWith(key)) currentSort = currentSort.endsWith('A') ? `${key}D` : `${key}A`;\n else currentSort = `${key}A`;\n\n if (!Object.hasOwn(gallerySorter, currentSort)) {\n error(`Gallery: \"${currentSort}\" is not a valid gallery sorting key`);\n return;\n }\n const t0 = performance.now();\n const arr = Array.from(el.files.children).filter((node) => node.name); // filter out separators\n if (arr.length === 0) return; // no files to sort\n const fragment = document.createDocumentFragment();\n\n // Helper to get directory path from a file node\n const getDirPath = (node) => {\n const match = node.name.match(/(.*)[/\\\\]/);\n return match ? match[1] : '';\n };\n\n // Partition into root files and subfolder files - root files always stay at top\n const rootFiles = arr.filter((node) => !getDirPath(node));\n const subfolderFiles = arr.filter((node) => getDirPath(node));\n\n // Group subfolder files by directory\n const folderGroups = new Map();\n for (const file of subfolderFiles) {\n const dir = getDirPath(file);\n if (!folderGroups.has(dir)) folderGroups.set(dir, []);\n folderGroups.get(dir).push(file);\n }\n\n sortMode = gallerySorter[currentSort];\n\n // Sort root files\n rootFiles.sort(sortMode.func);\n rootFiles.forEach((node) => fragment.appendChild(node));\n\n // Sort folder names alphabetically, then sort files within each folder\n // const sortedFolderNames = Array.from(folderGroups.keys()).sort((a, b) => a.localeCompare(b));\n const folderNames = Array.from(folderGroups.keys());\n const sortedFolderNames = currentSort.endsWith('A') ? folderNames.sort((a, b) => a.localeCompare(b)) : folderNames.sort((a, b) => b.localeCompare(a));\n\n for (const folderName of sortedFolderNames) {\n const files = folderGroups.get(folderName);\n files.sort(sortMode.func);\n files.forEach((node) => fragment.appendChild(node));\n }\n\n if (fragment.children.length === 0) return;\n el.files.innerHTML = '';\n el.files.appendChild(fragment);\n addSeparators();\n\n // After sorting and adding separators, ensure files respect separator states\n const all = Array.from(el.files.children);\n for (const f of all) {\n if (!f.name) continue; // Skip separators\n\n const dir = f.name.match(/(.*)[/\\\\]/);\n if (dir && dir[1]) {\n const dirPath = dir[1];\n const isOpen = separatorStates.get(dirPath);\n if (isOpen === false) {\n f.style.display = 'none';\n }\n }\n }\n\n const t1 = performance.now();\n log(`gallerySort: sort=${sortMode.name} len=${arr.length} time=${Math.floor(t1 - t0)}`);\n updateStatusLine(['Images', arr.length.toLocaleString()], ['Time', `${Math.round(t1 - t0).toLocaleString()}ms`]);\n timer(`gallerySort:${sortMode.name}`, t1 - t0);\n refreshGallerySelection();\n}\nwindow.gallerySort = gallerySort;\n\n/**\n * Function for removing the cleaning overlay\n * @callback ClearMsgCallback\n * @returns {void}\n */\n\n/**\n * Generate and display the overlay to announce cleanup is in progress.\n * @param {number} count - Number of entries being cleaned up\n * @param {boolean} all - Indicate that all thumbnails are being cleared\n * @returns {ClearMsgCallback}\n */\nfunction showCleaningMsg(count, all = false) {\n // Rendering performance isn't a priority since this doesn't run often\n const parent = el.folders.parentElement;\n const cleaningOverlay = document.createElement('div');\n const msgDiv = document.createElement('div');\n const msgText = document.createElement('div');\n const msgInfo = document.createElement('div');\n const anim = document.createElement('span');\n\n parent.style.position = 'relative';\n cleaningOverlay.style.cssText = 'position: absolute; height: 100%; width: 100%; background-color: var(--sd-main-accent-color); display: flex; align-items: center; justify-content: center; align-content: center; flex-wrap: wrap; opacity: 0.8; border-radius: var(--sd-border-radius);';\n msgDiv.style.cssText = 'display: block; color: var(--sd-button-normal-color); padding: 12px; border-radius: 8px; border-radius: var(--sd-border-radius);';\n msgText.style.cssText = 'font-size: 1.2em';\n msgInfo.style.cssText = 'font-size: 0.9em; text-align: center;';\n msgText.innerText = 'Thumbnail cleanup...';\n msgInfo.innerText = all ? 'Clearing all entries' : `Found ${count} old entries`;\n anim.classList.add('idbBusyAnim');\n\n msgDiv.append(msgText, msgInfo);\n cleaningOverlay.append(msgDiv, anim);\n parent.append(cleaningOverlay);\n return () => { cleaningOverlay.remove(); };\n}\n\nconst maintenanceQueue = new SimpleFunctionQueue('Gallery Maintenance');\n\n/**\n * Handles calling the cleanup function for the thumbnail cache\n * @param {string} folder - Folder to clean\n * @param {number} imgCount - Expected number of images in gallery\n * @param {AbortController} controller - AbortController that's handling this task\n * @param {boolean} force - Force full cleanup of the folder\n */\nasync function thumbCacheCleanup(folder, imgCount, controller, force = false) {\n if (!opts.browser_cache && !force) return;\n if (!folder || !imgCount) return;\n if (Date.now() - cleanupTimers[folder] < minCleanupTime) return; // Prevents multiple calls in quick succession\n cleanupTimers[folder] = Date.now();\n try {\n if (typeof folder !== 'string' || typeof imgCount !== 'number') {\n throw new Error('Function called with invalid arguments');\n }\n debug('thumbCacheCleanup', { folder, imgCount });\n await awaitForGallery(imgCount, controller.signal);\n } catch (err) {\n error('thumbCacheCleanup', { folder, error: err });\n return;\n }\n\n maintenanceQueue.enqueue({\n signal: controller.signal,\n callback: async () => {\n if (Date.now() - maintenanceTimers[folder] < minCleanupTime) return;\n maintenanceTimers[folder] = Date.now();\n const t0 = performance.now();\n const keptGalleryHashes = force ? new Set() : new Set(galleryHashes.values()); // External context should be safe since this function run is guarded by AbortController/AbortSignal in the SimpleFunctionQueue\n const folderNormalized = folder.replace(/\\/+/g, '/').replace(/\\/$/, '');\n const recursiveFolder = IDBKeyRange.bound(folderNormalized, `${folderNormalized}\\uffff`, false, true);\n const cachedHashesCount = await idbCount(recursiveFolder)\n .catch((e) => {\n error('maintenanceQueue', { folder, error: e });\n return Infinity; // Forces next check to fail if something went wrong\n });\n const cleanupCount = cachedHashesCount - keptGalleryHashes.size;\n if (!force && (cleanupCount < minCleanupCount || !Number.isFinite(cleanupCount))) return; // Don't run when there aren't many excess entries\n log('galleryMaintenance', { folder });\n\n if (controller.signal.aborted) {\n debug('maintenanceQueue', { folder, reason: controller.signal.reason });\n return;\n }\n const cb_clearMsg = showCleaningMsg(cleanupCount);\n await idbFolderCleanup(keptGalleryHashes, recursiveFolder, controller.signal)\n .then((delcount) => {\n const t1 = performance.now();\n log('galleryMaintenance', { folder, kept: keptGalleryHashes.size, deleted: delcount, time: Math.round(t1 - t0) });\n timer(`thumbnailDBCleanup:${folder}`, t1 - t0);\n currentGalleryFolder = null;\n updateStatusLine('Thumbnail cache cleared');\n })\n .catch((reason) => {\n SimpleFunctionQueue.abortLogger('thumbCacheCleanup', reason);\n })\n .finally(async () => {\n await new Promise((resolve) => { setTimeout(resolve, 1000); }); // Delay removal by 1 second to ensure at least minimum visibility\n cb_clearMsg();\n });\n },\n });\n}\n\nfunction resetGalleryState(reason) {\n maintenanceController.abort(reason);\n const controller = new AbortController();\n maintenanceController = controller;\n\n galleryHashes.clear(); // Must happen AFTER the AbortController steps\n pb.hide();\n resetGallerySelection();\n return controller;\n}\n\nfunction clearCacheIfDisabled(browser_cache) {\n if (browser_cache === false) {\n log('thumbCacheCleanup', { disabled: true });\n const controller = resetGalleryState('Clearing all thumbnails from cache');\n maintenanceQueue.enqueue({\n signal: controller.signal,\n callback: async () => {\n const t0 = performance.now();\n const cb_clearMsg = showCleaningMsg(0, true);\n await idbClearAll(controller.signal)\n .then(() => {\n log('thumbCacheCleanup', { time: Math.floor(performance.now() - t0) });\n currentGalleryFolder = null;\n updateStatusLine('Thumbnail cache cleared');\n })\n .catch((e) => {\n SimpleFunctionQueue.abortLogger('thumbCacheCleanup', e);\n })\n .finally(async () => {\n await new Promise((resolve) => { setTimeout(resolve, 1000); });\n cb_clearMsg();\n });\n },\n });\n }\n}\n\nexport function clearCache() {\n if (!currentGalleryFolder) return;\n const controller = resetGalleryState('Clearing folder thumbnails cache');\n el.files.innerHTML = '';\n log('clearCache', { folder: currentGalleryFolder });\n thumbCacheCleanup(currentGalleryFolder, 0, controller, true);\n}\nwindow.clearCache = clearCache;\n\nasync function fetchFilesHT(evt, controller) {\n const t0 = performance.now();\n const fragment = document.createDocumentFragment();\n updateStatusLine(['Folder', evt.target.name], 'in-progress');\n let numFiles = 0;\n\n const res = await authFetch(`${window.api}/browser/files?folder=${encodeURI(evt.target.name)}`);\n if (!res || res.status !== 200) {\n updateStatusLine(['Folder', evt.target.name], ['Failed', res?.statusText || 'No response']);\n return;\n }\n const jsonData = await res.json();\n for (const line of jsonData) {\n const data = decodeURI(line).split('##F##');\n const fileName = data[1];\n const ext = fileName.split('.').pop().toLowerCase();\n if (SUPPORTED_EXTENSIONS.includes(ext)) {\n numFiles++;\n const f = new GalleryFile(data[0], fileName, controller.signal);\n fragment.appendChild(f);\n }\n }\n\n if (controller.signal.aborted) return;\n el.files.appendChild(fragment);\n\n const t1 = performance.now();\n log(`gallery: folder=${evt.target.name} num=${numFiles} method=http time=${Math.floor(t1 - t0)}ms`);\n timer(`galleryFetch:${evt.target.name}`, t1 - t0);\n updateStatusLine(['Folder', evt.target.name], ['Images', numFiles.toLocaleString()], ['Time', `${Math.floor(t1 - t0).toLocaleString()}ms`]);\n pb.start(numFiles);\n addSeparators();\n refreshGallerySelection();\n thumbCacheCleanup(evt.target.name, numFiles, controller);\n}\n\nasync function fetchFilesWS(evt) { // fetch file-by-file list over websockets\n if (!url) return;\n // Abort previous controller and point to new controller for next time\n const controller = resetGalleryState('Gallery update'); // Called here because fetchFilesHT isn't called directly\n\n el.files.innerHTML = '';\n updateGalleryStyles();\n if (ws && ws.readyState === WebSocket.OPEN) ws.close(); // abort previous request\n let wsConnected = false;\n try {\n ws = new WebSocket(`${url}/sdapi/v1/browser/files`);\n wsConnected = await wsConnect(ws);\n } catch (err) {\n log('gallery: ws connect error', err);\n return;\n }\n log(`gallery: connected=${wsConnected} state=${ws?.readyState} url=${ws?.url}`);\n currentGalleryFolder = evt.target.name;\n if (!wsConnected) {\n await fetchFilesHT(evt, controller); // fallback to http\n return;\n }\n updateStatusLine(['Folder', evt.target.name]);\n const t0 = performance.now();\n let numFiles = 0;\n let t1 = performance.now();\n let fragment = document.createDocumentFragment();\n\n ws.onmessage = (event) => {\n t1 = performance.now();\n const data = decodeURI(event.data).split('##F##');\n if (data[0] === '#END#') {\n ws.close();\n } else {\n const fileName = data[1];\n const ext = fileName.split('.').pop().toLowerCase();\n if (SUPPORTED_EXTENSIONS.includes(ext)) {\n const file = new GalleryFile(data[0], fileName, controller.signal);\n numFiles++;\n fragment.appendChild(file);\n if (numFiles % fragmentSize === 0) {\n updateStatusLine(['Folder', evt.target.name], ['Images', numFiles.toLocaleString()], ['Status', 'in-progress'], ['Time', `${Math.floor(t1 - t0).toLocaleString()}ms`]);\n el.files.appendChild(fragment);\n fragment = document.createDocumentFragment();\n }\n }\n }\n };\n ws.onclose = (event) => {\n if (controller.signal.aborted) return;\n el.files.appendChild(fragment);\n // gallerySort();\n log(`gallery: folder=${evt.target.name} num=${numFiles} method=ws time=${Math.floor(t1 - t0)}ms`);\n updateStatusLine(['Folder', evt.target.name], ['Images', numFiles.toLocaleString()], ['Time', `${Math.floor(t1 - t0).toLocaleString()}ms`]);\n pb.start(numFiles);\n addSeparators();\n refreshGallerySelection();\n thumbCacheCleanup(evt.target.name, numFiles, controller);\n };\n ws.onerror = (event) => {\n log('gallery ws error', event);\n };\n ws.send(encodeURI(evt.target.name));\n}\n\nasync function updateFolders() {\n // if (el.folders.children.length > 0) return;\n const res = await authFetch(`${window.api}/browser/folders`);\n if (!res || res.status !== 200) return;\n url = res.url.split('/sdapi')[0].replace('http', 'ws'); // update global url as ws need fqdn\n const folders = await res.json();\n el.folders.innerHTML = '';\n for (const folder of folders) {\n const f = new GalleryFolder(folder);\n el.folders.appendChild(f);\n }\n}\n\nasync function monitorGalleries() {\n async function galleryMutation(mutations) {\n const galleries = mutations.filter((m) => m.target?.classList?.contains('preview'));\n for (const gallery of galleries) {\n const links = gallery.target.querySelectorAll('a');\n for (const link of links) {\n const href = link.getAttribute('href');\n if (!href) continue;\n const fn = href.split('/').pop().split('\\\\').pop();\n link.setAttribute('download', fn);\n }\n }\n }\n\n const galleryElements = gradioApp().querySelectorAll('.gradio-gallery');\n for (const gallery of galleryElements) {\n const galleryObserver = new MutationObserver(galleryMutation);\n galleryObserver.observe(gallery, { childList: true, subtree: true, attributes: true });\n }\n}\n\nasync function setOverlayAnimation() {\n const busyAnimation = document.createElement('style');\n\n // eslint-disable-next-line @stylistic/max-len\n busyAnimation.textContent = '.idbBusyAnim{width:16px;height:16px;border-radius:50%;display:block;margin:40px;position:relative;background:#aa3d00;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)}}';\n document.head.append(busyAnimation);\n}\n\nasync function initGalleryAutoRefresh() {\n const isModern = opts.theme_type?.toLowerCase() === 'modern';\n let galleryTab = isModern ? document.getElementById('gallery_tabitem') : document.getElementById('tab_gallery');\n let timeout = 0;\n while (!galleryTab && timeout++ < 60) {\n await new Promise((resolve) => { setTimeout(resolve, 2500); });\n galleryTab = isModern ? document.getElementById('gallery_tabitem') : document.getElementById('tab_gallery');\n }\n if (!galleryTab) {\n error('Gallery: timeout');\n return;\n }\n const displayNoneRegEx = /display:\\s*none/;\n async function galleryAutoRefresh(mutations) {\n if (!opts.browser_gallery_autoupdate) return;\n for (const mutation of mutations) {\n switch (mutation.attributeName) {\n case 'class':\n if (mutation.oldValue.includes('hidden') && !mutation.target.classList.contains('hidden')) {\n await updateFolders();\n GalleryFolder.getActive()?.click();\n }\n break;\n case 'style':\n if (displayNoneRegEx.test(mutation.oldValue) && !displayNoneRegEx.test(mutation.target.style.display)) {\n await updateFolders();\n GalleryFolder.getActive()?.click();\n }\n break;\n default:\n break;\n }\n }\n }\n const galleryVisObserver = new MutationObserver(galleryAutoRefresh);\n galleryVisObserver.observe(galleryTab, { attributeFilter: ['class', 'style'], attributeOldValue: true });\n}\n\nasync function overlayDelete(evt) {\n const res = await authFetch(`${window.api}/delete-image?file=${encodeURIComponent(currentImage)}`, { method: 'DELETE' });\n evt.stopPropagation();\n if (!res || res.status !== 200) {\n error('galleryDelete', { file: currentImage, status: res?.status, statusText: res?.statusText });\n return;\n }\n const data = await res.json();\n log('galleryDelete', data);\n GalleryFolder.getActive()?.click();\n}\n\nasync function overlayDownload(evt) {\n log('galleryDownload', currentImage);\n const link = document.createElement('a');\n link.href = `/file=${encodeURIComponent(currentImage)}`;\n link.download = currentName;\n document.body.appendChild(link);\n link.click();\n document.body.removeChild(link);\n evt.stopPropagation();\n}\n\nasync function overlayInfo(evt) {\n evt.stopPropagation();\n const tgt = document.getElementById('html_info_formatted_gallery');\n if (!tgt) return;\n const res = await authFetch(`${window.api}/png-info?file=${encodeURI(currentImage)}`);\n if (!res || res.status !== 200) return;\n const data = await res.json();\n log('galleryInfo res', data);\n const prompt = data?.parameters?.Prompt || '';\n const negative = data?.parameters?.Negative || data?.parameters?.['Negative prompt'] || '';\n const raw = data?.info || '';\n const params = data?.parameters || {};\n delete params.Prompt;\n delete params.Negative;\n delete params['Negative prompt'];\n const paramsFormatted = Object.entries(params).map(([key, value]) => `${key}: ${value}`).join(' | ');\n tgt.innerHTML = `\n
    File: ${currentImage}
    \n
    Prompt: ${prompt}
    \n
    Negative: ${negative}
    \n
    ${paramsFormatted}
    \n
    Raw:
    ${raw}
    \n `;\n const img = document.querySelector('#gallery_gallery img');\n if (img) img.src = `/file=${encodeURIComponent(currentImage)}?t=${Date.now()}`; // Force refresh in case info endpoint is faster than cache update\n const status = document.querySelector('#html_log_gallery p');\n if (status) status.innerText = currentTitle;\n}\n\nasync function createOverlay() {\n if (el.overlay) return;\n el.overlay = document.createElement('div');\n el.overlay.className = 'gallery-overlay';\n const btnDownload = document.createElement('span');\n btnDownload.innerHTML = '\\udb85\\udc64';\n btnDownload.title = 'Download image';\n btnDownload.style.cursor = 'pointer';\n btnDownload.addEventListener('click', overlayDownload);\n const btnDelete = document.createElement('span');\n btnDelete.innerHTML = '\\uf05c';\n btnDelete.title = 'Delete image';\n btnDelete.style.cursor = 'pointer';\n btnDelete.addEventListener('click', overlayDelete);\n const btnInfo = document.createElement('span');\n btnInfo.innerHTML = '\\uf05a';\n btnInfo.title = 'Image metadata';\n btnInfo.style.cursor = 'pointer';\n btnInfo.addEventListener('click', overlayInfo);\n el.overlay.append(btnInfo, btnDelete, btnDownload);\n}\n\nasync function observeImageError(img: HTMLImageElement) {\n if (!img || !img.src) return;\n if (!img.src.toLowerCase().includes('.heic') && !img.src.toLowerCase().includes('.heif')) return;\n const origSrc = img.src;\n try {\n const t0 = performance.now();\n img.src = loadingSvg; // Use a loading spinner or placeholder image\n // @ts-ignore: external CDN module with no local types\n // eslint-disable-next-line import-x/no-unresolved\n const { default: heic2any } = await import('https://esm.sh/heic2any@0.0.4');\n const res = await authFetch(origSrc);\n if (!res || res.status !== 200) return;\n const imageBlob = await res.blob();\n if (!imageBlob || imageBlob.size <= 1024) {\n error('imageHEIC', { src: origSrc, res, blob: imageBlob });\n return;\n }\n const convertedBlob = await heic2any({\n blob: imageBlob,\n toType: 'image/jpeg',\n quality: 0.9,\n });\n img.src = URL.createObjectURL(convertedBlob);\n const t1 = performance.now();\n log('imageHEIC', { time: Math.round(t1 - t0), originalSize: imageBlob.size, convertedSize: convertedBlob.size });\n } catch (err) {\n error('imageHEIC:', { src: origSrc, err });\n }\n}\n\nasync function observeGalleryMutations() {\n const galleryContainers = document.querySelectorAll('.gradio-gallery');\n for (const galleryContainer of galleryContainers) {\n if (!galleryContainer) return;\n const galleryObserver = new MutationObserver((mutations) => {\n for (const mutation of mutations) {\n if (mutation.type === 'childList' && mutation.addedNodes.length > 0) {\n const img = galleryContainer.querySelector('img');\n if (img && !galleryContainer.dataset.errorObserved) {\n galleryContainer.dataset.errorObserved = 'true';\n log('imageErrorHandler', { gallery: galleryContainer.id });\n img.addEventListener('error', () => observeImageError(img)); // late attach error handler as el may not be present\n galleryObserver.disconnect(); // stop observing after attaching the error handler\n }\n }\n }\n });\n galleryObserver.observe(galleryContainer, { childList: true, subtree: true });\n }\n}\n\nasync function blockQueueUntilReady() {\n // Add block to maintenanceQueue until cache is ready\n maintenanceQueue.enqueue({\n signal: new AbortController().signal, // Use standalone AbortSignal that can't be aborted\n callback: async () => {\n let timeout = 0;\n while (!idbIsReady() && timeout++ < 60) {\n await new Promise((resolve) => { setTimeout(resolve, 1000); });\n }\n if (!idbIsReady()) {\n throw new Error('Timed out waiting for thumbnail cache');\n }\n },\n });\n}\n\nexport async function initGallery() { // triggered on gradio change to monitor when ui gets sufficiently constructed\n const t0 = performance.now();\n el.folders = gradioApp().getElementById('tab-gallery-folders');\n el.files = gradioApp().getElementById('tab-gallery-files');\n el.status = gradioApp().getElementById('tab-gallery-status');\n el.search = gradioApp().querySelector('#tab-gallery-search textarea');\n el.size = document.getElementById('tab-gallery-thumb-size');\n if (!el.folders || !el.files || !el.status || !el.search) {\n error('initGallery', 'Missing gallery elements');\n return;\n }\n\n if (el.size) {\n el.size.value = opts.extra_networks_card_size;\n el.size.addEventListener('input', updateGalleryStyles);\n }\n blockQueueUntilReady(); // Run first\n createOverlay();\n updateGalleryStyles();\n injectGalleryStatusCSS();\n setOverlayAnimation();\n\n const progress = gradioApp().getElementById('tab-gallery-progress');\n if (progress) pb.attachTo(progress);\n else log('initGallery', 'Failed to attach loading progress bar');\n\n if (galleryInitialized) {\n log('initGallery', 'already initialized');\n return;\n }\n galleryInitialized = true;\n\n el.search.addEventListener('input', gallerySearch);\n el.btnSend = gradioApp().getElementById('tab-gallery-send-image');\n document.getElementById('tab-gallery-files').style.height = opts.logmonitor_show ? '75vh' : '85vh';\n\n monitorGalleries();\n updateFolders();\n initGalleryAutoRefresh();\n observeGalleryMutations();\n [\n 'browser_folders',\n 'outdir_samples',\n 'outdir_txt2img_samples',\n 'outdir_img2img_samples',\n 'outdir_control_samples',\n 'outdir_extras_samples',\n 'outdir_save',\n 'outdir_video',\n 'outdir_init_images',\n 'outdir_grids',\n 'outdir_txt2img_grids',\n 'outdir_img2img_grids',\n 'outdir_control_grids',\n ].forEach((op) => { monitorOption(op, updateFolders); });\n const t1 = performance.now();\n log('initGallery', Math.round(t1 - t0));\n timer('initGallery', t1 - t0);\n}\n\n// register on startup\n\ncustomElements.define('gallery-folder', GalleryFolder);\ncustomElements.define('gallery-file', GalleryFile);\n", "import exifr from 'exifr';\nimport Panzoom from 'panzoom';\nimport { log, debug } from './logger';\nimport { gradioApp, onAfterUiUpdate } from './script';\nimport { getENActiveTab } from './extraNetworks';\nimport { all_gallery_buttons, selected_gallery_button } from './ui';\nimport { timer } from './timers';\n\n// A full size 'lightbox' preview modal shown when left clicking on gallery previews\nlet previewDrag = false;\nlet modalPreviewZone;\nlet previewInstance;\n\nfunction cycleImageFit() {\n const root = document.documentElement;\n const current = getComputedStyle(root).getPropertyValue('--sd-image-fit').trim();\n let next = 'contain';\n if (current === 'contain') next = 'cover';\n else if (current === 'cover') next = 'fill';\n else if (current === 'fill') next = 'scale-down';\n else if (current === 'scale-down') next = 'none';\n root.style.setProperty('--sd-image-fit', next);\n log('cycleImageFit', current, next);\n}\n\nwindow.cycleImageFit = cycleImageFit;\n\nfunction isInViewport(element) {\n const rect = element.getBoundingClientRect();\n return rect.top >= 0 && rect.left >= 0 && rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) && rect.right <= (window.innerWidth || document.documentElement.clientWidth);\n}\n\nfunction closeModal(evt, force = false) {\n if (force) gradioApp().getElementById('lightboxModal').style.display = 'none';\n if (previewDrag) return;\n if (evt?.button !== 0) return;\n gradioApp().getElementById('lightboxModal').style.display = 'none';\n let thumbnails = Array.from(gradioApp().querySelectorAll('.thumbnails .thumbnail-item'));\n thumbnails = thumbnails.filter((el) => el.checkVisibility());\n if (thumbnails.length === 0) return;\n thumbnails[0].focus();\n}\n\nfunction modalImageSwitch(offset) {\n const negmod = (n, m) => ((n % m) + m) % m;\n const galleryButtons = all_gallery_buttons();\n if (galleryButtons.length > 1) {\n const currentButton = selected_gallery_button();\n let result = -1;\n galleryButtons.forEach((v, i) => {\n if (v === currentButton) result = i;\n });\n if (result !== -1) {\n const nextButton = galleryButtons[negmod((result + offset), galleryButtons.length)];\n nextButton.click();\n const modalImage = gradioApp().getElementById('modalImage');\n const modal = gradioApp().getElementById('lightboxModal');\n modalImage.src = nextButton.children[0].src;\n if (modalImage.style.display === 'none') modal.style.setProperty('background-image', `url(${modalImage.src})`);\n return;\n }\n }\n\n const galleryFilesContainer = gradioApp().getElementById('tab-gallery-files');\n if (!galleryFilesContainer || !galleryFilesContainer.offsetParent) return;\n const gallerySelection = window.getGallerySelection();\n if (!gallerySelection.files.length || gallerySelection.files.length <= 1) return;\n const baseIndex = gallerySelection.index >= 0 ? gallerySelection.index : 0;\n const nextIndex = negmod((baseIndex + offset), gallerySelection.files.length);\n window.setGallerySelection(nextIndex, { send: true });\n const modalImage = gradioApp().getElementById('modalImage');\n const modal = gradioApp().getElementById('lightboxModal');\n const directSrc = window.getGallerySelectedUrl();\n if (modalImage && modal && directSrc) {\n modalImage.src = directSrc;\n if (modalImage.style.display === 'none') modal.style.setProperty('background-image', `url(${directSrc})`);\n }\n}\n\nfunction modalSaveImage(event?: any) {\n const tabName = getENActiveTab();\n const saveBtn = gradioApp().getElementById(`save_${tabName}`);\n log('modalSaveImage', tabName, saveBtn);\n if (saveBtn) saveBtn.click();\n modalImageSwitch(0);\n}\n\nfunction modalKeyHandler(event) {\n log('modalKeyHandler', event.key);\n switch (event.key) {\n case 's':\n modalSaveImage();\n break;\n case 'ArrowLeft':\n modalImageSwitch(-1);\n break;\n case 'ArrowRight':\n modalImageSwitch(1);\n break;\n case 'Escape':\n closeModal(null, true);\n break;\n }\n event.stopPropagation();\n}\n\nfunction decodeBytes(bytes: Uint8Array): string {\n if (!bytes || bytes.length < 8) return '';\n const prefix = new TextDecoder('ascii').decode(bytes.slice(0, 8));\n const data = bytes.slice(8);\n if (prefix.startsWith('ASCII')) return new TextDecoder('ascii').decode(data).replace(/\\0+$/, '');\n if (prefix.startsWith('UNICODE')) return new TextDecoder('utf-16be').decode(data).replace(/\\0+$/, '');\n if (prefix.startsWith('JIS')) return new TextDecoder('shift-jis').decode(data).replace(/\\0+$/, '');\n return new TextDecoder().decode(bytes).replace(/\\0+$/, '');\n}\n\nexport async function getExif(el) {\n let exif: any = '';\n try {\n exif = await exifr.parse(el, { userComment: true });\n } catch (e) {\n log('getExif', el, e);\n return exif;\n }\n // let html = `Image ${el.src} Size ${el.naturalWidth}x${el.naturalHeight}
    `;\n let html = '';\n let params;\n if (!exif) {\n log('getExif', 'exif is none');\n return html;\n }\n if (exif.parameters) params = exif.parameters;\n else if (exif.userComment) params = decodeBytes(exif.userComment);\n else params = '';\n // debug('getExif', params);\n if (params.length > 0) html += `Prompt ${params || ''}
    `;\n html = html.replace('Negative prompt:', '
    Negative');\n html = html.replace('Steps:', '
    Params Steps:');\n html = html.replaceAll('\\n', '
    ');\n html = html.replaceAll('

    ', '
    ');\n return html;\n}\n\nasync function displayExif(el) {\n const modalExif = gradioApp().getElementById('modalExif');\n const html = await getExif(el);\n modalExif.innerHTML = html;\n}\n\nfunction showModal(event) {\n const source = event.target || event.srcElement;\n const modalImage = gradioApp().getElementById('modalImage');\n const lb = gradioApp().getElementById('lightboxModal');\n lb.ownerSVGElement = modalImage;\n modalImage.onload = () => {\n previewInstance.moveTo(0, 0);\n modalPreviewZone.focus();\n if (opts.viewer_show_metadata) displayExif(modalImage);\n };\n modalImage.src = source.src;\n if (modalImage.style.display === 'none') lb.style.setProperty('background-image', `url(${source.src})`);\n lb.style.display = 'flex';\n lb.onkeydown = modalKeyHandler;\n event.stopPropagation();\n}\n\nfunction modalDownloadImage() {\n const link = document.createElement('a');\n link.style.display = 'none';\n link.href = gradioApp().getElementById('modalImage').src;\n link.download = 'image';\n document.body.appendChild(link);\n link.click();\n setTimeout(() => {\n URL.revokeObjectURL(link.href);\n link.parentNode.removeChild(link);\n }, 0);\n}\n\nfunction modalZoomSet(modalImage, enable) {\n localStorage.setItem('modalZoom', enable ? 'yes' : 'no');\n if (modalImage) modalImage.classList.toggle('modalImageFullscreen', !!enable);\n}\n\nfunction setupImageForLightbox(image) {\n if (image.dataset.modded) return;\n image.dataset.modded = 'true';\n image.style.cursor = 'pointer';\n image.style.userSelect = 'none';\n}\n\nfunction modalZoomToggle(event) {\n const modalImage = gradioApp().getElementById('modalImage');\n modalZoomSet(modalImage, !modalImage.classList.contains('modalImageFullscreen'));\n event.stopPropagation();\n modalImageSwitch(0);\n}\n\nfunction modalTileToggle(event) {\n const modalImage = gradioApp().getElementById('modalImage');\n const modal = gradioApp().getElementById('lightboxModal');\n const isTiling = modalImage.style.display === 'none';\n if (isTiling) {\n modalImage.style.display = 'block';\n modal.style.setProperty('background-image', 'none');\n } else {\n modalImage.style.display = 'none';\n modal.style.setProperty('background-image', `url(${modalImage.src})`);\n }\n event.stopPropagation();\n modalImageSwitch(0);\n}\n\nfunction modalResetInstance(event) {\n const modalImage = document.getElementById('modalImage');\n previewInstance.dispose();\n previewInstance = Panzoom(modalImage, { zoomSpeed: 0.05, minZoom: 0.1, maxZoom: 5.0, filterKey: (/* e, dx, dy, dz */) => true });\n event.stopPropagation();\n modalImageSwitch(0);\n}\n\nfunction modalToggleParams(event) {\n const modalExif = gradioApp().getElementById('modalExif');\n if (modalExif.style.display === 'none' || modalExif.style.display === '') {\n modalExif.style.display = 'block';\n } else {\n modalExif.style.display = 'none';\n }\n event.stopPropagation();\n modalImageSwitch(0);\n}\n\nfunction galleryClickEventHandler(event) {\n if (event.button !== 0) return;\n if (event.target.nodeName === 'IMG' && !event.target.parentNode.classList.contains('thumbnail-item')) {\n const initialZoom = (localStorage.getItem('modalZoom') || true) === 'yes';\n modalZoomSet(gradioApp().getElementById('modalImage'), initialZoom);\n event.preventDefault();\n showModal(event);\n }\n}\n\nasync function bindImageViewer() {\n // Each tab has its own gradio-gallery\n const galleryPreviews = gradioApp().querySelectorAll('.gradio-gallery > div.preview');\n for (const galleryPreview of galleryPreviews) {\n if (!galleryPreview.hasAttribute('data-listener')) galleryPreview.addEventListener('click', galleryClickEventHandler, true);\n galleryPreview.setAttribute('data-listener', 'true');\n galleryPreview.querySelectorAll('img').forEach(setupImageForLightbox);\n }\n}\n\nexport async function initImageViewer() {\n const t0 = performance.now();\n // main elements\n const modal = document.createElement('div');\n modal.id = 'lightboxModal';\n\n modalPreviewZone = document.createElement('div');\n modalPreviewZone.className = 'lightboxModalPreviewZone';\n\n const modalImage = document.createElement('img');\n modalImage.id = 'modalImage';\n modalPreviewZone.appendChild(modalImage);\n previewInstance = Panzoom(modalImage, { zoomSpeed: 0.05, minZoom: 0.1, maxZoom: 5.0, filterKey: (/* e, dx, dy, dz */) => true });\n\n // toolbar\n const modalZoom = document.createElement('span');\n modalZoom.id = 'modal_zoom';\n modalZoom.className = 'cursor';\n modalZoom.innerHTML = '\\uf531';\n modalZoom.title = 'Toggle zoomed view';\n modalZoom.addEventListener('click', modalZoomToggle, true);\n\n const modalReset = document.createElement('span');\n modalReset.id = 'modal_reset';\n modalReset.className = 'cursor';\n modalReset.innerHTML = '\\uf532';\n modalReset.title = 'Reset zoomed view';\n modalReset.addEventListener('click', modalResetInstance, true);\n\n const modalTile = document.createElement('span');\n modalTile.id = 'modal_tile';\n modalTile.className = 'cursor';\n modalTile.innerHTML = '\\udb81\\udd70';\n modalTile.title = 'Preview tiling';\n modalTile.addEventListener('click', modalTileToggle, true);\n\n const modalSave = document.createElement('span');\n modalSave.id = 'modal_save';\n modalSave.className = 'cursor';\n modalSave.innerHTML = '\\udb80\\udd93';\n modalSave.title = 'Save Image';\n modalSave.addEventListener('click', modalSaveImage, true);\n\n const modalDownload = document.createElement('span');\n modalDownload.id = 'modal_download';\n modalDownload.className = 'cursor';\n modalDownload.innerHTML = '\\udb85\\udc62';\n modalDownload.title = 'Download Image';\n modalDownload.addEventListener('click', modalDownloadImage, true);\n\n const modalClose = document.createElement('span');\n modalClose.id = 'modal_close';\n modalClose.className = 'cursor';\n modalClose.innerHTML = '\\udb80\\udd57';\n modalClose.title = 'Close';\n modalClose.addEventListener('click', (evt) => closeModal(evt, true), true);\n\n const modalToggleParamsBtn = document.createElement('span');\n modalToggleParamsBtn.id = 'modal_toggle_params';\n modalToggleParamsBtn.className = 'cursor';\n modalToggleParamsBtn.innerHTML = '\\uf05a';\n modalToggleParamsBtn.title = 'Toggle Parameters';\n modalToggleParamsBtn.addEventListener('click', modalToggleParams, true);\n\n // exif\n const modalExif = document.createElement('div');\n modalExif.id = 'modalExif';\n modalExif.style = 'position: absolute; bottom: 0px; width: 100%; background-color: rgba(0, 0, 0, 0.5); color: var(--neutral-300); padding: 1em; font-size: small; line-height: 1.2em; z-index: 1; display: none;';\n\n // handlers\n modalPreviewZone.addEventListener('mousedown', () => { previewDrag = false; });\n modalPreviewZone.addEventListener('touchstart', () => { previewDrag = false; }, { passive: true });\n modalPreviewZone.addEventListener('mousemove', () => { previewDrag = true; });\n modalPreviewZone.addEventListener('touchmove', () => { previewDrag = true; }, { passive: true });\n modalPreviewZone.addEventListener('scroll', () => { previewDrag = true; });\n modalPreviewZone.addEventListener('mouseup', (evt) => closeModal(evt));\n modalPreviewZone.addEventListener('touchend', (evt) => closeModal(evt));\n\n const modalPrev = document.createElement('a');\n modalPrev.className = 'modalPrev';\n modalPrev.innerHTML = '❮';\n modalPrev.addEventListener('click', () => modalImageSwitch(-1), true);\n // modalPrev.addEventListener('keydown', modalKeyHandler, true);\n\n const modalNext = document.createElement('a');\n modalNext.className = 'modalNext';\n modalNext.innerHTML = '❯';\n modalNext.addEventListener('click', () => modalImageSwitch(1), true);\n // modalNext.addEventListener('keydown', modalKeyHandler, true);\n\n const modalControls = document.createElement('div');\n modalControls.className = 'modalControls gradio-container';\n\n // build interface\n modal.appendChild(modalPrev);\n modal.appendChild(modalPreviewZone);\n modal.appendChild(modalNext);\n modal.append(modalControls);\n modalControls.appendChild(modalZoom);\n modalControls.appendChild(modalReset);\n modalControls.appendChild(modalTile);\n modalControls.appendChild(modalSave);\n modalControls.appendChild(modalDownload);\n modalControls.appendChild(modalToggleParamsBtn);\n modalControls.appendChild(modalClose);\n modal.append(modalExif);\n\n gradioApp().appendChild(modal);\n const t1 = performance.now();\n log('initImageViewer', Math.round(t1 - t0));\n timer('initImageViewer', t1 - t0);\n}\n\nonAfterUiUpdate(bindImageViewer);\n", "import { log } from './logger';\n\n/*\n * Extra-networks completion for SD.Next prompt textareas.\n *\n * Companion to autocomplete.js: exposes sorted indices for LoRAs, embeddings, and wildcards,\n * each backed by an existing enumeration endpoint. Dispatch and insertion are driven from\n * autocomplete.js via the mode returned by getCurrentWord().\n */\n\ninterface XnItem {\n name: string;\n display?: string;\n}\n\ninterface SearchItem {\n name: string;\n display: string;\n}\n\ntype SearchResult = SearchItem & { kind: 'lora' | 'embed' | 'wildcard' };\n\n/** Binary search for the first item where item.name >= query. */\nexport function lowerBound(items: { name: string }[], query: string): number {\n let lo = 0;\n let hi = items.length;\n while (lo < hi) {\n const mid = (lo + hi) >>> 1;\n if (items[mid].name < query) lo = mid + 1;\n else hi = mid;\n }\n return lo;\n}\n\ninterface XnEngine {\n lora: XnIndex;\n embed: XnIndex;\n wildcard: XnIndex;\n fetchJson(path: string): Promise;\n loadAll(): Promise;\n searchLoras(prefix: string, limit?: number): SearchResult[];\n searchEmbeddings(prefix: string, limit?: number): SearchResult[];\n searchWildcards(prefix: string, limit?: number): SearchResult[];\n}\n\n// -- Indices --\n\nclass XnIndex {\n items: SearchItem[];\n\n constructor(items: XnItem[]) {\n // items: [{ name, display }]. Sorted in-place by lowercase name.\n this.items = items.map(({ name, display }) => ({\n name: String(name).toLowerCase(),\n display: display ?? name,\n }));\n this.items.sort((a, b) => a.name.localeCompare(b.name));\n }\n\n search(prefix: string, limit = 20): SearchItem[] {\n const query = String(prefix).toLowerCase();\n // Empty query returns the first `limit` items so `= 3) {\n for (let i = 0; i < this.items.length && matches.length < limit; i++) {\n if (this.items[i].name.includes(query)) matches.push(this.items[i]);\n }\n }\n return matches.slice(0, limit);\n }\n}\n\n// -- Engine --\n\nexport const xnEngine: XnEngine = {\n lora: new XnIndex([]),\n embed: new XnIndex([]),\n wildcard: new XnIndex([]),\n\n async fetchJson(path) {\n try {\n // const resp = await fetch(`${window.api}${path}`, { credentials: 'include' });\n const resp = await authFetch(`${window.api}${path}`);\n if (!resp?.ok) throw new Error(`${resp?.status}`);\n return await resp.json();\n } catch (e) {\n log('autoComplete', { xnFetchFailed: path, error: String(e) });\n return null;\n }\n },\n\n async loadAll() {\n // LoRAs: [{name, alias, path, metadata}, ...]\n const loraData = await this.fetchJson('/loras');\n if (Array.isArray(loraData)) {\n const items: XnItem[] = [];\n for (const lo of loraData) {\n if (typeof lo === 'object' && lo && 'name' in lo && typeof lo.name === 'string') items.push({ name: lo.name });\n if (typeof lo === 'object' && lo && 'alias' in lo && typeof lo.alias === 'string' && lo.alias !== (lo as { name?: string }).name) items.push({ name: lo.alias });\n }\n this.lora = new XnIndex(items);\n }\n // Embeddings: {loaded: [...], skipped: [...]}\n if (window.opts.diffusers_enable_embed) {\n const embData = await this.fetchJson('/embeddings') as Record | null;\n if (embData && typeof embData === 'object') {\n const loaded = Array.isArray(embData.loaded) ? embData.loaded : [];\n this.embed = new XnIndex(loaded.map((name) => ({ name: String(name) })));\n }\n } else {\n this.embed = new XnIndex([]);\n }\n // Wildcards: [{name}, ...]\n if (window.opts.wildcards_enabled) {\n const wcData = await this.fetchJson('/wildcards');\n if (Array.isArray(wcData)) {\n this.wildcard = new XnIndex(\n wcData\n .filter((w) => typeof w === 'object' && w && 'name' in w && typeof w.name === 'string')\n .map((w) => ({ name: w.name })),\n );\n }\n } else {\n this.wildcard = new XnIndex([]);\n }\n log('autoComplete', {\n xnLoaded: true,\n lora: this.lora.items.length,\n embed: this.embed.items.length,\n wildcard: this.wildcard.items.length,\n });\n },\n\n searchLoras(prefix, limit = 20) {\n return this.lora.search(prefix, limit).map((item) => ({ ...item, kind: 'lora' as const }));\n },\n\n searchEmbeddings(prefix, limit = 20) {\n return this.embed.search(prefix, limit).map((item) => ({ ...item, kind: 'embed' as const }));\n },\n\n searchWildcards(prefix, limit = 20) {\n return this.wildcard.search(prefix, limit).map((item) => ({ ...item, kind: 'wildcard' as const }));\n },\n};\n", "import { xnEngine, lowerBound } from './autocomplete_xn';\nimport { log } from './logger';\nimport { gradioApp, onAfterUiUpdate, onOptionsChanged, executeCallbacks, optionsChangedCallbacks } from './script';\nimport { timer } from './timers';\nimport { updateInput } from './ui';\n\n/*\n * Tag autocomplete for SD.Next prompt textareas.\n *\n * Ported from Enso's CodeMirror-based autocomplete (autocomplete.ts).\n * Uses binary search on sorted tag arrays for O(log n) prefix lookup,\n * with substring fallback for 4+ char queries.\n */\n\n// -- Category colors (unified 14-category scheme) --\n\nconst CATEGORY_COLORS = {\n 0: '#0075f8', // general\n 1: '#cc0000', // artist\n 2: '#ff4500', // studio\n 3: '#9900ff', // copyright\n 4: '#00ab2c', // character\n 5: '#ed5d1f', // species\n 6: '#8a66ff', // genre\n 7: '#00cccc', // medium\n 8: '#6b7280', // meta\n 9: '#228b22', // lore\n 10: '#e67e22', // lens\n 11: '#f1c40f', // lighting\n 12: '#1abc9c', // composition\n 13: '#e84393', // color\n};\n\nconst CATEGORY_NAMES = {\n 0: 'general',\n 1: 'artist',\n 2: 'studio',\n 3: 'copyright',\n 4: 'character',\n 5: 'species',\n 6: 'genre',\n 7: 'medium',\n 8: 'meta',\n 9: 'lore',\n 10: 'lens',\n 11: 'lighting',\n 12: 'composition',\n 13: 'color',\n};\n\n// Glyph + color per result kind. Renders in place of the category dot for non-tag results.\nconst KIND_GLYPHS = {\n tag: { glyph: '\u25CF', color: null }, // color pulled from tag category\n lora: { glyph: '\u25C6', color: '#8a66ff' },\n embed: { glyph: '\u25B2', color: '#1abc9c' },\n wildcard: { glyph: '\u2605', color: '#f1c40f' },\n};\n\nlet active = false;\n\ninterface TagResult {\n name: string;\n display: string;\n category: number | string;\n count: number;\n aliases?: string[];\n matchedVia?: 'alias' | 'translation';\n matchedAlias?: string;\n matchedTerm?: string;\n}\n\n// -- Utilities (ported from Enso) --\n\n/** Format post count as abbreviated string. */\nfunction formatCount(count: number): string {\n if (count >= 1_000_000) return `${(count / 1_000_000).toFixed(1)}M`;\n if (count >= 1_000) return `${Math.round(count / 1_000)}k`;\n return String(count);\n}\n\n/**\n * Estimate viewport Y of the bottom of the caret line using a persistent\n * offscreen mirror div. Styles and width are re-read from the textarea on\n * every call so resized textareas are handled correctly.\n */\nlet caretMirror: HTMLDivElement | null = null;\nlet caretMarker: HTMLSpanElement | null = null;\nconst MIRROR_PROPS = ['fontFamily', 'fontSize', 'fontWeight', 'fontStyle',\n 'lineHeight', 'letterSpacing', 'wordSpacing', 'textTransform',\n 'padding', 'border', 'boxSizing'];\n\nfunction caretViewportY(textarea: HTMLTextAreaElement): number {\n if (!caretMirror) {\n caretMirror = document.createElement('div');\n caretMirror.className = 'autocomplete-mirror';\n caretMirror.style.whiteSpace = 'pre-wrap';\n caretMirror.style.wordWrap = 'break-word';\n caretMirror.style.position = 'absolute';\n caretMirror.style.left = '-9999px';\n caretMirror.style.overflow = 'hidden';\n caretMarker = document.createElement('span');\n caretMarker.textContent = '\\u200b';\n document.body.appendChild(caretMirror);\n }\n const cs = getComputedStyle(textarea);\n for (const p of MIRROR_PROPS) caretMirror.style[p] = cs[p];\n caretMirror.style.width = `${textarea.offsetWidth}px`;\n caretMirror.textContent = textarea.value.substring(0, textarea.selectionStart);\n caretMirror.appendChild(caretMarker);\n const offset = caretMarker.offsetTop + caretMarker.offsetHeight;\n return textarea.getBoundingClientRect().top + offset - textarea.scrollTop;\n}\n\n// -- TagIndex --\n\nclass TagIndex {\n categories: Record;\n tags: TagResult[];\n aliasEntries: { name: string; display: string; tag: TagResult }[];\n translations: Map;\n tagByName: Map;\n translationEntries: { name: string; foreign: string; canonical: string }[];\n\n constructor(data: any) {\n this.categories = data.categories || {};\n // Tuples are [name, catId, count] or [name, catId, count, aliases]. Default `aliases = []`\n // keeps legacy 3-tuple dictionaries working unchanged.\n this.tags = data.tags.map(([name, category, count, aliases = []]) => ({\n name: name.toLowerCase(),\n display: name,\n category,\n count,\n aliases,\n }));\n this.tags.sort((a, b) => a.name.localeCompare(b.name));\n // Alias index parallel to this.tags. Each entry has .name so lowerBound works on both.\n this.aliasEntries = [];\n for (const tag of this.tags) {\n if (!tag.aliases || tag.aliases.length === 0) continue;\n for (const alias of tag.aliases) {\n this.aliasEntries.push({ name: alias.toLowerCase(), display: alias, tag });\n }\n }\n this.aliasEntries.sort((a, b) => a.name.localeCompare(b.name));\n // Optional translations companion: foreign_term -> canonical_tag_name.\n // tagByName is keyed on canonical lowercased name for O(1) resolution from a translation hit.\n this.translations = new Map();\n this.tagByName = new Map(this.tags.map((t) => [t.name, t]));\n if (data.translations && typeof data.translations === 'object') {\n for (const [foreign, canonical] of Object.entries(data.translations)) {\n if (typeof foreign !== 'string' || typeof canonical !== 'string') continue;\n this.translations.set(foreign.toLowerCase(), { canonical: canonical.toLowerCase(), foreign });\n }\n }\n // Sorted translation keys for prefix+substring scan via lowerBound.\n this.translationEntries = [...this.translations.entries()]\n .map(([foreignLower, { canonical, foreign }]) => ({ name: foreignLower, foreign, canonical }))\n .sort((a, b) => a.name.localeCompare(b.name));\n }\n\n /** Prefix search with binary search across canonical names and aliases. Returns matches sorted by count descending. */\n search(prefix: string, limit = 20): TagResult[] {\n const query = prefix.toLowerCase().replace(/ /g, '_');\n if (!query) return [];\n // Canonical prefix matches\n const matches = [];\n const start = lowerBound(this.tags, query);\n for (let i = start; i < this.tags.length && matches.length < limit * 5; i++) {\n if (!this.tags[i].name.startsWith(query)) break;\n matches.push(this.tags[i]);\n }\n // Alias prefix matches. Annotate so render can show \"canonical (alias)\".\n const aliasStart = lowerBound(this.aliasEntries, query);\n for (let i = aliasStart; i < this.aliasEntries.length && matches.length < limit * 10; i++) {\n const entry = this.aliasEntries[i];\n if (!entry.name.startsWith(query)) break;\n matches.push({ ...entry.tag, matchedVia: 'alias', matchedAlias: entry.display });\n }\n // Substring fallback (canonical + aliases) for 4+ char queries when prefix matching returned nothing.\n if (matches.length === 0 && query.length >= 4) {\n for (let i = 0; i < this.tags.length && matches.length < limit * 5; i++) {\n if (this.tags[i].name.includes(query)) matches.push(this.tags[i]);\n }\n for (let i = 0; i < this.aliasEntries.length && matches.length < limit * 10; i++) {\n const entry = this.aliasEntries[i];\n if (entry.name.includes(query)) matches.push({ ...entry.tag, matchedVia: 'alias', matchedAlias: entry.display });\n }\n }\n // Translation lookup. Prefix scan over foreign terms, resolving to canonical tags when present.\n if (this.translationEntries.length > 0) {\n const tStart = lowerBound(this.translationEntries, query);\n for (let i = tStart; i < this.translationEntries.length && matches.length < limit * 10; i++) {\n const entry = this.translationEntries[i];\n if (!entry.name.startsWith(query)) break;\n const canonicalTag = this.tagByName.get(entry.canonical);\n if (canonicalTag) matches.push({ ...canonicalTag, matchedVia: 'translation', matchedTerm: entry.foreign });\n }\n // Substring fallback over translation keys (CJK/short foreign terms benefit from 2-char threshold)\n if (query.length >= 2) {\n for (let i = 0; i < this.translationEntries.length && matches.length < limit * 10; i++) {\n const entry = this.translationEntries[i];\n if (entry.name.includes(query) && !entry.name.startsWith(query)) {\n const canonicalTag = this.tagByName.get(entry.canonical);\n if (canonicalTag) matches.push({ ...canonicalTag, matchedVia: 'translation', matchedTerm: entry.foreign });\n }\n }\n }\n }\n // Dedupe by canonical name; prefer canonical (no matchedVia) over alias/translation matches.\n const seen = new Map();\n for (const tag of matches) {\n const existing = seen.get(tag.name);\n if (!existing || (existing.matchedVia && !tag.matchedVia)) seen.set(tag.name, tag);\n }\n const result = [...seen.values()];\n result.sort((a, b) => b.count - a.count);\n return result.slice(0, limit);\n }\n}\n\n// -- Engine --\n\nconst engine = {\n indices: new Map(), // name -> TagIndex\n categoryColors: { ...CATEGORY_COLORS },\n categoryNames: { ...CATEGORY_NAMES },\n\n async loadEnabled() {\n const enabled = window.opts?.autocomplete_enabled || [];\n active = window.opts?.autocomplete_active || false;\n if (!active) {\n this.indices.clear();\n return;\n }\n const t0 = performance.now();\n const toLoad = enabled.filter((n) => !this.indices.has(n));\n const toRemove = [...this.indices.keys()].filter((n) => !enabled.includes(n));\n toRemove.forEach((n) => this.indices.delete(n));\n await Promise.all(toLoad.map(async (name) => {\n try {\n const resp = await authFetch(`${window.api}/autocomplete/${name}`);\n if (!resp?.ok) throw new Error(`${resp?.status}`);\n const data = await resp.json();\n this.indices.set(name, new TagIndex(data));\n // Extract category colors from first loaded file\n if (data.categories) {\n Object.entries(data.categories).forEach(([id, cat]) => {\n const category: any = cat;\n if (category.color) this.categoryColors[id] = category.color;\n if (category.name) this.categoryNames[id] = category.name;\n });\n }\n const t1 = performance.now();\n log('autoComplete', { loaded: name, tags: data.tags?.length || 0, time: Math.round(t1 - t0) });\n timer(`autocompleteLoad:${name}`, t1 - t0);\n } catch (e) {\n log('autoComplete', { failed: name, error: e });\n }\n }));\n },\n\n searchAll(prefix, limit = 20) {\n if (this.indices.size === 0) return [];\n const all = [];\n this.indices.forEach((index) => {\n all.push(...index.search(prefix, limit));\n });\n // Deduplicate by name, keeping highest count\n const seen = new Map();\n all.forEach((tag) => {\n const existing = seen.get(tag.name);\n if (!existing || tag.count > existing.count) seen.set(tag.name, tag);\n });\n const results = [...seen.values()];\n results.sort((a, b) => b.count - a.count);\n return results.slice(0, limit);\n },\n};\n\n// -- Textarea integration --\n\n/**\n * Extract the current completion context at the cursor position.\n *\n * Returns { word, start, end, mode } where:\n * mode === 'tag': ordinary tag completion\n * mode === 'artist': leading `@` trigger; results filtered to artist category and inserted with `@` preserved\n * mode === 'lora': inside an unclosed ` 0) {\n const ch = value[wordStart - 1];\n if (ch === ',' || ch === '\\n') break;\n wordStart--;\n }\n // Skip leading whitespace between the separator and the typed word\n while (wordStart < selectionStart && value[wordStart] === ' ') wordStart++;\n const segment = value.slice(wordStart, selectionStart);\n // LoRA / extra-network trigger: unclosed `<` with `kind:` prefix\n const before = value.slice(0, selectionStart);\n const lastOpen = before.lastIndexOf('<');\n const lastClose = before.lastIndexOf('>');\n if (lastOpen > lastClose && lastOpen >= wordStart) {\n const inside = before.slice(lastOpen + 1); // e.g. \"lora:foo\", \"lora:\", \"lor\", or \"\"\n const colon = inside.indexOf(':');\n if (colon < 0) {\n // Bare `<` (or `` kind we ship,\n // so browse-all-loras; whatever the user typed gets overwritten on accept.\n return { word: '', start: lastOpen, end: selectionStart, mode: 'lora' };\n }\n if (inside.slice(0, colon).toLowerCase() === 'lora') {\n return { word: inside.slice(colon + 1), start: lastOpen, end: selectionStart, mode: 'lora' };\n }\n // Recognized colon but unknown kind, suppress completion.\n return null;\n }\n // Wildcard trigger: unclosed `__` that doesn't close within the current word\n if (segment.startsWith('__') && !segment.slice(2).includes('__')) {\n return { word: segment.slice(2), start: wordStart, end: selectionStart, mode: 'wildcard' };\n }\n // Artist trigger: leading `@` filters tag results to the artist category.\n if (segment.startsWith('@')) {\n return { word: segment.slice(1), start: wordStart, end: selectionStart, mode: 'artist' };\n }\n // Ordinary tag\n if (!segment) return null;\n return { word: segment, start: wordStart, end: selectionStart, mode: 'tag' };\n}\n\n// Booru schemas (danbooru/e621/sankaku) all assign category id 1 to artist tags.\nconst ARTIST_CATEGORY_ID = 1;\n\n/** Escape bare parens so tag names like `fate_(series)` aren't parsed as attention syntax. */\nfunction escapeParensForPrompt(name) {\n return name.replace(/([()])/g, '\\\\$1');\n}\n\n/**\n * Insert an extra-network reference at the current trigger position.\n * kind === 'lora': inserts `` over the range including the leading `<`\n * kind === 'wildcard': inserts `__name__` over the range including the leading `__`\n * Embeddings use insertTag directly so they go through comma-separator and paren-escape logic.\n */\nfunction insertExtraNetwork(textarea, item, kind) {\n const info = getCurrentWord(textarea);\n if (!info || info.mode !== kind) return;\n const { value } = textarea;\n const before = value.slice(0, info.start);\n const after = value.slice(info.end);\n let insertion;\n if (kind === 'lora') {\n insertion = ``;\n } else if (kind === 'wildcard') {\n insertion = `__${item.display ?? item.name}__`;\n } else {\n return;\n }\n textarea.value = before + insertion + after;\n const cursorPos = before.length + insertion.length;\n textarea.selectionStart = cursorPos;\n textarea.selectionEnd = cursorPos;\n if (typeof updateInput === 'function') updateInput(textarea);\n}\n\n/** Insert a tag at the current word position, replacing the typed prefix. */\nfunction insertTag(textarea, tagName, kind = 'tag') {\n const info = getCurrentWord(textarea);\n if (!info || (info.mode !== 'tag' && info.mode !== 'artist')) return;\n const { value } = textarea;\n const before = value.slice(0, info.start);\n const after = value.slice(info.end);\n // Build insertion: tag + separator. Parens in tag names are escaped so the prompt parser doesn't read them as attention syntax.\n const useComma = window.opts?.autocomplete_append_comma ?? true;\n const sep = useComma ? ',' : '';\n const needsSepBefore = before.length > 0 && before.trimEnd().length > 0 && !before.trimEnd().endsWith(',');\n const prefix = needsSepBefore ? `${sep} ` : '';\n let suffix = `${sep} `;\n if (after.length > 0 && after.trimStart().startsWith(',')) suffix = ' ';\n // Embedding names are file-system identifiers, so underscores must be preserved regardless of the user setting.\n // Tags and artists honor `autocomplete_keep_underscores`; default is to swap `_` for space.\n const keepUnderscores = window.opts?.autocomplete_keep_underscores ?? false;\n let body = tagName;\n if (kind !== 'embed' && !keepUnderscores) body = body.replace(/_/g, ' ');\n // Artist mode optionally keeps the `@` prefix (Anima syntax). The `@` is consumed for non-Anima models.\n if (info.mode === 'artist' && window.opts?.autocomplete_at_prefix_artist) body = `@${body}`;\n const insertion = `${prefix}${escapeParensForPrompt(body)}${suffix}`;\n textarea.value = before.trimEnd() + (before.trimEnd().length > 0 ? ' ' : '') + insertion + after.trimStart();\n // Position cursor after the inserted tag + separator\n const cursorPos = before.trimEnd().length + (before.trimEnd().length > 0 ? 1 : 0) + insertion.length;\n textarea.selectionStart = cursorPos;\n textarea.selectionEnd = cursorPos;\n // Sync with Gradio\n if (typeof updateInput === 'function') updateInput(textarea);\n}\n\n// -- Dropdown --\n\nconst dropdown = {\n el: null,\n listEl: null,\n selectedIndex: -1,\n results: [],\n textarea: null,\n query: '',\n visible: false,\n resizeObserver: null as ResizeObserver | null,\n\n init() {\n this.el = document.createElement('div');\n this.el.className = 'autocompleteResults';\n this.el.style.display = 'none';\n this.listEl = document.createElement('ul');\n this.listEl.className = 'autocompleteResultsList';\n this.el.appendChild(this.listEl);\n document.body.appendChild(this.el);\n this.el.addEventListener('mousedown', (e) => e.preventDefault()); // prevent blur on click\n this.el.addEventListener('click', (e) => {\n const li = e.target.closest('li');\n if (!li) return;\n const idx = [...this.listEl.children].indexOf(li);\n if (idx >= 0 && idx < this.results.length) {\n this.selectedIndex = idx;\n this.accept();\n }\n });\n this.resizeObserver = new ResizeObserver(() => {\n if (this.visible) this.position();\n });\n },\n\n show(results, textarea, query) {\n if (results.length === 0) { this.hide(); return; }\n // Switching textareas: clear prior state so a stale render can't leak across.\n if (this.textarea && this.textarea !== textarea) this.hide();\n if (this.textarea !== textarea) this.resizeObserver?.observe(textarea);\n this.results = results;\n this.textarea = textarea;\n this.query = query || '';\n this.selectedIndex = -1;\n this.render();\n this.position();\n this.el.style.display = '';\n this.visible = true;\n },\n\n hide() {\n if (this.textarea) this.resizeObserver?.unobserve(this.textarea);\n this.textarea = null;\n this.el.style.display = 'none';\n this.visible = false;\n this.results = [];\n this.selectedIndex = -1;\n },\n\n render() {\n const keepUnderscores = window.opts?.autocomplete_keep_underscores ?? false;\n const queryNorm = this.query.toLowerCase().replace(/ /g, '_');\n this.listEl.replaceChildren();\n this.results.forEach((tag, i) => {\n const li = document.createElement('li');\n if (i === this.selectedIndex) li.classList.add('selected');\n const dot = document.createElement('span');\n dot.className = 'autocomplete-category';\n const kind = tag.kind || 'tag';\n const kindStyle = KIND_GLYPHS[kind] || KIND_GLYPHS.tag;\n dot.style.color = kindStyle.color || engine.categoryColors[tag.category] || '#888';\n dot.textContent = kindStyle.glyph;\n dot.title = kind === 'tag' ? (engine.categoryNames[tag.category] || '') : kind;\n const name = document.createElement('span');\n name.className = 'autocomplete-tag';\n // Embeddings are file-name identifiers, so they always render as-is to match how they get inserted.\n const swapForKind = kind !== 'embed';\n const tagText = (swapForKind && !keepUnderscores) ? tag.display.replace(/_/g, ' ') : tag.display;\n const canonicalMatch = tag.name.indexOf(queryNorm);\n if (canonicalMatch >= 0 && queryNorm.length > 0) {\n const mark = document.createElement('mark');\n mark.textContent = tagText.slice(canonicalMatch, canonicalMatch + queryNorm.length);\n name.append(\n document.createTextNode(tagText.slice(0, canonicalMatch)),\n mark,\n document.createTextNode(tagText.slice(canonicalMatch + queryNorm.length)),\n );\n } else {\n name.textContent = tagText;\n }\n // Alias/translation-matched rows append \" (foreign)\" with the query fragment highlighted.\n let annotationTerm = null;\n if (tag.matchedVia === 'alias') annotationTerm = tag.matchedAlias;\n else if (tag.matchedVia === 'translation') annotationTerm = tag.matchedTerm;\n if (annotationTerm) {\n const annotationDisplay = (swapForKind && !keepUnderscores) ? annotationTerm.replace(/_/g, ' ') : annotationTerm;\n const annotationLower = annotationTerm.toLowerCase();\n const annotationMatch = annotationLower.indexOf(queryNorm);\n const prefix = tag.matchedVia === 'translation' ? ' \\u{1F310} ' : ' (';\n const suffix = tag.matchedVia === 'translation' ? '' : ')';\n name.appendChild(document.createTextNode(prefix));\n if (annotationMatch >= 0 && queryNorm.length > 0) {\n const mark = document.createElement('mark');\n mark.textContent = annotationDisplay.slice(annotationMatch, annotationMatch + queryNorm.length);\n name.append(\n document.createTextNode(annotationDisplay.slice(0, annotationMatch)),\n mark,\n document.createTextNode(annotationDisplay.slice(annotationMatch + queryNorm.length)),\n );\n } else {\n name.appendChild(document.createTextNode(annotationDisplay));\n }\n if (suffix) name.appendChild(document.createTextNode(suffix));\n }\n const count = document.createElement('span');\n count.className = 'autocomplete-count';\n count.textContent = tag.count > 0 ? formatCount(tag.count) : '';\n li.append(dot, name, count);\n li.addEventListener('mouseenter', () => {\n this.selectedIndex = i;\n this.updateSelection();\n });\n this.listEl.appendChild(li);\n });\n },\n\n position() {\n if (!this.textarea) return;\n const rect = this.textarea.getBoundingClientRect();\n // Position near the caret line instead of the textarea bottom\n const cursorBottom = caretViewportY(this.textarea);\n const anchorY = Math.max(rect.top, Math.min(cursorBottom, rect.bottom));\n const spaceBelow = window.innerHeight - anchorY;\n const dropHeight = Math.min(this.el.scrollHeight, 300);\n if (spaceBelow >= dropHeight || spaceBelow >= anchorY - rect.top) {\n this.el.style.top = `${anchorY + 2}px`;\n } else {\n this.el.style.top = `${anchorY - dropHeight - 2}px`;\n }\n this.el.style.left = `${rect.left}px`;\n this.el.style.width = `${rect.width}px`;\n },\n\n updateSelection() {\n [...this.listEl.children].forEach((li, i) => {\n li.classList.toggle('selected', i === this.selectedIndex);\n });\n const selected = this.listEl.children[this.selectedIndex];\n if (selected) selected.scrollIntoView({ block: 'nearest' });\n },\n\n navigate(dir) {\n if (this.results.length === 0) return;\n if (this.selectedIndex === -1) {\n this.selectedIndex = dir > 0 ? 0 : this.results.length - 1;\n } else {\n this.selectedIndex = (this.selectedIndex + dir + this.results.length) % this.results.length;\n }\n this.updateSelection();\n },\n\n accept() {\n if (this.selectedIndex < 0 || this.selectedIndex >= this.results.length) {\n // Tab with no selection: select first\n if (this.results.length > 0) {\n this.selectedIndex = 0;\n this.updateSelection();\n }\n return;\n }\n const result = this.results[this.selectedIndex];\n if (this.textarea) {\n if (result.kind === 'lora' || result.kind === 'wildcard') {\n insertExtraNetwork(this.textarea, result, result.kind);\n } else {\n // 'embed' kind and untagged tag results both go through insertTag (comma-aware, paren-escaped).\n insertTag(this.textarea, result.display ?? result.name, result.kind);\n }\n }\n this.hide();\n },\n};\n\n// -- Event handlers --\n\nlet debounceInput: ReturnType | undefined;\nlet debounceFocus: ReturnType | undefined;\n\nfunction onInput(textarea) {\n if (!active) return;\n // IME candidate window open: value isn't committed, and Enter would race with tag accept.\n if (textarea.dataset.imeActive === '1') return;\n const minChars = window.opts?.autocomplete_min_chars ?? 3;\n const info = getCurrentWord(textarea);\n if (!info) {\n dropdown.hide();\n return;\n }\n // Threshold by mode. Trigger characters carry their own signal so we can lower (or zero) the bar.\n let threshold = minChars;\n if (info.mode === 'lora' || info.mode === 'wildcard') threshold = 0;\n else if (info.mode === 'artist') threshold = 1;\n if (info.word.length < threshold) {\n dropdown.hide();\n return;\n }\n clearTimeout(debounceInput);\n debounceInput = setTimeout(() => {\n let results;\n if (info.mode === 'lora') {\n results = xnEngine.searchLoras(info.word);\n } else if (info.mode === 'wildcard') {\n results = xnEngine.searchWildcards(info.word);\n } else if (info.mode === 'artist') {\n // `@` trigger: tag-search filtered to the artist category. The category-1 color carries the visual cue.\n results = engine.searchAll(info.word).filter((t) => t.category === ARTIST_CATEGORY_ID);\n } else {\n const tagResults = engine.searchAll(info.word);\n const embedResults = xnEngine.searchEmbeddings(info.word);\n // Embeddings fold into tag-mode results (a1111 tagcomplete parity).\n results = [...embedResults, ...tagResults];\n }\n dropdown.show(results, textarea, info.word);\n }, 150);\n}\n\nfunction onKeyDown(e) {\n if (!dropdown.visible) return;\n if (e.isComposing) return; // IME candidate selection, let the browser commit the candidate\n // Modifier + nav/accept keys belong to other handlers (editAttention.js on Ctrl+Arrow,\n // generate hotkey on Ctrl+Enter). Let them through even with the dropdown open.\n const hasModifier = e.ctrlKey || e.metaKey || e.altKey;\n switch (e.key) {\n case 'ArrowDown':\n if (hasModifier) return;\n e.preventDefault();\n e.stopPropagation();\n dropdown.navigate(1);\n break;\n case 'ArrowUp':\n if (hasModifier) return;\n e.preventDefault();\n e.stopPropagation();\n dropdown.navigate(-1);\n break;\n case 'Enter':\n if (hasModifier) return;\n if (dropdown.selectedIndex >= 0) {\n e.preventDefault();\n e.stopPropagation();\n dropdown.accept();\n }\n break;\n case 'Tab':\n if (hasModifier) return;\n e.preventDefault();\n e.stopPropagation();\n dropdown.accept();\n break;\n case 'Escape':\n e.preventDefault();\n e.stopPropagation();\n dropdown.hide();\n break;\n default:\n break;\n }\n}\n\n/** Attach autocomplete to a single textarea. */\nfunction attachAutocomplete(textarea) {\n textarea.addEventListener('input', () => onInput(textarea));\n textarea.addEventListener('keydown', onKeyDown);\n textarea.addEventListener('compositionstart', () => { textarea.dataset.imeActive = '1'; });\n textarea.addEventListener('compositionend', () => { delete textarea.dataset.imeActive; });\n textarea.addEventListener('focusin', () => {\n if (dropdown.visible && dropdown.textarea && dropdown.textarea !== textarea) dropdown.hide();\n // Cancel any pending hide from a recent blur so refocusing within 200ms doesn't close the dropdown.\n clearTimeout(debounceFocus);\n debounceFocus = undefined;\n // Re-fire input handling so a partial tag at the cursor reopens the dropdown.\n onInput(textarea);\n });\n textarea.addEventListener('focusout', () => {\n // Cancel any in-flight debounced dropdown.show; otherwise it fires against a stale textarea.\n clearTimeout(debounceInput);\n debounceFocus = setTimeout(() => dropdown.hide(), 200);\n });\n}\n\n// -- Prompt textarea IDs --\n\nconst PROMPT_IDS = [\n 'txt2img_prompt', 'txt2img_neg_prompt',\n 'img2img_prompt', 'img2img_neg_prompt',\n 'control_prompt', 'control_neg_prompt',\n 'video_prompt', 'video_neg_prompt',\n];\n\n// -- Active button --\n\nfunction patchActiveButton() {\n const buttons = [...gradioApp().querySelectorAll('.autocomplete-active')];\n active = window.opts?.autocomplete_active || false;\n buttons.forEach((btn) => {\n btn.classList.toggle('autocomplete-active', active);\n btn.classList.toggle('autocomplete-inactive', !active);\n btn.parentElement.onclick = () => {\n active = !active;\n window.opts.autocomplete_active = !active;\n btn.classList.toggle('autocomplete-active', active);\n btn.classList.toggle('autocomplete-inactive', !active);\n };\n });\n}\n\n// -- Config bridge --\n\n/** Monkey-patch script config bridge textboxes to push autocomplete config changes to window.opts immediately. */\nlet bridgeWarnedMissingDescriptor = false;\nfunction patchConfigBridge() {\n const proto = Object.getOwnPropertyDescriptor(HTMLTextAreaElement.prototype, 'value');\n if (!proto?.get || !proto?.set) {\n if (!bridgeWarnedMissingDescriptor) {\n log('autoComplete', { bridge: 'skipped', reason: 'HTMLTextAreaElement.prototype.value descriptor missing' });\n bridgeWarnedMissingDescriptor = true;\n }\n return;\n }\n const elements = gradioApp().querySelectorAll('[id$=\"_tag_autocomplete_config_json\"]');\n for (const el of elements) {\n const textarea = el.querySelector('textarea');\n if (!textarea || textarea.acBridgePatched) continue;\n textarea.acBridgePatched = true;\n Object.defineProperty(textarea, 'value', {\n set(newValue) {\n const oldValue = proto.get.call(textarea);\n proto.set.call(textarea, newValue);\n if (oldValue !== newValue && newValue) {\n try {\n const cfg = JSON.parse(newValue);\n for (const [key, val] of Object.entries(cfg)) window.opts[key] = val;\n executeCallbacks(optionsChangedCallbacks);\n } catch { /* ignore parse errors; the bridge is best-effort */ }\n }\n },\n get() { return proto.get.call(textarea); },\n });\n }\n}\n\n// -- Initialization --\n\nexport async function initAutocomplete() {\n const t0 = performance.now();\n const enabled = window.opts?.autocomplete_enabled || [];\n active = window.opts?.autocomplete_active || false;\n log('autoComplete', { active, enabled });\n // Inject styles (CSS files in javascript/ are not auto-loaded)\n const style = document.createElement('style');\n style.textContent = `\n .autocompleteResults { position: fixed; z-index: 9999; max-height: 300px; overflow-y: auto;\n background: var(--sd-main-background-color, var(--background-fill-primary, #1f2937));\n border: 1px solid var(--sd-input-border-color, var(--border-color-primary, #374151));\n border-radius: var(--sd-border-radius, 6px); box-shadow: 0 4px 16px rgba(0,0,0,0.4);\n font-size: 13px; scrollbar-width: thin; color: var(--body-text-color-subdued); }\n .autocompleteResultsList { list-style: none; margin: 0; padding: 4px 0; }\n .autocompleteResultsList > li { display: flex; align-items: center; padding: 6px 12px; cursor: pointer;\n gap: 8px; line-height: 1.4; transition: background 0.1s ease; border-bottom: 1px solid rgba(255,255,255,0.03); }\n .autocompleteResultsList > li:last-child { border-bottom: none; }\n .autocompleteResultsList > li:hover { background: var(--sd-panel-background-color, var(--input-background-fill-focus, #374151)); }\n .autocompleteResultsList > li.selected { background: var(--sd-main-accent-color, var(--button-primary-background-fill, #4b5563)); }\n .autocomplete-category { font-size: 10px; flex-shrink: 0; width: 10px; text-align: center; cursor: help; }\n .autocomplete-tag { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n .autocomplete-tag mark { background: transparent; color: inherit; font-weight: 700; }\n .autocomplete-count { font-size: 0.75em; opacity: 0.45; flex-shrink: 0; font-variant-numeric: tabular-nums;\n background: rgba(255,255,255,0.06); padding: 1px 6px; border-radius: 8px; min-width: 28px; text-align: right; }\n `;\n document.head.appendChild(style);\n dropdown.init();\n await engine.loadEnabled();\n xnEngine.loadAll();\n // Attach to all prompt textareas; even if no dictionaries loaded yet, they may be enabled later via script UI\n let attached = 0;\n PROMPT_IDS.forEach((id) => {\n const textarea = gradioApp().querySelector(`#${id} > label > textarea`);\n if (textarea) {\n attachAutocomplete(textarea);\n attached++;\n }\n });\n // Reload when settings change\n\n async function optionsChangedCallback() {\n const newActive = window.opts?.autocomplete_active || false;\n const newEnabled = window.opts?.autocomplete_enabled || [];\n const currentKeys = [...engine.indices.keys()].sort().join(',');\n const newKeys = [...newEnabled].sort().join(',');\n if ((currentKeys !== newKeys) || (active !== newActive)) {\n log('autoComplete', { reload: newEnabled });\n await engine.loadEnabled();\n active = newActive;\n patchActiveButton();\n }\n xnEngine.loadAll();\n }\n onOptionsChanged(optionsChangedCallback);\n // Watch for config updates from the script UI bridge\n patchConfigBridge();\n patchActiveButton();\n onAfterUiUpdate(patchConfigBridge);\n const t1 = performance.now();\n log('autoComplete', { attached, dicts: engine.indices.size, time: Math.round(t1 - t0) });\n timer('autocompleteInit', t1 - t0);\n}\n", "/* eslint-disable @typescript-eslint/no-use-before-define */\nimport { log } from './logger';\nimport { gradioApp } from './script';\nimport { timer } from './timers';\n\nlet hintsObserver: MutationObserver | null = null;\nconst allLocales = ['en', 'tb', 'nb', 'hr', 'es', 'it', 'fr', 'de', 'pt', 'ru', 'zh', 'ja', 'ko', 'hi', 'ar', 'bn', 'ur', 'id', 'vi', 'tr', 'sr', 'po', 'he', 'xx', 'qq', 'tlh'];\nconst localeData = {\n prev: null,\n locale: null,\n data: [],\n timeout: null,\n finished: false,\n initial: true,\n type: 2,\n hint: null,\n btn: null,\n expandTimeout: undefined, // Property for expansion timeout\n currentElement: null, // Track current element for expansion\n};\nlet localeTimeout: ReturnType | undefined;\nconst isTouchDevice = 'ontouchstart' in window;\n\nasync function cycleLocale() {\n clearTimeout(localeTimeout);\n localeTimeout = setTimeout(() => {\n log('cycleLocale', localeData.prev, localeData.locale);\n const index = allLocales.indexOf(localeData.prev);\n localeData.locale = allLocales[(index + 1) % allLocales.length];\n localeData.btn.innerText = localeData.locale;\n // localeData.btn.style.backgroundColor = localeData.locale !== 'en' ? 'var(--primary-500)' : '';\n localeData.finished = false;\n localeData.data = [];\n localeData.prev = localeData.locale;\n window.opts.ui_locale = localeData.locale;\n setHints();\n }, 250);\n}\n\nasync function resetLocale() {\n clearTimeout(localeTimeout); // Prevent the single click logic\n localeData.locale = 'en';\n log('resetLocale', localeData.locale);\n const index = allLocales.indexOf(localeData.locale);\n localeData.locale = allLocales[(index) % allLocales.length];\n localeData.btn.innerText = localeData.locale;\n localeData.finished = false;\n localeData.data = [];\n window.opts.ui_locale = localeData.locale;\n setHints();\n}\n\nasync function tooltipCreate() {\n localeData.hint = document.createElement('div');\n localeData.hint.className = 'tooltip';\n localeData.hint.id = 'tooltip-container';\n localeData.hint.innerText = 'this is a hint';\n gradioApp().appendChild(localeData.hint);\n localeData.btn = gradioApp().getElementById('locale-container');\n if (!localeData.btn) {\n localeData.btn = document.createElement('div');\n localeData.btn.className = 'locale';\n localeData.btn.id = 'locale-container';\n gradioApp().appendChild(localeData.btn);\n }\n localeData.btn.innerText = localeData.locale;\n localeData.btn.ondblclick = resetLocale;\n localeData.btn.onclick = cycleLocale;\n if (window.opts.tooltips === 'None') localeData.type = 0;\n if (window.opts.tooltips === 'Browser default') localeData.type = 1;\n if (window.opts.tooltips === 'UI tooltips') localeData.type = 2;\n\n if (localeData.type === 2) { // setup event delegation for tooltips instead of individual listeners\n if (isTouchDevice) {\n gradioApp().addEventListener('touchstart', tooltipShowDelegated);\n gradioApp().addEventListener('touchend', tooltipHideDelegated);\n }\n gradioApp().addEventListener('pointerover', tooltipShowDelegated);\n gradioApp().addEventListener('pointerout', tooltipHideDelegated);\n }\n if (!hintsObserver) initializeDOMObserver();\n}\n\nasync function expandTooltip(element, longHint) {\n if (localeData.currentElement === element && localeData.hint.classList.contains('tooltip-show')) {\n const ring = localeData.hint.querySelector('.tooltip-progress-ring');\n if (ring) ring.style.opacity = '0';\n localeData.hint.classList.add('tooltip-expanded');\n setTimeout(() => {\n const longContent = localeData.hint.querySelector('.long-content');\n if (longContent) longContent.classList.add('show');\n }, 100);\n }\n}\n\nasync function tooltipShowDelegated(e) { // use event delegation to handle dynamically created elements\n if (e.target.dataset && e.target.dataset.hint) tooltipShow(e);\n}\n\nasync function tooltipHideDelegated(e) {\n if (e.target.dataset && e.target.dataset.hint) tooltipHide(e);\n}\n\nasync function tooltipShow(e) {\n if (localeData.expandTimeout) { // clear any existing expansion timeout\n clearTimeout(localeData.expandTimeout);\n localeData.expandTimeout = undefined;\n }\n\n localeData.hint.classList.remove('tooltip-expanded'); // remove expanded class and reset current element\n localeData.currentElement = e.target;\n\n if (e.target.dataset.hint) {\n const progressRing = ` // create progress ring SVG\n
    \n \n \n \n \n
    \n `;\n // set up the complete content structure from the start\n let content = `\n
    \n ${e.target.textContent}\n ${e.target.dataset.longHint ? progressRing : ''}\n
    \n
    \n ${e.target.dataset.hint}\n `;\n if (e.target.dataset.longHint) content += `
    ${e.target.dataset.longHint}
    `; // add long content if available, but keep it hidden\n if (e.target.dataset.reload) { // add reload notice if needed\n const reloadType = e.target.dataset.reload;\n let reloadText = '';\n if (reloadType === 'model') reloadText = 'Requires model reload';\n else if (reloadType === 'server') reloadText = 'Requires server restart';\n if (reloadText) {\n content += `\n
    \n
    \n ${reloadText}\n
    \n `;\n }\n }\n\n localeData.hint.innerHTML = content;\n localeData.hint.classList.add('tooltip-show');\n\n if (e.clientX > window.innerWidth / 2) localeData.hint.classList.add('tooltip-left');\n else localeData.hint.classList.remove('tooltip-left');\n\n if (e.target.dataset.longHint) { // set up expansion timer if long hint is available\n const ring = localeData.hint.querySelector('.tooltip-progress-ring'); // start progress ring animation\n const ringProgress = localeData.hint.querySelector('.ring-progress');\n if (ring && ringProgress) {\n setTimeout(() => {\n ring.classList.add('active');\n ringProgress.classList.add('animate');\n }, 100);\n }\n localeData.expandTimeout = setTimeout(() => expandTooltip(e.target, e.target.dataset.longHint), 3000);\n }\n }\n}\n\nasync function tooltipHide(e) {\n if (localeData.expandTimeout) {\n clearTimeout(localeData.expandTimeout);\n localeData.expandTimeout = undefined;\n }\n localeData.hint.classList.remove('tooltip-show', 'tooltip-expanded');\n localeData.currentElement = null;\n}\n\nasync function replaceButtonText(el) {\n // https://www.nerdfonts.com/cheat-sheet\n // use unicode of icon with format nf-md-_circle\n const textIcons = {\n Generate: '\\uf144',\n Enqueue: '\\udb81\\udc17',\n Stop: '\\udb81\\ude66',\n Skip: '\\udb81\\ude61',\n Pause: '\\udb80\\udfe5',\n Restore: '\\udb82\\udd9b',\n Clear: '\\udb80\\udd59',\n Networks: '\\uf261',\n };\n if (textIcons[el.innerText]) {\n el.classList.add('button-icon');\n el.innerText = textIcons[el.innerText];\n }\n}\n\nasync function getLocaleData(desiredLocale = null) {\n if (desiredLocale) desiredLocale = desiredLocale.split(':')[0];\n if (desiredLocale === 'Auto') {\n try {\n localeData.locale = navigator.languages && navigator.languages.length ? navigator.languages[0] : navigator.language;\n localeData.locale = localeData.locale.split('-')[0];\n localeData.prev = localeData.locale;\n } catch (e) {\n localeData.locale = 'en';\n log('getLocale', e);\n }\n } else {\n localeData.locale = desiredLocale || 'en';\n localeData.prev = localeData.locale;\n }\n log('getLocale', { lang: desiredLocale, locale: localeData.locale });\n // primary\n let json: any = {};\n try {\n let res = await authFetch(`${window.subpath}/file=ui/locale/locale_${localeData.locale}.json`);\n if (!res || !res.ok) {\n localeData.locale = 'en';\n res = await authFetch(`${window.subpath}/file=ui/locale/locale_${localeData.locale}.json`);\n }\n json = await res.json();\n } catch { /**/ }\n\n try {\n const res = await authFetch(`${window.subpath}/file=ui/locale/override_${localeData.locale}.json`);\n if (res && res.ok) json.override = await res.json();\n } catch { /**/ }\n\n return json;\n}\n\nasync function replaceTextContent(el, text) {\n if (el.children.length === 1 && el.firstElementChild.classList.contains('mask-icon')) return;\n if (el.querySelector('span')) el = el.querySelector('span');\n if (el.querySelector('div')) el = el.querySelector('div');\n if (el.classList.contains('mask-icon')) return; // skip icon buttons\n if (el.dataset.selector) { // replace on rehosted child if exists\n el = el.firstElementChild || el.querySelector(el.dataset.selector);\n replaceTextContent(el, text);\n return;\n }\n el.textContent = text;\n}\n\nasync function setHint(el, entry) {\n if (localeData.type === 1) {\n el.title = entry.hint;\n } else if (localeData.type === 2) {\n el.dataset.hint = entry.hint;\n if (entry.longHint && entry.longHint.length > 0) el.dataset.longHint = entry.longHint;\n if (entry.reload && entry.reload.length > 0) el.dataset.reload = entry.reload;\n } else {\n // tooltips disabled\n }\n}\n\nfunction createLocaleJSON() {\n const excludeText = ['\u25BC']; // add any common non-label elements to exclude\n const ecxcludeIds = ['logo_nav']; // add any specific element IDs to exclude\n const elements = [...new Set([\n ...Array.from(gradioApp().querySelectorAll('button')),\n ...Array.from(gradioApp().querySelectorAll('h1')),\n ...Array.from(gradioApp().querySelectorAll('h2')),\n ...Array.from(gradioApp().querySelectorAll('h3')),\n ...Array.from(gradioApp().querySelectorAll('.hint')),\n ...Array.from(gradioApp().querySelectorAll('label > span')),\n ...Array.from(gradioApp().querySelectorAll('.label-wrap > span')),\n ...Array.from(gradioApp().querySelectorAll('span[data-testid=\"block-info\"]')),\n ])];\n const json = {};\n const allSeen = {};\n for (const el of elements) {\n const label = el.textContent.trim();\n if (!label || label.length < 1 || label.length > 1024) continue; // likely not UI element\n if (excludeText.includes(label)) continue; // skip common non-label elements\n if (ecxcludeIds.includes(el.id)) continue; // skip specific element IDs\n\n let hint = el.dataset.hint || '';\n if (hint.toLowerCase() === label.toLowerCase()) hint = ''; // skip if hint is same as label\n if (Object.keys(allSeen).includes(label.toLowerCase())) {\n if (hint.length === 0 || allSeen[label.toLowerCase()] === hint) continue; // seen this label and hint is empty or same as before\n hint = allSeen[label.toLowerCase()]; // use existing hint for this label\n }\n allSeen[label.toLowerCase()] = hint; // track seen labels\n\n let section = label[0].toLowerCase();\n if (section >= '0' && section <= '9') section = '0';\n if ((section < 'a' || section > 'z') && section !== '0') section = '_';\n\n let ui = el.closest('.group-extension')\n || el.closest('.group-scripts')\n || el.closest('.main-tab')\n || el.closest('.settings_section')\n || el.closest('.tabitem')\n || 'other';\n ui = ui?.id?.replace('_tabitem_parent', '').replace('_section_row', '');\n if (ui?.includes('_script')) ui = ui?.split('_').slice(1).join('_').split(':')[0];\n\n if (!json[section]) json[section] = [];\n const entry = { id: el.id || '', label, localized: '', hint, ui };\n json[section].push(entry); // add new entry\n }\n const sorted = Object.keys(json).sort().reduce((obj, key) => {\n obj[key] = json[key];\n return obj;\n }, {});\n console.log('localeJSON', sorted);\n}\n\nexport async function setHints() {\n let json: any;\n let overrideData: any[] = [];\n if (localeData.finished) return;\n if (Object.keys(opts).length === 0) return;\n const elements = [...new Set([\n ...Array.from(gradioApp().querySelectorAll('button')),\n ...Array.from(gradioApp().querySelectorAll('h2')),\n ...Array.from(gradioApp().querySelectorAll('label > span')),\n ...Array.from(gradioApp().querySelectorAll('.label-wrap > span')),\n ...Array.from(gradioApp().querySelectorAll('span[data-testid=\"block-info\"]')), // radio/checkboxgroup titles render as a bare block-info span, not under a label\n ])];\n if (elements.length === 0) return;\n if (localeData.data.length === 0) {\n json = await getLocaleData(window.opts.ui_locale);\n overrideData = Object.values(json.override || {}).flat().filter((e: any) => e.hint.length > 0);\n const jsonData = Object.values(json).flat().filter((e: any) => e.hint.length > 0);\n localeData.data = [...overrideData, ...jsonData];\n }\n if (!localeData.hint) tooltipCreate();\n let localized = 0;\n let hints = 0;\n const t0 = performance.now();\n\n for (const el of elements) {\n // localize elements text\n let found;\n if (el.id) found = localeData.data.find((l) => l.id && (l.id === el.id || el.id.endsWith(l.id))); // prefer id match for disambiguation\n if (!found) {\n if (el.dataset.original) found = localeData.data.find((l) => l.label.toLowerCase().trim() === el.dataset.original.toLowerCase().trim());\n else found = localeData.data.find((l) => l.label.toLowerCase().trim() === el.textContent.toLowerCase().trim());\n }\n if (found?.localized?.length > 0) {\n if (!el.dataset.original) el.dataset.original = el.textContent;\n replaceTextContent(el, found.localized);\n localized++;\n } else if (found?.label && !localeData.initial && (localeData.locale === 'en')) { // reset to english\n replaceTextContent(el, found.label);\n }\n // set hints\n if (found?.hint?.length > 0) {\n hints++;\n setHint(el, found);\n }\n }\n localeData.finished = true;\n localeData.initial = false;\n const t1 = performance.now();\n timer('setHints', t1 - t0);\n // localeData.btn.style.backgroundColor = localeData.locale !== 'en' ? 'var(--primary-500)' : '';\n log('touchDevice', isTouchDevice);\n log('setHints', { type: localeData.type, locale: localeData.locale, elements: elements.length, localized, hints, data: localeData.data.length, override: overrideData.length, time: Math.round(t1 - t0) });\n // sortUIElements();\n}\n\n// Apply hints to a single element immediately\nasync function applyHintToElement(el) {\n if (!localeData.data || localeData.data.length === 0) return;\n // if (!el.textContent) return;\n\n // check if element matches our selector criteria\n const isValidElement = el.tagName === 'BUTTON'\n || el.tagName === 'H2'\n || el.classList.contains('hint')\n || (el.tagName === 'SPAN' && (el.parentElement?.tagName === 'LABEL' || el.parentElement?.classList.contains('label-wrap') || el.dataset.testid === 'block-info'));\n if (!isValidElement) return;\n\n let found; // find matching hint data - prefer id match for disambiguation\n if (el.id) found = localeData.data.find((l) => l.id && (l.id === el.id || el.id.endsWith(l.id)));\n if (!found) {\n if (el.dataset.original) found = localeData.data.find((l) => l.label.toLowerCase().trim() === el.dataset.original.toLowerCase().trim());\n else found = localeData.data.find((l) => l.label.toLowerCase().trim() === el.textContent.toLowerCase().trim());\n }\n\n if (el.textContent && el.textContent.length > 0 && found?.localized?.length > 0) { // apply localization if found\n if (!el.dataset.original) el.dataset.original = el.textContent;\n replaceTextContent(el, found.localized);\n }\n\n if (found?.hint?.length > 0) setHint(el, found); // apply hint if found\n}\n\n// Initialize MutationObserver for immediate hint application\nfunction initializeDOMObserver() {\n if (hintsObserver) hintsObserver.disconnect();\n\n hintsObserver = new MutationObserver((mutations) => {\n // Process added nodes immediately\n for (const mutation of mutations) {\n if (mutation.type === 'childList') {\n for (const node of mutation.addedNodes) {\n if (node.nodeType === Node.ELEMENT_NODE) {\n // Apply hints to the node itself\n applyHintToElement(node);\n\n // Apply hints to all relevant children\n const elements = [\n ...Array.from(node.querySelectorAll('button')),\n ...Array.from(gradioApp().querySelectorAll('h1')),\n ...Array.from(gradioApp().querySelectorAll('h2')),\n ...Array.from(gradioApp().querySelectorAll('h3')),\n ...Array.from(gradioApp().querySelectorAll('.hint')),\n ...Array.from(node.querySelectorAll('label > span')),\n ...Array.from(node.querySelectorAll('.label-wrap > span')),\n ...Array.from(node.querySelectorAll('span[data-testid=\"block-info\"]')),\n ];\n\n // Include the node itself if it matches\n if (node.matches && (\n node.matches('button')\n || node.matches('h1')\n || node.matches('h2')\n || node.matches('h3')\n || node.matches('label > span')\n || node.matches('.hint')\n || node.matches('.label-wrap > span')\n || node.matches('span[data-testid=\"block-info\"]')\n )) {\n elements.push(node);\n }\n\n // Apply hints immediately to all found elements\n elements.forEach((el) => applyHintToElement(el));\n }\n }\n }\n }\n });\n\n // Start observing the entire gradio app for changes\n const targetNode = gradioApp();\n if (targetNode) {\n hintsObserver.observe(targetNode, {\n childList: true,\n subtree: true,\n });\n }\n}\n\nexport function disconnectHintsObserver() {\n if (hintsObserver) {\n hintsObserver.disconnect();\n hintsObserver = null;\n }\n}\n\n// Export for external use if needed\nconst forceReapplyHints = () => setHints();\n", "import { gradioApp, getUICurrentTabContent } from './script';\nimport { log } from './logger';\nimport { authFetch } from './authWrap';\nimport { quickApplyStyle, quickSaveStyle } from './extraNetworks';\n\ninterface ContextMenuItem {\n id: string;\n name: string;\n func: () => void;\n primary: boolean;\n}\n\nconst contextMenuInit = () => {\n let eventListenerApplied = false;\n const menuSpecs = new Map();\n\n const uid = () => Date.now().toString(36) + Math.random().toString(36).substring(2);\n\n function showContextMenu(event: MouseEvent, _element: Element, menuEntries: ContextMenuItem[]): void {\n const posx = event.clientX + document.body.scrollLeft + document.documentElement.scrollLeft;\n const posy = event.clientY + document.body.scrollTop + document.documentElement.scrollTop;\n const oldMenu = gradioApp().querySelector('#context-menu');\n if (oldMenu) oldMenu.remove();\n const contextMenu = document.createElement('nav');\n contextMenu.id = 'context-menu';\n contextMenu.style.top = `${posy}px`;\n contextMenu.style.left = `${posx}px`;\n const contextMenuList = document.createElement('ul');\n contextMenuList.className = 'context-menu-items';\n contextMenu.append(contextMenuList);\n menuEntries.forEach((entry) => {\n const contextMenuEntry = document.createElement('a');\n contextMenuEntry.innerHTML = entry.name;\n contextMenuEntry.addEventListener('click', () => entry.func());\n contextMenuList.append(contextMenuEntry);\n });\n gradioApp().appendChild(contextMenu);\n const menuWidth = contextMenu.offsetWidth + 4;\n const menuHeight = contextMenu.offsetHeight + 4;\n const windowWidth = window.innerWidth;\n const windowHeight = window.innerHeight;\n if ((windowWidth - posx) < menuWidth) contextMenu.style.left = `${windowWidth - menuWidth}px`;\n if ((windowHeight - posy) < menuHeight) contextMenu.style.top = `${windowHeight - menuHeight}px`;\n }\n\n function appendContextMenuOption(targetElementSelector: string, entryName: string, entryFunction: () => void, primary = false): string {\n let currentItems = menuSpecs.get(targetElementSelector);\n if (!currentItems) {\n currentItems = [];\n menuSpecs.set(targetElementSelector, currentItems);\n }\n const newItem = {\n id: `${targetElementSelector}_${uid()}`,\n name: entryName,\n func: entryFunction,\n primary,\n // isNew: true,\n };\n currentItems.push(newItem);\n return newItem.id;\n }\n\n function removeContextMenuOption(id: string): void {\n menuSpecs.forEach((v, k) => {\n let index = -1;\n v.forEach((e, ei) => {\n if (e.id === id) { index = ei; }\n });\n if (index >= 0) v.splice(index, 1);\n });\n }\n\n window.appendContextMenuOption = appendContextMenuOption;\n window.removeContextMenuOption = removeContextMenuOption;\n\n async function addContextMenuEventListener(): Promise {\n if (eventListenerApplied) return;\n log('initContextMenu');\n gradioApp().addEventListener('click', (e: Event) => {\n const mouseEvent = e as MouseEvent;\n if (!mouseEvent.isTrusted) return;\n const oldMenu = gradioApp().querySelector('#context-menu');\n if (oldMenu) oldMenu.remove();\n menuSpecs.forEach((v, k) => {\n const items = v.filter((item) => item.primary);\n const target = mouseEvent.target as Element | null;\n if (!target) return;\n const matched = target.closest(k);\n if (items.length > 0 && matched) {\n showContextMenu(mouseEvent, matched, items);\n mouseEvent.preventDefault();\n }\n });\n });\n gradioApp().addEventListener('contextmenu', (e: Event) => {\n const mouseEvent = e as MouseEvent;\n const oldMenu = gradioApp().querySelector('#context-menu');\n if (oldMenu) oldMenu.remove();\n menuSpecs.forEach((v, k) => {\n const items = v.filter((item) => !item.primary);\n const target = mouseEvent.target as Element | null;\n if (!target) return;\n const matched = target.closest(k);\n if (items.length > 0 && matched) {\n showContextMenu(mouseEvent, matched, items);\n mouseEvent.preventDefault();\n }\n });\n });\n eventListenerApplied = true;\n }\n return [appendContextMenuOption, removeContextMenuOption, addContextMenuEventListener];\n};\n\nconst initContextResponse = contextMenuInit();\nconst appendContextMenuOption = initContextResponse[0];\nconst removeContextMenuOption = initContextResponse[1];\nconst addContextMenuEventListener = initContextResponse[2] as () => void;\n\nlet generateOnRepeatInterval: ReturnType | null = null;\n\nexport const generateForever = (genbuttonid: string): void => {\n if (generateOnRepeatInterval) {\n log('generateForever: cancel');\n clearInterval(generateOnRepeatInterval);\n generateOnRepeatInterval = null;\n } else {\n const genbutton = gradioApp().querySelector(genbuttonid);\n if (!(genbutton instanceof HTMLElement)) return;\n const isBusy = () => {\n let busy = document.getElementById('progressbar')?.style.display === 'block';\n if (!busy) {\n // Also check in Modern UI\n const outerButton = genbutton.parentElement.closest('button');\n busy = outerButton?.classList.contains('generate') && outerButton?.classList.contains('active');\n }\n return busy;\n };\n log('generateForever: start');\n if (!isBusy()) genbutton.click();\n generateOnRepeatInterval = setInterval(() => {\n if (!isBusy()) genbutton.click();\n }, 500);\n }\n};\nwindow.generateForever = generateForever;\n\nconst reprocessClick = (tabId: string, state: string): void => {\n const btn = document.getElementById(`${tabId}_${state}`);\n window.submit_state = state;\n if (btn) btn.click();\n};\n\nconst getStatus = async () => {\n const headers = new Headers();\n const body = JSON.stringify({ id_task: -1, id_live_preview: false });\n headers.set('Content-Type', 'application/json');\n const tab = getUICurrentTabContent()?.id.replace('tab_', '') || '';\n const el = gradioApp().querySelector(`#html_log_${tab} .performance p`);\n\n let res;\n let data;\n res = await fetch('./internal/progress', { method: 'POST', headers, body });\n if (res?.ok) {\n data = await res.json();\n log('progressInternal:', data);\n if (el) el.innerText += `\\nProgress internal:\\n${JSON.stringify(data, null, 2)}`;\n }\n res = await authFetch('./sdapi/v1/progress?skip_current_image=true', { method: 'GET', headers });\n if (res?.ok) {\n data = await res.json();\n log('progressAPI:', data);\n if (el) el.innerText += `\\nProgress API:\\n${JSON.stringify(data, null, 2)}`;\n }\n};\n\nexport async function initContextMenu() {\n for (const tab of ['txt2img', 'img2img', 'control', 'video']) {\n appendContextMenuOption(`#${tab}_generate`, 'Get server status', getStatus);\n appendContextMenuOption(`#${tab}_generate`, 'Copy prompt to clipboard', () => navigator.clipboard.writeText(document.querySelector(`#${tab}_prompt > label > textarea`).value));\n appendContextMenuOption(`#${tab}_generate`, 'Generate forever', () => generateForever(`#${tab}_generate`));\n appendContextMenuOption(`#${tab}_generate`, 'Apply selected style', quickApplyStyle);\n appendContextMenuOption(`#${tab}_generate`, 'Quick save style', quickSaveStyle);\n appendContextMenuOption(`#${tab}_reprocess`, 'Decode full quality', () => reprocessClick(tab, 'reprocess_decode'), true);\n appendContextMenuOption(`#${tab}_reprocess`, 'Refine & HiRes pass', () => reprocessClick(tab, 'reprocess_refine'), true);\n appendContextMenuOption(`#${tab}_reprocess`, 'Detailer pass', () => reprocessClick(tab, 'reprocess_detail'), true);\n }\n // Right-click send-to-control button for prompt/params-only transfer.\n for (const tab of ['gallery', 'txt2img', 'img2img', 'extras']) {\n appendContextMenuOption(`#${tab}_tabitem #control_tab`, 'Transfer only prompt to Images tab', () => {\n document.querySelector(`#image_buttons_${tab} #control_tab_prompt`)?.click();\n document.getElementById('control_nav')?.click();\n });\n appendContextMenuOption(`#${tab}_tabitem #control_tab`, 'Transfer all parameters to Images tab', () => {\n document.querySelector(`#image_buttons_${tab} #control_tab_params`)?.click();\n document.getElementById('control_nav')?.click();\n });\n }\n addContextMenuEventListener();\n}\n", "import { gradioApp } from './script';\n\nexport function uiOpenSubmenus() {\n const accordions = Array.from(gradioApp().querySelectorAll('.gradio-accordion'));\n const states: Record = {};\n accordions.forEach((el) => {\n const labelEl = el.querySelector('.label-wrap > span:not(.icon)');\n const name = labelEl instanceof HTMLElement ? labelEl.innerText.trim() : '';\n if (!name) return;\n const children = Array.from(el.childNodes);\n const open = children.filter((c) => c instanceof HTMLElement && c.style.display === 'block');\n if (states[name] === undefined) states[name] = open.length > 0;\n });\n return states;\n}\n\nexport async function getUIDefaults() {\n const btn = gradioApp().getElementById('ui_defaults_view');\n if (!btn) return;\n const intersectionObserver = new IntersectionObserver((entries) => {\n if (entries[0].intersectionRatio <= 0) { /* Pass */ }\n if (entries[0].intersectionRatio > 0) btn.click();\n });\n intersectionObserver.observe(btn); // monitor visibility of tab\n}\n\nwindow.uiOpenSubmenus = uiOpenSubmenus;\n", "import { error, log, xhrPost } from './logger';\nimport { authFetch } from './authWrap';\nimport { timer } from './timers';\n\nexport const appStartTime = performance.now();\nlet monitorLogActive = false;\n\nasync function preloadImages(): Promise {\n const dark = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches;\n const imagePromises: Promise[] = [];\n const num = Math.floor(9.99 * Math.random());\n const imageUrls = [\n `file=ui/assets/logo-bg-${dark ? 'dark' : 'light'}.jpg`,\n `file=ui/assets/logo-bg-${num}.jpg`,\n ];\n for (const url of imageUrls) {\n const img = new Image();\n const promise = new Promise((resolve, reject) => {\n img.onload = () => resolve();\n img.onerror = () => reject(new Error(`failed to preload image: ${url}`));\n });\n img.src = url;\n imagePromises.push(promise);\n }\n try {\n await Promise.all(imagePromises);\n return true;\n } catch (err) {\n error(`preloadImages: ${err}`);\n return false;\n }\n}\n\nfunction joinArgs(messages: unknown[]): string {\n let output = '';\n for (let i = 0; i < messages.length; i++) {\n let arg = messages[i];\n if (arg === undefined) arg = 'undefined';\n if (arg === null) arg = 'null';\n output += ' ';\n if (typeof arg === 'object') output += JSON.stringify(arg).replace(/[\"]+/g, '');\n else output += arg;\n }\n return output;\n}\n\nfunction monitorLog(): void {\n if (window.logBufferDirty) {\n window.logBufferDirty = false;\n const maxLines = 100; // print last n logs from ring buffer to splash-log\n const lines: string[] = [];\n // print last n logs from ring buffer in time order\n for (let i = Math.max(0, window.logRingBuffer.length - maxLines); i < window.logRingBuffer.length; i++) {\n const logEntry = window.logRingBuffer[i];\n let color = 'white';\n if (logEntry.type === 'error') color = 'palevioletred';\n else if (logEntry.type === 'debug') color = 'gray';\n const html = `
    ${logEntry.ts}   ${joinArgs(logEntry.msg)}
    `;\n lines.push(html);\n }\n const splashLogEl = document.getElementById('splashLog');\n if (splashLogEl) splashLogEl.innerHTML = lines.join('');\n }\n if (monitorLogActive) setTimeout(monitorLog, 250);\n}\n\nexport async function removeSplash() {\n const splash = document.getElementById('splash');\n if (splash) splash.remove();\n log('removeSplash');\n const t = Math.round(performance.now() - appStartTime);\n log('startupTime', t);\n timer('splashVisible', t);\n xhrPost(`${window.api}/log`, { message: `ready time=${t}` });\n monitorLogActive = false;\n}\n\nasync function createSplash() {\n const dark = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches;\n log('createSplash', { theme: dark ? 'dark' : 'light' });\n const num = Math.floor(9.99 * Math.random());\n const splash = `\n
    \n
    \n
    \n
    \n
    `;\n document.body.insertAdjacentHTML('beforeend', splash);\n const ok = await preloadImages();\n if (!ok) {\n removeSplash();\n return;\n }\n const imgEl = `
    `;\n const splashEl = document.getElementById('splash');\n if (splashEl) splashEl.insertAdjacentHTML('afterbegin', imgEl);\n\n monitorLogActive = true;\n monitorLog();\n\n await authFetch(`${window.api}/motd`)\n .then((res) => res.text())\n .then((text) => {\n const clean = text.replace(/[\"]+/g, '');\n const boldMatch = clean.match(/(.*?)<\\/b>/);\n const boldText = boldMatch ? boldMatch[1] : clean;\n if (boldMatch) log('getMOTD', { version: boldText });\n else log('getMOTD', { text: clean });\n const motdEl = document.getElementById('motd');\n if (motdEl) motdEl.innerHTML = clean;\n })\n .catch((err) => error(`getMOTD: ${err}`));\n\n log('loadGradioUi');\n\n const splashMonitor = setInterval(() => {\n const splashVisible = !!document.getElementById('splash');\n if (splashVisible) {\n log('splashVisible', { visible: true, elapsed: Math.round(performance.now() - appStartTime) });\n } else {\n log('splashVisible', { visible: false, elapsed: Math.round(performance.now() - appStartTime) });\n clearInterval(splashMonitor);\n }\n }, 5000);\n}\n\nwindow.onload = createSplash;\n", "import { log } from './logger';\n\nexport function addLegacyNotice() {\n log('legacyNotice');\n const notice = document.createElement('div');\n notice.id = 'legacy-notice';\n notice.className = 'legacy-standard';\n notice.textContent = 'Legacy';\n notice.title = 'Standard UI is a legacy interface that is no longer maintained and will be removed in the future. Please switch to ModernUI for best experience.';\n document.body.appendChild(notice);\n}\n", "import { initChangelog } from './changelog';\nimport { setupControlUI } from './control';\nimport { initiGenerationParams } from './generationParams';\nimport { initDragDrop } from './imageParams';\nimport { initAccordions } from './inputAccordion';\nimport { initIndexDB } from './indexdb';\nimport { initLogMonitor } from './logMonitor';\nimport { monitorConnection } from './monitor';\nimport { setRefreshInterval } from './progressBar';\nimport { initPromptChecker } from './promptChecker';\nimport { initModels, initSettings } from './settings';\nimport { initGallery } from './gallery';\nimport { initImageViewer } from './imageViewer';\nimport { reconnectUI } from './ui';\nimport { setupExtraNetworks, showNetworks, applyStyles } from './extraNetworks';\nimport { initAutocomplete } from './autocomplete';\nimport { setHints, disconnectHintsObserver } from './setHints';\nimport { initContextMenu } from './contextMenus';\nimport { executeCallbacks, onUiLoaded, onUiReady, sleep, uiReadyCallbacks, initTableSorter } from './script';\nimport { timer, logTimers } from './timers';\nimport { getUIDefaults } from './uiConfig';\nimport { log } from './logger';\nimport { appStartTime, removeSplash } from './loader';\nimport { addLegacyNotice } from './legacy';\n\nwindow.api = '/sdapi/v1';\nwindow.subpath = '';\n\nconst startupPromises: Promise[] = [];\nlet optsReady = false;\nlet initialized = false;\n\nasync function waitForOpts() {\n // make sure all of the ui is ready and options are loaded\n const t0 = performance.now();\n let t1 = performance.now();\n while (true) {\n if (t1 - t0 > 60000) {\n log('waitForOpts timeout');\n break;\n }\n if (window.opts && Object.keys(window.opts).length > 0) {\n optsReady = (window.opts.theme_type === 'Modern') ? 'uiux_separator_appearance' in window.opts : true;\n if (optsReady) {\n log('waitForOpts', Math.round(t1 - t0));\n timer('waitForOpts', t1 - t0);\n break;\n }\n }\n if (t1 - t0 > 15000) {\n log('waitForOpts delayed', Math.round(t1 - t0));\n }\n await sleep(100);\n t1 = performance.now();\n }\n}\n\nasync function postStartup() {\n log('postStartup');\n disconnectHintsObserver();\n logTimers();\n}\n\nasync function updateSubpath() {\n log('mountURL', window.opts.subpath);\n if (window.opts.subpath?.length > 0) {\n window.subpath = window.opts.subpath;\n window.api = `${window.subpath}/sdapi/v1`;\n }\n log('API', { url: window.api });\n}\n\nexport async function initStartup() {\n if (initialized) return;\n initialized = true;\n const t0 = performance.now();\n log('initGradio', Math.round(t0 - appStartTime));\n timer('initGradio', t0 - appStartTime);\n log('initUi');\n if (window.setupLogger) await window.setupLogger();\n\n // all items here are non-blocking async calls\n\n startupPromises.push(initModels());\n startupPromises.push(getUIDefaults());\n startupPromises.push(initPromptChecker());\n startupPromises.push(initContextMenu());\n startupPromises.push(initDragDrop());\n startupPromises.push(Promise.resolve(initAccordions()));\n startupPromises.push(Promise.resolve(initSettings()));\n startupPromises.push(Promise.resolve(initImageViewer()));\n startupPromises.push(Promise.resolve(initGallery()));\n startupPromises.push(Promise.resolve(initiGenerationParams()));\n startupPromises.push(Promise.resolve(initChangelog()));\n startupPromises.push(Promise.resolve(setupControlUI()));\n\n // reconnect server session\n await reconnectUI();\n await waitForOpts();\n await updateSubpath();\n\n executeCallbacks(uiReadyCallbacks);\n\n // optionally wait for modern ui\n if (window.opts.theme_type.toLowerCase().startsWith('modern') && window.waitForUiReady) await window.waitForUiReady();\n\n // post startup tasks that may take longer but are not critical\n startupPromises.push(Promise.resolve(initLogMonitor()));\n startupPromises.push(Promise.resolve(setRefreshInterval()));\n startupPromises.push(Promise.resolve(setupExtraNetworks()));\n startupPromises.push(Promise.resolve(initAutocomplete()));\n startupPromises.push(Promise.resolve(monitorConnection()));\n startupPromises.push(Promise.resolve(showNetworks()));\n startupPromises.push(Promise.resolve(setHints()));\n startupPromises.push(Promise.resolve(applyStyles()));\n startupPromises.push(Promise.resolve(initIndexDB()));\n startupPromises.push(Promise.resolve(initTableSorter()));\n\n if (window.opts.theme_type !== 'Modern') addLegacyNotice();\n\n const t1 = performance.now();\n log('initStartup', Math.round(1000 * (t1 - t0) / 1000000));\n\n removeSplash();\n\n await Promise.all(startupPromises);\n const t2 = performance.now();\n log('initComplete', Math.round(1000 * (t2 - t0) / 1000000));\n postStartup();\n}\n\nonUiLoaded(initStartup);\nonUiReady(() => log('uiReady'));\n\nwindow.initStartup = initStartup;\nwindow.addEventListener('pageshow', (evt) => log('pageShow', evt));\nwindow.addEventListener('pagehide', (evt) => log('pageHide', evt));\n\n// onAfterUiUpdate(() => log('evt onAfterUiUpdate'));\n// onUiLoaded(() => log('evt onUiLoaded'));\n// onOptionsChanged(() => log('evt onOptionsChanged'));\n// onUiTabChange(() => log('evt onUiTabChange'));\n// onUiUpdate(() => log('evt onUiUpdate'));\n", "import { randomId } from './progressBar';\n\nimport { log } from './logger';\nimport { gradioApp } from './script';\nimport { restartReload, updateInput } from './ui';\n\nexport function extensions_apply(_extensionsDisabledList: unknown, _extensionsUpdateList: unknown, disableAll: unknown): [string, string, unknown] {\n const disable = [];\n const update = [];\n gradioApp().querySelectorAll('#extensions input[type=\"checkbox\"]').forEach((x) => {\n if (!(x instanceof HTMLInputElement)) return;\n if (x.name.startsWith('enable_') && !x.checked) disable.push(x.name.substring(7));\n if (x.name.startsWith('update_') && x.checked) update.push(x.name.substring(7));\n });\n restartReload();\n log('Extensions apply:', { disable, update });\n return [JSON.stringify(disable), JSON.stringify(update), disableAll];\n}\n\nexport function extensions_check(_info: unknown, _extensionsDisabledList: unknown, searchText: unknown, sortColumn: unknown): [string, string, unknown, unknown] {\n const disable = [];\n gradioApp().querySelectorAll('#extensions input[type=\"checkbox\"]').forEach((x) => {\n if (!(x instanceof HTMLInputElement)) return;\n if (x.name.startsWith('enable_') && !x.checked) disable.push(x.name.substring(7));\n });\n const id = randomId();\n log('Extensions check:', { disable });\n return [id, JSON.stringify(disable), searchText, sortColumn];\n}\n\nexport function install_extension(button: HTMLButtonElement | HTMLInputElement, url: string): void {\n button.disabled = true;\n button.value = 'Installing...';\n button.innerHTML = 'installing';\n const textarea = gradioApp().querySelector('#extension_to_install textarea');\n if (!(textarea instanceof HTMLTextAreaElement)) return;\n textarea.value = url;\n updateInput(textarea);\n log('Extension install:', { url });\n const installBtn = gradioApp().querySelector('#install_extension_button');\n if (installBtn instanceof HTMLElement) installBtn.click();\n}\n\nexport function uninstall_extension(button: HTMLButtonElement | HTMLInputElement, url: string): void {\n button.disabled = true;\n button.value = 'Uninstalling...';\n button.innerHTML = 'uninstalling';\n const textarea = gradioApp().querySelector('#extension_to_install textarea');\n if (!(textarea instanceof HTMLTextAreaElement)) return;\n textarea.value = url;\n updateInput(textarea);\n log('Extension uninstall:', { url });\n const uninstallBtn = gradioApp().querySelector('#uninstall_extension_button');\n if (uninstallBtn instanceof HTMLElement) uninstallBtn.click();\n}\n\nexport function update_extension(button: HTMLButtonElement | HTMLInputElement, url: string): void {\n button.value = 'Updating...';\n button.innerHTML = 'updating';\n const textarea = gradioApp().querySelector('#extension_to_install textarea');\n if (!(textarea instanceof HTMLTextAreaElement)) return;\n textarea.value = url;\n updateInput(textarea);\n log('Extension update:', { url });\n const updateBtn = gradioApp().querySelector('#update_extension_button');\n if (updateBtn instanceof HTMLInputElement) updateBtn.click();\n}\n\nwindow.extensions_apply = extensions_apply;\nwindow.extensions_check = extensions_check;\nwindow.uninstall_extension = uninstall_extension;\nwindow.install_extension = install_extension;\nwindow.update_extension = update_extension;\n", "import { log } from './logger';\nimport { gradioApp, uiElementIsVisible, uiElementInSight } from './script';\n\ntype PromptDropTarget = EventTarget & {\n placeholder?: string;\n closest: (selector: string) => Element | null;\n};\n\nfunction isValidImageList(files: FileList | null | undefined): files is FileList {\n return files && files?.length === 1 && ['image/png', 'image/gif', 'image/jpeg'].includes(files[0].type);\n}\n\nfunction dropReplaceImage(imgWrap: Element, files: FileList): void {\n log('dropReplaceImage', imgWrap, files);\n if (!isValidImageList(files)) return;\n const tmpFile = files[0];\n imgWrap.querySelector('.modify-upload button + button, .touch-none + div button + button')?.click();\n const callback = () => {\n const fileInput = imgWrap.querySelector('input[type=\"file\"]');\n if (fileInput instanceof HTMLInputElement) {\n if (files.length === 0) {\n const dt = new DataTransfer();\n dt.items.add(tmpFile);\n fileInput.files = dt.files;\n } else {\n fileInput.files = files;\n }\n fileInput.dispatchEvent(new Event('change'));\n }\n };\n\n if (imgWrap.closest('#pnginfo_image')) {\n const oldFetch = window.fetch;\n window.fetch = async (input: RequestInfo | URL, options?: RequestInit) => {\n const response = await oldFetch(input, options);\n if (input === 'api/predict/') {\n const content = await response.text();\n window.fetch = oldFetch;\n window.requestAnimationFrame(() => callback());\n return new Response(content, {\n status: response.status,\n statusText: response.statusText,\n headers: response.headers,\n });\n }\n return response;\n };\n } else {\n window.requestAnimationFrame(() => callback());\n }\n}\n\nwindow.document.addEventListener('dragover', (e) => {\n const target = e.composedPath()[0] as PromptDropTarget;\n const imgWrap = target.closest('[data-testid=\"image\"]');\n if (!imgWrap && target.placeholder && target.placeholder.indexOf('Prompt') === -1) return;\n if ((e.dataTransfer?.files?.length || 0) > 0) {\n e.stopPropagation();\n e.preventDefault();\n e.dataTransfer.dropEffect = 'copy';\n }\n});\n\nwindow.document.addEventListener('drop', (e) => {\n const target = e.composedPath()[0] as PromptDropTarget;\n log('dropEvent', e, target);\n if (!target.placeholder) return;\n if (target.placeholder.indexOf('Prompt') === -1) return;\n const imgWrap = target.closest('[data-testid=\"image\"]');\n if (!imgWrap) return;\n if ((e.dataTransfer?.files?.length || 0) > 0) {\n e.stopPropagation();\n e.preventDefault();\n dropReplaceImage(imgWrap, e.dataTransfer.files);\n }\n});\n\nwindow.addEventListener('paste', (e) => {\n log('pasteEvent', e);\n const files = e.clipboardData?.files;\n if (!isValidImageList(files)) return;\n const visibleImageFields = [...gradioApp().querySelectorAll('[data-testid=\"image\"]')]\n .filter((el) => uiElementIsVisible(el))\n .sort((a, b) => Number(uiElementInSight(b)) - Number(uiElementInSight(a)));\n if (!visibleImageFields.length) return;\n const firstFreeImageField = visibleImageFields.filter((el) => el.querySelector('input[type=file]'))?.[0];\n dropReplaceImage(firstFreeImageField || visibleImageFields[visibleImageFields.length - 1], files);\n});\n", "import { gradioApp, onUiLoaded } from './script';\nimport { log, error } from './logger';\nimport { authFetch } from './authWrap';\n\ninterface CivitFileMetadata {\n fp?: string | null;\n format?: string | null;\n size?: string | null;\n quantType?: string | null;\n}\n\ninterface CivitFile {\n id: number;\n url?: string;\n name?: string;\n type?: string;\n size?: number;\n primary?: boolean;\n metadata?: CivitFileMetadata;\n}\n\ninterface CivitImage {\n url: string;\n}\n\ninterface CivitVersion {\n id: number;\n name?: string;\n base?: string;\n mtime: string;\n availability?: string;\n desc?: string;\n files: CivitFile[];\n images: CivitImage[];\n}\n\ninterface CivitModel {\n id: number;\n url: string;\n name?: string;\n type?: string;\n tags?: string[];\n nsfw?: boolean;\n level?: number;\n availability?: string;\n downloads?: number;\n creator?: string;\n desc?: string;\n versions: CivitVersion[];\n}\n\ninterface QueuedFile {\n version: CivitVersion;\n file: CivitFile;\n}\n\n// eslint-disable-next-line no-extend-native\nString.prototype.format = function format(this: string, args: Record): string {\n let thisString = '';\n for (let charPos = 0; charPos < this.length; charPos++) thisString += this[charPos];\n for (const key in args) {\n const stringKey = `{${key}}`;\n thisString = thisString.replace(new RegExp(stringKey, 'g'), String(args[key]));\n }\n return thisString;\n};\n\nlet selectedURL: string[] = [];\nlet selectedName: string[] = [];\nlet selectedType: string[] = [];\nlet selectedBase: string[] = [];\nlet selectedModelId: number[] = [];\nlet selectedVersionId: number[] = [];\nlet currentModel: CivitModel | null = null;\n\nconst precisionOrder = ['fp32', 'bf16', 'fp16', 'fp8', 'int8', 'int4'];\nconst companionTypes = ['VAE', 'Text Encoder'];\n\nexport function clearModelDetails() {\n const el = gradioApp().getElementById('model-details') || gradioApp().getElementById('civitai_models_output') || gradioApp().getElementById('models_outcome');\n if (!el) return;\n el.innerHTML = '';\n}\nwindow.clearModelDetails = clearModelDetails;\n\nconst modelDetailsHTML = `\n
    \n \"model\n \n \n \n \n \n \n \n \n \n \n \n
    Name{name}
    Type{type}
    Tags
    {tags}
    NSFW{nsfw} | {level}
    Availability{availability}
    Downloads{downloads}
    Author{creator}
    Description
    {desc}
    Download
    All variants
    \n
    \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n {versions}\n \n
    VersionTypeBaseFileVariantUpdatedSizeAvailabilityDescription
    \n
    \n`;\n\nfunction fileVariant(file: CivitFile): string | null {\n return file.metadata?.fp || file.metadata?.quantType || null;\n}\n\n// Model files before companions, then by precision, then larger first\nfunction sortFiles(files: CivitFile[]): CivitFile[] {\n const isModel = (f: CivitFile) => f.type === 'Model' || f.type === 'Pruned Model';\n const rank = (f: CivitFile) => {\n const index = precisionOrder.indexOf((fileVariant(f) || '').toLowerCase());\n return index < 0 ? precisionOrder.length : index;\n };\n return [...files].sort((a, b) => Number(isModel(b)) - Number(isModel(a)) || rank(a) - rank(b) || (b.size || 0) - (a.size || 0));\n}\n\nfunction insertNameSuffix(name: string, suffix: string): string {\n const dot = name.lastIndexOf('.');\n return dot > 0 ? `${name.slice(0, dot)}-${suffix}${name.slice(dot)}` : `${name}-${suffix}`;\n}\n\n// Precision suffix, then full/pruned and the file id only as far as needed to stay unique within the version\nfunction fileSaveName(file: CivitFile, siblings: CivitFile[]): string {\n const tier1 = (f: CivitFile) => {\n const variant = fileVariant(f);\n return variant ? insertNameSuffix(f.name || '', variant) : f.name || '';\n };\n const tier2 = (f: CivitFile) => (f.metadata?.size ? insertNameSuffix(tier1(f), f.metadata.size) : tier1(f));\n const others = siblings.filter((s) => s.id !== file.id);\n const name = tier1(file);\n if (!others.some((s) => tier1(s) === name)) return name;\n const sized = tier2(file);\n if (!others.some((s) => tier2(s) === sized)) return sized;\n return insertNameSuffix(name, String(file.id));\n}\n\nfunction escapeHTML(text: string): string {\n return text.replace(/[&<>\"']/g, (c) => `&#${c.charCodeAt(0)};`);\n}\n\nfunction versionRows(version: CivitVersion, divider: boolean): string {\n const files = sortFiles(version.files);\n const entries: (CivitFile | null)[] = files.length > 0 ? files : [null];\n const border = divider ? ' style=\"border-top: 1px solid var(--sd-panel-border-color, #555)\"' : '';\n const span = entries.length > 1 ? ` rowspan=\"${entries.length}\"` : '';\n const versionCell = (content: string) => `${content}`;\n return entries.map((file, i) => {\n const first = i === 0;\n const cell = (content: string) => `${content}`;\n const link = file ? `
    \\udb80\\uddda
    ` : '';\n const name = file ? `${escapeHTML(file.name || 'unknown')}${file.primary ? ' \u2605' : ''}` : 'unknown';\n const variant = file ? [fileVariant(file), file.metadata?.size].filter(Boolean).join(' \u00B7 ') : '';\n const size = file?.size ? `${(file.size / 1024 / 1024 / 1024).toFixed(2)} GB` : 'unknown';\n const cells = [\n cell(link),\n first ? versionCell(escapeHTML(version.name || 'unknown')) : '',\n cell(escapeHTML(file?.type || 'unknown')),\n first ? versionCell(escapeHTML(version.base || 'unknown')) : '',\n cell(name),\n cell(escapeHTML(variant || '-')),\n first ? versionCell((new Date(version.mtime)).toLocaleDateString()) : '',\n cell(size),\n first ? versionCell(escapeHTML(version.availability || 'unknown')) : '',\n first ? versionCell(`
    ${version.desc || 'no description available'}
    `) : '',\n ];\n return `${cells.join('')}`;\n }).join('');\n}\n\nexport async function modelCardClick(id) {\n log('modelCardClick id', id);\n const el = gradioApp().getElementById('model-details') || gradioApp().getElementById('civitai_models_output') || gradioApp().getElementById('models_outcome');\n if (!el) return;\n const res = await authFetch(`${window.api}/civitai?model_id=${encodeURI(id)}`);\n if (!res || res.status !== 200) {\n error(`modelCardClick: id=${id} status=${res ? res.status : 'unknown'}`);\n return;\n }\n const dataArray = await res.json();\n log('modelCardClick data', dataArray);\n if (!dataArray || dataArray.length === 0) return;\n const data: any = dataArray[0]; // assuming the first item is the one we want\n currentModel = data;\n\n const versionsHTML = data.versions.map((v: CivitVersion, i: number) => versionRows(v, i > 0)).join('');\n const url = `${data.name || 'unknown'}`;\n const creator = `${data.creator || 'unknown'}`;\n const images = data.versions.map((v: CivitVersion) => v.images).flat().map((i: CivitImage) => i.url); // TODO image gallery\n const modelHTML = modelDetailsHTML.format({\n name: url,\n type: data.type || 'unknown',\n tags: data.tags?.join(', ') || '',\n nsfw: data.nsfw ? 'yes' : 'no',\n level: data.level?.toString() || '',\n availability: data.availability || 'unknown',\n downloads: data.downloads?.toString() || '',\n creator,\n desc: data.desc || 'no description available',\n image: images.length > 0 ? images[0] : '/sdapi/v1/network/thumb?filename=ui/assets/missing.png',\n versions: versionsHTML || '',\n });\n el.innerHTML = modelHTML;\n}\nwindow.modelCardClick = modelCardClick;\n\nfunction queueFiles(model: CivitModel, queued: QueuedFile[]) {\n selectedURL = queued.map(({ file }) => file.url || '');\n selectedName = queued.map(({ version, file }) => fileSaveName(file, version.files));\n selectedType = queued.map(({ file }) => (companionTypes.includes(file.type || '') ? file.type : model.type) || '');\n selectedBase = queued.map(({ version }) => version.base || '');\n selectedModelId = queued.map(() => model.id || 0);\n selectedVersionId = queued.map(({ version }) => version.id || 0);\n const civitDownloadBtn = gradioApp().getElementById('civitai_download_btn');\n if (civitDownloadBtn) civitDownloadBtn.click();\n}\n\nexport function startCivitFileDownload(versionId: number, fileId: number) {\n log('startCivitFileDownload', { versionId, fileId });\n const version = currentModel?.versions.find((v) => v.id === versionId);\n const file = version?.files.find((f) => f.id === fileId);\n if (!currentModel || !version || !file) return;\n queueFiles(currentModel, [{ version, file }]);\n}\nwindow.startCivitFileDownload = startCivitFileDownload;\n\nexport function startCivitAllDownload(evt) {\n log('startCivitAllDownload', evt);\n if (!currentModel) return;\n const queued = currentModel.versions\n .map((version) => ({ version, file: version.files.find((f) => f.primary) || version.files[0] }))\n .filter((entry): entry is QueuedFile => !!entry.file);\n queueFiles(currentModel, queued);\n}\nwindow.startCivitAllDownload = startCivitAllDownload;\n\nexport function downloadCivitModel(modelUrl, modelName, modelType, modelBase, mId, vId, modelPath, civitToken, innerHTML) {\n log('downloadCivitModel', { modelUrl, modelName, modelType, modelBase, mId, vId, modelPath, civitToken });\n const el = gradioApp().getElementById('civitai_models_output') || gradioApp().getElementById('models_outcome');\n const currentHTML = el?.innerHTML || '';\n return [selectedURL, selectedName, selectedType, selectedBase, selectedModelId, selectedVersionId, modelPath, civitToken, currentHTML];\n}\nwindow.downloadCivitModel = downloadCivitModel;\n\nlet civitMutualExcludeBound = false;\n\nexport function civitaiMutualExclude() {\n if (civitMutualExcludeBound) return;\n const searchEl = gradioApp().querySelector('#civit_search_text textarea');\n const tagEl = gradioApp().querySelector('#civit_search_tag textarea');\n if (!searchEl || !tagEl) return;\n civitMutualExcludeBound = true;\n searchEl.addEventListener('input', () => {\n tagEl.closest('.gradio-textbox')?.classList.toggle('disabled-look', !!searchEl.value.trim());\n });\n tagEl.addEventListener('input', () => {\n searchEl.closest('.gradio-textbox')?.classList.toggle('disabled-look', !!tagEl.value.trim());\n });\n}\n\nonUiLoaded(civitaiMutualExclude);\n", "import { log } from './logger';\n\ntype GuiderLike = string | { label?: string };\n\nconst guiders: Record = {\n None: '',\n 'LSC: LayerSkipConfig': 'https://github.com/huggingface/diffusers/blob/041501aea92919c9c7f36e189fc9cf7d865ebb96/src/diffusers/hooks/layer_skip.py#L41',\n 'CFG: ClassifierFreeGuidance': 'https://huggingface.co/docs/diffusers/v0.35.1/en/api/modular_diffusers/guiders#diffusers.ClassifierFreeGuidance',\n 'Auto: AutoGuidance': 'https://huggingface.co/docs/diffusers/v0.35.1/en/api/modular_diffusers/guiders#diffusers.AutoGuidance',\n 'Zero: ClassifierFreeZeroStar': 'https://huggingface.co/docs/diffusers/v0.35.1/en/api/modular_diffusers/guiders#diffusers.ClassifierFreeZeroStarGuidance',\n 'PAG: PerturbedAttentionGuidance': 'https://huggingface.co/docs/diffusers/v0.35.1/en/api/modular_diffusers/guiders#diffusers.PerturbedAttentionGuidance',\n 'APG: AdaptiveProjectedGuidance': 'https://huggingface.co/docs/diffusers/v0.35.1/en/api/modular_diffusers/guiders#diffusers.AdaptiveProjectedGuidance',\n 'SLG: SkipLayerGuidance': 'https://huggingface.co/docs/diffusers/v0.35.1/en/api/modular_diffusers/guiders#diffusers.SkipLayerGuidance',\n 'SEG: SmoothedEnergyGuidance': 'https://huggingface.co/docs/diffusers/v0.35.1/en/api/modular_diffusers/guiders#diffusers.SmoothedEnergyGuidance',\n 'TCFG: TangentialClassifierFreeGuidance': 'https://huggingface.co/docs/diffusers/v0.35.1/en/api/modular_diffusers/guiders#diffusers.TangentialClassifierFreeGuidance',\n 'FDG: FrequencyDecoupledGuidance': 'https://huggingface.co/docs/diffusers/v0.35.1/en/api/modular_diffusers/guiders#diffusers.FrequencyDecoupledGuidance',\n};\n\nexport function getGuidanceDocs(guider: GuiderLike): void {\n const key = typeof guider === 'object' && guider?.label ? guider.label : guider;\n const url = guiders[key as string];\n log('getGuidanceDocs', guider, url);\n if (url) window.open(url, '_blank');\n}\n\nwindow.getGuidanceDocs = getGuidanceDocs;\n", "/* eslint max-classes-per-file: [\"error\", 2] */\n\ninterface TimesheetItem {\n start: number;\n end: number;\n label: string;\n type: string;\n}\n\nclass Bubble {\n type: string;\n label: string;\n min: number;\n start: number;\n end: number;\n scale: number;\n offset: number;\n width: number;\n duration: number;\n title: string;\n\n constructor(min: number, start: number, end: number, label: string, scale: number, type: string) {\n this.type = type;\n this.label = label;\n this.min = min;\n this.start = start;\n this.end = end;\n this.scale = scale;\n this.offset = Math.round(this.scale * (this.start - this.min));\n this.width = Math.round(this.scale * (this.end - this.start));\n this.duration = Math.round(1000 * (this.end - this.start)) / 1000;\n this.title = `Job: ${this.label}\\nDuration: ${this.duration}s\\nStart: ${new Date(1000 * this.start).toLocaleString()}\\nEnd: ${new Date(1000 * this.end).toLocaleString()}`;\n }\n\n getDateLabel(): number {\n return Math.round(1000 * (this.end - this.start)) / 1000;\n }\n}\n\nexport class Timesheet {\n min: number;\n max: number;\n data: TimesheetItem[];\n container: HTMLElement;\n scale: number;\n\n constructor(container: HTMLElement, data: TimesheetItem[]) {\n this.min = Math.floor(data[0].start);\n this.max = Math.round(data[data.length - 1].end + 0.5);\n this.data = data;\n this.container = container;\n const box = container.getBoundingClientRect();\n const width = box.width - 140;\n this.scale = width / (this.max - this.min);\n\n // draw sections\n let html: string[] = [];\n for (let c = 0; c <= this.max - this.min; c++) html.push(`
    `);\n container.className = 'timesheet color-scheme-default';\n container.innerHTML = `
    ${html.join('')}
    `;\n\n // insert data\n html = [];\n for (let n = 0, m = this.data.length; n < m; n++) {\n const cur = this.data[n];\n const bubble = new Bubble(this.min, cur.start, cur.end, cur.label, this.scale, cur.type);\n const line = [\n ``,\n `${bubble.duration} `,\n `${bubble.label}`,\n ].join('');\n html.push(`
  • ${line}
  • `);\n }\n this.container.innerHTML += `
      ${html.join('')}
    `;\n }\n}\n", "import { Timesheet } from './timesheet';\nimport { log } from './logger';\nimport { authFetch } from './authWrap';\n\ninterface HistoryEntry {\n timestamp: number;\n id: string;\n job: string;\n op: string;\n duration?: number;\n outputs: string[];\n type?: 'inference' | 'io' | 'default';\n}\n\ninterface TimelineEntry {\n start: number;\n end: number;\n label: string;\n type: 'inference' | 'io' | 'default';\n}\n\nconst inferenceTypes = ['inference', 'vae', 'te'];\nconst ioTypes = ['load', 'save'];\n\nexport async function refreshHistory() {\n log('refreshHistory');\n authFetch(`${window.api}/history`, { priority: 'low' }).then((res) => {\n if (!res) return;\n const timeline = document.getElementById('history_timeline');\n const table = document.getElementById('history_table');\n if (!timeline || !table) return;\n timeline.innerHTML = '';\n res.json().then((rawData) => {\n let data = rawData as HistoryEntry[];\n if (!data || !data.length) {\n table.innerHTML = '

    No history data available.

    ';\n return;\n }\n\n // build table\n let html = '';\n for (const entry of data) {\n const ts = new Date(1000 * entry.timestamp).toLocaleString();\n const duration = entry.duration ? (entry.duration).toFixed(3) : '';\n const outputs = entry.outputs.join(', ');\n html += ``;\n }\n html += '
    TimeIDJobActionDurationOutputs
    ${ts}${entry.id}${entry.job}${entry.op}${duration}${outputs}
    ';\n table.innerHTML = html;\n\n // crop data to last processing session\n let startIdx = -1;\n for (let i = data.length - 1; i >= 0; --i) {\n const e = data[i];\n if ((e.job === 'control' || e.job === 'text' || e.job === 'control' || e.job === 'image') && (e.op === 'begin')) {\n startIdx = i;\n break;\n }\n }\n if (startIdx >= 0) data = data.slice(startIdx);\n\n // build timeline\n const ts: TimelineEntry[] = [];\n for (const entry of data) {\n if (entry.op === 'begin') {\n const start = entry.timestamp;\n const endEntry = data.find((e) => (e.id === entry.id && e.op === 'end'));\n const end = endEntry?.timestamp ?? data[data.length - 1].timestamp;\n if (end - start < 0.02) continue; // skip very short entries\n if (inferenceTypes.some((type) => entry.job.toLowerCase().startsWith(type))) entry.type = 'inference';\n else if (ioTypes.some((type) => entry.job.toLowerCase().startsWith(type))) entry.type = 'io';\n else entry.type = 'default';\n if (start && end) ts.push({ start, end, label: entry.job, type: entry.type });\n }\n }\n if (!ts.length) return;\n // eslint-disable-next-line no-new\n new Timesheet(timeline, ts);\n });\n });\n}\n\nwindow.refreshHistory = refreshHistory;\n", "import { Timesheet } from './timesheet';\nimport { log } from './logger';\nimport { authFetch } from './authWrap';\n\nconst types = ['Images', 'Videos', 'Models', 'Data', 'Cache', 'Code', 'Other'];\n\ninterface LocationEntry {\n name: string;\n type: 'Images' | 'Videos' | 'Models' | 'Data' | 'Cache' | 'Code' | 'Other';\n folders: string[];\n paths: string[];\n size: number;\n mtime: number;\n nfiles: number;\n nfolders: number;\n nsymlinks: number;\n nerrors: number;\n time: number;\n}\n\ninterface TimelineEntry {\n start: number;\n end: number;\n label: string;\n type: 'inference' | 'io' | 'default';\n}\n\nfunction buildTable(type: string, data: LocationEntry[]) {\n // let html = `

    ${type}

    `;\n const totalSize = data.reduce((acc, entry) => acc + entry.size, 0);\n const totalLoc = data.length;\n const totalFiles = data.reduce((acc, entry) => acc + entry.nfiles, 0);\n const totalFolders = data.reduce((acc, entry) => acc + entry.nfolders, 0);\n let title = `Locations: ${totalLoc}\\nTotal Size: ${(totalSize / (1024 * 1024)).toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })} MB\\nTotal Files: ${totalFiles}\\nTotal Folders: ${totalFolders}\\n`;\n let html = `

    ${type}

    LocationSizeMTime
    `;\n for (const entry of data) {\n if (entry.size === 0) continue;\n const size = (entry.size / (1024 * 1024)).toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 }) + ' MB';\n const mtime = entry.mtime > 0 ? new Date(entry.mtime * 1000).toLocaleString() : '';\n title = `Type: ${entry.type}\\nName: ${entry.name}\\nSize: ${size}\\nLast modified: ${mtime}\\n`;\n title += `Folders: ${entry.folders.join(', ')}\\nResolved paths: ${entry.paths.join(', ')}\\n`;\n title += `Subfolders: ${entry.nfolders}\\nFiles: ${entry.nfiles}\\nSymlinks: ${entry.nsymlinks}\\nErrors: ${entry.nerrors}\\n`;\n title += `Time to scan: ${entry.time.toFixed(3)} seconds`;\n const perc = Math.round((entry.size / totalSize) * 100);\n const color = `rgb(${perc}, 50, 80)`;\n const css = `background: linear-gradient(to right, ${color} ${perc}%, transparent ${perc}%);`;\n html += ``;\n }\n html += '
    ${entry.name}${size}${mtime}
    ';\n return html;\n}\n\nexport async function refreshStorage(storageTypes: string[]) {\n log('refreshStorage', storageTypes);\n authFetch(`${window.api}/storage?types=${storageTypes.join(',')}`, { priority: 'low' }).then((res) => {\n if (!res) return;\n const timeline = document.getElementById('storage_timeline');\n const table = document.getElementById('storage_table');\n if (!timeline || !table) return;\n timeline.innerHTML = '';\n res.json().then((rawData) => {\n const data = rawData as LocationEntry[];\n if (!data || !data.length) {\n table.innerHTML = '

    No storage data available.

    ';\n return;\n }\n table.innerHTML = '';\n if (storageTypes.includes('All')) storageTypes = types;\n for (const type of storageTypes) {\n const typeData = data.filter((entry) => entry.type === type);\n if (typeData.length > 0) table.innerHTML += buildTable(type, typeData);\n }\n\n /*\n // build timeline\n const ts: TimelineEntry[] = [];\n for (const entry of data) {\n if (entry.op === 'begin') {\n const start = entry.timestamp;\n const endEntry = data.find((e) => (e.id === entry.id && e.op === 'end'));\n const end = endEntry?.timestamp ?? data[data.length - 1].timestamp;\n if (end - start < 0.02) continue; // skip very short entries\n if (inferenceTypes.some((type) => entry.job.toLowerCase().startsWith(type))) entry.type = 'inference';\n else if (ioTypes.some((type) => entry.job.toLowerCase().startsWith(type))) entry.type = 'io';\n else entry.type = 'default';\n if (start && end) ts.push({ start, end, label: entry.job, type: entry.type });\n }\n }\n if (!ts.length) return;\n // eslint-disable-next-line no-new\n new Timesheet(timeline, ts);\n */\n });\n });\n}\n\nwindow.refreshStorage = refreshStorage;\n", "import { gradioApp, onAfterUiUpdate } from './script';\nimport { get_tab_index } from './ui';\n\nlet currentWidth: number | null = null;\nlet currentHeight: number | null = null;\nlet arFrameTimeout: ReturnType | undefined;\n\nfunction dimensionChange(e: Event, isWidth: boolean, isHeight: boolean): void {\n const { target } = e;\n if (!(target instanceof HTMLInputElement)) return;\n if (isWidth) currentWidth = Number(target.value);\n if (isHeight) currentHeight = Number(target.value);\n const tabImg2img = gradioApp().querySelector('#tab_img2img');\n if (!(tabImg2img instanceof HTMLElement)) return;\n const inImg2img = tabImg2img.style.display === 'block';\n if (!inImg2img) return;\n let targetElement: HTMLImageElement | null = null;\n const tabIndex = get_tab_index('mode_img2img');\n if (tabIndex === 0) targetElement = gradioApp().querySelector('#img2img_image div[data-testid=image] img'); // img2img\n else if (tabIndex === 1) targetElement = gradioApp().querySelector('#img2img_sketch div[data-testid=image] img'); // Sketch\n else if (tabIndex === 2) targetElement = gradioApp().querySelector('#img2maskimg div[data-testid=image] img'); // Inpaint\n else if (tabIndex === 3) targetElement = gradioApp().querySelector('#composite div[data-testid=image] img'); // Inpaint sketch\n\n if (targetElement && currentWidth && currentHeight) {\n let arPreviewRect = gradioApp().querySelector('#imageARPreview');\n if (!arPreviewRect) {\n arPreviewRect = document.createElement('div');\n arPreviewRect.id = 'imageARPreview';\n gradioApp().appendChild(arPreviewRect);\n }\n\n const viewportOffset = targetElement.getBoundingClientRect();\n const viewportscale = Math.min(targetElement.clientWidth / targetElement.naturalWidth, targetElement.clientHeight / targetElement.naturalHeight);\n const scaledx = targetElement.naturalWidth * viewportscale;\n const scaledy = targetElement.naturalHeight * viewportscale;\n const cleintRectTop = (viewportOffset.top + window.scrollY);\n const cleintRectLeft = (viewportOffset.left + window.scrollX);\n const cleintRectCentreY = cleintRectTop + (targetElement.clientHeight / 2);\n const cleintRectCentreX = cleintRectLeft + (targetElement.clientWidth / 2);\n const arscale = Math.min(scaledx / currentWidth, scaledy / currentHeight);\n const arscaledx = currentWidth * arscale;\n const arscaledy = currentHeight * arscale;\n const arRectTop = cleintRectCentreY - (arscaledy / 2);\n const arRectLeft = cleintRectCentreX - (arscaledx / 2);\n const arRectWidth = arscaledx;\n const arRectHeight = arscaledy;\n arPreviewRect.style.top = `${arRectTop}px`;\n arPreviewRect.style.left = `${arRectLeft}px`;\n arPreviewRect.style.width = `${arRectWidth}px`;\n arPreviewRect.style.height = `${arRectHeight}px`;\n\n if (arFrameTimeout) clearTimeout(arFrameTimeout);\n arFrameTimeout = setTimeout(() => { arPreviewRect.style.display = 'none'; }, 2000);\n arPreviewRect.style.display = 'block';\n }\n}\n\nexport function aspectRatioCallback(): void {\n const arPreviewRect = gradioApp().querySelector('#imageARPreview');\n if (arPreviewRect instanceof HTMLElement) arPreviewRect.style.display = 'none';\n const tabImg2img = gradioApp().querySelector('#tab_img2img');\n if (tabImg2img instanceof HTMLElement) {\n const inImg2img = tabImg2img.style.display === 'block';\n if (inImg2img) {\n const inputs = gradioApp().querySelectorAll('input');\n inputs.forEach((e) => {\n if (!(e instanceof HTMLInputElement) || !(e.parentElement instanceof HTMLElement)) return;\n const isWidth = e.parentElement.id === 'img2img_width';\n const isHeight = e.parentElement.id === 'img2img_height';\n if ((isWidth || isHeight) && !e.classList.contains('scrollwatch')) {\n e.addEventListener('input', (evt) => { dimensionChange(evt, isWidth, isHeight); });\n e.classList.add('scrollwatch');\n }\n if (isWidth) currentWidth = Number(e.value);\n if (isHeight) currentHeight = Number(e.value);\n });\n }\n }\n}\n\nonAfterUiUpdate(aspectRatioCallback);\n", "import { gradioApp, onAfterUiUpdate } from './script';\n\n// Aspect-ratio lock for the paired width/height sliders. The math runs client-side and debounced,\n// and only the partner axis is ever written, never the field being edited; writing the edited field\n// back is what yanked the value mid-type when this went through a gradio round-trip. Programmatic\n// updates dispatch a synthetic input event so gradio's store stays in sync. State is keyed per\n// dropdown element so duplicate elem ids across tabs stay isolated.\n\nconst RES_DEBOUNCE = 350;\nconst AR_DEBOUNCE = 120;\nconst timers = new WeakMap>();\nconst busy = new WeakSet();\n\nfunction parseAR(ar: string): [number, number] | null {\n if (!ar || ar === 'AR') return null;\n const parts = ar.split(':');\n if (parts.length !== 2) return null;\n const w = parseInt(parts[0], 10);\n const h = parseInt(parts[1], 10);\n return (w > 0 && h > 0) ? [w, h] : null;\n}\n\nfunction numberInput(group: Element): HTMLInputElement | null {\n const inp = group.querySelector('input[type=number]') || group.querySelector('input');\n return inp instanceof HTMLInputElement ? inp : null;\n}\n\nfunction readValue(group: Element): number {\n const inp = numberInput(group);\n return inp ? Number(inp.value) : 0;\n}\n\nfunction writeValue(group: Element, raw: number): void {\n const inp = numberInput(group);\n if (!inp) return;\n const step = Number(inp.step) || 8;\n const min = inp.min !== '' ? Number(inp.min) : 0;\n const max = inp.max !== '' ? Number(inp.max) : 8192;\n const value = Math.max(min, Math.min(max, Math.round(raw / step) * step));\n if (value === Number(inp.value)) return; // unchanged: skip so the listeners do not refire\n group.querySelectorAll('input').forEach((el) => {\n if (!(el instanceof HTMLInputElement)) return;\n el.value = String(value);\n const e = new Event('input', { bubbles: true });\n Object.defineProperty(e, 'target', { value: el });\n el.dispatchEvent(e);\n });\n}\n\nfunction arValue(arEl: Element): string {\n const inp = arEl.querySelector('input');\n return inp instanceof HTMLInputElement ? inp.value : 'AR';\n}\n\nfunction pairOf(arEl: Element): { width: Element; height: Element } | null {\n let container: Element | null = arEl.parentElement;\n for (let i = 0; i < 6 && container; i++) {\n const width = container.querySelector('[id$=\"_width\"]');\n const height = container.querySelector('[id$=\"_height\"]');\n if (width && height) return { width, height };\n container = container.parentElement;\n }\n return null;\n}\n\nfunction getNearestAspectRatio(width: number, height: number, maxPixelTolerance = 8): string | null {\n const STANDARD_RATIOS = [\n { label: '1:1', ratio: 1 / 1 },\n { label: '4:3', ratio: 4 / 3 },\n { label: '3:2', ratio: 3 / 2 },\n { label: '16:9', ratio: 16 / 9 },\n { label: '16:10', ratio: 16 / 10 },\n { label: '21:9', ratio: 64 / 27 }, // standard cinematic 21:9 ratio is actually 64/27\n { label: '2:3', ratio: 2 / 3 },\n { label: '3:4', ratio: 3 / 4 },\n { label: '9:16', ratio: 9 / 16 },\n { label: '10:16', ratio: 10 / 16 },\n { label: '9:21', ratio: 27 / 64 },\n ];\n const targetRatio = width / height;\n const closest = STANDARD_RATIOS.reduce((prev, curr) => (Math.abs(curr.ratio - targetRatio) < Math.abs(prev.ratio - targetRatio) ? curr : prev));\n const expectedWidth = height * closest.ratio;\n const expectedHeight = width / closest.ratio;\n const widthDiff = Math.abs(width - expectedWidth);\n const heightDiff = Math.abs(height - expectedHeight);\n if (widthDiff <= maxPixelTolerance || heightDiff <= maxPixelTolerance) return closest.label;\n const ratio = (width / height).toFixed(2);\n return `${ratio}:1`;\n}\n\nfunction settle(arEl: Element, source: 'width' | 'height'): void {\n const ar = parseAR(arValue(arEl));\n const pair = pairOf(arEl);\n if (!pair) return;\n if (ar) { // ar is set\n const [rw, rh] = ar;\n busy.add(arEl);\n if (source === 'height') writeValue(pair.width, (readValue(pair.height) * rw) / rh);\n else writeValue(pair.height, (readValue(pair.width) * rh) / rw);\n }\n const span = arEl.querySelector('span');\n if (span) span.innerText = getNearestAspectRatio(readValue(pair.width), readValue(pair.height));\n busy.delete(arEl);\n}\n\nfunction schedule(arEl: Element, source: 'width' | 'height', delay: number): void {\n if (busy.has(arEl)) return; // ignore the input events our own writes dispatch\n clearTimeout(timers.get(arEl));\n timers.set(arEl, setTimeout(() => settle(arEl, source), delay));\n}\n\nfunction flush(arEl: Element, source: 'width' | 'height'): void {\n if (busy.has(arEl)) return;\n clearTimeout(timers.get(arEl));\n settle(arEl, source);\n}\n\nfunction bind(arEl: Element, group: Element, source: 'width' | 'height'): void {\n group.querySelectorAll('input').forEach((el) => {\n if (!(el instanceof HTMLInputElement) || el.classList.contains('ar-lock-bound')) return;\n el.classList.add('ar-lock-bound');\n el.addEventListener('input', () => schedule(arEl, source, RES_DEBOUNCE));\n el.addEventListener('change', () => flush(arEl, source)); // commit on blur, enter, or slider release\n });\n}\n\nexport function setupResolutionLock(): void {\n gradioApp().querySelectorAll('.ar-dropdown').forEach((arEl) => {\n const pair = pairOf(arEl);\n if (!pair) return;\n bind(arEl, pair.width, 'width');\n bind(arEl, pair.height, 'height');\n arEl.querySelectorAll('span').forEach((el) => {\n if (el) el.innerText = '';\n });\n arEl.querySelectorAll('input').forEach((el) => {\n if (!(el instanceof HTMLInputElement) || el.classList.contains('ar-lock-bound')) return;\n el.classList.add('ar-lock-bound');\n el.addEventListener('change', () => flush(arEl, 'width')); // new ratio: keep width, derive height\n el.addEventListener('input', () => schedule(arEl, 'width', AR_DEBOUNCE));\n });\n });\n}\n\nonAfterUiUpdate(setupResolutionLock);\n", "import { updateInput } from './ui';\n\nexport function keyupEditAttention(event: KeyboardEvent): void {\n const target = (event as any).originalTarget || event.composedPath()[0];\n if (!(target instanceof HTMLTextAreaElement)) return;\n if (!target.matches(\"*:is([id*='_toprow'] [id*='_prompt'], .prompt) textarea\")) return;\n if (!(event.metaKey || event.ctrlKey)) return;\n const isPlus = event.key === 'ArrowUp';\n const isMinus = event.key === 'ArrowDown';\n if (!isPlus && !isMinus) return;\n let { selectionStart } = target;\n let { selectionEnd } = target;\n let text = target.value;\n\n function selectCurrentParenthesisBlock(OPEN: string, CLOSE: string): boolean {\n if (selectionStart !== selectionEnd) return false;\n\n // Find opening parenthesis around current cursor\n const before = text.substring(0, selectionStart);\n let beforeParen = before.lastIndexOf(OPEN);\n if (beforeParen === -1) return false;\n let beforeParenClose = before.lastIndexOf(CLOSE);\n while (beforeParenClose !== -1 && beforeParenClose > beforeParen) {\n beforeParen = before.lastIndexOf(OPEN, beforeParen - 1);\n beforeParenClose = before.lastIndexOf(CLOSE, beforeParenClose - 1);\n }\n\n // Find closing parenthesis around current cursor\n const after = text.substring(selectionStart);\n let afterParen = after.indexOf(CLOSE);\n if (afterParen === -1) return false;\n let afterParenOpen = after.indexOf(OPEN);\n while (afterParenOpen !== -1 && afterParen > afterParenOpen) {\n afterParen = after.indexOf(CLOSE, afterParen + 1);\n afterParenOpen = after.indexOf(OPEN, afterParenOpen + 1);\n }\n if (beforeParen === -1 || afterParen === -1) return false;\n\n // Set the selection to the text between the parenthesis\n const parenContent = text.substring(beforeParen + 1, selectionStart + afterParen);\n const lastColon = parenContent.lastIndexOf(':');\n selectionStart = beforeParen + 1;\n selectionEnd = selectionStart + lastColon;\n target.setSelectionRange(selectionStart, selectionEnd);\n return true;\n }\n\n function selectCurrentWord(): boolean {\n if (selectionStart !== selectionEnd) return false;\n const delimiters = `${window.opts.keyedit_delimiters} \\r\\n\\t`;\n // seek backward until to find beginning\n while (!delimiters.includes(text[selectionStart - 1]) && selectionStart > 0) selectionStart--;\n // seek forward to find end\n while (!delimiters.includes(text[selectionEnd]) && selectionEnd < text.length) selectionEnd++;\n target.setSelectionRange(selectionStart, selectionEnd);\n return true;\n }\n\n // If the user hasn't selected anything, let's select their current parenthesis block or word\n if (!selectCurrentParenthesisBlock('<', '>') && !selectCurrentParenthesisBlock('(', ')')) selectCurrentWord();\n event.preventDefault();\n\n let closeCharacter = ')';\n let delta = window.opts.keyedit_precision_attention;\n\n if (selectionStart > 0 && text[selectionStart - 1] === '<') {\n closeCharacter = '>';\n delta = window.opts.keyedit_precision_extra;\n } else if (selectionStart === 0 || text[selectionStart - 1] !== '(') {\n while (selectionEnd > selectionStart && text[selectionEnd - 1] === ' ') selectionEnd -= 1;\n if (selectionStart === selectionEnd) return;\n text = `${text.slice(0, selectionStart)}(${text.slice(selectionStart, selectionEnd)}:1.0)${text.slice(selectionEnd)}`;\n selectionStart += 1;\n selectionEnd += 1;\n }\n const end = text.slice(selectionEnd + 1).indexOf(closeCharacter) + 1;\n let weight: any = parseFloat(text.slice(selectionEnd + 1, selectionEnd + 1 + end));\n if (Number.isNaN(weight)) return;\n weight += isPlus ? delta : -delta;\n weight = parseFloat(weight.toPrecision(12));\n if (String(weight).length === 1) weight += '.0';\n if (closeCharacter === ')' && weight === 1) {\n text = text.slice(0, selectionStart - 1) + text.slice(selectionStart, selectionEnd) + text.slice(selectionEnd + 5);\n selectionStart--;\n selectionEnd--;\n } else {\n text = text.slice(0, selectionEnd + 1) + weight + text.slice(selectionEnd + 1 + end - 1);\n }\n target.focus();\n target.value = text;\n target.selectionStart = selectionStart;\n target.selectionEnd = selectionEnd;\n updateInput(target);\n}\n\naddEventListener('keydown', (event) => keyupEditAttention(event));\n", "/**\n*\n* jquery.sparkline.js\n*\n* v2.4.1\n* (c) Splunk, Inc\n* Contact: Gareth Watts (gareth@splunk.com)\n* http://omnipotent.net/jquery.sparkline/\n*\n* Generates inline sparkline charts from data supplied either to the method\n* or inline in HTML\n*\n* Compatible with Internet Explorer 6.0+ and modern browsers equipped with the canvas tag\n* (Firefox 2.0+, Safari, Opera, etc)\n*\n* License: New BSD License\n*\n* Copyright (c) 2012, Splunk Inc.\n* All rights reserved.\n*\n* Redistribution and use in source and binary forms, with or without modification,\n* are permitted provided that the following conditions are met:\n*\n* * Redistributions of source code must retain the above copyright notice,\n* this list of conditions and the following disclaimer.\n* * Redistributions in binary form must reproduce the above copyright notice,\n* this list of conditions and the following disclaimer in the documentation\n* and/or other materials provided with the distribution.\n* * Neither the name of Splunk Inc nor the names of its contributors may\n* be used to endorse or promote products derived from this software without\n* specific prior written permission.\n*\n* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY\n* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\n* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\n* SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\n* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\n* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*\n*\n* Usage:\n* $(selector).sparkline(values, options)\n*\n* If values is undefined or set to 'html' then the data values are read from the specified tag:\n*

    Sparkline: 1,4,6,6,8,5,3,5

    \n* $('.sparkline').sparkline();\n* There must be no spaces in the enclosed data set\n*\n* Otherwise values must be an array of numbers or null values\n*

    Sparkline: This text replaced if the browser is compatible

    \n* $('#sparkline1').sparkline([1,4,6,6,8,5,3,5])\n* $('#sparkline2').sparkline([1,4,6,null,null,5,3,5])\n*\n* Values can also be specified in an HTML comment, or as a values attribute:\n*

    Sparkline:

    \n*

    Sparkline:

    \n* $('.sparkline').sparkline();\n*\n* For line charts, x values can also be specified:\n*

    Sparkline: 1:1,2.7:4,3.4:6,5:6,6:8,8.7:5,9:3,10:5

    \n* $('#sparkline1').sparkline([ [1,1], [2.7,4], [3.4,6], [5,6], [6,8], [8.7,5], [9,3], [10,5] ])\n*\n* By default, options should be passed in as the second argument to the sparkline function:\n* $('.sparkline').sparkline([1,2,3,4], {type: 'bar'})\n*\n* Options can also be set by passing them on the tag itself. This feature is disabled by default though\n* as there's a slight performance overhead:\n* $('.sparkline').sparkline([1,2,3,4], {enableTagOptions: true})\n*

    Sparkline: loading

    \n* Prefix all options supplied as tag attribute with \"spark\" (configurable by setting tagOptionsPrefix)\n*\n* Supported options:\n* lineColor - Color of the line used for the chart\n* fillColor - Color used to fill in the chart - Set to '' or false for a transparent chart\n* width - Width of the chart - Defaults to 3 times the number of values in pixels\n* height - Height of the chart - Defaults to the height of the containing element\n* chartRangeMin - Specify the minimum value to use for the Y range of the chart - Defaults to the minimum value supplied\n* chartRangeMax - Specify the maximum value to use for the Y range of the chart - Defaults to the maximum value supplied\n* chartRangeClip - Clip out of range values to the max/min specified by chartRangeMin and chartRangeMax\n* chartRangeMinX - Specify the minimum value to use for the X range of the chart - Defaults to the minimum value supplied\n* chartRangeMaxX - Specify the maximum value to use for the X range of the chart - Defaults to the maximum value supplied\n* composite - If true then don't erase any existing chart attached to the tag, but draw\n* another chart over the top - Note that width and height are ignored if an\n* existing chart is detected.\n* tagValuesAttribute - Name of tag attribute to check for data values - Defaults to 'values'\n* enableTagOptions - Whether to check tags for sparkline options\n* tagOptionsPrefix - Prefix used for options supplied as tag attributes - Defaults to 'spark'\n* disableHiddenCheck - If set to true, then the plugin will assume that charts will never be drawn into a\n* hidden dom element, avoding a browser reflow\n* disableInteraction - If set to true then all mouseover/click interaction behaviour will be disabled,\n* making the plugin perform much like it did in 1.x\n* disableTooltips - If set to true then tooltips will be disabled - Defaults to false (tooltips enabled)\n* disableHighlight - If set to true then highlighting of selected chart elements on mouseover will be disabled\n* defaults to false (highlights enabled)\n* highlightLighten - Factor to lighten/darken highlighted chart values by - Defaults to 1.4 for a 40% increase\n* tooltipContainer - Specify which DOM element the tooltip should be rendered into - defaults to document.body\n* tooltipClassname - Optional CSS classname to apply to tooltips - If not specified then a default style will be applied\n* tooltipOffsetX - How many pixels away from the mouse pointer to render the tooltip on the X axis\n* tooltipOffsetY - How many pixels away from the mouse pointer to render the tooltip on the r axis\n* tooltipFormatter - Optional callback that allows you to override the HTML displayed in the tooltip\n* callback is given arguments of (sparkline, options, fields)\n* tooltipChartTitle - If specified then the tooltip uses the string specified by this setting as a title\n* tooltipFormat - A format string or SPFormat object (or an array thereof for multiple entries)\n* to control the format of the tooltip\n* tooltipPrefix - A string to prepend to each field displayed in a tooltip\n* tooltipSuffix - A string to append to each field displayed in a tooltip\n* tooltipSkipNull - If true then null values will not have a tooltip displayed (defaults to true)\n* tooltipValueLookups - An object or range map to map field values to tooltip strings\n* (eg. to map -1 to \"Lost\", 0 to \"Draw\", and 1 to \"Win\")\n* numberFormatter - Optional callback for formatting numbers in tooltips\n* numberDigitGroupSep - Character to use for group separator in numbers \"1,234\" - Defaults to \",\"\n* numberDecimalMark - Character to use for the decimal point when formatting numbers - Defaults to \".\"\n* numberDigitGroupCount - Number of digits between group separator - Defaults to 3\n*\n* There are 7 types of sparkline, selected by supplying a \"type\" option of 'line' (default),\n* 'bar', 'tristate', 'bullet', 'discrete', 'pie' or 'box'\n* line - Line chart. Options:\n* spotColor - Set to '' to not end each line in a circular spot\n* minSpotColor - If set, color of spot at minimum value\n* maxSpotColor - If set, color of spot at maximum value\n* spotRadius - Radius in pixels\n* lineWidth - Width of line in pixels\n* normalRangeMin\n* normalRangeMax - If set draws a filled horizontal bar between these two values marking the \"normal\"\n* or expected range of values\n* normalRangeColor - Color to use for the above bar\n* drawNormalOnTop - Draw the normal range above the chart fill color if true\n* defaultPixelsPerValue - Defaults to 3 pixels of width for each value in the chart\n* highlightSpotColor - The color to use for drawing a highlight spot on mouseover - Set to null to disable\n* highlightLineColor - The color to use for drawing a highlight line on mouseover - Set to null to disable\n* valueSpots - Specify which points to draw spots on, and in which color. Accepts a range map\n*\n* bar - Bar chart. Options:\n* barColor - Color of bars for postive values\n* negBarColor - Color of bars for negative values\n* zeroColor - Color of bars with zero values\n* nullColor - Color of bars with null values - Defaults to omitting the bar entirely\n* barWidth - Width of bars in pixels\n* colorMap - Optional mappnig of values to colors to override the *BarColor values above\n* can be an Array of values to control the color of individual bars or a range map\n* to specify colors for individual ranges of values\n* barSpacing - Gap between bars in pixels\n* zeroAxis - Centers the y-axis around zero if true\n*\n* tristate - Charts values of win (>0), lose (<0) or draw (=0)\n* posBarColor - Color of win values\n* negBarColor - Color of lose values\n* zeroBarColor - Color of draw values\n* barWidth - Width of bars in pixels\n* barSpacing - Gap between bars in pixels\n* colorMap - Optional mappnig of values to colors to override the *BarColor values above\n* can be an Array of values to control the color of individual bars or a range map\n* to specify colors for individual ranges of values\n*\n* discrete - Options:\n* lineHeight - Height of each line in pixels - Defaults to 30% of the graph height\n* thesholdValue - Values less than this value will be drawn using thresholdColor instead of lineColor\n* thresholdColor\n*\n* bullet - Values for bullet graphs msut be in the order: target, performance, range1, range2, range3, ...\n* options:\n* targetColor - The color of the vertical target marker\n* targetWidth - The width of the target marker in pixels\n* performanceColor - The color of the performance measure horizontal bar\n* rangeColors - Colors to use for each qualitative range background color\n*\n* pie - Pie chart. Options:\n* sliceColors - An array of colors to use for pie slices\n* offset - Angle in degrees to offset the first slice - Try -90 or +90\n* borderWidth - Width of border to draw around the pie chart, in pixels - Defaults to 0 (no border)\n* borderColor - Color to use for the pie chart border - Defaults to #000\n*\n* box - Box plot. Options:\n* raw - Set to true to supply pre-computed plot points as values\n* values should be: low_outlier, low_whisker, q1, median, q3, high_whisker, high_outlier\n* When set to false you can supply any number of values and the box plot will\n* be computed for you. Default is false.\n* showOutliers - Set to true (default) to display outliers as circles\n* outlierIQR - Interquartile range used to determine outliers. Default 1.5\n* boxLineColor - Outline color of the box\n* boxFillColor - Fill color for the box\n* whiskerColor - Line color used for whiskers\n* outlierLineColor - Outline color of outlier circles\n* outlierFillColor - Fill color of the outlier circles\n* spotRadius - Radius of outlier circles\n* medianColor - Line color of the median line\n* target - Draw a target cross hair at the supplied value (default undefined)\n*\n*\n*\n* Examples:\n* $('#sparkline1').sparkline(myvalues, { lineColor: '#f00', fillColor: false });\n* $('.barsparks').sparkline('html', { type:'bar', height:'40px', barWidth:5 });\n* $('#tristate').sparkline([1,1,-1,1,0,0,-1], { type:'tristate' }):\n* $('#discrete').sparkline([1,3,4,5,5,3,4,5], { type:'discrete' });\n* $('#bullet').sparkline([10,12,12,9,7], { type:'bullet' });\n* $('#pie').sparkline([1,1,2], { type:'pie' });\n*/\n\n/*jslint regexp: true, browser: true, jquery: true, white: true, nomen: false, plusplus: false, maxerr: 500, indent: 4 */\n\n(function(document, Math, undefined) { // performance/minified-size optimization\n(function(factory) {\n if(typeof define === 'function' && define.amd) {\n define(['jquery'], factory);\n } else if (jQuery && !jQuery.fn.sparkline) {\n factory(jQuery);\n }\n}\n(function($) {\n 'use strict';\n\n var UNSET_OPTION = {},\n getDefaults, createClass, SPFormat, clipval, quartile, normalizeValue, normalizeValues,\n remove, isNumber, all, sum, addCSS, ensureArray, formatNumber, RangeMap,\n MouseHandler, Tooltip, barHighlightMixin,\n line, bar, tristate, discrete, bullet, pie, box, defaultStyles, initStyles,\n VShape, VCanvas_base, VCanvas_canvas, VCanvas_vml, pending, shapeCount = 0;\n\n /**\n * Default configuration settings\n */\n getDefaults = function () {\n return {\n // Settings common to most/all chart types\n common: {\n type: 'line',\n lineColor: '#00f',\n fillColor: '#cdf',\n defaultPixelsPerValue: 3,\n width: 'auto',\n height: 'auto',\n composite: false,\n tagValuesAttribute: 'values',\n tagOptionsPrefix: 'spark',\n enableTagOptions: false,\n enableHighlight: true,\n highlightLighten: 1.4,\n tooltipSkipNull: true,\n tooltipPrefix: '',\n tooltipSuffix: '',\n disableHiddenCheck: false,\n numberFormatter: false,\n numberDigitGroupCount: 3,\n numberDigitGroupSep: ',',\n numberDecimalMark: '.',\n disableTooltips: false,\n disableInteraction: false\n },\n // Defaults for line charts\n line: {\n spotColor: '#f80',\n highlightSpotColor: '#5f5',\n highlightLineColor: '#f22',\n spotRadius: 1.5,\n minSpotColor: '#f80',\n maxSpotColor: '#f80',\n lineWidth: 1,\n normalRangeMin: undefined,\n normalRangeMax: undefined,\n normalRangeColor: '#ccc',\n drawNormalOnTop: false,\n chartRangeMin: undefined,\n chartRangeMax: undefined,\n chartRangeMinX: undefined,\n chartRangeMaxX: undefined,\n tooltipFormat: new SPFormat(' {{prefix}}{{y}}{{suffix}}')\n },\n // Defaults for bar charts\n bar: {\n barColor: '#3366cc',\n negBarColor: '#f44',\n stackedBarColor: ['#3366cc', '#dc3912', '#ff9900', '#109618', '#66aa00',\n '#dd4477', '#0099c6', '#990099'],\n zeroColor: undefined,\n nullColor: undefined,\n zeroAxis: true,\n barWidth: 4,\n barSpacing: 1,\n chartRangeMax: undefined,\n chartRangeMin: undefined,\n chartRangeClip: false,\n colorMap: undefined,\n tooltipFormat: new SPFormat(' {{prefix}}{{value}}{{suffix}}')\n },\n // Defaults for tristate charts\n tristate: {\n barWidth: 4,\n barSpacing: 1,\n posBarColor: '#6f6',\n negBarColor: '#f44',\n zeroBarColor: '#999',\n colorMap: {},\n tooltipFormat: new SPFormat(' {{value:map}}'),\n tooltipValueLookups: { map: { '-1': 'Loss', '0': 'Draw', '1': 'Win' } }\n },\n // Defaults for discrete charts\n discrete: {\n lineHeight: 'auto',\n thresholdColor: undefined,\n thresholdValue: 0,\n chartRangeMax: undefined,\n chartRangeMin: undefined,\n chartRangeClip: false,\n tooltipFormat: new SPFormat('{{prefix}}{{value}}{{suffix}}')\n },\n // Defaults for bullet charts\n bullet: {\n targetColor: '#f33',\n targetWidth: 3, // width of the target bar in pixels\n performanceColor: '#33f',\n rangeColors: ['#d3dafe', '#a8b6ff', '#7f94ff'],\n base: undefined, // set this to a number to change the base start number\n tooltipFormat: new SPFormat('{{fieldkey:fields}} - {{value}}'),\n tooltipValueLookups: { fields: {r: 'Range', p: 'Performance', t: 'Target'} }\n },\n // Defaults for pie charts\n pie: {\n offset: 0,\n sliceColors: ['#3366cc', '#dc3912', '#ff9900', '#109618', '#66aa00',\n '#dd4477', '#0099c6', '#990099'],\n borderWidth: 0,\n borderColor: '#000',\n tooltipFormat: new SPFormat(' {{value}} ({{percent.1}}%)')\n },\n // Defaults for box plots\n box: {\n raw: false,\n boxLineColor: '#000',\n boxFillColor: '#cdf',\n whiskerColor: '#000',\n outlierLineColor: '#333',\n outlierFillColor: '#fff',\n medianColor: '#f00',\n showOutliers: true,\n outlierIQR: 1.5,\n spotRadius: 1.5,\n target: undefined,\n targetColor: '#4a2',\n chartRangeMax: undefined,\n chartRangeMin: undefined,\n tooltipFormat: new SPFormat('{{field:fields}}: {{value}}'),\n tooltipFormatFieldlistKey: 'field',\n tooltipValueLookups: { fields: { lq: 'Lower Quartile', med: 'Median',\n uq: 'Upper Quartile', lo: 'Left Outlier', ro: 'Right Outlier',\n lw: 'Left Whisker', rw: 'Right Whisker'} }\n }\n };\n };\n\n // You can have tooltips use a css class other than jqstooltip by specifying tooltipClassname\n defaultStyles = '.jqstooltip { ' +\n 'position: absolute;' +\n 'left: 0px;' +\n 'top: 0px;' +\n 'visibility: hidden;' +\n 'background: rgb(0, 0, 0) transparent;' +\n 'background-color: rgba(0,0,0,0.6);' +\n 'filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=#99000000, endColorstr=#99000000);' +\n '-ms-filter: \"progid:DXImageTransform.Microsoft.gradient(startColorstr=#99000000, endColorstr=#99000000)\";' +\n 'color: white;' +\n 'font: 10px arial, san serif;' +\n 'text-align: left;' +\n 'white-space: nowrap;' +\n 'padding: 5px;' +\n 'border: 1px solid white;' +\n 'box-sizing: content-box;' +\n 'z-index: 10000;' +\n '}' +\n '.jqsfield { ' +\n 'color: white;' +\n 'font: 10px arial, san serif;' +\n 'text-align: left;' +\n '}';\n\n /**\n * Utilities\n */\n\n createClass = function (/* [baseclass, [mixin, ...]], definition */) {\n var Class, args;\n Class = function () {\n this.init.apply(this, arguments);\n };\n if (arguments.length > 1) {\n if (arguments[0]) {\n Class.prototype = $.extend(new arguments[0](), arguments[arguments.length - 1]);\n Class._super = arguments[0].prototype;\n } else {\n Class.prototype = arguments[arguments.length - 1];\n }\n if (arguments.length > 2) {\n args = Array.prototype.slice.call(arguments, 1, -1);\n args.unshift(Class.prototype);\n $.extend.apply($, args);\n }\n } else {\n Class.prototype = arguments[0];\n }\n Class.prototype.cls = Class;\n return Class;\n };\n\n /**\n * Wraps a format string for tooltips\n * {{x}}\n * {{x.2}\n * {{x:months}}\n */\n $.SPFormatClass = SPFormat = createClass({\n fre: /\\{\\{([\\w.]+?)(:(.+?))?\\}\\}/g,\n precre: /(\\w+)\\.(\\d+)/,\n\n init: function (format, fclass) {\n this.format = format;\n this.fclass = fclass;\n },\n\n render: function (fieldset, lookups, options) {\n var self = this,\n fields = fieldset,\n match, token, lookupkey, fieldvalue, prec;\n return this.format.replace(this.fre, function () {\n var lookup;\n token = arguments[1];\n lookupkey = arguments[3];\n match = self.precre.exec(token);\n if (match) {\n prec = match[2];\n token = match[1];\n } else {\n prec = false;\n }\n fieldvalue = fields[token];\n if (fieldvalue === undefined) {\n return '';\n }\n if (lookupkey && lookups && lookups[lookupkey]) {\n lookup = lookups[lookupkey];\n if (lookup.get) { // RangeMap\n return lookups[lookupkey].get(fieldvalue) || fieldvalue;\n } else {\n return lookups[lookupkey][fieldvalue] || fieldvalue;\n }\n }\n if (isNumber(fieldvalue)) {\n if (options.get('numberFormatter')) {\n fieldvalue = options.get('numberFormatter')(fieldvalue);\n } else {\n fieldvalue = formatNumber(fieldvalue, prec,\n options.get('numberDigitGroupCount'),\n options.get('numberDigitGroupSep'),\n options.get('numberDecimalMark'));\n }\n }\n return fieldvalue;\n });\n }\n });\n\n // convience method to avoid needing the new operator\n $.spformat = function(format, fclass) {\n return new SPFormat(format, fclass);\n };\n\n clipval = function (val, min, max) {\n if (val < min) {\n return min;\n }\n if (val > max) {\n return max;\n }\n return val;\n };\n\n quartile = function (values, q) {\n var vl;\n if (q === 2) {\n vl = Math.floor(values.length / 2);\n return values.length % 2 ? values[vl] : (values[vl-1] + values[vl]) / 2;\n } else {\n if (values.length % 2 ) { // odd\n vl = (values.length * q + q) / 4;\n return vl % 1 ? (values[Math.floor(vl)] + values[Math.floor(vl) - 1]) / 2 : values[vl-1];\n } else { //even\n vl = (values.length * q + 2) / 4;\n return vl % 1 ? (values[Math.floor(vl)] + values[Math.floor(vl) - 1]) / 2 : values[vl-1];\n\n }\n }\n };\n\n normalizeValue = function (val) {\n var nf;\n switch (val) {\n case 'undefined':\n val = undefined;\n break;\n case 'null':\n val = null;\n break;\n case 'true':\n val = true;\n break;\n case 'false':\n val = false;\n break;\n default:\n nf = parseFloat(val);\n if (val == nf) {\n val = nf;\n }\n }\n return val;\n };\n\n normalizeValues = function (vals) {\n var i, result = [];\n for (i = vals.length; i--;) {\n result[i] = normalizeValue(vals[i]);\n }\n return result;\n };\n\n remove = function (vals, filter) {\n var i, vl, result = [];\n for (i = 0, vl = vals.length; i < vl; i++) {\n if (vals[i] !== filter) {\n result.push(vals[i]);\n }\n }\n return result;\n };\n\n isNumber = function (num) {\n return !isNaN(parseFloat(num)) && isFinite(num);\n };\n\n formatNumber = function (num, prec, groupsize, groupsep, decsep) {\n var p, i;\n num = (prec === false ? parseFloat(num).toString() : num.toFixed(prec)).split('');\n p = (p = $.inArray('.', num)) < 0 ? num.length : p;\n if (p < num.length) {\n num[p] = decsep;\n }\n for (i = p - groupsize; i > 0; i -= groupsize) {\n num.splice(i, 0, groupsep);\n }\n return num.join('');\n };\n\n // determine if all values of an array match a value\n // returns true if the array is empty\n all = function (val, arr, ignoreNull) {\n var i;\n for (i = arr.length; i--; ) {\n if (ignoreNull && arr[i] === null) continue;\n if (arr[i] !== val) {\n return false;\n }\n }\n return true;\n };\n\n // sums the numeric values in an array, ignoring other values\n sum = function (vals) {\n var total = 0, i;\n for (i = vals.length; i--;) {\n total += typeof vals[i] === 'number' ? vals[i] : 0;\n }\n return total;\n };\n\n ensureArray = function (val) {\n return $.isArray(val) ? val : [val];\n };\n\n // http://paulirish.com/2008/bookmarklet-inject-new-css-rules/\n addCSS = function(css) {\n var tag, iefail;\n if (document.createStyleSheet) {\n try {\n document.createStyleSheet().cssText = css;\n return;\n } catch (e) {\n // IE <= 9 maxes out at 31 stylesheets; inject into page instead.\n iefail = true;\n }\n }\n tag = document.createElement('style');\n tag.type = 'text/css';\n document.getElementsByTagName('head')[0].appendChild(tag);\n if (iefail) {\n document.styleSheets[document.styleSheets.length - 1].cssText = css;\n } else {\n tag[(typeof document.body.style.WebkitAppearance == 'string') /* webkit only */ ? 'innerText' : 'innerHTML'] = css;\n }\n };\n\n // Provide a cross-browser interface to a few simple drawing primitives\n $.fn.simpledraw = function (width, height, useExisting, interact) {\n var target, mhandler;\n if (useExisting && (target = this.data('_jqs_vcanvas'))) {\n return target;\n }\n\n if ($.fn.sparkline.canvas === false) {\n // We've already determined that neither Canvas nor VML are available\n return false;\n\n } else if ($.fn.sparkline.canvas === undefined) {\n // No function defined yet -- need to see if we support Canvas or VML\n var el = document.createElement('canvas');\n if (!!(el.getContext && el.getContext('2d'))) {\n // Canvas is available\n $.fn.sparkline.canvas = function(width, height, target, interact) {\n return new VCanvas_canvas(width, height, target, interact);\n };\n } else if (document.namespaces && !document.namespaces.v) {\n // VML is available\n document.namespaces.add('v', 'urn:schemas-microsoft-com:vml', '#default#VML');\n $.fn.sparkline.canvas = function(width, height, target, interact) {\n return new VCanvas_vml(width, height, target);\n };\n } else {\n // Neither Canvas nor VML are available\n $.fn.sparkline.canvas = false;\n return false;\n }\n }\n\n if (width === undefined) {\n width = $(this).innerWidth();\n }\n if (height === undefined) {\n height = $(this).innerHeight();\n }\n\n target = $.fn.sparkline.canvas(width, height, this, interact);\n\n mhandler = $(this).data('_jqs_mhandler');\n if (mhandler) {\n mhandler.registerCanvas(target);\n }\n return target;\n };\n\n $.fn.cleardraw = function () {\n var target = this.data('_jqs_vcanvas');\n if (target) {\n target.reset();\n }\n };\n\n $.RangeMapClass = RangeMap = createClass({\n init: function (map) {\n var key, range, rangelist = [];\n for (key in map) {\n if (map.hasOwnProperty(key) && typeof key === 'string' && key.indexOf(':') > -1) {\n range = key.split(':');\n range[0] = range[0].length === 0 ? -Infinity : parseFloat(range[0]);\n range[1] = range[1].length === 0 ? Infinity : parseFloat(range[1]);\n range[2] = map[key];\n rangelist.push(range);\n }\n }\n this.map = map;\n this.rangelist = rangelist || false;\n },\n\n get: function (value) {\n var rangelist = this.rangelist,\n i, range, result;\n if ((result = this.map[value]) !== undefined) {\n return result;\n }\n if (rangelist) {\n for (i = rangelist.length; i--;) {\n range = rangelist[i];\n if (range[0] <= value && range[1] >= value) {\n return range[2];\n }\n }\n }\n return undefined;\n }\n });\n\n // Convenience function\n $.range_map = function(map) {\n return new RangeMap(map);\n };\n\n MouseHandler = createClass({\n init: function (el, options) {\n var $el = $(el);\n this.$el = $el;\n this.options = options;\n this.currentPageX = 0;\n this.currentPageY = 0;\n this.el = el;\n this.splist = [];\n this.tooltip = null;\n this.over = false;\n this.displayTooltips = !options.get('disableTooltips');\n this.highlightEnabled = !options.get('disableHighlight');\n },\n\n registerSparkline: function (sp) {\n this.splist.push(sp);\n if (this.over) {\n this.updateDisplay();\n }\n },\n\n registerCanvas: function (canvas) {\n var $canvas = $(canvas.canvas);\n this.canvas = canvas;\n this.$canvas = $canvas;\n $canvas.mouseenter($.proxy(this.mouseenter, this));\n $canvas.mouseleave($.proxy(this.mouseleave, this));\n $canvas.click($.proxy(this.mouseclick, this));\n },\n\n reset: function (removeTooltip) {\n this.splist = [];\n if (this.tooltip && removeTooltip) {\n this.tooltip.remove();\n this.tooltip = undefined;\n }\n },\n\n mouseclick: function (e) {\n var clickEvent = $.Event('sparklineClick');\n clickEvent.originalEvent = e;\n clickEvent.sparklines = this.splist;\n this.$el.trigger(clickEvent);\n },\n\n mouseenter: function (e) {\n $(document.body).unbind('mousemove.jqs');\n $(document.body).bind('mousemove.jqs', $.proxy(this.mousemove, this));\n this.over = true;\n this.currentPageX = e.pageX;\n this.currentPageY = e.pageY;\n this.currentEl = e.target;\n if (!this.tooltip && this.displayTooltips) {\n this.tooltip = new Tooltip(this.options);\n this.tooltip.updatePosition(e.pageX, e.pageY);\n }\n this.updateDisplay();\n },\n\n mouseleave: function () {\n $(document.body).unbind('mousemove.jqs');\n var splist = this.splist,\n spcount = splist.length,\n needsRefresh = false,\n sp, i;\n this.over = false;\n this.currentEl = null;\n\n if (this.tooltip) {\n this.tooltip.remove();\n this.tooltip = null;\n }\n\n for (i = 0; i < spcount; i++) {\n sp = splist[i];\n if (sp.clearRegionHighlight()) {\n needsRefresh = true;\n }\n }\n\n if (needsRefresh) {\n this.canvas.render();\n }\n },\n\n mousemove: function (e) {\n this.currentPageX = e.pageX;\n this.currentPageY = e.pageY;\n this.currentEl = e.target;\n if (this.tooltip) {\n this.tooltip.updatePosition(e.pageX, e.pageY);\n }\n this.updateDisplay();\n },\n\n updateDisplay: function () {\n var splist = this.splist,\n spcount = splist.length,\n needsRefresh = false,\n offset = this.$canvas.offset(),\n localX = this.currentPageX - offset.left,\n localY = this.currentPageY - offset.top,\n tooltiphtml, sp, i, result, changeEvent;\n if (!this.over) {\n return;\n }\n for (i = 0; i < spcount; i++) {\n sp = splist[i];\n result = sp.setRegionHighlight(this.currentEl, localX, localY);\n if (result) {\n needsRefresh = true;\n }\n }\n if (needsRefresh) {\n changeEvent = $.Event('sparklineRegionChange');\n changeEvent.sparklines = this.splist;\n this.$el.trigger(changeEvent);\n if (this.tooltip) {\n tooltiphtml = '';\n for (i = 0; i < spcount; i++) {\n sp = splist[i];\n tooltiphtml += sp.getCurrentRegionTooltip();\n }\n this.tooltip.setContent(tooltiphtml);\n }\n if (!this.disableHighlight) {\n this.canvas.render();\n }\n }\n if (result === null) {\n this.mouseleave();\n }\n }\n });\n\n\n Tooltip = createClass({\n sizeStyle: 'position: static !important;' +\n 'display: block !important;' +\n 'visibility: hidden !important;' +\n 'float: left !important;',\n\n init: function (options) {\n var tooltipClassname = options.get('tooltipClassname', 'jqstooltip'),\n sizetipStyle = this.sizeStyle,\n offset;\n this.container = options.get('tooltipContainer') || document.body;\n this.tooltipOffsetX = options.get('tooltipOffsetX', 10);\n this.tooltipOffsetY = options.get('tooltipOffsetY', 12);\n // remove any previous lingering tooltip\n $('#jqssizetip').remove();\n $('#jqstooltip').remove();\n this.sizetip = $('
    ', {\n id: 'jqssizetip',\n style: sizetipStyle,\n 'class': tooltipClassname\n });\n this.tooltip = $('
    ', {\n id: 'jqstooltip',\n 'class': tooltipClassname\n }).appendTo(this.container);\n // account for the container's location\n offset = this.tooltip.offset();\n this.offsetLeft = offset.left;\n this.offsetTop = offset.top;\n this.hidden = true;\n $(window).unbind('resize.jqs scroll.jqs');\n $(window).bind('resize.jqs scroll.jqs', $.proxy(this.updateWindowDims, this));\n this.updateWindowDims();\n },\n\n updateWindowDims: function () {\n this.scrollTop = $(window).scrollTop();\n this.scrollLeft = $(window).scrollLeft();\n this.scrollRight = this.scrollLeft + $(window).width();\n this.updatePosition();\n },\n\n getSize: function (content) {\n this.sizetip.html(content).appendTo(this.container);\n this.width = this.sizetip.width() + 1;\n this.height = this.sizetip.height();\n this.sizetip.remove();\n },\n\n setContent: function (content) {\n if (!content) {\n this.tooltip.css('visibility', 'hidden');\n this.hidden = true;\n return;\n }\n this.getSize(content);\n this.tooltip.html(content)\n .css({\n 'width': this.width,\n 'height': this.height,\n 'visibility': 'visible'\n });\n if (this.hidden) {\n this.hidden = false;\n this.updatePosition();\n }\n },\n\n updatePosition: function (x, y) {\n if (x === undefined) {\n if (this.mousex === undefined) {\n return;\n }\n x = this.mousex - this.offsetLeft;\n y = this.mousey - this.offsetTop;\n\n } else {\n this.mousex = x = x - this.offsetLeft;\n this.mousey = y = y - this.offsetTop;\n }\n if (!this.height || !this.width || this.hidden) {\n return;\n }\n\n y -= this.height + this.tooltipOffsetY;\n x += this.tooltipOffsetX;\n\n if (y < this.scrollTop) {\n y = this.scrollTop;\n }\n if (x < this.scrollLeft) {\n x = this.scrollLeft;\n } else if (x + this.width > this.scrollRight) {\n x = this.scrollRight - this.width;\n }\n\n this.tooltip.css({\n 'left': x,\n 'top': y\n });\n },\n\n remove: function () {\n this.tooltip.remove();\n this.sizetip.remove();\n this.sizetip = this.tooltip = undefined;\n $(window).unbind('resize.jqs scroll.jqs');\n }\n });\n\n initStyles = function() {\n addCSS(defaultStyles);\n };\n\n $(initStyles);\n\n pending = [];\n $.fn.sparkline = function (userValues, userOptions) {\n return this.each(function () {\n var options = new $.fn.sparkline.options(this, userOptions),\n $this = $(this),\n render, i;\n render = function () {\n var values, width, height, tmp, mhandler, sp, vals;\n if (userValues === 'html' || userValues === undefined) {\n vals = this.getAttribute(options.get('tagValuesAttribute'));\n if (vals === undefined || vals === null) {\n vals = $this.html();\n }\n values = vals.replace(/(^\\s*\\s*$)|\\s+/g, '').split(',');\n } else {\n values = userValues;\n }\n\n width = options.get('width') === 'auto' ? values.length * options.get('defaultPixelsPerValue') : options.get('width');\n if (options.get('height') === 'auto') {\n if (!options.get('composite') || !$.data(this, '_jqs_vcanvas')) {\n // must be a better way to get the line height\n tmp = document.createElement('span');\n tmp.innerHTML = 'a';\n $this.html(tmp);\n height = $(tmp).innerHeight() || $(tmp).height();\n $(tmp).remove();\n tmp = null;\n }\n } else {\n height = options.get('height');\n }\n\n if (!options.get('disableInteraction')) {\n mhandler = $.data(this, '_jqs_mhandler');\n if (!mhandler) {\n mhandler = new MouseHandler(this, options);\n $.data(this, '_jqs_mhandler', mhandler);\n } else if (!options.get('composite')) {\n mhandler.reset();\n }\n } else {\n mhandler = false;\n }\n\n if (options.get('composite') && !$.data(this, '_jqs_vcanvas')) {\n if (!$.data(this, '_jqs_errnotify')) {\n alert('Attempted to attach a composite sparkline to an element with no existing sparkline');\n $.data(this, '_jqs_errnotify', true);\n }\n return;\n }\n\n sp = new $.fn.sparkline[options.get('type')](this, values, options, width, height);\n\n sp.render();\n\n if (mhandler) {\n mhandler.registerSparkline(sp);\n }\n };\n if (($(this).html() && !options.get('disableHiddenCheck') && $(this).is(':hidden')) || !$(this).parents('body').length) {\n if (!options.get('composite') && $.data(this, '_jqs_pending')) {\n // remove any existing references to the element\n for (i = pending.length; i; i--) {\n if (pending[i - 1][0] == this) {\n pending.splice(i - 1, 1);\n }\n }\n }\n pending.push([this, render]);\n $.data(this, '_jqs_pending', true);\n } else {\n render.call(this);\n }\n });\n };\n\n $.fn.sparkline.defaults = getDefaults();\n\n\n $.sparkline_display_visible = function () {\n var el, i, pl;\n var done = [];\n for (i = 0, pl = pending.length; i < pl; i++) {\n el = pending[i][0];\n if ($(el).is(':visible') && !$(el).parents().is(':hidden')) {\n pending[i][1].call(el);\n $.data(pending[i][0], '_jqs_pending', false);\n done.push(i);\n } else if (!$(el).closest('html').length && !$.data(el, '_jqs_pending')) {\n // element has been inserted and removed from the DOM\n // If it was not yet inserted into the dom then the .data request\n // will return true.\n // removing from the dom causes the data to be removed.\n $.data(pending[i][0], '_jqs_pending', false);\n done.push(i);\n }\n }\n for (i = done.length; i; i--) {\n pending.splice(done[i - 1], 1);\n }\n };\n\n\n /**\n * User option handler\n */\n $.fn.sparkline.options = createClass({\n init: function (tag, userOptions) {\n var extendedOptions, defaults, base, tagOptionType;\n this.userOptions = userOptions = userOptions || {};\n this.tag = tag;\n this.tagValCache = {};\n defaults = $.fn.sparkline.defaults;\n base = defaults.common;\n this.tagOptionsPrefix = userOptions.enableTagOptions && (userOptions.tagOptionsPrefix || base.tagOptionsPrefix);\n\n tagOptionType = this.getTagSetting('type');\n if (tagOptionType === UNSET_OPTION) {\n extendedOptions = defaults[userOptions.type || base.type];\n } else {\n extendedOptions = defaults[tagOptionType];\n }\n this.mergedOptions = $.extend({}, base, extendedOptions, userOptions);\n },\n\n\n getTagSetting: function (key) {\n var prefix = this.tagOptionsPrefix,\n val, i, pairs, keyval;\n if (prefix === false || prefix === undefined) {\n return UNSET_OPTION;\n }\n if (this.tagValCache.hasOwnProperty(key)) {\n val = this.tagValCache.key;\n } else {\n val = this.tag.getAttribute(prefix + key);\n if (val === undefined || val === null) {\n val = UNSET_OPTION;\n } else if (val.substr(0, 1) === '[') {\n val = val.substr(1, val.length - 2).split(',');\n for (i = val.length; i--;) {\n val[i] = normalizeValue(val[i].replace(/(^\\s*)|(\\s*$)/g, ''));\n }\n } else if (val.substr(0, 1) === '{') {\n pairs = val.substr(1, val.length - 2).split(',');\n val = {};\n for (i = pairs.length; i--;) {\n keyval = pairs[i].split(':', 2);\n val[keyval[0].replace(/(^\\s*)|(\\s*$)/g, '')] = normalizeValue(keyval[1].replace(/(^\\s*)|(\\s*$)/g, ''));\n }\n } else {\n val = normalizeValue(val);\n }\n this.tagValCache.key = val;\n }\n return val;\n },\n\n get: function (key, defaultval) {\n var tagOption = this.getTagSetting(key),\n result;\n if (tagOption !== UNSET_OPTION) {\n return tagOption;\n }\n return (result = this.mergedOptions[key]) === undefined ? defaultval : result;\n }\n });\n\n\n $.fn.sparkline._base = createClass({\n disabled: false,\n\n init: function (el, values, options, width, height) {\n this.el = el;\n this.$el = $(el);\n this.values = values;\n this.options = options;\n this.width = width;\n this.height = height;\n this.currentRegion = undefined;\n },\n\n /**\n * Setup the canvas\n */\n initTarget: function () {\n var interactive = !this.options.get('disableInteraction');\n if (!(this.target = this.$el.simpledraw(this.width, this.height, this.options.get('composite'), interactive))) {\n this.disabled = true;\n } else {\n this.canvasWidth = this.target.pixelWidth;\n this.canvasHeight = this.target.pixelHeight;\n }\n },\n\n /**\n * Actually render the chart to the canvas\n */\n render: function () {\n if (this.disabled) {\n this.el.innerHTML = '';\n return false;\n }\n return true;\n },\n\n /**\n * Return a region id for a given x/y co-ordinate\n */\n getRegion: function (x, y) {\n },\n\n /**\n * Highlight an item based on the moused-over x,y co-ordinate\n */\n setRegionHighlight: function (el, x, y) {\n var currentRegion = this.currentRegion,\n highlightEnabled = !this.options.get('disableHighlight'),\n newRegion;\n if (x > this.canvasWidth || y > this.canvasHeight || x < 0 || y < 0) {\n return null;\n }\n newRegion = this.getRegion(el, x, y);\n if (currentRegion !== newRegion) {\n if (currentRegion !== undefined && highlightEnabled) {\n this.removeHighlight();\n }\n this.currentRegion = newRegion;\n if (newRegion !== undefined && highlightEnabled) {\n this.renderHighlight();\n }\n return true;\n }\n return false;\n },\n\n /**\n * Reset any currently highlighted item\n */\n clearRegionHighlight: function () {\n if (this.currentRegion !== undefined) {\n this.removeHighlight();\n this.currentRegion = undefined;\n return true;\n }\n return false;\n },\n\n renderHighlight: function () {\n this.changeHighlight(true);\n },\n\n removeHighlight: function () {\n this.changeHighlight(false);\n },\n\n changeHighlight: function (highlight) {},\n\n /**\n * Fetch the HTML to display as a tooltip\n */\n getCurrentRegionTooltip: function () {\n var options = this.options,\n header = '',\n entries = [],\n fields, formats, formatlen, fclass, text, i,\n showFields, showFieldsKey, newFields, fv,\n formatter, format, fieldlen, j;\n if (this.currentRegion === undefined) {\n return '';\n }\n fields = this.getCurrentRegionFields();\n formatter = options.get('tooltipFormatter');\n if (formatter) {\n return formatter(this, options, fields);\n }\n if (options.get('tooltipChartTitle')) {\n header += '
    ' + options.get('tooltipChartTitle') + '
    \\n';\n }\n formats = this.options.get('tooltipFormat');\n if (!formats) {\n return '';\n }\n if (!$.isArray(formats)) {\n formats = [formats];\n }\n if (!$.isArray(fields)) {\n fields = [fields];\n }\n showFields = this.options.get('tooltipFormatFieldlist');\n showFieldsKey = this.options.get('tooltipFormatFieldlistKey');\n if (showFields && showFieldsKey) {\n // user-selected ordering of fields\n newFields = [];\n for (i = fields.length; i--;) {\n fv = fields[i][showFieldsKey];\n if ((j = $.inArray(fv, showFields)) != -1) {\n newFields[j] = fields[i];\n }\n }\n fields = newFields;\n }\n formatlen = formats.length;\n fieldlen = fields.length;\n for (i = 0; i < formatlen; i++) {\n format = formats[i];\n if (typeof format === 'string') {\n format = new SPFormat(format);\n }\n fclass = format.fclass || 'jqsfield';\n for (j = 0; j < fieldlen; j++) {\n if (!fields[j].isNull || !options.get('tooltipSkipNull')) {\n $.extend(fields[j], {\n prefix: options.get('tooltipPrefix'),\n suffix: options.get('tooltipSuffix')\n });\n text = format.render(fields[j], options.get('tooltipValueLookups'), options);\n entries.push('
    ' + text + '
    ');\n }\n }\n }\n if (entries.length) {\n return header + entries.join('\\n');\n }\n return '';\n },\n\n getCurrentRegionFields: function () {},\n\n calcHighlightColor: function (color, options) {\n var highlightColor = options.get('highlightColor'),\n lighten = options.get('highlightLighten'),\n parse, mult, rgbnew, i;\n if (highlightColor) {\n return highlightColor;\n }\n if (lighten) {\n // extract RGB values\n parse = /^#([0-9a-f])([0-9a-f])([0-9a-f])$/i.exec(color) || /^#([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})$/i.exec(color);\n if (parse) {\n rgbnew = [];\n mult = color.length === 4 ? 16 : 1;\n for (i = 0; i < 3; i++) {\n rgbnew[i] = clipval(Math.round(parseInt(parse[i + 1], 16) * mult * lighten), 0, 255);\n }\n return 'rgb(' + rgbnew.join(',') + ')';\n }\n\n }\n return color;\n }\n\n });\n\n barHighlightMixin = {\n changeHighlight: function (highlight) {\n var currentRegion = this.currentRegion,\n target = this.target,\n shapeids = this.regionShapes[currentRegion],\n newShapes;\n // will be null if the region value was null\n if (shapeids) {\n newShapes = this.renderRegion(currentRegion, highlight);\n if ($.isArray(newShapes) || $.isArray(shapeids)) {\n target.replaceWithShapes(shapeids, newShapes);\n this.regionShapes[currentRegion] = $.map(newShapes, function (newShape) {\n return newShape.id;\n });\n } else {\n target.replaceWithShape(shapeids, newShapes);\n this.regionShapes[currentRegion] = newShapes.id;\n }\n }\n },\n\n render: function () {\n var values = this.values,\n target = this.target,\n regionShapes = this.regionShapes,\n shapes, ids, i, j;\n\n if (!this.cls._super.render.call(this)) {\n return;\n }\n for (i = values.length; i--;) {\n shapes = this.renderRegion(i);\n if (shapes) {\n if ($.isArray(shapes)) {\n ids = [];\n for (j = shapes.length; j--;) {\n shapes[j].append();\n ids.push(shapes[j].id);\n }\n regionShapes[i] = ids;\n } else {\n shapes.append();\n regionShapes[i] = shapes.id; // store just the shapeid\n }\n } else {\n // null value\n regionShapes[i] = null;\n }\n }\n target.render();\n }\n };\n\n /**\n * Line charts\n */\n $.fn.sparkline.line = line = createClass($.fn.sparkline._base, {\n type: 'line',\n\n init: function (el, values, options, width, height) {\n line._super.init.call(this, el, values, options, width, height);\n this.vertices = [];\n this.regionMap = [];\n this.xvalues = [];\n this.yvalues = [];\n this.yminmax = [];\n this.hightlightSpotId = null;\n this.lastShapeId = null;\n this.initTarget();\n },\n\n getRegion: function (el, x, y) {\n var i,\n regionMap = this.regionMap; // maps regions to value positions\n for (i = regionMap.length; i--;) {\n if (regionMap[i] !== null && x >= regionMap[i][0] && x <= regionMap[i][1]) {\n return regionMap[i][2];\n }\n }\n return undefined;\n },\n\n getCurrentRegionFields: function () {\n var currentRegion = this.currentRegion;\n return {\n isNull: this.yvalues[currentRegion] === null,\n x: this.xvalues[currentRegion],\n y: this.yvalues[currentRegion],\n color: this.options.get('lineColor'),\n fillColor: this.options.get('fillColor'),\n offset: currentRegion\n };\n },\n\n renderHighlight: function () {\n var currentRegion = this.currentRegion,\n target = this.target,\n vertex = this.vertices[currentRegion],\n options = this.options,\n spotRadius = options.get('spotRadius'),\n highlightSpotColor = options.get('highlightSpotColor'),\n highlightLineColor = options.get('highlightLineColor'),\n highlightSpot, highlightLine;\n\n if (!vertex) {\n return;\n }\n if (spotRadius && highlightSpotColor) {\n highlightSpot = target.drawCircle(vertex[0], vertex[1],\n spotRadius, undefined, highlightSpotColor);\n this.highlightSpotId = highlightSpot.id;\n target.insertAfterShape(this.lastShapeId, highlightSpot);\n }\n if (highlightLineColor) {\n highlightLine = target.drawLine(vertex[0], this.canvasTop, vertex[0],\n this.canvasTop + this.canvasHeight, highlightLineColor);\n this.highlightLineId = highlightLine.id;\n target.insertAfterShape(this.lastShapeId, highlightLine);\n }\n },\n\n removeHighlight: function () {\n var target = this.target;\n if (this.highlightSpotId) {\n target.removeShapeId(this.highlightSpotId);\n this.highlightSpotId = null;\n }\n if (this.highlightLineId) {\n target.removeShapeId(this.highlightLineId);\n this.highlightLineId = null;\n }\n },\n\n scanValues: function () {\n var values = this.values,\n valcount = values.length,\n xvalues = this.xvalues,\n yvalues = this.yvalues,\n yminmax = this.yminmax,\n i, val, isStr, isArray, sp;\n for (i = 0; i < valcount; i++) {\n val = values[i];\n isStr = typeof(values[i]) === 'string';\n isArray = typeof(values[i]) === 'object' && values[i] instanceof Array;\n sp = isStr && values[i].split(':');\n if (isStr && sp.length === 2) { // x:y\n xvalues.push(Number(sp[0]));\n yvalues.push(Number(sp[1]));\n yminmax.push(Number(sp[1]));\n } else if (isArray) {\n xvalues.push(val[0]);\n yvalues.push(val[1]);\n yminmax.push(val[1]);\n } else {\n xvalues.push(i);\n if (values[i] === null || values[i] === 'null') {\n yvalues.push(null);\n } else {\n yvalues.push(Number(val));\n yminmax.push(Number(val));\n }\n }\n }\n if (this.options.get('xvalues')) {\n xvalues = this.options.get('xvalues');\n }\n\n this.maxy = this.maxyorg = Math.max.apply(Math, yminmax);\n this.miny = this.minyorg = Math.min.apply(Math, yminmax);\n\n this.maxx = Math.max.apply(Math, xvalues);\n this.minx = Math.min.apply(Math, xvalues);\n\n this.xvalues = xvalues;\n this.yvalues = yvalues;\n this.yminmax = yminmax;\n\n },\n\n processRangeOptions: function () {\n var options = this.options,\n normalRangeMin = options.get('normalRangeMin'),\n normalRangeMax = options.get('normalRangeMax');\n\n if (normalRangeMin !== undefined) {\n if (normalRangeMin < this.miny) {\n this.miny = normalRangeMin;\n }\n if (normalRangeMax > this.maxy) {\n this.maxy = normalRangeMax;\n }\n }\n if (options.get('chartRangeMin') !== undefined && (options.get('chartRangeClip') || options.get('chartRangeMin') < this.miny)) {\n this.miny = options.get('chartRangeMin');\n }\n if (options.get('chartRangeMax') !== undefined && (options.get('chartRangeClip') || options.get('chartRangeMax') > this.maxy)) {\n this.maxy = options.get('chartRangeMax');\n }\n if (options.get('chartRangeMinX') !== undefined && (options.get('chartRangeClipX') || options.get('chartRangeMinX') < this.minx)) {\n this.minx = options.get('chartRangeMinX');\n }\n if (options.get('chartRangeMaxX') !== undefined && (options.get('chartRangeClipX') || options.get('chartRangeMaxX') > this.maxx)) {\n this.maxx = options.get('chartRangeMaxX');\n }\n\n },\n\n drawNormalRange: function (canvasLeft, canvasTop, canvasHeight, canvasWidth, rangey) {\n var normalRangeMin = this.options.get('normalRangeMin'),\n normalRangeMax = this.options.get('normalRangeMax'),\n ytop = canvasTop + Math.round(canvasHeight - (canvasHeight * ((normalRangeMax - this.miny) / rangey))),\n height = Math.round((canvasHeight * (normalRangeMax - normalRangeMin)) / rangey);\n this.target.drawRect(canvasLeft, ytop, canvasWidth, height, undefined, this.options.get('normalRangeColor')).append();\n },\n\n render: function () {\n var options = this.options,\n target = this.target,\n canvasWidth = this.canvasWidth,\n canvasHeight = this.canvasHeight,\n vertices = this.vertices,\n spotRadius = options.get('spotRadius'),\n regionMap = this.regionMap,\n rangex, rangey, yvallast,\n canvasTop, canvasLeft,\n vertex, path, paths, x, y, xnext, xpos, xposnext,\n last, next, yvalcount, lineShapes, fillShapes, plen,\n valueSpots, hlSpotsEnabled, color, xvalues, yvalues, i;\n\n if (!line._super.render.call(this)) {\n return;\n }\n\n this.scanValues();\n this.processRangeOptions();\n\n xvalues = this.xvalues;\n yvalues = this.yvalues;\n\n if (!this.yminmax.length || this.yvalues.length < 2) {\n // empty or all null valuess\n return;\n }\n\n canvasTop = canvasLeft = 0;\n\n rangex = this.maxx - this.minx === 0 ? 1 : this.maxx - this.minx;\n rangey = this.maxy - this.miny === 0 ? 1 : this.maxy - this.miny;\n yvallast = this.yvalues.length - 1;\n\n if (spotRadius && (canvasWidth < (spotRadius * 4) || canvasHeight < (spotRadius * 4))) {\n spotRadius = 0;\n }\n if (spotRadius) {\n // adjust the canvas size as required so that spots will fit\n hlSpotsEnabled = options.get('highlightSpotColor') && !options.get('disableInteraction');\n if (hlSpotsEnabled || options.get('minSpotColor') || (options.get('spotColor') && yvalues[yvallast] === this.miny)) {\n canvasHeight -= Math.ceil(spotRadius);\n }\n if (hlSpotsEnabled || options.get('maxSpotColor') || (options.get('spotColor') && yvalues[yvallast] === this.maxy)) {\n canvasHeight -= Math.ceil(spotRadius);\n canvasTop += Math.ceil(spotRadius);\n }\n if (hlSpotsEnabled ||\n ((options.get('minSpotColor') || options.get('maxSpotColor')) && (yvalues[0] === this.miny || yvalues[0] === this.maxy))) {\n canvasLeft += Math.ceil(spotRadius);\n canvasWidth -= Math.ceil(spotRadius);\n }\n if (hlSpotsEnabled || options.get('spotColor') ||\n (options.get('minSpotColor') || options.get('maxSpotColor') &&\n (yvalues[yvallast] === this.miny || yvalues[yvallast] === this.maxy))) {\n canvasWidth -= Math.ceil(spotRadius);\n }\n }\n\n\n canvasHeight--;\n\n if (options.get('normalRangeMin') !== undefined && !options.get('drawNormalOnTop')) {\n this.drawNormalRange(canvasLeft, canvasTop, canvasHeight, canvasWidth, rangey);\n }\n\n path = [];\n paths = [path];\n last = next = null;\n yvalcount = yvalues.length;\n for (i = 0; i < yvalcount; i++) {\n x = xvalues[i];\n xnext = xvalues[i + 1];\n y = yvalues[i];\n xpos = canvasLeft + Math.round((x - this.minx) * (canvasWidth / rangex));\n xposnext = i < yvalcount - 1 ? canvasLeft + Math.round((xnext - this.minx) * (canvasWidth / rangex)) : canvasWidth;\n next = xpos + ((xposnext - xpos) / 2);\n regionMap[i] = [last || 0, next, i];\n last = next;\n if (y === null) {\n if (i) {\n if (yvalues[i - 1] !== null) {\n path = [];\n paths.push(path);\n }\n vertices.push(null);\n }\n } else {\n if (y < this.miny) {\n y = this.miny;\n }\n if (y > this.maxy) {\n y = this.maxy;\n }\n if (!path.length) {\n // previous value was null\n path.push([xpos, canvasTop + canvasHeight]);\n }\n vertex = [xpos, canvasTop + Math.round(canvasHeight - (canvasHeight * ((y - this.miny) / rangey)))];\n path.push(vertex);\n vertices.push(vertex);\n }\n }\n\n lineShapes = [];\n fillShapes = [];\n plen = paths.length;\n for (i = 0; i < plen; i++) {\n path = paths[i];\n if (path.length) {\n if (options.get('fillColor')) {\n path.push([path[path.length - 1][0], (canvasTop + canvasHeight)]);\n fillShapes.push(path.slice(0));\n path.pop();\n }\n // if there's only a single point in this path, then we want to display it\n // as a vertical line which means we keep path[0] as is\n if (path.length > 2) {\n // else we want the first value\n path[0] = [path[0][0], path[1][1]];\n }\n lineShapes.push(path);\n }\n }\n\n // draw the fill first, then optionally the normal range, then the line on top of that\n plen = fillShapes.length;\n for (i = 0; i < plen; i++) {\n target.drawShape(fillShapes[i],\n options.get('fillColor'), options.get('fillColor')).append();\n }\n\n if (options.get('normalRangeMin') !== undefined && options.get('drawNormalOnTop')) {\n this.drawNormalRange(canvasLeft, canvasTop, canvasHeight, canvasWidth, rangey);\n }\n\n plen = lineShapes.length;\n for (i = 0; i < plen; i++) {\n target.drawShape(lineShapes[i], options.get('lineColor'), undefined,\n options.get('lineWidth')).append();\n }\n\n if (spotRadius && options.get('valueSpots')) {\n valueSpots = options.get('valueSpots');\n if (valueSpots.get === undefined) {\n valueSpots = new RangeMap(valueSpots);\n }\n for (i = 0; i < yvalcount; i++) {\n color = valueSpots.get(yvalues[i]);\n if (color) {\n target.drawCircle(canvasLeft + Math.round((xvalues[i] - this.minx) * (canvasWidth / rangex)),\n canvasTop + Math.round(canvasHeight - (canvasHeight * ((yvalues[i] - this.miny) / rangey))),\n spotRadius, undefined,\n color).append();\n }\n }\n\n }\n if (spotRadius && options.get('spotColor') && yvalues[yvallast] !== null) {\n target.drawCircle(canvasLeft + Math.round((xvalues[xvalues.length - 1] - this.minx) * (canvasWidth / rangex)),\n canvasTop + Math.round(canvasHeight - (canvasHeight * ((yvalues[yvallast] - this.miny) / rangey))),\n spotRadius, undefined,\n options.get('spotColor')).append();\n }\n if (this.maxy !== this.minyorg) {\n if (spotRadius && options.get('minSpotColor')) {\n x = xvalues[$.inArray(this.minyorg, yvalues)];\n target.drawCircle(canvasLeft + Math.round((x - this.minx) * (canvasWidth / rangex)),\n canvasTop + Math.round(canvasHeight - (canvasHeight * ((this.minyorg - this.miny) / rangey))),\n spotRadius, undefined,\n options.get('minSpotColor')).append();\n }\n if (spotRadius && options.get('maxSpotColor')) {\n x = xvalues[$.inArray(this.maxyorg, yvalues)];\n target.drawCircle(canvasLeft + Math.round((x - this.minx) * (canvasWidth / rangex)),\n canvasTop + Math.round(canvasHeight - (canvasHeight * ((this.maxyorg - this.miny) / rangey))),\n spotRadius, undefined,\n options.get('maxSpotColor')).append();\n }\n }\n\n this.lastShapeId = target.getLastShapeId();\n this.canvasTop = canvasTop;\n target.render();\n }\n });\n\n /**\n * Bar charts\n */\n $.fn.sparkline.bar = bar = createClass($.fn.sparkline._base, barHighlightMixin, {\n type: 'bar',\n\n init: function (el, values, options, width, height) {\n var barWidth = parseInt(options.get('barWidth'), 10),\n barSpacing = parseInt(options.get('barSpacing'), 10),\n chartRangeMin = options.get('chartRangeMin'),\n chartRangeMax = options.get('chartRangeMax'),\n chartRangeClip = options.get('chartRangeClip'),\n stackMin = Infinity,\n stackMax = -Infinity,\n isStackString, groupMin, groupMax, stackRanges,\n numValues, i, vlen, range, zeroAxis, xaxisOffset, min, max, clipMin, clipMax,\n stacked, vlist, j, slen, svals, val, yoffset, yMaxCalc, canvasHeightEf;\n bar._super.init.call(this, el, values, options, width, height);\n\n // scan values to determine whether to stack bars\n for (i = 0, vlen = values.length; i < vlen; i++) {\n val = values[i];\n isStackString = typeof(val) === 'string' && val.indexOf(':') > -1;\n if (isStackString || $.isArray(val)) {\n stacked = true;\n if (isStackString) {\n val = values[i] = normalizeValues(val.split(':'));\n }\n val = remove(val, null); // min/max will treat null as zero\n groupMin = Math.min.apply(Math, val);\n groupMax = Math.max.apply(Math, val);\n if (groupMin < stackMin) {\n stackMin = groupMin;\n }\n if (groupMax > stackMax) {\n stackMax = groupMax;\n }\n }\n }\n\n this.stacked = stacked;\n this.regionShapes = {};\n this.barWidth = barWidth;\n this.barSpacing = barSpacing;\n this.totalBarWidth = barWidth + barSpacing;\n this.width = width = (values.length * barWidth) + ((values.length - 1) * barSpacing);\n\n this.initTarget();\n\n if (chartRangeClip) {\n clipMin = chartRangeMin === undefined ? -Infinity : chartRangeMin;\n clipMax = chartRangeMax === undefined ? Infinity : chartRangeMax;\n }\n\n numValues = [];\n stackRanges = stacked ? [] : numValues;\n var stackTotals = [];\n var stackRangesNeg = [];\n for (i = 0, vlen = values.length; i < vlen; i++) {\n if (stacked) {\n vlist = values[i];\n values[i] = svals = [];\n stackTotals[i] = 0;\n stackRanges[i] = stackRangesNeg[i] = 0;\n for (j = 0, slen = vlist.length; j < slen; j++) {\n val = svals[j] = chartRangeClip ? clipval(vlist[j], clipMin, clipMax) : vlist[j];\n if (val !== null) {\n if (val > 0) {\n stackTotals[i] += val;\n }\n if (stackMin < 0 && stackMax > 0) {\n if (val < 0) {\n stackRangesNeg[i] += Math.abs(val);\n } else {\n stackRanges[i] += val;\n }\n } else {\n stackRanges[i] += Math.abs(val - (val < 0 ? stackMax : stackMin));\n }\n numValues.push(val);\n }\n }\n } else {\n val = chartRangeClip ? clipval(values[i], clipMin, clipMax) : values[i];\n val = values[i] = normalizeValue(val);\n if (val !== null) {\n numValues.push(val);\n }\n }\n }\n this.max = max = Math.max.apply(Math, numValues);\n this.min = min = Math.min.apply(Math, numValues);\n this.stackMax = stackMax = stacked ? Math.max.apply(Math, stackTotals) : max;\n this.stackMin = stackMin = stacked ? Math.min.apply(Math, numValues) : min;\n\n if (options.get('chartRangeMin') !== undefined && (options.get('chartRangeClip') || options.get('chartRangeMin') < min)) {\n min = options.get('chartRangeMin');\n }\n if (options.get('chartRangeMax') !== undefined && (options.get('chartRangeClip') || options.get('chartRangeMax') > max)) {\n max = options.get('chartRangeMax');\n }\n\n this.zeroAxis = zeroAxis = options.get('zeroAxis', true);\n if (min <= 0 && max >= 0 && zeroAxis) {\n xaxisOffset = 0;\n } else if (zeroAxis == false) {\n xaxisOffset = min;\n } else if (min > 0) {\n xaxisOffset = min;\n } else {\n xaxisOffset = max;\n }\n this.xaxisOffset = xaxisOffset;\n\n range = stacked ? (Math.max.apply(Math, stackRanges) + Math.max.apply(Math, stackRangesNeg)) : max - min;\n\n // as we plot zero/min values a single pixel line, we add a pixel to all other\n // values - Reduce the effective canvas size to suit\n this.canvasHeightEf = (zeroAxis && min < 0) ? this.canvasHeight - 2 : this.canvasHeight - 1;\n\n if (min < xaxisOffset) {\n yMaxCalc = (stacked && max >= 0) ? stackMax : max;\n yoffset = (yMaxCalc - xaxisOffset) / range * this.canvasHeight;\n if (yoffset !== Math.ceil(yoffset)) {\n this.canvasHeightEf -= 2;\n yoffset = Math.ceil(yoffset);\n }\n } else {\n yoffset = this.canvasHeight;\n }\n this.yoffset = yoffset;\n\n if ($.isArray(options.get('colorMap'))) {\n this.colorMapByIndex = options.get('colorMap');\n this.colorMapByValue = null;\n } else {\n this.colorMapByIndex = null;\n this.colorMapByValue = options.get('colorMap');\n if (this.colorMapByValue && this.colorMapByValue.get === undefined) {\n this.colorMapByValue = new RangeMap(this.colorMapByValue);\n }\n }\n\n this.range = range;\n },\n\n getRegion: function (el, x, y) {\n var result = Math.floor(x / this.totalBarWidth);\n return (result < 0 || result >= this.values.length) ? undefined : result;\n },\n\n getCurrentRegionFields: function () {\n var currentRegion = this.currentRegion,\n values = ensureArray(this.values[currentRegion]),\n result = [],\n value, i;\n for (i = values.length; i--;) {\n value = values[i];\n result.push({\n isNull: value === null,\n value: value,\n color: this.calcColor(i, value, currentRegion),\n offset: currentRegion\n });\n }\n return result;\n },\n\n calcColor: function (stacknum, value, valuenum) {\n var colorMapByIndex = this.colorMapByIndex,\n colorMapByValue = this.colorMapByValue,\n options = this.options,\n color, newColor;\n if (this.stacked) {\n color = options.get('stackedBarColor');\n } else {\n color = (value < 0) ? options.get('negBarColor') : options.get('barColor');\n }\n if (value === 0 && options.get('zeroColor') !== undefined) {\n color = options.get('zeroColor');\n }\n if (colorMapByValue && (newColor = colorMapByValue.get(value))) {\n color = newColor;\n } else if (colorMapByIndex && colorMapByIndex.length > valuenum) {\n color = colorMapByIndex[valuenum];\n }\n return $.isArray(color) ? color[stacknum % color.length] : color;\n },\n\n /**\n * Render bar(s) for a region\n */\n renderRegion: function (valuenum, highlight) {\n var vals = this.values[valuenum],\n options = this.options,\n xaxisOffset = this.xaxisOffset,\n result = [],\n range = this.range,\n stacked = this.stacked,\n target = this.target,\n x = valuenum * this.totalBarWidth,\n canvasHeightEf = this.canvasHeightEf,\n yoffset = this.yoffset,\n y, height, color, isNull, yoffsetNeg, i, valcount, val, minPlotted, allMin;\n\n vals = $.isArray(vals) ? vals : [vals];\n valcount = vals.length;\n val = vals[0];\n isNull = all(null, vals);\n allMin = all(xaxisOffset, vals, true);\n\n if (isNull) {\n if (options.get('nullColor')) {\n color = highlight ? options.get('nullColor') : this.calcHighlightColor(options.get('nullColor'), options);\n y = (yoffset > 0) ? yoffset - 1 : yoffset;\n return target.drawRect(x, y, this.barWidth - 1, 0, color, color);\n } else {\n return undefined;\n }\n }\n yoffsetNeg = yoffset;\n for (i = 0; i < valcount; i++) {\n val = vals[i];\n\n if (stacked && val === xaxisOffset) {\n if (!allMin || minPlotted) {\n continue;\n }\n minPlotted = true;\n }\n\n if (range > 0) {\n height = Math.floor(canvasHeightEf * ((Math.abs(val - xaxisOffset) / range))) + 1;\n } else {\n height = 1;\n }\n if (val < xaxisOffset || (val === xaxisOffset && yoffset === 0)) {\n y = yoffsetNeg;\n yoffsetNeg += height;\n } else {\n y = yoffset - height;\n yoffset -= height;\n }\n color = this.calcColor(i, val, valuenum);\n if (highlight) {\n color = this.calcHighlightColor(color, options);\n }\n result.push(target.drawRect(x, y, this.barWidth - 1, height - 1, color, color));\n }\n if (result.length === 1) {\n return result[0];\n }\n return result;\n }\n });\n\n /**\n * Tristate charts\n */\n $.fn.sparkline.tristate = tristate = createClass($.fn.sparkline._base, barHighlightMixin, {\n type: 'tristate',\n\n init: function (el, values, options, width, height) {\n var barWidth = parseInt(options.get('barWidth'), 10),\n barSpacing = parseInt(options.get('barSpacing'), 10);\n tristate._super.init.call(this, el, values, options, width, height);\n\n this.regionShapes = {};\n this.barWidth = barWidth;\n this.barSpacing = barSpacing;\n this.totalBarWidth = barWidth + barSpacing;\n this.values = $.map(values, Number);\n this.width = width = (values.length * barWidth) + ((values.length - 1) * barSpacing);\n\n if ($.isArray(options.get('colorMap'))) {\n this.colorMapByIndex = options.get('colorMap');\n this.colorMapByValue = null;\n } else {\n this.colorMapByIndex = null;\n this.colorMapByValue = options.get('colorMap');\n if (this.colorMapByValue && this.colorMapByValue.get === undefined) {\n this.colorMapByValue = new RangeMap(this.colorMapByValue);\n }\n }\n this.initTarget();\n },\n\n getRegion: function (el, x, y) {\n return Math.floor(x / this.totalBarWidth);\n },\n\n getCurrentRegionFields: function () {\n var currentRegion = this.currentRegion;\n return {\n isNull: this.values[currentRegion] === undefined,\n value: this.values[currentRegion],\n color: this.calcColor(this.values[currentRegion], currentRegion),\n offset: currentRegion\n };\n },\n\n calcColor: function (value, valuenum) {\n var values = this.values,\n options = this.options,\n colorMapByIndex = this.colorMapByIndex,\n colorMapByValue = this.colorMapByValue,\n color, newColor;\n\n if (colorMapByValue && (newColor = colorMapByValue.get(value))) {\n color = newColor;\n } else if (colorMapByIndex && colorMapByIndex.length > valuenum) {\n color = colorMapByIndex[valuenum];\n } else if (values[valuenum] < 0) {\n color = options.get('negBarColor');\n } else if (values[valuenum] > 0) {\n color = options.get('posBarColor');\n } else {\n color = options.get('zeroBarColor');\n }\n return color;\n },\n\n renderRegion: function (valuenum, highlight) {\n var values = this.values,\n options = this.options,\n target = this.target,\n canvasHeight, height, halfHeight,\n x, y, color;\n\n canvasHeight = target.pixelHeight;\n halfHeight = Math.round(canvasHeight / 2);\n\n x = valuenum * this.totalBarWidth;\n if (values[valuenum] < 0) {\n y = halfHeight;\n height = halfHeight - 1;\n } else if (values[valuenum] > 0) {\n y = 0;\n height = halfHeight - 1;\n } else {\n y = halfHeight - 1;\n height = 2;\n }\n color = this.calcColor(values[valuenum], valuenum);\n if (color === null) {\n return;\n }\n if (highlight) {\n color = this.calcHighlightColor(color, options);\n }\n return target.drawRect(x, y, this.barWidth - 1, height - 1, color, color);\n }\n });\n\n /**\n * Discrete charts\n */\n $.fn.sparkline.discrete = discrete = createClass($.fn.sparkline._base, barHighlightMixin, {\n type: 'discrete',\n\n init: function (el, values, options, width, height) {\n discrete._super.init.call(this, el, values, options, width, height);\n\n this.regionShapes = {};\n this.values = values = $.map(values, Number);\n this.min = Math.min.apply(Math, values);\n this.max = Math.max.apply(Math, values);\n this.range = this.max - this.min;\n this.width = width = options.get('width') === 'auto' ? values.length * 2 : this.width;\n this.interval = Math.floor(width / values.length);\n this.itemWidth = width / values.length;\n if (options.get('chartRangeMin') !== undefined && (options.get('chartRangeClip') || options.get('chartRangeMin') < this.min)) {\n this.min = options.get('chartRangeMin');\n }\n if (options.get('chartRangeMax') !== undefined && (options.get('chartRangeClip') || options.get('chartRangeMax') > this.max)) {\n this.max = options.get('chartRangeMax');\n }\n this.initTarget();\n if (this.target) {\n this.lineHeight = options.get('lineHeight') === 'auto' ? Math.round(this.canvasHeight * 0.3) : options.get('lineHeight');\n }\n },\n\n getRegion: function (el, x, y) {\n return Math.floor(x / this.itemWidth);\n },\n\n getCurrentRegionFields: function () {\n var currentRegion = this.currentRegion;\n return {\n isNull: this.values[currentRegion] === undefined,\n value: this.values[currentRegion],\n offset: currentRegion\n };\n },\n\n renderRegion: function (valuenum, highlight) {\n var values = this.values,\n options = this.options,\n min = this.min,\n max = this.max,\n range = this.range,\n interval = this.interval,\n target = this.target,\n canvasHeight = this.canvasHeight,\n lineHeight = this.lineHeight,\n pheight = canvasHeight - lineHeight,\n ytop, val, color, x;\n\n val = clipval(values[valuenum], min, max);\n x = valuenum * interval;\n ytop = Math.round(pheight - pheight * ((val - min) / range));\n color = (options.get('thresholdColor') && val < options.get('thresholdValue')) ? options.get('thresholdColor') : options.get('lineColor');\n if (highlight) {\n color = this.calcHighlightColor(color, options);\n }\n return target.drawLine(x, ytop, x, ytop + lineHeight, color);\n }\n });\n\n /**\n * Bullet charts\n */\n $.fn.sparkline.bullet = bullet = createClass($.fn.sparkline._base, {\n type: 'bullet',\n\n init: function (el, values, options, width, height) {\n var min, max, vals;\n bullet._super.init.call(this, el, values, options, width, height);\n\n // values: target, performance, range1, range2, range3\n this.values = values = normalizeValues(values);\n // target or performance could be null\n vals = values.slice();\n vals[0] = vals[0] === null ? vals[2] : vals[0];\n vals[1] = values[1] === null ? vals[2] : vals[1];\n min = Math.min.apply(Math, values);\n max = Math.max.apply(Math, values);\n if (options.get('base') === undefined) {\n min = min < 0 ? min : 0;\n } else {\n min = options.get('base');\n }\n this.min = min;\n this.max = max;\n this.range = max - min;\n this.shapes = {};\n this.valueShapes = {};\n this.regiondata = {};\n this.width = width = options.get('width') === 'auto' ? '4.0em' : width;\n this.target = this.$el.simpledraw(width, height, options.get('composite'));\n if (!values.length) {\n this.disabled = true;\n }\n this.initTarget();\n },\n\n getRegion: function (el, x, y) {\n var shapeid = this.target.getShapeAt(el, x, y);\n return (shapeid !== undefined && this.shapes[shapeid] !== undefined) ? this.shapes[shapeid] : undefined;\n },\n\n getCurrentRegionFields: function () {\n var currentRegion = this.currentRegion;\n return {\n fieldkey: currentRegion.substr(0, 1),\n value: this.values[currentRegion.substr(1)],\n region: currentRegion\n };\n },\n\n changeHighlight: function (highlight) {\n var currentRegion = this.currentRegion,\n shapeid = this.valueShapes[currentRegion],\n shape;\n delete this.shapes[shapeid];\n switch (currentRegion.substr(0, 1)) {\n case 'r':\n shape = this.renderRange(currentRegion.substr(1), highlight);\n break;\n case 'p':\n shape = this.renderPerformance(highlight);\n break;\n case 't':\n shape = this.renderTarget(highlight);\n break;\n }\n this.valueShapes[currentRegion] = shape.id;\n this.shapes[shape.id] = currentRegion;\n this.target.replaceWithShape(shapeid, shape);\n },\n\n renderRange: function (rn, highlight) {\n var rangeval = this.values[rn],\n rangewidth = Math.round(this.canvasWidth * ((rangeval - this.min) / this.range)),\n color = this.options.get('rangeColors')[rn - 2];\n if (highlight) {\n color = this.calcHighlightColor(color, this.options);\n }\n return this.target.drawRect(0, 0, rangewidth - 1, this.canvasHeight - 1, color, color);\n },\n\n renderPerformance: function (highlight) {\n var perfval = this.values[1],\n perfwidth = Math.round(this.canvasWidth * ((perfval - this.min) / this.range)),\n color = this.options.get('performanceColor');\n if (highlight) {\n color = this.calcHighlightColor(color, this.options);\n }\n return this.target.drawRect(0, Math.round(this.canvasHeight * 0.3), perfwidth - 1,\n Math.round(this.canvasHeight * 0.4) - 1, color, color);\n },\n\n renderTarget: function (highlight) {\n var targetval = this.values[0],\n x = Math.round(this.canvasWidth * ((targetval - this.min) / this.range) - (this.options.get('targetWidth') / 2)),\n targettop = Math.round(this.canvasHeight * 0.10),\n targetheight = this.canvasHeight - (targettop * 2),\n color = this.options.get('targetColor');\n if (highlight) {\n color = this.calcHighlightColor(color, this.options);\n }\n return this.target.drawRect(x, targettop, this.options.get('targetWidth') - 1, targetheight - 1, color, color);\n },\n\n render: function () {\n var vlen = this.values.length,\n target = this.target,\n i, shape;\n if (!bullet._super.render.call(this)) {\n return;\n }\n for (i = 2; i < vlen; i++) {\n shape = this.renderRange(i).append();\n this.shapes[shape.id] = 'r' + i;\n this.valueShapes['r' + i] = shape.id;\n }\n if (this.values[1] !== null) {\n shape = this.renderPerformance().append();\n this.shapes[shape.id] = 'p1';\n this.valueShapes.p1 = shape.id;\n }\n if (this.values[0] !== null) {\n shape = this.renderTarget().append();\n this.shapes[shape.id] = 't0';\n this.valueShapes.t0 = shape.id;\n }\n target.render();\n }\n });\n\n /**\n * Pie charts\n */\n $.fn.sparkline.pie = pie = createClass($.fn.sparkline._base, {\n type: 'pie',\n\n init: function (el, values, options, width, height) {\n var total = 0, i;\n\n pie._super.init.call(this, el, values, options, width, height);\n\n this.shapes = {}; // map shape ids to value offsets\n this.valueShapes = {}; // maps value offsets to shape ids\n this.values = values = $.map(values, Number);\n\n if (options.get('width') === 'auto') {\n this.width = this.height;\n }\n\n if (values.length > 0) {\n for (i = values.length; i--;) {\n total += values[i];\n }\n }\n this.total = total;\n this.initTarget();\n this.radius = Math.floor(Math.min(this.canvasWidth, this.canvasHeight) / 2);\n },\n\n getRegion: function (el, x, y) {\n var shapeid = this.target.getShapeAt(el, x, y);\n return (shapeid !== undefined && this.shapes[shapeid] !== undefined) ? this.shapes[shapeid] : undefined;\n },\n\n getCurrentRegionFields: function () {\n var currentRegion = this.currentRegion;\n return {\n isNull: this.values[currentRegion] === undefined,\n value: this.values[currentRegion],\n percent: this.values[currentRegion] / this.total * 100,\n color: this.options.get('sliceColors')[currentRegion % this.options.get('sliceColors').length],\n offset: currentRegion\n };\n },\n\n changeHighlight: function (highlight) {\n var currentRegion = this.currentRegion,\n newslice = this.renderSlice(currentRegion, highlight),\n shapeid = this.valueShapes[currentRegion];\n delete this.shapes[shapeid];\n this.target.replaceWithShape(shapeid, newslice);\n this.valueShapes[currentRegion] = newslice.id;\n this.shapes[newslice.id] = currentRegion;\n },\n\n renderSlice: function (valuenum, highlight) {\n var target = this.target,\n options = this.options,\n radius = this.radius,\n borderWidth = options.get('borderWidth'),\n offset = options.get('offset'),\n circle = 2 * Math.PI,\n values = this.values,\n total = this.total,\n next = offset ? (2*Math.PI)*(offset/360) : 0,\n start, end, i, vlen, color;\n\n vlen = values.length;\n for (i = 0; i < vlen; i++) {\n start = next;\n end = next;\n if (total > 0) { // avoid divide by zero\n end = next + (circle * (values[i] / total));\n }\n if (valuenum === i) {\n color = options.get('sliceColors')[i % options.get('sliceColors').length];\n if (highlight) {\n color = this.calcHighlightColor(color, options);\n }\n\n return target.drawPieSlice(radius, radius, radius - borderWidth, start, end, undefined, color);\n }\n next = end;\n }\n },\n\n render: function () {\n var target = this.target,\n values = this.values,\n options = this.options,\n radius = this.radius,\n borderWidth = options.get('borderWidth'),\n donutWidth = options.get('donutWidth'),\n shape, i;\n\n if (!pie._super.render.call(this)) {\n return;\n }\n if (borderWidth) {\n target.drawCircle(radius, radius, Math.floor(radius - (borderWidth / 2)),\n options.get('borderColor'), undefined, borderWidth).append();\n }\n for (i = values.length; i--;) {\n if (values[i]) { // don't render zero values\n shape = this.renderSlice(i).append();\n this.valueShapes[i] = shape.id; // store just the shapeid\n this.shapes[shape.id] = i;\n }\n }\n if (donutWidth) {\n target.drawCircle(radius, radius, radius - donutWidth, options.get('donutColor'), \n options.get('donutColor'), 0).append();\n }\n target.render();\n }\n });\n\n /**\n * Box plots\n */\n $.fn.sparkline.box = box = createClass($.fn.sparkline._base, {\n type: 'box',\n\n init: function (el, values, options, width, height) {\n box._super.init.call(this, el, values, options, width, height);\n this.values = $.map(values, Number);\n this.width = options.get('width') === 'auto' ? '4.0em' : width;\n this.initTarget();\n if (!this.values.length) {\n this.disabled = 1;\n }\n },\n\n /**\n * Simulate a single region\n */\n getRegion: function () {\n return 1;\n },\n\n getCurrentRegionFields: function () {\n var result = [\n { field: 'lq', value: this.quartiles[0] },\n { field: 'med', value: this.quartiles[1] },\n { field: 'uq', value: this.quartiles[2] }\n ];\n if (this.loutlier !== undefined) {\n result.push({ field: 'lo', value: this.loutlier});\n }\n if (this.routlier !== undefined) {\n result.push({ field: 'ro', value: this.routlier});\n }\n if (this.lwhisker !== undefined) {\n result.push({ field: 'lw', value: this.lwhisker});\n }\n if (this.rwhisker !== undefined) {\n result.push({ field: 'rw', value: this.rwhisker});\n }\n return result;\n },\n\n render: function () {\n var target = this.target,\n values = this.values,\n vlen = values.length,\n options = this.options,\n canvasWidth = this.canvasWidth,\n canvasHeight = this.canvasHeight,\n minValue = options.get('chartRangeMin') === undefined ? Math.min.apply(Math, values) : options.get('chartRangeMin'),\n maxValue = options.get('chartRangeMax') === undefined ? Math.max.apply(Math, values) : options.get('chartRangeMax'),\n canvasLeft = 0,\n lwhisker, loutlier, iqr, q1, q2, q3, rwhisker, routlier, i,\n size, unitSize;\n\n if (!box._super.render.call(this)) {\n return;\n }\n\n if (options.get('raw')) {\n if (options.get('showOutliers') && values.length > 5) {\n loutlier = values[0];\n lwhisker = values[1];\n q1 = values[2];\n q2 = values[3];\n q3 = values[4];\n rwhisker = values[5];\n routlier = values[6];\n } else {\n lwhisker = values[0];\n q1 = values[1];\n q2 = values[2];\n q3 = values[3];\n rwhisker = values[4];\n }\n } else {\n values.sort(function (a, b) { return a - b; });\n q1 = quartile(values, 1);\n q2 = quartile(values, 2);\n q3 = quartile(values, 3);\n iqr = q3 - q1;\n if (options.get('showOutliers')) {\n lwhisker = rwhisker = undefined;\n for (i = 0; i < vlen; i++) {\n if (lwhisker === undefined && values[i] > q1 - (iqr * options.get('outlierIQR'))) {\n lwhisker = values[i];\n }\n if (values[i] < q3 + (iqr * options.get('outlierIQR'))) {\n rwhisker = values[i];\n }\n }\n loutlier = values[0];\n routlier = values[vlen - 1];\n } else {\n lwhisker = values[0];\n rwhisker = values[vlen - 1];\n }\n }\n this.quartiles = [q1, q2, q3];\n this.lwhisker = lwhisker;\n this.rwhisker = rwhisker;\n this.loutlier = loutlier;\n this.routlier = routlier;\n\n unitSize = canvasWidth / (maxValue - minValue + 1);\n if (options.get('showOutliers')) {\n canvasLeft = Math.ceil(options.get('spotRadius'));\n canvasWidth -= 2 * Math.ceil(options.get('spotRadius'));\n unitSize = canvasWidth / (maxValue - minValue + 1);\n if (loutlier < lwhisker) {\n target.drawCircle((loutlier - minValue) * unitSize + canvasLeft,\n canvasHeight / 2,\n options.get('spotRadius'),\n options.get('outlierLineColor'),\n options.get('outlierFillColor')).append();\n }\n if (routlier > rwhisker) {\n target.drawCircle((routlier - minValue) * unitSize + canvasLeft,\n canvasHeight / 2,\n options.get('spotRadius'),\n options.get('outlierLineColor'),\n options.get('outlierFillColor')).append();\n }\n }\n\n // box\n target.drawRect(\n Math.round((q1 - minValue) * unitSize + canvasLeft),\n Math.round(canvasHeight * 0.1),\n Math.round((q3 - q1) * unitSize),\n Math.round(canvasHeight * 0.8),\n options.get('boxLineColor'),\n options.get('boxFillColor')).append();\n // left whisker\n target.drawLine(\n Math.round((lwhisker - minValue) * unitSize + canvasLeft),\n Math.round(canvasHeight / 2),\n Math.round((q1 - minValue) * unitSize + canvasLeft),\n Math.round(canvasHeight / 2),\n options.get('lineColor')).append();\n target.drawLine(\n Math.round((lwhisker - minValue) * unitSize + canvasLeft),\n Math.round(canvasHeight / 4),\n Math.round((lwhisker - minValue) * unitSize + canvasLeft),\n Math.round(canvasHeight - canvasHeight / 4),\n options.get('whiskerColor')).append();\n // right whisker\n target.drawLine(Math.round((rwhisker - minValue) * unitSize + canvasLeft),\n Math.round(canvasHeight / 2),\n Math.round((q3 - minValue) * unitSize + canvasLeft),\n Math.round(canvasHeight / 2),\n options.get('lineColor')).append();\n target.drawLine(\n Math.round((rwhisker - minValue) * unitSize + canvasLeft),\n Math.round(canvasHeight / 4),\n Math.round((rwhisker - minValue) * unitSize + canvasLeft),\n Math.round(canvasHeight - canvasHeight / 4),\n options.get('whiskerColor')).append();\n // median line\n target.drawLine(\n Math.round((q2 - minValue) * unitSize + canvasLeft),\n Math.round(canvasHeight * 0.1),\n Math.round((q2 - minValue) * unitSize + canvasLeft),\n Math.round(canvasHeight * 0.9),\n options.get('medianColor')).append();\n if (options.get('target')) {\n size = Math.ceil(options.get('spotRadius'));\n target.drawLine(\n Math.round((options.get('target') - minValue) * unitSize + canvasLeft),\n Math.round((canvasHeight / 2) - size),\n Math.round((options.get('target') - minValue) * unitSize + canvasLeft),\n Math.round((canvasHeight / 2) + size),\n options.get('targetColor')).append();\n target.drawLine(\n Math.round((options.get('target') - minValue) * unitSize + canvasLeft - size),\n Math.round(canvasHeight / 2),\n Math.round((options.get('target') - minValue) * unitSize + canvasLeft + size),\n Math.round(canvasHeight / 2),\n options.get('targetColor')).append();\n }\n target.render();\n }\n });\n\n // Setup a very simple \"virtual canvas\" to make drawing the few shapes we need easier\n // This is accessible as $(foo).simpledraw()\n\n VShape = createClass({\n init: function (target, id, type, args) {\n this.target = target;\n this.id = id;\n this.type = type;\n this.args = args;\n },\n append: function () {\n this.target.appendShape(this);\n return this;\n }\n });\n\n VCanvas_base = createClass({\n _pxregex: /(\\d+)(px)?\\s*$/i,\n\n init: function (width, height, target) {\n if (!width) {\n return;\n }\n this.width = width;\n this.height = height;\n this.target = target;\n this.lastShapeId = null;\n if (target[0]) {\n target = target[0];\n }\n $.data(target, '_jqs_vcanvas', this);\n },\n\n drawLine: function (x1, y1, x2, y2, lineColor, lineWidth) {\n return this.drawShape([[x1, y1], [x2, y2]], lineColor, lineWidth);\n },\n\n drawShape: function (path, lineColor, fillColor, lineWidth) {\n return this._genShape('Shape', [path, lineColor, fillColor, lineWidth]);\n },\n\n drawCircle: function (x, y, radius, lineColor, fillColor, lineWidth) {\n return this._genShape('Circle', [x, y, radius, lineColor, fillColor, lineWidth]);\n },\n\n drawPieSlice: function (x, y, radius, startAngle, endAngle, lineColor, fillColor) {\n return this._genShape('PieSlice', [x, y, radius, startAngle, endAngle, lineColor, fillColor]);\n },\n\n drawRect: function (x, y, width, height, lineColor, fillColor) {\n return this._genShape('Rect', [x, y, width, height, lineColor, fillColor]);\n },\n\n getElement: function () {\n return this.canvas;\n },\n\n /**\n * Return the most recently inserted shape id\n */\n getLastShapeId: function () {\n return this.lastShapeId;\n },\n\n /**\n * Clear and reset the canvas\n */\n reset: function () {\n alert('reset not implemented');\n },\n\n _insert: function (el, target) {\n $(target).html(el);\n },\n\n /**\n * Calculate the pixel dimensions of the canvas\n */\n _calculatePixelDims: function (width, height, canvas) {\n // XXX This should probably be a configurable option\n var match;\n match = this._pxregex.exec(height);\n if (match) {\n this.pixelHeight = match[1];\n } else {\n this.pixelHeight = $(canvas).height();\n }\n match = this._pxregex.exec(width);\n if (match) {\n this.pixelWidth = match[1];\n } else {\n this.pixelWidth = $(canvas).width();\n }\n },\n\n /**\n * Generate a shape object and id for later rendering\n */\n _genShape: function (shapetype, shapeargs) {\n var id = shapeCount++;\n shapeargs.unshift(id);\n return new VShape(this, id, shapetype, shapeargs);\n },\n\n /**\n * Add a shape to the end of the render queue\n */\n appendShape: function (shape) {\n alert('appendShape not implemented');\n },\n\n /**\n * Replace one shape with another\n */\n replaceWithShape: function (shapeid, shape) {\n alert('replaceWithShape not implemented');\n },\n\n /**\n * Insert one shape after another in the render queue\n */\n insertAfterShape: function (shapeid, shape) {\n alert('insertAfterShape not implemented');\n },\n\n /**\n * Remove a shape from the queue\n */\n removeShapeId: function (shapeid) {\n alert('removeShapeId not implemented');\n },\n\n /**\n * Find a shape at the specified x/y co-ordinates\n */\n getShapeAt: function (el, x, y) {\n alert('getShapeAt not implemented');\n },\n\n /**\n * Render all queued shapes onto the canvas\n */\n render: function () {\n alert('render not implemented');\n }\n });\n\n VCanvas_canvas = createClass(VCanvas_base, {\n init: function (width, height, target, interact) {\n VCanvas_canvas._super.init.call(this, width, height, target);\n this.canvas = document.createElement('canvas');\n if (target[0]) {\n target = target[0];\n }\n $.data(target, '_jqs_vcanvas', this);\n $(this.canvas).css({ display: 'inline-block', width: width, height: height, verticalAlign: 'top' });\n this._insert(this.canvas, target);\n this._calculatePixelDims(width, height, this.canvas);\n this.canvas.width = this.pixelWidth;\n this.canvas.height = this.pixelHeight;\n this.interact = interact;\n this.shapes = {};\n this.shapeseq = [];\n this.currentTargetShapeId = undefined;\n $(this.canvas).css({width: this.pixelWidth, height: this.pixelHeight});\n },\n\n _getContext: function (lineColor, fillColor, lineWidth) {\n var context = this.canvas.getContext('2d');\n if (lineColor !== undefined) {\n context.strokeStyle = lineColor;\n }\n context.lineWidth = lineWidth === undefined ? 1 : lineWidth;\n if (fillColor !== undefined) {\n context.fillStyle = fillColor;\n }\n return context;\n },\n\n reset: function () {\n var context = this._getContext();\n context.clearRect(0, 0, this.pixelWidth, this.pixelHeight);\n this.shapes = {};\n this.shapeseq = [];\n this.currentTargetShapeId = undefined;\n },\n\n _drawShape: function (shapeid, path, lineColor, fillColor, lineWidth) {\n var context = this._getContext(lineColor, fillColor, lineWidth),\n i, plen;\n context.beginPath();\n context.moveTo(path[0][0] + 0.5, path[0][1] + 0.5);\n for (i = 1, plen = path.length; i < plen; i++) {\n context.lineTo(path[i][0] + 0.5, path[i][1] + 0.5); // the 0.5 offset gives us crisp pixel-width lines\n }\n if (lineColor !== undefined) {\n context.stroke();\n }\n if (fillColor !== undefined) {\n context.fill();\n }\n if (this.targetX !== undefined && this.targetY !== undefined &&\n context.isPointInPath(this.targetX, this.targetY)) {\n this.currentTargetShapeId = shapeid;\n }\n },\n\n _drawCircle: function (shapeid, x, y, radius, lineColor, fillColor, lineWidth) {\n var context = this._getContext(lineColor, fillColor, lineWidth);\n context.beginPath();\n context.arc(x, y, radius, 0, 2 * Math.PI, false);\n if (this.targetX !== undefined && this.targetY !== undefined &&\n context.isPointInPath(this.targetX, this.targetY)) {\n this.currentTargetShapeId = shapeid;\n }\n if (lineColor !== undefined) {\n context.stroke();\n }\n if (fillColor !== undefined) {\n context.fill();\n }\n },\n\n _drawPieSlice: function (shapeid, x, y, radius, startAngle, endAngle, lineColor, fillColor) {\n var context = this._getContext(lineColor, fillColor);\n context.beginPath();\n context.moveTo(x, y);\n context.arc(x, y, radius, startAngle, endAngle, false);\n context.lineTo(x, y);\n context.closePath();\n if (lineColor !== undefined) {\n context.stroke();\n }\n if (fillColor) {\n context.fill();\n }\n if (this.targetX !== undefined && this.targetY !== undefined &&\n context.isPointInPath(this.targetX, this.targetY)) {\n this.currentTargetShapeId = shapeid;\n }\n },\n\n _drawRect: function (shapeid, x, y, width, height, lineColor, fillColor) {\n return this._drawShape(shapeid, [[x, y], [x + width, y], [x + width, y + height], [x, y + height], [x, y]], lineColor, fillColor);\n },\n\n appendShape: function (shape) {\n this.shapes[shape.id] = shape;\n this.shapeseq.push(shape.id);\n this.lastShapeId = shape.id;\n return shape.id;\n },\n\n replaceWithShape: function (shapeid, shape) {\n var shapeseq = this.shapeseq,\n i;\n this.shapes[shape.id] = shape;\n for (i = shapeseq.length; i--;) {\n if (shapeseq[i] == shapeid) {\n shapeseq[i] = shape.id;\n }\n }\n delete this.shapes[shapeid];\n },\n\n replaceWithShapes: function (shapeids, shapes) {\n var shapeseq = this.shapeseq,\n shapemap = {},\n sid, i, first;\n\n for (i = shapeids.length; i--;) {\n shapemap[shapeids[i]] = true;\n }\n for (i = shapeseq.length; i--;) {\n sid = shapeseq[i];\n if (shapemap[sid]) {\n shapeseq.splice(i, 1);\n delete this.shapes[sid];\n first = i;\n }\n }\n for (i = shapes.length; i--;) {\n shapeseq.splice(first, 0, shapes[i].id);\n this.shapes[shapes[i].id] = shapes[i];\n }\n\n },\n\n insertAfterShape: function (shapeid, shape) {\n var shapeseq = this.shapeseq,\n i;\n for (i = shapeseq.length; i--;) {\n if (shapeseq[i] === shapeid) {\n shapeseq.splice(i + 1, 0, shape.id);\n this.shapes[shape.id] = shape;\n return;\n }\n }\n },\n\n removeShapeId: function (shapeid) {\n var shapeseq = this.shapeseq,\n i;\n for (i = shapeseq.length; i--;) {\n if (shapeseq[i] === shapeid) {\n shapeseq.splice(i, 1);\n break;\n }\n }\n delete this.shapes[shapeid];\n },\n\n getShapeAt: function (el, x, y) {\n this.targetX = x;\n this.targetY = y;\n this.render();\n return this.currentTargetShapeId;\n },\n\n render: function () {\n var shapeseq = this.shapeseq,\n shapes = this.shapes,\n shapeCount = shapeseq.length,\n context = this._getContext(),\n shapeid, shape, i;\n context.clearRect(0, 0, this.pixelWidth, this.pixelHeight);\n for (i = 0; i < shapeCount; i++) {\n shapeid = shapeseq[i];\n shape = shapes[shapeid];\n this['_draw' + shape.type].apply(this, shape.args);\n }\n if (!this.interact) {\n // not interactive so no need to keep the shapes array\n this.shapes = {};\n this.shapeseq = [];\n }\n }\n\n });\n\n VCanvas_vml = createClass(VCanvas_base, {\n init: function (width, height, target) {\n var groupel;\n VCanvas_vml._super.init.call(this, width, height, target);\n if (target[0]) {\n target = target[0];\n }\n $.data(target, '_jqs_vcanvas', this);\n this.canvas = document.createElement('span');\n $(this.canvas).css({ display: 'inline-block', position: 'relative', overflow: 'hidden', width: width, height: height, margin: '0px', padding: '0px', verticalAlign: 'top'});\n this._insert(this.canvas, target);\n this._calculatePixelDims(width, height, this.canvas);\n this.canvas.width = this.pixelWidth;\n this.canvas.height = this.pixelHeight;\n groupel = '';\n this.canvas.insertAdjacentHTML('beforeEnd', groupel);\n this.group = $(this.canvas).children()[0];\n this.rendered = false;\n this.prerender = '';\n },\n\n _drawShape: function (shapeid, path, lineColor, fillColor, lineWidth) {\n var vpath = [],\n initial, stroke, fill, closed, vel, plen, i;\n for (i = 0, plen = path.length; i < plen; i++) {\n vpath[i] = '' + (path[i][0]) + ',' + (path[i][1]);\n }\n initial = vpath.splice(0, 1);\n lineWidth = lineWidth === undefined ? 1 : lineWidth;\n stroke = lineColor === undefined ? ' stroked=\"false\" ' : ' strokeWeight=\"' + lineWidth + 'px\" strokeColor=\"' + lineColor + '\" ';\n fill = fillColor === undefined ? ' filled=\"false\"' : ' fillColor=\"' + fillColor + '\" filled=\"true\" ';\n closed = vpath[0] === vpath[vpath.length - 1] ? 'x ' : '';\n vel = '' +\n ' ';\n return vel;\n },\n\n _drawCircle: function (shapeid, x, y, radius, lineColor, fillColor, lineWidth) {\n var stroke, fill, vel;\n x -= radius;\n y -= radius;\n stroke = lineColor === undefined ? ' stroked=\"false\" ' : ' strokeWeight=\"' + lineWidth + 'px\" strokeColor=\"' + lineColor + '\" ';\n fill = fillColor === undefined ? ' filled=\"false\"' : ' fillColor=\"' + fillColor + '\" filled=\"true\" ';\n vel = '';\n return vel;\n\n },\n\n _drawPieSlice: function (shapeid, x, y, radius, startAngle, endAngle, lineColor, fillColor) {\n var vpath, startx, starty, endx, endy, stroke, fill, vel;\n if (startAngle === endAngle) {\n return ''; // VML seems to have problem when start angle equals end angle.\n }\n if ((endAngle - startAngle) === (2 * Math.PI)) {\n startAngle = 0.0; // VML seems to have a problem when drawing a full circle that doesn't start 0\n endAngle = (2 * Math.PI);\n }\n\n startx = x + Math.round(Math.cos(startAngle) * radius);\n starty = y + Math.round(Math.sin(startAngle) * radius);\n endx = x + Math.round(Math.cos(endAngle) * radius);\n endy = y + Math.round(Math.sin(endAngle) * radius);\n\n if (startx === endx && starty === endy) {\n if ((endAngle - startAngle) < Math.PI) {\n // Prevent very small slices from being mistaken as a whole pie\n return '';\n }\n // essentially going to be the entire circle, so ignore startAngle\n startx = endx = x + radius;\n starty = endy = y;\n }\n\n if (startx === endx && starty === endy && (endAngle - startAngle) < Math.PI) {\n return '';\n }\n\n vpath = [x - radius, y - radius, x + radius, y + radius, startx, starty, endx, endy];\n stroke = lineColor === undefined ? ' stroked=\"false\" ' : ' strokeWeight=\"1px\" strokeColor=\"' + lineColor + '\" ';\n fill = fillColor === undefined ? ' filled=\"false\"' : ' fillColor=\"' + fillColor + '\" filled=\"true\" ';\n vel = '' +\n ' ';\n return vel;\n },\n\n _drawRect: function (shapeid, x, y, width, height, lineColor, fillColor) {\n return this._drawShape(shapeid, [[x, y], [x, y + height], [x + width, y + height], [x + width, y], [x, y]], lineColor, fillColor);\n },\n\n reset: function () {\n this.group.innerHTML = '';\n },\n\n appendShape: function (shape) {\n var vel = this['_draw' + shape.type].apply(this, shape.args);\n if (this.rendered) {\n this.group.insertAdjacentHTML('beforeEnd', vel);\n } else {\n this.prerender += vel;\n }\n this.lastShapeId = shape.id;\n return shape.id;\n },\n\n replaceWithShape: function (shapeid, shape) {\n var existing = $('#jqsshape' + shapeid),\n vel = this['_draw' + shape.type].apply(this, shape.args);\n existing[0].outerHTML = vel;\n },\n\n replaceWithShapes: function (shapeids, shapes) {\n // replace the first shapeid with all the new shapes then toast the remaining old shapes\n var existing = $('#jqsshape' + shapeids[0]),\n replace = '',\n slen = shapes.length,\n i;\n for (i = 0; i < slen; i++) {\n replace += this['_draw' + shapes[i].type].apply(this, shapes[i].args);\n }\n existing[0].outerHTML = replace;\n for (i = 1; i < shapeids.length; i++) {\n $('#jqsshape' + shapeids[i]).remove();\n }\n },\n\n insertAfterShape: function (shapeid, shape) {\n var existing = $('#jqsshape' + shapeid),\n vel = this['_draw' + shape.type].apply(this, shape.args);\n existing[0].insertAdjacentHTML('afterEnd', vel);\n },\n\n removeShapeId: function (shapeid) {\n var existing = $('#jqsshape' + shapeid);\n this.group.removeChild(existing[0]);\n },\n\n getShapeAt: function (el, x, y) {\n var shapeid = el.id.substr(8);\n return shapeid;\n },\n\n render: function () {\n if (!this.rendered) {\n // batch the intial render into a single repaint\n this.group.innerHTML = this.prerender;\n this.rendered = true;\n }\n }\n });\n\n}))}(document, Math));\n", "import './vendor';\nimport 'jquery-sparkline';\nimport { authFetch } from './authWrap';\nimport { error, log } from './logger';\n\ninterface GpuInfo {\n name: string;\n data: Record;\n chart?: [number, number];\n}\n\nlet gpuInterval: ReturnType | null = null;\nconst chartData: { mem: number[]; load: number[] } = { mem: [], load: [] };\n\nasync function updateGPUChart(mem: number, load: number): Promise {\n const maxLen = 120;\n const colorRangeMap = $.range_map({\n '0:5': '#fffafa',\n '6:10': '#fff7ed',\n '11:20': '#fed7aa',\n '21:30': '#fdba74',\n '31:40': '#fb923c',\n '41:50': '#f97316',\n '51:60': '#ea580c',\n '61:70': '#c2410c',\n '71:80': '#9a3412',\n '81:90': '#7c2d12',\n '91:100': '#6c2e12',\n });\n const sparklineConfigLOAD = { type: 'bar', height: '128px', barWidth: '3px', barSpacing: '1px', chartRangeMin: 0, chartRangeMax: 100, barColor: '#89007D' };\n const sparklineConfigMEM = { type: 'bar', height: '128px', barWidth: '3px', barSpacing: '1px', chartRangeMin: 0, chartRangeMax: 100, colorMap: colorRangeMap, composite: true };\n if (chartData.load.length > maxLen) chartData.load.shift();\n chartData.load.push(load);\n if (chartData.mem.length > maxLen) chartData.mem.shift();\n chartData.mem.push(mem);\n $('#gpuChart').sparkline(chartData.load, sparklineConfigLOAD);\n $('#gpuChart').sparkline(chartData.mem, sparklineConfigMEM);\n}\n\nasync function updateGPU(): Promise {\n const gpuEl = document.getElementById('gpu');\n const gpuTable = document.getElementById('gpu-table');\n if (!gpuEl || !gpuTable) return;\n try {\n const res = await authFetch(`${window.api}/gpu-smi`);\n if (!res || !res.ok) {\n clearInterval(gpuInterval);\n gpuEl.style.display = 'none';\n return;\n }\n const data = (await res.json()) as GpuInfo[];\n if (!data) {\n clearInterval(gpuInterval);\n gpuEl.style.display = 'none';\n return;\n }\n const gpuTbody = gpuTable.querySelector('tbody');\n if (!gpuTbody) return;\n let gpu = { data: {} } as GpuInfo;\n if (Array.isArray(data) && data.length >= 1) gpu = data[0];\n let rows = `GPU${gpu.name || 'unknown'}`;\n for (const item of Object.entries(gpu.data)) rows += `${item[0]}${item[1]}`;\n gpuTbody.innerHTML = rows;\n if (gpu.chart && gpu.chart.length === 2) updateGPUChart(gpu.chart[0], gpu.chart[1]);\n gpuEl.style.display = 'block';\n } catch (e) {\n error('updateGPU', e);\n clearInterval(gpuInterval);\n gpuEl.style.display = 'none';\n }\n}\n\nexport async function startGPU(): Promise {\n const gpuEl = document.getElementById('gpu');\n if (!gpuEl) return;\n gpuEl.style.display = 'block';\n if (gpuInterval) clearInterval(gpuInterval);\n const interval = window.opts?.gpu_monitor || 3000;\n log('startGPUmonitor', interval);\n gpuInterval = setInterval(updateGPU, interval);\n updateGPU();\n}\n\nwindow.startGPU = startGPU;\n\nexport async function disableGPU(): Promise {\n clearInterval(gpuInterval);\n const gpuEl = document.getElementById('gpu');\n if (gpuEl) gpuEl.style.display = 'none';\n}\n\nwindow.disableGPU = disableGPU;\n"], + "mappings": "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", + "names": ["global", "window", "i", "jQuery", "arr", "matches", "escape", "value", "document", "dir", "parent", "hash", "preFilter", "token", "find", "elem", "self", "add", "deferred", "process", "error", "data", "el", "nodeName", "types", "event", "name", "schedule", "opts", "index", "length", "timers", "timer", "location", "val", "url", "completed", "done", "method", "type", "undefined", "requestAnimationFrame", "timer", "addEventListener", "el", "log", "event", "iframeId", "location", "hash", "error", "MutationObserver", "options", "isVisible", "$", "e", "t", "i", "n", "s", "r", "a", "o", "l", "h", "u", "c", "f", "d", "K", "$", "eventify", "subject", "validateSubject", "eventsStorage", "createEventsStorage", "registeredEvents", "eventName", "callback", "ctx", "handlers", "callbacks", "fireArguments", "i", "callbackInfo", "reservedWords", "cancelAnimationFrame", "requestAnimationFrame", "isNaN", "parent", "onKeyDown", "el", "jQuery", "el", "url", "user", "token", "authFetch", "url", "event", "authFetch", "el", "isVisible", "el", "el", "el", "event", "el", "el", "event", "el", "el", "authFetch", "el", "gallerySelection", "authFetch", "authFetch", "updateInput", "active", "el", "el", "el", "updateInput", "updateInput", "event", "hash", "atBottom", "el", "authFetch", "parent", "el", "authFetch", "el", "authFetch", "Hash", "HMAC", "hash", "hmac", "authFetch", "parent", "authFetch", "event", "el", "modalImage", "modal", "gallerySelection", "event", "exifr", "Panzoom", "updateInput", "el", "el", "el", "event", "appendContextMenuOption", "removeContextMenuOption", "addContextMenuEventListener", "busy", "el", "authFetch", "el", "url", "authFetch", "url", "updateInput", "el", "el", "authFetch", "url", "url", "authFetch", "ts", "authFetch", "el", "delay", "event", "updateInput", "document", "Math", "undefined", "$", "format", "self", "token", "el", "width", "height", "target", "interact", "shapeCount", "authFetch"] } diff --git a/ui/dynamicUI.ts b/ui/dynamicUI.ts index eca71832c..e20fc56ba 100644 --- a/ui/dynamicUI.ts +++ b/ui/dynamicUI.ts @@ -18,7 +18,7 @@ async function updateUI(model: Model) { export async function updateModel() { const req = await authFetch(`${window.api}/checkpoint`); - if (req.ok) { + if (req && req.ok) { const model = await req.json() as Model; if (model?.type?.length > 0) updateUI(model); } diff --git a/ui/extraNetworks.ts b/ui/extraNetworks.ts index 36958c925..8f03ad0e5 100644 --- a/ui/extraNetworks.ts +++ b/ui/extraNetworks.ts @@ -103,7 +103,7 @@ function readCardTags(el, tags) { updateInput(textarea); }; - if (tags.length === 0) return; + if (!tags || tags.length === 0) return; const cardTags = tags.split('|'); if (!cardTags || cardTags.length === 0) return; const tagsEl = el.getElementsByClassName('tags')[0]; diff --git a/ui/gallery.ts b/ui/gallery.ts index f7139f412..67d3b9eb9 100644 --- a/ui/gallery.ts +++ b/ui/gallery.ts @@ -325,6 +325,7 @@ class SimpleProgressBar { } update(loaded, max) { + // log('galleryUpdate', { loaded, max }); this.#progress.style.width = `${Math.floor((loaded / max) * 100)}%`; this.#text.textContent = `${loaded}/${max}`; if (!this.#visible) { @@ -503,7 +504,7 @@ async function delayFetchThumb(fn, signal) { outstanding++; const ts = t0.toString(); const res = await authFetch(`${window.api}/browser/thumb?file=${encodeURI(fn)}&ts=${ts}&exif=false`, { priority: 'low' }); - if (!res.ok) { + if (!res?.ok) { error(`fetchThumb: ${res.statusText}`); return undefined; } @@ -1466,6 +1467,7 @@ async function observeImageError(img: HTMLImageElement) { // eslint-disable-next-line import-x/no-unresolved const { default: heic2any } = await import('https://esm.sh/heic2any@0.0.4'); const res = await authFetch(origSrc); + if (!res || res.status !== 200) return; const imageBlob = await res.blob(); if (!imageBlob || imageBlob.size <= 1024) { error('imageHEIC', { src: origSrc, res, blob: imageBlob }); diff --git a/ui/globals.d.ts b/ui/globals.d.ts index 9def89c66..889d5d338 100644 --- a/ui/globals.d.ts +++ b/ui/globals.d.ts @@ -23,6 +23,7 @@ declare global { // state objects api: string; // ui/startup.ts subpath: string; // ui/startup.ts + initStartup?: () => void; // ui/startup.ts opts: Record; // ui/ui.ts localization?: Record; // ui/ui.ts titles?: Record; // ui/ui.ts @@ -93,7 +94,7 @@ declare global { downloadCivitModel?: (...args: unknown[]) => unknown[]; // ui/civitai.ts modelCardClick?: (id: string | number) => Promise; // ui/civitai.ts startCivitAllDownload?: (evt: Event) => void; // ui/civitai.ts - startCivitDownload?: (url: string, name: string, type: string, base: string, modelId: number, versionId: number) => void; // ui/civitai.ts + startCivitFileDownload?: (versionId: number, fileId: number) => void; // ui/civitai.ts clickDocsPage?: (page: string) => Promise; // ui/docs.ts getDocsPage?: () => string; // ui/docs.ts getGitHubWikiPage?: () => string; // ui/docs.ts @@ -141,6 +142,7 @@ declare global { onUiUpdate?: (callback: () => void) => void; // ui/script.ts timer?: (name: string, elapsed: number) => Promise; // ui/timers.ts markIfModified?: (setting_name: string, value: unknown) => void; // ui/settings.ts + openSettingsSection?: (sectionId: string) => void; // ui/settings.ts appendContextMenuOption?: (targetElementSelector: string, entryName: string, entryFunction: () => void, primary?: boolean) => string; // ui/contextMenus.ts generateForever?: (genbuttonid: string) => void; // ui/contextMenus.ts removeContextMenuOption?: (id: string) => void; // ui/contextMenus.ts diff --git a/ui/js/login.js b/ui/js/login.js index 02fb71fc3..0ff90ce39 100644 --- a/ui/js/login.js +++ b/ui/js/login.js @@ -34,6 +34,9 @@ function forceLogin() { document.body.appendChild(form); const status = form.querySelector('#loginStatus'); + if (!status) { + console.error('forceLogin', 'loginStatus element not found'); + } form.addEventListener('submit', (event) => { event.preventDefault(); diff --git a/ui/loader.ts b/ui/loader.ts index c20b241bc..4e4e7b46b 100644 --- a/ui/loader.ts +++ b/ui/loader.ts @@ -112,6 +112,16 @@ async function createSplash() { .catch((err) => error(`getMOTD: ${err}`)); log('loadGradioUi'); + + const splashMonitor = setInterval(() => { + const splashVisible = !!document.getElementById('splash'); + if (splashVisible) { + log('splashVisible', { visible: true, elapsed: Math.round(performance.now() - appStartTime) }); + } else { + log('splashVisible', { visible: false, elapsed: Math.round(performance.now() - appStartTime) }); + clearInterval(splashMonitor); + } + }, 5000); } window.onload = createSplash; diff --git a/ui/locale/locale_en.json b/ui/locale/locale_en.json index 089b239b6..c695b60c5 100644 --- a/ui/locale/locale_en.json +++ b/ui/locale/locale_en.json @@ -152,7 +152,11 @@ {"id":"","label":"Adapter 2","localized":"","hint":"","ui":"txt2img"}, {"id":"","label":"Adapter 3","localized":"","hint":"","ui":"txt2img"}, {"id":"","label":"Adapter 4","localized":"","hint":"","ui":"txt2img"}, - {"id":"","label":"Audio","localized":"","hint":"","ui":"video"} + {"id":"","label":"Audio","localized":"","hint":"","ui":"video"}, + {"id":"","label":"Attention method","localized":"","hint":"Attention processor the pipeline is loaded with.

    Scaled-Dot-Product uses torch attention and is the path the rest of this section builds on; SDP kernels and SDP overrides apply to it and to nothing else.
    xFormers uses the xFormers library on the modules that accept it.
    Disabled leaves whatever the pipeline was built with.

    Default Scaled-Dot-Product.","ui":"settings_cuda"}, + {"id":"","label":"Attention slicing","localized":"","hint":"Computes attention in slices instead of one pass, trading speed for a lower memory peak. Applied by the pipeline rather than by the kernel, so it stacks on whichever Attention method is active.

    Default leaves the pipeline's own choice untouched, which for most models means off.
    Enabled and Disabled override that choice.

    Unrelated to Dynamic attention, which slices by a memory estimate; this one is diffusers' fixed slicing.

    Default Default.","ui":"settings_cuda"}, + {"id":"","label":"Attention Dispatcher","localized":"","hint":"Diffusers keeps its own attention backend registry, separate from the torch level settings above. A backend chosen here is installed on the model itself and changes what diffusers dispatches to inside its transformer blocks.

    Applies to diffusion transformer models that expose the call. UNet models and pipelines without it are left alone.","ui":"settings_cuda"}, + {"id":"","label":"Attention dispatcher kernel","localized":"","hint":"Name of the diffusers attention backend to install on the model. Empty leaves the diffusers default in place.

    Accepted names come from the diffusers build in use and currently include native, flash, flash_varlen, flex, sage, sage_varlen and xformers, alongside underscore-prefixed variants that pin one specific kernel.
    A name is checked against that list, and an unrecognized one is logged as a warning with the full list while the model keeps its current backend. A recognized name whose package is missing is logged as an error at the same point, with the same result.
    Names ending in _hub fetch the kernel from the Hugging Face Hub on first use, which needs a download and the kernels package.

    Empty by default.","ui":"settings_cuda"} ], "b": [ {"id":"","label":"Batch","localized":"","hint":"Batch processing settings","ui":"img2img"}, @@ -189,7 +193,6 @@ {"id":"","label":"block_level","localized":"","hint":"","ui":"settings_offload"}, {"id":"","label":"Backend storage","localized":"","hint":"","ui":"settings_quantization"}, {"id":"","label":"BF16","localized":"","hint":"Use modified 16-bit floating point precision for calculations","ui":"settings_cuda"}, - {"id":"","label":"Batch matrix-matrix","localized":"","hint":"Standard batched matrix multiplication for attention. Reliable but not VRAM-efficient.","ui":"settings_cuda"}, {"id":"","label":"BCFHW","localized":"","hint":"","ui":"settings_advanced"}, {"id":"","label":"BFCHW","localized":"","hint":"","ui":"settings_advanced"}, {"id":"","label":"BCHW","localized":"","hint":"","ui":"settings_advanced"}, @@ -234,7 +237,7 @@ {"id":"","label":"Control Media","localized":"","hint":"Add input image as separate initialization image for control processing","ui":"control"}, {"id":"","label":"Create Video","localized":"","hint":"","ui":"extras"}, {"id":"","label":"ChronoEdit","localized":"","hint":"","ui":"settings_model_options"}, - {"id":"","label":"Cross Attention","localized":"","hint":"","ui":"settings_cuda"}, + {"id":"","label":"Cross Attention","localized":"","hint":"Selects how attention is computed during generation. Attention is where a diffusion model spends most of its time and most of its peak memory, so these settings move both.

    Three layers apply in order. Attention method picks the attention processor the pipeline is loaded with. SDP kernels limits which kernels torch may choose from inside its own attention. SDP overrides replaces torch attention with a different implementation for the calls that implementation accepts.
    Overrides are tried in priority order and each one declines the calls it cannot serve, so several can be enabled at once and whatever is left over falls back to torch.","ui":"settings_cuda"}, {"id":"","label":"CLiP Skip","localized":"","hint":"Early stopping parameter for the CLiP text encoder; 1 is stop at last layer as usual, 2 is stop at penultimate layer, etc","ui":"settings_advanced"}, {"id":"","label":"Cache-DiT","localized":"","hint":"","ui":"settings_advanced"}, {"id":"","label":"CFG-Zero","localized":"","hint":"","ui":"settings_advanced"}, @@ -397,10 +400,9 @@ {"id":"","label":"Dequantize using torch.compile","localized":"","hint":"Compiles the dequantization step with torch.compile for faster inference. Requires Triton.

    Changing this needs a full restart to take effect.

    Enabled by default when Triton is available.","reload":"server","ui":"settings_quantization"}, {"id":"","label":"Dequantize using full precision","localized":"","hint":"Uses FP32 for the dequantization step for better numerical accuracy, at a small speed cost.

    Enabled by default.","reload":"model","ui":"settings_quantization"}, {"id":"","label":"Disabled","localized":"","hint":"","ui":"settings_cuda"}, - {"id":"","label":"Dynamic Attention BMM","localized":"","hint":"Performs attention computation in steps instead of all at once. Slower inference times, but greatly reduced memory usage","ui":"settings_cuda"}, {"id":"","label":"Dynamic attention","localized":"","hint":"Adjusts attention computation dynamically per step. Saves VRAM but slows generation.","ui":"settings_cuda"}, - {"id":"","label":"Dynamic Attention slicing rate","localized":"","hint":"","ui":"settings_cuda"}, - {"id":"","label":"Dynamic Attention trigger rate","localized":"","hint":"","ui":"settings_cuda"}, + {"id":"","label":"Dynamic Attention slicing rate","localized":"","hint":"Target size in GB for each attention slice once Dynamic attention starts slicing. Smaller slices hold the peak lower and add more per-slice overhead.
    Slicing is applied across the batch first, then across attention heads, then across query tokens, going a level deeper whenever the level above is still over target.

    Applies while Dynamic attention is enabled in SDP overrides.
    Default 0.5.","ui":"settings_cuda"}, + {"id":"","label":"Dynamic Attention trigger rate","localized":"","hint":"Estimated attention matrix size in GB above which Dynamic attention begins slicing. Below it the call runs in one pass.
    The estimate is batch x heads x query length x key length x bytes per element, so it grows with the square of the sequence length and crosses the threshold at high resolution or on video long before it does anywhere else.

    Applies while Dynamic attention is enabled in SDP overrides.
    Default 1.","ui":"settings_cuda"}, {"id":"","label":"Deterministic mode","localized":"","hint":"Forces deterministic output across runs. Useful for reproducibility, but may disable some optimizations.","ui":"settings_backends"}, {"id":"","label":"DirectML retry ops for NaN","localized":"","hint":"","ui":"settings_backends"}, {"id":"","label":"deep-cache","localized":"","hint":"","ui":"settings_compile"}, @@ -414,7 +416,7 @@ {"id":"","label":"Desktop","localized":"","hint":"","ui":"settings_ui"}, {"id":"","label":"Downscale high resolution live previews","localized":"","hint":"","ui":"settings_live-preview"}, {"id":"","label":"Detailer use model augment","localized":"","hint":"Run detailer detection models at extra precision","ui":"settings_postprocessing"}, - {"id":"","label":"Default strength","localized":"","hint":"When adding extra network such as Lora to prompt, use this multiplier for it","ui":"settings_extra_networks"}, + {"id":"","label":"Default strength","localized":"","hint":"When adding extra network such as Lora to prompt, use this multiplier for it","ui":"settings_lora"}, {"id":"","label":"Do not change selected model when reading generation parameters","localized":"","hint":"","ui":"settings_legacy_options"}, {"id":"","label":"Do conditional and unconditional denoising in one batch","localized":"","hint":"","ui":"settings_legacy_options"}, {"id":"","label":"Disable NaN check","localized":"","hint":"","ui":"settings_legacy_options"}, @@ -622,7 +624,8 @@ {"id":"","label":"Generic","localized":"","hint":"","ui":"video"}, {"id":"","label":"Google GenAI","localized":"","hint":"","ui":"settings_model_options"}, {"id":"","label":"Group Offload","localized":"","hint":"Offloads components in groups of layers rather than as a whole, so only the layers in use occupy VRAM.
    Lets a single component larger than the card run, at the cost of transferring weights throughout every step.

    Applies only when Model offload mode is group.","ui":"settings_offload"}, - {"id":"","label":"Group offload type","localized":"","hint":"Granularity used by group offload.
    - leaf_level: offloads at the smallest module level; maximum memory savings, slower
    - block_level: offloads groups of transformer blocks (size set by Offload blocks); faster with less savings
    This setting applies to the parts of the model that run at every step. Components used once per generation, such as text encoders, always offload at leaf_level. The VAE is handled separately: it waits in system memory and loads as a whole when encoding or decoding.
    Anything named in Modules to never offload or Model types not to offload stays in VRAM instead.

    Applies only when Model offload mode is group.

    Default is leaf_level.","ui":"settings_offload"}, + {"id":"","label":"Group offload type","localized":"","hint":"Granularity used by group offload.
    - leaf_level: offloads at the smallest module level; maximum memory savings, slower
    - block_level: offloads groups of transformer blocks (size set by Group offload blocks, one block when Prefetch with streams is enabled); faster with less savings
    This setting applies to the parts of the model that run at every step. Components used once per generation, such as text encoders, always offload at leaf_level. The VAE is handled separately: it waits in system memory and loads as a whole when encoding or decoding.
    Anything named in Modules to never offload or Model types not to offload stays in VRAM instead.

    Applies only when Model offload mode is group.

    Default is leaf_level.","ui":"settings_offload"}, + {"id":"","label":"Group offload blocks","localized":"","hint":"Number of transformer blocks moved together as one group on block_level group offload. Larger groups mean fewer, larger transfers and more weights resident in VRAM at once.
    Ignored when Prefetch with streams is enabled, which runs one block per group, and on leaf_level, which has no blocks. Components used once per generation always offload at leaf_level and never read this value.

    Applies only when Model offload mode is group.

    Default is 1.","ui":"settings_offload"}, {"id":"","label":"Grid Options","localized":"","hint":"","ui":"settings_saving-images"}, {"id":"","label":"Grids","localized":"","hint":"","ui":"settings_saving-paths"}, {"id":"","label":"Guider","localized":"","hint":"","ui":"txt2img"}, @@ -857,14 +860,21 @@ {"id":"","label":"Log view update period","localized":"","hint":"Log view update period, in milliseconds","ui":"settings_ui"}, {"id":"","label":"Live preview display period","localized":"","hint":"Request preview image every n steps, set to 0 to disable","ui":"settings_live-preview"}, {"id":"","label":"Load custom Diffusers pipeline","localized":"","hint":"","ui":"settings_huggingface"}, - {"id":"","label":"LoRA force reload always","localized":"","hint":"Forces LoRA networks to reload from storage on every generation, even if already cached.
    Useful for debugging or when LoRA files are being modified externally.
    Disable for normal use to benefit from caching.","ui":"settings_extra_networks"}, - {"id":"","label":"LoRA load using Diffusers method","localized":"","hint":"Alternative method uses diffusers built-in LoRA capabilities instead of native SD.Next implementation (may reduce LoRA compatibility)","ui":"settings_extra_networks"}, - {"id":"","label":"LoRA native apply to text encoder","localized":"","hint":"","ui":"settings_extra_networks"}, - {"id":"","label":"LoRA native fuse with model","localized":"","hint":"Merge LoRA into the model for lower memory usage.

    Warning: 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.","ui":"settings_extra_networks"}, - {"id":"","label":"LoRA diffusers fuse with model","localized":"","hint":"Merge LoRA into the model for lower memory usage and torch.compile compatibility.

    Warning: 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.","ui":"settings_extra_networks"}, - {"id":"","label":"LoRA auto-apply tags","localized":"","hint":"Automatically add trigger words/tags from LoRA metadata to your prompt.
    Set to the number of tags to auto-apply, e.g., 3 = add top 3 trigger tags.
    Set to 0 to disable, -1 to add all available tags.","ui":"settings_extra_networks"}, - {"id":"","label":"LoRA memory cache","localized":"","hint":"How many LoRAs to keep in network for future use before requiring reloading from storage","ui":"settings_extra_networks"}, - {"id":"","label":"LoRA add hash info to metadata","localized":"","hint":"Include LoRA file hashes in generated image metadata.
    Useful for reproducibility and tracking which exact LoRA versions were used.","ui":"settings_extra_networks"}, + {"id":"","label":"LoRA force reload always","localized":"","hint":"Forces LoRA networks to reload from storage on every generation, even if already cached.
    Useful for debugging or when LoRA files are being modified externally.
    Disable for normal use to benefit from caching.","ui":"settings_lora"}, + {"id":"","label":"LoRA load using Diffusers method","localized":"","hint":"Alternative method uses diffusers built-in LoRA capabilities instead of native SD.Next implementation (may reduce LoRA compatibility)","ui":"settings_lora"}, + {"id":"","label":"LoRA native fuse with model","localized":"","hint":"Merge LoRA into the model for lower memory usage.

    Warning: 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.","ui":"settings_lora"}, + {"id":"","label":"LoRA diffusers fuse with model","localized":"","hint":"Merge LoRA into the model for lower memory usage and torch.compile compatibility.

    Warning: 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.","ui":"settings_lora"}, + {"id":"","label":"LoRA quantized apply method","localized":"","hint":"How networks are applied to SDNQ-quantized model weights:
    - exact: adapters are carried alongside the quantized weights at full precision; apply and removal are exact and the quantized weights are never modified. The carried factors take additional VRAM, growing with adapter rank, size and count
    - requantize: adapters are merged into the quantized weights, matching the behavior of earlier releases. Uses no additional VRAM (a weight backup for network removal is held in system RAM); on models quantized below 8 bits rounding typically loses much of the adapter effect, with strong adapters retaining more

    With requantize selected, the host rank, calibration and cache options below have no effect.

    Default is exact.","ui":"settings_lora"}, + {"id":"","label":"LoRA quantized host rank","localized":"","hint":"Maximum rank used to carry adapter types that are not natively low-rank (LoKR, LoHA, OFT, DoRA) alongside the quantized weights instead of merging them in.
    Higher values retain more of the adapter at proportionally more memory. Plain LoRA files are carried exactly at their own rank.

    Applies only to SDNQ models quantized below 8 bits, where merging erases most of the adapter; at 8 bits and above merging retains it and hosting is skipped.

    0 disables hosting and merges every adapter into the quantized weights.

    Default is 256.","ui":"settings_lora"}, + {"id":"","label":"LoRA quantized host calibration","localized":"","hint":"Collects per-channel activation statistics from the model's own generations and uses them to focus hosted-adapter truncation on the channels with the strongest activations.
    Statistics accumulate in the background on models quantized below 8 bits, persist per checkpoint, and raise delivered adapter fidelity at the same LoRA quantized host rank, most at low ranks.

    Capture is skipped while the model is compiled; previously cached statistics still apply.

    Enabled by default.","ui":"settings_lora"}, + {"id":"","label":"LoRA quantized host cache","localized":"","hint":"Disk space in GB for caching computed hosting factors.
    A cached set skips the truncation math on the next load; least recently used entries are evicted once the budget is exceeded.

    0 disables the cache.

    Default is 10.","ui":"settings_lora"}, + {"id":"","label":"LoRA stack mode","localized":"","hint":"How multiple networks targeting the same layer are combined:
    - sum: adds all contributions
    - ties: keeps each network's strongest elements and merges only where signs agree
    - dare_ties: randomly drops elements, rescales the survivors, then merges where signs agree
    - dare_linear: randomly drops elements, rescales the survivors and sums
    - magnitude_prune: keeps each network's strongest elements and sums
    - klora / estlora: assign each layer to one of exactly two networks, the first in the prompt as subject and the second as style; LoRA stack ramp optionally shifts layers toward style over the sampling steps

    Each layer is given to a single network at a time, so a subject and a style that both need sustained strength can end up under-applied. For reliable blending of two strong networks, sum, ties and dare_ties apply every network throughout and combine more fully.

    Kept fractions are set by LoRA stack density; the subject-to-style shift by LoRA stack ramp and LoRA stack discrepancy.

    Applies to the native load path; other load methods and text encoder networks always combine as sum. Selection modes fall back to sum unless exactly two networks are loaded, or when model compile is active.

    Default is sum.","ui":"settings_lora"}, + {"id":"","label":"LoRA stack density","localized":"","hint":"Fraction of elements each network keeps under the ties, dare_ties, dare_linear and magnitude_prune stack modes.
    Lower values keep only the strongest contributions and reduce interference between networks at the cost of per-network detail. The dare variants drop at random and rescale the survivors to preserve expected strength.

    Default is 0.5.","ui":"settings_lora"}, + {"id":"","label":"LoRA stack ramp","localized":"","hint":"Slope of the subject-to-style shift across the sampling steps in the klora and estlora stack modes.

    0 keeps the layer assignment fixed for the whole generation: each layer stays with the network that is more salient there, which preserves the subject while the style keeps its own layers. Higher values hand layers to the style network progressively, ending in a style takeover; on few-step models the handover happens early enough to override the subject.

    Default is 0.","ui":"settings_lora"}, + {"id":"","label":"LoRA stack discrepancy","localized":"","hint":"Stand-in for the measured style separation the estlora stack mode would otherwise derive from data.
    Higher values keep layers with the subject network longer; lower values let the style network take layers earlier.

    Layer scores are balanced by each network's overall strength, so a louder network does not take layers on magnitude alone.

    Applies only when LoRA stack mode is estlora.

    Default is 0.5.","ui":"settings_lora"}, + {"id":"","label":"LoRA auto-apply tags","localized":"","hint":"Automatically add trigger words/tags from LoRA metadata to your prompt.
    Set to the number of tags to auto-apply, e.g., 3 = add top 3 trigger tags.
    Set to 0 to disable, -1 to add all available tags.","ui":"settings_lora"}, + {"id":"","label":"LoRA memory cache","localized":"","hint":"How many LoRAs to keep in network for future use before requiring reloading from storage","ui":"settings_lora"}, + {"id":"","label":"LoRA add hash info to metadata","localized":"","hint":"Include LoRA file hashes in generated image metadata.
    Useful for reproducibility and tracking which exact LoRA versions were used.","ui":"settings_lora"}, {"id":"","label":"LDSR Path","localized":"","hint":"","ui":"settings_legacy_options"}, {"id":"","label":"LoRA load using legacy method","localized":"","hint":"","ui":"settings_legacy_options"}, {"id":"","label":"Loaded LoRA","localized":"","hint":"","ui":"component-5851"}, @@ -937,9 +947,10 @@ {"id":"","label":"Max tags","localized":"","hint":"Maximum number of tags to include in the output.
    Limits the result length when an image has many detected features.
    Tags are sorted by confidence, so the most relevant ones are kept.","ui":"caption"}, {"id":"","label":"Memory","localized":"","hint":"","ui":"component-8779"}, {"id":"","label":"Memory optimization","localized":"","hint":"","ui":"component-8779"}, - {"id":"","label":"MiniMax Video Shift","localized":"","hint":"Controls how inference steps are distributed along the flow-matching curve, where higher values prioritize large-scale motion dynamics, camera movement, and global scene composition, while lower values focus steps on refining fine spatial textures and sharp visual details.","ui":"video"}, - {"id":"","label":"MiniMax Audio Shift","localized":"","hint":"Governs the step distribution for latent sound generation, where higher values enforce strong temporal alignment with visual action and macro rhythm, while lower values allocate sampling depth toward high-frequency acoustic fidelity, speech clarity, and crisp sound effects.","ui":"video"}, + {"id":"minimax_video_shift","label":"MiniMax video shift","localized":"","hint":"Exponential shift of the video sigma schedule, sigma' = s*sigma / (1 + (s-1)*sigma). Values above 1 move the step grid toward full noise, values below 1 toward the clean end. The value is absolute and does not scale with the step count.

    Default is 12, the value the model ships with. Distilled LoRAs run at the shift they were trained with: 12 for the 544p lightx2v files, 6 for their 768p files. Parallel decoding (PDD) LoRAs pin the shipped value.

    Recorded in the output metadata as Video shift.","ui":"video"}, + {"id":"minimax_audio_shift","label":"MiniMax audio shift","localized":"","hint":"Exponential shift of the audio sigma schedule. The audio rows are denoised on this schedule inside the joint pass, so the value applies with audio output disabled too.

    Default is 3, the value the model ships with; the published turbo LoRAs keep it. Parallel decoding (PDD) LoRAs pin the shipped value.

    Recorded in the output metadata as Audio shift.","ui":"video"}, {"id":"","label":"MiniMax Frames","localized":"","hint":"MiniMax is optimized to generate 5-15sec videos at 24 FPS","ui":"video"}, + {"id":"minimax_steps","label":"MiniMax steps","localized":"","hint":"Number of transformer evaluations, counted the same way as on every other model. Distilled LoRAs run at the count in their name: a 4-step file at 4, an 8-step file at 8. Parallel decoding (PDD) LoRAs pin their own count.

    Default is 30.","ui":"video"}, {"id":"","label":"Model Info","localized":"","hint":"","ui":"component-8779"}, {"id":"","label":"Model pipeline","localized":"","hint":"If autodetect does not detect model automatically, select model type before loading a model","ui":"settings_sd"}, {"id":"","label":"Model auto-load on start","localized":"","hint":"","ui":"settings_sd"}, @@ -1266,6 +1277,8 @@ ], "s": [ {"id":"txt2img_sampler","label":"Sampler","localized":"","hint":"Settings related to sampler and seed selection and configuration. Samplers guide the process of turning noise into an image over multiple steps.","ui":"txt2img"}, + {"id":"","label":"Sampler list filtered","localized":"","hint":"This list only shows samplers selected in Sampler Settings. Select to open settings.","ui":"txt2img"}, + {"id":"","label":"Sampler Settings","localized":"","hint":"Preferences for sampler and upscaler lists.","ui":"settings_sampler"}, {"id":"","label":"Scripts","localized":"","hint":"Enable additional features by using selected scripts during generate process","ui":"txt2img"}, {"id":"","label":"Scale","localized":"","hint":"Resize image to target scale. If resize fixed width/height are set this option is ignored","ui":"txt2img"}, {"id":"xy_grid_swap_axes_button","label":"Swap X/Y","localized":"","hint":"","ui":"script_xyz_grid_script"}, @@ -1316,6 +1329,8 @@ {"id":"","label":"Server log","localized":"","hint":""}, {"id":"","label":"Steps","localized":"","hint":"How many times to improve the generated image iteratively; higher values take longer; very low values can produce bad results","ui":"txt2img"}, {"id":"","label":"Sampling method","localized":"","hint":"Which algorithm to use to produce the image","ui":"txt2img"}, + {"id":"","label":"Show samplers in user interface","localized":"","hint":"Select favorite samplers to show in generated dropdowns. Leave empty to show all samplers. Restart the UI after changing this setting.","ui":"settings_sampler"}, + {"id":"","label":"Show upscalers in user interface","localized":"","hint":"Select favorite upscalers to show in generated dropdowns. Leave empty to show all upscalers. Restart the UI after changing this setting.","ui":"settings_sampler"}, {"id":"","label":"Sigma method","localized":"","hint":"Controls how noise levels (sigmas) are distributed across diffusion steps.
    Default: use the scheduler's built-in sigma method.
    Karras: smoother schedule that emphasizes later steps where fine details emerge; generally higher quality with fewer steps.
    Betas: derive sigmas directly from the model's beta schedule (classic DDPM behavior).
    Exponential: exponential decay of noise across steps; aggressive denoising early, slower refinement later.
    Lambdas: Lu's lambdas method from the DPM-Solver paper, specific to the DPM++ family.
    Flowmatch: sigma schedule tuned for flow-matching models (Flux, SD3, video models).","ui":"txt2img"}, {"id":"","label":"Sigma adjust","localized":"","hint":"Multiplier applied to the sampler's step size during the active timestep window. (Sigma is the amount of noise the sampler removes at each step.)
    Values below 1.0 shrink the step for smoother, more conservative denoising. Values above 1.0 enlarge it for sharper, more aggressive sampling.

    Default 1.0 disables the adjustment entirely. Use Adjust start and Adjust end to define the timestep range where the multiplier takes effect.","ui":"txt2img"}, {"id":"","label":"Sampler order","localized":"","hint":"Overrides the solver order of the active sampler when set above 0.
    Higher orders use more historical steps per update for greater stability and accuracy at the cost of extra compute. Lower orders are faster but noisier.

    Default 0 leaves each sampler at its built-in order. Many samplers in the dropdown already encode their order in the name (e.g. DPM++ 2M is order 2, DPM++ 3M is order 3, DPM++ 2M SDE is order 2).

    Within a sampler family, the named variants differ ONLY by this value, so picking DPM++ 2M with the slider at 3 produces a scheduler that is functionally identical to picking DPM++ 3M with the slider at 0. The same equivalence holds across the rest of the DPM++ multistep family (including the SDE and Inverse variants) and across the ER-SDE family.

    Samplers without a configurable solver order (DDIM, plain Euler, ancestrals, etc.) ignore this slider entirely.","ui":"txt2img"}, @@ -1454,7 +1469,24 @@ {"id":"","label":"Specify model revision","localized":"","hint":"","ui":"models_huggingface_tab"}, {"id":"","label":"SegmentAnything","localized":"","hint":"","ui":"control"}, {"id":"","label":"Sections","localized":"","hint":"","ui":"video"}, - {"id":"","label":"Samplers","localized":"","hint":"Samplers/schedulers advanced settings","ui":"tab_txt2img"} + {"id":"","label":"Samplers","localized":"","hint":"Samplers/schedulers advanced settings","ui":"tab_txt2img"}, + {"id":"","label":"SDP kernels","localized":"","hint":"Which of torch's built-in attention kernels torch is allowed to choose from. These are permissions rather than a selection: torch picks one per call from whatever is left enabled, preferring Flash, dropping to Memory for calls flash cannot serve such as those carrying an arbitrary attention mask, and to Math when neither fits. Clearing a box removes a candidate; it never pins the remaining one to every call.

    Flash is torch's own build of the FlashAttention kernel. It is not the same thing as the Flash attention entry in SDP overrides, which calls the separately installed flash-attn package and bypasses torch entirely.
    Memory is the memory-efficient kernel, which accepts arbitrary masks that flash does not.
    Math is the unfused reference path, the widest in what it accepts and the least optimized. Leaving it enabled keeps a fallback for calls the other two decline.

    Applies while Attention method is Scaled-Dot-Product, and continues to govern the calls that an enabled override declines.

    All three by default. ZLUDA starts with Math alone.","ui":"settings_cuda"}, + {"id":"","label":"SDP overrides","localized":"","hint":"Replaces torch attention with another implementation. Each entry declares the shapes, dtypes and mask conditions it can serve; a call that fails them moves to the next entry and finally back to torch, so several can be enabled together and the chain resolves per call.

    Flash attention installs and calls the flash-attn package directly, for calls with no attention mask, half precision inputs and a head dimension of 128 or less.
    Sage attention computes attention with quantized matmuls, for head dimensions of 64, 96 or 128 and no attention mask.
    SDNQ attention is SD.Next's own quantized Triton kernel, configured in the section below. It takes attention masks, which the other quantized backends do not, and it is one of the two backends Sparse Attention can drive.
    Flex attention uses torch's compiled flex_attention, the other backend Sparse Attention can drive.
    Dynamic attention slices attention to fit available memory and serves every call the others decline, standing in for the torch fallback.
    Triton AMD Flash attention is a Triton implementation for ROCm and ZLUDA, listed only on those backends.

    The quantized and compiled backends trade some numerical accuracy for throughput. How much of each arrives depends on the model, the sequence length and the GPU, so comparing them on the actual workload settles it faster than picking by reputation.

    None by default on CUDA. ZLUDA, CPU and MPS start with Dynamic attention, as do ROCm GPUs older than RDNA3.","ui":"settings_cuda"}, + {"id":"","label":"SDNQ Attention","localized":"","hint":"Settings for the SDNQ attention entry in SDP overrides. They do nothing until that override is enabled.

    The kernel quantizes the two matmuls inside attention, computing them on lower precision operands and rescaling the result. It is written in Triton, so it needs a working Triton for the active device.
    It takes an attention mask and a block mask together, which is what lets Sparse Attention use it.
    Short sequences and single-head calls are left to the rest of the chain, so text encoders and the VAE keep ordinary attention.","ui":"settings_cuda"}, + {"id":"","label":"SDNQ Attention use Smooth K","localized":"","hint":"Subtracts the mean of the keys before quantizing them. Keys carry a large offset that is shared across the sequence, which spends most of the quantized range representing a value identical for every key and leaves little of it for the differences that decide the attention.
    Softmax ignores a constant shift applied to every score in a row, so removing that offset changes the quantization error and not the attention.

    Costs one mean and one subtraction per call.
    Enabled by default.","ui":"settings_cuda"}, + {"id":"","label":"SDNQ Attention use Hadamard","localized":"","hint":"Rotates queries and keys by a Hadamard transform before quantizing them. The rotation spreads a few oversized channels across all of them, which is the error shape quantization handles worst. The transform is orthogonal, so the scores it produces are the ones the unrotated tensors would produce, minus the quantization error it removes.
    With SDNQ Attention PV MatMul type also set, the values are rotated as well and the output is rotated back.

    Costs a rotation pass on every attention call, so it is worth enabling where a model shows quantization artifacts without it.
    Idle while SDNQ Attention MatMul type is disabled, since nothing is quantized then.

    Disabled by default.","ui":"settings_cuda"}, + {"id":"","label":"SDNQ Attention use FP16 Accumulation","localized":"","hint":"Accumulates the floating point matmuls in fp16 rather than fp32. Some tensor cores run fp16 accumulation at a higher rate than fp32, and on those the kernel is cheaper for it.
    Operands are pre-scaled to keep products inside the fp16 range, which covers ordinary activations with less headroom than fp32 leaves.

    Reaches the parts of the kernel that run in floating point. An int8 matmul accumulates in int32 and is unaffected, so at the default SDNQ Attention MatMul type this applies to the probability-value matmul alone.

    Disabled by default.","ui":"settings_cuda"}, + {"id":"","label":"SDNQ Attention MatMul type","localized":"","hint":"Precision the query-key matmul is computed in, the first of the two matmuls in attention.

    enabled selects int8, and int8 and uint8 reach the same kernel.
    float16 and float8_e4m3fn take the floating point path. fp8 needs a GPU with fp8 tensor cores and fails on hardware without them rather than falling back.
    disabled leaves queries and keys in the model's own precision, which also idles SDNQ Attention use Smooth K and SDNQ Attention use Hadamard.

    Default enabled.","ui":"settings_cuda"}, + {"id":"","label":"SDNQ Attention PV MatMul type","localized":"","hint":"Precision the probability-value matmul is computed in, the second of the two matmuls in attention. Choices match SDNQ Attention MatMul type.

    Quantizing this one as well takes out the floating point work the first setting leaves behind, and it is the more delicate of the two: its inputs are already normalized probabilities, and the small ones among them carry the fine detail.
    disabled keeps this matmul in the model's own precision.

    Default disabled.","ui":"settings_cuda"}, + {"id":"","label":"SDNQ Attention Hadamard Group Size","localized":"","hint":"Width of the Hadamard rotation in channels. Wider groups mix more channels together and spread outliers further.

    Clamped to the head dimension of the running model, rounded down to a power of two that divides it. On a model with 64 or 128 channels per head the upper part of this range resolves to that head dimension rather than to the number shown. Rotation is skipped below 4.
    Applies while SDNQ Attention use Hadamard is enabled.

    Default 256.","ui":"settings_cuda"}, + {"id":"","label":"SDNQ Attention Quantize FP32","localized":"","hint":"Upcasts queries, keys and values to fp32 for the quantization step, meaning the mean subtraction, scale and rounding that produce the low precision operands. The matmuls themselves are unaffected, and the kernel applies the scales in fp32 either way.
    Turned off, that arithmetic runs in the model's own precision. bf16 carries eight mantissa bits, so a scale derived in it is coarser than one derived in fp32, and SDNQ Attention use Smooth K loses the most from it, since a mean across the whole sequence is exactly the kind of sum that wants the extra bits.

    Whether the upcast costs anything depends on how the GPU runs fp32 vector work against fp16 and bf16. NVIDIA and AMD run them at the same rate here, so there is nothing to save; Intel runs fp32 slower and takes a noticeable hit.

    Enabled by default.","ui":"settings_cuda"}, + {"id":"","label":"Sparse Attention","localized":"","hint":"Computes attention over a subset of the key tiles instead of all of them. Attention cost grows with the square of the sequence length, so on long sequences it dominates generation time, and skipping the tiles that contribute least buys much of it back.
    The saving grows with sequence length: negligible on a short sequence, useful at high resolution, largest on video.

    Requires an attention backend that accepts a block mask, SDNQ attention or Flex attention in SDP overrides; with neither enabled a warning is logged and attention stays dense. It also stays dense below Sparse Attention minimum sequence.
    Not every architecture tolerates a reduced key set. The ones known to break are listed in Sparse Attention excluded models and stay dense; a model that breaks up rather than merely softening belongs on that list.

    Disabled by default.","ui":"settings_cuda"}, + {"id":"","label":"Sparse Attention KV budget","localized":"","hint":"Percentage of the eligible key tiles each query tile keeps. Lower budgets are faster and coarser, and the cost shows first in fine detail and in consistency across the image.
    Text, conditioning and audio tokens are always kept, as are the tiles on the diagonal, so the budget applies only to the bulk image or video tokens.

    100 keeps every tile, which is ordinary dense attention and a convenient comparison run.
    Default 30.","ui":"settings_cuda"}, + {"id":"","label":"Sparse Attention minimum sequence","localized":"","hint":"Shortest sequence that is sparsified. Below it attention stays dense, because choosing the tiles costs more than skipping them saves.
    Sequence length is not resolution: a diffusion transformer sees roughly (width/16) x (height/16) tokens for an image, so 1024x1024 is about 4k tokens and 2048x2048 about 16k, and video multiplies that by the frame count.

    0 sparsifies every sequence that reaches the stage.
    Default 8192, around 1450x1450 for an image.","ui":"settings_cuda"}, + {"id":"","label":"Sparse Attention dense steps","localized":"","hint":"Number of steps at the start and end of sampling that receive a larger budget, where composition and fine detail are set. Counted at each end, and capped at half the run.

    Only takes effect when Sparse Attention dense step bonus is above 0.
    0 applies one budget to every step.
    Default 0.","ui":"settings_cuda"}, + {"id":"","label":"Sparse Attention dense step bonus","localized":"","hint":"Percentage points added to the budget on the dense steps, capped at 100.

    Only takes effect when Sparse Attention dense steps is above 0.
    Default 30, so a budget of 30 rises to 60 on those steps.","ui":"settings_cuda"}, + {"id":"","label":"Sparse Attention share selection across heads","localized":"","hint":"Computes one selection for all attention heads rather than one per head, by averaging the heads before scoring. Cheaper to select and coarser in what it keeps, since heads that attend to different regions are served by a single compromise.
    Worth trying when selection is itself a visible share of the cost, which happens on models with many heads.
    Also the first thing to try when a model breaks up into bands under sparse attention: some architectures need every head to see one consistent context, and per-head selection is what breaks them.

    Disabled by default.","ui":"settings_cuda"}, + {"id":"","label":"Sparse Attention excluded models","localized":"","hint":"Models that stay dense no matter how the rest of this section is set. Comma separated, matched case insensitively against the architecture, the pipeline class and the denoiser class, so whichever of those names is to hand works as an entry.
    The class names appear in the model load log; the architecture is the short name used elsewhere in the settings, such as f1 or anima.

    Listed by default is CosmosTransformer3DModel, the transformer Anima runs, which collapses into banded noise when each head selects its own tiles and stays degraded even with Sparse Attention share selection across heads enabled. The class is listed rather than the architecture because the other models built on it have not been checked.
    A model whose output breaks up rather than merely softening belongs here.

    Default CosmosTransformer3DModel.","ui":"settings_cuda"} ], "t": [ {"id":"txt2img_nav","label":"T2I","localized":"","hint":"Create image from text
    Legacy interface that mimics original text-to-image interface and behavior"}, @@ -1551,6 +1583,7 @@ {"id":"component-5611","label":"Update all","localized":"","hint":"","ui":"models_metadata_tab"}, {"id":"","label":"UNet/DiT","localized":"","hint":""}, {"id":"","label":"Upscale","localized":"","hint":"Upscale image","ui":"extras"}, + {"id":"","label":"Upscaler list filtered","localized":"","hint":"This list only shows upscalers selected in Sampler Settings. Select to open settings.","ui":"txt2img"}, {"id":"","label":"UI Tabs","localized":"","hint":"","ui":"settings_ui"}, {"id":"","label":"Upscaling","localized":"","hint":"","ui":"settings_postprocessing"}, {"id":"","label":"Use segmentation","localized":"","hint":"Use the model's pixel-precise segmentation mask as the inpaint mask instead of the rectangular bounding box.
    Tighter mask means less unintended change around the detection (e.g., the inpaint stays on the face, not on the hair or background behind it). Better blending and smaller seams.

    Requires a segmentation-capable model (filename usually contains -seg). Bounding-box-only models silently fall back to the rectangle.
    Default off.","ui":"txt2img"}, diff --git a/ui/monitor.ts b/ui/monitor.ts index b289aadb0..06ca70fd4 100644 --- a/ui/monitor.ts +++ b/ui/monitor.ts @@ -65,7 +65,7 @@ export class ConnectionMonitorState { else return; } this.element.dataset.hint = this.toHTML(); - this.element.style.backgroundColor = this.online ? 'var(--sd-main-accent-color)' : 'var(--color-error)'; + this.element.style.background = this.online ? 'var(--sd-main-accent-color)' : 'var(--color-error)'; } } diff --git a/ui/progressBar.ts b/ui/progressBar.ts index b87a706b6..e08922239 100644 --- a/ui/progressBar.ts +++ b/ui/progressBar.ts @@ -4,7 +4,7 @@ import { sendNotification } from './notification'; let lastState: any = {}; let refreshInterval = 10000; -const progressTimeout = 180; +const progressTimeout = 600; const startTimeout = 5; export function setRefreshInterval() { @@ -126,6 +126,7 @@ export function requestProgress(id_task = 'undefined', progressEl = null, galler const initLivePreview = () => { if (!parentGallery) return; + debug('initLivePreview', { el: galleryEl, parent: parentGallery }); const footers = Array.from(gradioApp().querySelectorAll('.gallery_footer')); for (const footer of footers) { if (footer.id !== 'gallery_footer') footer.style.display = 'none'; // remove all footers @@ -182,7 +183,7 @@ export function requestProgress(id_task = 'undefined', progressEl = null, galler const previewVisible = () => { try { - return !galleryEl?.closest('.section')?.classList.contains('minimize'); + return galleryEl ? !galleryEl.closest('.section')?.classList.contains('minimize') : true; } catch { return true; } diff --git a/ui/script.ts b/ui/script.ts index c262c0857..1df7e355f 100644 --- a/ui/script.ts +++ b/ui/script.ts @@ -139,6 +139,7 @@ const ignoreElementsSet = new Set(ignoreElements); const ignoreClasses = ['wrap']; let mutationTimer: ReturnType | undefined; +let mutationTS: number | undefined; let validMutations = []; async function mutationCallback(mutations) { @@ -152,9 +153,12 @@ async function mutationCallback(mutations) { } if (validMutations.length < 1) return; - if (mutationTimer) clearTimeout(mutationTimer); + if (mutationTimer) clearTimeout(mutationTimer); // bounce mutationTimer = setTimeout(async () => { + const ts = Date.now() - mutationTS; + if (!executedOnLoaded && (ts > 1000)) log('onUiLoaded delayed', { ts, prompts: anyPromptExists() }); if (!executedOnLoaded && anyPromptExists()) { // execute once + log('onUiLoaded', ts); executedOnLoaded = true; executeCallbacks(uiLoadedCallbacks); } @@ -174,6 +178,7 @@ async function mutationCallback(mutations) { document.addEventListener('DOMContentLoaded', () => { log('DOMContentLoaded'); + mutationTS = Date.now(); gradioObserver = new MutationObserver(mutationCallback); gradioObserver.observe(gradioApp(), { childList: true, subtree: true, attributes: false }); }); diff --git a/ui/settings.ts b/ui/settings.ts index 0ab055c75..7ef5b5a3a 100644 --- a/ui/settings.ts +++ b/ui/settings.ts @@ -78,6 +78,17 @@ function showAllSettings() { }); } +function openSettingsSection(sectionId: string) { + const settingsTab = gradioApp().getElementById('tab_settings'); + const settingsButton = settingsTab ? gradioApp().querySelector(`button[aria-controls="${settingsTab.id}"]`) : null; + settingsButton?.click(); + const section = gradioApp().getElementById(`settings_section_tab_${sectionId}`); + const sectionButton = section ? gradioApp().querySelector(`button[aria-controls="${section.id}"]`) : null; + sectionButton?.click(); + section?.scrollIntoView({ behavior: 'smooth', block: 'start' }); +} +window.openSettingsSection = openSettingsSection; + function markIfModified(setting_name, value) { if (!opts_metadata[setting_name]) return; const elem = gradioApp().getElementById(`modification_indicator_${setting_name}`); @@ -201,7 +212,7 @@ export async function initModels() { const en = gradioApp().getElementById('txt2img_extra_networks'); if (!el || !en) return; const req = await authFetch(`${window.api}/sd-models`); - const res = req.ok ? await req.json() : []; + const res = (req && req.ok) ? await req.json() : []; log('initModels', res.length); const ready = () => `

    Ready

    diff --git a/ui/startup.ts b/ui/startup.ts index 2e79a64a8..c4af4f0bc 100644 --- a/ui/startup.ts +++ b/ui/startup.ts @@ -27,25 +27,29 @@ window.api = '/sdapi/v1'; window.subpath = ''; const startupPromises: Promise[] = []; -let ok = false; +let optsReady = false; +let initialized = false; 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) { - if (t1 - t0 > 120000) { + if (t1 - t0 > 60000) { log('waitForOpts timeout'); break; } if (window.opts && Object.keys(window.opts).length > 0) { - ok = window.opts.theme_type === 'Modern' ? 'uiux_separator_appearance' in window.opts : true; - if (ok) { + optsReady = (window.opts.theme_type === 'Modern') ? 'uiux_separator_appearance' in window.opts : true; + if (optsReady) { log('waitForOpts', Math.round(t1 - t0)); timer('waitForOpts', t1 - t0); break; } } + if (t1 - t0 > 15000) { + log('waitForOpts delayed', Math.round(t1 - t0)); + } await sleep(100); t1 = performance.now(); } @@ -66,7 +70,9 @@ async function updateSubpath() { log('API', { url: window.api }); } -async function initStartup() { +export async function initStartup() { + if (initialized) return; + initialized = true; const t0 = performance.now(); log('initGradio', Math.round(t0 - appStartTime)); timer('initGradio', t0 - appStartTime); @@ -96,7 +102,7 @@ async function initStartup() { executeCallbacks(uiReadyCallbacks); // optionally wait for modern ui - if (window.waitForUiReady) await window.waitForUiReady(); + if (window.opts.theme_type.toLowerCase().startsWith('modern') && window.waitForUiReady) await window.waitForUiReady(); // post startup tasks that may take longer but are not critical startupPromises.push(Promise.resolve(initLogMonitor())); @@ -126,6 +132,10 @@ async function initStartup() { onUiLoaded(initStartup); onUiReady(() => log('uiReady')); +window.initStartup = initStartup; +window.addEventListener('pageshow', (evt) => log('pageShow', evt)); +window.addEventListener('pagehide', (evt) => log('pageHide', evt)); + // onAfterUiUpdate(() => log('evt onAfterUiUpdate')); // onUiLoaded(() => log('evt onUiLoaded')); // onOptionsChanged(() => log('evt onOptionsChanged')); diff --git a/ui/ui.ts b/ui/ui.ts index da4177712..01a7689dc 100644 --- a/ui/ui.ts +++ b/ui/ui.ts @@ -130,7 +130,7 @@ export async function setTheme(val, old) { for (const link of links) { const href = link.href.replace(old, val); const res = await authFetch(href); - if (res.ok) { + if (res?.ok) { log('setTheme', old, val); link.href = link.href.replace(old, val); } else { @@ -341,7 +341,7 @@ function submit_framepack(...args) { function submit_ltx(...args) { const id = randomId(); log('submitFramepack', id); - requestProgress(id, null, null); + requestProgress(id, null, gradioApp().getElementById('ltx_output_video')); window.submit_state = ''; args[0] = id; return args; @@ -350,7 +350,7 @@ function submit_ltx(...args) { function submit_minimax(...args) { const id = randomId(); log('submitMiniMax', id); - requestProgress(id, null, null); + requestProgress(id, null, gradioApp().getElementById('minimax_output_video')); window.submit_state = ''; args[0] = id; return args; diff --git a/webui.py b/webui.py index 911d35ccf..58521c71b 100644 --- a/webui.py +++ b/webui.py @@ -17,6 +17,7 @@ import modules.loader import modules.hashes import modules.paths import modules.devices +import modules.attention import modules.migrate from modules import shared from modules import call_queue @@ -76,10 +77,6 @@ fastapi_args = { def initialize(): log.debug('Initializing: modules') from concurrent.futures import ThreadPoolExecutor, as_completed - - from installer import register_sdnq - register_sdnq(skip=True, devices=modules.devices, shared=shared) # monkey-patch sdnq to use sdnext devices and shared modules - from modules.models_hf import hf_init hf_init() @@ -205,6 +202,8 @@ def load_model(): shared.opts.onchange("temp_dir", modules.gr_tempdir.on_tmpdir_changed) for opt in modules.sd_offload_state.offload_reapply_options: shared.opts.onchange(opt, call_queue.wrap_queued_call(modules.sd_models.reapply_offload), call=False) + for opt in modules.attention.reapply_options(): + shared.opts.onchange(opt, call_queue.wrap_queued_call(modules.attention.reapply), call=False) timer.startup.record("onchange") @@ -250,7 +249,7 @@ def async_policy(): if shared.cmd_opts.profile: loop.slow_callback_duration = 0.001 loop.set_debug(shared.cmd_opts.profile) - log.debug(f'AsyncIO: loop={loop}') + log.debug(f'AsyncIO: loop={loop.__class__.__name__}') loop.set_task_factory(verbose_task_factory) loop.set_exception_handler(self.handle_exception) return loop @@ -430,7 +429,8 @@ def start_ui(): uc = shared.demo.server.config get_name = lambda c: getattr(c, '__name__', c) # pylint: disable=unnecessary-lambda-assignment - log.debug(f'Server config: loop={shared.demo.server.loop} http={get_name(uc.http_protocol_class)} ws={get_name(uc.ws_protocol_class)} interface={uc.interface} workers={uc.workers} backlog={uc.backlog} timeout_keep_alive={uc.timeout_keep_alive} timeout_notify={uc.timeout_notify} ws_max_size={uc.ws_max_size} ws_max_queue={uc.ws_max_queue} ws_ping_interval={uc.ws_ping_interval} ws_ping_timeout={uc.ws_ping_timeout}') + log.debug(f'Server config: loop={shared.demo.server.loop} http={get_name(uc.http_protocol_class)} ws={get_name(uc.ws_protocol_class)} interface={uc.interface} workers={uc.workers} backlog={uc.backlog} timeout_keep_alive={uc.timeout_keep_alive}') + # log.debug(f'Server config: loop={shared.demo.server.loop} http={get_name(uc.http_protocol_class)} ws={get_name(uc.ws_protocol_class)} interface={uc.interface} workers={uc.workers} backlog={uc.backlog} timeout_keep_alive={uc.timeout_keep_alive} timeout_notify={uc.timeout_notify} ws_max_size={uc.ws_max_size} ws_max_queue={uc.ws_max_queue} ws_ping_interval={uc.ws_ping_interval} ws_ping_timeout={uc.ws_ping_timeout}') if shared.cmd_opts.data_dir is not None: modules.gr_tempdir.register_tmp_file(shared.demo, os.path.join(shared.cmd_opts.data_dir, 'x')) @@ -449,7 +449,7 @@ def start_ui(): log.info(f'Public URL: {proto}://{public_ip}:{shared.cmd_opts.port}') if shared.cmd_opts.docs: log.info(f'API docs: {local_url[:-1]}/docs') # pylint: disable=unsubscriptable-object - log.info(f'API redocs: {local_url[:-1]}/redocs') # pylint: disable=unsubscriptable-object + # log.info(f'API redocs: {local_url[:-1]}/redocs') # pylint: disable=unsubscriptable-object if share_url is not None: log.info(f'Share URL: {share_url}') if getattr(shared.cmd_opts, 'enso', False): diff --git a/wiki b/wiki index 47f645c59..0a592b3cf 160000 --- a/wiki +++ b/wiki @@ -1 +1 @@ -Subproject commit 47f645c59c21c5042f88bbe4c9ca550fe2b9300b +Subproject commit 0a592b3cff44bdf3b440b0791f68f71cd7ecc3ea