以开发客服功能为例,基于AVM框架编写,结合iflyRecognition 模块(封装了 科大讯飞 的SDK 的语音听写、语音在线合成功能),轻松简单地实现了语音转文字客服功能。
stml代码:
<template name='tpl'>
<view class="page">
<safe-area class="header">
<text class="header__title">客服</text>
</safe-area>
<scroll-view class="main" id="box">
<text class="time">{nowtime}</text>
<view class="servicebox">
<img class="avatarimg" src="../../image/kf@3x.png" alt="">
<view class="questionbox">
<view class="question">
<text class="questiontxt">猜你想问</text>
</view>
<view class="question" v-for="(item,index) in listdata" @click="trigger(item)">
<text class="questioncon">{item.titleName}</text>
<img class="rightimg" src="../../image/right.png" alt="">
</view>
</view>
</view>
<view class="answerbox">
<view class="answercon" v-for="(item,index) in showdata">
<text class="time">{item.time}</text>
<view class="userbox" v-if="item.user==1">
<view class="contxtbox">
<text class="answercontxt">{item.con}</text>
</view>
<img class="avatarimg2" src="../../image/wd_tx.png" alt="">
</view>
<view class="serbox" v-if="item.user==2">
<img class="avatarimg" src="../../image/kf@3x.png" alt="">
<view class="contxtbox">
<text class="answercontxt">{item.con}</text>
</view>
</view>
</view>
</view>
</scroll-view>
<view class="footer">
<img @click="phonebtn()" class="phoneimg" src="../../image/phone.png" alt="">
<input class="foottxt" v-model="sendword" type="text">
<button class="footbtn" @click="send()">发送</button>
</view>
<view class="showbox" v-if="isshow">
<view class="wordsbox" v-if="words">
<text class="wordstxt">{words}</text>
</view>
<view class="mainbox" @click="stop()">
<img class="ypgif" src="../../image/yp.gif" alt="">
<img class="stopimg" src="../../image/xslx_lzz@2x.png" alt="">
</view>
</view>
</view>
</template>
<script>
export default {
name: "tpl",
apiready() {
this.data.nowtime = this.getTimeData()//当前时间
this.init()//模块初始化
},
data() {
return {
nowtime: '',//当前时间
listdata: [//想问的问题
{
titleName: "公告",
titleContent: "2021年12月1日至2022年1月31日,APP开展深圳地区公测,欢迎各位家长及同学们参与公测并给我们提供宝贵的意见、建议。公测期间前100位成功注册的用户将免费获得VIP课程。",
},
{
titleName: "账号与登录",
titleContent: "输入手机号码,在获取验证码后可以快速完成账户注册。在这个过程中您需要选择并确认您的身份(学生、老师)。选择学生身份:请同学您按指引要求填写相关信息后点击“提交”完成账户注册。选择老师身份:请老师您按指引要求填写相关信息后点击“提交”完成老师身份的账户注册。",
},
{
titleName: "选择课程",
titleContent: "在【学习】栏目内,您可以选择您想要的课程内容,包括可以免费使用的“听、背、读”部分的内容,以及收费的“诵、讲”部分的VIP内容。完成充值后即可使用VIP内容。",
},
{
titleName: "充值与消费",
titleContent: "目前我们设立有“月卡VIP会员”、“季卡VIP会员”、“半年VIP会员”、“年卡VIP会员”四个档次,您可以根据自己的需求来购买会员。(公测期间,前100位注册用户可免费获得终生VIP用户权限)。",
},
{
titleName: "操作问题",
titleContent: "请您简单描述一下您所遇到的操作问题,现在由于咨询的人数较多,我们将尽快予以答复,请您耐心等待。",
},
{
titleName: "反馈bug",
titleContent: "请您简单描述一下您所遇到的bug,我们会将您所提供的线索及时反馈给技术部门,感谢给予我们的帮助。",
},
{
titleName: "建议",
titleContent: "我们非常乐于倾听您的声音,感谢您宝贵的建议!",
},
{
titleName: "投诉",
titleContent: "请您简单描述一下您要投诉的内容,现在由于咨询的人数较多,我们将尽快予以答复,请您耐心等待。",
}
],
isshow: false,//显示话筒输入
words: '',//文本
showdata: [],//显示的数据
sendword: "",//发送文字
};
},
computed: {
},
methods: {
//获取当前时间时分
getTimeData() {
var data = new Date()
var h = data.getHours() < 10 ? '0' + data.getHours() : data.getHours()
var m = data.getMinutes() < 10 ? '0' + data.getMinutes() : data.getMinutes()
var now = h + ':' + m
return now
},
//模块初始化
init() {
console.log("初始化");
var iflyRecognition = api.require('iflyRecognition');
iflyRecognition.createUtility({
ios_appid: '******',
android_appid: '*******'
}, function (ret, err) {
if (ret.status) {
console.log('创建成功');
} else {
console.log('创建失败');
}
});
},
//话筒输入
phonebtn() {
this.data.isshow = true
this.start()//开始识别
},
//开始识别
start() {
console.log("开始");
var that =this
var iflyRecognition = api.require('iflyRecognition');
iflyRecognition.record({
vadbos: 10000,
vadeos: 10000,
rate: 16000,
asrptt: 1,
}, function (ret, err) {
if (ret.status) {
that.data.words = ret.wordStr
console.log(JSON.stringify(ret));
} else {
console.log(JSON.stringify(err));
}
});
},
//停止
stop() {
this.data.isshow = false
console.log("停止");
var iflyRecognition = api.require('iflyRecognition');
iflyRecognition.stopRecord();
this.data.sendword =this.data.words
},
//点击问题
trigger(item) {
var obj = {
time: this.getTimeData(),
user: 1,//用户
con: item.titleName//用户点击的问题内容
}
this.data.showdata.push(obj) //用户点击的数据
document.getElementById('box').scrollTo({ position: 'lower' });//滚动到底部
//一秒后客服回答
setTimeout(() => {
var obj2 = {
time: this.getTimeData(),
user: 2,//客服
con: item.titleContent //回答的内容
}
this.data.showdata.push(obj2) //客服回答
}, 1000)
setTimeout(() => {
document.getElementById('box').scrollTo({ position: 'lower' });//滚动到底部
}, 1100)
},
//发送问题
send() {
var obj = {
time: this.getTimeData(),
user: 1,
con: this.data.sendword//用户输入的内容
}
this.data.showdata.push(obj) //用户发送的问题内容
document.getElementById('box').scrollTo({ position: 'lower' });//滚动到底部
//一秒后客服回答
setTimeout(() => {
var obj2 = {
time: this.getTimeData(),
user: 2,//客服
con: "反馈成功,24小时以内会联系您" //回答的内容
}
this.data.showdata.push(obj2) //客服回答
}, 1000)
setTimeout(() => {
document.getElementById('box').scrollTo({ position: 'lower' });//滚动到底部
}, 1100)
this.data.sendword = ""
},
}
};
</script>
<style>
.page {
height: 100%;
background-color: #fafafa;
}
.header {
background: #81a9c3;
justify-content: center;
align-items: center;
}
.header__title {
color: #fff;
font-size: 18px;
font-weight: bold;
height: 50px;
line-height: 50px;
}
.main {
flex: 1;
padding: 15px;
}
.time {
text-align: center;
line-height: 24px;
color: rgb(78, 78, 78);
}
.servicebox {
flex-direction: row;
}
.avatarimg {
width: 40px;
height: 40px;
margin-right: 10px;
border-radius: 50%;
}
.avatarimg2 {
width: 40px;
height: 40px;
margin-left: 10px;
border-radius: 50%;
}
.questionbox {
width: 200px;
background-color: #ffffff;
padding: 10px;
}
.question {
width: 100%;
padding: 5px;
flex-direction: row;
justify-content: space-between;
align-items: center;
border-bottom: 1px solid rgb(219, 219, 219);
}
.questiontxt {
color: rgb(0, 0, 0);
font-size: 16px;
}
.questioncon {
color: rgb(107, 107, 107);
font-size: 14px;
}
.rightimg {
width: 7px;
height: 12px;
}
.answercon {
padding: 10px 0px;
}
.userbox {
width: 100%;
flex-direction: row;
justify-content: flex-end;
}
.serbox {
width: 100%;
flex-direction: row;
justify-content: left;
}
.contxtbox {
background: #fff;
padding: 10px;
border-radius: 8px;
align-items: center;
}
.answercontxt {
font-size: 14px;
color: #333;
}
.footer {
width: 100%;
height: 60px;
background: #ffffff;
flex-direction: row;
justify-content: center;
align-items: center;
padding: 20px;
}
.phoneimg {
width: 30px;
height: 30px;
margin-right: 10px;
}
.foottxt {
width: 75%;
height: 30px;
padding: 0 5px;
}
.footbtn {
margin-left: 10px;
width: 80px;
height: 30px;
background-color: rgba(251, 131, 78, 0.8);
color: #fff;
}
.showbox {
width: 100%;
height: 100%;
background: rgba(33, 6, 0, 0.4);
position: absolute;
z-index: 9;
top: 0px;
left: 0px;
justify-content: center;
align-items: center;
}
.wordstxt {
background: #ffffff;
padding: 10px;
}
.mainbox {
width: 150px;
height: 80px;
justify-content: center;
align-items: center;
}
.ypgif {
width: 150px;
position: absolute;
top: 0;
left: 0;
z-index: -1;
}
.stopimg {
width: 70px;
}
</style>
效果图: