긴 방송/예능 영상을 업로드하면 AI가 쇼츠 후보를 추천하고, 브라우저에서 자막/크롭/오버레이를 조정한 뒤 MP4로 export하는 로컬 개발용 MVP입니다.
현재 버전은 클라우드 서비스가 아니라 내 컴퓨터에서 웹 서버와 영상 처리 worker를 같이 실행하는 방식입니다. 업로드한 원본 영상, 프록시, STT 결과, 렌더 결과는 모두 로컬 storage/ 폴더에 저장됩니다.
제출 소스 코드 구조는 CODEBOOK.md에 정리되어 있고, 제품 기능과 데이터/API/worker 상세 기준 문서는 MBC_CLIPOPS_MASTER_SPEC.md입니다. 기존 스펙/피드백 문서가 서로 다른 시점의 내용을 담고 있을 때는 마스터 스펙을 우선합니다.
- 코드를 받기만 하면 바로 실행되는 앱은 아닙니다. Node.js, Python, FFmpeg 설치가 필요합니다.
- Windows는 네이티브 PowerShell 대신 WSL2 Ubuntu 환경을 권장합니다. FFmpeg, 자막 렌더링, Python worker가 더 안정적으로 동작합니다.
- 기본 후보 분석은 AI 분석 CLI provider를 사용합니다. 초기 검증은 Codex CLI 기반 provider로 했고, 서버에
codex login이 되어 있어야 합니다. - 기본 STT는 whisper.cpp 로컬 실행입니다. 모델 파일 경로와 실행 파일 경로를 설정해야 실제 변환이 됩니다.
- 화자 분리는 STT가 아니라 pyannote.audio 선택 단계입니다. 켜려면 optional dependency와 Hugging Face token/model access가 필요합니다.
- 비용 없이 흐름만 확인하려면
.env.local에서STT_PROVIDER=mock,CANDIDATE_PROVIDER=rules를 쓰면 됩니다. - 1시간 영상은 CPU를 오래 사용합니다. 노트북 팬이 돌고 발열이 생기는 것은 정상입니다.
| 항목 | 용도 | 권장 버전 |
|---|---|---|
| Node.js | Next.js 웹 앱 실행 | 24.x |
| Python | 영상 처리 worker .venv 생성/실행 |
3.11 이상 |
| FFmpeg / ffprobe | 프록시, 오디오, 렌더링 생성 | 최신 stable |
| rsvg-convert | 자막 PNG overlay 생성 | librsvg 패키지 |
| AI 분석 CLI provider | 세그먼트/제목/요약 분석 | 초기 검증은 Codex CLI |
| whisper.cpp | 로컬 STT | Metal/CUDA/Vulkan/CPU 빌드 |
| pyannote.audio | 선택 화자 분리 | Hugging Face token 필요 |
| yt-dlp | YouTube VOD 다운로드 | 최신 stable |
| Git | 코드 다운로드 | 최신 stable |
터미널 앱을 열고 아래 순서대로 실행합니다.
brew --version명령이 없다고 나오면 Homebrew 안내에 따라 설치한 뒤 다시 진행합니다.
brew install node@24 python ffmpeg librsvg gitNode 24가 기본 node로 잡히지 않으면 아래를 실행합니다.
brew link --overwrite --force node@24초기 검증과 같은 후보 분석 경로를 쓰려면 Codex CLI가 필요합니다. 이미 설치된 환경이면 이 단계는 건너뛰고, 없으면 아래처럼 설치한 뒤 로그인합니다.
npm install -g @openai/codexnode -v
python3 --version
ffmpeg -version
ffprobe -version
rsvg-convert --version
codex --versionnode -v가 v24...로 시작하고, python3 --version이 3.11 이상이면 됩니다. 시스템 Python을 직접 쓰지 않고, 아래 앱 설정 단계에서 프로젝트 전용 .venv를 만듭니다.
Windows 서버는 WSL2 Ubuntu 실행을 권장합니다. 네이티브 Windows에서도 가능하지만 FFmpeg, Python worker, 자막 렌더링은 WSL2에서 더 안정적입니다.
worker를 실행할 같은 계정에서 초기 검증용 AI 분석 CLI 로그인을 먼저 마칩니다.
codex login
codex exec --help권장 .env.local 예시:
STT_PROVIDER=whisper_cpp
CANDIDATE_PROVIDER=codex_cli
CODEX_CLI_EXECUTABLE_PATH=codex
CODEX_CLI_MODEL=gpt-5.5
WHISPER_CPP_BINARY_PATH=/home/mbc/bin/whisper-cli
WHISPER_CPP_MODEL_PATH=/home/mbc/models/ggml-large-v3.bin
WHISPER_CPP_BACKEND=cuda
WHISPER_CPP_THREADS=0
YT_DLP_BINARY_PATH=yt-dlp
CUDA가 준비되지 않았으면 WHISPER_CPP_BACKEND=cpu 또는 vulkan으로 낮춰 시작하세요.
Mac Studio는 권장 운영 환경입니다.
초기 검증은 Codex CLI 기반 provider로 진행했습니다. 서버 운영 계정에서 한 번 로그인합니다.
codex login
codex exec --helpworker는 로그인된 CLI provider를 통해 후보 분석 요청을 실행합니다.
Mac에서는 Homebrew whisper-cpp와 프로젝트 로컬 모델 디렉터리를 쓰는 구성을 권장합니다.
brew install whisper-cpp
npm run whisper:downloadnpm run whisper:download는 models/whisper/ 아래에 tiny, base, small, medium, large-v3-turbo, large-v3 GGML 모델을 내려받습니다. 이 폴더는 git에 포함하지 않습니다. 설정 화면의 STT 섹션에서 다운로드된 모델을 선택할 수 있습니다.
models/whisper/는 whisper.cpp STT 모델 전용입니다. pyannote 화자 분리 모델은 이 폴더에 직접 넣지 않습니다.
.env.local 예시:
STT_PROVIDER=whisper_cpp
CANDIDATE_PROVIDER=codex_cli
CODEX_CLI_EXECUTABLE_PATH=codex
CODEX_CLI_MODEL=gpt-5.5
CODEX_CLI_TIMEOUT_SEC=180
WHISPER_CPP_BINARY_PATH=/opt/homebrew/bin/whisper-cli
WHISPER_CPP_MODEL_DIR=./models/whisper
WHISPER_CPP_MODEL_PATH=./models/whisper/ggml-large-v3.bin
WHISPER_CPP_BACKEND=metal
WHISPER_CPP_THREADS=0
OPENAI_API_KEY=
Gemini API provider로 전환해 테스트하려면 아래 값을 사용합니다.
CANDIDATE_PROVIDER=gemini
GEMINI_API_KEY=...
GEMINI_MODEL=gemini-3.5-flash
GEMINI_TIMEOUT_SEC=180
Windows에서는 WSL2 Ubuntu를 사용합니다. 이후 명령은 Ubuntu 터미널에서 실행합니다.
PowerShell을 관리자 권한으로 열고 실행합니다.
wsl --install -d Ubuntu설치가 끝나면 컴퓨터를 재시작하고, 시작 메뉴에서 Ubuntu를 엽니다. 처음 실행할 때 Ubuntu 사용자 이름과 비밀번호를 만듭니다.
이미 WSL이 설치되어 있다면 아래로 확인합니다.
wsl --list --verboseUbuntu 터미널에서 실행합니다.
sudo apt update
sudo apt install -y curl git python3 python3-venv ffmpeg librsvg2-binUbuntu 터미널에서 실행합니다.
curl -fsSL https://deb.nodesource.com/setup_24.x | sudo -E bash -
sudo apt install -y nodejs초기 검증과 같은 후보 분석 경로를 쓰려면 Codex CLI가 필요합니다.
npm install -g @openai/codexnode -v
python3 --version
ffmpeg -version
ffprobe -version
rsvg-convert --version
codex --versionnode -v가 v24...로 시작하면 됩니다.
GitHub URL은 공유받은 주소로 바꿔서 실행합니다.
git clone <공유받은-repo-url>
cd mbc이미 폴더를 zip으로 받았다면 압축을 풀고 터미널에서 해당 폴더로 이동합니다.
cd /path/to/mbcWindows WSL에서는 되도록 Ubuntu 홈 아래에 프로젝트를 두세요.
cd ~
git clone <공유받은-repo-url>
cd mbc/mnt/c/... 아래에서 실행하면 대용량 영상 처리 속도가 느릴 수 있습니다.
npm installpython3 -m venv .venv
source .venv/bin/activate
python -m pip install --upgrade pip
python -m pip install -r requirements.txt이후 worker 관련 명령은 .venv가 활성화된 터미널에서 실행합니다. 특정 Python으로 venv를 만들고 싶으면 python3 대신 해당 실행 파일을 사용하세요. 예: /opt/homebrew/bin/python3 -m venv .venv.
화자 분리까지 실행하려면 optional dependency를 추가로 설치합니다.
python -m pip install -e '.[diarization]'cp .env.example .env.local.env.local을 열고 값을 확인합니다.
기본 운영값:
STT_PROVIDER=whisper_cpp
CANDIDATE_PROVIDER=codex_cli
CODEX_CLI_EXECUTABLE_PATH=codex
CODEX_CLI_MODEL=gpt-5.5
WHISPER_CPP_BINARY_PATH=/absolute/path/to/whisper-cli
WHISPER_CPP_MODEL_DIR=/absolute/path/to/models/whisper
WHISPER_CPP_MODEL_PATH=/absolute/path/to/models/whisper/ggml-large-v3.bin
WHISPER_CPP_BACKEND=auto
FFMPEG_BINARY_PATH=ffmpeg
YT_DLP_BINARY_PATH=yt-dlp
LIVE_CHUNK_DURATION_SEC=30
LIVE_RECORD_DURATION_SEC=300
OPENAI_API_KEY=
화자 분리를 켤 때 추가할 값:
DIARIZATION_PROVIDER=pyannote
PYANNOTE_AUTH_TOKEN=hf_...
PYANNOTE_MODEL=pyannote/speaker-diarization-community-1
STT_DIARIZATION_PROVIDER=pyannote도 허용됩니다. token은 HF_TOKEN 또는 HUGGINGFACE_TOKEN으로 넣어도 됩니다. pyannote 모델 약관을 Hugging Face에서 승인하지 않았거나 token이 없으면 STT는 계속 성공하고 analysis/diarization.json에 skipped 사유가 저장됩니다.
화자 분리 모델 준비는 Hugging Face 쪽에서 합니다.
- Hugging Face 계정으로
pyannote/speaker-diarization-community-1모델 접근 약관을 승인합니다. - read 권한 token을 발급해
PYANNOTE_AUTH_TOKEN,HF_TOKEN, 또는HUGGINGFACE_TOKEN에 넣습니다. - 첫 실행 때
pyannote.audio가 모델을 내려받아 기본 Hugging Face 캐시에 저장합니다. macOS/Linux 기본 위치는~/.cache/huggingface/hub/models--pyannote--speaker-diarization-community-1/입니다.
따라서 제출/복사본에는 pyannote 모델 파일을 포함하지 않습니다. 캐시 위치를 바꾸고 싶으면 실행 환경에서 HF_HOME 또는 Hugging Face 캐시 관련 환경변수를 별도로 지정하세요.
비용 없이 테스트만 할 때:
STT_PROVIDER=mock
CANDIDATE_PROVIDER=rules
OPENAI_API_KEY=
OpenAI STT fallback을 명시적으로 쓸 때:
STT_PROVIDER=openai
CANDIDATE_PROVIDER=codex_cli
OPENAI_API_KEY=...
OPENAI_TRANSCRIBE_MODEL=whisper-1
OPENAI_TRANSCRIBE_LANGUAGE=ko
API key는 절대 GitHub, 메신저, 문서에 그대로 올리지 마세요.
터미널 2개를 열어야 합니다.
먼저 .venv가 준비되어 있어야 합니다.
source .venv/bin/activate
python --versionnpm run dev브라우저에서 엽니다.
http://localhost:3000
npm run worker:run업로드, 분석, STT, 후보 생성, export 작업은 이 worker가 처리합니다. 웹 화면만 켜고 worker를 켜지 않으면 큐가 진행되지 않습니다.
http://localhost:3000접속- 작업 생성: 프리셋, Reference Channel, 비디오/썸네일 템플릿을 선택하고 필요하면
오토 모드를 켭니다. - 오토 모드만 켜면 선택된 top N 구간이 검수 및 업로드 준비까지 자동 진행되고,
SNS Connect 자동 업로드도 켠 경우에만 실제 private YouTube 업로드를 시도합니다. - 로컬 파일 작업은 생성 요청에서 원본을 함께 업로드하고, YouTube URL 작업은 worker 큐에 등록되어
yt-dlp로 VOD를 다운로드합니다. - worker 터미널 또는 Job Space live log에서 분석/렌더/export/publish 진행을 확인합니다.
- 수동 워크플로우는 Job Space에서 세그먼트 검수, 자막 편집, AI 문안/메타데이터, 클립 디자인, 썸네일 디자인을 차례로 진행합니다.
- pyannote 화자 분리가 완료된 작업은 자막 편집 UI에서
SPEAKER_00같은 화자 라벨과 색상 스와치를 보여줍니다. 최종 렌더 자막에는 화자 라벨을 넣지 않습니다. - 썸네일 디자인 진입 시 AI 프레임 추천이 없으면 1회 자동 실행되고, 추천 1순위 프레임이 편집기의 기본 이미지로 들어갑니다.
- 최종
검수 및 업로드페이지에서 MP4 렌더/재생성, 썸네일 PNG 생성/재생성, 다운로드, 게시 메타데이터 저장을 진행합니다. - SNS 자동 업로드 또는 수동 게시 액션으로 YouTube/Meta/TikTok 게시 큐를 등록하거나 완료된 MP4/PNG를 다운로드합니다.
기본 실행은 로그인 없이 열립니다. 내부망 운영에서 로그인을 강제하려면 .env.local에 아래를 추가합니다.
MBC_REQUIRE_AUTH=true
처음에는 /login에서 최초 관리자 탭으로 관리자 계정을 만들고, 이후 같은 화면에서 로그인합니다. 역할은 admin, editor, viewer를 사용하며, 작업 생성/게시 같은 변경 API는 editor 이상, 설정/OAuth 연결은 admin 권한을 요구합니다.
YouTube 실제 연동:
GOOGLE_CLIENT_ID=...
GOOGLE_CLIENT_SECRET=...
GOOGLE_REDIRECT_URI=http://localhost:3000/api/accounts/youtube/callback
YOUTUBE_UPLOAD_MODE=real
서버에 이미 access token을 주입하는 운영 방식이면 YOUTUBE_ACCESS_TOKEN을 사용할 수 있습니다. YouTube URL 다운로드는 YT_DLP_BINARY_PATH로 지정한 yt-dlp를 worker가 실행합니다.
Meta/TikTok 실제 게시:
META_ACCESS_TOKEN=...
META_PAGE_ID=...
TIKTOK_ACCESS_TOKEN=...
PUBLIC_ASSET_BASE_URL=https://your-public-host.example
Meta/TikTok 게시 API는 외부 플랫폼이 접근할 수 있는 최종 영상 URL이 필요합니다. 요청에 publicVideoUrl을 직접 넘기거나, 렌더 결과의 renderedAssetId와 PUBLIC_ASSET_BASE_URL을 설정해 /api/rendered-assets/{assetId}/download 공개 URL을 자동 생성합니다. 로컬 localhost URL은 외부 플랫폼에서 접근할 수 없으므로 실제 운영에서는 NAS/CDN/공개 사내 미디어 게이트웨이 도메인을 사용해야 합니다.
STT_PROVIDER=whisper_cpp, CANDIDATE_PROVIDER=codex_cli 조합은 OpenAI API 과금 없이 서버 로컬 리소스와 로그인된 AI 분석 CLI provider를 사용합니다.
STT_PROVIDER=openai일 때 STT API 비용이 발생합니다.
- 현재는 영상 전체 오디오를 STT에 보냅니다.
- 실제 말한 시간만큼만 과금되는 구조는 아직 아닙니다.
- 같은 원본 파일, 같은 STT provider/model/language/diarization 설정으로 다시 분석하면
storage/stt-cache/를 재사용해 STT를 다시 호출하지 않습니다. - pyannote가 켜져 있고 캐시된 diarization이
completed가 아니면 캐시된 STT 전사는 재사용하되 diarization만 다시 시도합니다. - 다른 컴퓨터에서는 캐시가 없으므로 같은 영상도 STT 비용이 다시 발생할 수 있습니다.
후보/세그먼트 추천은 초기 검증 기준으로 CANDIDATE_PROVIDER=codex_cli를 사용합니다. Gemini API provider를 쓸 경우 CANDIDATE_PROVIDER=gemini와 GEMINI_API_KEY를 설정하세요. 비용 없이 테스트하려면 rules를 사용하세요.
기본 저장 위치는 storage/입니다. Next.js 서버와 Python worker가 같은 MBC_STORAGE_ROOT를 사용해야 하며, DB에는 절대 경로가 아니라 storage root 기준 상대 경로를 저장합니다.
storage/
mbc.sqlite # metadata, queue, settings, auth, publish state
mbc.sqlite-wal
mbc.sqlite-shm
stt-cache/
{cache_key}/
transcript.json
word_timestamps.json
diarization.json
projects/
{project_id}/
source/
upload_{id}/
source.{mp4|mov|m4v} # immutable uploaded original
proxy/
proxy.mp4
audio/
audio.wav
audio_stt.m4a
analysis/
ffprobe.json
metadata.json
transcript.json
word_timestamps.json
diarization.json
candidate_clips.json
analysis_summary.json
thumbnails/
thumb_000001.jpg
overlays/
{asset_id}.{png|jpg|jpeg}
edits/
{candidate_id}/
render_config.json
renders/
{render_job_id}/
final.mp4
render_manifest.json
ffmpeg.log
jobs/
{queue_job_id}/
status.json
worker.log
storage/는 Git에 올라가지 않습니다. 컴퓨터마다 별도 데이터가 생깁니다.
SQLite는 storage/mbc.sqlite 한 파일을 metadata와 queue DB로 사용합니다. 핵심 테이블은 projects, source_videos, queue_jobs, clip_candidates이며, 전체 schema는 db/schema.sql에 있습니다.
Queue 규칙:
- Next.js 서버는
queue_jobs.status = "queued"작업을 생성합니다. - Python worker는
BEGIN IMMEDIATE로 가장 오래된 eligible queued job을 claim하고running,locked_by,locked_at,locked_until,stage,progress를 갱신합니다. locked_until이 지난 stale running job은attempt_count < max_attempts일 때 다시 queued 처리됩니다.- 완료 job은 artifact 상대 경로를
resultJSON에 저장하고, 실패 job은error_message를 기록합니다. - STT cache는
source_sha256 + provider + model + language + diarization fingerprint기준이며, pyannote 활성/비활성 실행이 서로 섞이지 않습니다.
Path 규칙:
- 사용자가 올린 파일명은 storage 파일명으로 사용하지 않습니다.
- 기본 업로드 제한은
MBC_MAX_UPLOAD_BYTES이며 기본값은 10GB입니다. - API는
proxy,audio,metadata같은 known file type만 제공합니다. - 작업 삭제는 작업 산출물을 삭제하되 STT cache는 보존합니다.
제출본 문서는 루트에만 둡니다.
README.md: 설치, 실행, 환경변수, 운영/검증 방법.CODEBOOK.md: 제출 소스 코드 구조와 주요 실행 단위 안내.MBC_CLIPOPS_MASTER_SPEC.md: 제품 기능, UI 방향, 데이터/저장소/worker/API 스펙.
모든 프로젝트, 업로드 영상, STT 캐시, 렌더 결과를 지우고 새로 시작하려면 앱과 worker를 끈 뒤 실행합니다.
rm -rf storageWindows WSL에서도 Ubuntu 터미널에서 같은 명령을 사용합니다.
코드가 정상인지 확인하려면 실행합니다.
source .venv/bin/activate
npm run verify이 명령은 TypeScript, ESLint, unit test, Python worker test, Next.js build를 순서대로 실행합니다.
웹 UI 없이 로컬 영상으로 전처리 파이프라인만 테스트할 수도 있습니다.
npm run pipeline:preprocess -- /absolute/path/to/video.mp4여러 파일도 한 번에 처리할 수 있습니다.
npm run pipeline:preprocess -- /path/a.mp4 /path/b.movJSON 요약이 필요하면 --json을 붙입니다.
npm run pipeline:preprocess -- --json /absolute/path/to/video.mp4이 명령은 로컬 영상을 storage/projects/{project_id}/source/upload_{id}/source.{ext}로 복사하고, storage/mbc.sqlite에 project/source/queue row를 만든 뒤 worker와 같은 경로로 analyze_video 작업을 처리합니다. 성공하면 analysis/ffprobe.json, analysis/metadata.json, analysis/transcript.json, analysis/word_timestamps.json, analysis/diarization.json, analysis/candidate_clips.json, analysis/analysis_summary.json, proxy/proxy.mp4, audio/audio.wav, audio/audio_stt.m4a, thumbnails/thumb_000001.jpg가 생성됩니다.
기본 샘플 명령은 아래 파일을 기대합니다. 이 영상 파일은 제출본에 포함하지 않습니다.
npm run pipeline:sample.video/나혼산.mp4
마지막으로 기록된 샘플 baseline은 약 25분 05초, 94MB H.264/AAC 영상입니다. 전처리 결과 예시는 transcript segment 636개, word 1467개, 후보 5개, 9:16 렌더 샘플 12.012초/1080x1920/약 2.5MB입니다. OpenAI whisper-1을 쓸 경우 같은 길이 기준 STT 비용은 약 $0.15였고, whisper.cpp를 쓰면 STT는 로컬 모델로 처리됩니다.
npm run worker:run이 켜져 있는지 확인하세요. worker가 꺼져 있으면 큐가 처리되지 않습니다.
FFmpeg가 설치되지 않았거나 터미널 PATH에 없습니다. Mac은 brew install ffmpeg, Windows WSL은 sudo apt install -y ffmpeg를 실행하세요.
rsvg-convert가 설치되어 있는지 확인하세요.
Mac:
brew install librsvgWindows WSL:
sudo apt install -y librsvg2-binanalysis/diarization.json의 status를 확인하세요. completed가 아니면 pyannote가 실행되지 않았거나 Hugging Face token/model access가 막힌 상태입니다. DIARIZATION_PROVIDER=pyannote, PYANNOTE_AUTH_TOKEN 또는 HF_TOKEN, optional dependency 설치 상태를 확인하세요.
.env.local에 OPENAI_API_KEY가 들어 있는지 확인하세요. 실제 STT를 쓰려면 STT_PROVIDER=openai도 설정되어 있어야 합니다.
정상입니다. 프록시 생성, 오디오 추출, 렌더링은 FFmpeg가 CPU를 많이 사용합니다. 다른 무거운 프로그램을 닫고 전원 연결 상태에서 실행하세요.
- 업로드와 렌더링은 서버/worker가 실행되는 컴퓨터에서 처리됩니다.
- STT 비용 최적화용 VAD 처리는 아직 후속 TODO입니다.
- pyannote 화자 분리는 별도 로컬 단계이며, whisper.cpp 자체 화자 분리 기능으로 취급하지 않습니다.
- YouTube/Meta/TikTok 실제 게시에는 각 플랫폼의 OAuth, 앱 심사, quota, 공개 미디어 URL 제약이 적용됩니다.
- Meta/TikTok은 로컬 파일 직접 업로드가 아니라 공개 URL 기반 게시 경로로 구현되어 있습니다.