|
|
@@ -42,6 +42,11 @@ const props = defineProps({
|
|
|
maxDuration: {
|
|
|
type: Number,
|
|
|
default: 10
|
|
|
+ },
|
|
|
+ // 输入框选择器,用于获取输入框元素
|
|
|
+ inputSelector: {
|
|
|
+ type: String,
|
|
|
+ default: 'input[type="text"]'
|
|
|
}
|
|
|
})
|
|
|
|
|
|
@@ -55,6 +60,8 @@ const countdown = ref(0) // 倒计时剩余秒数
|
|
|
const countdownTimer = ref(null) // 倒计时定时器
|
|
|
const isBrowserSupported = ref(true) // 浏览器是否支持语音识别
|
|
|
const mediaStream = ref(null) // 媒体流引用,用于释放资源
|
|
|
+const recordingStartText = ref('') // 录音开始时的原始文本
|
|
|
+const recordingStartCursorPos = ref(0) // 录音开始时的光标位置
|
|
|
|
|
|
// 检测浏览器是否支持语音识别
|
|
|
const checkBrowserSupport = () => {
|
|
|
@@ -77,17 +84,38 @@ const initSpeechRecognition = () => {
|
|
|
|
|
|
const instance = new SpeechRecognition()
|
|
|
instance.lang = props.lang
|
|
|
- instance.interimResults = true
|
|
|
- instance.continuous = true
|
|
|
+ instance.interimResults = true//是否返回临时结果
|
|
|
+ instance.maxAlternatives = 1//返回的最大候选结果数
|
|
|
+ instance.continuous = true//收录音频时是否连续识别
|
|
|
|
|
|
instance.onresult = (event) => {
|
|
|
// 遍历所有结果,包括临时结果
|
|
|
- for (let i = event.resultIndex; i < event.results.length; i++) {
|
|
|
- const transcript = event.results[i][0].transcript
|
|
|
+ let fullTranscript = ''
|
|
|
+ for (let i = 0; i < event.results.length; i++) {
|
|
|
+ fullTranscript += event.results[i][0].transcript
|
|
|
+ }
|
|
|
+ // 只在录音状态下发送识别结果
|
|
|
+ if (isRecording.value) {
|
|
|
+ // 计算处理后的文本
|
|
|
+ let processedText = ''
|
|
|
+ let cursorPos = 0
|
|
|
+ if (recordingStartCursorPos.value >= recordingStartText.value.length) {
|
|
|
+ // 光标位置在文本末尾或找不到输入框时,追加到末尾
|
|
|
+ processedText = recordingStartText.value + fullTranscript
|
|
|
+ cursorPos = recordingStartText.value.length + fullTranscript.length
|
|
|
+ } else {
|
|
|
+ // 光标位置在文本中间时,插入到光标位置
|
|
|
+ processedText = recordingStartText.value.substring(0, recordingStartCursorPos.value) + fullTranscript + recordingStartText.value.substring(recordingStartCursorPos.value)
|
|
|
+ cursorPos = recordingStartCursorPos.value + fullTranscript.length
|
|
|
+ }
|
|
|
// 无论是否是最终结果,实时识别结果
|
|
|
- emit('voiceRecognized', transcript)
|
|
|
+ emit('voiceRecognized', {
|
|
|
+ originalText: fullTranscript,
|
|
|
+ processedText: processedText,
|
|
|
+ cursorPos: cursorPos
|
|
|
+ })
|
|
|
// 打印语音识别结果
|
|
|
- console.log('语音输入文字:', transcript)
|
|
|
+ console.log('语音输入文字:', fullTranscript)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -144,6 +172,19 @@ const getBrowserInfo = () => {
|
|
|
return { name: 'Unknown', version: 'Unknown' }
|
|
|
}
|
|
|
|
|
|
+// 记录录音开始时的输入框状态
|
|
|
+const recordInputState = () => {
|
|
|
+ const input = document.querySelector(props.inputSelector)
|
|
|
+ if (input) {
|
|
|
+ recordingStartCursorPos.value = input.selectionStart
|
|
|
+ recordingStartText.value = input.value
|
|
|
+ } else {
|
|
|
+ // 找不到输入框时,默认在最后面追加
|
|
|
+ recordingStartCursorPos.value = 999999
|
|
|
+ recordingStartText.value = ''
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
// 切换录音状态
|
|
|
const toggleSpeechInput = () => {
|
|
|
const browser = getBrowserInfo()
|
|
|
@@ -164,6 +205,8 @@ const toggleSpeechInput = () => {
|
|
|
emit('recordingStatusChanged', false)
|
|
|
recognition.value?.stop()
|
|
|
} else {
|
|
|
+ // 记录输入框状态
|
|
|
+ recordInputState()
|
|
|
// 初始化倒计时前再次清除定时器(防止快速点击)
|
|
|
clearInterval(countdownTimer.value)
|
|
|
countdown.value = props.maxDuration // 设置最大录音时间
|