// // UsageStats.swift // oAI // // All-time usage statistics (aggregated from the messages table) // // SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0 // Copyright (C) 2026 Rune Olsen // // This file is part of oAI. // // oAI is licensed under the PolyForm Noncommercial License 1.0.0. // You may use, study, modify, and share it for any noncommercial // purpose. Commercial use — including selling oAI or any part of // it, standalone or bundled into another product or service — // requires a separate commercial license from the copyright holder. // // See the LICENSE file or // for // the full license text. For commercial licensing, contact Rune // Olsen via . import Foundation struct UsageStats: Sendable { var totalMessages: Int = 0 var totalTokens: Int = 0 var totalCost: Double = 0.0 var hasCostData: Bool = false var firstMessageDate: Date? var lastMessageDate: Date? var totalTokensDisplay: String { if totalTokens >= 1_000_000 { return String(format: "%.1fM", Double(totalTokens) / 1_000_000) } else if totalTokens >= 1000 { return String(format: "%.1fK", Double(totalTokens) / 1000) } else { return "\(totalTokens)" } } var totalCostDisplay: String { hasCostData ? String(format: "$%.4f", totalCost) : "N/A" } } struct ModelUsageStat: Identifiable, Sendable { var id: String { modelId } let modelId: String var messageCount: Int var totalTokens: Int var totalCost: Double var hasCostData: Bool var lastUsed: Date var totalTokensDisplay: String { if totalTokens >= 1_000_000 { return String(format: "%.1fM", Double(totalTokens) / 1_000_000) } else if totalTokens >= 1000 { return String(format: "%.1fK", Double(totalTokens) / 1000) } else { return "\(totalTokens)" } } var totalCostDisplay: String { hasCostData ? String(format: "$%.4f", totalCost) : "N/A" } } struct ConversationUsageStat: Identifiable, Sendable { let conversationId: UUID var id: UUID { conversationId } var name: String var messageCount: Int var totalTokens: Int var totalCost: Double var hasCostData: Bool var totalTokensDisplay: String { if totalTokens >= 1_000_000 { return String(format: "%.1fM", Double(totalTokens) / 1_000_000) } else if totalTokens >= 1000 { return String(format: "%.1fK", Double(totalTokens) / 1000) } else { return "\(totalTokens)" } } var totalCostDisplay: String { hasCostData ? String(format: "$%.4f", totalCost) : "N/A" } }