|
|
@@ -3,12 +3,14 @@ package cn.i2edu.speech_plugin
|
|
|
import android.app.Activity
|
|
|
import android.content.Context
|
|
|
import android.text.TextUtils
|
|
|
-import android.widget.Toast
|
|
|
import cn.i2edu.dubbing_lib.bean.SimpleWord
|
|
|
-import cn.i2edu.dubbing_lib.util.AudioEvaluatorUtil
|
|
|
-import cn.i2edu.dubbing_lib.util.EvaluatorCallBack
|
|
|
+import cn.i2edu.dubbing_lib.util.ChivoxAudioEvaluatorUtil
|
|
|
+import cn.i2edu.dubbing_lib.util.ChivoxEvaluatorCallBack
|
|
|
import cn.i2edu.speech_plugin.audioUtils.audioEvaluator.resultParse.ReadSentenceResult
|
|
|
import cn.i2edu.speech_plugin.audioUtils.audioEvaluator.resultParse.XmlResultParser
|
|
|
+import cn.i2edu.speech_plugin.model.chivox.ChivoxResult
|
|
|
+import cn.i2edu.speech_plugin.util.IFlyAudioEvaluatorUtil
|
|
|
+import cn.i2edu.speech_plugin.util.IFlyEvaluatorCallBack
|
|
|
import com.alibaba.fastjson.JSON
|
|
|
import com.googlecode.mp4parser.authoring.Movie
|
|
|
import com.googlecode.mp4parser.authoring.Track
|
|
|
@@ -25,136 +27,168 @@ import io.flutter.plugin.common.MethodChannel.MethodCallHandler
|
|
|
import io.flutter.plugin.common.MethodChannel.Result
|
|
|
import io.flutter.plugin.common.PluginRegistry.Registrar
|
|
|
import java.io.File
|
|
|
+import java.io.FileInputStream
|
|
|
import java.io.RandomAccessFile
|
|
|
import java.util.*
|
|
|
+import com.chivox.AIEngine.*
|
|
|
|
|
|
-class SpeechPlugin: MethodCallHandler {
|
|
|
+class SpeechPlugin : MethodCallHandler {
|
|
|
|
|
|
companion object {
|
|
|
private lateinit var context: Context
|
|
|
private lateinit var channel: MethodChannel
|
|
|
private var evaluatorType: Int = 0
|
|
|
+ private var TAG: String = "SpeechPlugin"
|
|
|
|
|
|
@JvmStatic
|
|
|
fun registerWith(registrar: Registrar) {
|
|
|
if (registrar.activity() == null) return
|
|
|
+ System.loadLibrary("aiengine")
|
|
|
channel = MethodChannel(registrar.messenger(), "speech_plugin")
|
|
|
context = registrar.activeContext()
|
|
|
channel.setMethodCallHandler(SpeechPlugin())
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- override fun onMethodCall(call: MethodCall, result: Result) {
|
|
|
- if (call.method == "getPlatformVersion") {
|
|
|
- result.success("Android ${android.os.Build.VERSION.RELEASE}")
|
|
|
- } else if (call.method == "initSpeechSdk") {
|
|
|
- SpeechUtility.createUtility(context, SpeechConstant.APPID +"=5da1549c")
|
|
|
- result.success(true)
|
|
|
- } else if (call.method == "evaluatorByAudio") {
|
|
|
- val pathEvaluatorDecode = call.argument<String>("pathEvaluatorDecode")!!
|
|
|
- val index = call.argument<Int>("index")!!
|
|
|
- val videoId = call.argument<String>("videoId")!!
|
|
|
- val recordPath = call.argument<String>("recordPath")!!
|
|
|
- val en = call.argument<String>("en")!!
|
|
|
- evaluatorType = call.argument<Int>("evaluatorType")!!
|
|
|
+ override fun onMethodCall(call: MethodCall, result: Result) {
|
|
|
+ when {
|
|
|
+ call.method == "getPlatformVersion" -> result.success("Android ${android.os.Build.VERSION.RELEASE}")
|
|
|
+ call.method == "initSpeechSdk" -> {
|
|
|
+ SpeechUtility.createUtility(context, SpeechConstant.APPID + "=5da1549c")
|
|
|
+ result.success(true)
|
|
|
+ }
|
|
|
+ call.method == "evaluatorByAudio" -> {
|
|
|
+ val pathEvaluatorDecode = call.argument<String>("pathEvaluatorDecode")!!
|
|
|
+ val index = call.argument<Int>("index")!!
|
|
|
+ val videoId = call.argument<String>("videoId")!!
|
|
|
+ val recordPath = call.argument<String>("recordPath")!!
|
|
|
+ val en = call.argument<String>("en")!!
|
|
|
+ val sdkType = call.argument<Int>("sdkType")!!
|
|
|
+ evaluatorType = call.argument<Int>("evaluatorType")!!
|
|
|
|
|
|
- evaluatorRecord(pathEvaluatorDecode, index, recordPath, en, false)
|
|
|
- } else if (call.method == "evaluatorByMp4") {
|
|
|
- val pathEvaluatorDecode = call.argument<String>("pathEvaluatorDecode")!!
|
|
|
- val index = call.argument<Int>("index")!!
|
|
|
- val videoId = call.argument<String>("videoId")!!
|
|
|
- val recordPath = call.argument<String>("recordPath")!!
|
|
|
- val en = call.argument<String>("en")!!
|
|
|
- evaluatorType = call.argument<Int>("evaluatorType")!!
|
|
|
+ evaluatorRecord(pathEvaluatorDecode, index, recordPath, en, false, if (sdkType == 1) SpeechSdk.Chivox else SpeechSdk.IFly)
|
|
|
+ }
|
|
|
+ call.method == "evaluatorByMp4" -> {
|
|
|
+ val pathEvaluatorDecode = call.argument<String>("pathEvaluatorDecode")!!
|
|
|
+ val index = call.argument<Int>("index")!!
|
|
|
+ val videoId = call.argument<String>("videoId")!!
|
|
|
+ val recordPath = call.argument<String>("recordPath")!!
|
|
|
+ val en = call.argument<String>("en")!!
|
|
|
+ val sdkType = call.argument<Int>("sdkType")!!
|
|
|
+ evaluatorType = call.argument<Int>("evaluatorType")!!
|
|
|
|
|
|
- evaluatorVideoRecord(pathEvaluatorDecode, index, videoId, recordPath, en)
|
|
|
- } else {
|
|
|
- result.notImplemented()
|
|
|
+ evaluatorVideoRecord(pathEvaluatorDecode, index, videoId, recordPath, en, if (sdkType == 1) SpeechSdk.Chivox else SpeechSdk.IFly)
|
|
|
+ }
|
|
|
+ else -> result.notImplemented()
|
|
|
+ }
|
|
|
}
|
|
|
- }
|
|
|
|
|
|
- private fun evaluatorVideoRecord(pathEvaluatorDecode: String, index: Int, videoId: String, recordPath: String, en: String) {
|
|
|
- try {
|
|
|
- val movie = MovieCreator.build (recordPath)
|
|
|
- val audioTracks = arrayListOf<Track>()
|
|
|
- for (t in movie.tracks){
|
|
|
- if (t.handler == "soun") {
|
|
|
- audioTracks.add(t)
|
|
|
+ private fun evaluatorVideoRecord(pathEvaluatorDecode: String, index: Int, videoId: String, recordPath: String, en: String, sdk: SpeechSdk) {
|
|
|
+ try {
|
|
|
+ val movie = MovieCreator.build(recordPath)
|
|
|
+ val audioTracks = arrayListOf<Track>()
|
|
|
+ for (t in movie.tracks) {
|
|
|
+ if (t.handler == "soun") {
|
|
|
+ audioTracks.add(t)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ val result = Movie()
|
|
|
+ if (audioTracks.size > 0) {
|
|
|
+ val array = arrayOfNulls<Track>(audioTracks.size)
|
|
|
+ audioTracks.toArray(array)
|
|
|
+ result.addTrack(AppendTrack(*array))
|
|
|
+ }
|
|
|
+ val out = DefaultMp4Builder().build(result)
|
|
|
+ try {
|
|
|
+ val fc = RandomAccessFile("$pathEvaluatorDecode/${videoId}_$index.aac", "rw").channel
|
|
|
+ out.writeContainer(fc)
|
|
|
+ fc.close()
|
|
|
+ evaluatorRecord(pathEvaluatorDecode, index, "$pathEvaluatorDecode/${videoId}_$index.aac", en, true, sdk)
|
|
|
+ } catch (e: Exception) {
|
|
|
+ e.printStackTrace()
|
|
|
+ }
|
|
|
+ } catch (e: Exception) {
|
|
|
+ e.printStackTrace()
|
|
|
}
|
|
|
- }
|
|
|
- val result = Movie()
|
|
|
- if (audioTracks.size > 0) {
|
|
|
- val array = arrayOfNulls<Track>(audioTracks.size)
|
|
|
- audioTracks.toArray(array)
|
|
|
- result.addTrack(AppendTrack(*array))
|
|
|
- }
|
|
|
- val out = DefaultMp4Builder().build(result)
|
|
|
- try {
|
|
|
- val fc = RandomAccessFile("$pathEvaluatorDecode/${videoId}_$index.aac", "rw").channel
|
|
|
- out.writeContainer(fc)
|
|
|
- fc.close()
|
|
|
- evaluatorRecord(pathEvaluatorDecode, index, "$pathEvaluatorDecode/${videoId}_$index.aac", en, true)
|
|
|
- } catch ( e: Exception) {
|
|
|
- e.printStackTrace()
|
|
|
- }
|
|
|
- }catch (e: Exception) {
|
|
|
- e.printStackTrace()
|
|
|
}
|
|
|
- }
|
|
|
|
|
|
- private fun evaluatorRecord(pathEvaluatorDecode: String, index: Int, recordPath: String, en: String, isVideo: Boolean) {
|
|
|
- val dir = File(pathEvaluatorDecode)
|
|
|
- if (!dir.exists()) dir.mkdirs()
|
|
|
- val decodePath = pathEvaluatorDecode + UUID.randomUUID().toString() + ".pcm"
|
|
|
- AudioEvaluatorUtil.getInstance(context = context)
|
|
|
- .setEvaluatorCallBack(object : EvaluatorCallBack {
|
|
|
- override fun onResult(result: EvaluatorResult) {
|
|
|
- (context as Activity).runOnUiThread {
|
|
|
- if (isVideo) {
|
|
|
- try {
|
|
|
- File(recordPath).delete()
|
|
|
- } catch (e: java.lang.Exception) {
|
|
|
- e.printStackTrace()
|
|
|
- }
|
|
|
- }
|
|
|
- val builder = StringBuilder()
|
|
|
- builder.append(result.resultString)
|
|
|
- if (!TextUtils.isEmpty(builder)) {
|
|
|
- val resultParser = XmlResultParser()
|
|
|
- val parseResult = resultParser.parse(builder.toString()) as ReadSentenceResult
|
|
|
-// Toast.makeText(context,
|
|
|
-// "识别成功,结果:${if (parseResult.is_rejected) "您在乱读哦" else "您没乱读结果为:${parseResult.total_score}"}", Toast.LENGTH_SHORT).show()
|
|
|
- val formatWords = arrayListOf<SimpleWord>()
|
|
|
- for (sentence in parseResult.sentences) {
|
|
|
- val words = sentence.words
|
|
|
- for (word in words) {
|
|
|
- // 过滤掉sil、 silv 表示静音, fil 表示噪音
|
|
|
- if (word.content == "sil" || word.content == "silv" || word.content == "fil")
|
|
|
- continue
|
|
|
- formatWords.add(SimpleWord(word.content, word.total_score))
|
|
|
- }
|
|
|
- }
|
|
|
+ private fun evaluatorRecord(pathEvaluatorDecode: String, index: Int, recordPath: String, en: String, isVideo: Boolean, sdk: SpeechSdk) {
|
|
|
+ val dir = File(pathEvaluatorDecode)
|
|
|
+ if (!dir.exists()) dir.mkdirs()
|
|
|
+ val decodePath = pathEvaluatorDecode + UUID.randomUUID().toString() + ".pcm"
|
|
|
|
|
|
- channel.invokeMethod("evaluatorResult",
|
|
|
- mapOf("index" to index,"score" to (if(parseResult.is_rejected) null else parseResult.total_score), "integrity_score" to (if(parseResult.is_rejected) null else parseResult.integrity_score),
|
|
|
- "accuracy_score" to (if(parseResult.is_rejected) null else parseResult.accuracy_score), "fluency_score" to (if(parseResult.is_rejected) null else parseResult.fluency_score),
|
|
|
- "words" to JSON.toJSONString(formatWords)))
|
|
|
- } else {
|
|
|
-// Toast.makeText(context, "识别失败,结果为空", Toast.LENGTH_SHORT).show()
|
|
|
- channel.invokeMethod("evaluatorResult", mapOf("index" to index,"score" to null, "integrity_score" to null, "accuracy_score" to null, "fluency_score" to null))
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
+ if (sdk == SpeechSdk.Chivox) {
|
|
|
+ ChivoxAudioEvaluatorUtil.getInstance(context)
|
|
|
+ .setEvaluatorCallBack(object: ChivoxEvaluatorCallBack {
|
|
|
+ override fun onResult(result: ChivoxResult) {
|
|
|
+ (context as Activity).runOnUiThread {
|
|
|
+ val formatWords = arrayListOf<SimpleWord>()
|
|
|
+ for (detail in result.result.details) {
|
|
|
+ formatWords.add(SimpleWord(detail.char, detail.score / 20.0f))
|
|
|
+ }
|
|
|
+ channel.invokeMethod("evaluatorResult",
|
|
|
+ mapOf("index" to index, "score" to result.result.overall / 20.0f, "integrity_score" to result.result.integrity / 20.0f,
|
|
|
+ "accuracy_score" to result.result.accuracy / 20.0f, "fluency_score" to result.result.fluency.overall / 20.0f,
|
|
|
+ "words" to JSON.toJSONString(formatWords)))
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- override fun onError(error: SpeechError) {
|
|
|
- (context as Activity).runOnUiThread {
|
|
|
- // Toast.makeText(activity.applicationContext, "识别失败,错误描述:${error.errorDescription},错误码:${error.errorCode}",
|
|
|
-// Toast.LENGTH_SHORT).show()
|
|
|
- channel.invokeMethod("evaluatorResult", mapOf("index" to index,"score" to null))
|
|
|
- }
|
|
|
- }
|
|
|
- })
|
|
|
- ?.startEvaluator(en, recordPath, decodePath, evaluatorType)
|
|
|
- }
|
|
|
+ override fun onError(message: String) {
|
|
|
+ (context as Activity).runOnUiThread {
|
|
|
+ channel.invokeMethod("evaluatorResult", mapOf("index" to index, "score" to null, "integrity_score" to null, "accuracy_score" to null, "fluency_score" to null))
|
|
|
+ }
|
|
|
+ }
|
|
|
+ })
|
|
|
+ ?.startEvaluator(en, recordPath, decodePath)
|
|
|
+ } else {
|
|
|
+ IFlyAudioEvaluatorUtil.getInstance(context = context)
|
|
|
+ .setEvaluatorCallBack(object : IFlyEvaluatorCallBack {
|
|
|
+ override fun onResult(result: EvaluatorResult) {
|
|
|
+ (context as Activity).runOnUiThread {
|
|
|
+ if (isVideo) {
|
|
|
+ try {
|
|
|
+ File(recordPath).delete()
|
|
|
+ } catch (e: java.lang.Exception) {
|
|
|
+ e.printStackTrace()
|
|
|
+ }
|
|
|
+ }
|
|
|
+ val builder = StringBuilder()
|
|
|
+ builder.append(result.resultString)
|
|
|
+ if (!TextUtils.isEmpty(builder)) {
|
|
|
+ val resultParser = XmlResultParser()
|
|
|
+ val parseResult = resultParser.parse(builder.toString()) as ReadSentenceResult
|
|
|
+ val formatWords = arrayListOf<SimpleWord>()
|
|
|
+ for (sentence in parseResult.sentences) {
|
|
|
+ val words = sentence.words
|
|
|
+ for (word in words) {
|
|
|
+ // 过滤掉sil、 silv 表示静音, fil 表示噪音
|
|
|
+ if (word.content == "sil" || word.content == "silv" || word.content == "fil")
|
|
|
+ continue
|
|
|
+ formatWords.add(SimpleWord(word.content, word.total_score))
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
+ channel.invokeMethod("evaluatorResult",
|
|
|
+ mapOf("index" to index, "score" to (if (parseResult.is_rejected) null else parseResult.total_score), "integrity_score" to (if (parseResult.is_rejected) null else parseResult.integrity_score),
|
|
|
+ "accuracy_score" to (if (parseResult.is_rejected) null else parseResult.accuracy_score), "fluency_score" to (if (parseResult.is_rejected) null else parseResult.fluency_score),
|
|
|
+ "words" to JSON.toJSONString(formatWords)))
|
|
|
+ } else {
|
|
|
+ channel.invokeMethod("evaluatorResult", mapOf("index" to index, "score" to null, "integrity_score" to null, "accuracy_score" to null, "fluency_score" to null))
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ override fun onError(error: SpeechError) {
|
|
|
+ (context as Activity).runOnUiThread {
|
|
|
+ channel.invokeMethod("evaluatorResult", mapOf("index" to index, "score" to null))
|
|
|
+ }
|
|
|
+ }
|
|
|
+ })
|
|
|
+ ?.startEvaluator(en, recordPath, decodePath, evaluatorType)
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
+
|
|
|
+enum class SpeechSdk {
|
|
|
+ IFly, Chivox,
|
|
|
+}
|