DevxAman commited on
Commit
f5a6aa3
Β·
verified Β·
1 Parent(s): 6e956ea

Upload 3 files

Browse files
Files changed (3) hide show
  1. app.py +244 -0
  2. requirements.txt +7 -0
  3. space.py +8 -0
app.py ADDED
@@ -0,0 +1,244 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ HuggingFace Space App - News Sentiment Analyzer
3
+ ZeroGPU Compatible Version - torch 2.8.0
4
+ """
5
+
6
+ import gradio as gr
7
+ import torch
8
+ from transformers import AutoTokenizer, AutoModelForSequenceClassification
9
+ from scipy.special import softmax
10
+ import numpy as np
11
+
12
+ print("πŸš€ Loading Sentiment Models...")
13
+
14
+ # Device configuration - ZeroGPU compatible
15
+ device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
16
+ print(f"πŸ“± Using device: {device}")
17
+
18
+ # ============================================
19
+ # 1. LOAD ROBERTA MODEL
20
+ # ============================================
21
+ print("πŸ“₯ Loading RoBERTa model...")
22
+ roberta_model_name = "cardiffnlp/twitter-roberta-base-sentiment-latest"
23
+ roberta_tokenizer = AutoTokenizer.from_pretrained(roberta_model_name)
24
+ roberta_model = AutoModelForSequenceClassification.from_pretrained(roberta_model_name).to(device)
25
+ roberta_model.eval()
26
+ print("βœ… RoBERTa model loaded!")
27
+
28
+ # ============================================
29
+ # 2. LOAD SIEBERT MODEL
30
+ # ============================================
31
+ print("πŸ“₯ Loading Siebert model...")
32
+ siebert_model_name = "siebert/sentiment-roberta-large-english"
33
+ siebert_tokenizer = AutoTokenizer.from_pretrained(siebert_model_name)
34
+ siebert_model = AutoModelForSequenceClassification.from_pretrained(siebert_model_name).to(device)
35
+ siebert_model.eval()
36
+ print("βœ… Siebert model loaded!")
37
+
38
+ print("🎯 All models ready!")
39
+
40
+
41
+ # ============================================
42
+ # SENTIMENT ANALYSIS FUNCTIONS
43
+ # ============================================
44
+
45
+ def analyze_roberta(text):
46
+ """Analyze sentiment using RoBERTa model"""
47
+ try:
48
+ if not text or len(text.strip()) < 5:
49
+ return {'negative': 0.33, 'neutral': 0.34, 'positive': 0.33}
50
+
51
+ encoded = roberta_tokenizer(
52
+ text,
53
+ return_tensors='pt',
54
+ truncation=True,
55
+ max_length=512,
56
+ padding=True
57
+ ).to(device)
58
+
59
+ with torch.no_grad():
60
+ output = roberta_model(**encoded)
61
+
62
+ scores = softmax(output.logits.cpu().numpy()[0])
63
+ return {
64
+ 'negative': float(scores[0]),
65
+ 'neutral': float(scores[1]),
66
+ 'positive': float(scores[2])
67
+ }
68
+ except Exception as e:
69
+ print(f"❌ RoBERTa error: {e}")
70
+ return {'negative': 0.33, 'neutral': 0.34, 'positive': 0.33}
71
+
72
+
73
+ def analyze_siebert(text):
74
+ """Analyze sentiment using Siebert model"""
75
+ try:
76
+ if not text or len(text.strip()) < 5:
77
+ return {'negative': 0.5, 'positive': 0.5}
78
+
79
+ encoded = siebert_tokenizer(
80
+ text,
81
+ return_tensors='pt',
82
+ truncation=True,
83
+ max_length=512,
84
+ padding=True
85
+ ).to(device)
86
+
87
+ with torch.no_grad():
88
+ output = siebert_model(**encoded)
89
+
90
+ scores = softmax(output.logits.cpu().numpy()[0])
91
+ return {
92
+ 'negative': float(scores[0]),
93
+ 'positive': float(scores[1])
94
+ }
95
+ except Exception as e:
96
+ print(f"❌ Siebert error: {e}")
97
+ return {'negative': 0.5, 'positive': 0.5}
98
+
99
+
100
+ def get_ensemble_sentiment(text):
101
+ """Combine both models for accurate results"""
102
+
103
+ roberta_result = analyze_roberta(text)
104
+ siebert_result = analyze_siebert(text)
105
+
106
+ siebert_neg = siebert_result['negative']
107
+ siebert_pos = siebert_result['positive']
108
+ diff = abs(siebert_pos - siebert_neg)
109
+
110
+ if diff < 0.2:
111
+ siebert_neutral = 1 - diff
112
+ siebert_neg = siebert_neg * (1 - siebert_neutral/2)
113
+ siebert_pos = siebert_pos * (1 - siebert_neutral/2)
114
+ else:
115
+ siebert_neutral = 0.1
116
+ siebert_neg = siebert_neg * 0.95
117
+ siebert_pos = siebert_pos * 0.95
118
+
119
+ ensemble_neg = (roberta_result['negative'] + siebert_neg) / 2
120
+ ensemble_neu = (roberta_result['neutral'] + siebert_neutral) / 2
121
+ ensemble_pos = (roberta_result['positive'] + siebert_pos) / 2
122
+
123
+ total = ensemble_neg + ensemble_neu + ensemble_pos
124
+ if total > 0:
125
+ ensemble_neg /= total
126
+ ensemble_neu /= total
127
+ ensemble_pos /= total
128
+
129
+ max_score = max(ensemble_neg, ensemble_neu, ensemble_pos)
130
+ if max_score == ensemble_neg:
131
+ label = 'Negative'
132
+ elif max_score == ensemble_pos:
133
+ label = 'Positive'
134
+ else:
135
+ label = 'Neutral'
136
+
137
+ return {
138
+ 'sentiment': label,
139
+ 'confidence': round(max_score, 4),
140
+ 'negative_score': round(ensemble_neg, 4),
141
+ 'neutral_score': round(ensemble_neu, 4),
142
+ 'positive_score': round(ensemble_pos, 4)
143
+ }
144
+
145
+
146
+ def predict_single(text):
147
+ """Predict sentiment for single text"""
148
+ if not text or len(text.strip()) < 5:
149
+ return "⚠️ Please enter some text to analyze."
150
+
151
+ result = get_ensemble_sentiment(text)
152
+
153
+ sentiment_emoji = {'Positive': 'βœ…', 'Negative': '❌', 'Neutral': 'βšͺ'}
154
+ emoji = sentiment_emoji.get(result['sentiment'], 'βšͺ')
155
+ confidence_pct = result['confidence'] * 100
156
+
157
+ if confidence_pct > 80:
158
+ confidence_color = "🟒"
159
+ elif confidence_pct > 60:
160
+ confidence_color = "🟑"
161
+ else:
162
+ confidence_color = "πŸ”΄"
163
+
164
+ return f"""
165
+ # πŸ“Š Sentiment Analysis Results
166
+
167
+ ---
168
+
169
+ ### {emoji} **Final Sentiment: {result['sentiment']}**
170
+ **Confidence:** {confidence_color} {confidence_pct:.1f}%
171
+
172
+ ---
173
+
174
+ ### πŸ“ˆ Score Breakdown
175
+
176
+ | Aspect | Score |
177
+ |--------|-------|
178
+ | βœ… Positive | {result['positive_score']*100:.1f}% |
179
+ | ❌ Negative | {result['negative_score']*100:.1f}% |
180
+ | βšͺ Neutral | {result['neutral_score']*100:.1f}% |
181
+
182
+ ---
183
+
184
+ ### πŸ“ Analyzed Text
185
+ > {text[:200]}{'...' if len(text) > 200 else ''}
186
+ """
187
+
188
+
189
+ def api_predict(text):
190
+ """API endpoint for external calls (JSON response)"""
191
+ if not text or len(text.strip()) < 5:
192
+ return {
193
+ 'error': 'Text too short or empty',
194
+ 'sentiment': 'Neutral',
195
+ 'confidence': 0.0
196
+ }
197
+
198
+ return get_ensemble_sentiment(text)
199
+
200
+
201
+ # ============================================
202
+ # GRADIO INTERFACE
203
+ # ============================================
204
+
205
+ # Create the interface
206
+ demo = gr.Interface(
207
+ fn=predict_single,
208
+ inputs=gr.Textbox(
209
+ label="πŸ“ Enter News Text",
210
+ placeholder="Paste your news article here...",
211
+ lines=8,
212
+ max_lines=20
213
+ ),
214
+ outputs=gr.Markdown(label="πŸ“ˆ Analysis Results"),
215
+ title="πŸ“° News Sentiment Analyzer",
216
+ description="""
217
+ ### 🎯 Ensemble Model: RoBERTa + Siebert
218
+
219
+ This analyzer uses two powerful models combined for accurate sentiment analysis:
220
+ - **RoBERTa**: Twitter-based sentiment model (negative, neutral, positive)
221
+ - **Siebert**: Large-scale sentiment model (negative, positive)
222
+
223
+ The ensemble approach provides more robust results by combining both models.
224
+ """,
225
+ examples=[
226
+ ["Apple reported record profits with revenue growth of 15% this quarter. The tech giant exceeded market expectations."],
227
+ ["The company faces severe criticism over data breach affecting millions of users. Stocks fell sharply."],
228
+ ["Government announced new policies to boost economic growth and create jobs. Markets reacted positively."],
229
+ ["Defense ministry successfully tested new hypersonic missile system."],
230
+ ["The bank reported $2 billion in losses due to failed investments. CEO resigned."]
231
+ ],
232
+ theme="soft",
233
+ cache_examples=True
234
+ )
235
+
236
+ if __name__ == "__main__":
237
+ print("\n" + "="*60)
238
+ print("πŸš€ News Sentiment Analyzer")
239
+ print("="*60)
240
+ print("πŸ“± Device:", device)
241
+ print("πŸ€– Models: RoBERTa + Siebert")
242
+ print("="*60 + "\n")
243
+
244
+ demo.launch(share=True)
requirements.txt ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ torch==2.8.0
2
+ transformers==4.46.3
3
+ scipy==1.15.2
4
+ numpy==2.0.0
5
+ gradio==5.16.0
6
+ sentencepiece==0.2.0
7
+ protobuf==5.29.3
space.py ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Main entry point for HuggingFace Space
3
+ """
4
+
5
+ from app import demo
6
+
7
+ if __name__ == "__main__":
8
+ demo.launch()