From 0c80555cc77f466afe1541e16ad547b4615b1535 Mon Sep 17 00:00:00 2001 From: Will Miao <13051207myq@gmail.com> Date: Sun, 26 Jan 2025 23:32:17 +0800 Subject: [PATCH] Add refresh loras --- nodes.py | 13 ++++++--- static/js/script.js | 68 ++++++++++++++++++++++++++++++++++++++------ templates/loras.html | 13 +++++++-- utils/model_utils.py | 2 +- 4 files changed, 79 insertions(+), 17 deletions(-) diff --git a/nodes.py b/nodes.py index 0edeb7cb..421bfef5 100644 --- a/nodes.py +++ b/nodes.py @@ -161,6 +161,7 @@ class LorasEndpoint: "folder": lora["folder"], "sha256": lora["sha256"], "file_path": lora["file_path"], + "modified": lora["modified"], "civitai": lora.get("civitai", {}) or {} # 确保当 civitai 为 None 时返回空字典 } except Exception as e: @@ -174,6 +175,7 @@ class LorasEndpoint: "folder": lora.get("folder", ""), "sha256": lora.get("sha256", ""), "file_path": lora.get("file_path", ""), + "modified": lora.get("modified", ""), "civitai": { "id": "", "modelId": "", @@ -289,14 +291,17 @@ class LorasEndpoint: # 更新模型名称(优先使用CivitAI名称) if 'model' in civitai_metadata: local_metadata['model_name'] = civitai_metadata['model'].get('name', local_metadata.get('model_name')) + # update base model + local_metadata['base_model'] = civitai_metadata.get('baseModel') # 4. 下载预览图 - first_image = next((img for img in civitai_metadata.get('images', []) if img.get('type') == 'image'), None) - if first_image: - preview_extension = os.path.splitext(first_image['url'])[-1] # Get the image file extension + first_preview = next((img for img in civitai_metadata.get('images', [])), None) + if first_preview: + + preview_extension = '.mp4' if first_preview['type'] == 'video' else os.path.splitext(first_preview['url'])[-1] # Get the file extension preview_filename = os.path.splitext(os.path.basename(data['file_path']))[0] + preview_extension preview_path = os.path.join(os.path.dirname(data['file_path']), preview_filename) - await client.download_preview_image(first_image['url'], preview_path) + await client.download_preview_image(first_preview['url'], preview_path) # 存储相对路径,使用正斜杠格式 local_metadata['preview_url'] = os.path.relpath(preview_path, self.loras_root).replace(os.sep, '/') diff --git a/static/js/script.js b/static/js/script.js index 3a963c11..bb4f6d3a 100644 --- a/static/js/script.js +++ b/static/js/script.js @@ -2,15 +2,13 @@ function sortCards(sortBy) { const grid = document.getElementById('loraGrid'); const cards = Array.from(grid.children); - + cards.sort((a, b) => { switch(sortBy) { case 'name': return a.dataset.name.localeCompare(b.dataset.name); case 'date': - return new Date(b.dataset.date) - new Date(a.dataset.date); - case 'size': - return parseFloat(b.dataset.size) - parseFloat(a.dataset.size); + return b.dataset.modified - a.dataset.modified; } }); @@ -19,13 +17,59 @@ function sortCards(sortBy) { // 刷新功能 async function refreshLoras() { + const loadingOverlay = document.getElementById('loading-overlay'); + const loraGrid = document.getElementById('loraGrid'); + const currentSort = document.getElementById('sortSelect').value; + const activeFolder = document.querySelector('.tag.active')?.dataset.folder; + try { + // Show loading overlay + loadingOverlay.style.display = 'flex'; + + // Fetch new data const response = await fetch('/loras?refresh=true'); - if (response.ok) { - location.reload(); + if (!response.ok) throw new Error('Refresh failed'); + + // Parse the HTML response + const parser = new DOMParser(); + const doc = parser.parseFromString(await response.text(), 'text/html'); + + // Get the new lora cards + const newLoraGrid = doc.getElementById('loraGrid'); + + // Update the grid content + loraGrid.innerHTML = newLoraGrid.innerHTML; + + // Re-attach click listeners to new cards + document.querySelectorAll('.lora-card').forEach(card => { + card.addEventListener('click', () => { + const meta = JSON.parse(card.dataset.meta || '{}'); + if (Object.keys(meta).length > 0) { + showModal(meta); + } + }); + }); + + // Re-apply current sorting + sortCards(currentSort); + + // Re-apply current folder filter if any + if (activeFolder) { + document.querySelectorAll('.lora-card').forEach(card => { + if (card.getAttribute('data-folder') === activeFolder) { + card.style.display = ''; + } else { + card.style.display = 'none'; + } + }); } + } catch (error) { console.error('Refresh failed:', error); + alert('Failed to refresh loras'); + } finally { + // Hide loading overlay + loadingOverlay.style.display = 'none'; } } @@ -94,10 +138,16 @@ async function deleteModel(fileName) { } // 初始化排序 -document.getElementById('sortSelect').addEventListener('change', (e) => { +document.getElementById('sortSelect')?.addEventListener('change', (e) => { sortCards(e.target.value); }); +// 立即执行初始排序 +const sortSelect = document.getElementById('sortSelect'); +if (sortSelect) { + sortCards(sortSelect.value); +} + // 添加搜索功能 document.getElementById('searchInput')?.addEventListener('input', (e) => { const term = e.target.value.toLowerCase(); @@ -123,9 +173,9 @@ function showModal(lora) { const modal = document.getElementById('loraModal'); modal.innerHTML = `