File size: 4,428 Bytes
243879b
3f74701
a7328ec
 
 
 
 
243879b
a7328ec
 
 
c551a44
 
 
 
 
 
a7328ec
243879b
 
 
 
db87bba
243879b
 
 
 
bd7368b
243879b
a7328ec
b44978e
243879b
9e7ff90
243879b
211e5c4
9e7ff90
 
3f74701
a7328ec
c551a44
3f74701
c551a44
 
 
 
 
 
3f74701
 
 
 
 
 
 
a7328ec
 
 
 
 
c551a44
 
 
 
 
 
b824c83
a7328ec
 
c551a44
 
 
47b6497
b44978e
3f74701
 
9e7ff90
c551a44
b44978e
c551a44
 
 
 
 
 
 
 
b44978e
 
c551a44
 
 
 
3f74701
 
 
 
b44978e
c551a44
b44978e
 
 
 
 
c551a44
b44978e
 
 
 
c551a44
 
b44978e
 
 
 
 
 
 
 
c551a44
 
b44978e
a7328ec
3f74701
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
import os
from flask import Flask, jsonify, request, render_template, send_file
import pandas as pd
import torch
from transformers import BertTokenizer, BertForSequenceClassification
from collections import Counter
import matplotlib
matplotlib.use('Agg')  # Prevents GUI issues for Matplotlib
import matplotlib.pyplot as plt
import base64
from io import BytesIO


# Ensure the file exists in the current directory
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
FILE_PATH = os.path.join(BASE_DIR, "Student_Feedback_Dataset__20_Rows_.csv")


# Fix Permission Issues: Set Writable Directories for Hugging Face & Matplotlib
os.environ["HF_HOME"] = "/tmp"
os.environ["TRANSFORMERS_CACHE"] = "/tmp"
os.environ["MPLCONFIGDIR"] = "/tmp"

# Create directories if they don’t exist
os.makedirs(os.environ["HF_HOME"], exist_ok=True)
os.makedirs(os.environ["TRANSFORMERS_CACHE"], exist_ok=True)
os.makedirs(os.environ["MPLCONFIGDIR"], exist_ok=True)

app = Flask(__name__)

# Load Model from Hugging Face
MODEL_NAME = "philipobiorah/bert-imdb-model"
tokenizer = BertTokenizer.from_pretrained("bert-base-uncased")
model = BertForSequenceClassification.from_pretrained(MODEL_NAME)

model.eval()

# Function to Predict Sentiment + Confidence Score
def predict_sentiment(text):
    if not text.strip():
        return {"sentiment": "Neutral", "confidence": 0.0}  # Avoid processing empty text

    inputs = tokenizer(text, return_tensors="pt", truncation=True, padding=True, max_length=512)
    
    with torch.no_grad():
        outputs = model(**inputs)
    
    probabilities = torch.nn.functional.softmax(outputs.logits, dim=1)[0]  # Convert logits to probabilities
    sentiment_idx = probabilities.argmax().item()  # Get predicted class (0 = Negative, 1 = Positive)
    confidence = probabilities[sentiment_idx].item() * 100  # Convert to percentage
    
    sentiment_label = "Positive" if sentiment_idx == 1 else "Negative"
    
    return {"sentiment": sentiment_label, "confidence": round(confidence, 2)}

@app.route('/')
def upload_file():
    return render_template('upload.html')

@app.route('/download-sample')
def download_sample():
    if os.path.exists(FILE_PATH):
        return send_file(FILE_PATH, as_attachment=True)
    else:
        return "Error: File not found!", 404

@app.route('/analyze_text', methods=['POST'])
def analyze_text():
    text = request.form.get('text', '').strip()
    
    if not text:
        return jsonify({"error": "No text provided!"}), 400  # Return JSON error message

    result = predict_sentiment(text)
    return jsonify(result)  # Return JSON response including confidence score

@app.route('/uploader', methods=['POST'])
def upload_file_post():
    if 'file' not in request.files:
        return "Error: No file uploaded!", 400

    f = request.files['file']
    if f.filename == '':
        return "Error: No file selected!", 400

    try:
        data = pd.read_csv(f)

        # Ensure 'review' column exists
        if 'review' not in data.columns:
            return "Error: CSV file must contain a 'review' column!", 400

        # Predict sentiment & confidence for each review
        results = data['review'].astype(str).apply(predict_sentiment)
        data['sentiment'] = results.apply(lambda x: x['sentiment'])
        data['confidence'] = results.apply(lambda x: f"{x['confidence']}%")

        # Generate summary
        sentiment_counts = data['sentiment'].value_counts().to_dict()
        summary = f"Total Reviews: {len(data)}<br>" \
                  f"Positive: {sentiment_counts.get('Positive', 0)}<br>" \
                  f"Negative: {sentiment_counts.get('Negative', 0)}<br>"

        # Generate sentiment plot
        fig, ax = plt.subplots()
        ax.bar(sentiment_counts.keys(), sentiment_counts.values(), color=['red', 'blue'])
        ax.set_ylabel('Counts')
        ax.set_title('Sentiment Analysis Summary')

        # Save plot as an image
        img = BytesIO()
        plt.savefig(img, format='png', bbox_inches='tight')
        img.seek(0)
        plot_url = base64.b64encode(img.getvalue()).decode('utf8')
        plt.close(fig)

        return render_template('result.html', tables=[data.to_html(classes='data')], titles=data.columns.values, summary=summary, plot_url=plot_url)

    except Exception as e:
        return f"Error processing file: {str(e)}", 500

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=7860, debug=True)