diff --git a/routes/lora_routes.py b/routes/lora_routes.py index 350e785a..9eef5716 100644 --- a/routes/lora_routes.py +++ b/routes/lora_routes.py @@ -48,28 +48,12 @@ class LoraRoutes: async def handle_loras_page(self, request: web.Request) -> web.Response: """Handle GET /loras request""" try: - # Get cached data + # Get cached data for folders only cache = await self.scanner.get_cached_data() - # Get initial data (first page only) - initial_data = await self.scanner.get_paginated_data( - page=1, - page_size=20, - sort_by='name' - ) - - formatted_loras = [ - self.format_lora_data(l) - for l in initial_data['items'] - ] - - # Render template + # Render template with folders only template = self.template_env.get_template('loras.html') - rendered = template.render( - loras=formatted_loras, - folders=cache.folders, - total_items=initial_data['total'] - ) + rendered = template.render(folders=cache.folders) return web.Response( text=rendered, diff --git a/services/lora_scanner.py b/services/lora_scanner.py index b055cc64..c5f5ac7e 100644 --- a/services/lora_scanner.py +++ b/services/lora_scanner.py @@ -13,11 +13,30 @@ logger = logging.getLogger(__name__) class LoraScanner: """Service for scanning and managing LoRA files""" - + + _instance = None + _lock = asyncio.Lock() + + def __new__(cls): + if cls._instance is None: + cls._instance = super().__new__(cls) + return cls._instance + def __init__(self): - self._cache: Optional[LoraCache] = None - self._initialization_lock = asyncio.Lock() - self._initialization_task: Optional[asyncio.Task] = None + # 确保初始化只执行一次 + if not hasattr(self, '_initialized'): + self._cache: Optional[LoraCache] = None + self._initialization_lock = asyncio.Lock() + self._initialization_task: Optional[asyncio.Task] = None + self._initialized = True + + @classmethod + async def get_instance(cls): + """Get singleton instance with async support""" + async with cls._lock: + if cls._instance is None: + cls._instance = cls() + return cls._instance async def get_cached_data(self, force_refresh: bool = False) -> LoraCache: """Get cached LoRA data, refresh if needed""" diff --git a/static/js/script.js b/static/js/script.js index 069152f1..ec6b6b51 100644 --- a/static/js/script.js +++ b/static/js/script.js @@ -8,28 +8,7 @@ function debounce(func, wait) { } // Sorting functionality -function sortCards(sortBy) { - const grid = document.getElementById('loraGrid'); - if (!grid) return; - - const fragment = document.createDocumentFragment(); - const cards = Array.from(grid.children); - - requestAnimationFrame(() => { - cards.sort((a, b) => sortBy === 'date' - ? parseFloat(b.dataset.modified) - parseFloat(a.dataset.modified) - : a.dataset.name.localeCompare(b.dataset.name) - ).forEach(card => fragment.appendChild(card)); - - grid.appendChild(fragment); - }); -} - -// 立即执行初始排序 -const sortSelect = document.getElementById('sortSelect'); -if (sortSelect) { - sortCards(sortSelect.value); -} +// function sortCards(sortBy) { ... } // Loading management class LoadingManager { @@ -264,14 +243,12 @@ function initializeEventListeners() { sortSelect.value = state.sortBy; sortSelect.addEventListener('change', async (e) => { state.sortBy = e.target.value; - await resetAndReload(); + await resetAndReload(); // 直接重新从后端加载已排序的数据 }); } // Folder filter handler document.querySelectorAll('.folder-tags .tag').forEach(tag => { - // 移除原有的 onclick 属性处理方式,改用事件监听器 - tag.removeAttribute('onclick'); tag.addEventListener('click', toggleFolder); }); } @@ -562,7 +539,8 @@ document.addEventListener('DOMContentLoaded', () => { }); document.getElementById('sortSelect')?.addEventListener('change', e => { - sortCards(e.target.value); + // 移除这个函数 + // sortCards(e.target.value); }); lazyLoadImages();