updated
Browse files
app.py
CHANGED
|
@@ -657,13 +657,13 @@ with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue", secondary_hue="orange"),
|
|
| 657 |
|
| 658 |
output_path = "filtered_news_data.csv"; display_df.to_csv(output_path, index=False)
|
| 659 |
return display_df, output_path, analyzed_df
|
| 660 |
-
|
| 661 |
start_scraper_button.click(
|
| 662 |
fn=news_scraper_workflow,
|
| 663 |
inputs=[search_keywords_textbox, sites_to_search_textbox, start_date_textbox, end_date_textbox, interval_days_slider, max_pages_slider, filter_keywords_textbox],
|
| 664 |
outputs=[scraper_results_df, scraper_download_file, scraper_results_state]
|
| 665 |
)
|
| 666 |
-
|
| 667 |
def update_news_dashboards(analyzed_df):
|
| 668 |
if analyzed_df is None or analyzed_df.empty:
|
| 669 |
return [gr.update(visible=False), '', '', '', None, None, None, gr.update(visible=False), None, None]
|
|
@@ -682,14 +682,14 @@ with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue", secondary_hue="orange"),
|
|
| 682 |
sentiment_updates.get(sentiment_pie_plot, None),
|
| 683 |
sentiment_updates.get(sentiment_by_media_plot, None)
|
| 684 |
]
|
| 685 |
-
|
| 686 |
news_ui_components = [
|
| 687 |
scraper_dashboard_group, kpi_total_articles, kpi_unique_media, kpi_date_range,
|
| 688 |
dashboard_timeline_plot, dashboard_media_plot, dashboard_wordcloud_plot,
|
| 689 |
sentiment_dashboard_tab, sentiment_pie_plot, sentiment_by_media_plot
|
| 690 |
]
|
| 691 |
scraper_results_state.change(fn=update_news_dashboards, inputs=scraper_results_state, outputs=news_ui_components)
|
| 692 |
-
|
| 693 |
# --- YOUTUBE WORKFLOW ---
|
| 694 |
def youtube_workflow(api_key, query, max_stats, num_comments, max_comments, published_after, progress=gr.Progress()):
|
| 695 |
sanitized_api_key = api_key.strip()
|
|
@@ -699,30 +699,31 @@ with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue", secondary_hue="orange"),
|
|
| 699 |
)
|
| 700 |
if videos_df_full.empty:
|
| 701 |
gr.Info("No videos found for your YouTube query."); return None, None
|
| 702 |
-
|
| 703 |
if comments_df is not None and not comments_df.empty:
|
| 704 |
progress(0.9, desc="Analyzing comment sentiment...")
|
| 705 |
comments_df = run_sentiment_analysis(comments_df.copy(), 'comment_text', progress)
|
| 706 |
|
| 707 |
top_videos_for_display = videos_df_full.head(int(num_comments))
|
| 708 |
return top_videos_for_display, {"full_scan": videos_df_full, "comments": comments_df, "total_estimate": total_vids_est}
|
| 709 |
-
|
| 710 |
start_yt_analysis_button.click(
|
| 711 |
fn=youtube_workflow,
|
| 712 |
inputs=[yt_api_key, yt_search_keywords, yt_max_videos_for_stats, yt_num_videos_for_comments, yt_max_comments, yt_published_after],
|
| 713 |
outputs=[yt_videos_df_output, youtube_results_state]
|
| 714 |
)
|
| 715 |
-
|
| 716 |
def update_youtube_dashboards(results_data):
|
| 717 |
-
#
|
| 718 |
if not results_data or results_data.get("full_scan") is None or results_data["full_scan"].empty:
|
|
|
|
| 719 |
return [gr.update(visible=False), "0", "0", "0", "0", None, None, None, None, None, None, None, None]
|
| 720 |
-
|
| 721 |
videos_df_full, comments_df, total_estimate = results_data.get("full_scan"), results_data.get("comments"), results_data.get("total_estimate", 0)
|
| 722 |
deep_dive_updates = generate_youtube_dashboard(videos_df_full, comments_df)
|
| 723 |
fig_ch_views, fig_quad, fig_age = generate_youtube_topic_dashboard(videos_df_full)
|
| 724 |
-
|
| 725 |
-
# This return
|
| 726 |
return [
|
| 727 |
gr.update(visible=True),
|
| 728 |
f"{total_estimate:,}",
|
|
@@ -731,21 +732,22 @@ with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue", secondary_hue="orange"),
|
|
| 731 |
deep_dive_updates.get(kpi_yt_comments_scraped, "0"),
|
| 732 |
deep_dive_updates.get('yt_channel_plot', None),
|
| 733 |
deep_dive_updates.get('yt_wordcloud_plot', None),
|
| 734 |
-
fig_ch_views,
|
| 735 |
-
fig_quad,
|
| 736 |
-
fig_age,
|
| 737 |
deep_dive_updates.get('yt_top_videos_plot', None),
|
| 738 |
deep_dive_updates.get('yt_engagement_plot', None),
|
| 739 |
-
deep_dive_updates.get('yt_comment_activity_plot', None)
|
|
|
|
|
|
|
|
|
|
| 740 |
]
|
| 741 |
|
|
|
|
|
|
|
| 742 |
yt_ui_components = [
|
| 743 |
yt_dashboard_group, kpi_yt_total_topic_videos, kpi_yt_videos_found, kpi_yt_views_scanned, kpi_yt_comments_scraped,
|
| 744 |
-
yt_channel_plot, yt_wordcloud_plot,
|
| 745 |
-
yt_channel_views_plot, yt_performance_quadrant_plot, yt_content_age_plot
|
| 746 |
]
|
| 747 |
-
youtube_results_state.change(fn=update_youtube_dashboards, inputs=youtube_results_state, outputs=yt_ui_components)
|
| 748 |
-
|
| 749 |
# ==============================================================================
|
| 750 |
# LAUNCH THE APP
|
| 751 |
# ==============================================================================
|
|
|
|
| 657 |
|
| 658 |
output_path = "filtered_news_data.csv"; display_df.to_csv(output_path, index=False)
|
| 659 |
return display_df, output_path, analyzed_df
|
| 660 |
+
|
| 661 |
start_scraper_button.click(
|
| 662 |
fn=news_scraper_workflow,
|
| 663 |
inputs=[search_keywords_textbox, sites_to_search_textbox, start_date_textbox, end_date_textbox, interval_days_slider, max_pages_slider, filter_keywords_textbox],
|
| 664 |
outputs=[scraper_results_df, scraper_download_file, scraper_results_state]
|
| 665 |
)
|
| 666 |
+
|
| 667 |
def update_news_dashboards(analyzed_df):
|
| 668 |
if analyzed_df is None or analyzed_df.empty:
|
| 669 |
return [gr.update(visible=False), '', '', '', None, None, None, gr.update(visible=False), None, None]
|
|
|
|
| 682 |
sentiment_updates.get(sentiment_pie_plot, None),
|
| 683 |
sentiment_updates.get(sentiment_by_media_plot, None)
|
| 684 |
]
|
| 685 |
+
|
| 686 |
news_ui_components = [
|
| 687 |
scraper_dashboard_group, kpi_total_articles, kpi_unique_media, kpi_date_range,
|
| 688 |
dashboard_timeline_plot, dashboard_media_plot, dashboard_wordcloud_plot,
|
| 689 |
sentiment_dashboard_tab, sentiment_pie_plot, sentiment_by_media_plot
|
| 690 |
]
|
| 691 |
scraper_results_state.change(fn=update_news_dashboards, inputs=scraper_results_state, outputs=news_ui_components)
|
| 692 |
+
|
| 693 |
# --- YOUTUBE WORKFLOW ---
|
| 694 |
def youtube_workflow(api_key, query, max_stats, num_comments, max_comments, published_after, progress=gr.Progress()):
|
| 695 |
sanitized_api_key = api_key.strip()
|
|
|
|
| 699 |
)
|
| 700 |
if videos_df_full.empty:
|
| 701 |
gr.Info("No videos found for your YouTube query."); return None, None
|
| 702 |
+
|
| 703 |
if comments_df is not None and not comments_df.empty:
|
| 704 |
progress(0.9, desc="Analyzing comment sentiment...")
|
| 705 |
comments_df = run_sentiment_analysis(comments_df.copy(), 'comment_text', progress)
|
| 706 |
|
| 707 |
top_videos_for_display = videos_df_full.head(int(num_comments))
|
| 708 |
return top_videos_for_display, {"full_scan": videos_df_full, "comments": comments_df, "total_estimate": total_vids_est}
|
| 709 |
+
|
| 710 |
start_yt_analysis_button.click(
|
| 711 |
fn=youtube_workflow,
|
| 712 |
inputs=[yt_api_key, yt_search_keywords, yt_max_videos_for_stats, yt_num_videos_for_comments, yt_max_comments, yt_published_after],
|
| 713 |
outputs=[yt_videos_df_output, youtube_results_state]
|
| 714 |
)
|
| 715 |
+
|
| 716 |
def update_youtube_dashboards(results_data):
|
| 717 |
+
# This function is now corrected.
|
| 718 |
if not results_data or results_data.get("full_scan") is None or results_data["full_scan"].empty:
|
| 719 |
+
# Return the correct number of empty items (13) to match the component list
|
| 720 |
return [gr.update(visible=False), "0", "0", "0", "0", None, None, None, None, None, None, None, None]
|
| 721 |
+
|
| 722 |
videos_df_full, comments_df, total_estimate = results_data.get("full_scan"), results_data.get("comments"), results_data.get("total_estimate", 0)
|
| 723 |
deep_dive_updates = generate_youtube_dashboard(videos_df_full, comments_df)
|
| 724 |
fig_ch_views, fig_quad, fig_age = generate_youtube_topic_dashboard(videos_df_full)
|
| 725 |
+
|
| 726 |
+
# This return list now perfectly matches the yt_ui_components list below.
|
| 727 |
return [
|
| 728 |
gr.update(visible=True),
|
| 729 |
f"{total_estimate:,}",
|
|
|
|
| 732 |
deep_dive_updates.get(kpi_yt_comments_scraped, "0"),
|
| 733 |
deep_dive_updates.get('yt_channel_plot', None),
|
| 734 |
deep_dive_updates.get('yt_wordcloud_plot', None),
|
|
|
|
|
|
|
|
|
|
| 735 |
deep_dive_updates.get('yt_top_videos_plot', None),
|
| 736 |
deep_dive_updates.get('yt_engagement_plot', None),
|
| 737 |
+
deep_dive_updates.get('yt_comment_activity_plot', None),
|
| 738 |
+
fig_ch_views,
|
| 739 |
+
fig_quad,
|
| 740 |
+
fig_age
|
| 741 |
]
|
| 742 |
|
| 743 |
+
# This is the list that was causing the error.
|
| 744 |
+
# The undefined variables `yt_sentiment_pie_plot` and `yt_sentiment_by_video_plot` have been removed.
|
| 745 |
yt_ui_components = [
|
| 746 |
yt_dashboard_group, kpi_yt_total_topic_videos, kpi_yt_videos_found, kpi_yt_views_scanned, kpi_yt_comments_scraped,
|
| 747 |
+
yt_channel_plot, yt_wordcloud_plot, yt_top_videos_plot, yt_engagement_plot,
|
| 748 |
+
yt_comment_activity_plot, yt_channel_views_plot, yt_performance_quadrant_plot, yt_content_age_plot
|
| 749 |
]
|
| 750 |
+
youtube_results_state.change(fn=update_youtube_dashboards, inputs=youtube_results_state, outputs=yt_ui_components)
|
|
|
|
| 751 |
# ==============================================================================
|
| 752 |
# LAUNCH THE APP
|
| 753 |
# ==============================================================================
|