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

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +89 -266
app.py CHANGED
@@ -1,335 +1,158 @@
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()
 
1
  # app.py - Audio & Text Sentiment Analyzer
2
+ # Uses exact model: google-bert/bert-base-uncased (Masked LM)
3
+ # Runs locally with Gradio interface
4
 
5
  import gradio as gr
6
+ import whisper
7
  import torch
8
  import numpy as np
9
+ from transformers import AutoTokenizer, AutoModelForMaskedLM
10
+ from sklearn.linear_model import LogisticRegression
11
+ from sklearn.preprocessing import StandardScaler
 
 
 
 
 
12
 
13
+ print("Loading models... This may take a moment.")
14
 
15
+ # Load Whisper for audio transcription
16
+ whisper_model = whisper.load_model("base") # Fast and works well; use "small" for better accuracy
 
 
 
 
17
 
18
+ # Load exact requested BERT model
19
+ tokenizer = AutoTokenizer.from_pretrained("google-bert/bert-base-uncased")
20
+ model = AutoModelForMaskedLM.from_pretrained("google-bert/bert-base-uncased")
21
+ model.eval()
 
22
 
23
+ print("Models loaded successfully!")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
24
 
25
+ # Function to get [CLS] embedding
26
+ def get_cls_embedding(text):
27
+ inputs = tokenizer(text[:512], return_tensors="pt", truncation=True, padding=True)
28
  with torch.no_grad():
29
+ outputs = model(**inputs, output_hidden_states=True)
30
+ cls_embedding = outputs.hidden_states[-1][:, 0, :].cpu().numpy()
31
+ return cls_embedding.flatten()
32
 
33
+ # Training examples for simple sentiment classifier
34
+ example_texts = [
35
+ "I love this, it's absolutely amazing", "Best thing ever", "Fantastic experience",
36
+ "Highly recommend", "Super happy with it", "This is terrible", "Worst product ever",
37
+ "Very disappointed", "Complete waste", "Poor quality", "It's okay", "Nothing special",
38
+ "Arrived on time", "Works as expected", "Average"
39
+ ]
40
 
41
+ example_labels = [1,1,1,1,1, -1,-1,-1,-1,-1, 0,0,0,0,0] # 1=Positive, -1=Negative, 0=Neutral
 
 
 
 
 
 
 
 
 
 
 
 
42
 
43
+ # Train classifier
44
+ X_train = np.array([get_cls_embedding(t) for t in example_texts])
45
+ y_train = np.array(example_labels)
46
 
47
+ scaler = StandardScaler()
48
+ X_train_scaled = scaler.fit_transform(X_train)
 
 
 
 
 
 
 
 
 
 
49
 
50
+ clf = LogisticRegression(multi_class='ovr', class_weight='balanced')
51
+ clf.fit(X_train_scaled, y_train)
 
 
 
 
 
 
52
 
53
+ print("Sentiment classifier trained!")
54
 
55
+ # Predict sentiment with stars and confidence
56
+ def predict_sentiment(text):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
57
  if not text.strip():
58
  return "⭐⭐⭐ Neutral", "0%"
59
+
60
+ embedding = get_cls_embedding(text)
61
+ embedding_scaled = scaler.transform([embedding])
62
+
63
+ probabilities = clf.predict_proba(embedding_scaled)[0]
64
+ pred = clf.predict(embedding_scaled)[0]
65
+ confidence = np.max(probabilities) * 100
 
 
66
  conf_str = f"{confidence:.1f}%"
67
+
68
+ if pred == 1:
69
+ level = "⭐⭐⭐⭐⭐ Very Positive"
70
+ elif pred == -1:
71
+ level = "⭐ Very Negative"
 
 
 
 
 
72
  else:
73
+ level = "⭐⭐⭐ Neutral"
74
+
75
  return level, conf_str
76
 
77
+ # Main analysis function
78
  def analyze_input(audio_path, input_text):
79
+ # Prefer typed text if provided
80
  if input_text and input_text.strip():
81
  final_text = input_text.strip()
82
+
83
+ # Otherwise, transcribe audio
84
  elif audio_path is not None:
85
+ try:
86
+ print("Transcribing audio...")
87
+ result = whisper_model.transcribe(audio_path)
88
+ final_text = result["text"].strip()
89
+ if not final_text:
90
+ return "No speech detected in the audio.", "", "", "Please speak clearly and try again."
91
+ except Exception as e:
92
+ return "Error transcribing audio.", "", "", f"Error: {str(e)}"
93
+
94
  else:
95
  return "No input provided.", "", "", "Please type text or record/upload audio."
96
+
97
+ # Perform sentiment analysis
98
+ level, confidence = predict_sentiment(final_text)
99
  final_result = f"{level} (Confidence: {confidence})"
100
+
101
  return final_text, level, confidence, final_result
102
 
103
  # Gradio Interface
104
  with gr.Blocks(title="Audio & Text Sentiment Analyzer", theme=gr.themes.Soft()) as demo:
105
+ gr.Markdown("# 🎀✍️ Audio to Text + Sentiment Analyzer")
106
  gr.Markdown("""
107
+ - Record or upload audio β†’ **Automatically transcribed**
108
+ - Or type text directly
109
+ - Analyzes sentiment using **google-bert/bert-base-uncased** ([CLS] embedding)
110
  """)
111
+
112
  with gr.Row():
113
  with gr.Column(scale=1):
114
  audio_input = gr.Audio(
115
  sources=["microphone", "upload"],
116
  type="filepath",
117
+ label="Record or Upload Audio"
118
  )
119
+
120
  gr.Markdown("**OR**")
121
+
122
  text_input = gr.Textbox(
123
  label="Type or Paste Text",
124
+ placeholder="Enter your review or feedback here...",
125
  lines=6
126
  )
127
+
128
  btn = gr.Button("Transcribe & Analyze Sentiment", variant="primary", size="lg")
129
+
130
  with gr.Column():
131
  gr.Markdown("### πŸ“ Transcribed / Entered Text")
132
  text_display = gr.Textbox(label="Text", lines=8, interactive=False)
133
+
134
  gr.Markdown("### 🌟 Sentiment Result")
135
  with gr.Row():
136
  level_out = gr.Textbox(label="Sentiment Level", scale=2)
137
  conf_out = gr.Textbox(label="Confidence", scale=1)
138
+
139
  result_out = gr.Textbox(label="Final Verdict", lines=2, interactive=False)
140
+
141
  btn.click(
142
  fn=analyze_input,
143
  inputs=[audio_input, text_input],
144
  outputs=[text_display, level_out, conf_out, result_out]
145
  )
146
+
147
  gr.Markdown("""
148
  ### Notes
149
+ - Works with any language (Whisper handles transcription)
150
+ - Uses raw BERT base model β†’ educational demo
151
+ - Run locally, no data leaves your machine
152
+ - Made with ❀️ in Accra by Chris (@chrisbekor99)
 
153
  """)
154
 
155
+
156
  # Run app
157
  if __name__ == "__main__":
158
  demo.launch()