feat(api): expose effective extension filter on /experiment/models
Some checks are pending
Python Linting / Run Pylint (push) Waiting to run
Python Linting / Run Ruff (push) Waiting to run

Each folder in the listing now carries its effective display filter:
the registered extension set, or the global supported_pt_extensions for
match-all folders (registered with an empty set, e.g. LLM). Resolved per
request so runtime registrations by custom nodes are reflected.

Lets the asset-backed model sidebar filter match-all folder contents
(hiding README/config noise) without hardcoding the global set client
side, while registered folders stay governed by the scanner's
extension-filtered model_type tags.
This commit is contained in:
Simon Pinfold 2026-07-03 14:47:51 +12:00
parent 529abc991f
commit 6deeae99e7
3 changed files with 41 additions and 1 deletions

View File

@ -35,7 +35,17 @@ class ModelFileManager:
for folder in model_types: for folder in model_types:
if folder in folder_black_list: if folder in folder_black_list:
continue continue
output_folders.append({"name": folder, "folders": folder_paths.get_folder_paths(folder)}) # Effective display filter: the folder's registered extension
# set, or the global supported_pt_extensions for match-all
# folders (empty set), resolved live so runtime registrations
# by custom nodes are reflected.
registered = folder_paths.folder_names_and_paths[folder][1]
effective = set(registered) if registered else set(folder_paths.supported_pt_extensions)
output_folders.append({
"name": folder,
"folders": folder_paths.get_folder_paths(folder),
"extensions": sorted(effective),
})
return web.json_response(output_folders) return web.json_response(output_folders)
# NOTE: This is an experiment to replace `/models/{folder}` # NOTE: This is an experiment to replace `/models/{folder}`

View File

@ -775,6 +775,14 @@ components:
ModelFolder: ModelFolder:
description: Represents a folder containing models description: Represents a folder containing models
properties: properties:
extensions:
description: 'Effective file-extension display filter for this folder: the registered extension set, or the global supported model extensions for folders registered without one (match-all). Resolved live, so runtime registrations by custom nodes are reflected.'
example:
- .ckpt
- .safetensors
items:
type: string
type: array
folders: folders:
description: List of paths where models of this type are stored description: List of paths where models of this type are stored
example: example:

View File

@ -24,6 +24,28 @@ def app(model_manager):
app.add_routes(routes) app.add_routes(routes)
return app return app
async def test_get_model_folders_includes_effective_extensions(aiohttp_client, app, tmp_path):
"""Folders expose their effective display filter: the registered extension
set, or the global supported_pt_extensions for match-all (empty) folders."""
with patch('folder_paths.folder_names_and_paths', {
'test_checkpoints': ([str(tmp_path)], {'.safetensors', '.ckpt'}),
'test_configs': ([str(tmp_path)], ['.yaml']),
'test_match_all': ([str(tmp_path)], set()),
'configs': ([str(tmp_path)], ['.yaml']),
}), patch('folder_paths.supported_pt_extensions', {'.safetensors', '.bin'}):
client = await aiohttp_client(app)
response = await client.get('/experiment/models')
assert response.status == 200
folders = {f['name']: f for f in await response.json()}
assert 'configs' not in folders # blocklisted
assert folders['test_checkpoints']['folders'] == [str(tmp_path)]
assert folders['test_checkpoints']['extensions'] == ['.ckpt', '.safetensors']
assert folders['test_configs']['extensions'] == ['.yaml']
# Match-all folders substitute the live global set.
assert folders['test_match_all']['extensions'] == ['.bin', '.safetensors']
async def test_get_model_preview_safetensors(aiohttp_client, app, tmp_path): async def test_get_model_preview_safetensors(aiohttp_client, app, tmp_path):
img = Image.new('RGB', (100, 100), 'white') img = Image.new('RGB', (100, 100), 'white')
img_byte_arr = BytesIO() img_byte_arr = BytesIO()