add waas modal部署
This commit is contained in:
parent
c69d3cc326
commit
f0ee6e21d7
|
|
@ -1,10 +1,10 @@
|
||||||
# ComfyUI服务器地址
|
# ComfyUI服务器地址
|
||||||
COMFYUI_URL="ws://127.0.0.1:8188/ws"
|
COMFYUI_URL="ws://bowongai--local-ui-4.modal.run/ws"
|
||||||
COMFYUI_HTTP_URL="http://127.0.0.1:8188"
|
COMFYUI_HTTP_URL="https://bowongai--local-ui-4.modal.run"
|
||||||
# 绝对路径!例如: /home/user/ComfyUI/input
|
# 绝对路径!例如: /home/user/ComfyUI/input
|
||||||
COMFYUI_INPUT_DIR="F:\ComfyUI\input"
|
COMFYUI_INPUT_DIR="/db/input"
|
||||||
# 绝对路径!例如: /home/user/ComfyUI/output
|
# 绝对路径!例如: /home/user/ComfyUI/output
|
||||||
COMFYUI_OUTPUT_DIR="F:\ComfyUI\output"
|
COMFYUI_OUTPUT_DIR="/db/output"
|
||||||
|
|
||||||
# AWS S3 配置
|
# AWS S3 配置
|
||||||
S3_BUCKET_NAME="modal-media-cache"
|
S3_BUCKET_NAME="modal-media-cache"
|
||||||
|
|
@ -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
|
||||||
|
|
@ -3,7 +3,8 @@ import json
|
||||||
import uuid
|
import uuid
|
||||||
import aiohttp
|
import aiohttp
|
||||||
import random
|
import random
|
||||||
from config import settings
|
from workflow_service.config import Settings
|
||||||
|
settings = Settings()
|
||||||
|
|
||||||
|
|
||||||
async def queue_prompt(prompt: dict, client_id: str) -> str:
|
async def queue_prompt(prompt: dict, client_id: str) -> str:
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
|
from dotenv import dotenv_values
|
||||||
from pydantic_settings import BaseSettings, SettingsConfigDict
|
from pydantic_settings import BaseSettings, SettingsConfigDict
|
||||||
|
|
||||||
class Settings(BaseSettings):
|
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_URL: str = "ws://127.0.0.1:8188/ws"
|
||||||
COMFYUI_HTTP_URL: str = "http://127.0.0.1:8188"
|
COMFYUI_HTTP_URL: str = "http://127.0.0.1:8188"
|
||||||
COMFYUI_INPUT_DIR: str
|
COMFYUI_INPUT_DIR: str
|
||||||
|
|
@ -11,4 +12,4 @@ class Settings(BaseSettings):
|
||||||
AWS_SECRET_ACCESS_KEY: str
|
AWS_SECRET_ACCESS_KEY: str
|
||||||
AWS_REGION_NAME: str
|
AWS_REGION_NAME: str
|
||||||
|
|
||||||
settings = Settings()
|
# settings = Settings()
|
||||||
|
|
@ -2,7 +2,7 @@ import aiosqlite
|
||||||
import json
|
import json
|
||||||
import re
|
import re
|
||||||
|
|
||||||
DATABASE_FILE = "workflows_service.sqlite"
|
DATABASE_FILE = "/db/workflows_service.sqlite"
|
||||||
|
|
||||||
async def init_db():
|
async def init_db():
|
||||||
async with aiosqlite.connect(DATABASE_FILE) as db:
|
async with aiosqlite.connect(DATABASE_FILE) as db:
|
||||||
|
|
|
||||||
|
|
@ -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
|
import uvicorn
|
||||||
from fastapi import FastAPI, Request, HTTPException, Path
|
from fastapi import FastAPI, Request, HTTPException, Path
|
||||||
from fastapi.responses import JSONResponse
|
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,
|
async def startup_event(): await database.init_db(); os.makedirs(settings.COMFYUI_INPUT_DIR,
|
||||||
exist_ok=True); os.makedirs(
|
exist_ok=True); os.makedirs(
|
||||||
settings.COMFYUI_OUTPUT_DIR, exist_ok=True)
|
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"
|
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):
|
async def publish_workflow_endpoint(request: Request):
|
||||||
try:
|
try:
|
||||||
data = await request.json(); name, wf_json = data.get("name"), data.get(
|
data = await request.json();
|
||||||
"workflow"); await database.save_workflow(name, json.dumps(wf_json)); return JSONResponse(
|
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)
|
content={"status": "success", "message": f"Workflow '{name}' published."}, status_code=200)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise HTTPException(status_code=500, detail=f"Failed to save workflow: {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():
|
async def get_all_workflows_endpoint():
|
||||||
try:
|
try:
|
||||||
return await database.get_all_workflows()
|
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}")
|
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="...")):
|
async def delete_workflow_endpoint(workflow_name: str = Path(..., title="...")):
|
||||||
try:
|
try:
|
||||||
success = await database.delete_workflow(workflow_name);
|
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)
|
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):
|
async def execute_workflow_endpoint(base_name: str, request_data_raw: Dict[str, Any], version: Optional[str] = None):
|
||||||
cleanup_paths = []
|
cleanup_paths = []
|
||||||
try:
|
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)
|
save_path = os.path.join(settings.COMFYUI_INPUT_DIR, filename)
|
||||||
try:
|
try:
|
||||||
await download_file_from_url(session, image_url, save_path);
|
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:
|
except Exception as e:
|
||||||
raise HTTPException(status_code=500,
|
raise HTTPException(status_code=500,
|
||||||
detail=f"Failed to download file for '{param_name}' from {image_url}. Error: {e}")
|
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 (无改动) ---
|
# --- 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):
|
async def get_workflow_spec_endpoint(base_name: str, version: Optional[str] = None):
|
||||||
# ...
|
# ...
|
||||||
if version:
|
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}")
|
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!"}
|
def read_root(): return {"message": "Welcome to the ComfyUI Workflow Service API!"}
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
uvicorn.run(app, host="127.0.0.1", port=18000)
|
uvicorn.run(web_app, host="127.0.0.1", port=18000)
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import boto3
|
import boto3
|
||||||
from config import settings
|
from workflow_service.config import Settings
|
||||||
import asyncio
|
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)
|
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)
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue