|
@@ -0,0 +1,216 @@
|
|
|
+<script setup lang='ts'>
|
|
|
+import request from '~/request'
|
|
|
+import { showFailToast, showSuccessToast, showDialog } from 'vant';
|
|
|
+
|
|
|
+
|
|
|
+const props = defineProps<{
|
|
|
+ id: string
|
|
|
+}>()
|
|
|
+console.log('props : ', props.id)
|
|
|
+
|
|
|
+const router = useRouter()
|
|
|
+
|
|
|
+function onClickLeft() {
|
|
|
+ router.back()
|
|
|
+}
|
|
|
+
|
|
|
+const loading = ref(true)
|
|
|
+
|
|
|
+const current = ref(0)
|
|
|
+
|
|
|
+// {
|
|
|
+// audioId: '1',
|
|
|
+// demoAudio:
|
|
|
+// 'http://nls-cloud-cn-shanghai.oss-cn-shanghai.aliyuncs.com/portal/tts/text_audio/wave/tonghua/300001.wav?Expires=1703561504&OSSAccessKeyId=LTAIiIg37IN8xeMa&Signature=guvV7UOLaCby%2FYKjuIfQAzGa4DY%3D&response-content-disposition=attachment%3Bfilename%3Dportal%2Ftts%2Ftext_audio%2Fwave%2Ftonghua%2F300001.wav',
|
|
|
+// text: '希望我们大家都能像他一样。'
|
|
|
+// }
|
|
|
+const list = ref<any[]>([])
|
|
|
+
|
|
|
+request({
|
|
|
+ url: '/aimooc/xnszr_audio/get_demo_text'
|
|
|
+}).then(res => {
|
|
|
+
|
|
|
+ list.value = Object.values(res.data).sort((a: any, b: any) => a.audioId - b.audioId)
|
|
|
+ console.log('list.value : ', list.value)
|
|
|
+ loading.value = false
|
|
|
+})
|
|
|
+
|
|
|
+function playAudio() {
|
|
|
+ const audio = new Audio(list.value[current.value].demoAudio);
|
|
|
+ audio.play().then(() => {
|
|
|
+ console.log('audio play success')
|
|
|
+ }).catch((error) => {
|
|
|
+ console.error('Failed to play audio: ' + error);
|
|
|
+ showFailToast('播放失败');
|
|
|
+ });
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+let mediaRecorder: MediaRecorder | null = null
|
|
|
+let isRecording = ref(false)
|
|
|
+
|
|
|
+let audioChunks: any[] = []
|
|
|
+
|
|
|
+function startAudioRecord() {
|
|
|
+ console.log('点击 开始录音')
|
|
|
+ if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
|
|
|
+ console.log('浏览器支持相关 API')
|
|
|
+ navigator.mediaDevices.getUserMedia({ audio: true })
|
|
|
+ .then((stream) => {
|
|
|
+ console.log('stream')
|
|
|
+ isRecording.value = true
|
|
|
+
|
|
|
+ mediaRecorder = new MediaRecorder(stream);
|
|
|
+ console.log('mediaRecorder 初始化成功 ')
|
|
|
+
|
|
|
+ mediaRecorder.addEventListener("dataavailable", (event: any) => {
|
|
|
+ audioChunks.push(event.data);
|
|
|
+ });
|
|
|
+
|
|
|
+ mediaRecorder.addEventListener("stop", function (event: any) {
|
|
|
+ audioChunks.push(event.data);
|
|
|
+ });
|
|
|
+
|
|
|
+ console.log("mediaRecorder 开始录音")
|
|
|
+ mediaRecorder.start(500);
|
|
|
+ })
|
|
|
+ .catch((err) => {
|
|
|
+ console.error(err);
|
|
|
+ });
|
|
|
+ } else {
|
|
|
+ console.log("浏览器不支持相关 API", navigator.mediaDevices);
|
|
|
+ showFailToast('你的浏览器版本过低,不支持录音功能');
|
|
|
+ // showFailToast('请先去设置中打开浏览器录音权限');
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+function stopAudioRecord() {
|
|
|
+ if (!mediaRecorder) {
|
|
|
+ console.log('停止录音 录音机未启动时触发')
|
|
|
+ return
|
|
|
+ }
|
|
|
+ console.log('停止录音')
|
|
|
+ mediaRecorder.stop();
|
|
|
+ mediaRecorder = null
|
|
|
+ isRecording.value = false
|
|
|
+}
|
|
|
+
|
|
|
+onUnmounted(() => {
|
|
|
+ if (mediaRecorder) {
|
|
|
+ mediaRecorder.stop();
|
|
|
+ mediaRecorder = null
|
|
|
+ }
|
|
|
+})
|
|
|
+
|
|
|
+function submitAudio() {
|
|
|
+ return new Promise((resolve, reject) => {
|
|
|
+
|
|
|
+ stopAudioRecord()
|
|
|
+ console.log('audioChunks : ', audioChunks.length)
|
|
|
+ if (audioChunks.length === 0) {
|
|
|
+ showFailToast('请先录音');
|
|
|
+ return reject()
|
|
|
+ }
|
|
|
+ setTimeout(() => {
|
|
|
+ const audioBlob = new Blob(audioChunks, { type: 'audio/wav' });
|
|
|
+ console.log('audioBlob : ', audioBlob)
|
|
|
+ // const filedata = new File([audioBlob], 'audio.wav', { type: 'audio/wav' });
|
|
|
+ mediaRecorder = null
|
|
|
+
|
|
|
+ request({
|
|
|
+ url: '/upload/main/file',
|
|
|
+ data: {
|
|
|
+ filedata: audioBlob,
|
|
|
+ aliyun_oss: 1
|
|
|
+ },
|
|
|
+ transformRequest: [
|
|
|
+ function (data: any) {
|
|
|
+ const formData = new FormData();
|
|
|
+ Object.keys(data).forEach(key => formData.append(key, data[key]))
|
|
|
+ return formData;
|
|
|
+ },
|
|
|
+ ],
|
|
|
+ })
|
|
|
+ // Promise.resolve({})
|
|
|
+ .then((res) => {
|
|
|
+ if (res.code !== '1') {
|
|
|
+ return reject()
|
|
|
+ }
|
|
|
+ // return res
|
|
|
+ const url = res.data.oss_url
|
|
|
+ // console.log('https://aimoocapi.bozedu.net/' + url)
|
|
|
+ console.log(url)
|
|
|
+ return request({
|
|
|
+ url: '/aimooc/xnszr_audio/detect_audio',
|
|
|
+ data: {
|
|
|
+ voiceId: props.id,
|
|
|
+ audioRecordId: list.value[current.value].audioId,
|
|
|
+ recordUrl: url,
|
|
|
+ }
|
|
|
+ })
|
|
|
+ }).then((res: any) => {
|
|
|
+ if (current.value === list.value.length) {
|
|
|
+ request({
|
|
|
+ url: '/aimooc/xnszr_audio/submit_job',
|
|
|
+ data: {
|
|
|
+ voiceId: props.id,
|
|
|
+ }
|
|
|
+ })
|
|
|
+ showDialog({
|
|
|
+ title: '成功提醒',
|
|
|
+ message: '采集成功',
|
|
|
+ showCancelButton: false,
|
|
|
+ confirmButtonText: '确定',
|
|
|
+ }).then(() => {
|
|
|
+ router.back()
|
|
|
+ })
|
|
|
+ } else {
|
|
|
+ if (res?.code === '1') {
|
|
|
+ current.value++
|
|
|
+ showSuccessToast('声音采集识别成功')
|
|
|
+ } else {
|
|
|
+ showFailToast(res?.msg)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ resolve(res?.data)
|
|
|
+ }).catch(err => {
|
|
|
+ reject(err)
|
|
|
+ })
|
|
|
+ }, 500);
|
|
|
+ })
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+</script>
|
|
|
+
|
|
|
+<template>
|
|
|
+ <van-nav-bar title="声音采集" left-arrow @click-left="onClickLeft"></van-nav-bar>
|
|
|
+ <div class="flex-auto w-full flex flex-col items-center justify-between py-72px px-6 box-border">
|
|
|
+ <van-loading v-if="loading" size="36px" vertical class="text-xl">加载中...</van-loading>
|
|
|
+ <template v-else>
|
|
|
+ <div class="w-full flex flex-col items-center mb-12">
|
|
|
+ <div class="text-xl mt-26px"><span class="text-hex-DB664D">{{ current + 1 }}</span> / {{ list.length }}</div>
|
|
|
+ <p class="text-base indent mt-28px">
|
|
|
+ {{ list[current]?.text }}
|
|
|
+ </p>
|
|
|
+ </div>
|
|
|
+
|
|
|
+
|
|
|
+ <div class="flex w-full justify-around text-hex-242731">
|
|
|
+ <div class="p-4 rounded-8 bg-white " @click="playAudio">
|
|
|
+ <van-icon name="volume" size="28" />
|
|
|
+ </div>
|
|
|
+ <div class="p-4 rounded-8 bg-white " @click="() => isRecording ? stopAudioRecord() : startAudioRecord()">
|
|
|
+ <van-icon v-show="!isRecording" name="play" size="28" />
|
|
|
+ <!-- <van-icon name="pause" size="28" /> -->
|
|
|
+ <van-icon v-show="isRecording" name="stop" size="28" />
|
|
|
+ </div>
|
|
|
+ <div class="p-4 rounded-8 bg-white " @click="submitAudio">
|
|
|
+ <van-icon name="success" size="28" />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+
|
|
|
+ </div>
|
|
|
+</template>
|