add waas modal部署

This commit is contained in:
kyj@bowong.ai 2025-07-31 18:59:50 +08:00
parent c69d3cc326
commit f0ee6e21d7
7 changed files with 70 additions and 24 deletions

View File

@ -1,10 +1,10 @@
# ComfyUI服务器地址
COMFYUI_URL="ws://127.0.0.1:8188/ws"
COMFYUI_HTTP_URL="http://127.0.0.1:8188"
COMFYUI_URL="ws://bowongai--local-ui-4.modal.run/ws"
COMFYUI_HTTP_URL="https://bowongai--local-ui-4.modal.run"
# 绝对路径!例如: /home/user/ComfyUI/input
COMFYUI_INPUT_DIR="F:\ComfyUI\input"
COMFYUI_INPUT_DIR="/db/input"
# 绝对路径!例如: /home/user/ComfyUI/output
COMFYUI_OUTPUT_DIR="F:\ComfyUI\output"
COMFYUI_OUTPUT_DIR="/db/output"
# AWS S3 配置
S3_BUCKET_NAME="modal-media-cache"

29
modal_deploy.py Normal file
View File

@ -0,0 +1,29 @@
import modal
from dotenv import dotenv_values
from workflow_service.main import web_app
fastapi_image = (
modal.Image
.debian_slim(python_version="3.11")
.pip_install_from_requirements("./workflow_service/requirements.txt")
.env(dotenv_values(".env"))
.add_local_python_source("workflow_service")
)
app = modal.App(image=fastapi_image, name="waas-demo")
vol = modal.Volume.from_name("comfy_model", environment_name="dev", create_if_missing=True)
with fastapi_image.imports():
@app.function(
cpu=(0.125, 8),
memory=(128, 4096),
scaledown_window=1200,
volumes={
"/db": vol
}
)
@modal.concurrent(max_inputs=100)
@modal.asgi_app()
def fastapi_webapp():
return web_app

View File

@ -3,7 +3,8 @@ import json
import uuid
import aiohttp
import random
from config import settings
from workflow_service.config import Settings
settings = Settings()
async def queue_prompt(prompt: dict, client_id: str) -> str:

View File

@ -1,7 +1,8 @@
from dotenv import dotenv_values
from pydantic_settings import BaseSettings, SettingsConfigDict
class Settings(BaseSettings):
model_config = SettingsConfigDict(env_file='.env', env_file_encoding='utf-8')
model_config = SettingsConfigDict(env_file='./.env', env_file_encoding='utf-8')
COMFYUI_URL: str = "ws://127.0.0.1:8188/ws"
COMFYUI_HTTP_URL: str = "http://127.0.0.1:8188"
COMFYUI_INPUT_DIR: str
@ -11,4 +12,4 @@ class Settings(BaseSettings):
AWS_SECRET_ACCESS_KEY: str
AWS_REGION_NAME: str
settings = Settings()
# settings = Settings()

View File

@ -2,7 +2,7 @@ import aiosqlite
import json
import re
DATABASE_FILE = "workflows_service.sqlite"
DATABASE_FILE = "/db/workflows_service.sqlite"
async def init_db():
async with aiosqlite.connect(DATABASE_FILE) as db:

View File

@ -1,14 +1,24 @@
import aiohttp
from workflow_service import comfyui_client
from workflow_service import database
import json
import os
from workflow_service import s3_client
import uuid
from workflow_service import workflow_parser
from typing import Optional, List, Dict, Any, Set
import uvicorn
from fastapi import FastAPI, Request, HTTPException, Path
from fastapi.responses import JSONResponse
from typing import Optional, List, Dict, Any, Set
import json, uuid, os, shutil, aiohttp, database, workflow_parser, comfyui_client, s3_client
from config import settings
app = FastAPI(title="ComfyUI Workflow Service & Management API")
from workflow_service.config import Settings
settings = Settings()
web_app = FastAPI(title="ComfyUI Workflow Service & Management API")
@app.on_event("startup")
@web_app.on_event("startup")
async def startup_event(): await database.init_db(); os.makedirs(settings.COMFYUI_INPUT_DIR,
exist_ok=True); os.makedirs(
settings.COMFYUI_OUTPUT_DIR, exist_ok=True)
@ -19,17 +29,20 @@ async def startup_event(): await database.init_db(); os.makedirs(settings.COMFYU
BASE_MANAGEMENT_PATH = "/api/workflow"
@app.post(BASE_MANAGEMENT_PATH, status_code=200)
@web_app.post(BASE_MANAGEMENT_PATH, status_code=200)
async def publish_workflow_endpoint(request: Request):
try:
data = await request.json(); name, wf_json = data.get("name"), data.get(
"workflow"); await database.save_workflow(name, json.dumps(wf_json)); return JSONResponse(
data = await request.json();
name, wf_json = data.get("name"), data.get(
"workflow");
await database.save_workflow(name, json.dumps(wf_json));
return JSONResponse(
content={"status": "success", "message": f"Workflow '{name}' published."}, status_code=200)
except Exception as e:
raise HTTPException(status_code=500, detail=f"Failed to save workflow: {e}")
@app.get(BASE_MANAGEMENT_PATH, response_model=List[dict])
@web_app.get(BASE_MANAGEMENT_PATH, response_model=List[dict])
async def get_all_workflows_endpoint():
try:
return await database.get_all_workflows()
@ -37,7 +50,7 @@ async def get_all_workflows_endpoint():
raise HTTPException(status_code=500, detail=f"Failed to get workflows: {e}")
@app.delete(f"{BASE_MANAGEMENT_PATH}/{{workflow_name:path}}")
@web_app.delete(f"{BASE_MANAGEMENT_PATH}/{{workflow_name:path}}")
async def delete_workflow_endpoint(workflow_name: str = Path(..., title="...")):
try:
success = await database.delete_workflow(workflow_name);
@ -75,7 +88,7 @@ async def handle_file_upload(file_path: str, base_name: str) -> str:
return await s3_client.upload_file_to_s3(file_path, settings.S3_BUCKET_NAME, s3_object_name)
@app.post("/api/run/{base_name}")
@web_app.post("/api/run/{base_name}")
async def execute_workflow_endpoint(base_name: str, request_data_raw: Dict[str, Any], version: Optional[str] = None):
cleanup_paths = []
try:
@ -102,7 +115,8 @@ async def execute_workflow_endpoint(base_name: str, request_data_raw: Dict[str,
save_path = os.path.join(settings.COMFYUI_INPUT_DIR, filename)
try:
await download_file_from_url(session, image_url, save_path);
request_data[param_name] = filename; cleanup_paths.append(save_path)
request_data[param_name] = filename;
cleanup_paths.append(save_path)
except Exception as e:
raise HTTPException(status_code=500,
detail=f"Failed to download file for '{param_name}' from {image_url}. Error: {e}")
@ -187,7 +201,7 @@ async def execute_workflow_endpoint(base_name: str, request_data_raw: Dict[str,
# --- Section 3: 工作流元数据/规范API (无改动) ---
# ... (此部分代码与上一版完全相同) ...
@app.get("/api/spec/{base_name}")
@web_app.get("/api/spec/{base_name}")
async def get_workflow_spec_endpoint(base_name: str, version: Optional[str] = None):
# ...
if version:
@ -204,9 +218,9 @@ async def get_workflow_spec_endpoint(base_name: str, version: Optional[str] = No
raise HTTPException(status_code=500, detail=f"Failed to parse workflow specification: {e}")
@app.get("/")
@web_app.get("/")
def read_root(): return {"message": "Welcome to the ComfyUI Workflow Service API!"}
if __name__ == "__main__":
uvicorn.run(app, host="127.0.0.1", port=18000)
uvicorn.run(web_app, host="127.0.0.1", port=18000)

View File

@ -1,6 +1,7 @@
import boto3
from config import settings
from workflow_service.config import Settings
import asyncio
settings = Settings()
s3_client = boto3.client('s3', aws_access_key_id=settings.AWS_ACCESS_KEY_ID, aws_secret_access_key=settings.AWS_SECRET_ACCESS_KEY, region_name=settings.AWS_REGION_NAME)