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// DatasetsView.swift3// Zyquo MLX4//5// Author: Simon-Pierre Boucher6// Mail: contact@spboucher.ai7//89import SwiftUI10import UniformTypeIdentifiers1112/// Datasets section: import, validate, preview (charter §4.2).13struct DatasetsView: View {14 @Bindable var model: AppModel15 @State private var isImporting = false16 @State private var importError: String?1718 var body: some View {19 Group {20 if model.datasets.isEmpty {21 EmptyStateView(22 icon: "tablecells",23 title: "No Datasets Yet",24 message: "Import a JSONL file — chat conversations, prompt/completion pairs, or raw text. Zyquo validates every row, reports fixable issues, and splits it for training.",25 actionLabel: "Import JSONL…",26 action: { isImporting = true })27 } else {28 ScrollView {29 LazyVStack(spacing: ZyquoTheme.spacing8) {30 ForEach(model.datasets) { dataset in31 DatasetRow(dataset: dataset)32 }33 }34 .padding(ZyquoTheme.spacing20)35 }36 .toolbar {37 ToolbarItem {38 Button("Import JSONL…") { isImporting = true }39 }40 }41 }42 }43 .fileImporter(44 isPresented: $isImporting,45 allowedContentTypes: [UTType(filenameExtension: "jsonl") ?? .json]46 ) { result in47 if case .success(let url) = result {48 Task {49 do {50 let gotAccess = url.startAccessingSecurityScopedResource()51 defer { if gotAccess { url.stopAccessingSecurityScopedResource() } }52 _ = try await DatasetService.shared.importJSONL(53 from: url,54 name: url.deletingPathExtension().lastPathComponent)55 await model.refresh()56 } catch {57 importError = error.localizedDescription58 }59 }60 }61 }62 .alert("Import Failed", isPresented: .constant(importError != nil)) {63 Button("OK") { importError = nil }64 } message: {65 Text(importError ?? "")66 }67 }68}6970struct DatasetRow: View {71 let dataset: Dataset7273 var body: some View {74 HStack(spacing: ZyquoTheme.spacing12) {75 Image(systemName: "tablecells")76 .font(.system(size: 18, weight: .light))77 .foregroundStyle(ZyquoTheme.slate)78 .frame(width: 32, height: 32)79 .background(ZyquoTheme.surfaceSecondary)80 .clipShape(RoundedRectangle(cornerRadius: ZyquoTheme.radiusSmall))8182 VStack(alignment: .leading, spacing: ZyquoTheme.spacing2) {83 Text(dataset.name)84 .font(ZyquoTheme.bodyFont.weight(.medium))85 .foregroundStyle(ZyquoTheme.textPrimary)86 HStack(spacing: ZyquoTheme.spacing8) {87 Text(dataset.format.displayName)88 Text("train \(dataset.trainCount) · valid \(dataset.validCount)"89 + (dataset.testCount > 0 ? " · test \(dataset.testCount)" : ""))90 if let tokens = dataset.totalTokens {91 Text("≈\(tokens.formatted()) tokens")92 }93 }94 .font(ZyquoTheme.captionFont)95 .foregroundStyle(ZyquoTheme.textSecondary)96 }9798 Spacer()99100 Text(dataset.importedAt.formatted(date: .abbreviated, time: .omitted))101 .font(ZyquoTheme.captionFont)102 .foregroundStyle(ZyquoTheme.textTertiary)103 }104 .padding(ZyquoTheme.spacing12)105 .zyquoCard()106 }107}108