生成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"と名前を付けます。