refactor: move No LoRA feature from LoRA Pool to Lora Cycler widget

Move the 'empty/no LoRA' cycling functionality from the LoRA Pool node
to the Lora Cycler widget for cleaner architecture:

Frontend changes:
- Add include_no_lora field to CyclerConfig interface
- Add includeNoLora state and logic to useLoraCyclerState composable
- Add toggle UI in LoraCyclerSettingsView with special styling
- Show 'No LoRA' entry in LoraListModal when enabled
- Update LoraCyclerWidget to integrate new logic

Backend changes:
- lora_cycler.py reads include_no_lora from config
- Calculate effective_total_count (actual count + 1 when enabled)
- Return empty lora_stack when on No LoRA position
- Return actual LoRA count in total_count (not effective count)

Reverted files to pre-PR state:
- lora_loader.py, lora_pool.py, lora_randomizer.py, lora_stacker.py
- lora_routes.py, lora_service.py
- LoraPoolWidget.vue and related files

Related to PR #861

Co-authored-by: dogatech <dogatech@dogatech.home>
This commit is contained in:
Will Miao
2026-03-19 14:19:49 +08:00
parent 8dd849892d
commit 1ae1b0d607
22 changed files with 459 additions and 316 deletions

View File

@@ -62,17 +62,6 @@ class LoraService(BaseModelService):
if first_letter:
data = self._filter_by_first_letter(data, first_letter)
if kwargs.get("include_empty_lora"):
data.append({
"file_name": "None",
"model_name": "None",
"file_path": "",
"folder": "",
"base_model": "",
"tags": [],
"civitai": {},
})
return data
def _filter_by_first_letter(self, data: List[Dict], letter: str) -> List[Dict]:
@@ -414,7 +403,7 @@ class LoraService(BaseModelService):
"""
from .model_query import FilterCriteria
filter_section = pool_config.get("filters", pool_config)
filter_section = pool_config
# Extract filter parameters
selected_base_models = filter_section.get("baseModels", [])
@@ -427,7 +416,6 @@ class LoraService(BaseModelService):
license_dict = filter_section.get("license", {})
no_credit_required = license_dict.get("noCreditRequired", False)
allow_selling = license_dict.get("allowSelling", False)
include_empty_lora = filter_section.get("includeEmptyLora", False)
# Build tag filters dict
tag_filters = {}
@@ -497,18 +485,6 @@ class LoraService(BaseModelService):
if bool(lora.get("license_flags", 127) & (1 << 1))
]
if include_empty_lora:
available_loras.append({
"file_name": "None",
"model_name": "None",
"file_path": "",
"folder": "",
"base_model": "",
"tags": [],
"civitai": {},
})
return available_loras
async def get_cycler_list(