NeuronModule.py 5.8 KB

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