Dmitry Beresnev
commited on
Commit
Β·
92860fb
1
Parent(s):
e918eaf
fix breaking news banner
Browse files- app/components/news.py +5 -4
- app/pages/05_Dashboard.py +26 -10
app/components/news.py
CHANGED
|
@@ -353,10 +353,11 @@ def display_category_breakdown(stats: dict):
|
|
| 353 |
def display_breaking_news_banner(df: pd.DataFrame):
|
| 354 |
"""Display breaking news banner at the top with TradingView styling and ML-based impact score."""
|
| 355 |
|
| 356 |
-
|
| 357 |
-
|
| 358 |
-
|
| 359 |
-
|
|
|
|
| 360 |
|
| 361 |
# Escape HTML
|
| 362 |
summary = html_module.escape(latest.get('summary', '').strip())
|
|
|
|
| 353 |
def display_breaking_news_banner(df: pd.DataFrame):
|
| 354 |
"""Display breaking news banner at the top with TradingView styling and ML-based impact score."""
|
| 355 |
|
| 356 |
+
# With ML-based scoring, we trust that the passed DataFrame already contains
|
| 357 |
+
# the highest-impact news, so no need to filter by is_breaking
|
| 358 |
+
# (The scorer already selected the most impactful news)
|
| 359 |
+
if not df.empty:
|
| 360 |
+
latest = df.iloc[0]
|
| 361 |
|
| 362 |
# Escape HTML
|
| 363 |
summary = html_module.escape(latest.get('summary', '').strip())
|
app/pages/05_Dashboard.py
CHANGED
|
@@ -311,6 +311,9 @@ with st.spinner("π Fetching latest financial & tech news in parallel..."):
|
|
| 311 |
'ai_tech': future_ai_tech
|
| 312 |
}
|
| 313 |
|
|
|
|
|
|
|
|
|
|
| 314 |
for source_name, future in futures.items():
|
| 315 |
try:
|
| 316 |
result_df, error = future.result(timeout=90) # 90 second timeout per source
|
|
@@ -318,25 +321,25 @@ with st.spinner("π Fetching latest financial & tech news in parallel..."):
|
|
| 318 |
if source_name == 'twitter':
|
| 319 |
twitter_df = result_df
|
| 320 |
if error:
|
| 321 |
-
|
| 322 |
elif source_name == 'reddit':
|
| 323 |
reddit_df = result_df
|
| 324 |
if error:
|
| 325 |
-
|
| 326 |
elif source_name == 'rss':
|
| 327 |
rss_all_df = result_df
|
| 328 |
if error:
|
| 329 |
-
|
| 330 |
-
elif source_name == 'ai_tech':
|
| 331 |
-
ai_tech_df = result_df
|
| 332 |
-
if error:
|
| 333 |
-
st.warning(error)
|
| 334 |
# Get main page news subset for RSS
|
| 335 |
if not rss_all_df.empty and 'from_web' in rss_all_df.columns:
|
| 336 |
rss_main_df = rss_all_df[rss_all_df['from_web'] == True].copy()
|
|
|
|
|
|
|
|
|
|
|
|
|
| 337 |
|
| 338 |
except Exception as e:
|
| 339 |
-
|
| 340 |
|
| 341 |
# Clear force refresh flag after fetching is complete
|
| 342 |
if force_refresh:
|
|
@@ -379,8 +382,15 @@ if not all_news_df.empty:
|
|
| 379 |
breaking_df = pd.DataFrame([breaking_news_items[0]])
|
| 380 |
display_breaking_news_banner(breaking_df)
|
| 381 |
else:
|
| 382 |
-
# If no high-impact news found, show informational message
|
| 383 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 384 |
|
| 385 |
st.markdown("---")
|
| 386 |
|
|
@@ -520,6 +530,12 @@ with col4:
|
|
| 520 |
</style>
|
| 521 |
""", unsafe_allow_html=True)
|
| 522 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 523 |
# Auto-refresh logic
|
| 524 |
if auto_refresh:
|
| 525 |
import time
|
|
|
|
| 311 |
'ai_tech': future_ai_tech
|
| 312 |
}
|
| 313 |
|
| 314 |
+
# Track errors to display later (avoid cluttering top of page)
|
| 315 |
+
fetch_errors = []
|
| 316 |
+
|
| 317 |
for source_name, future in futures.items():
|
| 318 |
try:
|
| 319 |
result_df, error = future.result(timeout=90) # 90 second timeout per source
|
|
|
|
| 321 |
if source_name == 'twitter':
|
| 322 |
twitter_df = result_df
|
| 323 |
if error:
|
| 324 |
+
fetch_errors.append(error)
|
| 325 |
elif source_name == 'reddit':
|
| 326 |
reddit_df = result_df
|
| 327 |
if error:
|
| 328 |
+
fetch_errors.append(error)
|
| 329 |
elif source_name == 'rss':
|
| 330 |
rss_all_df = result_df
|
| 331 |
if error:
|
| 332 |
+
fetch_errors.append(error)
|
|
|
|
|
|
|
|
|
|
|
|
|
| 333 |
# Get main page news subset for RSS
|
| 334 |
if not rss_all_df.empty and 'from_web' in rss_all_df.columns:
|
| 335 |
rss_main_df = rss_all_df[rss_all_df['from_web'] == True].copy()
|
| 336 |
+
elif source_name == 'ai_tech':
|
| 337 |
+
ai_tech_df = result_df
|
| 338 |
+
if error:
|
| 339 |
+
fetch_errors.append(error)
|
| 340 |
|
| 341 |
except Exception as e:
|
| 342 |
+
fetch_errors.append(f"Error fetching {source_name} news: {e}")
|
| 343 |
|
| 344 |
# Clear force refresh flag after fetching is complete
|
| 345 |
if force_refresh:
|
|
|
|
| 382 |
breaking_df = pd.DataFrame([breaking_news_items[0]])
|
| 383 |
display_breaking_news_banner(breaking_df)
|
| 384 |
else:
|
| 385 |
+
# If no high-impact news found, show informational message with score
|
| 386 |
+
if breaking_news_items:
|
| 387 |
+
top_score = breaking_news_items[0]['breaking_score']
|
| 388 |
+
st.info(f"π Monitoring financial markets - highest impact score: {top_score:.1f}/100 (threshold: 40)")
|
| 389 |
+
else:
|
| 390 |
+
st.info("π Monitoring financial markets - no news items available for scoring")
|
| 391 |
+
else:
|
| 392 |
+
# No news data available at all
|
| 393 |
+
st.info("π Loading financial news - breaking news banner will appear when data is available")
|
| 394 |
|
| 395 |
st.markdown("---")
|
| 396 |
|
|
|
|
| 530 |
</style>
|
| 531 |
""", unsafe_allow_html=True)
|
| 532 |
|
| 533 |
+
# Display fetch errors in expander (less intrusive)
|
| 534 |
+
if 'fetch_errors' in locals() and fetch_errors:
|
| 535 |
+
with st.expander("β οΈ Source Fetch Warnings", expanded=False):
|
| 536 |
+
for error in fetch_errors:
|
| 537 |
+
st.caption(f"β’ {error}")
|
| 538 |
+
|
| 539 |
# Auto-refresh logic
|
| 540 |
if auto_refresh:
|
| 541 |
import time
|