From dc46f498be4f5b951ec6aa512d92c3deeb45ec66 Mon Sep 17 00:00:00 2001 From: Hayden <48267247+hayden-fr@users.noreply.github.com> Date: Tue, 3 Dec 2024 14:05:18 +0800 Subject: [PATCH] Split model get list (#74) Get the model list separately by model type and defer the request. --- __init__.py | 17 +++++++- py/services.py | 66 ++++++++++++++++---------------- src/App.vue | 11 +++++- src/components/DialogManager.vue | 10 +++-- src/components/ModelBaseInfo.vue | 6 +-- src/hooks/config.ts | 12 +----- src/hooks/model.ts | 56 +++++++++++++++++++++++---- 7 files changed, 114 insertions(+), 64 deletions(-) diff --git a/__init__.py b/__init__.py index cf5eefc..ceeaf8c 100644 --- a/__init__.py +++ b/__init__.py @@ -89,6 +89,7 @@ async def delete_model_download_task(request): return web.json_response({"success": False, "error": error_msg}) +# @deprecated @routes.get("/model-manager/base-folders") async def get_model_paths(request): """ @@ -124,12 +125,12 @@ async def create_model(request): @routes.get("/model-manager/models") -async def read_models(request): +async def list_model_types(request): """ Scan all models and read their information. """ try: - result = services.scan_models(request) + result = utils.resolve_model_base_paths() return web.json_response({"success": True, "data": result}) except Exception as e: error_msg = f"Read models failed: {str(e)}" @@ -137,6 +138,18 @@ async def read_models(request): return web.json_response({"success": False, "error": error_msg}) +@routes.get("/model-manager/models/{folder}") +async def read_models(request): + try: + folder = request.match_info.get("folder", None) + results = services.scan_models(folder, request) + return web.json_response({"success": True, "data": results}) + except Exception as e: + error_msg = f"Read models failed: {str(e)}" + utils.print_error(error_msg) + return web.json_response({"success": False, "error": error_msg}) + + @routes.get("/model-manager/model/{type}/{index}/{filename:.*}") async def read_model_info(request): """ diff --git a/py/services.py b/py/services.py index 41bb4fb..4cad9e5 100644 --- a/py/services.py +++ b/py/services.py @@ -8,48 +8,46 @@ from . import download from . import searcher -def scan_models(request): +def scan_models(folder: str, request): result = [] - model_base_paths = utils.resolve_model_base_paths() - for model_type in model_base_paths: - folders, extensions = folder_paths.folder_names_and_paths[model_type] - for path_index, base_path in enumerate(folders): - files = utils.recursive_search_files(base_path, request) + folders, extensions = folder_paths.folder_names_and_paths[folder] + for path_index, base_path in enumerate(folders): + files = utils.recursive_search_files(base_path, request) - models = folder_paths.filter_files_extensions(files, folder_paths.supported_pt_extensions) + models = folder_paths.filter_files_extensions(files, folder_paths.supported_pt_extensions) - for fullname in models: - fullname = utils.normalize_path(fullname) - basename = os.path.splitext(fullname)[0] - extension = os.path.splitext(fullname)[1] + for fullname in models: + fullname = utils.normalize_path(fullname) + basename = os.path.splitext(fullname)[0] + extension = os.path.splitext(fullname)[1] - abs_path = utils.join_path(base_path, fullname) - file_stats = os.stat(abs_path) + abs_path = utils.join_path(base_path, fullname) + file_stats = os.stat(abs_path) - # Resolve preview - image_name = utils.get_model_preview_name(abs_path) - image_name = utils.join_path(os.path.dirname(fullname), image_name) - abs_image_path = utils.join_path(base_path, image_name) - if os.path.isfile(abs_image_path): - image_state = os.stat(abs_image_path) - image_timestamp = round(image_state.st_mtime_ns / 1000000) - image_name = f"{image_name}?ts={image_timestamp}" - model_preview = f"/model-manager/preview/{model_type}/{path_index}/{image_name}" + # Resolve preview + image_name = utils.get_model_preview_name(abs_path) + image_name = utils.join_path(os.path.dirname(fullname), image_name) + abs_image_path = utils.join_path(base_path, image_name) + if os.path.isfile(abs_image_path): + image_state = os.stat(abs_image_path) + image_timestamp = round(image_state.st_mtime_ns / 1000000) + image_name = f"{image_name}?ts={image_timestamp}" + model_preview = f"/model-manager/preview/{folder}/{path_index}/{image_name}" - model_info = { - "fullname": fullname, - "basename": basename, - "extension": extension, - "type": model_type, - "pathIndex": path_index, - "sizeBytes": file_stats.st_size, - "preview": model_preview, - "createdAt": round(file_stats.st_ctime_ns / 1000000), - "updatedAt": round(file_stats.st_mtime_ns / 1000000), - } + model_info = { + "fullname": fullname, + "basename": basename, + "extension": extension, + "type": folder, + "pathIndex": path_index, + "sizeBytes": file_stats.st_size, + "preview": model_preview, + "createdAt": round(file_stats.st_ctime_ns / 1000000), + "updatedAt": round(file_stats.st_mtime_ns / 1000000), + } - result.append(model_info) + result.append(model_info) return result diff --git a/src/App.vue b/src/App.vue index a2afb43..4d0c8c9 100644 --- a/src/App.vue +++ b/src/App.vue @@ -15,16 +15,18 @@ import { useStoreProvider } from 'hooks/store' import { useToast } from 'hooks/toast' import GlobalConfirm from 'primevue/confirmdialog' import { $el, app, ComfyButton } from 'scripts/comfyAPI' -import { onMounted } from 'vue' +import { onMounted, ref } from 'vue' import { useI18n } from 'vue-i18n' const { t } = useI18n() const { dialog, models, config, download } = useStoreProvider() const { toast } = useToast() +const firstOpenManager = ref(true) + onMounted(() => { const refreshModelsAndConfig = async () => { - await Promise.all([models.refresh(), config.refresh()]) + await Promise.all([models.refresh(true)]) toast.add({ severity: 'success', summary: 'Refreshed Models', @@ -50,6 +52,11 @@ onMounted(() => { const openManagerDialog = () => { const { cardWidth, gutter, aspect } = config + if (firstOpenManager.value) { + models.refresh(true) + firstOpenManager.value = false + } + dialog.open({ key: 'model-manager', title: t('modelManager'), diff --git a/src/components/DialogManager.vue b/src/components/DialogManager.vue index 0b5baf5..836d9bb 100644 --- a/src/components/DialogManager.vue +++ b/src/components/DialogManager.vue @@ -88,9 +88,9 @@ import { genModelKey } from 'utils/model' import { computed, ref, watch } from 'vue' import { useI18n } from 'vue-i18n' -const { isMobile, cardWidth, gutter, aspect, modelFolders } = useConfig() +const { isMobile, cardWidth, gutter, aspect } = useConfig() -const { data } = useModels() +const { data, folders } = useModels() const { t } = useI18n() const responseScroll = ref() @@ -99,7 +99,7 @@ const searchContent = ref() const currentType = ref('all') const typeOptions = computed(() => { - return ['all', ...Object.keys(modelFolders.value)].map((type) => { + return ['all', ...Object.keys(folders.value)].map((type) => { return { label: type, value: type, @@ -143,7 +143,9 @@ const colSpan = ref(1) const colSpanWidth = ref(cardWidth) const list = computed(() => { - const filterList = data.value.filter((model) => { + const mergedList = Object.values(data.value).flat() + + const filterList = mergedList.filter((model) => { const showAllModel = currentType.value === 'all' const matchType = showAllModel || model.type === currentType.value diff --git a/src/components/ModelBaseInfo.vue b/src/components/ModelBaseInfo.vue index 98b23a1..1942881 100644 --- a/src/components/ModelBaseInfo.vue +++ b/src/components/ModelBaseInfo.vue @@ -49,15 +49,13 @@