saurav384 commited on
Commit
efdcedc
·
verified ·
1 Parent(s): 2006c2d

Upload 12 files

Browse files
app.py ADDED
@@ -0,0 +1,228 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import os
3
+ import warnings
4
+ from warnings import filterwarnings
5
+
6
+ # ---------- Services ----------
7
+ from services.zero_shot import classify_intent
8
+ from services.sentiment import detect_emotion
9
+ from services.similarity import text_quality_score
10
+ from services.cta_analysis import cta_strength
11
+ from services.copy_optimizer import optimize_copy
12
+ from services.meta_ads_api import fetch_live_ads
13
+
14
+ # ---------- Utils ----------
15
+ from utils.scoring import final_score
16
+ from utils.trend_analysis import market_trends
17
+
18
+
19
+ # ---------- Page Config ----------
20
+ st.set_page_config(
21
+ page_title="Meta AI Ads Intelligence Tool",
22
+ page_icon="📢",
23
+ layout="wide"
24
+ )
25
+
26
+ st.title("📢 Meta AI Ads Intelligence Tool")
27
+ st.caption("Live Meta Ads • Market Trends • AI Creative Analysis")
28
+
29
+
30
+ # ---------- Sidebar ----------
31
+ menu = st.sidebar.radio(
32
+ "Navigation",
33
+ [
34
+ "📊 Overview",
35
+ "🎯 Analyze My Ad",
36
+ "🧠 Live Competitor Ads",
37
+ "⚠️ Ad Fatigue Checker",
38
+ "✍️ Copy Optimizer",
39
+ "ℹ️ About"
40
+ ]
41
+ )
42
+
43
+
44
+ # =========================================================
45
+ # 📊 OVERVIEW
46
+ # =========================================================
47
+ if menu == "📊 Overview":
48
+ st.subheader("What does this tool do?")
49
+
50
+ st.write(
51
+ """
52
+ This platform combines **Meta Ads Library live data** with **pretrained AI models**
53
+ to analyze ad creatives, market trends, and competitor messaging — without using
54
+ any historical performance data.
55
+ """
56
+ )
57
+
58
+ col1, col2, col3 = st.columns(3)
59
+ col1.metric("Live Meta Ads", "Yes")
60
+ col2.metric("Model Training", "Not Required")
61
+ col3.metric("Analysis Type", "Real-Time")
62
+
63
+ st.info("🔒 No ads are stored. All analysis runs on demand.")
64
+
65
+
66
+ # =========================================================
67
+ # 🎯 ANALYZE USER AD
68
+ # =========================================================
69
+ elif menu == "🎯 Analyze My Ad":
70
+ st.subheader("Analyze Your Ad Creative")
71
+
72
+ col1, col2 = st.columns(2)
73
+
74
+ with col1:
75
+ caption = st.text_area("Ad Caption / Primary Text", height=150)
76
+ cta = st.selectbox(
77
+ "Call To Action",
78
+ ["Buy Now", "Shop Now", "Learn More", "DM Us", "Sign Up", "Check It Out"]
79
+ )
80
+ analyze = st.button("Analyze Ad")
81
+
82
+ with col2:
83
+ if analyze and caption.strip():
84
+ with st.spinner("Running AI analysis..."):
85
+ intent = classify_intent(caption)
86
+ emotion = detect_emotion(caption)
87
+ quality = text_quality_score(caption)
88
+ cta_score = cta_strength(cta)
89
+
90
+ score = final_score(
91
+ intent["score"],
92
+ emotion["score"],
93
+ cta_score,
94
+ quality
95
+ )
96
+
97
+ st.metric("Performance Score", f"{score}/100")
98
+
99
+ if score >= 75:
100
+ st.success("🟢 Low Risk – Ready to Run")
101
+ elif score >= 50:
102
+ st.warning("🟡 Medium Risk – Needs Optimization")
103
+ else:
104
+ st.error("🔴 High Risk – Likely Budget Waste")
105
+
106
+ st.progress(score / 100)
107
+
108
+ st.markdown("### 🔍 AI Insights")
109
+ st.write(f"**Intent:** {intent['label']}")
110
+ st.write(f"**Emotion:** {emotion['emotion']}")
111
+ st.write(f"**CTA Strength:** {round(cta_score * 100)}%")
112
+ st.write(f"**Text Quality:** {round(quality * 100)}%")
113
+
114
+
115
+ # =========================================================
116
+ # 🧠 LIVE COMPETITOR ADS (META ADS LIBRARY)
117
+ # =========================================================
118
+ elif menu == "🧠 Live Competitor Ads":
119
+ st.subheader("Live Competitor Ads (Meta Ads Library)")
120
+
121
+ keyword = st.text_input("Search Keyword / Brand / Product")
122
+ country = st.selectbox("Country", ["IN", "US", "UK", "AE"])
123
+
124
+ if st.button("Fetch Live Ads"):
125
+ try:
126
+ with st.spinner("Fetching live ads from Meta Ads Library..."):
127
+ ads = fetch_live_ads(keyword, country)
128
+
129
+ if not ads:
130
+ st.warning("No ads found for this keyword.")
131
+ else:
132
+ st.success(f"Fetched {len(ads)} live ads")
133
+
134
+ # ---------- Market Trends ----------
135
+ trends = market_trends(ads)
136
+
137
+ st.markdown("### 📊 Market Trend Analysis")
138
+ st.write("**Total Live Ads:**", trends["total_ads"])
139
+ st.write("**Trending Keywords:**", ", ".join(trends["top_keywords"]))
140
+
141
+ st.divider()
142
+
143
+ # ---------- Show Ads + AI Analysis ----------
144
+ for ad in ads[:5]:
145
+ st.markdown(f"### 🏷️ {ad['page_name']}")
146
+ st.write(ad["ad_creative_body"])
147
+
148
+ intent = classify_intent(ad["ad_creative_body"])
149
+ emotion = detect_emotion(ad["ad_creative_body"])
150
+
151
+ st.caption(
152
+ f"Intent: {intent['label']} | "
153
+ f"Emotion: {emotion['emotion']}"
154
+ )
155
+
156
+ st.divider()
157
+
158
+ except Exception as e:
159
+ st.error(f"Error fetching ads: {e}")
160
+
161
+
162
+ # =========================================================
163
+ # ⚠️ AD FATIGUE CHECKER
164
+ # =========================================================
165
+ elif menu == "⚠️ Ad Fatigue Checker":
166
+ st.subheader("Ad Fatigue Risk Estimator")
167
+
168
+ caption = st.text_area("Ad Caption", height=120)
169
+ days = st.slider("Planned Run Duration (Days)", 1, 30, 7)
170
+ frequency = st.slider("Estimated Frequency", 1.0, 5.0, 2.0)
171
+
172
+ if st.button("Check Fatigue"):
173
+ fatigue_risk = min((days * frequency) / 30, 1.0)
174
+
175
+ st.metric("Fatigue Risk", f"{round(fatigue_risk * 100)}%")
176
+ st.progress(fatigue_risk)
177
+
178
+ if fatigue_risk > 0.7:
179
+ st.error("High Fatigue Risk – Refresh Creative")
180
+ elif fatigue_risk > 0.4:
181
+ st.warning("Medium Risk – Monitor Performance")
182
+ else:
183
+ st.success("Low Risk – Safe to Run")
184
+
185
+
186
+ # =========================================================
187
+ # ✍️ COPY OPTIMIZER
188
+ # =========================================================
189
+ elif menu == "✍️ Copy Optimizer":
190
+ st.subheader("AI Copy Optimization")
191
+
192
+ caption = st.text_area("Original Caption", height=150)
193
+
194
+ if st.button("Get Suggestions") and caption.strip():
195
+ tips = optimize_copy(caption)
196
+
197
+ if tips:
198
+ st.markdown("### ✨ Optimization Suggestions")
199
+ for tip in tips:
200
+ st.write("•", tip)
201
+ else:
202
+ st.success("Your caption already follows best practices!")
203
+
204
+
205
+ # =========================================================
206
+ # ℹ️ ABOUT
207
+ # =========================================================
208
+ elif menu == "ℹ️ About":
209
+ st.subheader("About This Project")
210
+
211
+ st.write(
212
+ """
213
+ **Meta AI Ads Intelligence Tool** is a real-time marketing intelligence platform.
214
+
215
+ ### Key Capabilities
216
+ - Live Meta Ads Library integration
217
+ - Market trend analysis
218
+ - Zero-shot intent classification
219
+ - Emotion detection
220
+ - No model training or historical data
221
+
222
+ ### Tech Stack
223
+ - Python
224
+ - Streamlit
225
+ - HuggingFace Transformers
226
+ - Meta Ads Library API
227
+ """
228
+ )
projectstructure.txt ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ meta_ai_ads_tool/
2
+
3
+ ├── app.py
4
+
5
+ ├── services/
6
+ │ ├── meta_ads_api.py 👈 META API KEY USED HERE
7
+ │ ├── zero_shot.py
8
+ │ ├── sentiment.py
9
+ │ ├── similarity.py
10
+ │ ├── cta_analysis.py
11
+ │ └── copy_optimizer.py
12
+
13
+ ├── utils/
14
+ │ ├── scoring.py
15
+ │ └── trend_analysis.py 👈 MARKET TRENDS
16
+
17
+ └── requirements.txt
requirements.txt ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ streamlit==1.28.0
2
+ transformers==4.40.0
3
+ sentence-transformers==2.2.2
4
+ torch>=2.0.0
5
+ numpy>=1.24.0
6
+ requests>=2.31.0
7
+ scikit-learn>=1.3.0
8
+ pandas>=2.1.0
services/__pycache__/zero_shot.cpython-311.pyc ADDED
Binary file (1.54 kB). View file
 
services/copy_optimizer.py ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ def optimize_copy(ad_text: str):
2
+ """
3
+ Provides actionable suggestions to improve ad captions.
4
+ Rule-based, no training required.
5
+ """
6
+
7
+ if not ad_text or len(ad_text.strip()) == 0:
8
+ return ["Ad text is empty, please provide text."]
9
+
10
+ suggestions = []
11
+
12
+ # Suggest shortening long captions
13
+ word_count = len(ad_text.split())
14
+ if word_count > 20:
15
+ suggestions.append("Consider shortening the caption (under 20 words).")
16
+
17
+ # Add urgency if missing
18
+ urgency_words = ["now", "today", "limited", "hurry", "exclusive", "offer"]
19
+ if not any(word in ad_text.lower() for word in urgency_words):
20
+ suggestions.append("Add urgency words like 'now', 'limited', 'exclusive'.")
21
+
22
+ # Check for punctuation / excitement
23
+ if "!" not in ad_text:
24
+ suggestions.append("Add punctuation or exclamation marks for excitement.")
25
+
26
+ # Suggest including a CTA if missing
27
+ cta_words = ["buy", "shop", "order", "download", "register", "sign up"]
28
+ if not any(word in ad_text.lower() for word in cta_words):
29
+ suggestions.append("Include a clear call-to-action (CTA) in your caption.")
30
+
31
+ # Suggest adding emotional trigger words
32
+ emotional_words = ["amazing", "best", "incredible", "free", "surprise"]
33
+ if not any(word in ad_text.lower() for word in emotional_words):
34
+ suggestions.append("Consider adding emotional trigger words to attract attention.")
35
+
36
+ # If no suggestions, compliment the copy
37
+ if len(suggestions) == 0:
38
+ suggestions.append("Your caption follows best practices!")
39
+
40
+ return suggestions
services/cta_analysis.py ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import re
2
+
3
+ # High-performing CTA keywords (marketing proven)
4
+ STRONG_CTA = [
5
+ "buy now", "shop now", "order now", "get started",
6
+ "sign up", "register", "download now", "limited offer",
7
+ "claim now", "book now", "subscribe", "grab now"
8
+ ]
9
+
10
+ MEDIUM_CTA = [
11
+ "learn more", "discover", "find out", "see more",
12
+ "explore", "know more", "view details"
13
+ ]
14
+
15
+ WEAK_CTA = [
16
+ "click here", "visit us", "check this",
17
+ "read more", "watch now"
18
+ ]
19
+
20
+ def analyze_cta(ad_text: str):
21
+ """
22
+ Analyze CTA strength inside ad copy
23
+ Returns CTA score and insights
24
+ """
25
+
26
+ if not ad_text or len(ad_text.strip()) == 0:
27
+ return {"error": "Empty ad text"}
28
+
29
+ text = ad_text.lower()
30
+
31
+ found_strong = [cta for cta in STRONG_CTA if cta in text]
32
+ found_medium = [cta for cta in MEDIUM_CTA if cta in text]
33
+ found_weak = [cta for cta in WEAK_CTA if cta in text]
34
+
35
+ score = 0
36
+
37
+ # Scoring logic
38
+ score += len(found_strong) * 10
39
+ score += len(found_medium) * 5
40
+ score += len(found_weak) * 2
41
+
42
+ # Penalty if no CTA
43
+ if not (found_strong or found_medium or found_weak):
44
+ score -= 10
45
+
46
+ score = max(min(score, 100), 0)
47
+
48
+ return {
49
+ "cta_score": score,
50
+ "found_strong_cta": found_strong,
51
+ "found_medium_cta": found_medium,
52
+ "found_weak_cta": found_weak,
53
+ "has_cta": score > 0
54
+ }
services/meta_ads_api.py ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import requests
2
+ import os
3
+
4
+ META_ADS_TOKEN = os.getenv("EAAVtBlZBaes0BQZAfPSf7ZBO7Yv0WjULDVn3zZAwvgbdvCtU24x9MNG8rxGArSXDg4GFZBB3GBJOs5qblEU6BKCNx9GypIZAcneDRnuZBfkLYEWDZAMnzqblUUVNtPSjul792ZBuorTN36XHgqZCsOlFox4rsyYnw9Kjl2u244lfWsGZC4oCNIEwjslyljVryVXOY5W1LRiZAbnZCrMQ6GLdkkmKqJTkuLKKjrQxnPcnl7xCopI44nF1Moa3wtP1e61TQAoXc1UvdkEvllaJg7ircBzwYpILl")
5
+ BASE_URL = "https://www.facebook.com/ads/library/?active_status=all&ad_type=political_and_issue_ads&country=IN&is_targeted_country=false&media_type=all"
6
+
7
+ def fetch_live_ads(keyword, country="IN", limit=20):
8
+ if not META_ADS_TOKEN:
9
+ raise ValueError("META_ADS_TOKEN not set")
10
+
11
+ params = {
12
+ "search_terms": keyword,
13
+ "ad_reached_countries": country,
14
+ "ad_type": "ALL",
15
+ "fields": (
16
+ "page_name,"
17
+ "ad_creative_body,"
18
+ "ad_creative_link_title,"
19
+ "ad_delivery_start_time"
20
+ ),
21
+ "limit": limit,
22
+ "access_token": META_ADS_TOKEN
23
+ }
24
+
25
+ response = requests.get(BASE_URL, params=params)
26
+ response.raise_for_status()
27
+
28
+ ads = response.json().get("data", [])
29
+ return [ad for ad in ads if ad.get("ad_creative_body")]
services/sentiment.py ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from transformers import pipeline
2
+
3
+ # Pretrained emotion detection model
4
+ # No training required
5
+ emotion_classifier = pipeline(
6
+ task="text-classification",
7
+ model="j-hartmann/emotion-english-distilroberta-base",
8
+ return_all_scores=True
9
+ )
10
+
11
+ def analyze_emotion(ad_text: str):
12
+ """
13
+ Analyze emotional tone of an ad caption
14
+ Returns emotion scores
15
+ """
16
+
17
+ if not ad_text or len(ad_text.strip()) == 0:
18
+ return {"error": "Empty ad text"}
19
+
20
+ result = emotion_classifier(ad_text)[0]
21
+
22
+ emotions = []
23
+ for item in result:
24
+ emotions.append({
25
+ "emotion": item["label"],
26
+ "confidence": round(item["score"], 3)
27
+ })
28
+
29
+ # Sort by highest confidence
30
+ emotions = sorted(emotions, key=lambda x: x["confidence"], reverse=True)
31
+
32
+ return {
33
+ "ad_text": ad_text,
34
+ "emotions": emotions
35
+ }
services/similarity.py ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from sentence_transformers import SentenceTransformer, util
2
+
3
+ # Pretrained embedding model (NO training needed)
4
+ model = SentenceTransformer("all-MiniLM-L6-v2")
5
+
6
+ def compute_similarity(base_ad: str, competitor_ads: list):
7
+ """
8
+ Compare one ad caption with multiple competitor ads
9
+ Returns similarity scores
10
+ """
11
+
12
+ if not base_ad or not competitor_ads:
13
+ return {"error": "Base ad or competitor ads missing"}
14
+
15
+ # Encode base ad
16
+ base_embedding = model.encode(base_ad, convert_to_tensor=True)
17
+
18
+ results = []
19
+
20
+ for ad in competitor_ads:
21
+ competitor_embedding = model.encode(ad, convert_to_tensor=True)
22
+
23
+ score = util.cos_sim(base_embedding, competitor_embedding).item()
24
+
25
+ results.append({
26
+ "competitor_ad": ad,
27
+ "similarity_score": round(score * 100, 2) # percentage
28
+ })
29
+
30
+ # Sort highest similarity first
31
+ results = sorted(results, key=lambda x: x["similarity_score"], reverse=True)
32
+
33
+ return {
34
+ "base_ad": base_ad,
35
+ "comparisons": results
36
+ }
services/zero_shot.py ADDED
@@ -0,0 +1,49 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from transformers import pipeline
2
+
3
+ # Load pretrained Zero-Shot Classification model
4
+ # This model is already trained — NO custom data required
5
+ classifier = pipeline(
6
+ task="zero-shot-classification",
7
+ model="facebook/bart-large-mnli"
8
+ )
9
+
10
+ # Marketing / Ads-specific labels
11
+ DEFAULT_LABELS = [
12
+ "Brand Awareness",
13
+ "Lead Generation",
14
+ "Sales Promotion",
15
+ "Product Launch",
16
+ "Discount Offer",
17
+ "Emotional Appeal",
18
+ "Urgency Driven",
19
+ "Trust Building",
20
+ "Social Proof",
21
+ "Call To Action Focused"
22
+ ]
23
+
24
+ def analyze_ad_intent(ad_text: str, labels: list = DEFAULT_LABELS):
25
+ """
26
+ Analyze ad caption text using Zero-Shot Learning
27
+ Returns intent labels with confidence scores
28
+ """
29
+
30
+ if not ad_text or len(ad_text.strip()) == 0:
31
+ return {"error": "Empty ad text"}
32
+
33
+ result = classifier(
34
+ sequences=ad_text,
35
+ candidate_labels=labels,
36
+ multi_label=True
37
+ )
38
+
39
+ response = []
40
+ for label, score in zip(result["labels"], result["scores"]):
41
+ response.append({
42
+ "label": label,
43
+ "confidence": round(score, 3)
44
+ })
45
+
46
+ return {
47
+ "ad_text": ad_text,
48
+ "analysis": response
49
+ }
utils/scoring.py ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ def final_score(
2
+ intent_score: float = 0,
3
+ emotion_score: float = 0,
4
+ cta_score: float = 0,
5
+ text_quality_score: float = 0,
6
+ similarity_score: float = None
7
+ ) -> int:
8
+ """
9
+ Compute final Ad Performance Score (0-100)
10
+ Scores are expected between 0 and 1 (or 0-100 if already scaled)
11
+ similarity_score is optional (0-100)
12
+ """
13
+
14
+ # Scale 0-1 inputs to 0-100
15
+ intent_score = intent_score * 100 if intent_score <= 1 else intent_score
16
+ emotion_score = emotion_score * 100 if emotion_score <= 1 else emotion_score
17
+ cta_score = cta_score * 100 if cta_score <= 1 else cta_score
18
+ text_quality_score = text_quality_score * 100 if text_quality_score <= 1 else text_quality_score
19
+
20
+ # Weighted scoring (adjustable)
21
+ weights = {
22
+ "intent": 0.3,
23
+ "emotion": 0.25,
24
+ "cta": 0.2,
25
+ "text_quality": 0.15,
26
+ "similarity": 0.1
27
+ }
28
+
29
+ total_score = (
30
+ intent_score * weights["intent"] +
31
+ emotion_score * weights["emotion"] +
32
+ cta_score * weights["cta"] +
33
+ text_quality_score * weights["text_quality"]
34
+ )
35
+
36
+ # Include similarity if available
37
+ if similarity_score is not None:
38
+ total_score += similarity_score * weights["similarity"]
39
+
40
+ # Clamp between 0-100
41
+ total_score = max(min(total_score, 100), 0)
42
+
43
+ return round(total_score)
utils/trend_analysis.py ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from collections import Counter
2
+ import re
3
+
4
+ def extract_keywords(texts):
5
+ words = []
6
+ for t in texts:
7
+ clean = re.sub(r"[^a-zA-Z ]", "", t.lower())
8
+ words.extend(clean.split())
9
+ return Counter(words)
10
+
11
+ def market_trends(ads):
12
+ texts = [ad["ad_creative_body"] for ad in ads]
13
+
14
+ keyword_freq = extract_keywords(texts)
15
+
16
+ top_keywords = [
17
+ word for word, count in keyword_freq.items()
18
+ if count > 2 and len(word) > 3
19
+ ][:10]
20
+
21
+ return {
22
+ "total_ads": len(ads),
23
+ "top_keywords": top_keywords
24
+ }