Spaces:
Sleeping
Sleeping
| import gradio as gr | |
| from transformers import pipeline | |
| from datetime import datetime | |
| import matplotlib.pyplot as plt | |
| import io | |
| import base64 | |
| from langdetect import detect | |
| import qrcode | |
| from wordcloud import WordCloud | |
| import nltk | |
| from nltk.tokenize import sent_tokenize | |
| from better_profanity import profanity | |
| import tempfile | |
| import os | |
| from PIL import Image # For PIL image handling | |
| # Download NLTK data | |
| nltk.download('punkt', quiet=True) | |
| nltk.download('punkt_tab', quiet=True) | |
| # Model options | |
| models = { | |
| "DistilBERT": "distilbert-base-uncased-finetuned-sst-2-english", | |
| "Twitter RoBERTa": "cardiffnlp/twitter-roberta-base-sentiment-latest" | |
| } | |
| analyzer = None | |
| history = [] | |
| sentiment_scores = [] | |
| feedback_log = [] | |
| # Load the selected or custom model | |
| def load_model(model_name, custom_model_path=None): | |
| global analyzer | |
| if custom_model_path: | |
| analyzer = pipeline("sentiment-analysis", model=custom_model_path) | |
| return f"Loaded custom model from {custom_model_path}" | |
| analyzer = pipeline("sentiment-analysis", model=models[model_name]) | |
| return f"Loaded {model_name} model." | |
| # Highlight words | |
| def highlight_words(text, sentiment, pos_words, neg_words): | |
| words = text.split() | |
| highlighted = [] | |
| pos_list = pos_words.split(",") if pos_words else ["love", "great", "happy", "awesome", "good"] | |
| neg_list = neg_words.split(",") if neg_words else ["hate", "bad", "terrible", "awful", "sad"] | |
| for word in words: | |
| if sentiment == "POSITIVE" and word.lower() in [w.strip().lower() for w in pos_list]: | |
| highlighted.append(f"**{word}**") | |
| elif sentiment == "NEGATIVE" and word.lower() in [w.strip().lower() for w in neg_list]: | |
| highlighted.append(f"**{word}**") | |
| else: | |
| highlighted.append(word) | |
| return " ".join(highlighted) | |
| # Sentiment analysis with context | |
| def analyze_sentiment(text, model_name, pos_words, neg_words, intensity, custom_model_path=None, source="manual", compare_text=None): | |
| if not text or not text.strip(): | |
| return "Error: Please enter some text.", "", "", None, None, "", None, "" | |
| try: | |
| if analyzer is None: | |
| load_model(model_name, custom_model_path) | |
| # Language and profanity check | |
| lang = detect(text) | |
| lang_note = " (Warning: Text may not be in English)" if lang != "en" else "" | |
| profanity_note = " (Warning: Inappropriate language detected)" if profanity.contains_profanity(text) else "" | |
| # Contextual analysis | |
| sentences = sent_tokenize(text) | |
| results = [] | |
| for sent in sentences: | |
| result = analyzer(sent)[0] | |
| label, score = result['label'], result['score'] | |
| if score < intensity: | |
| label = "NEUTRAL" | |
| results.append(f"{sent} -> {label} ({score:.2f})") | |
| combined_result = analyzer(text)[0] | |
| label, score = combined_result['label'], combined_result['score'] | |
| if score < intensity: | |
| label, emoji = "NEUTRAL", "😐" | |
| else: | |
| emoji = "😊" if "POSITIVE" in label.upper() else "😞" if "NEGATIVE" in label.upper() else "😐" | |
| confidence_note = " (Low confidence)" if score < 0.7 else "" | |
| sentiment_result = f"Overall: {label} {emoji} (Confidence: {score:.2f}{confidence_note}{lang_note}{profanity_note})\n" + "\n".join(results) | |
| highlighted_text = highlight_words(text, label, pos_words, neg_words) | |
| # History and scores | |
| timestamp = datetime.now().strftime('%H:%M:%S') | |
| history.append(f"[{timestamp}] {source}: {text} -> {sentiment_result.splitlines()[0]}") | |
| sentiment_scores.append((timestamp, 1 if "POSITIVE" in label.upper() else -1 if "NEGATIVE" in label.upper() else 0)) | |
| history_str = "\n".join([h for h in history[-5:]]) | |
| # Visuals | |
| trend_img = generate_timeline() | |
| wordcloud_img = generate_wordcloud(text) | |
| qr_img = generate_qr(f"https://example.com/share?text={text}&result={sentiment_result.splitlines()[0].replace(' ', '+')}") | |
| # Comparative analysis | |
| compare_result = "" | |
| if compare_text: | |
| comp_result = analyzer(compare_text)[0] | |
| comp_label, comp_score = comp_result['label'], comp_result['score'] | |
| comp_emoji = "😊" if "POSITIVE" in comp_label.upper() else "😞" if "NEGATIVE" in comp_label.upper() else "😐" | |
| compare_result = f"Comparison: {comp_label} {comp_emoji} (Confidence: {comp_score:.2f})" | |
| return sentiment_result, highlighted_text, history_str, trend_img, wordcloud_img, qr_img, compare_result, "" | |
| except Exception as e: | |
| print(e) | |
| return f"Error: {str(e)}", "", "", None, None, "", "", "" | |
| # Fetch X post (simulated) | |
| def fetch_x_post(x_url, model_name, pos_words, neg_words, intensity, custom_model_path): | |
| sample_text = "Sample X post from " + x_url | |
| return analyze_sentiment(sample_text, model_name, pos_words, neg_words, intensity, custom_model_path, source="X post") | |
| # Generate timeline (return PIL Image) | |
| def generate_timeline(): | |
| if not sentiment_scores: | |
| return None | |
| times, scores = zip(*sentiment_scores[-10:]) | |
| plt.figure(figsize=(6, 3)) | |
| plt.plot(times, scores, marker='o', linestyle='-', color='b') | |
| plt.title("Sentiment Timeline") | |
| plt.xlabel("Time") | |
| plt.ylabel("Sentiment") | |
| plt.ylim(-1.5, 1.5) | |
| plt.xticks(rotation=45) | |
| plt.tight_layout() | |
| buf = io.BytesIO() | |
| plt.savefig(buf, format="png") | |
| buf.seek(0) | |
| img = Image.open(buf) # Standard PIL Image | |
| plt.close() | |
| return img | |
| # Generate word cloud (return PIL Image) | |
| def generate_wordcloud(text): | |
| wordcloud = WordCloud(width=400, height=200, background_color="white").generate(text) | |
| return wordcloud.to_image() # Standard PIL Image | |
| # Generate QR code (return standard PIL Image) | |
| def generate_qr(url): | |
| qr = qrcode.QRCode(version=1, box_size=10, border=4) | |
| qr.add_data(url) | |
| qr.make(fit=True) | |
| qr_img = qr.make_image(fill="black", back_color="white") # Returns qrcode.image.pil.PilImage | |
| buf = io.BytesIO() | |
| qr_img.save(buf, format="PNG") | |
| buf.seek(0) | |
| return Image.open(buf) # Convert to standard PIL Image | |
| # Export history with proper file handling | |
| def export_history(): | |
| if not history: | |
| return None | |
| with tempfile.NamedTemporaryFile(delete=False, suffix=".txt", mode="w") as temp_file: | |
| temp_file.write("\n".join(history)) | |
| temp_path = temp_file.name | |
| return temp_path | |
| # Log feedback | |
| def log_feedback(rating): | |
| feedback_log.append(f"[{datetime.now().strftime('%H:%M:%S')}] Rating: {rating}/5") | |
| return f"Feedback received! ({len(feedback_log)} total)" | |
| # Theme toggle function | |
| def toggle_theme(light_mode): | |
| return "Theme switched to " + ("Light" if light_mode else "Dark") + ". Please refresh the page to apply." | |
| # Gradio interface | |
| with gr.Blocks(theme=gr.themes.Monochrome()) as interface: | |
| gr.Markdown("# Sentify") | |
| gr.Markdown("Next-level sentiment analysis with context, comparison, and more!") | |
| with gr.Row(): | |
| with gr.Column(scale=2): | |
| model_dropdown = gr.Dropdown(choices=list(models.keys()), label="Select Model", value="DistilBERT") | |
| custom_model = gr.File(label="Upload Custom Model (optional)", file_types=[".bin", ".pt"]) | |
| text_input = gr.Textbox(label="Enter text or X URL", placeholder="Type text or paste an X URL...") | |
| compare_input = gr.Textbox(label="Compare with (optional)", placeholder="Enter second text...") | |
| audio_input = gr.Audio(label="Or Speak Your Text", type="filepath") | |
| pos_words = gr.Textbox(label="Custom Positive Words", placeholder="love, great") | |
| neg_words = gr.Textbox(label="Custom Negative Words", placeholder="hate, bad") | |
| intensity_slider = gr.Slider(0.5, 1.0, value=0.7, label="Sentiment Intensity Threshold") | |
| x_button = gr.Button("Analyze X Post") | |
| with gr.Column(scale=3): | |
| sentiment_output = gr.Textbox(label="Sentiment Result (Contextual)") | |
| highlighted_output = gr.Textbox(label="Highlighted Text") | |
| history_output = gr.Textbox(label="Analysis History (Last 5)", lines=5) | |
| trend_output = gr.Image(label="Sentiment Timeline") | |
| wordcloud_output = gr.Image(label="Word Cloud") | |
| qr_output = gr.Image(label="Shareable QR Code") | |
| compare_output = gr.Textbox(label="Comparative Analysis") | |
| with gr.Row(): | |
| export_button = gr.Button("Export History") | |
| export_file = gr.File(label="Download History") | |
| theme_toggle = gr.Checkbox(label="Light Mode", value=False) | |
| theme_status = gr.Textbox(label="Theme Status", value="Dark (default)") | |
| feedback_slider = gr.Slider(1, 5, step=1, label="Rate this analysis (1-5)") | |
| feedback_output = gr.Textbox(label="Feedback Status") | |
| gr.Examples( | |
| examples=["I love this app! It’s great.", "This is awful and sad.", "https://x.com/sample/post"], | |
| inputs=[text_input] | |
| ) | |
| # Event handlers | |
| def audio_to_text(audio_file, model_name, pos_words, neg_words, intensity, custom_model_path): | |
| text = "Simulated speech: I feel great today" if audio_file else "" | |
| return analyze_sentiment(text, model_name, pos_words, neg_words, intensity, custom_model_path, source="audio") | |
| text_input.change( | |
| fn=analyze_sentiment, | |
| inputs=[text_input, model_dropdown, pos_words, neg_words, intensity_slider, custom_model], | |
| outputs=[sentiment_output, highlighted_output, history_output, trend_output, wordcloud_output, qr_output, compare_output, feedback_output] | |
| ) | |
| x_button.click( | |
| fn=fetch_x_post, | |
| inputs=[text_input, model_dropdown, pos_words, neg_words, intensity_slider, custom_model], | |
| outputs=[sentiment_output, highlighted_output, history_output, trend_output, wordcloud_output, qr_output, compare_output, feedback_output] | |
| ) | |
| audio_input.change( | |
| fn=audio_to_text, | |
| inputs=[audio_input, model_dropdown, pos_words, neg_words, intensity_slider, custom_model], | |
| outputs=[sentiment_output, highlighted_output, history_output, trend_output, wordcloud_output, qr_output, compare_output, feedback_output] | |
| ) | |
| export_button.click(fn=export_history, inputs=None, outputs=export_file) | |
| theme_toggle.change(fn=toggle_theme, inputs=theme_toggle, outputs=theme_status) | |
| feedback_slider.change(fn=log_feedback, inputs=feedback_slider, outputs=feedback_output) | |
| # Launch the app | |
| interface.launch() |