# ui/analytics_tab_setup.py import gradio as gr from collections import OrderedDict from ui.ui_generators import ( build_analytics_tab_plot_area, # BOMB_ICON, EXPLORE_ICON, FORMULA_ICON, ACTIVE_ICON # These are used by handlers, not directly in setup ) import logging def get_plot_configurations(): """Return the plot configuration list.""" # This configuration should ideally live in a config file or be passed if it's dynamic plot_configs = [ {"label": "Numero di Follower nel Tempo", "id": "followers_count", "section": "Dinamiche dei Follower"}, {"label": "Tasso di Crescita Follower", "id": "followers_growth_rate", "section": "Dinamiche dei Follower"}, {"label": "Follower per Località", "id": "followers_by_location", "section": "Demografia Follower"}, {"label": "Follower per Ruolo (Funzione)", "id": "followers_by_role", "section": "Demografia Follower"}, {"label": "Follower per Settore", "id": "followers_by_industry", "section": "Demografia Follower"}, {"label": "Follower per Anzianità", "id": "followers_by_seniority", "section": "Demografia Follower"}, {"label": "Tasso di Engagement nel Tempo", "id": "engagement_rate", "section": "Approfondimenti Performance Post"}, {"label": "Copertura nel Tempo", "id": "reach_over_time", "section": "Approfondimenti Performance Post"}, {"label": "Visualizzazioni nel Tempo", "id": "impressions_over_time", "section": "Approfondimenti Performance Post"}, {"label": "Reazioni (Like) nel Tempo", "id": "likes_over_time", "section": "Approfondimenti Performance Post"}, {"label": "Click nel Tempo", "id": "clicks_over_time", "section": "Engagement Dettagliato Post nel Tempo"}, {"label": "Condivisioni nel Tempo", "id": "shares_over_time", "section": "Engagement Dettagliato Post nel Tempo"}, {"label": "Commenti nel Tempo", "id": "comments_over_time", "section": "Engagement Dettagliato Post nel Tempo"}, {"label": "Ripartizione Commenti per Sentiment", "id": "comments_sentiment", "section": "Engagement Dettagliato Post nel Tempo"}, {"label": "Frequenza Post", "id": "post_frequency_cs", "section": "Analisi Strategia Contenuti"}, {"label": "Ripartizione Contenuti per Formato", "id": "content_format_breakdown_cs", "section": "Analisi Strategia Contenuti"}, {"label": "Ripartizione Contenuti per Argomenti", "id": "content_topic_breakdown_cs", "section": "Analisi Strategia Contenuti"}, {"label": "Volume Menzioni nel Tempo (Dettaglio)", "id": "mention_analysis_volume", "section": "Analisi Menzioni (Dettaglio)"}, {"label": "Ripartizione Menzioni per Sentiment (Dettaglio)", "id": "mention_analysis_sentiment", "section": "Analisi Menzioni (Dettaglio)"} ] # IMPORTANT: Review if 'mention_analysis_volume' and 'mention_analysis_sentiment' plots # can still be generated without the dedicated mentions data processing. # If not, they should also be removed from plot_configs. # For now, I am assuming they might draw from a general data pool in token_state. assert len(plot_configs) == 19, "Mancata corrispondenza in plot_configs e grafici attesi. (If mentions plots were removed, adjust this number)" return plot_configs def _process_plot_area_result(ui_elements_tuple, unique_ordered_sections): """Process the result from build_analytics_tab_plot_area.""" plot_ui_objects = {} section_titles_map = {} if isinstance(ui_elements_tuple, tuple) and len(ui_elements_tuple) == 2: plot_ui_objects, section_titles_map = ui_elements_tuple # Validate section titles map if not all(sec_name in section_titles_map for sec_name in unique_ordered_sections): logging.error("section_titles_map from build_analytics_tab_plot_area is incomplete.") for sec_name in unique_ordered_sections: if sec_name not in section_titles_map: section_titles_map[sec_name] = gr.Markdown(f"### {sec_name} (Error Placeholder)") else: logging.error("build_analytics_tab_plot_area did not return a tuple of (plot_ui_objects, section_titles_map).") # Fallback: ui_elements_tuple might be just plot_ui_objects if build_analytics_tab_plot_area changed plot_ui_objects = ui_elements_tuple if isinstance(ui_elements_tuple, dict) else {} for sec_name in unique_ordered_sections: section_titles_map[sec_name] = gr.Markdown(f"### {sec_name} (Error Placeholder)") return plot_ui_objects, section_titles_map def _setup_action_panel(): """Set up the action panel with insights chat and formula display.""" gr.Markdown("### 💡 Azioni Contestuali Grafico") insights_chatbot_ui = gr.Chatbot( label="Chat Insights", type="messages", height=450, bubble_full_width=False, visible=False, show_label=False, placeholder="L'analisi AI del grafico apparirà qui. Fai domande di approfondimento!" ) insights_chat_input_ui = gr.Textbox( label="La tua domanda:", placeholder="Chiedi all'AI riguardo a questo grafico...", lines=2, visible=False, show_label=False ) with gr.Row(visible=False) as insights_suggestions_row_ui: insights_suggestion_1_btn = gr.Button(value="Suggerimento 1", size="sm", min_width=50) insights_suggestion_2_btn = gr.Button(value="Suggerimento 2", size="sm", min_width=50) insights_suggestion_3_btn = gr.Button(value="Suggerimento 3", size="sm", min_width=50) formula_display_markdown_ui = gr.Markdown( "I dettagli sulla formula/metodologia appariranno qui.", visible=False ) formula_close_hint_md = gr.Markdown( "

" "Click the active ƒ button on the plot again to close this panel.

", visible=False ) return { 'insights_chatbot_ui': insights_chatbot_ui, 'insights_chat_input_ui': insights_chat_input_ui, 'insights_suggestions_row_ui': insights_suggestions_row_ui, 'insights_suggestion_1_btn': insights_suggestion_1_btn, 'insights_suggestion_2_btn': insights_suggestion_2_btn, 'insights_suggestion_3_btn': insights_suggestion_3_btn, 'formula_display_markdown_ui': formula_display_markdown_ui, 'formula_close_hint_md': formula_close_hint_md } def setup_analytics_tab(): """Set up the analytics tab with all its components and return component references.""" gr.Markdown("## 📈 Analisi Performance LinkedIn") gr.Markdown("Seleziona un intervallo di date per i grafici. Clicca i pulsanti (💣 Insights, ƒ Formula, 🧭 Esplora) su un grafico per azioni.") analytics_status_md = gr.Markdown("Stato analisi grafici...") # Date filter controls with gr.Row(): date_filter_selector = gr.Radio( ["Sempre", "Ultimi 7 Giorni", "Ultimi 30 Giorni", "Intervallo Personalizzato"], label="Seleziona Intervallo Date per Grafici", value="Sempre", scale=3 ) with gr.Column(scale=2): custom_start_date_picker = gr.DateTime( label="Data Inizio", visible=False, include_time=False, type="datetime" # Ensure this matches expected type by handlers/plotters ) custom_end_date_picker = gr.DateTime( label="Data Fine", visible=False, include_time=False, type="datetime" # Ensure this matches ) apply_filter_btn = gr.Button("🔍 Applica Filtro & Aggiorna Grafici", variant="primary") # Set up date picker visibility toggle def toggle_custom_date_pickers(selection): is_custom = selection == "Intervallo Personalizzato" return gr.update(visible=is_custom), gr.update(visible=is_custom) date_filter_selector.change( fn=toggle_custom_date_pickers, inputs=[date_filter_selector], outputs=[custom_start_date_picker, custom_end_date_picker] ) # Plot configurations plot_configs = get_plot_configurations() unique_ordered_sections = list(OrderedDict.fromkeys(pc["section"] for pc in plot_configs)) num_unique_sections = len(unique_ordered_sections) # State components (defined in main app.py, but listed here for clarity of what this tab might conceptually own or interact with) # active_panel_action_state = gr.State(None) # Managed by main app # explored_plot_id_state = gr.State(None) # Managed by main app # Build plot area plot_ui_objects = {} section_titles_map = {} global_actions_column_ui = None # Define it to ensure it's in scope action_components = {} # Define it with gr.Row(equal_height=False): with gr.Column(scale=8) as plots_area_col: # This function is expected to create the actual plot components (e.g., gr.Plot) # and their associated action buttons (bomb, formula, explore) # It should return a dictionary of these plot UI objects and section title markdowns ui_elements_tuple = build_analytics_tab_plot_area(plot_configs) plot_ui_objects, section_titles_map = _process_plot_area_result( ui_elements_tuple, unique_ordered_sections ) # Action panel (global for the tab, shown/hidden based on plot interactions) with gr.Column(scale=4, visible=False) as global_actions_col: # Assign to variable global_actions_column_ui = global_actions_col # Store the column itself action_components = _setup_action_panel() # Package all components for return, so handlers can connect to them components = { 'analytics_status_md': analytics_status_md, 'date_filter_selector': date_filter_selector, 'custom_start_date_picker': custom_start_date_picker, 'custom_end_date_picker': custom_end_date_picker, 'apply_filter_btn': apply_filter_btn, 'plot_configs': plot_configs, # Pass config for handlers 'unique_ordered_sections': unique_ordered_sections, # Pass for handlers 'num_unique_sections': num_unique_sections, # Pass for handlers 'plot_ui_objects': plot_ui_objects, # Key for handlers to connect events 'section_titles_map': section_titles_map, # Key for handlers to update visibility 'global_actions_column_ui': global_actions_column_ui, # The visibility of this entire column is controlled **action_components # Spread the dict from _setup_action_panel } return components