| | import streamlit as st |
| | import requests |
| | from bs4 import BeautifulSoup |
| | from transformers import pipeline |
| | from transformers import AutoTokenizer, AutoModelForSequenceClassification |
| | import time |
| |
|
| | |
| | st.set_page_config(page_title="Stock News Sentiment Analysis", layout="centered") |
| |
|
| | st.markdown(""" |
| | <style> |
| | .main { background-color: #f9fbfc; } |
| | .stTextInput>div>div>input { |
| | font-size: 16px; |
| | padding: 0.5rem; |
| | } |
| | .stButton>button { |
| | background-color: #4CAF50; |
| | color: white; |
| | font-size: 16px; |
| | padding: 0.5rem 1rem; |
| | border-radius: 8px; |
| | } |
| | .stButton>button:hover { |
| | background-color: #45a049; |
| | } |
| | </style> |
| | """, unsafe_allow_html=True) |
| |
|
| | |
| | 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) |
| |
|
| | |
| | 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]: |
| | 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" |
| |
|
| | |
| | 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` |
| | """) |
| |
|
| | |
| | tickers_input = st.text_input("Enter stock tickers separated by commas:", "META, NVDA, AAPL, NTES, NCTY") |
| |
|
| | |
| | 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 = [] |
| |
|
| | |
| | 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: |
| | |
| | sentiments = [] |
| | for news in news_list: |
| | sentiment = analyze_sentiment(news['title']) |
| | sentiments.append(sentiment) |
| | |
| | |
| | positive_count = sentiments.count("Positive") |
| | negative_count = sentiments.count("Negative") |
| | overall_sentiment = "Positive" if positive_count > negative_count else "Negative" |
| | |
| | |
| | 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}**") |
| | |
| | |
| | st.write(f"**Overall Sentiment for {ticker}: {overall_sentiment}**") |
| | else: |
| | st.write(f"No news available for {ticker}.") |
| | |
| | |
| | progress_bar.progress((idx + 1) / total_stocks) |
| | time.sleep(0.1) |