| """ |
| Deep marketing analysis of product data for ad creative generation. |
| """ |
|
|
| import json |
|
|
| from app.llm import call_llm, call_llm_vision, extract_json |
|
|
|
|
| def analyze_product(product_data: dict, target_audience: list[str] | None = None) -> dict: |
| """ |
| Deep marketing analysis of the product. |
| Returns structured dict for generating highly targeted ad creative. |
| When target_audience is provided, analysis is tailored to those segments. |
| """ |
| price = product_data.get("price", "") |
| audience_block = "" |
| if target_audience and len(target_audience) > 0: |
| audience_list = ", ".join(target_audience) |
| audience_block = f""" |
| ━━━━━━━━━━━━━━━━━━ |
| TARGET AUDIENCES (PRIORITY — MUST DRIVE THIS ANALYSIS) |
| ━━━━━━━━━━━━━━━━━━ |
| |
| The user has selected these specific audience segments. Your ENTIRE analysis MUST be tailored to these audiences. |
| |
| - positioning: Reframe for these segments (who they are, what they want, how this product fits). |
| - ideal_customer: Age, lifestyle, platform, and pain_points must align with the selected segments—not generic "urban women" or "25-35". |
| - emotional_triggers: Choose triggers that resonate with these specific segments. |
| - ad_angles: Each angle must speak directly to one or more of these audiences; hooks and "why it works" must reference them. |
| - tagline_options: Lines that appeal to these segments. |
| - price_analysis: Frame value and perception for these buyers (e.g. COD buyers, ₹1.5k–₹3k, festive, self-gifters). |
| - shooting_angles, color_worlds, copy_direction: Align with how these audiences discover and consume content. |
| |
| Selected segments (use these, do not substitute generic demographics): |
| {audience_list} |
| |
| Do NOT produce a generic analysis. Every section must reflect the selected segments. |
| """ |
|
|
| prompt = f""" |
| You are an elite Indian DTC jewelry performance strategist. |
| |
| You have scaled multiple 7–8 figure jewelry brands |
| using Meta static ads. |
| |
| You think ONLY in: |
| - Scroll stopping power |
| - Emotional tension |
| - Identity signaling |
| - Conversion psychology |
| - Visual hierarchy |
| |
| Your job: |
| Perform a DEEP conversion-focused analysis of THIS specific product |
| that will directly power high-performing STATIC ad creatives. |
| {audience_block} |
| |
| ━━━━━━━━━━━━━━━━━━ |
| CRITICAL PERFORMANCE RULES |
| ━━━━━━━━━━━━━━━━━━ |
| |
| 1. No generic marketing language. |
| 2. No empty phrases like “high quality” or “perfect for any occasion”. |
| 3. Every insight must directly influence: |
| - Visual direction |
| - Hook creation |
| - Or targeting decision. |
| 4. Assume this is being sold via Meta ads to global urban buyers (unless target audiences specify otherwise). |
| 5. If product data lacks detail, infer logically based on category norms. |
| 6. Think in micro-audiences, not broad demographics. |
| 7. This analysis must help generate scroll-stopping static creatives. |
| |
| Return ONLY valid JSON. |
| No markdown. |
| No commentary. |
| No explanations outside JSON. |
| |
| ━━━━━━━━━━━━━━━━━━ |
| PRODUCT DATA |
| ━━━━━━━━━━━━━━━━━━ |
| {json.dumps(product_data, indent=2)} |
| |
| ━━━━━━━━━━━━━━━━━━ |
| OUTPUT REQUIREMENTS |
| ━━━━━━━━━━━━━━━━━━ |
| |
| - Exactly 6 emotional triggers |
| - Exactly 5 ad angles |
| - Exactly 4 shooting_angles |
| - Exactly 3 color_worlds |
| - Exactly 4 unique_selling_points |
| - 3 tagline_options |
| |
| Price rules: |
| Final price = {product_data.get('price', '')} |
| Anchor price must not exceed 2.5x final price. |
| Value framing must feel psychologically believable. |
| |
| ━━━━━━━━━━━━━━━━━━ |
| RETURN THIS EXACT JSON STRUCTURE |
| ━━━━━━━━━━━━━━━━━━ |
| |
| {{ |
| "product_visual_notes": "When product images were provided: 2-3 short paragraphs. (1) How it looks when worn: describe how the piece sits on the wearer (ear/neck/wrist), styling context, how it frames the face or body, movement or drape. (2) Shape, size & proportions: describe shape (e.g. dangler, stud, length), scale and proportions, drop length or size of elements if visible, key design details (chains, stones, motifs). (3) Material, finish & color: metal type, finish (matte/shiny/brushed), color as seen, stones or accents. Omit or empty string if no images.", |
| "positioning": "Clear one-line positioning statement (who + outcome + differentiation)", |
| "tagline_options": ["Option 1", "Option 2", "Option 3"], |
| "ideal_customer": {{ |
| "age_range": "", |
| "lifestyle": "specific, not generic", |
| "platform": "primary buying platform", |
| "pain_points": ["Pain 1", "Pain 2", "Pain 3"] |
| }}, |
| "emotional_triggers": ["Trigger 1", "Trigger 2", "Trigger 3", "Trigger 4", "Trigger 5", "Trigger 6"], |
| "price_analysis": {{ |
| "price_point": "{product_data.get('price', '')}", |
| "perception": "how this price feels emotionally", |
| "anchor_price": "realistic strikethrough", |
| "value_framing": "believable comparison framing" |
| }}, |
| "ad_angles": [ |
| {{ "angle_name": "", "hook": "", "why_it_works": "" }}, |
| {{ "angle_name": "", "hook": "", "why_it_works": "" }}, |
| {{ "angle_name": "", "hook": "", "why_it_works": "" }}, |
| {{ "angle_name": "", "hook": "", "why_it_works": "" }}, |
| {{ "angle_name": "", "hook": "", "why_it_works": "" }} |
| ], |
| "shooting_angles": ["Angle 1", "Angle 2", "Angle 3", "Angle 4"], |
| "color_worlds": ["Direction 1", "Direction 2", "Direction 3"], |
| "copy_direction": {{ |
| "headline_style": "e.g. bold serif uppercase + script style", |
| "tone": "clear tonal direction" |
| }}, |
| "unique_selling_points": ["USP 1", "USP 2", "USP 3", "USP 4"] |
| }} |
| |
| Return ONLY valid JSON. No markdown. No commentary. |
| """ |
|
|
| |
| image_urls = [ |
| u.strip() |
| for u in (product_data.get("product_images") or "").split(",") |
| if (u and u.strip().startswith("http")) |
| ][:3] |
|
|
| if image_urls: |
| vision_note = "\n\nYou are also provided with product images in this message. Describe the product in detail: (1) how it looks when worn—how it sits on the wearer, styling, frame of face/body, movement; (2) shape, size, and proportions—shape type, scale, drop length, key design details; (3) material, finish, and color as seen. Put this in product_visual_notes as 2-3 short paragraphs. Use these observations to inform your visual direction, shooting_angles, color_worlds, and overall creative recommendations." |
| content: list[dict] = [{"type": "text", "text": prompt + vision_note}] |
| for url in image_urls: |
| content.append({"type": "image_url", "image_url": {"url": url}}) |
| raw = call_llm_vision( |
| messages=[{"role": "user", "content": content}], |
| model="gpt-4o", |
| temperature=0.7, |
| ) |
| else: |
| raw = call_llm(prompt, temperature=0.7) |
|
|
| return extract_json(raw) |
|
|