feat(asr): 集成ASR助手并升级项目依赖
- 将Gradle版本从7.3.3升级到8.6 - 升级Kotlin版本从1.6.10到2.2.0并更新相关插件 - 升级Android Gradle Plugin到7.4.2 - 集成AsrHelper替代原有的IntentRecognizeHelper进行语音识别 - 添加Nova Nova唤醒词注册功能 - 更新SDK依赖版本并添加新的Maven仓库地址 - 移除废弃的kotlin-android-extensions插件 - 优化HeaderInterceptor中的HTTP响应处理逻辑 - 统一Toast消息显示方式为扩展函数实现
这个提交包含在:
父节点
a3e87727b7
当前提交
e389f9fda8
@ -1,6 +1,5 @@
|
|||||||
apply plugin: 'com.android.application'
|
apply plugin: 'com.android.application'
|
||||||
apply plugin: 'kotlin-android'
|
apply plugin: 'kotlin-android'
|
||||||
apply plugin: 'kotlin-android-extensions'
|
|
||||||
apply plugin: 'kotlin-kapt'
|
apply plugin: 'kotlin-kapt'
|
||||||
|
|
||||||
|
|
||||||
@ -56,9 +55,6 @@ android {
|
|||||||
jniLibs.srcDirs = ['libs']
|
jniLibs.srcDirs = ['libs']
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
androidExtensions {
|
|
||||||
experimental = true
|
|
||||||
}
|
|
||||||
namespace 'com.nova.brain.glass'
|
namespace 'com.nova.brain.glass'
|
||||||
|
|
||||||
packagingOptions {
|
packagingOptions {
|
||||||
@ -80,9 +76,10 @@ dependencies {
|
|||||||
implementation 'com.google.android.material:material:1.3.0'
|
implementation 'com.google.android.material:material:1.3.0'
|
||||||
implementation "io.noties.markwon:core:4.6.2"
|
implementation "io.noties.markwon:core:4.6.2"
|
||||||
|
|
||||||
implementation ('com.rokid.security:glass3.open.sdk:2.1.5-E') {
|
implementation ('com.rokid.security:glass3.open.sdk:2.1.6-E') {
|
||||||
exclude group: "org.slf4j"
|
exclude group: "org.slf4j"
|
||||||
}
|
}
|
||||||
|
implementation 'com.rokid.security.sdk:online-speech:0.1.0'
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
package com.nova.brain.glass;
|
package com.nova.brain.glass;
|
||||||
|
|
||||||
import com.blankj.utilcode.util.Utils;
|
import com.blankj.utilcode.util.Utils;
|
||||||
|
import com.nova.brain.glass.helper.AsrHelper;
|
||||||
import com.nova.brain.glass.helper.OfflineCmdServiceHelper;
|
import com.nova.brain.glass.helper.OfflineCmdServiceHelper;
|
||||||
import com.nova.brain.glass.repository.HeaderInterceptor;
|
import com.nova.brain.glass.repository.HeaderInterceptor;
|
||||||
import com.rokid.security.glass3.open.sdk.GlassSdk;
|
import com.rokid.security.glass3.open.sdk.GlassSdk;
|
||||||
@ -42,6 +43,7 @@ public class MyApplication extends App {
|
|||||||
@Override
|
@Override
|
||||||
public void onServiceConnected() {
|
public void onServiceConnected() {
|
||||||
OfflineCmdServiceHelper.INSTANCE.init();
|
OfflineCmdServiceHelper.INSTANCE.init();
|
||||||
|
AsrHelper.INSTANCE.init();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@ -0,0 +1,178 @@
|
|||||||
|
package com.nova.brain.glass.helper
|
||||||
|
|
||||||
|
import android.util.Log
|
||||||
|
import com.nova.brain.glass.model.RecognizeAction
|
||||||
|
import com.rokid.online.speech.AsrClient
|
||||||
|
import com.rokid.online.speech.OnlineSpeechSdk
|
||||||
|
import com.rokid.online.speech.OnlineSpeechSdkConfig
|
||||||
|
import com.rokid.online.speech.open.OpenSdkAudioSource
|
||||||
|
import com.xuqm.base.extensions.showMessage
|
||||||
|
|
||||||
|
object AsrHelper : OfflineCmdListener {
|
||||||
|
|
||||||
|
private const val TAG = "AsrHelper"
|
||||||
|
|
||||||
|
// 配置信息,从 online-speech-sdk-demo 参考项目复制
|
||||||
|
private const val DOMAIN = "api-test.rokid.com"
|
||||||
|
private const val ASR_PATH = "/ar/audio/api/ws/asr/streaming"
|
||||||
|
private const val TTS_PATH = "/ar/audio/api/ws/tts"
|
||||||
|
private const val AK = ""
|
||||||
|
private const val SK = ""
|
||||||
|
private const val UID = "demo-user"
|
||||||
|
private const val DEVICE_ID = "demo-device"
|
||||||
|
|
||||||
|
// 唤醒词:Nova Nova
|
||||||
|
private const val WAKE_WORD = "Nova Nova"
|
||||||
|
private const val WAKE_WORD_PINYIN = "nou wa nou wa"
|
||||||
|
|
||||||
|
private var sdk: OnlineSpeechSdk? = null
|
||||||
|
private var asr: AsrClient? = null
|
||||||
|
private val audioSource = OpenSdkAudioSource()
|
||||||
|
|
||||||
|
private var isConnected = false
|
||||||
|
private var isMicRunning = false
|
||||||
|
|
||||||
|
// 拼接每次识别会话中的中间结果
|
||||||
|
private var currentPartial = ""
|
||||||
|
// 拼接跨多次识别的最终结果
|
||||||
|
private val sessionBuilder = StringBuilder()
|
||||||
|
|
||||||
|
/** 当前页面的场景标识,由各 Activity 在 onResume/onPause 中维护 */
|
||||||
|
var scene: String = "home"
|
||||||
|
|
||||||
|
/** goToDecisionCenter 命中时的回调,由各 Activity 在 onResume/onPause 中注册/清空 */
|
||||||
|
var onGoToDecisionCenter: ((action: RecognizeAction) -> Unit)? = null
|
||||||
|
|
||||||
|
fun init() {
|
||||||
|
val cfg = OnlineSpeechSdkConfig(
|
||||||
|
domain = DOMAIN,
|
||||||
|
ak = AK,
|
||||||
|
sk = SK,
|
||||||
|
uid = UID,
|
||||||
|
deviceId = DEVICE_ID,
|
||||||
|
asrPath = ASR_PATH,
|
||||||
|
ttsPath = TTS_PATH,
|
||||||
|
trustAllCerts = true,
|
||||||
|
staticHttpHeaders = mapOf(
|
||||||
|
"appCredential" to "userInfo",
|
||||||
|
"messageId" to "android-asr-${System.currentTimeMillis()}",
|
||||||
|
),
|
||||||
|
staticMessageHeaders = mapOf(
|
||||||
|
"appCredential" to "userInfo",
|
||||||
|
"messageId" to "android-asr-${System.currentTimeMillis()}",
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
sdk = OnlineSpeechSdk(cfg)
|
||||||
|
asr = sdk!!.createAsrClient().attachAudioSource(audioSource).also { setupAsrCallbacks(it) }
|
||||||
|
|
||||||
|
// 注册离线关键词 Nova Nova,GlassSdk 触发后启动 ASR
|
||||||
|
OfflineCmdServiceHelper.registerAsrWakeWord()
|
||||||
|
OfflineCmdServiceHelper.addOnLineListener(this)
|
||||||
|
|
||||||
|
// 自动建立 ASR 连接
|
||||||
|
asrConnect()
|
||||||
|
|
||||||
|
Log.d(TAG, "AsrHelper init done")
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun asrConnect() {
|
||||||
|
asr?.connect()
|
||||||
|
Log.d(TAG, "ASR connect() called")
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun asrStartMic() {
|
||||||
|
if (!isConnected) {
|
||||||
|
Log.w(TAG, "ASR startMic ignored: not connected")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (isMicRunning) {
|
||||||
|
Log.w(TAG, "ASR startMic ignored: mic already running")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
runCatching { asr?.startAsrWithMic() }
|
||||||
|
.onSuccess {
|
||||||
|
isMicRunning = true
|
||||||
|
Log.d(TAG, "ASR startAsrWithMic()")
|
||||||
|
}
|
||||||
|
.onFailure { Log.e(TAG, "ASR startAsrWithMic failed: ${it.message}") }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setupAsrCallbacks(asrClient: AsrClient) {
|
||||||
|
asrClient.setListener(object : AsrClient.Listener {
|
||||||
|
override fun onOpen() {
|
||||||
|
isConnected = true
|
||||||
|
Log.d(TAG, "ASR websocket open")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onStart(taskId: String) {
|
||||||
|
currentPartial = ""
|
||||||
|
sessionBuilder.clear()
|
||||||
|
Log.d(TAG, "ASR started: $taskId")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onPartialResult(taskId: String, text: String) {
|
||||||
|
// 滚动更新当前识别中间结果
|
||||||
|
currentPartial = text
|
||||||
|
Log.d(TAG, "ASR partial: $text")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onFinalResult(taskId: String, text: String) {
|
||||||
|
// 将最终结果追加拼接到会话字符串
|
||||||
|
sessionBuilder.append(text)
|
||||||
|
val fullText = sessionBuilder.toString()
|
||||||
|
isMicRunning = false
|
||||||
|
Log.d(TAG, "ASR final result: $fullText")
|
||||||
|
IntentRecognizeHelper.recognize(
|
||||||
|
text = fullText,
|
||||||
|
scence = scene,
|
||||||
|
onSuccess = { action ->
|
||||||
|
if (action.name == "goToDecisionCenter") {
|
||||||
|
onGoToDecisionCenter?.invoke(action)
|
||||||
|
} else {
|
||||||
|
"需要跳转任务列表".showMessage()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onFinished(taskId: String) {
|
||||||
|
Log.d(TAG, "ASR ended: $taskId")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onError(code: Int, message: String) {
|
||||||
|
Log.e(TAG, "ASR error code=$code msg=$message")
|
||||||
|
isMicRunning = false
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onClosed(code: Int, reason: String) {
|
||||||
|
isConnected = false
|
||||||
|
isMicRunning = false
|
||||||
|
Log.d(TAG, "ASR closed code=$code reason=$reason")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 离线关键词回调:匹配唤醒词时启动麦克风
|
||||||
|
override fun onOfflineCmd(cmd: String) {
|
||||||
|
if (cmd == WAKE_WORD) {
|
||||||
|
Log.d(TAG, "Wake word triggered, starting mic")
|
||||||
|
asrStartMic()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun close() {
|
||||||
|
OfflineCmdServiceHelper.removeOnLineListener(this)
|
||||||
|
if (isMicRunning) {
|
||||||
|
runCatching { asr?.stopAsrWithMic() }
|
||||||
|
isMicRunning = false
|
||||||
|
}
|
||||||
|
asr?.close()
|
||||||
|
sdk?.close()
|
||||||
|
asr = null
|
||||||
|
sdk = null
|
||||||
|
isConnected = false
|
||||||
|
sessionBuilder.clear()
|
||||||
|
Log.d(TAG, "AsrHelper closed")
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -10,6 +10,7 @@ import com.nova.brain.glass.repository.HeaderInterceptor
|
|||||||
import com.nova.brain.glass.repository.Service
|
import com.nova.brain.glass.repository.Service
|
||||||
import com.rokid.utils.ContextUtil.getApplicationContext
|
import com.rokid.utils.ContextUtil.getApplicationContext
|
||||||
import com.xuqm.base.di.manager.HttpManager
|
import com.xuqm.base.di.manager.HttpManager
|
||||||
|
import com.xuqm.base.extensions.showMessage
|
||||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||||
import io.reactivex.disposables.Disposable
|
import io.reactivex.disposables.Disposable
|
||||||
import io.reactivex.schedulers.Schedulers
|
import io.reactivex.schedulers.Schedulers
|
||||||
@ -44,7 +45,6 @@ object IntentRecognizeHelper {
|
|||||||
* @param onComplete 无论成功失败都会回调,用于调用方重置 loading 状态
|
* @param onComplete 无论成功失败都会回调,用于调用方重置 loading 状态
|
||||||
*/
|
*/
|
||||||
fun recognize(
|
fun recognize(
|
||||||
context: Context,
|
|
||||||
text: String? = null,
|
text: String? = null,
|
||||||
scence: String = "home",
|
scence: String = "home",
|
||||||
onSuccess: (action: RecognizeAction) -> Unit,
|
onSuccess: (action: RecognizeAction) -> Unit,
|
||||||
@ -64,11 +64,11 @@ object IntentRecognizeHelper {
|
|||||||
if (model.code == "0") {
|
if (model.code == "0") {
|
||||||
onSuccess(model.data.action)
|
onSuccess(model.data.action)
|
||||||
} else {
|
} else {
|
||||||
Toast.makeText(context, model.message, Toast.LENGTH_SHORT).show()
|
model.message.showMessage()
|
||||||
}
|
}
|
||||||
onComplete() // 无论成功失败都执行
|
onComplete() // 无论成功失败都执行
|
||||||
}, { e ->
|
}, { e ->
|
||||||
Toast.makeText(context, "请求失败: ${e.message}", Toast.LENGTH_SHORT).show()
|
"请求失败: ${e.message}".showMessage()
|
||||||
onComplete()
|
onComplete()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@ -120,6 +120,11 @@ object OfflineCmdServiceHelper {
|
|||||||
// 通用关键词在 init 时注册一次,页面切换不会移除它们
|
// 通用关键词在 init 时注册一次,页面切换不会移除它们
|
||||||
addCommonCmds()
|
addCommonCmds()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 注册 ASR 唤醒词(由 AsrHelper 调用)
|
||||||
|
fun registerAsrWakeWord() {
|
||||||
|
registerBeans(listOf(OfflineCmdBean("Nova Nova", "nou wa nou wa"),OfflineCmdBean("Nova Nova", "nao wa nao wa")))
|
||||||
|
}
|
||||||
fun addOnLineListener(listener: OfflineCmdListener){
|
fun addOnLineListener(listener: OfflineCmdListener){
|
||||||
this.listenerList.add(listener)
|
this.listenerList.add(listener)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,8 +8,6 @@ import com.xuqm.base.extensions.loge
|
|||||||
import okhttp3.Headers
|
import okhttp3.Headers
|
||||||
import okhttp3.Interceptor
|
import okhttp3.Interceptor
|
||||||
import okhttp3.Response
|
import okhttp3.Response
|
||||||
import okhttp3.internal.http.HttpHeaders
|
|
||||||
import okhttp3.internal.http.StatusLine
|
|
||||||
import okio.Buffer
|
import okio.Buffer
|
||||||
import okio.BufferedSource
|
import okio.BufferedSource
|
||||||
import okio.GzipSource
|
import okio.GzipSource
|
||||||
@ -38,9 +36,9 @@ class HeaderInterceptor(val context: Context) : Interceptor {
|
|||||||
// context.getStringForPreferences(SHARE_UESR_TOKEN).loge()
|
// context.getStringForPreferences(SHARE_UESR_TOKEN).loge()
|
||||||
|
|
||||||
val request = requestBuilder.build()
|
val request = requestBuilder.build()
|
||||||
"${request.url()}(${request.method()})".loge()
|
"${request.url}(${request.method})".loge()
|
||||||
|
|
||||||
val headers = request.headers()
|
val headers = request.headers
|
||||||
|
|
||||||
val response = chain.proceed(request)
|
val response = chain.proceed(request)
|
||||||
|
|
||||||
@ -50,7 +48,7 @@ class HeaderInterceptor(val context: Context) : Interceptor {
|
|||||||
return response
|
return response
|
||||||
}
|
}
|
||||||
|
|
||||||
response.body()?.also {
|
response.body?.also {
|
||||||
if (!bodyHasUnknownEncoding(headers) && hasBody(response)) {
|
if (!bodyHasUnknownEncoding(headers) && hasBody(response)) {
|
||||||
val source: BufferedSource = it.source()
|
val source: BufferedSource = it.source()
|
||||||
source.request(Long.MAX_VALUE) // Buffer the entire body.
|
source.request(Long.MAX_VALUE) // Buffer the entire body.
|
||||||
@ -108,11 +106,11 @@ class HeaderInterceptor(val context: Context) : Interceptor {
|
|||||||
|
|
||||||
fun hasBody(response: Response): Boolean {
|
fun hasBody(response: Response): Boolean {
|
||||||
// HEAD requests never yield a body regardless of the response headers.
|
// HEAD requests never yield a body regardless of the response headers.
|
||||||
if (response.request().method() == "HEAD") {
|
if (response.request.method == "HEAD") {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
val responseCode = response.code()
|
val responseCode = response.code
|
||||||
if ((responseCode < StatusLine.HTTP_CONTINUE || responseCode >= 200)
|
if ((responseCode < 100 || responseCode >= 200)
|
||||||
&& responseCode != HttpURLConnection.HTTP_NO_CONTENT && responseCode != HttpURLConnection.HTTP_NOT_MODIFIED
|
&& responseCode != HttpURLConnection.HTTP_NO_CONTENT && responseCode != HttpURLConnection.HTTP_NOT_MODIFIED
|
||||||
) {
|
) {
|
||||||
return true
|
return true
|
||||||
@ -120,7 +118,8 @@ class HeaderInterceptor(val context: Context) : Interceptor {
|
|||||||
|
|
||||||
// If the Content-Length or Transfer-Encoding headers disagree with the response code, the
|
// If the Content-Length or Transfer-Encoding headers disagree with the response code, the
|
||||||
// response is malformed. For best compatibility, we honor the headers.
|
// response is malformed. For best compatibility, we honor the headers.
|
||||||
return HttpHeaders.contentLength(response) != -1L || "chunked".equals(
|
val contentLength = response.headers["Content-Length"]?.toLongOrNull() ?: -1L
|
||||||
|
return contentLength != -1L || "chunked".equals(
|
||||||
response.header("Transfer-Encoding"),
|
response.header("Transfer-Encoding"),
|
||||||
ignoreCase = true
|
ignoreCase = true
|
||||||
)
|
)
|
||||||
|
|||||||
@ -4,8 +4,8 @@ import android.view.View
|
|||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
import com.nova.brain.glass.R
|
import com.nova.brain.glass.R
|
||||||
import com.nova.brain.glass.databinding.ActivityChatBinding
|
import com.nova.brain.glass.databinding.ActivityChatBinding
|
||||||
|
import com.nova.brain.glass.helper.AsrHelper
|
||||||
import com.nova.brain.glass.helper.BgChatDrawable
|
import com.nova.brain.glass.helper.BgChatDrawable
|
||||||
import com.nova.brain.glass.helper.IntentRecognizeHelper
|
|
||||||
import com.nova.brain.glass.helper.OfflineCmdListener
|
import com.nova.brain.glass.helper.OfflineCmdListener
|
||||||
import com.nova.brain.glass.helper.OfflineCmdServiceHelper
|
import com.nova.brain.glass.helper.OfflineCmdServiceHelper
|
||||||
import com.nova.brain.glass.model.ChatItem
|
import com.nova.brain.glass.model.ChatItem
|
||||||
@ -54,31 +54,8 @@ class ChatActivity : BaseListFormLayoutNormalActivity<ChatItem, ChatVM, Activity
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 调用意图识别,识别成功后发起 SSE 请求。
|
|
||||||
* 立即启动 pb 旋转,不等 recognize 接口响应。
|
|
||||||
*/
|
|
||||||
private fun recognizeAndChat() {
|
private fun recognizeAndChat() {
|
||||||
binding.pb.visibility = View.VISIBLE
|
// 识别由 AsrHelper 在 onFinalResult 中统一触发,此处无需主动发起
|
||||||
binding.pb1.visibility = View.INVISIBLE
|
|
||||||
IntentRecognizeHelper.recognize(
|
|
||||||
context = this,
|
|
||||||
scence = "decision",
|
|
||||||
onSuccess = { action ->
|
|
||||||
if (action.name == "goToDecisionCenter") {
|
|
||||||
viewModel.demoPostSse(action.params.question)
|
|
||||||
} else {
|
|
||||||
// 识别成功但没有匹配动作,停止旋转
|
|
||||||
binding.pb.isIndeterminate = false
|
|
||||||
binding.pb.visibility = View.INVISIBLE
|
|
||||||
}
|
|
||||||
},
|
|
||||||
onComplete = {
|
|
||||||
// recognize 失败时兜底停止旋转(成功路径由 loading LiveData 接管)
|
|
||||||
binding.pb.isIndeterminate = false
|
|
||||||
binding.pb.visibility = View.INVISIBLE
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun scrollToBottom() {
|
private fun scrollToBottom() {
|
||||||
@ -116,15 +93,19 @@ class ChatActivity : BaseListFormLayoutNormalActivity<ChatItem, ChatVM, Activity
|
|||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
super.onResume()
|
super.onResume()
|
||||||
OfflineCmdServiceHelper.addOnLineListener(listener)
|
OfflineCmdServiceHelper.addOnLineListener(listener)
|
||||||
|
AsrHelper.scene = "decision"
|
||||||
|
AsrHelper.onGoToDecisionCenter = { action ->
|
||||||
|
viewModel.demoPostSse(action.params.question)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onPause() {
|
override fun onPause() {
|
||||||
super.onPause()
|
super.onPause()
|
||||||
OfflineCmdServiceHelper.removeOnLineListener(listener)
|
OfflineCmdServiceHelper.removeOnLineListener(listener)
|
||||||
|
AsrHelper.onGoToDecisionCenter = null
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroy() {
|
override fun onDestroy() {
|
||||||
super.onDestroy()
|
super.onDestroy()
|
||||||
IntentRecognizeHelper.dispose()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -7,7 +7,7 @@ import android.os.Looper
|
|||||||
import androidx.lifecycle.ViewModelProvider
|
import androidx.lifecycle.ViewModelProvider
|
||||||
import com.nova.brain.glass.R
|
import com.nova.brain.glass.R
|
||||||
import com.nova.brain.glass.databinding.ActivityWelcomeBinding
|
import com.nova.brain.glass.databinding.ActivityWelcomeBinding
|
||||||
import com.nova.brain.glass.helper.IntentRecognizeHelper
|
import com.nova.brain.glass.helper.AsrHelper
|
||||||
import com.nova.brain.glass.helper.OfflineCmdListener
|
import com.nova.brain.glass.helper.OfflineCmdListener
|
||||||
import com.nova.brain.glass.helper.OfflineCmdServiceHelper
|
import com.nova.brain.glass.helper.OfflineCmdServiceHelper
|
||||||
import com.nova.brain.glass.viewmodel.WelcomeVM
|
import com.nova.brain.glass.viewmodel.WelcomeVM
|
||||||
@ -47,34 +47,12 @@ class WelcomeActivity : BaseActivity<ActivityWelcomeBinding>() {
|
|||||||
super.initView(savedInstanceState)
|
super.initView(savedInstanceState)
|
||||||
vm = ViewModelProvider(this)[WelcomeVM::class.java]
|
vm = ViewModelProvider(this)[WelcomeVM::class.java]
|
||||||
window.addFlags(android.view.WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
|
window.addFlags(android.view.WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
|
||||||
binding.tv.setOnClickListener {
|
|
||||||
triggerRecognize()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun initData() {
|
override fun initData() {
|
||||||
super.initData()
|
super.initData()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun triggerRecognize() {
|
|
||||||
startDotsAnim()
|
|
||||||
IntentRecognizeHelper.recognize(
|
|
||||||
context = this,
|
|
||||||
text = "当前阶段,最紧急的任务是什么?",
|
|
||||||
onSuccess = { action ->
|
|
||||||
if (action.name == "goToDecisionCenter") {
|
|
||||||
startActivity(
|
|
||||||
Intent(this, ChatActivity::class.java)
|
|
||||||
.putExtra("question", action.params.question)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
onComplete = {
|
|
||||||
stopDotsAnim()
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private val offlineCmdListener = object : OfflineCmdListener {
|
private val offlineCmdListener = object : OfflineCmdListener {
|
||||||
override fun onOfflineCmd(cmd: String) {
|
override fun onOfflineCmd(cmd: String) {
|
||||||
runOnUiThread {
|
runOnUiThread {
|
||||||
@ -82,9 +60,6 @@ class WelcomeActivity : BaseActivity<ActivityWelcomeBinding>() {
|
|||||||
"任务列表", "查看任务", "查看任务列表" -> {
|
"任务列表", "查看任务", "查看任务列表" -> {
|
||||||
startActivity(Intent(this@WelcomeActivity, TaskListActivity::class.java))
|
startActivity(Intent(this@WelcomeActivity, TaskListActivity::class.java))
|
||||||
}
|
}
|
||||||
"决策中心", "紧急任务", "当前任务" -> {
|
|
||||||
triggerRecognize()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -95,6 +70,13 @@ class WelcomeActivity : BaseActivity<ActivityWelcomeBinding>() {
|
|||||||
OfflineCmdServiceHelper.addOnLineListener(offlineCmdListener)
|
OfflineCmdServiceHelper.addOnLineListener(offlineCmdListener)
|
||||||
OfflineCmdServiceHelper.addListenerWelcome()
|
OfflineCmdServiceHelper.addListenerWelcome()
|
||||||
stopDotsAnim() // 从 ChatActivity 返回时恢复原文
|
stopDotsAnim() // 从 ChatActivity 返回时恢复原文
|
||||||
|
AsrHelper.scene = "home"
|
||||||
|
AsrHelper.onGoToDecisionCenter = { action ->
|
||||||
|
startActivity(
|
||||||
|
Intent(this, ChatActivity::class.java)
|
||||||
|
.putExtra("question", action.params.question)
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onPause() {
|
override fun onPause() {
|
||||||
@ -102,6 +84,7 @@ class WelcomeActivity : BaseActivity<ActivityWelcomeBinding>() {
|
|||||||
OfflineCmdServiceHelper.removeOnLineListener(offlineCmdListener)
|
OfflineCmdServiceHelper.removeOnLineListener(offlineCmdListener)
|
||||||
OfflineCmdServiceHelper.removeListenerWelcome()
|
OfflineCmdServiceHelper.removeListenerWelcome()
|
||||||
dotsHandler.removeCallbacks(dotsRunnable)
|
dotsHandler.removeCallbacks(dotsRunnable)
|
||||||
|
AsrHelper.onGoToDecisionCenter = null
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroy() {
|
override fun onDestroy() {
|
||||||
|
|||||||
@ -6,7 +6,7 @@ import com.xuqm.base.App
|
|||||||
import com.xuqm.base.di.manager.HttpManager
|
import com.xuqm.base.di.manager.HttpManager
|
||||||
import com.xuqm.sdhbwfu.core.viewModel.BaseViewModel
|
import com.xuqm.sdhbwfu.core.viewModel.BaseViewModel
|
||||||
import io.reactivex.schedulers.Schedulers
|
import io.reactivex.schedulers.Schedulers
|
||||||
import okhttp3.MediaType
|
import okhttp3.MediaType.Companion.toMediaTypeOrNull
|
||||||
import okhttp3.RequestBody
|
import okhttp3.RequestBody
|
||||||
|
|
||||||
class WelcomeVM : BaseViewModel() {
|
class WelcomeVM : BaseViewModel() {
|
||||||
@ -26,7 +26,7 @@ class WelcomeVM : BaseViewModel() {
|
|||||||
fun demoPost() {
|
fun demoPost() {
|
||||||
result.value = "POST 请求中..."
|
result.value = "POST 请求中..."
|
||||||
val json = """{"demo":"post","from":"glass"}"""
|
val json = """{"demo":"post","from":"glass"}"""
|
||||||
val body = RequestBody.create(MediaType.parse("application/json"), json)
|
val body = RequestBody.create("application/json".toMediaTypeOrNull(), json)
|
||||||
HttpManager.getApi(Service::class.java).demoPost(body)
|
HttpManager.getApi(Service::class.java).demoPost(body)
|
||||||
.subscribeOn(Schedulers.io())
|
.subscribeOn(Schedulers.io())
|
||||||
.subscribe({ resp ->
|
.subscribe({ resp ->
|
||||||
|
|||||||
@ -1,12 +1,13 @@
|
|||||||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||||
apply from: "config.gradle"
|
apply from: "config.gradle"
|
||||||
buildscript {
|
buildscript {
|
||||||
ext.kotlin_version = "1.6.10"
|
ext.kotlin_version = "2.2.0"
|
||||||
repositories {
|
repositories {
|
||||||
google()
|
google()
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
maven { url 'https://nexus.xuqinmin.com/repository/android/' }
|
maven { url 'https://nexus.xuqinmin.com/repository/android/' }
|
||||||
maven { url 'https://maven.rokid.com/repository/maven-public/' }
|
maven { url 'https://maven.rokid.com/repository/maven-public/' }
|
||||||
|
maven { url 'https://maven.rokid-inc.com/repository/maven-public/' }
|
||||||
maven { url 'https://maven.aliyun.com/nexus/content/repositories/releases/' }
|
maven { url 'https://maven.aliyun.com/nexus/content/repositories/releases/' }
|
||||||
maven { url 'https://maven.aliyun.com/repository/google/' }
|
maven { url 'https://maven.aliyun.com/repository/google/' }
|
||||||
maven { url 'https://maven.aliyun.com/repository/public/' }
|
maven { url 'https://maven.aliyun.com/repository/public/' }
|
||||||
@ -18,8 +19,8 @@ buildscript {
|
|||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath 'com.android.tools.build:gradle:7.2.0'
|
classpath 'com.android.tools.build:gradle:7.4.2'
|
||||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.7.0"
|
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:2.2.0"
|
||||||
|
|
||||||
// NOTE: Do not place your application dependencies here; they belong
|
// NOTE: Do not place your application dependencies here; they belong
|
||||||
// in the individual module build.gradle files
|
// in the individual module build.gradle files
|
||||||
@ -33,6 +34,7 @@ allprojects {
|
|||||||
// maven { url 'http://developer.huawei.com/repo/' }
|
// maven { url 'http://developer.huawei.com/repo/' }
|
||||||
maven { url 'https://nexus.xuqinmin.com/repository/android/' }
|
maven { url 'https://nexus.xuqinmin.com/repository/android/' }
|
||||||
maven { url 'https://maven.rokid.com/repository/maven-public/' }
|
maven { url 'https://maven.rokid.com/repository/maven-public/' }
|
||||||
|
maven { url 'https://maven.rokid-inc.com/repository/maven-public/' }
|
||||||
maven { url 'https://maven.aliyun.com/nexus/content/repositories/releases/' }
|
maven { url 'https://maven.aliyun.com/nexus/content/repositories/releases/' }
|
||||||
maven { url 'https://maven.aliyun.com/repository/google/' }
|
maven { url 'https://maven.aliyun.com/repository/google/' }
|
||||||
maven { url 'https://maven.aliyun.com/repository/public/' }
|
maven { url 'https://maven.aliyun.com/repository/public/' }
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
apply plugin: 'com.android.library'
|
apply plugin: 'com.android.library'
|
||||||
apply plugin: 'kotlin-android'
|
apply plugin: 'kotlin-android'
|
||||||
apply plugin: 'kotlin-android-extensions'
|
|
||||||
|
|
||||||
android {
|
android {
|
||||||
compileSdkVersion versions.compileSdk
|
compileSdkVersion versions.compileSdk
|
||||||
|
|||||||
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
|
|||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-bin.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip
|
||||||
|
|||||||
正在加载...
在新工单中引用
屏蔽一个用户