YouTube Shorts Generator — Повний аналіз проекту

1. Документація проекту

Що це?

Повністю автоматизований AI-конвеєр для генерації YouTube Shorts (та TikTok/Reels). На вхід — лише тема каналу, на виході — готове вертикальне відео з озвучкою, субтитрами, SEO-метаданими та опціональним завантаженням на YouTube.

Ключові можливості

Технологічний стек

Компонент Технологія
API FastAPI + Uvicorn
Task Queue Celery + Redis
DB SQLite (2 бази: shorts.db + memory.db)
ORM SQLAlchemy 2.0 + Alembic
LLM g4f (безкоштовно) → Ollama → OpenAI (фолбек-ланцюг)
TTS edge-tts (Microsoft, безкоштовно)
Відео MoviePy 1.0.3 + FFmpeg
Візуали Pexels/Pixabay (стоки) + Pollinations (AI)
Тренди pytrends + PRAW (Reddit)
UI Streamlit
Deploy Docker Compose (6 сервісів)
Мова Python 3.11

Запуск

make setup        # Перший запуск: build, start, init DB
make up           # Старт сервісів
make run-now      # Тригер генерації через API
make logs-worker  # Перегляд логів worker

2. Знайдені та виправлені проблеми

🔴 КРИТИЧНІ (виправлено)

1. Path Traversal у /api/outputs/{filename}

Файл: app/main.py
Проблема: Ендпоінт serve_output не перевіряв, чи filename містить ../. Атакуючий міг отримати доступ до будь-якого файлу на сервері через GET /api/outputs/../../../../etc/passwd.
Виправлення: Додано resolve() + перевірку, що шлях залишається всередині OUTPUTS_DIR.

2. Невірні дефолти в Pexels portrait-детекції

Файл: app/providers/visuals/pexels_provider.py
Проблема: f.get("width", 9999) <= f.get("height", 1) — дефолтні значення інвертовані. Якщо в API-відповіді відсутні width/height, відео ніколи не вважалося portrait.
Виправлення: Змінено на f.get("width", 0) <= f.get("height", 9999).

3. Async/sync конфлікт у EdgeTTS

Файл: app/providers/tts/edge_tts_provider.py
Проблема: asyncio.run() падає з RuntimeError, якщо вже є активний event loop (можливо в Celery worker).
Виправлення: Перевірка наявності running loop + виконання через ThreadPoolExecutor як запасний варіант.

4. MoviePy нескінченний loop при коротких кліпах

Файл: app/pipeline/step_05_edit.py
Проблема: Якщо відео-кліп дуже короткий (0.1с), reps = int(duration / clip.duration) + 1 може дати тисячі повторень → OOM.
Виправлення: Додано ліміт min(..., 10) на кількість повторень.

5. Відсутність перевірки записаного відео

Файл: app/pipeline/step_05_edit.py
Проблема: Після write_videofile() нікуди не перевірялось, чи файл реально створено і не порожній.
Виправлення: Додано перевірку exists() + мінімальний розмір файлу.

6. Неатомарний запис конфігурації

Файл: app/api/routes_config.py
Проблема: open + write — якщо процес помер під час запису, config.yaml залишиться зіпсованим.
Виправлення: Запис через тимчасовий файл + os.replace() (атомарна операція на рівні FS).

⚠️ ВАЖЛИВІ (виправлено)

# Проблема Файл Виправлення
7 Відсутні DB-індекси на status, created_at, topic models.py Додано Index()
8 Відсутній індекс на ChannelMemory.topic memory_models.py Додано Index()
9 Немає валідації кількості сегментів у скрипті step_02_script.py Перевірка 1-10 сегментів
10 Ollama response["message"]["content"] — KeyError ollama_provider.py .get() з перевіркою
11 OpenAI — .content може бути None openai_provider.py Перевірка на None
12 DELETE memory видаляв ВСІ MemoryEvents, не тільки для топіку routes_memory.py Фільтр по topic
13 Beat schedule мовчки ковтав помилки beat_schedule.py Логування помилок
14 FFmpeg crop filter — непрозорі рядкові вирази ffmpeg_utils.py Виділення в змінні
15 Upload hardcoded en-US audio language step_07_upload.py Виправлено на en

📋 Залишкові проблеми (потребують окремих задач)

# Проблема Складність
1 piper_provider.py не існує, але є у factory Низька — додати заглушку або прибрати з enum
2 comfyui_provider.py не існує, але є у factory Низька — аналогічно
3 g4f_provider має 4 рівні фолбеку, складно дебажити Середня — рефактор на retry pattern
4 _extract_json() дубльована у 3 файлах Низька — винести у utils
5 CORS allow_origins=["*"] Середня — обмежити для prod
6 Логи тільки в stdout, не персистяться Середня — додати file handler
7 asset_cache_path() використовує MD5 Низька — міграція на SHA-256
8 Random seed в Pollinations (seed=42) — немає різноманітності Низька — зробити random
9 config reload не тригерить перезапуск workers Висока — потрібен config watcher

3. Архітектура

Загальна схема

┌──────────────┐    ┌──────────┐    ┌────────────────┐
│  Streamlit   │───▶│ FastAPI  │◀──▶│   SQLite DBs   │
│  UI :8501    │    │ :8000    │    │ shorts.db       │
└──────────────┘    └────┬─────┘    │ memory.db       │
                         │          └────────────────┘
                         │ trigger
                         ▼
                    ┌──────────┐    ┌────────────────┐
                    │  Redis   │◀──▶│ Celery Worker   │
                    │ :6379    │    │ (concurrency=2) │
                    └──────────┘    └────────┬───────┘
                         ▲                   │
                    ┌────┴─────┐             │ runs pipeline
                    │  Celery  │             ▼
                    │  Beat    │    ┌────────────────────┐
                    └──────────┘    │  PipelineOrchestrator│
                                   └────────┬───────────┘
                                            │
                    ┌───────────┬────────────┼─────────────┬──────────┐
                    ▼           ▼            ▼             ▼          ▼
               Step 01     Step 02     Step 03-05     Step 06-07  Step 08-09
               Trends      Script      Visuals/       SEO/Upload  Notify/
               (pytrends   (LLM)       Audio/Edit     (LLM/       Reflect
                + Reddit)              (TTS+MoviePy)   YouTube)    (Telegram)

Патерни

1. Context Dict Pattern

Кожен крок пайплайну отримує та мутує спільний ctx: dict. Кроки loosely coupled — крок N читає ключі, записані кроками 1..N-1.

ctx = {"job_id": "...", "topic": "AI", "config": AppConfig(...)}
# Step 01 додає: ctx["trend_keyword"] = "GPT-5 release"
# Step 02 додає: ctx["script"] = {...}, ctx["script_full_text"] = "..."
# Step 03 додає: ctx["visual_assets"] = [...]
# ...

Переваги: Простота, гнучкість, легко додавати нові кроки.
Недоліки: Немає type-safety, складно відстежити хто що пише/читає.

2. Provider Pattern (Strategy)

LLM, TTS, візуали, тренди — все реалізовано через абстрактні базові класи + фабрики:

LLMProvider (ABC)           VisualProvider (ABC)
├── G4FProvider              ├── PexelsProvider
├── OllamaProvider           ├── PixabayProvider
└── OpenAIProvider           └── PollinationsProvider

Фабрики (build_llm_provider, build_stock_provider) зчитують конфіг і повертають відповідну імплементацію. Є fallback chain: g4f → Ollama → OpenAI.

3. Pipeline Step Pattern

Кожен крок — клас, що наслідує PipelineStep:
- name — ідентифікатор
- required — чи зупиняти пайплайн при помилці
- is_disabled() — перевірка конфігу
- run(ctx, cfg) — основна логіка

PipelineOrchestrator виконує кроки послідовно, пишучи статус в DB.

4. Dual-Database Design

Розділення дозволяє легко чистити memory без впливу на історію робіт.

Потік даних пайплайну

1. TRENDS    → trend_keyword ("GPT-5 release date")
2. SCRIPT    → script JSON (hook + 4 segments + CTA), ~55s
3. VISUALS   → 4 video/image assets (Pexels + Pollinations)
4. AUDIO     → voiceover.mp3 + subtitles.vtt + background_music.mp3
5. EDIT      → final_video.mp4 (1080x1920, 30fps, karaoke subs)
6. SEO       → title, description, tags, hashtags
7. UPLOAD    → YouTube video_id + URL
8. NOTIFY    → Telegram message with preview
9. REFLECT   → ChannelMemory update (insights for next videos)

Docker сервіси

Сервіс Роль Порт
redis Celery broker + result backend 6379
app FastAPI REST API 8000
worker Celery worker (2 threads)
beat Celery Beat (cron scheduler)
ui Streamlit dashboard 8501
ollama Локальний LLM (опціонально) 11434
comfyui Stable Diffusion (profile, опціонально) 8188

4. Шляхи розвитку

🟢 Швидкі перемоги (1-3 дні)

  1. Тести — Проект не має тестів. Додати:
  2. Unit тести для _extract_json(), _proportional_durations(), _parse_vtt()
  3. Integration тест для PipelineOrchestrator з мок-кроками
  4. API тести для ендпоінтів

  5. Лінтинг та CI — Додати ruff + mypy + GitHub Actions pipeline

  6. Dry-run modetest_pipeline.py приймає --dry-run, але не мокає провайдери. Реалізувати мок-провайдери для всіх сервісів

  7. Health check у Dockerfile — Додати HEALTHCHECK CMD curl --fail http://localhost:8000/health

  8. Вінести _extract_json() — Єдина утиліта замість 3 копій

🟡 Середньострокові (1-2 тижні)

  1. Мультимовність — Наразі hardcoded "en-US" в upload, SEO, script prompts. Зробити channel.language домінуючим параметром для всіх LLM-промптів та TTS голосу

  2. Retry & Circuit Breaker — Замінити bare try/except у провайдерах на tenacity декоратори з exponential backoff та circuit breaker для зовнішніх API

  3. Prometheus метрики — Додати /metrics ендпоінт:

  4. pipeline_runs_total{status}
  5. pipeline_step_duration_seconds{step}
  6. api_requests_total{endpoint}
  7. celery_tasks_active

  8. Persistent logging — Логи зникають при рестарті контейнера. Додати:

  9. File handler з rotation
  10. Або JSON logs → Loki/ELK стек

  11. TikTok uploadUploadTikTokConfig існує в схемі, але не реалізований. Інтеграція через TikTok for Developers API

  12. A/B тестування — Генерувати 2-3 варіанти title/thumbnail, автоматично вибирати найкращий за CTR через Analytics API

  13. Config hot-reload — При оновленні config через API, відправляти сигнал workers для перезавантаження конфігу без перезапуску

🔵 Довгострокові (1-3 місяці)

  1. AI Voice Cloning — Інтеграція із ElevenLabs або XTTS для унікального голосу каналу замість стандартних Edge TTS голосів

  2. Автоматичний B-Roll — AI-аналіз скрипту для підбору тематично точніших візуалів замість простого keyword-пошуку

  3. YouTube Analytics feedback loop — Автоматичне збирання views/retention через YouTube Analytics API → навчання моделі на реальних метриках перформансу

  4. Multi-channel — Підтримка декількох каналів з різними темами, мовами та стилями в одному інстансі

  5. PostgreSQL міграція — SQLite не масштабується для concurrent writes. PostgreSQL або MySQL для production

  6. Kubernetes deploy — Helm chart для горизонтального скейлінгу workers

  7. Plugin system — Дати можливість додавати кастомні кроки пайплайну, провайдери, пост-процесори через plugin API

  8. Генерація Shorts із існуючого контенту — Автоматичне вирізання найцікавіших моментів із довгих відео (YouTube/podcast) у shorts-формат

  9. Real-time preview — WebSocket-стрім прогресу генерації з preview кожного кроку в UI

  10. GPU acceleration — CUDA-прискорення для FFmpeg та Stable Diffusion, автоматичне визначення доступного GPU

🏗️ Архітектурні покращення

  1. Typed Context — Замінити dict[str, Any] на Pydantic-модель PipelineContext з чіткими полями для кожного кроку

  2. Event Sourcing для Job — Замість мутації статусу, зберігати лог подій (started, step_completed, failed, etc.)

  3. Async Pipeline — Деякі кроки (визуали, аудіо) можна виконувати паралельно через asyncio.gather() або Celery chord

  4. Rate Limiter — Централізований rate limiter для всіх зовнішніх API (Pexels, Pixabay, Google Trends) замість розрізнених try/except


Резюме

Проект має солідну архітектуру з правильними патернами (provider pattern, pipeline steps, context dict). Основна кодова база добре структурована та легко розширюється.

Головні ризики:
- Відсутність тестів (один баг у одному кроці ламає весь пайплайн)
- Залежність від зовнішніх безкоштовних сервісів (g4f, edge-tts, Pollinations)
- SQLite не витримає concurrent load при масштабуванні

Головні сильні сторони:
- 100% Docker, zero manual setup (крім YouTube OAuth)
- Повний цикл від ідеї до публікації
- Graceful degradation — опціональні кроки не зупиняють пайплайн
- Memory loop — канал "навчається" з кожним відео