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:
Will Miao
2026-03-19 17:15:05 +08:00
parent b11c90e19b
commit 76c15105e6
13 changed files with 1131 additions and 105 deletions

View File

@@ -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,