From 0f5abe384f6a334c3255ab2a8ff376e46cb1fda6 Mon Sep 17 00:00:00 2001 From: austin Date: Tue, 31 Dec 2024 18:11:13 -0500 Subject: [PATCH] learnable quality, possession working, web fixes --- .../evaluators/transfer/TransferEval.java | 10 +++++ .../ai/conversation/web/ArgumentQuery.java | 13 ++++-- .../ai/conversation/web/MetaQuery.java | 43 +++++++++++++++++++ .../ai/conversation/web/QuoteQuery.java | 33 +++++++------- .../ai/knowledge/KnowledgeWeb.java | 28 ++++++++++++ .../ai/knowledge/query/InstanceQuery.java | 9 ++++ .../ai/knowledge/query/PossessionQuery.java | 12 ++++++ .../ai/knowledge/types/RelationTypes.java | 1 - .../transfer/TransferEvaluationTests.java | 2 + 9 files changed, 131 insertions(+), 20 deletions(-) create mode 100644 src/main/java/org/studiorailgun/ai/conversation/web/MetaQuery.java diff --git a/src/main/java/org/studiorailgun/ai/conversation/evaluators/transfer/TransferEval.java b/src/main/java/org/studiorailgun/ai/conversation/evaluators/transfer/TransferEval.java index 08c20e4..7bd9663 100644 --- a/src/main/java/org/studiorailgun/ai/conversation/evaluators/transfer/TransferEval.java +++ b/src/main/java/org/studiorailgun/ai/conversation/evaluators/transfer/TransferEval.java @@ -9,6 +9,7 @@ import org.studiorailgun.ai.conversation.tracking.Conversation; import org.studiorailgun.ai.conversation.tracking.Quote; import org.studiorailgun.ai.conversation.tracking.Sentence; import org.studiorailgun.ai.conversation.web.ArgumentQuery; +import org.studiorailgun.ai.conversation.web.MetaQuery; import org.studiorailgun.ai.knowledge.Node; import edu.stanford.nlp.ling.IndexedWord; @@ -101,6 +102,15 @@ public class TransferEval { throw new Error("Error querying object!"); } //make an equivalence link here if it doesn't exist already + if(MetaQuery.isLearnable(subjectNode)){ + + } else if(MetaQuery.isLearnable(objectNode)){ + + } else { + String message = "Information already stored?\n" + + sentence.getGraph(); + throw new Error(message); + } //for the moment, assume the other noun is a concept diff --git a/src/main/java/org/studiorailgun/ai/conversation/web/ArgumentQuery.java b/src/main/java/org/studiorailgun/ai/conversation/web/ArgumentQuery.java index e077b0b..49051bb 100644 --- a/src/main/java/org/studiorailgun/ai/conversation/web/ArgumentQuery.java +++ b/src/main/java/org/studiorailgun/ai/conversation/web/ArgumentQuery.java @@ -10,6 +10,7 @@ import org.studiorailgun.ai.conversation.tracking.Quote; import org.studiorailgun.ai.knowledge.Node; import org.studiorailgun.ai.knowledge.Relation; import org.studiorailgun.ai.knowledge.query.InstanceQuery; +import org.studiorailgun.ai.knowledge.query.PossessionQuery; import org.studiorailgun.ai.knowledge.types.RelationTypes; import org.studiorailgun.ai.linguistics.ProperNounQuery; import org.studiorailgun.ai.philosophy.ConceptQuery; @@ -55,7 +56,7 @@ public class ArgumentQuery { * @return The node that represents the possession modifier applied to the root node */ private static Node getPossessionModified(Quote quote, Node rootNode, Argument argument){ - Node rVal = rootNode; + Node speaker = QuoteQuery.getSpeaker(quote.getNode()); String possessionModifier = argument.getPossessiveModifier().originalText().toLowerCase(); switch(possessionModifier){ case "my": { @@ -67,19 +68,23 @@ public class ArgumentQuery { }).collect(Collectors.toList()); if(possessedInstances.size() == 1){ //already exists, return it - rVal = possessedInstances.get(0); + return possessedInstances.get(0); } else if(possessedInstances.size() > 1) { //already exists, return it throw new Error("Can't currently handle plural instances!"); } else { //does not already exist, see if we can generate a node to encapsulate it + Node newInstance = Globals.web.createNode(rootNode.getName() + "(inst)"); + InstanceQuery.setInstance(rootNode, newInstance); // ie (inst) <--instanceOf-- "name" + MetaQuery.flagAsLearnable(newInstance); // ie (inst) <--qualityOf-- "learnable" + PossessionQuery.setPossessor(speaker, newInstance); // ie (inst) <--possessionOf-- (person instance) + return newInstance; } - } break; + } default: { throw new Error("Unsupported possession modifier! " + possessionModifier); } } - return rVal; } } diff --git a/src/main/java/org/studiorailgun/ai/conversation/web/MetaQuery.java b/src/main/java/org/studiorailgun/ai/conversation/web/MetaQuery.java new file mode 100644 index 0000000..dd1c876 --- /dev/null +++ b/src/main/java/org/studiorailgun/ai/conversation/web/MetaQuery.java @@ -0,0 +1,43 @@ +package org.studiorailgun.ai.conversation.web; + +import java.util.List; +import java.util.stream.Collectors; + +import org.studiorailgun.Globals; +import org.studiorailgun.ai.knowledge.Node; +import org.studiorailgun.ai.knowledge.Relation; +import org.studiorailgun.ai.knowledge.types.RelationTypes; + +/** + * Queries about meta information about nodes + */ +public class MetaQuery { + + /** + * Flags a node as learnable + * @param node The node + */ + public static void flagAsLearnable(Node node){ + Node learnable = Globals.web.getAnchors().getLearnableNode(); + Globals.web.createRelation(RelationTypes.QUALITY_OF, learnable, node); + } + + /** + * Checks if this is a learnable node + * @param node The node + * @return true if it is learnable, false otherwise + */ + public static boolean isLearnable(Node node){ + Node learnableNode = Globals.web.getAnchors().getLearnableNode(); + List relations = Globals.web.getRelationsOfChildNode(node); + List discoveredLearnable = relations.stream() + .filter(relation -> relation.getName().equals(RelationTypes.QUALITY_OF)) + .map(relation -> relation.getParent()) + .filter(parentNode -> parentNode.equals(learnableNode)) + .collect(Collectors.toList()); + return discoveredLearnable.size() > 0; + } + + + +} diff --git a/src/main/java/org/studiorailgun/ai/conversation/web/QuoteQuery.java b/src/main/java/org/studiorailgun/ai/conversation/web/QuoteQuery.java index 84bc8a0..529d3b9 100644 --- a/src/main/java/org/studiorailgun/ai/conversation/web/QuoteQuery.java +++ b/src/main/java/org/studiorailgun/ai/conversation/web/QuoteQuery.java @@ -5,7 +5,6 @@ import java.util.stream.Collectors; import org.studiorailgun.Globals; import org.studiorailgun.ai.knowledge.Node; -import org.studiorailgun.ai.knowledge.Relation; import org.studiorailgun.ai.knowledge.types.RelationTypes; /** @@ -22,6 +21,24 @@ public class QuoteQuery { Globals.web.createRelation(RelationTypes.QUOTE_OF, speaker, quote); } + /** + * Gets the speaker of a quote + * @param quote The quote + * @return The speaker of the quote + */ + public static Node getSpeaker(Node quote){ + List speaker = Globals.web.getRelationsOfChildNode(quote).stream() + .filter(relation -> relation.getName().equals(RelationTypes.QUOTE_OF)) + .map(relation -> relation.getParent()) + .collect(Collectors.toList()); + if(speaker.size() == 0){ + throw new Error("No speaker defined!"); + } else if(speaker.size() > 1){ + throw new Error("Unhandled number of speakers! " + speaker.size()); + } + return speaker.get(0); + } + /** * Assigns a conversation to a quote * @param conversation The conversation @@ -31,18 +48,4 @@ public class QuoteQuery { Globals.web.createRelation(RelationTypes.MEMBER_OF, conversation, quote); } - /** - * Gets the speaker of a quote - * @param quote The quote - * @return The speaker of the quote - */ - public static Node getSpeaker(Node quote){ - List relations = Globals.web.getRelationsOfChildNode(quote); - List speakers = relations.stream().filter(relation -> relation.getName().equals(RelationTypes.QUOTE_OF)).map(relation -> relation.getParent()).collect(Collectors.toList()); - if(speakers.size() != 1){ - throw new Error("Invalid number of speakers! " + speakers.size()); - } - return speakers.get(0); - } - } diff --git a/src/main/java/org/studiorailgun/ai/knowledge/KnowledgeWeb.java b/src/main/java/org/studiorailgun/ai/knowledge/KnowledgeWeb.java index bc2312a..c530470 100644 --- a/src/main/java/org/studiorailgun/ai/knowledge/KnowledgeWeb.java +++ b/src/main/java/org/studiorailgun/ai/knowledge/KnowledgeWeb.java @@ -364,6 +364,34 @@ public class KnowledgeWeb { public Relation createRelation(String name, Node parent, Node child){ Relation relation = new Relation(name, parent, child); this.relations.put(relation.getId(), relation); + + if(typeRelationLookup.containsKey(relation.getName())){ + typeRelationLookup.get(relation.getName()).add(relation.getId()); + } else { + LinkedList newList = new LinkedList(); + newList.add(relation.getId()); + typeRelationLookup.put(relation.getName(),newList); + } + + //add to child tracking + List childRelations = this.childRelations.get(child); + if(childRelations == null){ + childRelations = new LinkedList(); + childRelations.add(relation); + this.childRelations.put(child, childRelations); + } else { + childRelations.add(relation); + } + + //add to parent tracking + List parentRelations = this.parentRelations.get(child); + if(parentRelations == null){ + parentRelations = new LinkedList(); + parentRelations.add(relation); + this.parentRelations.put(child, parentRelations); + } else { + parentRelations.add(relation); + } return relation; } diff --git a/src/main/java/org/studiorailgun/ai/knowledge/query/InstanceQuery.java b/src/main/java/org/studiorailgun/ai/knowledge/query/InstanceQuery.java index 650be79..0d76aaf 100644 --- a/src/main/java/org/studiorailgun/ai/knowledge/query/InstanceQuery.java +++ b/src/main/java/org/studiorailgun/ai/knowledge/query/InstanceQuery.java @@ -24,4 +24,13 @@ public class InstanceQuery { return relations.stream().filter(relation -> relation.getName().equals(RelationTypes.INSTANCE_OF)).map(relation -> relation.getChild()).collect(Collectors.toList()); } + /** + * Creates an instance relationship + * @param concept The concept + * @param instance The instance + */ + public static void setInstance(Node concept, Node instance){ + Globals.web.createRelation(RelationTypes.INSTANCE_OF, concept, instance); + } + } diff --git a/src/main/java/org/studiorailgun/ai/knowledge/query/PossessionQuery.java b/src/main/java/org/studiorailgun/ai/knowledge/query/PossessionQuery.java index d4831d8..617e9b6 100644 --- a/src/main/java/org/studiorailgun/ai/knowledge/query/PossessionQuery.java +++ b/src/main/java/org/studiorailgun/ai/knowledge/query/PossessionQuery.java @@ -34,4 +34,16 @@ public class PossessionQuery { return nodes.get(0); } + /** + * Sets the node that owns the possession + * @param possessor The owner + * @param possession The possession + */ + public static void setPossessor(Node possessor, Node possession){ + if(possessor == null || possession == null){ + throw new Error("Undefined arguments " + possessor + " " + possession); + } + Globals.web.createRelation(RelationTypes.POSSESSION_OF, possessor, possession); + } + } diff --git a/src/main/java/org/studiorailgun/ai/knowledge/types/RelationTypes.java b/src/main/java/org/studiorailgun/ai/knowledge/types/RelationTypes.java index 2b554f2..e956336 100644 --- a/src/main/java/org/studiorailgun/ai/knowledge/types/RelationTypes.java +++ b/src/main/java/org/studiorailgun/ai/knowledge/types/RelationTypes.java @@ -10,7 +10,6 @@ public class RelationTypes { */ public static final String INSTANCE_OF = "instanceOf"; - /** * A possession relationship */ diff --git a/src/test/java/org/studiorailgun/transfer/TransferEvaluationTests.java b/src/test/java/org/studiorailgun/transfer/TransferEvaluationTests.java index c87adc8..b0fdfd6 100644 --- a/src/test/java/org/studiorailgun/transfer/TransferEvaluationTests.java +++ b/src/test/java/org/studiorailgun/transfer/TransferEvaluationTests.java @@ -24,6 +24,8 @@ public class TransferEvaluationTests { Quote input = new Quote("My name is John."); NLPParser.parse(input); + Globals.conversation.addQuote(ConversationQuery.getOtherParticipant(), input); + TransferEval.evaluate(Globals.conversation, input, input.getSentences().get(0)); //search for the name being assigned in the knowledge web