import streamlit as st import requests from bs4 import BeautifulSoup from transformers import pipeline from transformers import AutoTokenizer, AutoModelForSequenceClassification import time # ----------- Page Layout & Custom Styling ----------- st.set_page_config(page_title="Stock News Sentiment Analysis", layout="centered") st.markdown(""" """, unsafe_allow_html=True) # ----------- Model Setup ----------- model_id = "LinkLinkWu/Boss_Stock_News_Analysis" tokenizer = AutoTokenizer.from_pretrained(model_id) model = AutoModelForSequenceClassification.from_pretrained(model_id) sentiment_pipeline = pipeline("sentiment-analysis", model=model, tokenizer=tokenizer) # ----------- Function Definitions ----------- def fetch_news(ticker): try: url = f"https://finviz.com/quote.ashx?t={ticker}" 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, headers=headers) soup = BeautifulSoup(response.text, 'html.parser') news_table = soup.find(id='news-table') news = [] for row in news_table.findAll('tr')[:50]: # Fetch up to 50 articles title = row.a.get_text() link = row.a['href'] news.append({'title': title, 'link': link}) return news except Exception as e: st.error(f"Failed to fetch news for {ticker}: {e}") return [] def analyze_sentiment(text): try: result = sentiment_pipeline(text)[0] return "Positive" if result['label'] == 'POSITIVE' else "Negative" except Exception as e: st.error(f"Sentiment analysis failed: {e}") return "Unknown" # ----------- Streamlit UI ----------- st.title("📊 Stock News Sentiment Analysis") st.markdown(""" This tool parses stock tickers and analyzes the sentiment of related news articles. 💡 *Example input:* `META, NVDA, AAPL, NTES, NCTY` """) # Input field for stock tickers tickers_input = st.text_input("Enter stock tickers separated by commas:", "META, NVDA, AAPL, NTES, NCTY") # Parse and display cleaned tickers in real-time if tickers_input: tickers = [ticker.strip().upper() for ticker in tickers_input.split(",") if ticker.strip()] cleaned_input = ", ".join(tickers) st.markdown(f"🔎 **Parsed Tickers:** `{cleaned_input}`") else: tickers = [] # Button to trigger sentiment analysis if st.button("Get News and Sentiment"): if not tickers: st.warning("Please enter at least one stock ticker.") else: progress_bar = st.progress(0) total_stocks = len(tickers) for idx, ticker in enumerate(tickers): st.subheader(f"Analyzing {ticker}...") news_list = fetch_news(ticker) if news_list: # Analyze sentiment for all news articles (up to 50) sentiments = [] for news in news_list: sentiment = analyze_sentiment(news['title']) sentiments.append(sentiment) # Determine overall sentiment based on majority positive_count = sentiments.count("Positive") negative_count = sentiments.count("Negative") overall_sentiment = "Positive" if positive_count > negative_count else "Negative" # Display top 3 news articles with sentiment st.write(f"**Top 3 News Articles for {ticker}**") for i, news in enumerate(news_list[:3], 1): sentiment = sentiments[i-1] st.markdown(f"{i}. [{news['title']}]({news['link']}) - **{sentiment}**") # Display overall sentiment st.write(f"**Overall Sentiment for {ticker}: {overall_sentiment}**") else: st.write(f"No news available for {ticker}.") # Update progress bar progress_bar.progress((idx + 1) / total_stocks) time.sleep(0.1) # Simulate processing time