Переглянути джерело

AI参谋跳转接口调试

zhujindu 1 рік тому
батько
коміт
be83f4270c
3 змінених файлів з 391 додано та 1 видалено
  1. 2 0
      package.json
  2. 386 0
      src/views/intelligence/audioBox.vue
  3. 3 1
      src/views/intelligence/index.vue

+ 2 - 0
package.json

@@ -19,6 +19,8 @@
     "coordtransform": "^2.1.2",
     "core-js": "^3.6.5",
     "element-ui": "^2.15.6",
+    "js-audio-recorder": "^1.0.7",
+    "lamejs": "^1.2.0",
     "vant": "^2.12.37",
     "vconsole": "^3.15.1",
     "vue": "^2.6.11",

+ 386 - 0
src/views/intelligence/audioBox.vue

@@ -0,0 +1,386 @@
+<template>
+  <div class="audioBoxContent">
+    <div class="audioBox">
+      <div
+        class="boxItem"
+        :class="recordStatus == 'begin' || recordStatus == 'resume' ? 'active' : ''"
+        @click="startRecorder('begin')">
+        <div class="item_icon iconfonts iconrecord-circle-line"></div>
+        <div class="item_desc">开始录制</div>
+      </div>
+      <div class="boxItem" v-show="recordStatus !== 'pause'" @click="pauseRecorder('pause')">
+        <div class="item_icon iconfonts iconzanting1"></div>
+        <div class="item_desc">暂停录制</div>
+      </div>
+      <div class="boxItem" v-show="recordStatus == 'pause'" @click="resumeRecorder('resume')">
+        <div class="item_icon iconfonts iconicon_play"></div>
+        <div class="item_desc">继续录制</div>
+      </div>
+      <div class="boxItem" @click="stopRecorder('stop')">
+        <div class="item_icon iconfonts iconstop-full"></div>
+        <div class="item_desc">停止录制</div>
+      </div>
+      <div class="boxItem">
+        <div class="item_dura">{{ formatNum(rm) }}:{{ formatNum(rs) }}</div>
+        <div class="item_desc">录音时长</div>
+      </div>
+    </div>
+    <div class="audioBox playBox">
+      <div class="boxItem" @click="playRecorder('play')">
+        <div class="item_icon iconfonts iconicon_play"></div>
+        <div class="item_desc">录音播放</div>
+      </div>
+      <div class="boxItem" @click="resumePlayRecorder('resume_play')">
+        <div class="item_icon iconfonts iconicon_play"></div>
+        <div class="item_desc">恢复播放</div>
+      </div>
+      <div class="boxItem" @click="pausePlayRecorder('pause_play')">
+        <div class="item_icon iconfonts iconzanting1"></div>
+        <div class="item_desc">暂停播放</div>
+      </div>
+      <div class="boxItem">
+        <div class="item_dura">
+          {{ formatNum(ym) }}:{{ formatNum(ys) }}/{{ formatNum(rm) }}:{{ formatNum(rs) }}
+        </div>
+        <div class="item_desc">播放时长/录音时长</div>
+      </div>
+      <div class="boxItem" @click="resetRecorder('reset')">
+        <div class="item_icon iconfonts iconzhongzhi"></div>
+        <div class="item_desc">重新录制</div>
+      </div>
+      <div class="boxItem" @click="getRecorder">
+        <div class="item_icon iconfonts iconbaocun01"></div>
+        <div class="item_desc">保存</div>
+      </div>
+    </div>
+  </div>
+</template>
+<script>
+// lamejs  版本号为  1.2.0  最新版本会报错 属性找不到
+import Recorder from 'js-audio-recorder';
+const lamejs = require('lamejs');
+var recorder = new Recorder({
+  sampleBits: 16, // 采样位数,支持 8 或 16,默认是16
+  sampleRate: 48000, // 采样率,支持 11025、16000、22050、24000、44100、48000,根据浏览器默认值,我的chrome是48000
+  numChannels: 1, // 声道,支持 1 或 2, 默认是1
+  // compiling: false,(0.x版本中生效,1.x增加中)  // 是否边录边转换,默认是false
+});
+
+export default {
+  name: 'audioRecord',
+  data() {
+    return {
+      //波浪图-录音
+      drawRecordId: null,
+      oCanvas: null,
+      ctx: null,
+      //波浪图-播放
+      drawPlayId: null,
+      pCanvas: null,
+      pCtx: null,
+      recordStatus: null,
+      rm: 0, // 录音时长 分
+      rs: 0, // 录音时长 秒
+      ym: 0, // 播放时长 分
+      ys: 0, // 播放时长 秒
+    };
+  },
+  created() {
+    // 绑定事件-打印的是当前录音数据
+    recorder.onprogress = function (params) {
+      // console.log('--------------START---------------')
+      console.log('录音时长(秒)', params.duration);
+      // console.log('录音大小(字节)', params.fileSize);
+      // console.log('录音音量百分比(%)', params.vol);
+      // console.log('当前录音的总数据([DataView, DataView...])', params.data);
+      // console.log('--------------END---------------')
+    };
+  },
+  mounted() {
+    // this.startCanvas();
+  },
+  methods: {
+    formatNum(val) {
+      return val < 10 ? '0' + val : val;
+    },
+    // 将秒数 转为 时间
+    secondsTotime(seconds) {
+      var hours = Math.floor(seconds / 3600);
+      var minutes = Math.floor((seconds - hours * 3600) / 60);
+      var second = seconds - hours * 3600 - minutes * 60;
+      second = Math.round(seconds * 100) / 100;
+      var result =
+        (minutes < 10 ? '0' + minutes : minutes) + ':' + (second < 10 ? '0' + second : second);
+      return result;
+    },
+    /**
+     * 波浪图配置
+     * */
+    startCanvas() {
+      //录音波浪
+      this.oCanvas = document.getElementById('canvas');
+      this.ctx = this.oCanvas.getContext('2d');
+      //播放波浪
+      this.pCanvas = document.getElementById('playChart');
+      this.pCtx = this.pCanvas.getContext('2d');
+    },
+    /**
+     *  录音的具体操作功能
+     * */
+    // 开始录音
+    startRecorder(val) {
+      this.recordStatus = val;
+      let that = this;
+      // 获取麦克风权限
+      Recorder.getPermission().then(
+        () => {
+          that.$message.success('获取权限成功,开始录音');
+          recorder.start();
+        },
+        (error) => {
+          that.$message.error('请先允许该网页使用麦克风');
+          // console.log(`${error.name} : ${error.message}`);
+        }
+      );
+      // recorder.start().then(() => {
+      //   this.drawRecord();//开始绘制图片
+      // }, (error) => {
+      //   // 出错了
+      //   console.log(`${error.name} : ${error.message}`);
+      // });
+    },
+    // 继续录音
+    resumeRecorder(val) {
+      this.recordStatus = val;
+      recorder.resume();
+    },
+    // 暂停录音
+    pauseRecorder(val) {
+      this.recordStatus = val;
+      recorder.pause();
+      // this.drawRecordId && cancelAnimationFrame(this.drawRecordId);
+      // this.drawRecordId = null;
+    },
+    // 结束录音
+    stopRecorder(val) {
+      this.recordStatus = val;
+      recorder.stop();
+      // this.drawRecordId && cancelAnimationFrame(this.drawRecordId);
+      // this.drawRecordId = null;
+    },
+    // 录音播放
+    playRecorder(val) {
+      this.recordStatus = val;
+      recorder.play();
+      // this.drawPlay();//绘制波浪图
+    },
+    // 暂停录音播放
+    pausePlayRecorder(val) {
+      this.recordStatus = val;
+      recorder.pausePlay();
+    },
+    // 恢复录音播放
+    resumePlayRecorder(val) {
+      this.recordStatus = val;
+      recorder.resumePlay();
+      // this.drawPlay();//绘制波浪图
+    },
+    // 停止录音播放
+    stopPlayRecorder(val) {
+      this.recordStatus = val;
+      recorder.stopPlay();
+    },
+    // 重新录制
+    resetRecorder(val) {
+      this.recordStatus = val;
+    },
+    // 销毁录音
+    destroyRecorder(val) {
+      this.recordStatus = val;
+      let that = this;
+      recorder.destroy().then(function () {
+        // recorder = null;
+        that.drawRecordId && cancelAnimationFrame(that.drawRecordId);
+        that.drawRecordId = null;
+      });
+    },
+    /**
+     *  获取录音文件
+     * */
+    getRecorder() {
+      let toltime = recorder.duration; //录音总时长
+      let fileSize = recorder.fileSize; //录音总大小
+      //录音结束,获取取录音数据
+      let PCMBlob = recorder.getPCMBlob(); //获取 PCM 数据
+      let wav = recorder.getWAVBlob(); //获取 WAV 数据
+      let channel = recorder.getChannelData(); //获取左声道和右声道音频数据
+    },
+    /**
+     *  下载录音文件
+     * */
+    //下载pcm
+    downPCM() {
+      //这里传参进去的时文件名
+      recorder.downloadPCM('新文件');
+    },
+    //下载wav
+    downWAV() {
+      //这里传参进去的时文件名
+      recorder.downloadWAV('新文件');
+    },
+    /**
+     *  获取麦克风权限
+     * */
+    getPermission() {
+      Recorder.getPermission().then(
+        () => {
+          this.$message.success('获取权限成功');
+        },
+        (error) => {
+          console.log(`${error.name} : ${error.message}`);
+        }
+      );
+    },
+    /**
+     * 文件格式转换 wav-map3
+     * */
+    getMp3Data() {
+      const mp3Blob = this.convertToMp3(recorder.getWAV());
+      recorder.download(mp3Blob, 'recorder', 'mp3');
+    },
+    convertToMp3(wavDataView) {
+      // 获取wav头信息
+      const wav = lamejs.WavHeader.readHeader(wavDataView); // 此处其实可以不用去读wav头信息,毕竟有对应的config配置
+      const { channels, sampleRate } = wav;
+      const mp3enc = new lamejs.Mp3Encoder(channels, sampleRate, 128);
+      // 获取左右通道数据
+      const result = recorder.getChannelData();
+      const buffer = [];
+      const leftData =
+        result.left && new Int16Array(result.left.buffer, 0, result.left.byteLength / 2);
+      const rightData =
+        result.right && new Int16Array(result.right.buffer, 0, result.right.byteLength / 2);
+      const remaining = leftData.length + (rightData ? rightData.length : 0);
+      const maxSamples = 1152;
+      for (let i = 0; i < remaining; i += maxSamples) {
+        const left = leftData.subarray(i, i + maxSamples);
+        let right = null;
+        let mp3buf = null;
+        if (channels === 2) {
+          right = rightData.subarray(i, i + maxSamples);
+          mp3buf = mp3enc.encodeBuffer(left, right);
+        } else {
+          mp3buf = mp3enc.encodeBuffer(left);
+        }
+        if (mp3buf.length > 0) {
+          buffer.push(mp3buf);
+        }
+      }
+      const enc = mp3enc.flush();
+      if (enc.length > 0) {
+        buffer.push(enc);
+      }
+      return new Blob(buffer, { type: 'audio/mp3' });
+    },
+    /**
+     * 绘制波浪图-录音
+     * */
+    drawRecord() {
+      // 用requestAnimationFrame稳定60fps绘制
+      this.drawRecordId = requestAnimationFrame(this.drawRecord);
+      // 实时获取音频大小数据
+      let dataArray = recorder.getRecordAnalyseData(),
+        bufferLength = dataArray.length;
+      // 填充背景色
+      this.ctx.fillStyle = 'rgb(200, 200, 200)';
+      this.ctx.fillRect(0, 0, this.oCanvas.width, this.oCanvas.height);
+      // 设定波形绘制颜色
+      this.ctx.lineWidth = 2;
+      this.ctx.strokeStyle = 'rgb(0, 0, 0)';
+      this.ctx.beginPath();
+      var sliceWidth = (this.oCanvas.width * 1.0) / bufferLength, // 一个点占多少位置,共有bufferLength个点要绘制
+        x = 0; // 绘制点的x轴位置
+      for (var i = 0; i < bufferLength; i++) {
+        var v = dataArray[i] / 128.0;
+        var y = (v * this.oCanvas.height) / 2;
+        if (i === 0) {
+          // 第一个点
+          this.ctx.moveTo(x, y);
+        } else {
+          // 剩余的点
+          this.ctx.lineTo(x, y);
+        }
+        // 依次平移,绘制所有点
+        x += sliceWidth;
+      }
+      this.ctx.lineTo(this.oCanvas.width, this.oCanvas.height / 2);
+      this.ctx.stroke();
+    },
+    /**
+     * 绘制波浪图-播放
+     * */
+    drawPlay() {
+      // 用requestAnimationFrame稳定60fps绘制
+      this.drawPlayId = requestAnimationFrame(this.drawPlay);
+      // 实时获取音频大小数据
+      let dataArray = recorder.getPlayAnalyseData(),
+        bufferLength = dataArray.length;
+      // 填充背景色
+      this.pCtx.fillStyle = 'rgb(200, 200, 200)';
+      this.pCtx.fillRect(0, 0, this.pCanvas.width, this.pCanvas.height);
+      // 设定波形绘制颜色
+      this.pCtx.lineWidth = 2;
+      this.pCtx.strokeStyle = 'rgb(0, 0, 0)';
+      this.pCtx.beginPath();
+      var sliceWidth = (this.pCanvas.width * 1.0) / bufferLength, // 一个点占多少位置,共有bufferLength个点要绘制
+        x = 0; // 绘制点的x轴位置
+      for (var i = 0; i < bufferLength; i++) {
+        var v = dataArray[i] / 128.0;
+        var y = (v * this.pCanvas.height) / 2;
+        if (i === 0) {
+          // 第一个点
+          this.pCtx.moveTo(x, y);
+        } else {
+          // 剩余的点
+          this.pCtx.lineTo(x, y);
+        }
+        // 依次平移,绘制所有点
+        x += sliceWidth;
+      }
+      this.pCtx.lineTo(this.pCanvas.width, this.pCanvas.height / 2);
+      this.pCtx.stroke();
+    },
+  },
+};
+</script>
+<style lang="scss" scoped>
+.audioBoxContent {
+  background: #fff;
+}
+.audioBox {
+  color: #bec0e0;
+  // width: 6.48rem;
+  // height: 1.3rem;
+  display: flex;
+  justify-content: space-around;
+  align-items: center;
+  font-size: 14px;
+  .boxItem {
+    cursor: pointer;
+    text-align: center;
+    margin: 0 5px;
+    .item_icon {
+      font-size: 14px !important;
+    }
+    .item_desc {
+      margin-top: 0.1rem;
+    }
+    &.active {
+      color: #49f66c;
+    }
+    &:hover {
+      color: #49f66c;
+    }
+  }
+}
+</style>

+ 3 - 1
src/views/intelligence/index.vue

@@ -422,6 +422,7 @@
         </div>
       </div>
     </van-overlay>
+    <audioBox></audioBox>
   </div>
 </template>
 
@@ -436,9 +437,10 @@ import { aiDialogue } from '@/api/inventory';
 import { getPosition, getTicketFun } from '@/utils/TXApiFun';
 import BenzAMRRecorder from 'benz-amr-recorder';
 import sample3s from '@/assets/mp3/sample-3s.mp3';
+import audioBox from './audioBox.vue';
 export default {
   name: 'ai',
-  components: { tabBar },
+  components: { tabBar, audioBox },
   data() {
     return {
       sample3s: sample3s,