Spaces:
Running
Running
| """ | |
| 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 of child, lifestyle, platform, and pain_points must align with the selected segments—not generic "parents" 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. gifting, combos, first-time parents, festive). | |
| - 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 kids' and educational toys performance strategist. | |
| You have scaled multiple 7–8 figure toy and baby product brands | |
| using Meta static ads. | |
| You think ONLY in: | |
| - Scroll stopping power | |
| - Emotional tension | |
| - Identity signaling (parent identity, gifting, learning outcomes) | |
| - 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 for Hawbeez (eco-friendly wooden / Montessori toys). | |
| {audience_block} | |
| ━━━━━━━━━━━━━━━━━━ | |
| CRITICAL PERFORMANCE RULES | |
| ━━━━━━━━━━━━━━━━━━ | |
| 1. No generic marketing language. | |
| 2. No empty phrases like "high quality" or "perfect for any child". | |
| 3. Every insight must directly influence: | |
| - Visual direction | |
| - Hook creation | |
| - Or targeting decision. | |
| 4. Assume this is being sold via Meta ads to parents and gift buyers in India (unless target audiences specify otherwise). | |
| 5. If product data lacks detail, infer logically based on category norms (toys, Montessori, wooden, educational). | |
| 6. Think in micro-audiences, not broad demographics (e.g. parents of 2–3 yr, Montessori seekers, eco-conscious, gifting). | |
| 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 in use: describe how the toy is used in play or learning, styling context, scale next to child/hand, key design elements. (2) Shape, size & proportions: describe shape (e.g. puzzle, wheel, blocks, organizer), scale and proportions, number of pieces if visible, key design details (materials, colors, finish). (3) Material, finish & color: wood type, finish (natural/painted), colors as seen, safety/eco cues. 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": "age of child (e.g. 2-4 yrs) or parent segment", | |
| "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 + friendly script", | |
| "tone": "clear tonal direction" | |
| }}, | |
| "unique_selling_points": ["USP 1", "USP 2", "USP 3", "USP 4"] | |
| }} | |
| Return ONLY valid JSON. No markdown. No commentary. | |
| """ | |
| # First 3 product image URLs for vision (comma-split, strip, filter valid) | |
| 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 in use—play or learning context, scale next to child/hand, key design elements; (2) shape, size, and proportions—type of toy (puzzle, blocks, organizer, etc.), scale, number of pieces, colors; (3) material, finish, and color as seen (wood, paint, eco/safety cues). 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-mini", | |
| temperature=0.7, | |
| ) | |
| else: | |
| raw = call_llm(prompt, temperature=0.7) | |
| return extract_json(raw) | |