diff --git a/py/routes/api_routes.py b/py/routes/api_routes.py index 3182dad6..71239b7b 100644 --- a/py/routes/api_routes.py +++ b/py/routes/api_routes.py @@ -10,7 +10,6 @@ from ..nodes.utils import get_lora_info from ..config import config from ..services.websocket_manager import ws_manager -from ..services.settings_manager import settings import asyncio from .update_routes import UpdateRoutes from ..utils.constants import PREVIEW_EXTENSIONS, CARD_PREVIEW_WIDTH, VALID_LORA_TYPES @@ -107,7 +106,21 @@ class ApiRoutes: """Handle CivitAI metadata fetch request""" if self.scanner is None: self.scanner = await ServiceRegistry.get_lora_scanner() - return await ModelRouteUtils.handle_fetch_civitai(request, self.scanner) + + response = await ModelRouteUtils.handle_fetch_civitai(request, self.scanner) + + # If successful, format the metadata before returning + if response.status == 200: + data = json.loads(response.body.decode('utf-8')) + if data.get("success") and data.get("metadata"): + formatted_metadata = self._format_lora_response(data["metadata"]) + return web.json_response({ + "success": True, + "metadata": formatted_metadata + }) + + # Otherwise, return the original response + return response async def replace_preview(self, request: web.Request) -> web.Response: """Handle preview image replacement request""" diff --git a/py/routes/checkpoints_routes.py b/py/routes/checkpoints_routes.py index d37aef2a..d96f5138 100644 --- a/py/routes/checkpoints_routes.py +++ b/py/routes/checkpoints_routes.py @@ -521,7 +521,20 @@ class CheckpointsRoutes: async def fetch_civitai(self, request: web.Request) -> web.Response: """Handle CivitAI metadata fetch request for checkpoints""" - return await ModelRouteUtils.handle_fetch_civitai(request, self.scanner) + response = await ModelRouteUtils.handle_fetch_civitai(request, self.scanner) + + # If successful, format the metadata before returning + if response.status == 200: + data = json.loads(response.body.decode('utf-8')) + if data.get("success") and data.get("metadata"): + formatted_metadata = self._format_checkpoint_response(data["metadata"]) + return web.json_response({ + "success": True, + "metadata": formatted_metadata + }) + + # Otherwise, return the original response + return response async def replace_preview(self, request: web.Request) -> web.Response: """Handle preview image replacement for checkpoints""" diff --git a/py/utils/routes_common.py b/py/utils/routes_common.py index 3c85877d..39484949 100644 --- a/py/utils/routes_common.py +++ b/py/utils/routes_common.py @@ -332,7 +332,7 @@ class ModelRouteUtils: scanner: The model scanner instance with cache management methods Returns: - web.Response: The HTTP response + web.Response: The HTTP response with metadata on success """ try: data = await request.json() @@ -357,7 +357,8 @@ class ModelRouteUtils: # Update the cache await scanner.update_single_model_cache(data['file_path'], data['file_path'], local_metadata) - return web.json_response({"success": True}) + # Return the updated metadata along with success status + return web.json_response({"success": True, "metadata": local_metadata}) finally: await client.close() diff --git a/static/js/api/baseModelApi.js b/static/js/api/baseModelApi.js index c2e6a7da..d0971be2 100644 --- a/static/js/api/baseModelApi.js +++ b/static/js/api/baseModelApi.js @@ -471,6 +471,11 @@ export async function refreshSingleModelMetadata(filePath, modelType = 'lora') { const data = await response.json(); if (data.success) { + // Use the returned metadata to update just this single item + if (data.metadata && state.virtualScroller) { + state.virtualScroller.updateSingleItem(filePath, data.metadata); + } + showToast('Metadata refreshed successfully', 'success'); return true; } else { diff --git a/static/js/api/checkpointApi.js b/static/js/api/checkpointApi.js index 7b9028e9..844f3228 100644 --- a/static/js/api/checkpointApi.js +++ b/static/js/api/checkpointApi.js @@ -81,11 +81,7 @@ export async function fetchCivitai() { // Refresh single checkpoint metadata export async function refreshSingleCheckpointMetadata(filePath) { - const success = await refreshSingleModelMetadata(filePath, 'checkpoint'); - if (success) { - // Reload the current view to show updated data - await resetAndReload(); - } + await refreshSingleModelMetadata(filePath, 'checkpoint'); } /** diff --git a/static/js/api/loraApi.js b/static/js/api/loraApi.js index c7421a42..d727d183 100644 --- a/static/js/api/loraApi.js +++ b/static/js/api/loraApi.js @@ -117,11 +117,7 @@ export async function refreshLoras(fullRebuild = false) { } export async function refreshSingleLoraMetadata(filePath) { - const success = await refreshSingleModelMetadata(filePath, 'lora'); - if (success) { - // Reload the current view to show updated data - await resetAndReload(); - } + await refreshSingleModelMetadata(filePath, 'lora'); } export async function fetchModelDescription(modelId, filePath) { diff --git a/static/js/utils/VirtualScroller.js b/static/js/utils/VirtualScroller.js index 9b2bb365..34a021d7 100644 --- a/static/js/utils/VirtualScroller.js +++ b/static/js/utils/VirtualScroller.js @@ -796,6 +796,39 @@ export class VirtualScroller { console.log('Virtual scroller enabled'); } + updateSingleItem(filePath, updatedItem) { + if (!filePath || !updatedItem) { + console.error('Invalid parameters for updateSingleItem'); + return false; + } + + // Find the index of the item with the matching file_path + const index = this.items.findIndex(item => item.file_path === filePath); + if (index === -1) { + console.warn(`Item with file path ${filePath} not found in virtual scroller data`); + return false; + } + + // Update the item data + this.items[index] = {...this.items[index], ...updatedItem}; + + // If the item is currently rendered, update its DOM representation + if (this.renderedItems.has(index)) { + const element = this.renderedItems.get(index); + + // Remove the old element + element.remove(); + this.renderedItems.delete(index); + + // Create and render the updated element + const updatedElement = this.createItemElement(this.items[index], index); + this.renderedItems.set(index, updatedElement); + this.gridElement.appendChild(updatedElement); + } + + return true; + } + // New method to remove an item by file path removeItemByFilePath(filePath) { if (!filePath || this.disabled || this.items.length === 0) return false;