@@ -142,33 +142,88 @@ async def list_models(self, embedding=False):
142142 models .remove (model )
143143 continue
144144 # Only set model["stored_in_filesystem"] to True if the model is a local model and not a Hugging Face model
145- if (
146- not model .get ("json_data" , {}).get ("source" , "" ) == "huggingface"
147- and not model .get ("json_data" , {}).get ("model_filename" , "" ) == ""
148- ):
145+ # model_filename can be:
146+ # - A filename (e.g., "model.gguf") for file-based models
147+ # - "." for directory-based models (indicates the directory itself)
148+ # - Empty string for legacy models (should be treated as directory-based)
149+ model_filename = model .get ("json_data" , {}).get ("model_filename" , "" )
150+ is_huggingface = model .get ("json_data" , {}).get ("source" , "" ) == "huggingface"
151+ has_model_filename = model_filename != ""
152+
153+ # Determine the potential model directory path
154+ # This applies to both HuggingFace models stored locally and local models
155+ model_id = model .get ("model_id" , "" )
156+ potential_path = os .path .join (models_dir , secure_filename (model_id ))
157+ # Check if local path exists
158+ if not os .path .exists (potential_path ):
159+ # Remove the Starting TransformerLab/ prefix to handle the save_transformerlab_model function
160+ potential_path = os .path .join (models_dir , secure_filename ("/" .join (model_id .split ("/" )[1 :])))
161+
162+ # Check if model should be considered local:
163+ # 1. If it has a model_filename set (and is not a HuggingFace model, OR is a HuggingFace model stored locally), OR
164+ # 2. If the directory exists and has files other than index.json
165+ is_local_model = False
166+ if not is_huggingface :
167+ # For non-HuggingFace models, check if it has model_filename or files in directory
168+ if has_model_filename :
169+ is_local_model = True
170+ elif os .path .exists (potential_path ) and os .path .isdir (potential_path ):
171+ # Check if directory has files other than index.json
172+ try :
173+ files = os .listdir (potential_path )
174+ # Filter out index.json and other metadata files
175+ model_files = [f for f in files if f not in ["index.json" , "_tlab_provenance.json" ]]
176+ if model_files :
177+ is_local_model = True
178+ except (OSError , PermissionError ):
179+ # If we can't read the directory, skip it
180+ pass
181+ elif is_huggingface and has_model_filename :
182+ # For HuggingFace models, if they have a model_filename and the file/directory exists locally,
183+ # treat them as stored locally (e.g., downloaded GGUF files)
184+ if os .path .exists (potential_path ):
185+ is_local_model = True
186+
187+ if is_local_model :
149188 # tells the app this model was loaded from workspace directory
150189 model ["stored_in_filesystem" ] = True
151-
152- # Set local_path to the filesystem location
153- # this will tell Hugging Face to not try downloading
154- model_id = model .get ("model_id" , "" )
155- model_filename = model .get ("json_data" , {}).get ("model_filename" , "" )
156- model ["local_path" ] = os .path .join (models_dir , secure_filename (model_id ))
157- # Check if local path exists
158- if not os .path .exists (model ["local_path" ]):
159- # Remove the Starting TransformerLab/ prefix to handle the save_transformerlab_model function
160- model ["local_path" ] = os .path .join (models_dir , secure_filename ("/" .join (model_id .split ("/" )[1 :])))
161-
162- # Some models are a single file (possibly of many in a directory, e.g. GGUF)
163- # For models that have model_filename set we should link directly to that specific file
164- if "model_filename" in model .get ("json_data" , {}):
165- model_filename = model ["json_data" ]["model_filename" ]
166- if model_filename .endswith (".gguf" ):
167- model ["local_path" ] = os .path .join (
168- os .path .join (models_dir , secure_filename (model_id )), model_filename
169- )
190+ model ["local_path" ] = potential_path
191+
192+ # Handle different model_filename cases
193+ if model_filename == "." :
194+ # Directory-based model - convert to absolute path so it can be used anywhere
195+ model ["local_path" ] = os .path .abspath (model ["local_path" ])
196+ elif model_filename and model_filename .endswith (".gguf" ):
197+ # GGUF file - append the filename to the model directory and convert to absolute path
198+ # This ensures we get the full path like: /path/to/models/dir/model.gguf
199+ base_path = model ["local_path" ]
200+ model_path = os .path .join (base_path , model_filename )
201+ if os .path .exists (model_path ):
202+ if os .path .isdir (model_path ):
203+ # List all files in the directory ending with .gguf
204+ gguf_files = [f for f in os .listdir (model_path ) if f .endswith (".gguf" )]
205+ if gguf_files :
206+ model_path = os .path .join (model_path , gguf_files [0 ])
170207 else :
171- model ["local_path" ] = os .path .join (model ["local_path" ], model ["json_data" ]["model_filename" ])
208+ # Seearch for files ending with .gguf in the directory
209+ gguf_files = [f for f in os .listdir (model ["local_path" ]) if f .endswith (".gguf" )]
210+ if gguf_files :
211+ gguf_file = gguf_files [0 ]
212+ model_path = os .path .join (base_path , gguf_file )
213+ if os .path .isdir (model_path ):
214+ gguf_files = [f for f in os .listdir (model_path ) if f .endswith (".gguf" )]
215+ if gguf_files :
216+ model_path = os .path .join (model_path , gguf_files [0 ])
217+
218+
219+
220+ model ["local_path" ] = os .path .abspath (model_path )
221+ elif model_filename :
222+ # Other file-based models - append the filename and convert to absolute path
223+ model ["local_path" ] = os .path .abspath (os .path .join (model ["local_path" ], model_filename ))
224+ else :
225+ # Legacy model without model_filename but with files - use directory path
226+ model ["local_path" ] = os .path .abspath (model ["local_path" ])
172227
173228 # Filter out models based on whether they are embedding models or not
174229 models = await self .filter_embedding_models (models , embedding )
0 commit comments