#
import os
import subprocess
import importlib.util
import sys,json
import execution
import uuid
import hashlib
import datetime
import folder_paths
import logging
import base64,io,re
import random
from PIL import Image
from comfy.cli_args import args
python = sys.executable

#修复 sys.stdout.isatty()  object has no attribute 'isatty'
try:
    sys.stdout.isatty()
except:
    print('#fix sys.stdout.isatty')
    sys.stdout.isatty = lambda: False

_URL_=None


# try:
#     from .nodes.ChatGPT import get_llama_models,get_llama_model_path,llama_cpp_client
#     llama_cpp_client("")

# except:
#     print("##nodes.ChatGPT ImportError")

# from .nodes.ChatGPT import openai_client

from .nodes.RembgNode import get_rembg_models,U2NET_HOME,run_briarmbg,run_rembg

from server import PromptServer

try:
    import aiohttp
    from aiohttp import web
except ImportError:
    print("Module 'aiohttp' not installed. Please install it via:")
    print("pip install aiohttp")
    print("or")
    print("pip install -r requirements.txt")
    sys.exit()


def is_installed(package, package_overwrite=None,auto_install=True):
    is_has=False
    try:
        spec = importlib.util.find_spec(package)
        is_has=spec is not None
    except ModuleNotFoundError:
        pass

    package = package_overwrite or package

    if spec is None:
        if auto_install==True:
            print(f"Installing {package}...")
            # 清华源 -i https://pypi.tuna.tsinghua.edu.cn/simple
            command = f'"{python}" -m pip install {package}'

            result = subprocess.run(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True, env=os.environ)

            is_has=True

            if result.returncode != 0:
                print(f"Couldn't install\nCommand: {command}\nError code: {result.returncode}")
                is_has=False
    else:
        print(package+'## OK')

    return is_has

try:
    import OpenSSL
except ImportError:
    print("Module 'pyOpenSSL' not installed. Please install it via:")
    print("pip install pyOpenSSL")
    print("or")
    print("pip install -r requirements.txt")
    is_installed('pyOpenSSL')
    sys.exit()

try:
    import watchdog
except ImportError:
    print("Module 'watchdog' not installed. Please install it via:")
    print("pip install watchdog")
    print("or")
    print("pip install -r requirements.txt")
    is_installed('watchdog')
    sys.exit()


def install_openai():
    # Helper function to install the OpenAI module if not already installed
    try:
        importlib.import_module('openai')
    except ImportError:
        import pip
        pip.main(['install', 'openai'])

install_openai()


current_path = os.path.abspath(os.path.dirname(__file__))


def remove_base64_prefix(base64_str):
  """
  去除 base64 字符串中的 data:image/*;base64, 前缀

  Args:
    base64_str: base64 编码的字符串

  Returns:
    去除前缀后的 base64 字符串
  """

  # 使用正则表达式匹配常见的前缀
  pattern = r'^data:image\/(.*);base64,(.+)$'
  match = re.match(pattern, base64_str)
  if match:
    # 如果匹配到常见的前缀，则去除前缀并返回
    return match.group(2)
  else:
    # 如果不匹配到常见的前缀，则直接返回
    return base64_str

def calculate_md5(string):
    encoded_string = string.encode()
    md5_hash = hashlib.md5(encoded_string).hexdigest()
    return md5_hash


def create_key(key_p,crt_p):
    import OpenSSL
    # 生成自签名证书
    # 生成私钥
    private_key = OpenSSL.crypto.PKey()
    private_key.generate_key(OpenSSL.crypto.TYPE_RSA, 2048)

    # 生成CSR
    csr = OpenSSL.crypto.X509Req()
    csr.get_subject().CN = "mixlab.com"  # 设置证书的通用名称
    csr.set_pubkey(private_key)
    csr.sign(private_key, "sha256")
    # 生成证书
    certificate = OpenSSL.crypto.X509()
    certificate.set_serial_number(1)
    certificate.gmtime_adj_notBefore(0)
    certificate.gmtime_adj_notAfter(365 * 24 * 60 * 60)  # 设置证书的有效期
    certificate.set_issuer(csr.get_subject())
    certificate.set_subject(csr.get_subject())
    certificate.set_pubkey(csr.get_pubkey())
    certificate.sign(private_key, "sha256")
    # 保存私钥到文件
    with open(key_p, "wb") as f:
        f.write(OpenSSL.crypto.dump_privatekey(OpenSSL.crypto.FILETYPE_PEM, private_key))

    # 保存证书到文件
    with open(crt_p, "wb") as f:
        f.write(OpenSSL.crypto.dump_certificate(OpenSSL.crypto.FILETYPE_PEM, certificate))
    return


def create_for_https():
    # print("#####path::", current_path)
    https_key_path=os.path.join(current_path, "https")
    crt=os.path.join(https_key_path, "certificate.crt")
    key=os.path.join(https_key_path, "private.key")
    # print("##https_key_path", crt,key)
    if not os.path.exists(https_key_path):
        # 使用mkdir()方法创建新目录
        os.mkdir(https_key_path)
    if not os.path.exists(crt):
        create_key(key,crt)
    # print('https_key OK: ', crt,key)
    return (crt,key)



# workflow  目录下的所有json
def read_workflow_json_files_all(folder_path):
    # print('#read_workflow_json_files_all',folder_path)
    json_files = []
    for root, dirs, files in os.walk(folder_path):
        for file in files:
            if file.endswith('.json'):
                json_files.append(os.path.join(root, file))

    data = []
    for file_path in json_files:
        try:
            with open(file_path) as json_file:
                json_data = json.load(json_file)
                creation_time = datetime.datetime.fromtimestamp(os.path.getctime(file_path))
                numeric_timestamp = creation_time.timestamp()
                file_info = {
                    'filename': os.path.basename(file_path),
                    'category': os.path.dirname(file_path),
                    'data': json_data,
                    'date': numeric_timestamp
                }
                data.append(file_info)
        except Exception as e:
            print(e)

    sorted_data = sorted(data, key=lambda x: x['date'], reverse=True)
    return sorted_data

# workflow
def read_workflow_json_files(folder_path ):
    json_files = []
    for filename in os.listdir(folder_path):
        if filename.endswith('.json'):
            json_files.append(filename)

    data = []
    for file in json_files:
        file_path = os.path.join(folder_path, file)
        try:
            with open(file_path) as json_file:
                json_data = json.load(json_file)
                creation_time=datetime.datetime.fromtimestamp(os.path.getctime(file_path))
                numeric_timestamp = creation_time.timestamp()
                file_info = {
                    'filename': file,
                    'data': json_data,
                    'date': numeric_timestamp
                }
                data.append(file_info)
        except Exception as e:
            print(e)
    sorted_data = sorted(data, key=lambda x: x['date'], reverse=True)
    return sorted_data

def get_workflows():
    # print("#####path::", current_path)
    workflow_path=os.path.join(current_path, "workflow")
    # print('workflow_path: ',workflow_path)
    if not os.path.exists(workflow_path):
        # 使用mkdir()方法创建新目录
        os.mkdir(workflow_path)
    workflows=read_workflow_json_files(workflow_path)
    return workflows

def get_my_workflow_for_app(filename="my_workflow_app.json",category="",is_all=False):
    app_path=os.path.join(current_path, "app")
    if not os.path.exists(app_path):
        os.mkdir(app_path)

    category_path=os.path.join(app_path,category)
    if not os.path.exists(category_path):
        os.mkdir(category_path)

    apps=[]
    if filename==None:

        #TODO 支持目录内遍历
        if is_all:
            data=read_workflow_json_files_all(category_path)
        else:
            data=read_workflow_json_files(category_path)

        i=0
        for item in data:
            # print(item)
            try:
                x=item["data"]
                # 管理员模式，读取全部数据
                if i==0 or is_all:
                    apps.append({
                        "filename":item["filename"],
                        # "category":item['category'],
                        "data":x,
                        "date":item["date"],
                    })
                else:
                    category=''
                    input=None
                    output=None
                    if 'category' in x['app']:
                        category=x['app']['category']
                    if 'input' in x['app']:
                        input=x['app']['input']
                    if 'output' in x['app']:
                        output=x['app']['output']
                    apps.append({
                        "filename":item["filename"],
                        "category":category,
                        "data":{
                            "app":{
                                "category":category,
                                "description":x['app']['description'],
                                "filename":(x['app']['filename'] if 'filename' in x['app'] else "") ,
                                "icon":(x['app']['icon'] if 'icon' in x['app'] else None),
                                "name":x['app']['name'],
                                "version":x['app']['version'],
                                "input":input,
                                "output":output,
                                "id":x['app']['id']
                            }
                        },
                        "date":item["date"]
                    })
                i+=1
            except Exception as e:
                print("发生异常：", str(e))
    else:
        app_workflow_path=os.path.join(category_path, filename)
        print('app_workflow_path: ',app_workflow_path)
        try:
            with open(app_workflow_path) as json_file:
                json_data=json.load(json_file)
                apps = [{
                    'filename':filename,
                    'data':json_data
                }]
        except Exception as e:
            print("发生异常：", str(e))

        # 这个代码不需要
        # if len(apps)==1 and category!='' and category!=None:
        data=read_workflow_json_files(category_path)

        for item in data:
            x=item["data"]
            # print(apps[0]['filename'] ,item["filename"])
            if apps[0]['filename']!=item["filename"]:
                category=''
                input=None
                output=None
                if 'category' in x['app']:
                    category=x['app']['category']
                if 'input' in x['app']:
                    input=x['app']['input']
                if 'output' in x['app']:
                    output=x['app']['output']
                apps.append({
                        "filename":item["filename"],
                        # "category":category,
                        "data":{
                            "app":{
                                "category":category,
                                "description":x['app']['description'],
                                "filename":(x['app']['filename'] if 'filename' in x['app'] else "") ,
                                "icon":(x['app']['icon'] if 'icon' in x['app'] else None),
                                "name":x['app']['name'],
                                "version":x['app']['version'],
                                "input":input,
                                "output":output,
                                "id":x['app']['id']
                            }
                        },
                        "date":item["date"]
                    })

    return apps

# 历史记录
def save_prompt_result(id,data):
    prompt_result_path=os.path.join(current_path, "workflow/prompt_result.json")
    prompt_result={}
    if os.path.exists(prompt_result_path):
        with open(prompt_result_path) as json_file:
            prompt_result = json.load(json_file)

    prompt_result[id]=data

    with open(prompt_result_path, 'w') as file:
        json.dump(prompt_result, file)
    return prompt_result_path

def get_prompt_result():
    prompt_result_path=os.path.join(current_path, "workflow/prompt_result.json")
    prompt_result={}
    if os.path.exists(prompt_result_path):
        with open(prompt_result_path) as json_file:
            prompt_result = json.load(json_file)
    res=list(prompt_result.values())
    # print(res)
    return res


def save_workflow_json(data):
    workflow_path=os.path.join(current_path, "workflow/my_workflow.json")
    with open(workflow_path, 'w') as file:
        json.dump(data, file)
    return workflow_path

def save_workflow_for_app(data,filename="my_workflow_app.json",category=""):
    app_path=os.path.join(current_path, "app")
    if not os.path.exists(app_path):
        os.mkdir(app_path)

    category_path=os.path.join(app_path,category)
    if not os.path.exists(category_path):
        os.mkdir(category_path)

    app_workflow_path=os.path.join(category_path, filename)

    try:
        output_str = json.dumps(data['output'])
        data['app']['id']=calculate_md5(output_str)
        # id=data['app']['id']
    except Exception as e:
        print("发生异常：", str(e))

    with open(app_workflow_path, 'w') as file:
        json.dump(data, file)
    return filename

def get_nodes_map():
    # print("#####path::", current_path)
    data_path=os.path.join(current_path, "data")
    print('data_path: ',data_path)
    # if not os.path.exists(data_path):
    #     # 使用mkdir()方法创建新目录
    #     os.mkdir(data_path)
    json_data={}
    nodes_map=os.path.join(current_path, "data/extension-node-map.json")
    if os.path.exists(nodes_map):
        with open(nodes_map) as json_file:
            json_data = json.load(json_file)

    return json_data


# 保存原始的 get 方法
_original_request = aiohttp.ClientSession._request

# 定义新的 get 方法
async def new_request(self, method, url, *args, **kwargs):
   # 检查环境变量以确定是否使用代理
    proxy = os.environ.get('HTTP_PROXY') or os.environ.get('HTTPS_PROXY') or os.environ.get('http_proxy') or os.environ.get('https_proxy')
    # print('Proxy Config:',proxy)
    if proxy and 'proxy' not in kwargs:
        kwargs['proxy'] = proxy
        print('Use Proxy:',proxy)
    # 调用原始的 _request 方法
    return await _original_request(self, method, url, *args, **kwargs)

# 应用 Monkey Patch
aiohttp.ClientSession._request = new_request
import socket

async def check_port_available(address, port):
    #检查端口是否可用
    with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
        sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        try:
            sock.bind((address, port))
            return True
        except socket.error:
            return False

# https
async def new_start(self, address, port, verbose=True, call_on_start=None):
    global _URL_
    try:
        runner = web.AppRunner(self.app, access_log=None)
        await runner.setup()

        # if not await check_port_available(address, port):
        #     raise RuntimeError(f"Port {port} is already in use.")

        http_success = False
        http_port=port
        for i in range(11):  # 尝试最多11次
            if await check_port_available(address, port + i):
                http_port = port + i
                site = web.TCPSite(runner, address, http_port)
                await site.start()
                http_success = True
                break

        if not http_success:
            raise RuntimeError(f"Ports {port} to {port + 10} are all in use.")


        # site = web.TCPSite(runner, address, port)
        # await site.start()

        ssl_context = None
        scheme = "http"
        try:
            # 跟着本体修改
            if args.tls_keyfile and args.tls_certfile:
                scheme = "https"
                ssl_context = ssl.SSLContext(protocol=ssl.PROTOCOL_TLS_SERVER, verify_mode=ssl.CERT_NONE)
                ssl_context.load_cert_chain(certfile=args.tls_certfile,
                                    keyfile=args.tls_keyfile)
            else:
                # 如果没传，则自动创建
                import ssl
                crt, key = create_for_https()
                ssl_context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
                ssl_context.load_cert_chain(crt, key)
        except:
            import ssl
            crt, key = create_for_https()
            ssl_context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
            ssl_context.load_cert_chain(crt, key)


        success = False
        for i in range(11):  # 尝试最多11次
            if await check_port_available(address, http_port + 1 + i):
                https_port = http_port + 1 + i
                site2 = web.TCPSite(runner, address, https_port, ssl_context=ssl_context)
                await site2.start()
                success = True
                break

        if not success:
            raise RuntimeError(f"Ports {http_port + 1} to {http_port + 10} are all in use.")

        if address == '':
            address = '127.0.0.1'
        if address=='0.0.0.0':
            address = '127.0.0.1'

        if verbose:

            logging.info("\n")
            logging.info("\n\nStarting server")

            import socket

            hostname = socket.gethostname()
            # logging.debug("hostname:", hostname)
            try:
                ip_address = socket.gethostbyname(hostname)
            except Exception as e:
                logging.debug("[mixlab]gethostbyname() downgraded due to exception:", e)
                ip_address = socket.gethostbyname("")

            # print(f"本机的 IP 地址是：{ip_address}")

            # print("\033[93mStarting server\n")
            logging.info("\033[93mTo see the GUI go to: http://{}:{} or http://{}:{}".format(ip_address, http_port,address,http_port))
            logging.info("\033[93mTo see the GUI go to: https://{}:{} or https://{}:{}\033[0m".format(ip_address, https_port,address,https_port))

            _URL_="http://{}:{}".format(address,http_port)
            # print("\033[93mTo see the GUI go to: http://{}:{}".format(address, http_port))
            # print("\033[93mTo see the GUI go to: https://{}:{}\033[0m".format(address, https_port))

        if call_on_start is not None:
            try:
                if scheme=='https':
                    call_on_start(scheme,address, https_port)
                else:
                    call_on_start(scheme,address, http_port)
            except:
                call_on_start(address,http_port)


    except Exception as e:
        print(f"Error starting the server: {e}")

        # import webbrowser
        # if os.name == 'nt' and address == '0.0.0.0':
        #     address = '127.0.0.1'
        # webbrowser.open(f"https://{address}")
        # webbrowser.open(f"http://{address}:{port}")

PromptServer.start=new_start

# 创建路由表
routes = PromptServer.instance.routes

@routes.post('/mixlab')
async def mixlab_hander(request):
    config=os.path.join(current_path, "nodes/config.json")
    data={}
    try:
        if os.path.exists(config):
            with open(config, 'r') as f:
                data = json.load(f)
                # print(data)
    except Exception as e:
            print(e)
    return web.json_response(data)

# llm的api key，使用硅基流动
@routes.post('/mixlab/llm_api_key')
async def mixlab_llm_api_key_handler(request):
    data = await request.json()
    api_key = data.get('key')

    app_folder = os.path.join(current_path, "app")
    key_file_path = os.path.join(app_folder, "llm_api_key.txt")

    if api_key:
        if not os.path.exists(app_folder):
            os.makedirs(app_folder)
        try:
            with open(key_file_path, 'w') as f:
                f.write(api_key)
            return web.json_response({'message': 'API key saved successfully'})
        except Exception as e:
            return web.json_response({'error': str(e)}, status=500)
    else:
        if os.path.exists(key_file_path):
            try:
                with open(key_file_path, 'r') as f:
                    saved_api_key = f.read().strip()
                return web.json_response({'key': saved_api_key})
            except Exception as e:
                return web.json_response({'error': str(e)}, status=500)
        else:
            return web.json_response({'error': 'No API key provided and no key found in local storage'}, status=400)


@routes.post('/chat/completions')
async def chat_completions(request):
    data = await request.json()
    messages = data.get('messages')
    key=data.get('key')
    api_url=data.get("api_url")
    model_name=data.get("model_name")

    if not api_url:
        api_url="https://api.siliconflow.cn/v1"

    if not model_name:
        model_name="01-ai/Yi-1.5-9B-Chat-16K"

    if not messages:
        return web.json_response({"error": "No messages provided"}, status=400)

    async def generate():
        try:
            headers = {
                'Authorization': f'Bearer {key}',
                'Content-Type': 'application/json'
            }
            payload = {
                'model': model_name,
                'messages': messages,
                'stream': True
            }
            async with aiohttp.ClientSession() as session:
                async with session.post(f'{api_url}/chat/completions', json=payload, headers=headers) as resp:
                    async for line in resp.content:
                        yield line

        except Exception as e:
            yield f"Error: {str(e)}".encode('utf-8') + b"\r\n"

    return web.Response(body=generate(), content_type='text/event-stream')


@routes.get('/mixlab/app')
async def mixlab_app_handler(request):
    html_file = os.path.join(current_path, "webApp/index.html")
    if os.path.exists(html_file):
        with open(html_file, 'r', encoding='utf-8', errors='ignore') as f:
            html_data = f.read()
            return web.Response(text=html_data, content_type='text/html')
    else:
        return web.Response(text="HTML file not found", status=404)

# web app模式独立
@routes.get('/mixlab/app/{filename:.*}')
async def static_file_handler(request):
    filename = request.match_info['filename']
    file_path = os.path.join(current_path, "webApp", filename)
    print(file_path)

    if os.path.exists(file_path) and os.path.isfile(file_path):
        if filename.endswith('.js'):
            content_type = 'application/javascript'
        elif filename.endswith('.css'):
            content_type = 'text/css'
        elif filename.endswith('.html'):
            content_type = 'text/html'
        elif filename.endswith('.svg'):
            content_type = 'image/svg+xml'
        else:
            content_type = 'application/octet-stream'

        with open(file_path, 'r', encoding='utf-8', errors='ignore') as f:
            file_data = f.read()
            return web.Response(text=file_data, content_type=content_type)
    else:
        return web.Response(text="File not found", status=404)


@routes.post('/mixlab/workflow')
async def mixlab_workflow_hander(request):
    data = await request.json()
    result={}
    try:
        if 'task' in data:
            if data['task']=='save':
                file_path=save_workflow_json(data['data'])
                result={
                    'status':'success',
                    'file_path':file_path
                }
            elif data['task']=='save_app':
                category=""
                if "category" in data:
                    category=data['category']
                file_path=save_workflow_for_app(data['data'],data['filename'],category)
                result={
                    'status':'success',
                    'file_path':file_path
                }
            elif data['task']=='my_app':
                filename=None
                category=""
                admin=False
                if 'filename' in data:
                    filename=data['filename']
                if 'category' in data:
                    category=data['category']
                if 'admin' in data:
                    admin=data['admin']

                ds=get_my_workflow_for_app(filename,category,admin)
                data=[]
                for json_data in ds:
                    # 不传给前端
                    if 'output' in json_data['data']:
                        del json_data['data']['output']
                    if 'workflow' in json_data['data']:
                        del json_data['data']['workflow']
                    data.append(json_data)

                result={
                    'data':data,
                    'status':'success',
                }
            elif data['task']=='list':
                ds=get_workflows()
                data=[]
                for json_data in ds:
                    # 不传给前端
                    if 'output' in json_data['data']:
                        del json_data['data']['output']
                    if 'workflow' in json_data['data']:
                        del json_data['data']['workflow']
                    data.append(json_data)

                result={
                    'data':data,
                    'status':'success',
                }
    except Exception as e:
            print(e)

    return web.json_response(result)

@routes.post('/mixlab/nodes_map')
async def nodes_map_hander(request):
    data = await request.json()
    result={}
    try:
        result={
            'data':get_nodes_map(),
            'status':'success',
                }
    except Exception as e:
            print(e)

    return web.json_response(result)


@routes.post("/mixlab/folder_paths")
async def get_checkpoints(request):
    data = await request.json()
    t="checkpoints"
    names=[]
    try:
        t=data['type']
        names = folder_paths.get_filename_list(t)
    except Exception as e:
        print('/mixlab/folder_paths',False,e)

    # try:
    #     if data['type']=='llamafile':
    #         names=get_llama_models()
    # except:
    #     print("llamafile none")

    try:
        if data['type']=='rembg':
            names=get_rembg_models(U2NET_HOME)
    except:
        print("rembg none")

    return web.json_response({"names":names,"types":list(folder_paths.folder_names_and_paths.keys())})


@routes.post('/mixlab/rembg')
async def rembg_hander(request):
    data = await request.json()
    model=data['model']
    result={}

    data_base64=remove_base64_prefix(data['base64'])
    image_data = base64.b64decode(data_base64)

    # 创建一个BytesIO对象
    image_stream = io.BytesIO(image_data)

    # 使用PIL Image模块读取图像
    image = Image.open(image_stream)

    if model=='briarmbg':
        _,rgba_images,_=run_briarmbg([image])
    else:
        _,rgba_images,_=run_rembg(model,[image])

    with io.BytesIO() as buf:
        rgba_images[0].save(buf, format='PNG')
        img_bytes = buf.getvalue()
    img_base64 = base64.b64encode(img_bytes).decode('utf-8')

    try:
        result={
            'data':img_base64,
            'model':model,
            'status':'success',
            }
    except Exception as e:
            print(e)

    return web.json_response(result)

# 保存运行结果？暂时去掉
# @routes.post("/mixlab/prompt_result")
# async def post_prompt_result(request):
#     data = await request.json()
#     res=None
#     # print(data)
#     try:
#         action=data['action']
#         if action=='save':
#             result=data['data']
#             res=save_prompt_result(result['prompt_id'],result)
#         elif action=='all':
#             res=get_prompt_result()
#     except Exception as e:
#         print('/mixlab/prompt_result',False,e)

#     return web.json_response({"result":res})

# 种子设置
def random_seed(seed, data):
    max_seed = 4294967295

    for id, value in data.items():
        # print(seed,id)
        if id in seed:
            if 'seed' in value['inputs'] and not isinstance(value['inputs']['seed'], list) and seed[id] in ['increment', 'decrement', 'randomize']:
                value['inputs']['seed'] = round(random.random() * max_seed)

            if 'noise_seed' in value['inputs'] and not isinstance(value['inputs']['noise_seed'], list) and seed[id] in ['increment', 'decrement', 'randomize']:
                value['inputs']['noise_seed'] = round(random.random() * max_seed)

            if value.get('class_type') == "Seed_" and seed[id] in ['increment', 'decrement', 'randomize']:
                value['inputs']['seed'] = round(random.random() * max_seed)
     
        # print('new Seed', value)

    return data


# 运行工作流，代替官方的prompt接口
@routes.post("/mixlab/prompt")
async def mixlab_post_prompt(request):
    p_intance=PromptServer.instance
    logging.info("/mixlab/prompt")
    resp_code = 200
    out_string = ""
    json_data =  await request.json()
    # json_data = p_intance.trigger_on_prompt(json_data)
    # filename,category, client_id ,input
    # workflow 的 filename,category

    # 输入的参数
    input_data=json_data['input'] if "input" in json_data else []
    # 种子
    seed=json_data['seed'] if "seed" in json_data else {}

    try:
        apps=json_data['apps']
    except:
        apps=get_my_workflow_for_app(json_data['filename'],json_data['category'],False)

    prompt=json_data['prompt'] if 'prompt' in json_data else None

    if len(apps)>0:
        # 取到prompt
        prompt=apps[0]['data']['output']
        # logging.info(prompt)
        # 更新input_data到prompt里
        '''
          {
                "inputs": {
                    "number": 512,
                    "min_value": 512,
                    "max_value": 2048,
                    "step": 1
                },
                "class_type": "IntNumber",
                "id": "22"
            },
        '''

        for inp in input_data:
            id=inp['id']
            if prompt[id]['class_type']==inp['class_type']:
                prompt[id]['inputs'].update(inp['inputs'])


    if prompt==None:
        return web.json_response({"error": "no prompt", "node_errors": []}, status=400)
    else:
        # 种子更新
        '''
            "seed": {
                    "45": "randomize",
                    "46": "randomize"
                }
            '''
        json_data["prompt"]=random_seed(seed,prompt)

    # print("#json_data",prompt)
    # 需要把apps处理成 prompt
    # 注意seed的处理

    if "number" in json_data:
        number = float(json_data['number'])
    else:
        number = p_intance.number
        if "front" in json_data:
            if json_data['front']:
                number = -number

        p_intance.number += 1

    if "prompt" in json_data:
        prompt = json_data["prompt"]
        valid = execution.validate_prompt(prompt)
        extra_data = {}
        if "extra_data" in json_data:
            extra_data = json_data["extra_data"]

        if "client_id" in json_data:
            extra_data["client_id"] = json_data["client_id"]
        if valid[0]:
            prompt_id = str(uuid.uuid4())
            outputs_to_execute = valid[2]
            p_intance.prompt_queue.put((number, prompt_id, prompt, extra_data, outputs_to_execute))
            response = {"prompt_id": prompt_id, "number": number, "node_errors": valid[3]}
            return web.json_response(response)
        else:
            logging.warning("invalid prompt: {}".format(valid[1]))
            return web.json_response({"error": valid[1], "node_errors": valid[3]}, status=400)
    else:
        return web.json_response({"error": "no prompt", "node_errors": []}, status=400)


# AR页面
# @routes.get('/mixlab/AR')
async def handle_ar_page(request):
    html_file = os.path.join(current_path, "web/ar.html")
    if os.path.exists(html_file):
        with open(html_file, 'r', encoding='utf-8', errors='ignore') as f:
            html_data = f.read()
            return web.Response(text=html_data, content_type='text/html')
    else:
        return web.Response(text="HTML file not found", status=404)


# 重启服务
@routes.post('/mixlab/re_start')
def re_start(request):
    p_intance=PromptServer.instance
    try:
        p_intance.prompt_queue.set_flag("free_memory", True)
        sys.stdout.close_log()
    except Exception as e:
        pass
    return os.execv(sys.executable, [sys.executable] + sys.argv)

# 状态
@routes.get('/mixlab/status')
def mix_status(request):
    return web.Response(text="running#"+_URL_)

# 导入节点
from .nodes.PromptNode import GLIGENTextBoxApply_Advanced,EmbeddingPrompt,RandomPrompt,PromptSlide,PromptSimplification,PromptImage,JoinWithDelimiter
from .nodes.ImageNode import DepthViewer_,ImageBatchToList_,ImageListToBatch_,ComparingTwoFrames,LoadImages_,CompositeImages,GridDisplayAndSave,GridInput,ImagesPrompt,SaveImageAndMetadata,SaveImageToLocal,SplitImage,GridOutput,GetImageSize_,MirroredImage,ImageColorTransfer,NoiseImage,TransparentImage,GradientImage,LoadImagesFromPath,LoadImagesFromURL,ResizeImage,TextImage,SvgImage,Image3D,ShowLayer,NewLayer,MergeLayers,CenterImage,AreaToMask,SmoothMask,SplitLongMask,ImageCropByAlpha,EnhanceImage,FaceToMask
# from .nodes.Vae import VAELoader,VAEDecode
from .nodes.ScreenShareNode import ScreenShareNode,FloatingVideo

from .nodes.Audio import AudioPlayNode,SpeechRecognition,SpeechSynthesis,AnalyzeAudioNone
from .nodes.Utils import CreateJsonNode,KeyInput,IncrementingListNode,ListSplit,CreateLoraNames,CreateSampler_names,CreateCkptNames,CreateSeedNode,TESTNODE_,TESTNODE_TOKEN,AppInfo,IntNumber,FloatSlider,TextInput,ColorInput,FontInput,TextToNumber,DynamicDelayProcessor,LimitNumber,SwitchByIndex,MultiplicationNode
from .nodes.Mask import PreviewMask_,MaskListReplace,MaskListMerge,OutlineMask,FeatheredMask

from .nodes.Style import ApplyVisualStylePrompting,StyleAlignedReferenceSampler,StyleAlignedBatchAlign,StyleAlignedSampleReferenceLatents

from .nodes.P5 import P5Input


# 要导出的所有节点及其名称的字典
# 注意：名称应全局唯一
NODE_CLASS_MAPPINGS = {
    "AppInfo":AppInfo,
    "TESTNODE_":TESTNODE_,
    "TESTNODE_TOKEN":TESTNODE_TOKEN,

    # Prompt
    "RandomPrompt":RandomPrompt,
    # "LoraPrompt":LoraPrompt,
    "EmbeddingPrompt":EmbeddingPrompt,
    "PromptSlide":PromptSlide,
    "GLIGENTextBoxApply_Advanced":GLIGENTextBoxApply_Advanced,
    "PromptSimplification":PromptSimplification,

    # Input
    "GridInput":GridInput,
    "ImagesPrompt_":ImagesPrompt,
    "KeyInput":KeyInput,
    "FloatSlider":FloatSlider,
    "IntNumber":IntNumber,
    "TextInput_":TextInput,
    "Font":FontInput,
    "LimitNumber":LimitNumber,

    # Output
    "PromptImage":PromptImage,
    "SaveImageToLocal":SaveImageToLocal,
    "SaveImageAndMetadata_":SaveImageAndMetadata,
    "ComparingTwoFrames_":ComparingTwoFrames,
    "CreateJsonNode":CreateJsonNode,

    # Image
    "MirroredImage":MirroredImage,
    "NoiseImage":NoiseImage,
    "GradientImage":GradientImage,
    "TransparentImage":TransparentImage,
    "ResizeImageMixlab":ResizeImage,
    "LoadImagesFromPath":LoadImagesFromPath,
    "LoadImagesFromURL":LoadImagesFromURL,
    "LoadImagesToBatch":LoadImages_,
    "TextImage":TextImage,
    "EnhanceImage":EnhanceImage,
    "SvgImage":SvgImage,
    "ImageListToBatch_":ImageListToBatch_,
    "ImageBatchToList_":ImageBatchToList_,
    "ImageCropByAlpha":ImageCropByAlpha,
    "GetImageSize_":GetImageSize_,

    # 3D
    "3DImage":Image3D,
    "DepthViewer": DepthViewer_,

    # Color
    "ImageColorTransfer":ImageColorTransfer,
    "Color":ColorInput,

    # Layer
    "ShowLayer":ShowLayer,
    "NewLayer":NewLayer,
    "MergeLayers":MergeLayers,
    "CompositeImages_":CompositeImages,
    "SplitImage":SplitImage,
    "CenterImage":CenterImage,
    "GridOutput":GridOutput,
    "GridDisplayAndSave":GridDisplayAndSave,

    # Mask
    "SplitLongMask":SplitLongMask,
    "FeatheredMask":FeatheredMask,
    "SmoothMask":SmoothMask,
    "FaceToMask":FaceToMask,
    "AreaToMask":AreaToMask,
    "OutlineMask":OutlineMask,
    "MaskListMerge_":MaskListMerge,
    "PreviewMask_":PreviewMask_,

    # "VAELoaderConsistencyDecoder":VAELoader,
    # "VAEDecodeConsistencyDecoder":VAEDecode,

    # Screen
    "ScreenShare":ScreenShareNode,
    "FloatingVideo":FloatingVideo,

    # Audio
    "SpeechRecognition":SpeechRecognition,
    "SpeechSynthesis":SpeechSynthesis,
    "AudioPlay":AudioPlayNode,
    "AnalyzeAudio":AnalyzeAudioNone,

    # Text
    "TextToNumber":TextToNumber,
    "JoinWithDelimiter":JoinWithDelimiter,

    # Utils
    "MultiplicationNode":MultiplicationNode,
    "DynamicDelayProcessor":DynamicDelayProcessor,
    "SwitchByIndex":SwitchByIndex,
    "ListSplit_":ListSplit,

    # Experiment
    "Seed_":CreateSeedNode,
    "CkptNames_":CreateCkptNames,
    "SamplerNames_":CreateSampler_names,
    "LoraNames_":CreateLoraNames,

    # Style
    "ApplyVisualStylePrompting_":ApplyVisualStylePrompting,
    "StyleAlignedReferenceSampler_": StyleAlignedReferenceSampler,
    "StyleAlignedSampleReferenceLatents_": StyleAlignedSampleReferenceLatents,
    "StyleAlignedBatchAlign_": StyleAlignedBatchAlign,

    # Video
    "MaskListReplace_":MaskListReplace,
    "IncrementingListNode_":IncrementingListNode,

    "P5Input":P5Input
}

# 一个包含节点友好/可读的标题的字典
NODE_DISPLAY_NAME_MAPPINGS = {
    "AppInfo":"App Info ♾️Mixlab",
    "TESTNODE_":"TESTNODE_ ♾️Mixlab",
    "TESTNODE_TOKEN":"TESTNODE_TOKEN ♾️Mixlab",

    # Prompt
    "RandomPrompt": "Random Prompt ♾️Mixlab",
    "EmbeddingPrompt":"Embedding Prompt ♾️Mixlab",
    "PromptSlide":"Prompt Slide ♾️Mixlab",
    "GLIGENTextBoxApply_Advanced":"GLIGEN TextBox Apply ♾️Mixlab",
    "PromptSimplification":"PromptSimplification ♾️Mixlab",
    "PromptGenerate_Mix":"Prompt Generate ♾️Mixlab",
    "ChinesePrompt_Mix":"Chinese Prompt ♾️Mixlab",

    # Input
    "GridInput":"Grid Input ♾️Mixlab",
    "ImagesPrompt_":"Images Input ♾️Mixlab",
    "KeyInput":"API Key Input ♾️Mixlab",
    "FloatSlider":"Float Slider Input ♾️Mixlab",
    "IntNumber":"Int Input ♾️Mixlab",
    "TextInput_":"Text Input ♾️Mixlab",
    "Font":"Font Input ♾️Mixlab",
    "LimitNumber":"LimitNumber Input ♾️Mixlab",

    # Output
    "PromptImage":"Output Prompt and Image ♾️Mixlab",
    "SaveImageToLocal":"Save Image To Local ♾️Mixlab",
    "SaveImageAndMetadata_":"Save Image Output ♾️Mixlab",
    "ComparingTwoFrames_":"Comparing Two Frames ♾️Mixlab",

    # Image
    "MirroredImage":"MirroredImage ♾️Mixlab",
    "NoiseImage":"NoiseImage ♾️Mixlab",
    "GradientImage":"GradientImage ♾️Mixlab",
    "TransparentImage":"TransparentImage ♾️Mixlab",
    "ResizeImageMixlab":"Resize Image ♾️Mixlab",
    "LoadImagesFromPath":"Load Images From Path ♾️Mixlab",
    "LoadImagesFromURL":"Load Images From URL ♾️Mixlab",
    "LoadImagesToBatch":"Load Images(base64) ♾️Mixlab",
    "TextImage":"Text Image ♾️Mixlab",
    "EnhanceImage":"Enhance Image ♾️Mixlab",
    "SvgImage":"Svg Image ♾️Mixlab",
    "ImageListToBatch_":"Image List To Batch ♾️Mixlab",
    "ImageBatchToList_":"Image Batch To List ♾️Mixlab",
    "ImageCropByAlpha":"ImageCropByAlpha ♾️Mixlab",
    "GetImageSize_":"Get Image Size ♾️Mixlab",

    # 3D
    "3DImage":"3DImage ♾️Mixlab",
    "DepthViewer": "Depth Viewer ♾️Mixlab",

    # "VAELoaderConsistencyDecoder":"Consistency Decoder Loader",
    # "VAEDecodeConsistencyDecoder":"Consistency Decoder Decode",

    # Color
    "ImageColorTransfer":"Image Color Transfer ♾️Mixlab",
    "Color":"Color Input ♾️MixlabApp",

    # Layer
    "ShowLayer":"Show Layer ♾️Mixlab",
    "NewLayer":"New Layer ♾️Mixlab",
    "MergeLayers":"Merge Layers ♾️Mixlab",
    "CompositeImages_":"Composite Images ♾️Mixlab",
    "SplitImage":"Split Image ♾️Mixlab",
    "CenterImage":"Center Image ♾️Mixlab",
    "GridDisplayAndSave":"Grid Display And Save ♾️Mixlab",
    "GridOutput":"Grid Output ♾️Mixlab",

    # Mask
    "SplitLongMask":"Splitting a long image into sections",
    "FeatheredMask":"Feathered Mask ♾️Mixlab",
    "SmoothMask":"Smooth Mask ♾️Mixlab",
    "FaceToMask":"Face To Mask ♾️Mixlab",
    "AreaToMask":"Area To Mask ♾️Mixlab",
    "OutlineMask":"Outline Mask ♾️Mixlab",
    "MaskListMerge_":"MaskList to Mask ♾️Mixlab",
    "PreviewMask_":"Preview Mask ♾️Mixlab",

    # Screen
    "ScreenShare":"Screen Share ♾️Mixlab",
    "FloatingVideo":"Floating Video ♾️Mixlab",

    # Audio
    "SpeechSynthesis":"SpeechSynthesis ♾️Mixlab",
    "SpeechRecognition":"SpeechRecognition ♾️Mixlab",
    "AudioPlay":"Preview Audio ♾️Mixlab",
    "AnalyzeAudio":"Analyze Audio ♾️Mixlab",

    # Utils
    "DynamicDelayProcessor":"DynamicDelayByText ♾️Mixlab",
    "MultiplicationNode":"Math Operation ♾️Mixlab",
    "ListSplit_":"Split List ♾️Mixlab",
    "SwitchByIndex":"List Switch By Index ♾️Mixlab",
    "CreateJsonNode":"Create Json",

    # "GamePal":"GamePal ♾️Mixlab",
    # Experiment
    "Seed_":"CreateSeedNode ♾️Mixlab",
    "CkptNames_":"CreateCkptNames ♾️Mixlab",
    "SamplerNames_":"CreateSampler_names ♾️Mixlab",
    "LoraNames_":"LoraName ♾️Mixlab",

    # Style
    "ApplyVisualStylePrompting_":"Apply VisualStyle Prompting ♾️Mixlab",
    "StyleAlignedReferenceSampler_": "StyleAligned Reference Sampler ♾️Mixlab",
    "StyleAlignedSampleReferenceLatents_": "StyleAligned Sample Reference Latents ♾️Mixlab",
    "StyleAlignedBatchAlign_": "StyleAligned Batch Align ♾️Mixlab",

    # Video
    "MaskListReplace_":"MaskList Replace ♾️Mixlab",
    "IncrementingListNode_":"Create Incrementing Number List ♾️Mixlab",
    "LoadVideoAndSegment_":"Load Video And Segment ♾️Mixlab",
    "VideoCombine_Adv":"Video Combine ♾️Mixlab",
    "ImageListReplace_":"ImageList Replace ♾️Mixlab",

    "P5Input":"P5 Input ♾️Mixlab for test"
}

# web ui的节点功能
WEB_DIRECTORY = "./web"

logging.info('--------------')
logging.info('\033[91m ### Mixlab Nodes: \033[93mLoaded')
# print('\033[91m ### Mixlab Nodes: \033[93mLoaded')

try:
    from .nodes.ChatGPT import SimulateDevDesignDiscussions,SiliconflowTextToImageNode,JsonRepair,ChatGPTNode,ShowTextForGPT,CharacterInText,TextSplitByDelimiter,SiliconflowFreeNode
    logging.info('ChatGPT.available True')

    NODE_CLASS_MAPPINGS_V = {
       "ChatGPTOpenAI":ChatGPTNode,
       "SiliconflowLLM":SiliconflowFreeNode,
       "SiliconflowTextToImageNode":SiliconflowTextToImageNode,
        "ShowTextForGPT":ShowTextForGPT,
        "CharacterInText":CharacterInText,
        "TextSplitByDelimiter":TextSplitByDelimiter,
        "JsonRepair":JsonRepair,

        "SimulateDevDesignDiscussions":SimulateDevDesignDiscussions
    }

    # 一个包含节点友好/可读的标题的字典
    NODE_DISPLAY_NAME_MAPPINGS_V = {
        "ChatGPTOpenAI":"ChatGPT & Local LLM ♾️Mixlab",
        "SiliconflowLLM":"LLM Siliconflow ♾️Mixlab",
        "SiliconflowTextToImageNode":"TextToImage Siliconflow ♾️Mixlab",
        "ShowTextForGPT":"Show Text ♾️MixlabApp",
        "CharacterInText":"Character In Text",
        "TextSplitByDelimiter":"Text Split By Delimiter",
        "JsonRepair":"Json Repair",

        "SimulateDevDesignDiscussions":"SimulateDevDesignDiscussions ♾️Mixlab Podcast"
    }


    NODE_CLASS_MAPPINGS.update(NODE_CLASS_MAPPINGS_V)
    NODE_DISPLAY_NAME_MAPPINGS.update(NODE_DISPLAY_NAME_MAPPINGS_V)

except Exception as e:
    logging.info('ChatGPT.available False')


try:
    from .nodes.edit_mask import EditMask
    logging.info('edit_mask.available True')
    NODE_CLASS_MAPPINGS['EditMask']=EditMask
    NODE_DISPLAY_NAME_MAPPINGS['EditMask']="Edit Mask ♾️Mixlab"
except Exception as e:
    logging.info('edit_mask.available False')

try:
    is_has=is_installed('simple_lama_inpainting',None,False)
    if is_has:
        from .nodes.Lama import LaMaInpainting
        logging.info('LaMaInpainting.available {}'.format(LaMaInpainting.available))
        if LaMaInpainting.available:
            NODE_CLASS_MAPPINGS['LaMaInpainting']=LaMaInpainting
            NODE_DISPLAY_NAME_MAPPINGS['LaMaInpainting']="LaMaInpainting ♾️Mixlab"
except Exception as e:
    logging.info('LaMaInpainting.available False')

try:
    from .nodes.ClipInterrogator import ClipInterrogator
    logging.info('ClipInterrogator.available {}'.format(ClipInterrogator.available))
    if ClipInterrogator.available:
        NODE_CLASS_MAPPINGS['ClipInterrogator']=ClipInterrogator
        NODE_DISPLAY_NAME_MAPPINGS['ClipInterrogator']="Clip Interrogator ♾️Mixlab"
except Exception as e:
    logging.info('ClipInterrogator.available False')

try:
    from .nodes.TextGenerateNode import PromptGenerate,ChinesePrompt
    logging.info('PromptGenerate.available {}'.format(PromptGenerate.available))
    if PromptGenerate.available:
        NODE_CLASS_MAPPINGS['PromptGenerate_Mix']=PromptGenerate
    logging.info('ChinesePrompt.available {}'.format(ChinesePrompt.available))
    if ChinesePrompt.available:
        NODE_CLASS_MAPPINGS['ChinesePrompt_Mix']=ChinesePrompt
except Exception as e:
    logging.info('TextGenerateNode.available False')

try:
    from .nodes.RembgNode import RembgNode_
    logging.info('RembgNode_.available {}'.format(RembgNode_.available))
    if RembgNode_.available:
        NODE_CLASS_MAPPINGS['RembgNode_Mix']=RembgNode_
        NODE_DISPLAY_NAME_MAPPINGS['RembgNode_Mix']="Remove Background ♾️Mixlab"
except Exception as e:
    logging.info('RembgNode_.available False' )


try:
    from .nodes.Video import GenerateFramesByCount,scenesNode_,CombineAudioVideo,VideoCombine_Adv,LoadVideoAndSegment,ImageListReplace,VAEEncodeForInpaint_Frames,LoadAndCombinedAudio_

    NODE_CLASS_MAPPINGS_V = {
        "VAEEncodeForInpaint_Frames":VAEEncodeForInpaint_Frames,
        "ImageListReplace_":ImageListReplace,
        "LoadVideoAndSegment_":LoadVideoAndSegment,
        "VideoCombine_Adv":VideoCombine_Adv,
        "LoadAndCombinedAudio_":LoadAndCombinedAudio_,
        "CombineAudioVideo":CombineAudioVideo,
        "ScenesNode_":scenesNode_,
        "GenerateFramesByCount":GenerateFramesByCount
    }

    # 一个包含节点友好/可读的标题的字典
    NODE_DISPLAY_NAME_MAPPINGS_V = {
        "VAEEncodeForInpaint_Frames":"VAE Encode For Inpaint Frames ♾️Mixlab",
        "ImageListReplace_":"Image List Replace",
        "LoadVideoAndSegment_":"Load Video And Segment",
        "VideoCombine_Adv":"Video Combine",
        "LoadAndCombinedAudio_":"Load And Combined Audio",
        "CombineAudioVideo":"Combine Audio Video",
        "ScenesNode_":"Select Scene",
        "GenerateFramesByCount":"Generate Frames By Count"
    }


    NODE_CLASS_MAPPINGS.update(NODE_CLASS_MAPPINGS_V)
    NODE_DISPLAY_NAME_MAPPINGS.update(NODE_DISPLAY_NAME_MAPPINGS_V)

except:
    logging.info('Video.available False')


try:
    from .nodes.TripoSR import LoadTripoSRModel,TripoSRSampler,SaveTripoSRMesh
    logging.info('TripoSR.available')
    # logging.info( folder_paths.get_temp_directory())
    NODE_CLASS_MAPPINGS['LoadTripoSRModel_']=LoadTripoSRModel
    NODE_DISPLAY_NAME_MAPPINGS["LoadTripoSRModel_"]= "Load TripoSR Model"

    NODE_CLASS_MAPPINGS['TripoSRSampler_']=TripoSRSampler
    NODE_DISPLAY_NAME_MAPPINGS["TripoSRSampler_"]= "TripoSR Sampler"

    NODE_CLASS_MAPPINGS['SaveTripoSRMesh']=SaveTripoSRMesh
    NODE_DISPLAY_NAME_MAPPINGS["SaveTripoSRMesh"]= "Save TripoSR Mesh"


except Exception as e:
    logging.info('TripoSR.available False' )

try:
    from .nodes.MiniCPMNode import MiniCPM_VQA_Simple
    logging.info('MiniCPMNode.available')
    # logging.info( folder_paths.get_temp_directory())
    NODE_CLASS_MAPPINGS['MiniCPM_VQA_Simple']=MiniCPM_VQA_Simple
    NODE_DISPLAY_NAME_MAPPINGS["MiniCPM_VQA_Simple"]= "MiniCPM VQA Simple"

except Exception as e:
    logging.info('MiniCPMNode.available False' )


try:
    from .nodes.scenedetectNode import ScenedetectNode_,SceneInfoNode
    logging.info('Scenedetect.available')
    NODE_CLASS_MAPPINGS['ScenedetectNode_']=ScenedetectNode_
    NODE_CLASS_MAPPINGS['SceneInfoNode']=SceneInfoNode
    NODE_DISPLAY_NAME_MAPPINGS["ScenedetectNode_"]= "Video Scene Detect"
    NODE_DISPLAY_NAME_MAPPINGS["SceneInfoNode"]= "Scene Info"

except Exception as e:
    logging.info('Scenedetect.available False' )


try:
    from .nodes.FishSpeech import LoadVQGAN,AudioToPrompt,Prompt2Semantic,Semantic2Audio
    logging.info('FishSpeech.available')
    NODE_CLASS_MAPPINGS['LoadVQGAN']=LoadVQGAN 
    NODE_CLASS_MAPPINGS['AudioToPrompt']=AudioToPrompt
    NODE_CLASS_MAPPINGS['Prompt2Semantic']=Prompt2Semantic
    NODE_CLASS_MAPPINGS['Semantic2Audio']=Semantic2Audio
    NODE_DISPLAY_NAME_MAPPINGS["LoadVQGAN"]= "Load VQGAN" 
    NODE_DISPLAY_NAME_MAPPINGS["AudioToPrompt"]= "Audio To Prompt"
    NODE_DISPLAY_NAME_MAPPINGS["Prompt2Semantic"]= "Prompt To Semantic"
    NODE_DISPLAY_NAME_MAPPINGS["Semantic2Audio"]= "Semantic To Audio"

except Exception as e:
    logging.info('FishSpeech.available False' )

try:
    from .nodes.SenseVoice import SenseVoiceNode
    logging.info('SenseVoice.available')
    NODE_CLASS_MAPPINGS['SenseVoiceNode']=SenseVoiceNode
    NODE_DISPLAY_NAME_MAPPINGS["SenseVoiceNode"]= "Sense Voice ♾️Mixlab"

except Exception as e:
    logging.info('SenseVoice.available False' )  

try:
    from .nodes.Whisper import LoadWhisperModel,WhisperTranscribe
    logging.info('Whisper.available')
    NODE_CLASS_MAPPINGS['LoadWhisperModel_']=LoadWhisperModel
    NODE_CLASS_MAPPINGS['WhisperTranscribe_']=WhisperTranscribe
    NODE_DISPLAY_NAME_MAPPINGS["LoadWhisperModel_"]= "Load Whisper Model ♾️Mixlab"
    NODE_DISPLAY_NAME_MAPPINGS["WhisperTranscribe_"]= "Whisper Transcribe ♾️Mixlab"

except Exception as e:
    logging.info('Whisper.available False' )  


try:
    from .nodes.FalVideo import VideoGenKlingNode,VideoGenLumaDreamMachineNode,VideoGenRunwayGen3Node,LoadVideoFromURL
    logging.info('FalVideo.available')
    # Update Node class mappings
    NODE_CLASS_MAPPINGS['VideoGenKlingNode']=VideoGenKlingNode
    NODE_CLASS_MAPPINGS['VideoGenRunwayGen3Node']=VideoGenRunwayGen3Node
    NODE_CLASS_MAPPINGS['VideoGenLumaDreamMachineNode']=VideoGenLumaDreamMachineNode
    NODE_CLASS_MAPPINGS['LoadVideoFromURL']=LoadVideoFromURL
    
    NODE_DISPLAY_NAME_MAPPINGS["VideoGenKlingNode"]=  "Kling Video Generation @fal"
    NODE_DISPLAY_NAME_MAPPINGS["VideoGenRunwayGen3Node"]= "Runway Gen3 Image-to-Video @fal"
    NODE_DISPLAY_NAME_MAPPINGS["VideoGenLumaDreamMachineNode"]= "Luma Dream Machine @fal"
    NODE_DISPLAY_NAME_MAPPINGS["LoadVideoFromURL"]= "Load Video from URL"
    

except Exception as e:
    logging.info('FalVideo.available False' )  

logging.info('\033[93m -------------- \033[0m')
