import Foundation struct VoiceOption: Codable, Equatable { let id: String let name: String let tag: String? var locale: String? = nil var gender: String? = nil var details: String { [locale, gender, tag].compactMap { $0 }.joined(separator: " ยท ") } var displayName: String { tag.map { "\(name) (\($0))" } ?? name } } struct VoiceCatalogResponse: Decodable { let defaultVoice: String let voices: [VoiceOption] let catalogAvailable: Bool let message: String? enum CodingKeys: String, CodingKey { case voices, message case defaultVoice = "default_voice" case catalogAvailable = "catalog_available" } } enum Voices { static let all: [VoiceOption] = [ VoiceOption(id: "en-US-Ava:DragonHDOmniLatestNeural", name: "Ava", tag: "Dragon HD Omni"), VoiceOption(id: "en-US-Jenny:DragonHDOmniLatestNeural", name: "Jenny", tag: "Dragon HD Omni"), VoiceOption(id: "en-US-Guy:DragonHDOmniLatestNeural", name: "Guy", tag: "Dragon HD Omni"), VoiceOption(id: "en-US-Andrew:DragonHDOmniLatestNeural", name: "Andrew", tag: "Dragon HD Omni"), VoiceOption(id: "en-US-Aria:DragonHDOmniLatestNeural", name: "Aria", tag: "Dragon HD Omni"), VoiceOption(id: "en-US-Emma:DragonHDOmniLatestNeural", name: "Emma", tag: "Dragon HD Omni"), VoiceOption(id: "en-US-Eric:DragonHDOmniLatestNeural", name: "Eric", tag: "Dragon HD Omni"), VoiceOption(id: "en-US-Brian:DragonHDOmniLatestNeural", name: "Brian", tag: "Dragon HD Omni"), VoiceOption(id: "en-US-Ashley:DragonHDOmniLatestNeural", name: "Ashley", tag: "Dragon HD Omni"), VoiceOption(id: "en-US-Richard:DragonHDOmniLatestNeural", name: "Richard", tag: "Dragon HD Omni"), VoiceOption(id: "en-US-Tina:DragonHDOmniLatestNeural", name: "Tina", tag: "Dragon HD Omni"), VoiceOption(id: "en-US-Steffan:DragonHDOmniLatestNeural", name: "Steffan", tag: "Dragon HD Omni"), ] static var defaultID: String { all[0].id } private static let legacyPersonaIDs: [String: String] = Dictionary(uniqueKeysWithValues: all.compactMap { option in guard let prefix = option.id.split(separator: ":").first else { return nil } return ("\(prefix)Neural", option.id) }) static func restoredID(_ saved: String?) -> String { guard let saved, saved.range(of: "^[A-Za-z0-9:_-]{1,120}$", options: .regularExpression) != nil else { return defaultID } if let migrated = legacyPersonaIDs[saved] { return migrated } return saved.replacingOccurrences(of: ":DragonHDLatestNeural", with: ":DragonHDOmniLatestNeural") } static func display(for id: String) -> String? { all.first { $0.id == id }?.displayName } }