Compare commits
11 Commits
Author | SHA1 | Date |
---|---|---|
jia | 7165b72777 | |
jia | 15b4ef5766 | |
jia | 1fefd30512 | |
jia | f5a7cf2791 | |
weipengfei | 2469fdf3fd | |
weipengfei | 10906ebbc2 | |
weipengfei | 21fdf942a7 | |
weipengfei | fdaa22276b | |
weipengfei | ebed1f6087 | |
weipengfei | d5d5500290 | |
weipengfei | 43c75b62fd |
|
@ -0,0 +1,92 @@
|
||||||
|
<template>
|
||||||
|
<view class="contentgb">
|
||||||
|
<view class="return_top">
|
||||||
|
<view class="z-bootm-img1" @click="returnbom()">
|
||||||
|
<image src="@/static/icon/fb1.png" mode="aspectFit"></image>
|
||||||
|
</view>
|
||||||
|
<view class="z-bootm-l"></view>
|
||||||
|
<view class="z-bootm-img2" @click="returnbom()">
|
||||||
|
<image src="@/static/icon/fb2.png" mode="aspectFit"></image>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
returnbom() {
|
||||||
|
uni.sendHostEvent('closeApp', (ret) => {
|
||||||
|
//发送消息成功回调
|
||||||
|
console.log('关闭应用' + JSON.stringify(ret));
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.contentgb {
|
||||||
|
|
||||||
|
width: 166rpx;
|
||||||
|
height: 56rpx;
|
||||||
|
|
||||||
|
.return_top {
|
||||||
|
width: 166rpx;
|
||||||
|
height: 56rpx;
|
||||||
|
background: rgba(255, 255, 255, 0.6);
|
||||||
|
border-radius: 44rpx 44rpx;
|
||||||
|
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
.z-bootm-img1 {
|
||||||
|
width: 41rpx;
|
||||||
|
height: 13rpx;
|
||||||
|
|
||||||
|
position: absolute;
|
||||||
|
top: 20rpx;
|
||||||
|
left: 25rpx;
|
||||||
|
|
||||||
|
image {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.z-bootm-l {
|
||||||
|
width: 1px;
|
||||||
|
height: 32rpx;
|
||||||
|
background: rgba(0, 0, 0, 0.2);
|
||||||
|
margin: auto 0;
|
||||||
|
|
||||||
|
position: absolute;
|
||||||
|
top: 10rpx;
|
||||||
|
left: 85rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.z-bootm-img2 {
|
||||||
|
width: 38rpx;
|
||||||
|
height: 34rpx;
|
||||||
|
margin-top: -15rpx;
|
||||||
|
margin-left: -15rpx;
|
||||||
|
position: absolute;
|
||||||
|
right: 25rpx;
|
||||||
|
top: 25rpx;
|
||||||
|
|
||||||
|
image {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name" : "农业咨询",
|
"name" : "养殖分析",
|
||||||
"appid" : "__UNI__9620511",
|
"appid" : "__UNI__EEA7DC9",
|
||||||
"description" : "",
|
"description" : "",
|
||||||
"versionName" : "1.0.0",
|
"versionName" : "1.0.0",
|
||||||
"versionCode" : "100",
|
"versionCode" : "100",
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
{
|
{
|
||||||
"path": "pages/index/index",
|
"path": "pages/index/index",
|
||||||
"style": {
|
"style": {
|
||||||
"navigationBarTitleText": "农业咨询",
|
"navigationBarTitleText": "种植分析",
|
||||||
"navigationStyle": "custom",
|
"navigationStyle": "custom",
|
||||||
"bounce": "none"
|
"bounce": "none"
|
||||||
// "softinputMode": "adjustResize"
|
// "softinputMode": "adjustResize"
|
||||||
|
|
|
@ -5,9 +5,10 @@
|
||||||
<view class="conten-top">
|
<view class="conten-top">
|
||||||
<view class="" style="position: absolute;left: 30rpx;"><i class="iconfont icon-xiangzuo"
|
<view class="" style="position: absolute;left: 30rpx;"><i class="iconfont icon-xiangzuo"
|
||||||
style="font-size: 40rpx;text-align: left;"></i></view>
|
style="font-size: 40rpx;text-align: left;"></i></view>
|
||||||
<view class="" style="font-size: 30rpx;">
|
<view class="" style="font-size: 30rpx;margin-top: 10rpx;">
|
||||||
农业咨询
|
养殖咨询
|
||||||
</view>
|
</view>
|
||||||
|
<returntop class="container-retun"/>
|
||||||
</view>
|
</view>
|
||||||
<view style="padding-top:var(--status-bar-height);padding-bottom: 30rpx; margin-bottom: 30rpx;"></view>
|
<view style="padding-top:var(--status-bar-height);padding-bottom: 30rpx; margin-bottom: 30rpx;"></view>
|
||||||
|
|
||||||
|
@ -22,21 +23,22 @@
|
||||||
您好!
|
您好!
|
||||||
</view>
|
</view>
|
||||||
<view class="talk-list-con-title1">
|
<view class="talk-list-con-title1">
|
||||||
您可以和我说任何有关农业的问题。<br />
|
您可以和我说任何有关养殖的问题。<br />
|
||||||
例如下面的问题,赶快试试吧!
|
例如下面的问题,赶快试试吧!
|
||||||
</view>
|
</view>
|
||||||
<view class="talk-list-con-title2">
|
<view class="talk-list-con-title2">
|
||||||
<text style="margin-top: 15rpx;"> 下方输入:</text>
|
<text style="margin-top: 15rpx;"> 下方输入:</text>
|
||||||
<view class="" @click="sendDetail('冬季怎么保存蔬菜')">
|
<view class="" @click="sendDetail('怎么养猪')">
|
||||||
冬季怎么保存蔬菜
|
怎么养猪
|
||||||
<image src="../../static/icon/airight.png" mode=""></image>
|
<image src="../../static/icon/airight.png" mode=""></image>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
|
|
||||||
</view>
|
</view>
|
||||||
<view v-for="(item,index) in talkList" :key="index" :id="`msg-${item.id}`">
|
<view v-for="(item,index) in talkList" :key="index" :id="`msg-${item.id}`">
|
||||||
<view class="item flex_col" :class="item.type == 1 ? 'push':'pull' ">
|
<view class="item flex_col" :class="item.type == 1 ? 'push':'pull' ">
|
||||||
|
|
||||||
<image :src="item.type==1?avatar:item.pic" mode="aspectFill" class="pic" v-if="item.pic">
|
<image :src="item.type==1?avatar:item.pic" mode="aspectFill" class="pic" v-if="item.pic">
|
||||||
</image>
|
</image>
|
||||||
<view class="content" v-if="item.id=='@'">
|
<view class="content" v-if="item.id=='@'">
|
||||||
|
@ -49,9 +51,11 @@
|
||||||
<view class="" v-else>
|
<view class="" v-else>
|
||||||
<view v-if="talkList.length-1==index" class="multiline-text">
|
<view v-if="talkList.length-1==index" class="multiline-text">
|
||||||
<view class="content">
|
<view class="content">
|
||||||
<view class="" v-if="item.type==3" style="border: 1px solid #2573fb;margin-left: 20rpx;">
|
<view class="" v-if="item.type==3"
|
||||||
<image :src="item.Image" mode="" style="width: 200rpx;height: 200rpx;" @click="previewImage(item.Image)"></image>
|
style="border: 1px solid #2573fb;margin-left: 20rpx;">
|
||||||
<view class="">{{c_content}}</view>
|
<image :src="item.Image" mode="" style="width: 200rpx;height: 200rpx;"
|
||||||
|
@click="previewImage(item.Image)"></image>
|
||||||
|
<view class="">{{c_content}}</view>
|
||||||
</view>
|
</view>
|
||||||
<view class="" v-else>
|
<view class="" v-else>
|
||||||
<bing-math v-if="c_content!=''" :key="`math-${item.id}`" class="bing-math1"
|
<bing-math v-if="c_content!=''" :key="`math-${item.id}`" class="bing-math1"
|
||||||
|
@ -89,8 +93,10 @@
|
||||||
|
|
||||||
|
|
||||||
<!-- <rich-text :nodes="item.content"></rich-text> -->
|
<!-- <rich-text :nodes="item.content"></rich-text> -->
|
||||||
<view class="" v-if="item.type==3" style="border: 1px solid #2573fb;margin-left: 20rpx;">
|
<view class="" v-if="item.type==3"
|
||||||
<image :src="item.Image" mode="" style="width: 200rpx;height: 200rpx;" @click="previewImage(item.Image)"></image>
|
style="border: 1px solid #2573fb;margin-left: 20rpx;">
|
||||||
|
<image :src="item.Image" mode="" style="width: 200rpx;height: 200rpx;"
|
||||||
|
@click="previewImage(item.Image)"></image>
|
||||||
</view>
|
</view>
|
||||||
<view class="" v-else>
|
<view class="" v-else>
|
||||||
<view class="content multiline-text">
|
<view class="content multiline-text">
|
||||||
|
@ -246,7 +252,7 @@
|
||||||
import BingMath from "@/components/bing-math/bing-math.vue"
|
import BingMath from "@/components/bing-math/bing-math.vue"
|
||||||
import qiqbshare from "@/components/qiqb-share/qiqb-share.vue"
|
import qiqbshare from "@/components/qiqb-share/qiqb-share.vue"
|
||||||
|
|
||||||
|
import returntop from '@/components/content-top/index.vue'
|
||||||
const recorderManager = uni.getRecorderManager()
|
const recorderManager = uni.getRecorderManager()
|
||||||
const innerAudioContext = uni.createInnerAudioContext()
|
const innerAudioContext = uni.createInnerAudioContext()
|
||||||
export default {
|
export default {
|
||||||
|
@ -254,12 +260,12 @@
|
||||||
'bing-math': BingMath,
|
'bing-math': BingMath,
|
||||||
'qiqbshare': qiqbshare,
|
'qiqbshare': qiqbshare,
|
||||||
|
|
||||||
|
returntop
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
wssType: 'nongye', // 网络连接类型
|
wssType: 'yangzhi', // 网络连接类型
|
||||||
avatarType: "/static/icon/ny.png", // AI头像类型
|
avatarType: "/static/icon/yz.png", // AI头像类型
|
||||||
talkList: [],
|
talkList: [],
|
||||||
ajax: {
|
ajax: {
|
||||||
rows: 15, //每页数量
|
rows: 15, //每页数量
|
||||||
|
@ -317,7 +323,7 @@
|
||||||
Imageurl: '',
|
Imageurl: '',
|
||||||
content1: '',
|
content1: '',
|
||||||
audioContext: null, // 存储当前的innerAudioContext实例
|
audioContext: null, // 存储当前的innerAudioContext实例
|
||||||
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
|
@ -341,7 +347,7 @@
|
||||||
|
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
onLoad() {
|
onLoad() {
|
||||||
let avatar = uni.getStorageSync('avatar');
|
let avatar = uni.getStorageSync('avatar');
|
||||||
avatar ? this.avatar = avatar : null;
|
avatar ? this.avatar = avatar : null;
|
||||||
|
@ -369,7 +375,7 @@
|
||||||
// obeyMuteSwitch: false
|
// obeyMuteSwitch: false
|
||||||
// })
|
// })
|
||||||
let that = this;
|
let that = this;
|
||||||
|
|
||||||
recorderManager.onStop(function(res) {
|
recorderManager.onStop(function(res) {
|
||||||
// 解决第一次录音,挂实例挂载问题
|
// 解决第一次录音,挂实例挂载问题
|
||||||
that.$nextTick(() => {
|
that.$nextTick(() => {
|
||||||
|
@ -378,7 +384,7 @@
|
||||||
that.voicePath = res.tempFilePath;
|
that.voicePath = res.tempFilePath;
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
watch: {
|
watch: {
|
||||||
|
@ -475,7 +481,7 @@
|
||||||
sourceType: ['album'], //这要注意,camera掉拍照,album是打开手机相册
|
sourceType: ['album'], //这要注意,camera掉拍照,album是打开手机相册
|
||||||
success: (res) => {
|
success: (res) => {
|
||||||
// const tempFilePaths = res.tempFilePaths;
|
// const tempFilePaths = res.tempFilePaths;
|
||||||
console.log(res.tempFilePaths,'2222222222')
|
console.log(res.tempFilePaths, '2222222222')
|
||||||
uni.uploadFile({
|
uni.uploadFile({
|
||||||
url: HTTP_REQUEST_URL + '/api/upload/image', // 上传地址
|
url: HTTP_REQUEST_URL + '/api/upload/image', // 上传地址
|
||||||
filePath: res.tempFilePaths[0], // 要上传的文件路径
|
filePath: res.tempFilePaths[0], // 要上传的文件路径
|
||||||
|
@ -486,7 +492,7 @@
|
||||||
success: function(res) {
|
success: function(res) {
|
||||||
|
|
||||||
let data = JSON.parse(res.data)
|
let data = JSON.parse(res.data)
|
||||||
console.log(data,'222222222222')
|
console.log(data, '222222222222')
|
||||||
if (data.code == 1) {
|
if (data.code == 1) {
|
||||||
// this.File()
|
// this.File()
|
||||||
let data1 = {
|
let data1 = {
|
||||||
|
@ -584,24 +590,24 @@
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
//图片预览
|
//图片预览
|
||||||
previewImage(url){
|
previewImage(url) {
|
||||||
uni.previewImage({
|
uni.previewImage({
|
||||||
urls: [url], // 图片地址数组
|
urls: [url], // 图片地址数组
|
||||||
current: url, // 当前预览的图片地址
|
current: url, // 当前预览的图片地址
|
||||||
success: function() {
|
success: function() {
|
||||||
console.log('预览图片成功');
|
console.log('预览图片成功');
|
||||||
},
|
},
|
||||||
fail: function(error) {
|
fail: function(error) {
|
||||||
console.error('预览图片失败', error);
|
console.error('预览图片失败', error);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
//图片转文字
|
//图片转文字
|
||||||
imgfile(tempFilePath) {
|
imgfile(tempFilePath) {
|
||||||
let that = this
|
let that = this
|
||||||
that.content1=''
|
that.content1 = ''
|
||||||
// console.log(tempFilePath, '2')
|
// console.log(tempFilePath, '2')
|
||||||
ttocr({
|
ttocr({
|
||||||
image: tempFilePath
|
image: tempFilePath
|
||||||
|
@ -615,7 +621,7 @@
|
||||||
that.gnishow = false
|
that.gnishow = false
|
||||||
|
|
||||||
that.talkList = that.talkList.filter(item => item.id !== '@');
|
that.talkList = that.talkList.filter(item => item.id !== '@');
|
||||||
|
|
||||||
if (res.data.words.length > 0) {
|
if (res.data.words.length > 0) {
|
||||||
|
|
||||||
for (let i in res.data.words) {
|
for (let i in res.data.words) {
|
||||||
|
@ -732,7 +738,7 @@
|
||||||
},
|
},
|
||||||
//语音转文字
|
//语音转文字
|
||||||
uploadFile(tempFilePath) {
|
uploadFile(tempFilePath) {
|
||||||
|
|
||||||
let that = this
|
let that = this
|
||||||
// console.log(tempFilePath)
|
// console.log(tempFilePath)
|
||||||
uni.uploadFile({
|
uni.uploadFile({
|
||||||
|
@ -743,14 +749,14 @@
|
||||||
'content-type': 'multipart/form-data'
|
'content-type': 'multipart/form-data'
|
||||||
},
|
},
|
||||||
success: function(res) {
|
success: function(res) {
|
||||||
|
|
||||||
|
|
||||||
let data = JSON.parse(res.data)
|
let data = JSON.parse(res.data)
|
||||||
if (data.code == 1) {
|
if (data.code == 1) {
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: '语音识别成功'
|
title: '语音识别成功'
|
||||||
});
|
});
|
||||||
|
|
||||||
that.talkList = that.talkList.filter(item => item.id !== '@');
|
that.talkList = that.talkList.filter(item => item.id !== '@');
|
||||||
if (data.data.words.length > 0) {
|
if (data.data.words.length > 0) {
|
||||||
that.content = data.data.words
|
that.content = data.data.words
|
||||||
|
@ -762,16 +768,16 @@
|
||||||
title: '语音识别失败'
|
title: '语音识别失败'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
},
|
},
|
||||||
fail: function(error) {
|
fail: function(error) {
|
||||||
// 上传失败处理逻辑
|
// 上传失败处理逻辑
|
||||||
that.deletespeech()
|
that.deletespeech()
|
||||||
console.log(error, 11);
|
console.log(error, 11);
|
||||||
uni.hideLoading();
|
uni.hideLoading();
|
||||||
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
@ -810,32 +816,32 @@
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
start(e) {
|
start(e) {
|
||||||
|
|
||||||
this.onFeedTap()
|
this.onFeedTap()
|
||||||
this.touchT = new Date().getTime();
|
this.touchT = new Date().getTime();
|
||||||
this.islong = true
|
this.islong = true
|
||||||
this.risshow = false
|
this.risshow = false
|
||||||
this.$refs.popup.open('center')
|
this.$refs.popup.open('center')
|
||||||
// 限制时长
|
// 限制时长
|
||||||
this.timer = setInterval(() => {
|
this.timer = setInterval(() => {
|
||||||
this.num++
|
this.num++
|
||||||
}, 1000)
|
}, 1000)
|
||||||
this.btnStatus = 1
|
this.btnStatus = 1
|
||||||
recorderManager.start({
|
recorderManager.start({
|
||||||
//时长5分钟,单位毫秒
|
//时长5分钟,单位毫秒
|
||||||
duration: 300000,
|
duration: 300000,
|
||||||
|
|
||||||
// format: "pcm",
|
// format: "pcm",
|
||||||
});
|
});
|
||||||
|
|
||||||
this.touchStartX = e.touches[0].pageX; // 获取触摸时的原点
|
this.touchStartX = e.touches[0].pageX; // 获取触摸时的原点
|
||||||
this.touchStartY = e.touches[0].pageY; // 获取触摸时的原点
|
this.touchStartY = e.touches[0].pageY; // 获取触摸时的原点
|
||||||
|
|
||||||
},
|
},
|
||||||
move(e) {
|
move(e) {
|
||||||
|
|
||||||
let that = this;
|
let that = this;
|
||||||
let moveX = this.touchMoveX - e.touches[0].pageX;
|
let moveX = this.touchMoveX - e.touches[0].pageX;
|
||||||
let moveY = this.touchMoveY - e.touches[0].pageY;
|
let moveY = this.touchMoveY - e.touches[0].pageY;
|
||||||
|
@ -866,15 +872,15 @@
|
||||||
|
|
||||||
|
|
||||||
this.touchE = new Date().getTime();
|
this.touchE = new Date().getTime();
|
||||||
|
|
||||||
if (this.islong) {
|
if (this.islong) {
|
||||||
this.closePop()
|
this.closePop()
|
||||||
|
|
||||||
this.islong = false
|
this.islong = false
|
||||||
clearInterval(this.timer)
|
clearInterval(this.timer)
|
||||||
this.btnStatus = 0
|
this.btnStatus = 0
|
||||||
recorderManager.stop();
|
recorderManager.stop();
|
||||||
|
|
||||||
// this.closePop()
|
// this.closePop()
|
||||||
if (this.risshow == false && this.touchE - this.touchT > 3000) {
|
if (this.risshow == false && this.touchE - this.touchT > 3000) {
|
||||||
let data = {
|
let data = {
|
||||||
|
@ -883,7 +889,7 @@
|
||||||
"type": 2,
|
"type": 2,
|
||||||
}
|
}
|
||||||
this.talkList.push(data);
|
this.talkList.push(data);
|
||||||
|
|
||||||
// 异步,解决录音结束后,路径没赋值就传值,导致的路径为空
|
// 异步,解决录音结束后,路径没赋值就传值,导致的路径为空
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
let obj = {
|
let obj = {
|
||||||
|
@ -894,31 +900,31 @@
|
||||||
soundTime: this.num
|
soundTime: this.num
|
||||||
}]
|
}]
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.voicePath.length > 0 && this.risshow == false) {
|
if (this.voicePath.length > 0 && this.risshow == false) {
|
||||||
// this.huashow=true
|
// this.huashow=true
|
||||||
this.TabItemTap()
|
this.TabItemTap()
|
||||||
|
|
||||||
|
|
||||||
throttle(this.uploadFile(this.voicePath), 1000)
|
throttle(this.uploadFile(this.voicePath), 1000)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.num = 0
|
this.num = 0
|
||||||
}, 500)
|
}, 500)
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
if (!this.risshow) {
|
if (!this.risshow) {
|
||||||
uni.showModal({
|
uni.showModal({
|
||||||
title: "录音时长不超过3s"
|
title: "录音时长不超过3s"
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
},
|
},
|
||||||
|
@ -992,18 +998,18 @@
|
||||||
//音频播放
|
//音频播放
|
||||||
|
|
||||||
palyaudio(items, i) {
|
palyaudio(items, i) {
|
||||||
|
|
||||||
// console.log(this.talkList,items.audio_file,'000000')
|
// console.log(this.talkList,items.audio_file,'000000')
|
||||||
if (this.audioContext) {
|
if (this.audioContext) {
|
||||||
// 停止上一段对话内容的播放
|
// 停止上一段对话内容的播放
|
||||||
this.audioContext.stop();
|
this.audioContext.stop();
|
||||||
this.audioContext = null;
|
this.audioContext = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.talkList.forEach((item, index) => {
|
this.talkList.forEach((item, index) => {
|
||||||
if (index != i) {
|
if (index != i) {
|
||||||
item.playStatus = true
|
item.playStatus = true
|
||||||
|
|
||||||
}
|
}
|
||||||
// item.playStatus = (index == i);
|
// item.playStatus = (index == i);
|
||||||
});
|
});
|
||||||
|
@ -1012,15 +1018,15 @@
|
||||||
this.talkList[i].playStatus = !this.talkList[i].playStatus
|
this.talkList[i].playStatus = !this.talkList[i].playStatus
|
||||||
|
|
||||||
if (!this.talkList[i].playStatus) {
|
if (!this.talkList[i].playStatus) {
|
||||||
|
|
||||||
if(items.audio_file.length>0){
|
if (items.audio_file.length > 0) {
|
||||||
innerAudioContext.src = items.audio_file;
|
innerAudioContext.src = items.audio_file;
|
||||||
innerAudioContext.play()
|
innerAudioContext.play()
|
||||||
this.talkList[i].playStatus = false
|
this.talkList[i].playStatus = false
|
||||||
}else{
|
} else {
|
||||||
this.talkList[i].playStatus = true
|
this.talkList[i].playStatus = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
innerAudioContext.pause()
|
innerAudioContext.pause()
|
||||||
|
@ -1180,28 +1186,28 @@
|
||||||
},
|
},
|
||||||
// 关闭连接
|
// 关闭连接
|
||||||
closeSocketTask() {
|
closeSocketTask() {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
this.talkList = this.talkList.filter(item => item.id !== '@');
|
this.talkList = this.talkList.filter(item => item.id !== '@');
|
||||||
clearInterval(this.timer);
|
clearInterval(this.timer);
|
||||||
this.talkList[this.talkList.length - 1].audio_file=''
|
this.talkList[this.talkList.length - 1].audio_file = ''
|
||||||
this.talkList[this.talkList.length - 1].content = this.c_content + '';
|
this.talkList[this.talkList.length - 1].content = this.c_content + '';
|
||||||
// console.log(this.talkList[this.talkList.length - 1].content);
|
// console.log(this.talkList[this.talkList.length - 1].content);
|
||||||
// this.c_content = '';
|
// this.c_content = '';
|
||||||
// this.n_content = '';
|
// this.n_content = '';
|
||||||
this.socketTask.close({
|
this.socketTask.close({
|
||||||
code: 500, // APP端存在BUG,正常关闭的code为1000,无法正常关闭,需要将code换为其他值
|
code: 500, // APP端存在BUG,正常关闭的code为1000,无法正常关闭,需要将code换为其他值
|
||||||
complete: (res) => {
|
complete: (res) => {
|
||||||
this.showStop = false;
|
this.showStop = false;
|
||||||
console.log('主动断开', res);
|
console.log('主动断开', res);
|
||||||
this.wsLiveFlag = false;
|
this.wsLiveFlag = false;
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
//TODO handle the exception
|
//TODO handle the exception
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
// 发送信息
|
// 发送信息
|
||||||
|
@ -1213,8 +1219,8 @@
|
||||||
})
|
})
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// 将当前发送信息 添加到消息列表。
|
// 将当前发送信息 添加到消息列表。
|
||||||
let data = {
|
let data = {
|
||||||
"id": new Date().getTime(),
|
"id": new Date().getTime(),
|
||||||
|
@ -1250,7 +1256,7 @@
|
||||||
|
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
send1() {
|
send1() {
|
||||||
if (!this.content1) {
|
if (!this.content1) {
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
|
@ -1335,7 +1341,7 @@
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
// };
|
// };
|
||||||
|
|
||||||
if (this.historyTextList.length > 9) this.params = JSON.parse(JSON.stringify(this
|
if (this.historyTextList.length > 9) this.params = JSON.parse(JSON.stringify(this
|
||||||
.historyTextList
|
.historyTextList
|
||||||
.splice(-9)));
|
.splice(-9)));
|
||||||
|
@ -1363,11 +1369,11 @@
|
||||||
realThis.tempRes = realThis.tempRes + dataArray[i].content
|
realThis.tempRes = realThis.tempRes + dataArray[i].content
|
||||||
|
|
||||||
}
|
}
|
||||||
if(this.n_content.length>0){
|
if (this.n_content.length > 0) {
|
||||||
this.nums = this.talkList.length - 1
|
this.nums = this.talkList.length - 1
|
||||||
this.txtspeech(this.n_content, this.talkList.length -
|
this.txtspeech(this.n_content, this.talkList.length -
|
||||||
1)
|
1)
|
||||||
this.showStop = true;
|
this.showStop = true;
|
||||||
}
|
}
|
||||||
this.cavshare(this.talkList)
|
this.cavshare(this.talkList)
|
||||||
let temp = JSON.parse(res.data)
|
let temp = JSON.parse(res.data)
|
||||||
|
@ -1392,7 +1398,7 @@
|
||||||
"role": "assistant",
|
"role": "assistant",
|
||||||
"content": this.tempRes
|
"content": this.tempRes
|
||||||
})
|
})
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
let that = this
|
let that = this
|
||||||
realThis.socketTask.close({
|
realThis.socketTask.close({
|
||||||
|
@ -1601,7 +1607,15 @@
|
||||||
top: 0;
|
top: 0;
|
||||||
position: fixed;
|
position: fixed;
|
||||||
z-index: 10;
|
z-index: 10;
|
||||||
|
.container-retun{
|
||||||
|
position: absolute;
|
||||||
|
right: 20rpx;
|
||||||
|
padding-top: var(--status-bar-height);
|
||||||
|
top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.popup_box {
|
.popup_box {
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,168 +0,0 @@
|
||||||
.h1 {
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
body{
|
|
||||||
background-color: transparent !important;
|
|
||||||
}
|
|
||||||
.voice-box {
|
|
||||||
box-sizing : border-box;
|
|
||||||
display : flex;
|
|
||||||
justify-content: center;
|
|
||||||
margin : 50px auto;
|
|
||||||
padding : 50px;
|
|
||||||
width : 60%;
|
|
||||||
|
|
||||||
border-radius : 3px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.voice-box input {
|
|
||||||
box-sizing : border-box;
|
|
||||||
padding : 10px;
|
|
||||||
width : 70%;
|
|
||||||
height : 50px;
|
|
||||||
font-size : 18px;
|
|
||||||
color : #187cff;
|
|
||||||
border : 1px solid #187cff;
|
|
||||||
border-radius: 3px 0px 0px 3px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.voice-box button {
|
|
||||||
width : 30%;
|
|
||||||
height : 50px;
|
|
||||||
line-height : 50px;
|
|
||||||
font-size : 18px;
|
|
||||||
color : white;
|
|
||||||
background : #187cff;
|
|
||||||
border : none;
|
|
||||||
border-radius: 0px 3px 3px 0px;
|
|
||||||
cursor : pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.voice-box button::before {
|
|
||||||
content : "";
|
|
||||||
display : inline-block;
|
|
||||||
width : 23px;
|
|
||||||
height : 26px;
|
|
||||||
vertical-align : middle;
|
|
||||||
background : url(../img/voice.png) no-repeat;
|
|
||||||
background-size: contain;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
.fixed-box {
|
|
||||||
box-sizing: border-box;
|
|
||||||
display : none;
|
|
||||||
position : fixed;
|
|
||||||
top : 0px;
|
|
||||||
right : 0px;
|
|
||||||
bottom : 0px;
|
|
||||||
left : 0px;
|
|
||||||
border : .04rem solid #e0e7ff;
|
|
||||||
background: rgba(16, 22, 62, .2);
|
|
||||||
}
|
|
||||||
|
|
||||||
.fixed-close {
|
|
||||||
position : absolute;
|
|
||||||
top : 0px;
|
|
||||||
right : 0px;
|
|
||||||
padding : 24px;
|
|
||||||
width : 20px;
|
|
||||||
height : 20px;
|
|
||||||
border : none;
|
|
||||||
background : url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAeCAYAAAA7MK6iAAABeklEQVRIibXWsWoVQRQA0LObgGCTFFr6env9h/yETSz0tclrBEUJWhjzAqkV/A9/QrC2CtgIYqk2DwvdMExm991ZJrdaZoY53Bnm3u0Wy80BPuI21jjRPjqc4il+4FG3WG4ucS9ZtMaqMfoej5OxLz3uZAuPcXaDKNzt/TuCPFrgYyi87fEK543xKfQFLvoEaYVvQ19DnwxO4euWaA5P4UcBPIzCbmHRcYLleDqfox9wGEG5nnGKRzOvRilnnOIDluPD/BT6HG/GNp+CI/j+HDQCR/BqlPE7LuGlO5+F1sARPIzWwh32Jub3K/YKw1PFYYgV3rWEI2iKh2r7NnhbGZzdWKaeU03tzZ/W8ARH/2TGMq5BZ7XUElzVZebiOTzU3ho0RUqts4in8Kwuk8Uqig/wti4TQSP41XgfQMNlMIBf9fPd/x8t0RTn+h/LEX52i+XmN241RtM4K+Dfe3y7QZTysV/u7D18+RkP8AfPxPpubXzCL9zHVzz5C8ecbD1n3xuUAAAAAElFTkSuQmCC) no-repeat center center;
|
|
||||||
background-size: 20px;
|
|
||||||
transition : all .5s;
|
|
||||||
cursor : pointer;
|
|
||||||
outline : none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.fixed-close:hover {
|
|
||||||
transform : rotate(270deg);
|
|
||||||
-webkit-transform: rotate(270deg);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.fixed-main {
|
|
||||||
box-sizing : border-box;
|
|
||||||
position : absolute;
|
|
||||||
left : 20%;
|
|
||||||
bottom : 0px;
|
|
||||||
padding : 30px;
|
|
||||||
width : 60%;
|
|
||||||
height : 240px;
|
|
||||||
font-size : 18px;
|
|
||||||
background : white;
|
|
||||||
border : 2px solid #e0e7ff;
|
|
||||||
border-radius: 5px 5px 0px 0px;
|
|
||||||
overflow-y : auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.fixed-icon {
|
|
||||||
box-sizing : border-box;
|
|
||||||
display : flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items : center;
|
|
||||||
position : absolute;
|
|
||||||
top : 50%;
|
|
||||||
left : 50%;
|
|
||||||
margin-top : -50px;
|
|
||||||
margin-left : -50px;
|
|
||||||
width : 100px;
|
|
||||||
height : 100px;
|
|
||||||
background : linear-gradient(115deg, #56d8e4 5%, #9f01ea 95%);
|
|
||||||
border : 1px solid #e0e7ff;
|
|
||||||
border-radius : 50%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.fixed-icon::before {
|
|
||||||
content : "";
|
|
||||||
position : absolute;
|
|
||||||
display : inline-block;
|
|
||||||
width : 100px;
|
|
||||||
height : 100px;
|
|
||||||
border : 1px solid #9f01ea;
|
|
||||||
box-shadow : 0px 0px 6px 0px #9f01ea;
|
|
||||||
border-radius: 50%;
|
|
||||||
animation : move 1.5s infinite;
|
|
||||||
}
|
|
||||||
|
|
||||||
.fixed-icon::after {
|
|
||||||
content : "";
|
|
||||||
position : absolute;
|
|
||||||
display : inline-block;
|
|
||||||
width : 100px;
|
|
||||||
height : 100px;
|
|
||||||
border : 1px solid #56d8e4;
|
|
||||||
box-shadow : 0px 0px 6px 0px #56d8e4;
|
|
||||||
border-radius: 50%;
|
|
||||||
animation : move 1.5s .5s infinite;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
.fixed-icon img {
|
|
||||||
width : 30px;
|
|
||||||
height: 50px;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes move {
|
|
||||||
0% {
|
|
||||||
opacity : 1;
|
|
||||||
transform: scale(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
100% {
|
|
||||||
opacity : 0;
|
|
||||||
transform: scale(2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
::-webkit-scrollbar {
|
|
||||||
width : 6px;
|
|
||||||
height : 6px;
|
|
||||||
background-color: #f9f9f9;
|
|
||||||
}
|
|
||||||
|
|
||||||
::-webkit-scrollbar-thumb {
|
|
||||||
border-radius : 6px;
|
|
||||||
background-color: #187cff;
|
|
||||||
}
|
|
Binary file not shown.
Before Width: | Height: | Size: 1.2 MiB |
Binary file not shown.
Before Width: | Height: | Size: 85 KiB |
Binary file not shown.
Before Width: | Height: | Size: 2.0 KiB |
|
@ -1,107 +0,0 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8" />
|
|
||||||
<meta name="viewport"
|
|
||||||
content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum=1.0, user-scalable=no shrink-to-fit=no" />
|
|
||||||
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
|
|
||||||
<link rel="stylesheet" href="./css/base.css" />
|
|
||||||
<!-- <script async src="https://hm.baidu.com/hm.js?85fad12bb9a6dab448f4eff0a19299a5"></script> -->
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
|
|
||||||
|
|
||||||
<section class="voice-box">
|
|
||||||
<input type="search" name="voice" id="voice-txt" />
|
|
||||||
<button id="start-btn">开始识别</button>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section class="fixed-box" id="fixed-box">
|
|
||||||
<div class="fixed-main">
|
|
||||||
<button class="fixed-close" id="close-btn"></button>
|
|
||||||
<div id="fixed-txt">Hello! 请说出你想说话。。。!</div>
|
|
||||||
<div class="fixed-icon">
|
|
||||||
<img src="./img/voice.png" alt="" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
<script type="text/javascript" src="https://js.cdn.aliyun.dcloud.net.cn/dev/uni-app/uni.webview.1.5.2.js">
|
|
||||||
</script>
|
|
||||||
<script src="./js/crypto-js.min.js"></script>
|
|
||||||
<script src="./js/voice.js"></script>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
window.onload = function() {
|
|
||||||
const voiceTxt = document.querySelector('#voice-txt');
|
|
||||||
const startBtn = document.querySelector('#start-btn');
|
|
||||||
const fixedBox = document.querySelector('#fixed-box');
|
|
||||||
const fixedTxt = document.querySelector('#fixed-txt');
|
|
||||||
const closeBtn = document.querySelector('#close-btn');
|
|
||||||
let times = null;
|
|
||||||
|
|
||||||
|
|
||||||
// 实例化迅飞语音听写(流式版)WebAPI
|
|
||||||
const voice = new Voice({
|
|
||||||
|
|
||||||
// 服务接口认证信息 注:apiKey 和 apiSecret 的长度都差不多,请要填错哦,!
|
|
||||||
appId: '2eda6c2e',
|
|
||||||
apiSecret: 'MDEyMzE5YTc5YmQ5NjMwOTU1MWY4N2Y2',
|
|
||||||
apiKey: '12ec1f9d113932575fc4b114a2f60ffd',
|
|
||||||
// 注:要获取以上3个参数,请到迅飞开放平台:https://www.xfyun.cn/services/voicedictation 【注:这是我的迅飞语音听写(流式版)每天服务量500(也就是调500次),如果你需求里大请购买服务量:https://www.xfyun.cn/services/voicedictation?target=price】
|
|
||||||
|
|
||||||
onWillStatusChange: function(oldStatus, newStatus) {
|
|
||||||
//可以在这里进行页面中一些交互逻辑处理:注:倒计时(语音听写只有60s),录音的动画,按钮交互等!
|
|
||||||
fixedBox.style.display = 'block';
|
|
||||||
},
|
|
||||||
onTextChange: function(text) {
|
|
||||||
//监听识别结果的变化
|
|
||||||
voiceTxt.value = text;
|
|
||||||
fixedTxt.innerText = text;
|
|
||||||
console.log(text,'11111')
|
|
||||||
// 3秒钟内没有说话,就自动关闭
|
|
||||||
if (text) {
|
|
||||||
setTimeout(() => {
|
|
||||||
voice.stop();
|
|
||||||
uni.postMessage({
|
|
||||||
data: text
|
|
||||||
});
|
|
||||||
fixedBox.style.display = 'none';
|
|
||||||
}, 3000);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
addUniEvenPassthrough()
|
|
||||||
addcloEvenPassthrough()
|
|
||||||
|
|
||||||
function addUniEvenPassthrough() {
|
|
||||||
window.uniEvent = function(info) {
|
|
||||||
console.log('addUniEvenPassthrough')
|
|
||||||
voice.start();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function addcloEvenPassthrough() {
|
|
||||||
window.closeEvent = function(info) {
|
|
||||||
console.log('addcloEvenPassthrough')
|
|
||||||
voice.stop();
|
|
||||||
fixedBox.style.display = 'none';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 开始识别
|
|
||||||
startBtn['onclick'] = function() {
|
|
||||||
voice.start();
|
|
||||||
};
|
|
||||||
|
|
||||||
// 关闭识别
|
|
||||||
closeBtn['onclick'] = function() {
|
|
||||||
voice.stop();
|
|
||||||
fixedBox.style.display = 'none';
|
|
||||||
};
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
</body>
|
|
||||||
|
|
||||||
</html>
|
|
File diff suppressed because one or more lines are too long
|
@ -1,48 +0,0 @@
|
||||||
;(function () {
|
|
||||||
let self = this
|
|
||||||
self.onmessage = function (e) {
|
|
||||||
transAudioData.transcode(e.data)
|
|
||||||
}
|
|
||||||
|
|
||||||
let transAudioData = {
|
|
||||||
transcode(audioData) {
|
|
||||||
|
|
||||||
let output = transAudioData.to16kHz(audioData)
|
|
||||||
output = transAudioData.to16BitPCM(output)
|
|
||||||
output = Array.from(new Uint8Array(output.buffer))
|
|
||||||
self.postMessage(output)
|
|
||||||
// return output
|
|
||||||
},
|
|
||||||
|
|
||||||
to16kHz(audioData) {
|
|
||||||
var data = new Float32Array(audioData)
|
|
||||||
var fitCount = Math.round(data.length * (16000 / 44100))
|
|
||||||
var newData = new Float32Array(fitCount)
|
|
||||||
var springFactor = (data.length - 1) / (fitCount - 1)
|
|
||||||
newData[0] = data[0]
|
|
||||||
for (let i = 1; i < fitCount - 1; i++) {
|
|
||||||
var tmp = i * springFactor
|
|
||||||
var before = Math.floor(tmp).toFixed()
|
|
||||||
var after = Math.ceil(tmp).toFixed()
|
|
||||||
var atPoint = tmp - before
|
|
||||||
newData[i] = data[before] + (data[after] - data[before]) * atPoint
|
|
||||||
}
|
|
||||||
newData[fitCount - 1] = data[data.length - 1]
|
|
||||||
return newData
|
|
||||||
},
|
|
||||||
|
|
||||||
to16BitPCM(input) {
|
|
||||||
var dataLength = input.length * (16 / 8)
|
|
||||||
var dataBuffer = new ArrayBuffer(dataLength)
|
|
||||||
var dataView = new DataView(dataBuffer)
|
|
||||||
var offset = 0
|
|
||||||
for (var i = 0; i < input.length; i++, offset += 2) {
|
|
||||||
var s = Math.max(-1, Math.min(1, input[i]))
|
|
||||||
dataView.setInt16(offset, s < 0 ? s * 0x8000 : s * 0x7fff, true)
|
|
||||||
}
|
|
||||||
return dataView
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
})();
|
|
|
@ -1,357 +0,0 @@
|
||||||
; (function (window, voice) {
|
|
||||||
"use strict";
|
|
||||||
if (typeof define === 'function' && define.amd) {
|
|
||||||
define(voice);
|
|
||||||
} else if (typeof exports === 'object') {
|
|
||||||
module.exports = voice();
|
|
||||||
} else {
|
|
||||||
window.Voice = voice();
|
|
||||||
};
|
|
||||||
}(typeof window !== "undefined" ? window : this, () => {
|
|
||||||
"use strict";
|
|
||||||
return class IatRecorder {
|
|
||||||
constructor(opts = {}) {
|
|
||||||
// 服务接口认证信息(语音听写(流式版)WebAPI)
|
|
||||||
this.appId = opts.appId || '';
|
|
||||||
this.apiKey = opts.apiKey || '';
|
|
||||||
this.apiSecret = opts.apiSecret || '';
|
|
||||||
// 识别监听方法
|
|
||||||
this.onTextChange = opts.onTextChange || Function();
|
|
||||||
this.onWillStatusChange = opts.onWillStatusChange || Function();
|
|
||||||
// 方言/语种
|
|
||||||
this.status = 'null'
|
|
||||||
this.language = opts.language || 'zh_cn'
|
|
||||||
this.accent = opts.accent || 'mandarin';
|
|
||||||
// 流媒体
|
|
||||||
this.streamRef = [];
|
|
||||||
// 记录音频数据
|
|
||||||
this.audioData = [];
|
|
||||||
// 记录听写结果
|
|
||||||
this.resultText = '';
|
|
||||||
// wpgs下的听写结果需要中间状态辅助记录
|
|
||||||
this.resultTextTemp = '';
|
|
||||||
// 音频数据多线程
|
|
||||||
this.init();
|
|
||||||
};
|
|
||||||
// WebSocket请求地址鉴权
|
|
||||||
getWebSocketUrl() {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
// 请求地址根据语种不同变化
|
|
||||||
try {
|
|
||||||
const CryptoJS = require('crypto-js');
|
|
||||||
let url = 'wss://iat-api.xfyun.cn/v2/iat',
|
|
||||||
host = 'iat-api.xfyun.cn',
|
|
||||||
date = new Date().toGMTString(),
|
|
||||||
algorithm = 'hmac-sha256',
|
|
||||||
headers = 'host date request-line',
|
|
||||||
signatureOrigin = `host: ${host}\ndate: ${date}\nGET /v2/iat HTTP/1.1`,
|
|
||||||
signatureSha = CryptoJS.HmacSHA256(signatureOrigin, this.apiSecret),
|
|
||||||
signature = CryptoJS.enc.Base64.stringify(signatureSha),
|
|
||||||
authorizationOrigin = `api_key="${this.apiKey}", algorithm="${algorithm}", headers="${headers}", signature="${signature}"`,
|
|
||||||
authorization = btoa(authorizationOrigin);
|
|
||||||
resolve(`${url}?authorization=${authorization}&date=${date}&host=${host}`);
|
|
||||||
} catch (error) {
|
|
||||||
let url = 'wss://iat-api.xfyun.cn/v2/iat',
|
|
||||||
host = 'iat-api.xfyun.cn',
|
|
||||||
date = new Date().toGMTString(),
|
|
||||||
algorithm = 'hmac-sha256',
|
|
||||||
headers = 'host date request-line',
|
|
||||||
signatureOrigin = `host: ${host}\ndate: ${date}\nGET /v2/iat HTTP/1.1`,
|
|
||||||
signatureSha = CryptoJS.HmacSHA256(signatureOrigin, this.apiSecret),
|
|
||||||
signature = CryptoJS.enc.Base64.stringify(signatureSha),
|
|
||||||
authorizationOrigin = `api_key="${this.apiKey}", algorithm="${algorithm}", headers="${headers}", signature="${signature}"`,
|
|
||||||
authorization = btoa(authorizationOrigin);
|
|
||||||
resolve(`${url}?authorization=${authorization}&date=${date}&host=${host}`);
|
|
||||||
};
|
|
||||||
});
|
|
||||||
};
|
|
||||||
// 操作初始化
|
|
||||||
init() {
|
|
||||||
const self = this;
|
|
||||||
try {
|
|
||||||
if (!self.appId || !self.apiKey || !self.apiSecret) {
|
|
||||||
alert('请正确配置【迅飞语音听写(流式版)WebAPI】服务接口认证信息!');
|
|
||||||
} else {
|
|
||||||
self.webWorker = new Worker('./js/transcode.worker.js');
|
|
||||||
self.webWorker.onmessage = function (event) {
|
|
||||||
|
|
||||||
self.audioData.push(...event.data);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
alert('对不起:请在服务器环境下运行!');
|
|
||||||
console.error('请在服务器如:WAMP、XAMPP、Phpstudy、http-server、WebServer等环境中运行!', error);
|
|
||||||
};
|
|
||||||
console.log("%c ❤️使用说明:http://www.muguilin.com/blog/info/609bafc50d572b3fd79b058f", "font-size:32px; color:blue; font-weight: bold;");
|
|
||||||
};
|
|
||||||
// 修改录音听写状态
|
|
||||||
setStatus(status) {
|
|
||||||
this.onWillStatusChange && this.status !== status && this.onWillStatusChange(this.status, status);
|
|
||||||
this.status = status;
|
|
||||||
};
|
|
||||||
// 设置识别结果内容
|
|
||||||
setResultText({ resultText, resultTextTemp } = {}) {
|
|
||||||
this.onTextChange && this.onTextChange(resultTextTemp || resultText || '');
|
|
||||||
resultText !== undefined && (this.resultText = resultText);
|
|
||||||
resultTextTemp !== undefined && (this.resultTextTemp = resultTextTemp);
|
|
||||||
};
|
|
||||||
// 修改听写参数
|
|
||||||
setParams({ language, accent } = {}) {
|
|
||||||
language && (this.language = language)
|
|
||||||
accent && (this.accent = accent)
|
|
||||||
};
|
|
||||||
// 对处理后的音频数据进行base64编码,
|
|
||||||
toBase64(buffer) {
|
|
||||||
let binary = '';
|
|
||||||
let bytes = new Uint8Array(buffer);
|
|
||||||
for (let i = 0; i < bytes.byteLength; i++) {
|
|
||||||
binary += String.fromCharCode(bytes[i]);
|
|
||||||
}
|
|
||||||
return window.btoa(binary);
|
|
||||||
};
|
|
||||||
// 连接WebSocket
|
|
||||||
connectWebSocket() {
|
|
||||||
return this.getWebSocketUrl().then(url => {
|
|
||||||
let iatWS;
|
|
||||||
if ('WebSocket' in window) {
|
|
||||||
iatWS = new WebSocket(url);
|
|
||||||
} else if ('MozWebSocket' in window) {
|
|
||||||
iatWS = new MozWebSocket(url);
|
|
||||||
} else {
|
|
||||||
alert('浏览器不支持WebSocket!');
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
this.webSocket = iatWS;
|
|
||||||
this.setStatus('init');
|
|
||||||
iatWS.onopen = e => {
|
|
||||||
this.setStatus('ing');
|
|
||||||
console.log('连接成功')
|
|
||||||
// 重新开始录音
|
|
||||||
setTimeout(() => {
|
|
||||||
this.webSocketSend();
|
|
||||||
}, 500);
|
|
||||||
};
|
|
||||||
iatWS.onmessage = e => {
|
|
||||||
this.webSocketRes(e.data);
|
|
||||||
};
|
|
||||||
iatWS.onerror = e => {
|
|
||||||
this.recorderStop(e);
|
|
||||||
};
|
|
||||||
iatWS.onclose = e => {
|
|
||||||
this.recorderStop(e);
|
|
||||||
};
|
|
||||||
})
|
|
||||||
};
|
|
||||||
// 初始化浏览器录音
|
|
||||||
recorderInit() {
|
|
||||||
// 创建音频环境
|
|
||||||
try {
|
|
||||||
this.audioContext = this.audioContext ? this.audioContext : new (window.AudioContext || window.webkitAudioContext)();
|
|
||||||
this.audioContext.resume();
|
|
||||||
if (!this.audioContext) {
|
|
||||||
alert('浏览器不支持webAudioApi相关接口');
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
if (!this.audioContext) {
|
|
||||||
alert('浏览器不支持webAudioApi相关接口');
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
// 获取浏览器录音权限成功时回调
|
|
||||||
let getMediaSuccess = _ => {
|
|
||||||
// 创建一个用于通过JavaScript直接处理音频
|
|
||||||
this.scriptProcessor = this.audioContext.createScriptProcessor(0, 1, 1);
|
|
||||||
this.scriptProcessor.onaudioprocess = e => {
|
|
||||||
if (this.status === 'ing') {
|
|
||||||
// 多线程音频数据处理
|
|
||||||
try {
|
|
||||||
this.webWorker.postMessage(e.inputBuffer.getChannelData(0));
|
|
||||||
} catch (error) { }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 创建一个新的MediaStreamAudioSourceNode 对象,使来自MediaStream的音频可以被播放和操作
|
|
||||||
this.mediaSource = this.audioContext.createMediaStreamSource(this.streamRef);
|
|
||||||
this.mediaSource.connect(this.scriptProcessor);
|
|
||||||
this.scriptProcessor.connect(this.audioContext.destination);
|
|
||||||
this.connectWebSocket();
|
|
||||||
};
|
|
||||||
// 获取浏览器录音权限失败时回调
|
|
||||||
let getMediaFail = (e) => {
|
|
||||||
alert('对不起:录音权限获取失败!');
|
|
||||||
this.audioContext && this.audioContext.close();
|
|
||||||
this.audioContext = undefined;
|
|
||||||
// 关闭websocket
|
|
||||||
if (this.webSocket && this.webSocket.readyState === 1) {
|
|
||||||
this.webSocket.close();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia;
|
|
||||||
// 获取浏览器录音权限
|
|
||||||
if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
|
|
||||||
navigator.mediaDevices.getUserMedia({
|
|
||||||
audio: true
|
|
||||||
}).then(stream => {
|
|
||||||
this.streamRef = stream;
|
|
||||||
getMediaSuccess();
|
|
||||||
}).catch(e => {
|
|
||||||
getMediaFail(e);
|
|
||||||
})
|
|
||||||
} else if (navigator.getUserMedia) {
|
|
||||||
navigator.getUserMedia({
|
|
||||||
audio: true
|
|
||||||
}, (stream) => {
|
|
||||||
this.streamRef = stream;
|
|
||||||
getMediaSuccess();
|
|
||||||
}, function (e) {
|
|
||||||
getMediaFail(e);
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
if (navigator.userAgent.toLowerCase().match(/chrome/) && location.origin.indexOf('https://') < 0) {
|
|
||||||
console.error('获取浏览器录音功能,因安全性问题,需要在localhost 或 127.0.0.1 或 https 下才能获取权限!');
|
|
||||||
} else {
|
|
||||||
alert('对不起:未识别到录音设备!');
|
|
||||||
}
|
|
||||||
this.audioContext && this.audioContext.close();
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
// 向webSocket发送数据(音频二进制数据经过Base64处理)
|
|
||||||
webSocketSend() {
|
|
||||||
if (this.webSocket.readyState !== 1) return false;
|
|
||||||
|
|
||||||
// 音频数据
|
|
||||||
const audioData = this.audioData.splice(0, 1280);
|
|
||||||
const params = {
|
|
||||||
common: {
|
|
||||||
app_id: this.appId,
|
|
||||||
},
|
|
||||||
business: {
|
|
||||||
language: this.language, //小语种可在控制台--语音听写(流式)--方言/语种处添加试用
|
|
||||||
domain: 'iat',
|
|
||||||
accent: this.accent, //中文方言可在控制台--语音听写(流式)--方言/语种处添加试用
|
|
||||||
vad_eos: 5000,
|
|
||||||
dwa: 'wpgs' //为使该功能生效,需到控制台开通动态修正功能(该功能免费)
|
|
||||||
},
|
|
||||||
data: {
|
|
||||||
status: 0,
|
|
||||||
format: 'audio/L16;rate=16000',
|
|
||||||
encoding: 'raw',
|
|
||||||
audio: this.toBase64(audioData)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
// 发送数据
|
|
||||||
this.webSocket.send(JSON.stringify(params));
|
|
||||||
this.handlerInterval = setInterval(() => {
|
|
||||||
// websocket未连接
|
|
||||||
if (this.webSocket.readyState !== 1) {
|
|
||||||
this.audioData = [];
|
|
||||||
clearInterval(this.handlerInterval);
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
if (this.audioData.length === 0) {
|
|
||||||
if (this.status === 'end') {
|
|
||||||
this.webSocket.send(
|
|
||||||
JSON.stringify({
|
|
||||||
data: {
|
|
||||||
status: 2,
|
|
||||||
format: 'audio/L16;rate=16000',
|
|
||||||
encoding: 'raw',
|
|
||||||
audio: ''
|
|
||||||
}
|
|
||||||
})
|
|
||||||
);
|
|
||||||
this.audioData = [];
|
|
||||||
clearInterval(this.handlerInterval);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
|
|
||||||
// 中间帧
|
|
||||||
this.webSocket.send(
|
|
||||||
JSON.stringify({
|
|
||||||
data: {
|
|
||||||
status: 1,
|
|
||||||
format: 'audio/L16;rate=16000',
|
|
||||||
encoding: 'raw',
|
|
||||||
audio: this.toBase64(this.audioData.splice(0, 1280))
|
|
||||||
}
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}, 40);
|
|
||||||
};
|
|
||||||
// 识别结束 webSocket返回数据
|
|
||||||
webSocketRes(resultData) {
|
|
||||||
|
|
||||||
let jsonData = JSON.parse(resultData);
|
|
||||||
console.log(JSON.stringify( jsonData))
|
|
||||||
if (jsonData.data && jsonData.data.result) {
|
|
||||||
let data = jsonData.data.result;
|
|
||||||
let str = '';
|
|
||||||
let ws = data.ws;
|
|
||||||
for (let i = 0; i < ws.length; i++) {
|
|
||||||
str = str + ws[i].cw[0].w;
|
|
||||||
}
|
|
||||||
// 开启wpgs会有此字段(前提:在控制台开通动态修正功能)
|
|
||||||
// 取值为 "apd"时表示该片结果是追加到前面的最终结果;取值为"rpl" 时表示替换前面的部分结果,替换范围为rg字段
|
|
||||||
if (data.pgs) {
|
|
||||||
if (data.pgs === 'apd') {
|
|
||||||
// 将resultTextTemp同步给resultText
|
|
||||||
this.setResultText({
|
|
||||||
resultText: this.resultTextTemp
|
|
||||||
});
|
|
||||||
}
|
|
||||||
// 将结果存储在resultTextTemp中
|
|
||||||
this.setResultText({
|
|
||||||
resultTextTemp: this.resultText + str
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
this.setResultText({
|
|
||||||
resultText: this.resultText + str
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (jsonData.code === 0 && jsonData.data.status === 2) {
|
|
||||||
this.webSocket.close();
|
|
||||||
|
|
||||||
}
|
|
||||||
if (jsonData.code !== 0) {
|
|
||||||
this.webSocket.close();
|
|
||||||
|
|
||||||
}
|
|
||||||
};
|
|
||||||
// 启动录音
|
|
||||||
recorderStart() {
|
|
||||||
|
|
||||||
if (!this.audioContext) {
|
|
||||||
this.recorderInit();
|
|
||||||
} else {
|
|
||||||
this.audioContext.resume();
|
|
||||||
this.connectWebSocket();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
// 停止录音
|
|
||||||
recorderStop() {
|
|
||||||
if (!(/Safari/.test(navigator.userAgent) && !/Chrome/.test(navigator.userAgen))) {
|
|
||||||
// safari下suspend后再次resume录音内容将是空白,设置safari下不做suspend
|
|
||||||
this.audioContext && this.audioContext.suspend();
|
|
||||||
}
|
|
||||||
this.setStatus('end');
|
|
||||||
try {
|
|
||||||
// this.streamRef.getTracks().map(track => track.stop()) || his.streamRef.getAudioTracks()[0].stop();
|
|
||||||
} catch (error) {
|
|
||||||
console.error('暂停失败!');
|
|
||||||
}
|
|
||||||
};
|
|
||||||
// 开始
|
|
||||||
start() {
|
|
||||||
console.log('startstartstartstartstartstart');
|
|
||||||
this.recorderStart();
|
|
||||||
this.setResultText({ resultText: '', resultTextTemp: '' });
|
|
||||||
};
|
|
||||||
// 停止
|
|
||||||
stop() {
|
|
||||||
this.recorderStop();
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}));
|
|
Binary file not shown.
After Width: | Height: | Size: 446 B |
Binary file not shown.
After Width: | Height: | Size: 1.1 KiB |
|
@ -0,0 +1,47 @@
|
||||||
|
# 讯飞星火大模型 小程序文档
|
||||||
|
|
||||||
|
### 农业咨询
|
||||||
|
|
||||||
|
参数:nongye
|
||||||
|
|
||||||
|
APPID:uni.UNI9620511
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### 教育咨询
|
||||||
|
|
||||||
|
参数:jiaoyu
|
||||||
|
|
||||||
|
APPID:uni.UNI7AA205C
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### 法律咨询
|
||||||
|
|
||||||
|
参数:falv
|
||||||
|
|
||||||
|
APPID:uni.UNI358D505
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### 情感咨询
|
||||||
|
|
||||||
|
参数:qinggan
|
||||||
|
|
||||||
|
APPID:uni.UNI8080F14
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### 种植分析
|
||||||
|
|
||||||
|
参数:zhongzhi
|
||||||
|
|
||||||
|
APPID:uni.UNI9EDFE40
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### 养殖分析
|
||||||
|
|
||||||
|
参数:yangzhi
|
||||||
|
|
||||||
|
APPID:uni.UNIEEA7DC9
|
Loading…
Reference in New Issue