diff --git a/lollms/app.py b/lollms/app.py index ac72d8c..6a33a71 100644 --- a/lollms/app.py +++ b/lollms/app.py @@ -646,42 +646,7 @@ class LollmsApplication(LoLLMsCom): ASCIIColors.execute_with_animation("Loading TTS services", start_tts, ASCIIColors.color_blue) def start_tti(*args, **kwargs): - if self.config.enable_sd_service: - try: - from lollms.services.tti.sd.lollms_sd import LollmsSD - self.sd = LollmsSD(self) - except: - self.warning(f"Couldn't load SD") - - if self.config.enable_comfyui_service: - try: - from lollms.services.tti.comfyui.lollms_comfyui import LollmsComfyUI - self.comfyui = LollmsComfyUI(self) - except: - self.warning(f"Couldn't load SD") - - if self.config.active_tti_service == "diffusers": - from lollms.services.tti.diffusers.lollms_diffusers import LollmsDiffusers - self.tti = LollmsDiffusers(self) - elif self.config.active_tti_service == "diffusers_client": - from lollms.services.tti.diffusers_client.lollms_diffusers_client import LollmsDiffusersClient - self.tti = LollmsDiffusersClient(self) - elif self.config.active_tti_service == "autosd": - from lollms.services.tti.sd.lollms_sd import LollmsSD - self.tti = LollmsSD(self) - elif self.config.active_tti_service == "dall-e": - from lollms.services.tti.dalle.lollms_dalle import LollmsDalle - self.tti = LollmsDalle(self) - elif self.config.active_tti_service == "midjourney": - from lollms.services.tti.midjourney.lollms_midjourney import LollmsMidjourney - self.tti = LollmsMidjourney(self) - elif self.config.active_tti_service == "comfyui" and (self.tti is None or self.tti.name!="comfyui"): - if self.comfyui: - self.tti = self.comfyui - else: - from lollms.services.tti.comfyui.lollms_comfyui import LollmsComfyUI - self.tti = LollmsComfyUI(self) - + self.tti = self.load_service_from_folder(self.lollms_paths.services_zoo_path/"tti", self.config.active_tti_service) ASCIIColors.execute_with_animation("Loading loacal TTI services", start_tti, ASCIIColors.color_blue) def start_ttv(*args, **kwargs): @@ -742,43 +707,10 @@ class LollmsApplication(LoLLMsCom): trace_exception(ex) self.warning(f"Couldn't load XTTS") - ASCIIColors.blue("Loading local TTI services") - if self.config.enable_sd_service and self.sd is None: - try: - from lollms.services.tti.sd.lollms_sd import LollmsSD - self.sd = LollmsSD(self) - except: - self.warning(f"Couldn't load SD") + def start_tti(*args, **kwargs): + self.tti = self.load_service_from_folder(self.lollms_paths.services_zoo_path/"tti", self.config.active_tti_service) + ASCIIColors.execute_with_animation("Loading loacal TTI services", start_tti, ASCIIColors.color_blue) - if self.config.enable_comfyui_service and self.comfyui is None: - try: - from lollms.services.tti.comfyui.lollms_comfyui import LollmsComfyUI - self.comfyui = LollmsComfyUI(self) - except: - self.warning(f"Couldn't load Comfyui") - - ASCIIColors.blue("Activating TTI service") - if self.config.active_tti_service == "diffusers" and (self.tti is None or self.tti.name!="diffusers" or self.tti.model!=self.config.diffusers_model): - from lollms.services.tti.diffusers.lollms_diffusers import LollmsDiffusers - self.tti = LollmsDiffusers(self) - elif self.config.active_tti_service == "diffusers_client" and (self.tti.name!="diffusers_client"): - from lollms.services.tti.diffusers_client.lollms_diffusers_client import LollmsDiffusersClient - self.tti = LollmsDiffusersClient(self) - elif self.config.active_tti_service == "autosd" and (self.tti is None or self.tti.name!="stable_diffusion"): - from lollms.services.tti.sd.lollms_sd import LollmsSD - self.tti = LollmsSD(self) - elif self.config.active_tti_service == "dall-e" and (self.tti is None or self.tti.name!="dall-e-2" or type(self.tti.name)!="dall-e-3"): - from lollms.services.tti.dalle.lollms_dalle import LollmsDalle - self.tti = LollmsDalle(self) - elif self.config.active_tti_service == "midjourney" and (self.tti is None or self.tti.name!="midjourney"): - from lollms.services.tti.midjourney.lollms_midjourney import LollmsMidjourney - self.tti = LollmsMidjourney(self) - elif self.config.active_tti_service == "comfyui" and (self.tti is None or self.tti.name!="comfyui"): - if self.comfyui: - self.tti = self.comfyui - else: - from lollms.services.tti.comfyui.lollms_comfyui import LollmsComfyUI - self.tti = LollmsComfyUI(self, comfyui_base_url=self.config.comfyui_base_url) ASCIIColors.blue("Activating TTS service") if self.config.active_tts_service == "eleven_labs_tts": diff --git a/lollms/server/endpoints/lollms_tti.py b/lollms/server/endpoints/lollms_tti.py index 299ba67..4d95209 100644 --- a/lollms/server/endpoints/lollms_tti.py +++ b/lollms/server/endpoints/lollms_tti.py @@ -7,10 +7,11 @@ from PIL import Image from fastapi import APIRouter from lollms_webui import LOLLMSWebUI from pydantic import BaseModel -from typing import List +from typing import List, Dict from ascii_colors import trace_exception from lollms.security import check_access from ascii_colors import ASCIIColors +import yaml router = APIRouter() lollmsElfServer = LOLLMSWebUI.get_instance() @@ -27,32 +28,55 @@ class ImageResponse(BaseModel): class ServiceListingRequest(BaseModel): client_id: str + @router.post("/list_tti_services") -async def list_tti_services(request: ServiceListingRequest): +async def list_tti_services(request: ServiceListingRequest) -> List[Dict[str, str]]: """ - Dumb endpoint that returns a static list of TTI services. + Endpoint that returns a list of TTI services by scanning subfolders in services_zoo_path. Args: request (ServiceListingRequest): The request body containing the client_id. Returns: - List[str]: A list of TTV service names. + List[Dict[str, str]]: A list of TTI service dictionaries containing name, caption, and help. """ - # Validate the client_id (dumb validation for demonstration) + # Validate the client_id check_access(lollmsElfServer, request.client_id) + # Get the services directory path + services_path = lollmsElfServer.lollms_paths.services_zoo_path/"tti" - # Static list of TTV services - ttv_services = [ - {"name": "diffusers", "caption":"Diffusers", "help":"Diffusers text to image service"}, - {"name": "diffusers_client", "caption":"Diffusers Client", "help":"Diffusers Client text to image service"}, - {"name": "autosd", "caption":"AUTO1111's SD", "help":"AUTO1111's SD text to image service"}, - {"name": "dall-e", "caption":"Open AI's DALL-E", "help":"Open AI's DALL-E text to image service"}, - {"name": "midjourney", "caption":"Midjourney", "help":"Midjourney text to image service"}, - {"name": "comfyui", "caption":"Comfyui", "help":"Comfyui text to image service"}, - {"name": "fooocus", "caption":"Fooocus", "help":"Fooocus text to image service"}, - ] - return ttv_services + # Initialize empty list for services + tti_services = [] + + # Check if the directory exists + if not services_path.exists() or not services_path.is_dir(): + return tti_services # Return empty list if directory doesn't exist + + # Iterate through subfolders + for service_folder in services_path.iterdir(): + if service_folder.is_dir() and service_folder.stem not in [".git", ".vscode"]: + # Look for config.yaml in each subfolder + config_file = service_folder / "config.yaml" + if config_file.exists(): + try: + # Read and parse the YAML file + with open(config_file, 'r') as f: + config = yaml.safe_load(f) + + # Build service dictionary + service_info = { + "name": service_folder.name, + "caption": config.get("caption", service_folder.name), + "help": config.get("help", f"{service_folder.name} text to image services") + } + tti_services.append(service_info) + except Exception as e: + # Log error if needed, skip invalid config files + continue + + return tti_services + @router.post("/generate_image", response_model=ImageResponse) async def generate_image(request: ImageRequest): diff --git a/lollms/server/endpoints/lollms_ttm.py b/lollms/server/endpoints/lollms_ttm.py index e0d5ffd..45a5a85 100644 --- a/lollms/server/endpoints/lollms_ttm.py +++ b/lollms/server/endpoints/lollms_ttm.py @@ -7,9 +7,10 @@ from PIL import Image from fastapi import APIRouter from lollms_webui import LOLLMSWebUI from pydantic import BaseModel -from typing import List +from typing import List, Dict from ascii_colors import trace_exception from lollms.security import check_access +import yaml router = APIRouter() lollmsElfServer = LOLLMSWebUI.get_instance() @@ -18,7 +19,54 @@ class ServiceListingRequest(BaseModel): client_id: str -# Define a Pydantic model for the request body + +@router.post("/list_ttm_services") +async def list_ttm_services(request: ServiceListingRequest) -> List[Dict[str, str]]: + """ + Endpoint that returns a list of TTM services by scanning subfolders in services_zoo_path. + + Args: + request (ServiceListingRequest): The request body containing the client_id. + + Returns: + List[Dict[str, str]]: A list of TTM service dictionaries containing name, caption, and help. + """ + # Validate the client_id + check_access(lollmsElfServer, request.client_id) + + # Get the services directory path + services_path = lollmsElfServer.lollms_paths.services_zoo_path/"ttm" + + # Initialize empty list for services + ttm_services = [] + + # Check if the directory exists + if not services_path.exists() or not services_path.is_dir(): + return ttm_services # Return empty list if directory doesn't exist + + # Iterate through subfolders + for service_folder in services_path.iterdir(): + if service_folder.is_dir() and service_folder.stem not in [".git", ".vscode"]: + # Look for config.yaml in each subfolder + config_file = service_folder / "config.yaml" + if config_file.exists(): + try: + # Read and parse the YAML file + with open(config_file, 'r') as f: + config = yaml.safe_load(f) + + # Build service dictionary + service_info = { + "name": service_folder.name, + "caption": config.get("caption", service_folder.name), + "help": config.get("help", f"{service_folder.name} text to image services") + } + ttm_services.append(service_info) + except Exception as e: + # Log error if needed, skip invalid config files + continue + + return ttm_services @router.post("/list_ttm_services") async def list_ttm_services(request: ServiceListingRequest): @@ -43,11 +91,11 @@ async def list_ttm_services(request: ServiceListingRequest): return ttm_services -@router.post("/get_active_ttm_settings") -async def get_active_ttm_settings(request: Request): +@router.post("/get_active_ttm_settmngs") +async def get_active_ttm_settmngs(request: Request): data = await request.json() check_access(lollmsElfServer,data["client_id"]) - print("- Retreiving ttm settings") + print("- Retreiving ttm settmngs") if lollmsElfServer.ttm is not None: if hasattr(lollmsElfServer.ttm,"service_config"): return lollmsElfServer.ttm.service_config.config_template.template @@ -56,26 +104,26 @@ async def get_active_ttm_settings(request: Request): else: return {} -@router.post("/set_active_ttm_settings") -async def set_active_ttm_settings(request: Request): +@router.post("/set_active_ttm_settmngs") +async def set_active_ttm_settmngs(request: Request): data = await request.json() check_access(lollmsElfServer,data["client_id"]) - settings = data["settings"] + settmngs = data["settmngs"] """ - Sets the active ttm settings. + Sets the active ttm settmngs. :param request: The Request object. :return: A JSON response with the status of the operation. """ try: - print("- Setting ttm settings") + print("- Settmng ttm settmngs") if lollmsElfServer.ttm is not None: if hasattr(lollmsElfServer.ttm,"service_config"): - lollmsElfServer.ttm.service_config.update_template(settings) + lollmsElfServer.ttm.service_config.update_template(settmngs) lollmsElfServer.ttm.service_config.config.save_config() - lollmsElfServer.ttm.settings_updated() + lollmsElfServer.ttm.settmngs_updated() return {'status':True} else: return {'status':False} diff --git a/lollms/server/endpoints/lollms_tts.py b/lollms/server/endpoints/lollms_tts.py index 45f213d..85c87c2 100644 --- a/lollms/server/endpoints/lollms_tts.py +++ b/lollms/server/endpoints/lollms_tts.py @@ -18,8 +18,10 @@ from lollms.utilities import find_next_available_filename, output_file_path_to_u from lollms.security import sanitize_path, validate_path, check_access from pathlib import Path from ascii_colors import ASCIIColors +from typing import List, Dict import os import platform +import yaml # ----------------------- Defining router and main class ------------------------------ diff --git a/lollms/utilities.py b/lollms/utilities.py index 791c782..b5225f8 100644 --- a/lollms/utilities.py +++ b/lollms/utilities.py @@ -685,13 +685,14 @@ def is_asyncio_loop_running(): import asyncio from typing import Callable, Coroutine, Any +from typing import Callable, Coroutine, Any def run_async(func: Callable[[], Coroutine[Any, Any, None]]) -> None: """ run_async(func) -> None - Utility function to run async functions in a synchronous environment. - Takes an async function as input and runs it within an async context. + Utility function to run async functions in either a synchronous or asynchronous environment. + Takes an async function as input and runs it appropriately based on the context. Parameters: func (Callable[[], Coroutine[Any, Any, None]]): The async function to run. @@ -700,18 +701,46 @@ def run_async(func: Callable[[], Coroutine[Any, Any, None]]) -> None: None: Nothing is returned since the function is meant to perform side effects. """ try: - # Check if an event loop is already running - loop = asyncio.get_event_loop() + # Try to get the currently running loop (works in async context) + loop = asyncio.get_running_loop() + # If we're here, a loop is already running, so schedule the coroutine + asyncio.ensure_future(func()) except RuntimeError: - # If no event loop is running, create a new one - loop = asyncio.new_event_loop() - asyncio.set_event_loop(loop) + # No running loop; we're in a synchronous context + # Get or create an event loop + try: + loop = asyncio.get_event_loop() + if loop.is_running(): + # Edge case: loop exists and is running but get_running_loop() failed + asyncio.ensure_future(func()) + else: + # No running loop; run the coroutine synchronously + loop.run_until_complete(func()) + except RuntimeError: + # No existing loop at all; create a new one + loop = asyncio.new_event_loop() + asyncio.set_event_loop(loop) + try: + loop.run_until_complete(func()) + finally: + loop.close() + +# Example usage +async def my_async_function(): + await asyncio.sleep(1) + print("Async function executed!") + +# From a synchronous context +def sync_caller(): + print("Calling from sync context") + run_async(my_async_function) + +# From an asynchronous context +async def async_caller(): + print("Calling from async context") + run_async(my_async_function) + await asyncio.sleep(2) # Give time for the async function to complete - # If the loop is not running, run the coroutine until it completes - try: - loop.run_until_complete(func()) - except: - func() def terminate_thread(thread): """