使用 React 实现语音识别并转换功能

news2025/5/14 16:11:25

在现代 Web 开发中,语音识别技术的应用越来越广泛。它为用户提供了更加便捷、自然的交互方式,例如语音输入、语音指令等。本文将介绍如何使用 React 实现一个简单的语音识别并转换的功能。

功能概述

我们要实现的功能是一个语音识别测试页面,用户可以选择不同的语言,录制音频,然后将录制的音频转换为文本。整个过程使用了 React 作为前端框架,RecordRTC 库用于录制音频,以及一个自定义的 CallAsr 函数用于调用语音识别服务。

注意⚠️:CallAsr 函数在博客已有相应的描述:前端 AI 开发实战:基于自定义工具类的大语言模型与语音识别调用指南_音频理解类大模型调用-CSDN博客

实现步骤

1.导入必要的模块

首先,我们需要导入 React 的钩子 useState 和 useRef,以及 RecordRTC 库和自定义的 CallAsr 函数和 AsrLanguage 枚举。

import { useState, useRef } from "react";
import { CallAsr, AsrLanguage } from "../../util/AIUtil";
import RecordRTC from "recordrtc";
  • useState 和 useRef 是 React 的钩子,useState 用于管理组件的状态,useRef 用于引用 DOM 元素或在组件重新渲染时保存值。
  • CallAsr 和 AsrLanguage 从 ../../util/AIUtil 导入(AI工具类),CallAsr 是用于调用语音识别服务的函数,AsrLanguage 是一个枚举类型,用于表示支持的语言。
  • RecordRTC 是一个用于录制音频和视频的库。

2.定义接口 

为了更好地处理语音识别服务的返回数据,我们定义了一个 AsrResponse 接口。

interface AsrResponse {
  code: number;
  msg: string;
  data?: {
    text_arr: string[];
    detail_arr?: Array<{
      text: string;
      time_from: number;
      time_end: number;
    }>;
  };
}

3.定义组件和状态管理 

我们创建了一个名为 ASRTest 的函数式组件,并使用 useState 钩子来管理组件的状态,例如是否正在录制、音频数据、识别结果等。

const ASRTest = () => {
  const [recording, setRecording] = useState<boolean>(false);
  const [audioBlob, setAudioBlob] = useState<Blob | null>(null);
  const [transcription, setTranscription] = useState<string>("");
  const [loading, setLoading] = useState<boolean>(false);
  const [selectedLanguage, setSelectedLanguage] = useState<AsrLanguage>(
    AsrLanguage.ZH_CN
  );
  const [error, setError] = useState<string | null>(null);
  const recorderRef = useRef<RecordRTC | null>(null);

  // ...
};
  • recording:表示是否正在录制音频。
  • audioBlob:存储录制的音频数据。
  • transcription:存储语音识别的结果。
  • loading:表示是否正在进行语音识别。
  • selectedLanguage:表示用户选择的语言。
  • error:存储可能出现的错误信息。
  • recorderRef:用于引用 RecordRTC 实例。

4.处理语言选择

用户可以通过下拉框选择不同的语言,我们使用 handleLanguageChange 函数来处理语言选择事件。

const handleLanguageChange = (e: React.ChangeEvent<HTMLSelectElement>) => {
  setSelectedLanguage(e.target.value as AsrLanguage);
};

5. 录制音频

用户可以点击 “开始录制” 按钮开始录制音频,点击 “停止录制” 按钮停止录制。我们使用 navigator.mediaDevices.getUserMedia 方法请求用户的麦克风权限,并使用 RecordRTC 库进行音频录制。

const startRecording = async () => {
  try {
    const stream = await navigator.mediaDevices.getUserMedia({
      audio: {
        sampleRate: 16000,
        echoCancellation: false,
        noiseSuppression: false,
        autoGainControl: false,
      },
    });

    const recorder = new RecordRTC(stream, {
      type: "audio",
      mimeType: "audio/wav",
      recorderType: RecordRTC.StereoAudioRecorder,
      numberOfAudioChannels: 1,
      desiredSampRate: 16000,
      disableLogs: true,
      // @ts-ignore
      sampleBits: 16,
      bufferSize: 16384,
    });

    recorder.startRecording();
    recorderRef.current = recorder;
    setRecording(true);
  } catch (error) {
    console.error("获取麦克风权限失败:", error);
    setError("无法访问麦克风,请确保您已授予麦克风权限。");
  }
};

const stopRecording = () => {
  if (recorderRef.current && recording) {
    recorderRef.current.stopRecording(() => {
      const blob = recorderRef.current!.getBlob();
      setAudioBlob(blob);

      // 停止并释放音频流
      const mediaStream =
        recorderRef.current!.getInternalRecorder().mediaStream;
      if (mediaStream) {
        mediaStream.getTracks().forEach((track) => track.stop());
      }

      setRecording(false);
    });
  }
};

6. 语音识别

用户可以点击 “转换” 按钮将录制的音频转换为文本。我们使用 CallAsr 函数调用语音识别服务,并根据返回结果更新识别结果或错误信息。

const handleTranscribe = async () => {
  if (!audioBlob) {
    setError("请先录制音频");
    return;
  }

  setLoading(true);
  setError(null);
  try {
    // 创建一个带有适当后缀名的文件对象
    const audioFile = new File([audioBlob], "recording.wav", {
      type: "audio/wav",
    });

    const response = await CallAsr(audioFile, selectedLanguage);
    const result: AsrResponse = await response.json();

    if (result.code === 0 && result.data) {
      setTranscription(result.data.text_arr.join(" "));
    } else {
      setError(`识别失败: ${result.msg || "未知错误"}`);
    }
  } catch (error) {
    console.error("语音识别错误:", error);
    setError(
      `识别过程中发生错误: ${
        error instanceof Error ? error.message : String(error)
      }`
    );
  } finally {
    setLoading(false);
  }
};

7. 渲染组件

最后,我们将所有的功能组合在一起,渲染出一个包含语言选择、录制按钮、音频预览、错误信息和识别结果的 UI。

return (
  <div className="container mx-auto p-4 max-w-2xl">
    <h1 className="text-2xl font-bold mb-6 text-center">ASR 语音识别测试</h1>

    <div className="mb-4">
      <label
        htmlFor="language-select"
        className="block mb-2 text-sm font-medium"
      >
        选择语言:
      </label>
      <select
        id="language-select"
        value={selectedLanguage}
        onChange={handleLanguageChange}
        className="bg-white border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5"
      >
        <option value={AsrLanguage.ZH_CN}>简体中文</option>
        <option value={AsrLanguage.YUE_CN}>粤语</option>
        <option value={AsrLanguage.EN_US}>美式英语</option>
        <option value={AsrLanguage.EN_UK}>英式英语</option>
        <option value={AsrLanguage.FR}>法语</option>
        <option value={AsrLanguage.JA}>日语</option>
        <option value={AsrLanguage.ES}>西班牙语</option>
        <option value={AsrLanguage.DE}>德语</option>
      </select>
    </div>

    <div className="flex flex-col items-center gap-4 mb-6">
      <div className="flex gap-4">
        <button
          onClick={recording ? stopRecording : startRecording}
          className={`px-6 py-2 rounded focus:outline-none focus:ring-2 ${
            recording
              ? "bg-red-500 hover:bg-red-600 text-white focus:ring-red-500"
              : "bg-blue-500 hover:bg-blue-600 text-white focus:ring-blue-500"
          }`}
        >
          {recording ? "停止录制" : "开始录制"}
        </button>

        <button
          onClick={handleTranscribe}
          disabled={!audioBlob || loading}
          className={`px-6 py-2 rounded focus:outline-none focus:ring-2 focus:ring-green-500 ${
            !audioBlob || loading
              ? "bg-gray-300 text-gray-500 cursor-not-allowed"
              : "bg-green-500 hover:bg-green-600 text-white"
          }`}
        >
          {loading ? "转换中..." : "转换"}
        </button>
      </div>

      {audioBlob && (
        <div className="w-full mt-4">
          <p className="text-sm text-gray-600 mb-2">录音预览:</p>
          <audio controls className="w-full">
            <source src={URL.createObjectURL(audioBlob)} type="audio/wav" />
            您的浏览器不支持音频标签。
          </audio>
        </div>
      )}
    </div>

    {loading && (
      <div className="text-center py-4">
        <div className="loader">转换中...</div>
      </div>
    )}

    {error && (
      <div className="mt-4 p-4 bg-red-100 text-red-700 rounded-lg">
        {error}
      </div>
    )}

    {transcription && (
      <div className="mt-6 border-t pt-4">
        <h2 className="font-semibold text-lg mb-2">识别结果:</h2>
        <div className="bg-gray-100 p-4 rounded whitespace-pre-wrap">
          {transcription}
        </div>
      </div>
    )}
  </div>
);

整体实现效果 

总结

通过以上步骤,我们成功实现了一个简单的语音识别并转换的功能。这个功能不仅可以帮助用户更方便地输入文本,还可以为 Web 应用增加更多的交互性。在实际应用中,我们可以根据需要对代码进行扩展,例如添加更多的语言支持、优化音频录制的质量等。

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

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

相关文章

[Git]ssh下用Tortoisegit每次提交都要输密码

问题描述 ssh模式下&#xff0c;用小乌龟提交代码&#xff0c;即使在git服务端存储了公钥&#xff0c;仍然要每次输入密码。 原因分析 小乌龟需要额外配置自己的密钥&#xff0c;才能免除每次输密码。 解决方案 1.配置好ssh密钥 具体方法参考我前一篇文章&#xff1a; […

如何查看项目是否支持最新 Android 16K Page Size 一文汇总

前几天刚聊过 《Google 开始正式强制 Android 适配 16 K Page Size》 之后&#xff0c;被问到最多的问题是「怎么查看项目是否支持 16K Page Size」 &#xff1f;其实有很多直接的方式&#xff0c;但是最难的是当你的项目有很多依赖时&#xff0c;怎么知道这个「不支持的动态库…

ESP32C3连接wifi

文章目录 &#x1f527; 一、ESP32-C3 连接 Wi-Fi 的基本原理&#xff08;STA 模式&#xff09;✅ 二、完整代码 注释讲解&#xff08;适配 ESP32-C3&#xff09;&#x1f4cc; 三、几个关键点解释&#x1f51a; 四、小结 &#x1f527; 一、ESP32-C3 连接 Wi-Fi 的基本原理&a…

机器学习中分类模型的常用评价指标

评价指标是针对模型性能优劣的一个定量指标。 一种评价指标只能反映模型一部分性能&#xff0c;如果选择的评价指标不合理&#xff0c;那么可能会得出错误的结论&#xff0c;故而应该针对具体的数据、模型选取不同的的评价指标。 本文将详细介绍机器学习分类任务的常用评价指…

MySQL的Docker版本,部署在ubantu系统

前言 MySQL的Docker版本&#xff0c;部署在ubantu系统&#xff0c;出现问题&#xff1a; 1.执行一个SQL&#xff0c;只有错误编码&#xff0c;没有错误提示信息&#xff0c;主要影响排查SQL运行问题&#xff1b; 2.这个问题&#xff0c;并不影响实际的MySQL运行&#xff0c;如…

Mac QT水平布局和垂直布局

首先上代码 #include "mainwindow.h" #include "ui_mainwindow.h" #include <QPushButton> #include<QVBoxLayout>//垂直布局 #include<QHBoxLayout>//水平布局头文件 MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), …

回答 | 图形数据库neo4j社区版可以应用小型企业嘛?

刚在知乎上看到了一个提问&#xff0c;挺有意思&#xff0c;于是乎&#xff0c;贴到这里再简聊一二。 转自知乎提问 当然可以&#xff0c;不过成本问题不容小觑。另外还有性能上的考量。 就在最近&#xff0c;米国国家航空航天局——NASA因为人力成本问题&#xff0c;摒弃了使…

Linux操作系统从入门到实战(二)手把手教你安装VMware17pro与CentOS 9 stream,实现Vim配置,并配置C++环境

Linux操作系统从入门到实战&#xff08;二&#xff09;手把手教你安装VMware17pro与CentOS 9.0 stream&#xff0c;实现Vim配置&#xff0c;并编译C文件 前言一、安装VMware17pro二、安装CentOS9.02.1 为什么选择CentOS9&#xff0c;与CentOS7对比2.1 官网下载CentOS9.02.2 国内…

软考架构师考试-UML图总结

考点 选择题 2-4分 案例分析0~1题和面向对象结合考察&#xff0c;前几年固定一题。近3次考试没有出现。但还是有可能考。 UML图概述 1.用例图&#xff1a;描述系统功能需求和用户&#xff08;参与者&#xff09;与系统之间的交互关系&#xff0c;聚焦于“做什么”。 2.类图&…

论文学习_Trex: Learning Execution Semantics from Micro-Traces for Binary Similarity

摘要&#xff1a;检测语义相似的函数在漏洞发现、恶意软件分析及取证等安全领域至关重要&#xff0c;但该任务面临实现差异大、跨架构、多编译优化及混淆等挑战。现有方法多依赖语法特征&#xff0c;难以捕捉函数的执行语义。对此&#xff0c;TREX 提出了一种基于迁移学习的框架…

在VirtualBox中安装虚拟机后不能全屏显示的问题及解决办法

在VirtualBox中安装Windows或Linux虚拟机后&#xff0c;将遇到启动虚拟机后&#xff0c;只能在屏幕中的一块区域里显示虚拟机桌面&#xff0c;却不能全屏显示的问题。要解决此问题&#xff0c;需要在虚拟机中安装与VirtualBox版本相对应的VBox GuestAdditons软件。 这里…

element-ui分页的使用及修改样式

1.安装 npm install element-ui -S 2.在main.js中引入,这里是全部引入&#xff0c;也可以按需引入 import ElementUI from element-ui import element-ui/lib/theme-chalk/index.css Vue.use(ElementUI) 3.使用 layout"prev, pager, next, jumper" &#xff1a;jumpe…

从数据中台到数据飞轮:数字化转型的演进之路

从数据中台到数据飞轮&#xff1a;数字化转型的演进之路 数据中台 数据中台是企业为整合内部和外部数据资源而构建的中介层&#xff0c;实现数据的统一管理、共享和高效利用&#xff0c;目标是打破信息孤岛&#xff0c;提高数据使用效率&#xff0c;支持业务决策和创新 实施成本…

2025年5月-信息系统项目管理师高级-软考高项一般计算题

决策树和期望货币值 加权算法 自制和外购分析 沟通渠道 三点估算PERT 当其他条件一样时&#xff0c;npv越大越好

zst-2001 上午题-历年真题 算法(5个内容)

回溯 算法 - 第1题 找合适的位置&#xff0c;如果没有位置就按B回家 d 分治 算法 - 第2题 b 算法 - 第3题 a 算法 - 第4题 划分一般就是分治 a 算法 - 第5题 分治 a 0-1背包 算法 - 第6题 c 算法 - 第7题 最小的为c 3100 c 算法 - 第8题 …

udp多点通信和心跳包

刷题 # UDP多点通信核心要点## 基础通信模式### 单播通信- 一对一通信方式- UDP默认通信模式- 地址指向具体目标主机### 广播通信- 一对多通信机制- 地址范围&#xff1a;xxx.xxx.xxx.255- 仅限局域网传输- 需设置SO_BROADCAST标志### 组播通信- 多对多群组通信- 地址范围&…

音视频学习:使用NDK编译FFmpeg动态库

1. 环境 1.1 基础配置 NDK 22b (r22b)FFmpeg 4.4Ubuntu 22.04 1.2 下载ffmpeg 官网提供了 .tar.xz 包&#xff0c;可以直接下载解压&#xff1a; wget https://ffmpeg.org/releases/ffmpeg-4.4.tar.xz tar -xvf ffmpeg-4.4.tar.xz cd ffmpeg-4.41.3 安装基础工具链 sudo …

如何使用 Qwen3 实现 Agentic RAG?

今天&#xff0c;我们将学习如何部署由阿里巴巴最新Qwen 3驱动的Agentic RAG。 这里是我们的工具栈&#xff1a; CrewAI用于代理编排。 Firecrawl用于网络搜索。 LightningAI的LitServe用于部署。 顶部的视频展示了这一过程。 图表显示了我们的Agentic RAG流程&#xff1…

相机、雷达标定工具,以及雷达自动标定的思路

本篇我们来看一下自动驾驶传感器配置一个非常重要的模块&#xff0c;也就是传感器的标定。这里主要是对我之前修改的功能包的使用进行一个介绍. 对应的资源也已经上传了&#xff0c;0积分下载 安装 首先整个项目是使用ros1来进行启动的,但是要想正常编译,需要先安装三个对应的…

vsomeip环境搭建保姆级教程

vsomeip环境搭建保姆级教程 ubuntu环境搭建 {% links %} site: VMware搭建ubuntu保姆级教程 url: https://zhuanlan.zhihu.com/p/1903219373906327339 desc: flechazo image: https://q1.qlogo.cn/g?b=qq&nk=2861099&s=5 color: “#9d5b8b” {% endlinks %} vsomei…