guoyu/Archive/fronted_uniapp_docs/语音评测-新方案使用示例.vue
2026-01-30 15:08:32 +08:00

224 lines
4.3 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="speech-page">
<view class="title">语音评测新方案</view>
<!-- 题目显示 -->
<view class="question-box">
<text class="question-label">请朗读</text>
<text class="question-text">{{ questionText }}</text>
</view>
<!-- 录音按钮 -->
<view class="record-box">
<button
@touchstart="startRecord"
@touchend="stopRecord"
:disabled="isProcessing"
class="record-btn"
:class="{ recording: isRecording }"
>
{{ recordButtonText }}
</button>
<text class="tip">{{ isRecording ? '松开结束录音' : '按住开始录音' }}</text>
</view>
<!-- 结果显示 -->
<view v-if="result" class="result-box">
<view class="result-item">
<text class="label">识别文本:</text>
<text class="value">{{ result.recognizedText || '-' }}</text>
</view>
<view class="result-item">
<text class="label">准确度:</text>
<text class="value score">{{ result.score || 0 }}分</text>
</view>
<view class="result-item">
<text class="label">评价:</text>
<text class="value">{{ result.comment || '-' }}</text>
</view>
</view>
</view>
</template>
<script>
import speechRecorder from '@/utils/speech-recorder.js'
export default {
data() {
return {
questionText: '你好,欢迎使用语音评测系统',
isRecording: false,
isProcessing: false,
result: null
}
},
computed: {
recordButtonText() {
if (this.isProcessing) return '处理中...'
if (this.isRecording) return '录音中...'
return '按住录音'
}
},
onLoad() {
// 初始化录音器
speechRecorder.init()
},
methods: {
// 开始录音
startRecord() {
this.isRecording = true
this.result = null
speechRecorder.start({
duration: 60000, // 最长60秒
sampleRate: 16000,
format: 'mp3'
})
},
// 停止录音并评测
async stopRecord() {
if (!this.isRecording) return
this.isRecording = false
this.isProcessing = true
try {
// 停止录音
const filePath = await speechRecorder.stop()
// 上传并识别
const result = await speechRecorder.uploadAndRecognize(filePath, {
referenceText: this.questionText,
mode: 'evaluation' // 评测模式
})
this.result = result
uni.showToast({
title: '评测完成',
icon: 'success'
})
} catch (error) {
console.error('语音评测失败', error)
uni.showToast({
title: '评测失败:' + error.message,
icon: 'none'
})
} finally {
this.isProcessing = false
}
}
}
}
</script>
<style scoped>
.speech-page {
padding: 40rpx;
}
.title {
font-size: 36rpx;
font-weight: bold;
text-align: center;
margin-bottom: 40rpx;
}
.question-box {
background: #f5f5f5;
padding: 30rpx;
border-radius: 12rpx;
margin-bottom: 40rpx;
}
.question-label {
font-size: 28rpx;
color: #666;
display: block;
margin-bottom: 10rpx;
}
.question-text {
font-size: 32rpx;
color: #333;
line-height: 1.6;
}
.record-box {
text-align: center;
margin: 60rpx 0;
}
.record-btn {
width: 300rpx;
height: 300rpx;
border-radius: 50%;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
font-size: 32rpx;
border: none;
}
.record-btn.recording {
background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
animation: pulse 1s infinite;
}
.record-btn:active {
opacity: 0.8;
}
@keyframes pulse {
0%, 100% { transform: scale(1); }
50% { transform: scale(1.05); }
}
.tip {
display: block;
margin-top: 20rpx;
font-size: 24rpx;
color: #999;
}
.result-box {
background: #fff;
border: 1rpx solid #e0e0e0;
border-radius: 12rpx;
padding: 30rpx;
}
.result-item {
display: flex;
margin-bottom: 20rpx;
}
.result-item:last-child {
margin-bottom: 0;
}
.label {
font-size: 28rpx;
color: #666;
width: 160rpx;
}
.value {
flex: 1;
font-size: 28rpx;
color: #333;
}
.value.score {
color: #f5576c;
font-size: 36rpx;
font-weight: bold;
}
</style>