KrizTech100 commited on
Commit
7d7870d
Β·
verified Β·
1 Parent(s): 02641fd

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +90 -83
app.py CHANGED
@@ -1,112 +1,118 @@
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():
@@ -114,14 +120,14 @@ with gr.Blocks(title="Audio & Text Sentiment Analyzer", theme=gr.themes.Soft())
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
 
@@ -146,10 +152,11 @@ with gr.Blocks(title="Audio & Text Sentiment Analyzer", theme=gr.themes.Soft())
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
 
 
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
+ # Transcribe audio using official Whisper
35
+ def transcribe_audio(audio_path):
36
+ if audio_path is None:
37
+ return ""
38
+
39
+ try:
40
+ # Load and resample to 16kHz
41
+ speech, _ = librosa.load(audio_path, sr=16000)
42
+
43
+ # Process input
44
+ input_features = processor(speech, sampling_rate=16000, return_tensors="pt").input_features
45
+ input_features = input_features.to(device)
46
+
47
+ # Generate transcription
48
+ with torch.no_grad():
49
+ predicted_ids = whisper_model.generate(input_features)
50
+
51
+ transcription = processor.batch_decode(predicted_ids, skip_special_tokens=True)[0]
52
+ return transcription.strip()
53
+
54
+ except Exception as e:
55
+ print(f"Transcription error: {e}")
56
+ return "[Transcription failed]"
57
 
58
+ # Sentiment analysis with 5-star rating and confidence
59
+ def analyze_sentiment(text):
60
  if not text.strip():
61
  return "⭐⭐⭐ Neutral", "0%"
62
 
63
+ inputs = sentiment_tokenizer(text[:512], return_tensors="pt", truncation=True).to(device)
64
+
65
+ with torch.no_grad():
66
+ logits = sentiment_model(**inputs).logits
67
 
68
+ probabilities = F.softmax(logits, dim=-1)[0]
69
+ predicted_class = torch.argmax(probabilities).item() + 1 # 1 to 5
70
+ confidence = probabilities[predicted_class - 1].item() * 100
71
  conf_str = f"{confidence:.1f}%"
72
 
73
+ stars = "⭐" * predicted_class
74
+ if predicted_class == 1:
75
+ level = f"{stars} Very Negative"
76
+ elif predicted_class == 2:
77
+ level = f"{stars} Negative"
78
+ elif predicted_class == 3:
79
+ level = f"{stars} Neutral"
80
+ elif predicted_class == 4:
81
+ level = f"{stars} Positive"
82
  else:
83
+ level = f"{stars} Very Positive"
84
 
85
  return level, conf_str
86
 
87
+ # Main unified function
88
  def analyze_input(audio_path, input_text):
89
+ # Use typed text if provided
90
  if input_text and input_text.strip():
91
  final_text = input_text.strip()
92
 
93
+ # Otherwise transcribe audio
94
  elif audio_path is not None:
95
+ print("Transcribing audio...")
96
+ final_text = transcribe_audio(audio_path)
97
+ if not final_text or "failed" in final_text.lower():
98
+ return "Transcription failed or no speech detected.", "", "", "Please try again with clearer English audio."
 
 
 
 
99
 
100
  else:
101
  return "No input provided.", "", "", "Please type text or record/upload audio."
102
 
103
+ # Sentiment analysis
104
+ level, confidence = analyze_sentiment(final_text)
105
  final_result = f"{level} (Confidence: {confidence})"
106
 
107
  return final_text, level, confidence, final_result
108
 
109
  # Gradio Interface
110
  with gr.Blocks(title="Audio & Text Sentiment Analyzer", theme=gr.themes.Soft()) as demo:
111
+ gr.Markdown("# 🎀✍️ Audio to Text + 5-Star Sentiment Analyzer")
112
  gr.Markdown("""
113
+ - **Transcription**: OpenAI Whisper-base.en (excellent English accuracy)
114
+ - **Sentiment**: Multilingual BERT fine-tuned on reviews β†’ accurate **1–5 star** ratings
115
+ - Record/upload audio **or** type text directly
116
  """)
117
 
118
  with gr.Row():
 
120
  audio_input = gr.Audio(
121
  sources=["microphone", "upload"],
122
  type="filepath",
123
+ label="Record or Upload Audio (English recommended)"
124
  )
125
 
126
  gr.Markdown("**OR**")
127
 
128
  text_input = gr.Textbox(
129
  label="Type or Paste Text",
130
+ placeholder="Enter your review, feedback, or transcribed text...",
131
  lines=6
132
  )
133
 
 
152
 
153
  gr.Markdown("""
154
  ### Notes
155
+ - Best performance with **clear English speech**
156
+ - Sentiment model excels at review-style language (opinions, experiences)
157
+ - Confidence >80% = very reliable prediction
158
+ - Runs completely locally β€” perfect for privacy
159
+ - Built with ❀️ in Accra by Chris (@chrisbekor99)
160
  """)
161
 
162