This commit is contained in:
shengchanzhe 2023-10-12 15:48:10 +08:00
parent ee064c2c55
commit 2fd4cd8798
2 changed files with 221 additions and 218 deletions

359
index.js
View File

@ -1,6 +1,5 @@
// (function () { // (function () {
// // btnControl.onclick = function () { // // btnControl.onclick = function () {
// // if (btnStatus === "UNDEFINED" || btnStatus === "CLOSED") { // // if (btnStatus === "UNDEFINED" || btnStatus === "CLOSED") {
// // connectWebSocket(); // // connectWebSocket();
@ -11,197 +10,205 @@
// // }; // // };
// })(); // })();
let btnStatus = "UNDEFINED"; // "UNDEFINED" "CONNECTING" "OPEN" "CLOSING" "CLOSED" let btnStatus = 'UNDEFINED' // "UNDEFINED" "CONNECTING" "OPEN" "CLOSING" "CLOSED"
// const btnControl = document.getElementById("btn_control"); // const btnControl = document.getElementById("btn_control");
const btnControl = {}; const btnControl = {}
const recorder = new RecorderManager("./dists"); const recorder = new RecorderManager('./dists')
recorder.onStart = () => { recorder.onStart = () => {
changeBtnStatus("OPEN"); changeBtnStatus('OPEN')
} }
let iatWS; let iatWS
let resultText = ""; let resultText = ''
let resultTextTemp = ""; let resultTextTemp = ''
let countdownInterval; let countdownInterval
window.winText = ''
/** /**
* 获取websocket url * 获取websocket url
* 该接口需要后端提供这里为了方便前端处理 * 该接口需要后端提供这里为了方便前端处理
*/ */
function getWebSocketUrl() { function getWebSocketUrl() {
// 请求地址根据语种不同变化 // 请求地址根据语种不同变化
var url = "wss://iat-api.xfyun.cn/v2/iat"; let url = 'wss://iat-api.xfyun.cn/v2/iat'
var host = "iat-api.xfyun.cn"; const host = 'iat-api.xfyun.cn'
var apiKey = API_KEY; const apiKey = API_KEY
var apiSecret = API_SECRET; const apiSecret = API_SECRET
var date = new Date().toGMTString(); const date = new Date().toGMTString()
var algorithm = "hmac-sha256"; const algorithm = 'hmac-sha256'
var headers = "host date request-line"; const headers = 'host date request-line'
var signatureOrigin = `host: ${host}\ndate: ${date}\nGET /v2/iat HTTP/1.1`; const signatureOrigin = `host: ${host}\ndate: ${date}\nGET /v2/iat HTTP/1.1`
var signatureSha = CryptoJS.HmacSHA256(signatureOrigin, apiSecret); const signatureSha = CryptoJS.HmacSHA256(signatureOrigin, apiSecret)
var signature = CryptoJS.enc.Base64.stringify(signatureSha); const signature = CryptoJS.enc.Base64.stringify(signatureSha)
var authorizationOrigin = `api_key="${apiKey}", algorithm="${algorithm}", headers="${headers}", signature="${signature}"`; const authorizationOrigin = `api_key="${apiKey}", algorithm="${algorithm}", headers="${headers}", signature="${signature}"`
var authorization = btoa(authorizationOrigin); const authorization = btoa(authorizationOrigin)
url = `${url}?authorization=${authorization}&date=${date}&host=${host}`; url = `${url}?authorization=${authorization}&date=${date}&host=${host}`
return url; return url
} }
function toBase64(buffer) { function toBase64(buffer) {
var binary = ""; let binary = ''
var bytes = new Uint8Array(buffer); const bytes = new Uint8Array(buffer)
var len = bytes.byteLength; const len = bytes.byteLength
for (var i = 0; i < len; i++) { for (let i = 0; i < len; i++)
binary += String.fromCharCode(bytes[i]); binary += String.fromCharCode(bytes[i])
return window.btoa(binary)
}
function countdown() {
let seconds = 60
btnControl.innerText = `录音中(${seconds}s`
countdownInterval = setInterval(() => {
seconds = seconds - 1
if (seconds <= 0) {
clearInterval(countdownInterval)
recorder.stop()
} }
return window.btoa(binary); else {
} btnControl.innerText = `录音中(${seconds}s`
}
}, 1000)
}
function countdown() { function changeBtnStatus(status) {
let seconds = 60; btnStatus = status
btnControl.innerText = `录音中(${seconds}s`; if (status === 'CONNECTING') {
countdownInterval = setInterval(() => { btnControl.innerText = '建立连接中'
seconds = seconds - 1; document.getElementById('result').innerText = ''
if (seconds <= 0) { resultText = ''
clearInterval(countdownInterval); resultTextTemp = ''
recorder.stop(); }
} else { else if (status === 'OPEN') {
btnControl.innerText = `录音中(${seconds}s`; countdown()
}
else if (status === 'CLOSING') {
btnControl.innerText = '关闭连接中'
}
else if (status === 'CLOSED') {
btnControl.innerText = '开始录音'
}
}
function renderResult(resultData) {
// 识别结束
const jsonData = JSON.parse(resultData)
if (jsonData.data && jsonData.data.result) {
const data = jsonData.data.result
let str = ''
const 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
resultText = resultTextTemp
} }
}, 1000); // 将结果存储在resultTextTemp中
resultTextTemp = resultText + str
}
else {
resultText = resultText + str
}
document.getElementById('result').innerText
= resultTextTemp || resultText || ''
console.log('录音结果:', resultTextTemp || resultText || '')
window.winText = resultTextTemp || resultText || ''
window.dispatchEvent(new Event('test'))
} }
if (jsonData.code === 0 && jsonData.data.status === 2)
iatWS.close()
function changeBtnStatus(status) { if (jsonData.code !== 0) {
btnStatus = status; iatWS.close()
if (status === "CONNECTING") { console.error(jsonData)
btnControl.innerText = "建立连接中";
document.getElementById("result").innerText = "";
resultText = "";
resultTextTemp = "";
} else if (status === "OPEN") {
countdown();
} else if (status === "CLOSING") {
btnControl.innerText = "关闭连接中";
} else if (status === "CLOSED") {
btnControl.innerText = "开始录音";
}
} }
}
function renderResult(resultData) { function connectWebSocket() {
// 识别结束 const websocketUrl = getWebSocketUrl()
let jsonData = JSON.parse(resultData); if ('WebSocket' in window) {
if (jsonData.data && jsonData.data.result) { iatWS = new WebSocket(websocketUrl)
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
resultText = resultTextTemp;
}
// 将结果存储在resultTextTemp中
resultTextTemp = resultText + str;
} else {
resultText = resultText + str;
}
document.getElementById("result").innerText =
resultTextTemp || resultText || "";
console.log(resultTextTemp);
}
if (jsonData.code === 0 && jsonData.data.status === 2) {
iatWS.close();
}
if (jsonData.code !== 0) {
iatWS.close();
console.error(jsonData);
}
} }
else if ('MozWebSocket' in window) {
function connectWebSocket() { iatWS = new MozWebSocket(websocketUrl)
const websocketUrl = getWebSocketUrl(); }
if ("WebSocket" in window) { else {
iatWS = new WebSocket(websocketUrl); alert('浏览器不支持WebSocket')
} else if ("MozWebSocket" in window) { return
iatWS = new MozWebSocket(websocketUrl); }
} else { changeBtnStatus('CONNECTING')
alert("浏览器不支持WebSocket"); iatWS.onopen = (e) => {
return; // 开始录音
recorder.start({
sampleRate: 16000,
frameSize: 1280,
})
const params = {
common: {
app_id: APPID,
},
business: {
language: 'zh_cn',
domain: 'iat',
accent: 'mandarin',
vad_eos: 5000,
dwa: 'wpgs',
},
data: {
status: 0,
format: 'audio/L16;rate=16000',
encoding: 'raw',
},
} }
changeBtnStatus("CONNECTING"); iatWS.send(JSON.stringify(params))
iatWS.onopen = (e) => { }
// 开始录音 iatWS.onmessage = (e) => {
recorder.start({ renderResult(e.data)
sampleRate: 16000, }
frameSize: 1280, iatWS.onerror = (e) => {
}); console.error(e)
var params = { recorder.stop()
common: { changeBtnStatus('CLOSED')
app_id: APPID, }
}, iatWS.onclose = (e) => {
business: { recorder.stop()
language: "zh_cn", changeBtnStatus('CLOSED')
domain: "iat", }
accent: "mandarin", }
vad_eos: 5000,
dwa: "wpgs", recorder.onFrameRecorded = ({ isLastFrame, frameBuffer }) => {
}, if (iatWS.readyState === iatWS.OPEN) {
iatWS.send(
JSON.stringify({
data: { data: {
status: 0, status: isLastFrame ? 2 : 1,
format: "audio/L16;rate=16000", format: 'audio/L16;rate=16000',
encoding: "raw", encoding: 'raw',
audio: toBase64(frameBuffer),
}, },
}; }),
iatWS.send(JSON.stringify(params)); )
}; if (isLastFrame)
iatWS.onmessage = (e) => { changeBtnStatus('CLOSING')
renderResult(e.data);
};
iatWS.onerror = (e) => {
console.error(e);
recorder.stop();
changeBtnStatus("CLOSED");
};
iatWS.onclose = (e) => {
recorder.stop();
changeBtnStatus("CLOSED");
};
} }
}
recorder.onFrameRecorded = ({ isLastFrame, frameBuffer }) => { recorder.onStop = () => {
if (iatWS.readyState === iatWS.OPEN) { clearInterval(countdownInterval)
iatWS.send( }
JSON.stringify({ function RecordXunfei() {
data: { if (btnStatus === 'UNDEFINED' || btnStatus === 'CLOSED') {
status: isLastFrame ? 2 : 1, console.log('开始录音')
format: "audio/L16;rate=16000", connectWebSocket()
encoding: "raw", }
audio: toBase64(frameBuffer), else if (btnStatus === 'CONNECTING' || btnStatus === 'OPEN') {
}, console.log('结束录音')
}) // 结束录音
); recorder.stop()
if (isLastFrame) { }
changeBtnStatus("CLOSING"); return window.winText
} }
}
};
recorder.onStop = () => {
clearInterval(countdownInterval);
};
function RecordXunfei(){
if (btnStatus === "UNDEFINED" || btnStatus === "CLOSED") {
console.log('开始录音');
connectWebSocket();
} else if (btnStatus === "CONNECTING" || btnStatus === "OPEN") {
console.log('结束录音');
// 结束录音
recorder.stop();
}
}

View File

@ -1,6 +1,6 @@
<script setup lang='ts'> <script setup lang='ts'>
import type { Ref } from 'vue' import type { Ref } from 'vue'
import { computed, onMounted, onUnmounted, reactive, ref, watch } from 'vue' import { computed, onMounted, onUnmounted, reactive, ref } from 'vue'
import { useRoute } from 'vue-router' import { useRoute } from 'vue-router'
import { storeToRefs } from 'pinia' import { storeToRefs } from 'pinia'
import { import {
@ -36,6 +36,9 @@ const connection = new Push({
auth: '/plugin/webman/push/auth', // () auth: '/plugin/webman/push/auth', // ()
}) })
//
let recordFalg = 0
// uid1 // uid1
const uid = 1 const uid = 1
// user-1uid1 // user-1uid1
@ -45,6 +48,15 @@ console.log(user_channel)
user_channel.on('message', (data: any) => { user_channel.on('message', (data: any) => {
// data // data
console.log('收到命令', data) console.log('收到命令', data)
if (recordFalg == 0) {
RecordXunfei()
recordFalg = 1
}
else {
RecordXunfei()
handleSubmit()
recordFalg = 0
}
}) })
let controller = new AbortController() let controller = new AbortController()
@ -545,51 +557,35 @@ onUnmounted(() => {
controller.abort() controller.abort()
}) })
const iatRecorder = reactive(new IatRecorder()) const iatRecorder = reactive(new IatRecorder())
let a = true const a = true
watch(() => iatRecorder.resultText, (n, o) => { // watch(() => iatRecorder.resultText, (n, o) => {
console.log('监听', n) // console.log('', n)
prompt.value = n // prompt.value = n
// })
window.winText = ''
window.addEventListener('test', (e) => {
if (recordFalg == 1)
prompt.value = window.winText
}) })
const click = () => { const click = () => {
// new RecordXunfei(); // prompt.value = window.winText
if (a) { RecordXunfei()
iatRecorder.start(prompt.value)
a = !a
console.log('录音开始')
}
else {
iatRecorder.stop()
a = !a
console.log('录音结束')
console.log('最终结果', iatRecorder)
}
}
const result = ref('') // if (a) {
// iatRecorder.start(prompt.value)
// // a = !a
const recordReady = () => { // console.log('')
console.info('按钮就绪!') // }
} // else {
const recordStart = () => { // iatRecorder.stop()
console.info('录音开始') // a = !a
} // console.log('')
const showResult = (text) => { // console.log('', iatRecorder)
console.info('收到识别结果:', text) // }
}
const recordStop = () => {
console.info('录音结束')
}
const recordNoResult = (text) => {
console.info('没有录到什么,请重试')
}
const recordComplete = (text) => {
console.info('识别完成! 最终结果:', text)
}
const recordFailed = (error) => {
console.info('识别失败,错误栈:', error)
} }
</script> </script>
@ -619,7 +615,7 @@ const recordFailed = (error) => {
</button> </button>
</div> </div>
<br> <br>
<div id="result" /> <div id="result" ref="resultRef" />
<template v-if="!dataSources.length"> <template v-if="!dataSources.length">
<div <div