KrizTech100 commited on
Commit
39a4dc6
Β·
verified Β·
1 Parent(s): f9a42db

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +335 -0
app.py ADDED
@@ -0,0 +1,335 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # app.py - Audio & Text Sentiment Analyzer
2
+ # Transcription: openai/whisper-base.en (official HF version)
3
+ # Sentiment: nlptown/bert-base-multilingual-uncased-sentiment (5-star accurate model)
4
+
5
+ import gradio as gr
6
+ import torch
7
+ import numpy as np
8
+ import librosa
9
+ from transformers import (
10
+ AutoProcessor,
11
+ AutoModelForSpeechSeq2Seq,
12
+ AutoTokenizer,
13
+ AutoModelForSequenceClassification
14
+ )
15
+ import torch.nn.functional as F
16
+
17
+ print("Loading models... Please wait.")
18
+
19
+ # === Load Whisper exactly as requested ===
20
+ processor = AutoProcessor.from_pretrained("openai/whisper-base.en")
21
+ whisper_model = AutoModelForSpeechSeq2Seq.from_pretrained("openai/whisper-base.en")
22
+ whisper_model.eval()
23
+ device = "cuda" if torch.cuda.is_available() else "cpu"
24
+ whisper_model.to(device)
25
+
26
+ # === Load Sentiment model exactly as requested ===
27
+ sentiment_tokenizer = AutoTokenizer.from_pretrained('nlptown/bert-base-multilingual-uncased-sentiment')
28
+ sentiment_model = AutoModelForSequenceClassification.from_pretrained('nlptown/bert-base-multilingual-uncased-sentiment')
29
+ sentiment_model.eval()
30
+ sentiment_model.to(device)
31
+
32
+ print("All models loaded successfully!")
33
+
34
+
35
+ # Transcribe audio using official Whisper
36
+ def transcribe_audio(audio_path):
37
+ if audio_path is None:
38
+ return ""
39
+
40
+ try:
41
+ # Load and resample to 16kHz
42
+ speech, _ = librosa.load(audio_path, sr=16000)
43
+
44
+ # Process input
45
+ input_features = processor(speech, sampling_rate=16000, return_tensors="pt").input_features
46
+ input_features = input_features.to(device)
47
+
48
+ # Generate transcription
49
+ with torch.no_grad():
50
+ predicted_ids = whisper_model.generate(input_features)
51
+
52
+ transcription = processor.batch_decode(predicted_ids, skip_special_tokens=True)[0]
53
+ return transcription.strip()
54
+
55
+ except Exception as e:
56
+ print(f"Transcription error: {e}")
57
+ return "[Transcription failed]"
58
+
59
+
60
+ # Sentiment analysis with 5-star rating and confidence
61
+ def analyze_sentiment(text):
62
+ if not text.strip():
63
+ return "⭐⭐⭐ Neutral", "0%"
64
+
65
+ inputs = sentiment_tokenizer(text[:512], return_tensors="pt", truncation=True).to(device)
66
+
67
+ with torch.no_grad():
68
+ logits = sentiment_model(**inputs).logits
69
+
70
+ probabilities = F.softmax(logits, dim=-1)[0]
71
+ predicted_class = torch.argmax(probabilities).item() + 1 # 1 to 5
72
+ confidence = probabilities[predicted_class - 1].item() * 100
73
+ conf_str = f"{confidence:.1f}%"
74
+
75
+ stars = "⭐" * predicted_class
76
+ if predicted_class == 1:
77
+ level = f"{stars} Very Negative"
78
+ elif predicted_class == 2:
79
+ level = f"{stars} Negative"
80
+ elif predicted_class == 3:
81
+ level = f"{stars} Neutral"
82
+ elif predicted_class == 4:
83
+ level = f"{stars} Positive"
84
+ else:
85
+ level = f"{stars} Very Positive"
86
+
87
+ return level, conf_str
88
+
89
+
90
+ # Main unified function
91
+ def analyze_input(audio_path, input_text):
92
+ # Use typed text if provided
93
+ if input_text and input_text.strip():
94
+ final_text = input_text.strip()
95
+
96
+ # Otherwise transcribe audio
97
+ elif audio_path is not None:
98
+ print("Transcribing audio...")
99
+ final_text = transcribe_audio(audio_path)
100
+ if not final_text or "failed" in final_text.lower():
101
+ return "Transcription failed or no speech detected.", "", "", "Please try again with clearer English audio."
102
+
103
+ else:
104
+ return "No input provided.", "", "", "Please type text or record/upload audio."
105
+
106
+ # Sentiment analysis
107
+ level, confidence = analyze_sentiment(final_text)
108
+ final_result = f"{level} (Confidence: {confidence})"
109
+
110
+ return final_text, level, confidence, final_result
111
+
112
+
113
+ # Gradio Interface
114
+ with gr.Blocks(title="Audio & Text Sentiment Analyzer", theme=gr.themes.Soft()) as demo:
115
+ gr.Markdown("# 🎀✍️ Audio to Text + 5-Star Sentiment Analyzer")
116
+ gr.Markdown("""
117
+ - **Transcription**: OpenAI Whisper-base.en (excellent English accuracy)
118
+ - **Sentiment**: Multilingual BERT fine-tuned on reviews β†’ accurate **1–5 star** ratings
119
+ - Record/upload audio **or** type text directly
120
+ """)
121
+
122
+ with gr.Row():
123
+ with gr.Column(scale=1):
124
+ audio_input = gr.Audio(
125
+ sources=["microphone", "upload"],
126
+ type="filepath",
127
+ label="Record or Upload Audio (English recommended)"
128
+ )
129
+
130
+ gr.Markdown("**OR**")
131
+
132
+ text_input = gr.Textbox(
133
+ label="Type or Paste Text",
134
+ placeholder="Enter your review, feedback, or transcribed text...",
135
+ lines=6
136
+ )
137
+
138
+ btn = gr.Button("Transcribe & Analyze Sentiment", variant="primary", size="lg")
139
+
140
+ with gr.Column():
141
+ gr.Markdown("### πŸ“ Transcribed / Entered Text")
142
+ text_display = gr.Textbox(label="Text", lines=8, interactive=False)
143
+
144
+ gr.Markdown("### 🌟 Sentiment Result")
145
+ with gr.Row():
146
+ level_out = gr.Textbox(label="Sentiment Level", scale=2)
147
+ conf_out = gr.Textbox(label="Confidence", scale=1)
148
+
149
+ result_out = gr.Textbox(label="Final Verdict", lines=2, interactive=False)
150
+
151
+ btn.click(
152
+ fn=analyze_input,
153
+ inputs=[audio_input, text_input],
154
+ outputs=[text_display, level_out, conf_out, result_out]
155
+ )
156
+
157
+ gr.Markdown("""
158
+ ### Notes
159
+ - Best performance with **clear English speech**
160
+ - Sentiment model excels at review-style language (opinions, experiences)
161
+ - Confidence >80% = very reliable prediction
162
+ - Runs completely locally β€” perfect for privacy
163
+ - Built with ❀️ in Accra by Chris (@chrisbekor99)
164
+ """)
165
+
166
+ # Launch
167
+ if __name__ == "__main__":
168
+ demo.launch(
169
+ server_name="127.0.0.1",
170
+ server_port=7860,
171
+ share=False # Change to True for public link via ngrok
172
+ )# app.py - Audio & Text Sentiment Analyzer
173
+ # Transcription: openai/whisper-base.en (official HF version)
174
+ # Sentiment: nlptown/bert-base-multilingual-uncased-sentiment (5-star accurate model)
175
+
176
+ import gradio as gr
177
+ import torch
178
+ import numpy as np
179
+ import librosa
180
+ from transformers import (
181
+ AutoProcessor,
182
+ AutoModelForSpeechSeq2Seq,
183
+ AutoTokenizer,
184
+ AutoModelForSequenceClassification
185
+ )
186
+ import torch.nn.functional as F
187
+
188
+ print("Loading models... Please wait.")
189
+
190
+ # === Load Whisper exactly as requested ===
191
+ processor = AutoProcessor.from_pretrained("openai/whisper-base.en")
192
+ whisper_model = AutoModelForSpeechSeq2Seq.from_pretrained("openai/whisper-base.en")
193
+ whisper_model.eval()
194
+ device = "cuda" if torch.cuda.is_available() else "cpu"
195
+ whisper_model.to(device)
196
+
197
+ # === Load Sentiment model exactly as requested ===
198
+ sentiment_tokenizer = AutoTokenizer.from_pretrained('nlptown/bert-base-multilingual-uncased-sentiment')
199
+ sentiment_model = AutoModelForSequenceClassification.from_pretrained('nlptown/bert-base-multilingual-uncased-sentiment')
200
+ sentiment_model.eval()
201
+ sentiment_model.to(device)
202
+
203
+ print("All models loaded successfully!")
204
+
205
+ # Transcribe audio using official Whisper
206
+ def transcribe_audio(audio_path):
207
+ if audio_path is None:
208
+ return ""
209
+
210
+ try:
211
+ # Load and resample to 16kHz
212
+ speech, _ = librosa.load(audio_path, sr=16000)
213
+
214
+ # Process input
215
+ input_features = processor(speech, sampling_rate=16000, return_tensors="pt").input_features
216
+ input_features = input_features.to(device)
217
+
218
+ # Generate transcription
219
+ with torch.no_grad():
220
+ predicted_ids = whisper_model.generate(input_features)
221
+
222
+ transcription = processor.batch_decode(predicted_ids, skip_special_tokens=True)[0]
223
+ return transcription.strip()
224
+
225
+ except Exception as e:
226
+ print(f"Transcription error: {e}")
227
+ return "[Transcription failed]"
228
+
229
+ # Sentiment analysis with 5-star rating and confidence
230
+ def analyze_sentiment(text):
231
+ if not text.strip():
232
+ return "⭐⭐⭐ Neutral", "0%"
233
+
234
+ inputs = sentiment_tokenizer(text[:512], return_tensors="pt", truncation=True).to(device)
235
+
236
+ with torch.no_grad():
237
+ logits = sentiment_model(**inputs).logits
238
+
239
+ probabilities = F.softmax(logits, dim=-1)[0]
240
+ predicted_class = torch.argmax(probabilities).item() + 1 # 1 to 5
241
+ confidence = probabilities[predicted_class - 1].item() * 100
242
+ conf_str = f"{confidence:.1f}%"
243
+
244
+ stars = "⭐" * predicted_class
245
+ if predicted_class == 1:
246
+ level = f"{stars} Very Negative"
247
+ elif predicted_class == 2:
248
+ level = f"{stars} Negative"
249
+ elif predicted_class == 3:
250
+ level = f"{stars} Neutral"
251
+ elif predicted_class == 4:
252
+ level = f"{stars} Positive"
253
+ else:
254
+ level = f"{stars} Very Positive"
255
+
256
+ return level, conf_str
257
+
258
+ # Main unified function
259
+ def analyze_input(audio_path, input_text):
260
+ # Use typed text if provided
261
+ if input_text and input_text.strip():
262
+ final_text = input_text.strip()
263
+
264
+ # Otherwise transcribe audio
265
+ elif audio_path is not None:
266
+ print("Transcribing audio...")
267
+ final_text = transcribe_audio(audio_path)
268
+ if not final_text or "failed" in final_text.lower():
269
+ return "Transcription failed or no speech detected.", "", "", "Please try again with clearer English audio."
270
+
271
+ else:
272
+ return "No input provided.", "", "", "Please type text or record/upload audio."
273
+
274
+ # Sentiment analysis
275
+ level, confidence = analyze_sentiment(final_text)
276
+ final_result = f"{level} (Confidence: {confidence})"
277
+
278
+ return final_text, level, confidence, final_result
279
+
280
+ # Gradio Interface
281
+ with gr.Blocks(title="Audio & Text Sentiment Analyzer", theme=gr.themes.Soft()) as demo:
282
+ gr.Markdown("# 🎀✍️ Audio to Text + 5-Star Sentiment Analyzer")
283
+ gr.Markdown("""
284
+ - **Transcription**: OpenAI Whisper-base.en (excellent English accuracy)
285
+ - **Sentiment**: Multilingual BERT fine-tuned on reviews β†’ accurate **1–5 star** ratings
286
+ - Record/upload audio **or** type text directly
287
+ """)
288
+
289
+ with gr.Row():
290
+ with gr.Column(scale=1):
291
+ audio_input = gr.Audio(
292
+ sources=["microphone", "upload"],
293
+ type="filepath",
294
+ label="Record or Upload Audio (English recommended)"
295
+ )
296
+
297
+ gr.Markdown("**OR**")
298
+
299
+ text_input = gr.Textbox(
300
+ label="Type or Paste Text",
301
+ placeholder="Enter your review, feedback, or transcribed text...",
302
+ lines=6
303
+ )
304
+
305
+ btn = gr.Button("Transcribe & Analyze Sentiment", variant="primary", size="lg")
306
+
307
+ with gr.Column():
308
+ gr.Markdown("### πŸ“ Transcribed / Entered Text")
309
+ text_display = gr.Textbox(label="Text", lines=8, interactive=False)
310
+
311
+ gr.Markdown("### 🌟 Sentiment Result")
312
+ with gr.Row():
313
+ level_out = gr.Textbox(label="Sentiment Level", scale=2)
314
+ conf_out = gr.Textbox(label="Confidence", scale=1)
315
+
316
+ result_out = gr.Textbox(label="Final Verdict", lines=2, interactive=False)
317
+
318
+ btn.click(
319
+ fn=analyze_input,
320
+ inputs=[audio_input, text_input],
321
+ outputs=[text_display, level_out, conf_out, result_out]
322
+ )
323
+
324
+ gr.Markdown("""
325
+ ### Notes
326
+ - Best performance with **clear English speech**
327
+ - Sentiment model excels at review-style language (opinions, experiences)
328
+ - Confidence >80% = very reliable prediction
329
+ - Runs completely locally β€” perfect for privacy
330
+ - Built with ❀️ in Accra by Chris (@chrisbekor99)
331
+ """)
332
+
333
+ # Run app
334
+ if __name__ == "__main__":
335
+ demo.launch()