edu.cmu.sv.semantics.SemanticsModel Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of yoda Show documentation
Show all versions of yoda Show documentation
A library that allows rapid prototyping of dialog systems (language understanding, discourse modelling, dialog management, language generation).
package edu.cmu.sv.semantics;
import edu.cmu.sv.database.Ontology;
import edu.cmu.sv.dialog_management.DialogRegistry;
import edu.cmu.sv.spoken_language_understanding.Tokenizer;
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.apache.commons.lang3.tuple.Pair;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
import java.util.*;
import java.util.stream.Collectors;
/**
* Created by David Cohen on 8/27/14.
*
* A hierarchical slot-filling model.
* Used to represent utterance / discourse unit meaning.
* Uses a JSON object as the internal representation.
*
*/
public class SemanticsModel {
private static final JSONParser parser = new JSONParser();
JSONObject internalRepresentation;
public SemanticsModel(String jsonSource) {
internalRepresentation = parseJSON(jsonSource);
}
public SemanticsModel(JSONObject internalRepresentation){this.internalRepresentation = internalRepresentation;}
public SemanticsModel(){
internalRepresentation = new JSONObject();
}
public JSONObject getInternalRepresentation() {
return internalRepresentation;
}
public SemanticsModel deepCopy(){
SemanticsModel ans = new SemanticsModel();
ans.internalRepresentation = parseJSON(internalRepresentation.toJSONString());
return ans;
}
public void extendAndOverwrite(SemanticsModel other){
extendAndOverwriteHelper(internalRepresentation, other.internalRepresentation);
}
/*
* (extend because original content should remain as long as it doesn't conflict with the new content)
* Copy the contents of other on top of what is already in initial.
* Overwrite slots that conflict.
* The class UnknownThingWithRoles does not overwrite any other class,
* any other class overwrites UnknownThingWithRoles without considering it to be a conflict.
*
* This calls itself on children so that current nested content isn't erased unless there is a conflict.
* */
void extendAndOverwriteHelper(JSONObject initial, final JSONObject other){
if (other.containsKey("class") && (other.get("class").equals("And") || other.get("class").equals("Or"))){
throw new Error("Not Yet Implemented: SemanticsModel.extendAndOverwriteHelper with conjunctions in other JSON object");
}
if (initial.containsKey("class") && (initial.get("class").equals("And") || initial.get("class").equals("Or"))){
throw new Error("Not Yet Implemented: SemanticsModel.extendAndOverwriteHelper with conjunctions in internal JSON object");
}
if (other.containsKey("class") && !other.get("class").equals("UnknownThingWithRoles")){
initial.put("class", other.get("class"));
}
for (Object key : other.keySet()){
if ("class".equals(key))
continue;
if (!initial.containsKey(key)){
initial.put(key, other.get(key));
} else {
if (other.get(key) instanceof String){
initial.put(key, other.get(key));
} else if ((initial.get(key) instanceof JSONObject) &&
(other.get(key) instanceof JSONObject)){
extendAndOverwriteHelper(((JSONObject) initial.get(key)), ((JSONObject) other.get(key)));
}
}
}
}
void extendAndOverwriteAtPointHelper(String slotPath, Object currentPoint, JSONObject insertionContent){
if (currentPoint==null){
throw new Error("Can not extend null");
} else if (currentPoint instanceof String){
throw new Error("Can not extend a String");
} else if (currentPoint instanceof JSONObject){
if (slotPath.equals("")) {
extendAndOverwriteHelper((JSONObject)currentPoint, insertionContent);
return;
}
String[] fillerPath = slotPath.split("\\.");
String thisFiller = fillerPath[0];
List remainingFillers = new LinkedList<>(Arrays.asList(fillerPath));
remainingFillers.remove(0);
String remainingSlotPath = String.join(".", remainingFillers);
if (((JSONObject) currentPoint).containsKey("class") &&
(((JSONObject) currentPoint).get("class").equals("Or") ||
((JSONObject) currentPoint).get("class").equals("And"))){
JSONArray nestedArray = (JSONArray) ((JSONObject) currentPoint).get("HasValues");
for (Object child : nestedArray){
extendAndOverwriteAtPointHelper(slotPath, child, insertionContent);
}
} else {
extendAndOverwriteAtPointHelper(remainingSlotPath, ((JSONObject) currentPoint).get(thisFiller),
insertionContent);
}
} else {
assert false;
}
}
public void filterOutLeafSlot(String slot){
Set internalPaths = getAllInternalNodePaths();
for (String path: internalPaths){
JSONObject node = (JSONObject)newGetSlotPathFiller(path);
if (node.containsKey(slot))
node.remove(slot);
}
}
/*
* Extend other and overwrite what is there currently at the point specified by slotPath
*
* If slotPath filler is null or a String, throw an error
* If slotPath filler is a single point, insert and overwrite at that point
* If slotPath filler is a conjunction, insert and overwrite at all the points
*
* */
public void extendAndOverwriteAtPoint(String slotPath, SemanticsModel other){
extendAndOverwriteAtPointHelper(slotPath, internalRepresentation, other.internalRepresentation);
}
/*
* Returns:
*
* 1) A JSONObject directly copied from this if slotPath path refers to a non-ambiguous non-leaf node
* 2) A String if slotPath refers to a non-ambiguous leaf node
* 3) An OR node if the level of ambiguity closest to the root is an OR ambiguity
* 4) Same as above, replace OR with AND
* 5) null if the path is invalid
*
* */
//TODO: deal with null after conjunctions
private static Object getSlotPathFillerHelper(Object startingPoint, String slotPath){
if (slotPath.equals(""))
return startingPoint;
String[] fillerPath = slotPath.split("\\.");
String thisFiller = fillerPath[0];
List remainingFillers = new LinkedList<>(Arrays.asList(fillerPath));
remainingFillers.remove(0);
String remainingSlotPath = String.join(".", remainingFillers);
if (!(startingPoint instanceof JSONObject))
return null;
if (((JSONObject) startingPoint).containsKey("class") &&
(((JSONObject) startingPoint).get("class").equals("Or") ||
((JSONObject) startingPoint).get("class").equals("And"))){
JSONObject ans = new JSONObject();
JSONArray ansArray = new JSONArray();
ans.put("class", ((JSONObject) startingPoint).get("class"));
JSONArray nestedArray = (JSONArray) ((JSONObject) startingPoint).get("HasValues");
for (Object child : nestedArray){
ansArray.add(getSlotPathFillerHelper(child, slotPath));
}
ans.put("HasValues", ansArray);
return ans;
} else {
return getSlotPathFillerHelper(((JSONObject) startingPoint).get(thisFiller), remainingSlotPath);
}
}
/*
* Returns a String, null, or a JSONObject
* */
public Object newGetSlotPathFiller(String slotPath){
Object ans = getSlotPathFillerHelper(internalRepresentation, slotPath);
return ans;
}
public static void putAtPath(JSONObject source, String slotPath, Object insertContent){
if (!slotPath.contains("."))
source.put(slotPath, insertContent);
else {
String[] fillerPath = slotPath.split("\\.");
String thisFiller = fillerPath[0];
List remainingFillers = new LinkedList<>(Arrays.asList(fillerPath));
remainingFillers.remove(0);
String remainingSlotPath = String.join(".", remainingFillers);
putAtPath((JSONObject) source.get(thisFiller), remainingSlotPath, insertContent);
}
}
public Set