WHITEPLUS TechBlog

株式会社ホワイトプラスのエンジニアによる開発ブログです。

NotebookLM に Meet の議事録を GAS で自動連携する

こんにちは!
ホワイトプラスのコアシステム開発Gエンジニアのさとうです。

打ち合わせで話した内容を後から検索したい、そんなときに便利なのが NotebookLM です。
メモ(議事録)を NotebookLM に取り込んでおけば、「あの件、誰が何て言ってたっけ?」を数秒で引き出せるようになります。

Google Meet にはメモを自動で作成する機能があるものの、そのままでは NotebookLM のリソースとして取り込むために毎回手動でアップロードする必要があり、地味に手間がかかります。
そこで Google Apps Script(以降 GAS)を使って、Meet のメモを NotebookLM に自動で読み込む仕組みを構築してみました。

この記事では、その仕組みの全体像と具体的な設定方法、実運用で気をつけたい注意点などを紹介します。

1. 全体的な流れ

まずは今回構築する仕組みの全体像から押さえておきましょう。
処理の流れは大きく3ステップです。

  1. Meet のメモが自動的に Google Drive に保存される
  2. GAS により、メモの内容がスプレッドシートに転記される
  3. NotebookLM に最新のメモが反映される

Meet で会議を実施すると、設定次第で Google Drive のマイドライブ配下にメモドキュメントが自動生成されます。
GAS は Google ドライブを定期的にスキャンし、新たに生成されたメモがあれば、必要な情報をスプレッドシートに転記していきます。
NotebookLM 側ではそのスプレッドシートをリソースとして登録しておけば、自動転記のタイミングで最新のメモを読み込める、という流れです。

2. 具体的な設定方法

ここからは、実際に手を動かしていく手順を紹介します。

2.1. Meet の設定

まずは Meet 側でメモが自動生成されるように設定します。
会議中に「メモを取る」機能を都度有効化することもできますが、毎回手動で操作するのは大変です。
Meet の設定ページ(歯車アイコン)から「今後の会議での自動メモ作成」のチェックボックスを ON にしておけば、以降の会議で自動的にメモが作成されるようになります。

今後の会議での自動メモ作成

メモが生成されると、主催者のマイドライブ内に「Meet Recordings」フォルダが作成され、その中にメモ用のドキュメントが保存されます。
まずはこのドキュメントが自動生成される状態を作っておくことが第一歩です。

2.2. スプレッドシートの用意

メモの内容を集約するスプレッドシートを用意します。
シート構成の例は以下のようなイメージです。

列名 内容
ファイルID Meet のメモのファイル ID
ファイル名 Meet のメモのファイル名
URL 元のメモのドキュメントへのリンク
メモ メモに記載されている Meet の内容要約(メモタブ)
文字起こし メモに記載されている Meet の文字起こし(文字起こしタブ)

このスプレッドシートを NotebookLM のリソースに登録する想定なので、後から検索したときにわかりやすい単位(会議体など)によってシートを分けておくのもよいでしょう。

2.3. GAS の作成

用意したスプレッドシートに紐づく形で GAS を作成します。
GAS は「メニューバー > 拡張機能 > Apps Script」で作成できます。

処理内容は大きく次の2つです。

  • Google Drive からメモドキュメントを取得する
  • ドキュメントの中身をスプレッドシートに転記する

Drive の検索には DriveApp.searchFiles を使い、ファイル名やフォルダで絞り込みます。
ドキュメントの本文取得には DocumentApp.openById を使うと、テキストの抽出が簡単に行えます。

実際に使っている GAS は、以下のような処理になっています。

function appendSpecificDocsTabsToSheet() {
  // メモを読み込むフォルダの ID
  //   例: Drive でフォルダを開いた URL 「drive.google.com/drive/folders/XXXX」の XXXX 部分
  const folderId = '<フォルダの ID>';

  // 転記先スプレッドシートの ID
  //   例: 「docs.google.com/spreadsheets/d/YYYY/edit」の YYYY 部分
  const spreadsheetId = '<スプレッドシートの ID>';

  // 転記先のシート名(デフォルトは 'シート1')
  const sheetName = 'シート1';

  // 対象にしたい会議のタイトル(Meet メモのファイル名の先頭と前方一致で判定)
  const meetingTitle = '<Google カレンダーに登録されている会議のタイトル>';

  const folder = DriveApp.getFolderById(folderId);
  const ss = SpreadsheetApp.openById(spreadsheetId);
  const sheet = ss.getSheetByName(sheetName);

  // 重複チェック用の一覧取得 & ヘッダーの自動追加
  const lastRow = sheet.getLastRow();
  let existingIds = [];

  if (lastRow > 0) {
    const idValues = sheet.getRange(1, 1, lastRow, 1).getValues();
    existingIds = idValues.map(row => row[0]);
  } else {
    // ヘッダーを「メモ」と「文字起こし」用に変更
    const headers = ['ファイルID', 'ファイル名', 'URL', 'メモ', '文字起こし'];
    sheet.appendRow(headers);

    const headerRange = sheet.getRange(1, 1, 1, headers.length);
    headerRange.setFontWeight('bold');
    headerRange.setBackground('#f3f3f3');

    existingIds.push('ファイルID');
  }

  // 検索条件(containsで検索)
  const query = `mimeType = '${MimeType.GOOGLE_DOCS}' and title contains '${meetingTitle}' and trashed = false`;
  const files = folder.searchFiles(query);

  while (files.hasNext()) {
    const file = files.next();
    const fileName = file.getName();
    const fileId = file.getId();

    // 前方一致で厳密にチェック
    if (fileName.startsWith(meetingTitle)) {

      // 未登録のファイルのみ処理
      if (!existingIds.includes(fileId)) {
        const fileUrl = file.getUrl();

        try {
          const doc = DocumentApp.openById(fileId);

          // 各タブのテキストを一時的に保存する変数を用意
          let memoText = "";
          let transcriptText = "";

          // ドキュメント内にある「タブ」の一覧を取得
          const tabs = doc.getTabs();

          // タブを1つずつ順番に確認する
          for (let i = 0; i < tabs.length; i++) {
            const tab = tabs[i];
            const tabTitle = tab.getTitle(); // タブの名前を取得

            // タブ名に「メモ」が含まれていたら、そのタブの本文を取得
            if (tabTitle.includes('メモ')) {
              memoText = tab.asDocumentTab().getBody().getText();
            }
            // タブ名に「文字起こし」が含まれていたら、そのタブの本文を取得
            else if (tabTitle.includes('文字起こし')) {
              transcriptText = tab.asDocumentTab().getBody().getText();
            }
          }

          // スプレッドシートに新しく行を追加(D列にメモ、E列に文字起こし)
          sheet.appendRow([fileId, fileName, fileUrl, memoText, transcriptText]);

        } catch(e) {
          console.log('ファイルID: ' + fileId + ' の読み込みに失敗しました。: ' + e.toString());
        }
      }
    }
  }
}

作成した GAS は、時間主導型トリガーで1日1回など定期実行するように設定しておくと、基本放置でメモが溜まっていきます。 スケジュールはコードを記載した Apps Script でサイドバーの「トリガー」から設定することができます。

例えば1日1回の頻度で転記させたい場合は

  • イベントのソースを選択:時間主導型
  • 時間ベースのトリガーのタイプを選択:日付ベースのタイマー
  • 時刻を選択:任意の時間

を選択すれば OK です。

トリガーを追加

2.4. NotebookLM にスプレッドシートを登録

あとは GAS を設定したスプレッドシートを NotebookLM のリソースに追加すれば完成です。 以前はリソースを最新化するために NotebookLM 内で手動更新の操作が必要でしたが、Google 側の改修によって、リソース元のスプレッドシートの内容が自動反映されるようになりました。

3. 注意点と拡張方法

実際に運用することを考えたときに、いくつか気をつけたいポイントやその対策、より簡易的なやり方があります。

3.1. スプレッドシートの1セルの最大文字数は5万文字

スプレッドシートは1セルあたり 最大5万文字 までしか格納できません。
日本人の発話は1時間あたり約1万5千文字〜2万文字と言われているので、単純計算でも 2〜3時間程度の会議が1セルに収まる上限になります。

長時間の会議や、要約前の生ログをまるごと保存したいような場合には、あっさり上限に到達してしまう可能性があります。

3.2. スプレッドシートとドキュメントの組み合わせ

長時間開催されたり、発話量が多かったりする会議のときに有効なのが、スプレッドシートとドキュメントを併用する構成です。

  • 会議日時、タイトル、参加者などのメタ情報 → スプレッドシートで管理
  • 発話記録の本文 → Google ドキュメントに追記

このように役割を分けると、5万文字の制限を気にすることなく発話記録を蓄積できます。
NotebookLM にも両方をリソースとして登録しておけば、メタ情報を軸に検索して、詳細をドキュメント側で確認する、という使い方ができます。

3.3. プロジェクト機能の活用

NotebookLM の代わりに、Google Drive の「プロジェクト機能」を活用する構成もあります。
プロジェクト機能は、関連するフォルダやファイルなどをひとまとめにして、Gemini に質問・要約・分析させることができる機能です。

NotebookLM と比べると、音声解説やマインドマップといった成果物への変換はできないなど、できることは少なくなります。
とはいえ、メモを後から検索するというチャット用途に絞れば十分に活用できる印象です。

この構成の嬉しいところは、プロジェクトに フォルダを登録できる 点です。
GAS 側の処理は Meet のメモを指定フォルダにコピーするだけで済むため、スプレッドシートに転記する構成と比べて実装がぐっとシンプルになります。

音声解説やマインドマップも活用したい場合は NotebookLM、実装のシンプルさを重視するならプロジェクト機能、といった形で使い分けてみるのもよいでしょう。

4. まとめ

この記事では、GAS を使って Meet のメモを NotebookLM に自動で連携する方法を紹介しました。

  • Meet のメモが Google Drive に自動保存される
  • GAS が Drive からメモを読み取り、スプレッドシートに転記する
  • NotebookLM でスプレッドシートをリソースとして登録しておけば、自動的にメモが読み込まれる

設定には Meet、Drive、GAS、NotebookLM といくつかのサービスの知識が必要ですが、一度組み上げてしまえば、メモの検索がぐっと楽になります。
「あの会議、なんて話してたっけ?」と過去を掘り返す時間が減るだけでも、日々の業務体験がかなり変わってくるはずです。

私たちのチームでは、NotebookLM を事業部との要件定義をまとめる場として活用しています。

blog.wh-plus.co.jp

Meet から生成されるメモも重要なリソースの1つとなっているので、自動連携によりスムーズに取り込んでいつでも引き出せる状態にしていければと思います。

メモを活用しきれていないと感じている方は、ぜひ試してみてください。

さいごに

ホワイトプラスでは、ビジョンバリューに共感していただけるエンジニアを募集しています! ネットクリーニングの「リネット」など「生活領域×テクノロジー」で事業を展開している会社です。

どんな会社か気になった方は、オウンドメディア「ホワプラSTYLE」をぜひご覧ください。 エンジニアの方向けのエントランスブック「WHITEPLUS Entrance Book for Engineer」もございます。

オンラインでカジュアル面談もできますので、ぜひお気軽にお問い合わせください!

www.wh-plus.co.jp