Files
Reflect/Shared/Models/AIInsight.swift
Trey t 5974002a82 Add AI-powered insights using Apple Foundation Models
- Replace static insights with on-device AI generation via FoundationModels framework
- Add @Generable AIInsight model for structured LLM output
- Create FoundationModelsInsightService with session-per-request for concurrent generation
- Add MoodDataSummarizer to prepare mood data for AI analysis
- Implement loading states with skeleton UI and pull-to-refresh
- Add AI availability badge and error handling
- Support default (supportive) and rude (sarcastic) personality modes
- Optimize prompts to fit within 4096 token context limit
- Bump iOS deployment target to 26.0 for Foundation Models support

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-13 10:20:11 -06:00

69 lines
2.1 KiB
Swift

//
// AIInsight.swift
// Feels
//
// Created by Claude Code on 12/13/24.
//
import Foundation
import FoundationModels
/// Represents a single AI-generated insight using @Generable for structured LLM output
@Generable
struct AIInsight: Equatable {
@Guide(description: "A brief, engaging title for the insight (3-6 words)")
var title: String
@Guide(description: "A detailed, personalized description of the insight (1-2 sentences)")
var description: String
@Guide(description: "The type of insight: pattern (observed trend), advice (recommendation), prediction (future forecast), achievement (milestone), or trend (direction analysis)")
var insightType: String
@Guide(description: "The primary mood associated with this insight: great, good, average, bad, horrible, or none")
var associatedMood: String
@Guide(description: "SF Symbol name for the insight icon (e.g., star.fill, chart.line.uptrend.xyaxis, heart.fill)")
var iconName: String
@Guide(description: "Sentiment of the insight: positive, neutral, or negative")
var sentiment: String
}
/// Container for period-specific insights - the LLM generates this structure
@Generable
struct AIInsightsResponse: Equatable {
@Guide(description: "Array of exactly 5 diverse insights covering patterns, advice, and predictions")
var insights: [AIInsight]
}
// MARK: - Conversion to App's Insight Model
extension AIInsight {
/// Converts AI-generated insight to the app's existing Insight model
func toInsight() -> Insight {
let mood: Mood? = switch associatedMood.lowercased() {
case "great": .great
case "good": .good
case "average": .average
case "bad": .bad
case "horrible": .horrible
default: nil
}
return Insight(
icon: iconName,
title: title,
description: description,
mood: mood
)
}
}
extension AIInsightsResponse {
/// Converts all AI insights to app's Insight models
func toInsights() -> [Insight] {
insights.map { $0.toInsight() }
}
}