Ahmadjunaid's picture
Update app.py
ae645e8 verified
"""
app.py β€” Sentiment Analysis Demo
Deployed on Hugging Face Spaces (Gradio)
NLP Course Project β€” Dr. Rao Muhammad Adeel Nawab
"""
import gradio as gr
import torch
import re
import os
from transformers import pipeline
# ── Load model β€” tries your fine-tuned model first, falls back to public ──
HF_TOKEN = os.environ.get("HF_TOKEN", None)
MY_MODEL = "Ahmadjunaid/tweet_sentiment_distilbert"
BACKUP = "distilbert-base-uncased-finetuned-sst-2-english"
try:
classifier = pipeline(
"text-classification",
model=MY_MODEL,
token=HF_TOKEN,
device=-1,
)
print(f"βœ… Loaded custom model: {MY_MODEL}")
except Exception as e:
print(f"⚠️ Custom model failed ({e}), using backup model.")
classifier = pipeline(
"text-classification",
model=BACKUP,
device=-1,
)
# ── Tweet cleaner ──
def clean_tweet(text: str) -> str:
text = re.sub(r"http\S+|www\S+", "", text)
text = re.sub(r"@\w+", "", text)
text = re.sub(r"#(\w+)", r"\1", text)
text = re.sub(r"[^\w\s!?.,']", " ", text)
return re.sub(r"\s+", " ", text).strip()
# ── Inference ──
def predict(tweet: str):
if not tweet.strip():
return "⚠️ Please enter a tweet.", None, None
clean = clean_tweet(tweet)
result = classifier(clean)[0]
raw_label = result["label"].upper()
score = result["score"]
if raw_label in ("POSITIVE", "LABEL_1"):
label, emoji = "Positive", "😊"
pos_score, neg_score = score, 1 - score
else:
label, emoji = "Negative", "😠"
neg_score, pos_score = score, 1 - score
result_text = f"{emoji} {label} ({score*100:.1f}% confident)"
bar_data = {
"Negative 😠": round(neg_score * 100, 1),
"Positive 😊": round(pos_score * 100, 1),
}
return result_text, bar_data, f'"{clean}"'
EXAMPLES = [
["I absolutely love this new phone, it changed my life!"],
["This is the worst customer service I have ever experienced."],
["Just had coffee. Today feels like a normal day."],
["Can't believe how amazing the concert was last night!"],
["My flight got cancelled and I missed the meeting. Terrible."],
]
CSS = """
@import url('https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;600;700&display=swap');
body, .gradio-container { background: #0D1B2A !important; font-family: 'Space Grotesk', sans-serif !important; }
#header-block { background: linear-gradient(135deg, #1565C0 0%, #0D47A1 50%, #00ACC1 100%); border-radius: 16px; padding: 32px 40px; margin-bottom: 24px; text-align: center; }
#header-block h1 { font-size: 2.2rem !important; font-weight: 700; color: #fff; margin: 0 0 6px 0; }
#header-block p { color: #B3E5FC; font-size: 0.95rem; margin: 4px 0 0 0; }
label { color: #90CAF9 !important; font-weight: 600 !important; font-size: 0.85rem !important; text-transform: uppercase !important; }
.footer-note { text-align: center; color: #455A6A; font-size: 0.8rem; margin-top: 16px; }
"""
with gr.Blocks(css=CSS, title="Tweet Sentiment Analysis") as demo:
gr.HTML("""
<div id="header-block">
<h1>🐦 Tweet Sentiment Analysis</h1>
<p>Fine-tuned DistilBERT &middot; Trained on 10,000 English Tweets &middot; F1 = 0.85</p>
<p style="color:#80DEEA; font-size:0.82rem;">NLP Course Project &middot; Dr. Rao Muhammad Adeel Nawab</p>
</div>
""")
with gr.Row():
with gr.Column(scale=3):
tweet_input = gr.Textbox(label="Enter a Tweet", placeholder="e.g. I love this! It completely changed my day πŸŽ‰", lines=3)
with gr.Row():
submit_btn = gr.Button("Analyse Sentiment β†’", variant="primary")
clear_btn = gr.Button("Clear", variant="secondary")
gr.Examples(examples=EXAMPLES, inputs=tweet_input, label="Try an Example")
with gr.Column(scale=2):
result_out = gr.Textbox(label="Prediction")
bar_out = gr.Json(label="Confidence Scores (%)")
cleaned_out = gr.Textbox(label="Cleaned Input", lines=2)
gr.HTML('<div class="footer-note">Model: DistilBERT &middot; Dataset: Sentiment140 &middot; Split: 80/20</div>')
submit_btn.click(fn=predict, inputs=tweet_input, outputs=[result_out, bar_out, cleaned_out])
clear_btn.click(lambda: ("", None, ""), outputs=[result_out, bar_out, cleaned_out])
tweet_input.submit(fn=predict, inputs=tweet_input, outputs=[result_out, bar_out, cleaned_out])
demo.launch()