Remote-aware LoRA Manager nodes that fetch metadata via HTTP from a remote Docker instance while loading LoRA files from local NFS/SMB mounts. Includes reverse-proxy middleware for transparent web UI access. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
93 lines
3.0 KiB
Python
93 lines
3.0 KiB
Python
"""Remote LoRA Cycler — uses remote API instead of local ServiceRegistry."""
|
|
from __future__ import annotations
|
|
|
|
import logging
|
|
import os
|
|
|
|
from .remote_utils import get_lora_info_remote
|
|
from ..remote_client import RemoteLoraClient
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
class LoraCyclerRemoteLM:
|
|
"""Node that sequentially cycles through LoRAs from a pool (remote)."""
|
|
|
|
NAME = "Lora Cycler (Remote, LoraManager)"
|
|
CATEGORY = "Lora Manager/randomizer"
|
|
|
|
@classmethod
|
|
def INPUT_TYPES(cls):
|
|
return {
|
|
"required": {
|
|
"cycler_config": ("CYCLER_CONFIG", {}),
|
|
},
|
|
"optional": {
|
|
"pool_config": ("POOL_CONFIG", {}),
|
|
},
|
|
}
|
|
|
|
RETURN_TYPES = ("LORA_STACK",)
|
|
RETURN_NAMES = ("LORA_STACK",)
|
|
FUNCTION = "cycle"
|
|
OUTPUT_NODE = False
|
|
|
|
async def cycle(self, cycler_config, pool_config=None):
|
|
current_index = cycler_config.get("current_index", 1)
|
|
model_strength = float(cycler_config.get("model_strength", 1.0))
|
|
clip_strength = float(cycler_config.get("clip_strength", 1.0))
|
|
execution_index = cycler_config.get("execution_index")
|
|
|
|
client = RemoteLoraClient.get_instance()
|
|
lora_list = await client.get_cycler_list(
|
|
pool_config=pool_config, sort_by="filename"
|
|
)
|
|
|
|
total_count = len(lora_list)
|
|
|
|
if total_count == 0:
|
|
logger.warning("[LoraCyclerRemoteLM] No LoRAs available in pool")
|
|
return {
|
|
"result": ([],),
|
|
"ui": {
|
|
"current_index": [1],
|
|
"next_index": [1],
|
|
"total_count": [0],
|
|
"current_lora_name": [""],
|
|
"current_lora_filename": [""],
|
|
"error": ["No LoRAs available in pool"],
|
|
},
|
|
}
|
|
|
|
actual_index = execution_index if execution_index is not None else current_index
|
|
clamped_index = max(1, min(actual_index, total_count))
|
|
|
|
current_lora = lora_list[clamped_index - 1]
|
|
|
|
lora_path, _ = get_lora_info_remote(current_lora["file_name"])
|
|
if not lora_path:
|
|
logger.warning("[LoraCyclerRemoteLM] Could not find path for LoRA: %s", current_lora["file_name"])
|
|
lora_stack = []
|
|
else:
|
|
lora_path = lora_path.replace("/", os.sep)
|
|
lora_stack = [(lora_path, model_strength, clip_strength)]
|
|
|
|
next_index = clamped_index + 1
|
|
if next_index > total_count:
|
|
next_index = 1
|
|
|
|
next_lora = lora_list[next_index - 1]
|
|
|
|
return {
|
|
"result": (lora_stack,),
|
|
"ui": {
|
|
"current_index": [clamped_index],
|
|
"next_index": [next_index],
|
|
"total_count": [total_count],
|
|
"current_lora_name": [current_lora["file_name"]],
|
|
"current_lora_filename": [current_lora["file_name"]],
|
|
"next_lora_name": [next_lora["file_name"]],
|
|
"next_lora_filename": [next_lora["file_name"]],
|
|
},
|
|
}
|