React實現(xiàn)語音識別并轉(zhuǎn)換功能
在現(xiàn)代 Web 開發(fā)中,語音識別技術(shù)的應(yīng)用越來越廣泛。它為用戶提供了更加便捷、自然的交互方式,例如語音輸入、語音指令等。本文將介紹如何使用 React 實現(xiàn)一個簡單的語音識別并轉(zhuǎn)換的功能。
功能概述
我們要實現(xiàn)的功能是一個語音識別測試頁面,用戶可以選擇不同的語言,錄制音頻,然后將錄制的音頻轉(zhuǎn)換為文本。整個過程使用了 React 作為前端框架,RecordRTC 庫用于錄制音頻,以及一個自定義的 CallAsr 函數(shù)用于調(diào)用語音識別服務(wù)。
注意:CallAsr 函數(shù)在文末有相應(yīng)的知識補充
實現(xiàn)步驟
1.導(dǎo)入必要的模塊
首先,我們需要導(dǎo)入 React 的鉤子 useState 和 useRef,以及 RecordRTC 庫和自定義的 CallAsr 函數(shù)和 AsrLanguage 枚舉。
import { useState, useRef } from "react";
import { CallAsr, AsrLanguage } from "../../util/AIUtil";
import RecordRTC from "recordrtc";
useState 和 useRef 是 React 的鉤子,useState 用于管理組件的狀態(tài),useRef 用于引用 DOM 元素或在組件重新渲染時保存值。
CallAsr 和 AsrLanguage 從 ../../util/AIUtil 導(dǎo)入(AI工具類),CallAsr 是用于調(diào)用語音識別服務(wù)的函數(shù),AsrLanguage 是一個枚舉類型,用于表示支持的語言。
RecordRTC 是一個用于錄制音頻和視頻的庫。
2.定義接口
為了更好地處理語音識別服務(wù)的返回數(shù)據(jù),我們定義了一個 AsrResponse 接口。
interface AsrResponse {
code: number;
msg: string;
data?: {
text_arr: string[];
detail_arr?: Array<{
text: string;
time_from: number;
time_end: number;
}>;
};
}
3.定義組件和狀態(tài)管理
我們創(chuàng)建了一個名為 ASRTest 的函數(shù)式組件,并使用 useState 鉤子來管理組件的狀態(tài),例如是否正在錄制、音頻數(shù)據(jù)、識別結(jié)果等。
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:存儲錄制的音頻數(shù)據(jù)。
- transcription:存儲語音識別的結(jié)果。
- loading:表示是否正在進(jìn)行語音識別。
- selectedLanguage:表示用戶選擇的語言。
- error:存儲可能出現(xiàn)的錯誤信息。
- recorderRef:用于引用 RecordRTC 實例。
4.處理語言選擇
用戶可以通過下拉框選擇不同的語言,我們使用 handleLanguageChange 函數(shù)來處理語言選擇事件。
const handleLanguageChange = (e: React.ChangeEvent<HTMLSelectElement>) => {
setSelectedLanguage(e.target.value as AsrLanguage);
};
5. 錄制音頻
用戶可以點擊 “開始錄制” 按鈕開始錄制音頻,點擊 “停止錄制” 按鈕停止錄制。我們使用 navigator.mediaDevices.getUserMedia 方法請求用戶的麥克風(fēng)權(quán)限,并使用 RecordRTC 庫進(jìn)行音頻錄制。
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("獲取麥克風(fēng)權(quán)限失敗:", error);
setError("無法訪問麥克風(fēng),請確保您已授予麥克風(fēng)權(quán)限。");
}
};
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. 語音識別
用戶可以點擊 “轉(zhuǎn)換” 按鈕將錄制的音頻轉(zhuǎn)換為文本。我們使用 CallAsr 函數(shù)調(diào)用語音識別服務(wù),并根據(jù)返回結(jié)果更新識別結(jié)果或錯誤信息。
const handleTranscribe = async () => {
if (!audioBlob) {
setError("請先錄制音頻");
return;
}
setLoading(true);
setError(null);
try {
// 創(chuàng)建一個帶有適當(dāng)后綴名的文件對象
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(
`識別過程中發(fā)生錯誤: ${
error instanceof Error ? error.message : String(error)
}`
);
} finally {
setLoading(false);
}
};7. 渲染組件
最后,我們將所有的功能組合在一起,渲染出一個包含語言選擇、錄制按鈕、音頻預(yù)覽、錯誤信息和識別結(jié)果的 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 ? "轉(zhuǎn)換中..." : "轉(zhuǎn)換"}
</button>
</div>
{audioBlob && (
<div className="w-full mt-4">
<p className="text-sm text-gray-600 mb-2">錄音預(yù)覽:</p>
<audio controls className="w-full">
<source src={URL.createObjectURL(audioBlob)} type="audio/wav" />
您的瀏覽器不支持音頻標(biāo)簽。
</audio>
</div>
)}
</div>
{loading && (
<div className="text-center py-4">
<div className="loader">轉(zhuǎn)換中...</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">識別結(jié)果:</h2>
<div className="bg-gray-100 p-4 rounded whitespace-pre-wrap">
{transcription}
</div>
</div>
)}
</div>
);整體實現(xiàn)效果


總結(jié)
通過以上步驟,我們成功實現(xiàn)了一個簡單的語音識別并轉(zhuǎn)換的功能。這個功能不僅可以幫助用戶更方便地輸入文本,還可以為 Web 應(yīng)用增加更多的交互性。在實際應(yīng)用中,我們可以根據(jù)需要對代碼進(jìn)行擴(kuò)展,例如添加更多的語言支持、優(yōu)化音頻錄制的質(zhì)量等。
知識補充
語音識別調(diào)用函數(shù)
export function CallAsr(file: File, language: AsrLanguage = AsrLanguage.ZH_CN) {
const formData = new FormData();
formData.append("audio_file", file);
// 添加認(rèn)證和配置參數(shù)
return fetch(ASR_BASE_URL, {
method: "POST",
body: formData,
});
}CallAsr函數(shù)接收音頻文件和識別語言(默認(rèn)為簡體中文),通過FormData封裝文件和請求參數(shù),使用fetch向語音識別 API 發(fā)起請求,將音頻轉(zhuǎn)換為文字信息。
到此這篇關(guān)于React實現(xiàn)語音識別并轉(zhuǎn)換功能的文章就介紹到這了,更多相關(guān)React語音識別并轉(zhuǎn)換內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
解決React報錯Cannot assign to 'current'
這篇文章主要為大家介紹了React報錯Cannot assign to 'current' because it is a read-only property的解決方法,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-12-12
React?中使用?RxJS?優(yōu)化數(shù)據(jù)流的處理方案
這篇文章主要為大家介紹了React?中使用?RxJS?優(yōu)化數(shù)據(jù)流的處理方案示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-02-02
react-router-dom 嵌套路由的實現(xiàn)
這篇文章主要介紹了react-router-dom 嵌套路由的實現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-05-05
React-redux?中useSelector使用源碼分析
在一個 action 被分發(fā)(dispatch) 后,useSelector() 默認(rèn)對 select 函數(shù)的返回值進(jìn)行引用比較 ===,并且僅在返回值改變時觸發(fā)重渲染,,這篇文章主要介紹了React-redux?中useSelector使用,需要的朋友可以參考下2023-10-10

