07 August 2013

เปลี่ยนเสียงพูดให้กลายเป็นข้อความด้วย Voice Recognition

Updated on


        Voice Recognition (บ้างก็เรียกว่า Speech Recognition) หรือที่รู้จักกันในนามของฟีเจอร์สั่งงานด้วยเสียง ซึ่งบนแอนดรอยด์ถือเป็นฟีเจอร์ปกติที่มีอยู่แทบทุกอุปกรณ์แอนดรอยด์อยู่แล้ว และการเรียกใช้งานก็โคตรจะง่ายเลยล่ะ

        ซึ่งบนแอนดรอยด์จะรองรับการเรียกใช้งานความสามารถนี้อยู่แล้ว โดยไม่จำเป็นต้องเขียนโค้ดใดๆเพื่อเรียกใช้งาน Voice Recognition ภายในแอพ แต่จะเป็นการเรียกหน้าต่าง Voice Recognition ขึ้นมาแทน

เรื่อง (ที่ควรจะ) น่ารู้

        Voice Recognition บนแอนดรอยด์แทบทุกเครื่องในทุกวันนี้ เบื้องหลังของมันก็คือ Google นั่นเอง ซึ่งทาง Google ก็ได้พัฒนาระบบตัวนี้มาตลอดทุกเวอร์ชัน ซึ่งเมื่อก่อนนั้นจะมีข้อจำกัดที่ว่าเวลาใช้งานจะต้องต่ออินเตอร์เน็ตเท่านั้น เพราะว่าเสียงที่พูดจะถูกส่งขึ้นไปประมวลผลบนเซิฟเวอร์แล้วส่งผลลัพธ์ที่ได้กลับมา ในตอนนั้นการทำ Offline Voice Recognition ยังไม่อำนวยมากนัก แถมยังไม่มีภาษาไทยด้วย

        จนมาวันหนึ่ง Google ก็ได้ประกาศกร้าวว่ารองรับภาษาไทยแล้ว​ (ก็เฮสิครับ) จึงทำให้นักพัฒนาหลายๆคนสามารถใช้ประโยชน์จาก Voice Recognition ได้สะดวกขึ้น จากเดิมที่ต้องใช้เฉพาะภาษาอังกฤษ เพียงแค่ไปตั้งค่าใน Settings > Language and input > Voice input ก็สามารถเลือกภาษาไทยเพิ่มได้เลย


        ล่าสุดนี้บนแอนดรอยด์ก็ได้มี Offline Voice Recognition เป็นที่เรียบร้อยแล้ว โดยจะต้องดาวน์โหลดข้อมูลที่ใช้ในการวิเคราะห์มาเก็บไว้ในเครื่องก่อนถึงจะทำงานได้ ซึ่งที่น่าเสียดายก็คือในตอนนี้ภาษาไทยยังทำ Offline Voice Recognition ไม่ได้จ้า ต้องใช้แบบต่ออินเตอร์เน็ตไปก่อน


        แต่ก็ดีกว่าไม่มีให้ใช้เนอะ

การใช้งานที่โคตรจะง่าย

        ในการทำ Text To Speech จะต้องเรียกใช้งานผ่านคลาส TextToSpeech แต่สำหรับ Voice Recognition นั้นไม่ต้องใช้คลาสอะไรเกี่ยวกับมันเลย เพียงแค่เรียกใช้งานคำสั่ง startActivityForResult(...) ก็สามารถทำงานได้แล้ว

// MainActivity.kt

import android.content.Intent
import android.speech.RecognizerIntent
import android.support.v7.app.AppCompatActivity

class MainActivity : AppCompatActivity() {

    companion object {
        const val REQUEST_CODE_VOICE_RECOGNITION = 1001
    }

    private fun callVoiceRecognition() {
        val intent = Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH)
        startActivityForResult(intent, REQUEST_CODE_VOICE_RECOGNITION)
    }

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)
        // Result will return here
    }
    ...
}

        แค่นี้แหละ!! ซึ่ง Request Code ที่กำหนดเป็น 10001 ไม่ใช่เลขตายตัว กำหนดเป็นเลขอะไรก็ได้ เอาไว้เช็คตอนขากลับเฉยๆว่าข้อมูลที่ส่งกลับมาเป็นอันเดียวกับตอนที่ส่งไปในตอนแรกหรือป่าว

        ทีนี้ก็เหลือแค่การดึงข้อมูลผลลัพธ์ที่ได้นั่นเอง ก่อนอื่นต้องเช็ค Request Code ว่า Request Code เป็นค่าที่ส่งไปใช่มั้ย และ Result Code ที่ได้คือ OK ใช่มั้ย จากนั้นก็ค่อยดึงข้อมูลที่ส่งกลับมา

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    super.onActivityResult(requestCode, resultCode, data)
    if (requestCode == REQUEST_CODE_VOICE_RECOGNITION && resultCode == Activity.RESULT_OK) {
        val resultList = data?.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS)
        // Do something with resultList
    }
}

        จะเห็นว่าผลลัพธ์ที่ได้นั้นเป็น String Array List เพราะว่าผลลัพธ์ไม่ได้แม่นยำ 100% เสมอไป ดังนั้นอันไหนที่น่าจะใกล้เคียงก็จะถูกส่งกลับมาด้วย ซึ่งเรียงลำดับตามใกล้เคียง โดย Index ที่ 0 คือตัวที่น่าจะใกล้เคียงที่สุด

        สมมติว่าเจ้าของบล็อกพูดไปว่า "Digital Smart Box" ผลลัพธ์ที่ได้กลับมาก็จะมีให้เลือกดังนี้

Digital smart box
digital smart box
Digital smart lock
Digital Smart Watch
digital smart lock

        ถ้าไม่คิดอะไรมากก็ใช้ตัวแรกสุดน่ะแหละครับ เพราะเป็นตัวที่น่าจะถูกต้องมากที่สุดแล้ว พอได้ข้อความเป็น String แล้วก็เอาไปใช้ทำอะไรตามใจชอบเลยครับ

กำหนดที่ต้องการได้ด้วยนะ

        สมมติว่าผู้ที่หลงเข้ามาอ่านอยากให้ Voice Recognition รับข้อความเป็นภาษาไทย ถึงแม้ว่าเครื่องนั้นๆจะใช้เป็นภาษาอังกฤษอยู่ก็ตาม สามารถกำหนดค่าเข้าไปใน Intent ได้ครับ เพื่อเลือกภาษาที่ต้องการ

val intent = Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH)
intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, "th-TH")
startActivityForResult(intent, REQUEST_CODE_VOICE_RECOGNITION)

        เวลาเรียกขึ้นมาก็จะเห็นว่ามีห้อยท้ายบรรทัดว่าเป็นภาษาอะไรอยู่ด้วย


        โดยปกติแล้วจะ Default เป็นภาษาอังกฤษให้ ในกรณีที่ไม่ใช่ภาษาไทยให้กำหนดภาษาจากคลาส Locale ได้เลย เพราะภาษาไทยไม่มีอยู่ในคลาส Locale ก็เลยต้องใส่เป็น String แบบนั้นไปตรงๆ

val intent = Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH)
intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, Locale.JAPAN.displayName)
startActivityForResult(intent, REQUEST_CODE_VOICE_RECOGNITION)

        เสร็จเรียบร้อย