🍳 はじめに
こんにちは!最近、冷蔵庫の余り物問題を解決すべく、AIレシピ提案アプリ 「Butler's Kitchen」 を開発・リリースしました。
本記事では、Google の Gemini API や Imagen 4 を iOS アプリに組み込む際の実装の工夫や、多言語対応でのハマりどころなどを技術的な視点で共有します。
📱 アプリ概要
食材をカメラスキャン、あるいは入力すると AI が「10分レシピ」を提案してくれます。
- Stack: SwiftUI, SwiftData, Google Generative AI SDK (Gemini 2.0/2.5 Flash)
- 特徴: レシピ生成だけでなく、Imagen モデルによる完成予想図の生成も行います。
🛠 技術的な工夫と実装の裏側
1. JSON モードによる安定したレスポンス取得
AI からのレスポンスをアプリで扱う際、最も苦労するのが「パース」です。
今回は GenerationConfig で responseMIMEType を application/json に指定し、確実な構造化データを取得するようにしました。
let config = GenerationConfig(responseMIMEType: "application/json")
let model = GenerativeModel(name: "gemini-2.5-flash", apiKey: apiKey, generationConfig: config)
// プロンプトで JSON スキーマを厳格に指定
let prompt = """
Use the following ingredients: [\(ingredients)] to propose one creative recipe.
Output must be in JSON format:
{
"title": "Recipe Title",
"ingredients": ["item 1", "item 2"],
"steps": ["Step 1", "Step 2"]
}
"""
2. 多言語対応(Localization)の設計戦略 (v1.1)
最新の v1.1 では、ジャンル選択の多言語対応を行いました。ここでこだわったのは、「表示言語」と「AI エンジン言語」の分離 です。
-
表示:
String(localized:)と.xcstringsを利用してユーザーの端末設定に合わせる。 - AI への指示: 英語の方が推論精度が高くトークン効率も良いため、内部的には英語の ID(rawValue)をプロンプトに使用。
enum RecipeGenre: String, CaseIterable {
case japanese = "Japanese"
// ユーザー表示用
var displayName: String {
return String(localized: "GENRE_JAPANESE") // システム言語に依存
}
// AIプロンプト用
var promptDescription: String {
return "Recipe genre should be within \(self.rawValue) style." // 常に英語
}
}
3. Imagen 4 による画像生成とコスト管理
料理の完成イメージは Imagen モードで生成していますが、API コストを考慮して「リワード広告(AdMob)によるポイント制」を導入しました。
PointsManager を自作し、ユーザーが能動的にポイントを貯めて使う体験にすることで、無料でのサービス維持を可能にしています。
🚀 開発中の試行錯誤
💡 プロンプト・エンジニアリングの沼
最初は「卵と豆腐」などのシンプルな食材だと、AI が「卵焼きに豆腐を添えるだけ」のような手抜きレシピを出すことがありました(笑)。
「驚き(Surprise)」「10分以内のリアリティ」「プロフェッショナルな盛り付け」といったキーワードをプロンプトに盛り込むことで、現在の「10分で作れるクリエイティブなレシピ」という着地点を見出しました。
📝 まとめ
Gemini API を使った個人開発は、以前よりも JSON モードの安定感が増しており、非常に触りやすくなっています。
Butler's Kitchen も、さらに最新モデルを追いかけながら、最高のキッチン体験を作っていきたいと思います。
App Store で公開中!
もしよろしければ、いいね・フォローお願いいたします!
