Add AI-powered mental wellness features: Reflection Companion, Pattern Tags, Weekly Digest
Three new Foundation Models features to deepen user engagement with mental wellness: 1. AI Reflection Companion — personalized feedback after completing guided reflections, referencing the user's actual words with personality-pack-adapted tone 2. Mood Pattern Tags — auto-extracts theme tags (work, family, stress, etc.) from notes and reflections, displayed as colored pills on entries 3. Weekly Emotional Digest — BGTask-scheduled Sunday digest with headline, summary, highlight, and intention; shown as card in Insights tab with notification All features: on-device (zero cost), premium-gated, iOS 26+ with graceful degradation. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
64
Shared/Models/AIWeeklyDigest.swift
Normal file
64
Shared/Models/AIWeeklyDigest.swift
Normal file
@@ -0,0 +1,64 @@
|
||||
//
|
||||
// AIWeeklyDigest.swift
|
||||
// Reflect
|
||||
//
|
||||
// @Generable model and storage for AI-generated weekly emotional digest.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import FoundationModels
|
||||
|
||||
/// AI-generated weekly mood digest
|
||||
@available(iOS 26, *)
|
||||
@Generable
|
||||
struct AIWeeklyDigestResponse: Equatable {
|
||||
@Guide(description: "An engaging headline summarizing the week's emotional arc (3-7 words)")
|
||||
var headline: String
|
||||
|
||||
@Guide(description: "A warm 2-3 sentence summary of the week's mood patterns and notable moments")
|
||||
var summary: String
|
||||
|
||||
@Guide(description: "The best moment or strongest positive pattern from the week (1 sentence)")
|
||||
var highlight: String
|
||||
|
||||
@Guide(description: "A gentle, actionable intention or suggestion for the coming week (1 sentence)")
|
||||
var intention: String
|
||||
|
||||
@Guide(description: "SF Symbol name for the digest icon (e.g., sun.max.fill, leaf.fill, heart.fill)")
|
||||
var iconName: String
|
||||
}
|
||||
|
||||
/// Storable weekly digest (Codable for UserDefaults persistence)
|
||||
struct WeeklyDigest: Codable, Equatable {
|
||||
let headline: String
|
||||
let summary: String
|
||||
let highlight: String
|
||||
let intention: String
|
||||
let iconName: String
|
||||
let generatedAt: Date
|
||||
let weekStartDate: Date
|
||||
let weekEndDate: Date
|
||||
|
||||
var isFromCurrentWeek: Bool {
|
||||
let calendar = Calendar.current
|
||||
let now = Date()
|
||||
let currentWeekStart = calendar.dateInterval(of: .weekOfYear, for: now)?.start ?? now
|
||||
let digestWeekStart = calendar.dateInterval(of: .weekOfYear, for: weekStartDate)?.start ?? weekStartDate
|
||||
return calendar.isDate(currentWeekStart, inSameDayAs: digestWeekStart) ||
|
||||
calendar.isDate(digestWeekStart, inSameDayAs: calendar.date(byAdding: .weekOfYear, value: -1, to: currentWeekStart)!)
|
||||
}
|
||||
|
||||
/// Whether the digest was dismissed by the user
|
||||
static var isDismissedKey: String { "weeklyDigestDismissedDate" }
|
||||
|
||||
static func markDismissed() {
|
||||
GroupUserDefaults.groupDefaults.set(Date(), forKey: isDismissedKey)
|
||||
}
|
||||
|
||||
static func isDismissed(for digest: WeeklyDigest) -> Bool {
|
||||
guard let dismissedDate = GroupUserDefaults.groupDefaults.object(forKey: isDismissedKey) as? Date else {
|
||||
return false
|
||||
}
|
||||
return dismissedDate >= digest.generatedAt
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user