Spaces:
Sleeping
Sleeping
File size: 5,590 Bytes
29e42d5 78c1fff 6af8332 908b282 72f2309 908b282 47ffeb1 908b282 47ffeb1 908b282 72f2309 78c1fff 47ffeb1 78c1fff e3ea312 78c1fff e3ea312 78c1fff e3ea312 78c1fff e3ea312 78c1fff 72f2309 e3ea312 78c1fff 29e42d5 47ffeb1 e3ea312 47ffeb1 29e42d5 78c1fff 47ffeb1 822643b 47ffeb1 78c1fff 47ffeb1 78c1fff 47ffeb1 72f2309 47ffeb1 |
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 |
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("""
<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 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',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
'Accept-Language': 'en-US,en;q=0.5',
'Referer': 'https://finviz.com/',
'Connection': 'keep-alive',
}
response = requests.get(url, headers=headers)
if response.status_code != 200:
st.error(f"Failed to fetch page for {ticker}: Status code {response.status_code}")
return []
soup = BeautifulSoup(response.text, 'html.parser')
title = soup.title.text if soup.title else ""
if ticker not in title:
st.error(f"Page for {ticker} not found or access denied.")
return []
news_table = soup.find(id='news-table')
if news_table is None:
st.error(f"News table not found for {ticker}. The website structure might have changed.")
return []
news = []
for row in news_table.findAll('tr')[:50]: # Fetch up to 50 articles
a_tag = row.find('a')
if a_tag:
title = a_tag.get_text()
link = a_tag['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`
**Note:** If news fetching fails, it might be due to changes in the Finviz website structure or access restrictions. Please verify the website manually or try again later.
""")
# 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 |