| """ |
| 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 |
|
|
| |
| 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, |
| ) |
|
|
| |
| 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() |
|
|
| |
| 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 · Trained on 10,000 English Tweets · F1 = 0.85</p> |
| <p style="color:#80DEEA; font-size:0.82rem;">NLP Course Project · 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 · Dataset: Sentiment140 · 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() |