昨天,我們對Whisper模型進行了初步的探索和使用。今天,我們將結合這兩個部分,利用Whisper API將錄製的語音轉成文字。正如【Day - 8】所述,儘管市場上存在許多語音轉文字的技術,但Whisper以它強大的精確度而脫穎而出。讓我開始今天的挑戰吧!Let's Go!
由於Whisper API有音訊格式的限制,例如:「mp3」、「mp4」、「mpeg」、「mpga」、「m4a」、「wav」和「webm」等,因此在串接之前,我們需要確認錄音套件所生成的音訊格式是什麼。
先在停止錄音的地方使用alert()
來查看音訊的格式(mimeType):
//停止錄音
VoiceRecorder.stopRecording().then((result: RecordingData) => {
if (result.value && result.value.recordDataBase64) {
//查看音訊格式
alert(result.value.mimeType);
}
});
經過測試後,實際的音訊格式為「audio/aac」。
其實這個插件在Github的Readme中也有說明了,音訊格式會依據不同的操作平台和瀏覽器有所不同。在Android和iOS平台上,音訊格式皆為「audio/aac」。
另外,我也在網路上找到了一個Base64到Audio的轉換工具網頁,用以測試套件所產生的base64字串。透過測試,確定錄音檔是aac格式。而這個工具也提示我們,在Chrome上並不支援這種格式。
Whisper API對音訊格式有特定限制,不幸的是,aac格式並未在它的支援範圍內。儘管如此,我還是決定嘗試看看。首先,我們需要為API建立Model。Whisper API的Response相當簡單,只一個text參數。
建立一個chatgpt.model.ts
的檔案,並依照Response的格式建立WhisperResponseModel
:
export interface WhisperResponseModel {
text: string;
}
接著在voicerecording.component.ts
中建立一個EventEmitter
。我們在停止錄音的地方,觸發這個 EventEmitter
來發送事件,並將值傳送到Home主頁:
@Output() getRecordingBase64Text: EventEmitter<RecordingData> = new EventEmitter<RecordingData>();
.
.
.
//停止錄音
VoiceRecorder.stopRecording().then((result: RecordingData) => {
if (result.value && result.value.recordDataBase64) {
this.getRecordingBase64Text.emit(result);
}
});
在Home主頁的home.page.ts
中,建立了一個OnGetRecordingBase64Text()
的方法。這個方法首先將Base64字串轉換成Blob格式,然後放入FormData
中。另外,由於呼叫OpenAI API需要Token,因此在此建立了一個HTTPHeader
。
//建立Http header
private headers = new HttpHeaders({
'Authorization': 'Bearer {你的Token}'
});
constructor(private http: HttpClient) { }
OnGetRecordingBase64Text(recordingBase64Data: RecordingData) {
const recordData = recordingBase64Data.value.recordDataBase64;
const mimeType = recordingBase64Data.value.mimeType;
//將Base64字串轉為Blob
const byteCharacters = atob(recordData);
const byteNumbers = new Array(byteCharacters.length);
for (let i = 0; i < byteCharacters.length; i++) {
byteNumbers[i] = byteCharacters.charCodeAt(i);
}
const byteArray = new Uint8Array(byteNumbers);
const blob = new Blob([byteArray], { type: mimeType });
//建立FormData
const formData = new FormData();
formData.append('file', blob, 'audio.m4a');
formData.append('model', 'whisper-1');
formData.append('language', 'en');
//Whisper API
this.http.post<WhisperResponseModel>('https://api.openai.com/v1/audio/transcriptions', formData, { headers: this.headers }).subscribe(result => alert(result.text));
}
當需要使用HttpClient服務時,別忘了在專案中匯入HttpClientModule
。若專案是Standalone,則是在main.ts
檔案內加入importProvidersFrom(HttpClientModule)
或Angular 15開始可以使用的provideHttpClient()
。這樣才能順利使用HttpClient服務來進行HTTP請求:
bootstrapApplication(AppComponent, {
providers: [
{ provide: RouteReuseStrategy, useClass: IonicRouteStrategy },
importProvidersFrom(IonicModule.forRoot({})),
provideRouter(routes),
//importProvidersFrom(HttpClientModule),
//Since Angular 15
provideHttpClient(),
],
});
最後在Home頁面的home.page.html
上,將事件綁定:
<app-voicerecording (getRecordingBase64Text)="OnGetRecordingBase64Text($event)"></app-voicerecording>
測試後,得到API Response 400 Error,錯誤內容說明:「無效的檔案格式」。
不死心的我,嘗試將Base64數據保存為wav檔案,然後再將其放入Blob中。然而,由於這個過程並未涉及真正的音訊轉檔,原始音訊的格式依然是aac。結果如我所預料的,這種方法並未奏效。
果然不出意外的話就要出意外了!今天可說是充滿困難的一天,特別是與audio/aac音訊格式有關的問題,這讓我耗費了許多時間和精力。最初是希望能在JavaScript端解決音訊轉檔的問題。雖然有一些在本地可以使用的音訊轉檔JavaScript套件,但大部分都是基於Node.js建構的,而且我也沒有找到可用的音訊轉檔API。但是,這些困難也激發了我尋找新方向和創新解決方案的決心,我們將在明天,持續面對並且克服這些挑戰!
Github專案程式碼:Ionic結合ChatGPT - Day9