DanielKiani commited on
Commit
63b1daf
·
2 Parent(s): eb6c9fd f41eb18

Merge branch 'main' of https://github.com/Deathshot78/ReviewSense

Browse files
Files changed (4) hide show
  1. .gitattributes +1 -0
  2. requirements.txt +15 -1
  3. scripts/app.py +164 -1
  4. scripts/main.py +113 -1
.gitattributes CHANGED
@@ -1,4 +1,5 @@
1
  <<<<<<< HEAD
 
2
  *.7z filter=lfs diff=lfs merge=lfs -text
3
  *.arrow filter=lfs diff=lfs merge=lfs -text
4
  *.bin filter=lfs diff=lfs merge=lfs -text
 
1
  <<<<<<< HEAD
2
+ <<<<<<< HEAD
3
  *.7z filter=lfs diff=lfs merge=lfs -text
4
  *.arrow filter=lfs diff=lfs merge=lfs -text
5
  *.bin filter=lfs diff=lfs merge=lfs -text
requirements.txt CHANGED
@@ -1,3 +1,4 @@
 
1
  langchain==0.3.27
2
  langchain-community==0.3.31
3
  gradio==5.49.1
@@ -13,4 +14,17 @@ datasets==4.0.0
13
  numpy==2.0.2
14
  accelerate==1.11.0
15
  aiohttp==3.13.1
16
- huggingface-hub==0.35.3
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <<<<<<< HEAD
2
  langchain==0.3.27
3
  langchain-community==0.3.31
4
  gradio==5.49.1
 
14
  numpy==2.0.2
15
  accelerate==1.11.0
16
  aiohttp==3.13.1
17
+ huggingface-hub==0.35.3
18
+ =======
19
+ torch==2.8.0
20
+ transformers==4.56.1
21
+ pytorch-lightning==2.5.5
22
+ torchmetrics==1.8.2
23
+ sentencepiece==0.2.1
24
+ pandas==2.2.2
25
+ scikit-learn==1.6.1
26
+ gradio==5.44.1
27
+ matplotlib==3.10.0
28
+ seaborn==0.13.2
29
+ wordcloud==1.9.4
30
+ >>>>>>> e6de3c4338f79386345fa6e4bba5b0666ad808da
scripts/app.py CHANGED
@@ -1,3 +1,4 @@
 
1
  # app.py
2
 
3
  import gradio as gr
@@ -277,4 +278,166 @@ with gr.Blocks(theme=gr.themes.Soft()) as demo:
277
  # --- Launch Command ---
278
  if __name__ == "__main__":
279
  chat_memory.clear() # Clear memory each time app starts
280
- demo.launch(debug=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <<<<<<< HEAD
2
  # app.py
3
 
4
  import gradio as gr
 
278
  # --- Launch Command ---
279
  if __name__ == "__main__":
280
  chat_memory.clear() # Clear memory each time app starts
281
+ demo.launch(debug=True)
282
+ =======
283
+ import gradio as gr
284
+ import os
285
+ import torch
286
+ import pandas as pd
287
+ import re
288
+
289
+ # --- IMPORTANT ---
290
+ # This script assumes you have a 'models.py' file in the same directory
291
+ # containing the definitions for all model and inference classes.
292
+ try:
293
+ from models import (
294
+ ReviewSummarizer,
295
+ AspectAnalyzer,
296
+ AspectExtractor,
297
+ FineTunedSentimentClassifier
298
+ )
299
+ except ImportError:
300
+ print("CRITICAL ERROR: Make sure 'models.py' exists and contains the required classes.")
301
+ # Define dummy classes if imports fail, so Gradio can at least launch with an error message.
302
+ class ReviewSummarizer: pass
303
+ class AspectAnalyzer: pass
304
+ class AspectExtractor: pass
305
+ class FineTunedSentimentClassifier: pass
306
+
307
+ # --- Configuration ---
308
+ # --- IMPORTANT: UPDATE THIS PATH ---
309
+ # You need to provide the path to the best checkpoint file that was saved
310
+ # during the training of your sentiment model.
311
+ SENTIMENT_CHECKPOINT_PATH = "checkpoints/sentiment-binary-best-checkpoint.ckpt" # <-- CHANGE THIS
312
+
313
+ # --- Pre-defined Aspect Dictionaries for Different Product Categories ---
314
+ ASPECT_DICTIONARIES = {
315
+ "Phone": ['camera', 'battery', 'battery life', 'screen', 'performance', 'price', 'design'],
316
+ "Coffee Maker": ['ease of use', 'design', 'noise level', 'coffee quality', 'brew time', 'cleaning'],
317
+ "Book": ['plot', 'characters', 'writing style', 'pacing', 'ending'],
318
+ "Default": ['quality', 'price', 'service', 'design', 'features'] # A fallback list
319
+ }
320
+
321
+
322
+ # --- 1. Load All Models (Global Objects) ---
323
+ print("--- Initializing all models for the Gradio App ---")
324
+ sentiment_classifier, summarizer, aspect_analyzer, aspect_extractor = None, None, None, None
325
+ try:
326
+ summarizer = ReviewSummarizer(force_cpu=True)
327
+ aspect_analyzer = AspectAnalyzer(force_cpu=True)
328
+ aspect_extractor = AspectExtractor(force_cpu=True)
329
+
330
+ if not os.path.exists(SENTIMENT_CHECKPOINT_PATH):
331
+ print("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!")
332
+ print("!!! WARNING: Sentiment checkpoint path not found or not set. !!!")
333
+ print(f"!!! Please update the 'SENTIMENT_CHECKPOINT_PATH' variable in app.py")
334
+ print("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!")
335
+ else:
336
+ sentiment_classifier = FineTunedSentimentClassifier(
337
+ checkpoint_path=SENTIMENT_CHECKPOINT_PATH, force_cpu=True
338
+ )
339
+ print("\n--- All models loaded successfully ---\n")
340
+ except Exception as e:
341
+ print(f"An error occurred during model initialization: {e}")
342
+
343
+
344
+ # --- 2. Define the Core Analysis Function ---
345
+ def analyze_review(review_text, product_category):
346
+ if not review_text:
347
+ return {"ERROR": "Please enter a review."}, "", None
348
+
349
+ # --- a. Overall Sentiment Analysis ---
350
+ if sentiment_classifier:
351
+ sentiment_result = sentiment_classifier.classify(review_text)
352
+ sentiment_output = {
353
+ sentiment_result['label']: f"{sentiment_result['score']:.2f}"
354
+ }
355
+ else:
356
+ sentiment_output = {"ERROR": "Fine-tuned model not loaded. Check path."}
357
+
358
+ # --- b. Review Summarization ---
359
+ if summarizer:
360
+ summary_output = summarizer.summarize(review_text)
361
+ else:
362
+ summary_output = "ERROR: Summarizer model not loaded."
363
+
364
+ # --- c. Dynamic Aspect Extraction & Analysis ---
365
+ aspect_df = None
366
+ if aspect_extractor and aspect_analyzer:
367
+ aspect_dictionary = ASPECT_DICTIONARIES.get(product_category, ASPECT_DICTIONARIES["Default"])
368
+ extracted_aspects = aspect_extractor.extract(review_text, aspect_dictionary=aspect_dictionary)
369
+
370
+ if extracted_aspects:
371
+ aspect_results = aspect_analyzer.analyze(review_text, extracted_aspects)
372
+ aspect_df = pd.DataFrame([
373
+ {'Aspect': aspect, 'Sentiment': result['sentiment'], 'Score': f"{result['score']:.2f}"}
374
+ for aspect, result in aspect_results.items()
375
+ ])
376
+
377
+ return sentiment_output, summary_output, aspect_df
378
+
379
+
380
+ # --- 3. Build the Gradio Interface ---
381
+ with gr.Blocks(theme=gr.themes.Soft()) as demo:
382
+ gr.Markdown("# 🛍️ ReviewSense: Product Review Analysis Engine")
383
+ gr.Markdown(
384
+ "Enter a product review and select the product category. The tool will automatically "
385
+ "detect relevant features and provide an overall sentiment score, a summary, and a "
386
+ "breakdown of sentiment towards each feature."
387
+ )
388
+
389
+ with gr.Row():
390
+ with gr.Column(scale=2):
391
+ review_input = gr.Textbox(
392
+ lines=10,
393
+ label="Enter Product Review Here",
394
+ placeholder="e.g., The camera is amazing, but the battery life is terrible..."
395
+ )
396
+ category_input = gr.Dropdown(
397
+ choices=list(ASPECT_DICTIONARIES.keys()),
398
+ label="Select Product Category",
399
+ value="Phone"
400
+ )
401
+ analyze_button = gr.Button("Analyze Review", variant="primary")
402
+
403
+ with gr.Column(scale=1):
404
+ gr.Markdown("### Overall Sentiment")
405
+ sentiment_output = gr.Label()
406
+
407
+ gr.Markdown("### Generated Summary")
408
+ summary_output = gr.Textbox(lines=5, label="Summary", interactive=False)
409
+
410
+ gr.Markdown("### Detected Aspect Sentiments")
411
+ aspect_output = gr.DataFrame(headers=["Aspect", "Sentiment", "Score"], label="Aspects", interactive=False)
412
+
413
+ # Connect the button to the function
414
+ analyze_button.click(
415
+ fn=analyze_review,
416
+ inputs=[review_input, category_input],
417
+ outputs=[sentiment_output, summary_output, aspect_output]
418
+ )
419
+
420
+ gr.Examples(
421
+ examples=[
422
+ [
423
+ "The camera on this phone is incredible, the pictures are professional quality. However, the battery life is a total disaster, it barely lasts half a day with light use. The screen is bright and responsive, which I love.",
424
+ "Phone"
425
+ ],
426
+ [
427
+ "I am absolutely in love with this coffee maker! It's incredibly easy to use, brews a perfect cup every single time, and the design looks fantastic on my countertop. It's also surprisingly quiet.",
428
+ "Coffee Maker"
429
+ ],
430
+ [
431
+ "An amazing story with characters that felt so real. The plot had me hooked from the first page, though I felt the ending was a bit rushed.",
432
+ "Book"
433
+ ]
434
+ ],
435
+ inputs=[review_input, category_input]
436
+ )
437
+
438
+
439
+ # --- 4. Launch the App ---
440
+ if __name__ == "__main__":
441
+ print("Launching Gradio App...")
442
+ demo.launch()
443
+ >>>>>>> e6de3c4338f79386345fa6e4bba5b0666ad808da
scripts/main.py CHANGED
@@ -1,3 +1,4 @@
 
1
  # main.py
2
 
3
  import torch
@@ -209,4 +210,115 @@ if __name__ == "__main__":
209
  break
210
  print("\n--- Chat session ended. ---")
211
 
212
- print("\n--- Local Execution Finished ---")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <<<<<<< HEAD
2
  # main.py
3
 
4
  import torch
 
210
  break
211
  print("\n--- Chat session ended. ---")
212
 
213
+ print("\n--- Local Execution Finished ---")
214
+ =======
215
+ import os
216
+ import torch
217
+ import pandas as pd
218
+
219
+ try:
220
+ from data_prepare import ReviewDataset, ReviewDataModule
221
+ from models import SentimentClassifier, ReviewSummarizer, AspectAnalyzer, FineTunedSentimentClassifier, AspectExtractor
222
+ except ImportError:
223
+ print("CRITICAL ERROR: Make sure 'review_summarizer.py', 'aspect_extractor.py', and 'sentiment_classifier_model.py' are in the same directory.")
224
+ exit()
225
+
226
+ # --- Configuration ---
227
+ # --- IMPORTANT: UPDATE THIS PATH ---
228
+ # You need to provide the path to the best checkpoint file that was saved
229
+ # during the training of your sentiment model.
230
+ SENTIMENT_CHECKPOINT_PATH = "checkpoints/sentiment-binary-best-checkpoint.ckpt"
231
+
232
+ # --- Pre-defined Aspect Dictionaries for Different Product Categories ---
233
+ ASPECT_DICTIONARIES = {
234
+ "Phone": ['camera', 'battery', 'battery life', 'screen', 'performance', 'price', 'design'],
235
+ "Coffee Maker": ['ease of use', 'design', 'noise level', 'coffee quality', 'brew time', 'cleaning'],
236
+ "Book": ['plot', 'characters', 'writing style', 'pacing', 'ending'],
237
+ "Default": ['quality', 'price', 'service', 'design', 'features'] # A fallback list
238
+ }
239
+
240
+ def main():
241
+ """
242
+ Main function to run the command-line review analysis tool.
243
+ """
244
+ # --- 1. Load All Models ---
245
+ print("--- Initializing all models ---")
246
+ sentiment_classifier, summarizer, aspect_analyzer, aspect_extractor = None, None, None, None
247
+ try:
248
+ summarizer = ReviewSummarizer(force_cpu=True)
249
+ aspect_analyzer = AspectAnalyzer(force_cpu=True)
250
+ aspect_extractor = AspectExtractor(force_cpu=True)
251
+
252
+ if not os.path.exists(SENTIMENT_CHECKPOINT_PATH):
253
+ print("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!")
254
+ print("!!! WARNING: Sentiment checkpoint path not found or not set. !!!")
255
+ print(f"!!! Please update the 'SENTIMENT_CHECKPOINT_PATH' variable in main.py")
256
+ print("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!")
257
+ else:
258
+ sentiment_classifier = FineTunedSentimentClassifier(
259
+ checkpoint_path=SENTIMENT_CHECKPOINT_PATH, force_cpu=True
260
+ )
261
+ print("\n--- All models loaded successfully ---\n")
262
+ except Exception as e:
263
+ print(f"An error occurred during model initialization: {e}")
264
+ return
265
+
266
+ # --- 2. Interactive Loop ---
267
+ while True:
268
+ print("\n==================================================")
269
+ print(" Product Review Analysis Tool ")
270
+ print("==================================================")
271
+
272
+ # Get user input
273
+ review_text = input("Enter the product review text (or type 'quit' to exit):\n> ")
274
+ if review_text.lower() == 'quit':
275
+ break
276
+
277
+ print("\nAvailable Product Categories:")
278
+ for i, category in enumerate(ASPECT_DICTIONARIES.keys(), 1):
279
+ print(f"{i}. {category}")
280
+
281
+ category_choice = input(f"Select a product category (1-{len(ASPECT_DICTIONARIES)}):\n> ")
282
+ try:
283
+ category_idx = int(category_choice) - 1
284
+ product_category = list(ASPECT_DICTIONARIES.keys())[category_idx]
285
+ except (ValueError, IndexError):
286
+ print("Invalid choice. Using 'Default' category.")
287
+ product_category = "Default"
288
+
289
+ # --- 3. Run Analysis ---
290
+ print("\n--- Analyzing Review... ---")
291
+
292
+ # a. Overall Sentiment
293
+ sentiment_result = sentiment_classifier.classify(review_text)
294
+
295
+ # b. Summary
296
+ summary_result = summarizer.summarize(review_text)
297
+
298
+ # c. Aspect Extraction and Analysis
299
+ aspect_dictionary = ASPECT_DICTIONARIES.get(product_category)
300
+ extracted_aspects = aspect_extractor.extract(review_text, aspect_dictionary)
301
+ aspect_results = None
302
+ if extracted_aspects:
303
+ aspect_results = aspect_analyzer.analyze(review_text, extracted_aspects)
304
+
305
+ # --- 4. Display Results ---
306
+ print("\n-------------------- ANALYSIS RESULTS --------------------")
307
+ print(f"\n[ Overall Sentiment ]")
308
+ print(f" - Sentiment: {sentiment_result['label']} (Score: {sentiment_result['score']:.2f})")
309
+
310
+ print(f"\n[ Generated Summary ]")
311
+ print(f" - {summary_result}")
312
+
313
+ print(f"\n[ Detected Aspect Sentiments ]")
314
+ if aspect_results:
315
+ for aspect, result in aspect_results.items():
316
+ print(f" - {aspect.title()}: {result['sentiment']} (Score: {result['score']:.2f})")
317
+ else:
318
+ print(" - No relevant aspects from the dictionary were detected in the review.")
319
+ print("----------------------------------------------------------")
320
+
321
+
322
+ if __name__ == "__main__":
323
+ main()
324
+ >>>>>>> e6de3c4338f79386345fa6e4bba5b0666ad808da