first query somewhat complete
All checks were successful
studiorailgun/trpg/pipeline/head This commit looks good

This commit is contained in:
austin 2024-12-29 22:43:15 -05:00
parent ee5f4eab86
commit 664ea1420e
16 changed files with 377 additions and 12 deletions

View File

@ -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?"
1 utility transfer query imperative sentence
2 1 0 0 0 Hello
3 1 0 0 0 Hi
4 1 0 0 0 Howdy
5 0 0 1 0 What color is your hat?
6 0 0 1 0 Which color is your hat?

View File

@ -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?"
1 utility transfer query imperative sentence
2 1 0 0 0 Hello
3 1 0 0 0 Hi
4 1 0 0 0 Howdy
5 0 0 1 0 What color is your hat?
6 0 0 1 0 Which color is your hat?
7 0 0 1 0 What is the color is your hat?

View File

@ -13,7 +13,7 @@
"relations" : {
"0" : {
"id" : 0,
"name" : "InstanceOf",
"name" : "instanceOf",
"parent" : 0,
"child" : 1
}

View File

@ -16,6 +16,11 @@ public class GoalData {
* Say a greeting
*/
GREET,
/**
* Answer a question
*/
ANSWER,
}
/**

View File

@ -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!");
}
}

View File

@ -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;

View File

@ -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());
}

View File

@ -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!");
}
}

View File

@ -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!");
}
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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();
}
}

View File

@ -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

View File

@ -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());
}
}

View File

@ -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());
}
}

View File

@ -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);
}
}