Spaces:
Sleeping
Sleeping
File size: 14,116 Bytes
9808943 910cc1c 7b769b4 d263152 e5fd7cb 910cc1c d2aa4a3 d263152 7b769b4 d2aa4a3 e5fd7cb 7b769b4 d2aa4a3 e5fd7cb 7b769b4 d2aa4a3 2cd985f e5fd7cb 2cd985f e5fd7cb 7b769b4 d263152 d2aa4a3 7b769b4 d263152 d2aa4a3 d263152 7b769b4 d2aa4a3 d263152 910cc1c e5fd7cb d2aa4a3 7b769b4 d263152 d2aa4a3 d263152 4703f39 d263152 4703f39 d263152 d2aa4a3 d263152 d2aa4a3 d263152 d2aa4a3 d263152 d2aa4a3 d263152 d2aa4a3 d263152 d2aa4a3 d263152 d2aa4a3 d263152 d2aa4a3 d263152 d2aa4a3 d263152 eadcbe8 d2aa4a3 7b769b4 d2aa4a3 d263152 7b769b4 d263152 d2aa4a3 d263152 d2aa4a3 d263152 4703f39 d263152 d2aa4a3 d263152 d2aa4a3 7b769b4 d2aa4a3 d263152 d2aa4a3 d263152 7b769b4 d263152 d2aa4a3 910cc1c d2aa4a3 d263152 d2aa4a3 d263152 d2aa4a3 d263152 eadcbe8 d2aa4a3 d263152 d2aa4a3 d263152 d2aa4a3 d263152 d2aa4a3 d263152 d2aa4a3 d263152 d2aa4a3 eadcbe8 | 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 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 | import streamlit as st
import feedparser
import requests
import json
import os
from bs4 import BeautifulSoup
from transformers import MarianMTModel, MarianTokenizer
# Configure the Streamlit page
st.set_page_config(page_title="📍 BharatPulse - Local News & Sentiment", layout="wide")
# --- User Authentication Functions ---
# IMPORTANT: For production, this 'users.json' file will not persist across deployments
# on cloud platforms like Streamlit Community Cloud. For persistent user data,
# a proper database (e.g., Firebase Firestore, PostgreSQL) is REQUIRED.
# If you are seeing PermissionError even with /tmp, your environment does not allow file writes.
USERS_FILE = "/tmp/users.json" # Attempt to use /tmp for write permissions
def load_users():
"""Loads user data from the JSON file."""
users_data = {}
if os.path.exists(USERS_FILE):
try:
with open(USERS_FILE, "r") as f:
users_data = json.load(f)
except json.JSONDecodeError:
st.error("Error: users.json file is corrupted. Starting with an empty user database.")
except PermissionError:
st.error("Permission Error: Cannot read users.json. Your environment might restrict file access. For persistent user data, a database is required.")
except Exception as e:
st.error(f"An unexpected error occurred while loading users: {e}. For persistent user data, a database is required.")
return users_data
def save_users(users):
"""Saves user data to the JSON file."""
try:
with open(USERS_FILE, "w") as f:
json.dump(users, f, indent=2)
except PermissionError:
st.error("Permission Error: Cannot write to users.json. Your environment might restrict file access. For persistent user data, a database is required.")
except Exception as e:
st.error(f"An unexpected error occurred while saving users: {e}. For persistent user data, a database is required.")
def register_user(username, email, password, location):
"""Registers a new user."""
users = load_users()
if email in users:
return False, "User already exists with this email."
users[email] = {
"username": username,
"email": email,
"password": password, # In a real app, hash passwords!
"location": location
}
save_users(users) # Attempt to save
# The success of saving will be indicated by the absence of an error from save_users
return True, "Registration successful. You can now log in."
def login_user(email, password):
"""Logs in an existing user."""
users = load_users()
user = users.get(email)
if user and user["password"] == password: # In a real app, compare hashed hashed passwords!
return True, user
return False, "Invalid email or password. If you don't have an account, please go to the 'Register' tab to create one."
# --- MarianMT Model for Translation ---
@st.cache_resource # Caches the model to avoid reloading on rerun
def load_translation_model():
"""Loads the MarianMT English-Telugu translation model."""
st.info("Loading translation model (this may take a moment)...")
model_name = "Helsinki-NLP/opus-mt-en-te"
tokenizer = MarianTokenizer.from_pretrained(model_name)
model = MarianMTModel.from_pretrained(model_name)
st.success("Translation model loaded!")
return tokenizer, model
def translate_to_telugu(text):
"""Translates English text to Telugu."""
try:
tokenizer, model = load_translation_model()
# Prepare input for the model, ensuring truncation for long texts
tokens = tokenizer.prepare_seq2seq_batch([text], return_tensors="pt", truncation=True, max_length=512)
translated = model.generate(**tokens)
return tokenizer.decode(translated[0], skip_special_tokens=True)
except Exception as e:
st.error(f"Error during translation: {e}")
return "Translation failed."
# --- Article Content Extraction ---
def extract_article_content(url):
"""Extracts the first few paragraphs from an article URL."""
try:
# Add headers to mimic a browser, as some sites block direct requests
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'
}
response = requests.get(url, timeout=10, headers=headers) # Increased timeout
response.raise_for_status() # Raise an HTTPError for bad responses (4xx or 5xx)
soup = BeautifulSoup(response.text, "html.parser")
paragraphs = soup.find_all('p')
# Join the text of the first 5 paragraphs, or fewer if not available
content = ' '.join([p.get_text() for p in paragraphs[:5]])
if not content: # If no paragraphs found, try to get text from body
content = soup.body.get_text(separator=' ', strip=True)[:1000] # Get first 1000 chars
return content if content else "Could not extract article content."
except requests.exceptions.RequestException as e:
return f"Network or HTTP error: {e}"
except Exception as e:
return f"Error extracting content: {e}"
# --- Weather Functionality ---
# IMPORTANT: Replace 'YOUR_OPENWEATHER_API_KEY' with your actual OpenWeatherMap API key.
# You can get one from https://openweathermap.org/api
# For production, store this securely (e.g., Streamlit secrets or environment variables).
OPENWEATHER_API_KEY = "YOUR_OPENWEATHER_API_KEY"
WEATHER_API_URL = "http://api.openweathermap.org/data/2.5/weather"
def get_weather_data(city):
"""Fetches weather data for a given city from OpenWeatherMap."""
if OPENWEATHER_API_KEY == "YOUR_OPENWEATHER_API_KEY":
st.warning("Please replace 'YOUR_OPENWEATHER_API_KEY' with your actual OpenWeatherMap API key to fetch weather data.")
return None
params = {
"q": city,
"appid": OPENWEATHER_API_KEY,
"units": "metric" # Get temperature in Celsius
}
try:
response = requests.get(WEATHER_API_URL, params=params, timeout=10)
response.raise_for_status() # Raise an HTTPError for bad responses (4xx or 5xx)
data = response.json()
return data
except requests.exceptions.RequestException as e:
st.error(f"Error fetching weather data for {city}: {e}. Please check the city name or your internet connection.")
return None
except json.JSONDecodeError:
st.error(f"Error decoding weather data for {city}. Unexpected response from API.")
return None
except Exception as e:
st.error(f"An unexpected error occurred while fetching weather data: {e}")
return None
# --- Authentication UI ---
# Initialize session state for login status
if "logged_in" not in st.session_state:
st.session_state.logged_in = False
if "user" not in st.session_state:
st.session_state.user = None
if not st.session_state.logged_in:
st.title("🔐 Login to BharatPulse")
tab1, tab2 = st.tabs(["🔑 Login", "📝 Register"])
with tab1:
st.subheader("Existing User Login")
email = st.text_input("Email", key="login_email")
password = st.text_input("Password", type="password", key="login_password")
if st.button("Login", key="login_button"):
success, user_or_msg = login_user(email, password)
if success:
st.session_state.logged_in = True
st.session_state.user = user_or_msg
st.success(f"Welcome, {st.session_state.user['username']}!")
st.rerun() # Rerun to switch to the main app view
else:
st.error(user_or_msg) # This error message now includes the suggestion to register
with tab2:
st.subheader("New User Registration")
new_username = st.text_input("Username", key="register_username")
new_email = st.text_input("New Email", key="register_email")
new_password = st.text_input("New Password", type="password", key="register_password")
new_location = st.text_input("Location (e.g., Hyderabad)", key="register_location")
if st.button("Register", key="register_button"):
if new_username and new_email and new_password and new_location:
success, message = register_user(new_username, new_email, new_password, new_location)
if success:
st.success(message)
else:
st.error(message)
else:
st.warning("Please fill in all registration fields.")
st.stop() # Stop execution if not logged in
# --- Main News UI (only runs if logged in) ---
st.sidebar.header("User Info")
st.sidebar.success(f"Logged in as: {st.session_state.user['username']}")
st.sidebar.info(f"Your registered location: {st.session_state.user['location']}")
if st.sidebar.button("🚪 Logout"):
st.session_state.logged_in = False
st.session_state.user = None
st.rerun() # Rerun to go back to login screen
st.title("📍 BharatPulse - Local News & Sentiment")
# Define RSS feeds
# You can expand this dictionary with more RSS feeds for different regions/newspapers
feeds = {
"Sakshi - Medak": "https://www.sakshi.com/rss/district-news/medak.xml",
"Eenadu - AP": "https://www.eenadu.net/rss/andhra-pradesh.xml",
# Add more feeds here, e.g., "Eenadu - Telangana": "https://www.eenadu.net/rss/telangana.xml"
}
# Added "☁️ Weather" tab
tabs = st.tabs(["📰 Headlines", "🔍 Search by City", "☁️ Weather"])
# --- 📰 Headlines Tab ---
with tabs[0]:
st.header("📰 Latest Local Telugu News Headlines")
for name, url in feeds.items():
st.subheader(name)
try:
feed = feedparser.parse(url)
if not feed.entries:
st.info(f"No entries found for {name}.")
continue
for entry in feed.entries[:3]: # Display top 3 articles per feed
st.markdown(f"### [{entry.title}]({entry.link})") # Make title a clickable link
st.write(f"Published: {entry.published}")
# Extract and summarize article content
summary = extract_article_content(entry.link)
st.markdown(f"**English Summary:** {summary}")
# Translate summary to Telugu
telugu_summary = translate_to_telugu(summary)
st.markdown(f"**తెలుగు అనువాదం:** {telugu_summary}")
st.markdown("---")
except Exception as e:
st.error(f"Could not fetch news from {name}: {e}")
# --- 🔍 Search by City Tab ---
with tabs[1]:
st.header("🔎 Search News by City / District")
# Pre-fill with user's registered location if available
default_city = st.session_state.user['location'] if st.session_state.user else ""
city_search_input = st.text_input("Enter your city/district name (e.g., Medak, Hyderabad)", value=default_city)
if city_search_input:
st.success(f"Searching news for: **{city_search_input}**")
found_news = False
for name, url in feeds.items():
# Basic matching: checks if the city name is in the feed's name (case-insensitive)
if city_search_input.lower() in name.lower():
st.subheader(f"News from {name}")
try:
feed = feedparser.parse(url)
if not feed.entries:
st.info(f"No entries found for {name} matching '{city_search_input}'.")
continue
for entry in feed.entries[:2]: # Display top 2 articles per matching feed
st.markdown(f"**🗞️ [{entry.title}]({entry.link})**")
summary = extract_article_content(entry.link)
telugu_summary = translate_to_telugu(summary)
st.markdown(f"**తెలుగు అనువాదం:** {telugu_summary}")
st.markdown("---")
found_news = True
except Exception as e:
st.error(f"Could not fetch news from {name}: {e}")
if not found_news:
st.info(f"No news found for '{city_search_input}' in the available feeds. Try a different city or check our 'Headlines' tab.")
# --- ☁️ Weather Tab ---
with tabs[2]:
st.header("☁️ Weather Conditions")
# Pre-fill with user's registered location if available
default_weather_city = st.session_state.user['location'] if st.session_state.user else ""
weather_city_input = st.text_input("Enter city name for weather (e.g., Hyderabad, Delhi)", value=default_weather_city, key="weather_city_input")
if st.button("Get Weather", key="get_weather_button"):
if weather_city_input:
with st.spinner(f"Fetching weather for {weather_city_input}..."):
weather_data = get_weather_data(weather_city_input)
if weather_data:
st.subheader(f"Current Weather in {weather_data['name']}, {weather_data['sys']['country']}")
col1, col2, col3 = st.columns(3)
with col1:
st.metric("Temperature", f"{weather_data['main']['temp']:.1f}°C")
with col2:
st.metric("Feels Like", f"{weather_data['main']['feels_like']:.1f}°C")
with col3:
st.metric("Humidity", f"{weather_data['main']['humidity']}%")
st.write(f"**Description:** {weather_data['weather'][0]['description'].capitalize()}")
st.write(f"**Wind Speed:** {weather_data['wind']['speed']} m/s")
st.write(f"**Pressure:** {weather_data['main']['pressure']} hPa")
else:
st.info("Could not retrieve weather data. Please check the city name or your API key.")
else:
st.warning("Please enter a city name to get weather information.")
|