GuglielmoTor commited on
Commit
fd85262
·
verified ·
1 Parent(s): 9d57af8

Delete analytics_fetch_and_rendering.py

Browse files
Files changed (1) hide show
  1. analytics_fetch_and_rendering.py +0 -421
analytics_fetch_and_rendering.py DELETED
@@ -1,421 +0,0 @@
1
- import json
2
- import requests
3
- from datetime import datetime, timezone, timedelta
4
- import matplotlib.pyplot as plt
5
- import gradio as gr
6
- import traceback
7
- import html
8
-
9
- from sessions import create_session
10
- from error_handling import display_error
11
-
12
- from Data_Fetching_and_Rendering import fetch_posts_and_stats
13
- from mentions_dashboard import generate_mentions_dashboard
14
-
15
- import logging
16
-
17
- logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(levelname)s - %(message)s')
18
-
19
- API_V2_BASE = 'https://api.linkedin.com/v2'
20
- API_REST_BASE = 'https://api.linkedin.com/rest'
21
-
22
- def extract_follower_gains(data):
23
- elements = data.get("elements", [])
24
- if not elements:
25
- return []
26
-
27
- results = []
28
- for item in elements:
29
- start_timestamp = item.get("timeRange", {}).get("start")
30
- if not start_timestamp:
31
- continue
32
-
33
- try:
34
- date_str = datetime.fromtimestamp(start_timestamp / 1000, tz=timezone.utc).strftime('%Y-%m')
35
- except Exception:
36
- continue
37
-
38
- gains = item.get("followerGains", {})
39
- results.append({
40
- "date": date_str,
41
- "organic": gains.get("organicFollowerGain", 0) or 0,
42
- "paid": gains.get("paidFollowerGain", 0) or 0
43
- })
44
-
45
- return sorted(results, key=lambda x: x['date'])
46
-
47
- def fetch_analytics_data(client_id, token):
48
- if not token:
49
- raise ValueError("comm_token is missing.")
50
-
51
- token_dict = token if isinstance(token, dict) else {'access_token': token, 'token_type': 'Bearer'}
52
- session = create_session(client_id, token=token_dict)
53
-
54
- try:
55
- org_urn, org_name = "urn:li:organization:19010008", "GRLS"
56
-
57
- count_url = f"{API_V2_BASE}/networkSizes/{org_urn}?edgeType=CompanyFollowedByMember"
58
- follower_count = session.get(count_url).json().get("firstDegreeSize", 0)
59
-
60
- start = datetime.now(timezone.utc) - timedelta(days=365)
61
- start = start.replace(day=1, hour=0, minute=0, second=0, microsecond=0)
62
- start_ms = int(start.timestamp() * 1000)
63
-
64
- gains_url = (
65
- f"{API_REST_BASE}/organizationalEntityFollowerStatistics"
66
- f"?q=organizationalEntity&organizationalEntity={org_urn}"
67
- f"&timeIntervals.timeGranularityType=MONTH"
68
- f"&timeIntervals.timeRange.start={start_ms}"
69
- )
70
- gains_data = session.get(gains_url).json()
71
- gains = extract_follower_gains(gains_data)
72
-
73
- return org_name, follower_count, gains
74
-
75
- except requests.exceptions.RequestException as e:
76
- status = getattr(e.response, 'status_code', 'N/A')
77
- msg = f"Failed to fetch LinkedIn analytics (Status: {status})."
78
- raise ValueError(msg) from e
79
- except Exception as e:
80
- raise ValueError("Unexpected error during LinkedIn analytics fetch.") from e
81
-
82
- def plot_follower_gains(data):
83
- plt.style.use('seaborn-v0_8-whitegrid')
84
-
85
- if not data:
86
- fig, ax = plt.subplots(figsize=(10, 5))
87
- ax.text(0.5, 0.5, 'No follower gains data.', ha='center', va='center', transform=ax.transAxes)
88
- ax.set_title('Monthly Follower Gains')
89
- ax.set_xticks([]); ax.set_yticks([])
90
- return fig
91
-
92
- dates = [d['date'] for d in data]
93
- organic = [d['organic'] for d in data]
94
- paid = [d['paid'] for d in data]
95
-
96
- fig, ax = plt.subplots(figsize=(12, 6))
97
- ax.plot(dates, organic, label='Organic', marker='o', color='#0073b1')
98
- ax.plot(dates, paid, label='Paid', marker='x', linestyle='--', color='#d9534f')
99
- ax.set(title='Monthly Follower Gains', xlabel='Month', ylabel='New Followers')
100
- ax.tick_params(axis='x', rotation=45)
101
- ax.legend()
102
- plt.tight_layout()
103
- return fig
104
-
105
- def plot_growth_rate(data, total):
106
- if not data:
107
- fig, ax = plt.subplots(figsize=(10, 5))
108
- ax.text(0.5, 0.5, 'No data for growth rate.', ha='center', va='center', transform=ax.transAxes)
109
- ax.set_title('Growth Rate (%)')
110
- ax.set_xticks([]); ax.set_yticks([])
111
- return fig
112
-
113
- dates = [d['date'] for d in data]
114
- gains = [d['organic'] + d['paid'] for d in data]
115
-
116
- history = []
117
- current = total
118
- for g in reversed(gains):
119
- history.insert(0, current)
120
- current -= g
121
-
122
- rates = [((history[i] - history[i-1]) / history[i-1] * 100 if history[i-1] else 0) for i in range(1, len(history))]
123
-
124
- fig, ax = plt.subplots(figsize=(12, 6))
125
- ax.plot(dates[1:], rates, label='Growth Rate (%)', marker='o', color='green')
126
- ax.set(title='Monthly Growth Rate (%)', xlabel='Month', ylabel='Growth %')
127
- ax.tick_params(axis='x', rotation=45)
128
- ax.legend()
129
- plt.tight_layout()
130
- return fig
131
-
132
- def compute_monthly_avg_engagement_rate(posts):
133
- from collections import defaultdict
134
- import statistics
135
-
136
- if not posts:
137
- return []
138
-
139
- monthly_data = defaultdict(lambda: {"engagement_sum": 0, "post_count": 0, "impression_total": 0})
140
-
141
- for post in posts:
142
- try:
143
- month = post["when"][:7] # Format: YYYY-MM
144
- likes = post.get("likes", 0)
145
- comments = post.get("comments", 0)
146
- shares = post.get("shares", 0)
147
- clicks = post.get("clicks", 0)
148
- impressions = post.get("impressions", 0)
149
-
150
- engagement = likes + comments + shares + clicks
151
- monthly_data[month]["engagement_sum"] += engagement
152
- monthly_data[month]["post_count"] += 1
153
- monthly_data[month]["impression_total"] += impressions
154
- except Exception:
155
- continue
156
-
157
- results = []
158
- for month in sorted(monthly_data.keys()):
159
- data = monthly_data[month]
160
- if data["post_count"] == 0 or data["impression_total"] == 0:
161
- rate = 0
162
- else:
163
- avg_impressions = data["impression_total"] / data["post_count"]
164
- rate = (data["engagement_sum"] / (data["post_count"] * avg_impressions)) * 100
165
- results.append({"month": month, "engagement_rate": round(rate, 2)})
166
-
167
- return results
168
-
169
- def plot_avg_engagement_rate(data):
170
- import matplotlib.pyplot as plt
171
-
172
- if not data:
173
- fig, ax = plt.subplots(figsize=(10, 5))
174
- ax.text(0.5, 0.5, 'No engagement data.', ha='center', va='center', transform=ax.transAxes)
175
- ax.set_title('Average Post Engagement Rate (%)')
176
- ax.set_xticks([]); ax.set_yticks([])
177
- return fig
178
-
179
- months = [d["month"] for d in data]
180
- rates = [d["engagement_rate"] for d in data]
181
-
182
- fig, ax = plt.subplots(figsize=(12, 6))
183
- ax.plot(months, rates, label="Engagement Rate (%)", marker="s", color="#ff7f0e")
184
- ax.set(title="Average Post Engagement Rate (%)", xlabel="Month", ylabel="Engagement Rate %")
185
- ax.tick_params(axis='x', rotation=45)
186
- ax.legend()
187
- plt.tight_layout()
188
- return fig
189
-
190
- def compute_post_interaction_metrics(posts):
191
- from collections import defaultdict
192
-
193
- if not posts:
194
- return []
195
-
196
- monthly_stats = defaultdict(lambda: {
197
- "comments": 0,
198
- "shares": 0,
199
- "clicks": 0,
200
- "likes": 0,
201
- "posts": 0
202
- })
203
-
204
- for post in posts:
205
- try:
206
- month = post["when"][:7] # YYYY-MM
207
- monthly_stats[month]["comments"] += post.get("comments", 0)
208
- monthly_stats[month]["shares"] += post.get("shares", 0)
209
- monthly_stats[month]["clicks"] += post.get("clicks", 0)
210
- monthly_stats[month]["likes"] += post.get("likes", 0)
211
- monthly_stats[month]["posts"] += 1
212
- except Exception:
213
- continue
214
-
215
- results = []
216
- for month in sorted(monthly_stats.keys()):
217
- stats = monthly_stats[month]
218
- total_engagement = stats["comments"] + stats["shares"] + stats["clicks"] + stats["likes"]
219
- posts_count = stats["posts"] or 1 # Avoid division by zero
220
-
221
- results.append({
222
- "month": month,
223
- "comments_per_post": round(stats["comments"] / posts_count, 2),
224
- "shares_per_post": round(stats["shares"] / posts_count, 2),
225
- "clicks_per_post": round(stats["clicks"] / posts_count, 2),
226
- "comment_share_of_engagement": round((stats["comments"] / total_engagement) * 100 if total_engagement else 0, 2)
227
- })
228
- logging.info(f"this are the inter<ction results {results}")
229
- return results
230
-
231
- def plot_interaction_metrics(data):
232
- if not data:
233
- fig, ax = plt.subplots(figsize=(10, 5))
234
- ax.text(0.5, 0.5, 'No interaction data.', ha='center', va='center', transform=ax.transAxes)
235
- ax.set_title('Post Interaction Metrics')
236
- ax.set_xticks([]); ax.set_yticks([])
237
- return fig
238
-
239
- months = [d["month"] for d in data]
240
- comments_pp = [d["comments_per_post"] for d in data]
241
- shares_pp = [d["shares_per_post"] for d in data]
242
- clicks_pp = [d["clicks_per_post"] for d in data]
243
- comment_share = [d["comment_share_of_engagement"] for d in data]
244
-
245
- fig, axes = plt.subplots(nrows=4, ncols=1, figsize=(12, 10), sharex=True)
246
- fig.suptitle("Post Interaction Metrics", fontsize=16)
247
-
248
- axes[0].plot(months, comments_pp, marker="o", color="#1f77b4")
249
- axes[0].set_ylabel("Comments/Post")
250
- axes[0].grid(True)
251
-
252
- axes[1].plot(months, shares_pp, marker="s", color="#ff7f0e")
253
- axes[1].set_ylabel("Shares/Post")
254
- axes[1].grid(True)
255
-
256
- axes[2].plot(months, clicks_pp, marker="^", color="#2ca02c")
257
- axes[2].set_ylabel("Clicks/Post")
258
- axes[2].grid(True)
259
-
260
- axes[3].plot(months, comment_share, marker="x", linestyle="--", color="#d62728")
261
- axes[3].set_ylabel("Comment Share (%)")
262
- axes[3].set_xlabel("Month")
263
- axes[3].grid(True)
264
-
265
- plt.xticks(rotation=45)
266
- plt.tight_layout(rect=[0, 0, 1, 0.96]) # Leave space for suptitle
267
- return fig
268
-
269
- from collections import defaultdict
270
- import matplotlib.pyplot as plt
271
-
272
- def compute_eb_content_ratio(posts):
273
- if not posts:
274
- return []
275
-
276
- monthly_counts = defaultdict(lambda: {"eb_count": 0, "total": 0})
277
-
278
- for post in posts:
279
- try:
280
- month = post["when"][:7] # YYYY-MM
281
- category = post.get("category", "None")
282
- monthly_counts[month]["total"] += 1
283
- if category and category.strip() != "None":
284
- monthly_counts[month]["eb_count"] += 1
285
- except Exception:
286
- continue
287
-
288
- results = []
289
- for month in sorted(monthly_counts.keys()):
290
- data = monthly_counts[month]
291
- ratio = (data["eb_count"] / data["total"]) * 100 if data["total"] else 0
292
- results.append({"month": month, "eb_ratio": round(ratio, 2)})
293
-
294
- return results
295
-
296
- def plot_eb_content_ratio(data):
297
- if not data:
298
- fig, ax = plt.subplots(figsize=(10, 5))
299
- ax.text(0.5, 0.5, 'No EB content data.', ha='center', va='center', transform=ax.transAxes)
300
- ax.set_title('EB Content Ratio (%)')
301
- ax.set_xticks([]); ax.set_yticks([])
302
- return fig
303
-
304
- months = [d["month"] for d in data]
305
- ratios = [d["eb_ratio"] for d in data]
306
-
307
- fig, ax = plt.subplots(figsize=(12, 6))
308
- ax.plot(months, ratios, label="EB Content Ratio (%)", marker="o", color="#2ca02c")
309
- ax.set(title="Monthly EB Content Ratio (%)", xlabel="Month", ylabel="EB Content %")
310
- ax.tick_params(axis='x', rotation=45)
311
- ax.legend()
312
- plt.tight_layout()
313
- return fig
314
-
315
- def compute_mention_metrics(mention_data):
316
- if not mention_data:
317
- return [], []
318
-
319
- monthly_stats = defaultdict(lambda: {"positive": 0, "negative": 0, "neutral": 0, "total": 0})
320
-
321
- for m in mention_data:
322
- month = m["date"].strftime("%Y-%m")
323
- sentiment = m["sentiment"]
324
- monthly_stats[month]["total"] += 1
325
- if "Positive" in sentiment:
326
- monthly_stats[month]["positive"] += 1
327
- elif "Negative" in sentiment:
328
- monthly_stats[month]["negative"] += 1
329
- elif "Neutral" in sentiment:
330
- monthly_stats[month]["neutral"] += 1
331
-
332
- volume_data = []
333
- sentiment_data = []
334
- sorted_months = sorted(monthly_stats.keys())
335
-
336
- for i, month in enumerate(sorted_months):
337
- stats = monthly_stats[month]
338
- positive = stats["positive"]
339
- negative = stats["negative"]
340
- total = stats["total"]
341
-
342
- sentiment_score = ((positive / total) * 100 - (negative / total) * 100) if total else 0
343
- sentiment_ratio = (positive / negative) if negative else float('inf')
344
-
345
- sentiment_data.append({
346
- "month": month,
347
- "score": round(sentiment_score, 2),
348
- "ratio": round(sentiment_ratio, 2) if sentiment_ratio != float('inf') else None
349
- })
350
-
351
- prev_total = monthly_stats[sorted_months[i - 1]]["total"] if i > 0 else 0
352
- change = (((total - prev_total) / prev_total) * 100) if prev_total else None
353
- volume_data.append({"month": month, "count": total, "change": round(change, 2) if change is not None else None})
354
-
355
- return volume_data, sentiment_data
356
-
357
- def plot_mention_volume_trend(volume_data):
358
- fig, ax = plt.subplots(figsize=(12, 6))
359
- if not volume_data:
360
- ax.text(0.5, 0.5, 'No Mention Volume Data.', ha='center', va='center', transform=ax.transAxes)
361
- ax.set_title('Mention Volume Over Time')
362
- return fig
363
-
364
- months = [d["month"] for d in volume_data]
365
- counts = [d["count"] for d in volume_data]
366
- ax.plot(months, counts, marker='o', linestyle='-', color="#1f77b4")
367
- ax.set(title="Monthly Mention Volume", xlabel="Month", ylabel="Mentions")
368
- ax.tick_params(axis='x', rotation=45)
369
- plt.tight_layout()
370
- return fig
371
-
372
- def plot_mention_sentiment_score(sentiment_data):
373
- fig, ax = plt.subplots(figsize=(12, 6))
374
- if not sentiment_data:
375
- ax.text(0.5, 0.5, 'No Sentiment Score Data.', ha='center', va='center', transform=ax.transAxes)
376
- ax.set_title('Mention Sentiment Score')
377
- return fig
378
-
379
- months = [d["month"] for d in sentiment_data]
380
- scores = [d["score"] for d in sentiment_data]
381
- ax.plot(months, scores, marker='o', linestyle='-', color="#ff7f0e")
382
- ax.set(title="Monthly Sentiment Score (% Positive - % Negative)", xlabel="Month", ylabel="Score")
383
- ax.axhline(0, color='gray', linestyle='--', linewidth=1)
384
- ax.tick_params(axis='x', rotation=45)
385
- plt.tight_layout()
386
- return fig
387
-
388
-
389
- def fetch_and_render_analytics(client_id, token):
390
- loading = gr.update(value="<p>Loading follower count...</p>", visible=True)
391
- hidden = gr.update(value=None, visible=False)
392
-
393
- if not token:
394
- error = "<p style='color:red;'>❌ Missing token. Please log in.</p>"
395
- return gr.update(value=error, visible=True), hidden, hidden
396
-
397
- try:
398
- name, count, gains = fetch_analytics_data(client_id, token)
399
- posts, org_name, sentiments = fetch_posts_and_stats(client_id, token, count=30)
400
- engagement_data = compute_monthly_avg_engagement_rate(posts)
401
- interaction_data = compute_post_interaction_metrics(posts)
402
- eb_data = compute_eb_content_ratio(posts)
403
- html_mentions, fig, mention_data = generate_mentions_dashboard(client_id, token)
404
- volume_data, sentiment_data = compute_mention_metrics(mention_data)
405
-
406
-
407
-
408
-
409
- count_html = f"""
410
- <div style='text-align:center; padding:20px; background:#e7f3ff; border:1px solid #bce8f1; border-radius:8px;'>
411
- <p style='font-size:1.1em; color:#31708f;'>Total Followers for</p>
412
- <p style='font-size:1.4em; font-weight:bold; color:#005a9e;'>{html.escape(name)}</p>
413
- <p style='font-size:2.8em; font-weight:bold; color:#0073b1;'>{count:,}</p>
414
- <p style='font-size:0.9em; color:#777;'>(As of latest data)</p>
415
- </div>
416
- """
417
- return gr.update(value=count_html, visible=True), gr.update(value=plot_follower_gains(gains), visible=True), gr.update(value=plot_growth_rate(gains, count), visible=True), gr.update(value=plot_avg_engagement_rate(engagement_data), visible=True), gr.update(value=plot_interaction_metrics(interaction_data), visible=True), gr.update(value=plot_eb_content_ratio(eb_data), visible=True), gr.update(value=plot_mention_volume_trend(volume_data), visible=True), gr.update(value=plot_mention_sentiment_score(sentiment_data), visible=True)
418
-
419
- except Exception as e:
420
- error = display_error("Analytics load failed.", e).get('value', "<p style='color:red;'>Error loading data.</p>")
421
- return gr.update(value=error, visible=True), hidden, hidden