Spaces:
Running
Running
Update app.py
Browse files
app.py
CHANGED
@@ -132,40 +132,30 @@ with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue", secondary_hue="sky"),
|
|
132 |
]
|
133 |
assert len(plot_configs) == 19, "Mancata corrispondenza in plot_configs e grafici attesi."
|
134 |
|
135 |
-
# Get unique section names in order of appearance in plot_configs
|
136 |
unique_ordered_sections = list(OrderedDict.fromkeys(pc["section"] for pc in plot_configs))
|
137 |
num_unique_sections = len(unique_ordered_sections)
|
138 |
|
139 |
active_panel_action_state = gr.State(None)
|
140 |
explored_plot_id_state = gr.State(None)
|
141 |
|
142 |
-
# plot_ui_objects will store plot-specific UI like panels and buttons
|
143 |
-
# section_titles_map will store Markdown components for section titles
|
144 |
plot_ui_objects = {}
|
145 |
-
section_titles_map = {}
|
146 |
|
147 |
with gr.Row(equal_height=False):
|
148 |
with gr.Column(scale=8) as plots_area_col:
|
149 |
-
|
150 |
-
# (dict_of_plot_ui_elements, dict_of_section_title_markdown_components)
|
151 |
-
# Ensure ui_generators.py is updated accordingly.
|
152 |
-
ui_elements_tuple = build_analytics_tab_plot_area(plot_configs)
|
153 |
if isinstance(ui_elements_tuple, tuple) and len(ui_elements_tuple) == 2:
|
154 |
-
plot_ui_objects = ui_elements_tuple
|
155 |
-
section_titles_map = ui_elements_tuple[1]
|
156 |
-
# Verify section_titles_map contains all unique_ordered_sections
|
157 |
if not all(sec_name in section_titles_map for sec_name in unique_ordered_sections):
|
158 |
-
logging.error("section_titles_map from build_analytics_tab_plot_area is incomplete
|
159 |
-
# Fallback for safety, though this indicates an issue in ui_generators
|
160 |
for sec_name in unique_ordered_sections:
|
161 |
if sec_name not in section_titles_map:
|
162 |
-
section_titles_map[sec_name] = gr.Markdown(f"
|
163 |
else:
|
164 |
-
logging.error("build_analytics_tab_plot_area did not return
|
165 |
-
plot_ui_objects = ui_elements_tuple
|
166 |
-
|
167 |
-
|
168 |
-
section_titles_map[sec_name] = gr.Markdown(f"## {sec_name} (Placeholder - Error)")
|
169 |
|
170 |
|
171 |
with gr.Column(scale=4, visible=False) as global_actions_column_ui:
|
@@ -187,34 +177,32 @@ with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue", secondary_hue="sky"),
|
|
187 |
formula_display_markdown_ui = gr.Markdown(
|
188 |
"I dettagli sulla formula/metodologia appariranno qui.", visible=False
|
189 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
190 |
|
191 |
async def handle_panel_action(
|
192 |
-
plot_id_clicked: str,
|
193 |
-
|
194 |
-
|
195 |
-
current_chat_histories: dict,
|
196 |
-
current_chat_plot_id: str,
|
197 |
-
current_plot_data_for_chatbot: dict,
|
198 |
-
current_explored_plot_id: str
|
199 |
):
|
200 |
-
logging.info(f"
|
201 |
|
202 |
clicked_plot_config = next((p for p in plot_configs if p["id"] == plot_id_clicked), None)
|
203 |
if not clicked_plot_config:
|
204 |
-
logging.error(f"
|
|
|
205 |
num_plots = len(plot_configs)
|
206 |
-
|
207 |
-
|
208 |
-
|
209 |
-
|
210 |
-
|
211 |
-
|
212 |
-
|
213 |
-
error_output_list.extend([gr.update()] * num_plots) # Panel vis
|
214 |
-
error_output_list.extend([gr.update()] * (2 * num_plots)) # Bomb, Formula icons
|
215 |
-
error_output_list.extend([gr.update()] * num_plots) # Explore icons
|
216 |
-
error_output_list.extend([gr.update()] * num_unique_sections) # Section title vis
|
217 |
-
return error_output_list
|
218 |
|
219 |
clicked_plot_label = clicked_plot_config["label"]
|
220 |
clicked_plot_section = clicked_plot_config["section"]
|
@@ -224,196 +212,179 @@ with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue", secondary_hue="sky"),
|
|
224 |
action_col_visible_update = gr.update(visible=False)
|
225 |
insights_chatbot_visible_update, insights_chat_input_visible_update, insights_suggestions_row_visible_update = gr.update(visible=False), gr.update(visible=False), gr.update(visible=False)
|
226 |
formula_display_visible_update = gr.update(visible=False)
|
227 |
-
|
|
|
228 |
|
229 |
-
new_active_action_state_to_set = None
|
230 |
-
|
231 |
-
updated_chat_histories = current_chat_histories
|
232 |
-
new_explored_plot_id_to_set = current_explored_plot_id
|
233 |
-
|
234 |
-
panel_visibility_updates = []
|
235 |
-
action_button_updates = []
|
236 |
-
explore_button_updates = []
|
237 |
-
section_title_visibility_updates = [gr.update()] * num_unique_sections
|
238 |
|
|
|
|
|
239 |
|
240 |
if is_toggling_off:
|
241 |
new_active_action_state_to_set = None
|
242 |
-
action_col_visible_update = gr.update(visible=False)
|
243 |
-
|
244 |
-
|
245 |
-
if current_explored_plot_id:
|
246 |
-
|
247 |
-
|
248 |
for i, sec_name in enumerate(unique_ordered_sections):
|
249 |
-
|
250 |
-
for
|
251 |
-
|
252 |
-
|
253 |
-
|
254 |
-
else:
|
255 |
-
for i in range(num_unique_sections):
|
256 |
for _ in plot_configs:
|
257 |
-
|
258 |
-
|
259 |
-
|
260 |
for _ in plot_configs: # Reset bomb/formula icons
|
261 |
-
|
262 |
-
action_button_updates.append(gr.update(value=FORMULA_ICON))
|
263 |
if action_type == "insights": new_current_chat_plot_id = None
|
264 |
|
265 |
-
else: # Opening a new panel or switching
|
266 |
new_active_action_state_to_set = hypothetical_new_active_state
|
267 |
-
action_col_visible_update = gr.update(visible=True)
|
268 |
-
new_explored_plot_id_to_set = None # Cancel explore
|
269 |
-
|
270 |
-
logging.info(f"Apertura pannello {action_type} per {plot_id_clicked}. Solo questo grafico visibile. Esplorazione annullata.")
|
271 |
|
272 |
for i, sec_name in enumerate(unique_ordered_sections): # Show only relevant section title
|
273 |
-
|
274 |
-
|
275 |
-
|
276 |
-
|
277 |
-
|
278 |
-
|
279 |
-
|
280 |
-
|
281 |
-
|
282 |
-
|
283 |
-
action_button_updates.append(gr.update(value=ACTIVE_ICON if is_active_formula else FORMULA_ICON))
|
284 |
-
|
285 |
if action_type == "insights":
|
286 |
insights_chatbot_visible_update, insights_chat_input_visible_update, insights_suggestions_row_visible_update = gr.update(visible=True), gr.update(visible=True), gr.update(visible=True)
|
287 |
new_current_chat_plot_id = plot_id_clicked
|
288 |
-
|
289 |
-
|
290 |
-
if not
|
291 |
-
|
292 |
-
|
293 |
-
|
294 |
-
|
295 |
-
updated_chat_histories = {**current_chat_histories, plot_id_clicked:
|
296 |
-
else:
|
297 |
-
|
298 |
-
|
299 |
-
suggestion_1_update, suggestion_2_update, suggestion_3_update = gr.update(value=suggestions[0] if suggestions else "N/A"), gr.update(value=suggestions[1] if len(suggestions) > 1 else "N/A"), gr.update(value=suggestions[2] if len(suggestions) > 2 else "N/A")
|
300 |
elif action_type == "formula":
|
301 |
formula_display_visible_update = gr.update(visible=True)
|
302 |
-
|
303 |
-
|
304 |
-
|
305 |
-
|
|
|
|
|
|
|
|
|
306 |
new_current_chat_plot_id = None
|
307 |
|
308 |
final_updates = [
|
309 |
action_col_visible_update, insights_chatbot_visible_update, chatbot_content_update,
|
310 |
insights_chat_input_visible_update, insights_suggestions_row_visible_update,
|
311 |
-
|
312 |
-
|
313 |
new_active_action_state_to_set, new_current_chat_plot_id, updated_chat_histories,
|
314 |
new_explored_plot_id_to_set
|
315 |
]
|
316 |
-
final_updates.extend(
|
317 |
-
final_updates.extend(
|
318 |
-
final_updates.extend(
|
319 |
-
final_updates.extend(
|
320 |
return final_updates
|
321 |
|
322 |
async def handle_chat_message_submission(user_message: str, current_plot_id: str, chat_histories: dict, current_plot_data_for_chatbot: dict ):
|
323 |
if not current_plot_id or not user_message.strip():
|
324 |
-
yield chat_histories.get(current_plot_id, []), gr.update(value=""), chat_histories
|
325 |
-
|
326 |
-
|
327 |
-
|
328 |
-
|
329 |
-
|
330 |
-
|
331 |
-
|
332 |
-
|
333 |
-
yield history_for_plot, "", {**chat_histories, current_plot_id: history_for_plot}
|
334 |
|
335 |
async def handle_suggested_question_click(suggestion_text: str, current_plot_id: str, chat_histories: dict, current_plot_data_for_chatbot: dict):
|
336 |
if not current_plot_id or not suggestion_text.strip():
|
337 |
-
yield chat_histories.get(current_plot_id, []), gr.update(value=""), chat_histories
|
338 |
-
|
339 |
-
async for update in handle_chat_message_submission(suggestion_text, current_plot_id, chat_histories, current_plot_data_for_chatbot):
|
340 |
-
yield update
|
341 |
|
342 |
def handle_explore_click(plot_id_clicked, current_explored_plot_id_from_state, current_active_panel_action_state):
|
343 |
-
logging.info(f"Click
|
344 |
num_plots = len(plot_configs)
|
345 |
-
if not plot_ui_objects:
|
346 |
-
logging.error("plot_ui_objects
|
347 |
-
|
348 |
-
|
349 |
-
|
350 |
-
|
351 |
-
|
352 |
-
is_toggling_off_explore = (plot_id_clicked == current_explored_plot_id_from_state)
|
353 |
-
|
354 |
-
|
355 |
-
|
356 |
-
|
357 |
-
|
358 |
-
|
359 |
-
|
360 |
-
section_of_clicked_plot = clicked_plot_cfg["section"] if clicked_plot_cfg else None
|
361 |
|
362 |
if is_toggling_off_explore:
|
363 |
new_explored_id_to_set = None
|
364 |
-
logging.info(f"
|
365 |
-
for i in range(num_unique_sections):
|
366 |
for _ in plot_configs:
|
367 |
-
|
368 |
-
|
369 |
-
bomb_btn_icon_upds.append(gr.update()) # No change if not active
|
370 |
-
formula_btn_icon_upds.append(gr.update()) # No change if not active
|
371 |
else:
|
372 |
new_explored_id_to_set = plot_id_clicked
|
373 |
-
logging.info(f"
|
374 |
-
for i, sec_name in enumerate(unique_ordered_sections):
|
375 |
-
section_title_vis_updates[i] = gr.update(visible=(sec_name == section_of_clicked_plot))
|
376 |
for cfg in plot_configs:
|
377 |
is_target = (cfg["id"] == new_explored_id_to_set)
|
378 |
-
|
379 |
-
explore_btn_updates.append(gr.update(value=ACTIVE_ICON if is_target else EXPLORE_ICON))
|
380 |
if current_active_panel_action_state: # Close insight/formula if explore is activated
|
381 |
-
logging.info("
|
382 |
-
|
383 |
-
|
384 |
-
|
385 |
-
|
386 |
-
formula_btn_icon_upds.append(gr.update(value=FORMULA_ICON))
|
387 |
-
else:
|
388 |
-
for _ in plot_configs: bomb_btn_icon_upds.append(gr.update()); formula_btn_icon_upds.append(gr.update())
|
389 |
|
390 |
-
return [new_explored_id_to_set,
|
391 |
-
|
392 |
|
393 |
# --- Define Output Lists for Event Handlers ---
|
394 |
-
# Base UI elements for action panel
|
395 |
_base_action_panel_ui_outputs = [
|
396 |
global_actions_column_ui, insights_chatbot_ui, insights_chatbot_ui,
|
397 |
insights_chat_input_ui, insights_suggestions_row_ui,
|
398 |
insights_suggestion_1_btn, insights_suggestion_2_btn, insights_suggestion_3_btn,
|
399 |
-
formula_display_markdown_ui, formula_display_markdown_ui
|
|
|
400 |
]
|
401 |
_action_panel_state_outputs = [active_panel_action_state, current_chat_plot_id_st, chat_histories_st, explored_plot_id_state]
|
402 |
|
403 |
action_panel_outputs_list = _base_action_panel_ui_outputs + _action_panel_state_outputs
|
404 |
-
action_panel_outputs_list.extend([plot_ui_objects[
|
405 |
-
action_panel_outputs_list.extend([plot_ui_objects[
|
406 |
-
action_panel_outputs_list.extend([plot_ui_objects[
|
407 |
-
action_panel_outputs_list.extend([plot_ui_objects[
|
408 |
-
action_panel_outputs_list.extend([section_titles_map
|
409 |
|
410 |
-
_explore_state_outputs = [explored_plot_id_state, global_actions_column_ui, active_panel_action_state]
|
411 |
explore_outputs_list = _explore_state_outputs
|
412 |
-
explore_outputs_list.extend([plot_ui_objects[
|
413 |
-
explore_outputs_list.extend([plot_ui_objects[
|
414 |
-
explore_outputs_list.extend([plot_ui_objects[
|
415 |
-
explore_outputs_list.extend([plot_ui_objects[
|
416 |
-
explore_outputs_list.extend([section_titles_map
|
417 |
|
418 |
action_click_inputs = [active_panel_action_state, chat_histories_st, current_chat_plot_id_st, plot_data_for_chatbot_st, explored_plot_id_state]
|
419 |
explore_click_inputs = [explored_plot_id_state, active_panel_action_state]
|
@@ -442,43 +413,58 @@ with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue", secondary_hue="sky"),
|
|
442 |
|
443 |
def refresh_all_analytics_ui_elements(current_token_state, date_filter_val, custom_start_val, custom_end_val, current_chat_histories):
|
444 |
logging.info("Refreshing all analytics UI elements and resetting actions/chat.")
|
445 |
-
|
446 |
-
status_msg,
|
447 |
|
448 |
all_updates = [status_msg]
|
449 |
-
all_updates.extend(
|
450 |
|
451 |
-
all_updates.extend([ # Reset action panel UI
|
452 |
gr.update(visible=False), gr.update(value=[], visible=False), gr.update(value="", visible=False),
|
453 |
gr.update(visible=False), gr.update(value="S1"), gr.update(value="S2"), gr.update(value="S3"),
|
454 |
-
gr.update(value="Formula details here.", visible=False),
|
455 |
-
None, None, {},
|
456 |
-
])
|
457 |
-
for _ in plot_configs: # Reset button icons & panel visibility
|
458 |
all_updates.extend([gr.update(value=BOMB_ICON), gr.update(value=FORMULA_ICON), gr.update(value=EXPLORE_ICON), gr.update(visible=True)])
|
459 |
-
all_updates.append(None) # Reset explored_plot_id_state
|
460 |
-
all_updates.extend([gr.update(visible=True)] * num_unique_sections) # Make all section titles visible
|
461 |
logging.info(f"Prepared {len(all_updates)} updates for analytics refresh.")
|
462 |
return all_updates
|
463 |
|
464 |
-
apply_filter_and_sync_outputs_list = [analytics_status_md] # Status
|
465 |
-
apply_filter_and_sync_outputs_list.extend([plot_ui_objects
|
466 |
-
apply_filter_and_sync_outputs_list.extend([ # Action panel UI reset
|
467 |
global_actions_column_ui, insights_chatbot_ui, insights_chat_input_ui,
|
468 |
insights_suggestions_row_ui, insights_suggestion_1_btn, insights_suggestion_2_btn, insights_suggestion_3_btn,
|
469 |
-
formula_display_markdown_ui,
|
470 |
-
active_panel_action_state, current_chat_plot_id_st, chat_histories_st, plot_data_for_chatbot_st
|
471 |
-
])
|
472 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
473 |
pid = pc["id"]
|
474 |
apply_filter_and_sync_outputs_list.extend([
|
475 |
-
plot_ui_objects
|
476 |
-
plot_ui_objects
|
477 |
-
plot_ui_objects
|
478 |
-
plot_ui_objects
|
479 |
])
|
480 |
-
apply_filter_and_sync_outputs_list.append(explored_plot_id_state) # Reset explored state
|
481 |
-
apply_filter_and_sync_outputs_list.extend([section_titles_map
|
482 |
|
483 |
apply_filter_btn.click(
|
484 |
fn=refresh_all_analytics_ui_elements,
|
@@ -487,7 +473,6 @@ with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue", secondary_hue="sky"),
|
|
487 |
)
|
488 |
|
489 |
with gr.TabItem("3️⃣ Menzioni", id="tab_mentions"):
|
490 |
-
# ... (rest of the tab unchanged) ...
|
491 |
refresh_mentions_display_btn = gr.Button("🔄 Aggiorna Visualizzazione Menzioni", variant="secondary")
|
492 |
mentions_html = gr.HTML("Dati menzioni...")
|
493 |
mentions_sentiment_dist_plot = gr.Plot(label="Distribuzione Sentiment Menzioni")
|
@@ -498,7 +483,6 @@ with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue", secondary_hue="sky"),
|
|
498 |
)
|
499 |
|
500 |
with gr.TabItem("4️⃣ Statistiche Follower", id="tab_follower_stats"):
|
501 |
-
# ... (rest of the tab unchanged) ...
|
502 |
refresh_follower_stats_btn = gr.Button("🔄 Aggiorna Visualizzazione Statistiche Follower", variant="secondary")
|
503 |
follower_stats_html = gr.HTML("Statistiche follower...")
|
504 |
with gr.Row():
|
|
|
132 |
]
|
133 |
assert len(plot_configs) == 19, "Mancata corrispondenza in plot_configs e grafici attesi."
|
134 |
|
|
|
135 |
unique_ordered_sections = list(OrderedDict.fromkeys(pc["section"] for pc in plot_configs))
|
136 |
num_unique_sections = len(unique_ordered_sections)
|
137 |
|
138 |
active_panel_action_state = gr.State(None)
|
139 |
explored_plot_id_state = gr.State(None)
|
140 |
|
|
|
|
|
141 |
plot_ui_objects = {}
|
142 |
+
section_titles_map = {}
|
143 |
|
144 |
with gr.Row(equal_height=False):
|
145 |
with gr.Column(scale=8) as plots_area_col:
|
146 |
+
ui_elements_tuple = build_analytics_tab_plot_area(plot_configs) # This function is in ui_generators.py
|
|
|
|
|
|
|
147 |
if isinstance(ui_elements_tuple, tuple) and len(ui_elements_tuple) == 2:
|
148 |
+
plot_ui_objects, section_titles_map = ui_elements_tuple
|
|
|
|
|
149 |
if not all(sec_name in section_titles_map for sec_name in unique_ordered_sections):
|
150 |
+
logging.error("section_titles_map from build_analytics_tab_plot_area is incomplete.")
|
|
|
151 |
for sec_name in unique_ordered_sections:
|
152 |
if sec_name not in section_titles_map:
|
153 |
+
section_titles_map[sec_name] = gr.Markdown(f"### {sec_name} (Error Placeholder)")
|
154 |
else:
|
155 |
+
logging.error("build_analytics_tab_plot_area did not return (plot_ui_objects, section_titles_map).")
|
156 |
+
plot_ui_objects = ui_elements_tuple if isinstance(ui_elements_tuple, dict) else {} # Fallback
|
157 |
+
for sec_name in unique_ordered_sections: # Fallback for section titles
|
158 |
+
section_titles_map[sec_name] = gr.Markdown(f"### {sec_name} (Error Placeholder)")
|
|
|
159 |
|
160 |
|
161 |
with gr.Column(scale=4, visible=False) as global_actions_column_ui:
|
|
|
177 |
formula_display_markdown_ui = gr.Markdown(
|
178 |
"I dettagli sulla formula/metodologia appariranno qui.", visible=False
|
179 |
)
|
180 |
+
# NEW: Hint for closing the formula panel
|
181 |
+
formula_close_hint_md = gr.Markdown(
|
182 |
+
"<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>",
|
183 |
+
visible=False
|
184 |
+
)
|
185 |
+
|
186 |
|
187 |
async def handle_panel_action(
|
188 |
+
plot_id_clicked: str, action_type: str, current_active_action_from_state: dict,
|
189 |
+
current_chat_histories: dict, current_chat_plot_id: str,
|
190 |
+
current_plot_data_for_chatbot: dict, current_explored_plot_id: str
|
|
|
|
|
|
|
|
|
191 |
):
|
192 |
+
logging.info(f"Panel Action: '{action_type}' for plot '{plot_id_clicked}'. Active: {current_active_action_from_state}, Explored: {current_explored_plot_id}")
|
193 |
|
194 |
clicked_plot_config = next((p for p in plot_configs if p["id"] == plot_id_clicked), None)
|
195 |
if not clicked_plot_config:
|
196 |
+
logging.error(f"Config not found for plot_id {plot_id_clicked}")
|
197 |
+
# Ensure this error return matches the expected number of outputs
|
198 |
num_plots = len(plot_configs)
|
199 |
+
error_list = [gr.update(visible=False)] * 10 # Base action panel UI elements (incl. new hint)
|
200 |
+
error_list.extend([current_active_action_from_state, current_chat_plot_id, current_chat_histories, current_explored_plot_id]) # States
|
201 |
+
error_list.extend([gr.update()] * num_plots) # Panel visibilities
|
202 |
+
error_list.extend([gr.update()] * (2 * num_plots)) # Bomb, Formula icons
|
203 |
+
error_list.extend([gr.update()] * num_plots) # Explore icons
|
204 |
+
error_list.extend([gr.update()] * num_unique_sections) # Section title visibilities
|
205 |
+
return error_list
|
|
|
|
|
|
|
|
|
|
|
206 |
|
207 |
clicked_plot_label = clicked_plot_config["label"]
|
208 |
clicked_plot_section = clicked_plot_config["section"]
|
|
|
212 |
action_col_visible_update = gr.update(visible=False)
|
213 |
insights_chatbot_visible_update, insights_chat_input_visible_update, insights_suggestions_row_visible_update = gr.update(visible=False), gr.update(visible=False), gr.update(visible=False)
|
214 |
formula_display_visible_update = gr.update(visible=False)
|
215 |
+
formula_close_hint_visible_update = gr.update(visible=False) # NEW: Default to hidden
|
216 |
+
chatbot_content_update, s1_upd, s2_upd, s3_upd, formula_content_update = gr.update(), gr.update(), gr.update(), gr.update(), gr.update()
|
217 |
|
218 |
+
new_active_action_state_to_set, new_current_chat_plot_id = None, current_chat_plot_id
|
219 |
+
updated_chat_histories, new_explored_plot_id_to_set = current_chat_histories, current_explored_plot_id
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
220 |
|
221 |
+
panel_vis_updates, action_btn_updates, explore_btn_updates = [], [], []
|
222 |
+
section_title_vis_updates = [gr.update()] * num_unique_sections
|
223 |
|
224 |
if is_toggling_off:
|
225 |
new_active_action_state_to_set = None
|
226 |
+
action_col_visible_update = gr.update(visible=False) # Hide the whole right panel
|
227 |
+
# formula_close_hint_visible_update is already set to hidden by default
|
228 |
+
logging.info(f"Toggling OFF panel {action_type} for {plot_id_clicked}.")
|
229 |
+
if current_explored_plot_id: # If an explore view was active, restore it
|
230 |
+
explored_cfg = next((p for p in plot_configs if p["id"] == current_explored_plot_id), None)
|
231 |
+
explored_sec = explored_cfg["section"] if explored_cfg else None
|
232 |
for i, sec_name in enumerate(unique_ordered_sections):
|
233 |
+
section_title_vis_updates[i] = gr.update(visible=(sec_name == explored_sec))
|
234 |
+
for cfg in plot_configs:
|
235 |
+
is_exp = (cfg["id"] == current_explored_plot_id)
|
236 |
+
panel_vis_updates.append(gr.update(visible=is_exp))
|
237 |
+
explore_btn_updates.append(gr.update(value=ACTIVE_ICON if is_exp else EXPLORE_ICON))
|
238 |
+
else: # No explore active, make all plots and sections visible
|
239 |
+
for i in range(num_unique_sections): section_title_vis_updates[i] = gr.update(visible=True)
|
240 |
for _ in plot_configs:
|
241 |
+
panel_vis_updates.append(gr.update(visible=True))
|
242 |
+
explore_btn_updates.append(gr.update(value=EXPLORE_ICON))
|
|
|
243 |
for _ in plot_configs: # Reset bomb/formula icons
|
244 |
+
action_btn_updates.extend([gr.update(value=BOMB_ICON), gr.update(value=FORMULA_ICON)])
|
|
|
245 |
if action_type == "insights": new_current_chat_plot_id = None
|
246 |
|
247 |
+
else: # Opening a new panel or switching to a different one
|
248 |
new_active_action_state_to_set = hypothetical_new_active_state
|
249 |
+
action_col_visible_update = gr.update(visible=True) # Show the right panel
|
250 |
+
new_explored_plot_id_to_set = None # Cancel any active explore view
|
251 |
+
logging.info(f"Toggling ON panel {action_type} for {plot_id_clicked}. Cancelling explore view.")
|
|
|
252 |
|
253 |
for i, sec_name in enumerate(unique_ordered_sections): # Show only relevant section title
|
254 |
+
section_title_vis_updates[i] = gr.update(visible=(sec_name == clicked_plot_section))
|
255 |
+
for cfg in plot_configs: # Show only relevant plot panel
|
256 |
+
panel_vis_updates.append(gr.update(visible=(cfg["id"] == plot_id_clicked)))
|
257 |
+
explore_btn_updates.append(gr.update(value=EXPLORE_ICON)) # Reset all explore buttons
|
258 |
+
|
259 |
+
for cfg_btn in plot_configs: # Set active icons for bomb/formula
|
260 |
+
is_act_ins = new_active_action_state_to_set == {"plot_id": cfg_btn["id"], "type": "insights"}
|
261 |
+
is_act_for = new_active_action_state_to_set == {"plot_id": cfg_btn["id"], "type": "formula"}
|
262 |
+
action_btn_updates.extend([gr.update(value=ACTIVE_ICON if is_act_ins else BOMB_ICON),
|
263 |
+
gr.update(value=ACTIVE_ICON if is_act_for else FORMULA_ICON)])
|
|
|
|
|
264 |
if action_type == "insights":
|
265 |
insights_chatbot_visible_update, insights_chat_input_visible_update, insights_suggestions_row_visible_update = gr.update(visible=True), gr.update(visible=True), gr.update(visible=True)
|
266 |
new_current_chat_plot_id = plot_id_clicked
|
267 |
+
history = current_chat_histories.get(plot_id_clicked, [])
|
268 |
+
summary = current_plot_data_for_chatbot.get(plot_id_clicked, f"No summary for '{clicked_plot_label}'.")
|
269 |
+
if not history:
|
270 |
+
prompt, sugg = get_initial_insight_prompt_and_suggestions(plot_id_clicked, clicked_plot_label, summary)
|
271 |
+
llm_hist = [{"role": "user", "content": prompt}]
|
272 |
+
resp = await generate_llm_response(prompt, plot_id_clicked, clicked_plot_label, llm_hist, summary)
|
273 |
+
history = [{"role": "assistant", "content": resp}]
|
274 |
+
updated_chat_histories = {**current_chat_histories, plot_id_clicked: history}
|
275 |
+
else: _, sugg = get_initial_insight_prompt_and_suggestions(plot_id_clicked, clicked_plot_label, summary)
|
276 |
+
chatbot_content_update = gr.update(value=history)
|
277 |
+
s1_upd,s2_upd,s3_upd = gr.update(value=sugg[0] if sugg else "N/A"),gr.update(value=sugg[1] if len(sugg)>1 else "N/A"),gr.update(value=sugg[2] if len(sugg)>2 else "N/A")
|
|
|
278 |
elif action_type == "formula":
|
279 |
formula_display_visible_update = gr.update(visible=True)
|
280 |
+
formula_close_hint_visible_update = gr.update(visible=True) # NEW: Show hint
|
281 |
+
f_key = PLOT_ID_TO_FORMULA_KEY_MAP.get(plot_id_clicked)
|
282 |
+
f_text = f"**Formula/Methodology for: {clicked_plot_label}** (ID: `{plot_id_clicked}`)\n\n"
|
283 |
+
if f_key and f_key in PLOT_FORMULAS:
|
284 |
+
f_data = PLOT_FORMULAS[f_key]
|
285 |
+
f_text += f"### {f_data['title']}\n\n{f_data['description']}\n\n**Calculation:**\n" + "\n".join([f"- {s}" for s in f_data['calculation_steps']])
|
286 |
+
else: f_text += "(No detailed formula information found.)"
|
287 |
+
formula_content_update = gr.update(value=f_text)
|
288 |
new_current_chat_plot_id = None
|
289 |
|
290 |
final_updates = [
|
291 |
action_col_visible_update, insights_chatbot_visible_update, chatbot_content_update,
|
292 |
insights_chat_input_visible_update, insights_suggestions_row_visible_update,
|
293 |
+
s1_upd, s2_upd, s3_upd, formula_display_visible_update, formula_content_update,
|
294 |
+
formula_close_hint_visible_update, # NEW
|
295 |
new_active_action_state_to_set, new_current_chat_plot_id, updated_chat_histories,
|
296 |
new_explored_plot_id_to_set
|
297 |
]
|
298 |
+
final_updates.extend(panel_vis_updates)
|
299 |
+
final_updates.extend(action_btn_updates)
|
300 |
+
final_updates.extend(explore_btn_updates)
|
301 |
+
final_updates.extend(section_title_vis_updates)
|
302 |
return final_updates
|
303 |
|
304 |
async def handle_chat_message_submission(user_message: str, current_plot_id: str, chat_histories: dict, current_plot_data_for_chatbot: dict ):
|
305 |
if not current_plot_id or not user_message.strip():
|
306 |
+
yield chat_histories.get(current_plot_id, []), gr.update(value=""), chat_histories; return
|
307 |
+
cfg = next((p for p in plot_configs if p["id"] == current_plot_id), None)
|
308 |
+
lbl = cfg["label"] if cfg else "Selected Plot"
|
309 |
+
summary = current_plot_data_for_chatbot.get(current_plot_id, f"No summary for '{lbl}'.")
|
310 |
+
hist = chat_histories.get(current_plot_id, []).copy() + [{"role": "user", "content": user_message}]
|
311 |
+
yield hist, gr.update(value=""), chat_histories
|
312 |
+
resp = await generate_llm_response(user_message, current_plot_id, lbl, hist, summary)
|
313 |
+
hist.append({"role": "assistant", "content": resp})
|
314 |
+
yield hist, "", {**chat_histories, current_plot_id: hist}
|
|
|
315 |
|
316 |
async def handle_suggested_question_click(suggestion_text: str, current_plot_id: str, chat_histories: dict, current_plot_data_for_chatbot: dict):
|
317 |
if not current_plot_id or not suggestion_text.strip():
|
318 |
+
yield chat_histories.get(current_plot_id, []), gr.update(value=""), chat_histories; return
|
319 |
+
async for update in handle_chat_message_submission(suggestion_text, current_plot_id, chat_histories, current_plot_data_for_chatbot): yield update
|
|
|
|
|
320 |
|
321 |
def handle_explore_click(plot_id_clicked, current_explored_plot_id_from_state, current_active_panel_action_state):
|
322 |
+
logging.info(f"Explore Click: Plot '{plot_id_clicked}'. Current Explored: {current_explored_plot_id_from_state}. Active Panel: {current_active_panel_action_state}")
|
323 |
num_plots = len(plot_configs)
|
324 |
+
if not plot_ui_objects:
|
325 |
+
logging.error("plot_ui_objects not populated for handle_explore_click.")
|
326 |
+
# Match expected outputs: states (3) + panels (N) + explore_btns (N) + bomb_btns (N) + formula_btns (N) + section_titles (M) + formula_hint (1)
|
327 |
+
err_list = [current_explored_plot_id_from_state, gr.update(visible=False), current_active_panel_action_state]
|
328 |
+
err_list.extend([gr.update()] * (num_plots * 4 + num_unique_sections + 1) )
|
329 |
+
return err_list
|
330 |
+
|
331 |
+
new_explored_id_to_set, is_toggling_off_explore = None, (plot_id_clicked == current_explored_plot_id_from_state)
|
332 |
+
action_col_upd, new_active_panel_state_upd = gr.update(), current_active_panel_action_state
|
333 |
+
panel_vis, explore_btns, bomb_btns, formula_btns = [], [], [], []
|
334 |
+
section_title_vis = [gr.update()] * num_unique_sections
|
335 |
+
formula_hint_upd = gr.update(visible=False) # Hide formula hint when exploring
|
336 |
+
|
337 |
+
clicked_cfg = next((p for p in plot_configs if p["id"] == plot_id_clicked), None)
|
338 |
+
sec_of_clicked = clicked_cfg["section"] if clicked_cfg else None
|
|
|
339 |
|
340 |
if is_toggling_off_explore:
|
341 |
new_explored_id_to_set = None
|
342 |
+
logging.info(f"Stopping explore for {plot_id_clicked}. All plots/sections visible.")
|
343 |
+
for i in range(num_unique_sections): section_title_vis[i] = gr.update(visible=True)
|
344 |
for _ in plot_configs:
|
345 |
+
panel_vis.append(gr.update(visible=True)); explore_btns.append(gr.update(value=EXPLORE_ICON))
|
346 |
+
bomb_btns.append(gr.update()); formula_btns.append(gr.update()) # No change to these unless panel was active
|
|
|
|
|
347 |
else:
|
348 |
new_explored_id_to_set = plot_id_clicked
|
349 |
+
logging.info(f"Exploring {plot_id_clicked}. Hiding other plots/sections.")
|
350 |
+
for i, sec_name in enumerate(unique_ordered_sections): section_title_vis[i] = gr.update(visible=(sec_name == sec_of_clicked))
|
|
|
351 |
for cfg in plot_configs:
|
352 |
is_target = (cfg["id"] == new_explored_id_to_set)
|
353 |
+
panel_vis.append(gr.update(visible=is_target)); explore_btns.append(gr.update(value=ACTIVE_ICON if is_target else EXPLORE_ICON))
|
|
|
354 |
if current_active_panel_action_state: # Close insight/formula if explore is activated
|
355 |
+
logging.info("Closing active insight/formula panel due to explore click.")
|
356 |
+
action_col_upd = gr.update(visible=False); new_active_panel_state_upd = None
|
357 |
+
for _ in plot_configs: bomb_btns.extend([gr.update(value=BOMB_ICON), gr.update(value=FORMULA_ICON)])
|
358 |
+
else:
|
359 |
+
for _ in plot_configs: bomb_btns.append(gr.update()); formula_btns.append(gr.update())
|
|
|
|
|
|
|
360 |
|
361 |
+
return [new_explored_id_to_set, action_col_upd, new_active_panel_state_upd, formula_hint_upd] + \
|
362 |
+
panel_vis + explore_btns + bomb_btns + formula_btns + section_title_vis
|
363 |
|
364 |
# --- Define Output Lists for Event Handlers ---
|
|
|
365 |
_base_action_panel_ui_outputs = [
|
366 |
global_actions_column_ui, insights_chatbot_ui, insights_chatbot_ui,
|
367 |
insights_chat_input_ui, insights_suggestions_row_ui,
|
368 |
insights_suggestion_1_btn, insights_suggestion_2_btn, insights_suggestion_3_btn,
|
369 |
+
formula_display_markdown_ui, formula_display_markdown_ui,
|
370 |
+
formula_close_hint_md # NEW
|
371 |
]
|
372 |
_action_panel_state_outputs = [active_panel_action_state, current_chat_plot_id_st, chat_histories_st, explored_plot_id_state]
|
373 |
|
374 |
action_panel_outputs_list = _base_action_panel_ui_outputs + _action_panel_state_outputs
|
375 |
+
action_panel_outputs_list.extend([plot_ui_objects.get(pc["id"], {}).get("panel_component", gr.update()) for pc in plot_configs]) # Panel vis
|
376 |
+
action_panel_outputs_list.extend([plot_ui_objects.get(pc["id"], {}).get("bomb_button", gr.update()) for pc in plot_configs]) # Bomb icon
|
377 |
+
action_panel_outputs_list.extend([plot_ui_objects.get(pc["id"], {}).get("formula_button", gr.update()) for pc in plot_configs]) # Formula icon
|
378 |
+
action_panel_outputs_list.extend([plot_ui_objects.get(pc["id"], {}).get("explore_button", gr.update()) for pc in plot_configs]) # Explore icon
|
379 |
+
action_panel_outputs_list.extend([section_titles_map.get(s_name, gr.update()) for s_name in unique_ordered_sections]) # Section Titles
|
380 |
|
381 |
+
_explore_state_outputs = [explored_plot_id_state, global_actions_column_ui, active_panel_action_state, formula_close_hint_md] # NEW: add hint to explore outputs
|
382 |
explore_outputs_list = _explore_state_outputs
|
383 |
+
explore_outputs_list.extend([plot_ui_objects.get(pc["id"], {}).get("panel_component", gr.update()) for pc in plot_configs])
|
384 |
+
explore_outputs_list.extend([plot_ui_objects.get(pc["id"], {}).get("explore_button", gr.update()) for pc in plot_configs])
|
385 |
+
explore_outputs_list.extend([plot_ui_objects.get(pc["id"], {}).get("bomb_button", gr.update()) for pc in plot_configs])
|
386 |
+
explore_outputs_list.extend([plot_ui_objects.get(pc["id"], {}).get("formula_button", gr.update()) for pc in plot_configs])
|
387 |
+
explore_outputs_list.extend([section_titles_map.get(s_name, gr.update()) for s_name in unique_ordered_sections])
|
388 |
|
389 |
action_click_inputs = [active_panel_action_state, chat_histories_st, current_chat_plot_id_st, plot_data_for_chatbot_st, explored_plot_id_state]
|
390 |
explore_click_inputs = [explored_plot_id_state, active_panel_action_state]
|
|
|
413 |
|
414 |
def refresh_all_analytics_ui_elements(current_token_state, date_filter_val, custom_start_val, custom_end_val, current_chat_histories):
|
415 |
logging.info("Refreshing all analytics UI elements and resetting actions/chat.")
|
416 |
+
plot_gen_results = update_analytics_plots_figures(current_token_state, date_filter_val, custom_start_val, custom_end_val, plot_configs)
|
417 |
+
status_msg, gen_figs, new_summaries = plot_gen_results[0], plot_gen_results[1:-1], plot_gen_results[-1]
|
418 |
|
419 |
all_updates = [status_msg]
|
420 |
+
all_updates.extend(gen_figs if len(gen_figs) == len(plot_configs) else [create_placeholder_plot("Error", f"Fig missing {i}") for i in range(len(plot_configs))])
|
421 |
|
422 |
+
all_updates.extend([ # Reset action panel UI (11 elements including new hint)
|
423 |
gr.update(visible=False), gr.update(value=[], visible=False), gr.update(value="", visible=False),
|
424 |
gr.update(visible=False), gr.update(value="S1"), gr.update(value="S2"), gr.update(value="S3"),
|
425 |
+
gr.update(value="Formula details here.", visible=False), gr.update(visible=False), # Formula MD and Hint MD
|
426 |
+
None, None, {}, new_summaries # Reset states (4 elements)
|
427 |
+
]) # Total 11 + 4 = 15 here
|
428 |
+
for _ in plot_configs: # Reset button icons & panel visibility (4 per plot)
|
429 |
all_updates.extend([gr.update(value=BOMB_ICON), gr.update(value=FORMULA_ICON), gr.update(value=EXPLORE_ICON), gr.update(visible=True)])
|
430 |
+
all_updates.append(None) # Reset explored_plot_id_state (1 element)
|
431 |
+
all_updates.extend([gr.update(visible=True)] * num_unique_sections) # Make all section titles visible (M elements)
|
432 |
logging.info(f"Prepared {len(all_updates)} updates for analytics refresh.")
|
433 |
return all_updates
|
434 |
|
435 |
+
apply_filter_and_sync_outputs_list = [analytics_status_md] # Status (1)
|
436 |
+
apply_filter_and_sync_outputs_list.extend([plot_ui_objects.get(pc["id"], {}).get("plot_component", gr.update()) for pc in plot_configs]) # Plot figures (N)
|
437 |
+
apply_filter_and_sync_outputs_list.extend([ # Action panel UI reset (11 elements)
|
438 |
global_actions_column_ui, insights_chatbot_ui, insights_chat_input_ui,
|
439 |
insights_suggestions_row_ui, insights_suggestion_1_btn, insights_suggestion_2_btn, insights_suggestion_3_btn,
|
440 |
+
formula_display_markdown_ui, formula_close_hint_md, # Added hint
|
441 |
+
active_panel_action_state, current_chat_plot_id_st, chat_histories_st, plot_data_for_chatbot_st # States (4) -> total 11+4 = 15 for this block
|
442 |
+
]) # This was 12, now 13 with hint. State resets are separate. Let's be precise.
|
443 |
+
# Action Panel UI (9) + Formula MD (1) + Hint MD (1) = 11
|
444 |
+
# States (4) = active_panel_action_state, current_chat_plot_id_st, chat_histories_st, plot_data_for_chatbot_st
|
445 |
+
# So, 11 UI + 4 states = 15 elements.
|
446 |
+
|
447 |
+
# Corrected block for apply_filter_outputs:
|
448 |
+
_ui_resets_for_filter = [
|
449 |
+
global_actions_column_ui, insights_chatbot_ui, insights_chat_input_ui,
|
450 |
+
insights_suggestions_row_ui, insights_suggestion_1_btn, insights_suggestion_2_btn, insights_suggestion_3_btn,
|
451 |
+
formula_display_markdown_ui, formula_close_hint_md # 9 elements
|
452 |
+
]
|
453 |
+
_state_resets_for_filter = [active_panel_action_state, current_chat_plot_id_st, chat_histories_st, plot_data_for_chatbot_st] # 4 elements
|
454 |
+
|
455 |
+
apply_filter_and_sync_outputs_list.extend(_ui_resets_for_filter)
|
456 |
+
apply_filter_and_sync_outputs_list.extend(_state_resets_for_filter)
|
457 |
+
|
458 |
+
for pc in plot_configs: # Button icons (3) and panel visibility (1) = 4 per plot
|
459 |
pid = pc["id"]
|
460 |
apply_filter_and_sync_outputs_list.extend([
|
461 |
+
plot_ui_objects.get(pid, {}).get("bomb_button", gr.update()),
|
462 |
+
plot_ui_objects.get(pid, {}).get("formula_button", gr.update()),
|
463 |
+
plot_ui_objects.get(pid, {}).get("explore_button", gr.update()),
|
464 |
+
plot_ui_objects.get(pid, {}).get("panel_component", gr.update())
|
465 |
])
|
466 |
+
apply_filter_and_sync_outputs_list.append(explored_plot_id_state) # Reset explored state (1)
|
467 |
+
apply_filter_and_sync_outputs_list.extend([section_titles_map.get(s_name, gr.update()) for s_name in unique_ordered_sections]) # Section Titles (M)
|
468 |
|
469 |
apply_filter_btn.click(
|
470 |
fn=refresh_all_analytics_ui_elements,
|
|
|
473 |
)
|
474 |
|
475 |
with gr.TabItem("3️⃣ Menzioni", id="tab_mentions"):
|
|
|
476 |
refresh_mentions_display_btn = gr.Button("🔄 Aggiorna Visualizzazione Menzioni", variant="secondary")
|
477 |
mentions_html = gr.HTML("Dati menzioni...")
|
478 |
mentions_sentiment_dist_plot = gr.Plot(label="Distribuzione Sentiment Menzioni")
|
|
|
483 |
)
|
484 |
|
485 |
with gr.TabItem("4️⃣ Statistiche Follower", id="tab_follower_stats"):
|
|
|
486 |
refresh_follower_stats_btn = gr.Button("🔄 Aggiorna Visualizzazione Statistiche Follower", variant="secondary")
|
487 |
follower_stats_html = gr.HTML("Statistiche follower...")
|
488 |
with gr.Row():
|