Commit Graph

18533 Commits

Author SHA1 Message Date
psychedelicious
b87bfd9a06 tidy(mm): clarify that model id utils are private 2025-10-10 16:48:32 +11:00
psychedelicious
37743dea38 fix(mm): abstractmethod bork 2025-10-10 16:48:31 +11:00
psychedelicious
202979dcb7 refactor(mm): add model config parsing utils 2025-10-10 16:48:31 +11:00
psychedelicious
4476ebff60 refactor(mm): remove unused methods in config.py 2025-10-10 16:48:31 +11:00
psychedelicious
e278b120b1 refactor(mm): simplify model classification process
Previously, we had a multi-phase strategy to identify models from their
files on disk:
1. Run each model config classes' `matches()` method on the files. It
checks if the model could possibly be an identified as the candidate
model type. This was intended to be a quick check. Break on the first
match.
2. If we have a match, run the config class's `parse()` method. It
derive some additional model config attrs from the model files. This was
intended to encapsulate heavier operations that may require loading the
model into memory.
3. Derive the common model config attrs, like name, description,
calculate the hash, etc. Some of these are also heavier operations.

This strategy has some issues:
- It is not clear how the pieces fit together. There is some
back-and-forth between different methods and the config base class. It
is hard to trace the flow of logic until you fully wrap your head around
the system and therefore difficult to add a model architecture to the
probe.
- The assumption that we could do quick, lightweight checks before
heavier checks is incorrect. We often _must_ load the model state dict
in the `matches()` method. So there is no practical perf benefit to
splitting up the responsibility of `matches()` and `parse()`.
- Sometimes we need to do the same checks in `matches()` and `parse()`.
In these cases, splitting the logic is has a negative perf impact
because we are doing the same work twice.
- As we introduce the concept of an "unknown" model config (i.e. a model
that we cannot identify, but still record in the db; see #8582), we will
_always_ run _all_ the checks for every model. Therefore we need not try
to defer heavier checks or resource-intensive ops like hashing. We are
going to do them anyways.
- There are situations where a model may match multiple configs. One
known case are SD pipeline models with merged LoRAs. In the old probe
API, we relied on the implicit order of checks to know that if a model
matched for pipeline _and_ LoRA, we prefer the pipeline match. But, in
the new API, we do not have this implicit ordering of checks. To resolve
this in a resilient way, we need to get all matches up front, then use
tie-breaker logic to figure out which should win (or add "differential
diagnosis" logic to the matchers).
- Field overrides weren't handled well by this strategy. They were only
applied at the very end, if a model matched successfully. This means we
cannot tell the system "Hey, this model is type X with base Y. Trust me
bro.". We cannot override the match logic. As we move towards letting
users correct mis-identified models (see #8582), this is a requirement.

We can simplify the process significantly and better support "unknown"
models.

Firstly, model config classes now have a single `from_model_on_disk()`
method that attempts to construct an instance of the class from the
model files. This replaces the `matches()` and `parse()` methods.

If we fail to create the config instance, a special exception is raised
that indicates why we think the files cannot be identified as the given
model config class.

Next, the flow for model identification is a bit simpler:
- Derive all the common fields up-front (name, desc, hash, etc).
- Merge in overrides.
- Call `from_model_on_disk()` for every config class, passing in the
fields. Overrides are handled in this method.
- Record the results for each config class and choose the best one.

The identification logic is a bit more verbose, with the special
exceptions and handling of overrides, but it is very clear what is
happening.

The one downside I can think of for this strategy is we do need to check
every model type, instead of stopping at the first match. It's a bit
less efficient. In practice, however, this isn't a hot code path, and
the improved clarity is worth far more than perf optimizations that the
end user will likely never notice.
2025-10-10 16:48:31 +11:00
psychedelicious
9fba676346 feat(mm): make config_path optional 2025-10-10 16:48:31 +11:00
psychedelicious
f10d0e80a2 feat(mm): port t5 to new API 2025-10-10 16:48:31 +11:00
psychedelicious
424b2deb5c feat(mm): better errors when invalid model config found in db 2025-10-10 16:48:31 +11:00
psychedelicious
b7491b700f tidy(mm): patcher types and import paths 2025-10-10 16:48:31 +11:00
psychedelicious
93db54957c fix(mm): vae class inheritance and config_path 2025-10-10 16:48:31 +11:00
psychedelicious
3dfcf9a869 feat(mm): port vae to new API 2025-10-10 16:48:31 +11:00
psychedelicious
37de184198 fix(mm): tis use existing weight_files method 2025-10-10 16:48:31 +11:00
psychedelicious
18165bc265 fix(mm): loader for clip embed 2025-10-10 16:48:31 +11:00
psychedelicious
3bebae0deb fix(mm): parsing for spandrel 2025-10-10 16:48:31 +11:00
psychedelicious
4f413d2714 feat(mm): port spandrel to new API 2025-10-10 16:48:31 +11:00
psychedelicious
6877e0bd01 tidy(mm): remove unused probes 2025-10-10 16:48:31 +11:00
psychedelicious
1087aadcd9 feat(mm): port TIs to new API 2025-10-10 16:48:31 +11:00
psychedelicious
4b52cc2546 refactor: port MM probes to new api
- Add concept of match certainty to new probe
- Port CLIP Embed models to new API
- Fiddle with stuff
2025-10-10 16:48:31 +11:00
psychedelicious
613fa15ee7 fix(mm): normalized multi-file/diffusers model installation no worky
now worky
2025-10-10 16:48:31 +11:00
psychedelicious
ebd8e7dc04 feat(mm): add migration to flat model storage 2025-10-10 16:48:31 +11:00
psychedelicious
d67d652dcf feat(mm): normalized model storage
Store models in a flat directory structure. Each model is in a dir named
its unique key (a UUID). Inside that dir is either the model file or the
model dir.
2025-10-10 16:48:30 +11:00
psychedelicious
f47fd29abb fix(ui): wrong translation string 2025-10-10 16:48:30 +11:00
psychedelicious
7fcd14074d chore(ui): lint 2025-10-10 16:48:30 +11:00
psychedelicious
e4d68ca9bf tidy(ui): prefer types from zod schemas for model attrs 2025-10-10 16:48:30 +11:00
psychedelicious
4d3715e786 tests(mm): fix test for MM, leave the UnknownModelConfig class in the list of configs 2025-10-10 16:48:30 +11:00
psychedelicious
7ccb689452 chore(ui): typegen 2025-10-10 16:48:30 +11:00
psychedelicious
f421b7beef docs: update config docstrings 2025-10-10 16:48:30 +11:00
psychedelicious
c4a4e8b85e feat(ui): toast warning when installed model is unidentified 2025-10-10 16:48:30 +11:00
psychedelicious
e7530f6789 chore(ui): typegen 2025-10-10 16:48:30 +11:00
psychedelicious
78d9659bcd feat(app): add the installed model config to install complete events 2025-10-10 16:48:30 +11:00
psychedelicious
3d270ca030 feat(ui): allow changing model format in MM 2025-10-10 16:48:30 +11:00
psychedelicious
c5418efd3b feat(app): add setting to allow unknown models 2025-10-10 16:48:30 +11:00
psychedelicious
0e79fed1dc feat(mm): omit model description instead of making it "base type filename model" 2025-10-10 16:48:30 +11:00
psychedelicious
2a5a84ac65 feat(ui): allow changing model type in MM, fix up base and variant selects 2025-10-10 16:48:30 +11:00
psychedelicious
3ea6b39c90 feat(ui): add unknown model base support in ui 2025-10-10 16:48:30 +11:00
psychedelicious
df954eb6d7 chore(ui): typegen 2025-10-10 16:48:30 +11:00
psychedelicious
55e3ccff08 feat(nodes): add unknown as model base 2025-10-10 16:48:30 +11:00
psychedelicious
39ad14bc1a refactor(ui): remove unused excludeSubmodels
I can't remember what this was for and don't see any reference to it.
Maybe it's just remnants from a previous implementation?
2025-10-10 16:48:30 +11:00
psychedelicious
48ff8f9967 refactor(ui)refactor(ui): more cleanup of model categories 2025-10-10 16:48:29 +11:00
psychedelicious
102fb26169 refactor(ui): move model categorisation-ish logic to central location, simplify model manager models list 2025-10-10 16:48:29 +11:00
psychedelicious
3af504eee8 feat(mm): add UnknownModelConfig 2025-10-10 16:48:29 +11:00
dunkeroni
bd4bb075a5 bump node version to 2.0.0 2025-10-09 17:55:13 +11:00
dunkeroni
e19b7d4afb update typegen 2025-10-09 17:55:13 +11:00
dunkeroni
f8d0b43a9b change Colorspace title to "Color Space" 2025-10-09 17:55:13 +11:00
dunkeroni
50c77d9bf0 error message for incorrect mask size 2025-10-09 17:55:13 +11:00
dunkeroni
358cc0349e (chore) cleanup and schema 2025-10-09 17:55:13 +11:00
copilot-swe-agent[bot]
417e6ebdbc Simplify mask application by pasting base on corrected instead of inverting mask
Co-authored-by: dunkeroni <3298737+dunkeroni@users.noreply.github.com>
2025-10-09 17:55:13 +11:00
copilot-swe-agent[bot]
7919d659b7 Use PIL Image.paste() for mask application instead of numpy array blending
Co-authored-by: dunkeroni <3298737+dunkeroni@users.noreply.github.com>
2025-10-09 17:55:13 +11:00
dunkeroni
ec665d2c7f remove extra conversion 2025-10-09 17:55:13 +11:00
dunkeroni
020d36b234 remove extra conversion 2025-10-09 17:55:13 +11:00