mirror of
https://github.com/willmiao/ComfyUI-Lora-Manager.git
synced 2026-03-21 13:12:12 -03:00
Backend fixes: - Add missing API route for /api/lm/recipes/batch-import/progress (GET) - Add missing API route for /api/lm/recipes/batch-import/directory (POST) - Add missing API route for /api/lm/recipes/browse-directory (POST) - Register WebSocket endpoint for batch import progress - Fix skip_no_metadata default value (True -> False) to allow no-LoRA imports - Add items array to BatchImportProgress.to_dict() for detailed results Frontend implementation: - Create BatchImportManager.js with complete batch import workflow - Add directory browser UI for selecting folders - Add batch import modal with URL list and directory input modes - Implement real-time progress tracking (WebSocket + HTTP polling) - Add results summary with success/failed/skipped statistics - Add expandable details view showing individual item status - Auto-refresh recipe list after import completion UI improvements: - Add spinner animation for importing status - Simplify results summary UI to match progress stats styling - Fix current item text alignment - Fix dark theme styling for directory browser button - Fix batch import button styling consistency Translations: - Add batch import related i18n keys to all locale files - Run sync_translation_keys.py to sync all translations Fixes: - Batch import now allows images without LoRAs (matches single import behavior) - Progress endpoint now returns complete items array with status details - Results view correctly displays skipped items with error messages
97 lines
4.1 KiB
Python
97 lines
4.1 KiB
Python
"""Route registrar for recipe endpoints."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from dataclasses import dataclass
|
|
from typing import Callable, Mapping
|
|
|
|
from aiohttp import web
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class RouteDefinition:
|
|
"""Declarative definition for a recipe HTTP route."""
|
|
|
|
method: str
|
|
path: str
|
|
handler_name: str
|
|
|
|
|
|
ROUTE_DEFINITIONS: tuple[RouteDefinition, ...] = (
|
|
RouteDefinition("GET", "/loras/recipes", "render_page"),
|
|
RouteDefinition("GET", "/api/lm/recipes", "list_recipes"),
|
|
RouteDefinition("GET", "/api/lm/recipe/{recipe_id}", "get_recipe"),
|
|
RouteDefinition("GET", "/api/lm/recipes/import-remote", "import_remote_recipe"),
|
|
RouteDefinition("POST", "/api/lm/recipes/analyze-image", "analyze_uploaded_image"),
|
|
RouteDefinition(
|
|
"POST", "/api/lm/recipes/analyze-local-image", "analyze_local_image"
|
|
),
|
|
RouteDefinition("POST", "/api/lm/recipes/save", "save_recipe"),
|
|
RouteDefinition("DELETE", "/api/lm/recipe/{recipe_id}", "delete_recipe"),
|
|
RouteDefinition("GET", "/api/lm/recipes/top-tags", "get_top_tags"),
|
|
RouteDefinition("GET", "/api/lm/recipes/base-models", "get_base_models"),
|
|
RouteDefinition("GET", "/api/lm/recipes/roots", "get_roots"),
|
|
RouteDefinition("GET", "/api/lm/recipes/folders", "get_folders"),
|
|
RouteDefinition("GET", "/api/lm/recipes/folder-tree", "get_folder_tree"),
|
|
RouteDefinition(
|
|
"GET", "/api/lm/recipes/unified-folder-tree", "get_unified_folder_tree"
|
|
),
|
|
RouteDefinition("GET", "/api/lm/recipe/{recipe_id}/share", "share_recipe"),
|
|
RouteDefinition(
|
|
"GET", "/api/lm/recipe/{recipe_id}/share/download", "download_shared_recipe"
|
|
),
|
|
RouteDefinition("GET", "/api/lm/recipe/{recipe_id}/syntax", "get_recipe_syntax"),
|
|
RouteDefinition("PUT", "/api/lm/recipe/{recipe_id}/update", "update_recipe"),
|
|
RouteDefinition("POST", "/api/lm/recipe/move", "move_recipe"),
|
|
RouteDefinition("POST", "/api/lm/recipes/move-bulk", "move_recipes_bulk"),
|
|
RouteDefinition("POST", "/api/lm/recipe/lora/reconnect", "reconnect_lora"),
|
|
RouteDefinition("GET", "/api/lm/recipes/find-duplicates", "find_duplicates"),
|
|
RouteDefinition("POST", "/api/lm/recipes/bulk-delete", "bulk_delete"),
|
|
RouteDefinition(
|
|
"POST", "/api/lm/recipes/save-from-widget", "save_recipe_from_widget"
|
|
),
|
|
RouteDefinition("GET", "/api/lm/recipes/for-lora", "get_recipes_for_lora"),
|
|
RouteDefinition("GET", "/api/lm/recipes/scan", "scan_recipes"),
|
|
RouteDefinition("POST", "/api/lm/recipes/repair", "repair_recipes"),
|
|
RouteDefinition("POST", "/api/lm/recipes/cancel-repair", "cancel_repair"),
|
|
RouteDefinition("POST", "/api/lm/recipe/{recipe_id}/repair", "repair_recipe"),
|
|
RouteDefinition("GET", "/api/lm/recipes/repair-progress", "get_repair_progress"),
|
|
RouteDefinition("POST", "/api/lm/recipes/batch-import/start", "start_batch_import"),
|
|
RouteDefinition(
|
|
"GET", "/api/lm/recipes/batch-import/progress", "get_batch_import_progress"
|
|
),
|
|
RouteDefinition(
|
|
"POST", "/api/lm/recipes/batch-import/cancel", "cancel_batch_import"
|
|
),
|
|
RouteDefinition(
|
|
"POST", "/api/lm/recipes/batch-import/directory", "start_directory_import"
|
|
),
|
|
RouteDefinition("POST", "/api/lm/recipes/browse-directory", "browse_directory"),
|
|
)
|
|
|
|
|
|
class RecipeRouteRegistrar:
|
|
"""Bind declarative recipe definitions to an aiohttp router."""
|
|
|
|
_METHOD_MAP = {
|
|
"GET": "add_get",
|
|
"POST": "add_post",
|
|
"PUT": "add_put",
|
|
"DELETE": "add_delete",
|
|
}
|
|
|
|
def __init__(self, app: web.Application) -> None:
|
|
self._app = app
|
|
|
|
def register_routes(
|
|
self, handler_lookup: Mapping[str, Callable[[web.Request], object]]
|
|
) -> None:
|
|
for definition in ROUTE_DEFINITIONS:
|
|
handler = handler_lookup[definition.handler_name]
|
|
self._bind_route(definition.method, definition.path, handler)
|
|
|
|
def _bind_route(self, method: str, path: str, handler: Callable) -> None:
|
|
add_method_name = self._METHOD_MAP[method.upper()]
|
|
add_method = getattr(self._app.router, add_method_name)
|
|
add_method(path, handler)
|