spb/zyquo-mlx Public MIT
The local MLX foundry for your Mac — run, fine-tune, quantize, and ship models. Nothing leaves your machine.
Swift 93.4%
Python 3.8%
Makefile 2.2%
Shell 0.5%
1//2// SettingsView.swift3// Zyquo MLX4//5// Author: Simon-Pierre Boucher6// Mail: contact@spboucher.ai7//89import SwiftUI1011/// Settings window (charter §4.2): native tabs, 760×560.12/// Functional depth (HF token vault, compute limits) lands in Phase 6.13struct SettingsView: View {14 var body: some View {15 TabView {16 GeneralSettings()17 .tabItem { Label("General", systemImage: "gearshape") }18 ComputeSettings()19 .tabItem { Label("Compute", systemImage: "cpu") }20 PythonSettings()21 .tabItem { Label("Python", systemImage: "terminal") }22 StorageSettings()23 .tabItem { Label("Storage", systemImage: "internaldrive") }24 HuggingFaceSettings()25 .tabItem { Label("Hugging Face", systemImage: "key") }26 AppearanceSettings()27 .tabItem { Label("Appearance", systemImage: "paintpalette") }28 }29 .frame(width: 760, height: 560)30 }31}3233private struct GeneralSettings: View {34 var body: some View {35 Form {36 LabeledContent("Models") {37 PathLabel(url: PersistenceService.modelsDirectory)38 }39 LabeledContent("Datasets") {40 PathLabel(url: PersistenceService.datasetsDirectory)41 }42 LabeledContent("Training runs") {43 PathLabel(url: PersistenceService.runsDirectory)44 }45 }46 .formStyle(.grouped)47 }48}4950private struct ComputeSettings: View {51 var body: some View {52 Form {53 Section("GPU") {54 LabeledContent("Unified memory") {55 Text(ByteCountFormatter.string(56 fromByteCount: MemoryAdvisor.physicalMemory, countStyle: .memory))57 }58 LabeledContent("Recommended working set") {59 Text(ByteCountFormatter.string(60 fromByteCount: MemoryAdvisor.recommendedWorkingSet, countStyle: .memory))61 }62 }63 }64 .formStyle(.grouped)65 }66}6768private struct PythonSettings: View {69 @State private var status = "Checking…"7071 var body: some View {72 Form {73 Section("Environment") {74 LabeledContent("Status") { Text(status) }75 LabeledContent("Location") {76 PathLabel(url: PersistenceService.pythonDirectory)77 }78 LabeledContent("Pinned packages") {79 Text(PythonEnvironment.corePins.joined(separator: ", "))80 .font(ZyquoTheme.monoSmallFont)81 }82 }83 }84 .formStyle(.grouped)85 .task {86 status = await PythonEnvironment.shared.isProvisioned87 ? "Ready (Python \(PythonEnvironment.pythonVersion))"88 : "Not provisioned — installs automatically on first use"89 }90 }91}9293private struct StorageSettings: View {94 @State private var usage: [(String, Int64)] = []9596 var body: some View {97 Form {98 Section("Disk usage") {99 ForEach(usage, id: \.0) { name, bytes in100 LabeledContent(name) {101 Text(ByteCountFormatter.string(fromByteCount: bytes, countStyle: .file))102 }103 }104 }105 }106 .formStyle(.grouped)107 .task {108 usage = [109 ("Models", directorySize(PersistenceService.modelsDirectory)),110 ("Datasets", directorySize(PersistenceService.datasetsDirectory)),111 ("Runs", directorySize(PersistenceService.runsDirectory)),112 ("Python", directorySize(PersistenceService.pythonDirectory)),113 ]114 }115 }116117 private func directorySize(_ url: URL) -> Int64 {118 let fm = FileManager.default119 guard let files = try? fm.subpathsOfDirectory(atPath: url.path) else { return 0 }120 return files.reduce(Int64(0)) { total, path in121 let size = (try? url.appendingPathComponent(path)122 .resourceValues(forKeys: [.fileSizeKey]))?.fileSize ?? 0123 return total + Int64(size)124 }125 }126}127128private struct HuggingFaceSettings: View {129 @State private var token = HFTokenStore.token ?? ""130 @State private var saved = false131132 var body: some View {133 Form {134 Section("Access token") {135 SecureField("hf_…", text: $token)136 Text("Stored in your login Keychain — used for gated models and higher rate limits.")137 .font(ZyquoTheme.captionFont)138 .foregroundStyle(ZyquoTheme.textSecondary)139 HStack {140 Button("Save") {141 HFTokenStore.save(token.trimmingCharacters(in: .whitespaces))142 saved = true143 }144 if saved {145 Text("Saved ✓")146 .font(ZyquoTheme.captionFont)147 .foregroundStyle(ZyquoTheme.success)148 }149 }150 }151 }152 .formStyle(.grouped)153 }154}155156private struct AppearanceSettings: View {157 @AppStorage("appearance") private var appearance = "system"158159 var body: some View {160 Form {161 Picker("Appearance", selection: $appearance) {162 Text("System").tag("system")163 Text("Light").tag("light")164 Text("Dark").tag("dark")165 }166 .pickerStyle(.inline)167 }168 .formStyle(.grouped)169 }170}171172private struct PathLabel: View {173 let url: URL174175 var body: some View {176 HStack {177 Text(url.path.replacingOccurrences(of: NSHomeDirectory(), with: "~"))178 .font(ZyquoTheme.monoSmallFont)179 .foregroundStyle(ZyquoTheme.textSecondary)180 .lineLimit(1)181 .truncationMode(.middle)182 Button {183 NSWorkspace.shared.activateFileViewerSelecting([url])184 } label: {185 Image(systemName: "arrow.right.circle")186 }187 .buttonStyle(.plain)188 .help("Reveal in Finder")189 }190 }191}192