package edu.stanford.nlp.sempre.corenlp;
import edu.stanford.nlp.sempre.*;
import edu.stanford.nlp.sempre.LanguageInfo.DependencyEdge;
import edu.stanford.nlp.ling.CoreAnnotations;
import edu.stanford.nlp.ling.IndexedWord;
import edu.stanford.nlp.ling.CoreAnnotations.*;
import edu.stanford.nlp.ling.CoreLabel;
import edu.stanford.nlp.pipeline.Annotation;
import edu.stanford.nlp.pipeline.StanfordCoreNLP;
import edu.stanford.nlp.semgraph.SemanticGraph;
import edu.stanford.nlp.semgraph.SemanticGraphCoreAnnotations;
import edu.stanford.nlp.semgraph.SemanticGraphEdge;
import edu.stanford.nlp.util.CoreMap;
import com.google.common.collect.Lists;
import com.google.common.base.Joiner;
import fig.basic.*;
import java.io.*;
import java.util.*;
/**
* CoreNLPAnalyzer uses Stanford CoreNLP pipeline to analyze an input string utterance
* and return a LanguageInfo object
*
* @author akchou
*/
public class CoreNLPAnalyzer extends LanguageAnalyzer {
public static class Options {
@Option(gloss = "What CoreNLP annotators to run")
public List<String> annotators = Lists.newArrayList("tokenize", "ssplit", "pos", "lemma", "ner", "parse");
@Option(gloss = "Whether to use case-sensitive models")
public boolean caseSensitive = false;
}
public static Options opts = new Options();
// TODO(pliang): don't muck with the POS tag; instead have a separate flag
// for isContent which looks at posTag != "MD" && lemma != "be" && lemma !=
// "have"
// Need to update TextToTextMatcher
private static final String[] AUX_VERB_ARR = new String[] {"is", "are", "was",
"were", "am", "be", "been", "will", "shall", "have", "has", "had",
"would", "could", "should", "do", "does", "did", "can", "may", "might",
"must", "seem"};
private static final Set<String> AUX_VERBS = new HashSet<String>(Arrays.asList(AUX_VERB_ARR));
private static final String AUX_VERB_TAG = "VBD-AUX";
public static StanfordCoreNLP pipeline = null;
public static void initModels() {
if (pipeline != null) return;
Properties props = new Properties();
props.put("annotators", Joiner.on(',').join(opts.annotators));
if (opts.caseSensitive) {
props.put("pos.model", "edu/stanford/nlp/models/pos-tagger/english-bidirectional/english-bidirectional-distsim.tagger");
props.put("ner.model", "edu/stanford/nlp/models/ner/english.all.3class.distsim.crf.ser.gz,edu/stanford/nlp/models/ner/english.conll.4class.distsim.crf.ser.gz");
} else {
props.put("pos.model", "edu/stanford/nlp/models/pos-tagger/english-caseless-left3words-distsim.tagger");
props.put("ner.model", "edu/stanford/nlp/models/ner/english.all.3class.caseless.distsim.crf.ser.gz,edu/stanford/nlp/models/ner/english.conll.4class.caseless.distsim.crf.ser.gz");
}
pipeline = new StanfordCoreNLP(props);
}
// Stanford tokenizer doesn't break hyphens.
// Replace hypens with spaces for utterances like
// "Spanish-speaking countries" but not for "2012-03-28".
public static String breakHyphens(String utterance) {
StringBuilder buf = new StringBuilder(utterance);
for (int i = 0; i < buf.length(); i++) {
if (buf.charAt(i) == '-' && (i + 1 < buf.length() && Character.isLetter(buf.charAt(i + 1))))
buf.setCharAt(i, ' ');
}
return buf.toString();
}
public LanguageInfo analyze(String utterance) {
LanguageInfo languageInfo = new LanguageInfo();
// Clear these so that analyze can hypothetically be called
// multiple times.
languageInfo.tokens.clear();
languageInfo.posTags.clear();
languageInfo.nerTags.clear();
languageInfo.nerValues.clear();
languageInfo.lemmaTokens.clear();
languageInfo.dependencyChildren.clear();
// Break hyphens
utterance = breakHyphens(utterance);
// Run Stanford CoreNLP
initModels();
Annotation annotation = pipeline.process(utterance);
for (CoreLabel token : annotation.get(CoreAnnotations.TokensAnnotation.class)) {
String word = token.get(TextAnnotation.class);
String wordLower = word.toLowerCase();
if (LanguageAnalyzer.opts.lowerCaseTokens) {
languageInfo.tokens.add(wordLower);
} else {
languageInfo.tokens.add(word);
}
languageInfo.posTags.add(
AUX_VERBS.contains(wordLower) ?
AUX_VERB_TAG :
token.get(PartOfSpeechAnnotation.class));
languageInfo.nerTags.add(token.get(NamedEntityTagAnnotation.class));
languageInfo.lemmaTokens.add(token.get(LemmaAnnotation.class));
languageInfo.nerValues.add(token.get(NormalizedNamedEntityTagAnnotation.class));
}
// Fills in a stanford dependency graph for constructing a feature
for (CoreMap sentence : annotation.get(CoreAnnotations.SentencesAnnotation.class)) {
SemanticGraph ccDeps = sentence.get(SemanticGraphCoreAnnotations.CollapsedCCProcessedDependenciesAnnotation.class);
if (ccDeps == null) continue;
int sentenceBegin = sentence.get(CoreAnnotations.TokenBeginAnnotation.class);
// Iterate over all tokens and their dependencies
for (int sourceTokenIndex = sentenceBegin;
sourceTokenIndex < sentence.get(CoreAnnotations.TokenEndAnnotation.class);
sourceTokenIndex++) {
final ArrayList<DependencyEdge> outgoing = new ArrayList<DependencyEdge>();
languageInfo.dependencyChildren.add(outgoing);
IndexedWord node = ccDeps.getNodeByIndexSafe(sourceTokenIndex - sentenceBegin + 1); // + 1 for ROOT
if (node != null) {
for (SemanticGraphEdge edge : ccDeps.outgoingEdgeList(node)) {
final String relation = edge.getRelation().toString();
final int targetTokenIndex = sentenceBegin + edge.getTarget().index() - 1;
outgoing.add(new DependencyEdge(relation, targetTokenIndex));
}
}
}
}
return languageInfo;
}
// Test on example sentence.
public static void main(String[] args) {
CoreNLPAnalyzer analyzer = new CoreNLPAnalyzer();
while (true) {
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
System.out.println("Enter some text:");
String text = reader.readLine();
LanguageInfo langInfo = analyzer.analyze(text);
LogInfo.begin_track("Analyzing \"%s\"", text);
LogInfo.logs("tokens: %s", langInfo.tokens);
LogInfo.logs("lemmaTokens: %s", langInfo.lemmaTokens);
LogInfo.logs("posTags: %s", langInfo.posTags);
LogInfo.logs("nerTags: %s", langInfo.nerTags);
LogInfo.logs("nerValues: %s", langInfo.nerValues);
LogInfo.logs("dependencyChildren: %s", langInfo.dependencyChildren);
LogInfo.end_track();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}