ADD 增加HeyGem APP
ADD 增加包含HeyGem的ComfyUI APP
This commit is contained in:
@@ -1,22 +0,0 @@
|
|||||||
services:
|
|
||||||
comfyui-service:
|
|
||||||
image: comfyui-image:v1.2
|
|
||||||
container_name: comfyui
|
|
||||||
ports:
|
|
||||||
- 8188:8188
|
|
||||||
ipc: host
|
|
||||||
deploy:
|
|
||||||
resources:
|
|
||||||
limits:
|
|
||||||
memory: 64000M
|
|
||||||
reservations:
|
|
||||||
devices:
|
|
||||||
- driver: nvidia
|
|
||||||
count: 1
|
|
||||||
capabilities: [ gpu ]
|
|
||||||
volumes:
|
|
||||||
#- ./custom_nodes:/app/ComfyUI/custom_nodes
|
|
||||||
- E://models:/root/comfy/ComfyUI/models
|
|
||||||
- E://comfy//ComfyUI//input:/root/comfy/ComfyUI/input
|
|
||||||
# - s3:/app/ComfyUI/input_s3
|
|
||||||
#- s3:/app/ComfyUI/output_s3
|
|
||||||
134
dockerfile
134
dockerfile
@@ -1,134 +0,0 @@
|
|||||||
# 使用 Debian Slim 作为基础镜像
|
|
||||||
FROM python:3.10-slim
|
|
||||||
|
|
||||||
# 创建并配置腾讯云的 apt 源
|
|
||||||
RUN apt update
|
|
||||||
RUN apt install -y wget
|
|
||||||
RUN wget https://linuxmirrors.cn/main.sh
|
|
||||||
RUN bash main.sh --source mirrors.cloud.tencent.com
|
|
||||||
|
|
||||||
RUN apt update
|
|
||||||
|
|
||||||
# 替换 pip 源为阿里云
|
|
||||||
RUN pip config set global.index-url https://mirrors.aliyun.com/pypi/simple/
|
|
||||||
|
|
||||||
# 安装 git
|
|
||||||
RUN apt-get update && apt-get install -y git
|
|
||||||
|
|
||||||
# 安装 Python 依赖
|
|
||||||
RUN pip install fastapi[standard]==0.115.4 \
|
|
||||||
comfy-cli==1.3.5 \
|
|
||||||
cos-python-sdk-v5 \
|
|
||||||
sqlalchemy \
|
|
||||||
ultralytics \
|
|
||||||
tencentcloud-sdk-python \
|
|
||||||
pymysql \
|
|
||||||
Pillow \
|
|
||||||
ffmpy \
|
|
||||||
opencv-python \
|
|
||||||
av \
|
|
||||||
imageio \
|
|
||||||
loguru
|
|
||||||
|
|
||||||
# 安装 ComfyUI 及其依赖
|
|
||||||
RUN comfy --skip-prompt install --nvidia --version 0.3.10
|
|
||||||
|
|
||||||
# 克隆并安装自定义节点
|
|
||||||
RUN git clone https://github.com/M1kep/ComfyLiterals /root/comfy/ComfyUI/custom_nodes/ComfyLiterals && \
|
|
||||||
if [ -f /root/comfy/ComfyUI/custom_nodes/ComfyLiterals/requirements.txt ]; then pip install -r /root/comfy/ComfyUI/custom_nodes/ComfyLiterals/requirements.txt; fi
|
|
||||||
|
|
||||||
RUN git clone https://github.com/evanspearman/ComfyMath /root/comfy/ComfyUI/custom_nodes/ComfyMath && \
|
|
||||||
if [ -f /root/comfy/ComfyUI/custom_nodes/ComfyMath/requirements.txt ]; then pip install -r /root/comfy/ComfyUI/custom_nodes/ComfyMath/requirements.txt; fi
|
|
||||||
|
|
||||||
RUN git clone https://github.com/Kosinkadink/ComfyUI-AnimateDiff-Evolved /root/comfy/ComfyUI/custom_nodes/ComfyUI-AnimateDiff-Evolved && \
|
|
||||||
if [ -f /root/comfy/ComfyUI/custom_nodes/ComfyUI-AnimateDiff-Evolved/requirements.txt ]; then pip install -r /root/comfy/ComfyUI/custom_nodes/ComfyUI-AnimateDiff-Evolved/requirements.txt; fi
|
|
||||||
|
|
||||||
RUN git clone https://e.coding.net/g-ldyi2063/dev/ComfyUI-Bowong.git /root/comfy/ComfyUI/custom_nodes/ComfyUI-Bowong && \
|
|
||||||
if [ -f /root/comfy/ComfyUI/custom_nodes/ComfyUI-Bowong/requirements.txt ]; then pip install -r /root/comfy/ComfyUI/custom_nodes/ComfyUI-Bowong/requirements.txt; fi
|
|
||||||
|
|
||||||
RUN git clone https://github.com/crystian/ComfyUI-Crystools /root/comfy/ComfyUI/custom_nodes/ComfyUI-Crystools && \
|
|
||||||
if [ -f /root/comfy/ComfyUI/custom_nodes/ComfyUI-Crystools/requirements.txt ]; then pip install -r /root/comfy/ComfyUI/custom_nodes/ComfyUI-Crystools/requirements.txt; fi
|
|
||||||
|
|
||||||
RUN git clone https://github.com/pythongosssss/ComfyUI-Custom-Scripts /root/comfy/ComfyUI/custom_nodes/ComfyUI-Custom-Scripts && \
|
|
||||||
if [ -f /root/comfy/ComfyUI/custom_nodes/ComfyUI-Custom-Scripts/requirements.txt ]; then pip install -r /root/comfy/ComfyUI/custom_nodes/ComfyUI-Custom-Scripts/requirements.txt; fi
|
|
||||||
|
|
||||||
RUN git clone https://github.com/BennyKok/comfyui-deploy /root/comfy/ComfyUI/custom_nodes/comfyui-deploy && \
|
|
||||||
if [ -f /root/comfy/ComfyUI/custom_nodes/comfyui-deploy/requirements.txt ]; then pip install -r /root/comfy/ComfyUI/custom_nodes/comfyui-deploy/requirements.txt; fi
|
|
||||||
|
|
||||||
RUN git clone https://github.com/yolain/ComfyUI-Easy-Use /root/comfy/ComfyUI/custom_nodes/ComfyUI-Easy-Use && \
|
|
||||||
if [ -f /root/comfy/ComfyUI/custom_nodes/ComfyUI-Easy-Use/requirements.txt ]; then pip install -r /root/comfy/ComfyUI/custom_nodes/ComfyUI-Easy-Use/requirements.txt; fi
|
|
||||||
|
|
||||||
RUN git clone https://e.coding.net/g-ldyi2063/dev/ComfyUI-VideoHelperSuite.git /root/comfy/ComfyUI/custom_nodes/ComfyUI-VideoHelperSuite && \
|
|
||||||
if [ -f /root/comfy/ComfyUI/custom_nodes/ComfyUI-VideoHelperSuite/requirements.txt ]; then pip install -r /root/comfy/ComfyUI/custom_nodes/ComfyUI-VideoHelperSuite/requirements.txt; fi
|
|
||||||
|
|
||||||
#防止依赖安装问题
|
|
||||||
RUN pip install conformer==0.3.2 einops>0.6.1 --no-dependencies
|
|
||||||
|
|
||||||
RUN pip install -U openai-whisper
|
|
||||||
|
|
||||||
RUN apt install --reinstall -y gcc
|
|
||||||
|
|
||||||
RUN git clone https://e.coding.net/g-ldyi2063/dev/CosyVoice-ComfyUI.git /root/comfy/ComfyUI/custom_nodes/CosyVoice-ComfyUI && \
|
|
||||||
if [ -f /root/comfy/ComfyUI/custom_nodes/CosyVoice-ComfyUI/requirements.txt ]; then pip install -r /root/comfy/ComfyUI/custom_nodes/CosyVoice-ComfyUI/requirements.txt; fi
|
|
||||||
|
|
||||||
|
|
||||||
RUN git clone https://github.com/jags111/efficiency-nodes-comfyui /root/comfy/ComfyUI/custom_nodes/efficiency-nodes-comfyui && \
|
|
||||||
if [ -f /root/comfy/ComfyUI/custom_nodes/efficiency-nodes-comfyui/requirements.txt ]; then pip install -r /root/comfy/ComfyUI/custom_nodes/efficiency-nodes-comfyui/requirements.txt; fi
|
|
||||||
|
|
||||||
RUN git clone https://github.com/WASasquatch/was-node-suite-comfyui /root/comfy/ComfyUI/custom_nodes/was-node-suite-comfyui && \
|
|
||||||
if [ -f /root/comfy/ComfyUI/custom_nodes/was-node-suite-comfyui/requirements.txt ]; then pip install -r /root/comfy/ComfyUI/custom_nodes/was-node-suite-comfyui/requirements.txt; fi
|
|
||||||
|
|
||||||
RUN git clone https://github.com/rgthree/rgthree-comfy /root/comfy/ComfyUI/custom_nodes/rgthree-comfy && \
|
|
||||||
if [ -f /root/comfy/ComfyUI/custom_nodes/rgthree-comfy/requirements.txt ]; then pip install -r /root/comfy/ComfyUI/custom_nodes/rgthree-comfy/requirements.txt; fi
|
|
||||||
|
|
||||||
RUN git clone https://github.com/cubiq/ComfyUI_essentials /root/comfy/ComfyUI/custom_nodes/ComfyUI_essentials && \
|
|
||||||
if [ -f /root/comfy/ComfyUI/custom_nodes/ComfyUI_essentials/requirements.txt ]; then pip install -r /root/comfy/ComfyUI/custom_nodes/ComfyUI_essentials/requirements.txt; fi
|
|
||||||
|
|
||||||
RUN git clone https://github.com/melMass/comfy_mtb /root/comfy/ComfyUI/custom_nodes/comfy_mtb && \
|
|
||||||
if [ -f /root/comfy/ComfyUI/custom_nodes/comfy_mtb/requirements.txt ]; then pip install -r /root/comfy/ComfyUI/custom_nodes/comfy_mtb/requirements.txt; fi
|
|
||||||
|
|
||||||
RUN git clone https://e.coding.net/g-ldyi2063/dev/ComfyUI-CustomNode.git /root/comfy/ComfyUI/custom_nodes/ComfyUI-CustomNode && \
|
|
||||||
if [ -f /root/comfy/ComfyUI/custom_nodes/ComfyUI-CustomNode/requirements.txt ]; then pip install -r /root/comfy/ComfyUI/custom_nodes/ComfyUI-CustomNode/requirements.txt; fi
|
|
||||||
|
|
||||||
RUN git clone https://e.coding.net/g-ldyi2063/dev/ComfyUI-LatentSync-Node.git /root/comfy/ComfyUI/custom_nodes/ComfyUI-LatentSync-Node && \
|
|
||||||
if [ -f /root/comfy/ComfyUI/custom_nodes/ComfyUI-LatentSync-Node/requirements.txt ]; then pip install -r /root/comfy/ComfyUI/custom_nodes/ComfyUI-LatentSync-Node/requirements.txt; fi
|
|
||||||
|
|
||||||
#解决PortAudio library not found问题
|
|
||||||
RUN apt-get install -y libportaudio2
|
|
||||||
|
|
||||||
RUN git clone https://e.coding.net/g-ldyi2063/dev/ComfyUI_SparkTTS.git /root/comfy/ComfyUI/custom_nodes/ComfyUI_SparkTTS && \
|
|
||||||
if [ -f /root/comfy/ComfyUI/custom_nodes/ComfyUI_SparkTTS/requirements.txt ]; then pip install -r /root/comfy/ComfyUI/custom_nodes/ComfyUI_SparkTTS/requirements.txt; fi
|
|
||||||
|
|
||||||
# 创建符号链接
|
|
||||||
RUN mkdir -p /root/comfy/ComfyUI/models/ComfyUI-CustomNode/model && \
|
|
||||||
rm -rf /root/comfy/ComfyUI/custom_nodes/ComfyUI-CustomNode/model && \
|
|
||||||
ln -s /root/comfy/ComfyUI/models/ComfyUI-CustomNode/model /root/comfy/ComfyUI/custom_nodes/ComfyUI-CustomNode/model
|
|
||||||
|
|
||||||
RUN mkdir -p /root/comfy/ComfyUI/models/ComfyUI-LatentSync-Node/checkpoints && \
|
|
||||||
rm -rf /root/comfy/ComfyUI/custom_nodes/ComfyUI-LatentSync-Node/checkpoints && \
|
|
||||||
ln -s /root/comfy/ComfyUI/models/ComfyUI-LatentSync-Node/checkpoints /root/comfy/ComfyUI/custom_nodes/ComfyUI-LatentSync-Node/checkpoints
|
|
||||||
|
|
||||||
RUN mkdir -p /root/comfy/ComfyUI/models/CosyVoice-ComfyUI/pretrained_models/CosyVoice-300M && \
|
|
||||||
mkdir -p /root/comfy/ComfyUI/custom_nodes/CosyVoice-ComfyUI/pretrained_models/CosyVoice-300M && \
|
|
||||||
rm -rf /root/comfy/ComfyUI/custom_nodes/CosyVoice-ComfyUI/pretrained_models/CosyVoice-300M && \
|
|
||||||
ln -s /root/comfy/ComfyUI/models/CosyVoice-ComfyUI/pretrained_models/CosyVoice-300M /root/comfy/ComfyUI/custom_nodes/CosyVoice-ComfyUI/pretrained_models/CosyVoice-300M
|
|
||||||
|
|
||||||
RUN mkdir -p /root/comfy/ComfyUI/models/.cache/torch/hub/checkpoints && \
|
|
||||||
mkdir -p /root/.cache/torch/hub/checkpoints && \
|
|
||||||
rm -rf /root/.cache/torch/hub/checkpoints && \
|
|
||||||
ln -s /root/comfy/ComfyUI/models/.cache/torch/hub/checkpoints /root/.cache/torch/hub/checkpoints
|
|
||||||
|
|
||||||
RUN mkdir -p /root/comfy/ComfyUI/models/stabilityai && \
|
|
||||||
ln -s /root/comfy/ComfyUI/models/stabilityai /root/comfy/ComfyUI/stabilityai
|
|
||||||
|
|
||||||
RUN rm -rf /root/comfy/ComfyUI/models
|
|
||||||
|
|
||||||
# 安装 ffmpeg
|
|
||||||
RUN apt-get update && apt-get install -y ffmpeg && ffmpeg -version
|
|
||||||
|
|
||||||
# 添加本地配置文件
|
|
||||||
COPY config.yaml /root/comfy/ComfyUI/custom_nodes/ComfyUI-CustomNode/config.yaml
|
|
||||||
|
|
||||||
WORKDIR /root/comfy
|
|
||||||
|
|
||||||
CMD ["comfy", "--here", "launch", "--", "--listen", "0.0.0.0", "--port", "8188"]
|
|
||||||
@@ -5,7 +5,7 @@ pkg_path = site.getsitepackages()[0]
|
|||||||
sys.path.append(f"{pkg_path}/heygem/code")
|
sys.path.append(f"{pkg_path}/heygem/code")
|
||||||
|
|
||||||
p = subprocess.Popen(f"cd {pkg_path}/heygem/code && "
|
p = subprocess.Popen(f"cd {pkg_path}/heygem/code && "
|
||||||
"python3 app_local.py", shell=True)
|
"python3.8 app_local.py", shell=True)
|
||||||
p.communicate()
|
p.communicate()
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
149
server.py
149
server.py
@@ -1,149 +0,0 @@
|
|||||||
import json
|
|
||||||
import os
|
|
||||||
import subprocess
|
|
||||||
import uuid
|
|
||||||
from pathlib import Path
|
|
||||||
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"
|
|
||||||
)
|
|
||||||
.apt_install("git") # install git to clone ComfyUI
|
|
||||||
.pip_install("fastapi[standard]==0.115.4") # install web dependencies
|
|
||||||
.pip_install("comfy-cli==1.3.5") # install comfy-cli
|
|
||||||
.pip_install("cos-python-sdk-v5")
|
|
||||||
.pip_install("sqlalchemy")
|
|
||||||
.pip_install("ultralytics")
|
|
||||||
.pip_install("tencentcloud-sdk-python")
|
|
||||||
.pip_install("pymysql")
|
|
||||||
.pip_install("Pillow")
|
|
||||||
.pip_install("ffmpy")
|
|
||||||
.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 = (
|
|
||||||
image.run_commands("comfy node install https://github.com/M1kep/ComfyLiterals")
|
|
||||||
.run_commands("comfy node install https://github.com/evanspearman/ComfyMath")
|
|
||||||
.run_commands("comfy node install https://github.com/Kosinkadink/ComfyUI-AnimateDiff-Evolved")
|
|
||||||
.run_commands("comfy node install https://e.coding.net/g-ldyi2063/dev/ComfyUI-Bowong.git")
|
|
||||||
.run_commands("comfy node install https://github.com/crystian/ComfyUI-Crystools")
|
|
||||||
.run_commands("comfy node install https://github.com/pythongosssss/ComfyUI-Custom-Scripts")
|
|
||||||
.run_commands("comfy node install https://e.coding.net/g-ldyi2063/dev/ComfyUI-CustomNode.git")
|
|
||||||
.run_commands("comfy node install https://github.com/BennyKok/comfyui-deploy")
|
|
||||||
.run_commands("comfy node install https://github.com/yolain/ComfyUI-Easy-Use")
|
|
||||||
.run_commands("comfy node install https://e.coding.net/g-ldyi2063/dev/ComfyUI-LatentSync-Node.git")
|
|
||||||
.run_commands("comfy node install https://e.coding.net/g-ldyi2063/dev/ComfyUI-VideoHelperSuite.git")
|
|
||||||
.run_commands("comfy node install https://e.coding.net/g-ldyi2063/dev/CosyVoice-ComfyUI.git")
|
|
||||||
.run_commands("comfy node install https://github.com/jags111/efficiency-nodes-comfyui")
|
|
||||||
.run_commands("comfy node install https://github.com/WASasquatch/was-node-suite-comfyui")
|
|
||||||
.run_commands("comfy node install https://github.com/rgthree/rgthree-comfy")
|
|
||||||
.run_commands("comfy node install https://github.com/cubiq/ComfyUI_essentials")
|
|
||||||
.run_commands("comfy node install https://github.com/melMass/comfy_mtb")
|
|
||||||
.run_commands(
|
|
||||||
"mkdir -p /root/comfy/ComfyUI/models/ComfyUI-CustomNode/model && rm -rf /root/comfy/ComfyUI/custom_nodes/ComfyUI-CustomNode/model && ln -s /root/comfy/ComfyUI/models/ComfyUI-CustomNode/model /root/comfy/ComfyUI/custom_nodes/ComfyUI-CustomNode/model"
|
|
||||||
).run_commands(
|
|
||||||
"mkdir -p /root/comfy/ComfyUI/models/ComfyUI-LatentSync-Node/checkpoints && rm -rf /root/comfy/ComfyUI/custom_nodes/ComfyUI-LatentSync-Node/checkpoints && ln -s /root/comfy/ComfyUI/models/ComfyUI-LatentSync-Node/checkpoints /root/comfy/ComfyUI/custom_nodes/ComfyUI-LatentSync-Node/checkpoints"
|
|
||||||
).run_commands(
|
|
||||||
"mkdir -p /root/comfy/ComfyUI/models/CosyVoice-ComfyUI/pretrained_models/CosyVoice-300M-SFT && mkdir -p /root/comfy/ComfyUI/custom_nodes/CosyVoice-ComfyUI/pretrained_models/CosyVoice-300M-SFT && rm -rf /root/comfy/ComfyUI/custom_nodes/CosyVoice-ComfyUI/pretrained_models/CosyVoice-300M-SFT && ln -s /root/comfy/ComfyUI/models/CosyVoice-ComfyUI/pretrained_models/CosyVoice-300M-SFT /root/comfy/ComfyUI/custom_nodes/CosyVoice-ComfyUI/pretrained_models/CosyVoice-300M-SFT"
|
|
||||||
).run_commands(
|
|
||||||
"mkdir -p /root/comfy/ComfyUI/models/.cache/torch/hub/checkpoints && mkdir -p /root/.cache/torch/hub/checkpoints && rm -rf /root/.cache/torch/hub/checkpoints && ln -s /root/comfy/ComfyUI/models/.cache/torch/hub/checkpoints /root/.cache/torch/hub/checkpoints"
|
|
||||||
).run_commands(
|
|
||||||
"mkdir -p /root/comfy/ComfyUI/models/stabilityai && ln -s /root/comfy/ComfyUI/models/stabilityai /root/comfy/ComfyUI/stabilityai"
|
|
||||||
).run_commands(
|
|
||||||
"rm -rf /root/comfy/ComfyUI/models"
|
|
||||||
).run_commands(
|
|
||||||
"apt update && apt install -y ffmpeg && ffmpeg -version"
|
|
||||||
).pip_install("av")
|
|
||||||
# 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", image=image)
|
|
||||||
vol = modal.Volume.from_name("comfyui-model", create_if_missing=True)
|
|
||||||
secret = modal.Secret.from_name("aws-s3-secret")
|
|
||||||
|
|
||||||
@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
|
|
||||||
timeout=800,
|
|
||||||
gpu="T4",
|
|
||||||
secrets=[secret],
|
|
||||||
volumes={
|
|
||||||
"/root/comfy/ComfyUI/models": vol,
|
|
||||||
# "/root/comfy/ComfyUI/input": modal.CloudBucketMount(
|
|
||||||
# bucket_name=os.environ["BUCKET_INPUT"],
|
|
||||||
# # bucket_endpoint_url="https://s3.%s.amazonaws.com" % os.environ["AWS_REGION"],
|
|
||||||
# secret=secret,
|
|
||||||
# key_prefix="comfyui"
|
|
||||||
# ),
|
|
||||||
# "/root/comfy/ComfyUI/output": modal.CloudBucketMount(
|
|
||||||
# bucket_name=os.environ["BUCKET_OUTPUT"],
|
|
||||||
# # bucket_endpoint_url="https://s3.%s.amazonaws.com" % os.environ["AWS_REGION"],
|
|
||||||
# secret=secret,
|
|
||||||
# key_prefix="comfyui"
|
|
||||||
# ),
|
|
||||||
},
|
|
||||||
)
|
|
||||||
class ComfyUI:
|
|
||||||
@modal.enter()
|
|
||||||
def launch_comfy_background(self):
|
|
||||||
# starts the ComfyUI server in the background exactly once when the first input is received
|
|
||||||
cmd = "comfy launch --background"
|
|
||||||
subprocess.run(cmd, shell=True, check=True)
|
|
||||||
|
|
||||||
@modal.method()
|
|
||||||
def infer(self, workflow_json: str = ""):
|
|
||||||
# runs the comfy run --workflow command as a subprocess
|
|
||||||
session_id = str(uuid.uuid4())
|
|
||||||
with open(f"/root/{session_id}.json", "w", encoding="utf-8") as f:
|
|
||||||
f.write(workflow_json)
|
|
||||||
cmd = f"comfy run --workflow /root/{session_id}.json --wait --timeout 1200"
|
|
||||||
# TODO 接收返回值
|
|
||||||
subprocess.run(cmd, shell=True, check=True)
|
|
||||||
|
|
||||||
# completed workflows write output images to this directory
|
|
||||||
output_dir = "/root/comfy/ComfyUI/output"
|
|
||||||
|
|
||||||
# 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()
|
|
||||||
if node.get("class_type") == "VHS_VideoCombine"
|
|
||||||
][0]["filename_prefix"]
|
|
||||||
|
|
||||||
# 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)
|
|
||||||
print("file_list", new_file_list)
|
|
||||||
for f in new_file_list:
|
|
||||||
if f.startswith(file_prefix):
|
|
||||||
return f
|
|
||||||
|
|
||||||
@modal.web_endpoint(method="POST")
|
|
||||||
def api(self, item: Dict):
|
|
||||||
from fastapi import Response
|
|
||||||
|
|
||||||
# save this updated workflow to a new file
|
|
||||||
new_workflow_file = item["prompt"]
|
|
||||||
|
|
||||||
# run inference on the currently running container
|
|
||||||
fname = self.infer.local(new_workflow_file)
|
|
||||||
j = {
|
|
||||||
"file_name": fname
|
|
||||||
}
|
|
||||||
print("json", j)
|
|
||||||
|
|
||||||
return Response(content=json.dumps(j), media_type="application/json")
|
|
||||||
284
server_pure_heygem.py
Normal file
284
server_pure_heygem.py
Normal file
@@ -0,0 +1,284 @@
|
|||||||
|
# HeyGem模板
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import shutil
|
||||||
|
import socket
|
||||||
|
import subprocess
|
||||||
|
import time
|
||||||
|
import traceback
|
||||||
|
import uuid
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
import httpx
|
||||||
|
import loguru
|
||||||
|
import modal
|
||||||
|
from fastapi import Depends, HTTPException, status, UploadFile
|
||||||
|
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
|
||||||
|
from fastapi.responses import Response, FileResponse
|
||||||
|
|
||||||
|
image = (
|
||||||
|
modal.Image.debian_slim( # start from basic Linux with Python
|
||||||
|
python_version="3.10"
|
||||||
|
).apt_install("git")
|
||||||
|
.apt_install("gcc")
|
||||||
|
.pip_install("loguru")
|
||||||
|
.pip_install("fastapi[standard]")
|
||||||
|
.run_commands(
|
||||||
|
"apt update && apt install -y ffmpeg && ffmpeg -version"
|
||||||
|
)
|
||||||
|
# 添加Python3.8 HeyGem
|
||||||
|
.run_commands("apt update && apt install -y curl build-essential libssl-dev zlib1g-dev libncurses5-dev libncursesw5-dev libreadline-dev libsqlite3-dev libgdbm-dev libdb5.3-dev libbz2-dev libexpat1-dev lzma liblzma-dev tk-dev libffi-dev")
|
||||||
|
.run_commands("curl -O https://www.python.org/ftp/python/3.8.12/Python-3.8.12.tar.xz&&tar -xf Python-3.8.12.tar.xz")
|
||||||
|
.run_commands("cd Python-3.8.12 && ./configure --enable-optimizations && make -j 10 && make altinstall")
|
||||||
|
.add_local_file("heygem-1.0-py3-none-any.whl","/root/heygem-1.0-py3-none-any.whl", copy=True)
|
||||||
|
.shell(["/bin/bash", "-c"])
|
||||||
|
.run_commands("python3.8 -m pip install /root/heygem-1.0-py3-none-any.whl")
|
||||||
|
.env({"LD_LIBRARY_PATH":"/usr/local/lib/python3.8/site-packages/nvidia/cuda_nvrtc/lib"})
|
||||||
|
.run_commands("ln -s /usr/local/lib/python3.8/site-packages/nvidia/cuda_nvrtc/lib/libnvrtc.so.11.2 /usr/local/lib/python3.8/site-packages/nvidia/cuda_nvrtc/lib/libnvrtc.so")
|
||||||
|
.run_commands("python3.8 -m pip install https://github.com/pydata/numexpr/releases/download/v2.8.6/numexpr-2.8.6-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl")
|
||||||
|
.add_local_file("heygem.py", "/root/heygem.py", copy=True)
|
||||||
|
.add_local_file("config.yaml", "/root/config.yaml", copy=True)
|
||||||
|
.workdir("/root").pip_install("boto3").pip_install("PyYAML")
|
||||||
|
)
|
||||||
|
|
||||||
|
app = modal.App(name="heygem", image=image)
|
||||||
|
secret = modal.Secret.from_name("aws-s3-secret")
|
||||||
|
auth_scheme = HTTPBearer()
|
||||||
|
bucket_output = "bw-heygem-output"
|
||||||
|
|
||||||
|
@app.cls(
|
||||||
|
allow_concurrent_inputs=1, # required for UI startup process which runs several API calls concurrently
|
||||||
|
max_containers=25, # limit interactive session to 1 container
|
||||||
|
gpu="T4", # good starter GPU for inference
|
||||||
|
cpu=(2,32),
|
||||||
|
memory=(6144, 32768),
|
||||||
|
timeout=2160,
|
||||||
|
scaledown_window=240,
|
||||||
|
secrets=[secret, modal.Secret.from_name("web_auth_token")],
|
||||||
|
volumes={
|
||||||
|
"/code/data/final": modal.CloudBucketMount(
|
||||||
|
bucket_name=bucket_output,
|
||||||
|
# bucket_endpoint_url="https://s3.%s.amazonaws.com" % os.environ["AWS_REGION"],
|
||||||
|
secret=secret,
|
||||||
|
key_prefix="/"
|
||||||
|
),
|
||||||
|
"/root/logs": modal.CloudBucketMount(
|
||||||
|
bucket_name=bucket_output,
|
||||||
|
# bucket_endpoint_url="https://s3.%s.amazonaws.com" % os.environ["AWS_REGION"],
|
||||||
|
secret=secret,
|
||||||
|
key_prefix="/logs/"
|
||||||
|
)
|
||||||
|
}, # mounts our cached models
|
||||||
|
)
|
||||||
|
class HeyGem:
|
||||||
|
@modal.enter()
|
||||||
|
def start(self):
|
||||||
|
def check_port_in_use(port, host='127.0.0.1'):
|
||||||
|
s = None
|
||||||
|
try:
|
||||||
|
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
|
s.settimeout(1)
|
||||||
|
s.connect((host, int(port)))
|
||||||
|
return True
|
||||||
|
except socket.error:
|
||||||
|
return False
|
||||||
|
finally:
|
||||||
|
if s:
|
||||||
|
s.close()
|
||||||
|
uid = str(uuid.uuid4())
|
||||||
|
cmd = "echo client_id: %s && nohup python3.8 /root/heygem.py >> /root/logs/%s.log 2>&1 &" % (uid, uid)
|
||||||
|
subprocess.run(cmd, shell=True, check=True)
|
||||||
|
timeout = 30
|
||||||
|
while timeout > 0:
|
||||||
|
check = check_port_in_use(8383)
|
||||||
|
if check:
|
||||||
|
loguru.logger.success("HeyGem Server started on port 8383")
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
timeout -= 1
|
||||||
|
time.sleep(2)
|
||||||
|
if timeout == 0:
|
||||||
|
raise TimeoutError("HeyGem Server Start timed out")
|
||||||
|
|
||||||
|
|
||||||
|
@modal.method()
|
||||||
|
def infer(self, code, video_path, audio_path) -> str:
|
||||||
|
def task_submit(uid, video, audio, heygem_url) -> dict[str, Any]:
|
||||||
|
"""Submit a task to the API"""
|
||||||
|
task_submit_api = f'{heygem_url}/easy/submit'
|
||||||
|
result_json = {
|
||||||
|
'status': False, 'data': {}, 'msg': ''
|
||||||
|
}
|
||||||
|
try:
|
||||||
|
data = {
|
||||||
|
"code": uid,
|
||||||
|
"video_url": video,
|
||||||
|
"audio_url": audio,
|
||||||
|
"chaofen": 1,
|
||||||
|
"watermark_switch": 0,
|
||||||
|
"pn": 1
|
||||||
|
}
|
||||||
|
loguru.logger.info(f'data={data}')
|
||||||
|
with httpx.Client() as client:
|
||||||
|
resp = client.post(task_submit_api, json=data)
|
||||||
|
resp_dict = resp.json()
|
||||||
|
loguru.logger.info(f'submit data: {resp_dict}')
|
||||||
|
if resp_dict['code'] != 10000:
|
||||||
|
result_json['status'] = False
|
||||||
|
result_json['msg'] = result_json['msg']
|
||||||
|
else:
|
||||||
|
result_json['status'] = True
|
||||||
|
result_json['data'] = uid
|
||||||
|
result_json['msg'] = '任务提交成功'
|
||||||
|
return result_json
|
||||||
|
except Exception as e:
|
||||||
|
loguru.logger.info(f'submit task fail case by:{str(e)}')
|
||||||
|
raise RuntimeError(str(e))
|
||||||
|
|
||||||
|
def query_task_progress(heygem_url, heygem_temp_path, task_id: str, interval: int = 10, timeout: int = 60 * 35) -> dict[str, Any]:
|
||||||
|
"""Query task progress and wait for completion"""
|
||||||
|
result_json = {'status': False, 'data': {}, 'msg': ''}
|
||||||
|
|
||||||
|
def query_result(t_id: str):
|
||||||
|
tmp_dict = {'status': True, 'data': dict(), 'msg': ''}
|
||||||
|
try:
|
||||||
|
query_task_url = f'{heygem_url}/easy/query'
|
||||||
|
params = {
|
||||||
|
'code': t_id
|
||||||
|
}
|
||||||
|
with httpx.Client() as client:
|
||||||
|
resp = client.get(query_task_url, params=params)
|
||||||
|
resp_dict = resp.json()
|
||||||
|
loguru.logger.info(f'query task data: {json.dumps(resp_dict)}')
|
||||||
|
status_code = resp_dict['code']
|
||||||
|
if status_code in (9999, 10002, 10003, 10001):
|
||||||
|
tmp_dict['status'] = False
|
||||||
|
tmp_dict['msg'] = resp_dict['msg']
|
||||||
|
elif status_code == 10000:
|
||||||
|
status_code = resp_dict['data'].get('status', 1)
|
||||||
|
if status_code == 3:
|
||||||
|
tmp_dict['status'] = False
|
||||||
|
tmp_dict['msg'] = resp_dict['data']['msg']
|
||||||
|
else:
|
||||||
|
process = resp_dict['data'].get('progress', 20)
|
||||||
|
if status_code == 2:
|
||||||
|
process = 100
|
||||||
|
else:
|
||||||
|
process = process
|
||||||
|
result = resp_dict['data'].get('result', '')
|
||||||
|
tmp_dict['data'] = {'progress': process,
|
||||||
|
'path': result,
|
||||||
|
}
|
||||||
|
else:
|
||||||
|
pass
|
||||||
|
except Exception as e:
|
||||||
|
loguru.logger.info(f'query task fail case by:{str(e)}')
|
||||||
|
raise RuntimeError(str(e))
|
||||||
|
return tmp_dict
|
||||||
|
|
||||||
|
end = time.time() + timeout
|
||||||
|
while time.time() < end:
|
||||||
|
tmp_result = query_result(task_id)
|
||||||
|
if not tmp_result['status'] or tmp_result['data'].__eq__({}):
|
||||||
|
result_json['status'] = False
|
||||||
|
result_json['msg'] = tmp_result['msg']
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
process = tmp_result['data']['progress']
|
||||||
|
loguru.logger.info(f'query task progress :{process}')
|
||||||
|
if tmp_result['data']['progress'] < 100:
|
||||||
|
time.sleep(interval)
|
||||||
|
loguru.logger.info(f'wait next interval:{interval}')
|
||||||
|
else:
|
||||||
|
p = tmp_result['data']['path']
|
||||||
|
p = p.replace('/', '').replace('\\', '')
|
||||||
|
result_json['data'] = "%s/%s" % (heygem_temp_path, p)
|
||||||
|
result_json['status'] = True
|
||||||
|
break
|
||||||
|
return result_json
|
||||||
|
|
||||||
|
try:
|
||||||
|
heygem_url = "http://127.0.0.1:8383"
|
||||||
|
heygem_temp_path = "/code/data/temp"
|
||||||
|
submit_result = task_submit(code, video_path, audio_path, heygem_url)
|
||||||
|
if not submit_result['status']:
|
||||||
|
raise Exception(f"Task submission failed: {submit_result['msg']}")
|
||||||
|
|
||||||
|
task_id = submit_result['data']
|
||||||
|
loguru.logger.info(f'Submitted task: {task_id}')
|
||||||
|
|
||||||
|
# Query task progress
|
||||||
|
progress_result = query_task_progress(heygem_url, heygem_temp_path, task_id, interval=5)
|
||||||
|
|
||||||
|
if not progress_result['status']:
|
||||||
|
raise RuntimeError(f"Task processing failed: {progress_result['msg']}")
|
||||||
|
|
||||||
|
# Return the file for download
|
||||||
|
file_path = progress_result['data']
|
||||||
|
if not os.path.exists(file_path):
|
||||||
|
raise FileNotFoundError(f"Output file not found at {file_path}")
|
||||||
|
return file_path
|
||||||
|
except Exception as e:
|
||||||
|
loguru.logger.error(f"Error processing request || {str(e)}")
|
||||||
|
raise Exception(str(e))
|
||||||
|
finally:
|
||||||
|
try:
|
||||||
|
os.remove(video_path)
|
||||||
|
os.remove(audio_path)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
@modal.fastapi_endpoint(method="POST")
|
||||||
|
async def api(self, video_file: UploadFile, audio_file: UploadFile, token: HTTPAuthorizationCredentials = Depends(auth_scheme)) -> Response:
|
||||||
|
if token.credentials != os.environ["AUTH_TOKEN"]:
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=status.HTTP_401_UNAUTHORIZED,
|
||||||
|
detail="Incorrect bearer token",
|
||||||
|
headers={"WWW-Authenticate": "Bearer"},
|
||||||
|
)
|
||||||
|
code = str(uuid.uuid4())
|
||||||
|
try:
|
||||||
|
video_path = "/root/%s" % video_file.filename
|
||||||
|
with open(video_path, "wb") as f:
|
||||||
|
data = await video_file.read()
|
||||||
|
f.write(data)
|
||||||
|
|
||||||
|
audio_path = "/root/%s" % audio_file.filename
|
||||||
|
with open(audio_path, "wb") as f:
|
||||||
|
data = await audio_file.read()
|
||||||
|
f.write(data)
|
||||||
|
except Exception as e:
|
||||||
|
return Response({"status": "fail", "msg": f"video or audio file save failed: {str(e)}"})
|
||||||
|
|
||||||
|
loguru.logger.info(f"Enter Inference Module")
|
||||||
|
try:
|
||||||
|
file_path = self.infer.local(code, video_path, audio_path)
|
||||||
|
try:
|
||||||
|
shutil.copy(file_path, os.path.join("/code/data/final",file_path.split(os.path.sep)[-1]))
|
||||||
|
except Exception as e:
|
||||||
|
loguru.logger.info(f"Moving {file_path} to S3 Failed: {str(e)}")
|
||||||
|
try:
|
||||||
|
print("Try move file to S3 manually")
|
||||||
|
# S3 Fallback
|
||||||
|
import boto3
|
||||||
|
import yaml
|
||||||
|
with open("/root/config.yaml", encoding="utf-8",
|
||||||
|
mode="r+") as config:
|
||||||
|
yaml_config = yaml.load(config, Loader=yaml.FullLoader)
|
||||||
|
awss3 = boto3.resource('s3', aws_access_key_id=yaml_config["aws_key_id"],
|
||||||
|
aws_secret_access_key=yaml_config["aws_access_key"])
|
||||||
|
awss3.meta.client.upload_file(file_path, bucket_output, file_path.split(os.path.sep)[-1])
|
||||||
|
except:
|
||||||
|
raise Exception("Failed to move file to S3 manually")
|
||||||
|
resp = FileResponse(path=file_path, filename=Path(file_path).name, status_code=200, headers={
|
||||||
|
"Content-Type": "application/octet-stream",
|
||||||
|
"Content-Disposition": f"attachment; filename={Path(file_path).name}",
|
||||||
|
})
|
||||||
|
return resp
|
||||||
|
except Exception as e:
|
||||||
|
traceback.print_exc()
|
||||||
|
return Response({"status": "fail", "msg": "Inference module failed: "+str(e)})
|
||||||
|
|
||||||
|
|
||||||
@@ -1,11 +1,9 @@
|
|||||||
|
# ComfyUI模板--Base 停止维护!!
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
import shutil
|
import shutil
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
|
||||||
import traceback
|
|
||||||
import uuid
|
import uuid
|
||||||
from pathlib import Path
|
|
||||||
from typing import Dict
|
from typing import Dict
|
||||||
|
|
||||||
import modal
|
import modal
|
||||||
|
|||||||
@@ -1,11 +1,9 @@
|
|||||||
|
# ComfyUI模板--Base Auth
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
import shutil
|
import shutil
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
|
||||||
import traceback
|
|
||||||
import uuid
|
import uuid
|
||||||
from pathlib import Path
|
|
||||||
from typing import Dict
|
from typing import Dict
|
||||||
|
|
||||||
import modal
|
import modal
|
||||||
|
|||||||
@@ -1,11 +1,9 @@
|
|||||||
|
# ComfyUI模板--Base Auth Heygem
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
import shutil
|
import shutil
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
|
||||||
import traceback
|
|
||||||
import uuid
|
import uuid
|
||||||
from pathlib import Path
|
|
||||||
from typing import Dict
|
from typing import Dict
|
||||||
|
|
||||||
import modal
|
import modal
|
||||||
@@ -13,14 +11,14 @@ from fastapi import Depends, HTTPException, status
|
|||||||
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
|
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
|
||||||
|
|
||||||
image = ( # build up a Modal Image to run ComfyUI, step by step
|
image = ( # build up a Modal Image to run ComfyUI, step by step
|
||||||
modal.Image.from_registry( # start from basic Linux with Python
|
modal.Image.debian_slim( # start from basic Linux with Python
|
||||||
"ubuntu/python:3.12-24.04_stable"
|
python_version="3.10"
|
||||||
).apt_install("python3.8-dev")
|
)
|
||||||
.apt_install("git") # install git to clone ComfyUI
|
.apt_install("git") # install git to clone ComfyUI
|
||||||
.apt_install("gcc")
|
.apt_install("gcc")
|
||||||
.apt_install("libportaudio2")
|
.apt_install("libportaudio2")
|
||||||
.pip_install("fastapi[standard]==0.115.4") # install web dependencies
|
.pip_install("fastapi[standard]==0.115.4") # install web dependencies
|
||||||
.pip_install("comfy-cli==1.3.8") # install comfy-cli
|
.pip_install("comfy-cli==1.3.5") # install comfy-cli
|
||||||
.pip_install("cos-python-sdk-v5")
|
.pip_install("cos-python-sdk-v5")
|
||||||
.pip_install("sqlalchemy")
|
.pip_install("sqlalchemy")
|
||||||
.pip_install("ultralytics")
|
.pip_install("ultralytics")
|
||||||
@@ -56,7 +54,7 @@ image = (
|
|||||||
.run_commands("comfy node install https://github.com/cubiq/ComfyUI_essentials")
|
.run_commands("comfy node install https://github.com/cubiq/ComfyUI_essentials")
|
||||||
.run_commands("comfy node install https://github.com/melMass/comfy_mtb")
|
.run_commands("comfy node install https://github.com/melMass/comfy_mtb")
|
||||||
.run_commands("echo 3 && comfy node install https://e.coding.net/g-ldyi2063/dev/ComfyUI_SparkTTS.git")
|
.run_commands("echo 3 && comfy node install https://e.coding.net/g-ldyi2063/dev/ComfyUI_SparkTTS.git")
|
||||||
.run_commands("echo 1 && comfy node install https://e.coding.net/g-ldyi2063/dev/ComfyUI-CustomNode.git")
|
.run_commands("echo 4 && comfy node install https://e.coding.net/g-ldyi2063/dev/ComfyUI-CustomNode.git")
|
||||||
.run_commands("comfy node install https://e.coding.net/g-ldyi2063/dev/cosyvoice_comfyui.git")
|
.run_commands("comfy node install https://e.coding.net/g-ldyi2063/dev/cosyvoice_comfyui.git")
|
||||||
.run_commands("echo 4 && comfy node install https://e.coding.net/g-ldyi2063/dev/ComfyUI-LatentSync-Node.git")
|
.run_commands("echo 4 && comfy node install https://e.coding.net/g-ldyi2063/dev/ComfyUI-LatentSync-Node.git")
|
||||||
.run_commands(
|
.run_commands(
|
||||||
@@ -75,9 +73,17 @@ image = (
|
|||||||
"apt update && apt install -y ffmpeg && ffmpeg -version"
|
"apt update && apt install -y ffmpeg && ffmpeg -version"
|
||||||
).add_local_file("config.yaml", "/root/comfy/ComfyUI/custom_nodes/ComfyUI-CustomNode/config.yaml", copy=True
|
).add_local_file("config.yaml", "/root/comfy/ComfyUI/custom_nodes/ComfyUI-CustomNode/config.yaml", copy=True
|
||||||
).add_local_file("config.py", "/root/comfy/ComfyUI/custom_nodes/cosyvoice_comfyui/pretrained_models/tools/config.py", copy=True
|
).add_local_file("config.py", "/root/comfy/ComfyUI/custom_nodes/cosyvoice_comfyui/pretrained_models/tools/config.py", copy=True
|
||||||
).add_local_file("heygem-1.0-py3-none-any.whl","/root/comfy/heygem-1.0-py3-none-any.whl", copy=True
|
) # 添加Python3.8 HeyGem
|
||||||
).add_local_file("heygem.py", "/root/comfy/heygem.py", copy=True
|
.run_commands("apt update && apt install -y curl build-essential libssl-dev zlib1g-dev libncurses5-dev libncursesw5-dev libreadline-dev libsqlite3-dev libgdbm-dev libdb5.3-dev libbz2-dev libexpat1-dev lzma liblzma-dev tk-dev libffi-dev")
|
||||||
).pip_install("/root/comfy/heygem-1.0-py3-none-any.whl")
|
.run_commands("curl -O https://www.python.org/ftp/python/3.8.12/Python-3.8.12.tar.xz&&tar -xf Python-3.8.12.tar.xz")
|
||||||
|
.run_commands("cd Python-3.8.12 && ./configure --enable-optimizations && make -j 10 && make altinstall")
|
||||||
|
.add_local_file("heygem-1.0-py3-none-any.whl","/root/comfy/heygem-1.0-py3-none-any.whl", copy=True)
|
||||||
|
.shell(["/bin/bash", "-c"])
|
||||||
|
.run_commands("python3.8 -m pip install /root/comfy/heygem-1.0-py3-none-any.whl")
|
||||||
|
.env({"LD_LIBRARY_PATH":"/usr/local/lib/python3.8/site-packages/nvidia/cuda_nvrtc/lib"})
|
||||||
|
.run_commands("ln -s /usr/local/lib/python3.8/site-packages/nvidia/cuda_nvrtc/lib/libnvrtc.so.11.2 /usr/local/lib/python3.8/site-packages/nvidia/cuda_nvrtc/lib/libnvrtc.so")
|
||||||
|
.run_commands("python3.8 -m pip install https://github.com/pydata/numexpr/releases/download/v2.8.6/numexpr-2.8.6-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl")
|
||||||
|
.add_local_file("heygem.py", "/root/comfy/heygem.py", copy=True)
|
||||||
.workdir("/root/comfy")
|
.workdir("/root/comfy")
|
||||||
|
|
||||||
# Add .run_commands(...) calls for any other custom nodes you want to download
|
# Add .run_commands(...) calls for any other custom nodes you want to download
|
||||||
@@ -101,13 +107,12 @@ auth_scheme = HTTPBearer()
|
|||||||
buffer_containers=0,
|
buffer_containers=0,
|
||||||
scaledown_window=120,
|
scaledown_window=120,
|
||||||
# 5 minute container keep alive after it processes an input; increasing this value is a great way to reduce ComfyUI cold start times
|
# 5 minute container keep alive after it processes an input; increasing this value is a great way to reduce ComfyUI cold start times
|
||||||
timeout=900,
|
timeout=1200,
|
||||||
gpu=["L4", "T4"],
|
gpu=["L4", "T4"],
|
||||||
cpu=(2,16),
|
cpu=(2,16),
|
||||||
# memory=(32768, 32768), # (内存预留量, 内存使用上限)
|
# memory=(32768, 32768), # (内存预留量, 内存使用上限)
|
||||||
memory=(20480,40960),
|
memory=(20480,81920),
|
||||||
retries=1,
|
enable_memory_snapshot=False,
|
||||||
enable_memory_snapshot=True,
|
|
||||||
secrets=[secret, modal.Secret.from_name("web_auth_token")],
|
secrets=[secret, modal.Secret.from_name("web_auth_token")],
|
||||||
volumes={
|
volumes={
|
||||||
"/root/comfy/ComfyUI/models": vol,
|
"/root/comfy/ComfyUI/models": vol,
|
||||||
@@ -134,8 +139,10 @@ class ComfyUI:
|
|||||||
" && rm -rf /root/comfy/ComfyUI/user"
|
" && rm -rf /root/comfy/ComfyUI/user"
|
||||||
" && mkdir -p /root/comfy/ComfyUI/output_s3/logs/{}"
|
" && mkdir -p /root/comfy/ComfyUI/output_s3/logs/{}"
|
||||||
" && ln -s /root/comfy/ComfyUI/output_s3/logs/{} /root/comfy/ComfyUI/user"
|
" && ln -s /root/comfy/ComfyUI/output_s3/logs/{} /root/comfy/ComfyUI/user"
|
||||||
" && comfy launch --background"
|
" && nohup python3.8 /root/comfy/heygem.py >> /root/comfy/ComfyUI/output_s3/logs/{}/heygem.log 2>&1 &"
|
||||||
" && nohup python heygem.py >> /root/comfy/ComfyUI/output_s3/logs/{}/heygem.log 2>&1 &").format(self.session_id,self.session_id, self.session_id, self.session_id)
|
).format(self.session_id,self.session_id, self.session_id, self.session_id)
|
||||||
|
subprocess.run(cmd, shell=True, check=True)
|
||||||
|
cmd = "comfy launch --background"
|
||||||
subprocess.run(cmd, shell=True, check=True)
|
subprocess.run(cmd, shell=True, check=True)
|
||||||
|
|
||||||
@modal.method()
|
@modal.method()
|
||||||
@@ -170,41 +177,78 @@ class ComfyUI:
|
|||||||
node["inputs"]["default_value"] = node["inputs"]["default_value"].replace("input_s3", "input")
|
node["inputs"]["default_value"] = node["inputs"]["default_value"].replace("input_s3", "input")
|
||||||
with open(f"/root/{self.prompt_uuid}.json", "w", encoding="utf-8") as fi:
|
with open(f"/root/{self.prompt_uuid}.json", "w", encoding="utf-8") as fi:
|
||||||
fi.write(json.dumps(workflow, ensure_ascii=False))
|
fi.write(json.dumps(workflow, ensure_ascii=False))
|
||||||
cmd = f"comfy run --workflow /root/{self.prompt_uuid}.json --wait --timeout 890 --verbose"
|
cmd = f"comfy run --workflow /root/{self.prompt_uuid}.json --wait --timeout 1190 --verbose"
|
||||||
subprocess.run(cmd, shell=True, check=True, timeout=895)
|
subprocess.run(cmd, shell=True, check=True, timeout=1195)
|
||||||
|
|
||||||
# looks up the name of the output image file based on the workflow
|
# looks up the name of the output image file based on the workflow
|
||||||
file_prefix = [
|
if "VHS_VideoCombine" in workflow_json:
|
||||||
node.get("inputs")
|
file_prefix = [
|
||||||
for node in workflow.values()
|
node.get("inputs")
|
||||||
if node.get("class_type") == "VHS_VideoCombine"
|
for node in workflow.values()
|
||||||
][0]["filename_prefix"]
|
if node.get("class_type") == "VHS_VideoCombine"
|
||||||
|
][0]["filename_prefix"]
|
||||||
|
|
||||||
# returns the image as bytes
|
# returns the image as bytes
|
||||||
file_list = os.listdir(output_dir)
|
file_list = os.listdir(output_dir)
|
||||||
# 获取按照文件时间创建排序的列表,默认是按时间升序
|
# 获取按照文件时间创建排序的列表,默认是按时间升序
|
||||||
new_file_list = sorted(file_list, key=lambda file: os.path.getctime(os.path.join(output_dir, file)),
|
new_file_list = sorted(file_list, key=lambda file: os.path.getctime(os.path.join(output_dir, file)),
|
||||||
reverse=True)
|
reverse=True)
|
||||||
# print("file_list", new_file_list)
|
# print("file_list", new_file_list)
|
||||||
for f in new_file_list:
|
for f in new_file_list:
|
||||||
if f.startswith(file_prefix):
|
if f.startswith(file_prefix):
|
||||||
os.makedirs(os.path.dirname(os.path.join(output_dir.replace("output", "output_s3"), f)), exist_ok=True)
|
os.makedirs(os.path.dirname(os.path.join(output_dir.replace("output", "output_s3"), f)), exist_ok=True)
|
||||||
|
try:
|
||||||
|
shutil.copy(os.path.join(output_dir, f), os.path.join(output_dir.replace("output", "output_s3"), f))
|
||||||
|
except:
|
||||||
|
try:
|
||||||
|
print("Try move file to S3 manually")
|
||||||
|
# S3 Fallback
|
||||||
|
import boto3
|
||||||
|
import yaml
|
||||||
|
with open("/root/comfy/ComfyUI/custom_nodes/ComfyUI-CustomNode/config.yaml", encoding="utf-8",mode="r+") as config:
|
||||||
|
yaml_config = yaml.load(config, Loader=yaml.FullLoader)
|
||||||
|
awss3 = boto3.resource('s3', aws_access_key_id=yaml_config["aws_key_id"],
|
||||||
|
aws_secret_access_key=yaml_config["aws_access_key"])
|
||||||
|
awss3.meta.client.upload_file(os.path.join(output_dir, f), bucket_output, f)
|
||||||
|
except:
|
||||||
|
raise Exception("Failed to move file to S3 manually")
|
||||||
|
return f
|
||||||
|
elif "HeyGemF2F" in workflow_json or "HeyGemF2FFromFile" in workflow_json:
|
||||||
|
heygem_dir = [
|
||||||
|
node.get("inputs")
|
||||||
|
for node in workflow.values()
|
||||||
|
if node.get("class_type") == "HeyGemF2F" or node.get("class_type") == "HeyGemF2FFromFile"
|
||||||
|
][0]["heygem_temp_path"]
|
||||||
|
# returns the image as bytes
|
||||||
|
file_list = os.listdir(heygem_dir)
|
||||||
|
# 获取按照文件时间创建排序的列表,默认是按时间升序
|
||||||
|
new_file_list = sorted(file_list, key=lambda file: os.path.getctime(os.path.join(heygem_dir, file)),
|
||||||
|
reverse=True)
|
||||||
|
if len(new_file_list) > 0:
|
||||||
try:
|
try:
|
||||||
shutil.copy(os.path.join(output_dir, f), os.path.join(output_dir.replace("output", "output_s3"), f))
|
shutil.copy(os.path.join(heygem_dir, new_file_list[0]), os.path.join(output_dir.replace("output", "output_s3"), new_file_list[0]))
|
||||||
except:
|
except:
|
||||||
try:
|
try:
|
||||||
print("Try move file to S3 manually")
|
print("Try move file to S3 manually")
|
||||||
# S3 Fallback
|
# S3 Fallback
|
||||||
import boto3
|
import boto3
|
||||||
import yaml
|
import yaml
|
||||||
with open("/root/comfy/ComfyUI/custom_nodes/ComfyUI-CustomNode/config.yaml", encoding="utf-8",mode="r+") as config:
|
with open("/root/comfy/ComfyUI/custom_nodes/ComfyUI-CustomNode/config.yaml", encoding="utf-8",
|
||||||
|
mode="r+") as config:
|
||||||
yaml_config = yaml.load(config, Loader=yaml.FullLoader)
|
yaml_config = yaml.load(config, Loader=yaml.FullLoader)
|
||||||
awss3 = boto3.resource('s3', aws_access_key_id=yaml_config["aws_key_id"],
|
awss3 = boto3.resource('s3', aws_access_key_id=yaml_config["aws_key_id"],
|
||||||
aws_secret_access_key=yaml_config["aws_access_key"])
|
aws_secret_access_key=yaml_config["aws_access_key"])
|
||||||
awss3.meta.client.upload_file(os.path.join(output_dir, f), bucket_output, f)
|
awss3.meta.client.upload_file(os.path.join(heygem_dir, new_file_list[0]), bucket_output, new_file_list[0])
|
||||||
except:
|
except:
|
||||||
raise Exception("Failed to move file to S3 manually")
|
raise Exception("Failed to move HeyGem file to S3 manually")
|
||||||
return f
|
return new_file_list[0]
|
||||||
|
else:
|
||||||
|
raise FileNotFoundError("HeyGem generation file not found")
|
||||||
|
else:
|
||||||
|
raise Exception("Workflow does not contain VHS_VideoCombine/HeygemF2F node, cannot find output file")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@modal.fastapi_endpoint(method="POST")
|
@modal.fastapi_endpoint(method="POST")
|
||||||
def api(self, item: Dict, token: HTTPAuthorizationCredentials = Depends(auth_scheme)):
|
def api(self, item: Dict, token: HTTPAuthorizationCredentials = Depends(auth_scheme)):
|
||||||
|
|||||||
Reference in New Issue
Block a user