Spaces:
Running
Running
# 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( | |
"<p style='font-size:0.9em; text-align:center; margin-top:10px;'>" | |
"<em>Click the active ƒ button on the plot again to close this panel.</em></p>", | |
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 | |