| import pandas as pd |
| import gradio as gr |
| import matplotlib.pyplot as plt |
| import io |
| from PIL import Image |
| from transformers import pipeline |
|
|
| |
| |
| |
| sentiment_model = pipeline( |
| "sentiment-analysis", |
| model="distilbert-base-uncased-finetuned-sst-2-english" |
| ) |
|
|
| theme_model = pipeline( |
| "zero-shot-classification", |
| model="valhalla/distilbart-mnli-12-3" |
| ) |
|
|
| THEMES = [ |
| "product quality", |
| "delivery", |
| "price", |
| "packaging", |
| "taste", |
| "customer service" |
| ] |
|
|
| |
| |
| |
| def analyze_review(text): |
| text = str(text)[:512] |
|
|
| sentiment_result = sentiment_model(text)[0] |
| label = sentiment_result["label"] |
| confidence = round(sentiment_result["score"] * 100, 1) |
|
|
| theme_result = theme_model(text, THEMES) |
| top_theme = theme_result["labels"][0] |
| theme_score = round(theme_result["scores"][0] * 100, 1) |
|
|
| return label, confidence, top_theme, theme_score |
|
|
|
|
| |
| |
| |
| def build_chart(df): |
| fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(10, 4)) |
|
|
| sentiment_counts = df["Sentiment"].value_counts() |
|
|
| color_map = { |
| "POSITIVE": "#22c55e", |
| "NEGATIVE": "#ef4444", |
| "NEUTRAL": "#94a3b8" |
| } |
|
|
| colors = [color_map.get(label, "#94a3b8") for label in sentiment_counts.index] |
|
|
| ax1.pie( |
| sentiment_counts.values, |
| labels=sentiment_counts.index, |
| autopct="%1.0f%%", |
| colors=colors, |
| startangle=90, |
| wedgeprops=dict(width=0.5) |
| ) |
|
|
| ax1.set_title("Sentiment Split") |
|
|
| theme_counts = df["Top Theme"].value_counts() |
|
|
| ax2.barh(theme_counts.index, theme_counts.values) |
| ax2.set_title("Top Themes") |
| ax2.invert_yaxis() |
|
|
| plt.tight_layout() |
|
|
| buf = io.BytesIO() |
| plt.savefig(buf, format="png") |
| plt.close(fig) |
|
|
| buf.seek(0) |
|
|
| return Image.open(buf) |
|
|
|
|
| |
| |
| |
| def analyze_excel(file): |
|
|
| df = pd.read_excel(file.name) |
|
|
| if "review_text" not in df.columns: |
|
|
| if "Text" in df.columns: |
| df = df.rename(columns={"Text": "review_text"}) |
| else: |
| return ( |
| None, |
| "❌ Excel file must contain a 'review_text' or 'Text' column.", |
| None |
| ) |
|
|
| df = df.dropna(subset=["review_text"]) |
|
|
| results = [] |
|
|
| for _, row in df.iterrows(): |
|
|
| label, confidence, theme, theme_confidence = analyze_review( |
| row["review_text"] |
| ) |
|
|
| results.append( |
| { |
| "Review": str(row["review_text"])[:100] + "...", |
| "Sentiment": label, |
| "Confidence %": confidence, |
| "Top Theme": theme, |
| "Theme Confidence %": theme_confidence |
| } |
| ) |
|
|
| output_df = pd.DataFrame(results) |
|
|
| positive_pct = round( |
| (output_df["Sentiment"] == "POSITIVE").mean() * 100, |
| 1 |
| ) |
|
|
| summary = ( |
| f"✅ Successfully analyzed {len(output_df)} reviews.\n" |
| f"Positive Reviews: {positive_pct}%" |
| ) |
|
|
| chart = build_chart(output_df) |
|
|
| return output_df, summary, chart |
|
|
|
|
| |
| |
| |
| with gr.Blocks(title="Customer Feedback Analyzer") as app: |
|
|
| gr.Markdown( |
| """ |
| # 🧠 AI Customer Feedback Analyzer |
| |
| Upload an Excel (.xlsx) file containing customer reviews. |
| |
| The app automatically predicts: |
| |
| - Sentiment |
| - Confidence |
| - Top Theme |
| - Theme Confidence |
| """ |
| ) |
|
|
| file_input = gr.File( |
| label="Upload Excel File (.xlsx)", |
| file_types=[".xlsx"] |
| ) |
|
|
| analyze_button = gr.Button("Analyze") |
|
|
| summary_output = gr.Textbox(label="Summary") |
|
|
| chart_output = gr.Image(label="Charts") |
|
|
| table_output = gr.Dataframe(label="Analysis Results") |
|
|
| analyze_button.click( |
| analyze_excel, |
| inputs=file_input, |
| outputs=[ |
| table_output, |
| summary_output, |
| chart_output |
| ] |
| ) |
|
|
|
|
| app.launch() |