File size: 10,080 Bytes
05158d6 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 |
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)") |