在現代 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-ignoresampleBits: 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"><labelhtmlFor="language-select"className="block mb-2 text-sm font-medium">選擇語言:</label><selectid="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"><buttononClick={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><buttononClick={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 應用增加更多的交互性。在實際應用中,我們可以根據需要對代碼進行擴展,例如添加更多的語言支持、優化音頻錄制的質量等。