fix: voice input recording format + ASR logging
- Change recorder format from mp3 (8kHz) to aac (22kHz) for better
whisper ASR accuracy
- Move recorder.onStop binding before recorder.stop() to prevent
race condition (onStop may fire before handler is registered)
- Backend: add Logger, log ASR errors instead of silent catch {}
- Backend: change default extension from .mp3 to .aac
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
import { Controller, Get, Post, Body, Param, Res, HttpException, HttpStatus, UseGuards, UploadedFile, UseInterceptors } from '@nestjs/common'
|
import { Controller, Get, Post, Body, Param, Res, HttpException, HttpStatus, UseGuards, UploadedFile, UseInterceptors, Logger } from '@nestjs/common'
|
||||||
import { FileInterceptor } from '@nestjs/platform-express'
|
import { FileInterceptor } from '@nestjs/platform-express'
|
||||||
import { Response } from 'express'
|
import { Response } from 'express'
|
||||||
import * as fs from 'fs'
|
import * as fs from 'fs'
|
||||||
@@ -10,6 +10,7 @@ import { Public } from '../../common/decorators/public.decorator'
|
|||||||
|
|
||||||
@Controller('tts')
|
@Controller('tts')
|
||||||
export class TtsController {
|
export class TtsController {
|
||||||
|
private readonly logger = new Logger(TtsController.name)
|
||||||
constructor(private ttsService: TtsService) {}
|
constructor(private ttsService: TtsService) {}
|
||||||
|
|
||||||
@UseGuards(JwtAuthGuard)
|
@UseGuards(JwtAuthGuard)
|
||||||
@@ -42,7 +43,7 @@ export class TtsController {
|
|||||||
if (!file) throw new HttpException('请上传音频文件', HttpStatus.BAD_REQUEST)
|
if (!file) throw new HttpException('请上传音频文件', HttpStatus.BAD_REQUEST)
|
||||||
const uploadDir = '/tmp/asr_uploads'
|
const uploadDir = '/tmp/asr_uploads'
|
||||||
if (!fs.existsSync(uploadDir)) fs.mkdirSync(uploadDir, { recursive: true })
|
if (!fs.existsSync(uploadDir)) fs.mkdirSync(uploadDir, { recursive: true })
|
||||||
const ext = path.extname(file.originalname) || '.mp3'
|
const ext = file.originalname ? path.extname(file.originalname) || '.aac' : '.aac'
|
||||||
const dest = path.join(uploadDir, file.filename + ext)
|
const dest = path.join(uploadDir, file.filename + ext)
|
||||||
fs.renameSync(file.path, dest)
|
fs.renameSync(file.path, dest)
|
||||||
try {
|
try {
|
||||||
@@ -63,7 +64,11 @@ export class TtsController {
|
|||||||
if (whisperResult && whisperResult.trim()) {
|
if (whisperResult && whisperResult.trim()) {
|
||||||
return { text: whisperResult.trim() }
|
return { text: whisperResult.trim() }
|
||||||
}
|
}
|
||||||
} catch {}
|
} catch (e: any) {
|
||||||
|
this.logger.error(`ASR failed: ${e?.message || e}`)
|
||||||
|
}
|
||||||
|
// 清理临时文件
|
||||||
|
try { fs.unlinkSync(dest) } catch {}
|
||||||
return { text: '' }
|
return { text: '' }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -351,19 +351,7 @@ function startRecord() {
|
|||||||
isRecording.value = true
|
isRecording.value = true
|
||||||
recorder = uni.getRecorderManager()
|
recorder = uni.getRecorderManager()
|
||||||
recorder.onStart(() => {})
|
recorder.onStart(() => {})
|
||||||
recorder.onError(() => { isRecording.value = false })
|
recorder.onError(() => { isRecording.value = false; uni.showToast({ title: '录音失败', icon: 'none' }) })
|
||||||
recorder.start({ format: 'mp3' })
|
|
||||||
uni.vibrateShort({ type: 'medium' })
|
|
||||||
// #endif
|
|
||||||
// #ifndef MP-WEIXIN
|
|
||||||
uni.showToast({ title: '语音输入仅支持小程序', icon: 'none' })
|
|
||||||
// #endif
|
|
||||||
}
|
|
||||||
|
|
||||||
function stopRecord() {
|
|
||||||
if (!recorder || !isRecording.value) return
|
|
||||||
isRecording.value = false
|
|
||||||
recorder.stop()
|
|
||||||
recorder.onStop(async (res) => {
|
recorder.onStop(async (res) => {
|
||||||
if (!res.tempFilePath) return
|
if (!res.tempFilePath) return
|
||||||
const audioPath = res.tempFilePath
|
const audioPath = res.tempFilePath
|
||||||
@@ -387,6 +375,18 @@ function stopRecord() {
|
|||||||
}
|
}
|
||||||
uni.showToast({ title: '语音识别失败,请手动输入', icon: 'none' })
|
uni.showToast({ title: '语音识别失败,请手动输入', icon: 'none' })
|
||||||
})
|
})
|
||||||
|
recorder.start({ format: 'aac', sampleRate: 22050, numberOfChannels: 1, encodeBitRate: 16000 })
|
||||||
|
uni.vibrateShort({ type: 'medium' })
|
||||||
|
// #endif
|
||||||
|
// #ifndef MP-WEIXIN
|
||||||
|
uni.showToast({ title: '语音输入仅支持小程序', icon: 'none' })
|
||||||
|
// #endif
|
||||||
|
}
|
||||||
|
|
||||||
|
function stopRecord() {
|
||||||
|
if (!recorder || !isRecording.value) return
|
||||||
|
isRecording.value = false
|
||||||
|
recorder.stop()
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user