first query somewhat complete
All checks were successful
studiorailgun/trpg/pipeline/head This commit looks good
All checks were successful
studiorailgun/trpg/pipeline/head This commit looks good
This commit is contained in:
parent
ee5f4eab86
commit
664ea1420e
@ -2,4 +2,5 @@
|
||||
1,0,0,0,"Hello"
|
||||
1,0,0,0,"Hi"
|
||||
1,0,0,0,"Howdy"
|
||||
0,0,1,0,"What color is your hat?"
|
||||
0,0,1,0,"What color is your hat?"
|
||||
0,0,1,0,"Which color is your hat?"
|
||||
|
@ -2,4 +2,6 @@
|
||||
1,0,0,0,"Hello"
|
||||
1,0,0,0,"Hi"
|
||||
1,0,0,0,"Howdy"
|
||||
0,0,1,0,"What color is your hat?"
|
||||
0,0,1,0,"What color is your hat?"
|
||||
0,0,1,0,"Which color is your hat?"
|
||||
0,0,1,0,"What is the color is your hat?"
|
||||
|
@ -13,7 +13,7 @@
|
||||
"relations" : {
|
||||
"0" : {
|
||||
"id" : 0,
|
||||
"name" : "InstanceOf",
|
||||
"name" : "instanceOf",
|
||||
"parent" : 0,
|
||||
"child" : 1
|
||||
}
|
||||
|
||||
@ -16,6 +16,11 @@ public class GoalData {
|
||||
* Say a greeting
|
||||
*/
|
||||
GREET,
|
||||
|
||||
/**
|
||||
* Answer a question
|
||||
*/
|
||||
ANSWER,
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -2,6 +2,7 @@ package org.studiorailgun.conversation.evaluators.goal;
|
||||
|
||||
import org.studiorailgun.conversation.evaluators.goal.GoalData.ConversationGoal;
|
||||
import org.studiorailgun.conversation.evaluators.greet.GreetingData;
|
||||
import org.studiorailgun.conversation.evaluators.query.QueryData;
|
||||
import org.studiorailgun.conversation.tracking.ConvParticipant;
|
||||
import org.studiorailgun.conversation.tracking.Conversation;
|
||||
|
||||
@ -17,11 +18,26 @@ public class GoalEval {
|
||||
*/
|
||||
public static void evaluate(Conversation conversation){
|
||||
GreetingData greetingData = conversation.getGreetingData();
|
||||
GoalData goalData = conversation.getGoalData();
|
||||
QueryData queryData = goalData.getQueryData();
|
||||
ConvParticipant selfParticipant = conversation.getSelf();
|
||||
|
||||
boolean set = false;
|
||||
|
||||
//evaluate if goal should be to greet
|
||||
if(!greetingData.getHaveGreeted().contains(selfParticipant)){
|
||||
conversation.getGoalData().setGoal(ConversationGoal.GREET);
|
||||
} else {
|
||||
conversation.getGoalData().setGoal(null);
|
||||
set = true;
|
||||
}
|
||||
|
||||
//evaluate if goal should be to answer a question
|
||||
if(queryData.getRecentQueries().size() > 0){
|
||||
conversation.getGoalData().setGoal(ConversationGoal.ANSWER);
|
||||
set = true;
|
||||
}
|
||||
|
||||
if(!set){
|
||||
throw new Error("Failed to find a goal to pursue in the conversation!");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,17 +1,12 @@
|
||||
package org.studiorailgun.conversation.evaluators.query;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.studiorailgun.Globals;
|
||||
import org.studiorailgun.conversation.parser.NLPParser;
|
||||
import org.studiorailgun.conversation.parser.PennTreebankTagSet;
|
||||
import org.studiorailgun.conversation.tracking.Conversation;
|
||||
import org.studiorailgun.conversation.tracking.Quote;
|
||||
import org.studiorailgun.knowledge.Node;
|
||||
import org.studiorailgun.knowledge.query.InstanceQuery;
|
||||
import org.studiorailgun.knowledge.query.filter.PossessionQueryFilter;
|
||||
|
||||
import edu.stanford.nlp.ling.IndexedWord;
|
||||
import edu.stanford.nlp.semgraph.SemanticGraph;
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
package org.studiorailgun.conversation.evaluators.synthesis;
|
||||
|
||||
import org.studiorailgun.conversation.evaluators.greet.GreetingEval;
|
||||
import org.studiorailgun.conversation.evaluators.transfer.TransferEval;
|
||||
import org.studiorailgun.conversation.tracking.Conversation;
|
||||
import org.studiorailgun.conversation.tracking.Quote;
|
||||
|
||||
@ -21,6 +22,9 @@ public class ResponseEval {
|
||||
response = GreetingEval.constructGreeting(conversation);
|
||||
conversation.getGreetingData().getHaveGreeted().add(conversation.getSelf());
|
||||
} break;
|
||||
case ANSWER: {
|
||||
response = TransferEval.synthesize(conversation);
|
||||
} break;
|
||||
default: {
|
||||
throw new UnsupportedOperationException("Unsupported conversation goal! " + conversation.getGoalData().getGoal());
|
||||
}
|
||||
|
||||
@ -0,0 +1,99 @@
|
||||
package org.studiorailgun.conversation.evaluators.transfer;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.Set;
|
||||
|
||||
import org.studiorailgun.conversation.evaluators.query.NounStack;
|
||||
import org.studiorailgun.conversation.parser.NLPParser;
|
||||
import org.studiorailgun.conversation.parser.PennTreebankTagSet;
|
||||
import org.studiorailgun.conversation.tracking.Conversation;
|
||||
import org.studiorailgun.conversation.tracking.Quote;
|
||||
|
||||
import edu.stanford.nlp.ling.IndexedWord;
|
||||
import edu.stanford.nlp.semgraph.SemanticGraph;
|
||||
|
||||
/**
|
||||
* Synthesizes an answer to a question
|
||||
*/
|
||||
public class AnswerSynthesis {
|
||||
|
||||
|
||||
/**
|
||||
* Evaluates a quote
|
||||
* @param conversation The conversation
|
||||
* @param quote The quote
|
||||
*/
|
||||
public static Quote evaluate(Conversation conversation, Quote query){
|
||||
NLPParser.parse(query);
|
||||
SemanticGraph semanticGraph = query.getGraph();
|
||||
if(semanticGraph.getRoots().size() > 1){
|
||||
String message = "Multiple roots to sentence!\n" +
|
||||
"\"" + query.getRaw() + "\"\n" +
|
||||
semanticGraph;
|
||||
throw new UnsupportedOperationException(message);
|
||||
}
|
||||
IndexedWord root = semanticGraph.getFirstRoot();
|
||||
if(PennTreebankTagSet.isVerb(root.tag())){
|
||||
if(PennTreebankTagSet.isBe(root.tag())){
|
||||
String answerRaw = AnswerSynthesis.evaluateBe(conversation, query);
|
||||
Quote quote = new Quote(answerRaw);
|
||||
return quote;
|
||||
} else {
|
||||
String message = "Unsupported root verb type!\n" +
|
||||
"\"" + query.getRaw() + "\"\n" +
|
||||
semanticGraph;
|
||||
throw new UnsupportedOperationException(message);
|
||||
}
|
||||
} else {
|
||||
String message = "Unsupported root type!\n" +
|
||||
"\"" + query.getRaw() + "\"\n" +
|
||||
semanticGraph;
|
||||
throw new UnsupportedOperationException(message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluates an equivalence query
|
||||
* @param conversation The conversation
|
||||
* @param quote The quote
|
||||
*/
|
||||
private static String evaluateBe(Conversation conversation, Quote quote){
|
||||
//get the two things we're comparing
|
||||
SemanticGraph graph = quote.getGraph();
|
||||
IndexedWord root = graph.getFirstRoot();
|
||||
Set<IndexedWord> children = graph.getChildren(root);
|
||||
Iterator<IndexedWord> iterator = children.iterator();
|
||||
IndexedWord firstItem = iterator.next();
|
||||
IndexedWord secondItem = iterator.next();
|
||||
NounStack firstNoun = NounStack.parse(graph, firstItem);
|
||||
NounStack secondNoun = NounStack.parse(graph, secondItem);
|
||||
|
||||
//interrogative error checking
|
||||
if(firstNoun.getInterrogative() != null && secondNoun.getInterrogative() != null){
|
||||
String message = "Comparing two interrogatives!";
|
||||
throw new Error(message);
|
||||
}
|
||||
|
||||
//handle interrogative solving
|
||||
if(firstNoun.getInterrogative() != null || secondNoun.getInterrogative() != null){
|
||||
NounStack interrogativeStack = firstNoun.getInterrogative() != null ? firstNoun : secondNoun;
|
||||
NounStack qualifierStack = firstNoun.getInterrogative() != null ? secondNoun : firstNoun;
|
||||
|
||||
switch(interrogativeStack.getInterrogative().toLowerCase()){
|
||||
case "which": {
|
||||
return Interrogative.evalWhichQuery(conversation, quote, interrogativeStack, qualifierStack);
|
||||
}
|
||||
case "what": {
|
||||
return Interrogative.evalWhatQuery(conversation, quote, interrogativeStack, qualifierStack);
|
||||
}
|
||||
default : {
|
||||
throw new Error("Unhandled interrogative type! " + interrogativeStack.getInterrogative().toLowerCase());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
throw new Error("Failed to synthesize answer!");
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,90 @@
|
||||
package org.studiorailgun.conversation.evaluators.transfer;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.studiorailgun.Globals;
|
||||
import org.studiorailgun.conversation.evaluators.query.NounStack;
|
||||
import org.studiorailgun.conversation.synthesis.NounStackSynthesizer;
|
||||
import org.studiorailgun.conversation.synthesis.QualitySynthesizer;
|
||||
import org.studiorailgun.conversation.tracking.Conversation;
|
||||
import org.studiorailgun.conversation.tracking.Quote;
|
||||
import org.studiorailgun.knowledge.Node;
|
||||
import org.studiorailgun.knowledge.query.InstanceQuery;
|
||||
import org.studiorailgun.knowledge.query.QualiaQuery;
|
||||
import org.studiorailgun.knowledge.query.filter.InstanceQueryFilter;
|
||||
import org.studiorailgun.knowledge.query.filter.PossessionQueryFilter;
|
||||
|
||||
/**
|
||||
* Interrogatives available
|
||||
*/
|
||||
public class Interrogative {
|
||||
|
||||
/**
|
||||
* Evaluates a query of "which"
|
||||
* @param conversation The conversation
|
||||
* @param quote The quote
|
||||
* @param interrogative The interrogative noun
|
||||
* @param items The items noun
|
||||
* @return null
|
||||
*/
|
||||
public static String evalWhichQuery(Conversation conversation, Quote quote, NounStack interrogative, NounStack items){
|
||||
|
||||
//get the thing that has the quality
|
||||
if(QualiaQuery.isQualiaClarificationQuery(interrogative)){
|
||||
Node finalQualifier = InstanceQuery.getConcept(items.getIndexedWord().originalText());
|
||||
if(items.getPossessive() != null){
|
||||
List<Node> qualifierInstances = InstanceQuery.getInstances(finalQualifier);
|
||||
finalQualifier = PossessionQueryFilter.withPossessor(qualifierInstances, Globals.web.getAnchors().getSelfNode());
|
||||
}
|
||||
|
||||
//get the actual qualities that we care about
|
||||
List<Node> qualiaOfInstance = QualiaQuery.getQualiaOfInstance(finalQualifier);
|
||||
Node qualiaType = QualiaQuery.getRequestedQualiaType(interrogative);
|
||||
List<Node> applicableQualities = InstanceQueryFilter.filter(qualiaOfInstance, qualiaType);
|
||||
|
||||
//synthesize
|
||||
String subject = NounStackSynthesizer.synthesize(finalQualifier, items.getPossessive() != null);
|
||||
String verb = "is";
|
||||
String object = QualitySynthesizer.synthesize(applicableQualities, qualiaType);
|
||||
|
||||
return subject + " " + verb + " " + object;
|
||||
} else {
|
||||
throw new Error("Unknown query type!");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluates a query of "what"
|
||||
* @param conversation The conversation
|
||||
* @param quote The quote
|
||||
* @param interrogative The interrogative noun
|
||||
* @param items The items noun
|
||||
* @return null
|
||||
*/
|
||||
public static String evalWhatQuery(Conversation conversation, Quote quote, NounStack interrogative, NounStack items){
|
||||
if(QualiaQuery.isQualiaClarificationQuery(interrogative)){
|
||||
|
||||
//get the thing that has the quality
|
||||
Node finalQualifier = InstanceQuery.getConcept(items.getIndexedWord().originalText());
|
||||
if(items.getPossessive() != null){
|
||||
List<Node> qualifierInstances = InstanceQuery.getInstances(finalQualifier);
|
||||
finalQualifier = PossessionQueryFilter.withPossessor(qualifierInstances, Globals.web.getAnchors().getSelfNode());
|
||||
}
|
||||
|
||||
//get the actual qualities that we care about
|
||||
List<Node> qualiaOfInstance = QualiaQuery.getQualiaOfInstance(finalQualifier);
|
||||
Node qualiaType = QualiaQuery.getRequestedQualiaType(interrogative);
|
||||
List<Node> applicableQualities = InstanceQueryFilter.filter(qualiaOfInstance, qualiaType);
|
||||
|
||||
//synthesize
|
||||
String subject = NounStackSynthesizer.synthesize(finalQualifier, items.getPossessive() != null);
|
||||
String verb = "is";
|
||||
String object = QualitySynthesizer.synthesize(applicableQualities, qualiaType);
|
||||
|
||||
return subject + " " + verb + " " + object;
|
||||
} else {
|
||||
throw new Error("Unknown query type!");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,33 @@
|
||||
package org.studiorailgun.conversation.evaluators.transfer;
|
||||
|
||||
import org.studiorailgun.conversation.evaluators.goal.GoalData;
|
||||
import org.studiorailgun.conversation.tracking.Conversation;
|
||||
import org.studiorailgun.conversation.tracking.Quote;
|
||||
|
||||
/**
|
||||
* Evaluation for transfer quotes
|
||||
*/
|
||||
public class TransferEval {
|
||||
|
||||
|
||||
/**
|
||||
* Synthesizes an information transfer quote
|
||||
* @param conversation The conversation
|
||||
* @return The quote
|
||||
*/
|
||||
public static Quote synthesize(Conversation conversation){
|
||||
Quote response = null;
|
||||
GoalData goalData = conversation.getGoalData();
|
||||
switch(goalData.getGoal()){
|
||||
case ANSWER: {
|
||||
Quote questionToAnswer = goalData.getQueryData().getRecentQueries().remove(0);
|
||||
response = AnswerSynthesis.evaluate(conversation, questionToAnswer);
|
||||
} break;
|
||||
case GREET: {
|
||||
throw new Error("Unsupported goal type for information transfer! " + goalData.getGoal());
|
||||
}
|
||||
}
|
||||
return response;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,21 @@
|
||||
package org.studiorailgun.conversation.synthesis;
|
||||
|
||||
import org.studiorailgun.knowledge.Node;
|
||||
|
||||
/**
|
||||
* Synthesizes text for a noun stack
|
||||
*/
|
||||
public class NounStackSynthesizer {
|
||||
|
||||
/**
|
||||
* Synthesizes a noun to describe this node
|
||||
* @param noun The node
|
||||
* @return The synthesized text
|
||||
*/
|
||||
public static String synthesize(Node node, boolean possessive){
|
||||
String rVal = "";
|
||||
|
||||
return rVal;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,42 @@
|
||||
package org.studiorailgun.conversation.synthesis;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.studiorailgun.knowledge.Node;
|
||||
|
||||
/**
|
||||
* Quality noun synthesizers
|
||||
*/
|
||||
public class QualitySynthesizer {
|
||||
|
||||
/**
|
||||
* Synthesizes a noun to describe a quality
|
||||
* @param nodes The collection of nodes that are the quality
|
||||
* @param quality The type of quality (color, time, weight, etc)
|
||||
* @return The text of the noun
|
||||
*/
|
||||
public static String synthesize(List<Node> nodes, Node quality){
|
||||
switch(quality.getName()){
|
||||
case "Color":
|
||||
case "color": {
|
||||
return summarizeColor(nodes);
|
||||
}
|
||||
default: {
|
||||
throw new Error("Unhandled quality type! " + quality.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sumarizes a set of colors into text
|
||||
* @param nodes The colors
|
||||
* @return The text
|
||||
*/
|
||||
private static String summarizeColor(List<Node> nodes){
|
||||
if(nodes.size() < 1){
|
||||
throw new Error("No colors available!");
|
||||
}
|
||||
return nodes.get(0).getName();
|
||||
}
|
||||
|
||||
}
|
||||
@ -43,6 +43,11 @@ public class KnowledgeWeb {
|
||||
*/
|
||||
transient Map<Node,List<Relation>> parentRelations;
|
||||
|
||||
/**
|
||||
* Map of node -> relations where that node is the child
|
||||
*/
|
||||
transient Map<Node,List<Relation>> childRelations;
|
||||
|
||||
/**
|
||||
* The anchor nodes
|
||||
*/
|
||||
@ -61,6 +66,7 @@ public class KnowledgeWeb {
|
||||
this.relations = new HashMap<Integer,Relation>();
|
||||
this.typeRelationLookup = new HashMap<String,List<Integer>>();
|
||||
this.parentRelations = new HashMap<Node,List<Relation>>();
|
||||
this.childRelations = new HashMap<Node,List<Relation>>();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -100,6 +106,7 @@ public class KnowledgeWeb {
|
||||
}
|
||||
//populate lookup acceleration structures
|
||||
for(Relation relation : rVal.relations.values()){
|
||||
//parent->relation map
|
||||
Node parent = relation.getParent();
|
||||
if(rVal.parentRelations.containsKey(parent)){
|
||||
List<Relation> relations = rVal.parentRelations.get(parent);
|
||||
@ -109,6 +116,17 @@ public class KnowledgeWeb {
|
||||
relations.add(relation);
|
||||
rVal.parentRelations.put(parent,relations);
|
||||
}
|
||||
|
||||
//child->relation map
|
||||
Node child = relation.getChild();
|
||||
if(rVal.childRelations.containsKey(child)){
|
||||
List<Relation> relations = rVal.childRelations.get(child);
|
||||
relations.add(relation);
|
||||
} else {
|
||||
List<Relation> relations = new LinkedList<Relation>();
|
||||
relations.add(relation);
|
||||
rVal.childRelations.put(child,relations);
|
||||
}
|
||||
}
|
||||
//error check that all anchors are defined
|
||||
Globals.web.getAnchors().errorCheck();
|
||||
@ -296,6 +314,19 @@ public class KnowledgeWeb {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the relations where the provided node is the parent of the relationship
|
||||
* @param node The node
|
||||
* @return The list of relations
|
||||
*/
|
||||
public List<Relation> getRelationsOfChildNode(Node node){
|
||||
if(this.childRelations.containsKey(node)){
|
||||
return this.childRelations.get(node);
|
||||
} else {
|
||||
return new LinkedList<Relation>();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the anchor nodes for the web
|
||||
* @return The anchor nodes
|
||||
|
||||
@ -44,7 +44,7 @@ public class QualiaQuery {
|
||||
* @return The qualia
|
||||
*/
|
||||
public static List<Node> getQualiaOfInstance(Node inst){
|
||||
return Globals.web.getRelationsOfParentNode(inst).stream().filter(relation -> relation.getName().equals(RelationTypes.QUALIA_OF)).map(relation -> relation.getChild()).collect(Collectors.toList());
|
||||
return Globals.web.getRelationsOfChildNode(inst).stream().filter(relation -> relation.getName().equals(RelationTypes.QUALIA_OF)).map(relation -> relation.getParent()).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -0,0 +1,25 @@
|
||||
package org.studiorailgun.knowledge.query.filter;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.studiorailgun.knowledge.Node;
|
||||
import org.studiorailgun.knowledge.query.InstanceQuery;
|
||||
|
||||
/**
|
||||
* Filter nodes to just instances of a specific node
|
||||
*/
|
||||
public class InstanceQueryFilter {
|
||||
|
||||
/**
|
||||
* Filters nodes to just those that are instanced of the category
|
||||
* @param collection The collection of nodes
|
||||
* @param category The category to filter to
|
||||
* @return The list of ndoes within that category
|
||||
*/
|
||||
public static List<Node> filter(List<Node> collection, Node category){
|
||||
List<Node> categoryInstances = InstanceQuery.getInstances(category);
|
||||
return collection.stream().filter(node -> categoryInstances.contains(node)).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
}
|
||||
@ -17,7 +17,8 @@ public class QueryTests {
|
||||
|
||||
Quote response = ConvAI.simFrame("What color is your hat?");
|
||||
|
||||
// assertEquals(response.getRaw(), "Blue");
|
||||
boolean responseContainsBlue = response.getRaw().contains("Blue");
|
||||
assertEquals(responseContainsBlue, true);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user