mirror of
https://github.com/willmiao/ComfyUI-Lora-Manager.git
synced 2026-03-24 22:52:12 -03:00
Add filters - base model only for now
This commit is contained in:
@@ -121,6 +121,10 @@ class ApiRoutes:
|
|||||||
fuzzy = request.query.get('fuzzy', 'false').lower() == 'true'
|
fuzzy = request.query.get('fuzzy', 'false').lower() == 'true'
|
||||||
recursive = request.query.get('recursive', 'false').lower() == 'true'
|
recursive = request.query.get('recursive', 'false').lower() == 'true'
|
||||||
|
|
||||||
|
# Parse base models filter parameter
|
||||||
|
base_models = request.query.get('base_models', '').split(',')
|
||||||
|
base_models = [model.strip() for model in base_models if model.strip()]
|
||||||
|
|
||||||
# Validate parameters
|
# Validate parameters
|
||||||
if page < 1 or page_size < 1 or page_size > 100:
|
if page < 1 or page_size < 1 or page_size > 100:
|
||||||
return web.json_response({
|
return web.json_response({
|
||||||
@@ -132,7 +136,7 @@ class ApiRoutes:
|
|||||||
'error': 'Invalid sort parameter'
|
'error': 'Invalid sort parameter'
|
||||||
}, status=400)
|
}, status=400)
|
||||||
|
|
||||||
# Get paginated data with search
|
# Get paginated data with search and filters
|
||||||
result = await self.scanner.get_paginated_data(
|
result = await self.scanner.get_paginated_data(
|
||||||
page=page,
|
page=page,
|
||||||
page_size=page_size,
|
page_size=page_size,
|
||||||
@@ -140,7 +144,8 @@ class ApiRoutes:
|
|||||||
folder=folder,
|
folder=folder,
|
||||||
search=search,
|
search=search,
|
||||||
fuzzy=fuzzy,
|
fuzzy=fuzzy,
|
||||||
recursive=recursive # 添加递归参数
|
recursive=recursive,
|
||||||
|
base_models=base_models # Pass base models filter
|
||||||
)
|
)
|
||||||
|
|
||||||
# Format the response data
|
# Format the response data
|
||||||
|
|||||||
@@ -148,7 +148,7 @@ class LoraScanner:
|
|||||||
|
|
||||||
async def get_paginated_data(self, page: int, page_size: int, sort_by: str = 'name',
|
async def get_paginated_data(self, page: int, page_size: int, sort_by: str = 'name',
|
||||||
folder: str = None, search: str = None, fuzzy: bool = False,
|
folder: str = None, search: str = None, fuzzy: bool = False,
|
||||||
recursive: bool = False):
|
recursive: bool = False, base_models: list = None):
|
||||||
"""Get paginated and filtered lora data
|
"""Get paginated and filtered lora data
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@@ -159,6 +159,7 @@ class LoraScanner:
|
|||||||
search: Search term
|
search: Search term
|
||||||
fuzzy: Use fuzzy matching for search
|
fuzzy: Use fuzzy matching for search
|
||||||
recursive: Include subfolders when folder filter is applied
|
recursive: Include subfolders when folder filter is applied
|
||||||
|
base_models: List of base models to filter by
|
||||||
"""
|
"""
|
||||||
cache = await self.get_cached_data()
|
cache = await self.get_cached_data()
|
||||||
|
|
||||||
@@ -180,6 +181,13 @@ class LoraScanner:
|
|||||||
if item['folder'] == folder
|
if item['folder'] == folder
|
||||||
]
|
]
|
||||||
|
|
||||||
|
# Apply base model filtering
|
||||||
|
if base_models and len(base_models) > 0:
|
||||||
|
filtered_data = [
|
||||||
|
item for item in filtered_data
|
||||||
|
if item.get('base_model') in base_models
|
||||||
|
]
|
||||||
|
|
||||||
# 应用搜索过滤
|
# 应用搜索过滤
|
||||||
if search:
|
if search:
|
||||||
if fuzzy:
|
if fuzzy:
|
||||||
|
|||||||
@@ -2,10 +2,10 @@ from typing import Optional
|
|||||||
|
|
||||||
# Base model mapping based on version string
|
# Base model mapping based on version string
|
||||||
BASE_MODEL_MAPPING = {
|
BASE_MODEL_MAPPING = {
|
||||||
"sd-v1-5": "SD1.5",
|
"sd-v1-5": "SD 1.5",
|
||||||
"sd-v2-1": "SD2.1",
|
"sd-v2-1": "SD 2.1",
|
||||||
"sdxl": "SDXL",
|
"sdxl": "SDXL 1.0",
|
||||||
"sd-v2": "SD2.0",
|
"sd-v2": "SD 2.0",
|
||||||
"flux1": "Flux.1 D",
|
"flux1": "Flux.1 D",
|
||||||
"flux.1 d": "Flux.1 D",
|
"flux.1 d": "Flux.1 D",
|
||||||
"illustrious": "IL",
|
"illustrious": "IL",
|
||||||
|
|||||||
@@ -438,6 +438,10 @@
|
|||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: all 0.2s ease;
|
transition: all 0.2s ease;
|
||||||
|
user-select: none; /* Prevent text selection */
|
||||||
|
-webkit-user-select: none; /* For Safari */
|
||||||
|
-moz-user-select: none; /* For Firefox */
|
||||||
|
-ms-user-select: none; /* For IE/Edge */
|
||||||
}
|
}
|
||||||
|
|
||||||
.filter-tag:hover {
|
.filter-tag:hover {
|
||||||
@@ -467,42 +471,28 @@
|
|||||||
/* Filter actions */
|
/* Filter actions */
|
||||||
.filter-actions {
|
.filter-actions {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: center;
|
||||||
margin-top: 16px;
|
margin-top: 16px;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.clear-filters-btn,
|
|
||||||
.apply-filters-btn {
|
|
||||||
padding: 6px 12px;
|
|
||||||
border-radius: var(--border-radius-sm);
|
|
||||||
font-size: 14px;
|
|
||||||
cursor: pointer;
|
|
||||||
transition: background-color 0.2s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
.clear-filters-btn {
|
.clear-filters-btn {
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
color: var(--text-color);
|
color: var(--text-color);
|
||||||
border: 1px solid var(--border-color);
|
border: 1px solid var(--border-color);
|
||||||
flex: 1;
|
padding: 6px 12px;
|
||||||
|
border-radius: var(--border-radius-sm);
|
||||||
|
font-size: 14px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background-color 0.2s ease;
|
||||||
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.clear-filters-btn:hover {
|
.clear-filters-btn:hover {
|
||||||
background-color: var(--lora-surface-hover);
|
background-color: var(--lora-surface-hover);
|
||||||
}
|
}
|
||||||
|
|
||||||
.apply-filters-btn {
|
/* Remove apply-filters-btn styles since we no longer need it */
|
||||||
background-color: var(--lora-accent);
|
|
||||||
color: white;
|
|
||||||
border: 1px solid var(--lora-accent);
|
|
||||||
flex: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.apply-filters-btn:hover {
|
|
||||||
background-color: var(--lora-accent-hover, var(--lora-accent));
|
|
||||||
filter: brightness(1.1);
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: 768px) {
|
@media (max-width: 768px) {
|
||||||
.actions {
|
.actions {
|
||||||
|
|||||||
@@ -31,6 +31,12 @@ export async function loadMoreLoras(boolUpdateFolders = false) {
|
|||||||
params.append('fuzzy', 'true');
|
params.append('fuzzy', 'true');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add filter parameters if active
|
||||||
|
if (state.filters && state.filters.baseModel && state.filters.baseModel.length > 0) {
|
||||||
|
// Convert the array of base models to a comma-separated string
|
||||||
|
params.append('base_models', state.filters.baseModel.join(','));
|
||||||
|
}
|
||||||
|
|
||||||
console.log('Loading loras with params:', params.toString());
|
console.log('Loading loras with params:', params.toString());
|
||||||
|
|
||||||
const response = await fetch(`/api/loras?${params}`);
|
const response = await fetch(`/api/loras?${params}`);
|
||||||
|
|||||||
@@ -55,6 +55,12 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
modalManager.initialize(); // Initialize modalManager after DOM is loaded
|
modalManager.initialize(); // Initialize modalManager after DOM is loaded
|
||||||
window.downloadManager = new DownloadManager(); // Move this after modalManager initialization
|
window.downloadManager = new DownloadManager(); // Move this after modalManager initialization
|
||||||
window.filterManager = new FilterManager(); // Initialize filter manager
|
window.filterManager = new FilterManager(); // Initialize filter manager
|
||||||
|
|
||||||
|
// Initialize state filters from filterManager if available
|
||||||
|
if (window.filterManager && window.filterManager.filters) {
|
||||||
|
state.filters = { ...window.filterManager.filters };
|
||||||
|
}
|
||||||
|
|
||||||
initializeInfiniteScroll();
|
initializeInfiniteScroll();
|
||||||
initializeEventListeners();
|
initializeEventListeners();
|
||||||
lazyLoadImages();
|
lazyLoadImages();
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { BASE_MODELS, BASE_MODEL_CLASSES } from '../utils/constants.js';
|
import { BASE_MODELS, BASE_MODEL_CLASSES } from '../utils/constants.js';
|
||||||
import { state } from '../state/index.js';
|
import { state } from '../state/index.js';
|
||||||
import { showToast } from '../utils/uiHelpers.js';
|
import { showToast } from '../utils/uiHelpers.js';
|
||||||
|
import { resetAndReload } from '../api/loraApi.js';
|
||||||
|
|
||||||
export class FilterManager {
|
export class FilterManager {
|
||||||
constructor() {
|
constructor() {
|
||||||
@@ -45,8 +46,8 @@ export class FilterManager {
|
|||||||
tag.dataset.baseModel = value;
|
tag.dataset.baseModel = value;
|
||||||
tag.innerHTML = value;
|
tag.innerHTML = value;
|
||||||
|
|
||||||
// Add click handler to toggle selection
|
// Add click handler to toggle selection and automatically apply
|
||||||
tag.addEventListener('click', () => {
|
tag.addEventListener('click', async () => {
|
||||||
tag.classList.toggle('active');
|
tag.classList.toggle('active');
|
||||||
|
|
||||||
if (tag.classList.contains('active')) {
|
if (tag.classList.contains('active')) {
|
||||||
@@ -58,6 +59,9 @@ export class FilterManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.updateActiveFiltersCount();
|
this.updateActiveFiltersCount();
|
||||||
|
|
||||||
|
// Auto-apply filter when tag is clicked
|
||||||
|
await this.applyFilters(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
baseModelTagsContainer.appendChild(tag);
|
baseModelTagsContainer.appendChild(tag);
|
||||||
@@ -101,30 +105,39 @@ export class FilterManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
applyFilters() {
|
async applyFilters(showToastNotification = true) {
|
||||||
// Save filters to localStorage
|
// Save filters to localStorage
|
||||||
localStorage.setItem('loraFilters', JSON.stringify(this.filters));
|
localStorage.setItem('loraFilters', JSON.stringify(this.filters));
|
||||||
|
|
||||||
// Apply filters to cards (will be implemented later)
|
// Update state with current filters
|
||||||
showToast('Filters applied', 'success');
|
state.filters = { ...this.filters };
|
||||||
|
|
||||||
// Close the filter panel
|
// Reload loras with filters applied
|
||||||
this.closeFilterPanel();
|
await resetAndReload();
|
||||||
|
|
||||||
// Update filter button to show active state
|
// Update filter button to show active state
|
||||||
if (this.hasActiveFilters()) {
|
if (this.hasActiveFilters()) {
|
||||||
this.filterButton.classList.add('active');
|
this.filterButton.classList.add('active');
|
||||||
|
if (showToastNotification) {
|
||||||
|
showToast(`Filtering by ${this.filters.baseModel.length} base models`, 'success');
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
this.filterButton.classList.remove('active');
|
this.filterButton.classList.remove('active');
|
||||||
|
if (showToastNotification) {
|
||||||
|
showToast('Filters cleared', 'info');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
clearFilters() {
|
async clearFilters() {
|
||||||
// Clear all filters
|
// Clear all filters
|
||||||
this.filters = {
|
this.filters = {
|
||||||
baseModel: []
|
baseModel: []
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Update state
|
||||||
|
state.filters = { ...this.filters };
|
||||||
|
|
||||||
// Update UI
|
// Update UI
|
||||||
this.updateTagSelections();
|
this.updateTagSelections();
|
||||||
this.updateActiveFiltersCount();
|
this.updateActiveFiltersCount();
|
||||||
@@ -132,8 +145,9 @@ export class FilterManager {
|
|||||||
// Remove from localStorage
|
// Remove from localStorage
|
||||||
localStorage.removeItem('loraFilters');
|
localStorage.removeItem('loraFilters');
|
||||||
|
|
||||||
|
// Update UI and reload data
|
||||||
this.filterButton.classList.remove('active');
|
this.filterButton.classList.remove('active');
|
||||||
showToast('All filters cleared', 'info');
|
await resetAndReload();
|
||||||
}
|
}
|
||||||
|
|
||||||
loadFiltersFromStorage() {
|
loadFiltersFromStorage() {
|
||||||
|
|||||||
@@ -1,24 +1,90 @@
|
|||||||
export const BASE_MODELS = {
|
export const BASE_MODELS = {
|
||||||
SD_1_5: "SD1.5",
|
// Stable Diffusion 1.x models
|
||||||
SD_2_0: "SD2.0",
|
SD_1_4: "SD 1.4",
|
||||||
SD_2_1: "SD2.1",
|
SD_1_5: "SD 1.5",
|
||||||
SDXL: "SDXL",
|
SD_1_5_LCM: "SD 1.5 LCM",
|
||||||
|
SD_1_5_HYPER: "SD 1.5 Hyper",
|
||||||
|
|
||||||
|
// Stable Diffusion 2.x models
|
||||||
|
SD_2_0: "SD 2.0",
|
||||||
|
SD_2_1: "SD 2.1",
|
||||||
|
|
||||||
|
// Stable Diffusion 3.x models
|
||||||
|
SD_3: "SD 3",
|
||||||
|
SD_3_5: "SD 3.5",
|
||||||
|
SD_3_5_MEDIUM: "SD 3.5 Medium",
|
||||||
|
SD_3_5_LARGE: "SD 3.5 Large",
|
||||||
|
SD_3_5_LARGE_TURBO: "SD 3.5 Large Turbo",
|
||||||
|
|
||||||
|
// SDXL models
|
||||||
|
SDXL: "SDXL 1.0",
|
||||||
|
SDXL_LIGHTNING: "SDXL Lightning",
|
||||||
|
SDXL_HYPER: "SDXL Hyper",
|
||||||
|
|
||||||
|
// Other models
|
||||||
FLUX_1_D: "Flux.1 D",
|
FLUX_1_D: "Flux.1 D",
|
||||||
|
FLUX_1_S: "Flux.1 S",
|
||||||
|
AURAFLOW: "AuraFlow",
|
||||||
|
PIXART_A: "PixArt a",
|
||||||
|
PIXART_E: "PixArt E",
|
||||||
|
HUNYUAN_1: "Hunyuan 1",
|
||||||
|
LUMINA: "Lumina",
|
||||||
|
KOLORS: "Kolors",
|
||||||
|
NOOBAI: "NoobAI",
|
||||||
IL: "IL",
|
IL: "IL",
|
||||||
PONY: "Pony",
|
PONY: "Pony",
|
||||||
|
|
||||||
|
// Video models
|
||||||
|
SVD: "SVD",
|
||||||
|
WAN_VIDEO: "Wan Video",
|
||||||
HUNYUAN_VIDEO: "Hunyuan Video",
|
HUNYUAN_VIDEO: "Hunyuan Video",
|
||||||
|
|
||||||
|
// Default
|
||||||
UNKNOWN: "Unknown"
|
UNKNOWN: "Unknown"
|
||||||
};
|
};
|
||||||
|
|
||||||
// Base model display names and their corresponding class names (for styling)
|
// Base model display names and their corresponding class names (for styling)
|
||||||
export const BASE_MODEL_CLASSES = {
|
export const BASE_MODEL_CLASSES = {
|
||||||
|
// Stable Diffusion 1.x models
|
||||||
|
[BASE_MODELS.SD_1_4]: "sd-1-4",
|
||||||
[BASE_MODELS.SD_1_5]: "sd-1-5",
|
[BASE_MODELS.SD_1_5]: "sd-1-5",
|
||||||
|
[BASE_MODELS.SD_1_5_LCM]: "sd-1-5-lcm",
|
||||||
|
[BASE_MODELS.SD_1_5_HYPER]: "sd-1-5-hyper",
|
||||||
|
|
||||||
|
// Stable Diffusion 2.x models
|
||||||
[BASE_MODELS.SD_2_0]: "sd-2-0",
|
[BASE_MODELS.SD_2_0]: "sd-2-0",
|
||||||
[BASE_MODELS.SD_2_1]: "sd-2-1",
|
[BASE_MODELS.SD_2_1]: "sd-2-1",
|
||||||
|
|
||||||
|
// Stable Diffusion 3.x models
|
||||||
|
[BASE_MODELS.SD_3]: "sd-3",
|
||||||
|
[BASE_MODELS.SD_3_5]: "sd-3-5",
|
||||||
|
[BASE_MODELS.SD_3_5_MEDIUM]: "sd-3-5-medium",
|
||||||
|
[BASE_MODELS.SD_3_5_LARGE]: "sd-3-5-large",
|
||||||
|
[BASE_MODELS.SD_3_5_LARGE_TURBO]: "sd-3-5-large-turbo",
|
||||||
|
|
||||||
|
// SDXL models
|
||||||
[BASE_MODELS.SDXL]: "sdxl",
|
[BASE_MODELS.SDXL]: "sdxl",
|
||||||
[BASE_MODELS.FLUX_1_D]: "flux",
|
[BASE_MODELS.SDXL_LIGHTNING]: "sdxl-lightning",
|
||||||
|
[BASE_MODELS.SDXL_HYPER]: "sdxl-hyper",
|
||||||
|
|
||||||
|
// Video models
|
||||||
|
[BASE_MODELS.SVD]: "svd",
|
||||||
|
[BASE_MODELS.WAN_VIDEO]: "wan-video",
|
||||||
|
[BASE_MODELS.HUNYUAN_VIDEO]: "hunyuan-video",
|
||||||
|
|
||||||
|
// Other models
|
||||||
|
[BASE_MODELS.FLUX_1_D]: "flux-d",
|
||||||
|
[BASE_MODELS.FLUX_1_S]: "flux-s",
|
||||||
|
[BASE_MODELS.AURAFLOW]: "auraflow",
|
||||||
|
[BASE_MODELS.PIXART_A]: "pixart-a",
|
||||||
|
[BASE_MODELS.PIXART_E]: "pixart-e",
|
||||||
|
[BASE_MODELS.HUNYUAN_1]: "hunyuan-1",
|
||||||
|
[BASE_MODELS.LUMINA]: "lumina",
|
||||||
|
[BASE_MODELS.KOLORS]: "kolors",
|
||||||
|
[BASE_MODELS.NOOBAI]: "noobai",
|
||||||
[BASE_MODELS.IL]: "il",
|
[BASE_MODELS.IL]: "il",
|
||||||
[BASE_MODELS.PONY]: "pony",
|
[BASE_MODELS.PONY]: "pony",
|
||||||
[BASE_MODELS.HUNYUAN_VIDEO]: "hunyuan",
|
|
||||||
|
// Default
|
||||||
[BASE_MODELS.UNKNOWN]: "unknown"
|
[BASE_MODELS.UNKNOWN]: "unknown"
|
||||||
};
|
};
|
||||||
@@ -61,8 +61,5 @@
|
|||||||
<button class="clear-filters-btn" onclick="filterManager.clearFilters()">
|
<button class="clear-filters-btn" onclick="filterManager.clearFilters()">
|
||||||
Clear All Filters
|
Clear All Filters
|
||||||
</button>
|
</button>
|
||||||
<button class="apply-filters-btn" onclick="filterManager.applyFilters()">
|
|
||||||
Apply Filters
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
Reference in New Issue
Block a user