Реализация AI-планировщика задач в мобильном приложении
AI-планировщик — не просто чат, который добавляет задачи в список. Это интеграция естественного языка с реальной логикой: парсинг дедлайнов, расстановка приоритетов, учёт текущей загруженности, синхронизация с нативным календарём.
Парсинг задач из естественного языка
Пользователь пишет «Позвонить Игорю до конца недели насчёт презентации, важно» — нужно извлечь: название задачи, дедлайн, приоритет, возможно привязку к контакту.
Function calling в OpenAI — правильный инструмент:
let tools: [[String: Any]] = [{
"type": "function",
"function": {
"name": "add_task",
"description": "Add a task extracted from user input",
"parameters": {
"type": "object",
"properties": {
"title": {"type": "string", "description": "Task title, concise"},
"due_date": {"type": "string", "format": "date-time", "description": "ISO 8601 deadline if mentioned"},
"priority": {"type": "string", "enum": ["low", "medium", "high", "urgent"]},
"tags": {"type": "array", "items": {"type": "string"}},
"contact_name": {"type": "string", "description": "Person involved if mentioned"}
},
"required": ["title"]
}
}
}]
Контекст для промпта обязателен: текущая дата/время и часовой пояс, иначе «до конца недели» не распарсить.
let systemPrompt = """
Today is \(ISO8601DateFormatter().string(from: Date())).
Timezone: \(TimeZone.current.identifier).
Extract task details from user input. For relative dates ('next week', 'tomorrow', 'end of week'), calculate exact dates.
"""
Умная расстановка приоритетов
Пользователи плохо расставляют приоритеты сами — всё кажется срочным. AI может переоценить очередь задач по дедлайнам и паттернам.
struct TaskPrioritizationInput: Encodable {
let tasks: [TaskItem]
let currentDateTime: String
let workingHoursPerDay: Int
}
// Запрос на переоценку приоритетов
func reprioritize(_ tasks: [TaskItem]) async throws -> [TaskItem] {
let input = TaskPrioritizationInput(
tasks: tasks,
currentDateTime: ISO8601DateFormatter().string(from: Date()),
workingHoursPerDay: userSettings.workHours
)
let prompt = """
Reorder these tasks by urgency+importance matrix.
Consider deadlines and estimated durations.
Mark overdue tasks as urgent.
Return the same array with updated priority field.
Current tasks: \(try JSONEncoder().encode(input).utf8String)
"""
let response = try await openAI.chat(messages: [.system(prompt)])
return try JSONDecoder().decode([TaskItem].self, from: response.text.data(using: .utf8)!)
}
Интеграция с EventKit (iOS) и ContentProvider (Android)
AI-планировщик без синхронизации с системным календарём — половина ценности. EventKit на iOS даёт доступ к Calendar и Reminders.
import EventKit
class CalendarIntegration {
let store = EKEventStore()
func addReminder(for task: TaskItem) async throws {
let granted = try await store.requestFullAccessToReminders()
guard granted else { throw IntegrationError.permissionDenied }
let reminder = EKReminder(eventStore: store)
reminder.title = task.title
reminder.priority = task.priority.ekPriority // Int 1-9
reminder.calendar = store.defaultCalendarForNewReminders()
if let due = task.dueDate {
let components = Calendar.current.dateComponents(
[.year, .month, .day, .hour, .minute],
from: due
)
reminder.dueDateComponents = components
reminder.addAlarm(EKAlarm(relativeOffset: -3600)) // -1 час напоминание
}
try store.save(reminder, commit: true)
}
}
На Android — CalendarContract для событий в календаре, ReminderProvider недоступен системно, используем AlarmManager + NotificationManager для напоминаний.
Ежедневный AI-бриф
Утром при открытии приложения генерируем короткий план дня на основе текущих задач. Это не полноценный чат, а одиночный prompt-to-text:
func generateDailyBrief(tasks: [TaskItem]) async throws -> String {
let todayTasks = tasks.filter { task in
guard let due = task.dueDate else { return task.priority == .urgent }
return Calendar.current.isDateInToday(due) || due < Date()
}
let prompt = """
Create a short (3-5 sentences) morning briefing for the user's day.
Focus on what's most urgent and what should be done first.
Be direct and practical, not motivational.
Tasks: \(todayTasks.map { "\($0.title) [priority: \($0.priority), due: \($0.dueDate?.formatted() ?? "today")]" }.joined(separator: "; "))
"""
return try await openAI.complete(prompt: prompt)
}
Голосовой ввод задач
Большая часть добавления задач в мобильном приложении происходит голосом — быстро, без печати. На iOS — SFSpeechRecognizer, на Android — SpeechRecognizer API.
Важно: не нужно ждать конца фразы. Используем .continuous режим и обрабатываем транскрипт по паузам > 1.5 секунды.
recognitionRequest.shouldReportPartialResults = true
recognitionTask = recognizer.recognitionTask(with: recognitionRequest) { [weak self] result, error in
guard let result else { return }
self?.lastTranscript = result.bestTranscription.formattedString
if result.isFinal {
self?.processVoiceInput(self?.lastTranscript ?? "")
}
}
После транскрипции текст идёт через тот же function calling пайплайн что и при текстовом вводе.
Ориентиры по срокам
Базовый ввод задач через natural language + function calling — 3–5 дней. Полноценный планировщик с приоритизацией, CalendarKit интеграцией, утренним брифом и голосовым вводом — 3–5 недель.







