diff --git a/zhiyin-app/src/manifest.json b/zhiyin-app/src/manifest.json
index d30c6db..083601a 100644
--- a/zhiyin-app/src/manifest.json
+++ b/zhiyin-app/src/manifest.json
@@ -17,6 +17,12 @@
"__usePrivacyCheck__": true
},
"usingComponents": true,
+ "plugins": {
+ "WechatSI": {
+ "version": "0.3.6",
+ "provider": "wx069ba97219f66d99"
+ }
+ },
"permission": {
"scope.record": {
"desc": "用于语音输入回答面试问题"
diff --git a/zhiyin-app/src/pages/interview/interview.vue b/zhiyin-app/src/pages/interview/interview.vue
index b93aa69..7beb125 100644
--- a/zhiyin-app/src/pages/interview/interview.vue
+++ b/zhiyin-app/src/pages/interview/interview.vue
@@ -65,7 +65,7 @@
{{ isRecording ? recordingDuration + 's' : '按住' }}
-
+
{{ isRecording ? '◉' : '➤' }}
@@ -153,76 +153,49 @@ const isSpeaking = ref(false)
const dhRef = ref(null)
const isRecording = ref(false)
const recordingDuration = ref(0)
-const asrLoading = ref(false)
-let recorder = null
+let manager = null
let recordTimer = null
-let skipAsr = false
-let recorderStarted = false
-let pendingStop = false
+let suppressAutoSend = false
function initRecorder() {
// #ifdef MP-WEIXIN
- if (recorder) return
- recorder = uni.getRecorderManager()
- recorder.onStart(() => {
- console.log('[Recorder] start recording')
- recorderStarted = true
- recordingDuration.value = 0
- recordTimer = setInterval(() => { recordingDuration.value++ }, 1000)
- if (pendingStop) {
- pendingStop = false
- recorder.stop()
+ if (manager) return
+ try {
+ const plugin = requirePlugin('WechatSI')
+ manager = plugin.getRecordRecognitionManager()
+ manager.onStart = () => {
+ console.log('[WechatSI] start')
+ isRecording.value = true
+ recordingDuration.value = 0
+ recordTimer = setInterval(() => { recordingDuration.value++ }, 1000)
}
- })
- recorder.onError((err) => {
- console.error('[Recorder] error:', JSON.stringify(err))
- isRecording.value = false
- recorderStarted = false
- pendingStop = false
- skipAsr = false
- recordingDuration.value = 0
- asrLoading.value = false
- if (recordTimer) { clearInterval(recordTimer); recordTimer = null }
- const msg = err?.errMsg?.includes('permission') ? '请允许录音权限' : (err?.errMsg || '录音失败,请重试')
- uni.showToast({ title: msg, icon: 'none' })
- recorder = null
- })
- recorder.onStop(async (res) => {
- isRecording.value = false
- recorderStarted = false
- recordingDuration.value = 0
- if (recordTimer) { clearInterval(recordTimer); recordTimer = null }
- if (skipAsr) { skipAsr = false; return }
- if (!res.tempFilePath) {
- uni.showToast({ title: '录音文件为空', icon: 'none' })
- return
+ manager.onRecognize = (res) => {
+ if (res?.result?.trim()) inputText.value = res.result.trim()
}
- asrLoading.value = true
- try {
- const uploadRes = await uni.uploadFile({
- url: api(API_ENDPOINTS.TTS.ASR),
- filePath: res.tempFilePath,
- name: 'audio',
- header: { 'Authorization': `Bearer ${token()}` },
- timeout: 30000,
- })
- if (uploadRes.statusCode === 200 && uploadRes.data) {
- const data = typeof uploadRes.data === 'string' ? JSON.parse(uploadRes.data) : uploadRes.data
- if (data.text) {
- inputText.value = data.text
- uni.vibrateShort({ type: 'light' })
- return
- }
- } else if (checkAuth(uploadRes)) {
- return
+ manager.onStop = (res) => {
+ isRecording.value = false
+ recordingDuration.value = 0
+ if (recordTimer) { clearInterval(recordTimer); recordTimer = null }
+ if (suppressAutoSend) { suppressAutoSend = false; return }
+ const text = res?.result?.trim()
+ if (text && text.length >= 2) {
+ inputText.value = text
+ sendAnswer()
}
- } catch (e) {
- console.error('[ASR] upload error:', e?.message || e)
- } finally {
- asrLoading.value = false
}
- uni.showToast({ title: '语音识别失败,请手动输入', icon: 'none' })
- })
+ manager.onError = (res) => {
+ console.error('[WechatSI] error:', JSON.stringify(res))
+ isRecording.value = false
+ recordingDuration.value = 0
+ if (recordTimer) { clearInterval(recordTimer); recordTimer = null }
+ const msg = res?.errMsg?.includes('permission') ? '请允许录音权限' : '语音识别失败,请重试'
+ uni.showToast({ title: msg, icon: 'none' })
+ manager = null
+ }
+ } catch (e) {
+ console.error('WechatSI plugin init failed:', e)
+ manager = null
+ }
// #endif
}
@@ -438,22 +411,15 @@ const confirmExit = () => {
}
function startRecord() {
- if (aiLoading.value || isComplete.value || asrLoading.value) return
+ if (aiLoading.value || isComplete.value) return
// #ifdef MP-WEIXIN
if (isRecording.value) return
- isRecording.value = true
- if (!recorder) initRecorder()
- if (!recorder) {
- isRecording.value = false
- uni.showToast({ title: '录音初始化失败', icon: 'none' })
+ if (!manager) initRecorder()
+ if (!manager) {
+ uni.showToast({ title: '语音功能初始化失败', icon: 'none' })
return
}
- recorder.start({
- format: 'aac',
- sampleRate: 22050,
- numberOfChannels: 1,
- encodeBitRate: 16000,
- })
+ manager.start({ lang: 'zh_CN', duration: 60000 })
uni.vibrateShort({ type: 'medium' })
// #endif
// #ifndef MP-WEIXIN
@@ -463,18 +429,13 @@ function startRecord() {
function stopRecord() {
if (!isRecording.value) return
- isRecording.value = false
- if (!recorder) return
+ if (!manager) { isRecording.value = false; return }
if (recordingDuration.value < 1) {
- skipAsr = true
+ suppressAutoSend = true
if (recordTimer) { clearInterval(recordTimer); recordTimer = null }
recordingDuration.value = 0
}
- if (!recorderStarted) {
- pendingStop = true
- return
- }
- recorder.stop()
+ manager.stop()
}