NeuronModule.py 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. # coding: utf8
  2. import logging
  3. import os
  4. import random
  5. from jinja2 import Template
  6. from core.Utils import Utils
  7. from core.ConfigurationManager import SettingLoader
  8. logging.basicConfig()
  9. logger = logging.getLogger("kalliope")
  10. class NoTemplateException(Exception):
  11. pass
  12. class MultipleTemplateException(Exception):
  13. pass
  14. class TemplateFileNotFoundException(Exception):
  15. pass
  16. class TTSModuleNotFound(Exception):
  17. pass
  18. class TTSNotInstantiable(Exception):
  19. pass
  20. class NeuronModule(object):
  21. def __init__(self, **kwargs):
  22. """
  23. Class used by neuron for talking
  24. :param kwargs: Same parameter as the Child. Can contain info about the tts to use instead of the
  25. default one
  26. """
  27. # get the child who called the class
  28. child_name = self.__class__.__name__
  29. logger.debug("NeuronModule called from class %s with parameters: %s" % (child_name, str(kwargs)))
  30. self.settings = SettingLoader.get_settings()
  31. # check if the user has overrider the TTS
  32. tts = kwargs.get('tts', None)
  33. if tts is None:
  34. # No tts provided, we load the default one
  35. self.tts = self.settings.default_tts_name
  36. else:
  37. self.tts = tts
  38. # get if the cache settings is present
  39. self.override_cache = kwargs.get('cache', None)
  40. # get templates if provided
  41. # Check if there is a template associate to the output message
  42. self.say_template = kwargs.get('say_template', None)
  43. # check if there is a template file associate to the output message
  44. self.file_template = kwargs.get('file_template', None)
  45. def say(self, message):
  46. """
  47. USe TTS to speak out loud the Message.
  48. A message can be a string, a list or a dict
  49. If it's a string, simply use the TTS with the message
  50. If it's a list, we select randomly a string in the list and give it to the TTS
  51. If it's a dict, we use the template given in parameter to create a string that we give to the TTS
  52. :param message: Can be a String or a dict
  53. :return:
  54. """
  55. logger.debug("NeuronModule Say() called with message: %s" % message)
  56. tts_message = None
  57. if isinstance(message, str) or isinstance(message, unicode):
  58. logger.debug("message is string")
  59. tts_message = message
  60. if isinstance(message, list):
  61. logger.debug("message is list")
  62. tts_message = self._get_message_from_list(message)
  63. if isinstance(message, dict):
  64. logger.debug("message is dict")
  65. tts_message = self._get_message_from_dict(message)
  66. if message is not None:
  67. # get an instance of the target TTS
  68. tts_instance = self._get_tts_instance(self.tts)
  69. tts_args = None
  70. for tts_object in self.settings.ttss:
  71. if tts_object.name == self.tts:
  72. tts_args = tts_object.parameters
  73. logger.debug("NeuronModule: tts_args: %s" % tts_args)
  74. logger.debug("tts_message to say: %s" % tts_message)
  75. # change the cache settings with the one precised for the current neuron
  76. if self.override_cache is not None:
  77. tts_args = self._update_cache_var(self.override_cache, tts_args)
  78. logger.debug("NeuroneModule: TTS args: %s" % tts_args)
  79. tts_instance.say(words=tts_message, **(tts_args if tts_args is not None else {}))
  80. @staticmethod
  81. def _get_message_from_list(message_list):
  82. """
  83. Return an element from the list randomly
  84. :param message_list:
  85. :return:
  86. """
  87. return random.choice(message_list)
  88. def _get_message_from_dict(self, message_dict):
  89. returned_message = None
  90. if (self.say_template is not None and self.file_template is None) or \
  91. (self.say_template is None and self.file_template is not None):
  92. # the user choose a say_template option
  93. if self.say_template is not None:
  94. if isinstance(self.say_template, list):
  95. # then we pick randomly one template
  96. self.say_template = random.choice(self.say_template)
  97. t = Template(self.say_template)
  98. returned_message = t.render(**message_dict)
  99. # the user choose a file_template option
  100. if self.file_template is not None: # the user choose a file_template option
  101. real_file_template_path = "templates/%s" % self.file_template
  102. if os.path.isfile(real_file_template_path):
  103. # load the content of the file as template
  104. t = Template(self._get_content_of_file(real_file_template_path))
  105. returned_message = t.render(**message_dict)
  106. else:
  107. raise TemplateFileNotFoundException("Template file %s not found in templates folder"
  108. % real_file_template_path)
  109. return returned_message
  110. else:
  111. raise NoTemplateException("You must specify a say_template or a file_template")
  112. @staticmethod
  113. def _get_content_of_file(real_file_template_path):
  114. with open(real_file_template_path, 'r') as content_file:
  115. return content_file.read()
  116. @staticmethod
  117. def _get_tts_instance(tts_name):
  118. return Utils.get_dynamic_class_instantiation("tts", tts_name.capitalize())
  119. @staticmethod
  120. def _update_cache_var(new_override_cache, args_list):
  121. logger.debug("args for TTS plugin before update: %s" % str(args_list))
  122. args_list["cache"] = new_override_cache
  123. logger.debug("args for TTS plugin after update: %s" % str(args_list))
  124. return args_list