Youtube ASR + Diarization + SRT format#

Let say you want to transcribe long audio from youtube and detect speakers using TorchAudio and save to SRT format, malaya-speech able to do that.

This tutorial is available as an IPython notebook at malaya-speech/example/youtube-asr-diarization-torchaudio-srt.

This module is not language independent, so it not save to use on different languages. Pretrained models trained on hyperlocal languages.

This is an application of malaya-speech Pipeline, read more about malaya-speech Pipeline at malaya-speech/example/pipeline.

Download youtube video#

I use https://github.com/ytdl-org/youtube-dl to download,

pip install youtube-dl
[1]:
import os

os.environ['CUDA_VISIBLE_DEVICES'] = ''
[2]:
filename = 'LIVE - Perutusan khas oleh Perdana Menteri Muhyiddin Yassin-YzjNAOSALU8.mp3'
url = 'https://www.youtube.com/watch?v=YzjNAOSALU8&ab_channel=KiniTV'

if not os.path.exists(filename):
    import youtube_dl

    ydl_opts = {
        'format': 'bestaudio/best',
        'postprocessors': [{
            'key': 'FFmpegExtractAudio',
            'preferredcodec': 'mp3',
            'preferredquality': '192',
        }],
        'no-check-certificate': True
    }

    with youtube_dl.YoutubeDL(ydl_opts) as ydl:
        ydl.download([url])
[3]:
import malaya_speech
from malaya_speech import Pipeline
from malaya_speech.utils.astype import float_to_int
`pyaudio` is not available, `malaya_speech.streaming.pyaudio` is not able to use.

Load VAD model#

We are going to use WebRTC VAD model, read more about VAD at https://malaya-speech.readthedocs.io/en/latest/load-vad.html

[4]:
vad_model = malaya_speech.vad.webrtc()
p_vad = Pipeline()
pipeline = (
    p_vad.map(lambda x: float_to_int(x, divide_max_abs=False))
    .map(vad_model)
)
p_vad.visualize()
[4]:
_images/youtube-asr-diarization-torchaudio-srt_9_0.png

Starting malaya-speech 1.4.0, streaming always returned a float32 array between -1 and +1 values.

Load ASR model#

[5]:
model = malaya_speech.stt.transducer.pt_transformer(model = 'mesolitica/conformer-medium')
[6]:
_ = model.eval()

ASR Pipeline#

Feel free to add speech enhancement or any function, but in this example, I just keep it simple.

[7]:
p_asr = Pipeline()
pipeline_asr = (
    p_asr.map(lambda x: model.beam_decoder([x])[0], name = 'speech-to-text')
)
p_asr.visualize()
[7]:
_images/youtube-asr-diarization-torchaudio-srt_15_0.png

You need to make sure the last output should named as ``speech-to-text`` or else the streaming interface will throw an error.

Diarization Pipeline#

[8]:
speaker_v = malaya_speech.speaker_vector.nemo(model = 'huseinzol05/nemo-titanet_large')
[9]:
_ = speaker_v.eval()
[11]:
from malaya_speech.diarization import streaming
from malaya_speech.model.clustering import StreamingSpeakerSimilarity
import numpy as np
[12]:
streaming_model = StreamingSpeakerSimilarity(similarity_threshold = 0.7)
[13]:
p_classification = Pipeline()
to_float = p_classification
to_float.map(lambda x: speaker_v([x])[0]) \
.map(lambda x: streaming(x, streaming_model), name = 'classification')

p_classification.visualize()
[13]:
_images/youtube-asr-diarization-torchaudio-srt_22_0.png

Straight forward, predict each frames, if similar at least 70%, returned existing speaker, else append new speaker.

Postfilter Pipeline#

The problem with multispeaker audio, sometime there are frames got speaker overlapped each other, so I want to reject those frames.

[14]:
speaker_overlap = malaya_speech.speaker_overlap.deep_model(model = 'vggvox-v2')
2023-05-16 14:35:12.211557: I tensorflow/core/platform/cpu_feature_guard.cc:142] This TensorFlow binary is optimized with oneAPI Deep Neural Network Library (oneDNN) to use the following CPU instructions in performance-critical operations:  AVX2 FMA
To enable them in other operations, rebuild TensorFlow with the appropriate compiler flags.
2023-05-16 14:35:12.217160: E tensorflow/stream_executor/cuda/cuda_driver.cc:271] failed call to cuInit: CUDA_ERROR_NO_DEVICE: no CUDA-capable device is detected
2023-05-16 14:35:12.217180: I tensorflow/stream_executor/cuda/cuda_diagnostics.cc:169] retrieving CUDA diagnostic information for host: husein-MS-7D31
2023-05-16 14:35:12.217183: I tensorflow/stream_executor/cuda/cuda_diagnostics.cc:176] hostname: husein-MS-7D31
2023-05-16 14:35:12.217221: I tensorflow/stream_executor/cuda/cuda_diagnostics.cc:200] libcuda reported version is: 470.182.3
2023-05-16 14:35:12.217234: I tensorflow/stream_executor/cuda/cuda_diagnostics.cc:204] kernel reported version is: 470.182.3
2023-05-16 14:35:12.217236: I tensorflow/stream_executor/cuda/cuda_diagnostics.cc:310] kernel version seems to match DSO: 470.182.3
/home/husein/dev/malaya-speech/malaya_speech/utils/featurization.py:38: FutureWarning: Pass sr=16000, n_fft=512 as keyword args. From version 0.10 passing these as positional arguments will result in an error
  self.mel_basis = librosa.filters.mel(
[15]:
is_clean = malaya_speech.is_clean.nemo(model = 'huseinzol05/nemo-is-clean-speakernet')
[16]:
_ = is_clean.eval()
[17]:
p_postfilter = Pipeline()
p_frames = p_postfilter.map(malaya_speech.utils.generator.frames, frame_duration_ms = 100,
                     append_ending_trail = False)
p_speaker_overlap = p_frames.foreach_map(speaker_overlap) \
.map(lambda x: np.mean(x) <= 0.1)
is_clean_overlap = p_frames.foreach_map(is_clean) \
.map(lambda x: np.mean(x) >= 0.1)
p_speaker_overlap.zip(is_clean_overlap).map(lambda x: np.mean(x) == 1, name = 'postfilter')
p_postfilter.visualize()
[17]:
_images/youtube-asr-diarization-torchaudio-srt_28_0.png

The pipeline is simple, a long frame splitted into 100 ms frames, 1. predict speaker overlapped, if those 100 ms frames are less than 10% speaker overlapped. 2. predict speeches are clean at least 10%. 3. if (1) and (2) are correct, we accept the frame.

postfilter pipeline must returned True to accept a frame.

You need to make sure the last output should named as ``postfilter`` or else the streaming interface will throw an error.

Start streaming#

[18]:
samples = malaya_speech.streaming.torchaudio.stream(filename,
                                                    vad_model = p_vad,
                                                    asr_model = p_asr,
                                                    classification_model = p_classification,
                                                    postfilter_model = p_postfilter,
                                                    segment_length = 320,
                                                    realtime_print = True,
                                                    streaming_max_length = 360)
dua ribu dua puluh satu (speaker 0) berbanding dengan suku suku sebelumnya (speaker 0) trend pemulihan yang berterusan ini adalah bukti jelas (speaker 0) bahawa dasar dasar kerajaan telah membuahkan hasil (speaker 0) walaupun dalam keadaan yang amat mencabar (speaker 0) perkembangan ini (speaker 0) disokong oleh belanjawan dua ribu dua puluh satu (speaker 0) serta pakej pakej rangsangan dan bantuan kerajaan (speaker 0) pasaran kewangan (speaker 0) dan juga modal kita menunjukkan daya tahan yang baik (speaker 0) pada suku kedua (speaker 0) dua ribu dua puluh satu (speaker 0) melangkah ke hadapan (speaker 0) dengan pelaksanaan pelan pemulihan negara (speaker 0) dan peningkatan program imunisasi kobis babas kebangsaan (speaker 0) ekonomi malaysia dijangka akan beransur pulih (speaker 0) sasaran lima puluh peratus populasi dewasa negara (speaker 0) divaksinasi sepenuhnya pada akhir ogos (speaker 0) akan membolehkan kita membuka semula kegiatan ekonomi (speaker 0) dan sosial (speaker 0) secara lebih meluas untuk memacu pemulihan ekonomi negara (speaker 0) astrolibilife (speaker 0) where will here this nation together (speaker 0) and bring back it s clorry (speaker 0) namun saya berasa agak sedih (speaker 0) dan dukacita (speaker 0) dengan perkembangan politik yang sedang berlaku mutakhir ini (speaker 0) hari ini di hadapan saudara dan saudari semua (speaker 0) saya ingin bercakap secara jujur (speaker 0) sebagai seorang manusia (speaker 0) saya tentunya tidak terhindar daripada kelemahan (speaker 0) dan kekurangan (speaker 0) apa lagi dalam keadaan saya sebagai perdana menteri (speaker 0) yang memikul suatu tanggungjawab berat (speaker 0) untuk mengurus pandemik yang luar biasa ini (speaker 0) sejak lebih setahun yang lalu (speaker 0) pastinya saya memerlukan sokongan (speaker 0) dan juga saya memerlukan dokongan daripada rakan rakan saya dalam kabinet (speaker 0) pimpinan kerajaan (speaker 0) negeri (speaker 0) pegawai pegawai kerajaan fran liners (speaker 0) dan rakyat seluruhnya untuk membolehkan saya melaksanakan tanggungjawab (speaker 0) membawa negara ini keluar daripada krisis (speaker 0) tidak kurang pentingnya ialah sokongan (speaker 0) rakan rakan ahli parlimen (speaker 0) dalam kerajaan perikatan nasional yang mana (speaker 0) dengan sokongan merekalah (speaker 0) saya berada di sini pada hari ini (speaker 0) keabsahan saya sebagai perdana menteri (speaker 0) ditentukan oleh sokongan majoriti ahli ahli parlimen (speaker 0) namun malangnya (speaker 0) dalam keadaan saya dan rakan rakan dalam kabinet berhempas pulas (speaker 0) kepada saya (speaker 0) ini (speaker 1) tentang keabsahan saya sebagai perdana menteri (speaker 0) dalam keadaan ini saya mempunyai dua pilihan (speaker 0) menurut (speaker 0) perlembagaan persekutuan (speaker 0) berkenaan kebawah duli yang maha mulia (speaker 0) seri paduka baginda yang di pertuan agong untuk membubarkan parlimen (speaker 0) dan mengadakan pilihanraya (speaker 0) atau meletak jawatan (speaker 0) pilihan saya yang paling mudah ialah meletak jawatan (speaker 0) jika saya mengambil keputusan ini maka selesailah urusan saya (speaker 0) dan terserahlah (speaker 0) kepada kebijaksanaan ke bawah duli yang maha mulia seri paduka baginda yang di pertuan agong (speaker 0) menurut perkara empat pertiga dua perlembagaan persekutuan (speaker 0) kebawah duli yang maha mulia tuanku boleh melantik seorang perdana menteri (speaker 0) dari kalangan ahli dewan rakyat (speaker 0) yang pada hematnya mungkin mendapat kepercayaan majoriti (speaker 0) ahli dewan rakyat (speaker 0) saya patuh pada perlembagaan (speaker 0) dan akan mengambil jalan (speaker 0) yang terhormat (speaker 0) untuk menyelesaikan kemelut politik yang sedang berlaku ini (speaker 0) namun (speaker 0) saya ulangi sehingga saat ini tiada seorang pun (speaker 0) ahli dewan rakyat lain (speaker 0) yang dapat membuktikan dia mendapat sokongan majoriti (speaker 0) untuk membolehkan kebawah duli yang maha mulia seri paduka baginda yang tuan agong melantik (speaker 0) perdana menteri yang baru (speaker 0) jika saya meletak jawatan pada masa ini saudara saudari sekelian (speaker 0) bukan saya seorang saja yang berhenti (speaker 0) untuk menjadi perdana menteri (speaker 0) menurut perlembagaan persekutuan saya hendaklah meletak jawatan seluruh (speaker 0) ini bermakna kerajaan perikatan nasional yang mentadbir negara (speaker 0) pada masa itu akan jatuh (speaker 0) saya memikirkan dalam keadaan tiada seorang pun (speaker 0) ahli dewan rakyat lain yang mendapat sokongan majoriti pada masa ini (speaker 0) perdana menteri yang baru tidak boleh dilantik menurut perlembagaan (speaker 0) jadi apabila perdana menteri tidak boleh dilantik maka kabinet pun tidak boleh dilantik (speaker 0) dan kerajaan baru tidak dapat (speaker 0) apa akan jadi kepada negara kita (speaker 0) sekiranya krisis politik ini berlarutan (speaker 0) dan kerajaan baru tidak dapat dibentuk dalam kadar yang segera (speaker 0) kerajaan mana yang akan memastikan (speaker 0) sebagai contoh program vaksinasi (speaker 0) berjalan lancar (speaker 0) mengikut jadual (speaker 0) sedangkan tempoh dua bulan akan datang adalah amat genting (speaker 0) jika semua perancangan kerajaan dapat dilaksanakan seperti yang dijadualkan (speaker 0) kita akan mencapai imuniti kelompok (speaker 0) pada bulan oktober insyaallah (speaker 0) sekiranya terganggu (speaker 0) dengan kamera politik yang tidak berkesudahan (speaker 0) dan kerajaan yang sah (speaker 0) maka sasaran imuniti kelompok tidak akan dapat dicapai (speaker 0) dan nyawa rakyat (speaker 0) akan terus berada (speaker 0) dalam bahaya (speaker 0) justeru saya telah pun meruni (speaker 0) rakan rakan saya di dalam kabinet dan pimpinan parti parti (speaker 0)
[19]:
import IPython.display as ipd
[20]:
len(samples)
[20]:
112
[21]:
samples[0]
[21]:
{'wav_data': array([ 0.        ,  0.        ,  0.        , ..., -0.00017348,
        -0.00051391, -0.00028344], dtype=float32),
 'start': 0.0,
 'asr_model': 'dua ribu dua puluh satu',
 'classification_model': 'speaker 0',
 'end': 1.88}
[22]:
ipd.Audio(samples[0]['wav_data'], rate = 16000)
[22]:

Save to SRT#

You can load SRT file using VLC or something like that, malaya_speech.utils.io.write_srt required list of dictionary with {start, end, text} keys.

[23]:
transcript = []
for s in samples:
    transcript.append({
        'start': s['start'],
        'end': s['end'],
        'text': f"{s['asr_model']} ({s['classification_model']})"
    })

transcript[:2]
[23]:
[{'start': 0.0, 'end': 1.88, 'text': 'dua ribu dua puluh satu (speaker 0)'},
 {'start': 2.64,
  'end': 5.48,
  'text': 'berbanding dengan suku suku sebelumnya (speaker 0)'}]
[24]:
from malaya_speech.utils.io import write_srt

with open('muhyiddin-perutusan.srt', 'w') as fopen:
    write_srt(transcript, fopen)

You can download the srt file at malaya-speech/example/youtube-asr-diarization-torchaudio-srt/muhyiddin-perutusan.srt

[25]:
!mv muhyiddin-perutusan.srt example/youtube-asr-diarization-torchaudio-srt
[ ]: