生成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"と名前を付けます。
デザイン編集
Screen1のタイトルを"生成AI写真解説"にします。
uk.co.metricrat.imagebase64v2.aixエクステンションを https://metricrat-hosting.web.app/files/uk.co.metricrat.imagebase64v2.aix からダウンロードし、エクステンションパレットにアップロード後、ビューアーに追加します。
ユーザーインターフェース パレットからラベル、テキストボックス、ラベル、画像をこの順番でビューアーに追加します。名前はそれぞれラベル1、テキストボックス1、ラベル2、画像1になります。
レイアウト パレットから 水平配置コンポーネント を画像1の下に追加し、その中にユーザーインターフェース パレットからボタンを追加します。名前はそれぞれ水平配置1、ボタン1なります。
最後に接続 パレットからウェブ、メディアパレットからカメラを追加します。名前はそれぞれウェブ1、カメラ1になります。
プロパティーは以下の通り設定します。
- ラベル1: 太字フォント=チェック、フォントサイズ=20、テキスト=写真の解説
- テキストボックス1: 背景の色=グレー、高さ=20パーセント、横幅="親要素に合わせる"、テキストカラー=白、マルチライン=チェック
- ラベル2: 太字フォント=チェック、フォントサイズ=20、テキスト=写真
- 画像1: 高さ="親要素に合わせる"、横幅="親要素に合わせる"、回転角度=90、目にみえる=チェック
- 水平配置1: 水平に整列する=”中央揃え”、横幅="親要素に合わせる"
- ボタン1: テキスト=解析実行
- ウェブ1: 変更なし
下図のようになります。

ブロック編集機能を使用したプログラミング
グローバル変数
内蔵ブロック の 変数 カテゴリから”グローバル変数 変数名 を次の値で初期化”ブロックをドラッグアンドドロップして、変数名を以下のように変更し初期値を設定します。
- ポストurl: ウェブアプリのURL。Google Apps Scriptの設定でコピーしておいたウェブアプリのURLを入力します。
- base64エンコード: base64エンコードした結果を格納する変数
- レスポンスディクショナリ: 受け取ったJsonテキストをデコードしたディクショナリを格納する変数
- status: 受け取ったJsonテキストのなかのstatusの文字列、success または error
- 解析中: 解析中に表示する文字列

スクリーン初期化
アプリ起動時の初期化をするために、ブロック編集機能の左側にあるScreen1パネルをクリックして開き、”いつもScreen1.初期化したら 実行する”をドラッグアンドドロップし、この中でウェブ1のUrlにポストurl変数をセットします。

撮影ボタンクリック
撮影ボタンがクリックされたらカメラ1.撮影するを呼び出します。

撮影終了後
カメラで撮影が終了するといつもカメラ1.撮影終了後イベントがトリガーされるので以下を実行します。
- 画像1に撮影した画像を表示
- 画像1をBase64エンコード
- テキストボックス1に解析中を表示

Base64エンコード後
Base64エンコードが終了すると いつもImageBase641.AfterImageBase64 実行する イベントがトリガーされます。
Gemini APIではBase64エンコードした文字列に改行が入っているとエラーを起こすので、Base64エンコードした文字列から改行文字(\n)を除き、imageをキーにBase64エンコードした文字列を値にしたディクショナリからウェブ1.Jsonオブジェクトのエンコードを呼んで、Jsonテキストをウェブ1にポストすることによりGASを呼びます。

GASから結果が戻ったら
GASから結果が戻ると ウェブ1.テキストを取得したら イベントがトリガーされるので、受け取ったJsonテキストをデコードして認識結果を表示します。必ずしもうまく認識できるとは限らないのでエラー処理もしています。

ダウンロード
ソースコード(aiaファイル): ここからダウンロード