React와 TypeScript로 ComfyUI용 커스텀 노드 만들기
2024-10-10 08:14:38소개
안녕하세요, 개발자 커뮤니티 여러분! 이번 포스트에서는 React와 TypeScript를 사용하여 Stable Diffusion 모델을 활용한 ComfyUI용 커스텀 노드를 개발하는 방법에 대해 알아보겠습니다. 이 도구는 개발자와 아티스트가 간단한 UI를 통해 창의적인 비주얼을 생성하는 데 도움을 줍니다. 이번 구현에서는 WebSocket 통신, workflow.json 통합, 실시간 이미지 생성 피드백 등 강력하고 직관적인 사용자 경험을 위한 주요 측면을 다룹니다.
사전 준비 사항
ComfyUI 설치
ComfyUI를 설치해야 합니다. ComfyUI는 Stable Diffusion을 사용하여 이미지 생성 워크플로우 및 파이프라인을 생성할 수 있는 강력하고 모듈화된 UI입니다. 설치 지침은 GitHub 페이지에서 확인할 수 있습니다. 이 예제에서는 DreamShaper 8 모델을 사용합니다.
ComfyUI 커스텀 노드
커스텀 노드는 ComfyUI의 기능을 확장하는 사용자 정의 노드입니다. 개발자는 이를 통해 새로운 유형의 작업을 생성하거나 다양한 모델과 알고리즘을 통합하여 기본 노드에서는 할 수 없는 특정 목표를 달성할 수 있습니다. 커스텀 노드를 통해 할 수 있는 일은 다음과 같습니다:
- ● 기능 확장: 새로운 모델, 이미지 필터, 또는 사용자 정의 변환 통합
- ● 개인화된 워크플로우: 프롬프트를 조작하거나 고유한 이미지 변형 생성
- ● 사용자 경험 향상: 사용자 제어, 피드백, 동적 매개변수 조정 노드 추가
ComfyUI API와 함께 React 앱 서버 실행하기
ComfyUI 폴더에서 python main.py를 실행하면 Comfy는 custom_nodes 디렉토리를 스캔하여 Python 모듈을 로드하려고 시도합니다. NODE_CLASS_MAPPINGS를 내보내는 모듈이 커스텀 노드로 식별됩니다.
__init__.py Python 모듈은 React 프론트엔드를 ComfyUI 백엔드와 통합합니다. React 애플리케이션을 제공하기 위한 경로를 설정하여 사용자가 웹 인터페이스를 통해 커스텀 노드와 상호작용할 수 있도록 합니다.
웹 루트 설정
React 자산을 제공할 디렉토리를 정의합니다:
WEBROOT = os.path.join(os.path.dirname(os.path.realpath(__file__)), "web/dist")
경로 설정
서버 경로를 추가하여 React 애플리케이션(/Text2Image)과 정적 자산(/assets)을 제공하도록 합니다:
@server.PromptServer.instance.routes.get("/Text2Image")
def init(request):
return web.FileResponse(os.path.join(WEBROOT, "index.html"))
노드 매핑
워크플로우에서 사용할 커스텀 노드 클래스 매핑을 노출합니다. 추가로 ComfyUI 커스텀 노드에 대한 자세한 내용을 읽어보세요.
React 클라이언트 사이드 코드 설명
이제 WebSocket 연결을 설정하고, 특정 수신 메시지를 수신하며, 워크플로우 API JSON 파일을 처리하여 텍스트 프롬프트에 기반한 이미지를 생성하는 방법을 설명하겠습니다.
ComfyUI WebSocket 연결
-
호스트 이름 및 프로토콜: 현재 창의 호스트 이름과 포트를 사용하여 서버 주소를 구성합니다. 보안 연결(https:)에는
wss:를 선택하고, 그렇지 않은 경우에는ws:를 선택합니다. -
wsClient: 고유한 클라이언트 ID를 사용하여
/ws에 WebSocket 연결을 초기화합니다. -
wsClient.onopen: 서버와의 연결이 성공적으로 설정되면 메시지를 로그에 출력합니다.
기본 코드 예제는 다음과 같습니다:
const hostname = window.location.hostname + ":" + window.location.port;
const protocol = window.location.protocol === "https:" ? "wss:" : "ws:";
const wsClient = new WebSocket(
`${protocol}//${hostname}/ws?clientId=${clientUniqueId}`
);
ComfyUI로부터 응답 대기하기
ComfyUI의 응답을 기다립니다. 예를 들어, 다음 코드는 executed 타입의 메시지를 수신했을 때 이미지를 처리합니다.
wsClient.addEventListener("message", (event) => {
const data = JSON.parse(event.data);
if (data.type === "executed") {
if ("images" in data.data.output) {
const image = data.data.output.images[0];
const { filename, type, subfolder } = image;
const rando = Math.floor(Math.random() * 1000);
const imageSrc = `/view?filename=${filename}&type=${type}&subfolder=${subfolder}&rand=${rando}`;
}
}
});
ComfyUI 워크플로우 API JSON 수정하기
워크플로우 API JSON은 ComfyUI의 노드 구성을 나타냅니다. 관련 노드 ID를 찾아 JSON 파일을 검색합니다. 이 예제에서는 랜덤으로 생성된 시드와 적용된 프롬프트 텍스트를 사용합니다.
const samplerNodeNumber = Object.entries(workflow).find(
([key, value]) => value.class_type === "KSampler"
)[0] as keyof typeof workflow;
workflow[samplerNodeNumber].inputs.seed = Math.floor(
Math.random() * 9999999999
);
workflow[inputNodeNumber].inputs.text = prompt.replaceAll(
/\r\n|\n|\r/gm,
" "
);
프롬프트 기반 이미지 생성
ComfyUI는 /prompt 및 /interrupt와 같은 API 라우트를 노출하여 프로세스를 중단합니다.
async function queuePrompt(workflow = {}) {
const data = { prompt: workflow, client_id: clientUniqueId };
const response = await fetch("/prompt", {
method: "POST",
cache: "no-cache",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(data),
});
return await response.json();
}
전체 소스 코드를 확인하고 작업 대기열에 대한 진행 추적과 같은 추가 조정 방법을 찾아보세요. 소스 코드 바로가기
결론
이 포스트를 통해 여러분은 ComfyUI에 React와 TypeScript를 사용하여 커스텀 노드를 생성하고 설정하는 방법을 배우셨습니다. 커스텀 노드는 다양한 이미지 생성 작업을 보다 효율적으로 수행할 수 있게 해줍니다. 앞으로도 새로운 기능을 추가하고, 개선하며, 개발을 통해 더 나은 사용자 경험을 제공할 수 있도록 노력해 봅시다.
참고자료
위의 링크를 통해 다양한 자료를 참고하실 수 있습니다. 여러분의 커스텀 노드 개발에 도움이 되길 바랍니다!