🐬

「さっきからなんなんだ このふわっとした指示は!」をどうにかしたいスプレッドシート用チャットを作ってみる

2024/02/21に公開

スプレッドシートで資料を作っていると「もうちょっと◯◯な感じの表にできるかな?」という「ふわっとした指示」を言ったり言われたりするかと思います。

そこで、「ふわったとした指示」や「簡単な手書きメモ」などを元に、表の見た目を良い感じに変更してくれるチャットを試作してみました。

どんなチャット?

スプレッドシートのサイドバーでお願いするとシートが更新されるというもので、Copilot Pro や Duet AI(Gemini) for Workspace の超簡易版といった感じです。

図 1-1 チャットで表を更新(1.5 倍速で再生しています)

簡単な値の挿入や変更などもできますが、基本的には「交互の背景色」を変更することに偏った作りとなっています。

リポジトリー:

https://github.com/hankei6km/test-sheets-addon-inline-chat

仕組み

Gemini API の関数呼び出しを使っています。

https://ai.google.dev/docs/function_calling?hl=ja

いくつか使いそうな関数を定義しておき、プロンプトにシートの情報を含めることでシートの更新を自動化しています。

リスト 2-1 関数定義

https://github.com/hankei6km/test-sheets-addon-inline-chat/blob/e976149e94356403372d4701a900e6942dd0b746/src/gemini.ts#L140-L296

リスト 2-2 UI(サイドバー)で入力されたプロンプト

売上列の合計の式をセットして

リスト 2-3 実際に送信されるプロンプト

 {
    "parts": [
      {
        "text": "Goolge SpreadSheets についての要望または質問に対応してください。"
      },
      {
        "text": "## 要望または質問\\n\\n売上列の合計の式をセットして}\\n"
      },
      {
        "text": "## 条件\\n\\n 要望についてはできるだけ関数呼び出すを使ってシートを更新してください。\\n シートの更新が難しい場合や質問の場合はテキストで返答してください。 \\n"
      },
      {
        "text": "## 知識\\n\\n以下はアクティブシートの状態\\n\\nシート名: シート7\\n\\n\\n\\n\\n\\n\\n\\n以下はシート内の A! から収められている値と式の二次元配列です。\\n\\n```json\\n[[\\"品名\\",\\"単価\\",\\"個数\\",\\"売上\\"],[\\"消しゴム\\",50,10,\\"=B2*C2\\"],[\\"ノート\\",100,20,\\"=B3*C3\\"],[\\"ペン\\",150,30,\\"=B4*C4\\"],[\\"鉛筆\\",200,40,\\"=B5*C5\\"],[\\"定規\\",250,50,\\"=B6*C6\\"],[\\"シャーペン\\",300,60,\\"=B7*C7\\"],[\\"ファイル\\",350,70,\\"=B8*C8\\"],[\\"クリップ\\",400,80,\\"=B9*C9\\"],[\\"ホッチキス\\",450,90,\\"=B10*C10\\"],[\\"合計\\",\\"\\",\\"\\",\\"\\"]]\\n```\\n\\n"
      }
    ]
  },

これで以下のような返答が得られるので、シート(GAS)側で関数を実行します。

リスト 2-4 返答(関数呼び出し部分の抜粋)

[
  {
    "functionCall": {
      "name": "setValuesOrFormulas",
      "args": {
        "a1Notation": "D11",
        "valuesOrFormulas": [
          [
            "=SUM(D2:D10)"
          ]
        ]
      }
    }
  }
]

このような感じで関数呼び出しにより、自然言語での指示を通常のコード実行に落とし込むことができます。ただし、1 回の指示で複数のタスクを実行したり、複雑な関数の定義はまだちょっと不安定なようです。

また、マルチモーダルで使える gemini-pro-vision では関数呼び出しが使えません。よって、マルチモーダルで使う場合は、ちょとひねる必要があります(この辺は後述します)。

試してみる

いくつか「ふわっとした指示」を想定して試してみます。

なんでもいいから簡単なサンプルの表を作って

サンプルの表を作るのも地味に面倒なのでまるなげしてみます。ちょっと試してみた感じだと「パソコン教室で使う Google スプレッドシート用の教材を作っています」みたいにすると良い感じになる印象です。

図 3-1 サンプル作成用のプロンプト入力

列名のみのシートに「パソコン教室で使う Google スプレッドシート用の教材を作っています。文房具の売上表のサンプルとして適当な値と式を 10 品目追加して。」と入力しているスクリーンショット

図 3-2 Run すると値や式が挿入される

列名の下に「消しゴム」などの文房具の単価や売上が 10 行挿入されたスクリーンショット

列名などは無くても良い感じに生成されるときもありますが、少数のサンプルで誘導すると安定するかと思います。

図 3-3 1 行目のデータで誘導し残りの行を追加

1 行目にサンプルとなるデータを入力し範囲選択、その後にプロンプトで行を追加したスクリーンショット

この辺はアプリの Gemini などでもできますが「式もセットされる」という利点があったりします。 (後述しますが、無制限に式をセットするのも危ないので簡単なものだけに限定しています)

表の見た目をシンプルでクールな感じにして

こういうとき、「いまどきは罫線少なめで交互の背景色をなんかいい感じにすればいいんだよね、たぶん」という風に推測できます(個人の感想です)。

ということで、範囲指定しておき交互の背景色とヘッダーについて配色の方法を指定します。

図 3-4 チョコミントアイス風にした表(範囲選択しているので実際の色は少し違います)

ヘッダーが濃いめの緑色で、交互の背景色がパステル調の緑になった表のスクリーンショット

ヘッダーがちょっと濃いめなので明るめの色に変更してもらいます。

図 3-5 ヘッダーの文字が見やすくなりました

「ヘッダーの色をちょっと明るめにして」という指示で色を変更したスクリーンショット

操作自体はマウスで普通にやった方が簡単そうですが、配色の指示は「もうちょっと明るい感じで」みたくなるので少し楽になるかなと。

このメモと同じような見た目にして

手書きのメモを渡されたときを想定してみます。この場合はマルチモーダルの出番ですが、現状では関数呼び出しをサポートしていないので、以下のように対処してみます。

今回は手書きメモを用意するのがちょっと面倒だったので、Google ドライブから draw.io で作った図を使います。

図 3-6 色が付いた表を含む図

diagram.net で表を図として描画しているスクリーンショット

マルチモーダル用のチャットで配色をどのようにするのか確認します。

図 3-7 Google ドライブのファイルを指定し配色を確認する

メモ(図のファイル)のサムネイルからプロンプトにより配色を確認しているスクリーンショット

プロンプト:

画像内の表について、ヘッダーなどに使われている色を調べてください。


アクティブシートで選択されている表を画像の表と同じような配色にする場合、以下の値はどのようになりますか?


- 交互の背景色の1行目の色
- 交互の背景色の2行目の色
- ヘッダーの色

返答:

 ## 回答


画像の表と同じ配色にする場合、以下の値になります。


- 交互の背景色の1行目の色: #C5E0B4
- 交互の背景色の2行目の色: #FFFFFF
- ヘッダーの色: #9CCC65

上記の返答から配色部分をコピペして通常のチャットで指示します。

図 3-8 図の中の表と似たような配色になる

プロンプトを実行しヘッダーなどが薄い緑になったスクリーンショット

メモと見比べるとちょっと違う色で、1 行目と 2 行目の色指定も逆ですが、そこそこ良い感じかと思います。

現状はこのような感じで少し面倒ですが、マルチモーダルで関数呼び出しがサポートされたら、もう少し簡単にできるかと思います(たぶん)。

また、関数呼び出しが複雑なタスクを安定して処理できるようになれば、以下のようなメモも対処できるかもしれません(願望)。

図 3-9 特に理由のないふわっとした指示がジェミナイを襲う!

配色の他に文字の太さの指定や、円グラフもお願いしている図のスクリーンショット

応用

マルチモーダルのチャットを使った場合、指示や入力の幅が広がりそうな可能性を感じています。

いまのところ機能的に実現は難しいのですが、いくつか応用できそうな操作を試してみます。

画像で操作対象を指定する

イメージ的には「かこって検索」のようなことができそうかなと思っています。

https://www.watch.impress.co.jp/docs/news/1561845.html

現状、GAS でシート上に手書きするような UI は作れないので(作れないですよね?)、スクリーンショットを使ってみます。

図 4-1 スクリーンショットの列を囲って指定

シートのスクリーンショットの「品名」列を赤線で囲っている

今回は少しいじわるして、赤線で見えなくなるセルを作ってあります。

この画像を指定し、以下のプロンプトを指定します。

プロンプト:

画像はアクティブシートのスクリーンショットです。

赤線で囲った列を調べてください。

列の各値を表示してください。

返答は以下のようになります。

図 4-2 画像とプロンプトを指定して Run

マルチモーダル用のチャットで画像をと指定し、上記プロンプトを Run したスクリーンショット

返答:

 赤線で囲った列は、シート内の「**品名**」という列です。

列の各値は、

* 鉛筆
* シャーペン
* 消しゴム
* ペン
* 定規
* ハサミ
* ファイル
* ホッチキス
* クリップ
* カッター
* 修正テープ

です。

画像では判別できない情報が含まれているので、「画像から操作対象を特定しテキストプロンプトの情報を利用した」と考えられます。

この例くらいなら範囲選択の方が簡単ですが、いろいろ応用できかるかなと思っています。

メディアファイルを入力ソースにする

値の更新などもテキスト以外にメディアファイルを使うことができそうです。

図 4-3 入力に利用する画像(5 つの赤いイチゴ : Photo by Chris Bayer)

図 4-4 画像を元に表内で変更する箇所を確認する

「いちご」の個数が入力されているセル(C7)を変更するように返答されているスクリーンショット

図 4-5 変更箇所を普通のチャットにコピペして Run

「いちご」の個数のセル(C7)が"5"に変更されたスクリーンショット

上記では写真を使っていますが、動画を読み込ませて「通り過ぎた車を車種別に集計し表へ反映させて」みたいなことができたらいいな、と妄想しています。

考慮点

UI 的に「変更前にプレビュー欲しいな」とかいろいろあるのですが、ここでは Gemini API と関数呼び出し関連についていくつか。

きっちりした返答が要求されるときはまだ難しい

今回は外観を扱っているので「絶対にこの返答でないとダメ」という状況は少ないと思います(場合にもよりますが)。

一方で、表の値を扱うときは「きっちりした返答」が必要になりますが、思ったような挙動にするのは難しいです。たとえば「売上の多い順に行を並べ直して」みたいな指示は正しい結果にならないことがほとんどでした。

私は Copilot Pro や Duet AI(Gemini) for Workspace を使ってないので詳しくはわかりませんが、いくつか記事を読んだ感じではまだハードルが高いのかなと。

https://ascii.jp/elem/000/004/183/4183975/

シートの情報を含めたプロンプトを組み立てるのも難しい

これは私のプロンプト作成能力も原因なのですが、汎用的に使えそうなプロンプトを組み立てるのはやはり難しかったです。

たとえば、最初はプロンプトに「アクティブセルの情報」も含めていたのですが、「範囲指定しているのにアクティブセルのみ変更しようとする」ことが多かったので「どうするのがよい?」と四苦八苦しています。

また、装飾関連の指示を充実させるなら、フォントや罫線などより多くの情報も含める必要がありそうです。しかし、テキストとして表現するのは難しそうです(最終的にはスクリーンショットなども送信するところまで行き着きそうです)。

まじめにやるなら、プロンプトエンジニアリングや埋込みなども勉強した方がよいのかなと思いました。

安全性

まず「どこまでプロンプトに含めるか」は難しいと思いました。今回はアクティブシートの値をまるっと送ってしまうので実際に使うのはちょっと危ないかなと。

もう 1 つは、「返答をどこまで自動処理するか」です。上の方でも少し書きましたが、今回のチャットではセルに式をセットできます。最初は無制限に式をセットしていましたが、以下のようなことが想定されたので制限をかけました。

  • IMPORT 系の関数を使われると外部に情報を送信できそう
  • 実行にコストがかかる関数を大量にセットされると請求書見るのが怖くなる

この辺は全面的に制限かける方が安全ですが、それだと生成 AI によるコンテンツ作成支援の魅力が半減しそうなので、悩ましいところになるのかなと。

関数呼び出しの定義

API リクエストに関数の定義を含めることと、実際に関数を作るのが二度手間だなと思ってしまいました。また、引数の型指定は厳密には反映されないので、コード側にチェック処理が必要になってきます(現状、関数呼び出しはベータ版なので改善されるかもしれませんが)。

この辺はマッパー的なものがあるとうれしい感じです(探せばあるのもかもしれません)。

関数呼び出しの挙動

呼び出しの挙動については「1 つのターンに複数の関数呼び出しを含める方法が不明」というのがあります。たとえば、「背景色をセットし、ヘッダーに罫線をセットして」みたいな場合、背景色用の関数しか呼びされません。機能的にはサポートされているようなのでプロンプトの組み立て方に問題ありそうな感じですが、いまのところ原因はよくわかっていません。

あとは、定義のところでも書きましたが「型の定義を無視した引数を渡してくる」ということがわりとありました。とくに「少しでも複雑な型を指定している」とその傾向が高くなる印象です(「オブジェクトの配列」などはまったく言うことを聞いてくれませんでした)。

関数はなるべくシンプルに呼び出せるよう計画した方がよさそうです。

ローカライズ

試作したチャットでは関数定義にいわゆる「日本の罫線文化」用の記述が入っています。

以下は合計線についての(あまり正しくなさそうだけど、よく見かける使われ方の)説明を追加した PR です。

https://github.com/hankei6km/test-sheets-addon-inline-chat/pull/12

最初は「表に合計線をセットして」などではどうやっても二重線にならなかったのですが、上記 PR をマージした後は以下のようになっています。 (何度か試すと、おかしな位置にセットしたりするので完全ではないですが)

図 5-1 合計線をセットする指示

「表に合計線をセットして」という指示により、合計が表示されている行の上に二重線がセットされているスクリーンショット

このような感じでメッセージや単位の設定などの他に、関数の定義などにもローカライズが必要かなと感じました。

まぁ、こんな心配しなくても将来的には Gemini もバリバリに罫線使ってるかもしれませんが。 (Gemini「罫線アートは最も得意な操作の 1 つです。エキサイティングなセル結合もお見せできますよ👍」みたいな)

おわりに

Gemini API を利用してスプレッドシートの見た目を変更できるチャットを試作してみました。

配色関連の操作は思っていたよりも良い感じ(ふわっとした指示で操作できる)ですが、実用的に使うにはまだまだ改良は必要だと思いました。

また、チャットを構成している関数呼び出しやマルチモーダルに関しては以下のようなこともわかりました。

  • 自然言語による指示から特定の関数を実行するハードルは下がってきた
  • マルチモーダルを使うと面白い UI を作れそう

今後も言語モデルや周辺のライブラリーなどが進化し、複雑なタスクもサポートされていくと予想されるので、それに合わせて面白いツールなどを作っていければなと思っています。

GitHubで編集を提案

Discussion