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