Skip to content
Snippets Groups Projects
Commit 3ba3e75f authored by ywb16155's avatar ywb16155
Browse files

commit #45 - Adding sentiment analysis service

parent 1ad81b3a
No related branches found
No related tags found
No related merge requests found
Showing
with 802 additions and 46 deletions
package app.analysis.entailment;
public class EntailmentAnalzser {
}
package app.analysis.sentiment;
import edu.stanford.nlp.ling.CoreAnnotations;
import edu.stanford.nlp.neural.rnn.RNNCoreAnnotations;
import edu.stanford.nlp.pipeline.Annotation;
import edu.stanford.nlp.pipeline.StanfordCoreNLP;
import edu.stanford.nlp.sentiment.SentimentCoreAnnotations;
import edu.stanford.nlp.trees.Tree;
import org.ejml.simple.SimpleMatrix;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
public class SentimentAnalyzer {
private StanfordCoreNLP pipeline;
public SentimentAnalyzer() {
this.initialise();
}
private void initialise() {
Properties properties = new Properties();
properties.setProperty("annotators", "tokenize, ssplit, parse, sentiment");
pipeline = new StanfordCoreNLP(properties);
}
public SentimentResult analyse(String input) {
SentimentClassification classification = new SentimentClassification();
SentimentResult result = new SentimentResult();
if(input != null && input.length() > 0) {
Annotation annotation = pipeline.process(input);
annotation.get(CoreAnnotations.SentencesAnnotation.class).forEach(sentence -> {
Tree tree = sentence.get(SentimentCoreAnnotations.SentimentAnnotatedTree.class);
SimpleMatrix simpleMatrix = RNNCoreAnnotations.getPredictions(tree);
classification.setVeryNegative((int)Math.round(simpleMatrix.get(0)*100d));
classification.setNegative((int)Math.round(simpleMatrix.get(1)*100d));
classification.setNeutral((int)Math.round(simpleMatrix.get(2)*100d));
classification.setPositive((int)Math.round(simpleMatrix.get(3)*100d));
classification.setVeryPositive((int)Math.round(simpleMatrix.get(4)*100d));
String type = sentence.get(SentimentCoreAnnotations.SentimentClass.class);
result.setType(type);
result.setClassification(classification);
result.setScore(RNNCoreAnnotations.getPredictedClass(tree));
});
List<String> words = new ArrayList<>();
//TODO - look at fixing tokenization of punctuation..
annotation.get(CoreAnnotations.TokensAnnotation.class).forEach(word -> {
words.add(word.word());
});
result.setText(words);
}
return result;
}
}
package app.analysis.sentiment;
/*
* "Very negative" = 0
* "Negative" = 1
* "Neutral" = 2
* "Positive" = 3
* "Very positive" = 4
*/
public class SentimentClassification {
private int veryPositive;
private int positive;
private int neutral;
private int negative;
private int veryNegative;
public int getVeryPositive() {
return veryPositive;
}
public void setVeryPositive(int veryPositive) {
this.veryPositive = veryPositive;
}
public int getPositive() {
return positive;
}
public void setPositive(int positive) {
this.positive = positive;
}
public int getNeutral() {
return neutral;
}
public void setNeutral(int neutral) {
this.neutral = neutral;
}
public int getNegative() {
return negative;
}
public void setNegative(int negative) {
this.negative = negative;
}
public int getVeryNegative() {
return veryNegative;
}
public void setVeryNegative(int veryNegative) {
this.veryNegative = veryNegative;
}
}
package app.analysis.sentiment;
import java.util.List;
public class SentimentResult {
private List<String> text;
private String type;
private int score;
private SentimentClassification classification;
public List<String> getText() {
return text;
}
public void setText(List<String> text) {
this.text = text;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public int getScore() {
return score;
}
public void setScore(int score) {
this.score = score;
}
public SentimentClassification getClassification() {
return classification;
}
public void setClassification(SentimentClassification classification) {
this.classification = classification;
}
}
......@@ -5,15 +5,14 @@ import app.entities.MinutePaperEntity;
import app.pojo.PaperDetailsWrapper;
import app.pojo.ResponseGraphDetails;
import app.pojo.StudentGraphDetails;
import app.pojo.WordDetails;
import app.services.ClassInfoService;
import app.services.GraphDataService;
import app.services.LecturerInfoService;
import app.services.SentimentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Map;
......@@ -30,6 +29,9 @@ public class LecturerController {
@Autowired
private GraphDataService graphDataService;
@Autowired
private SentimentService sentimentService;
@PostMapping(value = "/getLecturerClasses",consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseBody
public List<ClassEntity> getClassList(@RequestBody Map<String,String> request) {
......@@ -69,12 +71,20 @@ public class LecturerController {
}
@PostMapping(value = "/getResponseData",consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseBody
public List<ResponseGraphDetails> getResponseData(@RequestBody Map<String,String> request) {
return graphDataService.getResponseGraphData(request.get("username"));
}
@PostMapping(value = "/getStudentResponseData",consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseBody
public List<StudentGraphDetails> getStudentResponseData(@RequestBody Map<String,String> request) {
return graphDataService.getStudentGraphData(request.get("classCode"));
}
@GetMapping(value = "/wordCloudTest", produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseBody
public List<WordDetails> getStudentResponseData() {
return sentimentService.generateWordCloud(39); //TODO - CHANGE TO POSTMAPPING AND ADD CONSUME MEDIATYPE
}
}
......@@ -11,30 +11,30 @@ import org.springframework.context.annotation.Configuration;
@Configuration
public class ConnectorConfig {
@Bean
public TomcatEmbeddedServletContainerFactory servletContainer() {
TomcatEmbeddedServletContainerFactory tomcat = new TomcatEmbeddedServletContainerFactory() {
@Override
protected void postProcessContext(Context context) {
SecurityConstraint securityConstraint = new SecurityConstraint();
securityConstraint.setUserConstraint("CONFIDENTIAL");
SecurityCollection collection = new SecurityCollection();
collection.addPattern("/*");
securityConstraint.addCollection(collection);
context.addConstraint(securityConstraint);
}
};
tomcat.addAdditionalTomcatConnectors(getHttpConnector());
return tomcat;
}
private Connector getHttpConnector() {
Connector connector = new Connector(TomcatEmbeddedServletContainerFactory.DEFAULT_PROTOCOL);
connector.setScheme("http");
connector.setPort(8080);
connector.setSecure(false);
connector.setRedirectPort(8433);
return connector;
}
//
// @Bean
// public TomcatEmbeddedServletContainerFactory servletContainer() {
// TomcatEmbeddedServletContainerFactory tomcat = new TomcatEmbeddedServletContainerFactory() {
// @Override
// protected void postProcessContext(Context context) {
// SecurityConstraint securityConstraint = new SecurityConstraint();
// securityConstraint.setUserConstraint("CONFIDENTIAL");
// SecurityCollection collection = new SecurityCollection();
// collection.addPattern("/*");
// securityConstraint.addCollection(collection);
// context.addConstraint(securityConstraint);
// }
// };
// tomcat.addAdditionalTomcatConnectors(getHttpConnector());
// return tomcat;
// }
//
// private Connector getHttpConnector() {
// Connector connector = new Connector(TomcatEmbeddedServletContainerFactory.DEFAULT_PROTOCOL);
// connector.setScheme("http");
// connector.setPort(8080);
// connector.setSecure(false);
// connector.setRedirectPort(8433);
// return connector;
// }
}
......@@ -85,7 +85,6 @@ public class AnswerEntity {
this.questionId = questionId;
}
public Boolean getSubmitted() {
return this.submitted;
}
......@@ -101,5 +100,16 @@ public class AnswerEntity {
public void setSubmissionDate(Date submissionDate) {
this.submissionDate = submissionDate;
}
public int hashCode() {
return Integer.valueOf(this.paperId).hashCode();
}
public boolean equals(Object obj) {
if (obj instanceof Integer) {
return this.paperId == (Integer) obj;
}
return false;
}
}
package app.pojo;
public class WordDetails {
private int questionId;
private String word;
private int polarity;
private int numberOfOccurrences;
public WordDetails() {
}
public int getQuestionId() {
return questionId;
}
public void setQuestionId(int questionId) {
this.questionId = questionId;
}
public String getWord() {
return word;
}
public void setWord(String word) {
this.word = word;
}
public int getPolarity() {
return polarity;
}
public void setPolarity(int polarity) {
this.polarity = polarity;
}
public int getNumberOfOccurrences() {
return numberOfOccurrences;
}
public void setNumberOfOccurrences(int numberOfOccurrences) {
this.numberOfOccurrences = numberOfOccurrences;
}
}
package app.services;
import app.analysis.sentiment.SentimentAnalyzer;
import app.analysis.sentiment.SentimentResult;
import app.entities.AnswerEntity;
import app.pojo.WordDetails;
import app.repositories.AnswerEntityRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.io.BufferedReader;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Component
public class SentimentService {
@Autowired
private AnswerEntityRepository answerRepo;
public List<WordDetails> generateWordCloud(int paperId) {
List<WordDetails> result = new ArrayList<>();
List<AnswerEntity> answers = answerRepo.findAllByPaperIdAndSubmitted(paperId, true).orElseGet(ArrayList::new);
if(answers.size() > 0) {
List<String> stopwords = getStopwords();
SentimentAnalyzer analyzer = new SentimentAnalyzer();
Map<AnswerEntity, SentimentResult> sentimentResultMap = new HashMap<>();
Map<String, WordDetails> wordcloud = new HashMap<>();
answers.forEach(answerEntity -> sentimentResultMap.put(answerEntity, analyzer.analyse(answerEntity.getAnswerText())));
sentimentResultMap.forEach((k,v) -> {
stopwords.forEach(word -> v.getText().remove(word));
});
sentimentResultMap.forEach((k,v) -> {
v.getText().forEach(word -> {
WordDetails details;
if(wordcloud.get(word) == null) {
details = new WordDetails();
details.setWord(word);
details.setPolarity(v.getScore());
details.setNumberOfOccurrences(1);
details.setQuestionId(k.getQuestionId());
wordcloud.put(word, details);
} else {
details = wordcloud.get(word);
details.setPolarity(calculateScore(details, v.getScore()));
details.setNumberOfOccurrences(details.getNumberOfOccurrences() + 1);
}
});
});
wordcloud.forEach((k,v) -> result.add(v));
}
return result;
}
private int calculateScore(WordDetails currentWord, int score) {
if(score == currentWord.getPolarity()) {
return score;
}
if (score < currentWord.getPolarity()) {
return score + 1;
} else {
return score - 1;
}
}
private List<String> getStopwords() {
List<String> stopwords = new ArrayList<>();
Path path = Paths.get("stopwords.txt");
try (BufferedReader reader = Files.newBufferedReader(path, StandardCharsets.UTF_8)){
String line = null;
while ((line = reader.readLine()) != null) {
stopwords.add(line);
}
} catch (IOException ioe) {
return new ArrayList<>();
}
return stopwords;
}
}
spring.jpa.hibernate.ddl-auto=none
spring.datasource.url=jdbc:mysql://devweb2018.cis.strath.ac.uk:3306/ywb16155
#spring.datasource.url=jdbc:mysql://localhost:3306/ompdb
#spring.datasource.url=jdbc:mysql://devweb2018.cis.strath.ac.uk:3306/ywb16155
spring.datasource.url=jdbc:mysql://localhost:3306/ompdb
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.username=ywb16155
spring.datasource.password=Uir2Imaim7eo
#spring.datasource.username=apiuser
#spring.datasource.password=password
#spring.datasource.username=ywb16155
#spring.datasource.password=Uir2Imaim7eo
spring.datasource.username=apiuser
spring.datasource.password=password
spring.datasource.tomcat.max-active=50
spring.datasource.tomcat.max-idle=10
spring.datasource.tomcat.max-wait=10000
......@@ -13,11 +13,11 @@ spring.jpa.database-platform=org.hibernate.dialect.MySQLDialect
spring.jpa.open-in-view=false
spring.jpa.show-sql=false
server.tomcat.additional-tld-skip-patterns='*.jar'
server.context-path=/ywb16155-root/ompp-api
server.port=8443
server.ssl.enabled=true
server.ssl.key-store-type=PKCS12
server.ssl.key-store=classpath:server.p12
server.ssl.key-store-password=certpassword
server.ssl.key-alias=tomcat
#server.tomcat.additional-tld-skip-patterns='*.jar'
#server.context-path=/ywb16155-root/ompp-api
#server.port=8443
#server.ssl.enabled=true
#server.ssl.key-store-type=PKCS12
#server.ssl.key-store=classpath:server.p12
#server.ssl.key-store-password=certpassword
#server.ssl.key-alias=tomcat
a
about
above
across
after
again
against
all
almost
alone
along
already
also
although
always
among
an
and
another
any
anybody
anyone
anything
anywhere
are
area
areas
around
as
ask
asked
asking
asks
at
away
b
back
backed
backing
backs
be
became
because
become
becomes
been
before
began
behind
being
beings
best
better
between
big
both
but
by
c
came
can
cannot
case
cases
certain
certainly
clear
clearly
come
could
d
did
differ
different
differently
do
does
done
down
down
downed
downing
downs
during
e
each
early
either
end
ended
ending
ends
enough
even
evenly
ever
every
everybody
everyone
everything
everywhere
f
face
faces
fact
facts
far
felt
few
find
finds
first
for
four
from
full
fully
further
furthered
furthering
furthers
g
gave
general
generally
get
gets
give
given
gives
go
going
good
goods
got
great
greater
greatest
group
grouped
grouping
groups
h
had
has
have
having
he
her
here
herself
high
high
high
higher
highest
him
himself
his
how
however
i
if
important
in
interest
interested
interesting
interests
into
is
it
its
itself
j
just
k
keep
keeps
kind
knew
know
known
knows
l
large
largely
last
later
latest
least
less
let
lets
like
likely
long
longer
longest
m
made
make
making
man
many
may
me
member
members
men
might
more
most
mostly
mr
mrs
much
must
my
myself
n
necessary
need
needed
needing
needs
never
new
new
newer
newest
next
no
nobody
non
noone
not
nothing
now
nowhere
number
numbers
o
of
off
often
old
older
oldest
on
once
one
only
open
opened
opening
opens
or
order
ordered
ordering
orders
other
others
our
out
over
p
part
parted
parting
parts
per
perhaps
place
places
point
pointed
pointing
points
possible
present
presented
presenting
presents
problem
problems
put
puts
q
quite
r
rather
really
right
right
room
rooms
s
said
same
saw
say
says
second
seconds
see
seem
seemed
seeming
seems
sees
several
shall
she
should
show
showed
showing
shows
side
sides
since
small
smaller
smallest
so
some
somebody
someone
something
somewhere
state
states
still
still
such
sure
t
take
taken
than
that
the
their
them
then
there
therefore
these
they
thing
things
think
thinks
this
those
though
thought
thoughts
three
through
thus
to
today
together
too
took
toward
turn
turned
turning
turns
two
u
under
until
up
upon
us
use
used
uses
v
very
w
want
wanted
wanting
wants
was
way
ways
we
well
wells
went
were
what
when
where
whether
which
while
who
whole
whose
why
will
with
within
without
work
worked
working
works
would
x
y
year
years
yet
you
young
younger
youngest
your
yours
z
......@@ -3,7 +3,6 @@ import {Chart} from 'angular-highcharts';
import {LecturerInfoService} from 'src/app/services/lecturer-info.service';
import {ResponseGraphDetailsDao} from 'src/app/dao/ResponseGraphDetails.dao';
import {LecturerResponseGraphService} from 'src/app/services/lecturer-response-graph.service';
import {OmpClassDao} from 'src/app/dao/omp-class.dao';
import {StudentGraphDetailsDao} from 'src/app/dao/StudentGraphDetails.dao';
import {Subject} from 'rxjs';
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment