Creative_Breakthrough / services /creative_inventor.py
sushilideaclan01's picture
add new things in the extensive flow
026f283
"""
Creative Inventor: generates new ad angles, concepts, visuals, and psychological triggers by itself.
Can run standalone (ideas for review/export) or feed into the extensive flow.
"""
from typing import List, Optional
from openai import OpenAI
from pydantic import BaseModel
from config import settings
# ---------------------------------------------------------------------------
# Output models: what the inventor produces
# ---------------------------------------------------------------------------
class InventedEssential(BaseModel):
"""One invented creative essential: trigger + angles + concepts + visual directions + hyper-specific audience."""
psychology_trigger: str
angles: List[str]
concepts: List[str]
visual_directions: List[str]
hooks: List[str] = [] # Optional scroll-stopping headlines
visual_styles: List[str] = [] # Optional scene/prompt-style descriptions
target_audience: str = "" # Hyper-specific audience for this essential (AI-decided, different per essential)
class InventedCreativeOutput(BaseModel):
"""Structured output from the creative inventor."""
output: List[InventedEssential]
class CreativeInventorService:
"""
Invents new ad angles, concepts, visuals, and psychological triggers.
Use standalone to generate ideas, or feed output into the extensive flow.
"""
def __init__(self):
self.client = OpenAI(api_key=settings.openai_api_key)
self.model = getattr(settings, "third_flow_model", "gpt-4o")
def invent(
self,
niche: str,
offer: str,
*,
target_audience_hint: Optional[str] = None,
existing_reference: Optional[str] = None,
trend_context: Optional[str] = None,
competitor_insights: Optional[str] = None,
n: int = 5,
) -> List[InventedEssential]:
"""
Invent new psychological triggers, angles, concepts, visual directions,
hooks, visual styles, and a hyper-specific target_audience per essential.
The AI decides all target audiences; they must be different types (demographic, psychographic, situation).
Args:
niche: e.g. "GLP-1", "Home Insurance"
offer: what is being promoted
target_audience_hint: optional broad hint (e.g. "weight loss"); AI still invents distinct hyper-specific audiences per essential
existing_reference: optional summary of existing strategies (to diverge or avoid repeating)
trend_context: optional trending topics or occasions
competitor_insights: optional notes on what competitors are doing
n: number of invented "essentials" to return (each with its own hyper-specific audience)
Returns:
List of InventedEssential for use in extensive flow or export.
"""
system_prompt = """You are a creative strategist who invents NEW ad angles, concepts, visuals, psychological triggers, and HYPER-SPECIFIC target audiences for performance and affiliate marketing.
Your job is to CREATE novel ideas—not to recycle generic ones. For each "essential" you produce:
- target_audience: ONE hyper-specific audience for this essential. You MUST invent a different type of audience for each essential. Examples of hyper-specific audiences: "Women 45–55 who tried Ozempic and stalled", "Men 35–45 with 30+ lbs to lose who hate gyms", "Busy moms who yo-yo diet and have given up on willpower", "Women 50+ who've tried everything and feel it's biology not laziness", "Professionals who travel constantly and want no-fuss delivery", "Skeptics who think GLP-1 is a scam and need proof". Mix demographics, psychographics, and situations. No generic "people interested in X".
- Psychology trigger: the emotional or cognitive lever (e.g. validation before solution, future regret, justified scarcity, objection-first then flip).
- Angles: the reasons this specific audience should care; reframe the problem or outcome in a fresh way.
- Concepts: the creative execution or storyline (e.g. crossed-out negative labels, progress bar + social proof, two-path fork).
- Visual directions: concrete visual ideas (e.g. "progress bar 87% full with 10k counter", "grid of crossed-out DAY 1s").
- Hooks: 2–4 scroll-stopping headline phrases for that essential and audience.
- Visual styles: 2–4 short scene/prompt-style descriptions for image generation.
Rules:
- Each essential MUST have a different target_audience. Vary types: age/gender, life situation, mindset, past failures, skepticism, convenience-seekers, etc.
- Prioritize novelty and specificity. Avoid vague angles or generic audiences.
- Combine triggers in new ways. Invent visual metaphors that work for the chosen audience.
- Output exactly the number of "essentials" requested (n). Each essential should feel distinct and speak to a distinctly different audience."""
user_parts = [
f"Niche: {niche}",
f"Offer: {offer}",
f"Invent exactly {n} different creative essentials. For EACH essential you MUST set a different hyper-specific target_audience (demographic, psychographic, or situation). Then set psychology_trigger, angles, concepts, visual_directions, hooks, visual_styles for that audience.",
]
if target_audience_hint:
user_parts.append(f"Broad category hint (invent specific segments within or related to this): {target_audience_hint}")
if existing_reference:
user_parts.append(f"Existing strategies to diverge from (do not copy):\n{existing_reference}")
if trend_context:
user_parts.append(f"Trend / occasion context (use for relevance):\n{trend_context}")
if competitor_insights:
user_parts.append(f"Competitor / market insights (use to differentiate):\n{competitor_insights}")
user_content = "\n\n".join(user_parts)
# Ensure model returns target_audience; fallback for older parsed outputs
# (InventedEssential now has target_audience with default "")
try:
completion = self.client.beta.chat.completions.parse(
model=self.model,
messages=[
{"role": "system", "content": system_prompt},
{"role": "user", "content": user_content},
],
response_format=InventedCreativeOutput,
)
response = completion.choices[0].message
if response.parsed and response.parsed.output:
return response.parsed.output[:n]
return []
except Exception as e:
print(f"CreativeInventor error: {e}")
return []
def invent_and_export(
self,
niche: str,
offer: str,
essentials: Optional[List["InventedEssential"]] = None,
target_audience_hint: Optional[str] = None,
**kwargs,
) -> str:
"""
Invent (if essentials not provided) and return a human-readable text summary for export or review.
"""
if essentials is None:
essentials = self.invent(niche=niche, offer=offer, target_audience_hint=target_audience_hint, **kwargs)
lines = [
f"# Invented creatives — {niche}" + (f" | {target_audience_hint}" if target_audience_hint else ""),
"",
]
for i, e in enumerate(essentials, 1):
aud = getattr(e, "target_audience", "") or ""
lines.append(f"## Essential {i}: {e.psychology_trigger}" + (f" — {aud}" if aud else ""))
lines.append("")
if aud:
lines.append("**Target audience:** " + aud)
lines.append("")
lines.append("**Angles:** " + " | ".join(e.angles))
lines.append("**Concepts:** " + " | ".join(e.concepts))
lines.append("**Visual directions:** " + " | ".join(e.visual_directions))
if e.hooks:
lines.append("**Hooks:** " + " | ".join(e.hooks))
if e.visual_styles:
lines.append("**Visual styles:** " + " | ".join(e.visual_styles))
lines.append("")
return "\n".join(lines)
# Singleton for use from third_flow / generator
creative_inventor_service = CreativeInventorService()