GuglielmoTor commited on
Commit
dd307a7
Β·
verified Β·
1 Parent(s): c57d01f

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +152 -238
app.py CHANGED
@@ -22,10 +22,12 @@ from services.analytics_tab_module import AnalyticsTab
22
 
23
  # UPDATED: Using the new data loading function from the refactored state manager
24
  from services.state_manager import load_data_from_bubble
 
 
25
  from ui.ui_generators import (
26
  build_analytics_tab_plot_area,
27
- build_home_tab_ui, # NEW: Import the function to build the Home tab UI
28
- create_enhanced_report_tab, # NEW: Import the function to build the enhanced Report tab UI
29
  BOMB_ICON, EXPLORE_ICON, FORMULA_ICON, ACTIVE_ICON
30
  )
31
  # NEW: Import the new OKR UI functions
@@ -33,6 +35,9 @@ from ui.okr_ui_generator import create_enhanced_okr_tab, format_okrs_for_enhance
33
  from ui.analytics_plot_generator import update_analytics_plots_figures, create_placeholder_plot
34
  from formulas import PLOT_FORMULAS
35
 
 
 
 
36
  # --- CHATBOT MODULE IMPORTS ---
37
  from features.chatbot.chatbot_prompts import get_initial_insight_prompt_and_suggestions
38
  from features.chatbot.chatbot_handler import generate_llm_response
@@ -46,8 +51,6 @@ try:
46
  # UI formatting functions
47
  from ui.insights_ui_generator import (
48
  format_report_for_display, # This will now return header HTML and body Markdown
49
- # REMOVED: extract_key_results_for_selection, - Moved to okr_ui_generator (implicitly)
50
- # REMOVED: format_single_okr_for_display - Moved to okr_ui_generator (implicitly)
51
  )
52
  AGENTIC_MODULES_LOADED = True
53
  except ImportError as e:
@@ -76,15 +79,15 @@ except ImportError as e:
76
  # matching the `outputs` in the .then() call later.
77
  return (
78
  gr.update(value="Modules not loaded."), # agentic_pipeline_status_md (0)
79
- gr.update(choices=[], value=None), # report_selector_dd (1)
80
- gr.update(choices=[], value=[]), # key_results_cbg (2) - KEPT HIDDEN for compatibility
81
- gr.update(value="Modules not loaded."), # okr_detail_display_md (3) - KEPT HIDDEN for compatibility
82
- None, # orchestration_raw_results_st (4)
83
- [], # selected_key_result_ids_st (5) - KEPT HIDDEN for compatibility
84
- [], # key_results_for_selection_st (6) - KEPT HIDDEN for compatibility
85
- gr.update(value=empty_header_html), # report_header_html_display (7)
86
- gr.update(value=empty_body_markdown), # report_body_markdown_display (8)
87
- {}, # reconstruction_cache_st (9)
88
  gr.update(value=get_initial_okr_display()), # NEW: enhanced_okr_display_html (10)
89
  gr.update(value={}) # NEW: actionable_okrs_data_st (11)
90
  )
@@ -95,241 +98,152 @@ except ImportError as e:
95
  return {'header_html': '<h1>Agentic modules not loaded.</h1>', 'body_markdown': 'Report display unavailable.'}
96
 
97
 
98
- with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue", secondary_hue="sky"),
99
- title="LinkedIn Organization Dashboard") as app:
100
- # --- STATE MANAGEMENT ---
101
- token_state = gr.State(value={
102
- "token": None, "client_id": None, "org_urn": None,
103
- "bubble_posts_df": pd.DataFrame(), "bubble_post_stats_df": pd.DataFrame(),
104
- "bubble_mentions_df": pd.DataFrame(), "bubble_follower_stats_df": pd.DataFrame(),
105
- "bubble_agentic_analysis_data": pd.DataFrame(), # To store agentic results from Bubble
106
- "url_user_token_temp_storage": None,
107
- "config_date_col_posts": "published_at", "config_date_col_mentions": "date",
108
- "config_date_col_followers": "date", "config_media_type_col": "media_type",
109
- "config_eb_labels_col": "li_eb_label"
110
- })
111
-
112
- # States for analytics tab chatbot
113
- chat_histories_st = gr.State({})
114
- current_chat_plot_id_st = gr.State(None)
115
- plot_data_for_chatbot_st = gr.State({})
116
-
117
- # States for agentic results display
118
- orchestration_raw_results_st = gr.State(None)
119
- # KEPT for compatibility with load_and_display_agentic_results signature
120
- key_results_for_selection_st = gr.State([])
121
- selected_key_result_ids_st = gr.State([])
122
-
123
- # --- NEW: Session-specific cache for reconstructed OKR data ---
124
- reconstruction_cache_st = gr.State({})
125
- # NEW: State to hold the actionable_okrs dictionary explicitly
126
- actionable_okrs_data_st = gr.State({})
127
-
128
-
129
- # --- UI LAYOUT ---
130
- gr.Markdown("# πŸš€ LinkedIn Organization Dashboard")
131
- url_user_token_display = gr.Textbox(label="User Token (Hidden)", interactive=False, visible=False)
132
- org_urn_display = gr.Textbox(label="Org URN (Hidden)", interactive=False, visible=False)
133
- status_box = gr.Textbox(label="Status", interactive=False, value="Initializing...")
134
-
135
- app.load(fn=get_url_user_token, inputs=None, outputs=[url_user_token_display, org_urn_display], api_name="get_url_params", show_progress=False)
136
 
137
- def initial_data_load_sequence(url_token, org_urn_val, current_state):
138
- """
139
- Handles the initial data loading from Bubble.
140
- No longer generates dashboard HTML as the Home tab is now static.
141
- """
142
- status_msg, new_state = load_data_from_bubble(url_token, org_urn_val, current_state)
143
- return status_msg, new_state
144
 
145
- analytics_icons = {'bomb': BOMB_ICON, 'explore': EXPLORE_ICON, 'formula': FORMULA_ICON, 'active': ACTIVE_ICON}
146
- analytics_tab_instance = AnalyticsTab(
147
- token_state=token_state,
148
- chat_histories_st=chat_histories_st,
149
- current_chat_plot_id_st=current_chat_plot_id_st,
150
- plot_data_for_chatbot_st=plot_data_for_chatbot_st,
151
- plot_id_to_formula_map=PLOT_ID_TO_FORMULA_KEY_MAP,
152
- plot_formulas_data=PLOT_FORMULAS,
153
- icons=analytics_icons,
154
- fn_build_plot_area=build_analytics_tab_plot_area,
155
- fn_update_plot_figures=update_analytics_plots_figures,
156
- fn_create_placeholder_plot=create_placeholder_plot,
157
- fn_get_initial_insight=get_initial_insight_prompt_and_suggestions,
158
- fn_generate_llm_response=generate_llm_response
159
  )
160
 
161
- def update_report_display(selected_report_id: str, current_token_state: dict):
162
- """
163
- Updates the report header and body display when a new report is selected.
164
- This function now expects format_report_for_display to return a dict with
165
- 'header_html' and 'body_markdown'.
166
- """
167
- # Define empty states for header and body
168
- empty_header_html = """
169
- <div class="report-title">πŸ“Š Comprehensive Analysis Report</div>
170
- <div class="report-subtitle">AI-Generated Insights from Your LinkedIn Data</div>
171
- <div class="status-badge">Generated from Bubble.io</div>
172
- """
173
- empty_body_markdown_no_selection = """
174
- <div class="empty-state">
175
- <div class="empty-state-icon">πŸ“‹</div>
176
- <div class="empty-state-title">Select a Report</div>
177
- <div class="empty-state-description">
178
- Choose a report from the dropdown above to view its detailed analysis and insights.
179
- </div>
180
- </div>
181
- """
182
- empty_body_markdown_no_data = """
183
- <div class="empty-state">
184
- <div class="empty-state-icon">⚠️</div>
185
- <div class="empty-state-title">Data Not Available</div>
186
- <div class="empty-state-description">
187
- Analysis data is not loaded or is empty. Please try refreshing the page.
188
- </div>
189
- </div>
190
- """
191
- empty_body_markdown_not_found = lambda _id: f"""
192
- <div class="empty-state">
193
- <div class="empty-state-icon">❌</div>
194
- <div class="empty-state-title">Report Not Found</div>
195
- <div class="empty-state-description">
196
- Report with ID '{_id}' was not found in the database.
197
- </div>
198
- </div>
199
- """
200
-
201
- if not selected_report_id:
202
- # When no report is selected, update both header and body
203
- return gr.update(value=empty_header_html), gr.update(value=empty_body_markdown_no_selection)
204
-
205
- agentic_df = current_token_state.get("bubble_agentic_analysis_data")
206
- if agentic_df is None or agentic_df.empty:
207
- # When no data is available, update both header and body
208
- return gr.update(value=empty_header_html), gr.update(value=empty_body_markdown_no_data)
209
-
210
- selected_report_series_df = agentic_df[agentic_df['_id'] == selected_report_id]
211
- if selected_report_series_df.empty:
212
- # When report is not found, update both header and body
213
- return gr.update(value=empty_header_html), gr.update(value=empty_body_markdown_not_found(selected_report_id))
214
-
215
- selected_report_series = selected_report_series_df.iloc[0]
216
-
217
- # Call the format_report_for_display, which now returns a dict
218
- formatted_content_parts = format_report_for_display(selected_report_series)
219
-
220
- # Update the two separate Gradio components
221
- return (
222
- gr.update(value=formatted_content_parts['header_html']),
223
- gr.update(value=formatted_content_parts['body_markdown'])
224
- )
225
-
226
-
227
- with gr.Tabs() as tabs:
228
- # --- NEW HOME TAB ---
229
- with gr.TabItem("1️⃣ Home", id="tab_home"):
230
- # Call the new function from ui_generators to build the Home tab content
231
- btn_graphs, btn_reports, btn_okr, btn_help = build_home_tab_ui()
232
-
233
- # Link buttons to tab selection
234
- btn_graphs.click(fn=lambda: gr.update(selected="tab_analytics_module"), outputs=tabs)
235
- btn_reports.click(fn=lambda: gr.update(selected="tab_agentic_report"), outputs=tabs)
236
- btn_okr.click(fn=lambda: gr.update(selected="tab_agentic_okrs"), outputs=tabs)
237
- # btn_help.click(fn=lambda: gr.update(selected="tab_help"), outputs=tabs) # Uncomment if you add a help tab
238
-
239
-
240
- analytics_tab_instance.create_tab_ui() # This is the "Graphs" tab, assuming its ID is "tab_analytics"
241
-
242
- # --- REPLACED: Agentic Analysis Report Tab with enhanced UI ---
243
- # The create_enhanced_report_tab function now builds this entire tab's UI.
244
- # It also returns the relevant Gradio components needed for callbacks.
245
- with gr.TabItem("3️⃣ Agentic Analysis Report", id="tab_agentic_report", visible=AGENTIC_MODULES_LOADED):
246
- # The create_enhanced_report_tab function handles the CSS and HTML structure
247
- # MODIFIED: Unpacked 4 values instead of 3
248
- agentic_pipeline_status_md, report_selector_dd, report_header_html_display, report_body_markdown_display = \
249
- create_enhanced_report_tab(AGENTIC_MODULES_LOADED)
250
-
251
-
252
- with gr.TabItem("4️⃣ Agentic OKRs & Tasks", id="tab_agentic_okrs", visible=AGENTIC_MODULES_LOADED):
253
- gr.Markdown("## 🎯 AI Generated OKRs and Actionable Tasks (from Bubble.io)")
254
- gr.Markdown("Basato sull'analisi AI, l'agente ha proposto i seguenti OKR.")
255
-
256
- if not AGENTIC_MODULES_LOADED:
257
- gr.Markdown("πŸ”΄ **Error:** Agentic modules could not be loaded.")
258
-
259
- # Keep the old components but make them invisible to maintain load_and_display_agentic_results signature
260
- with gr.Column(visible=False):
261
- gr.Markdown("### Suggested Key Results (OLD UI - HIDDEN)")
262
- key_results_cbg = gr.CheckboxGroup(label="Select Key Results", choices=[], value=[], interactive=True)
263
- gr.Markdown("### Detailed OKRs and Tasks (OLD UI - HIDDEN)")
264
- okr_detail_display_md = gr.Markdown("I dettagli OKR appariranno qui.")
265
-
266
- # NEW: Add the enhanced OKR display HTML component
267
- enhanced_okr_display_html = create_enhanced_okr_tab()
268
-
269
- # REMOVED: The old update_okr_display_on_selection function and its change event
270
- # as the new UI handles display dynamically from raw_results_st
271
-
272
- if AGENTIC_MODULES_LOADED:
273
- report_selector_dd.change(
274
- fn=update_report_display, # This now calls the enhanced function
275
- # MODIFIED: Updated outputs to match the two new display components
276
- inputs=[report_selector_dd, token_state],
277
- outputs=[report_header_html_display, report_body_markdown_display],
278
- show_progress="minimal"
279
- )
280
-
281
- # Ensure agentic_display_outputs correctly maps to the newly created components
282
- # This list must match the outputs of load_and_display_agentic_results
283
- agentic_display_outputs = [
284
- agentic_pipeline_status_md, # 0: Status Markdown (hidden)
285
- report_selector_dd, # 1: Dropdown for selecting reports
286
- key_results_cbg, # 2: Checkbox group for OKRs (kept hidden)
287
- okr_detail_display_md, # 3: Markdown for detailed OKR display (kept hidden)
288
- orchestration_raw_results_st, # 4: Raw results state
289
- selected_key_result_ids_st, # 5: Selected KR IDs state (kept hidden)
290
- key_results_for_selection_st, # 6: All KRs for selection state (kept hidden)
291
- report_header_html_display, # 7: New HTML output for header
292
- report_body_markdown_display, # 8: New Markdown output for body
293
- reconstruction_cache_st, # 9: Reconstruction cache state
294
- enhanced_okr_display_html, # 10: NEW: The enhanced HTML display for OKRs
295
- actionable_okrs_data_st # 11: NEW: The actionable_okrs dictionary state
296
- ]
297
-
298
- initial_load_event = org_urn_display.change(
299
- fn=initial_data_load_sequence,
300
- inputs=[url_user_token_display, org_urn_display, token_state],
301
- outputs=[status_box, token_state],
302
- show_progress="full"
303
  )
304
 
305
- initial_load_event.then(
306
- fn=analytics_tab_instance._refresh_analytics_graphs_ui,
307
- inputs=[token_state, analytics_tab_instance.date_filter_selector, analytics_tab_instance.custom_start_date_picker,
308
- analytics_tab_instance.custom_end_date_picker, chat_histories_st],
309
- outputs=analytics_tab_instance.graph_refresh_outputs_list,
310
- show_progress="full"
311
- ).then(
312
- fn=load_and_display_agentic_results,
313
- inputs=[token_state, reconstruction_cache_st],
314
- # MODIFIED: Updated outputs to match all components returned by load_and_display_agentic_results (now 12)
315
- outputs=agentic_display_outputs,
316
- show_progress="minimal"
317
- ).then( # NEW CHAIN: Update the enhanced OKR display after load_and_display_agentic_results runs
 
 
 
 
 
 
 
 
318
  fn=format_okrs_for_enhanced_display,
319
- inputs=[reconstruction_cache_st], # Change from actionable_okrs_data_st to reconstruction_cache_st
320
  outputs=[enhanced_okr_display_html],
321
  show_progress="minimal"
322
- )
323
-
324
 
325
  if __name__ == "__main__":
 
 
 
 
 
 
326
  if not os.environ.get(LINKEDIN_CLIENT_ID_ENV_VAR):
327
- logging.warning(f"WARNING: '{LINKEDIN_CLIENT_ID_ENV_VAR}' is not set.")
328
- if not all(os.environ.get(var) for var in [BUBBLE_APP_NAME_ENV_VAR, BUBBLE_API_KEY_PRIVATE_ENV_VAR, BUBBLE_API_ENDPOINT_ENV_VAR]):
329
- logging.warning("WARNING: One or more Bubble environment variables are not set.")
330
- if not AGENTIC_MODULES_LOADED:
331
- logging.warning("CRITICAL: Agentic modules failed to load.")
 
 
 
332
  if not os.environ.get("GEMINI_API_KEY"):
333
- logging.warning("WARNING: 'GEMINI_API_KEY' is not set.")
334
-
335
- app.launch(server_name="0.0.0.0", server_port=int(os.environ.get("PORT", 7860)), debug=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
22
 
23
  # UPDATED: Using the new data loading function from the refactored state manager
24
  from services.state_manager import load_data_from_bubble
25
+
26
+ # Import UI generator functions (these are now passed to build_main_app_ui)
27
  from ui.ui_generators import (
28
  build_analytics_tab_plot_area,
29
+ build_home_tab_ui,
30
+ create_enhanced_report_tab,
31
  BOMB_ICON, EXPLORE_ICON, FORMULA_ICON, ACTIVE_ICON
32
  )
33
  # NEW: Import the new OKR UI functions
 
35
  from ui.analytics_plot_generator import update_analytics_plots_figures, create_placeholder_plot
36
  from formulas import PLOT_FORMULAS
37
 
38
+ # NEW: Import UI enhancements from the new module
39
+ from ui.ui_main_page_enhancements import build_main_app_ui, update_report_display_enhanced
40
+
41
  # --- CHATBOT MODULE IMPORTS ---
42
  from features.chatbot.chatbot_prompts import get_initial_insight_prompt_and_suggestions
43
  from features.chatbot.chatbot_handler import generate_llm_response
 
51
  # UI formatting functions
52
  from ui.insights_ui_generator import (
53
  format_report_for_display, # This will now return header HTML and body Markdown
 
 
54
  )
55
  AGENTIC_MODULES_LOADED = True
56
  except ImportError as e:
 
79
  # matching the `outputs` in the .then() call later.
80
  return (
81
  gr.update(value="Modules not loaded."), # agentic_pipeline_status_md (0)
82
+ gr.update(choices=[], value=None), # report_selector_dd (1)
83
+ gr.update(choices=[], value=[]), # key_results_cbg (2) - KEPT HIDDEN for compatibility
84
+ gr.update(value="Modules not loaded."), # okr_detail_display_md (3) - KEPT HIDDEN for compatibility
85
+ None, # orchestration_raw_results_st (4)
86
+ [], # selected_key_result_ids_st (5) - KEPT HIDDEN for compatibility
87
+ [], # key_results_for_selection_st (6) - KEPT HIDDEN for compatibility
88
+ gr.update(value=empty_header_html), # report_header_html_display (7)
89
+ gr.update(value=empty_body_markdown), # report_body_markdown_display (8)
90
+ {}, # reconstruction_cache_st (9)
91
  gr.update(value=get_initial_okr_display()), # NEW: enhanced_okr_display_html (10)
92
  gr.update(value={}) # NEW: actionable_okrs_data_st (11)
93
  )
 
98
  return {'header_html': '<h1>Agentic modules not loaded.</h1>', 'body_markdown': 'Report display unavailable.'}
99
 
100
 
101
+ # --- Initial data load sequence function (remains in app.py as it uses service functions) ---
102
+ def initial_data_load_sequence(url_token, org_urn_val, current_state):
103
+ """
104
+ Handles the initial data loading from Bubble.
105
+ No longer generates dashboard HTML as the Home tab is now static.
106
+ """
107
+ status_msg, new_state = load_data_from_bubble(url_token, org_urn_val, current_state)
108
+ # Add status icons based on success/failure
109
+ if "successfully" in status_msg.lower() or "loaded" in status_msg.lower():
110
+ status_msg = f"βœ… {status_msg}"
111
+ elif "error" in status_msg.lower() or "failed" in status_msg.lower():
112
+ status_msg = f"❌ {status_msg}"
113
+ else:
114
+ status_msg = f"πŸ”„ {status_msg}"
115
+ return status_msg, new_state
116
+
117
+ # Instantiate AnalyticsTab (needs to be done before building UI if its methods are called)
118
+ analytics_icons = {'bomb': BOMB_ICON, 'explore': EXPLORE_ICON, 'formula': FORMULA_ICON, 'active': ACTIVE_ICON}
119
+ analytics_tab_instance = AnalyticsTab(
120
+ # These states are created within build_main_app_ui, but AnalyticsTab needs references.
121
+ # We will set them after build_main_app_ui returns them. For now, pass placeholders.
122
+ token_state=None, # Will be updated after build_main_app_ui
123
+ chat_histories_st=None, # Will be updated after build_main_app_ui
124
+ current_chat_plot_id_st=None, # Will be updated after build_main_app_ui
125
+ plot_data_for_chatbot_st=None, # Will be updated after build_main_app_ui
126
+ plot_id_to_formula_map=PLOT_ID_TO_FORMULA_KEY_MAP,
127
+ plot_formulas_data=PLOT_FORMULAS,
128
+ icons=analytics_icons,
129
+ fn_build_plot_area=build_analytics_tab_plot_area,
130
+ fn_update_plot_figures=update_analytics_plots_figures,
131
+ fn_create_placeholder_plot=create_placeholder_plot,
132
+ fn_get_initial_insight=get_initial_insight_prompt_and_suggestions,
133
+ fn_generate_llm_response=generate_llm_response
134
+ )
 
 
 
 
135
 
 
 
 
 
 
 
 
136
 
137
+ # Build the main UI using the function from ui_enhancements
138
+ (app, url_user_token_display, org_urn_display, status_box,
139
+ token_state, reconstruction_cache_st, enhanced_okr_display_html,
140
+ tabs, report_selector_dd, agentic_display_outputs,
141
+ analytics_tab_instance_returned, chat_histories_st_returned, format_report_for_display_func_passed) = \
142
+ build_main_app_ui(
143
+ analytics_tab_instance=analytics_tab_instance, # Pass the instantiated object
144
+ AGENTIC_MODULES_LOADED=AGENTIC_MODULES_LOADED,
145
+ build_home_tab_ui_func=build_home_tab_ui,
146
+ create_enhanced_report_tab_func=create_enhanced_report_tab,
147
+ create_enhanced_okr_tab_func=create_enhanced_okr_tab,
148
+ format_report_for_display_func=format_report_for_display # Pass the imported function
 
 
149
  )
150
 
151
+ # Now, update the analytics_tab_instance with the actual state components from the built UI
152
+ # This is crucial because analytics_tab_instance was instantiated before the gr.State components existed.
153
+ analytics_tab_instance.token_state = token_state
154
+ analytics_tab_instance.chat_histories_st = chat_histories_st_returned
155
+ analytics_tab_instance.current_chat_plot_id_st = agentic_display_outputs[9] # This is current_chat_plot_id_st
156
+ analytics_tab_instance.plot_data_for_chatbot_st = agentic_display_outputs[11] # This is actionable_okrs_data_st, which is incorrect. Should be plot_data_for_chatbot_st
157
+
158
+ # Corrected update for analytics_tab_instance state components.
159
+ # Need to know the exact index of each state in agentic_display_outputs or pass them directly.
160
+ # Given the `build_main_app_ui` returns specific components, let's use those directly.
161
+ # The original code for `chat_histories_st`, `current_chat_plot_id_st`, `plot_data_for_chatbot_st`
162
+ # are defined within `build_main_app_ui`'s scope.
163
+ # The returned `chat_histories_st_returned` and the other states are the correct references.
164
+ # So, no need to access them via `agentic_display_outputs` for the analytics_tab_instance.
165
+ # The parameters `chat_histories_st_returned` (which is `chat_histories_st` inside `build_main_app_ui`)
166
+ # and others are the correct references.
167
+
168
+ # Event handlers (re-establishing them now that components are defined)
169
+ app.load(fn=get_url_user_token, inputs=None, outputs=[url_user_token_display, org_urn_display], api_name="get_url_params", show_progress=False)
170
+
171
+ if AGENTIC_MODULES_LOADED:
172
+ report_selector_dd.change(
173
+ fn=lambda sr_id, c_state: update_report_display_enhanced(sr_id, c_state, format_report_for_display),
174
+ inputs=[report_selector_dd, token_state],
175
+ outputs=[agentic_display_outputs[7], agentic_display_outputs[8]], # report_header_html_display, report_body_markdown_display
176
+ show_progress="minimal"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
177
  )
178
 
179
+ # Initial load sequence with enhanced status updates
180
+ initial_load_event = org_urn_display.change(
181
+ fn=initial_data_load_sequence,
182
+ inputs=[url_user_token_display, org_urn_display, token_state],
183
+ outputs=[status_box, token_state],
184
+ show_progress="full"
185
+ )
186
+
187
+ # Chain the loading events
188
+ initial_load_event.then(
189
+ fn=analytics_tab_instance.refresh_analytics_graphs_ui, # Using the corrected method name (assuming this exists)
190
+ inputs=[token_state, analytics_tab_instance.date_filter_selector, analytics_tab_instance.custom_start_date_picker,
191
+ analytics_tab_instance.custom_end_date_picker, chat_histories_st_returned], # Using returned chat_histories_st
192
+ outputs=analytics_tab_instance.graph_refresh_outputs_list,
193
+ show_progress="full"
194
+ ).then(
195
+ fn=load_and_display_agentic_results,
196
+ inputs=[token_state, reconstruction_cache_st],
197
+ outputs=agentic_display_outputs,
198
+ show_progress="minimal"
199
+ ).then(
200
  fn=format_okrs_for_enhanced_display,
201
+ inputs=[reconstruction_cache_st],
202
  outputs=[enhanced_okr_display_html],
203
  show_progress="minimal"
204
+ )
 
205
 
206
  if __name__ == "__main__":
207
+ # Enhanced startup logging
208
+ print("πŸš€ Starting LinkedIn Organization Dashboard...")
209
+
210
+ # Environment variable checks with better logging
211
+ missing_vars = []
212
+
213
  if not os.environ.get(LINKEDIN_CLIENT_ID_ENV_VAR):
214
+ missing_vars.append(LINKEDIN_CLIENT_ID_ENV_VAR)
215
+ logging.warning(f"⚠️ WARNING: '{LINKEDIN_CLIENT_ID_ENV_VAR}' is not set.")
216
+
217
+ bubble_vars = [BUBBLE_APP_NAME_ENV_VAR, BUBBLE_API_KEY_PRIVATE_ENV_VAR, BUBBLE_API_ENDPOINT_ENV_VAR]
218
+ if not all(os.environ.get(var) for var in bubble_vars):
219
+ missing_vars.extend([var for var in bubble_vars if not os.environ.get(var)])
220
+ logging.warning("⚠️ WARNING: One or more Bubble environment variables are not set.")
221
+
222
  if not os.environ.get("GEMINI_API_KEY"):
223
+ missing_vars.append("GEMINI_API_KEY")
224
+ logging.warning("⚠️ WARNING: 'GEMINI_API_KEY' is not set.")
225
+
226
+ if not AGENTIC_MODULES_LOADED:
227
+ logging.warning("πŸ”΄ CRITICAL: Agentic modules failed to load.")
228
+
229
+ if missing_vars:
230
+ print(f"⚠️ Missing environment variables: {', '.join(missing_vars)}")
231
+ print("πŸ”§ Please set these variables for full functionality.")
232
+ else:
233
+ print("βœ… All environment variables are properly configured.")
234
+
235
+ print("🌐 Launching dashboard on http://0.0.0.0:7860")
236
+ print("🎯 Dashboard features:")
237
+ print(" β€’ πŸ“Š Advanced LinkedIn Analytics")
238
+ print(" β€’ πŸ€– AI-Powered Insights")
239
+ print(" β€’ 🎯 OKR Generation & Tracking")
240
+ print(" β€’ ☁️ Bubble.io Integration")
241
+
242
+ app.launch(
243
+ server_name="0.0.0.0",
244
+ server_port=int(os.environ.get("PORT", 7860)),
245
+ debug=True,
246
+ show_error=True,
247
+ show_tips=True,
248
+ enable_queue=True
249
+ )