GoogleのSpeechToTextAPIとnode.jsを使って音声をワンコマンドでテキスト化してみた

メモ用です。

## 概要
1. GoogleCloudPlatform(GCP)を使ったプロジェクト、パケット、データオブジェクトの作成方法並びに認証設定を解説します。

2. その後npmパッケージのgoogle-cloud/speechを使ってGCPConsoleにアクセスするために必要なアクセスキーなどの情報が書かれたjsonファイルをダウンロードする手順や環境変数のセットアップを行います。

3. 必要な音声ファイルをFLAC形式に変換する方法、並びにmp4, m4a, FLAC, waveなどの音声フォーマット・エンコーディングについてちょびっと解説します。

4. jsプログラムを記載しますので、node.jsで実行するところをお見せします。

### 手順１
https://console.cloud.google.com/
GoogleCloudPlatformにアクセスして,Cloud Speech APIを有効化します。

以下の手順です。
<img width="409" alt="スクリーンショット 2018-12-28 16.46.53.png" src="https://qiita-image-store.s3.amazonaws.com/0/252596/d4e6be1e-d6bc-bbae-ab6a-7d495f681547.png">

<img width="757" alt="スクリーンショット 2018-12-28 16.47.09.png" src="https://qiita-image-store.s3.amazonaws.com/0/252596/a35575df-c25e-84f8-9afe-911673dfe6b1.png">

APIとサービスの有効化をクリック

<img width="815" alt="スクリーンショット 2018-12-28 16.47.32.png" src="https://qiita-image-store.s3.amazonaws.com/0/252596/2823e9bf-6c3b-b977-5ab6-e3f81ec26e5f.png">

Cloud Speechと検索すると上のような画面になるので、Cloud Speech APIをクリック

<img width="623" alt="スクリーンショット 2018-12-28 16.47.42.png" src="https://qiita-image-store.s3.amazonaws.com/0/252596/7e1114ac-3f1f-c999-2590-be79d8f53222.png">

上の画面では青いボタンが「管理」と書かれていますが、APIが有効化されていなければ「APIを有効化する」と書かれてるのでそれをクリックして有効化します。

次にprojectを作成してください。

Projectが作成できたら、
GCP用のコマンド（SDK）または各プログラミング言語からライブラリを使ってgoogleのconsoleにアクセスしてAPIなどを利用できるようにするために、シークレットアクセスきーなるものが必要です。

左のサイドメニューからAPIとサービスをクリックして認証情報に行ってください。

<img width="180"　height="50" alt="スクリーンショット 2018-12-28 13.38.56.png" src="https://qiita-image-store.s3.amazonaws.com/0/252596/08b8cd66-f2c9-ef63-16c4-633fab400bac.png">


するとこんなページが出るので、青色ボタンの「認証情報の作成」をクリックし、
<img width="300" alt="スクリーンショット 2018-12-28 13.39.30.png" src="https://qiita-image-store.s3.amazonaws.com/0/252596/b7e19dc1-1a1c-f851-e6f0-f8713695942d.png">

サービスアカウントキーをクリックします。

<img width="493" alt="スクリーンショット 2018-12-28 13.42.10.png" src="https://qiita-image-store.s3.amazonaws.com/0/252596/c758f2d6-1056-2712-909d-14dce80e95e0.png">


キーのタイプはjsonにして作成します。
サービスアカウント(IAM)を作るのですが、好きな名前をサービスアカウント名に設定して役割はProjectのオーナーに設定します。


作成を押すとファイルがダウンロードされるので
<b>demoフォルダにserviceaccount.jsonで保存します。<b>

#### ファイルツリー
demo
　serviceaccount.json

## 手順２
続いて、作成したプロジェクトにおいて音声ファイルなどのデータを保存するStorageサービスを使うのですが、フォルダ的な意味合いでパケットと呼ばれるものを使います。

下のような感じで

<img width="432" alt="スクリーンショット 2018-12-28 13.47.25.png" src="https://qiita-image-store.s3.amazonaws.com/0/252596/2df013e5-f379-7606-a087-3cbc2f206ad1.png">

パケットを作成します。
<img width="451" alt="スクリーンショット 2018-12-28 14.03.41.png" src="https://qiita-image-store.s3.amazonaws.com/0/252596/9f4b3c69-af53-7202-71f7-ddb73dd15662.png">


名前を適当に入れて場所をアジアにします。
<img width="542" alt="スクリーンショット 2018-12-28 14.04.21.png" src="https://qiita-image-store.s3.amazonaws.com/0/252596/ba80aec3-9be6-55c8-997e-a40fa4bcd9c5.png">


そして作成を押すと


<img width="938" alt="スクリーンショット 2018-12-28 14.05.37.png" src="https://qiita-image-store.s3.amazonaws.com/0/252596/d2fe492b-0a69-268e-d929-2a940ad48dc5.png">
みたいな画面になりますので、

ここに文字起こししたい音声ファイルを入れていくのですが、ここで課題が発生します。

### 手順３

このSpeechToTextAPIが文字起こしできる音声ファイルのエンコーディング形式やチャンネル数は決まっているので、その形式に沿ったファイルに変換できるサイトを使います。

以下のサイトを使います。
https://online-audio-converter.com/

<img width="780" alt="スクリーンショット 2018-12-28 14.08.04.png" src="https://qiita-image-store.s3.amazonaws.com/0/252596/69b9e656-41a9-1cf8-975f-69ebf150d534.png">

## 音声用語の解説
音声ファイルの圧縮形式には可逆形式と不可逆形式があり、圧縮した後に元のファイルに戻せるか否かの違いがあります。

よくあるMP３などは人間が聞き取れない周波数の高い音を中心に取り除くことで軽量化を図るファイル形式でWAVEというのは非圧縮状態のファイル形式です。生の音声データです。

最近ではm4aなども多いみたいです。

そしてFLACという圧縮形式を使えばMP3とは違いかなり重い音声データファイルになるのですが、WAVEに戻せますし、綺麗に音を拾うので文字起こしの精度を重視する際はこのFLACがおすすめですしSpeechToTextAPIが対応しているファイルエンコーディングもFLACとかLINEARぐらいです。

なのでお手元にお持ちの音声ファイルを上記画像で表示されているOpenFilesというところに入れて、

FLACを選択、AdvancedSettingsでは
SampleRate 48000
Channels 1
にして変換したやつをダウンロードします。

### 手順４
先ほどのパケット管理画面へ行き、ファイルをアップロードするというボタンをクリックして
この〜〜.flacという音声ファイルをアップロードします。
<img width="925" alt="スクリーンショット 2018-12-28 14.15.49.png" src="https://qiita-image-store.s3.amazonaws.com/0/252596/b837d300-b2e6-2df7-eb39-d39e8a935fe6.png">


こんな感じです。
<img width="998" alt="スクリーンショット 2018-12-28 14.22.06.png" src="https://qiita-image-store.s3.amazonaws.com/0/252596/af44e685-b192-98f7-c178-4bec14634601.png">

### 手順５
それでは先ほど作ったフォルダの中で以下コマンドを打ちましょう。
npm init

#### ファイルツリー
demo
　serviceaccount.json
　package.json

そして出来上がったpakcage.jsonを以下のように記述します

```json

{
  "name": "demo",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "@google-cloud/speech": "^2.1.1",
    "dotenv": "^6.2.0"
  }
}

```

そしてnpm installとコマンドを打ちます。
これで必要なパッケージが整いました。

#### ファイルツリー
demo
　node_module（フォルダ）
　serviceaccount.json
　package.json
　package-lock.json


では次にjsファイルを作りましょう。
同じディレクトリで
文字起こしされたスクリプトを格納するフォルダをsrcという名前で作り、
プログラムとなるspeech.jsというファイルを作り、
そのファイルに以下のコードを貼り付けてください。

```js
const speech = require("@google-cloud/speech");
const fs = require('fs');
require('dotenv').config();
const client = new speech.SpeechClient();

const gcsUri = 'gs://' + process.argv[2] + '/' + process.argv[3]
const audio = {
  uri: gcsUri
};
const config = {
  encoding: 'FLAC',
  sampleRateHertz: 48000,
  languageCode: 'ja-JP',
};
const request = {
  audio: audio,
  config: config,
};

// Detects speech in the audio file
client
  .longRunningRecognize(request)
  .then(data => {
    const operation = data[0];
    // Get a Promise representation of the final result of the job
    return operation.promise();
  })
  .then(data => {
    const response = data[0];
    const transcription = response.results
      .map(result => result.alternatives[0].transcript)
      .join('\n');
      var outputName = 'src/' + process.argv[3].replace("flac", "txt")
      fs.writeFileSync(outputName, transcription)
    console.log(`Transcription: ${transcription}`);
  })
  .catch(err => {
    console.error('ERROR:', err);
  });
```

#### ファイルツリー
demo
　node_module(フォルダ)
　src(フォルダ)
　serviceaccount.json
　package.json
　package-lock.json
　speech.js



さて、あと少しですがこのままだとうまくいきません。
最後にGOOGLE_APPLICATION_CREDENTIALSという環境変数に、先ほどダウンロードしたサービスアカウントキーであるjsonファイルまでのパスを設定しなければなりません。

.envファイルをフォルダの中に作りましょう。
そして以下のように記述してください。

```
GOOGLE_APPLICATION_CREDENTIALS='./serviceaccount.json'
```

#### ファイルツリー
demo
　node_module(フォルダ)
　src(フォルダ)
　.env
　serviceaccount.json
　package.json
　package-lock.json
　speech.js


さぁこれで準備が整いました。
demoディレクトリ上で次のコマンドを打ちましょう。
node speech.js  aaa   bbb.flac

aaaには文字起こししたい音声ファイルを入れているパケットの名前を入れます。
下の写真ならば
　<b>audio-demo</b>
になるはずです


<img width="875" alt="スクリーンショット 2018-12-28 16.27.43.png" src="https://qiita-image-store.s3.amazonaws.com/0/252596/58236753-f907-2b5b-1afe-ab31ff402862.png">


続いて　bbbには音声ファイルの名前を入れます。

下の写真の例ならば
<b> sample.flac </b>
になります

<img width="656" alt="スクリーンショット 2018-12-28 16.29.19.png" src="https://qiita-image-store.s3.amazonaws.com/0/252596/bf73eb2b-4cc9-d1a1-a0f9-182e424a5e17.png">


ですので、打つべきコマンドは、
node speech.js audio-memo sample.flacです。

するとsrcフォルダにsample.txtというファイルが出力されているはずです。
#### ファイルツリー
demo
　node_module(フォルダ)
　src(フォルダ)
　　sample.txt
　.env
　serviceaccount.json
　package.json
　package-lock.json
　speech.js


もしも
Error: 7 PERMISSION_DENIED
~~~~.iam.gserviceaccount.com does not have storage.objects.get access to ~~/sample.flac
というエラーが出ましたら、

パケット管理画面へ行ってください。

<img width="1342" alt="スクリーンショット 2018-12-28 16.34.55.png" src="https://qiita-image-store.s3.amazonaws.com/0/252596/701c1bcd-0a59-63b7-318f-cca839ca3960.png">

そして右下の「パケットの権限を編集」というボタンを押します。


<img width="443" alt="スクリーンショット 2018-12-28 16.37.21.png" src="https://qiita-image-store.s3.amazonaws.com/0/252596/e66fd17d-4e23-e9b1-8a56-4bba23a8a2dc.png">

役割の部分には上の写真のようにストレージオブジェクトの閲覧者と入力し、メンバーには
projectOwner:~~~~~~と入力してください。
~~~~~には自分のprojectのidが入ります。


以上です。