mirror of
https://github.com/willmiao/ComfyUI-Lora-Manager.git
synced 2026-03-27 07:58:52 -03:00
feat(lora-pool): add regex include/exclude name pattern filtering (#839)
Add name pattern filtering to LoRA Pool node allowing users to filter LoRAs by filename or model name using either plain text or regex patterns. Features: - Include patterns: only show LoRAs matching at least one pattern - Exclude patterns: exclude LoRAs matching any pattern - Regex toggle: switch between substring and regex matching - Case-insensitive matching for both modes - Invalid regex automatically falls back to substring matching - Filters apply to both file_name and model_name fields Backend: - Update LoraPoolLM._default_config() with namePatterns structure - Add name pattern filtering to _apply_pool_filters() and _apply_specific_filters() - Add API parameter parsing for name_pattern_include/exclude/use_regex - Update LoraPoolConfig type with namePatterns field Frontend: - Add NamePatternsSection.vue component with pattern input UI - Update useLoraPoolState to manage pattern state and API integration - Update LoraPoolSummaryView to display NamePatternsSection - Increase LORA_POOL_WIDGET_MIN_HEIGHT to accommodate new UI Tests: - Add 7 test cases covering text/regex include, exclude, combined filtering, model name fallback, and invalid regex handling Closes #839
This commit is contained in:
@@ -10,6 +10,11 @@ export interface LoraPoolConfig {
|
||||
noCreditRequired: boolean
|
||||
allowSelling: boolean
|
||||
}
|
||||
namePatterns: {
|
||||
include: string[]
|
||||
exclude: string[]
|
||||
useRegex: boolean
|
||||
}
|
||||
includeEmptyLora?: boolean // Optional, deprecated (moved to Cycler)
|
||||
}
|
||||
preview: { matchCount: number; lastUpdated: number }
|
||||
|
||||
@@ -62,6 +62,9 @@ export function useLoraPoolApi() {
|
||||
foldersExclude?: string[]
|
||||
noCreditRequired?: boolean
|
||||
allowSelling?: boolean
|
||||
namePatternsInclude?: string[]
|
||||
namePatternsExclude?: string[]
|
||||
namePatternsUseRegex?: boolean
|
||||
page?: number
|
||||
pageSize?: number
|
||||
}
|
||||
@@ -92,6 +95,13 @@ export function useLoraPoolApi() {
|
||||
urlParams.set('allow_selling_generated_content', String(params.allowSelling))
|
||||
}
|
||||
|
||||
// Name pattern filters
|
||||
params.namePatternsInclude?.forEach(pattern => urlParams.append('name_pattern_include', pattern))
|
||||
params.namePatternsExclude?.forEach(pattern => urlParams.append('name_pattern_exclude', pattern))
|
||||
if (params.namePatternsUseRegex !== undefined) {
|
||||
urlParams.set('name_pattern_use_regex', String(params.namePatternsUseRegex))
|
||||
}
|
||||
|
||||
const response = await fetch(`/api/lm/loras/list?${urlParams}`)
|
||||
const data = await response.json()
|
||||
|
||||
|
||||
@@ -24,6 +24,9 @@ export function useLoraPoolState(widget: ComponentWidget<LoraPoolConfig>) {
|
||||
const excludeFolders = ref<string[]>([])
|
||||
const noCreditRequired = ref(false)
|
||||
const allowSelling = ref(false)
|
||||
const includePatterns = ref<string[]>([])
|
||||
const excludePatterns = ref<string[]>([])
|
||||
const useRegex = ref(false)
|
||||
|
||||
// Available options from API
|
||||
const availableBaseModels = ref<BaseModelOption[]>([])
|
||||
@@ -52,6 +55,11 @@ export function useLoraPoolState(widget: ComponentWidget<LoraPoolConfig>) {
|
||||
license: {
|
||||
noCreditRequired: noCreditRequired.value,
|
||||
allowSelling: allowSelling.value
|
||||
},
|
||||
namePatterns: {
|
||||
include: includePatterns.value,
|
||||
exclude: excludePatterns.value,
|
||||
useRegex: useRegex.value
|
||||
}
|
||||
},
|
||||
preview: {
|
||||
@@ -94,6 +102,9 @@ export function useLoraPoolState(widget: ComponentWidget<LoraPoolConfig>) {
|
||||
updateIfChanged(excludeFolders, filters.folders?.exclude || [])
|
||||
updateIfChanged(noCreditRequired, filters.license?.noCreditRequired ?? false)
|
||||
updateIfChanged(allowSelling, filters.license?.allowSelling ?? false)
|
||||
updateIfChanged(includePatterns, filters.namePatterns?.include || [])
|
||||
updateIfChanged(excludePatterns, filters.namePatterns?.exclude || [])
|
||||
updateIfChanged(useRegex, filters.namePatterns?.useRegex ?? false)
|
||||
|
||||
// matchCount doesn't trigger watchers, so direct assignment is fine
|
||||
matchCount.value = preview?.matchCount || 0
|
||||
@@ -125,6 +136,9 @@ export function useLoraPoolState(widget: ComponentWidget<LoraPoolConfig>) {
|
||||
foldersExclude: excludeFolders.value,
|
||||
noCreditRequired: noCreditRequired.value || undefined,
|
||||
allowSelling: allowSelling.value || undefined,
|
||||
namePatternsInclude: includePatterns.value,
|
||||
namePatternsExclude: excludePatterns.value,
|
||||
namePatternsUseRegex: useRegex.value,
|
||||
pageSize: 6
|
||||
})
|
||||
|
||||
@@ -150,7 +164,10 @@ export function useLoraPoolState(widget: ComponentWidget<LoraPoolConfig>) {
|
||||
includeFolders,
|
||||
excludeFolders,
|
||||
noCreditRequired,
|
||||
allowSelling
|
||||
allowSelling,
|
||||
includePatterns,
|
||||
excludePatterns,
|
||||
useRegex
|
||||
], onFilterChange, { deep: true })
|
||||
|
||||
return {
|
||||
@@ -162,6 +179,9 @@ export function useLoraPoolState(widget: ComponentWidget<LoraPoolConfig>) {
|
||||
excludeFolders,
|
||||
noCreditRequired,
|
||||
allowSelling,
|
||||
includePatterns,
|
||||
excludePatterns,
|
||||
useRegex,
|
||||
|
||||
// Available options
|
||||
availableBaseModels,
|
||||
|
||||
Reference in New Issue
Block a user