React實(shí)現(xiàn)語(yǔ)音識(shí)別并轉(zhuǎn)換功能
在現(xiàn)代 Web 開(kāi)發(fā)中,語(yǔ)音識(shí)別技術(shù)的應(yīng)用越來(lái)越廣泛。它為用戶提供了更加便捷、自然的交互方式,例如語(yǔ)音輸入、語(yǔ)音指令等。本文將介紹如何使用 React 實(shí)現(xiàn)一個(gè)簡(jiǎn)單的語(yǔ)音識(shí)別并轉(zhuǎn)換的功能。
功能概述
我們要實(shí)現(xiàn)的功能是一個(gè)語(yǔ)音識(shí)別測(cè)試頁(yè)面,用戶可以選擇不同的語(yǔ)言,錄制音頻,然后將錄制的音頻轉(zhuǎn)換為文本。整個(gè)過(guò)程使用了 React 作為前端框架,RecordRTC 庫(kù)用于錄制音頻,以及一個(gè)自定義的 CallAsr 函數(shù)用于調(diào)用語(yǔ)音識(shí)別服務(wù)。
注意:CallAsr
函數(shù)在文末有相應(yīng)的知識(shí)補(bǔ)充
實(shí)現(xiàn)步驟
1.導(dǎo)入必要的模塊
首先,我們需要導(dǎo)入 React 的鉤子 useState 和 useRef,以及 RecordRTC 庫(kù)和自定義的 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 元素或在組件重新渲染時(shí)保存值。
CallAsr 和 AsrLanguage 從 ../../util/AIUtil 導(dǎo)入(AI工具類),CallAsr 是用于調(diào)用語(yǔ)音識(shí)別服務(wù)的函數(shù),AsrLanguage 是一個(gè)枚舉類型,用于表示支持的語(yǔ)言。
RecordRTC 是一個(gè)用于錄制音頻和視頻的庫(kù)。
2.定義接口
為了更好地處理語(yǔ)音識(shí)別服務(wù)的返回?cái)?shù)據(jù),我們定義了一個(gè) 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)建了一個(gè)名為 ASRTest 的函數(shù)式組件,并使用 useState 鉤子來(lái)管理組件的狀態(tài),例如是否正在錄制、音頻數(shù)據(jù)、識(shí)別結(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:存儲(chǔ)錄制的音頻數(shù)據(jù)。
- transcription:存儲(chǔ)語(yǔ)音識(shí)別的結(jié)果。
- loading:表示是否正在進(jìn)行語(yǔ)音識(shí)別。
- selectedLanguage:表示用戶選擇的語(yǔ)言。
- error:存儲(chǔ)可能出現(xiàn)的錯(cuò)誤信息。
- recorderRef:用于引用 RecordRTC 實(shí)例。
4.處理語(yǔ)言選擇
用戶可以通過(guò)下拉框選擇不同的語(yǔ)言,我們使用 handleLanguageChange 函數(shù)來(lái)處理語(yǔ)言選擇事件。
const handleLanguageChange = (e: React.ChangeEvent<HTMLSelectElement>) => { setSelectedLanguage(e.target.value as AsrLanguage); };
5. 錄制音頻
用戶可以點(diǎn)擊 “開(kāi)始錄制” 按鈕開(kāi)始錄制音頻,點(diǎn)擊 “停止錄制” 按鈕停止錄制。我們使用 navigator.mediaDevices.getUserMedia 方法請(qǐng)求用戶的麥克風(fēng)權(quán)限,并使用 RecordRTC 庫(kù)進(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("無(wú)法訪問(wèn)麥克風(fēng),請(qǐ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. 語(yǔ)音識(shí)別
用戶可以點(diǎn)擊 “轉(zhuǎn)換” 按鈕將錄制的音頻轉(zhuǎn)換為文本。我們使用 CallAsr 函數(shù)調(diào)用語(yǔ)音識(shí)別服務(wù),并根據(jù)返回結(jié)果更新識(shí)別結(jié)果或錯(cuò)誤信息。
const handleTranscribe = async () => { if (!audioBlob) { setError("請(qǐng)先錄制音頻"); return; } setLoading(true); setError(null); try { // 創(chuàng)建一個(gè)帶有適當(dāng)后綴名的文件對(duì)象 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(`識(shí)別失敗: ${result.msg || "未知錯(cuò)誤"}`); } } catch (error) { console.error("語(yǔ)音識(shí)別錯(cuò)誤:", error); setError( `識(shí)別過(guò)程中發(fā)生錯(cuò)誤: ${ error instanceof Error ? error.message : String(error) }` ); } finally { setLoading(false); } };
7. 渲染組件
最后,我們將所有的功能組合在一起,渲染出一個(gè)包含語(yǔ)言選擇、錄制按鈕、音頻預(yù)覽、錯(cuò)誤信息和識(shí)別結(jié)果的 UI。
return ( <div className="container mx-auto p-4 max-w-2xl"> <h1 className="text-2xl font-bold mb-6 text-center">ASR 語(yǔ)音識(shí)別測(cè)試</h1> <div className="mb-4"> <label htmlFor="language-select" className="block mb-2 text-sm font-medium" > 選擇語(yǔ)言: </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}>簡(jiǎn)體中文</option> <option value={AsrLanguage.YUE_CN}>粵語(yǔ)</option> <option value={AsrLanguage.EN_US}>美式英語(yǔ)</option> <option value={AsrLanguage.EN_UK}>英式英語(yǔ)</option> <option value={AsrLanguage.FR}>法語(yǔ)</option> <option value={AsrLanguage.JA}>日語(yǔ)</option> <option value={AsrLanguage.ES}>西班牙語(yǔ)</option> <option value={AsrLanguage.DE}>德語(yǔ)</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 ? "停止錄制" : "開(kāi)始錄制"} </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">識(shí)別結(jié)果:</h2> <div className="bg-gray-100 p-4 rounded whitespace-pre-wrap"> {transcription} </div> </div> )} </div> );
整體實(shí)現(xiàn)效果
總結(jié)
通過(guò)以上步驟,我們成功實(shí)現(xiàn)了一個(gè)簡(jiǎn)單的語(yǔ)音識(shí)別并轉(zhuǎn)換的功能。這個(gè)功能不僅可以幫助用戶更方便地輸入文本,還可以為 Web 應(yīng)用增加更多的交互性。在實(shí)際應(yīng)用中,我們可以根據(jù)需要對(duì)代碼進(jìn)行擴(kuò)展,例如添加更多的語(yǔ)言支持、優(yōu)化音頻錄制的質(zhì)量等。
知識(shí)補(bǔ)充
語(yǔ)音識(shí)別調(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ù)接收音頻文件和識(shí)別語(yǔ)言(默認(rèn)為簡(jiǎn)體中文),通過(guò)FormData
封裝文件和請(qǐng)求參數(shù),使用fetch
向語(yǔ)音識(shí)別 API 發(fā)起請(qǐng)求,將音頻轉(zhuǎn)換為文字信息。
到此這篇關(guān)于React實(shí)現(xiàn)語(yǔ)音識(shí)別并轉(zhuǎn)換功能的文章就介紹到這了,更多相關(guān)React語(yǔ)音識(shí)別并轉(zhuǎn)換內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
解決React報(bào)錯(cuò)Cannot assign to 'current'
這篇文章主要為大家介紹了React報(bào)錯(cuò)Cannot assign to 'current' because it is a read-only property的解決方法,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-12-12React?中使用?RxJS?優(yōu)化數(shù)據(jù)流的處理方案
這篇文章主要為大家介紹了React?中使用?RxJS?優(yōu)化數(shù)據(jù)流的處理方案示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-02-02react-router-dom 嵌套路由的實(shí)現(xiàn)
這篇文章主要介紹了react-router-dom 嵌套路由的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-05-05React-redux?中useSelector使用源碼分析
在一個(gè) action 被分發(fā)(dispatch) 后,useSelector() 默認(rèn)對(duì) select 函數(shù)的返回值進(jìn)行引用比較 ===,并且僅在返回值改變時(shí)觸發(fā)重渲染,,這篇文章主要介紹了React-redux?中useSelector使用,需要的朋友可以參考下2023-10-10