基于阿里云微信小程序语音识别

news2024/10/6 12:21:02

页面效果
在这里插入图片描述
其中采用阿里云语音识别:阿里云一句话语音识别

语音识别页面


<template>
    <view>
        <view class="chat_list">
            <view v-for="v in chatList" :class="v.type == 'right' ? 'type_right' : 'type_left'">
                <chat :text="v.result" :type="v.type"></chat>
            </view>
        </view>
        <view :class="longPress == '1' ? 'record-layer' : 'record-layer1'">
            <view :class="longPress == '1' ? 'record-box' : 'record-box1'">
                <view class="record-btn-layer flex_row">
                    <button v-show="longPress == '1'" class="record-btn-cir" @click="isKeyWord = !isKeyWord">
                        <image v-if="!isKeyWord" :src="keyword" style=" margin-top: -8rpx;" />
                        <image v-else :src="record" style=" margin-top: -8rpx;" />
                    </button>
                    <button v-show="!isKeyWord" class="record-btn"
                        :class="longPress == '1' ? 'record-btn-1' : 'record-btn-2'"
                        :style="VoiceTitle != '松开手指,取消发送' && longPress != '1' ? 'background-image: linear-gradient(to top, #cfd9df 0%, #e2ebf0 100%);' : 'background-color: rgba(0, 0, 0, .5);color:white'"
                        @longpress="longpressBtn" @touchend="touchendBtn()" @touchmove="handleTouchMove">
                        <image :src="record" />
                        <text>{{ VoiceText }}</text>
                    </button>
                    <u--input v-if="longPress == '1' && isKeyWord" shape="circle" customStyle="u_input" clearable
                        placeholder="请输入内容..." @confirm="confirmMsg"></u--input>
                </view>
                <!-- 语音音阶动画 -->
                <view :class="VoiceTitle != '松开手指,取消发送' ? 'prompt-layer prompt-layer-1' : 'prompt-layer1 prompt-layer-1'"
                    v-if="longPress == '2'">
                    <view class="prompt-loader">
                        <view class="em" v-for="(item, index) in 15" :key="index"></view>
                    </view>
                    <text class="span">{{ VoiceTitle }}</text>
                </view>
            </view>
        </view>
    </view>
</template>

<script>
const recorderManager = uni.getRecorderManager()
const SpeechRecognition = require("../../utils/sr")
const getToken = require("../../utils/token").getToken
import keyword from '../public/images/keyword.png'
import record from '../public/images/record.png'
import chat from './com/chat.vue'
export default {
    components: { chat },
    data() {
        return {
            record,
            keyword,
            longPress: '1', // 1显示 按住 说话 2显示 说话中
            delShow: false, // 删除提示框显示隐藏
            time: 0, //录音时长
            duration: 60000, //录音最大值ms 60000/1分钟
            tempFilePath: '', //音频路径
            startPoint: {}, //记录长按录音开始点信息,用于后面计算滑动距离。
            sendLock: true, //发送锁,当为true时上锁,false时解锁发送
            VoiceTitle: '松手结束录音',
            VoiceText: '按住 说话',
            token: "",
            srStart: false,
            srResult: {},
            sr: null,
            isKeyWord: false,
            chatList: []
        }
    },
    async onLoad() {
        recorderManager.onFrameRecorded((res) => {
            if (this.sr && this.srStart) {
                if (res.frameBuffer) {
                    console.log("send " + res.frameBuffer.byteLength)
                    this.sr.sendAudio(res.frameBuffer)
                }
            }
        })
        recorderManager.onStop(async (res) => {
            if (this.sendLock) {
                //上锁不发送
            } else {//解锁发送,发送网络请求
                if (res.duration < 1000) {
                    wx.showToast({
                        title: "录音时间太短",
                        icon: "none",
                        duration: 1000
                    });
                    await this.sr.close()
                    this.srStart = false
                }
                else {
                    // this.tempFilePath = res.tempFilePath
                    await this.sr.close()
                    this.srStart = false
                    this.srResult.payload.type = 'right'
                    this.chatList.push(this.srResult.payload)
                    console.log('this.chatList.', this.chatList);
                }
            }
        })
        try {
            let token = await getToken('your akid','your akkey')
            this.token = token
        } catch (e) {
            console.log("error on get token:", JSON.stringify(e))
        }
    },
    onUnload: function () {
        this.srStart = false
        recorderManager.stop()
        if (this.sr) {
            this.sr.shutdown()
        }
    },
    methods: {
        initSt() {
            const sr = new SpeechRecognition({
                url: 'wss://nls-gateway-cn-shanghai.aliyuncs.com/ws/v1',
                appkey: 'your app key',
                token: this.token
            })
            console.warn("sr 初始化成功")
            sr.on("started", (msg) => {
                console.log("Client recv started", JSON.parse(msg))
            })

            sr.on("changed", (msg) => {
                console.log("Client recv changed:", JSON.parse(msg))
                this.srResult = JSON.parse(msg)
            })

            sr.on("completed", (msg) => {
                console.log("Client recv completed:", JSON.parse(msg))
                this.srResult = JSON.parse(msg)
            })

            sr.on("failed", (msg) => {
                console.log("Client recv failed:", JSON.parse(msg))
            })
            sr.on("closed", () => {
                console.error("sr 连接已关闭")
            })
            this.sr = sr
        },
        // 长按录音事件
        async longpressBtn(e) {
            recorderManager.start({
                duration: 600000,
                numberOfChannels: 1,
                sampleRate: 16000,
                format: "PCM",
                frameSize: 4
            })
            this.initSt()
            this.startPoint = e.touches[0];//记录长按时开始点信息,后面用于计算上划取消时手指滑动的距离。
            this.longPress = '2';
            this.VoiceText = '说话中...';
            if (!this.sr || this.srStart) {
                return
            }
            try {
                await this.sr.start(this.sr.defaultStartParams())
                this.srStart = true
            } catch (e) {
                console.log("start failed:" + e)
                return
            }

            // 监听音频开始事件
            this.sendLock = false;//长按时是不上锁的。
        },
        // 长按松开录音事件
        touchendBtn() {
            this.longPress = '1';
            this.VoiceText = '按住 说话';
            this.VoiceTitle = '松手结束录音'
            recorderManager.stop();
        },
        // 删除录音
        handleTouchMove(e) {
            //touchmove时触发
            var moveLenght = e.touches[e.touches.length - 1].clientY - this.startPoint.clientY; //移动距离
            if (Math.abs(moveLenght) > 70) {
                this.VoiceTitle = "松开手指,取消发送";
                this.VoiceText = '松开手指,取消发送';
                this.delBtn()
                this.sendLock = true;//触发了上滑取消发送,上锁
            } else {
                this.VoiceTitle = "松手结束录音";
                this.VoiceText = '松手结束录音';
                this.sendLock = false;//上划距离不足,依然可以发送,不上锁
            }
        },
        delBtn() {
            this.delShow = false;
            this.time = 0
            // this.tempFilePath = '';
            // this.VoiceTitle = '松手结束录音'
        },
    }
}
</script>

<style lang="scss">
/* 语音录制开始--------------------------------------------------------------------- */
.record-layer {
    width: 91vw;
    box-sizing: border-box;
    height: 15vw;
    position: fixed;
    margin-left: 4vw;
    z-index: 10;
    bottom: 2vh;
}

.record-layer1 {
    width: 100vw;
    box-sizing: border-box;
    height: 100vh;
    position: fixed;
    background-color: rgba(0, 0, 0, .6);
    z-index: 10;
    bottom: 0vh;
}

.record-box {
    width: 100%;
    position: relative;
}

.record-box1 {
    width: 100%;
    position: relative;
    bottom: -83vh;
    height: 17vh;
}

.record-btn-layer {
    // width: 100%;
}

.record-btn-layer button::after {
    border: none;
    transition: all 0.1s;
}

.record-btn-layer button {
    font-size: 14px;
    line-height: 40px;
    width: 100%;
    height: 40px;
    text-align: center;
    transition: all 0.1s;
}

.record-btn-layer button image {
    width: 16px;
    height: 16px;
    margin-right: 4px;
    vertical-align: middle;
    transition: all 0.3s;
}


.record-btn-layer .record-btn-2 {
    border-radius: 168rpx 168rpx 0 0;
    height: 17vh;
    line-height: 17vh;
    transition: all 0.3s;
}

/* 提示小弹窗 */
.prompt-layer {
    border-radius: 15px;
    background: #95EB6C;
    padding: 8px 16px;
    box-sizing: border-box;
    position: absolute;
    left: 50%;
    height: 11vh;
    transform: translateX(-50%);
    transition: all 0.3s;
}

.prompt-layer::after {
    content: '';
    display: block;
    border: 12px solid rgba(0, 0, 0, 0);
    border-radius: 10rpx;
    border-top-color: #95EB6C;
    position: absolute;
    bottom: -46rpx;
    left: 50%;
    transform: translateX(-50%);
    transition: all 0.3s;
}

//取消动画
.prompt-layer1 {
    border-radius: 15px;
    background: #FB5353;
    padding: 8px 16px;
    box-sizing: border-box;
    position: absolute;
    left: 50%;
    height: 11vh;
    transform: translateX(-50%);
    transition: all 0.3s;
}

.prompt-layer1::after {
    content: '';
    display: block;
    border: 12px solid rgba(0, 0, 0, 0);
    border-radius: 10rpx;
    border-top-color: #FB5353;
    position: absolute;
    bottom: -46rpx;
    left: 50%;
    transform: translateX(-50%);
    transition: all 0.3s;
}

.prompt-layer-1 {
    font-size: 12px;
    width: 150px;
    text-align: center;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    top: -400rpx;
}

.prompt-layer-1 .p {
    color: #000000;
}

.prompt-layer-1 .span {
    color: rgba(0, 0, 0, .6);
}

.prompt-loader .em {}

/* 语音音阶------------- */
.prompt-loader {
    width: 96px;
    height: 20px;
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: 6px;
}

.prompt-loader .em {
    display: block;
    background: #333333;
    width: 1px;
    height: 10%;
    margin-right: 2.5px;
    float: left;
}

.prompt-loader .em:last-child {
    margin-right: 0px;
}

.prompt-loader .em:nth-child(1) {
    animation: load 2.5s 1.4s infinite linear;
}

.prompt-loader .em:nth-child(2) {
    animation: load 2.5s 1.2s infinite linear;
}

.prompt-loader .em:nth-child(3) {
    animation: load 2.5s 1s infinite linear;
}

.prompt-loader .em:nth-child(4) {
    animation: load 2.5s 0.8s infinite linear;
}

.prompt-loader .em:nth-child(5) {
    animation: load 2.5s 0.6s infinite linear;
}

.prompt-loader .em:nth-child(6) {
    animation: load 2.5s 0.4s infinite linear;
}

.prompt-loader .em:nth-child(7) {
    animation: load 2.5s 0.2s infinite linear;
}

.prompt-loader .em:nth-child(8) {
    animation: load 2.5s 0s infinite linear;
}

.prompt-loader .em:nth-child(9) {
    animation: load 2.5s 0.2s infinite linear;
}

.prompt-loader .em:nth-child(10) {
    animation: load 2.5s 0.4s infinite linear;
}

.prompt-loader .em:nth-child(11) {
    animation: load 2.5s 0.6s infinite linear;
}

.prompt-loader .em:nth-child(12) {
    animation: load 2.5s 0.8s infinite linear;
}

.prompt-loader .em:nth-child(13) {
    animation: load 2.5s 1s infinite linear;
}

.prompt-loader .em:nth-child(14) {
    animation: load 2.5s 1.2s infinite linear;
}

.prompt-loader .em:nth-child(15) {
    animation: load 2.5s 1.4s infinite linear;
}

@keyframes load {
    0% {
        height: 10%;
    }

    50% {
        height: 100%;
    }

    100% {
        height: 10%;
    }
}

/* 语音音阶-------------------- */
.prompt-layer-2 {
    top: -40px;
}

.prompt-layer-2 .text {
    color: rgba(0, 0, 0, 1);
    font-size: 12px;
}

/* 语音录制结束---------------------------------------------------------------- */
.flex_row {
    display: flex;
    flex-direction: row;
    gap: 10rpx
}

.record-btn-cir {
    flex-basis: 100rpx;
    border-width: 0.5px !important;
    border-color: #dadbde !important;
    border-style: solid;
}

.u_input {
    border-width: 0.5px !important;
    border-color: #dadbde !important;
    border-style: solid;
}

.record-btn-layer .record-btn-1 {
    background: #fff !important;
    // background-image: linear-gradient(to right, #43e97b 0%, #38f9d7 100%);
    color: #000000 !important;
    border-width: 0.5px !important;
    border-color: #dadbde !important;
    border-style: solid;
    border-radius: 8px;
}

.chat_list {
    padding-top: 30rpx;
    max-height: 86vh;
    overflow-y: scroll;
}

.type_right {
    margin: 30rpx 0 30rpx 50%;
}

.type_left {
    margin: 30rpx 0 30rpx 30rpx;
}
</style>

聊天组件

<template>
    <view class="box">
        <view class="qpk">{{ text }}</view>
        <view :class="type == 'right' ? 'triangle_right' : 'triangle_left'"></view>
    </view>
</template>

<script>
export default {
    props: {
        text: {
            type: String,
            default: ""
        },
        type: {
            type: String,
            default: "right"
        }
    },
    data() {
        return {
        };
    },
    watch: {},
    methods: {},
};
</script>
<style lang="scss" scoped>
// 气泡框样式
.box {
    position: relative;

    .qpk {
        width: 300rpx;
        height: 100%;
        text-align: left;
        background: #43e97b !important;
        -webkit-border-radius: 10px;
        -moz-border-radius: 10px;
        border-radius: 10px;
        word-break: break-all;
        padding: 18rpx 20rpx;
        font-size: 14px;
    }

    .triangle_left {
        position: absolute;
        height: 0px;
        width: 0px;
        border-width: 8px 18px 8px 0;
        border-style: solid;
        border-color: transparent #43e97b transparent transparent;
        top: 8rpx;
        left: -26rpx;
    }

    .triangle_right {
        position: absolute;
        height: 0px;
        width: 0px;
        border-width: 8px 0px 8px 18px;
        border-style: solid;
        border-color: transparent transparent transparent #43e97b;
        top: 8rpx;
        left: 326rpx;
    }
}
</style>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/763092.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

matlab基础篇(一)

matlab对大小写敏感&#xff0c;首字母必须为字母&#xff0c;命名最长长度为63 1.计算语法 2^(3.5*1.7) 不是 e^sin(10) 而是 exp(sin(10)) ln在matlab中表示为log&#xff0c;ln10用matlab语句表示为log10π用pi表示 sinπ&#xff0c;sin2π分别表示为 sinpi(1) sinpi(2)…

修改kernel的spi驱动,cmd+addr+data时序连续以支持spiFlash的mtd设备

【背景】 新增加的spi-nvFram芯片mb85rs4mt&#xff0c;以支持mtd设备挂载&#xff0c;发现只修改jedec无法读取芯片id&#xff0c;以及mtd设备生成。 【目的】 linux系统下支持spi-nvFram芯片。 【排查】 结合datasheet的数据传输时序需求&#xff0c;用示波器查看&#xff…

SSM入门—Spring:AOP切面

目录 代理 基于XML的AOP配置 基于注解的AOP配置 代理 &#xff08;帮别人做事情&#xff09;&#xff0c;在执行真正的任务之间或者之后&#xff0c;去完成某些事情。 比如日志&#xff0c;权限验证 1、静态代理&#xff1a;手动创建代理类 2、动态代理&#xff1a;自动创…

1.计算机网络体系结构

1.1 计算机网络概述 1.1.1 计算机网络的概念 计算机网络是将一个分散的、具有独立功能的计算机系统&#xff0c;通过通信设备与线路连接起来&#xff0c;由功能完善的软件实现资源共享和信息传递的系统。 1.1.2 计算机网络的组成 &#xff08;1&#xff09;从组成部分看&#x…

PB8-RH、PB12-LH、PB5-RH单向离合器

PB3-RH、PB3-LH、PB5-RH、PB5-LH、PB6-RH、PB6-LH、PB8-RH、PB8-LH、PB10-RH、PB10-LH、PB12-RH、PB12-LH、PB14-RH、PB14-LH单向离合器、凸轮离合器、单向轴承外环为套筒可方便与小外径的链轮、齿轮、同步带轮等一同装配&#xff0c;请根据箭头方向指定内环的啮合回转方向。右…

不同的二叉搜索树(简单题目+升级题目)

简单题目&#xff08;只需要返回多少种&#xff09;&#xff1a; 给你一个整数 n &#xff0c;求恰由 n 个节点组成且节点值从 1 到 n 互不相同的 二叉搜索树 有多少种&#xff1f;返回满足题意的二叉搜索树的种数。 示例&#xff1a; 输入&#xff1a;n 3 输出&#xff1a;5…

2023年人工智能行业研究报告

第一章 行业概况 1.1 定义和分类 人工智能&#xff08;ArtificialIntelligence, AI&#xff09;是一个广泛的计算机科学分支&#xff0c;它致力于创建和应用智能机器。在更深入的层次上&#xff0c;人工智能可以被理解为以下几个方面&#xff1a; 学习和适应&#xff1a;人工…

深入篇【C++】手搓模拟实现vector类(详细剖析接口底层实现原理):【200行代码实现】

深入篇【C】手搓模拟实现vector类(详细剖析接口底层实现原理&#xff09;【200行代码实现】 【vector类模拟实现代码】Ⅰ.构造/析构1.vector()2.operator3.~string() Ⅱ.访问遍历1.operator[]2.begin()/end() Ⅲ.增操作1.push_back()2.insert() Ⅳ.删操作1.erase()2.pop_back()…

uniapp安卓签名证书生成,签名证书的SHA1,SHA256,MD5获取

uniapp安卓证书生成有两种方式&#xff0c;一种是去dcloud开发者中心生成证书&#xff0c;另一种是安装jre环境&#xff0c;自己生成证书 第一种 dcloud生成证书 去该项目对应的应用处&#xff0c;生成证书需要等几分钟&#xff0c;生成后可以查看证书信息 第二种 自己生成…

优维科技通过TMMi3级认证,软件测试能力迈上新台阶

近日&#xff0c;优维科技正式通过国际软件测试成熟度模型集成&#xff08;TMMi&#xff09;3级认证&#xff0c;标志着优维科技的软件测试能力、风险应对水平、产品质量管理水平、测试技术创新能力迈上新台阶&#xff0c;获得国际权威组织认可。 TMMi全称为Test Maturity Mode…

反向传播笔录

文章目录 反向传播概述反向传播-前向过程反向传播-反向过程反向传播概述 为了有效的计算梯度,我们使用反向传播。 链式法则: 给定一组neural network参数 θ \theta θ, 我们把一个training data

[JVM] 4. 运行时数据区(1)-- 概述

一、JVM整体结构回顾 类加载子系统将class文件的静态代码加载到内存中&#xff0c;执行引擎需要与这块内存进行交互&#xff0c;从而使用这些数据。 存放这块数据的内存被称为运行时数据区&#xff08;Runtinme Data Area&#xff09;。 一个JVM只能有一个运行时环境&#xff0…

华为机试(JAVA)真题Od【A卷+B卷】2023最新版

目录 一、机考攻略二、机考重要性三、下面&#xff0c;哪吒将华为OD机试真题归归类&#xff0c;让大家一目而了然。四、下面分享一道**“2022Q4 100分的路灯照明问题”**&#xff0c;提前体验一下华为OD机试的**“恐怖如斯”**。1、题目描述2、输入描述3、输出描述4、解题思路特…

二、DDL-2.表操作-创建查询

一、查询所有表 1、查询当前数据库所有表 首先进入数据库itheima&#xff1a; use itheima; 查看itheima数据库的所有表&#xff1a; show tables; ——该数据库是新建的&#xff0c;下面没有表 切换到sys数据库&#xff0c;查看sys下的所有表&#xff1a; 2、查询表结构、…

【FPGA】基于C5的第一个SoC工程

文章目录 前言SoC的Linux系统搭建 前言 本文是在毕业实习期间学习FPGA的SoC开发板运行全连接神经网络实例手写体的总结。 声明&#xff1a;本文仅作记录和操作指南&#xff0c;涉及到的操作会尽量细致&#xff0c;但是由于文件过大不会分享文件&#xff0c;具体软件可以自行搜…

2023年NOC决赛-加码未来编程赛项决赛模拟题-Python模拟题--卷6

第一题 题目:回文字符串是指正序(从左向右)和倒序(从右向左)读都是一样的字符串。 输入一个字符串,在只考虑字母的前提下,判断该字符串是否为回文字符串 【输入格式】输入数据只有一行,一个字符串 s 【输出格式】True 或者 False 在只考虑字母(区分大小写)的情况…

Linux5.17 Ceph应用

文章目录 计算机系统5G云计算第四章 LINUX Ceph应用一、创建 CephFS 文件系统 MDS 接口1.服务端操作2.客户端操作 二、创建 Ceph 块存储系统 RBD 接口三、创建 Ceph 对象存储系统 RGW 接口四、OSD 故障模拟与恢复 计算机系统 5G云计算 第四章 LINUX Ceph应用 一、创建 CephF…

学会快速排序库函数qsort的使用以及实现

qsort的使用使用细节一完成代码 qsort的实现&#xff08;用冒泡排序&#xff09;写法一写法二完整代码 qsort的使用 qsort函数的官方介绍: 点这里 qsort函数需要包含头文件<stdlib.h> qsort函数有四个参数&#xff0c;逐一介绍 base&#xff1a;指向数组中要排序的第一…

趁同事上厕所的时间,看完了 Dubbo SPI 的源码,瞬间觉得 JDK SPI 不香了

&#x1f44f;作者简介&#xff1a;大家好&#xff0c;我是爱敲代码的小黄&#xff0c;独角兽企业的Java开发工程师&#xff0c;CSDN博客专家&#xff0c;阿里云专家博主&#x1f4d5;系列专栏&#xff1a;Java设计模式、Spring源码系列、Netty源码系列、Kafka源码系列、JUC源码…

大数据平台测试-git常用操作(白盒测试基础)

一、前言 学习Git是非常有价值和重要的&#xff0c;无论是一个个人开发者还是在团队中进行协作开发。以下是一些学习Git的原因&#xff1a; 版本控制&#xff1a;Git是目前最流行的分布式版本控制系统&#xff0c;可以帮助你跟踪、管理和控制代码的版本。你可以轻松地回退到先…