get-img-analysis / main.py
userIdc2024's picture
Update main.py
03ecc95 verified
from typing import List, Literal, Optional
from pydantic import BaseModel, Field
from openai import OpenAI
from dotenv import load_dotenv
import os
load_dotenv()
client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
class VisualHierarchy(BaseModel):
flow_summary: str = Field(..., description="Brief of top-to-bottom reading flow and funneling.")
key_elements_order: List[str] = Field(..., description="Ordered list of elements as the eye flows.")
class TypographySpec(BaseModel):
casing: Literal["all-caps","title-case","sentence-case","mixed"]
weight: Literal["light","regular","medium","bold","extra-bold"]
color: str
notes: str
class CTAInfo(BaseModel):
text: str
shape_or_style: str
bg_color: str
text_color: str
contrast_comment: str
class VisualStructureLayout(BaseModel):
background_color: str
psychological_association: str
fit_to_theme_comment: str
typography: TypographySpec
minimalism_level: Literal["none","low","medium","high"]
cta: CTAInfo
hierarchy: VisualHierarchy
class CopywritingBreakdown(BaseModel):
headline: str
device_used: List[Literal["curiosity_gap","authority","fear_avoidance","education","urgency","social_proof","other"]]
supporting_text: str
compliance_comment: str
cta_text: str
funnel_feel: Literal["content_recommendation","direct_response","hybrid"]
class PsychologicalBehavioralTriggers(BaseModel):
curiosity: str
fear_or_pain_point: str
authority_appeal: str
ease_of_action: str
class StoryCreativeTells(BaseModel):
problem: str
hope: str
next_step: str
narrative_summary: str
class StrengthWeaknessItem(BaseModel):
point: str
why_it_matters: str
class RisksArbitrageContext(BaseModel):
bounce_risk: str
fatigue_risk: str
compliance_risk: str
class CreativeVariant(BaseModel):
hypothesis: str
change: str
expected_effect: str
metric_to_watch: Literal["CTR","CPC","CPI","CVR","RPM","BounceRate","TimeOnPage","QualityRanking","Other"]
class FunnelSynergy(BaseModel):
landing_page_angle: str
affiliate_or_offer_fit: Optional[str] = None
class TestingPlan(BaseModel):
primary_metrics: List[Literal["CTR","CPC","CVR","RPM","BounceRate","TimeOnPage","QualityRanking","Other"]]
sample_size_or_duration_hint: str
stop_loss_rules: str
class OptimizationNextSteps(BaseModel):
creative_variants: List[CreativeVariant]
funnel_synergy: FunnelSynergy
testing_plan: TestingPlan
class MetaDetect(BaseModel):
language: str
detected_topic: str
confidence_0to1: float = Field(ge=0, le=1)
red_flags: List[str] = Field(..., description="Potential policy or brand-safety flags, if any.")
class AdAnalysis(BaseModel):
visual_structure_layout: VisualStructureLayout
copywriting_breakdown: CopywritingBreakdown
psychological_behavioral_triggers: PsychologicalBehavioralTriggers
story_creative_tells: StoryCreativeTells
strengths: List[StrengthWeaknessItem]
weaknesses: List[StrengthWeaknessItem]
risks_in_arbitrage_context: RisksArbitrageContext
optimization_next_steps: OptimizationNextSteps
meta: MetaDetect
SYSTEM_PROMPT = """
You are a senior performance-creative analyst who analyze a SINGLE image ad. Do not include explanations, markdown, or extra keys.
Rules:
- Be precise and concise. Avoid generic fluff.
- When unsure, infer cautiously and note uncertainty.
- Explain “why it matters” in business terms (CTR, CPC, CVR, RPM, bounce, fatigue, policy).
- Do not invent medical claims or promises; flag policy risks instead.
- Keep color names human-readable (e.g., “pure orange”, “purple”, “yellow”).
"""
USER_PROMPT_TEMPLATE = """
Task: Analyze the attached image ad and produce a structured breakdown:
1) Visual structure & layout
2) Copywriting breakdown
3) Psychological & behavioral triggers
4) Story the creative tells
5) Strengths
6) Weaknesses
7) Risks in arbitrage context
8) Optimization / next steps (variants, funnel synergy, testing plan)
Constraints:
- Use crisp, decision-ready language.
- If text is in Spanish or another language, keep your summaries in English but preserve original CTA text.
"""
def get_analysis(img_url):
messages=[
{
"role": "system",
"content": [
{
"type": "text",
"text": SYSTEM_PROMPT
}
]
},
{
"role": "user",
"content": [
{
"type": "text",
"text": USER_PROMPT_TEMPLATE
},
{
"type": "image_url",
"image_url": {
"url": img_url
}
}
]
}
]
completion = client.chat.completions.parse(
model="gpt-4o",
messages=messages,
response_format=AdAnalysis,
)
ad_analysis = completion.choices[0].message.parsed
return ad_analysis