왜 폴더 구조를 먼저 설계하는가
이미지 생성 자동화는 여러 파일이 서로 의존합니다. job.json을 worker.ps1이 읽고, worker.ps1이 comfy_workflow.json을 읽고, 결과를 result.json에 씁니다. 파일들이 흩어져 있으면 어디서 문제가 생겼는지 찾기 어렵습니다. 폴더 구조를 처음부터 잡아두면 코드도 단순해지고, 나중에 시스템을 바꿀 때도 특정 폴더만 건드리면 됩니다.
실제 폴더 전체 구조
D:\016_CardNew\n├── io\n│ ├── comfy_workflow.json ← ComfyUI 워크플로우 (API Format)
│ ├── job.json ← Linux가 보내는 작업 요청 파일
│ ├── result.json ← worker.ps1이 완료 후 돌려주는 결과
│ └── restart-comfy.ps1 ← ComfyUI (재)시작 스크립트
├── scripts\n│ ├── worker.ps1 ← 메인 실행 스크립트 (PowerShell)
│ └── worker.py ← 대안 실행 스크립트 (Python)
├── output\n│ └── result_20260305_143022.jpg ← 생성 이미지 (날짜시간으로 누적)
├── .venv ← worker.py용 Python 가상환경
└── slide_01.png ← 기타 작업 파일
폴더가 세 개입니다. io/는 파일 교환 공간, scripts/는 실행 스크립트, output/은 결과 이미지 보관입니다.
io 폴더 — Linux와 Windows의 교환 공간
io 폴더는 Linux 서버와 Windows 서버가 파일을 주고받는 우체통입니다. Linux가 편지(job.json)를 보내면, worker.ps1이 꺼내 읽고, 답장(result.json)을 넣어둡니다. Linux가 그 답장을 가져갑니다.
job.json — 작업 요청 파일
Linux 서버가 만들어서 Windows로 SCP 전송하는 파일입니다.
{
"job_id": "test_001",
"topic": "card_test",
"image_prompt": "cozy korean chibi girl, cat-ear hoodie, warm pastel light, cinematic",
"negative_prompt": "blurry, watermark, text"
}
각 필드의 역할입니다.
job_id: 작업 식별자입니다. 여러 작업이 순서대로 처리될 때 어떤 작업인지 구분합니다. result.json에 그대로 담겨서 돌아옵니다. Linux에서 결과를 받았을 때 "이게 내가 보낸 test_001 요청의 결과구나"라고 확인하는 데 씁니다.
topic: 이 이미지가 어떤 주제의 카드뉴스용인지 적는 메모입니다. 파이프라인 로직에는 영향을 주지 않습니다. 나중에 로그를 볼 때 맥락을 파악하는 데 씁니다.
image_prompt: ComfyUI에 넣을 긍정 프롬프트입니다. worker.ps1이 이 값을 comfy_workflow.json의 노드 "6"(Positive Prompt)의 inputs.text에 주입합니다. 영어로 적어야 z_image_turbo 모델에서 결과가 잘 나옵니다. 한국어 프롬프트도 qwen 인코더 덕분에 인식되지만, 영어 품질이 더 안정적입니다.
negative_prompt: 원하지 않는 요소를 적습니다. worker.ps1이 노드 "7"(Negative Prompt)에 주입합니다. 이 필드가 job.json에 없으면 worker.ps1이 기본값 "blurry, low quality, watermark"를 씁니다.
result.json — 작업 완료 결과
worker.ps1이 이미지 생성을 마친 후 io 폴더에 저장하는 파일입니다. Linux가 이 파일을 가져가서 성공 여부를 확인하고 이미지 경로를 얻습니다.
{
"prompt_id": "626d4d7c-6955-4577-a2b6-80d4cd80c172",
"status": "ok",
"output_image": "D:\016_CardNew\output\result_20260322_105758.jpg"
}
prompt_id: ComfyUI가 이 작업에 부여한 UUID입니다. ComfyUI 히스토리에서 이 작업을 직접 찾을 때 씁니다. 디버깅 시 ComfyUI GUI에서 이 ID로 작업을 검색할 수 있습니다.
status: "ok" 또는 "error"입니다. Linux에서 result.json을 받으면 이 값을 제일 먼저 확인합니다. "ok"면 output_image 경로의 파일을 가져오면 됩니다. "error"면 이미지 생성이 실패한 것입니다.
output_image: 생성된 이미지 파일의 Windows 전체 경로입니다. JSON에서 백슬래시를 이스케이프해서 씁니다. Linux에서 이 경로를 파싱해서 SCP로 파일을 가져옵니다.
comfy_workflow.json — 워크플로우
1단계에서 ComfyUI API Format으로 내보낸 파일입니다. 이 파일이 없으면 worker.ps1이 실행을 거부하고 "workflow not found" 에러를 result.json에 씁니다.
노드 구성을 다시 정리합니다. 핵심은 노드 "6"과 "7"입니다.
노드 16 (UNETLoader) : z_image_turbo_nvfp4.safetensors 로드
노드 17 (VAELoader) : ae.safetensors 로드
노드 18 (CLIPLoader) : qwen_3_4b.safetensors 로드 (type: lumina2)
|
노드 11 (ModelSamplingAuraFlow): shift=7 적용
노드 6 (CLIPTextEncode) : Positive Prompt ← worker.ps1이 교체
노드 7 (CLIPTextEncode) : Negative Prompt ← worker.ps1이 교체
노드 13 (EmptySD3LatentImage) : 1080x1080 빈 잠재 생성
|
노드 3 (KSampler) : steps=15, cfg=1, dpmpp_sde, beta 스케줄러
|
노드 8 (VAEDecode) : 잠재 -> 이미지
노드 9 (SaveImage) : ComfyUI output 폴더에 저장
cfg=1은 매우 낮은 값입니다. 일반적인 Stable Diffusion에서는 7~10을 씁니다. z_image_turbo는 Flow Matching 기반이라 cfg=1에서도 좋은 결과가 나옵니다. 높게 설정하면 오히려 품질이 떨어집니다.
restart-comfy.ps1 — ComfyUI 재시작
ComfyUI가 멈췄거나 모델을 다시 로드해야 할 때 씁니다. 위치는 D:\016_CardNewio estart-comfy.ps1입니다.
Stop-Process -Name python -Force -ErrorAction SilentlyContinue
Start-Sleep -Seconds 2
Start-Process -FilePath 'E:AIpython_embededpython.exe' `
-ArgumentList @('-s','ComfyUImain.py','--windows-standalone-build') `
-WorkingDirectory 'E:AI' `
-WindowStyle Minimized
Start-Sleep -Seconds 20
Invoke-RestMethod -Method Get -Uri 'http://127.0.0.1:8188/system_stats' | ConvertTo-Json -Depth 3
scripts 폴더 — 실행 스크립트
worker.ps1 — 메인 스크립트
파이프라인 전체를 실행하는 PowerShell 스크립트입니다. 다음 단계에서 전체 코드를 라인별로 분석합니다. PowerShell을 쓰는 이유는 Windows에서 SSH 원격 실행이 가장 자연스럽기 때문입니다.
worker.py — Python 대안 스크립트
worker.ps1과 동일한 역할을 Python으로 구현한 버전입니다. 사용하려면 먼저 .venv를 활성화해야 합니다.
D:\016_CardNew.venvScriptspython.exe D:\016_CardNewscriptsworker.py
Python 버전은 결과 이미지를 고정 파일명 output/result.jpg로 저장합니다. 여러 번 실행하면 덮어씌워집니다. 타임스탬프 파일명이 필요하면 worker.ps1을 씁니다.
output 폴더 — 이미지 보관
worker.ps1이 생성 이미지를 여기 저장합니다. 파일명 형식은 result_날짜_시간.jpg입니다.
result_20260305_143022.jpg
result_20260310_091547.jpg
result_20260322_105758.jpg
2026년 3월 5일부터 이미지가 누적됩니다. 파일명에 날짜시간이 있으므로 중복 없이 쌓입니다.
주의: ComfyUI 자체도 E:AIComfyUIoutput 폴더에 이미지를 저장합니다. worker.ps1은 ComfyUI가 저장한 이미지를 /view API로 가져와서 D:\016_CardNewoutput에 별도로 저장합니다. 즉 이미지가 두 곳에 생깁니다. ComfyUI 내부 output 폴더는 지우지 않으면 계속 쌓입니다.
폴더 만들기
Windows PowerShell에서 아래 명령으로 전체 구조를 한 번에 만들 수 있습니다.
New-Item -ItemType Directory -Force -Path "D:\016_CardNewio"
New-Item -ItemType Directory -Force -Path "D:\016_CardNewscripts"
New-Item -ItemType Directory -Force -Path "D:\016_CardNewoutput"
-Force 옵션은 이미 폴더가 있어도 에러 없이 넘어갑니다. 이미 만들어진 상태라면 아무 것도 바꾸지 않습니다.
ComfyUI 내부 output 폴더 확인
ComfyUI가 이미지를 내부적으로 어디에 저장했는지 확인하려면 ComfyUI GUI를 열거나, E:AIComfyUIoutput 폴더를 직접 탐색기로 확인합니다. 이 프로젝트의 SaveImage 노드는 prefix를 Z_Image_Turbo/날짜/image로 설정했기 때문에 파일이 E:AIComfyUIoutputZ_Image_Turbo날짜 폴더 안에 생깁니다.
worker.ps1의 /view API 호출이 이 파일을 가져옵니다. ComfyUI 내부 output 폴더에 파일이 없으면 worker.ps1도 실패합니다.
다음 단계에서 할 것
폴더 구조와 각 파일의 역할을 이해했습니다. job.json, result.json, comfy_workflow.json의 실제 내용도 확인했습니다. 다음 단계에서는 메인 스크립트인 worker.ps1의 전체 코드를 라인별로 분석합니다.
