Walks users through 3-4 guided questions based on mood category: positive (great/good) gets gratitude-oriented questions, neutral (average) gets exploratory questions, and negative (bad/horrible) gets empathetic questions. Stored as JSON in MoodEntryModel, integrated into PDF reports, AI summaries, and CSV export. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
149 lines
4.6 KiB
Swift
149 lines
4.6 KiB
Swift
//
|
|
// AIReport.swift
|
|
// Reflect
|
|
//
|
|
// Data models for AI-generated mood reports with PDF export.
|
|
//
|
|
|
|
import Foundation
|
|
import FoundationModels
|
|
|
|
// MARK: - Report Type
|
|
|
|
enum ReportType: String, CaseIterable {
|
|
case quickSummary = "Quick Summary"
|
|
case detailed = "Detailed Report"
|
|
|
|
var icon: String {
|
|
switch self {
|
|
case .quickSummary: return "doc.text"
|
|
case .detailed: return "doc.text.magnifyingglass"
|
|
}
|
|
}
|
|
|
|
var description: String {
|
|
switch self {
|
|
case .quickSummary: return "AI overview of your mood patterns"
|
|
case .detailed: return "Week-by-week analysis with full data"
|
|
}
|
|
}
|
|
}
|
|
|
|
// MARK: - Report Entry (decoupled from SwiftData)
|
|
|
|
struct ReportEntry {
|
|
let date: Date
|
|
let mood: Mood
|
|
let notes: String?
|
|
let weather: WeatherData?
|
|
let reflection: GuidedReflection?
|
|
|
|
init(from model: MoodEntryModel) {
|
|
self.date = model.forDate
|
|
self.mood = model.mood
|
|
self.notes = model.notes
|
|
self.weather = model.weatherJSON.flatMap { WeatherData.decode(from: $0) }
|
|
self.reflection = model.reflectionJSON.flatMap { GuidedReflection.decode(from: $0) }
|
|
}
|
|
}
|
|
|
|
// MARK: - Report Overview Stats
|
|
|
|
struct ReportOverviewStats {
|
|
let totalEntries: Int
|
|
let averageMood: Double
|
|
let moodDistribution: [Mood: Int]
|
|
let trend: String
|
|
let dateRange: String
|
|
}
|
|
|
|
// MARK: - Report Week
|
|
|
|
struct ReportWeek: Identifiable {
|
|
let id = UUID()
|
|
let weekNumber: Int
|
|
let startDate: Date
|
|
let endDate: Date
|
|
let entries: [ReportEntry]
|
|
var aiSummary: String?
|
|
}
|
|
|
|
// MARK: - Report Month Summary
|
|
|
|
struct ReportMonthSummary: Identifiable {
|
|
let id = UUID()
|
|
let month: Int
|
|
let year: Int
|
|
let entryCount: Int
|
|
let averageMood: Double
|
|
var aiSummary: String?
|
|
|
|
var title: String {
|
|
let formatter = DateFormatter()
|
|
formatter.dateFormat = "MMMM yyyy"
|
|
var components = DateComponents()
|
|
components.month = month
|
|
components.year = year
|
|
let date = Calendar.current.date(from: components) ?? Date()
|
|
return formatter.string(from: date)
|
|
}
|
|
}
|
|
|
|
// MARK: - Report Year Summary
|
|
|
|
struct ReportYearSummary: Identifiable {
|
|
let id = UUID()
|
|
let year: Int
|
|
let entryCount: Int
|
|
let averageMood: Double
|
|
var aiSummary: String?
|
|
}
|
|
|
|
// MARK: - Assembled Report
|
|
|
|
struct MoodReport {
|
|
let reportType: ReportType
|
|
let generatedAt: Date
|
|
let overview: ReportOverviewStats
|
|
let weeks: [ReportWeek]
|
|
let monthlySummaries: [ReportMonthSummary]
|
|
let yearlySummaries: [ReportYearSummary]
|
|
var quickSummary: String?
|
|
}
|
|
|
|
// MARK: - @Generable AI Response Structs
|
|
|
|
@available(iOS 26, *)
|
|
@Generable
|
|
struct AIWeeklySummary: Equatable {
|
|
@Guide(description: "A clinical, factual summary of the user's mood patterns for this week. Use third-person perspective (e.g., 'The individual'). 2-3 sentences covering mood trends, notable patterns, and any significant changes. Neutral, professional tone suitable for a therapist to read.")
|
|
var summary: String
|
|
}
|
|
|
|
@available(iOS 26, *)
|
|
@Generable
|
|
struct AIMonthSummary: Equatable {
|
|
@Guide(description: "A clinical, factual summary of the user's mood patterns for this month. Use third-person perspective. 3-4 sentences covering overall mood trend, week-over-week changes, and notable patterns. Professional tone suitable for clinical review.")
|
|
var summary: String
|
|
}
|
|
|
|
@available(iOS 26, *)
|
|
@Generable
|
|
struct AIYearSummary: Equatable {
|
|
@Guide(description: "A clinical, factual summary of the user's mood patterns for this year. Use third-person perspective. 3-5 sentences covering seasonal patterns, long-term trends, and significant periods. Professional tone suitable for clinical review.")
|
|
var summary: String
|
|
}
|
|
|
|
@available(iOS 26, *)
|
|
@Generable
|
|
struct AIQuickSummaryResponse: Equatable {
|
|
@Guide(description: "A comprehensive clinical summary of the user's mood data for the selected period. Use third-person perspective (e.g., 'The individual'). 4-6 sentences covering: overall mood patterns, notable trends, day-of-week patterns, and any areas of concern or improvement. Factual, neutral, professional tone suitable for sharing with a therapist.")
|
|
var summary: String
|
|
|
|
@Guide(description: "2-3 key clinical observations as brief bullet points. Each should be a single factual sentence about a pattern or trend observed in the data.")
|
|
var keyObservations: [String]
|
|
|
|
@Guide(description: "1-2 brief, neutral recommendations based on observed patterns. Frame as observations rather than prescriptions (e.g., 'Mood data suggests weekday routines may benefit from...').")
|
|
var recommendations: [String]
|
|
}
|