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)")