تبدیل صدا به متن در JS ( پروژه کاربردی )

صدا به نوشته در JS – در این آموزش یکی مینی پروژه باحال رو هم پیاده سازی می کنیم . ابتدا یاد می گیریم که چطوری با SpeechRecognition کار کنیم .
سپس با api سایت علی بابا پرواز های موجود رو با جزئیات نمایش می دهیم . البته نیاز هست که فیلد هایی را وارد کنیم اما با صوت که به نوشته تبدیل می شود فیلد ها رو پر می کنیم .
دموی برنامه
آشنایی با SpeechRecognition
var SpeechRecognition = SpeechRecognition || webkitSpeechRecognition var recognition = new SpeechRecognition();
option های SpeechRecognition
recognition.continuous = false; recognition.lang = 'en-US'; recognition.interimResults = false; recognition.maxAlternatives = 1;
- continuous : آیا در صورتی که موردی پیدا شد همچنان صوت را دریافت کند یا متوقف شود
- lang : صوت که دریافت می کند به چه زبانی است برای ایرانی fa-IR
- interimResults : اینکه نتیجه را مستقیما برگرداند یا کمی بیشتر پردازش کرده و نتیجه نهایی را نمایش دهد
- maxAlternatives : موارد مرتبط را هم نمایش دهد یا فقط یک نتیجه باشد
دستورات شروع و توقف ضبط صدا
recognition.start(); recognition.stop();
event های SpeechRecognition
onresult زمانی که نتیجه یافت گردید
recognition.onresult = function(event) { var result = event.results[0][0].transcript; }
onspeechend زمانی که دریافت صدا به پایان رسید
recognition.onspeechend = function(event) {}
onnomatch زمانی که هیچ موردی یافت نشد
recognition.onnomatch = function(event) {}
onerror زمانی که خطایی هنگام دریافت صدا رخ داده
recognition.onerror= function(event) {}
شروع پروژه صدا به متن
ابتدا باید کتابخانه های زیر را وارد پروژه خود کنید مثل کد پایین :
- skeleton : کتابخانه css
- jquery : کتابخانه قدرتمند JS
- persian-datepicker : تقویم شمسی برای JS
- persian-date : کتابخانه تبدیل تاریخ میلادی به شمسی یا بالعکس
فایل index.html
<!DOCTYPE html> <html lang="fa"> <head> <meta charset="UTF-8"> <title>Rapidcode.iR - سورس کد</title> <link rel="stylesheet" href="static/css/main.css"> <link rel="stylesheet" href="static/css/lib/normalize.css"> <link rel="stylesheet" href="static/css/lib/skeleton.css"> <link rel="stylesheet" href="static/css/lib/persian-datepicker.min.css"> </head> <body> <div class="container"> <a id="introduce" href="https://rapidcode.ir" target="_blank">رپید کد • کتابخانه مجازی برنامه نویسان</a> <form class="booking"> <div class="row"> <input class="four columns button-primary" type="button" id="getUserVoiceData" value="جستجو بلیت"> </div> <div class="row"> <input class="six columns geobase" data-voice="origin" data-json-key="origin" readonly="readonly" type="text" id="originPlace" placeholder="مبدا"> <input class="six columns geobase" data-voice="destination" data-json-key="destination" readonly="readonly" type="text" id="destinationPlace" placeholder="مقصد"> </div> <div class="row"> <input class="six columns" data-voice="leavingDate" data-json-key="departureDate" readonly="readonly" type="text" id="leavingDate" placeholder="تاریخ رفت"> <input class="six columns" data-voice="numberOfPassenger" data-json-key="adult" readonly="readonly" type="text" id="NumberOfPassengers" placeholder="تعداد مسافران"> </div> </form> <div class="row list-content"></div> </div> <script src="static/js/lib/jquery-3.2.1.min.js"></script> <script src="static/js/lib/persian-date.min.js"></script> <script src="static/js/lib/persian-datepicker.min.js"></script> <script src="static/js/app.js"></script> <script> const datepickerDOM = $("#leavingDate"); window.dateObject = datepickerDOM.persianDatepicker( { "inline": false, "format": "LLLL", "viewMode": "day", "initialValue": true, "onSelect" : function(){ const currentDateState = date.dateObject.State.gregorian; window.selectedDate = `${currentDateState.year}-${(currentDateState.month + 1).toString().padStart(2, "0")}-${currentDateState.day.toString().padStart(2, "0")}`; dateObject.hide(); getTheVoiceResult(selectedDate); } }); const date = dateObject.getState().view; </script> </body> </html>
اسکریپت app.js
- در این اسکریپت از Audio استفاده کرده ایم جهت پخش صدا برای هر فیلد به طور اختصاصی .
- از Generator ها استفاده کردیم .
- با xhr ها جهت ارسال درخواست http با استفاده از مکانیزم AJAX
- با تابع listDataToHtml داده ها را در قالب html نمایش می دهیم
- اعداد فارسی را به عامیانه تبدیل کرده با استفاده از regex
- همچنین از تقویم فارسی جهت دریافت تاریخ رفت استفاده کرده ایم چون با صدا زیاد دقیق به دست نمی آمد .
- تابع elementFocus جهت نمایش برجسته فیلد فعال است
- از Web Speech API استفاده کردیم .
const audio = new Audio(); const audioError = new Audio(); var SpeechRecognition = SpeechRecognition || webkitSpeechRecognition const recognition = new SpeechRecognition(); recognition.continuous = false; recognition.lang = 'fa-IR'; recognition.interimResults = false; recognition.maxAlternatives = 1; const voiceList = { destination : '/static/audio/destination.mp3', leavingDate : '/static/audio/leavingDate.mp3', numberOfPassenger : '/static/audio/numberOfPassenger.mp3', origin : '/static/audio/origin.mp3', notDetected : '/static/audio/notDetected.mp3', Problem : '/static/audio/Problem.mp3' } const cities = { THR:"تهران", MHD:"مشهد", AWZ:"اهواز", SYZ:"شیراز", BND:"بندر عباس", IFN:"اصفهان", TBZ:"تبریز", KIH:"کیش" } const voiceButtonDOM = document.getElementById('getUserVoiceData'); const inputTextDOM = document.querySelectorAll(".booking input[type='text']"); const listContentDOM = document.getElementsByClassName('list-content')[0]; voiceButtonDOM.onclick = startGettingVoice; recognition.onresult = function(event) { const result = event.results[0][0].transcript; getTheVoiceResult(result); } recognition.onspeechend = function() { recognition.stop(); } recognition.onnomatch = function(event) { playVoiceState("notDetected",audioError); } recognition.onerror = function(event) { playVoiceState("Problem",audioError); } audio.onended = function(){ if(activeInput.id == 'leavingDate'){ dateObject.show(); }else{ recognition.start(); } } // ######## END HANDLER function playVoiceState(state , audioObj){ audioObj.src = voiceList[state]; audioObj.onloadeddata = function(){ audioObj.play(); } } function * generatorInputList(){ for(var i=0;i<inputTextDOM.length;i++){ yield inputTextDOM[i]; } } function tabTheElement(currentElement){ elementFocus(currentElement); const voice = currentElement.dataset.voice; playVoiceState(voice, audio); } function startGettingVoice(){ window.inputGenerator = generatorInputList(); const currentElement = inputGenerator.next().value; tabTheElement(currentElement); } function elementFocus(customElement){ inputTextDOM.forEach(function(element){ if(customElement == element){ customElement.classList.add("activeBorder"); window.activeInput = customElement; } else if(element.classList.contains("activeBorder")) element.classList.remove("activeBorder"); }); } function fixNumbers (str) { var persianNumbers = [/۰/g, /۱/g, /۲/g, /۳/g, /۴/g, /۵/g, /۶/g, /۷/g, /۸/g, /۹/g] if(typeof str === 'string') { for(var i=0; i<10; i++) { str = str.replace(persianNumbers[i], i); } } return str; }; function funcReverseString(str) { return str.split('').reverse().join(''); } function seperateNumbers(numberValue){ if (isNaN(Number(numberValue))) { alert("لطفا از وارد کردن حروف خودداری فرمایید !") return false; } let seperatedNumber = numberValue.toString(); seperatedNumber = funcReverseString(seperatedNumber); seperatedNumber = seperatedNumber.split(""); let tmpSeperatedNumber = ""; j = 0; for (let i = 0; i < seperatedNumber.length; i++) { tmpSeperatedNumber += seperatedNumber[i]; j++; if (j == 3) { tmpSeperatedNumber += ","; j = 0; } } seperatedNumber = funcReverseString(tmpSeperatedNumber); if(seperatedNumber[0] === ",") seperatedNumber = seperatedNumber.replace("," , ""); return seperatedNumber; } function seperateDateAndTime(date , type="time"){ const dateList = date.split("T"); const finallValue = type == "date" ? dateList[0] : dateList[1]; return finallValue; } function getTheVoiceResult(result){ result = fixNumbers(result); if(activeInput.id != "leavingDate") activeInput.value = result; if(activeInput.classList.contains('geobase')){ const indexCities = Object.keys(cities); indexCities.forEach(function(element){ const currentCity = cities[element]; if(currentCity == activeInput.value) activeInput.value = `${activeInput.value}-${element}`; }); } const nextInput = inputGenerator.next().value; if(nextInput != undefined) tabTheElement(nextInput); else{ const data = { child : 0, infant : 0, } inputTextDOM.forEach(function(element){ let finallValue = element.value; if(element.classList.contains('geobase')){ finallValue = element.value.split('-')[1]; }else if(element.id == "leavingDate"){ finallValue = selectedDate; }if(!isNaN(Number(finallValue))) finallValue = Number(finallValue); const key = element.dataset.jsonKey; data[key] = finallValue; }); getOnlineFlight(data); } } function emptyTheListContent(){ listContentDOM.innerHTML = ""; } function listDataToHtml(data){ data['priceAdult'] = seperateNumbers(data['priceAdult']); data['status'] = data['status'] == 0 ? "نا موجود" : data['status'] + " صندلی"; data['leaveDateTime'] = seperateDateAndTime(data['leaveDateTime']); data['arrivalDateTime'] = seperateDateAndTime(data['arrivalDateTime']); const htmlContent = `<div class="u-full-width content-booking"><img src="${data.airlineLogo}" id="logo"> <h6 id="ariline">${data.airlineName}</h6> <h2 id="title"><span id="from">${data.originName}</span> به <span id="to">${data.destinationName}</span></h2> <h3 id="time"><span id="leave">پرواز : ${data.leaveDateTime}</span> <span id="arrive">حضور : ${data.arrivalDateTime}</span></h3> <h4 id="price">${data.priceAdult} ریال</h4><h5 id="entity">${data.status}</h5><div></div></div>`; listContentDOM.innerHTML += htmlContent; } function getOnlineFlight(data){ voiceButtonDOM.setAttribute("disabled", "disabled"); const xhr = new XMLHttpRequest(); const params = JSON.stringify(data); console.log(params); xhr.open("POST", "https://ws.alibaba.ir/api/v1/flights/domestic/available"); xhr.setRequestHeader('Content-Type', 'application/json'); xhr.onload = function(xhrLoaded){ let data = xhrLoaded.currentTarget.response; data = JSON.parse(data); if(!data.success){ playVoiceState("notDetected",audioError); voiceButtonDOM.removeAttribute("disabled"); return false; } const RequestID = data.result.requestId; xhr.open("GET", 'https://ws.alibaba.ir/api/v1/flights/domestic/available/' + RequestID); xhr.setRequestHeader('Content-Type', null); xhr.onload = function(xhr){ let data = xhr.currentTarget.response; data = JSON.parse(data); let customData = []; emptyTheListContent(); data.result.departing.forEach(function(val){ const tempObj = { originName : val.originName, destinationName : val.destinationName, airlineName : val.airlineName, leaveDateTime : val.leaveDateTime, arrivalDateTime : val.arrivalDateTime, priceAdult : val.priceAdult, status : val.status, airlineLogo : val.airlineLogo } customData.push(tempObj); listDataToHtml(tempObj); }); voiceButtonDOM.removeAttribute("disabled"); } xhr.onerror = function (){ console.warn("ERROR 2"); voiceButtonDOM.removeAttribute("disabled"); }; xhr.send(); } xhr.onerror = function (){ console.warn("ERROR"); voiceButtonDOM.removeAttribute("disabled"); }; xhr.send(params); }
دانلود پروژه صدا به نوشته در JS
توجه داشته باشید که برنامه باید روی سرور یا حداقل یک localhost اجرا شود .
لیست نظرات
سلام من در هاست اجرا کردم ولی پروژ کار نکرد؟
درود ، اگر در تب console از پیغام خطا وجود داره بفرستید تا بررسی بشه .
آیا از این قابلیت برای ترجمه و درج زیر نویس فیلم میشه استفاده کرد؟
بله ، اما باید شمرده شمرده و کتابی صحبت کرد .