// // StatsView.swift // oAI // // Session statistics screen // import SwiftUI struct StatsView: View { let stats: SessionStats let model: ModelInfo? let provider: Settings.Provider @Environment(\.dismiss) var dismiss var body: some View { NavigationStack { List { Section("Session Info") { StatRow(label: "Provider", value: provider.displayName) StatRow(label: "Model", value: model?.name ?? "None selected") StatRow(label: "Messages", value: "\(stats.messageCount)") } Section("Token Usage") { StatRow(label: "Input Tokens", value: stats.totalInputTokens.formatted()) StatRow(label: "Output Tokens", value: stats.totalOutputTokens.formatted()) StatRow(label: "Total Tokens", value: stats.totalTokens.formatted()) if stats.totalTokens > 0 { HStack { Text("Token Distribution") .font(.caption) .foregroundColor(.secondary) Spacer() GeometryReader { geo in HStack(spacing: 0) { Rectangle() .fill(Color.blue) .frame(width: geo.size.width * CGFloat(stats.totalInputTokens) / CGFloat(stats.totalTokens)) Rectangle() .fill(Color.green) .frame(width: geo.size.width * CGFloat(stats.totalOutputTokens) / CGFloat(stats.totalTokens)) } } .frame(height: 20) .cornerRadius(4) } } } Section("Costs") { StatRow(label: "Total Cost", value: stats.totalCostDisplay) if stats.messageCount > 0 { StatRow(label: "Avg per Message", value: String(format: "$%.4f", stats.averageCostPerMessage)) } } if let model = model { Section("Model Details") { StatRow(label: "Context Length", value: model.contextLengthDisplay) StatRow(label: "Prompt Price", value: model.promptPriceDisplay + "/1M tokens") StatRow(label: "Completion Price", value: model.completionPriceDisplay + "/1M tokens") HStack { Text("Capabilities") .font(.caption) .foregroundColor(.secondary) Spacer() HStack(spacing: 8) { if model.capabilities.vision { CapabilityBadge(icon: "👁️", label: "Vision") } if model.capabilities.tools { CapabilityBadge(icon: "🔧", label: "Tools") } if model.capabilities.online { CapabilityBadge(icon: "🌐", label: "Online") } } } } } } #if os(iOS) .listStyle(.insetGrouped) #else .listStyle(.sidebar) #endif .navigationTitle("Statistics") .toolbar { ToolbarItem(placement: .confirmationAction) { Button("Done") { dismiss() } } } .frame(minWidth: 500, idealWidth: 550, minHeight: 450, idealHeight: 500) } } } struct StatRow: View { let label: String let value: String var body: some View { HStack { Text(label) .font(.body) Spacer() Text(value) .font(.body.monospacedDigit()) .foregroundColor(.secondary) } } } struct CapabilityBadge: View { let icon: String let label: String var body: some View { HStack(spacing: 2) { Text(icon) Text(label) } .font(.caption2) .padding(.horizontal, 6) .padding(.vertical, 3) .background(Color.blue.opacity(0.1)) .cornerRadius(4) } } #Preview { StatsView( stats: SessionStats( totalInputTokens: 1250, totalOutputTokens: 3420, totalCost: 0.0152, messageCount: 12 ), model: ModelInfo.mockModels.first, provider: .openrouter ) }