LinkedinMonitor / ui /analytics_tab_setup.py
GuglielmoTor's picture
Create analytics_tab_setup.py
55594d3 verified
raw
history blame
10.8 kB
# 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