Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 81a5fc1

Browse files
committedOct 26, 2021
Initial commit
0 parents  commit 81a5fc1

File tree

10 files changed

+659
-0
lines changed

10 files changed

+659
-0
lines changed
 

‎.gitattributes

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# Auto detect text files and perform LF normalization
2+
* text=auto

‎Procfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
web: gunicorn app:app

‎README.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# Sentiment Analysis
2+
A simple sentiment analysis application made using following packages:
3+
- Tensorflow Keras
4+
- Natural Language Toolkit (NLTK)
5+
- TfidfVectorizer
6+
7+
8+
The model was trained using tweets from [Sentiment140 dataset with 1.6 million tweets](http://www.kaggle.com/kazanova/sentiment140).
9+
10+
The app has has been deployed using Flask and Heroku. The app can be found [here](http://sentiment-analysis-mp.herokuapp.com/).

‎app.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import numpy as np
2+
from flask import Flask, request, jsonify, render_template
3+
import pickle
4+
import os
5+
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '3'
6+
import tensorflow as tf
7+
import re
8+
from nltk.corpus import stopwords
9+
from nltk.stem import SnowballStemmer
10+
11+
app = Flask(__name__)
12+
vect = pickle.load(open("vectorizer.pickle",'rb'))
13+
model = tf.keras.models.load_model('model.h5')
14+
15+
def preprocess(text, stem=False):
16+
text = re.sub("@\S+|https?:\S+|http?:\S|[^A-Za-z0-9]+", ' ', str(text).lower()).strip()
17+
stop_words = stopwords.words('english')
18+
stemmer = SnowballStemmer('english')
19+
tokens = []
20+
for token in text.split():
21+
if token not in stop_words:
22+
if stem:
23+
tokens.append(stemmer.stem(token))
24+
else:
25+
tokens.append(token)
26+
return " ".join(tokens)
27+
28+
29+
@app.route('/')
30+
def home():
31+
return render_template('index.html')
32+
33+
@app.route('/predict',methods=['POST'])
34+
def predict():
35+
inp = [x for x in request.form.values()]
36+
inp = preprocess(inp)
37+
inp = vect.transform([inp]).toarray().reshape(1,1,2500)
38+
output = model.predict(inp)[0]
39+
40+
return render_template('index.html', prediction_text='{}'.format(output[0]))
41+
42+
if __name__ == "__main__":
43+
app.run(debug=True)

‎model.h5

18.9 MB
Binary file not shown.

‎nltk.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
stopwords

‎requirements.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
Flask==1.1.2
2+
numpy==1.18.5
3+
nltk==3.5
4+
tensorflow==2.3.1
5+
scikit-learn==0.23.2
6+
gunicorn==20.0.4

‎sentiment-analysis.ipynb

Lines changed: 482 additions & 0 deletions
Large diffs are not rendered by default.

‎templates/index.html

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
<!DOCTYPE html>
2+
<html >
3+
<head>
4+
<meta charset="UTF-8">
5+
<title>Sentiment Analysis</title>
6+
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
7+
<link href="https://fonts.googleapis.com/css2?family=Roboto" rel='stylesheet' type='text/css'>
8+
<style type="text/css">
9+
body {
10+
background: #232526;
11+
background: -webkit-linear-gradient(to right, #414345, #232526);
12+
background: linear-gradient(to right, #414345, #232526);
13+
font-family: Roboto;
14+
}
15+
.main{
16+
margin-top: 150px;
17+
}
18+
.heading {
19+
color: #EFEFEF;
20+
font-size: 50px;
21+
}
22+
td {
23+
padding: 20px;
24+
}
25+
.senti-label {
26+
color: #fefefe;
27+
}
28+
input[type=text] {
29+
width: 35%;
30+
height: 40px;
31+
border-radius: 10px;
32+
padding: 5px 15px 5px 15px;
33+
border: 0px;
34+
}
35+
input[type=submit] {
36+
display: block;
37+
font-family: 'Open Sans', Helvetica, Arial, sans-serif;
38+
font-weight: 600;
39+
font-size: .75em;
40+
letter-spacing: 1px;
41+
height: 38px;
42+
width: 120px;
43+
line-height: 38px;
44+
overflow: hidden;
45+
background: #4dbecf;
46+
border-radius: 3px;
47+
box-shadow: 0 15px 30px rgba(black,.1);
48+
border: 0;
49+
cursor: pointer;
50+
transition: all .3s ease;
51+
}
52+
progress {
53+
width: 400px;
54+
height: 25px;
55+
background: white;
56+
border-radius: 45px;
57+
padding: 2px;
58+
box-shadow: 0 1px 0px 0 rgba(255, 255, 255, 0.2);
59+
}
60+
progress::-webkit-progress-bar {
61+
background: white;
62+
border-radius: 45px;
63+
padding: 2px;
64+
box-shadow: 0 1px 0px 0 rgba(255, 255, 255, 0.2);
65+
}
66+
progress::-webkit-progress-value{
67+
border-radius: 25px;
68+
box-shadow: inset 0 1px 1px 0 rgba(255, 255, 255, 0.4);
69+
background-size: 250px 25px;
70+
transition: width 2s ease-in-out;
71+
}
72+
.pos::-webkit-progress-value{
73+
background-color: green;
74+
}
75+
.neg::-webkit-progress-value{
76+
background-color: red;
77+
}
78+
</style>
79+
</head>
80+
81+
<body>
82+
<div class="main" align="center">
83+
<h1 class="heading">Sentiment Analysis</h1>
84+
<form action="{{ url_for('predict')}}" method="post">
85+
<input type="text" name="input" placeholder="Enter text to analyse" required="required" /><br><br>
86+
<input type="submit" value="Analyse" id="sub">
87+
</form>
88+
<br>
89+
<br>
90+
91+
<table>
92+
<tr>
93+
<td class="senti-label">Positive Sentiment</td>
94+
<td><progress min=0 max=100 value=100 id="posbar" class="pos"></progress></td>
95+
</tr>
96+
<tr>
97+
<td class="senti-label">Negative Sentiment</td>
98+
<td><progress min=0 max=100 value=100 id="negbar" class="neg"></progress></td>
99+
</tr>
100+
</table>
101+
</div>
102+
103+
<script type="text/javascript">
104+
var val = {{prediction_text}};
105+
document.getElementById('posbar').value = val*100;
106+
document.getElementById('negbar').value = (1-val)*100;
107+
function dis(){
108+
document.getElementById("sub").value = 'Analysing...';
109+
document.getElementById("sub").disabled = true;
110+
}
111+
</script>
112+
</script>
113+
</body>
114+
</html>

‎vectorizer.pickle

2.43 MB
Binary file not shown.

0 commit comments

Comments
 (0)
Please sign in to comment.