import requests import re import comfy.model_management as model_management import lmstudio as lms from torchvision.transforms.functional import to_pil_image from io import BytesIO from tempfile import NamedTemporaryFile import torchvision.transforms as T import folder_paths from pathlib import Path SCRIPT_DIR = Path(__file__).parent folder_paths.add_model_folder_path( "lms_config", (SCRIPT_DIR / "lms_config").as_posix()) class YANCLMSTUDIO: def __init__(self): pass @classmethod def INPUT_TYPES(s): return { "required": { "prompt": ("STRING", {"forceInput": True}), "model_identifier": ("STRING", {"default": ""}), "draft_model": ("STRING", {"default": ""}), "system_message": ("STRING", { "multiline": True, "default": "You are an AI assistant specialized in generating detailed and creative image prompts for AI image generation. Your task is to expand a given user prompt into a well-structured, vivid, and highly descriptive prompt while ensuring that all terms from the original prompt are included. Enhance the visual quality and artistic impact by adding relevant details, but do not omit or alter any key elements provided by the user. Follow the given instructions or guidelines and respond only with the refined prompt." }), "reasoning_tag": ("STRING", {"default": "think"}), "seed": ("INT", {"default": 0, "min": 0, "max": 0xffffffffffffffff}), "ip": ("STRING", {"default": "localhost"}), "port": ("INT", {"default": 1234}), "temperature": ("FLOAT", {"default": 0.7, "min": 0.01, "max": 1.0, "step": 0.01}), "max_tokens": ("INT", {"default": 600, "min": -1, "max": 0xffffffffffffffff}), "unload_llm": ("BOOLEAN", {"default": False}), "unload_comfy_models": ("BOOLEAN", {"default": False}) }, "optional": { "image": ("IMAGE", {"forceInput": True}) }, } RETURN_TYPES = ("STRING", "STRING") RETURN_NAMES = ("Extended Prompt", "Reasoning") OUTPUT_NODE = False FUNCTION = "do_it" CATEGORY = "YANC/😼 LMStudio" def do_it(self, prompt, model_identifier, draft_model, system_message, reasoning_tag, seed, ip, port, temperature, max_tokens, unload_llm, unload_comfy_models, image=None): if unload_comfy_models: model_management.unload_all_models() model_management.soft_empty_cache(True) server_api_host = f"{ip}:{port}" result = "" reasoning = "" with lms.Client(server_api_host) as client: model = client.llm.model(model_identifier) if image is None: try: chat = lms.Chat(system_message) chat.add_user_message(prompt) content = str(model.respond(chat, config={ "temperature": temperature, "maxTokens": max_tokens, "draftModel": draft_model })) except: print( "Prediction error: Trying alternative approach to prevent prediction error based on wrong template type.") chat = lms.Chat() chat.add_user_message( f"{system_message}: User input: {prompt}") content = str(model.respond(chat, config={ "temperature": temperature, "maxTokens": max_tokens, "draftModel": draft_model })) # Separate the reasoning block. result = re.sub(rf"<{reasoning_tag}>.*?", "", content, flags=re.DOTALL).strip() reasoning = re.sub( rf".*<{reasoning_tag}>(.*?).*", r"\1", content, flags=re.DOTALL).strip() else: info = model.get_info() if not info.vision: if unload_llm: model.unload() raise Exception( "The loaded model is not vision enabled. Please try another model.") image_new = image.squeeze(0).permute(2, 0, 1) image_pil = to_pil_image(image_new) with NamedTemporaryFile(suffix=".jpg", delete=False) as temp: image_pil.save(temp, format="JPEG") temp.flush() image_handle = client.files.prepare_image(temp.name) chat = lms.Chat() chat.add_user_message( prompt, images=[image_handle]) result = model.respond(chat) reasoning = result if unload_llm: model.unload() return (result, reasoning,) class YANCSELECTLMSMODEL: def __init__(self): pass @classmethod def get_models(cls, id="models.txt"): file_path = folder_paths.get_full_path("lms_config", id) with open(file_path, "r", encoding="utf-8") as f: return [line.strip() for line in f if line.strip()] @classmethod def INPUT_TYPES(s): return { "required": { "model_id": ( s.get_models(), {"tooltip": "Add your favorite model names to the models.txt file in custom_nodes\\YANC_LMStudio\\lms_config\\"} ) }, } RETURN_TYPES = ("STRING",) RETURN_NAMES = ("model_id",) OUTPUT_NODE = False FUNCTION = "do_it" CATEGORY = "YANC/😼 LMStudio" def do_it(self, model_id): return (model_id,) NODE_CLASS_MAPPINGS = { "> LMStudio": YANCLMSTUDIO, "> Select LMS Model": YANCSELECTLMSMODEL } NODE_DISPLAY_NAME_MAPPINGS = { "> LMStudio": "😼> LMStudio", "> Select LMS Model": "😼> Select LMS Model" }