import logging
import random

import numpy as np
import pypinyin
import tensorflow as tf

from augmentations.augments import Augmentation
from utils.speech_featurizers import SpeechFeaturizer
from utils.text_featurizers import TextFeaturizer

logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
import time

class AM_DataLoader():

    def __init__(self, config_dict, training=True):

        self.speech_config = config_dict['speech_config']
        self.phone_config = config_dict['inp_config']
        self.text_config = config_dict['tar_config']
        self.running_config=config_dict['running_config']
        self.augment_config = config_dict['augments_config']
        self.streaming = self.speech_config['streaming']
        self.chunk = self.speech_config['sample_rate'] * self.speech_config['streaming_bucket']
        self.batch = config_dict['running_config']['batch_size']
        self.speech_featurizer = SpeechFeaturizer(self.speech_config)
        self.phone_featurizer = TextFeaturizer(self.phone_config)
        self.text_featurizer = TextFeaturizer(self.text_config)
        self.make_file_list( training)
        self.augment = Augmentation(self.augment_config)
        self.init_text_to_vocab()
        self.epochs = 1
        self.steps = 0


    def return_data_types(self):

        return (tf.float32, tf.int32, tf.int32, tf.int32,tf.int32)

    def return_data_shape(self):

        return (
            tf.TensorShape([self.batch, None, 1]),

            tf.TensorShape([self.batch, ]),
            tf.TensorShape([self.batch, None]),
            tf.TensorShape([self.batch, ]),
            tf.TensorShape([self.batch, None]),
        )

    def get_per_epoch_steps(self):
        return len(self.train_list) // self.batch

    def eval_per_epoch_steps(self):
        return len(self.test_list) // self.batch

    def init_text_to_vocab(self):
        pypinyin.load_phrases_dict({'调大': [['tiáo'], ['dà']],
                                    '调小': [['tiáo'], ['xiǎo']],
                                    '调亮': [['tiáo'], ['liàng']],
                                    '调暗': [['tiáo'], ['àn']],
                                    '肖': [['xiāo']],
                                    '英雄传': [['yīng'], ['xióng'], ['zhuàn']],
                                    '新传': [['xīn'], ['zhuàn']],
                                    '外传': [['wài'], ['zhuàn']],
                                    '正传': [['zhèng'], ['zhuàn']], '水浒传': [['shuǐ'], ['hǔ'], ['zhuàn']]
                                    })

        def text_to_vocab_func(txt):
            pins = pypinyin.pinyin(txt)
            pins = [i[0] for i in pins]
            phones = []
            for pin in pins:
                if pin in self.phone_featurizer.vocab_array:
                    phones += [pin]
                else:
                    phones += list(pin)
            # print(phones)
            return phones

        self.text_to_vocab = text_to_vocab_func

    def make_file_list(self, training=True):
        train_list=self.speech_config['train_list']
        test_list=self.speech_config['eval_list']
        if training:
            with open(train_list, encoding='utf-8') as f:
                train_list = f.readlines()
            train_list = [i.strip() for i in train_list if i != '']

            self.train_list = train_list

            np.random.shuffle(self.train_list)
            with open(test_list, encoding='utf-8') as f:
                data = f.readlines()
            data = [i.strip() for i in data if i != '']
            self.test_list = data
            self.train_offset = 0
            self.test_offset = 0
            logging.info('load train list {} test list {}'.format(len(self.train_list), len(self.test_list)))
        else:
            with open(test_list, encoding='utf-8') as f:
                data = f.readlines()
            data = [i.strip() for i in data if i != '']
            self.test_list = data
            self.test_offset = 0

    def only_chinese(self, word):
        txt = ''
        for ch in word:
            if '\u4e00' <= ch <= '\u9fff':
                txt += ch
            else:
                continue

        return txt

    def eval_data_generator(self):

        sample = []
        speech_features = []
        input_length = []
        phones = []
        phones_length = []
        txts = []
        max_input = 0
        batch = self.batch

        for i in range(batch * 10):

            line = self.test_list[self.test_offset]
            self.test_offset += 1
            if self.test_offset > len(self.test_list) - 1:
                self.test_offset = 0
            wp, txt = line.strip().split('\t')
            try:
                data = self.speech_featurizer.load_wav(wp)
            except:
                logging.info('{} load data failed,skip'.format(wp))
                continue
            if len(data) < 400:
                continue
            elif len(data) > self.speech_featurizer.sample_rate * self.speech_config['wav_max_duration']:
                logging.info(
                    '{} duration out of wav_max_duration({}),skip'.format(wp, self.speech_config['wav_max_duration']))
                continue
            if self.speech_config['only_chinese']:
                txt = self.only_chinese(txt)

            if not self.streaming:
                speech_feature = data / np.abs(data).max()
                speech_feature = np.expand_dims(speech_feature, -1)
                in_len = len(speech_feature) // (
                        self.speech_config['reduction_factor'] * (self.speech_featurizer.sample_rate / 1000) *
                        self.speech_config['stride_ms'])
            else:
                speech_feature = data
                speech_feature = np.expand_dims(speech_feature, -1)
                reduce = self.speech_config['reduction_factor'] * (self.speech_featurizer.sample_rate / 1000) * \
                         self.speech_config['stride_ms']
                in_len = len(speech_feature) // self.chunk
                if len(speech_feature) % self.chunk != 0:
                    in_len += 1
                chunk_times = self.chunk // reduce
                if self.chunk % reduce != 0:
                    chunk_times += 1
                in_len *= chunk_times

            py = self.text_to_vocab(txt)
            if self.check_valid(py, self.phone_featurizer.vocab_array) is not True:
                logging.info(' {} txt phone {} not all in tokens,continue'.format(txt, self.check_valid(py,
                                                                                                        self.phone_featurizer.vocab_array)))
                continue
            if self.check_valid(txt, self.text_featurizer.vocab_array) is not True:
                logging.info(' {} txt phone {} not all in tokens,continue'.format(txt, self.check_valid(py,
                                                                                                        self.text_featurizer.vocab_array)))
                continue

            txt = list(txt)
            phone_feature = self.phone_featurizer.extract(py)
            text_feature = self.text_featurizer.extract(txt)+[self.text_featurizer.endid()]

            if in_len < len(phone_feature):
                logging.info('{} feature length < phone length,continue'.format(wp))
                continue
            max_input = max(max_input, len(speech_feature))

            speech_features.append(speech_feature)
            input_length.append(in_len)
            phones.append(np.array(phone_feature))
            txts.append(np.array(text_feature))
            phones_length.append(len(phone_feature))
            sample.append(line)
            if len(sample) == batch:
                break


        if self.streaming:
            max_input = max_input // self.chunk * self.chunk + self.chunk
        speech_features = self.speech_featurizer.pad_signal(speech_features, max_input)



        if self.streaming:
            reduce = self.speech_config['reduction_factor'] * (self.speech_featurizer.sample_rate / 1000) * \
                     self.speech_config['stride_ms']
            max_input = max_input // self.chunk * self.chunk + self.chunk
            max_in_len = max_input // self.chunk
            chunk_times = self.chunk // reduce
            if self.chunk % reduce != 0:
                chunk_times += 1
            max_in_len *= chunk_times
            input_length = np.clip(input_length, 0, max_in_len)
        speech_features = self.speech_featurizer.pad_signal(speech_features, max_input)

        phones = tf.keras.preprocessing.sequence.pad_sequences(phones, maxlen=max([len(i) for i in phones]),
                                                               padding='post', value=self.phone_featurizer.pad)
        txts = tf.keras.preprocessing.sequence.pad_sequences(txts, maxlen=max([len(i) for i in txts]), padding='post',
                                                             value=self.text_featurizer.pad)
        x = np.array(speech_features, 'float32')
        phones = np.array(phones, 'int32')
        txts = np.array(txts, 'int32')

        input_length = np.array(input_length, 'int32')
        phones_length = np.array(phones_length, 'int32')

        return x, input_length, phones, phones_length, txts

    def check_valid(self, txt, vocab_list):
        if len(txt) == 0:
            return False
        for n in txt:
            if n in vocab_list:
                pass
            else:
                return n
        return True


    def generate(self, train=True):

        sample = []
        speech_features = []
        input_length = []
        phones = []
        phones_length = []
        txts = []

        max_input = 0

        if train:
            batch = self.batch * 3 // 4 if self.augment.available() else self.batch
        else:
            batch = self.batch

        for i in range(batch * 10):
            if train:
                line = self.train_list[self.train_offset]
                self.train_offset += 1
                if self.train_offset > len(self.train_list) - 1:
                    self.train_offset = 0
                    np.random.shuffle(self.train_list)
                    self.epochs += 1
            else:
                line = self.test_list[self.test_offset]
                self.test_offset += 1
                if self.test_offset > len(self.test_list) - 1:
                    self.test_offset = 0
            wp, txt = line.strip().split('\t')
            try:
                data = self.speech_featurizer.load_wav(wp)
            except:
                logging.info('{} load data failed,skip'.format(wp))
                continue
            if len(data) < 400:
                continue
            elif len(data) > self.speech_featurizer.sample_rate * self.speech_config['wav_max_duration']:
                logging.info(
                    '{} duration out of wav_max_duration({}),skip'.format(wp, self.speech_config['wav_max_duration']))
                continue
            if self.speech_config['only_chinese']:
                txt = self.only_chinese(txt)

            if not self.streaming:
                speech_feature = data / np.abs(data).max()
                speech_feature = np.expand_dims(speech_feature, -1)
                in_len = len(speech_feature) // (
                        self.speech_config['reduction_factor'] * (self.speech_featurizer.sample_rate / 1000) *
                        self.speech_config['stride_ms'])
            else:
                speech_feature = data
                speech_feature = np.expand_dims(speech_feature, -1)
                reduce = self.speech_config['reduction_factor'] * (self.speech_featurizer.sample_rate / 1000) * \
                         self.speech_config['stride_ms']
                in_len = len(speech_feature) // self.chunk
                if len(speech_feature) % self.chunk != 0:
                    in_len += 1
                chunk_times = self.chunk // reduce
                if self.chunk % reduce != 0:
                    chunk_times += 1
                in_len *= chunk_times

            py = self.text_to_vocab(txt)
            if self.check_valid(py, self.phone_featurizer.vocab_array) is not True:
                logging.info(' {} txt phone {} not all in tokens,continue'.format(txt, self.check_valid(py,
                                                                                                        self.phone_featurizer.vocab_array)))
                continue
            if self.check_valid(txt, self.text_featurizer.vocab_array) is not True:
                logging.info(' {} txt  {} not all in tokens,continue'.format(txt, self.check_valid(txt,
                                                                                                        self.text_featurizer.vocab_array)))
                continue

            txt = list(txt)
            phone_feature = self.phone_featurizer.extract(py)
            text_feature = self.text_featurizer.extract(txt)+[self.text_featurizer.endid()]

            if in_len < len(phone_feature):
                logging.info('{} feature length < phone length,continue'.format(wp))
                continue
            max_input = max(max_input, len(speech_feature))

            speech_features.append(speech_feature)
            input_length.append(in_len)
            phones.append(np.array(phone_feature))
            txts.append(np.array(text_feature))
            phones_length.append(len(phone_feature))
            sample.append(line)
            if len(sample) == batch:
                break
        if train and self.augment.available():

            sample = random.sample(sample, self.batch // 4)
            for i in sample:
                wp, txt = i.strip().split('\t')
                try:
                    data = self.speech_featurizer.load_wav(wp)
                except:
                    continue
                if len(data) < 400:
                    logging.info('{} wav too short < 25ms,skip'.format(wp))
                    continue
                elif len(data) > self.speech_featurizer.sample_rate * self.speech_config['wav_max_duration']:
                    continue
                data = self.augment.process(data)
                if self.speech_config['only_chinese']:
                    txt = self.only_chinese(txt)

                if not self.streaming:
                    speech_feature = data / np.abs(data).max()
                    speech_feature = np.expand_dims(speech_feature, -1)
                    in_len = len(speech_feature) // (
                            self.speech_config['reduction_factor'] * (self.speech_featurizer.sample_rate / 1000) *
                            self.speech_config['stride_ms'])
                else:
                    speech_feature = data
                    speech_feature = np.expand_dims(speech_feature, -1)
                    reduce = self.speech_config['reduction_factor'] * (self.speech_featurizer.sample_rate / 1000) * \
                             self.speech_config['stride_ms']
                    in_len = len(speech_feature) // self.chunk
                    if len(speech_feature) % self.chunk != 0:
                        in_len += 1
                    chunk_times = self.chunk // reduce
                    if self.chunk % reduce != 0:
                        chunk_times += 1
                    in_len *= chunk_times

                py = self.text_to_vocab(txt)
                if self.check_valid(py, self.phone_featurizer.vocab_array) is not True:
                    logging.info(' {} txt phone {} not all in tokens,continue'.format(txt, self.check_valid(py,
                                                                                                             self.phone_featurizer.vocab_array)))
                    continue
                if self.check_valid(txt, self.text_featurizer.vocab_array) is not True:
                    logging.info(' {} txt  {} not all in tokens,continue'.format(txt, self.check_valid(txt,
                                                                                                             self.text_featurizer.vocab_array)))
                    continue

                txt = list(txt)
                phone_feature = self.phone_featurizer.extract(py)
                text_feature = self.text_featurizer.extract(txt)+[self.text_featurizer.endid()]

                if in_len < len(phone_feature):
                    logging.info('{} feature length < phone length,continue'.format(wp))
                    continue

                max_input = max(max_input, len(speech_feature))

                speech_features.append(speech_feature)
                input_length.append(in_len)
                phones.append(np.array(phone_feature))
                txts.append(np.array(text_feature))
                phones_length.append(len(phone_feature))


        if self.streaming:
            reduce = self.speech_config['reduction_factor'] * (self.speech_featurizer.sample_rate / 1000) * \
                     self.speech_config['stride_ms']
            max_input = max_input // self.chunk * self.chunk + self.chunk
            max_in_len = max_input // self.chunk
            chunk_times = self.chunk // reduce
            if self.chunk % reduce != 0:
                chunk_times += 1
            max_in_len *= chunk_times
            input_length = np.clip(input_length, 0, max_in_len)
        speech_features = self.speech_featurizer.pad_signal(speech_features, max_input)


        phones=tf.keras.preprocessing.sequence.pad_sequences(phones,maxlen=max([len(i) for i in phones]),padding='post',value=self.phone_featurizer.pad)
        txts=tf.keras.preprocessing.sequence.pad_sequences(txts,maxlen=max([len(i) for i in txts]),padding='post',value=self.text_featurizer.pad)
        x = np.array(speech_features, 'float32')
        phones = np.array(phones, 'int32')
        txts = np.array(txts, 'int32')

        input_length = np.array(input_length, 'int32')
        phones_length = np.array(phones_length, 'int32')

        return x, input_length, phones, phones_length,txts

    def generator(self, train=True):
        while 1:
            s=time.time()
            x, input_length, phones, phones_length,txts = self.generate(train)
            e=time.time()
            logging.info('load data cost time: {}'.format(e-s))
            if x.shape[0] == 0:
                logging.info('load data length zero,continue')
                continue


            yield x, input_length, phones, phones_length,txts

[((12, 0, 12, 102), 'logging.basicConfig', 'logging.basicConfig', (), '', False, 'import logging\n'), ((27, 33, 27, 69), 'utils.speech_featurizers.SpeechFeaturizer', 'SpeechFeaturizer', ({(27, 50, 27, 68): 'self.speech_config'}, {}), '(self.speech_config)', False, 'from utils.speech_featurizers import SpeechFeaturizer\n'), ((28, 32, 28, 65), 'utils.text_featurizers.TextFeaturizer', 'TextFeaturizer', ({(28, 47, 28, 64): 'self.phone_config'}, {}), '(self.phone_config)', False, 'from utils.text_featurizers import TextFeaturizer\n'), ((29, 31, 29, 63), 'utils.text_featurizers.TextFeaturizer', 'TextFeaturizer', ({(29, 46, 29, 62): 'self.text_config'}, {}), '(self.text_config)', False, 'from utils.text_featurizers import TextFeaturizer\n'), ((31, 23, 31, 56), 'augmentations.augments.Augmentation', 'Augmentation', ({(31, 36, 31, 55): 'self.augment_config'}, {}), '(self.augment_config)', False, 'from augmentations.augments import Augmentation\n'), ((59, 8, 68, 38), 'pypinyin.load_phrases_dict', 'pypinyin.load_phrases_dict', ({(59, 35, 68, 37): "{'调大': [['tiáo'], ['dà']], '调小': [['tiáo'], ['xiǎo']], '调亮': [['tiáo'], [\n    'liàng']], '调暗': [['tiáo'], ['àn']], '肖': [['xiāo']], '英雄传': [['yīng'],\n    ['xióng'], ['zhuàn']], '新传': [['xīn'], ['zhuàn']], '外传': [['wài'], [\n    'zhuàn']], '正传': [['zhèng'], ['zhuàn']], '水浒传': [['shuǐ'], ['hǔ'], [\n    'zhuàn']]}"}, {}), "({'调大': [['tiáo'], ['dà']], '调小': [['tiáo'], [\n    'xiǎo']], '调亮': [['tiáo'], ['liàng']], '调暗': [['tiáo'], ['àn']], '肖': [\n    ['xiāo']], '英雄传': [['yīng'], ['xióng'], ['zhuàn']], '新传': [['xīn'], [\n    'zhuàn']], '外传': [['wài'], ['zhuàn']], '正传': [['zhèng'], ['zhuàn']],\n    '水浒传': [['shuǐ'], ['hǔ'], ['zhuàn']]})", False, 'import pypinyin\n'), ((221, 12, 221, 48), 'numpy.array', 'np.array', ({(221, 21, 221, 36): 'speech_features', (221, 38, 221, 47): '"""float32"""'}, {}), "(speech_features, 'float32')", True, 'import numpy as np\n'), ((222, 17, 222, 42), 'numpy.array', 'np.array', ({(222, 26, 222, 32): 'phones', (222, 34, 222, 41): '"""int32"""'}, {}), "(phones, 'int32')", True, 'import numpy as np\n'), ((223, 15, 223, 38), 'numpy.array', 'np.array', ({(223, 24, 223, 28): 'txts', (223, 30, 223, 37): '"""int32"""'}, {}), "(txts, 'int32')", True, 'import numpy as np\n'), ((225, 23, 225, 54), 'numpy.array', 'np.array', ({(225, 32, 225, 44): 'input_length', (225, 46, 225, 53): '"""int32"""'}, {}), "(input_length, 'int32')", True, 'import numpy as np\n'), ((226, 24, 226, 56), 'numpy.array', 'np.array', ({(226, 33, 226, 46): 'phones_length', (226, 48, 226, 55): '"""int32"""'}, {}), "(phones_length, 'int32')", True, 'import numpy as np\n'), ((410, 12, 410, 48), 'numpy.array', 'np.array', ({(410, 21, 410, 36): 'speech_features', (410, 38, 410, 47): '"""float32"""'}, {}), "(speech_features, 'float32')", True, 'import numpy as np\n'), ((411, 17, 411, 42), 'numpy.array', 'np.array', ({(411, 26, 411, 32): 'phones', (411, 34, 411, 41): '"""int32"""'}, {}), "(phones, 'int32')", True, 'import numpy as np\n'), ((412, 15, 412, 38), 'numpy.array', 'np.array', ({(412, 24, 412, 28): 'txts', (412, 30, 412, 37): '"""int32"""'}, {}), "(txts, 'int32')", True, 'import numpy as np\n'), ((414, 23, 414, 54), 'numpy.array', 'np.array', ({(414, 32, 414, 44): 'input_length', (414, 46, 414, 53): '"""int32"""'}, {}), "(input_length, 'int32')", True, 'import numpy as np\n'), ((415, 24, 415, 56), 'numpy.array', 'np.array', ({(415, 33, 415, 46): 'phones_length', (415, 48, 415, 55): '"""int32"""'}, {}), "(phones_length, 'int32')", True, 'import numpy as np\n'), ((44, 12, 44, 49), 'tensorflow.TensorShape', 'tf.TensorShape', ({(44, 27, 44, 48): '[self.batch, None, 1]'}, {}), '([self.batch, None, 1])', True, 'import tensorflow as tf\n'), ((46, 12, 46, 42), 'tensorflow.TensorShape', 'tf.TensorShape', ({(46, 27, 46, 41): '[self.batch]'}, {}), '([self.batch])', True, 'import tensorflow as tf\n'), ((47, 12, 47, 46), 'tensorflow.TensorShape', 'tf.TensorShape', ({(47, 27, 47, 45): '[self.batch, None]'}, {}), '([self.batch, None])', True, 'import tensorflow as tf\n'), ((48, 12, 48, 42), 'tensorflow.TensorShape', 'tf.TensorShape', ({(48, 27, 48, 41): '[self.batch]'}, {}), '([self.batch])', True, 'import tensorflow as tf\n'), ((49, 12, 49, 46), 'tensorflow.TensorShape', 'tf.TensorShape', ({(49, 27, 49, 45): '[self.batch, None]'}, {}), '([self.batch, None])', True, 'import tensorflow as tf\n'), ((71, 19, 71, 39), 'pypinyin.pinyin', 'pypinyin.pinyin', ({(71, 35, 71, 38): 'txt'}, {}), '(txt)', False, 'import pypinyin\n'), ((94, 12, 94, 46), 'numpy.random.shuffle', 'np.random.shuffle', ({(94, 30, 94, 45): 'self.train_list'}, {}), '(self.train_list)', True, 'import numpy as np\n'), ((214, 27, 214, 63), 'numpy.clip', 'np.clip', ({(214, 35, 214, 47): 'input_length', (214, 49, 214, 50): '0', (214, 52, 214, 62): 'max_in_len'}, {}), '(input_length, 0, max_in_len)', True, 'import numpy as np\n'), ((333, 21, 333, 59), 'random.sample', 'random.sample', ({(333, 35, 333, 41): 'sample', (333, 43, 333, 58): 'self.batch // 4'}, {}), '(sample, self.batch // 4)', False, 'import random\n'), ((404, 27, 404, 63), 'numpy.clip', 'np.clip', ({(404, 35, 404, 47): 'input_length', (404, 49, 404, 50): '0', (404, 52, 404, 62): 'max_in_len'}, {}), '(input_length, 0, max_in_len)', True, 'import numpy as np\n'), ((421, 14, 421, 25), 'time.time', 'time.time', ({}, {}), '()', False, 'import time\n'), ((423, 14, 423, 25), 'time.time', 'time.time', ({}, {}), '()', False, 'import time\n'), ((153, 33, 153, 67), 'numpy.expand_dims', 'np.expand_dims', ({(153, 48, 153, 62): 'speech_feature', (153, 64, 153, 66): '-1'}, {}), '(speech_feature, -1)', True, 'import numpy as np\n'), ((159, 33, 159, 67), 'numpy.expand_dims', 'np.expand_dims', ({(159, 48, 159, 62): 'speech_feature', (159, 64, 159, 66): '-1'}, {}), '(speech_feature, -1)', True, 'import numpy as np\n'), ((191, 26, 191, 49), 'numpy.array', 'np.array', ({(191, 35, 191, 48): 'phone_feature'}, {}), '(phone_feature)', True, 'import numpy as np\n'), ((192, 24, 192, 46), 'numpy.array', 'np.array', ({(192, 33, 192, 45): 'text_feature'}, {}), '(text_feature)', True, 'import numpy as np\n'), ((287, 33, 287, 67), 'numpy.expand_dims', 'np.expand_dims', ({(287, 48, 287, 62): 'speech_feature', (287, 64, 287, 66): '-1'}, {}), '(speech_feature, -1)', True, 'import numpy as np\n'), ((293, 33, 293, 67), 'numpy.expand_dims', 'np.expand_dims', ({(293, 48, 293, 62): 'speech_feature', (293, 64, 293, 66): '-1'}, {}), '(speech_feature, -1)', True, 'import numpy as np\n'), ((325, 26, 325, 49), 'numpy.array', 'np.array', ({(325, 35, 325, 48): 'phone_feature'}, {}), '(phone_feature)', True, 'import numpy as np\n'), ((326, 24, 326, 46), 'numpy.array', 'np.array', ({(326, 33, 326, 45): 'text_feature'}, {}), '(text_feature)', True, 'import numpy as np\n'), ((426, 16, 426, 62), 'logging.info', 'logging.info', ({(426, 29, 426, 61): '"""load data length zero,continue"""'}, {}), "('load data length zero,continue')", False, 'import logging\n'), ((263, 20, 263, 54), 'numpy.random.shuffle', 'np.random.shuffle', ({(263, 38, 263, 53): 'self.train_list'}, {}), '(self.train_list)', True, 'import numpy as np\n'), ((351, 37, 351, 71), 'numpy.expand_dims', 'np.expand_dims', ({(351, 52, 351, 66): 'speech_feature', (351, 68, 351, 70): '-1'}, {}), '(speech_feature, -1)', True, 'import numpy as np\n'), ((357, 37, 357, 71), 'numpy.expand_dims', 'np.expand_dims', ({(357, 52, 357, 66): 'speech_feature', (357, 68, 357, 70): '-1'}, {}), '(speech_feature, -1)', True, 'import numpy as np\n'), ((390, 30, 390, 53), 'numpy.array', 'np.array', ({(390, 39, 390, 52): 'phone_feature'}, {}), '(phone_feature)', True, 'import numpy as np\n'), ((391, 28, 391, 50), 'numpy.array', 'np.array', ({(391, 37, 391, 49): 'text_feature'}, {}), '(text_feature)', True, 'import numpy as np\n'), ((152, 40, 152, 52), 'numpy.abs', 'np.abs', ({(152, 47, 152, 51): 'data'}, {}), '(data)', True, 'import numpy as np\n'), ((286, 40, 286, 52), 'numpy.abs', 'np.abs', ({(286, 47, 286, 51): 'data'}, {}), '(data)', True, 'import numpy as np\n'), ((350, 44, 350, 56), 'numpy.abs', 'np.abs', ({(350, 51, 350, 55): 'data'}, {}), '(data)', True, 'import numpy as np\n')]