comfyui openwebui 랑 연동하여 api 로 이미지 생성하기
comfyui openwebui 랑 연동하여 api 로 이미지 생성하기(우분투,arm64, 도커)
ComfyUI + OpenWebUI API 연동을 통한 이미지 생성 가이드 (Ubuntu, ARM64, Docker)
이 가이드는 Docker 환경에서 ComfyUI와 OpenWebUI를 연동하여 API로 이미지를 생성하는 완전한 설정 방법을 제공합니다.
1. Docker Compose 설정
먼저 필요한 디렉토리 구조와 docker-compose.yml을 설정합니다.
version: '3.8'
services:
comfyui:
image: comfyui:arm64 # ARM64 기반 이미지 사용
container_name: comfyui-server
restart: unless-stopped
environment:
- NVIDIA_VISIBLE_DEVICES=all # NVIDIA GPU 사용 (지원 시)
ports:
- "8188:8188" # ComfyUI 웹 인터페이스
volumes:
- ./comfyui-data/models:/comfyui/models
- ./comfyui-data/input:/comfyui/input
- ./comfyui-data/output:/comfyui/output
- ./comfyui-data/custom_nodes:/comfyui/custom_nodes
networks:
- ai-network
command: >
python -m comfyui.server
--listen 0.0.0.0
--port 8188
--disable-auto-launch
openwebui:
image: ghcr.io/open-webui/open-webui:arm64 # ARM64 버전
container_name: openwebui
restart: unless-stopped
ports:
- "3000:8080" # OpenWebUI 웹 인터페이스
environment:
- OLLAMA_BASE_URL=http://ollama:11434 # Ollama 연동 (선택)
- OPENAI_API_KEY=${OPENAI_API_KEY} # 환경 변수로 설정
volumes:
- ./openwebui-data:/app/backend/data
networks:
- ai-network
depends_on:
- comfyui
networks:
ai-network:
driver: bridge
volumes:
comfyui-models:
openwebui-data:
2. ComfyUI ARM64 Docker 이미지 빌드
ARM64 시스템(예: Raspberry Pi, 다른 ARM 보드)에서 ComfyUI를 실행하려면 커스텀 Dockerfile이 필요합니다.
# Dockerfile.comfyui (ComfyUI ARM64)
FROM python:3.11-slim-bullseye
# ARM64 의존성 설치
RUN apt-get update && apt-get install -y \
git \
build-essential \
libssl-dev \
libffi-dev \
wget \
curl \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /comfyui
# ComfyUI 저장소 클론
RUN git clone https://github.com/comfyanonymous/ComfyUI.git /comfyui
# Python 의존성 설치 (ARM64 호환성)
RUN pip install --no-cache-dir \
torch==2.1.0 torchvision==0.16.0 torchaudio==2.1.0 \
numpy \
pillow \
scipy \
scikit-image \
opencv-python-headless \
aiohttp \
websockets
# 포트 노출
EXPOSE 8188
# 기본 커맨드
CMD ["python", "-m", "comfyui.server", "--listen", "0.0.0.0", "--port", "8188"]
빌드 명령:
docker build -f Dockerfile.comfyui -t comfyui:arm64 .
3. ComfyUI API를 통한 이미지 생성
ComfyUI API 호출을 위한 Python 스크립트:
# generate_image.py
import requests
import json
import time
import base64
from pathlib import Path
from typing import Dict, Optional
class ComfyUIClient:
def __init__(self, base_url: str = "http://localhost:8188"):
self.base_url = base_url
self.api_url = f"{base_url}/api"
def get_system_stats(self) -> Dict:
"""시스템 상태 조회"""
response = requests.get(f"{self.api_url}/system")
return response.json()
def queue_prompt(self, workflow: Dict) -> str:
"""프롬프트 큐에 추가"""
response = requests.post(
f"{self.api_url}/prompt",
json=workflow
)
data = response.json()
return data.get("prompt_id")
def get_history(self, prompt_id: str) -> Dict:
"""실행 결과 조회"""
response = requests.get(f"{self.api_url}/history/{prompt_id}")
return response.json()
def wait_for_completion(self, prompt_id: str, timeout: int = 300) -> Optional[Dict]:
"""작업 완료 대기"""
start_time = time.time()
while time.time() - start_time < timeout:
history = self.get_history(prompt_id)
if prompt_id in history:
return history[prompt_id]
time.sleep(1)
raise TimeoutError(f"작업이 {timeout}초 내에 완료되지 않음")
def download_image(self, filename: str, subfolder: str = "output") -> bytes:
"""생성된 이미지 다운로드"""
response = requests.get(
f"{self.api_url}/view",
params={"filename": filename, "subfolder": subfolder},
stream=True
)
return response.content
def create_txt2img_workflow(
prompt: str,
negative_prompt: str = "",
steps: int = 20,
cfg_scale: float = 7.5,
width: int = 512,
height: int = 512,
seed: int = 0,
checkpoint: str = "sd15.safetensors"
) -> Dict:
"""텍스트-이미지 워크플로우 생성"""
workflow = {
"1": {
"inputs": {
"seed": seed,
"steps": steps,
"cfg": cfg_scale,
"sampler_name": "euler",
"scheduler": "normal",
"denoise": 1,
"model": ["4", 0],
"positive": ["3", 0],
"negative": ["3", 1],
"latent_image": ["5", 0]
},
"class_type": "KSampler",
"_meta": {"title": "KSampler"}
},
"3": {
"inputs": {
"text": prompt,
"clip": ["4", 1]
},
"class_type": "CLIPTextEncode",
"_meta": {"title": "CLIP Text Encode (Prompt)"}
},
"4": {
"inputs": {
"ckpt_name": checkpoint
},
"class_type": "CheckpointLoaderSimple",
"_meta": {"title": "Load Checkpoint"}
},
"5": {
"inputs": {
"width": width,
"height": height,
"length": 1,
"batch_size": 1
},
"class_type": "EmptyLatentImage",
"_meta": {"title": "Empty Latent Image"}
},
"8": {
"inputs": {
"samples": ["1", 0],
"vae": ["4", 2]
},
"class_type": "VAEDecode",
"_meta": {"title": "VAE Decode"}
},
"9": {
"inputs": {
"filename_prefix": "ComfyUI",
"images": ["8", 0]
},
"class_type": "SaveImage",
"_meta": {"title": "Save Image"}
}
}
# Negative prompt 추가 (있는 경우)
if negative_prompt:
workflow["3"]["inputs"]["text"] = {
"positive": prompt,
"negative": negative_prompt
}
return workflow
# 사용 예제
if __name__ == "__main__":
client = ComfyUIClient(base_url="http://localhost:8188")
# 시스템 상태 확인
print("ComfyUI 시스템 상태:", client.get_system_stats())
# 워크플로우 생성
workflow = create_txt2img_workflow(
prompt="a beautiful landscape with mountains",
negative_prompt="blurry, low quality",
steps=30,
cfg_scale=7.5,
width=768,
height=512
)
# 프롬프트 큐에 추가
prompt_id = client.queue_prompt(workflow)
print(f"작업 ID: {prompt_id}")
# 완료 대기
result = client.wait_for_completion(prompt_id)
print(f"완료됨: {result}")
# 이미지 다운로드
if result and "outputs" in result:
for node_id, output in result["outputs"].items():
if "images" in output:
for image in output["images"]:
image_data = client.download_image(image["filename"])
with open(f"output_{image['filename']}", "wb") as f:
f.write(image_data)
print(f"이미지 저장됨: output_{image['filename']}")
4. OpenWebUI와 ComfyUI 연동
OpenWebUI에서 ComfyUI API를 호출하도록 설정합니다.
# .env 파일 (docker-compose와 같은 디렉토리)
OPENAI_API_KEY=your_api_key_here
COMFYUI_API_URL=http://comfyui:8188
OpenWebUI 커스텀 필터 스크립트:
# openwebui_comfyui_filter.py
from typing import Optional
import requests
import json
class ToolFilter:
def __init__(self):
self.comfyui_url = "http://comfyui:8188"
async def inlet(self, body: dict, __user__: Optional[dict] = None) -> dict:
"""OpenWebUI 요청 전 처리"""
return body
async def outlet(self, body: dict, __user__: Optional[dict] = None) -> dict:
"""OpenWebUI 응답 후 처리 - 이미지 생성 요청 감지"""
# 사용자 메시지에서 이미지 생성 키워드 감지
if "generate image" in body.get("content", "").lower():
try:
# ComfyUI API 호출
workflow = self._create_workflow(body.get("content"))
response = requests.post(
f"{self.comfyui_url}/api/prompt",
json=workflow
)
if response.status_code == 200:
prompt_id = response.json().get("prompt_id")
body["content"] += f"\n\n[Image generation started: {prompt_id}]"
except Exception as e:
body["content"] += f"\n\n[Error: {str(e)}]"
return body
def _create_workflow(self, prompt: str) -> dict:
"""프롬프트에서 워크플로우 생성"""
return {
# 워크플로우 JSON (위 코드 참고)
}
5. 실행 및 배포
컨테이너 시작
# docker-compose 실행
docker-compose up -d
# 로그 확인
docker-compose logs -f comfyui
docker-compose logs -f openwebui
# ComfyUI 접속: http://localhost:8188
# OpenWebUI 접속: http://localhost:3000
헬스 체크
# ComfyUI 상태 확인
curl http://localhost:8188/api/system
# OpenWebUI 상태 확인
curl http://localhost:3000/api/status
6. ARM64 최적화 팁
성능 개선:
# GPU 메모리 할당 최적화 (docker-compose에 추가)
environment:
- PYTORCH_ENABLE_MPS_FALLBACK=1
- OMP_NUM_THREADS=4
# 리소스 제한 설정
deploy:
resources:
limits:
cpus: '4'
memory: 4G
reservations:
memory: 2G
모델 최적화:
- INT8/INT4 양자화 모델 사용
- 낮은 해상도(256x256, 512x512)로 시작
- 스텝 수 감소 (15-20 스텝)
- CPU 기반 추론은 느릴 수 있으므로 GPU 가속 권장
이 설정으로 Ubuntu ARM64 도커 환경에서 ComfyUI와 OpenWebUI를 완벽하게 연동할 수 있습니다!