import httpRequestApi from '../../utils/APIClient'; const aiengine = require('../../utils/ChivoxAiEngine') const sha1 = require('../../utils/sha1'); import { getUserInfo, getVipInfo } from '~/api/user' const app = getApp() import { formatDate } from '../../utils/util'; Page({ data: { userInfo: {}, isVip: false, title: '', id: '', img: '', fullScreenBtn: false, playBtn: true, gesture: true, muted: false, gesture: false, centerBtn: true, recordFlag: 0, recordSource: '', videoCtr: 'recordingVideoEnd', btnFlag: false, btnImgFlag: false, microphonePng: '../../static/index/microphone.png', recordingGif: '../../static/index/readingNow.gif', videoUrl: '', readingText: '', videoList: [], pageNo: 1, totalSize: 0, nextMargin: getApp().globalData.nextMargin, lowerThresHold: 100, isVideoListShow: true, overall: '', // 评测总分 integrity: '', //完成度 tone: '', //语调声调 fluency: '', //流利度 accuracy: '', // 正确分,发音分 star: [0, 0, 0, 0, 0], ifTextShow: true, ifScoreDialogShow: false, ifScoreShow: false, statusbarobj: { isshowbtn: false, //是否显示按钮 title: "小学语文朗读配音", //标题 }, isScroll: true, noMoreWork: false, authHide: true, authImg: '', isIOS: app.globalData.isIOS, payPrice: '' }, onLoad: function(option) { console.log(option); this.videoCtx = null; const uid = wx.getStorageSync('uid') this.getClassInfo(option.id); // this.getMicAuth() }, getClassInfo: function(id) { httpRequestApi.getClassDetail(id).success(res => { wx.setNavigationBarTitle({ title: res.data.data.userRead.title, }) console.log('课程信息', res) let reg = /\\n/g this.setData({ title: res.data.data.userRead.title, videoUrl: res.data.data.userRead.videoPath, videoPathTemp: res.data.data.userRead.videoPath, originVideo: res.data.data.userRead.originVideo, img: res.data.data.userRead.iconImg, id: res.data.data.userRead.id, readingText: res.data.data.userRead.lessonText, grade: res.data.data.userRead.grade, exampleId: res.data.data.userRead.exampleId, summary: res.data.data.userRead.summary, coverImg: res.data.data.userRead.coverImg, shareImg: res.data.data.userRead.shareImg, }) this.getReadInfo(id) httpRequestApi.userIntoPage('pages/reading/reading', '朗读页面').success((res) => { }) }) }, onHide: function() { console.log('onhide') if (this.data.btnImgFlag) { this.recorderManager.stop(); } if (this.innerAudioContext) { this.innerAudioContext.stop(); } // this.ss.destroyEngine(); this.setData({ recordFlag: 0 }) }, onUnload: function() { console.log('onUnload') if (this.data.btnImgFlag) { this.recorderManager.stop(); } if (this.innerAudioContext) { this.innerAudioContext.stop(); } }, onShow: function() { // this.getUserInfo() this.videoCtx = wx.createVideoContext('myVideo', this); let data = requirePlugin("myPlugin"); const obj = { appid: 'a415', userid: wx.getStorageSync('uid'), getEvalMessage: (res) => { this.getRecordScore(res) // console.log('评测结果',res) }, recorderCallback: (type, data) => { // 录音测评监控回调 this.ssRecorderCallback(type, data) } } // this.ss = new data.ssEngine(obj); this.recorderManager = wx.getRecorderManager(); this.recorderManager.onStop((res) => { this.videoCtx.seek(0); this.videoCtx.stop(); console.log('recorder stop', res) const recordFile = res.tempFilePath; this.setData({ recordFlag: 0, recordSource: recordFile, btnFlag: true, btnImgFlag: false }) this.wsEngine.stop({ success: () => { console.log('====== wsEngine stop success ======'); wx.showLoading({ title: '作品评测中', mask: true }) // TODO: add your code here }, fail: (res) => { console.log("====== wsEngine stop fail ======"); console.log(JSON.stringify(res)); //请关注res.errId, res.error // TODO: add your code here }, complete: () => { // TODO: add your code here // clearInterval(recordTimeInterval); console.log("====== wsEngine stop complete ======"); } }); }) this.recorderManager.onStart(() => { // this.saveVideo(); this.setData({ btnImgFlag: true, btnFlag: false }) console.log('recorder start') }); //监听已录制完指定帧大小的文件事件。如果设置了 frameSize,则会回调此事件。 this.recorderManager.onFrameRecorded((res) => { const { frameBuffer } = res console.log('frameBuffer.byteLength', frameBuffer.byteLength) //TODO 调用feed接口传递音频片给驰声评测引擎 this.wsEngine.feed({ data: frameBuffer, // frameBuffer为微信录音机回调的音频数据 success: () => { // feed 成功 console.log('feed success.') }, fail: (res) => { // feed 失败, 请关注res.errId, res.error console.log('feed fail:', JSON.stringify(res)) }, complete: () => { // feed 完成 } }); }); }, async getUserInfo() { /* let userInfo = await getUserInfo() let vip = await getVipInfo() console.log(userInfo); this.setData({ userInfo, isVip: vip ? true : false }) */ }, ssRecorderCallback: function(type, data) { /* 录音开始 */ if (type === 'onStart') { this.setData({ btnImgFlag: true, btnFlag: false }) console.log('recorder start') } if (type === 'onStop') { this.videoCtx.stop(); this.setData({ recordFlag: 0, recordSource: data.tempFilePath, btnFlag: true, btnImgFlag: false }) console.log('recorder start') } }, // 录音中视频播放结束 (控制录音同时结束) recordingVideoEnd: function() { console.log(this.data.videoCtr) console.log('recordingVideoEnd'); // if (this.data.recordFlag === 0) { // this.recordStop(); this.playingVideoEnd(); return; } // 录音结束 if (this.data.recordFlag === 1) { this.recordStop(); } }, // 播放中视频播放结束 (控制录音同时结束) playingVideoEnd: function() { console.log('playingVideoEnd') // this.ss.stopPlay(); }, /*** * recordFlag: * 0 初始状态 * 1 录音中 * 2 录音结束 ***/ audioRecord: function() { let child = this.selectComponent('#readingTips').data // 判断是否有权限朗读 不是vip并且没有朗读机会 const isVip = child.vipTime ? true : false if (!isVip && child.userInfo.experienceAmount == 0) { this.selectComponent('#readingTips').showModal(); } else { if (this.recorderManager) { this.recorderManager.stop(); } if (this.innerAudioContext) { this.innerAudioContext.stop(); } if (this.data.recordFlag === 0) { this.wsEngine = aiengine.createWsEngine({}); this.wsEngine.onResult(res => { wx.hideLoading(); this.getRecordScore(res) }) this.wsEngine.onErrorResult(res => { wx.hideLoading(); console.log('驰声createWsEngine失败', res); }) this.videoComplete(); if (this.data.btnFlag) { httpRequestApi.userEvent('RERECORDING'); } else { httpRequestApi.userEvent('READING', this.data.exampleId); } // this.getMicAuth() return; } // 录音结束后 if (this.data.recordFlag === 1) { wx.showLoading({ title: '作品转码中', mask: true }) this.recordStop(); } } }, // 录音开始 /** * duration: 时长 最长10分钟 sampleRate: 44100, 采样率 numberOfChannels: 1, 录音通道 encodeBitRate: 192000, 码率 format: 'mp3', 格式 frameSize: 50 制定帧大小 */ recordStart: function() { console.log('录音开始'); const options = { duration: 600000, sampleRate: 44100, numberOfChannels: 1, encodeBitRate: 192000, format: 'mp3', frameSize: 50 } this.recorderManager.start(options); // this.ss.startRecord({ // coreType: 'cn.sent.score', //测评题型 // evalTime: 300000, //测评的录音时间,时间到自动停止测评 // refText: this.data.readingText, //测评文本 // warrantId: 'c11163aa6c834a028da4a4b30955be96', //鉴权id // }) // 驰声测评 let timeStamp = new Date().getTime() let sig = sha1(`16075689600000da${timeStamp}caa8e60da6042731c230fe431ac9c7fd`) console.log('加密串', sig) // return let app = { applicationId: '16075689600000da', sig, //签名字符串 通过签名算法alg(appkey + timestamp + secretKey)生成 alg: 'sha1', timestamp: timeStamp + '', userId: wx.getStorageSync('uid') } console.log('app数据', app) let lessonText = this.data.readingText; console.log('课文课文课文', lessonText) this.wsEngine.start({ app, request: { coreType: "cn.pred.raw", refText: lessonText, rank: 100, attachAudioUrl: 1, result: { details: { gop_adjust: 1 } } }, audio: { audioType: "mp3", channel: 1, sampleBytes: 2, sampleRate: 16000 }, success: (res) => { // 调用成功 console.log('驰声start成功', res) }, fail: (res) => { // start失败,请关注res.errId, res.error console.log('驰声start失败', res) } }) }, getMicAuth() { let _this = this; wx.getSetting({ success(res) { if (res.authSetting['scope.record']) { _this.videoComplete(); } else { _this.getMicSetAuth(); return; } } }) }, getMicSetAuth() { let _this = this; wx.authorize({ scope: 'scope.record', success() { // 用户已经同意小程序使用录音功能,后续调用 wx.startRecord 接口不会弹窗询问 _this.audioRecord(); }, fail() { wx.showModal({ title: '录音前请打开麦克风权限', content: '', confirmText: '我知道了', showCancel: false, success(res) { // console.log('用户点击确定') wx.openSetting({ success(res) { console.log('跳转到设置页', res.authSetting) // res.authSetting = { // "scope.userInfo": true, // "scope.userLocation": true // } } }) } }) } }) }, // 录音结束 recordStop: function() { this.setData({ muted: false }) // this.ss.stopRecord(); console.log('录音结束') this.recorderManager.stop(); wx.hideLoading() }, // 获取测评结果 getRecordScore(res) { console.log('测评结果', JSON.stringify(res)) const result = res.result; const overall = result.overall; // 总分 const integrity = result.integrity; //完成度 const tone = result.tone; // 语调声调 // const accuracy = result.accuracy; // 准确度 发音分 const accuracy = result.overall; // 准确度 发音分 const fluency = result.fluency.overall; //流利度 let starArray = []; let myOverall = integrity * 0.3 + accuracy * 0.5 + fluency * 0.1 + tone * 0.1; // let myOverall = 80; console.log('我的总分', myOverall) if (myOverall < 5) { starArray = [0, 0, 0, 0, 0] } else if (5 <= myOverall && myOverall < 30) { starArray = [1, 0, 0, 0, 0] } else if (30 <= myOverall && myOverall < 50) { starArray = [1, 1, 0, 0, 0] } else if (50 <= myOverall && myOverall < 70) { starArray = [1, 1, 1, 0, 0] } else if (70 <= myOverall && myOverall < 90) { starArray = [1, 1, 1, 1, 0] } else if (90 <= myOverall) { starArray = [1, 1, 1, 1, 1] } // let score = myOverall / 20; // if (score <= 0) { // starArray = [0, 0, 0, 0, 0] // } else { // for (let i = 1; i < 5; i += 0.9) { // if (i <= score) { // starArray.push(1); // } else { // starArray.push(0) // } // } // } this.setData({ overall, integrity, tone, accuracy, fluency, ifScoreDialogShow: true, star: starArray }) }, closeScoreDialog() { this.setData({ ifScoreDialogShow: false, ifScoreShow: true, ifTextShow: false }) }, // 播放录音 audioPlay: function() { /* 用了先声智能以后录音播放由先声只能接管 */ if (this.innerAudioContext) { this.innerAudioContext.stop(); this.videoCtx.stop(); } this.innerAudioContext = wx.createInnerAudioContext(); this.innerAudioContext.src = this.data.recordSource; // 这里可以是录音的临时路径 console.log('音频路径', this.data.recordSource) this.setData({ videoUrl: this.data.videoUrl, muted: true }) console.log(this.innerAudioContext.src); this.videoCtx.play(); this.innerAudioContext.play(); }, exampleVideoPlay: function() { if (this.data.videoPathTemp == this.data.videoUrl) { // 播放记录增加一条 httpRequestApi.playLogReport({ userReadId: this.data.id, playStopTime: 1000 }).success(res => { console.log('播放记录', res) }) } httpRequestApi.userEvent('EXAMPLE'); }, videoComplete: function() { this.setData({ recordFlag: 1, videoUrl: this.data.originVideo, centerBtn: false, playBtn: false, isVideoListShow: false, muted: false, ifTextShow: true, ifScoreShow: false }, () => { console.log('播放视频播放视频播放视频') // this.videoCtx.seek(1); this.videoCtx.stop(); this.videoCtx.play(); this.recordStart(); }) }, // 上传 upload: function() { if (this.videoCtx) { this.videoCtx.stop(); } if (this.data.audioPlaying) { // this.ss.stopPlay(); this.setData({ audioPlaying: false }) } wx.showLoading({ title: '作品上传中', mask: true }) const recordSource = this.data.recordSource; wx.uploadFile({ url: 'https://reader-api.ai160.com//file/upload', filePath: recordSource, name: '朗读录音', header: { uid: wx.getStorageSync('uid') }, success: (res) => { const formateRes = JSON.parse(res.data); let audioPath = formateRes.data; this.shareWorks(audioPath); } }) }, shareWorks: function(audio) { const data = { "lessonId": this.data.id, "originVideo": this.data.videoUrl, "audioPath": audio, "title": this.data.title, "iconImg": this.data.img, "summary": this.data.summary, "productId": this.data.productId, "grade": this.data.grade, "exampleId": this.data.exampleId, "coverImg": this.data.coverImg, "shareImg": this.data.shareImg }; httpRequestApi.postWork(data).success(res => { wx.hideLoading({ success: () => { wx.showToast({ title: '作品已上传正在审核中', icon: 'none', duration: 1000, success: () => { console.log('上传成功', res); if (res.data.count > 0) { this.setData({ flowerNum: res.data.count }) } const _data = this.data; const scoreData = { "userReadId": res.data.data.id, "complete": _data.integrity, "accuracy": _data.accuracy, "speed": _data.fluency, "intonation": _data.tone, "score": _data.overall } // 上传评分 httpRequestApi.postWorksScore(scoreData).success(res => { console.log(res) }); const pages = getCurrentPages(); const prevPage = pages[pages.length - 2]; prevPage.setData({ // workId: res.data.data.id, // 有id就塞到第一位 fromReading: true }, () => { wx.redirectTo({ url: '/pages/userWorks/index' }) }) } }) } }); }).fail(res => { wx.hideLoading({ success: () => { wx.showToast({ title: '上传超时', icon: 'fail', duration: 1000 }) } }); }) httpRequestApi.userEvent('UPLOAD'); }, // 获取本课朗读内容 getReadInfo: function(id, pageNo, pageSize) { // const uid = wx.getStorageSync('uid'); const data = { exampleId: this.data.id || id, pageNo: this.data.pageNo, pageSize: 3, type: 'READ' }; httpRequestApi.getClassRead(data).success(res => { const readInfo = res.data.data.list; readInfo.forEach(item => { const temp = {}; temp.title = item.userRead ? item.userRead.title : ''; temp.img = item.userRead.iconImg; temp.plays = item.userRead.playAmount ? item.userRead.playAmount : 0; temp.likes = item.userRead.likeAmount ? item.userRead.likeAmount : 0; temp.shareAmount = item.userRead.shareAmount; temp.favoritesAmount = item.userRead.favoritesAmount; temp.commentAmount = item.userRead.commentAmount ? item.userRead.commentAmount : 0; temp.classId = item.userRead.exampleId; temp.time = formatDate(item.userRead.gmtCreated, 3); temp.avatar = item.user ? item.user.avatar : ''; temp.uid = item.user ? item.user.uid : ''; temp.url = item.userRead.videoPath; temp.isLike = item.isLike; // temp.avatar = item.user.avatar; temp.nickName = item.user ? item.user.nickName : ''; temp.id = item.userRead.id; temp.noReading = true; temp.isFans = item.isFans ? true : item.user.uid === this.uid ? true : false; temp.coverImg = item.userRead.coverImg; temp.videoShow = false; temp.grade = item.userRead.grade; temp.type = item.userRead.type; temp.shareImg = item.userRead.shareImg; item.isActivity && (temp.activity = true); // recommendWorks.push(temp); // that.data.hotData.hotWorks.push(temp); this.data.videoList.push(temp); }); this.setData({ videoList: this.data.videoList, totalSize: res.data.data.totalSize, noMoreWork: readInfo.length <= 0 ? true : false }) }); }, // 评论区点击 commentTap: function(e) { console.log('点击评论区', e) if (e.target.dataset.type === 'blank') { if (this.data.commentShow && this.data.commentId) { httpRequestApi.getClassDetail(this.data.commentId).success(res => { console.log('评论回显', res.data.data.userRead.commentAmount) let str = `videoList[${this.data.commentIndex}].commentAmount`; this.setData({ [str]: res.data.data.userRead.commentAmount }) }) } this.setData({ commentShow: false }) } }, scrollToLower: function(e) { console.log('滑动到底部', e) this.setData({ pageNo: this.data.pageNo + 1 }, () => { this.getReadInfo() }) }, onReachBottom: function(e) { console.log('滑动到底部', e) this.setData({ pageNo: this.data.pageNo + 1 }, () => { this.getReadInfo() }) }, scrollToUpper: function(e) { console.log('滑动到顶部', e) }, // 打开评论 openComment: function(e) { console.log('id', e.detail.activeId) this.setData({ commentShow: !this.data.commentShow, commentId: e.detail.activeId, commentIndex: e.detail.activeIndex }); }, goToReading: function(e) { this.setData({ pageNo: 1, videoList: [] }) const id = e.detail.activeId ? e.detail.activeId : e.currentTarget.dataset.id; this.getClassInfo(id) }, creatShare(video) { return new Promise((resolve, reject) => { let context = wx.createSelectorQuery(); context .select('#share') .fields({ node: true, size: true }).exec((res) => { const canvas = res[0].node; const ctx = canvas.getContext('2d'); const dpr = wx.getSystemInfoSync().pixelRatio; canvas.width = res[0].width * dpr; canvas.height = res[0].height * dpr; ctx.scale(dpr, dpr); ctx.font = '14px PingFang'; let pic = canvas.createImage(); pic.src = video.coverImg; //可以是本地,也可以是网络图片 pic.onload = () => { ctx.drawImage(pic, 0, 0, 375, 211); } let peiyin = canvas.createImage(); peiyin.src = '/static/image/peiyin.jpg'; peiyin.onload = () => { ctx.drawImage(peiyin, 0, 211, 375, 89); // 收藏,一个一个渲染 let sc = canvas.createImage(); sc.src = '/static/image/no_collect.png' sc.onload = () => { ctx.drawImage(sc, 12, 220, 20, 20) ctx.fillText('收藏', 36, 238) //分享 let fx = canvas.createImage(); fx.src = '/static/index/share.png' fx.onload = () => { ctx.drawImage(fx, 78, 220, 22, 22) ctx.fillText('分享', 104, 238) //点赞 let dz = canvas.createImage(); dz.src = video.isLike ? '/static/index/heart_colored.png' : '/static/index/heart.png' dz.onload = () => { ctx.drawImage(dz, 258, 222, 22, 22) ctx.fillText(video.likes, 284, 238) //评论 let pl = canvas.createImage(); pl.src = '/static/index/comment.png' pl.onload = () => { ctx.drawImage(pl, 318, 222, 22, 22) ctx.fillText(video.commentAmount, 340, 238) setTimeout(() => { wx.canvasToTempFilePath({ canvas: canvas, success(res) { resolve({ title: '请欣赏我的课文朗读作品,点赞+评论。', path: `/pages/index/index?readId=${video.id}&uid=${wx.getStorageSync('uid')}`, imageUrl: res.tempFilePath }) }, fail(res) { reject() } }, this) }, 500) } } } } } }) }) }, /** * 用户点击右上角分享 */ onShareAppMessage({ from, target }) { if (from == 'button') { let video = target.dataset.info const promise = new Promise(resolve => { this.creatShare(video).then(res => { resolve(res) }) }) console.log(video); return { title: '请欣赏我的课文朗读作品,点赞+评论。', path: `/pages/index/index?readId=${video.id}&uid=${wx.getStorageSync('uid')}`, imageUrl: video.coverImg, promise } } else { return { title: '课文朗读,从未如此有趣。', path: `/pages/index/index?&uid=${wx.getStorageSync('uid')}`, imageUrl: 'http://reader-wx.ai160.com/images/reader/v3/shareContent.png' } } }, touchMove: function() { return }, openShare: function(e) { console.log('用户点击分享按钮回调', e) this.setData({ shareTitle: e.detail.currentTarget.dataset.title, shareId: e.detail.currentTarget.dataset.id, shareImg: e.detail.currentTarget.dataset.shareimg, ifTapActivity: e.detail.currentTarget.dataset.activity }) }, onPlay: function(e) { // 下边视频列表onplay console.log('视频播放视频播放') if (this.videoCtx) { this.videoCtx.stop(); } else { this.videoCtx = wx.createVideoContext('myVideo', this); this.videoCtx.stop(); } }, collectTap: function(e) { const index = e.detail.index; let str = `videoList[${index}].isFavorite`; let str2 = `videoList[${index}].favoritesAmount`; let favoritesAmount = e.detail.isCollect ? this.data.videoList[index].favoritesAmount + 1 : this.data.videoList[index].favoritesAmount - 1 this.setData({ [str]: e.detail.isCollect, [str2]: favoritesAmount }) }, likeTap: function(e) { console.log('点赞', e) const index = e.detail.index; let likeStr = `videoList[${index}].isLike`; let likeNumStr = `videoList[${index}].likes`; this.setData({ [likeStr]: true, [likeNumStr]: this.data.videoList[index].likes + 1 }) }, // 获取焦点事件 inputFocus(e) { this.setData({ isScroll: false }) this.triggerEvent('inputFocus'); }, // 失去焦点事件 inputBlur(e) { this.setData({ isScroll: true }) this.triggerEvent('inputBlur'); }, addShareAmount: function(e) { console.log('+++++1', e) let str = `videoList[${e.detail.index}].shareAmount`; this.setData({ [str]: this.data.videoList[e.detail.index].shareAmount + 1 }) }, // 去鉴权 goToAuth() { if (!wx.getStorageSync('message')) { wx.requestSubscribeMessage({ tmplIds: ['KJ0YtcAacJNSXDBsE27JXqoaFrcJ1-N6Jcu85yTtQuY', '-2ZZpWFoyKvAtX1HwEIQLQ92LnN8cryamB94LqLGo98' ], success: (res) => { console.log(res) if (res['KJ0YtcAacJNSXDBsE27JXqoaFrcJ1-N6Jcu85yTtQuY'] === 'reject') { console.log('用户不同意订阅') wx.setStorageSync('message', false) } else if (res['KJ0YtcAacJNSXDBsE27JXqoaFrcJ1-N6Jcu85yTtQuY'] === 'accept') { console.log('订阅成功') wx.setStorageSync('message', true) } this.userAuth() }, fail: () => { this.userAuth() } }) } else { this.userAuth() } }, userAuth() { if (this.data.isIOS) { wx.navigateTo({ url: `../vipActivity/vipActivity` }); } else { const productId = wx.getStorageSync('productId'); httpRequestApi.createOrder(productId).success(res => { console.log(res.data.data.package); const timeStamp = res.data.data.timeStamp; const nonceStr = res.data.data.nonceStr; const packages = res.data.data.package; const paySign = res.data.data.sign; wx.requestPayment({ timeStamp, nonceStr, package: packages, signType: 'MD5', paySign, success: (res) => { this.setData({ authHide: !this.data.authHide }) httpRequestApi.getAuthActivity().success(res => { if (!res.data.data) { wx.setStorageSync('vip', false) wx.setStorageSync('date', '') } else { wx.setStorageSync('vip', true) wx.setStorageSync('date', res.data.data) } }).fail(error => { console.log(error) }) }, fail(res) {} }) }) } this.hideAuth(); }, hideAuth() { this.setData({ authHide: !this.data.authHide }) }, onShareTimeline: function() { return { title: '终于找到适合孩子的朗读神器了!动画配音,边玩边学!', query: `uid=${wx.getStorageSync('uid')}`, imageUrl: 'http://reader-wx.ai160.com/images/reader/v3/yuwen.jpg' } }, })