def test_big_db(self): from tts.db import DB from tts.synthesizer import SpeechSynthesizer from tts.srv import SynthesizerRequest import uuid db = DB() speech_synthesizer = SpeechSynthesizer(engine='DUMMY', max_cache_bytes=401) speech_synthesizer.engine.set_file_sizes(100) for i in range(20): request = SynthesizerRequest(text=uuid.uuid4().hex, metadata={}) response = speech_synthesizer._node_request_handler(request) self.assertEqual(db.get_num_files(), 4) speech_synthesizer = SpeechSynthesizer(engine='DUMMY', max_cache_bytes=40001) speech_synthesizer.engine.set_file_sizes(1000) for i in range(80): request = SynthesizerRequest(text=uuid.uuid4().hex, metadata={}) response = speech_synthesizer._node_request_handler(request) self.assertEqual(db.get_num_files(), 40)
def test_lost_file(self): from tts.db import DB from tts.synthesizer import SpeechSynthesizer from tts.srv import SynthesizerRequest import uuid import os import json db = DB() init_num_files = db.get_num_files() req_text = uuid.uuid4().hex speech_synthesizer = SpeechSynthesizer(engine='DUMMY') request = SynthesizerRequest(text=req_text, metadata={}) response = speech_synthesizer._node_request_handler(request) res_dict = json.loads(response.result) audio_file1 = res_dict['Audio File'] self.assertEqual(db.get_num_files(), init_num_files + 1) os.remove(audio_file1) request = SynthesizerRequest(text=req_text, metadata={}) response = speech_synthesizer._node_request_handler(request) res_dict = json.loads(response.result) audio_file2 = res_dict['Audio File'] self.assertEqual(db.get_num_files(), init_num_files + 1) self.assertEqual(audio_file1, audio_file2) self.assertTrue(os.path.exists(audio_file2))
def test_multiple_novel(self): from tts.db import DB from tts.synthesizer import SpeechSynthesizer from tts.srv import SynthesizerRequest import uuid db = DB() init_num_files = db.get_num_files() for i in range(4): speech_synthesizer = SpeechSynthesizer(engine='DUMMY') request = SynthesizerRequest(text=uuid.uuid4().hex, metadata={}) response = speech_synthesizer._node_request_handler(request) self.assertEqual(db.get_num_files(), init_num_files + i + 1)
def test_no_connection_novel(self): from tts.db import DB from tts.synthesizer import SpeechSynthesizer from tts.srv import SynthesizerRequest import uuid db = DB() init_num_files = db.get_num_files() speech_synthesizer = SpeechSynthesizer(engine='DUMMY') speech_synthesizer.engine.set_connection(False) request = SynthesizerRequest(text=uuid.uuid4().hex, metadata={}) response = speech_synthesizer._node_request_handler(request) self.assertEqual(db.get_num_files(), init_num_files)
def test_file_cleanup_priority(self): from tts.db import DB from tts.synthesizer import SpeechSynthesizer from tts.srv import SynthesizerRequest import uuid import json import os db = DB() speech_synthesizer = SpeechSynthesizer(engine='DUMMY', max_cache_bytes=401) speech_synthesizer.engine.set_file_sizes(100) special_text = uuid.uuid4().hex request = SynthesizerRequest(text=special_text, metadata={}) response = speech_synthesizer._node_request_handler(request) res_dict = json.loads(response.result) audio_file1 = res_dict['Audio File'] self.assertTrue(os.path.exists(audio_file1)) special_text2 = uuid.uuid4().hex request = SynthesizerRequest(text=special_text2, metadata={}) response = speech_synthesizer._node_request_handler(request) res_dict = json.loads(response.result) audio_file2 = res_dict['Audio File'] self.assertTrue(os.path.exists(audio_file2)) for z in range(2): for i in range(2): request = SynthesizerRequest(text=uuid.uuid4().hex, metadata={}) response = speech_synthesizer._node_request_handler(request) request = SynthesizerRequest(text=special_text, metadata={}) response = speech_synthesizer._node_request_handler(request) res_dict = json.loads(response.result) audio_file1 = res_dict['Audio File'] self.assertFalse(os.path.exists(audio_file2)) self.assertTrue(os.path.exists(audio_file1))
def _call_engine(self, **kw): """Call engine to do the job. If no output path is found from input, the audio file will be put into /tmp and the file name will have a prefix of the md5 hash of the text. If a filename is not given, the utterance is added to the cache. If a filename is specified, then we will assume that the file is being managed by the user and it will not be added to the cache. :param kw: what AmazonPolly needs to synthesize :return: response from AmazonPolly """ if 'output_path' not in kw: tmp_filename = hashlib.md5(json.dumps(kw, sort_keys=True)).hexdigest() tmp_filepath = os.path.join(os.sep, 'tmp', 'voice_{}'.format(tmp_filename)) kw['output_path'] = os.path.abspath(tmp_filepath) rospy.loginfo('managing file with name: {}'.format(tmp_filename)) # because the hash will include information about any file ending choices, we only # need to look at the hash itself. db = DB() db_search_result = db.ex( 'SELECT file, audio_type FROM cache WHERE hash=?', tmp_filename).fetchone() current_time = time.time() file_found = False if db_search_result: # then there is data # check if the file exists, if not, remove from db # TODO: add a test that deletes a file without telling the db and tries to synthesize it if os.path.exists(db_search_result['file']): file_found = True db.ex('update cache set last_accessed=? where hash=?', current_time, tmp_filename) synth_result = PollyResponse( json.dumps({ 'Audio File': db_search_result['file'], 'Audio Type': db_search_result['audio_type'], 'Amazon Polly Response Metadata': '' })) rospy.loginfo('audio file was already cached at: %s', db_search_result['file']) else: rospy.logwarn( 'A file in the database did not exist on the disk, removing from db' ) db.remove_file(db_search_result['file']) if not file_found: # havent cached this yet rospy.loginfo('Caching file') synth_result = self.engine(**kw) res_dict = json.loads(synth_result.result) if 'Exception' not in res_dict: file_name = res_dict['Audio File'] if file_name: file_size = os.path.getsize(file_name) db.ex( '''insert into cache( hash, file, audio_type, last_accessed,size) values (?,?,?,?,?)''', tmp_filename, file_name, res_dict['Audio Type'], current_time, file_size) rospy.loginfo( 'generated new file, saved to %s and cached', file_name) # make sure the cache hasn't grown too big while db.get_size( ) > self.max_cache_bytes and db.get_num_files() > 1: remove_res = db.ex( 'select file, min(last_accessed), size from cache' ).fetchone() db.remove_file(remove_res['file']) rospy.loginfo( 'removing %s to maintain cache size, new size: %i', remove_res['file'], db.get_size()) else: synth_result = self.engine(**kw) return synth_result