File size: 5,810 Bytes
39a4dc6
7d7870d
 
39a4dc6
 
 
 
7d7870d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
39a4dc6
7d7870d
 
39a4dc6
 
03a5c69
7d7870d
 
 
 
03a5c69
7d7870d
 
 
39a4dc6
03a5c69
7d7870d
 
 
 
 
 
 
 
 
39a4dc6
7d7870d
03a5c69
39a4dc6
 
7d7870d
39a4dc6
7d7870d
39a4dc6
 
03a5c69
7d7870d
39a4dc6
7d7870d
 
 
 
03a5c69
39a4dc6
 
03a5c69
7d7870d
 
39a4dc6
03a5c69
39a4dc6
 
 
 
7d7870d
39a4dc6
7d7870d
 
 
39a4dc6
03a5c69
39a4dc6
 
 
 
 
7d7870d
39a4dc6
03a5c69
39a4dc6
03a5c69
39a4dc6
 
7d7870d
39a4dc6
 
03a5c69
39a4dc6
03a5c69
39a4dc6
 
 
03a5c69
39a4dc6
 
 
 
03a5c69
39a4dc6
03a5c69
39a4dc6
 
 
 
 
03a5c69
02fd047
 
 
 
 
 
 
 
39a4dc6
03a5c69
39a4dc6
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
# app.py - Audio & Text Sentiment Analyzer
# Transcription: openai/whisper-base.en (official HF version)
# Sentiment: nlptown/bert-base-multilingual-uncased-sentiment (5-star accurate model)

import gradio as gr
import torch
import numpy as np
import librosa
from transformers import (
    AutoProcessor,
    AutoModelForSpeechSeq2Seq,
    AutoTokenizer,
    AutoModelForSequenceClassification
)
import torch.nn.functional as F

print("Loading models... Please wait.")

# === Load Whisper exactly as requested ===
processor = AutoProcessor.from_pretrained("openai/whisper-base.en")
whisper_model = AutoModelForSpeechSeq2Seq.from_pretrained("openai/whisper-base.en")
whisper_model.eval()
device = "cuda" if torch.cuda.is_available() else "cpu"
whisper_model.to(device)

# === Load Sentiment model exactly as requested ===
sentiment_tokenizer = AutoTokenizer.from_pretrained('nlptown/bert-base-multilingual-uncased-sentiment')
sentiment_model = AutoModelForSequenceClassification.from_pretrained('nlptown/bert-base-multilingual-uncased-sentiment')
sentiment_model.eval()
sentiment_model.to(device)

print("All models loaded successfully!")

# Transcribe audio using official Whisper
def transcribe_audio(audio_path):
    if audio_path is None:
        return ""
    
    try:
        # Load and resample to 16kHz
        speech, _ = librosa.load(audio_path, sr=16000)
        
        # Process input
        input_features = processor(speech, sampling_rate=16000, return_tensors="pt").input_features
        input_features = input_features.to(device)
        
        # Generate transcription
        with torch.no_grad():
            predicted_ids = whisper_model.generate(input_features)
        
        transcription = processor.batch_decode(predicted_ids, skip_special_tokens=True)[0]
        return transcription.strip()
    
    except Exception as e:
        print(f"Transcription error: {e}")
        return "[Transcription failed]"

# Sentiment analysis with 5-star rating and confidence
def analyze_sentiment(text):
    if not text.strip():
        return "⭐⭐⭐ Neutral", "0%"
    
    inputs = sentiment_tokenizer(text[:512], return_tensors="pt", truncation=True).to(device)
    
    with torch.no_grad():
        logits = sentiment_model(**inputs).logits
    
    probabilities = F.softmax(logits, dim=-1)[0]
    predicted_class = torch.argmax(probabilities).item() + 1  # 1 to 5
    confidence = probabilities[predicted_class - 1].item() * 100
    conf_str = f"{confidence:.1f}%"
    
    stars = "⭐" * predicted_class
    if predicted_class == 1:
        level = f"{stars} Very Negative"
    elif predicted_class == 2:
        level = f"{stars} Negative"
    elif predicted_class == 3:
        level = f"{stars} Neutral"
    elif predicted_class == 4:
        level = f"{stars} Positive"
    else:
        level = f"{stars} Very Positive"
    
    return level, conf_str

# Main unified function
def analyze_input(audio_path, input_text):
    # Use typed text if provided
    if input_text and input_text.strip():
        final_text = input_text.strip()
    
    # Otherwise transcribe audio
    elif audio_path is not None:
        print("Transcribing audio...")
        final_text = transcribe_audio(audio_path)
        if not final_text or "failed" in final_text.lower():
            return "Transcription failed or no speech detected.", "", "", "Please try again with clearer English audio."
    
    else:
        return "No input provided.", "", "", "Please type text or record/upload audio."
    
    # Sentiment analysis
    level, confidence = analyze_sentiment(final_text)
    final_result = f"{level} (Confidence: {confidence})"
    
    return final_text, level, confidence, final_result

# Gradio Interface
with gr.Blocks(title="Audio & Text Sentiment Analyzer", theme=gr.themes.Soft()) as demo:
    gr.Markdown("# 🎀✍️ Audio to Text + 5-Star Sentiment Analyzer")
    gr.Markdown("""
    - **Transcription**: OpenAI Whisper-base.en (excellent English accuracy)  
    - **Sentiment**: Multilingual BERT fine-tuned on reviews β†’ accurate **1–5 star** ratings  
    - Record/upload audio **or** type text directly
    """)
    
    with gr.Row():
        with gr.Column(scale=1):
            audio_input = gr.Audio(
                sources=["microphone", "upload"],
                type="filepath",
                label="Record or Upload Audio (English recommended)"
            )
            
            gr.Markdown("**OR**")
            
            text_input = gr.Textbox(
                label="Type or Paste Text",
                placeholder="Enter your review, feedback, or transcribed text...",
                lines=6
            )
    
    btn = gr.Button("Transcribe & Analyze Sentiment", variant="primary", size="lg")
    
    with gr.Column():
        gr.Markdown("### πŸ“ Transcribed / Entered Text")
        text_display = gr.Textbox(label="Text", lines=8, interactive=False)
        
        gr.Markdown("### 🌟 Sentiment Result")
        with gr.Row():
            level_out = gr.Textbox(label="Sentiment Level", scale=2)
            conf_out = gr.Textbox(label="Confidence", scale=1)
        
        result_out = gr.Textbox(label="Final Verdict", lines=2, interactive=False)
    
    btn.click(
        fn=analyze_input,
        inputs=[audio_input, text_input],
        outputs=[text_display, level_out, conf_out, result_out]
    )
    
    # gr.Markdown("""
    # ### Notes
    # - Best performance with **clear English speech**
    # - Sentiment model excels at review-style language (opinions, experiences)
    # - Confidence >80% = very reliable prediction
    # - Runs completely locally β€” perfect for privacy
    # - Built with ❀️ in Accra by Chris (@chrisbekor99)
    # """)


# Run app
if __name__ == "__main__":
    demo.launch()