Spaces:
Running
Running
Update app.py
Browse files
app.py
CHANGED
@@ -141,20 +141,19 @@ def update_analytics_plots_figures(token_state_value, date_filter_option, custom
|
|
141 |
plot_figs.append(create_placeholder_plot(title=f"Errore Grafico {i+1}", message=f"Dettaglio: {str(plot_e)[:100]}"))
|
142 |
|
143 |
message = f"📊 Analisi aggiornate per il periodo: {date_filter_option}"
|
144 |
-
if date_filter_option == "Intervallo Personalizzato":
|
145 |
s_display = start_dt_for_msg.strftime('%Y-%m-%d') if start_dt_for_msg else "Qualsiasi"
|
146 |
e_display = end_dt_for_msg.strftime('%Y-%m-%d') if end_dt_for_msg else "Qualsiasi"
|
147 |
message += f" (Da: {s_display} A: {e_display})"
|
148 |
|
149 |
final_plot_figs = []
|
150 |
for i, p_fig in enumerate(plot_figs):
|
151 |
-
if p_fig is not None and not isinstance(p_fig, str):
|
152 |
final_plot_figs.append(p_fig)
|
153 |
else:
|
154 |
logging.warning(f"Plot generation failed or unexpected type for slot {i}, using placeholder. Figure: {p_fig}")
|
155 |
final_plot_figs.append(create_placeholder_plot(title="Errore Grafico", message="Impossibile generare questa figura."))
|
156 |
|
157 |
-
# Ensure the list has exactly num_expected_plots items
|
158 |
while len(final_plot_figs) < num_expected_plots:
|
159 |
logging.warning(f"Adding missing plot placeholder. Expected {num_expected_plots}, got {len(final_plot_figs)}.")
|
160 |
final_plot_figs.append(create_placeholder_plot(title="Grafico Mancante", message="Figura non generata."))
|
@@ -181,12 +180,8 @@ with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue", secondary_hue="sky"),
|
|
181 |
"config_eb_labels_col": "li_eb_label"
|
182 |
})
|
183 |
|
184 |
-
# --- NEW CHATBOT STATES ---
|
185 |
-
# Stores chat history for each plot_id: {plot_id: [{"role": "user/assistant", "content": "..."}, ...]}
|
186 |
chat_histories_st = gr.State({})
|
187 |
-
# Stores the plot_id of the currently active chat, e.g., "followers_count"
|
188 |
current_chat_plot_id_st = gr.State(None)
|
189 |
-
# --- END NEW CHATBOT STATES ---
|
190 |
|
191 |
gr.Markdown("# 🚀 LinkedIn Organization Dashboard")
|
192 |
url_user_token_display = gr.Textbox(label="User Token (Nascosto)", interactive=False, visible=False)
|
@@ -224,7 +219,7 @@ with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue", secondary_hue="sky"),
|
|
224 |
["Sempre", "Ultimi 7 Giorni", "Ultimi 30 Giorni", "Intervallo Personalizzato"],
|
225 |
label="Seleziona Intervallo Date", value="Sempre", scale=3
|
226 |
)
|
227 |
-
with gr.Column(scale=2):
|
228 |
custom_start_date_picker = gr.DateTime(label="Data Inizio", visible=False, include_time=False, type="datetime")
|
229 |
custom_end_date_picker = gr.DateTime(label="Data Fine", visible=False, include_time=False, type="datetime")
|
230 |
|
@@ -263,20 +258,18 @@ with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue", secondary_hue="sky"),
|
|
263 |
]
|
264 |
assert len(plot_configs) == 19, "Mancata corrispondenza in plot_configs e grafici attesi."
|
265 |
|
266 |
-
active_panel_action_state = gr.State(None)
|
267 |
-
explored_plot_id_state = gr.State(None)
|
268 |
|
269 |
-
plot_ui_objects = {}
|
270 |
|
271 |
with gr.Row(equal_height=False):
|
272 |
with gr.Column(scale=8) as plots_area_col:
|
273 |
plot_ui_objects = build_analytics_tab_plot_area(plot_configs)
|
274 |
|
275 |
-
|
276 |
-
|
277 |
-
gr.Markdown("### 💡 Azioni Contestuali Grafico") # General title for the panel
|
278 |
|
279 |
-
# Chatbot components (initially hidden)
|
280 |
insights_chatbot_ui = gr.Chatbot(
|
281 |
label="Chat Insights", type="messages", height=450,
|
282 |
bubble_full_width=False, visible=False, show_label=False,
|
@@ -291,28 +284,22 @@ with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue", secondary_hue="sky"),
|
|
291 |
insights_suggestion_2_btn = gr.Button(value="Suggerimento 2", size="sm", min_width=50)
|
292 |
insights_suggestion_3_btn = gr.Button(value="Suggerimento 3", size="sm", min_width=50)
|
293 |
|
294 |
-
# Formula display component (initially hidden)
|
295 |
formula_display_markdown_ui = gr.Markdown(
|
296 |
"I dettagli sulla formula/metodologia appariranno qui.", visible=False
|
297 |
)
|
298 |
-
# --- END UPDATED GLOBAL ACTIONS COLUMN ---
|
299 |
|
300 |
-
# --- Event Handler for Insights (Chatbot) and Formula Buttons ---
|
301 |
async def handle_panel_action(
|
302 |
plot_id_clicked: str,
|
303 |
-
action_type: str,
|
304 |
-
current_active_action_from_state: dict,
|
305 |
-
|
306 |
-
|
307 |
-
current_chat_plot_id: str # from current_chat_plot_id_st
|
308 |
):
|
309 |
logging.info(f"Azione '{action_type}' per grafico: {plot_id_clicked}. Attualmente attivo: {current_active_action_from_state}")
|
310 |
|
311 |
-
# Find the label for the clicked plot_id
|
312 |
clicked_plot_config = next((p for p in plot_configs if p["id"] == plot_id_clicked), None)
|
313 |
if not clicked_plot_config:
|
314 |
logging.error(f"Configurazione non trovata per plot_id {plot_id_clicked}")
|
315 |
-
# Basic error feedback if needed, though this shouldn't happen if UI is built correctly
|
316 |
return [gr.update(visible=False)] * 7 + [current_active_action_from_state, current_chat_plot_id, current_chat_histories] + [gr.update() for _ in range(2 * len(plot_configs))]
|
317 |
|
318 |
clicked_plot_label = clicked_plot_config["label"]
|
@@ -323,27 +310,24 @@ with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue", secondary_hue="sky"),
|
|
323 |
new_active_action_state_to_set = None
|
324 |
action_col_visible_update = gr.update(visible=True)
|
325 |
|
326 |
-
# Default visibility for components in the action column
|
327 |
insights_chatbot_visible_update = gr.update(visible=False)
|
328 |
insights_chat_input_visible_update = gr.update(visible=False)
|
329 |
insights_suggestions_row_visible_update = gr.update(visible=False)
|
330 |
formula_display_visible_update = gr.update(visible=False)
|
331 |
|
332 |
-
# Chat-specific updates
|
333 |
chatbot_content_update = gr.update()
|
334 |
suggestion_1_update = gr.update()
|
335 |
suggestion_2_update = gr.update()
|
336 |
suggestion_3_update = gr.update()
|
337 |
-
new_current_chat_plot_id = current_chat_plot_id
|
338 |
-
updated_chat_histories = current_chat_histories
|
339 |
|
340 |
-
# Formula-specific updates
|
341 |
formula_content_update = gr.update()
|
342 |
|
343 |
if is_toggling_off:
|
344 |
new_active_action_state_to_set = None
|
345 |
action_col_visible_update = gr.update(visible=False)
|
346 |
-
new_current_chat_plot_id = None
|
347 |
logging.info(f"Chiusura pannello {action_type} per {plot_id_clicked}")
|
348 |
else:
|
349 |
new_active_action_state_to_set = hypothetical_new_active_state
|
@@ -355,12 +339,12 @@ with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue", secondary_hue="sky"),
|
|
355 |
new_current_chat_plot_id = plot_id_clicked
|
356 |
chat_history_for_this_plot = current_chat_histories.get(plot_id_clicked, [])
|
357 |
|
358 |
-
if not chat_history_for_this_plot:
|
359 |
initial_insight_msg, suggestions = get_initial_insight_and_suggestions(plot_id_clicked, clicked_plot_label)
|
360 |
chat_history_for_this_plot = [initial_insight_msg]
|
361 |
updated_chat_histories = current_chat_histories.copy()
|
362 |
updated_chat_histories[plot_id_clicked] = chat_history_for_this_plot
|
363 |
-
else:
|
364 |
_, suggestions = get_initial_insight_and_suggestions(plot_id_clicked, clicked_plot_label)
|
365 |
|
366 |
chatbot_content_update = gr.update(value=chat_history_for_this_plot)
|
@@ -383,19 +367,16 @@ with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue", secondary_hue="sky"),
|
|
383 |
else:
|
384 |
formula_text += "(Nessuna informazione dettagliata sulla formula trovata per questo ID grafico in `formulas.py`)"
|
385 |
formula_content_update = gr.update(value=formula_text)
|
386 |
-
new_current_chat_plot_id = None
|
387 |
logging.info(f"Apertura pannello FORMULA per {plot_id_clicked} (mappato a {formula_key})")
|
388 |
|
389 |
-
# Update button icons
|
390 |
all_button_icon_updates = []
|
391 |
for cfg_item in plot_configs:
|
392 |
p_id_iter = cfg_item["id"]
|
393 |
-
# Insights (Bomb) button
|
394 |
if new_active_action_state_to_set == {"plot_id": p_id_iter, "type": "insights"}:
|
395 |
all_button_icon_updates.append(gr.update(value=ACTIVE_ICON))
|
396 |
else:
|
397 |
all_button_icon_updates.append(gr.update(value=BOMB_ICON))
|
398 |
-
# Formula button
|
399 |
if new_active_action_state_to_set == {"plot_id": p_id_iter, "type": "formula"}:
|
400 |
all_button_icon_updates.append(gr.update(value=ACTIVE_ICON))
|
401 |
else:
|
@@ -407,36 +388,32 @@ with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue", secondary_hue="sky"),
|
|
407 |
insights_chat_input_visible_update,
|
408 |
insights_suggestions_row_visible_update, suggestion_1_update, suggestion_2_update, suggestion_3_update,
|
409 |
formula_display_visible_update, formula_content_update,
|
410 |
-
new_active_action_state_to_set,
|
411 |
-
new_current_chat_plot_id,
|
412 |
-
updated_chat_histories
|
413 |
] + all_button_icon_updates
|
414 |
|
415 |
return final_updates
|
416 |
|
417 |
-
# --- Event Handler for Chat Message Submission ---
|
418 |
async def handle_chat_message_submission(
|
419 |
user_message: str,
|
420 |
-
current_plot_id: str,
|
421 |
-
chat_histories: dict,
|
422 |
-
# token_state_val: dict # If needed for context, but LLM should get context from history
|
423 |
):
|
424 |
if not current_plot_id or not user_message.strip():
|
425 |
-
# Return current history for the plot_id if message is empty
|
426 |
history_for_plot = chat_histories.get(current_plot_id, [])
|
427 |
-
|
|
|
|
|
428 |
|
429 |
-
# Find plot label for context
|
430 |
plot_config = next((p for p in plot_configs if p["id"] == current_plot_id), None)
|
431 |
plot_label = plot_config["label"] if plot_config else "Grafico Selezionato"
|
432 |
|
433 |
history_for_plot = chat_histories.get(current_plot_id, []).copy()
|
434 |
history_for_plot.append({"role": "user", "content": user_message})
|
435 |
|
436 |
-
|
437 |
-
yield history_for_plot, "", chat_histories # Update chatbot, clear input, keep histories
|
438 |
|
439 |
-
# Generate bot response
|
440 |
bot_response_text = await generate_llm_response(user_message, current_plot_id, plot_label, history_for_plot)
|
441 |
|
442 |
history_for_plot.append({"role": "assistant", "content": bot_response_text})
|
@@ -444,24 +421,18 @@ with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue", secondary_hue="sky"),
|
|
444 |
updated_chat_histories = chat_histories.copy()
|
445 |
updated_chat_histories[current_plot_id] = history_for_plot
|
446 |
|
447 |
-
yield history_for_plot, "", updated_chat_histories
|
448 |
|
449 |
-
# --- Event Handler for Suggested Question Click ---
|
450 |
async def handle_suggested_question_click(
|
451 |
suggestion_text: str,
|
452 |
-
current_plot_id: str,
|
453 |
-
chat_histories: dict,
|
454 |
-
# token_state_val: dict
|
455 |
):
|
456 |
-
# This will effectively call handle_chat_message_submission
|
457 |
-
# We need to ensure the output signature matches what Gradio expects for this button's .click event
|
458 |
-
# which is the same as handle_chat_message_submission's output.
|
459 |
-
# The 'yield' pattern is for streaming, if handle_chat_message_submission uses it, this should too.
|
460 |
-
|
461 |
-
# Simulate the submission process
|
462 |
if not current_plot_id or not suggestion_text.strip():
|
463 |
history_for_plot = chat_histories.get(current_plot_id, [])
|
464 |
-
return
|
|
|
|
|
465 |
|
466 |
plot_config = next((p for p in plot_configs if p["id"] == current_plot_id), None)
|
467 |
plot_label = plot_config["label"] if plot_config else "Grafico Selezionato"
|
@@ -469,7 +440,7 @@ with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue", secondary_hue="sky"),
|
|
469 |
history_for_plot = chat_histories.get(current_plot_id, []).copy()
|
470 |
history_for_plot.append({"role": "user", "content": suggestion_text})
|
471 |
|
472 |
-
yield history_for_plot, "", chat_histories
|
473 |
|
474 |
bot_response_text = await generate_llm_response(suggestion_text, current_plot_id, plot_label, history_for_plot)
|
475 |
history_for_plot.append({"role": "assistant", "content": bot_response_text})
|
@@ -479,18 +450,13 @@ with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue", secondary_hue="sky"),
|
|
479 |
|
480 |
yield history_for_plot, "", updated_chat_histories
|
481 |
|
482 |
-
|
483 |
-
# --- Explore button logic (remains largely the same) ---
|
484 |
def handle_explore_click(plot_id_clicked, current_explored_plot_id_from_state):
|
485 |
-
# (This function's logic for showing/hiding plot panels based on explore state)
|
486 |
-
# ... (original logic from user's code) ...
|
487 |
logging.info(f"Click su Esplora per: {plot_id_clicked}. Attualmente esplorato da stato: {current_explored_plot_id_from_state}")
|
488 |
if not plot_ui_objects:
|
489 |
logging.error("plot_ui_objects non popolato durante handle_explore_click.")
|
490 |
-
# Need to return updates for all explore buttons and panels
|
491 |
updates_for_missing_ui = [current_explored_plot_id_from_state]
|
492 |
for _ in plot_configs:
|
493 |
-
updates_for_missing_ui.extend([gr.update(), gr.update()])
|
494 |
return updates_for_missing_ui
|
495 |
|
496 |
new_explored_id_to_set = None
|
@@ -508,80 +474,69 @@ with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue", secondary_hue="sky"),
|
|
508 |
p_id = cfg["id"]
|
509 |
if p_id in plot_ui_objects:
|
510 |
panel_visible = not new_explored_id_to_set or (p_id == new_explored_id_to_set)
|
511 |
-
panel_and_button_updates.append(gr.update(visible=panel_visible))
|
512 |
|
513 |
-
if p_id == new_explored_id_to_set:
|
514 |
panel_and_button_updates.append(gr.update(value=ACTIVE_ICON))
|
515 |
else:
|
516 |
panel_and_button_updates.append(gr.update(value=EXPLORE_ICON))
|
517 |
-
else:
|
518 |
panel_and_button_updates.extend([gr.update(), gr.update()])
|
519 |
|
520 |
-
final_updates = [new_explored_id_to_set] + panel_and_button_updates
|
521 |
return final_updates
|
522 |
-
|
523 |
-
# --- Define output lists for event handlers ---
|
524 |
|
525 |
-
# Outputs for handle_panel_action (insights/formula clicks)
|
526 |
action_panel_outputs_list = [
|
527 |
-
global_actions_column_ui,
|
528 |
-
insights_chatbot_ui, insights_chatbot_ui,
|
529 |
-
insights_chat_input_ui,
|
530 |
-
insights_suggestions_row_ui, insights_suggestion_1_btn, insights_suggestion_2_btn, insights_suggestion_3_btn,
|
531 |
-
formula_display_markdown_ui, formula_display_markdown_ui,
|
532 |
active_panel_action_state,
|
533 |
current_chat_plot_id_st,
|
534 |
chat_histories_st
|
535 |
]
|
536 |
-
for cfg_item_action in plot_configs:
|
537 |
pid_action = cfg_item_action["id"]
|
538 |
if pid_action in plot_ui_objects:
|
539 |
action_panel_outputs_list.append(plot_ui_objects[pid_action]["bomb_button"])
|
540 |
action_panel_outputs_list.append(plot_ui_objects[pid_action]["formula_button"])
|
541 |
-
else:
|
542 |
action_panel_outputs_list.extend([None, None])
|
543 |
|
544 |
-
# Outputs for handle_explore_click
|
545 |
explore_buttons_outputs_list = [explored_plot_id_state]
|
546 |
for cfg_item_explore in plot_configs:
|
547 |
pid_explore = cfg_item_explore["id"]
|
548 |
if pid_explore in plot_ui_objects:
|
549 |
explore_buttons_outputs_list.append(plot_ui_objects[pid_explore]["panel_component"])
|
550 |
explore_buttons_outputs_list.append(plot_ui_objects[pid_explore]["explore_button"])
|
551 |
-
else:
|
552 |
explore_buttons_outputs_list.extend([None, None])
|
553 |
|
554 |
-
# Inputs for action clicks (insights/formula)
|
555 |
action_click_inputs = [
|
556 |
active_panel_action_state,
|
557 |
-
# token_state, # No longer passing full token_state if not needed by handle_panel_action
|
558 |
chat_histories_st,
|
559 |
current_chat_plot_id_st
|
560 |
]
|
561 |
-
# Inputs for explore clicks
|
562 |
explore_click_inputs = [explored_plot_id_state]
|
563 |
|
564 |
-
# Wire up action and explore buttons
|
565 |
for config_item in plot_configs:
|
566 |
plot_id = config_item["id"]
|
567 |
-
plot_label = config_item["label"]
|
568 |
if plot_id in plot_ui_objects:
|
569 |
ui_obj = plot_ui_objects[plot_id]
|
570 |
-
# Insights (Bomb) Button
|
571 |
ui_obj["bomb_button"].click(
|
572 |
fn=lambda current_active_val, current_chats_val, current_chat_pid, p_id=plot_id: handle_panel_action(p_id, "insights", current_active_val, current_chats_val, current_chat_pid),
|
573 |
-
inputs=action_click_inputs,
|
574 |
outputs=action_panel_outputs_list,
|
575 |
api_name=f"action_insights_{plot_id}"
|
576 |
)
|
577 |
-
# Formula Button
|
578 |
ui_obj["formula_button"].click(
|
579 |
fn=lambda current_active_val, current_chats_val, current_chat_pid, p_id=plot_id: handle_panel_action(p_id, "formula", current_active_val, current_chats_val, current_chat_pid),
|
580 |
inputs=action_click_inputs,
|
581 |
outputs=action_panel_outputs_list,
|
582 |
api_name=f"action_formula_{plot_id}"
|
583 |
)
|
584 |
-
# Explore Button
|
585 |
ui_obj["explore_button"].click(
|
586 |
fn=lambda current_explored_val, p_id=plot_id: handle_explore_click(p_id, current_explored_val),
|
587 |
inputs=explore_click_inputs,
|
@@ -591,37 +546,33 @@ with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue", secondary_hue="sky"),
|
|
591 |
else:
|
592 |
logging.warning(f"Oggetto UI per plot_id '{plot_id}' non trovato durante il tentativo di associare i gestori di click.")
|
593 |
|
594 |
-
# Wire up chat input submission
|
595 |
chat_submission_outputs = [insights_chatbot_ui, insights_chat_input_ui, chat_histories_st]
|
596 |
insights_chat_input_ui.submit(
|
597 |
fn=handle_chat_message_submission,
|
598 |
-
inputs=[insights_chat_input_ui, current_chat_plot_id_st, chat_histories_st],
|
599 |
outputs=chat_submission_outputs,
|
600 |
api_name="submit_chat_message"
|
601 |
)
|
602 |
|
603 |
-
# Wire up suggested question buttons
|
604 |
insights_suggestion_1_btn.click(
|
605 |
fn=handle_suggested_question_click,
|
606 |
-
inputs=[insights_suggestion_1_btn, current_chat_plot_id_st, chat_histories_st],
|
607 |
-
outputs=chat_submission_outputs,
|
608 |
api_name="click_suggestion_1"
|
609 |
)
|
610 |
insights_suggestion_2_btn.click(
|
611 |
fn=handle_suggested_question_click,
|
612 |
-
inputs=[insights_suggestion_2_btn, current_chat_plot_id_st, chat_histories_st],
|
613 |
outputs=chat_submission_outputs,
|
614 |
api_name="click_suggestion_2"
|
615 |
)
|
616 |
insights_suggestion_3_btn.click(
|
617 |
fn=handle_suggested_question_click,
|
618 |
-
inputs=[insights_suggestion_3_btn, current_chat_plot_id_st, chat_histories_st],
|
619 |
outputs=chat_submission_outputs,
|
620 |
api_name="click_suggestion_3"
|
621 |
)
|
622 |
|
623 |
-
|
624 |
-
# --- Function to refresh all analytics UI elements (plots and action panel states) ---
|
625 |
def refresh_all_analytics_ui_elements(current_token_state, date_filter_val, custom_start_val, custom_end_val, current_chat_histories):
|
626 |
logging.info("Aggiornamento di tutti gli elementi UI delle analisi e reset delle azioni/chat.")
|
627 |
plot_generation_results = update_analytics_plots_figures(
|
@@ -630,84 +581,76 @@ with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue", secondary_hue="sky"),
|
|
630 |
status_message_update = plot_generation_results[0]
|
631 |
generated_plot_figures = plot_generation_results[1:]
|
632 |
|
633 |
-
all_updates = [status_message_update]
|
634 |
|
635 |
-
# Add plot figure updates
|
636 |
for i in range(len(plot_configs)):
|
637 |
if i < len(generated_plot_figures):
|
638 |
-
all_updates.append(generated_plot_figures[i])
|
639 |
-
else:
|
640 |
all_updates.append(create_placeholder_plot("Errore Figura", f"Figura mancante per grafico {plot_configs[i]['id']}"))
|
641 |
|
642 |
-
# Reset global actions column and its content
|
643 |
all_updates.extend([
|
644 |
-
gr.update(visible=False),
|
645 |
-
gr.update(value=[], visible=False),
|
646 |
-
gr.update(value="", visible=False),
|
647 |
-
gr.update(visible=False),
|
648 |
-
gr.update(value="Suggerimento 1", visible=True),
|
649 |
-
gr.update(value="Suggerimento 2", visible=True),
|
650 |
-
gr.update(value="Suggerimento 3", visible=True),
|
651 |
-
gr.update(value="I dettagli sulla formula/metodologia appariranno qui.", visible=False),
|
652 |
-
None,
|
653 |
-
None,
|
654 |
-
current_chat_histories,
|
655 |
-
# If you want to clear all chats on refresh: use `{}` instead of current_chat_histories
|
656 |
])
|
657 |
|
658 |
-
# Reset action buttons (bomb, formula, explore icons) and plot panel visibility (for explore)
|
659 |
for cfg in plot_configs:
|
660 |
pid = cfg["id"]
|
661 |
if pid in plot_ui_objects:
|
662 |
-
all_updates.append(gr.update(value=BOMB_ICON))
|
663 |
-
all_updates.append(gr.update(value=FORMULA_ICON))
|
664 |
-
all_updates.append(gr.update(value=EXPLORE_ICON))
|
665 |
-
all_updates.append(gr.update(visible=True))
|
666 |
-
else:
|
667 |
all_updates.extend([None, None, None, None])
|
668 |
|
669 |
-
all_updates.append(None)
|
670 |
|
671 |
logging.info(f"Preparati {len(all_updates)} aggiornamenti per il refresh completo delle analisi.")
|
672 |
return all_updates
|
673 |
|
674 |
-
|
675 |
-
apply_filter_and_sync_outputs_list = [analytics_status_md] # Status message
|
676 |
-
# Add plot components
|
677 |
for config_item_filter_sync in plot_configs:
|
678 |
pid_filter_sync = config_item_filter_sync["id"]
|
679 |
if pid_filter_sync in plot_ui_objects and "plot_component" in plot_ui_objects[pid_filter_sync]:
|
680 |
apply_filter_and_sync_outputs_list.append(plot_ui_objects[pid_filter_sync]["plot_component"])
|
681 |
else:
|
682 |
-
apply_filter_and_sync_outputs_list.append(None)
|
683 |
|
684 |
-
# Add updates for the global actions column and its contents + states
|
685 |
apply_filter_and_sync_outputs_list.extend([
|
686 |
-
global_actions_column_ui,
|
687 |
-
insights_chatbot_ui,
|
688 |
-
insights_chat_input_ui,
|
689 |
-
insights_suggestions_row_ui,
|
690 |
-
insights_suggestion_1_btn,
|
691 |
-
insights_suggestion_2_btn,
|
692 |
-
insights_suggestion_3_btn,
|
693 |
-
formula_display_markdown_ui,
|
694 |
-
active_panel_action_state,
|
695 |
-
current_chat_plot_id_st,
|
696 |
-
chat_histories_st
|
697 |
])
|
698 |
|
699 |
-
# Add updates for individual plot action buttons (bomb, formula, explore) and plot panels (explore visibility)
|
700 |
for cfg_filter_sync_btns in plot_configs:
|
701 |
pid_filter_sync_btns = cfg_filter_sync_btns["id"]
|
702 |
if pid_filter_sync_btns in plot_ui_objects:
|
703 |
apply_filter_and_sync_outputs_list.append(plot_ui_objects[pid_filter_sync_btns]["bomb_button"])
|
704 |
apply_filter_and_sync_outputs_list.append(plot_ui_objects[pid_filter_sync_btns]["formula_button"])
|
705 |
apply_filter_and_sync_outputs_list.append(plot_ui_objects[pid_filter_sync_btns]["explore_button"])
|
706 |
-
apply_filter_and_sync_outputs_list.append(plot_ui_objects[pid_filter_sync_btns]["panel_component"])
|
707 |
else:
|
708 |
-
apply_filter_and_sync_outputs_list.extend([None, None, None, None])
|
709 |
|
710 |
-
apply_filter_and_sync_outputs_list.append(explored_plot_id_state)
|
711 |
|
712 |
logging.info(f"Output totali definiti per apply_filter/sync: {len(apply_filter_and_sync_outputs_list)}")
|
713 |
|
@@ -731,7 +674,7 @@ with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue", secondary_hue="sky"),
|
|
731 |
with gr.TabItem("4️⃣ Statistiche Follower", id="tab_follower_stats"):
|
732 |
refresh_follower_stats_btn = gr.Button("🔄 Aggiorna Visualizzazione Statistiche Follower", variant="secondary")
|
733 |
follower_stats_html = gr.HTML("Statistiche follower...")
|
734 |
-
with gr.Row():
|
735 |
fs_plot_monthly_gains = gr.Plot(label="Guadagni Mensili Follower")
|
736 |
with gr.Row():
|
737 |
fs_plot_seniority = gr.Plot(label="Follower per Anzianità (Top 10 Organici)")
|
@@ -743,25 +686,23 @@ with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue", secondary_hue="sky"),
|
|
743 |
show_progress="full"
|
744 |
)
|
745 |
|
746 |
-
# Sync data flow
|
747 |
sync_event_part1 = sync_data_btn.click(
|
748 |
fn=sync_all_linkedin_data_orchestrator,
|
749 |
inputs=[token_state], outputs=[sync_status_html_output, token_state], show_progress="full"
|
750 |
)
|
751 |
-
sync_event_part2 = sync_event_part1.then(
|
752 |
-
fn=process_and_store_bubble_token,
|
753 |
inputs=[url_user_token_display, org_urn_display, token_state],
|
754 |
-
outputs=[status_box, token_state, sync_data_btn], show_progress=False
|
755 |
)
|
756 |
sync_event_part3 = sync_event_part2.then(
|
757 |
-
fn=display_main_dashboard,
|
758 |
inputs=[token_state], outputs=[dashboard_display_html], show_progress=False
|
759 |
)
|
760 |
-
# After sync, refresh analytics tab including plots and resetting chat/formula panels
|
761 |
sync_event_final = sync_event_part3.then(
|
762 |
fn=refresh_all_analytics_ui_elements,
|
763 |
inputs=[token_state, date_filter_selector, custom_start_date_picker, custom_end_date_picker, chat_histories_st],
|
764 |
-
outputs=apply_filter_and_sync_outputs_list,
|
765 |
show_progress="full"
|
766 |
)
|
767 |
|
@@ -775,7 +716,7 @@ if __name__ == "__main__":
|
|
775 |
|
776 |
try:
|
777 |
logging.info(f"Versione Matplotlib: {matplotlib.__version__}, Backend: {matplotlib.get_backend()}")
|
778 |
-
except ImportError:
|
779 |
logging.warning("Matplotlib non trovato direttamente, ma potrebbe essere usato dai generatori di grafici.")
|
780 |
|
781 |
app.launch(server_name="0.0.0.0", server_port=7860, debug=True)
|
|
|
141 |
plot_figs.append(create_placeholder_plot(title=f"Errore Grafico {i+1}", message=f"Dettaglio: {str(plot_e)[:100]}"))
|
142 |
|
143 |
message = f"📊 Analisi aggiornate per il periodo: {date_filter_option}"
|
144 |
+
if date_filter_option == "Intervallo Personalizzato":
|
145 |
s_display = start_dt_for_msg.strftime('%Y-%m-%d') if start_dt_for_msg else "Qualsiasi"
|
146 |
e_display = end_dt_for_msg.strftime('%Y-%m-%d') if end_dt_for_msg else "Qualsiasi"
|
147 |
message += f" (Da: {s_display} A: {e_display})"
|
148 |
|
149 |
final_plot_figs = []
|
150 |
for i, p_fig in enumerate(plot_figs):
|
151 |
+
if p_fig is not None and not isinstance(p_fig, str):
|
152 |
final_plot_figs.append(p_fig)
|
153 |
else:
|
154 |
logging.warning(f"Plot generation failed or unexpected type for slot {i}, using placeholder. Figure: {p_fig}")
|
155 |
final_plot_figs.append(create_placeholder_plot(title="Errore Grafico", message="Impossibile generare questa figura."))
|
156 |
|
|
|
157 |
while len(final_plot_figs) < num_expected_plots:
|
158 |
logging.warning(f"Adding missing plot placeholder. Expected {num_expected_plots}, got {len(final_plot_figs)}.")
|
159 |
final_plot_figs.append(create_placeholder_plot(title="Grafico Mancante", message="Figura non generata."))
|
|
|
180 |
"config_eb_labels_col": "li_eb_label"
|
181 |
})
|
182 |
|
|
|
|
|
183 |
chat_histories_st = gr.State({})
|
|
|
184 |
current_chat_plot_id_st = gr.State(None)
|
|
|
185 |
|
186 |
gr.Markdown("# 🚀 LinkedIn Organization Dashboard")
|
187 |
url_user_token_display = gr.Textbox(label="User Token (Nascosto)", interactive=False, visible=False)
|
|
|
219 |
["Sempre", "Ultimi 7 Giorni", "Ultimi 30 Giorni", "Intervallo Personalizzato"],
|
220 |
label="Seleziona Intervallo Date", value="Sempre", scale=3
|
221 |
)
|
222 |
+
with gr.Column(scale=2):
|
223 |
custom_start_date_picker = gr.DateTime(label="Data Inizio", visible=False, include_time=False, type="datetime")
|
224 |
custom_end_date_picker = gr.DateTime(label="Data Fine", visible=False, include_time=False, type="datetime")
|
225 |
|
|
|
258 |
]
|
259 |
assert len(plot_configs) == 19, "Mancata corrispondenza in plot_configs e grafici attesi."
|
260 |
|
261 |
+
active_panel_action_state = gr.State(None)
|
262 |
+
explored_plot_id_state = gr.State(None)
|
263 |
|
264 |
+
plot_ui_objects = {}
|
265 |
|
266 |
with gr.Row(equal_height=False):
|
267 |
with gr.Column(scale=8) as plots_area_col:
|
268 |
plot_ui_objects = build_analytics_tab_plot_area(plot_configs)
|
269 |
|
270 |
+
with gr.Column(scale=4, visible=False) as global_actions_column_ui:
|
271 |
+
gr.Markdown("### 💡 Azioni Contestuali Grafico")
|
|
|
272 |
|
|
|
273 |
insights_chatbot_ui = gr.Chatbot(
|
274 |
label="Chat Insights", type="messages", height=450,
|
275 |
bubble_full_width=False, visible=False, show_label=False,
|
|
|
284 |
insights_suggestion_2_btn = gr.Button(value="Suggerimento 2", size="sm", min_width=50)
|
285 |
insights_suggestion_3_btn = gr.Button(value="Suggerimento 3", size="sm", min_width=50)
|
286 |
|
|
|
287 |
formula_display_markdown_ui = gr.Markdown(
|
288 |
"I dettagli sulla formula/metodologia appariranno qui.", visible=False
|
289 |
)
|
|
|
290 |
|
|
|
291 |
async def handle_panel_action(
|
292 |
plot_id_clicked: str,
|
293 |
+
action_type: str,
|
294 |
+
current_active_action_from_state: dict,
|
295 |
+
current_chat_histories: dict,
|
296 |
+
current_chat_plot_id: str
|
|
|
297 |
):
|
298 |
logging.info(f"Azione '{action_type}' per grafico: {plot_id_clicked}. Attualmente attivo: {current_active_action_from_state}")
|
299 |
|
|
|
300 |
clicked_plot_config = next((p for p in plot_configs if p["id"] == plot_id_clicked), None)
|
301 |
if not clicked_plot_config:
|
302 |
logging.error(f"Configurazione non trovata per plot_id {plot_id_clicked}")
|
|
|
303 |
return [gr.update(visible=False)] * 7 + [current_active_action_from_state, current_chat_plot_id, current_chat_histories] + [gr.update() for _ in range(2 * len(plot_configs))]
|
304 |
|
305 |
clicked_plot_label = clicked_plot_config["label"]
|
|
|
310 |
new_active_action_state_to_set = None
|
311 |
action_col_visible_update = gr.update(visible=True)
|
312 |
|
|
|
313 |
insights_chatbot_visible_update = gr.update(visible=False)
|
314 |
insights_chat_input_visible_update = gr.update(visible=False)
|
315 |
insights_suggestions_row_visible_update = gr.update(visible=False)
|
316 |
formula_display_visible_update = gr.update(visible=False)
|
317 |
|
|
|
318 |
chatbot_content_update = gr.update()
|
319 |
suggestion_1_update = gr.update()
|
320 |
suggestion_2_update = gr.update()
|
321 |
suggestion_3_update = gr.update()
|
322 |
+
new_current_chat_plot_id = current_chat_plot_id
|
323 |
+
updated_chat_histories = current_chat_histories
|
324 |
|
|
|
325 |
formula_content_update = gr.update()
|
326 |
|
327 |
if is_toggling_off:
|
328 |
new_active_action_state_to_set = None
|
329 |
action_col_visible_update = gr.update(visible=False)
|
330 |
+
new_current_chat_plot_id = None
|
331 |
logging.info(f"Chiusura pannello {action_type} per {plot_id_clicked}")
|
332 |
else:
|
333 |
new_active_action_state_to_set = hypothetical_new_active_state
|
|
|
339 |
new_current_chat_plot_id = plot_id_clicked
|
340 |
chat_history_for_this_plot = current_chat_histories.get(plot_id_clicked, [])
|
341 |
|
342 |
+
if not chat_history_for_this_plot:
|
343 |
initial_insight_msg, suggestions = get_initial_insight_and_suggestions(plot_id_clicked, clicked_plot_label)
|
344 |
chat_history_for_this_plot = [initial_insight_msg]
|
345 |
updated_chat_histories = current_chat_histories.copy()
|
346 |
updated_chat_histories[plot_id_clicked] = chat_history_for_this_plot
|
347 |
+
else:
|
348 |
_, suggestions = get_initial_insight_and_suggestions(plot_id_clicked, clicked_plot_label)
|
349 |
|
350 |
chatbot_content_update = gr.update(value=chat_history_for_this_plot)
|
|
|
367 |
else:
|
368 |
formula_text += "(Nessuna informazione dettagliata sulla formula trovata per questo ID grafico in `formulas.py`)"
|
369 |
formula_content_update = gr.update(value=formula_text)
|
370 |
+
new_current_chat_plot_id = None
|
371 |
logging.info(f"Apertura pannello FORMULA per {plot_id_clicked} (mappato a {formula_key})")
|
372 |
|
|
|
373 |
all_button_icon_updates = []
|
374 |
for cfg_item in plot_configs:
|
375 |
p_id_iter = cfg_item["id"]
|
|
|
376 |
if new_active_action_state_to_set == {"plot_id": p_id_iter, "type": "insights"}:
|
377 |
all_button_icon_updates.append(gr.update(value=ACTIVE_ICON))
|
378 |
else:
|
379 |
all_button_icon_updates.append(gr.update(value=BOMB_ICON))
|
|
|
380 |
if new_active_action_state_to_set == {"plot_id": p_id_iter, "type": "formula"}:
|
381 |
all_button_icon_updates.append(gr.update(value=ACTIVE_ICON))
|
382 |
else:
|
|
|
388 |
insights_chat_input_visible_update,
|
389 |
insights_suggestions_row_visible_update, suggestion_1_update, suggestion_2_update, suggestion_3_update,
|
390 |
formula_display_visible_update, formula_content_update,
|
391 |
+
new_active_action_state_to_set,
|
392 |
+
new_current_chat_plot_id,
|
393 |
+
updated_chat_histories
|
394 |
] + all_button_icon_updates
|
395 |
|
396 |
return final_updates
|
397 |
|
|
|
398 |
async def handle_chat_message_submission(
|
399 |
user_message: str,
|
400 |
+
current_plot_id: str,
|
401 |
+
chat_histories: dict,
|
|
|
402 |
):
|
403 |
if not current_plot_id or not user_message.strip():
|
|
|
404 |
history_for_plot = chat_histories.get(current_plot_id, [])
|
405 |
+
# Corrected: Use yield and then a bare return for early exit in async generator
|
406 |
+
yield history_for_plot, "", chat_histories
|
407 |
+
return
|
408 |
|
|
|
409 |
plot_config = next((p for p in plot_configs if p["id"] == current_plot_id), None)
|
410 |
plot_label = plot_config["label"] if plot_config else "Grafico Selezionato"
|
411 |
|
412 |
history_for_plot = chat_histories.get(current_plot_id, []).copy()
|
413 |
history_for_plot.append({"role": "user", "content": user_message})
|
414 |
|
415 |
+
yield history_for_plot, "", chat_histories
|
|
|
416 |
|
|
|
417 |
bot_response_text = await generate_llm_response(user_message, current_plot_id, plot_label, history_for_plot)
|
418 |
|
419 |
history_for_plot.append({"role": "assistant", "content": bot_response_text})
|
|
|
421 |
updated_chat_histories = chat_histories.copy()
|
422 |
updated_chat_histories[current_plot_id] = history_for_plot
|
423 |
|
424 |
+
yield history_for_plot, "", updated_chat_histories
|
425 |
|
|
|
426 |
async def handle_suggested_question_click(
|
427 |
suggestion_text: str,
|
428 |
+
current_plot_id: str,
|
429 |
+
chat_histories: dict,
|
|
|
430 |
):
|
|
|
|
|
|
|
|
|
|
|
|
|
431 |
if not current_plot_id or not suggestion_text.strip():
|
432 |
history_for_plot = chat_histories.get(current_plot_id, [])
|
433 |
+
# Corrected: Use yield and then a bare return for early exit in async generator
|
434 |
+
yield history_for_plot, "", chat_histories
|
435 |
+
return
|
436 |
|
437 |
plot_config = next((p for p in plot_configs if p["id"] == current_plot_id), None)
|
438 |
plot_label = plot_config["label"] if plot_config else "Grafico Selezionato"
|
|
|
440 |
history_for_plot = chat_histories.get(current_plot_id, []).copy()
|
441 |
history_for_plot.append({"role": "user", "content": suggestion_text})
|
442 |
|
443 |
+
yield history_for_plot, "", chat_histories
|
444 |
|
445 |
bot_response_text = await generate_llm_response(suggestion_text, current_plot_id, plot_label, history_for_plot)
|
446 |
history_for_plot.append({"role": "assistant", "content": bot_response_text})
|
|
|
450 |
|
451 |
yield history_for_plot, "", updated_chat_histories
|
452 |
|
|
|
|
|
453 |
def handle_explore_click(plot_id_clicked, current_explored_plot_id_from_state):
|
|
|
|
|
454 |
logging.info(f"Click su Esplora per: {plot_id_clicked}. Attualmente esplorato da stato: {current_explored_plot_id_from_state}")
|
455 |
if not plot_ui_objects:
|
456 |
logging.error("plot_ui_objects non popolato durante handle_explore_click.")
|
|
|
457 |
updates_for_missing_ui = [current_explored_plot_id_from_state]
|
458 |
for _ in plot_configs:
|
459 |
+
updates_for_missing_ui.extend([gr.update(), gr.update()])
|
460 |
return updates_for_missing_ui
|
461 |
|
462 |
new_explored_id_to_set = None
|
|
|
474 |
p_id = cfg["id"]
|
475 |
if p_id in plot_ui_objects:
|
476 |
panel_visible = not new_explored_id_to_set or (p_id == new_explored_id_to_set)
|
477 |
+
panel_and_button_updates.append(gr.update(visible=panel_visible))
|
478 |
|
479 |
+
if p_id == new_explored_id_to_set:
|
480 |
panel_and_button_updates.append(gr.update(value=ACTIVE_ICON))
|
481 |
else:
|
482 |
panel_and_button_updates.append(gr.update(value=EXPLORE_ICON))
|
483 |
+
else:
|
484 |
panel_and_button_updates.extend([gr.update(), gr.update()])
|
485 |
|
486 |
+
final_updates = [new_explored_id_to_set] + panel_and_button_updates
|
487 |
return final_updates
|
|
|
|
|
488 |
|
|
|
489 |
action_panel_outputs_list = [
|
490 |
+
global_actions_column_ui,
|
491 |
+
insights_chatbot_ui, insights_chatbot_ui,
|
492 |
+
insights_chat_input_ui,
|
493 |
+
insights_suggestions_row_ui, insights_suggestion_1_btn, insights_suggestion_2_btn, insights_suggestion_3_btn,
|
494 |
+
formula_display_markdown_ui, formula_display_markdown_ui,
|
495 |
active_panel_action_state,
|
496 |
current_chat_plot_id_st,
|
497 |
chat_histories_st
|
498 |
]
|
499 |
+
for cfg_item_action in plot_configs:
|
500 |
pid_action = cfg_item_action["id"]
|
501 |
if pid_action in plot_ui_objects:
|
502 |
action_panel_outputs_list.append(plot_ui_objects[pid_action]["bomb_button"])
|
503 |
action_panel_outputs_list.append(plot_ui_objects[pid_action]["formula_button"])
|
504 |
+
else:
|
505 |
action_panel_outputs_list.extend([None, None])
|
506 |
|
|
|
507 |
explore_buttons_outputs_list = [explored_plot_id_state]
|
508 |
for cfg_item_explore in plot_configs:
|
509 |
pid_explore = cfg_item_explore["id"]
|
510 |
if pid_explore in plot_ui_objects:
|
511 |
explore_buttons_outputs_list.append(plot_ui_objects[pid_explore]["panel_component"])
|
512 |
explore_buttons_outputs_list.append(plot_ui_objects[pid_explore]["explore_button"])
|
513 |
+
else:
|
514 |
explore_buttons_outputs_list.extend([None, None])
|
515 |
|
|
|
516 |
action_click_inputs = [
|
517 |
active_panel_action_state,
|
|
|
518 |
chat_histories_st,
|
519 |
current_chat_plot_id_st
|
520 |
]
|
|
|
521 |
explore_click_inputs = [explored_plot_id_state]
|
522 |
|
|
|
523 |
for config_item in plot_configs:
|
524 |
plot_id = config_item["id"]
|
525 |
+
plot_label = config_item["label"]
|
526 |
if plot_id in plot_ui_objects:
|
527 |
ui_obj = plot_ui_objects[plot_id]
|
|
|
528 |
ui_obj["bomb_button"].click(
|
529 |
fn=lambda current_active_val, current_chats_val, current_chat_pid, p_id=plot_id: handle_panel_action(p_id, "insights", current_active_val, current_chats_val, current_chat_pid),
|
530 |
+
inputs=action_click_inputs,
|
531 |
outputs=action_panel_outputs_list,
|
532 |
api_name=f"action_insights_{plot_id}"
|
533 |
)
|
|
|
534 |
ui_obj["formula_button"].click(
|
535 |
fn=lambda current_active_val, current_chats_val, current_chat_pid, p_id=plot_id: handle_panel_action(p_id, "formula", current_active_val, current_chats_val, current_chat_pid),
|
536 |
inputs=action_click_inputs,
|
537 |
outputs=action_panel_outputs_list,
|
538 |
api_name=f"action_formula_{plot_id}"
|
539 |
)
|
|
|
540 |
ui_obj["explore_button"].click(
|
541 |
fn=lambda current_explored_val, p_id=plot_id: handle_explore_click(p_id, current_explored_val),
|
542 |
inputs=explore_click_inputs,
|
|
|
546 |
else:
|
547 |
logging.warning(f"Oggetto UI per plot_id '{plot_id}' non trovato durante il tentativo di associare i gestori di click.")
|
548 |
|
|
|
549 |
chat_submission_outputs = [insights_chatbot_ui, insights_chat_input_ui, chat_histories_st]
|
550 |
insights_chat_input_ui.submit(
|
551 |
fn=handle_chat_message_submission,
|
552 |
+
inputs=[insights_chat_input_ui, current_chat_plot_id_st, chat_histories_st],
|
553 |
outputs=chat_submission_outputs,
|
554 |
api_name="submit_chat_message"
|
555 |
)
|
556 |
|
|
|
557 |
insights_suggestion_1_btn.click(
|
558 |
fn=handle_suggested_question_click,
|
559 |
+
inputs=[insights_suggestion_1_btn, current_chat_plot_id_st, chat_histories_st],
|
560 |
+
outputs=chat_submission_outputs,
|
561 |
api_name="click_suggestion_1"
|
562 |
)
|
563 |
insights_suggestion_2_btn.click(
|
564 |
fn=handle_suggested_question_click,
|
565 |
+
inputs=[insights_suggestion_2_btn, current_chat_plot_id_st, chat_histories_st],
|
566 |
outputs=chat_submission_outputs,
|
567 |
api_name="click_suggestion_2"
|
568 |
)
|
569 |
insights_suggestion_3_btn.click(
|
570 |
fn=handle_suggested_question_click,
|
571 |
+
inputs=[insights_suggestion_3_btn, current_chat_plot_id_st, chat_histories_st],
|
572 |
outputs=chat_submission_outputs,
|
573 |
api_name="click_suggestion_3"
|
574 |
)
|
575 |
|
|
|
|
|
576 |
def refresh_all_analytics_ui_elements(current_token_state, date_filter_val, custom_start_val, custom_end_val, current_chat_histories):
|
577 |
logging.info("Aggiornamento di tutti gli elementi UI delle analisi e reset delle azioni/chat.")
|
578 |
plot_generation_results = update_analytics_plots_figures(
|
|
|
581 |
status_message_update = plot_generation_results[0]
|
582 |
generated_plot_figures = plot_generation_results[1:]
|
583 |
|
584 |
+
all_updates = [status_message_update]
|
585 |
|
|
|
586 |
for i in range(len(plot_configs)):
|
587 |
if i < len(generated_plot_figures):
|
588 |
+
all_updates.append(generated_plot_figures[i])
|
589 |
+
else:
|
590 |
all_updates.append(create_placeholder_plot("Errore Figura", f"Figura mancante per grafico {plot_configs[i]['id']}"))
|
591 |
|
|
|
592 |
all_updates.extend([
|
593 |
+
gr.update(visible=False),
|
594 |
+
gr.update(value=[], visible=False),
|
595 |
+
gr.update(value="", visible=False),
|
596 |
+
gr.update(visible=False),
|
597 |
+
gr.update(value="Suggerimento 1", visible=True),
|
598 |
+
gr.update(value="Suggerimento 2", visible=True),
|
599 |
+
gr.update(value="Suggerimento 3", visible=True),
|
600 |
+
gr.update(value="I dettagli sulla formula/metodologia appariranno qui.", visible=False),
|
601 |
+
None,
|
602 |
+
None,
|
603 |
+
current_chat_histories,
|
|
|
604 |
])
|
605 |
|
|
|
606 |
for cfg in plot_configs:
|
607 |
pid = cfg["id"]
|
608 |
if pid in plot_ui_objects:
|
609 |
+
all_updates.append(gr.update(value=BOMB_ICON))
|
610 |
+
all_updates.append(gr.update(value=FORMULA_ICON))
|
611 |
+
all_updates.append(gr.update(value=EXPLORE_ICON))
|
612 |
+
all_updates.append(gr.update(visible=True))
|
613 |
+
else:
|
614 |
all_updates.extend([None, None, None, None])
|
615 |
|
616 |
+
all_updates.append(None)
|
617 |
|
618 |
logging.info(f"Preparati {len(all_updates)} aggiornamenti per il refresh completo delle analisi.")
|
619 |
return all_updates
|
620 |
|
621 |
+
apply_filter_and_sync_outputs_list = [analytics_status_md]
|
|
|
|
|
622 |
for config_item_filter_sync in plot_configs:
|
623 |
pid_filter_sync = config_item_filter_sync["id"]
|
624 |
if pid_filter_sync in plot_ui_objects and "plot_component" in plot_ui_objects[pid_filter_sync]:
|
625 |
apply_filter_and_sync_outputs_list.append(plot_ui_objects[pid_filter_sync]["plot_component"])
|
626 |
else:
|
627 |
+
apply_filter_and_sync_outputs_list.append(None)
|
628 |
|
|
|
629 |
apply_filter_and_sync_outputs_list.extend([
|
630 |
+
global_actions_column_ui,
|
631 |
+
insights_chatbot_ui,
|
632 |
+
insights_chat_input_ui,
|
633 |
+
insights_suggestions_row_ui,
|
634 |
+
insights_suggestion_1_btn,
|
635 |
+
insights_suggestion_2_btn,
|
636 |
+
insights_suggestion_3_btn,
|
637 |
+
formula_display_markdown_ui,
|
638 |
+
active_panel_action_state,
|
639 |
+
current_chat_plot_id_st,
|
640 |
+
chat_histories_st
|
641 |
])
|
642 |
|
|
|
643 |
for cfg_filter_sync_btns in plot_configs:
|
644 |
pid_filter_sync_btns = cfg_filter_sync_btns["id"]
|
645 |
if pid_filter_sync_btns in plot_ui_objects:
|
646 |
apply_filter_and_sync_outputs_list.append(plot_ui_objects[pid_filter_sync_btns]["bomb_button"])
|
647 |
apply_filter_and_sync_outputs_list.append(plot_ui_objects[pid_filter_sync_btns]["formula_button"])
|
648 |
apply_filter_and_sync_outputs_list.append(plot_ui_objects[pid_filter_sync_btns]["explore_button"])
|
649 |
+
apply_filter_and_sync_outputs_list.append(plot_ui_objects[pid_filter_sync_btns]["panel_component"])
|
650 |
else:
|
651 |
+
apply_filter_and_sync_outputs_list.extend([None, None, None, None])
|
652 |
|
653 |
+
apply_filter_and_sync_outputs_list.append(explored_plot_id_state)
|
654 |
|
655 |
logging.info(f"Output totali definiti per apply_filter/sync: {len(apply_filter_and_sync_outputs_list)}")
|
656 |
|
|
|
674 |
with gr.TabItem("4️⃣ Statistiche Follower", id="tab_follower_stats"):
|
675 |
refresh_follower_stats_btn = gr.Button("🔄 Aggiorna Visualizzazione Statistiche Follower", variant="secondary")
|
676 |
follower_stats_html = gr.HTML("Statistiche follower...")
|
677 |
+
with gr.Row():
|
678 |
fs_plot_monthly_gains = gr.Plot(label="Guadagni Mensili Follower")
|
679 |
with gr.Row():
|
680 |
fs_plot_seniority = gr.Plot(label="Follower per Anzianità (Top 10 Organici)")
|
|
|
686 |
show_progress="full"
|
687 |
)
|
688 |
|
|
|
689 |
sync_event_part1 = sync_data_btn.click(
|
690 |
fn=sync_all_linkedin_data_orchestrator,
|
691 |
inputs=[token_state], outputs=[sync_status_html_output, token_state], show_progress="full"
|
692 |
)
|
693 |
+
sync_event_part2 = sync_event_part1.then(
|
694 |
+
fn=process_and_store_bubble_token,
|
695 |
inputs=[url_user_token_display, org_urn_display, token_state],
|
696 |
+
outputs=[status_box, token_state, sync_data_btn], show_progress=False
|
697 |
)
|
698 |
sync_event_part3 = sync_event_part2.then(
|
699 |
+
fn=display_main_dashboard,
|
700 |
inputs=[token_state], outputs=[dashboard_display_html], show_progress=False
|
701 |
)
|
|
|
702 |
sync_event_final = sync_event_part3.then(
|
703 |
fn=refresh_all_analytics_ui_elements,
|
704 |
inputs=[token_state, date_filter_selector, custom_start_date_picker, custom_end_date_picker, chat_histories_st],
|
705 |
+
outputs=apply_filter_and_sync_outputs_list,
|
706 |
show_progress="full"
|
707 |
)
|
708 |
|
|
|
716 |
|
717 |
try:
|
718 |
logging.info(f"Versione Matplotlib: {matplotlib.__version__}, Backend: {matplotlib.get_backend()}")
|
719 |
+
except ImportError:
|
720 |
logging.warning("Matplotlib non trovato direttamente, ma potrebbe essere usato dai generatori di grafici.")
|
721 |
|
722 |
app.launch(server_name="0.0.0.0", server_port=7860, debug=True)
|