NeuronModule.py 6.0 KB

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