freeeに関係ない話題ですが、Google Apps Script(以下GAS)でできる効率化の例として番外編としてfreee API以外のGASでの活用に関しても記事にしています。
今回は、「Google Cloud Text-to-Speech とGASで毎日届くメルマガを音声ファイル化する」です。
読みきれないメルマガをなんとかしたい
まず目的ですが、今情報収集というと書籍、SNS、ブログ、Podcast、Voicy、Audible、YouTubeと多岐にわたるインプットソースがあります。
私はもともと読書大好き人間で、書籍や文字メディアから情報を得ていたのですが、最近はなかなか時間の確保が難しく、メルマガや書籍よりもスキマ時間やながら作業中に耳で聞ける音声メディアからのインプットの割合が多くなってきました。
結果、せっかく有料で購読しているメルマガも読みきれない事が多くなってきたので、このメルマガを自動で音声ファイル化できたらもっと聞ける(読める)のではないかというのが目的です。
参考にしたブログ
テキスト > 音声 がGASでできることを知ったのは、以前に以下の記事を見たことで知りました。その時はすぐには取り組まなかったのですが、情報としてストックしていました。
今回もこちらにならって実装をと思ったのですが、GASやGoogleの仕様変更などもあり、記事の手順通りだと詰まってしまった部分がありました。
ということで、情報のアップデートをしつつCloud Text-to-SpeechとGASでテキストを音声ファイル化する方法をご紹介したいと思います。
Cloud Text-to-Speechとは
まず今回の肝となるのがCloud Text-to-Speechサービスです。公式サイトの説明では
Text-to-Speech
https://cloud.google.com/text-to-speech?hl=ja
Google の AI テクノロジーを活用した API を利用して、テキストを自然な音声に変換できます。
とあり、デモアプリも公開されています。

ちょっと感動します。
Cloud Text-to-SpeechはGoogle Cloudから利用する
Cloud Text-to-Speechを使用できるようにするには、Google Cloud(旧 Google Cloud Platform)からサービスの有効化をする必要があります。
Google Cloud(以下GC)は機械学習をはじめとしたGoogleが培ってきた様々な技術をパッケージにして、外部で利用ができるように提供しているプラットフォームです。
クレジットカードなどの登録が必要な有料のサービスですが、サービスごとに無料枠などの設定がありますので、枠内に収まる使い方であれば無料で利用することも可能です。
Google Cloudの登録にはGoogleのアカウントが必要です。
まずはGoogle Cloudのサイトにアクセスして無料トライアルの登録をします。

利用者の国やどんな目的で使用するかを選択して利用規約に同意の上で続行します。

Googleアカウントに紐付けされている連絡先の電話番号を確認します。連絡先として別の電話番号を指定することも可能です。

最後にアカウントの種類(組織で使うか個人で使うか)を選択し、クレジットカードを登録して完成です。

Google Cloudコンソールで新しいプロジェクトを作成する
続いてCloud Text-to-Speechを有効化するためにGCのコンソールにアクセスし、左上にあるプロジェクト選択タブから、まずは新しいプロジェクトを作成します。

新しいプロジェクトをクリック

任意のプロジェクト名を指定して作成

Cloud Text-to-Speech APIとGoogle Drive APIを有効化する
続いて、「Cloud Text-to-Speech とGASで毎日届くメルマガを音声ファイル化する」に必要なCloud Text-to-Speech APIとGoogle Drive APIを有効化します。
続いて新しく作成したプロジェクトを選択し、ダッシュボード画面の左上のメニューからAPIとサービス > ライブラリを選択します。

検索窓にText-to-Speechと入力して検索します。

検索結果がいくつか出てきますのでCloud Text-to-Speech APIを選択します。

有効にするのボタンを押して完了です。

同様の流れでGoogle Drive APIも有効化します。

OAuth 同意画面の設定をする
続いてOAuth 同意画面の設定です。APIとサービスの左側のメニューからOAuth 同意画面を選択します。

User Typeを選択する画面が出てきますが、Google Workspaceユーザーでない一般のGoogleアカウントの場合は外部しか選択できません。


続いてこのGCのプロジェクトに許可されたAPIを利用するアプリ情報を登録します。外部への公開を意図していないので、必須項目のみを入力していきます。


続いてスコープの設定画面に進みますが、ここでは特に何かを設定せずに次に進みます。

続いてテストユーザーを追加する画面になります。ここでは自身のGoogleアカウントを追加します。

これでOAuth 同意画面の設定は終了です。
GCのプロジェクト番号をコピーしてGASのスクリプトに入力する
続いて、GAS側のスクリプトとGCのプロジェクトを紐付けするためにプロジェクト番号を確認し、GASの設定画面で入力していきます。
GCのプロジェクト番号はコンソールのホーム画面に表示されていますのでその番号をコピーします。

続いてGASのスクリプトファイルを開き、設定画面を表示させます。

Google Cloud Platform(GCP)プロジェクトという項目がありますので、プロジェクトを変更ボタンを押して、GCで確認したプロジェクト番号を追加します。


マニュフェストファイル appsscript.jsonを編集する
普段は意識することはあまりないですが、GASのプロジェクトにはマニュフェストファイルとよばれる設定ファイル appsscript.json が存在します。普段は表示されていないのですが、設定画面からエディタに表示させることができます。

今回はこのマニュフェストファイルにGCのAPIサービスを利用するためのOAuthスコープ(権限範囲)を追加する必要があります。
どういう時にこのスコープの追加が必要になるのか、イマイチよくわかっていないのですが、GCのAPIを使うGASプロジェクトの場合、その利用したいAPIだけでなくスクリプト内で使用するDriveやGmail等のスコープも追加しないとエラーになります。
今回は
- GmailAppクラスでメール本文からテキストを取得
- テキストをUrlFetchAppクラスを使用しCloud Text-to-Speech APIに接続し音声ファイル化
- 音声ファイルをDriveAppクラスでグーグルドライブの指定フォルダに保存
といくつかのサービスを横断するためGmail・Drive・外部へのアクセス・Google Cloudのスコープを追加する必要があります。
{
"timeZone": "Asia/Tokyo",
"oauthScopes": [
"https://www.googleapis.com/auth/script.external_request",
"https://www.googleapis.com/auth/drive",
"https://www.googleapis.com/auth/cloud-platform",
"https://www.googleapis.com/auth/gmail.readonly",
"https://www.googleapis.com/auth/gmail.modify",
"https://mail.google.com/"
],
"dependencies": {},
"exceptionLogging": "STACKDRIVER",
"runtimeVersion": "V8"
}
これでやっと事前準備が完了しました。
Cloud Text-to-Speechの料金
Cloud Text-to-Speechの利用にあたっての料金に関してですが、2022/07/30現在においては、文字数に応じて課金され、読み上げ音声の種類によって料金が違います。
- 標準音声:400万文字/月までは無料
- WaveNet(より自然な)音声:100万文字/月までは無料
どのくらい使用したかなどはGCのコンソール画面から確認できるので、無料枠に収めたいという方などは定期的に使用状況をモニタリングすると良いと思います。
テキストから音声ファイルを生成するサンプルスクリプト
ではいよいよ本題です。まずはテキストから音声ファイルを生成する関数を作成したいと思います。パラメーターとして設定したいのは
- 音声化したいテキスト
- 生成するファイルの名前
- ファイルのGoogle Drive内の保存先フォルダ
です。
/* テキストから音声ファイルを生成する関数 */
function demoText2Audio() {
const text = '今望んでいるものを手にして、何の得があろうか。それは夢、瞬間の出来事、泡のように消えてしまう束の間の喜びでしかない。';
const fileName = 'シェイクスピア.mp3'; // 生成する音声ファイルの名前
const folder = DriveApp.getRootFolder(); // グーグルドライブのルートフォルダを指定
// 音声ファイル変換パラメーター
const objText = {
input: {
text: text
},
voice: {
languageCode: 'ja-JP', // 言語コードを指定
name: 'ja-JP-Standard-B' // 音声の種類を指定
},
audioConfig: {
audioEncoding: 'MP3', // エンコードフォーマットを指定
speakingRate: 1.3 // 音声の速度
}
}
const payload = JSON.stringify(objText);
const options = {
contentType: 'application/json; charset=utf-8',
headers: { Authorization: 'Bearer ' + ScriptApp.getOAuthToken() },
payload: payload,
};
const url = 'https://texttospeech.googleapis.com/v1/text:synthesize';
const response = UrlFetchApp.fetch(url, options); // JSON文字列
const objSpeech = JSON.parse(response); // JSONオブジェクトへ変換
const decoded = Utilities.base64Decode(objSpeech.audioContent); // audioContentプロパティにbase64-encoded文字列が格納されている
const blob = Utilities.newBlob(decoded, 'audio/mpeg', fileName); // base64-encoded文字列をデコードしてblobオブジェクトを生成
return folder.createFile(blob); // blobオブジェクトからファイルを生成
}
まずtextとfileNameの定数に任意の文字列を指定します。上記のデモではシェイクスピアからの引用です。
folderにはGoogle Driveの保存先フォルダオブジェクトを指定します。今回はルートフォルダを指定しました。
objTextではCloud Text-to-Speech APIにわたす各種データ・パラメーターを指定しています。voiceのプロパティでは言語にまつわる設定が、audioConfigプロパティでは音声にまつわる設定ができます。
このパラメーターの詳細については公式リファレンスを参照してください。
name: 'ja-JP-Standard-B' // 音声の種類を指定
voiceプロパティ内のnameプロパティで読み上げ音声の種類が指定できます。日本語ですと女性・男性、標準音声・WaveNet(より自然な)音声といくつか選択が可能です。
サポートされている音声と言語のページではサンプル音声を聞くこともできます。
こうして各種データ・パラメーターを指定したものをUrlFetchAppクラスのfetchメソッドを使用してリクエストを送信するとレスポンスとしてJSON文字列が返ってきます。
このJSON文字列をオブジェクトに変換し、そのaudioContentプロパティ内にお目当ての音声ファイルが格納されています。
音声ファイルといっても、レスポンスの段階ではbase64-encoded文字列という文字列でしかありませんので、この文字列を
- デコード
- blobオブジェクト化
- Google Driveのファイル化
する必要があります。
const decoded = Utilities.base64Decode(objSpeech.audioContent);
const blob = Utilities.newBlob(decoded, 'audio/mpeg', fileName);
return folder.createFile(blob);
このスクリプトを実行するとルートフォルダに「シェイクスピア.mp3」ファイルが生成されているはずです。
受信メールからメルマガを取得し本文の一部を抜粋する
テキストから音声ファイルを生成する関数ができてしまえば、あとは任意のメールから音声ファイル化したいテキストを抜粋していくだけです。
多数の受信メールから特定のメールを抽出する方法は、以下の記事で紹介しています。
またメルマガ本文には前文やあとがきなど音声化に不要なテキストも含まれていると思います。APIへ送信する文字数を節約するためにも正規表現を用いて必要なテキストのみを抽出しましょう。
こちらも以下の記事が参考になります。
あとはメルマガが届くタイミングにあわせてトリガーを設定し、スクリプトを実行すれば、自動でメルマガが音声ファイル化されGoogle Driveに保存されます。
トリガーに関しては以下の記事が参考になります。
いつも隣にITのお仕事|【初心者向けGAS】時限式のイベントトリガーを設置して決まった時刻にBotを送信する方法
追記:5000文字を超えるとエラーになる
Cloud Text-to-Speechの仕様で、1回のリクエストあたりに音声化できるテキストの文字数が5000文字という制限がありました。5000文字を超える場合はテキストを分割する必要があります。次の記事ではテキストを5000文字ごとに分割するスクリプトを紹介しています。
おわりに
いかがだったでしょうか?「Google Cloud Text-to-Speech とGASで毎日届くメルマガを音声ファイル化する」ですが、事前設定が少しややこしいのですが、スクリプト自体は比較的コンパクトです。
このスクリプトは、メルマガ読み上げだけでなく、外国語学習や、視覚障害者の方にも活用していただけそうですね。
もし実際に活用された方がいらっしゃったらTwitterなどで感想いただけると嬉しいです。