1212from invokeai .backend .model_manager .configs .unknown import Unknown_Config
1313from invokeai .backend .model_manager .taxonomy import (
1414 BaseModelType ,
15+ ClipVariantType ,
1516 FluxVariantType ,
1617 ModelFormat ,
1718 ModelType ,
19+ ModelVariantType ,
1820 SchedulerPredictionType ,
1921)
2022
@@ -30,10 +32,20 @@ def __call__(self, cursor: sqlite3.Cursor) -> None:
3032 cursor .execute ("SELECT id, config FROM models;" )
3133 rows = cursor .fetchall ()
3234
35+ migrated_count = 0
36+ fallback_count = 0
37+
3338 for model_id , config_json in rows :
3439 try :
3540 # Migrate the config JSON to the latest schema
36- migrated_config = self ._parse_and_migrate_config (config_json )
41+ config_dict : dict [str , Any ] = json .loads (config_json )
42+ migrated_config = self ._parse_and_migrate_config (config_dict )
43+
44+ if isinstance (migrated_config , Unknown_Config ):
45+ fallback_count += 1
46+ else :
47+ migrated_count += 1
48+
3749 # Write the migrated config back to the database
3850 cursor .execute (
3951 "UPDATE models SET config = ? WHERE id = ?;" ,
@@ -46,9 +58,21 @@ def __call__(self, cursor: sqlite3.Cursor) -> None:
4658 self ._logger .error ("Invalid config JSON for model %s: %s" , model_id , e )
4759 raise
4860
49- def _parse_and_migrate_config (self , config_json : Any ) -> AnyModelConfig :
50- config_dict : dict [str , Any ] = json .loads (config_json )
61+ if migrated_count > 0 and fallback_count == 0 :
62+ self ._logger .info (f"Migration complete: { migrated_count } model configs migrated" )
63+ elif migrated_count > 0 and fallback_count > 0 :
64+ self ._logger .warning (
65+ f"Migration complete: { migrated_count } model configs migrated, "
66+ f"{ fallback_count } model configs could not be migrated and were saved as unknown models" ,
67+ )
68+ elif migrated_count == 0 and fallback_count > 0 :
69+ self ._logger .warning (
70+ f"Migration complete: all { fallback_count } model configs could not be migrated and were saved as unknown models" ,
71+ )
72+ else :
73+ self ._logger .info ("Migration complete: no model configs needed migration" )
5174
75+ def _parse_and_migrate_config (self , config_dict : dict [str , Any ]) -> AnyModelConfig :
5276 # In v6.9.0 we made some improvements to the model taxonomy and the model config schemas. There are a changes
5377 # we need to make to old configs to bring them up to date.
5478
@@ -101,7 +125,12 @@ def _parse_and_migrate_config(self, config_json: Any) -> AnyModelConfig:
101125 # It's only on SD1.x, SD2.x, and SDXL main models.
102126 config_dict ["prediction_type" ] = config_dict .get ("prediction_type" , SchedulerPredictionType .Epsilon .value )
103127
104- if base == BaseModelType .Flux and type == ModelType .LoRA .value and format == ModelFormat .Diffusers .value :
128+ # Prior to v6.9.0, the variant field was optional and would default to Normal if not present.
129+ # We now make it explicit and always present. Use the existing value if present, otherwise default to
130+ # Normal. It's only on SD main models.
131+ config_dict ["variant" ] = config_dict .get ("variant" , ModelVariantType .Normal .value )
132+
133+ if base == BaseModelType .Flux .value and type == ModelType .LoRA .value and format == ModelFormat .Diffusers .value :
105134 # Prior to v6.9.0, we used the Diffusers format for FLUX LoRA models that used the diffusers _key_
106135 # structure. This was misleading, as everywhere else in the application, we used the Diffusers format
107136 # to indicate that the model files were in the Diffusers _file_ format (i.e. a directory containing
@@ -124,9 +153,18 @@ def _parse_and_migrate_config(self, config_json: Any) -> AnyModelConfig:
124153 # as independent of any specific base model architecture.
125154 config_dict ["base" ] = BaseModelType .Any .value
126155
156+ if type == ModelType .CLIPEmbed .value :
157+ # Prior to v6.9.0, some CLIP Embed models did not have a variant set. The default was the L variant.
158+ # We now make it explicit and always present. Use the existing value if present, otherwise default to
159+ # L variant. Also, treat CLIP Embed models as independent of any specific base model architecture.
160+ config_dict ["base" ] = BaseModelType .Any .value
161+ config_dict ["variant" ] = config_dict .get ("variant" , ClipVariantType .L .value )
162+
127163 try :
128164 migrated_config = AnyModelConfigValidator .validate_python (config_dict )
129- except ValidationError as e :
165+ # This could be a ValidationError or any other error that occurs during validation. A failure to generate a
166+ # union discriminator could raise a ValueError, for example. Who knows what else could fail - catch all.
167+ except Exception as e :
130168 self ._logger .error ("Failed to validate migrated config, attempting to save as unknown model: %s" , e )
131169 cloned_config_dict = deepcopy (config_dict )
132170 cloned_config_dict .pop ("base" , None )
0 commit comments