بسیاری از افراد در پروژه‌های گوناگونی که با «زبان برنامه‌نویسی پایتون» (Python Programming Language) انجام می‌دهند نیاز به «بازشناسی گفتار» (Speech Recognition) دارند. این کار هرچند در ظاهر بسیار پیچیده و دشوار به نظر می‌رسد، ولی در عمل ساده‌تر از آن است. پروژه‌های بسیار موفقی که در آن‌ها از تشخیص صدا استفاده شده مانند «آمازون الکسا» (Amazon Alexa) اثبات کرده‌اند که وجود درجاتی از پشتیبانی گفتار در فناوری‌های لوازم خانگی، جنبه‌ای حیاتی برای خانه‌ها و شهرهای هوشمند آینده (در حال وقوع ) دارد. به کارگیری بازشناسی گفتار در برنامه‌های کاربردی پایتون، سطحی از تعامل و دسترسی‌پذیری را فراهم می‌کند که فناوری‌های کمی می‌توانند با آن تطبیق پیدا کنند.

بهبود دسترسی‌پذیری به تنهایی ارزش در نظر گرفته شدن را دارد. بازشناسی گفتار به سالمندان و افرادی که دچار اختلالات جسمانی و یا بینایی هستند این امکان را می‌دهد تا با محصولات و خدمات به شیوه‌ای سریع و طبیعی تعامل برقرار کنند، بدون آنکه به «رابط کاربری گرافیکی» (Graphical User Interface) نیازی باشد. بهتر از همه اینکه، استفاده از بازشناسی گفتار (speech recognition) در پروژه‌های پایتون واقعا کار آسانی است. در این راهنما انجام این کار آموزش داده می‌شود و مخاطبان چگونگی انجام کارهای زیر را می‌آموزند:

  • بازشناسی گفتار چگونه کار می‌کند.
  • چه «بسته‌هایی» (packages) در PyPI موجود هستند.
  • چگونگه می‌توان بسته «SpeechRecognition» – که یک کتابخانه پایتون برای بازشناسی گفتار با ویژگی‌های کامل و کاربری آسان است را نصب و استفاده کرد.

در پایان، آنچه آموزش داده شده در یک بازی «Guess the Word» ساده اعمال می‌شود تا مخاطبان به خوبی با چگونگی در کنار هم قرار دادن کلیه این موارد آشنا شوند.

بازشناسی گفتار چگونه کار می‌کند؟

پیش از آنکه به چگونگی انجام بازشناسی گفتار در پایتون پرداخته شود، نگاهی به مفهوم و چگونگی بازشناسی گفتار در حالت کلی انداخته خواهد شد. قطعا بررسی کلی در این حوزه در چندین جلد کتاب می‌گنجد، بنابراین در این مطلب جزئیات فنی مورد بررسی قرار نمی‌گیرند. در حقیقت، این بخش پیش‌نیاز سایر بخش‌های این راهنما نیست (هرچند مطالعه آن به شدت توصیه می‌شود).

بازشناسی گفتار ریشه در پژوهش‌های انجام شده در «آزمایشگاه‌های بِل» (Bell Labs) در اوایل ۱۹۵۰ دارد. سیستم‌های اولیه محدود به تک سخنران و واژگان محدودی بودند. سیستم‌های بازشناسی گفتار مدرن، راهی طولانی را پس از همتایان باستانی خود طی کرده‌اند تا به نقطه کنونی برسند. این سیستم‌ها می‌توانند گفتار را از چندین سخنران تشخیص دهند و دارای دایره لغات گسترده‌ای در زبان‌های متعدد هستند. اولین مولفه بازشناسی گفتار قطعا «گفتار» است. گفتار باید از صدای فیزیکی با میکروفون به یک سیگنال الکتریکی و سپس با یک «مبدل آنالوگ به دیجیتال» به داده دیجیتال تبدیل شود. پس از دیجیتال شدن گفتار، چندین مدل برای «رونویسی» (transcribe) صدا به متن وجود دارد.

تشخیص گفتار
رونویسی گفتار به متن

اغلب سیستم‌های بازشناسی گفتار مدرن بر چیزی که «زنجیره پنهان مارکوف» (Hidden Markov Model | HMM) نامیده می‌شود تکیه دارند. این رویکرد بر این فرض استوار است که سیگنال گفتار، هنگامی که در زمان‌بندی‌های (مقیاس‌های زمانی) به اندازه کافی کوچک نمایش داده شود (مثلا ده میلی ثانیه)، می‌تواند به عنوان یک «فرآیند مانا» (Stationary Process) در نظر گرفته شود. فرآیند مانا، فرآیندی است که در آن مشخصه‌های آماری در طول زمان تغییر نمی‌کنند.

در یک زنجیره پنهان مارکوف متداول، سگینال گفتار به قطعات ده میلی ثانیه‌ای تقسیم می‌شود. طیف قدرت هر قطعه، که اساسا یک بخش از قدرت سیگنال به عنوان تابع فرکانس است، به برداری از اعداد حقیقی که با عنوان «ضرایب کپسترال» (Cepstral Coefficients) شناخته شده‌اند نگاشت می‌شود. ابعاد این بردار معمولا کم و گاهی به کمی ۱۰ است، اما در سیستم‌های دقیق‌تر امکان دارد ابعادی بالغ بر ۳۲ یا بیشتر نیز داشته باشند. خروجی نهایی زنجیره پنهان مارکوف (HMM) یک توالی از این بردارها است.

برای «رمزگشایی» گفتار به متن، گروهی از بردارها با یک یا تعداد بیشتری «واج» (phoneme) – واحد پایه‌ای گفتار – تطبیق پیدا می‌کنند. این محاسبات نیازمند آموزش است، زیر صدای یک واج از سخنرانی به سخنران دیگر و حتی از یک نطق به نطق دیگر برای یک سخنران واحد متفاوت است. سپس، یک الگوریتم ویژه برای تعیین محتمل‌ترین کلمه (یا کلماتی) که توالی داده شده از واج‌ها را تولید می‌کند اعمال می‌شود.

ممکن است کسی تصور کند انجام چنین فرآیندی به لحاظ محاسباتی بسیار پرهزینه است. در بسیاری از سیستم‌های بازشناسی گفتار مدرن، «شبکه‌های عصبی» (Neural Networks) برای ساده کردن سیگنال‌های بازشناسی گفتار با استفاده از روش‌هایی برای «تبدیل ویژگی» (Feature Transformation) و «کاهش ابعاد» (Dimensionality Reduction) پیش از تشخیص زنجیره پنهان مارکوف مورد استفاده قرار می‌گیرند. همچنین، «تشخیص‌دهنده‌های فعالیت صدا» (Voice Activity Detectors | VAD) برای کاهش یک سیگنال صدا صرفا به بخش‌هایی که احتمال دارد دربرگیرنده گفتار باشند مورد استفاده قرار می‌گیرد.

خوشبختانه، یک برنامه‌نویس پایتون نیازی به نگرانی پیرامون هیچ یک از موارد بیان شده ندارد، زیرا سرویس‌های تشخیص صدای بسیاری برای استفاده آنلاین از طریق یک «رابط برنامه‌نویسی نرم‌افزارهای کاربردی» (Application Programming Interface | API) در دسترس هستند. بسیاری از این سرویس‌ها، «کیت توسعه نرم‌افزار» (Software Development Kit | SDK) پایتون ارائه می‌کنند.

انتخاب بسته بازشناسی گفتار پایتون

بسته‌های کاربردی برای بازشناسی گفتار در PyPI وجود دارد. برخی از این بسته‌ها در ادامه بیان شده‌اند.

  • apiai (+)
  • assemblyai (+)
  • google-cloud-speech (+)
  • pocketsphinx (+)
  • SpeechRecognition (+)
  • watson-developer-cloud (+)
  • wit (+)

برخی از این بسته‌ها – مانند wit و apiai – ویژگی‌های توکاری مانند «پردازش زبان طبیعی» (Natural Language Processing) برای تعیین نیت سخنران ارائه می‌کنند که از بازشناسی گفتار پایه‌ای کاری فراتر است. دیگر بسته‌ها، مانند google-cloud-speech، صرفا روی تبدیل گفتار به متن تمرکز می‌کنند. اما «SpeechRecognition» بسته‌ای محسوب می‌شود که سهولت کار با آن مثال زدنی و فوق‌العاده به شمار می‌آید. بازشناسی گفتار نیازمند ورودی صوتی است و بسته SpeechRecognition بازیابی این ورودی را بسیار آسان می‌کند. از سوی دیگر، به جای آنکه نیاز به ساخت اسکریپتی برای دسترسی به میکروفون و پردازش فایل صوتی از پایه باشد، SpeechRecognition این کارها را تنها در چند دقیقه انجام می‌دهد.

کتابخانه SpeechRecognition مانند پوششی برای چندین «رابط برنامه‌نویسی نرم‌افزارهای کاربردی» (API) محبوب عمل کرده و بنابراین بسیار انعطاف‌پذیر است. یکی از این موارد «Google Web Speech API» است که از کلید API پیش‌فرض که در کتابخانه SpeechRecognition هاردکد (hard-coded) شده، پشتیبانی می‌کند. این بدین معنا است که کاربر بدون نیاز به ثبت‌نام برای این سرویس می‌تواند از آن استفاده کند.

کتابخانه SpeechRecognition پایتون برای تشخیص گفتار
کتابخانه SpeechRecognition پایتون برای بازشناسی گفتار

انعطاف‌پذیری و سهولت کاربری بسته SpeechRecognition آن را به یک انتخاب فوق‌العاده برای هر پروژه پایتونی مبدل ساخته است. اگرچه، پشتیبانی از کلیه ویژگی‌های API‌هایی که این بسته پوششی برای آن‌ها است، تضمین نمی‌شود. کاربر باید زمانی را اختصاص داده و با جست‌و‌جو پیرامون گزینه‌های موجود اطمینان حاصل کند که بسته SpeechRecognition در مساله مورد نظر کاربر کار می‌کند یا خیر. به نظر می‌رسد آنچه پیش‌تر بیان شد توانسته در راستای استفاده از بسته SpeechRecognition متقاعد کننده واقع شود، بنابراین گام بعدی روش نصب این بسته خواهد بود.

نصب SpeechRecognition

SpeechRecognition با پایتون نسخه ۲.۶، ۲.۷ و ۳.۳ به بالا سازگار است اما نیاز به یک سری مراحل نصب افزوده برای پایتون ۲ دارد. در این راهنما، فرض می‌شود که کاربر از پایتون ۳.۳ به بالا استفاده می‌کند. بسته SpeechRecognition را می‌توان از ترمینال با pip نصب کرد.

پس از انجام نصب، باید فرآیند نصب را با باز کردن یک «سشن» (session) مفسر و تایپ دستورات زیر تایید کرد.

تذکر: کاربران گوناگون ممکن است از نسخه‌های متفاوتی از پایتون استفاده کنند. در هنگام نگارش این راهنما، آخرین نسخه موجود ۳.۸.۱ بوده است.

سشن موجود باید باز نگه داشته شود زیرا به زودی کارهای زیادی باید در آن انجام شود. SpeechRecognition به صورت «out of the box» (در زمینه نرم‌افزار این عبارت به معنای ویژگی یا کارکردی است که بلافاصله پس از نصب بدون پیکربندی یا دستکاری یا حتی بدون نصب کار می‌کند، همچنین به معنای آن است که برای کلیه کاربران به طور پیش‌فرض وجود دارد و نیاز به انجام کارهای اضافی برای استفاده یا پیکربندی این نرم‌افزارها یا فایل‌ها وجود ندارد.) با فایل‌های صوتی موجود کار می‌کند. شایان توجه است که به بسته PyAudio برای ثبت ورودی میکروفون نیاز وجود دارد. در ادامه، لیست «وابستگی‌هایی» (dependencies) که نیاز خواهند شد بیان می‌شوند. اکنون باید به اکتشاف در بسته نصب شده پرداخت.

کلاس Recognizer

همه کارهای جادویی بسته SpeechRecognition با کلاس Recognizer به وقوع می‌پیوندد. البته، هدف اولیه نمونه Recognizer بازشناسی گفتار است. هر «نمونه» (instance) با تنظیمات و کارکردهای متنوعی برای بازشناسی گفتار از یک منبع صوتی همراه است. ساخت یک نمونه Recognizer آسان محسوب می‌شود. در این راستا کافی است در سشن مفسر موجود کد زیر وارد شود.

هر نمونه Recognizer دارای هفت متد برای بازشناسی گفتار از منبع صوتی با استفاده از API‌های متنوع است.

  • (+) recognize_bing(): Microsoft Bing Speech
  • (+) recognize_google(): Google Web Speech API
  • (+) recognize_google_cloud(): Google Cloud Speech – requires installation of the google-cloud-speech package
  • (+) recognize_houndify(): Houndify by SoundHound
  • (+) recognize_ibm(): IBM Speech to Text
  • (+) recognize_sphinx(): CMU Sphinx – requires installing PocketSphinx
  • (+) recognize_wit(): Wit.ai

در میان هفت مورد بیان شده در بالا، تنها ()recognize_sphinx به صورت آفلاین با موتور CMU Sphinx کار می‌کند و شش گزینه دیگر نیاز به اتصال اینترنت دارند. بحث کامل پیرامون ویژگی‌ها و مزایای هر API فراتر از موضوع این راهنما است. با توجه به آنکه SpeechRecognition با کلید API پیش‌فرض Google Web Speech API همراه است، می‌توان کار با آن را در لحظه آغاز کرد. به همین دلیل، از Web Speech API در این راهنما استفاده می‌شود. شش API دیگر نیاز به احراز هویت با یک کلید API یا نام‌کاربری/گذرواژه دارند. برای کسب جزئیات بیشتر، باید به مستندات SpeechRecognition رجوع کرد (+).

هشدار: کلید پیش‌فرض فراهم شده توسط SpeechRecognition به منظور تست است و امکان دارد گوگل هر زمانی آن را باطل کند. بنابراین استفاده از Google Web Speech API در تولید ایده خوبی نیست. حتی با یک کلید API معتبر نیز کاربر به تنها ۵۰ درخواست در روز محدود می‌شود و هیچ راهکاری برای افزایش این سهمیه وجود ندارد. خوشبختانه، رابط SpeechRecognition  تقریبا در کلیه API‌ها یکسان است، بنابراین استفاده از آنچه در این راهنما ارائه شده در پروژه‌های جهان واقعی آسان خواهد بود.

هر متد ()*ـrecognize در صورتی که API در دسترس نباشد، یک استثنای speech_recognition.RequestError راه‌اندازی می‌کند. برای ()recognize_sphinx این مساله در نتیجه نصب ناموجود، خراب یا ناسازگار Sphinx به وقوع می‌پیوندد. برای شش متد دیگر، در صورتی که به محدودیت API رسیده شود، سرور در دسترس نباشد و یا اتصال اینترنت وجود نداشته باشد RequestError راه‌اندازی می‌شود. اکنون در سشن مفسر ()recognize_google فراخونی می‌شود.

خروجی کد بالا چیزی شبیه زیر خواهد بود.

Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: recognize_google() missing 1 required positional argument: 'audio_data'

برخی ممکن است حدس زده باشند که چنین اتفاقی به وقوع می‌پیوندد. اما چگونه ممکن است چیزی از هیچی تشخیص داده شود؟ همه هفت متد کلاس ()*ـrecognize نیازمند یک آرگومان audio_data هستند. در هر مورد، audio_data باید نمونه‌ای از کلاس AudioData بسته SpeechRecognition باشد. دو راه برای ساخت یک نمونه AudioData وجود دارد. راه اول، از یک فایل صوتی  و راه دوم صوت ضبط شده توسط یک میکروفون است. کار با فایل‌های صوتی اندکی آسان‌تر است، بنابراین ابتدا این مورد بررسی می‌شود.

کار با فایل‌های صوتی

پیش از ادامه دادن، نیاز به دانلود یک فایل صوتی وجود دارد. فایلی که در اینجا برای آغاز کار استفاده شده، «harvard.wav» (+) است. کاربر باید اطمینان حاصل کند که این فایل در دایرکتوری مشابه با آنچه مفسر پایتون در آن اجرا شده قرار دارد. SpeechRecognition با استفاده از کلاس مفید AudioFile کار با فایل‌های صوتی را آسان می‌سازد. این کلاس قابل مقداردهی اولیه با مسیر یک فایل صوتی و فراهم کردن رابط مدیریت زمینه برای خواندن و کار با محتوای این فایل‌های صوتی است.

نوع فایل‌های پشتیبانی شده

در حال حاضر، بسته SpeechRecognition از فرمت‌های فایل زیر پشتیبانی می‌کند.

  • WAV: باید در فرمت‌های PCM/LPCM باشد.
  • AIFF
  • AIFF-C
  • FLAC: باید در فرمت FLAC محلی باشد. OGG-FLAC پشتیبانی نمی‌شود.

افرادی که در لینوکس‌های برپایه x-86، ویندوز یا macOS کار می‌کنند، باید قادر به کار با فایل‌های FLAC بدون هیچ مشکلی باشند. در دیگر پلتفرم‌ها، نیاز به نصب «انکدر» (Encoder) خاص FLAC و حصول اطمینان از این است که به ابزارهای خط فرمان FLAC  دسترسی وجود دارد. جزئیات بیشتر در این رابطه در اینجا (+) وجود دارد.

استفاده از ()record برای ثبت داده‌ها از یک فایل

کد زیر به منظور پردازش محتوای فایل «harvard.wav» باید در سشن مفسر نوشته شود.

مدیر زمینه فایل را باز کرده و محتوای آن را می‌خواند، سپس داده‌ها را در یک نمونه AudioFile که source نامیده می‌شود ذخیره می‌کند. پس از آن، متد ()record داده‌ها را از کل یک فایل در یک نمونه AudioData ذخیره می‌کند. این مورد را می‌توان با بررسی نوع یک audio تایید کرد.

اکنون می‌توان ()recognize_google را در تلاش برای شناسایی هر گفتاری در فایل صوتی فراخوانی (invoke) کرد.

ممکن است این پرسش در ذهن برخی افراد نقش ببندد که «عبارات موجود در فایل harvard.wav از کجا آمده‌اند؟». این موارد مثال‌هایی از «Harvard Sentences» هستند. این عبارات توسط IEEE در سال ۱۹۶۵ به منظور تست قابلیت بازشناسی گفتار در خطوط تلفن منتشر شدند. این داده‌ها همچنان در تست سلولی و VOIP مورد استفاده قرار می‌گیرند.

Harvard Sentences متشکل از ۷۲ لیست از ده عبارت است. می‌توان رکوردهای رایگان از این عبارات را در وب‌سایت «Open Speech Repository» (+) پیدا کرد. موارد ضبط شده به زبان انگلیسی، چینی ماندارین، فرانسوی و هندی نیز موجود هستند و منبع فوق‌العاده‌ای از موارد رایگان برای ارزیابی کد را فراهم می‌کنند.

ثبت قطعات با offset و duration

پرسشی که امکان دارد در این لحظه برای برخی افراد مطرح شود آن است که اگر نیاز به ثبت یک بخش از گفتار روی فایل باشد چه باید کرد. متد ()record آرگومان کلیدواژه duration را می‌پذیرد که ضبط را پس از تعداد ثانیه‌های مشخص شده‌ای متوقف می‌کند. برای مثال، کد زیر هر گفتاری را در چهار ثانیه اول فایل ثبت می‌کند.

متد ()record، هنگامی که درون یک بلوک with استفاده می‌شود، همیشه در جریان فایل به جلو حرکت می‌کند. این بدین معنا است که اگر یک بار برای ۴ ثانیه فایل ضبط شود و سپس دوباره برای ۴ ثانیه رکورد کردن آغاز شود، بار دوم چهار ثانیه از صوت پس از اولین چهارثانیه بازگردانده می‌شود.

شایان توجه است که audio2 شامل یک بخش از فاز سوم در فایل می‌شود. هنگام تعیین مدت زمان، رکورد کردن ممکن است mid-phrase یا حتی mid-word را متوقف کند که می‌تواند به صحت «رونویسی» (transcription) آسیب برساند. علاوه بر این، برای تعیین طول مدت ثبت، می‌توان به متد ()record با استفاده از آرگومان کلیدواژه offset یک نقطه شروع مشخص داد. این مقدار تعداد ثانیه‌ها از آغاز فایل که باید پیش از آغاز ضبط از آن‌ها چشم‌پوشی (ignore) شود را تعیین می‌کند. برای ثبت صرفا دومین عبارت در فایل، می‌توان با انحراف از ۴ ثانیه و ضبط برای مثلا ۳ ثانیه کار را آغاز کرد.

آرگومان‌های کلیدواژه offset و duration برای بخش‌بندی یک فایل صوتی، اگر کاربر دانش پیشینی از ساختار گفتار در فایل را داشته باشد مفید هستند. اگرچه، استفاده شتاب‌زده از آن‌ها می‌تواند منجر به رونویسی ضعیفی شود. برای مشاهده این اثر، از کد زیر در مفسر می‌توان استفاده کرد.

با آغاز ضبط از ثانیه ۴.۷، بخش «it t» از آغاز عبارت «it takes heat to bring out the odor» از دست می‌رود، بنابراین API فقط «akes heat» را دریافت می‌کند که با «Mesquite» مطابقت یافته است. به طور مشابه، در پایان ضبط «a co» ثبت می‌شود که آغاز سومین عبارت «a cold dip restores health and zest» است. این مورد با استفاده از API با «Aiko» تطبیق یافته.

دلیل دیگری نیز برای دریافت رونویسی اشتباه وجود دارد. «نویز» (Noise)! مثال بالا به این دلیل به خوبی عمل کرده که فایل صوتی به طرز منطقی تمییز است. در جهان واقعی، به جز حالتی که فرد فرصت پردازش فایل صوتی را پیش از داشته باشد، کاربر نمی‌تواند انتظار صوت بدون نویز را داشته باشد.

اثر نویز در بازشناسی گفتار

نویز یک واقعیت در زندگی بشر است. همه رکوردهای صوتی دارای درجاتی از نویز هستند و نویزهای مدیریت نشده می‌توانند صحت برنامه‌های کاربردی بازشناسی گفتار را مخدوش کنند. برای گرفتن احساس اینکه نویز چگونه می‌توان بازشناسی گفتار را متاثر کند، باید فایل «jackhammer.wav» را از اینجا (+) دانلود کرد. همچون همیشه، باید اطمینان حاصل کرد که این فایل در دایرکتوری کار سشن‌های مفسر ذخیره شده است. این فایل حاوی عبارت «the stale smell of old beer lingers» است و در عین حال jackhammer که در پس زمینه با صدای بلند صحبت می‌کنم. در صورت تبدیل این فایل به رونویس چه اتفاقی خواهد افتاد؟

پس چگونه می‌توان با این مشکل مواجه شد؟ یکی از مواردی که می‌توان آن را مورد آزمون قرار داد استفاده از متد ()adjust_for_ambient_noise برای کلاس Recognizer است.

این کار کاربر را یک گام به عبارت واقعی نزدیک‌تر می‌کند، اما همچنان عالی نیست. همچنین، «the» از آغاز عبارت گم شده است. متد ()adjust_for_ambient_noise اول دوم جریان فایل را می‌خواند و تشخیص‌دهنده را برای سطح نویز فایل صوتی کالیبره می‌کند. از این رو، بخشی از جریان پیش از آنکه ()record برای ثبت داده‌ها فراخوانی شود، صرف شده است.

می‌توان «فرم زمانی» (time-frame) را که ()adjust_for_ambient_noise برای تحلیل استفاده می‌کند با آرگومان کلیدی duration تنظیم کرد. این آرگومان یک مقدار عددی را در ثانیه دریافت کرده و به طور پیش‌فرض روی ۱ قرار می‌دهد. در کد زیر تلاش شده این مقدار به ۰.۵ کاهش پیدا کند.

بسیار خب، این کار موجب می‌شود «the» در آغاز عبارت بیاید، اما اکنون باید به مشکلات جدیدی رسیدگی کرد. گاهی این امکان وجود ندارد که اثر نویز را حذف کرد، زیرا سیگنال بسیار نویزی‌تر از آن است که بتوان به شکل موفقیت‌آمیزی با آن س و کله زد. مساله این فایل نیز همین است.

به افرادی که زیاد با این مشکل مواجه می‌شوند توصیه می‌شود به انجام «پیش‌پردازش داده‌ها»  (pre-processing) اهتمام بورزند. این کار را می‌توان با نرم‌افزارهای ویرایش فایل صوتی (+) و یا بسته‌های پایتون (مانند SciPy) که می‌توانند فیلترهایی را به فایل اضافه کنند انجام داد. بحث تخصصی در این زمینه از حوصله این مطلب خارج است و در همین رابطه مطالعه کتاب «الن دونی» (Allen Downey) با نام «Think DSP» (+) توصیه می‌شود. در حال حاضر آگاهی از نویز محیط در فایل صوتی می‌تواند مشکلاتی را ایجاد کند و باید به منظور بیشینه کردن صحت تشخیص صدا به آن‌ها پرداخته شود.

هنگام کار با فایل‌های دارای نویز، مشاهده پاسخ API واقعی مفید خواهد بود. اغلب API‌ها یک رشته JSON باز می‌گردانند که دربرگیرنده رونویس‌های بسیاری است. متد ()recognize_google همیشه محتمل‌ترین رونویس را باز می‌گرداند مگر اینکه کاربر آن را مجبور به ارائه پاسخ کامل کند. می‌توان این کار را با تنظیم آرگومان کلیدواژه show_all برابر با مقدار True در متد ()recognize_google انجام داد.

همانطور که مشهود است، ()recognize_google یک دیکشنری با کلید «alternative» باز می‌گرداند که به لیست رونویس‌های ممکن اشاره می‌کند. ساختار این پاسخ ممکن است از یک API به API دیگر متفاوت باشد و این موضوع برای «اشکال‌زدایی» (debugging) مفید است.

در حال حاضر یک ایده کلی پیرامون مبانی بسته SpeechRecognition شکل گرفت. تاکنون چگونگی ساخت یک نمونه AudioFile از فایل صوتی و استفاده از متد ()record برای ثبت داده‌ها از فایل بیان شد. همچنین، نحوه ثبت قطعات یک فایل با استفاده از آرگومان‌های کلیدواژه offset و duration از ()record و تاثیر مخربی که نویز بر صحت رونویس‌ها دارد تشریح شد. کم کم زمان انجام کارهای جالب فرا رسیده است. با گذر از مرحله رونویسی فایل‌های صوتی استاتیک، در ادامه به انجام پروژه تعاملی با پذیرش ورودی از یک میکروفون پرداخته می‌شود.

کار با میکروفون

برای دسترسی به میکروفون با SpeechRecognizer، باید بسته PyAudio (+) را نصب کرد. برای ادامه، سشن کنونی مفسر را بسته و نصب به صورتی که در زیر تشریح شده انجام می‌شود.

نصب PyAudio

فرآیند نصب PyAudio بسته به سیستم‌عامل متفاوت است.

گنو/لینوکس دبیان

افرادی که از سیستم‌عامل‌های مبتنی بر دبیان (مانند اوبونتو) استفاده می‌کنند، می‌توانند PyAudio را با استفاده از apt به صورت زیر نصب کنند.

پس از نصب، ممکن است هنوز نیاز به اجرای pip install pyaudio باشد، به ویژه اگر کاربر با «محیط مجازی» (Virtual Environment) کار کند.

macOS

برای macOS، ابتدا نیاز به نصب PortAudio با Homebrew و سپس نصب PyAudio با pip است.

ویندوز

در ویندوز می‌توان PyAudio را با pip نصب کرد.

تست نصب

پس از نصب PyAudio، می‌توان نصب را از کنسول تست کرد.

اکنون کاربران باید اطمینان حاصل کنند که میکروفون روشن است و صدای آن بسته نیست. اگر نصب به طور صحیح انجام شده بود، کاربر باید چیزی شبیه آنچه در زیر آمده را مشاهده کند.

اکنون می‌توان با حرف زدن در میکروفون مشاهده کرد که SpeechRecognition چقدر خوب گفتار را رونویس می‌کند.

نکته: کاربرانی که از اوبونتو استفاده و خروجی‌های عجیبی مانند «ALSA lib … Unknown PCM» دریافت می‌کنند، می‌توانند به این صفحه (+) مراجعه کنند. این خروجی‌ها مربوط به بسته ALSA هستند که با اوبونتو نصب شده و ارتباطی با SpeechRecognition و PyAudio ندارد. در حقیقت، این پیام‌ها ممکن است خبر از مشکلی که در «پیکربندی» (configuration) بسته ALSA وجود دارد بدهند، اما بر اساس تجربه به نظر می‌رسد عملکرد کد را تحت تاثیر قرار نمی‌دهند و بیشتر حکم ایجاد مزاحمت دارند.

کلاس Microphone

اکنون باید یک سشن مفسر دیگر را باز کرد و یک نمونه از کلاس recognizer ساخت.

اکنون، به جای استفاده از فایل صوتی به عنوان منبع، از میکروفون پیش‌فرض سیستم استفاده می‌شود. می‌توان به این میکروفون از طریق کلاس Microphone دسترسی داشت.

اگر سیستم هیچ میکروفون پیش‌فرضی ندارد (مثلا در زربری‌پای)، یا کاربر قصد دارد که از میکروفونی غیر از پیش‌فرض سیستم استفاده کند، نیاز به تغیین میکروفون مورد استفاده با دادن اندیس دستگاه است. می‌توان لیست نام میکروفون‌ها را با فراخوانی متد استاتیک ()list_microphone_names از کلاس Microphone دریافت کرد.

توجه به این نکته لازم است که خروجی در سیستم‌های گوناگون امکان دارد با مثال بالا متفاوت باشد. اندیس دستگاه میکروفون، در واقع اندیس نام آن در لیست بازگردانده شده توسط ()list_microphone_names است. برای مثال، در خروجی بالا، برای استفاده از میکروفونی که «front» نامیده می‌شود و اندیس آن «3» است، باید یک نمونه از میکروفون به صورت زیر ساخته شود.

در اغلب پروژه‌ها، کاربر احتمالا از میکروفون پیش‌فرض سیستم استفاده می‌کند.

استفاده از ()listen برای ثبت ورودی‌های میکروفون

اکنون که نمونه Microphone آماده است، زمان ثبت ورودی‌ها فرارسیده. درست مانند کلاس AudioFile ، نمونه Microphone نیز مدیر زمینه محسوب می‌شود. می‌توان ورودی‌ها را با میکروفون با استفاده از متد ()listen از کلاس Recognizer درون بلوک with ثبت کرد. این روش یک منبع صوتی را به عنوان اولین آرگومان خود دریافت کرده و ورودی را از منبع تا زمانی که سکوت تشخیص داده شود دریافت می‌کند.

پس از آنکه بلوک with اجرا شد، کاربر می‌تواند با گفتن «hello» امتحان و یک دقیقه برای اینکه خط مفسر (interpreter prompt) نمایش داده شود صبر کند. هنگامی که «>>>» باز می‌گردد، کاربر آماده بازشناسی گفتار است.

اگر خط مفسر باز نگردد، به احتمال زیاد میکروفون نویز زیادی از محیط دریافت کرده است. می‌توان با استفاده از کلیدهای ترکیبی «Ctrl + C» در فرآیند وقفه ایجاد کرد تا prompt بازگردد. برای مدیریت نویز محیط، نیاز به استفاده از متد ()adjust_for_ambient_noise از کلاس Recognizer است، از آنجا که ورودی از میکروفون کمتر از ورودی از فایل صوتی قابل پیش‌بینی محسوب می‌شود، بهتر است در هر بار استفاده از ورودی میکروفون از روش گفته شده استفاده شود.

پس از اجرای کد بالا، باید یک ثانیه برای ()adjust_for_ambient_noise صبر کرد تا کارش را انجام دهد، سپس مجددا می‌توان در میکروفون «hello» گفت. پس از آن باید صبر کرد تا خط مفسر پیش از آنکه سعی کند گفتار را تشخیص دهد بازگردد. با فراخوانی ()adjust_for_ambient_noise منابع صوتی برای یک ثانیه آنالیز می‌شوند. اگر این زمان به نظر کاربر زیاد است، می‌تواند آن را با آرگومان کلیدواژه duration تنظیم کند.

در مستندات SpeechRecognition پیشنهاد شده که duration کمتر از ۰/۵ ثانیه نباشد. در برخی موارد، ممکن است کاربر تشخیص دهد که طول مدت بیشتر از یک ثانیه نتایج بهتری را تولید می‌کند. حداقل مقداری که کاربر نیاز دارد، بسته به محیط میکروفون است. متاسفانه، این اطلاعات اغلب در طول توسعه ناشناخته هستند. براساس تجربه نویسنده این مطلب، به نظر می‌رسد طول مدت پیش‌فرض برای اغلب کاربردها مناسب باشد.

مدیریت گفتار غیرقابل تشخیص

اکنون باید کد مثال پیشین را در مفسر  نوشته و نویزهای نامفهوم در میکروفون ایجاد شود. در پاسخ باید پیامی شبیه آنچه در زیر آمده داده شود.

صوتی که نمی‌تواند توسط API تشخیص داده شود، منجر به نمایش پیام استثنای UnknownValueError می‌شود. کاربر باید همیشه فراخوانی‌های خود به API را با بلوک try and except پوشش دهد تا این استثناها را مدیریت کند.

تذکر: برای راه‌اندازی بلوک‌های «try and except» جهت مدیریت «استثناها» امکان دارد به تلاشی بیش از آنچه به نظر می‌رسد نیاز باشد. API برای رونویس هرگونه صوتی به شدت تلاش می‌کند. حتی خرخرهای اندک نیز به کلماتی مانند «how» رونویس می‌شوند. سرفه کردن، دست زدن و تپق‌های زبانی همواره استثنا را افزایش می‌دهند.

بازی «Guess the Word» با کد کامل

اکنون که مبانی بازشناسی گفتار با بسته SpeechRecognition به طور کامل بیان شد، از دانش جدید حاصل شده برای نوشن یک بازی که یک کلمه تصادفی را از یک لیست انتخاب می‌کند و به کاربر فرصت سه تلاش برای حدس زدن آن را می‌دهد استفاده می‌شود. اسکریپت کامل این بازی در زیر آمده است.

اکنون، کد بالا به قطعات کوچک شکسته و توضیحات مربوط به هر بخش آن ارائه می‌شود. تابع ()recognize_speech_from_mic نمونه‌های Recognizer و Microphone را به عنوان آرگومان دریافت کرده و یک دیکشنری با سه کلید باز می‌گرداند. اولین کلید، «success»، یک متغیر بولی است که نشان می‌دهد یک درخواست API موفقیت‌آمیز بوده یا نه. دومین کلید، «error»، یا «None» است و یا یک پیام خطا که نشان می‌دهد API در دسترس نیست یا گفتار نامفهوم بوده است. در نهایت، کلید «transcription» شامل رونویس از صوت رکورد شده توسط میکروفون می‌شود. تابع ابتدا بررسی می‌کند که آرگومان‌های recognizer و microphone از نوع صحیحی هستند و در صورتی که یکی و یا هر دوی آن‌ها نامعتبر باشد، TypeError داده می‌شود.

متد ()listen سپس برای رکورد ورودی میکروفون مورد استفاده قرار می‌گیرد.

متد ()adjust_for_ambient_noise برای کالیبره کردن سازمان‌دهنده برای تغییر شرایط نویز هر بار که تابع ()recognize_speech_from_mic فراخوانی می‌شود مورد استفاده قرار می‌گیرد. سپس، ()recognize_google برای رونویس هر گفتاری در رکوردها فراخوانی می‌شود. یک بلوک try…except برای گرفتن استثناهای RequestError و UnknownValueError و مدیریت آن‌ها مورد استفاده قرار می‌گیرد. موفقیت درخواست API، هر گونه پیغام خطایی و گفتار رونویس شده در کلیدهای error ،success و transcription از دیکشنری response ذخیره می‌شوند که با تابع ()recognize_speech_from_mic بازگردانده می‌شود.

می‌توان تابع ()recognize_speech_from_mic را با ذخیره‌سازی اسکریپت بالا در فایلی با نام «guessing_game.py» و اجرای دستوری که در ادامه می‌آید در یک سشن مفسر تست کرد.

خود بازی بسیار ساده است. ابتدا، یک لیست از کلمات، حداکثر تعداد حدس‌های قابل پذیرش، محدودیت prompt به صورت زیر تعیین می‌شود.

سپس، نمونه Recognizer و میکروفون ساخته می‌شوند و کلمه تصادفی از میان کلمات انتخاب می‌شود.

پس از پرینت کردن دستورالعمل‌ها و منتظر ماندن به مدت ۳ ثانیه، یک حلقه for برای مدیریت هر تلاش جهت حدس زدن و انتخاب کلمات استفاده می‌شود. اولین چیز درون حلقه for یک حلقه for دیگر است که کاربر را برای حداکثر زمان PROMPT_LIMIT به تلاش برای حدس زدن برمی‌انگیزد، و تلاش می‌کند که ورودی را هر بار با تابع ()recognize_speech_from_mic تشخیص دهد و دیکشنری بازگردانده شده به متغیر محلی guess را ذخیره کند.

اگر کلید transcription برای guess برابر با None باشد، گفتار کاربر رونویسی می‌شود و حلقه داخلی با break خاتمه پیدا می‌کند. اگر گفتار رونویسی نشود و مقدار کلید success برابر با False شود، خطای API به وقوع می‌پیوندد و حلقه مجددا با break خاتمه پیدا می‌کند. در غیر این صورت، درخواست API موفقیت‌آمیز اما گفتار غیر قابل تشخیص بوده است. به کاربر هشدار داده و حلقه for تکرار خواهد شد و به کاربر شانس دیگری در همان تلاش داده می‌شود.

پس از آنکه حلقه for داخلی متوقف شد، دیکشنری guess از جهت خطاها مورد بررسی قرار می‌گیرد. اگر خطایی به وقوع بپیوندد، پیام خطا نمایش داده می‌شود و حلقه for بیرونی با دستور break متوقف می‌شود که این کار منجر به پایان اجرای برنامه می‌شود.

اگر هیچ خطایی وجود نداشت، رونویس با کلمه‌ای که به طور تصادفی انتخاب شده مقایسه می‌شود. متد ()lower برای اشیای رشته برای حصول اطمینان از تطبیق بهتر کلمه انتخاب شده و حدس مورد استفاده قرار می‌گیرد. API ممکن است سخنرانی تطبیق یافته با کلمه «سیب» را به صورت «apple» یا «Apple» بازگرداند و پاسخ باید به عنوان صحیح در نظر گرفته شود.

اگر حدس صحیح باشد، کاربر پیروز می‌شود و بازی پایان می‌یابد. اگر کاربر اشتباه کرده باشد و تلاشی برای او باقی مانده باشد، حلقه for خارجی تکرار می‌شود و یک حدس جدید بازیابی می‌شود. در غیر این صورت، کاربر بازی را می‌بازد.

هنگام اجرا، خروجی چیزی شبیه زیر خواهد بود.

I'm thinking of one of these words:
apple, banana, grape, orange, mango, lemon
You have 3 tries to guess which one.

Guess 1. Speak!
You said: banana
Incorrect. Try again.

Guess 2. Speak!
You said: lemon
Incorrect. Try again.

Guess 3. Speak!
You said: Orange
Correct! You win!

بازشناسی گفتار در زبان‌های غیر انگلیسی

در این راهنما، بازشناسی گفتار در زبان انگلیسی انجام شد که زبان پیش‌فرض برای متدهای ()*_recognize از بسته SpeechRecognition است. اگرچه، قطعا امکان بازشناسی گفتار در دیگر زبان‌ها وجود دارد و انجام آن ساده خواهد بود. برای بازشناسی گفتار در زبان‌های گوناگون، آرگومان کلیدواژه language از متد ()*_recognize باید روی رشته‌ای از زبان دلخواه قرار بگیرد. اغلب متدها تگ زبان BCP-47، مانند «en-US» برای انگلیسی آمریکایی یا «fr-FR» برای فرانسوی را می‌پذیرند. برای مثال، کد زیر گفتار فرانسوی را در یک فایل صوتی تشخیص می‌دهد.

تنها متدهای زیر آرگومان کلیدواژه language را می‌پذیرند.

  • recognize_bing()
  • recognize_google()
  • recognize_google_cloud()
  • recognize_ibm()
  • recognize_sphinx()

برای آگاهی از اینکه کدام تگ‌های زبانی توسط API مورد استفاده کاربر پشتیبانی می‌شوند، مطالعه مستندات (+) مربوط به آن‌ها توصیه می‌شود. لیستی از تگ‌های پذیرفته شده توسط ()recognize_google در اینجا (+) موجود هستند.

خلاصه

در این راهنما، چگونگی نصب بسته SpeechRecognition و استفاده از کلاس Recognizer آن برای تشخیص آسان از هر دو فایل با استفاده از ()record و ورودی میکروفون با استفاده از ()listen بیان شد. همچنین، چگونگی پردازش قطعات یک فایل صوتی با استفاده از آرگومان‌های کلیدواژه offset و duration از متد ()record مورد بررسی قرار گرفت.

تشخیص گفتار در پایتون
بازشناسی گفتار در پایتون

در ادامه مطلب، تاثیر نویز بر صحت رونویس‌ها و چگونگی تنظیم حساسیت نمونه‌های Recognizer برای نویز محیط با ()adjust_for_ambient_noise تشریح شد. در نهایت، استثناهای مورد استفاده و خطاهای ممکن در حالات گوناگون مورد بررسی قرار گرفت. در مجموع باید گفت، بازشناسی گفتار یک موضوع عمیق است و آنچه در اینجا بیان شد همچون کاهی در مقابل کوه است.

اگر مطلب بالا برای شما مفید بوده، آموزش‌های زیر نیز به شما پیشنهاد می‌شود:

^^

الهام حصارکی (+)

«الهام حصارکی»، فارغ‌التحصیل مقطع کارشناسی ارشد مهندسی فناوری اطلاعات، گرایش سیستم‌های اطلاعات مدیریت است. او در زمینه هوش مصنوعی و داده‌کاوی، به ویژه تحلیل شبکه‌های اجتماعی، فعالیت می‌کند.

بر اساس رای 5 نفر

آیا این مطلب برای شما مفید بود؟

5 نظر در “بازشناسی گفتار (Speech Recognition) با پایتون — از صفر تا صد

  1. سلام وقتتون بخیر
    یه سوال داشتم چجوری فرمان های صوتی از راه دور روی کامپیوتر اجرا میشن
    مثلا صد متر دور از کامپیوتر با میکروفون یه فرمان صوتی میدهیم و روی کامپیوتر اجرا میشن کردن چجوری این فرمان صوتی به کامپیوتر میرسه
    ممنون میشم اگه بگید

  2. تو cmd که این کد رو می زنم یک خطا عجیب میاد چه کار کنم؟
    pip install pyaudio

  3. سلام
    خیلییی جامع و کامل بود همون چیزی بود که میخواستم
    ممنون از نویسنده و سایت

  4. فوق العاده بود
    البته اگه با IDE pycharm
    کارکنید نصب این کتابخونه ها خیلی راحت می شه
    ممنون

  5. سلام
    یه چیزی رو یادتون رفته بود بگید اونم روش استفاده برای زبان فارسی بود :
    (‘r.recognize_google(audio, language=’fa-ir)

نظر شما چیست؟

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

برچسب‌ها