yasutomogのブログ

Software Engineerの雑記

Google Cloud Platform(Cloud Functions, Cloud PubSub, Cloud Storage, Speech-to-Text, Secret Manager)を使ってPodcast音声データの文字起こし

概要

  • 2020年のコロナ時期から社内コミュニケーションを活性化させたく、社内環境でPodcast配信を開始
  • Podcastの収録はzoomで録音し、編集などはせずに社内のGoogleサイトへアップする流れ(継続させることに重き置いて、極力手間を掛けないことを意識している)
  • 収録はいつも1〜1.5hほどになっている
  • 社内から聞く前にある程度話の内容などがわかると嬉しいという意見をもらったので、Google Cloud APIのSpeech-to-Textを利用して文字起こしを試してみた

ゴール

  • 当初は、自分のローカルマシンでやっていたが色々運用がめんどくさくなってきたのと、GCPのサービス連携を試してみたかったので、Storageに音声ファイル(wav)をアップロードしたら自動で文字起こしをしてくれるものをゴールにした。
  • 今回、Secret ManagerやPubSubは利用しなくても構築可能だったが、色々な連携を試してみたかったので利用することに決めた。(サービスの最適化よりかは、色々な素振りをするために利用サービスを検討した。)
  • 言語はNode.jsで書く

GCPのサービス関連図と処理内容

Podcast音声データ文字起こしGCPの関連図
Podcast音声データ文字起こしGCPの関連図

  1. wavファイルをローカルPCからCloud Storageへアップロード(zoom収録時はm4a形式になっているので、それをwavに変換するところまではローカルで実施)
  2. アップロード用のCloud Storageにファイル配置(上書き)されたことを契機にCloud Functions実行。
  3. 関数内ではシークレットマネージャーからCloud Storageアクセス情報(Bucket名)を取得(特に不要そうではあるが、試しに使ってみたかった)
  4. Speech-to-Text APIを利用して、音声(wav)データから話している内容を取得(結構、処理に時間が掛かる)
  5. アップロードとは別のCloud Storageへjsonファイルを書き出し
  6. Cloud PubSubにjsonファイル名をメッセージとしてパブリッシュ
  7. メッセージのパブリッシュを契機にCloud Functions実行
  8. 関数内ではシークレットマネージャーからCloud Storageアクセス情報(Bucket名)を取得(特に不要そうではあるが、試しに使ってみたかった)
  9. Cloud Storageからjsonデータを取得
  10. 取得したjsonデータを解析し、時間ごとの会話内容として整形したファイルを別なCloud Storageへ書き出し

ハマったポイント

  • Cloud FunctionsからStorageやシークレットマネージャーにアクセスしたときに権限エラーが発生。
    単純にStorageやシークレットマネージャー側で権限を絞っていたので、適宜権限を変更することで解決した
  • Speech-to-Text APIの利用でタイムアウトエラー
    Cloud Functionsのタイムアウト最大値が540秒なため、タイムアウトや使用メモリサイズにMAX値を設定していたが540秒以内に完了せずタイムアウトエラーとなっていた。
    当初、Storageへのファイル配置をトリガーとして呼ばれる関数には、asyncをつけて同期的な処理実行をするようにしていたが、それをやめ非同期処理させるようにして解決。

今後の課題

  • デプロイ方法
    gcloudコマンドを利用してローカルからデプロイしているが、GitHubと連携させたい
  • エラーハンドリング
    音声ファイルのテキスト化部分は非同期処理としただけなので、エラー時の処理を検討したい
  • GoogleのSpeech-to-Text APIの精度
    雑な日本語で話しているせいかもしれないが、結構話している内容とテキストで差が生じる。
    マイクやレコーディング後の編集などで音質を上げることで、精度向上につながるものなのか時間があれば試してみたい。

GitHub

github.com

※helloWorldのソースは、Cloud Functionsの関数内でsetTimeoutした場合に、大元の関数処理自体は完了しても非同期処理される関数はその後実行されることを確認するためのもの。