GuglielmoTor commited on
Commit
265cb73
·
verified ·
1 Parent(s): 1644cc1

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +41 -66
app.py CHANGED
@@ -23,8 +23,8 @@ from state_manager import process_and_store_bubble_token
23
  from sync_logic import sync_all_linkedin_data_orchestrator
24
  from ui_generators import (
25
  display_main_dashboard,
26
- run_mentions_tab_display,
27
- run_follower_stats_tab_display,
28
  build_analytics_tab_plot_area, # EXPECTED TO RETURN: plot_ui_objects, section_titles_map
29
  BOMB_ICON, EXPLORE_ICON, FORMULA_ICON, ACTIVE_ICON
30
  )
@@ -46,7 +46,7 @@ try:
46
  )
47
  AGENTIC_MODULES_LOADED = True
48
  except ImportError as e:
49
- logging.error(f"Could not import agentic pipeline modules: {e}. Tabs 5 and 6 will be disabled.")
50
  AGENTIC_MODULES_LOADED = False
51
  # Define placeholder functions if modules are not loaded to avoid NameErrors
52
  async def run_full_analytics_orchestration(*args, **kwargs): return None
@@ -76,7 +76,8 @@ with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue", secondary_hue="sky"),
76
  token_state = gr.State(value={
77
  "token": None, "client_id": None, "org_urn": None,
78
  "bubble_posts_df": pd.DataFrame(), "bubble_post_stats_df": pd.DataFrame(),
79
- "bubble_mentions_df": pd.DataFrame(), "bubble_follower_stats_df": pd.DataFrame(),
 
80
  "fetch_count_for_api": 0, "url_user_token_temp_storage": None,
81
  "config_date_col_posts": "published_at", "config_date_col_mentions": "date",
82
  "config_date_col_followers": "date", "config_media_type_col": "media_type",
@@ -113,25 +114,21 @@ with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue", secondary_hue="sky"),
113
  sync_status_html_output = gr.HTML("<p style='text-align:center;'>Stato sincronizzazione...</p>")
114
  dashboard_display_html = gr.HTML("<p style='text-align:center;'>Caricamento dashboard...</p>")
115
 
116
- # Initial load sequence will be defined later with .then() for agentic pipeline
117
- # org_urn_display.change(...)
118
-
119
- with gr.TabItem("2️⃣ Analisi", id="tab_analytics"):
120
  gr.Markdown("## 📈 Analisi Performance LinkedIn")
121
  gr.Markdown("Seleziona un intervallo di date per i grafici. Clicca i pulsanti (💣 Insights, ƒ Formula, 🧭 Esplora) su un grafico per azioni.")
122
  analytics_status_md = gr.Markdown("Stato analisi grafici...")
123
- # Agentic pipeline status will be moved to Tab 5
124
 
125
  with gr.Row():
126
  date_filter_selector = gr.Radio(
127
  ["Sempre", "Ultimi 7 Giorni", "Ultimi 30 Giorni", "Intervallo Personalizzato"],
128
- label="Seleziona Intervallo Date per Grafici", value="Sempre", scale=3 # Clarified label
129
  )
130
  with gr.Column(scale=2):
131
  custom_start_date_picker = gr.DateTime(label="Data Inizio", visible=False, include_time=False, type="datetime")
132
  custom_end_date_picker = gr.DateTime(label="Data Fine", visible=False, include_time=False, type="datetime")
133
 
134
- apply_filter_btn = gr.Button("🔍 Applica Filtro & Aggiorna Grafici", variant="primary") # Clarified button text
135
 
136
  def toggle_custom_date_pickers(selection):
137
  is_custom = selection == "Intervallo Personalizzato"
@@ -161,10 +158,15 @@ with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue", secondary_hue="sky"),
161
  {"label": "Frequenza Post", "id": "post_frequency_cs", "section": "Analisi Strategia Contenuti"},
162
  {"label": "Ripartizione Contenuti per Formato", "id": "content_format_breakdown_cs", "section": "Analisi Strategia Contenuti"},
163
  {"label": "Ripartizione Contenuti per Argomenti", "id": "content_topic_breakdown_cs", "section": "Analisi Strategia Contenuti"},
164
- {"label": "Volume Menzioni nel Tempo (Dettaglio)", "id": "mention_analysis_volume", "section": "Analisi Menzioni (Dettaglio)"},
165
- {"label": "Ripartizione Menzioni per Sentiment (Dettaglio)", "id": "mention_analysis_sentiment", "section": "Analisi Menzioni (Dettaglio)"}
166
  ]
167
- assert len(plot_configs) == 19, "Mancata corrispondenza in plot_configs e grafici attesi."
 
 
 
 
 
168
 
169
  unique_ordered_sections = list(OrderedDict.fromkeys(pc["section"] for pc in plot_configs))
170
  num_unique_sections = len(unique_ordered_sections)
@@ -378,28 +380,16 @@ with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue", secondary_hue="sky"),
378
  insights_suggestion_2_btn.click(fn=handle_suggested_question_click, inputs=[insights_suggestion_2_btn] + suggestion_click_inputs_base, outputs=chat_submission_outputs, api_name="click_suggestion_2")
379
  insights_suggestion_3_btn.click(fn=handle_suggested_question_click, inputs=[insights_suggestion_3_btn] + suggestion_click_inputs_base, outputs=chat_submission_outputs, api_name="click_suggestion_3")
380
 
381
- with gr.TabItem("3️⃣ Menzioni", id="tab_mentions"):
382
- refresh_mentions_display_btn = gr.Button("🔄 Aggiorna Visualizzazione Menzioni", variant="secondary")
383
- mentions_html = gr.HTML("Dati menzioni...")
384
- mentions_sentiment_dist_plot = gr.Plot(label="Distribuzione Sentiment Menzioni")
385
- refresh_mentions_display_btn.click(fn=run_mentions_tab_display, inputs=[token_state], outputs=[mentions_html, mentions_sentiment_dist_plot], show_progress="full")
386
-
387
- with gr.TabItem("4️⃣ Statistiche Follower", id="tab_follower_stats"):
388
- refresh_follower_stats_btn = gr.Button("🔄 Aggiorna Visualizzazione Statistiche Follower", variant="secondary")
389
- follower_stats_html = gr.HTML("Statistiche follower...")
390
- with gr.Row(): fs_plot_monthly_gains = gr.Plot(label="Guadagni Mensili Follower")
391
- with gr.Row(): fs_plot_seniority = gr.Plot(label="Follower per Anzianità (Top 10 Organici)"); fs_plot_industry = gr.Plot(label="Follower per Settore (Top 10 Organici)")
392
- refresh_follower_stats_btn.click(fn=run_follower_stats_tab_display, inputs=[token_state], outputs=[follower_stats_html, fs_plot_monthly_gains, fs_plot_seniority, fs_plot_industry], show_progress="full")
393
-
394
- with gr.TabItem("5️⃣ Agentic Analysis Report", id="tab_agentic_report", visible=AGENTIC_MODULES_LOADED):
395
  gr.Markdown("## 🤖 Comprehensive Analysis Report (AI Generated)")
396
- # Moved agentic_pipeline_status_md here
397
  agentic_pipeline_status_md = gr.Markdown("Stato Pipeline AI (filtro 'Sempre'): In attesa...", visible=True)
398
  gr.Markdown("Questo report è generato da un agente AI con filtro 'Sempre' sui dati disponibili. Rivedi criticamente.")
399
  agentic_report_display_md = gr.Markdown("La pipeline AI si avvierà automaticamente dopo il caricamento iniziale dei dati o dopo una sincronizzazione.")
400
  if not AGENTIC_MODULES_LOADED: gr.Markdown("🔴 **Error:** Agentic pipeline modules could not be loaded. This tab is disabled.")
401
 
402
- with gr.TabItem("6️⃣ Agentic OKRs & Tasks", id="tab_agentic_okrs", visible=AGENTIC_MODULES_LOADED):
403
  gr.Markdown("## 🎯 AI Generated OKRs and Actionable Tasks (filtro 'Sempre')")
404
  gr.Markdown("Basato sull'analisi AI (filtro 'Sempre'), l'agente ha proposto i seguenti OKR e task. Seleziona i Key Results per dettagli.")
405
  if not AGENTIC_MODULES_LOADED: gr.Markdown("🔴 **Error:** Agentic pipeline modules could not be loaded. This tab is disabled.")
@@ -453,24 +443,16 @@ with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue", secondary_hue="sky"),
453
  logging.info(f"Prepared {len(all_updates)} updates for graph refresh. Expected {expected_len}.")
454
  return tuple(all_updates)
455
 
456
- async def run_agentic_pipeline_autonomously(current_token_state_val, request: gr.Request):
457
- # Added request: gr.Request to check if it's the initial call or subsequent.
458
- # This is a simple way to prevent multiple rapid fires if not needed,
459
- # though ideally Gradio's event system handles this.
460
- # For more robust control, a separate state could track if the pipeline has run for current data.
461
- client_ip = request.client.host if request else "unknown_client"
462
- logging.info(f"Agentic pipeline check triggered for token_state update from {client_ip}. Current token: {'Set' if current_token_state_val.get('token') else 'Not Set'}")
463
 
464
  if not current_token_state_val or not current_token_state_val.get("token"):
465
  logging.info("Agentic pipeline: Token not available in token_state. Skipping.")
466
- yield ( # Yield initial "waiting" state if token not ready
467
- gr.update(value="Pipeline AI: In attesa dei dati necessari..."), # agentic_report_display_md
468
- gr.update(choices=[], value=[], interactive=False), # key_results_cbg
469
- gr.update(value="Pipeline AI: In attesa dei dati necessari..."), # okr_detail_display_md
470
- None, # orchestration_raw_results_st
471
- [], # selected_key_result_ids_st
472
- [], # key_results_for_selection_st
473
- "Pipeline AI: In attesa dei dati..." # agentic_pipeline_status_md
474
  )
475
  return
476
 
@@ -479,9 +461,9 @@ with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue", secondary_hue="sky"),
479
  gr.update(value="Analisi AI (Sempre) in corso..."),
480
  gr.update(choices=[], value=[], interactive=False),
481
  gr.update(value="Dettagli OKR (Sempre) in corso di generazione..."),
482
- None, # orchestration_raw_results_st (don't overwrite with None if it already has results)
483
- [], # selected_key_result_ids_st
484
- [], # key_results_for_selection_st
485
  "Esecuzione pipeline AI (Sempre)..."
486
  )
487
 
@@ -539,9 +521,8 @@ with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue", secondary_hue="sky"),
539
  agentic_pipeline_outputs_list = [agentic_report_display_md, key_results_cbg, okr_detail_display_md, orchestration_raw_results_st, selected_key_result_ids_st, key_results_for_selection_st, agentic_pipeline_status_md]
540
 
541
  graph_refresh_inputs = [token_state, date_filter_selector, custom_start_date_picker, custom_end_date_picker, chat_histories_st]
542
- agentic_pipeline_inputs = [token_state] # Removed request for now, can be added back if needed for advanced logic
543
 
544
- # Event for Apply Filter Button (only refreshes graphs)
545
  apply_filter_btn.click(
546
  fn=refresh_analytics_graphs_ui,
547
  inputs=graph_refresh_inputs,
@@ -549,28 +530,24 @@ with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue", secondary_hue="sky"),
549
  show_progress="full"
550
  )
551
 
552
- # --- Event Chains for Initial Load and Sync ---
553
- # Initial Load
554
  initial_load_event = org_urn_display.change(
555
  fn=initial_load_sequence,
556
  inputs=[url_user_token_display, org_urn_display, token_state],
557
  outputs=[status_box, token_state, sync_data_btn, dashboard_display_html],
558
  show_progress="full"
559
  )
560
- # After initial load, refresh graphs AND run agentic pipeline
561
  initial_load_event.then(
562
- fn=refresh_analytics_graphs_ui, # Refresh graphs with default "Sempre" filter
563
- inputs=[token_state, date_filter_selector, custom_start_date_picker, custom_end_date_picker, chat_histories_st], # date_filter_selector will provide "Sempre"
564
  outputs=graph_refresh_outputs_list,
565
  show_progress="full"
566
  ).then(
567
- fn=run_agentic_pipeline_autonomously, # Run agentic pipeline
568
- inputs=agentic_pipeline_inputs, # Uses token_state
569
  outputs=agentic_pipeline_outputs_list,
570
  show_progress="minimal"
571
  )
572
 
573
- # Sync Process
574
  sync_event_part1 = sync_data_btn.click(
575
  fn=sync_all_linkedin_data_orchestrator,
576
  inputs=[token_state],
@@ -580,17 +557,15 @@ with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue", secondary_hue="sky"),
580
  sync_event_part2 = sync_event_part1.then(
581
  fn=process_and_store_bubble_token,
582
  inputs=[url_user_token_display, org_urn_display, token_state],
583
- outputs=[status_box, token_state, sync_data_btn], # token_state is updated here
584
  show_progress=False
585
  )
586
- # After token_state is updated by sync, run agentic pipeline
587
- sync_event_part2.then(
588
  fn=run_agentic_pipeline_autonomously,
589
- inputs=agentic_pipeline_inputs, # Uses updated token_state
590
  outputs=agentic_pipeline_outputs_list,
591
  show_progress="minimal"
592
  )
593
- # Separately, update dashboard and graphs after sync
594
  sync_event_part3 = sync_event_part2.then(
595
  fn=display_main_dashboard,
596
  inputs=[token_state],
@@ -609,8 +584,8 @@ if __name__ == "__main__":
609
  if not os.environ.get(LINKEDIN_CLIENT_ID_ENV_VAR): logging.warning(f"ATTENZIONE: '{LINKEDIN_CLIENT_ID_ENV_VAR}' non impostata.")
610
  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]):
611
  logging.warning("ATTENZIONE: Variabili Bubble non impostate.")
612
- if not AGENTIC_MODULES_LOADED: logging.warning("CRITICAL: Agentic pipeline modules failed to load. Tabs 5 and 6 will be non-functional.")
613
- if not os.environ.get("GEMINI_API_KEY") and AGENTIC_MODULES_LOADED: logging.warning("ATTENZIONE: 'GEMINI_API_KEY' non impostata. La pipeline AI per le tab 5 e 6 potrebbe non funzionare.")
614
  try: logging.info(f"Matplotlib: {matplotlib.__version__}, Backend: {matplotlib.get_backend()}")
615
  except ImportError: logging.warning("Matplotlib non trovato.")
616
- app.launch(server_name="0.0.0.0", server_port=7860, debug=True)
 
23
  from sync_logic import sync_all_linkedin_data_orchestrator
24
  from ui_generators import (
25
  display_main_dashboard,
26
+ # run_mentions_tab_display, # Removed
27
+ # run_follower_stats_tab_display, # Removed
28
  build_analytics_tab_plot_area, # EXPECTED TO RETURN: plot_ui_objects, section_titles_map
29
  BOMB_ICON, EXPLORE_ICON, FORMULA_ICON, ACTIVE_ICON
30
  )
 
46
  )
47
  AGENTIC_MODULES_LOADED = True
48
  except ImportError as e:
49
+ logging.error(f"Could not import agentic pipeline modules: {e}. Tabs 3 and 4 (formerly 5 and 6) will be disabled.")
50
  AGENTIC_MODULES_LOADED = False
51
  # Define placeholder functions if modules are not loaded to avoid NameErrors
52
  async def run_full_analytics_orchestration(*args, **kwargs): return None
 
76
  token_state = gr.State(value={
77
  "token": None, "client_id": None, "org_urn": None,
78
  "bubble_posts_df": pd.DataFrame(), "bubble_post_stats_df": pd.DataFrame(),
79
+ "bubble_mentions_df": pd.DataFrame(), # Data still in state, but not used by UI
80
+ "bubble_follower_stats_df": pd.DataFrame(), # Data still in state, but not used by UI
81
  "fetch_count_for_api": 0, "url_user_token_temp_storage": None,
82
  "config_date_col_posts": "published_at", "config_date_col_mentions": "date",
83
  "config_date_col_followers": "date", "config_media_type_col": "media_type",
 
114
  sync_status_html_output = gr.HTML("<p style='text-align:center;'>Stato sincronizzazione...</p>")
115
  dashboard_display_html = gr.HTML("<p style='text-align:center;'>Caricamento dashboard...</p>")
116
 
117
+ with gr.TabItem("2️⃣ Analisi Grafici", id="tab_analytics"): # Renamed for clarity
 
 
 
118
  gr.Markdown("## 📈 Analisi Performance LinkedIn")
119
  gr.Markdown("Seleziona un intervallo di date per i grafici. Clicca i pulsanti (💣 Insights, ƒ Formula, 🧭 Esplora) su un grafico per azioni.")
120
  analytics_status_md = gr.Markdown("Stato analisi grafici...")
 
121
 
122
  with gr.Row():
123
  date_filter_selector = gr.Radio(
124
  ["Sempre", "Ultimi 7 Giorni", "Ultimi 30 Giorni", "Intervallo Personalizzato"],
125
+ label="Seleziona Intervallo Date per Grafici", value="Sempre", scale=3
126
  )
127
  with gr.Column(scale=2):
128
  custom_start_date_picker = gr.DateTime(label="Data Inizio", visible=False, include_time=False, type="datetime")
129
  custom_end_date_picker = gr.DateTime(label="Data Fine", visible=False, include_time=False, type="datetime")
130
 
131
+ apply_filter_btn = gr.Button("🔍 Applica Filtro & Aggiorna Grafici", variant="primary")
132
 
133
  def toggle_custom_date_pickers(selection):
134
  is_custom = selection == "Intervallo Personalizzato"
 
158
  {"label": "Frequenza Post", "id": "post_frequency_cs", "section": "Analisi Strategia Contenuti"},
159
  {"label": "Ripartizione Contenuti per Formato", "id": "content_format_breakdown_cs", "section": "Analisi Strategia Contenuti"},
160
  {"label": "Ripartizione Contenuti per Argomenti", "id": "content_topic_breakdown_cs", "section": "Analisi Strategia Contenuti"},
161
+ {"label": "Volume Menzioni nel Tempo (Dettaglio)", "id": "mention_analysis_volume", "section": "Analisi Menzioni (Dettaglio)"}, # This plot might need data from the removed mentions tab. Consider if this plot should also be removed or if its data source is independent.
162
+ {"label": "Ripartizione Menzioni per Sentiment (Dettaglio)", "id": "mention_analysis_sentiment", "section": "Analisi Menzioni (Dettaglio)"} # Same as above.
163
  ]
164
+ # IMPORTANT: Review if 'mention_analysis_volume' and 'mention_analysis_sentiment' plots
165
+ # can still be generated without the dedicated mentions data processing.
166
+ # If not, they should also be removed from plot_configs.
167
+ # For now, I am assuming they might draw from a general data pool in token_state.
168
+
169
+ assert len(plot_configs) == 19, "Mancata corrispondenza in plot_configs e grafici attesi. (If mentions plots were removed, adjust this number)"
170
 
171
  unique_ordered_sections = list(OrderedDict.fromkeys(pc["section"] for pc in plot_configs))
172
  num_unique_sections = len(unique_ordered_sections)
 
380
  insights_suggestion_2_btn.click(fn=handle_suggested_question_click, inputs=[insights_suggestion_2_btn] + suggestion_click_inputs_base, outputs=chat_submission_outputs, api_name="click_suggestion_2")
381
  insights_suggestion_3_btn.click(fn=handle_suggested_question_click, inputs=[insights_suggestion_3_btn] + suggestion_click_inputs_base, outputs=chat_submission_outputs, api_name="click_suggestion_3")
382
 
383
+ # Tab 3 (Menzioni) and Tab 4 (Statistiche Follower) are removed.
384
+
385
+ with gr.TabItem("3️⃣ Agentic Analysis Report", id="tab_agentic_report", visible=AGENTIC_MODULES_LOADED): # Renumbered from 5
 
 
 
 
 
 
 
 
 
 
 
386
  gr.Markdown("## 🤖 Comprehensive Analysis Report (AI Generated)")
 
387
  agentic_pipeline_status_md = gr.Markdown("Stato Pipeline AI (filtro 'Sempre'): In attesa...", visible=True)
388
  gr.Markdown("Questo report è generato da un agente AI con filtro 'Sempre' sui dati disponibili. Rivedi criticamente.")
389
  agentic_report_display_md = gr.Markdown("La pipeline AI si avvierà automaticamente dopo il caricamento iniziale dei dati o dopo una sincronizzazione.")
390
  if not AGENTIC_MODULES_LOADED: gr.Markdown("🔴 **Error:** Agentic pipeline modules could not be loaded. This tab is disabled.")
391
 
392
+ with gr.TabItem("4️⃣ Agentic OKRs & Tasks", id="tab_agentic_okrs", visible=AGENTIC_MODULES_LOADED): # Renumbered from 6
393
  gr.Markdown("## 🎯 AI Generated OKRs and Actionable Tasks (filtro 'Sempre')")
394
  gr.Markdown("Basato sull'analisi AI (filtro 'Sempre'), l'agente ha proposto i seguenti OKR e task. Seleziona i Key Results per dettagli.")
395
  if not AGENTIC_MODULES_LOADED: gr.Markdown("🔴 **Error:** Agentic pipeline modules could not be loaded. This tab is disabled.")
 
443
  logging.info(f"Prepared {len(all_updates)} updates for graph refresh. Expected {expected_len}.")
444
  return tuple(all_updates)
445
 
446
+ async def run_agentic_pipeline_autonomously(current_token_state_val): # Removed request: gr.Request for simplicity
447
+ logging.info(f"Agentic pipeline check triggered for token_state update. Current token: {'Set' if current_token_state_val.get('token') else 'Not Set'}")
 
 
 
 
 
448
 
449
  if not current_token_state_val or not current_token_state_val.get("token"):
450
  logging.info("Agentic pipeline: Token not available in token_state. Skipping.")
451
+ yield (
452
+ gr.update(value="Pipeline AI: In attesa dei dati necessari..."),
453
+ gr.update(choices=[], value=[], interactive=False),
454
+ gr.update(value="Pipeline AI: In attesa dei dati necessari..."),
455
+ None, [], [], "Pipeline AI: In attesa dei dati..."
 
 
 
456
  )
457
  return
458
 
 
461
  gr.update(value="Analisi AI (Sempre) in corso..."),
462
  gr.update(choices=[], value=[], interactive=False),
463
  gr.update(value="Dettagli OKR (Sempre) in corso di generazione..."),
464
+ orchestration_raw_results_st.value, # Preserve existing results if any during processing
465
+ selected_key_result_ids_st.value,
466
+ key_results_for_selection_st.value,
467
  "Esecuzione pipeline AI (Sempre)..."
468
  )
469
 
 
521
  agentic_pipeline_outputs_list = [agentic_report_display_md, key_results_cbg, okr_detail_display_md, orchestration_raw_results_st, selected_key_result_ids_st, key_results_for_selection_st, agentic_pipeline_status_md]
522
 
523
  graph_refresh_inputs = [token_state, date_filter_selector, custom_start_date_picker, custom_end_date_picker, chat_histories_st]
524
+ agentic_pipeline_inputs = [token_state]
525
 
 
526
  apply_filter_btn.click(
527
  fn=refresh_analytics_graphs_ui,
528
  inputs=graph_refresh_inputs,
 
530
  show_progress="full"
531
  )
532
 
 
 
533
  initial_load_event = org_urn_display.change(
534
  fn=initial_load_sequence,
535
  inputs=[url_user_token_display, org_urn_display, token_state],
536
  outputs=[status_box, token_state, sync_data_btn, dashboard_display_html],
537
  show_progress="full"
538
  )
 
539
  initial_load_event.then(
540
+ fn=refresh_analytics_graphs_ui,
541
+ inputs=[token_state, date_filter_selector, custom_start_date_picker, custom_end_date_picker, chat_histories_st],
542
  outputs=graph_refresh_outputs_list,
543
  show_progress="full"
544
  ).then(
545
+ fn=run_agentic_pipeline_autonomously,
546
+ inputs=agentic_pipeline_inputs,
547
  outputs=agentic_pipeline_outputs_list,
548
  show_progress="minimal"
549
  )
550
 
 
551
  sync_event_part1 = sync_data_btn.click(
552
  fn=sync_all_linkedin_data_orchestrator,
553
  inputs=[token_state],
 
557
  sync_event_part2 = sync_event_part1.then(
558
  fn=process_and_store_bubble_token,
559
  inputs=[url_user_token_display, org_urn_display, token_state],
560
+ outputs=[status_box, token_state, sync_data_btn],
561
  show_progress=False
562
  )
563
+ sync_event_part2.then( # This will now use the updated token_state from process_and_store_bubble_token
 
564
  fn=run_agentic_pipeline_autonomously,
565
+ inputs=agentic_pipeline_inputs, # token_state is the first element
566
  outputs=agentic_pipeline_outputs_list,
567
  show_progress="minimal"
568
  )
 
569
  sync_event_part3 = sync_event_part2.then(
570
  fn=display_main_dashboard,
571
  inputs=[token_state],
 
584
  if not os.environ.get(LINKEDIN_CLIENT_ID_ENV_VAR): logging.warning(f"ATTENZIONE: '{LINKEDIN_CLIENT_ID_ENV_VAR}' non impostata.")
585
  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]):
586
  logging.warning("ATTENZIONE: Variabili Bubble non impostate.")
587
+ if not AGENTIC_MODULES_LOADED: logging.warning("CRITICAL: Agentic pipeline modules failed to load. Tabs 3 and 4 (formerly 5 and 6) will be non-functional.")
588
+ if not os.environ.get("GEMINI_API_KEY") and AGENTIC_MODULES_LOADED: logging.warning("ATTENZIONE: 'GEMINI_API_KEY' non impostata. La pipeline AI per le tab 3 e 4 potrebbe non funzionare.")
589
  try: logging.info(f"Matplotlib: {matplotlib.__version__}, Backend: {matplotlib.get_backend()}")
590
  except ImportError: logging.warning("Matplotlib non trovato.")
591
+ app.launch(server_name="0.0.0.0", server_port=7860, debug=True)