Geminiプロンプト備忘録

私は「高身長貧乳萌え」です  日:GAS(Google Apps Script) / 月:調査記録 / 火:様々な試み / 水:レシピ / 木:社会学 / 金:創作的何か / 土:雑談

AIはGoogleスライドの夢を見るか?――生成AIとの185日に渡る激闘の記録

はじめに――悪夢の始まり

 「添付の資料をもとに、内容を要約し、12ページのスライドをGoogleスライドで作成します。そのための、GASを最終的に作成してもらいます」

 すべての始まりは、この一文だった。

 軽い気持ちだった。本当に、軽い気持ちだったのだ。手元には、PDF化された市場調査報告書。これを要約して、Googleスライドにまとめるだけの、ありふれた作業。しかし、面倒くさい。定型業務は、AIに任せるのが現代的というものではないか。私はGoogleの生成AI、Geminiに向かって、そうプロンプトを打ち込んだ。デザインやレイアウトの要件をいくつか付け加えて……。

 まさかこの軽い一歩が、10回以上ものエラーと格闘し、APIの仕様という名の巨大な壁に頭を打ち付け、AIの知識の限界を目の当たりにする、長く、そして精神をすり減らすデバッグ作業の始まりになるとは、この時の私は知る由もなかったのである。

 これは、生成AIにGoogle Apps Script(GAS)を書かせようとした、一人の人間の奮闘記。そして、AIと人間が二人三脚でバグの迷宮を彷徨った、リアルな開発ドキュメンタリーである。

🤖💥👨‍💻

第1ラウンド:存在しない「グラデーション」との戦い

 まず、Geminiが意気揚々と提示してきた最初のコードは、実にそれっぽいものだった。定数管理、関数の分割……。なるほど、なかなか綺麗に書くじゃないか。私は感心しながら、実行ボタンをクリックした。

 ――そして、即座に赤いエラーメッセージが表示された。

TypeError: SlidesApp.newGradient is not a function

 「そんな関数は存在しない」

 原因は、Geminiが気を利かせてスライドの背景に設定しようとした「グラデーション」にあった。見栄えを良くしようというAIなりの配慮なのだろうが、そのグラデーションを描画するための命令(API)の関数名が、newGradient()ではなく、そもそも存在しなかったのだ。

 「おいおい、知らないのかよ……」と思いつつ、エラーを指摘すると、Geminiは殊勝な態度で謝罪し、こう言った。「申し訳ありません、正しくはnewGradientBuilder()でした」。そして自信満々に修正コードを提示してきた。結果は……言うまでもない。

TypeError: SlidesApp.newGradientBuilder is not a function

 また存在しなかった。

 この時点で、私はAIの知識レベルに一抹の不安を覚えた。どうやら、Googleスライドの細かな描画APIまでは、正確に学習しきれていないらしい。結局、「グラデーションなんていらん!」と、この機能自体を廃止することで、第一ラウンドは幕を閉じた。先が思いやられる……。

第2ラウンド:見えない「枠線」、APIの迷宮

 気を取り直して、次のステップへ進む。背景の問題が片付いたと思いきや、今度はテキストボックスの描画でエラーが頻発した。

 「背景を透明にしたい」「枠線を消したい」という、デザイン上の簡単な要求が、ことごとくAPIの壁に阻まれるのだ。

    1. 背景透明化の失敗: TypeError: Cannot read properties of undefined (reading 'FillType')
      私が「背景を透明にして」と頼んだのに対し、GeminiはSlidesApp.PageElement.FillType.NONEという命令を書いた。これは「『無し』という種類の単色で塗りつぶす」という、回りくどい上に存在しない命令だった。正解は、もっと直接的なsetTransparent()APIの思想を理解していないことがよくわかる。

 

    1. 枠線消去の失敗: TypeError: title.getOutline is not a function
      次に枠線を消そうとすると、今度はgetOutline()という、またも存在しない命令を呼び出す始末。正しくはgetBorder()OutlineBorder、意味は似ているがAPIの世界では天と地ほどの差がある。

 

  1. 修正案の迷走: さらに悪いことに、私が「getBorder()が正しいぞ」と教えても、Geminiはその先の命令をgetBorder().getLineFill().setTransparent()と間違える。これは「枠線の『塗り』を透明にする」という、これまた存在しない複雑な命令だった。

 この一連のエラーでハッキリしたのは、GeminiがGoogleスライドのオブジェクト構造を全く理解していないという事実だ。「テキストボックス」という一つのオブジェクトが、「塗り(Fill)」と「枠線(Border)」という別々の部品で構成されており、それぞれに専用の命令が必要だという基本中の基本が、すっぽりと抜け落ちていたのである。

 何度も何度も同じ種類のミスを繰り返すAIに、私は半ば呆れながら、根気強く正しいAPIを教え続けた。まるで、新人プログラマーOJTをしているような気分だった。違うのは、相手が疲れ知らずのAIだということだけだ。

😵‍💫→🤯→😇

第3ラウンド:「has no text」地獄の黙示録

 そして、ついにこの開発プロジェクトにおける最大の敵、最も根深く、最も厄介なエラーがその姿を現した。

Exception: The object (SLIDES_API1558273952_52) has no text.

 「そのオブジェクトにはテキストを書き込めない」。

 馬鹿な……! 今、insertTextBox()でテキストボックスを作ったばかりじゃないか! なぜ、文字が書けない?

 このエラーは、これまでのTypeErrorとは質が違った。命令の名前が間違っているのではない。命令の対象、つまり「テキストボックス」そのものを見失っているのだ。スクリプトがあまりにも高速に命令を出すため、Googleのサーバーがテキストボックスの作成を完了する前に、次の「文字を書き込め」という命令が届いてしまい、サーバーが混乱して、直前に作った別のオブジェクト(ただの線など)を掴んでしまう……。

 いわゆる、APIの「タイミング問題」。これは、コードの表面的な間違いではなく、システムの内部的な動作に起因する、極めてデバッグが困難な問題だった。

第1の矢:待機時間(sleep)という名の気休め

 Geminiが最初に提案してきた解決策は、Utilities.sleep(300)、つまり0.3秒の意図的な待機時間を設けるというものだった。「サーバーの処理を待ってあげましょう」というわけだ。

 結果は、失敗。

 待機時間を延ばしたところで、サーバーの混雑状況によってはエラーが再発する。これは「運任せ」の対策でしかない。根本的な解決にはならないと、私はすぐに悟った。

第2の矢:アーキテクチャ変更という希望と絶望

 次にGeminiが提案したのは、スクリプトの構造を抜本的に見直す、大掛かりなアーキテクチャ変更だった。

「まず、中身が空っぽのオブジェクトを全て配置し終える(作成フェーズ)。その後、改めて最初のスライドから順に、内容を書き込んでいく(編集フェーズ)」

 なるほど! 「作成」と「編集」を完全に分離すれば、タイミング問題は起きないはずだ。これは名案だと思った。私は期待に胸を膨らませ、再生成されたコードを実行した。

 ――しかし、非情にも画面には同じエラーメッセージが表示された。

 絶望した。

 アーキテクチャを変更しても解決しない。もはや、この問題は私の手には負えないのではないか……。諦めかけたその時、私の中に一つの仮説が閃いた。

第3の矢:ユーザーからの天啓

 「なあ、Gemini。箇条書きを一つのテキストボックスに追記していくから問題なんじゃないか? いっそ、箇条書きの一項目を、一つの独立したテキストボックスとして作れば、タイミング問題は起きないんじゃないか?」

 我ながら、素晴らしいアイディアだと思った。これは、不安定な「追記」処理を完全に排除し、「作成と書き込みが一体となった」安定した命令だけで全体を構築するという、発想の転換だ。

 この提案に、Geminiは「非常に的確で、この問題を解決するための最も優れた改善策です」と感嘆の声を上げた。そして、この新しいロジックで生成されたコードは、ついに、ついに長きにわたったhas no textの呪縛から我々を解放したのだった!

最終ラウンド:「はみ出し問題」と最後のAPIトラップ

 ようやく、全12ページのスライドが生成された。しかし、喜びも束の間、新たな問題が発覚した。箇条書きのテキストボックスが、スライドの範囲をはみ出しているのだ。

 これに対し、Geminiは最終兵器を提案してきた。Googleスライドが持つ「オートフィット」機能だ。「もしテキストが範囲を超えたら、自動でフォントサイズを縮小する」という、まさにこの状況にうってつけの機能。

 しかし、神は我々に最後の試練を与えた。Geminiが提示してきたオートフィットの命令は、

TypeError: bodyShape.setAutofitType is not a function

 最後の最後まで、関数名を間違えるのである。

 正しくは、setTextAutofit()Textの一語が足りなかったのだ。

 私は天を仰ぎ、乾いた笑いを漏らしながら、その最後の修正を指示した。そして、ついに、すべてのエラーがなくなり、すべての要素がスライド内に完璧に収まった、完全なプレゼンテーションが、私の目の前で生成されたのだった。

結論――AIとの協業、その光と闇

 今回の開発を通じて、私は生成AIとの協業のリアルな姿を体験した。

 光は、その圧倒的な速度と実装力だ。面倒な定型コードを瞬時に書き上げる能力は、間違いなく開発の初速を上げてくれる。

 しかし、闇は、その知識の「浅さ」と「不正確さ」にある。特に、GASのようにニッチで、バージョンによって仕様が変わりやすいAPIの細部については、平気で嘘(存在しない関数)をつく。そして、一度間違えると、人間が正しい道を指摘しない限り、同じような間違いを何度も繰り返す。

 結局のところ、現状のAIは、まだ「魔法の杖」ではない。それは、非常に優秀だが、致命的な知識の穴があり、時々平気で嘘をつく、手のかかる新人プログラマーのような存在だ。

 AIを使いこなすには、こちらもAPIの仕様を読み解き、エラーの原因を特定し、正しい方向へと導く「根気」と「デバッグ能力」が不可欠となる。AIに仕事を「丸投げ」するのではなく、AIを「相棒」として、共に試行錯誤する。

 AIプログラミングの未来とは、そういう泥臭くも、人間らしい対話の先にあるのかもしれない。……まあ、当分はこりごりだけどな!(笑)


筆者の叫び(有料)

この続きはcodocで購入