mirror of
https://github.com/willmiao/ComfyUI-Lora-Manager.git
synced 2026-08-06 22:10:14 -03:00
feat(lora-info): add Lora Info display node
Add a pure frontend node that shows filename and editable notes for a selected LoRA. Connect any output from a LoRA Loader/Stacker/Randomizer/ WanVideoSelect to the lora_source input — selecting a LoRA in the source widget updates the info display automatically. - Python node (LoraInfoLM): display-only, no workflow execution - Vue widget: filename label, auto-sizing notes textarea, save button with ComfyUI toast feedback on save - Frontend extension: wire-based selection propagation with stale-response race guard; clears display on wire disconnect - Backend: get-notes endpoint now returns file_path alongside notes; matching supports full-path lora syntax; fix NoneType crash in trigger words endpoint; document cache file_name invariant - Wired into all four lora widget nodes (Loader, Stacker, Randomizer, WanVideoSelect)
This commit is contained in:
@@ -955,13 +955,21 @@ class BaseModelService(ABC):
|
||||
|
||||
return unified_tree
|
||||
|
||||
async def get_model_notes(self, model_name: str) -> Optional[str]:
|
||||
"""Get notes for a specific model file"""
|
||||
async def get_model_notes(self, model_name: str) -> Optional[dict]:
|
||||
"""Get notes and file_path for a specific model file.
|
||||
|
||||
Supports both simple names (``OWSMianne_ANIMA_V1``) and full-path
|
||||
syntax (``Anima/character/OWSMianne_ANIMA_V1``).
|
||||
"""
|
||||
cache = await self.scanner.get_cached_data()
|
||||
|
||||
for model in cache.raw_data:
|
||||
if model["file_name"] == model_name:
|
||||
return model.get("notes", "")
|
||||
file_name = model.get("file_name", "")
|
||||
if file_name == model_name or model_name.endswith("/" + file_name) or model_name.endswith("\\" + file_name):
|
||||
return {
|
||||
"notes": model.get("notes", ""),
|
||||
"file_path": model.get("file_path", ""),
|
||||
}
|
||||
|
||||
return None
|
||||
|
||||
|
||||
@@ -271,12 +271,16 @@ class LoraService(BaseModelService):
|
||||
return letters
|
||||
|
||||
async def get_lora_trigger_words(self, lora_name: str) -> List[str]:
|
||||
"""Get trigger words for a specific LoRA file"""
|
||||
"""Get trigger words for a specific LoRA file.
|
||||
|
||||
Supports both simple names and full-path syntax.
|
||||
"""
|
||||
cache = await self.scanner.get_cached_data()
|
||||
|
||||
for lora in cache.raw_data:
|
||||
if lora["file_name"] == lora_name:
|
||||
civitai_data = lora.get("civitai", {})
|
||||
file_name = lora.get("file_name", "")
|
||||
if file_name == lora_name or lora_name.endswith("/" + file_name) or lora_name.endswith("\\" + file_name):
|
||||
civitai_data = lora.get("civitai") or {}
|
||||
return civitai_data.get("trainedWords", [])
|
||||
|
||||
return []
|
||||
|
||||
@@ -227,6 +227,11 @@ class ModelScanner:
|
||||
|
||||
entry: Dict[str, Any] = {
|
||||
'file_path': normalized_path,
|
||||
# file_name is always stored WITHOUT extension (e.g. "OWSMianne_ANIMA_V1",
|
||||
# not "OWSMianne_ANIMA_V1.safetensors"). All upstream population points
|
||||
# (MetadataManager, from_civitai_info, download manager, etc.) strip the
|
||||
# extension via os.path.splitext before writing. Code consuming this field
|
||||
# should match against names that are likewise extension-free.
|
||||
'file_name': get_value('file_name', '') or '',
|
||||
'model_name': get_value('model_name', '') or '',
|
||||
'folder': normalized_folder,
|
||||
|
||||
Reference in New Issue
Block a user