ryu преди 2 години
ревизия
afdfb660ea
променени са 10 файла, в които са добавени 1418 реда и са изтрити 0 реда
  1. 34 0
      AWS_transcribe/lambda_1.py
  2. 32 0
      AWS_transcribe/lambda_2.py
  3. 42 0
      README.md
  4. 326 0
      aug_multi.py
  5. 173 0
      check_ogg.py
  6. 170 0
      failure_check.py
  7. 194 0
      postprocess.py
  8. 165 0
      srt_split.py
  9. 232 0
      transcribe_process.py
  10. 50 0
      wrd_error.py

+ 34 - 0
AWS_transcribe/lambda_1.py

@@ -0,0 +1,34 @@
+import json
+#Create an s3 bucket with the command below after configuing the CLI
+import boto3
+#Create low level clients for s3 and Transcribe
+s3  = boto3.client('s3')
+transcribe = boto3.client('transcribe')
+
+def lambda_handler(event, context):
+    # TODO implement
+    for record in event['Records']:
+        file_bucket = record['s3']['bucket']['name']
+        file_name = record['s3']['object']['key']
+        
+        print(file_bucket, file_name)
+        if file_name.find(".wav") == -1:
+            continue
+        
+        object_url = f"https://s3.amazonaws.com/{file_bucket}/{file_name}"
+        
+        print(object_url)
+        
+        response = transcribe.start_transcription_job(
+                TranscriptionJobName=file_name.replace('/', '-'),
+                LanguageCode='ko-KR',
+                MediaFormat='wav',
+                Media={
+                    'MediaFileUri': object_url
+                })
+        print(response)
+        
+    return {
+        'statusCode': 200,
+        'body': json.dumps('Hello from Lambda!')
+    }

+ 32 - 0
AWS_transcribe/lambda_2.py

@@ -0,0 +1,32 @@
+import json
+import boto3
+import os
+import urllib
+import requests
+
+BUCKET_NAME = os.environ['BUCKET_NAME']
+
+s3 = boto3.resource('s3')
+transcribe = boto3.client('transcribe')
+
+def lambda_handler(event, context):
+    
+    job_name = event['detail']['TranscriptionJobName']
+    job = transcribe.get_transcription_job(TranscriptionJobName=job_name)
+    uri = job['TranscriptionJob']['Transcript']['TranscriptFileUri']
+    print(uri)
+    
+    job_name = job_name.split('input-')[1]
+    
+    content = urllib.request.urlopen(uri).read().decode('utf-8')
+    #write content to cloudwatch logs
+    print(json.dumps(content))
+    
+    data =  json.loads(content)
+    transcribed_text = data['results']['transcripts'][0]['transcript']
+    
+    print(job_name)
+    file_name = "output/" + job_name.replace('-', '/', 1).rsplit('.wav',1)[0] + ".txt"
+    
+    object = s3.Object(BUCKET_NAME, file_name)
+    object.put(Body=transcribed_text)

+ 42 - 0
README.md

@@ -0,0 +1,42 @@
+# Dataset
+1. AIHub 방송 콘텐츠 대화체 음성인식 데이터
+2. AIHub 자유대화 음성(일반남여)
+3. AIHub 저음질 전화망 음성인식 데이터 
+4. 부동산 114 고객센터
+5. clovacall
+6. Kspon
+
+각 전사 데이터를 NAS에 업로드하고 데이터 증강, 전/후처리 진행하고 검증 진행함.
+
+# Augmentation
+## Aug용 추가 데이터셋
+http://www.openslr.org/resources/28/rirs_noises.zip
+e6f48e257286e05de56413b4779d8ffb
+
+http://www.openslr.org/resources/17/musan.tar.gz
+0c472d4fc0c5141eca47ad1ffeb2a7df
+
+## 실행 구문
+python3 aug_multi.py --musan-path musan/ --rir-path RIRS_NOISES/simulated_rirs/ --root-dir dataset/path
+
+## 단일 샘플 만들기
+python3 aug_multi.py --musan-path musan/ --rir-path RIRS_NOISES/simulated_rirs/ --root-dir dataset/path --use-list false
+
+
+# 검증
+## 실행 구문
+python3 check_ogg.py --sub-dir {directory_name} --use-list true
+
+# NAS 폴더
+![NAS](https://user-images.githubusercontent.com/30919143/209759212-5a7b9640-07dc-403b-b9f8-6c62efc50140.png)
+
+# AWS Transcribe
+## Lambda 1
+- s3 특정 폴더에 음원 파일 업로드
+- AWS Cloudwatch의 log를 인지해서 lambda1 동작
+- AWS Transcribe에 해당 음원 파일의 s3 url을 전달해서 동작 요청
+
+## Lambda 2
+- AWS Transcribe에서 전사 완료 후 log 출력
+- AWS Cloudwatch에서 log를 인지해서 lambda2 동작
+- 해당 전사 내용을 txt 파일로 파일명 처리 후 저장

+ 326 - 0
aug_multi.py

@@ -0,0 +1,326 @@
+import argparse
+import numpy
+import random
+import os
+import time
+import math
+import glob
+import soundfile
+from scipy import signal
+from scipy.io import wavfile
+import soundfile as sf
+import librosa
+
+import torch
+# import torchaudio
+import torchaudio.transforms as T
+import torch.nn.functional as F
+
+from tqdm import tqdm
+import multiprocessing as mp
+from multiprocessing import Pool
+from typing import Any, Coroutine, Iterable, List, Tuple
+
+def loadWAV(filepath, max_audio, evalmode=False, num_eval=10):
+    """
+    Ignore 'evalmode' and 'num_eval' argument. We not use in this code.
+    """
+
+    # Read wav file and convert to torch tensor
+    audio, sample_rate = soundfile.read(filepath)
+    audiosize = audio.shape[0]
+
+    if audiosize <= max_audio:
+        shortage    = max_audio - audiosize + 1 
+        audio       = numpy.pad(audio, (0, shortage), 'wrap') # repeat wav to extend the wav length to max length
+        audiosize   = audio.shape[0]
+
+    if evalmode:
+        startframe = numpy.linspace(0,audiosize-max_audio,num=num_eval)
+    else:
+        startframe = numpy.array([numpy.int64(random.random()*(audiosize-max_audio))])
+    
+    feats = []
+    if evalmode and max_frames == 0:
+        feats.append(audio)
+    else:
+        for asf in startframe:
+            feats.append(audio[int(asf):int(asf)+max_audio])
+
+    feat = numpy.stack(feats,axis=0).astype(numpy.float64)
+
+    return feat;
+
+
+def loadWav_samplerate(filepath, sample_rate, transform=None):
+    waveform, _sample_rate = soundfile.read(filepath)
+
+    if _sample_rate != sample_rate:
+        t = torch.from_numpy(waveform).type(torch.float32)
+        if transform is None:
+            transform = T.Resample(_sample_rate, sample_rate)
+        waveform = transform(t).numpy()
+
+    return waveform
+
+
+def augment_2ogg(root_path, file_path, sample_rate = 16000, args = None):
+    
+    sub_path = file_path.rsplit('.', 1)[0].split(root_path)[-1] + '.ogg'
+
+    conv_list = ['ogg']
+    conv_list.extend([f'aug{i+1}' for i in range(4)])
+
+    org = None
+
+    for idx, conv in enumerate(conv_list):
+        conv_path = root_path + conv + '/' + sub_path
+
+        if os.path.isfile(conv_path):
+            continue
+        
+        os.makedirs(conv_path.rsplit('/', 1)[0], exist_ok=True)
+        
+        if org is None:
+            org = loadWav_samplerate(file_path, sample_rate)
+
+        if conv == 'ogg':
+            sf.write(conv_path, org, sample_rate)
+        else:
+            aug_audio = augmentation.augment_wav_type(org, idx)
+            if len(aug_audio.shape) >= 2:
+                aug_audio = aug_audio.squeeze(0)
+            
+            sf.write(conv_path, aug_audio, sample_rate)
+    
+
+class AugmentWAV(object):
+    def __init__(self, data_list, dest_dir, musan_path, rir_path, log_interval=100, **kwargs):
+        self.data_list = data_list
+        self.dest_dir = dest_dir
+        self.log_interval = log_interval
+
+        self.noisetypes = ['noise','speech','music']
+
+        self.noisesnr   = {'noise':[0,15],'speech':[13,20],'music':[5,15]}
+        self.numnoise   = {'noise':[1,1], 'speech':[3,7],  'music':[1,1] }
+        self.noiselist  = {}
+
+        augment_files = glob.glob(os.path.join(musan_path,'*/*/*.wav'))
+
+        for file in augment_files:
+            if not file.split('/')[-3] in self.noiselist:
+                self.noiselist[file.split('/')[-3]] = []
+            self.noiselist[file.split('/')[-3]].append(file)
+
+        self.rir_files = glob.glob(os.path.join(rir_path,'**/*.wav'), recursive=True)
+
+    def augment_wav_type(self, audio, augtype):
+        if augtype == 1:
+            audio   = self.reverberate(audio)
+        elif augtype == 2:
+            audio   = self.additive_noise('music',audio)
+        elif augtype == 3:
+            audio   = self.additive_noise('speech',audio)
+        elif augtype == 4:
+            audio   = self.additive_noise('noise',audio)
+
+        return audio
+
+
+
+    async def augment_2ogg(self, file_path, root_path, sample_rate=16000):
+
+        org, samplerate = sf.read(file_path)
+
+        sub_path = file_path.rsplit('.', 1)[0].split(root_path)[-1] + '.ogg'
+
+        ogg_path = root_path + 'ogg/' + sub_path
+        if os.path.isfile(ogg_path):
+            return
+        
+        os.makedirs(ogg_path.rsplit('/', 1)[0], exist_ok=True)
+        sf.write(ogg_path , org, sample_rate)
+
+        aug_audios = self.augemnt_all(org)
+        for idx, aa in enumerate(aug_audios):
+            aug_path = f"{root_path}aug{idx+1}/{sub_path}"
+            os.makedirs(aug_path.rsplit('/', 1)[0], exist_ok=True)
+
+            if len(aa.shape) >= 2:
+                aa = aa.squeeze(0)
+
+            soundfile.write(aug_path, aa, sample_rate)
+
+
+    def run(self):
+        count = 0 
+        for i, data_path in enumerate(self.data_list):
+            count += 1
+
+            filename = os.path.basename(data_path) # get string 'filename.ext' from 'src_dir/filename.ext'
+            dest_path = os.path.join(self.dest_dir, filename) # make 'dest_dir/filename.ext'
+
+            audio, sample_rate = soundfile.read(data_path)
+
+            aug_audio = self.augment_wav(audio)
+
+            if len(aug_audio.shape) >= 2:
+                aug_audio = aug_audio.squeeze(0)
+
+            soundfile.write(dest_path, aug_audio, sample_rate)
+
+            if i % self.log_interval == 0:
+                print(f'{count}/{len(self.data_list)}...')
+
+
+    def augment_wav(self, audio):
+        augtype = random.randint(0,4) #  augment audio with 4 noise type randomly.
+        if augtype == 1:
+            audio   = self.reverberate(audio)
+        elif augtype == 2:
+            audio   = self.additive_noise('music',audio)
+        elif augtype == 3:
+            audio   = self.additive_noise('speech',audio)
+        elif augtype == 4:
+            audio   = self.additive_noise('noise',audio)
+
+        return audio
+
+    def augemnt_all(self, audio):
+        arr = []
+
+        arr.append(self.reverberate(audio))
+        arr.append(self.additive_noise('music',audio))
+        arr.append(self.additive_noise('speech',audio))
+        arr.append(self.additive_noise('noise',audio))
+
+        return arr
+
+
+    def additive_noise(self, noisecat, audio):
+        max_audio = audio.shape[0]
+        clean_db = 10 * numpy.log10(numpy.mean(audio ** 2)+1e-4) 
+
+        numnoise    = self.numnoise[noisecat]
+        noiselist   = random.sample(self.noiselist[noisecat], random.randint(numnoise[0],numnoise[1]))
+
+        noises = []
+
+        for noise in noiselist:
+            noiseaudio  = loadWAV(noise, max_audio, evalmode=False)
+            noise_snr   = random.uniform(self.noisesnr[noisecat][0],self.noisesnr[noisecat][1])
+            noise_db = 10 * numpy.log10(numpy.mean(noiseaudio[0] ** 2)+1e-4) 
+            noises.append(numpy.sqrt(10 ** ((clean_db - noise_db - noise_snr) / 10)) * noiseaudio)
+
+        return numpy.sum(numpy.concatenate(noises,axis=0),axis=0,keepdims=True) + audio
+
+
+    def reverberate(self, audio, scale=1.0):
+        max_audio = audio.shape[0]
+
+        rir_file    = random.choice(self.rir_files)
+        
+        rir, fs     = soundfile.read(rir_file)
+        rir         = numpy.expand_dims(rir.astype(numpy.float64),0)
+        rir         = rir / numpy.sqrt(numpy.sum(rir**2))
+        
+        rirsize = rir.shape[1]
+
+        if rirsize >= max_audio: # If rir size is longer than target audio length
+            rir = rir[:,:max_audio]
+
+        if len(rir.shape) >= 3 and rir.shape[2] > 1:
+        #     rir = rir[:,:,0]
+            rir = librosa.to_mono(rir.squeeze().T)
+            rir = numpy.expand_dims(rir,0)
+
+        # print(rir.shape, type(rir))
+       
+
+        return signal.convolve(numpy.expand_dims(audio,0), rir, mode='full')[:,:max_audio]
+
+async def augment_func(root_dir, path):
+    await augment_2ogg(root_dir, path)
+
+
+async def aprogress(tasks: Iterable[Coroutine], **pbar_kws: Any) -> Any:
+    if not tasks:
+        return -1
+    
+    pbar = tqdm(asyncio.as_completed(tasks), total=len(tasks), **pbar_kws)
+
+    for task in pbar:
+        await task
+        pbar.update()
+
+def str2bool(v):
+    if isinstance(v, bool):
+       return v
+    if v.lower() in ('yes', 'true', 't', 'y', '1'):
+        return True
+    elif v.lower() in ('no', 'false', 'f', 'n', '0'):
+        return False
+    else:
+        raise argparse.ArgumentTypeError('Boolean value expected.')
+
+
+if __name__ == '__main__':
+    parser = argparse.ArgumentParser()
+    parser.add_argument('--filestxt',       default='files.txt', type=str, help='The txt with absolute path of files')
+    parser.add_argument('--dest-dir',       default='output', type=str, help='The destination save path of augmented audio file')
+    parser.add_argument('--musan-path',     default='musan_split/', type=str, help='musan file directory')
+    parser.add_argument('--rir-path',       default='simulated_rirs/', type=str, help='rir file directory')
+    parser.add_argument('--log-interval',   default=50,   type=int)
+
+    parser.add_argument('--root-dir',   default='/mnt/data/',   type=str, help='setting to the root directory')
+    parser.add_argument('--use-list',   default=True,   type=str2bool, help='use a files.txt')
+    
+    args = parser.parse_args()
+
+    args.data_list = []
+
+    augmentation = AugmentWAV(**vars(args))
+
+    if args.root_dir[-1] != '/':
+        args.root_dir += '/'
+        print(args.root_dir)
+    
+    files_txt = 'files.txt'
+    augment_files = []
+
+    if args.use_list and os.path.exists(args.root_dir + files_txt):
+        with open(args.root_dir + files_txt, 'r') as f:
+            for line in f:
+                augment_files.append(line.split('\n')[0])
+    else:
+        augment_files = glob.glob(os.path.join(args.root_dir,'**/*.wav'), recursive=True)
+        if args.use_list:
+            with open(args.root_dir + files_txt, 'w') as f:
+                for item in augment_files:
+                    f.write(f'{item}\n')
+
+    print("augment len = ", len(augment_files))
+    
+    num_cores = mp.cpu_count()
+    def work_func(path):
+        augment_2ogg(args.root_dir, path, 16000, args)
+
+
+    try:
+        pool = Pool((num_cores)//2)
+
+        with tqdm(total=len(augment_files)) as pbar:
+            for _ in tqdm(pool.imap_unordered(work_func, augment_files)):
+                pbar.update()
+
+        pool.close()
+        pool.join()
+        print("Script complete!") 
+    except KeyboardInterrupt:
+        pool.close()
+        pool.join()
+
+    
+
+    

+ 173 - 0
check_ogg.py

@@ -0,0 +1,173 @@
+import argparse
+import numpy as np
+import random
+import os
+import time
+import math
+import glob
+import soundfile as sf
+from scipy import signal
+from scipy.io import wavfile
+import librosa
+import io
+
+import torch
+# import torchaudio
+import torchaudio.transforms as T
+import torch.nn.functional as F
+
+from tqdm import tqdm
+import multiprocessing as mp
+from multiprocessing import Pool
+from typing import Any, Coroutine, Iterable, List, Tuple
+
+
+def loadWav_samplerate(filepath, sample_rate, transform=None):
+    waveform, _sample_rate = sf.read(filepath)
+
+    if _sample_rate != sample_rate:
+        t = torch.from_numpy(waveform).type(torch.float32)
+        if transform is None:
+            transform = T.Resample(_sample_rate, sample_rate)
+        waveform = transform(t).numpy()
+
+    return waveform
+
+
+def check_ogg(root_dir, wav_path, sample_rate = 16000):
+    try:
+        sub_path = wav_path.rsplit('.', 1)[0].split(root_dir)[-1] + '.ogg' ## wav_path = root_dir + sub_path
+        if sub_path[0] == '/':
+            sub_path = sub_path[1:]
+        ogg_path = os.path.join(root_dir, 'ogg', sub_path)
+
+        errors = []
+
+        if not os.path.isfile(ogg_path):
+            error = {'status' : "ogg file not exist", 'detail' : ogg_path}
+            errors.append(error)
+
+            return {'status' : 'fail', 'file' : wav_path, 'errors' : errors}
+        
+        wav_sound = loadWav_samplerate(wav_path, sample_rate)
+
+        file_format = "OGG"
+        memory_file = io.BytesIO( )
+        memory_file.name = "test.ogg"
+        sf.write( memory_file, wav_sound, sample_rate, format = file_format )
+
+        memory_file.seek( 0 )
+        temp_data, temp_sr = sf.read( memory_file )
+
+
+        ogg_sound, sr = sf.read(ogg_path)
+
+        if sr != sample_rate:
+            error = {'status' : "sample rate not match", 'detail' : str(sr) + "\t" + str(sample_rate)}
+            errors.append(error)
+        
+        if not np.array_equal(temp_data, ogg_sound):
+            error = {'status' : "wav and ogg not equal"}
+            errors.append(error)
+
+            return {'status' : 'fail', 'file' : wav_path, 'errors' : errors}
+        
+    except Exception as e:
+        return {'status' : 'exception', 'file' : wav_path, 'errors' : [str(e)]}
+
+    return {'status' : 'success', 'file' : wav_path}
+    
+
+
+def str2bool(v):
+    if isinstance(v, bool):
+       return v
+    if v.lower() in ('yes', 'true', 't', 'y', '1'):
+        return True
+    elif v.lower() in ('no', 'false', 'f', 'n', '0'):
+        return False
+    else:
+        raise argparse.ArgumentTypeError('Boolean value expected.')
+
+
+
+if __name__ == '__main__':
+    parser = argparse.ArgumentParser()
+   
+    parser.add_argument('--root-dir',   default='/root/nas/data/',   type=str, help='setting to the root directory')
+    parser.add_argument('--sub-dir',   default='clovacall',   type=str, help='setting to the root directory')
+    parser.add_argument('--dest-dir',       default='/root/preprocess/backup', type=str, help='The destination save path of ogg audio file')
+    parser.add_argument('--use-list',   default=False,   type=str2bool, help='use a files.txt')
+    
+    args = parser.parse_args()
+
+    print("task dir : ", os.path.join(args.root_dir, args.sub_dir))
+
+
+    wav_files = []
+    files_txt = args.sub_dir + "_wavs.txt"
+    if args.use_list and os.path.exists(files_txt):
+        with open(files_txt, 'r') as f:
+            for line in f:
+                wav_files.append(line.split('\n')[0])
+    else:
+        print("glob start !!")
+        wav_files = glob.glob(os.path.join(args.root_dir, args.sub_dir, '**/*.wav'), recursive=True)
+        print("glob end !!")
+
+        if args.use_list and not os.path.isfile(files_txt):
+            with open(files_txt, 'w+') as f:
+                for wav in wav_files:
+                    f.write(f'{wav}\n')
+
+    # wav_files = wav_files[:100] ## for test
+
+    # for wav_path in wav_files:
+    #     r = os.path.join(args.root_dir, args.sub_dir)
+    #     sub_path = wav_path.rsplit('.', 1)[0].split(r)[-1] + '.ogg' ## wav_path = root_dir + sub_path
+    #     if sub_path[0] == '/':
+    #         sub_path = sub_path[1:]
+
+    #     ogg_path = os.path.join(r, 'ogg', sub_path)
+    #     # ogg_path = f"{os.path.join(args.root_dir, args.sub_dir)}/ogg/{sub_path}"
+
+    #     print(sub_path + "\t" + ogg_path + "\t" + r)
+
+    print("wav len = ", len(wav_files))
+    # exit()
+    
+    num_cores = mp.cpu_count()
+    def work_func(path):
+        return check_ogg(os.path.join(args.root_dir, args.sub_dir), path, 16000)
+
+    fail_list = []
+    try:
+        pool = Pool((num_cores * 2) // 3)
+
+        with tqdm(total=len(wav_files)) as pbar:
+            for res in tqdm(pool.imap_unordered(work_func, wav_files)):
+                # print(res)
+                if res['status'] != 'success':
+                    fail_list.append(res)
+                    
+                pbar.update()
+
+        pool.close()
+        pool.join()
+
+        fail_txt = "fail_" + args.sub_dir + ".txt"
+        if len(fail_list) >= 1:
+            with open(fail_txt, 'w+') as f:
+                for fail in fail_list:
+                    content = res["file"] + "\t" + str(res['errors'])
+                    f.write(content + "\n")
+
+        print("Fail len ", len(fail_list))
+        print("Script complete!") 
+    except KeyboardInterrupt:
+        pool.close()
+        pool.join()
+
+    
+
+    

+ 170 - 0
failure_check.py

@@ -0,0 +1,170 @@
+from tqdm import tqdm
+from postprocess import postprocess
+import glob
+import os
+import re
+import re
+
+from datetime import datetime
+now = datetime.now()
+time_str = now.strftime('%Y_%m_%d_%H_%M_%S')
+
+## none 이면 저장 안됨.
+def broadcast_none_check():
+    total_txt = "/root/mnt/data_aug/audio_augmentation/script/total.txt"
+    failure_txt = f"broadcast_none_{time_str}.txt"
+    ogg_path = '/root/sata/broadcast/split/data'
+    total_ogg_txt = 'broadcast_total_ogg.txt'
+
+    total_txt_set = set()
+    ogg_set = set()
+
+    failure = []
+    cnt = 0
+
+    def split1_split2_compare():
+        failure_txt = f"broadcast_split1_split2_compare_{time_str}.txt"
+        ogg_files = glob.glob(os.path.join('/root/sata/broadcast_split/data', '**/*.ogg'), recursive=True)
+        for ogg in tqdm(ogg_files):
+            txt_file = ogg.strip().replace("ogg", "txt").replace("broadcast_split", "broadcast/split")
+
+            if not os.path.isfile(txt_file):
+                failure.append([ogg, txt_file])
+
+        with open(failure_txt, 'w+') as ft:
+            for fail in failure:
+                ft.write("\t".join(fail) + "\n")
+        print("len failire = ", len(failure))
+
+    
+    def split2_split1_compare():
+        failure_txt = f"broadcast_split2_split1_compare_{time_str}.txt"
+
+        txt_files = glob.glob(os.path.join('/root/sata/broadcast/split/data', '**/*.txt'), recursive=True)
+        for txt in tqdm(txt_files):
+            ogg_file = txt.strip().replace("txt", "ogg").replace("broadcast/split", "broadcast_split" )
+
+            if not os.path.isfile(ogg_file):
+                failure.append([txt, ogg_file])
+
+        with open(failure_txt, 'w+') as ft:
+            for fail in failure:
+                ft.write("\t".join(fail) + "\n")
+        print("len failire = ", len(failure))
+
+
+    
+    split2_split1_compare()
+    return
+
+def broadcast_special_check():
+    failure = []
+    failure_txt = f"broadcast_special_check{time_str}.txt"
+    pattern_1 = r'[%$#]'
+
+    txt_files = glob.glob(os.path.join('/root/sata/broadcast/split/data', '**/*.txt'), recursive=True)
+    for txt in tqdm(txt_files):
+        with open(txt, 'r') as t:
+            tt = t.read().strip()
+            tt = tt.strip()
+            tmp = re.search(pattern=pattern_1, string = tt)
+            if tmp:
+                failure.append([txt, tt])
+
+    with open(failure_txt, 'w+') as ft:
+        for fail in failure:
+            ft.write("\t".join(fail) + "\n")
+    print("len failire = ", len(failure))
+
+def broadcast_post_check():
+    failure_list = []
+    for source_txt in tqdm.tqdm(glob.glob(os.path.join('/root/sata/broadcast/split/data', '**/*.txt'), recursive=True)):
+        with open(source_txt, 'r') as f:
+            content = f.read().strip()
+            post = postprocess(content)
+
+            if post is None:
+                failure_list.append([source_txt, content])
+
+    failure_txt = f"broadcast_post.txt"
+
+    with open(failure_txt, 'w+') as ft:
+        for fail in failure_list:
+            ft.write("\t".join(fail) + "\n")
+
+    print("len = ", len(failure_list))
+
+def broadcast_post_check():
+    total_txt = "/root/mnt/data_aug/audio_augmentation/script/total.txt"
+    failure_txt = f"broadcast_none_{time_str}.txt"
+    ogg_path = '/root/sata/broadcast_split/data'
+    total_ogg_txt = 'broadcast_total_ogg.txt'
+
+    total_txt_set = set()
+    ogg_set = set()
+
+    failure = []
+    cnt = 0
+
+    try:
+        with open(total_ogg_txt, 'r') as tf:
+            for ogg in tqdm(tf):
+                ogg = ogg.strip()
+                txt_file = ogg.replace('ogg', 'txt')
+
+                if not os.path.isfile(txt_file):
+                    failure.append(ogg)
+                else:
+                    cnt += 1
+    except:
+        tf.close()
+    finally:
+        with open(failure_txt, 'w+') as ft:
+            for fail in failure:
+                ft.write(fail + "\n")
+
+        print('cnt', cnt, len(failure))
+
+    return
+
+
+def freetalk_special_check():
+    ogg_path = '/root/nas/data/freetalk/ogg'
+
+    total_txt = 'freetalk_total.txt'
+    failure_txt = f"freetalk_failure_{time_str}.txt"
+    failure = []
+
+    pattern = r"[^\uAC00-\uD7A30-9a-zA-Z\s]" ## 특문
+
+    with open(total_txt, 'w+') as tf:
+        for txt_file in tqdm(glob.glob(os.path.join(ogg_path, '**/*.txt'), recursive=True), leave=True):
+            tf.write(f"{txt_file}\n")
+            with open(txt_file, 'r') as f:
+                content = f.read().strip()
+                
+            
+            exist = re.search(pattern=pattern, string=content)
+            
+            if exist:
+                failure.append((file, content))
+
+            if idx == 100:
+                break
+
+    if len(failure) >= 1:
+        with open(failure_txt, "w+") as f:
+            for _failure in failure:
+                f.write(f"{' '.join(_failure)}\n")
+
+    return
+            
+
+# print('test')
+# freetalk_special_check()
+    
+
+if __name__ == '__main__':
+    # broadcast_none_check()
+    broadcast_special_check()
+    # freetalk_special_check()

+ 194 - 0
postprocess.py

@@ -0,0 +1,194 @@
+import re
+import glob
+import time
+import tqdm
+from datetime import datetime
+from shutil import copyfile
+import os
+
+a1 = "머리를 (()) 그담에 뭐 하트도 날리고 뽀뽀도 해주고 윙크도 해주고 토닥토닥 안아주고 이 두 가지를 적절하게 잘 사용하면 굉장히 인제 조금 칭찬 방법이 되는 거죠."
+a2 = "니가 이반에서 제일 머리가 좋아 그런 거는 쪼끔 안 좋습니다 왜냐면 인제 자기보다 예쁜 아이가 있는 다른 반에 가지 않을려고 {laughing} 다른 친구보다 다른 형제자매들 보다 훨씬 낫다는 식의 비교 칭찬은 가급적 하지 않는 것이 좋습니다."
+a3 = "그니까 아까 왜 너 얼마나 잘할 거 같애 칠십 퍼센트요 팔십 퍼센트요 그니까 (아이 캔 두잇)(i can do it 나 할 수 있을 거 같애요 라고 하는 건데요."
+a4 = f"    "
+a = [a1, a2, a3, a4]
+
+
+pattern_1 = r'\(\(\)\)' ## (())
+pattern_2 = r'\{(\w*)\}' ## {@@@}
+pattern_3 = r'\((\w*)\)' ## (@@@) 찾기
+
+pattern_4 = r'[\(\)\{\}]' ## (, ), {, } 찾기
+pattern_4_1 = r'&([\w|-]*)&' ## &(id-id123)& 찾기
+
+pattern_5 = r"[^\uAC00-\uD7A30-9a-zA-Z\s]" ## 특문 repl=' '
+pattern_6 = r" {2,}" ## 빈 문자열 2개 이상
+
+
+def postprocess(origin):
+    _a = re.sub(pattern=pattern_1, repl='', string = origin)
+    _a = re.sub(pattern=pattern_2, repl='', string = _a)
+    _a = re.sub(pattern=pattern_3, repl='', string = _a)
+    tmp = re.search(pattern=pattern_4, string = _a)
+    if tmp:
+        return None
+    
+    tmp = re.search(pattern=pattern_4_1, string = _a)
+    if tmp:
+        return None
+
+    _a = re.sub(pattern=pattern_5, repl = " ", string = _a)
+    _a = re.sub(pattern=pattern_6, repl = " ", string = _a)
+    _a = _a.strip()
+
+    if len(_a) == 0:
+        return None
+    else:
+        return _a
+
+# test = '{laughing} 기억하고 있어야지 후생에도 혹시 {laughing} (()) (()) (광)'
+# test = '저희 음악 한 곡 듣고 와서 조금 더 마지막 사연 이야기 나눠볼게요.여러분의 의견도 많이 보내주시길 바래요.&company-name225& &tel-num1& 오십 원 혹은 백 원의 유료문자'
+# test = '저희 음악 한 곡 듣고 와서 조금 더 마지막 사연 이야기 나눠볼게요.여러분의 의견도 많이 보내주시길 바래요.'
+# print(list(map(postprocess, a)))
+# print(re.sub(pattern=pattern_1, repl='', string = test))
+# exit()
+
+root_dir = "/root/sata/broadcast_split/data/"
+total_txt = "/root/mnt/data_aug/audio_augmentation/script/total.txt"
+
+# with open(total_txt, 'w+') as tf:
+#     for idx, content in enumerate(a):
+#         content = content.strip()
+    
+#         post = postprocess(content)
+#         if post is not None:
+#             print(content + "\n  -->  " + post)
+#             tf.write(post + "\n")
+
+
+# exit()
+
+
+## 1 = broadcast_split
+## 2 = broadcast/split 
+## 1에 있는 ogg를 기준으로, txt2를 가져오고, 이를 후처리 해서 txt1에 적용함.
+def broadcast_move_split2_split1(time_str):
+
+    total_txt_file = '/root/mnt/data_aug/audio_augmentation/script/txt/broadcast_total_2.txt'
+    ## for test
+    # total_txt_file = '/root/mnt/data_aug/audio_augmentation/script/txt/broadcast_total_test.txt'
+    
+    ogg_path = '/root/sata/etc/broadcast_split/data'
+    ## for text
+    # ogg_path = '/root/mnt/data_aug/audio_augmentation/sample/broadcast_split'
+
+    post_none_list = []
+    not_exist_list = []
+    ogg_list = []
+
+    print('glob start !!')
+    if os.path.isfile(total_txt_file):
+        with open(total_txt_file, 'r') as f:
+            for ogg in f:
+                tt = ogg.strip()
+                ogg_list.append(tt)
+    else:
+        ogg_list = glob.glob(os.path.join(ogg_path, '**/*.ogg'), recursive=True)
+        with open(total_txt_file, 'w+') as f:
+            for ogg in ogg_list:
+                f.write(ogg + '\n')
+        
+    print('glob end !!', len(ogg_list))
+
+    # return
+
+    for source_ogg in tqdm.tqdm(ogg_list):
+        source_ogg = source_ogg.strip()
+        
+        split1_txt_file = source_ogg.strip().replace("ogg", "txt")
+        split2_txt_file = source_ogg.strip().replace("ogg", "txt").replace("broadcast_split", "broadcast/split")
+
+        if not os.path.isfile(split2_txt_file):
+            not_exist_list.append([source_ogg, split2_txt_file])
+        else:
+            with open(split2_txt_file, 'r') as f:
+                content = f.read().strip()
+
+            post = postprocess(content)
+
+            with open(split1_txt_file, 'w') as f:
+                if post is None:
+                    post_none_list.append([split2_txt_file, content])
+                    if os.path.isfile(split1_txt_file):
+                        os.remove(split1_txt_file)
+                    tmp_ogg = split1_txt_file.replace('txt', 'ogg')
+                    if os.path.isfile(tmp_ogg):
+                        os.remove(tmp_ogg)
+                else:
+                    f.write(post + '\n')
+
+
+    if post_none_list:
+        print('postprocess none = ', len(post_none_list))
+        txt = f'log/post_none_{time_str}.txt'
+
+        with open(txt, 'w+') as f:
+            for item in post_none_list:
+                f.write("\t".join(item) + "\n")
+    
+    if not_exist_list:
+        print('not exist = ', len(not_exist_list))
+        txt = f'log/not_exist_{time_str}.txt'
+
+        for item in post_none_list:
+            with open(txt, 'w+') as f:
+                f.write("\t".join(item) + "\n")
+
+    
+    
+            
+            
+
+
+if __name__ == '__main__':
+
+    now = datetime.now()
+    time_str = now.astimezone().strftime('%Y_%m_%d_%H_%M_%S')
+
+    # print(time_str)
+    # # exit()
+
+    broadcast_move_split2_split1(time_str)
+
+    # failure = []
+    # failure_txt = f"broadcast_failure_{time_str}.txt"
+
+    # with open(total_txt, 'w+') as tf:
+    #     for file in tqdm.tqdm(glob.glob(f'{root_dir}**/*.txt', recursive=True)):
+    #         content = ''
+    #         with open(file, 'r') as f:
+    #             content = f.read().strip()
+            
+    #         post = postprocess(content)
+    #         # print(str(idx) + " : " + content + "\n  -->  " + post)
+
+    #         with open(file, 'w') as f:
+                    
+    #             if post is not None:
+    #                 # tf.write(file + "\n")
+    #                 # f.write(post)
+    #                 pass
+    #             else:
+    #                 failure.append([file, content, post])
+    
+    # # print(failure)
+    # print(len(failure))
+
+    # with open(failure_txt, 'w+') as ft:
+    #     for fail in tqdm.tqdm(failure):
+    #         if fail[2] is None: fail[2] = 'None'
+
+    #         ft.write("\t".join(fail) + "\n")
+            
+#         else:
+#             print(file)
+#             cnt += 1

+ 165 - 0
srt_split.py

@@ -0,0 +1,165 @@
+from datetime import datetime
+import glob
+import os
+import soundfile as sf
+import re
+import tqdm
+import pysubs2
+
+### 부동산 - 전사 srt -> split ogg + 텍스트
+root_path = ""
+
+dir_list = glob.glob(root_path + "*/") ## root path 밑에 있는 sub dir 모두 가져오기
+
+pattern_1 = r'\(\(\)\)' ## (())
+pattern_2 = r'\{(\w*)\}' ## {@@@} -> @@
+pattern_2_1 = r'\[(\w*)\]' ## [@@@] -> @@
+pattern_2_2 = r'\((\w*)\)' ## (@@@) 찾기 -> @@
+pattern_2_1 = r'[^/]\(([\w|\s]*)\)[^/]' ## (@@)/(@@)이 아닌 (@@) 찾기 repl=' \1 '
+
+pattern_3_1 = r'\(([\w|\s|.]*)\)/\(([\w|\s|.]*)\)' ## (@@)/(@@) -> {@@}/{@@} 임시 변환, repl=r'{\1}/{\2}'
+pattern_3_2 = r'\(([\w|\s]*)\)' ## (@@) 찾기, repl=r'\1'
+pattern_3_3 = r'\{([\w|\s|.]*)\}/\{([\w|\s|.]*)\}' ## {@@}/{@@} -> (@@)/(@@) 임시변환 해제, r'(\1)/(\2)'
+
+pattern_4 = r'[\(\)\{\}]' ## (, ), {, } 찾기
+pattern_4_1 = r'&([\w|-]*)&' ## &(id-id123)& 찾기
+
+pattern_5 = r"[^\uAC00-\uD7A30-9a-zA-Z\s]" ## 특문
+pattern_6 = r" {2,}" ## 빈 문자열 2개 이상
+
+pattern_7 = r"\\N"
+
+now = datetime.now()
+time_str = now.astimezone().strftime('%Y_%m_%d_%H_%M_%S')
+
+def postprocess(origin):
+    _a = re.sub(pattern=pattern_7, repl=' ', string = origin)
+    _a = re.sub(pattern=pattern_1, repl='', string = _a)
+    _a = re.sub(pattern=pattern_2, repl=r'\1', string = _a)
+    _a = re.sub(pattern=pattern_2_1, repl=r'\1', string = _a)
+    # _a = re.sub(pattern=pattern_3, repl=r'\1', string = _a)
+
+    _a = re.sub(pattern=pattern_5, repl = "", string = _a)
+    _a = re.sub(pattern=pattern_6, repl = " ", string = _a)
+    _a = _a.strip()
+
+    if len(_a) == 0:
+        return None
+    else:
+        return _a
+
+
+def time_convert(time):
+    split = re.split(r',|:', time)
+
+    mi = int(split[0])
+    mi = mi * 60 + int(split[1])
+    mi = mi * 60 + int(split[2]) + float('0.' + split[3])
+    
+    return mi
+
+ 
+for _dir in dir_list:
+    post_none_list = []
+    not_exist_list = []
+
+    ## _dir이 directory일 때만 실행
+    if not os.path.isdir(_dir):
+        continue
+
+    ## 저장용 split directory 생성
+    output_dir = os.path.join(_dir, "split")
+    os.makedirs(output_dir, exist_ok=True)
+
+    ## _dir 폴더 하위의 srt 파일 모두 가져오기
+    srt_list = glob.glob(os.path.join(_dir,'*.srt'))
+
+    for srt in tqdm.tqdm(srt_list):
+        ## 파일명 전처리 -> 폴더 구조별 동작이 다를 수 있으니, 확인 필요
+        base_name = srt.rsplit('_', 2)[0]
+        folder_name, file_name = base_name.rsplit('/', 1)
+
+        ## srt와 wav가 함께 존재하지 않으면 fail list에 추가 후 continue
+        if not os.path.isfile(base_name + '.wav'):
+            not_exist_list.append(file_name)
+            continue
+
+        y, sr = sf.read(base_name + '.wav')
+
+        subs = pysubs2.load(srt, encoding="utf-8")
+        for idx, sub in enumerate(subs):
+            start = int(sub.start / 1000 * sr)
+            end = int(sub.end/1000*sr)
+
+            ## 전사 내용 후처리 -> 데이터셋별 튜닝 필요.
+            post = postprocess(sub.text)
+
+            ## split file 이름 처리
+            str_num = str(idx)
+            str_num = '_' + ('0' * (3 - len(str_num))) + str_num
+            tmp_file_name = file_name + str_num + ".wav"
+
+            ## 전사 내용이 이상값이면 None, None이면 fail list에 추가
+            if post is None:
+                post_none_list.append([tmp_file_name, sub.text])
+                continue
+        
+            sp_wav = y[start : end+1]
+            sf.write(os.path.join(output_dir, tmp_file_name), sp_wav, sr)
+
+            with open(os.path.join(output_dir, tmp_file_name.replace('wav', 'txt')), 'w+') as f:
+                f.write(post + '\n')
+
+
+
+        ## 직접 srt static하게 자르기
+        # with open(srt, 'r') as f:
+        #     text = ''
+        #     start = 0
+        #     end = 0
+
+        #     b = False
+
+        #     for idx, line in enumerate(f):
+        #         if str.isdigit(line):
+        #             b = True
+        #             continue
+                
+        #         if idx % 4 == 1: ## time
+        #             try:
+        #                 start, end = map(time_convert, line.split(' --> '))
+        #             except:
+        #                 print(srt, '\t', line)
+        #                 exit()
+        #         elif idx % 4 == 2: ## transcribe
+        #             str_num = str(idx//4)
+        #             str_num = '_' + ('0' * (3 - len(str_num))) + str_num
+        #             file_name = file_name + str_num + ".wav"
+
+        #             post = postprocess(line.strip())
+        #             if post is None:
+        #                 post_none_list.append([file_name, line])
+        #                 continue
+
+        #             sp_wav = y[int(sr * start) : int(sr * end)+1]
+        #             sf.write(os.path.join(output_dir, file_name), sp_wav, sr)
+
+        #             with open(os.path.join(output_dir, file_name.replace('wav', 'txt')), 'w+') as f:
+        #                 f.write(post + '\n')
+    
+
+    if post_none_list:
+        print('postprocess none = ', len(post_none_list))
+        txt = f'log/post_none_{time_str}.txt'
+
+        with open(txt, 'w+') as f:
+            for item in post_none_list:
+                f.write("\t".join(item) + "\n")
+    
+    if not_exist_list:
+        print('not exist = ', len(not_exist_list))
+        txt = f'log/not_exist_{time_str}.txt'
+
+        for item in post_none_list:
+            with open(txt, 'w+') as f:
+                f.write("\t".join(item) + "\n")

+ 232 - 0
transcribe_process.py

@@ -0,0 +1,232 @@
+import jiwer
+import glob
+import pandas as pd
+import tqdm
+import os
+import re
+from collections import defaultdict
+
+import matplotlib.pyplot as plt
+
+root_path = ""
+sub_path = [
+    "", ""
+]
+
+def readNumber(n):
+    units = [''] + list('십백천만') + ['십만', '백만', '천만', '억']
+    # units = [''] + list('십백천만')
+    nums = '일이삼사오육칠팔구'
+    result = []
+    i = 0
+    while n > 0:
+        n, r = divmod(n, 10)
+        if r > 0:
+            result.append(nums[r-1] + units[i])
+        i += 1
+    return ''.join(result[::-1])
+
+def convert(str):
+    iter = re.finditer(r'\d+', str)
+    L = sum(1 for _ in re.finditer(r'\d+', str))
+    res = ''
+    prev = 0
+
+    if L == 0:
+        return str
+
+    for idx, match in enumerate(iter):
+        s, e = match.span()
+        if prev < s:
+            res += str[prev:s]
+        
+        a = str[s : e]
+        a = readNumber(int(a))
+        res += a
+        prev = e
+
+        if idx == L - 1:
+            res += str[e:]
+
+    return res
+
+def create_total(total_name):
+    for sub in sub_path:
+        srt_list = glob.glob(root_path + sub + "*.srt")
+
+        with open(root_path + f"total/{total_name}", 'a') as tt:
+            for srt in srt_list:
+                base_name = srt.rsplit('_', 2)[0]
+                folder_name, file_name = base_name.rsplit('/', 1)
+
+                with open(srt, 'r') as f:
+                    split_text = ' '
+
+                    for idx, org_text in enumerate(f):
+                        if idx%4 == 2:
+                            str_num = str(idx//4)
+                            str_num = '_' + ('0' * (3 - len(str_num))) + str_num
+
+                            split_file = folder_name + "/split/" + file_name + str_num + ".txt"
+
+                            if not os.path.exists(split_file):
+                                split_text = ''
+                            else:
+                                with open(split_file, 'r') as f:
+                                    split_text = f.read()
+                            
+                            
+                            org_text = re.sub(r"[^\uAC00-\uD7A30-9a-zA-Z\s]", "", org_text.strip())
+                            split_text = re.sub(r"[^\uAC00-\uD7A30-9a-zA-Z\s]", "", split_text.strip())
+                            # org_text = re.sub(r"[^\uAC00-\uD7A30-9a-zA-Z]", "", org_text.strip())
+                            # split_text = re.sub(r"[^\uAC00-\uD7A30-9a-zA-Z]", "", split_text.strip())
+
+                            if len(org_text) == 0 or len(split_text) == 0:
+                                cer, wer, c_cer, c_wer = [ 1 for _ in range(4) ]
+                            else:
+                                cer = jiwer.cer(org_text, split_text)
+                                wer = jiwer.wer(org_text, split_text)
+
+                                try:
+                                    c_org = convert(org_text)
+                                    c_split = convert(split_text)
+
+                                    c_cer = jiwer.cer(c_org, c_split)
+                                    c_wer = jiwer.wer(c_org, c_split)
+                                except:
+                                    c_cer = cer
+                                    c_wer = wer
+                            
+                            tt.write(f"{file_name + str_num}\t{org_text}\t{split_text}\t{cer}\t{wer}\t{c_cer}\t{c_wer}\n")
+def create_dataframe(total_name):
+    with open(root_path + f"total/{total_name}", 'r') as f:
+        data = f.readlines()
+    
+    columns = ['path', 'script1', 'script2', 'cer', 'wer', 'c_cer', 'c_wer']
+    data = [ d.strip().split('\t') for d in data ]
+    df = pd.DataFrame(data, columns=columns)
+
+    threshold = '0.2'
+
+    print(df[(df['cer'] < threshold) | (df['wer'] < threshold) | (df['c_cer'] < threshold) | (df['c_wer'] < threshold) ][['path', 'cer', 'wer', 'c_cer', 'c_wer']])
+    print('-'*50)
+
+    print(df[(df['cer'] < threshold) | (df['wer'] < threshold) | (df['c_cer'] < threshold) | (df['c_wer'] < threshold) ][['path', 'script1', 'script2']])
+    print('-'*50)
+
+    threshold = '0.0'
+    print(df[(df['cer'] <= threshold) | (df['wer'] <= threshold) | (df['c_cer'] <= threshold) | (df['c_wer'] <= threshold) ][['path', 'script1', 'script2']])
+    print('-'*50)
+    
+
+def create_plt_file(d, name):
+    plt.title(name)
+    plt.xlim([0, 3])
+    plt.bar(d.keys(), d.values(), 0.01, color='g')
+    plt.savefig(f'plot/{name}.png')
+
+def create_hist():
+
+    hist_cer  = defaultdict(int)
+    hist_wer = defaultdict(int)
+    hist_c_cer = defaultdict(int)
+    hist_c_wer = defaultdict(int)
+
+    error_cnt = 0
+
+    for sub in sub_path:
+        srt_list = glob.glob(root_path + sub + "*.srt")
+        for srt in srt_list:
+            base_name = srt.rsplit('_', 2)[0]
+            folder_name, file_name = base_name.rsplit('/', 1)
+
+            with open(srt, 'r') as f:
+                split_text = ' '
+
+                for idx, org_text in enumerate(f):
+                    cer, wer, c_cer, c_wer = [ 0 for _ in range(4) ]
+                    if idx%4 == 2:
+                        str_num = str(idx//4)
+                        str_num = '_' + ('0' * (3 - len(str_num))) + str_num
+
+                        split_file = folder_name + "/split/" + file_name + str_num + ".txt"
+
+                        if not os.path.exists(split_file):
+                            split_text = ''
+                        else:
+                            with open(split_file, 'r') as f:
+                                split_text = f.read()
+                        
+                        org_text = org_text.strip()
+                        split_text = split_text.strip()
+
+                        if len(org_text) == 0 or len(split_text) == 0:
+                            e = 1.0
+
+                            hist_cer[e] += 1
+                            hist_wer[e] += 1
+                            hist_c_cer[e] += 1
+                            hist_c_wer[e] += 1
+
+                        else:
+                            cer = round(jiwer.cer(org_text, split_text), 4)
+                            wer = round(jiwer.wer(org_text, split_text), 4)
+                            hist_cer[cer] += 1
+                            hist_wer[wer] += 1
+
+                            try:
+                                c_org = convert(org_text)
+                                c_split = convert(split_text)
+
+                                c_cer = round(jiwer.cer(c_org, c_split), 4)
+                                c_wer = round(jiwer.wer(c_org, c_split), 4)
+
+                                hist_c_cer[c_cer] += 1
+                                hist_c_wer[c_wer] += 1
+                            except:
+                                error_cnt += 1 
+                                pass
+
+                            
+
+    # create_plt_file(hist_cer, 'cer')
+    # create_plt_file(hist_wer, 'wer')
+    # create_plt_file(hist_c_cer, 'convert cer')
+    # create_plt_file(hist_c_wer, 'convert wer')
+
+    # print(error_cnt)
+    width = 0.005
+    xlim = [0, 1.1]
+
+    # plt.subplot(2, 2, 1) 
+    # plt.title('cer')
+    # plt.xlim(xlim)
+    # plt.bar(hist_cer.keys(), hist_cer.values(), width, color='g')
+
+    # plt.subplot(2, 2, 2) 
+    # plt.title('wer')
+    # plt.xlim(xlim)
+    # plt.bar(hist_wer.keys(), hist_wer.values(), width, color='g')
+
+    # plt.subplot(2, 2, 3) 
+    # plt.title('convert cer')
+    # plt.xlim(xlim)
+    # plt.bar(hist_c_cer.keys(), hist_c_cer.values(), width, color='g')
+
+    # plt.subplot(2, 2, 4) 
+    # plt.title('convert wer')
+    # plt.xlim(xlim)
+    # plt.bar(hist_c_wer.keys(), hist_c_wer.values(), width, color='g')
+
+    # plt.tight_layout()
+
+    # plt.savefig(f'plot/total.png', dpi=200)
+
+
+                        
+if __name__ == '__main__':
+
+    total_name = "total_without_space.txt"
+    # create_hist()
+    create_total(total_name)
+    create_dataframe(total_name)

+ 50 - 0
wrd_error.py

@@ -0,0 +1,50 @@
+import jiwer
+import glob
+import os
+import re
+from collections import defaultdict
+
+root_path = 'sample/wrd/'
+clova = 'clova_200.wrd'
+aws = 'aws_200.wrd'
+GT = 'GT_200.wrd'
+
+
+def get_list(list, path):
+    with open(os.path.join(root_path, path), 'r') as f:
+        for line in f:
+            line = f.readline().strip()
+            line = re.sub(r"[^\uAC00-\uD7A30-9a-zA-Z\s]", "", line)
+
+            list.append(line)
+    
+    return list
+
+def get_error_rate(gt, target, filename):
+    cer_list = []
+    wer_list = []
+
+    sum_cer = 0
+    sum_wer = 0
+
+    for _gt, _target in zip(gt, target):
+        cer = jiwer.cer(_gt, _target)
+        wer = jiwer.wer(_gt, _target)
+
+        cer_list.append(cer)
+        wer_list.append(wer)
+
+        sum_cer += cer
+        sum_wer += wer
+    
+    print(f"cer avg : {sum_cer/len(cer_list)}")
+    print(f"wer avg : {sum_wer/len(wer_list)}")
+
+ 
+if __name__ == '__main__':
+    clova_list = get_list([], clova)
+    aws_list = get_list([], aws)
+    GT_list = get_list([], GT)
+
+    get_error_rate(GT_list, clova_list, '')
+    get_error_rate(GT_list, aws_list, '')