81 lines
2.3 KiB
Dart
81 lines
2.3 KiB
Dart
/// An AI generated digest of the day's news, grouped into topics.
|
|||
|
|
class DailyBriefing {
|
||
|
|
const DailyBriefing({
|
||
|
|
required this.createdAt,
|
||
|
|
required this.intro,
|
||
|
|
required this.topics,
|
||
|
|
required this.generatedBy,
|
||
|
|
});
|
||
|
|
|
||
|
|
final DateTime createdAt;
|
||
|
|
final String intro;
|
||
|
|
final List<BriefingTopic> topics;
|
||
|
|
|
||
|
|
/// Human readable name of the summarizer, e.g. "Claude (claude-opus-5-5)".
|
||
|
|
final String generatedBy;
|
||
|
|
|
||
|
|
Map<String, dynamic> toJson() => {
|
||
|
|
'createdAt': createdAt.toIso8601String(),
|
||
|
|
'intro': intro,
|
||
|
|
'generatedBy': generatedBy,
|
||
|
|
'topics': topics.map((t) => t.toJson()).toList(),
|
||
|
|
};
|
||
|
|
|
||
|
|
factory DailyBriefing.fromJson(Map<String, dynamic> json) => DailyBriefing(
|
||
|
|
createdAt: DateTime.parse(json['createdAt'] as String),
|
||
|
|
intro: json['intro'] as String? ?? '',
|
||
|
|
generatedBy: json['generatedBy'] as String? ?? '',
|
||
|
|
topics: (json['topics'] as List? ?? [])
|
||
|
|
.map((t) => BriefingTopic.fromJson(t as Map<String, dynamic>))
|
||
|
|
.toList(),
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
class BriefingTopic {
|
||
|
|
const BriefingTopic({
|
||
|
|
required this.title,
|
||
|
|
required this.summary,
|
||
|
|
required this.sources,
|
||
|
|
});
|
||
|
|
|
||
|
|
final String title;
|
||
|
|
final String summary;
|
||
|
|
final List<ArticleRef> sources;
|
||
|
|
|
||
|
|
Map<String, dynamic> toJson() => {
|
||
|
|
'title': title,
|
||
|
|
'summary': summary,
|
||
|
|
'sources': sources.map((s) => s.toJson()).toList(),
|
||
|
|
};
|
||
|
|
|
||
|
|
factory BriefingTopic.fromJson(Map<String, dynamic> json) => BriefingTopic(
|
||
|
|
title: json['title'] as String? ?? '',
|
||
|
|
summary: json['summary'] as String? ?? '',
|
||
|
|
sources: (json['sources'] as List? ?? [])
|
||
|
|
.map((s) => ArticleRef.fromJson(s as Map<String, dynamic>))
|
||
|
|
.toList(),
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
/// A lightweight pointer to an article, stored with the briefing so links
|
||
|
|
/// still work after the feed has been refreshed.
|
||
|
|
class ArticleRef {
|
||
|
|
const ArticleRef({
|
||
|
|
required this.title,
|
||
|
|
required this.url,
|
||
|
|
required this.sourceName,
|
||
|
|
});
|
||
|
|
|
||
|
|
final String title;
|
||
|
|
final String url;
|
||
|
|
final String sourceName;
|
||
|
|
|
||
|
|
Map<String, dynamic> toJson() =>
|
||
|
|
{'title': title, 'url': url, 'sourceName': sourceName};
|
||
|
|
|
||
|
|
factory ArticleRef.fromJson(Map<String, dynamic> json) => ArticleRef(
|
||
|
|
title: json['title'] as String? ?? '',
|
||
|
|
url: json['url'] as String? ?? '',
|
||
|
|
sourceName: json['sourceName'] as String? ?? '',
|
||
|
|
);
|
||
|
|
}
|