Google Apps ScriptからGemini API?で質問してみた【GAS】

かつては様々なAI分野では先を行っていたハズのGoogle。コロナ禍が明けてみたら、周回遅れもいいところみたいな感じでわずか数年でChatGPTStable DiffusionといったAIプログラムに大きく差を付けられてしまいました。そんな中焦って表に出したGoogle Bardですが、大爆死して株価急落というのは記憶に新しい所です。

ここから巻き返すのはかなりの大変だと思いますが、Google Workspaceアカウントでも使えるようになり、またまだ表沙汰になっていないのですが、Google Bard APIがどうも叩けるらしいという情報を得て、Google Apps Scriptで挑戦してみました。

※2024年2月8日、これまでGoogle Bardと呼ばれていたサービスをGoogle Geminiに改称しパワーアップしました。Webでテストする場合はこちらから利用可能です。

2023年アップデート Google Workspaceの新機能

今回利用するサンプルスプレッドシート

但し、2023年現在、まだAPIからの実行では日本語が使えない為、日本語の質問は一度英語に翻訳し質問=>返答を再度日本語に翻訳といったまどろっこしい手順を踏む必要があるため(Bardそのものは既に日本語が使えるのですが)、翻訳のスクリプトも併用が必要です。

図:ウェブで使ってみた事例

Google Apps Scriptでは簡単に翻訳できる【GAS】

事前準備

概要

2023年7月現在、Google Bard APIというものがリリースされているわけではなく、Bard APIで利用されてるVertex AI APIというRest APIがリリースされたことで利用が可能になっています。これをGoogle Apps Scriptから叩きに行くわけです。ただこのAPIはChatGPTのようなシンプルなチャットの為のAPIというわけじゃなく、様々な言語モデルと方向性、トレーニングなどが重なり合ってるAPIで、チャットはその1部分に過ぎないといった感じです。

利用料金

ChatGPTと比較すると非常に料金体系がわかりにくいものになっています。前述のように単純なAPIではないので、テキスト、画像、動画、それに伴うディスクやCPUなどでも大きく変わってきます。今回は単純にテキストでリクエストして簡単に返してもらうだけなのでそこまで気にするような金額にならないと思いますが・・・

APIを有効化

GCP側で今回利用するAPIを有効化する必要性があります。

  1. GCPを開き、サイドバーからAPIとサービスを開きます。
  2. 上部にある「APIとサービスの有効化」をクリック
  3. 「Vertex」を検索し、Vertex AI APIクリックします。
  4. 有効化をクリックします。

図:今回はこのAPIを有効化する

プロジェクトを移動する

Google Apps ScriptのプロジェクトをGCP側と連結する手順は以下の通り

  1. Google Cloud Consoleを開く
  2. 左上にある▼をクリックする
  3. ダイアログが出てくるので、新規プロジェクトを作るか?既存のプロジェクトを選択する。この時、Google Workspaceであれば選択元は「自分のドメイン」を選択する必要があります。
  4. プロジェクト情報パネルから「プロジェクト番号」をコピーする
  5. 同じくプロジェクトIDもコピーしておく(こちらはコード内で利用します)
  6. 対象のGoogle Apps Scriptのスクリプトエディタを開く
  7. サイドバーからプロジェクト設定を開く
  8. プロジェクトを変更ボタンをクリック
  9. GCPのプロジェクト番号に、4.の番号を入れてプロジェクトを設定をクリック

図:プロジェクト番号をコピーしておきます

図:プロジェクト変更画面

appsscript.jsonに記述を追加する

スクリプトエディタの左サイドバーから「プロジェクト設定」を開き、「appsscript.json」マニフェスト ファイルをエディタで表示するにチェックを入れて、appsscript.jsonを表示する。その後そのファイルを開き、以下のように記述を行います。必須の作業です。これをしてしまうと、今後メソッドを追加したときに追加の認証は手動で、Scopeを入れてあげないと認証されないので要注意。

{
        ...
       "oauthScopes": [
              "https://www.googleapis.com/auth/cloud-platform",
              "https://www.googleapis.com/auth/userinfo.profile",
              "https://www.googleapis.com/auth/script.external_request"
       ],
       ...
}

これを入れてあげないと403などのエラーになってしまうので要注意。GCPのAPIを叩く場合には必須の作業です。

初回認証をしておく

ここまでの準備で適当な関数を用意して実行すると認証が始まります。これをやっておかないと、スコープが足らないであったり、コードが初回で旨く動かないことが稀にあるので必ず実行しておきましょう。

クイックスタートを覗いてみる

Vertex AI APIクイックスタートと様々なユースケースを網羅してるVertex Model Gardenを覗いてみます。今回はChatGPTに対するBardの比較ということなので、テキストチャットの項目を調べてみたい。チャットプロンプトを試してみるという項目があるので、見てみるとAPIのエンドポイントやら追加するパラメータに関しての情報が記載されているので、これをもとにGASで組み立ててあげます。

また、Vertex Model Gardenに於いては、ものすごい色々な情報が記載されていて圧倒するのですが、モデル検索で「chat」と入れて絞り込むと出てくる「PaLM 2 for Chat」というものがそれに該当するので、開いてみる。クイックスタート同様に詳細な内容が出てきます。プロンプト設計を開くをクリックすると、実際のチャット画面とプロンプト項目が出てきて、微妙なバランスを調整しながらの最終的なコードを出力してくれます。

但し日本語に対応してるわけじゃないので、日本語対応のGoogle Bardと違ってローカルすぎる質問だと焼肉がBBQのメニューとしてアメリカンな答えが返ってきますので要注意。コードはPythonとCurlで叩いたときのものが出てくるので、Google Apps Scriptで参考にする場合は後者のcurlの構文を取得しましょう。

以下が得られた今回のサンプルコードです。bearer tokenが使えるようなので、OAuth2認証でもいけそうですね。というより、GASで叩くならばScriptApp.getOAuthToken()で行けるのではないかと。GCPは身内なんだし。

なお、parametersの様々な要素に関してクイックスタートにも記載がありますが、こちらにもドキュメントが用意されています。

API_ENDPOINT="us-central1-aiplatform.googleapis.com"
PROJECT_ID="ここにプロジェクトIDを入れる"
MODEL_ID="text-bison@001"

curl \
-X POST \
-H "Authorization: Bearer $(gcloud auth print-access-token)" \
-H "Content-Type: application/json" \
"https://${API_ENDPOINT}/v1/projects/${PROJECT_ID}/locations/us-central1/publishers/google/models/${MODEL_ID}:predict" -d \
$'{
    "instances": [
        {
            "content": "List the 10 most popular yakiniku menu items
"
        }
    ],
    "parameters": {
        "temperature": 0.4,
        "maxOutputTokens": 256,
        "topP": 0.8,
        "topK": 28
    }
}'

図:質問内容がローカルすぎた事例

ソースコード

前述のVertex AI API Model Garden等のサンプルコードをもとにGASでアクセストークンを使って叩いてみようと思います。

GAS側コード

var apiendpoint = "us-central1-aiplatform.googleapis.com"
var modelid = "text-bison@001"
var projectid="ここにGCPプロジェクトのIDを入れる(番号じゃないよ)"

//Vertex AI APIを叩く
function mr_vertex() {
  //リクエストを投げるエンドポイントを構築
  let endpoint = `https://${apiendpoint}/v1/projects/${projectid}/locations/us-central1/publishers/google/models/${modelid}:predict`

  //リクエストボディ
  let payload = {
    "instances": [ 
      { "content": "List the 10 most popular yakiniku menu items " }
    ],
    "parameters": {
      "temperature": 0.4,       //回答のランダム具合
      "maxOutputTokens": 1024,  //最大返り値のワード数
      "topP": 0.8,              //選択範囲の制限値
      "topK": 28                //選択可能性
    }
  }

  //リクエストヘッダ
  let headers = {
    "Authorization":"Bearer " + ScriptApp.getOAuthToken(),
    "Content-Type": "application/json"
  }

  //リクエストオプション
  let options = {
    method: "POST",
    headers: headers,
    payload: JSON.stringify(payload),
    muteHttpExceptions: true
  }

  //リクエスト実行
  const response = UrlFetchApp.fetch(endpoint, options);

  //リクエスト結果を取得する
  const result = JSON.parse(response.getContentText());

  //回答だけを取り出す
  const content = result.predictions[0].content;

  //日本語に変換
  console.log(LanguageApp.translate(content,"en","ja"));

}
  • 予め前述で控えておいたGCPのプロジェクトIDを変数に入れておくことを忘れずに
  • Vertex Model Gardenで出力したcurlのコードをベースにPOSTでリクエストするコードに書き換えています。
  • apiendpointは他のリージョンのエンドポイントでも動くのではないだろうか?
  • payloadのcontentがチャットでこちらから問い合わせる文章になります。parameterが回答に対するランダム性などのオプション項目
  • 認証はGAS上で済ませてるので、ScriptApp.getAuthTokenでアクセストークンはすぐに取得出来る。便利。
  • POSTで投げて、resultの中のcontentが返り値。これをLanguageAppで翻訳すると日本語になって出力される。
  • Vertex AI APIのベースエンドポイントは複数リージョンあるので、上記のus-central以外でもリクエストは投げられるのではないかと。

10回もリクエスト投げてしまったけれど、果たしていくらくらい請求くるかな?

返り値

{
  "predictions": [
    {
      "safetyAttributes": {
        "categories": [
          "Health"
        ],
        "blocked": false,
        "scores": [
          0.1
        ]
      },
      "content": "1. **Beef tongue** (gyu-tan) is a thinly sliced, chewy cut of beef that is often served with ponzu sauce or salt. It is a popular choice for yakiniku because it is relatively inexpensive and has a rich, beefy flavor.\n2. **Marinated beef** (sukiyaki-gyu) is a thinly sliced, marinated cut of beef that is cooked at the table in a hot pot. It is typically served with a variety of dipping sauces, such as ponzu sauce, sesame sauce, or soy sauce.\n3. **Lamb** (hitsumabushi) is a thinly sliced, grilled lamb that is often served with a variety of sauces, such as teriyaki sauce, garlic sauce, or miso sauce. It is a popular choice for yakiniku because it is flavorful and has a slightly chewy texture.\n4. **Chicken** (tori) is a thinly sliced, grilled chicken that is often served with a variety of sauces, such as teriyaki sauce, garlic sauce, or soy sauce. It is a popular choice for yakiniku because it is relatively inexpensive and has a mild flavor.\n5. **Pork belly** (butabara) is a thinly sliced, grilled pork belly that is often served with a variety of sauces, such as teriyaki sauce, garlic sauce, or soy sauce. It is a popular choice for yakiniku because it is flavorful and has a slightly fatty texture.\n6. **Fish** (sakana) is a thinly sliced, grilled fish that is often served with a variety of sauces, such as ponzu sauce, sesame sauce, or soy sauce. It is a popular choice for yakiniku because it is light and refreshing.\n7. **Tofu** (tofu) is a soft, white block of soybean curd that is often grilled or fried. It is a popular choice for yakiniku because it is a good source of protein and is relatively low in calories.\n8. **Vegetables** (yasai) are a popular side dish for yakiniku. They are often grilled or stir-fried and served with a variety of sauces, such as teriyaki sauce, garlic sauce, or soy sauce.\n9. **Rice** (gohan) is a staple of Japanese cuisine and is often served with yakiniku. It is typically cooked in a rice cooker and served with a variety of toppings, such as furikake, pickled vegetables, or seaweed.\n10. **Miso soup** (miso shiru) is a traditional Japanese soup made with miso paste, dashi stock, and vegetables. It is a popular side dish for yakiniku and is often served at the beginning of the meal.",
      "citationMetadata": {
        "citations": []
      }
    }
  ],
  "metadata": {
    "tokenMetadata": {
      "outputTokenCount": {
        "totalTokens": 555,
        "totalBillableCharacters": 1845
      },
      "inputTokenCount": {
        "totalTokens": 12,
        "totalBillableCharacters": 37
      }
    }
  }
}
  • Contentの中に回答が入っています。英語ですが・・・
  • また、metadataの中にはリクエストで送ったトークンと、回答で返ってきたトークン数が記録されているので、だいたいの料金とかが想像できそうです。

動画

Chat GPT vs Google Bard for JavaScript, Apps Script Code

関連リンク

 

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)