charantejapolavarapu commited on
Commit
7b769b4
·
verified ·
1 Parent(s): 2e17ce9

Update src/streamlit_app.py

Browse files
Files changed (1) hide show
  1. src/streamlit_app.py +97 -536
src/streamlit_app.py CHANGED
@@ -1,551 +1,112 @@
1
  import streamlit as st
2
-
3
- # --- CRITICAL: set_page_config MUST BE THE FIRST STREAMLIT COMMAND ---
4
- st.set_page_config(
5
- page_title="భారత్ పల్స్ (BharatPulse) - వార్తలు",
6
- page_icon="📰",
7
- layout="wide",
8
- initial_sidebar_state="expanded"
9
- )
10
-
11
- # --- Remaining Imports (after set_page_config) ---
12
  import feedparser
13
  import requests
14
  from bs4 import BeautifulSoup
15
- from newspaper import Article # Make sure newspaper3k and lxml_html_clean are installed
16
  import time
17
  import json
18
  import datetime
 
 
19
 
20
- # --- Configuration ---
21
- TELUGU_CATEGORIES = {
22
- "ాతీయ వార్తలు": "National",
23
- "రాష్ట్ర వార్తలు": "State",
24
- "క్రైం": "Crime",
25
- "రాజకీయాలు": "Politics",
26
- "వ్యాపారం": "Business",
27
- "క్రీడలు": "Sports",
28
- "వినోదం": "Entertainment",
29
- "ఉద్యోగాలు": "Jobs",
30
- "వాతావరణం": "Weather",
31
- "వైరల్": "Viral",
32
- }
33
-
34
- # --- RSS Feed URLs (for general headlines) ---
35
- # IMPORTANT: These URLs might be outdated or not provide full content.
36
- # You might need to find current, active RSS feeds for Telugu news sources.
37
- RSS_FEEDS = {
38
- "Sakshi": "https://www.sakshi.com/tags/rss",
39
- "Eenadu": "https://www.eenadu.net/telugu-news/rss",
40
- }
41
-
42
- # --- OpenWeatherMap API Configuration (for Realtime Weather) ---
43
- OPENWEATHERMAP_API_KEY = "52f888dddede635f9b1d8a08141b5c49"
44
- OPENWEATHERMAP_API_URL = "http://api.openweathermap.org/data/2.5/weather"
45
-
46
- # --- NewsAPI.org Configuration (for Local News Search) ---
47
- NEWSAPI_API_KEY = "54035029265744dab172f28d58a93b56" # Your NewsAPI.org Key
48
- NEWSAPI_EVERYTHING_URL = "https://newsapi.org/v2/everything"
49
-
50
- # --- Dummy Translation Function (Translation is temporarily disabled) ---
51
- def translate_en_to_te(text):
52
- return text # Just return the original text
53
-
54
- # --- RSS Feed Fetching and Parsing (Cached for performance) ---
55
- @st.cache_data(ttl=3600) # Cache for 1 hour to reduce API calls to news sites
56
- def get_news_from_rss(url):
57
- try:
58
- feed = feedparser.parse(url)
59
- articles = []
60
- for entry in feed.entries:
61
- title = entry.title if hasattr(entry, 'title') else ""
62
- link = entry.link if hasattr(entry, 'link') else "#"
63
- summary = entry.summary if hasattr(entry, 'summary') and entry.summary.strip() else ""
64
- published = entry.published if hasattr(entry, 'published') else "N/A"
65
- image_url = None
66
-
67
- if hasattr(entry, 'media_content') and entry.media_content:
68
- for media in entry.media_content:
69
- if 'url' in media and media.get('type', '').startswith('image'):
70
- image_url = media['url']
71
- break
72
- elif hasattr(entry, 'description'):
73
- soup = BeautifulSoup(entry.description, 'html.parser')
74
- img_tag = soup.find('img')
75
- if img_tag and 'src' in img_tag.attrs:
76
- image_url = img_tag['src']
77
-
78
- if link and "http" in link and link != "#" and (not image_url or not summary):
79
- try:
80
- article_parser = Article(link)
81
- article_parser.download()
82
- article_parser.parse()
83
- if not image_url and article_parser.top_image:
84
- image_url = article_parser.top_image
85
- if not summary and article_parser.text:
86
- summary = article_parser.text[:200] + "..." if len(article_parser.text) > 200 else article_parser.text
87
-
88
- except Exception as e:
89
- pass
90
-
91
- if title.strip() and link.strip() != "#":
92
- articles.append({
93
- "title": title,
94
- "link": link,
95
- "summary": summary,
96
- "published": published,
97
- "image_url": image_url,
98
- "translated_title": None
99
- })
100
- return articles
101
- except Exception as e:
102
- st.error(f"Error fetching news from {url}: {e}")
103
- return []
104
-
105
- # --- NewsAPI.org Fetching for Local News (Cached for performance) ---
106
- @st.cache_data(ttl=600) # Cache for 10 minutes
107
- def get_news_from_newsapi(query, api_key, language='en', page_size=10):
108
- if not api_key:
109
- return None
110
-
111
- params = {
112
- 'q': query + " news", # Add " news" to the query for better results
113
- 'apiKey': api_key,
114
- 'language': language, # Can try 'te' but English coverage is better
115
- 'pageSize': page_size,
116
- 'sortBy': 'relevancy'
117
- }
118
- try:
119
- response = requests.get(NEWSAPI_EVERYTHING_URL, params=params)
120
- response.raise_for_status() # Raise an HTTPError for bad responses (4xx or 5xx)
121
- news_data = response.json()
122
-
123
- articles = []
124
- if news_data['status'] == 'ok' and news_data['articles']:
125
- for article in news_data['articles']:
126
- if article['title'] and article['url']: # Basic validation
127
- articles.append({
128
- "title": article.get('title', 'No Title'),
129
- "link": article.get('url', '#'),
130
- "summary": article.get('description', article.get('content', 'No description available.')),
131
- "published": article.get('publishedAt', 'N/A'),
132
- "image_url": article.get('urlToImage'),
133
- "source": article['source']['name'] if article.get('source') else 'Unknown Source',
134
- "translated_title": None # Placeholder
135
- })
136
- return articles
137
- except requests.exceptions.RequestException as e:
138
- st.error(f"Error fetching news from NewsAPI for '{query}': {e}. Check API key or network.")
139
- return None
140
- except json.JSONDecodeError:
141
- st.error(f"Error decoding NewsAPI response for '{query}'.")
142
- return None
143
- except Exception as e:
144
- st.error(f"An unexpected error occurred with NewsAPI for '{query}': {e}")
145
- return None
146
-
147
- # --- Voice Search (Placeholder - requires a separate library/API) ---
148
- def voice_search_widget():
149
- st.write("### 🎙️ వాయిస్ సెర్చ్ (Voice Search)")
150
- st.warning("Voice search integration with Whisper requires external setup (e.g., a local Whisper model, an API, or a custom Streamlit component). This is a placeholder.")
151
- audio_file = st.file_uploader("Upload an audio file (e.g., .wav, .mp3) for transcription:", type=["wav", "mp3"])
152
- if audio_file:
153
- st.audio(audio_file, format="audio/wav")
154
- st.info("Transcribing audio... (This is a mock transcription)")
155
- st.write("ట్రాన్స్క్రిప్షన్: ఇది వాయిస్ సెర్చ్ కోసం ఒక నకిలీ ట్రాన్స్క్రిప్షన్ (Transcription: This is a mock transcription for voice search)")
156
-
157
- # --- Hardcoded Location (Bypasses ipinfo.io issues) ---
158
- @st.cache_data(ttl=3600)
159
- def get_user_location():
160
- return "Hyderabad", "Telangana", "India"
161
-
162
- # --- Weather Integration ---
163
- @st.cache_data(ttl=600)
164
- def get_current_weather(city_name, api_key):
165
- if not api_key:
166
- return None
167
 
168
- params = {
169
- 'q': city_name,
170
- 'appid': api_key,
171
- 'units': 'metric',
172
- 'lang': 'te'
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
173
  }
174
- try:
175
- response = requests.get(OPENWEATHERMAP_API_URL, params=params)
176
- response.raise_for_status()
177
- weather_data = response.json()
178
-
179
- main_weather = weather_data['weather'][0]['description'] if weather_data.get('weather') else "N/A"
180
- temperature = weather_data['main']['temp']
181
- feels_like = weather_data['main']['feels_like']
182
- humidity = weather_data['main']['humidity']
183
- wind_speed = weather_data['wind']['speed']
184
-
185
- weather_info = {
186
- "description": main_weather.capitalize(),
187
- "temperature": temperature,
188
- "feels_like": feels_like,
189
- "humidity": humidity,
190
- "wind_speed": wind_speed
191
- }
192
- return weather_info
193
- except requests.exceptions.RequestException as e:
194
- st.error(f"Error fetching weather for {city_name}: {e}. This might be due to an invalid city name or network issues.")
195
- return None
196
- except json.JSONDecodeError:
197
- st.error(f"Error decoding weather data for {city_name}. Invalid response from API.")
198
- return None
199
- except KeyError as e:
200
- st.error(f"Missing key in weather data for {city_name}: {e}. API response might be incomplete or unexpected.")
201
- return None
202
-
203
- # --- Custom CSS for card-like appearance, horizontal scrolling (no background color) ---
204
- st.markdown("""
205
- <style>
206
- /* Streamlit Tabs Styling */
207
- .stTabs [data-baseweb="tab-list"] button {
208
- padding: 10px 15px;
209
- font-size: 16px;
210
- }
211
- .stTabs [data-baseweb="tab-list"] {
212
- gap: 15px;
213
- flex-wrap: nowrap;
214
- overflow-x: auto;
215
- -webkit-overflow-scrolling: touch;
216
- scrollbar-width: thin;
217
- scrollbar-color: #ccc #f1f1f1;
218
- }
219
- .stTabs [data-baseweb="tab-list"]::-webkit-scrollbar {
220
- height: 6px;
221
- }
222
- .stTabs [data-baseweb="tab-list"]::-webkit-scrollbar-thumb {
223
- background-color: #ccc;
224
- border-radius: 3px;
225
- }
226
- .stTabs [data-baseweb="tab-list"]::-webkit-scrollbar-track {
227
- background-color: #f1f1f1;
228
- }
229
-
230
- /* News Card Styling */
231
- .news-card {
232
- border: 1px solid #ddd;
233
- border-radius: 8px;
234
- padding: 15px;
235
- margin-bottom: 20px;
236
- box-shadow: 2px 2px 8px rgba(0,0,0,0.1);
237
- display: flex;
238
- flex-direction: column;
239
- height: 100%;
240
- background-color: #ffffff;
241
- }
242
- .news-card img {
243
- max-width: 100%;
244
- height: 200px;
245
- object-fit: cover;
246
- border-radius: 4px;
247
- margin-bottom: 10px;
248
- }
249
- .news-card h3 {
250
- font-size: 1.2em;
251
- margin-bottom: 5px;
252
- min-height: 2.4em;
253
- display: -webkit-box;
254
- -webkit-line-clamp: 2;
255
- -webkit-box-orient: vertical;
256
- overflow: hidden;
257
- text-overflow: ellipsis;
258
- }
259
- .news-card p {
260
- font-size: 0.9em;
261
- color: #555;
262
- flex-grow: 1;
263
- min-height: 4.5em;
264
- display: -webkit-box;
265
- -webkit-line-clamp: 3;
266
- -webkit-box-orient: vertical;
267
- overflow: hidden;
268
- text-overflow: ellipsis;
269
- }
270
- .news-card a {
271
- text-decoration: none;
272
- color: #007bff;
273
- font-weight: bold;
274
- margin-top: auto;
275
- }
276
- .news-card a:hover {
277
- text_decoration: underline;
278
- }
279
-
280
- /* For horizontal scrolling category buttons (using st.radio) */
281
- .stRadio > label {
282
- margin-right: 15px;
283
- padding: 8px 12px;
284
- border: 1px solid #007bff;
285
- border-radius: 20px;
286
- cursor: pointer;
287
- background-color: #f0f8ff;
288
- white-space: nowrap;
289
- }
290
- .stRadio > label:hover {
291
- background-color: #e0f0ff;
292
- }
293
- /* Style for the selected radio button */
294
- .stRadio [aria-checked="true"] > div:first-child {
295
- background-color: #007bff !important;
296
- color: white !important;
297
- border-color: #007bff !important;
298
- }
299
-
300
- /* Make the radio button container scrollable */
301
- div[data-testid="stRadio"] > div {
302
- flex-wrap: nowrap;
303
- overflow-x: auto;
304
- -webkit-overflow-scrolling: touch;
305
- scrollbar-width: thin;
306
- scrollbar-color: #ccc #f1f1f1;
307
- }
308
- div[data-testid="stRadio"] > div::-webkit-scrollbar {
309
- height: 6px;
310
- }
311
- div[data-testid="stRadio"] > div::-webkit-scrollbar-thumb {
312
- background-color: #ccc;
313
- border-radius: 3px;
314
- }
315
- div[data-testid="stRadio"] > div::-webkit-scrollbar-track {
316
- background-color: #f1f1f1;
317
- }
318
-
319
- </style>
320
- """, unsafe_allow_html=True)
321
-
322
-
323
- st.title("భారత్ పల్స్ (BharatPulse) 🇮🇳")
324
- st.markdown("మీ స్థానిక మరియు జాతీయ వార్తల వన్-స్టాప్ మూలం (Your one-stop source for local and national news)")
325
-
326
- # Add "User Profile" to the main tabs
327
- main_tabs = st.tabs(["📰 Headlines", "📍 My Location", "🔍 Search City", "🎙️ Voice Search", "👤 User Profile"])
328
-
329
- # Initialize session state variables for user profile details
330
- if 'user_name' not in st.session_state:
331
- st.session_state.user_name = ""
332
- if 'user_email' not in st.session_state:
333
  st.session_state.user_email = ""
334
- if 'user_location' not in st.session_state:
335
  st.session_state.user_location = ""
336
- if 'account_creation_date' not in st.session_state:
337
  st.session_state.account_creation_date = "N/A"
 
338
 
339
- # --- Tab 1: Headlines ---
340
- with main_tabs[0]:
341
- st.header("ప్రధాన వార్తలు (Headlines)")
342
-
343
- # Category selection for filtering
344
- st.markdown("##### వార్తల విభాగాలు (News Categories)")
345
- selected_category_tl = st.radio(
346
- "విభాగం ఎంచుకోండి (Select Category):",
347
- options=list(TELUGU_CATEGORIES.keys()),
348
- index=0,
349
- horizontal=True,
350
- key="headlines_category_select"
351
- )
352
- st.markdown(f"**ఎంచుకున్న విభాగం:** {selected_category_tl}")
353
-
354
- st.markdown("---")
355
-
356
- all_articles = []
357
- with st.spinner("వార్తలను లోడ్ చేస్తోంది... (Loading news...)"):
358
- for source_name, rss_url in RSS_FEEDS.items():
359
- st.markdown(f"**{source_name} నుండి వార్తలు**")
360
- articles = get_news_from_rss(rss_url)
361
-
362
- for article in articles:
363
- article['translated_title'] = article['title']
364
-
365
- all_articles.extend(articles)
366
-
367
- if not all_articles:
368
- st.warning("వార్తలు లోడ్ చేయబడలేదు. దయచేసి మీ RSS ఫీడ్ URLలను తనిఖి చేయండి లేదా ఇంటర్నెట్ కనెక్షన్\u200cని తనిఖి చేయండి. (No news loaded. Please check your RSS feed URLs or internet connection.)")
369
-
370
- if all_articles:
371
- num_cols = 3
372
- rows = []
373
- for i in range(0, len(all_articles), num_cols):
374
- rows.append(all_articles[i:i + num_cols])
375
-
376
- for row_articles in rows:
377
- cols = st.columns(num_cols)
378
- for i, article in enumerate(row_articles):
379
- with cols[i]:
380
- with st.container():
381
- st.markdown(f'<div class="news-card">', unsafe_allow_html=True)
382
- if article['image_url']:
383
- st.image(article['image_url'], use_column_width="always", caption="")
384
-
385
- st.markdown(f"### {article['title']}")
386
-
387
- st.markdown(f"<p>{article['summary']}</p>", unsafe_allow_html=True)
388
- st.markdown(f"[పూర్తిగా చదవండి (Read More)]({article['link']})", unsafe_allow_html=True)
389
- st.markdown('</div>', unsafe_allow_html=True)
390
-
391
-
392
- # --- Tab 2: My Location ---
393
- with main_tabs[1]:
394
- st.header("📍 నా స్థానం (My Location)")
395
-
396
- user_city, user_state, user_country = get_user_location()
397
- st.write(f"మీ ప్రస్తుత స్థానం: **{user_city}, {user_state}, {user_country}**")
398
-
399
- st.subheader("నిజ-సమయ వాతావరణం + హెచ్చరికలు (Real-time Weather + Alerts)")
400
-
401
- weather_data = get_current_weather(user_city, OPENWEATHERMAP_API_KEY)
402
- if weather_data:
403
- st.metric(label="ఉష్ణోగ్రత (Temperature)", value=f"{weather_data['temperature']:.1f}°C", delta=f"Feels like {weather_data['feels_like']:.1f}°C")
404
- st.write(f"**పరిస్థితి (Condition):** {weather_data['description']}")
405
- st.write(f"**తేమ (Humidity):** {weather_data['humidity']}%")
406
- st.write(f"**గాలి వేగం (Wind Speed):** {weather_data['wind_speed']:.1f} m/s")
407
- st.info(f"'{user_city}' కోసం ప్రస్తుత వాతావరణం. (Current weather for '{user_city}').")
408
- else:
409
- st.info(f"'{user_city}' కోసం వాతావరణ డేట�� అందుబాటులో లేదు. (Weather data not available for '{user_city}').")
410
-
411
- st.subheader("స్థానిక వార్తలు (Local News)")
412
- # Local news for "My Location" still uses the RSS feeds, or you'd need another API for this
413
- st.info(f"'{user_city}' కు సంబంధించిన స్థానిక వార్తలు ఇక్కడ ప్రదర్శించబడతాయి. (Local news for '{user_city}' will be displayed here.)")
414
-
415
- st.subheader("అలర్ట్స్ (Alerts)")
416
- st.info("స్థానిక హెచ్చరికలు ఇక్కడ ప్రదర్శించబడతాయి. (Local alerts will be displayed here.)")
417
-
418
-
419
- # --- Tab 3: Search City ---
420
- with main_tabs[2]:
421
- st.header("🔍 నగరాన్ని శోధించండి (Search City)")
422
-
423
- search_city = st.text_input("నగరం లేదా జిల్లా పేరును నమోదు చేయండి (Enter City or District Name):", "హైదరాబాద్", key="city_search_input")
424
-
425
- if st.button("వార్తలు శోధించండి (Search News)", key="search_city_button"):
426
- st.write(f"**'{search_city}'** కోసం వార్తలు లోడ్ అవుతున్నాయి... (Loading news for '{search_city}')...")
427
-
428
- st.subheader(f"వాతావరణం: {search_city} (Weather: {search_city})")
429
-
430
- weather_data_search = get_current_weather(search_city, OPENWEATHERMAP_API_KEY)
431
- if weather_data_search:
432
- st.metric(label="ఉష్ణోగ్రత (Temperature)", value=f"{weather_data_search['temperature']:.1f}°C", delta=f"Feels like {weather_data_search['feels_like']:.1f}°C")
433
- st.write(f"**పరిస్థితి (Condition):** {weather_data_search['description']}")
434
- st.write(f"**తేమ (Humidity):** {weather_data_search['humidity']}%")
435
- st.write(f"**గాలి వేగం (Wind Speed):** {weather_data_search['wind_speed']:.1f} m/s")
436
- else:
437
- st.info(f"'{search_city}' కోసం వాతావరణ డేటా అందుబాటులో లేదు. (Weather data not available for '{search_city}').")
438
-
439
- st.subheader(f"స్థానిక వార్తలు: {search_city} (Local News: {search_city})")
440
-
441
- # --- NEW: Fetch and display local news using NewsAPI.org ---
442
- local_news_articles = get_news_from_newsapi(search_city, NEWSAPI_API_KEY, language='en') # Use 'en' for broader coverage
443
-
444
- if local_news_articles:
445
- num_cols = 3
446
- rows = []
447
- for i in range(0, len(local_news_articles), num_cols):
448
- rows.append(local_news_articles[i:i + num_cols])
449
-
450
- for row_articles in rows:
451
- cols = st.columns(num_cols)
452
- for i, article in enumerate(row_articles):
453
- with cols[i]:
454
- with st.container():
455
- st.markdown(f'<div class="news-card">', unsafe_allow_html=True)
456
- if article['image_url']:
457
- st.image(article['image_url'], use_column_width="always", caption="")
458
-
459
- st.markdown(f"### {article['title']}")
460
- st.markdown(f"**Source:** {article.get('source', 'Unknown')} | **Published:** {article['published']}")
461
- st.markdown(f"<p>{article['summary']}</p>", unsafe_allow_html=True)
462
- st.markdown(f"[పూర్తిగా చదవండి (Read More)]({article['link']})", unsafe_allow_html=True)
463
- st.markdown('</div>', unsafe_allow_html=True)
464
- else:
465
- st.info(f"'{search_city}' కోసం స్థానిక వార్తలు అందుబాటులో లేవు. దయచేసి మరొక నగరాన్ని ప్రయత్నించండి లేదా మీ NewsAPI.org కీని తనిఖి చేయండి. (No local news available for '{search_city}'. Please try another city or check your NewsAPI.org key.)")
466
-
467
-
468
- # --- Tab 4: Voice Search ---
469
- with main_tabs[3]:
470
- voice_search_widget()
471
-
472
- # --- Tab 5: User Profile (New Tab) ---
473
- with main_tabs[4]:
474
- st.header("👤 యూజర్ ప్రొఫైల్ (User Profile)")
475
- st.markdown("మీ ప్రొఫైల్ వివరాలు మరియు యాప్ వినియోగ విశ్లేషణలు (Your profile details and app usage analytics)")
476
-
477
- # User Input for Personal Details
478
- st.subheader("వ్యక్తిగత వివరాలు (Personal Details)")
479
-
480
- st.session_state.user_name = st.text_input(
481
- "పేరు (Name):",
482
- value=st.session_state.user_name,
483
- placeholder="మీ పేరు నమోదు చేయండి (Enter your name)",
484
- key="profile_name"
485
- )
486
- st.session_state.user_email = st.text_input(
487
- "ఇమెయిల్ (Email):",
488
- value=st.session_state.user_email,
489
- placeholder="మీ ఇమెయిల్ నమోదు చేయండి (Enter your email)",
490
- key="profile_email"
491
- )
492
- st.session_state.user_location = st.text_input(
493
- "స్థానం (Location):",
494
- value=st.session_state.user_location,
495
- placeholder="మీ స్థానం నమోదు చేయండి (Enter your location)",
496
- key="profile_location"
497
- )
498
-
499
- if st.session_state.account_creation_date == "N/A" and st.session_state.user_name:
500
- st.session_state.account_creation_date = datetime.date.today().strftime("%B %d, %Y")
501
-
502
- st.write(f"**ఖాతా సృష్టించిన తేదీ (Account Created On):** {st.session_state.account_creation_date}")
503
-
504
- st.markdown("---")
505
-
506
- st.subheader("యాప్ వినియోగం (App Usage)")
507
-
508
- st.markdown("###### మీ వీక్షణలు (Your Views):")
509
- st.info("ఈ విభాగానికి వాస్తవ వినియోగదారు డేటా నిల్వ అవసరం. ఇవి ఉదాహరణ పాయింట్లు. (This section requires actual user data storage. These are example points.)")
510
-
511
- st.markdown("""
512
- <ul>
513
- <li><b>చూసిన వార్తల సంఖ్య (Articles Viewed):</b> 150+</li>
514
- <li><b>అత్యంత ఎక్కువగా చూసిన వర్గం (Most Viewed Category):</b> రాజకీయాలు (Politics)</li>
515
- <li><b>అత్యంత ఎక్కువగా చూసిన మూలం (Most Viewed Source):</b> సాక్షి (Sakshi)</li>
516
- <li><b>చివరిగా చూసిన వార్త (Last Viewed Article):</b> "హైదరాబాద్‌లో కొత్త వంతెన నిర్మాణం" (New Bridge Construction in Hyderabad)</li>
517
- <li><b>అనువాదాలను ఉపయోగించిన సంఖ్య (Translations Used):</b> 0 సార్లు (0 times)</li>
518
- </ul>
519
- """, unsafe_allow_html=True)
520
-
521
- st.markdown("---")
522
-
523
- st.subheader("ప్రాధాన్యతలు (Preferences)")
524
- st.write("వార్తల వర్గం ప్రాధాన్యతలు (Preferred News Categories):")
525
- preferred_categories = st.multiselect(
526
- "మీ ప్రాధాన్యత గల వర్గాలను ఎంచుకోండి (Select your preferred categories):",
527
- options=list(TELUGU_CATEGORIES.keys()),
528
- default=["జాతీయ వార్తలు", "రాష్ట్ర వార్తలు", "వ్యాపారం"]
529
- )
530
- st.write(f"మీరు ఎంచుకున్నవి: {', '.join(preferred_categories)}")
531
-
532
- st.write("వార్తా మూలాల ప్రాధాన్యతలు (Preferred News Sources):")
533
- preferred_sources = st.multiselect(
534
- "మీ ప్రాధాన్యత గల వార్తా మూలాలను ఎంచుకోండి (Select your preferred news sources):",
535
- options=list(RSS_FEEDS.keys()),
536
- default=["Sakshi"]
537
- )
538
- st.write(f"మీరు ఎంచుకున్నవి: {', '.join(preferred_sources)}")
539
-
540
- st.info("ఈ ప్రాధాన్యతలు భవిష్యత్తులో మీ వార్తల ఫీడ్‌ను వ్యక్తిగతీకరించడానికి ఉపయోగించబడతాయి. (These preferences will be used to personalize your news feed in the future.)")
541
-
542
- st.sidebar.title("భారత్ పల్స్ - సెట్టింగ్‌లు")
543
- st.sidebar.info("ఇక్కడ మీరు యాప్ సెట్టింగ్‌లను కాన్ఫిగర్ చేయవచ్చు. (Here you can configure app settings.)")
544
-
545
- if st.sidebar.button("రీఫ్రెష్ వార్తలు", key="refresh_news_button"):
546
- st.cache_data.clear() # Clear all data caches (news, location, weather)
547
- st.rerun() # Rerun the app to load fresh data
548
- st.sidebar.success("వార్తలు రీఫ్రెష్ చేయబడ్డాయి!")
549
 
550
- st.sidebar.markdown("---")
551
- st.sidebar.markdown("© 2025 భారత్ పల్స్")
 
1
  import streamlit as st
 
 
 
 
 
 
 
 
 
 
2
  import feedparser
3
  import requests
4
  from bs4 import BeautifulSoup
5
+ from newspaper import Article
6
  import time
7
  import json
8
  import datetime
9
+ import hashlib
10
+ import os
11
 
12
+ # --- Page Config ---
13
+ st.set_page_config(
14
+ page_title=" పల్స్ (BharatPulse) - వార్తలు",
15
+ page_icon="📰",
16
+ layout="wide",
17
+ initial_sidebar_state="expanded"
18
+ )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19
 
20
+ # --- User Auth Utilities ---
21
+ USERS_FILE = "users.json"
22
+
23
+ def hash_password(password):
24
+ return hashlib.sha256(password.encode()).hexdigest()
25
+
26
+ def load_users():
27
+ if os.path.exists(USERS_FILE):
28
+ with open(USERS_FILE, "r") as f:
29
+ return json.load(f)
30
+ return {}
31
+
32
+ def save_users(users):
33
+ with open(USERS_FILE, "w") as f:
34
+ json.dump(users, f, indent=2)
35
+
36
+ def login_user(username, password):
37
+ users = load_users()
38
+ if username in users and users[username]["password"] == hash_password(password):
39
+ return users[username]
40
+ return None
41
+
42
+ def register_user(username, email, password, location=""):
43
+ users = load_users()
44
+ if username in users:
45
+ return False, "User already exists"
46
+ users[username] = {
47
+ "email": email,
48
+ "password": hash_password(password),
49
+ "location": location,
50
+ "created": datetime.datetime.now().strftime("%Y-%m-%d")
51
  }
52
+ save_users(users)
53
+ return True, "Registration successful"
54
+
55
+ # --- Login/Register Page ---
56
+ if "logged_in" not in st.session_state:
57
+ st.session_state.logged_in = False
58
+ st.session_state.username = ""
59
+
60
+ def show_login_page():
61
+ st.title("🔐 లాగిన్ (Login)")
62
+ st.write("దయచేసి మీ ఖాతా వివరాలను నమోదు చేయండి.")
63
+
64
+ username = st.text_input("వినియోగదారు పేరు (Username)")
65
+ password = st.text_input("పాస్‌వర్డ్ (Password)", type="password")
66
+
67
+ if st.button("లాగిన్ చేయండి (Login)"):
68
+ user = login_user(username, password)
69
+ if user:
70
+ st.session_state.logged_in = True
71
+ st.session_state.username = username
72
+ st.session_state.user_email = user.get("email", "")
73
+ st.session_state.user_location = user.get("location", "")
74
+ st.session_state.account_creation_date = user.get("created", "N/A")
75
+ st.success("లాగిన్ విజయవంతమైంది!")
76
+ st.rerun()
77
+ else:
78
+ st.error("చెల్లని లాగిన్ వివరాలు. దయచేసి మళ్లీ ప్రయత్నించండి.")
79
+
80
+ st.info("మీకు ఖాతా లేనట్లయితే, దయచేసి క్రింద నమోదు చేసుకోండి.")
81
+
82
+ with st.expander("👉 ఖాతా రిజిస్ట్రేషన్ (Register New Account)"):
83
+ new_username = st.text_input("కొత్త వినియ��గదారు పేరు", key="register_username")
84
+ new_email = st.text_input("ఇమెయిల్", key="register_email")
85
+ new_password = st.text_input("పాస్‌వర్డ్", type="password", key="register_password")
86
+ new_location = st.text_input("స్థానం (ఐచ్ఛికం)", key="register_location")
87
+ if st.button("రిజిస్టర్ (Register)"):
88
+ success, message = register_user(new_username, new_email, new_password, new_location)
89
+ if success:
90
+ st.success(message + " ఇప్పుడు లాగిన్ చేయండి.")
91
+ else:
92
+ st.error(message)
93
+
94
+ # If not logged in, show login page and stop app
95
+ if not st.session_state.logged_in:
96
+ show_login_page()
97
+ st.stop()
98
+
99
+ # --- LOGOUT Button ---
100
+ st.sidebar.title("భారత్ పల్స్ - సెట్టింగ్‌లు")
101
+ if st.sidebar.button("లాగ్ అవుట్ (Logout)"):
102
+ st.session_state.logged_in = False
103
+ st.session_state.username = ""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
104
  st.session_state.user_email = ""
 
105
  st.session_state.user_location = ""
 
106
  st.session_state.account_creation_date = "N/A"
107
+ st.rerun()
108
 
109
+ # Continue with full BharatPulse app...
110
+ # (Insert your BharatPulse main app code here – you already provided it)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
111
 
112
+ # ✅ Tip: Use st.session_state.username, user_email, etc., in Profile tab