diff --git a/CHANGELOG.md b/CHANGELOG.md index 1f10dbc17..51dedbb14 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,8 @@ # Change Log for SD.Next -## Update for 2026-05-27 +## Update for 2026-05-29 -### Highlights for 2026-05-27 +### Highlights for 2026-05-29 *What's New?* - **Anima** made it to release version, Microsoft joins the game with **Lens** @@ -14,7 +14,7 @@ And we have new [Home](https://vladmandic.github.io/sdnext/) page and new [Contr Plus continued work on modernization of codebase: UI is now fully TypeScript based and we have a new modular LoRA loader -### Details for 2026-05-25 +### Details for 2026-05-29 - **Models** - [CircleStone Anima 1.0](https://huggingface.co/circlestone-labs/Anima) in *Base* and *Turbo* (distilled) variants @@ -91,6 +91,9 @@ Plus continued work on modernization of codebase: UI is now fully TypeScript bas - `hf download` model card lookup - `ltx video` padding logic - `prompt enhance` custom model loader + - `styles` loader exception handling + - `kanvas` image change notification + - `reinstall` force reinstal of transformers and diffusers ## Update for 2026-05-13 diff --git a/installer.py b/installer.py index 5763e3142..ff2c88e81 100644 --- a/installer.py +++ b/installer.py @@ -572,7 +572,7 @@ def check_transformers(): target_tokenizers = '0.23.1' if target_transformers is not None: # Pinned release version (e.g. DirectML) - if (pkg_transformers is None) or ((pkg_transformers.version != target_transformers) or (pkg_tokenizers is None) or ((pkg_tokenizers.version != target_tokenizers) and (not args.experimental))): + if args.reinstall or (pkg_transformers is None) or ((pkg_transformers.version != target_transformers) or (pkg_tokenizers is None) or ((pkg_tokenizers.version != target_tokenizers) and (not args.experimental))): if pkg_transformers is None: log.info(f'Install: package="transformers" version={target_transformers}') else: @@ -583,7 +583,7 @@ def check_transformers(): else: # Git commit-pinned version current = opts.get('transformers_version', '') - if (pkg_transformers is None) or (pkg_transformers.version.startswith('4')) or (current != target_commit): + if args.reinstall or (pkg_transformers is None) or (pkg_transformers.version.startswith('4')) or (current != target_commit): if pkg_transformers is None: log.info(f'Install: package="transformers" commit={target_commit}') else: diff --git a/modules/styles.py b/modules/styles.py index 930ff6a41..79e70a9bc 100644 --- a/modules/styles.py +++ b/modules/styles.py @@ -305,40 +305,40 @@ class StyleDatabase: pass def load_style(self, fn, prefix=None): - with open(fn, encoding='utf-8') as f: - new_style = None - try: + new_style = None + try: + with open(fn, encoding='utf-8') as f: all_styles = json.load(f) - if type(all_styles) is dict: - all_styles = [all_styles] - for style in all_styles: - if type(style) is not dict or "name" not in style: - raise ValueError('cannot parse style') - basename = os.path.splitext(os.path.basename(fn))[0] - name = re.sub(r'[\t\r\n]', '', style.get("name", basename)).strip() - if prefix is not None: - name = os.path.join(prefix, name) - else: - name = os.path.join(os.path.dirname(os.path.relpath(fn, self.path)), name) - new_style = Style( - name=name, - desc=style.get('description', name), - prompt=style.get("prompt", ""), - negative_prompt=style.get("negative", ""), - extra=style.get("extra", ""), - wildcards=style.get("wildcards", ""), - preview=style.get("preview", None), - filename=fn, - mtime=os.path.getmtime(fn), - ) - # key by the prefixed name so styles with the same base name in different - # subfolders do not collide and overwrite each other - if name in self.styles: - log.warning(f'Style duplicate name: name="{name}" file="{fn}" existing="{self.styles[name].filename}"') - self.styles[name] = new_style - except Exception as e: - log.error(f'Failed to load style: file="{fn}" error={e}') - return new_style + if type(all_styles) is dict: + all_styles = [all_styles] + for style in all_styles: + if type(style) is not dict or "name" not in style: + raise ValueError('cannot parse style') + basename = os.path.splitext(os.path.basename(fn))[0] + name = re.sub(r'[\t\r\n]', '', style.get("name", basename)).strip() + if prefix is not None: + name = os.path.join(prefix, name) + else: + name = os.path.join(os.path.dirname(os.path.relpath(fn, self.path)), name) + new_style = Style( + name=name, + desc=style.get('description', name), + prompt=style.get("prompt", ""), + negative_prompt=style.get("negative", ""), + extra=style.get("extra", ""), + wildcards=style.get("wildcards", ""), + preview=style.get("preview", None), + filename=fn, + mtime=os.path.getmtime(fn), + ) + # key by the prefixed name so styles with the same base name in different + # subfolders do not collide and overwrite each other + if name in self.styles: + log.warning(f'Style duplicate name: name="{name}" file="{fn}" existing="{self.styles[name].filename}"') + self.styles[name] = new_style + except Exception as e: + log.error(f'Failed to load style: file="{fn}" error={e}') + return new_style def reload(self): t0 = time.time()