AppSheetでGemini連携植物図鑑を作ってみた【GAS】
AppSheetを使い始めて思うことが「やはり出来ない事や未だ装備されていない」ことで限界に達することが早いなぁと思う次第。今後アップデートされていって装備してほしいなと思うのが、直接ボタンを配置してGASをトリガーし、返り値を受け取れること。現在は追加や更新時をトリガーにしてしか連携出来ません。
そこでGoogle Apps Scriptのウェブアプリを利用しつつ、Gemini 1.5 Flash APIが無料で使えると耳にしたので連携するアプリを作ってみようと思います。
今回利用するAppSheet等
今回はGoogle Gemini 1.5 FlashのAPIキーを取得して、植物の名前から栽培方法を教えてくれる機能を装備します。しかし通常の方法では現在AppSheetとGASの連携ではデータの追加時や更新時などのイベントでなければ直接ボタンからトリガーは出来ないので、工夫をして表示する必要があります。
上記テンプレートからコピーを実行すると、スプレッドシートおよび画像類がすべて新しい環境にそのままコピーされます。
図:こんな感じのアプリを作る
図:スプシの構造はこんな感じで作ってます
事前準備
今回のサンプルはGeminiを使う為に、以下の手順で事前準備が必要です。
Gemini 1.5 FlashのAPIキーを取得する
2024年5月15日、Googleが発表した最新のAIモデルであるGemini 1.5 Flash。これは、Gemini Advancedのバックグラウンドで動いてるものになりますが、今回はそのAPIを直接利用します。
Bardの時とは違いGCPで色々準備してといった手間が省けるようになっています。以下の手順でGemini 1.5 FlashのAPIキーを今回は取得してみます。
- Googleアカウントにログインした状態にしておく
- こちらのウェブサイトにアクセスする
- APIキーを作成をクリックする
- 1個だけはそのままAPIキーを作成で続行できます。2つ目は既存のGCPプロジェクトを選ぶよう指示が出ます。GCPプロジェクトを指定しなかった場合には新規にGCPプロジェクトが生成されます。
- APIキーが発行されるのでコピーする
このAPIキーは無料ですが、流出することの無いように大切に保管する必要があります。
図:APIキーを発行してる画面
GAS側の準備
スクリプトプロパティにキーを保存
前述のGeminiのAPIキーについては、直接コード内に記述するのは少々問題があると思われるので、以下の手順で手動でスクリプトプロパティに格納します。今回のAppSheet連携は前回の記事のようなAutomationを利用した手法ではないので、スタンドアローンスクリプトである必要はありません(ですが、自分はStandaloneスクリプトを作って格納しています)。
- スクリプトエディタを開く
- 左サイドバーの「プロジェクトの設定」を開く
- 一番下のスクリプトプロパティの編集をクリック
- プロパティに「geminikey」として入力し、値に取得したAPIキーを入力して保存します。
図:APIキーを格納する
スプレッドシートのURLを記述
スクリプト上部にスプレッドシートのIDとして、ここにAppSheetと連結してるスプレッドシートのIDを入力して保存します。今回はスタンドアローンスクリプトとして作っている為この方法が必要ですが、スプレッドシート直でコードを実装する場合でも、バックグラウンドで動作することになるので、同様にIDを入力しておく必要があります。
図:ssidにスプシのIDを入力しておく
ウェブアプリケーションとしてデプロイ
今回のアプリはGASの関数を叩くのではなく、ウェブアプリとして出力したURLに対してGETでリクエストをしてアクションを実現しています。そのため、以下の手順でウェブアプリケーションとしてデプロイし、URLを取得しておく必要があります。
- スクリプトエディタを開く
- 右上のデプロイをクリック
- 新しいデプロイをクリック
- 種類の選択ではウェブアプリを選択し、次のユーザとしてアプリケーションを実行で誰の権限で動かすかを指定する。今回は自分自身を指定します。
- アプリケーションにアクセスできるユーザを指定する。今回は組織内ユーザに限定します。
- 最後に導入すると、ウェブアプリケーションのURLが取得できます。このURLでアクセスをします。URLの最後がexecが本番用、devがテスト用で、テスト用はデプロイをテストをクリックすると表示されますが、変更したコードがそのまますぐに反映されてしまうので、テスト用のURLで運用しないように。
- 次回以降コードを編集して再デプロイ時はデプロイを管理から同じURLにて、新しいバージョンを指定して発行することが出来ます。
図:今回は次のユーザとして実行は管理者権限のあるアカウントにて
AppSheet側の準備
AIに聞くボタンの準備
今回のアプリでは、AIに聞くボタンに於いて、前述のウェブアプリのURLに対して植物の名前をつけた状態でリクエストを投げてGeminiからの回答をウェブアプリとして表示するようにしています。その為、以下のように書き換える必要があります。
- AppSheetのアプリ編集画面を開く
- 左サイドバーのActionsをクリックし、「Gemini」をクリックする
- Targetに入ってる関数を以下のように書き換える。前述のウェブアプリのexecを含むURLを入れてあげます。
1CONCATENATE("ウェブアプリのURL?param1=",[ID]) - 右上のSAVEをクリックする
図:関数を書き換えます。
日本語化してみる
AppSheetの開発画面は英語のままではあるのですが、アプリ側の表示は殆どが日本語化することが可能です。この辺りの下りについては吉積情報さんのページで詳しく紹介されています(ただ情報がちょっと古い)。いい加減全部日本語化してほしいのですが。
ビューの名前を日本語化
アプリ下部の各種ボタン部分(フッター部分)の表記が標準では英語表記のままだったりします。これを日本語化します。
- アプリ編集画面の左サイドバーのViewsをクリックする
- 各種ViewのView nameを直接編集しちゃいます。
- 右上のSAVEをクリックする
図:このあたりはとっても簡単
詳細画面のフィールド名を日本語化
メインの画面で新しいデータの登録や、データをクリックして詳細表示した場合の各項目の表示もスプレッドシート側のフィールド名が表示されるようになっています。しかし、これを下手に弄ると面倒なので、以下の手順で表示を変えてあげます。
- 右側のプレビュー画面で実際にその詳細画面を表示する
- 各項目にカーソルをわせて鉛筆マークをクリックする
- Edit Columnをクリックする
- Column Nameがフィールドと連結してる名前。ずっと下にあるDisplayをクリックし、Display Nameに「"植物の名前"」といったように数式として入力する
- 右上のSAVEをクリックする
これでフィールド名とは別の名称をセットすることが可能です。
図:別名をセットすることが可能です
システム側の表記の日本語化
ダイアログの名称や、OK・Cancelといったシステム上の表記が全部英語になっています。これを主要なものだけ日本語にしてみようと思います。以下の手順で書き換えるだけです。
- アプリ編集画面の左サイドバーより、Settingsをクリックする
- Localizationをクリックする
- Customize System Textの中にたくさん項目があります。これらの主要なものを日本語での名称に書き換える
- 右上のSAVEをクリックする
図:システム表記は殆ど日本語化可能
実装してみる
スプレッドシートについて
今回のAppSheetはデータの読み書き土台としてスプレッドシートを利用しています。このスプレッドシートですが、AppSheet上でユーザを追加してもファイルそのものにはアクセス権が付与されません。
作成者はアクセス出来るのは当然としても、編集権限を付けてAppSheetにアプリを弄れるメンバーについては、別途対象のスプレッドシートに必要に応じてアクセス権を付けてあげる必要があります。
そして、AppSheetでスプレッドシートを元にアプリを作る場合には以下のようなスプシの構造が必要になります。
- 必ずユニークな連番を記述するID列を設けること。
- 今回のテーマでは取り上げていませんが、テーブル間を結合する場合には、子テーブル側にID列とは別に親ID列を設けること。
- タイトル行は必ず1行目とし、タイトル行を複数行にしたりしないこと。
- またセルの結合など一切のよけいな装飾を行わないこと。
- タイトル行に同じ名称の重複する列を作らないこと。
- ID列の値は半角数字や文字列が使えますが全角などは使わないこと。
こういったアプリケーションを作るうえでのスプシ上での設計を守らず始めてしまう人がいるので、「統計表における機械判読可能なデータ作成に関する表記方法について」であったり、同様のことをExcel上級編講座でも扱っていますのでよく確認してから始めましょう。
AppSheet側の実装
今回はスプシから作成後にカスタマイズを加えた領域についてここで列挙します。
フィールド設定
左サイドバーのDataを開いて、アプリが使いやすいように以下の設定を行っています。
- 画像フィールドはTypeをImageに変更しています。
- 画像URLは、formulaにて画像フィールドをText関数でURL取得を自動で行うようにしています。
- IDに対してはInitial ValueにてUNIQUEID関数を指定し、自動でIDを振るようにしています。
- 撮影日フィールドはTODAY関数にて自動で今日の日付が入るようになっています。
- いくつか手入力不要のフィールドはShowを外しています。
- 右上のSAVEをクリックして保存する
図:ここでの設定も重要な項目です
マップ用の処理
マップ用のスライスを作成する
マップのビューをそのまま追加すると、マップ用のピンを追加するボタンなどが表示されてしまい、これがそのままだと非表示に出来ません。そこで、メインのDataをフィルタして作る「スライス」と呼ばれるデータセットのようなものを用意して、そのスライスに対してビューを作ると消すことが可能になります。
※ここでの設定でマップビューにてPlace Pinボタンを非表示にすることが出来ます。
- 左サイドバーのDataをクリックする
- データベースの横の+をクリックする
- Create a new slice for xxxをクリックする
- Slice Nameを適当に入力する
- Update modeをUpdatesのみにする(これでPlace Pinが表示されなくなる)
- 右上のSAVEをクリックする
図:スライスを作るけれどフィルタはしない
マップビューを追加
メイン画面下に表示させるマップ一覧のビューを追加しておきます。これをしておかないと詳細画面からのマップをタップした時に何も表示されません。
- 左サイドバーのViewをクリックする
- Primary Navigationの+ボタンをクリックして、Create New Viewをクリックする
- Viewが追加されるので、Positionをnextに変更し、View Typeをmapに変更します
- For this dataにて前述で作ったスライスを指定する
- Map columnは位置情報フィールドを指定する
- 右上のSAVEをクリックして保存する
これでマップ表示はバッチリできるようになりました。
図:マップビューの設定画面
マップのピンのフォーマット
デフォルトのままだと、位置情報を反映したピンがやたら小さく薄緑色で見づらいという状態です。これを解消するべく、ピンのフォーマットを変更します。
- 左サイドバーのView => Format Rulesを開く
- Add format Rulesという+ボタンをクリックする
- Rule Nameを適当に入力
- Format these columns and actionsでは位置情報を選択する
- Iconでわかりやすいアイコンを選択します。
- Highlight colorは赤を選択しました。
- 右上のSAVEをクリックして保存する
これでわかりやすい赤いピンのアイコンになり、詳細表示画面でも位置情報のところにアイコンが表示されます。
図:ピンがこれでわかりやすくなる
ギャラリービューを追加
画像での一覧も作りたい所。ということで、新しいビューとしてギャラリーを追加します。
- 左サイドバーのViewをクリックする
- Primary Navigationの+ボタンをクリックして、Create New Viewをクリックする
- Viewが追加されるので、Positionをlaterに変更し、View Typeをgalleryに変更します
- Sort byでは撮影日をAscendingとしました(降順ソート)
- Image SizeはMediumとしました
- Iconを適当に選択
- 右上のSAVEをクリックして保存する
これだけで画像での一覧表示に自動的になります。非常に簡単。
図:ギャラリービューを追加する
AIに聞くボタン
今回のアプリの肝の1つがAIに聞くボタン。すでに事前準備でも説明済みの項目ですが、これを追加する方法です。
- 左サイドバーのActionsをクリックする
- Add Actionの+ボタンをクリックする
- Action nameにはGeminiとでも入力する
- Do ThisはExternal : go to a websiteを選択する
- Targetには事前準備にもあるようにGASのexecのURLとID列の2つをCONCATENATE関数で結合したものを入力する
- PositionはProminentを選択する
- Displayを開き、Display Nameには「AIに聞く」と入力(ちなみにこの名称は改行が出来ない)
- 右上のSAVEをクリックして保存する
図:AIに聞くボタンの実装
画像の保存先の指定
デフォルトだとGoogle Driveのスプレッドシートファイルと同じディレクトリ内にフォルダが作成されて、そこに写真はすべて格納されるようになっています。今回は特にその辺りを変えていないのですが、アップロード先を変更することが出来ます。
- 左サイドバーからDataをクリック
- 画像フィールド横の鉛筆マークをクリックする
- Type DetailsのImage/File folder pathが該当箇所になる
- ルート直下からみて、「/appsheet/image」といった指定をすれば、直下のappsheetディレクトリ=>imageディレクトリ内に保存がなされるようになります。
図:アップロード先を変更出来る
GAS側の実装
GASのコード
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 |
//引数に基づいて問い合わせを行うメイン関数 function doGet(e) { //受け取るパラメータを用意する var param = e.parameter.param1; var output = HtmlService.createTemplateFromFile('index').evaluate().getContent(); var html = HtmlService.createTemplate(output + "<script>\n" + "doIt( " + JSON.stringify(param) + ");\n</script>") .evaluate() .addMetaTag('viewport', 'width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no, minimal-ui') .addMetaTag("mobile-web-app-capable", "yes") .addMetaTag("apple-mobile-web-app-capable", "yes") return html; } //対象のIDを持つシートのデータを元に栽培法をGeminiに聞いてみる function getanswer(recid){ //geminiのapi keyを取得する let prop = PropertiesService.getScriptProperties(); let apikey =prop.getProperty("geminikey"); //スプレッドシートを探索し対象のレコードを見つける let ss = SpreadsheetApp.openById(ssid).getSheetByName("plants").getRange("A2:G").getValues(); let targetname = ""; for(let i = 0;i<ss.length;i++){ //レコードを一個取り出す let rec = ss[i]; //recidと一致するレコードを見つける if(rec[0] == recid){ targetname = rec[1]; break; } } //対象のレコードが見つからなかった場合 if(targetname == ""){ return "Error : 対象のレコードが見つかりませんでした。" } //プロンプトを作成する let prompttext = targetname + "の簡単な説明と栽培方法について教えてください。水やりや肥料、土の内容について注意点も加えてください。回答にはMarkdownを使わず、HTMLを使ってください" //レコードが見つかった場合にはGeminiにリクエストする // リクエストボディを作成する。 var body = { "contents": [ { "parts": [ { "text": prompttext } ] } ], "generationConfig": { "temperature": 0.4, "topK": 50, "topP": 0.1, "maxOutputTokens": 2048, "stopSequences": [] } }; // リクエストを送信する。(Gemini 1.5 Flashを使用) var response = UrlFetchApp.fetch('https://generativelanguage.googleapis.com/v1beta/models/gemini-1.5-flash-latest:generateContent?key=' + apikey, { method: 'post', contentType: 'application/json', payload: JSON.stringify(body) }); // レスポンスをパースする。 var responseJson = JSON.parse(response.getContentText()); // 生成されたテキストを返す。 let answer = responseJson.candidates[0].content.parts[0].text; //テキストを返す return JSON.stringify(answer); } |
- doGetはパラメータを受け取ってdoIt関数で即時実行できるようにウェブアプリを生成します。
- getanswer関数がウェブアプリ側からのリクエストに応じてGeminiに対して問い合わせをするメインの関数です。
- パラメータはレコードのIDが入ってるので、スプシを探索。見つかったら植物名を取得しておきます。
- プロンプトでは、植物の栽培法および簡単な説明をする命令を入れておく。またそのままだと回答がMarkdownで返ってきてしまうのでHTMLで返すように追記しておく。
- Gemini 1.5 FlashのリクエストエンドポイントのURLは「https://generativelanguage.googleapis.com/v1beta/models/gemini-1.5-flash-latest:generateContent?key=」となっています。
- リクエストをして返ってきた答えをウェブアプリ側に返しています。
- generationConfigについては、いい加減が答えが返ってこないようにちょっと絞り気味で設定しています。
- 2024年6月、返り値に関してJSONで返してくれるオプションがGemini 1.5に装備されたようで、よりプログラマブルにAIのAPIを利用可能になっています。
HTMLのコード
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
<!DOCTYPE html> <html> <head> <base target="_top"> <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script> <script> //引数を受け取って起動時に即時処理する function doIt(data){ google.script.run.withSuccessHandler(onSuccess).getanswer(data) } //GASからの解答を取得する async function onSuccess(data){ //解答を取得する let answer = JSON.parse(data); //表示を切り替える $("#answer").css("display", "block"); $("#circle").css("display", "none"); //解答内容をはめ込む $('#answer').html(answer); } </script> </head> <body> <div id="circle" style="text-align: center;display:block"> <img border="0" src="https://officeforest.org/wp/library/ProgressSpinner.gif" width="128" height="128"><br> <p>Geminiに問い合わせ中・・・</p> </div> <div id="answer" style="display:none"> </div> </body> </html> |
- こちら側は非常に単純。起動時にdoIt関数が植物の名前を受け取って、getanswer関数へリクエストをしています。
- 返ってきた答えをHTMLに差し込み、ローダーの表示を非表示にしています。オカシイ場合にはエラーが表示されるようになっています。
植物図鑑を使ってみる
AppSheetアプリを導入する
今回スマートフォン向けとして作ってるので、スマフォにAppSheetアプリを入れます。
アプリを構築したアカウントでログインし、対象のアプリをギャラリーから見つけて開くだけ。
メイン画面(植物図鑑)
メイン画面はこれまで作成した図鑑の植物たちが一覧で表示されます。検索することで目的の植物に絞り込みすることも可能です。これらの機能はAppSheetの標準機能で、自身でコーディングする必要はありません。
画像も表示されていますがこれも自動で判断してこのように作ってくれます。結構こういうUIの作り込みだけでも相当時間が掛かるので、AppSheetをフロントエンドに使うというのは良い手段です。
図:ずらっと一覧表示
詳細表示
メイン画面等で対象の植物をタップすると中の詳細な情報が出てきます。この画面から中身を書き換える編集画面へ移動することが出来ます。マップをタップすれば対象のマップまでジャンプしてくれます。カメラを起動して写真を取ったり、取得済みの写真を登録することも可能です。
また、AIに聞いてみるボタンを押すと、レコードのIDを元にGASで作成したウェブへ引数が渡されて、Geminiで栽培方法についての情報を表示してくれます。
いちいち栽培法などをChrome起動して、探して調べる => 詳細に書かれていないページでまた戻るみたいな面倒な行き来をする必要がありません。
図:AI連携機能つけました
AIに聞いてみる
詳細画面からAIに聞いてみるボタンを押すと、GASのウェブアプリの画面が開かれて、Geminiからの返答を表示するようにしています。植物名がオカシイ場合にはエラーとだけ表示されます。
画像をアップロードして、画像から判定させるといったような応用も出来るのではないかと思います。AppSheetでは実現が難しい機能をGASがあれば容易に壁を突破できます。
※早く、通常のボタンから直接GASを叩けるようにしていただきたいものです。
図:聞いてみた結果
マップ画面
今回のアプリは位置情報を記録できるフィールドを用意しています。新規作成時にボタンを押すと緯度経度情報が記録され、詳細画面でマップをタップすると対象のマップまでジャンプします。
またマップビューを入れておかないとジャンプしてくれないので入れてあります。登録した植物の緯度経度情報がマップに反映されて一括で把握することが出来、ピンをタップすると対象の植物の詳細画面が開かれます。
この辺りが簡単に構築できちゃうのがAppSheetのいい所です。
図:マップで撮影場所を一括で把握
ギャラリー画面
ギャラリー画面はメインの一覧画面の画像オンリーバージョン。こちらのほうが目的の植物を見つけやすいという特徴もあります。タップすれば詳細表示画面となります。
図:でかい画像で一覧表示
関連リンク
- GoogleSheetsでGeminiを使おう(初心者向け全行程解説)
- Generative Language API - REST
- Google AppSheet Coreライセンスでできることメモ
- AppSheet と ChatGPT連携させてみた!~手順をイチから解説!~|keita
- Show Actions button based on specific view
- 【AppSheet】脱初心者!ボタンを条件で出し分けるにはCONTEXT()関数が使える件
- AppSheet実践編シリーズ⑦~ビュータイプ活用術を学ぼう!!~
- How to hide pin icon (for add new data) from map view?
- AppSheetでタスク管理アプリ(第4回)スライスでデータを切り出す
- Appsheetアプリにて読み込んだ画像をSpreadsheetで表示する方法が分かりません。
- 【最新情報】Gemini in AppSheet (旧 Duet AI in AppSheet )を使ってみた!
- Gemini in AppSheet - Google Workspace Marketplace
- Gemini in AppSheet - Release Note