diff --git a/data/test/webs/web.json b/data/test/webs/web.json index 6012496..d79259d 100644 --- a/data/test/webs/web.json +++ b/data/test/webs/web.json @@ -20,6 +20,18 @@ "4" : { "id" : 4, "name" : "Other" + }, + "5" : { + "id" : 5, + "name" : "Quote" + }, + "6" : { + "id" : 6, + "name" : "Conversation" + }, + "7" : { + "id" : 7, + "name" : "CurrentConversation" } }, "relations" : { @@ -46,6 +58,18 @@ "name" : "InstanceOf", "parent" : 3, "child" : 4 + }, + "4" : { + "id" : 4, + "name" : "ParticipantOf", + "parent" : 7, + "child" : 4 + }, + "5" : { + "id" : 5, + "name" : "ParticipantOf", + "parent" : 7, + "child" : 2 } } } \ No newline at end of file diff --git a/improvement_ideas.txt b/docs/improvement_ideas.txt similarity index 100% rename from improvement_ideas.txt rename to docs/improvement_ideas.txt diff --git a/src/main/java/org/studiorailgun/AI.java b/src/main/java/org/studiorailgun/AI.java new file mode 100644 index 0000000..c547166 --- /dev/null +++ b/src/main/java/org/studiorailgun/AI.java @@ -0,0 +1,21 @@ +package org.studiorailgun; + +import org.studiorailgun.conversation.Quote; +import org.studiorailgun.conversation.evaluators.EvaluationTree; + +/** + * The top level ai class + */ +public class AI { + + /** + * Simulates a frame of the ai + * @param input The raw input text + */ + public static void simFrame(String input){ + Quote playerQuote = new Quote(input); + //handle ai statement + EvaluationTree.evaluate(Globals.conversation, playerQuote); + } + +} diff --git a/src/main/java/org/studiorailgun/Globals.java b/src/main/java/org/studiorailgun/Globals.java index ddea2c9..6b6f6ee 100644 --- a/src/main/java/org/studiorailgun/Globals.java +++ b/src/main/java/org/studiorailgun/Globals.java @@ -3,6 +3,7 @@ package org.studiorailgun; import java.io.File; import org.studiorailgun.conversation.Conversation; +import org.studiorailgun.conversation.evaluators.GreetingEval; import org.studiorailgun.knowledge.KnowledgeWeb; /** @@ -23,17 +24,15 @@ public class Globals { /** * Initializes the knowledge web */ - public static void init(){ - Globals.loadWeb("web.json"); - } + public static void init(String webPath){ + //initialize evaluators + GreetingEval.init(); - /** - * Loads a web - * @param webPath The web's path - */ - public static void loadWeb(String webPath){ - Globals.web = FileUtils.loadObjectFromFile(new File("web.json"), KnowledgeWeb.class); + //init web + Globals.web = FileUtils.loadObjectFromFile(new File(webPath), KnowledgeWeb.class); Globals.web.initLinks(); + + //init convo Globals.conversation = Conversation.parse(Globals.web); } diff --git a/src/main/java/org/studiorailgun/conversation/AgentLoop.java b/src/main/java/org/studiorailgun/conversation/AgentLoop.java index 82ae190..3883620 100644 --- a/src/main/java/org/studiorailgun/conversation/AgentLoop.java +++ b/src/main/java/org/studiorailgun/conversation/AgentLoop.java @@ -2,10 +2,9 @@ package org.studiorailgun.conversation; import java.util.Scanner; +import org.studiorailgun.AI; import org.studiorailgun.Globals; -import org.studiorailgun.conversation.llm.Actor; -import org.studiorailgun.conversation.llm.LLMConversation; -import org.studiorailgun.conversation.llm.Statement; +import org.studiorailgun.conversation.evaluators.EvaluationTree; import org.studiorailgun.conversation.parser.CommandParser; public class AgentLoop { @@ -24,18 +23,11 @@ public class AgentLoop { * The main method */ public static void main(){ - Globals.init(); + Globals.init("web.json"); try (Scanner scan = new Scanner(System.in)) { String prompt = ""; - //setup conversation tracking - LLMConversation convo = new LLMConversation(); - Actor player = new Actor("John"); - Actor ai = new Actor("Dave"); - convo.addParticipant(player); - convo.addParticipant(ai); - //actual main loop while(running){ @@ -44,10 +36,7 @@ public class AgentLoop { if(CommandParser.parseCommands(prompt)){ continue; } - convo.addStatement(new Statement(player, prompt)); - - //handle ai statement - throw new UnsupportedOperationException("asdf"); + AI.simFrame(prompt); } } } diff --git a/src/main/java/org/studiorailgun/conversation/Conversation.java b/src/main/java/org/studiorailgun/conversation/Conversation.java index b956d40..a95974f 100644 --- a/src/main/java/org/studiorailgun/conversation/Conversation.java +++ b/src/main/java/org/studiorailgun/conversation/Conversation.java @@ -1,7 +1,9 @@ package org.studiorailgun.conversation; import org.studiorailgun.conversation.evaluators.GreetingData; +import org.studiorailgun.conversation.evaluators.goal.GoalData; import org.studiorailgun.knowledge.KnowledgeWeb; +import org.studiorailgun.knowledge.Node; /** * A conversation @@ -18,35 +20,51 @@ public class Conversation { */ ConvParticipant other; + /** + * The node in the knowledge web representing this conversation + */ + Node data; + /** * Data on greetings */ GreetingData greetingData; + /** + * The goal data + */ + GoalData goalData; + /** * Parses the current conversation's data from the knowledge web * @param web The web * @return The conversation */ public static Conversation parse(KnowledgeWeb web){ + Node node = web.getNode(7); + //find the self ConvParticipant self = new ConvParticipant(web.getSelf()); //find the other participant ConvParticipant other = new ConvParticipant(web.getNode(4)); - Conversation rVal = new Conversation(self, other); + Conversation rVal = new Conversation(node, self, other); return rVal; } /** * Constructor + * @param node The node representing this conversation instance * @param self The participant representing this bot instance * @param other The participant representing the other party in the conversation */ - public Conversation(ConvParticipant self, ConvParticipant other){ + public Conversation(Node node, ConvParticipant self, ConvParticipant other){ + this.data = node; this.self = self; this.other = other; + this.greetingData = new GreetingData(); + this.goalData = new GoalData(); } /** @@ -73,4 +91,14 @@ public class Conversation { return other; } + public GoalData getGoalData() { + return goalData; + } + + public void setGoalData(GoalData goalData) { + this.goalData = goalData; + } + + + } diff --git a/src/main/java/org/studiorailgun/conversation/Quote.java b/src/main/java/org/studiorailgun/conversation/Quote.java new file mode 100644 index 0000000..90aa036 --- /dev/null +++ b/src/main/java/org/studiorailgun/conversation/Quote.java @@ -0,0 +1,48 @@ +package org.studiorailgun.conversation; + +import org.studiorailgun.conversation.categorization.SentenceFunctionCategorizor.SentenceFunction; + +/** + * A quote stated during the conversation + */ +public class Quote { + + /** + * The raw text of the quote + */ + String raw; + + /** + * The function of the sentence + */ + SentenceFunction function; + + /** + * Constructor + * @param input The raw text of the quote + */ + public Quote(String input){ + this.raw = input; + } + + /** + * Gets the raw text of the quote + * @return The raw text of the quote + */ + public String getRaw(){ + return raw; + } + + /** + * Gets the function of the quote + * @return The function + */ + public SentenceFunction getFunction(){ + return function; + } + + public void setFunction(SentenceFunction function){ + this.function = function; + } + +} diff --git a/src/main/java/org/studiorailgun/conversation/categorization/SentenceFunctionCategorizor.java b/src/main/java/org/studiorailgun/conversation/categorization/SentenceFunctionCategorizor.java index e9c7bf5..f86f1ae 100644 --- a/src/main/java/org/studiorailgun/conversation/categorization/SentenceFunctionCategorizor.java +++ b/src/main/java/org/studiorailgun/conversation/categorization/SentenceFunctionCategorizor.java @@ -1,5 +1,7 @@ package org.studiorailgun.conversation.categorization; +import org.studiorailgun.conversation.Quote; + /** * Categorizes sentences based on function */ @@ -10,27 +12,35 @@ public class SentenceFunctionCategorizor { */ public static enum SentenceFunction { /** - * Transfers information to the other party - * ie, declaring facts, declaring perspective of the world (how you feel), etc - * "The ball is red". "I don't like that". + * A sentence whose purpose is to perform some non-informational duty in a conversation. + * An example of this could be a greeting or farewell. */ - TRANSFER_INFORMATION, + UTILITY, /** - * Query information from the other party - * ie, asking for a fact or perspective - * "Is that ball red?" "What color is your hat?" "How do you feel about that?" + * Transfers a piece of information to another participant. For instance, describing + * the details of an object. */ - QUERY_INFORMATION, + TRANSFER, + + /** + * Queries a piece of information from another participant. + */ + QUERY, + + /** + * Commands a participant to do something. + */ + IMPERATIVE, } /** * Categorizes the sentence by function - * @param input The input sentence + * @param input The input quote * @return The function of the sentence */ - public static SentenceFunction categorize(String input){ - return SentenceFunction.QUERY_INFORMATION; + public static void categorize(Quote input){ + input.setFunction(SentenceFunction.UTILITY); } } diff --git a/src/main/java/org/studiorailgun/conversation/evaluators/EvaluationTree.java b/src/main/java/org/studiorailgun/conversation/evaluators/EvaluationTree.java new file mode 100644 index 0000000..3579a29 --- /dev/null +++ b/src/main/java/org/studiorailgun/conversation/evaluators/EvaluationTree.java @@ -0,0 +1,38 @@ +package org.studiorailgun.conversation.evaluators; + +import org.studiorailgun.conversation.Conversation; +import org.studiorailgun.conversation.Quote; +import org.studiorailgun.conversation.categorization.SentenceFunctionCategorizor; +import org.studiorailgun.conversation.evaluators.goal.GoalEval; + +/** + * Evaluates a sentence based on data about the sentence + */ +public class EvaluationTree { + + /** + * Evaluates a quote + * @param quote The quote + */ + public static void evaluate(Conversation conversation, Quote quote){ + //parse data about the quote + SentenceFunctionCategorizor.categorize(quote); + + //perform actions based on the tree + switch(quote.getFunction()){ + case UTILITY: { + GreetingEval.evaluate(conversation, quote); + } break; + default: { + + } break; + } + + //evaluate the AI's current goal in the conversation + GoalEval.evaluate(conversation); + + //synthesize language based on the results of the actions performed + //TODO + } + +} diff --git a/src/main/java/org/studiorailgun/conversation/evaluators/GreetingEval.java b/src/main/java/org/studiorailgun/conversation/evaluators/GreetingEval.java index 979e7a6..2f00b07 100644 --- a/src/main/java/org/studiorailgun/conversation/evaluators/GreetingEval.java +++ b/src/main/java/org/studiorailgun/conversation/evaluators/GreetingEval.java @@ -5,7 +5,9 @@ import java.io.IOException; import java.nio.file.Files; import java.util.List; +import org.studiorailgun.conversation.ConvParticipant; import org.studiorailgun.conversation.Conversation; +import org.studiorailgun.conversation.Quote; /** * Evaluates a greeting @@ -32,9 +34,12 @@ public class GreetingEval { * Evaluates a greeting * @param input The sentence */ - public static void evaluate(Conversation conversation, String input){ - if(greetingStrings.contains(input)){ - System.out.println("Contained!"); + public static void evaluate(Conversation conversation, Quote input){ + if(greetingStrings.contains(input.getRaw())){ + ConvParticipant other = conversation.getOther(); + if(!conversation.getGreetingData().getHaveGreeted().contains(other)){ + conversation.getGreetingData().getHaveGreeted().add(other); + } } } diff --git a/src/main/java/org/studiorailgun/conversation/evaluators/goal/GoalData.java b/src/main/java/org/studiorailgun/conversation/evaluators/goal/GoalData.java new file mode 100644 index 0000000..f6c2278 --- /dev/null +++ b/src/main/java/org/studiorailgun/conversation/evaluators/goal/GoalData.java @@ -0,0 +1,34 @@ +package org.studiorailgun.conversation.evaluators.goal; + +/** + * Data about the AI's goal in the conversation + */ +public class GoalData { + + /** + * A goal the ai can have for the conversation + */ + public static enum ConversationGoal { + + /** + * Say a greeting + */ + GREET, + } + + /** + * The goal of the conversation + */ + ConversationGoal goal; + + public ConversationGoal getGoal() { + return goal; + } + + public void setGoal(ConversationGoal goal) { + this.goal = goal; + } + + + +} diff --git a/src/main/java/org/studiorailgun/conversation/evaluators/goal/GoalEval.java b/src/main/java/org/studiorailgun/conversation/evaluators/goal/GoalEval.java new file mode 100644 index 0000000..4db1d9c --- /dev/null +++ b/src/main/java/org/studiorailgun/conversation/evaluators/goal/GoalEval.java @@ -0,0 +1,28 @@ +package org.studiorailgun.conversation.evaluators.goal; + +import org.studiorailgun.conversation.ConvParticipant; +import org.studiorailgun.conversation.Conversation; +import org.studiorailgun.conversation.evaluators.GreetingData; +import org.studiorailgun.conversation.evaluators.goal.GoalData.ConversationGoal; + +/** + * Evaluates the AI's goal in the conversation + */ +public class GoalEval { + + + /** + * Evaluates the goal of the ai in the given conversation + * @param conversation The conversation + */ + public static void evaluate(Conversation conversation){ + GreetingData greetingData = conversation.getGreetingData(); + ConvParticipant selfParticipant = conversation.getSelf(); + if(!greetingData.getHaveGreeted().contains(selfParticipant)){ + conversation.getGoalData().setGoal(ConversationGoal.GREET); + } else { + conversation.getGoalData().setGoal(null); + } + } + +} diff --git a/src/test/java/org/studiorailgun/ConvLoadingTests.java b/src/test/java/org/studiorailgun/ConvLoadingTests.java index 952f1aa..5397796 100644 --- a/src/test/java/org/studiorailgun/ConvLoadingTests.java +++ b/src/test/java/org/studiorailgun/ConvLoadingTests.java @@ -2,11 +2,7 @@ package org.studiorailgun; import static org.junit.jupiter.api.Assertions.*; -import java.io.File; - import org.junit.jupiter.api.Test; -import org.studiorailgun.conversation.Conversation; -import org.studiorailgun.knowledge.KnowledgeWeb; /** * Tests loading conversations @@ -15,12 +11,9 @@ public class ConvLoadingTests { @Test public void testLoadConversation(){ - KnowledgeWeb web = FileUtils.loadObjectFromFile(new File("./data/test/webs/web.json"), KnowledgeWeb.class); - web.initLinks(); - Globals.web = web; - Conversation convo = Conversation.parse(web); - assertEquals(web.getSelf(), convo.getSelf().getData()); - assertNotEquals(web.getSelf(), convo.getOther().getData()); + Globals.init("./data/test/webs/web.json"); + assertEquals(Globals.web.getSelf(), Globals.conversation.getSelf().getData()); + assertNotEquals(Globals.web.getSelf(), Globals.conversation.getOther().getData()); } diff --git a/src/test/java/org/studiorailgun/GreetingTests.java b/src/test/java/org/studiorailgun/GreetingTests.java new file mode 100644 index 0000000..0024eb2 --- /dev/null +++ b/src/test/java/org/studiorailgun/GreetingTests.java @@ -0,0 +1,21 @@ +package org.studiorailgun; + +import static org.junit.jupiter.api.Assertions.*; + +import org.junit.jupiter.api.Test; + +/** + * Tests greeting + */ +public class GreetingTests { + + @Test + public void testOtherGreeting(){ + Globals.init("./data/test/webs/web.json"); + + AI.simFrame("Hello"); + + assertEquals(Globals.conversation.getGreetingData().getHaveGreeted().size(), 1); + } + +} diff --git a/web.json b/web.json index 9029418..d79259d 100644 --- a/web.json +++ b/web.json @@ -1,4 +1,5 @@ { + "selfId": 2, "nodes" : { "0" : { "id" : 0, @@ -18,7 +19,19 @@ }, "4" : { "id" : 4, - "name" : "ConversationParticipant" + "name" : "Other" + }, + "5" : { + "id" : 5, + "name" : "Quote" + }, + "6" : { + "id" : 6, + "name" : "Conversation" + }, + "7" : { + "id" : 7, + "name" : "CurrentConversation" } }, "relations" : { @@ -39,6 +52,24 @@ "name" : "InstanceOf", "parent" : 1, "child" : 0 + }, + "3" : { + "id" : 3, + "name" : "InstanceOf", + "parent" : 3, + "child" : 4 + }, + "4" : { + "id" : 4, + "name" : "ParticipantOf", + "parent" : 7, + "child" : 4 + }, + "5" : { + "id" : 5, + "name" : "ParticipantOf", + "parent" : 7, + "child" : 2 } } } \ No newline at end of file