def getTexts(self, module, talk, strType='default') -> list:
        arr = list()
        try:
            module = commons.toCamelCase(module)
            arr = self._langData[module][
                self.LanguageManager.activeLanguage][talk][strType]
        except KeyError:
            self._logger.warning(
                f'[{self.name}] Was asked to return unexisting texts {talk} for module {module} with type {strType}'
            )

        return arr
    def _loadModuleList(self, moduleToLoad: str = '', isUpdate: bool = False):
        if moduleToLoad:
            modules = self._modules.copy()
        else:
            modules = dict()

        availableModules = self.ConfigManager.modulesConfigurations
        availableModules = collections.OrderedDict(
            sorted(availableModules.items()))

        if Customisation.MODULE_NAME in availableModules:
            customisationModule = availableModules.pop(
                Customisation.MODULE_NAME)
            availableModules[Customisation.MODULE_NAME] = customisationModule

        for moduleName, module in availableModules.items():
            if moduleToLoad and moduleName != moduleToLoad:
                continue

            conditionName = ''
            conditionValue = ''
            try:
                if not module['active']:
                    if moduleName in self.NEEDED_MODULES:
                        self._logger.info(
                            "Module {} marked as disable but it shouldn't be".
                            format(moduleName))
                        SuperManager.getInstance().onStop()
                        break
                    else:
                        self._logger.info(
                            'Module {} is disabled'.format(moduleName))
                        continue

                if 'conditions' in module:
                    for conditionName, conditionValue in module[
                            'conditions'].items():
                        if conditionName == 'lang' and self.LanguageManager.activeLanguage not in conditionValue:
                            raise ModuleNotConditionCompliant

                        elif conditionName == 'online':
                            if conditionValue and self.ConfigManager.getAliceConfigByName(
                                    'stayCompletlyOffline'):
                                raise ModuleNotConditionCompliant
                            elif not conditionValue and not self.ConfigManager.getAliceConfigByName(
                                    'stayCompletlyOffline'):
                                raise ModuleNotConditionCompliant

                        elif conditionName == 'module':
                            for requiredModule in conditionValue:
                                if requiredModule[
                                        'name'] in availableModules and not availableModules[
                                            requiredModule['name']]['active']:
                                    raise ModuleNotConditionCompliant
                                elif requiredModule[
                                        'name'] not in availableModules:
                                    self._logger.info(
                                        '[{}] Module {} has another module as dependency, adding download'
                                        .format(self.name, moduleName))
                                    subprocess.run([
                                        'wget', requiredModule['url'], '-O',
                                        Path(
                                            commons.rootDir(),
                                            'system/moduleInstallTickets/{}.install'
                                            .format(requiredModule['name']))
                                    ])

                        elif conditionName == 'notModule':
                            for excludedModule in conditionValue:
                                author, name = excludedModule.split('/')
                                if name in availableModules and availableModules[
                                        name][
                                            'author'] == author and availableModules[
                                                name]['active']:
                                    raise ModuleNotConditionCompliant

                        elif conditionName == 'asrArbitraryCapture':
                            if conditionValue and not self.ASRManager.asr.capableOfArbitraryCapture:
                                raise ModuleNotConditionCompliant

                        elif conditionName == 'activeManager':
                            for manager in conditionValue:
                                if not manager: continue

                                man = SuperManager.getInstance().getManager(
                                    manager)
                                if not man or not man.isActive:
                                    raise ModuleNotConditionCompliant

                if ' ' in moduleName:
                    name = commons.toCamelCase(moduleName)
                else:
                    name = moduleName

                moduleInstance = self.importFromModule(moduleName=name,
                                                       isUpdate=isUpdate)

                if moduleInstance:
                    modules[moduleInstance.name] = {'instance': moduleInstance}
            except ModuleStartingFailed as e:
                self._logger.warning('[{}] Failed loading module: {}'.format(
                    self.name, e))
                continue
            except ModuleNotConditionCompliant:
                self._logger.info(
                    '[{}] Module {} does not comply to "{}" condition, required "{}"'
                    .format(self.name, moduleName, conditionName,
                            conditionValue))
                continue
            except Exception as e:
                self._logger.warning(
                    '[{}] Something went wrong loading a module: {}'.format(
                        self.name, e))
                continue

        # noinspection PyTypeChecker
        return collections.OrderedDict(sorted(modules.items()))
Beispiel #3
0
    def syncRemoteToLocal(self,
                          runOnAssistantId: str,
                          moduleFilter: list = None,
                          languageFilter: str = None):

        # Build cache
        self._ctx.entity.listEntitiesByUserEmail(userEmail=self._ctx.userEmail,
                                                 returnAllCacheIndexedBy='id')
        remoteIndexedIntents = self._ctx.intent.listIntentsByUserId(
            userId=self._ctx.userId, returnAllCacheIndexedBy='id')
        remoteIndexedSkills = self._ctx.skill.listSkillsByUserId(
            userId=self._ctx.userId, returnAllCacheIndexedBy='id')
        hasFork = False

        # Check for fork and execute fork if needed
        for assistant in self._ctx.assistant.list(
                rawResponse=True)['assistants']:
            if assistant['id'] != runOnAssistantId:
                continue

            for skill in assistant['skills']:
                skillId = skill['id']

                if skillId not in remoteIndexedSkills:
                    skillId = self._ctx.assistant.forkAssistantSkill(
                        assistantId=runOnAssistantId, sourceSkillId=skillId)
                    self._ctx.log(
                        f"[Forked] Skill from {skill['id']} to {skillId}")
                    hasFork = True

                for intent in skill['intents']:
                    intentId = intent['id']

                    if intentId not in remoteIndexedIntents:
                        intentId = self._ctx.skill.forkSkillIntent(
                            skillId=skillId,
                            sourceIntentId=intentId,
                            userId=self._ctx.userId)
                        self._ctx.log(
                            f"[Forked] Intent from {skill['id']} to {intentId} used in skill {skillId}"
                        )
                        hasFork = True

        if hasFork:
            # Rebuild cache
            self._ctx.entity.listEntitiesByUserEmail(
                userEmail=self._ctx.userEmail)
            self._ctx.intent.listIntentsByUserId(userId=self._ctx.userId)
            self._ctx.skill.listSkillsByUserId(userId=self._ctx.userId)

        # Build each module configuration
        modules = dict()

        cachedIndexedSkills = self._ctx.skill.listSkillsByUserIdAndAssistantId(
            userId=self._ctx.userId,
            assistantId=runOnAssistantId,
            fromCache=True)

        for skill in cachedIndexedSkills:
            moduleName = commons.toCamelCase(string=skill['name'],
                                             replaceSepCharacters=True,
                                             sepCharacters=('/', '-', '_'))

            if moduleFilter and moduleName not in moduleFilter:
                continue

            modules[moduleName] = {
                'module': moduleName,
                'icon': EnumSkillImageUrl.urlToResourceKey(skill['imageUrl']),
                'description': skill['description'],
                'slotTypes': list(),
                'intents': list()
            }
            moduleSyncState = {
                'skillId': skill['id'],
                'name': moduleName,
                'slotTypes': dict(),
                'intents': dict(),
                'hash': ''
            }

            cachedIndexedIntents = self._ctx.intent.listIntentsByUserIdAndSkillId(
                userId=self._ctx.userId, skillId=skill['id'], fromCache=True)
            typeEntityMatching = dict()

            for intent in cachedIndexedIntents:
                intentName = intent['name']

                if intentName.startswith(skill['name'] + '_'):
                    intentName = intentName.replace(skill['name'] + '_', '')

                intentName = commons.toCamelCase(string=intentName,
                                                 replaceSepCharacters=True,
                                                 sepCharacters=('/', '-', '_'))

                utterances = list()
                slots = list()
                slotIdAndNameMatching = dict()
                objectUtterances = self._ctx.intent.listUtterancesByIntentId(
                    intentId=intent['id'])

                for slot in intent['slots']:
                    slotIdAndNameMatching[slot['id']] = slot

                for objectUtterance in objectUtterances:
                    text = objectUtterance['text']
                    positionOffset = 0

                    for hole in objectUtterance['data']:
                        word = hole['text']
                        start = hole['range']['start'] + positionOffset
                        end = hole['range']['end'] + positionOffset
                        slotName = slotIdAndNameMatching[
                            hole['slotId']]['name']
                        slotName = commons.toCamelCase(
                            string=slotName,
                            replaceSepCharacters=True,
                            sepCharacters=('/', '-', '_'))
                        newWord = '{' + word + self._ctx.intent.GLUE_SLOT_WORD + slotName + '}'
                        text = text[:start] + newWord + text[end:]
                        positionOffset += len(newWord) - len(word)

                    utterances.append(text)

                cachedIndexedEntities = self._ctx.entity.listEntitiesByUserEmailAndIntentId(
                    userEmail=self._ctx.userEmail,
                    intentId=intent['id'],
                    fromCache=True)

                for entity in cachedIndexedEntities:
                    if entity['id'] in typeEntityMatching:
                        continue

                    values = self._ctx.entity.listEntityValuesByEntityId(
                        entityId=entity['id'])
                    entityName = commons.toCamelCase(string=entity['name'],
                                                     replaceSepCharacters=True,
                                                     sepCharacters=('/', '-',
                                                                    '_'))
                    typeEntityMatching[entity['id']] = entityName

                    modules[moduleName]['slotTypes'].append({
                        'name':
                        entityName,
                        'matchingStrictness':
                        entity['matchingStrictness'],
                        'automaticallyExtensible':
                        entity['automaticallyExtensible'],
                        'useSynonyms':
                        entity['useSynonyms'],
                        'values':
                        values
                    })
                    moduleSyncState['slotTypes'][entityName] = {
                        'entityId': entity['id'],
                        'hash': ''
                    }

                for slot in intent['slots']:
                    slots.append({
                        'name':
                        commons.toCamelCase(string=slot['name'],
                                            replaceSepCharacters=True,
                                            sepCharacters=('/', '-', '_')),
                        'description':
                        slot['description'],
                        'required':
                        slot['required'],
                        'type':
                        slot['entityId']
                        if slot['entityId'].startswith('snips/') else
                        typeEntityMatching[slot['entityId']],
                        'missingQuestion':
                        slot['missingQuestion']
                    })

                modules[moduleName]['intents'].append({
                    'name':
                    intentName,
                    'description':
                    intent['description'],
                    'enabledByDefault':
                    intent['enabledByDefault'],
                    'utterances':
                    utterances,
                    'slots':
                    slots
                })
                moduleSyncState['intents'][intentName] = {
                    'intentId': intent['id'],
                    'hash': ''
                }

            # Persist module configuration
            moduleConfig = modules[moduleName]
            moduleIntentsMountpoint = Path(self.SAVED_MODULES_DIR, moduleName,
                                           'dialogTemplate')
            moduleIntentsMountpoint.mkdir(parents=True, exist_ok=True)

            moduleIntentsOutputFile = moduleIntentsMountpoint / f'{languageFilter}.json'

            moduleIntentsOutputFile.write_text(
                json.dumps(moduleConfig,
                           indent=4,
                           sort_keys=False,
                           ensure_ascii=False))
            self._ctx.log(f'[LocalModule] Finished for module {moduleName}')
    def _loadModuleList(self,
                        moduleToLoad: str = '',
                        isUpdate: bool = False) -> dict:
        if moduleToLoad:
            modules = self._modules.copy()
        else:
            modules = dict()

        availableModules = self.ConfigManager.modulesConfigurations
        availableModules = collections.OrderedDict(
            sorted(availableModules.items()))

        if Customisation.MODULE_NAME in availableModules:
            customisationModule = availableModules.pop(
                Customisation.MODULE_NAME)
            availableModules[Customisation.MODULE_NAME] = customisationModule

        for moduleName, module in availableModules.items():
            if moduleToLoad and moduleName != moduleToLoad:
                continue

            try:
                if not module['active']:
                    if moduleName in self.NEEDED_MODULES:
                        self._logger.info(
                            f"Module {moduleName} marked as disable but it shouldn't be"
                        )
                        SuperManager.getInstance().onStop()
                        break
                    else:
                        self._logger.info(f'Module {moduleName} is disabled')

                        moduleInstance = self.importFromModule(
                            moduleName=moduleName, isUpdate=False)
                        if moduleInstance:
                            moduleInstance.active = False

                            if moduleName in self.NEEDED_MODULES:
                                moduleInstance.required = True

                            self._deactivatedModules[moduleInstance.name] = {
                                'instance': moduleInstance
                            }
                        continue

                self.checkModuleConditions(moduleName, module['conditions'],
                                           availableModules)

                if ' ' in moduleName:
                    name = commons.toCamelCase(moduleName)
                else:
                    name = moduleName

                moduleInstance = self.importFromModule(moduleName=name,
                                                       isUpdate=isUpdate)

                if moduleInstance:

                    if moduleName in self.NEEDED_MODULES:
                        moduleInstance.required = True

                    modules[moduleInstance.name] = {'instance': moduleInstance}
            except ModuleStartingFailed as e:
                self._logger.warning(
                    f'[{self.name}] Failed loading module: {e}')
                continue
            except ModuleNotConditionCompliant as e:
                self._logger.info(
                    f'[{self.name}] Module {moduleName} does not comply to "{e.condition}" condition, required "{e.conditionValue}"'
                )
                continue
            except Exception as e:
                self._logger.warning(
                    f'[{self.name}] Something went wrong loading a module: {e}'
                )
                continue

        # noinspection PyTypeChecker
        return collections.OrderedDict(sorted(modules.items()))