bharat_pulse / src /streamlit_app.py
charantejapolavarapu's picture
Update src/streamlit_app.py
eadcbe8 verified
Raw
History Blame Contribute Delete
14.1 kB
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.")