123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123 |
- <!-- 语音识别 -->
- <template>
- <div class="ai-recording">
- <div v-for="(_i, index) in 31" :key="index" class="ai-recording-bar"></div>
- </div>
- </template>
- <script setup lang="ts">
- import { IatRecorder } from '../utils/voice'
- const iatRecorder:Recordable = new IatRecorder()
- import { ref, onMounted, nextTick, onUnmounted } from 'vue'
- const text = ref('')
- let mediaStream // 保存麦克风流
- // 获取麦克风权限并开始录音
- async function startRecording() {
- mediaStream = await navigator.mediaDevices.getUserMedia({ audio: true })
- console.log('麦克风已开启')
- }
- // 停止麦克风访问
- function stopRecording() {
- if (mediaStream) {
- const tracks = mediaStream.getTracks() // 获取所有音轨
- tracks.forEach((track) => track.stop()) // 停止每个音轨
- console.log('麦克风已关闭')
- }
- }
- const emit = defineEmits(['on-complete'])
- onMounted(() => {
- nextTick(() => {
- iatRecorder.onWillStatusChange = (_oldStatus, status, _audioData) => {
- console.log(`status===${status}`)
- // 可以在这里进行页面中一些交互逻辑处理:倒计时(听写只有60s),录音的动画,按钮交互等
- // status: null init ing end
- if (status === 'init') {
- startRecording()
- }
- if (status === 'end') {
- console.log(text.value)
- stopRecording()
- // 转写结束 事件
- emit('on-complete', text.value)
- }
- }
- iatRecorder.onTextChange = (text) => {
- console.log(`text===${text}`)
- if (text) {
- sendMessage(text)
- }
- }
- // 开始识别
- iatRecorder.start()
- })
- })
- onUnmounted(() => {
- // 停止转写
- iatRecorder.stop()
- })
- const sendMessage = (msg) => {
- if (msg) {
- // 转写结果都会带个标点符号 移除之
- const last = msg[msg.length - 1]
- const arr = ['.', ',', '。', ',']
- if (arr.indexOf(last) !== -1) {
- msg = msg.substring(0, msg.length - 1)
- }
- }
- text.value = msg || ''
- }
- </script>
- <style lang="less" scoped>
- .ai-recording {
- display: flex;
- align-items: center;
- &-bar {
- width: 2px;
- height: 20px;
- display: inline-block;
- background-color: #3786fd;
- animation: ani 1s infinite;
- & + .ai-recording-bar {
- margin-left: 2px;
- }
- &:nth-child(6n + 1) {
- height: 2px;
- }
- &:nth-child(6n + 2) {
- height: 6px;
- }
- &:nth-child(6n + 3) {
- height: 10px;
- }
- &:nth-child(6n + 4) {
- height: 18px;
- }
- &:nth-child(6n + 5) {
- height: 10px;
- }
- &:nth-child(6n + 6) {
- height: 6px;
- }
- }
- @keyframes ani {
- 0% {
- transform: scale(1);
- }
- 50% {
- transform: scale(0.4);
- }
- 100% {
- transform: scale(1);
- }
- }
- }
- </style>
|