Google Apps ScriptとGemini 2.0 Flash 画像編集で出力する【GAS】

Imagen3を使って画像編集リクエストができるというのでやってみたのですが、非常にイマイチな結果になり、Google AI Studioの時のような期待した画像編集結果が得られませんでした。そこで、AI Studioと同様のモデルである「gemini-2.0-flash-preview-image-generation」を使って、Google Apps Scriptでリクエストしてみました。

かなり期待した画像に再編集されてスライドに挿入することが可能です。

今回利用するツール等

Imagen3は画像生成では非常に素晴らしい結果を出すモデルなのですが、いかんせん画像の編集機能に関しては全然駄目で、色々パラメータやプロンプトを弄っても期待した結果を得られず。しかし、同じプロンプトでも今回使ったモデルの場合は、期待した結果を返してくれるので、このモデルを採用してみました。

事前準備

Gemini のAPIキーを取得する

GeminiのAPIキーが必要です。以下のエントリーに独立してまとめています。課金されますので利用のしすぎには要注意。また課金されていない場合、学習に利用されてしまう恐れがあるので、きちんとGoogle Cloud上で課金アカウントとの紐付けなどをしておきましょう。

GeminiのAPIキーの取得と学習の可否

スクリプトプロパティに値を格納

前述までに取得しておいたGeminiのAPIキーについて、GASのスクリプトプロパティに値をセットします。

  • apikey : Gemini APIのAPIキー

図:スクリプトプロパティに格納する

ソースコード

サイドバーから画像のIDと指定のプロンプトを入れて実行すると、スライドに挿入されるという仕掛けで、同じファイルがスライドと同じフォルダに生成されるように構築しています。

ペイロードの構築部分がこれまでと違い、画像をアップロードしながらプロンプトで指定していますが、generationConfigの指定が必要になります。

//画像生成エンドポイント
const imageModel = "gemini-2.0-flash-preview-image-generation";
const endpoint = `https://generativelanguage.googleapis.com/v1beta/models/${imageModel}:generateContent?key=`

//Imagen3で画像生成する
function imagen3Generator(fileId,prompt){
  //プロパティの値を取得する
  let prop = PropertiesService.getScriptProperties()
  let apikey = prop.getProperty("apikey");

  //リクエストURLを構築する
  let url = endpoint + apikey;

  //ファイルを取得してbase64エンコードする
  const originalImageFile = DriveApp.getFileById(fileId)
  const imageBlob = originalImageFile.getBlob();
  const imageBase64 = Utilities.base64Encode(imageBlob.getBytes());
  const mimeType = imageBlob.getContentType();

  //リクエスト用のペイロードを作成
  const payload = {
      "contents": [
        {
          "parts": [
            { "text": prompt },
            {
              "inline_data": {
                "mime_type": mimeType,
                "data": imageBase64
              }
            }
          ]
        }
      ],
      "generationConfig": {
        "responseModalities": ["IMAGE", "TEXT"]
      }
    };

  //リクエストオプション
  const options = {
    'method': 'post',
    'contentType': 'application/json',
    'payload': JSON.stringify(payload),
    'muteHttpExceptions': true
  };
  
  //Gemini APIリクエスト
  const response = UrlFetchApp.fetch(url, options);
  const jsonResponse = JSON.parse(response.getContentText());

  //APIエラーを捕捉する
  if (jsonResponse.error) {
    console.error('API Error:', jsonResponse.error.message);
    throw new Error('Gemini API エラー: ' + jsonResponse.error.message);
  }

  //画像パートを取得する
  const parts = jsonResponse.candidates[0].content.parts;
  const imagePart = parts.find(part => part.inlineData);
  if (!imagePart) {
    throw new Error('APIの応答に画像データが含まれていませんでした。');
  }
  const editedImageBase64 = imagePart.inlineData.data;
  const newFileName = `(編集済_Flash) ${originalImageFile.getName()}`;
  // Blobを作成する時点でファイル名を指定する
  const editedImageBlob = Utilities.newBlob(Utilities.base64Decode(editedImageBase64), 'image/png', newFileName);

  //オリジナルと同じ場所にファイルを生成する
  const parentFolder = originalImageFile.getParents().next(); 
  const newFile = parentFolder.createFile(editedImageBlob);
  const newBlob = newFile.getBlob()

  //スライドに挿入
  let slide = SlidesApp.getActivePresentation().getSelection().getCurrentPage();
  slide.insertImage(newBlob).setWidth(500).setHeight(300).setLeft(350).setTop(80);

  //終了処理
  console.log(`生成されたファイルID: ${newFile.getId()}`);
  return newFile.getUrl();
}

使ってみた結果

元画像とプロンプト

今回、メニュー上からサイドバーを出してそこから指示を送れるように組んでいます。その中にはファイルのIDとプロンプト指定のテキストエリアがあるので、入力して画像を編集を実行するとGemini APIへアップロードと編集リクエストが送られます。

編集前の画像は以下のような感じ。空はなんだかちょっと曇っていて、白いバスが映っています。これを今回プロンプトで加工しようというお話です。プロンプトとしては以下のような内容になります。

アップロードした画像を以下の要件にしたがって編集してください

#編集する内容
- 映ってるバスを青いバスに変えてください
- 空が曇ってるので、透き通るような青空にして明るい感じにしてください

図:編集前の元画像はこんな感じ

出力結果

出力結果は素晴らしいもので、美しい青空になり、バスも青いバスに変わりました。挿入する際の画像のサイズ指定がコード内でちょっとあっていなかったので、サイズ手修正はしていますが、見事にフォトレタッチした形で結果を得ることができました。

ChatGPTなどはすでにアプリ上でこれができるようになっていて、背景透明化などいろいろできるのですがなぜか今のGeminiアプリはこの機能が備わっていないのが非常に不満だったので今回このプログラムを作ってみました。画像生成はImagen3でも、画像編集はこのモデルを使って再生成してくれたら、Geminiもいよいよ追いついたと言えるのですが・・・

図:サイドバーから画像IDとプロンプトで送った結果

関連リンク

 

コメントを残す

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

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