«Що приготувати з того, що є в холодильнику» — класичне завдання на обмежений інвентар. AI-асистент тут не просто пошуковик по базі рецептів, а генератор рецептів під конкретний набір інгредієнтів, дієтичні обмеження та час приготування. Ми беремо на себе реалізацію такого асистента під ключ: від проєктування до публікації в сторах.
На практиці це означає: користувач відкриває застосунок, фотографує полицю холодильника — і отримує три варіанти страв з урахуванням часу та дієти. Час від фото до рецепта — менше 5 секунд. Ми реалізували такі рішення для десятків клієнтів, що дозволило скоротити час на пошук рецептів у середньому на 40%.
Проблеми, які вирішує AI-асистент
Не знаєте, що приготувати з залишків?
Продукти закінчуються, а ідей немає. AI-асистент сканує вміст холодильника (текстом, голосом або фото) і генерує рецепт, використовуючи лише доступні інгредієнти. Базові продукти (сіль, олія, вода) додаються автоматично.
Алергії та дієти: як не помилитися?
Помилка у виборі страви може коштувати здоров'я. Ми реалізуємо гнучку систему фільтрів: користувач вказує алергії (горіхи, глютен, лактоза), дієту (веган, кето, палео), і промпт гарантує виключення заборонених інгредієнтів. Модель повертає JSON з повним складом, який можна перевірити.
Час приготування: як вкластися в 30 хвилин?
Працюючі професіонали цінують швидкі рецепти. Асистент враховує максимальний час готування і підбирає страви, які реально приготувати за вказаний термін. Кожен крок таймується, а таймер вбудований прямо в картку рецепта.
Як ми це робимо: стек і підхід
Розпізнавання інгредієнтів
Три канали введення, всі потрібні. Текстовий — очевидний. Голосовий — через SFSpeechRecognizer на iOS або SpeechRecognizer на Android. Найкорисніший — фото вмісту холодильника з розпізнаванням інгредієнтів.
Для розпізнавання ми використовуємо on-device моделі: CoreML на iOS та ML Kit на Android. Це швидше і приватніше за хмарні рішення. Наприклад, CoreML з моделлю, донавченою на Food-101, обробляє зображення за 200-300 мс, що в 3 рази швидше за Cloud Vision API (без урахування затримок мережі).
// iOS - розпізнавання інгредієнтів через Vision + CoreML
func recognizeIngredients(in image: UIImage) async throws -> [String] {
guard let cgImage = image.cgImage else { return [] }
let model = try FoodClassifier(configuration: .init())
let vnModel = try VNCoreMLModel(for: model.model)
let request = VNCoreMLRequest(model: vnModel)
request.imageCropAndScaleOption = .centerCrop
let handler = VNImageRequestHandler(cgImage: cgImage)
try handler.perform([request])
guard let results = request.results as? [VNClassificationObservation] else { return [] }
return results
.filter { $0.confidence > 0.6 }
.prefix(10)
.map { $0.identifier }
}
На Android використовуємо ML Kit ImageLabeler з локальною моделлю (RemoteModel завантажується при першому запуску). Вибір між on-device і cloud — компроміс швидкості та точності. Ми рекомендуємо on-device для базових продуктів і cloud для рідкісних інгредієнтів.
Порівняння підходів:
| Параметр | On-device (CoreML/ML Kit) | Cloud (Vision API) |
|---|---|---|
| Швидкість | 200-300 мс | 500-1500 мс + мережа |
| Приватність | Дані не покидають пристрій | Передача на сервер |
| Точність | ~85% базові продукти | ~95% рідкісні інгредієнти |
| Вартість | Безкоштовно | Плата за запити |
Технічні деталі інтеграції розпізнавання
Для iOS ми використовуємо Vision + CoreML з моделлю FoodClassifier (донавчена на Food-101). Конфіденційність забезпечується обробкою на пристрої. Для Android — ML Kit ImageLabeling з локальною моделлю.Генерація рецепта з урахуванням обмежень
Промпт — ключова частина. Ми будуємо його динамічно, додаючи обмеження з профілю користувача. response_format: json_object обов'язковий — парсити markdown-обгортку навколо JSON у продакшні не варто.
struct RecipeRequest: Encodable {
let ingredients: [String]
let servings: Int
let maxCookingMinutes: Int
let dietaryRestrictions: [String] // "vegan", "gluten-free", "nut-allergy", ...
let difficulty: String // "easy", "medium", "hard"
let cuisinePreferences: [String] // опціонально
}
func buildRecipePrompt(_ req: RecipeRequest) -> String {
"""
Create a recipe using ONLY these ingredients (you may add basic pantry staples: salt, oil, water, common spices):
Available: \(req.ingredients.joined(separator: ", "))
Requirements:
- Servings: \(req.servings)
- Max cooking time: \(req.maxCookingMinutes) minutes
- Dietary: \(req.dietaryRestrictions.isEmpty ? "none" : req.dietaryRestrictions.joined(separator: ", "))
- Difficulty: \(req.difficulty)
Return JSON: {name, cookingTime, servings, ingredients: [{name, amount, unit}], steps: [{number, instruction, duration}], nutrition: {calories, protein, carbs, fat}}
"""
}
Картка рецепта в UI
// Android Compose
@Composable
fun RecipeCard(recipe: Recipe) {
LazyColumn(
modifier = Modifier.fillMaxSize(),
contentPadding = PaddingValues(16.dp),
verticalArrangement = Arrangement.spacedBy(12.dp)
) {
item {
Text(recipe.name, style = MaterialTheme.typography.headlineSmall)
Row(horizontalArrangement = Arrangement.spacedBy(16.dp)) {
InfoChip(Icons.Default.Timer, "${recipe.cookingTime} хв")
InfoChip(Icons.Default.People, "${recipe.servings} порц.")
InfoChip(Icons.Default.LocalFireDepartment, "${recipe.nutrition.calories} ккал")
}
}
item { Text("Інгредієнти", style = MaterialTheme.typography.titleMedium) }
items(recipe.ingredients) { ing ->
Text("• ${ing.amount} ${ing.unit} ${ing.name}")
}
item { Text("Приготування", style = MaterialTheme.typography.titleMedium) }
itemsIndexed(recipe.steps) { index, step ->
StepCard(number = index + 1, instruction = step.instruction, duration = step.duration)
}
}
}
Таймер для кроків приготування
Кожен крок з часом запускає таймер прямо з картки. Ми використовуємо Timer і UNUserNotificationCenter для сповіщень, навіть якщо застосунок у фоні.
class StepTimerManager: ObservableObject {
@Published var activeTimers = [Int: TimeInterval]()
private var timers = [Int: Timer]()
func startTimer(for stepIndex: Int, duration: TimeInterval) {
activeTimers[stepIndex] = duration
timers[stepIndex] = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { [weak self] _ in
guard let self else { return }
if let remaining = self.activeTimers[stepIndex], remaining > 0 {
self.activeTimers[stepIndex] = remaining - 1
} else {
self.timers[stepIndex]?.invalidate()
self.notifyStepComplete(stepIndex)
}
}
}
private func notifyStepComplete(_ step: Int) {
let content = UNMutableNotificationContent()
content.title = "Крок \(step + 1) готовий"
content.sound = .default
UNUserNotificationCenter.current().add(
UNNotificationRequest(identifier: "step-\(step)", content: content, trigger: nil)
)
}
}
Чому важливо використовувати JSON response_format?
Без нього модель повертає markdown-обгортку з кодом. Парсити таку відповідь надійно — майже неможливо: модель може змінити форматування. Вказавши response_format: json_object, ми гарантуємо чистий JSON, який можна декодувати через Codable або Gson. Це прискорює розробку та знижує баги.
Як працює персоналізація рецептів?
Кожен збережений і приготований рецепт додається в профіль уподобань. При наступному запиті ми включаємо в промпт список страв, що сподобалися, що підвищує релевантність без необхідності fine-tuning моделі. Зберігання рецептів: SwiftData (iOS останніх версій) або Core Data — JSON-серіалізація структури рецепта в атрибут. На Android — Room з TypeConverter для List<Ingredient> та List<Step>.
Що входить в роботу
| Етап | Що робимо | Тривалість |
|---|---|---|
| Аналітика | Описуємо UX, сценарії використання, обмеження | 1–2 дні |
| Дизайн | UI-кіти для iOS та Android, адаптація під Material You / HIG | 3–5 днів |
| Розробка AI | Інтеграція розпізнавання, генерації, промпт-інжиніринг | 5–10 днів |
| Фронтенд | SwiftUI / Compose екрани, таймери, анімації | 5–7 днів |
| Бекенд | GraphQL / REST API, зберігання профілів, аналітика | 4–6 днів |
| Тестування | Unit + UI тести, навантажувальне тестування API | 3–5 днів |
| Деплой | Публікація в App Store / Google Play, налаштування CI/CD | 2–3 дні |
| Підтримка | Документація, навчання, гарантія 1 місяць | 5 днів |
Орієнтири за термінами
Базовий асистент (текстове введення + генерація рецепта) — від 3 днів. Повна реалізація з розпізнаванням фото, таймерами кроків, профілем уподобань та офлайн-зберіганням — від 4 тижнів. Вартість розраховується індивідуально після оцінки проєкту.
Досвід команди — 5+ років у мобільній розробці, понад 30 успішних проєктів. Ми гарантуємо дотримання вимог App Store та Google Play. Кожен проєкт проходить код-рев'ю та навантажувальне тестування.
Зв'яжіться з нами, щоб обговорити ваш проєкт та отримати індивідуальну оцінку.







