mirror of
https://github.com/vladmandic/automatic
synced 2026-09-06 13:00:44 +02:00
video loader use generic methods and auth
Signed-off-by: Vladimir Mandic <mandic00@live.com>
This commit is contained in:
+3
-1
@@ -1,6 +1,6 @@
|
||||
# Change Log for SD.Next
|
||||
|
||||
## Update for 2026-08-14
|
||||
## Update for 2026-08-16
|
||||
|
||||
- **Models**
|
||||
- [MiniMax H3](https://huggingface.co/MiniMaxAI/MiniMax-H3) available in *base* and *ref* variants
|
||||
@@ -60,8 +60,10 @@
|
||||
- ltx: reload the latent upsampler when the model or its repo changes
|
||||
- video: take the audio sample rate from the loaded vocoder
|
||||
- video: keep the shared text encoder out of the registry rows
|
||||
- video: use generic loader methods
|
||||
- processing stats reporting
|
||||
- image metadata handle correct image index
|
||||
- gguf transformer loader
|
||||
|
||||
## Update for 2026-08-07
|
||||
|
||||
|
||||
@@ -214,6 +214,7 @@ from tqdm.rich import tqdm # pylint: disable=W0611,C0411
|
||||
try:
|
||||
logging.getLogger("diffusers.guiders").setLevel(logging.ERROR)
|
||||
logging.getLogger("diffusers.loaders.single_file").setLevel(logging.ERROR)
|
||||
logging.getLogger("huggingface_hub._login").setLevel(logging.ERROR)
|
||||
import diffusers.utils.import_utils # pylint: disable=W0611,C0411
|
||||
diffusers.utils.import_utils._k_diffusion_available = True # pylint: disable=protected-access # monkey-patch since we use k-diffusion from git
|
||||
diffusers.utils.import_utils._k_diffusion_version = '0.0.12' # pylint: disable=protected-access
|
||||
|
||||
@@ -48,7 +48,6 @@ def hf_login(token=None):
|
||||
except Exception:
|
||||
pass
|
||||
try:
|
||||
# with contextlib.nullcontext():
|
||||
with contextlib.redirect_stdout(stdout), contextlib.redirect_stderr(stderr):
|
||||
hf.login(token=token, add_to_git_credential=False)
|
||||
except Exception as e:
|
||||
@@ -56,6 +55,7 @@ def hf_login(token=None):
|
||||
text = (stdout.getvalue() or '') + (stderr.getvalue() or '')
|
||||
try:
|
||||
new_token = hf.get_token()
|
||||
os.environ['HF_TOKEN'] = new_token
|
||||
except Exception:
|
||||
pass
|
||||
obfuscated_token = 'hf_...' + new_token[-4:]
|
||||
|
||||
@@ -1605,27 +1605,29 @@ def unload_model_weights(op='model'):
|
||||
log.debug(f'Unload {op}: {memory_stats()} fn={fn}')
|
||||
|
||||
|
||||
def hf_auth_check(checkpoint_info: CheckpointInfo, force:bool=False):
|
||||
def hf_auth_check(checkpoint_info: CheckpointInfo | str, force:bool=False):
|
||||
if shared.opts.offline_mode:
|
||||
log.info('Offline mode: skipping auth check')
|
||||
return False
|
||||
login = None
|
||||
if not force:
|
||||
try:
|
||||
if (checkpoint_info.path.endswith('.safetensors') and os.path.isfile(checkpoint_info.path)): # skip check for single-file safetensors models
|
||||
fn = checkpoint_info.path if isinstance(checkpoint_info, CheckpointInfo) else checkpoint_info
|
||||
if (fn.endswith('.safetensors') and os.path.isfile(fn)): # skip check for single-file safetensors models
|
||||
return True
|
||||
if os.path.exists(checkpoint_info.path) and os.path.isdir(checkpoint_info.path) and any(os.path.isfile(os.path.join(checkpoint_info.path, f)) for f in ('model_index.json', 'modular_model_index.json')): # skip check for local diffusers folders
|
||||
if os.path.exists(fn) and os.path.isdir(fn) and any(os.path.isfile(os.path.join(fn, f)) for f in ('model_index.json', 'modular_model_index.json')): # skip check for local diffusers folders
|
||||
return True
|
||||
except Exception:
|
||||
pass
|
||||
repo_id = path_to_repo(checkpoint_info)
|
||||
repo_id = path_to_repo(checkpoint_info) # already handles str or CheckpointInfo
|
||||
if repo_id is None or '/' not in repo_id:
|
||||
# log.warning(f'Auth: repo="{repo_id}" invalid repo id')
|
||||
return False
|
||||
auth_ok = False
|
||||
try:
|
||||
login = modelloader.hf_login()
|
||||
hf.auth_check(repo_id, write=False)
|
||||
token = os.environ.get('HF_TOKEN', None)
|
||||
hf.auth_check(repo_id, write=False, token=token)
|
||||
auth_ok = True
|
||||
except Exception as e:
|
||||
log.error(f'Auth: repo="{repo_id}" login={login} auth={auth_ok} {e}')
|
||||
|
||||
@@ -8,6 +8,7 @@ import diffusers
|
||||
from modules import shared, errors, sd_models, sd_checkpoint, model_quant, devices, sd_hijack_te, sd_hijack_vae, modular_load
|
||||
from modules.logger import log
|
||||
from modules.video_models import models_def, video_utils, video_overrides, video_cache
|
||||
from pipelines import generic
|
||||
|
||||
|
||||
def _loader(component):
|
||||
@@ -92,77 +93,41 @@ def load_model(selected: models_def.Model):
|
||||
os.unsetenv('HF_HUB_OFFLINE')
|
||||
|
||||
kwargs = video_overrides.load_override(selected, **offline_args)
|
||||
sd_models.hf_auth_check(selected.repo)
|
||||
|
||||
# text encoder
|
||||
if selected.te_cls is not None:
|
||||
try:
|
||||
load_args, quant_args = model_quant.get_dit_args({}, module='TE', device_map=True)
|
||||
|
||||
# loader deduplication of text-encoder models: picked per load, not written back onto
|
||||
# the registry row where it would outlive the setting
|
||||
te_repo, te_folder, te_revision = selected.te, selected.te_folder, selected.te_revision
|
||||
if shared.opts.te_shared_te:
|
||||
te_cls_name = selected.te_cls.__name__
|
||||
if te_cls_name == 'T5EncoderModel':
|
||||
te_repo, te_folder, te_revision = 'Disty0/t5-xxl', '', None
|
||||
elif te_cls_name == 'UMT5EncoderModel':
|
||||
te_repo = 'Disty0/Wan2.2-T2V-A14B-SDNQ-uint4-svd-r32' if 'SDNQ' in selected.name else 'Wan-AI/Wan2.2-TI2V-5B-Diffusers'
|
||||
te_folder, te_revision = 'text_encoder', None
|
||||
elif te_cls_name == 'LlamaModel':
|
||||
te_repo, te_folder, te_revision = 'hunyuanvideo-community/HunyuanVideo', 'text_encoder', None
|
||||
elif te_cls_name == 'Qwen2_5_VLForConditionalGeneration':
|
||||
te_repo, te_folder, te_revision = 'ai-forever/Kandinsky-5.0-T2V-Lite-sft-5s-Diffusers', 'text_encoder', None
|
||||
elif te_cls_name == 'Gemma3ForConditionalGeneration':
|
||||
te_repo = 'OzzyGT/LTX-2.3-sdnq-dynamic-int4' if 'SDNQ' in selected.name else 'OzzyGT/LTX-2.3'
|
||||
te_folder, te_revision = 'text_encoder', None
|
||||
|
||||
log.debug(f'Load video: module=te repo="{te_repo or selected.repo}" folder="{te_folder}" cls={selected.te_cls.__name__} quant={model_quant.get_quant_type(quant_args)} loader={_loader("transformers")}')
|
||||
kwargs["text_encoder"] = selected.te_cls.from_pretrained(
|
||||
pretrained_model_name_or_path=te_repo or selected.repo,
|
||||
subfolder=te_folder,
|
||||
revision=te_revision or selected.repo_revision,
|
||||
cache_dir=shared.opts.hfcache_dir,
|
||||
**load_args,
|
||||
**quant_args,
|
||||
**offline_args,
|
||||
)
|
||||
except Exception as e:
|
||||
log.error(f'video load: module=te cls={selected.te_cls.__name__} {e}')
|
||||
errors.display(e, 'video')
|
||||
te_repo, te_folder, te_revision = selected.te, selected.te_folder, selected.te_revision
|
||||
kwargs["text_encoder"] = generic.load_text_encoder(
|
||||
te_repo or selected.repo,
|
||||
cls_name=selected.te_cls,
|
||||
subfolder=te_folder,
|
||||
revision=te_revision or selected.repo_revision,
|
||||
)
|
||||
|
||||
# transformer
|
||||
if selected.dit_cls is not None:
|
||||
try:
|
||||
def load_dit_folder(dit_folder, dit_kwarg=None):
|
||||
dit_kwarg = dit_kwarg or dit_folder # ltx-2.5 keeps its dev transformer in transformer_full
|
||||
if dit_folder is not None and dit_kwarg not in kwargs:
|
||||
# get a new quant arg on every loop to prevent the quant config classes getting entangled
|
||||
load_args, quant_args = model_quant.get_dit_args({}, module='Model', device_map=True)
|
||||
log.debug(f'Load video: module=transformer repo="{selected.dit or selected.repo}" module="{dit_kwarg}" folder="{dit_folder}" cls={selected.dit_cls.__name__} quant={model_quant.get_quant_type(quant_args)} loader={_loader("diffusers")}')
|
||||
kwargs[dit_kwarg] = selected.dit_cls.from_pretrained(
|
||||
pretrained_model_name_or_path=selected.dit or selected.repo,
|
||||
subfolder=dit_folder,
|
||||
revision=selected.dit_revision or selected.repo_revision,
|
||||
cache_dir=shared.opts.hfcache_dir,
|
||||
**load_args,
|
||||
**quant_args,
|
||||
**offline_args,
|
||||
)
|
||||
else:
|
||||
log.debug(f'Load video: module=transformer repo="{selected.dit or selected.repo}" module="{dit_kwarg}" folder="{dit_folder}" cls={selected.dit_cls.__name__} loader={_loader("diffusers")} skip')
|
||||
|
||||
if selected.dit_folder is None:
|
||||
selected.dit_folder = ['transformer']
|
||||
if isinstance(selected.dit_folder, list) or isinstance(selected.dit_folder, tuple):
|
||||
if selected.dit_kwarg is not None:
|
||||
log.warning(f'Load video: model="{selected.name}" dit_kwarg unsupported with multiple folders')
|
||||
for dit_folder in selected.dit_folder: # wan a14b has transformer and transformer_2
|
||||
load_dit_folder(dit_folder)
|
||||
def load_dit_folder(dit_folder, dit_kwarg=None):
|
||||
dit_kwarg = dit_kwarg or dit_folder # ltx-2.5 keeps its dev transformer in transformer_full
|
||||
if dit_folder is not None and dit_kwarg not in kwargs:
|
||||
kwargs[dit_kwarg] = generic.load_transformer(
|
||||
selected.dit or selected.repo,
|
||||
cls_name=selected.dit_cls,
|
||||
subfolder=dit_folder,
|
||||
revision=selected.dit_revision or selected.repo_revision,
|
||||
)
|
||||
else:
|
||||
load_dit_folder(selected.dit_folder, selected.dit_kwarg)
|
||||
except Exception as e:
|
||||
log.error(f'video load: module=transformer cls={selected.dit_cls.__name__} {e}')
|
||||
errors.display(e, 'video')
|
||||
log.debug(f'Load video: module=transformer repo="{selected.dit or selected.repo}" module="{dit_kwarg}" folder="{dit_folder}" cls={selected.dit_cls.__name__} loader={_loader("diffusers")} skip')
|
||||
|
||||
if selected.dit_folder is None:
|
||||
selected.dit_folder = ['transformer']
|
||||
if isinstance(selected.dit_folder, list) or isinstance(selected.dit_folder, tuple):
|
||||
if selected.dit_kwarg is not None:
|
||||
log.warning(f'Load video: model="{selected.name}" dit_kwarg unsupported with multiple folders')
|
||||
for dit_folder in selected.dit_folder: # wan a14b has transformer and transformer_2
|
||||
load_dit_folder(dit_folder)
|
||||
else:
|
||||
load_dit_folder(selected.dit_folder, selected.dit_kwarg)
|
||||
|
||||
# model
|
||||
try:
|
||||
|
||||
@@ -88,6 +88,7 @@ def load_text_encoder(
|
||||
allow_quant=True,
|
||||
allow_shared=True,
|
||||
variant=None,
|
||||
revision=None,
|
||||
dtype=None,
|
||||
modules_to_not_convert=None,
|
||||
modules_dtype_dict=None,
|
||||
@@ -167,6 +168,8 @@ def load_text_encoder(
|
||||
load_args['subfolder'] = subfolder
|
||||
if variant is not None:
|
||||
load_args['variant'] = variant
|
||||
if revision is not None:
|
||||
load_args['revision'] = revision
|
||||
text_encoder = cls_name.from_pretrained(
|
||||
repo_id,
|
||||
cache_dir=shared.opts.hfcache_dir,
|
||||
|
||||
@@ -111,7 +111,7 @@ def load_transformer(
|
||||
if local_file is not None and local_file.lower().endswith('.gguf'):
|
||||
log.debug(f'Load model: transformer="{local_file}" cls={cls_name.__name__} quant="{quant_type}" loader={get_loader("diffusers")} args={load_args}')
|
||||
from modules import ggml
|
||||
ggml.load_gguf_diffusers(local_file, cls=cls_name, compute_dtype=dtype, config=repo_id, subfolder=subfolder, variant=variant)
|
||||
transformer = ggml.load_gguf_diffusers(local_file, cls=cls_name, compute_dtype=dtype, config=repo_id, subfolder=subfolder, variant=variant)
|
||||
# transformer = model_quant.do_post_load_quant(transformer, allow=quant_type is not None)
|
||||
|
||||
# 2. load safetensors with native loader if spec is available
|
||||
|
||||
Reference in New Issue
Block a user