You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

152 lines
5.7 KiB

//
// PromptView.swift
// Diffusion-macOS
//
// Created by Cyril Zakka on 1/12/23.
// See LICENSE at https://github.com/huggingface/swift-coreml-diffusers/LICENSE
//
import Combine
import SwiftUI
import CompactSlider
enum PipelineState {
case downloading(Double)
case uncompressing
case loading
case ready
case failed(Error)
}
struct ControlsView: View {
@EnvironmentObject var generation: GenerationContext
static let models = ModelInfo.MODELS
static let modelNames = models.map { $0.modelVersion }
@State private var model = Settings.shared.currentModel.modelVersion
@State private var disclosedPrompt = true
// TODO: refactor download with similar code in Loading.swift (iOS)
@State private var stateSubscriber: Cancellable?
@State private var pipelineState: PipelineState = .downloading(0)
func modelDidChange(model: ModelInfo) {
print("Loading model \(model)")
Settings.shared.currentModel = model
pipelineState = .downloading(0)
Task.init {
let loader = PipelineLoader(model: model)
stateSubscriber = loader.statePublisher.sink { state in
DispatchQueue.main.async {
switch state {
case .downloading(let progress):
pipelineState = .downloading(progress)
case .uncompressing:
pipelineState = .uncompressing
case .readyOnDisk:
pipelineState = .loading
default:
break
}
}
}
do {
generation.pipeline = try await loader.prepare()
pipelineState = .ready
} catch {
print("Could not load model, error: \(error)")
pipelineState = .failed(error)
}
}
}
var body: some View {
VStack(alignment: .leading) {
Label("Adjustments", systemImage: "gearshape.2")
.font(.headline)
.fontWeight(.bold)
Divider()
ScrollView {
Group {
DisclosureGroup {
Picker("", selection: $model) {
ForEach(Self.modelNames, id: \.self) {
Text($0)
}
}
.onChange(of: model) { theModel in
guard let model = ModelInfo.from(modelVersion: theModel) else { return }
modelDidChange(model: model)
}
} label: {
Label("Model", systemImage: "cpu").foregroundColor(.secondary)
}
Divider()
DisclosureGroup(isExpanded: $disclosedPrompt) {
Group {
TextField("Positive prompt", text: $generation.positivePrompt,
axis: .vertical).lineLimit(5)
.textFieldStyle(.squareBorder)
.listRowInsets(EdgeInsets(top: 0, leading: -20, bottom: 0, trailing: 20))
TextField("Negative prompt", text: $generation.negativePrompt,
axis: .vertical).lineLimit(5)
.textFieldStyle(.squareBorder)
}.padding(.leading, 10)
} label: {
Label("Prompts", systemImage: "text.quote").foregroundColor(.secondary)
}
Divider()
DisclosureGroup {
CompactSlider(value: $generation.steps, in: 0...150, step: 5) {
Text("Steps")
Spacer()
Text("\(Int(generation.steps))")
}.padding(.leading, 10)
} label: {
Label("Step count", systemImage: "square.3.layers.3d.down.left").foregroundColor(.secondary)
}
Divider()
// DisclosureGroup() {
// CompactSlider(value: $generation.numImages, in: 0...10, step: 1) {
// Text("Number of Images")
// Spacer()
// Text("\(Int(generation.numImages))")
// }.padding(.leading, 10)
// } label: {
// Label("Number of images", systemImage: "photo.stack").foregroundColor(.secondary)
// }
// Divider()
DisclosureGroup() {
let sliderLabel = generation.seed < 0 ? "Random Seed" : "Seed"
CompactSlider(value: $generation.seed, in: -1...1000, step: 1) {
Text(sliderLabel)
Spacer()
Text("\(Int(generation.seed))")
}.padding(.leading, 10)
} label: {
Label("Seed", systemImage: "leaf").foregroundColor(.secondary)
}
}
}
StatusView(pipelineState: $pipelineState)
}
.padding()
.onAppear {
print(PipelineLoader.models)
modelDidChange(model: ModelInfo.from(modelVersion: model) ?? ModelInfo.v2Base)
}
}
}