|
|
""" |
|
|
Affiliate Marketing Concepts Framework (Lite Version) |
|
|
100 concepts organized into 10 categories. |
|
|
Concepts answer: "How do I show it visually?" (Creative HOW) |
|
|
""" |
|
|
|
|
|
from typing import Dict, List, Any, Optional |
|
|
from enum import Enum |
|
|
import random |
|
|
|
|
|
|
|
|
class ConceptCategory(str, Enum): |
|
|
"""Concept categories - focused on creative HOW (storytelling, proof, etc.) |
|
|
Note: Visual layouts (before/after, split screen, etc.) are now in visuals.py |
|
|
""" |
|
|
UGC_NATIVE = "ugc_native" |
|
|
STORYTELLING = "storytelling" |
|
|
COMPARISON = "comparison" |
|
|
AUTHORITY = "authority" |
|
|
SOCIAL_PROOF = "social_proof" |
|
|
SCROLL_STOPPING = "scroll_stopping" |
|
|
EDUCATIONAL = "educational" |
|
|
PERSONALIZATION = "personalization" |
|
|
CTA_FOCUSED = "cta_focused" |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
CONCEPTS = { |
|
|
ConceptCategory.UGC_NATIVE: { |
|
|
"name": "UGC & Native", |
|
|
"concepts": [ |
|
|
{"key": "selfie_style", "name": "Selfie-Style Image", "structure": "Phone camera angle", "visual": "Casual, authentic feel"}, |
|
|
{"key": "casual_phone", "name": "Casual Phone Shot", "structure": "Mobile perspective", "visual": "Unpolished, authentic"}, |
|
|
{"key": "pov", "name": "POV Perspective", "structure": "First-person view", "visual": "Immersive feel"}, |
|
|
{"key": "just_found", "name": "Just Found This", "structure": "Discovery moment", "visual": "Excited, sharing"}, |
|
|
{"key": "organic_feed", "name": "Organic Feed Style", "structure": "Native to platform", "visual": "Doesn't look like ad"}, |
|
|
{"key": "influencer", "name": "Influencer-Style", "structure": "Polished but authentic", "visual": "Influencer aesthetic"}, |
|
|
{"key": "low_production", "name": "Low-Production Authentic", "structure": "Raw, unpolished", "visual": "Authentic feel"}, |
|
|
{"key": "reaction", "name": "Reaction Shot", "structure": "Emotional reaction", "visual": "Clear emotion visible"}, |
|
|
{"key": "screenshot", "name": "Screenshot-Style", "structure": "Device screenshot", "visual": "Realistic screenshot"}, |
|
|
{"key": "story_frame", "name": "Story Frame", "structure": "Vertical story format", "visual": "Story-style layout"}, |
|
|
{"key": "behind_scenes", "name": "Behind the Scenes", "structure": "Raw, unedited look", "visual": "Authentic, unpolished"}, |
|
|
{"key": "day_in_life", "name": "Day in the Life", "structure": "Daily routine snapshot", "visual": "Relatable daily moments"}, |
|
|
{"key": "unboxing_style", "name": "Unboxing Style", "structure": "Product reveal moment", "visual": "Discovery excitement"}, |
|
|
] |
|
|
}, |
|
|
ConceptCategory.STORYTELLING: { |
|
|
"name": "Storytelling", |
|
|
"concepts": [ |
|
|
{"key": "emotional_snapshot", "name": "Emotional Snapshot", "structure": "Single emotional moment", "visual": "Authentic expression"}, |
|
|
{"key": "relatable_moment", "name": "Relatable Daily Moment", "structure": "Everyday scene", "visual": "Relatable situation"}, |
|
|
{"key": "micro_story", "name": "Micro-Story Scene", "structure": "Small story moment", "visual": "Narrative feel"}, |
|
|
{"key": "life_situation", "name": "Life Situation", "structure": "Real-life context", "visual": "Authentic situation"}, |
|
|
{"key": "decision_moment", "name": "Decision Moment", "structure": "Decision point", "visual": "Contemplative"}, |
|
|
{"key": "problem_awareness", "name": "Problem Awareness Scene", "structure": "Problem visible", "visual": "Awareness moment"}, |
|
|
{"key": "turning_point", "name": "Turning Point Frame", "structure": "Transformation moment", "visual": "Change visible"}, |
|
|
{"key": "relief_moment", "name": "Relief Moment", "structure": "Relief visible", "visual": "Peace visible"}, |
|
|
{"key": "success_moment", "name": "Success Moment", "structure": "Success visible", "visual": "Achievement visible"}, |
|
|
{"key": "future_projection", "name": "Future Projection", "structure": "Future vision", "visual": "Aspirational"}, |
|
|
{"key": "journey_arc", "name": "Journey Arc", "structure": "Complete transformation story", "visual": "Full journey visible"}, |
|
|
{"key": "milestone_moment", "name": "Milestone Moment", "structure": "Key achievement moment", "visual": "Celebration visible"}, |
|
|
] |
|
|
}, |
|
|
ConceptCategory.COMPARISON: { |
|
|
"name": "Comparison & Logic", |
|
|
"concepts": [ |
|
|
{"key": "side_by_side_table", "name": "Side-by-Side Table", "structure": "Comparison table", "visual": "Checkmarks/crosses"}, |
|
|
{"key": "old_vs_new", "name": "Old Way vs New Way", "structure": "Old vs new comparison", "visual": "Modern highlighted"}, |
|
|
{"key": "choice_elimination", "name": "Choice Elimination", "structure": "Others crossed out", "visual": "Winner clear"}, |
|
|
{"key": "feature_breakdown", "name": "Feature Breakdown", "structure": "Features compared", "visual": "Easy to compare"}, |
|
|
{"key": "pros_cons", "name": "Pros vs Cons", "structure": "Pros on one side, cons other", "visual": "Balanced view"}, |
|
|
{"key": "ranking", "name": "Ranking Visual", "structure": "Ranked list", "visual": "Top highlighted"}, |
|
|
{"key": "winner_highlight", "name": "Winner Highlight", "structure": "Winner highlighted", "visual": "Others dimmed"}, |
|
|
{"key": "bar_scale", "name": "Bar / Scale Visual", "structure": "Visual bars/scales", "visual": "Easy to compare"}, |
|
|
{"key": "price_stack", "name": "Price Stack", "structure": "Prices stacked", "visual": "Savings visible"}, |
|
|
{"key": "value_breakdown", "name": "Value Breakdown", "structure": "Value components", "visual": "Easy to understand"}, |
|
|
{"key": "versus_comparison", "name": "Versus Comparison", "structure": "Head-to-head comparison", "visual": "Clear winner"}, |
|
|
{"key": "feature_matrix", "name": "Feature Matrix", "structure": "Feature comparison grid", "visual": "Easy comparison"}, |
|
|
] |
|
|
}, |
|
|
ConceptCategory.AUTHORITY: { |
|
|
"name": "Authority & Trust", |
|
|
"concepts": [ |
|
|
{"key": "expert_portrait", "name": "Expert Portrait", "structure": "Professional portrait", "visual": "Trustworthy appearance"}, |
|
|
{"key": "badge_seal", "name": "Badge / Seal Visual", "structure": "Badges prominent", "visual": "Official look"}, |
|
|
{"key": "certification", "name": "Certification Overlay", "structure": "Cert overlaid", "visual": "Official"}, |
|
|
{"key": "media_mention", "name": "Media Mention Style", "structure": "Media logos/quotes", "visual": "Credible"}, |
|
|
{"key": "professional_setting", "name": "Professional Setting", "structure": "Office/professional space", "visual": "Clean, organized"}, |
|
|
{"key": "office_scene", "name": "Office / Desk Scene", "structure": "Office environment", "visual": "Professional"}, |
|
|
{"key": "institutional", "name": "Institutional Look", "structure": "Official design", "visual": "Institutional"}, |
|
|
{"key": "data_backed", "name": "Data-Backed Visual", "structure": "Charts, graphs", "visual": "Data visible"}, |
|
|
{"key": "chart_graph", "name": "Chart / Graph Snapshot", "structure": "Chart dominates", "visual": "Easy to read"}, |
|
|
{"key": "trust_signals", "name": "Trust Signal Stack", "structure": "Multiple trust elements", "visual": "Organized signals"}, |
|
|
{"key": "credentials_display", "name": "Credentials Display", "structure": "Certifications shown", "visual": "Official credentials"}, |
|
|
{"key": "partnership_logos", "name": "Partnership Logos", "structure": "Partner brands visible", "visual": "Trusted partnerships"}, |
|
|
] |
|
|
}, |
|
|
ConceptCategory.SOCIAL_PROOF: { |
|
|
"name": "Social Proof", |
|
|
"concepts": [ |
|
|
{"key": "testimonial_screenshot", "name": "Testimonial Screenshot", "structure": "Screenshot format", "visual": "Authentic testimonial"}, |
|
|
{"key": "quote_card", "name": "Quote Card", "structure": "Quote as main visual", "visual": "Clear, readable"}, |
|
|
{"key": "case_study_frame", "name": "Case Study Frame", "structure": "Case study format", "visual": "Results visible"}, |
|
|
{"key": "crowd", "name": "Crowd Visual", "structure": "Many people visible", "visual": "Popular feel"}, |
|
|
{"key": "others_like_you", "name": "Others Like You", "structure": "Similar people", "visual": "Relatable, authentic"}, |
|
|
{"key": "real_customer", "name": "Real Customer Photo", "structure": "Real customer shown", "visual": "Authentic, relatable"}, |
|
|
{"key": "comment_screenshot", "name": "Comment Screenshot", "structure": "Comments visible", "visual": "Realistic comments"}, |
|
|
{"key": "ugc_collage", "name": "UGC Collage", "structure": "Multiple UGC pieces", "visual": "Collage format"}, |
|
|
{"key": "community", "name": "Community Visual", "structure": "Community visible", "visual": "Belonging feel"}, |
|
|
{"key": "user_spotlight", "name": "User Spotlight", "structure": "Individual user featured", "visual": "Personal success story"}, |
|
|
{"key": "group_success", "name": "Group Success", "structure": "Multiple success stories", "visual": "Collective achievement"}, |
|
|
] |
|
|
}, |
|
|
ConceptCategory.SCROLL_STOPPING: { |
|
|
"name": "Scroll-Stopping", |
|
|
"concepts": [ |
|
|
{"key": "shock_headline", "name": "Shock Headline", "structure": "Shocking headline dominates", "visual": "Bold, high contrast"}, |
|
|
{"key": "unusual_contrast", "name": "Unusual Contrast", "structure": "High contrast, unusual colors", "visual": "Stands out"}, |
|
|
{"key": "pattern_break", "name": "Pattern Break Design", "structure": "Different from expected", "visual": "Unexpected"}, |
|
|
{"key": "unexpected_image", "name": "Unexpected Image", "structure": "Surprising visual", "visual": "Attention-grabbing"}, |
|
|
{"key": "bold_claim", "name": "Bold Claim Card", "structure": "Bold claim prominent", "visual": "Large text"}, |
|
|
{"key": "glitch_highlight", "name": "Glitch / Highlight", "structure": "Glitch effect", "visual": "Modern"}, |
|
|
{"key": "disruptive_color", "name": "Disruptive Color Use", "structure": "Unexpected colors", "visual": "Disruptive"}, |
|
|
{"key": "meme_style", "name": "Meme-Style Image", "structure": "Meme format", "visual": "Shareable"}, |
|
|
{"key": "visual_tension", "name": "Visual Tension", "structure": "Tension in visual", "visual": "Engaging"}, |
|
|
{"key": "bold_typography", "name": "Bold Typography Focus", "structure": "Typography dominates", "visual": "Text-first impact"}, |
|
|
{"key": "motion_blur", "name": "Motion Blur Effect", "structure": "Dynamic movement feel", "visual": "Energy and action"}, |
|
|
] |
|
|
}, |
|
|
ConceptCategory.EDUCATIONAL: { |
|
|
"name": "Educational & Explainer", |
|
|
"concepts": [ |
|
|
{"key": "how_it_works", "name": "How It Works", "structure": "Process explanation", "visual": "Step-by-step"}, |
|
|
{"key": "three_step", "name": "3-Step Process", "structure": "Step 1→2→3", "visual": "Simple flow"}, |
|
|
{"key": "flow_diagram", "name": "Flow Diagram", "structure": "Flowchart format", "visual": "Easy to follow"}, |
|
|
{"key": "simple_explainer", "name": "Simple Explainer", "structure": "Simple explanation", "visual": "Easy to understand"}, |
|
|
{"key": "faq", "name": "FAQ Visual", "structure": "FAQ format", "visual": "Clear Q&A"}, |
|
|
{"key": "mistake_callout", "name": "Mistake Callout", "structure": "Mistakes highlighted", "visual": "Avoid them"}, |
|
|
{"key": "do_dont", "name": "Do / Don't Visual", "structure": "Do vs Don't", "visual": "Easy to understand"}, |
|
|
{"key": "learning_card", "name": "Learning Card", "structure": "Card with content", "visual": "Educational"}, |
|
|
{"key": "visual_guide", "name": "Visual Guide", "structure": "Guide format", "visual": "Instructional"}, |
|
|
{"key": "instructional", "name": "Instructional Frame", "structure": "Instruction format", "visual": "Easy to follow"}, |
|
|
{"key": "tip_card", "name": "Tip Card", "structure": "Quick tip format", "visual": "Actionable advice"}, |
|
|
{"key": "checklist_visual", "name": "Checklist Visual", "structure": "Checklist format", "visual": "Easy to follow"}, |
|
|
] |
|
|
}, |
|
|
ConceptCategory.PERSONALIZATION: { |
|
|
"name": "Call-Out & Personalization", |
|
|
"concepts": [ |
|
|
{"key": "if_you_are", "name": "If You Are X…", "structure": "Direct callout", "visual": "Specific group"}, |
|
|
{"key": "age_specific", "name": "Age-Specific Visual", "structure": "Age-specific imagery", "visual": "Relatable"}, |
|
|
{"key": "location_specific", "name": "Location-Specific", "structure": "Location visible", "visual": "Local feel"}, |
|
|
{"key": "role_based", "name": "Role-Based Scene", "structure": "Role-specific scene", "visual": "Relatable"}, |
|
|
{"key": "lifestyle_scene", "name": "Lifestyle Match", "structure": "Lifestyle visible", "visual": "Match"}, |
|
|
{"key": "identity_mirror", "name": "Identity Mirror", "structure": "Identity reflected", "visual": "Connection"}, |
|
|
{"key": "targeted_headline", "name": "Targeted Headline", "structure": "Targeted headline", "visual": "Relevant"}, |
|
|
{"key": "personalized_hook", "name": "Personalized Hook", "structure": "Personalized opening", "visual": "Connection"}, |
|
|
{"key": "segment_callout", "name": "Segment Callout", "structure": "Segment-specific", "visual": "Targeted"}, |
|
|
{"key": "direct_address", "name": "Direct Address", "structure": "Direct address format", "visual": "Personal"}, |
|
|
{"key": "custom_message", "name": "Custom Message", "structure": "Personalized message", "visual": "One-on-one feel"}, |
|
|
{"key": "targeted_audience", "name": "Targeted Audience Visual", "structure": "Specific audience shown", "visual": "Relatable group"}, |
|
|
] |
|
|
}, |
|
|
ConceptCategory.CTA_FOCUSED: { |
|
|
"name": "CTA-Focused", |
|
|
"concepts": [ |
|
|
{"key": "button_focused", "name": "Button-Focused Image", "structure": "Button prominent", "visual": "Action-oriented"}, |
|
|
{"key": "arrow_flow", "name": "Arrow-Directed Flow", "structure": "Arrows point to CTA", "visual": "Directional"}, |
|
|
{"key": "highlighted_cta", "name": "Highlighted CTA Box", "structure": "CTA box stands out", "visual": "Clear"}, |
|
|
{"key": "action_words", "name": "Action Words Overlay", "structure": "Action words prominent", "visual": "Urgent"}, |
|
|
{"key": "click_prompt", "name": "Click Prompt Visual", "structure": "Click prompt visible", "visual": "Action-oriented"}, |
|
|
{"key": "tap_here", "name": "Tap-Here Cue", "structure": "Tap here visible", "visual": "Mobile-friendly"}, |
|
|
{"key": "next_step", "name": "Next Step Highlight", "structure": "Next step prominent", "visual": "Action-oriented"}, |
|
|
{"key": "simple_cta", "name": "Simple CTA Card", "structure": "Simple card with CTA", "visual": "Minimal"}, |
|
|
{"key": "countdown_cta", "name": "Countdown CTA", "structure": "Countdown + CTA", "visual": "Urgent"}, |
|
|
{"key": "final_push", "name": "Final Push Frame", "structure": "Final push format", "visual": "Urgent, action"}, |
|
|
{"key": "pulsing_cta", "name": "Pulsing CTA", "structure": "Animated attention", "visual": "Eye-catching action"}, |
|
|
{"key": "multi_cta", "name": "Multiple CTAs", "structure": "Multiple action options", "visual": "Flexible engagement"}, |
|
|
] |
|
|
}, |
|
|
} |
|
|
|
|
|
|
|
|
def get_all_concepts() -> List[Dict[str, Any]]: |
|
|
"""Get all concepts as a flat list.""" |
|
|
all_concepts = [] |
|
|
for category, data in CONCEPTS.items(): |
|
|
for concept in data["concepts"]: |
|
|
concept_copy = concept.copy() |
|
|
concept_copy["category"] = data["name"] |
|
|
concept_copy["category_key"] = category |
|
|
all_concepts.append(concept_copy) |
|
|
return all_concepts |
|
|
|
|
|
|
|
|
def get_concepts_by_category(category: ConceptCategory) -> List[Dict[str, Any]]: |
|
|
"""Get concepts for a specific category.""" |
|
|
return CONCEPTS.get(category, {}).get("concepts", []) |
|
|
|
|
|
|
|
|
def get_concept_by_key(key: str) -> Optional[Dict[str, Any]]: |
|
|
"""Get a specific concept by key.""" |
|
|
for category, data in CONCEPTS.items(): |
|
|
for concept in data["concepts"]: |
|
|
if concept["key"] == key: |
|
|
concept_copy = concept.copy() |
|
|
concept_copy["category"] = data["name"] |
|
|
concept_copy["category_key"] = category |
|
|
return concept_copy |
|
|
return None |
|
|
|
|
|
|
|
|
def get_random_concepts(count: int = 5, diverse: bool = True) -> List[Dict[str, Any]]: |
|
|
"""Get random concepts, optionally ensuring diversity across categories.""" |
|
|
if diverse: |
|
|
selected = [] |
|
|
categories = list(CONCEPTS.keys()) |
|
|
random.shuffle(categories) |
|
|
|
|
|
for category in categories[:count]: |
|
|
concepts = CONCEPTS[category]["concepts"] |
|
|
concept = random.choice(concepts).copy() |
|
|
concept["category"] = CONCEPTS[category]["name"] |
|
|
concept["category_key"] = category |
|
|
selected.append(concept) |
|
|
|
|
|
return selected[:count] |
|
|
else: |
|
|
all_concepts = get_all_concepts() |
|
|
return random.sample(all_concepts, min(count, len(all_concepts))) |
|
|
|
|
|
|
|
|
|
|
|
TOP_CONCEPTS = [ |
|
|
"selfie_style", "problem_awareness", "side_by_side_table", |
|
|
"relatable_moment", "testimonial_screenshot" |
|
|
] |
|
|
|
|
|
|
|
|
def get_top_concepts() -> List[Dict[str, Any]]: |
|
|
"""Get top performing concepts for initial testing.""" |
|
|
return [get_concept_by_key(key) for key in TOP_CONCEPTS if get_concept_by_key(key)] |
|
|
|
|
|
|
|
|
def get_compatible_concepts(angle_trigger: str) -> List[Dict[str, Any]]: |
|
|
"""Get concepts compatible with a psychological trigger. |
|
|
Note: Visual layouts (before_after, split_screen, etc.) are now in visuals.py |
|
|
""" |
|
|
|
|
|
compatibility = { |
|
|
"Fear": ["shock_headline", "problem_awareness", "micro_story", "visual_tension"], |
|
|
"Relief": ["relief_moment", "success_moment", "turning_point", "emotional_snapshot"], |
|
|
"Greed": ["price_stack", "value_breakdown", "side_by_side_table", "ranking"], |
|
|
"FOMO": ["countdown_cta", "crowd", "community", "urgent"], |
|
|
"Social Proof": ["testimonial_screenshot", "real_customer", "crowd", "ugc_collage"], |
|
|
"Authority": ["expert_portrait", "badge_seal", "data_backed", "certification"], |
|
|
"Curiosity": ["shock_headline", "unexpected_image", "pattern_break", "bold_claim"], |
|
|
"Pride": ["success_moment", "winner_highlight", "milestone_moment"], |
|
|
"Convenience": ["three_step", "how_it_works", "simple_explainer"], |
|
|
"Trust": ["trust_signals", "badge_seal", "real_customer", "testimonial_screenshot"], |
|
|
} |
|
|
|
|
|
concept_keys = compatibility.get(angle_trigger, []) |
|
|
return [get_concept_by_key(key) for key in concept_keys if get_concept_by_key(key)] |
|
|
|
|
|
|