LinkLinkWu commited on
Commit
58a9d5d
·
verified ·
1 Parent(s): 99b85b9

Delete app.py

Browse files
Files changed (1) hide show
  1. app.py +0 -166
app.py DELETED
@@ -1,166 +0,0 @@
1
- import streamlit as st
2
- import requests
3
- from bs4 import BeautifulSoup
4
- from transformers import pipeline
5
- from transformers import AutoTokenizer, AutoModelForSequenceClassification, AutoModelForTokenClassification
6
- import time
7
-
8
- # ----------- Page Layout & Custom Styling -----------
9
- st.set_page_config(page_title="Stock News Sentiment Analysis", layout="centered")
10
-
11
- st.markdown("""
12
- <style>
13
- .main { background-color: #f9fbfc; }
14
- .stTextInput>div>div>input {
15
- font-size: 16px;
16
- padding: 0.5rem;
17
- }
18
- .stButton>button {
19
- background-color: #4CAF50;
20
- color: white;
21
- font-size: 16px;
22
- padding: 0.5rem 1rem;
23
- border-radius: 8px;
24
- }
25
- .stButton>button:hover {
26
- background-color: #45a049;
27
- }
28
- </style>
29
- """, unsafe_allow_html=True)
30
-
31
- # ----------- Model Setup -----------
32
- sentiment_model_id = "LinkLinkWu/Boss_Stock_News_Analysis"
33
- sentiment_tokenizer = AutoTokenizer.from_pretrained(sentiment_model_id)
34
- sentiment_model = AutoModelForSequenceClassification.from_pretrained(sentiment_model_id)
35
- sentiment_pipeline = pipeline("sentiment-analysis", model=sentiment_model, tokenizer=sentiment_tokenizer)
36
-
37
- ner_tokenizer = AutoTokenizer.from_pretrained("dslim/bert-base-NER")
38
- ner_model = AutoModelForTokenClassification.from_pretrained("dslim/bert-base-NER")
39
- ner_pipeline = pipeline("ner", model=ner_model, tokenizer=ner_tokenizer, grouped_entities=True)
40
-
41
- # ----------- Functions -----------
42
- def fetch_news(ticker):
43
- try:
44
- url = f"https://finviz.com/quote.ashx?t={ticker}"
45
- headers = {
46
- 'User-Agent': 'Mozilla/5.0',
47
- 'Accept': 'text/html',
48
- 'Accept-Language': 'en-US,en;q=0.5',
49
- 'Referer': 'https://finviz.com/',
50
- 'Connection': 'keep-alive',
51
- }
52
- response = requests.get(url, headers=headers)
53
- if response.status_code != 200:
54
- st.error(f"Failed to fetch page for {ticker}: Status code {response.status_code}")
55
- return []
56
-
57
- soup = BeautifulSoup(response.text, 'html.parser')
58
- title = soup.title.text if soup.title else ""
59
- if ticker not in title:
60
- st.error(f"Page for {ticker} not found or access denied.")
61
- return []
62
-
63
- news_table = soup.find(id='news-table')
64
- if news_table is None:
65
- st.error(f"News table not found for {ticker}. The website structure might have changed.")
66
- return []
67
-
68
- news = []
69
- for row in news_table.findAll('tr')[:50]:
70
- a_tag = row.find('a')
71
- if a_tag:
72
- title = a_tag.get_text()
73
- link = a_tag['href']
74
- news.append({'title': title, 'link': link})
75
- return news
76
- except Exception as e:
77
- st.error(f"Failed to fetch news for {ticker}: {e}")
78
- return []
79
-
80
- def analyze_sentiment(text):
81
- try:
82
- result = sentiment_pipeline(text)[0]
83
- return "Positive" if result['label'] == 'POSITIVE' else "Negative"
84
- except Exception as e:
85
- st.error(f"Sentiment analysis failed: {e}")
86
- return "Unknown"
87
-
88
- def extract_org_entities(text):
89
- try:
90
- entities = ner_pipeline(text)
91
- org_entities = []
92
- for ent in entities:
93
- if ent["entity_group"] == "ORG":
94
- clean_word = ent["word"].replace("##", "").strip()
95
- if clean_word.upper() not in org_entities:
96
- org_entities.append(clean_word.upper())
97
- if len(org_entities) >= 5:
98
- break
99
- return org_entities
100
- except Exception as e:
101
- st.error(f"NER entity extraction failed: {e}")
102
- return []
103
-
104
- # ----------- UI -----------
105
- st.title("\U0001F4CA Stock News Sentiment Analysis")
106
- st.markdown("""
107
- This tool parses stock tickers and analyzes the sentiment of related news articles.
108
- \U0001F4A1 *Example input:* `META, NVDA, AAPL, NTES, NCTY`
109
- **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.
110
- """)
111
-
112
- input_mode = st.radio("Choose input method:", ("Text (auto detect)", "Manual tickers"))
113
-
114
- if input_mode == "Manual tickers":
115
- tickers_input = st.text_input("Enter stock tickers separated by commas:", "META, NVDA, AAPL")
116
- tickers = [ticker.strip().upper() for ticker in tickers_input.split(",") if ticker.strip()]
117
- else:
118
- free_text = st.text_area("Enter text mentioning companies:", height=100)
119
- tickers = extract_org_entities(free_text)
120
-
121
- if tickers:
122
- cleaned_input = ", ".join(tickers)
123
- st.markdown(f"\U0001F50E **Parsed Tickers:** `{cleaned_input}`")
124
- else:
125
- tickers = []
126
-
127
- if st.button("Get News and Sentiment"):
128
- if not tickers:
129
- st.warning("Please enter at least one stock ticker.")
130
- else:
131
- progress_bar = st.progress(0)
132
- total_stocks = len(tickers)
133
- for idx, ticker in enumerate(tickers):
134
- st.subheader(f"Analyzing {ticker}...")
135
- news_list = fetch_news(ticker)
136
-
137
- if news_list:
138
- sentiments = []
139
- for news in news_list:
140
- sentiment = analyze_sentiment(news['title'])
141
- sentiments.append(sentiment)
142
-
143
- positive_count = sentiments.count("Positive")
144
- negative_count = sentiments.count("Negative")
145
- total = len(sentiments)
146
- positive_ratio = positive_count / total if total else 0
147
- negative_ratio = negative_count / total if total else 0
148
-
149
- if positive_ratio >= 0.4:
150
- overall_sentiment = "Positive"
151
- elif negative_ratio >= 0.6:
152
- overall_sentiment = "Negative"
153
- else:
154
- overall_sentiment = "Neutral"
155
-
156
- st.write(f"**Top 3 News Articles for {ticker}**")
157
- for i, news in enumerate(news_list[:3], 1):
158
- sentiment = sentiments[i-1]
159
- st.markdown(f"{i}. [{news['title']}]({news['link']}) - **{sentiment}**")
160
-
161
- st.write(f"**Overall Sentiment for {ticker}: {overall_sentiment}**")
162
- else:
163
- st.write(f"No news available for {ticker}.")
164
-
165
- progress_bar.progress((idx + 1) / total_stocks)
166
- time.sleep(0.1)