diff --git a/app/src/main/java/com/nova/brain/glass/MyApplication.java b/app/src/main/java/com/nova/brain/glass/MyApplication.java index 46e175e..0ada3d6 100644 --- a/app/src/main/java/com/nova/brain/glass/MyApplication.java +++ b/app/src/main/java/com/nova/brain/glass/MyApplication.java @@ -6,6 +6,7 @@ import com.nova.brain.glass.repository.HeaderInterceptor; import com.rokid.security.glass3.open.sdk.GlassSdk; import com.rokid.security.glass3.open.sdk.client.IServiceConnectionCallback; import com.xuqm.base.App; +import com.xuqm.base.di.component.AppComponent; import com.xuqm.base.di.manager.HttpManager; /** @@ -13,8 +14,8 @@ import com.xuqm.base.di.manager.HttpManager; */ public class MyApplication extends App { - public static String baseUrl = "http://192.168.6.20"; -// public static String baseUrl = "http://22fs132201.imwork.net"; +// public static String baseUrl = "http://192.168.6.20"; + public static String baseUrl = "http://22fs132201.imwork.net"; @Override public void onCreate() { diff --git a/app/src/main/java/com/nova/brain/glass/helper/IntentRecognizeHelper.kt b/app/src/main/java/com/nova/brain/glass/helper/IntentRecognizeHelper.kt new file mode 100644 index 0000000..0659e6e --- /dev/null +++ b/app/src/main/java/com/nova/brain/glass/helper/IntentRecognizeHelper.kt @@ -0,0 +1,79 @@ +package com.nova.brain.glass.helper + +import android.content.Context +import android.widget.Toast +import com.nova.brain.glass.helper.IntentRecognizeHelper.dispose +import com.nova.brain.glass.helper.IntentRecognizeHelper.recognize +import com.nova.brain.glass.model.RecognizeAction +import com.nova.brain.glass.model.data.RecognizeData +import com.nova.brain.glass.repository.HeaderInterceptor +import com.nova.brain.glass.repository.Service +import com.rokid.utils.ContextUtil.getApplicationContext +import com.xuqm.base.di.manager.HttpManager +import io.reactivex.android.schedulers.AndroidSchedulers +import io.reactivex.disposables.Disposable +import io.reactivex.schedulers.Schedulers + +/** + * 意图识别全局工具。 + * + * - [recognize] 发起识别请求;自动轮换内置问题作为 text(非 Welcome 页调用)。 + * - [dispose] 在页面销毁时调用,取消进行中的请求。 + */ +object IntentRecognizeHelper { + + private val builtInQuestions = listOf( + "C大脑V2.24版本进行到什么阶段了", + "我的任务有哪些", + "个人任务系统功能的需求来自哪个项目", + "浙江华瑞项目有哪些进行中的采购流程" + ) + private var questionIndex = 0 + private var disposable: Disposable? = null + + private val baseUrl: String = "https://22v1322u01.vicp.fun" + + /** + * @param context 用于显示 Toast + * @param text 指定问题文本;为 null 时自动轮换内置问题 + * @param scence 场景标识,默认 "home" + * @param onSuccess 识别成功且 code=="0" 时回调,参数为 [RecognizeAction] + */ + fun recognize( + context: Context, + text: String? = null, + scence: String = "home", + onSuccess: (action: RecognizeAction) -> Unit + ) { + disposable?.dispose() + val question = text ?: nextQuestion() + disposable = HttpManager.getApi( + HttpManager.getAppComponent( + baseUrl, + HeaderInterceptor(getApplicationContext()) + ), Service::class.java) + .recognize(RecognizeData(text = question, scence = scence)) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe({ model -> + if (model.code == "0") { + onSuccess(model.data.action) + } else { + Toast.makeText(context, model.data.error, Toast.LENGTH_SHORT).show() + } + }, { e -> + Toast.makeText(context, "请求失败: ${e.message}", Toast.LENGTH_SHORT).show() + }) + } + + fun dispose() { + disposable?.dispose() + disposable = null + } + + private fun nextQuestion(): String { + val q = builtInQuestions[questionIndex % builtInQuestions.size] + questionIndex++ + return q + } +} \ No newline at end of file diff --git a/app/src/main/java/com/nova/brain/glass/model/RecognizeModel.kt b/app/src/main/java/com/nova/brain/glass/model/RecognizeModel.kt index e40a5f2..008f553 100644 --- a/app/src/main/java/com/nova/brain/glass/model/RecognizeModel.kt +++ b/app/src/main/java/com/nova/brain/glass/model/RecognizeModel.kt @@ -29,6 +29,7 @@ data class RecognizeModel( // } data class RecognizeModelData( val action: RecognizeAction, + val error: String?, ) //{ diff --git a/app/src/main/java/com/nova/brain/glass/model/data/RecognizeData.kt b/app/src/main/java/com/nova/brain/glass/model/data/RecognizeData.kt index 4c198a8..b7bfcdc 100644 --- a/app/src/main/java/com/nova/brain/glass/model/data/RecognizeData.kt +++ b/app/src/main/java/com/nova/brain/glass/model/data/RecognizeData.kt @@ -12,5 +12,5 @@ data class RecognizeData( val text: String, val scence: String = "home", val extra: List = emptyList(), - val actions: List = emptyList() + val actions: List = listOf("goToTaskCenter","goToDecisionCenter") ) diff --git a/app/src/main/java/com/nova/brain/glass/ui/ChatActivity.kt b/app/src/main/java/com/nova/brain/glass/ui/ChatActivity.kt index d336491..aff3ab9 100644 --- a/app/src/main/java/com/nova/brain/glass/ui/ChatActivity.kt +++ b/app/src/main/java/com/nova/brain/glass/ui/ChatActivity.kt @@ -3,8 +3,9 @@ package com.nova.brain.glass.ui import android.view.View import android.widget.TextView import com.nova.brain.glass.R -import com.nova.brain.glass.helper.BgChatDrawable import com.nova.brain.glass.databinding.ActivityChatBinding +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.OfflineCmdServiceHelper import com.nova.brain.glass.model.ChatItem @@ -25,7 +26,7 @@ class ChatActivity : BaseListFormLayoutNormalActivity finish() - "继续" -> viewModel.demoPostSse() + "继续" -> recognizeAndChat() } } } @@ -40,24 +41,38 @@ class ChatActivity : BaseListFormLayoutNormalActivity - binding.pb.visibility = if (loading) View.VISIBLE else View.GONE + binding.pb.isIndeterminate = loading } - viewModel.demoPostSse() + val question = intent.getStringExtra("question") ?: "" + if (question.isNotEmpty()) { + viewModel.demoPostSse(question) + } + } + private fun recognizeAndChat() { + IntentRecognizeHelper.recognize( + context = this, + scence = "decision", + onSuccess = { action -> + if (action.name == "goToDecisionCenter") { + viewModel.demoPostSse(action.params.question) + } + } + ) } override fun adapter() = object : CommonPagedAdapter(R.layout.item_chat) { override fun convert(holder: ViewHolder, item: ChatItem, position: Int) { - holder.setVisibility(R.id.line, position!=0) + holder.setVisibility(R.id.line, position != 0) val chatItems = viewModel.chatItems val liveItem = if (position < chatItems.size) chatItems[position] else item holder.setText(R.id.title, liveItem.title) val tv = holder.getView(R.id.content) markwon.setMarkdown(tv, liveItem.content) - holder.setClickListener(R.id.root, { - viewModel.demoPostSse() - }) + holder.setClickListener(R.id.root) { + recognizeAndChat() + } } } @@ -74,4 +89,9 @@ class ChatActivity : BaseListFormLayoutNormalActivity() { } binding.btnGet.setOnClickListener { vm.demoGet() } binding.btnPost.setOnClickListener { vm.demoPost() } - binding.md.setOnClickListener { startActivity(Intent(this@WelcomeActivity, ChatActivity::class.java)) } + binding.md.setOnClickListener { + IntentRecognizeHelper.recognize( + context = this, + text = "当前阶段,最紧急的任务是什么?", + onSuccess = { action -> + if (action.name == "goToDecisionCenter") { + startActivity( + Intent(this, ChatActivity::class.java) + .putExtra("question", action.params.question) + ) + } + } + ) + } } override fun initData() { diff --git a/app/src/main/java/com/nova/brain/glass/viewmodel/ChatVM.kt b/app/src/main/java/com/nova/brain/glass/viewmodel/ChatVM.kt index 7ef8913..a2ef33b 100644 --- a/app/src/main/java/com/nova/brain/glass/viewmodel/ChatVM.kt +++ b/app/src/main/java/com/nova/brain/glass/viewmodel/ChatVM.kt @@ -1,5 +1,7 @@ package com.nova.brain.glass.viewmodel +import android.os.Handler +import android.os.Looper import androidx.lifecycle.MutableLiveData import com.nova.brain.glass.model.ChatItem import com.nova.brain.glass.model.ChatModel @@ -7,11 +9,10 @@ import com.nova.brain.glass.model.ChatModel1 import com.nova.brain.glass.model.data.ChatData import com.nova.brain.glass.repository.Service import com.xuqm.base.common.GsonImplHelp +import com.xuqm.base.common.LogHelper import com.xuqm.base.di.manager.HttpManager import com.xuqm.base.viewmodel.BaseListViewModel import com.xuqm.base.viewmodel.callback.Response -import android.os.Handler -import android.os.Looper import io.reactivex.disposables.Disposable import io.reactivex.schedulers.Schedulers @@ -21,20 +22,7 @@ class ChatVM : BaseListViewModel() { val chatItems: MutableList = mutableListOf() private var currentTask: Disposable? = null - - private val questions = listOf( - "我的代办任务有哪些?", - "今天天气情况如何?", - "当前设备状态如何?", - "今日巡检计划是什么?", - "有哪些待处理的告警?", - "最近的维修记录有哪些?", - "当前区域的安全评分是多少?", - "有哪些设备需要维护?", - "今天有哪些会议安排?", - "当前库存状态如何?" - ) - private var questionIndex = 0 + private var itemIdCounter = 0 private var dataSourceReady = false private val mainHandler = Handler(Looper.getMainLooper()) @@ -47,14 +35,11 @@ class ChatVM : BaseListViewModel() { } } - fun demoPostSse() { + fun demoPostSse(question: String) { currentTask?.dispose() currentTask = null - val question = questions[questionIndex % questions.size] - val itemId = questionIndex - questionIndex++ - + val itemId = itemIdCounter++ chatItems.add(ChatItem(itemId, question, "")) if (dataSourceReady) invalidate() loading.postValue(true) @@ -70,11 +55,10 @@ class ChatVM : BaseListViewModel() { val l = line!! if (l.isNotEmpty()) { if (l.trimStart().startsWith("<")) { - // HTML响应(隧道断开),回退问题索引并在主线程重试 + // HTML 响应(隧道断开),移除占位项并在主线程用相同问题重试 mainHandler.post { - questionIndex-- if (chatItems.isNotEmpty()) chatItems.removeAt(chatItems.size - 1) - demoPostSse() + demoPostSse(question) } loading.postValue(false) return@use @@ -104,6 +88,7 @@ class ChatVM : BaseListViewModel() { } } } catch (e: Exception) { + LogHelper.e(">>>>11", e) loading.postValue(false) val errMsg = "AI反馈异常: ${e.message}" val lastIndex = chatItems.size - 1 @@ -116,6 +101,7 @@ class ChatVM : BaseListViewModel() { } loading.postValue(false) }, { e -> + LogHelper.e(">>>>22", e) loading.postValue(false) result.postValue("AI反馈异常: ${e.message}") })