Spaces:
Running
Running
File size: 10,799 Bytes
55594d3 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 |
# 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
|