Architecture Overview
This page explains how the system fits together: processes, apps, libraries, data flow, and configuration.
Process Model
The application runs as 5 concurrent processes, defined in the Procfile and managed by Honcho:
graph LR
subgraph Docker["Docker Compose"]
PG["PostgreSQL 17<br/>:5435"]
VK["Valkey<br/>:6379"]
LK["Loki<br/>:3100"]
AL["Alloy"]
GR["Grafana<br/>:3000"]
end
DJ["Django<br/>:8000"]
CW["Celery Worker<br/>(solo pool)"]
FL["Flower<br/>:5555"]
TW["Tailwind<br/>(watcher)"]
DJ -->|reads/writes| PG
DJ -->|queues tasks| VK
CW -->|polls tasks| VK
CW -->|stores results| PG
FL -->|monitors| VK
AL -->|ships logs| LK
GR -->|queries| LK
Process |
Command |
Port |
|---|---|---|
docker |
|
Various |
django |
|
8000 |
worker |
Celery worker on |
— |
flower |
Celery task monitor |
5555 |
tailwind |
Tailwind CSS watcher (rebuilds on file change) |
— |
The Celery worker uses the solo pool — a single-threaded, non-forking worker. This is intentional: it prevents concurrent GPU model loading, ensuring only one diffusion model occupies VRAM at a time.
Docker Services
Service |
Port |
Purpose |
|---|---|---|
PostgreSQL 17 |
5435 |
Primary database for all Django models and Celery result storage |
Valkey |
6379 |
Redis-compatible broker for Celery task queuing |
Loki |
3100 |
Log aggregation backend (stores structured JSON logs) |
Alloy |
— |
Observability collector that ships |
Grafana |
3000 |
Web UI for log search and visualization (anonymous login enabled for dev) |
Project Structure
The project uses a src layout for proper Python packaging:
generative-creative-lab/
├── src/cw/ # Main Python package
│ ├── core/ # LLM models, prompt templates, pipeline settings
│ ├── audiences/ # Regions, countries, languages, segments, personas
│ ├── diffusion/ # Diffusion models, LoRAs, prompts, generation jobs
│ ├── tvspots/ # Campaigns, ad units, scripts, storyboards, video analysis
│ ├── lib/ # Supporting library modules (see below)
│ └── settings.py # Django settings (Celery, logging, apps)
├── data/ # JSON configuration and seed data
├── media/ # Generated images and uploaded files
├── logs/ # Structured JSON log files
├── Procfile # Process definitions for Honcho
├── docker-compose.yml # Infrastructure services
└── manage.py # Django management script
Django Apps
Four apps, each with a focused domain:
App |
Key Models |
Purpose |
|---|---|---|
core |
LLMModel, PromptTemplate, PipelineSettings |
LLM model registry, Jinja2 prompt templates (database-backed with versioning), and pipeline default configuration |
diffusion |
DiffusionModel, LoraModel, Prompt, DiffusionJob |
Diffusion model catalog, LoRA adapters, prompt creation/enhancement, and image generation jobs |
audiences |
Region, Country, Language, Segment, Persona |
Geographic hierarchy (Region → Country → Language) and non-geographic segmentation (Demographic/Behavioral/Psychographic) with persona composition |
tvspots |
Brand, Campaign, VideoAdUnit, AdUnitScriptRow, Storyboard, StoryboardImage |
TV spot campaigns, origin/adaptation ad units, script management, multi-agent pipeline, storyboard generation, and video analysis |
Library Modules
Supporting code lives in src/cw/lib/, separate from Django app logic:
Module |
Purpose |
|---|---|
models/ |
Diffusion model implementations: BaseModel, mixins, 7 concrete models, ModelFactory (see Diffusion Models) |
pipeline/ |
LangGraph-based adaptation pipeline: state, schemas, 7 nodes, graph construction, model loader (see Adaptation Pipeline) |
prompts/ |
Jinja2 template rendering from database ( |
loras/ |
LoRA filtering by base architecture and optional theme |
video_analysis/ |
Video processing: scene detection, transcription, object detection, visual style, sentiment, audience insights |
security/ |
Video upload validation (MIME type, codec, size) |
prompt_enhancer.py |
Three prompt enhancement strategies: rule-based, local HF (Qwen2.5-3B), Anthropic API |
config.py |
|
civitai.py |
CivitAI integration: parse AIR URNs, auto-download LoRA files |
insights.py |
Hierarchical insights composition (Region → Country → Language → Persona) |
storyboard.py |
Generates image prompts from script rows and creates DiffusionJobs |
adaptation.py |
Adaptation pipeline utilities: state building, model resolution, context composition |
Data Flow
Image Generation
sequenceDiagram
participant User as Admin UI
participant Django
participant Celery as Celery Worker
participant Model as Diffusion Model
participant FS as media/diffusion/
User->>Django: Create Prompt + DiffusionJob
Django->>Celery: Auto-queue generate_images_task
Celery->>Celery: Load model (warm cache)
Celery->>Celery: Apply LoRA (if set)
Celery->>Model: Generate image(s)
Model->>FS: Save to media/diffusion/
Celery->>Django: Update job status + metadata
User->>Django: View results in admin
TV Spot Adaptation
sequenceDiagram
participant User as Admin UI
participant Django
participant Celery as Celery Worker
participant LLM as LLM Models
participant Diff as Diffusion Model
User->>Django: Create Campaign + Origin VideoAdUnit
User->>Django: Create Adaptation VideoAdUnit
Django->>Celery: Auto-queue create_adaptation_task
Celery->>LLM: Concept extraction
Celery->>LLM: Cultural research
Celery->>LLM: Script writing
Celery->>LLM: Evaluation gates (format, cultural, concept, brand)
Celery->>Django: Save briefs + adapted script rows
User->>Django: Create Storyboard
Django->>Celery: Auto-queue generate_storyboard_task
Celery->>Diff: Generate frame images
Celery->>Django: Update storyboard progress
User->>Django: View storyboard frames
Configuration Layers
The system has four configuration layers, from most general to most specific:
Layer |
Source |
What it configures |
|---|---|---|
Environment |
|
Database credentials, API keys (Anthropic, CivitAI), model base path |
Presets |
|
Diffusion model catalog: steps, guidance, dtype, scheduler, LoRA definitions, per-model settings flags |
Django Settings |
|
Celery config (broker, queues, time limits), logging, installed apps, Unfold admin |
Database |
Django admin UI |
Prompt templates (versioned), pipeline settings (per-node LLM defaults), audience data, brands |
Seed data files in data/ bootstrap the database: presets.json, llm_models.json, regions.json, countries.json, languages.json, prompt_templates.json, segments.json, personas.json, brands.json, and their M2M relationship files. All are imported via management commands (see Data Import & Export).
Celery Task Architecture
Task |
Queue |
Purpose |
|---|---|---|
|
enhancement |
Enhance a prompt using rule-based, HF, or Anthropic method |
|
default |
Generate image(s) for a DiffusionJob |
|
default |
Run the 7-node multi-agent adaptation pipeline |
|
default |
Create prompts and DiffusionJobs for storyboard frames |
The worker uses a module-level model cache — a dictionary that keeps the most recently used diffusion model (or LLM enhancer) loaded in memory. When a new model is needed, the old one is evicted and VRAM is freed. This avoids re-loading the same model for consecutive jobs.
Time limits: 1 hour hard limit, 55 minutes soft limit. Results stored in the Django database via django-celery-results.