흔한 오해: Pixelle-Video가 영상을 직접 "생성하는 거대 모델"이라고 생각하기 쉽다. 아니다. 무거운 추론(이미지·영상 생성)은 전부 ComfyUI·RunningHub·외부 API에 위임하고, 이 저장소 자체에는 torch·diffusers 같은 모델 의존성이 없다. Pixelle-Video의 진짜 정체는 "주제 → 대본 → 이미지 → 음성 → 영상"이라는 조립 라인을 순서대로 돌리고, 각 공정을 어떤 모델로 할지 런타임에 결정하는 오케스트레이터다. 그래서 배울 거리는 "영상 생성 모델"이 아니라 "멀티모달 파이프라인을 어떻게 설계하는가"에 있다.
README의 표현 그대로다 — "Just input a topic, and Pixelle-Video will automatically: 대본 작성 / AI 이미지·영상 생성 / 음성 나레이션 합성 / 배경음악 추가 / 원클릭 영상 완성." 입력은 (A) 주제 한 줄("독서 습관을 길러야 하는 이유" 같은), (B) 이미 완성된 대본, (C) 직접 올린 사진·영상·오디오 중 하나. 출력은 자막·나레이션·BGM이 다 얹힌 세로/정사각/가로 숏폼 MP4 한 편이다.
영상 제작 스튜디오를 통째로 자동화한 "무인 공장"을 생각하면 된다. 보통 유튜브 쇼츠 한 편을 만들려면 작가(대본), 일러스트레이터(그림), 성우(내레이션), 편집자(자막·BGM·컷 편집)가 각자 일하고 그 결과물을 이어 붙여야 한다. Pixelle-Video는 이 네 직군을 각각 AI 모델로 세워놓고, "주제만 던지면 컨베이어 벨트가 알아서 돈다".
여기서 핵심은 공장장(오케스트레이터)이다. 공장장은 그림을 직접 그리지 않는다. "이번 그림은 FLUX 라인에서, 다음 영상은 WAN 라인에서, 내레이션은 Edge-TTS 라인에서 뽑아" 하고 각 작업대에 지시만 내린다. 작업대(모델)는 언제든 교체 가능하다.
setup → generate_content → determine_title → plan_visuals → initialize_storyboard → produce_assets → post_production → finalize 8단계로 되어 있다. 각 단계는 독립적이라, 한 단계만 바꿔 끼워도 전체가 돌아간다.Pixelle-Video가 노리는 지점이 정확히 여기다. "더 좋은 영상 생성 모델을 만든다"가 아니라 — 그건 이미 FLUX·WAN·Seedance 같은 전문 모델들이 하고 있다 — 그 모델들을 순서대로 엮어서 "주제 한 줄 → 완성 영상"이라는 사용자 경험을 완성하는 쪽으로 문제를 푼다. 진입 장벽 제로, 편집 경험 제로가 슬로건이다.
"MoneyPrinterTurbo 같은 자동 영상 도구는 이미 있는데 왜 또?"가 당연한 첫 반응이다. 실제로 README도 MoneyPrinterTurbo·NarratoAI·MoneyPrinterPlus를 참조 프로젝트로 밝히고 있다. 차별점은 "원자 능력(Atomic Capability)의 조합"이라는 설계 철학에 있다.
| 방식 | 영상 생성 방식 | 한계 / 특징 |
|---|---|---|
| MoneyPrinterTurbo류 | 스톡 영상 클립을 검색해 짜깁기 + TTS | 빠르지만 "내 주제에 딱 맞는 장면"은 못 만듦. 생성이 아니라 검색·조합 |
| 단일 모델 SaaS (Sora·Kling 웹) | 거대 영상 모델이 클립 하나를 생성 | 클립 품질은 높지만 대본·자막·나레이션·BGM까지의 "완성 파이프라인"은 사용자 몫 |
| ComfyUI 단독 | 노드 그래프로 이미지·영상 생성 | 강력하지만 노드를 직접 짜야 함. "주제→영상" 자동화 로직은 없음 |
| Pixelle-Video | LLM+TTS+이미지+영상 모델을 조립 라인으로 오케스트레이션 | 각 공정을 ComfyUI/RunningHub/직접 API로 런타임 교체. 완성 파이프라인 전체를 자동화 |
다른 도구들이 특정 모델·특정 방식에 묶여 있다면, Pixelle-Video는 각 단계를 독립 부품으로 분리했다. 이미지는 오늘 FLUX, 내일 Qwen-Image, 모레 Nano Banana로 바꿔도 된다. 영상은 로컬 GPU(ComfyUI)로 뽑든, 클라우드(RunningHub)로 뽑든, 직접 API(Seedance·Kling)로 뽑든 같은 파이프라인이 돈다. 이 유연성이 채택률을 갈랐다.
실무 채택에서 이게 크다. Pixelle-Video는 LLM을 로컬 Ollama로, 영상 생성을 로컬 ComfyUI로 돌리면 API 비용 0원으로 전체 파이프라인을 굴릴 수 있다. README FAQ가 이 "완전 로컬·무료" 경로를 명시한다. 반대로 GPU가 없으면 RunningHub(클라우드 GPU)나 DashScope·Seedance·Kling 같은 직접 API로 갈아타면 된다 — 같은 코드, 설정만 바꿔서.
커피를 내리는데 "우리 카페 전용 캡슐만 쓰세요"가 아니라, "원두를 직접 갈든(로컬 GPU), 캡슐을 쓰든(클라우드 API), 드립백을 쓰든(직접 API) 우리 기계는 다 받아요"인 셈이다. 예산과 장비에 맞춰 경로를 고르되, 나오는 커피(영상)의 제조 공정은 똑같다.
신뢰에 기여하는 요소다. 이미 Pixelle-MCP·ComfyKit 같은 오픈소스 생태계를 운영하는 조직이라, "AIGC 파이프라인용 완성형 제품"이라는 맥락이 자연스럽다. 게다가 FilmAgent(SIGGRAPH Asia 2024)·ComfyUI-Copilot(ACL 2025)·AniMaker(SIGGRAPH Asia 2025) 같은 논문 시리즈를 README가 함께 걸어둔다 — 단순 토이 프로젝트가 아니라 연구 기반 엔지니어링이라는 신호다. Docker 2-서비스 배포, Windows 올인원 패키지, 다국어 UI까지 실제 팀이 쓸 살이 붙어 있다.
| 영역 | 라이브러리 (버전) | 역할 |
|---|---|---|
| ComfyUI 실행 | comfykit >=0.1.12 | 핵심. ComfyUI 워크플로우를 실행하는 래퍼 — selfhost(로컬)·RunningHub(클라우드) 추상화 |
| LLM 호출 | openai >=2.6.0 | OpenAI 호환 엔드포인트 전부(Qwen·GPT·DeepSeek·Ollama)를 하나의 SDK로 |
| 이미지·영상 API | dashscope >=1.23.0 | 알리바바 통이(Tongyi) Wan 이미지·영상 API 직접 호출 |
| TTS(로컬) | edge-tts ==7.2.7 | Microsoft Edge 음성으로 로컬 나레이션 합성(버전 핀 고정) |
| 영상 합성 | moviepy ==1.0.3 + ffmpeg-python | 세그먼트 concat·오디오 병합·오버레이(버전 핀 고정) |
| 자막 렌더링 | playwright >=1.58.0 | HTML 템플릿을 Chromium 헤드리스로 렌더해 프레임 이미지 생성 |
| MCP | fastmcp >=2.0.0 | Pixelle 생태계 MCP 프레임워크 |
| 스키마/검증 | pydantic >=2.0.0 | 스토리보드·미디어·진행상태 데이터 모델, LLM 구조화 출력 |
| 보조 | pillow · beautifulsoup4 · httpx · loguru · pyyaml | 이미지·HTML 파싱·HTTP·로깅·설정 |
pip+venv+poetry를 한 번에 대체한다. Pixelle-Video는 uv run streamlit run web/app.py 한 줄로 의존성 설치·가상환경·실행을 동시에 처리한다 — requirements.txt 대신 pyproject.toml + uv.lock(652KB)로 의존성을 잠근다.흥미로운 선택이다. React·Vue 같은 SPA 프레임워크가 없다. 대신 Streamlit 멀티페이지 앱으로 UI를 짰다(web/app.py가 st.navigation으로 Home·History 두 페이지 구성). i18n은 web/i18n/locales/{en_US,zh_CN}.json으로 영어·중국어 지원. UI 파이프라인은 5종 — standard·asset_based·digital_human(디지털 아바타)·i2v(이미지→영상)·action_transfer(모션 트랜스퍼). 데이터 과학 도구인 Streamlit을 프로덕션 제품 UI로 쓴, "빠른 UI가 곧 경쟁력"이라는 판단이 읽힌다.
UI와 별개로 api/에 FastAPI 서버가 있다. 라우터가 기능별로 쪼개져 있다 — health · llm · tts · image · content · video · tasks · files · resources · frame. 비동기 태스크 매니저(api/tasks/)로 오래 걸리는 영상 생성을 백그라운드로 돌린다. 즉 Streamlit(사람용 UI)과 FastAPI(프로그램용 API)가 같은 엔진(pixelle_video 패키지)을 공유하는 이중 진입 구조다.
| 경로 | 방식 | 예시 |
|---|---|---|
| ComfyUI 워크플로우 | comfykit이 워크플로우 JSON을 실행. selfhost(로컬 GPU) 또는 runninghub(클라우드) | 이미지 FLUX·Qwen·SD3.5·Nano Banana / 영상 WAN 2.1·2.2·LTX2 / TTS Edge·Index·Spark |
| Direct API 모델 | ComfyUI 없이 provider를 직접 호출(services/api_services/) | Seedance(doubao-seedance-2-0)·Kling(kling-v3)·Seedream·GPT 이미지·DashScope Wan |
노드ID → {inputs, class_type, _meta} 형태의 JSON이 된다(예: KSampler, CLIPTextEncode, FluxGuidance, VAEDecode, SaveImage 노드). Pixelle-Video는 이 JSON을 workflows/{source}/{name}.json에 저장해두고, 실행 시 프롬프트·해상도·길이 같은 값을 해당 노드에 주입해서 돌린다. 즉 ComfyUI를 "그래프 실행 엔진"으로만 빌려 쓴다.| 수단 | 내용 |
|---|---|
| Windows 올인원 | Python·uv·ffmpeg 불필요. start.bat → localhost:8501. packaging/windows/build.py로 빌드 |
| 소스(mac/Linux) | 전제조건 uv + ffmpeg. uv run streamlit run web/app.py |
| Docker | python:3.11-slim + ffmpeg + fonts-noto-cjk + playwright install chromium. API(8000)·Web(8501) 2컨테이너, init이 config.yaml 자동 생성 |
| 문서 | mkdocs 기반 docs/{en,zh}, 사이트 aidc-ai.github.io/Pixelle-Video |
이 장이 이 문서의 심장이다. 주제 텍스트 하나가 StandardPipeline에 들어가 완성 MP4로 나올 때까지 내부에서 벌어지는 일을 따라간다. 두 층위로 나뉜다 — 파이프라인 8단계(전체 흐름)와 그 안의 프레임 처리 4스텝(한 장면씩).
service.py의 전역 싱글턴 pixelle_video가 모든 것의 진입점이다. initialize()에서 LLM·TTS·미디어 서비스를 만들고 파이프라인 3종(standard·custom·asset_based)을 등록한다.
# pixelle_video/service.py — 서비스와 파이프라인을 한곳에 묶는다
self.pipelines = {
"standard": StandardPipeline(self),
"custom": CustomPipeline(self),
"asset_based": AssetBasedPipeline(self),
}
pixelle_video = PixelleVideoCore() # 전역 싱글턴
LinearVideoPipeline이 8단계 순서를 고정하고, StandardPipeline이 각 단계(훅)를 override한다. 새 영상 타입을 만들고 싶으면 8단계 중 필요한 것만 갈아 끼우면 되니, 흐름 제어 코드를 반복해 짤 필요가 없다.8단계가 서로 데이터를 주고받는 방식이 깔끔하다. 각 단계가 전역 변수를 건드리는 대신, 하나의 PipelineContext dataclass를 단계에서 단계로 넘긴다. 앞 단계가 채운 필드(나레이션·제목·스토리보드)를 뒤 단계가 읽는다. 예외가 나면 handle_exception이 한곳에서 처리한다. 상태가 한 객체에 모여 있으니 디버깅과 중간 재개가 쉽다.
produce_assets 단계는 스토리보드의 각 프레임(장면)을 FrameProcessor에 하나씩 넘긴다. 한 프레임이 완성 영상 세그먼트가 되는 과정이 4스텝이다.
멀티모달 파이프라인의 골칫거리는 "음성 길이와 영상 길이가 안 맞는 것"이다. 보통은 영상을 자르거나 무음을 채워 억지로 맞춘다. Pixelle-Video는 반대로 간다 — 먼저 나레이션 오디오를 만들어 그 길이를 재고, 그 길이를 영상 생성 요청의 목표 duration으로 넘긴다. 그러면 영상이 처음부터 나레이션에 맞는 길이로 생성돼 패딩·트리밍이 필요 없다. 순서를 뒤집는 것만으로 동기화 문제를 없앤 실전 해법이다.
# services/frame_processor.py — TTS 길이를 영상 생성에 전달
if is_video_workflow and frame.duration:
media_params["duration"] = frame.duration # TTS 오디오에서 잰 길이
plan_visuals 단계에 영리한 분기가 있다. 템플릿 이름이 static_으로 시작하면(고정 배경 스타일) 이미지 생성 자체를 건너뛴다. 로그에 "Savings: N LLM calls + N media generations"가 찍힌다. 장면마다 그림이 꼭 필요한 건 아니라는 통찰 — 텍스트·타이포 중심 영상이면 이미지 생성 비용을 통째로 아낀다. 반대로 image_·video_ 템플릿이면 장면별 프롬프트를 LLM으로 배치 생성한다(batch=10, 실패 시 최대 3회 재시도, 개수 안 맞으면 재시도).
모든 프레임 세그먼트가 완성되면 post_production이 VideoService.concat_videos로 이어 붙이고 배경음악을 얹는다. BGM은 bgm_mode="loop"로 영상 길이에 맞춰 반복되고, 볼륨은 나레이션을 방해하지 않도록 0.2로 낮춘다. 기본 BGM 파일은 bgm/default.mp3. 마지막 finalize에서 태스크 메타데이터와 스토리보드를 저장하고 최종 결과 객체를 반환한다.
| 디렉토리 | 역할 |
|---|---|
pixelle_video/ | 실제 설치되는 엔진 패키지. UI·API가 전부 이걸 import해서 쓴다 |
pipelines/ | Template Method 파이프라인. linear.py가 뼈대, standard.py가 기본 구현 |
services/ | LLM·TTS·이미지·영상·VLM을 각각 독립 서비스로. "원자 능력"의 실체 |
services/api_services/ | ComfyUI를 안 거치는 직접 API 클라이언트들(Seedance·Kling·Seedream·DashScope) |
workflows/ | ComfyUI 그래프 JSON을 {source}/{name}.json으로. 파일명 프리픽스(image_/video_/tts_)로 자동 스캔 |
templates/ | 자막·레이아웃 HTML. static_/image_/video_ 3종 네이밍이 곧 렌더 전략 |
web/ · api/ | 같은 엔진을 감싸는 두 진입점 — 사람용 Streamlit, 프로그램용 FastAPI |
config/ | YAML 설정 로더. 해시 변경을 감지해 ComfyKit을 재생성(핫리로드) |
media.py(ComfyUI)와 api_media.py(직접 API)가 나란히 있는 게 이 코드베이스의 설계 감각을 보여준다. "이미지를 만든다"라는 같은 능력을 두 가지 다른 수단으로 구현해두고, 설정만으로 고를 수 있게 했다. 능력(무엇을)과 수단(어떻게)을 분리하는 이 감각이 services/ 전체를 관통한다 — 그래서 새 모델 provider가 나와도 api_services/에 파일 하나만 추가하면 된다.
# services/llm_service.py — OpenAI SDK 하나로 모든 provider
# Ollama는 API 키가 필요 없지만 SDK는 키를 요구한다 → 가짜 키를 넣는다
final_api_key = api_key or self._get_config_value("api_key") or "dummy-key"
# LLM이 ```json ... ``` 코드블록으로 감싸 답해도, 앞뒤에 말을 붙여도 파싱
def _parse_json(text):
# markdown 코드펜스 제거 + 정규식으로 { ... } 추출 후 json.loads
... # 개수가 안 맞으면 호출부에서 max_retries=3으로 재시도
# RunningHub(클라우드)면 프레임을 동시에, 아니면 순차로
if is_runninghub and runninghub_concurrent_limit > 1:
semaphore = asyncio.Semaphore(runninghub_concurrent_limit)
results = await asyncio.gather(*tasks) # 프레임 병렬
# Role Definition: 콘텐츠 전문가 역할 부여
# - 단어 수 {min_words}~{max_words} 제한
# - 언어 일관성 강제: 입력이 영어면 출력도 영어
# - 오프닝 다양성: 같은 단어로 2회 이상 시작하면 실패
# - 출력은 엄격한 {"narrations": [...]} JSON
_get_or_create_comfykit이 ComfyKit 인스턴스를 새로 만든다. 서비스들은 항상 config_manager에서 값을 동적으로 조회하므로, UI에서 모델·API 키를 바꿔도 앱을 껐다 켤 필요가 없다.| 주제 | 구체적으로 무엇을 |
|---|---|
| 멀티모달 파이프라인 설계 | LLM→이미지→TTS→영상을 순서 있는 조립 라인으로. Template Method + Context 객체 전달 |
| ComfyUI를 백엔드로 추상화 | 무거운 모델을 앱에 넣지 않고, 워크플로우 JSON에 파라미터를 주입해 "그래프 실행 엔진"으로 사용 |
| 능력/수단 분리 | "이미지 생성"이라는 능력을 ComfyUI·직접API 두 수단으로 구현, 런타임 교체 |
| 오디오 주도 동기화 | TTS 길이를 먼저 재서 영상 길이를 맞추는, 순서 뒤집기로 동기화 문제 제거 |
| HTML+Playwright 렌더링 | 자막·레이아웃을 HTML/CSS로 짜고 Chromium 헤드리스로 프레임 이미지화(웹 스킬 재사용) |
| OpenAI 호환 통합 | Qwen·GPT·DeepSeek·Ollama를 base_url만 바꿔 하나의 SDK로 처리 |
| 견고한 LLM 출력 파싱 | 코드펜스·잡음 제거 + 배치 + 개수 검증 + 재시도. 실전 LLM 신뢰성 패턴 |
| 비용 최적화 분기 | static 템플릿이면 이미지 생성·LLM 호출을 통째로 스킵 |
| 항목 | 요구사항 |
|---|---|
| Python | 3.11+ (pyproject 기준). 설치·실행은 uv 권장 |
| 필수 도구 | ffmpeg(영상 합성) + Playwright Chromium(자막 렌더, playwright install chromium) |
| OS | Windows(올인원 패키지) · macOS · Linux(소스/Docker) |
| GPU | 선택. RunningHub·직접 API를 쓰면 로컬 GPU 불필요 / ComfyUI selfhost로 로컬 생성 시 GPU 필요(README에 "RunningHub 48G VRAM 지원" 언급) |
| ComfyUI | selfhost 모드일 때 별도로 기동해야 함(기본 127.0.0.1:8188). Docker에선 host.docker.internal:8188 |
| API 키 | LLM provider 1개(Qwen/OpenAI/DeepSeek) 또는 Ollama(무료) + (선택) RunningHub·DashScope·ARK·Kling 키 |
# 전제조건: uv + ffmpeg 설치
git clone https://github.com/AIDC-AI/Pixelle-Video.git
cd Pixelle-Video
cp config.example.yaml config.yaml # 설정 편집(LLM·모델·API 키)
uv run streamlit run web/app.py # 의존성 자동 설치 후 실행
# → http://localhost:8501
docker-compose up -d
# init이 config.yaml 자동 생성, api(8000)·web(8501) 2컨테이너 기동
# 중국 미러가 필요하면: USE_CN_MIRROR=true
LLM = Ollama(로컬, 예: llama3.2) + 이미지·영상 = 로컬 ComfyUI. 이 조합이면 외부 API 비용이 0원이다. GPU가 없거나 품질을 높이고 싶으면 그 두 축만 클라우드(RunningHub) 또는 직접 API(Seedance·Kling)로 갈아 끼우면 된다 — 파이프라인 코드는 그대로.
Ollama를 로컬에 띄우고 config.yaml의 LLM을 localhost:11434/v1로 설정한다. 이미지 생성이 필요 없는 static_ 템플릿을 골라, 주제 한 줄로 텍스트·나레이션 중심 영상을 만든다. 로그에서 "Savings: N media generations"가 찍히는 걸 확인하며 "언제 이미지 생성을 건너뛰는가"를 체감한다.
templates/의 기존 HTML 하나를 복제해 폰트·색·자막 위치를 바꾼 image_mytheme.html을 만든다. Playwright가 이 HTML을 렌더해 프레임이 되는 구조라, CSS만 고쳐도 영상 룩이 바뀐다. "영상 편집을 웹 디자인으로 치환한" 설계를 직접 활용해보는 단계.
services/api_services/의 기존 클라이언트(예: image_seedream)를 본떠, 아무 이미지 생성 API를 감싸는 새 클라이언트를 추가한다. api_media.list_workflows()에 노출되게 하고, 설정에서 선택 가능하게 한다. "능력/수단 분리"가 왜 확장에 강한지 직접 확인.
LinearVideoPipeline을 상속한 새 파이프라인을 만들어, initialize_storyboard 뒤에 "각 나레이션을 영어로 번역해 이중 자막을 만드는" 단계를 끼운다. Template Method 구조라 다른 단계는 건드리지 않고 훅 하나만 추가하면 된다는 걸 체험.
api/의 태스크 매니저를 활용해, 주제 여러 개를 받아 큐에 넣고 병렬로 영상을 생성하는 배치 엔드포인트를 짠다. RunningHub의 concurrent_limit와 연동해 동시 실행 수를 제어하고, 진행률을 폴링으로 반환하는 실전 비동기 서비스.
| 주차 | 주제 | 무엇을 |
|---|---|---|
| 1주차 | AIGC 파이프라인 기초 | 텍스트→이미지→영상 생성 모델의 계보(Diffusion·FLUX·WAN). 프롬프트 엔지니어링과 배치·재시도 패턴 |
| 2주차 | ComfyUI & 워크플로우 | 노드 그래프의 원리, 워크플로우 JSON 구조, API 실행. ComfyKit이 어떻게 파라미터를 주입하는지 추적 |
| 3주차 | 멀티모달 동기화·합성 | ffmpeg concat·overlay·audio merge, TTS 길이 측정(ffmpeg.probe), 오디오 주도 동기화. Playwright 헤드리스 렌더 |
| 4주차 | 오케스트레이션 설계 | Template Method·Context 전달·능력/수단 분리·핫리로드 설정. 나만의 새 파이프라인 타입 구현 |
Storyboard는 StoryboardFrame(index, narration, image_prompt) 배열로, 각 프레임이 나레이션·이미지프롬프트를 들고 있다가 FrameProcessor에서 실제 영상 세그먼트로 실체화된다.edge-tts(Microsoft Edge 음성)를 기본으로, ComfyUI 워크플로우(Index-TTS·Spark-TTS)로 확장한다. Index-TTS는 ref_audio(참조 음성)로 목소리 복제도 지원한다.comfykit으로 둘을 같은 인터페이스로 추상화해, 설정만 바꿔 로컬↔클라우드를 전환한다.st.navigation으로 멀티페이지 구성).