كيفية استخدام Openais Whisper لنسخ وملفات الصوت
Whisper هو نظام التعرف على الكلام على أحدث طراز من Openai تم تدريبه على 680،000 ساعة من البيانات المتعددة اللغات التي تم جمعها من الويب التي تم جمعها من الويب. تؤدي مجموعة البيانات الكبيرة والمتنوعة هذه إلى تحسين المتانة في لهجات وضوضاء الخلفية واللغة التقنية. بالإضافة إلى ذلك ، فإنه يتيح النسخ بلغات متعددة ، وكذلك ترجمة من تلك اللغات إلى اللغة الإنجليزية. أصدرت Openai النماذج والرمز لتكون بمثابة أساس لبناء تطبيقات مفيدة تستفيد من التعرف على الكلام.
على الرغم من ذلك ، لا يمكن أن يخبرك أحدهما السلبي الكبير من الهامس من يتحدث في محادثة. هذه مشكلة عند تحليل المحادثات. هذا هو المكان الذي تأتي فيه الإسهال. مذكرات هي عملية تحديد من يتحدث في محادثة.
في هذا البرنامج التعليمي ، سوف تتعلم كيفية التعرف على مكبرات الصوت ، ثم تطابقهم مع نسخ الهمس. سوف نستخدم pyannote-audio لإنجاز هذا. لنبدأ!
أولاً ، نحتاج إلى إعداد ملف الصوت. سوف نستخدم أول 20 دقيقة من بودكاست Lex Fridmans مع تنزيل Yann. لتنزيل الفيديو واستخراج الصوت ، سنستخدم حزمة yt-dlp .
! pip install -U yt-dlpسنحتاج أيضًا إلى تثبيت FFMPEG
! wget -O - -q https://github.com/yt-dlp/FFmpeg-Builds/releases/download/latest/ffmpeg-master-latest-linux64-gpl.tar.xz | xz -qdc | tar -xالآن يمكننا القيام بالتنزيل الفعلي والاستخراج الصوتي عبر سطر الأوامر.
! yt-dlp -xv --ffmpeg-location ffmpeg-master-latest-linux64-gpl/bin --audio-format wav -o download.wav -- https://youtu.be/SGzMElJ11Cc الآن لدينا ملف download.wav في دليل العمل الخاص بنا. دعنا نقطع أول 20 دقيقة من الصوت. يمكننا استخدام حزمة Pydub لهذا مع بضعة أسطر من التعليمات البرمجية.
! pip install pydub from pydub import AudioSegment
t1 = 0 * 1000 # works in milliseconds
t2 = 20 * 60 * 1000
newAudio = AudioSegment . from_wav ( "download.wav" )
a = newAudio [ t1 : t2 ]
a . export ( "audio.wav" , format = "wav" ) audio.wav الآن أول 20 دقيقة من ملف الصوت.
pyannote.audio هي مجموعة أدوات مفتوحة المصدر مكتوبة في Python لمقاطع مذكرات المتحدث. استنادًا إلى إطار التعلم الآلي لشركة Pytorch ، يوفر مجموعة من اللبنات العصبية القابلة للتدريب التي يمكن دمجها وتحسينها بشكل مشترك لبناء خطوط أنابيب مذكرات السماعة. يأتي pyannote.audio أيضًا مع نماذج وخطوط أنابيب تُغطي مجموعة واسعة من المجالات للكشف عن النشاط الصوتي ، تجزئة السماعات ، الكشف عن الكلام المتداخلة ، تضمين المتحدثين في الوصول إلى أحدث الأداء لمعظمها.
تثبيت Pyannote وتشغيله على صوت الفيديو لإنشاء التهوية.
! pip install pyannote.audio from pyannote . audio import Pipeline
pipeline = Pipeline . from_pretrained ( 'pyannote/speaker-diarization' ) DEMO_FILE = { 'uri' : 'blabal' , 'audio' : 'audio.wav' }
dz = pipeline ( DEMO_FILE )
with open ( "diarization.txt" , "w" ) as text_file :
text_file . write ( str ( dz ))دعنا نطبع هذا لترى كيف يبدو.
print(*list(dz.itertracks(yield_label = True))[:10], sep="n")
الإخراج:
(<Segment(2.03344, 36.8128)>, 0, 'SPEAKER_00')
(<Segment(38.1122, 51.3759)>, 0, 'SPEAKER_00')
(<Segment(51.8653, 90.2053)>, 1, 'SPEAKER_01')
(<Segment(91.2853, 92.9391)>, 1, 'SPEAKER_01')
(<Segment(94.8628, 116.497)>, 0, 'SPEAKER_00')
(<Segment(116.497, 124.124)>, 1, 'SPEAKER_01')
(<Segment(124.192, 151.597)>, 1, 'SPEAKER_01')
(<Segment(152.018, 179.12)>, 1, 'SPEAKER_01')
(<Segment(180.318, 194.037)>, 1, 'SPEAKER_01')
(<Segment(195.016, 207.385)>, 0, 'SPEAKER_00')
هذا يبدو جيدًا بالفعل ، لكن دعنا ننظف البيانات قليلاً:
def millisec ( timeStr ):
spl = timeStr . split ( ":" )
s = ( int )(( int ( spl [ 0 ]) * 60 * 60 + int ( spl [ 1 ]) * 60 + float ( spl [ 2 ]) ) * 1000 )
return s
import re
dz = open ( 'diarization.txt' ). read (). splitlines ()
dzList = []
for l in dz :
start , end = tuple ( re . findall ( '[0-9]+:[0-9]+:[0-9]+.[0-9]+' , string = l ))
start = millisec ( start ) - spacermilli
end = millisec ( end ) - spacermilli
lex = not re . findall ( 'SPEAKER_01' , string = l )
dzList . append ([ start , end , lex ])
print ( * dzList [: 10 ], sep = ' n ' ) [33, 34812, True]
[36112, 49375, True]
[49865, 88205, False]
[89285, 90939, False]
[92862, 114496, True]
[114496, 122124, False]
[122191, 149596, False]
[150018, 177119, False]
[178317, 192037, False]
[193015, 205385, True]
الآن لدينا بيانات الإسهال في قائمة. الرقمين الأولين هما وقت البدء والنهاية لقطاع السماعة بالميلي ثانية. الرقم الثالث هو منطقية تخبرنا إذا كان المتحدث ليكس أم لا.
بعد ذلك ، سنقوم بتوصيل الخرائط الصوتية وفقًا للمذكرات ، مع فاصل كحدد.
from pydub import AudioSegment
import re
sounds = spacer
segments = []
dz = open ( 'diarization.txt' ). read (). splitlines ()
for l in dz :
start , end = tuple ( re . findall ( '[0-9]+:[0-9]+:[0-9]+.[0-9]+' , string = l ))
start = int ( millisec ( start )) #milliseconds
end = int ( millisec ( end )) #milliseconds
segments . append ( len ( sounds ))
sounds = sounds . append ( audio [ start : end ], crossfade = 0 )
sounds = sounds . append ( spacer , crossfade = 0 )
sounds . export ( "dz.wav" , format = "wav" ) #Exports to a wav file in the current path. print ( segments [: 8 ])[2000, 38779, 54042, 94382, 98036, 121670, 131297, 160702]بعد ذلك ، سوف نستخدم Whisper لنسخ الأجزاء المختلفة من ملف الصوت. هام: هناك نسخة تعارض مع pyannote.audio مما يؤدي إلى خطأ. حلنا هو تشغيل pyannote أولاً ثم يهمس. يمكنك تجاهل الخطأ بأمان.
تثبيت فتح الذكاء الاصطناعي.
! pip install git+https://github.com/openai/whisper.git تشغيل Open AI Whisper على ملف الصوت المعد. يكتب النسخ في ملف. يمكنك ضبط حجم النموذج لاحتياجاتك. يمكنك العثور على جميع الطرز على بطاقة النموذج على Github.
! whisper dz.wav --language en --model base [00:00.000 --> 00:04.720] The following is a conversation with Yann LeCun,
[00:04.720 --> 00:06.560] his second time on the podcast.
[00:06.560 --> 00:11.160] He is the chief AI scientist at Meta, formerly Facebook,
[00:11.160 --> 00:15.040] professor at NYU, touring award winner,
[00:15.040 --> 00:17.600] one of the seminal figures in the history
[00:17.600 --> 00:20.460] of machine learning and artificial intelligence,
...
من أجل العمل مع ملفات .vtt ، نحتاج إلى تثبيت مكتبة WebVTT-PY.
! pip install -U webvtt-pyلنلقي نظرة على البيانات:
import webvtt
captions = [[( int )( millisec ( caption . start )), ( int )( millisec ( caption . end )), caption . text ] for caption in webvtt . read ( 'dz.wav.vtt' )]
print ( * captions [: 8 ], sep = ' n ' ) [0, 4720, 'The following is a conversation with Yann LeCun,']
[4720, 6560, 'his second time on the podcast.']
[6560, 11160, 'He is the chief AI scientist at Meta, formerly Facebook,']
[11160, 15040, 'professor at NYU, touring award winner,']
[15040, 17600, 'one of the seminal figures in the history']
[17600, 20460, 'of machine learning and artificial intelligence,']
[20460, 23940, 'and someone who is brilliant and opinionated']
[23940, 25400, 'in the best kind of way,']
...
بعد ذلك ، سنطابق كل خط نسخ مع بعض التهوية ، وعرض كل شيء عن طريق إنشاء ملف HTML. للحصول على التوقيت الصحيح ، يجب أن نعتني بالأجزاء في الصوت الأصلي والتي لم تكن في قطاع مذكرات. نقوم بإلحاق DIV جديد لكل قطاع في الصوت لدينا.
# we need this fore our HTML file (basicly just some styling)
preS = '<!DOCTYPE html>n<html lang="en">n <head>n <meta charset="UTF-8">n <meta name="viewport" content="width=device-width, initial-scale=1.0">n <meta http-equiv="X-UA-Compatible" content="ie=edge">n <title>Lexicap</title>n <style>n body {n font-family: sans-serif;n font-size: 18px;n color: #111;n padding: 0 0 1em 0;n }n .l {n color: #050;n }n .s {n display: inline-block;n }n .e {n display: inline-block;n }n .t {n display: inline-block;n }n #player {nttposition: sticky;ntttop: 20px;nttfloat: right;nt}n </style>n </head>n <body>n <h2>Yann LeCun: Dark Matter of Intelligence and Self-Supervised Learning | Lex Fridman Podcast #258</h2>n <div id="player"></div>n <script>n var tag = document.createElement('script');n tag.src = "https://www.youtube.com/iframe_api";n var firstScriptTag = document.getElementsByTagName('script')[0];n firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);n var player;n function onYouTubeIframeAPIReady() {n player = new YT.Player('player', {n height: '210',n width: '340',n videoId: 'SGzMElJ11Cc',n });n }n function setCurrentTime(timepoint) {n player.seekTo(timepoint);n player.playVideo();n }n </script><br>n'
postS = 't</body>n</html>'
from datetime import timedelta
html = list(preS)
for i in range(len(segments)):
idx = 0
for idx in range(len(captions)):
if captions[idx][0] >= (segments[i] - spacermilli):
break;
while (idx < (len(captions))) and ((i == len(segments) - 1) or (captions[idx][1] < segments[i+1])):
c = captions[idx]
start = dzList[i][0] + (c[0] -segments[i])
if start < 0:
start = 0
idx += 1
start = start / 1000.0
startStr = '{0:02d}:{1:02d}:{2:02.2f}'.format((int)(start // 3600),
(int)(start % 3600 // 60),
start % 60)
html.append('ttt<div class="c">n')
html.append(f'tttt<a class="l" href="#{startStr}" id="{startStr}">link</a> |n')
html.append(f'tttt<div class="s"><a href="javascript:void(0);" onclick=setCurrentTime({int(start)})>{startStr}</a></div>n')
html.append(f'tttt<div class="t">{"[Lex]" if dzList[i][2] else "[Yann]"} {c[2]}</div>n')
html.append('ttt</div>nn')
html.append(postS)
s = "".join(html)
with open("lexicap.html", "w") as text_file:
text_file.write(s)
print(s)
على Discord Lablab ، نناقش هذا الريبو والعديد من الموضوعات الأخرى المتعلقة بالذكاء الاصطناعي! الخروج من حدث Hackathons الذكاء الاصطناعي القادم