ปรับใช้งาน Web Speech API ใน jQuery Plugin ตอนที่ 2

บทความใหม่ ยังไม่ถึงปี โดย Ninenik Narkdee
type4me jquery web speech jquery jquery plugin

คำสั่ง การ กำหนด รูปแบบ ตัวอย่าง เทคนิค ลูกเล่น การประยุกต์ การใช้งาน เกี่ยวกับ type4me jquery web speech jquery jquery plugin



ในตอนที่ผ่านมา เราได้เริ่มต้น แนวทางการประยุกต์
ใช้งาน Web Speech API เพื่อสร้างเป็น jQuery Plugin สำหรับ
ใช้งานร่วมกับ Bootstrap ไปเบื้องต้นแล้ว เนื้อหาตอนต่อไปนี้
เราจะมาต่อกันในส่วนของ การปรับใช้งาน Web Speech API มากำหนด
ใช้งานใน plugin ทบทวนตอนที่แล้วได้ที่
 
    ประยุกต์สร้าง jQuery Web Speech ร่วมกับ Bootstrap ตอนที่ 1 http://niik.in/970 
 
สำหรับรูปแบบการใช้งาน Web Speech API เราจะใช้โค้ดจากเนื้อหาบทความ
 
    การใช้งาน web speech api แปลงเสียง เป็นข้อความ ใน html5 http://niik.in/558 
 
 

ปรับใช้งาน Web Speech API 

    สามารถ เข้าไปดู DEMO และรูปแบบการทำงานที่หน้าบทความดังกล่าวได้ 
ในที่นี้จะยกโค้ดทั้งหมดมาตามด้านล่าง
 
var final_transcript = '';  // ตัวแปร สำหรับเก็บข้อความที่แปลงจากเสียง
var recognizing = false;  // กำหนดค่าเริ่มต้นการจดจำเสียง เริ่มต้น ให้เป็น false ไม่ทำงาน
var language = 'th-TH';  // กำหนดภาษา th-TH,
$(function(){
 
        // ตรวจสอบ browser ว่าสนับสนุนการใช้งาน Speech API หรือไม่
        if (!('webkitSpeechRecognition' in window)) {
            alert("Your Browser does not support the Speech API");
        }else{
 
            // สร้าง recognition object และกำหนด event handlers
            // (onstart , onerror, onend, onresult)
 
            var recognition = new webkitSpeechRecognition(); // สร้าง recognition object 
            recognition.continuous = true;         // กำหนด true ให้รับค่า จากเสียงไปเรื่อยๆ จนกว่าจะกดปุ่มหยุด
            recognition.interimResults = true;     // แสดงข้อความช่วงจังหวะหรือไม่ กรณีพูดยาวๆ
            recognition.lang = language;           // กำหนดภาษา จากตัวแปรด้านบน
 
            recognition.onstart = function() {
                // เมื่อเกิดการเริ่มทำงานของการจดจำเสียง มาจากคำสั่ง recognition.start();
                recognizing = true;  // เปลี่ยนค่าให้เริ่มทำการจดสับเสียงเป็น true เริ่มทำงาน
                $('#instructions').html('Speak slowly and clearly'); // แสดงคำแนะนำ 
                $('#start_button').html('Click to Stop'); // เมื่อกดแล้วเปลี่ยนข้อความปุ่มเป็น คลิกอีกทีเพื่อหยุด หรือ Stop
            };
 
            recognition.onerror = function(event) {
                // ถ้าเกิดข้อผิดพลาด ทำงานส่วนนี้
                $('#instructions').html("There was a recognition error..."); // แจ้งสถานะถ้าเกิดข้อผิดพลาด
            };
 
            recognition.onend = function() {
                // ถ้าจบการทำงาน เช่นหยุดด้วยคำสั่ง recognition.stop();
                // หรือไม่ได้พูดเพื่อใช้งาน การจดจำเสียงนาน ก็จะหยุดการทำงานเอง
                recognizing = false;  // กำหนดให้การจดจำเสียงอยูในสถานะหยุดการทำงาน
                $('#instructions').html('Done'); // แสดงสถานะว่าเสร็จสิ้นแล้ว Done
                $('#start_button').html('Click to Start'); // เปลี่ยนข้อความปุ่มกดให้เป็นค่าเริ่มต้น
            };
 
            recognition.onresult = function(event) {
                // เมื่อแปลงเสียงเป็นข้อความสำเร็จ ส่งผลลัธ์กลับมา
                // ตัวแปรไว้เก็บข้อความในช่วงจังหวะหนึ่งจังหวะใดบางช่วง กรณีพูดยาวๆ
                var interim_transcript = ''; // ปกติค่านี้ไม่ค่อยได้ใช้ จะใช้ค่า final มากกว่า
                 
                // ถอดจากข้อความจาก array ผลลัพธ์
                for (var i = event.resultIndex; i < event.results.length; ++i) {
                    // ถ้าเป็นค่าสุดท้ายแล้ว หยุดพูด หรือไม่ได้พูดต่อ
                    if (event.results[i].isFinal) {
                        // เอาข้อความผลัพธ์ที่ได้ มาต่อๆ กันและกับในตัวแปร final_transcript
                        final_transcript += event.results[i][0].transcript+' ';
                    } else { 
                        // ถ้าเป็นค่าข้อความระหว่างช่วงเวลา ในกรณีพูดยาวๆ เก็บในตัวแปร 
                        // เก็บในตัวแปร  interim_transcript
                        interim_transcript += event.results[i][0].transcript+' '; 
                    }
                }
 
                // บรรทัดที่ เอาไว้ทดสอบดูค่า ใน console  ไม่ได้ใช้ปิดไป
//                console.log("interim:  " + interim_transcript); 
//                console.log("final:    " + final_transcript);
 
                if(final_transcript.length > 0) { // นับความยาวข้อความ ถ้ามากกว่า 0 แสดงว่ามีค่า
                    // ตัวแปร final_transcript คือค่าข้อความที่ได้ เอาไปใช้งานต่อได้
                    $('#transcript').val(final_transcript); // แสดงค่าใน textarea 
                }
            };
 
 
            // ภ้ากดปุ่ม id start_button
            $("#start_button").click(function(e) {
                e.preventDefault();
                 
                // การจดจำเสียงกำลังทำงานอยู่หรือไม่ กดครั้งแรก จะยังไม่ทำงาน
                if (recognizing) { // ภ้าทำงานอยู่ เมื่อกดก็จะเป็นหยุด
                    recognition.stop();  // ให้หยุดการจัดจำเสียง
                    $('#start_button').html('Click to Start Again'); // เปลี่ยนข้อความปุ่ม แนะนำกดใหม่ ถ้าต้องการจดจำเสียงอีกครั้ง
                    recognizing = false;  // เปลี่ยนสถานะว่าหยุดทำงาน
                } else { // ถ้ากดแล้วสถานะการจดจำเสียงหยุดอยู่ ให้ทำงาน
                    final_transcript = ''; // กำหนดตัวแปรเก็บข้อความเป็นค่าว่างก่อน
 
                    // ขออนุญาตใช้งานการจดจำเสียงและเริ่มใช้งาน
                    recognition.start();
                     
                    // แจ้งคำแนะนำว่าให้ กด allow หรือตกลง เพื่ออนุญาตให้ใช้งาน Microphone
                    $('#instructions').html('Allow the browser to use your Microphone');
                    $('#start_button').html('waiting'); // เปลี่ยนข้อความปุ่ม ว่ารอ waiting
                    $('#transcript').val(''); // แสดงข้อความเป็นค่าว่าง 
                }
            });
        }
});
 
ในโค้ดข้างต้น เราจะเห็นความสัมพันธ์ของตัวแปรต่างๆ พอแยกอธิบายได้ดังนี้
ตัวแปร 3 ตัวแรก เป็นส่วนของ option การกำหนด่าเริ่มต้น
 
// บรรทัดที่ 1,2,3
var final_transcript = '';  // ตัวแปร สำหรับเก็บข้อความที่แปลงจากเสียง
var recognizing = false;  // กำหนดค่าเริ่มต้นการจดจำเสียง เริ่มต้น ให้เป็น false ไม่ทำงาน
var language = 'th-TH';  // กำหนดภาษา th-TH,
 
และส่วนการทำงาน จะมี element ที่เกี่ยวข้องอยู่ด้วยกัน 3 ตัวคือ
 
// บรรทัดที่ใช้งาน 22,23,28,35,36,63,69,75,84,85,86
$('#instructions') // ส่วนอ้างอิงสำหรับแสดงข้อความแจ้ง คำแนะนำ
$('#start_button') // ปุ่มสำหรับเพิ่มหรือหยุดการพิมพ์ด้วยเสียง
$('#transcript') // ส่วนที่แสดงผลลัพธ์ข้อความ ที่ได้จากข้อความเสียง
 
จะเห็นว่าแบบเดิม เรากำหนดการเรียกใช้งานแบบอ้างอิงผ่าน id แบบตายตัว ถ้าจะใช้งาน ก็ต้องมาเปลี่ยนค่า
ของส่วนนี้เป็นค่าที่ต้องการ แต่ถ้าเราสร้างเป็น plugin ก็จะไม่ต้องมากำหนดในส่วนนี้ แต่จะอ้างอิงความสัมพันธ์
และเรียกใช้งานตามรูปแบบให้อัตโนมัติ
 
เราจะดึงโค้ดทั้งหมดมาไว้ใน plugin ที่เราสร้างในตอนที่แล้ว โดยจะ highlight ส่วนของโค้ดที่ยกมา
เพื่อแยกให้เห็นแต่ละส่วนชัดเจนขึ้น
 
<script type="text/javascript">
// JavaScript Document
(function($){
    var final_transcript = '';  // ตัวแปร สำหรับเก็บข้อความที่แปลงจากเสียง
    var recognizing = false;  // กำหนดค่าเริ่มต้นการจดจำเสียง เริ่มต้น ให้เป็น false ไม่ทำงาน
    var language = 'th-TH';  // กำหนดภาษา th-TH,

    // type4me คือชื่อของ plugin ที่เราต้องการ 
    $.fn.type4me = function( options ) { // กำหนดให้ plugin ของเราสามารถ รับค่าเพิ่มเติมได้ มี options
      
        // ส่วนนี้ สำหรับกำหนดค่าเริ่มต้น
        var defaults={
          btnSpeakObj:[],
          btnResetObj:[],    
        };
      
        // ส่วนสำหรับ  เป็นต้วแปร รับค่า options หากมี หรือใช้ค่าเริ่มต้น ถ้ากำหนด
        var settings = $.extend( {}, defaults, options );
      
        /// คืนค่ากลับ การทำงานของ plugin
        return this.each(function(k, ele) { // กำหนดใช้งาน key หรือ index

            // ตรวจสอบ browser ว่าสนับสนุนการใช้งาน Speech API หรือไม่
            if (!('webkitSpeechRecognition' in window)) {
                alert("Your Browser does not support the Speech API");
            }else{
    
                // สร้าง recognition object และกำหนด event handlers
                // (onstart , onerror, onend, onresult)
    
                var recognition = new webkitSpeechRecognition(); // สร้าง recognition object 
                recognition.continuous = true;         // กำหนด true ให้รับค่า จากเสียงไปเรื่อยๆ จนกว่าจะกดปุ่มหยุด
                recognition.interimResults = true;     // แสดงข้อความช่วงจังหวะหรือไม่ กรณีพูดยาวๆ
                recognition.lang = language;           // กำหนดภาษา จากตัวแปรด้านบน
    
                recognition.onstart = function() {
                    // เมื่อเกิดการเริ่มทำงานของการจดจำเสียง มาจากคำสั่ง recognition.start();
                    recognizing = true;  // เปลี่ยนค่าให้เริ่มทำการจดสับเสียงเป็น true เริ่มทำงาน
                    $('#instructions').html('Speak slowly and clearly'); // แสดงคำแนะนำ 
                    $('#start_button').html('Click to Stop'); // เมื่อกดแล้วเปลี่ยนข้อความปุ่มเป็น คลิกอีกทีเพื่อหยุด หรือ Stop
                };
    
                recognition.onerror = function(event) {
                    // ถ้าเกิดข้อผิดพลาด ทำงานส่วนนี้
                    $('#instructions').html("There was a recognition error..."); // แจ้งสถานะถ้าเกิดข้อผิดพลาด
                };
    
                recognition.onend = function() {
                    // ถ้าจบการทำงาน เช่นหยุดด้วยคำสั่ง recognition.stop();
                    // หรือไม่ได้พูดเพื่อใช้งาน การจดจำเสียงนาน ก็จะหยุดการทำงานเอง
                    recognizing = false;  // กำหนดให้การจดจำเสียงอยูในสถานะหยุดการทำงาน
                    $('#instructions').html('Done'); // แสดงสถานะว่าเสร็จสิ้นแล้ว Done
                    $('#start_button').html('Click to Start'); // เปลี่ยนข้อความปุ่มกดให้เป็นค่าเริ่มต้น
                };
    
                recognition.onresult = function(event) {
                    // เมื่อแปลงเสียงเป็นข้อความสำเร็จ ส่งผลลัธ์กลับมา
                    // ตัวแปรไว้เก็บข้อความในช่วงจังหวะหนึ่งจังหวะใดบางช่วง กรณีพูดยาวๆ
                    var interim_transcript = ''; // ปกติค่านี้ไม่ค่อยได้ใช้ จะใช้ค่า final มากกว่า
                    
                    // ถอดจากข้อความจาก array ผลลัพธ์
                    for (var i = event.resultIndex; i < event.results.length; ++i) {
                        // ถ้าเป็นค่าสุดท้ายแล้ว หยุดพูด หรือไม่ได้พูดต่อ
                        if (event.results[i].isFinal) {
                            // เอาข้อความผลัพธ์ที่ได้ มาต่อๆ กันและกับในตัวแปร final_transcript
                            final_transcript += event.results[i][0].transcript+' ';
                        } else { 
                            // ถ้าเป็นค่าข้อความระหว่างช่วงเวลา ในกรณีพูดยาวๆ เก็บในตัวแปร 
                            // เก็บในตัวแปร  interim_transcript
                            interim_transcript += event.results[i][0].transcript+' '; 
                        }
                    }
    
                    // บรรทัดที่ เอาไว้ทดสอบดูค่า ใน console  ไม่ได้ใช้ปิดไป
    //                console.log("interim:  " + interim_transcript); 
    //                console.log("final:    " + final_transcript);
    
                    if(final_transcript.length > 0) { // นับความยาวข้อความ ถ้ามากกว่า 0 แสดงว่ามีค่า
                        // ตัวแปร final_transcript คือค่าข้อความที่ได้ เอาไปใช้งานต่อได้
                        $('#transcript').val(final_transcript); // แสดงค่าใน textarea 
                    }
                };
    
    
                // ภ้ากดปุ่ม id start_button
                $("#start_button").click(function(e) {
                    e.preventDefault();
                    
                    // การจดจำเสียงกำลังทำงานอยู่หรือไม่ กดครั้งแรก จะยังไม่ทำงาน
                    if (recognizing) { // ภ้าทำงานอยู่ เมื่อกดก็จะเป็นหยุด
                        recognition.stop();  // ให้หยุดการจัดจำเสียง
                        $('#start_button').html('Click to Start Again'); // เปลี่ยนข้อความปุ่ม แนะนำกดใหม่ ถ้าต้องการจดจำเสียงอีกครั้ง
                        recognizing = false;  // เปลี่ยนสถานะว่าหยุดทำงาน
                    } else { // ถ้ากดแล้วสถานะการจดจำเสียงหยุดอยู่ ให้ทำงาน
                        final_transcript = ''; // กำหนดตัวแปรเก็บข้อความเป็นค่าว่างก่อน
    
                        // ขออนุญาตใช้งานการจดจำเสียงและเริ่มใช้งาน
                        recognition.start();
                        
                        // แจ้งคำแนะนำว่าให้ กด allow หรือตกลง เพื่ออนุญาตให้ใช้งาน Microphone
                        $('#instructions').html('Allow the browser to use your Microphone');
                        $('#start_button').html('waiting'); // เปลี่ยนข้อความปุ่ม ว่ารอ waiting
                        $('#transcript').val(''); // แสดงข้อความเป็นค่าว่าง 
                    }
                });
            }

            // โค้ตสำหรับ การทำงานของ plugin
            settings.btnResetObj[k] = $(`
            <div class="input-group-prepend" style="cursor: pointer">
                <span class="input-group-text"><i class="far fa-times-circle"></i></span>
              </div>
            `);
            settings.btnSpeakObj[k] = $(`
            <div class="input-group-append" style="cursor: pointer">
                <span class="input-group-text"><i class="fas fa-microphone"></i></span>
              </div>  
            `);            
            // ใช้ back qoute กดปุ่ม alt + 96

            $(this)
            .wrap('<div class="input-group">')
            .before(settings.btnResetObj[k])
            .after(settings.btnSpeakObj[k]); 


           // กำหนดการทำงานปุ่ม เริ่มพิมพ์ด้วยเสียง
           settings.btnSpeakObj[k].click(function(e) {
              e.preventDefault();
              console.log('Microphone click');
            });	
			
            // ภ้ากดปุ่ม reset ข้อความ
            settings.btnResetObj[k].click(function(e) {
              e.preventDefault();
              console.log('reset click');
            });            


        });
      
    };
 
})(jQuery);
$(function(){
     $(".use-voice").type4me();
});
</script>
 
ต่อไปเป็นส่วนของการจัดการตัวแปร และการจัดการโค้ด ส่วนนี้ จะไม่อธิบายทุกบรรทัด ให้เปรียบเทียบโค้ดเดิม
กับโค้ดที่ปรับแต่งแล้วด้านล่าง
 
<script type="text/javascript">
// JavaScript Document
(function($){

    // type4me คือชื่อของ plugin ที่เราต้องการ 
    $.fn.type4me = function( options ) { // กำหนดให้ plugin ของเราสามารถ รับค่าเพิ่มเติมได้ มี options
      
        // ส่วนนี้ สำหรับกำหนดค่าเริ่มต้น
        var defaults={
          recognizing:false, // กำหนดค่าเริ่มต้นการจดจำเสียง เริ่มต้น ให้เป็น false ไม่ทำงาน
          language:'th-TH',    // กำหนดภาษา th-TH,      
          btnSpeakObj:[], // สำหรับ object ปุ่มเริ่มพิมพ์ด้วยเสียง
          btnResetObj:[], // สำหรับ object ปุ่มรีเซ็ตข้อความ   
          transcript:[], // สำหรับ object ที่เป็น input หรือ textarea ที่จะแสดงข้อความ
          labelInstruction:[], // สำหรับ object แสดงคำแนะนำ คำเตือน
          final_transcript:[],   // ตัวแปร สำหรับเก็บข้อความที่แปลงจากเสียง       
        };
      
        // ส่วนสำหรับ  เป็นต้วแปร รับค่า options หากมี หรือใช้ค่าเริ่มต้น ถ้ากำหนด
        var settings = $.extend( {}, defaults, options );
      
        /// คืนค่ากลับ การทำงานของ plugin
        return this.each(function(k, ele) { // กำหนดใช้งาน key หรือ index

            // ตรวจสอบ browser ว่าสนับสนุนการใช้งาน Speech API หรือไม่
            if (!('webkitSpeechRecognition' in window)) {
                alert("Your Browser does not support the Speech API");
                return false; // หากไม่สามารถใช้งานได้ ให้ออกจากลูป
            }else{

                // โค้ตสำหรับ การทำงานของ plugin
                settings.btnResetObj[k] = $(`
                <div class="input-group-prepend" style="cursor: pointer">
                    <span class="input-group-text"><i class="far fa-times-circle"></i></span>
                  </div>
                `);
                settings.btnSpeakObj[k] = $(`
                <div class="input-group-append" style="cursor: pointer">
                    <span class="input-group-text"><i class="fas fa-microphone"></i></span>
                  </div>  
                `);    
                settings.labelInstruction[k] = $('<label class="instructions"></label>');
                settings.transcript[k] = $(this);
				        settings.labelInstruction[k].hide();                        
                // ใช้ back qoute กดปุ่ม alt + 96

                $(this)
                .after(settings.labelInstruction[k]) // แทรกส่วนของการแสดงคำแนะนำ
                .wrap('<div class="input-group">')
                .before(settings.btnResetObj[k])
                .after(settings.btnSpeakObj[k]);        

                // สร้าง recognition object และกำหนด event handlers
                // (onstart , onerror, onend, onresult)
    
                var recognition = new webkitSpeechRecognition(); // สร้าง recognition object 
                recognition.continuous = true;         // กำหนด true ให้รับค่า จากเสียงไปเรื่อยๆ จนกว่าจะกดปุ่มหยุด
                recognition.interimResults = true;     // แสดงข้อความช่วงจังหวะหรือไม่ กรณีพูดยาวๆ
                recognition.lang = settings.language;           // กำหนดภาษา จากตัวแปรด้านบน
    
                recognition.onstart = function() {
                    // เมื่อเกิดการเริ่มทำงานของการจดจำเสียง มาจากคำสั่ง recognition.start();
                    settings.recognizing = true;  // เปลี่ยนค่าให้เริ่มทำการจดสับเสียงเป็น true เริ่มทำงาน
                    settings.labelInstruction[k].slideDown('fast').html('กรุณาพูดช้าๆ และชัดเจน'); // แสดงคำแนะนำ 
                    settings.btnSpeakObj[k].find(".input-group-text").addClass('text-success'); // เมื่อกดแล้วเปลี่ยนข้อความปุ่มเป็น คลิกอีกทีเพื่อหยุด หรือ Stop
                };
    
                recognition.onerror = function(event) {
                    // ถ้าเกิดข้อผิดพลาด ทำงานส่วนนี้
                    settings.labelInstruction[k].slideDown('fast').html("There was a recognition error..."); // แจ้งสถานะถ้าเกิดข้อผิดพลาด
                };
    
                recognition.onend = function() {
                    // ถ้าจบการทำงาน เช่นหยุดด้วยคำสั่ง recognition.stop();
                    // หรือไม่ได้พูดเพื่อใช้งาน การจดจำเสียงนาน ก็จะหยุดการทำงานเอง
                    settings.recognizing = false;  // กำหนดให้การจดจำเสียงอยูในสถานะหยุดการทำงาน
                    settings.labelInstruction[k].html('Done').fadeOut(); // แสดงสถานะว่าเสร็จสิ้นแล้ว Done
                    settings.btnSpeakObj[k].find(".input-group-text")
                    .removeClass('text-danger text-warning text-success'); // เปลี่ยนข้อความปุ่มกดให้เป็นค่าเริ่มต้น
                };
    
                recognition.onresult = function(event) {
                    // เมื่อแปลงเสียงเป็นข้อความสำเร็จ ส่งผลลัธ์กลับมา
                    // ตัวแปรไว้เก็บข้อความในช่วงจังหวะหนึ่งจังหวะใดบางช่วง กรณีพูดยาวๆ
                    var interim_transcript = ''; // ปกติค่านี้ไม่ค่อยได้ใช้ จะใช้ค่า final มากกว่า
                    
                    // ถอดจากข้อความจาก array ผลลัพธ์
                    for (var i = event.resultIndex; i < event.results.length; ++i) {
                        // ถ้าเป็นค่าสุดท้ายแล้ว หยุดพูด หรือไม่ได้พูดต่อ
                        if (event.results[i].isFinal) {
                            // เอาข้อความผลัพธ์ที่ได้ มาต่อๆ กันและกับในตัวแปร final_transcript
                            settings.final_transcript[k] += event.results[i][0].transcript+' ';
                        } else { 
                            // ถ้าเป็นค่าข้อความระหว่างช่วงเวลา ในกรณีพูดยาวๆ เก็บในตัวแปร 
                            // เก็บในตัวแปร  interim_transcript
                            interim_transcript += event.results[i][0].transcript+' '; 
                        }
                    }
    
                    // บรรทัดที่ เอาไว้ทดสอบดูค่า ใน console  ไม่ได้ใช้ปิดไป
    //                console.log("interim:  " + interim_transcript); 
    //                console.log("final:    " + final_transcript);
    
                    if(settings.final_transcript[k].length > 0) { // นับความยาวข้อความ ถ้ามากกว่า 0 แสดงว่ามีค่า
                        // ตัวแปร final_transcript คือค่าข้อความที่ได้ เอาไปใช้งานต่อได้
                        settings.transcript[k].val(settings.final_transcript[k]); // แสดงค่าใน textarea 
                    }
                };
    
    
                // กำหนดการทำงานปุ่ม เริ่มพิมพ์ด้วยเสียง
                settings.btnSpeakObj[k].click(function(e) {
                    e.preventDefault();
                    
                    // การจดจำเสียงกำลังทำงานอยู่หรือไม่ กดครั้งแรก จะยังไม่ทำงาน
                    if (settings.recognizing) { // ภ้าทำงานอยู่ เมื่อกดก็จะเป็นหยุด
                        recognition.stop();  // ให้หยุดการจัดจำเสียง
                        settings.btnSpeakObj[k].find(".input-group-text")
                        .removeClass('text-danger text-warning text-success'); // เปลี่ยนข้อความปุ่มกดให้เป็นค่าเริ่มต้น
                        settings.recognizing = false;  // เปลี่ยนสถานะว่าหยุดทำงาน
                    } else { // ถ้ากดแล้วสถานะการจดจำเสียงหยุดอยู่ ให้ทำงาน
                        settings.final_transcript[k] = ''; // กำหนดตัวแปรเก็บข้อความเป็นค่าว่างก่อน
    
                        // ขออนุญาตใช้งานการจดจำเสียงและเริ่มใช้งาน
                        recognition.start();
                        
                        // แจ้งคำแนะนำว่าให้ กด allow หรือตกลง เพื่ออนุญาตให้ใช้งาน Microphone
                        settings.labelInstruction[k].slideDown('fast').html('Allow the browser to use your Microphone');
                        settings.btnSpeakObj[k].find(".input-group-text")
                        .removeClass("text-success").addClass('text-warning'); // เปลี่ยนสีปุ่ม สำหรับรอคำสั่งเสียงพูด
                        settings.transcript[k].val(''); // แสดงข้อความเป็นค่าว่าง 
                    }
                });

                // ภ้ากดปุ่ม reset ข้อความ
                settings.btnResetObj[k].click(function(e) {
                  e.preventDefault();
                  interim_transcript = '';
                  settings.final_transcript[k] = '';
                  settings.transcript[k].val(''); // แสดงข้อความเป็นค่าว่าง 		
                });                      

            }

        });
      
    };
 
})(jQuery);
$(function(){
     $(".use-voice").type4me();
});
</script>
 
ในส่วนของการกำหนด ตัวแปร option 
 
// ส่วนนี้ สำหรับกำหนดค่าเริ่มต้น
var defaults={
  recognizing:false, // กำหนดค่าเริ่มต้นการจดจำเสียง เริ่มต้น ให้เป็น false ไม่ทำงาน
  language:'th-TH',    // กำหนดภาษา th-TH,      
  btnSpeakObj:[], // สำหรับ object ปุ่มเริ่มพิมพ์ด้วยเสียง
  btnResetObj:[], // สำหรับ object ปุ่มรีเซ็ตข้อความ   
  transcript:[], // สำหรับ object ที่เป็น input หรือ textarea ที่จะแสดงข้อความ
  labelInstruction:[], // สำหรับ object แสดงคำแนะนำ คำเตือน
  final_transcript:[],   // ตัวแปร สำหรับเก็บข้อความที่แปลงจากเสียง       
};
 
ค่าเหล่านี้เป็นการกำหนดค่าเริ่มต้น โดยค่า recognizing และ language จะเป็นการกำหนดการเริ่มต้น
จำเสียงว่าทำงานทันทีหรือไม่ และการกำหนดภาษา ในที่นี้เป็น false และ 'th-TH' ตามลำดับ
ส่วนค่าที่เหลืออีก 5 อัน กำหนดเป็น array object สำหรับอ้างอิง
 
ต่อส่วนของการทำงานของ plugin และการตรวจสอบและใช้งาน web speech api
 
/// คืนค่ากลับ การทำงานของ plugin
return this.each(function(k, ele) { // กำหนดใช้งาน key หรือ index

	// ตรวจสอบ browser ว่าสนับสนุนการใช้งาน Speech API หรือไม่
	if (!('webkitSpeechRecognition' in window)) {
		alert("Your Browser does not support the Speech API");
		return false; // หากไม่สามารถใช้งานได้ ให้ออกจากลูป
	}else{
		// ส่วนของโค้ด web speech api
	}
	
};
 
ส่วนนี้จะตรวจสอบ ว่า บราวเซอร์รองรับการใช้งานหรือไม่ ถ้าไม่รองรับให้ทำการ return false; เพื่อออกจาก
ลูปของการจัดการ element ของคำสั่ง each()
 
ต่อไปส่่วนของการใช้งานโค้ด web speech api จะเริ่มที่ส่วนของการจัดการหน้าตา การกำหนด object ต่างๆ
 
	// โค้ตสำหรับ การทำงานของ plugin
	settings.btnResetObj[k] = $(`
	<div class="input-group-prepend" style="cursor: pointer">
		<span class="input-group-text"><i class="far fa-times-circle"></i></span>
	  </div>
	`);
	settings.btnSpeakObj[k] = $(`
	<div class="input-group-append" style="cursor: pointer">
		<span class="input-group-text"><i class="fas fa-microphone"></i></span>
	  </div>  
	`);    
	settings.labelInstruction[k] = $('<label class="instructions"></label>');
	settings.transcript[k] = $(this);
			settings.labelInstruction[k].hide();                        
	// ใช้ back qoute กดปุ่ม alt + 96

	$(this)
	.after(settings.labelInstruction[k]) // แทรกส่วนของการแสดงคำแนะนำ
	.wrap('<div class="input-group">')
	.before(settings.btnResetObj[k])
	.after(settings.btnSpeakObj[k]);     
 
ส่วนนี้ เรามีการเพิ่มส่วนของการแสดงคำแนะนำโดยใช้เป้น label เพิ่มเข้ามา โดยจะแสดงต่อจาก input
หรือ textarea ที่เรียกใช้งาน
 
และส่วนสุดท้าย เป็นส่วนของการทำงานของ web speech api รูปแบบโค้ดจะเป็นลักษณะคล้ายตัวเดิม
แต่ปรับเปลี่ยนในส่วนของการแสดงเล็กน้อย เช่นข้อความที่แสดง สีของปุ่มไมโครโฟนเมื่อรอรับคำสั่ง
ตัวแปรที่อ้างอิงต่างๆ เราเปลี่ยนไปตามค่าที่กำหนด
 
	var recognition = new webkitSpeechRecognition(); // สร้าง recognition object 
	recognition.continuous = true;         // กำหนด true ให้รับค่า จากเสียงไปเรื่อยๆ จนกว่าจะกดปุ่มหยุด
	recognition.interimResults = true;     // แสดงข้อความช่วงจังหวะหรือไม่ กรณีพูดยาวๆ
	recognition.lang = settings.language;           // กำหนดภาษา จากตัวแปรด้านบน

	recognition.onstart = function() {
		// เมื่อเกิดการเริ่มทำงานของการจดจำเสียง มาจากคำสั่ง recognition.start();
		settings.recognizing = true;  // เปลี่ยนค่าให้เริ่มทำการจดสับเสียงเป็น true เริ่มทำงาน
		settings.labelInstruction[k].slideDown('fast').html('กรุณาพูดช้าๆ และชัดเจน'); // แสดงคำแนะนำ 
		settings.btnSpeakObj[k].find(".input-group-text").addClass('text-success'); // เมื่อกดแล้วเปลี่ยนข้อความปุ่มเป็น คลิกอีกทีเพื่อหยุด หรือ Stop
	};

	recognition.onerror = function(event) {
		// ถ้าเกิดข้อผิดพลาด ทำงานส่วนนี้
		settings.labelInstruction[k].slideDown('fast').html("There was a recognition error..."); // แจ้งสถานะถ้าเกิดข้อผิดพลาด
	};

	recognition.onend = function() {
		// ถ้าจบการทำงาน เช่นหยุดด้วยคำสั่ง recognition.stop();
		// หรือไม่ได้พูดเพื่อใช้งาน การจดจำเสียงนาน ก็จะหยุดการทำงานเอง
		settings.recognizing = false;  // กำหนดให้การจดจำเสียงอยูในสถานะหยุดการทำงาน
		settings.labelInstruction[k].html('Done').fadeOut(); // แสดงสถานะว่าเสร็จสิ้นแล้ว Done
		settings.btnSpeakObj[k].find(".input-group-text")
		.removeClass('text-danger text-warning text-success'); // เปลี่ยนข้อความปุ่มกดให้เป็นค่าเริ่มต้น
	};

	recognition.onresult = function(event) {
		// เมื่อแปลงเสียงเป็นข้อความสำเร็จ ส่งผลลัธ์กลับมา
		// ตัวแปรไว้เก็บข้อความในช่วงจังหวะหนึ่งจังหวะใดบางช่วง กรณีพูดยาวๆ
		var interim_transcript = ''; // ปกติค่านี้ไม่ค่อยได้ใช้ จะใช้ค่า final มากกว่า
		
		// ถอดจากข้อความจาก array ผลลัพธ์
		for (var i = event.resultIndex; i < event.results.length; ++i) {
			// ถ้าเป็นค่าสุดท้ายแล้ว หยุดพูด หรือไม่ได้พูดต่อ
			if (event.results[i].isFinal) {
				// เอาข้อความผลัพธ์ที่ได้ มาต่อๆ กันและกับในตัวแปร final_transcript
				settings.final_transcript[k] += event.results[i][0].transcript+' ';
			} else { 
				// ถ้าเป็นค่าข้อความระหว่างช่วงเวลา ในกรณีพูดยาวๆ เก็บในตัวแปร 
				// เก็บในตัวแปร  interim_transcript
				interim_transcript += event.results[i][0].transcript+' '; 
			}
		}

		// บรรทัดที่ เอาไว้ทดสอบดูค่า ใน console  ไม่ได้ใช้ปิดไป
//                console.log("interim:  " + interim_transcript); 
//                console.log("final:    " + final_transcript);

		if(settings.final_transcript[k].length > 0) { // นับความยาวข้อความ ถ้ามากกว่า 0 แสดงว่ามีค่า
			// ตัวแปร final_transcript คือค่าข้อความที่ได้ เอาไปใช้งานต่อได้
			settings.transcript[k].val(settings.final_transcript[k]); // แสดงค่าใน textarea 
		}
	};


	// กำหนดการทำงานปุ่ม เริ่มพิมพ์ด้วยเสียง
	settings.btnSpeakObj[k].click(function(e) {
		e.preventDefault();
		
		// การจดจำเสียงกำลังทำงานอยู่หรือไม่ กดครั้งแรก จะยังไม่ทำงาน
		if (settings.recognizing) { // ภ้าทำงานอยู่ เมื่อกดก็จะเป็นหยุด
			recognition.stop();  // ให้หยุดการจัดจำเสียง
			settings.btnSpeakObj[k].find(".input-group-text")
			.removeClass('text-danger text-warning text-success'); // เปลี่ยนข้อความปุ่มกดให้เป็นค่าเริ่มต้น
			settings.recognizing = false;  // เปลี่ยนสถานะว่าหยุดทำงาน
		} else { // ถ้ากดแล้วสถานะการจดจำเสียงหยุดอยู่ ให้ทำงาน
			settings.final_transcript[k] = ''; // กำหนดตัวแปรเก็บข้อความเป็นค่าว่างก่อน

			// ขออนุญาตใช้งานการจดจำเสียงและเริ่มใช้งาน
			recognition.start();
			
			// แจ้งคำแนะนำว่าให้ กด allow หรือตกลง เพื่ออนุญาตให้ใช้งาน Microphone
			settings.labelInstruction[k].slideDown('fast').html('Allow the browser to use your Microphone');
			settings.btnSpeakObj[k].find(".input-group-text")
			.removeClass("text-success").addClass('text-warning'); // เปลี่ยนสีปุ่ม สำหรับรอคำสั่งเสียงพูด
			settings.transcript[k].val(''); // แสดงข้อความเป็นค่าว่าง 
		}
	});

	// ภ้ากดปุ่ม reset ข้อความ
	settings.btnResetObj[k].click(function(e) {
	  e.preventDefault();
	  interim_transcript = '';
	  settings.final_transcript[k] = '';
	  settings.transcript[k].val(''); // แสดงข้อความเป็นค่าว่าง 		
	});  
 
ทดสอบการทำงานได้ที่ DEMO 1 อย่าลืมอนุญาตให้ใช้งาน microphone เมื่อบราวเซอร์แจ้งเตือน หรือกรณี block ไปแล้วให้ทำการ
คลิกที่ปุ่ม ลูกกุญแจ ที่ address bar ของบราวเซอร์ แล้วเลือกอนุญาตใช้งาน microphone
 
เราสามารถแยกไฟล์ plugin เป็นอีกไฟล์สำหรับเรียกใช้งานได้ สมมติเป็น jquery.type4me.js 
 

ไฟล์ jquery.type4me.js

 
// JavaScript Document
(function($){

    // type4me คือชื่อของ plugin ที่เราต้องการ 
    $.fn.type4me = function( options ) { // กำหนดให้ plugin ของเราสามารถ รับค่าเพิ่มเติมได้ มี options
      
        // ส่วนนี้ สำหรับกำหนดค่าเริ่มต้น
        var defaults={
          recognizing:false, // กำหนดค่าเริ่มต้นการจดจำเสียง เริ่มต้น ให้เป็น false ไม่ทำงาน
          language:'th-TH',    // กำหนดภาษา th-TH,      
          btnSpeakObj:[], // สำหรับ object ปุ่มเริ่มพิมพ์ด้วยเสียง
          btnResetObj:[], // สำหรับ object ปุ่มรีเซ็ตข้อความ   
          transcript:[], // สำหรับ object ที่เป็น input หรือ textarea ที่จะแสดงข้อความ
          labelInstruction:[], // สำหรับ object แสดงคำแนะนำ คำเตือน
          final_transcript:[],   // ตัวแปร สำหรับเก็บข้อความที่แปลงจากเสียง       
        };
      
        // ส่วนสำหรับ  เป็นต้วแปร รับค่า options หากมี หรือใช้ค่าเริ่มต้น ถ้ากำหนด
        var settings = $.extend( {}, defaults, options );
      
        /// คืนค่ากลับ การทำงานของ plugin
        return this.each(function(k, ele) { // กำหนดใช้งาน key หรือ index

            // ตรวจสอบ browser ว่าสนับสนุนการใช้งาน Speech API หรือไม่
            if (!('webkitSpeechRecognition' in window)) {
                alert("Your Browser does not support the Speech API");
                return false; // หากไม่สามารถใช้งานได้ ให้ออกจากลูป
            }else{

                // โค้ตสำหรับ การทำงานของ plugin
                settings.btnResetObj[k] = $(`
                <div class="input-group-prepend" style="cursor: pointer">
                    <span class="input-group-text"><i class="far fa-times-circle"></i></span>
                  </div>
                `);
                settings.btnSpeakObj[k] = $(`
                <div class="input-group-append" style="cursor: pointer">
                    <span class="input-group-text"><i class="fas fa-microphone"></i></span>
                  </div>  
                `);    
                settings.labelInstruction[k] = $('<label class="instructions"></label>');
                settings.transcript[k] = $(this);
				        settings.labelInstruction[k].hide();                        
                // ใช้ back qoute กดปุ่ม alt + 96

                $(this)
                .after(settings.labelInstruction[k]) // แทรกส่วนของการแสดงคำแนะนำ
                .wrap('<div class="input-group">')
                .before(settings.btnResetObj[k])
                .after(settings.btnSpeakObj[k]);        

                // สร้าง recognition object และกำหนด event handlers
                // (onstart , onerror, onend, onresult)
    
                var recognition = new webkitSpeechRecognition(); // สร้าง recognition object 
                recognition.continuous = true;         // กำหนด true ให้รับค่า จากเสียงไปเรื่อยๆ จนกว่าจะกดปุ่มหยุด
                recognition.interimResults = true;     // แสดงข้อความช่วงจังหวะหรือไม่ กรณีพูดยาวๆ
                recognition.lang = settings.language;           // กำหนดภาษา จากตัวแปรด้านบน
    
                recognition.onstart = function() {
                    // เมื่อเกิดการเริ่มทำงานของการจดจำเสียง มาจากคำสั่ง recognition.start();
                    settings.recognizing = true;  // เปลี่ยนค่าให้เริ่มทำการจดสับเสียงเป็น true เริ่มทำงาน
                    settings.labelInstruction[k].slideDown('fast').html('กรุณาพูดช้าๆ และชัดเจน'); // แสดงคำแนะนำ 
                    settings.btnSpeakObj[k].find(".input-group-text").addClass('text-success'); // เมื่อกดแล้วเปลี่ยนข้อความปุ่มเป็น คลิกอีกทีเพื่อหยุด หรือ Stop
                };
    
                recognition.onerror = function(event) {
                    // ถ้าเกิดข้อผิดพลาด ทำงานส่วนนี้
                    settings.labelInstruction[k].slideDown('fast').html("There was a recognition error..."); // แจ้งสถานะถ้าเกิดข้อผิดพลาด
                };
    
                recognition.onend = function() {
                    // ถ้าจบการทำงาน เช่นหยุดด้วยคำสั่ง recognition.stop();
                    // หรือไม่ได้พูดเพื่อใช้งาน การจดจำเสียงนาน ก็จะหยุดการทำงานเอง
                    settings.recognizing = false;  // กำหนดให้การจดจำเสียงอยูในสถานะหยุดการทำงาน
                    settings.labelInstruction[k].html('Done').fadeOut(); // แสดงสถานะว่าเสร็จสิ้นแล้ว Done
                    settings.btnSpeakObj[k].find(".input-group-text")
                    .removeClass('text-danger text-warning text-success'); // เปลี่ยนข้อความปุ่มกดให้เป็นค่าเริ่มต้น
                };
    
                recognition.onresult = function(event) {
                    // เมื่อแปลงเสียงเป็นข้อความสำเร็จ ส่งผลลัธ์กลับมา
                    // ตัวแปรไว้เก็บข้อความในช่วงจังหวะหนึ่งจังหวะใดบางช่วง กรณีพูดยาวๆ
                    var interim_transcript = ''; // ปกติค่านี้ไม่ค่อยได้ใช้ จะใช้ค่า final มากกว่า
                    
                    // ถอดจากข้อความจาก array ผลลัพธ์
                    for (var i = event.resultIndex; i < event.results.length; ++i) {
                        // ถ้าเป็นค่าสุดท้ายแล้ว หยุดพูด หรือไม่ได้พูดต่อ
                        if (event.results[i].isFinal) {
                            // เอาข้อความผลัพธ์ที่ได้ มาต่อๆ กันและกับในตัวแปร final_transcript
                            settings.final_transcript[k] += event.results[i][0].transcript+' ';
                        } else { 
                            // ถ้าเป็นค่าข้อความระหว่างช่วงเวลา ในกรณีพูดยาวๆ เก็บในตัวแปร 
                            // เก็บในตัวแปร  interim_transcript
                            interim_transcript += event.results[i][0].transcript+' '; 
                        }
                    }
    
                    // บรรทัดที่ เอาไว้ทดสอบดูค่า ใน console  ไม่ได้ใช้ปิดไป
    //                console.log("interim:  " + interim_transcript); 
    //                console.log("final:    " + final_transcript);
    
                    if(settings.final_transcript[k].length > 0) { // นับความยาวข้อความ ถ้ามากกว่า 0 แสดงว่ามีค่า
                        // ตัวแปร final_transcript คือค่าข้อความที่ได้ เอาไปใช้งานต่อได้
                        settings.transcript[k].val(settings.final_transcript[k]); // แสดงค่าใน textarea 
                    }
                };
    
    
                // กำหนดการทำงานปุ่ม เริ่มพิมพ์ด้วยเสียง
                settings.btnSpeakObj[k].click(function(e) {
                    e.preventDefault();
                    
                    // การจดจำเสียงกำลังทำงานอยู่หรือไม่ กดครั้งแรก จะยังไม่ทำงาน
                    if (settings.recognizing) { // ภ้าทำงานอยู่ เมื่อกดก็จะเป็นหยุด
                        recognition.stop();  // ให้หยุดการจัดจำเสียง
                        settings.btnSpeakObj[k].find(".input-group-text")
                        .removeClass('text-danger text-warning text-success'); // เปลี่ยนข้อความปุ่มกดให้เป็นค่าเริ่มต้น
                        settings.recognizing = false;  // เปลี่ยนสถานะว่าหยุดทำงาน
                    } else { // ถ้ากดแล้วสถานะการจดจำเสียงหยุดอยู่ ให้ทำงาน
                        settings.final_transcript[k] = ''; // กำหนดตัวแปรเก็บข้อความเป็นค่าว่างก่อน
    
                        // ขออนุญาตใช้งานการจดจำเสียงและเริ่มใช้งาน
                        recognition.start();
                        
                        // แจ้งคำแนะนำว่าให้ กด allow หรือตกลง เพื่ออนุญาตให้ใช้งาน Microphone
                        settings.labelInstruction[k].slideDown('fast').html('Allow the browser to use your Microphone');
                        settings.btnSpeakObj[k].find(".input-group-text")
                        .removeClass("text-success").addClass('text-warning'); // เปลี่ยนสีปุ่ม สำหรับรอคำสั่งเสียงพูด
                        settings.transcript[k].val(''); // แสดงข้อความเป็นค่าว่าง 
                    }
                });

                // ภ้ากดปุ่ม reset ข้อความ
                settings.btnResetObj[k].click(function(e) {
                  e.preventDefault();
                  interim_transcript = '';
                  settings.final_transcript[k] = '';
                  settings.transcript[k].val(''); // แสดงข้อความเป็นค่าว่าง 		
                });                      

            }

        });
      
    };
 
})(jQuery);
 
แล้วเรียกใช้งานเป็น
 
<input type="text" class="form-control use-voice" name="news_title"
            autocomplete="off" value="" required>    

<script src="https://unpkg.com/jquery@3.3.1/dist/jquery.min.js"></script>
<script src="jquery.type4me.js"></script>
<script type="text/javascript">
$(function(){
     $(".use-voice").type4me();
});
</script>
 
หรือสร้างเป็น JavaScript Minifier เพื่อให้มีขนาดเล็กไว้ใช้งานก็ได้ ดาวน์โหลด 
 
วิธีใช้งาน
 
<input type="text" class="form-control use-voice" name="news_title"
            autocomplete="off" value="" required>    

<script src="https://unpkg.com/jquery@3.3.1/dist/jquery.min.js"></script>
<script src="jquery.type4me.min.js"></script>
<script type="text/javascript">
$(function(){
     $(".use-voice").type4me();
});
</script>
 
เราสามารถปรับให้รองรับภาษา สมมติเป็นจีน ได้ดังนี้
 
<script type="text/javascript">
$(function(){
     $(".use-voice").type4me({
      language:'cmn-Hans-CN' // จีนกลาง (จีนแผ่นดินใหญ่) เพิ่มเติม http://niik.in/558
     });
});
</script>
 
ตัวอย่างผลลัพธ์
 

 
 
ทดสอบพูดภาษาจีนกลาง ใน DEMO 2
 
หวังว่าเนื้อหา และแนวทางข้างต้น จะเป็นประโยชน์สำหรับประยุกต์ใช้งานต่อไปได้





กด Like หรือ Share เป็นกำลังใจ ให้มีบทความใหม่ๆ เรื่อยๆ น่ะครับ







เนื้อหาที่เกี่ยวข้อง









URL สำหรับอ้างอิง











เว็บไซต์ของเราให้บริการเนื้อหาบทความสำหรับนักพัฒนา โดยพึ่งพารายได้เล็กน้อยจากการแสดงโฆษณา โปรดสนับสนุนเว็บไซต์ของเราด้วยการปิดการใช้งานตัวปิดกั้นโฆษณา (Disable Ads Blocker) ขอบคุณครับ