MaroofTechSorcerer's picture
Rename app3.py to app.py
8a9eb02 verified
raw
history blame
7.32 kB
import os
import streamlit as st
import tempfile
import whisper
from transformers import pipeline
import plotly.express as px
import torch
import logging
import warnings
import shutil
# Suppress warnings for a clean console
logging.getLogger("torch").setLevel(logging.CRITICAL)
logging.getLogger("transformers").setLevel(logging.CRITICAL)
warnings.filterwarnings("ignore")
os.environ["TOKENIZERS_PARALLELISM"] = "false"
torch.device("cpu")
# Set Streamlit app layout
st.set_page_config(layout="wide", page_title="Voice Based Sentiment Analysis")
# Interface design
st.title("πŸŽ™οΈ Voice Based Sentiment Analysis")
st.write("Detect emotions, sentiment, and sarcasm from your voice with high accuracy.")
# Sidebar for file upload
st.sidebar.title("Audio Input")
st.sidebar.write("Upload a WAV file for transcription and detailed analysis.")
audio_file = st.sidebar.file_uploader("Choose an audio file", type=["wav"], help="Supports WAV format only.")
upload_button = st.sidebar.button("Analyze", help="Click to process the uploaded audio.")
# Check if FFmpeg is available
def check_ffmpeg():
return shutil.which("ffmpeg") is not None
# Emotion Detection Function
@st.cache_resource
def get_emotion_classifier():
emotion_model = "bhadresh-savani/distilbert-base-uncased-emotion"
return pipeline("text-classification", model=emotion_model, top_k=None, device=-1)
def perform_emotion_detection(text):
try:
emotion_classifier = get_emotion_classifier()
emotion_results = emotion_classifier(text)[0]
emotion_map = {"anger": "😑", "fear": "😨", "joy": "😊", "love": "❀️", "sadness": "😒", "surprise": "😲"}
emotions_dict = {result['label']: result['score'] for result in emotion_results}
top_emotion = max(emotions_dict, key=emotions_dict.get)
sentiment_map = {"joy": "POSITIVE", "love": "POSITIVE", "anger": "NEGATIVE", "fear": "NEGATIVE", "sadness": "NEGATIVE", "surprise": "NEUTRAL"}
sentiment = sentiment_map.get(top_emotion, "NEUTRAL")
return emotions_dict, top_emotion, emotion_map, sentiment
except Exception as e:
st.error(f"Emotion detection failed: {str(e)}")
return {}, "unknown", {}, "UNKNOWN"
# Sarcasm Detection Function
@st.cache_resource
def get_sarcasm_classifier():
sarcasm_model = "cardiffnlp/twitter-roberta-base-irony"
return pipeline("text-classification", model=sarcasm_model, device=-1)
def perform_sarcasm_detection(text):
try:
sarcasm_classifier = get_sarcasm_classifier()
result = sarcasm_classifier(text)[0]
is_sarcastic = result['label'] == "LABEL_1"
sarcasm_score = result['score'] if is_sarcastic else 1 - result['score']
return is_sarcastic, sarcasm_score
except Exception as e:
st.error(f"Sarcasm detection failed: {str(e)}")
return False, 0.0
# Transcription Function with Whisper
@st.cache_resource
def get_whisper_model():
return whisper.load_model("base")
def transcribe_audio(audio_file):
if not check_ffmpeg():
st.error("FFmpeg is not installed or not found in PATH. Please install FFmpeg and add it to your system PATH.")
st.markdown("**Instructions to install FFmpeg on Windows:**\n"
"1. Download FFmpeg from [https://www.gyan.dev/ffmpeg/builds/](https://www.gyan.dev/ffmpeg/builds/) (e.g., `ffmpeg-release-essentials.zip`).\n"
"2. Extract the ZIP to a folder (e.g., `C:\\ffmpeg`).\n"
"3. Add `C:\\ffmpeg\\bin` to your system PATH:\n"
" - Right-click 'This PC' > 'Properties' > 'Advanced system settings' > 'Environment Variables'.\n"
" - Under 'System variables', edit 'Path' and add the new path.\n"
"4. Restart your terminal and rerun the app.")
return ""
try:
model = get_whisper_model()
# Save uploaded file to a temporary location
temp_dir = tempfile.gettempdir()
temp_file_path = os.path.join(temp_dir, "temp_audio.wav")
with open(temp_file_path, "wb") as f:
f.write(audio_file.getvalue())
# Verify file exists
if not os.path.exists(temp_file_path):
st.error(f"Temporary file not created at {temp_file_path}. Check write permissions.")
return ""
# Transcribe using Whisper
result = model.transcribe(temp_file_path)
# Clean up temporary file
if os.path.exists(temp_file_path):
os.remove(temp_file_path)
return result["text"]
except Exception as e:
st.error(f"Transcription failed: {str(e)}")
return ""
# Main App Logic
def main():
if audio_file and upload_button:
st.audio(audio_file.getvalue(), format='audio/wav')
st.caption("🎧 Uploaded Audio Playback")
with st.spinner('Analyzing audio with advanced precision...'):
transcribed_text = transcribe_audio(audio_file)
if not transcribed_text:
return
emotions_dict, top_emotion, emotion_map, sentiment = perform_emotion_detection(transcribed_text)
is_sarcastic, sarcasm_score = perform_sarcasm_detection(transcribed_text)
st.header("Transcribed Text")
st.text_area("Text", transcribed_text, height=150, disabled=True, help="The audio converted to text.")
st.header("Analysis Results")
col1, col2 = st.columns([1, 2])
with col1:
st.subheader("Sentiment")
sentiment_icon = "πŸ‘" if sentiment == "POSITIVE" else "πŸ‘Ž" if sentiment == "NEGATIVE" else "😐"
st.markdown(f"**{sentiment_icon} {sentiment.capitalize()}** (Based on {top_emotion})")
st.info("Sentiment reflects the dominant emotion’s tone.")
st.subheader("Sarcasm")
sarcasm_icon = "😏" if is_sarcastic else "😐"
sarcasm_text = "Detected" if is_sarcastic else "Not Detected"
st.markdown(f"**{sarcasm_icon} {sarcasm_text}** (Score: {sarcasm_score:.3f})")
st.info("Score indicates sarcasm confidence (0 to 1).")
with col2:
st.subheader("Emotions")
if emotions_dict:
st.markdown(f"**Dominant:** {emotion_map.get(top_emotion, '❓')} {top_emotion.capitalize()} (Score: {emotions_dict[top_emotion]:.3f})")
sorted_emotions = sorted(emotions_dict.items(), key=lambda x: x[1], reverse=True)
emotions = [e[0] for e in sorted_emotions]
scores = [e[1] for e in sorted_emotions]
fig = px.bar(x=emotions, y=scores, labels={'x': 'Emotion', 'y': 'Score'},
title="Emotion Distribution", color=emotions,
color_discrete_sequence=px.colors.qualitative.Pastel1)
fig.update_layout(yaxis_range=[0, 1], showlegend=False, title_font_size=14)
st.plotly_chart(fig, use_container_width=True)
else:
st.write("No emotions detected.")
st.info("Emotions drive sentiment here. Sarcasm is analyzed separately for accuracy.")
elif upload_button and not audio_file:
st.sidebar.error("Please upload an audio file first!")
if __name__ == "__main__":
main()