Files

342 lines
9.2 KiB
Vue

<template>
<view
:class="{
'focus': inputOnFocus
}"
class="fix-page-bottom"
>
<view v-if="inputModel === 'input'" class="bottom-body flex-center-between">
<view class="history-wrap" @click="historyViewHandle">
历史
</view>
<view class="input-container">
<!-- 输入模式切换 -->
<view
class="input-model"
@click="toggleInputModel"
>
<image
:src="webUrl + '/aiChat/microphone.png'"
class="icon"
mode="widthFix"
/>
</view>
<!-- 输入框 -->
<view class="input-wrap flex-center-between">
<textarea
v-model.trim="prompt"
:show-confirm-bar="false"
:adjust-position="true"
:auto-height="true"
:disabled="loading"
:maxlength="500"
class="inp"
@confirm="sendHandle"
@focus="promptInputFocusHandle"
@blur="promptInputBlurHandle"
/>
<view v-if="!prompt && !inputOnFocus" class="placeholder-txt">发消息...</view>
</view>
<view
class="send-btn"
@click="sendHandle"
>
<image
:src="webUrl + '/aiChat/send.png'"
class="icon"
mode="widthFix"
/>
</view>
</view>
</view>
<!-- 语音输入 -->
<view
v-if="inputModel === 'sound'"
class="sound-input-wrap"
>
<view class="toggle-btn">
<image
:src="webUrl + '/aiChat/icon-06.png'"
class="input-icon"
mode="widthFix"
@click="toggleInputModel"
/>
</view>
<view
class="sound-wrap"
@touchstart="startRecord"
@touchend="stopRecord"
>
<view v-if="startTaskFlag" class="music-wrap">
<view class="item one" />
<view class="item two" />
<view class="item three" />
<view class="item four" />
<view class="item five" />
<view class="item six" />
<view class="item seven" />
</view>
<image
:src="webUrl + '/aiChat/microphone-big.png'"
class="icon"
mode="widthFix"
/>
<view v-if="startTaskFlag" class="music-wrap music-wrap2">
<view class="item one" />
<view class="item two" />
<view class="item three" />
<view class="item four" />
<view class="item five" />
<view class="item six" />
<view class="item seven" />
</view>
</view>
</view>
</view>
</template>
<script>
import {
makeFileTransTask,
getFileTransResult
} from '@/api/voiceToText/index'
import { VUE_APP_API_URL } from '@/config'
import cookie from '@/utils/store/cookie'
export default {
name: 'BottomSend',
props: {
loading: {
type: Boolean,
default: false
},
keyboardHeight: {
type: Number,
default: 0
},
voiceException: {
type: String,
default: '没有听清您说了什么,请再说一遍'
}
},
data() {
return {
token: cookie.get('login_status'),
userInfo: cookie.get('userInfo'),
webUrl: this.$VUE_APP_RESOURCES_URL,
// 输入模式:input-键盘,sound-语音
inputModel: 'input',
/**
* 端午节送礼攻略
* 丽江逛吃攻略
* 云南非遗有哪些?
* 怎么申请地理标志保护产品?
* 想找个像《去有风的地方》那样的治愈县城
* 云南有哪些小众县城适合旅居?
* 查询最近一个月的订单
*/
prompt: '',
recordManager: null,
// 录音权限是否开通
recordPermission: false,
taskId: '',
taskTimer: null,
startTaskFlag: false,
// 输入框是否聚焦
inputOnFocus: false
}
},
beforeDestroy() {
this.clearIntervalFn()
},
created() {
uni.getSetting({
success: res => {
if (res.authSetting['scope.record']) {
this.recordPermission = true
}
}
})
},
methods: {
promptInputFocusHandle() {
this.$emit('focus', 1)
setTimeout(() => {
this.inputOnFocus = true
}, 100)
},
promptInputBlurHandle() {
this.$emit('focus', 0)
this.inputOnFocus = false
},
toggleInputModel() {
if (!this.token) {
uni.reLaunch({ url: '/pages/auth/login' })
return
}
if (this.loading) return
if (this.inputModel === 'input') {
uni.getSetting({
success: res => {
if (!res.authSetting['scope.record']) {
uni.authorize({
scope: 'scope.record',
success: () => {
console.log('获取录音权限成功')
this.recordPermission = true
this.inputModel = 'sound'
},
fail: () => {
console.log('获取录音权限失败')
this.recordPermission = false
uni.showModal({
title: '提示',
content: '需要获取麦克风权限',
confirmText: '前往设置',
confirmColor: '#3D4CF1',
success(res2) {
if (res2.confirm) {
wx.openSetting()
}
}
})
}
})
} else {
this.recordPermission = true
this.inputModel = 'sound'
}
}
})
return
}
if (this.inputModel === 'sound') {
this.clearIntervalFn()
this.inputModel = 'input'
return
}
},
startRecord() {
if (this.loading) {
this.$toast('正在检索')
return
}
// 正在识别,不触发相关动作
if (this.startTaskFlag || this.taskTimer) {
return
}
this.recordManager = uni.getRecorderManager()
console.log('启动录音')
this.startTaskFlag = true
this.recordManager.start({
duration: 60 * 1000,
frameSize: 1,
sampleRate: 16000,
format: 'wav'
})
},
stopRecord() {
const _this = this
// 正在识别,不触发相关动作
if (this.taskTimer) {
return
}
if (_this.recordManager) {
_this.recordManager.stop()
console.log('停止录音')
_this.startTaskFlag = false
_this.recordManager.onStop((res) => {
console.log('录音结束------------')
console.log(res)
const { tempFilePath, fileSize, duration } = res
if (tempFilePath && fileSize && duration) {
_this.taskId = ''
_this.clearIntervalFn()
uni.showLoading({ title: '识别中...' })
uni.uploadFile({
url: `${VUE_APP_API_URL}/api/upload`,
filePath: tempFilePath,
header: {
Authorization: 'Bearer ' + (_this.token || '')
},
name: 'file',
success: uploadRes => {
console.log(JSON.parse(uploadRes.data))
_this.renderTransTask(uploadRes)
},
fail: err => {
console.log(err)
uni.hideLoading()
_this.$toast(_this.voiceException)
}
})
} else {
_this.$toast(_this.voiceException)
}
})
}
},
renderTransTask(uploadRes) {
const _this = this
const file = JSON.parse(uploadRes.data).link || ''
if (!file) return
makeFileTransTask({
file
}).then(taskRes => {
_this.taskId = taskRes.data
_this.getTransResultReq()
}).catch(() => {
uni.hideLoading()
_this.$toast(_this.voiceException)
})
},
getTransResultReq() {
const _this = this
_this.taskTimer = setInterval(() => {
getFileTransResult({
taskId: _this.taskId
}).then(res => {
const { success, data = [] } = res
if (success && data) {
uni.hideLoading()
_this.clearIntervalFn()
if (data === '__NULL__') {
_this.$toast(_this.voiceException)
} else {
if (data.length > 0) {
const prompt = data[0].Text
if (prompt) {
_this.$emit('send', { prompt: prompt.replace('。', '') })
}
}
}
}
}).catch(() => {
uni.hideLoading()
_this.$toast(_this.voiceException)
})
}, 1000)
},
clearIntervalFn() {
this.taskTimer && clearInterval(this.taskTimer)
this.taskTimer = null
setTimeout(() => {
this.startTaskFlag = false
}, 300)
},
sendHandle() {
if (this.loading) return
if (!this.prompt) {
this.$toast('请输入您想问的内容')
return
}
this.$emit('send', { prompt: this.prompt })
this.prompt = ''
this.inputOnFocus = false
},
historyViewHandle() {
this.$emit('history')
}
}
}
</script>