Distilbert_multiLLM / src /streamlit_app.py
shivam-1706's picture
Update src/streamlit_app.py
24db65a verified
import streamlit as st
import torch
from transformers import pipeline, AutoTokenizer, AutoModelForSequenceClassification
from openai import OpenAI
import re
# --- Page configuration ---
st.set_page_config(
page_title="Sentiment Analyzer",
page_icon="🎭",
layout="wide"
)
# --- App Header ---
st.title("🎭 Sentiment Analysis with AI Responses")
st.markdown("**5-Class Amazon Review Sentiment Analysis + AI-Generated Customer Support Responses**")
st.markdown("*Powered by GPT4.0 mini*")
st.markdown("---")
# --- API Key and Model Setup ---
GITHUB_TOKEN = "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"
@st.cache_resource
def load_llm_client():
try:
return OpenAI(
api_key=GITHUB_TOKEN,
base_url="https://models.inference.ai.azure.com/"
)
except Exception as e:
st.error(f"Failed to initialize LLM client: {str(e)}")
return None
@st.cache_resource
def load_sentiment_model():
try:
model_name = "shivam-1706/distilbert-amazon-sentiment"
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoModelForSequenceClassification.from_pretrained(model_name)
if model.config.num_labels == 5:
st.success("βœ… 5-class sentiment model loaded successfully!")
else:
st.warning(f"⚠️ Model has {model.config.num_labels} classes, expected 5")
return pipeline(
"text-classification",
model=model,
tokenizer=tokenizer,
return_all_scores=True,
device=0 if torch.cuda.is_available() else -1
)
except Exception as e:
st.error(f"Error loading custom model: {str(e)}")
st.warning("⚠️ Using fallback model - this will only show 3 classes")
return pipeline(
"text-classification",
model="cardiffnlp/twitter-roberta-base-sentiment-latest",
return_all_scores=True
)
with st.spinner("Loading DistilBERT model..."):
sentiment_pipeline = load_sentiment_model()
llm_client = load_llm_client()
if llm_client:
st.success("βœ… GPT4.0 mini connected automatically!")
# --- Helper functions ---
def fix_problematic_words(text):
fixes = {
'phenomenal': 'absolutely amazing excellent outstanding incredible wonderful',
'fabulous': 'excellent amazing wonderful fantastic great',
'superb': 'excellent outstanding amazing great wonderful',
'marvelous': 'amazing excellent wonderful fantastic outstanding',
'spectacular': 'outstanding excellent amazing incredible wonderful',
'divine': 'absolutely perfect excellent amazing wonderful',
'sublime': 'excellent amazing wonderful outstanding perfect',
'magnificent': 'excellent outstanding amazing wonderful great',
'exceptional': 'outstanding excellent amazing wonderful great',
'extraordinary': 'amazing excellent outstanding incredible wonderful',
'brilliant': 'excellent amazing outstanding great',
'fantastic': 'excellent amazing wonderful great',
'incredible': 'amazing excellent outstanding wonderful',
'outstanding': 'excellent amazing great wonderful',
'remarkable': 'excellent amazing outstanding wonderful',
'horrendous': 'absolutely terrible awful horrible disgusting',
'dreadful': 'terrible awful horrible bad disgusting',
'atrocious': 'extremely terrible awful horrible disgusting',
'abysmal': 'terrible awful horrible bad disgusting',
'deplorable': 'terrible awful horrible bad',
'appalling': 'extremely terrible awful horrible',
'horrid': 'terrible awful horrible bad',
'ghastly': 'terrible awful horrible disgusting',
'abominable': 'terrible awful horrible disgusting',
'despicable': 'terrible awful horrible bad'
}
text_fixed = text
for word, replacement in fixes.items():
text_fixed = re.sub(rf'\b{word}\b', replacement, text_fixed, flags=re.IGNORECASE)
return text_fixed
def predict_sentiment_enhanced(text):
if not text.strip():
return "Average", 0.20, {
'Very Bad': 0.10, 'Bad': 0.15, 'Average': 0.50, 'Good': 0.15, 'Very Good': 0.10
}
try:
results = sentiment_pipeline(fix_problematic_words(text))
if isinstance(results[0], list):
results = results[0]
label_map = {
'LABEL_0': 'Very Bad',
'LABEL_1': 'Bad',
'LABEL_2': 'Average',
'LABEL_3': 'Good',
'LABEL_4': 'Very Good'
}
if len(results) == 5:
best_result = max(results, key=lambda x: x['score'])
sentiment = label_map.get(best_result['label'], best_result['label'])
confidence = best_result['score']
all_scores = {label_map.get(r['label'], r['label']): r['score'] for r in results}
return sentiment, confidence, all_scores
else:
fallback_map = {'NEGATIVE': 'Bad', 'NEUTRAL': 'Average', 'POSITIVE': 'Good'}
best_result = max(results, key=lambda x: x['score'])
sentiment = fallback_map.get(best_result['label'], 'Average')
confidence = best_result['score']
all_scores = {'Very Bad': 0.0, 'Bad': 0.0, 'Average': 0.0, 'Good': 0.0, 'Very Good': 0.0}
all_scores[sentiment] = confidence
return sentiment, confidence, all_scores
except Exception as e:
st.error(f"Error in prediction: {str(e)}")
return "Average", 0.5, {'Average': 0.5}
def generate_llm_response(review_text, sentiment):
if not llm_client:
return "❌ GitHub Models API not available. Please check your API key."
prompts = {
'Very Bad': f"""You are a professional customer service manager. A customer left this review: "{review_text}"...
Their sentiment is very negative. Provide a response that:
1. Shows empathy
2. Offers resolution (refund/replacement)
3. Provides next steps
Response:""",
'Bad': f"""You are a customer service rep. Customer said: "{review_text}"...
Their experience was bad. Acknowledge & offer help. Response:""",
'Average': f"""Respond to a mixed review: "{review_text}"...
Thank, acknowledge, offer help, ask for suggestions. Response:""",
'Good': f"""Customer left a positive review: "{review_text}"...
Thank them and reinforce quality. Response:""",
'Very Good': f"""Delighted customer wrote: "{review_text}"...
Celebrate, thank, and invite sharing. Response:"""
}
try:
response = llm_client.chat.completions.create(
model="gpt-4o-mini",
messages=[{"role": "user", "content": prompts.get(sentiment)}],
max_tokens=150,
temperature=0.7
)
return response.choices[0].message.content.strip()
except Exception:
fallback = {
'Very Bad': "We’re truly sorry for your experience. Please reach out so we can make this right.",
'Bad': "Thanks for your feedback. We’d like to help resolve your concern.",
'Average': "Thanks for your honest review. We're listening and happy to improve.",
'Good': "Thank you for your kind words! We appreciate your support.",
'Very Good': "We’re thrilled you loved it! Thanks for your amazing review."
}
return fallback.get(sentiment, "Thank you for your feedback!")
# --- App Interface ---
col1, col2 = st.columns([2, 1])
with col1:
st.subheader("πŸ“ Enter Product Review")
review_text = st.text_area(
"Type or paste a product review here:",
height=150,
placeholder="Example: This product broke after just two days of use. Very disappointed with the quality and delivery was delayed too."
)
analyze_button = st.button("πŸ” Analyze & Generate Response", type="primary")
if analyze_button and not review_text.strip():
st.warning("⚠️ Please enter a review to analyze!")
if analyze_button and review_text.strip():
sentiment, confidence, all_scores = predict_sentiment_enhanced(review_text)
with col2:
st.subheader("πŸ“Š Analysis Results")
color_map = {
'Very Good': 'green',
'Good': 'blue',
'Average': 'orange',
'Bad': 'red',
'Very Bad': 'violet'
}
emoji_map = {
'Very Bad': '😑',
'Bad': '😞',
'Average': '😐',
'Good': '😊',
'Very Good': '🀩'
}
color = color_map.get(sentiment, 'blue')
emoji = emoji_map.get(sentiment, '😐')
st.markdown(f"**Sentiment:** :{color}[{sentiment}] {emoji}")
st.progress(confidence)
st.caption(f"Confidence: {confidence:.2%}")
st.subheader("🎯 All 5 Class Predictions")
class_order = ['Very Bad', 'Bad', 'Average', 'Good', 'Very Good']
for class_name in class_order:
score = all_scores.get(class_name, 0.0)
st.write(f"{emoji_map.get(class_name)} {class_name}: {score:.1%}")
with col1:
st.markdown("---")
with st.spinner("Generating AI response..."):
ai_response = generate_llm_response(review_text, sentiment)
st.subheader("πŸ€– AI Customer Support Response")
st.info(ai_response)
strategies = {
'Very Bad': "πŸ†˜ Crisis Management: Immediate resolution",
'Bad': "πŸ”§ Problem Resolution: Solutions & improvements",
'Average': "βš–οΈ Balanced: Acknowledge & enhance",
'Good': "πŸ‘ Appreciation: Maintain quality",
'Very Good': "πŸŽ‰ Celebration: Encourage sharing"
}
st.caption(f"**Strategy:** {strategies.get(sentiment)}")