Example #1
0
class NLU():
    def __init__(self):

        ###############################################################
        #
        # Sets up all default requirements and placeholders
        # needed for the NLU engine to run.
        #
        # - Helpers: Useful global functions
        # - JumpWay/jumpWayClient: iotJumpWay class and connection
        # - Logging: Logging class
        #
        ###############################################################

        self.isTraining = False
        self.ner = None

        self.Helpers = Helpers()
        self._confs = self.Helpers.loadConfigs()

        self.user = {}

        self.LogFile = self.Helpers.setLogFile(self._confs["aiCore"]["Logs"] +
                                               "NLU/")
        self.ChatLogFile = self.Helpers.setLogFile(
            self._confs["aiCore"]["Logs"] + "Chat/")

        self.jumpWay = JumpWay()
        self.jumpWayClient = self.jumpWay.startMQTT()

        self.jumpWayClient.subscribeToDeviceChannel(
            self._confs["iotJumpWay"]["Channels"]["Commands"])
        self.jumpWayClient.deviceCommandsCallback = self.commandsCallback

    def initiateSession(self):

        ###############################################################
        #
        # Initiates empty guest user session, GeniSys will ask the user
        # verify their GeniSys user by speaking or typing if it does
        # not know who it is speaking to.
        #
        ###############################################################

        self.userID = 0
        if not self.userID in self.user:
            self.user[self.userID] = {}
            self.user[self.userID]["history"] = {}

    def initNLU(self):

        ###############################################################
        #
        # Initiates the NLU setting up the data, NLU / entities models
        # and required modules such as context and extensions.
        #
        ###############################################################

        self.Data = Data()
        self.trainingData = self.Data.loadTrainingData()
        self.trainedData = self.Data.loadTrainedData()

        self.Model = Model()
        self.Context = Context()
        self.Extensions = Extensions()

        self.restoreData()
        self.restoreNER()
        self.restoreNLU()

        self.initiateSession()
        self.setThresholds()

    def commandsCallback(self, topic, payload):

        ###############################################################
        #
        # The callback function that is triggerend in the event of a
        # command communication from the iotJumpWay.
        #
        ###############################################################

        self.Helpers.logMessage(
            self.LogFile, "iotJumpWay", "INFO",
            "Recieved iotJumpWay Command Data : " + str(payload))

        commandData = json.loads(payload.decode("utf-8"))

    def restoreData(self):

        ###############################################################
        #
        # Sets the local trained data using data retrieved above
        #
        ###############################################################

        self.trainedWords = self.trainedData["words"]
        self.trainedClasses = self.trainedData["classes"]
        self.x = self.trainedData["x"]
        self.y = self.trainedData["y"]
        self.intentMap = self.trainedData["intentMap"][0]

    def loadEntityController(self):

        ###############################################################
        #
        # Initiates the entity extractor class from tools
        #
        ###############################################################

        self.entityController = Entities()

    def restoreNER(self):

        ###############################################################
        #
        # Loads entity controller and restores the NER model
        #
        ###############################################################

        self.loadEntityController()
        self.ner = self.entityController.restoreNER()

    def restoreNLU(self):

        ###############################################################
        #
        # Restores the NLU model
        #
        ###############################################################

        self.tmodel = self.Model.buildDNN(self.x, self.y)

    def setThresholds(self):

        ###############################################################
        #
        # Sets the threshold for the NLU engine, this can be changed
        # using arguments to commandline programs or paramters for
        # API calls.
        #
        ###############################################################

        self.threshold = self._confs["NLU"]["Threshold"]
        self.entityThrshld = self._confs["NLU"]["Mitie"]["Threshold"]

    def communicate(self, sentence):

        ###############################################################
        #
        # First checks to ensure that the program is not training,
        # then parses any entities that may be in the intent, then
        # checks context and extensions before providing a response.
        #
        ###############################################################

        if self.isTraining == False:

            parsed, fallback, entityHolder, parsedSentence = self.entityController.parseEntities(
                sentence, self.ner, self.trainingData)

            classification = self.Model.predict(self.tmodel, parsedSentence,
                                                self.trainedWords,
                                                self.trainedClasses)

            if len(classification) > 0:

                clearEntities = False
                theIntent = self.trainingData["intents"][self.intentMap[
                    classification[0][0]]]

                if len(entityHolder) and not len(theIntent["entities"]):
                    clearEntities = True

                if (self.Context.checkSessionContext(self.user[self.userID],
                                                     theIntent)):

                    if self.Context.checkClearContext(theIntent, 0):
                        self.user[self.userID]["context"] = ""

                    contextIn, contextOut, contextCurrent = self.Context.setContexts(
                        theIntent, self.user[self.userID])

                    if not len(entityHolder) and len(theIntent["entities"]):
                        response, entities = self.entityController.replaceResponseEntities(
                            random.choice(theIntent["fallbacks"]),
                            entityHolder)
                        extension, extensionResponses, exEntities = self.Extensions.setExtension(
                            theIntent)

                    elif clearEntities:
                        entityHolder = []
                        response = random.choice(theIntent["responses"])
                        extension, extensionResponses, exEntities = self.Extensions.setExtension(
                            theIntent)

                    else:
                        response, entities = self.entityController.replaceResponseEntities(
                            random.choice(theIntent["responses"]),
                            entityHolder)
                        extension, extensionResponses, exEntities = self.Extensions.setExtension(
                            theIntent)

                    if extension != None:

                        classParts = extension.split(".")
                        classFolder = classParts[0]
                        className = classParts[1]
                        theEntities = None

                        if exEntities != False:
                            theEntities = entities

                        module = __import__(
                            classParts[0] + "." + classParts[1], globals(),
                            locals(), [className])
                        extensionClass = getattr(module, className)()
                        response = getattr(extensionClass,
                                           classParts[2])(extensionResponses,
                                                          theEntities)

                    return {
                        "Response":
                        "OK",
                        "ResponseData": [{
                            "Received":
                            sentence,
                            "Intent":
                            classification[0][0],
                            "Confidence":
                            str(classification[0][1]),
                            "Response":
                            response,
                            "Context": [{
                                "In": contextIn,
                                "Out": contextOut,
                                "Current": contextCurrent
                            }],
                            "Extension":
                            extension,
                            "Entities":
                            entityHolder
                        }]
                    }

                else:

                    self.user[self.userID]["context"] = ""
                    contextIn, contextOut, contextCurrent = self.Context.setContexts(
                        theIntent, self.user[self.userID])

                    if fallback and fallback in theIntent and len(
                            theIntent["fallbacks"]):
                        response = self.entityController.replaceResponseEntities(
                            random.choice(theIntent["fallbacks"]),
                            entityHolder)
                        extension, extensionResponses = None, []

                    else:
                        response = self.entityController.replaceResponseEntities(
                            random.choice(theIntent["responses"]),
                            entityHolder)
                        extension, extensionResponses, exEntities = self.Extensions.setExtension(
                            theIntent)

                    if extension != None:

                        classParts = extension.split(".")
                        classFolder = classParts[0]
                        className = classParts[1]
                        theEntities = None

                        if exEntities != False:
                            theEntities = entities

                        module = __import__(
                            classParts[0] + "." + classParts[1], globals(),
                            locals(), [className])
                        extensionClass = getattr(module, className)()
                        response = getattr(extensionClass,
                                           classParts[2])(extensionResponses,
                                                          theEntities)

                    else:
                        response = self.entityController.replaceResponseEntities(
                            random.choice(theIntent["responses"]),
                            entityHolder)

                    return {
                        "Response":
                        "OK",
                        "ResponseData": [{
                            "Received":
                            sentence,
                            "Intent":
                            classification[0][0],
                            "Confidence":
                            str(classification[0][1]),
                            "Response":
                            response,
                            "Context": [{
                                "In": contextIn,
                                "Out": contextOut,
                                "Current": contextCurrent
                            }],
                            "Extension":
                            extension,
                            "Entities":
                            entityHolder
                        }]
                    }

            else:

                contextCurrent = self.Context.getCurrentContext(
                    self.user[self.userID])

                return {
                    "Response":
                    "FAILED",
                    "ResponseData": [{
                        "Received":
                        sentence,
                        "Intent":
                        "UNKNOWN",
                        "Confidence":
                        "NA",
                        "Responses": [],
                        "Response":
                        random.choice(self._confs["NLU"]["defaultResponses"]),
                        "Context": [{
                            "In": "NA",
                            "Out": "NA",
                            "Current": contextCurrent
                        }],
                        "Extension":
                        "NA",
                        "Entities":
                        entityHolder
                    }]
                }
        else:

            return {
                "Response":
                "FAILED",
                "ResponseData": [{
                    "Status": "Training",
                    "Message": "NLU Engine is currently training"
                }]
            }
Example #2
0
class NLU():
    def __init__(self):

        self.Helpers = Helpers()
        self.Logging = Logging()
        self._confs = self.Helpers.loadConfigs()
        self.LogFile = self.Logging.setLogFile(self._confs["AI"]["Logs"] +
                                               "NLU/")
        self.ChatLogFile = self.Logging.setLogFile(self._confs["AI"]["Logs"] +
                                                   "Chat/")

        self.Logging.logMessage(self.LogFile, "NLU", "INFO",
                                "NLU Classifier LogFile Set")

        self.startMQTT()

    def commandsCallback(self, topic, payload):

        self.Logging.logMessage(
            self.LogFile, "iotJumpWay", "INFO",
            "Recieved iotJumpWay Command Data : " + str(payload))

        commandData = json.loads(payload.decode("utf-8"))

    def startMQTT(self):

        try:
            self.jumpwayClient = jumpWayDevice.DeviceConnection({
                "locationID":
                self._confs["iotJumpWay"]["Location"],
                "zoneID":
                self._confs["iotJumpWay"]["Zone"],
                "deviceId":
                self._confs["iotJumpWay"]["Device"],
                "deviceName":
                self._confs["iotJumpWay"]["DeviceName"],
                "username":
                self._confs["iotJumpWay"]["MQTT"]["Username"],
                "password":
                self._confs["iotJumpWay"]["MQTT"]["Password"]
            })

            self.jumpwayClient.connectToDevice()
            self.jumpwayClient.subscribeToDeviceChannel("Commands")
            self.jumpwayClient.deviceCommandsCallback = self.commandsCallback

            self.Logging.logMessage(self.LogFile, "iotJumpWay", "INFO",
                                    "iotJumpWay Client Ready")

        except Exception as e:

            self.Logging.logMessage(self.LogFile, "iotJumpWay", "INFO",
                                    "iotJumpWay Client Initiation Failed")

            print(str(e))
            sys.exit()

    def setup(self):

        self.Logging.logMessage(self.LogFile, "NLU", "INFO",
                                "NLU Classifier Initiating")

        self.Data = Data(self.Logging, self.LogFile)
        self.Model = Model()
        self.Context = Context()

        self.user = {}
        self.ner = None
        self.trainingData = self.Data.loadTrainingData()
        self.trainedData = self.Data.loadTrainedData()

        self.trainedWords = self.trainedData["words"]
        self.trainedClasses = self.trainedData["classes"]
        self.x = self.trainedData["x"]
        self.y = self.trainedData["y"]
        self.intentMap = self.trainedData["iMap"][0]

        self.restoreEntitiesModel()
        self.restoreModel()

        self.Logging.logMessage(self.LogFile, "NLU", "INFO", "NLU Ready")

    def restoreEntitiesModel(self):

        if os.path.exists(self._confs["ClassifierSettings"]["EntitiesDat"]):
            self.ner = named_entity_extractor(
                self._confs["ClassifierSettings"]["EntitiesDat"])

            self.Logging.logMessage(self.LogFile, "NER", "OK",
                                    "Restored NLU NER Model")

    def restoreModel(self):

        self.tmodel = self.Model.buildDNN(self.x, self.y)

        self.Logging.logMessage(self.LogFile, "NLU", "INFO",
                                "Restored NLU Model")

    def setupEntities(self):

        if self._confs["ClassifierSettings"]["Entities"] == "Mitie":
            self.entityExtractor = Entities()

        self.Logging.logMessage(self.LogFile, "NER", "INFO",
                                "NLU Entity Extractor Initiated")

    def initiateSession(self, userID):

        self.userID = userID
        if not self.userID in self.user:
            self.user[self.userID] = {}
            self.user[self.userID]["history"] = {}

        self.Logging.logMessage(self.LogFile, "Session", "INFO",
                                "NLU Session Ready For User #" + self.userID)

    def setThresholds(self, threshold):

        self.threshold = float(threshold)
        self.entityThrshld = self._confs["ClassifierSettings"]["Mitie"][
            "Threshold"]

    def predict(self, parsedSentence):

        predictions = [[index, confidence] for index, confidence in enumerate(
            self.tmodel.predict([
                self.Data.makeInferenceBag(parsedSentence, self.trainedWords)
            ])[0]) if confidence > self.threshold]
        predictions.sort(key=lambda x: x[1], reverse=True)

        classification = []
        for prediction in predictions:
            classification.append(
                (self.trainedClasses[prediction[0]], prediction[1]))

        return classification

    def talk(self, sentence, debug=False):

        self.Logging.logMessage(self.LogFile, "GeniSys", "STATUS",
                                "Processing")

        parsed, fallback, entityHolder, parsedSentence = self.entityExtractor.parseEntities(
            sentence, self.ner, self.trainingData)

        classification = self.predict(parsedSentence)

        if len(classification) > 0:

            clearEntities = False
            theIntent = self.trainingData["intents"][self.intentMap[
                classification[0][0]]]

            if len(entityHolder) and not len(theIntent["entities"]):
                clearEntities = True

            if (self.Context.checkSessionContext(self.user[self.userID],
                                                 theIntent)):

                if self.Context.checkClearContext(theIntent, 0):
                    self.user[self.userID]["context"] = ""

                contextIn, contextOut, contextCurrent = self.Context.setContexts(
                    theIntent, self.user[self.userID])

                if fallback and "fallbacks" in theIntent and len(
                        theIntent["fallbacks"]):
                    response = self.entityExtractor.replaceResponseEntities(
                        random.choice(theIntent["fallbacks"]), entityHolder)
                    action, actionResponses = self.Helpers.setAction(theIntent)

                elif "entityType" in theIntent and theIntent[
                        "entityType"] == "Numbers":
                    response = random.choice(theIntent["responses"])
                    action, actionResponses = self.Helpers.setAction(theIntent)

                elif not len(entityHolder) and len(theIntent["entities"]):
                    response = self.entityExtractor.replaceResponseEntities(
                        random.choice(theIntent["fallbacks"]), entityHolder)
                    action, actionResponses = self.Helpers.setAction(theIntent)

                elif clearEntities:
                    entityHolder = []
                    response = random.choice(theIntent["responses"])
                    action, actionResponses = self.Helpers.setAction(theIntent)

                else:
                    response = self.entityExtractor.replaceResponseEntities(
                        random.choice(theIntent["responses"]), entityHolder)
                    action, actionResponses = self.Helpers.setAction(theIntent)

                if action != None:

                    classParts = action.split(".")
                    classFolder = classParts[0]
                    className = classParts[1]

                    module = __import__(classParts[0] + "." + classParts[1],
                                        globals(), locals(), [className])
                    actionClass = getattr(module, className)()
                    response = getattr(actionClass, classParts[2])(
                        random.choice(actionResponses))

                return {
                    "Response":
                    "OK",
                    "ResponseData": [{
                        "Received": sentence,
                        "Intent": classification[0][0],
                        "Confidence": str(classification[0][1]),
                        "Response": response,
                        "ContextIn": contextIn,
                        "ContextOut": contextOut,
                        "Context": contextCurrent,
                        "Action": action,
                        "Entities": entityHolder
                    }]
                }

            else:

                self.user[self.userID]["context"] = ""
                contextIn, contextOut, contextCurrent = self.Context.setContexts(
                    theIntent, self.user[self.userID])

                if fallback and fallback in theIntent and len(
                        theIntent["fallbacks"]):
                    response = self.entityExtractor.replaceResponseEntities(
                        random.choice(theIntent["fallbacks"]), entityHolder)
                    action, actionResponses = None, []

                else:
                    response = self.entityExtractor.replaceResponseEntities(
                        random.choice(theIntent["responses"]), entityHolder)
                    action, actionResponses = self.Helpers.setAction(theIntent)

                if action != None:

                    classParts = action.split(".")
                    classFolder = classParts[0]
                    className = classParts[1]

                    module = __import__(classParts[0] + "." + classParts[1],
                                        globals(), locals(), [className])
                    actionClass = getattr(module, className)()
                    response = getattr(actionClass, classParts[2])(
                        random.choice(actionResponses))

                else:
                    response = self.entityExtractor.replaceResponseEntities(
                        random.choice(theIntent["responses"]), entityHolder)

                return {
                    "Response":
                    "OK",
                    "ResponseData": [{
                        "Received": sentence,
                        "Intent": classification[0][0],
                        "Confidence": str(classification[0][1]),
                        "Response": response,
                        "ContextIn": contextIn,
                        "ContextOut": contextOut,
                        "ContextCurrent": contextCurrent,
                        "Action": action,
                        "Entities": entityHolder
                    }]
                }

        else:

            contextCurrent = self.Context.getCurrentContext(
                self.user[self.userID])

            return {
                "Response":
                "FAILED",
                "ResponseData": [{
                    "Received":
                    sentence,
                    "Intent":
                    "UNKNOWN",
                    "Confidence":
                    "NA",
                    "Responses": [],
                    "Response":
                    random.choice(
                        self._confs["ClassifierSettings"]["defaultResponses"]),
                    "ContextIn":
                    "NA",
                    "ContextOut":
                    "NA",
                    "ContextCurrent":
                    contextCurrent,
                    "Action":
                    "NA",
                    "Entities":
                    entityHolder
                }]
            }