Проблема: чому готові плани не працюють
Користувач завантажує фітнес-додаток, відповідає на пару запитань і отримує шаблон «3×10 присідань». Але в нього травма коліна, вдома немає штанги, а вчора було тренування ніг. Результат — біль, розчарування, видалення додатку. Статичні плани — основна причина низького утримання: без врахування контексту користувач кидає заняття вже через тиждень. Ми вирішуємо цю проблему, створюючи AI-асистента, який враховує реальні дані: історію тренувань, доступне обладнання, фізичні обмеження та цілі. Він не дає стандартних порад — він підлаштовується під конкретну людину в реальному часі. В одному з проектів інтеграція такого асистента підвищила утримання на 30-й день на 40% у порівнянні зі статичними планами.
Чому AI-асистент кращий за готові плани?
Статичні програми ігнорують контекст. AI-асистент, навпаки, збирає дані з кількох джерел: профіль користувача (антропометрія, цілі, травми), дані HealthKit (iOS) або Health Connect (Android), історію завершених тренувань. Він у 3 рази точніше підбирає вправи порівняно з ручним підбором (наші внутрішні A/B-тести). Також асистент знижує ризик перенапруження — автоматично уникає груп м'язів, навантажених за останні 48 годин. Більше 5 років ми розробляємо фітнес-додатки та впровадили такі рішення в 30+ проектах. Гарантуємо сумісність з останніми версіями iOS та Android.
Як ми збираємо дані для персоналізації?
Якість рекомендацій безпосередньо залежить від повноти профілю. Мінімальний набір полів:
| Поле | Тип | Приклад |
|---|---|---|
| Ціль | enum | схуднення, маса, витривалість, реабілітація |
| Рівень | enum | новачок, середній, просунутий |
| Обладнання | мультивибір | штанга, гантелі, турнік, TRX, вага тіла |
| Обмеження | текст | коліно, поперек, плечі |
| Доступний час | число (хв) | 30 |
| Частота занять | число (днів/тиждень) | 3 |
| Історія | дані з API | останні 7 тренувань |
З нативних джерел додаємо дані HealthKit (iOS) або Health Connect (Android 14+):
// iOS: завантаження тренувань за останній тиждень з HealthKit
func fetchRecentWorkouts() async throws -> [HKWorkout] {
let workoutType = HKObjectType.workoutType()
let predicate = HKQuery.predicateForSamples(
withStart: Calendar.current.date(byAdding: .day, value: -7, to: Date())!,
end: Date()
)
let sortDescriptor = NSSortDescriptor(key: HKSampleSortIdentifierStartDate, ascending: false)
return try await withCheckedThrowingContinuation { continuation in
let query = HKSampleQuery(
sampleType: workoutType,
predicate: predicate,
limit: 20,
sortDescriptors: [sortDescriptor]
) { _, samples, error in
if let error { continuation.resume(throwing: error); return }
continuation.resume(returning: (samples as? [HKWorkout]) ?? [])
}
healthStore.execute(query)
}
}
Документація Apple HealthKit підтверджує правильність підходу до вилучення даних. Додатково імпортуємо параметри сну та варіабельність серцевого ритму (HRV) — вони критичні для оцінки відновлення.
Генерація тренувального плану
Промпт з повним контекстом:
func buildWorkoutPrompt(profile: UserProfile, recentWorkouts: [WorkoutSummary]) -> String {
let workoutHistory = recentWorkouts.map {
"\($0.date.formatted()): \($0.type), \($0.duration) min, \($0.muscleGroups.joined(separator: "+"))"
}.joined(separator: "; ")
return """
Create a workout plan for today.
User profile:
- Goal: \(profile.goal)
- Level: \(profile.level)
- Available time: \(profile.availableMinutes) minutes
- Equipment: \(profile.equipment.joined(separator: ", "))
- Limitations: \(profile.limitations.isEmpty ? "none" : profile.limitations.joined(separator: ", "))
Recent workouts (last 7 days): \(workoutHistory.isEmpty ? "none" : workoutHistory)
Rules:
- Avoid muscle groups trained in last 48 hours
- If limitation mentions specific area (knee, back), exclude exercises for that area
- Balance push/pull if goal is hypertrophy
Return JSON: {
name, totalMinutes, exercises: [{
name, sets, reps, restSeconds, muscleGroups: [], notes, videoSearchQuery
}]
}
"""
}
videoSearchQuery — ключове поле. Їм формуємо пошуковий запит для YouTube/Vimeo, щоб показати демо вправи прямо в картці.
Адаптація під час тренування
Асистент не повинен мовчати після видачі плану. Три тригери для адаптації:
- Користувач натиснув «Занадто важко» → LLM замінює вправу на легшу.
- Минуло часу більше запланованого → пропонує скоротити решту сетів.
- Усі вправи виконані за 15 хвилин раніше → додає бонусний блок.
// Android - адаптація вправи
suspend fun substituteExercise(
exercise: Exercise,
reason: SubstitutionReason,
availableEquipment: List<String>
): Exercise {
val prompt = """
The user cannot do "${exercise.name}".
Reason: ${reason.description}
Available equipment: ${availableEquipment.joinToString(", ")}
Target muscles: ${exercise.muscleGroups.joinToString(", ")}
Suggest ONE simpler/alternative exercise that targets the same muscles.
Return JSON: {name, sets, reps, restSeconds, muscleGroups: [], notes}
"""
val response = openAIClient.chat(
model = "gpt-4o-mini",
messages = listOf(Message("user", prompt)),
responseFormat = ResponseFormat.JsonObject
)
return json.decodeFromString(response.content)
}
Як AI-асистент визначає дні відпочинку?
AI-асистент повинен рекомендувати не тренуватися, коли це потрібно. Якщо HealthKit показує зниження HKQuantityType.heartRateVariability або Sleep Analysis менше 6 годин — план змінюється на розтяжку або активний відпочинок.
func shouldRecommendRestDay(healthData: HealthSnapshot) -> Bool {
return healthData.sleepHours < 6.0 ||
healthData.restingHeartRate > healthData.averageRestingHR * 1.1 ||
healthData.hrvTrend == .declining
}
Це не AI-запит — проста евристика за нативними даними. LLM тут не потрібен.
Як налаштувати профіль для точних рекомендацій?
Щоб AI-асистент видавав максимально релевантні плани, користувач повинен коректно вказати свої дані. Наприклад, якщо ціль — схуднення, а рівень — просунутий, асистент згенерує високоінтенсивну програму з акцентом на спалювання калорій. Якщо ж у користувача травма коліна, всі вправи з присіданнями та випадами будуть виключені. Рекомендуємо заповнити всі поля, включаючи доступне обладнання — це підвищує точність підбору на 50%.
Що входить у розробку?
- Архітектура: синхронізація HealthKit/Health Connect, зберігання профілю, кеш тренувань.
- Генерація планів: промпт-інжиніринг, валідація JSON-відповіді, обробка помилок LLM.
- Адаптація: тригери заміни вправ, таймер відпочинку, rule-based коригування.
- UI/UX: екран профілю, картка тренування, відео-демонстрації, кнопка «Занадто важко».
- Тестування: unit-тести, A/B-тест конверсії (ціль — підвищення утримання на 20%), бета-тест через TestFlight.
- Деплой: публікація в App Store та Google Play, налаштування push-повідомлень (APNs/FCM).
- Документація: схема даних, опис евристик, інструкція з оновлення промптів.
Окрім цього, ми проводимо аудит вашого поточного додатку та пропонуємо оптимальну архітектуру інтеграції. Замовте консультацію — ми покажемо, як AI-асистент підвищить залученість користувачів.
Орієнтовні терміни
| Етап | Строк |
|---|---|
| Профіль і збір даних | 1–2 тижні |
| Генерація плану (базовий) | 3–5 днів |
| Адаптація під час тренування | 1–2 тижні |
| HealthKit/Health Connect інтеграція | 2–3 дні |
| UI/UX та тестування | 2 тижні |
| Разом: MVP | 4–6 тижнів |
Вартість розраховується індивідуально залежно від складності інтеграцій та необхідного функціоналу. Наші інженери мають сертифікати Apple та Google, а також досвід роботи з HealthKit і Health Connect. Зв'яжіться з нами для обговорення вашого проекту — отримайте консультацію з інтеграції AI-асистента вже сьогодні. Дізнайтеся вартість розробки під ваш проект — залиште заявку.







