makbar023 commited on
Commit
cd8db5f
·
verified ·
1 Parent(s): e970fe1

Upload 2 files

Browse files
Files changed (2) hide show
  1. app.py +206 -0
  2. requirements.txt +13 -0
app.py ADDED
@@ -0,0 +1,206 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+
3
+ import base64
4
+ import io
5
+ from flask import Flask, request, jsonify
6
+ from flask_cors import CORS
7
+ import torch
8
+ import torch.nn as nn
9
+ import torch.nn.functional as F
10
+ from transformers import BertModel, BertTokenizer, BertConfig
11
+ from werkzeug.utils import secure_filename
12
+ import os
13
+
14
+ os.environ['KMP_DUPLICATE_LIB_OK'] = 'TRUE'
15
+ import pandas as pd
16
+ from openpyxl import load_workbook
17
+ import pandas as pd
18
+ import matplotlib.pyplot as plt
19
+ import matplotlib
20
+ matplotlib.use('Agg')
21
+ import plotly.express as px
22
+
23
+ # Load the model
24
+ from huggingface_hub import hf_hub_download
25
+
26
+ app = Flask(__name__)
27
+ CORS(app) # Enable CORS for all routes
28
+
29
+ # Define class_names and device if not already defined
30
+ class_names = ['Negative', 'Neutral', 'Positive']
31
+ device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
32
+
33
+ # Create a modified BERT model with the correct vocabulary size
34
+ class ModifiedBertForSentiment(nn.Module):
35
+ def __init__(self, config, n_classes):
36
+ super(ModifiedBertForSentiment, self).__init__()
37
+ self.bert = BertModel(config)
38
+ self.drop = nn.Dropout(p=0.3)
39
+ self.out = nn.Linear(config.hidden_size, n_classes)
40
+
41
+ def forward(self, input_ids, attention_mask):
42
+ outputs = self.bert(input_ids=input_ids, attention_mask=attention_mask)
43
+ pooled_output = outputs.last_hidden_state.mean(dim=1)
44
+ output = self.drop(pooled_output)
45
+ return self.out(output)
46
+
47
+
48
+ # Load the model
49
+ tokenizer = BertTokenizer.from_pretrained('nlptown/bert-base-multilingual-uncased-sentiment')
50
+ config = BertConfig.from_pretrained('nlptown/bert-base-multilingual-uncased-sentiment')
51
+ model = ModifiedBertForSentiment(config, len(class_names))
52
+
53
+ # Download model from Hugging Face if not exists locally
54
+ model_filename = 'roman_Sentiment.pth'
55
+ if not os.path.exists(model_filename):
56
+ print("Downloading model from Hugging Face...")
57
+ model_filename = hf_hub_download(
58
+ repo_id="makbar023/roman-sentiment-model",
59
+ filename="roman_Sentiment.pth"
60
+ )
61
+ print(f"Model downloaded to: {model_filename}")
62
+ else:
63
+ print("Using local model file")
64
+
65
+ model.load_state_dict(torch.load(model_filename, map_location=device))
66
+ model.to(device)
67
+ model.eval()
68
+
69
+ # Helper function to tokenize text
70
+ def tokenize_text(text):
71
+ inputs = tokenizer(text, padding=True, truncation=True, return_tensors='pt', max_length=512)
72
+ return inputs['input_ids'], inputs['attention_mask']
73
+
74
+ # Sentiment analysis function
75
+ def predict_single_sentence_sentiment(review_text):
76
+ input_ids, attention_mask = tokenize_text(review_text)
77
+ input_ids = input_ids.to(device)
78
+ attention_mask = attention_mask.to(device)
79
+
80
+ with torch.no_grad():
81
+ outputs = model(input_ids=input_ids, attention_mask=attention_mask)
82
+ _, preds = torch.max(outputs, dim=1)
83
+ probs = F.softmax(outputs, dim=1)
84
+
85
+ sentiment = class_names[preds.item()]
86
+ return sentiment, probs
87
+
88
+ @app.route('/analyze-sentiment', methods=['POST'])
89
+ def analyze_sentiment_route():
90
+ try:
91
+ data = request.get_json()
92
+ review = data['review']
93
+
94
+ sentiment, _ = predict_single_sentence_sentiment(review)
95
+ return jsonify(sentiment)
96
+
97
+ except Exception as e:
98
+ return jsonify({'error': str(e)})
99
+
100
+ # Sentiment analysis function
101
+ def predict_sentiment(review_text):
102
+ input_ids, attention_mask = tokenize_text(review_text)
103
+ input_ids = input_ids.to(device)
104
+ attention_mask = attention_mask.to(device)
105
+
106
+ with torch.no_grad():
107
+ outputs = model(input_ids=input_ids, attention_mask=attention_mask)
108
+ _, preds = torch.max(outputs, dim=1)
109
+ probs = F.softmax(outputs, dim=1)
110
+
111
+ sentiment = class_names[preds.item()]
112
+ return sentiment, probs
113
+
114
+ @app.route('/analyze-multi-sentences', methods=['POST'])
115
+ def analyze_multi_sentences_route():
116
+ try:
117
+ data = request.get_json()
118
+ sentences = data['sentences']
119
+ results = []
120
+
121
+ for sentence in sentences:
122
+ sentiment, probabilities = predict_sentiment(sentence)
123
+ result = {
124
+ 'sentence': sentence,
125
+ 'sentiment': sentiment,
126
+ 'probabilities': {class_names[i]: float(probabilities[0][i]) for i in range(len(class_names))}
127
+ }
128
+ results.append(result)
129
+
130
+ return jsonify(results)
131
+
132
+ except Exception as e:
133
+ return jsonify({'error': str(e)})
134
+
135
+ # Define your prediction data (you should replace this with actual data)
136
+ prediction_data = ['Negative', 'Neutral', 'Positive']
137
+
138
+ @app.route('/analyze-sentiment-file', methods=['POST'])
139
+ def analyze_sentiment_file():
140
+ if 'file' not in request.files:
141
+ return jsonify({'error': 'No file part'})
142
+
143
+ file = request.files['file']
144
+
145
+ if file.filename == '':
146
+ return jsonify({'error': 'No selected file'})
147
+
148
+ if file:
149
+ filename = secure_filename(file.filename)
150
+ file.save(filename)
151
+ data = None
152
+
153
+ # Handle different file formats
154
+ if filename.endswith('.csv'):
155
+ data = pd.read_csv(filename)
156
+ elif filename.endswith('.xlsx'):
157
+ wb = load_workbook(filename)
158
+ sheet = wb.active
159
+ data = pd.DataFrame(sheet.values)
160
+ elif filename.endswith('.txt'):
161
+ # Read text content from a .txt file
162
+ with open(filename, 'r') as txt_file:
163
+ data = [line.strip() for line in txt_file]
164
+
165
+ line_count = len(data)
166
+ sentiments = []
167
+ sentiment_counts = {'Negative': 0, 'Neutral': 0, 'Positive': 0}
168
+ reviews = []
169
+
170
+ for text_data in data:
171
+ sentiment, _ = predict_single_sentence_sentiment(text_data)
172
+ sentiments.append(sentiment)
173
+ sentiment_counts[sentiment] += 1
174
+ reviews.append(text_data)
175
+
176
+ # Create a pie chart
177
+ fig = px.pie(
178
+ names=class_names,
179
+ values=[sentiment_counts['Negative'], sentiment_counts['Neutral'], sentiment_counts['Positive']],
180
+ title='Sentiment Distribution'
181
+ )
182
+ fig.write_image("pie_chart.png", width=800, height=400)
183
+
184
+ with open("pie_chart.png", "rb") as image_file:
185
+ encoded_image = base64.b64encode(image_file.read()).decode('utf-8')
186
+
187
+ os.remove(filename)
188
+ os.remove("pie_chart.png")
189
+
190
+ return jsonify({
191
+ 'line_count': line_count,
192
+ 'sentiment_counts': sentiment_counts,
193
+ 'sentiments': sentiments,
194
+ 'reviews': reviews,
195
+ 'pie_chart_path': encoded_image
196
+ })
197
+
198
+ @app.route('/health', methods=['GET'])
199
+ def health_check():
200
+ return jsonify({'status': 'healthy', 'message': 'SentimentSense API is running'})
201
+
202
+ if __name__ == '__main__':
203
+ if not os.path.exists('uploads'):
204
+ os.makedirs('uploads')
205
+ port = int(os.environ.get("PORT", 5000))
206
+ app.run(host="0.0.0.0", port=port)
requirements.txt ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ flask==3.1.2
2
+ flask-cors==6.0.2
3
+ torch==2.10.0
4
+ transformers==5.0.0
5
+ werkzeug==3.1.5
6
+ pandas==3.0.0
7
+ openpyxl==3.1.5
8
+ matplotlib==3.10.8
9
+ plotly==6.5.2
10
+ kaleido==1.2.0
11
+ protobuf
12
+ gunicorn==21.2.0
13
+ huggingface_hub