import json import re import time import aiohttp import server from aiohttp import web from collections import deque from .install import * import os import uuid import hashlib import platform import stat import urllib.request import numpy as np from .wss import thread_run, update_worker_flow from .public import ( get_port_from_cmdline, set_token, get_token, get_version, find_project_root, args, get_client_id, ) import threading import folder_paths from PIL import Image input_directory = ( args.input_directory if args.input_directory else find_project_root() + "input" ) def get_mac_address(): mac = uuid.getnode() return ":".join(("%012X" % mac)[i : i + 2] for i in range(0, 12, 2)) def generate_unique_subdomain(mac_address, port): unique_key = f"{mac_address}:{port}" hash_object = hashlib.sha256(unique_key.encode()) subdomain = hash_object.hexdigest()[:12] return subdomain def set_executable_permission(file_path): try: st = os.stat(file_path) os.chmod(file_path, st.st_mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH) print(f"Execution permissions set on {file_path}") except Exception as e: print(f"Failed to set execution permissions: {e}") def download_file(url, dest_path): try: with urllib.request.urlopen(url) as response, open(dest_path, "wb") as out_file: data = response.read() out_file.write(data) print(f"File downloaded successfully: {dest_path}") except Exception as e: print(f"Failed to download the file: {e}") PLUGIN_DIR = os.path.dirname(os.path.abspath(__file__)) SD_CLIENT_DIR = os.path.join(PLUGIN_DIR, "sdc") SDC_EXECUTABLE = os.path.join( SD_CLIENT_DIR, "sdc" if platform.system() != "Windows" else "sdc.exe" ) INI_FILE = os.path.join(SD_CLIENT_DIR, "sdc.toml") LOG_FILE = os.path.join(SD_CLIENT_DIR, "sdc.log") subdomain = "" thread_run() def extract_and_verify_images(output): results = {} app_img_keys = [] for key, node in output.items(): if node["class_type"] == "DeployCash": inputs = node.get("inputs", {}) for k, v in inputs.items(): if k.startswith("app_img") and isinstance(v, list) and len(v) > 0: app_img_keys.append((k, v[0])) err = 0 err_msg = "" for app_img_key, img_key in app_img_keys: if str(img_key) in output: image_node = output[str(img_key)] image_path = image_node.get("inputs", {}).get("image") if image_path: if verify_image_exists(input_directory + "/" + image_path): results[app_img_key] = { "image_path": image_path, "status": "图片存在", } else: err = err + 1 err_msg = err_msg + f"图片不存在: {app_img_key}\n" else: err = err + 1 err_msg = err_msg + f"图片不存在: {app_img_key}\n" else: err = err + 1 err_msg = err_msg + f"图片不存在: {app_img_key}\n" return {"results": results, "err": err, "err_msg": err_msg} def verify_image_exists(path): if os.path.exists(path): valid_extensions = {".jpg", ".jpeg", ".png", ".gif"} ext = os.path.splitext(path)[1].lower() if ext in valid_extensions: return True return False @server.PromptServer.instance.routes.post("/manager/tech_main") async def tech_zhulu(request): json_data = await request.json() print(1, f"json_data={json_data}\n") if "postData" in json_data and isinstance(json_data["postData"], dict): json_data["postData"]["subdomain"] = subdomain async with aiohttp.ClientSession() as session: json_data["version"] = get_version() techsid = get_token() upload_url = ( "https://aidep.cn/flow/api/upload/?i=66&t=0&v=1.0&from=wxapp&tech_client=wx&c=entry&a=wxapp&tech_client=sj&do=ttapp&m=tech_huise&r=" + json_data["r"] + "&techsid=" + techsid + "&client_id=" + get_client_id() ) print(2, f"upload_url={upload_url}\n") if json_data["r"] == "comfyui.apiv2.upload": output = json_data["postData"]["output"] workflow = json_data["postData"]["workflow"] try: output_verify = extract_and_verify_images(output) if output_verify["err"] > 0: err_info = { "errno": 0, "message": "ERROR", "data": { "data": { "message": output_verify["err_msg"], "code": 0, } }, } return web.Response(status=200, text=json.dumps(err_info)) # json_data["postData"].pop("output") # json_data["postData"].pop("workflow") form_data = aiohttp.FormData() form_data.add_field("json_data", json.dumps(json_data)) if "mainImages" in json_data["postData"]: for item in json_data["postData"]["mainImages"]: with open(input_directory + "/" + item, "rb") as f: file_content = f.read() form_data.add_field( "mainImages", file_content, filename=os.path.basename(item), content_type="application/octet-stream", ) except Exception as e: return web.Response(status=200, text=e) async with session.post(upload_url, data=form_data) as response: try: response_result = await response.text() result = json.loads(response_result) if "data" in result and isinstance(result["data"], dict): if "data" in result["data"] and isinstance( result["data"]["data"], dict ): result_data = result["data"]["data"] print(3, f"techsid={techsid}, code={result_data["code"]}\n") if ( techsid != "" and techsid != "init" and result_data["code"] == 1 ): print(31, f"techsid={techsid}, code={result_data["code"]}\n") await update_worker_flow(result_data["name"], output) await update_worker_flow( result_data["name"], workflow, "workflow/" ) return web.Response( status=response.status, text=response_result ) else: return web.Response( status=response.status, text=await response.text() ) except json.JSONDecodeError as e: return web.Response( status=response.status, text=await response.text() ) else: async with session.post(upload_url, json=json_data) as resp: print(4, f"upload_url={upload_url}, json_data={json_data}\n") if ( resp.status == 200 and resp.headers.get("Content-Type") == "application/json" ): try: other_api_data = await resp.json() result = web.json_response(other_api_data) if len(other_api_data["data"]["data"]["techsid"]) > len("12345"): print(41, f"other_api_data={other_api_data}\n") set_token(other_api_data["data"]["data"]["techsid"]) return result except aiohttp.ContentTypeError: error_text = await resp.text() return web.Response(text=error_text, status=400) if resp.status == 200: try: result = await resp.text() result = json.loads(result) result_data = result["data"] if ( isinstance(result_data, dict) and json_data["r"] == "comfyui.apiv2.code" and "data" in result_data and "techsid" in result_data["data"]["data"] ): if len(result_data["data"]["data"]["techsid"]) > len("12345"): print(42, f"result_data={result_data}\n") set_token(result_data["data"]["data"]["techsid"]) return web.json_response(result) except json.JSONDecodeError as e: return web.Response(status=resp.status, text=await resp.text()) else: return web.Response(status=resp.status, text=await resp.text()) @server.PromptServer.instance.routes.post("/manager/do_wss") async def do_wss(request): pass class DeployCash: def __init__(self): pass @classmethod def INPUT_TYPES(s): return { "required": { "app_title": ( "STRING", { "multiline": False, "default": "这是默认作品标题,请在comfyui中修改", "placeholder": "", }, ), "app_desc": ( "STRING", { "multiline": False, "default": "这是默认功能介绍,请在comfyui中修改", "placeholder": "", }, ), "app_fee": ( "INT", { "default": 18, "min": 0, "max": 999999, "step": 1, "display": "number", }, ), "free_times": ( "INT", { "default": 0, "min": 0, "max": 999999, "step": 1, "display": "number", }, ), }, "optional": { "app_img1(optional)": ("IMAGE",), "app_img2(optional)": ("IMAGE",), "app_img3(optional)": ("IMAGE",), "custom_img1(optional)": ("IMAGE",), "custom_img2(optional)": ("IMAGE",), "custom_img3(optional)": ("IMAGE",), "custom_video1(optional)": ("IMAGE",), "custom_video2(optional)": ("IMAGE",), "custom_video3(optional)": ("IMAGE",), "custom_text1(optional)": ( "STRING", {"multiline": False, "forceInput": True, "dynamicPrompts": False}, ), "custom_text2(optional)": ( "STRING", {"multiline": False, "forceInput": True, "dynamicPrompts": False}, ), "custom_text3(optional)": ( "STRING", {"multiline": False, "forceInput": True, "dynamicPrompts": False}, ), "custom_img1_desc": ( "STRING", {"multiline": False, "default": "请上传图片"}, ), "custom_img2_desc": ( "STRING", {"multiline": False, "default": "请上传图片"}, ), "custom_img3_desc": ( "STRING", {"multiline": False, "default": "请上传图片"}, ), "custom_video1_desc": ( "STRING", {"multiline": False, "default": "请上传视频"}, ), "custom_video2_desc": ( "STRING", {"multiline": False, "default": "请上传视频"}, ), "custom_video3_desc": ( "STRING", {"multiline": False, "default": "请上传视频"}, ), "custom_text1_desc": ( "STRING", {"multiline": False, "default": "请输入文本"}, ), "custom_text2_desc": ( "STRING", {"multiline": False, "default": "请输入文本"}, ), "custom_text3_desc": ( "STRING", {"multiline": False, "default": "请输入文本"}, ), }, "hidden": { "custom_text333333": ( "STRING", {"multiline": False, "default": "输入文本"}, ), }, } RETURN_TYPES = () CATEGORY = "DeployCash" class DeployCash_textInput: def __init__(self): pass @classmethod def INPUT_TYPES(s): return { "required": { "text": ( "STRING", {"default": "", "multiline": True, "placeholder": "文本输入"}, ), } } RETURN_TYPES = ("STRING",) FUNCTION = "main" CATEGORY = "DeployCash" @staticmethod def main(text): return (text,) class DeployCash_saveImage: def __init__(self): self.output_dir = folder_paths.get_output_directory() self.type = "output" self.prefix_append = "" self.compress_level = 4 @classmethod def INPUT_TYPES(s): return { "required": { "images": ("IMAGE",), "filename_prefix": ("STRING", {"default": "ComfyUI"}), }, } RETURN_TYPES = () FUNCTION = "save_images" OUTPUT_NODE = True CATEGORY = "DeployCash" def save_images(self, images, filename_prefix="DeployCash"): filename_prefix += self.prefix_append full_output_folder, filename, counter, subfolder, filename_prefix = ( folder_paths.get_save_image_path( filename_prefix, self.output_dir, images[0].shape[1], images[0].shape[0] ) ) results = list() for batch_number, image in enumerate(images): i = 255.0 * image.cpu().numpy() img = Image.fromarray(np.clip(i, 0, 255).astype(np.uint8)) metadata = None filename_with_batch_num = filename.replace("%batch_num%", str(batch_number)) file = f"DeployCash_{filename_with_batch_num}_{counter:05}_.png" img.save( os.path.join(full_output_folder, file), pnginfo=metadata, compress_level=self.compress_level, ) results.append( {"filename": file, "subfolder": subfolder, "type": self.type} ) counter += 1 return {"ui": {"images": results}} workspace_path = os.path.join(os.path.dirname(__file__)) dist_path = os.path.join(workspace_path, "huise_admin") if os.path.exists(dist_path): server.PromptServer.instance.app.add_routes( [ web.static("/huise_admin/", dist_path), ] ) WEB_DIRECTORY = "./web" NODE_CLASS_MAPPINGS = { "DeployCash": DeployCash, "DeployCash_textInput": DeployCash_textInput, "DeployCash_saveImage": DeployCash_saveImage, } NODE_DISPLAY_NAME_MAPPINGS = { "DeployCash": "DeployCash", "DeployCash_textInput": "textInput", "DeployCash_saveImage": "saveImage", }