GuglielmoTor commited on
Commit
a9b7f24
Β·
verified Β·
1 Parent(s): 90673d4

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +98 -44
app.py CHANGED
@@ -1,24 +1,54 @@
1
  # -*- coding: utf-8 -*-
2
  import gradio as gr
3
  import json
 
4
  from Data_Fetching_and_Rendering import fetch_and_render_dashboard
5
  from analytics_fetch_and_rendering import fetch_and_render_analytics
6
  from mentions_dashboard import generate_mentions_dashboard
7
 
8
-
9
- # Shared state
10
  token_received = {"status": False, "token": None, "client_id": None}
11
 
12
- # --- Handlers for token reception and status ---
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13
  def receive_token(accessToken: str, client_id: str):
14
  """
15
  Called by a hidden POST mechanism to supply the OAuth code/token and client ID.
16
  """
17
  try:
 
 
18
  token_dict = json.loads(accessToken.replace("'", '"'))
19
  except json.JSONDecodeError as e:
 
 
 
 
20
  return {
21
- "status": "❌ Invalid token format",
22
  "token": "",
23
  "client_id": client_id
24
  }
@@ -26,25 +56,28 @@ def receive_token(accessToken: str, client_id: str):
26
  token_received["status"] = True
27
  token_received["token"] = token_dict
28
  token_received["client_id"] = client_id
 
29
  return {
30
- "status": "βœ… Token received",
31
- "token": token_dict.get("access_token", ""),
32
  "client_id": client_id
33
  }
34
 
35
  def check_status():
36
- return "βœ… Token received" if token_received["status"] else "❌ Waiting for token…"
37
 
38
- def show_token():
39
- return token_received["token"].get("access_token", "") if token_received["status"] else ""
 
 
40
 
41
- def show_client():
42
- return token_received["client_id"] or "" if token_received["status"] else ""
43
 
44
- # --- Guarded fetch functions ---
45
  def guarded_fetch_dashboard():
46
  if not token_received["status"]:
47
- return "<p style='color:red; text-align:center;'>❌ Access denied. No token available. Please send token first.</p>"
48
  # token_received["client_id"] and token_received["token"] required by fetch function
49
  html = fetch_and_render_dashboard(
50
  token_received["client_id"],
@@ -52,53 +85,72 @@ def guarded_fetch_dashboard():
52
  )
53
  return html
54
 
55
-
56
  def guarded_fetch_analytics():
57
  if not token_received["status"]:
58
  return (
59
- "<p style='color:red; text-align:center;'>❌ Access denied. No token available.</p>",
60
- None,
61
- None
62
  )
 
63
  count_md, plot, growth_plot, avg_post_eng_rate, interaction_metrics, eb_metrics, mentions_vol_metrics, mentions_sentiment_metrics = fetch_and_render_analytics(
64
  token_received["client_id"],
65
  token_received["token"]
66
  )
67
  return count_md, plot, growth_plot, avg_post_eng_rate, interaction_metrics, eb_metrics, mentions_vol_metrics, mentions_sentiment_metrics
68
 
69
-
70
  def run_mentions_and_load():
 
 
71
  html, fig = generate_mentions_dashboard(
72
  token_received["client_id"],
73
  token_received["token"]
74
  )
75
  return html, fig
76
 
77
-
78
  # --- Build the Gradio UI ---
79
  with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue", secondary_hue="sky"),
80
  title="LinkedIn Post Viewer & Analytics") as app:
81
  gr.Markdown("# πŸš€ LinkedIn Organization Post Viewer & Analytics")
82
- gr.Markdown("Send your OAuth token via API call, then explore dashboard and analytics.")
83
 
84
- # Hidden elements: simulate POST endpoint
85
  hidden_token = gr.Textbox(visible=False, elem_id="hidden_token")
86
  hidden_client = gr.Textbox(visible=False, elem_id="hidden_client_id")
87
  hidden_btn = gr.Button(visible=False, elem_id="hidden_btn")
88
 
89
- status_box = gr.Textbox(value=check_status(), label="Status", interactive=False)
90
- token_display = gr.Textbox(value=show_token(), label="Access Token", interactive=False)
91
- client_display = gr.Textbox(value=show_client(), label="Client ID", interactive=False)
 
 
 
 
 
 
 
 
 
 
 
 
 
92
 
93
- # Wire hidden POST handler
94
  hidden_btn.click(
95
  fn=receive_token,
96
  inputs=[hidden_token, hidden_client],
97
  outputs=[status_box, token_display, client_display]
98
  )
99
 
100
- # Polling timer to update status and displays
101
- timer = gr.Timer(1.0)
 
 
 
 
 
 
 
102
  timer.tick(fn=check_status, outputs=status_box)
103
  timer.tick(fn=show_token, outputs=token_display)
104
  timer.tick(fn=show_client, outputs=client_display)
@@ -108,7 +160,7 @@ with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue", secondary_hue="sky"),
108
  with gr.TabItem("1️⃣ Dashboard"):
109
  gr.Markdown("View your organization's recent posts and their engagement statistics.")
110
  fetch_dashboard_btn = gr.Button("πŸ“Š Fetch Posts & Stats", variant="primary")
111
- dashboard_html = gr.HTML(value="<p style='text-align: center; color: #555;'>Waiting for token...</p>")
112
  fetch_dashboard_btn.click(
113
  fn=guarded_fetch_dashboard,
114
  inputs=[],
@@ -119,45 +171,47 @@ with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue", secondary_hue="sky"),
119
  gr.Markdown("View follower count and monthly gains for your organization.")
120
  fetch_analytics_btn = gr.Button("πŸ“ˆ Fetch Follower Analytics", variant="primary")
121
 
122
- follower_count = gr.Markdown("<p style='text-align: center; color: #555;'>Waiting for token...</p>")
123
 
124
- with gr.Row(): # Use Row to align the two plots side-by-side
125
- follower_plot = gr.Plot(visible=False)
126
- growth_rate_plot = gr.Plot(visible=False)
127
 
128
  with gr.Row():
129
- post_eng_rate_plot = gr.Plot(visible=False)
130
 
131
  with gr.Row():
132
- interaction_data = gr.Plot(visible=False)
133
 
134
  with gr.Row():
135
- eb_data = gr.Plot(visible=False)
136
 
137
  with gr.Row():
138
- mentions_vol_data = gr.Plot(visible=False)
139
- mentions_sentiment_data = gr.Plot(visible=False)
140
-
141
  fetch_analytics_btn.click(
142
  fn=guarded_fetch_analytics,
143
  inputs=[],
144
- outputs=[follower_count, follower_plot, growth_rate_plot, post_eng_rate_plot, interaction_data, eb_data, mentions_vol_data, mentions_sentiment_data]
 
 
145
  )
146
 
147
-
148
  with gr.TabItem("3️⃣ Mentions"):
149
  gr.Markdown("Analyze sentiment of recent posts that mention your organization.")
150
  fetch_mentions_btn = gr.Button("🧠 Fetch Mentions & Sentiment", variant="primary")
151
- mentions_html = gr.HTML()
152
- mentions_plot = gr.Plot(visible=False)
153
  fetch_mentions_btn.click(
154
  fn=run_mentions_and_load,
155
  inputs=[],
156
  outputs=[mentions_html, mentions_plot]
157
  )
158
 
159
-
160
-
161
  # Launch the app
162
  if __name__ == "__main__":
 
 
163
  app.launch(server_name="0.0.0.0", server_port=7860, share=True)
 
 
1
  # -*- coding: utf-8 -*-
2
  import gradio as gr
3
  import json
4
+ # Assuming these custom modules exist in your project directory or Python path
5
  from Data_Fetching_and_Rendering import fetch_and_render_dashboard
6
  from analytics_fetch_and_rendering import fetch_and_render_analytics
7
  from mentions_dashboard import generate_mentions_dashboard
8
 
9
+ # Shared state for token received via POST
 
10
  token_received = {"status": False, "token": None, "client_id": None}
11
 
12
+ # --- Function to get user_token from URL on load ---
13
+ def get_url_user_token(request: gr.Request):
14
+ """
15
+ This function is called when the Gradio app loads.
16
+ It attempts to retrieve 'user_token' from the URL query parameters.
17
+ """
18
+ user_token_from_url = "user_token not found in URL" # Default message
19
+ if request:
20
+ # request.query_params is a dictionary-like object.
21
+ # Example URL: https://your-gradio-app/?user_token=ABC123XYZ
22
+ # query_params would be {'user_token': 'ABC123XYZ'}
23
+ retrieved_token = request.query_params.get("session_id")
24
+ if retrieved_token:
25
+ user_token_from_url = retrieved_token
26
+ print(f"Retrieved user_token from URL: {user_token_from_url}")
27
+ else:
28
+ print("user_token key was not found in the URL query parameters.")
29
+ else:
30
+ # This case should ideally not happen if app.load is configured correctly
31
+ # and Gradio supplies the request object.
32
+ print("Request object not available to get_url_user_token function.")
33
+ user_token_from_url = "Could not access request object on load"
34
+ return user_token_from_url
35
+
36
+ # --- Handlers for token reception (POST) and status ---
37
  def receive_token(accessToken: str, client_id: str):
38
  """
39
  Called by a hidden POST mechanism to supply the OAuth code/token and client ID.
40
  """
41
  try:
42
+ # The .replace("'", '"') is kept from your original code.
43
+ # Be cautious if accessToken format can vary.
44
  token_dict = json.loads(accessToken.replace("'", '"'))
45
  except json.JSONDecodeError as e:
46
+ print(f"Error decoding accessToken: {e}")
47
+ token_received["status"] = False # Ensure status reflects failure
48
+ token_received["token"] = None
49
+ token_received["client_id"] = client_id # Keep client_id if provided
50
  return {
51
+ "status": "❌ Invalid token format (POST)",
52
  "token": "",
53
  "client_id": client_id
54
  }
 
56
  token_received["status"] = True
57
  token_received["token"] = token_dict
58
  token_received["client_id"] = client_id
59
+ print(f"Token (from POST) received successfully. Client ID: {client_id}")
60
  return {
61
+ "status": "βœ… Token received (POST)",
62
+ "token": token_dict.get("access_token", "Access token key missing"), # Display part of the token
63
  "client_id": client_id
64
  }
65
 
66
  def check_status():
67
+ return "βœ… Token received (POST)" if token_received["status"] else "❌ Waiting for token (POST)…"
68
 
69
+ def show_token(): # Shows token from POST
70
+ if token_received["status"] and token_received["token"]:
71
+ return token_received["token"].get("access_token", "Access token key missing")
72
+ return ""
73
 
74
+ def show_client(): # Shows client_id from POST
75
+ return token_received["client_id"] if token_received["status"] and token_received["client_id"] else ""
76
 
77
+ # --- Guarded fetch functions (using token from POST) ---
78
  def guarded_fetch_dashboard():
79
  if not token_received["status"]:
80
+ return "<p style='color:red; text-align:center;'>❌ Access denied. No token (POST) available. Please send token first.</p>"
81
  # token_received["client_id"] and token_received["token"] required by fetch function
82
  html = fetch_and_render_dashboard(
83
  token_received["client_id"],
 
85
  )
86
  return html
87
 
 
88
  def guarded_fetch_analytics():
89
  if not token_received["status"]:
90
  return (
91
+ "<p style='color:red; text-align:center;'>❌ Access denied. No token (POST) available.</p>",
92
+ None, None, None, None, None, None, None # Match number of outputs
 
93
  )
94
+ # Assuming fetch_and_render_analytics returns 8 values
95
  count_md, plot, growth_plot, avg_post_eng_rate, interaction_metrics, eb_metrics, mentions_vol_metrics, mentions_sentiment_metrics = fetch_and_render_analytics(
96
  token_received["client_id"],
97
  token_received["token"]
98
  )
99
  return count_md, plot, growth_plot, avg_post_eng_rate, interaction_metrics, eb_metrics, mentions_vol_metrics, mentions_sentiment_metrics
100
 
 
101
  def run_mentions_and_load():
102
+ if not token_received["status"]: # Added guard similar to other functions
103
+ return ("<p style='color:red; text-align:center;'>❌ Access denied. No token (POST) available.</p>", None)
104
  html, fig = generate_mentions_dashboard(
105
  token_received["client_id"],
106
  token_received["token"]
107
  )
108
  return html, fig
109
 
 
110
  # --- Build the Gradio UI ---
111
  with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue", secondary_hue="sky"),
112
  title="LinkedIn Post Viewer & Analytics") as app:
113
  gr.Markdown("# πŸš€ LinkedIn Organization Post Viewer & Analytics")
114
+ gr.Markdown("Send your OAuth token via API call (POST), then explore dashboard and analytics. URL parameters can also be displayed.")
115
 
116
+ # Hidden elements: simulate POST endpoint for OAuth token
117
  hidden_token = gr.Textbox(visible=False, elem_id="hidden_token")
118
  hidden_client = gr.Textbox(visible=False, elem_id="hidden_client_id")
119
  hidden_btn = gr.Button(visible=False, elem_id="hidden_btn")
120
 
121
+ # --- Display elements ---
122
+ # Textbox for the user_token from URL
123
+ url_user_token_display = gr.Textbox(label="User Token (from URL)", interactive=False, placeholder="Attempting to load from URL...")
124
+
125
+ status_box = gr.Textbox(label="POST Token Status", interactive=False) # Clarified label
126
+ token_display = gr.Textbox(label="Access Token (from POST)", interactive=False)
127
+ client_display = gr.Textbox(label="Client ID (from POST)", interactive=False)
128
+
129
+ # --- Load URL parameter on app start ---
130
+ # The `get_url_user_token` function will be called when the app loads.
131
+ # `gr.Request` is automatically passed to `get_url_user_token`.
132
+ app.load(
133
+ fn=get_url_user_token,
134
+ inputs=None, # No explicit Gradio inputs needed, only gr.Request
135
+ outputs=[url_user_token_display]
136
+ )
137
 
138
+ # Wire hidden POST handler for OAuth token
139
  hidden_btn.click(
140
  fn=receive_token,
141
  inputs=[hidden_token, hidden_client],
142
  outputs=[status_box, token_display, client_display]
143
  )
144
 
145
+ # Polling timer to update status and displays for the POSTed token
146
+ # Initial values are set by app.load for status_box, token_display, client_display
147
+ # then updated by timer ticks or hidden_btn click.
148
+ # We call check_status, show_token, show_client once at load time and then via timer.
149
+ app.load(fn=check_status, outputs=status_box)
150
+ app.load(fn=show_token, outputs=token_display)
151
+ app.load(fn=show_client, outputs=client_display)
152
+
153
+ timer = gr.Timer(1.0) # Poll every 1 second
154
  timer.tick(fn=check_status, outputs=status_box)
155
  timer.tick(fn=show_token, outputs=token_display)
156
  timer.tick(fn=show_client, outputs=client_display)
 
160
  with gr.TabItem("1️⃣ Dashboard"):
161
  gr.Markdown("View your organization's recent posts and their engagement statistics.")
162
  fetch_dashboard_btn = gr.Button("πŸ“Š Fetch Posts & Stats", variant="primary")
163
+ dashboard_html = gr.HTML(value="<p style='text-align: center; color: #555;'>Waiting for POST token...</p>")
164
  fetch_dashboard_btn.click(
165
  fn=guarded_fetch_dashboard,
166
  inputs=[],
 
171
  gr.Markdown("View follower count and monthly gains for your organization.")
172
  fetch_analytics_btn = gr.Button("πŸ“ˆ Fetch Follower Analytics", variant="primary")
173
 
174
+ follower_count = gr.Markdown("<p style='text-align: center; color: #555;'>Waiting for POST token...</p>")
175
 
176
+ with gr.Row():
177
+ follower_plot = gr.Plot(visible=True) # Made visible, will be empty until data
178
+ growth_rate_plot = gr.Plot(visible=True) # Made visible
179
 
180
  with gr.Row():
181
+ post_eng_rate_plot = gr.Plot(visible=True) # Made visible
182
 
183
  with gr.Row():
184
+ interaction_data = gr.Plot(visible=True) # Made visible
185
 
186
  with gr.Row():
187
+ eb_data = gr.Plot(visible=True) # Made visible
188
 
189
  with gr.Row():
190
+ mentions_vol_data = gr.Plot(visible=True) # Made visible
191
+ mentions_sentiment_data = gr.Plot(visible=True) # Made visible
192
+
193
  fetch_analytics_btn.click(
194
  fn=guarded_fetch_analytics,
195
  inputs=[],
196
+ outputs=[follower_count, follower_plot, growth_rate_plot, post_eng_rate_plot, interaction_data, eb_data, mentions_vol_data, mentions_sentiment_data],
197
+ # Show plots after click; they might need to be initially invisible if fetch_and_render_analytics can return None for plots on error
198
+ # For simplicity, keeping them visible. Handle None returns in your fetch function if necessary.
199
  )
200
 
 
201
  with gr.TabItem("3️⃣ Mentions"):
202
  gr.Markdown("Analyze sentiment of recent posts that mention your organization.")
203
  fetch_mentions_btn = gr.Button("🧠 Fetch Mentions & Sentiment", variant="primary")
204
+ mentions_html = gr.HTML(value="<p style='text-align: center; color: #555;'>Waiting for POST token...</p>") # Added placeholder
205
+ mentions_plot = gr.Plot(visible=True) # Made visible
206
  fetch_mentions_btn.click(
207
  fn=run_mentions_and_load,
208
  inputs=[],
209
  outputs=[mentions_html, mentions_plot]
210
  )
211
 
 
 
212
  # Launch the app
213
  if __name__ == "__main__":
214
+ # The share=True option creates a public link. Be mindful of security.
215
+ # For embedding, you'll use the server_name and server_port you configure for your hosting.
216
  app.launch(server_name="0.0.0.0", server_port=7860, share=True)
217
+