Files
rely/lib/features/ai_digest/domain/ai_digest_models.dart
T
2026-05-19 19:17:35 +02:00

240 lines
7.2 KiB
Dart

// ignore_for_file: sort_constructors_first
import 'package:flutter/foundation.dart';
enum AiSuggestionKind { giftIdea, eventIdea, checkIn, reminder }
enum AiSuggestionStatus { pending, accepted, dismissed }
enum LlmDigestCadence { weekly }
@immutable
class AiSuggestionDraft {
const AiSuggestionDraft({
required this.id,
required this.personId,
required this.kind,
required this.title,
required this.details,
required this.suggestedAt,
required this.confidence,
required this.status,
required this.sourceRunId,
this.suggestedFor,
this.eventEndsAt,
this.eventLocation,
this.eventUrl,
this.sourceUrls = const <String>[],
this.reason,
});
final String id;
final String personId;
final AiSuggestionKind kind;
final String title;
final String details;
final DateTime suggestedAt;
final DateTime? suggestedFor;
final DateTime? eventEndsAt;
final String? eventLocation;
final String? eventUrl;
final List<String> sourceUrls;
final double confidence;
final AiSuggestionStatus status;
final String sourceRunId;
final String? reason;
AiSuggestionDraft copyWith({
String? id,
String? personId,
AiSuggestionKind? kind,
String? title,
String? details,
DateTime? suggestedAt,
DateTime? suggestedFor,
DateTime? eventEndsAt,
String? eventLocation,
String? eventUrl,
List<String>? sourceUrls,
double? confidence,
AiSuggestionStatus? status,
String? sourceRunId,
String? reason,
}) {
return AiSuggestionDraft(
id: id ?? this.id,
personId: personId ?? this.personId,
kind: kind ?? this.kind,
title: title ?? this.title,
details: details ?? this.details,
suggestedAt: suggestedAt ?? this.suggestedAt,
suggestedFor: suggestedFor ?? this.suggestedFor,
eventEndsAt: eventEndsAt ?? this.eventEndsAt,
eventLocation: eventLocation ?? this.eventLocation,
eventUrl: eventUrl ?? this.eventUrl,
sourceUrls: sourceUrls ?? this.sourceUrls,
confidence: confidence ?? this.confidence,
status: status ?? this.status,
sourceRunId: sourceRunId ?? this.sourceRunId,
reason: reason ?? this.reason,
);
}
Map<String, dynamic> toJson() {
return <String, dynamic>{
'id': id,
'personId': personId,
'kind': kind.name,
'title': title,
'details': details,
'suggestedAt': suggestedAt.toUtc().toIso8601String(),
'suggestedFor': suggestedFor?.toUtc().toIso8601String(),
'eventEndsAt': eventEndsAt?.toUtc().toIso8601String(),
'eventLocation': eventLocation,
'eventUrl': eventUrl,
'sourceUrls': sourceUrls,
'confidence': confidence,
'status': status.name,
'sourceRunId': sourceRunId,
'reason': reason,
};
}
factory AiSuggestionDraft.fromJson(Map<String, dynamic> json) {
final String kindName =
json['kind'] as String? ?? AiSuggestionKind.checkIn.name;
final String statusName =
json['status'] as String? ?? AiSuggestionStatus.pending.name;
return AiSuggestionDraft(
id: json['id'] as String,
personId: json['personId'] as String,
kind: AiSuggestionKind.values.firstWhere(
(AiSuggestionKind value) => value.name == kindName,
orElse: () => AiSuggestionKind.checkIn,
),
title: json['title'] as String? ?? 'Suggestion',
details: json['details'] as String? ?? '',
suggestedAt: DateTime.parse(
json['suggestedAt'] as String? ??
DateTime.now().toUtc().toIso8601String(),
).toLocal(),
suggestedFor: json['suggestedFor'] == null
? null
: DateTime.parse(json['suggestedFor'] as String).toLocal(),
eventEndsAt: json['eventEndsAt'] == null
? null
: DateTime.parse(json['eventEndsAt'] as String).toLocal(),
eventLocation: json['eventLocation'] as String?,
eventUrl: json['eventUrl'] as String?,
sourceUrls: (json['sourceUrls'] as List<dynamic>? ?? <dynamic>[])
.map((dynamic value) => '$value')
.toList(growable: false),
confidence: (json['confidence'] as num?)?.toDouble() ?? 0,
status: AiSuggestionStatus.values.firstWhere(
(AiSuggestionStatus value) => value.name == statusName,
orElse: () => AiSuggestionStatus.pending,
),
sourceRunId: json['sourceRunId'] as String? ?? 'unknown-run',
reason: json['reason'] as String?,
);
}
}
@immutable
class LlmDigestRunState {
const LlmDigestRunState({
this.lastStartedAt,
this.lastCompletedAt,
this.lastFailure,
this.consecutiveFailures = 0,
this.running = false,
});
final DateTime? lastStartedAt;
final DateTime? lastCompletedAt;
final String? lastFailure;
final int consecutiveFailures;
final bool running;
LlmDigestRunState copyWith({
DateTime? lastStartedAt,
DateTime? lastCompletedAt,
String? lastFailure,
int? consecutiveFailures,
bool? running,
}) {
return LlmDigestRunState(
lastStartedAt: lastStartedAt ?? this.lastStartedAt,
lastCompletedAt: lastCompletedAt ?? this.lastCompletedAt,
lastFailure: lastFailure,
consecutiveFailures: consecutiveFailures ?? this.consecutiveFailures,
running: running ?? this.running,
);
}
Map<String, dynamic> toJson() {
return <String, dynamic>{
'lastStartedAt': lastStartedAt?.toUtc().toIso8601String(),
'lastCompletedAt': lastCompletedAt?.toUtc().toIso8601String(),
'lastFailure': lastFailure,
'consecutiveFailures': consecutiveFailures,
'running': running,
};
}
factory LlmDigestRunState.fromJson(Map<String, dynamic> json) {
return LlmDigestRunState(
lastStartedAt: json['lastStartedAt'] == null
? null
: DateTime.parse(json['lastStartedAt'] as String).toLocal(),
lastCompletedAt: json['lastCompletedAt'] == null
? null
: DateTime.parse(json['lastCompletedAt'] as String).toLocal(),
lastFailure: json['lastFailure'] as String?,
consecutiveFailures: (json['consecutiveFailures'] as num?)?.toInt() ?? 0,
running: json['running'] as bool? ?? false,
);
}
}
@immutable
class LlmDigestConfigState {
const LlmDigestConfigState({
this.enabled = false,
this.cadence = LlmDigestCadence.weekly,
this.preferredWeekday = DateTime.sunday,
this.preferredHour = 21,
this.requireWifi = true,
this.requireCharging = true,
this.enableWebSearch = true,
});
final bool enabled;
final LlmDigestCadence cadence;
final int preferredWeekday;
final int preferredHour;
final bool requireWifi;
final bool requireCharging;
final bool enableWebSearch;
LlmDigestConfigState copyWith({
bool? enabled,
LlmDigestCadence? cadence,
int? preferredWeekday,
int? preferredHour,
bool? requireWifi,
bool? requireCharging,
bool? enableWebSearch,
}) {
return LlmDigestConfigState(
enabled: enabled ?? this.enabled,
cadence: cadence ?? this.cadence,
preferredWeekday: preferredWeekday ?? this.preferredWeekday,
preferredHour: preferredHour ?? this.preferredHour,
requireWifi: requireWifi ?? this.requireWifi,
requireCharging: requireCharging ?? this.requireCharging,
enableWebSearch: enableWebSearch ?? this.enableWebSearch,
);
}
}