Seagle123 commited on
Commit
95d2a92
·
verified ·
1 Parent(s): 8bde6d1

Delete app.py

Browse files
Files changed (1) hide show
  1. app.py +0 -624
app.py DELETED
@@ -1,624 +0,0 @@
1
- """
2
- AUTOMATION 2 (UPGRADED) — Hugging Face Spaces App
3
- ==================================================
4
- Improvements over v1:
5
- ✓ LLM (GPT-4o-mini) called DIRECTLY from inside the app
6
- ✓ Richer interactive visualisations (radar chart, trend bars, gauge)
7
- ✓ Side-by-side metric comparison panel
8
- ✓ Session history tracker
9
- ✓ Automated pipeline trigger button (runs agentic_pipeline.py)
10
- ✓ Confidence intervals on predictions
11
- ✓ Better UX: loading states, cleaner layout, collapsible AI section
12
-
13
- Deploy on Hugging Face Spaces (SDK: Gradio).
14
- Set HF Secret: OPENAI_API_KEY
15
- """
16
-
17
- import os
18
- import json
19
- import time
20
- import subprocess
21
- import gradio as gr
22
- import pandas as pd
23
- import numpy as np
24
- import matplotlib
25
- matplotlib.use("Agg")
26
- import matplotlib.pyplot as plt
27
- import matplotlib.patches as mpatches
28
- import warnings
29
- warnings.filterwarnings("ignore")
30
-
31
- from sklearn.ensemble import RandomForestRegressor
32
- from sklearn.model_selection import train_test_split
33
- from vaderSentiment.vaderSentiment import SentimentIntensityAnalyzer
34
-
35
- try:
36
- import requests
37
- REQUESTS_OK = True
38
- except ImportError:
39
- REQUESTS_OK = False
40
-
41
- # ── CONFIG ──────────────────────────────────────────────────
42
- OPENAI_KEY = os.environ.get("OPENAI_API_KEY", "") # Set as HF Secret
43
- GPT_MODEL = "gpt-4o-mini"
44
-
45
- PALETTE = {
46
- "blue": "#2E86AB",
47
- "pink": "#A23B72",
48
- "amber": "#F18F01",
49
- "red": "#C73E1D",
50
- "teal": "#44BBA4",
51
- "light": "#F5F5F5",
52
- "dark": "#1A1A2E",
53
- }
54
-
55
- # ── STARTUP: TRAIN MODELS ───────────────────────────────────
56
- print("Loading data and training models on startup...")
57
-
58
- def _load_and_train_amazon():
59
- df = pd.read_csv("amazon_synthetic.csv")
60
- df["log_sales"] = np.log1p(df["rating_count"])
61
- features = ["actual_price", "discounted_price", "discount_pct", "rating", "sentiment_score"]
62
- X = df[features].dropna()
63
- y = df.loc[X.index, "log_sales"]
64
- rf = RandomForestRegressor(n_estimators=150, random_state=42)
65
- rf.fit(X, y)
66
- # Compute prediction std via individual trees for confidence interval
67
- return rf, features, df
68
-
69
- def _load_and_train_spotify():
70
- df = pd.read_csv("spotify_synthetic.csv")
71
- df["explicit"] = df["explicit"].astype(int)
72
- features = ["danceability", "energy", "loudness", "speechiness",
73
- "acousticness", "instrumentalness", "valence", "tempo", "explicit"]
74
- X = df[features].dropna()
75
- y = df.loc[X.index, "popularity"]
76
- rf = RandomForestRegressor(n_estimators=150, random_state=42)
77
- rf.fit(X, y)
78
- return rf, features, df
79
-
80
- try:
81
- rf_amz, features_amz, df_amz = _load_and_train_amazon()
82
- AMZ_OK = True
83
- print("✓ Amazon model ready")
84
- except Exception as e:
85
- AMZ_OK = False
86
- print(f"✗ Amazon model failed: {e}")
87
-
88
- try:
89
- rf_spot, features_spot, df_spot = _load_and_train_spotify()
90
- SPOT_OK = True
91
- print("✓ Spotify model ready")
92
- except Exception as e:
93
- SPOT_OK = False
94
- print(f"✗ Spotify model failed: {e}")
95
-
96
- analyzer = SentimentIntensityAnalyzer()
97
-
98
- # Session history
99
- session_history = []
100
-
101
-
102
- # ════════════════════════════════════════════════════════════
103
- # GPT HELPER — called directly from the app
104
- # ════════════════════════════════════════════════════════════
105
-
106
- def call_gpt_in_app(system_prompt: str, user_prompt: str, max_tokens=500) -> str:
107
- """
108
- Call GPT-4o-mini directly from within the Gradio app.
109
- Falls back to a template report if API key is not set.
110
- """
111
- if not OPENAI_KEY or not REQUESTS_OK:
112
- return None # will use fallback below
113
-
114
- headers = {
115
- "Authorization": f"Bearer {OPENAI_KEY}",
116
- "Content-Type": "application/json",
117
- }
118
- payload = {
119
- "model": GPT_MODEL,
120
- "messages": [
121
- {"role": "system", "content": system_prompt},
122
- {"role": "user", "content": user_prompt},
123
- ],
124
- "temperature": 0.4,
125
- "max_tokens": max_tokens,
126
- }
127
- try:
128
- r = requests.post(
129
- "https://api.openai.com/v1/chat/completions",
130
- headers=headers, json=payload, timeout=25
131
- )
132
- r.raise_for_status()
133
- return r.json()["choices"][0]["message"]["content"]
134
- except Exception as e:
135
- return f"[GPT unavailable: {e}]"
136
-
137
-
138
- def get_amazon_gpt_insight(category, actual_price, discounted_price, discount_pct,
139
- rating, sentiment_score, sentiment_label, sales_pred, score):
140
- system = (
141
- "You are a senior e-commerce performance analyst. Given Amazon product metrics, "
142
- "write a concise 4-section report: (1) Performance verdict in 1 sentence, "
143
- "(2) Pricing strategy assessment referencing the exact discount%, "
144
- "(3) Sentiment interpretation referencing the exact score, "
145
- "(4) Two specific, actionable recommendations. "
146
- "Be data-driven. Reference every number provided. Keep total response under 200 words."
147
- )
148
- user = (
149
- f"Category: {category} | Actual price: ₹{actual_price:.0f} | "
150
- f"Discounted price: ₹{discounted_price:.0f} | Discount: {discount_pct}% | "
151
- f"Rating: {rating}/5 | Sentiment score: {sentiment_score:.3f} ({sentiment_label}) | "
152
- f"Predicted rating count: ~{sales_pred:,} | Performance score: {score}/100"
153
- )
154
- result = call_gpt_in_app(system, user)
155
- if result and not result.startswith("[GPT"):
156
- return "🤖 AI Analysis (GPT-4o-mini)\n" + "─" * 36 + "\n" + result
157
- # Fallback
158
- return (
159
- "🤖 AI Analysis (template fallback — set OPENAI_API_KEY for live GPT)\n"
160
- + "─" * 36 + "\n"
161
- f"1. Performance: This {category} product scores {score}/100 — "
162
- f"{'strong' if score >= 75 else 'average' if score >= 45 else 'underperforming'}.\n"
163
- f"2. Pricing: A {discount_pct}% discount brings the price from ₹{actual_price:.0f} to "
164
- f"₹{discounted_price:.0f}. {'This aggressive discount may signal lower quality.' if discount_pct > 50 else 'Moderate discount maintains perceived value.'}\n"
165
- f"3. Sentiment: Score of {sentiment_score:.3f} is {sentiment_label}. "
166
- f"{'Strong reviews support organic growth.' if sentiment_label == 'Positive' else 'Negative sentiment risks algorithmic deprioritisation.'}\n"
167
- f"4. Recommendations:\n"
168
- f" • {'Leverage positive reviews in sponsored ads' if sentiment_label == 'Positive' else 'Address negative feedback within 48h'}\n"
169
- f" • {'Reduce discount to 20–30% to protect margin' if discount_pct > 50 else 'Maintain current pricing strategy'}"
170
- )
171
-
172
-
173
- def get_spotify_gpt_insight(genre, danceability, energy, loudness, tempo,
174
- valence, acousticness, pop_pred, tier):
175
- system = (
176
- "You are a music industry data analyst. Given Spotify audio features, "
177
- "write a concise 4-section report: (1) Commercial potential verdict in 1 sentence, "
178
- "(2) Audio profile assessment — is it radio-friendly? Reference exact feature values, "
179
- "(3) Genre fit analysis, "
180
- "(4) Two specific promotional or production recommendations. "
181
- "Be data-driven. Reference every number. Under 200 words total."
182
- )
183
- user = (
184
- f"Genre: {genre} | Popularity prediction: {pop_pred:.1f}/100 ({tier}) | "
185
- f"Danceability: {danceability:.2f} | Energy: {energy:.2f} | Loudness: {loudness:.1f} dB | "
186
- f"Tempo: {tempo:.0f} BPM | Valence: {valence:.2f} | Acousticness: {acousticness:.2f}"
187
- )
188
- result = call_gpt_in_app(system, user)
189
- if result and not result.startswith("[GPT"):
190
- return "🤖 AI Analysis (GPT-4o-mini)\n" + "─" * 36 + "\n" + result
191
- return (
192
- "🤖 AI Analysis (template fallback — set OPENAI_API_KEY for live GPT)\n"
193
- + "─" * 36 + "\n"
194
- f"1. Commercial potential: This {genre} track scores {pop_pred:.1f}/100 — {tier}.\n"
195
- f"2. Audio profile: Danceability {danceability:.2f} + energy {energy:.2f} at {loudness:.1f} dB. "
196
- f"{'Radio-friendly profile.' if danceability > 0.6 and energy > 0.6 else 'Niche profile — limited mainstream appeal.'}\n"
197
- f"3. Genre fit: {'Aligns with' if pop_pred >= 50 else 'Partially aligns with'} {genre} conventions.\n"
198
- f"4. Recommendations:\n"
199
- f" • {'Pitch to editorial playlists — strong commercial profile' if pop_pred >= 60 else 'Consider a remix to boost danceability'}\n"
200
- f" • {'Capitalize on high energy for live and sync licensing' if energy >= 0.7 else 'Explore streaming-first promotional strategy'}"
201
- )
202
-
203
-
204
- # ════════════════════════════════════════════════════════════
205
- # VISUALISATION HELPERS
206
- # ════════════════════════════════════════════════════════════
207
-
208
- def _radar_chart(labels, values, title, color):
209
- """Create a radar (spider) chart for audio features."""
210
- n = len(labels)
211
- angles = np.linspace(0, 2 * np.pi, n, endpoint=False).tolist()
212
- values_loop = values + [values[0]]
213
- angles += angles[:1]
214
-
215
- fig, ax = plt.subplots(figsize=(4.5, 4.5), subplot_kw={"polar": True})
216
- fig.patch.set_facecolor("#FAFAFA")
217
- ax.set_facecolor("#F0F4F8")
218
- ax.plot(angles, values_loop, color=color, linewidth=2)
219
- ax.fill(angles, values_loop, color=color, alpha=0.25)
220
- ax.set_xticks(angles[:-1])
221
- ax.set_xticklabels(labels, fontsize=9)
222
- ax.set_ylim(0, 1)
223
- ax.set_yticks([0.25, 0.5, 0.75])
224
- ax.set_yticklabels(["0.25", "0.50", "0.75"], fontsize=7, color="gray")
225
- ax.set_title(title, fontsize=11, fontweight="bold", pad=15)
226
- ax.grid(color="white", linewidth=0.8)
227
- plt.tight_layout()
228
- return fig
229
-
230
-
231
- def make_amazon_chart(rating, sentiment_score, discount_pct, score, sales_pred):
232
- import tempfile
233
- fig, axes = plt.subplots(1, 3, figsize=(14, 4.5))
234
- fig.patch.set_facecolor("#FAFAFA")
235
- fig.suptitle("Amazon Product — Performance Dashboard", fontsize=13, fontweight="bold", y=1.01)
236
-
237
- # Panel 1: Feature bars
238
- ax = axes[0]
239
- ax.set_facecolor("#F8F9FA")
240
- metrics = ["Rating (/5)", "Sentiment", "Discount (%/100)", "Score (/100)"]
241
- values = [rating / 5, (sentiment_score + 1) / 2, discount_pct / 100, score / 100]
242
- bar_cols = [PALETTE["blue"], PALETTE["teal"], PALETTE["amber"], PALETTE["pink"]]
243
- bars = ax.bar(metrics, values, color=bar_cols, edgecolor="white", width=0.6)
244
- ax.set_ylim(0, 1.15)
245
- ax.set_title("Key Metrics (normalised)", fontweight="bold")
246
- for bar, val in zip(bars, values):
247
- ax.text(bar.get_x() + bar.get_width() / 2, bar.get_height() + 0.025,
248
- f"{val:.2f}", ha="center", fontsize=10, fontweight="bold")
249
- ax.set_xticklabels(metrics, fontsize=9)
250
-
251
- # Panel 2: Gauge
252
- ax2 = axes[1]
253
- ax2.set_facecolor("#F8F9FA")
254
- tier_color = (PALETTE["teal"] if score >= 75 else
255
- PALETTE["amber"] if score >= 45 else PALETTE["red"])
256
- tier = "Top Performer" if score >= 75 else "Average" if score >= 45 else "Underperformer"
257
- wedge_colors = [tier_color, "#E8E8E8"]
258
- ax2.pie([score, 100 - score], colors=wedge_colors, startangle=90,
259
- wedgeprops={"edgecolor": "white", "linewidth": 2})
260
- ax2.text(0, 0, f"{score}", ha="center", va="center",
261
- fontsize=28, fontweight="bold", color=tier_color)
262
- ax2.set_title(f"Score: {tier}", fontweight="bold")
263
-
264
- # Panel 3: Est. rating count vs category benchmarks (synthetic)
265
- ax3 = axes[2]
266
- ax3.set_facecolor("#F8F9FA")
267
- benchmarks = {
268
- "This product": sales_pred,
269
- "Category avg": int(df_amz["rating_count"].mean()) if AMZ_OK else 15000,
270
- "Top 10%": int(df_amz["rating_count"].quantile(0.9)) if AMZ_OK else 50000,
271
- }
272
- bc = [PALETTE["pink"], PALETTE["blue"], PALETTE["blue"]]
273
- ax3.barh(list(benchmarks.keys()), list(benchmarks.values()),
274
- color=bc, edgecolor="white")
275
- ax3.set_title("Est. Sales vs Benchmarks", fontweight="bold")
276
- ax3.set_xlabel("Predicted Rating Count")
277
-
278
- plt.tight_layout()
279
- tmp = tempfile.NamedTemporaryFile(delete=False, suffix=".png")
280
- plt.savefig(tmp.name, dpi=130, bbox_inches="tight", facecolor="#FAFAFA")
281
- plt.close()
282
- return tmp.name
283
-
284
-
285
- def make_spotify_chart(danceability, energy, loudness, tempo, valence,
286
- acousticness, speechiness, pop_pred, genre):
287
- import tempfile
288
- fig = plt.figure(figsize=(14, 4.5))
289
- fig.patch.set_facecolor("#FAFAFA")
290
- fig.suptitle("Spotify Track — Audio Profile Dashboard", fontsize=13, fontweight="bold")
291
-
292
- # Panel 1: Radar
293
- ax1 = fig.add_subplot(1, 3, 1, polar=True)
294
- labels = ["Dance", "Energy", "Valence", "Acoust.", "Speech"]
295
- vals = [danceability, energy, valence, acousticness, speechiness]
296
- n = len(labels)
297
- angles = np.linspace(0, 2 * np.pi, n, endpoint=False).tolist()
298
- vals_loop = vals + [vals[0]]
299
- angles_loop = angles + angles[:1]
300
- ax1.plot(angles_loop, vals_loop, color=PALETTE["blue"], linewidth=2)
301
- ax1.fill(angles_loop, vals_loop, color=PALETTE["blue"], alpha=0.25)
302
- ax1.set_xticks(angles)
303
- ax1.set_xticklabels(labels, fontsize=9)
304
- ax1.set_ylim(0, 1)
305
- ax1.set_yticks([0.25, 0.5, 0.75])
306
- ax1.set_yticklabels(["", "", ""], fontsize=7)
307
- ax1.set_title("Audio Radar", fontweight="bold", pad=14)
308
- ax1.set_facecolor("#F0F4F8")
309
- ax1.grid(color="white")
310
-
311
- # Panel 2: Gauge
312
- ax2 = fig.add_subplot(1, 3, 2)
313
- ax2.set_facecolor("#F8F9FA")
314
- tier = ("Hit 🔥" if pop_pred >= 70 else "Popular" if pop_pred >= 50
315
- else "Mid-tier" if pop_pred >= 30 else "Niche")
316
- tier_color = (PALETTE["red"] if pop_pred >= 70 else
317
- PALETTE["teal"] if pop_pred >= 50 else
318
- PALETTE["amber"] if pop_pred >= 30 else "#888")
319
- ax2.pie([pop_pred, 100 - pop_pred], colors=[tier_color, "#E8E8E8"],
320
- startangle=90, wedgeprops={"edgecolor": "white", "linewidth": 2})
321
- ax2.text(0, 0, f"{pop_pred:.0f}", ha="center", va="center",
322
- fontsize=28, fontweight="bold", color=tier_color)
323
- ax2.set_title(f"Popularity: {tier}", fontweight="bold")
324
-
325
- # Panel 3: Feature importance comparison (from model)
326
- ax3 = fig.add_subplot(1, 3, 3)
327
- ax3.set_facecolor("#F8F9FA")
328
- if SPOT_OK:
329
- imp = pd.Series(rf_spot.feature_importances_, index=features_spot).sort_values()
330
- ax3.barh(imp.index, imp.values, color=PALETTE["blue"], edgecolor="white")
331
- ax3.set_title("Feature Importance\n(model weights)", fontweight="bold")
332
- ax3.set_xlabel("Importance")
333
- else:
334
- ax3.text(0.5, 0.5, "Model not loaded", ha="center")
335
-
336
- plt.tight_layout()
337
- tmp = tempfile.NamedTemporaryFile(delete=False, suffix=".png")
338
- plt.savefig(tmp.name, dpi=130, bbox_inches="tight", facecolor="#FAFAFA")
339
- plt.close()
340
- return tmp.name
341
-
342
-
343
- # ════════════════════════════════════════════════════════════
344
- # AMAZON ANALYSIS FUNCTION
345
- # ════════════════════════════════════════════════════════════
346
-
347
- def analyze_amazon(category, actual_price, discount_pct, rating, review_text, use_gpt):
348
- discounted_price = actual_price * (1 - discount_pct / 100)
349
- sentiment_score = analyzer.polarity_scores(review_text)["compound"] if review_text else 0.0
350
- sentiment_label = ("Positive" if sentiment_score >= 0.05
351
- else "Negative" if sentiment_score <= -0.05 else "Neutral")
352
-
353
- if AMZ_OK:
354
- X = np.array([[actual_price, discounted_price, discount_pct, rating, sentiment_score]])
355
- # Confidence interval via individual tree predictions
356
- tree_preds = np.array([t.predict(X)[0] for t in rf_amz.estimators_])
357
- log_pred = tree_preds.mean()
358
- log_std = tree_preds.std()
359
- sales_pred = int(np.expm1(log_pred))
360
- sales_low = int(np.expm1(max(0, log_pred - log_std)))
361
- sales_high = int(np.expm1(log_pred + log_std))
362
- else:
363
- sales_pred = int(rating * 1000 * (1 + sentiment_score))
364
- sales_low = int(sales_pred * 0.7)
365
- sales_high = int(sales_pred * 1.3)
366
-
367
- score = min(100, int(
368
- 25 * (rating / 5) +
369
- 25 * ((sentiment_score + 1) / 2) +
370
- 25 * min(sales_pred / 50000, 1) +
371
- 25 * min(discount_pct / 70, 1)
372
- ))
373
- tier = ("Top Performer" if score >= 75 else "Average" if score >= 45 else "Underperformer")
374
-
375
- # Chart
376
- chart_path = make_amazon_chart(rating, sentiment_score, discount_pct, score, sales_pred)
377
-
378
- # Text report
379
- report = (
380
- f"📦 AMAZON PRODUCT ANALYSIS\n{'═'*42}\n"
381
- f"Category: {category}\n"
382
- f"Actual Price: ₹{actual_price:.0f}\n"
383
- f"Discounted Price: ₹{discounted_price:.0f} (−{discount_pct}%)\n"
384
- f"Rating: {rating}/5\n"
385
- f"{'─'*42}\n"
386
- f"SENTIMENT\n"
387
- f" Score: {sentiment_score:+.3f} Label: {sentiment_label}\n"
388
- f"{'─'*42}\n"
389
- f"PREDICTED SALES\n"
390
- f" Est. Reviews: ~{sales_pred:,}\n"
391
- f" 90% Range: {sales_low:,} – {sales_high:,}\n"
392
- f"{'─'*42}\n"
393
- f"PERFORMANCE SCORE: {score}/100 ({tier})\n"
394
- )
395
-
396
- # GPT or fallback
397
- gpt_section = ""
398
- if use_gpt:
399
- gpt_section = "\n" + get_amazon_gpt_insight(
400
- category, actual_price, discounted_price, discount_pct,
401
- rating, sentiment_score, sentiment_label, sales_pred, score
402
- )
403
-
404
- session_history.append({
405
- "platform": "Amazon", "category": category,
406
- "score": score, "tier": tier,
407
- "timestamp": time.strftime("%H:%M:%S"),
408
- })
409
-
410
- return report.strip() + gpt_section, chart_path
411
-
412
-
413
- # ════════════════════════════════════════════════════════════
414
- # SPOTIFY ANALYSIS FUNCTION
415
- # ════════════════════════════════════════════════════════════
416
-
417
- def analyze_spotify(genre, danceability, energy, loudness, tempo, valence,
418
- acousticness, speechiness, instrumentalness, explicit, use_gpt):
419
- exp = int(explicit)
420
-
421
- if SPOT_OK:
422
- X = np.array([[danceability, energy, loudness, speechiness, acousticness,
423
- instrumentalness, valence, tempo, exp]])
424
- tree_preds = np.array([t.predict(X)[0] for t in rf_spot.estimators_])
425
- pop_pred = float(np.clip(tree_preds.mean(), 0, 100))
426
- pop_std = tree_preds.std()
427
- else:
428
- pop_pred = float(np.clip(20 + 30*danceability + 15*energy + 0.5*(loudness+20), 0, 100))
429
- pop_std = 5.0
430
-
431
- tier = ("Hit 🔥" if pop_pred >= 70 else "Popular" if pop_pred >= 50
432
- else "Mid-tier" if pop_pred >= 30 else "Niche")
433
- pop_low = max(0, pop_pred - pop_std)
434
- pop_high = min(100, pop_pred + pop_std)
435
-
436
- chart_path = make_spotify_chart(
437
- danceability, energy, loudness, tempo, valence,
438
- acousticness, speechiness, pop_pred, genre
439
- )
440
-
441
- report = (
442
- f"🎵 SPOTIFY TRACK ANALYSIS\n{'═'*42}\n"
443
- f"Genre: {genre}\n"
444
- f"Tempo: {tempo:.0f} BPM\n"
445
- f"Explicit: {'Yes' if explicit else 'No'}\n"
446
- f"{'─'*42}\n"
447
- f"AUDIO FEATURES\n"
448
- f" Danceability: {danceability:.3f}\n"
449
- f" Energy: {energy:.3f}\n"
450
- f" Loudness: {loudness:.1f} dB\n"
451
- f" Valence: {valence:.3f}\n"
452
- f" Acousticness: {acousticness:.3f}\n"
453
- f" Speechiness: {speechiness:.3f}\n"
454
- f"{'─'*42}\n"
455
- f"PREDICTED POPULARITY\n"
456
- f" Score: {pop_pred:.1f}/100 ({tier})\n"
457
- f" Range: {pop_low:.1f} – {pop_high:.1f} (±1 std dev)\n"
458
- )
459
-
460
- gpt_section = ""
461
- if use_gpt:
462
- gpt_section = "\n" + get_spotify_gpt_insight(
463
- genre, danceability, energy, loudness, tempo,
464
- valence, acousticness, pop_pred, tier
465
- )
466
-
467
- session_history.append({
468
- "platform": "Spotify", "genre": genre,
469
- "score": round(pop_pred, 1), "tier": tier,
470
- "timestamp": time.strftime("%H:%M:%S"),
471
- })
472
-
473
- return report.strip() + gpt_section, chart_path
474
-
475
-
476
- # ════════════════════════════════════════════════════════════
477
- # SESSION HISTORY & PIPELINE TRIGGER
478
- # ════════════════════════════════════════════════════════════
479
-
480
- def get_history():
481
- if not session_history:
482
- return "No analyses run yet this session."
483
- lines = [f"{'#':<4} {'Time':<10} {'Platform':<10} {'Detail':<25} {'Score':<8} {'Tier'}"]
484
- lines.append("─" * 70)
485
- for i, h in enumerate(session_history[-10:], 1):
486
- detail = h.get("category", h.get("genre", "—"))
487
- lines.append(f"{i:<4} {h['timestamp']:<10} {h['platform']:<10} {detail:<25} {h['score']:<8} {h['tier']}")
488
- return "\n".join(lines)
489
-
490
-
491
- def run_pipeline():
492
- """Trigger the agentic pipeline from the UI."""
493
- if not os.path.exists("agentic_pipeline.py"):
494
- return "agentic_pipeline.py not found in current directory."
495
- try:
496
- result = subprocess.run(
497
- ["python3", "agentic_pipeline.py", "--mode", "both", "--quiet"],
498
- capture_output=True, text=True, timeout=120
499
- )
500
- out = result.stdout[-2000:] if len(result.stdout) > 2000 else result.stdout
501
- if result.returncode == 0:
502
- return f"✓ Pipeline completed successfully.\n\n{out}"
503
- else:
504
- return f"✗ Pipeline error:\n{result.stderr[:1000]}"
505
- except subprocess.TimeoutExpired:
506
- return "✗ Pipeline timed out after 120s."
507
- except Exception as e:
508
- return f"✗ Could not run pipeline: {e}"
509
-
510
-
511
- # ════════════════════════════════════════════════════════════
512
- # GRADIO INTERFACE
513
- # ════════════════════════════════════════════════════════════
514
-
515
- CUSTOM_CSS = """
516
- .gr-button-primary { background: #2E86AB !important; border: none !important; }
517
- .gr-button-secondary { border: 1px solid #2E86AB !important; color: #2E86AB !important; }
518
- footer { display: none !important; }
519
- """
520
-
521
- with gr.Blocks(
522
- title="AI Performance Analyzer — Amazon × Spotify",
523
- theme=gr.themes.Soft(primary_hue="blue", secondary_hue="pink"),
524
- css=CUSTOM_CSS,
525
- ) as demo:
526
-
527
- gr.Markdown("""
528
- # 🤖 AI Performance Analyzer
529
- ### Amazon Products × Spotify Tracks
530
- *Real-time ML predictions + GPT-4o-mini insights from a single interface*
531
- """)
532
-
533
- with gr.Tabs():
534
-
535
- # ── TAB 1: AMAZON ────────────────────────────────────
536
- with gr.TabItem("🛒 Amazon Product"):
537
- gr.Markdown("### Predict product sales performance and get AI-powered strategy insights")
538
- with gr.Row():
539
- with gr.Column(scale=1):
540
- amz_category = gr.Dropdown(
541
- ["Electronics", "Clothing", "HomeKitchen", "Books",
542
- "Sports", "Beauty", "Toys", "OfficeProducts", "MusicalInstruments"],
543
- label="Product Category", value="Electronics")
544
- amz_actual = gr.Slider(50, 80000, value=999, step=50,
545
- label="Actual Price (₹)")
546
- amz_discount = gr.Slider(0, 80, value=30, step=1,
547
- label="Discount %")
548
- amz_rating = gr.Slider(1.0, 5.0, value=4.2, step=0.1,
549
- label="Star Rating (/5)")
550
- amz_review = gr.Textbox(
551
- label="Sample Review Text",
552
- value="Great product, works perfectly and arrived on time!",
553
- lines=3, placeholder="Enter a customer review for sentiment analysis...")
554
- amz_gpt = gr.Checkbox(label="🤖 Generate GPT-4o-mini AI insight", value=True)
555
- amz_btn = gr.Button("Analyze Product", variant="primary", size="lg")
556
-
557
- with gr.Column(scale=2):
558
- amz_output = gr.Textbox(label="Analysis Report", lines=22)
559
- amz_plot = gr.Image(label="Performance Dashboard", type="filepath")
560
-
561
- amz_btn.click(
562
- analyze_amazon,
563
- inputs=[amz_category, amz_actual, amz_discount, amz_rating, amz_review, amz_gpt],
564
- outputs=[amz_output, amz_plot],
565
- )
566
-
567
- # ── TAB 2: SPOTIFY ───────────────────────────────────
568
- with gr.TabItem("🎵 Spotify Track"):
569
- gr.Markdown("### Predict commercial success and get AI-powered music industry insights")
570
- with gr.Row():
571
- with gr.Column(scale=1):
572
- sp_genre = gr.Dropdown(
573
- ["pop", "hip-hop", "rock", "electronic", "jazz",
574
- "r-n-b", "country", "latin", "indie", "classical"],
575
- label="Genre", value="pop")
576
- sp_dance = gr.Slider(0.0, 1.0, value=0.70, step=0.01, label="Danceability")
577
- sp_energy = gr.Slider(0.0, 1.0, value=0.80, step=0.01, label="Energy")
578
- sp_loud = gr.Slider(-40, 0, value=-7, step=0.5, label="Loudness (dB)")
579
- sp_tempo = gr.Slider(60, 200, value=120, step=1, label="Tempo (BPM)")
580
- sp_val = gr.Slider(0.0, 1.0, value=0.60, step=0.01, label="Valence (mood positivity)")
581
- sp_acou = gr.Slider(0.0, 1.0, value=0.10, step=0.01, label="Acousticness")
582
- sp_speech = gr.Slider(0.0, 1.0, value=0.05, step=0.01, label="Speechiness")
583
- sp_instr = gr.Slider(0.0, 1.0, value=0.00, step=0.01, label="Instrumentalness")
584
- sp_exp = gr.Checkbox(label="Explicit content", value=False)
585
- sp_gpt = gr.Checkbox(label="🤖 Generate GPT-4o-mini AI insight", value=True)
586
- sp_btn = gr.Button("Analyze Track", variant="primary", size="lg")
587
-
588
- with gr.Column(scale=2):
589
- sp_output = gr.Textbox(label="Analysis Report", lines=22)
590
- sp_plot = gr.Image(label="Audio Profile Dashboard", type="filepath")
591
-
592
- sp_btn.click(
593
- analyze_spotify,
594
- inputs=[sp_genre, sp_dance, sp_energy, sp_loud, sp_tempo,
595
- sp_val, sp_acou, sp_speech, sp_instr, sp_exp, sp_gpt],
596
- outputs=[sp_output, sp_plot],
597
- )
598
-
599
- # ── TAB 3: SESSION HISTORY ───────────────────────────
600
- with gr.TabItem("📋 Session History"):
601
- gr.Markdown("### All analyses run this session")
602
- hist_output = gr.Textbox(label="Session Log", lines=15)
603
- hist_btn = gr.Button("Refresh History", variant="secondary")
604
- hist_btn.click(get_history, inputs=[], outputs=[hist_output])
605
-
606
- # ── TAB 4: PIPELINE ──────────────────────────────────
607
- with gr.TabItem("⚙️ Agentic Pipeline"):
608
- gr.Markdown("""
609
- ### Automated End-to-End Pipeline
610
- Runs the full agentic pipeline: data ingestion → synthetic generation →
611
- model training → inference → report generation. Single-command execution.
612
- """)
613
- pipe_btn = gr.Button("▶ Run Agentic Pipeline", variant="primary", size="lg")
614
- pipe_output = gr.Textbox(label="Pipeline Output", lines=20)
615
- pipe_btn.click(run_pipeline, inputs=[], outputs=[pipe_output])
616
-
617
- gr.Markdown("""
618
- ---
619
- *Built with Gradio · Models: Random Forest (sklearn) · NLP: VADER · AI: GPT-4o-mini*
620
- *Set `OPENAI_API_KEY` as a Hugging Face Secret to enable live GPT insights*
621
- """)
622
-
623
- if __name__ == "__main__":
624
- demo.launch(share=True)