用Kotlin開發android平臺語音識別語義理解應用

Kotlin開發android平臺語音識別,語義理解應用(olamisdk

轉載請注明CSDN博文地址:http://blog.csdn.net/ls0609/article/details/75084994

本文使用Kotlin開發Android平臺的一個語音識別方面的應用,用的是歐拉密開放平臺olamisdk。

1.Kotlin簡介

Kotlin是由JetBrains創建的基于JVM的編程語言,IntelliJ正是JetBrains的杰作,而android Studio是

基于IntelliJ修改而來的。Kotlin是一門包含很多函數式編程思想的面向對象編程語言。

后來了解到Kotlin原來是以一個島的名字命名的(Котлин),它是一門靜態類型編程語言,支持JVM平臺,android平臺,瀏覽器js運行環境,本地機器碼等。支持與Java,Android 100%完全互操作。Kotlin生來就是為了彌補Java缺失的現代語言的特性,并極大的簡化了代碼,使得開發者可以編寫盡量少的樣板代碼。

2.Kotlin,java,Swift簡單比較

1.輸出Hello,World!

JAVA:System.out.println("Hello,World!");

Kotlin:println("Hello,World!")

Swift:print("Hello,World!")

2.變量和常量

Java:intmVariable =10;

mVariable =20;

staticfinalintmConstant =10;

Kotlin:varmVariable =10

mVariable =20

val mConstant =10

Swift:varmVariable =10

mVariable =20

letmConstant =10

感覺Swift和Kotlin比Java簡潔,Kotlin和swift很像。

3.強制類型轉換

Swift:

letlabel ="Hello world "

letwidth =80

letwidthLabel = label + String(width)

Kotlin:

vallabel ="Hello world"

valwidth =80

valwidthLabel =label + width

4數組

Swift:

vartempList = ["one","two","three"]

tempList[1] ="zero"

Kotlin:

valtempList = arrayOf("one","two","three")

tempList[1] ="zero"

5.函數

Swift:func greet(_ name:String,_

day:String)->String{

return"Hello

\(name),today is \(day)."}

greet("Bob","Tuesday")

Kotlin:

fun greet(name:String, day:String):String{

return"Hello

$name, today is $day."}

greet("Bob","Tuesday")

6.類聲明及用法

Swift:

聲明:classShape{

var numberOfSides =0

func simpleDescription()-> String {

return"A shape

with \(numberOfSides) sides."

}

}

用法:varshape = Shape()

shape.numberOfSides =7

var shapeDescription =shape.simpleDescription()

Kotlin:

聲明:classShape{

var numberOfSides =0

fun simpleDescription() ="A shape

with $numberOfSides sides."

}

用法:var shape = Shape()

shape.numberOfSides =7

var shapeDescription= shape.simpleDescription()

可見,Kotlin和Swift好像,現代語言的特征,比java這樣的高級語言更加簡化,更貼近自然語言

3.開發環境

本文使用的是android studio2.0版本,啟動androd studio。

如下圖在configure下拉菜單中選擇plugins,在搜索框中搜索Kotlin,找到結果列表中的”Kotlin”插件。


如下圖,找了一張還沒有安裝kotlin插件的圖


點擊右側intall,安裝后重啟studio.

4.新建android項目

你可以像以前使用android stuio一樣新建一個andoid項目,建立一個activity。本文用已經完成的一個demo來做示范。

如下圖是一個stuio的demo工程


選擇MainActivity和MessageConst兩個java文件,然后選擇導航欄上的code,在下拉菜單中選擇convertJavafile to kotlin file


系統會自動進行轉化,轉化完后會生成對應的MainActivity.kt MessageConst.kt文件,打開MainActivity.kt,編譯器上方會提示”Kotlin not configured”,點擊一下Configure按鈕,IDE就會自動幫我們配置好了!

將兩個kt文件復制到src/kotlin目錄下,如下圖


轉化后的文件,也許有些語法錯誤,需要按照kotlin的語法修改。

環境配置好后,來看下gradle更新有哪些區別

project的gradle代碼如下:

buildscript {

ext.kotlin_version ='1.1.3-2'

repositories {

jcenter()

}

dependencies {

classpath'com.android.tools.build:gradle:2.0.0'

//此處多了kotlin插件依賴

classpath"org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"

}

}

allprojects {

repositories {

jcenter()

}

}

再來看看某個module的gradle代碼:

apply plugin:'com.android.application'

apply plugin:'kotlin-android'//此處多了這條插件聲明

android {

compileSdkVersion14

buildToolsVersion"24.0.0"

defaultConfig {

applicationId"com.olami"

minSdkVersion8

targetSdkVersion14

}

buildTypes {

release {

minifyEnabledfalse

proguardFilesgetDefaultProguardFile('proguard-android.txt'),'proguard-rules.txt'

}

}

sourceSets {

main.java.srcDirs +='src/main/kotlin'//生成的***.kt文件需要copy到對應的目錄

}

}

dependencies {

compile'com.android.support:support-v4:18.0.0'

compile files('libs/voicesdk_android.jar')

compile"org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"http://此處多了kotlin包的依賴

}

repositories {

mavenCentral()

}

如上所示,如果不是通過轉化的方式新建kotlin工程,則需要自己按照上面的gradle中增加的部分配置好。

5.olami語音識別應用

先貼一張識別后的效果圖:


在MainActivity.kt中

override funonCreate(savedInstanceState: Bundle?) {

super.onCreate(savedInstanceState)

setContentView(R.layout.activity_main)

initHandler()//初始化handler用于處理消息

initView()//初始化view控件,比如點擊開始錄音的button

initViaVoiceRecognizerListener()//初始化語音識別回調,用于返回錄音狀態和識別結果

init()//初始化語音識別對象

}

fun init()

{

initHandler()

//定義olami語音識別對象

mOlamiVoiceRecognizer =OlamiVoiceRecognizer(this@MainActivity)

valtelephonyManager =this.getSystemService(

Context.TELEPHONY_SERVICE) as TelephonyManager

valimei = telephonyManager.deviceId

mOlamiVoiceRecognizer!!.init(imei)

//set null if you do not want to notify

olami server.

//設置回調,用于更新錄音狀態和數據等的界面

mOlamiVoiceRecognizer!!.setListener(mOlamiVoiceRecognizerListener)

//設置支持的語言類型,默認請設置簡體中文

mOlamiVoiceRecognizer!!.setLocalization(

OlamiVoiceRecognizer.LANGUAGE_SIMPLIFIED_CHINESE)

mOlamiVoiceRecognizer!!.setAuthorization("51a4bb56ba954655a4fc834bfdc46af1",

"asr","68bff251789b426896e70e888f919a6d","nli")

//注冊Appkey,在olami官網注冊應用后生成的appkey

//注冊api,請直接填寫“asr”,標識語音識別類型

//注冊secret,在olami官網注冊應用后生成的secret

mOlamiVoiceRecognizer!!.setVADTailTimeout(2000)

//錄音時尾音結束時間,建議填//2000ms

mOlamiVoiceRecognizer!!.setLatitudeAndLongitude(

31.155364678184498,121.34882432933009)

//設置經緯度信息,不愿上傳位置信息,可以填0

}

代碼比較簡單,點擊開始錄音button后,啟動錄音,在OlamiVoiceRecognizerListener中回調處理,然后通過handler發送消息用于更新界面。

來看一下初始化view的代碼,看看跟java方式書寫有哪些不同

private fun initView()

{

mBtnStart = findViewById(R.id.btn_start) asButton

mBtnStop = findViewById(R.id.btn_stop) as Button

mBtnCancel = findViewById(R.id.btn_cancel) asButton

mBtnSend = findViewById(R.id.btn_send) as Button

mInputTextView = findViewById(R.id.tv_inputText) asTextView

mEditText = findViewById(R.id.et_content) asEditText

mTextView = findViewById(R.id.tv_result) asTextView

mTextViewVolume = findViewById(R.id.tv_volume) asTextView

mBtnStart!!.setOnClickListener{

if (mOlamiVoiceRecognizer != null)

mOlamiVoiceRecognizer!!.start()

}

mBtnStop!!.setOnClickListener{

if (mOlamiVoiceRecognizer != null)

mOlamiVoiceRecognizer!!.stop()

mBtnStart!!.text="開始"

Log.i("led","MusicActivity mBtnStop onclick開始")

}

mBtnCancel!!.setOnClickListener{

if (mOlamiVoiceRecognizer != null)

mOlamiVoiceRecognizer!!.cancel()

}

mBtnSend!!.setOnClickListener{

if (mOlamiVoiceRecognizer != null)

mOlamiVoiceRecognizer!!.sendText(mEditText!!.text.toString())

mInputTextView!!.text="輸入: "+ mEditText!!.text

}

}

是不是感覺代碼更簡練了?

下面兩句賦值,效果相同,第二句可以用id之間進行文本賦值,比以前簡練好多。

mInputTextView!!.text="輸入: "+ mEditText!!.text

tv_inputText.text="輸入: "+ et_content.text

再來看看handler:

private funinitHandler() {

mHandler = object : Handler() {

override fun handleMessage(msg:Message) {

when (msg.what) {

MessageConst.CLIENT_ACTION_START_RECORED

-> mBtnStart!!.text

="錄音中"

MessageConst.CLIENT_ACTION_STOP_RECORED -> mBtnStart!!.text

="識別中"

MessageConst.CLIENT_ACTION_CANCEL_RECORED-> {

mBtnStart!!.text="開始"

mTextView!!.text="已取消"

}

MessageConst.CLIENT_ACTION_ON_ERROR-> {

mTextView!!.text="錯誤代碼:"+ msg.arg1

mBtnStart!!.text="開始"

}

MessageConst.CLIENT_ACTION_UPDATA_VOLUME

-> mTextViewVolume!!.text

="音量: "+ msg.arg1

MessageConst.SERVER_ACTION_RETURN_RESULT-> {

if (msg.obj!= null)

mTextView!!.text="服務器返回: "+ msg.obj.toString()

mBtnStart!!.text="開始"

try {

val message = msg.objas String

var input: String?= null

val jsonObject =JSONObject(message)

val jArrayNli =

jsonObject.optJSONObject("data").optJSONArray("nli")

val jObj =jArrayNli.optJSONObject(0)

var jArraySemantic:JSONArray? = null

if (message.contains("semantic")) {

jArraySemantic= jObj.getJSONArray("semantic")

input =

jArraySemantic!!.optJSONObject(0).optString("input")

} else {

input =jsonObject.optJSONObject("data")

.optJSONObject("asr").optString("result")

}

if (input != null)

mInputTextView!!.text="輸入: "+ input

} catch (e: Exception) {

e.printStackTrace()

}

}

}

}

}

}

原來的switch case的方式,變成了when***,代碼不僅簡練,更貼近現代語言,更容易理解。

上面的MessageConst.SERVER_ACTION_RETURN_RESULT時,獲取了服務器返回的結果,緊接著對這段語義進行了簡單的解析

{

? ? ? "data": {

? ? ? ? ? ? ? ? ? "asr": {

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? "result":"我要聽三國演義",

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? "speech_status":0,

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?"final":true,

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? "status":0

? ? ? ? ? ? ? ? ? ? ? },

? ? ? ? ? ? ? ? ? ?"nli": [

? ? ? ? ? ? ? ? ? ? ? ? ? ? ?{

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?"desc_obj": {

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?"result":"正在努力搜索中,請稍等",

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?"status":0

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?},

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? "semantic": [

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?{

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?"app":"musiccontrol",

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?"input":"我要聽三國演義",

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?"slots": [

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? {

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?"name":"songname",

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?"value":"三國演義"

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?],

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? "modifier": [

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? "play"

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?],

? ? ? ? ? ? ? "customer":"58df512384ae11f0bb7b487e"

? ? ? ? ? ? ? }

? ? ? ? ],

? ? ? ? ?"type":"musiccontrol"

? ? ? ?}

? ?]

},

"status":"ok"

}

1)解析出nli中type類型是musiccontrol,這是語法返回app的類型,而這個在線聽書的demo只關心musiccontrol這個app類型,其他的忽略。

2)用戶說的話轉成文字是在asr中的result中獲取

3)在nli中的semantic中,input值是用戶說的話,同asr中的result。

modifier代表返回的行為動作,此處可以看到是play就是要求播放,slots中的數據表示歌曲名稱是三國演義。

那么動作是play,內容是歌曲名稱是三國演義,在這個demo中調用

mBookUtil.searchBookAndPlay(songName,0,0);會先查詢,查詢到結果會再發播放消息要求播放,我要聽三國演義這個流程就走完了。

這段是在線聽書應用中的語義解析,詳情請看博客:http://blog.csdn.net/ls0609/article/details/71519203

6.代碼下載

https://github.com/ls0609/WebVoiceRecognize

7.相關博客

語音在線聽書博客:http://blog.csdn.net/ls0609/article/details/71519203

語音記賬demo:http://blog.csdn.net/ls0609/article/details/72765789

基于JavaScript用olamisdk實現web端語音識別語義理解(speex壓縮)

http://blog.csdn.net/ls0609/article/details/73920229

olami開放平臺語法編寫簡介:http://blog.csdn.net/ls0609/article/details/71624340

olami開放平臺語法官方介紹:https://cn.olami.ai/wiki/?mp=nli&content=nli2.html

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容