import { getreadInfo } from '~/api/video' import { publishWorks, uploadPk } from '~/api/works' import { createStoreBindings } from 'mobx-miniprogram-bindings' import { store } from '~/store/index' const aiengine = require('~/utils/ChivoxAiEngine') const sha1 = require('~/utils/sha1'); // 文章行高 let rowH = 0 let videoContext = null // 滚动变色定时器 let stl = null // 倒计时 let setTimeoutObj = null // 录音 let innerAudioContext = null let resultAudioContext = null /*创建基础引擎*/ let wsEngine = aiengine.createWsEngine({}); /*微信录音*/ let recorderManager = wx.getRecorderManager(); Page({ data: { videoInfo: {}, currentRow: null, state: false, countDown: { state: false, num: 3, }, contentH: 0, scrollTop: 0, //如果readingReset为true就是重读 readingReset: false, //readingType为public是普通阅读,为pk是pk逻辑,readMatch为朗读赛 readingType: 'public', percent: 0, uploadState: false, article: [] }, onLoad(options) { let videoId = options.videoId this.getreadInfo(videoId, options.reset) console.log(options, 'options'); this.setData({ readingReset: options.reset || false, readingType: options.readingType || 'public' }) // 手工绑定 this.storeBindings = createStoreBindings(this, { store, fields: { userInfo: 'userInfo', readDetail: 'readDetail', pkData: 'pkData' }, actions: { setReadDetail: 'setReadDetail' } }) // 录音授权 wx.getSetting({ success(res) { if (!res.authSetting['scope.record']) { wx.authorize({ scope: 'scope.record', success() { // 用户已经同意小程序使用录音功能,后续调用接口不会弹窗询问 wx.getRecorderManager() } }) } } }) /*监听评测结果:必须在基础引擎创建后,调用任何评测接口前设置监听,否则有可能收不到相关事件。*/ wsEngine.onResult((res) => { this.getRecordScore(res) }); wsEngine.onErrorResult((res) => { console.log("===收到错误结果=============", res) }); }, // 获取阅读内容 async getreadInfo(videoId, reset = false) { let videoInfo = await getreadInfo(videoId) wx.setNavigationBarTitle({ title: videoInfo.userRead.title }) let data console.log(videoInfo); if (videoInfo.userReadExtend) { data = JSON.parse(videoInfo.userReadExtend.lessonText) data = data.map((item, index) => { item.time = Number(item.time) item.readTime = data[index + 1] ? data[index + 1].time - item.time : '' return item }) } else { data = videoInfo.userRead.lessonText.split('\n'), console.log(data); } this.setData({ article: data, videoInfo }) if (!reset) { this.getHeight() } if (!this.data.videoInfo.userReadExtend || this.data.videoInfo.userReadExtend.resourcesType == 0) { this.videoContext = wx.createVideoContext('myVideo') } else { this.innerAudioContext = wx.createInnerAudioContext(); this.innerAudioContext.src = videoInfo.userRead.audioPath this.innerAudioContext.onEnded(res => { this.finishRecord() }) this.innerAudioContext.onStop((res) => { this.finishRecord() }); } }, // 开始录制 setCountDown() { let child = this.selectComponent('#readingTips').data // 判断是否有权限朗读 不是vip并且没有朗读机会 const isVip = child.vipTime ? true : false if (!isVip && child.userInfo.experienceAmount == 0) { return this.selectComponent('#readingTips').showModal(); } if (this.data.state) { this.finishRecord() return } if (this.data.readingReset) { this.clearReset() this.getHeight() } this.setData({ 'countDown.state': true }) this.stl = setInterval(() => { if (this.data.countDown.num == 0) { clearInterval(this.stl) this.setData({ state: true, countDown: { state: false, num: 3 } }) this.soundRecording() this.playMediaState() this.startRecording() } else { this.setData({ 'countDown.num': --this.data.countDown.num }) } }, 1000) }, // 录音 soundRecording() { /*调用微信开始录音接口,并启动语音评测*/ let timeStamp = new Date().getTime() let sig = sha1(`16075689600000da${timeStamp}caa8e60da6042731c230fe431ac9c7fd`) let app = { applicationId: '16075689600000da', sig, //签名字符串 alg: 'sha1', timestamp: timeStamp + '', userId: wx.getStorageSync('uid') } let lessonText = this.data.videoInfo.userRead.lessonText; wsEngine.start({ request: { coreType: "cn.pred.raw", refText: lessonText, rank: 100, attachAudioUrl: 1, result: { details: { gop_adjust: 1 } } }, app, audio: { audioType: "mp3", channel: 1, sampleBytes: 2, sampleRate: 16000 }, success: (res) => { /*引擎启动成功,可以启动录音机开始录音,并将音频片传给引擎*/ const options = { sampleRate: 44100, //采样率 numberOfChannels: 1, //录音通道数 encodeBitRate: 192000, //编码码率 format: 'mp3', //音频格式,有效值aac/mp3 frameSize: 50 //指定帧大小,单位 KB }; //开始录音,在开始录音回调中feed音频片 recorderManager.start(options); }, fail: (res) => { console.log("fail============= " + res); }, }); //监听录音开始事件 recorderManager.onStart(() => {}); //监听录音结束事件 recorderManager.onStop((res) => { console.log('录音结束', res); this.setData({ tempFilePath: res.tempFilePath, }); //录音机结束后,驰声引擎执行结束操作,等待评测返回结果 wsEngine.stop({ success: () => { console.log('====== wsEngine stop success ======'); }, fail: (res) => { console.log('录音结束报错', res); }, }); }); //监听已录制完指定帧大小的文件事件。如果设置了 frameSize,则会回调此事件。 recorderManager.onFrameRecorded((res) => { const { frameBuffer } = res //TODO 调用feed接口传递音频片给驰声评测引擎 wsEngine.feed({ data: frameBuffer, // frameBuffer为微信录音机回调的音频数据 success: () => { console.log('feed success.监听已录制完指定帧大小的文件事件') }, fail: (res) => { console.log('监听已录制完指定帧大小报错', res) }, }); }); }, // 结束录制 finishRecord() { recorderManager.stop(); this.stopMediaState() clearTimeout(this.setTimeoutObj) clearInterval(this.stl) this.setData({ state: false, currentRow: null, scrollTop: 0 }) }, // 获取测评结果 getRecordScore(res) { console.log('获取评测结果'); const result = res.result; const integrity = Math.floor(result.integrity); //完成度 const tone = Math.floor(result.tone); // 语调声调 const accuracy = Math.floor(result.overall); // 准确度 发音分 const fluency = Math.floor(result.fluency.overall); //流利度 let myOverall = Math.floor(integrity * 0.3 + accuracy * 0.5 + fluency * 0.1 + tone * 0.1); let detail = { integrity, tone, accuracy, fluency, myOverall, tempFilePath: this.data.tempFilePath, title: this.data.videoInfo.userRead.title, id: this.data.videoInfo.userRead.exampleId, coverImg: this.data.videoInfo.userRead.coverImg, originVideo: this.data.videoInfo.userRead.originVideo } this.setReadDetail(detail) if (this.data.readingType == 'public' || this.data.readingType == 'readMatch') { wx.redirectTo({ url: `/pages/score/index?readingType=${this.data.readingType}` }) } else { this.uploadAudio(detail) } }, // 挑战录音上传 uploadAudio(detail) { this.setData({ uploadState: true }) const uploadTask = wx.uploadFile({ url: 'https://reader-api.ai160.com//file/upload', filePath: this.data.tempFilePath, name: '朗读录音', header: { uid: wx.getStorageSync('uid') }, success: async (res) => { const formateRes = JSON.parse(res.data); let audioPath = formateRes.data; let uploadRes = await publishWorks({ exampleId: this.data.pkData.exampleId, audioPath }) console.log('uploadRes', uploadRes); /* let winnerUId = this.data.pkData > detail.myOverall ? this.data.pkData.exampleId : this.data.pkData < detail.myOverall ? detail.id : '' */ let data = { challengerUserReadId: uploadRes.id, userReadId: this.data.pkData.id, } await uploadPk(data) wx.redirectTo({ url: '/pages/pkResult/index' }) }, complete: () => { this.setData({ uploadState: false }) } }); uploadTask.onProgressUpdate((res) => { this.setData({ percent: res.progress }) }) }, // 测试的 pkResult() { wx.redirectTo({ url: `/pages/score/index?readingType=${this.data.readingType}` }) /* wx.redirectTo({ url: `/pages/pkResult/index`, }) */ }, // 字体换行 startRecording() { if (this.data.currentRow == null) { this.setData({ currentRow: 0 }) } let row = this.data.article[this.data.currentRow] if (!row.readTime) { return } this.setTimeoutObj = setTimeout(() => { this.setData({ currentRow: ++this.data.currentRow }) this.setData({ scrollTop: this.rowH * this.data.currentRow }) this.startRecording() }, row.readTime); }, // 视频播放结束 videoEnd() { this.finishRecord() }, videoPlay() { if (this.data.readingReset) { this.resultAudioContext = wx.createInnerAudioContext(); this.resultAudioContext.src = this.data.readDetail.tempFilePath; // 这里可以是录音的临时路径 this.resultAudioContext.play(); } }, // 清除试听状态 clearReset() { if (this.resultAudioContext) { this.resultAudioContext.stop() } this.setData({ readingReset: false }) }, // 控制视频或音频的播放状态 playMediaState() { if (!this.data.videoInfo.userReadExtend || this.data.videoInfo.userReadExtend.resourcesType == 0) { this.videoContext.play() } else { this.innerAudioContext.play(); } }, // 控制视频或音频的暂停状态 stopMediaState() { if (!this.data.videoInfo.userReadExtend || this.data.videoInfo.userReadExtend.resourcesType == 0) { this.videoContext.stop() this.videoContext.seek(0) } else { this.innerAudioContext.stop() } }, // 获取设备高度与行高度 getHeight() { var query = wx.createSelectorQuery(); query.select('.content').boundingClientRect((rect) => { this.setData({ contentH: rect.height }) }).exec() query.select('.row').boundingClientRect((rect) => { this.rowH = rect.height }).exec() }, /** * 生命周期函数--监听页面卸载 */ onUnload() { wsEngine.reset() recorderManager.stop(); if (this.innerAudioContext) { this.innerAudioContext.stop() } clearTimeout(this.setTimeoutObj) clearInterval(this.stl) }, })