GuglielmoTor commited on
Commit
179ea1f
·
verified ·
1 Parent(s): 7a4c907

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +65 -65
app.py CHANGED
@@ -9,41 +9,33 @@ from analytics_fetch_and_rendering import fetch_and_render_analytics
9
  from mentions_dashboard import generate_mentions_dashboard
10
 
11
  # Import the function from your utils file
12
- from gradio_utils import get_url_user_token
13
  # Import the Bubble API call function (ensure filename matches: Bubble_API_Calls.py)
14
  from Bubble_API_Calls import fetch_linkedin_token_from_bubble
15
 
16
  # --- Session State dependent functions ---
17
  def check_token_status(current_token_state):
18
- """Checks if a valid token exists in the session state."""
19
- if current_token_state and current_token_state.get("token") and current_token_state.get("status"):
 
20
  return "✅ Token available"
21
- return "❌ Waiting for token…"
22
-
23
- def get_active_client_id(current_token_state):
24
- """Gets the client_id from the session state if a token is available."""
25
- if current_token_state and current_token_state.get("token") and current_token_state.get("status"):
26
- return current_token_state.get("client_id", "Client ID not set")
27
- return ""
28
 
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.
37
  Returns:
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")
@@ -52,46 +44,49 @@ def process_and_store_bubble_token(url_user_token_str, current_token_state):
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}")
63
  parsed_token_dict = fetch_linkedin_token_from_bubble(url_user_token_str)
64
 
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
 
79
 
80
- # --- Guarded fetch functions (now use token_state) ---
81
  def guarded_fetch_dashboard(current_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
 
90
  def guarded_fetch_analytics(current_token_state):
91
- if not (current_token_state and current_token_state.get("status") and current_token_state.get("token")):
 
92
  return (
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")
@@ -102,53 +97,54 @@ def guarded_fetch_analytics(current_token_state):
102
  return count_md, plot, growth_plot, avg_post_eng_rate, interaction_metrics, eb_metrics, mentions_vol_metrics, mentions_sentiment_metrics
103
 
104
  def run_mentions_and_load(current_token_state):
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
 
113
  # --- Build the Gradio UI ---
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,
125
  placeholder="Attempting to load from URL...",
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"):
@@ -157,18 +153,18 @@ with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue", secondary_hue="sky"),
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
 
164
  with gr.TabItem("2️⃣ Analytics"):
165
  gr.Markdown("View follower count and monthly gains for your organization.")
166
  fetch_analytics_btn = gr.Button("📈 Fetch Follower Analytics", variant="primary")
167
-
168
  follower_count = gr.Markdown("<p style='text-align: center; color: #555;'>Waiting for token...</p>")
169
-
170
  with gr.Row():
171
- follower_plot = gr.Plot(visible=True)
172
  growth_rate_plot = gr.Plot(visible=True)
173
  with gr.Row():
174
  post_eng_rate_plot = gr.Plot(visible=True)
@@ -179,10 +175,10 @@ with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue", secondary_hue="sky"),
179
  with gr.Row():
180
  mentions_vol_data = gr.Plot(visible=True)
181
  mentions_sentiment_data = gr.Plot(visible=True)
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,9 +189,13 @@ with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue", secondary_hue="sky"),
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)
 
 
 
 
 
9
  from mentions_dashboard import generate_mentions_dashboard
10
 
11
  # Import the function from your utils file
12
+ from gradio_utils import get_url_user_token
13
  # Import the Bubble API call function (ensure filename matches: Bubble_API_Calls.py)
14
  from Bubble_API_Calls import fetch_linkedin_token_from_bubble
15
 
16
  # --- Session State dependent functions ---
17
  def check_token_status(current_token_state):
18
+ """Checks if a token exists in the session state."""
19
+ # Only check for the presence of the token
20
+ if current_token_state and current_token_state.get("token"):
21
  return "✅ Token available"
22
+ return "❌ Token not available" # Changed message for clarity
 
 
 
 
 
 
23
 
24
  # --- Function to process and store token from Bubble ---
25
  def process_and_store_bubble_token(url_user_token_str, current_token_state):
26
  """
27
+ Fetches token from Bubble, loads client_id from env, updates session state,
28
  and returns UI update values.
29
  Args:
30
  url_user_token_str: The token string extracted from the URL.
31
  current_token_state: The current session state for the token.
32
  Returns:
33
+ Tuple: (bubble_api_status_msg, overall_token_status_msg, updated_token_state)
34
  """
35
  bubble_api_status_msg = "Waiting for URL token..."
36
+ # Initialize new_token_state, removing the 'status' field
37
+ new_token_state = current_token_state.copy() if current_token_state else {"token": None, "client_id": None}
38
+ new_token_state["token"] = None # Assume no token until successfully fetched
 
 
 
39
 
40
  # Attempt to load Linkedin_client_id from environment variable
41
  linkedin_client_id_from_env = os.environ.get("Linkedin_client_id")
 
44
  bubble_api_status_msg = "❌ CRITICAL ERROR: 'Linkedin_client_id' environment variable not set."
45
  print(bubble_api_status_msg)
46
  new_token_state["client_id"] = "ENV VAR MISSING" # Indicate error in state
47
+ # Return values: bubble_api_status, overall_token_status, new_token_state
48
+ return bubble_api_status_msg, check_token_status(new_token_state), new_token_state
49
+
50
+ # Store client_id from env in the state, regardless of token outcome (if env var exists)
51
+ new_token_state["client_id"] = linkedin_client_id_from_env
52
 
53
  if not url_user_token_str or "not found" in url_user_token_str or "Could not access" in url_user_token_str:
54
  bubble_api_status_msg = f"ℹ️ No valid user token from URL to query Bubble. ({url_user_token_str})"
55
+ # Client ID is known (if env var was found), but no token to fetch
56
+ return bubble_api_status_msg, check_token_status(new_token_state), new_token_state
57
 
58
+ print(f"Attempting to fetch token from Bubble with user token: {url_user_token_str}") # Changed "state" to "user token" for clarity
59
  parsed_token_dict = fetch_linkedin_token_from_bubble(url_user_token_str)
60
 
61
  if parsed_token_dict and isinstance(parsed_token_dict, dict) and "access_token" in parsed_token_dict:
62
+ new_token_state["token"] = parsed_token_dict # Store the actual token
63
+ bubble_api_status_msg = f"✅ Token successfully fetched from Bubble for user token: {url_user_token_str}. Client ID loaded."
 
 
64
  print(bubble_api_status_msg)
65
  else:
66
+ bubble_api_status_msg = f"❌ Failed to fetch a valid token from Bubble for user token: {url_user_token_str}. Check console logs from Bubble_API_Calls.py."
67
  print(bubble_api_status_msg)
68
+ # Token fetch failed, token remains None. Client_id is already set if env var was found.
 
 
69
 
70
+ # Return values: bubble_api_status, overall_token_status, new_token_state
71
+ return bubble_api_status_msg, check_token_status(new_token_state), new_token_state
72
 
73
+ # --- Guarded fetch functions (now use token_state, checking only for token presence) ---
74
  def guarded_fetch_dashboard(current_token_state):
75
+ # Check only for the presence of the token
76
+ if not (current_token_state and current_token_state.get("token")):
77
  return "<p style='color:red; text-align:center;'>❌ Access denied. No token available.</p>"
78
  html = fetch_and_render_dashboard(
79
  current_token_state.get("client_id"), # Use .get for safety
80
+ current_token_state.get("token")
81
  )
82
  return html
83
 
84
  def guarded_fetch_analytics(current_token_state):
85
+ # Check only for the presence of the token
86
+ if not (current_token_state and current_token_state.get("token")):
87
  return (
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.get("client_id")
92
  token_data = current_token_state.get("token")
 
97
  return count_md, plot, growth_plot, avg_post_eng_rate, interaction_metrics, eb_metrics, mentions_vol_metrics, mentions_sentiment_metrics
98
 
99
  def run_mentions_and_load(current_token_state):
100
+ # Check only for the presence of the token
101
+ if not (current_token_state and current_token_state.get("token")):
102
  return ("<p style='color:red; text-align:center;'>❌ Access denied. No token available.</p>", None)
103
  html, fig = generate_mentions_dashboard(
104
  current_token_state.get("client_id"),
105
+ current_token_state.get("token")
106
  )
107
  return html, fig
108
 
109
  # --- Build the Gradio UI ---
110
  with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue", secondary_hue="sky"),
111
  title="LinkedIn Post Viewer & Analytics") as app:
112
+
113
+ # Modified token_state: removed 'status', client_id will be populated from env
114
+ token_state = gr.State(value={"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
  url_user_token_display = gr.Textbox(
120
+ label="User Token (from URL - Hidden)",
121
+ interactive=False,
122
  placeholder="Attempting to load from URL...",
123
+ visible=False # Kept hidden as per original logic
124
  )
 
 
125
 
126
+ status_box = gr.Textbox(label="Overall Token Status", interactive=False, placeholder="Waiting for token check...") # Added placeholder
 
127
 
128
  app.load(
129
+ fn=get_url_user_token,
130
+ inputs=None,
131
+ outputs=[url_user_token_display]
132
  )
133
 
134
+ # Modified outputs for process_and_store_bubble_token
135
  url_user_token_display.change(
136
  fn=process_and_store_bubble_token,
137
+ inputs=[url_user_token_display, token_state],
138
+ outputs=[status_box, token_state] # Removed client_display
139
  )
140
+
141
+ # app.load to initialize status_box based on initial token_state
142
  app.load(fn=check_token_status, inputs=[token_state], outputs=status_box)
143
+ # Removed app.load for get_active_client_id and client_display
144
+
145
+ timer = gr.Timer(5.0)
146
  timer.tick(fn=check_token_status, inputs=[token_state], outputs=status_box)
147
+ # Removed timer.tick for get_active_client_id and client_display
148
 
149
  with gr.Tabs():
150
  with gr.TabItem("1️⃣ Dashboard"):
 
153
  dashboard_html = gr.HTML(value="<p style='text-align: center; color: #555;'>Waiting for token...</p>")
154
  fetch_dashboard_btn.click(
155
  fn=guarded_fetch_dashboard,
156
+ inputs=[token_state],
157
  outputs=[dashboard_html]
158
  )
159
 
160
  with gr.TabItem("2️⃣ Analytics"):
161
  gr.Markdown("View follower count and monthly gains for your organization.")
162
  fetch_analytics_btn = gr.Button("📈 Fetch Follower Analytics", variant="primary")
163
+
164
  follower_count = gr.Markdown("<p style='text-align: center; color: #555;'>Waiting for token...</p>")
165
+
166
  with gr.Row():
167
+ follower_plot = gr.Plot(visible=True)
168
  growth_rate_plot = gr.Plot(visible=True)
169
  with gr.Row():
170
  post_eng_rate_plot = gr.Plot(visible=True)
 
175
  with gr.Row():
176
  mentions_vol_data = gr.Plot(visible=True)
177
  mentions_sentiment_data = gr.Plot(visible=True)
178
+
179
  fetch_analytics_btn.click(
180
  fn=guarded_fetch_analytics,
181
+ inputs=[token_state],
182
  outputs=[follower_count, follower_plot, growth_rate_plot, post_eng_rate_plot, interaction_data, eb_data, mentions_vol_data, mentions_sentiment_data]
183
  )
184
 
 
189
  mentions_plot = gr.Plot(visible=True)
190
  fetch_mentions_btn.click(
191
  fn=run_mentions_and_load,
192
+ inputs=[token_state],
193
  outputs=[mentions_html, mentions_plot]
194
  )
195
 
196
  if __name__ == "__main__":
197
+ # Ensure the Linkedin_client_id environment variable is set before launching.
198
+ # You might want to add a check here and print a warning if it's not set.
199
+ if not os.environ.get("Linkedin_client_id"):
200
+ print("WARNING: The 'Linkedin_client_id' environment variable is not set. The application may not function correctly.")
201
+ app.launch(server_name="0.0.0.0", server_port=7860, share=True)