diff --git a/py/nodes/lora_loader.py b/py/nodes/lora_loader.py index f49eb34b..ed37837d 100644 --- a/py/nodes/lora_loader.py +++ b/py/nodes/lora_loader.py @@ -1,7 +1,6 @@ import logging from nodes import LoraLoader from comfy.comfy_types import IO # type: ignore -import asyncio from ..utils.utils import get_lora_info from .utils import FlexibleOptionalInputType, any_type, extract_lora_name, get_loras_list, nunchaku_load_lora @@ -66,7 +65,7 @@ class LoraManagerLoader: # Extract lora name for trigger words lookup lora_name = extract_lora_name(lora_path) - _, trigger_words = asyncio.run(get_lora_info(lora_name)) + _, trigger_words = get_lora_info(lora_name) all_trigger_words.extend(trigger_words) # Add clip strength to output if different from model strength (except for Nunchaku models) @@ -87,7 +86,7 @@ class LoraManagerLoader: clip_strength = float(lora.get('clipStrength', model_strength)) # Get lora path and trigger words - lora_path, trigger_words = asyncio.run(get_lora_info(lora_name)) + lora_path, trigger_words = get_lora_info(lora_name) # Apply the LoRA using the appropriate loader if is_nunchaku_model: diff --git a/py/nodes/lora_stacker.py b/py/nodes/lora_stacker.py index 34d8adc0..0c57803b 100644 --- a/py/nodes/lora_stacker.py +++ b/py/nodes/lora_stacker.py @@ -1,5 +1,4 @@ from comfy.comfy_types import IO # type: ignore -import asyncio import os from ..utils.utils import get_lora_info from .utils import FlexibleOptionalInputType, any_type, extract_lora_name, get_loras_list @@ -43,7 +42,7 @@ class LoraStacker: # Get trigger words from existing stack entries for lora_path, _, _ in lora_stack: lora_name = extract_lora_name(lora_path) - _, trigger_words = asyncio.run(get_lora_info(lora_name)) + _, trigger_words = get_lora_info(lora_name) all_trigger_words.extend(trigger_words) # Process loras from kwargs with support for both old and new formats @@ -58,7 +57,7 @@ class LoraStacker: clip_strength = float(lora.get('clipStrength', model_strength)) # Get lora path and trigger words - lora_path, trigger_words = asyncio.run(get_lora_info(lora_name)) + lora_path, trigger_words = get_lora_info(lora_name) # Add to stack without loading # replace '/' with os.sep to avoid different OS path format diff --git a/py/nodes/wanvideo_lora_select.py b/py/nodes/wanvideo_lora_select.py index 44d2d25c..2bc2cb43 100644 --- a/py/nodes/wanvideo_lora_select.py +++ b/py/nodes/wanvideo_lora_select.py @@ -1,5 +1,4 @@ from comfy.comfy_types import IO # type: ignore -import asyncio import folder_paths # type: ignore from ..utils.utils import get_lora_info from .utils import FlexibleOptionalInputType, any_type, get_loras_list @@ -56,7 +55,7 @@ class WanVideoLoraSelect: clip_strength = float(lora.get('clipStrength', model_strength)) # Get lora path and trigger words - lora_path, trigger_words = asyncio.run(get_lora_info(lora_name)) + lora_path, trigger_words = get_lora_info(lora_name) # Create lora item for WanVideo format lora_item = { diff --git a/py/routes/api_routes.py b/py/routes/api_routes.py index 7dfb3e8b..53db4d8c 100644 --- a/py/routes/api_routes.py +++ b/py/routes/api_routes.py @@ -827,7 +827,7 @@ class ApiRoutes: all_trigger_words = [] for lora_name in lora_names: - _, trigger_words = await get_lora_info(lora_name) + _, trigger_words = get_lora_info(lora_name) all_trigger_words.extend(trigger_words) # Format the trigger words diff --git a/py/utils/utils.py b/py/utils/utils.py index 710065f2..88adcb23 100644 --- a/py/utils/utils.py +++ b/py/utils/utils.py @@ -5,25 +5,50 @@ import os from bs4 import BeautifulSoup from ..services.service_registry import ServiceRegistry from ..config import config +import asyncio -async def get_lora_info(lora_name): +def get_lora_info(lora_name): """Get the lora path and trigger words from cache""" - scanner = await ServiceRegistry.get_lora_scanner() - cache = await scanner.get_cached_data() + async def _get_lora_info_async(): + scanner = await ServiceRegistry.get_lora_scanner() + cache = await scanner.get_cached_data() + + for item in cache.raw_data: + if item.get('file_name') == lora_name: + file_path = item.get('file_path') + if file_path: + for root in config.loras_roots: + root = root.replace(os.sep, '/') + if file_path.startswith(root): + relative_path = os.path.relpath(file_path, root).replace(os.sep, '/') + # Get trigger words from civitai metadata + civitai = item.get('civitai', {}) + trigger_words = civitai.get('trainedWords', []) if civitai else [] + return relative_path, trigger_words + return lora_name, [] - for item in cache.raw_data: - if item.get('file_name') == lora_name: - file_path = item.get('file_path') - if file_path: - for root in config.loras_roots: - root = root.replace(os.sep, '/') - if file_path.startswith(root): - relative_path = os.path.relpath(file_path, root).replace(os.sep, '/') - # Get trigger words from civitai metadata - civitai = item.get('civitai', {}) - trigger_words = civitai.get('trainedWords', []) if civitai else [] - return relative_path, trigger_words - return lora_name, [] + try: + # Check if we're already in an event loop + loop = asyncio.get_running_loop() + # If we're in a running loop, we need to use a different approach + # Create a new thread to run the async code + import concurrent.futures + + def run_in_thread(): + new_loop = asyncio.new_event_loop() + asyncio.set_event_loop(new_loop) + try: + return new_loop.run_until_complete(_get_lora_info_async()) + finally: + new_loop.close() + + with concurrent.futures.ThreadPoolExecutor() as executor: + future = executor.submit(run_in_thread) + return future.result() + + except RuntimeError: + # No event loop is running, we can use asyncio.run() + return asyncio.run(_get_lora_info_async()) def download_twitter_image(url): """Download image from a URL containing twitter:image meta tag