/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package com.meaningcloud.gate;
/**
*
* @author ADRIAN
*/
import com.meaningcloud.gate.clients.SentimentClient;
import com.meaningcloud.gate.param.ASutil;
import com.meaningcloud.gate.param.Serialized_resp;
import gate.Annotation;
import gate.AnnotationSet;
import gate.DocumentContent;
import gate.ProcessingResource;
import gate.creole.AbstractLanguageAnalyser;
import gate.creole.ExecutionException;
import gate.creole.metadata.CreoleParameter;
import gate.creole.metadata.CreoleResource;
import gate.creole.metadata.Optional;
import gate.creole.metadata.RunTime;
import gate.util.InvalidOffsetException;
import gate.util.Out;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.xml.xpath.XPathExpressionException;
/**
* This class is the implementation of the resource MeaningCloud Sentiment Analysis.
*/
@CreoleResource(name = "MeaningCloud Sentiment Analysis", comment = "MeaningCloud Sentiment Analysis", helpURL = "http://www.meaningcloud.com/developer/sentiment-analysis/doc/2.1", icon = "/MeaningCloud.png")
public class MeaningCloudSentiment extends AbstractLanguageAnalyser implements
ProcessingResource {
private String inputASname, outputASname, apiURL, key, lang, model, verbose, egp, rt, uw, dm, sdg, cont, cs, ud;
private boolean debug;
private List<String> annotationTypes = new ArrayList<String>(); // list of
// input
// annotations
// from
// which
// string
// content
// will be
// submitted
private static final int RETRY = 5;
public String textTransform(boolean bool) {
String ret = bool ? "y" : "n";
return ret;
}
@Override
public void execute() throws ExecutionException {
if (document == null)
throw new ExecutionException("No document provided");
AnnotationSet inputAnnSet = document.getAnnotations(inputASname);
AnnotationSet outputAnnSet = document.getAnnotations(outputASname);
String text = "";
String type = "";
DocumentContent content = document.getContent();
if (inputAnnSet.isEmpty()) {
text += content.toString();
// type = "_document";
boolean apiOK = false;
int times = 0;
while (times < RETRY && !apiOK) {
try {
apiOK = processWithMeaningCloud(text, type, null,
outputAnnSet);
if (debug)
Out.println("Nr of retry: " + times + ". Text: " + text);
times++;
} catch (InvalidOffsetException ex) {
Logger.getLogger(MeaningCloudSentiment.class.getName()).log(
Level.SEVERE, null, ex);
} catch (XPathExpressionException ex) {
Logger.getLogger(MeaningCloudSentiment.class.getName()).log(
Level.SEVERE, null, ex);
} catch (UnsupportedEncodingException ex) {
Logger.getLogger(MeaningCloudSentiment.class.getName()).log(
Level.SEVERE, null, ex);
} catch (IOException ex) {
Logger.getLogger(MeaningCloudSentiment.class.getName()).log(
Level.SEVERE, null, ex);
}
}
times = 0;
} else {
if (annotationTypes.size() == 0) {
text += content.toString();
// type = "_document";
boolean apiOK = false;
int times = 0;
while (times < RETRY && !apiOK) {
try {
apiOK = processWithMeaningCloud(text, type, null,
outputAnnSet);
if (debug)
Out.println("Nr of retry: " + times + ". Text: "
+ text);
times++;
} catch (InvalidOffsetException ex) {
Logger.getLogger(MeaningCloudSentiment.class.getName())
.log(Level.SEVERE, null, ex);
} catch (XPathExpressionException ex) {
Logger.getLogger(MeaningCloudSentiment.class.getName())
.log(Level.SEVERE, null, ex);
} catch (UnsupportedEncodingException ex) {
Logger.getLogger(MeaningCloudSentiment.class.getName())
.log(Level.SEVERE, null, ex);
} catch (IOException ex) {
Logger.getLogger(MeaningCloudSentiment.class.getName())
.log(Level.SEVERE, null, ex);
}
}
times = 0;
} else {
if (debug)
Out.println("annotationTypes size: "
+ annotationTypes.size());
for (String inputAnnExpr : annotationTypes) {
if (debug)
Out.println("inputAnnExpr: " + inputAnnExpr);
AnnotationSet filteredAS = ASutil.getFilteredAS(
inputAnnSet, inputAnnExpr);
if (debug)
Out.println("FilteredAS: "
+ gate.Utils.cleanStringFor(document,
filteredAS));
Iterator<Annotation> itr = gate.Utils.inDocumentOrder(
filteredAS).iterator();
while (itr.hasNext()) {
Annotation ann = itr.next();
try {
text = content.getContent(
ann.getStartNode().getOffset(),
ann.getEndNode().getOffset()).toString();
} catch (InvalidOffsetException ex) {
Logger.getLogger(
MeaningCloudSentiment.class.getName()).log(
Level.SEVERE, null, ex);
}
// type = "_"+ann.getType();
boolean apiOK = false;
int times = 0;
while (times < RETRY && !apiOK) {
try {
apiOK = processWithMeaningCloud(text, type, ann,
outputAnnSet);
if (debug)
Out.println("Nr of retry: " + times
+ ". Text: " + text);
times++;
} catch (InvalidOffsetException ex) {
Logger.getLogger(
MeaningCloudSentiment.class.getName())
.log(Level.SEVERE, null, ex);
} catch (XPathExpressionException ex) {
Logger.getLogger(
MeaningCloudSentiment.class.getName())
.log(Level.SEVERE, null, ex);
} catch (UnsupportedEncodingException ex) {
Logger.getLogger(
MeaningCloudSentiment.class.getName())
.log(Level.SEVERE, null, ex);
} catch (IOException ex) {
Logger.getLogger(
MeaningCloudSentiment.class.getName())
.log(Level.SEVERE, null, ex);
}
}
times = 0;
}
}
}
}
}
public boolean processWithMeaningCloud(String text, String type,
Annotation inputAnn, AnnotationSet outputAnnSet)
throws InvalidOffsetException, XPathExpressionException,
MalformedURLException, UnsupportedEncodingException, IOException {
if (inputAnn != null) {
if (debug)
Out.println("Processing: " + inputAnn.getType());
} else {
if (debug)
Out.println("Processing the whole document");
}
// ParserClient c = new ParserClient();
String api = this.getapiURL();
String key = this.getkey();
String txt = text;
if (!txt.isEmpty() && !txt.equals("0")) {
if (debug)
Out.println("Text: " + txt);
Post post;
post = new Post(api);
post.addParameter("src", "gate_2.3");
if (this.getkey() != null && !this.getkey().isEmpty())
post.addParameter("key", key);
else {
Logger.getLogger(MeaningCloudSentiment.class.getName()).severe(
"Key is unset");
return false;
}
post.addParameter("txt", txt);
if (this.getlang() != null && !this.getlang().isEmpty())
post.addParameter("lang", this.getlang());
else {
Logger.getLogger(MeaningCloudSentiment.class.getName()).severe(
"Lang is unset");
return false;
}
if (this.getmodel() != null && !this.getmodel().isEmpty())
post.addParameter("model", this.getmodel());
else {
Logger.getLogger(MeaningCloudSentiment.class.getName()).severe(
"Model is unset");
return false;
}
post.addParameter("of", "json");
if(this.getVerbose() != null && !this.getVerbose().isEmpty())
post.addParameter("verbose", this.getVerbose());
if(this.getEgp() != null && !this.getEgp().isEmpty())
post.addParameter("egp", this.getEgp());
if(this.getRt() != null && !this.getRt().isEmpty())
post.addParameter("rt", this.getRt());
if(this.getUw() != null && !this.getUw().isEmpty())
post.addParameter("uw", this.getUw());
if(this.getDm() != null && !this.getDm().isEmpty())
post.addParameter("dm", this.getDm());
if(this.getSdg() != null && !this.getSdg().isEmpty())
post.addParameter("sdg", this.getSdg());
if(this.getCont() != null && !this.getCont().isEmpty())
post.addParameter("cont", this.getCont());
if(this.getCs() != null && !this.getCs().isEmpty())
post.addParameter("cs", this.getCs());
if(this.getUd() != null && !this.getUd().isEmpty())
post.addParameter("ud", this.getUd());
if (debug)
Logger.getLogger(MeaningCloudSentiment.class.getName()).info(
"" + post.params + "");
byte[] response = post.getResponse().getBytes("UTF-8");
String resp = new String(response, "UTF-8");
if (debug)
Out.println("Response:" + resp);
SentimentClient sClient = new SentimentClient();
Serialized_resp sr = sClient.getResponse(resp);
if (sr.s.code == 0) {
if (sr.annot_list.size() > 0) {
for (Serialized_resp.Annot at : sr.annot_list) {
if (inputAnn != null) {// Inter-sentence offsets are
// added here to the
// intra-sentence offsets
// returned by the API
outputAnnSet.add(inputAnn.getStartNode()
.getOffset() + at.inip, inputAnn
.getStartNode().getOffset() + at.endp,
"sentiment" + type + "_segment", at.fm);
} else {
outputAnnSet.add(at.inip, at.endp, "sentiment"
+ type + "_segment", at.fm);
}
}
} else {
Logger.getLogger(MeaningCloudSentiment.class.getName())
.info("According to the MeaningCloud model you chose, the text you have processed does not contain any sentiment or opinion (no keywords relevant for sentiment analysis have been found).");
}
} else {
Logger.getLogger(MeaningCloudSentiment.class.getName()).severe(
"API Error" + sr.s.toString() + "\n"
+ post.params.toString());
}
}
return true;
}
@RunTime
@Optional
@CreoleParameter(comment = "Input Annotation Set")
public void setinputASname(String inputASname) {
this.inputASname = inputASname;
}
public String getinputASname() {
return inputASname;
}
@RunTime
@Optional
@CreoleParameter(comment = "Filter content by this expression. It allows format: \n"
+ "Type, \n"
+ "Type.FeatureName \n"
+ "or \n"
+ "Type.FeatureName==FeatureValue \n")
public void setannotationTypes(List<String> iat) {
this.annotationTypes = iat;
}
public List<String> getannotationTypes() {
return annotationTypes;
}
@RunTime
@Optional
@CreoleParameter(comment = "Output Annotation Set", defaultValue = "MeaningCloud")
public void setoutputASname(String outputASname) {
this.outputASname = outputASname;
}
public String getoutputASname() {
return outputASname;
}
@RunTime
@CreoleParameter(comment = "URL of the API", defaultValue = "http://api.meaningcloud.com/sentiment-2.1")
public void setapiURL(String apiURL) {
this.apiURL = apiURL;
}
public String getapiURL() {
return apiURL;
}
@RunTime
@CreoleParameter(comment = "License key")
public void setkey(String key) {
this.key = key;
}
public String getkey() {
return key;
}
@RunTime
@CreoleParameter(comment = "Language")
public void setlang(String lang) {
this.lang = lang;
}
public String getlang() {
return lang;
}
@RunTime
@CreoleParameter(defaultValue = "general", comment = "Sentiment model chosen.\n"
+ "The current available models are the following:\n"
+ "\tgeneral: Generic domain\n")
public void setmodel(String model) {
this.model = model;
}
public String getmodel() {
return model;
}
@RunTime
@Optional
@CreoleParameter(defaultValue = "false", comment = "Debug variable for the GATE plugin")
public void setdebug(Boolean verb) {
this.debug = verb;
}
public Boolean getdebug() {
return debug;
}
public String getVerbose() {
return verbose;
}
@RunTime
@Optional
@CreoleParameter(defaultValue = "n", comment = "Verbose mode")
public void setVerbose(String verbose) {
this.verbose = verbose;
}
public String getEgp() {
return egp;
}
@RunTime
@Optional
@CreoleParameter(defaultValue = "n", comment = "Expand global polarity")
public void setEgp(String egp) {
this.egp = egp;
}
public String getRt() {
return rt;
}
@RunTime
@Optional
@CreoleParameter(defaultValue = "n", comment = "Relaxed typography")
public void setRt(String rt) {
this.rt = rt;
}
public String getUw() {
return uw;
}
@RunTime
@Optional
@CreoleParameter(defaultValue = "n", comment = "Deal with unknown words")
public void setUw(String uw) {
this.uw = uw;
}
public String getDm() {
return dm;
}
@RunTime
@Optional
@CreoleParameter(defaultValue = "s", comment = "Disambiguation level")
public void setDm(String dm) {
this.dm = dm;
}
public String getSdg() {
return sdg;
}
@RunTime
@Optional
@CreoleParameter(defaultValue = "l", comment = "Semantic disambiguation grouping")
public void setSdg(String sdg) {
this.sdg = sdg;
}
public String getCont() {
return cont;
}
@RunTime
@Optional
@CreoleParameter(defaultValue = "", comment = "Disambiguation context")
public void setCont(String cont) {
this.cont = cont;
}
public String getCs() {
return cs;
}
@RunTime
@Optional
@CreoleParameter(defaultValue = "n", comment = "Case sensitive concepts")
public void setCs(String cs) {
this.cs = cs;
}
public String getUd() {
return ud;
}
@RunTime
@Optional
@CreoleParameter(defaultValue = "", comment = "User dictionary")
public void setUd(String ud) {
this.ud = ud;
}
} // class MeaningCloudSentiment