diff --git a/Diffusion-macOS/ControlsView.swift b/Diffusion-macOS/ControlsView.swift index dacd547..63a6ef6 100644 --- a/Diffusion-macOS/ControlsView.swift +++ b/Diffusion-macOS/ControlsView.swift @@ -108,6 +108,15 @@ struct ControlsView: View { return } + if !model.supportsNeuralEngine && generation.computeUnits == .cpuAndNeuralEngine { + // Reset compute units to GPU if Neural Engine is not supported + Settings.shared.userSelectedComputeUnits = .cpuAndGPU + resetComputeUnitsState() + print("Neural Engine not supported for model \(model), switching to GPU") + } else { + resetComputeUnitsState() + } + Settings.shared.currentModel = model pipelineLoader?.cancel() @@ -155,9 +164,15 @@ struct ControlsView: View { VStack { Spacer() PromptTextField(text: $generation.positivePrompt, isPositivePrompt: true, model: $model) + .onChange(of: generation.positivePrompt) { prompt in + Settings.shared.prompt = prompt + } .padding(.top, 5) Spacer() PromptTextField(text: $generation.negativePrompt, isPositivePrompt: false, model: $model) + .onChange(of: generation.negativePrompt) { negativePrompt in + Settings.shared.negativePrompt = negativePrompt + } .padding(.bottom, 5) Spacer() } @@ -242,7 +257,11 @@ struct ControlsView: View { Text("Guidance Scale") Spacer() Text(guidanceScaleValue) - }.padding(.leading, 10) + } + .onChange(of: generation.guidanceScale) { guidanceScale in + Settings.shared.guidanceScale = guidanceScale + } + .padding(.leading, 10) } label: { HStack { Label("Guidance Scale", systemImage: "scalemass").foregroundColor(.secondary) @@ -269,7 +288,11 @@ struct ControlsView: View { Text("Steps") Spacer() Text("\(Int(generation.steps))") - }.padding(.leading, 10) + } + .onChange(of: generation.steps) { steps in + Settings.shared.stepCount = steps + } + .padding(.leading, 10) } label: { HStack { Label("Step count", systemImage: "square.3.layers.3d.down.left").foregroundColor(.secondary) @@ -295,7 +318,11 @@ struct ControlsView: View { Text("Previews") Spacer() Text("\(Int(generation.previews))") - }.padding(.leading, 10) + } + .onChange(of: generation.previews) { previews in + Settings.shared.previewCount = previews + } + .padding(.leading, 10) } label: { HStack { Label("Preview count", systemImage: "eye.square").foregroundColor(.secondary) @@ -334,7 +361,7 @@ struct ControlsView: View { seedHelp($showSeedHelp) } } else { - Text("\(Int(generation.seed))") + Text(generation.seed.formatted(.number.grouping(.never))) } } .foregroundColor(.secondary) @@ -342,17 +369,24 @@ struct ControlsView: View { if Capabilities.hasANE { Divider() + let isNeuralEngineDisabled = !(ModelInfo.from(modelVersion: model)?.supportsNeuralEngine ?? true) DisclosureGroup(isExpanded: $disclosedAdvanced) { HStack { Picker(selection: $generation.computeUnits, label: Text("Use")) { Text("GPU").tag(ComputeUnits.cpuAndGPU) - Text("Neural Engine").tag(ComputeUnits.cpuAndNeuralEngine) + Text("Neural Engine\(isNeuralEngineDisabled ? " (unavailable)" : "")") + .foregroundColor(isNeuralEngineDisabled ? .secondary : .primary) + .tag(ComputeUnits.cpuAndNeuralEngine) Text("GPU and Neural Engine").tag(ComputeUnits.all) }.pickerStyle(.radioGroup).padding(.leading) Spacer() } .onChange(of: generation.computeUnits) { units in guard let currentModel = ModelInfo.from(modelVersion: model) else { return } + if isNeuralEngineDisabled && units == .cpuAndNeuralEngine { + resetComputeUnitsState() + return + } let variantDownloaded = isModelDownloaded(currentModel, computeUnits: units) if variantDownloaded { updateComputeUnitsState() @@ -430,8 +464,10 @@ struct ControlsView: View { set: { newValue in if let seed = UInt32(newValue) { generation.seed = seed + Settings.shared.seed = seed } else { generation.seed = 0 + Settings.shared.seed = 0 } } ) @@ -442,8 +478,10 @@ struct ControlsView: View { .onChange(of: seedBinding.wrappedValue, perform: { newValue in if let seed = UInt32(newValue) { generation.seed = seed + Settings.shared.seed = seed } else { generation.seed = 0 + Settings.shared.seed = 0 } }) .onReceive(Just(seedBinding.wrappedValue)) { newValue in diff --git a/Diffusion.xcodeproj/project.pbxproj b/Diffusion.xcodeproj/project.pbxproj index 27e5d97..dccf3de 100644 --- a/Diffusion.xcodeproj/project.pbxproj +++ b/Diffusion.xcodeproj/project.pbxproj @@ -7,6 +7,8 @@ objects = { /* Begin PBXBuildFile section */ + 16AFDD4F2C1B7D6200536A62 /* StableDiffusion in Frameworks */ = {isa = PBXBuildFile; productRef = 16AFDD4E2C1B7D6200536A62 /* StableDiffusion */; }; + 16AFDD512C1B7D6700536A62 /* StableDiffusion in Frameworks */ = {isa = PBXBuildFile; productRef = 16AFDD502C1B7D6700536A62 /* StableDiffusion */; }; 8C4B32042A770C1D0090EF17 /* DiffusionImage+macOS.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8C4B32032A770C1D0090EF17 /* DiffusionImage+macOS.swift */; }; 8C4B32062A770C300090EF17 /* DiffusionImage+iOS.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8C4B32052A770C300090EF17 /* DiffusionImage+iOS.swift */; }; 8C4B32082A77F90C0090EF17 /* Utils_iOS.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8C4B32072A77F90C0090EF17 /* Utils_iOS.swift */; }; @@ -16,8 +18,6 @@ 8CEEB7D92A54C88C00C23829 /* DiffusionImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8CEEB7D82A54C88C00C23829 /* DiffusionImage.swift */; }; 8CEEB7DA2A54C88C00C23829 /* DiffusionImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8CEEB7D82A54C88C00C23829 /* DiffusionImage.swift */; }; EB067F872992E561004D1AD9 /* HelpContent.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB067F862992E561004D1AD9 /* HelpContent.swift */; }; - EB25B3D62A3A2DC4000E25A1 /* StableDiffusion in Frameworks */ = {isa = PBXBuildFile; productRef = EB25B3D52A3A2DC4000E25A1 /* StableDiffusion */; }; - EB25B3D82A3A2DD5000E25A1 /* StableDiffusion in Frameworks */ = {isa = PBXBuildFile; productRef = EB25B3D72A3A2DD5000E25A1 /* StableDiffusion */; }; EB560F0429A3C20800C0F8B8 /* Capabilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB560F0329A3C20800C0F8B8 /* Capabilities.swift */; }; EBB5BA5329425BEE003A2A5B /* PipelineLoader.swift in Sources */ = {isa = PBXBuildFile; fileRef = EBB5BA5229425BEE003A2A5B /* PipelineLoader.swift */; }; EBB5BA5A29426E06003A2A5B /* Downloader.swift in Sources */ = {isa = PBXBuildFile; fileRef = EBB5BA5929426E06003A2A5B /* Downloader.swift */; }; @@ -116,8 +116,8 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - EB25B3D62A3A2DC4000E25A1 /* StableDiffusion in Frameworks */, EBB5BA5D294504DE003A2A5B /* ZIPFoundation in Frameworks */, + 16AFDD512C1B7D6700536A62 /* StableDiffusion in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -140,7 +140,7 @@ buildActionMask = 2147483647; files = ( F155203C297118E700DC009B /* CompactSlider in Frameworks */, - EB25B3D82A3A2DD5000E25A1 /* StableDiffusion in Frameworks */, + 16AFDD4F2C1B7D6200536A62 /* StableDiffusion in Frameworks */, EBDD7DAF29731FB300C1C4B2 /* ZIPFoundation in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -318,7 +318,7 @@ name = Diffusion; packageProductDependencies = ( EBB5BA5C294504DE003A2A5B /* ZIPFoundation */, - EB25B3D52A3A2DC4000E25A1 /* StableDiffusion */, + 16AFDD502C1B7D6700536A62 /* StableDiffusion */, ); productName = Diffusion; productReference = EBE755C5293E37DD00806B32 /* Diffusion.app */; @@ -378,7 +378,7 @@ packageProductDependencies = ( F155203B297118E700DC009B /* CompactSlider */, EBDD7DAE29731FB300C1C4B2 /* ZIPFoundation */, - EB25B3D72A3A2DD5000E25A1 /* StableDiffusion */, + 16AFDD4E2C1B7D6200536A62 /* StableDiffusion */, ); productName = "Diffusion-macOS"; productReference = F15520212971093300DC009B /* Diffusers.app */; @@ -422,7 +422,7 @@ packageReferences = ( EBB5BA5B294504DE003A2A5B /* XCRemoteSwiftPackageReference "ZIPFoundation" */, F155203A297118E600DC009B /* XCRemoteSwiftPackageReference "CompactSlider" */, - EB25B3D42A3A2DC4000E25A1 /* XCRemoteSwiftPackageReference "ml-stable-diffusion" */, + 16AFDD4D2C1B7D4800536A62 /* XCRemoteSwiftPackageReference "ml-stable-diffusion" */, ); productRefGroup = EBE755C6293E37DD00806B32 /* Products */; projectDirPath = ""; @@ -876,7 +876,7 @@ "$(inherited)", "@executable_path/../Frameworks", ); - MACOSX_DEPLOYMENT_TARGET = 13.1; + MACOSX_DEPLOYMENT_TARGET = 14.0; SDKROOT = macosx; SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_VERSION = 5.0; @@ -904,7 +904,7 @@ "$(inherited)", "@executable_path/../Frameworks", ); - MACOSX_DEPLOYMENT_TARGET = 13.1; + MACOSX_DEPLOYMENT_TARGET = 14.0; PRODUCT_BUNDLE_IDENTIFIER = com.huggingface.Diffusers; SDKROOT = macosx; SWIFT_EMIT_LOC_STRINGS = YES; @@ -963,9 +963,9 @@ /* End XCConfigurationList section */ /* Begin XCRemoteSwiftPackageReference section */ - EB25B3D42A3A2DC4000E25A1 /* XCRemoteSwiftPackageReference "ml-stable-diffusion" */ = { + 16AFDD4D2C1B7D4800536A62 /* XCRemoteSwiftPackageReference "ml-stable-diffusion" */ = { isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/apple/ml-stable-diffusion"; + repositoryURL = "https://github.com/argmaxinc/ml-stable-diffusion.git"; requirement = { branch = main; kind = branch; @@ -990,18 +990,18 @@ /* End XCRemoteSwiftPackageReference section */ /* Begin XCSwiftPackageProductDependency section */ - EB0199482A31FEAF00B133E2 /* StableDiffusion */ = { + 16AFDD4E2C1B7D6200536A62 /* StableDiffusion */ = { isa = XCSwiftPackageProductDependency; + package = 16AFDD4D2C1B7D4800536A62 /* XCRemoteSwiftPackageReference "ml-stable-diffusion" */; productName = StableDiffusion; }; - EB25B3D52A3A2DC4000E25A1 /* StableDiffusion */ = { + 16AFDD502C1B7D6700536A62 /* StableDiffusion */ = { isa = XCSwiftPackageProductDependency; - package = EB25B3D42A3A2DC4000E25A1 /* XCRemoteSwiftPackageReference "ml-stable-diffusion" */; + package = 16AFDD4D2C1B7D4800536A62 /* XCRemoteSwiftPackageReference "ml-stable-diffusion" */; productName = StableDiffusion; }; - EB25B3D72A3A2DD5000E25A1 /* StableDiffusion */ = { + EB0199482A31FEAF00B133E2 /* StableDiffusion */ = { isa = XCSwiftPackageProductDependency; - package = EB25B3D42A3A2DC4000E25A1 /* XCRemoteSwiftPackageReference "ml-stable-diffusion" */; productName = StableDiffusion; }; EBB5BA5C294504DE003A2A5B /* ZIPFoundation */ = { diff --git a/Diffusion.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Diffusion.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 4fa2375..3eaff71 100644 --- a/Diffusion.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/Diffusion.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -1,4 +1,5 @@ { + "originHash" : "e97aab54879429ea40e58df49ffe4eef5228d95a28a7cf4d5dca9204c33564e1", "pins" : [ { "identity" : "compactslider", @@ -12,10 +13,10 @@ { "identity" : "ml-stable-diffusion", "kind" : "remoteSourceControl", - "location" : "https://github.com/apple/ml-stable-diffusion", + "location" : "https://github.com/argmaxinc/ml-stable-diffusion.git", "state" : { "branch" : "main", - "revision" : "d456a972cd7d84cab2ec353a29896d59b8602248" + "revision" : "d1f0604fab5345011e0b9f5b87ee0c155612565f" } }, { @@ -23,8 +24,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-argument-parser.git", "state" : { - "revision" : "fddd1c00396eed152c45a46bea9f47b98e59301d", - "version" : "1.2.0" + "revision" : "0fbc8848e389af3bb55c182bc19ca9d5dc2f255b", + "version" : "1.4.0" } }, { @@ -37,5 +38,5 @@ } } ], - "version" : 2 + "version" : 3 } diff --git a/Diffusion/Assets.xcassets/placeholder.imageset/labrador.png b/Diffusion/Assets.xcassets/placeholder.imageset/labrador.png index 0cdaef7..a93e1bf 100644 Binary files a/Diffusion/Assets.xcassets/placeholder.imageset/labrador.png and b/Diffusion/Assets.xcassets/placeholder.imageset/labrador.png differ diff --git a/Diffusion/Common/Downloader.swift b/Diffusion/Common/Downloader.swift index 69944df..b8cd9cd 100644 --- a/Diffusion/Common/Downloader.swift +++ b/Diffusion/Common/Downloader.swift @@ -28,8 +28,14 @@ class Downloader: NSObject, ObservableObject { self.destination = destination super.init() + var config = URLSessionConfiguration.default + #if !os(macOS) // .background allows downloads to proceed in the background - let config = URLSessionConfiguration.background(withIdentifier: "net.pcuenca.diffusion.download") + // helpful for devices that may not keep the app in the foreground for the download duration + config = URLSessionConfiguration.background(withIdentifier: "net.pcuenca.diffusion.download") + config.isDiscretionary = false + config.sessionSendsLaunchEvents = true + #endif urlSession = URLSession(configuration: config, delegate: self, delegateQueue: OperationQueue()) downloadState.value = .downloading(0) urlSession?.getAllTasks { tasks in @@ -75,8 +81,8 @@ class Downloader: NSObject, ObservableObject { } extension Downloader: URLSessionDelegate, URLSessionDownloadDelegate { - func urlSession(_: URLSession, downloadTask: URLSessionDownloadTask, didWriteData _: Int64, totalBytesWritten _: Int64, totalBytesExpectedToWrite _: Int64) { - downloadState.value = .downloading(downloadTask.progress.fractionCompleted) + func urlSession(_: URLSession, downloadTask: URLSessionDownloadTask, didWriteData _: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) { + downloadState.value = .downloading(Double(totalBytesWritten) / Double(totalBytesExpectedToWrite)) } func urlSession(_: URLSession, downloadTask _: URLSessionDownloadTask, didFinishDownloadingTo location: URL) { diff --git a/Diffusion/Common/ModelInfo.swift b/Diffusion/Common/ModelInfo.swift index ab03201..bffcd69 100644 --- a/Diffusion/Common/ModelInfo.swift +++ b/Diffusion/Common/ModelInfo.swift @@ -33,7 +33,10 @@ struct ModelInfo { /// Suffix of the archive containing the SPLIT_EINSUM_V2 attention variant. Usually something like "split_einsum_v2_compiled" let splitAttentionV2Suffix: String - + + /// Whether the archive contains ANE optimized models + let supportsNeuralEngine: Bool + /// Whether the archive contains the VAE Encoder (for image to image tasks). Not yet in use. let supportsEncoder: Bool @@ -46,25 +49,33 @@ struct ModelInfo { /// Whether this is a Stable Diffusion XL model // TODO: retrieve from remote config let isXL: Bool - + + /// Whether this is a Stable Diffusion 3 model + // TODO: retrieve from remote config + let isSD3: Bool + //TODO: refactor all these properties init(modelId: String, modelVersion: String, originalAttentionSuffix: String = "original_compiled", splitAttentionSuffix: String = "split_einsum_compiled", splitAttentionV2Suffix: String = "split_einsum_v2_compiled", + supportsNeuralEngine: Bool = true, supportsEncoder: Bool = false, supportsAttentionV2: Bool = false, quantized: Bool = false, - isXL: Bool = false) { + isXL: Bool = false, + isSD3: Bool = false) { self.modelId = modelId self.modelVersion = modelVersion self.originalAttentionSuffix = originalAttentionSuffix self.splitAttentionSuffix = splitAttentionSuffix self.splitAttentionV2Suffix = splitAttentionV2Suffix + self.supportsNeuralEngine = supportsNeuralEngine self.supportsEncoder = supportsEncoder self.supportsAttentionV2 = supportsAttentionV2 self.quantized = quantized self.isXL = isXL + self.isSD3 = isSD3 } } @@ -202,6 +213,24 @@ extension ModelInfo { isXL: true ) + static let sd3 = ModelInfo( + modelId: "argmaxinc/coreml-stable-diffusion-3-medium", + modelVersion: "SD3 medium (512, macOS)", + supportsNeuralEngine: false, // TODO: support SD3 on ANE + supportsEncoder: false, + quantized: false, + isSD3: true + ) + + static let sd3highres = ModelInfo( + modelId: "argmaxinc/coreml-stable-diffusion-3-medium-1024-t5", + modelVersion: "SD3 medium (1024, T5, macOS)", + supportsNeuralEngine: false, // TODO: support SD3 on ANE + supportsEncoder: false, + quantized: false, + isSD3: true + ) + static let MODELS: [ModelInfo] = { if deviceSupportsQuantization { var models = [ @@ -218,7 +247,9 @@ extension ModelInfo { models.append(contentsOf: [ ModelInfo.xl, ModelInfo.xlWithRefiner, - ModelInfo.xlmbp + ModelInfo.xlmbp, + ModelInfo.sd3, + ModelInfo.sd3highres, ]) } else { models.append(ModelInfo.xlmbpChunked) diff --git a/Diffusion/Common/Pipeline/Pipeline.swift b/Diffusion/Common/Pipeline/Pipeline.swift index ac69dcc..ae34b5b 100644 --- a/Diffusion/Common/Pipeline/Pipeline.swift +++ b/Diffusion/Common/Pipeline/Pipeline.swift @@ -50,6 +50,13 @@ class Pipeline { return false } + var isSD3: Bool { + if #available(macOS 14.0, iOS 17.0, *) { + return (pipeline as? StableDiffusion3Pipeline) != nil + } + return false + } + var progress: StableDiffusionProgress? = nil { didSet { progressPublisher.value = progress @@ -94,6 +101,13 @@ class Pipeline { config.schedulerTimestepSpacing = .karras } + if isSD3 { + config.encoderScaleFactor = 1.5305 + config.decoderScaleFactor = 1.5305 + config.decoderShiftFactor = 0.0609 + config.schedulerTimestepShift = 3.0 + } + // Evenly distribute previews based on inference steps let previewIndices = previewIndices(stepCount, previewCount) diff --git a/Diffusion/Common/Pipeline/PipelineLoader.swift b/Diffusion/Common/Pipeline/PipelineLoader.swift index 9dacd93..e2d0029 100644 --- a/Diffusion/Common/Pipeline/PipelineLoader.swift +++ b/Diffusion/Common/Pipeline/PipelineLoader.swift @@ -18,7 +18,7 @@ class PipelineLoader { let model: ModelInfo let computeUnits: ComputeUnits let maxSeed: UInt32 - + private var downloadSubscriber: Cancellable? init(model: ModelInfo, computeUnits: ComputeUnits? = nil, maxSeed: UInt32 = UInt32.max) { @@ -28,7 +28,7 @@ class PipelineLoader { state = .undetermined setInitialState() } - + enum PipelinePreparationPhase { case undetermined case waitingToDownload @@ -39,7 +39,7 @@ class PipelineLoader { case loaded case failed(Error) } - + var state: PipelinePreparationPhase { didSet { statePublisher.value = state @@ -82,38 +82,38 @@ extension PipelineLoader { var url: URL { return model.modelURL(for: variant) } - + var filename: String { return url.lastPathComponent } - + var downloadedURL: URL { PipelineLoader.models.appendingPathComponent(filename) } var uncompressURL: URL { PipelineLoader.models } - + var packagesFilename: String { (filename as NSString).deletingPathExtension } - + var compiledURL: URL { downloadedURL.deletingLastPathComponent().appendingPathComponent(packagesFilename) } var downloaded: Bool { return FileManager.default.fileExists(atPath: downloadedURL.path) } - + var ready: Bool { return FileManager.default.fileExists(atPath: compiledURL.path) } - + var variant: AttentionVariant { switch computeUnits { case .cpuOnly : return .original // Not supported yet case .cpuAndGPU : return .original case .cpuAndNeuralEngine: return model.supportsAttentionV2 ? .splitEinsumV2 : .splitEinsum - case .all : return .splitEinsum + case .all : return model.isSD3 ? .original : .splitEinsum @unknown default: fatalError("Unknown MLComputeUnits") } } - + func prepare() async throws -> Pipeline { do { do { @@ -131,11 +131,11 @@ extension PipelineLoader { throw error } } - + @discardableResult func download() async throws -> URL { if ready || downloaded { return downloadedURL } - + let downloader = Downloader(from: url, to: downloadedURL) self.downloader = downloader downloadSubscriber = downloader.downloadState.sink { state in @@ -146,7 +146,7 @@ extension PipelineLoader { try downloader.waitUntilDone() return downloadedURL } - + func unzip() async throws { guard downloaded else { return } state = .uncompressing @@ -160,7 +160,7 @@ extension PipelineLoader { try FileManager.default.removeItem(at: downloadedURL) state = .readyOnDisk } - + func load(url: URL) async throws -> StableDiffusionPipelineProtocol { let beginDate = Date() let configuration = MLModelConfiguration() @@ -169,11 +169,20 @@ extension PipelineLoader { if model.isXL { if #available(macOS 14.0, iOS 17.0, *) { pipeline = try StableDiffusionXLPipeline(resourcesAt: url, - configuration: configuration, - reduceMemory: model.reduceMemory) + configuration: configuration, + reduceMemory: model.reduceMemory) } else { throw "Stable Diffusion XL requires macOS 14" } + + } else if model.isSD3 { + if #available(macOS 14.0, iOS 17.0, *) { + pipeline = try StableDiffusion3Pipeline(resourcesAt: url, + configuration: configuration, + reduceMemory: model.reduceMemory) + } else { + throw "Stable Diffusion 3 requires macOS 14" + } } else { pipeline = try StableDiffusionPipeline(resourcesAt: url, controlNet: [], diff --git a/Diffusion/Common/State.swift b/Diffusion/Common/State.swift index ad667f6..ae2601a 100644 --- a/Diffusion/Common/State.swift +++ b/Diffusion/Common/State.swift @@ -11,7 +11,7 @@ import SwiftUI import StableDiffusion import CoreML -let DEFAULT_MODEL = ModelInfo.v2Base +let DEFAULT_MODEL = ModelInfo.sd3 let DEFAULT_PROMPT = "Labrador in the style of Vermeer" enum GenerationState { @@ -30,11 +30,14 @@ public enum StableDiffusionScheduler: String { case pndmScheduler /// Scheduler that uses a second order DPM-Solver++ algorithm case dpmSolverMultistepScheduler + /// Scheduler for rectified flow based multimodal diffusion transformer models + case discreteFlowScheduler func asStableDiffusionScheduler() -> StableDiffusion.StableDiffusionScheduler { switch self { case .pndmScheduler: return StableDiffusion.StableDiffusionScheduler.pndmScheduler case .dpmSolverMultistepScheduler: return StableDiffusion.StableDiffusionScheduler.dpmSolverMultistepScheduler + case .discreteFlowScheduler: return StableDiffusion.StableDiffusionScheduler.discreteFlowScheduler } } } @@ -58,15 +61,15 @@ class GenerationContext: ObservableObject { } @Published var state: GenerationState = .startup - @Published var positivePrompt = DEFAULT_PROMPT - @Published var negativePrompt = "" - + @Published var positivePrompt = Settings.shared.prompt + @Published var negativePrompt = Settings.shared.negativePrompt + // FIXME: Double to support the slider component - @Published var steps = 25.0 - @Published var numImages = 1.0 - @Published var seed: UInt32 = 0 - @Published var guidanceScale = 7.5 - @Published var previews = runningOnMac ? 5.0 : 0.0 + @Published var steps: Double = Settings.shared.stepCount + @Published var numImages: Double = 1.0 + @Published var seed: UInt32 = Settings.shared.seed + @Published var guidanceScale: Double = Settings.shared.guidanceScale + @Published var previews: Double = runningOnMac ? Settings.shared.previewCount : 0.0 @Published var disableSafety = false @Published var previewImage: CGImage? = nil @@ -112,16 +115,28 @@ class Settings { case model case safetyCheckerDisclaimer case computeUnits + case prompt + case negativePrompt + case guidanceScale + case stepCount + case previewCount + case seed } - + private init() { defaults.register(defaults: [ Keys.model.rawValue: ModelInfo.v2Base.modelId, Keys.safetyCheckerDisclaimer.rawValue: false, - Keys.computeUnits.rawValue: -1 // Use default + Keys.computeUnits.rawValue: -1, // Use default + Keys.prompt.rawValue: DEFAULT_PROMPT, + Keys.negativePrompt.rawValue: "", + Keys.guidanceScale.rawValue: 7.5, + Keys.stepCount.rawValue: 25, + Keys.previewCount.rawValue: 5, + Keys.seed.rawValue: 0 ]) } - + var currentModel: ModelInfo { set { defaults.set(newValue.modelId, forKey: Keys.model.rawValue) @@ -131,7 +146,64 @@ class Settings { return ModelInfo.from(modelId: modelId) ?? DEFAULT_MODEL } } - + + var prompt: String { + set { + defaults.set(newValue, forKey: Keys.prompt.rawValue) + } + get { + return defaults.string(forKey: Keys.prompt.rawValue) ?? DEFAULT_PROMPT + } + } + + var negativePrompt: String { + set { + defaults.set(newValue, forKey: Keys.negativePrompt.rawValue) + } + get { + return defaults.string(forKey: Keys.negativePrompt.rawValue) ?? "" + } + } + + var guidanceScale: Double { + set { + defaults.set(newValue, forKey: Keys.guidanceScale.rawValue) + } + get { + return defaults.double(forKey: Keys.guidanceScale.rawValue) + } + } + + var stepCount: Double { + set { + defaults.set(newValue, forKey: Keys.stepCount.rawValue) + } + get { + return defaults.double(forKey: Keys.stepCount.rawValue) + } + } + + var previewCount: Double { + set { + defaults.set(newValue, forKey: Keys.previewCount.rawValue) + } + get { + return defaults.double(forKey: Keys.previewCount.rawValue) + } + } + + var seed: UInt32 { + set { + defaults.set(String(newValue), forKey: Keys.seed.rawValue) + } + get { + if let seedString = defaults.string(forKey: Keys.seed.rawValue), let seedValue = UInt32(seedString) { + return seedValue + } + return 0 + } + } + var safetyCheckerDisclaimerShown: Bool { set { defaults.set(newValue, forKey: Keys.safetyCheckerDisclaimer.rawValue) diff --git a/config/common.xcconfig b/config/common.xcconfig index 8c20eb6..f582cb1 100644 --- a/config/common.xcconfig +++ b/config/common.xcconfig @@ -10,8 +10,8 @@ // https://help.apple.com/xcode/#/dev745c5c974 PRODUCT_NAME = Diffusers -CURRENT_PROJECT_VERSION = 1.1.0 -MARKETING_VERSION = 1.1 +CURRENT_PROJECT_VERSION = 20240607.135124 +MARKETING_VERSION = 1.5 // Update if you fork this repo DEVELOPMENT_TEAM = 2EADP68M95