生成AIお絵描きコーチアプリ

このチュートリアルでは、Google Gemini APIを使って手書きで描いた絵の説明をして改善点を教えてくれるアプリを作ります。

Google Gemini APIの呼び出しにはGoogle Apps Script(GAS)を使います。GASのスクリプトはGoogle Gemini 2.5 Proで書いています。バイブコーディングです。

Google AI Studio で作るGemini APIは課金方法を登録しなくても以下の範囲ならば無料で使えます。

  • 1 分あたりのリクエスト数: 5
  • 1 日あたりのリクエスト数: 250,000
  • 1 分あたりのトークン数(入力): 100

Google Apps Scriptの設定

API呼び出し処理を行うサーバー側のプログラムをGoogle Apps Scriptに設定します。

Gemini 2.5 Pro を使って Google Apps Script を書く

無料のアカウントでもこちらからGemini 2.5 Proが使えます。

プロンプト

App inventorのキャンバスに描いた絵に説明をつけて改良点を提案させたい。Google apps script とGoogle ai studio を使う。キャンバスに描いた絵はエクステンションでbase64エンコードしてJSONでアップロードする。結果はJSONで戻す。APIキーはスクリプトプロパティから読む。App inventor部分は自分でやるから、それ以外の部分を教えて。

返答

Google Apps Scriptだけではなく、Gemini APIの設定からウェブアプリとしてのデプロイ方法、使い方まで詳しく教えてくれます。

はい、承知いたしました。
App Inventorで描いた絵をGoogle AI(Gemini)で分析し、説明と改善点を返すGoogle Apps Scriptのウェブアプリケーションを作成します。

App Inventor側の実装はご自身でされるとのことですので、Google Apps Script側の設定方法とコードを提供します。

全体の流れ
App Inventor:

Canvasに絵を描く。

描いた絵をBase64形式でエンコードする。

Base64文字列をJSONに含めて、Google Apps Scriptで作成したウェブアプリのURLにPOSTリクエストを送信する。

Google Apps Script (今回作成するもの):

App InventorからのPOSTリクエストを受け取る。

JSONからBase64形式の画像データを取り出す。

スクリプトプロパティに保存したAPIキーを読み込む。

Google AI (Gemini Pro Vision) APIに画像データとプロンプトを送信する。

Geminiから返ってきた「説明」と「改善点の提案」をJSON形式で整形する。

整形したJSONをApp Inventorに返す。

App Inventor:

Google Apps Scriptから返ってきたJSONを解析し、結果をアプリに表示する。

それでは、Google Apps Scriptの設定とコードを以下に示します。

Google Apps Script (GAS) の設定手順

Google AI (Gemini) APIを利用するためのGoogle Apps Scriptプロジェクトの設定手順です。

1. Google Apps Script プロジェクトの作成

  1. Google Drive を開きます。
  2. 「+ 新規」 > 「その他」 > 「Google Apps Script」 をクリックして、新しいプロジェクトを作成します。
  3. プロジェクトに名前を付けます(例:「画像分析AI」)。

2. APIキーの保存

APIキーをコードに直接書き込むのはセキュリティ上好ましくありません。代わりにスクリプトプロパティに保存します。

  1. GASエディタの左側メニューから「プロジェクトの設定」(歯車のアイコン)をクリックします。
  2. 「スクリプト プロパティ」のセクションにある「スクリプト プロパティを追加」をクリックします。
  3. 以下の情報を入力します。

    • プロパティ: GEMINI_API_KEY
    • 値: ご自身のGoogle AI StudioのAPIキー

  4. 「スクリプト プロパティを保存」をクリックします。

3. ウェブアプリとしてデプロイ

作成したスクリプトを外部(App Inventor)から利用できるように、ウェブアプリとして公開します。

  1. GASエディタの右上にある「デプロイ」ボタンをクリックし、「新しいデプロイ」を選択します。
  2. 「種類の選択」の横にある歯車アイコンをクリックし、「ウェブアプリ」を選択します。
  3. 設定を以下のように変更します。

    • 説明: (任意)画像分析用のAPIなど
    • 次のユーザーとして実行: 「自分」
    • アクセスできるユーザー: 「全員」

  4. 「デプロイ」ボタンをクリックします。
  5. 初回は「アクセスを承認」を求められます。ご自身のアカウントを選択し、詳細画面で「(安全でないページに)移動」をクリックして、アクセスを許可してください。
  6. 承認が終わると、ウェブアプリのURLが表示されます。このURLをコピーしてください。App Inventorからリクエストを送信する先のURLになります。

重要: コードを修正した場合は、再度「デプロイ」 > 「デプロイを管理」から、新しいバージョンを公開する必要があります。その際、「バージョン」を「新バージョン」にしてデプロイしてください。ウェブアプリのURLは通常変わりません。

これで、Google Apps Script側の準備は完了です。次に示すコードをGASエディタに貼り付けて保存してください。

Code.gs – 画像分析スクリプト

/**
 * App InventorからのPOSTリクエストを処理する関数
 * @param {Object} e - App Inventorから送信されるイベントオブジェクト
 * @return {ContentService.TextOutput} - Gemini APIからの結果をJSON形式で返す
 */
function doPost(e) {
  // エラーハンドリング
  try {
    // 1. App Inventorから送信されたJSONデータを解析
    const postData = JSON.parse(e.postData.contents);
    const base64Image = postData.image; // App Inventor側で "image" というキーに設定

    // 2. スクリプトプロパティからAPIキーを読み込む
    const API_KEY = PropertiesService.getScriptProperties().getProperty('API_KEY');
    if (!API_KEY) {
      return createErrorResponse('APIキーが設定されていません。');
    }

    // 3. Gemini APIのエンドポイントURL
    const API_URL = `https://generativelanguage.googleapis.com/v1beta/models/gemini-pro-vision:generateContent?key=${API_KEY}`;

    // 4. Gemini APIに送信するリクエストボディを作成
    const payload = {
      "contents": [{
        "parts": [{
          "text": "この絵を説明して、改善点を提案してください。説明と提案は明確に分けて記述してください。"
        }, {
          "inline_data": {
            "mime_type": "image/png", // App InventorのCanvasはPNG形式
            "data": base64Image
          }
        }]
      }]
    };

    // 5. Gemini APIにリクエストを送信するための設定
    const options = {
      'method': 'post',
      'contentType': 'application/json',
      'payload': JSON.stringify(payload),
      'muteHttpExceptions': true // エラーレスポンスを例外ではなくオブジェクトとして取得
    };

    // 6. APIにリクエストを送信
    const response = UrlFetchApp.fetch(API_URL, options);
    const responseCode = response.getResponseCode();
    const responseBody = response.getContentText();

    if (responseCode !== 200) {
       return createErrorResponse(`APIリクエストエラー: ${responseCode} ${responseBody}`);
    }
    
    // 7. APIからのレスポンスを解析
    const resultJson = JSON.parse(responseBody);
    
    // レスポンスの構造をチェックし、テキスト部分を取得
    let generatedText = "解析結果を取得できませんでした。";
    if (resultJson.candidates && resultJson.candidates.length > 0 &&
        resultJson.candidates[0].content && resultJson.candidates[0].content.parts &&
        resultJson.candidates[0].content.parts.length > 0) {
      generatedText = resultJson.candidates[0].content.parts[0].text;
    } else {
       // Geminiからのレスポンスが期待した形式でない場合
       return createErrorResponse(`予期しないAPIレスポンス形式です: ${responseBody}`);
    }

    // 8. App Inventorに返すJSONを作成
    const output = JSON.stringify({
      "status": "success",
      "result": generatedText
    });

    // 9. 結果をJSON形式で返す
    return ContentService.createTextOutput(output).setMimeType(ContentService.MimeType.JSON);

  } catch (error) {
    // スクリプト全体で発生したエラーをキャッチ
    return createErrorResponse(`スクリプトエラー: ${error.toString()}`);
  }
}

/**
 * エラーレスポンスを生成するヘルパー関数
 * @param {string} message - エラーメッセージ
 * @return {ContentService.TextOutput} - エラー情報を格納したJSONオブジェクト
 */
function createErrorResponse(message) {
  const errorOutput = JSON.stringify({
    "status": "error",
    "message": message
  });
  return ContentService.createTextOutput(errorOutput).setMimeType(ContentService.MimeType.JSON);
}

プロンプト

Gemini APIのAPIキーの取り方が無かったので、追加で尋ねます。

APIキーの取り方教えて

返答

残りのコンテンツを表示するにはログインする必要がありますどうぞ . 会員ではないですか ? 入会のご案内