AI,gemini,JavaScript,アプリ開発,チュートリアル,バイブコーディング,中級,生成AI

App Inventorでテトリスゲームを作ろうと思い立ち、いろいろと調べてみたところ、App Inventorだけで実装している記事を見つけました。しかし、その内容を見るとかなり手間がかかっており、大変そうでした。

本来、App Inventorは「簡単にスマホアプリを作る」ことを目的としたツールのはずです。それにもかかわらず、ゲームをひとつ作るのにここまで苦労するのは本末転倒だと感じました。そこで、複雑な処理はWebViewer内でJavaScriptに任せればよいことを思い出しました。

例えば、関数電卓アプリでは、複雑な計算部分をJavaScriptのライブラリで処理し、App Inventor側では結果の表示や操作部分だけを担当させることで、全体をずっと簡潔に構築できます。

そこで今回は、GoogleのGemini 2.5 Proを活用してテトリスゲームを作成します。なお、ここに掲載しているプロンプトと返答は、掲載用に改めて行った会話の内容であり、実際にゲームを作成した際のやり取りとは多少異なります。

実際に作ったテトリスゲームのチュートリアルはこちらです。

Gemini 2.5 Proとの対話

プロンプト

App Inventorでテトリスゲームを作りたい。ゲーム本体はウェブビュー内でJavaScriptで実行する。ゲームプレイ用のボタンなどはApp Inventor側で定義する。ウェブビューで使うhtmlファイルは1個にまとめる。

返答

App InventorとWebViewを組み合わせたテトリスゲームですね。承知いたしました。

WebView内で動作する、単一のHTMLファイルを作成します。このファイルには、ゲームのロジック(JavaScript)、描画(Canvas)、スタイル(CSS)がすべて含まれています。

App Inventor側では、このHTMLファイルをメディアとしてアップロードし、WebViewのHomeUrlに設定します。そして、App Inventorで作成したボタンから、WebViewのJavaScript関数を呼び出す(RunJavaScriptブロックを使用)ことでゲームを操作します。

こちらが、App InventorのWebViewで使用するための単一のHTMLファイルです。

tetris.html

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

AI,API,gemini,Google Apps Script,クラウド,中級,生成AI

最近家族と公園に行ったのですが、見たことのないトンボが飛んでいました。なんという種類のとんぼなのか調べるのに生成AIが使えるんではないかと思い、カメラで撮影して調べるアプリを作ろうと思い立ちました。

そこで、このチュートリアルでは、Google Gemini APIを使って撮影した写真を解析し、写っているものを百科事典を引いてわかりやすく説明してくれるアプリを作ります。さらに説明の読み上げ機能もつけました。生徒の学習用に良いと思います。

Google Gemini APIの呼び出しにはGoogle Apps Script(GAS)を使います。GASのスクリプトはGoogle Gemini 2.5 Proで書いた生成AIお絵描きコーチアプリ用のスクリプトのプロンプトを書き換えています。プロンプトの書き換えにはもちろんGoogle Gemini 2.5 Proを使っています。

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

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

Google Apps Scriptの設定

Gemini APIの設定からウェブアプリとしてのデプロイ方法、使い方などは生成AIお絵描きコーチアプリを参照してください。

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-2.5-pro:generateContent?key=${API_KEY}`;
  
    // 4. Gemini APIに送信するリクエストボディを作成
    const payload = {
      "contents": [{
        "parts": [{
          "text": `# 命令
あなたは、あらゆる事象を網羅した百科事典の知識を持つ博士です。提供された画像を注意深く分析し、以下の指示に従って解説文を作成してください。

# 実行ステップ
1.  **被写体の特定:** 画像に写っている最も主要な対象物(物、生物、場所、人物など)を正確に特定します。
2.  **情報抽出:** 特定した対象物について、あなたの知識の中から「名称」「最も重要な特徴」「歴史的背景や興味深い事実」を抽出します。
3.  **文章構成:** 抽出した情報を基に、最も伝えたい核心部分から書き始め、読み手の興味を引くように自然な文章を構成します。

# 出力制約
*   文字数: 200文字以内
*   段落: 必ず一つの段落で完結させること。
*   形式: 箇条書きは絶対に使用しないこと。
*   文体: 専門的でありながらも、その分野に詳しくない人にも分かりやすい、簡潔で平易な言葉で記述すること。`
        }, {
          "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);
}

App Inventorアプリ

ページの最後にあるダウンロードセクションからソースコードをダウンロードできます。

[プロジェクト]メニューから[新規プロジェクトを始める]を選択し、"EncyclopediaCamera"と名前を付けます。

デザイン編集

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

gemini,JavaScript,ゲーム,チュートリアル,中級

有名なゲームのテトリスを作ります

このチュートリアルでは、有名なゲームのテトリスを作ります。App Inventorだけで作った記事がありましたが随分大変そうなので、Google Gemini 2.5 Proに相談してウェブビュー内のJavaScriptでゲーム本体は作りました。App InventorからはこのJavaScriptをコントロールしています。

ページの最後にあるダウンロードセクションからソースコードをダウンロードできます。

[プロジェクト]メニューから[新規プロジェクトを始める]を選択し、"Tetris"と名前を付けます。

このチュートリアルで学べること

  • ウェブビューでJavaScriptを実行する方法
  • ウェブビューとの値の受け渡し方法

使用コンポーネント

ボタン、ラベル、ウェブビュー、水平配置、垂直配置

使用ブロック

特別なものは無し

デザイン編集

Screen1のタイトルを"テトリス"にします。

ページの最後にあるダウンロードセクションからtetris.htmlとover.mp3をダウンロードして、両方のファイルをファイルをアップロードボタンをクリックしてアップロードします。

レイアウト パレットから 垂直配置コンポーネント をビューアーに追加します。水平に整列するは"中央揃え"に、高さと横幅は"親要素に合わせる"に設定します。名前は垂直配置1になります。

ユーザーインターフェース パレットからウェブビュー垂直配置1に追加します。高さと横幅は"親要素に合わせる"に設定します。名前はウェブビュー1になります。

レイアウト パレットから 水平配置コンポーネント(水平配置1) を垂直配置コンポーネントに追加し、水平に整列するは"中央揃え"に、横幅は"親要素に合わせる"に設定します。水平配置1の中にユーザーインターフェース パレットからボタンを4個追加します。名前はボタン1ボタン2ボタン3ボタン4になります。

ユーザーインターフェース パレットからボタンラベル水平配置1の下に追加します。名前はそれぞれボタン5ラベル1になります。

以下のようにボタンラベルのプロパティを設定します。

  • ボタン1: テキスト="左″
  • ボタン2: テキスト="回転″
  • ボタン3: テキスト="右″
  • ボタン4: テキスト="下″
  • ボタン5: テキスト="スタート″
  • ラベル1: テキスト="″、横幅="親要素に合わせる"

最後にメディアパレットから、 サウンドコンポーネントをビューアーにドラッグアンドドロップします。ソースプロパティをover.mp3に指定します。

下図のようになります。

ブロック編集機能を使用したプログラミング

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

AI,API,Google Apps Script,nano banana,クラウド,中級,生成AI

このチュートリアルでは、Google Gemini APIを使って、撮影した写真から有名な画家が描いたような絵を表示するアプリを作ります。

2025年8月にGoogleから公開されたNano Banana(Gemini 2.5 Flash Image)は写真を人物や被写体の特徴を保ったまま自然言語で自由に加工・変換できるAIです。生成AIコスプレカメラアプリでは撮影した顔写真からコスプレした全身写真を表示しましたが、別の面白い応用として顔写真を有名画家風に変更してみました。

こちらがGoogleによるNano Bananaの解説です。

https://note.com/google_gemini/n/n1afcbf4d5275?rt=email&sub_rt=daily_report_followee_notes

生成AI画家風カメラアプリのデモビデオをこちらからご覧ください。

ただ、Nano BananaはAPI経由では無料では使えませんので、課金方法の登録が必要です。Nano Bananaを使う場合はGoogle AI Studioから課金方法を登録してください。

Google Gemini APIの呼び出しにはGoogle Apps Script(GAS)を使います。GASのスクリプトはGoogle Gemini 2.5 Proで書いた生成AIお絵描きマジックアプリ用のスクリプトのプロンプトを書き換えています。スクリプトのプロンプトを書き換えるだけで簡単に機能が変更できるので、参考にしてください。

Google Apps Scriptの設定

Gemini APIの設定からウェブアプリとしてのデプロイ方法、使い方などは生成AIお絵描きコーチアプリを参照してください。

Code.gs – 絵画風カメラスクリプト

/**
 * App InventorからのPOSTリクエストを処理するメイン関数
 * @param {Object} e - App Inventorから送信されるイベントオブジェクト
 * @returns {ContentService.TextOutput} - 処理結果(新しい画像のBase64文字列 or エラーメッセージ)をJSON形式で返す
 */
function doPost(e) {
  // レスポンスの基本構造
  let response = {
    status: 'error',
    message: 'An unknown error occurred.',
    imageData: null
  };

  try {
    // POSTされたJSONデータをパース
    if (!e || !e.postData || !e.postData.contents) {
      throw new Error('Invalid request: No data received.');
    }
    const jsonData = JSON.parse(e.postData.contents);
    const base64Data = jsonData.imageData;
    const artist = jsonData.artist;
    const prompt = jsonData.prompt || `写真自体の特徴は一切変更しないで、${artist}風に描いて。言葉での返答は不要`;

    // 入力データの検証
    if (!base64Data || typeof base64Data !== 'string') {
      throw new Error('Invalid request: imageData is missing or not a string.');
    }

    // Base64データからヘッダーを削除
    const cleanedBase64 = cleanBase64String(base64Data);

    // スクリプトプロパティからAPIキーを取得
    const apiKey = PropertiesService.getScriptProperties().getProperty('GEMINI_API_KEY');
    if (!apiKey) {
      throw new Error('Configuration error: API key is not set in Script Properties.');
    }

    // Gemini APIを呼び出して新しい画像を生成
    const generatedBase64 = callGeminiApi(apiKey, cleanedBase64, prompt);

    // 成功レスポンスを作成
    response = {
      status: 'success',
      message: 'Image generated successfully.',
      prompt: prompt,
      imageData: generatedBase64
    };

  } catch (error) {
    // エラーレスポンスを作成
    console.error(error.toString());
    response.message = error.message;
  }

  // 結果をJSON形式で返す
  return ContentService.createTextOutput(JSON.stringify(response))
    .setMimeType(ContentService.MimeType.JSON);
}

/**
 * Base64文字列からヘッダー部分(例: "data:image/png;base64,")を削除する
 * @param {string} base64String - 元のBase64文字列
 * @returns {string} - ヘッダーが削除されたBase64文字列
 */
function cleanBase64String(base64String) {
  // "data:[<mime-type>];base64," という形式のヘッダーを正規表現で探して削除
  return base64String.replace(/^data:image\/[a-z]+;base64,/, '');
}

/**
 * Gemini API (Image Generation) を呼び出して画像を生成する
 * @param {string} apiKey - Google AI StudioのAPIキー
 * @param {string} base64Image - 解析・改良の元となる画像のBase64文字列
 * @param {string} prompt - 画像をどのように改良するかを指定する指示文
 * @returns {string} - 生成された新しい画像のBase64文字列
 */
function callGeminiApi(apiKey, base64Image, prompt) {
  // Geminiの画像生成モデルのエンドポイント
  const model = 'gemini-2.5-flash-image-preview';
  const url = `https://generativelanguage.googleapis.com/v1beta/models/${model}:generateContent?key=${apiKey}`;

  // APIに送信するペイロード(リクエストボディ)
  const payload = {
    contents: [{
      parts: [
        // 1. 指示テキスト
        { text: prompt },
        // 2. 入力画像
        {
          inlineData: {
            mimeType: 'image/png', // App InventorのCanvasはPNG形式
            data: base64Image
          }
        }
      ]
    }],
    generationConfig: {
      // レスポンスとして画像とテキストの両方を要求する
      responseModalities: ['IMAGE', 'TEXT'] 
    },
  };

  // APIリクエストのオプション
  const options = {
    method: 'post',
    contentType: 'application/json',
    payload: JSON.stringify(payload),
    muteHttpExceptions: true // HTTPエラー時に例外をスローさせず、レスポンスを直接受け取る
  };

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

  // レスポンスを解析
  if (responseCode === 200) {
    const jsonResponse = JSON.parse(responseBody);
    
    // レスポンスの中から画像データ部分を探す
    const imagePart = jsonResponse?.candidates?.[0]?.content?.parts?.find(p => p.inlineData);
    
    if (imagePart && imagePart.inlineData.data) {
      // 画像のBase64データを返す
      return imagePart.inlineData.data;
    } else {
      // 画像が見つからない場合のエラー
      console.error('API response did not contain image data. Response: ' + responseBody);
      // テキスト部分があれば、それをエラーメッセージとして利用
      const textPart = jsonResponse?.candidates?.[0]?.content?.parts?.find(p => p.text);
      const errorMessage = textPart ? textPart.text : 'No image data in response.';
      throw new Error(`API Error: ${errorMessage}`);
    }
  } else {
    // APIがエラーを返した場合
    console.error('API Error. Code: ' + responseCode + '. Body: ' + responseBody);
    throw new Error(`API request failed with status code ${responseCode}. Details: ${responseBody}`);
  }
}

App Inventorアプリ

ページの最後にあるダウンロードセクションからソースコードをダウンロードできます。

[プロジェクト]メニューから[新規プロジェクトを始める]を選択し、"ArtCamera"と名前を付けます。

デザイン編集

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

AI,API,Google Apps Script,nano banana,クラウド,中級,生成AI

このチュートリアルでは、Google Gemini APIを使って、撮影した顔写真からコスプレした全身写真を表示するアプリを作ります。

2025年8月にGoogleから公開されたNano Banana(Gemini 2.5 Flash Image)は写真を人物や被写体の特徴を保ったまま自然言語で自由に加工・変換できるAIです。生成AI表情変更アプリでは撮影した顔写真の表情を変更しましたが、もっと面白い応用としてコスプレさせてみました。

こちらがGoogleによるNano Bananaの解説です。

https://note.com/google_gemini/n/n1afcbf4d5275?rt=email&sub_rt=daily_report_followee_notes

生成AIコスプレカメラアプリのデモビデオをこちらからご覧ください。

ただ、Nano BananaはAPI経由では無料では使えませんので、課金方法の登録が必要です。Nano Bananaを使う場合はGoogle AI Studioから課金方法を登録してください。

Google Gemini APIの呼び出しにはGoogle Apps Script(GAS)を使います。GASのスクリプトはGoogle Gemini 2.5 Proで書いた生成AIお絵描きマジックアプリ用のスクリプトのプロンプトを書き換えています。

Google Apps Scriptの設定

Gemini APIの設定からウェブアプリとしてのデプロイ方法、使い方などは生成AIお絵描きコーチアプリを参照してください。

Code.gs – コスプレカメラスクリプト

/**
 * App InventorからのPOSTリクエストを処理するメイン関数
 * @param {Object} e - App Inventorから送信されるイベントオブジェクト
 * @returns {ContentService.TextOutput} - 処理結果(新しい画像のBase64文字列 or エラーメッセージ)をJSON形式で返す
 */
function doPost(e) {
  // レスポンスの基本構造
  let response = {
    status: 'error',
    message: 'An unknown error occurred.',
    imageData: null
  };

  try {
    // POSTされたJSONデータをパース
    if (!e || !e.postData || !e.postData.contents) {
      throw new Error('Invalid request: No data received.');
    }
    const jsonData = JSON.parse(e.postData.contents);
    const base64Data = jsonData.imageData;
    const characer = jsonData.characer;
    const prompt = jsonData.prompt || `全身写真にしてから顔自体は一切変更しないで、${characer}でコスプレして。言葉での返答は不要`;

    // 入力データの検証
    if (!base64Data || typeof base64Data !== 'string') {
      throw new Error('Invalid request: imageData is missing or not a string.');
    }

    // Base64データからヘッダーを削除
    const cleanedBase64 = cleanBase64String(base64Data);

    // スクリプトプロパティからAPIキーを取得
    const apiKey = PropertiesService.getScriptProperties().getProperty('GEMINI_API_KEY');
    if (!apiKey) {
      throw new Error('Configuration error: API key is not set in Script Properties.');
    }

    // Gemini APIを呼び出して新しい画像を生成
    const generatedBase64 = callGeminiApi(apiKey, cleanedBase64, prompt);

    // 成功レスポンスを作成
    response = {
      status: 'success',
      message: 'Image generated successfully.',
      prompt: prompt,
      imageData: generatedBase64
    };

  } catch (error) {
    // エラーレスポンスを作成
    console.error(error.toString());
    response.message = error.message;
  }

  // 結果をJSON形式で返す
  return ContentService.createTextOutput(JSON.stringify(response))
    .setMimeType(ContentService.MimeType.JSON);
}

/**
 * Base64文字列からヘッダー部分(例: "data:image/png;base64,")を削除する
 * @param {string} base64String - 元のBase64文字列
 * @returns {string} - ヘッダーが削除されたBase64文字列
 */
function cleanBase64String(base64String) {
  // "data:[<mime-type>];base64," という形式のヘッダーを正規表現で探して削除
  return base64String.replace(/^data:image\/[a-z]+;base64,/, '');
}

/**
 * Gemini API (Image Generation) を呼び出して画像を生成する
 * @param {string} apiKey - Google AI StudioのAPIキー
 * @param {string} base64Image - 解析・改良の元となる画像のBase64文字列
 * @param {string} prompt - 画像をどのように改良するかを指定する指示文
 * @returns {string} - 生成された新しい画像のBase64文字列
 */
function callGeminiApi(apiKey, base64Image, prompt) {
  // Geminiの画像生成モデルのエンドポイント
  const model = 'gemini-2.5-flash-image-preview';
  const url = `https://generativelanguage.googleapis.com/v1beta/models/${model}:generateContent?key=${apiKey}`;

  // APIに送信するペイロード(リクエストボディ)
  const payload = {
    contents: [{
      parts: [
        // 1. 指示テキスト
        { text: prompt },
        // 2. 入力画像
        {
          inlineData: {
            mimeType: 'image/png', // App InventorのCanvasはPNG形式
            data: base64Image
          }
        }
      ]
    }],
    generationConfig: {
      // レスポンスとして画像とテキストの両方を要求する
      responseModalities: ['IMAGE', 'TEXT'] 
    },
  };

  // APIリクエストのオプション
  const options = {
    method: 'post',
    contentType: 'application/json',
    payload: JSON.stringify(payload),
    muteHttpExceptions: true // HTTPエラー時に例外をスローさせず、レスポンスを直接受け取る
  };

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

  // レスポンスを解析
  if (responseCode === 200) {
    const jsonResponse = JSON.parse(responseBody);
    
    // レスポンスの中から画像データ部分を探す
    const imagePart = jsonResponse?.candidates?.[0]?.content?.parts?.find(p => p.inlineData);
    
    if (imagePart && imagePart.inlineData.data) {
      // 画像のBase64データを返す
      return imagePart.inlineData.data;
    } else {
      // 画像が見つからない場合のエラー
      console.error('API response did not contain image data. Response: ' + responseBody);
      // テキスト部分があれば、それをエラーメッセージとして利用
      const textPart = jsonResponse?.candidates?.[0]?.content?.parts?.find(p => p.text);
      const errorMessage = textPart ? textPart.text : 'No image data in response.';
      throw new Error(`API Error: ${errorMessage}`);
    }
  } else {
    // APIがエラーを返した場合
    console.error('API Error. Code: ' + responseCode + '. Body: ' + responseBody);
    throw new Error(`API request failed with status code ${responseCode}. Details: ${responseBody}`);
  }
}

App Inventorアプリ

ページの最後にあるダウンロードセクションからソースコードをダウンロードできます。

[プロジェクト]メニューから[新規プロジェクトを始める]を選択し、"CosplayCamera"と名前を付けます。

デザイン編集

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

AI,API,Google Apps Script,nano banana,クラウド,中級,生成AI

このチュートリアルでは、Google Gemini APIを使って撮影した顔写真の表情を変更して表示するアプリを作ります。

2025年8月にGoogleから公開されたNano Banana(Gemini 2.5 Flash Image)は写真を人物や被写体の特徴を保ったまま自然言語で自由に加工・変換できるAIです。たとえば、従来の gemini-2.0-flash-preview-image-generation ではうまく顔の表情の変換はできませんでしたが、Nano Bananaだと上手に変換できます。こちらがGoogleの解説です。

https://note.com/google_gemini/n/n1afcbf4d5275?rt=email&sub_rt=daily_report_followee_notes

生成AI表情変更アプリのデモビデオをこちらからご覧ください。

ただ、Nano BananaはAPI経由では無料では使えませんので、課金方法の登録が必要です。Nano Bananaを使う場合はGoogle AI Studioから課金方法を登録してください。

Google Gemini APIの呼び出しにはGoogle Apps Script(GAS)を使います。GASのスクリプトはGoogle Gemini 2.5 Proで書いた生成AIお絵描きマジックアプリ用のスクリプトのプロンプトを書き換えています。

Google Apps Scriptの設定

Gemini APIの設定からウェブアプリとしてのデプロイ方法、使い方などは生成AIお絵描きコーチアプリを参照してください。

Code.gs – 表情変更スクリプト

/**
 * App InventorからのPOSTリクエストを処理するメイン関数
 * @param {Object} e - App Inventorから送信されるイベントオブジェクト
 * @returns {ContentService.TextOutput} - 処理結果(新しい画像のBase64文字列 or エラーメッセージ)をJSON形式で返す
 */
function doPost(e) {
  // レスポンスの基本構造
  let response = {
    status: 'error',
    message: 'An unknown error occurred.',
    imageData: null
  };

  try {
    // POSTされたJSONデータをパース
    if (!e || !e.postData || !e.postData.contents) {
      throw new Error('Invalid request: No data received.');
    }
    const jsonData = JSON.parse(e.postData.contents);
    const base64Data = jsonData.imageData;
// expression には表情が入っている。「笑った顔」など
    const expression = jsonData.expression;
    const prompt = jsonData.prompt || `この写真が顔写真ならば${expression}に変換して画像を戻して。言葉での返答は不要だから画像を戻して`;

    // 入力データの検証
    if (!base64Data || typeof base64Data !== 'string') {
      throw new Error('Invalid request: imageData is missing or not a string.');
    }

    // Base64データからヘッダーを削除
    const cleanedBase64 = cleanBase64String(base64Data);

    // スクリプトプロパティからAPIキーを取得
    const apiKey = PropertiesService.getScriptProperties().getProperty('GEMINI_API_KEY');
    if (!apiKey) {
      throw new Error('Configuration error: API key is not set in Script Properties.');
    }

    // Gemini APIを呼び出して新しい画像を生成
    const generatedBase64 = callGeminiApi(apiKey, cleanedBase64, prompt);

    // 成功レスポンスを作成
    response = {
      status: 'success',
      message: 'Image generated successfully.',
      prompt: prompt,
      imageData: generatedBase64
    };

  } catch (error) {
    // エラーレスポンスを作成
    console.error(error.toString());
    response.message = error.message;
  }

  // 結果をJSON形式で返す
  return ContentService.createTextOutput(JSON.stringify(response))
    .setMimeType(ContentService.MimeType.JSON);
}

/**
 * Base64文字列からヘッダー部分(例: "data:image/png;base64,")を削除する
 * @param {string} base64String - 元のBase64文字列
 * @returns {string} - ヘッダーが削除されたBase64文字列
 */
function cleanBase64String(base64String) {
  // "data:[<mime-type>];base64," という形式のヘッダーを正規表現で探して削除
  return base64String.replace(/^data:image\/[a-z]+;base64,/, '');
}

/**
 * Gemini API (Image Generation) を呼び出して画像を生成する
 * @param {string} apiKey - Google AI StudioのAPIキー
 * @param {string} base64Image - 解析・改良の元となる画像のBase64文字列
 * @param {string} prompt - 画像をどのように改良するかを指定する指示文
 * @returns {string} - 生成された新しい画像のBase64文字列
 */
function callGeminiApi(apiKey, base64Image, prompt) {
  // Geminiの画像生成モデルのエンドポイント
  const model = 'gemini-2.5-flash-image-preview';
  const url = `https://generativelanguage.googleapis.com/v1beta/models/${model}:generateContent?key=${apiKey}`;

  // APIに送信するペイロード(リクエストボディ)
  const payload = {
    contents: [{
      parts: [
        // 1. 指示テキスト
        { text: prompt },
        // 2. 入力画像
        {
          inlineData: {
            mimeType: 'image/png', // App InventorのCanvasはPNG形式
            data: base64Image
          }
        }
      ]
    }],
    generationConfig: {
      // レスポンスとして画像とテキストの両方を要求する
      responseModalities: ['IMAGE', 'TEXT'] 
    },
  };

  // APIリクエストのオプション
  const options = {
    method: 'post',
    contentType: 'application/json',
    payload: JSON.stringify(payload),
    muteHttpExceptions: true // HTTPエラー時に例外をスローさせず、レスポンスを直接受け取る
  };

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

  // レスポンスを解析
  if (responseCode === 200) {
    const jsonResponse = JSON.parse(responseBody);
    
    // レスポンスの中から画像データ部分を探す
    const imagePart = jsonResponse?.candidates?.[0]?.content?.parts?.find(p => p.inlineData);
    
    if (imagePart && imagePart.inlineData.data) {
      // 画像のBase64データを返す
      return imagePart.inlineData.data;
    } else {
      // 画像が見つからない場合のエラー
      console.error('API response did not contain image data. Response: ' + responseBody);
      // テキスト部分があれば、それをエラーメッセージとして利用
      const textPart = jsonResponse?.candidates?.[0]?.content?.parts?.find(p => p.text);
      const errorMessage = textPart ? textPart.text : 'No image data in response.';
      throw new Error(`API Error: ${errorMessage}`);
    }
  } else {
    // APIがエラーを返した場合
    console.error('API Error. Code: ' + responseCode + '. Body: ' + responseBody);
    throw new Error(`API request failed with status code ${responseCode}. Details: ${responseBody}`);
  }
}

App Inventorアプリ

ページの最後にあるダウンロードセクションからソースコードをダウンロードできます。

[プロジェクト]メニューから[新規プロジェクトを始める]を選択し、"FaceChanger"と名前を付けます。

デザイン編集

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

AI,API,gemini,Google Apps Script,クラウド,中級,生成AI

このチュートリアルでは、Google Gemini APIを使って撮影した写真の解説をしてくれるアプリを作ります。

Google Gemini APIの呼び出しにはGoogle Apps Script(GAS)を使います。GASのスクリプトはGoogle Gemini 2.5 Proで書いた生成AIお絵描きコーチアプリ用のスクリプトのプロンプトを書き換えています。

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

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

Google Apps Scriptの設定

Gemini APIの設定からウェブアプリとしてのデプロイ方法、使い方などは生成AIお絵描きコーチアプリを参照してください。

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-2.5-pro:generateContent?key=${API_KEY}`;
  
    // 4. Gemini APIに送信するリクエストボディを作成
    const payload = {
      "contents": [{
        "parts": [{
          "text": "画像を解析してください。  まず、ランドマークや観光地が写っている場合は正式な地名を含めてください。  そうでない場合は人物を確認し、有名人(俳優・女優・著名人)であればその人物名を含めてください。  最後に、写真全体の内容を200文字以内で自然な文章として解説してください。  出力は必ず一つの段落の文章で返答してください。箇条書きは禁止です。"
        }, {
          "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);
}

App Inventorアプリ

ページの最後にあるダウンロードセクションからソースコードをダウンロードできます。

[プロジェクト]メニューから[新規プロジェクトを始める]を選択し、"KnowledgeCamera"と名前を付けます。

デザイン編集

AI,API,gemini,Google Apps Script,クラウド,センサー,中級,地図,生成AI

このチュートリアルでは、地図の中心周辺の観光名所をGoogle Gemini APIに問い合わせて地図上に表示し、マーカーをクリックするとその場所の説明を表示するアプリを作ります。

生成AI観光名所地図アプリでは観光名所をGeminiで検索してその場所を地図上にマーカーで表示しましたが、結構知らない場所も表示されるので、どんなところかわかると便利だろうと思い、マーカーをクリックするとその名前と住所に加えてその場所の説明も表示するようにしました。

この機能追加のために、アプリ本体とGASスクリプトを変更しています。

Google Gemini APIの呼び出しにはGoogle Apps Script(GAS)を使います。

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

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

Google Apps Scriptの設定

Google Apps Scriptに設定方法などはここを参照してください。

GASスクリプトの変更

200文字以内の説明も返すようにマニュアルでスクリプトの中のプロンプトを変更します。

観光地検索API (Google Apps Script)

/**
 * App InventorからのGETリクエストを処理するメイン関数
 * @param {object} e - App Inventorから渡されるイベントオブジェクト
 * @returns {ContentService.TextOutput} - 観光地情報のJSONまたはエラーメッセージ
 */
function doGet(e) {
  // レスポンスのMIMEタイプをJSONに設定
  const response = ContentService.createTextOutput();
  response.setMimeType(ContentService.MimeType.JSON);

  try {
    // クエリパラメータから緯度、経度、半径を取得
    const lat = e.parameter.latitude;
    const lon = e.parameter.longitude;
    const radius = e.parameter.radius;

    // パラメータが不足している場合はエラーを返す
    if (!lat || !lon || !radius) {
      response.setContent(JSON.stringify({
        error: "パラメータが不足しています。'latitude', 'longitude', 'radius'が必要です。"
      }));
      return response;
    }

    // Gemini APIを呼び出して観光地情報を取得
    const touristSpots = getTouristSpots(lat, lon, radius);
    
    // 取得した情報をJSON形式で返す
    response.setContent(JSON.stringify(touristSpots));

  } catch (error) {
    // エラーが発生した場合、エラーメッセージをJSONで返す
    response.setContent(JSON.stringify({
      error: "データの取得中にエラーが発生しました。",
      details: error.message
    }));
  }

  return response;
}

/**
 * Gemini APIを呼び出して、指定された座標周辺の観光地情報を取得する
 * @param {number} latitude - 中心の緯度
 * @param {number} longitude - 中心の経度
 * @param {number} radius - 検索半径(メートル)
 * @returns {Array<Object>} - 観光地のリスト
 */
function getTouristSpots(latitude, longitude, radius) {
  // スクリプトプロパティからAPIキーを読み込む
  const API_KEY = PropertiesService.getScriptProperties().getProperty('GEMINI_API_KEY');
  if (!API_KEY) {
    throw new Error("APIキーがスクリプトプロパティに設定されていません。");
  }

  const API_URL = `https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent?key=${API_KEY}`;

  // Geminiに渡すプロンプト(指示文)- 緯度経度が不要なことを明記
  const prompt = `
あなたは優秀なローカルツアーガイドです。
以下の中心座標と半径の範囲内にある観光地を最大5件まで探してください。
結果は必ず指定されたJSON形式で、名前と住所と200文字以内の説明のみを含めてください。緯度と経度は不要です。

中心緯度: ${latitude}
中心経度: ${longitude}
半径: ${radius}メートル
`;

  // Gemini APIに送信するデータ(ペイロード)- responseSchemaから緯度経度を削除
  const payload = {
    "contents": [{
      "parts": [{
        "text": prompt
      }]
    }],
    "generationConfig": {
      "responseMimeType": "application/json",
      "responseSchema": {
        "type": "ARRAY",
        "items": {
          "type": "OBJECT",
          "properties": {
            "name": { "type": "STRING", "description": "観光地の名前" },
            "address": { "type": "STRING", "description": "観光地の住所" },
            "desc": { "type": "STRING", "description": "観光地の説明" }
          },
          "required": ["name", "address"]
        }
      }
    }
  };

  // APIリクエストのオプション
  const options = {
    'method': 'post',
    'contentType': 'application/json',
    'payload': JSON.stringify(payload),
    'muteHttpExceptions': true // HTTPエラー時もレスポンスを返す
  };

  // APIを呼び出す
  const response = UrlFetchApp.fetch(API_URL, options);
  const responseCode = response.getResponseCode();
  const responseBody = response.getContentText();

  if (responseCode !== 200) {
    throw new Error(`APIリクエストに失敗しました。ステータスコード: ${responseCode}, レスポンス: ${responseBody}`);
  }
  
  // レスポンスからJSON部分を抽出してパースする
  const result = JSON.parse(responseBody);
  const jsonText = result.candidates[0].content.parts[0].text;
  
  return JSON.parse(jsonText);
}

App Inventorアプリ

ページの最後にあるダウンロードセクションからソースコードをダウンロードできます。

[プロジェクト]メニューから[新規プロジェクトを始める]を選択し、"AITravelGuide"と名前を付けます。

デザイン編集

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

AI,API,gemini,Google Apps Script,クラウド,センサー,バイブコーディング,中級,地図,生成AI

このチュートリアルでは、地図の中心周辺の観光名所をGoogle Gemini APIに問い合わせて地図上に表示するアプリを作ります。観光名所地図アプリではGoogle Sheets APIを使ってGoogleスプレッドシートに入力された東京の観光名所を地図上に表示したので、あらかじめ入力した観光名所しか表示できませんでしたが、このアプリでは原理的にどの場所の観光名所でも表示できます。

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が使えます。

プロンプト

観光名所を地図上に表示するには緯度、経度が必要ですが、Geminiは緯度、経度を知っているとは限らないので、代わりに知っているはずの住所を返してもらい、位置センサーコンポーネントを使って緯度、経度に変換します。

App inventorの地図コンポーネントの中心の緯度、経度から指定した半径内にある観光地の名前と住所(緯度、経度は不要)を最大5件取得し、地図上にマーカーで表示したい。Google apps script とGoogle ai studio で取得するGemini APIキーでGemini 2.5 Flashを使う。他のAPIは使わない。結果はJSONで戻す。APIキーはスクリプトプロパティから読む。App inventor部分は自分でやるから、それ以外の部分を教えて。

返答

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

はい、承知いたしました。App Inventorから呼び出すためのGoogle Apps Scriptを作成します。

このスクリプトは、指定された緯度・経度・半径を基に、Gemini 2.5 Flashモデルを使用して周辺の観光地情報を最大5件取得し、JSON形式で返します。

以下に、Google Apps Scriptのコードと、その設定方法を説明します。

1. Google Apps Scriptの準備
まず、Google Apps Scriptプロジェクトを準備する手順を説明します。

Google Apps Script プロジェクトの作成と設定ガイド

  1. Google Driveを開く: Google Driveにアクセスします。
  2. 新規プロジェクト作成:

    • 左上の「+ 新規」ボタンをクリックします。
    • その他」 > 「Google Apps Script」を選択します。
    • もし表示されない場合は、「アプリを追加」から「Google Apps Script」を検索して接続してください。

  3. プロジェクトに名前を付ける:

    • 左上の「無題のプロジェクト」をクリックし、「観光地検索API」などの分かりやすい名前に変更します。

  4. スクリプトの貼り付け:

    • エディタに最初から書かれている function myFunction() { ... } をすべて削除します。
    • 後述するコードをすべてコピーして、エディタに貼り付けます。

  5. APIキーの設定:

    • 左側のメニューから歯車アイコンの「プロジェクトの設定」をクリックします。
    • スクリプト プロパティ」のセクションにある「スクリプト プロパティを追加」ボタンをクリックします。
    • プロパティGEMINI_API_KEY と入力します。
    • に、Google AI Studioで取得したご自身のAPIキーを貼り付けます。
    • スクリプト プロパティを保存」をクリックします。

  6. プロジェクトのデプロイ:

    • 右上の青い「デプロイ」ボタンをクリックし、「新しいデプロイ」を選択します。
    • 種類の選択(歯車アイコンの隣)で「ウェブアプリ」を選択します。
    • 次の設定を行います。

      • 説明: 「観光地検索API for App Inventor」など、分かりやすい説明を入力します。
      • 次のユーザーとして実行: 自分
      • アクセスできるユーザー: 全員

    • デプロイ」ボタンをクリックします。
    • 初回は「アクセスを承認」を求められます。ご自身のアカウントを選択し、詳細設定から安全でないページへの移動を許可して、スクリプトの実行を許可してください。
    • デプロイが完了すると、「ウェブアプリのURL」が表示されます。このURLをコピーしてください。App InventorからAPIを呼び出す際にこのURLが必要になります。

以上で、Google Apps Script側の準備は完了です。

2. Google Apps Script コード
こちらのコードを、先ほど作成したGoogle Apps Scriptプロジェクトのエディタに貼り付けてください。

観光地検索API (Google Apps Script)

/**
 * App InventorからのGETリクエストを処理するメイン関数
 * @param {object} e - App Inventorから渡されるイベントオブジェクト
 * @returns {ContentService.TextOutput} - 観光地情報のJSONまたはエラーメッセージ
 */
function doGet(e) {
  // レスポンスのMIMEタイプをJSONに設定
  const response = ContentService.createTextOutput();
  response.setMimeType(ContentService.MimeType.JSON);

  try {
    // クエリパラメータから緯度、経度、半径を取得
    const lat = e.parameter.latitude;
    const lon = e.parameter.longitude;
    const radius = e.parameter.radius;

    // パラメータが不足している場合はエラーを返す
    if (!lat || !lon || !radius) {
      response.setContent(JSON.stringify({
        error: "パラメータが不足しています。'latitude', 'longitude', 'radius'が必要です。"
      }));
      return response;
    }

    // Gemini APIを呼び出して観光地情報を取得
    const touristSpots = getTouristSpots(lat, lon, radius);
    
    // 取得した情報をJSON形式で返す
    response.setContent(JSON.stringify(touristSpots));

  } catch (error) {
    // エラーが発生した場合、エラーメッセージをJSONで返す
    response.setContent(JSON.stringify({
      error: "データの取得中にエラーが発生しました。",
      details: error.message
    }));
  }

  return response;
}

/**
 * Gemini APIを呼び出して、指定された座標周辺の観光地情報を取得する
 * @param {number} latitude - 中心の緯度
 * @param {number} longitude - 中心の経度
 * @param {number} radius - 検索半径(メートル)
 * @returns {Array<Object>} - 観光地のリスト
 */
function getTouristSpots(latitude, longitude, radius) {
  // スクリプトプロパティからAPIキーを読み込む
  const API_KEY = PropertiesService.getScriptProperties().getProperty('GEMINI_API_KEY');
  if (!API_KEY) {
    throw new Error("APIキーがスクリプトプロパティに設定されていません。");
  }

  const API_URL = `https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent?key=${API_KEY}`;

  // Geminiに渡すプロンプト(指示文)
  const prompt = `
あなたは優秀なローカルツアーガイドです。
以下の中心座標と半径の範囲内にある観光地を最大5件まで探してください。
結果は必ず指定されたJSON形式で、名前、住所、緯度、経度を含めてください。

中心緯度: ${latitude}
中心経度: ${longitude}
半径: ${radius}メートル
`;

  // Gemini APIに送信するデータ(ペイロード)
  const payload = {
    "contents": [{
      "parts": [{
        "text": prompt
      }]
    }],
    "generationConfig": {
      "responseMimeType": "application/json",
      "responseSchema": {
        "type": "ARRAY",
        "items": {
          "type": "OBJECT",
          "properties": {
            "name": { "type": "STRING", "description": "観光地の名前" },
            "address": { "type": "STRING", "description": "観光地の住所" },
            "latitude": { "type": "NUMBER", "description": "観光地の緯度" },
            "longitude": { "type": "NUMBER", "description": "観光地の経度" }
          },
          "required": ["name", "address", "latitude", "longitude"]
        }
      }
    }
  };

  // APIリクエストのオプション
  const options = {
    'method': 'post',
    'contentType': 'application/json',
    'payload': JSON.stringify(payload),
    'muteHttpExceptions': true // HTTPエラー時もレスポンスを返す
  };

  // APIを呼び出す
  const response = UrlFetchApp.fetch(API_URL, options);
  const responseCode = response.getResponseCode();
  const responseBody = response.getContentText();

  if (responseCode !== 200) {
    throw new Error(`APIリクエストに失敗しました。ステータスコード: ${responseCode}, レスポンス: ${responseBody}`);
  }
  
  // レスポンスからJSON部分を抽出してパースする
  const result = JSON.parse(responseBody);
  const jsonText = result.candidates[0].content.parts[0].text;
  
  return JSON.parse(jsonText);
}

3. App Inventorでの使い方
App Inventor側では、「Web」コンポーネントを使って、デプロイ時に取得したウェブアプリのURLにGETリクエストを送信します。

URLの末尾に、以下のようにパラメータを追加してください。

<あなたのウェブアプリのURL>?latitude=35.681236&longitude=139.767125&radius=1000
latitude: 地図の中心の緯度

longitude: 地図の中心の経度

radius: 検索したい半径(メートル単位)

Webコンポーネントが GotText イベントで結果を受け取ったら、返ってきたJSON文字列を解析して、リストとして処理します。その後、各観光地の名前、住所、緯度、経度を使って地図上にマーカーを配置してください。

これで、App InventorアプリからGoogle Apps ScriptとGemini APIを連携させて、周辺の観光地情報を地図に表示する機能が実装できます。もし何かご不明な点があれば、お気軽にご質問ください。

プロンプト

結果に緯度、経度が含まれているので、緯度、経度を除いてコードを書き直してもらいます。

Geminiの結果から観光地の緯度、観光地の経度を除いて観光地検索APIコードを書き直して。

返答

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

AI,API,gemini,Google Apps Script,クラウド,バイブコーディング,中級,生成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のキャンバスに描いた絵を解析して改良した絵を出力させたい。改良した絵はbase64エンコードした文字列で受け取ってオリジナルの下のキャンバスに表示したい。
Google Apps Script からGoogle ai studio のAPIを呼び出して使う。キャンバスに描いた絵はエクステンションでbase64エンコードしてJSONでアップロードするのでGASでbase64が正しいか確認し、必要であれば修正する。結果はJSONで戻す。APIキーはスクリプトプロパティから読む。
App inventor部分は自分でやるから、それ以外の部分を教えて。

返答

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

App InventorとGoogle AIのGeminiモデルを連携させるためのGoogle Apps Script(GAS)ですね。承知いたしました。

App Inventorから送られてくる手描きの絵(Base64文字列)をGemini APIで解析・改良し、新しい画像を生成してApp Inventorに返すためのGASコードを作成します。

このスクリプトは、以下の処理を行います。

POSTリクエストの受付: App Inventorから送信されたJSONデータ(画像データとプロンプトを含む)を受け取ります。

Base64データの整形: 受け取ったBase64文字列から不要なヘッダー(data:image/png;base64,など)を削除します。

Gemini APIの呼び出し:

スクリプトプロパティに保存されたAPIキーを安全に読み込みます。

入力された画像とプロンプトをgemini-2.0-flash-preview-image-generationモデルに送信し、画像の改良を依頼します。このモデルは、入力画像を解釈し、指示に基づいて新しい画像を生成できます。

結果の返却: 生成された新しい画像のBase64文字列をJSON形式でApp Inventorに返します。

以下のドキュメントに、GASのコードと設定方法の詳細を記載します。

画像改良GAS for App Inventor

/**
 * App InventorからのPOSTリクエストを処理するメイン関数
 * @param {Object} e - App Inventorから送信されるイベントオブジェクト
 * @returns {ContentService.TextOutput} - 処理結果(新しい画像のBase64文字列 or エラーメッセージ)をJSON形式で返す
 */
function doPost(e) {
  // レスポンスの基本構造
  let response = {
    status: 'error',
    message: 'An unknown error occurred.',
    imageData: null
  };

  try {
    // POSTされたJSONデータをパース
    if (!e || !e.postData || !e.postData.contents) {
      throw new Error('Invalid request: No data received.');
    }
    const jsonData = JSON.parse(e.postData.contents);
    const base64Data = jsonData.imageData;
    const prompt = jsonData.prompt || 'この手描きの絵を、より洗練された高品質なデジタルアートにしてください。';

    // 入力データの検証
    if (!base64Data || typeof base64Data !== 'string') {
      throw new Error('Invalid request: imageData is missing or not a string.');
    }

    // Base64データからヘッダーを削除
    const cleanedBase64 = cleanBase64String(base64Data);

    // スクリプトプロパティからAPIキーを取得
    const apiKey = PropertiesService.getScriptProperties().getProperty('GEMINI_API_KEY');
    if (!apiKey) {
      throw new Error('Configuration error: API key is not set in Script Properties.');
    }

    // Gemini APIを呼び出して新しい画像を生成
    const generatedBase64 = callGeminiApi(apiKey, cleanedBase64, prompt);

    // 成功レスポンスを作成
    response = {
      status: 'success',
      message: 'Image generated successfully.',
      imageData: generatedBase64
    };

  } catch (error) {
    // エラーレスポンスを作成
    console.error(error.toString());
    response.message = error.message;
  }

  // 結果をJSON形式で返す
  return ContentService.createTextOutput(JSON.stringify(response))
    .setMimeType(ContentService.MimeType.JSON);
}

/**
 * Base64文字列からヘッダー部分(例: "data:image/png;base64,")を削除する
 * @param {string} base64String - 元のBase64文字列
 * @returns {string} - ヘッダーが削除されたBase64文字列
 */
function cleanBase64String(base64String) {
  // "data:[<mime-type>];base64," という形式のヘッダーを正規表現で探して削除
  return base64String.replace(/^data:image\/[a-z]+;base64,/, '');
}

/**
 * Gemini API (Image Generation) を呼び出して画像を生成する
 * @param {string} apiKey - Google AI StudioのAPIキー
 * @param {string} base64Image - 解析・改良の元となる画像のBase64文字列
 * @param {string} prompt - 画像をどのように改良するかを指定する指示文
 * @returns {string} - 生成された新しい画像のBase64文字列
 */
function callGeminiApi(apiKey, base64Image, prompt) {
  // Geminiの画像生成モデルのエンドポイント
  const model = 'gemini-2.0-flash-preview-image-generation';
  const url = `https://generativelanguage.googleapis.com/v1beta/models/${model}:generateContent?key=${apiKey}`;

  // APIに送信するペイロード(リクエストボディ)
  const payload = {
    contents: [{
      parts: [
        // 1. 指示テキスト
        { text: prompt },
        // 2. 入力画像
        {
          inlineData: {
            mimeType: 'image/png', // App InventorのCanvasはPNG形式
            data: base64Image
          }
        }
      ]
    }],
    generationConfig: {
      // レスポンスとして画像とテキストの両方を要求する
      responseModalities: ['IMAGE', 'TEXT'] 
    },
  };

  // APIリクエストのオプション
  const options = {
    method: 'post',
    contentType: 'application/json',
    payload: JSON.stringify(payload),
    muteHttpExceptions: true // HTTPエラー時に例外をスローさせず、レスポンスを直接受け取る
  };

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

  // レスポンスを解析
  if (responseCode === 200) {
    const jsonResponse = JSON.parse(responseBody);
    
    // レスポンスの中から画像データ部分を探す
    const imagePart = jsonResponse?.candidates?.[0]?.content?.parts?.find(p => p.inlineData);
    
    if (imagePart && imagePart.inlineData.data) {
      // 画像のBase64データを返す
      return imagePart.inlineData.data;
    } else {
      // 画像が見つからない場合のエラー
      console.error('API response did not contain image data. Response: ' + responseBody);
      // テキスト部分があれば、それをエラーメッセージとして利用
      const textPart = jsonResponse?.candidates?.[0]?.content?.parts?.find(p => p.text);
      const errorMessage = textPart ? textPart.text : 'No image data in response.';
      throw new Error(`API Error: ${errorMessage}`);
    }
  } else {
    // APIがエラーを返した場合
    console.error('API Error. Code: ' + responseCode + '. Body: ' + responseBody);
    throw new Error(`API request failed with status code ${responseCode}. Details: ${responseBody}`);
  }
}

設定と使用方法
Google Apps Scriptプロジェクトの作成:

Googleドライブで「新規」>「その他」>「Google Apps Script」を選択して、新しいプロジェクトを作成します。

上記のコードをコピーして、コード.gsファイルに貼り付けます。

APIキーの設定:

GASエディタの左側のメニューから「プロジェクトの設定」(歯車アイコン)をクリックします。

「スクリプト プロパティ」のセクションで、「スクリプト プロパティを追加」をクリックします。

プロパティに GEMINI_API_KEY と入力します。

値に、ご自身のGoogle AI StudioのAPIキーを貼り付けます。

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

デプロイ:

エディタ右上の「デプロイ」ボタンをクリックし、「新しいデプロイ」を選択します。

種類の選択で「ウェブアプリ」を選択します。

「アクセスできるユーザー」を**「全員」**に設定します。(App Inventorから呼び出すために必要です)

「デプロイ」ボタンをクリックします。初回は承認を求められるので、許可してください。

表示されるウェブアプリのURLをコピーします。このURLをApp Inventorから呼び出すことになります。

App Inventor側の実装(ヒント)
App Inventor側では、以下の手順でこのGASと連携します。

Webコンポーネントを配置します。

描画完了のボタンなどが押されたら、CanvasのSaveAsブロックを使って描画内容をファイルに保存し、そのファイルパスを取得します。

エクステンション(例: TaifunFileエクステンションなど)を使って、保存したファイルをBase64形式にエンコードします。

WebコンポーネントのPostTextブロックを使います。

url: 上記でコピーしたGASのウェブアプリURLを設定します。

text: joinブロックやBuildJsonブロック(Dictionaryを使うと便利)を使い、以下のようなJSON文字列を作成して渡します。

JSON

{"imageData": "(ここにBase64文字列)", "prompt": "プロのイラストレーター風にしてください"}
WebコンポーネントのGotTextイベントで、GASからの応答を受け取ります。

responseContentをJSONとしてパース(JsonTextDecodeブロック)します。

statusがsuccessであることを確認します。

imageDataキーの値(改良された画像のBase64文字列)を取得します。

取得したBase64文字列を、結果表示用の下のキャンバスのBackgroundImageプロパティなどに設定します。(data:image/png;base64,を先頭に付ける必要があるかもしれません)

これで、App Inventorで描いた絵をAIで改良して表示する仕組みが完成します。ご不明な点があれば、お気軽にご質問ください。

プロンプト

Gemini APIのAPIキーの取り方を生成AIお絵描きコーチアプリチュートリアルから転記します。

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