読者です 読者をやめる 読者になる 読者になる

よいちろ日記

忘れないようにメモ。

iOSでBluetoothヘッドセット音声認識アプリを作りかけた。(Google Speech API 編)

に続いて、Google音声認識APIを利用してみる。

 

Google Speech API(Cloud & Not Cloudの2種類)を利用する。

f:id:yoichiro0903:20161203235246p:plain

これは勘違いしてて混乱したけど、Google Speech APIには2種類ある。
Speech APIGoogle Cloud Speech APIである。
※両方試したが、認識精度は素人目にはほぼ同じで高い認識率だと感じた。

Speech APIは、Chrome-devグループに参加しないとAPI検索にすら引っ掛かってこない。で、無料でつかう場合、1日50回まで(+100秒に1人100回まで)という制限がある。

一方、Google Cloud Speech APIGoogle Cloud Platform上で「API Manager > ライブラリ」で検索かければ出てくる。1日25万リクエストまで。個人利用なら余裕。

f:id:yoichiro0903:20161203235020p:plain
「Speech API Private API」ってのが、グループに入らないと使えないやつ。

 

Speech APIの使い方。

この記事を参考にグループ参加、キーの作成を行う。

上記記事から、API ManagerのUIが変わっているみたいなので、掲載。認証情報を作成から、APIキーを作成。作成後はAPIキー欄のキーがAPIに接続するときに必要になる。

f:id:yoichiro0903:20161203235319p:plain

ダッシュボードから各APIの利用状況などが見れる。

curlで試すとこんな感じ。

// soxインストール
$ brew install sox
// 音声録音
$ rec --encoding signed-integer --bits 16 --channels 1 --rate 16000 <出力ファイル名(test.wav)>
// flac形式に変換(flac形式のファイルが作られる(test.flac))
$ flac -V <変換するファイル(test.wav)>
// google speech API音声認識
$ curl -X POST \
--data-binary @'<ファイル名>' \
--header 'Content-Type: audio/x-flac; rate=16000;' \

f:id:yoichiro0903:20161203235415p:plain

アプリへの組み込みは後述。

Google Cloud Speech APIの使い方。

以下の記事を参考にAPIキーを取得するところまで行う。Speech APIGoogle Cloud Speech APIを混同して、Speech APIの導入記事を読んで、Google Cloud Speech APIの実装をするみたいな、わけわからんことしてた。しかもいろんな記事に「課金設定を有効に」と書かれていたのも「課金なんていらんだろ」てな具合で無視して進んでて、クレカ登録してなかった。これがあとでAPIを利用するために必要になることを知る。

さすがGoogleとだけあって、iOSはじめアプリへの組み込みサンプルコードが充実している。
https://cloud.google.com/speech/docs/samples?hl=ja


動作検証をアプリと同時進行していて、アプリだと戻り値が無くてうんともすんとも言わないから、原因が(アカウントの課金設定だとは)わからずATSが原因かな?とか思って、 

<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>

あたりをいじっていたけど違った。 原因解明のために、そもそもアプリのコードが問題なのか、APIが使えてないのか切り分けることに。

ここを参考にCloud SDKで動作確認。


gcloudコマンドでservice-account-key-fileを指定してアクセストークンを発行。service-account-key-fileはAPI Managerの「認証情報を作成 > サービスアカウントキー」から、「Compute Engine default service account」を選択するとjsonがダウンロードできるので、そのjsonを指定する。

すると、

[~]$ curl -s -k -H "Content-Type: application/json" -H "Authorization: Bearer <アクセストークン>"  https://speech.googleapis.com/v1beta1/speech:syncrecognize -d @sync-request.json
{
  "error": {
    "code": 403,
    "message": "Project <プロジェクト名>(#000000000) has billing disabled. Please enable it.",
    "status": "PERMISSION_DENIED",
    "details": [
      {
        "@type": "type.googleapis.com/google.rpc.Help",
        "links": [
          {
            "description": "Google developer console API key",
            "url": “<Google Cloud Platformの管理画面URLがでてくる>"
          }
        ]
      }
    ]
  }
}

billing disabled!これか!と膝を打った。

ググると、

Cloud Vision APIは、課金を有効にしないと利用できません。APIキーは発行できたので、そのまま使ってみるか、といった具合にリクエストをしても、次のエラーメッセージが含まれたJSONが返ってきます。「課金有効にしろや」というメッセージですね。

すべてを理解した。

で、クレカ登録を済ませると、できるようになったというオチ。(使い方ミスって巨額請求きたりしたら怖えとか思いながら登録したけど今のところ平気。)

 

iOSアプリでの利用方法。

動作確認だけであれば、GoogleのサンプルコードのAPIKeyを入れ替えるだけで動く。
音声認識につかうAPIの切り替えは、簡単に言うと接続先URLを変更するだけ。

 

 

コードの流れとしては、

  •  AVAudioRecorderで音声データを保存。
  • 保存した音声データをNSData形式で取り出し。
  • 音声データをbase64EncodedStringWithOptionsでエンコードして、NSDictionary形式に。
  • 音声認識時に必要な設定に関するデータもNSDictionary形式で定義。
  • 両方をリクエスト用のNSDictionaryにまとめる。
  • NSURLSessionTaskで接続先URLやら設定やら音声データやらをひとまとめに投げて、音声認識開始。
  • Blocks処理内で音声認識結果を受け取る。
- (IBAction) processAudio:(id) sender {
  [self stopAudio:sender];

  NSString *service = @"https:/speech.googleapis.com/v1beta1/speech:syncrecognize";
  service = [service stringByAppendingString:@"?key="];
  service = [service stringByAppendingString:API_KEY];

  NSData *audioData = [NSData dataWithContentsOfFile:[self soundFilePath]];
  NSDictionary *configRequest = @{@"encoding":@"LINEAR16",
                                  @"sampleRate":@(SAMPLE_RATE),
                                  @"languageCode":@"ja-JP",
                                  @"maxAlternatives":@30};
  NSDictionary *audioRequest = @{@"content":[audioData base64EncodedStringWithOptions:0]};
  NSDictionary *requestDictionary = @{@"config":configRequest,
                                      @"audio":audioRequest};
  NSError *error;
  NSData *requestData = [NSJSONSerialization dataWithJSONObject:requestDictionary
                                                        options:0
                                                          error:&error];

  NSString *path = service;
  NSURL *URL = [NSURL URLWithString:path];
  NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:URL];
  // if your API key has a bundle ID restriction, specify the bundle ID like this:
  [request addValue:[[NSBundle mainBundle] bundleIdentifier] forHTTPHeaderField:@"X-Ios-Bundle-Identifier"];
  NSString *contentType = @"application/json";
  [request addValue:contentType forHTTPHeaderField:@"Content-Type"];
  [request setHTTPBody:requestData];
  [request setHTTPMethod:@"POST"];

  NSURLSessionTask *task =
  [[NSURLSession sharedSession]
   dataTaskWithRequest:request
   completionHandler:
   ^(NSData *data, NSURLResponse *response, NSError *error) {
     dispatch_async(dispatch_get_main_queue(),
                    ^{
                      NSString *stringResult = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
                      _textView.text = stringResult;
                      NSLog(@"RESULT: %@", stringResult);
                    });
   }];
  [task resume];
}

 とまあGoogleさまのおかげでとっても簡単に音声認識を組み込んだアプリが作れそう。音声データの保存とマイク音量取得についても書く。