Whisper APIを使って既存の音声録音iOSアプリに音声認識機能を追加する


## はじめに
最近の技術進歩により、音声認識技術はますます普及しています。[Whisper API](https://openai.com/blog/introducing-chatgpt-and-whisper-apis)は、高い精度とリアルタイム性を誇る音声認識サービスです。この記事では、既存の音声録音iOSアプリにWhisper APIを組み込んで音声認識機能を追加する方法を紹介します。

## 目次
1. [Whisper APIの概要](#1-whisper-apiの概要)
2. [必要なツールとライブラリ](#2-必要なツールとライブラリ)
3. [音声録音アプリの準備](#3-音声録音アプリの準備)
4. [Whisper APIの実装](#4-whisper-apiの実装)
5. [音声認識結果の表示](#5-音声認識結果の表示)
6. [まとめ](#6-まとめ)

## 1. Whisper APIの概要

### 1.1 Whisper APIとは？

Whisper APIは、OpenAIが開発した音声認識APIです。ディープラーニング技術に基づいており、高い精度とリアルタイム性を提供することが特徴です。Whisper APIは、様々な言語やアクセントに対応しており、幅広い用途で音声認識を利用することができます。

### 1.2 どのような機能があるのか？

Whisper APIは、以下のような主要な機能を提供しています。

1. **リアルタイム音声認識**: 音声データをリアルタイムでテキストに変換することができます。これにより、通話や会議の字幕生成など、リアルタイムでの音声認識が求められるシーンで活用できます。

2. **音声データの後処理**: 既に録音された音声データをテキストに変換することができます。これにより、録音された講義や会議の議事録作成などが容易になります。

3. **多言語対応**: Whisper APIは、多くの言語とアクセントに対応しています。これにより、グローバルな環境での音声認識ニーズに対応することができます。

4. **高い認識精度**: Whisper APIは、ディープラーニング技術を活用し、高い認識精度を実現しています。これにより、誤認識による手間やストレスを軽減できます。


## 2. 必要なツールとライブラリ
- Xcode
- [Open AIのAPIキー](https://platform.openai.com/account/api-keys)

## 3. 音声録音アプリの準備

### 3.1 既存の音声録音アプリの概要
今まで私が作っていた音声録音アプリには以下のような機能がついていました。
- 録音の開始・停止ボタン: 音声録音を開始し、再度タップすることで録音を停止します。
- 録音済み音声の再生ボタン: 録音した音声を再生します。
- 録音ファイルの一覧表示: これまでに録音された音声ファイルを一覧で表示します。
- 録音ファイルにコメントをつける: これまで録音されたファイル1つ1つにコメントやチャプターをつけてコミュニケーションをとることが可能です。

### 3.2 音声録音アプリの改良ポイント

しかし、既存の音声録音アプリでは、忙しい中で長時間の音声に関しては全ては聞ききれないという課題がありました。
そこで、そこで土日二日間を使い社内ハッカソンのような形で、以下の改良を行ってWhisper APIを組み込み、音声文字起こし機能を追加しました。

1. **音声データの送信**: 録音された音声データをWhisper APIに送信する機能を追加します。
2. **音声認識結果の受信**: Whisper APIからの音声認識結果を受け取る機能を追加します。
3. **音声認識結果の表示**: 音声認識結果をアプリ上で表示する機能を追加します。リアルタイムでの更新も可能にします。

これらの改良を行うことで、既存の音声録音アプリに音声認識機能が追加され、録音した音声をテキスト化することができるようになります。


## 4. Whisper APIの実装

このセクションでは、Whisper APIを使用して音声をテキストに変換する`whisper.swift`ファイルの実装について説明します。

Open AIをSwiftで使いやすくする、[OpenAISwift](https://github.com/adamrushy/OpenAISwift)というライブラリも存在しましたが、こちらではWhisperの対応がなかったため、エンドポイントをURLSessionを使って実行するという方針で実装しました。


### 4.1 音声データの送信と受信

```ruby:whisper.swift
func transcribeAudio(urlString: String, postId: String) -> String? {
    // Replace with your API key
    let env = ProcessInfo.processInfo.environment
    guard let openAI_API_Key = env["OPENAPIKEY"] else {
        print("環境変数にOpenAI API Keyを設定してください")
        return nil
    }

    let url = URL(string: "https://api.openai.com/v1/audio/transcriptions")!
    var request = URLRequest(url: url)
    request.httpMethod = "POST"
    request.setValue("Bearer \(openAI_API_Key)", forHTTPHeaderField: "Authorization")
    request.setValue("multipart/form-data; boundary=boundary", forHTTPHeaderField: "Content-Type")

    let downloadSemaphore = DispatchSemaphore(value: 0)
    var audioData = Data()

    URLSession.shared.dataTask(with: URL(string: urlString)!) { data, _, error in
        if let error = error {
            print("Error downloading audio file: \(error.localizedDescription)")
            downloadSemaphore.signal()
        } else if let data = data {
            audioData = data
            downloadSemaphore.signal()
        }
    }.resume()

    downloadSemaphore.wait()


    let body = NSMutableData()
    
    body.append("--boundary\r\n".data(using: .utf8)!)
    body.append("Content-Disposition: form-data; name=\"model\"\r\n\r\n".data(using: .utf8)!)
    body.append("whisper-1\r\n".data(using: .utf8)!)
    
    body.append("--boundary\r\n".data(using: .utf8)!)
    body.append("Content-Disposition: form-data; name=\"file\"; filename=\"openai.mp3\"\r\n".data(using: .utf8)!)
    body.append("Content-Type: audio/mpeg\r\n\r\n".data(using: .utf8)!)
    body.append(audioData)
    body.append("\r\n".data(using: .utf8)!)
    body.append("--boundary--\r\n".data(using: .utf8)!)
    
    request.httpBody = body as Data
    
    let semaphore = DispatchSemaphore(value: 0)
    var resultString: String?
    
    let task = URLSession.shared.dataTask(with: request) { data, response, error in
        if let error = error {
            print("Error: \(error.localizedDescription)")
        } else if let data = data {
            print("Response: \(String(data: data, encoding: .utf8) ?? "Unable to decode response")")
            let dataString = String(data: data, encoding: .utf8)
            if let dataString = dataString {
                resultString = extractTextFromJson(jsonString: dataString)
            }
        }
        semaphore.signal()
    }
    
    task.resume()
    semaphore.wait()
    return resultString
}
```

`transcribeAudio(urlString: String, postId: String) -> String?`関数は、音声ファイルのURLと投稿IDを引数に取り、音声データをWhisper APIに送信して音声認識を実行します。この関数は、認識結果を文字列として返します。

実際のコードの流れとしては以下のようになっています。
1. OpenAI APIキーを環境変数から取得し、リクエストヘッダに追加します。
2. 音声データ(https://xxxxooo.mp3のようなもの)をダウンロードし、`audioData`変数に保存します。
3. リクエストボディを構築し、`model`と音声データを含めます。
4. APIリクエストを実行し、結果をJSON形式で受け取ります。
5. JSONデータから音声認識結果のテキストを抽出します。

### 4.2 投稿の文字起こしの更新

```firestore.swift
import Firebase

func updatePostTranscription(_ postId: String, _ transcription: String, completion: @escaping (Bool) -> ()) {
    
    Firestore.firestore()collection("posts").document("\(postId)").updateData([
        "transcription": transcription,
    ]) { err in
        if let err = err {
            print("Error update documet: \(err)")
            completion(false)
        }
        else {
            print("Document successfully update")
            completion(true)
        }
    }
}

```


`updatePostTranscription(_ postId: String, _ transcription: String, completion: @escaping (Bool) -> ())`関数は、投稿IDと音声認識結果の文字起こしを引数に取り、データベースに保存されている対応する投稿の文字起こしを更新します。

実際のコードの流れとしては以下のようになっています。
1. Firestoreデータベースの対象の投稿を特定し、`transcription`コレクションを更新します。

## 5. まとめ

この記事では、既存の音声録音アプリにWhisper APIを組み込み、音声認識機能を追加する方法を紹介しました。このセクションでは、この方法の利点、他の音声認識APIとの比較、および今後の展望について説明します。

### 5.1 この記事で紹介した方法の利点

1. **高い認識精度**: Whisper APIはディープラーニング技術を活用しており、高い認識精度を実現しています。これにより、誤認識による手間やストレスを軽減できます。
2. **リアルタイム性**: Whisper APIはリアルタイムで音声認識が可能であり、アプリのユーザーエクスペリエンスを向上させます。
3. **多言語対応**: Whisper APIは多くの言語とアクセントに対応しており、国際化された環境でも利用できます。

### 5.2 他の音声認識APIとの比較

他の音声認識API（例：Google Cloud Speech-to-Text、IBM Watson Speech to Textなど）と比較して、Whisper APIは以下の点で優れています。

1. **精度**: Whisper APIは、ディープラーニング技術を活用して高い認識精度を実現しています。
2. **リアルタイム性**: Whisper APIはリアルタイムでの音声認識に対応しており、他のAPIよりも高速に結果を返すことができます。
3. **柔軟性**: Whisper APIは、幅広い言語とアクセントに対応しており、多様なニーズに適応できます。

### 5.3 今後の展望

今回、Whiper APIを使って文字起こしをするところまで実装しましたが、今後は同じOpen AI社のAPIで公開されているGPT-4などを使い、音声 -> 文字起こし　-> 要約というところまで一括でアプリ上で動作をさせるようにしたいと考えています。


この記事で、Whisper APIを使って既存の音声録音iOSアプリに音声認識機能を追加する方法を紹介しました。これにより、アプリの利便性が向上し、音声認識を利用した新たなアイデアや機能を実現することができます。是非、Whisper APIを試してみてください。