EveryCricket / app.py
AK97GAMERZ's picture
Create app.py
05158d6 verified
import streamlit as st
import requests
import pandas as pd
import json # To pretty-print JSON for debugging
# --- Configuration ---
st.set_page_config(page_title="Info Hub by Anand", layout="wide")
# App Title
st.title("🌐 Info Hub by Anand")
st.caption("Bing News Search & Twitter Trends")
# --- API Setup ---
# Fetch API Keys from Hugging Face secrets
try:
# IMPORTANT: Use distinct names for your secrets
BING_API_KEY = st.secrets["RAPIDAPI_KEY_BING"]
TWITTER_API_KEY = st.secrets["RAPIDAPI_KEY_TWITTER"]
except KeyError as e:
st.error(f"πŸ”΄ Error: Missing API Key in Hugging Face secrets: {e}. Please add RAPIDAPI_KEY_BING and RAPIDAPI_KEY_TWITTER.")
st.stop()
# --- API Constants ---
BING_API_HOST = "bing-news-search1.p.rapidapi.com"
BING_BASE_URL = f"https://{BING_API_HOST}"
TWITTER_API_HOST = "twitter241.p.rapidapi.com"
TWITTER_BASE_URL = f"https://{TWITTER_API_HOST}"
# --- Helper Function to Fetch API Data ---
# Cache data to avoid hitting API limits too quickly on reruns
# TTL (time-to-live) set to 300 seconds (5 minutes)
@st.cache_data(ttl=300)
def fetch_api_data(url, headers, params=None):
"""Fetches data from a RapidAPI endpoint."""
try:
response = requests.get(url, headers=headers, params=params, timeout=15)
response.raise_for_status() # Raises HTTPError for bad responses (4XX, 5XX)
return response.json()
except requests.exceptions.Timeout:
st.error(f"🚨 API Error: Request timed out accessing {url}")
return None
except requests.exceptions.HTTPError as e:
# Try to get more info from response if possible
error_detail = ""
try:
error_detail = e.response.json()
except json.JSONDecodeError:
error_detail = e.response.text
st.error(f"🚨 API HTTP Error fetching {url}: {e}. Response: {error_detail}")
return None
except requests.exceptions.RequestException as e:
st.error(f"🚨 API Connection Error fetching {url}: {e}")
return None
except json.JSONDecodeError:
st.error(f"🚨 API Error: Could not decode JSON response from {url}")
# st.text(response.text) # Uncomment to see raw response text if needed
return None
except Exception as e:
st.error(f"🚨 An unexpected error occurred: {e}")
return None
# --- UI Sections ---
tab1, tab2 = st.tabs(["πŸ“° Bing News Search", "πŸ“ˆ Twitter Trends"])
# --- Bing News Tab ---
with tab1:
st.header("Search Bing News")
# Input for search query
search_query = st.text_input("Enter search term (e.g., 'cricket world cup', 'AI technology'):", key="bing_query")
col1, col2 = st.columns([1, 3])
with col1:
freshness = st.selectbox("Freshness:", ["Day", "Week", "Month"], index=0, key="bing_freshness")
with col2:
safe_search = st.selectbox("Safe Search:", ["Off", "Moderate", "Strict"], index=0, key="bing_safe")
if st.button("Search News", key="bing_search_button"):
if not search_query:
st.warning("Please enter a search term.")
else:
st.write(f"Searching for '{search_query}'...")
bing_headers = {
"X-BingApis-SDK": "true", # As seen in your cURL example
"X-RapidAPI-Key": BING_API_KEY,
"X-RapidAPI-Host": BING_API_HOST
}
bing_params = {
"q": search_query,
"freshness": freshness,
"textFormat": "Raw",
"safeSearch": safe_search,
"mkt": "en-US" # Market - adjust if needed
}
endpoint = "/news/search"
news_data = fetch_api_data(f"{BING_BASE_URL}{endpoint}", headers=bing_headers, params=bing_params)
if news_data:
# --- Display Results (Adapt based on actual API response structure) ---
st.success("News Results:")
# COMMON BING NEWS STRUCTURE: results are often in a 'value' list
articles = news_data.get("value", [])
if not articles:
st.info("No news articles found for this query.")
# st.json(news_data) # Uncomment to debug the response structure
for i, item in enumerate(articles):
title = item.get("name", "No Title")
description = item.get("description", "No Description")
url = item.get("url", "#")
provider_list = item.get("provider", [{}])
provider_name = provider_list[0].get("name", "Unknown Source") if provider_list else "Unknown Source"
date_published = item.get("datePublished", "N/A")
# Format date nicely if possible
try:
date_published_dt = pd.to_datetime(date_published)
date_published_str = date_published_dt.strftime('%Y-%m-%d %H:%M')
except:
date_published_str = date_published # Keep original if parsing fails
st.subheader(f"{i+1}. {title}")
st.caption(f"Source: {provider_name} | Published: {date_published_str}")
st.write(description)
st.markdown(f"[Read More]({url})", unsafe_allow_html=True)
st.divider()
# Option to show raw JSON for debugging
# with st.expander("Show Raw API Response (Debug)"):
# st.json(news_data)
else:
st.error("Failed to retrieve news data from the API.")
# --- Twitter Trends Tab ---
with tab2:
st.header("Get Twitter Trends by Location")
# Input for WOEID
# You can find WOEIDs here: http://www.woeidlookup.com/ (or other online sources)
# Example: 1 = Global, 23424848 = India, 23424977 = United States, 23424975 = United Kingdom
woeid = st.text_input("Enter WOEID (Where On Earth ID):", value="23424848", key="twitter_woeid", help="e.g., 1 (Global), 23424848 (India), 23424977 (USA)")
if st.button("Fetch Trends", key="twitter_fetch_button"):
if not woeid or not woeid.isdigit():
st.warning("Please enter a valid numeric WOEID.")
else:
st.write(f"Fetching trends for WOEID: {woeid}...")
twitter_headers = {
"X-RapidAPI-Key": TWITTER_API_KEY,
"X-RapidAPI-Host": TWITTER_API_HOST
}
# Note: The specific endpoint name might vary. Check RapidAPI docs.
# '/trends-by-location' was in your example
endpoint = "/trends-by-location"
twitter_params = {"woeid": woeid}
trends_data = fetch_api_data(f"{TWITTER_BASE_URL}{endpoint}", headers=twitter_headers, params=twitter_params)
if trends_data:
# --- Display Results (Adapt based on actual API response structure) ---
st.success("Trending Topics:")
# COMMON TWITTER TRENDS STRUCTURE: Often a list, potentially nested under a key.
# Check API docs: Is it trends_data[0]['trends']? Or just trends_data['trends']? Or just trends_data?
# Assuming structure: [{"trends": [ { "name": "...", "url": "...", "tweet_volume": ... } ]}]
# Or maybe: {"results": [ { "name": "...", "url": "...", "tweet_volume": ... } ]}
# Let's try a few common possibilities:
trends_list = []
if isinstance(trends_data, list) and len(trends_data) > 0 and "trends" in trends_data[0]:
trends_list = trends_data[0].get("trends", [])
elif isinstance(trends_data, dict) and "trends" in trends_data:
trends_list = trends_data.get("trends", [])
elif isinstance(trends_data, dict) and "results" in trends_data:
trends_list = trends_data.get("results", [])
elif isinstance(trends_data, list): # Maybe the list itself contains trend objects
trends_list = trends_data
if not trends_list:
st.info("No trends found or could not parse the response structure.")
st.json(trends_data) # Show raw response for debugging
else:
# Prepare data for table/list display
display_data = []
for trend in trends_list:
# Check if 'trend' is actually a dictionary
if isinstance(trend, dict):
name = trend.get("name", "N/A")
url = trend.get("url", "#")
volume = trend.get("tweet_volume", None) # May be None or not present
display_data.append({
"Trend": name,
"Tweet Volume": f"{volume:,}" if volume else "N/A", # Format volume nicely
"Link": url
})
else:
st.warning(f"Unexpected item in trends list: {trend}")
if display_data:
df_trends = pd.DataFrame(display_data)
st.dataframe(df_trends, hide_index=True, use_container_width=True,
column_config={"Link": st.column_config.LinkColumn("Link", display_text="Go to Twitter")})
else:
st.info("Formatted trend data is empty.")
# Option to show raw JSON for debugging
# with st.expander("Show Raw API Response (Debug)"):
# st.json(trends_data)
else:
st.error("Failed to retrieve trends data from the API.")
# --- Footer ---
st.markdown("---")
st.caption("Info Hub by Anand | Data powered by RapidAPI (Bing News, Twitter)")