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>
This commit is contained in:
68
Shared/Models/AIInsight.swift
Normal file
68
Shared/Models/AIInsight.swift
Normal file
@@ -0,0 +1,68 @@
|
||||
//
|
||||
// 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() }
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user