forked from mcintyre94/wisp
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathLoopModels.swift
More file actions
166 lines (142 loc) · 3.95 KB
/
LoopModels.swift
File metadata and controls
166 lines (142 loc) · 3.95 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
import Foundation
import SwiftData
// MARK: - Enums
enum LoopState: String, Codable, Sendable {
case active
case paused
case stopped
}
enum LoopInterval: Double, Codable, Sendable, CaseIterable {
case oneMinute = 60
case fiveMinutes = 300
case tenMinutes = 600
case fifteenMinutes = 900
case thirtyMinutes = 1800
case oneHour = 3600
var seconds: TimeInterval {
rawValue
}
var displayName: String {
switch self {
case .oneMinute: "1m"
case .fiveMinutes: "5m"
case .tenMinutes: "10m"
case .fifteenMinutes: "15m"
case .thirtyMinutes: "30m"
case .oneHour: "1h"
}
}
}
enum LoopDuration: Double, Codable, Sendable, CaseIterable {
case oneDay = 86400
case threeDays = 259200
case oneWeek = 604800
case oneMonth = 2592000
var timeInterval: TimeInterval {
rawValue
}
var displayName: String {
switch self {
case .oneDay: "1 Day"
case .threeDays: "3 Days"
case .oneWeek: "1 Week"
case .oneMonth: "1 Month"
}
}
}
enum IterationStatus: Codable, Sendable, Equatable {
case running
case completed
case failed(String)
case skipped
}
// MARK: - SpriteLoop
@Model
final class SpriteLoop {
var id: UUID
var spriteName: String
var workingDirectory: String
var prompt: String
var intervalRaw: Double
var stateRaw: String
var createdAt: Date
var expiresAt: Date
var lastRunAt: Date?
var nextRunAt: Date
var iterationsData: Data?
var interval: LoopInterval {
get { LoopInterval(rawValue: intervalRaw) ?? .tenMinutes }
set { intervalRaw = newValue.rawValue }
}
var state: LoopState {
get { LoopState(rawValue: stateRaw) ?? .active }
set { stateRaw = newValue.rawValue }
}
var isExpired: Bool {
Date() >= expiresAt
}
var timeRemainingDisplay: String {
let remaining = expiresAt.timeIntervalSince(Date())
if remaining <= 0 { return "Expired" }
let hours = Int(remaining) / 3600
let days = hours / 24
if days > 0 {
return "\(days)d \(hours % 24)h remaining"
} else if hours > 0 {
let minutes = (Int(remaining) % 3600) / 60
return "\(hours)h \(minutes)m remaining"
} else {
let minutes = Int(remaining) / 60
return "\(minutes)m remaining"
}
}
var iterations: [LoopIteration] {
get {
guard let data = iterationsData else { return [] }
return (try? JSONDecoder().decode([LoopIteration].self, from: data)) ?? []
}
set {
iterationsData = try? JSONEncoder().encode(newValue)
}
}
init(
spriteName: String,
workingDirectory: String,
prompt: String,
interval: LoopInterval,
duration: LoopDuration = .oneWeek
) {
let createdAt = Date()
self.id = UUID()
self.spriteName = spriteName
self.workingDirectory = workingDirectory
self.prompt = prompt
self.intervalRaw = interval.rawValue
self.stateRaw = LoopState.active.rawValue
self.createdAt = createdAt
self.expiresAt = createdAt.addingTimeInterval(duration.timeInterval)
self.nextRunAt = createdAt
}
func markDueNow(at date: Date = Date()) {
nextRunAt = date
}
func scheduleNextRun(after referenceDate: Date) {
nextRunAt = referenceDate.addingTimeInterval(interval.seconds)
}
}
// MARK: - LoopIteration
struct LoopIteration: Identifiable, Codable, Sendable {
var id: UUID
var startedAt: Date
var completedAt: Date?
var prompt: String
var responseText: String?
var status: IterationStatus
var notificationSummary: String?
init(prompt: String) {
self.id = UUID()
self.startedAt = Date()
self.prompt = prompt
self.status = .running
}
}