Spaces:
Sleeping
Sleeping
| import gradio as gr | |
| import numpy as np | |
| import logging | |
| from collections import Counter | |
| from config import config | |
| from analyzer import SentimentEngine | |
| from visualizer import PlotFactory, ThemeContext | |
| from utils import HistoryManager, DataHandler, handle_errors, managed_figure | |
| class SentimentApp: | |
| """Main application orchestrator""" | |
| def __init__(self): | |
| self.engine = SentimentEngine() | |
| self.history = HistoryManager() | |
| self.data_handler = DataHandler() | |
| self.examples = [ | |
| ["While the film's visual effects were undeniably impressive, the story lacked emotional weight, and the pacing felt inconsistent throughout."], | |
| ["An extraordinary achievement in filmmaking — the direction was masterful, the script was sharp, and every performance added depth and realism."], | |
| ["Despite a promising start, the film quickly devolved into a series of clichés, with weak character development and an ending that felt rushed and unearned."], | |
| ["A beautifully crafted story with heartfelt moments and a soundtrack that perfectly captured the emotional tone of each scene."], | |
| ["The movie was far too long, with unnecessary subplots and dull dialogue that made it difficult to stay engaged until the end."] | |
| ] | |
| def analyze_single_fast(self, text: str, theme: str = 'default'): | |
| """Fast single text analysis without keywords""" | |
| if not text.strip(): | |
| return "Please enter text", None, None, None | |
| result = self.engine.analyze_single_fast(text) | |
| self.history.add({ | |
| 'text': text[:100], | |
| 'full_text': text, | |
| **result | |
| }) | |
| theme_ctx = ThemeContext(theme) | |
| probs = np.array([result['neg_prob'], result['pos_prob']]) | |
| prob_plot = PlotFactory.create_sentiment_bars(probs, theme_ctx) | |
| gauge_plot = PlotFactory.create_confidence_gauge(result['confidence'], result['sentiment'], theme_ctx) | |
| cloud_plot = PlotFactory.create_wordcloud(text, result['sentiment'], theme_ctx) | |
| result_text = f"Sentiment: {result['sentiment']} (Confidence: {result['confidence']:.3f})" | |
| return result_text, prob_plot, gauge_plot, cloud_plot | |
| def analyze_single_advanced(self, text: str, theme: str = 'default'): | |
| """Advanced single text analysis with LIME and SHAP explanation""" | |
| if not text.strip(): | |
| return "Please enter text", None, None, None | |
| result = self.engine.analyze_single_advanced(text) | |
| self.history.add({ | |
| 'text': text[:100], | |
| 'full_text': text, | |
| **result | |
| }) | |
| theme_ctx = ThemeContext(theme) | |
| lime_plot = PlotFactory.create_lime_keyword_chart(result['lime_words'], result['sentiment'], theme_ctx) | |
| shap_plot = PlotFactory.create_shap_keyword_chart(result['shap_words'], result['sentiment'], theme_ctx) | |
| lime_words_str = ", ".join([f"{word}({score:.3f})" for word, score in result['lime_words'][:5]]) | |
| shap_words_str = ", ".join([f"{word}({score:.3f})" for word, score in result['shap_words'][:5]]) | |
| result_text = (f"Sentiment: {result['sentiment']} (Confidence: {result['confidence']:.3f})\n" | |
| f"LIME Key Words: {lime_words_str}\n" | |
| f"SHAP Key Words: {shap_words_str}") | |
| return result_text, lime_plot, shap_plot, result['heatmap_html'] | |
| def analyze_batch(self, reviews: str, progress=None): | |
| """Batch analysis""" | |
| if not reviews.strip(): | |
| return None | |
| texts = [r.strip() for r in reviews.split('\n') if r.strip()] | |
| if len(texts) < 2: | |
| return None | |
| results = self.engine.analyze_batch(texts, progress) | |
| for result in results: | |
| self.history.add(result) | |
| theme_ctx = ThemeContext('default') | |
| return PlotFactory.create_batch_analysis(results, theme_ctx) | |
| def plot_history(self, theme: str = 'default'): | |
| """Plot analysis history""" | |
| history = self.history.get_all() | |
| if len(history) < 2: | |
| return None, f"Need at least 2 analyses for trends. Current: {len(history)}" | |
| theme_ctx = ThemeContext(theme) | |
| with managed_figure(figsize=(12, 8)) as fig: | |
| gs = fig.add_gridspec(2, 1, hspace=0.3) | |
| indices = list(range(len(history))) | |
| pos_probs = [item['pos_prob'] for item in history] | |
| confs = [item['confidence'] for item in history] | |
| # Sentiment trend | |
| ax1 = fig.add_subplot(gs[0, 0]) | |
| colors = [theme_ctx.colors['pos'] if p > 0.5 else theme_ctx.colors['neg'] | |
| for p in pos_probs] | |
| ax1.scatter(indices, pos_probs, c=colors, alpha=0.7, s=60) | |
| ax1.plot(indices, pos_probs, alpha=0.5, linewidth=2) | |
| ax1.axhline(y=0.5, color='gray', linestyle='--', alpha=0.5) | |
| ax1.set_title('Sentiment History') | |
| ax1.set_ylabel('Positive Probability') | |
| ax1.grid(True, alpha=0.3) | |
| # Confidence trend | |
| ax2 = fig.add_subplot(gs[1, 0]) | |
| ax2.bar(indices, confs, alpha=0.7, color='lightblue', edgecolor='navy') | |
| ax2.set_title('Confidence Over Time') | |
| ax2.set_xlabel('Analysis Number') | |
| ax2.set_ylabel('Confidence') | |
| ax2.grid(True, alpha=0.3) | |
| fig.tight_layout() | |
| return fig, f"History: {len(history)} analyses" | |
| def create_interface(): | |
| """Create streamlined Gradio interface""" | |
| app = SentimentApp() | |
| with gr.Blocks(theme=gr.themes.Soft(), title="Movie Sentiment Analyzer") as demo: | |
| gr.Markdown("# 🎬 AI Movie Sentiment Analyzer") | |
| gr.Markdown("Fast sentiment analysis with advanced deep learning explanations") | |
| with gr.Tab("Quick Analysis"): | |
| with gr.Row(): | |
| with gr.Column(): | |
| text_input = gr.Textbox( | |
| label="Movie Review", | |
| placeholder="Enter your movie review...", | |
| lines=5 | |
| ) | |
| with gr.Row(): | |
| analyze_btn = gr.Button("Analyze", variant="primary") | |
| theme_selector = gr.Dropdown( | |
| choices=list(config.THEMES.keys()), | |
| value="default", | |
| label="Theme" | |
| ) | |
| gr.Examples( | |
| examples=app.examples, | |
| inputs=text_input | |
| ) | |
| with gr.Column(): | |
| result_output = gr.Textbox(label="Result", lines=3) | |
| with gr.Row(): | |
| prob_plot = gr.Plot(label="Probabilities") | |
| gauge_plot = gr.Plot(label="Confidence") | |
| with gr.Row(): | |
| wordcloud_plot = gr.Plot(label="Word Cloud") | |
| with gr.Tab("Advanced Analysis"): | |
| with gr.Row(): | |
| with gr.Column(): | |
| adv_text_input = gr.Textbox( | |
| label="Movie Review", | |
| placeholder="Enter your movie review for deep analysis...", | |
| lines=5 | |
| ) | |
| with gr.Row(): | |
| adv_analyze_btn = gr.Button("Deep Analyze", variant="primary") | |
| adv_theme_selector = gr.Dropdown( | |
| choices=list(config.THEMES.keys()), | |
| value="default", | |
| label="Theme" | |
| ) | |
| gr.Examples( | |
| examples=app.examples, | |
| inputs=adv_text_input | |
| ) | |
| with gr.Column(): | |
| adv_result_output = gr.Textbox(label="Analysis Result", lines=4) | |
| with gr.Row(): | |
| lime_plot = gr.Plot(label="LIME: Key Contributing Words") | |
| shap_plot = gr.Plot(label="SHAP: Key Contributing Words") | |
| with gr.Row(): | |
| heatmap_output = gr.HTML(label="Word Importance Heatmap (LIME-based)") | |
| with gr.Tab("Batch Analysis"): | |
| with gr.Row(): | |
| with gr.Column(): | |
| file_upload = gr.File(label="Upload File", file_types=[".csv", ".txt"]) | |
| batch_input = gr.Textbox( | |
| label="Reviews (one per line)", | |
| lines=8 | |
| ) | |
| with gr.Column(): | |
| load_btn = gr.Button("Load File") | |
| batch_btn = gr.Button("Analyze Batch", variant="primary") | |
| batch_plot = gr.Plot(label="Batch Results") | |
| with gr.Tab("History & Export"): | |
| with gr.Row(): | |
| refresh_btn = gr.Button("Refresh") | |
| clear_btn = gr.Button("Clear", variant="stop") | |
| with gr.Row(): | |
| csv_btn = gr.Button("Export CSV") | |
| json_btn = gr.Button("Export JSON") | |
| history_status = gr.Textbox(label="Status") | |
| history_plot = gr.Plot(label="History Trends") | |
| csv_file = gr.File(label="CSV Download", visible=True) | |
| json_file = gr.File(label="JSON Download", visible=True) | |
| # Event bindings for Quick Analysis | |
| analyze_btn.click( | |
| app.analyze_single_fast, | |
| inputs=[text_input, theme_selector], | |
| outputs=[result_output, prob_plot, gauge_plot, wordcloud_plot] | |
| ) | |
| # Event bindings for Advanced Analysis | |
| adv_analyze_btn.click( | |
| app.analyze_single_advanced, | |
| inputs=[adv_text_input, adv_theme_selector], | |
| outputs=[adv_result_output, lime_plot, shap_plot, heatmap_output] | |
| ) | |
| # Event bindings for Batch Analysis | |
| load_btn.click(app.data_handler.process_file, inputs=file_upload, outputs=batch_input) | |
| batch_btn.click(app.analyze_batch, inputs=batch_input, outputs=batch_plot) | |
| # Event bindings for History & Export | |
| refresh_btn.click( | |
| lambda theme: app.plot_history(theme), | |
| inputs=theme_selector, | |
| outputs=[history_plot, history_status] | |
| ) | |
| clear_btn.click( | |
| lambda: f"Cleared {app.history.clear()} entries", | |
| outputs=history_status | |
| ) | |
| csv_btn.click( | |
| lambda: app.data_handler.export_data(app.history.get_all(), 'csv'), | |
| outputs=[csv_file, history_status] | |
| ) | |
| json_btn.click( | |
| lambda: app.data_handler.export_data(app.history.get_all(), 'json'), | |
| outputs=[json_file, history_status] | |
| ) | |
| return demo | |
| # Application Entry Point | |
| if __name__ == "__main__": | |
| logging.basicConfig(level=logging.INFO) | |
| demo = create_interface() | |
| demo.launch(share=True) |