diff --git a/CHANGELOG.md b/CHANGELOG.md index e709c954b..051361715 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,8 @@ # Change Log for SD.Next -## Update for 2026-03-27 +## Update for 2026-03-28 -### Highlights for 2026-03-27 +### Highlights for 2026-03-28 This release brings massive code refactoring to modernize codebase and removal of some obsolete features. Leaner & Faster! And since its a bit quieter period when it comes to new models, notable additions would be : *FireRed-Image-Edit*, *SkyWorks-UniPic-3* and new versions of *Anima-Preview*, *Flux-Klein-KV* @@ -20,7 +20,7 @@ Just how big? Some stats: *~530 commits over 880 files* [ReadMe](https://github.com/vladmandic/automatic/blob/master/README.md) | [ChangeLog](https://github.com/vladmandic/automatic/blob/master/CHANGELOG.md) | [Docs](https://vladmandic.github.io/sdnext-docs/) | [WiKi](https://github.com/vladmandic/automatic/wiki) | [Discord](https://discord.com/invite/sd-next-federal-batch-inspectors-1101998836328697867) | [Sponsor](https://github.com/sponsors/vladmandic) -### Details for 2026-03-27 +### Details for 2026-03-28 - **Models** - [Google Flash 3.1 Image](https://ai.google.dev/gemini-api/docs/models/gemini-3-flash-preview) a.k.a. *Nano Banana 2* @@ -77,6 +77,7 @@ Just how big? Some stats: *~530 commits over 880 files* - *note* **Cuda** `torch==2.10` removed support for `rtx1000` series and older GPUs use following before first startup to force installation of `torch==2.9.1` with `cuda==12.6`: > `set TORCH_COMMAND='torch==2.9.1 torchvision==0.24.1 torchaudio==2.9.1 --index-url https://download.pytorch.org/whl/cu126'` + - update installer and support `nunchaku==1.2.1` - **UI** - legacy panels **T2I** and **I2I** are disabled by default you can re-enable them in *settings -> ui -> hide legacy tabs* diff --git a/installer.py b/installer.py index b07e75db8..0b7c491ad 100644 --- a/installer.py +++ b/installer.py @@ -197,14 +197,15 @@ def installed(package, friendly: str | None = None, quiet = False): # pylint: di def uninstall(package, quiet = False): t_start = time.time() packages = package if isinstance(package, list) else [package] - res = '' + txt = '' for p in packages: if installed(p, p, quiet=True): if not quiet: log.warning(f'Package: {p} uninstall') - res += pip(f"uninstall {p} --yes --quiet", ignore=True, quiet=True, uv=False) + _result, _txt = pip(f"uninstall {p} --yes --quiet", ignore=True, quiet=True, uv=False) + txt += _txt ts('uninstall', t_start) - return res + return txt def run(cmd: str, *nargs: str, **kwargs): @@ -259,20 +260,20 @@ def pip(arg: str, ignore: bool = False, quiet: bool = True, uv = True): all_args = f'{pip_log}{arg} {env_args}'.strip() if not quiet: log.debug(f'Running: {pipCmd}="{all_args}"') - result, txt = run(sys.executable, "-m", pipCmd, all_args) + result, output = run(sys.executable, "-m", pipCmd, all_args) if len(result.stderr) > 0: if uv and result.returncode != 0: log.warning(f'Install: cmd="{pipCmd}" args="{all_args}" cannot use uv, fallback to pip') debug(f'Install: uv pip error: {result.stderr}') cleanup_broken_packages() return pip(originalArg, ignore, quiet, uv=False) - debug(f'Install {pipCmd}: {txt}') + debug(f'Install {pipCmd}: {output}') if result.returncode != 0 and not ignore: errors.append(f'pip: {package}') log.error(f'Install: {pipCmd}: {arg}') - log.debug(f'Install: pip output {txt}') + log.debug(f'Install: pip code={result.returncode} stdout={result.stdout} stderr={result.stderr} output={output}') ts('pip', t_start) - return txt + return result, output # install package using pip if not already installed diff --git a/modules/mit_nunchaku.py b/modules/mit_nunchaku.py index aa8eb228b..f9501e36c 100644 --- a/modules/mit_nunchaku.py +++ b/modules/mit_nunchaku.py @@ -2,43 +2,20 @@ from installer import pip from modules.logger import log -from modules import devices -nunchaku_versions = { - '2.5': '1.0.1', - '2.6': '1.0.1', - '2.7': '1.1.0', - '2.8': '1.1.0', - '2.9': '1.1.0', - '2.10': '1.0.2', - '2.11': '1.1.0', -} ok = False -def _expected_ver(): - try: - import torch - torch_ver = '.'.join(torch.__version__.split('+')[0].split('.')[:2]) - return nunchaku_versions.get(torch_ver) - except Exception: - return None - - def check(): global ok # pylint: disable=global-statement if ok: return True try: import nunchaku - import nunchaku.utils - from nunchaku import __version__ - expected = _expected_ver() + import nunchaku.utils # pylint: disable=no-name-in-module, no-member + from nunchaku import __version__ # pylint: disable=no-name-in-module log.info(f'Nunchaku: path={nunchaku.__path__} version={__version__.__version__} precision={nunchaku.utils.get_precision()}') - if expected is not None and __version__.__version__ != expected: - ok = False - return False ok = True return True except Exception as e: @@ -47,14 +24,15 @@ def check(): return False -def install_nunchaku(): - if devices.backend is None: - return False # too early +def install_nunchaku(force=False): + if not force: + from modules import devices + if devices.backend is None: + return False # too early if not check(): import os import sys import platform - import torch python_ver = f'{sys.version_info.major}{sys.version_info.minor}' if python_ver not in ['311', '312', '313']: log.error(f'Nunchaku: python={sys.version_info} unsupported') @@ -63,24 +41,56 @@ def install_nunchaku(): if arch not in ['linux', 'windows']: log.error(f'Nunchaku: platform={arch} unsupported') return False - if devices.backend not in ['cuda']: + if not force and devices.backend not in ['cuda']: log.error(f'Nunchaku: backend={devices.backend} unsupported') return False - torch_ver = '.'.join(torch.__version__.split('+')[0].split('.')[:2]) - nunchaku_ver = nunchaku_versions.get(torch_ver) - if nunchaku_ver is None: - log.error(f'Nunchaku: torch={torch.__version__} unsupported') - return False - suffix = 'x86_64' if arch == 'linux' else 'win_amd64' + url = os.environ.get('NUNCHAKU_COMMAND', None) - if url is None: - arch = f'{arch}_' if arch == 'linux' else '' - url = f'https://huggingface.co/nunchaku-ai/nunchaku/resolve/main/nunchaku-{nunchaku_ver}' - url += f'+torch{torch_ver}-cp{python_ver}-cp{python_ver}-{arch}{suffix}.whl' - cmd = f'install --upgrade {url}' - log.debug(f'Nunchaku: install="{url}"') - pip(cmd, ignore=False, uv=False) + if url is not None: + cmd = f'install --upgrade {url}' + log.debug(f'Nunchaku: install="{url}"') + result, _output = pip(cmd, uv=False, ignore=not force, quiet=not force) + return result.returncode == 0 + else: + import torch + torch_ver = '.'.join(torch.__version__.split('+')[0].split('.')[:2]) + cuda_ver = torch.__version__.split('+')[1]if '+' in torch.__version__ else None + cuda_ver = cuda_ver[:4] + '.' + cuda_ver[-1] if cuda_ver and len(cuda_ver) >= 4 else None + suffix = 'linux_x86_64' if arch == 'linux' else 'win_amd64' + if cuda_ver is None: + log.error(f'Nunchaku: torch={torch.__version__} cuda="unknown"') + return False + if cuda_ver.startswith('cu13'): + nunchaku_versions = ['1.2.1', '1.2.0', '1.1.0', '1.0.2', '1.0.1'] + else: + nunchaku_versions = ['1.2.1', '1.0.2', '1.0.1'] # 1.2.0 and 1.1.0 imply cu13 but do not specify it + for v in nunchaku_versions: + url = f'https://github.com/nunchaku-ai/nunchaku/releases/download/v{v}/' + fn = f'nunchaku-{v}+{cuda_ver}torch{torch_ver}-cp{python_ver}-cp{python_ver}-{suffix}.whl' + result, _output = pip(f'install --upgrade {url+fn}', uv=False, ignore=True, quiet=True) + if force: + log.debug(f'Nunchaku: url="{fn}" code={result.returncode} stdout={result.stdout} stderr={result.stderr} output={_output}') + if result.returncode == 0: + log.info(f'Nunchaku: install url="{url}"') + return True + fn = f'nunchaku-{v}+torch{torch_ver}-cp{python_ver}-cp{python_ver}-{suffix}.whl' + result, _output = pip(f'install --upgrade {url+fn}', uv=False, ignore=True, quiet=True) + if force: + log.debug(f'Nunchaku: url="{fn}" code={result.returncode} stdout={result.stdout} stderr={result.stderr} output={_output}') + if result.returncode == 0: + log.info(f'Nunchaku: install version={v} url="{url+fn}"') + return True + log.error(f'Nunchaku install failed: torch={torch.__version__} cuda={cuda_ver} python={python_ver} platform={arch}') + return False + if not check(): log.error('Nunchaku: install failed') return False return True + + +if __name__ == '__main__': + from modules.logger import setup_logging + setup_logging() + log.info('Nunchaku: manual install') + install_nunchaku(force=True)