ayanokoji13 commited on
Commit
b2e6bd9
Β·
verified Β·
1 Parent(s): 2466c1c

Upload 6 files

Browse files
Files changed (6) hide show
  1. Dockerfile +7 -0
  2. agent/__init__.py +0 -0
  3. agent/core.py +109 -0
  4. agent/personas.py +7 -0
  5. main.py +18 -0
  6. requirements.txt +6 -0
Dockerfile ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ FROM python:3.10-slim
2
+ WORKDIR /app
3
+ COPY requirements.txt .
4
+ RUN pip install --no-cache-dir -r requirements.txt
5
+ COPY . .
6
+ # Using 4 workers to handle multiple concurrent API requests
7
+ CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "7860", "--workers", "4"]
agent/__init__.py ADDED
File without changes
agent/core.py ADDED
@@ -0,0 +1,109 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import json
3
+ import random
4
+ import base64
5
+ from io import BytesIO
6
+ from PIL import Image
7
+ from groq import Groq
8
+ from .personas import PERSONAS
9
+
10
+ # The client will automatically use the GROQ_API_KEY environment variable
11
+ client = Groq()
12
+
13
+ def prep_image_bytes(image_bytes: bytes) -> str:
14
+ img = Image.open(BytesIO(image_bytes))
15
+ buffer = BytesIO()
16
+ img.save(buffer, format='PNG')
17
+ return f"data:image/png;base64,{base64.b64encode(buffer.getvalue()).decode()}"
18
+
19
+ def get_image_description(image_data: str) -> str:
20
+ prompt = """<|begin_of_text|><|start_header_id|>user<|end_header_id|>
21
+ Analyze this cosmetics ad image as Instagram post:
22
+ β€’ Product (serum/lipstick)?
23
+ β€’ Colors/lighting/vibe?
24
+ β€’ Text/CTAs?
25
+ β€’ Target audience/emotions?
26
+ β€’ Engagement hooks/weaknesses?
27
+ Concise bullet summary:<|eot_id|><|start_header_id|>assistant<|end_header_id|>"""
28
+
29
+ chat = client.chat.completions.create(
30
+ model="meta-llama/llama-3.2-90b-vision-preview", # Updated to a stable Groq vision model
31
+ messages=[
32
+ {"role": "user", "content": [
33
+ {"type": "text", "text": prompt},
34
+ {"type": "image_url", "image_url": {"url": image_data}}
35
+ ]}
36
+ ],
37
+ temperature=0.3,
38
+ max_tokens=250
39
+ )
40
+ return chat.choices[0].message.content.strip()
41
+
42
+ def simulate_user(image_desc: str, persona: dict) -> dict:
43
+ agent_prompt = f"""You are {persona['name']}, {persona['age']} {persona['gender']}, {persona['bias']}.
44
+ Instagram ad scroll: {image_desc}
45
+ **Think aloud** (1 sentence, your real reaction), THEN decide naturally:
46
+ - Reaction: love/like/wow/haha/neutral/angry (text names)
47
+ - Comment: AUTHENTIC Instagram - SHORT, slang/emojis/hashtags/varied! Cosmetics chat. null ok.
48
+ - Click shop?: true/false
49
+ Varied examples: "glowy af πŸ”₯", "pricey sis?", "need this asap πŸ’Έβœ¨", "#skincarejunkie"
50
+ JSON ONLY: {{"thought": "private", "reaction": "love/etc", "comment": "varied text or null", "click": true/false}}"""
51
+
52
+ chat = client.chat.completions.create(
53
+ model="llama-3.1-8b-instant", # Fast, stable model for rapid agent simulation
54
+ messages=[{"role": "user", "content": agent_prompt}],
55
+ temperature=1.0,
56
+ top_p=0.9,
57
+ max_tokens=100
58
+ )
59
+
60
+ try:
61
+ data = json.loads(chat.choices[0].message.content)
62
+ reaction_map = {"❀️": "love", "πŸ’™": "like", "😍": "love", "πŸ‘": "like", "πŸ˜‚": "haha", "πŸ€”": "wow", "😑": "angry"}
63
+ if data.get("reaction") in reaction_map:
64
+ data["reaction"] = reaction_map[data["reaction"]]
65
+ return data
66
+ except:
67
+ return {"reaction": "like", "comment": None, "click": False}
68
+
69
+ def run_simulation(image_bytes: bytes, num_users: int = 100, impressions: int = 10000) -> dict:
70
+ image_data = prep_image_bytes(image_bytes)
71
+ desc = get_image_description(image_data)
72
+
73
+ engagements = {
74
+ "post_id": f"sim_{random.randint(10000, 99999)}",
75
+ "ad_analysis": desc,
76
+ "insights": {
77
+ "impressions": impressions,
78
+ "reach": int(impressions * 0.7),
79
+ "likes": 0
80
+ },
81
+ "reactions": {"love": 0, "like": 0, "wow": 0, "haha": 0, "sorry": 0, "angry": 0},
82
+ "comments": [],
83
+ "clicks": 0
84
+ }
85
+
86
+ users_sample = random.choices(PERSONAS, k=num_users)
87
+ for persona in users_sample:
88
+ user_data = simulate_user(desc, persona)
89
+
90
+ if user_data.get("reaction") in engagements["reactions"]:
91
+ engagements["reactions"][user_data["reaction"]] += random.randint(1, 5)
92
+ engagements["insights"]["likes"] += 1
93
+
94
+ if user_data.get("comment"):
95
+ engagements["comments"].append({
96
+ "id": f"c_{random.randint(1,999)}",
97
+ "message": user_data["comment"],
98
+ "like_count": random.randint(0, 20)
99
+ })
100
+
101
+ if user_data.get("click"):
102
+ engagements["clicks"] += random.randint(1, 10)
103
+
104
+ engagements["insights"]["ctr"] = round((engagements["clicks"] / impressions) * 100, 2)
105
+ engagements["insights"]["engagement_rate"] = round((
106
+ sum(engagements["reactions"].values()) + len(engagements["comments"])
107
+ ) / impressions * 100, 2)
108
+
109
+ return engagements
agent/personas.py ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ PERSONAS = [
2
+ {"id": 1, "name": "GenZ_Influencer", "age": "18-24", "gender": "F", "bias": "trendy, emojis, hype", "engagement_bias": 0.8},
3
+ {"id": 2, "name": "Skeptical_Mom", "age": "30-45", "gender": "F", "bias": "practical, questions efficacy", "engagement_bias": 0.4},
4
+ {"id": 3, "name": "Luxury_Buyer", "age": "25-35", "gender": "F", "bias": "premium, aesthetics", "engagement_bias": 0.7},
5
+ {"id": 4, "name": "Casual_Shopper", "age": "20-30", "gender": "M", "bias": "simple, value", "engagement_bias": 0.5},
6
+ {"id": 5, "name": "Beauty_Nerd", "age": "22-28", "gender": "F", "bias": "ingredients, science", "engagement_bias": 0.6},
7
+ ]
main.py ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import FastAPI, UploadFile, File, Form
2
+ from agent.core import run_simulation
3
+
4
+ app = FastAPI(title="Ad Simulation API")
5
+
6
+ @app.get("/")
7
+ def home():
8
+ return {"message": "Ad Agent is running in the cloud!"}
9
+
10
+ @app.post("/simulate")
11
+ async def simulate(
12
+ file: UploadFile = File(...),
13
+ num_users: int = Form(20),
14
+ impressions: int = Form(1000)
15
+ ):
16
+ contents = await file.read()
17
+ results = run_simulation(contents, num_users=num_users, impressions=impressions)
18
+ return results
requirements.txt ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ fastapi
2
+ uvicorn
3
+ python-multipart
4
+ groq
5
+ pillow
6
+ pandas