Files
jundot--omlx/apps/omlx-mac/Sources/AppView/ViewModels/ModelsScreenVM.swift
T
wehub-resource-sync e9a2f726c9
CI / test (3.11) (push) Has been cancelled
CI / test (3.12) (push) Has been cancelled
CI / test (3.13) (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:29:51 +08:00

108 lines
3.2 KiB
Swift

import SwiftUI
@MainActor
@Observable
final class ModelsScreenVM {
private(set) var allModels: [ModelDTO] = []
var lastError: String?
/// Library row the user just clicked "trash" on; non-nil drives the
/// confirmation dialog. Cleared on cancel or after delete completes.
var pendingRemoveID: String?
/// While a delete is in flight, the row shows a spinner instead of the
/// trash glyph and the whole row's button-stack is disabled to prevent
/// double-tap deletes against a model the server is still unloading.
private(set) var deletingID: String?
@ObservationIgnored
private weak var client: OMLXClient?
@ObservationIgnored
private var pollTask: Task<Void, Never>?
var activeModels: [ModelDTO] {
allModels.filter { $0.loaded || $0.isLoading }
}
var libraryModels: [ModelDTO] { allModels }
func start(client: OMLXClient) async {
self.client = client
pollTask?.cancel()
pollTask = Task { [weak self] in
while !Task.isCancelled {
guard let self else { return }
await self.refresh()
try? await Task.sleep(for: .seconds(2))
}
}
}
func stop() {
pollTask?.cancel()
pollTask = nil
}
func load(id: String, client: OMLXClient) {
Task { [weak self] in
do {
_ = try await client.loadModel(id: id)
await self?.refresh()
} catch {
guard let self else { return }
self.lastError = error.omlxDescription
}
}
}
func unload(id: String, client: OMLXClient) {
Task { [weak self] in
do {
_ = try await client.unloadModel(id: id)
await self?.refresh()
} catch {
guard let self else { return }
self.lastError = error.omlxDescription
}
}
}
func setFavorite(id: String, favorite: Bool, client: OMLXClient) {
Task { [weak self] in
do {
var patch = ModelSettingsPatch()
patch.isFavorite = favorite
_ = try await client.updateModelSettings(id: id, patch: patch)
await self?.refresh()
} catch {
guard let self else { return }
self.lastError = error.omlxDescription
}
}
}
func remove(id: String, client: OMLXClient) {
pendingRemoveID = nil
deletingID = id
Task { [weak self] in
defer { Task { @MainActor [weak self] in self?.deletingID = nil } }
do {
_ = try await client.deleteHFModel(modelName: id)
await self?.refresh()
self?.lastError = nil
} catch {
guard let self else { return }
self.lastError = error.omlxDescription
}
}
}
private func refresh() async {
guard let client else { return }
do {
self.allModels = sortModelsByName(try await client.listModels().models)
self.lastError = nil
} catch {
self.lastError = error.omlxDescription
}
}
}