Replaces the earlier
creative_concept_clusters Bob tool that returned anonymous integer cluster IDs. Materialized weekly so cluster names stay stable across calls in the same week.How it works
Naming pass
For each cluster the task asksgpt-4o-mini (cheap, fast):
name="Cluster N" and summary="". The page still renders it — you just lose the readable label until the next refresh.
What’s in a cluster
Endpoints
Read-only list of materialized concepts for the tenant.Query params:
client_id— required (or implicit for single-tenant users).
{ "client_id": "...", "concepts": [...] } ordered by (spend_30d desc, roas_30d desc).Force a recluster outside the weekly schedule. Useful after a sweep of new creatives lands.Body:
{ "client_id": "..." }. Returns 202 Accepted with a Celery task id. The page polls for completion and reloads.shared.auth.get_accessible_client_ids.
Bob tool
Bubble chart UI
The Ad Creative Analytics page renders concepts as a Highcharts bubble chart:
A grid of cards below the chart shows each cluster with its name, summary, and stats. Clicking a bubble (or a card — wired in v2) opens a drawer with the member creative thumbnails so the user can quickly scan the actual content of a cluster.
Worked example
After a tenant’s Monday refresh, the page might show:
The Studio hero and Before / after clusters are clearly underperforming relative to the others — that’s a useful prompt for the daily brief to recommend leaning into the founder talking heads concept next.
Cost & cadence
- Embedding the corpus is a one-time cost (~$0.0002 per creative; shared with similarity / search).
- k-means is local CPU compute (sklearn).
- Naming pass is the only ongoing cost: ~0.07 per tenant per month.
Tunable knobs
Where the code lives
marketing_resources/tasks/refresh_creative_concepts.py— the cron task + naming pass.marketing_resources/models/creative_concept.py— the row.marketing_resources/views/creative_concepts.py— the two endpoints.ai_chat/tools_creative.py:creative_concept_clusters— the Bob tool.
.png?fit=max&auto=format&n=Frm2GFbmok4D-yJA&q=85&s=93c3ebd47542af65d1cd06d8563a7f6e)