import Foundation /// A curated transcription model (mirrors `fcpxml/models.json`). struct ModelInfo: Identifiable { let displayName: String let internalName: String let language: String let storage: String let accuracy: Int let speed: Int var isDownloaded: Bool var isSelected: Bool var isRecommended: Bool var id: String { internalName } } /// Full catalog snapshot returned by the `catalog` command. struct Catalog { var models: [ModelInfo] var selected: String var language: String var modelsDir: String var installedCount: Int var diarization: Bool var diarizationMessage: String var hfTokenSet: Bool var numSpeakers: String init(json: [String: Any]) { let recommended = Set((json["recommended"] as? [String] ?? [])) let installed = Set((json["installed"] as? [String] ?? [])) let selected = json["selected"] as? String ?? "" let rawModels = json["models"] as? [[String: Any]] ?? [] var parsed: [ModelInfo] = [] for m in rawModels { let name = m["internal_name"] as? String ?? "" parsed.append(ModelInfo( displayName: m["display_name"] as? String ?? name, internalName: name, language: m["language"] as? String ?? "", storage: m["storage"] as? String ?? "", accuracy: m["accuracy"] as? Int ?? 0, speed: m["speed"] as? Int ?? 0, isDownloaded: installed.contains(name), isSelected: name == selected, isRecommended: recommended.contains(name) )) } self.models = parsed self.selected = selected self.language = json["language"] as? String ?? "auto" self.modelsDir = json["models_dir"] as? String ?? "" self.installedCount = json["installed_count"] as? Int ?? 0 self.diarization = json["diarization"] as? Bool ?? false self.diarizationMessage = json["diarization_message"] as? String ?? "" self.hfTokenSet = json["hf_token_set"] as? Bool ?? false self.numSpeakers = json["num_speakers"] as? String ?? "" } /// Models sorted: recommended first, then by download state, then name. var orderedModels: [ModelInfo] { models.sorted { if $0.isDownloaded != $1.isDownloaded { return $0.isDownloaded } if $0.isRecommended != $1.isRecommended { return $0.isRecommended } return $0.displayName < $1.displayName } } } /// A single transcript result from the `transcribe` command. struct TranscriptResult { let media: String let language: String let words: Int let duration: Double let preview: String let saved: String let speakers: [String] init(json: [String: Any]) { media = json["media"] as? String ?? "" language = json["language"] as? String ?? "?" words = json["words"] as? Int ?? 0 duration = json["duration"] as? Double ?? 0 preview = json["preview"] as? String ?? "" saved = json["saved"] as? String ?? "" speakers = json["speakers"] as? [String] ?? [] } } struct ZoomClip: Identifiable { let id: String let index: Int let name: String let start: Double let duration: Double let media: String let preview: String let hasTranscript: Bool init(json: [String: Any]) { id = json["id"] as? String ?? "" index = json["index"] as? Int ?? 0 name = json["name"] as? String ?? "Clipe" start = json["start"] as? Double ?? 0 duration = json["duration"] as? Double ?? 0 media = json["media"] as? String ?? "" preview = json["preview"] as? String ?? "" hasTranscript = json["has_transcript"] as? Bool ?? false } var label: String { let time = String(format: "%02d:%02d", Int(start) / 60, Int(start) % 60) return "Clipe \(index + 1) · \(name) · \(time)" } } struct ZoomSegment: Identifiable { let id: Int let start: Double let end: Double let text: String init(json: [String: Any]) { id = json["id"] as? Int ?? 0 start = json["start"] as? Double ?? 0 end = json["end"] as? Double ?? 0 text = json["text"] as? String ?? "" } var label: String { String(format: "%06.2f–%06.2f %@", start, end, text) } }