cwpkd commited on
Commit
eaa6f1b
Β·
verified Β·
1 Parent(s): c3e03eb

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +313 -0
app.py ADDED
@@ -0,0 +1,313 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # app.py
2
+ """
3
+ Yahoo Finance Sentiment Analysis with Gemma LLM
4
+ Hugging Face Space Application
5
+ """
6
+
7
+ import gradio as gr
8
+ import pandas as pd
9
+ from datetime import datetime
10
+ from utils import YahooFinanceScraper, SentimentAnalyzer, LLMAnalyzer
11
+ from config import POPULAR_STOCKS
12
+ import plotly.graph_objects as go
13
+
14
+ # Initialize components
15
+ print("Initializing application...")
16
+ scraper = YahooFinanceScraper()
17
+ sentiment_analyzer = SentimentAnalyzer()
18
+ llm_analyzer = LLMAnalyzer()
19
+ print("Application ready!")
20
+
21
+
22
+ def analyze_stock_news(symbol: str, num_articles: int = 10):
23
+ """
24
+ Main function to analyze stock news
25
+
26
+ Args:
27
+ symbol: Stock ticker symbol
28
+ num_articles: Number of articles to analyze
29
+
30
+ Returns:
31
+ Tuple of (summary, dataframe, chart, llm_insights)
32
+ """
33
+ try:
34
+ # Fetch news
35
+ articles = scraper.get_stock_news(symbol, num_articles)
36
+
37
+ if not articles:
38
+ return "No news found for this symbol.", None, None, "No articles to analyze."
39
+
40
+ # Analyze sentiments
41
+ sentiments = []
42
+ for article in articles:
43
+ text = f"{article['title']}. {article.get('summary', '')}"
44
+ sentiment = sentiment_analyzer.analyze_comprehensive(text)
45
+ sentiments.append(sentiment)
46
+
47
+ # Generate LLM insights
48
+ market_summary = llm_analyzer.summarize_news(articles)
49
+ investment_insight = llm_analyzer.generate_investment_insight(symbol, articles, sentiments)
50
+
51
+ # Create dataframe
52
+ df_data = []
53
+ for article, sentiment in zip(articles, sentiments):
54
+ df_data.append({
55
+ 'Title': article['title'],
56
+ 'Publisher': article['publisher'],
57
+ 'Sentiment': sentiment['sentiment_label'],
58
+ 'Score': f"{sentiment['combined_score']:.3f}",
59
+ 'Confidence': f"{sentiment['confidence']:.2%}",
60
+ 'VADER': f"{sentiment['vader']['compound']:.3f}",
61
+ 'FinBERT +': f"{sentiment['finbert']['positive']:.3f}",
62
+ 'FinBERT -': f"{sentiment['finbert']['negative']:.3f}",
63
+ })
64
+
65
+ df = pd.DataFrame(df_data)
66
+
67
+ # Create visualization
68
+ sentiment_counts = df['Sentiment'].value_counts()
69
+ fig = go.Figure(data=[
70
+ go.Bar(
71
+ x=sentiment_counts.index,
72
+ y=sentiment_counts.values,
73
+ marker_color=['#00cc66' if x=='Positive' else '#ff6666' if x=='Negative' else '#999999'
74
+ for x in sentiment_counts.index]
75
+ )
76
+ ])
77
+ fig.update_layout(
78
+ title=f"Sentiment Distribution for {symbol}",
79
+ xaxis_title="Sentiment",
80
+ yaxis_title="Number of Articles",
81
+ height=400
82
+ )
83
+
84
+ # Calculate statistics
85
+ avg_score = sum(s['combined_score'] for s in sentiments) / len(sentiments)
86
+ positive_pct = (sentiment_counts.get('Positive', 0) / len(sentiments)) * 100
87
+ negative_pct = (sentiment_counts.get('Negative', 0) / len(sentiments)) * 100
88
+
89
+ summary = f"""
90
+ ## πŸ“Š Analysis Summary for {symbol}
91
+
92
+ **Total Articles Analyzed:** {len(articles)}
93
+
94
+ **Sentiment Distribution:**
95
+ - 🟒 Positive: {sentiment_counts.get('Positive', 0)} ({positive_pct:.1f}%)
96
+ - πŸ”΄ Negative: {sentiment_counts.get('Negative', 0)} ({negative_pct:.1f}%)
97
+ - βšͺ Neutral: {sentiment_counts.get('Neutral', 0)} ({100-positive_pct-negative_pct:.1f}%)
98
+
99
+ **Average Sentiment Score:** {avg_score:.3f}
100
+
101
+ **Overall Sentiment:** {"🟒 Positive" if avg_score > 0.05 else "πŸ”΄ Negative" if avg_score < -0.05 else "βšͺ Neutral"}
102
+ """
103
+
104
+ llm_insights = f"""
105
+ ## πŸ€– AI-Generated Insights (Powered by Gemma)
106
+
107
+ ### Market Summary:
108
+ {market_summary}
109
+
110
+ ### Investment Perspective:
111
+ {investment_insight}
112
+
113
+ ---
114
+ *Note: These insights are generated by AI and should not be considered as financial advice.*
115
+ """
116
+
117
+ return summary, df, fig, llm_insights
118
+
119
+ except Exception as e:
120
+ return f"Error: {str(e)}", None, None, "Error generating insights."
121
+
122
+
123
+ def analyze_single_headline(headline: str):
124
+ """
125
+ Analyze a single headline
126
+
127
+ Args:
128
+ headline: News headline text
129
+
130
+ Returns:
131
+ Analysis results
132
+ """
133
+ try:
134
+ sentiment = sentiment_analyzer.analyze_comprehensive(headline)
135
+
136
+ # Create a dummy article dict for LLM analysis
137
+ article = {'title': headline, 'summary': ''}
138
+ explanation = llm_analyzer.analyze_sentiment_context(article, sentiment)
139
+
140
+ result = f"""
141
+ ## Sentiment Analysis Results
142
+
143
+ **Headline:** {headline}
144
+
145
+ **Overall Sentiment:** {sentiment['sentiment_label']} (Score: {sentiment['combined_score']:.3f})
146
+ **Confidence:** {sentiment['confidence']:.2%}
147
+
148
+ ### Detailed Scores:
149
+ - **VADER Compound:** {sentiment['vader']['compound']:.3f}
150
+ - **FinBERT Positive:** {sentiment['finbert']['positive']:.3%}
151
+ - **FinBERT Negative:** {sentiment['finbert']['negative']:.3%}
152
+ - **FinBERT Neutral:** {sentiment['finbert']['neutral']:.3%}
153
+
154
+ ### AI Explanation:
155
+ {explanation}
156
+ """
157
+
158
+ return result
159
+
160
+ except Exception as e:
161
+ return f"Error analyzing headline: {str(e)}"
162
+
163
+
164
+ # Create Gradio Interface
165
+ with gr.Blocks(title="Yahoo Finance Sentiment Analyzer", theme=gr.themes.Soft()) as demo:
166
+ gr.Markdown("""
167
+ # πŸ“ˆ Yahoo Finance Sentiment Analyzer
168
+ ### Powered by FinBERT + Gemma LLM
169
+
170
+ Analyze market sentiment from Yahoo Finance news using advanced NLP and AI.
171
+ """)
172
+
173
+ with gr.Tabs():
174
+ # Tab 1: Stock Analysis
175
+ with gr.Tab("πŸ“Š Stock Sentiment Analysis"):
176
+ gr.Markdown("### Analyze sentiment of news for any stock symbol")
177
+
178
+ with gr.Row():
179
+ with gr.Column(scale=2):
180
+ stock_input = gr.Textbox(
181
+ label="Stock Symbol",
182
+ placeholder="e.g., AAPL, GOOGL, TSLA",
183
+ value="AAPL"
184
+ )
185
+ with gr.Column(scale=1):
186
+ num_articles = gr.Slider(
187
+ minimum=5,
188
+ maximum=20,
189
+ value=10,
190
+ step=1,
191
+ label="Number of Articles"
192
+ )
193
+
194
+ gr.Markdown("**Quick Select:**")
195
+ quick_buttons = []
196
+ with gr.Row():
197
+ for stock in POPULAR_STOCKS[:5]:
198
+ btn = gr.Button(stock, size="sm")
199
+ quick_buttons.append(btn)
200
+ with gr.Row():
201
+ for stock in POPULAR_STOCKS[5:10]:
202
+ btn = gr.Button(stock, size="sm")
203
+ quick_buttons.append(btn)
204
+
205
+ analyze_btn = gr.Button("πŸ” Analyze News", variant="primary", size="lg")
206
+
207
+ summary_output = gr.Markdown(label="Summary")
208
+ insights_output = gr.Markdown(label="AI Insights")
209
+ chart_output = gr.Plot(label="Sentiment Distribution")
210
+ table_output = gr.Dataframe(label="Detailed Results")
211
+
212
+ # Button actions
213
+ analyze_btn.click(
214
+ fn=analyze_stock_news,
215
+ inputs=[stock_input, num_articles],
216
+ outputs=[summary_output, table_output, chart_output, insights_output]
217
+ )
218
+
219
+ # Quick select buttons
220
+ for btn in quick_buttons:
221
+ btn.click(
222
+ fn=lambda x: x,
223
+ inputs=[btn],
224
+ outputs=[stock_input]
225
+ )
226
+
227
+ # Tab 2: Single Headline Analysis
228
+ with gr.Tab("πŸ“° Single Headline Analyzer"):
229
+ gr.Markdown("### Analyze sentiment of a single news headline")
230
+
231
+ headline_input = gr.Textbox(
232
+ label="News Headline",
233
+ placeholder="Enter a financial news headline...",
234
+ lines=3
235
+ )
236
+
237
+ gr.Markdown("**Example Headlines:**")
238
+ example_headlines = [
239
+ "Apple reaches all-time high as iPhone sales surge",
240
+ "Tesla stock plummets amid production concerns",
241
+ "Fed maintains interest rates, markets remain stable"
242
+ ]
243
+
244
+ with gr.Row():
245
+ for example in example_headlines:
246
+ gr.Button(example[:50] + "...", size="sm").click(
247
+ fn=lambda x: x,
248
+ inputs=[gr.Textbox(value=example, visible=False)],
249
+ outputs=[headline_input]
250
+ )
251
+
252
+ analyze_headline_btn = gr.Button("πŸ” Analyze Headline", variant="primary")
253
+ headline_output = gr.Markdown(label="Analysis Results")
254
+
255
+ analyze_headline_btn.click(
256
+ fn=analyze_single_headline,
257
+ inputs=[headline_input],
258
+ outputs=[headline_output]
259
+ )
260
+
261
+ # Tab 3: About
262
+ with gr.Tab("ℹ️ About"):
263
+ gr.Markdown("""
264
+ ## About This Application
265
+
266
+ This application analyzes sentiment from Yahoo Finance news using multiple advanced techniques:
267
+
268
+ ### πŸ› οΈ Technologies Used:
269
+
270
+ 1. **VADER Sentiment Analysis**
271
+ - Rule-based sentiment analysis
272
+ - Good for general text sentiment
273
+
274
+ 2. **FinBERT**
275
+ - BERT model fine-tuned for financial text
276
+ - Specialized in financial sentiment analysis
277
+ - Model: `ProsusAI/finbert`
278
+
279
+ 3. **Gemma LLM**
280
+ - Google's Gemma language model
281
+ - Generates human-like insights and summaries
282
+ - Model: `google/gemma-2-2b-it`
283
+
284
+ ### πŸ“Š Features:
285
+
286
+ - Real-time news scraping from Yahoo Finance
287
+ - Multi-model sentiment analysis
288
+ - AI-generated market insights
289
+ - Interactive visualizations
290
+ - Batch and single headline analysis
291
+
292
+ ### πŸ“ Sentiment Scores:
293
+
294
+ - **Positive**: Score > 0.05
295
+ - **Negative**: Score < -0.05
296
+ - **Neutral**: -0.05 ≀ Score ≀ 0.05
297
+
298
+ ### ⚠️ Disclaimer:
299
+
300
+ This tool is for educational and research purposes only.
301
+ The sentiment analysis and AI-generated insights should NOT be used as financial advice.
302
+ Always do your own research and consult with financial professionals before making investment decisions.
303
+
304
+ ---
305
+
306
+ **Created with ❀️ using Hugging Face Spaces**
307
+ """)
308
+
309
+ # Launch the app
310
+ if __name__ == "__main__":
311
+ demo.launch()
312
+
313
+