Spaces:
Sleeping
Sleeping
| # app.py - Audio & Text Sentiment Analyzer | |
| # Uses exact model: google-bert/bert-base-uncased (Masked LM) | |
| # Runs locally with Gradio interface | |
| import gradio as gr | |
| import whisper | |
| import torch | |
| import numpy as np | |
| from transformers import AutoTokenizer, AutoModelForMaskedLM | |
| from sklearn.linear_model import LogisticRegression | |
| from sklearn.preprocessing import StandardScaler | |
| print("Loading models... This may take a moment.") | |
| # Load Whisper for audio transcription | |
| whisper_model = whisper.load_model("base") # Fast and works well; use "small" for better accuracy | |
| # Load exact requested BERT model | |
| tokenizer = AutoTokenizer.from_pretrained("google-bert/bert-base-uncased") | |
| model = AutoModelForMaskedLM.from_pretrained("google-bert/bert-base-uncased") | |
| model.eval() | |
| print("Models loaded successfully!") | |
| # Function to get [CLS] embedding | |
| def get_cls_embedding(text): | |
| inputs = tokenizer(text[:512], return_tensors="pt", truncation=True, padding=True) | |
| with torch.no_grad(): | |
| outputs = model(**inputs, output_hidden_states=True) | |
| cls_embedding = outputs.hidden_states[-1][:, 0, :].cpu().numpy() | |
| return cls_embedding.flatten() | |
| # Training examples for simple sentiment classifier | |
| example_texts = [ | |
| "I love this, it's absolutely amazing", "Best thing ever", "Fantastic experience", | |
| "Highly recommend", "Super happy with it", "This is terrible", "Worst product ever", | |
| "Very disappointed", "Complete waste", "Poor quality", "It's okay", "Nothing special", | |
| "Arrived on time", "Works as expected", "Average" | |
| ] | |
| example_labels = [1,1,1,1,1, -1,-1,-1,-1,-1, 0,0,0,0,0] # 1=Positive, -1=Negative, 0=Neutral | |
| # Train classifier | |
| X_train = np.array([get_cls_embedding(t) for t in example_texts]) | |
| y_train = np.array(example_labels) | |
| scaler = StandardScaler() | |
| X_train_scaled = scaler.fit_transform(X_train) | |
| clf = LogisticRegression(multi_class='ovr', class_weight='balanced') | |
| clf.fit(X_train_scaled, y_train) | |
| print("Sentiment classifier trained!") | |
| # Predict sentiment with stars and confidence | |
| def predict_sentiment(text): | |
| if not text.strip(): | |
| return "βββ Neutral", "0%" | |
| embedding = get_cls_embedding(text) | |
| embedding_scaled = scaler.transform([embedding]) | |
| probabilities = clf.predict_proba(embedding_scaled)[0] | |
| pred = clf.predict(embedding_scaled)[0] | |
| confidence = np.max(probabilities) * 100 | |
| conf_str = f"{confidence:.1f}%" | |
| if pred == 1: | |
| level = "βββββ Very Positive" | |
| elif pred == -1: | |
| level = "β Very Negative" | |
| else: | |
| level = "βββ Neutral" | |
| return level, conf_str | |
| # Main analysis function | |
| def analyze_input(audio_path, input_text): | |
| # Prefer 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: | |
| try: | |
| print("Transcribing audio...") | |
| result = whisper_model.transcribe(audio_path) | |
| final_text = result["text"].strip() | |
| if not final_text: | |
| return "No speech detected in the audio.", "", "", "Please speak clearly and try again." | |
| except Exception as e: | |
| return "Error transcribing audio.", "", "", f"Error: {str(e)}" | |
| else: | |
| return "No input provided.", "", "", "Please type text or record/upload audio." | |
| # Perform sentiment analysis | |
| level, confidence = predict_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 + Sentiment Analyzer") | |
| gr.Markdown(""" | |
| - Record or upload audio β **Automatically transcribed** | |
| - Or type text directly | |
| - Analyzes sentiment using **google-bert/bert-base-uncased** ([CLS] embedding) | |
| """) | |
| with gr.Row(): | |
| with gr.Column(scale=1): | |
| audio_input = gr.Audio( | |
| sources=["microphone", "upload"], | |
| type="filepath", | |
| label="Record or Upload Audio" | |
| ) | |
| gr.Markdown("**OR**") | |
| text_input = gr.Textbox( | |
| label="Type or Paste Text", | |
| placeholder="Enter your review or feedback here...", | |
| 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 | |
| - Works with any language (Whisper handles transcription) | |
| - Uses raw BERT base model β educational demo | |
| - Run locally, no data leaves your machine | |
| - Made with β€οΈ in Accra by Chris (@chrisbekor99) | |
| """) | |
| # Run app | |
| if __name__ == "__main__": | |
| demo.launch() |