GuglielmoTor commited on
Commit
7a4c907
·
verified ·
1 Parent(s): 3038c7b

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +35 -45
app.py CHANGED
@@ -1,8 +1,7 @@
1
  # -*- coding: utf-8 -*-
2
  import gradio as gr
3
  import json
4
- # requests, os, urllib.parse are used by Bubble_API_Calls.py, not directly here anymore
5
- # but good to keep if you add other direct calls later.
6
 
7
  # Assuming these custom modules exist in your project directory or Python path
8
  from Data_Fetching_and_Rendering import fetch_and_render_dashboard
@@ -30,7 +29,8 @@ def get_active_client_id(current_token_state):
30
  # --- Function to process and store token from Bubble ---
31
  def process_and_store_bubble_token(url_user_token_str, current_token_state):
32
  """
33
- Fetches token from Bubble, updates session state, and returns UI update values.
 
34
  Args:
35
  url_user_token_str: The token string extracted from the URL.
36
  current_token_state: The current session state for the token.
@@ -38,11 +38,25 @@ def process_and_store_bubble_token(url_user_token_str, current_token_state):
38
  Tuple: (bubble_api_status_msg, overall_status, client_id_display, updated_token_state)
39
  """
40
  bubble_api_status_msg = "Waiting for URL token..."
 
41
  new_token_state = current_token_state.copy() if current_token_state else {"status": False, "token": None, "client_id": None}
 
 
 
 
 
 
 
 
 
 
 
 
 
42
 
43
  if not url_user_token_str or "not found" in url_user_token_str or "Could not access" in url_user_token_str:
44
  bubble_api_status_msg = f"ℹ️ No valid user token from URL to query Bubble. ({url_user_token_str})"
45
- # Even if no valid URL token, return current status based on existing state
46
  return bubble_api_status_msg, check_token_status(new_token_state), get_active_client_id(new_token_state), new_token_state
47
 
48
  print(f"Attempting to fetch token from Bubble with state: {url_user_token_str}")
@@ -51,23 +65,14 @@ def process_and_store_bubble_token(url_user_token_str, current_token_state):
51
  if parsed_token_dict and isinstance(parsed_token_dict, dict) and "access_token" in parsed_token_dict:
52
  new_token_state["status"] = True
53
  new_token_state["token"] = parsed_token_dict
54
- new_token_state["client_id"] = f"Bubble (state: {url_user_token_str})"
55
- bubble_api_status_msg = f"✅ Token successfully fetched from Bubble for state: {url_user_token_str}"
56
  print(bubble_api_status_msg)
57
  else:
58
- # Fetch failed or no valid token returned, keep previous state or mark as no token
59
- # If you want a Bubble failure to explicitly clear any old token:
60
- # new_token_state["status"] = False
61
- # new_token_state["token"] = None
62
- # new_token_state["client_id"] = None
63
- # For now, it just means the Bubble fetch didn't provide a new one.
64
  bubble_api_status_msg = f"❌ Failed to fetch a valid token from Bubble for state: {url_user_token_str}. Check console logs from Bubble_API_Calls.py."
65
  print(bubble_api_status_msg)
66
- # If the goal is that ONLY a successful bubble fetch provides a token, then reset status:
67
- new_token_state["status"] = False
68
- new_token_state["token"] = None
69
- # client_id might be kept or cleared based on preference
70
- # new_token_state["client_id"] = f"Bubble fetch failed (state: {url_user_token_str})"
71
 
72
 
73
  return bubble_api_status_msg, check_token_status(new_token_state), get_active_client_id(new_token_state), new_token_state
@@ -77,8 +82,8 @@ def guarded_fetch_dashboard(current_token_state):
77
  if not (current_token_state and current_token_state.get("status") and current_token_state.get("token")):
78
  return "<p style='color:red; text-align:center;'>❌ Access denied. No token available.</p>"
79
  html = fetch_and_render_dashboard(
80
- current_token_state["client_id"],
81
- current_token_state["token"]
82
  )
83
  return html
84
 
@@ -88,8 +93,8 @@ def guarded_fetch_analytics(current_token_state):
88
  "<p style='color:red; text-align:center;'>❌ Access denied. No token available.</p>",
89
  None, None, None, None, None, None, None
90
  )
91
- client_id = current_token_state["client_id"]
92
- token_data = current_token_state["token"]
93
  count_md, plot, growth_plot, avg_post_eng_rate, interaction_metrics, eb_metrics, mentions_vol_metrics, mentions_sentiment_metrics = fetch_and_render_analytics(
94
  client_id,
95
  token_data
@@ -100,8 +105,8 @@ def run_mentions_and_load(current_token_state):
100
  if not (current_token_state and current_token_state.get("status") and current_token_state.get("token")):
101
  return ("<p style='color:red; text-align:center;'>❌ Access denied. No token available.</p>", None)
102
  html, fig = generate_mentions_dashboard(
103
- current_token_state["client_id"],
104
- current_token_state["token"]
105
  )
106
  return html, fig
107
 
@@ -109,14 +114,11 @@ def run_mentions_and_load(current_token_state):
109
  with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue", secondary_hue="sky"),
110
  title="LinkedIn Post Viewer & Analytics") as app:
111
 
112
- # Session state to store the token info
113
- # Initial value is a dictionary representing an unauthenticated state.
114
  token_state = gr.State(value={"status": False, "token": None, "client_id": None})
115
 
116
  gr.Markdown("# 🚀 LinkedIn Organization Post Viewer & Analytics")
117
  gr.Markdown("Token is supplied via URL parameter for Bubble.io lookup. Then explore dashboard and analytics.")
118
 
119
- # Hidden textbox to capture token from URL
120
  url_user_token_display = gr.Textbox(
121
  label="User Token (from URL - Hidden)",
122
  interactive=False,
@@ -124,40 +126,30 @@ with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue", secondary_hue="sky"),
124
  visible=False
125
  )
126
 
127
- # Display for Bubble API call status
128
  bubble_api_status_display = gr.Textbox(label="Bubble API Call Status", interactive=False, placeholder="Waiting for URL token...")
129
 
130
- # Overall status displays
131
  status_box = gr.Textbox(label="Overall Token Status", interactive=False)
132
  client_display = gr.Textbox(label="Client ID (Active)", interactive=False)
133
- # Note: The textbox for displaying the actual token is removed.
134
 
135
- # --- Load URL parameter on app start & Link to Bubble Fetch ---
136
  app.load(
137
  fn=get_url_user_token,
138
- inputs=None, # get_url_user_token takes gr.Request implicitly
139
  outputs=[url_user_token_display]
140
  )
141
 
142
- # When the hidden url_user_token_display changes (due to app.load),
143
- # trigger the Bubble API call and update session state.
144
  url_user_token_display.change(
145
  fn=process_and_store_bubble_token,
146
- inputs=[url_user_token_display, token_state], # Pass current state
147
- outputs=[bubble_api_status_display, status_box, client_display, token_state] # Update UI and state
148
  )
149
 
150
- # Initial UI state based on initial token_state
151
  app.load(fn=check_token_status, inputs=[token_state], outputs=status_box)
152
  app.load(fn=get_active_client_id, inputs=[token_state], outputs=client_display)
153
 
154
- # Timer to periodically update status (e.g., if token could expire or be managed externally)
155
- # This might be less critical if token acquisition is only at the start via URL.
156
- timer = gr.Timer(5.0) # Poll every 5 seconds, adjust as needed
157
  timer.tick(fn=check_token_status, inputs=[token_state], outputs=status_box)
158
  timer.tick(fn=get_active_client_id, inputs=[token_state], outputs=client_display)
159
 
160
- # Tabs for functionality
161
  with gr.Tabs():
162
  with gr.TabItem("1️⃣ Dashboard"):
163
  gr.Markdown("View your organization's recent posts and their engagement statistics.")
@@ -165,7 +157,7 @@ with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue", secondary_hue="sky"),
165
  dashboard_html = gr.HTML(value="<p style='text-align: center; color: #555;'>Waiting for token...</p>")
166
  fetch_dashboard_btn.click(
167
  fn=guarded_fetch_dashboard,
168
- inputs=[token_state], # Pass session state
169
  outputs=[dashboard_html]
170
  )
171
 
@@ -190,7 +182,7 @@ with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue", secondary_hue="sky"),
190
 
191
  fetch_analytics_btn.click(
192
  fn=guarded_fetch_analytics,
193
- inputs=[token_state], # Pass session state
194
  outputs=[follower_count, follower_plot, growth_rate_plot, post_eng_rate_plot, interaction_data, eb_data, mentions_vol_data, mentions_sentiment_data]
195
  )
196
 
@@ -201,11 +193,9 @@ with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue", secondary_hue="sky"),
201
  mentions_plot = gr.Plot(visible=True)
202
  fetch_mentions_btn.click(
203
  fn=run_mentions_and_load,
204
- inputs=[token_state], # Pass session state
205
  outputs=[mentions_html, mentions_plot]
206
  )
207
 
208
- # Launch the app
209
  if __name__ == "__main__":
210
- # Ensure the 'Bubble_API' environment variable is set where this app is run.
211
  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
+ import os # Added to access environment variables
 
5
 
6
  # Assuming these custom modules exist in your project directory or Python path
7
  from Data_Fetching_and_Rendering import fetch_and_render_dashboard
 
29
  # --- Function to process and store token from Bubble ---
30
  def process_and_store_bubble_token(url_user_token_str, current_token_state):
31
  """
32
+ Fetches token from Bubble, loads client_id from env, updates session state,
33
+ and returns UI update values.
34
  Args:
35
  url_user_token_str: The token string extracted from the URL.
36
  current_token_state: The current session state for the token.
 
38
  Tuple: (bubble_api_status_msg, overall_status, client_id_display, updated_token_state)
39
  """
40
  bubble_api_status_msg = "Waiting for URL token..."
41
+ # Ensure new_token_state is a new dictionary, not a reference to current_token_state
42
  new_token_state = current_token_state.copy() if current_token_state else {"status": False, "token": None, "client_id": None}
43
+ # Default to current state values unless explicitly changed
44
+ new_token_state["status"] = False # Assume failure until success
45
+ new_token_state["token"] = None
46
+ # new_token_state["client_id"] will be set or cleared based on env var
47
+
48
+ # Attempt to load Linkedin_client_id from environment variable
49
+ linkedin_client_id_from_env = os.environ.get("Linkedin_client_id")
50
+
51
+ if not linkedin_client_id_from_env:
52
+ bubble_api_status_msg = "❌ CRITICAL ERROR: 'Linkedin_client_id' environment variable not set."
53
+ print(bubble_api_status_msg)
54
+ new_token_state["client_id"] = "ENV VAR MISSING" # Indicate error in state
55
+ return bubble_api_status_msg, check_token_status(new_token_state), get_active_client_id(new_token_state), new_token_state
56
 
57
  if not url_user_token_str or "not found" in url_user_token_str or "Could not access" in url_user_token_str:
58
  bubble_api_status_msg = f"ℹ️ No valid user token from URL to query Bubble. ({url_user_token_str})"
59
+ new_token_state["client_id"] = linkedin_client_id_from_env # Client ID is known, but no token
60
  return bubble_api_status_msg, check_token_status(new_token_state), get_active_client_id(new_token_state), new_token_state
61
 
62
  print(f"Attempting to fetch token from Bubble with state: {url_user_token_str}")
 
65
  if parsed_token_dict and isinstance(parsed_token_dict, dict) and "access_token" in parsed_token_dict:
66
  new_token_state["status"] = True
67
  new_token_state["token"] = parsed_token_dict
68
+ new_token_state["client_id"] = linkedin_client_id_from_env # Use client_id from env var
69
+ bubble_api_status_msg = f"✅ Token successfully fetched from Bubble for state: {url_user_token_str}. Client ID loaded."
70
  print(bubble_api_status_msg)
71
  else:
 
 
 
 
 
 
72
  bubble_api_status_msg = f"❌ Failed to fetch a valid token from Bubble for state: {url_user_token_str}. Check console logs from Bubble_API_Calls.py."
73
  print(bubble_api_status_msg)
74
+ # Token fetch failed, status remains False, token remains None
75
+ new_token_state["client_id"] = linkedin_client_id_from_env # Client ID is known, but no token
 
 
 
76
 
77
 
78
  return bubble_api_status_msg, check_token_status(new_token_state), get_active_client_id(new_token_state), new_token_state
 
82
  if not (current_token_state and current_token_state.get("status") and current_token_state.get("token")):
83
  return "<p style='color:red; text-align:center;'>❌ Access denied. No token available.</p>"
84
  html = fetch_and_render_dashboard(
85
+ current_token_state.get("client_id"), # Use .get for safety
86
+ current_token_state.get("token")
87
  )
88
  return html
89
 
 
93
  "<p style='color:red; text-align:center;'>❌ Access denied. No token available.</p>",
94
  None, None, None, None, None, None, None
95
  )
96
+ client_id = current_token_state.get("client_id")
97
+ token_data = current_token_state.get("token")
98
  count_md, plot, growth_plot, avg_post_eng_rate, interaction_metrics, eb_metrics, mentions_vol_metrics, mentions_sentiment_metrics = fetch_and_render_analytics(
99
  client_id,
100
  token_data
 
105
  if not (current_token_state and current_token_state.get("status") and current_token_state.get("token")):
106
  return ("<p style='color:red; text-align:center;'>❌ Access denied. No token available.</p>", None)
107
  html, fig = generate_mentions_dashboard(
108
+ current_token_state.get("client_id"),
109
+ current_token_state.get("token")
110
  )
111
  return html, fig
112
 
 
114
  with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue", secondary_hue="sky"),
115
  title="LinkedIn Post Viewer & Analytics") as app:
116
 
 
 
117
  token_state = gr.State(value={"status": False, "token": None, "client_id": None})
118
 
119
  gr.Markdown("# 🚀 LinkedIn Organization Post Viewer & Analytics")
120
  gr.Markdown("Token is supplied via URL parameter for Bubble.io lookup. Then explore dashboard and analytics.")
121
 
 
122
  url_user_token_display = gr.Textbox(
123
  label="User Token (from URL - Hidden)",
124
  interactive=False,
 
126
  visible=False
127
  )
128
 
 
129
  bubble_api_status_display = gr.Textbox(label="Bubble API Call Status", interactive=False, placeholder="Waiting for URL token...")
130
 
 
131
  status_box = gr.Textbox(label="Overall Token Status", interactive=False)
132
  client_display = gr.Textbox(label="Client ID (Active)", interactive=False)
 
133
 
 
134
  app.load(
135
  fn=get_url_user_token,
136
+ inputs=None,
137
  outputs=[url_user_token_display]
138
  )
139
 
 
 
140
  url_user_token_display.change(
141
  fn=process_and_store_bubble_token,
142
+ inputs=[url_user_token_display, token_state],
143
+ outputs=[bubble_api_status_display, status_box, client_display, token_state]
144
  )
145
 
 
146
  app.load(fn=check_token_status, inputs=[token_state], outputs=status_box)
147
  app.load(fn=get_active_client_id, inputs=[token_state], outputs=client_display)
148
 
149
+ timer = gr.Timer(5.0)
 
 
150
  timer.tick(fn=check_token_status, inputs=[token_state], outputs=status_box)
151
  timer.tick(fn=get_active_client_id, inputs=[token_state], outputs=client_display)
152
 
 
153
  with gr.Tabs():
154
  with gr.TabItem("1️⃣ Dashboard"):
155
  gr.Markdown("View your organization's recent posts and their engagement statistics.")
 
157
  dashboard_html = gr.HTML(value="<p style='text-align: center; color: #555;'>Waiting for token...</p>")
158
  fetch_dashboard_btn.click(
159
  fn=guarded_fetch_dashboard,
160
+ inputs=[token_state],
161
  outputs=[dashboard_html]
162
  )
163
 
 
182
 
183
  fetch_analytics_btn.click(
184
  fn=guarded_fetch_analytics,
185
+ inputs=[token_state],
186
  outputs=[follower_count, follower_plot, growth_rate_plot, post_eng_rate_plot, interaction_data, eb_data, mentions_vol_data, mentions_sentiment_data]
187
  )
188
 
 
193
  mentions_plot = gr.Plot(visible=True)
194
  fetch_mentions_btn.click(
195
  fn=run_mentions_and_load,
196
+ inputs=[token_state],
197
  outputs=[mentions_html, mentions_plot]
198
  )
199
 
 
200
  if __name__ == "__main__":
 
201
  app.launch(server_name="0.0.0.0", server_port=7860, share=True)