SPB Git

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%
3.9 KB · 108 lines swift
Raw Blame History
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