Googleスプレッドシートの英単語をクリックしたら音声で聞き取れる実装してみたが車輪の再発明だった件

2023.12.16

はじめに

こんにちは。データアナリティクス事業本部ビッグデータチームのyosh-kです。
私は最近TOEICのListening & Reading Testの勉強をしていました。その際にGoogle Spreadsheetで英単語をメモしており、発音がわからない英単語はその都度COPYしてwebで検索して発音を確認していました。この作業が中々手間であり、なんとか既存機能や拡張機能で解決できないかと模索したところがきっかけでした。

結論

スプレッドシートの機能で無かったので、以降の実装を行いましたが、実装後に拡張機能を調べていたらGoogle翻訳で全く同様にかつ無料でできました。完全に車輪の再発明でした。。私の様にこの機能に気づいていない人(あまりいない気もしますが)に少しでも広まってほしいという思いでこのブログは執筆しているので、以降の実装については、興味ある方だけ見ていただけたらと思います。唯一需要があるとしたら、音声がfemaleかmaleか、イギリス英語かアメリカ英語かなど細かく設定したい人にはおすすめかもしれません。

やってみた動画

GCP設定

それではGoogle Spreadsheetに対して、カスタム機能を実装していきます。具体的にはGoogle Apps Scriptを使用して、クリックした英単語をGoogle CloudのText-to-Speech APIを用いて音声に変換します。

API概要と料金については、以下をご確認いただければと思います。今回は1ヶ月あたりの無料枠の範囲で検証しました。音声は、のテキスト読み上げシステムよりも自然な音声であるWaveNetを使用しました。

Text-to-Speech APIの有効化

最初にText-to-Speech APIの有効化を行います。

任意のGCPプロジェクトからAPIとサービスを検索し、遷移したページのAPIとサービスの有効化をクリックします。その後、APIライブラリの画面に飛びますのでText-to-Speechと検索し、候補として出るCloud Text-to-Speech APIを選択し有効化します。

サービスアカウントの作成

今回はAPI認証情報はサービスアカウントを使用します。API有効化後は認証情報からサービスアカウントの管理を選択し、サービスアカウントを作成します。

サービスアカウント名、アカウントIDは任意の値を指定し、ロールはオーナー権限を設定します。

サービスアカウント作成後は、キーから鍵を追加を選択し、サービスアカウントキーを生成します。キーのタイプはJSONを選択します。こちらの情報は後ほど使用します。

実装

実装対象のGoogle Spreadsheetの拡張機能メニューからApps Scriptを選択します。以降はGoogle Apps Script 上でのmain.jsの実装になります。

function getSecretKeys() {
  var scriptProperties = PropertiesService.getScriptProperties();
   return {
    privateKey: scriptProperties.getProperty('PRIVATE_KEY').replace(/\\n/g, '\n'),
    clientEmail: scriptProperties.getProperty('CLIENT_EMAIL')
  };
}

function getOAuthService() {

  var keys  = getSecretKeys();
  return OAuth2.createService('GoogleCloudTextToSpeech')
    .setTokenUrl('https://oauth2.googleapis.com/token')
    .setPrivateKey(keys.privateKey)
    .setIssuer(keys.clientEmail)
    .setPropertyStore(PropertiesService.getUserProperties())
    .setScope('https://www.googleapis.com/auth/cloud-platform');
}


function onOpen() {
  var sheet = SpreadsheetApp.getActiveSpreadsheet();
  var entries = [{
    name: "Listen to the pronunciation",
    functionName: "playPronunciation"
  }];
  sheet.addMenu("カスタムメニュー", entries);
}

function playPronunciation() {
  var cell = SpreadsheetApp.getCurrentCell();
  var word = cell.getValue();
  if (word) {
     var audioContent = textToSpeech(word);
    if (audioContent) {
      var htmlString = '<audio id="audioPlayer" controls autoplay>' + 
                       '<source src="data:audio/mp3;base64,' + audioContent + '" type="audio/mp3">' +
                       '</audio>' +
                       '<script>' +
                       'document.getElementById("audioPlayer").onended = function() {' +
                       'google.script.host.close();' + 
                       '};' +
                       '</script>';
      var htmlOutput = HtmlService
        .createHtmlOutput(htmlString)
        .setWidth(1)
        .setHeight(1);
      SpreadsheetApp.getUi().showModalDialog(htmlOutput, 'Play sound');
    }
  }
}


function textToSpeech(text) {
  var oAuthService = getOAuthService();
  if (!oAuthService.hasAccess()) {
    Logger.log('認証に失敗しました: %s', oAuthService.getLastError());
    return null;
  }
  
  var url = 'https://texttospeech.googleapis.com/v1/text:synthesize';
  var payload = {
    input: { text: text },
    voice: { languageCode: "en-US", name: "en-US-Wavenet-D", },
    audioConfig: { audioEncoding: "MP3" }
  };
  
  var options = {
    headers: {
      Authorization: 'Bearer ' + oAuthService.getAccessToken()
    },
    method: "post",
    contentType: "application/json",
    payload: JSON.stringify(payload)
  };
  
  var response = UrlFetchApp.fetch(url, options);
  var jsonResponse = JSON.parse(response.getContentText());

  if (jsonResponse.audioContent) {
    return jsonResponse.audioContent; 
  } else {
    SpreadsheetApp.getUi().alert("音声を取得できませんでした");
    return null;
  }
}
  1. onOpen functionでSpreadsheetのメニューに追加したカスタムメニューからListen to the pronunciationを押下されたことをトリガーにplayPronunciation functionを実行
  2. 選択されているせるの値を取得し、functiontextToSpeechを実行
  3. OAuth2を用いてaccess tokenを取得し、tokenとvoice、textパラメータを元にtexttospeechのAPIをpost
  4. 戻り値のaudioContentから音声データを再生
  5. 音声データが終了したらscriptをclose

Google Apps Scriptでサービスアカウントとしてデータ操作する方法として、OAuth2ライブラリを用いた認証を使用しました。

設定としてはGoogle Apps ScriptのライブラリからスクリプトID1B7FSrk5Zi6L1rSxxTDgDEUsPzlukDsi4KGuTMorsTQHhGBzBkMun4iDFで検索し、OAuth2を追加する手順となります。

認証に用いるためのPRIVATE_KEYCLIENT_EMAILをApps Script上で設定します。Apps Scriptのプロジェクトの設定からスクリプトプロパティの編集を選択し、以下それぞれ入力します。

  • CLIENT_EMAIL: サービスアカウントキーのjsonファイルからclient_emailの値
  • PRIVATE_KEY: サービスアカウントキーのjsonファイルからprivate_keyの値

実行結果

やってみた動画になります!

最後に

結果として実装した機能としてはあまり活用していませんが、Google Apps Scriptは試したことがなかったので、良い経験になりました。あとはTOEICスコアを祈るのみです。。