File size: 6,479 Bytes
cf56ee3
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
import torch
import gradio as gr
from transformers import (
    pipeline,
    BartForConditionalGeneration,
    BartTokenizer
)

# ── Device ────────────────────────────────────
DEVICE     = 0 if torch.cuda.is_available() else -1
DEVICE_STR = "cuda" if torch.cuda.is_available() else "cpu"

# ── Categories & Aspects ──────────────────────
CATEGORIES = [
    "Electronics",
    "Clothing and Fashion",
    "Books and Literature",
    "Food and Grocery",
    "Sports and Outdoors",
    "Home and Kitchen",
    "Beauty and Personal Care",
    "Toys and Games"
]

ASPECTS = [
    "price and value",
    "quality and durability",
    "delivery and shipping",
    "customer service",
    "ease of use",
    "design and appearance",
    "performance and speed",
    "battery life"
]

# ── Load all models from HuggingFace Hub ──────
print("Loading sentiment model...")
sentiment_pipe = pipeline(
    "text-classification",
    model  = "Ved2001/pranalyzer",
    device = DEVICE
)

print("Loading category classifier...")
category_pipe = pipeline(
    "zero-shot-classification",
    model  = "facebook/bart-large-mnli",
    device = DEVICE
)

print("Loading aspect analyzer...")
aspect_pipe = pipeline(
    "zero-shot-classification",
    model  = "cross-encoder/nli-roberta-base",
    device = DEVICE
)

print("Loading summarization model...")
bart_tokenizer = BartTokenizer.from_pretrained(
    "facebook/bart-large-xsum")
bart_model = BartForConditionalGeneration\
    .from_pretrained("facebook/bart-large-xsum")\
    .to(DEVICE_STR)

print("All models loaded!")


# ── Inference functions ───────────────────────
def analyze_sentiment(text):
    result = sentiment_pipe(text[:512])[0]
    return {'label': result['label'], 'score': round(result['score'], 4)}

def classify_category(text):
    result = category_pipe(
        text[:512],
        candidate_labels=CATEGORIES,
        multi_label=False
    )
    return {'category': result['labels'][0], 'score': round(result['scores'][0], 4)}

def analyze_aspects(text):
    result = aspect_pipe(
        text[:512],
        candidate_labels=ASPECTS,
        multi_label=True
    )
    return [
        (label, round(score, 4))
        for label, score in zip(result['labels'], result['scores'])
        if score > 0.3
    ][:3]

def summarize_review(text):
    if len(text.split()) < 30:
        return text
    inputs = bart_tokenizer(
        text[:512],
        return_tensors="pt",
        truncation=True,
        max_length=512
    ).to(DEVICE_STR)
    summary_ids = bart_model.generate(
        inputs["input_ids"],
        max_new_tokens=80,
        min_length=15,
        length_penalty=2.0,
        num_beams=4,
        early_stopping=True
    )
    return bart_tokenizer.decode(
        summary_ids[0], skip_special_tokens=True)


# ── Gradio function ───────────────────────────
def run_analysis(review_text):
    if not review_text.strip():
        return ("Please enter a review!",) * 4

    sentiment = analyze_sentiment(review_text)
    category  = classify_category(review_text)
    aspects   = analyze_aspects(review_text)
    summary   = summarize_review(review_text)

    # Format sentiment
    emoji = "😊" if sentiment['label'] == "POSITIVE" else "😞"
    sentiment_out = (
        f"{emoji} {sentiment['label']}\n"
        f"Confidence: {sentiment['score']*100:.1f}%"
    )

    # Format category
    category_out = (
        f"πŸ“¦ {category['category']}\n"
        f"Confidence: {category['score']*100:.1f}%"
    )

    # Format aspects
    aspects_out = "πŸ” Aspects Mentioned:\n\n"
    for aspect, score in aspects:
        bar   = "β–ˆ" * int(score * 10)
        empty = "β–‘" * (10 - int(score * 10))
        aspects_out += f"β€’ {aspect:<25} {score:.2f}  {bar}{empty}\n"
    if not aspects:
        aspects_out += "No strong aspects detected."

    # Format summary
    summary_out = f"πŸ“ {summary}"

    return sentiment_out, category_out, aspects_out, summary_out


# ── Gradio UI ─────────────────────────────────
with gr.Blocks(title="pranalyzer") as demo:

    gr.Markdown("""
    # πŸ›οΈ pranalyzer
    ### Product Review Analyzer
    Paste any Amazon product review and get instant analysis
    using 4 NLP models running in parallel.
    ---
    """)

    review_input = gr.Textbox(
        label       = "πŸ“ Paste your product review here",
        placeholder = "e.g. This laptop is amazing! Battery lasts all day...",
        lines       = 6
    )

    analyze_btn = gr.Button(
        "πŸ” Analyze Review",
        variant = "primary",
        size    = "lg"
    )

    gr.Markdown("### πŸ“Š Analysis Results")

    with gr.Row():
        sentiment_out = gr.Textbox(label="😊 Sentiment", lines=3)
        category_out  = gr.Textbox(label="πŸ“¦ Category",  lines=3)

    with gr.Row():
        aspects_out = gr.Textbox(label="πŸ” Aspects", lines=6)
        summary_out = gr.Textbox(label="πŸ“ Summary", lines=6)

    gr.Examples(
        examples=[
            ["This laptop is absolutely incredible! Battery lasts all day, easily 10-12 hours of real work. The display is crisp and bright. Performance is blazing fast. Highly recommended!"],
            ["Complete waste of money. Stopped working after a week. Customer service was useless and refused a refund. Avoid at all costs."],
            ["Ordered these running shoes for marathon training. Delivery was super fast. Cushioning is excellent. Only downside is sizing runs small, order a size up."],
            ["This cookbook is a disappointment. Half the recipes have missing ingredients. Very misleading. Wasted expensive ingredients trying three different recipes."]
        ],
        inputs=review_input
    )

    gr.Markdown("""
    ---
    **Models:** `DistilBERT` β†’ Sentiment | `BART-MNLI` β†’ Category | `RoBERTa` β†’ Aspects | `BART-XSUM` β†’ Summary  
    Built by [Vedant Nagarkar](https://huggingface.co/Ved2001) β€’ 
    [GitHub](https://github.com/Vedant-Nagarkar/product-review-analyzer)
    """)

    analyze_btn.click(
        fn      = run_analysis,
        inputs  = review_input,
        outputs = [sentiment_out, category_out, aspects_out, summary_out]
    )

demo.launch()