cache_handler.py
Go to the documentation of this file.
1 # Copyright 2019 Mycroft AI Inc.
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 # http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14 
15 """
16 Cache handler - reads all the .dialog files (The default
17 mycroft responses) and does a tts inference.
18 It then saves the .wav files to mark1 device
19 
20 """
21 
22 import base64
23 import glob
24 import os
25 import re
26 import shutil
27 import hashlib
28 import json
29 import mycroft.util as util
30 from urllib import parse
31 from requests_futures.sessions import FuturesSession
32 from mycroft.util.log import LOG
33 
34 
35 REGEX_SPL_CHARS = re.compile(r'[@#$%^*()<>/\|}{~:]')
36 MIMIC2_URL = 'https://mimic-api.mycroft.ai/synthesize?text='
37 
38 # For now we only get the cache for mimic2-kusal
39 TTS = 'Mimic2'
40 
41 # Check for more default dialogs
42 res_path = os.path.abspath(os.path.join(os.path.abspath(__file__), '..',
43  '..', 'res', 'text', 'en-us'))
44 wifi_setup_path = '/usr/local/mycroft/mycroft-wifi-setup/dialog/en-us'
45 cache_dialog_path = [res_path, wifi_setup_path]
46 
47 
48 def generate_cache_text(cache_audio_dir, cache_text_file):
49  """
50  This prepares a text file with all the sentences
51  from *.dialog files present in
52  mycroft/res/text/en-us and mycroft-wifi setup skill
53  Args:
54  cache_audio_dir (path): path to store .wav files
55  cache_text_file (file): file containing the sentences
56  """
57  try:
58  if not os.path.isfile(cache_text_file):
59  os.makedirs(cache_audio_dir)
60  f = open(cache_text_file, 'w')
61  for each_path in cache_dialog_path:
62  if os.path.exists(each_path):
63  write_cache_text(each_path, f)
64  f.close()
65  LOG.debug("Completed generating cache")
66  else:
67  LOG.debug("Cache file 'cache_text.txt' already exists")
68  except Exception:
69  LOG.error("Could not open text file to write cache")
70 
71 
72 def write_cache_text(cache_path, f):
73  for file in glob.glob(cache_path + "/*.dialog"):
74  try:
75  with open(file, 'r') as fp:
76  all_dialogs = fp.readlines()
77  for each_dialog in all_dialogs:
78  # split the sentences
79  each_dialog = re.split(
80  r'(?<!\w\.\w.)(?<![A-Z][a-z]\.)(?<=\.|\;|\?)\s',
81  each_dialog.strip())
82  for each in each_dialog:
83  if (REGEX_SPL_CHARS.search(each) is None):
84  # Do not consider sentences with special
85  # characters other than any punctuation
86  # ex : <<< LOADING <<<
87  # should not be considered
88  f.write(each.strip() + '\n')
89  except Exception:
90  # LOG.debug("Dialog Skipped")
91  pass
92 
93 
94 def download_audio(cache_audio_dir, cache_text_file):
95  """
96  This method takes the sentences from the text file generated
97  using generate_cache_text() and performs TTS inference on
98  mimic2-api. The wav files and phonemes are stored in
99  'cache_audio_dir'
100  Args:
101  cache_audio_dir (path): path to store .wav files
102  cache_text_file (file): file containing the sentences
103  """
104  if os.path.isfile(cache_text_file) and \
105  os.path.exists(cache_audio_dir):
106  if not os.listdir(cache_audio_dir):
107  session = FuturesSession()
108  with open(cache_text_file, 'r') as fp:
109  all_dialogs = fp.readlines()
110  for each_dialog in all_dialogs:
111  each_dialog = each_dialog.strip()
112  key = str(hashlib.md5(
113  each_dialog.encode('utf-8', 'ignore')).hexdigest())
114  wav_file = os.path.join(cache_audio_dir, key + '.wav')
115  each_dialog = parse.quote(each_dialog)
116 
117  mimic2_url = MIMIC2_URL + each_dialog + '&visimes=True'
118  try:
119  req = session.get(mimic2_url)
120  results = req.result().json()
121  audio = base64.b64decode(results['audio_base64'])
122  vis = results['visimes']
123  if audio:
124  with open(wav_file, 'wb') as audiofile:
125  audiofile.write(audio)
126  if vis:
127  pho_file = os.path.join(cache_audio_dir,
128  key + ".pho")
129  with open(pho_file, "w") as cachefile:
130  cachefile.write(json.dumps(vis)) # Mimic2
131  # cachefile.write(str(vis)) # Mimic
132  except Exception as e:
133  # Skip this dialog and continue
134  LOG.error("Unable to get pre-loaded cache "
135  "due to ({})".format(repr(e)))
136 
137  LOG.debug("Completed getting cache for {}".format(TTS))
138 
139  else:
140  LOG.debug("Pre-loaded cache for {} already exists".
141  format(TTS))
142  else:
143  missing_path = cache_text_file if not \
144  os.path.isfile(cache_text_file)\
145  else cache_audio_dir
146  LOG.error("Path ({}) does not exist for getting the cache"
147  .format(missing_path))
148 
149 
150 def copy_cache(cache_audio_dir):
151  """
152  This method copies the cache from 'cache_audio_dir'
153  to TTS specific cache directory given by
154  get_cache_directory()
155  Args:
156  cache_audio_dir (path): path containing .wav files
157  """
158  if os.path.exists(cache_audio_dir):
159  # get tmp directory where tts cache is stored
160  dest = util.get_cache_directory('tts/' + 'Mimic2')
161  files = os.listdir(cache_audio_dir)
162  for f in files:
163  shutil.copy2(os.path.join(cache_audio_dir, f), dest)
164  LOG.debug("Copied all pre-loaded cache for {} to {}"
165  .format(TTS, dest))
166  else:
167  LOG.debug("No Source directory for {} pre-loaded cache"
168  .format(TTS))
169 
170 
171 # Start here
172 def main(cache_audio_dir):
173  # Path where cache is stored and not cleared on reboot/TTS change
174  if cache_audio_dir:
175  cache_text_file = os.path.join(cache_audio_dir,
176  '..', 'cache_text.txt')
177  generate_cache_text(cache_audio_dir, cache_text_file)
178  download_audio(cache_audio_dir, cache_text_file)
179  copy_cache(cache_audio_dir)
def copy_cache(cache_audio_dir)
def write_cache_text(cache_path, f)
def main(cache_audio_dir)
def generate_cache_text(cache_audio_dir, cache_text_file)
def download_audio(cache_audio_dir, cache_text_file)


mycroft_ros
Author(s):
autogenerated on Mon Apr 26 2021 02:35:40