voxygen.py 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. import hashlib
  2. import os
  3. import shutil
  4. import pygame
  5. import requests
  6. import logging
  7. import sys
  8. from core import AudioPlayer
  9. VOXYGEN_LANGUAGES = dict(
  10. fr=dict(electra="Electra", emma="Emma", becool="Becool", agnes="Agnes", loic="Loic", fabienne="Fabienne", helene="Helene", marion="Marion", matteo="Matteo",
  11. melodine="Melodine", mendoo="Mendoo", michel="Michel", moussa="Moussa", philippe="Philippe", sorciere="Sorciere"),
  12. ar=dict(adel="Adel"),
  13. de=dict(matthias="Matthias", jylvia="Sylvia"),
  14. uk=dict(bronwen="Bronwen", elizabeth="elizabeth", judith="Judith", paul="Paul", witch="Witch"),
  15. us=dict(bruce="Bruce", jenny="Jenny"),
  16. es=dict(martha="Martha"),
  17. it=dict(sonia="Sonia"))
  18. VOXYGEN_VOICE_DEFAULT = "Michel"
  19. VOXYGEN_LANGUAGES_DEFAULT = "default"
  20. VOXYGEN_URL = "https://www.voxygen.fr/sites/all/modules/voxygen_voices/assets/proxy/index.php"
  21. VOXYGEN_CONTENT_TYPE = "audio/mpeg"
  22. VOXYGEN_TIMEOUT_SEC = 30
  23. CACHE_PATH = "/tmp/jarvis/tts/voxygen"
  24. CACHE_EXTENSION = ".tts"
  25. AUDIO_FREQUENCY = 16000
  26. AUDIO_SIZE = -16
  27. AUDIO_CHANNEL = 1
  28. AUDIO_BUFFER = 2048
  29. def say(words=None, voice=None, language=VOXYGEN_LANGUAGES_DEFAULT, cache=True):
  30. voice = get_voice(voice, language)
  31. file_path = get_file_path(words, voice, language)
  32. if get_audio(voice, words, file_path, cache):
  33. AudioPlayer.play_audio(file_path, keep_file=cache)
  34. def get_file_path(words, voice, language):
  35. md5 = hashlib.md5(words).hexdigest()
  36. filename = voice + "." + md5 + CACHE_EXTENSION
  37. cache_directory = os.path.join(CACHE_PATH, language)
  38. file_path = os.path.join(cache_directory, filename)
  39. create_directory(cache_directory)
  40. logging.debug("Cache directory %s exists and File path for audio is: %s", cache_directory, file_path)
  41. return file_path
  42. def get_voice(voice, language):
  43. if language in VOXYGEN_LANGUAGES and voice in VOXYGEN_LANGUAGES[language]:
  44. return VOXYGEN_LANGUAGES[language][voice]
  45. logging.warn("Cannot find language matching language: %s voice: %s replace by default voice: %s", language, voice, VOXYGEN_VOICE_DEFAULT)
  46. return VOXYGEN_VOICE_DEFAULT
  47. def get_audio(voice, text, file_path, cache):
  48. if not cache or not os.path.exists(file_path) or file_is_empty(file_path):
  49. payload = {
  50. "method": "redirect",
  51. "text": text.encode('utf8'),
  52. "voice": voice
  53. }
  54. r = requests.get(VOXYGEN_URL, params=payload, stream=True, timeout=VOXYGEN_TIMEOUT_SEC)
  55. content_type = r.headers['Content-Type']
  56. logging.debug("Trying to get url: %s response code: %s and content-type: %s", r.url, r.status_code, content_type)
  57. try:
  58. if r.status_code == requests.codes.ok and content_type == VOXYGEN_CONTENT_TYPE:
  59. return write_in_file(file_path, r.content)
  60. else:
  61. return False
  62. except IOError as e:
  63. logging.error("I/O error(%s): %s", e.errno, e.strerror)
  64. except ValueError:
  65. logging.error("Could not convert data to an integer.")
  66. except:
  67. logging.error("Unexpected error: %s", sys.exc_info()[0])
  68. else:
  69. return True
  70. def write_in_file(file_path, content):
  71. with open(file_path, "wb") as file_open:
  72. file_open.write(content)
  73. file_open.close()
  74. return not file_is_empty(file_path)
  75. def file_is_empty(file_path):
  76. return os.path.getsize(file_path) == 0
  77. def create_directory(cache_path):
  78. if not os.path.exists(cache_path):
  79. os.makedirs(cache_path)
  80. def wipe_cache():
  81. shutil.rmtree(CACHE_PATH)