CoolFace
Apppublic

Sentiment-Analysis/PWU-MSIT-v1

sourceHugging Faceapache-2.0updated 1y agoView on Hugging Face
0likes
app.py428 linesDownload Raw Back to root
1#pip install nltk textblob vaderSentiment transformers2#pip install gradio3#pip install torch transformers scikit-learn joblib nltk4import pandas as pd5import numpy as np6import matplotlib.pyplot as plt7import seaborn as sns8import nltk9from nltk.sentiment import SentimentIntensityAnalyzer10from textblob import TextBlob11from vaderSentiment.vaderSentiment import SentimentIntensityAnalyzer as VaderAnalyzer12from transformers import pipeline13nltk.download('vader_lexicon')14import gradio as gr15import pandas as pd16import matplotlib.pyplot as plt17import numpy as np18from nltk.sentiment.vader import SentimentIntensityAnalyzer19from sklearn.linear_model import LogisticRegression20from sklearn.feature_extraction.text import TfidfVectorizer21from transformers import pipeline22import joblib23import nltk24import re25import logging26import seaborn as sns27import tempfile28import os29from datetime import datetime30 31# Configure logging32logging.basicConfig(level=logging.INFO)33nltk.download('vader_lexicon', quiet=True)34 35# Initialize components and results file36RESULTS_FILE = "sentiment_analysis_results.csv"37try:38    if not os.path.exists(RESULTS_FILE):39        pd.DataFrame(columns=['timestamp', 'text', 'method', 'sentiment', 'compound', 'scores']).to_csv(RESULTS_FILE, index=False)40except Exception as e:41    logging.error(f"Could not initialize results file: {str(e)}")42 43# Initialize models44try:45    vader = SentimentIntensityAnalyzer()46    ml_model = joblib.load('logreg_model.joblib')47    tfidf = joblib.load('tfidf_vectorizer.joblib')48except (FileNotFoundError, Exception) as e:49    logging.warning(f"Model loading failed: {str(e)} - Training new models...")50    from sklearn.datasets import fetch_20newsgroups51    from sklearn.pipeline import make_pipeline52 53    newsgroups = fetch_20newsgroups(subset='train',54                                   categories=['alt.atheism', 'soc.religion.christian'])55    tfidf = TfidfVectorizer(max_features=1000, stop_words='english')56    ml_model = make_pipeline(57        tfidf,58        LogisticRegression(max_iter=1000)59    ).fit(newsgroups.data, newsgroups.target)60 61    joblib.dump(ml_model, 'logreg_model.joblib')62    joblib.dump(tfidf, 'tfidf_vectorizer.joblib')63 64try:65    transformer_model = pipeline(66        "sentiment-analysis",67        model="distilbert-base-uncased-finetuned-sst-2-english"68    )69except Exception as e:70    logging.error(f"Transformer model failed to load: {str(e)}")71    transformer_model = None72 73def clean_text(text):74    return re.sub(r'[^a-zA-Z\s]', '', str(text)).lower().strip()75 76def get_sentiment_emoji(sentiment):77    emoji_map = {78        'positive': '๐Ÿ˜Š',79        'negative': '๐Ÿ˜ ',80        'neutral': '๐Ÿ˜',81        'error': 'โŒ'82    }83    return emoji_map.get(sentiment.lower(), 'โ“')84 85def save_to_results(timestamp, text, method, result):86    try:87        new_row = {88            'timestamp': timestamp,89            'text': text,90            'method': method,91            'sentiment': f"{get_sentiment_emoji(result['sentiment'])} {result['sentiment'].upper()}",92            'compound': result['compound'],93            'scores': str(result['scores'])94        }95 96        # Read existing data97        try:98            df = pd.read_csv(RESULTS_FILE)99        except:100            df = pd.DataFrame(columns=['timestamp', 'text', 'method', 'sentiment', 'compound', 'scores'])101 102        # Append new result103        df = pd.concat([df, pd.DataFrame([new_row])], ignore_index=True)104        df.to_csv(RESULTS_FILE, index=False)105 106    except Exception as e:107        logging.error(f"Failed to save results: {str(e)}")108 109def analyze_vader(text):110    try:111        scores = vader.polarity_scores(str(text))112        result = {113            'sentiment': 'positive' if scores['compound'] >= 0.05 else114                         'negative' if scores['compound'] <= -0.05 else 'neutral',115            'compound': scores['compound'],116            'scores': scores117        }118        save_to_results(datetime.now().strftime("%Y-%m-%d %H:%M:%S"), text, "VADER", result)119        return result120    except Exception as e:121        logging.error(f"VADER analysis failed: {str(e)}")122        return {'sentiment': 'error', 'compound': 0, 'scores': {}}123 124def analyze_ml(text):125    try:126        cleaned = clean_text(text)127        pred = ml_model.predict([cleaned])[0]128        result = {129            'sentiment': 'positive' if pred == 1 else 'negative',130            'compound': 0.8 if pred == 1 else -0.8,131            'scores': {'pos': pred, 'neg': 1-pred}132        }133        save_to_results(datetime.now().strftime("%Y-%m-%d %H:%M:%S"), text, "Logistic Regression", result)134        return result135    except Exception as e:136        logging.error(f"ML analysis failed: {str(e)}")137        return {'sentiment': 'error', 'compound': 0, 'scores': {}}138 139def analyze_transformer(text):140    try:141        if not transformer_model:142            return {'sentiment': 'model_unavailable', 'compound': 0, 'scores': {}}143        result = transformer_model(str(text)[:512])[0]144        result = {145            'sentiment': result['label'].lower(),146            'compound': result['score'] if result['label'] == 'POSITIVE' else -result['score'],147            'scores': {'confidence': result['score']}148        }149        save_to_results(datetime.now().strftime("%Y-%m-%d %H:%M:%S"), text, "Transformer", result)150        return result151    except Exception as e:152        logging.error(f"Transformer analysis failed: {str(e)}")153        return {'sentiment': 'error', 'compound': 0, 'scores': {}}154 155def create_visualization(df, method):156    fig, (ax1, ax2, ax3) = plt.subplots(1, 3, figsize=(18, 5))157 158    # Ensure required columns exist159    if 'sentiment' not in df.columns:160        df['sentiment'] = 'neutral'161    if 'compound' not in df.columns:162        df['compound'] = 0.0163 164    # Clean sentiment labels165    df['sentiment_cleaned'] = df['sentiment'].apply(166        lambda x: x.split()[1].lower() if ' ' in str(x) else str(x).lower()167    )168 169    # Replace invalid sentiments with neutral170    valid_sentiments = ['positive', 'negative', 'neutral']171    df['sentiment_cleaned'] = df['sentiment_cleaned'].apply(172        lambda x: x if x in valid_sentiments else 'neutral'173    )174 175    # Define colors176    colors = {'positive': '#4CAF50', 'negative': '#F44336', 'neutral': '#2196F3'}177 178    # Plot 1: Sentiment distribution179    sentiment_counts = df['sentiment_cleaned'].value_counts()180    sentiment_counts.plot(181        kind='bar',182        ax=ax1,183        color=[colors.get(sent, '#999999') for sent in sentiment_counts.index]184    )185 186    # Add emojis to bars187    for i, (label, _) in enumerate(sentiment_counts.items()):188        emoji = get_sentiment_emoji(label)189        ax1.text(i, sentiment_counts.iloc[i] + 0.5, emoji, ha='center', va='bottom', fontsize=14)190 191    ax1.set_title('Sentiment Distribution')192    ax1.set_ylabel('Count')193 194    # Plot 2: Compound score distribution195    df['compound'].plot(kind='hist', bins=20, ax=ax2, color='#9C27B0')196    ax2.set_title('Compound Score Distribution')197    ax2.set_xlabel('Compound Score')198    ax2.set_ylabel('Frequency')199 200    # Plot 3: Dot plot201    sns.stripplot(202        x='sentiment_cleaned',203        y='compound',204        data=df,205        ax=ax3,206        palette=colors,207        jitter=True,208        size=6209    )210    ax3.set_title('Sentiment Scores Distribution')211    ax3.axhline(0.05, color='gray', linestyle='--')212    ax3.axhline(-0.05, color='gray', linestyle='--')213 214    plt.suptitle(f"Sentiment Analysis Results ({method})", y=1.05)215    plt.tight_layout()216    return fig217 218def process_csv(csv_file, method):219    try:220        df = pd.read_csv(csv_file.name)221 222        if 'text' not in df.columns:223            raise gr.Error("CSV must contain a 'text' column")224 225        method_map = {226            "VADER": analyze_vader,227            "Logistic Regression": analyze_ml,228            "Transformer": analyze_transformer229        }230 231        if method not in method_map:232            raise gr.Error("Invalid analysis method selected")233 234        analysis_results = df['text'].apply(method_map[method])235        df = pd.concat([df, pd.json_normalize(analysis_results)], axis=1)236 237        # Ensure compound column exists238        if 'compound' not in df.columns:239            df['compound'] = 0.0240 241        fig = create_visualization(df, method)242 243        # Save results244        output_csv = f"results_{method}.csv"245        df.to_csv(output_csv, index=False)246 247        # Save visualization to temp file248        temp_dir = tempfile.mkdtemp()249        plot_path = os.path.join(temp_dir, "sentiment_analysis.png")250        fig.savefig(plot_path, bbox_inches='tight')251        plt.close(fig)252 253        preview_df = df[['text', 'sentiment', 'compound']].head(50)254        preview_df.columns = ['Text', 'Sentiment', 'Compound Score']255        return preview_df, plot_path, output_csv, plot_path256 257    except Exception as e:258        logging.error(f"CSV processing failed: {str(e)}")259        raise gr.Error(f"Processing error: {str(e)}")260 261def analyze_single_text(text, method):262    if not text.strip():263        raise gr.Error("Please enter some text to analyze")264 265    method_map = {266        "VADER": analyze_vader,267        "Logistic Regression": analyze_ml,268        "Transformer": analyze_transformer269    }270 271    if method not in method_map:272        raise gr.Error("Invalid analysis method selected")273 274    result = method_map[method](text)275    emoji = get_sentiment_emoji(result['sentiment'])276 277    interpretation = ""278    if result['compound'] >= 0.05:279        interpretation = "Positive ๐Ÿ˜Š"280    elif result['compound'] <= -0.05:281        interpretation = "Negative ๐Ÿ˜ "282    else:283        interpretation = "Neutral ๐Ÿ˜"284 285    detailed_explanation = f"""286    **Analysis Method**: {method}287    **Detected Sentiment**: {emoji} {result['sentiment'].upper()}288    **Compound Score**: {result['compound']:.3f}289    **Interpretation**: {interpretation}290    **Detailed Scores**:291    {str(result['scores'])}292    """293 294    return (295        f"{emoji} {result['sentiment'].upper()}",  # For sentiment_output (Label)296        float(result['compound']),                # For compound_score (Number)297        result['scores'],                         # For detailed_scores (JSON)298        detailed_explanation                      # For explanation (Markdown)299    )300 301def clear_single_analysis():302    return (303        "",  # Clear text input304        "VADER",  # Reset method to default305        "",  # Clear sentiment output306        0.0,  # Reset compound score307        {},  # Clear detailed scores308        """**Sentiment Interpretation Guide**:309    - **Positive ๐Ÿ˜Š**: Compound score โ‰ฅ 0.05310    - **Neutral ๐Ÿ˜**: -0.05 < Compound score < 0.05311    - **Negative ๐Ÿ˜ **: Compound score โ‰ค -0.05312    Higher absolute values indicate stronger sentiment.313    """,  # Reset explanation314        pd.read_csv(RESULTS_FILE).tail(10) if os.path.exists(RESULTS_FILE) else None  # Keep history315    )316 317def clear_all():318    return None, None, None, None319 320with gr.Blocks(theme=gr.themes.Soft(primary_hue="emerald")) as demo:321    gr.Markdown("""# ๐Ÿ“Š Enhanced Sentiment Analysis Dashboard""")322 323    with gr.Tab("๐Ÿ“ Batch CSV Analysis"):324        with gr.Row():325            with gr.Column(scale=1):326                gr.Markdown("## CSV Settings")327                file_input = gr.File(label="Upload CSV", file_types=['.csv'])328                method_choice = gr.Dropdown(329                    label="Analysis Method",330                    choices=["VADER", "Logistic Regression", "Transformer"],331                    value="VADER"332                )333                with gr.Row():334                    analyze_btn = gr.Button("Analyze ๐Ÿš€", variant="primary")335                    clear_btn = gr.Button("Clear ๐Ÿงน", variant="secondary")336 337            with gr.Column(scale=2):338                gr.Markdown("## Analysis Results")339                with gr.Tab("Data Preview"):340                    df_display = gr.DataFrame(341                        value=None,342                        headers=["Text", "Sentiment", "Compound Score"],343                        interactive=False,344                        datatype=["str", "str", "number"],345                        col_count=(3, "fixed")346                    )347                with gr.Tab("Visualization"):348                    plot_output = gr.Image(label="Generated Visualization")349 350                with gr.Row():351                    download_csv = gr.File(label="Download CSV Results ๐Ÿ’พ")352                    download_plot = gr.File(label="Download Visualization ๐Ÿ–ผ๏ธ")353 354    with gr.Tab("๐Ÿ‘ค Single Text Analysis"):355        with gr.Row():356            with gr.Column(scale=1):357                gr.Markdown("## Text Input")358                text_input = gr.Textbox(359                    label="Enter your text โœ๏ธ",360                    placeholder="Type or paste text here...",361                    lines=5362                )363                method_choice_single = gr.Dropdown(364                    label="Analysis Method",365                    choices=["VADER", "Logistic Regression", "Transformer"],366                    value="VADER"367                )368                with gr.Row():369                    analyze_btn_single = gr.Button("Analyze ๐Ÿ”", variant="primary")370                    clear_btn_single = gr.Button("Clear ๐Ÿงน", variant="secondary")371 372            with gr.Column(scale=2):373                gr.Markdown("## Analysis Results")374                with gr.Tab("Sentiment Scores"):375                    sentiment_output = gr.Label(label="Predicted Sentiment")376                    compound_score = gr.Number(label="Compound Score", precision=3)377 378                    with gr.Accordion("Show Detailed Scores ๐Ÿ”Ž", open=False):379                        detailed_scores = gr.JSON(label="Detailed Scores")380 381                with gr.Tab("Explanation ๐Ÿ“"):382                    explanation = gr.Markdown("""**Sentiment Interpretation Guide**:383                    - **Positive ๐Ÿ˜Š**: Compound score โ‰ฅ 0.05384                    - **Neutral ๐Ÿ˜**: -0.05 < Compound score < 0.05385                    - **Negative ๐Ÿ˜ **: Compound score โ‰ค -0.05386                    Higher absolute values indicate stronger sentiment.387                    """)388 389                with gr.Accordion("View History โณ", open=False):390                    history_df = gr.DataFrame(391                        value=pd.read_csv(RESULTS_FILE).tail(10) if os.path.exists(RESULTS_FILE) else None,392                        headers=["Timestamp", "Method", "Sentiment", "Score"],393                        interactive=False,394                        datatype=["str", "str", "str", "number"]395                    )396 397    analyze_btn.click(398        fn=process_csv,399        inputs=[file_input, method_choice],400        outputs=[df_display, plot_output, download_csv, download_plot]401    )402 403    analyze_btn_single.click(404        fn=analyze_single_text,405        inputs=[text_input, method_choice_single],406        outputs=[sentiment_output, compound_score, detailed_scores, explanation]407    ).then(408        fn=lambda: pd.read_csv(RESULTS_FILE).tail(10) if os.path.exists(RESULTS_FILE) else None,409        outputs=history_df410    )411 412    clear_btn_single.click(413        fn=clear_single_analysis,414        outputs=[text_input, method_choice_single, sentiment_output, compound_score, detailed_scores, explanation, history_df]415    )416 417    clear_btn.click(418        fn=clear_all,419        outputs=[df_display, plot_output, download_csv, download_plot]420    )421 422if __name__ == "__main__":423    try:424        demo.launch(share=True)425    except Exception as e:426        logging.error(f"Failed to launch interface: {str(e)}")427        print(f"Error: {str(e)}")428