Automates automotive dealership ad creative at scale: copy generation, vehicle image generation, multi-layer OEM brand compliance, state/provincial legal compliance, and proactive grace-period law monitoring.
cp .env.example .env
# Set GEMINI_API_KEY in .env
docker compose up -d
docker compose exec api alembic upgrade head
docker compose exec api python -m scripts.seed_db
docker compose exec api python -m scripts.run_pipelinesAPI: http://localhost:8000/docs
Neo4j Browser: http://localhost:7474 (neo4j / carad_neo4j)
OpenSearch Dashboards: http://localhost:5601
Grafana: http://localhost:3001 (admin / carad_grafana)
Flower (Celery): http://localhost:5555
Marquez (Lineage): http://localhost:3000
LiteLLM Proxy: http://localhost:4000
curl -X POST http://localhost:8000/api/v1/ads/generate \
-H "Content-Type: application/json" \
-d '{
"dealer_slug": "sunrise-ford-dallas",
"platform": "meta",
"campaign_name": "July 4th Sales Event",
"start_date": "2025-07-01",
"end_date": "2025-07-31"
}'curl http://localhost:8000/api/v1/review/queue
# Get grace-period risk alerts
curl http://localhost:8000/api/v1/review/alerts/grace-periodDealer Request
│
▼
[1] RETRIEVAL ── OpenSearch RAG
│ OEM rules (per brand, versioned)
│ Legal rules (per jurisdiction)
│ Inventory data (per dealer)
│
▼
[2] GENERATION ── LiteLLM → Gemini Flash
│ Copy with [SLOT] placeholders
│ slot_filler injects verified prices
│ Gemini Imagen 3 → vehicle image
│
▼
[3] COMPLIANCE GATE
│ Deterministic: regex, slot validation
│ Grace-period: future law overlap check
│ LLM-as-judge: Gemini Pro evaluates vs. rules
│ → PASS / FAIL / FLAG / GRACE_PERIOD_RISK
│
▼
[4] DELIVERY or HUMAN REVIEW
PASS → mark approved
FLAG/LOW CONFIDENCE → human review queue
GRACE_PERIOD_RISK → priority 1 alert
FAIL + retries exhausted → escalate
Slot-filling for prices: The LLM never generates dollar amounts, APR rates, or incentive values. It generates templates with [PRICE], [APR_RATE] placeholders. slot_filler.py injects verified values from the inventory feed. A post-fill validator checks no unverified numbers appear.
Separate judge model: The compliance LLM judge (gemini-judge) is a different model instance from the generator (gemini-flash). This prevents self-grading bias.
Grace-period monitoring: When a new law passes with a future effective_date, every new campaign is checked against it. If the campaign's end_date >= (effective_date - grace_period_days - alert_buffer_days), a GracePeriodAlert is created and a specialized LLM pass assesses content risk. See ARCHITECTURE.md.
OEM rule versioning: Each dealer is pinned to an OEM rule version. When OEM publishes new guidelines, only dealers explicitly migrated to the new version are affected. Full audit trail on rule changes.
Edit src/ingestion/legal/source.py to implement fetch_legal_rules(). Return a list of dicts matching the schema documented in that file. Then run:
python -m scripts.seed_db # after source.py is implemented
python -m scripts.index_oem_rules # re-index after adding rules| Service | Port | Purpose |
|---|---|---|
| FastAPI | 8000 | REST API |
| PostgreSQL | 5432 | Primary data store |
| OpenSearch | 9200 | RAG vector index |
| OpenSearch Dashboards | 5601 | Search UI |
| Redis | 6379 | Celery broker/backend |
| LiteLLM Proxy | 4000 | LLM routing (Gemini/OpenAI) |
| Celery Worker | — | Async ad generation |
| Flower | 5555 | Celery monitoring |
| Marquez API | 5000 | OpenLineage backend |
| Marquez Web | 3000 | Lineage visualization |
| Neo4j | 7474 / 7687 | Graph DB (OEM → Dealer → Law relationships) |
| Prometheus | 9090 | Metrics collection |
| Grafana | 3001 | Metrics dashboard |