diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..35410ca --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# 默认忽略的文件 +/shelf/ +/workspace.xml +# 基于编辑器的 HTTP 客户端请求 +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 0000000..d93e1eb --- /dev/null +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,13 @@ + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml new file mode 100644 index 0000000..105ce2d --- /dev/null +++ b/.idea/inspectionProfiles/profiles_settings.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..b7d0c18 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/.idea/modalDeploy.iml b/.idea/modalDeploy.iml new file mode 100644 index 0000000..6fd4e9e --- /dev/null +++ b/.idea/modalDeploy.iml @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..f4632ae --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/server_with_s3.py b/server_with_s3.py index 6e8935a..eba0821 100644 --- a/server_with_s3.py +++ b/server_with_s3.py @@ -1,5 +1,6 @@ import json import os +import shutil import subprocess import uuid from pathlib import Path @@ -7,7 +8,6 @@ from typing import Dict import modal - image = ( # build up a Modal Image to run ComfyUI, step by step modal.Image.debian_slim( # start from basic Linux with Python python_version="3.10" @@ -25,7 +25,7 @@ image = ( # build up a Modal Image to run ComfyUI, step by step .pip_install("opencv-python") .run_commands( # use comfy-cli to install ComfyUI and its dependencies "comfy --skip-prompt install --nvidia --version 0.3.10" - ).add_local_file("snapshot.json","/root/snapshot.json", copy=True) + ) ) image = ( @@ -60,14 +60,14 @@ image = ( "rm -rf /root/comfy/ComfyUI/models" ).run_commands( "apt update && apt install -y ffmpeg && ffmpeg -version" - ).pip_install("av") + ).pip_install( + "av" + ).run_commands( + "comfy node install https://e.coding.net/g-ldyi2063/dev/ComfyUI-FFmpeg.git" + ) # Add .run_commands(...) calls for any other custom nodes you want to download ) -image = image.add_local_file( - "highlight_v0.113_api.json", "/root/workflow_api.json" -) - app = modal.App(name="highlight-comfyui-s3", image=image) vol = modal.Volume.from_name("comfyui-model", create_if_missing=True) bucket_dict = modal.Dict.from_name("aws_s3_bucket", create_if_missing=True) @@ -77,26 +77,28 @@ secret = modal.Secret.from_name("aws-s3-secret") # completed workflows write output images to this directory output_dir = "/root/comfy/ComfyUI/output" + @app.cls( allow_concurrent_inputs=1, # allow 10 concurrent API calls concurrency_limit=50, - container_idle_timeout=120, # 5 minute container keep alive after it processes an input; increasing this value is a great way to reduce ComfyUI cold start times + container_idle_timeout=120, + # 5 minute container keep alive after it processes an input; increasing this value is a great way to reduce ComfyUI cold start times timeout=800, gpu="T4", secrets=[secret], volumes={ "/root/comfy/ComfyUI/models": vol, - "/root/comfy/ComfyUI/input": modal.CloudBucketMount( + "/root/comfy/ComfyUI/input_s3": modal.CloudBucketMount( bucket_name=bucket_input, # bucket_endpoint_url="https://s3.%s.amazonaws.com" % os.environ["AWS_REGION"], secret=secret, - key_prefix="comfyui/" + key_prefix="/" ), - "/root/comfy/ComfyUI/output": modal.CloudBucketMount( + "/root/comfy/ComfyUI/output_s3": modal.CloudBucketMount( bucket_name=bucket_output, # bucket_endpoint_url="https://s3.%s.amazonaws.com" % os.environ["AWS_REGION"], secret=secret, - key_prefix="comfyui/" + key_prefix="/" ), }, ) @@ -111,14 +113,23 @@ class ComfyUI: def infer(self, workflow_json: str = ""): # runs the comfy run --workflow command as a subprocess session_id = str(uuid.uuid4()) + workflow = json.loads(workflow_json) + file_to_move = None + for node in workflow.values(): + if node.get("class_type") == "ComfyUIDeployExternalText": + if node.get("inputs").get("input_id") == "file_path": + file_to_move = node.get("inputs").get("default_value") + if file_to_move: + os.makedirs(os.path.dirname(file_to_move.replace("input_s3", "input")), exist_ok=True) + shutil.copy(file_to_move, file_to_move.replace("input_s3", "input")) + node["inputs"]["default_value"] = node["inputs"]["default_value"].replace("input_s3", "input") with open(f"/root/{session_id}.json", "w", encoding="utf-8") as f: - f.write(workflow_json) + f.write(json.dumps(workflow, ensure_ascii=False)) cmd = f"comfy run --workflow /root/{session_id}.json --wait --timeout 1200" # TODO 接收返回值 subprocess.run(cmd, shell=True, check=True) # looks up the name of the output image file based on the workflow - workflow = json.loads(workflow_json) file_prefix = [ node.get("inputs") for node in workflow.values() @@ -128,10 +139,13 @@ class ComfyUI: # returns the image as bytes file_list = os.listdir(output_dir) # 获取按照文件时间创建排序的列表,默认是按时间升序 - new_file_list = sorted(file_list, key=lambda file: os.path.getctime(os.path.join(output_dir, file)), reverse=True) + new_file_list = sorted(file_list, key=lambda file: os.path.getctime(os.path.join(output_dir, file)), + reverse=True) # print("file_list", new_file_list) for f in new_file_list: if f.startswith(file_prefix): + os.makedirs(os.path.dirname(os.path.join(output_dir.replace("output","output_s3"), f)), exist_ok=True) + shutil.copy(os.path.join(output_dir, f), os.path.join(output_dir.replace("output","output_s3"), f)) return f @modal.web_endpoint(method="POST") @@ -144,7 +158,7 @@ class ComfyUI: # run inference on the currently running container fname = self.infer.local(new_workflow_file) j = { - "file_name": os.path.join("comfyui",fname) + "file_name": fname } print("json", j)