def start_kalliope(settings, brain): """ Start all signals declared in the brain """ # start kalliope Utils.print_success("Starting Kalliope") Utils.print_info("Press Ctrl+C for stopping") # catch signal for killing on Ctrl+C pressed signal.signal(signal.SIGINT, signal_handler) # get a list of signal class to load from declared synapse in the brain # this list will contain string of signal class type. # For example, if the brain contains multiple time the signal type "order", the list will be ["order"] # If the brain contains some synapse with "order" and "event", the list will be ["order", "event"] list_signals_class_to_load = get_list_signal_class_to_load(brain) # start each class name for signal_class_name in list_signals_class_to_load: signal_instance = SignalLauncher.launch_signal_class_by_name( signal_name=signal_class_name, settings=settings) if signal_instance is not None: signal_instance.daemon = True signal_instance.start() while True: # keep main thread alive time.sleep(0.1)
def load_events(self): """ For each received synapse that have an event as signal, we add a new job scheduled to launch the synapse :return: """ for synapse in self.synapses: for signal in synapse.signals: # if the signal is an event we add it to the task list if signal.name == "event": if self.check_event_dict(signal.parameters): my_cron = CronTrigger( year=self.get_parameter_from_dict( "year", signal.parameters), month=self.get_parameter_from_dict( "month", signal.parameters), day=self.get_parameter_from_dict( "day", signal.parameters), week=self.get_parameter_from_dict( "week", signal.parameters), day_of_week=self.get_parameter_from_dict( "day_of_week", signal.parameters), hour=self.get_parameter_from_dict( "hour", signal.parameters), minute=self.get_parameter_from_dict( "minute", signal.parameters), second=self.get_parameter_from_dict( "second", signal.parameters), ) Utils.print_info( "Add synapse name \"%s\" to the scheduler: %s" % (synapse.name, my_cron)) self.scheduler.add_job(self.run_synapse_by_name, my_cron, args=[synapse.name])
def __init__(self, **kwargs): super(Event, self).__init__(**kwargs) Utils.print_info('[Event] Starting manager') self.scheduler = BackgroundScheduler() self.list_synapses_with_event = list( super(Event, self).get_list_synapse()) self.load_events()
def __init__(self, **kwargs): super(SignalModule, self).__init__(**kwargs) # get the child who called the class self.signal_name = self.__class__.__name__ Utils.print_info('Init Signal :' + self.signal_name) self.brain = BrainLoader().brain
def __init__(self, **kwargs): super(Event, self).__init__(**kwargs) Thread.__init__(self, name=Event) Utils.print_info('[Event] Starting manager') self.scheduler = BackgroundScheduler() self.list_synapses_with_event = list(super(Event, self).get_list_synapse()) self.load_events()
def _add_event(self, period_string, event_id): """ Add a single event in the crontab. Will add a line like: <period_string> python /path/to/kalliope.py start --brain-file /path/to/brain.yml --run-synapse "<event_id>" E.g: 30 7 * * * python /home/me/kalliope/kalliope.py start --brain-file /home/me/brain.yml --run-synapse "Say-hello" :param period_string: crontab period :type period_string: str :param event_id: :type event_id: str :return: """ my_user_cron = CronTab(user=True) job = my_user_cron.new(command=self.base_command + " " + str("\"" + event_id + "\""), comment=CRONTAB_COMMENT) if CronSlices.is_valid(period_string): job.setall(period_string) job.enable() else: raise InvalidCrontabPeriod("The crontab period %s is not valid" % period_string) # write the file my_user_cron.write() Utils.print_info("Synapse \"%s\" added to the crontab" % event_id)
def __init__(self): super(Event, self).__init__() Utils.print_info('Starting event manager') self.scheduler = BackgroundScheduler() self.brain = BrainLoader().get_brain() self.synapses = self.brain.synapses self.load_events()
def __init__(self, **kwargs): super(SignalModule, self).__init__() # get the child who called the class self.signal_name = self.__class__.__name__ Utils.print_info('Init Signal :' + self.signal_name) self.brain = BrainLoader().brain
def __init__(self, **kwargs): super(Mqtt_subscriber, self).__init__(**kwargs) Thread.__init__(self, name=Mqtt_subscriber) Utils.print_info('[Mqtt_subscriber] Starting manager')# variables self.list_synapses_with_mqtt = list(super(Mqtt_subscriber, self).get_list_synapse()) self.broker_ip = None self.topic = None self.json_message = False
def __init__(self, **kwargs): super(Mqtt_subscriber, self).__init__(**kwargs) Utils.print_info('[Mqtt_subscriber] Starting manager') # variables self.list_synapses_with_mqtt = list( super(Mqtt_subscriber, self).get_list_synapse()) self.broker_ip = None self.topic = None self.json_message = False
def run_synapse_by_name(synapse_name): """ This method will run the synapse """ Utils.print_info("[Event] triggered, running synapse: %s" % synapse_name) # get a brain brain_loader = BrainLoader() brain = brain_loader.brain SynapseLauncher.start_synapse_by_list_name([synapse_name], brain=brain)
def signal_handler(signal, frame): """ Used to catch a keyboard signal like Ctrl+C in order to kill the kalliope program :param signal: signal handler :param frame: execution frame """ print "\n" Utils.print_info("Ctrl+C pressed. Killing Kalliope") sys.exit(0)
def unpausing_trigger_process(self): """ If the trigger was in pause, this method will unpause it to listen again for the hotword """ logger.debug("Entering state: %s" % self.state) self.trigger_instance.unpause() self.trigger_callback_called = False Utils.print_info("Waiting for trigger detection") self.next_state()
def run_synapse_by_name(synapse_name): """ This method will run the synapse """ Utils.print_info("Event triggered, running synapse: %s" % synapse_name) # get a brain brain_loader = BrainLoader() brain = brain_loader.brain SynapseLauncher.start_synapse(synapse_name, brain=brain)
def waiting_for_trigger_callback_thread(self): """ Method to print in debug that the main process is waiting for a trigger detection """ logger.debug("[MainController] Entering state: %s" % self.state) Utils.print_info("Waiting for trigger detection") # this loop is used to keep the main thread alive while not self.trigger_callback_called: sleep(0.1) self.next_state()
def muted_button_pressed(self, muted=False): logger.debug( "[MainController] Mute button pressed. Switch trigger process to muted: %s" % muted) if muted: self.trigger_instance.pause() Utils.print_info("Kalliope now muted") else: self.trigger_instance.unpause() Utils.print_info("Kalliope now listening for trigger detection")
def houndify_callback(self, recognizer, audio): """ called from the background thread """ try: captured_audio = recognizer.recognize_houndify( audio, client_id=self.client_id, client_key=self.key, show_all=self.show_all) Utils.print_success( "Houndify Speech Recognition thinks you said %s" % captured_audio) self._analyse_audio(captured_audio) except sr.UnknownValueError: Utils.print_warning( "Houndify Speech Recognition could not understand audio") # callback anyway, we need to listen again for a new order self._analyse_audio(audio_to_text=None) except sr.RequestError as e: Utils.print_danger( "Could not request results from Houndify Speech Recognition service; {0}" .format(e)) # callback anyway, we need to listen again for a new order self._analyse_audio(audio_to_text=None) except AssertionError: Utils.print_warning("No audio caught from microphone") self._analyse_audio(audio_to_text=None)
def apiai_callback(self, recognizer, audio): """ called from the background thread :param recognizer: :param audio: :return: """ try: captured_audio = recognizer.recognize_api(audio, client_access_token=self.key, language=self.language, session_id=self.session_id, show_all=self.show_all) Utils.print_success("Apiai Speech Recognition thinks you said %s" % captured_audio) self._analyse_audio(captured_audio) except sr.UnknownValueError as e: Utils.print_warning("Apiai Speech Recognition could not understand audio; {0}".format(e)) # callback anyway, we need to listen again for a new order self._analyse_audio(audio_to_text=None) except sr.RequestError as e: Utils.print_danger("Could not request results from Apiai Speech Recognition service; {0}".format(e)) # callback anyway, we need to listen again for a new order self._analyse_audio(audio_to_text=None) except AssertionError: Utils.print_warning("No audio caught from microphone") self._analyse_audio(audio_to_text=None)
def apiai_callback(self, recognizer, audio): """ called from the background thread :param recognizer: :param audio: :return: """ try: captured_audio = recognizer.recognize_api( audio, client_access_token=self.key, language=self.language, session_id=self.session_id, show_all=self.show_all) Utils.print_success("Apiai Speech Recognition thinks you said %s" % captured_audio) self._analyse_audio(captured_audio) except sr.UnknownValueError as e: Utils.print_warning( "Apiai Speech Recognition could not understand audio; {0}". format(e)) # callback anyway, we need to listen again for a new order self._analyse_audio(audio_to_text=None) except sr.RequestError as e: Utils.print_danger( "Could not request results from Apiai Speech Recognition service; {0}" .format(e)) # callback anyway, we need to listen again for a new order self._analyse_audio(audio_to_text=None) except AssertionError: Utils.print_warning("No audio caught from microphone") self._analyse_audio(audio_to_text=None)
def _start_rest_api(self): """ Start the Rest API if asked in the user settings """ # run the api if the user want it if self.settings.rest_api.active: Utils.print_info("Starting REST API Listening port: %s" % self.settings.rest_api.port) app = Flask(__name__) flask_api = FlaskAPI(app=app, port=self.settings.rest_api.port, brain=self.brain, allowed_cors_origin=self.settings.rest_api.allowed_cors_origin) flask_api.daemon = True flask_api.start()
def sphinx_callback(self, recognizer, audio): """ called from the background thread """ try: captured_audio = recognizer.recognize_sphinx( audio, language=self.language, keyword_entries=self.keyword_entries, grammar=self.grammar_file) Utils.print_success( "Sphinx Speech Recognition thinks you said %s" % captured_audio) self._analyse_audio(captured_audio) except sr.UnknownValueError: Utils.print_warning( "Sphinx Speech Recognition could not understand audio") # callback anyway, we need to listen again for a new order self._analyse_audio(audio_to_text=None) except sr.RequestError as e: Utils.print_danger( "Could not request results from Sphinx Speech Recognition service; {0}" .format(e)) # callback anyway, we need to listen again for a new order self._analyse_audio(audio_to_text=None) except AssertionError: Utils.print_warning("No audio caught from microphone") self._analyse_audio(audio_to_text=None)
def analyse_order(self, order): """ Receive an order, try to retrieve it in the brain.yml to launch to attached plugins :param order: the sentence received :type order: str """ if order is not None: # maybe we have received a null audio from STT engine order_analyser = OrderAnalyser(order, brain=self.brain) order_analyser.start() # restart the trigger when the order analyser has finish his job Utils.print_info("Waiting for trigger detection") self.trigger_instance.unpause() # create a new order listener that will wait for start self.order_listener = OrderListener(self.analyse_order)
def get_trigger(settings, callback): """ Start a trigger module :param trigger: trigger object to instantiate :type trigger: Trigger :param callback: Callback function to call when the trigger catch the magic word :return: The instance of Trigger :rtype: Trigger """ trigger_folder = None if settings.resources: trigger_folder = settings.resources.trigger_folder trigger_instance = None for trigger in settings.triggers: if trigger.name == settings.default_trigger_name: # add the callback method to parameters trigger.parameters["callback"] = callback logger.debug( "TriggerLauncher: Start trigger %s with parameters: %s" % (trigger.name, trigger.parameters)) trigger_instance = Utils.get_dynamic_class_instantiation( package_name="trigger", module_name=trigger.name, parameters=trigger.parameters, resources_dir=trigger_folder) break return trigger_instance
def load_events(self): """ For each received synapse that have an event as signal, we add a new job scheduled to launch the synapse :return: """ for synapse in self.synapses: for signal in synapse.signals: # if the signal is an event we add it to the task list if type(signal) == Event: my_cron = CronTrigger(year=signal.year, month=signal.month, day=signal.day, week=signal.week, day_of_week=signal.day_of_week, hour=signal.hour, minute=signal.minute, second=signal.second) Utils.print_info("Add synapse name \"%s\" to the scheduler: %s" % (synapse.name, my_cron)) self.scheduler.add_job(self.run_synapse_by_name, my_cron, args=[synapse.name])
def load_events(self): """ For each received synapse that have an event as signal, we add a new job scheduled to launch the synapse """ for synapse in self.list_synapses_with_event: for signal in synapse.signals: # We need to loop here again if the synapse has multiple event signals. # if the signal is an event we add it to the task list. if signal.name == "event": my_cron = CronTrigger(year=self.get_parameter_from_dict("year", signal.parameters), month=self.get_parameter_from_dict("month", signal.parameters), day=self.get_parameter_from_dict("day", signal.parameters), week=self.get_parameter_from_dict("week", signal.parameters), day_of_week=self.get_parameter_from_dict("day_of_week", signal.parameters), hour=self.get_parameter_from_dict("hour", signal.parameters), minute=self.get_parameter_from_dict("minute", signal.parameters), second=self.get_parameter_from_dict("second", signal.parameters), ) Utils.print_info("Add synapse name \"%s\" to the scheduler: %s" % (synapse.name, my_cron)) self.scheduler.add_job(self.run_synapse_by_name, my_cron, args=[synapse.name])
def _get_random_sound(random_wake_up_sounds): """ Return a path of a sound to play If the path is absolute, test if file exist If the path is relative, we check if the file exist in the sound folder :param random_wake_up_sounds: List of wake_up sounds :return: path of a sound to play """ # take first randomly a path random_path = random.choice(random_wake_up_sounds) logger.debug("Selected sound: %s" % random_path) return Utils.get_real_file_path(random_path)
def google_callback(self, recognizer, audio): """ called from the background thread """ try: captured_audio = recognizer.recognize_google( audio, key=self.key, language=self.language, show_all=self.show_all) Utils.print_success( "Google Speech Recognition thinks you said %s" % captured_audio) self._analyse_audio(audio_to_text=captured_audio) except sr.UnknownValueError: Utils.print_warning( "Google Speech Recognition could not understand audio") # callback anyway, we need to listen again for a new order self._analyse_audio(audio_to_text=None) except sr.RequestError as e: Utils.print_danger( "Could not request results from Google Speech Recognition service; {0}" .format(e)) # callback anyway, we need to listen again for a new order self._analyse_audio(audio_to_text=None) self.stop_listening()
def start_kalliope(settings, brain): """ Start all signals declared in the brain """ # start kalliope Utils.print_success("Starting Kalliope") Utils.print_info("Press Ctrl+C for stopping") # catch signal for killing on Ctrl+C pressed signal.signal(signal.SIGINT, signal_handler) # get a list of signal class to load from declared synapse in the brain # this list will contain string of signal class type. # For example, if the brain contains multiple time the signal type "order", the list will be ["order"] # If the brain contains some synapse with "order" and "event", the list will be ["order", "event"] list_signals_class_to_load = get_list_signal_class_to_load(brain) # start each class name try: for signal_class_name in list_signals_class_to_load: signal_instance = SignalLauncher.launch_signal_class_by_name(signal_name=signal_class_name, settings=settings) if signal_instance is not None: signal_instance.daemon = True signal_instance.start() while True: # keep main thread alive time.sleep(0.1) except (KeyboardInterrupt, SystemExit): # we need to switch GPIO pin to default status if we are using a Rpi if settings.rpi_settings: Utils.print_info("GPIO cleaned") logger.debug("Clean GPIO") import RPi.GPIO as GPIO GPIO.cleanup()
def sphinx_callback(self, recognizer, audio): """ called from the background thread """ try: captured_audio = recognizer.recognize_sphinx(audio) Utils.print_success( "Sphinx Speech Recognition thinks you said %s" % captured_audio) self._analyse_audio(captured_audio) except sr.UnknownValueError: Utils.print_warning( "Sphinx Speech Recognition could not understand audio") # callback anyway, we need to listen again for a new order self._analyse_audio(audio_to_text=None) except sr.RequestError as e: Utils.print_danger( "Could not request results from Sphinx Speech Recognition service; {0}" .format(e)) # callback anyway, we need to listen again for a new order self._analyse_audio(audio_to_text=None) # stop listening for an audio self.stop_listening()
def __init__(self, callback=None, **kwargs): """ Start recording the microphone and analyse audio with google api :param callback: The callback function to call to send the text :param kwargs: """ OrderListener.__init__(self) # callback function to call after the translation speech/tex self.callback = callback # obtain audio from the microphone r = sr.Recognizer() with sr.Microphone() as source: # listen for 1 second to calibrate the energy threshold for ambient noise levels r.adjust_for_ambient_noise(source) Utils.print_info("Say something!") audio = r.listen(source) # recognize speech using Google Speech Recognition try: # for testing purposes, we're just using the default API key # to use another API key, use `r.recognize_google(audio, key="GOOGLE_SPEECH_RECOGNITION_API_KEY")` # instead of `r.recognize_google(audio)` key = kwargs.get('key', None) language = kwargs.get('language', "en-US") show_all = kwargs.get('show_all', False) captured_audio = r.recognize_google(audio, key=key, language=language, show_all=show_all) Utils.print_success( "Google Speech Recognition thinks you said %s" % captured_audio) self._analyse_audio(captured_audio) except sr.UnknownValueError: Utils.print_warning( "Google Speech Recognition could not understand audio") # callback anyway, we need to listen again for a new order self._analyse_audio(audio=None) except sr.RequestError as e: Utils.print_danger( "Could not request results from Google Speech Recognition service; {0}" .format(e)) # callback anyway, we need to listen again for a new order self._analyse_audio(audio=None)
def get_tts(cls, tts): """ Return an instance of a TTS module from the name of this module :param tts: TTS model :type tts: Tts :return: TTS module instance .. seealso:: TTS .. warnings:: Class Method and Public """ logger.debug("get TTS module \"%s\" with parameters %s" % (tts.name, tts.parameters)) return Utils.get_dynamic_class_instantiation(package_name="tts", module_name=tts.name, parameters=tts.parameters)
def get_trigger(cls, trigger, callback): """ Start a trigger module :param trigger: trigger object to instantiate :type trigger: Trigger :param callback: Callback function to call when the trigger catch the magic word :return: """ # add the callback method to parameters trigger.parameters["callback"] = callback logger.debug("TriggerLauncher: Start trigger %s with parameters: %s" % (trigger.name, trigger.parameters)) return Utils.get_dynamic_class_instantiation("trigger", trigger.name.capitalize(), trigger.parameters)
def __init__(self, brain=None): self.brain = brain # get global configuration sl = SettingLoader.Instance() self.settings = sl.settings # run the api if the user want it if self.settings.rest_api.active: Utils.print_info("Starting REST API Listening port: %s" % self.settings.rest_api.port) app = Flask(__name__) flask_api = FlaskAPI(app, port=self.settings.rest_api.port, brain=self.brain) flask_api.daemon = True flask_api.start() # create an order listener object. This last will the trigger callback before starting self.order_listener = OrderListener(self.analyse_order) # Wait that the kalliope trigger is pronounced by the user self.trigger_instance = self._get_default_trigger() self.trigger_instance.start() Utils.print_info("Waiting for trigger detection")
def __init__(self, callback=None, **kwargs): """ Start recording the microphone and analyse audio with Houndify api :param callback: The callback function to call to send the text :param kwargs: """ OrderListener.__init__(self) # callback function to call after the translation speech/tex self.callback = callback # obtain audio from the microphone r = sr.Recognizer() with sr.Microphone() as source: # listen for 1 second to calibrate the energy threshold for ambient noise levels r.adjust_for_ambient_noise(source) Utils.print_info("Say something!") audio = r.listen(source) # recognize speech using Houndify Speech Recognition try: client_id = kwargs.get('client_id', None) key = kwargs.get('key', None) language = kwargs.get('language', "en-US") show_all = kwargs.get('show_all', False) captured_audio = r.recognize_houndify(audio, client_id=client_id, client_key=key, language=language, show_all=show_all) Utils.print_success( "Houndify Speech Recognition thinks you said %s" % captured_audio) self._analyse_audio(captured_audio) except sr.UnknownValueError: Utils.print_warning( "Houndify Speech Recognition could not understand audio") # callback anyway, we need to listen again for a new order self._analyse_audio(audio=None) except sr.RequestError as e: Utils.print_danger( "Could not request results from Houndify Speech Recognition service; {0}" .format(e)) # callback anyway, we need to listen again for a new order self._analyse_audio(audio=None)
def vosk_callback(self, recognizer, audio_data): model = Model("model-fr") rec = KaldiRecognizer(model, 16000) upm = sr.Microphone() kl = sr.Recognizer() if not os.path.exists("model-fr"): print( "Please download the model from https://github.com/alphacep/kaldi-android-demo/releases and unpack as 'model-fr' in the current folder." ) exit(1) sl_data = audio_data.get_raw_data( convert_rate=16000, convert_width=2 ) # the included language models require audio to be 16-bit mono 16 kHz format try: if len(sl_data) == 0: print("len = 0") if rec.AcceptWaveform(sl_data): res = json.loads(rec.Result()) res = json.loads(rec.FinalResult()) captured_audio = res['text'] Utils.print_success("Vosk thinks you said %s" % captured_audio) self._analyse_audio(captured_audio) except sr.UnknownValueError: Utils.print_warning( "Vosk Speech Recognition could not understand audio") self._analyse_audio(audio_to_text=None) except sr.RequestError as e: Utils.print_danger( "Could not request results from Vosk Speech Recognition service; {0}" .format(e)) self._analyse_audio(audio_to_text=None) except AssertionError: Utils.print_warning("No audio caught from microphone") self._analyse_audio(audio_to_text=None)
def get_player(settings): """ Instantiate a Player :param settings: setting object :type settings: Settings :return: the Player instance :rtype: Player """ player_instance = None for player in settings.players: if player.name == settings.default_player_name: logger.debug("PlayerLauncher: Start player %s with parameters: %s" % (player.name, player.parameters)) player_instance = Utils.get_dynamic_class_instantiation(package_name="players", module_name=player.name, parameters=player.parameters) break return player_instance
def wit_callback(self, recognizer, audio): try: captured_audio = recognizer.recognize_wit(audio, key=self.key, show_all=self.show_all) Utils.print_success("Wit.ai Speech Recognition thinks you said %s" % captured_audio) self._analyse_audio(captured_audio) except sr.UnknownValueError: Utils.print_warning("Wit.ai Speech Recognition could not understand audio") # callback anyway, we need to listen again for a new order self._analyse_audio(audio_to_text=None) except sr.RequestError as e: Utils.print_danger("Could not request results from Wit.ai Speech Recognition service; {0}".format(e)) # callback anyway, we need to listen again for a new order self._analyse_audio(audio_to_text=None) except AssertionError: Utils.print_warning("No audio caught from microphone") self._analyse_audio(audio_to_text=None)
def google_callback(self, recognizer, audio): """ called from the background thread """ try: captured_audio = recognizer.recognize_google(audio, key=self.key, language=self.language, show_all=self.show_all) Utils.print_success("Google Speech Recognition thinks you said %s" % captured_audio) self._analyse_audio(audio_to_text=captured_audio) except sr.UnknownValueError: Utils.print_warning("Google Speech Recognition could not understand audio") # callback anyway, we need to listen again for a new order self._analyse_audio(audio_to_text=None) except sr.RequestError as e: Utils.print_danger("Could not request results from Google Speech Recognition service; {0}".format(e)) # callback anyway, we need to listen again for a new order self._analyse_audio(audio_to_text=None) except AssertionError: Utils.print_warning("No audio caught from microphone") self._analyse_audio(audio_to_text=None)
def get_player(settings): """ Instantiate a Player :param settings: setting object :type settings: Settings :return: the Player instance :rtype: Player """ player_instance = None for player in settings.players: if player.name == settings.default_player_name: logger.debug( "PlayerLauncher: Start player %s with parameters: %s" % (player.name, player.parameters)) player_instance = Utils.get_dynamic_class_instantiation( package_name="players", module_name=player.name, parameters=player.parameters) break return player_instance
def _check_dna_file(dna_file): """ Check the content of a DNA file :param dna_file: the dna to check :return: True if ok, False otherwise """ success_loading = True if "name" not in dna_file: Utils.print_danger("The DNA of does not contains a \"name\" tag") success_loading = False if "type" not in dna_file: Utils.print_danger("The DNA of does not contains a \"type\" tag") success_loading = False else: # we have a type, check that is a valid one if dna_file["type"] not in VALID_DNA_MODULE_TYPE: Utils.print_danger("The DNA type %s is not valid" % dna_file["type"]) Utils.print_danger("The DNA type must be one of the following: %s" % VALID_DNA_MODULE_TYPE) success_loading = False if "kalliope_supported_version" not in dna_file: Utils.print_danger("The DNA of does not contains a \"kalliope_supported_version\" tag") success_loading = False else: # kalliope_supported_version must be a non empty list if not isinstance(dna_file["kalliope_supported_version"], list): Utils.print_danger("kalliope_supported_version is not a list") success_loading = False else: if not dna_file["kalliope_supported_version"]: Utils.print_danger("kalliope_supported_version cannot be empty") success_loading = False else: for supported_version in dna_file["kalliope_supported_version"]: # check if major version is provided if not re.search('^[\d]*[.][\d]*$', str(supported_version)): Utils.print_danger("kalliope_supported_version cannot handle this format of version %s. " "Only major version should be provided" % supported_version) success_loading = False return success_loading