Skip to content

Commit 424e532

Browse files
committed
Help popovers, additional info on collapsed groups
1 parent d0465aa commit 424e532

File tree

3 files changed

+222
-10
lines changed

3 files changed

+222
-10
lines changed

Diffusion-macOS/ControlsView.swift

+93-10
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,12 @@ struct ControlsView: View {
6565
// TODO: make this computed, and observable, and easy to read
6666
@State private var mustShowSafetyCheckerDisclaimer = false
6767

68+
@State private var showModelsHelp = false
69+
@State private var showPromptsHelp = false
70+
@State private var showGuidanceHelp = false
71+
@State private var showStepsHelp = false
72+
@State private var showSeedHelp = false
73+
6874
func updateSafetyCheckerState() {
6975
mustShowSafetyCheckerDisclaimer = generation.disableSafety && !Settings.shared.safetyCheckerDisclaimerShown
7076
}
@@ -110,7 +116,7 @@ struct ControlsView: View {
110116
let prefix = downloaded ? "" : "" //"○ "
111117
return Text(prefix).foregroundColor(downloaded ? .accentColor : .secondary) + Text(model.modelVersion)
112118
}
113-
119+
114120
var body: some View {
115121
VStack(alignment: .leading) {
116122

@@ -132,9 +138,23 @@ struct ControlsView: View {
132138
modelDidChange(model: model)
133139
}
134140
} label: {
135-
Label("Model from Hub", systemImage: "cpu").foregroundColor(.secondary)
141+
HStack {
142+
Label("Model from Hub", systemImage: "cpu").foregroundColor(.secondary)
143+
Spacer()
144+
if disclosedModel {
145+
Button {
146+
showModelsHelp.toggle()
147+
} label: {
148+
Image(systemName: "info.circle")
149+
}
150+
.buttonStyle(.plain)
151+
// Or maybe use .sheet instead
152+
.sheet(isPresented: $showModelsHelp) {
153+
modelsHelp($showModelsHelp)
154+
}
155+
}
156+
}.foregroundColor(.secondary)
136157
}
137-
138158
Divider()
139159

140160
DisclosureGroup(isExpanded: $disclosedPrompt) {
@@ -148,19 +168,51 @@ struct ControlsView: View {
148168
.textFieldStyle(.squareBorder)
149169
}.padding(.leading, 10)
150170
} label: {
151-
Label("Prompts", systemImage: "text.quote").foregroundColor(.secondary)
171+
HStack {
172+
Label("Prompts", systemImage: "text.quote").foregroundColor(.secondary)
173+
Spacer()
174+
if disclosedPrompt {
175+
Button {
176+
showPromptsHelp.toggle()
177+
} label: {
178+
Image(systemName: "info.circle")
179+
}
180+
.buttonStyle(.plain)
181+
// Or maybe use .sheet instead
182+
.popover(isPresented: $showPromptsHelp, arrowEdge: .trailing) {
183+
promptsHelp($showPromptsHelp)
184+
}
185+
}
186+
}.foregroundColor(.secondary)
152187
}
153-
154188
Divider()
155189

190+
let guidanceScaleValue = generation.guidanceScale.formatted("%.1f")
156191
DisclosureGroup(isExpanded: $disclosedGuidance) {
157192
CompactSlider(value: $generation.guidanceScale, in: 0...20, step: 0.5) {
158193
Text("Guidance Scale")
159194
Spacer()
160-
Text(generation.guidanceScale.formatted("%.1f"))
195+
Text(guidanceScaleValue)
161196
}.padding(.leading, 10)
162197
} label: {
163-
Label("Guidance Scale", systemImage: "scalemass").foregroundColor(.secondary)
198+
HStack {
199+
Label("Guidance Scale", systemImage: "scalemass").foregroundColor(.secondary)
200+
Spacer()
201+
if disclosedGuidance {
202+
Button {
203+
showGuidanceHelp.toggle()
204+
} label: {
205+
Image(systemName: "info.circle")
206+
}
207+
.buttonStyle(.plain)
208+
// Or maybe use .sheet instead
209+
.popover(isPresented: $showGuidanceHelp, arrowEdge: .trailing) {
210+
guidanceHelp($showGuidanceHelp)
211+
}
212+
} else {
213+
Text(guidanceScaleValue)
214+
}
215+
}.foregroundColor(.secondary)
164216
}
165217
Divider()
166218

@@ -171,7 +223,23 @@ struct ControlsView: View {
171223
Text("\(Int(generation.steps))")
172224
}.padding(.leading, 10)
173225
} label: {
174-
Label("Step count", systemImage: "square.3.layers.3d.down.left").foregroundColor(.secondary)
226+
HStack {
227+
Label("Step count", systemImage: "square.3.layers.3d.down.left").foregroundColor(.secondary)
228+
Spacer()
229+
if disclosedSteps {
230+
Button {
231+
showStepsHelp.toggle()
232+
} label: {
233+
Image(systemName: "info.circle")
234+
}
235+
.buttonStyle(.plain)
236+
.popover(isPresented: $showStepsHelp, arrowEdge: .trailing) {
237+
stepsHelp($showStepsHelp)
238+
}
239+
} else {
240+
Text("\(Int(generation.steps))")
241+
}
242+
}.foregroundColor(.secondary)
175243
}
176244
Divider()
177245

@@ -183,7 +251,23 @@ struct ControlsView: View {
183251
Text("\(Int(generation.seed))")
184252
}.padding(.leading, 10)
185253
} label: {
186-
Label("Seed", systemImage: "leaf").foregroundColor(.secondary)
254+
HStack {
255+
Label("Seed", systemImage: "leaf").foregroundColor(.secondary)
256+
Spacer()
257+
if disclosedSeed {
258+
Button {
259+
showSeedHelp.toggle()
260+
} label: {
261+
Image(systemName: "info.circle")
262+
}
263+
.buttonStyle(.plain)
264+
.popover(isPresented: $showSeedHelp, arrowEdge: .trailing) {
265+
seedHelp($showSeedHelp)
266+
}
267+
} else {
268+
Text("\(Int(generation.seed))")
269+
}
270+
}.foregroundColor(.secondary)
187271
}
188272
}
189273
}
@@ -224,4 +308,3 @@ struct ControlsView: View {
224308
}
225309
}
226310
}
227-

Diffusion-macOS/HelpContent.swift

+125
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
//
2+
// HelpContent.swift
3+
// Diffusion-macOS
4+
//
5+
// Created by Pedro Cuenca on 7/2/23.
6+
// See LICENSE at https://github.com/huggingface/swift-coreml-diffusers/LICENSE
7+
//
8+
9+
import SwiftUI
10+
11+
func helpContent(title: String, description: Text, showing: Binding<Bool>, width: Double = 400) -> some View {
12+
VStack {
13+
Text(title)
14+
.font(.title3)
15+
.padding(.top, 10)
16+
.padding(.all, 5)
17+
description
18+
.lineLimit(nil)
19+
.padding(.bottom, 5)
20+
.padding([.leading, .trailing], 15)
21+
Button {
22+
showing.wrappedValue.toggle()
23+
} label: {
24+
Text("Dismiss").frame(maxWidth: 200)
25+
}
26+
.padding(.bottom)
27+
}
28+
.frame(minWidth: width, idealWidth: width, maxWidth: width)
29+
}
30+
31+
func helpContent(title: String, description: String, showing: Binding<Bool>, width: Double = 400) -> some View {
32+
helpContent(title: title, description: Text(description), showing: showing)
33+
}
34+
35+
func helpContent(title: String, description: AttributedString, showing: Binding<Bool>, width: Double = 400) -> some View {
36+
helpContent(title: title, description: Text(description), showing: showing)
37+
}
38+
39+
40+
func modelsHelp(_ showing: Binding<Bool>) -> some View {
41+
let description = try! AttributedString(markdown:
42+
"""
43+
Diffusers launches with a set of 5 models that can be downloaded from the Hugging Face Hub:
44+
45+
**Stable Diffusion 1.4**
46+
47+
This is the original Stable Diffusion model that changed the landscape of AI image generation.
48+
49+
**Stable Diffusion 1.5**
50+
51+
Same architecture as 1.4, but trained on additional images with a focus on aesthetics.
52+
53+
**Stable Diffusion 2**
54+
55+
Improved model, heavily retrained on millions of additional images.
56+
57+
**Stable Diffusion 2.1**
58+
59+
The last reference in the Stable Diffusion family. Works great with _negative prompts_.
60+
61+
OFA small v0
62+
63+
This is a special so-called _distilled_ model, half the size of the others. It runs faster and requires less RAM, try it out if you find generation slow!
64+
65+
""", options: AttributedString.MarkdownParsingOptions(interpretedSyntax: .inlineOnlyPreservingWhitespace))
66+
return helpContent(title: "Available Models", description: description, showing: showing, width: 600)
67+
}
68+
69+
func promptsHelp(_ showing: Binding<Bool>) -> some View {
70+
let description = try! AttributedString(markdown:
71+
"""
72+
**Prompt** is the description of what you want, and **negative prompt** is what you _don't want_.
73+
74+
Use the negative prompt to tweak a previous generation (by removing unwanted items), or to provide hints for the model.
75+
76+
Many people like to use negative prompts such as "ugly, bad quality" to make the model try harder. \
77+
Or consider excluding terms like "3d" or "realistic" if you're after particular drawing styles.
78+
79+
""", options: AttributedString.MarkdownParsingOptions(interpretedSyntax: .inlineOnlyPreservingWhitespace))
80+
return helpContent(title: "Prompt and Negative Prompt", description: description, showing: showing, width: 600)
81+
}
82+
83+
func guidanceHelp(_ showing: Binding<Bool>) -> some View {
84+
let description =
85+
"""
86+
Indicates how much the image should resemble the prompt.
87+
88+
Low values produce more varied results, while excessively high ones \
89+
may result in image artifacts such as posterization.
90+
91+
Values between 7 and 10 are usually good choices, but they affect \
92+
differently to different models.
93+
94+
Feel free to experiment!
95+
"""
96+
return helpContent(title: "Guidance Scale", description: description, showing: showing)
97+
}
98+
99+
func stepsHelp(_ showing: Binding<Bool>) -> some View {
100+
let description =
101+
"""
102+
How many times to go through the diffusion process.
103+
104+
Quality increases the more steps you choose, but marginal improvements \
105+
get increasingly smaller.
106+
107+
🧨 Diffusers currently uses the super efficient DPM Solver scheduler, \
108+
which produces great results in just 20 or 25 steps 🤯
109+
"""
110+
return helpContent(title: "Inference Steps", description: description, showing: showing)
111+
}
112+
113+
func seedHelp(_ showing: Binding<Bool>) -> some View {
114+
let description =
115+
"""
116+
This is a number that allows you to reproduce a previous generation.
117+
118+
Use it like this: select a seed and write a prompt, then generate an image. \
119+
Next, maybe add a negative prompt or tweak the prompt slightly, and see how the result changes. \
120+
Rinse and repeat until you are satisfied, or select a new seed to start over.
121+
122+
If you select -1, a random seed will be chosen for you.
123+
"""
124+
return helpContent(title: "Generation Seed", description: description, showing: showing)
125+
}

Diffusion.xcodeproj/project.pbxproj

+4
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
objects = {
88

99
/* Begin PBXBuildFile section */
10+
EB067F872992E561004D1AD9 /* HelpContent.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB067F862992E561004D1AD9 /* HelpContent.swift */; };
1011
EB33A51D2954D89F00B16357 /* StableDiffusion in Frameworks */ = {isa = PBXBuildFile; productRef = EB33A51C2954D89F00B16357 /* StableDiffusion */; };
1112
EBB5BA5329425BEE003A2A5B /* PipelineLoader.swift in Sources */ = {isa = PBXBuildFile; fileRef = EBB5BA5229425BEE003A2A5B /* PipelineLoader.swift */; };
1213
EBB5BA5829425E17003A2A5B /* Path in Frameworks */ = {isa = PBXBuildFile; productRef = EBB5BA5729425E17003A2A5B /* Path */; };
@@ -61,6 +62,7 @@
6162
/* End PBXContainerItemProxy section */
6263

6364
/* Begin PBXFileReference section */
65+
EB067F862992E561004D1AD9 /* HelpContent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HelpContent.swift; sourceTree = "<group>"; };
6466
EB33A51E2954E1BC00B16357 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = "<group>"; };
6567
EBB5BA5229425BEE003A2A5B /* PipelineLoader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PipelineLoader.swift; sourceTree = "<group>"; };
6668
EBB5BA5929426E06003A2A5B /* Downloader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Downloader.swift; sourceTree = "<group>"; };
@@ -244,6 +246,7 @@
244246
EBDD7DBB2977FFB300C1C4B2 /* GeneratedImageView.swift */,
245247
F1552030297109C300DC009B /* ControlsView.swift */,
246248
F155203329710B3600DC009B /* StatusView.swift */,
249+
EB067F862992E561004D1AD9 /* HelpContent.swift */,
247250
F155202C2971093400DC009B /* Diffusion_macOS.entitlements */,
248251
F15520292971093400DC009B /* Preview Content */,
249252
);
@@ -472,6 +475,7 @@
472475
EBDD7DAA29731F6C00C1C4B2 /* Pipeline.swift in Sources */,
473476
F15520262971093300DC009B /* ContentView.swift in Sources */,
474477
EBDD7DB92976AAFE00C1C4B2 /* State.swift in Sources */,
478+
EB067F872992E561004D1AD9 /* HelpContent.swift in Sources */,
475479
EBDD7DB42973200200C1C4B2 /* Utils.swift in Sources */,
476480
F1552031297109C300DC009B /* ControlsView.swift in Sources */,
477481
EBDD7DB62973206600C1C4B2 /* Downloader.swift in Sources */,

0 commit comments

Comments
 (0)