Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -4,6 +4,8 @@ import pandas as pd
|
|
| 4 |
import plotly.express as px
|
| 5 |
import numpy as np # for a tiny linear-forecast
|
| 6 |
|
|
|
|
|
|
|
| 7 |
from search import get_news
|
| 8 |
from llm import summarize
|
| 9 |
from huggingface_nlp import analyze_sentiment, analyze_entities, extract_keywords
|
|
@@ -345,19 +347,46 @@ def export_briefing_pdf(topic: str, briefing_md: str, timestamp_str: str):
|
|
| 345 |
|
| 346 |
# ---------------------- Gradio callbacks ----------------------
|
| 347 |
def analyze_news(mode, preset_company, topic, days, k, entity_filter, sentiment_filter, fast_mode):
|
|
|
|
| 348 |
query_hint = ONE_CLICK.get(mode, ONE_CLICK["General"])["query_hint"] if mode in ONE_CLICK else ""
|
| 349 |
|
| 350 |
-
#
|
| 351 |
if preset_company and preset_company.lower() not in (topic or "").lower():
|
| 352 |
topic = f"{topic} {preset_company}".strip()
|
| 353 |
-
|
|
|
|
| 354 |
rows, df, mdf, rollup, briefing, press, jobs, ts = run_pipeline(
|
| 355 |
topic, days, k, query_hint=query_hint, fast=bool(fast_mode)
|
| 356 |
)
|
| 357 |
-
|
| 358 |
-
|
| 359 |
-
|
| 360 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 361 |
|
| 362 |
# wiring: include fast_mode in inputs
|
| 363 |
run_btn.click(
|
|
@@ -403,22 +432,24 @@ with gr.Blocks(theme=gr.themes.Soft(primary_hue="violet", neutral_hue="slate"))
|
|
| 403 |
</div>
|
| 404 |
""")
|
| 405 |
|
|
|
|
| 406 |
with gr.Row():
|
| 407 |
mode = gr.Dropdown(choices=list(ONE_CLICK.keys()), value="General", label="One-Click Mode")
|
| 408 |
preset_company = gr.Dropdown(choices=H1B_TECH_PRESETS, label="Company Presets (H-1B Tech)", allow_custom_value=True)
|
| 409 |
-
topic = gr.Textbox(label="Topic / Company",
|
| 410 |
-
value="", # was "NVIDIA"
|
| 411 |
placeholder="e.g., AMD, Healthcare AI, EV market India")
|
| 412 |
days = gr.Slider(1, 30, value=7, step=1, label="Lookback (days)")
|
| 413 |
-
k = gr.Slider(3,
|
| 414 |
fast_mode = gr.Checkbox(value=True, label="β‘ Fast mode (skip Entities & Key Phrases)")
|
| 415 |
|
| 416 |
with gr.Row():
|
| 417 |
entity_filter = gr.Dropdown(choices=[], label="Filter by Mentioned Company/Person", value=None)
|
| 418 |
sentiment_filter = gr.Dropdown(choices=["ALL","POSITIVE","NEUTRAL","NEGATIVE","MIXED"], value="ALL", label="Sentiment filter")
|
| 419 |
|
|
|
|
| 420 |
run_btn = gr.Button("Run Analysis", variant="primary")
|
| 421 |
|
|
|
|
| 422 |
header_bar = gr.Markdown(value="ποΈ NewsIntel β Data last updated: β")
|
| 423 |
with gr.Tab("Insights"):
|
| 424 |
tip_md = gr.Markdown("π‘ **Tip:** *Entities* are detected names of companies/people/places (e.g., βTSMCβ, βARMβ). Use the filters to focus the feed.")
|
|
@@ -445,20 +476,18 @@ with gr.Blocks(theme=gr.themes.Soft(primary_hue="violet", neutral_hue="slate"))
|
|
| 445 |
email_btn = gr.Button("Email Weekly Briefing (SES)")
|
| 446 |
email_status = gr.Markdown()
|
| 447 |
|
| 448 |
-
#
|
| 449 |
def _apply_mode(m, current_topic):
|
| 450 |
cfg = ONE_CLICK.get(m, ONE_CLICK["General"])
|
| 451 |
-
|
| 452 |
-
new_value = current_topic or cfg.get("topic", "")
|
| 453 |
-
return gr.update(value=new_value)
|
| 454 |
|
| 455 |
mode.change(_apply_mode, inputs=[mode, topic], outputs=[topic])
|
| 456 |
-
|
| 457 |
preset_company.change(lambda x: x or "", inputs=preset_company, outputs=topic)
|
| 458 |
|
|
|
|
| 459 |
run_btn.click(
|
| 460 |
analyze_news,
|
| 461 |
-
inputs=[mode, preset_company, topic, days, k, entity_filter, sentiment_filter],
|
| 462 |
outputs=[header_bar, cards, plot_sent, plot_trend, plot_forecast, table, per_article, rollup, briefing_md, entity_filter]
|
| 463 |
).then(
|
| 464 |
lambda: datetime.datetime.now().strftime("%b %d, %Y %I:%M %p"),
|
|
@@ -468,6 +497,7 @@ with gr.Blocks(theme=gr.themes.Soft(primary_hue="violet", neutral_hue="slate"))
|
|
| 468 |
export_btn.click(export_cb, inputs=[topic, briefing_md, timestamp_str], outputs=[export_html, export_pdf, s3_links])
|
| 469 |
email_btn.click(email_weekly_cb, inputs=[topic, weekly_email, briefing_md, timestamp_str], outputs=[email_status])
|
| 470 |
|
|
|
|
| 471 |
if __name__ == "__main__":
|
| 472 |
print("π Launching NewsIntel (light-only UI + caching + one-click modes + forecast)")
|
| 473 |
demo.launch()
|
|
|
|
| 4 |
import plotly.express as px
|
| 5 |
import numpy as np # for a tiny linear-forecast
|
| 6 |
|
| 7 |
+
from concurrent.futures import ThreadPoolExecutor, as_completed
|
| 8 |
+
|
| 9 |
from search import get_news
|
| 10 |
from llm import summarize
|
| 11 |
from huggingface_nlp import analyze_sentiment, analyze_entities, extract_keywords
|
|
|
|
| 347 |
|
| 348 |
# ---------------------- Gradio callbacks ----------------------
|
| 349 |
def analyze_news(mode, preset_company, topic, days, k, entity_filter, sentiment_filter, fast_mode):
|
| 350 |
+
# Build query hint from mode
|
| 351 |
query_hint = ONE_CLICK.get(mode, ONE_CLICK["General"])["query_hint"] if mode in ONE_CLICK else ""
|
| 352 |
|
| 353 |
+
# If a preset company is chosen and not already in the topic, append it
|
| 354 |
if preset_company and preset_company.lower() not in (topic or "").lower():
|
| 355 |
topic = f"{topic} {preset_company}".strip()
|
| 356 |
+
|
| 357 |
+
# Run pipeline (fast mode skips entities/keywords + parallelizes)
|
| 358 |
rows, df, mdf, rollup, briefing, press, jobs, ts = run_pipeline(
|
| 359 |
topic, days, k, query_hint=query_hint, fast=bool(fast_mode)
|
| 360 |
)
|
| 361 |
+
|
| 362 |
+
# Render cards with current filters
|
| 363 |
+
cards_html = render_cards(rows, entity_filter or None, sentiment_filter or None)
|
| 364 |
+
|
| 365 |
+
# Collect entities for the dropdown (limit to 50 unique)
|
| 366 |
+
all_ents = sorted(set(
|
| 367 |
+
e.strip()
|
| 368 |
+
for r in rows
|
| 369 |
+
for e in (r.get("Entities", "").split(", "))
|
| 370 |
+
if e.strip()
|
| 371 |
+
))[:50]
|
| 372 |
+
|
| 373 |
+
# Header bar text
|
| 374 |
+
header = f"ποΈ NewsIntel β Data last updated: {ts}"
|
| 375 |
+
|
| 376 |
+
# Return in same order your .click() expects
|
| 377 |
+
return (
|
| 378 |
+
header, # header_bar
|
| 379 |
+
cards_html, # cards
|
| 380 |
+
make_sentiment_chart(df), # plot_sent
|
| 381 |
+
make_trend_chart(df), # plot_trend
|
| 382 |
+
make_forecast_chart(df), # plot_forecast
|
| 383 |
+
df, # table
|
| 384 |
+
mdf if not mdf.empty else pd.DataFrame([{"note": "No per-article metrics yet"}]), # per_article
|
| 385 |
+
rollup, # rollup
|
| 386 |
+
briefing, # briefing_md
|
| 387 |
+
gr.update(choices=all_ents) # entity_filter (choices updated)
|
| 388 |
+
)
|
| 389 |
+
|
| 390 |
|
| 391 |
# wiring: include fast_mode in inputs
|
| 392 |
run_btn.click(
|
|
|
|
| 432 |
</div>
|
| 433 |
""")
|
| 434 |
|
| 435 |
+
# ---------- inputs ----------
|
| 436 |
with gr.Row():
|
| 437 |
mode = gr.Dropdown(choices=list(ONE_CLICK.keys()), value="General", label="One-Click Mode")
|
| 438 |
preset_company = gr.Dropdown(choices=H1B_TECH_PRESETS, label="Company Presets (H-1B Tech)", allow_custom_value=True)
|
| 439 |
+
topic = gr.Textbox(label="Topic / Company", value="", # <β was "NVIDIA"
|
|
|
|
| 440 |
placeholder="e.g., AMD, Healthcare AI, EV market India")
|
| 441 |
days = gr.Slider(1, 30, value=7, step=1, label="Lookback (days)")
|
| 442 |
+
k = gr.Slider(3, 12, value=4, step=1, label="Articles") # faster default
|
| 443 |
fast_mode = gr.Checkbox(value=True, label="β‘ Fast mode (skip Entities & Key Phrases)")
|
| 444 |
|
| 445 |
with gr.Row():
|
| 446 |
entity_filter = gr.Dropdown(choices=[], label="Filter by Mentioned Company/Person", value=None)
|
| 447 |
sentiment_filter = gr.Dropdown(choices=["ALL","POSITIVE","NEUTRAL","NEGATIVE","MIXED"], value="ALL", label="Sentiment filter")
|
| 448 |
|
| 449 |
+
# run button MUST be defined before we call run_btn.click(...)
|
| 450 |
run_btn = gr.Button("Run Analysis", variant="primary")
|
| 451 |
|
| 452 |
+
# ---------- outputs ----------
|
| 453 |
header_bar = gr.Markdown(value="ποΈ NewsIntel β Data last updated: β")
|
| 454 |
with gr.Tab("Insights"):
|
| 455 |
tip_md = gr.Markdown("π‘ **Tip:** *Entities* are detected names of companies/people/places (e.g., βTSMCβ, βARMβ). Use the filters to focus the feed.")
|
|
|
|
| 476 |
email_btn = gr.Button("Email Weekly Briefing (SES)")
|
| 477 |
email_status = gr.Markdown()
|
| 478 |
|
| 479 |
+
# ---------- helpers & wiring ----------
|
| 480 |
def _apply_mode(m, current_topic):
|
| 481 |
cfg = ONE_CLICK.get(m, ONE_CLICK["General"])
|
| 482 |
+
return gr.update(value=current_topic or cfg.get("topic",""))
|
|
|
|
|
|
|
| 483 |
|
| 484 |
mode.change(_apply_mode, inputs=[mode, topic], outputs=[topic])
|
|
|
|
| 485 |
preset_company.change(lambda x: x or "", inputs=preset_company, outputs=topic)
|
| 486 |
|
| 487 |
+
# include fast_mode in inputs
|
| 488 |
run_btn.click(
|
| 489 |
analyze_news,
|
| 490 |
+
inputs=[mode, preset_company, topic, days, k, entity_filter, sentiment_filter, fast_mode],
|
| 491 |
outputs=[header_bar, cards, plot_sent, plot_trend, plot_forecast, table, per_article, rollup, briefing_md, entity_filter]
|
| 492 |
).then(
|
| 493 |
lambda: datetime.datetime.now().strftime("%b %d, %Y %I:%M %p"),
|
|
|
|
| 497 |
export_btn.click(export_cb, inputs=[topic, briefing_md, timestamp_str], outputs=[export_html, export_pdf, s3_links])
|
| 498 |
email_btn.click(email_weekly_cb, inputs=[topic, weekly_email, briefing_md, timestamp_str], outputs=[email_status])
|
| 499 |
|
| 500 |
+
|
| 501 |
if __name__ == "__main__":
|
| 502 |
print("π Launching NewsIntel (light-only UI + caching + one-click modes + forecast)")
|
| 503 |
demo.launch()
|