f512d94c74
git-subtree-dir: clients/ds-app git-subtree-mainline:a24e3e6f22git-subtree-split:5206cf3b0c
89 lines
2.9 KiB
Swift
89 lines
2.9 KiB
Swift
import Foundation
|
|
|
|
public struct ArticleRef: Codable, Sendable, Identifiable {
|
|
public let id: Int
|
|
public let title: String?
|
|
}
|
|
|
|
public struct TopicResponse: Codable, Sendable, Identifiable {
|
|
public let topicRank: Int
|
|
public let topicLabel: String
|
|
public let summary: String
|
|
public let articleIds: [Int]?
|
|
public let articles: [ArticleRef]
|
|
public let articleCount: Int?
|
|
public let importanceScore: Double?
|
|
public let rawWeightSum: Double?
|
|
public let llmFallbackUsed: Bool?
|
|
|
|
public var id: Int { topicRank }
|
|
|
|
enum CodingKeys: String, CodingKey {
|
|
case summary, articles
|
|
case topicRank = "topic_rank"
|
|
case topicLabel = "topic_label"
|
|
case articleIds = "article_ids"
|
|
case articleCount = "article_count"
|
|
case importanceScore = "importance_score"
|
|
case rawWeightSum = "raw_weight_sum"
|
|
case llmFallbackUsed = "llm_fallback_used"
|
|
}
|
|
}
|
|
|
|
public struct CountryGroup: Codable, Sendable, Identifiable {
|
|
public let country: String
|
|
public let topics: [TopicResponse]
|
|
public var id: String { country }
|
|
}
|
|
|
|
public struct DigestResponse: Codable, Sendable {
|
|
public let digestDateRaw: String?
|
|
public let windowStartRaw: String?
|
|
public let windowEndRaw: String?
|
|
public let decayLambda: Double?
|
|
public let totalArticles: Int?
|
|
public let totalCountries: Int?
|
|
public let totalTopics: Int?
|
|
public let generationMs: Int?
|
|
public let llmCalls: Int?
|
|
public let llmFailures: Int?
|
|
public let status: String?
|
|
public let countries: [CountryGroup]
|
|
|
|
/// date-only (B-1 r2): DISPLAY the raw string (no Date conversion → no KST off-by-one).
|
|
public var digestDateDisplay: String { digestDateRaw ?? "" }
|
|
/// Date conversions are for sort/window math only (UTC-fixed via DSDate).
|
|
public var windowStart: Date? { DSDate.parse(windowStartRaw) }
|
|
public var windowEnd: Date? { DSDate.parse(windowEndRaw) }
|
|
|
|
enum CodingKeys: String, CodingKey {
|
|
case status, countries
|
|
case digestDateRaw = "digest_date"
|
|
case windowStartRaw = "window_start"
|
|
case windowEndRaw = "window_end"
|
|
case decayLambda = "decay_lambda"
|
|
case totalArticles = "total_articles"
|
|
case totalCountries = "total_countries"
|
|
case totalTopics = "total_topics"
|
|
case generationMs = "generation_ms"
|
|
case llmCalls = "llm_calls"
|
|
case llmFailures = "llm_failures"
|
|
}
|
|
}
|
|
|
|
public struct DigestDateSummary: Codable, Sendable {
|
|
public let digestDateRaw: String?
|
|
public let totalTopics: Int?
|
|
public let totalCountries: Int?
|
|
public let totalArticles: Int?
|
|
public let status: String?
|
|
|
|
enum CodingKeys: String, CodingKey {
|
|
case status
|
|
case digestDateRaw = "digest_date"
|
|
case totalTopics = "total_topics"
|
|
case totalCountries = "total_countries"
|
|
case totalArticles = "total_articles"
|
|
}
|
|
}
|