Whisper、ChatGPT、Google DriveのAPIを使って議事録を自動生成してみた(part4: UIの作成/GASを使用した自動化)

議事録を自動生成させる過程で、Google Driveの監視を目的としてGASを使用したのでその具体的な使い方をまとめました。今回は監視対象にファイルがアップロードされるとPub/Subメッセージを送信します。
目次
はじめに
今回はGAS(Google Apps Script)を使ってGoogle Driveを監視し、更新があったタイミングでPub/Subメッセージを作成する方法についてご紹介します。
GASについて
今回GASを使用した最大の理由は、無料であるという点にあります。Google Driveにファイルがアップロードされたことを検知するためには、part3で紹介したPub/Subサービスを定期的に使用してGoogle Cloud Functionsに実装した関数を定期実行して特定の対象を監視する方法が考えられます。しかし、Pub/Subは有料のサービスであり無駄なコストがかかってしまいます。
そこで、Driveの監視を無料であるGASを使って行い、必要なタイミングでPub/Subメッセージを作成することでコストを抑えた運用が可能であると考え、GASをDriv監視とPub/Subメッセージの作成を目的に使用します。
GASを用いたトリガー作成の実行フロー
全体の流れは以下の通りです。
1. OAuth2.0クライアントの作成
2. Google Driveから該当ファイルのファイルidの取得
3. GASコードを使ったOAuth2認証
4. Pub/Subメッセージの送信
1のみGoogle cloud consoleで作業を行い、2以降はGASに記述します。1についてはこちらを参考にしてください。
また、それぞれの過程での実体は下図のようになっています。以下では2以降の手順について順番に説明していきます。必要があればこの図を参照してください。
Google Driveの監視とファイルIDの取得
今回の実装では監視対象であるGoogle Driveのフォルダに対して、GASを所有するGoogle Accountがアクセス権を持っていることを想定しているので、特別な認証を必要とせずにこれらの操作を行うことが可能です。
function checkForNewFilesAndPublish() {
const folderId = PropertiesService.getScriptProperties().getProperty('OBSERVED_FOLDER_ID');
const folder = DriveApp.getFolderById(folderId);
const files = folder.getFiles();
const newFiles = [];
const lastCheckTime = PropertiesService.getScriptProperties().getProperty('lastCheckTime') || '1970-01-01T00:00:00Z';
const lastCheckDate = new Date(lastCheckTime);
DriveAppメソッドを使ってファイルIDを取得します。また、PropertiesServiceクラスを使用して、環境変数のような形で一部の変数を保持しています(この値はGASのプロジェクト設定から確認できます)。
Google Cloud Functions上に私が実装した関数は議事録の生成過程でファイルを移動させることで、監視対象とするフォルダはアップロードされたとき以外は空になるようにしていますが、念の為ここでは最後にチェックした時刻よりも後にアップロードされたファイルのみを対象としています。
OAuth2.0認証
GASからGoogle Cloud Projectにデータを送信するには、GASの所有者であるGoogle Accountの認証が必要でした。今回はここでOAuth2.0を使用しています。
GASでOAuth2.0認証を行うためのライブラリとしてOAuth2があるのでこれを使用します。GASのエディタ > ライブラリから、READMEに記載されたコードを使用します。
CLIENT_IDやCLIENT_SECRETはGoogle Cloud ConsoleでOAuth2.0クライアントの作成を行なったものを、この変数名でプロジェクトの設定 > スクリプトプロパティから設定してください。
function getOAuthService() {
// OAuth2サービスの作成
var scriptProperties = PropertiesService.getScriptProperties();
return OAuth2.createService('GoogleCloudPubSub')
.setAuthorizationBaseUrl('https://accounts.google.com/o/oauth2/auth')
.setTokenUrl('https://accounts.google.com/o/oauth2/token')
.setClientId(scriptProperties.getProperty('CLIENT_ID'))
.setClientSecret(scriptProperties.getProperty('CLIENT_SECRET'))
.setCallbackFunction('authCallback')
.setPropertyStore(PropertiesService.getUserProperties())
.setScope('https://www.googleapis.com/auth/pubsub')
.setCache(CacheService.getUserCache())
.setParam('access_type', 'offline')
.setParam('prompt', 'consent');
}
function authCallback(request) {
var pubSubService = getOAuthService();
var isAuthorized = pubSubService.handleCallback(request);
if (isAuthorized) {
return HtmlService.createHtmlOutput('Success! You can close this tab.');
} else {
return HtmlService.createHtmlOutput('Denied. You can close this tab');
}
}
このコードでは、OAuth2.0で認証する対象や範囲をgetOAuthService関数で指定しており、認証を行う際に使用する関数としてauthCallback関数を使用しています。なお、getOAuthService関数の.setParamで指定している2つについては、トークンのリフレッシュを行い認証の回数を削減するために使用しています。使用するセキュリティ要件に応じて適宜削除してください。
Pub/Subメッセージの送信
function publishToPubSub(data) {
var topicName = 'Your Topic Name';
var message = Utilities.base64Encode(JSON.stringify(data));
var pubSubService = getOAuthService(); // OAuth2サービスを取得
Logger.log(message)
Logger.log(pubSubService.hasAccess())
// 認証が必要な場合
if (!pubSubService.hasAccess()) {
var authorizationUrl = pubSubService.getAuthorizationUrl();
Logger.log("認証が必要です。以下のURLにアクセスしてください: %s", authorizationUrl);
return;
} else {
var options = {
method: "post",
contentType: "application/json",
headers: {
Authorization: 'Bearer ' + pubSubService.getAccessToken()
},
payload: JSON.stringify({
"messages": [
{ "data": message }
]
})
};
var response = UrlFetchApp.fetch('https://pubsub.googleapis.com/v1/' + topicName + ':publish', options);
var statusCode = response.getResponseCode();
var responseBody = response.getContentText();
Logger.log("Status Code: " + statusCode);
Logger.log("Response Body: " + responseBody);
// 現在の実行時刻をプロパティに保存して次回の比較に使用
PropertiesService.getScriptProperties().setProperty('lastCheckTime', new Date().toISOString());
}
}
このコードの前半部分でOAuth認証を行い、認証が通った場合にはファイルIDをjsonの形で送っています。フェッチするURLの一部にPub/Subのトピックネームが必要なので、Google Cloud Consoleで確認の上、Your Topic Nameを変更してください。
最後に
今回はGASを使って監視する方法を具体的なGASコードと共にご紹介しました。この実装では、Google Accountを使用する必要があるという問題はありますが、無料のGASを使用してPub/Subメッセージをファイルのアップロードに対して自動的に生成することはできました。部分的に同様のことを使う機会は多いかと思いますので、参考になれば幸いです。