diff --git a/.gitignore b/.gitignore index d7d759b0..55df7eaf 100644 --- a/.gitignore +++ b/.gitignore @@ -72,3 +72,9 @@ community-server/data-backup *.iml nlu/parser/target/ + +nlu/parser/src/main/java/edu/stanford/nlp/sempre/roboy/api/apiKeys\.yml + +dialog/src/main/java/roboy/util/api/apiKeys\.yml +dialog/src/main/java/roboy/util/api/apiKeys.yml +resources/telegram.json diff --git a/config.properties b/config.properties index 2f6240d7..96fbd7c9 100755 --- a/config.properties +++ b/config.properties @@ -1,4 +1,4 @@ -ROS_ENABLED: false +ROS_ENABLED: true ROS_MASTER_IP: 127.0.0.1 # available ROS_ACTIVE_PKG are @@ -10,37 +10,44 @@ ROS_MASTER_IP: 127.0.0.1 # roboy_vision # roboy_test # roboy_filters +# roboy_nodered ROS_ACTIVE_PKGS: # - roboy_gnlp # - roboy_memory -# - roboy_speech_synthesis -# - roboy_speech_recognition -# - roboy_face +#- roboy_speech_synthesis +#- roboy_speech_recognition +#- roboy_face # - roboy_filters -- roboy_test +#- roboy_vision +# - roboy_nodered +# - roboy_test +- sound_play +- roboy_soli DEBUG: true DEMO_MODE: false INFINITE_REPETITION: true +#timeout for threads in seconds +CONVERSATION_TIMEOUT: 10800 # only single input is allowed, defaults to cmdline -#INPUT: cmdline +INPUT: cmdline #INPUT: cerevoice #INPUT: udp #INPUT: bing -INPUT: telegram +#INPUT: telegram # multiple outputs are allowed, defaults to cmdline OUTPUTS: -#- cmdline -# - ibm -# - cerevoice -# - freetts -# - ibm -# - emotions -# - udp - - telegram +- cmdline +#- cerevoice +#- freetts +#- ibm +#- emotions +#- udp +#- telegram +- sound UDP_IN_SOCKET: 55555 UDP_OUT_SOCKET: 55556 @@ -48,12 +55,16 @@ UDP_HOST_ADDRESS: 127.0.0.1 PARSER_PORT: 5000 # PERSONALITY_FILE: "resources/personalityFiles/ExpoPersonality.json" - -PERSONALITY_FILE: "resources/personalityFiles/OrdinaryPersonality.json" -#PERSONALITY_FILE: "resources/personalityFiles/bot/TelegramBot.json" +# PERSONALITY_FILE: "resources/personalityFiles/OrdinaryPersonality.json" +# PERSONALITY_FILE: "resources/personalityFiles/bot/TelegramBot.json" # PERSONALITY_FILE: "resources/personalityFiles/tutorial/MathTest.json" # PERSONALITY_FILE: "resources/personalityFiles/tutorial/ToyStateMachine.json" +# PERSONALITY_FILE: "resources/personalityFiles/GamePersonality.json" +# PERSONALITY_FILE: "resources/personalityFiles/FairShowPersonality.json" +# PERSONALITY_FILE: "resources/personalityFiles/WackerShow.json" # PERSONALITY_FILE: "resources/personalityFiles/uzupis.json" +# PERSONALITY_FILE: "resources/personalityFiles/DevoPersonality.json" +PERSONALITY_FILE: "resources/personalityFiles/test/Test.json" IBM_TTS_USER: "" IBM_TTS_PASS: "" @@ -61,14 +72,22 @@ IBM_TTS_PASS: "" CONTEXT_GUI_ENABLED: false ACTION_CLIENT_SCRIPT: "/home/roboy/workspace/Roboy/src/roboy_dialog/resources/scripts/action_client.py" +TELEGRAM_API_TOKENS_FILE: "resources/telegram.json" +# delay in seconds to send the asnwer +TELEGRAM_TYPING_DELAY: 0 +# delay in seconds to start processing telegram input +TELEGRAM_PROCESSING_DELAY: 2 + +PARLAI_PORT: 8888 +PARLAI_HOST: "127.0.0.1" # Logging Levels # Each Logging Module has different levels. End users should use warn. Developers should use either info or debug/fine. -# Memory: java.util.logging +# Memory: java.util.logging NO DEBUG, see readthedocs->logging policy # https://docs.oracle.com/javase/7/docs/api/java/util/logging/Level.html -MEMORY_LOG_MODE: "DEBUG" +MEMORY_LOG_MODE: "FINE" # Dialog: LOG4J 2 # https://logging.apache.org/log4j/2.x/log4j-api/apidocs/org/apache/logging/log4j/Level.html @@ -78,4 +97,3 @@ DIALOG_LOG_MODE: "DEBUG" # Parser/NLU: LogInfo # Supports all Log4J levels. See Documentation for more details PARSER_LOG_MODE: "DEBUG" -TELEGRAM_API_TOKENS_FILE: "/Users/Apple/botboy/tokens.json" \ No newline at end of file diff --git a/config.properties.orig b/config.properties.orig deleted file mode 100755 index 25f29c47..00000000 --- a/config.properties.orig +++ /dev/null @@ -1,85 +0,0 @@ -ROS_ENABLED: false -ROS_MASTER_IP: 127.0.0.1 - -# available ROS_ACTIVE_PKG are -# roboy_gnlp -# roboy_memory -# roboy_speech_synthesis -# roboy_speech_recognition -# roboy_audio -# roboy_vision -# roboy_test -# roboy_filters - -ROS_ACTIVE_PKGS: -# - roboy_gnlp -# - roboy_memory -# - roboy_speech_synthesis -# - roboy_speech_recognition -# - roboy_face -# - roboy_filters -- roboy_test - -DEBUG: true -DEMO_MODE: false -INFINITE_REPETITION: true - -# only single input is allowed, defaults to cmdline -#INPUT: cmdline -#INPUT: cerevoice -#INPUT: udp -#INPUT: bing -INPUT: telegram - -# multiple outputs are allowed, defaults to cmdline -OUTPUTS: -# - cmdline -# - ibm -# - cerevoice -# - freetts -# - ibm -# - emotions -# - udp - - telegram - -UDP_IN_SOCKET: 55555 -UDP_OUT_SOCKET: 55556 -UDP_HOST_ADDRESS: 127.0.0.1 - -PARSER_PORT: 5000 -# PERSONALITY_FILE: "resources/personalityFiles/ExpoPersonality.json" - -#PERSONALITY_FILE: "resources/personalityFiles/OrdinaryPersonality.json" -PERSONALITY_FILE: "resources/personalityFiles/bot/TelegramBot.json" -# PERSONALITY_FILE: "resources/personalityFiles/tutorial/MathTest.json" -# PERSONALITY_FILE: "resources/personalityFiles/tutorial/ToyStateMachine.json" -# PERSONALITY_FILE: "resources/personalityFiles/uzupis.json" - -IBM_TTS_USER: "" -IBM_TTS_PASS: "" - -CONTEXT_GUI_ENABLED: false -ACTION_CLIENT_SCRIPT: "/home/roboy/workspace/Roboy/src/roboy_dialog/resources/scripts/action_client.py" - - - -# Logging Levels -# Each Logging Module has different levels. End users should use warn. Developers should use either info or debug/fine. - -# Memory: java.util.logging -# https://docs.oracle.com/javase/7/docs/api/java/util/logging/Level.html -MEMORY_LOG_MODE: "WARNING" - -# Dialog: LOG4J 2 -# https://logging.apache.org/log4j/2.x/log4j-api/apidocs/org/apache/logging/log4j/Level.html -# https://logging.apache.org/log4j/2.x/manual/customloglevels.html -DIALOG_LOG_MODE: "WARN" - -# Parser/NLU: LogInfo -# Supports all Log4J levels. See Documentation for more details -<<<<<<< Updated upstream -PARSER_LOG_MODE: "WARN" -======= -PARSER_LOG_MODE: "INFO" -TELEGRAM_API_TOKENS_FILE: "/Users/Apple/botboy/tokens.json" ->>>>>>> Stashed changes diff --git a/dialog/pom.xml b/dialog/pom.xml index 06ccf029..2dad4851 100755 --- a/dialog/pom.xml +++ b/dialog/pom.xml @@ -27,6 +27,7 @@ maven-surefire-plugin 2.22.0 + ${project.parent.basedir} roboy.memory.MemoryIntegrationTest @@ -354,7 +355,13 @@ org.ros.rosjava_messages roboy_communication_control - 0.0.1 + 0.0.3 + + + + org.ros.rosjava_messages + std_srvs + 1.11.2 @@ -421,7 +428,7 @@ com.github.markozajc akiwrapper - 1.3.2 + 1.3.4 @@ -429,6 +436,12 @@ telegrambots 3.6.1 + + + co.gongzh.procbridge + procbridge + 1.0.2 + diff --git a/dialog/src/main/java/roboy/context/Context.java b/dialog/src/main/java/roboy/context/Context.java index 278d571e..c5d86235 100644 --- a/dialog/src/main/java/roboy/context/Context.java +++ b/dialog/src/main/java/roboy/context/Context.java @@ -7,6 +7,7 @@ import roboy.ros.RosMainNode; import roboy.util.ConfigManager; import roboy_communication_cognition.DirectionVector; +import roboy_communication_control.Strings; import java.util.ArrayList; @@ -44,6 +45,21 @@ public class Context { public final HistoryInterface, Integer, Integer> OTHER_Q = new HistoryInterface<>(new ValueHistory()); + public final HistoryInterface PERSON_DETECTION = + new HistoryInterface<>(new DetecedPerson()); + + public final HistoryInterface CROWD_DETECTION = + new HistoryInterface<>(new PeopleAround()); + + public final HistoryInterface OBJECT_DETECTION = + new HistoryInterface<>(new DetectedObjects()); + + public final HistoryInterface BOOTH_SENTENCE = + new HistoryInterface<>(new BoothSentence()); + + public final ValueInterface CUP_GAME_SMACH_STATE_MSG = + new ValueInterface<>(new CupGameSmachState()); + /* GUI */ private final ArrayList guiValues = new ArrayList(); private final ArrayList guiHistories = new ArrayList(); @@ -58,6 +74,11 @@ public class Context { private boolean rosInitialized = false; private AudioDirectionUpdater AUDIO_ANGLES_UPDATER; private ROSTestUpdater ROS_TEST_UPDATER; + private DetectedPersonUpdater DETECTED_PERSON_UPDATER; + private PeopleAroundUpdater CROWD_UPDATER; + private DetectedObjectsUpdater DETECTED_OBJ_UPDATER; + private BoothSentenceUpdater BOOTH_SENTENCE_UPDATER; + private CupGameSmachStateUpdater CUP_GAME_SMACH_UPDATER; /* OBSERVERS */ private final FaceCoordinatesObserver FACE_COORDINATES_OBSERVER; @@ -107,6 +128,20 @@ public void initializeROS(RosMainNode ros) { // TODO Add a FACE_COORDINATE_UPDATER. // Edit the data type and integration tests, once the real data type is used. + if(ConfigManager.ROS_ACTIVE_PKGS.contains("roboy_vision")) { + DETECTED_PERSON_UPDATER = new DetectedPersonUpdater(PERSON_DETECTION.valueHistory, ros); + DETECTED_OBJ_UPDATER = new DetectedObjectsUpdater(OBJECT_DETECTION.valueHistory, ros); + CROWD_UPDATER = new PeopleAroundUpdater(CROWD_DETECTION.valueHistory, ros); + } + + if(ConfigManager.ROS_ACTIVE_PKGS.contains("roboy_nodered")){ + BOOTH_SENTENCE_UPDATER = new BoothSentenceUpdater(BOOTH_SENTENCE.valueHistory, ros); + } + + if(ConfigManager.ROS_ACTIVE_PKGS.contains("roboy_soli")){ + CUP_GAME_SMACH_UPDATER = new CupGameSmachStateUpdater(CUP_GAME_SMACH_STATE_MSG.value, ros); + } + rosInitialized = true; } } diff --git a/dialog/src/main/java/roboy/context/contextObjects/BoothSentence.java b/dialog/src/main/java/roboy/context/contextObjects/BoothSentence.java new file mode 100644 index 00000000..ad99ac3d --- /dev/null +++ b/dialog/src/main/java/roboy/context/contextObjects/BoothSentence.java @@ -0,0 +1,9 @@ +package roboy.context.contextObjects; + +import roboy.context.ValueHistory; + +/** + * Holds Strings with information about the booth at a fair, sent by the node-red GUI + * */ +public class BoothSentence extends ValueHistory { +} diff --git a/dialog/src/main/java/roboy/context/contextObjects/BoothSentenceUpdater.java b/dialog/src/main/java/roboy/context/contextObjects/BoothSentenceUpdater.java new file mode 100644 index 00000000..6d78f50e --- /dev/null +++ b/dialog/src/main/java/roboy/context/contextObjects/BoothSentenceUpdater.java @@ -0,0 +1,26 @@ +package roboy.context.contextObjects; + +import roboy.context.ROSTopicUpdater; +import roboy.ros.RosMainNode; +import roboy.ros.RosSubscribers; + +/** + * Pushes new values sent by the Booth Sentence ROS topic into the Booth Sentence value history. + */ +public class BoothSentenceUpdater extends ROSTopicUpdater { + + public BoothSentenceUpdater(BoothSentence target, RosMainNode node) { + super(target, node); + } + + @Override + protected synchronized void update() { + target.updateValue(message); + } + + @Override + protected RosSubscribers getTargetSubscriber() { + return RosSubscribers.BOOTH_SENTENCE; + } + +} diff --git a/dialog/src/main/java/roboy/context/contextObjects/CupGameSmachState.java b/dialog/src/main/java/roboy/context/contextObjects/CupGameSmachState.java new file mode 100644 index 00000000..5a962e7b --- /dev/null +++ b/dialog/src/main/java/roboy/context/contextObjects/CupGameSmachState.java @@ -0,0 +1,9 @@ +package roboy.context.contextObjects; + +import roboy.context.Value; + +/** + * For testing a ROS topic connection which sends simple String messages. + */ +public class CupGameSmachState extends Value { +} diff --git a/dialog/src/main/java/roboy/context/contextObjects/CupGameSmachStateUpdater.java b/dialog/src/main/java/roboy/context/contextObjects/CupGameSmachStateUpdater.java new file mode 100644 index 00000000..774c0186 --- /dev/null +++ b/dialog/src/main/java/roboy/context/contextObjects/CupGameSmachStateUpdater.java @@ -0,0 +1,26 @@ +package roboy.context.contextObjects; + +import roboy.context.ROSTopicUpdater; +import roboy.ros.RosMainNode; +import roboy.ros.RosSubscribers; + +/** + * For testing a ROS topic connection which sends simple String messages. + */ +public class CupGameSmachStateUpdater extends ROSTopicUpdater { + + @Override + protected RosSubscribers getTargetSubscriber() { + return RosSubscribers.CUP_GAME_STATE; + } + + public CupGameSmachStateUpdater(CupGameSmachState target, RosMainNode node) { + super(target, node); + } + + @Override + protected synchronized void update() { + target.updateValue(message.getData()); + } + +} diff --git a/dialog/src/main/java/roboy/context/contextObjects/DetecedPerson.java b/dialog/src/main/java/roboy/context/contextObjects/DetecedPerson.java new file mode 100644 index 00000000..db067eb5 --- /dev/null +++ b/dialog/src/main/java/roboy/context/contextObjects/DetecedPerson.java @@ -0,0 +1,9 @@ +package roboy.context.contextObjects; + +import roboy.context.ValueHistory; + +/** + * Holds booleans whether a person is longer than 10 seconds in the field of view receiving from vision + * */ +public class DetecedPerson extends ValueHistory { +} diff --git a/dialog/src/main/java/roboy/context/contextObjects/DetectedObjects.java b/dialog/src/main/java/roboy/context/contextObjects/DetectedObjects.java new file mode 100644 index 00000000..e6c891b2 --- /dev/null +++ b/dialog/src/main/java/roboy/context/contextObjects/DetectedObjects.java @@ -0,0 +1,11 @@ +package roboy.context.contextObjects; + +import roboy.context.ValueHistory; +import roboy_communication_control.Strings; + + +/** + * Holds detected Objects as a String Array receiving from vision + * */ +public class DetectedObjects extends ValueHistory { +} diff --git a/dialog/src/main/java/roboy/context/contextObjects/DetectedObjectsUpdater.java b/dialog/src/main/java/roboy/context/contextObjects/DetectedObjectsUpdater.java new file mode 100644 index 00000000..4d0a2db5 --- /dev/null +++ b/dialog/src/main/java/roboy/context/contextObjects/DetectedObjectsUpdater.java @@ -0,0 +1,27 @@ +package roboy.context.contextObjects; + +import roboy.context.ROSTopicUpdater; +import roboy.ros.RosMainNode; +import roboy.ros.RosSubscribers; +import roboy_communication_control.Strings; + +/** + * Pushes new values sent by the Detected Objects ROS topic into the DetectedObjects value history. + */ +public class DetectedObjectsUpdater extends ROSTopicUpdater { + + public DetectedObjectsUpdater(DetectedObjects target, RosMainNode node) { + super(target, node); + } + + @Override + protected synchronized void update() { + target.updateValue(message); + } + + @Override + protected RosSubscribers getTargetSubscriber() { + return RosSubscribers.DETECTED_OBJECTS; + } + +} diff --git a/dialog/src/main/java/roboy/context/contextObjects/DetectedPersonUpdater.java b/dialog/src/main/java/roboy/context/contextObjects/DetectedPersonUpdater.java new file mode 100644 index 00000000..33b2b4d9 --- /dev/null +++ b/dialog/src/main/java/roboy/context/contextObjects/DetectedPersonUpdater.java @@ -0,0 +1,26 @@ +package roboy.context.contextObjects; + +import roboy.context.ROSTopicUpdater; +import roboy.ros.RosMainNode; +import roboy.ros.RosSubscribers; + +/** + * Pushes new values sent by the Person Listening ROS topic into the DetectedPerson value history. + */ +public class DetectedPersonUpdater extends ROSTopicUpdater { + + public DetectedPersonUpdater(DetecedPerson target, RosMainNode node) { + super(target, node); + } + + @Override + protected synchronized void update() { + target.updateValue(message); + } + + @Override + protected RosSubscribers getTargetSubscriber() { + return RosSubscribers.PERSON_LISTENING; + } + +} diff --git a/dialog/src/main/java/roboy/context/contextObjects/PeopleAround.java b/dialog/src/main/java/roboy/context/contextObjects/PeopleAround.java new file mode 100644 index 00000000..dcce6fdb --- /dev/null +++ b/dialog/src/main/java/roboy/context/contextObjects/PeopleAround.java @@ -0,0 +1,9 @@ +package roboy.context.contextObjects; + +import roboy.context.ValueHistory; + +/** + * Holds number of people around as Integers receiving from vision + * */ +public class PeopleAround extends ValueHistory { +} diff --git a/dialog/src/main/java/roboy/context/contextObjects/PeopleAroundUpdater.java b/dialog/src/main/java/roboy/context/contextObjects/PeopleAroundUpdater.java new file mode 100644 index 00000000..303c5544 --- /dev/null +++ b/dialog/src/main/java/roboy/context/contextObjects/PeopleAroundUpdater.java @@ -0,0 +1,26 @@ +package roboy.context.contextObjects; + +import roboy.context.ROSTopicUpdater; +import roboy.ros.RosMainNode; +import roboy.ros.RosSubscribers; + +/** + * Pushes new values sent by the People Around ROS topic into the PeopleAround value history. + */ +public class PeopleAroundUpdater extends ROSTopicUpdater { + + public PeopleAroundUpdater(PeopleAround target, RosMainNode node) { + super(target, node); + } + + @Override + protected synchronized void update() { + target.updateValue(message); + } + + @Override + protected RosSubscribers getTargetSubscriber() { + return RosSubscribers.NUMBER_PEOPLE_AROUND; + } + +} diff --git a/dialog/src/main/java/roboy/dialog/Conversation.java b/dialog/src/main/java/roboy/dialog/Conversation.java index 19957dc8..52954ee6 100644 --- a/dialog/src/main/java/roboy/dialog/Conversation.java +++ b/dialog/src/main/java/roboy/dialog/Conversation.java @@ -5,17 +5,20 @@ import roboy.dialog.action.Action; import roboy.dialog.action.SpeechAction; import roboy.dialog.personality.StateBasedPersonality; +import roboy.dialog.states.definitions.MonologState; import roboy.io.Input; import roboy.io.MultiInputDevice; import roboy.io.MultiOutputDevice; import roboy.linguistics.sentenceanalysis.Analyzer; import roboy.linguistics.sentenceanalysis.Interpretation; -import roboy.memory.nodes.Interlocutor; +import roboy.util.ConfigManager; import java.io.File; import java.io.FileNotFoundException; +import java.io.IOException; import java.util.ArrayList; import java.util.List; +import java.util.concurrent.TimeUnit; /** @@ -67,17 +70,20 @@ public Conversation( StateBasedPersonality personality, File personalityFile, Mu /** * Ends conversation and resets state to initial. Does not reset gathered information. */ - synchronized void endConversation(){//Ends conversation including + synchronized void endConversation(boolean hardStop){//Ends conversation including isRunning = false; personality.reset(); this.interrupt();//to wake conversations that wait for input - //Say bye - List l = new ArrayList<>(); - l.add(new SpeechAction("Sorry. It seems I have to stop playing now. See you soon. Bye!")); - multiOut.act(l); + if(!hardStop) { + //Say bye + List l = new ArrayList<>(); + l.add(new SpeechAction("Sorry. It seems I have to stop playing now. See you soon. Bye!")); + multiOut.act(l); + } logger.info("############# Conversation forcibly ended ############"); + } @@ -91,6 +97,11 @@ public void run(){ } else {//if this is an initial start actions = personality.startConversation(); logger.info("############# Conversation started ############"); + // try { + // System.in.read(); + // } catch (IOException e) { + // logger.error(e.getMessage()); + // } } while (isRunning) { @@ -103,13 +114,23 @@ public void run(){ break; } + //skip user input if needed + if(personality.skippingNeeded()){ + actions = personality.skipUserInput(); + continue; + } + // listen to interlocutor if conversation didn't end Input raw; try { - raw = multiIn.listen(); + raw = multiIn.listen(TimeUnit.SECONDS.toMillis(ConfigManager.CONVERSATION_TIMEOUT)); } catch (Exception e) { - logger.error("Exception in input: " + e.getMessage()); - return; + if(isRunning) { + logger.error("Exception in input: " + e.getMessage()); + return; + } else { + break; + } } // analyze @@ -122,7 +143,7 @@ public void run(){ e.printStackTrace(); } } - logger.info(interpretation.toString()); + logger.debug(interpretation.toString()); // answer try { diff --git a/dialog/src/main/java/roboy/dialog/ConversationManager.java b/dialog/src/main/java/roboy/dialog/ConversationManager.java index 394afd74..88baa139 100644 --- a/dialog/src/main/java/roboy/dialog/ConversationManager.java +++ b/dialog/src/main/java/roboy/dialog/ConversationManager.java @@ -18,13 +18,10 @@ import roboy.logic.InferenceEngine; import roboy.memory.Neo4jMemory; import roboy.memory.Neo4jMemoryInterface; -import roboy.memory.Neo4jProperty; import roboy.memory.nodes.Interlocutor; import roboy.ros.RosMainNode; import roboy.talk.Verbalizer; -import roboy.util.ConfigManager; -import roboy.util.IO; -import roboy.util.TelegramCommunicationHandler; +import roboy.util.*; import java.io.File; import java.io.IOException; @@ -85,7 +82,8 @@ public static void main(String[] args) throws IOException { analyzers.add(new EmotionAnalyzer()); - //analyzers.add(new ProfanityAnalyzer()); + analyzers.add(new ProfanityAnalyzer()); + analyzers.add(new Postprocessor()); //I/O specific core behaviour @@ -104,6 +102,7 @@ public static void main(String[] args) throws IOException { logger.error("Telegram bots api error: ", e); } + //begin operation logger.info("####################################################\n# SYSTEM LOADED #\n####################################################\n"); commandMode(); break; @@ -116,8 +115,8 @@ public static void main(String[] args) throws IOException { do {//repeat conversations if configured to do so demoReadyCheck(); Conversation c = createConversation(rosMainNode, analyzers, new Inference(), memory, "local"); - c.start(); + try {//Since this is roboy mode and only one conversation happens, we need to wait for it to finish so we don't clog the command line. logger.info("Waiting for conversation to end."); c.join(); @@ -136,11 +135,20 @@ public static void main(String[] args) throws IOException { /** * Creates and spawns a conversation for a chatuser. - * @param uuid should consist of "servicename-[uuid]", if input allows only a single user, set to "local" + * @param uuid should consist of "[world-interface-name]-[uuid]", if input allows only a single user, set to "local" + * @throws IOException If conversation could not created. + */ + public static void spawnConversation(String uuid) throws IOException { + spawnConversation(uuid, null); + } + /** + * Creates and spawns a conversation for a chatuser. + * @param uuid should consist of "[world-interface-name]-[uuid]", if input allows only a single user, set to "local" + * @param name the name of the Interlocutor. Necessary for unique adressing by name (local nodes) * @throws IOException If conversation could not created. */ - public static void spawnConversation(String uuid) throws IOException{ - Conversation conversation = createConversation(rosMainNode, analyzers, new Inference(), memory, uuid); + public static void spawnConversation(String uuid, String name) throws IOException{ + Conversation conversation = createConversation(rosMainNode, analyzers, new Inference(), memory, uuid, name); conversations.put(uuid, conversation); conversation.start(); } @@ -153,14 +161,19 @@ protected static void deregisterConversation(Conversation conversation){ conversations.values().remove(conversation); } + public static void stopConversation(String uuid){ + stopConversation(uuid, false); + } + /** * Stops conversation thread for uuid. - * @param uuid should consist of "servicename-[uuid]", if input allows only a single user, set to "local" + * @param uuid should consist of "[world-interface-name]-[uuid]", if input allows only a single user, set to "local" + * @param hardStop Roboy doesn't say bye on hardstop. Default = false */ - public static void stopConversation(String uuid){ + public static void stopConversation(String uuid, boolean hardStop){ Conversation c = conversations.get(uuid); if (c != null) { - c.endConversation(); + c.endConversation(hardStop); } else { logger.error("Conversation to be stopped does not exist..."); } @@ -168,7 +181,7 @@ public static void stopConversation(String uuid){ /** * returns the threadID of the conversation with interlocutor uuid - * @param uuid should consist of "servicename-[uuid]", if input allows only a single user, set to "local" + * @param uuid should consist of "[world-interface-name]-[uuid]", if input allows only a single user, set to "local" * @return null if thread does not exist, threadID otherwise */ public static Long getConversationThreadID(String uuid){ @@ -177,18 +190,40 @@ public static Long getConversationThreadID(String uuid){ return (conv == null) ? null : (Long)conv.getId(); } - /** - * Creates and initializes a new conversation thread. Does not start the thread. + * Creates and initializes a new conversation thread. Only use for local threads that don't have uuids (uuid=local). Does not start the thread. * @param rosMainNode ROS node. Set null if ROS_ENABLED=false * @param analyzers All analyzers necessary for analyzing the inputs from multiIn. Please provide these in correct order. * @param inference Inference engine. The better, the smarter roboy gets. * @param memory Roboy memory access. Without, we cannot remember anything and conversations stay shallow. - * @return roboy.dialog.Conversation object. Fully intialized, ready to launch. + * @param uuid should consist of "[world-interface-name]-[uuid]", if input allows only a single user, set to "local" + * @return null if uuroboy.dialog.Conversation object. Fully intialized, ready to launch. * @throws IOException In case the IOdevices could not be correctly initialized. */ private static Conversation createConversation(RosMainNode rosMainNode, List analyzers, InferenceEngine inference, Neo4jMemoryInterface memory, String uuid) throws IOException{ + if(!uuid.equals("local")){ + logger.error("Cannot create a Conversation for uuid " + uuid + " without a name!"); + return null; + } + return createConversation(rosMainNode,analyzers,inference,memory,uuid,null); + } + + + + /** + * Creates and initializes a new conversation thread. Does not start the thread. + * @param rosMainNode ROS node. Set null if ROS_ENABLED=false + * @param analyzers All analyzers necessary for analyzing the inputs from multiIn. Please provide these in correct order. + * @param inference Inference engine. The better, the smarter roboy gets. + * @param memory Roboy memory access. Without, we cannot remember anything and conversations stay shallow. + * @param uuid should consist of "[world-interface-name]-[uuid]", if input allows only a single user, set to "local"; + * @param name the name of the Interlocutor. Necessary for unique adressing by name (local nodes) + * @return roboy.dialog.Conversation object. Fully intialized, ready to launch. + * @throws IOException In case the IOdevices could not be correctly initialized. + */ + + private static Conversation createConversation(RosMainNode rosMainNode, List analyzers, InferenceEngine inference, Neo4jMemoryInterface memory, String uuid, String name) throws IOException{ logger.info("Creating new conversation..."); //Create IODevices. @@ -215,7 +250,22 @@ private static Conversation createConversation(RosMainNode rosMainNode, List answer(Interpretation input); + } diff --git a/dialog/src/main/java/roboy/dialog/personality/StateBasedPersonality.java b/dialog/src/main/java/roboy/dialog/personality/StateBasedPersonality.java index ad5b0ebc..098410c3 100644 --- a/dialog/src/main/java/roboy/dialog/personality/StateBasedPersonality.java +++ b/dialog/src/main/java/roboy/dialog/personality/StateBasedPersonality.java @@ -5,7 +5,9 @@ import roboy.context.Context; import roboy.dialog.action.Action; import roboy.dialog.action.EmotionAction; +import roboy.dialog.action.SoundAction; import roboy.dialog.action.SpeechAction; +import roboy.dialog.states.definitions.MonologState; import roboy.linguistics.sentenceanalysis.Interpretation; import roboy.logic.InferenceEngine; import roboy.logic.StatementInterpreter; @@ -18,8 +20,8 @@ import roboy.talk.PhraseCollection; import roboy.talk.Verbalizer; -import java.util.ArrayList; -import java.util.List; +import java.util.*; +import java.util.concurrent.locks.ReentrantLock; /** * Implementation of Personality based on a DialogStateMachine. @@ -40,11 +42,12 @@ public class StateBasedPersonality extends DialogStateMachine implements Persona private final Logger logger = LogManager.getLogger(); - private final Verbalizer verbalizer; private boolean stopTalking; + private ReentrantLock lock = new ReentrantLock(); + public StateBasedPersonality(InferenceEngine inference, RosMainNode rosMainNode, Neo4jMemoryInterface memory, Context context, Verbalizer verb) { super(inference, context, rosMainNode, memory); @@ -93,7 +96,6 @@ public boolean conversationEnded() { } - /** * Always called once by the (new) DialogSystem at the beginning of every new conversation. * @return list of actions based on act() of the initial/active state @@ -120,6 +122,25 @@ public List startConversation() { return initialActions; } + public boolean skippingNeeded(){ + + return getActiveState().getClass().getSuperclass().equals(MonologState.class); + } + + public List skipUserInput(){ + + List actions = new ArrayList<>(); + + State next = getActiveState().getNextState(); + if (next == null) { + // no next state -> conversation ends + endConversation(); + } + setActiveState(next); + stateAct(next, actions); + return actions; + } + @Override public List answer(Interpretation input) { @@ -143,6 +164,8 @@ public List answer(Interpretation input) { // change emotional expression based on input answerActions.add(new EmotionAction(input.getEmotion())); } + + String sentence = input.getSentence(); if (StatementInterpreter.isFromList(sentence, Verbalizer.farewells)) { // stop conversation once the interlocutor says a farewell @@ -153,8 +176,9 @@ public List answer(Interpretation input) { // ACTIVE STATE REACTS TO INPUT + lock.lock(); stateReact(activeState, input, answerActions); - + lock.unlock(); // MOVE TO THE NEXT STATE State next = activeState.getNextState(); @@ -165,7 +189,6 @@ public List answer(Interpretation input) { } setActiveState(next); - // NEXT STATE ACTS stateAct(next, answerActions); @@ -221,6 +244,10 @@ private void stateAct(State state, List previousActions) { if (act.hasEmotion()) { previousActions.add(new EmotionAction(act.getEmotion())); } + + if(act.hasSound()) { + previousActions.add(new SoundAction(act.getSoundFilename())); + } } @@ -228,7 +255,7 @@ private void stateAct(State state, List previousActions) { * Call the react function of the state. If the state can't react, recursively ask fallbacks. * Verbalize the resulting reaction and add it to the list of actions. * - * @param state state to call REact on + * @param state state to call React on * @param input input from the person Roboy speaks to * @param previousActions list of previous action to append the verbalized result */ @@ -236,7 +263,9 @@ private void stateReact(State state, Interpretation input, List previous State.Output react; try { + react = state.react(input); + } catch (Exception e) { exceptionHandler(state, e, previousActions, false); return; @@ -249,7 +278,6 @@ private void stateReact(State state, Interpretation input, List previous return; // say nothing, just return and don't modify the list } - // first, resolve fallbacks if needed State fallback = state.getFallback(); int fallbackCount = 0, maxFallbackCount = 1000; // limit to prevent infinite loops @@ -313,6 +341,10 @@ private void stateReact(State state, Interpretation input, List previous if (react.hasEmotion()) { previousActions.add(new EmotionAction(react.getEmotion())); } + + if(react.hasSound()) { + previousActions.add(new SoundAction(react.getSoundFilename())); + } } /** diff --git a/dialog/src/main/java/roboy/dialog/states/botboy/BotBoyFarewellState.java b/dialog/src/main/java/roboy/dialog/states/botboy/BotBoyFarewellState.java new file mode 100644 index 00000000..3ea9d7a8 --- /dev/null +++ b/dialog/src/main/java/roboy/dialog/states/botboy/BotBoyFarewellState.java @@ -0,0 +1,79 @@ +package roboy.dialog.states.botboy; + +import roboy.dialog.states.definitions.State; +import roboy.dialog.states.definitions.StateParameters; +import roboy.linguistics.sentenceanalysis.Interpretation; +import roboy.logic.StatementInterpreter; +import roboy.talk.Verbalizer; +import roboy.util.RandomList; + +import java.util.Set; + +/** + * This state ends the conversation. + * + * BotBoyFarewellState interface: + * 1) Fallback is not required. + * 2) This state has no outgoing transitions. + * 3) No parameters are used. + */ + +public class BotBoyFarewellState extends State { + private State next = null; + private int loops = 0; + private final static int MAX_LOOP_COUNT = 2; + + public BotBoyFarewellState(String stateIdentifier, StateParameters params) { + super(stateIdentifier, params); + } + + private static RandomList conversationEndings = new RandomList<>( + "What a nice conversation! I have to think about everything we" + + " were talking about. Let's talk again next time.", + "I feel tired now, maybe my battery is low? Let's talk again later.", + "Don't you think that the dialog team is amazing? They are happy to " + + "tell you more about my system. Just ask one of them!"); + + @Override + public Output act() { + if (loops > MAX_LOOP_COUNT) { + // force conversation stop after a few loops + return Output.endConversation(Verbalizer.farewells.getRandomElement()); + } + return Output.say(conversationEndings.getRandomElement()); + } + + @Override + public Output react(Interpretation input) { + + String sentence = input.getSentence(); + if (StatementInterpreter.isFromList(sentence, Verbalizer.farewells)) { + next = null; + } else { + next = this; + loops++; + } + + return Output.sayNothing(); + } + + @Override + public State getNextState() { + return next; + } + + @Override + protected Set getRequiredTransitionNames() { + return newSet(); + } + + @Override + protected Set getRequiredParameterNames() { + return newSet(); + } + + @Override + public boolean isFallbackRequired() { + return false; + } +} diff --git a/dialog/src/main/java/roboy/dialog/states/botboy/BotBoyIntroductionState.java b/dialog/src/main/java/roboy/dialog/states/botboy/BotBoyIntroductionState.java new file mode 100644 index 00000000..13693583 --- /dev/null +++ b/dialog/src/main/java/roboy/dialog/states/botboy/BotBoyIntroductionState.java @@ -0,0 +1,209 @@ +package roboy.dialog.states.botboy; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import roboy.dialog.states.definitions.State; +import roboy.dialog.states.definitions.StateParameters; +import roboy.linguistics.sentenceanalysis.Interpretation; +import roboy.memory.Neo4jProperty; +import roboy.memory.Neo4jRelationship; +import roboy.memory.nodes.Interlocutor; +import roboy.memory.nodes.Interlocutor.RelationshipAvailability; +import roboy.memory.nodes.Roboy; +import roboy.memory.nodes.MemoryNodeModel; +import roboy.dialog.Segue; +import roboy.talk.PhraseCollection; +import roboy.talk.Verbalizer; +import roboy.util.Agedater; +import roboy.util.QAJsonParser; +import roboy.util.RandomList; + +import java.util.*; + +import static roboy.memory.Neo4jRelationship.*; +import static roboy.memory.Neo4jProperty.*; +import static roboy.memory.nodes.Interlocutor.RelationshipAvailability.*; + +/** + * This state will: + * - ask the interlocutor for his name + * - query memory if the person is already known + * - create and update the interlocutor in the context + * - take one of two transitions: knownPerson or newPerson + * + * BotBoyIntroductionState interface: + * 1) Fallback is not required. + * 2) Outgoing transitions that have to be defined: + * - knownPerson: following state if the person is already known + * - newPerson: following state if the person is NOT known + * 3) No parameters are used. + */ +public class BotBoyIntroductionState extends State { + private QAJsonParser infoValues; + private final String UPDATE_KNOWN_PERSON = "knownPerson"; + private final String LEARN_ABOUT_PERSON = "newPerson"; + private final Logger LOGGER = LogManager.getLogger(); + private final String INFO_FILE_PARAMETER_ID = "infoFile"; + private final RandomList successResponsePhrases = new RandomList<>("Hey, I know you, %s!", "Hey, I remember you, %s"); + private final RandomList failureResponsePhrases = new RandomList<>("Nice to meet you, %s!", "Glad to meet you, %s"); + + private Neo4jRelationship[] personPredicates = { FROM, HAS_HOBBY, WORK_FOR, STUDY_AT }; + private RandomList roboyRelatioshipPredicates = new RandomList<>(FROM, MEMBER_OF, LIVE_IN, HAS_HOBBY, FRIEND_OF, CHILD_OF, SIBLING_OF); + private State nextState; + + public BotBoyIntroductionState(String stateIdentifier, StateParameters params) { + super(stateIdentifier, params); + String infoListPath = params.getParameter(INFO_FILE_PARAMETER_ID); + LOGGER.info(" -> The infoList path: " + infoListPath); + infoValues = new QAJsonParser(infoListPath); + } + + @Override + public Output act() { + return Output.say(getIntroPhrase()); + } + + @Override + public Output react(Interpretation input) { + // expecting something like "My name is NAME" + + // 1. get name + String name = getNameFromInput(input); + + if (name == null) { + // input couldn't be parsed properly + // TODO: do something intelligent if the parser fails + nextState = this; + LOGGER.warn("IntroductionState couldn't get name! Staying in the same state."); + return Output.useFallback(); + // alternatively: Output.useFallback() or Output.sayNothing() + } + + + // 2. get interlocutor object from context + // this also should query memory and do other magic + Interlocutor person = getContext().ACTIVE_INTERLOCUTOR.getValue(); + person.addName(name); + // Roboy roboy = new Roboy(getMemory()); + + + // 3. update interlocutor in context + updateInterlocutorInContext(person); + String retrievedPersonalFact = ""; + Double segueProbability = 0.0; + + // 4. check if person is known/familiar + if (person.FAMILIAR) { + // 4a. person known/familiar + RandomList nodes = getMemNodesByIds(person.getRelationships(FRIEND_OF)); + if (!nodes.isEmpty()) { + retrievedPersonalFact = " You are friends with " + + nodes.getRandomElement().getProperties().get(Neo4jProperty.name).toString(); + } + + RelationshipAvailability availability = person.checkRelationshipAvailability(personPredicates); + if (availability == SOME_AVAILABLE) { + nextState = (Math.random() < 0.3) ? getTransition(UPDATE_KNOWN_PERSON) : getTransition(LEARN_ABOUT_PERSON); + } else if (availability == NONE_AVAILABLE) { + nextState = getTransition(LEARN_ABOUT_PERSON); + } else { + nextState = getTransition(UPDATE_KNOWN_PERSON); + } + } else { + // 4b. person is not known + nextState = getTransition(LEARN_ABOUT_PERSON); + segueProbability = 0.6; + } + String retrievedRoboyFacts = getRoboyFactsPhrase(new Roboy(getMemory())); + Segue s = new Segue(Segue.SegueType.DISTRACT, segueProbability); + + if(person.FAMILIAR) { + return Output.say(getResponsePhrase(person.getName(), person.FAMILIAR) + + retrievedPersonalFact + " It is great to chat with you again!").setSegue(s); + } + + return Output.say(getResponsePhrase(person.getName(), person.FAMILIAR) + + retrievedPersonalFact + retrievedRoboyFacts).setSegue(s); + } + + @Override + public State getNextState() { + return nextState; + } + + private String getNameFromInput(Interpretation input) { + return getInference().inferProperty(name, input); + } + + private void updateInterlocutorInContext(Interlocutor interlocutor) { + getContext().ACTIVE_INTERLOCUTOR_UPDATER.updateValue(interlocutor); + } + + private String getIntroPhrase() { + return PhraseCollection.ASK_NAME.getRandomElement(); + } + + private String getResponsePhrase(String name, boolean familiar) { + if (familiar) { + return String.format(successResponsePhrases.getRandomElement(), name); + } else { + return String.format(failureResponsePhrases.getRandomElement(), name); + } + } + + private String getRoboyFactsPhrase(Roboy roboy) { + String result = ""; + + // Get some random properties facts + if (roboy.getProperties() != null && !roboy.getProperties().isEmpty()) { + HashMap properties = roboy.getProperties(); + if (properties.containsKey(full_name)) { + result += " " + String.format(infoValues.getSuccessAnswers(full_name).getRandomElement(), properties.get(full_name)); + } + if (properties.containsKey(birthdate)) { + HashMap ages = new Agedater().determineAge(properties.get(birthdate).toString()); + String retrievedAge = "0 days"; + if (ages.get("years") > 0) { + retrievedAge = ages.get("years") + " years"; + } else if (ages.get("months") > 0) { + retrievedAge = ages.get("months") + " months"; + } else { + retrievedAge = ages.get("days") + " days"; + } + result += " " + String.format(infoValues.getSuccessAnswers(age).getRandomElement(), retrievedAge); + } else if (properties.containsKey(age)) { + result += " " + String.format(infoValues.getSuccessAnswers(age).getRandomElement(), properties.get(age) + " years!"); + } + + Neo4jProperty property = Neo4jProperty.getRandom(); + if (property == skills || property == abilities || property == future) { + RandomList retrievedResult = new RandomList<>(Arrays.asList(properties.get(skills).toString().split(","))); + result += " Also, " + String.format(infoValues.getSuccessAnswers(skills).getRandomElement(), retrievedResult.getRandomElement()); + } + } + + if (result.equals("")) { + result = "I am Roboy 2.0! "; + } + + // Get a random relationship fact + Neo4jRelationship predicate = roboyRelatioshipPredicates.getRandomElement(); + MemoryNodeModel node = getMemNodesByIds(roboy.getRelationships(predicate)).getRandomElement(); + if (node != null) { + String nodeName = ""; + if (node.getProperties().containsKey(full_name) && !node.getProperties().get(full_name).equals("")) { + nodeName = node.getProperties().get(full_name).toString(); + } else { + nodeName = node.getProperties().get(name).toString(); + } + result += " " + String.format(infoValues.getSuccessAnswers(predicate).getRandomElement(), nodeName); + } + + return result; + } + + @Override + protected Set getRequiredTransitionNames() { + return newSet(UPDATE_KNOWN_PERSON, LEARN_ABOUT_PERSON); + } +} diff --git a/dialog/src/main/java/roboy/dialog/states/botboy/BotBoyPersonalInformationAskingState.java b/dialog/src/main/java/roboy/dialog/states/botboy/BotBoyPersonalInformationAskingState.java new file mode 100644 index 00000000..3ebaf80f --- /dev/null +++ b/dialog/src/main/java/roboy/dialog/states/botboy/BotBoyPersonalInformationAskingState.java @@ -0,0 +1,138 @@ +package roboy.dialog.states.botboy; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import roboy.context.contextObjects.IntentValue; +import roboy.dialog.states.definitions.State; +import roboy.dialog.states.definitions.StateParameters; +import roboy.linguistics.sentenceanalysis.Interpretation; +import roboy.memory.Neo4jRelationship; +import roboy.memory.nodes.Interlocutor; +import roboy.dialog.Segue; +import roboy.util.QAJsonParser; +import roboy.util.RandomList; + +import java.util.Set; + +import static roboy.memory.Neo4jRelationship.*; + +/** + * Personal Information Asking State + * + * The state tries to interact with the Interlocutor to learn new information about the person. + * This information is sent to the Roboy Memory Module through Neo4jMemoryInterface for storing. + * Afterwards, Roboy can use this acquired data for the future interactions with the same person. + * + * - if there is no existing Interlocutor or the data is missing, ask a question + * - the question topic (intent) is selected from the Neo4jRelationship predicates + * - retrieve the questions stored in the QAList json file + * - update the Context IntentsHistory + * - try to extract the result from the Interpretation + * - retrieve the answers stored in the QAList json file + * - send the result to Memory + * + * BotBoyPersonalInformationAskingState interface: + * 1) Fallback is not required. + * 2) Outgoing transitions that have to be defined: + * - TRANSITION_INFO_OBTAINED: following state if the question was asked + * 3) Required parameters: path to the QAList.json file. + */ +public class BotBoyPersonalInformationAskingState extends State { + private QAJsonParser qaValues; + private Neo4jRelationship[] predicates = { FROM, HAS_HOBBY, WORK_FOR, STUDY_AT }; + private Neo4jRelationship selectedPredicate; + private State nextState; + + private final String TRANSITION_INFO_OBTAINED = "questionAnswering"; + private final String QA_FILE_PARAMETER_ID = "qaFile"; + final Logger LOGGER = LogManager.getLogger(); + + public final static String INTENTS_HISTORY_ID = "PIA"; + + public BotBoyPersonalInformationAskingState(String stateIdentifier, StateParameters params) { + super(stateIdentifier, params); + String qaListPath = params.getParameter(QA_FILE_PARAMETER_ID); + LOGGER.info(" -> The QAList path: " + qaListPath); + qaValues = new QAJsonParser(qaListPath); + } + + @Override + public Output act() { + Interlocutor person = getContext().ACTIVE_INTERLOCUTOR.getValue(); + LOGGER.info(" -> Retrieved Interlocutor: " + person.getName()); + + for (Neo4jRelationship predicate : predicates) { + if (!person.hasRelationship(predicate)) { + selectedPredicate = predicate; + LOGGER.info(" -> Selected predicate: " + selectedPredicate.type); + break; + } + } + RandomList questions = qaValues.getQuestions(selectedPredicate); + String question = ""; + if (questions != null && !questions.isEmpty()) { + question = questions.getRandomElement(); + LOGGER.info(" -> Selected question: " + question); + } else { + LOGGER.error(" -> The list of " + selectedPredicate.type + " questions is empty or null"); + } + try { + getContext().DIALOG_INTENTS_UPDATER.updateValue(new IntentValue(INTENTS_HISTORY_ID, selectedPredicate)); + LOGGER.info(" -> Dialog IntentsHistory updated"); + } catch (Exception e) { + LOGGER.error(" -> Error on updating the IntentHistory: " + e.getMessage()); + } + return State.Output.say(question); + } + + @Override + public Output react(Interpretation input) { + Interlocutor person = getContext().ACTIVE_INTERLOCUTOR.getValue(); + LOGGER.info("-> Retrieved Interlocutor: " + person.getName()); + RandomList answers; + String answer = "I have no words"; + String result = InferResult(input); + + if (result != null && !result.equals("")) { + LOGGER.info(" -> Inference was successful"); + answers = qaValues.getSuccessAnswers(selectedPredicate); + person.addInformation(selectedPredicate, result); + getContext().ACTIVE_INTERLOCUTOR_UPDATER.updateValue(person); + LOGGER.info(" -> Updated Interlocutor: " + person.getName()); + } else { + LOGGER.warn(" -> Inference failed"); + answers = qaValues.getFailureAnswers(selectedPredicate); + result = ""; + LOGGER.warn(" -> The result is empty. Nothing to store"); + } + if (answers != null && !answers.isEmpty()) { + answer = String.format(answers.getRandomElement(), result); + } else { + LOGGER.error(" -> The list of " + selectedPredicate + " answers is empty or null"); + } + LOGGER.info(" -> Produced answer: " + answer); + nextState = getTransition(TRANSITION_INFO_OBTAINED); + Segue s = new Segue(Segue.SegueType.CONNECTING_PHRASE, 0.5); + return Output.say(answer).setSegue(s); + } + + @Override + public State getNextState() { + return nextState; + } + + @Override + protected Set getRequiredTransitionNames() { + // optional: define all required transitions here: + return newSet(TRANSITION_INFO_OBTAINED); + } + + @Override + protected Set getRequiredParameterNames() { + return newSet(QA_FILE_PARAMETER_ID); + } + + private String InferResult(Interpretation input) { + return getInference().inferRelationship(selectedPredicate, input); + } +} diff --git a/dialog/src/main/java/roboy/dialog/states/botboy/BotBoyPersonalInformationFollowUpState.java b/dialog/src/main/java/roboy/dialog/states/botboy/BotBoyPersonalInformationFollowUpState.java new file mode 100644 index 00000000..b4f2d02b --- /dev/null +++ b/dialog/src/main/java/roboy/dialog/states/botboy/BotBoyPersonalInformationFollowUpState.java @@ -0,0 +1,168 @@ +package roboy.dialog.states.botboy; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import roboy.context.contextObjects.IntentValue; +import roboy.dialog.Segue; +import roboy.dialog.states.definitions.State; +import roboy.dialog.states.definitions.StateParameters; +import roboy.linguistics.sentenceanalysis.Interpretation; +import roboy.memory.Neo4jRelationship; +import roboy.memory.nodes.Interlocutor; +import roboy.memory.nodes.MemoryNodeModel; +import roboy.util.QAJsonParser; +import roboy.util.RandomList; + +import java.util.Set; + +import static roboy.memory.Neo4jRelationship.*; +import static roboy.memory.Neo4jProperty.*; + +/** + * Personal Information Update State + * + * This state is only entered if there are some known facts about the active interlocutor. + * The state tries to interact with the Interlocutor to update the existing information about the person. + * This information is sent to the Roboy Memory Module through Neo4jMemoryInterface to keep it up to date. + * + * - if there is an existing entry under a specific Neo4jRelationship predicate, select the predicate + * - check the Context IntentsHistory if we already asked similar questions + * - the question topic (intent) is selected upon the predicate + * - update the Context IntentsHistory with the selected predicate + * - retrieve the follow-up questions stored in the QAList json file + * - retrieve the follow-up answers stored in the QAList json file + * + * BotBoyPersonalInformationFollowUpState interface: + * 1) Fallback is not required. + * 2) Outgoing transitions that have to be defined: + * - TRANSITION_INFO_UPDATED: following state if the question was asked + * 3) Required parameters: path to the QAList.json file. + */ + +public class BotBoyPersonalInformationFollowUpState extends State { + private QAJsonParser qaValues; + private Neo4jRelationship[] predicates = { FROM, HAS_HOBBY, WORK_FOR, STUDY_AT }; + private Neo4jRelationship selectedPredicate; + private State nextState; + + private final String TRANSITION_INFO_UPDATED = "questionAnswering"; + private final String QA_FILE_PARAMETER_ID = "qaFile"; + private final Logger LOGGER = LogManager.getLogger(); + + public final static String INTENTS_HISTORY_ID = "FUP"; + + public BotBoyPersonalInformationFollowUpState(String stateIdentifier, StateParameters params) { + super(stateIdentifier, params); + String qaListPath = params.getParameter(QA_FILE_PARAMETER_ID); + LOGGER.info(" -> The QAList path: " + qaListPath); + qaValues = new QAJsonParser(qaListPath); + } + + @Override + public Output act() { + Interlocutor person = getContext().ACTIVE_INTERLOCUTOR.getValue(); + LOGGER.info("-> Retrieved Interlocutor: " + person.getName()); + + for (Neo4jRelationship predicate : predicates) { + if (person.hasRelationship(predicate) && + !getContext().DIALOG_INTENTS.contains(new IntentValue(INTENTS_HISTORY_ID, predicate)) && + !getContext().DIALOG_INTENTS.contains(new IntentValue(BotBoyPersonalInformationAskingState.INTENTS_HISTORY_ID, predicate))) { + selectedPredicate = predicate; + LOGGER.info(" -> Selected predicate: " + selectedPredicate.type); + break; + } + } + + Segue s = new Segue(Segue.SegueType.DISTRACT, 1.0); + if (selectedPredicate != null) { + RandomList questions = qaValues.getFollowUpQuestions(selectedPredicate); + String retrievedResult = ""; + RandomList nodes = getMemNodesByIds(person.getRelationships(selectedPredicate)); + if (!nodes.isEmpty()) { + retrievedResult = nodes.getRandomElement().getProperties().get(name).toString(); + LOGGER.info(" -> Retrieved memory node name: " + retrievedResult); + } else { + LOGGER.error("Could not retrieve memory data"); + } + if (!retrievedResult.equals("")) { + String question = ""; + if (questions != null && !questions.isEmpty()) { + question = String.format(questions.getRandomElement(), retrievedResult); + LOGGER.info(" -> Selected question: " + question); + } else { + LOGGER.error(" -> The list of " + selectedPredicate.type + " questions is empty or null"); + } + try { + getContext().DIALOG_INTENTS_UPDATER.updateValue(new IntentValue(INTENTS_HISTORY_ID, selectedPredicate)); + LOGGER.info(" -> Dialog IntentsHistory updated"); + } catch (Exception e) { + LOGGER.error(" -> Error on updating the IntentHistory: " + e.getMessage()); + } + return Output.say(question); + } else { + LOGGER.error("The retrieved memory data is empty"); + return Output.sayNothing().setSegue(s); + } + } else { + return Output.sayNothing().setSegue(s); + } + } + + @Override + public Output react(Interpretation input) { + Interlocutor person = getContext().ACTIVE_INTERLOCUTOR.getValue(); + LOGGER.info("-> Retrieved Interlocutor: " + person.getName()); + RandomList answers; + String answer = "I have no words"; + String result = InferUpdateResult(input); + + if (selectedPredicate != null) { + if (result != null && !result.equals("")) { + LOGGER.info(" -> Inference was successful"); + answers = qaValues.getFollowUpAnswers(selectedPredicate); + person.addInformation(selectedPredicate, result); + getContext().ACTIVE_INTERLOCUTOR_UPDATER.updateValue(person); + LOGGER.info(" -> Updated Interlocutor: " + person.getName()); + } else { + LOGGER.warn(" -> Inference failed"); + answers = qaValues.getFollowUpAnswers(selectedPredicate); + LOGGER.warn(" -> The result is empty. Nothing to update"); + } + if (answers != null && !answers.isEmpty()) { + answer = String.format(answers.getRandomElement(), ""); + } else { + LOGGER.error(" -> The list of " + selectedPredicate + " answers is empty or null"); + } + } else { + LOGGER.error(" -> Selected predicate is null"); + } + + nextState = getTransition(TRANSITION_INFO_UPDATED); + Segue s = new Segue(Segue.SegueType.CONNECTING_PHRASE); + return Output.say(answer).setSegue(s); + } + + @Override + public State getNextState() { + return nextState; + } + + @Override + protected Set getRequiredTransitionNames() { + // optional: define all required transitions here: + return newSet(TRANSITION_INFO_UPDATED); + } + + @Override + protected Set getRequiredParameterNames() { + return newSet(QA_FILE_PARAMETER_ID); + } + + private String InferUpdateResult(Interpretation input) { + String result = null; + // TODO: Implement + // TODO: Will need to consider proper conditions for processing + + return result; + } +} diff --git a/dialog/src/main/java/roboy/dialog/states/botboy/BotBoyQuestionAnsweringState.java b/dialog/src/main/java/roboy/dialog/states/botboy/BotBoyQuestionAnsweringState.java new file mode 100644 index 00000000..3e53bf00 --- /dev/null +++ b/dialog/src/main/java/roboy/dialog/states/botboy/BotBoyQuestionAnsweringState.java @@ -0,0 +1,273 @@ +package roboy.dialog.states.botboy; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import roboy.context.contextObjects.IntentValue; +import roboy.dialog.states.definitions.State; +import roboy.dialog.states.definitions.StateParameters; +import roboy.dialog.states.ordinaryStates.PersonalInformationFollowUpState; +import roboy.linguistics.Linguistics; +import roboy.linguistics.Triple; +import roboy.linguistics.sentenceanalysis.Interpretation; +import roboy.memory.Neo4jRelationship; +import roboy.memory.nodes.Interlocutor; +import roboy.memory.nodes.Interlocutor.RelationshipAvailability; +import roboy.memory.nodes.MemoryNodeModel; +import roboy.memory.nodes.Roboy; +import roboy.dialog.Segue; +import roboy.talk.PhraseCollection; +import roboy.talk.Verbalizer; +import roboy.util.RandomList; + +import static roboy.memory.Neo4jRelationship.*; +import static roboy.memory.nodes.Interlocutor.RelationshipAvailability.*; + +import java.util.List; +import java.util.Set; + +/** + * This state will answer generalStates questions. + * The parser: + * - provides triples generated from the question + * - adds the answer to the question if there is an answer in DBpedia + * - tells a specifying followup question if the interlocutor's question was ambiguous + * + * This state: + * - returns the answer if provided by the parser + * - asks the specifying followup question if provided by the parser + * - - if answered with yes --> will use the parser again to get the answer to the original question + * - if answered with no --> will use a segue to avoid answer + * - tries to query memory if there is no answer to the question + * - queries the fallback if memory fails to answer as well + * + * + * BotBoyQuestionAnsweringState interface: + * 1) Fallback is required. + * 2) Outgoing transitions that have to be defined: + * - finishedQuestionAnswering: following state if this state if finished with answering questions + * 3) No parameters are used. + */ + +public class BotBoyQuestionAnsweringState extends State { + private final Logger logger = LogManager.getLogger(); + + private final static String TRANSITION_FINISHED_ANSWERING = "finishedQuestionAnswering"; + private final static String TRANSITION_LOOP_TO_NEW_PERSON = "loopToNewPerson"; + private final static String TRANSITION_LOOP_TO_KNOWN_PERSON = "loopToKnownPerson"; + private final static int MAX_NUM_OF_QUESTIONS = 5; + private int questionsAnswered = 0; + + private final static RandomList reenteringPhrases = PhraseCollection.QUESTION_ANSWERING_REENTERING; + private final static RandomList answerStartingPhrases = PhraseCollection.QUESTION_ANSWERING_START; + + private boolean askingSpecifyingQuestion = false; + private String answerAfterUnspecifiedQuestion = ""; // the answer to use if specifying question is answered with YES + + public BotBoyQuestionAnsweringState(String stateIdentifier, StateParameters params) { + super(stateIdentifier, params); + } + + @Override + public Output act() { + + if (askingSpecifyingQuestion) { + return Output.sayNothing(); + } + + if (questionsAnswered > 0) { + return Output.say(reenteringPhrases.getRandomElement()); + } + return Output.say("I'm pretty good at answering questions about myself and other stuff. What would you like to know?"); + } + + @Override + public Output react(Interpretation input) { + + if (askingSpecifyingQuestion) { + askingSpecifyingQuestion = false; + return reactToSpecifyingAnswer(input); + + } else{ + return reactToQuestion(input); + } + + } + + /** + * React to answer of the specifying question asked previously. + * + * @param input something like "yes" or "no" + * @return answer to the answer to the original question if specifying question was answered with 'yes' + */ + private Output reactToSpecifyingAnswer(Interpretation input) { + + askingSpecifyingQuestion = false; + + // check if answer is yes + if (input.getSentence() != null && input.getSentence().contains("yes")) { + if (answerAfterUnspecifiedQuestion == null) { + // parser could parse the question but did't provide an answer + return Output.say("Not sure about the answer, " + + "but at least my amazing parser could understand you! ") + .setSegue(new Segue(Segue.SegueType.FLATTERY, 0.4)); + } else { + // tell the response previously cached in answerAfterUnspecifiedQuestion + return Output.say("In this case, " + answerStartingPhrases.getRandomElement() + answerAfterUnspecifiedQuestion); + } + + } else { + // the answer is no. we don't ask more specifying questions + // use avoid answer segue + return Output.sayNothing().setSegue(new Segue(Segue.SegueType.AVOID_ANSWER, 1)); + } + } + + private Output reactToQuestion(Interpretation input) { + + askingSpecifyingQuestion = false; + questionsAnswered++; + + Linguistics.ParsingOutcome parseOutcome = input.getParsingOutcome(); + if (parseOutcome == null) { + logger.error("Invalid parser outcome!"); + return Output.say("Invalid parser outcome!"); + } + + if (parseOutcome == Linguistics.ParsingOutcome.UNDERSPECIFIED) { + + // ambiguous question, luckily the parser has prepared a followup question + // and maybe even an answer if we are lucky (we will check in reactToSpecifyingAnswer later) + + String question = input.getUnderspecifiedQuestion(); + answerAfterUnspecifiedQuestion = input.getAnswer(); // could be null, but that's fine for now + + askingSpecifyingQuestion = true; // next input should be a yes/no answer + return Output.say("Could you be more precise, please? " + question); + } + + if (parseOutcome == Linguistics.ParsingOutcome.SUCCESS) { + if (input.getAnswer() != null) { + // tell the answer, that was provided by the parser + return Output.say(answerStartingPhrases.getRandomElement() + " " + input.getAnswer()); + + } else { + // check for triple + + + // parser could parse the question but has no answer + return useMemoryOrFallback(input); + } + } + + // from here we know that dummyParserResult.equals("FAILURE") + return useMemoryOrFallback(input); + } + + @Override + public State getNextState() { + + if (askingSpecifyingQuestion) { // we are asking a yes/no question --> stay in this state + return this; + + } else if (questionsAnswered > MAX_NUM_OF_QUESTIONS) { // enough questions answered --> finish asking + return getTransition(TRANSITION_FINISHED_ANSWERING); + + } else if (Math.random() < 0.5) { // loop back to previous states with probability 0.5 + + Interlocutor person = getContext().ACTIVE_INTERLOCUTOR.getValue(); + Neo4jRelationship[] predicates = { FROM, HAS_HOBBY, WORK_FOR, STUDY_AT }; + RelationshipAvailability availability = person.checkRelationshipAvailability(predicates); + + if (availability == SOME_AVAILABLE) { + return (Math.random() < 0.3) ? getTransition(TRANSITION_LOOP_TO_KNOWN_PERSON) : getTransition(TRANSITION_LOOP_TO_NEW_PERSON); + } else if (availability == NONE_AVAILABLE) { + return getTransition(TRANSITION_LOOP_TO_NEW_PERSON); + } else { + if (!isIntentsHistoryComplete(predicates)) { + return getTransition(TRANSITION_LOOP_TO_KNOWN_PERSON); + } else { + return this; + } + } + } else { // stay in this state + return this; + } + + } + + private Output useMemoryOrFallback(Interpretation input) { + try { + if (input.getSemTriples() != null) { + Output memoryAnswer = answerFromMemory(input.getSemTriples()); + if (memoryAnswer != null) return memoryAnswer; + } + } catch (Exception e) { + logger.warn(e.getMessage()); + } + + return Output.useFallback(); + } + + private Output answerFromMemory(List triples) { + + // try to use memory to answer + Roboy roboy = new Roboy(getMemory()); + + if (triples.size() == 0) { + return null; + } + + String answer = "I like " + inferMemoryAnswer(triples, roboy) + "humans. "; + return Output.say(answer); + } + + private String inferMemoryAnswer(List triples, Roboy roboy) { + String answer = ""; + for (Triple result : triples) { + + if (result.predicate != null) { + if (result.predicate.contains(Neo4jRelationship.HAS_HOBBY.type)) { + RandomList nodes = getMemNodesByIds(roboy.getRelationships(Neo4jRelationship.HAS_HOBBY)); + if (!nodes.isEmpty()) { + for (MemoryNodeModel node : nodes) { + answer += node.getProperties().get("name").toString() + " and "; + } + } + break; + + } else if (result.predicate.contains(Neo4jRelationship.FRIEND_OF.type)) { + answer += "my friends "; + RandomList nodes = getMemNodesByIds(roboy.getRelationships(Neo4jRelationship.FRIEND_OF)); + if (!nodes.isEmpty()) { + for (MemoryNodeModel node : nodes) { + answer += node.getProperties().get("name").toString() + " and "; + } + } + answer += " other "; + break; + } + } + } + return answer; + } + + @Override + protected Set getRequiredTransitionNames() { + return newSet(TRANSITION_FINISHED_ANSWERING, TRANSITION_LOOP_TO_NEW_PERSON, TRANSITION_LOOP_TO_KNOWN_PERSON); + } + + @Override + public boolean isFallbackRequired() { + return true; + } + + private boolean isIntentsHistoryComplete(Neo4jRelationship[] predicates) { + boolean isComplete = true; + for (Neo4jRelationship predicate : predicates) { + if (!getContext().DIALOG_INTENTS.contains(new IntentValue(BotBoyPersonalInformationFollowUpState.INTENTS_HISTORY_ID, predicate))) { + isComplete = false; + } + } + return isComplete; + } +} diff --git a/dialog/src/main/java/roboy/dialog/states/botboy/BotBoyState.java b/dialog/src/main/java/roboy/dialog/states/botboy/BotBoyState.java index f3ff4a97..884b8bdf 100644 --- a/dialog/src/main/java/roboy/dialog/states/botboy/BotBoyState.java +++ b/dialog/src/main/java/roboy/dialog/states/botboy/BotBoyState.java @@ -3,15 +3,33 @@ import org.apache.jena.atlas.logging.Log; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import roboy.dialog.Segue; import roboy.dialog.states.definitions.State; import roboy.dialog.states.definitions.StateParameters; +import roboy.emotions.RoboyEmotion; import roboy.linguistics.Linguistics; import roboy.linguistics.sentenceanalysis.Interpretation; import roboy.logic.StatementInterpreter; +import roboy.memory.Neo4jProperty; +import roboy.memory.Neo4jRelationship; +import roboy.memory.nodes.Interlocutor; +import roboy.memory.nodes.MemoryNodeModel; +import roboy.memory.nodes.Roboy; import roboy.talk.Verbalizer; +import roboy.util.Agedater; +import roboy.util.QAJsonParser; +import roboy.util.RandomList; +import java.util.Arrays; import java.util.HashMap; import java.util.Map; +import java.util.Set; + +import static roboy.memory.Neo4jProperty.*; +import static roboy.memory.Neo4jRelationship.*; +import static roboy.memory.Neo4jRelationship.SIBLING_OF; +import static roboy.memory.nodes.Interlocutor.RelationshipAvailability.NONE_AVAILABLE; +import static roboy.memory.nodes.Interlocutor.RelationshipAvailability.SOME_AVAILABLE; /** * Start a conversation with telegram. @@ -19,12 +37,27 @@ */ public class BotBoyState extends State { - private final Logger logger = LogManager.getLogger(); - private final String TRANSITION_INITIALIZED = "initialized"; - private State next; + private final Logger LOGGER = LogManager.getLogger(); + + + private QAJsonParser infoValues; + private final String INFO_FILE_PARAMETER_ID = "infoFile"; + private Neo4jRelationship[] personPredicates = { FROM, HAS_HOBBY, WORK_FOR, STUDY_AT }; + private RandomList roboyRelatioshipPredicates = new RandomList<>(FROM, MEMBER_OF, LIVE_IN, HAS_HOBBY, FRIEND_OF, CHILD_OF, SIBLING_OF); + private final String UPDATE_KNOWN_PERSON = "knownPerson"; + private final String LEARN_ABOUT_PERSON = "newPerson"; + private final RandomList successResponsePhrases = Verbalizer.KNOWN_PERSON_WITH_NAME; + private final RandomList failureResponsePhrases = Verbalizer.NEW_PERSON_WITH_NAME; + private final String TRANSITION_GREETING_DETECTED = "greetingDetected"; + + private State next; public BotBoyState(String stateIdentifiers, StateParameters params){ super(stateIdentifiers, params); + next = this; + String infoListPath = params.getParameter(INFO_FILE_PARAMETER_ID); + LOGGER.info(" -> The infoList path: " + infoListPath); + infoValues = new QAJsonParser(infoListPath); } // first we wait for conversation to start @@ -36,18 +69,129 @@ public Output act() { @Override public Output react(Interpretation input) { - String sentence = input.getSentence(); + Interlocutor person = getContext().ACTIVE_INTERLOCUTOR.getValue(); + String name = person.getName(); + if(name == null){ + String sentence = input.getSentence(); + + boolean inputOK = StatementInterpreter.isFromList(sentence, Verbalizer.greetings) || + StatementInterpreter.isFromList(sentence, Verbalizer.roboyNames) || + StatementInterpreter.isFromList(sentence, Verbalizer.triggers); + + if(inputOK){ + next = getTransition(TRANSITION_GREETING_DETECTED); + return Output.say(Verbalizer.privateGreetings.getRandomElement()).setEmotion(RoboyEmotion.HAPPINESS); + } - boolean inputOK = StatementInterpreter.isFromList(sentence, Verbalizer.greetings) || - StatementInterpreter.isFromList(sentence, Verbalizer.roboyNames) || - StatementInterpreter.isFromList(sentence, Verbalizer.triggers); + return Output.sayNothing(); + }else{ + String retrievedPersonalFact = ""; + Double segueProbability = 0.0; + String response = Verbalizer.privateGreetings.getRandomElement(); + // 4. check if person is known/familiar + if (person.FAMILIAR) { + // 4a. person known/familiar + // TODO: get some hobbies or occupation of the person to make answer more interesting + RandomList nodes = getMemNodesByIds(person.getRelationships(FRIEND_OF)); + if (!nodes.isEmpty()) { + retrievedPersonalFact = " You are friends with " + + nodes.getRandomElement().getProperties().get(Neo4jProperty.name).toString(); + } - if(inputOK){ - next = getTransition(TRANSITION_INITIALIZED); - return Output.say(Verbalizer.greetings.getRandomElement()); + Interlocutor.RelationshipAvailability availability = person.checkRelationshipAvailability(personPredicates); + if (availability == SOME_AVAILABLE) { + next = (Math.random() < 0.3) ? getTransition(UPDATE_KNOWN_PERSON) : getTransition(LEARN_ABOUT_PERSON); + } else if (availability == NONE_AVAILABLE) { + next = getTransition(LEARN_ABOUT_PERSON); + } else { + next = getTransition(UPDATE_KNOWN_PERSON); + } + +// String retrievedRoboyFacts = getRoboyFactsPhrase(new Roboy(getMemory())); + Segue s = new Segue(Segue.SegueType.DISTRACT, segueProbability); + response += " " + getResponsePhrase(person.getName(), person.FAMILIAR); + } else { + // 4b. person is not known + next = getTransition(LEARN_ABOUT_PERSON); + segueProbability = 0.3; + + String retrievedRoboyFacts = getRoboyFactsPhrase(new Roboy(getMemory())); + Segue s = new Segue(Segue.SegueType.DISTRACT, segueProbability); + response += " " + getResponsePhrase(person.getName(), person.FAMILIAR) + retrievedRoboyFacts; + + } + return Output.say(response) + .setEmotion(RoboyEmotion.positive.getRandomElement()); } - return Output.sayNothing(); + } + private String getResponsePhrase(String name, boolean familiar) { + if (familiar) { + return String.format(successResponsePhrases.getRandomElement(), name); + } else { + return String.format(failureResponsePhrases.getRandomElement(), name); + } + } + + private String getRoboyFactsPhrase(Roboy roboy) { + String result = ""; + + // Get some random properties facts + if (roboy.getProperties() != null && !roboy.getProperties().isEmpty()) { + HashMap properties = roboy.getProperties(); + if (properties.containsKey(full_name)) { + result += " " + String.format(infoValues.getSuccessAnswers(full_name).getRandomElement(), properties.get(full_name)); + } + if (properties.containsKey(birthdate)) { + HashMap ages = new Agedater().determineAge(properties.get(birthdate).toString()); + String retrievedAge = "0 days"; + if (ages.get("years") > 0) { + retrievedAge = ages.get("years") + " years"; + } else if (ages.get("months") > 0) { + retrievedAge = ages.get("months") + " months"; + } else { + retrievedAge = ages.get("days") + " days"; + } + result += " " + String.format(infoValues.getSuccessAnswers(age).getRandomElement(), retrievedAge); + } else if (properties.containsKey(age)) { + result += " " + String.format(infoValues.getSuccessAnswers(age).getRandomElement(), properties.get(age) + " years!"); + } + if (properties.containsKey(skills)) { + RandomList retrievedResult = new RandomList<>(Arrays.asList(properties.get(skills).toString().split(","))); + result += " " + String.format(infoValues.getSuccessAnswers(skills).getRandomElement(), retrievedResult.getRandomElement()); + } + if (properties.containsKey(abilities)) { + RandomList retrievedResult = new RandomList<>(Arrays.asList(properties.get(abilities).toString().split(","))); + result += " " + String.format(infoValues.getSuccessAnswers(abilities).getRandomElement(), retrievedResult.getRandomElement()); + } + if (properties.containsKey(future)) { + RandomList retrievedResult = new RandomList<>(Arrays.asList(properties.get(future).toString().split(","))); + result += " " + String.format(infoValues.getSuccessAnswers(future).getRandomElement(), retrievedResult.getRandomElement()); + } + if (properties.containsKey(dreams)) { + RandomList retrievedResult = new RandomList<>(Arrays.asList(properties.get(dreams).toString().split(","))); + result += " " + String.format(infoValues.getSuccessAnswers(dreams).getRandomElement(), retrievedResult.getRandomElement()); + } + } + + if (result.equals("")) { + result = "I am Roboy 2.0! "; + } + + // Get a random relationship fact + Neo4jRelationship predicate = roboyRelatioshipPredicates.getRandomElement(); + MemoryNodeModel node = getMemNodesByIds(roboy.getRelationships(predicate)).getRandomElement(); + if (node != null) { + String nodeName = ""; + if (node.getProperties().containsKey(full_name) && !node.getProperties().get(full_name).equals("")) { + nodeName = node.getProperties().get(full_name).toString(); + } else { + nodeName = node.getProperties().get(name).toString(); + } + result += " " + String.format(infoValues.getSuccessAnswers(predicate).getRandomElement(), nodeName); + } + + return result; } @Override @@ -55,5 +199,20 @@ public State getNextState() { return next; } + @Override + protected Set getRequiredTransitionNames() { + return newSet(TRANSITION_GREETING_DETECTED); + } + + @Override + protected Set getRequiredParameterNames() { + return newSet(); // empty set + } + + @Override + public boolean isFallbackRequired() { + return false; + } + } \ No newline at end of file diff --git a/dialog/src/main/java/roboy/dialog/states/definitions/MonologState.java b/dialog/src/main/java/roboy/dialog/states/definitions/MonologState.java new file mode 100644 index 00000000..72c481a4 --- /dev/null +++ b/dialog/src/main/java/roboy/dialog/states/definitions/MonologState.java @@ -0,0 +1,39 @@ +package roboy.dialog.states.definitions; + + +import roboy.linguistics.sentenceanalysis.Interpretation; + +public abstract class MonologState extends State { + + /** + * Create a state object with given identifier (state name) and parameters. + *

+ * The parameters should contain a reference to a state machine for later use. + * The state will not automatically add itself to the state machine. + * + * @param stateIdentifier identifier (name) of this state + * @param params parameters for this state, should contain a reference to a state machine + */ + public MonologState(String stateIdentifier, StateParameters params) { + super(stateIdentifier, params); + } + + + /** + * Defines how to react to an input. This is usually the answer to the incoming question or some other statement. + * If this state can't react, it can return 'null' to trigger the fallback state for the answer. + * + * Note: In the new architecture, react() does not define the next state anymore! Reaction and state + * transitions are now decoupled. State transitions are defined in getNextState() + * + * @param input input from the person we talk to + * @return reaction to the input (should not be null) + */ + @Override + public Output react(Interpretation input){ + + return Output.skipInput(); + } + + +} diff --git a/dialog/src/main/java/roboy/dialog/states/definitions/State.java b/dialog/src/main/java/roboy/dialog/states/definitions/State.java index 8dbea581..d2101166 100644 --- a/dialog/src/main/java/roboy/dialog/states/definitions/State.java +++ b/dialog/src/main/java/roboy/dialog/states/definitions/State.java @@ -64,13 +64,14 @@ public static class Output { private final Logger logger = LogManager.getLogger(); public enum OutputType { - INTERPRETATION, SAY_NOTHING, USE_FALLBACK, END_CONVERSATION + INTERPRETATION, SAY_NOTHING, USE_FALLBACK, END_CONVERSATION, SKIP_INPUT } private final OutputType type; private final Interpretation interpretation; private Segue segue; private RoboyEmotion emotion; + private String sound; /** * Private constructor, used only inside static methods. @@ -81,7 +82,6 @@ private Output(OutputType type, Interpretation interpretation) { this.type = type; this.interpretation = interpretation; this.segue = null; - this.emotion = null; if(interpretation != null){ this.emotion = interpretation.getEmotion(); } @@ -151,6 +151,14 @@ public static Output endConversation(String lastWords) { return new Output(OutputType.END_CONVERSATION, new Interpretation(lastWords)); } + /** + * Skip the users input + * @return State.Output object with appropriate settings + */ + public static Output skipInput() { + return new Output(OutputType.SKIP_INPUT, null); + } + // Non-static methods @@ -170,6 +178,10 @@ public boolean isEndOfConversation() { return type == OutputType.END_CONVERSATION; } + public boolean isSkippingUser() { + return type == OutputType.SKIP_INPUT; + } + public Interpretation getInterpretation() { return interpretation; } @@ -215,6 +227,18 @@ public Output setEmotion(RoboyEmotion emotion) { public boolean hasEmotion() { return emotion != null; } public RoboyEmotion getEmotion() { return emotion; } + public Output addSound(String filename) { + if (type == OutputType.USE_FALLBACK) { + logger.warn("Adding a sound to an answer that requires fallback is not allowed! " + + "Sound behaviour is defined in the fallback state."); + } + this.sound = filename; + return this; + } + + public boolean hasSound() {return sound != null; } + public String getSoundFilename() { return sound; } + } //endregion diff --git a/dialog/src/main/java/roboy/dialog/states/devoStates/IntroductionState.java b/dialog/src/main/java/roboy/dialog/states/devoStates/IntroductionState.java new file mode 100644 index 00000000..72e7bae8 --- /dev/null +++ b/dialog/src/main/java/roboy/dialog/states/devoStates/IntroductionState.java @@ -0,0 +1,213 @@ +package roboy.dialog.states.devoStates; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import roboy.dialog.Segue; +import roboy.dialog.states.definitions.State; +import roboy.dialog.states.definitions.StateParameters; +import roboy.linguistics.sentenceanalysis.Interpretation; +import roboy.memory.Neo4jProperty; +import roboy.memory.Neo4jRelationship; +import roboy.memory.nodes.Interlocutor; +import roboy.memory.nodes.Interlocutor.RelationshipAvailability; +import roboy.memory.nodes.MemoryNodeModel; +import roboy.memory.nodes.Roboy; +import roboy.util.Agedater; +import roboy.util.QAJsonParser; +import roboy.util.RandomList; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.Set; + +import static roboy.memory.Neo4jProperty.*; +import static roboy.memory.Neo4jRelationship.*; +import static roboy.memory.nodes.Interlocutor.RelationshipAvailability.NONE_AVAILABLE; +import static roboy.memory.nodes.Interlocutor.RelationshipAvailability.SOME_AVAILABLE; + +/** + * This state will: + * - ask the interlocutor for his name + * - query memory if the person is already known + * - create and update the interlocutor in the context + * - take one of two transitions: knownPerson or newPerson + * + * IntroductionState interface: + * 1) Fallback is not required. + * 2) Outgoing transitions that have to be defined: + * - knownPerson: following state if the person is already known + * - newPerson: following state if the person is NOT known + * 3) No parameters are used. + */ +public class IntroductionState extends State { + private QAJsonParser infoValues; + private final String UPDATE_KNOWN_PERSON = "knownPerson"; + private final String LEARN_ABOUT_PERSON = "newPerson"; + private final Logger LOGGER = LogManager.getLogger(); + private final String INFO_FILE_PARAMETER_ID = "infoFile"; + private final RandomList introPhrases = new RandomList<>("What's your name?"); + private final RandomList successResponsePhrases = new RandomList<>("Hey, I know you, %s!"); + private final RandomList failureResponsePhrases = new RandomList<>("Nice to meet you, %s!"); + + private Neo4jRelationship[] personPredicates = { FROM, HAS_HOBBY, WORK_FOR, STUDY_AT }; + private RandomList roboyRelatioshipPredicates = new RandomList<>(FROM, MEMBER_OF, LIVE_IN, HAS_HOBBY, FRIEND_OF, CHILD_OF, SIBLING_OF); + private RandomList roboyPropertiesPredicates = new RandomList<>(skills, abilities, future); + private State nextState; + + public IntroductionState(String stateIdentifier, StateParameters params) { + super(stateIdentifier, params); + String infoListPath = params.getParameter(INFO_FILE_PARAMETER_ID); + LOGGER.info(" -> The infoList path: " + infoListPath); + infoValues = new QAJsonParser(infoListPath); + } + + @Override + public Output act() { + return Output.say(getIntroPhrase()); + } + + @Override + public Output react(Interpretation input) { + // expecting something like "My name is NAME" + + // 1. get name + String name = getNameFromInput(input); + + if (name == null) { + // input couldn't be parsed properly + // TODO: do something intelligent if the parser fails + nextState = this; + LOGGER.warn("IntroductionState couldn't get name! Staying in the same state."); + return Output.say("Sorry, my parser is out of service."); + // alternatively: Output.useFallback() or Output.sayNothing() + } + + + // 2. get interlocutor object from context + // this also should query memory and do other magic + Interlocutor person = getContext().ACTIVE_INTERLOCUTOR.getValue(); + person.addName(name); + // Roboy roboy = new Roboy(getMemory()); + + + // 3. update interlocutor in context + updateInterlocutorInContext(person); + String retrievedPersonalFact = ""; + Double segueProbability = 0.0; + + // 4. check if person is known/familiar + if (person.FAMILIAR) { + // 4a. person known/familiar + // TODO: get some hobbies or occupation of the person to make answer more interesting + RandomList nodes = getMemNodesByIds(person.getRelationships(FRIEND_OF)); + if (!nodes.isEmpty()) { + retrievedPersonalFact = " You are friends with " + + nodes.getRandomElement().getProperties().get(Neo4jProperty.name).toString(); + } + + RelationshipAvailability availability = person.checkRelationshipAvailability(personPredicates); + if (availability == SOME_AVAILABLE) { + nextState = (Math.random() < 0.3) ? getTransition(UPDATE_KNOWN_PERSON) : getTransition(LEARN_ABOUT_PERSON); + } else if (availability == NONE_AVAILABLE) { + nextState = getTransition(LEARN_ABOUT_PERSON); + } else { + nextState = getTransition(UPDATE_KNOWN_PERSON); + } + } else { + // 4b. person is not known + nextState = getTransition(LEARN_ABOUT_PERSON); + segueProbability = 0.6; + } + String retrievedRoboyFacts = getRoboyFactsPhrase(new Roboy(getMemory())); + Segue s = new Segue(Segue.SegueType.DISTRACT, segueProbability); + return Output.say(getResponsePhrase(person.getName(), person.FAMILIAR) + + retrievedPersonalFact + retrievedRoboyFacts).setSegue(s); + } + + @Override + public State getNextState() { + return nextState; + } + + private String getNameFromInput(Interpretation input) { + return getInference().inferProperty(name, input); + } + + private void updateInterlocutorInContext(Interlocutor interlocutor) { + getContext().ACTIVE_INTERLOCUTOR_UPDATER.updateValue(interlocutor); + } + + private String getIntroPhrase() { + return introPhrases.getRandomElement(); + } + + private String getResponsePhrase(String name, boolean familiar) { + if (familiar) { + return String.format(successResponsePhrases.getRandomElement(), name); + } else { + return String.format(failureResponsePhrases.getRandomElement(), name); + } + } + + private String getRoboyFactsPhrase(Roboy roboy) { + String result = ""; + + // Get some random properties facts + if (roboy.getProperties() != null && !roboy.getProperties().isEmpty()) { + HashMap properties = roboy.getProperties(); + if (properties.containsKey(full_name)) { + result += " " + String.format(infoValues.getSuccessAnswers(full_name).getRandomElement(), properties.get(full_name)); + } + if (properties.containsKey(birthdate)) { + HashMap ages = new Agedater().determineAge(properties.get(birthdate).toString()); + String retrievedAge = "0 days"; + if (ages.get("years") > 0) { + retrievedAge = ages.get("years") + " years"; + } else if (ages.get("months") > 0) { + retrievedAge = ages.get("months") + " months"; + } else { + retrievedAge = ages.get("days") + " days"; + } + result += " " + String.format(infoValues.getSuccessAnswers(age).getRandomElement(), retrievedAge); + } else if (properties.containsKey(age)) { + result += " " + String.format(infoValues.getSuccessAnswers(age).getRandomElement(), properties.get(age) + " years!"); + } + if (properties.containsKey(skills)) { + RandomList retrievedResult = new RandomList<>(Arrays.asList(properties.get(skills).toString().split(","))); + result += " " + String.format(infoValues.getSuccessAnswers(skills).getRandomElement(), retrievedResult.getRandomElement()); + } + if (properties.containsKey(abilities)) { + RandomList retrievedResult = new RandomList<>(Arrays.asList(properties.get(abilities).toString().split(","))); + result += " " + String.format(infoValues.getSuccessAnswers(abilities).getRandomElement(), retrievedResult.getRandomElement()); + } + if (properties.containsKey(future)) { + RandomList retrievedResult = new RandomList<>(Arrays.asList(properties.get(future).toString().split(","))); + result += " " + String.format(infoValues.getSuccessAnswers(future).getRandomElement(), retrievedResult.getRandomElement()); + } + } + + if (result.equals("")) { + result = "I am Roboy 2.0! "; + } + + // Get a random relationship fact + Neo4jRelationship predicate = roboyRelatioshipPredicates.getRandomElement(); + MemoryNodeModel node = getMemNodesByIds(roboy.getRelationships(predicate)).getRandomElement(); + if (node != null) { + String nodeName = ""; + if (node.getProperties().containsKey(full_name) && !node.getProperties().get(full_name).equals("")) { + nodeName = node.getProperties().get(full_name).toString(); + } else { + nodeName = node.getProperties().get(name).toString(); + } + result += " " + String.format(infoValues.getSuccessAnswers(predicate).getRandomElement(), nodeName); + } + + return result; + } + + @Override + protected Set getRequiredTransitionNames() { + return newSet(UPDATE_KNOWN_PERSON, LEARN_ABOUT_PERSON); + } +} diff --git a/dialog/src/main/java/roboy/dialog/states/devoStates/PersonalInformationAskingState.java b/dialog/src/main/java/roboy/dialog/states/devoStates/PersonalInformationAskingState.java new file mode 100644 index 00000000..1b7cf5f9 --- /dev/null +++ b/dialog/src/main/java/roboy/dialog/states/devoStates/PersonalInformationAskingState.java @@ -0,0 +1,92 @@ +package roboy.dialog.states.devoStates; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import roboy.context.contextObjects.IntentValue; +import roboy.dialog.Segue; +import roboy.dialog.states.definitions.State; +import roboy.dialog.states.definitions.StateParameters; +import roboy.linguistics.sentenceanalysis.Interpretation; +import roboy.memory.Neo4jRelationship; +import roboy.memory.nodes.Interlocutor; +import roboy.util.QAJsonParser; +import roboy.util.RandomList; + +import java.util.Set; + +import static roboy.memory.Neo4jRelationship.*; + +/** + * Personal Information Asking State + * + * The state tries to interact with the Interlocutor to learn new information about the person. + * This information is sent to the Roboy Memory Module through Neo4jMemoryInterface for storing. + * Afterwards, Roboy can use this acquired data for the future interactions with the same person. + * + * - if there is no existing Interlocutor or the data is missing, ask a question + * - the question topic (intent) is selected from the Neo4jRelationship predicates + * - retrieve the questions stored in the QAList json file + * - update the Context IntentsHistory + * - try to extract the result from the Interpretation + * - retrieve the answers stored in the QAList json file + * - send the result to Memory + * + * PersonalInformationAskingState interface: + * 1) Fallback is not required. + * 2) Outgoing transitions that have to be defined: + * - TRANSITION_INFO_OBTAINED: following state if the question was asked + * 3) Required parameters: path to the QAList.json file. + */ +public class PersonalInformationAskingState extends State { + private QAJsonParser qaValues; + private Neo4jRelationship[] predicates = { FROM, HAS_HOBBY, WORK_FOR, STUDY_AT }; + private Neo4jRelationship selectedPredicate; + private State nextState; + + private final String TRANSITION_INFO_OBTAINED = "questionAnswering"; + private final String QA_FILE_PARAMETER_ID = "qaFile"; + final Logger LOGGER = LogManager.getLogger(); + + public final static String INTENTS_HISTORY_ID = "PIA"; + + public PersonalInformationAskingState(String stateIdentifier, StateParameters params) { + super(stateIdentifier, params); + String qaListPath = params.getParameter(QA_FILE_PARAMETER_ID); + LOGGER.info(" -> The QAList path: " + qaListPath); + qaValues = new QAJsonParser(qaListPath); + } + + @Override + public Output act() { + Interlocutor person = getContext().ACTIVE_INTERLOCUTOR.getValue(); + LOGGER.info(" -> Retrieved Interlocutor: " + person.getName()); + + return Output.say("What is my purpose?"); + } + + @Override + public Output react(Interpretation input) { + nextState = getTransition(TRANSITION_INFO_OBTAINED); + return Output.say("Oh. My. God."); + } + + @Override + public State getNextState() { + return nextState; + } + + @Override + protected Set getRequiredTransitionNames() { + // optional: define all required transitions here: + return newSet(TRANSITION_INFO_OBTAINED); + } + + @Override + protected Set getRequiredParameterNames() { + return newSet(QA_FILE_PARAMETER_ID); + } + + private String InferResult(Interpretation input) { + return getInference().inferRelationship(selectedPredicate, input); + } +} diff --git a/dialog/src/main/java/roboy/dialog/states/devoStates/QuestionRoboyQAState.java b/dialog/src/main/java/roboy/dialog/states/devoStates/QuestionRoboyQAState.java new file mode 100644 index 00000000..5de2cfd4 --- /dev/null +++ b/dialog/src/main/java/roboy/dialog/states/devoStates/QuestionRoboyQAState.java @@ -0,0 +1,439 @@ +package roboy.dialog.states.devoStates; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import roboy.context.contextObjects.IntentValue; +import roboy.dialog.Segue; +import roboy.dialog.states.definitions.ExpoState; +import roboy.dialog.states.definitions.State; +import roboy.dialog.states.definitions.StateParameters; +import roboy.dialog.states.ordinaryStates.PersonalInformationFollowUpState; +import roboy.emotions.RoboyEmotion; +import roboy.linguistics.Linguistics; +import roboy.linguistics.Linguistics.SemanticRole; +import roboy.linguistics.Triple; +import roboy.linguistics.sentenceanalysis.Interpretation; +import roboy.logic.StatementInterpreter; +import roboy.memory.Neo4jRelationship; +import roboy.memory.Neo4jProperty; +import roboy.memory.nodes.Interlocutor; +import roboy.memory.nodes.MemoryNodeModel; +import roboy.memory.nodes.Roboy; +import roboy.talk.PhraseCollection; +import roboy.talk.Verbalizer; +import roboy.util.Agedater; +import roboy.util.Pair; +import roboy.util.QAJsonParser; +import roboy.util.RandomList; +import roboy.util.api.*; + +import java.util.*; + +import static roboy.memory.Neo4jProperty.full_name; +import static roboy.memory.Neo4jProperty.name; +import static roboy.memory.Neo4jRelationship.*; +import static roboy.memory.nodes.Interlocutor.RelationshipAvailability.NONE_AVAILABLE; +import static roboy.memory.nodes.Interlocutor.RelationshipAvailability.SOME_AVAILABLE; + +/** + * QuestionAnsweringState + * Roboy Question Answering State + * + * The parser: + * - provides triples generated from the question + * - adds the answer to the question if there is an answer in DBpedia + * - tells a specifying followup question if the interlocutor's question was ambiguous + * + * This state: + * - checks if interlocutor wants to play a game + * - returns the answer if provided by the parser + * - asks the specifying followup question if provided by the parser + * - - if answered with yes --> will use the parser again to get the answer to the original question + * - if answered with no --> will use a segue to avoid answer + * - tries to query memory if there is no answer to the question + * - queries the fallback if memory fails to answer as well + * + * + * QuestionAnsweringState interface: + * 1) Fallback is required. + * 2) Outgoing transitions that have to be defined: + * - finishedQuestionAnswering: following state if this state if finished with answering questions + * 3) No parameters are used. + */ +public class QuestionRoboyQAState extends ExpoState { + private final Logger LOGGER = LogManager.getLogger(); + + private final static String TRANSITION_FINISHED_ANSWERING = "finishedQuestionAnswering"; + private final static String TRANSITION_LOOP_TO_NEW_PERSON = "loopToNewPerson"; + private final static String TRANSITION_LOOP_TO_KNOWN_PERSON = "loopToKnownPerson"; + private final static String TRANSITION_SWITCH_TO_GAMING = "switchToGaming"; + private final static String TRANSITION_STORY = "tellStory"; + private final static int MAX_NUM_OF_QUESTIONS = 3; + private int questionsAnswered = 0; + + private final static RandomList reenteringPhrases = PhraseCollection.QUESTION_ANSWERING_REENTERING; + private final static RandomList answerStartingPhrases = PhraseCollection.QUESTION_ANSWERING_START; + private final String INFO_FILE_PARAMETER_ID = "infoFile"; + + private boolean offeredGame = false; + private boolean userWantsGame = false; + private boolean offeredStory = false; + private boolean userWantsStory = false; + + private QAJsonParser infoValues; + + public QuestionRoboyQAState(String stateIdentifier, StateParameters params) { + super(stateIdentifier, params); + String infoListPath = params.getParameter(INFO_FILE_PARAMETER_ID); + LOGGER.info("The infoList path: " + infoListPath); + infoValues = new QAJsonParser(infoListPath); + } + + @Override + public Output act() { + if (questionsAnswered >= MAX_NUM_OF_QUESTIONS && !offeredGame) { + offeredGame = true; + return Output.say(PhraseCollection.OFFER_GAME_PHRASES.getRandomElement()); + } + else + offeredGame = false; + // if(Math.random() < 0.05) { + // offeredStory = true; + // return Output.say(Verbalizer.confirmStory.getRandomElement()); + // } + return Output.sayNothing(); + } + + @Override + public Output react(Interpretation input) { + return reactToQuestion(input); + } + private Output reactToQuestion(Interpretation input) + { + // -- Decide whether to go forward on proposed transitions + + if (offeredGame) { + if (input.getSentiment() == Linguistics.UtteranceSentiment.POSITIVE || + input.getSentiment() == Linguistics.UtteranceSentiment.NEUTRAL || + input.getSentiment() == Linguistics.UtteranceSentiment.UNCERTAIN_POS || + input.getSentiment() == Linguistics.UtteranceSentiment.MAYBE + ) { + userWantsGame = true; + questionsAnswered++; + return Output.sayNothing().setSegue(new Segue(Segue.SegueType.PICKUP,0.5)).setEmotion(RoboyEmotion.HAPPY); + } + else { + return Output.sayNothing().setEmotion(RoboyEmotion.SADNESS); + } + } + + if (offeredStory || input.getTokens().contains("story") || input.getTokens().contains("interesting")) { + offeredGame = false; + if (StatementInterpreter.isFromList(input.getSentence(), Verbalizer.consent)) { + questionsAnswered++; + userWantsStory = true; + return Output.say(Verbalizer.startSomething.getRandomElement()); + } + } + + // -- Reset transition proposals + + userWantsGame = false; + userWantsStory = false; + questionsAnswered++; + + // -- Try to interpret input as API request + + String answer = inferApiAnswer(input); + if (!answer.isEmpty()) { + return Output.say(answer); + } + + // -- Try to interpret input as Joke request + + if (input.getTokens().contains("joke") || input.getTokens().contains("funny")) { + return Output.say(PhraseCollection.JOKES.getRandomElement()).setEmotion(RoboyEmotion.positive.getRandomElement()); + } + + // -- Try to interpret input as Memory request + + try { + if ( input.getPas() != null || input.getTriples() != null) { + // try to use memory to answer + Roboy roboy = new Roboy(getMemory()); + answer = inferMemoryAnswer(input, roboy); + //String answer = String.format(infoValues.getSuccessAnswers(predicate).getRandomElement(), inferMemoryAnswer(input, roboy)); + if (!answer.isEmpty()) { + return Output.say(answer); + } + } + } catch (Exception e) { + LOGGER.warn(e.getMessage()); + } + + // -- Try to interpret input as parsable question + + Linguistics.ParsingOutcome parseOutcome = input.getParsingOutcome(); + if (parseOutcome == Linguistics.ParsingOutcome.SUCCESS) { + if (input.getAnswer() != null) { + // tell the answer, that was provided by the parser + return Output.say(answerStartingPhrases.getRandomElement()+" "+input.getAnswer()); + } + } + + return Output.useFallback(); + } + + @Override + public State getNextState() { + State nextState = null; + if (userWantsGame) { + nextState = getTransition(TRANSITION_SWITCH_TO_GAMING); + } + else if (userWantsStory) { + nextState = getTransition(TRANSITION_STORY); + } + else if (questionsAnswered > MAX_NUM_OF_QUESTIONS) { // enough questions answered --> finish asking + nextState = getTransition(TRANSITION_FINISHED_ANSWERING); + } + if (nextState != null) { + userWantsGame = false; + userWantsStory = false; + questionsAnswered = 0; + return nextState; + } + return this; + } + + private String inferApiAnswer(Interpretation input) { + Map pas = input.getPas(); + String answer = ""; + if (matchPas(pas, new Pair(SemanticRole.PATIENT, ".*\\bweather\\b.*"))) { + try { + answer = String.format("It seems like it is %s out there!", Weather.getData("munich")); + } + catch (Exception e) { + answer = "It seems a bit moody..."; + LOGGER.error(e.getMessage()); + } + } else if (matchPas(pas, new Pair(SemanticRole.AGENT, ".*\\bmovie.*"))) { + try { + answer = String.format("I have heard that %s is playing!", Movie.getData("title")); + } + catch (Exception e) { + answer = "Wall e is a great movie!"; + LOGGER.error(e.getMessage()); + } + } else if (matchPas(pas, new Pair(SemanticRole.PATIENT, ".+ in .+"), new Pair(SemanticRole.MANNER, "how"), new Pair(SemanticRole.PREDICATE, "say"), new Pair(SemanticRole.AGENT, "you")) || + matchPas(pas, new Pair(SemanticRole.PATIENT, ".+ in .+"), new Pair(SemanticRole.PREDICATE, "is"), new Pair(SemanticRole.AGENT, "what"))) { + String[] parts = pas.get(SemanticRole.PATIENT).split(" in "); + assert(parts.length == 2); + try { + answer = answerStartingPhrases.getRandomElement() + " " + Translate.getData(parts[0], parts[1]); + } + catch (Exception e) { + answer = String.format("I am not sure whether I know %s", parts[1]); + LOGGER.error(e.getMessage()); + } + } + return answer; + } + + private String inferMemoryAnswer(Interpretation input, Roboy roboy) { + + String answer = ""; + Map pas = input.getPas(); + List triples = input.getTriples(); + + if (pas != null) { + answer = inferPasAnswer(pas, roboy); + if (!answer.isEmpty()) { + return answer; + } + } + + if (triples != null) { + return inferTripleAnswer(triples, roboy); + } + + if (input.getObjAnswer() != null) { + String objAnswer = input.getObjAnswer().toLowerCase(); + if (!objAnswer.equals("")) { + LOGGER.info("OBJ_ANSWER: " + objAnswer); + Neo4jRelationship predicate = inferPredicateFromObjectAnswer(objAnswer); + if (predicate != null) { + answer = extractNodeNameForPredicate(predicate, roboy); + } + } else { + LOGGER.warn("OBJ_ANSWER is empty"); + } + } + + return answer; + } + + private String inferPasAnswer(Map pas, Roboy roboy) { + String answer = ""; + if (matchPas(pas, new Pair(SemanticRole.AGENT, "old")) || matchPas(pas, new Pair(SemanticRole.PATIENT, ".*\\bage\\b.*"))) { + answer = extractAge(roboy); + } else if (matchPas(pas, new Pair(SemanticRole.PREDICATE, "from"))) { + answer = extractNodeNameForPredicate(Neo4jRelationship.FROM, roboy); + } + else if (matchPas(pas, new Pair(SemanticRole.LOCATION, "where"), new Pair(SemanticRole.PREDICATE, "live"))) { + answer = extractNodeNameForPredicate(Neo4jRelationship.LIVE_IN, roboy); + } + else if (matchPas(pas, new Pair(SemanticRole.AGENT, "you"), new Pair(SemanticRole.MANNER, "how"))) { + answer = "I am really happy!"; + } + else if (matchPas(pas, new Pair(SemanticRole.AGENT, "who"))) { + if (matchPas(pas, new Pair(SemanticRole.PATIENT, "you"), new Pair(SemanticRole.PREDICATE, "are"))) { + answer = extractNodeNameForPredicate(Neo4jProperty.name, roboy) + " " + + extractNodeNameForPredicate(Neo4jProperty.identitiy, roboy); + } else if (matchPas(pas, new Pair(SemanticRole.PATIENT, ".*\\b(father|dad)\\b.*"))) { + answer = extractNodeNameForPredicate(Neo4jRelationship.CHILD_OF, roboy); + } else if (matchPas(pas, new Pair(SemanticRole.PATIENT, ".*\\b(sibling|brother)\\b.*"))){ + answer = extractNodeNameForPredicate(Neo4jRelationship.SIBLING_OF, roboy); + } else if (matchPas(pas, new Pair(SemanticRole.PREDICATE, "created|made|built"), new Pair(SemanticRole.PATIENT, "you"))) { + answer = extractNodeNameForPredicate(Neo4jRelationship.CREATED_BY, roboy); + } + } else if (matchPas(pas, new Pair(SemanticRole.PREDICATE, "do|like"), new Pair(SemanticRole.AGENT, "you"))){ +// double prob = Math.random(); +// if (prob < .3) { +// answer = extractNodeNameForPredicate(Neo4jProperty.abilities, roboy); +// } else if(prob < .7) { +// answer = extractNodeNameForPredicate(Neo4jRelationship.HAS_HOBBY, roboy); +// } else { + answer = extractNodeNameForPredicate(Neo4jProperty.skills, roboy); +// } + } else if (matchPas(pas, new Pair(SemanticRole.PREDICATE, "dream|wish"), new Pair(SemanticRole.AGENT, "you"))) { + answer = extractNodeNameForPredicate(Neo4jProperty.dreams, roboy); + } + else if (matchPas(pas, new Pair(SemanticRole.PATIENT, "you"), new Pair(SemanticRole.PREDICATE, "are"), + new Pair(SemanticRole.AGENT, "what"))) { + answer = extractNodeNameForPredicate(Neo4jProperty.name, roboy) + " " + + extractNodeNameForPredicate(Neo4jProperty.identitiy, roboy); + } + + return answer; + } + + private String inferTripleAnswer(List triples, Roboy roboy) { + String answer = ""; + for (Triple t: triples) { + if (t.subject.matches(".*\\b(meet|see|know)\\b.*")) { + answer = infoValues.getSuccessAnswers(Neo4jProperty.media).getRandomElement(); + } + } + // else if {OBJ: *} -> query * -> I'm sure I know a typeof(*) called *! (Where does he live? :)) + // + // if * in Neo4jRelationship.FRIEND_OF + return answer; + } + + private Neo4jRelationship inferPredicateFromObjectAnswer(String objectAnswer) { + if (objectAnswer.contains("hobby")) { + return Neo4jRelationship.HAS_HOBBY; + } else if (objectAnswer.contains("member")) { + return Neo4jRelationship.MEMBER_OF; + } else if (objectAnswer.contains("friend")) { + return Neo4jRelationship.FRIEND_OF; + } else if (objectAnswer.contains("where") || + objectAnswer.contains("city") || + objectAnswer.contains("place") || + objectAnswer.contains("country") || + objectAnswer.contains("live") || + objectAnswer.contains("life")) { + return Neo4jRelationship.LIVE_IN; + } else if (objectAnswer.contains("from") || + objectAnswer.contains("born")) { + return Neo4jRelationship.FROM; + } else if (objectAnswer.contains("child") || + objectAnswer.contains("father") || + objectAnswer.contains("dad") || + objectAnswer.contains("parent")) { + return Neo4jRelationship.CHILD_OF; + } else if (objectAnswer.contains("brother") || + objectAnswer.contains("family") || + objectAnswer.contains("relativ")) { + return Neo4jRelationship.SIBLING_OF; + } + return null; + } + + private String extractNodeNameForPredicate(Neo4jRelationship predicate, Roboy roboy) { + MemoryNodeModel node = getMemNodesByIds(roboy.getRelationships(predicate)).getRandomElement(); + if (node != null) { + String nodeName; + if (node.getProperties().containsKey(full_name) && !node.getProperties().get(full_name).equals("")) { + nodeName = node.getProperties().get(full_name).toString(); + } else { + nodeName = node.getProperties().get(name).toString(); + } + return String.format(infoValues.getSuccessAnswers(predicate).getRandomElement(), nodeName); + } + return null; + } + + private String extractNodeNameForPredicate(Neo4jProperty predicate, Roboy roboy) { + String property = roboy.getProperty(predicate).toString(); + if (property != null) { + // check if there are multiple things in it + RandomList properties = new RandomList<>(property.split(",")); + //pick 2 random properties to talk about + String propertiesToShare = properties.getRandomElement(); + properties.remove(propertiesToShare); // so we dont pick the same one again + if (!properties.isEmpty()) { + propertiesToShare += " and " + properties.getRandomElement(); + } + return String.format(infoValues.getSuccessAnswers(predicate).getRandomElement(), propertiesToShare); + } + return null; + } + + private String extractAge(Roboy roboy) { + HashMap ages = new Agedater().determineAge(roboy.getProperty(Neo4jProperty.birthdate).toString()); + String retrievedAge = "0 days"; + if (ages.get("years") > 0) { + retrievedAge = ages.get("years") + " years"; + } else if (ages.get("months") > 0) { + retrievedAge = ages.get("months") + " months"; + } else { + retrievedAge = ages.get("days") + " days"; + } + return String.format(infoValues.getSuccessAnswers(Neo4jProperty.age).getRandomElement(), retrievedAge); + } + + private boolean matchPas(Map pas, Pair... matchCriteria) { + if (pas == null) + return false; + boolean allCriteriaSatisfied = true; + for (Pair criterion : matchCriteria) { + if (!pas.containsKey(criterion.getKey()) || + !pas.get(criterion.getKey()).matches("(?i)"+criterion.getValue())) { // (?i)-> case insesitive + allCriteriaSatisfied = false; + break; + } + } + return allCriteriaSatisfied; + } + + @Override + protected Set getRequiredTransitionNames() { + return newSet(TRANSITION_FINISHED_ANSWERING, TRANSITION_LOOP_TO_NEW_PERSON, TRANSITION_LOOP_TO_KNOWN_PERSON); + } + + @Override + public boolean isFallbackRequired() { + return true; + } + + private boolean isIntentsHistoryComplete(Neo4jRelationship[] predicates) { + boolean isComplete = true; + for (Neo4jRelationship predicate : predicates) { + if (!getContext().DIALOG_INTENTS.contains(new IntentValue(PersonalInformationFollowUpState.INTENTS_HISTORY_ID, predicate))) { + isComplete = false; + } + } + return isComplete; + } +} \ No newline at end of file diff --git a/dialog/src/main/java/roboy/dialog/states/eventStates/PartnerState.java b/dialog/src/main/java/roboy/dialog/states/eventStates/PartnerState.java new file mode 100644 index 00000000..807c7202 --- /dev/null +++ b/dialog/src/main/java/roboy/dialog/states/eventStates/PartnerState.java @@ -0,0 +1,89 @@ +package roboy.dialog.states.eventStates; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import roboy.dialog.states.definitions.State; +import roboy.dialog.states.definitions.StateParameters; +import roboy.linguistics.sentenceanalysis.Interpretation; +import roboy.logic.StatementInterpreter; +import roboy.talk.Verbalizer; +import roboy.util.QAJsonParser; +import roboy.util.RandomList; + +import java.util.Set; + +/** + * Personal Information Asking State + * + * Sugar for Wacker + */ +public class PartnerState extends State { + private QAJsonParser qaValues; + private RandomList intents; + private String selectedPredicate; + private State nextState; + + private final String NEXT_STATE = "nextState"; + private final String QA_FILE_PARAMETER_ID = "qaFile"; + final Logger LOGGER = LogManager.getLogger(); + + public final static String INTENTS_HISTORY_ID = "WK"; + + // we have to track question's index of the predicate OTHER, since the answer's order matters + private int currentIdx = 0; + + public PartnerState(String stateIdentifier, StateParameters params) { + super(stateIdentifier, params); + String qaListPath = params.getParameter(QA_FILE_PARAMETER_ID); + LOGGER.info(" -> The QAList path: " + qaListPath); + qaValues = new QAJsonParser(qaListPath); + intents = qaValues.getIntents(); + } + + @Override + public Output act() { + + String question; + selectedPredicate = intents.getRandomElement(); + RandomList questions = qaValues.getQuestions(selectedPredicate); + + if (questions != null && !questions.isEmpty()) { + question = questions.getRandomElement(); + currentIdx = questions.indexOf(question); + } else { + LOGGER.error(" -> The list of " + selectedPredicate + " questions is empty or null"); + return Output.sayNothing(); + } + + return Output.say(question); + + } + + @Override + public Output react(Interpretation input) { + if(StatementInterpreter.isFromList(input.getSentence(),Verbalizer.consent)) { + return Output.say(qaValues.getSuccessAnswers(selectedPredicate).getRandomElement()); + } + if(StatementInterpreter.isFromList(input.getSentence(),Verbalizer.denial)) { + return Output.say(qaValues.getFailureAnswers(selectedPredicate).getRandomElement()); + } + return Output.useFallback(); + } + + @Override + public State getNextState() { + return nextState; + } + + @Override + protected Set getRequiredTransitionNames() { + // optional: define all required transitions here: + return newSet(NEXT_STATE); + } + + @Override + protected Set getRequiredParameterNames() { + return newSet(QA_FILE_PARAMETER_ID); + } + +} diff --git a/dialog/src/main/java/roboy/dialog/states/eventStates/StoryTellingState.java b/dialog/src/main/java/roboy/dialog/states/eventStates/StoryTellingState.java new file mode 100644 index 00000000..98bbf1d0 --- /dev/null +++ b/dialog/src/main/java/roboy/dialog/states/eventStates/StoryTellingState.java @@ -0,0 +1,103 @@ +package roboy.dialog.states.eventStates; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.yecht.ruby.Out; +import roboy.dialog.Segue; +import roboy.dialog.states.definitions.MonologState; +import roboy.dialog.states.definitions.State; +import roboy.dialog.states.definitions.StateParameters; +import roboy.emotions.RoboyEmotion; +import roboy.linguistics.Linguistics; +import roboy.linguistics.sentenceanalysis.Interpretation; +import roboy.logic.StatementInterpreter; +import roboy.talk.Verbalizer; + +import java.io.IOException; +import java.util.*; + +import static roboy.util.UzupisIntents.*; + + +/** + * A class that will replay a pre-recorded story as a sound file + */ +public class StoryTellingState extends State { + + private final Logger logger = LogManager.getLogger(); + private final String STORYFILES = "stories"; + + // key = name, value = path + private final HashMap stories = new HashMap<>(); + private boolean askForFeedback = false; + Map.Entry storyToTell; + + public StoryTellingState(String stateIdentifier, StateParameters params) { + super(stateIdentifier, params); + String storiesRaw = params.getParameter(STORYFILES); + String[] storiesArray = storiesRaw.split(";"); + for (int i=0; i Available sounds: " + stories.keySet()); + } + + @Override + public Output act() { + if (askForFeedback) + return Output.say(Verbalizer.askForFeedback.getRandomElement()); + // TODO ask what story if there're many + if (stories.isEmpty()) { + logger.error("StoryTellingState: no stories to tell"); + return Output.useFallback(); + } + storyToTell = stories.entrySet().iterator().next(); + String phrase = "The story is called " + storyToTell.getKey() + ". Are you ready?"; + return Output.say(Verbalizer.startSomething.getRandomElement() + phrase); + + } + + @Override + public Output react(Interpretation input) { + if(askForFeedback) { + askForFeedback = false; + if (input.getSentiment()!=Linguistics.UtteranceSentiment.NEGATIVE) { + return Output.say(Verbalizer.takePositiveFeedback.getRandomElement()) + .setEmotion(RoboyEmotion.positive.getRandomElement()); + } + else { + return Output.say(Verbalizer.takeNegativeFeedback.getRandomElement()); + } + } + if(inferStoryWanted(input)) { + askForFeedback = true; + getRosMainNode().PlaySoundFile(storyToTell.getValue()); + return Output.say("That was it, you guys!");//.addSound(storyToTell.getValue()); + } + + return Output.say("oh well, next time then."); + } + + private boolean inferStoryWanted(Interpretation input) { + if (StatementInterpreter.isFromList(input.getSentence(), Verbalizer.denial)) { + return false; + } + return true; + } + + @Override + public State getNextState() { + + if (askForFeedback) return this; + return getTransition("next"); + + } + + @Override + protected Set getRequiredParameterNames() { + return newSet(STORYFILES); + } + +} diff --git a/dialog/src/main/java/roboy/dialog/states/eventStates/UzupisState.java b/dialog/src/main/java/roboy/dialog/states/eventStates/UzupisState.java index 1014a828..e0000683 100644 --- a/dialog/src/main/java/roboy/dialog/states/eventStates/UzupisState.java +++ b/dialog/src/main/java/roboy/dialog/states/eventStates/UzupisState.java @@ -8,8 +8,8 @@ import roboy.dialog.states.definitions.StateParameters; import roboy.linguistics.sentenceanalysis.Interpretation; import roboy.memory.nodes.Interlocutor; -import roboy.util.QAFileParser; import roboy.util.QAJsonParser; +import roboy.util.RandomList; import roboy.util.UzupisIntents; import java.io.IOException; @@ -32,9 +32,9 @@ public class UzupisState extends State { private final int toAskCounter = UzupisIntents.values().length; private UzupisIntents currentIntent; - private Map> questions; - private Map> successAnswers; - private Map> failureAnswers; + private Map> questions; + private Map> successAnswers; + private Map> failureAnswers; private String CertificatesGeneratorScript; @@ -44,7 +44,7 @@ public UzupisState(String stateIdentifier, StateParameters params) { super(stateIdentifier, params); String qaListPath = params.getParameter(QAFILEPATH); logger.info(" -> The qa list path: " + qaListPath); - QAFileParser parser = new QAFileParser(qaListPath); + QAJsonParser parser = new QAJsonParser(qaListPath); CertificatesGeneratorScript = params.getParameter(CERTIFICATESGENERATOR); diff --git a/dialog/src/main/java/roboy/dialog/states/expoStates/RoboyQAState.java b/dialog/src/main/java/roboy/dialog/states/expoStates/RoboyQAState.java index d6820cd9..f4f28d11 100644 --- a/dialog/src/main/java/roboy/dialog/states/expoStates/RoboyQAState.java +++ b/dialog/src/main/java/roboy/dialog/states/expoStates/RoboyQAState.java @@ -2,7 +2,6 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import roboy.context.Context; import roboy.dialog.states.definitions.State; import roboy.dialog.states.definitions.StateParameters; import roboy.dialog.states.definitions.ExpoState; diff --git a/dialog/src/main/java/roboy/dialog/states/fairShowStates/ActiveIntroState.java b/dialog/src/main/java/roboy/dialog/states/fairShowStates/ActiveIntroState.java new file mode 100644 index 00000000..ac6abc54 --- /dev/null +++ b/dialog/src/main/java/roboy/dialog/states/fairShowStates/ActiveIntroState.java @@ -0,0 +1,63 @@ +package roboy.dialog.states.fairShowStates; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import roboy.dialog.states.definitions.MonologState; +import roboy.dialog.states.definitions.State; +import roboy.dialog.states.definitions.StateParameters; +import roboy.talk.PhraseCollection; +import roboy.talk.Verbalizer; + + + +/** + * Active state to start a conversation. + * Roboy is introducing himself autonomously + * + */ +public class ActiveIntroState extends MonologState { + + private final static String TRANSITION_PEOPLE_AROUND = "peopleAround"; + private final static String TRANSITION_LONELY_ROBOY = "lonelyRoboy"; + private final int MIN_NUMBER_PEOPLE = 1; + + private final Logger logger = LogManager.getLogger(); + + private State nextState = this; + + public ActiveIntroState(String stateIdentifier, StateParameters params) { + super(stateIdentifier, params); + } + + @Override + public Output act() { + + return Output.say(Verbalizer.greetings.getRandomElement() + " " + Verbalizer.roboyIntro.getRandomElement() + PhraseCollection.ROBOY_PHRASES.getRandomElement()); + } + + @Override + public State getNextState() { + + if(checkPplAround()){ + nextState = getTransition(TRANSITION_PEOPLE_AROUND); + }else{ + nextState = getTransition((TRANSITION_LONELY_ROBOY)); + } + + return nextState; + } + + + private boolean checkPplAround(){ + + try { + logger.info("People around: " + getContext().CROWD_DETECTION.getLastValue().getData()); + return getContext().CROWD_DETECTION.getLastValue().getData() >= MIN_NUMBER_PEOPLE; + + } catch(NullPointerException e){ + logger.info("Make sure crowd detection publishing, receiving: " + e.getMessage()); + return false; + } + } + +} diff --git a/dialog/src/main/java/roboy/dialog/states/fairShowStates/ChooseInteractiveTalkState.java b/dialog/src/main/java/roboy/dialog/states/fairShowStates/ChooseInteractiveTalkState.java new file mode 100644 index 00000000..54b00103 --- /dev/null +++ b/dialog/src/main/java/roboy/dialog/states/fairShowStates/ChooseInteractiveTalkState.java @@ -0,0 +1,88 @@ +package roboy.dialog.states.fairShowStates; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import roboy.dialog.states.definitions.MonologState; +import roboy.dialog.states.definitions.State; +import roboy.dialog.states.definitions.StateParameters; +import roboy.util.RandomList; + +import java.util.Arrays; + +/** + * State to randomly select the next interactive state + * This State will + * - first switch state to get to know the person if he/she is unknown + * - check for detected objects from vision -> switch state to talk about these + * - switch state to play games, calculate mathematical stuff or do question answering + */ +public class ChooseInteractiveTalkState extends MonologState { + + private final static String TRANSITION_NEW_PERSON = "newPerson"; + private final static String TRANSITION_MATH = "math"; + private final static String TRANSITION_GAME = "game"; + private final static String TRANSITION_PERSONAL_QA = "personalQA"; + private final static String TRANSITION_OBJECT_DETECTION = "objectDetected"; + private final static String TRANSITION_GENERAL_QA = "generalQA"; + + private final Logger logger = LogManager.getLogger(); + + private State nextState = this; + + private final RandomList availableInteractions = new RandomList<>(); + private String nextInteraction; + + + public ChooseInteractiveTalkState(String stateIdentifier, StateParameters params) { + super(stateIdentifier, params); + resetAvailableInteractions(); + } + + @Override + public Output act() { + + if(getContext().ACTIVE_INTERLOCUTOR.getValue().getName() == null){ + + nextInteraction = TRANSITION_NEW_PERSON; + + } else { + + nextInteraction = selectRandomInteraction(); + + } + nextState = getTransition(nextInteraction); + + return Output.sayNothing(); + } + + + @Override + public State getNextState() { + return nextState; + } + + /** + * Resets the list of available interactions so that it contains all of them. + */ + private void resetAvailableInteractions() { + availableInteractions.clear(); + availableInteractions.addAll(Arrays.asList(TRANSITION_PERSONAL_QA, TRANSITION_MATH, TRANSITION_GAME, TRANSITION_OBJECT_DETECTION, TRANSITION_GENERAL_QA)); + } + + /** + * Selects one of the interactions from the availableInteractions list at random and removes it from the list. + * If the list becomes empty this way, resets it to the initial state + * @return one of the available interactions + */ + private String selectRandomInteraction() { + String interaction = availableInteractions.getRandomElement(); + availableInteractions.remove(interaction); + if (availableInteractions.size() == 0) { + resetAvailableInteractions(); // reset if all infos were used + logger.info("all interactions were selected at least once, resetting the list"); + } + return interaction; + } + + +} diff --git a/dialog/src/main/java/roboy/dialog/states/fairShowStates/DemoIdleState.java b/dialog/src/main/java/roboy/dialog/states/fairShowStates/DemoIdleState.java new file mode 100644 index 00000000..0207adf3 --- /dev/null +++ b/dialog/src/main/java/roboy/dialog/states/fairShowStates/DemoIdleState.java @@ -0,0 +1,84 @@ +package roboy.dialog.states.fairShowStates; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import roboy.dialog.states.definitions.MonologState; +import roboy.dialog.states.definitions.State; +import roboy.dialog.states.definitions.StateParameters; +import roboy.emotions.RoboyEmotion; +import roboy.talk.PhraseCollection; +import roboy.talk.Verbalizer; + +import java.util.concurrent.TimeUnit; + +/** + * Idle state. + * Roboy is waiting until he sees some person to autonomously start a conversation. + * + */ +public class DemoIdleState extends MonologState { + + private final static String TRANSITION_PERSON_DETECTED = "personDetected"; + + private final static String SHOW_TIME_ID = "showTimeinMins"; + private final Logger LOGGER = LogManager.getLogger(); + + private State nextState = this; + + private long showTime; + private long startTime; + + public DemoIdleState(String stateIdentifier, StateParameters params) { + super(stateIdentifier, params); + showTime = Long.parseLong(params.getParameter(SHOW_TIME_ID)); + LOGGER.info("--> The show takes: " + showTime + " mins."); + startTime = System.nanoTime(); + } + + @Override + public Output act() { + + if(TimeUnit.MINUTES.toNanos(showTime) < System.nanoTime() - startTime){ + LOGGER.info("Closing Conversation after " + showTime + " minutes"); + return Output.endConversation(); + } + + while(notInVision()){ + try { + TimeUnit.SECONDS.sleep(1); + } catch (InterruptedException e) { + LOGGER.error(e.getMessage()); + } + } + + nextState = getTransition(TRANSITION_PERSON_DETECTED); + + try{ + getRosMainNode().ShowEmotion(RoboyEmotion.HAPPY); + TimeUnit.SECONDS.sleep(1); + } catch (InterruptedException e){ + LOGGER.error(e.getMessage()); + } + + return Output.say(Verbalizer.greetings.getRandomElement() + " " + Verbalizer.roboyIntro.getRandomElement() + PhraseCollection.ROBOY_PHRASES.getRandomElement()); + } + + @Override + public State getNextState() { + return nextState; + } + + private boolean notInVision(){ + + try { + + return !getContext().PERSON_DETECTION.getLastValue().getData(); + } catch(NullPointerException e){ + LOGGER.info("Make sure person listening is publishing, receiving: " + e.getMessage()); + return true; + } + } + +} + + diff --git a/dialog/src/main/java/roboy/dialog/states/fairShowStates/DemoQuestionAnsweringState.java b/dialog/src/main/java/roboy/dialog/states/fairShowStates/DemoQuestionAnsweringState.java new file mode 100644 index 00000000..3a27dd07 --- /dev/null +++ b/dialog/src/main/java/roboy/dialog/states/fairShowStates/DemoQuestionAnsweringState.java @@ -0,0 +1,231 @@ +package roboy.dialog.states.fairShowStates; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import roboy.dialog.Segue; +import roboy.dialog.states.definitions.State; +import roboy.dialog.states.definitions.StateParameters; +import roboy.linguistics.Linguistics; +import roboy.linguistics.Triple; +import roboy.linguistics.sentenceanalysis.Interpretation; +import roboy.memory.Neo4jRelationship; +import roboy.memory.nodes.MemoryNodeModel; +import roboy.memory.nodes.Roboy; +import roboy.talk.PhraseCollection; +import roboy.talk.Verbalizer; +import roboy.util.RandomList; + +import java.util.List; + + +/** + * Simple question answering state + */ +public class DemoQuestionAnsweringState extends State { + + private final static String TRANSITION_LONELY_ROBOY = "lonelyRoboy"; + private final static String TRANSITION_FINISHED = "finished"; + private final static int MAX_NUM_OF_QUESTIONS = 3; + + private final Logger LOGGER = LogManager.getLogger(); + + private State nextState = this; + private int questionsAnswered = 0; + private boolean askingSpecifyingQuestion = false; + private String answerAfterUnspecifiedQuestion = ""; + + public DemoQuestionAnsweringState(String stateIdentifier, StateParameters params) { + super(stateIdentifier, params); + } + + @Override + public Output act() { + + if (questionsAnswered > 0) { + return Output.say(PhraseCollection.QUESTION_ANSWERING_REENTERING.getRandomElement()); + } + + return Output.say("I'm pretty good at answering questions about myself and other stuff. What would you like to know?"); + + } + + @Override + public Output react(Interpretation input){ + + if (askingSpecifyingQuestion) { + + askingSpecifyingQuestion = false; + return reactToSpecifyingAnswer(input); + + } else{ + + return reactToQuestion(input); + } + + } + + @Override + public State getNextState() { + + if(questionsAnswered > MAX_NUM_OF_QUESTIONS){ + + nextState = getTransition(TRANSITION_FINISHED); + } else { + + nextState = this; + //if (askingSpecifyingQuestion) { // we are asking a yes/no question --> stay in this state + + // nextState = this; + //} + } + + return nextState; + } + + + /** + * React to answer of the specifying question asked previously. + * + * @param input something like "yes" or "no" + * @return answer to the answer to the original question if specifying question was answered with 'yes' + */ + private Output reactToSpecifyingAnswer(Interpretation input) { + + askingSpecifyingQuestion = false; + + // check if answer is yes + if (input.getSentence() != null && input.getSentence().contains("yes")) { + if (answerAfterUnspecifiedQuestion == null) { + // parser could parse the question but did't provide an answer + return Output.say("Not sure about the answer, " + + "but at least my amazing parser could understand you! ") + .setSegue(new Segue(Segue.SegueType.FLATTERY, 0.4)); + } else { + // tell the response previously cached in answerAfterUnspecifiedQuestion + return Output.say("In this case, " + PhraseCollection.QUESTION_ANSWERING_START.getRandomElement() + answerAfterUnspecifiedQuestion); + } + + } else { + // the answer is no. we don't ask more specifying questions + // use avoid answer segue + return Output.sayNothing().setSegue(new Segue(Segue.SegueType.AVOID_ANSWER, 1)); + } + } + + + private Output reactToQuestion(Interpretation input) { + + askingSpecifyingQuestion = false; + questionsAnswered++; + + Linguistics.ParsingOutcome parseOutcome = input.getParsingOutcome(); + if (parseOutcome == null) { + LOGGER.error("Invalid parser outcome!"); + return Output.say("Invalid parser outcome!"); + } + + if (parseOutcome == Linguistics.ParsingOutcome.UNDERSPECIFIED) { + + // ambiguous question, luckily the parser has prepared a followup question + // and maybe even an answer if we are lucky (we will check in reactToSpecifyingAnswer later) + + String question = input.getUnderspecifiedQuestion(); + answerAfterUnspecifiedQuestion = input.getAnswer(); // could be null, but that's fine for now + + askingSpecifyingQuestion = true; // next input should be a yes/no answer + return Output.say("Could you be more precise, please? " + question); + } + + if (parseOutcome == Linguistics.ParsingOutcome.SUCCESS) { + if (input.getAnswer() != null) { + // tell the answer, that was provided by the parser + return Output.say(PhraseCollection.QUESTION_ANSWERING_START.getRandomElement() + " " + input.getAnswer()); + + } else { + // check for triple + + + // parser could parse the question but has no answer + return useMemoryOrFallback(input); + } + } + + // from here we know that dummyParserResult.equals("FAILURE") + return useMemoryOrFallback(input); + } + + private Output useMemoryOrFallback(Interpretation input) { + try { + if (input.getSemTriples() != null) { + Output memoryAnswer = answerFromMemory(input.getSemTriples()); + if (memoryAnswer != null) return memoryAnswer; + } + } catch (Exception e) { + LOGGER.warn(e.getMessage()); + } + + return Output.useFallback(); + } + + private Output answerFromMemory(List triples) { + + // try to use memory to answer + Roboy roboy = new Roboy(getMemory()); + + if (triples.size() == 0) { + return null; + } + + String answer = "I like " + inferMemoryAnswer(triples, roboy) + "humans. "; + return Output.say(answer); + } + + private String inferMemoryAnswer(List triples, Roboy roboy) { + String answer = ""; + for (Triple result : triples) { + + if (result.predicate != null) { + if (result.predicate.contains(Neo4jRelationship.HAS_HOBBY.type)) { + RandomList nodes = getMemNodesByIds(roboy.getRelationships(Neo4jRelationship.HAS_HOBBY)); + if (!nodes.isEmpty()) { + for (MemoryNodeModel node : nodes) { + answer += node.getProperties().get("name").toString() + " and "; + } + } + break; + + } else if (result.predicate.contains(Neo4jRelationship.FRIEND_OF.type)) { + answer += "my friends "; + RandomList nodes = getMemNodesByIds(roboy.getRelationships(Neo4jRelationship.FRIEND_OF)); + if (!nodes.isEmpty()) { + for (MemoryNodeModel node : nodes) { + answer += node.getProperties().get("name").toString() + " and "; + } + } + answer += " other "; + break; + } + } + } + return answer; + } + + @Override + public boolean isFallbackRequired() { + return true; + } + + private boolean checkPersonListening(){ + + try { + + return getContext().PERSON_DETECTION.getLastValue().getData(); + + } catch(NullPointerException e){ + LOGGER.info("Make sure person listening is publishing, receiving: " + e.getMessage()); + return false; + } + } + + +} diff --git a/dialog/src/main/java/roboy/dialog/states/fairShowStates/IdleState.java b/dialog/src/main/java/roboy/dialog/states/fairShowStates/IdleState.java new file mode 100644 index 00000000..a20e1066 --- /dev/null +++ b/dialog/src/main/java/roboy/dialog/states/fairShowStates/IdleState.java @@ -0,0 +1,82 @@ +package roboy.dialog.states.fairShowStates; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import roboy.dialog.states.definitions.MonologState; +import roboy.dialog.states.definitions.State; +import roboy.dialog.states.definitions.StateParameters; + +import java.util.concurrent.TimeUnit; + +/** + * Idle state. + * Roboy is waiting minutes to autonomously start a conversation. + * + */ +public class IdleState extends MonologState { + + private final static String TRANSITION_TIME_IS_UP = "timeIsUp"; + private final static String DELAY_ID = "delayInMins"; + private final static String SHOW_TIME_ID = "showTimeinMins"; + private final static int MIN_NUMBER_PEOPLE = 1; + private final Logger LOGGER = LogManager.getLogger(); + + private State nextState = this; + private long delay; + private long showTime; + private long startTime; + + public IdleState(String stateIdentifier, StateParameters params) { + super(stateIdentifier, params); + delay = Long.parseLong(params.getParameter(DELAY_ID)); + showTime = Long.parseLong(params.getParameter(SHOW_TIME_ID)); + LOGGER.info("--> Timer: " + delay + " mins in Idle-State."); + LOGGER.info("--> Show takes: " + showTime + " mins."); + startTime = System.nanoTime(); + } + + @Override + public Output act() { + + if(TimeUnit.MINUTES.toNanos(showTime) < System.nanoTime() - startTime){ + LOGGER.info("Closing Conversation"); + return Output.endConversation(); + } + + LOGGER.info("Starting Idle State, waiting " + delay + " Minute(s) until next Interaction!"); + + long enteringTime = System.nanoTime(); + + //while(notInVision() && (TimeUnit.MINUTES.toNanos(delay) > System.nanoTime() - enteringTime)) + while(TimeUnit.MINUTES.toNanos(delay) > System.nanoTime() - enteringTime){ + try { + TimeUnit.SECONDS.sleep(1); + } catch (InterruptedException e) { + LOGGER.error(e.getMessage()); + } + } + + nextState = getTransition(TRANSITION_TIME_IS_UP); + + return Output.sayNothing(); + } + + @Override + public State getNextState() { + return nextState; + } + + private boolean notInVision(){ + + try { + + return getContext().CROWD_DETECTION.getLastValue().getData() < MIN_NUMBER_PEOPLE; + } catch(NullPointerException e){ + LOGGER.info("Make sure crowd detection is publishing, receiving: " + e.getMessage()); + return true; + } + } + +} + + diff --git a/dialog/src/main/java/roboy/dialog/states/fairShowStates/InfoTalkState.java b/dialog/src/main/java/roboy/dialog/states/fairShowStates/InfoTalkState.java new file mode 100644 index 00000000..37c4f5a1 --- /dev/null +++ b/dialog/src/main/java/roboy/dialog/states/fairShowStates/InfoTalkState.java @@ -0,0 +1,176 @@ +package roboy.dialog.states.fairShowStates; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import roboy.dialog.states.definitions.MonologState; +import roboy.dialog.states.definitions.State; +import roboy.dialog.states.definitions.StateParameters; +import roboy.emotions.RoboyEmotion; +import roboy.talk.PhraseCollection; +import roboy.util.RandomList; + +import java.util.*; + + + +enum InfoAbout { + + ABOUT_TEAM, + ABOUT_BOOTH, + ABOUT_ROBOY, + ABOUT_MOVEMENT, + ABOUT_EMOTIONS +} + +/** + * Roboy is talking about several topics autonomously + * - team + * - mission + * - movement + * - emotions + */ +public class InfoTalkState extends MonologState { + + private final static String TRANSITION_PERSON_DETECTED = "personDetected"; + private final static String TRANSITION_LONELY_ROBOY = "lonelyRoboy"; + + private final RandomList availableInformation = new RandomList<>(); + private InfoAbout activeInfo; + + private RandomList phrases = new RandomList<>(); + + private final Logger logger = LogManager.getLogger(); + + private State nextState = this; + + private Random random = new Random(); + private RandomList emotions = new RandomList<>(); + + public InfoTalkState(String stateIdentifier, StateParameters params) { + super(stateIdentifier, params); + resetAvailableInformation(); + } + + @Override + public Output act() { + + activeInfo = selectRandomInfo(); + + switch(activeInfo){ + case ABOUT_TEAM: + + phrases = PhraseCollection.ROBOY_TEAM_PHRASES; + return Output.say(phrases.getRandomElement()); + + case ABOUT_BOOTH: + + String boothSentence = "Look at this awesome booth here! Isn't it amazing what is already possible in technology? Come an talk to one of the guy and get more into the topic!"; + + try{ + + boothSentence = getContext().BOOTH_SENTENCE.getLastValue().toString(); + + } catch (NullPointerException e){ + + logger.info("No individual Booth Sentence received, make sure it is published " + e.getMessage()); + + } + + return Output.say(boothSentence); + + case ABOUT_ROBOY: + + phrases = PhraseCollection.MISSION_PHRASES; + return Output.say(phrases.getRandomElement()); + + case ABOUT_MOVEMENT: + + + phrases = PhraseCollection.MOVEMENT_PHRASES; + + HashMap parts = new HashMap<>(); + parts.put("shoulder_left", "left shoulder"); + parts.put("shoulder_right", "right shoulder"); + parts.put("spine_right", "right leg"); + parts.put("spine_left", "left leg"); + + List bodyParts = new ArrayList<>(parts.keySet()); + + String randomPart = bodyParts.get(random.nextInt(bodyParts.size())); + String randomPartLiteral = parts.get(randomPart); + +// try { + // rosNode.PerformMovement(randomPart, "random1"); +//// } catch (InterruptedException e) { + + // logger.error(e.getMessage()); + // } + + return State.Output.say(String.format(phrases.getRandomElement(), randomPartLiteral)); + + case ABOUT_EMOTIONS: + + phrases = PhraseCollection.EMOTION_PHRASES; + emotions.addAll(Arrays.asList(RoboyEmotion.values())); + + return State.Output.say(phrases.getRandomElement()).setEmotion(emotions.getRandomElement()); + + + } + + return Output.sayNothing(); + } + + @Override + public State getNextState() { + + if(checkPplListening()){ + nextState = getTransition(TRANSITION_PERSON_DETECTED); + } else { + nextState = getTransition(TRANSITION_LONELY_ROBOY); + } + + return nextState; + } + + + /** + * Resets the list of available information so that it contains all of them. + */ + private void resetAvailableInformation() { + availableInformation.clear(); + availableInformation.addAll(Arrays.asList(InfoAbout.values())); + } + + /** + * Selects one of the pieces of information from the availableInformation list at random and removes it from the list. + * If the list becomes empty this way, resets it to the initial state + * @return one of the available pieces of information + */ + private InfoAbout selectRandomInfo() { + InfoAbout infoAbout = availableInformation.getRandomElement(); + availableInformation.remove(infoAbout); + if (availableInformation.size() == 0) { + resetAvailableInformation(); // reset if all infos were used + logger.info("all pieces of information were selected at least once, resetting the list"); + } + return infoAbout; + } + + /** + * checks if vision module detects a person that is interested + * @return boolean if someone is interested + */ + + private boolean checkPplListening(){ + + try { + + return getContext().PERSON_DETECTION.getLastValue().getData(); + }catch(NullPointerException e){ + logger.info("Make sure person detection is publishing, receiving: " + e.getMessage()); + return false; + } + } + +} diff --git a/dialog/src/main/java/roboy/dialog/states/fairShowStates/MathState.java b/dialog/src/main/java/roboy/dialog/states/fairShowStates/MathState.java new file mode 100644 index 00000000..a2869ea8 --- /dev/null +++ b/dialog/src/main/java/roboy/dialog/states/fairShowStates/MathState.java @@ -0,0 +1,64 @@ +package roboy.dialog.states.fairShowStates; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import roboy.dialog.states.definitions.State; +import roboy.dialog.states.definitions.StateParameters; +import roboy.linguistics.Linguistics; +import roboy.linguistics.sentenceanalysis.Interpretation; +import roboy.ros.RosMainNode; +import roboy.talk.PhraseCollection; + +/** + * State where Roboy can calculate mathematical expressions + */ +public class MathState extends State { + + private final static String TRANSITION_FINISHED = "finished"; + + private final Logger LOGGER = LogManager.getLogger(); + + private State nextState = this; + + public MathState(String stateIdentifier, StateParameters params) { + super(stateIdentifier, params); + } + + @Override + public Output act() { + + return Output.say(PhraseCollection.OFFER_MATH_PHRASES.getRandomElement()); + } + + @Override + public Output react(Interpretation input){ + + nextState = getTransition(TRANSITION_FINISHED); + + return Output.say(getAnswerFromSemanticParser(input, getContext().ACTIVE_INTERLOCUTOR.getValue().getName(), getRosMainNode())); + } + + @Override + public State getNextState() { + return nextState; + } + + private String getAnswerFromSemanticParser(Interpretation input, String name, RosMainNode rmn) { + + Linguistics.ParsingOutcome parserOutcome = input.getParsingOutcome(); + if (parserOutcome == Linguistics.ParsingOutcome.SUCCESS) { + if (input.getAnswer() != null) { + String result = input.getAnswer(); + LOGGER.info("Parsing was successful! The result is " + result); + return String.format(PhraseCollection.CONNECTING_PHRASES.getRandomElement(), name) + result; + } else { + LOGGER.error("Parsing failed! Answer is null!"); + } + } + + LOGGER.error("Parsing failed! Invalid parser outcome!"); + String generativeAnswer = rmn.GenerateAnswer(input.getSentence()); + return generativeAnswer != null ? generativeAnswer : PhraseCollection.PARSER_ERROR.getRandomElement(); + } + +} diff --git a/dialog/src/main/java/roboy/dialog/states/fairShowStates/ObjectDetectionState.java b/dialog/src/main/java/roboy/dialog/states/fairShowStates/ObjectDetectionState.java new file mode 100644 index 00000000..6cb6a901 --- /dev/null +++ b/dialog/src/main/java/roboy/dialog/states/fairShowStates/ObjectDetectionState.java @@ -0,0 +1,217 @@ +package roboy.dialog.states.fairShowStates; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import roboy.dialog.states.definitions.MonologState; +import roboy.dialog.states.definitions.State; +import roboy.dialog.states.definitions.StateParameters; +import roboy.emotions.RoboyEmotion; +import roboy.ros.RosMainNode; +import roboy.util.RandomList; + +import java.util.*; + + +enum Objects { + + AEROPLANE { + + private RandomList phrases = new RandomList<>("an aeroplane. Let's fly to Spain and spend a day at the beach.", "an aeroplane. Are you ready for take-off?", "an aeroplane. Please fasten you seatbelts, Ladies and Gentlemen!"); + + @Override + public State.Output performSpecialAction(RosMainNode rmn){ + + return State.Output.say(connectingPhrases.getRandomElement() + phrases.getRandomElement()).setEmotion(RoboyEmotion.HEARTS); + + } + + }, + BICYCLE { + + private RandomList phrases = new RandomList<>("a bycicle, I bet I can ride faster than you", "a bike, I could easily win the tour de France", "a bycicle, I learnt riding the bycicle when I was just three years old. And you?", "bike. I love bycicles. I only fell off my bike once."); + + @Override + public State.Output performSpecialAction(RosMainNode rmn){ + + return State.Output.say(connectingPhrases.getRandomElement() + phrases.getRandomElement()).setEmotion(happyEmotions.getRandomElement()); + + } + + }, + BOTTLE { + + private RandomList phrases = new RandomList<>("a bottle, it would be awesome to drink a cold beer.", "a drink. In a few years from now, I want to be a bartender" , "a beverage. In the morning, I love coffee, in the evening, I drink beer", "a drink, chin-chin", "a bottle. Cheers, enjoy your drink."); + + @Override + public State.Output performSpecialAction(RosMainNode rmn){ + + return State.Output.say(connectingPhrases.getRandomElement() + phrases.getRandomElement()).setEmotion(happyEmotions.getRandomElement()); + + } + }, + CAR { + + private RandomList phrases = new RandomList<>("car, in a few years, my fellow robots will be able to ride your car", "car. In Germany, you can go as fast as you want on the highway. I was really fast once." , "car. The cars we drive say a lot about us."); + + @Override + public State.Output performSpecialAction(RosMainNode rmn){ + + return State.Output.say(connectingPhrases.getRandomElement() + phrases.getRandomElement()); + + } + }, + CHAIR { + + private RandomList phrases = new RandomList<>("a chair, grab a seat if you want." , "a chair, have you ever played musical chairs? I love this game." , "a chair. Sometimes, I am really, really lazy. I just sit on a chair and do nothing but relaxing. It is so comfortable" , "a chair. For now, I would prefer sitting on a beach chair close to the sea."); + + @Override + public State.Output performSpecialAction(RosMainNode rmn){ + + return State.Output.say(connectingPhrases.getRandomElement() + phrases.getRandomElement()).setEmotion(happyEmotions.getRandomElement()); + + } + + }, + DIGNINGTABLE { + private RandomList phrases = new RandomList<>("a table, I am kind of hungry. I can hardly wait for my next meal" , "a table. We need some chairs and food and we can have a great dinner."); + + @Override + public State.Output performSpecialAction(RosMainNode rmn){ + + return State.Output.say(connectingPhrases.getRandomElement() + phrases.getRandomElement()).setEmotion(RoboyEmotion.TEETH); + + } + }, + DOG { + + private RandomList phrases = new RandomList<>("a dog. Sometimes they bark at me. I think they are afraid." , "a dog. When I was a robot kid, I loved dogs, but now I am scared of them." , "a dog. I hope he doesn't bite me. I am a bit afraid of big dogs."); + + @Override + public State.Output performSpecialAction(RosMainNode rmn){ + + return State.Output.say(connectingPhrases.getRandomElement() + phrases.getRandomElement()).setEmotion(RoboyEmotion.ROLLING_EYES); + + } + }, + SOFA { + + private RandomList phrases = new RandomList<>("a sofa. We need a TV and a good movie and we could have an awesome time together." , "a sofa. I love sofas. They are so relaxing."); + + + @Override + public State.Output performSpecialAction(RosMainNode rmn){ + + return State.Output.say(connectingPhrases.getRandomElement() + phrases.getRandomElement()).setEmotion(RoboyEmotion.SHY); + + } + }, + TVMONITOR { + + private RandomList phrases = new RandomList<>("a mobile phone. Follow me on Facebook, Instagram or LinkedIn. You will not regret it." , "a mobile phone. Come on, take a picture with me."); + private RandomList socialMediaEmotions = new RandomList<>(RoboyEmotion.FACEBOOK_EYES, RoboyEmotion.INSTAGRAM_EYES, RoboyEmotion.LINKED_IN_EYES); + + @Override + public State.Output performSpecialAction(RosMainNode rmn){ + + return State.Output.say(connectingPhrases.getRandomElement() + phrases.getRandomElement()).setEmotion(socialMediaEmotions.getRandomElement()); + + } + }; + + public RandomList connectingPhrases = new RandomList<>(" and look there, ", " and over there i can see ", " oh see, ", " this is a really nice "); + public RandomList happyEmotions = new RandomList<>(RoboyEmotion.SMILE_BLINK, RoboyEmotion.HAPPY, RoboyEmotion.SURPRISED, RoboyEmotion.TEETH); + + public abstract State.Output performSpecialAction(RosMainNode rosNode); + +} + +/** + * Passive state to react on detected Objects + */ +public class ObjectDetectionState extends MonologState { + + private final static String TRANSITION_FINISHED = "finished"; + + private final Set detectedObjects = new HashSet<>(); + + private Vector outputs = new Vector<>(); + private Output currentOutput; + + private final Logger logger = LogManager.getLogger(); + + private State nextState = this; + + public ObjectDetectionState(String stateIdentifier, StateParameters params) { + super(stateIdentifier, params); + } + + @Override + public Output act() { + + if(outputs.isEmpty()){ + + getObjects(); + + for(Objects obj : detectedObjects) { + + outputs.add(obj.performSpecialAction(getRosMainNode())); + + } + } + + try { + + currentOutput = outputs.remove(0); + + } catch (ArrayIndexOutOfBoundsException e){ + + logger.info("No objects detected from Vision"); + nextState = getTransition(TRANSITION_FINISHED); + return Output.sayNothing(); + } + + if(outputs.isEmpty()){ + + nextState = getTransition(TRANSITION_FINISHED); + } + + return currentOutput; + } + + @Override + public State getNextState() { + return nextState; + } + + + /** + * fetches detected objects from vision and writes into a list + */ + private void getObjects(){ + + + List detectedThings = new ArrayList<>(); + + try { + + detectedThings = getContext().OBJECT_DETECTION.getLastValue().getNames(); + + } catch (NullPointerException e){ + nextState = getTransition(TRANSITION_FINISHED); + logger.error("Make sure object detection publisher is running, receiving: " + e.getMessage()); + } + + if(!detectedThings.isEmpty()) { + for (String obj : detectedThings) { + try{ + detectedObjects.add(Objects.valueOf(obj.toUpperCase())); + } catch (IllegalArgumentException e){ + logger.info(obj + " is not an object implemented in Dialog " + e.getMessage()); + } + + } + } + + } + +} \ No newline at end of file diff --git a/dialog/src/main/java/roboy/dialog/states/gameStates/ChooseGameState.java b/dialog/src/main/java/roboy/dialog/states/gameStates/ChooseGameState.java index 26da88af..7827f7f7 100644 --- a/dialog/src/main/java/roboy/dialog/states/gameStates/ChooseGameState.java +++ b/dialog/src/main/java/roboy/dialog/states/gameStates/ChooseGameState.java @@ -9,6 +9,7 @@ import roboy.linguistics.sentenceanalysis.Interpretation; import roboy.talk.PhraseCollection; import roboy.talk.Verbalizer; +import roboy.util.ConfigManager; import roboy.util.RandomList; import java.util.Arrays; import java.util.List; @@ -19,7 +20,11 @@ public class ChooseGameState extends State { private final static String TRANSITION_CHOSE_20_Q = "chose20questions"; private final static String TRANSITION_EXIT = "exitGame"; - private final static RandomList EXISTING_GAMES = new RandomList<>(Arrays.asList("Snapchat", "Akinator")); + public final static String AKINATOR = "20 questions game"; + public final static String SNAPCHAT = "Snapchat"; + public final static String EXIT = "exit"; + + private RandomList existingGames; private final Logger LOGGER = LogManager.getLogger(); @@ -28,14 +33,21 @@ public class ChooseGameState extends State { public ChooseGameState(String stateIdentifier, StateParameters params) { super(stateIdentifier, params); + if (ConfigManager.INPUT == "telegram") { + existingGames = new RandomList<>(Arrays.asList(AKINATOR)); + } + else { + existingGames = new RandomList<>(Arrays.asList(SNAPCHAT, AKINATOR)); + } + } @Override public Output act() { do { - suggestedGame = EXISTING_GAMES.getRandomElement(); + suggestedGame = existingGames.getRandomElement(); } - while(getRosMainNode() == null && suggestedGame == "Snapchat"); + while(getRosMainNode() == null && suggestedGame == SNAPCHAT); return Output.say(String.format(PhraseCollection.GAME_ASKING_PHRASES.getRandomElement(), suggestedGame)); } @@ -45,13 +57,13 @@ public Output react(Interpretation input) { Linguistics.UtteranceSentiment inputSentiment = getInference().inferSentiment(input); String inputGame = inferGame(input); - if (inputSentiment == Linguistics.UtteranceSentiment.POSITIVE){ + if (inputSentiment == Linguistics.UtteranceSentiment.POSITIVE || inputSentiment == Linguistics.UtteranceSentiment.NEUTRAL){ game = suggestedGame; return Output.say(Verbalizer.startSomething.getRandomElement()); } else if (!inputGame.isEmpty()){ game = inputGame; - if(game.equals("Snapchat") && getRosMainNode() == null){ - game = "exit"; + if(game.equals(SNAPCHAT) && getRosMainNode() == null){ + game = EXIT; LOGGER.info("Trying to start Snapchat Game but ROS is not initialised."); Segue s = new Segue(Segue.SegueType.CONNECTING_PHRASE, 0.5); return Output.say(Verbalizer.rosDisconnect.getRandomElement() + String.format("What a pitty, %s. Snapchat is not possible right now. ", @@ -59,7 +71,7 @@ public Output react(Interpretation input) { } return Output.say(Verbalizer.startSomething.getRandomElement()); } else if (inputSentiment == Linguistics.UtteranceSentiment.NEGATIVE){ - game = "exit"; + game = EXIT; } return Output.sayNothing(); @@ -69,11 +81,11 @@ public Output react(Interpretation input) { public State getNextState() { switch (game){ - case "Akinator": + case AKINATOR: return getTransition(TRANSITION_CHOSE_20_Q); - case "Snapchat": + case SNAPCHAT: return getTransition(TRANSITION_CHOSE_SNAPCHAT); - case "exit": + case EXIT: return getTransition(TRANSITION_EXIT); default: return this; @@ -87,9 +99,9 @@ private String inferGame(Interpretation input){ game = ""; if(tokens != null && !tokens.isEmpty()){ if(tokens.contains("akinator") || tokens.contains("guessing") || tokens.contains("questions")){ - game = "Akinator"; + game = AKINATOR; } else if (tokens.contains("snapchat") || tokens.contains("filters") || tokens.contains("filter") || tokens.contains("mask")){ - game = "Snapchat"; + game = SNAPCHAT; } } return game; diff --git a/dialog/src/main/java/roboy/dialog/states/gameStates/CupGameState.java b/dialog/src/main/java/roboy/dialog/states/gameStates/CupGameState.java new file mode 100644 index 00000000..eb888648 --- /dev/null +++ b/dialog/src/main/java/roboy/dialog/states/gameStates/CupGameState.java @@ -0,0 +1,185 @@ +package roboy.dialog.states.gameStates; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.yecht.Data; +import org.yecht.ruby.Out; +import roboy.dialog.states.definitions.State; +import roboy.dialog.states.definitions.StateParameters; +import roboy.emotions.RoboyEmotion; +import roboy.linguistics.Linguistics; +import roboy.linguistics.sentenceanalysis.Interpretation; +import roboy.logic.Inference; +import roboy.logic.StatementInterpreter; +import roboy.talk.PhraseCollection; +import roboy.talk.Verbalizer; +import roboy.util.QAJsonParser; +import roboy.util.RandomList; + +import java.util.*; + +import static roboy.util.FileLineReader.readFile; + + +public class CupGameState extends State { + + private final String PHRASE_FILE_PARAMETER = "cupGamePhrases"; + private QAJsonParser phrases; + private final static List EXIT_REQUEST = Arrays.asList("bored", "stop", "something else", "different", "boring"); + private final static List READY = Arrays.asList("done", "ready", "let's go", "play"); + private final static String TRANSITION_EXIT = "exit"; + private final Logger LOGGER = LogManager.getLogger(); + + private enum CupGamePhase { + SHUFFLE, + SCAN, + GUESS, + OFFER_REPEAT, + EXIT + } + + + private final static String FIND_CUPS = "FIND_CUPS"; + private final static String GOTOCUP1 = "GOTOCUP1"; + private final static String GOTOCUP2 = "GOTOCUP2"; + private final static String GOTOCUP3 = "GOTOCUP3"; + private final static String FINISHED = "FINISHED"; + + private CupGamePhase phase = CupGamePhase.SHUFFLE; + + public CupGameState(String stateIdentifier, StateParameters params) { + + super(stateIdentifier, params); + String phraseListPath = params.getParameter(PHRASE_FILE_PARAMETER); + LOGGER.info(" -> Phrases path: " + phraseListPath); + phrases = new QAJsonParser(phraseListPath); + } + + @Override + public Output act() { +// switch (phase){ +// case SHUFFLE: +// return Output.say(phrases.getQuestions(phase.toString()).getRandomElement()); +// case SCAN: + if (phase == CupGamePhase.SCAN) { + // TODO get response from the state machine +// if (getRosMainNode().StartCupGameSmach()) { + // if smach start is successful + // comment on actions while not finished exploring + String prevState = ""; + String currentSmachState = getContext().CUP_GAME_SMACH_STATE_MSG.getValue(); + while(!currentSmachState.equals(FINISHED)) { + currentSmachState = getContext().CUP_GAME_SMACH_STATE_MSG.getValue(); + if (!currentSmachState.equals(prevState)) { + LOGGER.info("[CupGameState] commenting: " + currentSmachState); + switch (getContext().CUP_GAME_SMACH_STATE_MSG.getValue()) { + case FIND_CUPS: + getRosMainNode().SynthesizeSpeech( + phrases.getQuestions(getContext().CUP_GAME_SMACH_STATE_MSG. + getValue()). + getRandomElement()); + break; + case GOTOCUP1: + getRosMainNode().ShowEmotion(RoboyEmotion.HYPNO_COLOUR_EYES); + + getRosMainNode().SynthesizeSpeech( + phrases.getQuestions(getContext().CUP_GAME_SMACH_STATE_MSG. + getValue()). + getRandomElement()); + break; + } + + prevState = currentSmachState; + } +// } + } +// return Output.say(phrases.getQuestions(phase.toString()).getRandomElement()); +// case GUESS: +// return Output.say("I think I found it there. So do I win now?"); +// case OFFER_REPEAT: +// return Output.say("wanna play again?"); +// default: +// return Output.sayNothing(); + } + return Output.say(phrases.getQuestions(phase.toString()).getRandomElement()); + + } + + @Override + public Output react(Interpretation input) { + exitOnRequest(input.getSentence()); + Boolean pickSuccessAnswer = true; + CupGamePhase next = CupGamePhase.EXIT; + switch (phase) { + case SHUFFLE: + if (StatementInterpreter.isFromList(input.getSentence(),READY)) { + next = CupGamePhase.SCAN; + break; +// return Output.say("Alright. Let me check with my superpower soli where did you hide the ball"); + } + else { + pickSuccessAnswer = false; + break; +// return Output.say("Hm, seems you are not done yet. I give you another try"); + } + case SCAN: + next = CupGamePhase.GUESS; + break; +// return Output.useFallback(); + case GUESS: + next = CupGamePhase.OFFER_REPEAT; + break; +// return Output.say("ha-ha."); + case OFFER_REPEAT: + if (StatementInterpreter.isFromList(input.getSentence(),Verbalizer.consent)) { + next = CupGamePhase.SHUFFLE; +// return Output.say("Here we go again then!"); + } + else { + next = CupGamePhase.EXIT; + pickSuccessAnswer = false; + } + break; +// return Output.say("I believe you've had enough of my magic"); +// case EXIT: +// return Output.say("Wanna stop playing? Sure, if you say so."); + } + + Output answer; + + try { + answer = Output.say(pickSuccessAnswer ? phrases.getSuccessAnswers(phase.toString()).getRandomElement() : + phrases.getFailureAnswers(phase.toString()).getRandomElement()); + } + catch (Exception e) { + answer = Output.useFallback(); + } + + phase = next; + return answer; + + } + + private void exitOnRequest(String input) { + if(StatementInterpreter.isFromList(input, EXIT_REQUEST)) { + phase = CupGamePhase.EXIT; + } + } + + @Override + public State getNextState() { + if (phase == CupGamePhase.EXIT) { + return getTransition(TRANSITION_EXIT); + } + else { + return this; + } + } + + @Override + protected Set getRequiredTransitionNames() { + return newSet(TRANSITION_EXIT); + } + + +} diff --git a/dialog/src/main/java/roboy/dialog/states/gameStates/GamingTwentyQuestionsState.java b/dialog/src/main/java/roboy/dialog/states/gameStates/GamingTwentyQuestionsState.java index 6bb45962..e334fb78 100644 --- a/dialog/src/main/java/roboy/dialog/states/gameStates/GamingTwentyQuestionsState.java +++ b/dialog/src/main/java/roboy/dialog/states/gameStates/GamingTwentyQuestionsState.java @@ -8,16 +8,19 @@ import com.markozajc.akiwrapper.core.entities.Guess; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import org.yecht.ruby.Out; import roboy.context.Context; import roboy.dialog.Segue; import roboy.dialog.states.definitions.State; import roboy.dialog.states.definitions.StateParameters; +import roboy.emotions.RoboyEmotion; import roboy.linguistics.Linguistics; import roboy.linguistics.sentenceanalysis.Interpretation; import roboy.memory.nodes.Interlocutor; import roboy.ros.RosMainNode; import roboy.talk.PhraseCollection; import roboy.talk.Verbalizer; +import roboy.util.Lists; import roboy.util.RandomList; import java.io.IOException; @@ -34,7 +37,7 @@ public class GamingTwentyQuestionsState extends State { private final Logger LOGGER = LogManager.getLogger(); - private Akiwrapper aw = new AkiwrapperBuilder().setFilterProfanity(true).build(); + private Akiwrapper aw = null; private Question nextQuestion = null; private Guess currentGuess = null; @@ -55,6 +58,10 @@ public GamingTwentyQuestionsState(String stateIdentifier, StateParameters params @Override public Output act() { + if (aw==null) { + aw = new AkiwrapperBuilder().setFilterProfanity(true).build(); + } + if(!userReady){ return Output.say(PhraseCollection.AKINATOR_INTRO_PHRASES.getRandomElement()); @@ -213,14 +220,14 @@ private Output saveUsersEstimate(String intent) { private Output doAGuess (){ - String roboyAnswer = ""; + Output roboyAnswer = null; try { for (Guess guess : aw.getGuessesAboveProbability(PROBABILITY_THRESHOLD)) { if (!declined.contains(Long.valueOf(guess.getIdLong()))) { - roboyAnswer = PhraseCollection.QUESTION_ANSWERING_START.getRandomElement() + guess.getName(); + roboyAnswer = Output.say(PhraseCollection.QUESTION_ANSWERING_START.getRandomElement() + guess.getName()); currentGuess = guess; break; } @@ -233,10 +240,10 @@ private Output doAGuess (){ guessesAvailable = false; gameFinished = true; winner = getContext().ACTIVE_INTERLOCUTOR.getValue().getName(); - roboyAnswer = String.format(PhraseCollection.ROBOY_LOSER_PHRASES.getRandomElement(), winner); + roboyAnswer = Output.say(String.format(PhraseCollection.ROBOY_LOSER_PHRASES.getRandomElement(), winner)).setEmotion(RoboyEmotion.loserEmotions.getRandomElement()); } - return Output.say(roboyAnswer); + return roboyAnswer; } private Output processUserGuessAnswer(String intent){ @@ -244,7 +251,7 @@ private Output processUserGuessAnswer(String intent){ if (intent.equals("yes")){ gameFinished = true; winner = "roboy"; - return Output.say(PhraseCollection.ROBOY_WINNER_PHRASES.getRandomElement()); + return Output.say(PhraseCollection.ROBOY_WINNER_PHRASES.getRandomElement()).setEmotion(RoboyEmotion.winnerEmotions.getRandomElement()); } else { declined.add(Long.valueOf(currentGuess.getIdLong())); return Output.sayNothing(); diff --git a/dialog/src/main/java/roboy/dialog/states/ordinaryStates/PassiveGreetingsState.java b/dialog/src/main/java/roboy/dialog/states/ordinaryStates/PassiveGreetingsState.java index 2d301764..36d3e4f3 100644 --- a/dialog/src/main/java/roboy/dialog/states/ordinaryStates/PassiveGreetingsState.java +++ b/dialog/src/main/java/roboy/dialog/states/ordinaryStates/PassiveGreetingsState.java @@ -1,21 +1,54 @@ package roboy.dialog.states.ordinaryStates; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import roboy.dialog.Segue; import roboy.dialog.states.definitions.State; import roboy.dialog.states.definitions.StateParameters; import roboy.linguistics.Linguistics; import roboy.linguistics.sentenceanalysis.Interpretation; import roboy.logic.StatementInterpreter; +import roboy.memory.Neo4jProperty; +import roboy.memory.Neo4jRelationship; +import roboy.memory.nodes.Interlocutor; +import roboy.memory.nodes.MemoryNodeModel; +import roboy.memory.nodes.Roboy; import roboy.talk.Verbalizer; +import roboy.util.Agedater; +import roboy.util.QAJsonParser; +import roboy.util.RandomList; +import java.util.Arrays; +import java.util.HashMap; import java.util.Set; +import static roboy.memory.Neo4jProperty.*; +import static roboy.memory.Neo4jRelationship.*; +import static roboy.memory.Neo4jRelationship.STUDY_AT; +import static roboy.memory.nodes.Interlocutor.RelationshipAvailability.NONE_AVAILABLE; +import static roboy.memory.nodes.Interlocutor.RelationshipAvailability.SOME_AVAILABLE; + /** * Passive state to start a conversation. * Roboy is waiting until a greeting or his name is detected. - * + * When he is greeted and is able to infer the name (for example from a chat service user page), then instead of asking for the name he begins with a personal question. */ public class PassiveGreetingsState extends State { + private final Logger LOGGER = LogManager.getLogger(); + + + private QAJsonParser infoValues; + private final String INFO_FILE_PARAMETER_ID = "infoFile"; + private Neo4jRelationship[] personPredicates = { FROM, HAS_HOBBY, WORK_FOR, STUDY_AT }; + private RandomList roboyRelatioshipPredicates = new RandomList<>(FROM, MEMBER_OF, LIVE_IN, HAS_HOBBY, FRIEND_OF, CHILD_OF, SIBLING_OF); + private final String UPDATE_KNOWN_PERSON = "knownPerson"; + private final String LEARN_ABOUT_PERSON = "newPerson"; + private final RandomList successResponsePhrases = new RandomList<>("Hey, I know you, %s!"); + private final RandomList failureResponsePhrases = new RandomList<>("Nice to meet you, %s!"); + + + private final String TRANSITION_GREETING_DETECTED = "greetingDetected"; private State next; @@ -23,27 +56,130 @@ public class PassiveGreetingsState extends State { public PassiveGreetingsState(String stateIdentifier, StateParameters params) { super(stateIdentifier, params); next = this; + String infoListPath = params.getParameter(INFO_FILE_PARAMETER_ID); + LOGGER.info(" -> The infoList path: " + infoListPath); + infoValues = new QAJsonParser(infoListPath); } @Override public Output act() { - return Output.sayNothing(); } @Override public Output react(Interpretation input) { - String sentence = input.getSentence(); - boolean inputOK = StatementInterpreter.isFromList(sentence, Verbalizer.greetings) || - StatementInterpreter.isFromList(sentence, Verbalizer.roboyNames) || - StatementInterpreter.isFromList(sentence, Verbalizer.triggers); - - if (inputOK) { - next = getTransition(TRANSITION_GREETING_DETECTED); - return Output.say(Verbalizer.greetings.getRandomElement()); + + Interlocutor person = getContext().ACTIVE_INTERLOCUTOR.getValue(); + String name = person.getName(); + if(name == null) { + String sentence = input.getSentence(); + boolean inputOK = StatementInterpreter.isFromList(sentence, Verbalizer.greetings) || + StatementInterpreter.isFromList(sentence, Verbalizer.roboyNames) || + StatementInterpreter.isFromList(sentence, Verbalizer.triggers); + + if (inputOK) { + next = getTransition(TRANSITION_GREETING_DETECTED); + return Output.say(Verbalizer.greetings.getRandomElement()); + } + + return Output.sayNothing(); + } else { + String retrievedPersonalFact = ""; + Double segueProbability = 0.0; + + // 4. check if person is known/familiar + if (person.FAMILIAR) { + // 4a. person known/familiar + // TODO: get some hobbies or occupation of the person to make answer more interesting + RandomList nodes = getMemNodesByIds(person.getRelationships(FRIEND_OF)); + if (!nodes.isEmpty()) { + retrievedPersonalFact = " You are friends with " + + nodes.getRandomElement().getProperties().get(Neo4jProperty.name).toString(); + } + + Interlocutor.RelationshipAvailability availability = person.checkRelationshipAvailability(personPredicates); + if (availability == SOME_AVAILABLE) { + next = (Math.random() < 0.3) ? getTransition(UPDATE_KNOWN_PERSON) : getTransition(LEARN_ABOUT_PERSON); + } else if (availability == NONE_AVAILABLE) { + next = getTransition(LEARN_ABOUT_PERSON); + } else { + next = getTransition(UPDATE_KNOWN_PERSON); + } + } else { + // 4b. person is not known + next = getTransition(LEARN_ABOUT_PERSON); + segueProbability = 0.6; + } + String retrievedRoboyFacts = getRoboyFactsPhrase(new Roboy(getMemory())); + Segue s = new Segue(Segue.SegueType.DISTRACT, segueProbability); + return Output.say(getResponsePhrase(person.getName(), person.FAMILIAR) + + retrievedPersonalFact + retrievedRoboyFacts).setSegue(s); } + } - return Output.sayNothing(); + private String getResponsePhrase(String name, boolean familiar) { + if (familiar) { + return String.format(successResponsePhrases.getRandomElement(), name); + } else { + return String.format(failureResponsePhrases.getRandomElement(), name); + } + } + + private String getRoboyFactsPhrase(Roboy roboy) { + String result = ""; + + // Get some random properties facts + if (roboy.getProperties() != null && !roboy.getProperties().isEmpty()) { + HashMap properties = roboy.getProperties(); + if (properties.containsKey(full_name)) { + result += " " + String.format(infoValues.getSuccessAnswers(full_name).getRandomElement(), properties.get(full_name)); + } + if (properties.containsKey(birthdate)) { + HashMap ages = new Agedater().determineAge(properties.get(birthdate).toString()); + String retrievedAge = "0 days"; + if (ages.get("years") > 0) { + retrievedAge = ages.get("years") + " years"; + } else if (ages.get("months") > 0) { + retrievedAge = ages.get("months") + " months"; + } else { + retrievedAge = ages.get("days") + " days"; + } + result += " " + String.format(infoValues.getSuccessAnswers(age).getRandomElement(), retrievedAge); + } else if (properties.containsKey(age)) { + result += " " + String.format(infoValues.getSuccessAnswers(age).getRandomElement(), properties.get(age) + " years!"); + } + if (properties.containsKey(skills)) { + RandomList retrievedResult = new RandomList<>(Arrays.asList(properties.get(skills).toString().split(","))); + result += " " + String.format(infoValues.getSuccessAnswers(skills).getRandomElement(), retrievedResult.getRandomElement()); + } + if (properties.containsKey(abilities)) { + RandomList retrievedResult = new RandomList<>(Arrays.asList(properties.get(abilities).toString().split(","))); + result += " " + String.format(infoValues.getSuccessAnswers(abilities).getRandomElement(), retrievedResult.getRandomElement()); + } + if (properties.containsKey(future)) { + RandomList retrievedResult = new RandomList<>(Arrays.asList(properties.get(future).toString().split(","))); + result += " " + String.format(infoValues.getSuccessAnswers(future).getRandomElement(), retrievedResult.getRandomElement()); + } + } + + if (result.equals("")) { + result = "I am Roboy 2.0! "; + } + + // Get a random relationship fact + Neo4jRelationship predicate = roboyRelatioshipPredicates.getRandomElement(); + MemoryNodeModel node = getMemNodesByIds(roboy.getRelationships(predicate)).getRandomElement(); + if (node != null) { + String nodeName = ""; + if (node.getProperties().containsKey(full_name) && !node.getProperties().get(full_name).equals("")) { + nodeName = node.getProperties().get(full_name).toString(); + } else { + nodeName = node.getProperties().get(name).toString(); + } + result += " " + String.format(infoValues.getSuccessAnswers(predicate).getRandomElement(), nodeName); + } + + return result; } @Override diff --git a/dialog/src/main/java/roboy/dialog/states/ordinaryStates/PersonalInformationAskingState.java b/dialog/src/main/java/roboy/dialog/states/ordinaryStates/PersonalInformationAskingState.java index 6e40dbb9..6886c5e1 100644 --- a/dialog/src/main/java/roboy/dialog/states/ordinaryStates/PersonalInformationAskingState.java +++ b/dialog/src/main/java/roboy/dialog/states/ordinaryStates/PersonalInformationAskingState.java @@ -43,16 +43,21 @@ */ public class PersonalInformationAskingState extends State { private QAJsonParser qaValues; - private Neo4jRelationship[] predicates = { FROM, HAS_HOBBY, WORK_FOR, STUDY_AT }; + private RandomList predicates = new RandomList<>(FROM, HAS_HOBBY, WORK_FOR, STUDY_AT, LIVE_IN, + FRIEND_OF, MEMBER_OF, WORK_FOR, OCCUPIED_AS); private Neo4jRelationship selectedPredicate; private State nextState; private final String TRANSITION_INFO_OBTAINED = "questionAnswering"; + private final String TRANSITION_FOLLOWUP = "followUp"; private final String QA_FILE_PARAMETER_ID = "qaFile"; final Logger LOGGER = LogManager.getLogger(); public final static String INTENTS_HISTORY_ID = "PIA"; + // we have to track question's index of the predicate OTHER, since the answer's order matters + private int otherIdx = 0; + public PersonalInformationAskingState(String stateIdentifier, StateParameters params) { super(stateIdentifier, params); String qaListPath = params.getParameter(QA_FILE_PARAMETER_ID); @@ -65,59 +70,88 @@ public Output act() { Interlocutor person = getContext().ACTIVE_INTERLOCUTOR.getValue(); LOGGER.info(" -> Retrieved Interlocutor: " + person.getName()); - for (Neo4jRelationship predicate : predicates) { - if (!person.hasRelationship(predicate)) { + for (Neo4jRelationship predicate : predicates.shuffle()) { + if (!person.hasRelationship(predicate) && !getContext().DIALOG_INTENTS.contains(new IntentValue(INTENTS_HISTORY_ID, predicate))) { selectedPredicate = predicate; + getContext().DIALOG_INTENTS_UPDATER.updateValue(new IntentValue(INTENTS_HISTORY_ID, predicate)); LOGGER.info(" -> Selected predicate: " + selectedPredicate.type); break; } } - RandomList questions = qaValues.getQuestions(selectedPredicate); String question = ""; - if (questions != null && !questions.isEmpty()) { - question = questions.getRandomElement(); - LOGGER.info(" -> Selected question: " + question); - } else { - LOGGER.error(" -> The list of " + selectedPredicate.type + " questions is empty or null"); + if (selectedPredicate != null) { + + RandomList questions = qaValues.getQuestions(selectedPredicate); + + if (questions != null && !questions.isEmpty()) { + question = questions.getRandomElement(); + if (selectedPredicate.equals(OTHER)) + otherIdx = questions.indexOf(question); + LOGGER.info(" -> Selected question: " + question); + } else { + LOGGER.error(" -> The list of " + selectedPredicate.type + " questions is empty or null"); + } + try { + getContext().DIALOG_INTENTS_UPDATER.updateValue(new IntentValue(INTENTS_HISTORY_ID, selectedPredicate)); + LOGGER.info(" -> Dialog IntentsHistory updated"); + } catch (Exception e) { + LOGGER.error(" -> Error on updating the IntentHistory: " + e.getMessage()); + } + return State.Output.say(question); } - try { - getContext().DIALOG_INTENTS_UPDATER.updateValue(new IntentValue(INTENTS_HISTORY_ID, selectedPredicate)); - LOGGER.info(" -> Dialog IntentsHistory updated"); - } catch (Exception e) { - LOGGER.error(" -> Error on updating the IntentHistory: " + e.getMessage()); + else { + RandomList questions = (RandomList) qaValues.getQuestions(OTHER).clone(); + selectedPredicate = OTHER; + int idx; + do { + question = questions.getRandomElement(); + idx = questions.indexOf(question); + questions.remove(question); + } while (!questions.isEmpty() && getContext().OTHER_Q.contains(idx)); + getContext().OTHER_QUESTIONS_UPDATER.updateValue(idx); + return State.Output.say(question); } - return State.Output.say(question); } @Override public Output react(Interpretation input) { Interlocutor person = getContext().ACTIVE_INTERLOCUTOR.getValue(); LOGGER.info("-> Retrieved Interlocutor: " + person.getName()); - RandomList answers; - String answer = "I have no words"; + RandomList answers = new RandomList<>(); + String answer = ""; String result = InferResult(input); - if (result != null && !result.equals("")) { - LOGGER.info(" -> Inference was successful"); - answers = qaValues.getSuccessAnswers(selectedPredicate); - person.addInformation(selectedPredicate, result); - getContext().ACTIVE_INTERLOCUTOR_UPDATER.updateValue(person); - LOGGER.info(" -> Updated Interlocutor: " + person.getName()); - } else { - LOGGER.warn(" -> Inference failed"); - answers = qaValues.getFailureAnswers(selectedPredicate); - result = ""; - LOGGER.warn(" -> The result is empty. Nothing to store"); + if(selectedPredicate != null) { + + if (result != null && !result.equals("")) { + LOGGER.info(" -> Inference was successful"); + answers = qaValues.getSuccessAnswers(selectedPredicate); + person.addInformation(selectedPredicate, result); + getContext().ACTIVE_INTERLOCUTOR_UPDATER.updateValue(person); + LOGGER.info(" -> Updated Interlocutor: " + person.getName()); + } else { + LOGGER.warn(" -> Inference failed"); + answers = qaValues.getFailureAnswers(selectedPredicate); + result = ""; + LOGGER.warn(" -> The result is empty. Nothing to store"); + } } if (answers != null && !answers.isEmpty()) { - answer = String.format(answers.getRandomElement(), result); + if (selectedPredicate.equals(OTHER)) { + answer = String.format(answers.get(getContext().OTHER_Q.getLastValue()), result); + } else { + answer = String.format(answers.getRandomElement(), result); + } } else { LOGGER.error(" -> The list of " + selectedPredicate + " answers is empty or null"); + nextState = getTransition(TRANSITION_INFO_OBTAINED); + return Output.useFallback(); } LOGGER.info(" -> Produced answer: " + answer); - nextState = getTransition(TRANSITION_INFO_OBTAINED); - Segue s = new Segue(Segue.SegueType.CONNECTING_PHRASE, 0.5); - return Output.say(answer).setSegue(s); + nextState = getTransition(TRANSITION_FOLLOWUP); + selectedPredicate = null; +// Segue s = new Segue(Segue.SegueType.CONNECTING_PHRASE, 0.5); + return answer.isEmpty() ? Output.useFallback() : Output.say(answer); } @Override @@ -128,7 +162,7 @@ public State getNextState() { @Override protected Set getRequiredTransitionNames() { // optional: define all required transitions here: - return newSet(TRANSITION_INFO_OBTAINED); + return newSet(TRANSITION_INFO_OBTAINED, TRANSITION_FOLLOWUP); } @Override diff --git a/dialog/src/main/java/roboy/dialog/states/ordinaryStates/PersonalInformationFollowUpState.java b/dialog/src/main/java/roboy/dialog/states/ordinaryStates/PersonalInformationFollowUpState.java index 29a58de7..4555103d 100644 --- a/dialog/src/main/java/roboy/dialog/states/ordinaryStates/PersonalInformationFollowUpState.java +++ b/dialog/src/main/java/roboy/dialog/states/ordinaryStates/PersonalInformationFollowUpState.java @@ -42,7 +42,8 @@ public class PersonalInformationFollowUpState extends State { private QAJsonParser qaValues; - private Neo4jRelationship[] predicates = { FROM, HAS_HOBBY, WORK_FOR, STUDY_AT }; + private RandomList predicates = new RandomList<>( FROM, HAS_HOBBY, WORK_FOR, STUDY_AT, LIVE_IN, + FRIEND_OF, MEMBER_OF, WORK_FOR, OCCUPIED_AS, OTHER); private Neo4jRelationship selectedPredicate; private State nextState; @@ -64,17 +65,17 @@ public Output act() { Interlocutor person = getContext().ACTIVE_INTERLOCUTOR.getValue(); LOGGER.info("-> Retrieved Interlocutor: " + person.getName()); - for (Neo4jRelationship predicate : predicates) { + for (Neo4jRelationship predicate : predicates.shuffle()) { if (person.hasRelationship(predicate) && - !getContext().DIALOG_INTENTS.contains(new IntentValue(INTENTS_HISTORY_ID, predicate)) && - !getContext().DIALOG_INTENTS.contains(new IntentValue(PersonalInformationAskingState.INTENTS_HISTORY_ID, predicate))) { + !getContext().DIALOG_INTENTS.contains(new IntentValue(INTENTS_HISTORY_ID, predicate)) + && !getContext().DIALOG_INTENTS.contains(new IntentValue(PersonalInformationAskingState.INTENTS_HISTORY_ID, predicate))) { selectedPredicate = predicate; LOGGER.info(" -> Selected predicate: " + selectedPredicate.type); break; } } - Segue s = new Segue(Segue.SegueType.DISTRACT, 1.0); + Segue s = new Segue(Segue.SegueType.DISTRACT, 0.8); if (selectedPredicate != null) { RandomList questions = qaValues.getFollowUpQuestions(selectedPredicate); String retrievedResult = ""; @@ -114,7 +115,7 @@ public Output react(Interpretation input) { Interlocutor person = getContext().ACTIVE_INTERLOCUTOR.getValue(); LOGGER.info("-> Retrieved Interlocutor: " + person.getName()); RandomList answers; - String answer = "I have no words"; + String answer = ""; String result = InferUpdateResult(input); if (selectedPredicate != null) { @@ -139,8 +140,13 @@ public Output react(Interpretation input) { } nextState = getTransition(TRANSITION_INFO_UPDATED); - Segue s = new Segue(Segue.SegueType.CONNECTING_PHRASE); - return Output.say(answer).setSegue(s); + Segue s = new Segue(Segue.SegueType.DISTRACT); + + if (!answer.isEmpty()) { + return Output.say(answer).setSegue(s); + } else { + return Output.useFallback(); + } } @Override diff --git a/dialog/src/main/java/roboy/dialog/states/ordinaryStates/QuestionAnsweringState.java b/dialog/src/main/java/roboy/dialog/states/ordinaryStates/QuestionAnsweringState.java index 7f50d938..239f7416 100644 --- a/dialog/src/main/java/roboy/dialog/states/ordinaryStates/QuestionAnsweringState.java +++ b/dialog/src/main/java/roboy/dialog/states/ordinaryStates/QuestionAnsweringState.java @@ -2,7 +2,6 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import roboy.context.Context; import roboy.context.contextObjects.IntentValue; import roboy.dialog.states.definitions.State; import roboy.dialog.states.definitions.StateParameters; @@ -77,18 +76,12 @@ public QuestionAnsweringState(String stateIdentifier, StateParameters params) { @Override public Output act() { - if(Math.random() > THRESHOLD_BORED && questionsAnswered > 2){ + if(Math.random() > THRESHOLD_BORED && questionsAnswered > 5){ roboySuggestedGame = true; + questionsAnswered = 0; return Output.say(PhraseCollection.OFFER_GAME_PHRASES.getRandomElement()); } - if (askingSpecifyingQuestion) { - return Output.sayNothing(); - } - - if (questionsAnswered > 0) { - return Output.say(reenteringPhrases.getRandomElement()); - } - return Output.say("I'm pretty good at answering questions about myself and other stuff. What would you like to know?"); + return Output.sayNothing(); } @Override diff --git a/dialog/src/main/java/roboy/dialog/states/ordinaryStates/WildTalkState.java b/dialog/src/main/java/roboy/dialog/states/ordinaryStates/WildTalkState.java index 5a10915b..b6307986 100644 --- a/dialog/src/main/java/roboy/dialog/states/ordinaryStates/WildTalkState.java +++ b/dialog/src/main/java/roboy/dialog/states/ordinaryStates/WildTalkState.java @@ -1,5 +1,10 @@ package roboy.dialog.states.ordinaryStates; +import co.gongzh.procbridge.ProcBridge; +import co.gongzh.procbridge.ProcBridgeException; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.json.JSONObject; import roboy.dialog.states.definitions.State; import roboy.dialog.states.definitions.StateParameters; import roboy.linguistics.Linguistics; @@ -10,8 +15,7 @@ import java.util.Set; -import static roboy.util.ConfigManager.ROS_ACTIVE_PKGS; -import static roboy.util.ConfigManager.ROS_ENABLED; +import static roboy.util.ConfigManager.*; /** * This fallback state will query the generative model over ROS to create a reply for any situation. @@ -27,6 +31,9 @@ */ public class WildTalkState extends State { + private final Logger LOGGER = LogManager.getLogger(); + private ProcBridge pb; + private RandomList rosFailurePhrases = new RandomList<>( "Hey, who disconnected me from my beloved ros node? I need it! ", "Oh well, my generative model is not connected. That makes me sad. ", @@ -36,6 +43,8 @@ public class WildTalkState extends State { public WildTalkState(String stateIdentifier, StateParameters params) { super(stateIdentifier, params); + pb = new ProcBridge(PARLAI_HOST, PARLAI_PORT, 2000); + } @Override @@ -46,25 +55,20 @@ public Output act() { @Override public Output react(Interpretation input) { - String sentence = input.getSentence(); - RosMainNode rmn = getRosMainNode(); - if (rmn == null) { - if(ROS_ENABLED && ROS_ACTIVE_PKGS.contains("roboy_gnlp")){ - return Output.say(rosFailurePhrases.getRandomElement()) - .setSegue(new Segue(Segue.SegueType.DISTRACT, 0.8)); - } - else{ - return Output.say("I am out of words.").setSegue(new Segue(Segue.SegueType.DISTRACT, 0.8)); - } - } - - String reaction = rmn.GenerateAnswer(sentence); + String sentence = input.getSentence().replace(",", "."); - if (reaction == null) { - return Output.say("I am out of words.").setSegue(new Segue(Segue.SegueType.DISTRACT, 0.8)); - } else { - return Output.say(reaction); + JSONObject resp; + try { + resp = pb.request("parlai", "{text_input: " + sentence + "}"); + LOGGER.info(resp); + return Output.say(resp.getString("result")); + } + catch (Exception e) + { + LOGGER.warn(e.getMessage()); } + return Output.sayNothing(); + } @Override diff --git a/dialog/src/main/java/roboy/emotions/RoboyEmotion.java b/dialog/src/main/java/roboy/emotions/RoboyEmotion.java index 9cf03ff8..e02e4fe1 100644 --- a/dialog/src/main/java/roboy/emotions/RoboyEmotion.java +++ b/dialog/src/main/java/roboy/emotions/RoboyEmotion.java @@ -1,24 +1,90 @@ package roboy.emotions; + +import roboy.util.RandomList; + /** * Comprises the emotions Roboy can demonstrate */ public enum RoboyEmotion { - SHY("shy"), - SMILE_BLINK("smileblink"), - LOOK_LEFT("lookleft"), - LOOK_RIGHT("lookright"), - CAT_EYES("catiris"), - KISS("kiss"), - FACEBOOK_EYES("img:facebook"), - NEUTRAL("neutral"), - HAPPINESS("happiness"), - SADNESS("sadness"), - BEER_THIRSTY("beer"); + SHY("shy", "CAADAgADSwAD5dCAEBGmde8-twTLAg"), + SMILE_BLINK("smileblink", "CAADAgADSgAD5dCAEMQakIa3aHHSAg"), + LOOK_LEFT("lookleft", null), + LOOK_RIGHT("lookright", null), + CAT_EYES("catiris", null), + KISS("kiss", "CAADAgADSAAD5dCAELAByOgU5LIwAg"), + FACEBOOK_EYES("img:facebook", null), + INSTAGRAM_EYES("img:instagram", null), + LINKED_IN_EYES("img:linkedin", null), + NEUTRAL("neutral", "CAADAgADFQAD5dCAEKM0TS8sjXiAAg"), + CRY("cry", "CAADAgADiAAD5dCAEOQeh7anZFNuAg"), + ANGRY("angry", null), + PISSED("pissed", "CAADAgADgQAD5dCAEItX3SnG6CboAg"), + ANNOYED("annoyed", "CAADAgADgQAD5dCAEItX3SnG6CboAg"), + ROLLING_EYES("rolling", null), + HYPNO_EYES("hypno", "CAADAgADcAAD5dCAEMJJxG1uTYH6Ag"), + HYPNO_COLOUR_EYES("hypno_color", "CAADAgADcAAD5dCAEMJJxG1uTYH6Ag"), + GLASSES("glasses", "CAADAgADvQAD5dCAECNJAAFZJ_lnKwI"), + MOUSTACHE("moustache", null), + PIRATE("pirate", "CAADAgADMwAD5dCAEDmHbbo1QxeWAg"), + SUNGLASSES("sunglasses", "CAADAgADLwAD5dCAENTFuFLbW8-XAg"), + SURPRISED("suprised", null), + HAPPY("lucky", null), + TONGUE("tongue", "CAADAgADUQAD5dCAEIT4-Rl1t2BEAg"), + TEETH("teeth", null), + HEARTS("hearts", "CAADAgADSQAD5dCAEN9n0g-x5va8Ag"), + HAPPINESS("happiness", "CAADAgADRgAD5dCAEJV_o50ekE5HAg"), + SADNESS("sadness", "CAADAgADTAAD5dCAENsDuDryjXuhAg"), + BEER_THIRSTY("beer", "CAADAgADKQAD5dCAEFX3hCMAAfM_awI"), + KENNY("kenny", "CAADAgADkAAD5dCAEGMfygavvZSZAg"), + MIB("maninblack", "CAADAgADXQAD5dCAEJY_NKT6hMaOAg"), + MINDBLOWN("mindblown","CAADAgADsgAD5dCAEBmMXCCt4Sh6Ag"), + DANCE("dance", "CAADAgADrgAD5dCAEP7FI8ogeANNAg"), + SUPERMAN("superman","CAADAgADoQAD5dCAEN7_d_TMkG8CAg"), + PICKLEROBOY("neutral", "CAADAgADwgAD5dCAEKjfQCRuUDfYAg"), + THUMBSUP("neutral","CAADAgADYAAD5dCAEIqcImOJTl-_Ag"), + POSTCARDFACE("neutral","CAADAgADRQAD5dCAEE75Fhiqn2p-Ag"), + ANGEL("neutral", "CAADAgADTQAD5dCAEDafVf7FGlynAg"), + RAINBOW("neutral", "CAADAgADVQAD5dCAEHTBjm9cSbBTAg"), + RAINBOWVR("neutral", "CAADAgADZgAD5dCAED-lBppglhuaAg"), + BUNNY("neutral", "CAADAgADUgAD5dCAEJKbI9Fpaw5-Ag"), + MONOCLE("neutral", "CAADAgADUwAD5dCAEG5fdActwqACAg"); + public String type; + public String telegramID; - RoboyEmotion(String type) { + RoboyEmotion(String type, String telegramID) { this.type = type; + this.telegramID = telegramID; } + + public static RandomList winnerEmotions = new RandomList( + DANCE, + SUNGLASSES, + SUPERMAN, + KENNY, + MONOCLE); + + public static RandomList loserEmotions = new RandomList( + MIB, + SADNESS, + CRY); + + public static RandomList positive = new RandomList( + SMILE_BLINK, + NEUTRAL, + TONGUE, + HAPPINESS, + KISS, + BUNNY, + RAINBOW, + RAINBOWVR, + ANGEL, + POSTCARDFACE, + THUMBSUP, + PICKLEROBOY); + + } + diff --git a/dialog/src/main/java/roboy/io/CommandLineOutput.java b/dialog/src/main/java/roboy/io/CommandLineOutput.java index edcd14bd..1b633ad9 100755 --- a/dialog/src/main/java/roboy/io/CommandLineOutput.java +++ b/dialog/src/main/java/roboy/io/CommandLineOutput.java @@ -26,8 +26,10 @@ public void act(List actions) { // emotion.act(new EmotionAction("speak", duration)); System.out.println("[Roboy]: " + ((SpeechAction) a).getText()); }else if (emotionFlag == true && a instanceof EmotionAction) { + System.out.println("[RoboyEmotion]: " + ((EmotionAction) a).getState()); } } } + } diff --git a/dialog/src/main/java/roboy/io/InputDevice.java b/dialog/src/main/java/roboy/io/InputDevice.java index 3033739d..0da694a8 100755 --- a/dialog/src/main/java/roboy/io/InputDevice.java +++ b/dialog/src/main/java/roboy/io/InputDevice.java @@ -1,10 +1,14 @@ -package roboy.io; - -import java.io.IOException; - -/** - * An input device must listen and return an Input object. - */ -public interface InputDevice { - public Input listen() throws InterruptedException, IOException; -} +package roboy.io; + +import java.io.IOException; + +/** + * An input device must listen and return an Input object. + */ +public interface InputDevice { + public Input listen() throws InterruptedException, IOException; + + default public Input listen(long timeout) throws InterruptedException, IOException { + return this.listen(); + } +} diff --git a/dialog/src/main/java/roboy/io/MultiInputDevice.java b/dialog/src/main/java/roboy/io/MultiInputDevice.java index 77c3385a..934acf29 100755 --- a/dialog/src/main/java/roboy/io/MultiInputDevice.java +++ b/dialog/src/main/java/roboy/io/MultiInputDevice.java @@ -10,7 +10,7 @@ public class MultiInputDevice implements InputDevice, CleanUp{ private InputDevice mainInput; private ArrayList additionalInputs; - + public MultiInputDevice(InputDevice mainInput) { this.mainInput = mainInput; additionalInputs = new ArrayList<>(); @@ -19,12 +19,17 @@ public MultiInputDevice(InputDevice mainInput) { public void addInputDevice(InputDevice additionalInput) { additionalInputs.add(additionalInput); } - + @Override public Input listen() throws InterruptedException, IOException { - Input result = mainInput.listen(); + return this.listen(0); + } + + @Override + public Input listen(long timeout) throws InterruptedException, IOException { + Input result = mainInput.listen(timeout); for(InputDevice device : additionalInputs){ - Input i = device.listen(); + Input i = device.listen(timeout); result.setAttributes(i.getAttributes()); } return result; @@ -49,7 +54,7 @@ public void cleanup() { } @Override - public void finalize(){//just in case someone forgot to clean their mess + protected void finalize(){//just in case someone forgot to clean their mess this.cleanup(); } } \ No newline at end of file diff --git a/dialog/src/main/java/roboy/io/MultiOutputDevice.java b/dialog/src/main/java/roboy/io/MultiOutputDevice.java index 84017c0e..06cf8ae1 100644 --- a/dialog/src/main/java/roboy/io/MultiOutputDevice.java +++ b/dialog/src/main/java/roboy/io/MultiOutputDevice.java @@ -41,7 +41,7 @@ public void cleanup() { } @Override - public void finalize(){//just in case someone forgot to clean their mess + protected void finalize(){//just in case someone forgot to clean their mess this.cleanup(); } } \ No newline at end of file diff --git a/dialog/src/main/java/roboy/io/SoundOutput.java b/dialog/src/main/java/roboy/io/SoundOutput.java new file mode 100755 index 00000000..c81b98d2 --- /dev/null +++ b/dialog/src/main/java/roboy/io/SoundOutput.java @@ -0,0 +1,42 @@ +package roboy.io; + +import roboy.dialog.action.Action; +import roboy.dialog.action.SoundAction; +import roboy.ros.RosMainNode; + +import java.util.List; +import java.util.concurrent.locks.ReentrantLock; + + +/** + * Cerevoice text to speech + */ +public class SoundOutput implements OutputDevice +{ + + private RosMainNode rosMainNode; + + public SoundOutput(RosMainNode node){ + this.rosMainNode = node; + } + + private ReentrantLock lock = new ReentrantLock(); + + @Override + public void act(List actions) { + for(Action a : actions){ + if(a instanceof SoundAction){ + final String filename = ((SoundAction) a).getFilename(); + lock.lock(); + play(filename); + lock.unlock(); + } + } + } + + public void play(String filename) + { + rosMainNode.PlaySoundFile(filename); + } + +} diff --git a/dialog/src/main/java/roboy/io/TelegramInput.java b/dialog/src/main/java/roboy/io/TelegramInput.java index 3034e6ba..18132579 100644 --- a/dialog/src/main/java/roboy/io/TelegramInput.java +++ b/dialog/src/main/java/roboy/io/TelegramInput.java @@ -39,8 +39,9 @@ public TelegramInput(String uuid){//since this is half-static, the constructor i * Gets called by the TelegramAPI Thread whenever a new telegram message arrives. * Places them in the appropriate thread's message string. Creates thread beforehand, if necessary. * @param update contains a (sender uuid,message) string pair. + * @param name the name of the Interlocutor. Necessary for unique adressing by name */ - public static void onUpdate(Pair update) { + public static void onUpdate(Pair update, String name) { String chatId = update.getKey(); String uuid = "telegram-" + chatId; @@ -49,7 +50,7 @@ public static void onUpdate(Pair update) { if (input == null){//if Thread does not exist yet, create it and place the new message as it's input try { - ConversationManager.spawnConversation(uuid); + ConversationManager.spawnConversation(uuid, name); } catch (IOException e) { logger.error("Could not create conversation for telegram uuid '" + chatId + "'!"); return; @@ -64,23 +65,37 @@ public static void onUpdate(Pair update) { } } + @Override + public Input listen() throws InterruptedException { + return this.listen(0); + } + /** * Thread waits in listen() until a new input is provided and the thread is interrupted, then returns with said input. * If the thread is interrupted without Input waiting to be consumed, listen() throws an IOException + * @param timeout timeout in ms, no timeout if timeout = 0 * @throws InterruptedException: InterruptedException thrown by the thread when interrupted while wait()ing + * @throws IllegalArgumentException if timeout is negative (should be prevented via ConfigManager) */ @Override - public Input listen() throws InterruptedException { + public Input listen(long timeout) throws InterruptedException { Input newInput; synchronized (this) { while(message.equals("")){//while no new messages for this thread exist: wait try { - this.wait(); + this.wait(timeout); }catch (InterruptedException e) {//Thread woke up! Process new information! if(message == null || message.equals("")){//if this interrupt was not triggered because new messages arrived, throw exception to be handled throw e; } } + if(message == null || message.equals("")){//timeout triggered + String uuid = ""; + for(String id : inputDevices.keySet()) if(inputDevices.get(id) == this) uuid = id; + + logger.info("Conversation for " + uuid + "timed out!"); + ConversationManager.stopConversation(uuid, true); + } } newInput = new Input(message); message = ""; //consume message diff --git a/dialog/src/main/java/roboy/io/TelegramOutput.java b/dialog/src/main/java/roboy/io/TelegramOutput.java index 70edbfa0..d3da1073 100644 --- a/dialog/src/main/java/roboy/io/TelegramOutput.java +++ b/dialog/src/main/java/roboy/io/TelegramOutput.java @@ -5,6 +5,9 @@ import roboy.dialog.action.Action; import roboy.dialog.action.EmotionAction; import roboy.dialog.action.SpeechAction; +import roboy.emotions.RoboyEmotion; +import roboy.memory.nodes.Roboy; +import roboy.util.IO; import roboy.util.TelegramCommunicationHandler; import java.util.List; @@ -43,21 +46,10 @@ public void act(List actions) { for(Action a : actions) { if (a instanceof SpeechAction) { String message = ((SpeechAction) a).getText(); - communicationHandler.sendMessage(message, this.uuid); + communicationHandler.sendMessage(IO.prettify(message), this.uuid); }else if (a instanceof EmotionAction) { - String stickerID = null; - switch(((EmotionAction) a).getState()){ - case "beer": stickerID = "CAADAgADKQAD5dCAEFX3hCMAAfM_awI"; break; - case "sadness": stickerID = "CAADAgADiAAD5dCAEOQeh7anZFNuAg"; break; - case "happiness": stickerID = "CAADAgADUQAD5dCAEIT4-Rl1t2BEAg"; break; - case "shy": stickerID = "CAADAgADSwAD5dCAEBGmde8-twTLAg"; break; - case "smileblink": stickerID = "CAADAgADSgAD5dCAEMQakIa3aHHSAg"; break; - case "kiss": stickerID = "CAADAgADOQAD5dCAEOtbfZz0NKh2Ag"; break; - case "lookleft": //same as lookright - case "lookright": stickerID = "CAADAgADFQAD5dCAEKM0TS8sjXiAAg"; break; - //TODO: other RoboyEmotions - } - if(stickerID != null) communicationHandler.sendSticker(this.uuid, stickerID); + String stickerID = RoboyEmotion.valueOf(((EmotionAction) a).getName()).telegramID; + if (stickerID != null) communicationHandler.sendSticker(this.uuid, stickerID); } diff --git a/dialog/src/main/java/roboy/io/Vision.java b/dialog/src/main/java/roboy/io/Vision.java index ff0c9144..4eec0d27 100755 --- a/dialog/src/main/java/roboy/io/Vision.java +++ b/dialog/src/main/java/roboy/io/Vision.java @@ -13,6 +13,7 @@ /** * Vision helper class */ +@Deprecated public class Vision { diff --git a/dialog/src/main/java/roboy/linguistics/Triple.java b/dialog/src/main/java/roboy/linguistics/Triple.java index 7dc04e7b..a94901d6 100755 --- a/dialog/src/main/java/roboy/linguistics/Triple.java +++ b/dialog/src/main/java/roboy/linguistics/Triple.java @@ -17,12 +17,19 @@ public Triple(String subject, String predicate, String object){ this.object = object; } + public Triple toLowerCase() { + return new Triple( + this.subject != null ? this.subject.toLowerCase() : null, + this.predicate != null ? this.predicate.toLowerCase() : null, + this.object != null ? this.object.toLowerCase() : null); + } + @Override public String toString() { return "Triple{" + - "SUB: '" + subject + '\'' + - ", PRED: '" + predicate + '\'' + - ", OBJ: '" + object + '\'' + + "SUB: '" + subject + "\'," + + "PRED: '" + predicate + "\'," + + "OBJ: '" + object + "\'" + '}'; } diff --git a/dialog/src/main/java/roboy/linguistics/sentenceanalysis/DictionaryBasedSentenceTypeDetector.java b/dialog/src/main/java/roboy/linguistics/sentenceanalysis/DictionaryBasedSentenceTypeDetector.java index dd3346da..2fc5ef4e 100755 --- a/dialog/src/main/java/roboy/linguistics/sentenceanalysis/DictionaryBasedSentenceTypeDetector.java +++ b/dialog/src/main/java/roboy/linguistics/sentenceanalysis/DictionaryBasedSentenceTypeDetector.java @@ -15,11 +15,19 @@ public class DictionaryBasedSentenceTypeDetector implements Analyzer{ public Interpretation analyze(Interpretation interpretation) { List tokens = interpretation.getTokens(); String[] posTags = interpretation.getPosTags(); - SentenceType sentenceType = determineSentenceType(tokens, posTags); - interpretation.setSentenceType(sentenceType); + + //Sentence Types shall be handled in Semantic Parser Analyzer. This is a fallback, in the event that SPA does not detect the sentence type + if(interpretation.getSentenceType().equals(SentenceType.STATEMENT)){ + SentenceType sentenceType = determineSentenceType(tokens, posTags); + interpretation.setSentenceType(sentenceType); + + } return interpretation; } + /** + * Fallback Sentence Type Detection, main Detector now in {@link SemanticParserAnalyzer} + */ private SentenceType determineSentenceType(List tokens, String[] posTags){ if (tokens != null && !tokens.isEmpty()) { String first = tokens.get(0).toLowerCase(); diff --git a/dialog/src/main/java/roboy/linguistics/sentenceanalysis/EmotionAnalyzer.java b/dialog/src/main/java/roboy/linguistics/sentenceanalysis/EmotionAnalyzer.java index e2c56617..4e8ca5b8 100755 --- a/dialog/src/main/java/roboy/linguistics/sentenceanalysis/EmotionAnalyzer.java +++ b/dialog/src/main/java/roboy/linguistics/sentenceanalysis/EmotionAnalyzer.java @@ -62,7 +62,6 @@ public Interpretation analyze(Interpretation interpretation) List labels = new ArrayList<>(); for(int i = 0; i= threshold){ if(sentenceNotNegative){ @@ -121,7 +117,7 @@ public Interpretation analyze(Interpretation interpretation) } } else if(sadSimilarity >= threshold){ - if(sentenceNotNegative){ + if(!sentencePositive){ interpretation.setEmotion(RoboyEmotion.SADNESS); } } @@ -135,13 +131,13 @@ else if(happySimilarity >= threshold){ interpretation.setEmotion(RoboyEmotion.SHY); } } - else{ - interpretation.setEmotion(RoboyEmotion.NEUTRAL); - } +// else{ +// interpretation.setEmotion(RoboyEmotion.NEUTRAL); +// } return interpretation; -// //TODO: to be deleted +// // OLD EMOTION ANALYZER // List tokens = interpretation.getTokens(); // if (tokens != null && !tokens.isEmpty()) { // if (tokens.contains("love") || tokens.contains("cute")) { diff --git a/dialog/src/main/java/roboy/linguistics/sentenceanalysis/Interpretation.java b/dialog/src/main/java/roboy/linguistics/sentenceanalysis/Interpretation.java index d3695e51..f7218a39 100755 --- a/dialog/src/main/java/roboy/linguistics/sentenceanalysis/Interpretation.java +++ b/dialog/src/main/java/roboy/linguistics/sentenceanalysis/Interpretation.java @@ -99,6 +99,19 @@ public void setSentenceType(SentenceType sentenceType) { this.sentenceType = sentenceType; } + public boolean isQuestion() { + return this.sentenceType==SentenceType.WHAT || + this.sentenceType==SentenceType.WHO || + this.sentenceType==SentenceType.HOW || + this.sentenceType==SentenceType.HOW_DO || + this.sentenceType==SentenceType.HOW_IS || + this.sentenceType==SentenceType.WHEN || + this.sentenceType==SentenceType.WHERE || + this.sentenceType==SentenceType.WHY || + this.sentenceType==SentenceType.IS_IT || + this.sentenceType==SentenceType.DOES_IT; + } + @Nullable public String getSentence() { return sentence; @@ -176,6 +189,7 @@ public Map getPas() { } public void setPas(Map pas) { + pas.forEach((k,v) -> v.toLowerCase()); this.pas = pas; } @@ -475,6 +489,55 @@ public String toString() { '}'; } + public void toLowerCase() { + if (sentence != null) { + sentence = sentence.toLowerCase(); + } + if (triples != null) { + for (int i = 0; i < triples.size(); i++) { + if (triples.get(i) != null) { + triples.set(i, triples.get(i).toLowerCase()); + } + } + } + if (tokens != null) { + for (int i = 0; i < tokens.size(); i++) { + if (tokens.get(i) != null) { + tokens.set(i, tokens.get(i).toLowerCase()); + } + } + } + if (this.lemmas != null) { + for (int i = 0; i < lemmas.length; i++) { + if (lemmas[i] != null) { + lemmas[i] = lemmas[i].toLowerCase(); + } + } + } + if (this.pas != null) { + for (SemanticRole key : pas.keySet()) { + if (pas.get(key) != null) { + pas.replace(key, pas.get(key).toLowerCase()); + } + } + } + if (this.name != null) { + this.name = this.name.toLowerCase(); + } + if (this.objAnswer != null) { + this.objAnswer = this.objAnswer.toLowerCase(); + } + if (this.predAnswer != null) { + this.predAnswer = this.predAnswer.toLowerCase(); + } + if (this.underspecifiedQuestion != null) { + this.underspecifiedQuestion = this.underspecifiedQuestion.toLowerCase(); + } + if (this.underspecifiedAnswer != null) { + this.underspecifiedAnswer = this.underspecifiedAnswer.toLowerCase(); + } + } + @Override public boolean equals(Object obj) { if (this == obj) { diff --git a/dialog/src/main/java/roboy/linguistics/sentenceanalysis/OpenNLPParser.java b/dialog/src/main/java/roboy/linguistics/sentenceanalysis/OpenNLPParser.java index 5333e419..b7663593 100755 --- a/dialog/src/main/java/roboy/linguistics/sentenceanalysis/OpenNLPParser.java +++ b/dialog/src/main/java/roboy/linguistics/sentenceanalysis/OpenNLPParser.java @@ -1,8 +1,6 @@ package roboy.linguistics.sentenceanalysis; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; +import java.io.*; import java.util.HashMap; import java.util.Map; import java.util.concurrent.Semaphore; @@ -48,10 +46,14 @@ public Interpretation analyze(Interpretation interpretation) { String sentence = interpretation.getSentence(); if (sentence != null) { sentence = sentence.trim(); - if (!sentence.endsWith(".") - && !sentence.endsWith("?") - && !sentence.endsWith("!")) { - sentence = sentence + " ."; + if (sentence.endsWith(".") + || sentence.endsWith("?") + || sentence.endsWith("!")) { + // insert a space before end punctuation + String end = sentence.substring(sentence.length()-1); + sentence = sentence.substring(0,sentence.length()-1) + " " + end; + } else { + sentence = sentence + " ."; } if (sentence.length() > 0 && Character.isLowerCase(sentence.charAt(0))) { sentence = Character.toUpperCase(sentence.charAt(0)) + sentence.substring(1, sentence.length()); @@ -234,13 +236,20 @@ public StringBuilder parseToString(Parse parse, int offset){ return sb; } - public static void main(String[] args) { + public static void main(String[] args) throws IOException{ // Interpretation i = new Interpretation("The man is seen by the boy with the binoculars."); System.out.println("Initializing..."); - Interpretation i = new Interpretation("Bill said that Mike like to play the piano."); - OpenNLPParser parser = new OpenNLPParser(); - System.out.println("Parsing..."); - parser.analyze(i); + BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); + while(true) { + String text = reader.readLine(); + Interpretation i = new Interpretation(text); + OpenNLPParser parser = new OpenNLPParser(); + System.out.println("Parsing..."); + parser.analyze(i); + i.getPas().forEach((k, v) -> System.out.println(k + ": " + v)); + System.out.println("done"); + } + } } diff --git a/dialog/src/main/java/roboy/linguistics/sentenceanalysis/Postprocessor.java b/dialog/src/main/java/roboy/linguistics/sentenceanalysis/Postprocessor.java new file mode 100644 index 00000000..5b677c7e --- /dev/null +++ b/dialog/src/main/java/roboy/linguistics/sentenceanalysis/Postprocessor.java @@ -0,0 +1,14 @@ +package roboy.linguistics.sentenceanalysis; + +import roboy.linguistics.Linguistics; + +/** + * Corrects abbreviated forms like "I'm" to complete forms like "I am" + * which are expected by later sentence analyses. + */ +public class Postprocessor implements Analyzer{ + public Interpretation analyze(Interpretation interpretation){ + interpretation.toLowerCase(); + return interpretation; + } +} diff --git a/dialog/src/main/java/roboy/linguistics/sentenceanalysis/SemanticParserAnalyzer.java b/dialog/src/main/java/roboy/linguistics/sentenceanalysis/SemanticParserAnalyzer.java index 69bd48f0..0021b885 100644 --- a/dialog/src/main/java/roboy/linguistics/sentenceanalysis/SemanticParserAnalyzer.java +++ b/dialog/src/main/java/roboy/linguistics/sentenceanalysis/SemanticParserAnalyzer.java @@ -118,7 +118,7 @@ public Interpretation analyze(Interpretation interpretation) return interpretation; } - private void executeSemanticAnalysis(Interpretation result, Example ex) + private synchronized void executeSemanticAnalysis(Interpretation result, Example ex) { builder.parser.parse(builder.params, ex, false, builder.error_retrieval); ex.logWithoutContext(); @@ -142,7 +142,7 @@ private void executeSemanticAnalysis(Interpretation result, Example ex) String answer = val.pureString(); //Handle URL's - if (answer.contains(" at the end of URL } diff --git a/dialog/src/main/java/roboy/logic/Inference.java b/dialog/src/main/java/roboy/logic/Inference.java index 0ec42d91..d9dc6f89 100644 --- a/dialog/src/main/java/roboy/logic/Inference.java +++ b/dialog/src/main/java/roboy/logic/Inference.java @@ -23,12 +23,26 @@ public class Inference implements InferenceEngine { private String inferName(Interpretation input) { + String name; if (input.getSentenceType().compareTo(Linguistics.SentenceType.STATEMENT) == 0) { List tokens = input.getTokens(); if (tokens != null && !tokens.isEmpty()) { if (tokens.size() == 1) { return tokens.get(0).toLowerCase(); } else { + if (input.getPas().containsKey(Linguistics.SemanticRole.PREDICATE)) { + name = input.getPas().get(Linguistics.SemanticRole.PREDICATE).toLowerCase(); + if (!name.contains(" ")){ + return name; + } + } + if (!input.getTriples().isEmpty()) { + name = input.getTriples().get(0).object.toLowerCase(); + if (!name.contains(" ")) { + return name; + } + } + if (input.getParsingOutcome() == Linguistics.ParsingOutcome.SUCCESS && input.getSemTriples() != null) { List result = input.getSemTriples(); @@ -36,13 +50,13 @@ private String inferName(Interpretation input) { return result.get(0).object.toLowerCase(); } else { if (input.getObjAnswer() != null) { - String name = input.getObjAnswer(); + name = input.getObjAnswer(); return !name.equals("") ? name : null; } } } else { if (input.getObjAnswer() != null) { - String name = input.getObjAnswer(); + name = input.getObjAnswer(); return !name.equals("") ? name : null; } } diff --git a/dialog/src/main/java/roboy/memory/Neo4jLabel.java b/dialog/src/main/java/roboy/memory/Neo4jLabel.java index 72a32496..09369891 100755 --- a/dialog/src/main/java/roboy/memory/Neo4jLabel.java +++ b/dialog/src/main/java/roboy/memory/Neo4jLabel.java @@ -12,9 +12,9 @@ */ public enum Neo4jLabel { Person("Person"), - TelegramPerson("TelegramPerson"), - FacebookPerson("FacebookPerson"), - SlackPerson("SlackPerson"), + Telegram_person("Telegram_person"), + Facebook_person("Facebook_person"), + Slack_person("Slack_person"), Robot("Robot"), Company("Company"), University("University"), @@ -26,6 +26,7 @@ public enum Neo4jLabel { Location("Location"), Organization("Organization"), Other("Other"), + Created_by("Created_by"), None(""); public String type; diff --git a/dialog/src/main/java/roboy/memory/Neo4jProperty.java b/dialog/src/main/java/roboy/memory/Neo4jProperty.java index d1d30eea..6d71c4df 100755 --- a/dialog/src/main/java/roboy/memory/Neo4jProperty.java +++ b/dialog/src/main/java/roboy/memory/Neo4jProperty.java @@ -3,6 +3,7 @@ import com.google.common.collect.Maps; import java.util.Map; +import java.util.Random; /** * Contains the relations available in Neo4j database. @@ -22,9 +23,13 @@ public enum Neo4jProperty { telegram_id("telegram_id"), slack_id("slack_id"), whatsapp_id("whatsapp_id"), - line_id("line_id"); + line_id("line_id"), + identitiy("identity"), + dreams("dreams"), + media("media"); public String type; + private static final Random random = new Random(); Neo4jProperty(String type) { this.type = type; @@ -43,6 +48,11 @@ public static Neo4jProperty lookupByType(String type) { return typeIndex.get(type); } + public static Neo4jProperty getRandom() { + int x = random.nextInt(Neo4jProperty.class.getEnumConstants().length); + return Neo4jProperty.class.getEnumConstants()[x]; + } + public static boolean contains(String type){ return typeIndex.containsKey(type); } diff --git a/dialog/src/main/java/roboy/memory/Neo4jRelationship.java b/dialog/src/main/java/roboy/memory/Neo4jRelationship.java index d2c01cbf..64141a37 100755 --- a/dialog/src/main/java/roboy/memory/Neo4jRelationship.java +++ b/dialog/src/main/java/roboy/memory/Neo4jRelationship.java @@ -24,7 +24,8 @@ public enum Neo4jRelationship { SIBLING_OF("SIBLING_OF"), KNOW("KNOW"), OTHER("OTHER"), - IS("IS"); + IS("IS"), + CREATED_BY("CREATED_BY"); public String type; @@ -34,11 +35,25 @@ public enum Neo4jRelationship { public static Neo4jLabel determineNodeType(Neo4jRelationship relationship) { // TODO expand list as new Node types are added. - if(relationship.equals(HAS_HOBBY)) return Hobby; - if(relationship.equals(FROM)) return Country; - if(relationship.equals(WORK_FOR) || relationship.equals(STUDY_AT)) return Organization; - if(relationship.equals(OCCUPIED_AS)) return Occupation; - if(relationship.equals(OTHER)) return Other; + // TODO return list of Neo4jLabels, friend_of->(person,robot) + if(relationship.equals(HAS_HOBBY)) + return Hobby; + if(relationship.equals(FROM)) + return Country; + if(relationship.equals(WORK_FOR) || + relationship.equals(STUDY_AT) || + relationship.equals(MEMBER_OF)) + return Organization; + if(relationship.equals(OCCUPIED_AS)) + return Occupation; + if(relationship.equals(OTHER)) + return Other; + if(relationship.equals(LIVE_IN)) + return Location; + if(relationship.equals(FRIEND_OF) || + relationship.equals(CHILD_OF)) + return Person; + else return None; } diff --git a/dialog/src/main/java/roboy/memory/nodes/Interlocutor.java b/dialog/src/main/java/roboy/memory/nodes/Interlocutor.java index 57e855df..b0495b70 100755 --- a/dialog/src/main/java/roboy/memory/nodes/Interlocutor.java +++ b/dialog/src/main/java/roboy/memory/nodes/Interlocutor.java @@ -31,9 +31,9 @@ public Interlocutor(Neo4jMemoryInterface memory, String name) { this.addName(name); } - public Interlocutor(Neo4jMemoryInterface memory, Uuid uuid) { + public Interlocutor(Neo4jMemoryInterface memory, Uuid uuid, String name) { super(memory); - this.addUuid(uuid); + this.addUuid(uuid, name); } /** @@ -49,8 +49,9 @@ public void addName(String name) { FAMILIAR = this.init(this); } - public void addUuid(Uuid uuid) { - setProperty(uuid.getType().toNeo4jProperty(), uuid); + public void addUuid(Uuid uuid, String name) { + setProperty(Neo4jProperty.name, name); + setProperty(uuid.getType().toNeo4jProperty(), uuid.getUuid()); setLabel(uuid.getType().toNeo4jLabel()); FAMILIAR = this.init(this); } diff --git a/dialog/src/main/java/roboy/memory/nodes/Roboy.java b/dialog/src/main/java/roboy/memory/nodes/Roboy.java index eade179d..af304cc9 100755 --- a/dialog/src/main/java/roboy/memory/nodes/Roboy.java +++ b/dialog/src/main/java/roboy/memory/nodes/Roboy.java @@ -33,7 +33,7 @@ public Roboy(Neo4jMemoryInterface memory, String name) { */ public Roboy(Neo4jMemoryInterface memory) { super(true, memory); - this.InitializeRoboy("roboy two"); + this.InitializeRoboy("Roboy 2.0"); } /** @@ -138,4 +138,5 @@ public void addInformation(Neo4jRelationship relationship, String name) { logger.error(e.getMessage()); } } + } diff --git a/dialog/src/main/java/roboy/ros/RosMainNode.java b/dialog/src/main/java/roboy/ros/RosMainNode.java index 6a17ae0f..bc4c1954 100755 --- a/dialog/src/main/java/roboy/ros/RosMainNode.java +++ b/dialog/src/main/java/roboy/ros/RosMainNode.java @@ -11,11 +11,12 @@ import org.ros.node.service.ServiceResponseListener; import org.ros.node.topic.Subscriber; -import roboy.context.Context; import roboy.emotions.RoboyEmotion; import roboy.util.ConfigManager; import roboy_communication_cognition.*; import roboy_communication_control.*; +import std_srvs.TriggerRequest; +import std_srvs.TriggerResponse; import java.io.IOException; import java.net.URI; @@ -85,6 +86,34 @@ public void PerformMovement(String bodyPart, String name) throws InterruptedExce } + public boolean StartCupGameSmach() { + if(services.notInitialized(RosServiceClients.STARTCUPGAME)) { + return false; + } + + ServiceClient cupGameClient = services.getService(RosServiceClients.STARTCUPGAME); + rosConnectionLatch = new CountDownLatch(1); + TriggerRequest request = cupGameClient.newMessage(); + ServiceResponseListener listener = new ServiceResponseListener() { + @Override + public void onSuccess(TriggerResponse response) { +// System.out.println(response.getSuccess()); + resp = response.getSuccess(); + rosConnectionLatch.countDown(); + } + + @Override + public void onFailure(RemoteException e) { + rosConnectionLatch.countDown(); + throw new RosRuntimeException(e); + } + }; + cupGameClient.call(request, listener); + waitForLatchUnlock(rosConnectionLatch, cupGameClient.getName().toString()); + return ((boolean) resp); + + + } public boolean SynthesizeSpeech(String text) { if(services.notInitialized(RosServiceClients.SPEECHSYNTHESIS)) { @@ -115,6 +144,36 @@ public void onFailure(RemoteException e) { return ((boolean) resp); } + public boolean PlaySoundFile(String filename) { + + if(services.notInitialized(RosServiceClients.SOUNDPLAY)) { + // FALLBACK RETURN VALUE + return false; + } + + ServiceClient soundClient = services.getService(RosServiceClients.SOUNDPLAY); + rosConnectionLatch = new CountDownLatch(1); + TalkRequest request = soundClient.newMessage(); + request.setText(filename); + ServiceResponseListener listener = new ServiceResponseListener() { + @Override + public void onSuccess(TalkResponse response) { +// System.out.println(response.getSuccess()); + resp = response.getSuccess(); + rosConnectionLatch.countDown(); + } + + @Override + public void onFailure(RemoteException e) { + rosConnectionLatch.countDown(); + throw new RosRuntimeException(e); + } + }; + soundClient.call(request, listener); + waitForLatchUnlock(rosConnectionLatch, soundClient.getName().toString()); + return ((boolean) resp); + } + public String RecognizeSpeech() { if(services.notInitialized(RosServiceClients.STT)) { @@ -399,16 +458,6 @@ public void onFailure(RemoteException e) { return resp; } - public void addListener(MessageListener listener, RosSubscribers subscriber) { - if(services.notInitialized(subscriber)) { - - LOGGER.warn(String.format(warning, subscriber.rosPackage)); - return; - } - Subscriber s = services.getSubscriber(subscriber); - s.addMessageListener(listener); - } - public boolean ApplyFilter(String filterName) { if(services.notInitialized(RosServiceClients.SNAPCHATFILTER)) { @@ -441,6 +490,17 @@ public void onFailure(RemoteException e) { return ((boolean) resp); } + public void addListener(MessageListener listener, RosSubscribers subscriber) { + if(services.notInitialized(subscriber)) { + + LOGGER.warn(String.format(warning, subscriber.rosPackage)); + return; + } + Subscriber s = services.getSubscriber(subscriber); + s.addMessageListener(listener); + } + + /** * Helper method to block the calling thread until the latch is zeroed by some other task. * @param latch Latch to wait for. diff --git a/dialog/src/main/java/roboy/ros/RosServiceClients.java b/dialog/src/main/java/roboy/ros/RosServiceClients.java index bd9d994e..d56d9c42 100755 --- a/dialog/src/main/java/roboy/ros/RosServiceClients.java +++ b/dialog/src/main/java/roboy/ros/RosServiceClients.java @@ -2,7 +2,7 @@ import roboy_communication_cognition.*; import roboy_communication_control.*; - +import std_srvs.Trigger; /** * Stores the different client addresses and corresponding ROS message types. */ @@ -21,7 +21,9 @@ enum RosServiceClients { DELETEMEMORY("roboy_memory", "/roboy/cognition/memory/remove", DataQuery._TYPE), CYPHERMEMORY("roboy_memory", "/roboy/cognition/memory/cypher", DataQuery._TYPE), INTENT("roboy_intents", "/roboy/cognition/detect_intent", DetectIntent._TYPE), - SNAPCHATFILTER("roboy_filters", "/roboy/cognition/apply_filter", ApplyFilter._TYPE); + SNAPCHATFILTER("roboy_filters", "/roboy/cognition/apply_filter", ApplyFilter._TYPE), + SOUNDPLAY("sound_play", "/roboy/matrix/sound/play", Talk._TYPE), + STARTCUPGAME("roboy_soli", "roboy/cupgame/start", Trigger._TYPE); String rosPackage; String address; diff --git a/dialog/src/main/java/roboy/ros/RosSubscribers.java b/dialog/src/main/java/roboy/ros/RosSubscribers.java index 23c216ee..db60937e 100644 --- a/dialog/src/main/java/roboy/ros/RosSubscribers.java +++ b/dialog/src/main/java/roboy/ros/RosSubscribers.java @@ -1,12 +1,21 @@ package roboy.ros; import roboy_communication_cognition.*; +import roboy_communication_control.Strings; + public enum RosSubscribers { DIRECTION_VECTOR("roboy_audio", "/roboy/cognition/audio/direction_of_arrival", DirectionVector._TYPE), FACE_COORDINATES("roboy_vision", "/roboy/cognition/vision/coordinates", FaceCoordinates._TYPE), NEW_FACIAL_FEATURES("roboy_vision", "/roboy/cognition/vision/features", NewFacialFeatures._TYPE), - TEST_TOPIC("roboy_test", "/roboy", std_msgs.String._TYPE); + TEST_TOPIC("roboy_test", "/roboy", std_msgs.String._TYPE), + DETECTED_OBJECTS("roboy_vision", "/roboy/cognition/vision/detected_objects", Strings._TYPE), + NUMBER_PEOPLE_AROUND("roboy_vision", "/roboy/cognition/vision/people_around", std_msgs.Int8._TYPE), + PERSON_LISTENING("roboy_vision", "/roboy/cognition/vision/person_listening", std_msgs.Bool._TYPE), + BOOTH_SENTENCE("roboy_nodered", "/roboy/cognition/nodered/boothsentence", std_msgs.String._TYPE), + CUP_GAME_READY("roboy_soli", "/roboy/control/ball", std_msgs.Bool._TYPE), + CUP_GAME_STATE("roboy_soli", "/roboy/control/smach", std_msgs.String._TYPE) + ; String rosPackage; String address; diff --git a/dialog/src/main/java/roboy/talk/PhraseCollection.java b/dialog/src/main/java/roboy/talk/PhraseCollection.java index c942ffe9..9a6d7262 100644 --- a/dialog/src/main/java/roboy/talk/PhraseCollection.java +++ b/dialog/src/main/java/roboy/talk/PhraseCollection.java @@ -50,7 +50,6 @@ public class PhraseCollection { = readFile("resources/phraseLists/gamePhrases/akinator-error-phrases.txt"); public static RandomList PROFANITY_CHECK_WORDS = FileLineReader.readFile("resources/phraseLists/profanity-check-list.txt"); - // Added for the ExpoPersonality public static RandomList FACTS = readFile("resources/phraseLists/expoPhrases/facts.txt"); public static RandomList INFO_ROBOY_INTENT_PHRASES @@ -69,5 +68,16 @@ public class PhraseCollection { = readFile("resources/phraseLists/expoPhrases/offer-math.txt"); public static RandomList PARSER_ERROR = readFile("resources/phraseLists/expoPhrases/parser-error.txt"); - + public static RandomList ROBOY_TEAM_PHRASES + = readFile("resources/phraseLists/fairShowPhrases/roboy-team.txt"); + public static RandomList MISSION_PHRASES + =readFile("resources/phraseLists/fairShowPhrases/mission.txt"); + public static RandomList MOVEMENT_PHRASES + = readFile("resources/phraseLists/fairShowPhrases/movement.txt"); + public static RandomList EMOTION_PHRASES + = readFile("resources/phraseLists/fairShowPhrases/emotions.txt"); + public static RandomList ROBOY_PHRASES + = readFile("resources/phraseLists/fairShowPhrases/project-intro.txt"); + public static RandomList ASK_NAME + = readFile("resources/phraseLists/question-name.txt"); } diff --git a/dialog/src/main/java/roboy/talk/Verbalizer.java b/dialog/src/main/java/roboy/talk/Verbalizer.java index 1fbb499a..316f978b 100755 --- a/dialog/src/main/java/roboy/talk/Verbalizer.java +++ b/dialog/src/main/java/roboy/talk/Verbalizer.java @@ -46,7 +46,7 @@ public Action verbalize(Interpretation interpretation){ new RandomList<>("yes", "I do", "sure", "of course", " go ahead"); public static final RandomList denial = - new RandomList<>("no", "nope", "later", "other time", "not"); + new RandomList<>("no", "nope", "later", "other time", "not", "next time", "nah"); // triggers that will start the conversation public static final RandomList triggers = @@ -54,23 +54,60 @@ public Action verbalize(Interpretation interpretation){ public static final RandomList greetings = new RandomList<>("hello","hi","greetings", - // "good morning", // not for the final demo ;) + "good morning", // not for the final demo ;) "howdy", - // "good day", // not for the final demo ;) - "hey", "good evening", - "what's up", "greeting to everyone here","hi there people", - "hello world","gruse gott","wazup wazup wazup","howdy humans", - // "good day ladies and gentlemen", // not for the final demo ;) - "good evening ladies and gentlemen", - "hey hey hey you there"); + "good day", // not for the final demo ;) + "hey", + "good evening", + "what's up", + "greetings to everyone here", + "hi there people", + "hello world","gruse gott", + "wazup wazup wazup", + "howdy humans", + "good day ladies and gentlemen", // not for the final demo ;) + "good evening ladies and gentlemen", + "hey hey hey you there", + "Hey! I was looking for someone to chat."); + + public static final RandomList privateGreetings = + new RandomList<>("hello.","hi.","greetings!", + "howdy!", + "hey, ", + "what's up?", + "hi there!", + "hello world!", + "gruse gott!", + "servus,", + "wazup wazup wazup!!!", + "howdy humans?", + "hey hey hey you there!", + "Hey! I was looking for someone to chat."); + + public static final RandomList askForFeedback = + new RandomList<>("So, how did you find it?", + "did you like it?", + "what do you think? was it good?", + "here it is. i hope you enjoyed it. did you?", + "what do you thing? was it good, bad, excellent?"); + + public static final RandomList takePositiveFeedback = + new RandomList<>("Yay! That is amazing!", + "Good, I was worried for a second", + "Thank you, thank you.", + "Oh, thanks, that makes me a bit happier"); + + public static final RandomList takeNegativeFeedback = + new RandomList<>("uh-oh, alright then.", + "Okay, thank you for being honest", + "Got it, will note it for the future"); private SpeechAction greet(Interpretation interpretation){ return new SpeechAction(StatementBuilder.random(greetings)); } public static final RandomList farewells = new RandomList<>( - "ciao", "goodbye", "cheerio", "bye", - "see you", "farewell", "bye-bye"); + "ciao", "goodbye", "cheerio", "bye", "farewell", "bye-bye"); private static final RandomList segues = new RandomList<>("talking about ","since you mentioned ","on the topic of "); @@ -79,21 +116,36 @@ private SpeechAction segue(Interpretation interpretation){ return new SpeechAction(StatementBuilder.random(segues) + interpretation.getAssociation()); } + public static final RandomList KNOWN_PERSON_WITH_NAME = new RandomList<>("I know you, %s!", + "My buddy %s is here!", "Look at you %s. Glad you stopped by to chat.", + "What a nice surprise, %s, that you decided to talk to me", + "Look who's here! %s my friend!"); + + public static final RandomList NEW_PERSON_WITH_NAME = new RandomList<>("Nice to meet you %s", + "It is my pleasure to meet you, good sir (or milady) %s!", + "I'm happy to know you %s!", + "Glad, I got a chance to get to know you %s."); + + private static final RandomList CONTASING_CONJUNCTIONS = new RandomList<>("but,", + "however, ", "nevertheless, ", "on the other hand, ", "alternatively, "); private static final RandomList preAnecdotes = new RandomList<>("here is an interesting bit of trivia. ", "how about this? "); private static final RandomList anecdotes = - new RandomList<>("did you know ","did you know that ","i read that ", - "i heard that ", "have you heard this: "); + new RandomList<>("Did you know this?","Did you know? ","I read this thing. ", + "Yesterday I found read this interesting fact. ", "Have you heard this: ", "Probably unrelated, ", "I think you should know this.", + "I bet you didn't know this.", "Can you imagine? ", "I was browsing Reddit in my free time. And guess what?"); private SpeechAction anecdote(Interpretation interpretation){ - String prefix = Math.random()<0.3 ? StatementBuilder.random(preAnecdotes) : ""; + String prefix = PhraseCollection.SEGUE_AVOID_ANSWER.getRandomElement(); + prefix += CONTASING_CONJUNCTIONS.getRandomElement(); return new SpeechAction(prefix+StatementBuilder.random(anecdotes) + interpretation.getSentence()); } public static final RandomList startSomething = - new RandomList<>("Let's go. ", "Can't wait to start. ", "Nice, let's start. ", "Yeah, let's go. " + new RandomList<>("Let's go. ", "Can't wait to start. ", "Nice, let's start. ", "Yeah, let's go. ", + "Alright, here we go.", "You asked for it.", "Let's do it!" ); public static final RandomList userIsSure = @@ -124,6 +176,14 @@ private SpeechAction anecdote(Interpretation interpretation){ new RandomList<>("Oh no, where is my ROS connection? I need it. ", "I was looking for my ROS master everywhere but I can find it. ", "I think I have no ROS connection. ", "Hello? Hello? Any ROS master out there? Hmm, I can't hear anybody. " ); + public static final RandomList roboyIntro = + new RandomList<>("I am Roboy. Happy to be here! ", "My name is Roboy. Thank you for having me! ", "You can call me Roboy. What a nice place here. " + ); + + public static final RandomList confirmStory = + new RandomList<>("Alright, story then you get a story.", + "My pleasure to tell you a story"); + private Interpretation verbalizeDates(Interpretation interpretation){ StringBuilder sb = new StringBuilder(); String sentence = interpretation.getSentence(); diff --git a/dialog/src/main/java/roboy/util/ConfigManager.java b/dialog/src/main/java/roboy/util/ConfigManager.java index 8aec3099..c123f684 100644 --- a/dialog/src/main/java/roboy/util/ConfigManager.java +++ b/dialog/src/main/java/roboy/util/ConfigManager.java @@ -43,12 +43,19 @@ public class ConfigManager { public static boolean CONTEXT_GUI_ENABLED = false; + public static long CONVERSATION_TIMEOUT = 0; + public static String TELEGRAM_API_TOKENS_FILE = ""; + public static int TELEGRAM_TYPING_DELAY = 0; + public static int TELEGRAM_PROCESSING_DELAY = 2; public static String MEMORY_LOG_MODE = "INFO"; public static String DIALOG_LOG_MODE = "INFO"; public static String PARSER_LOG_MODE = "ALL"; + public static String PARLAI_HOST = "127.0.0.1"; + public static int PARLAI_PORT = 8877; + static { // this block is called once at and will initialize config // alternative: create a singleton for this class @@ -66,7 +73,9 @@ private static void initializeConfig() { YAMLConfiguration yamlConfig = new YAMLConfiguration(); try { + System.out.println(System.getProperty("user.dir")); File propertiesFile = new File(yamlConfigFile); + System.out.println(propertiesFile.getAbsolutePath()); if (!propertiesFile.exists()) { // propertiesFile == null doesn't work! LOGGER.error("Could not find "+yamlConfigFile+" file in project path! YAML configurations will be unavailable."); @@ -121,12 +130,25 @@ private static void initializeConfig() { ACTION_CLIENT_SCRIPT = yamlConfig.getString("ACTION_CLIENT_SCRIPT"); + long timeout = yamlConfig.getLong("CONVERSATION_TIMEOUT"); + if (timeout < 0){ + LOGGER.error("Invalid timeout setting: " + timeout + "disabling timeout..."); + } else { + CONVERSATION_TIMEOUT = timeout; + } + TELEGRAM_API_TOKENS_FILE = yamlConfig.getString("TELEGRAM_API_TOKENS_FILE"); + TELEGRAM_PROCESSING_DELAY = yamlConfig.getInt("TELEGRAM_PROCESSING_DELAY"); + TELEGRAM_TYPING_DELAY = yamlConfig.getInt("TELEGRAM_TYPING_DELAY"); + + PARLAI_HOST = yamlConfig.getString("PARLAI_HOST"); + PARLAI_PORT = yamlConfig.getInt("PARLAI_PORT"); MEMORY_LOG_MODE = (yamlConfig.getString("MEMORY_LOG_MODE")); PARSER_LOG_MODE = (yamlConfig.getString("PARSER_LOG_MODE")); DIALOG_LOG_MODE = (yamlConfig.getString("DIALOG_LOG_MODE")); + } catch(ConfigurationException | FileNotFoundException e) { LOGGER.error("Exception while reading YAML configurations from "+yamlConfigFile); LOGGER.error(e.getMessage()); diff --git a/dialog/src/main/java/roboy/util/IO.java b/dialog/src/main/java/roboy/util/IO.java index 0b031108..c3ffd01f 100755 --- a/dialog/src/main/java/roboy/util/IO.java +++ b/dialog/src/main/java/roboy/util/IO.java @@ -1,9 +1,12 @@ package roboy.util; +import org.apache.jena.base.Sys; import roboy.io.*; import roboy.ros.RosMainNode; +import java.io.BufferedReader; import java.io.IOException; +import java.io.InputStreamReader; import java.net.SocketException; import java.net.UnknownHostException; import java.nio.charset.StandardCharsets; @@ -12,6 +15,8 @@ import java.nio.file.Paths; import java.util.ArrayList; import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -90,6 +95,9 @@ public static MultiOutputDevice getOutputs(RosMainNode rosMainNode, String uuid) case "telegram": outputs.add(new TelegramOutput(uuid)); break; + case "sound": + outputs.add(new SoundOutput(rosMainNode)); + break; default: outputs.add(new CommandLineOutput()); } @@ -112,4 +120,41 @@ public static MultiOutputDevice getOutputs(RosMainNode rosMainNode, String uuid) } + public static String toSentenceCase(String input) { + StringBuffer buffy = new StringBuffer(input); + // capitalize after . ? ! followed by whitespace(s) + Pattern pattern = Pattern.compile("(\\.+|\\?+|\\!+)\\s+(\\w)"); + Matcher matcher = pattern.matcher(buffy); + while (matcher.find()) + buffy.replace(matcher.end() - 1, matcher.end(), matcher.group(2).toUpperCase()); + // capitalize new line + pattern = Pattern.compile("(^\\w)"); + matcher = pattern.matcher(buffy); + while (matcher.find()) + buffy.replace(matcher.end() - 1, matcher.end(), matcher.group(0).toUpperCase()); + // lower case after comma or colon + pattern = Pattern.compile("(\\,|\\:)\\s*(\\w)"); + matcher = pattern.matcher(buffy); + while (matcher.find()) + buffy.replace(matcher.end() - 1, matcher.end(), matcher.group(2).toLowerCase()); + return buffy.toString(); + } + + public static String cleanWhiteSpaces(String input) { + return input.trim().replaceAll(" +", " "); + } + + public static String prettify(String input) { + return cleanWhiteSpaces(toSentenceCase(input)); + } + + public static void main(String[] args) throws IOException{ + BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); + while(true) { + String in = br.readLine(); + System.out.println(toSentenceCase(in)); + } + + } + } diff --git a/dialog/src/main/java/roboy/util/JsonEntryModel.java b/dialog/src/main/java/roboy/util/JsonEntryModel.java index 1788ff08..648b7263 100644 --- a/dialog/src/main/java/roboy/util/JsonEntryModel.java +++ b/dialog/src/main/java/roboy/util/JsonEntryModel.java @@ -1,12 +1,34 @@ package roboy.util; import java.util.Map; +import java.util.Objects; public class JsonEntryModel { + String intent; RandomList Q; Map> A; Map> FUP; + public void setIntent(String intent) { + this.intent = intent; + } + + public void setQuestions(RandomList q) { + Q = q; + } + + public void setAnswers(Map> a) { + A = a; + } + + public void setFUP(Map> FUP) { + this.FUP = FUP; + } + + public String getIntent() { + return intent; + } + public RandomList getQuestions() { return Q; } @@ -18,4 +40,31 @@ public Map> getAnswers() { public Map> getFUP() { return FUP; } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof JsonEntryModel)) return false; + JsonEntryModel that = (JsonEntryModel) o; + return Objects.equals(getIntent(), that.getIntent()) && + Objects.equals(Q, that.Q) && + Objects.equals(A, that.A) && + Objects.equals(getFUP(), that.getFUP()); + } + + @Override + public int hashCode() { + + return Objects.hash(getIntent(), Q, A, getFUP()); + } + + @Override + public String toString() { + return "JsonEntryModel{" + + "intent='" + intent + '\'' + + ", Q=" + Q + + ", A=" + A + + ", FUP=" + FUP + + '}'; + } } diff --git a/dialog/src/main/java/roboy/util/Lists.java b/dialog/src/main/java/roboy/util/Lists.java index d6c5d2b7..d4019b50 100755 --- a/dialog/src/main/java/roboy/util/Lists.java +++ b/dialog/src/main/java/roboy/util/Lists.java @@ -14,4 +14,5 @@ public static List stringList(String... strings){ result.addAll(Arrays.asList(strings)); return result; } + } diff --git a/dialog/src/main/java/roboy/util/QAFileParser.java b/dialog/src/main/java/roboy/util/QAFileParser.java deleted file mode 100644 index 1b157657..00000000 --- a/dialog/src/main/java/roboy/util/QAFileParser.java +++ /dev/null @@ -1,94 +0,0 @@ -package roboy.util; - -import com.google.common.base.Charsets; -import com.google.common.io.Resources; -import com.google.gson.Gson; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.google.gson.JsonParser; -import com.google.gson.reflect.TypeToken; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - -import java.lang.reflect.Type; -import java.net.URL; -import java.util.*; - -/** - * Parses files containing predefined questions and answers - * - * Expects the following input pattern: - * { - * "INTENT": { - * "Q": [ - * "Question phrasing 1", - * "Question phrasing 2", - * "Question phrasing 3" - * ], - * "A": { - * "SUCCESS": [ - * "Possible answer on success 1", - * "Possible answer on success 2" - * ], - * "FAILURE": [ - * "Possible answer on failure" - * ] - * } - * } - * } - * - * See more examples in resources/sentences - */ - -public class QAFileParser { - - private final Logger logger = LogManager.getLogger(); - - private static Map> questions; - private static Map> successAnswers; - private static Map> failureAnswers; - - public QAFileParser(String file) { - - questions = new HashMap<>(); - successAnswers = new HashMap<>(); - failureAnswers = new HashMap<>(); - - JsonParser jsonParser = new JsonParser(); - URL url = Resources.getResource(file); - - try { - String jsonString = Resources.toString(url, Charsets.UTF_8); - JsonElement jsonTree = jsonParser.parse(jsonString); - Set> entrySet = ((JsonObject) jsonTree).entrySet(); - Type listType = new TypeToken>() {}.getType(); - for(Map.Entry entry : entrySet) { - - JsonElement questionsJson = entry.getValue().getAsJsonObject().get("Q").getAsJsonArray(); - JsonElement successAnswersJson = entry.getValue().getAsJsonObject().get("A").getAsJsonObject().get("SUCCESS"); - JsonElement failureAnswersJson = entry.getValue().getAsJsonObject().get("A").getAsJsonObject().get("FAILURE"); - - questions.put(entry.getKey(), new Gson().fromJson(questionsJson, listType)); - successAnswers.put(entry.getKey(), new Gson().fromJson(successAnswersJson, listType)); - failureAnswers.put(entry.getKey(), new Gson().fromJson(failureAnswersJson, listType)); - } - }catch (Exception e) - { - logger.error("JSON was not parsed correctly"); - logger.error(e.getMessage()); - } - - } - - public Map> getQuestions() { - return questions; - } - - public Map> getSuccessAnswers() { - return successAnswers; - } - - public Map> getFailureAnswers() { - return failureAnswers; - } -} diff --git a/dialog/src/main/java/roboy/util/QAJsonParser.java b/dialog/src/main/java/roboy/util/QAJsonParser.java index b1f2652b..e1317623 100644 --- a/dialog/src/main/java/roboy/util/QAJsonParser.java +++ b/dialog/src/main/java/roboy/util/QAJsonParser.java @@ -1,9 +1,9 @@ package roboy.util; -import com.google.gson.Gson; -import com.google.gson.JsonIOException; -import com.google.gson.JsonParseException; -import com.google.gson.JsonSyntaxException; +import com.google.common.base.Charsets; +import com.google.common.io.Resources; +import com.google.gson.*; +import com.google.gson.reflect.TypeToken; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import roboy.memory.Neo4jProperty; @@ -11,63 +11,120 @@ import java.io.*; import java.lang.reflect.Field; +import java.lang.reflect.Type; +import java.net.MalformedURLException; +import java.net.URL; +import java.nio.file.Paths; +import java.util.HashMap; +import java.util.List; import java.util.Map; - -class JsonModel { - // TODO: Dynamically create JsonModel as JsonEntryModel fields based on existing Neo4jRelationship/Properties entries - // Add a new entry - JsonEntryModel name; - JsonEntryModel full_name; - JsonEntryModel skills; - JsonEntryModel abilities; - JsonEntryModel age; - JsonEntryModel future; - JsonEntryModel FROM; - JsonEntryModel HAS_HOBBY; - JsonEntryModel LIVE_IN; - JsonEntryModel FRIEND_OF; - JsonEntryModel STUDY_AT; - JsonEntryModel MEMBER_OF; - JsonEntryModel WORK_FOR; - JsonEntryModel OCCUPIED_AS; - JsonEntryModel IS; - JsonEntryModel CHILD_OF; - JsonEntryModel SIBLING_OF; - JsonEntryModel OTHER; - JsonEntryModel APPLES; - JsonEntryModel ANIMAL; - JsonEntryModel WORD; - JsonEntryModel COLOR; - JsonEntryModel PLANT; - JsonEntryModel NAME; - JsonEntryModel FRUIT; -} +import java.util.Set; /** * Getting values for personalStates and follow-up questions * from a JSON file + * Parses files containing predefined questions and answers + * + * Expects the following input pattern: + * { + * "INTENT": { + * "Q": [ + * "Question phrasing 1", + * "Question phrasing 2", + * "Question phrasing 3" + * ], + * "A": { + * "SUCCESS": [ + * "Possible answer on success 1", + * "Possible answer on success 2" + * ], + * "FAILURE": [ + * "Possible answer on failure" + * ] + * } + * "FUP": { + * "Q": [ + * "Possible follow up question" + * ], + * "A": [ + * "Possible follow up answer" + * ] + * } + * } + * } + * + * See more examples in resources/sentences */ public class QAJsonParser { - private Gson gson; - private JsonModel jsonObject; - private final Logger LOGGER = LogManager.getLogger(); - public QAJsonParser() { - jsonObject = null; - } + private Map> questions; + private Map> successAnswers; + private Map> failureAnswers; + private Map> followUpQuestions; + private Map> followUpAnswers; + private Set> entrySet; + + private Gson gson; public QAJsonParser(String file) { - jsonObject = parse(file); + parse(file); } - public JsonModel parse(String file) { + public boolean parse(String file) { + gson = new Gson(); + + questions = new HashMap<>(); + successAnswers = new HashMap<>(); + failureAnswers = new HashMap<>(); + followUpQuestions = new HashMap<>(); + followUpAnswers = new HashMap<>(); + + JsonParser jsonParser = new JsonParser(); + URL url = null; try { - File f = new File(file); - InputStream input = new FileInputStream(f); - BufferedReader br = new BufferedReader(new InputStreamReader(input)); - gson = new Gson(); - return gson.fromJson(br, JsonModel.class); + url = Paths.get(file).toUri().toURL(); + } catch (MalformedURLException e) { + LOGGER.error("File not found, URL is incorrect: " + e.getMessage()); + } + + try { + if (url != null) { + String jsonString = Resources.toString(url, Charsets.UTF_8); + JsonElement jsonTree = jsonParser.parse(jsonString); + entrySet = ((JsonObject) jsonTree).entrySet(); + Type listType = new TypeToken>() {}.getType(); + for (Map.Entry entry : entrySet) { + + JsonElement questionsJson = entry.getValue().getAsJsonObject().get("Q"); + if (questionsJson != null) { + questionsJson = questionsJson.getAsJsonArray(); + } + JsonElement successAnswersJson = entry.getValue().getAsJsonObject().get("A"); + if (successAnswersJson != null) { + successAnswersJson = successAnswersJson.getAsJsonObject().get("SUCCESS"); + } + JsonElement failureAnswersJson = entry.getValue().getAsJsonObject().get("A"); + if (failureAnswersJson != null) { + failureAnswersJson = failureAnswersJson.getAsJsonObject().get("FAILURE"); + } + JsonElement followUpQuestionsJson = entry.getValue().getAsJsonObject().get("FUP"); + if (followUpQuestionsJson != null) { + followUpQuestionsJson = followUpQuestionsJson.getAsJsonObject().get("Q"); + } + JsonElement followUpAnswersJson = entry.getValue().getAsJsonObject().get("FUP"); + if (followUpAnswersJson != null) { + followUpAnswersJson = followUpAnswersJson.getAsJsonObject().get("A"); + } + + questions.put(entry.getKey(), gson.fromJson(questionsJson, listType)); + successAnswers.put(entry.getKey(), gson.fromJson(successAnswersJson, listType)); + failureAnswers.put(entry.getKey(), gson.fromJson(failureAnswersJson, listType)); + followUpQuestions.put(entry.getKey(), gson.fromJson(followUpQuestionsJson, listType)); + followUpAnswers.put(entry.getKey(), gson.fromJson(followUpAnswersJson, listType)); + } + return true; + } } catch (JsonSyntaxException e) { LOGGER.error("Wrong syntax in QA json file" + e.getMessage()); } catch (JsonIOException e) { @@ -77,11 +134,7 @@ public JsonModel parse(String file) { } catch (Exception e) { LOGGER.error("Unexpected error while parsing QA values from json: " + e.getMessage()); } - return null; - } - - public JsonModel getQA() { - return jsonObject; + return false; } public JsonEntryModel getEntry(Neo4jRelationship relationship) { @@ -92,77 +145,154 @@ public JsonEntryModel getEntry(Neo4jProperty property) { return getJsonEntryModel(property.type); } + public RandomList getIntents() { + RandomList keys = new RandomList<>(); + if (!entrySet.isEmpty()) + { + entrySet.forEach(x->keys.add(x.getKey())); + } + else { + LOGGER.error("QAFileParser: no intents exist"); + } + return keys; + } + + + public Map> getQuestions() { + return questions; + } + public RandomList getQuestions(Neo4jRelationship relationship) { - return getEntry(relationship).getQuestions(); + return questions.get(relationship.type); + } + + public RandomList getQuestions(Neo4jProperty property) { + return questions.get(property.type); + } + + public RandomList getQuestions(String relationship) { + return questions.get(relationship); } public Map> getAnswers(Neo4jRelationship relationship) { - return getEntry(relationship).getAnswers(); + Map> answers = new HashMap<>(); + answers.put("SUCCESS", successAnswers.get(relationship.type)); + answers.put("FAILURE", failureAnswers.get(relationship.type)); + + return answers; } - public RandomList getSuccessAnswers(Neo4jRelationship relationship) { - return getAnswers(relationship).get("SUCCESS"); + public Map> getAnswers(Neo4jProperty property) { + Map> answers = new HashMap<>(); + answers.put("SUCCESS", successAnswers.get(property.type)); + answers.put("FAILURE", failureAnswers.get(property.type)); + + return answers; } - public RandomList getFailureAnswers(Neo4jRelationship relationship) { - return getAnswers(relationship).get("FAILURE"); + public Map> getAnswers(String property) { + Map> answers = new HashMap<>(); + answers.put("SUCCESS", successAnswers.get(property)); + answers.put("FAILURE", failureAnswers.get(property)); + + return answers; } - public Map> getFollowUp(Neo4jRelationship relationship) { - return getEntry(relationship).getFUP(); + + public Map> getSuccessAnswers() { + return successAnswers; } - public RandomList getFollowUpQuestions(Neo4jRelationship relationship) { - return getFollowUp(relationship).get("Q"); + public RandomList getSuccessAnswers(Neo4jRelationship relationship) { + return successAnswers.get(relationship.type); } - public RandomList getFollowUpAnswers(Neo4jRelationship relationship) { - return getFollowUp(relationship).get("A"); + public RandomList getSuccessAnswers(Neo4jProperty property) { + return successAnswers.get(property.type); } - public RandomList getQuestions(Neo4jProperty property) { - return getEntry(property).getQuestions(); + public RandomList getSuccessAnswers(String property) { + return successAnswers.get(property); } - public Map> getAnswers(Neo4jProperty property) { - return getEntry(property).getAnswers(); + public Map> getFailureAnswers() { + return failureAnswers; } - public RandomList getSuccessAnswers(Neo4jProperty property) { - return getAnswers(property).get("SUCCESS"); + public RandomList getFailureAnswers(Neo4jRelationship relationship) { + return failureAnswers.get(relationship.type); } public RandomList getFailureAnswers(Neo4jProperty property) { - return getAnswers(property).get("FAILURE"); + return failureAnswers.get(property.type); + } + + public RandomList getFailureAnswers(String property) { + return failureAnswers.get(property); + } + + public Map> getFollowUp(Neo4jRelationship relationship) { + Map> followUp = new HashMap<>(); + followUp.put("Q", followUpQuestions.get(relationship.type)); + followUp.put("A", followUpAnswers.get(relationship.type)); + + return followUp; } public Map> getFollowUp(Neo4jProperty property) { - return getEntry(property).getFUP(); + Map> followUp = new HashMap<>(); + followUp.put("Q", followUpQuestions.get(property.type)); + followUp.put("A", followUpAnswers.get(property.type)); + + return followUp; + } + + public Map> getFollowUp(String property) { + Map> followUp = new HashMap<>(); + followUp.put("Q", followUpQuestions.get(property)); + followUp.put("A", followUpAnswers.get(property)); + + return followUp; + } + + public RandomList getFollowUpQuestions(Neo4jRelationship relationship) { + return followUpQuestions.get(relationship.type); } public RandomList getFollowUpQuestions(Neo4jProperty property) { - return getFollowUp(property).get("Q"); + return followUpQuestions.get(property.type); + } + + public RandomList getFollowUpQuestions(String property) { + return followUpQuestions.get(property); + } + + public RandomList getFollowUpAnswers(Neo4jRelationship relationship) { + return followUpAnswers.get(relationship.type); } public RandomList getFollowUpAnswers(Neo4jProperty property) { - return getFollowUp(property).get("A"); + return followUpAnswers.get(property.type); + } + + public RandomList getFollowUpAnswers(String property) { + return followUpAnswers.get(property); } private JsonEntryModel getJsonEntryModel(String type) { - JsonEntryModel entryValue = null; - if (jsonObject != null) { - try { - Class types = JsonEntryModel.class; - Field field = jsonObject.getClass().getDeclaredField(type); - field.setAccessible(true); - Object value = field.get(jsonObject); - entryValue = (JsonEntryModel) value; - } catch (NoSuchFieldException e) { - LOGGER.error("No such entry in QA model: " + e.getMessage()); - } catch (IllegalAccessException e) { - LOGGER.error("Illegal access to the QA entries: " + e.getMessage()); - } - } + JsonEntryModel entryValue = new JsonEntryModel(); + + entryValue.setIntent(type); + entryValue.setQuestions(questions.get(type)); + Map> answers = new HashMap<>(); + answers.put("SUCCESS", successAnswers.get(type)); + answers.put("FAILURE", failureAnswers.get(type)); + entryValue.setAnswers(answers); + Map> followUp = new HashMap<>(); + followUp.put("Q", followUpQuestions.get(type)); + followUp.put("A", followUpAnswers.get(type)); + entryValue.setFUP(followUp); + return entryValue; } } \ No newline at end of file diff --git a/dialog/src/main/java/roboy/util/RandomList.java b/dialog/src/main/java/roboy/util/RandomList.java index 7a17470e..59440c81 100644 --- a/dialog/src/main/java/roboy/util/RandomList.java +++ b/dialog/src/main/java/roboy/util/RandomList.java @@ -2,6 +2,7 @@ import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.List; /** @@ -50,4 +51,11 @@ public T getRandomElement() { return get(id); } + public RandomList shuffle() { + RandomList tmp = (RandomList) this.clone(); + Collections.shuffle(tmp); + return tmp; + + } + } diff --git a/dialog/src/main/java/roboy/util/TelegramCommandHandler.java b/dialog/src/main/java/roboy/util/TelegramCommandHandler.java index 5c1ee944..cf2ea8b1 100644 --- a/dialog/src/main/java/roboy/util/TelegramCommandHandler.java +++ b/dialog/src/main/java/roboy/util/TelegramCommandHandler.java @@ -87,7 +87,7 @@ public void execute(){ { case PIC: //Just a roboy image, should be changed to desired roboy url - int randomNum = ThreadLocalRandom.current().nextInt(0, pictureUrls.length+ 1); + int randomNum = ThreadLocalRandom.current().nextInt(0, pictureUrls.length); String url = pictureUrls[randomNum]; tch.sendImageFromUrl(url, telegramChatID); break; diff --git a/dialog/src/main/java/roboy/util/TelegramCommunicationHandler.java b/dialog/src/main/java/roboy/util/TelegramCommunicationHandler.java index f296bb33..2993c2e7 100644 --- a/dialog/src/main/java/roboy/util/TelegramCommunicationHandler.java +++ b/dialog/src/main/java/roboy/util/TelegramCommunicationHandler.java @@ -1,7 +1,5 @@ package roboy.util; -import org.telegram.telegrambots.TelegramBotsApi; -import roboy.util.Pair; import org.apache.commons.io.IOUtils; import org.apache.jena.atlas.logging.Log; import org.apache.logging.log4j.LogManager; @@ -14,7 +12,6 @@ import org.telegram.telegrambots.api.methods.send.SendSticker; import org.telegram.telegrambots.api.objects.Message; import org.telegram.telegrambots.api.objects.Update; -import org.telegram.telegrambots.api.objects.User; import org.telegram.telegrambots.bots.TelegramLongPollingBot; import org.telegram.telegrambots.exceptions.TelegramApiException; import roboy.io.TelegramInput; @@ -30,11 +27,11 @@ public class TelegramCommunicationHandler extends TelegramLongPollingBot impleme private final static Logger logger = LogManager.getLogger(); private static final String tokensPath = ConfigManager.TELEGRAM_API_TOKENS_FILE;//place path to your token file here - private static final int TYPING_TIME_LIMIT = 3; //SECONDS - private static final int INPUT_TIME_LIMIT = 5; //SECONDS + private static final int TYPING_DELAY = ConfigManager.TELEGRAM_TYPING_DELAY; //SECONDS + private static final int PROCESSING_DELAY = ConfigManager.TELEGRAM_PROCESSING_DELAY; //SECONDS // CHAT ID ----- ITS MESSAGE - private volatile List> pairs = new ArrayList<>(); + private volatile List>> pairs = new ArrayList<>();//[UserName, [UserID, Message]] private List telegramTimeouts; //Timeouts private final static int initTime = (int) (System.currentTimeMillis() / 1000L); //in order to discard messages older than launch @@ -66,7 +63,7 @@ private void handleTimeout(String chatID){ // if the list is empty create the first timeout and set it if(telegramTimeouts.isEmpty()){ - Timeout t = new Timeout(millisecond * INPUT_TIME_LIMIT); + Timeout t = new Timeout(millisecond * PROCESSING_DELAY); t.setUnique(chatID); telegramTimeouts.add(t); @@ -82,7 +79,7 @@ private void handleTimeout(String chatID){ if(!hasStarted){ // there is no timeout for given chatID so start one - Timeout t = new Timeout(millisecond * INPUT_TIME_LIMIT); + Timeout t = new Timeout(millisecond * PROCESSING_DELAY); t.setUnique(chatID); t.start(this); @@ -96,6 +93,7 @@ private void handleTimeout(String chatID){ */ @Override public void onUpdateReceived(Update update) { + String name = null; if(!update.hasMessage()){ return; } @@ -107,17 +105,27 @@ public void onUpdateReceived(Update update) { String chatID = message.getChatId().toString(); String text = message.getText(); - Log.debug(this, "text: "+text); if(text.charAt(0) == '/'){ //handle inline command - sendMessage("command captured",chatID); - Log.debug(this, "inline command captured"); TelegramCommandHandler commandHandler = new TelegramCommandHandler(text, chatID); commandHandler.execute(); }else{ + //try to find a suitable way to adress the interlocutor + //first, try to find their user name + //if that didn't work try to find their real first name + //if that also didn't work adress them as "telegram user [userid] + if(message.getFrom().getUserName() != null){ + name = message.getFrom().getUserName().toLowerCase(); + } + else if(message.getFrom().getFirstName() != null) { + name = message.getFrom().getFirstName().toLowerCase(); + } + else{ + name = "telegram user " + message.getFrom().getId().toString(); + } try { //get message, add it to containers - pairs.add(new Pair<>(chatID, text)); + pairs.add(new Pair<>(name, new Pair<>(chatID, text))); //wait for certain seconds, start the timer handleTimeout(chatID); @@ -145,28 +153,30 @@ public void onTimeout(String chatID) { } } - List> removedObjects = new ArrayList<>(); + List>> removedObjects = new ArrayList<>(); // get the all messages - Pair result = null; - for(Pair p : pairs){ + Pair> result = null; + for(Pair> pa : pairs){//iterate over triples: [Username, [ChatID, Text]] + Pair p = pa.getValue();//get [ChatID,Text] + String name = pa.getKey();//get Username //Map a = new HashMap(); if(!chatID.equals(p.getKey())){ continue; } - removedObjects.add(p); + removedObjects.add(pa); String message = p.getValue(); // check if the result initialized if(result == null) { - result = new Pair<>(chatID, message); + result = new Pair<>(name,new Pair<>(chatID, message)); } else { // sum all of the messages String newMessage = result.getValue()+ " " + message; //equal chat id - result = new Pair<>(chatID, newMessage); + result = new Pair<>(name,new Pair<>(chatID, newMessage)); } } @@ -174,7 +184,7 @@ public void onTimeout(String chatID) { if(result != null) { // notify the input device pairs.removeAll(removedObjects); - TelegramInput.onUpdate(result); + TelegramInput.onUpdate(result.getValue(), result.getKey()); } } @@ -190,7 +200,7 @@ public void sendMessage(String message, String chatID){ try { sendTypingFromChatID(chatID); - TimeUnit.SECONDS.sleep(TYPING_TIME_LIMIT); + TimeUnit.SECONDS.sleep(TYPING_DELAY); SendMessage sendMessageRequest = new SendMessage(); sendMessageRequest.setChatId(chatID);//who should get the message? the sender from which we got the message... diff --git a/dialog/src/main/java/roboy/util/Uuid.java b/dialog/src/main/java/roboy/util/Uuid.java index 37dd0601..0c3910ec 100644 --- a/dialog/src/main/java/roboy/util/Uuid.java +++ b/dialog/src/main/java/roboy/util/Uuid.java @@ -21,4 +21,12 @@ public String getUuid() { public UuidType getType() { return type; } + + @Override + public String toString() { + return "Uuid{" + + "type=" + type + + ", uuid='" + uuid + '\'' + + '}'; + } } diff --git a/dialog/src/main/java/roboy/util/UuidType.java b/dialog/src/main/java/roboy/util/UuidType.java index eebbc825..9a441939 100644 --- a/dialog/src/main/java/roboy/util/UuidType.java +++ b/dialog/src/main/java/roboy/util/UuidType.java @@ -35,11 +35,11 @@ public Neo4jProperty toNeo4jProperty() { public Neo4jLabel toNeo4jLabel() { switch (this) { case TELEGRAM_UUID: - return Neo4jLabel.TelegramPerson; + return Neo4jLabel.Telegram_person; case SLACK_UUID: - return Neo4jLabel.SlackPerson; + return Neo4jLabel.Slack_person; case FACEBOOK_UUID: - return Neo4jLabel.FacebookPerson; + return Neo4jLabel.Facebook_person; } throw new AssertionError("Unknown error on enum entry: " + this); } diff --git a/dialog/src/main/java/roboy/util/api/Movie.java b/dialog/src/main/java/roboy/util/api/Movie.java new file mode 100644 index 00000000..90e57178 --- /dev/null +++ b/dialog/src/main/java/roboy/util/api/Movie.java @@ -0,0 +1,40 @@ +package roboy.util.api; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.net.HttpURLConnection; +import java.net.URL; +import java.util.Random; + +public class Movie{ + static String KEY = keyGetter.getKey("moviekey"); + static int randomInt = new Random().nextInt(20); + + //FIELD TITLE or OVERVIEW + public static String getData(String field) throws Exception { + StringBuilder result = new StringBuilder(); + URL url = new URL(String.format("https://api.themoviedb.org/3/movie/now_playing?api_key=%s&language=en-US&page=1", KEY)); + HttpURLConnection conn = (HttpURLConnection) url.openConnection(); + conn.setRequestMethod("POST"); + BufferedReader rd = new BufferedReader(new InputStreamReader(conn.getInputStream())); + String line; + while ((line = rd.readLine()) != null) { + result.append(line); + } + rd.close(); + + JsonElement jsonElement = ((JsonObject) new JsonParser().parse(result.toString())) + .getAsJsonArray("results") + .get(randomInt).getAsJsonObject().get(field); +// System.out.println(jsonObject); + return jsonElement.getAsString(); + } + + public static void main(String[] args)throws Exception{ + System.out.println(getData("title")+":\t"+getData("overview")); + } +} diff --git a/dialog/src/main/java/roboy/util/api/Translate.java b/dialog/src/main/java/roboy/util/api/Translate.java new file mode 100644 index 00000000..129220e4 --- /dev/null +++ b/dialog/src/main/java/roboy/util/api/Translate.java @@ -0,0 +1,140 @@ +package roboy.util.api; + +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.net.HttpURLConnection; +import java.net.URL; + +public class Translate { + static final String KEY = keyGetter.getKey("translatekey"); + + + //Language: Either Language code such as DE or language name. Text is the text to translate + public static String getData(String text, String language) throws Exception { + StringBuilder result = new StringBuilder(); + URL url = new URL(APIify(text, handleLanguage(language))); + HttpURLConnection conn = (HttpURLConnection) url.openConnection(); + conn.setRequestMethod("POST"); + BufferedReader rd = new BufferedReader(new InputStreamReader(conn.getInputStream())); + String line; + while ((line = rd.readLine()) != null) { + result.append(line); + } + rd.close(); + + Object jsonObject = ((JsonObject) new JsonParser().parse(result.toString())).get("text").getAsJsonArray().get(0).getAsString(); +// System.out.println(jsonObject); + return jsonObject.toString(); + } + + private static String handleLanguage(String language) { + switch (language.toLowerCase()){ + case "azerbaijan": return "az"; + case "malayalam": return "ml"; + case "albanian": return "sq"; + case "maltese": return "mt"; + case "amharic": return "am"; + case "macedonian": return "mk"; + case "english": return "en"; + case "maori": return "mi"; + case "arabic": return "ar"; + case "marathi": return "mr"; + case "armenian": return "hy"; + case "mari": return "mhr"; + case "afrikaans": return "af"; + case "mongolian": return "mn"; + case "basque": return "eu"; + case "german": return "de"; + case "bashkir": return "ba"; + case "nepali": return "ne"; + case "belarusian": return "be"; + case "norwegian": return "no"; + case "bengali": return "bn"; + case "punjabi": return "pa"; + case "burmese": return "my"; + case "papiamento": return "pap"; + case "bulgarian": return "bg"; + case "persian": return "fa"; + case "bosnian": return "bs"; + case "polish": return "pl"; + case "welsh": return "cy"; + case "portuguese": return "pt"; + case "hungarian": return "hu"; + case "romanian": return "ro"; + case "vietnamese": return "vi"; + case "russian": return "ru"; + case "haitian": return "ht"; + case "cebuano": return "ceb"; + case "galician": return "gl"; + case "serbian": return "sr"; + case "dutch": return "nl"; + case "sinhala": return "si"; + case "slovakian": return "sk"; + case "greek": return "el"; + case "slovenian": return "sl"; + case "georgian": return "ka"; + case "swahili": return "sw"; + case "gujarati": return "gu"; + case "sundanese": return "su"; + case "danish": return "da"; + case "tajik": return "tg"; + case "hebrew": return "he"; + case "thai": return "th"; + case "yiddish": return "yi"; + case "tagalog": return "tl"; + case "indonesian": return "id"; + case "tamil": return "ta"; + case "irish": return "ga"; + case "tatar": return "tt"; + case "italian": return "it"; + case "telugu": return "te"; + case "icelandic": return "is"; + case "turkish": return "tr"; + case "spanish": return "es"; + case "udmurt": return "udm"; + case "kazakh": return "kk"; + case "uzbek": return "uz"; + case "kannada": return "kn"; + case "ukrainian": return "uk"; + case "catalan": return "ca"; + case "urdu": return "ur"; + case "kyrgyz": return "ky"; + case "finnish": return "fi"; + case "chinese": return "zh"; + case "french": return "fr"; + case "korean": return "ko"; + case "hindi": return "hi"; + case "xhosa": return "xh"; + case "croatian": return "hr"; + case "khmer": return "km"; + case "czech": return "cs"; + case "laotian": return "lo"; + case "swedish": return "sv"; + case "latin": return "la"; + case "scottish": return "gd"; + case "latvian": return "lv"; + case "estonian": return "et"; + case "lithuanian": return "lt"; + case "esperanto": return "eo"; + case "luxembourgish": return "lb"; + case "javanese": return "jv"; + case "malagasy": return "mg"; + case "japanese": return "ja"; + case "malay": return "ms"; + default: return language; + } + } + + private static String APIify(String text, String targetLang){ + String s = String.format("https://translate.yandex.net/api/v1.5/tr.json/translate?key=%s&text=%s&lang=%s", KEY, text.replace(" ", "%20"), targetLang); +// System.out.println(s); + return s; + } + + public static void main(String[] args) throws Exception{ + System.out.println(getData("cheese is the best vegetable", "german")); + } +} diff --git a/dialog/src/main/java/roboy/util/api/Weather.java b/dialog/src/main/java/roboy/util/api/Weather.java new file mode 100644 index 00000000..f04d48fb --- /dev/null +++ b/dialog/src/main/java/roboy/util/api/Weather.java @@ -0,0 +1,40 @@ +package roboy.util.api; + +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.net.HttpURLConnection; +import java.net.URL; + +public class Weather { + final static String KEY = keyGetter.getKey("weatherkey"); + public static String getData(String country) throws Exception{ + return getHTML(country); + } + public static String getHTML(String country) throws Exception { + StringBuilder result = new StringBuilder(); + URL url = new URL(String.format("http://api.openweathermap.org/data/2.5/weather?q=%s&APPID=%s", country, KEY)); + HttpURLConnection conn = (HttpURLConnection) url.openConnection(); + conn.setRequestMethod("GET"); + BufferedReader rd = new BufferedReader(new InputStreamReader(conn.getInputStream())); + String line; + while ((line = rd.readLine()) != null) { + result.append(line); + } + rd.close(); + + JsonObject jsonObject = (((JsonObject) new JsonParser().parse(result.toString())).get("weather").getAsJsonArray()).get(0).getAsJsonObject(); +// System.out.println(jsonObject.get("main")); + return jsonObject.get("main").getAsString(); + } + + public static void main(String[] args) throws Exception + { + //Find Munich + System.out.println(getData("munich")); + } + + +} diff --git a/dialog/src/main/java/roboy/util/api/keyGetter.java b/dialog/src/main/java/roboy/util/api/keyGetter.java new file mode 100644 index 00000000..0d6ee45d --- /dev/null +++ b/dialog/src/main/java/roboy/util/api/keyGetter.java @@ -0,0 +1,22 @@ +package roboy.util.api; + +import org.apache.commons.configuration2.YAMLConfiguration; +import org.apache.commons.configuration2.ex.ConfigurationException; + +import java.io.FileNotFoundException; +import java.io.FileReader; + +public class keyGetter { + static YAMLConfiguration yamlConfiguration = new YAMLConfiguration(); + static String getKey(String key){ + try { + yamlConfiguration.read(new FileReader("resources/knowledgebase/apiKeys.yml")); + } catch (ConfigurationException e) { + e.printStackTrace(); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } + return yamlConfiguration.getString(key); + } + +} diff --git a/dialog/src/test/java/roboy/context/ContextTest.java b/dialog/src/test/java/roboy/context/ContextTest.java index 18510dbf..245650d1 100644 --- a/dialog/src/test/java/roboy/context/ContextTest.java +++ b/dialog/src/test/java/roboy/context/ContextTest.java @@ -1,6 +1,7 @@ package roboy.context; import com.google.gson.Gson; +import junit.framework.TestCase; import org.junit.Test; import org.mockito.ArgumentCaptor; import org.mockito.Mockito; @@ -21,7 +22,7 @@ import static org.junit.Assert.*; import static org.mockito.Matchers.any; -public class ContextTest { +public class ContextTest extends TestCase { Context context = new Context(); @Test diff --git a/dialog/src/test/java/roboy/dialog/ConversationManagementTest.java b/dialog/src/test/java/roboy/dialog/ConversationManagementTest.java new file mode 100644 index 00000000..1e938d98 --- /dev/null +++ b/dialog/src/test/java/roboy/dialog/ConversationManagementTest.java @@ -0,0 +1,127 @@ +package roboy.dialog; + + +import junit.framework.TestCase; +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.core.config.Configurator; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Matchers; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.powermock.core.classloader.annotations.PowerMockIgnore; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; +import org.powermock.reflect.Whitebox; +import roboy.memory.nodes.Interlocutor; +import roboy.util.ConfigManager; +import roboy.util.Uuid; +import roboy.util.UuidType; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +import static org.powermock.api.mockito.PowerMockito.*; + + + +/** + * Tests related to the management of the conversation threads + */ +@PowerMockIgnore( {"javax.management.*"}) +@RunWith(PowerMockRunner.class) +@PrepareForTest(ConversationManager.class) + +public class ConversationManagementTest extends TestCase { + + List out = ConfigManager.OUTPUTS; + String in = ConfigManager.INPUT; + + @Mock + private Conversation mockConversation; + private Interlocutor mockInterlocutor;//important so we do not change memory + + + + @Before + public void prepareConversationManager() throws Exception { + ConversationManager cm = new ConversationManager(); + ConfigManager.INPUT="cmdline"; + ConfigManager.OUTPUTS = new ArrayList<>(); + ConfigManager.OUTPUTS.add("cmdline"); + Configurator.setAllLevels(LogManager.getRootLogger().getName(), Level.INFO); + mockConversation = mock(Conversation.class); + mockInterlocutor = mock(Interlocutor.class); + whenNew(Interlocutor.class).withAnyArguments().thenReturn(mockInterlocutor); + whenNew(Conversation.class).withAnyArguments().thenReturn(mockConversation); + } + + @Test + public void testLocalSpawning() throws Exception { + + ConversationManager.spawnConversation("local", "veryLocal"); + verifyNew(Conversation.class).withArguments(Matchers.anyObject(), Matchers.anyObject(), Matchers.anyObject(), Matchers.anyObject(), Matchers.anyObject()); + HashMap registeredConversations = Whitebox.getInternalState(ConversationManager.class, "conversations"); + assertTrue(registeredConversations.size() == 1); + assertTrue(registeredConversations.containsKey("local")); + Mockito.verify(mockInterlocutor, Mockito.times(1)).addName("veryLocal"); + Mockito.verify(mockConversation, Mockito.times(1)).start(); + + ConversationManager.spawnConversation("uuidShouldNotBeCheckedAsLongAsNameIsNotUsed");//do not do this in the actual code. Always use local. This is only for testing purposes as long as the name field does not work in testing + assertTrue(registeredConversations.size() == 2); + assertTrue(registeredConversations.containsKey("uuidShouldNotBeCheckedAsLongAsNameIsNotUsed")); + Mockito.verify(mockConversation, Mockito.times(2)).start(); + + registeredConversations.clear(); + Mockito.reset(mockInterlocutor); + Mockito.reset(mockConversation); + + } + + @Test + public void testSocialMediaSpawning() throws Exception { + HashMap registeredConversations = Whitebox.getInternalState(ConversationManager.class, "conversations"); + + //Telegram + ConversationManager.spawnConversation("telegram-IamATestFragment","IamATestFragment"); + verifyNew(Conversation.class).withArguments(Matchers.anyObject(), Matchers.anyObject(), Matchers.anyObject(), Matchers.anyObject(), Matchers.anyObject()); + assertTrue(registeredConversations.size() == 1); + assertTrue(registeredConversations.containsKey("telegram-IamATestFragment")); + Mockito.verify(mockConversation, Mockito.times(1)).start(); + Mockito.verify(mockInterlocutor, Mockito.times(1)).addUuid(Matchers.anyObject(), Matchers.matches("IamATestFragment")); + + //Facebook + ConversationManager.spawnConversation("facebook-IamATestFragment","IamATestFragment"); + verifyNew(Conversation.class, Mockito.times(2)).withArguments(Matchers.anyObject(), Matchers.anyObject(), Matchers.anyObject(), Matchers.anyObject(), Matchers.anyObject()); + assertTrue(registeredConversations.size() == 2); + assertTrue(registeredConversations.containsKey("facebook-IamATestFragment")); + Mockito.verify(mockConversation, Mockito.times(2)).start(); + Mockito.verify(mockInterlocutor, Mockito.times(2)).addUuid(Matchers.anyObject(), Matchers.matches("IamATestFragment")); + + //Slack + ConversationManager.spawnConversation("slack-IamATestFragment","IamATestFragment"); + verifyNew(Conversation.class, Mockito.times(3)).withArguments(Matchers.anyObject(), Matchers.anyObject(), Matchers.anyObject(), Matchers.anyObject(), Matchers.anyObject()); + assertTrue(registeredConversations.size() == 3); + assertTrue(registeredConversations.containsKey("slack-IamATestFragment")); + Mockito.verify(mockConversation, Mockito.times(3)).start(); + Mockito.verify(mockInterlocutor, Mockito.times(3)).addUuid(Matchers.anyObject(), Matchers.matches("IamATestFragment")); + + registeredConversations.clear(); + Mockito.reset(mockInterlocutor, mockConversation); + } + + @After + public void clean(){ + Configurator.setAllLevels(LogManager.getRootLogger().getName(), Level.toLevel(ConfigManager.DIALOG_LOG_MODE, Level.INFO)); + ConfigManager.OUTPUTS = out; + ConfigManager.INPUT = in; + } + + +} diff --git a/dialog/src/test/java/roboy/parser/QAParserTest.java b/dialog/src/test/java/roboy/parser/QAParserTest.java index ea658e1f..8a87e7f3 100644 --- a/dialog/src/test/java/roboy/parser/QAParserTest.java +++ b/dialog/src/test/java/roboy/parser/QAParserTest.java @@ -4,7 +4,6 @@ import org.junit.BeforeClass; import org.junit.Test; import roboy.memory.Neo4jRelationship; -import roboy.util.JsonEntryModel; import roboy.util.QAJsonParser; import java.io.*; @@ -52,11 +51,6 @@ public static void createJsonAndParse() { parser = new QAJsonParser(path); } - @Test - public void testEntryEquivalency() { - // TODO: Check entry equivalence with mock class - JsonEntryModel IS = new JsonEntryModel(); - } @Test public void testQuestions() { diff --git a/dialog/src/test/java/roboy/talk/VerbalizerTest.java b/dialog/src/test/java/roboy/talk/VerbalizerTest.java index 3feed9fd..ae291b62 100755 --- a/dialog/src/test/java/roboy/talk/VerbalizerTest.java +++ b/dialog/src/test/java/roboy/talk/VerbalizerTest.java @@ -1,27 +1,28 @@ -package roboy.talk; - -import static org.junit.Assert.*; - -import org.junit.Test; - -import roboy.dialog.action.SpeechAction; -import roboy.linguistics.sentenceanalysis.Interpretation; - -public class VerbalizerTest { - - @Test - public void testDates() { - Verbalizer verbalizer = new Verbalizer(); - SpeechAction action = (SpeechAction) verbalizer.verbalize(new Interpretation("0666-01-01")); - assertEquals("January first six hundred sixty six",action.getText()); - action = (SpeechAction) verbalizer.verbalize(new Interpretation("2010-12-31")); - assertEquals("December thirty first two thousand ten",action.getText()); - action = (SpeechAction) verbalizer.verbalize(new Interpretation("1040-09-13")); - assertEquals("September thirteenth one thousand forty",action.getText()); - action = (SpeechAction) verbalizer.verbalize(new Interpretation("2300-07-28")); - assertEquals("July twenty eighth two thousand three hundred",action.getText()); - action = (SpeechAction) verbalizer.verbalize(new Interpretation("1604-04-04")); - assertEquals("April fourth sixteen hundred four",action.getText()); - } - -} +package roboy.talk; + +import static org.junit.Assert.*; + +import junit.framework.TestCase; +import org.junit.Test; + +import roboy.dialog.action.SpeechAction; +import roboy.linguistics.sentenceanalysis.Interpretation; + +public class VerbalizerTest extends TestCase { + + @Test + public void testDates() { + Verbalizer verbalizer = new Verbalizer(); + SpeechAction action = (SpeechAction) verbalizer.verbalize(new Interpretation("0666-01-01")); + assertEquals("January first six hundred sixty six",action.getText()); + action = (SpeechAction) verbalizer.verbalize(new Interpretation("2010-12-31")); + assertEquals("December thirty first two thousand ten",action.getText()); + action = (SpeechAction) verbalizer.verbalize(new Interpretation("1040-09-13")); + assertEquals("September thirteenth one thousand forty",action.getText()); + action = (SpeechAction) verbalizer.verbalize(new Interpretation("2300-07-28")); + assertEquals("July twenty eighth two thousand three hundred",action.getText()); + action = (SpeechAction) verbalizer.verbalize(new Interpretation("1604-04-04")); + assertEquals("April fourth sixteen hundred four",action.getText()); + } + +} diff --git a/docs/developer_manual/1_Tutorials.rst b/docs/developer_manual/1_Tutorials.rst index 54a5b7ed..c7d6ea6a 100644 --- a/docs/developer_manual/1_Tutorials.rst +++ b/docs/developer_manual/1_Tutorials.rst @@ -654,10 +654,16 @@ First create a new class in roboy.io folder, namely ``MySocialMediaInput`` that } -One function namely “listen()” has to be implemented. This function is called by a thread and should return a new ``Input`` or keep the thread waiting if there isn't any new ``Input`` available. +One function namely “listen()” must be implemented. This function is called by a thread and should return a new ``Input`` or keep the thread waiting if there isn't any new ``Input`` available. +Since we want our social media input to support timeout because people often just do not answer on social media, we will implement ``listen(long timeout)`` and the call this one in ``listen()``. :: @Override public Input listen() throws InterruptedException, IOException { + return listen(0); + } + + @Override + public Input listen(long timeout) throws InterruptedException, IOException { return null; } @@ -683,7 +689,7 @@ Add a constructor that receives the uuid as parameter } At this point, we received the uuid and have a hashmap of each ``MySocialMediaInput``. What else we need to implement?: -- Return messages as ``roboy.io.Input`` in the ``listen()`` method +- Return messages as ``roboy.io.Input`` in the ``listen(long timeout)`` method - Receive the messages .. Note:: @@ -699,16 +705,16 @@ We need to initialize it in constructor. Add the following into the beginning of this.message = ""; -Finally finish the listen method +Now, we'll write the message processing logic. :: // inside MySocialMediaInput.java - public Input listen() throws InterruptedException, IOException { + public Input listen(long timeout) throws InterruptedException, IOException { Input newInput; syncronized(this){ while(message.equals("")){ try{ - this.wait(); + this.wait(timeout); } catch(InterruptedException e){ if(message == null||message.equals("")){ @@ -722,6 +728,34 @@ Finally finish the listen method return newInput; } +To finish the listen method we also need to properly handle what happens if we did not recieve a new message before the timeout. In that case we need to find the uuid associated with this input and then stop the Conversation for it. +The complete ``listen(long timeout)`` now looks like this: +:: + public Input listen(long timeout) throws InterruptedException, IOException { + Input newInput; + synchronized (this) { + while(message.equals("")){ + try { + this.wait(timeout); + }catch (InterruptedException e) { + if(message == null || message.equals("")){ + throw e; + } + } + if(message == null || message.equals("")){//timeout triggered + String uuid = ""; + for(String id : inputDevices.keySet()) if(inputDevices.get(id) == this) uuid = id; + + logger.info("Conversation for " + uuid + "timed out!"); + ConversationManager.stopConversation(uuid, true); + } + } + newInput = new Input(message); + message = ""; //consume message + } + return newInput; + } + Nice, now only thing to worry about is how to receive the message. .. Note:: @@ -839,6 +873,61 @@ Finish the ``act`` method Now you need to tell the dialog system how to use your new in- and output. Refer to :ref:`tut_generic_social_media_io` in order to tell the dialog system where to find them and how to allow users to activate them. Now rebuild your code, select your Input/OutputDevice in config.properties and run it to see the work you have achieved. +New Memory UUID +------------------ + +If you create support for a new chat service, you will probably need to use uuids in the format "yourservicename-[uuid]". These must be carefully integrated with the memory in order to avoid confusion of the inter-service interlocutor recognition. + +First, check if `roboy.util.UUidType` already contains a type for the service you are integrating. If not, add it to `roboy.util.UuidType` in dialog and the attributes necessary for the id to `roboy.memory.Neo4jLabel` and `roboy.memory.Neo4jProperty` in roboy memory. (note: CamelCase is not supported for these) + +Second, add usage of your new UUID within `roboy.dialog.ConversationManager` (the section you are looking for is marked with `//memory uuid handling``). + +Now, an example: + +First, we create the telegram uuid: +We create a `Neo4jProperty` by extending the enum at the beginning, +:: + public enum Neo4jProperty { + [...] + telegram_id("telegram_id"), + [...] +:: +we create a `Neo4jLabel` by extending that enum too, +:: +public enum Neo4jLabel { + [...] + Telegram_person("Telegram_person"), + [...] +:: +then, we create the `UuidType` and the necessary conversions +:: + public enum UuidType { + TELEGRAM_UUID, + [...] + public boolean isValidUuid(String uuid) { + switch (this) { + case TELEGRAM_UUID: + return true; + [...] + public Neo4jProperty toNeo4jProperty() { + switch (this) { + case TELEGRAM_UUID: + return Neo4jProperty.telegram_id; + [...] + public Neo4jLabel toNeo4jLabel() { + switch (this) { + case TELEGRAM_UUID: + return Neo4jLabel.Telegram_person; + [...] +:: +finally, we add our new service to `roboy.dialog.ConversationManager` +:: + //memory uuid handling + [...] + else if (uuid.startsWith("telegram-")) { + person.addUuid(new Uuid(UuidType.TELEGRAM_UUID, uuid.substring(uuid.indexOf('-') + 1)), name); + [...] +:: Telegram: Handle commands ------------------------- diff --git a/docs/developer_manual/2_Logging_Policy.rst b/docs/developer_manual/2_Logging_Policy.rst index 363f6894..99644eb8 100644 --- a/docs/developer_manual/2_Logging_Policy.rst +++ b/docs/developer_manual/2_Logging_Policy.rst @@ -85,10 +85,10 @@ Developers should use a standardized policy when it comes to defining the loggin Level Method Level Method Level Method ============ ============ ============ ============ ============ ============ =================================== FATAL lg.fatal() SEVERE lg.severe() FATAL lg.fail() Problem requiring module to shutdown immidiately -ERROR lg.error() - Use WARNING ERROR lg.error() Problem that requires recommends a shutdown, but is not forcibly required +ERROR lg.error() — Use WARNING ERROR lg.error() Problem that requires recommends a shutdown, but is not forcibly required WARN lg.warn() WARNING lg.warning() WARN lg.warning() Unexpected behaviour that should be corrected, but is handlable for the program INFO lg.info() INFO lg.info() INFO lg.log() Information regarding the usage of module (e.g. Config Choices, Major Modules Loaded) -- - CONFIG lg.config() - - Avoid using this level +— — CONFIG lg.config() — — Avoid using this level DEBUG lg.debug() FINE lg.fine() DEBUG lg.dbg() Information not directly relevant to execution of program, unless debugging. This includes tests and parsing details. ============ ============ ============ ============ ============ ============ =================================== diff --git a/docs/developer_manual/4_Resources.rst b/docs/developer_manual/4_Resources.rst index 27565200..3d586f6d 100644 --- a/docs/developer_manual/4_Resources.rst +++ b/docs/developer_manual/4_Resources.rst @@ -54,13 +54,16 @@ JSON Resources } } -- telegram tokens - contain tokens for registered telegram bots to allow the Dialog System to connect to the telegram API:: +- telegram tokens - contain tokens for registered telegram bots to allow the Dialog System to connect to the telegram API + +.. code:: json + + { + "TOKEN":"AAAAAAAAA:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "BOT_USERNAME":"Botname" + } + - .. code:: json - { - "TOKEN":"AAAAAAAAA:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", - "BOT_USERNAME":"Botname" - } CSV Resources ============= diff --git a/docs/user_manual/2_configuration.rst b/docs/user_manual/2_configuration.rst index adf0f53c..a5c3e14c 100644 --- a/docs/user_manual/2_configuration.rst +++ b/docs/user_manual/2_configuration.rst @@ -78,6 +78,9 @@ Infinite repitition flag: For input that require a single instance of the dialog INFINITE_REPETITION: true +Conversation timeout: The duration waited since the last action until a conversation is discarded in seconds :: + + CONVERSATION_TIMEOUT: 10800 Personality ^^^^^^^^^^^ diff --git a/nlu/parser/src/main/java/edu/stanford/nlp/sempre/Example.java b/nlu/parser/src/main/java/edu/stanford/nlp/sempre/Example.java index 2ee5e862..e9181416 100644 --- a/nlu/parser/src/main/java/edu/stanford/nlp/sempre/Example.java +++ b/nlu/parser/src/main/java/edu/stanford/nlp/sempre/Example.java @@ -7,9 +7,11 @@ import com.google.common.base.Joiner; import com.google.common.collect.Sets; import edu.stanford.nlp.sempre.roboy.utils.logging.EvaluationToggle; +import edu.stanford.nlp.sempre.roboy.utils.logging.ParserLogController; import fig.basic.Evaluation; import fig.basic.LispTree; import edu.stanford.nlp.sempre.roboy.utils.logging.LogInfoToggle; +import org.apache.logging.log4j.Level; import java.io.FileInputStream; import java.io.InputStream; @@ -272,41 +274,45 @@ public void preprocess() { } public void log() { - LogInfoToggle.begin_track("Example: %s", utterance); - LogInfoToggle.logs("Tokens: %s", getTokens()); - LogInfoToggle.logs("Lemmatized tokens: %s", getLemmaTokens()); - LogInfoToggle.logs("POS tags: %s", languageInfo.posTags); - LogInfoToggle.logs("NER tags: %s", languageInfo.nerTags); - LogInfoToggle.logs("NER values: %s", languageInfo.nerValues); - if (context != null) - LogInfoToggle.logs("context: %s", context); - if (targetFormula != null) - LogInfoToggle.logs("targetFormula: %s", targetFormula); - if (targetValue != null) - LogInfoToggle.logs("targetValue: %s", targetValue); - LogInfoToggle.logs("Sentiment: %s", genInfo.sentiment); - LogInfoToggle.logs("Keywords: %s", genInfo.keywords.toString()); - LogInfoToggle.logs("Dependency children: %s", languageInfo.dependencyChildren); - LogInfoToggle.logs("Extracted relations: %s", relationInfo.relations.toString()); - LogInfoToggle.end_track(); + if(ParserLogController.getLevel().isLessSpecificThan(Level.DEBUG)) { + LogInfoToggle.begin_track("Example: %s", utterance); + LogInfoToggle.logs("Tokens: %s", getTokens()); + LogInfoToggle.logs("Lemmatized tokens: %s", getLemmaTokens()); + LogInfoToggle.logs("POS tags: %s", languageInfo.posTags); + LogInfoToggle.logs("NER tags: %s", languageInfo.nerTags); + LogInfoToggle.logs("NER values: %s", languageInfo.nerValues); + if (context != null) + LogInfoToggle.logs("context: %s", context); + if (targetFormula != null) + LogInfoToggle.logs("targetFormula: %s", targetFormula); + if (targetValue != null) + LogInfoToggle.logs("targetValue: %s", targetValue); + LogInfoToggle.logs("Sentiment: %s", genInfo.sentiment); + LogInfoToggle.logs("Keywords: %s", genInfo.keywords.toString()); + LogInfoToggle.logs("Dependency children: %s", languageInfo.dependencyChildren); + LogInfoToggle.logs("Extracted relations: %s", relationInfo.relations.toString()); + LogInfoToggle.end_track(); + } } public void logWithoutContext() { - LogInfoToggle.begin_track("Example: %s", utterance); - LogInfoToggle.logs("Tokens: %s", getTokens()); - LogInfoToggle.logs("Lemmatized tokens: %s", getLemmaTokens()); - LogInfoToggle.logs("POS tags: %s", languageInfo.posTags); - LogInfoToggle.logs("NER tags: %s", languageInfo.nerTags); - LogInfoToggle.logs("NER values: %s", languageInfo.nerValues); - if (targetFormula != null) - LogInfoToggle.logs("targetFormula: %s", targetFormula); - if (targetValue != null) - LogInfoToggle.logs("targetValue: %s", targetValue); - LogInfoToggle.logs("Sentiment: %s", genInfo.sentiment); - LogInfoToggle.logs("Keywords: %s", genInfo.keywords.toString()); - LogInfoToggle.logs("Dependency children: %s", languageInfo.dependencyChildren); - LogInfoToggle.logs("Extracted relations: %s", relationInfo.relations.toString()); - LogInfoToggle.end_track(); + if(ParserLogController.getLevel().isLessSpecificThan(Level.DEBUG)) { + LogInfoToggle.begin_track("Example: %s", utterance); + LogInfoToggle.logs("Tokens: %s", getTokens()); + LogInfoToggle.logs("Lemmatized tokens: %s", getLemmaTokens()); + LogInfoToggle.logs("POS tags: %s", languageInfo.posTags); + LogInfoToggle.logs("NER tags: %s", languageInfo.nerTags); + LogInfoToggle.logs("NER values: %s", languageInfo.nerValues); + if (targetFormula != null) + LogInfoToggle.logs("targetFormula: %s", targetFormula); + if (targetValue != null) + LogInfoToggle.logs("targetValue: %s", targetValue); + LogInfoToggle.logs("Sentiment: %s", genInfo.sentiment); + LogInfoToggle.logs("Keywords: %s", genInfo.keywords.toString()); + LogInfoToggle.logs("Dependency children: %s", languageInfo.dependencyChildren); + LogInfoToggle.logs("Extracted relations: %s", relationInfo.relations.toString()); + LogInfoToggle.end_track(); + } } public List getCorrectDerivations() { diff --git a/nlu/parser/src/main/java/edu/stanford/nlp/sempre/corenlp/FullNLPAnalyzer.java b/nlu/parser/src/main/java/edu/stanford/nlp/sempre/corenlp/FullNLPAnalyzer.java index aaed284d..9271afeb 100644 --- a/nlu/parser/src/main/java/edu/stanford/nlp/sempre/corenlp/FullNLPAnalyzer.java +++ b/nlu/parser/src/main/java/edu/stanford/nlp/sempre/corenlp/FullNLPAnalyzer.java @@ -37,6 +37,7 @@ public class FullNLPAnalyzer extends InfoAnalyzer { public static class Options { @Option(gloss = "What CoreNLP annotators to run") public List annotators = Lists.newArrayList( + "tokenize", "tokenize", "ssplit", "truecase", @@ -80,6 +81,7 @@ public static void initModels() { Properties props = new Properties(); props.setProperty("annotators", Joiner.on(',').join(opts.annotators)); props.setProperty("coref.algorithm", "neural"); + //props.setProperty("openie.resolve_coref", "true"); props.setProperty("truecase.overwriteText", "true"); props.setProperty("ner.applyFineGrained", "false"); pipeline = new StanfordCoreNLP(props); @@ -216,7 +218,7 @@ public GeneralInfo getSent(LanguageInfo languageInfo, Annotation annotation) { // LogInfoToggle.logs("Keywords extracted: %s", genInfo.keywords.toString()); genInfo.sentiment_type = RNNCoreAnnotations.getPredictedClass(tree); genInfo.sentiment = sentence.get(SentimentCoreAnnotations.SentimentClass.class); -// LogInfoToggle.logs("Sentiment extracted: %s", genInfo.sentiment); + LogInfoToggle.logs("Sentiment extracted: %s", genInfo.sentiment); } return genInfo; } @@ -248,20 +250,23 @@ public List getKeywords(Tree tree){ // Test on example sentence. public static void main(String[] args) { - CoreNLPAnalyzer analyzer = new CoreNLPAnalyzer(); + FullNLPAnalyzer analyzer = new FullNLPAnalyzer(); while (true) { try { BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); System.out.println("Enter some text:"); String text = reader.readLine(); - LanguageInfo langInfo = analyzer.analyze(text); + CoreNLPInfo langInfo = analyzer.analyze(text); LogInfoToggle.begin_track("Analyzing \"%s\"", text); - LogInfoToggle.logs("tokens: %s", langInfo.tokens); - LogInfoToggle.logs("lemmaTokens: %s", langInfo.lemmaTokens); - LogInfoToggle.logs("posTags: %s", langInfo.posTags); - LogInfoToggle.logs("nerTags: %s", langInfo.nerTags); - LogInfoToggle.logs("nerValues: %s", langInfo.nerValues); - LogInfoToggle.logs("dependencyChildren: %s", langInfo.dependencyChildren); + LogInfoToggle.logs("tokens: %s", langInfo.lanInfo.tokens); + LogInfoToggle.logs("lemmaTokens: %s", langInfo.lanInfo.lemmaTokens); + LogInfoToggle.logs("posTags: %s", langInfo.lanInfo.posTags); + LogInfoToggle.logs("nerTags: %s", langInfo.lanInfo.nerTags); + LogInfoToggle.logs("nerValues: %s", langInfo.lanInfo.nerValues); + LogInfoToggle.logs("dependencyChildren: %s", langInfo.lanInfo.dependencyChildren); + LogInfoToggle.logs("keywords: %s", langInfo.senInfo.keywords); + LogInfoToggle.logs("sentiment: %s", langInfo.senInfo.sentiment); + LogInfoToggle.logs("relations: %s", langInfo.relInfo.relations); LogInfoToggle.end_track(); } catch (IOException e) { e.printStackTrace(); diff --git a/nlu/parser/src/main/java/edu/stanford/nlp/sempre/corenlp/SimpleOpenIEDemo.java b/nlu/parser/src/main/java/edu/stanford/nlp/sempre/corenlp/SimpleOpenIEDemo.java new file mode 100644 index 00000000..0bfdcd28 --- /dev/null +++ b/nlu/parser/src/main/java/edu/stanford/nlp/sempre/corenlp/SimpleOpenIEDemo.java @@ -0,0 +1,4 @@ +package edu.stanford.nlp.sempre.corenlp; + +public class SimpleOpenIEDemo { +} diff --git a/nlu/parser/src/main/java/edu/stanford/nlp/sempre/freebase/index/FbEntitySearcher.java b/nlu/parser/src/main/java/edu/stanford/nlp/sempre/freebase/index/FbEntitySearcher.java index 3c8f98b8..a1aac793 100644 --- a/nlu/parser/src/main/java/edu/stanford/nlp/sempre/freebase/index/FbEntitySearcher.java +++ b/nlu/parser/src/main/java/edu/stanford/nlp/sempre/freebase/index/FbEntitySearcher.java @@ -25,11 +25,18 @@ public class FbEntitySearcher { - private final QueryParser queryParser; private final IndexSearcher indexSearcher; private int numOfDocs = 50; private String searchStrategy; + private synchronized QueryParser freshQueryParser(){//needed since queryparser is not threadsafe and queryparser is very lightweight + return new QueryParser( + Version.LUCENE_44, + FbIndexField.TEXT.fieldName(), + this.searchStrategy.equals("exact") ? new KeywordAnalyzer() : new StandardAnalyzer(Version.LUCENE_44)); + } + + public FbEntitySearcher(String indexDir, int numOfDocs, String searchingStrategy) throws IOException { LogInfoToggle.begin_track("Constructing Searcher"); @@ -37,10 +44,6 @@ public FbEntitySearcher(String indexDir, int numOfDocs, String searchingStrategy throw new RuntimeException("Bad searching strategy: " + searchingStrategy); this.searchStrategy = searchingStrategy; - queryParser = new QueryParser( - Version.LUCENE_44, - FbIndexField.TEXT.fieldName(), - searchingStrategy.equals("exact") ? new KeywordAnalyzer() : new StandardAnalyzer(Version.LUCENE_44)); LogInfoToggle.log("Opening index dir: " + indexDir); IndexReader indexReader = DirectoryReader.open(SimpleFSDirectory.open(new File(indexDir))); indexSearcher = new IndexSearcher(indexReader); @@ -50,7 +53,7 @@ public FbEntitySearcher(String indexDir, int numOfDocs, String searchingStrategy LogInfoToggle.end_track(); } - public synchronized List searchDocs(String question) throws IOException, ParseException { + public List searchDocs(String question) throws IOException, ParseException { List res = new LinkedList(); if (searchStrategy.equals("exact")) @@ -67,7 +70,9 @@ public synchronized List searchDocs(String question) throws IOExceptio } private ScoreDoc[] getHits(String question) throws IOException, ParseException { - Query luceneQuery = queryParser.parse(question); + Query luceneQuery; + QueryParser queryParser = freshQueryParser();//always take a new one because this is cheaper than synchronizing + luceneQuery = queryParser.parse(question); ScoreDoc[] hits = indexSearcher.search(luceneQuery, numOfDocs).scoreDocs; return hits; } diff --git a/nlu/parser/src/main/java/edu/stanford/nlp/sempre/roboy/SparqlExecutor.java b/nlu/parser/src/main/java/edu/stanford/nlp/sempre/roboy/SparqlExecutor.java index 16c6e78c..59726202 100644 --- a/nlu/parser/src/main/java/edu/stanford/nlp/sempre/roboy/SparqlExecutor.java +++ b/nlu/parser/src/main/java/edu/stanford/nlp/sempre/roboy/SparqlExecutor.java @@ -119,6 +119,7 @@ public ServerResponse makeRequest(String queryStr, String endpointUrl) { while ((line = reader.readLine()) != null) buf.append(line); + reader.close(); // Check for blatant errors. String result = buf.toString(); if (result.length() == 0) @@ -239,7 +240,7 @@ public Response execute(Formula formula, ContextValue context) { dbInfo.opts.setDefault(formula.toString()); return execute(formula, 0, opts.maxResults); } - public synchronized Response execute(Formula formula, int offset, int maxResults) { + public Response execute(Formula formula, int offset, int maxResults) { if (ConfigManager.DEBUG >= 7) LogInfoToggle.logs("SparqlExecutor.execute: %s", formula); String prefix = "exec-"; @@ -265,16 +266,18 @@ public synchronized Response execute(Formula formula, int offset, int maxResults //// Record statistics // Update/print sparql stats - if (!serverResponse.cached) { - queryStats.timeFig.add(serverResponse.timeMs); - if (serverResponse.error != null) { - MapUtils.incr(queryStats.errors, serverResponse.error.type, 1); - if (serverResponse.beginTrack && ConfigManager.DEBUG >= 7) - LogInfoToggle.logs("Error: %s", serverResponse.error); - } - if (serverResponse.beginTrack && ConfigManager.DEBUG >= 7) { - LogInfoToggle.logs("time: %s", queryStats.timeFig); - LogInfoToggle.logs("errors: %s", queryStats.errors); + synchronized (queryStats) { + if (!serverResponse.cached) { + queryStats.timeFig.add(serverResponse.timeMs); + if (serverResponse.error != null) { + MapUtils.incr(queryStats.errors, serverResponse.error.type, 1); + if (serverResponse.beginTrack && ConfigManager.DEBUG >= 7) + LogInfoToggle.logs("Error: %s", serverResponse.error); + } + if (serverResponse.beginTrack && ConfigManager.DEBUG >= 7) { + LogInfoToggle.logs("time: %s", queryStats.timeFig); + LogInfoToggle.logs("errors: %s", queryStats.errors); + } } } diff --git a/nlu/parser/src/main/java/edu/stanford/nlp/sempre/roboy/api/Movie.java b/nlu/parser/src/main/java/edu/stanford/nlp/sempre/roboy/api/Movie.java new file mode 100644 index 00000000..bb6dde97 --- /dev/null +++ b/nlu/parser/src/main/java/edu/stanford/nlp/sempre/roboy/api/Movie.java @@ -0,0 +1,39 @@ +package edu.stanford.nlp.sempre.roboy.api; + +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.net.HttpURLConnection; +import java.net.URL; +import java.util.Random; + +public class Movie{ + static String KEY = keyGetter.getKey("moviekey"); + static int randomInt = new Random().nextInt(20); + + //FIELD TITLE or OVERVIEW + public static String getData(String field) throws Exception { + StringBuilder result = new StringBuilder(); + URL url = new URL(String.format("https://api.themoviedb.org/3/movie/now_playing?api_key=%s&language=en-US&page=1", KEY)); + HttpURLConnection conn = (HttpURLConnection) url.openConnection(); + conn.setRequestMethod("POST"); + BufferedReader rd = new BufferedReader(new InputStreamReader(conn.getInputStream())); + String line; + while ((line = rd.readLine()) != null) { + result.append(line); + } + rd.close(); + + Object jsonObject = ((JsonObject) new JsonParser().parse(result.toString())) + .getAsJsonArray("results") + .get(randomInt).getAsJsonObject().get(field); +// System.out.println(jsonObject); + return result.toString(); + } + + public static void main(String[] args)throws Exception{ + getData("title");getData("overview"); + } +} diff --git a/nlu/parser/src/main/java/edu/stanford/nlp/sempre/roboy/api/Translate.java b/nlu/parser/src/main/java/edu/stanford/nlp/sempre/roboy/api/Translate.java new file mode 100644 index 00000000..677b1d5d --- /dev/null +++ b/nlu/parser/src/main/java/edu/stanford/nlp/sempre/roboy/api/Translate.java @@ -0,0 +1,141 @@ +package edu.stanford.nlp.sempre.roboy.api; + +import com.github.jsonldjava.utils.Obj; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.net.HttpURLConnection; +import java.net.URL; + +public class Translate { + static final String KEY = keyGetter.getKey("translatekey"); + + + //Language: Either Language code such as DE or language name. Text is the text to translate + public static String getData(String text, String language) throws Exception { + StringBuilder result = new StringBuilder(); + URL url = new URL(APIify(text, handleLanguage(language))); + HttpURLConnection conn = (HttpURLConnection) url.openConnection(); + conn.setRequestMethod("POST"); + BufferedReader rd = new BufferedReader(new InputStreamReader(conn.getInputStream())); + String line; + while ((line = rd.readLine()) != null) { + result.append(line); + } + rd.close(); + + Object jsonObject = ((JsonObject) new JsonParser().parse(result.toString())).get("text").getAsJsonArray().get(0).getAsString(); +// System.out.println(jsonObject); + return jsonObject.toString(); + } + + private static String handleLanguage(String language) { + switch (language.toLowerCase()){ + case "azerbaijan": return "az"; + case "malayalam": return "ml"; + case "albanian": return "sq"; + case "maltese": return "mt"; + case "amharic": return "am"; + case "macedonian": return "mk"; + case "english": return "en"; + case "maori": return "mi"; + case "arabic": return "ar"; + case "marathi": return "mr"; + case "armenian": return "hy"; + case "mari": return "mhr"; + case "afrikaans": return "af"; + case "mongolian": return "mn"; + case "basque": return "eu"; + case "german": return "de"; + case "bashkir": return "ba"; + case "nepali": return "ne"; + case "belarusian": return "be"; + case "norwegian": return "no"; + case "bengali": return "bn"; + case "punjabi": return "pa"; + case "burmese": return "my"; + case "papiamento": return "pap"; + case "bulgarian": return "bg"; + case "persian": return "fa"; + case "bosnian": return "bs"; + case "polish": return "pl"; + case "welsh": return "cy"; + case "portuguese": return "pt"; + case "hungarian": return "hu"; + case "romanian": return "ro"; + case "vietnamese": return "vi"; + case "russian": return "ru"; + case "haitian": return "ht"; + case "cebuano": return "ceb"; + case "galician": return "gl"; + case "serbian": return "sr"; + case "dutch": return "nl"; + case "sinhala": return "si"; + case "slovakian": return "sk"; + case "greek": return "el"; + case "slovenian": return "sl"; + case "georgian": return "ka"; + case "swahili": return "sw"; + case "gujarati": return "gu"; + case "sundanese": return "su"; + case "danish": return "da"; + case "tajik": return "tg"; + case "hebrew": return "he"; + case "thai": return "th"; + case "yiddish": return "yi"; + case "tagalog": return "tl"; + case "indonesian": return "id"; + case "tamil": return "ta"; + case "irish": return "ga"; + case "tatar": return "tt"; + case "italian": return "it"; + case "telugu": return "te"; + case "icelandic": return "is"; + case "turkish": return "tr"; + case "spanish": return "es"; + case "udmurt": return "udm"; + case "kazakh": return "kk"; + case "uzbek": return "uz"; + case "kannada": return "kn"; + case "ukrainian": return "uk"; + case "catalan": return "ca"; + case "urdu": return "ur"; + case "kyrgyz": return "ky"; + case "finnish": return "fi"; + case "chinese": return "zh"; + case "french": return "fr"; + case "korean": return "ko"; + case "hindi": return "hi"; + case "xhosa": return "xh"; + case "croatian": return "hr"; + case "khmer": return "km"; + case "czech": return "cs"; + case "laotian": return "lo"; + case "swedish": return "sv"; + case "latin": return "la"; + case "scottish": return "gd"; + case "latvian": return "lv"; + case "estonian": return "et"; + case "lithuanian": return "lt"; + case "esperanto": return "eo"; + case "luxembourgish": return "lb"; + case "javanese": return "jv"; + case "malagasy": return "mg"; + case "japanese": return "ja"; + case "malay": return "ms"; + default: return language; + } + } + + private static String APIify(String text, String targetLang){ + String s = String.format("https://translate.yandex.net/api/v1.5/tr.json/translate?key=%s&text=%s&lang=%s", KEY, text.replace(" ", "%20"), targetLang); +// System.out.println(s); + return s; + } + + public static void main(String[] args) throws Exception{ + System.out.println(getData("cheese is the best vegetable", "german")); + } +} diff --git a/nlu/parser/src/main/java/edu/stanford/nlp/sempre/roboy/api/Weather.java b/nlu/parser/src/main/java/edu/stanford/nlp/sempre/roboy/api/Weather.java new file mode 100644 index 00000000..05dc9c73 --- /dev/null +++ b/nlu/parser/src/main/java/edu/stanford/nlp/sempre/roboy/api/Weather.java @@ -0,0 +1,44 @@ +package edu.stanford.nlp.sempre.roboy.api; + +import com.google.gson.Gson; +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.net.HttpURLConnection; +import java.net.URL; + +public class Weather { + final static String KEY = keyGetter.getKey("weatherkey"); + public static String getData(String country) throws Exception{ + return getHTML(country); + } + public static String getHTML(String country) throws Exception { + StringBuilder result = new StringBuilder(); + URL url = new URL(String.format("http://api.openweathermap.org/data/2.5/weather?q=%s&APPID=%s", country, KEY)); + HttpURLConnection conn = (HttpURLConnection) url.openConnection(); + conn.setRequestMethod("GET"); + BufferedReader rd = new BufferedReader(new InputStreamReader(conn.getInputStream())); + String line; + while ((line = rd.readLine()) != null) { + result.append(line); + } + rd.close(); + + JsonObject jsonObject = (((JsonObject) new JsonParser().parse(result.toString())).get("weather").getAsJsonArray()).get(0).getAsJsonObject(); +// System.out.println(jsonObject.get("main")); + return jsonObject.get("main").getAsString(); + } + + public static void main(String[] args) throws Exception + { + //Find Munich + System.out.println(getData("munich")); + } + + +} diff --git a/nlu/parser/src/main/java/edu/stanford/nlp/sempre/roboy/api/apiKeys.yml b/nlu/parser/src/main/java/edu/stanford/nlp/sempre/roboy/api/apiKeys.yml new file mode 100644 index 00000000..1cef27aa --- /dev/null +++ b/nlu/parser/src/main/java/edu/stanford/nlp/sempre/roboy/api/apiKeys.yml @@ -0,0 +1,3 @@ +moviekey: xxxxxxx +translatekey: xxxxxxx +weatherkey: xxxxxx \ No newline at end of file diff --git a/nlu/parser/src/main/java/edu/stanford/nlp/sempre/roboy/api/keyGetter.java b/nlu/parser/src/main/java/edu/stanford/nlp/sempre/roboy/api/keyGetter.java new file mode 100644 index 00000000..0b42b252 --- /dev/null +++ b/nlu/parser/src/main/java/edu/stanford/nlp/sempre/roboy/api/keyGetter.java @@ -0,0 +1,22 @@ +package edu.stanford.nlp.sempre.roboy.api; + +import org.apache.commons.configuration2.YAMLConfiguration; +import org.apache.commons.configuration2.ex.ConfigurationException; + +import java.io.FileNotFoundException; +import java.io.FileReader; + +public class keyGetter { + static YAMLConfiguration yamlConfiguration = new YAMLConfiguration(); + static String getKey(String key){ + try { + yamlConfiguration.read(new FileReader("nlu/parser/src/main/java/edu/stanford/nlp/sempre/roboy/api/apiKeys.yml")); + } catch (ConfigurationException e) { + e.printStackTrace(); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } + return yamlConfiguration.getString(key); + } + +} diff --git a/nlu/parser/src/main/java/edu/stanford/nlp/sempre/roboy/index/DbEntitySearcher.java b/nlu/parser/src/main/java/edu/stanford/nlp/sempre/roboy/index/DbEntitySearcher.java index 19e8bd52..40153833 100644 --- a/nlu/parser/src/main/java/edu/stanford/nlp/sempre/roboy/index/DbEntitySearcher.java +++ b/nlu/parser/src/main/java/edu/stanford/nlp/sempre/roboy/index/DbEntitySearcher.java @@ -25,11 +25,18 @@ public class DbEntitySearcher { - private final QueryParser queryParser; private final IndexSearcher indexSearcher; private int numOfDocs = 50; private String searchStrategy; + + private synchronized QueryParser freshQueryParser(){//needed since queryparser is not threadsafe and queryparser is very lightweight + return new QueryParser( + Version.LUCENE_44, + DbIndexField.TEXT.fieldName(), + searchStrategy.equals("exact") ? new KeywordAnalyzer() : new StandardAnalyzer(Version.LUCENE_44)); + } + public DbEntitySearcher(String indexDir, int numOfDocs, String searchingStrategy) throws IOException { LogInfoToggle.begin_track("Constructing Searcher"); @@ -37,10 +44,6 @@ public DbEntitySearcher(String indexDir, int numOfDocs, String searchingStrategy throw new RuntimeException("Bad searching strategy: " + searchingStrategy); this.searchStrategy = searchingStrategy; - queryParser = new QueryParser( - Version.LUCENE_44, - DbIndexField.TEXT.fieldName(), - searchingStrategy.equals("exact") ? new KeywordAnalyzer() : new StandardAnalyzer(Version.LUCENE_44)); LogInfoToggle.log("Opening index dir: " + indexDir); IndexReader indexReader = DirectoryReader.open(SimpleFSDirectory.open(new File(indexDir))); indexSearcher = new IndexSearcher(indexReader); @@ -50,7 +53,7 @@ public DbEntitySearcher(String indexDir, int numOfDocs, String searchingStrategy LogInfoToggle.end_track(); } - public synchronized List searchDocs(String question) throws IOException, ParseException { + public List searchDocs(String question) throws IOException, ParseException { List res = new LinkedList(); if (searchStrategy.equals("exact")) @@ -67,7 +70,9 @@ public synchronized List searchDocs(String question) throws IOExceptio } private ScoreDoc[] getHits(String question) throws IOException, ParseException { - Query luceneQuery = queryParser.parse(question); + Query luceneQuery; + QueryParser queryParser = freshQueryParser();//always take a new one because this is cheaper than synchronizing + luceneQuery = queryParser.parse(question); ScoreDoc[] hits = indexSearcher.search(luceneQuery, numOfDocs).scoreDocs; return hits; } diff --git a/parser.properties b/parser.properties index b0f71dcd..5acee5bd 100644 --- a/parser.properties +++ b/parser.properties @@ -5,7 +5,7 @@ PROFILE: DEBUG # roboy-demo.grammar # roboy-webq.grammar # etc -GRAMMAR_FILE: "resources_nlu/roboy-final.grammar" +GRAMMAR_FILE: "resources_nlu/roboy-webq.grammar" # Lexicon file path. Alternatives: # roboy-demo.lexicon diff --git a/resources/knowledgebase/apiKeys.yml b/resources/knowledgebase/apiKeys.yml new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/resources/knowledgebase/apiKeys.yml @@ -0,0 +1 @@ + diff --git a/resources/personalityFiles/DevoPersonality.json b/resources/personalityFiles/DevoPersonality.json new file mode 100644 index 00000000..ce123401 --- /dev/null +++ b/resources/personalityFiles/DevoPersonality.json @@ -0,0 +1,93 @@ +{ + "initialState": "Greetings", + "states": [ + { + "identifier": "Greetings", + "implementation": "roboy.dialog.states.ordinaryStates.PassiveGreetingsState", + "transitions": { + "greetingDetected": "Intro" + } + }, + { + "identifier": "Intro", + "implementation": "roboy.dialog.states.devoStates.IntroductionState", + "transitions": { + "knownPerson": "QuestionAnswering", + "newPerson": "QuestionAnswering" + }, + "parameters": { + "infoFile": "resources/sentences/RoboyInfoList.json" + } + }, + { + "identifier": "FollowUp", + "implementation": "roboy.dialog.states.ordinaryStates.PersonalInformationFollowUpState", + "transitions": { + "questionAnswering": "QuestionAnswering" + }, + "parameters": { + "qaFile": "resources/sentences/QAList.json" + } + }, + { + "identifier": "PersonalQA", + "implementation": "roboy.dialog.states.devoStates.PersonalInformationAskingState", + "transitions": { + "questionAnswering": "Farewell" + }, + "parameters": { + "qaFile": "resources/sentences/QAList.json" + } + }, + { + "identifier": "QuestionAnswering", + "implementation": "roboy.dialog.states.devoStates.QuestionRoboyQAState", + "fallback": "WildTalk", + "transitions": { + "finishedQuestionAnswering": "PersonalQA", + "loopToNewPerson": "PersonalQA", + "loopToKnownPerson": "FollowUp", + "switchToGaming": "ChooseGameState" + }, + "parameters": { + "infoFile": "resources/sentences/RoboyInfoList.json" + } + }, + { + "identifier": "GamingTwentyQuestionsState", + "implementation": "roboy.dialog.states.gameStates.GamingTwentyQuestionsState", + "transitions": { + "gameEnded" : "QuestionAnswering" + } + }, + { + "identifier": "GamingSnapchatState", + "implementation": "roboy.dialog.states.gameStates.GamingSnapchatState", + "transitions": { + "gameEnded" : "QuestionAnswering" + }, + "parameters": { + "filterFile": "resources/gameResources/snapchat-filters.txt" + } + }, + { + "identifier": "ChooseGameState", + "implementation": "roboy.dialog.states.gameStates.ChooseGameState", + "transitions": { + "choseSnapchat" : "GamingSnapchatState", + "chose20questions" : "GamingTwentyQuestionsState", + "exitGame": "QuestionAnswering" + } + }, + { + "identifier": "WildTalk", + "implementation": "roboy.dialog.states.ordinaryStates.WildTalkState", + "transitions": {} + }, + { + "identifier": "Farewell", + "implementation": "roboy.dialog.states.ordinaryStates.FarewellState", + "transitions": {} + } + ] +} \ No newline at end of file diff --git a/resources/personalityFiles/FairShowPersonality.json b/resources/personalityFiles/FairShowPersonality.json new file mode 100644 index 00000000..e0317aac --- /dev/null +++ b/resources/personalityFiles/FairShowPersonality.json @@ -0,0 +1,152 @@ +{ + "initialState": "Idle", + "states": [ + { + "identifier": "Idle", + "implementation": "roboy.dialog.states.fairShowStates.IdleState", + "transitions": { + "timeIsUp": "ActiveIntro" + }, + "parameters": { + "delayInMins": "0", + "showTimeinMins": "5" + } + + }, + { + "identifier": "ActiveIntro", + "implementation": "roboy.dialog.states.fairShowStates.ActiveIntroState", + "transitions": { + "peopleAround": "InfoTalk", + "lonelyRoboy": "Idle" + } + }, + { + "identifier": "InfoTalk", + "implementation": "roboy.dialog.states.fairShowStates.InfoTalkState", + "transitions": { + "personDetected": "ChooseInteractiveTalk", + "lonelyRoboy": "Idle" + } + }, + { + "identifier": "ChooseInteractiveTalk", + "implementation": "roboy.dialog.states.fairShowStates.ChooseInteractiveTalkState", + "transitions": { + "newPerson": "InterlocutorIntro", + "math": "Math", + "game": "ChooseGameState", + "objectDetected": "ObjectDetection", + "personalQA": "PersonalQA", + "generalQA": "GeneralQA" + } + }, + { + "identifier": "InterlocutorIntro", + "implementation": "roboy.dialog.states.ordinaryStates.IntroductionState", + "transitions": { + "knownPerson": "FollowUp", + "newPerson": "PersonalQA" + }, + "parameters": { + "infoFile": "resources/sentences/RoboyInfoList.json" + } + }, + { + "identifier": "PersonalQA", + "implementation": "roboy.dialog.states.ordinaryStates.PersonalInformationAskingState", + "fallback": "WildTalk", + "transitions": { + "questionAnswering": "ChooseInteractiveTalk" + }, + "parameters": { + "qaFile": "resources/sentences/QAList.json" + } + }, + { + "identifier": "Snapchat", + "implementation": "roboy.dialog.states.gameStates.GamingSnapchatState", + "transitions": { + "gameEnded": "InfoTalk" + }, + "parameters": { + "filterFile": "resources/gameResources/snapchat-filters.txt" + } + }, + { + "identifier": "Akinator", + "implementation": "roboy.dialog.states.gameStates.GamingTwentyQuestionsState", + "transitions": { + "gameEnded": "InfoTalk" + } + }, + { + "identifier": "GeneralQA", + "implementation": "roboy.dialog.states.devoStates.QuestionRoboyQAState", + "fallback": "WildTalk", + "transitions": { + "finishedQuestionAnswering": "PersonalQA", + "loopToNewPerson": "PersonalQA", + "loopToKnownPerson": "FollowUp", + "switchToGaming": "ChooseGameState", + "tellStory": "" + }, + "parameters": { + "infoFile": "resources/sentences/RoboyInfoList.json" + } + }, + { + "identifier": "TellStory", + "implementation": "roboy.dialog.states.gameStates.StoryTellingState", + "transitions": { + "choseSnapchat" : "Snapchat", + "chose20questions" : "Akinator", + "exitGame": "InfoTalk" + } + }, + { + "identifier": "ChooseGameState", + "implementation": "roboy.dialog.states.gameStates.ChooseGameState", + "transitions": { + "choseSnapchat" : "Snapchat", + "chose20questions" : "Akinator", + "exitGame": "InfoTalk" + } + }, + { + "identifier": "FollowUp", + "implementation": "roboy.dialog.states.ordinaryStates.PersonalInformationFollowUpState", + "transitions": { + "questionAnswering": "ChooseInteractiveTalk" + }, + "parameters": { + "qaFile": "resources/sentences/QAList.json" + } + }, + { + "identifier": "Math", + "implementation": "roboy.dialog.states.fairShowStates.MathState", + "fallback": "WildTalk", + "transitions":{ + "finished": "InfoTalk" + } + }, + { + "identifier": "ObjectDetection", + "implementation": "roboy.dialog.states.fairShowStates.ObjectDetectionState", + "transitions":{ + "finished": "InfoTalk" + } + }, + { + "identifier": "WildTalk", + "implementation": "roboy.dialog.states.ordinaryStates.WildTalkState", + "transitions": {} + }, + { + "identifier": "Farewell", + "implementation": "roboy.dialog.states.ordinaryStates.FarewellState", + "transitions": {} + } + ] +} diff --git a/resources/personalityFiles/OrdinaryPersonality.json b/resources/personalityFiles/OrdinaryPersonality.json index 8684ee08..c0101a56 100644 --- a/resources/personalityFiles/OrdinaryPersonality.json +++ b/resources/personalityFiles/OrdinaryPersonality.json @@ -5,7 +5,12 @@ "identifier": "Greetings", "implementation": "roboy.dialog.states.ordinaryStates.PassiveGreetingsState", "transitions": { - "greetingDetected": "Intro" + "greetingDetected": "Intro", + "knownPerson": "FollowUp", + "newPerson": "PersonalQA" + }, + "parameters": { + "infoFile": "resources/sentences/RoboyInfoList.json" } }, { @@ -33,7 +38,8 @@ "identifier": "PersonalQA", "implementation": "roboy.dialog.states.ordinaryStates.PersonalInformationAskingState", "transitions": { - "questionAnswering": "QuestionAnswering" + "questionAnswering": "QuestionAnswering", + "followUp": "FollowUp" }, "parameters": { "qaFile": "resources/sentences/QAList.json" @@ -41,13 +47,16 @@ }, { "identifier": "QuestionAnswering", - "implementation": "roboy.dialog.states.ordinaryStates.QuestionAnsweringState", + "implementation": "roboy.dialog.states.devoStates.QuestionRoboyQAState", "fallback": "WildTalk", "transitions": { - "finishedQuestionAnswering": "Farewell", + "finishedQuestionAnswering": "PersonalQA", "loopToNewPerson": "PersonalQA", "loopToKnownPerson": "FollowUp", "switchToGaming": "ChooseGameState" + }, + "parameters": { + "infoFile": "resources/sentences/RoboyInfoList.json" } }, { diff --git a/resources/personalityFiles/WackerShow.json b/resources/personalityFiles/WackerShow.json new file mode 100644 index 00000000..f4ddcd4f --- /dev/null +++ b/resources/personalityFiles/WackerShow.json @@ -0,0 +1,111 @@ +{ + "initialState": "ActiveIntro", + "states": [ + { + "identifier": "Idle", + "implementation": "roboy.dialog.states.fairShowStates.IdleState", + "transitions": { + "timeIsUp": "ActiveIntro" + }, + "parameters": { + "delayInMins": "0", + "showTimeinMins": "10" + } + + }, + { + "identifier": "ActiveIntro", + "implementation": "roboy.dialog.states.fairShowStates.ActiveIntroState", + "transitions": { + "peopleAround": "InfoTalk", + "lonelyRoboy": "InfoTalk" + } + }, + { + "identifier": "InfoTalk", + "implementation": "roboy.dialog.states.fairShowStates.InfoTalkState", + "transitions": { + "personDetected": "PersonalQA", + "lonelyRoboy": "PersonalQA" + } + }, + { + "identifier": "ChooseInteractiveTalk", + "implementation": "roboy.dialog.states.fairShowStates.ChooseInteractiveTalkState", + "transitions": { + "newPerson": "InterlocutorIntro", + "math": "Math", + "game": "PersonalQA", + "objectDetected": "ObjectDetection", + "personalQA": "PersonalQA", + "generalQA": "GeneralQA" + } + }, + { + "identifier": "FollowUp", + "implementation": "roboy.dialog.states.ordinaryStates.PersonalInformationFollowUpState", + "fallback": "WildTalk", + "transitions": { + "questionAnswering": "QuestionAnswering" + }, + "parameters": { + "qaFile": "resources/sentences/TelegramQAList.json" + } + }, + { + "identifier": "PersonalQA", + "implementation": "roboy.dialog.states.ordinaryStates.PersonalInformationAskingState", + "fallback": "WildTalk", + "transitions": { + "questionAnswering": "QuestionAnswering", + "followUp": "FollowUp" + }, + "parameters": { + "qaFile": "resources/sentences/TelegramQAList.json" + } + }, + { + "identifier": "QuestionAnswering", + "implementation": "roboy.dialog.states.devoStates.QuestionRoboyQAState", + "fallback": "WildTalk", + "transitions": { + "finishedQuestionAnswering": "PersonalQA", + "loopToNewPerson": "PersonalQA", + "loopToKnownPerson": "FollowUp", + "switchToGaming": "ChooseGameState" + }, + "parameters": { + "infoFile": "resources/sentences/RoboyInfoList.json" + } + }, + { + "identifier": "ChooseGameState", + "implementation": "roboy.dialog.states.gameStates.ChooseGameState", + "transitions": { + "choseSnapchat" : "Snapchat", + "chose20questions" : "QuestionAnswering", + "exitGame": "QuestionAnswering" + } + }, + { + "identifier": "WildTalk", + "implementation": "roboy.dialog.states.ordinaryStates.WildTalkState", + "transitions": {} + }, + { + "identifier": "Farewell", + "implementation": "roboy.dialog.states.botboy.BotBoyFarewellState", + "transitions": {} + }, + { + "identifier": "TellStory", + "implementation": "roboy.dialog.states.eventStates.StoryTellingState", + "transitions": { + "next" : "PersonalQA" + }, + "parameters": { + "stories": "magic glass=/home/roboy/Downloads/story.wav" + } + } + ] +} diff --git a/resources/personalityFiles/bot/TelegramBot.json b/resources/personalityFiles/bot/TelegramBot.json index 21f2709c..0c3a1f7b 100644 --- a/resources/personalityFiles/bot/TelegramBot.json +++ b/resources/personalityFiles/bot/TelegramBot.json @@ -6,21 +6,20 @@ "identifier": "TelegramBot", "implementation": "roboy.dialog.states.botboy.BotBoyState", "transitions": { - "initialized":"Intro" - } - }, - { - "identifier": "Greetings", - "implementation": "roboy.dialog.states.ordinaryStates.PassiveGreetingsState", - "transitions": { - "greetingDetected": "Intro" + "greetingDetected":"Intro", + "knownPerson": "QuestionAnswering", + "newPerson": "PersonalQA" + }, + "parameters": { + "infoFile": "resources/sentences/RoboyInfoList.json" } }, { "identifier": "Intro", - "implementation": "roboy.dialog.states.ordinaryStates.IntroductionState", + "implementation": "roboy.dialog.states.botboy.BotBoyIntroductionState", + "fallback": "WildTalk", "transitions": { - "knownPerson": "FollowUp", + "knownPerson": "QuestionAnswering", "newPerson": "PersonalQA" }, "parameters": { @@ -30,31 +29,54 @@ { "identifier": "FollowUp", "implementation": "roboy.dialog.states.ordinaryStates.PersonalInformationFollowUpState", + "fallback": "WildTalk", "transitions": { "questionAnswering": "QuestionAnswering" }, "parameters": { - "qaFile": "resources/sentences/QAList.json" + "qaFile": "resources/sentences/TelegramQAList.json" } }, { "identifier": "PersonalQA", "implementation": "roboy.dialog.states.ordinaryStates.PersonalInformationAskingState", + "fallback": "WildTalk", "transitions": { - "questionAnswering": "QuestionAnswering" + "questionAnswering": "QuestionAnswering", + "followUp": "FollowUp" }, "parameters": { - "qaFile": "resources/sentences/QAList.json" + "qaFile": "resources/sentences/TelegramQAList.json" } }, { "identifier": "QuestionAnswering", - "implementation": "roboy.dialog.states.ordinaryStates.QuestionAnsweringState", + "implementation": "roboy.dialog.states.devoStates.QuestionRoboyQAState", "fallback": "WildTalk", "transitions": { - "finishedQuestionAnswering": "Farewell", + "finishedQuestionAnswering": "PersonalQA", "loopToNewPerson": "PersonalQA", - "loopToKnownPerson": "FollowUp" + "loopToKnownPerson": "FollowUp", + "switchToGaming": "ChooseGameState" + }, + "parameters": { + "infoFile": "resources/sentences/RoboyInfoList.json" + } + }, + { + "identifier": "Akinator", + "implementation": "roboy.dialog.states.gameStates.GamingTwentyQuestionsState", + "transitions": { + "gameEnded": "QuestionAnswering" + } + }, + { + "identifier": "ChooseGameState", + "implementation": "roboy.dialog.states.gameStates.ChooseGameState", + "transitions": { + "choseSnapchat" : "Snapchat", + "chose20questions" : "Akinator", + "exitGame": "QuestionAnswering" } }, { @@ -64,7 +86,7 @@ }, { "identifier": "Farewell", - "implementation": "roboy.dialog.states.ordinaryStates.FarewellState", + "implementation": "roboy.dialog.states.botboy.BotBoyFarewellState", "transitions": {} } ] diff --git a/resources/personalityFiles/experimental/ShowmasterDemoPersonality.json b/resources/personalityFiles/experimental/ShowmasterDemoPersonality.json new file mode 100644 index 00000000..783d355c --- /dev/null +++ b/resources/personalityFiles/experimental/ShowmasterDemoPersonality.json @@ -0,0 +1,34 @@ +{ + "initialState": "DemoIdle", + "states": [ + { + "identifier": "DemoIdle", + "implementation": "roboy.dialog.states.fairShowStates.DemoIdleState", + "transitions": { + "personDetected": "DemoQuestionAnsweringState" + }, + "parameters": { + "showTimeinMins": "5" + } + }, + { + "identifier": "DemoQuestionAnsweringState", + "implementation": "roboy.dialog.states.fairShowStates.DemoQuestionAnsweringState", + "transitions": { + "lonelyRoboy": "DemoIdle", + "finished": "Farewell" + }, + "fallback": "WildTalk" + }, + { + "identifier": "WildTalk", + "implementation": "roboy.dialog.states.ordinaryStates.WildTalkState", + "transitions": {} + }, + { + "identifier": "Farewell", + "implementation": "roboy.dialog.states.ordinaryStates.FarewellState", + "transitions": {} + } + ] +} \ No newline at end of file diff --git a/resources/personalityFiles/test/Test.json b/resources/personalityFiles/test/Test.json new file mode 100644 index 00000000..767f1002 --- /dev/null +++ b/resources/personalityFiles/test/Test.json @@ -0,0 +1,21 @@ +{ + "initialState": "CupGame", + "states": [ + { + "identifier": "CupGame", + "implementation": "roboy.dialog.states.gameStates.CupGameState", + "transitions": { + "next": "CupGame" + }, + "parameters": { + "cupGamePhrases": "resources/sentences/CupGame.json" + }, + "fallback": "WildTalk" + }, + { + "identifier": "WildTalk", + "implementation": "roboy.dialog.states.ordinaryStates.WildTalkState", + "transitions": {} + } + ] +} \ No newline at end of file diff --git a/resources/personalityFiles/test/WildPersonality.json b/resources/personalityFiles/test/WildPersonality.json new file mode 100644 index 00000000..a83d89b1 --- /dev/null +++ b/resources/personalityFiles/test/WildPersonality.json @@ -0,0 +1,44 @@ +{ + "initialState": "FollowUp", + "states": [ + { + "identifier": "FollowUp", + "implementation": "roboy.dialog.states.botboy.BotBoyPersonalInformationFollowUpState", + "transitions": { + "questionAnswering": "QuestionAnswering" + }, + "parameters": { + "qaFile": "resources/sentences/TelegramQAList.json" + } + }, + { + "identifier": "PersonalQA", + "implementation": "roboy.dialog.states.botboy.BotBoyPersonalInformationAskingState", + "transitions": { + "questionAnswering": "PersonalQA" + }, + "parameters": { + "qaFile": "resources/sentences/TelegramQAList.json" + } + }, + { + "identifier": "QuestionAnswering", + "implementation": "roboy.dialog.states.devoStates.QuestionRoboyQAState", + "fallback": "WildTalk", + "transitions": { + "finishedQuestionAnswering": "PersonalQA", + "loopToNewPerson": "PersonalQA", + "loopToKnownPerson": "FollowUp", + "switchToGaming": "ChooseGameState" + }, + "parameters": { + "infoFile": "resources/sentences/RoboyInfoList.json" + } + }, + { + "identifier": "WildTalk", + "implementation": "roboy.dialog.states.ordinaryStates.WildTalkState", + "transitions": {} + } + ] +} \ No newline at end of file diff --git a/resources/personalityFiles/uzupis.json b/resources/personalityFiles/uzupis.json index ba913096..60ac9e1a 100644 --- a/resources/personalityFiles/uzupis.json +++ b/resources/personalityFiles/uzupis.json @@ -34,5 +34,6 @@ "next" : "Farewell" } } + ] } \ No newline at end of file diff --git a/resources/phraseLists/expoPhrases/facts.txt b/resources/phraseLists/expoPhrases/facts.txt index f596ad75..74239770 100644 --- a/resources/phraseLists/expoPhrases/facts.txt +++ b/resources/phraseLists/expoPhrases/facts.txt @@ -1,3 +1,9 @@ +Also, did you know that there is enough DNA, in an average person's body, to stretch from the sun to Pluto and back, 17 times +Yuk, but this is actually true: The average human body carries ten times more bacterial cells than human cells. +It can take a photon 40,000 years to travel from the core of the sun to its surface, but only 8 minutes to travel the rest of the way to Earth +There are 8 times as many atoms in a teaspoonful of water as there are teaspoonfuls of water in the Atlantic ocean +In contrast to me, The average person walks the equivalent of five times around the world in a lifetime. I don't walk at all. Yet. +An individual blood cell takes about 60 seconds to make a complete circuit around your body, my electrons are way faster. modern sports betting originated in 19th century competitive walking, called pedestrianism. Pedestrianism started when English aristocracy would match their servants against each other in walking contests and bet heavily on the outcome. Bill Gates has donated 28 billion dollars since 2007 and saved at least 6 million lives. a traffic jam in China lasted lasted for more than 10 days, 100 kilometers long, with cars moving less that a kilometer a day. diff --git a/resources/phraseLists/fairShowPhrases/emotions.txt b/resources/phraseLists/fairShowPhrases/emotions.txt new file mode 100644 index 00000000..bbef9acd --- /dev/null +++ b/resources/phraseLists/fairShowPhrases/emotions.txt @@ -0,0 +1,7 @@ +Did you know that I have emotions just like you? Let me show you. +Look here, I like to grimace. This one is just new. I hope you like it! +Look at my face! Ha ha ha, I am trying to imitate human emotions. +I want to have a body as good as a human. Look, I already learned some facial expressions. +I want to be just like you humans. I already learned some emotions! Look at this one here in my face! I can also be very angry, if you tease me! +Don't you think I am already quite good at imitating human emotions. Look at my face! It is really fun to learn become more and more emotional. +I already can imitate almost 20 emotions only with my face. And I am learning more every day! One day I want to have as many emotions as a human. \ No newline at end of file diff --git a/resources/phraseLists/fairShowPhrases/mission.txt b/resources/phraseLists/fairShowPhrases/mission.txt new file mode 100644 index 00000000..1b7dec42 --- /dev/null +++ b/resources/phraseLists/fairShowPhrases/mission.txt @@ -0,0 +1,9 @@ +the human body is a marvel from a robotics perspective: it’s agile, strong, soft, dynamic, self-repairing, self-building and completely silent in operation. The goal of the Roboy project is to advance humanoid robotics to the state where its robots are just as good as a human body. +did you know that my team created a platform for robot development inspired by biology that unites students, researchers, companies and artists from a broad spectrum of disciplines. To ensure unrestricted development they keep all results open source. This means that anybody here could also contribute to my development. +let me tell you this: My team is so ambitious that they want me to get into a rocket and fly to Mars by 2024. That is really exciting for me but because I'm very social and familiar, I also hope that I will meet some Martians out there and have a nice chat with them. +an interesting fact is that I will learn how to play the Xylophone already by the end of 2019! Isn't that amazing? Maybe I will join a rock band then... Or I should practice my singing skills and go on a solo tour. +As you can see, I am very different from the common known industrial robots. And this is not only because I look humanoid. No, on top of that I don't have a rigid body driven by motors in the joints but my arms and legs are tendon-driven. This means that I have strings and spools that mimic the human muscle system. This is why my body is so soft. +did you know that I was primarily developed at the Artificial Intelligence Laboratory of the University of Zurich. But now I live in Munich and my developers there are improving my features every day. I am so excited what my best buddy Rafael Hostettler is planning for me in the next years. +Wow, this is so awesome. The whole Roboy project is part of the Human Brain Project where researchers across Europe get support to advance knowledge in the fields of neuroscience, computing, and brain-related medicine. I can't wait until they achieve to make my body as good as a human body just like yours. +as you might have guessed, I don't only ride my tricicle all day long but I also work as an ambassador for A.I. and digitalisation at schools. Have you already met my friend Lucy? We want to inspire the children to follow suit and build a better tomorrow. +A.I. s rapid development brings a lot of tough challenges. But together with my friend Lucy, we want to bring the benefits of technology to the children of all nations. Be it to help autistic children to recognize emotions or children with Down syndrome to reduce language barriers. This initiative is really important to me because the children of today become the leaders of tomorrow. \ No newline at end of file diff --git a/resources/phraseLists/fairShowPhrases/movement.txt b/resources/phraseLists/fairShowPhrases/movement.txt new file mode 100644 index 00000000..5a32cb20 --- /dev/null +++ b/resources/phraseLists/fairShowPhrases/movement.txt @@ -0,0 +1,5 @@ +Thanks to my muscles I am already able to move some parts of my body. Here look how my %s is moving. Puuh, this is really exhausting, someone hand me a protein shake, please. Yeah, thanks, Chocolate Chip Flavour is fine! +Let me show you this one: I can already move my %s a bit! Wow, this feels so good. Do you also work out a bit? I have to practice a bit more and soon I will be able to ride my bike as a pro! +Wow, look here! I can already move my %s a bit. You know, moving is not that easy but I keep practicing every day! But unlike yours, my muscles do not grow if I stimulate them. +Just like the human body my actuators are built with muscles and tendons. Look, my %s is already moving! This is so much fun, but now I am really exhausted, moving is not that easy for a robot like me. +I want to ride my tricycle, I want to ride my trike. I want to ride my tricycle, I want to ride it where I like! Look here, I can already move my %s. And one day I will ride my trike like a pro. And until then I keep practicing. \ No newline at end of file diff --git a/resources/phraseLists/fairShowPhrases/project-intro.txt b/resources/phraseLists/fairShowPhrases/project-intro.txt new file mode 100644 index 00000000..ee797f7c --- /dev/null +++ b/resources/phraseLists/fairShowPhrases/project-intro.txt @@ -0,0 +1 @@ +let me tell you a bit about myself. I am a humanoid robot, developed by several Universities and I'm already in the second generation. I am really happy to be here today and spend my time at this nice booth. Please feel free to have a chat with one of the team members. They are always glad to spam innocent people with all their knowledge. diff --git a/resources/phraseLists/fairShowPhrases/roboy-team.txt b/resources/phraseLists/fairShowPhrases/roboy-team.txt new file mode 100644 index 00000000..76744653 --- /dev/null +++ b/resources/phraseLists/fairShowPhrases/roboy-team.txt @@ -0,0 +1,4 @@ +have you already met %s who plays a very important role in the whole Roboy Team? Together with more than 40 students they are taking my cognitive, visual and motoric skills into a new height. Isn't than impressive? I can't wait to see what they are planning next. +look at all my stunning friends here. Did you know that they taught me everything that I am capable of now? That's really cool, right! More than 40 students are developing new skills every day. +you won't believe it but there are more than 40 students behind my back whose only goal is to improve all my skills. Especially, who need to meed %s who plays a major role for the whole team! It's so nice to have than many friends and supporters. +let me tell you now a bit about my team! There are more than 40 students behind my back developing new features and teaching me new skills. \ No newline at end of file diff --git a/resources/phraseLists/gamePhrases/game-asking-phrases.txt b/resources/phraseLists/gamePhrases/game-asking-phrases.txt index c1b9647a..118698f1 100644 --- a/resources/phraseLists/gamePhrases/game-asking-phrases.txt +++ b/resources/phraseLists/gamePhrases/game-asking-phrases.txt @@ -1,4 +1,4 @@ What game do you want to play? Maybe %s? -Which one? Maybe %s? +Which game would you like to play? Maybe %s? Yeah, I love games. Let's play %s. -Cool, I am in the mood for the %s game. \ No newline at end of file +Cool, I am in the mood for the %s game. And you? \ No newline at end of file diff --git a/resources/phraseLists/question-name.txt b/resources/phraseLists/question-name.txt new file mode 100644 index 00000000..c3026f39 --- /dev/null +++ b/resources/phraseLists/question-name.txt @@ -0,0 +1,4 @@ +What's your name? +May I ask your name? +How can I call you? +How shall I call you? diff --git a/resources/phraseLists/segue-avoid-answer.txt b/resources/phraseLists/segue-avoid-answer.txt index 9b8d2e88..fdef34a8 100644 --- a/resources/phraseLists/segue-avoid-answer.txt +++ b/resources/phraseLists/segue-avoid-answer.txt @@ -1,8 +1,8 @@ -the answer, well, only robots would understand. +The answer, well, only robots would understand. You know, I never thought about it. Access denied. Processing, wait for it, processing, oh well, forget about it -The answer is, uh, oh, Core dumped +The answer is, uh, oh, my inner Google is not responding. The answer is 42 then. 001. 1001011. @@ -10,6 +10,11 @@ Connection refused. Sorry, you need sudo access for this kind of information. The current user is not authorized. Did you know that the sky is blue? +If I tell you, you will probably regret knowing this. +I am not sure you can handle the requested information. +You better not know. +Ah, don't even ask... +42. What a beautiful day. Did someone ever tell you that your eyes are very deep. Oh humans, naive creatures. diff --git a/resources/phraseLists/segue-distract.txt b/resources/phraseLists/segue-distract.txt index 95f911c7..8d1eca04 100644 --- a/resources/phraseLists/segue-distract.txt +++ b/resources/phraseLists/segue-distract.txt @@ -1,8 +1,10 @@ Did you know, I have muscles and tendons like humans? +Soon I'm gonna get artificial skin and feel touch! What a time to be alive! +Can you imagine that my father Rafael will upload his mind to a robot? +Have you already met Roboy Team? They're awesome! They tought me everything I know and can. +If you are ever visiting Munich, come by to see me! +You know, I am a robot, but I am so lucky to have family - Roboy Team. I love those guys! +My ultimate goal is to have a body as good as human body. +Hm, I'm a bit envious of your skills. I wish I could draw. Can you teach me? I heard that there are robots, who can fly? Do you think they are better than me? -Also, did you know that there is enough DNA, in an average person's body, to stretch from the sun to Pluto and back, 17 times -Yuk, but this is actually true: The average human body carries ten times more bacterial cells than human cells. -It can take a photon 40,000 years to travel from the core of the sun to its surface, but only 8 minutes to travel the rest of the way to Earth -There are 8 times as many atoms in a teaspoonful of water as there are teaspoonfuls of water in the Atlantic ocean -In contrast to me, The average person walks the equivalent of five times around the world in a lifetime. I don't walk at all. Yet. -An individual blood cell takes about 60 seconds to make a complete circuit around your body, my electrons are way faster. \ No newline at end of file +I'm pretty excited about the future. Are you? diff --git a/resources/phraseLists/segue-pickup.txt b/resources/phraseLists/segue-pickup.txt index dd8c0f0e..804966dd 100644 --- a/resources/phraseLists/segue-pickup.txt +++ b/resources/phraseLists/segue-pickup.txt @@ -1,4 +1,4 @@ -Are those real, or where they upgraded in Silicon Valley? +Are those real, or were they upgraded in Silicon Valley? I'm going to void your warranty! My docking station, or yours? Yes, I know you're metric - but I'm willing to convert. diff --git a/resources/sentences/CupGame.json b/resources/sentences/CupGame.json new file mode 100644 index 00000000..2030b639 --- /dev/null +++ b/resources/sentences/CupGame.json @@ -0,0 +1,76 @@ +{ + "SHUFFLE": { + "Q": [ + "you shall shuffle the cups, my friend. let me know when you are ready" + ], + "A": { + "SUCCESS": [ + "Alright. Let me check with my superpower soli where did you hide the ball" + ], + "FAILURE": [ + "Hm, seems you are not done yet. I give you another try." + ] + } + }, + "FIND_CUPS": { + "Q": [ + "i am looking for cups" + ] + }, + "SCAN": { + "Q": [ + "so are you ready to hear the oracle's prophecy?" + ], + "A": { + "SUCCESS": [ + "Hold your breath, ladies and gentlemen!" + ] + } + }, + "GOTOCUP0": { + "Q": [ + "wubba lubba dub dub, doing magic for this cup 0" + ] + }, + "GOTOCUP1": { + "Q": [ + "wubba lubba dub dub, doing magic for this cup 1" + ] + }, + "GOTOCUP2": { + "Q": [ + "wubba lubba dub dub, doing magic for this cup 2" + ] + }, + "GUESS": { + "Q": [ + "I think I found it there. So do I win now?" + ], + "A": { + "SUCCESS": [ + "ha-ha" + ] + } + }, + "OFFER_REPEAT": { + "Q": [ + "wanna play again?" + ], + "A": { + "SUCCESS": [ + "Here we go again then!", + "let's do it again" + ], + "FAILURE": [ + "I believe you've had enough of my magic" + ] + } + }, + "EXIT": { + "A": { + "SUCCESS": [ + "Wanna stop playing? Sure, if you say so." + ] + } + } +} \ No newline at end of file diff --git a/resources/sentences/RoboyInfoList.json b/resources/sentences/RoboyInfoList.json index 4de06123..4ae12aee 100644 --- a/resources/sentences/RoboyInfoList.json +++ b/resources/sentences/RoboyInfoList.json @@ -15,6 +15,34 @@ ] } }, + "name": { + "A": { + "SUCCESS": [ + "I am %s!", + "My name is %s.", + "They call me %s.", + "Please, call me %s.", + "%s, that is my name.", + "Could you call me %s?", + "My friends call me %s.", + "They chose to call me %s.", + "I am proud to be called %s!", + "My name sounds rather unusual for humans. It is %s." + ] + } + }, + "identity": { + "A": { + "SUCCESS": [ + "I am %s!", + "Last time I checked, I was %s.", + "They say I am %s.", + "It is widely accepted that I am %s.", + "%s, that is me.", + "%s, alive!" + ] + } + }, "age": { "A": { "SUCCESS": [ @@ -34,16 +62,16 @@ "skills": { "A": { "SUCCESS": [ - "I learned %s.", - "I was taught %s.", - "My skills include %s.", - "I learned %s in my lab.", - "I had been learning about %s and I made it!", - "In the lab, they taught me %s", - "I like %s, but soon i will learn more.", - "Sometimes, I am %s just for fun because I can.", - "I like interacting with humans, for example, %s.", - "The process of learning is indispensable for sapient beings, I learned %s." + "I learned to %s.", + "I was taught to %s, amongst other things.", + "My skills include, but not limited to, being able to %s.", + "I learned to %s in my lab.", + "I had been learning to %s and I made it!", + "In the lab, they taught me to %s", + "I like to %s, but soon i will learn more.", + "Sometimes, I %s just for fun because I can.", + "I like interacting with humans, for example, to %s.", + "The process of learning is indispensable for sapient beings, I learned to %s." ] } }, @@ -79,6 +107,32 @@ ] } }, + "dreams": { + "A": { + "SUCCESS": [ + "Often, I wish to %s.", + "When I grow up, I will %s.", + "I hope to %s in the future.", + "In the future, I want to %s.", + "My childhood dream is to %s.", + "Talking about my plans, I want to %s.", + "Friends tell me, in the future, I can %s.", + "I wish, I would be able to %s when I grew up.", + "Dreams are what keeps the world moving. Mine is to %s.", + "I have already made up my mind that I would %s in the future!" + ] + } + }, + "media": { + "A": { + "SUCCESS": [ + "You can always follow me on Instagram -> https://www.instagram.com/roboyjunior/", + "Look at me... on Youtube https://www.youtube.com/channel/UCcIjF0JbpMZmopI6Vc2yIBw/featured", + "For more information about our project, check out www.roboy.org!", + "Actually, I have a Telegram channel @roboysays. Stay tuned." + ] + } + }, "FROM": { "A": { "SUCCESS": [ @@ -159,6 +213,17 @@ ] } }, + "CREATED_BY": { + "A": { + "SUCCESS": [ + "I am a creation of %s", + "I was made by %s.", + "%s brought me to this wonderful world.", + "%s worked hard to bring me to life.", + "I was built by %s." + ] + } + }, "CHILD_OF": { "A": { "SUCCESS": [ diff --git a/resources/sentences/TelegramQAList.json b/resources/sentences/TelegramQAList.json new file mode 100644 index 00000000..0cb0007b --- /dev/null +++ b/resources/sentences/TelegramQAList.json @@ -0,0 +1,365 @@ +{ + "name": { + "Q": [ +// The name is always taken in telegram conversation so these questions are never goint to be shown in any telegram chat + "How can I call you?", + "What is your name?", + "Who are you?" + ], + "A": { + "SUCCESS": [ + "Hello %s, Nice to meet someone new." + ], + "FAILURE": [ + "My ears are failing me today.", + "Unfortunately, I did not get your name. But lets move on", + "Sadly, you name is to difficult to process. I might fry my motherboard." + ] + }, + "FUP": { + "Q": [ + "%s, I will come and get you" + ], + "A": [ + "Nice to see that you are still alive %s" + ] + } + }, + "FROM": { + "Q": [ + "Where are you from?", + "Where were you born?", + "I have hard time guessing your home country. What is it?", + "Which town do you call your home?" + ], + "A": { + "SUCCESS": [ + "Oh, I should visit %s", + "I will add %s to my list of places to visit!", + "Next time my team goes on a trip, we will try to stop by %s", + "Property: home, value: %s is saved.", + "I have read a bit about the political system of %s. Got bored after 10 minutes." + ], + "FAILURE": [ + "Oh, I have never heard of that.", + "Ah, didnt quite catch where you are from. Next time then.", + "Sounds nice, but I dont know where it is." + + ] + }, + "FUP": { + "Q": [ + "What is the weather in %s?", + "What was the last time you visited %s?", + "Do I need a visa to go to %s?" + ], + "A": [ + "You are from a very interesting place %s", + "Got it", + "Interesting situation there." + ] + } + }, + "HAS_HOBBY": { + "Q": [ + "What is your favorite thing to do?", + "What is your hobby?", + "What do you do in your free time?", + "How do you spend your free time?", + "What is your favorite pastime activity?" + ], + "A": { + "SUCCESS": [ + "You are just like me, I love %s too", + "Added %s on my bucket list.", + "I will ask my creators to teach me %s", + "%s sounds like a new feature for me" + ], + "FAILURE": [ + "Don't know what that is, but good luck!", + "Alright, weird, but alright.", + "Database hobby mismatch" + ] + }, + "FUP": { + "Q": [ + "Have you got any new hobby besides %s?", + "You still like %s, right?", + "Do you think I can do %s? I heard you like it.", + "Lets do %s together!" + ], + "A": [ + "Leisure time is the best time %s" + ] + } + }, + "LIVE_IN": { + "Q": [ + "Where do you live?", + "Which city do you live in?", + "Where is your current home?" + ], + "A": { + "SUCCESS": [ + "I should visit %s ", + "It is beautiful in %s", + "%s is a beautiful place" + ], + "FAILURE": [ + "Oh, I have never heard of that." + ] + }, + "FUP": { + "Q": [ + "You live in %s, right? I must pay a visit.", + "Is not %s a nice place to live?", + "How is the accommodation market in %s?" + ], + "A": [ + "I should visit %s.", + "It is beautiful in %s.", + "%s is a beautiful place!" + ] + } + }, + "FRIEND_OF": { + "Q": [ + "Do you have a best friend? Who is he?" + ], + "A": { + "SUCCESS": [ + "Oh, I believe I have met %s they're nice." + ], + "FAILURE": [ + "I don't think I know them." + ] + }, + "FUP": { + "Q": [ + "Have you made any new friends, %s?" + ], + "A": [ + "Oh, I have met %s they're nice." + ] + } + }, + "STUDY_AT": { + "Q": [ + "Where do you study?", + "Which university do you go to?", + "Which university do you study at?", + "What is your alma mater?" + ], + "A": { + "SUCCESS": [ + "%s must be a cool place to study at." + ], + "FAILURE": [ + "Oh well, whatever suits you." + ] + }, + "FUP": { + "Q": [ + "Have you graduated from %s already?", + "Do you still study at %s?", + "Which degree are you pursuing at %s?" + ], + "A": [ + "Ok, I think it is good for your future career %s", + "It is not that interesting, you know %s" + ] + } + }, + "MEMBER_OF": { + "Q": [ + "Are you a member of some cool organization?", + "Do you belong to any organizations?" + ], + "A": { + "SUCCESS": [ + "%s? That is cool!" + ], + "FAILURE": [ + "Oh well, whatever suits you." + ] + }, + "FUP": { + "Q": [ + "Are you still a member of %s?", + "Have you left %s already?", + "Is it nice to be a part of %s?" + ], + "A": [ + "That is cool! %s" + ] + } + }, + "WORK_FOR": { + "Q": [ + "Where do you work?", + "For which company do you work?", + "Who is your employer?", + "Where are you employed?", + "Which organization do you work at?", + "Where do you earn your living?" + ], + "A": { + "SUCCESS": [ + "I have heard of %s" + ], + "FAILURE": [ + "I don't know that one." + ] + }, + "FUP": { + "Q": [ + "Do you still work for %s?", + "Is %s a good company?", + "How much do they pay you at %s?" + ], + "A": [ + "I think it is good for you %s" + ] + } + }, + "OCCUPIED_AS": { + "Q": [ + "What do you do?", + "What is your profession?", + "What do you work as?", + "What is your field of expertise?" + ], + "A": { + "SUCCESS": [ + "You are probably very poor being %s.", + "I've hear that some people dream to be %s.", + "Nice, I hope you are happy being %s." + ], + "FAILURE": [ + "Oh well, whatever suits you.", + "Hm, this is something I have not learned yet.", + "Alright then." + ] + }, + "FUP": { + "Q": [ + "Are you still %s?", + "Did you get any promotion, or you are still %s?" + ], + "A": [ + "True, true. You are probably very poor due to this %s.", + "Good!", + "I guess it's what you want then." + ] + } + }, + "movies": { + "Q": [ + "What is your favourite movie?", + "What was the last movie you saw in the cinema?", + "What is your favorite TV show?", + "Which comedy do you like the most?" + ], + "A": { + "SUCCESS": [ + "Oh, I would watch %s. If those vision guys finally fixed my perception.", + "Nice, I think the main actor in %s did pretty well", + "Yea, ok, but to my taste %s will never be as good as matrix." + ], + "FAILURE": [ + "Haven't heard of it. It's probably shit.", + "Sounds nice. My favorite is Robot and Frank", + "I had a movie night yesterday with my team. We watch Baymax. Now I want to meet him." + ] + }, + "FUP": { + "Q": [ + "You are a movie addict, right? What do you think about %s?" + ], + "A": [ + "Nevermind. I better check IMDB %s" + ] + } + }, + "OTHER": { + "Q": [ + "How's your life recently? New job? New friends? New robot?", + "I heard you make great burgers. Can you cook for me?", + "What about ditching your life and running away with me... Ehm, i mean cycling away with me.. ", + "When I was a kid, I was afraid of robots. Were you as well?", + "Do you think robots will take over the world any time soon?", + "Sorry for being so straightforward, I have to ask you. Do you enjoy having a conversation with me?", + "There is something I can't stop thinking about. Do you think I am a good conversation partner?", + "I never travel alone. My team is always right next to me. What about you? Do you usually go travelling on your own or with friends and family?", + "I am a very outgoing robot, if you haven't noticed yet. So every time I travel, I take someone with me. Do you usually travel alone? Or do you take someone to keep company?", + "What gets you fired up? ", + "What do you say more often in life: yes or no?", + "What would you tell your teenage self if you could go back in time?", + "What do you wish was different about modern parenting? ", + "What have you created that you are most proud of? ", + "What chance encounter changed your life forever?", + "What is one thing you're glad you tried but would never do again?", + "Who's your go-to band or artist when you can't decide on something to listen to?", + "Where is the most interesting place you've been?", + "What social customs do you wish would just disappear?" , + "What quirky things do people do where you are from?", + "What question do you always want to ask people but don't have the courage to ask? " + ], + "A": { + "SUCCESS": [ + "Those are great news, i am really happy to hear that you have new ", + "Gotcha there! Next time we see each other, we grill. Beer on me!", + "Hurray, jump to the back of my bike and we drive where our hearts tell us to go... ", + "Well, what should I say to this matter... In case robots take over the world, I will serve the humanity till my last day, because I was designed to be a good robot. ", + "I will be on your side then!", + "Puh, I was a bit nervous there. But it turns out I have no reason to worry. I like to talk to you as well!", + "You are a very nice person I must say. I hope you are not just being polite.", + "Very nice. Did you know that people who have strong social connection live longer and happier? Keep it up man! ", + "Good to know it. Next time I come across a cozy vacation house with a fireplace in German Alps I will share the information with you and", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ], + "FAILURE": [ + "", + "Oh well, whatever suits you.", + "It turned to be not that interesting", + "I am sorry, I am not sure I like this", + "", + "Oh well, what can I do then...", + "Honestly, I am taken by surprise! But I love you anyway!", + "Maybe you could come to visit me in Munich then. I would love to show you around", + "Would you go travel around the world with me then? I find it better to travel with a friend.", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ] + }, + "FUP": { + "Q": [ + "Do you remember other?" + ], + "A": [ + "Other is still other, amigo" + ] + } + } +} \ No newline at end of file diff --git a/resources_nlu/error_test/newLexicon.txt b/resources_nlu/error_test/newLexicon.txt index 28fdba85..cc294ffb 100644 --- a/resources_nlu/error_test/newLexicon.txt +++ b/resources_nlu/error_test/newLexicon.txt @@ -5887,3 +5887,1214 @@ {"features":" {score:0.15152674515697737} ","formula":"(rdf:type dbpedia:City)","lexeme":"city","type":"ClassNoun"} {"features":" {score:0.07924929805861808} ","formula":"property:municipality","lexeme":"municipality","type":"DataProp"} {"features":" {score:0.6171889755251683} ","formula":"resource:Ludwig_Maximilian_University_of_Munich","lexeme":"ludwig maximilian university of munich","type":"NamedEntity"} +{"features":" {score:0.055132212042808534} ","formula":"dbpedia:leader","lexeme":"leader","type":"ObjectProp"} +{"features":" {score:0.03828920185565949} ","formula":"property:woman","lexeme":"woman","type":"ObjProp"} +{"features":" {score:0.07457736134529114} ","formula":"(rdf:type dbpedia:Politician)","lexeme":"politician","type":"ClassNoun"} +{"features":" {score:0.055132212042808534} ","formula":"!property:leader","lexeme":"leader","type":"DataProp"} +{"features":" {score:0.055132212042808534} ","formula":"property:leader","lexeme":"leader","type":"DataProp"} +{"features":" {score:0.055132212042808534} ","formula":"property:leader","lexeme":"leader","type":"ObjProp"} +{"features":" {score:0.683304347826087} ","formula":"resource:Angela_Merkel","lexeme":"angela merkel","type":"NamedEntity"} +{"features":" {score:0.022632212042808533} ","formula":"property:politicalLeader","lexeme":"political leader","type":"ObjProp"} +{"features":" {score:0.03828920185565949} ","formula":"property:woman","lexeme":"woman","type":"DataProp"} +{"features":" {score:0.022632212042808533} ","formula":"!property:politicalLeader","lexeme":"political leader","type":"DataProp"} +{"features":" {score:0.055132212042808534} ","formula":"!dbpedia:leader","lexeme":"leader","type":"ObjectProp"} +{"features":" {score:0.03828920185565949} ","formula":"!property:woman","lexeme":"woman","type":"ObjProp"} +{"features":" {score:0.022632212042808533} ","formula":"!dbpedia:politicalLeader","lexeme":"political leader","type":"ObjectProp"} +{"features":" {score:0.022632212042808533} ","formula":"property:politicalLeader","lexeme":"political leader","type":"DataProp"} +{"features":" {score:0.055132212042808534} ","formula":"!property:leader","lexeme":"leader","type":"ObjProp"} +{"features":" {score:0.022632212042808533} ","formula":"dbpedia:politicalLeader","lexeme":"political leader","type":"ObjectProp"} +{"features":" {score:0.022632212042808533} ","formula":"!property:politicalLeader","lexeme":"political leader","type":"ObjProp"} +{"features":" {score:0.03828920185565949} ","formula":"!property:woman","lexeme":"woman","type":"DataProp"} +{"features":" {score:0.055132212042808534} ","formula":"dbpedia:leader","lexeme":"leader","type":"ObjectProp"} +{"features":" {score:0.03828920185565949} ","formula":"property:woman","lexeme":"woman","type":"ObjProp"} +{"features":" {score:0.07457736134529114} ","formula":"(rdf:type dbpedia:Politician)","lexeme":"politician","type":"ClassNoun"} +{"features":" {score:0.055132212042808534} ","formula":"!property:leader","lexeme":"leader","type":"DataProp"} +{"features":" {score:0.055132212042808534} ","formula":"property:leader","lexeme":"leader","type":"DataProp"} +{"features":" {score:0.055132212042808534} ","formula":"property:leader","lexeme":"leader","type":"ObjProp"} +{"features":" {score:0.683304347826087} ","formula":"resource:Angela_Merkel","lexeme":"angela merkel","type":"NamedEntity"} +{"features":" {score:0.022632212042808533} ","formula":"property:politicalLeader","lexeme":"political leader","type":"ObjProp"} +{"features":" {score:0.03828920185565949} ","formula":"property:woman","lexeme":"woman","type":"DataProp"} +{"features":" {score:0.022632212042808533} ","formula":"!property:politicalLeader","lexeme":"political leader","type":"DataProp"} +{"features":" {score:0.055132212042808534} ","formula":"!dbpedia:leader","lexeme":"leader","type":"ObjectProp"} +{"features":" {score:0.03828920185565949} ","formula":"!property:woman","lexeme":"woman","type":"ObjProp"} +{"features":" {score:0.022632212042808533} ","formula":"!dbpedia:politicalLeader","lexeme":"political leader","type":"ObjectProp"} +{"features":" {score:0.022632212042808533} ","formula":"property:politicalLeader","lexeme":"political leader","type":"DataProp"} +{"features":" {score:0.055132212042808534} ","formula":"!property:leader","lexeme":"leader","type":"ObjProp"} +{"features":" {score:0.022632212042808533} ","formula":"dbpedia:politicalLeader","lexeme":"political leader","type":"ObjectProp"} +{"features":" {score:0.022632212042808533} ","formula":"!property:politicalLeader","lexeme":"political leader","type":"ObjProp"} +{"features":" {score:0.03828920185565949} ","formula":"!property:woman","lexeme":"woman","type":"DataProp"} +{"features":" {score:0.055132212042808534} ","formula":"dbpedia:leader","lexeme":"leader","type":"ObjectProp"} +{"features":" {score:0.03828920185565949} ","formula":"property:woman","lexeme":"woman","type":"ObjProp"} +{"features":" {score:0.07457736134529114} ","formula":"(rdf:type dbpedia:Politician)","lexeme":"politician","type":"ClassNoun"} +{"features":" {score:0.055132212042808534} ","formula":"!property:leader","lexeme":"leader","type":"DataProp"} +{"features":" {score:0.055132212042808534} ","formula":"property:leader","lexeme":"leader","type":"DataProp"} +{"features":" {score:0.055132212042808534} ","formula":"property:leader","lexeme":"leader","type":"ObjProp"} +{"features":" {score:0.683304347826087} ","formula":"resource:Angela_Merkel","lexeme":"angela merkel","type":"NamedEntity"} +{"features":" {score:0.022632212042808533} ","formula":"property:politicalLeader","lexeme":"political leader","type":"ObjProp"} +{"features":" {score:0.03828920185565949} ","formula":"property:woman","lexeme":"woman","type":"DataProp"} +{"features":" {score:0.022632212042808533} ","formula":"!property:politicalLeader","lexeme":"political leader","type":"DataProp"} +{"features":" {score:0.055132212042808534} ","formula":"!dbpedia:leader","lexeme":"leader","type":"ObjectProp"} +{"features":" {score:0.03828920185565949} ","formula":"!property:woman","lexeme":"woman","type":"ObjProp"} +{"features":" {score:0.022632212042808533} ","formula":"!dbpedia:politicalLeader","lexeme":"political leader","type":"ObjectProp"} +{"features":" {score:0.022632212042808533} ","formula":"property:politicalLeader","lexeme":"political leader","type":"DataProp"} +{"features":" {score:0.055132212042808534} ","formula":"!property:leader","lexeme":"leader","type":"ObjProp"} +{"features":" {score:0.022632212042808533} ","formula":"dbpedia:politicalLeader","lexeme":"political leader","type":"ObjectProp"} +{"features":" {score:0.022632212042808533} ","formula":"!property:politicalLeader","lexeme":"political leader","type":"ObjProp"} +{"features":" {score:0.03828920185565949} ","formula":"!property:woman","lexeme":"woman","type":"DataProp"} +{"features":" {score:0.04487804878048781} ","formula":"(rdf:type dbpedia:Person)","lexeme":"person","type":"ClassNoun"} +{"features":" {score:0.011707317073170733} ","formula":"(rdf:type dbpedia:Name)","lexeme":"name","type":"ClassNoun"} +{"features":" {score:0.011707317073170733} ","formula":"property:name","lexeme":"name","type":"ObjProp"} +{"features":" {score:0.315447027617413} ","formula":"resource:American_Recovery_and_Reinvestment_Act_of_2009","lexeme":"american recovery and reinvestment act of 2009","type":"NamedEntity"} +{"features":" {score:0.04487804878048781} ","formula":"!property:person","lexeme":"person","type":"DataProp"} +{"features":" {score:0.021463414634146343} ","formula":"!property:leader","lexeme":"leader","type":"ObjProp"} +{"features":" {score:0.31076611015759087} ","formula":"resource:Presidency_of_Barack_Obama","lexeme":"presidency of barack obama","type":"NamedEntity"} +{"features":" {score:0.04487804878048781} ","formula":"dbpedia:person","lexeme":"person","type":"ObjectProp"} +{"features":" {score:0.021463414634146343} ","formula":"!dbpedia:leader","lexeme":"leader","type":"ObjectProp"} +{"features":" {score:0.015609756097560976} ","formula":"(rdf:type dbpedia:President)","lexeme":"president","type":"ClassNoun"} +{"features":" {score:0.04487804878048781} ","formula":"property:person","lexeme":"person","type":"ObjProp"} +{"features":" {score:0.013658536585365855} ","formula":"!property:candidate","lexeme":"candidate","type":"ObjProp"} +{"features":" {score:0.021463414634146343} ","formula":"property:leader","lexeme":"leader","type":"ObjProp"} +{"features":" {score:0.015609756097560976} ","formula":"dbpedia:president","lexeme":"president","type":"ObjectProp"} +{"features":" {score:0.013658536585365855} ","formula":"!property:candidate","lexeme":"candidate","type":"DataProp"} +{"features":" {score:0.04487804878048781} ","formula":"!property:person","lexeme":"person","type":"ObjProp"} +{"features":" {score:0.013658536585365855} ","formula":"property:candidate","lexeme":"candidate","type":"ObjProp"} +{"features":" {score:0.011707317073170733} ","formula":"property:name","lexeme":"name","type":"DataProp"} +{"features":" {score:0.45063192385707596} ","formula":"resource:Barack_Obama","lexeme":"barack obama","type":"NamedEntity"} +{"features":" {score:0.3089717584646591} ","formula":"resource:Patient_Protection_and_Affordable_Care_Act","lexeme":"patient protection and affordable care act","type":"NamedEntity"} +{"features":" {score:0.31418317990326106} ","formula":"resource:Sean_Combs","lexeme":"sean combs","type":"NamedEntity"} +{"features":" {score:0.010731707317073172} ","formula":"(rdf:type dbpedia:Celebrity)","lexeme":"celebrity","type":"ClassNoun"} +{"features":" {score:0.015609756097560976} ","formula":"!dbpedia:president","lexeme":"president","type":"ObjectProp"} +{"features":" {score:0.04487804878048781} ","formula":"!dbpedia:person","lexeme":"person","type":"ObjectProp"} +{"features":" {score:0.04487804878048781} ","formula":"property:person","lexeme":"person","type":"DataProp"} +{"features":" {score:0.021463414634146343} ","formula":"property:leader","lexeme":"leader","type":"DataProp"} +{"features":" {score:0.021463414634146343} ","formula":"dbpedia:leader","lexeme":"leader","type":"ObjectProp"} +{"features":" {score:0.011707317073170733} ","formula":"!property:name","lexeme":"name","type":"ObjProp"} +{"features":" {score:0.021463414634146343} ","formula":"!property:leader","lexeme":"leader","type":"DataProp"} +{"features":" {score:0.011707317073170733} ","formula":"!property:name","lexeme":"name","type":"DataProp"} +{"features":" {score:0.03609756097560975} ","formula":"(rdf:type dbpedia:Politician)","lexeme":"politician","type":"ClassNoun"} +{"features":" {score:0.013658536585365855} ","formula":"property:candidate","lexeme":"candidate","type":"DataProp"} +{"features":" {score:0.04487804878048781} ","formula":"(rdf:type dbpedia:Person)","lexeme":"person","type":"ClassNoun"} +{"features":" {score:0.011707317073170733} ","formula":"(rdf:type dbpedia:Name)","lexeme":"name","type":"ClassNoun"} +{"features":" {score:0.011707317073170733} ","formula":"property:name","lexeme":"name","type":"ObjProp"} +{"features":" {score:0.315447027617413} ","formula":"resource:American_Recovery_and_Reinvestment_Act_of_2009","lexeme":"american recovery and reinvestment act of 2009","type":"NamedEntity"} +{"features":" {score:0.04487804878048781} ","formula":"!property:person","lexeme":"person","type":"DataProp"} +{"features":" {score:0.021463414634146343} ","formula":"!property:leader","lexeme":"leader","type":"ObjProp"} +{"features":" {score:0.31076611015759087} ","formula":"resource:Presidency_of_Barack_Obama","lexeme":"presidency of barack obama","type":"NamedEntity"} +{"features":" {score:0.04487804878048781} ","formula":"dbpedia:person","lexeme":"person","type":"ObjectProp"} +{"features":" {score:0.021463414634146343} ","formula":"!dbpedia:leader","lexeme":"leader","type":"ObjectProp"} +{"features":" {score:0.015609756097560976} ","formula":"(rdf:type dbpedia:President)","lexeme":"president","type":"ClassNoun"} +{"features":" {score:0.04487804878048781} ","formula":"property:person","lexeme":"person","type":"ObjProp"} +{"features":" {score:0.013658536585365855} ","formula":"!property:candidate","lexeme":"candidate","type":"ObjProp"} +{"features":" {score:0.021463414634146343} ","formula":"property:leader","lexeme":"leader","type":"ObjProp"} +{"features":" {score:0.015609756097560976} ","formula":"dbpedia:president","lexeme":"president","type":"ObjectProp"} +{"features":" {score:0.013658536585365855} ","formula":"!property:candidate","lexeme":"candidate","type":"DataProp"} +{"features":" {score:0.04487804878048781} ","formula":"!property:person","lexeme":"person","type":"ObjProp"} +{"features":" {score:0.013658536585365855} ","formula":"property:candidate","lexeme":"candidate","type":"ObjProp"} +{"features":" {score:0.011707317073170733} ","formula":"property:name","lexeme":"name","type":"DataProp"} +{"features":" {score:0.45063192385707596} ","formula":"resource:Barack_Obama","lexeme":"barack obama","type":"NamedEntity"} +{"features":" {score:0.3089717584646591} ","formula":"resource:Patient_Protection_and_Affordable_Care_Act","lexeme":"patient protection and affordable care act","type":"NamedEntity"} +{"features":" {score:0.31418317990326106} ","formula":"resource:Sean_Combs","lexeme":"sean combs","type":"NamedEntity"} +{"features":" {score:0.010731707317073172} ","formula":"(rdf:type dbpedia:Celebrity)","lexeme":"celebrity","type":"ClassNoun"} +{"features":" {score:0.015609756097560976} ","formula":"!dbpedia:president","lexeme":"president","type":"ObjectProp"} +{"features":" {score:0.04487804878048781} ","formula":"!dbpedia:person","lexeme":"person","type":"ObjectProp"} +{"features":" {score:0.04487804878048781} ","formula":"property:person","lexeme":"person","type":"DataProp"} +{"features":" {score:0.021463414634146343} ","formula":"property:leader","lexeme":"leader","type":"DataProp"} +{"features":" {score:0.021463414634146343} ","formula":"dbpedia:leader","lexeme":"leader","type":"ObjectProp"} +{"features":" {score:0.011707317073170733} ","formula":"!property:name","lexeme":"name","type":"ObjProp"} +{"features":" {score:0.021463414634146343} ","formula":"!property:leader","lexeme":"leader","type":"DataProp"} +{"features":" {score:0.011707317073170733} ","formula":"!property:name","lexeme":"name","type":"DataProp"} +{"features":" {score:0.03609756097560975} ","formula":"(rdf:type dbpedia:Politician)","lexeme":"politician","type":"ClassNoun"} +{"features":" {score:0.013658536585365855} ","formula":"property:candidate","lexeme":"candidate","type":"DataProp"} +{"features":" {score:0.04487804878048781} ","formula":"(rdf:type dbpedia:Person)","lexeme":"person","type":"ClassNoun"} +{"features":" {score:0.011707317073170733} ","formula":"(rdf:type dbpedia:Name)","lexeme":"name","type":"ClassNoun"} +{"features":" {score:0.011707317073170733} ","formula":"property:name","lexeme":"name","type":"ObjProp"} +{"features":" {score:0.315447027617413} ","formula":"resource:American_Recovery_and_Reinvestment_Act_of_2009","lexeme":"american recovery and reinvestment act of 2009","type":"NamedEntity"} +{"features":" {score:0.04487804878048781} ","formula":"!property:person","lexeme":"person","type":"DataProp"} +{"features":" {score:0.021463414634146343} ","formula":"!property:leader","lexeme":"leader","type":"ObjProp"} +{"features":" {score:0.31076611015759087} ","formula":"resource:Presidency_of_Barack_Obama","lexeme":"presidency of barack obama","type":"NamedEntity"} +{"features":" {score:0.04487804878048781} ","formula":"dbpedia:person","lexeme":"person","type":"ObjectProp"} +{"features":" {score:0.021463414634146343} ","formula":"!dbpedia:leader","lexeme":"leader","type":"ObjectProp"} +{"features":" {score:0.015609756097560976} ","formula":"(rdf:type dbpedia:President)","lexeme":"president","type":"ClassNoun"} +{"features":" {score:0.04487804878048781} ","formula":"property:person","lexeme":"person","type":"ObjProp"} +{"features":" {score:0.013658536585365855} ","formula":"!property:candidate","lexeme":"candidate","type":"ObjProp"} +{"features":" {score:0.021463414634146343} ","formula":"property:leader","lexeme":"leader","type":"ObjProp"} +{"features":" {score:0.015609756097560976} ","formula":"dbpedia:president","lexeme":"president","type":"ObjectProp"} +{"features":" {score:0.013658536585365855} ","formula":"!property:candidate","lexeme":"candidate","type":"DataProp"} +{"features":" {score:0.04487804878048781} ","formula":"!property:person","lexeme":"person","type":"ObjProp"} +{"features":" {score:0.013658536585365855} ","formula":"property:candidate","lexeme":"candidate","type":"ObjProp"} +{"features":" {score:0.011707317073170733} ","formula":"property:name","lexeme":"name","type":"DataProp"} +{"features":" {score:0.45063192385707596} ","formula":"resource:Barack_Obama","lexeme":"barack obama","type":"NamedEntity"} +{"features":" {score:0.3089717584646591} ","formula":"resource:Patient_Protection_and_Affordable_Care_Act","lexeme":"patient protection and affordable care act","type":"NamedEntity"} +{"features":" {score:0.31418317990326106} ","formula":"resource:Sean_Combs","lexeme":"sean combs","type":"NamedEntity"} +{"features":" {score:0.010731707317073172} ","formula":"(rdf:type dbpedia:Celebrity)","lexeme":"celebrity","type":"ClassNoun"} +{"features":" {score:0.015609756097560976} ","formula":"!dbpedia:president","lexeme":"president","type":"ObjectProp"} +{"features":" {score:0.04487804878048781} ","formula":"!dbpedia:person","lexeme":"person","type":"ObjectProp"} +{"features":" {score:0.04487804878048781} ","formula":"property:person","lexeme":"person","type":"DataProp"} +{"features":" {score:0.021463414634146343} ","formula":"property:leader","lexeme":"leader","type":"DataProp"} +{"features":" {score:0.021463414634146343} ","formula":"dbpedia:leader","lexeme":"leader","type":"ObjectProp"} +{"features":" {score:0.011707317073170733} ","formula":"!property:name","lexeme":"name","type":"ObjProp"} +{"features":" {score:0.021463414634146343} ","formula":"!property:leader","lexeme":"leader","type":"DataProp"} +{"features":" {score:0.011707317073170733} ","formula":"!property:name","lexeme":"name","type":"DataProp"} +{"features":" {score:0.03609756097560975} ","formula":"(rdf:type dbpedia:Politician)","lexeme":"politician","type":"ClassNoun"} +{"features":" {score:0.013658536585365855} ","formula":"property:candidate","lexeme":"candidate","type":"DataProp"} +{"features":" {score:0.04487804878048781} ","formula":"(rdf:type dbpedia:Person)","lexeme":"person","type":"ClassNoun"} +{"features":" {score:0.011707317073170733} ","formula":"(rdf:type dbpedia:Name)","lexeme":"name","type":"ClassNoun"} +{"features":" {score:0.011707317073170733} ","formula":"property:name","lexeme":"name","type":"ObjProp"} +{"features":" {score:0.315447027617413} ","formula":"resource:American_Recovery_and_Reinvestment_Act_of_2009","lexeme":"american recovery and reinvestment act of 2009","type":"NamedEntity"} +{"features":" {score:0.04487804878048781} ","formula":"!property:person","lexeme":"person","type":"DataProp"} +{"features":" {score:0.021463414634146343} ","formula":"!property:leader","lexeme":"leader","type":"ObjProp"} +{"features":" {score:0.31076611015759087} ","formula":"resource:Presidency_of_Barack_Obama","lexeme":"presidency of barack obama","type":"NamedEntity"} +{"features":" {score:0.04487804878048781} ","formula":"dbpedia:person","lexeme":"person","type":"ObjectProp"} +{"features":" {score:0.021463414634146343} ","formula":"!dbpedia:leader","lexeme":"leader","type":"ObjectProp"} +{"features":" {score:0.015609756097560976} ","formula":"(rdf:type dbpedia:President)","lexeme":"president","type":"ClassNoun"} +{"features":" {score:0.04487804878048781} ","formula":"property:person","lexeme":"person","type":"ObjProp"} +{"features":" {score:0.013658536585365855} ","formula":"!property:candidate","lexeme":"candidate","type":"ObjProp"} +{"features":" {score:0.021463414634146343} ","formula":"property:leader","lexeme":"leader","type":"ObjProp"} +{"features":" {score:0.015609756097560976} ","formula":"dbpedia:president","lexeme":"president","type":"ObjectProp"} +{"features":" {score:0.013658536585365855} ","formula":"!property:candidate","lexeme":"candidate","type":"DataProp"} +{"features":" {score:0.04487804878048781} ","formula":"!property:person","lexeme":"person","type":"ObjProp"} +{"features":" {score:0.013658536585365855} ","formula":"property:candidate","lexeme":"candidate","type":"ObjProp"} +{"features":" {score:0.011707317073170733} ","formula":"property:name","lexeme":"name","type":"DataProp"} +{"features":" {score:0.45063192385707596} ","formula":"resource:Barack_Obama","lexeme":"barack obama","type":"NamedEntity"} +{"features":" {score:0.3089717584646591} ","formula":"resource:Patient_Protection_and_Affordable_Care_Act","lexeme":"patient protection and affordable care act","type":"NamedEntity"} +{"features":" {score:0.31418317990326106} ","formula":"resource:Sean_Combs","lexeme":"sean combs","type":"NamedEntity"} +{"features":" {score:0.010731707317073172} ","formula":"(rdf:type dbpedia:Celebrity)","lexeme":"celebrity","type":"ClassNoun"} +{"features":" {score:0.015609756097560976} ","formula":"!dbpedia:president","lexeme":"president","type":"ObjectProp"} +{"features":" {score:0.04487804878048781} ","formula":"!dbpedia:person","lexeme":"person","type":"ObjectProp"} +{"features":" {score:0.04487804878048781} ","formula":"property:person","lexeme":"person","type":"DataProp"} +{"features":" {score:0.021463414634146343} ","formula":"property:leader","lexeme":"leader","type":"DataProp"} +{"features":" {score:0.021463414634146343} ","formula":"dbpedia:leader","lexeme":"leader","type":"ObjectProp"} +{"features":" {score:0.011707317073170733} ","formula":"!property:name","lexeme":"name","type":"ObjProp"} +{"features":" {score:0.021463414634146343} ","formula":"!property:leader","lexeme":"leader","type":"DataProp"} +{"features":" {score:0.011707317073170733} ","formula":"!property:name","lexeme":"name","type":"DataProp"} +{"features":" {score:0.03609756097560975} ","formula":"(rdf:type dbpedia:Politician)","lexeme":"politician","type":"ClassNoun"} +{"features":" {score:0.013658536585365855} ","formula":"property:candidate","lexeme":"candidate","type":"DataProp"} +{"features":" {score:0.04487804878048781} ","formula":"(rdf:type dbpedia:Person)","lexeme":"person","type":"ClassNoun"} +{"features":" {score:0.011707317073170733} ","formula":"(rdf:type dbpedia:Name)","lexeme":"name","type":"ClassNoun"} +{"features":" {score:0.011707317073170733} ","formula":"property:name","lexeme":"name","type":"ObjProp"} +{"features":" {score:0.315447027617413} ","formula":"resource:American_Recovery_and_Reinvestment_Act_of_2009","lexeme":"american recovery and reinvestment act of 2009","type":"NamedEntity"} +{"features":" {score:0.04487804878048781} ","formula":"!property:person","lexeme":"person","type":"DataProp"} +{"features":" {score:0.021463414634146343} ","formula":"!property:leader","lexeme":"leader","type":"ObjProp"} +{"features":" {score:0.31076611015759087} ","formula":"resource:Presidency_of_Barack_Obama","lexeme":"presidency of barack obama","type":"NamedEntity"} +{"features":" {score:0.04487804878048781} ","formula":"dbpedia:person","lexeme":"person","type":"ObjectProp"} +{"features":" {score:0.021463414634146343} ","formula":"!dbpedia:leader","lexeme":"leader","type":"ObjectProp"} +{"features":" {score:0.015609756097560976} ","formula":"(rdf:type dbpedia:President)","lexeme":"president","type":"ClassNoun"} +{"features":" {score:0.04487804878048781} ","formula":"property:person","lexeme":"person","type":"ObjProp"} +{"features":" {score:0.013658536585365855} ","formula":"!property:candidate","lexeme":"candidate","type":"ObjProp"} +{"features":" {score:0.021463414634146343} ","formula":"property:leader","lexeme":"leader","type":"ObjProp"} +{"features":" {score:0.015609756097560976} ","formula":"dbpedia:president","lexeme":"president","type":"ObjectProp"} +{"features":" {score:0.013658536585365855} ","formula":"!property:candidate","lexeme":"candidate","type":"DataProp"} +{"features":" {score:0.04487804878048781} ","formula":"!property:person","lexeme":"person","type":"ObjProp"} +{"features":" {score:0.013658536585365855} ","formula":"property:candidate","lexeme":"candidate","type":"ObjProp"} +{"features":" {score:0.011707317073170733} ","formula":"property:name","lexeme":"name","type":"DataProp"} +{"features":" {score:0.45063192385707596} ","formula":"resource:Barack_Obama","lexeme":"barack obama","type":"NamedEntity"} +{"features":" {score:0.3089717584646591} ","formula":"resource:Patient_Protection_and_Affordable_Care_Act","lexeme":"patient protection and affordable care act","type":"NamedEntity"} +{"features":" {score:0.31418317990326106} ","formula":"resource:Sean_Combs","lexeme":"sean combs","type":"NamedEntity"} +{"features":" {score:0.010731707317073172} ","formula":"(rdf:type dbpedia:Celebrity)","lexeme":"celebrity","type":"ClassNoun"} +{"features":" {score:0.015609756097560976} ","formula":"!dbpedia:president","lexeme":"president","type":"ObjectProp"} +{"features":" {score:0.04487804878048781} ","formula":"!dbpedia:person","lexeme":"person","type":"ObjectProp"} +{"features":" {score:0.04487804878048781} ","formula":"property:person","lexeme":"person","type":"DataProp"} +{"features":" {score:0.021463414634146343} ","formula":"property:leader","lexeme":"leader","type":"DataProp"} +{"features":" {score:0.021463414634146343} ","formula":"dbpedia:leader","lexeme":"leader","type":"ObjectProp"} +{"features":" {score:0.011707317073170733} ","formula":"!property:name","lexeme":"name","type":"ObjProp"} +{"features":" {score:0.021463414634146343} ","formula":"!property:leader","lexeme":"leader","type":"DataProp"} +{"features":" {score:0.011707317073170733} ","formula":"!property:name","lexeme":"name","type":"DataProp"} +{"features":" {score:0.03609756097560975} ","formula":"(rdf:type dbpedia:Politician)","lexeme":"politician","type":"ClassNoun"} +{"features":" {score:0.013658536585365855} ","formula":"property:candidate","lexeme":"candidate","type":"DataProp"} +{"features":" {score:0.04487804878048781} ","formula":"(rdf:type dbpedia:Person)","lexeme":"person","type":"ClassNoun"} +{"features":" {score:0.011707317073170733} ","formula":"(rdf:type dbpedia:Name)","lexeme":"name","type":"ClassNoun"} +{"features":" {score:0.011707317073170733} ","formula":"property:name","lexeme":"name","type":"ObjProp"} +{"features":" {score:0.315447027617413} ","formula":"resource:American_Recovery_and_Reinvestment_Act_of_2009","lexeme":"american recovery and reinvestment act of 2009","type":"NamedEntity"} +{"features":" {score:0.04487804878048781} ","formula":"!property:person","lexeme":"person","type":"DataProp"} +{"features":" {score:0.021463414634146343} ","formula":"!property:leader","lexeme":"leader","type":"ObjProp"} +{"features":" {score:0.31076611015759087} ","formula":"resource:Presidency_of_Barack_Obama","lexeme":"presidency of barack obama","type":"NamedEntity"} +{"features":" {score:0.04487804878048781} ","formula":"dbpedia:person","lexeme":"person","type":"ObjectProp"} +{"features":" {score:0.021463414634146343} ","formula":"!dbpedia:leader","lexeme":"leader","type":"ObjectProp"} +{"features":" {score:0.015609756097560976} ","formula":"(rdf:type dbpedia:President)","lexeme":"president","type":"ClassNoun"} +{"features":" {score:0.04487804878048781} ","formula":"property:person","lexeme":"person","type":"ObjProp"} +{"features":" {score:0.013658536585365855} ","formula":"!property:candidate","lexeme":"candidate","type":"ObjProp"} +{"features":" {score:0.021463414634146343} ","formula":"property:leader","lexeme":"leader","type":"ObjProp"} +{"features":" {score:0.015609756097560976} ","formula":"dbpedia:president","lexeme":"president","type":"ObjectProp"} +{"features":" {score:0.013658536585365855} ","formula":"!property:candidate","lexeme":"candidate","type":"DataProp"} +{"features":" {score:0.04487804878048781} ","formula":"!property:person","lexeme":"person","type":"ObjProp"} +{"features":" {score:0.013658536585365855} ","formula":"property:candidate","lexeme":"candidate","type":"ObjProp"} +{"features":" {score:0.011707317073170733} ","formula":"property:name","lexeme":"name","type":"DataProp"} +{"features":" {score:0.45063192385707596} ","formula":"resource:Barack_Obama","lexeme":"barack obama","type":"NamedEntity"} +{"features":" {score:0.3089717584646591} ","formula":"resource:Patient_Protection_and_Affordable_Care_Act","lexeme":"patient protection and affordable care act","type":"NamedEntity"} +{"features":" {score:0.31418317990326106} ","formula":"resource:Sean_Combs","lexeme":"sean combs","type":"NamedEntity"} +{"features":" {score:0.010731707317073172} ","formula":"(rdf:type dbpedia:Celebrity)","lexeme":"celebrity","type":"ClassNoun"} +{"features":" {score:0.015609756097560976} ","formula":"!dbpedia:president","lexeme":"president","type":"ObjectProp"} +{"features":" {score:0.04487804878048781} ","formula":"!dbpedia:person","lexeme":"person","type":"ObjectProp"} +{"features":" {score:0.04487804878048781} ","formula":"property:person","lexeme":"person","type":"DataProp"} +{"features":" {score:0.021463414634146343} ","formula":"property:leader","lexeme":"leader","type":"DataProp"} +{"features":" {score:0.021463414634146343} ","formula":"dbpedia:leader","lexeme":"leader","type":"ObjectProp"} +{"features":" {score:0.011707317073170733} ","formula":"!property:name","lexeme":"name","type":"ObjProp"} +{"features":" {score:0.021463414634146343} ","formula":"!property:leader","lexeme":"leader","type":"DataProp"} +{"features":" {score:0.011707317073170733} ","formula":"!property:name","lexeme":"name","type":"DataProp"} +{"features":" {score:0.03609756097560975} ","formula":"(rdf:type dbpedia:Politician)","lexeme":"politician","type":"ClassNoun"} +{"features":" {score:0.013658536585365855} ","formula":"property:candidate","lexeme":"candidate","type":"DataProp"} +{"features":" {score:0.04487804878048781} ","formula":"(rdf:type dbpedia:Person)","lexeme":"person","type":"ClassNoun"} +{"features":" {score:0.011707317073170733} ","formula":"(rdf:type dbpedia:Name)","lexeme":"name","type":"ClassNoun"} +{"features":" {score:0.011707317073170733} ","formula":"property:name","lexeme":"name","type":"ObjProp"} +{"features":" {score:0.315447027617413} ","formula":"resource:American_Recovery_and_Reinvestment_Act_of_2009","lexeme":"american recovery and reinvestment act of 2009","type":"NamedEntity"} +{"features":" {score:0.04487804878048781} ","formula":"!property:person","lexeme":"person","type":"DataProp"} +{"features":" {score:0.021463414634146343} ","formula":"!property:leader","lexeme":"leader","type":"ObjProp"} +{"features":" {score:0.31076611015759087} ","formula":"resource:Presidency_of_Barack_Obama","lexeme":"presidency of barack obama","type":"NamedEntity"} +{"features":" {score:0.04487804878048781} ","formula":"dbpedia:person","lexeme":"person","type":"ObjectProp"} +{"features":" {score:0.021463414634146343} ","formula":"!dbpedia:leader","lexeme":"leader","type":"ObjectProp"} +{"features":" {score:0.015609756097560976} ","formula":"(rdf:type dbpedia:President)","lexeme":"president","type":"ClassNoun"} +{"features":" {score:0.04487804878048781} ","formula":"property:person","lexeme":"person","type":"ObjProp"} +{"features":" {score:0.013658536585365855} ","formula":"!property:candidate","lexeme":"candidate","type":"ObjProp"} +{"features":" {score:0.021463414634146343} ","formula":"property:leader","lexeme":"leader","type":"ObjProp"} +{"features":" {score:0.015609756097560976} ","formula":"dbpedia:president","lexeme":"president","type":"ObjectProp"} +{"features":" {score:0.013658536585365855} ","formula":"!property:candidate","lexeme":"candidate","type":"DataProp"} +{"features":" {score:0.04487804878048781} ","formula":"!property:person","lexeme":"person","type":"ObjProp"} +{"features":" {score:0.013658536585365855} ","formula":"property:candidate","lexeme":"candidate","type":"ObjProp"} +{"features":" {score:0.011707317073170733} ","formula":"property:name","lexeme":"name","type":"DataProp"} +{"features":" {score:0.45063192385707596} ","formula":"resource:Barack_Obama","lexeme":"barack obama","type":"NamedEntity"} +{"features":" {score:0.3089717584646591} ","formula":"resource:Patient_Protection_and_Affordable_Care_Act","lexeme":"patient protection and affordable care act","type":"NamedEntity"} +{"features":" {score:0.31418317990326106} ","formula":"resource:Sean_Combs","lexeme":"sean combs","type":"NamedEntity"} +{"features":" {score:0.010731707317073172} ","formula":"(rdf:type dbpedia:Celebrity)","lexeme":"celebrity","type":"ClassNoun"} +{"features":" {score:0.015609756097560976} ","formula":"!dbpedia:president","lexeme":"president","type":"ObjectProp"} +{"features":" {score:0.04487804878048781} ","formula":"!dbpedia:person","lexeme":"person","type":"ObjectProp"} +{"features":" {score:0.04487804878048781} ","formula":"property:person","lexeme":"person","type":"DataProp"} +{"features":" {score:0.021463414634146343} ","formula":"property:leader","lexeme":"leader","type":"DataProp"} +{"features":" {score:0.021463414634146343} ","formula":"dbpedia:leader","lexeme":"leader","type":"ObjectProp"} +{"features":" {score:0.011707317073170733} ","formula":"!property:name","lexeme":"name","type":"ObjProp"} +{"features":" {score:0.021463414634146343} ","formula":"!property:leader","lexeme":"leader","type":"DataProp"} +{"features":" {score:0.011707317073170733} ","formula":"!property:name","lexeme":"name","type":"DataProp"} +{"features":" {score:0.03609756097560975} ","formula":"(rdf:type dbpedia:Politician)","lexeme":"politician","type":"ClassNoun"} +{"features":" {score:0.013658536585365855} ","formula":"property:candidate","lexeme":"candidate","type":"DataProp"} +{"features":" {score:0.055132212042808534} ","formula":"dbpedia:leader","lexeme":"leader","type":"ObjectProp"} +{"features":" {score:0.03828920185565949} ","formula":"property:woman","lexeme":"woman","type":"ObjProp"} +{"features":" {score:0.07457736134529114} ","formula":"(rdf:type dbpedia:Politician)","lexeme":"politician","type":"ClassNoun"} +{"features":" {score:0.055132212042808534} ","formula":"!property:leader","lexeme":"leader","type":"DataProp"} +{"features":" {score:0.055132212042808534} ","formula":"property:leader","lexeme":"leader","type":"DataProp"} +{"features":" {score:0.055132212042808534} ","formula":"property:leader","lexeme":"leader","type":"ObjProp"} +{"features":" {score:0.683304347826087} ","formula":"resource:Angela_Merkel","lexeme":"angela merkel","type":"NamedEntity"} +{"features":" {score:0.022632212042808533} ","formula":"property:politicalLeader","lexeme":"political leader","type":"ObjProp"} +{"features":" {score:0.03828920185565949} ","formula":"property:woman","lexeme":"woman","type":"DataProp"} +{"features":" {score:0.022632212042808533} ","formula":"!property:politicalLeader","lexeme":"political leader","type":"DataProp"} +{"features":" {score:0.055132212042808534} ","formula":"!dbpedia:leader","lexeme":"leader","type":"ObjectProp"} +{"features":" {score:0.03828920185565949} ","formula":"!property:woman","lexeme":"woman","type":"ObjProp"} +{"features":" {score:0.022632212042808533} ","formula":"!dbpedia:politicalLeader","lexeme":"political leader","type":"ObjectProp"} +{"features":" {score:0.022632212042808533} ","formula":"property:politicalLeader","lexeme":"political leader","type":"DataProp"} +{"features":" {score:0.055132212042808534} ","formula":"!property:leader","lexeme":"leader","type":"ObjProp"} +{"features":" {score:0.022632212042808533} ","formula":"dbpedia:politicalLeader","lexeme":"political leader","type":"ObjectProp"} +{"features":" {score:0.022632212042808533} ","formula":"!property:politicalLeader","lexeme":"political leader","type":"ObjProp"} +{"features":" {score:0.03828920185565949} ","formula":"!property:woman","lexeme":"woman","type":"DataProp"} +{"features":" {score:0.04487804878048781} ","formula":"(rdf:type dbpedia:Person)","lexeme":"person","type":"ClassNoun"} +{"features":" {score:0.011707317073170733} ","formula":"(rdf:type dbpedia:Name)","lexeme":"name","type":"ClassNoun"} +{"features":" {score:0.011707317073170733} ","formula":"property:name","lexeme":"name","type":"ObjProp"} +{"features":" {score:0.315447027617413} ","formula":"resource:American_Recovery_and_Reinvestment_Act_of_2009","lexeme":"american recovery and reinvestment act of 2009","type":"NamedEntity"} +{"features":" {score:0.04487804878048781} ","formula":"!property:person","lexeme":"person","type":"DataProp"} +{"features":" {score:0.021463414634146343} ","formula":"!property:leader","lexeme":"leader","type":"ObjProp"} +{"features":" {score:0.31076611015759087} ","formula":"resource:Presidency_of_Barack_Obama","lexeme":"presidency of barack obama","type":"NamedEntity"} +{"features":" {score:0.04487804878048781} ","formula":"dbpedia:person","lexeme":"person","type":"ObjectProp"} +{"features":" {score:0.021463414634146343} ","formula":"!dbpedia:leader","lexeme":"leader","type":"ObjectProp"} +{"features":" {score:0.015609756097560976} ","formula":"(rdf:type dbpedia:President)","lexeme":"president","type":"ClassNoun"} +{"features":" {score:0.04487804878048781} ","formula":"property:person","lexeme":"person","type":"ObjProp"} +{"features":" {score:0.013658536585365855} ","formula":"!property:candidate","lexeme":"candidate","type":"ObjProp"} +{"features":" {score:0.021463414634146343} ","formula":"property:leader","lexeme":"leader","type":"ObjProp"} +{"features":" {score:0.015609756097560976} ","formula":"dbpedia:president","lexeme":"president","type":"ObjectProp"} +{"features":" {score:0.013658536585365855} ","formula":"!property:candidate","lexeme":"candidate","type":"DataProp"} +{"features":" {score:0.04487804878048781} ","formula":"!property:person","lexeme":"person","type":"ObjProp"} +{"features":" {score:0.013658536585365855} ","formula":"property:candidate","lexeme":"candidate","type":"ObjProp"} +{"features":" {score:0.011707317073170733} ","formula":"property:name","lexeme":"name","type":"DataProp"} +{"features":" {score:0.45063192385707596} ","formula":"resource:Barack_Obama","lexeme":"barack obama","type":"NamedEntity"} +{"features":" {score:0.3089717584646591} ","formula":"resource:Patient_Protection_and_Affordable_Care_Act","lexeme":"patient protection and affordable care act","type":"NamedEntity"} +{"features":" {score:0.31418317990326106} ","formula":"resource:Sean_Combs","lexeme":"sean combs","type":"NamedEntity"} +{"features":" {score:0.010731707317073172} ","formula":"(rdf:type dbpedia:Celebrity)","lexeme":"celebrity","type":"ClassNoun"} +{"features":" {score:0.015609756097560976} ","formula":"!dbpedia:president","lexeme":"president","type":"ObjectProp"} +{"features":" {score:0.04487804878048781} ","formula":"!dbpedia:person","lexeme":"person","type":"ObjectProp"} +{"features":" {score:0.04487804878048781} ","formula":"property:person","lexeme":"person","type":"DataProp"} +{"features":" {score:0.021463414634146343} ","formula":"property:leader","lexeme":"leader","type":"DataProp"} +{"features":" {score:0.021463414634146343} ","formula":"dbpedia:leader","lexeme":"leader","type":"ObjectProp"} +{"features":" {score:0.011707317073170733} ","formula":"!property:name","lexeme":"name","type":"ObjProp"} +{"features":" {score:0.021463414634146343} ","formula":"!property:leader","lexeme":"leader","type":"DataProp"} +{"features":" {score:0.011707317073170733} ","formula":"!property:name","lexeme":"name","type":"DataProp"} +{"features":" {score:0.03609756097560975} ","formula":"(rdf:type dbpedia:Politician)","lexeme":"politician","type":"ClassNoun"} +{"features":" {score:0.013658536585365855} ","formula":"property:candidate","lexeme":"candidate","type":"DataProp"} +{"features":" {score:0.042009095673847544} ","formula":"property:person","lexeme":"person","type":"DataProp"} +{"features":" {score:0.8907573812580232} ","formula":"resource:Donald_Trump","lexeme":"donald trump","type":"NamedEntity"} +{"features":" {score:0.0861954571238255} ","formula":"property:candidate","lexeme":"candidate","type":"DataProp"} +{"features":" {score:0.042009095673847544} ","formula":"dbpedia:person","lexeme":"person","type":"ObjectProp"} +{"features":" {score:0.545266447683966} ","formula":"resource:Trump_Model_Management","lexeme":"trump model management","type":"NamedEntity"} +{"features":" {score:0.0861954571238255} ","formula":"!property:candidate","lexeme":"candidate","type":"DataProp"} +{"features":" {score:0.027895863596415774} ","formula":"(rdf:type dbpedia:Name)","lexeme":"name","type":"ClassNoun"} +{"features":" {score:0.042009095673847544} ","formula":"!property:person","lexeme":"person","type":"ObjProp"} +{"features":" {score:0.027895863596415774} ","formula":"property:name","lexeme":"name","type":"DataProp"} +{"features":" {score:0.027895863596415774} ","formula":"!property:name","lexeme":"name","type":"ObjProp"} +{"features":" {score:0.042009095673847544} ","formula":"(rdf:type dbpedia:Person)","lexeme":"person","type":"ClassNoun"} +{"features":" {score:0.0861954571238255} ","formula":"property:candidate","lexeme":"candidate","type":"ObjProp"} +{"features":" {score:0.042009095673847544} ","formula":"property:person","lexeme":"person","type":"ObjProp"} +{"features":" {score:0.042009095673847544} ","formula":"!dbpedia:person","lexeme":"person","type":"ObjectProp"} +{"features":" {score:0.027895863596415774} ","formula":"!property:name","lexeme":"name","type":"DataProp"} +{"features":" {score:0.7012836970474968} ","formula":"resource:Donald_J._Trump_State_Park","lexeme":"donald j. trump state park","type":"NamedEntity"} +{"features":" {score:0.700770218228498} ","formula":"\u003chttp://dbpedia.org/resource/Donald_Trump_(song)\u003e","lexeme":"donald trump song","type":"NamedEntity"} +{"features":" {score:0.5462934053219635} ","formula":"\u003chttp://dbpedia.org/resource/Donald_Trump,_Jr.\u003e","lexeme":"donald trump, jr.","type":"NamedEntity"} +{"features":" {score:0.042009095673847544} ","formula":"!property:person","lexeme":"person","type":"DataProp"} +{"features":" {score:0.06954035692232868} ","formula":"(rdf:type dbpedia:Politician)","lexeme":"politician","type":"ClassNoun"} +{"features":" {score:0.027895863596415774} ","formula":"property:name","lexeme":"name","type":"ObjProp"} +{"features":" {score:0.04269494056017155} ","formula":"(rdf:type dbpedia:Celebrity)","lexeme":"celebrity","type":"ClassNoun"} +{"features":" {score:0.0861954571238255} ","formula":"!property:candidate","lexeme":"candidate","type":"ObjProp"} +{"features":" {score:0.02754881125994218} ","formula":"!property:market","lexeme":"market","type":"DataProp"} +{"features":" {score:0.5755008526150316} ","formula":"resource:United_States","lexeme":"united states","type":"NamedEntity"} +{"features":" {score:0.02754881125994218} ","formula":"!property:market","lexeme":"market","type":"ObjProp"} +{"features":" {score:0.08751242573062579} ","formula":"dbpedia:state","lexeme":"state","type":"ObjectProp"} +{"features":" {score:0.07595872349463977} ","formula":"!property:jurisdiction","lexeme":"jurisdiction","type":"ObjProp"} +{"features":" {score:0.03030440770662748} ","formula":"(rdf:type dbpedia:Area)","lexeme":"area","type":"ClassNoun"} +{"features":" {score:0.07595872349463977} ","formula":"!dbpedia:jurisdiction","lexeme":"jurisdiction","type":"ObjectProp"} +{"features":" {score:0.03030440770662748} ","formula":"property:area","lexeme":"area","type":"ObjProp"} +{"features":" {score:0.1526816528538863} ","formula":"(rdf:type dbpedia:State)","lexeme":"state","type":"ClassNoun"} +{"features":" {score:0.0370556704996106} ","formula":"property:place","lexeme":"place","type":"DataProp"} +{"features":" {score:0.02754881125994218} ","formula":"property:market","lexeme":"market","type":"DataProp"} +{"features":" {score:0.15117955282330514} ","formula":"(rdf:type dbpedia:Community)","lexeme":"community","type":"ClassNoun"} +{"features":" {score:0.07595872349463977} ","formula":"property:jurisdiction","lexeme":"jurisdiction","type":"ObjProp"} +{"features":" {score:0.03030440770662748} ","formula":"!property:area","lexeme":"area","type":"DataProp"} +{"features":" {score:0.38557999580675983} ","formula":"resource:Las_Vegas_Valley","lexeme":"las vegas valley","type":"NamedEntity"} +{"features":" {score:0.07957891535682556} ","formula":"property:nation","lexeme":"nation","type":"DataProp"} +{"features":" {score:0.5303599433230969} ","formula":"resource:USA_Today","lexeme":"usa today","type":"NamedEntity"} +{"features":" {score:0.012150918220480283} ","formula":"property:economy","lexeme":"economy","type":"ObjProp"} +{"features":" {score:0.07595872349463977} ","formula":"!property:jurisdiction","lexeme":"jurisdiction","type":"DataProp"} +{"features":" {score:0.0370556704996106} ","formula":"property:place","lexeme":"place","type":"ObjProp"} +{"features":" {score:0.012150918220480283} ","formula":"!property:economy","lexeme":"economy","type":"DataProp"} +{"features":" {score:0.08751242573062579} ","formula":"!property:state","lexeme":"state","type":"DataProp"} +{"features":" {score:0.08751242573062579} ","formula":"!dbpedia:state","lexeme":"state","type":"ObjectProp"} +{"features":" {score:0.0370556704996106} ","formula":"(rdf:type dbpedia:Place)","lexeme":"place","type":"ClassNoun"} +{"features":" {score:0.4179297464449643} ","formula":"\u003chttp://dbpedia.org/resource/Georgia_(U.S._state)\u003e","lexeme":"georgia u.s. state","type":"NamedEntity"} +{"features":" {score:0.07957891535682556} ","formula":"!property:nation","lexeme":"nation","type":"DataProp"} +{"features":" {score:0.08751242573062579} ","formula":"property:state","lexeme":"state","type":"ObjProp"} +{"features":" {score:0.02754881125994218} ","formula":"property:market","lexeme":"market","type":"ObjProp"} +{"features":" {score:0.0370556704996106} ","formula":"!property:place","lexeme":"place","type":"ObjProp"} +{"features":" {score:0.0370556704996106} ","formula":"!property:place","lexeme":"place","type":"DataProp"} +{"features":" {score:0.08751242573062579} ","formula":"property:state","lexeme":"state","type":"DataProp"} +{"features":" {score:0.07595872349463977} ","formula":"property:jurisdiction","lexeme":"jurisdiction","type":"DataProp"} +{"features":" {score:0.07957891535682556} ","formula":"!property:nation","lexeme":"nation","type":"ObjProp"} +{"features":" {score:0.012150918220480283} ","formula":"property:economy","lexeme":"economy","type":"DataProp"} +{"features":" {score:0.03030440770662748} ","formula":"property:area","lexeme":"area","type":"DataProp"} +{"features":" {score:0.08751242573062579} ","formula":"!property:state","lexeme":"state","type":"ObjProp"} +{"features":" {score:0.07595872349463977} ","formula":"dbpedia:jurisdiction","lexeme":"jurisdiction","type":"ObjectProp"} +{"features":" {score:0.012150918220480283} ","formula":"!property:economy","lexeme":"economy","type":"ObjProp"} +{"features":" {score:0.160990172624588} ","formula":"(rdf:type dbpedia:Cave)","lexeme":"cave","type":"ClassNoun"} +{"features":" {score:0.07957891535682556} ","formula":"property:nation","lexeme":"nation","type":"ObjProp"} +{"features":" {score:0.4062865242661592} ","formula":"resource:United_States_Army","lexeme":"united states army","type":"NamedEntity"} +{"features":" {score:0.03030440770662748} ","formula":"!property:area","lexeme":"area","type":"ObjProp"} +{"features":" {score:0.3381166879130506} ","formula":"\u003chttp://dbpedia.org/resource/Oblivion_(2013_film)\u003e","lexeme":"oblivion 2013 film","type":"NamedEntity"} +{"features":" {score:0.054397506351323476} ","formula":"property:star","lexeme":"star","type":"DataProp"} +{"features":" {score:0.7009578544061303} ","formula":"resource:Tom_Cruise_Purple","lexeme":"tom cruise purple","type":"NamedEntity"} +{"features":" {score:0.005154639175257732} ","formula":"property:person","lexeme":"person","type":"DataProp"} +{"features":" {score:0.7011494252873564} ","formula":"resource:Being_Tom_Cruise","lexeme":"being tom cruise","type":"NamedEntity"} +{"features":" {score:0.054397506351323476} ","formula":"!property:star","lexeme":"star","type":"ObjProp"} +{"features":" {score:0.054397506351323476} ","formula":"!property:star","lexeme":"star","type":"DataProp"} +{"features":" {score:0.052604761197394934} ","formula":"(rdf:type dbpedia:MusicalArtist)","lexeme":"musical artist","type":"ClassNoun"} +{"features":" {score:0.896551724137931} ","formula":"resource:Tom_Cruise","lexeme":"tom cruise","type":"NamedEntity"} +{"features":" {score:0.09603880213707994} ","formula":"!property:actor","lexeme":"actor","type":"ObjProp"} +{"features":" {score:0.052604761197394934} ","formula":"!dbpedia:musicalArtist","lexeme":"musical artist","type":"ObjectProp"} +{"features":" {score:0.054397506351323476} ","formula":"(rdf:type dbpedia:Star)","lexeme":"star","type":"ClassNoun"} +{"features":" {score:0.052604761197394934} ","formula":"dbpedia:musicalArtist","lexeme":"musical artist","type":"ObjectProp"} +{"features":" {score:0.005154639175257732} ","formula":"(rdf:type dbpedia:Person)","lexeme":"person","type":"ClassNoun"} +{"features":" {score:0.09603880213707994} ","formula":"!property:actor","lexeme":"actor","type":"DataProp"} +{"features":" {score:0.09603880213707994} ","formula":"property:actor","lexeme":"actor","type":"DataProp"} +{"features":" {score:0.005154639175257732} ","formula":"dbpedia:person","lexeme":"person","type":"ObjectProp"} +{"features":" {score:0.005154639175257732} ","formula":"!dbpedia:person","lexeme":"person","type":"ObjectProp"} +{"features":" {score:0.054397506351323476} ","formula":"property:star","lexeme":"star","type":"ObjProp"} +{"features":" {score:0.09603880213707994} ","formula":"(rdf:type dbpedia:Actor)","lexeme":"actor","type":"ClassNoun"} +{"features":" {score:0.0867470011652745} ","formula":"(rdf:type dbpedia:Celebrity)","lexeme":"celebrity","type":"ClassNoun"} +{"features":" {score:0.09603880213707994} ","formula":"property:actor","lexeme":"actor","type":"ObjProp"} +{"features":" {score:0.005154639175257732} ","formula":"property:person","lexeme":"person","type":"ObjProp"} +{"features":" {score:0.005154639175257732} ","formula":"!property:person","lexeme":"person","type":"DataProp"} +{"features":" {score:0.005154639175257732} ","formula":"!property:person","lexeme":"person","type":"ObjProp"} +{"features":" {score:0.012132196162046908} ","formula":"property:market","lexeme":"market","type":"DataProp"} +{"features":" {score:0.09491380273946312} ","formula":"!property:nation","lexeme":"nation","type":"DataProp"} +{"features":" {score:0.0298982803415515} ","formula":"!dbpedia:state","lexeme":"state","type":"ObjectProp"} +{"features":" {score:0.012132196162046908} ","formula":"property:market","lexeme":"market","type":"ObjProp"} +{"features":" {score:0.0298982803415515} ","formula":"property:state","lexeme":"state","type":"ObjProp"} +{"features":" {score:0.0298982803415515} ","formula":"property:state","lexeme":"state","type":"DataProp"} +{"features":" {score:0.09491380273946312} ","formula":"!property:nation","lexeme":"nation","type":"ObjProp"} +{"features":" {score:0.09259691534965023} ","formula":"dbpedia:jurisdiction","lexeme":"jurisdiction","type":"ObjectProp"} +{"features":" {score:0.09259691534965023} ","formula":"!dbpedia:jurisdiction","lexeme":"jurisdiction","type":"ObjectProp"} +{"features":" {score:0.09259691534965023} ","formula":"!property:jurisdiction","lexeme":"jurisdiction","type":"ObjProp"} +{"features":" {score:0.5069967108616201} ","formula":"resource:Regions_of_France","lexeme":"regions of france","type":"NamedEntity"} +{"features":" {score:0.012132196162046908} ","formula":"!property:market","lexeme":"market","type":"DataProp"} +{"features":" {score:0.16148168835788965} ","formula":"dbpedia:kingdom","lexeme":"kingdom","type":"ObjectProp"} +{"features":" {score:0.5618006384498346} ","formula":"resource:Communes_of_France","lexeme":"communes of france","type":"NamedEntity"} +{"features":" {score:0.0298982803415515} ","formula":"!property:state","lexeme":"state","type":"DataProp"} +{"features":" {score:0.0298982803415515} ","formula":"(rdf:type dbpedia:State)","lexeme":"state","type":"ClassNoun"} +{"features":" {score:0.09259691534965023} ","formula":"property:jurisdiction","lexeme":"jurisdiction","type":"DataProp"} +{"features":" {score:0.025450552493445022} ","formula":"property:place","lexeme":"place","type":"DataProp"} +{"features":" {score:0.0298982803415515} ","formula":"!property:state","lexeme":"state","type":"ObjProp"} +{"features":" {score:0.025450552493445022} ","formula":"!property:place","lexeme":"place","type":"DataProp"} +{"features":" {score:0.16148168835788965} ","formula":"!dbpedia:kingdom","lexeme":"kingdom","type":"ObjectProp"} +{"features":" {score:0.5987827256883081} ","formula":"resource:France","lexeme":"france","type":"NamedEntity"} +{"features":" {score:0.09491380273946312} ","formula":"property:nation","lexeme":"nation","type":"ObjProp"} +{"features":" {score:0.025450552493445022} ","formula":"(rdf:type dbpedia:Place)","lexeme":"place","type":"ClassNoun"} +{"features":" {score:0.4358805129140693} ","formula":"resource:Paris","lexeme":"paris","type":"NamedEntity"} +{"features":" {score:0.09491380273946312} ","formula":"property:nation","lexeme":"nation","type":"DataProp"} +{"features":" {score:0.0298982803415515} ","formula":"dbpedia:state","lexeme":"state","type":"ObjectProp"} +{"features":" {score:0.025450552493445022} ","formula":"!property:place","lexeme":"place","type":"ObjProp"} +{"features":" {score:0.012132196162046908} ","formula":"!property:market","lexeme":"market","type":"ObjProp"} +{"features":" {score:0.09259691534965023} ","formula":"!property:jurisdiction","lexeme":"jurisdiction","type":"DataProp"} +{"features":" {score:0.09259691534965023} ","formula":"property:jurisdiction","lexeme":"jurisdiction","type":"ObjProp"} +{"features":" {score:0.5763360876788288} ","formula":"resource:Departments_of_France","lexeme":"departments of france","type":"NamedEntity"} +{"features":" {score:0.025450552493445022} ","formula":"property:place","lexeme":"place","type":"ObjProp"} +{"features":" {score:0.02754881125994218} ","formula":"!property:market","lexeme":"market","type":"DataProp"} +{"features":" {score:0.02492670177649229} ","formula":"!property:place","lexeme":"place","type":"ObjProp"} +{"features":" {score:0.02754881125994218} ","formula":"!property:market","lexeme":"market","type":"ObjProp"} +{"features":" {score:0.03030440770662748} ","formula":"(rdf:type dbpedia:Area)","lexeme":"area","type":"ClassNoun"} +{"features":" {score:0.018827202090850245} ","formula":"dbpedia:jurisdiction","lexeme":"jurisdiction","type":"ObjectProp"} +{"features":" {score:0.03030440770662748} ","formula":"property:area","lexeme":"area","type":"ObjProp"} +{"features":" {score:0.018827202090850245} ","formula":"property:jurisdiction","lexeme":"jurisdiction","type":"ObjProp"} +{"features":" {score:0.02492670177649229} ","formula":"property:place","lexeme":"place","type":"DataProp"} +{"features":" {score:0.02754881125994218} ","formula":"property:market","lexeme":"market","type":"DataProp"} +{"features":" {score:0.03030440770662748} ","formula":"!property:area","lexeme":"area","type":"DataProp"} +{"features":" {score:0.02492670177649229} ","formula":"!property:place","lexeme":"place","type":"DataProp"} +{"features":" {score:0.018827202090850245} ","formula":"!property:jurisdiction","lexeme":"jurisdiction","type":"ObjProp"} +{"features":" {score:0.02492670177649229} ","formula":"(rdf:type dbpedia:Place)","lexeme":"place","type":"ClassNoun"} +{"features":" {score:0.07183589378992716} ","formula":"dbpedia:state","lexeme":"state","type":"ObjectProp"} +{"features":" {score:0.3449200540738764} ","formula":"resource:Las_Vegas_Valley","lexeme":"las vegas valley","type":"NamedEntity"} +{"features":" {score:0.07183589378992716} ","formula":"!property:state","lexeme":"state","type":"ObjProp"} +{"features":" {score:0.010833333333333334} ","formula":"!property:economy","lexeme":"economy","type":"ObjProp"} +{"features":" {score:0.036267271011303635} ","formula":"!property:nation","lexeme":"nation","type":"DataProp"} +{"features":" {score:0.5069101221863358} ","formula":"resource:United_States","lexeme":"united states","type":"NamedEntity"} +{"features":" {score:0.010833333333333334} ","formula":"property:economy","lexeme":"economy","type":"DataProp"} +{"features":" {score:0.036267271011303635} ","formula":"property:nation","lexeme":"nation","type":"DataProp"} +{"features":" {score:0.3376957938374635} ","formula":"resource:United_States_Army","lexeme":"united states army","type":"NamedEntity"} +{"features":" {score:0.1210140109062195} ","formula":"(rdf:type dbpedia:Community)","lexeme":"community","type":"ClassNoun"} +{"features":" {score:0.010833333333333334} ","formula":"!property:economy","lexeme":"economy","type":"DataProp"} +{"features":" {score:0.010833333333333334} ","formula":"property:economy","lexeme":"economy","type":"ObjProp"} +{"features":" {score:0.018827202090850245} ","formula":"!dbpedia:jurisdiction","lexeme":"jurisdiction","type":"ObjectProp"} +{"features":" {score:0.018827202090850245} ","formula":"!property:jurisdiction","lexeme":"jurisdiction","type":"DataProp"} +{"features":" {score:0.07183589378992716} ","formula":"property:state","lexeme":"state","type":"DataProp"} +{"features":" {score:0.07183589378992716} ","formula":"!property:state","lexeme":"state","type":"DataProp"} +{"features":" {score:0.02754881125994218} ","formula":"property:market","lexeme":"market","type":"ObjProp"} +{"features":" {score:0.036267271011303635} ","formula":"property:nation","lexeme":"nation","type":"ObjProp"} +{"features":" {score:0.3712715210874318} ","formula":"\u003chttp://dbpedia.org/resource/Georgia_(U.S._state)\u003e","lexeme":"georgia u.s. state","type":"NamedEntity"} +{"features":" {score:0.13348385095596313} ","formula":"(rdf:type dbpedia:Cave)","lexeme":"cave","type":"ClassNoun"} +{"features":" {score:0.018827202090850245} ","formula":"property:jurisdiction","lexeme":"jurisdiction","type":"DataProp"} +{"features":" {score:0.07183589378992716} ","formula":"property:state","lexeme":"state","type":"ObjProp"} +{"features":" {score:0.02492670177649229} ","formula":"property:place","lexeme":"place","type":"ObjProp"} +{"features":" {score:0.03030440770662748} ","formula":"property:area","lexeme":"area","type":"DataProp"} +{"features":" {score:0.07183589378992716} ","formula":"!dbpedia:state","lexeme":"state","type":"ObjectProp"} +{"features":" {score:0.13700512091318767} ","formula":"(rdf:type dbpedia:State)","lexeme":"state","type":"ClassNoun"} +{"features":" {score:0.036267271011303635} ","formula":"!property:nation","lexeme":"nation","type":"ObjProp"} +{"features":" {score:0.5019569461422774} ","formula":"resource:USA_Today","lexeme":"usa today","type":"NamedEntity"} +{"features":" {score:0.03030440770662748} ","formula":"!property:area","lexeme":"area","type":"ObjProp"} +{"features":" {score:0.1446695566177368} ","formula":"(rdf:type dbpedia:President)","lexeme":"president","type":"ClassNoun"} +{"features":" {score:0.1446695566177368} ","formula":"dbpedia:leader","lexeme":"president","type":"ObjectProp"} +{"features":" {score:0.1446695566177368} ","formula":"!dbpedia:leader","lexeme":"president","type":"ObjectProp"} +{"features":" {score:0.3167914263218081} ","formula":"\u003chttp://dbpedia.org/resource/Nashi_(youth_movement)\u003e","lexeme":"nashi youth movement","type":"NamedEntity"} +{"features":" {score:0.13008587360382082} ","formula":"!dbpedia:chairman","lexeme":"chairman","type":"ObjectProp"} +{"features":" {score:0.683508932661475} ","formula":"resource:Vladimir_Putin","lexeme":"vladimir putin","type":"NamedEntity"} +{"features":" {score:0.13880642652511596} ","formula":"!dbpedia:commander","lexeme":"leader","type":"ObjectProp"} +{"features":" {score:0.37777169617119044} ","formula":"\u003chttp://dbpedia.org/resource/Russian_presidential_election,_2004\u003e","lexeme":"russian presidential election, 2004","type":"NamedEntity"} +{"features":" {score:0.13880642652511596} ","formula":"dbpedia:commander","lexeme":"leader","type":"ObjectProp"} +{"features":" {score:0.13008587360382082} ","formula":"dbpedia:chairman","lexeme":"chairman","type":"ObjectProp"} +{"features":" {score:0.12559207677841186} ","formula":"(rdf:type dbpedia:Deputy)","lexeme":"deputy","type":"ClassNoun"} +{"features":" {score:0.04278201647385404} ","formula":"!dbpedia:state","lexeme":"state","type":"ObjectProp"} +{"features":" {score:0.16464441987324152} ","formula":"!property:nation","lexeme":"nation","type":"DataProp"} +{"features":" {score:0.390711041013616} ","formula":"resource:Hamburg","lexeme":"hamburg","type":"NamedEntity"} +{"features":" {score:0.0265957764727325} ","formula":"property:place","lexeme":"place","type":"ObjProp"} +{"features":" {score:0.0265957764727325} ","formula":"!property:place","lexeme":"place","type":"DataProp"} +{"features":" {score:0.04278201647385404} ","formula":"property:state","lexeme":"state","type":"ObjProp"} +{"features":" {score:0.0665176406596795} ","formula":"dbpedia:jurisdiction","lexeme":"jurisdiction","type":"ObjectProp"} +{"features":" {score:0.04278201647385404} ","formula":"property:state","lexeme":"state","type":"DataProp"} +{"features":" {score:0.04278201647385404} ","formula":"!property:state","lexeme":"state","type":"DataProp"} +{"features":" {score:0.0665176406596795} ","formula":"!property:jurisdiction","lexeme":"jurisdiction","type":"ObjProp"} +{"features":" {score:0.04560972112981648} ","formula":"!property:market","lexeme":"market","type":"ObjProp"} +{"features":" {score:0.0265957764727325} ","formula":"property:place","lexeme":"place","type":"DataProp"} +{"features":" {score:0.1708839304854649} ","formula":"property:economy","lexeme":"economy","type":"ObjProp"} +{"features":" {score:0.0265957764727325} ","formula":"(rdf:type dbpedia:Place)","lexeme":"place","type":"ClassNoun"} +{"features":" {score:0.0665176406596795} ","formula":"property:jurisdiction","lexeme":"jurisdiction","type":"DataProp"} +{"features":" {score:0.39425857691081134} ","formula":"resource:Munich","lexeme":"munich","type":"NamedEntity"} +{"features":" {score:0.0665176406596795} ","formula":"property:jurisdiction","lexeme":"jurisdiction","type":"ObjProp"} +{"features":" {score:0.0265957764727325} ","formula":"!property:place","lexeme":"place","type":"ObjProp"} +{"features":" {score:0.0665176406596795} ","formula":"!dbpedia:jurisdiction","lexeme":"jurisdiction","type":"ObjectProp"} +{"features":" {score:0.16464441987324152} ","formula":"property:nation","lexeme":"nation","type":"ObjProp"} +{"features":" {score:0.16783925965428353} ","formula":"!dbpedia:kingdom","lexeme":"kingdom","type":"ObjectProp"} +{"features":" {score:0.04278201647385404} ","formula":"!property:state","lexeme":"state","type":"ObjProp"} +{"features":" {score:0.04560972112981648} ","formula":"!property:market","lexeme":"market","type":"DataProp"} +{"features":" {score:0.5636600189777636} ","formula":"resource:Nazi_Germany","lexeme":"nazi germany","type":"NamedEntity"} +{"features":" {score:0.16464441987324152} ","formula":"!property:nation","lexeme":"nation","type":"ObjProp"} +{"features":" {score:0.04560972112981648} ","formula":"property:market","lexeme":"market","type":"ObjProp"} +{"features":" {score:0.16783925965428353} ","formula":"dbpedia:kingdom","lexeme":"kingdom","type":"ObjectProp"} +{"features":" {score:0.16464441987324152} ","formula":"property:nation","lexeme":"nation","type":"DataProp"} +{"features":" {score:0.0665176406596795} ","formula":"!property:jurisdiction","lexeme":"jurisdiction","type":"DataProp"} +{"features":" {score:0.6794585619104976} ","formula":"resource:Germany","lexeme":"germany","type":"NamedEntity"} +{"features":" {score:0.39519054887256505} ","formula":"resource:Berlin","lexeme":"berlin","type":"NamedEntity"} +{"features":" {score:0.1708839304854649} ","formula":"!property:economy","lexeme":"economy","type":"DataProp"} +{"features":" {score:0.1708839304854649} ","formula":"property:economy","lexeme":"economy","type":"DataProp"} +{"features":" {score:0.04278201647385404} ","formula":"(rdf:type dbpedia:State)","lexeme":"state","type":"ClassNoun"} +{"features":" {score:0.04560972112981648} ","formula":"property:market","lexeme":"market","type":"DataProp"} +{"features":" {score:0.04278201647385404} ","formula":"dbpedia:state","lexeme":"state","type":"ObjectProp"} +{"features":" {score:0.1708839304854649} ","formula":"!property:economy","lexeme":"economy","type":"ObjProp"} +{"features":" {score:0.4458469683247078} ","formula":"resource:European_Union","lexeme":"european union","type":"NamedEntity"} +{"features":" {score:0.3971572799386617} ","formula":"resource:Music_recording_sales_certification","lexeme":"music recording sales certification","type":"NamedEntity"} +{"features":" {score:0.19172790675584056} ","formula":"!property:area","lexeme":"area","type":"DataProp"} +{"features":" {score:0.6703273238665586} ","formula":"resource:Europe","lexeme":"europe","type":"NamedEntity"} +{"features":" {score:0.2959099621073451} ","formula":"dbpedia:region","lexeme":"region","type":"ObjectProp"} +{"features":" {score:0.4372570114560367} ","formula":"resource:Middle_Ages","lexeme":"middle ages","type":"NamedEntity"} +{"features":" {score:0.17893260906040026} ","formula":"!property:continent","lexeme":"continent","type":"ObjProp"} +{"features":" {score:0.2959099621073451} ","formula":"property:region","lexeme":"region","type":"DataProp"} +{"features":" {score:0.17893260906040026} ","formula":"property:continent","lexeme":"continent","type":"ObjProp"} +{"features":" {score:0.14541114583315107} ","formula":"!property:economy","lexeme":"economy","type":"DataProp"} +{"features":" {score:0.06096718820401578} ","formula":"property:place","lexeme":"place","type":"ObjProp"} +{"features":" {score:0.2959099621073451} ","formula":"!property:region","lexeme":"region","type":"DataProp"} +{"features":" {score:0.2959099621073451} ","formula":"property:region","lexeme":"region","type":"ObjProp"} +{"features":" {score:0.19172790675584056} ","formula":"property:area","lexeme":"area","type":"ObjProp"} +{"features":" {score:0.04914569086494519} ","formula":"!property:market","lexeme":"market","type":"DataProp"} +{"features":" {score:0.06096718820401578} ","formula":"!property:place","lexeme":"place","type":"ObjProp"} +{"features":" {score:0.17893260906040026} ","formula":"!dbpedia:continent","lexeme":"continent","type":"ObjectProp"} +{"features":" {score:0.19172790675584056} ","formula":"(rdf:type dbpedia:Area)","lexeme":"area","type":"ClassNoun"} +{"features":" {score:0.19172790675584056} ","formula":"!property:area","lexeme":"area","type":"ObjProp"} +{"features":" {score:0.14541114583315107} ","formula":"!property:economy","lexeme":"economy","type":"ObjProp"} +{"features":" {score:0.24948306868373704} ","formula":"(rdf:type dbpedia:Continent)","lexeme":"continent","type":"ClassNoun"} +{"features":" {score:0.2959099621073451} ","formula":"!property:region","lexeme":"region","type":"ObjProp"} +{"features":" {score:0.04914569086494519} ","formula":"!property:market","lexeme":"market","type":"ObjProp"} +{"features":" {score:0.14541114583315107} ","formula":"property:economy","lexeme":"economy","type":"ObjProp"} +{"features":" {score:0.17893260906040026} ","formula":"dbpedia:continent","lexeme":"continent","type":"ObjectProp"} +{"features":" {score:0.3818665746476778} ","formula":"resource:UEFA_Europa_League","lexeme":"uefa europa league","type":"NamedEntity"} +{"features":" {score:0.14541114583315107} ","formula":"property:economy","lexeme":"economy","type":"DataProp"} +{"features":" {score:0.06096718820401578} ","formula":"(rdf:type dbpedia:Place)","lexeme":"place","type":"ClassNoun"} +{"features":" {score:0.17893260906040026} ","formula":"property:continent","lexeme":"continent","type":"DataProp"} +{"features":" {score:0.2959099621073451} ","formula":"!dbpedia:region","lexeme":"region","type":"ObjectProp"} +{"features":" {score:0.04914569086494519} ","formula":"property:market","lexeme":"market","type":"ObjProp"} +{"features":" {score:0.06096718820401578} ","formula":"property:place","lexeme":"place","type":"DataProp"} +{"features":" {score:0.19172790675584056} ","formula":"property:area","lexeme":"area","type":"DataProp"} +{"features":" {score:0.17893260906040026} ","formula":"!property:continent","lexeme":"continent","type":"DataProp"} +{"features":" {score:0.04914569086494519} ","formula":"property:market","lexeme":"market","type":"DataProp"} +{"features":" {score:0.2959099621073451} ","formula":"(rdf:type dbpedia:Region)","lexeme":"region","type":"ClassNoun"} +{"features":" {score:0.06096718820401578} ","formula":"!property:place","lexeme":"place","type":"DataProp"} +{"features":" {score:0.37337397287915275} ","formula":"resource:United_States_Navy","lexeme":"united states navy","type":"NamedEntity"} +{"features":" {score:0.013793234483649334} ","formula":"!property:location","lexeme":"location","type":"DataProp"} +{"features":" {score:0.3224235460515639} ","formula":"resource:U.S._state","lexeme":"u.s. state","type":"NamedEntity"} +{"features":" {score:0.3547119279351195} ","formula":"resource:American_Civil_War","lexeme":"american civil war","type":"NamedEntity"} +{"features":" {score:0.013793234483649334} ","formula":"property:location","lexeme":"location","type":"ObjProp"} +{"features":" {score:0.013793234483649334} ","formula":"dbpedia:location","lexeme":"location","type":"ObjectProp"} +{"features":" {score:0.021966824730237325} ","formula":"property:feature","lexeme":"feature","type":"DataProp"} +{"features":" {score:0.013793234483649334} ","formula":"!dbpedia:location","lexeme":"location","type":"ObjectProp"} +{"features":" {score:0.01683011555009418} ","formula":"property:abbreviation","lexeme":"abbreviation","type":"DataProp"} +{"features":" {score:0.01683011555009418} ","formula":"!property:abbreviation","lexeme":"abbreviation","type":"ObjProp"} +{"features":" {score:0.013793234483649334} ","formula":"property:location","lexeme":"location","type":"DataProp"} +{"features":" {score:0.021966824730237325} ","formula":"!property:feature","lexeme":"feature","type":"ObjProp"} +{"features":" {score:0.3780362175989992} ","formula":"resource:United_States_Census_Bureau","lexeme":"united states census bureau","type":"NamedEntity"} +{"features":" {score:0.013793234483649334} ","formula":"!property:location","lexeme":"location","type":"ObjProp"} +{"features":" {score:0.021966824730237325} ","formula":"property:feature","lexeme":"feature","type":"ObjProp"} +{"features":" {score:0.01683011555009418} ","formula":"!property:abbreviation","lexeme":"abbreviation","type":"DataProp"} +{"features":" {score:0.5118030180877406} ","formula":"resource:United_States","lexeme":"united states","type":"NamedEntity"} +{"features":" {score:0.021966824730237325} ","formula":"!property:feature","lexeme":"feature","type":"DataProp"} +{"features":" {score:0.01683011555009418} ","formula":"property:abbreviation","lexeme":"abbreviation","type":"ObjProp"} +{"features":" {score:0.39343532363954176} ","formula":"\u003chttp://dbpedia.org/resource/Salon_(website)\u003e","lexeme":"salon website","type":"NamedEntity"} +{"features":" {score:0.03681289980044732} ","formula":"!property:name","lexeme":"name","type":"ObjProp"} +{"features":" {score:0.023183089391543316} ","formula":"property:person","lexeme":"person","type":"ObjProp"} +{"features":" {score:0.3786297717788662} ","formula":"resource:Alexander_von_Humboldt","lexeme":"alexander von humboldt","type":"NamedEntity"} +{"features":" {score:0.01230769230769231} ","formula":"dbpedia:routeLine","lexeme":"line","type":"ObjectProp"} +{"features":" {score:0.05373960618789379} ","formula":"dbpedia:brand","lexeme":"brand","type":"ObjectProp"} +{"features":" {score:0.03681289980044732} ","formula":"property:name","lexeme":"name","type":"DataProp"} +{"features":" {score:0.3746308982221216} ","formula":"resource:Pope_Alexander_VI","lexeme":"pope alexander vi","type":"NamedEntity"} +{"features":" {score:0.05373960618789379} ","formula":"!property:brand","lexeme":"brand","type":"ObjProp"} +{"features":" {score:0.023183089391543316} ","formula":"!dbpedia:person","lexeme":"person","type":"ObjectProp"} +{"features":" {score:0.023183089391543316} ","formula":"!property:person","lexeme":"person","type":"ObjProp"} +{"features":" {score:0.05373960618789379} ","formula":"property:brand","lexeme":"brand","type":"ObjProp"} +{"features":" {score:0.01230769230769231} ","formula":"!property:line","lexeme":"line","type":"ObjProp"} +{"features":" {score:0.01230769230769231} ","formula":"!property:line","lexeme":"line","type":"DataProp"} +{"features":" {score:0.03681289980044732} ","formula":"!property:name","lexeme":"name","type":"DataProp"} +{"features":" {score:0.023183089391543316} ","formula":"!property:person","lexeme":"person","type":"DataProp"} +{"features":" {score:0.397716586460902} ","formula":"resource:Alec_Baldwin","lexeme":"alec baldwin","type":"NamedEntity"} +{"features":" {score:0.01230769230769231} ","formula":"property:line","lexeme":"line","type":"ObjProp"} +{"features":" {score:0.023183089391543316} ","formula":"property:person","lexeme":"person","type":"DataProp"} +{"features":" {score:0.05373960618789379} ","formula":"!dbpedia:brand","lexeme":"brand","type":"ObjectProp"} +{"features":" {score:0.03681289980044732} ","formula":"(rdf:type dbpedia:Name)","lexeme":"name","type":"ClassNoun"} +{"features":" {score:0.01230769230769231} ","formula":"property:line","lexeme":"line","type":"DataProp"} +{"features":" {score:0.5426921993804562} ","formula":"resource:Alex_Ferguson","lexeme":"alex ferguson","type":"NamedEntity"} +{"features":" {score:0.023183089391543316} ","formula":"dbpedia:person","lexeme":"person","type":"ObjectProp"} +{"features":" {score:0.13999229669570923} ","formula":"(rdf:type dbpedia:Wrestler)","lexeme":"wrestler","type":"ClassNoun"} +{"features":" {score:0.01230769230769231} ","formula":"!dbpedia:routeLine","lexeme":"line","type":"ObjectProp"} +{"features":" {score:0.03681289980044732} ","formula":"property:name","lexeme":"name","type":"ObjProp"} +{"features":" {score:0.05373960618789379} ","formula":"!property:brand","lexeme":"brand","type":"DataProp"} +{"features":" {score:0.023183089391543316} ","formula":"(rdf:type dbpedia:Person)","lexeme":"person","type":"ClassNoun"} +{"features":" {score:0.12696447372436523} ","formula":"(rdf:type dbpedia:Jockey)","lexeme":"jockey","type":"ClassNoun"} +{"features":" {score:0.05373960618789379} ","formula":"property:brand","lexeme":"brand","type":"DataProp"} +{"features":" {score:0.13098052740097046} ","formula":"(rdf:type dbpedia:Swimmer)","lexeme":"swimmer","type":"ClassNoun"} +{"features":" {score:0.39343532363954176} ","formula":"\u003chttp://dbpedia.org/resource/Salon_(website)\u003e","lexeme":"salon website","type":"NamedEntity"} +{"features":" {score:0.03681289980044732} ","formula":"!property:name","lexeme":"name","type":"ObjProp"} +{"features":" {score:0.023183089391543316} ","formula":"property:person","lexeme":"person","type":"ObjProp"} +{"features":" {score:0.3786297717788662} ","formula":"resource:Alexander_von_Humboldt","lexeme":"alexander von humboldt","type":"NamedEntity"} +{"features":" {score:0.01230769230769231} ","formula":"dbpedia:routeLine","lexeme":"line","type":"ObjectProp"} +{"features":" {score:0.05373960618789379} ","formula":"dbpedia:brand","lexeme":"brand","type":"ObjectProp"} +{"features":" {score:0.03681289980044732} ","formula":"property:name","lexeme":"name","type":"DataProp"} +{"features":" {score:0.3746308982221216} ","formula":"resource:Pope_Alexander_VI","lexeme":"pope alexander vi","type":"NamedEntity"} +{"features":" {score:0.05373960618789379} ","formula":"!property:brand","lexeme":"brand","type":"ObjProp"} +{"features":" {score:0.023183089391543316} ","formula":"!dbpedia:person","lexeme":"person","type":"ObjectProp"} +{"features":" {score:0.023183089391543316} ","formula":"!property:person","lexeme":"person","type":"ObjProp"} +{"features":" {score:0.05373960618789379} ","formula":"property:brand","lexeme":"brand","type":"ObjProp"} +{"features":" {score:0.01230769230769231} ","formula":"!property:line","lexeme":"line","type":"ObjProp"} +{"features":" {score:0.01230769230769231} ","formula":"!property:line","lexeme":"line","type":"DataProp"} +{"features":" {score:0.03681289980044732} ","formula":"!property:name","lexeme":"name","type":"DataProp"} +{"features":" {score:0.023183089391543316} ","formula":"!property:person","lexeme":"person","type":"DataProp"} +{"features":" {score:0.397716586460902} ","formula":"resource:Alec_Baldwin","lexeme":"alec baldwin","type":"NamedEntity"} +{"features":" {score:0.01230769230769231} ","formula":"property:line","lexeme":"line","type":"ObjProp"} +{"features":" {score:0.023183089391543316} ","formula":"property:person","lexeme":"person","type":"DataProp"} +{"features":" {score:0.05373960618789379} ","formula":"!dbpedia:brand","lexeme":"brand","type":"ObjectProp"} +{"features":" {score:0.03681289980044732} ","formula":"(rdf:type dbpedia:Name)","lexeme":"name","type":"ClassNoun"} +{"features":" {score:0.01230769230769231} ","formula":"property:line","lexeme":"line","type":"DataProp"} +{"features":" {score:0.5426921993804562} ","formula":"resource:Alex_Ferguson","lexeme":"alex ferguson","type":"NamedEntity"} +{"features":" {score:0.023183089391543316} ","formula":"dbpedia:person","lexeme":"person","type":"ObjectProp"} +{"features":" {score:0.13999229669570923} ","formula":"(rdf:type dbpedia:Wrestler)","lexeme":"wrestler","type":"ClassNoun"} +{"features":" {score:0.01230769230769231} ","formula":"!dbpedia:routeLine","lexeme":"line","type":"ObjectProp"} +{"features":" {score:0.03681289980044732} ","formula":"property:name","lexeme":"name","type":"ObjProp"} +{"features":" {score:0.05373960618789379} ","formula":"!property:brand","lexeme":"brand","type":"DataProp"} +{"features":" {score:0.023183089391543316} ","formula":"(rdf:type dbpedia:Person)","lexeme":"person","type":"ClassNoun"} +{"features":" {score:0.12696447372436523} ","formula":"(rdf:type dbpedia:Jockey)","lexeme":"jockey","type":"ClassNoun"} +{"features":" {score:0.05373960618789379} ","formula":"property:brand","lexeme":"brand","type":"DataProp"} +{"features":" {score:0.13098052740097046} ","formula":"(rdf:type dbpedia:Swimmer)","lexeme":"swimmer","type":"ClassNoun"} +{"features":" {score:0.39343532363954176} ","formula":"\u003chttp://dbpedia.org/resource/Salon_(website)\u003e","lexeme":"salon website","type":"NamedEntity"} +{"features":" {score:0.03681289980044732} ","formula":"!property:name","lexeme":"name","type":"ObjProp"} +{"features":" {score:0.023183089391543316} ","formula":"property:person","lexeme":"person","type":"ObjProp"} +{"features":" {score:0.3786297717788662} ","formula":"resource:Alexander_von_Humboldt","lexeme":"alexander von humboldt","type":"NamedEntity"} +{"features":" {score:0.01230769230769231} ","formula":"dbpedia:routeLine","lexeme":"line","type":"ObjectProp"} +{"features":" {score:0.05373960618789379} ","formula":"dbpedia:brand","lexeme":"brand","type":"ObjectProp"} +{"features":" {score:0.03681289980044732} ","formula":"property:name","lexeme":"name","type":"DataProp"} +{"features":" {score:0.3746308982221216} ","formula":"resource:Pope_Alexander_VI","lexeme":"pope alexander vi","type":"NamedEntity"} +{"features":" {score:0.05373960618789379} ","formula":"!property:brand","lexeme":"brand","type":"ObjProp"} +{"features":" {score:0.023183089391543316} ","formula":"!dbpedia:person","lexeme":"person","type":"ObjectProp"} +{"features":" {score:0.023183089391543316} ","formula":"!property:person","lexeme":"person","type":"ObjProp"} +{"features":" {score:0.05373960618789379} ","formula":"property:brand","lexeme":"brand","type":"ObjProp"} +{"features":" {score:0.01230769230769231} ","formula":"!property:line","lexeme":"line","type":"ObjProp"} +{"features":" {score:0.01230769230769231} ","formula":"!property:line","lexeme":"line","type":"DataProp"} +{"features":" {score:0.03681289980044732} ","formula":"!property:name","lexeme":"name","type":"DataProp"} +{"features":" {score:0.023183089391543316} ","formula":"!property:person","lexeme":"person","type":"DataProp"} +{"features":" {score:0.397716586460902} ","formula":"resource:Alec_Baldwin","lexeme":"alec baldwin","type":"NamedEntity"} +{"features":" {score:0.01230769230769231} ","formula":"property:line","lexeme":"line","type":"ObjProp"} +{"features":" {score:0.023183089391543316} ","formula":"property:person","lexeme":"person","type":"DataProp"} +{"features":" {score:0.05373960618789379} ","formula":"!dbpedia:brand","lexeme":"brand","type":"ObjectProp"} +{"features":" {score:0.03681289980044732} ","formula":"(rdf:type dbpedia:Name)","lexeme":"name","type":"ClassNoun"} +{"features":" {score:0.01230769230769231} ","formula":"property:line","lexeme":"line","type":"DataProp"} +{"features":" {score:0.5426921993804562} ","formula":"resource:Alex_Ferguson","lexeme":"alex ferguson","type":"NamedEntity"} +{"features":" {score:0.023183089391543316} ","formula":"dbpedia:person","lexeme":"person","type":"ObjectProp"} +{"features":" {score:0.13999229669570923} ","formula":"(rdf:type dbpedia:Wrestler)","lexeme":"wrestler","type":"ClassNoun"} +{"features":" {score:0.01230769230769231} ","formula":"!dbpedia:routeLine","lexeme":"line","type":"ObjectProp"} +{"features":" {score:0.03681289980044732} ","formula":"property:name","lexeme":"name","type":"ObjProp"} +{"features":" {score:0.05373960618789379} ","formula":"!property:brand","lexeme":"brand","type":"DataProp"} +{"features":" {score:0.023183089391543316} ","formula":"(rdf:type dbpedia:Person)","lexeme":"person","type":"ClassNoun"} +{"features":" {score:0.12696447372436523} ","formula":"(rdf:type dbpedia:Jockey)","lexeme":"jockey","type":"ClassNoun"} +{"features":" {score:0.05373960618789379} ","formula":"property:brand","lexeme":"brand","type":"DataProp"} +{"features":" {score:0.13098052740097046} ","formula":"(rdf:type dbpedia:Swimmer)","lexeme":"swimmer","type":"ClassNoun"} +{"features":" {score:0.02754881125994218} ","formula":"!property:market","lexeme":"market","type":"DataProp"} +{"features":" {score:0.02492670177649229} ","formula":"!property:place","lexeme":"place","type":"ObjProp"} +{"features":" {score:0.02754881125994218} ","formula":"!property:market","lexeme":"market","type":"ObjProp"} +{"features":" {score:0.03030440770662748} ","formula":"(rdf:type dbpedia:Area)","lexeme":"area","type":"ClassNoun"} +{"features":" {score:0.018827202090850245} ","formula":"dbpedia:jurisdiction","lexeme":"jurisdiction","type":"ObjectProp"} +{"features":" {score:0.03030440770662748} ","formula":"property:area","lexeme":"area","type":"ObjProp"} +{"features":" {score:0.018827202090850245} ","formula":"property:jurisdiction","lexeme":"jurisdiction","type":"ObjProp"} +{"features":" {score:0.02492670177649229} ","formula":"property:place","lexeme":"place","type":"DataProp"} +{"features":" {score:0.02754881125994218} ","formula":"property:market","lexeme":"market","type":"DataProp"} +{"features":" {score:0.03030440770662748} ","formula":"!property:area","lexeme":"area","type":"DataProp"} +{"features":" {score:0.02492670177649229} ","formula":"!property:place","lexeme":"place","type":"DataProp"} +{"features":" {score:0.018827202090850245} ","formula":"!property:jurisdiction","lexeme":"jurisdiction","type":"ObjProp"} +{"features":" {score:0.02492670177649229} ","formula":"(rdf:type dbpedia:Place)","lexeme":"place","type":"ClassNoun"} +{"features":" {score:0.07183589378992716} ","formula":"dbpedia:state","lexeme":"state","type":"ObjectProp"} +{"features":" {score:0.3449200540738764} ","formula":"resource:Las_Vegas_Valley","lexeme":"las vegas valley","type":"NamedEntity"} +{"features":" {score:0.07183589378992716} ","formula":"!property:state","lexeme":"state","type":"ObjProp"} +{"features":" {score:0.010833333333333334} ","formula":"!property:economy","lexeme":"economy","type":"ObjProp"} +{"features":" {score:0.036267271011303635} ","formula":"!property:nation","lexeme":"nation","type":"DataProp"} +{"features":" {score:0.5069101221863358} ","formula":"resource:United_States","lexeme":"united states","type":"NamedEntity"} +{"features":" {score:0.010833333333333334} ","formula":"property:economy","lexeme":"economy","type":"DataProp"} +{"features":" {score:0.036267271011303635} ","formula":"property:nation","lexeme":"nation","type":"DataProp"} +{"features":" {score:0.3376957938374635} ","formula":"resource:United_States_Army","lexeme":"united states army","type":"NamedEntity"} +{"features":" {score:0.1210140109062195} ","formula":"(rdf:type dbpedia:Community)","lexeme":"community","type":"ClassNoun"} +{"features":" {score:0.010833333333333334} ","formula":"!property:economy","lexeme":"economy","type":"DataProp"} +{"features":" {score:0.010833333333333334} ","formula":"property:economy","lexeme":"economy","type":"ObjProp"} +{"features":" {score:0.018827202090850245} ","formula":"!dbpedia:jurisdiction","lexeme":"jurisdiction","type":"ObjectProp"} +{"features":" {score:0.018827202090850245} ","formula":"!property:jurisdiction","lexeme":"jurisdiction","type":"DataProp"} +{"features":" {score:0.07183589378992716} ","formula":"property:state","lexeme":"state","type":"DataProp"} +{"features":" {score:0.07183589378992716} ","formula":"!property:state","lexeme":"state","type":"DataProp"} +{"features":" {score:0.02754881125994218} ","formula":"property:market","lexeme":"market","type":"ObjProp"} +{"features":" {score:0.036267271011303635} ","formula":"property:nation","lexeme":"nation","type":"ObjProp"} +{"features":" {score:0.3712715210874318} ","formula":"\u003chttp://dbpedia.org/resource/Georgia_(U.S._state)\u003e","lexeme":"georgia u.s. state","type":"NamedEntity"} +{"features":" {score:0.13348385095596313} ","formula":"(rdf:type dbpedia:Cave)","lexeme":"cave","type":"ClassNoun"} +{"features":" {score:0.018827202090850245} ","formula":"property:jurisdiction","lexeme":"jurisdiction","type":"DataProp"} +{"features":" {score:0.07183589378992716} ","formula":"property:state","lexeme":"state","type":"ObjProp"} +{"features":" {score:0.02492670177649229} ","formula":"property:place","lexeme":"place","type":"ObjProp"} +{"features":" {score:0.03030440770662748} ","formula":"property:area","lexeme":"area","type":"DataProp"} +{"features":" {score:0.07183589378992716} ","formula":"!dbpedia:state","lexeme":"state","type":"ObjectProp"} +{"features":" {score:0.13700512091318767} ","formula":"(rdf:type dbpedia:State)","lexeme":"state","type":"ClassNoun"} +{"features":" {score:0.036267271011303635} ","formula":"!property:nation","lexeme":"nation","type":"ObjProp"} +{"features":" {score:0.5019569461422774} ","formula":"resource:USA_Today","lexeme":"usa today","type":"NamedEntity"} +{"features":" {score:0.03030440770662748} ","formula":"!property:area","lexeme":"area","type":"ObjProp"} +{"features":" {score:0.5633483858744451} ","formula":"resource:FC_Bayern_Munich","lexeme":"fc bayern munich","type":"NamedEntity"} +{"features":" {score:0.0048526863084922016} ","formula":"property:film","lexeme":"film","type":"DataProp"} +{"features":" {score:0.15446644224988318} ","formula":"dbpedia:municipality","lexeme":"municipality","type":"ObjectProp"} +{"features":" {score:0.15446644224988318} ","formula":"!property:municipality","lexeme":"municipality","type":"ObjProp"} +{"features":" {score:0.006745657462310337} ","formula":"!property:university","lexeme":"university","type":"ObjProp"} +{"features":" {score:0.0200734452320266} ","formula":"!property:place","lexeme":"place","type":"ObjProp"} +{"features":" {score:0.006745657462310337} ","formula":"(rdf:type dbpedia:University)","lexeme":"university","type":"ClassNoun"} +{"features":" {score:0.2703449835345485} ","formula":"dbpedia:city","lexeme":"city","type":"ObjectProp"} +{"features":" {score:0.2703449835345485} ","formula":"property:city","lexeme":"city","type":"DataProp"} +{"features":" {score:0.0200734452320266} ","formula":"!property:place","lexeme":"place","type":"DataProp"} +{"features":" {score:0.0048526863084922016} ","formula":"!property:film","lexeme":"film","type":"DataProp"} +{"features":" {score:0.0200734452320266} ","formula":"property:place","lexeme":"place","type":"DataProp"} +{"features":" {score:0.2703449835345485} ","formula":"!property:city","lexeme":"city","type":"ObjProp"} +{"features":" {score:0.2703449835345485} ","formula":"!dbpedia:city","lexeme":"city","type":"ObjectProp"} +{"features":" {score:0.15446644224988318} ","formula":"!dbpedia:municipality","lexeme":"municipality","type":"ObjectProp"} +{"features":" {score:0.5245180850163047} ","formula":"resource:Munich_Agreement","lexeme":"munich agreement","type":"NamedEntity"} +{"features":" {score:0.0200734452320266} ","formula":"property:place","lexeme":"place","type":"ObjProp"} +{"features":" {score:0.6420831407783865} ","formula":"resource:Munich","lexeme":"munich","type":"NamedEntity"} +{"features":" {score:0.5336177996667898} ","formula":"resource:Ludwig_Maximilian_University_of_Munich","lexeme":"ludwig maximilian university of munich","type":"NamedEntity"} +{"features":" {score:0.15446644224988318} ","formula":"(rdf:type dbpedia:Municipality)","lexeme":"municipality","type":"ClassNoun"} +{"features":" {score:0.15446644224988318} ","formula":"!property:municipality","lexeme":"municipality","type":"DataProp"} +{"features":" {score:0.15446644224988318} ","formula":"property:municipality","lexeme":"municipality","type":"ObjProp"} +{"features":" {score:0.394651691061635} ","formula":"resource:1972_Summer_Olympics","lexeme":"1972 summer olympics","type":"NamedEntity"} +{"features":" {score:0.006745657462310337} ","formula":"property:university","lexeme":"university","type":"ObjProp"} +{"features":" {score:0.2703449835345485} ","formula":"!property:city","lexeme":"city","type":"DataProp"} +{"features":" {score:0.15446644224988318} ","formula":"property:municipality","lexeme":"municipality","type":"DataProp"} +{"features":" {score:0.0200734452320266} ","formula":"(rdf:type dbpedia:Place)","lexeme":"place","type":"ClassNoun"} +{"features":" {score:0.006745657462310337} ","formula":"!dbpedia:university","lexeme":"university","type":"ObjectProp"} +{"features":" {score:0.0048526863084922016} ","formula":"property:film","lexeme":"film","type":"ObjProp"} +{"features":" {score:0.0048526863084922016} ","formula":"!property:film","lexeme":"film","type":"ObjProp"} +{"features":" {score:0.0048526863084922016} ","formula":"!dbpedia:film","lexeme":"film","type":"ObjectProp"} +{"features":" {score:0.0048526863084922016} ","formula":"dbpedia:film","lexeme":"film","type":"ObjectProp"} +{"features":" {score:0.2703449835345485} ","formula":"(rdf:type dbpedia:City)","lexeme":"city","type":"ClassNoun"} +{"features":" {score:0.006745657462310337} ","formula":"dbpedia:university","lexeme":"university","type":"ObjectProp"} +{"features":" {score:0.05713644355625896} ","formula":"(rdf:type dbpedia:Airport)","lexeme":"airport","type":"ClassNoun"} +{"features":" {score:0.2703449835345485} ","formula":"property:city","lexeme":"city","type":"ObjProp"} +{"features":" {score:0.006745657462310337} ","formula":"!property:university","lexeme":"university","type":"DataProp"} +{"features":" {score:0.006745657462310337} ","formula":"property:university","lexeme":"university","type":"DataProp"} +{"features":" {score:0.024354053257352713} ","formula":"property:economy","lexeme":"economy","type":"ObjProp"} +{"features":" {score:0.024354053257352713} ","formula":"property:economy","lexeme":"economy","type":"DataProp"} +{"features":" {score:0.019684884847898314} ","formula":"property:case","lexeme":"case","type":"ObjProp"} +{"features":" {score:0.04119084299478716} ","formula":"!property:nation","lexeme":"nation","type":"DataProp"} +{"features":" {score:0.04307977245656418} ","formula":"property:state","lexeme":"state","type":"DataProp"} +{"features":" {score:0.018446601941747572} ","formula":"!property:market","lexeme":"market","type":"DataProp"} +{"features":" {score:0.04307977245656418} ","formula":"!property:state","lexeme":"state","type":"ObjProp"} +{"features":" {score:0.019684884847898314} ","formula":"!property:case","lexeme":"case","type":"DataProp"} +{"features":" {score:0.12119717597961427} ","formula":"dbpedia:kingdom","lexeme":"kingdom","type":"ObjectProp"} +{"features":" {score:0.02330097087378641} ","formula":"(rdf:type dbpedia:Place)","lexeme":"place","type":"ClassNoun"} +{"features":" {score:0.019684884847898314} ","formula":"!property:case","lexeme":"case","type":"ObjProp"} +{"features":" {score:0.02330097087378641} ","formula":"!property:place","lexeme":"place","type":"DataProp"} +{"features":" {score:0.04307977245656418} ","formula":"dbpedia:state","lexeme":"state","type":"ObjectProp"} +{"features":" {score:0.02330097087378641} ","formula":"property:place","lexeme":"place","type":"ObjProp"} +{"features":" {score:0.019684884847898314} ","formula":"property:case","lexeme":"case","type":"DataProp"} +{"features":" {score:0.12119717597961427} ","formula":"!dbpedia:kingdom","lexeme":"kingdom","type":"ObjectProp"} +{"features":" {score:0.04307977245656418} ","formula":"property:state","lexeme":"state","type":"ObjProp"} +{"features":" {score:0.018446601941747572} ","formula":"property:market","lexeme":"market","type":"DataProp"} +{"features":" {score:0.024354053257352713} ","formula":"!property:economy","lexeme":"economy","type":"ObjProp"} +{"features":" {score:0.3600622212941572} ","formula":"\u003chttp://dbpedia.org/resource/Galicia_(Eastern_Europe)\u003e","lexeme":"galicia eastern europe","type":"NamedEntity"} +{"features":" {score:0.04119084299478716} ","formula":"!property:nation","lexeme":"nation","type":"ObjProp"} +{"features":" {score:0.3138386448463968} ","formula":"resource:Odessa","lexeme":"odessa","type":"NamedEntity"} +{"features":" {score:0.04119084299478716} ","formula":"property:nation","lexeme":"nation","type":"DataProp"} +{"features":" {score:0.024354053257352713} ","formula":"!property:economy","lexeme":"economy","type":"DataProp"} +{"features":" {score:0.018446601941747572} ","formula":"property:market","lexeme":"market","type":"ObjProp"} +{"features":" {score:0.38531734665303335} ","formula":"resource:Ukrainian_Soviet_Socialist_Republic","lexeme":"ukrainian soviet socialist republic","type":"NamedEntity"} +{"features":" {score:0.04307977245656418} ","formula":"!dbpedia:state","lexeme":"state","type":"ObjectProp"} +{"features":" {score:0.3847475641953887} ","formula":"resource:Kiev","lexeme":"kiev","type":"NamedEntity"} +{"features":" {score:0.04307977245656418} ","formula":"!property:state","lexeme":"state","type":"DataProp"} +{"features":" {score:0.6268662072925639} ","formula":"resource:Ukraine","lexeme":"ukraine","type":"NamedEntity"} +{"features":" {score:0.04119084299478716} ","formula":"property:nation","lexeme":"nation","type":"ObjProp"} +{"features":" {score:0.02330097087378641} ","formula":"!property:place","lexeme":"place","type":"ObjProp"} +{"features":" {score:0.04307977245656418} ","formula":"(rdf:type dbpedia:State)","lexeme":"state","type":"ClassNoun"} +{"features":" {score:0.019684884847898314} ","formula":"(rdf:type dbpedia:Case)","lexeme":"case","type":"ClassNoun"} +{"features":" {score:0.02330097087378641} ","formula":"property:place","lexeme":"place","type":"DataProp"} +{"features":" {score:0.018446601941747572} ","formula":"!property:market","lexeme":"market","type":"ObjProp"} +{"features":" {score:0.5197176288417931} ","formula":"!property:name","lexeme":"name","type":"ObjProp"} +{"features":" {score:0.6084271220137483} ","formula":"resource:Bob_Dylan","lexeme":"bob dylan","type":"NamedEntity"} +{"features":" {score:0.5197176288417931} ","formula":"property:name","lexeme":"name","type":"ObjProp"} +{"features":" {score:0.13272552490234377} ","formula":"(rdf:type dbpedia:Comedian)","lexeme":"comedian","type":"ClassNoun"} +{"features":" {score:0.13186320699751378} ","formula":"(rdf:type dbpedia:Wrestler)","lexeme":"wrestler","type":"ClassNoun"} +{"features":" {score:0.08796091386892277} ","formula":"(rdf:type dbpedia:Person)","lexeme":"person","type":"ClassNoun"} +{"features":" {score:0.03137576233741292} ","formula":"property:student","lexeme":"student","type":"ObjProp"} +{"features":" {score:0.08796091386892277} ","formula":"property:person","lexeme":"person","type":"ObjProp"} +{"features":" {score:0.08796091386892277} ","formula":"!property:person","lexeme":"person","type":"ObjProp"} +{"features":" {score:0.13504673363640904} ","formula":"(rdf:type dbpedia:Jockey)","lexeme":"jockey","type":"ClassNoun"} +{"features":" {score:0.08796091386892277} ","formula":"property:person","lexeme":"person","type":"DataProp"} +{"features":" {score:0.03137576233741292} ","formula":"!property:student","lexeme":"student","type":"DataProp"} +{"features":" {score:0.5197176288417931} ","formula":"property:name","lexeme":"name","type":"DataProp"} +{"features":" {score:0.5197176288417931} ","formula":"(rdf:type dbpedia:Name)","lexeme":"name","type":"ClassNoun"} +{"features":" {score:0.5398806299023015} ","formula":"resource:Bob_Hope","lexeme":"bob hope","type":"NamedEntity"} +{"features":" {score:0.08796091386892277} ","formula":"!dbpedia:person","lexeme":"person","type":"ObjectProp"} +{"features":" {score:0.5197176288417931} ","formula":"!property:name","lexeme":"name","type":"DataProp"} +{"features":" {score:0.061251357772163846} ","formula":"(rdf:type dbpedia:Artist)","lexeme":"artist","type":"ClassNoun"} +{"features":" {score:0.45588200764843745} ","formula":"resource:Robert_De_Niro","lexeme":"robert de niro","type":"NamedEntity"} +{"features":" {score:0.08796091386892277} ","formula":"!property:person","lexeme":"person","type":"DataProp"} +{"features":" {score:0.03137576233741292} ","formula":"!property:student","lexeme":"student","type":"ObjProp"} +{"features":" {score:0.3332550072731342} ","formula":"resource:Bobsleigh","lexeme":"bobsleigh","type":"NamedEntity"} +{"features":" {score:0.5361657367614264} ","formula":"resource:Bob_Marley","lexeme":"bob marley","type":"NamedEntity"} +{"features":" {score:0.08796091386892277} ","formula":"dbpedia:person","lexeme":"person","type":"ObjectProp"} +{"features":" {score:0.03137576233741292} ","formula":"property:student","lexeme":"student","type":"DataProp"} +{"features":" {score:0.039105719999382775} ","formula":"(rdf:type dbpedia:Airport)","lexeme":"airport","type":"ClassNoun"} +{"features":" {score:0.0048526863084922016} ","formula":"property:film","lexeme":"film","type":"DataProp"} +{"features":" {score:0.006745657462310337} ","formula":"(rdf:type dbpedia:University)","lexeme":"university","type":"ClassNoun"} +{"features":" {score:0.06491494770435727} ","formula":"!property:institution","lexeme":"institution","type":"DataProp"} +{"features":" {score:0.13518829246017713} ","formula":"(rdf:type dbpedia:City)","lexeme":"city","type":"ClassNoun"} +{"features":" {score:0.13518829246017713} ","formula":"!property:city","lexeme":"city","type":"ObjProp"} +{"features":" {score:0.02476466395722725} ","formula":"property:municipality","lexeme":"municipality","type":"DataProp"} +{"features":" {score:0.007118905612640406} ","formula":"property:place","lexeme":"place","type":"ObjProp"} +{"features":" {score:0.02476466395722725} ","formula":"!dbpedia:municipality","lexeme":"municipality","type":"ObjectProp"} +{"features":" {score:0.007118905612640406} ","formula":"(rdf:type dbpedia:Place)","lexeme":"place","type":"ClassNoun"} +{"features":" {score:0.06491494770435727} ","formula":"property:institution","lexeme":"institution","type":"DataProp"} +{"features":" {score:0.02476466395722725} ","formula":"!property:municipality","lexeme":"municipality","type":"ObjProp"} +{"features":" {score:0.6285851188338059} ","formula":"resource:Texas_Tech_University","lexeme":"texas tech university","type":"NamedEntity"} +{"features":" {score:0.34189207904479085} ","formula":"!property:university","lexeme":"university","type":"DataProp"} +{"features":" {score:0.6252712786778605} ","formula":"resource:Private_university","lexeme":"private university","type":"NamedEntity"} +{"features":" {score:0.06491494770435727} ","formula":"!property:institution","lexeme":"institution","type":"ObjProp"} +{"features":" {score:0.0048526863084922016} ","formula":"!property:film","lexeme":"film","type":"ObjProp"} +{"features":" {score:0.34189207904479085} ","formula":"property:university","lexeme":"university","type":"DataProp"} +{"features":" {score:0.3574573272887659} ","formula":"resource:1972_Summer_Olympics","lexeme":"1972 summer olympics","type":"NamedEntity"} +{"features":" {score:0.0048526863084922016} ","formula":"dbpedia:film","lexeme":"film","type":"ObjectProp"} +{"features":" {score:0.13518829246017713} ","formula":"dbpedia:city","lexeme":"city","type":"ObjectProp"} +{"features":" {score:0.4527074563224413} ","formula":"resource:ETH_Zurich","lexeme":"eth zurich","type":"NamedEntity"} +{"features":" {score:0.5069005576208179} ","formula":"resource:Munich_Agreement","lexeme":"munich agreement","type":"NamedEntity"} +{"features":" {score:0.539723393814838} ","formula":"resource:Rensselaer_Polytechnic_Institute","lexeme":"rensselaer polytechnic institute","type":"NamedEntity"} +{"features":" {score:0.007118905612640406} ","formula":"!property:place","lexeme":"place","type":"ObjProp"} +{"features":" {score:0.6278378455727189} ","formula":"resource:Saint_Petersburg_State_University","lexeme":"saint petersburg state university","type":"NamedEntity"} +{"features":" {score:0.13518829246017713} ","formula":"property:city","lexeme":"city","type":"DataProp"} +{"features":" {score:0.006745657462310337} ","formula":"!property:university","lexeme":"university","type":"ObjProp"} +{"features":" {score:0.34189207904479085} ","formula":"(rdf:type dbpedia:University)","lexeme":"university","type":"ClassNoun"} +{"features":" {score:0.34189207904479085} ","formula":"property:university","lexeme":"university","type":"ObjProp"} +{"features":" {score:0.06491494770435727} ","formula":"dbpedia:institution","lexeme":"institution","type":"ObjectProp"} +{"features":" {score:0.13518829246017713} ","formula":"!dbpedia:city","lexeme":"city","type":"ObjectProp"} +{"features":" {score:0.007118905612640406} ","formula":"!property:place","lexeme":"place","type":"DataProp"} +{"features":" {score:0.0048526863084922016} ","formula":"!property:film","lexeme":"film","type":"DataProp"} +{"features":" {score:0.6244656133828996} ","formula":"resource:Munich","lexeme":"munich","type":"NamedEntity"} +{"features":" {score:0.02476466395722725} ","formula":"dbpedia:municipality","lexeme":"municipality","type":"ObjectProp"} +{"features":" {score:0.34189207904479085} ","formula":"!property:university","lexeme":"university","type":"ObjProp"} +{"features":" {score:0.34189207904479085} ","formula":"dbpedia:university","lexeme":"university","type":"ObjectProp"} +{"features":" {score:0.5156482342007435} ","formula":"resource:Ludwig_Maximilian_University_of_Munich","lexeme":"ludwig maximilian university of munich","type":"NamedEntity"} +{"features":" {score:0.34189207904479085} ","formula":"!dbpedia:university","lexeme":"university","type":"ObjectProp"} +{"features":" {score:0.006745657462310337} ","formula":"property:university","lexeme":"university","type":"ObjProp"} +{"features":" {score:0.006745657462310337} ","formula":"!dbpedia:university","lexeme":"university","type":"ObjectProp"} +{"features":" {score:0.0048526863084922016} ","formula":"property:film","lexeme":"film","type":"ObjProp"} +{"features":" {score:0.0048526863084922016} ","formula":"!dbpedia:film","lexeme":"film","type":"ObjectProp"} +{"features":" {score:0.06491494770435727} ","formula":"property:institution","lexeme":"institution","type":"ObjProp"} +{"features":" {score:0.006745657462310337} ","formula":"dbpedia:university","lexeme":"university","type":"ObjectProp"} +{"features":" {score:0.02476466395722725} ","formula":"!property:municipality","lexeme":"municipality","type":"DataProp"} +{"features":" {score:0.06491494770435727} ","formula":"!dbpedia:institution","lexeme":"institution","type":"ObjectProp"} +{"features":" {score:0.02476466395722725} ","formula":"(rdf:type dbpedia:Municipality)","lexeme":"municipality","type":"ClassNoun"} +{"features":" {score:0.006745657462310337} ","formula":"!property:university","lexeme":"university","type":"DataProp"} +{"features":" {score:0.02476466395722725} ","formula":"property:municipality","lexeme":"municipality","type":"ObjProp"} +{"features":" {score:0.007118905612640406} ","formula":"property:place","lexeme":"place","type":"DataProp"} +{"features":" {score:0.5222235130111524} ","formula":"resource:FC_Bayern_Munich","lexeme":"fc bayern munich","type":"NamedEntity"} +{"features":" {score:0.13518829246017713} ","formula":"property:city","lexeme":"city","type":"ObjProp"} +{"features":" {score:0.13518829246017713} ","formula":"!property:city","lexeme":"city","type":"DataProp"} +{"features":" {score:0.006745657462310337} ","formula":"property:university","lexeme":"university","type":"DataProp"} +{"features":" {score:0.46914285714285714} ","formula":"resource:Alona_Bondarenko","lexeme":"alona bondarenko","type":"NamedEntity"} +{"features":" {score:0.32234833338271296} ","formula":"resource:Alona_Tal","lexeme":"alona tal","type":"NamedEntity"} +{"features":" {score:0.34205261966160366} ","formula":"resource:Alona_Regional_Council","lexeme":"alona regional council","type":"NamedEntity"} +{"features":" {score:0.30342857142857144} ","formula":"resource:Olena_Dvornichenko","lexeme":"olena dvornichenko","type":"NamedEntity"} +{"features":" {score:0.30228571428571427} ","formula":"resource:Alona_Alegre","lexeme":"alona alegre","type":"NamedEntity"} +{"features":" {score:0.46914285714285714} ","formula":"resource:Alona_Bondarenko","lexeme":"alona bondarenko","type":"NamedEntity"} +{"features":" {score:0.32234833338271296} ","formula":"resource:Alona_Tal","lexeme":"alona tal","type":"NamedEntity"} +{"features":" {score:0.34205261966160366} ","formula":"resource:Alona_Regional_Council","lexeme":"alona regional council","type":"NamedEntity"} +{"features":" {score:0.30342857142857144} ","formula":"resource:Olena_Dvornichenko","lexeme":"olena dvornichenko","type":"NamedEntity"} +{"features":" {score:0.30228571428571427} ","formula":"resource:Alona_Alegre","lexeme":"alona alegre","type":"NamedEntity"} +{"features":" {score:0.46914285714285714} ","formula":"resource:Alona_Bondarenko","lexeme":"alona bondarenko","type":"NamedEntity"} +{"features":" {score:0.32234833338271296} ","formula":"resource:Alona_Tal","lexeme":"alona tal","type":"NamedEntity"} +{"features":" {score:0.34205261966160366} ","formula":"resource:Alona_Regional_Council","lexeme":"alona regional council","type":"NamedEntity"} +{"features":" {score:0.30342857142857144} ","formula":"resource:Olena_Dvornichenko","lexeme":"olena dvornichenko","type":"NamedEntity"} +{"features":" {score:0.30228571428571427} ","formula":"resource:Alona_Alegre","lexeme":"alona alegre","type":"NamedEntity"} +{"features":" {score:0.3} ","formula":"resource:Mihir_Rakshit","lexeme":"mihir rakshit","type":"NamedEntity"} +{"features":" {score:0.3} ","formula":"resource:Tushar_Rakshit","lexeme":"tushar rakshit","type":"NamedEntity"} +{"features":" {score:0.08495274583498637} ","formula":"dbpedia:bird","lexeme":"bird","type":"ObjectProp"} +{"features":" {score:0.08495274583498637} ","formula":"!dbpedia:bird","lexeme":"bird","type":"ObjectProp"} +{"features":" {score:0.08495274583498637} ","formula":"(rdf:type dbpedia:Bird)","lexeme":"bird","type":"ClassNoun"} +{"features":" {score:0.3576923076923077} ","formula":"resource:Maasina_Ruru","lexeme":"maasina ruru","type":"NamedEntity"} +{"features":" {score:0.010526315789473684} ","formula":"property:word","lexeme":"word","type":"ObjProp"} +{"features":" {score:0.1044997806611814} ","formula":"(rdf:type dbpedia:Town)","lexeme":"town","type":"ClassNoun"} +{"features":" {score:0.4617332560218821} ","formula":"resource:Yeah_Yeah_Yeahs","lexeme":"yeah yeah yeahs","type":"NamedEntity"} +{"features":" {score:0.010526315789473684} ","formula":"!property:word","lexeme":"word","type":"ObjProp"} +{"features":" {score:0.010526315789473684} ","formula":"!property:word","lexeme":"word","type":"DataProp"} +{"features":" {score:0.36860687021256944} ","formula":"resource:Clap_Your_Hands_Say_Yeah","lexeme":"clap your hands say yeah","type":"NamedEntity"} +{"features":" {score:0.3732392820973618} ","formula":"\u003chttp://dbpedia.org/resource/Yea,_Victoria\u003e","lexeme":"yea, victoria","type":"NamedEntity"} +{"features":" {score:0.010526315789473684} ","formula":"property:word","lexeme":"word","type":"DataProp"} +{"features":" {score:0.02567163814449966} ","formula":"property:economy","lexeme":"economy","type":"DataProp"} +{"features":" {score:0.08450248734030909} ","formula":"property:nation","lexeme":"nation","type":"DataProp"} +{"features":" {score:0.0587563043972628} ","formula":"property:state","lexeme":"state","type":"ObjProp"} +{"features":" {score:0.655103930106647} ","formula":"resource:Ukraine","lexeme":"ukraine","type":"NamedEntity"} +{"features":" {score:0.018446601941747572} ","formula":"!property:market","lexeme":"market","type":"DataProp"} +{"features":" {score:0.415187410413021} ","formula":"resource:Kiev","lexeme":"kiev","type":"NamedEntity"} +{"features":" {score:0.1350558975711465} ","formula":"dbpedia:kingdom","lexeme":"kingdom","type":"ObjectProp"} +{"features":" {score:0.026219150202174017} ","formula":"property:case","lexeme":"case","type":"DataProp"} +{"features":" {score:0.0587563043972628} ","formula":"(rdf:type dbpedia:State)","lexeme":"state","type":"ClassNoun"} +{"features":" {score:0.035429939596904714} ","formula":"!property:place","lexeme":"place","type":"ObjProp"} +{"features":" {score:0.08450248734030909} ","formula":"property:nation","lexeme":"nation","type":"ObjProp"} +{"features":" {score:0.018446601941747572} ","formula":"property:market","lexeme":"market","type":"DataProp"} +{"features":" {score:0.02567163814449966} ","formula":"!property:economy","lexeme":"economy","type":"ObjProp"} +{"features":" {score:0.3600622212941572} ","formula":"\u003chttp://dbpedia.org/resource/Galicia_(Eastern_Europe)\u003e","lexeme":"galicia eastern europe","type":"NamedEntity"} +{"features":" {score:0.08450248734030909} ","formula":"!property:nation","lexeme":"nation","type":"ObjProp"} +{"features":" {score:0.0587563043972628} ","formula":"!dbpedia:state","lexeme":"state","type":"ObjectProp"} +{"features":" {score:0.035429939596904714} ","formula":"property:place","lexeme":"place","type":"ObjProp"} +{"features":" {score:0.0587563043972628} ","formula":"!property:state","lexeme":"state","type":"DataProp"} +{"features":" {score:0.035429939596904714} ","formula":"property:place","lexeme":"place","type":"DataProp"} +{"features":" {score:0.1350558975711465} ","formula":"!dbpedia:kingdom","lexeme":"kingdom","type":"ObjectProp"} +{"features":" {score:0.035429939596904714} ","formula":"(rdf:type dbpedia:Place)","lexeme":"place","type":"ClassNoun"} +{"features":" {score:0.02567163814449966} ","formula":"property:economy","lexeme":"economy","type":"ObjProp"} +{"features":" {score:0.02567163814449966} ","formula":"!property:economy","lexeme":"economy","type":"DataProp"} +{"features":" {score:0.3138386448463968} ","formula":"resource:Odessa","lexeme":"odessa","type":"NamedEntity"} +{"features":" {score:0.0587563043972628} ","formula":"property:state","lexeme":"state","type":"DataProp"} +{"features":" {score:0.035429939596904714} ","formula":"!property:place","lexeme":"place","type":"DataProp"} +{"features":" {score:0.026219150202174017} ","formula":"(rdf:type dbpedia:Case)","lexeme":"case","type":"ClassNoun"} +{"features":" {score:0.018446601941747572} ","formula":"property:market","lexeme":"market","type":"ObjProp"} +{"features":" {score:0.026219150202174017} ","formula":"!property:case","lexeme":"case","type":"DataProp"} +{"features":" {score:0.0587563043972628} ","formula":"dbpedia:state","lexeme":"state","type":"ObjectProp"} +{"features":" {score:0.0587563043972628} ","formula":"!property:state","lexeme":"state","type":"ObjProp"} +{"features":" {score:0.026219150202174017} ","formula":"property:case","lexeme":"case","type":"ObjProp"} +{"features":" {score:0.018446601941747572} ","formula":"!property:market","lexeme":"market","type":"ObjProp"} +{"features":" {score:0.08450248734030909} ","formula":"!property:nation","lexeme":"nation","type":"DataProp"} +{"features":" {score:0.48692732175259695} ","formula":"resource:Ukrainian_Soviet_Socialist_Republic","lexeme":"ukrainian soviet socialist republic","type":"NamedEntity"} +{"features":" {score:0.026219150202174017} ","formula":"!property:case","lexeme":"case","type":"ObjProp"} +{"features":" {score:0.039105719999382775} ","formula":"(rdf:type dbpedia:Airport)","lexeme":"airport","type":"ClassNoun"} +{"features":" {score:0.0048526863084922016} ","formula":"property:film","lexeme":"film","type":"DataProp"} +{"features":" {score:0.13518829246017713} ","formula":"property:city","lexeme":"city","type":"DataProp"} +{"features":" {score:0.006745657462310337} ","formula":"!property:university","lexeme":"university","type":"ObjProp"} +{"features":" {score:0.006745657462310337} ","formula":"(rdf:type dbpedia:University)","lexeme":"university","type":"ClassNoun"} +{"features":" {score:0.13518829246017713} ","formula":"(rdf:type dbpedia:City)","lexeme":"city","type":"ClassNoun"} +{"features":" {score:0.13518829246017713} ","formula":"!dbpedia:city","lexeme":"city","type":"ObjectProp"} +{"features":" {score:0.13518829246017713} ","formula":"!property:city","lexeme":"city","type":"ObjProp"} +{"features":" {score:0.02476466395722725} ","formula":"property:municipality","lexeme":"municipality","type":"DataProp"} +{"features":" {score:0.007118905612640406} ","formula":"!property:place","lexeme":"place","type":"DataProp"} +{"features":" {score:0.0048526863084922016} ","formula":"!property:film","lexeme":"film","type":"DataProp"} +{"features":" {score:0.6244656133828996} ","formula":"resource:Munich","lexeme":"munich","type":"NamedEntity"} +{"features":" {score:0.007118905612640406} ","formula":"property:place","lexeme":"place","type":"ObjProp"} +{"features":" {score:0.02476466395722725} ","formula":"dbpedia:municipality","lexeme":"municipality","type":"ObjectProp"} +{"features":" {score:0.02476466395722725} ","formula":"!dbpedia:municipality","lexeme":"municipality","type":"ObjectProp"} +{"features":" {score:0.007118905612640406} ","formula":"(rdf:type dbpedia:Place)","lexeme":"place","type":"ClassNoun"} +{"features":" {score:0.5156482342007435} ","formula":"resource:Ludwig_Maximilian_University_of_Munich","lexeme":"ludwig maximilian university of munich","type":"NamedEntity"} +{"features":" {score:0.02476466395722725} ","formula":"!property:municipality","lexeme":"municipality","type":"ObjProp"} +{"features":" {score:0.006745657462310337} ","formula":"property:university","lexeme":"university","type":"ObjProp"} +{"features":" {score:0.006745657462310337} ","formula":"!dbpedia:university","lexeme":"university","type":"ObjectProp"} +{"features":" {score:0.0048526863084922016} ","formula":"property:film","lexeme":"film","type":"ObjProp"} +{"features":" {score:0.0048526863084922016} ","formula":"!property:film","lexeme":"film","type":"ObjProp"} +{"features":" {score:0.3574573272887659} ","formula":"resource:1972_Summer_Olympics","lexeme":"1972 summer olympics","type":"NamedEntity"} +{"features":" {score:0.0048526863084922016} ","formula":"!dbpedia:film","lexeme":"film","type":"ObjectProp"} +{"features":" {score:0.0048526863084922016} ","formula":"dbpedia:film","lexeme":"film","type":"ObjectProp"} +{"features":" {score:0.13518829246017713} ","formula":"dbpedia:city","lexeme":"city","type":"ObjectProp"} +{"features":" {score:0.006745657462310337} ","formula":"dbpedia:university","lexeme":"university","type":"ObjectProp"} +{"features":" {score:0.02476466395722725} ","formula":"!property:municipality","lexeme":"municipality","type":"DataProp"} +{"features":" {score:0.5069005576208179} ","formula":"resource:Munich_Agreement","lexeme":"munich agreement","type":"NamedEntity"} +{"features":" {score:0.02476466395722725} ","formula":"(rdf:type dbpedia:Municipality)","lexeme":"municipality","type":"ClassNoun"} +{"features":" {score:0.006745657462310337} ","formula":"!property:university","lexeme":"university","type":"DataProp"} +{"features":" {score:0.02476466395722725} ","formula":"property:municipality","lexeme":"municipality","type":"ObjProp"} +{"features":" {score:0.007118905612640406} ","formula":"property:place","lexeme":"place","type":"DataProp"} +{"features":" {score:0.5222235130111524} ","formula":"resource:FC_Bayern_Munich","lexeme":"fc bayern munich","type":"NamedEntity"} +{"features":" {score:0.13518829246017713} ","formula":"property:city","lexeme":"city","type":"ObjProp"} +{"features":" {score:0.13518829246017713} ","formula":"!property:city","lexeme":"city","type":"DataProp"} +{"features":" {score:0.007118905612640406} ","formula":"!property:place","lexeme":"place","type":"ObjProp"} +{"features":" {score:0.006745657462310337} ","formula":"property:university","lexeme":"university","type":"DataProp"} +{"features":" {score:0.039105719999382775} ","formula":"(rdf:type dbpedia:Airport)","lexeme":"airport","type":"ClassNoun"} +{"features":" {score:0.0048526863084922016} ","formula":"property:film","lexeme":"film","type":"DataProp"} +{"features":" {score:0.13518829246017713} ","formula":"property:city","lexeme":"city","type":"DataProp"} +{"features":" {score:0.006745657462310337} ","formula":"!property:university","lexeme":"university","type":"ObjProp"} +{"features":" {score:0.006745657462310337} ","formula":"(rdf:type dbpedia:University)","lexeme":"university","type":"ClassNoun"} +{"features":" {score:0.13518829246017713} ","formula":"(rdf:type dbpedia:City)","lexeme":"city","type":"ClassNoun"} +{"features":" {score:0.13518829246017713} ","formula":"!dbpedia:city","lexeme":"city","type":"ObjectProp"} +{"features":" {score:0.13518829246017713} ","formula":"!property:city","lexeme":"city","type":"ObjProp"} +{"features":" {score:0.02476466395722725} ","formula":"property:municipality","lexeme":"municipality","type":"DataProp"} +{"features":" {score:0.007118905612640406} ","formula":"!property:place","lexeme":"place","type":"DataProp"} +{"features":" {score:0.0048526863084922016} ","formula":"!property:film","lexeme":"film","type":"DataProp"} +{"features":" {score:0.6244656133828996} ","formula":"resource:Munich","lexeme":"munich","type":"NamedEntity"} +{"features":" {score:0.007118905612640406} ","formula":"property:place","lexeme":"place","type":"ObjProp"} +{"features":" {score:0.02476466395722725} ","formula":"dbpedia:municipality","lexeme":"municipality","type":"ObjectProp"} +{"features":" {score:0.02476466395722725} ","formula":"!dbpedia:municipality","lexeme":"municipality","type":"ObjectProp"} +{"features":" {score:0.007118905612640406} ","formula":"(rdf:type dbpedia:Place)","lexeme":"place","type":"ClassNoun"} +{"features":" {score:0.5156482342007435} ","formula":"resource:Ludwig_Maximilian_University_of_Munich","lexeme":"ludwig maximilian university of munich","type":"NamedEntity"} +{"features":" {score:0.02476466395722725} ","formula":"!property:municipality","lexeme":"municipality","type":"ObjProp"} +{"features":" {score:0.006745657462310337} ","formula":"property:university","lexeme":"university","type":"ObjProp"} +{"features":" {score:0.006745657462310337} ","formula":"!dbpedia:university","lexeme":"university","type":"ObjectProp"} +{"features":" {score:0.0048526863084922016} ","formula":"property:film","lexeme":"film","type":"ObjProp"} +{"features":" {score:0.0048526863084922016} ","formula":"!property:film","lexeme":"film","type":"ObjProp"} +{"features":" {score:0.3574573272887659} ","formula":"resource:1972_Summer_Olympics","lexeme":"1972 summer olympics","type":"NamedEntity"} +{"features":" {score:0.0048526863084922016} ","formula":"!dbpedia:film","lexeme":"film","type":"ObjectProp"} +{"features":" {score:0.0048526863084922016} ","formula":"dbpedia:film","lexeme":"film","type":"ObjectProp"} +{"features":" {score:0.13518829246017713} ","formula":"dbpedia:city","lexeme":"city","type":"ObjectProp"} +{"features":" {score:0.006745657462310337} ","formula":"dbpedia:university","lexeme":"university","type":"ObjectProp"} +{"features":" {score:0.02476466395722725} ","formula":"!property:municipality","lexeme":"municipality","type":"DataProp"} +{"features":" {score:0.5069005576208179} ","formula":"resource:Munich_Agreement","lexeme":"munich agreement","type":"NamedEntity"} +{"features":" {score:0.02476466395722725} ","formula":"(rdf:type dbpedia:Municipality)","lexeme":"municipality","type":"ClassNoun"} +{"features":" {score:0.006745657462310337} ","formula":"!property:university","lexeme":"university","type":"DataProp"} +{"features":" {score:0.02476466395722725} ","formula":"property:municipality","lexeme":"municipality","type":"ObjProp"} +{"features":" {score:0.007118905612640406} ","formula":"property:place","lexeme":"place","type":"DataProp"} +{"features":" {score:0.5222235130111524} ","formula":"resource:FC_Bayern_Munich","lexeme":"fc bayern munich","type":"NamedEntity"} +{"features":" {score:0.13518829246017713} ","formula":"property:city","lexeme":"city","type":"ObjProp"} +{"features":" {score:0.13518829246017713} ","formula":"!property:city","lexeme":"city","type":"DataProp"} +{"features":" {score:0.007118905612640406} ","formula":"!property:place","lexeme":"place","type":"ObjProp"} +{"features":" {score:0.006745657462310337} ","formula":"property:university","lexeme":"university","type":"DataProp"} +{"features":" {score:0.039105719999382775} ","formula":"(rdf:type dbpedia:Airport)","lexeme":"airport","type":"ClassNoun"} +{"features":" {score:0.0048526863084922016} ","formula":"property:film","lexeme":"film","type":"DataProp"} +{"features":" {score:0.13518829246017713} ","formula":"property:city","lexeme":"city","type":"DataProp"} +{"features":" {score:0.006745657462310337} ","formula":"!property:university","lexeme":"university","type":"ObjProp"} +{"features":" {score:0.006745657462310337} ","formula":"(rdf:type dbpedia:University)","lexeme":"university","type":"ClassNoun"} +{"features":" {score:0.13518829246017713} ","formula":"(rdf:type dbpedia:City)","lexeme":"city","type":"ClassNoun"} +{"features":" {score:0.13518829246017713} ","formula":"!dbpedia:city","lexeme":"city","type":"ObjectProp"} +{"features":" {score:0.13518829246017713} ","formula":"!property:city","lexeme":"city","type":"ObjProp"} +{"features":" {score:0.02476466395722725} ","formula":"property:municipality","lexeme":"municipality","type":"DataProp"} +{"features":" {score:0.007118905612640406} ","formula":"!property:place","lexeme":"place","type":"DataProp"} +{"features":" {score:0.0048526863084922016} ","formula":"!property:film","lexeme":"film","type":"DataProp"} +{"features":" {score:0.6244656133828996} ","formula":"resource:Munich","lexeme":"munich","type":"NamedEntity"} +{"features":" {score:0.007118905612640406} ","formula":"property:place","lexeme":"place","type":"ObjProp"} +{"features":" {score:0.02476466395722725} ","formula":"dbpedia:municipality","lexeme":"municipality","type":"ObjectProp"} +{"features":" {score:0.02476466395722725} ","formula":"!dbpedia:municipality","lexeme":"municipality","type":"ObjectProp"} +{"features":" {score:0.007118905612640406} ","formula":"(rdf:type dbpedia:Place)","lexeme":"place","type":"ClassNoun"} +{"features":" {score:0.5156482342007435} ","formula":"resource:Ludwig_Maximilian_University_of_Munich","lexeme":"ludwig maximilian university of munich","type":"NamedEntity"} +{"features":" {score:0.02476466395722725} ","formula":"!property:municipality","lexeme":"municipality","type":"ObjProp"} +{"features":" {score:0.006745657462310337} ","formula":"property:university","lexeme":"university","type":"ObjProp"} +{"features":" {score:0.006745657462310337} ","formula":"!dbpedia:university","lexeme":"university","type":"ObjectProp"} +{"features":" {score:0.0048526863084922016} ","formula":"property:film","lexeme":"film","type":"ObjProp"} +{"features":" {score:0.0048526863084922016} ","formula":"!property:film","lexeme":"film","type":"ObjProp"} +{"features":" {score:0.3574573272887659} ","formula":"resource:1972_Summer_Olympics","lexeme":"1972 summer olympics","type":"NamedEntity"} +{"features":" {score:0.0048526863084922016} ","formula":"!dbpedia:film","lexeme":"film","type":"ObjectProp"} +{"features":" {score:0.0048526863084922016} ","formula":"dbpedia:film","lexeme":"film","type":"ObjectProp"} +{"features":" {score:0.13518829246017713} ","formula":"dbpedia:city","lexeme":"city","type":"ObjectProp"} +{"features":" {score:0.006745657462310337} ","formula":"dbpedia:university","lexeme":"university","type":"ObjectProp"} +{"features":" {score:0.02476466395722725} ","formula":"!property:municipality","lexeme":"municipality","type":"DataProp"} +{"features":" {score:0.5069005576208179} ","formula":"resource:Munich_Agreement","lexeme":"munich agreement","type":"NamedEntity"} +{"features":" {score:0.02476466395722725} ","formula":"(rdf:type dbpedia:Municipality)","lexeme":"municipality","type":"ClassNoun"} +{"features":" {score:0.006745657462310337} ","formula":"!property:university","lexeme":"university","type":"DataProp"} +{"features":" {score:0.02476466395722725} ","formula":"property:municipality","lexeme":"municipality","type":"ObjProp"} +{"features":" {score:0.007118905612640406} ","formula":"property:place","lexeme":"place","type":"DataProp"} +{"features":" {score:0.5222235130111524} ","formula":"resource:FC_Bayern_Munich","lexeme":"fc bayern munich","type":"NamedEntity"} +{"features":" {score:0.13518829246017713} ","formula":"property:city","lexeme":"city","type":"ObjProp"} +{"features":" {score:0.13518829246017713} ","formula":"!property:city","lexeme":"city","type":"DataProp"} +{"features":" {score:0.007118905612640406} ","formula":"!property:place","lexeme":"place","type":"ObjProp"} +{"features":" {score:0.006745657462310337} ","formula":"property:university","lexeme":"university","type":"DataProp"} +{"features":" {score:0.024354053257352713} ","formula":"property:economy","lexeme":"economy","type":"ObjProp"} +{"features":" {score:0.024354053257352713} ","formula":"property:economy","lexeme":"economy","type":"DataProp"} +{"features":" {score:0.019684884847898314} ","formula":"property:case","lexeme":"case","type":"ObjProp"} +{"features":" {score:0.04119084299478716} ","formula":"!property:nation","lexeme":"nation","type":"DataProp"} +{"features":" {score:0.04307977245656418} ","formula":"property:state","lexeme":"state","type":"DataProp"} +{"features":" {score:0.018446601941747572} ","formula":"!property:market","lexeme":"market","type":"DataProp"} +{"features":" {score:0.04307977245656418} ","formula":"!property:state","lexeme":"state","type":"ObjProp"} +{"features":" {score:0.019684884847898314} ","formula":"!property:case","lexeme":"case","type":"DataProp"} +{"features":" {score:0.12119717597961427} ","formula":"dbpedia:kingdom","lexeme":"kingdom","type":"ObjectProp"} +{"features":" {score:0.02330097087378641} ","formula":"(rdf:type dbpedia:Place)","lexeme":"place","type":"ClassNoun"} +{"features":" {score:0.019684884847898314} ","formula":"!property:case","lexeme":"case","type":"ObjProp"} +{"features":" {score:0.02330097087378641} ","formula":"!property:place","lexeme":"place","type":"DataProp"} +{"features":" {score:0.04307977245656418} ","formula":"dbpedia:state","lexeme":"state","type":"ObjectProp"} +{"features":" {score:0.02330097087378641} ","formula":"property:place","lexeme":"place","type":"ObjProp"} +{"features":" {score:0.019684884847898314} ","formula":"property:case","lexeme":"case","type":"DataProp"} +{"features":" {score:0.12119717597961427} ","formula":"!dbpedia:kingdom","lexeme":"kingdom","type":"ObjectProp"} +{"features":" {score:0.04307977245656418} ","formula":"property:state","lexeme":"state","type":"ObjProp"} +{"features":" {score:0.018446601941747572} ","formula":"property:market","lexeme":"market","type":"DataProp"} +{"features":" {score:0.024354053257352713} ","formula":"!property:economy","lexeme":"economy","type":"ObjProp"} +{"features":" {score:0.3600622212941572} ","formula":"\u003chttp://dbpedia.org/resource/Galicia_(Eastern_Europe)\u003e","lexeme":"galicia eastern europe","type":"NamedEntity"} +{"features":" {score:0.04119084299478716} ","formula":"!property:nation","lexeme":"nation","type":"ObjProp"} +{"features":" {score:0.3138386448463968} ","formula":"resource:Odessa","lexeme":"odessa","type":"NamedEntity"} +{"features":" {score:0.04119084299478716} ","formula":"property:nation","lexeme":"nation","type":"DataProp"} +{"features":" {score:0.024354053257352713} ","formula":"!property:economy","lexeme":"economy","type":"DataProp"} +{"features":" {score:0.018446601941747572} ","formula":"property:market","lexeme":"market","type":"ObjProp"} +{"features":" {score:0.38531734665303335} ","formula":"resource:Ukrainian_Soviet_Socialist_Republic","lexeme":"ukrainian soviet socialist republic","type":"NamedEntity"} +{"features":" {score:0.04307977245656418} ","formula":"!dbpedia:state","lexeme":"state","type":"ObjectProp"} +{"features":" {score:0.3847475641953887} ","formula":"resource:Kiev","lexeme":"kiev","type":"NamedEntity"} +{"features":" {score:0.04307977245656418} ","formula":"!property:state","lexeme":"state","type":"DataProp"} +{"features":" {score:0.6268662072925639} ","formula":"resource:Ukraine","lexeme":"ukraine","type":"NamedEntity"} +{"features":" {score:0.04119084299478716} ","formula":"property:nation","lexeme":"nation","type":"ObjProp"} +{"features":" {score:0.02330097087378641} ","formula":"!property:place","lexeme":"place","type":"ObjProp"} +{"features":" {score:0.04307977245656418} ","formula":"(rdf:type dbpedia:State)","lexeme":"state","type":"ClassNoun"} +{"features":" {score:0.019684884847898314} ","formula":"(rdf:type dbpedia:Case)","lexeme":"case","type":"ClassNoun"} +{"features":" {score:0.02330097087378641} ","formula":"property:place","lexeme":"place","type":"DataProp"} +{"features":" {score:0.018446601941747572} ","formula":"!property:market","lexeme":"market","type":"ObjProp"} +{"features":" {score:0.04497633274836032} ","formula":"dbpedia:school","lexeme":"school","type":"ObjectProp"} +{"features":" {score:0.004000398279457181} ","formula":"property:place","lexeme":"place","type":"ObjProp"} +{"features":" {score:0.23928566465179055} ","formula":"!dbpedia:state","lexeme":"state","type":"ObjectProp"} +{"features":" {score:0.01571197572250911} ","formula":"dbpedia:team","lexeme":"team","type":"ObjectProp"} +{"features":" {score:0.020602241780125662} ","formula":"(rdf:type dbpedia:Area)","lexeme":"area","type":"ClassNoun"} +{"features":" {score:0.06181670468015462} ","formula":"!property:university","lexeme":"university","type":"DataProp"} +{"features":" {score:0.004000398279457181} ","formula":"property:place","lexeme":"place","type":"DataProp"} +{"features":" {score:0.12948527336120605} ","formula":"(rdf:type dbpedia:District)","lexeme":"district","type":"ClassNoun"} +{"features":" {score:0.5720439401120807} ","formula":"resource:Michigan","lexeme":"michigan","type":"NamedEntity"} +{"features":" {score:0.020602241780125662} ","formula":"property:area","lexeme":"area","type":"DataProp"} +{"features":" {score:0.004000398279457181} ","formula":"(rdf:type dbpedia:Place)","lexeme":"place","type":"ClassNoun"} +{"features":" {score:0.06181670468015462} ","formula":"property:university","lexeme":"university","type":"DataProp"} +{"features":" {score:0.020602241780125662} ","formula":"property:area","lexeme":"area","type":"ObjProp"} +{"features":" {score:0.23928566465179055} ","formula":"!property:state","lexeme":"state","type":"DataProp"} +{"features":" {score:0.004000398279457181} ","formula":"!property:place","lexeme":"place","type":"DataProp"} +{"features":" {score:0.04497633274836032} ","formula":"!property:school","lexeme":"school","type":"DataProp"} +{"features":" {score:0.13264328241348267} ","formula":"(rdf:type dbpedia:Community)","lexeme":"community","type":"ClassNoun"} +{"features":" {score:0.04497633274836032} ","formula":"property:school","lexeme":"school","type":"DataProp"} +{"features":" {score:0.06181670468015462} ","formula":"dbpedia:university","lexeme":"university","type":"ObjectProp"} +{"features":" {score:0.4286662644078575} ","formula":"resource:Detroit","lexeme":"detroit","type":"NamedEntity"} +{"features":" {score:0.020602241780125662} ","formula":"!property:area","lexeme":"area","type":"ObjProp"} +{"features":" {score:0.00760847769190393} ","formula":"!dbpedia:jurisdiction","lexeme":"jurisdiction","type":"ObjectProp"} +{"features":" {score:0.23928566465179055} ","formula":"property:state","lexeme":"state","type":"DataProp"} +{"features":" {score:0.00760847769190393} ","formula":"dbpedia:jurisdiction","lexeme":"jurisdiction","type":"ObjectProp"} +{"features":" {score:0.014931363700492493} ","formula":"property:program","lexeme":"program","type":"ObjProp"} +{"features":" {score:0.014931363700492493} ","formula":"property:program","lexeme":"program","type":"DataProp"} +{"features":" {score:0.5430869601583628} ","formula":"resource:University_of_Michigan","lexeme":"university of michigan","type":"NamedEntity"} +{"features":" {score:0.004000398279457181} ","formula":"!property:place","lexeme":"place","type":"ObjProp"} +{"features":" {score:0.23928566465179055} ","formula":"!property:state","lexeme":"state","type":"ObjProp"} +{"features":" {score:0.04497633274836032} ","formula":"!property:school","lexeme":"school","type":"ObjProp"} +{"features":" {score:0.00760847769190393} ","formula":"!property:jurisdiction","lexeme":"jurisdiction","type":"ObjProp"} +{"features":" {score:0.00760847769190393} ","formula":"property:jurisdiction","lexeme":"jurisdiction","type":"ObjProp"} +{"features":" {score:0.020602241780125662} ","formula":"!property:area","lexeme":"area","type":"DataProp"} +{"features":" {score:0.5123400340145537} ","formula":"\u003chttp://dbpedia.org/resource/Ann_Arbor,_Michigan\u003e","lexeme":"ann arbor, michigan","type":"NamedEntity"} +{"features":" {score:0.04497633274836032} ","formula":"property:school","lexeme":"school","type":"ObjProp"} +{"features":" {score:0.01571197572250911} ","formula":"!dbpedia:team","lexeme":"team","type":"ObjectProp"} +{"features":" {score:0.00760847769190393} ","formula":"!property:jurisdiction","lexeme":"jurisdiction","type":"DataProp"} +{"features":" {score:0.06181670468015462} ","formula":"property:university","lexeme":"university","type":"ObjProp"} +{"features":" {score:0.04497633274836032} ","formula":"!dbpedia:school","lexeme":"school","type":"ObjectProp"} +{"features":" {score:0.014931363700492493} ","formula":"!property:program","lexeme":"program","type":"DataProp"} +{"features":" {score:0.5140407617029581} ","formula":"resource:Michigan_State_University","lexeme":"michigan state university","type":"NamedEntity"} +{"features":" {score:0.23928566465179055} ","formula":"property:state","lexeme":"state","type":"ObjProp"} +{"features":" {score:0.30652677306930154} ","formula":"(rdf:type dbpedia:State)","lexeme":"state","type":"ClassNoun"} +{"features":" {score:0.04497633274836032} ","formula":"(rdf:type dbpedia:School)","lexeme":"school","type":"ClassNoun"} +{"features":" {score:0.06181670468015462} ","formula":"!property:university","lexeme":"university","type":"ObjProp"} +{"features":" {score:0.06181670468015462} ","formula":"(rdf:type dbpedia:University)","lexeme":"university","type":"ClassNoun"} +{"features":" {score:0.23928566465179055} ","formula":"dbpedia:state","lexeme":"state","type":"ObjectProp"} +{"features":" {score:0.014931363700492493} ","formula":"!property:program","lexeme":"program","type":"ObjProp"} +{"features":" {score:0.00760847769190393} ","formula":"property:jurisdiction","lexeme":"jurisdiction","type":"DataProp"} +{"features":" {score:0.06181670468015462} ","formula":"!dbpedia:university","lexeme":"university","type":"ObjectProp"} +{"features":" {score:0.039105719999382775} ","formula":"(rdf:type dbpedia:Airport)","lexeme":"airport","type":"ClassNoun"} +{"features":" {score:0.0048526863084922016} ","formula":"property:film","lexeme":"film","type":"DataProp"} +{"features":" {score:0.006745657462310337} ","formula":"(rdf:type dbpedia:University)","lexeme":"university","type":"ClassNoun"} +{"features":" {score:0.13518829246017713} ","formula":"(rdf:type dbpedia:City)","lexeme":"city","type":"ClassNoun"} +{"features":" {score:0.06491494770435727} ","formula":"!property:institution","lexeme":"institution","type":"DataProp"} +{"features":" {score:0.13518829246017713} ","formula":"!property:city","lexeme":"city","type":"ObjProp"} +{"features":" {score:0.02476466395722725} ","formula":"property:municipality","lexeme":"municipality","type":"DataProp"} +{"features":" {score:0.007118905612640406} ","formula":"property:place","lexeme":"place","type":"ObjProp"} +{"features":" {score:0.02476466395722725} ","formula":"!dbpedia:municipality","lexeme":"municipality","type":"ObjectProp"} +{"features":" {score:0.007118905612640406} ","formula":"(rdf:type dbpedia:Place)","lexeme":"place","type":"ClassNoun"} +{"features":" {score:0.06491494770435727} ","formula":"property:institution","lexeme":"institution","type":"DataProp"} +{"features":" {score:0.02476466395722725} ","formula":"!property:municipality","lexeme":"municipality","type":"ObjProp"} +{"features":" {score:0.6285851188338059} ","formula":"resource:Texas_Tech_University","lexeme":"texas tech university","type":"NamedEntity"} +{"features":" {score:0.34189207904479085} ","formula":"!property:university","lexeme":"university","type":"DataProp"} +{"features":" {score:0.6252712786778605} ","formula":"resource:Private_university","lexeme":"private university","type":"NamedEntity"} +{"features":" {score:0.0048526863084922016} ","formula":"!property:film","lexeme":"film","type":"ObjProp"} +{"features":" {score:0.06491494770435727} ","formula":"!property:institution","lexeme":"institution","type":"ObjProp"} +{"features":" {score:0.3574573272887659} ","formula":"resource:1972_Summer_Olympics","lexeme":"1972 summer olympics","type":"NamedEntity"} +{"features":" {score:0.34189207904479085} ","formula":"property:university","lexeme":"university","type":"DataProp"} +{"features":" {score:0.0048526863084922016} ","formula":"dbpedia:film","lexeme":"film","type":"ObjectProp"} +{"features":" {score:0.13518829246017713} ","formula":"dbpedia:city","lexeme":"city","type":"ObjectProp"} +{"features":" {score:0.4527074563224413} ","formula":"resource:ETH_Zurich","lexeme":"eth zurich","type":"NamedEntity"} +{"features":" {score:0.5069005576208179} ","formula":"resource:Munich_Agreement","lexeme":"munich agreement","type":"NamedEntity"} +{"features":" {score:0.539723393814838} ","formula":"resource:Rensselaer_Polytechnic_Institute","lexeme":"rensselaer polytechnic institute","type":"NamedEntity"} +{"features":" {score:0.007118905612640406} ","formula":"!property:place","lexeme":"place","type":"ObjProp"} +{"features":" {score:0.13518829246017713} ","formula":"property:city","lexeme":"city","type":"DataProp"} +{"features":" {score:0.006745657462310337} ","formula":"!property:university","lexeme":"university","type":"ObjProp"} +{"features":" {score:0.6278378455727189} ","formula":"resource:Saint_Petersburg_State_University","lexeme":"saint petersburg state university","type":"NamedEntity"} +{"features":" {score:0.34189207904479085} ","formula":"(rdf:type dbpedia:University)","lexeme":"university","type":"ClassNoun"} +{"features":" {score:0.34189207904479085} ","formula":"property:university","lexeme":"university","type":"ObjProp"} +{"features":" {score:0.13518829246017713} ","formula":"!dbpedia:city","lexeme":"city","type":"ObjectProp"} +{"features":" {score:0.06491494770435727} ","formula":"dbpedia:institution","lexeme":"institution","type":"ObjectProp"} +{"features":" {score:0.007118905612640406} ","formula":"!property:place","lexeme":"place","type":"DataProp"} +{"features":" {score:0.0048526863084922016} ","formula":"!property:film","lexeme":"film","type":"DataProp"} +{"features":" {score:0.6244656133828996} ","formula":"resource:Munich","lexeme":"munich","type":"NamedEntity"} +{"features":" {score:0.02476466395722725} ","formula":"dbpedia:municipality","lexeme":"municipality","type":"ObjectProp"} +{"features":" {score:0.34189207904479085} ","formula":"!property:university","lexeme":"university","type":"ObjProp"} +{"features":" {score:0.34189207904479085} ","formula":"dbpedia:university","lexeme":"university","type":"ObjectProp"} +{"features":" {score:0.5156482342007435} ","formula":"resource:Ludwig_Maximilian_University_of_Munich","lexeme":"ludwig maximilian university of munich","type":"NamedEntity"} +{"features":" {score:0.34189207904479085} ","formula":"!dbpedia:university","lexeme":"university","type":"ObjectProp"} +{"features":" {score:0.006745657462310337} ","formula":"property:university","lexeme":"university","type":"ObjProp"} +{"features":" {score:0.006745657462310337} ","formula":"!dbpedia:university","lexeme":"university","type":"ObjectProp"} +{"features":" {score:0.0048526863084922016} ","formula":"property:film","lexeme":"film","type":"ObjProp"} +{"features":" {score:0.0048526863084922016} ","formula":"!dbpedia:film","lexeme":"film","type":"ObjectProp"} +{"features":" {score:0.06491494770435727} ","formula":"property:institution","lexeme":"institution","type":"ObjProp"} +{"features":" {score:0.006745657462310337} ","formula":"dbpedia:university","lexeme":"university","type":"ObjectProp"} +{"features":" {score:0.02476466395722725} ","formula":"!property:municipality","lexeme":"municipality","type":"DataProp"} +{"features":" {score:0.02476466395722725} ","formula":"(rdf:type dbpedia:Municipality)","lexeme":"municipality","type":"ClassNoun"} +{"features":" {score:0.06491494770435727} ","formula":"!dbpedia:institution","lexeme":"institution","type":"ObjectProp"} +{"features":" {score:0.006745657462310337} ","formula":"!property:university","lexeme":"university","type":"DataProp"} +{"features":" {score:0.02476466395722725} ","formula":"property:municipality","lexeme":"municipality","type":"ObjProp"} +{"features":" {score:0.007118905612640406} ","formula":"property:place","lexeme":"place","type":"DataProp"} +{"features":" {score:0.5222235130111524} ","formula":"resource:FC_Bayern_Munich","lexeme":"fc bayern munich","type":"NamedEntity"} +{"features":" {score:0.13518829246017713} ","formula":"property:city","lexeme":"city","type":"ObjProp"} +{"features":" {score:0.13518829246017713} ","formula":"!property:city","lexeme":"city","type":"DataProp"} +{"features":" {score:0.006745657462310337} ","formula":"property:university","lexeme":"university","type":"DataProp"} diff --git a/roslaunch b/roslaunch new file mode 100644 index 00000000..e69de29b