【Gemini】Gmailの内容をGeminiでサマライズしてGoogleチャットに送る【GPTs】

みなさまこんにちは。今回はタイトル通りGmailの内容をサマライズしてGoogleチャットに送ろうと思います。

事の経緯として、最近DuetAIやコパイロットについてのニュースをよく聞くようになりましたね!でもまだ日本語に対応できていなかったりするので、そんなに真剣に考えていませんでした。

でもよく考えればGAS使えばそれっぽい挙動を再現できるのでは?と思い試してみました\(^o^)/
ブラウザのChatGPTを毎回開いてサマライズも面倒ですしね!

※今回のコードではメールをサマライズしますが、GeminiAPIを使用する場合モデルの学習に利用されます。Googleアカウントを新しく作るか、広告メールとかを選択してサマライズすることをおすすめします。

最終的なコードは以下のとおりです。

function summarizeAndPostToGoogleChat() {
  var apiKey = 'your_api_key'; // あなたのGemini APIキー
  var apiUrl = 'https://generativelanguage.googleapis.com/v1beta/models/gemini-pro:generateContent';
  var googleChatWebhookUrl = 'your_webhook_url'; // あなたのGoogleチャットのWebhook URL

  var threads = GmailApp.search('in:inbox is:unread');
  threads.forEach(function(thread) {
    var messages = thread.getMessages();
    messages.forEach(function(message) {
      var subject = message.getSubject();
      var body = message.getPlainBody();
      
      // 英語のメール内容を日本語でサマライズするよう指示を追加
      var promptText = "この英語のメールを日本語でサマライズしてください: " + body;
      
      var payload = {
        contents: [{
          parts: [{
            text: promptText
          }]
        }]
      };
      
      var options = {
        'method' : 'post',
        'contentType': 'application/json',
        'payload' : JSON.stringify(payload),
        'muteHttpExceptions': true
      };
      
      try {
        var response = UrlFetchApp.fetch(apiUrl + '?key=' + apiKey, options);
        var content = JSON.parse(response.getContentText());
        var summary = content.candidates[0].content.parts[0].text; // サマライズした内容
        
        // サマライズした内容をGoogleチャットに投稿
        UrlFetchApp.fetch(googleChatWebhookUrl, {
          'method': 'post',
          'contentType': 'application/json',
          'payload': JSON.stringify({'text': 'Subject: ' + subject + '\nSummary: ' + summary})
        });
        
        // メールを開封済みにマーク
        message.markRead();
      } catch (error) {
        Logger.log(error.toString());
      }
    });
  });
}

全体像

はじめに全体像を考えてみます。使用する要素は以下の通り。

  • Gmail
  • Googleチャット
  • GeminiAPI
  • Google Apps script
  • Gemini Script Assistant(GeminiのAPIを使ったGAS作成をサポートしてくれます。)

Gmailに届いたメール本文をGASでGeminiに送る。内容をサマライズしてもらってGoogleチャットに返してもらうって流れですね。なんとなく今回のは簡単そうです笑

それでは早速GPTと対話しながら作っていきましょう!(GPTの振る舞いを以前と変更しました。あまりにも事務的な会話で疲れるのでギャル語を使用させてます)

GPTとコードを考える

こんにちは

こんにちは!どうしたの?何かお手伝いできることがあるかな?

GmailをGeminiでサマライズしてGoogleチャットにその内容を送って欲しいんだよね。未読のメールにだけね。で、サマライズしたら開封済みにしてほしい

了解した!メールをサマライズして、その内容をGoogleチャットに送るスクリプトが必要ってことね。未読のメールだけ対象にして、サマライズしたら開封済みにするんだね。ちょっと考えてみたよ。Google Apps Scriptを使って、Gmailの未読メールを取得して、Geminiでサマライズし、その結果をGoogleチャットに投稿するスクリプトを作ればいいじゃん!
以下にサンプルコードを示すから、このステップに沿ってカスタマイズしてみてね。
Gmailから未読メールを取得して開封済みにする
Gemini APIを使ってメールの内容をサマライズ
サマライズした内容をGoogleチャットに投稿

function summarizeAndPostToGoogleChat() {
  var apiKey = 'your_api_key'; // GeminiのAPIキーを設定
  var apiUrl = 'https://generativelanguage.googleapis.com/v1beta/models/gemini-pro:generateContent';
  var googleChatWebhookUrl = 'your_webhook_url'; // GoogleチャットのWebhook URLを設定
  
  // Gmailから未読メールを取得
  var threads = GmailApp.search('is:unread');
  threads.forEach(function(thread) {
    var messages = thread.getMessages();
    messages.forEach(function(message) {
      var subject = message.getSubject();
      var body = message.getPlainBody();
      
      // Gemini APIを使ってメールの内容をサマライズ
      var payload = {
        contents: [{
          parts: [{
            text: body // メールの本文を使用
          }]
        }]
      };
      
      var options = {
        'method' : 'post',
        'contentType': 'application/json',
        'payload' : JSON.stringify(payload),
        'muteHttpExceptions': true,
        'headers': {
          'Authorization': 'Bearer ' + apiKey
        }
      };
      
      try {
        var response = UrlFetchApp.fetch(apiUrl + '?key=' + apiKey, options);
        var content = JSON.parse(response.getContentText());
        var summary = content.candidates[0].content.parts[0].text; // サマライズした内容
        
        // サマライズした内容をGoogleチャットに投稿
        UrlFetchApp.fetch(googleChatWebhookUrl, {
          'method': 'post',
          'contentType': 'application/json',
          'payload': JSON.stringify({'text': 'Subject: ' + subject + '\nSummary: ' + summary})
        });
        
        // メールを開封済みにする
        message.markRead();
      } catch (error) {
        Logger.log(error.toString());
      }
    });
  });
}

このコードを使う前に、your_api_keyにGeminiのAPIキーを、your_webhook_urlにGoogleチャットのWebhook URLを設定してね。また、このスクリプトはGoogle Apps Scriptで動くから、Googleスクリプトエディタでプロジェクトを作って、コードを貼り付けて実行してみて!
ちなみに、このコードはすべての未読メールに対して動くから、特定のラベルがついたメールだけにしたい場合は、GmailApp.searchの検索クエリを調整してね。

大体いい感じっぽいですが、本当にあっているか一回確認します。ナレッジファイルを読み込ませるとちゃんと書いてくれる率が上がりますよ!

URLの書き方あってるかな?ナレッジを見返してみたほうが良くね?

ごめんごめん!本当だね、ちょっと間違えちゃったみたい。ナレッジをチェックしたところ、Gemini APIの正しいURLは「https://generativelanguage.googleapis.com/v1beta/models/gemini-pro:generateContent」で、APIキーはURLの末尾に「?key=API_KEY」を追加して指定するんだったね
修正したコードはこんな感じになるよ。このAPI URLを使って、HTTPリクエストのオプションにAPIキーを含めるところをちょっと直してみたよ。

function summarizeAndPostToGoogleChat() {
  var apiKey = 'your_api_key'; // GeminiのAPIキーを設定
  var apiUrl = 'https://generativelanguage.googleapis.com/v1beta/models/gemini-pro:generateContent';
  var googleChatWebhookUrl = 'your_webhook_url'; // GoogleチャットのWebhook URLを設定
  
  // Gmailから未読メールを取得
  var threads = GmailApp.search('is:unread');
  threads.forEach(function(thread) {
    var messages = thread.getMessages();
    messages.forEach(function(message) {
      var subject = message.getSubject();
      var body = message.getPlainBody();
      
      // Gemini APIを使ってメールの内容をサマライズ
      var payload = {
        contents: [{
          parts: [{
            text: body // メールの本文を使用
          }]
        }]
      };
      
      var options = {
        'method' : 'post',
        'contentType': 'application/json',
        'payload' : JSON.stringify(payload),
        'muteHttpExceptions': true
      };
      
      try {
        var response = UrlFetchApp.fetch(apiUrl + '?key=' + apiKey, options);
        var content = JSON.parse(response.getContentText());
        var summary = content.candidates[0].content.parts[0].text; // サマライズした内容
        
        // サマライズした内容をGoogleチャットに投稿
        UrlFetchApp.fetch(googleChatWebhookUrl, {
          'method': 'post',
          'contentType': 'application/json',
          'payload': JSON.stringify({'text': 'Subject: ' + subject + '\nSummary: ' + summary})
        });
        
        // メールを開封済みにする
        message.markRead();
      } catch (error) {
        Logger.log(error.toString());
      }
    });
  });
}

your_api_keyには自分のGemini APIキーを、your_webhook_urlにはGoogleチャットのWebhook URLをセットしてね。それでこのスクリプトをGoogle Apps Scriptのエディタに貼り付けて実行してみて!

早速実行してみましたが、なかなか完了しません。。。

Googleチャットを確認すると3つほどのサマライズされた内容が投稿されてる☹
どうやらアーカイブされたメールも全部取得してたみたいです。基本的には受信トレイに残ってるメールで、自分宛てに送られたものだけをサマライズしたいので修正をかけていきます。

これさ、受信トレイに限定してくれる?あと俺に届いたメールにだけにしよーぜ

了解!受信トレイに限定して、さらにあなたに届いたメールだけにするには、Gmailの検索クエリをちょっと調整する必要があるね。GmailApp.searchのクエリを「in:inbox is:unread」にして、受信トレイ内の未読メールだけを対象にしよう。
コードもちょっとアップデートしてみたよ。チェックしてみてね!

function summarizeAndPostToGoogleChat() {
  var apiKey = 'your_api_key'; // GeminiのAPIキーを設定
  var apiUrl = 'https://generativelanguage.googleapis.com/v1beta/models/gemini-pro:generateContent';
  var googleChatWebhookUrl = 'your_webhook_url'; // GoogleチャットのWebhook URLを設定
  
  // 受信トレイから未読メールを取得
  var threads = GmailApp.search('in:inbox is:unread');
  threads.forEach(function(thread) {
    var messages = thread.getMessages();
    messages.forEach(function(message) {
      // メールがあなた宛てのものか確認(ここでは例としてあなたのメールアドレスをチェック)
      var toAddress = 'your_email_address@example.com'; // あなたのメールアドレスを設定
      if (message.getTo().indexOf(toAddress) > -1) {
        var subject = message.getSubject();
        var body = message.getPlainBody();
        
        // Gemini APIを使ってメールの内容をサマライズ
        var payload = {
          contents: [{
            parts: [{
              text: body // メールの本文を使用
            }]
          }]
        };
        
        var options = {
          'method' : 'post',
          'contentType': 'application/json',
          'payload' : JSON.stringify(payload),
          'muteHttpExceptions': true
        };
        
        try {
          var response = UrlFetchApp.fetch(apiUrl + '?key=' + apiKey, options);
          var content = JSON.parse(response.getContentText());
          var summary = content.candidates[0].content.parts[0].text; // サマライズした内容
          
          // サマライズした内容をGoogleチャットに投稿
          UrlFetchApp.fetch(googleChatWebhookUrl, {
            'method': 'post',
            'contentType': 'application/json',
            'payload': JSON.stringify({'text': 'Subject: ' + subject + '\nSummary: ' + summary})
          });
          
          // メールを開封済みにする
          message.markRead();
        } catch (error) {
          Logger.log(error.toString());
        }
      }
    });
  });
}

このコードで、「in:inbox is:unread」を使って受信トレイの未読メールだけを対象にし、さらにmessage.getTo().indexOf(toAddress) > -1でメールがあなた宛てかどうかをチェックしてるよ。your_email_address@example.comの部分はあなたのメールアドレスに置き換えてね!
これで望んでいる動作になるはずだから、試してみて!何か他に聞きたいことがあれば、どんどん言ってね!

無事サマライズできました!

しかし、英語のメールは英語でサマライズしてしまう模様。。。更に修正をしていきます。

かなりいい感じ!でも英語のメールは英語でサマライズされちゃってるみたい。日本語でサマライズしてくれる?

日本語でサマライズしたい場合、Gemini APIへのリクエストに言語設定を追加して、サマライズの言語を指定する必要があるね。ただし、直接的な言語指定のオプションはGemini APIの標準機能としてドキュメントには記載されていないから、クリエイティブな解決策を考える必要があるよ。
一つの方法として、プロンプトに「日本語でサマライズしてください」といった指示を追加することで、APIに意図を伝えられるかもしれない。しかし、この方法の有効性は保証されないし、APIの現在の挙動に依存するから、実際に試してみないと分からない部分があるね。
もう一つのアプローチは、サマライズされた英語のテキストを別途翻訳APIを使って日本語に翻訳することだよ。この方法なら、サマライズの結果を確実に日本語で得られるけど、追加で翻訳APIの呼び出しを行う必要があるから、処理が少し複雑になるね。
もし後者のアプローチを取るなら、Google Cloud Translation APIなどを使ってサマライズした内容を日本語に翻訳するステップを追加するといいよ。ただし、これには別途APIキーが必要になるし、コストも発生する可能性があるから注意してね。
どちらの方法を試すか、または他に何かアイデアがあるか教えてくれたら、さらに具体的なサポートができると思うよ!

プロンプトを工夫してみようか!(これが一番楽な気がする)

プロンプトを工夫して、メールの内容を日本語でサマライズするよう指示することができるよね。たとえば、英語のメール内容を「この英語のメールを日本語でサマライズしてください」というような形でGeminiに送れば、Geminiがその指示に従って日本語でのサマライズを試みるはずだよ。
ここでのポイントは、Geminiに対するプロンプトに「日本語で」という指示を明確に含めること。これにより、Geminiがメールの内容を日本語でサマライズすることを期待できるよ。
コード例をちょっと修正してみたよ。メールの本文をGeminiに送る部分に、サマライズの言語指示を追加してみるね。

function summarizeAndPostToGoogleChat() {
  var apiKey = 'your_api_key'; // あなたのGemini APIキー
  var apiUrl = 'https://generativelanguage.googleapis.com/v1beta/models/gemini-pro:generateContent';
  var googleChatWebhookUrl = 'your_webhook_url'; // あなたのGoogleチャットのWebhook URL

  var threads = GmailApp.search('in:inbox is:unread');
  threads.forEach(function(thread) {
    var messages = thread.getMessages();
    messages.forEach(function(message) {
      var subject = message.getSubject();
      var body = message.getPlainBody();
      
      // 英語のメール内容を日本語でサマライズするよう指示を追加
      var promptText = "この英語のメールを日本語でサマライズしてください: " + body;
      
      var payload = {
        contents: [{
          parts: [{
            text: promptText
          }]
        }]
      };
      
      var options = {
        'method' : 'post',
        'contentType': 'application/json',
        'payload' : JSON.stringify(payload),
        'muteHttpExceptions': true
      };
      
      try {
        var response = UrlFetchApp.fetch(apiUrl + '?key=' + apiKey, options);
        var content = JSON.parse(response.getContentText());
        var summary = content.candidates[0].content.parts[0].text; // サマライズした内容
        
        // サマライズした内容をGoogleチャットに投稿
        UrlFetchApp.fetch(googleChatWebhookUrl, {
          'method': 'post',
          'contentType': 'application/json',
          'payload': JSON.stringify({'text': 'Subject: ' + subject + '\nSummary: ' + summary})
        });
        
        // メールを開封済みにマーク
        message.markRead();
      } catch (error) {
        Logger.log(error.toString());
      }
    });
  });
}

とりあえずvar promptTextの後ろに指示を入れれば良いことだけはわかった笑
一旦ここに思いのまま指示を入れてみましょう。

このメールをギャルとして日本語でサマライズしてください。(めっちゃフレンドリーになります笑)

だいぶフレンドリーになりすぎた\(^o^)/
この部分はモデルのアップデートとかでもばらつきが出るとこなので、これで完成とします!

おわりに

今回はAIをより日常の中に溶け込ませるのを目的にやってみました。DuetAIなどが日本語対応したり、もっと普及したらあまり必要のない技術になりそうです。。。AIの進歩が早すぎてついていけないですね。

最初にもお伝えしましたが、GeminiはAPIを使用してもモデルの学習に使用されます。

GPTはAPIを使用した場合、入力を学習しないので、ちゃんと作るときはGPTでやることをおすすめします!今回のはあくまでAIを身近に体験できるまでです。

GPTのAPIに特化したGPTsも作成してみようと思いますので。今回は以上!

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

コメント

コメントする

コメントは日本語で入力してください。(スパム対策)

目次