Spaces:
Running
Running
Update app.py
Browse files
app.py
CHANGED
@@ -1,3 +1,5 @@
|
|
|
|
|
|
1 |
import gradio as gr
|
2 |
import pandas as pd
|
3 |
import os
|
@@ -46,7 +48,7 @@ from analytics_plot_generator import (
|
|
46 |
from formulas import PLOT_FORMULAS
|
47 |
|
48 |
# --- NEW CHATBOT MODULE IMPORTS ---
|
49 |
-
from chatbot_prompts import
|
50 |
from chatbot_handler import generate_llm_response
|
51 |
# --- END NEW CHATBOT MODULE IMPORTS ---
|
52 |
|
@@ -93,60 +95,65 @@ def generate_chatbot_data_summaries(
|
|
93 |
"""
|
94 |
data_summaries = {}
|
95 |
date_col_posts = token_state_value.get("config_date_col_posts", "published_at")
|
|
|
96 |
# Ensure date columns are datetime objects for proper formatting and comparison
|
97 |
-
if
|
|
|
|
|
|
|
98 |
filtered_merged_posts_df[date_col_posts] = pd.to_datetime(filtered_merged_posts_df[date_col_posts], errors='coerce')
|
99 |
-
|
100 |
-
|
|
|
|
|
101 |
# Add more date conversions as needed for other dataframes
|
102 |
|
103 |
for plot_cfg in plot_configs_list:
|
104 |
plot_id = plot_cfg["id"]
|
105 |
-
summary_text = f"
|
106 |
|
107 |
try:
|
108 |
-
if plot_id == "followers_count" and not date_filtered_follower_stats_df.empty:
|
109 |
df_summary = date_filtered_follower_stats_df[['date', 'follower_gains_monthly']].copy()
|
110 |
df_summary['date'] = df_summary['date'].dt.strftime('%Y-%m-%d')
|
111 |
-
summary_text = f"Follower Count (Monthly Gains):\n{df_summary.tail(5).to_string(index=False)}"
|
112 |
|
113 |
-
elif plot_id == "followers_growth_rate" and not date_filtered_follower_stats_df.empty:
|
114 |
-
df_summary = date_filtered_follower_stats_df[['date', 'growth_rate_monthly']].copy()
|
115 |
df_summary['date'] = df_summary['date'].dt.strftime('%Y-%m-%d')
|
116 |
-
summary_text = f"Follower Growth Rate (Monthly):\n{df_summary.tail(5).to_string(index=False)}"
|
117 |
-
|
118 |
-
elif plot_id == "followers_by_location" and not raw_follower_stats_df.empty and 'follower_geo' in raw_follower_stats_df.columns:
|
119 |
-
# Assuming 'follower_geo' contains location names and another column like 'count' exists
|
120 |
-
# This part needs to align with how generate_followers_by_demographics_plot processes 'follower_geo' data
|
121 |
-
# For simplicity, let's assume raw_follower_stats_df has pre-aggregated data for geo
|
122 |
-
# This is a placeholder, actual column names for count and name are needed from your data prep
|
123 |
-
if 'geo_name' in raw_follower_stats_df.columns and 'geo_count' in raw_follower_stats_df.columns:
|
124 |
-
df_summary = raw_follower_stats_df[['geo_name', 'geo_count']].nlargest(5, 'geo_count')
|
125 |
-
summary_text = f"Followers by Location (Top 5):\n{df_summary.to_string(index=False)}"
|
126 |
-
else:
|
127 |
-
summary_text = "Follower location data structure not as expected for summary."
|
128 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
129 |
|
130 |
-
|
|
|
131 |
df_summary = filtered_merged_posts_df[[date_col_posts, 'engagement_rate']].copy()
|
132 |
df_summary[date_col_posts] = df_summary[date_col_posts].dt.strftime('%Y-%m-%d')
|
133 |
-
summary_text = f"Engagement Rate Over Time:\n{df_summary.tail(5).to_string(index=False)}"
|
134 |
|
135 |
-
elif plot_id == "reach_over_time" and not filtered_merged_posts_df.empty:
|
136 |
df_summary = filtered_merged_posts_df[[date_col_posts, 'reach']].copy()
|
137 |
df_summary[date_col_posts] = df_summary[date_col_posts].dt.strftime('%Y-%m-%d')
|
138 |
-
summary_text = f"Reach Over Time:\n{df_summary.tail(5).to_string(index=False)}"
|
139 |
|
140 |
-
elif plot_id == "impressions_over_time" and not filtered_merged_posts_df.empty:
|
141 |
-
df_summary = filtered_merged_posts_df[[date_col_posts, 'impressions_sum']].copy()
|
142 |
df_summary[date_col_posts] = df_summary[date_col_posts].dt.strftime('%Y-%m-%d')
|
143 |
-
summary_text = f"Impressions Over Time:\n{df_summary.tail(5).to_string(index=False)}"
|
144 |
|
145 |
elif plot_id == "comments_sentiment" and not filtered_merged_posts_df.empty and 'comment_sentiment' in filtered_merged_posts_df.columns:
|
146 |
sentiment_counts = filtered_merged_posts_df['comment_sentiment'].value_counts().reset_index()
|
147 |
sentiment_counts.columns = ['Sentiment', 'Count']
|
148 |
summary_text = f"Comments Sentiment Breakdown:\n{sentiment_counts.to_string(index=False)}"
|
149 |
-
|
150 |
# Add more elif blocks for other plot_ids, extracting relevant data:
|
151 |
# e.g., likes_over_time, clicks_over_time, shares_over_time, comments_over_time
|
152 |
# post_frequency_cs, content_format_breakdown_cs, content_topic_breakdown_cs
|
@@ -217,7 +224,7 @@ def update_analytics_plots_figures(token_state_value, date_filter_option, custom
|
|
217 |
try:
|
218 |
# Dinamiche dei Follower (2 plots)
|
219 |
plot_figs.append(generate_followers_count_over_time_plot(date_filtered_follower_stats_df, type_value='follower_gains_monthly'))
|
220 |
-
plot_figs.append(generate_followers_growth_rate_plot(date_filtered_follower_stats_df, type_value='follower_gains_monthly'))
|
221 |
|
222 |
# Demografia Follower (4 plots)
|
223 |
plot_figs.append(generate_followers_by_demographics_plot(raw_follower_stats_df, type_value='follower_geo', plot_title="Follower per Località"))
|
@@ -228,7 +235,7 @@ def update_analytics_plots_figures(token_state_value, date_filter_option, custom
|
|
228 |
# Approfondimenti Performance Post (4 plots)
|
229 |
plot_figs.append(generate_engagement_rate_over_time_plot(filtered_merged_posts_df, date_column=date_column_posts))
|
230 |
plot_figs.append(generate_reach_over_time_plot(filtered_merged_posts_df, date_column=date_column_posts))
|
231 |
-
plot_figs.append(generate_impressions_over_time_plot(filtered_merged_posts_df, date_column=date_column_posts))
|
232 |
plot_figs.append(generate_likes_over_time_plot(filtered_merged_posts_df, date_column=date_column_posts))
|
233 |
|
234 |
# Engagement Dettagliato Post nel Tempo (4 plots)
|
@@ -288,13 +295,13 @@ def update_analytics_plots_figures(token_state_value, date_filter_option, custom
|
|
288 |
placeholder_figs_general = [create_placeholder_plot(title=plot_titles_for_errors[i] if i < len(plot_titles_for_errors) else f"Grafico {i+1}", message=str(e_general)) for i in range(num_expected_plots)]
|
289 |
for p_cfg in current_plot_configs: # Ensure summaries dict is populated on error
|
290 |
if p_cfg["id"] not in plot_data_summaries_for_chatbot:
|
291 |
-
|
292 |
return [error_msg] + placeholder_figs_general + [plot_data_summaries_for_chatbot]
|
293 |
|
294 |
|
295 |
# --- Gradio UI Blocks ---
|
296 |
with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue", secondary_hue="sky"),
|
297 |
-
|
298 |
token_state = gr.State(value={
|
299 |
"token": None, "client_id": None, "org_urn": None,
|
300 |
"bubble_posts_df": pd.DataFrame(), "bubble_post_stats_df": pd.DataFrame(),
|
@@ -361,8 +368,6 @@ with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue", secondary_hue="sky"),
|
|
361 |
outputs=[custom_start_date_picker, custom_end_date_picker]
|
362 |
)
|
363 |
|
364 |
-
# Moved plot_configs to be globally accessible within the Blocks scope if needed by update_analytics_plots_figures
|
365 |
-
# or pass it explicitly. For now, it's defined here.
|
366 |
plot_configs = [
|
367 |
{"label": "Numero di Follower nel Tempo", "id": "followers_count", "section": "Dinamiche dei Follower"},
|
368 |
{"label": "Tasso di Crescita Follower", "id": "followers_growth_rate", "section": "Dinamiche dei Follower"},
|
@@ -430,7 +435,8 @@ with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue", secondary_hue="sky"),
|
|
430 |
if not clicked_plot_config:
|
431 |
logging.error(f"Configurazione non trovata per plot_id {plot_id_clicked}")
|
432 |
num_button_updates = 2 * len(plot_configs) # insights, formula buttons
|
433 |
-
error_updates = [gr.update(visible=False)] *
|
|
|
434 |
error_updates.extend([current_active_action_from_state, current_chat_plot_id, current_chat_histories])
|
435 |
error_updates.extend([gr.update()] * num_button_updates)
|
436 |
return error_updates
|
@@ -448,7 +454,7 @@ with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue", secondary_hue="sky"),
|
|
448 |
insights_suggestions_row_visible_update = gr.update(visible=False)
|
449 |
formula_display_visible_update = gr.update(visible=False)
|
450 |
|
451 |
-
chatbot_content_update = gr.update()
|
452 |
suggestion_1_update = gr.update()
|
453 |
suggestion_2_update = gr.update()
|
454 |
suggestion_3_update = gr.update()
|
@@ -472,27 +478,38 @@ with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue", secondary_hue="sky"),
|
|
472 |
new_current_chat_plot_id = plot_id_clicked
|
473 |
chat_history_for_this_plot = current_chat_histories.get(plot_id_clicked, [])
|
474 |
|
475 |
-
# Get data summary for this plot
|
476 |
plot_specific_data_summary = current_plot_data_for_chatbot.get(plot_id_clicked, f"Nessun sommario dati specifico disponibile per '{clicked_plot_label}'.")
|
477 |
|
478 |
if not chat_history_for_this_plot:
|
479 |
-
|
480 |
plot_id_clicked,
|
481 |
clicked_plot_label,
|
482 |
-
plot_specific_data_summary
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
483 |
)
|
484 |
-
|
|
|
|
|
|
|
485 |
updated_chat_histories = current_chat_histories.copy()
|
486 |
updated_chat_histories[plot_id_clicked] = chat_history_for_this_plot
|
487 |
-
else:
|
488 |
-
|
489 |
-
_, suggestions = get_initial_insight_and_suggestions(
|
490 |
plot_id_clicked,
|
491 |
clicked_plot_label,
|
492 |
-
plot_specific_data_summary
|
493 |
)
|
494 |
|
495 |
-
|
496 |
chatbot_content_update = gr.update(value=chat_history_for_this_plot)
|
497 |
suggestion_1_update = gr.update(value=suggestions[0])
|
498 |
suggestion_2_update = gr.update(value=suggestions[1])
|
@@ -537,8 +554,8 @@ with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue", secondary_hue="sky"),
|
|
537 |
insights_suggestions_row_visible_update, suggestion_1_update, suggestion_2_update, suggestion_3_update,
|
538 |
formula_display_visible_update, formula_content_update,
|
539 |
new_active_action_state_to_set,
|
540 |
-
new_current_chat_plot_id,
|
541 |
-
updated_chat_histories
|
542 |
] + all_button_icon_updates
|
543 |
|
544 |
return final_updates
|
@@ -561,7 +578,6 @@ with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue", secondary_hue="sky"),
|
|
561 |
# Retrieve the specific data summary for the current plot
|
562 |
plot_specific_data_summary = current_plot_data_for_chatbot.get(current_plot_id, f"Nessun sommario dati specifico disponibile per '{plot_label}'.")
|
563 |
|
564 |
-
|
565 |
history_for_plot = chat_histories.get(current_plot_id, []).copy()
|
566 |
history_for_plot.append({"role": "user", "content": user_message})
|
567 |
|
@@ -573,7 +589,7 @@ with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue", secondary_hue="sky"),
|
|
573 |
user_message,
|
574 |
current_plot_id,
|
575 |
plot_label,
|
576 |
-
history_for_plot, # This history now includes the
|
577 |
plot_specific_data_summary # Explicitly pass for this turn if needed by LLM handler logic
|
578 |
)
|
579 |
|
@@ -660,7 +676,7 @@ with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue", secondary_hue="sky"),
|
|
660 |
action_panel_outputs_list.append(plot_ui_objects[pid_action]["bomb_button"])
|
661 |
action_panel_outputs_list.append(plot_ui_objects[pid_action]["formula_button"])
|
662 |
else:
|
663 |
-
action_panel_outputs_list.extend([
|
664 |
|
665 |
# Outputs for explore actions
|
666 |
explore_buttons_outputs_list = [explored_plot_id_state]
|
@@ -670,7 +686,7 @@ with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue", secondary_hue="sky"),
|
|
670 |
explore_buttons_outputs_list.append(plot_ui_objects[pid_explore]["panel_component"])
|
671 |
explore_buttons_outputs_list.append(plot_ui_objects[pid_explore]["explore_button"])
|
672 |
else:
|
673 |
-
explore_buttons_outputs_list.extend([
|
674 |
|
675 |
# Inputs for panel actions
|
676 |
action_click_inputs = [
|
@@ -767,16 +783,16 @@ with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue", secondary_hue="sky"),
|
|
767 |
|
768 |
all_updates.extend([
|
769 |
gr.update(visible=False), # global_actions_column_ui
|
770 |
-
gr.update(value=[], visible=False), # insights_chatbot_ui (value)
|
771 |
-
gr.update(value="", visible=False), # insights_chat_input_ui (value)
|
772 |
gr.update(visible=False), # insights_suggestions_row_ui
|
773 |
-
gr.update(value="Suggerimento 1"
|
774 |
-
gr.update(value="Suggerimento 2"
|
775 |
-
gr.update(value="Suggerimento 3"
|
776 |
gr.update(value="I dettagli sulla formula/metodologia appariranno qui.", visible=False), # formula_display_markdown_ui
|
777 |
None, # active_panel_action_state
|
778 |
None, # current_chat_plot_id_st
|
779 |
-
|
780 |
new_plot_data_summaries # NEW: plot_data_for_chatbot_st
|
781 |
])
|
782 |
|
@@ -786,9 +802,9 @@ with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue", secondary_hue="sky"),
|
|
786 |
all_updates.append(gr.update(value=BOMB_ICON))
|
787 |
all_updates.append(gr.update(value=FORMULA_ICON))
|
788 |
all_updates.append(gr.update(value=EXPLORE_ICON))
|
789 |
-
all_updates.append(gr.update(visible=True))
|
790 |
else:
|
791 |
-
all_updates.extend([
|
792 |
|
793 |
all_updates.append(None) # explored_plot_id_state
|
794 |
|
@@ -801,21 +817,21 @@ with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue", secondary_hue="sky"),
|
|
801 |
if pid_filter_sync in plot_ui_objects and "plot_component" in plot_ui_objects[pid_filter_sync]:
|
802 |
apply_filter_and_sync_outputs_list.append(plot_ui_objects[pid_filter_sync]["plot_component"])
|
803 |
else:
|
804 |
-
apply_filter_and_sync_outputs_list.append(
|
805 |
|
806 |
apply_filter_and_sync_outputs_list.extend([
|
807 |
-
global_actions_column_ui,
|
808 |
-
insights_chatbot_ui,
|
809 |
-
insights_chat_input_ui,
|
810 |
-
insights_suggestions_row_ui,
|
811 |
-
insights_suggestion_1_btn,
|
812 |
insights_suggestion_2_btn,
|
813 |
insights_suggestion_3_btn,
|
814 |
-
formula_display_markdown_ui,
|
815 |
-
active_panel_action_state,
|
816 |
-
current_chat_plot_id_st,
|
817 |
-
chat_histories_st,
|
818 |
-
plot_data_for_chatbot_st
|
819 |
])
|
820 |
|
821 |
for cfg_filter_sync_btns in plot_configs:
|
@@ -826,7 +842,7 @@ with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue", secondary_hue="sky"),
|
|
826 |
apply_filter_and_sync_outputs_list.append(plot_ui_objects[pid_filter_sync_btns]["explore_button"])
|
827 |
apply_filter_and_sync_outputs_list.append(plot_ui_objects[pid_filter_sync_btns]["panel_component"])
|
828 |
else:
|
829 |
-
apply_filter_and_sync_outputs_list.extend([
|
830 |
|
831 |
apply_filter_and_sync_outputs_list.append(explored_plot_id_state) # Reset state
|
832 |
|
@@ -897,4 +913,4 @@ if __name__ == "__main__":
|
|
897 |
except ImportError:
|
898 |
logging.warning("Matplotlib non trovato direttamente, ma potrebbe essere usato dai generatori di grafici.")
|
899 |
|
900 |
-
app.launch(server_name="0.0.0.0", server_port=7860, debug=True)
|
|
|
1 |
+
# app.py
|
2 |
+
# (Showing relevant parts that need modification)
|
3 |
import gradio as gr
|
4 |
import pandas as pd
|
5 |
import os
|
|
|
48 |
from formulas import PLOT_FORMULAS
|
49 |
|
50 |
# --- NEW CHATBOT MODULE IMPORTS ---
|
51 |
+
from chatbot_prompts import get_initial_insight_prompt_and_suggestions # MODIFIED IMPORT
|
52 |
from chatbot_handler import generate_llm_response
|
53 |
# --- END NEW CHATBOT MODULE IMPORTS ---
|
54 |
|
|
|
95 |
"""
|
96 |
data_summaries = {}
|
97 |
date_col_posts = token_state_value.get("config_date_col_posts", "published_at")
|
98 |
+
|
99 |
# Ensure date columns are datetime objects for proper formatting and comparison
|
100 |
+
# Make copies to avoid SettingWithCopyWarning if dataframes are slices
|
101 |
+
if not filtered_merged_posts_df.empty and date_col_posts in filtered_merged_posts_df.columns:
|
102 |
+
# Use .loc to ensure modification happens on the correct DataFrame
|
103 |
+
filtered_merged_posts_df = filtered_merged_posts_df.copy()
|
104 |
filtered_merged_posts_df[date_col_posts] = pd.to_datetime(filtered_merged_posts_df[date_col_posts], errors='coerce')
|
105 |
+
|
106 |
+
if not date_filtered_follower_stats_df.empty and 'date' in date_filtered_follower_stats_df.columns:
|
107 |
+
date_filtered_follower_stats_df = date_filtered_follower_stats_df.copy()
|
108 |
+
date_filtered_follower_stats_df['date'] = pd.to_datetime(date_filtered_follower_stats_df['date'], errors='coerce')
|
109 |
# Add more date conversions as needed for other dataframes
|
110 |
|
111 |
for plot_cfg in plot_configs_list:
|
112 |
plot_id = plot_cfg["id"]
|
113 |
+
summary_text = f"Nessun sommario dati specifico disponibile per '{plot_cfg['label']}' per il periodo selezionato." # Ensure this matches prompt logic
|
114 |
|
115 |
try:
|
116 |
+
if plot_id == "followers_count" and not date_filtered_follower_stats_df.empty and 'follower_gains_monthly' in date_filtered_follower_stats_df.columns and 'date' in date_filtered_follower_stats_df.columns:
|
117 |
df_summary = date_filtered_follower_stats_df[['date', 'follower_gains_monthly']].copy()
|
118 |
df_summary['date'] = df_summary['date'].dt.strftime('%Y-%m-%d')
|
119 |
+
summary_text = f"Follower Count (Monthly Gains):\n{df_summary.sort_values(by='date').tail(5).to_string(index=False)}"
|
120 |
|
121 |
+
elif plot_id == "followers_growth_rate" and not date_filtered_follower_stats_df.empty and 'growth_rate_monthly' in date_filtered_follower_stats_df.columns and 'date' in date_filtered_follower_stats_df.columns:
|
122 |
+
df_summary = date_filtered_follower_stats_df[['date', 'growth_rate_monthly']].copy()
|
123 |
df_summary['date'] = df_summary['date'].dt.strftime('%Y-%m-%d')
|
124 |
+
summary_text = f"Follower Growth Rate (Monthly %):\n{df_summary.sort_values(by='date').tail(5).to_string(index=False)}"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
125 |
|
126 |
+
elif plot_id == "followers_by_location" and not raw_follower_stats_df.empty:
|
127 |
+
# This assumes 'follower_geo' is a column that needs processing similar to the plot generator
|
128 |
+
# For simplicity, if your raw_follower_stats_df might have pre-aggregated 'geo_name' and 'geo_count'
|
129 |
+
if 'follower_geo_processed_for_summary' in raw_follower_stats_df.columns: # Placeholder for actual processed data
|
130 |
+
# Example: df_summary = raw_follower_stats_df[['geo_name', 'geo_count']].nlargest(5, 'geo_count')
|
131 |
+
# summary_text = f"Followers by Location (Top 5):\n{df_summary.to_string(index=False)}"
|
132 |
+
pass # Implement actual summary logic based on your data structure
|
133 |
+
else: # Fallback if specific processed columns aren't ready for summary
|
134 |
+
summary_text = f"Follower location demographic data for '{plot_cfg['label']}' is complex; specific summary requires pre-processing aligned with the chart."
|
135 |
|
136 |
+
|
137 |
+
elif plot_id == "engagement_rate" and not filtered_merged_posts_df.empty and 'engagement_rate' in filtered_merged_posts_df.columns and date_col_posts in filtered_merged_posts_df.columns:
|
138 |
df_summary = filtered_merged_posts_df[[date_col_posts, 'engagement_rate']].copy()
|
139 |
df_summary[date_col_posts] = df_summary[date_col_posts].dt.strftime('%Y-%m-%d')
|
140 |
+
summary_text = f"Engagement Rate Over Time (%):\n{df_summary.sort_values(by=date_col_posts).tail(5).to_string(index=False)}"
|
141 |
|
142 |
+
elif plot_id == "reach_over_time" and not filtered_merged_posts_df.empty and 'reach' in filtered_merged_posts_df.columns and date_col_posts in filtered_merged_posts_df.columns:
|
143 |
df_summary = filtered_merged_posts_df[[date_col_posts, 'reach']].copy()
|
144 |
df_summary[date_col_posts] = df_summary[date_col_posts].dt.strftime('%Y-%m-%d')
|
145 |
+
summary_text = f"Reach Over Time:\n{df_summary.sort_values(by=date_col_posts).tail(5).to_string(index=False)}"
|
146 |
|
147 |
+
elif plot_id == "impressions_over_time" and not filtered_merged_posts_df.empty and 'impressions_sum' in filtered_merged_posts_df.columns and date_col_posts in filtered_merged_posts_df.columns:
|
148 |
+
df_summary = filtered_merged_posts_df[[date_col_posts, 'impressions_sum']].copy()
|
149 |
df_summary[date_col_posts] = df_summary[date_col_posts].dt.strftime('%Y-%m-%d')
|
150 |
+
summary_text = f"Impressions Over Time:\n{df_summary.sort_values(by=date_col_posts).tail(5).to_string(index=False)}"
|
151 |
|
152 |
elif plot_id == "comments_sentiment" and not filtered_merged_posts_df.empty and 'comment_sentiment' in filtered_merged_posts_df.columns:
|
153 |
sentiment_counts = filtered_merged_posts_df['comment_sentiment'].value_counts().reset_index()
|
154 |
sentiment_counts.columns = ['Sentiment', 'Count']
|
155 |
summary_text = f"Comments Sentiment Breakdown:\n{sentiment_counts.to_string(index=False)}"
|
156 |
+
|
157 |
# Add more elif blocks for other plot_ids, extracting relevant data:
|
158 |
# e.g., likes_over_time, clicks_over_time, shares_over_time, comments_over_time
|
159 |
# post_frequency_cs, content_format_breakdown_cs, content_topic_breakdown_cs
|
|
|
224 |
try:
|
225 |
# Dinamiche dei Follower (2 plots)
|
226 |
plot_figs.append(generate_followers_count_over_time_plot(date_filtered_follower_stats_df, type_value='follower_gains_monthly'))
|
227 |
+
plot_figs.append(generate_followers_growth_rate_plot(date_filtered_follower_stats_df, type_value='follower_gains_monthly')) # Assuming this uses 'follower_gains_monthly' to calculate rate
|
228 |
|
229 |
# Demografia Follower (4 plots)
|
230 |
plot_figs.append(generate_followers_by_demographics_plot(raw_follower_stats_df, type_value='follower_geo', plot_title="Follower per Località"))
|
|
|
235 |
# Approfondimenti Performance Post (4 plots)
|
236 |
plot_figs.append(generate_engagement_rate_over_time_plot(filtered_merged_posts_df, date_column=date_column_posts))
|
237 |
plot_figs.append(generate_reach_over_time_plot(filtered_merged_posts_df, date_column=date_column_posts))
|
238 |
+
plot_figs.append(generate_impressions_over_time_plot(filtered_merged_posts_df, date_column=date_column_posts)) # Ensure 'impressions_sum' or equivalent is used by this func
|
239 |
plot_figs.append(generate_likes_over_time_plot(filtered_merged_posts_df, date_column=date_column_posts))
|
240 |
|
241 |
# Engagement Dettagliato Post nel Tempo (4 plots)
|
|
|
295 |
placeholder_figs_general = [create_placeholder_plot(title=plot_titles_for_errors[i] if i < len(plot_titles_for_errors) else f"Grafico {i+1}", message=str(e_general)) for i in range(num_expected_plots)]
|
296 |
for p_cfg in current_plot_configs: # Ensure summaries dict is populated on error
|
297 |
if p_cfg["id"] not in plot_data_summaries_for_chatbot:
|
298 |
+
plot_data_summaries_for_chatbot[p_cfg["id"]] = f"Errore generale grafici: {e_general}"
|
299 |
return [error_msg] + placeholder_figs_general + [plot_data_summaries_for_chatbot]
|
300 |
|
301 |
|
302 |
# --- Gradio UI Blocks ---
|
303 |
with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue", secondary_hue="sky"),
|
304 |
+
title="LinkedIn Organization Dashboard") as app:
|
305 |
token_state = gr.State(value={
|
306 |
"token": None, "client_id": None, "org_urn": None,
|
307 |
"bubble_posts_df": pd.DataFrame(), "bubble_post_stats_df": pd.DataFrame(),
|
|
|
368 |
outputs=[custom_start_date_picker, custom_end_date_picker]
|
369 |
)
|
370 |
|
|
|
|
|
371 |
plot_configs = [
|
372 |
{"label": "Numero di Follower nel Tempo", "id": "followers_count", "section": "Dinamiche dei Follower"},
|
373 |
{"label": "Tasso di Crescita Follower", "id": "followers_growth_rate", "section": "Dinamiche dei Follower"},
|
|
|
435 |
if not clicked_plot_config:
|
436 |
logging.error(f"Configurazione non trovata per plot_id {plot_id_clicked}")
|
437 |
num_button_updates = 2 * len(plot_configs) # insights, formula buttons
|
438 |
+
error_updates = [gr.update(visible=False)] * 7 # action_col, chatbot, input, suggestions_row, 3x sugg_btn
|
439 |
+
error_updates.append(gr.update(visible=False, value="")) # formula_md (visibility and value)
|
440 |
error_updates.extend([current_active_action_from_state, current_chat_plot_id, current_chat_histories])
|
441 |
error_updates.extend([gr.update()] * num_button_updates)
|
442 |
return error_updates
|
|
|
454 |
insights_suggestions_row_visible_update = gr.update(visible=False)
|
455 |
formula_display_visible_update = gr.update(visible=False)
|
456 |
|
457 |
+
chatbot_content_update = gr.update() # No change by default
|
458 |
suggestion_1_update = gr.update()
|
459 |
suggestion_2_update = gr.update()
|
460 |
suggestion_3_update = gr.update()
|
|
|
478 |
new_current_chat_plot_id = plot_id_clicked
|
479 |
chat_history_for_this_plot = current_chat_histories.get(plot_id_clicked, [])
|
480 |
|
|
|
481 |
plot_specific_data_summary = current_plot_data_for_chatbot.get(plot_id_clicked, f"Nessun sommario dati specifico disponibile per '{clicked_plot_label}'.")
|
482 |
|
483 |
if not chat_history_for_this_plot:
|
484 |
+
initial_llm_prompt, suggestions = get_initial_insight_prompt_and_suggestions(
|
485 |
plot_id_clicked,
|
486 |
clicked_plot_label,
|
487 |
+
plot_specific_data_summary
|
488 |
+
)
|
489 |
+
# History for LLM's first turn: the system's prompt as a user message
|
490 |
+
history_for_llm_first_turn = [{"role": "user", "content": initial_llm_prompt}]
|
491 |
+
|
492 |
+
logging.info(f"Generating initial LLM insight for {plot_id_clicked}...")
|
493 |
+
initial_bot_response_text = await generate_llm_response(
|
494 |
+
user_message=initial_llm_prompt, # For context/logging in handler
|
495 |
+
plot_id=plot_id_clicked,
|
496 |
+
plot_label=clicked_plot_label,
|
497 |
+
chat_history_for_plot=history_for_llm_first_turn,
|
498 |
+
plot_data_summary=plot_specific_data_summary
|
499 |
)
|
500 |
+
logging.info(f"LLM initial insight received for {plot_id_clicked}.")
|
501 |
+
|
502 |
+
# History for Gradio display starts with the assistant's response
|
503 |
+
chat_history_for_this_plot = [{"role": "assistant", "content": initial_bot_response_text}]
|
504 |
updated_chat_histories = current_chat_histories.copy()
|
505 |
updated_chat_histories[plot_id_clicked] = chat_history_for_this_plot
|
506 |
+
else: # History exists, get fresh suggestions
|
507 |
+
_, suggestions = get_initial_insight_prompt_and_suggestions(
|
|
|
508 |
plot_id_clicked,
|
509 |
clicked_plot_label,
|
510 |
+
plot_specific_data_summary
|
511 |
)
|
512 |
|
|
|
513 |
chatbot_content_update = gr.update(value=chat_history_for_this_plot)
|
514 |
suggestion_1_update = gr.update(value=suggestions[0])
|
515 |
suggestion_2_update = gr.update(value=suggestions[1])
|
|
|
554 |
insights_suggestions_row_visible_update, suggestion_1_update, suggestion_2_update, suggestion_3_update,
|
555 |
formula_display_visible_update, formula_content_update,
|
556 |
new_active_action_state_to_set,
|
557 |
+
new_current_chat_plot_id,
|
558 |
+
updated_chat_histories
|
559 |
] + all_button_icon_updates
|
560 |
|
561 |
return final_updates
|
|
|
578 |
# Retrieve the specific data summary for the current plot
|
579 |
plot_specific_data_summary = current_plot_data_for_chatbot.get(current_plot_id, f"Nessun sommario dati specifico disponibile per '{plot_label}'.")
|
580 |
|
|
|
581 |
history_for_plot = chat_histories.get(current_plot_id, []).copy()
|
582 |
history_for_plot.append({"role": "user", "content": user_message})
|
583 |
|
|
|
589 |
user_message,
|
590 |
current_plot_id,
|
591 |
plot_label,
|
592 |
+
history_for_plot, # This history now includes the user message
|
593 |
plot_specific_data_summary # Explicitly pass for this turn if needed by LLM handler logic
|
594 |
)
|
595 |
|
|
|
676 |
action_panel_outputs_list.append(plot_ui_objects[pid_action]["bomb_button"])
|
677 |
action_panel_outputs_list.append(plot_ui_objects[pid_action]["formula_button"])
|
678 |
else:
|
679 |
+
action_panel_outputs_list.extend([gr.update(), gr.update()]) # Use gr.update() as placeholder
|
680 |
|
681 |
# Outputs for explore actions
|
682 |
explore_buttons_outputs_list = [explored_plot_id_state]
|
|
|
686 |
explore_buttons_outputs_list.append(plot_ui_objects[pid_explore]["panel_component"])
|
687 |
explore_buttons_outputs_list.append(plot_ui_objects[pid_explore]["explore_button"])
|
688 |
else:
|
689 |
+
explore_buttons_outputs_list.extend([gr.update(), gr.update()])
|
690 |
|
691 |
# Inputs for panel actions
|
692 |
action_click_inputs = [
|
|
|
783 |
|
784 |
all_updates.extend([
|
785 |
gr.update(visible=False), # global_actions_column_ui
|
786 |
+
gr.update(value=[], visible=False), # insights_chatbot_ui (value & visibility)
|
787 |
+
gr.update(value="", visible=False), # insights_chat_input_ui (value & visibility)
|
788 |
gr.update(visible=False), # insights_suggestions_row_ui
|
789 |
+
gr.update(value="Suggerimento 1"), # insights_suggestion_1_btn (reset value, visibility handled by row)
|
790 |
+
gr.update(value="Suggerimento 2"), # insights_suggestion_2_btn
|
791 |
+
gr.update(value="Suggerimento 3"), # insights_suggestion_3_btn
|
792 |
gr.update(value="I dettagli sulla formula/metodologia appariranno qui.", visible=False), # formula_display_markdown_ui
|
793 |
None, # active_panel_action_state
|
794 |
None, # current_chat_plot_id_st
|
795 |
+
{}, # chat_histories_st (reset chat histories on filter change)
|
796 |
new_plot_data_summaries # NEW: plot_data_for_chatbot_st
|
797 |
])
|
798 |
|
|
|
802 |
all_updates.append(gr.update(value=BOMB_ICON))
|
803 |
all_updates.append(gr.update(value=FORMULA_ICON))
|
804 |
all_updates.append(gr.update(value=EXPLORE_ICON))
|
805 |
+
all_updates.append(gr.update(visible=True)) # panel_component visibility
|
806 |
else:
|
807 |
+
all_updates.extend([gr.update(), gr.update(), gr.update(), gr.update()])
|
808 |
|
809 |
all_updates.append(None) # explored_plot_id_state
|
810 |
|
|
|
817 |
if pid_filter_sync in plot_ui_objects and "plot_component" in plot_ui_objects[pid_filter_sync]:
|
818 |
apply_filter_and_sync_outputs_list.append(plot_ui_objects[pid_filter_sync]["plot_component"])
|
819 |
else:
|
820 |
+
apply_filter_and_sync_outputs_list.append(gr.update())
|
821 |
|
822 |
apply_filter_and_sync_outputs_list.extend([
|
823 |
+
global_actions_column_ui, # Reset visibility
|
824 |
+
insights_chatbot_ui, # Reset content & visibility
|
825 |
+
insights_chat_input_ui, # Reset content & visibility
|
826 |
+
insights_suggestions_row_ui, # Reset visibility
|
827 |
+
insights_suggestion_1_btn, # Reset text & visibility
|
828 |
insights_suggestion_2_btn,
|
829 |
insights_suggestion_3_btn,
|
830 |
+
formula_display_markdown_ui, # Reset content & visibility
|
831 |
+
active_panel_action_state, # Reset state
|
832 |
+
current_chat_plot_id_st, # Reset state
|
833 |
+
chat_histories_st, # Preserve or reset state (resetting via refresh_all_analytics_ui_elements)
|
834 |
+
plot_data_for_chatbot_st # NEW: Update this state
|
835 |
])
|
836 |
|
837 |
for cfg_filter_sync_btns in plot_configs:
|
|
|
842 |
apply_filter_and_sync_outputs_list.append(plot_ui_objects[pid_filter_sync_btns]["explore_button"])
|
843 |
apply_filter_and_sync_outputs_list.append(plot_ui_objects[pid_filter_sync_btns]["panel_component"])
|
844 |
else:
|
845 |
+
apply_filter_and_sync_outputs_list.extend([gr.update(), gr.update(), gr.update(), gr.update()])
|
846 |
|
847 |
apply_filter_and_sync_outputs_list.append(explored_plot_id_state) # Reset state
|
848 |
|
|
|
913 |
except ImportError:
|
914 |
logging.warning("Matplotlib non trovato direttamente, ma potrebbe essere usato dai generatori di grafici.")
|
915 |
|
916 |
+
app.launch(server_name="0.0.0.0", server_port=7860, debug=True)
|