name: video-gen
description: Use when the user asks about video generation, YouTube "Past & Possible" channel, Vast.ai GPU rental, ComfyUI workflows, Flux Schnell or Flux Dev image generation, LTX 2.3 video generation, upscale pipeline, video-gen dashboard, runner.sh, generate.py, batch generation, prompts for video clips, or anything related to the video-gen-vast project at /home/app/video-gen-vast/.
Video Gen Skill (Past & Possible)
Генерация видео для YouTube канала "Past & Possible" через Vast.ai GPU.
Pipeline: Qwen-Image-2512 fp8 (30 steps, 1280x720) → LTX 2.3 2-pass I2V (640x360 → upscale+refine 1280x720) + audio
2-phase PHASED mode: all images (без SageAttention) → restart ComfyUI → all videos (с SageAttention)
11 total steps (8+3), distilled LoRA, ~2.3x быстрее старого 25-step pipeline
Target: ~$1 per 10 clips on RTX 4090
Расположение проекта
/home/app/video-gen-vast/
Архитектура
| Файл / Папка |
Назначение |
generate.py |
Основной скрипт генерации (Python, ComfyUI API) |
runner.sh |
Автономный раннер: SSH -> Vast.ai -> setup -> generate -> destroy |
setup-server.sh |
Setup ComfyUI + модели на Vast.ai (8 шагов, ~50GB) |
run-generate.sh |
Аварийный скрипт: tunnel + generate (если runner упал) |
monitor-setup.sh |
Мониторинг setup стадий с remote лога |
start-comfyui.sh |
Запуск ComfyUI сервера |
runner.log |
Лог раннера (НЕ коммитить) |
batch.json |
Текущий batch config (НЕ коммитить) |
prompts/ |
Файлы с промптами (img | vid формат, по строке на клип). Макс 3 пары (6 файлов), авто-очистка при upload |
workflows/ |
ComfyUI workflows (JSON) |
dashboard/ |
Express dashboard (port 3230) |
output/ |
Сгенерированные видео (по батчам) |
brain/decisions/log.md |
Лог архитектурных решений |
Pipeline
Phased mode (дефолт, 2 фазы)
Phase 1: все картинки (Qwen-Image-2512 fp8 в VRAM, 30 steps, БЕЗ SageAttention — fp8 overflow!)
→ restart ComfyUI с --use-sage-attention
Phase 2: все видео 2-pass I2V + audio (LTX 2.3 fp8 + Gemma 3 12B fp4 + distilled LoRA)
- Pass 1: 640x360, 8 steps (euler_ancestral_cfg_pp)
- Pass 2: x2 upscale → 1280x720, 3 steps refine (euler_cfg_pp)
- Audio: LTXVEmptyLatentAudio → decode (параллельно)
Модели грузятся 1 раз на фазу, не перезагружаются между клипами.
Resume/Recovery (2026-05-27)
--resume флаг — auto-skip готовых (state + file + validation)
- batch_state.json — атомарная запись после каждого клипа (output/{batchName}/)
- runner.sh —
run_with_retry() + reconnect_comfyui(), exponential backoff 15s→300s, 5 retries
- Dashboard — кнопка "Resume Batch" (
POST /api/resume), показывает прогресс
--resume по дефолту в runner.sh — безопасен при первом запуске
- Resume vs Rerun: Resume продолжает текущий batch, Rerun создаёт новый
- ⚠️
runner-resume.sh СЛОМАН для resume — НЕ передаёт --resume (regen всего) + старый BATCH_NAME. Юзать основной runner.sh (там --resume в GEN_ARGS_BASE стр.314).
- Resume на НОВЫЙ инстанс (напр. сменил GPU): картинки целы локально (
output/.../*.png, источник для I2V). Правишь только INSTANCE_ID/SSH_HOST/SSH_PORT (runner.sh стр.9-11), BATCH_NAME оставляешь тот же → pm2 restart video-gen. Phase 1 скипнется (--resume+PNG есть), пойдёт Phase 2 с места обрыва.
- 🆕 Авто-ретрай на VRAM OOM (1 Jun 2026,
a64d5b9): step_video при падении клипа проверяет is_oom_in_history() (scan history.status.messages на out of memory/vram/oom/cuda error/alloc) → 1 ретрай ТОЛЬКО для OOM, перед ним free_vram()+sleep(3). Не-OOM падения = fail-fast. Единичный OOM-клип теперь сам переподнимается.
- 🆕 Кнопка Resume догоняет упавшие клипы (1 Jun 2026,
69d842e): раньше батч с провалами метился phase=done → кнопка скрыта + /api/resume отказывал. Фиксы в server.js: canResume += hasFailures (failed_videos/images>0 ИЛИ completed<total), /api/resume считает imagesIncomplete/videosIncomplete и запускает фазу с --resume вместо отказа. Кнопка показывает ▶ Retry N failed (X/Y done). --resume+should_skip_video (file exists + size>0) перегенерят только отсутствующие mp4. Нужен живой инстанс.
- ⚠️ Video-gen дашборд = PM2
video-gen-dash (порт 3230), НЕ dashboard (порт 3000 — другой проект!).
🔴 Resume = "ComfyUI not reachable" → инстанс мёртв (1 Jun 2026)
- Симптом: жмёшь Resume, через минуту
❌ ComfyUI not reachable. Проверь vastai show instances — скорее всего пусто (vast забрал interruptible/кредиты). Resume работает ТОЛЬКО на живом инстансе.
- 🚨 НЕ жми «Start New Batch» для восстановления —
saveBatch→cleanOldBatches чистит output/. Фикс c8f0b9d: активный батч (batch.json.batchName) теперь НЕ удаляется, но всё равно Start = новый батч с нуля, а не догон.
- Восстановить N упавших клипов: нужен живой GPU → SSH-параметры в runner.sh (INSTANCE_ID/SSH_HOST/SSH_PORT), BATCH_NAME тот же, output НЕ трогать → resume (--resume) скипнет готовые, догенерит недостающие по локальным PNG. Картинки/видео локально целы (
output/{batch}/).
- Пробел: дашборд не умеет «арендовать GPU и продолжить ЭТОТ батч» — death инстанса = тупик. TODO-фича Resume→auto-rent (ждёт решения Rick).
🔴 "Connection reset by peer" при upload — сетевой сбой (1 Jun 2026)
- Симптом:
upload_file failed: [Errno 104] Connection reset by peer → ✗ Upload failed, skipping clip N, в итоге много failed (наблюдали 32/113). НЕ OOM, НЕ torch — SSH-туннель моргнул.
- Фикс (
a200c94): upload_file ретраит 3x с backoff 2s/4s. Покрывает обе фазы.
- Если всё равно частичные провалы + GPU жив: кнопка
▶ Retry N failed на дашборде догенерит только упавшие.
🔴 "no kernel image is available" — torch/GPU arch mismatch (1 Jun 2026)
- Симптом: «со старта» Phase 1 падает на
CLIPTextEncode, exception_message: "CUDA error: no kernel image is available for execution on the device". НЕ OOM.
- Причина: установлен torch cu-wheel без кернелов под архитектуру карты. RTX 5090 (Blackwell, sm_120) требует cu128; cu124 = максимум sm_90 (Hopper) → падает первая же CUDA-операция.
- Фикс (
236158b, 8d2d803): маппинг в setup-server.sh: CUDA<12.4→cu121, 12.4-12.7→cu124, ≥12.8→cu128, ≥13→default. + после install torch — проверка torch.randn().cuda() @ self (fail-fast): при провале setup exit 1 → runner.sh уничтожает инстанс + notify, не жжёт аренду на битом батче.
- Лечится только re-provision (новый инстанс с правильным setup). Хотфикс живого:
pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu128 + рестарт ComfyUI.
🔴 OOM в видео-фазе (30 May 2026)
- Симптом: Phase 2 падает на ВСЕХ клипах, нода
SamplerCustomAdvanced. Лог runner.log обрезает ошибку на 239 симв + врёт SageAttention=❌ (ложный след).
- Реальная причина (из
/workspace/comfyui.log): torch.OutOfMemoryError при fp8-квантизации весов LTX 2.3 22B (comfy_kitchen quantization.py stochastic_rounding_fp8).
- 22B fp8 в 24GB (3090/4090) = впритык. Раньше влезало с тонким запасом; сломанный SageAttention-стаб (20KB wheel «not importable») + фрагментация съедают запас → OOM. Решение: 5090 32GB (штатный GPU, см. комментарий в generate.py про free_vram).
- При диагностике OOM — смотреть
comfyui.log на vast (ssh), а НЕ runner.log.
🔴 Resume через дашборд СТИРАЕТ картинки (30 May 2026)
- Запуск нового инстанса через дашборд (
POST /api/start, saveBatch) ресетит батч → исходные PNG + batch_state стираются, --resume начинает с нуля. Бэкапа картинок нет.
- Правильный resume на новый GPU: вручную поменять
INSTANCE_ID/SSH_HOST/SSH_PORT в runner.sh (стр.9-11), BATCH_NAME оставить тот же, output-папку НЕ трогать → pm2 restart video-gen. НЕ юзать дашборд для продолжения батча.
Ускоритель вместо SageAttention (sage 1.0.6 = битая заглушка)
- sage
1.0.6 с PyPI = 20KB pure-python без CUDA-кернелов → «not importable» → ComfyUI крутит fallback. Sage давал ~30-40%.
- Альтернативы (без риска чёрных fp8):
--fast (fp8 fast accumulation, топ для 5090/Blackwell), xformers (pip install), --use-flash-attention. Полный sage = собрать SageAttention 2.x из исходников (build в setup + верификация). Рекомендация: --fast+xformers.
Combined mode (--combined, legacy)
IMG→VIDEO→UPSCALE в одном ComfyUI queue. flux_ltx_combined.json.
~140с/пару — модели перезагружаются каждый клип.
GPU варианты (dashboard: 10 типов, топ-20)
| GPU |
$/hr |
~с/клип |
Примечание |
| RTX 5090 |
~$1.00 |
~60s |
Самый быстрый |
| RTX 4090 |
~$0.40 |
~90s |
Основной |
| RTX 3090 |
~$0.16 |
~140s |
Бюджетный, тот же 24GB |
| L40S |
~$0.50 |
~95s |
Датацентр |
Refine pass (Phase 3, отдельный workflow)
- Workflow:
ltx_refine.json (standalone, VHS_LoadVideoPath input)
- Node 30: BasicScheduler (steps=5, denoise=0.25)
- Node 50: VHS_LoadVideoPath (STRING input, без combo валидации)
- Node 32: SamplerCustomAdvanced
- Убирает артефакты upscale, улучшает детализацию
- Отключается: settings.refine.enabled=false
Текущий подход (проверенный)
- Docker image:
nvidia/cuda:12.1.0-devel-ubuntu22.04 (~5GB, boot 1-2 мин)
- Setup:
setup-server.sh скачивает модели 50GB с HuggingFace (5-8 мин)
- Disk: 100GB
- ComfyUI: запускается БЕЗ
--highvram (иначе OOM)
- Connectivity: Direct HTTP first (
--direct flag), SSH tunnel fallback
- Persistent WebSocket: одно подключение на батч (не reconnect каждый step)
- SageAttention:
--use-sage-attention + fp16 patch (INT8/FP16 CUDA kernel, ~1.4x speedup)
- SageAttention fp16 patch: setup-server.sh патчит core.py:
sageattn_qk_int8_pv_fp8_cuda → sageattn_qk_int8_pv_fp16_cuda (RTX 4090 sm89 black image fix)
- free_vram(): POST
/free API между фазами (unload_models + free_memory) — предотвращает OOM
❌ Отвергнутые подходы
- Docker image 68GB (GHCR): Vast.ai НЕ кэширует Docker слои, каждый раз pull с нуля
- Vast.ai Volumes: 0 машин с GPU + Volume storage одновременно
Критические правила
- НИКОГДА
--highvram — OOM: Flux(17G)+LTX(22G)+Gemma(12G)=51G > 32G VRAM
</dev/null в SSH nohup — иначе SSH зависает навсегда
mkdir -p /workspace перед SCP — nvidia/cuda не имеет /workspace
encodeURIComponent() для кириллических batch names в URL
Quality Settings (текущие)
| Параметр |
Значение |
| Video Steps |
20 |
| Video CFG |
5 |
| Video STG |
2 |
| Sampler |
euler |
| Negative prompt |
blurry, low quality, distorted, watermark, jittery, morphing, melting, disappearing objects, flickering, artifacts, deformed, glitch, static noise |
| Video resolution |
768x432 (16:9) |
| Image model |
Qwen-Image-2512 fp8 (default, 30 steps, SageAttention fp16 patch) |
| Image resolution |
1280x720 (settings.json) |
| Image VAE |
ae.safetensors (fp16, отдельный от fp8 checkpoint — убирает мыльность) |
| Frame rate |
24 fps |
| Video length |
97 frames (~4 sec) |
| LoRA style |
none (тестируем базовое качество) |
Quality Improvement Plan (2026-05-20)
Фидбек Бороды + ресёрч LTX 2.3 доки.
| # |
Что |
Статус |
Описание |
| 1 |
Latent upscale |
✅ |
Unified workflow: sampling → upscale → refine → decode |
| 2 |
FPS fix |
✅ |
24fps generation = 24fps output |
| 3 |
STG guider |
✅ |
STGGuiderNode (cfg=3.5, stg=1.2, rescale=0.7) |
| 4 |
Negative prompt |
✅ |
Safety + quality terms в generate.py |
| 5 |
LoRA |
✅ |
Стили через dashboard settings |
| 6 |
Refine denoise |
✅ |
10 steps, denoise=0.4 после upscale (Node 32) |
Доступные ноды LTX (из доки ComfyUI-LTXVideo)
STGGuiderNode — cfg, stg, rescale (замена CFGGuider)
LTXVApplySTG — block_indices (default "14, 19")
STGAdvancedPresetsNode — preset "13b Balanced"
APGGuiderNode — Adaptive Projected Guidance
LTXVBaseSampler — all-in-one sampler
LTXVImgToVideoAdvanced — advanced img2vid (crf, blur, interpolation)
LTXVAddGuideAdvanced — keyframe guidance
LTXVHDRDecodePostprocess — HDR output
LTXVLatentUpsampler — latent space upscale (уже используем отдельно)
LTXVTiledVAEDecode — tiled decode для больших latents
Ключевые технические решения
- Text encoder:
LTXAVTextEncoderLoader (НЕ CLIPLoader) + gemma_3_12B_it_fp8_e4m3fn.safetensors (PUBLIC, от GitMylo)
- Upscale VAE decode:
LTXVTiledVAEDecode (НЕ LTXVSpatioTemporalTiledVAEDecode — tensor mismatch)
- VHS_VAEEncodeBatched: per_batch=256 (НЕ 16, иначе потеря кадров)
- Upscale model dir:
latent_upscale_models/ (НЕ upscale_models/)
- Upload перед upscale: upload_file() видео в ComfyUI input/ перед VHS_LoadVideo
- Image model (default): Flux Schnell fp8 (CheckpointLoaderSimple + DualCLIPLoader + KSampler, steps from settings.json). Дистиллированная модель, оптимальна 4-12 steps
- Image model (alt): Flux Dev fp8 + ByteDance Hyper-FLUX 8steps LoRA (--model flux). Лучше prompt adherence для сложных композиций
- GPU: RTX 3090/4090/5090 на Vast.ai, ~$0.20-1.05/hr (target: RTX 3090 $0.20/hr)
- SSH tunnel:
ssh -p PORT -N -L 18188:localhost:8188 root@sshX.vast.ai (PRIMARY метод, runner.sh делает автоматически)
Dashboard
Функционал
- JWT авторизация (7 дней), query param token для скачивания
- 8-stat grid: Phase, Clips, GPU+badge, Batch Cost, Vast.ai Credit, Elapsed, ETA, Server Disk
- Smart buttons: Start (GPU offers modal), Stop, Destroy
- Help модалка с инструкцией
- Prompts: Two Files / Combined mode, preview, upload
- Multi-GPU offers: Score-based ranking (R% × 40 + Speed × 35 + Net × 10 + Price × 15)
- Batch selector + Delete old batches + Download All (tar.gz img+video)
- Setup progress bar (шаг X/8 с названием)
- Stage tracking при генерации (IMG/VIDEO/UPSCALE с иконками)
- Output files viewer (auto-refresh)
- Live log (30 строк, 5s poll)
API Endpoints (server.js)
| Method |
Path |
Auth |
Описание |
| POST |
/api/login |
No |
JWT login (поле user) |
| GET |
/api/status |
Yes |
Phase, progress, GPU, cost, elapsed, ETA, currentStage |
| GET |
/api/logs?lines=N |
Yes |
Последние N строк runner.log |
| GET |
/api/instances |
Yes |
Vast.ai active instances |
| GET |
/api/output?batch=name |
Yes |
Список generated files (по batch) |
| GET |
/api/batches |
Yes |
Список всех батчей + текущий |
| GET |
/api/balance |
Yes |
Vast.ai credit баланс |
| GET |
/api/prompts |
Yes |
Список prompt файлов |
| GET |
/api/prompts/:file |
Yes |
Содержимое prompt файла |
| POST |
/api/prompts/upload |
Yes |
Загрузка prompt файла (кириллица ОК) |
| GET |
/api/offers?clips=N |
Yes |
Multi-GPU offers + est time/cost |
| GET |
/api/download/:filename |
Yes |
Скачать один файл |
| GET |
/api/download-all?batch=name |
Yes |
Скачать все upscaled как tar.gz |
| POST |
/api/start |
Yes |
Rent GPU + start pipeline |
| POST |
/api/stop |
Yes |
Stop runner (GPU stays) |
| POST |
/api/rerun |
Yes |
Re-run on same GPU (different settings/prompts) |
| POST |
/api/resume |
Yes |
Resume interrupted batch (auto-detect phase) |
| GET |
/api/batch-state |
Yes |
batch_state.json — resume progress |
| POST |
/api/destroy |
Yes |
Destroy GPU instance |
| PUT |
/api/settings |
Yes |
Update generation settings |
| GET |
/api/styles |
Yes |
Available LoRA styles |
Формат промптов
Файл .txt в prompts/, одна строка на клип:
IMAGE_PROMPT | VIDEO_PROMPT
Пример:
A panoramic view of Manhattan in the 1920s, sepia tones | Camera slowly pans across the skyline as smoke rises from factories
Стоимость (реальные данные)
| GPU |
Цена |
Setup |
18 clips |
Total |
| RTX 4090 |
~$0.76/hr |
~10 мин |
~30 мин (99s/clip) |
~$0.50 |
| RTX 5090 |
~$1.05/hr |
~10 мин |
~26 мин (87s/clip) |
~$0.63 |
Завершённые батчи
| Батч |
Клипов |
GPU |
Время |
Стоимость |
| america-history |
36 |
RTX 4090 |
59 мин |
~$0.75 |
| jungle cities |
18 |
RTX 5090 |
26 мин |
~$0.63 |
Решённые баги (21)
python vs python3 — Docker image без python
_comment в workflow JSON — ComfyUI не принимает
- ComfyUI порт не экспонирован — SSH tunnel
- LTX 2.3 CLIP=None — LTXAVTextEncoderLoader
- Gemma + LTX + Flux = OOM — убрать
--highvram
- LTXVSpatioTemporalTiledVAEDecode tensor mismatch — LTXVTiledVAEDecode
- per_batch=16 потеря кадров — per_batch=256
- Upscale model wrong dir — latent_upscale_models/
- step_upscale видео не на сервере — upload_file()
- Dashboard Download nginx path — API endpoint
- PM2 restart video-gen — рестартил старый run-batch.sh
- runner.sh Stage 4 — хардкод america-history
- progress.percent — деление на 0
- $TUNNEL_PID не инициализирована
- elapsed time — timezone mismatch
- Phase stuck on "booting" — error checks BEFORE booting
- Cost overcount — freeze таймер на done/error
- SSH disconnect during setup — ServerAliveInterval=30
/workspace/ не существует на nvidia/cuda — mkdir -p
- SSH nohup зависает —
</dev/null &
- Download кириллица — encodeURIComponent()
Завершённые батчи (обновлено)
| Батч |
Клипов |
GPU |
Время |
Стоимость |
Pipeline |
| america-history |
36 |
RTX 4090 |
59 мин |
~$0.75 |
base (no refine) |
| jungle cities |
18 |
RTX 5090 |
26 мин |
~$0.63 |
base (no refine) |
| картинки_merged |
10 |
RTX 5090 |
50 мин |
~$1.20 |
+refine +SageAttn |
Dashboard Research Tab (2026-05-29)
Вкладка Research для анализа YouTube-каналов и поиска контента.
Flow: Channel Analysis
- Вбить URL канала → кнопка "Smart Search" (или Enter)
- Автоматически: определяет нишу → ищет trending → ищет конкурентов
- Результат: Channel Analysis карточка + Trending Videos + Competitors
Ключевые механики
- fetchChannelInfo() —
topicDetails + statistics + snippet. YouTube topicIds → readable categories (TOPIC_MAP). Video categoryId detection
- searchNiche формула: top title content word + longest channel name word (max 2, content language). Multi-lang stop words: EN ~80, ES ~40, PT ~40, YouTube filler ~20
- Format filter: Shorts (≤60s) / Long (>60s) —
contentDetails.duration ISO 8601 → seconds, client-side filtering
- Duration badges: красный SHORT / серый ⏱ mm:ss
- AI Find Competitors: использует searchNiche (content-language keywords), НЕ English categories
- Case-insensitive handle matching:
qLow.includes((c.handle||'').toLowerCase())
Грабли Research
- YouTube search ANDs все термы → max 2 слова в запросе
- English categories для Portuguese каналов = 0 результатов
- 100K+ minViews слишком строго для нишевых тем → auto-lower до 10K
stats variable scope: searchNiche код ВНУТРИ if (videoIds.length) блока
Dashboard live data
- Dashboard читает
generation.log напрямую (authoritative source)
- runner.log = setup фаза только, НЕ generation progress
- Live step detail: Node X: Y% (step/total)
- Auto-refresh 5s, merged logs endpoint
- Download-all: video_*.mp4 (НЕ *_upscaled)
- ⚠️ runner.log bloat: setup wget progress → 104MB. Фильтр в runner.sh (grep --line-buffered)
Ключевые грабли
- SSH tunnel = primary (direct IP виснет — curl ifconfig.me без таймаута)
- runner.log bloat (wget progress bars → 104MB → dashboard 35s, 772MB RAM)
- generation.log vs runner.log рассинхрон (grep >> дубликаты)
- download-all искал upscaled, а новый pipeline сохраняет video.mp4
- Combined workflow: download_output хватал PNG (SaveImage) вместо MP4 (VHS_VideoCombine) → битые файлы. Fix: gifs > images priority
- JS
"\n" is truthy → .trim() check
- PM2
--update-env обязателен при изменении ecosystem env vars
- ComfyUI sqlalchemy — новые версии требуют sqlalchemy (asset management)
- CUDA 12.8 + default PyTorch = crash. 3-tier: cu121/cu124/default
- ssh|grep $? = grep exit code, не ssh. Fix: set -o pipefail
- fp8 VAE = мыльные картинки. Fix: отдельный ae.safetensors (fp16) через VAELoader
- Workflow ссылается на удалённую модель → HTTP 400 на все prompts
- SageAttention fp8 CUDA kernel на sm89 (RTX 4090) = чёрные картинки с Qwen fp8. Fix: patch core.py fp8→fp16
- VHS_LoadVideo combo dropdown валидация = 400 на uploaded файлы. Fix: VHS_LoadVideoPath (STRING input)
- OOM между фазами (Qwen→LTX, 24GB VRAM). Fix: free_vram() POST /free API
- Docker Hub rate limit на vast.ai. Fix:
toomanyrequests|rate limit в grep детектор runner.sh
Что осталось