必备插件 js-audio-recorder
父级界面
<template>
<div class="kfMain">
<div class="back"><van-icon name="cross" color="#fff" @click="back" /></div>
<van-image
width="10rem"
height="10rem"
fit="contain"
:src="kfImg"
class="img-kf"
/>
<div class="bk-card">
<div class="content">
<h2>{{ message }}</h2>
<div class="prompt" v-if="!messageInfo">{{ prompt }}</div>
<div class="result" v-if="messageInfo">{{ messageInfo }}</div>
<div class="result-button" v-if="messageInfo">
<van-row
><van-col :span="12"
><span class="result-button1" @click="cleanInfo"
>清空</span
> </van-col
><van-col :span="12"
><span class="result-button2" @click="getRun">发送</span>
</van-col></van-row
>
</div>
<ul class="aubox" v-if="avdioitem">
<li class="au1 auItem"></li>
<li class="au2 auItem"></li>
<li class="au3 auItem"></li>
<li class="au4 auItem"></li>
<li class="au5 auItem"></li>
<li class="au6 auItem"></li>
<li class="au7 auItem"></li>
<li class="au3 auItem"></li>
<li class="au4 auItem"></li>
<li class="au5 auItem"></li>
<li class="au6 auItem"></li>
<li class="au7 auItem"></li>
<li class="au3 auItem"></li>
<li class="au4 auItem"></li>
<li class="au5 auItem"></li>
<li class="au6 auItem"></li>
<li class="au7 auItem"></li>
<li class="au3 auItem"></li>
<li class="au4 auItem"></li>
<li class="au5 auItem"></li>
<li class="au6 auItem"></li>
<li class="au7 auItem"></li>
<li class="au6 auItem"></li>
<li class="au7 auItem"></li>
<li class="au3 auItem"></li>
<li class="au4 auItem"></li>
<li class="au5 auItem"></li>
<li class="au6 auItem"></li>
<li class="au7 auItem"></li>
<li class="au3 auItem"></li>
<li class="au4 auItem"></li>
<li class="au5 auItem"></li>
<li class="au6 auItem"></li>
<li class="au7 auItem"></li>
<li class="au3 auItem"></li>
<li class="au4 auItem"></li>
<li class="au5 auItem"></li>
<li class="au6 auItem"></li>
<li class="au7 auItem"></li>
<li class="au6 auItem"></li>
<li class="au7 auItem"></li>
<li class="au3 auItem"></li>
<li class="au4 auItem"></li>
<li class="au5 auItem"></li>
<li class="au6 auItem"></li>
<li class="au7 auItem"></li>
<li class="au3 auItem"></li>
<li class="au4 auItem"></li>
<li class="au5 auItem"></li>
<li class="au6 auItem"></li>
<li class="au7 auItem"></li>
<li class="au3 auItem"></li>
<li class="au4 auItem"></li>
<li class="au5 auItem"></li>
<li class="au6 auItem"></li>
<li class="au7 auItem"></li>
</ul>
<div style="text-align: center">
<recording
@getAudio="getAudio"
@getResult="getResult"
ref="child"
></recording>
</div>
</div>
</div>
</div>
</template>
<script>
import Recorder from "js-audio-recorder";
import moment from "moment";
import recording from "../components/recording";
export default {
components: { recording },
data() {
return {
recorder: null,
playTime: 0,
timer: null,
src: null,
kfImg: require("../../../assets/images/kfs.png"),
kfmk: require("../../../assets/images/kfmk.png"),
message: "AI助手在听,请提问",
prompt: "请点击下方按钮开始",
items: "开始",
isStart: false,
avdioitem: false, //是否显示音频波纹
messageInfo: null,
};
},
created() {},
methods: {
back() {
this.$router.go(-1);
},
getResult(value) {
this.messageInfo = value;
},
getAudio() {
this.avdioitem = !this.avdioitem;
},
cleanInfo() {
this.messageInfo = null;
this.$refs.child.cleanMessage();
},
getRun() {
this.$router.push({
path: "/xxx",
});
},
},
};
</script>
<style scoped lang="scss">
.kfMain {
.back {
width: 100%;
text-align: right;
margin: 0 -10px;
padding: 10px 0;
}
height: 100vh;
background: linear-gradient(90deg, #00d1ed, #00b5ff, #1890ff);
.img-kf {
position: absolute;
bottom: 280px;
}
.bk-card {
margin: 0 auto;
height: 300px;
position: flex;
bottom: 0px;
padding: 10px;
position: fixed;
.content {
background: #fff;
border-radius: 10px;
height: 300px;
width: calc(100vw - 20px);
h2 {
font-size: 18px;
text-align: center;
padding-top: 30px;
}
.prompt {
padding: 20px 0;
font-size: 14px;
text-align: center;
color: #666;
}
}
}
}
.result {
padding: 10px;
height: 190px;
}
.result-button {
text-align: center;
.result-button1 {
color: #888;
}
.result-button2 {
color: #1890ff;
}
}
.aubox {
display: flex;
align-items: flex-end; //重要属性,让hight翻转过来,往上延伸
justify-content: center;
}
.auItem {
width: 1px;
margin-right: 5px;
list-style: none;
background: black;
height: 20px;
}
.au1 {
animation: audio 0.5s linear 0.1s infinite alternate;
}
.au2 {
animation: audio 0.5s linear 0.2s infinite alternate;
}
.au3 {
animation: audio 0.5s linear 0.5s infinite alternate;
}
.au4 {
}
.au5 {
animation: audio 0.5s linear 0.2s infinite alternate;
}
.au6 {
animation: audio 0.5s linear 0.3s infinite alternate;
}
.au7 {
animation: audio 0.5s linear 0.1s infinite alternate;
}
@keyframes audio {
from {
height: 1px;
}
to {
height: 20px;
}
}
</style>
子组件recording.vue
<template>
<div class="recordPlagin">
<div v-if="yxsbPlay">
<div class="mask" v-if="yingPingDisPlay">
<span>正在听,松开进行搜索!</span>
</div>
<div
@touchstart="gtouchstart()"
@touchend="gtouchend()"
style="background-image: linear-gradient(#FE4C6B, #FE4C6B); font-weight: bold; border-radius: 20px; display: flex;align-items: center;color: #fff; center;padding: 5px 2%;width: 30%;margin: 10px 33%;justify-content: space-evenly;"
>
<img
style="width: 20px; height: 20px"
:src="buttonImg"
v-if="!yingPingDisPlay"
/>
<img style="width: 20px; height: 20px" :src="buttonImg2" v-else />
<div>{{ viodeText }}</div>
</div>
</div>
</div>
</template>
<script>
import Recorder from "js-audio-recorder";
import axios from "axios";
import Config from "../utils/setting";
export default {
data() {
return {
viodeText: "长按说话",
search: "",
yingPingDisPlay: false,
buttonImg: require("../../../assets/images/kfmk1.png"),
buttonImg2: require("../../../assets/images/kfmk2.png"),
recorder: null,
Tolsize: null, //录音大小
yxsbPlay: true,
resultMessage: "",
};
},
created() {
if (!localStorage.getItem("ai_access_token")) {
axios
.post(
`/api/oauth/2.0/token?grant_type=client_credentials&client_id=${Config.client_id}&client_secret=${Config.client_secret}`
)
.then((res) => {
localStorage.setItem("ai_access_token", res.data.access_token);
})
.catch((e) => {});
} else {
}
this.recorder = new Recorder({
sampleBits: 16, // 采样位数,支持 8 或 16,默认是16
sampleRate: 16000, // 采样率,支持 11025、16000、22050、24000、44100、48000,根据浏览器默认值,我的chrome是48000
numChannels: 1, // 声道,支持 1 或 2, 默认是1
// compiling: false,(0.x版本中生效,1.x增加中) // 是否边录边转换,默认是false
});
// 绑定事件-打印的是当前录音数据
this.recorder.onprogress = function (params) {
// alert('--------------START---------------')
// alert('录音时长(秒)', params.duration);
// alert('录音大小(字节)', params.fileSize);
// alert('录音音量百分比(%)', params.vol);
// alert('当前录音的总数据([DataView, DataView...])', params.data);
// alert('--------------END---------------')
};
},
mounted() {
//获取录音权限
Recorder.getPermission().then(
() => {
// this.$vux.toast.text('获取权限成功', 'top');
},
(error) => {
alert(`${error.name} : ${error.message}`);
}
);
},
methods: {
gtouchstart() {
// this.viodeText = '松开搜索'
// (this.buttonImg = require("../../../assets/images/kfmk1.png"))
this.startRecorder();
this.yingPingDisPlay = true;
this.$emit("getAudio");
},
gtouchend(event) {
this.yingPingDisPlay = false;
// this.viodeText = '长按说话'
// this.buttonImg = require("../../../assets/images/kfmk2.png");
this.stopRecorder();
this.getRecorder();
// this.getAudio();
this.$emit("getAudio");
},
//开始录音
startRecorder() {
this.recorder.start().then(
() => {},
(error) => {
// 出错了
alert(`${error.name} : ${error.message}`);
}
);
},
// 结束录音
stopRecorder() {
this.recorder.stop();
},
cleanMessage() {
this.yxsbPlay = true;
},
//获取onload里面的录音信息
getRecordInfo(e) {
var that = this;
let wavValue = e.split("base64,")[1];
var data = {
cuid: "keinfo_str_12456", //用户唯一标识,用来区分用户,计算UV值。建议填写能区分用户的机器 MAC 地址或 IMEI 码,长度为60字符以内。
token: localStorage.getItem("ai_access_token"), //开放平台获取到的开发者[access_token]获取 Access Token "access_token")
SourceType: 1, //语音数据
format: "wav", //识别音频的音频格式。
speech: wavValue,
channel: 1, //声道数,仅支持单声道,请填写固定值 1
len: this.Tolsize, //本地语音文件的的字节数,单位字节
rate: 16000, //采样率,16000、8000,固定值s
};
axios
.post("/vopapi/server_api", data)
.then((res) => {
console.log(res.data.result[0]);
this.recorder.destroy(); // 毁实例
if (res.data.result[0]) {
this.resultMessage = res.data.result[0];
this.yxsbPlay = false;
this.$emit("getResult", this.resultMessage);
}
})
.catch((e) => {
console.log("失败了");
this.recorder.destroy(); // 毁实例
});
},
//获取录音wav
getRecorder() {
let toltime = this.recorder.duration; //录音总时长
let fileSize = this.recorder.fileSize; //录音总大小
var wav = this.recorder.getWAVBlob(); //获取 WAV 数据
this.Tolsize = wav.size;
var reader = new FileReader();
reader.readAsDataURL(wav);
this.search = "";
reader.onload = () => {
this.search = reader.result;
//调用其他方法
this.getRecordInfo(this.search, "");
};
},
},
};
</script>
<style scoped lang="scss">
.recordPlagin {
position: fixed;
bottom: 50px;
width: 100%;
.mask {
margin-bottom: 35px;
img {
width: 100%;
}
span {
display: flex;
justify-content: center;
opacity: 0.5;
}
}
.buttonImg {
width: 135px;
height: 37.44px;
background-size: 100% 100%;
margin: auto;
}
}
</style>
注:百度ai接口需自己制作代理 。 具体逻辑根据自己需求修改 文中icon可私信免费领取,如有需要请私信。
可开发app h5 pc web端 微信小程序 微信公众号等项目 指导毕设等 拥有5年一线开发经验 如有需要私信联系
感谢你的关注。觉得有用点个赞吧!!!!!!!!