bleam 0.0.7 → 0.0.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.cjs +23 -4
- package/dist/cli.d.cts +2 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +23 -4
- package/dist/{ui-234Plg7Z.d.cts → ui-Bg11tvlc.d.ts} +7 -7
- package/dist/ui.d.ts +1 -1
- package/dist/window.d.ts +1 -1
- package/package.json +4 -1
- package/templates/image-generation/app/index.tsx +1 -1
- package/templates/native/.gitattributes +1 -0
- package/templates/native/App.tsx +26 -0
- package/templates/native/app.json +12 -0
- package/templates/native/index.ts +8 -0
- package/templates/native/ios/.xcode.env +11 -0
- package/templates/native/ios/Bleam/AI/Flux2/Configuration/Flux2Config.swift +288 -0
- package/templates/native/ios/Bleam/AI/Flux2/Configuration/MemoryConfig.swift +233 -0
- package/templates/native/ios/Bleam/AI/Flux2/Configuration/MemoryOptimizationConfig.swift +157 -0
- package/templates/native/ios/Bleam/AI/Flux2/Configuration/ModelRegistry.swift +425 -0
- package/templates/native/ios/Bleam/AI/Flux2/Configuration/QuantizationConfig.swift +138 -0
- package/templates/native/ios/Bleam/AI/Flux2/Configuration/TransformerRepoProfile.swift +59 -0
- package/templates/native/ios/Bleam/AI/Flux2/Configuration/VAEConfig.swift +134 -0
- package/templates/native/ios/Bleam/AI/Flux2/Flux2Core.swift +55 -0
- package/templates/native/ios/Bleam/AI/Flux2/Loading/WeightLoader.swift +1192 -0
- package/templates/native/ios/Bleam/AI/Flux2/Pipeline/FluxImageRunner.swift +1282 -0
- package/templates/native/ios/Bleam/AI/Flux2/Pipeline/LatentUtils.swift +191 -0
- package/templates/native/ios/Bleam/AI/Flux2/Scheduler/FlowMatchEulerScheduler.swift +279 -0
- package/templates/native/ios/Bleam/AI/Flux2/Text/KleinTextEncoder.swift +380 -0
- package/templates/native/ios/Bleam/AI/Flux2/Transformer/Flux2Attention.swift +379 -0
- package/templates/native/ios/Bleam/AI/Flux2/Transformer/Flux2Embeddings.swift +159 -0
- package/templates/native/ios/Bleam/AI/Flux2/Transformer/Flux2FeedForward.swift +154 -0
- package/templates/native/ios/Bleam/AI/Flux2/Transformer/Flux2FusedKernels.swift +198 -0
- package/templates/native/ios/Bleam/AI/Flux2/Transformer/Flux2KVCache.swift +36 -0
- package/templates/native/ios/Bleam/AI/Flux2/Transformer/Flux2Modulation.swift +193 -0
- package/templates/native/ios/Bleam/AI/Flux2/Transformer/Flux2ParallelAttention.swift +389 -0
- package/templates/native/ios/Bleam/AI/Flux2/Transformer/Flux2RoPE.swift +304 -0
- package/templates/native/ios/Bleam/AI/Flux2/Transformer/Flux2SingleBlock.swift +290 -0
- package/templates/native/ios/Bleam/AI/Flux2/Transformer/Flux2Transformer.swift +530 -0
- package/templates/native/ios/Bleam/AI/Flux2/Transformer/Flux2TransformerBlock.swift +362 -0
- package/templates/native/ios/Bleam/AI/Flux2/Utils/Flux2Debug.swift +101 -0
- package/templates/native/ios/Bleam/AI/Flux2/Utils/MLXCheckpoint.swift +118 -0
- package/templates/native/ios/Bleam/AI/Flux2/Utils/MemoryManager.swift +201 -0
- package/templates/native/ios/Bleam/AI/Flux2/VAE/AutoencoderKL.swift +476 -0
- package/templates/native/ios/Bleam/AI/Flux2/VAE/ResnetBlock.swift +316 -0
- package/templates/native/ios/Bleam/AI/Flux2/VAE/VAEDecoder.swift +120 -0
- package/templates/native/ios/Bleam/AI/Flux2/VAE/VAEEncoder.swift +136 -0
- package/templates/native/ios/Bleam/AppDelegate.swift +373 -0
- package/templates/native/ios/Bleam/Appearance.swift +62 -0
- package/templates/native/ios/Bleam/Bridging-Header.h +3 -0
- package/templates/native/ios/Bleam/Images.xcassets/AppIcon.appiconset/Contents.json +13 -0
- package/templates/native/ios/Bleam/Images.xcassets/Contents.json +6 -0
- package/templates/native/ios/Bleam/Info.plist +76 -0
- package/templates/native/ios/Bleam/PrivacyInfo.xcprivacy +48 -0
- package/templates/native/ios/Bleam/SceneDelegate.swift +58 -0
- package/templates/native/ios/Bleam/SplashScreen.storyboard +47 -0
- package/templates/native/ios/Bleam/Supporting/Expo.plist +6 -0
- package/templates/native/ios/Bleam/bleam.entitlements +10 -0
- package/templates/native/ios/Bleam.xcodeproj/project.pbxproj +1146 -0
- package/templates/native/ios/Bleam.xcodeproj/xcshareddata/xcschemes/Bleam.xcscheme +88 -0
- package/templates/native/ios/GenerationService/GenerationService.entitlements +10 -0
- package/templates/native/ios/GenerationService/ImageGenerationRunner.swift +591 -0
- package/templates/native/ios/GenerationService/Info.plist +31 -0
- package/templates/native/ios/GenerationService/main.swift +165 -0
- package/templates/native/ios/PlatformHelper/Info.plist +29 -0
- package/templates/native/ios/PlatformHelper/main.swift +335 -0
- package/templates/native/ios/Podfile +198 -0
- package/templates/native/ios/Podfile.lock +2284 -0
- package/templates/native/ios/Podfile.properties.json +5 -0
- package/templates/native/ios/Shared/Generation/GenerationServiceProtocol.swift +12 -0
- package/templates/native/ios/Shared/Generation/GenerationWorkerProtocol.swift +124 -0
- package/templates/native/metro.config.js +6 -0
- package/templates/native/modules/bleam-runtime/BleamRuntime.podspec +14 -0
- package/templates/native/modules/bleam-runtime/expo-module.config.json +8 -0
- package/templates/native/modules/bleam-runtime/ios/AIModule.swift +1258 -0
- package/templates/native/modules/bleam-runtime/ios/GenerationContracts.swift +135 -0
- package/templates/native/modules/bleam-runtime/ios/PlatformModule.swift +313 -0
- package/templates/native/modules/bleam-runtime/package.json +5 -0
- package/templates/native/package.json +39 -0
- package/templates/native/scripts/build/mlx-frameworks.ts +421 -0
- package/templates/native/scripts/start/index.ts +474 -0
- package/templates/native/scripts/start/known-failures.ts +20 -0
- package/templates/native/scripts/start/loader.ts +76 -0
- package/templates/native/scripts/start/native-state.ts +242 -0
- package/templates/native/scripts/start/package.json +4 -0
- package/templates/native/scripts/start/swift-packages.ts +414 -0
- package/templates/native/scripts/start/xcode-formatter.ts +106 -0
- package/templates/native/tsconfig.json +14 -0
- package/templates/native/yarn.lock +3749 -0
- package/dist/ui-BJmXhz9Q.d.ts +0 -92
- package/dist/ui-Dd7SXdbg.d.cts +0 -92
- package/dist/ui-Ds88eETu.d.ts +0 -92
- package/dist/ui-TaqnB5SP.d.ts +0 -92
- package/dist/ui-WQvnXL0W.d.ts +0 -92
|
@@ -0,0 +1,425 @@
|
|
|
1
|
+
import Foundation
|
|
2
|
+
|
|
3
|
+
public enum ModelRegistry {
|
|
4
|
+
public enum TransformerRepo: String, CaseIterable, Sendable {
|
|
5
|
+
case blackForestLabsKlein4B = "black-forest-labs/FLUX.2-klein-4B"
|
|
6
|
+
case moxinOrgKlein4B8bit = "moxin-org/FLUX.2-klein-4B-8bit-mlx"
|
|
7
|
+
case themindstudioKlein4B4bit = "themindstudio/flux2-klein-4b-mlx-4bit"
|
|
8
|
+
// These can be presented as Bonsai models while still using the Flux2 pipeline/runtime.
|
|
9
|
+
case prismMLBonsaiKlein4B2bit = "prism-ml/bonsai-image-ternary-4B-mlx-2bit"
|
|
10
|
+
case themindstudioKlein9B4bit = "themindstudio/flux2-klein-9b-mlx-4bit"
|
|
11
|
+
case aitraderKlein9B8bit = "AITRADER/FLUX2-klein-9B-mlx-8bit"
|
|
12
|
+
case mlxCommunityKlein9B4bit = "mlx-community/FLUX.2-klein-9B"
|
|
13
|
+
|
|
14
|
+
public var profile: Flux2TransformerRepoProfile {
|
|
15
|
+
switch self {
|
|
16
|
+
case .blackForestLabsKlein4B:
|
|
17
|
+
return Flux2TransformerRepoProfile(
|
|
18
|
+
repoId: rawValue,
|
|
19
|
+
model: .klein4B,
|
|
20
|
+
quantization: .bf16,
|
|
21
|
+
relativePathComponents: ["models--black-forest-labs--FLUX.2-klein-4B"],
|
|
22
|
+
requiredSnapshotPatterns: [
|
|
23
|
+
"config.json",
|
|
24
|
+
"model_index.json",
|
|
25
|
+
"flux-2-klein-4b*.safetensors",
|
|
26
|
+
"flux-2-klein-4b*.safetensors.index.json",
|
|
27
|
+
],
|
|
28
|
+
estimatedSizeGB: 8,
|
|
29
|
+
checkpointFormat: .diffusers
|
|
30
|
+
)
|
|
31
|
+
case .moxinOrgKlein4B8bit:
|
|
32
|
+
return Flux2TransformerRepoProfile(
|
|
33
|
+
repoId: rawValue,
|
|
34
|
+
model: .klein4B,
|
|
35
|
+
quantization: .qint8,
|
|
36
|
+
relativePathComponents: ["models--moxin-org--FLUX.2-klein-4B-8bit-mlx", "transformer"],
|
|
37
|
+
requiredSnapshotPatterns: [
|
|
38
|
+
"transformer/config.json",
|
|
39
|
+
"transformer/quantized_8bit.safetensors",
|
|
40
|
+
],
|
|
41
|
+
estimatedSizeGB: 4,
|
|
42
|
+
checkpointFormat: .diffusersQuanto
|
|
43
|
+
)
|
|
44
|
+
case .themindstudioKlein4B4bit:
|
|
45
|
+
return Flux2TransformerRepoProfile(
|
|
46
|
+
repoId: rawValue,
|
|
47
|
+
model: .klein4B,
|
|
48
|
+
quantization: .int4,
|
|
49
|
+
relativePathComponents: ["models--themindstudio--flux2-klein-4b-mlx-4bit", "transformer"],
|
|
50
|
+
requiredSnapshotPatterns: [
|
|
51
|
+
"transformer/model.safetensors.index.json",
|
|
52
|
+
"transformer/*.safetensors",
|
|
53
|
+
],
|
|
54
|
+
estimatedSizeGB: 5,
|
|
55
|
+
checkpointFormat: .packedDiffusers,
|
|
56
|
+
needsNormOutSwap: false,
|
|
57
|
+
usesNormOutBias: true
|
|
58
|
+
)
|
|
59
|
+
case .prismMLBonsaiKlein4B2bit:
|
|
60
|
+
return Flux2TransformerRepoProfile(
|
|
61
|
+
repoId: rawValue,
|
|
62
|
+
model: .klein4B,
|
|
63
|
+
quantization: .int4,
|
|
64
|
+
relativePathComponents: ["models--prism-ml--bonsai-image-ternary-4B-mlx-2bit", "transformer-packed-mflux"],
|
|
65
|
+
requiredSnapshotPatterns: [
|
|
66
|
+
"transformer-packed-mflux/config.json",
|
|
67
|
+
"transformer-packed-mflux/diffusion_pytorch_model.safetensors",
|
|
68
|
+
"transformer-packed-mflux/quantization_config.json",
|
|
69
|
+
],
|
|
70
|
+
estimatedSizeGB: 3,
|
|
71
|
+
checkpointFormat: .packedDiffusers,
|
|
72
|
+
needsNormOutSwap: false,
|
|
73
|
+
usesNormOutBias: false
|
|
74
|
+
)
|
|
75
|
+
case .themindstudioKlein9B4bit:
|
|
76
|
+
return Flux2TransformerRepoProfile(
|
|
77
|
+
repoId: rawValue,
|
|
78
|
+
model: .klein9B,
|
|
79
|
+
quantization: .int4,
|
|
80
|
+
relativePathComponents: ["models--themindstudio--flux2-klein-9b-mlx-4bit", "transformer"],
|
|
81
|
+
requiredSnapshotPatterns: [
|
|
82
|
+
"transformer/model.safetensors.index.json",
|
|
83
|
+
"transformer/*.safetensors",
|
|
84
|
+
],
|
|
85
|
+
estimatedSizeGB: 20,
|
|
86
|
+
checkpointFormat: .packedDiffusers,
|
|
87
|
+
needsNormOutSwap: false,
|
|
88
|
+
usesNormOutBias: true
|
|
89
|
+
)
|
|
90
|
+
case .aitraderKlein9B8bit:
|
|
91
|
+
return Flux2TransformerRepoProfile(
|
|
92
|
+
repoId: rawValue,
|
|
93
|
+
model: .klein9B,
|
|
94
|
+
quantization: .qint8,
|
|
95
|
+
relativePathComponents: ["models--AITRADER--FLUX2-klein-9B-mlx-8bit", "transformer"],
|
|
96
|
+
requiredSnapshotPatterns: [
|
|
97
|
+
"transformer/model.safetensors.index.json",
|
|
98
|
+
"transformer/*.safetensors",
|
|
99
|
+
],
|
|
100
|
+
estimatedSizeGB: 10,
|
|
101
|
+
checkpointFormat: .packedDiffusers,
|
|
102
|
+
needsNormOutSwap: false,
|
|
103
|
+
usesNormOutBias: true
|
|
104
|
+
)
|
|
105
|
+
case .mlxCommunityKlein9B4bit:
|
|
106
|
+
return Flux2TransformerRepoProfile(
|
|
107
|
+
repoId: rawValue,
|
|
108
|
+
model: .klein9B,
|
|
109
|
+
quantization: .int4,
|
|
110
|
+
relativePathComponents: ["models--mlx-community--FLUX.2-klein-9B", "transformer"],
|
|
111
|
+
requiredSnapshotPatterns: [
|
|
112
|
+
"transformer/model.safetensors.index.json",
|
|
113
|
+
"transformer/*.safetensors",
|
|
114
|
+
],
|
|
115
|
+
estimatedSizeGB: 20,
|
|
116
|
+
checkpointFormat: .packedDiffusers,
|
|
117
|
+
needsNormOutSwap: false,
|
|
118
|
+
usesNormOutBias: true
|
|
119
|
+
)
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
public static func repo(for model: Flux2Model, quantization: TransformerQuantization) -> TransformerRepo {
|
|
124
|
+
switch model {
|
|
125
|
+
case .klein4B:
|
|
126
|
+
switch quantization {
|
|
127
|
+
case .bf16:
|
|
128
|
+
return .blackForestLabsKlein4B
|
|
129
|
+
case .int4:
|
|
130
|
+
return .themindstudioKlein4B4bit
|
|
131
|
+
case .qint8:
|
|
132
|
+
return .moxinOrgKlein4B8bit
|
|
133
|
+
}
|
|
134
|
+
case .klein9B:
|
|
135
|
+
switch quantization {
|
|
136
|
+
case .qint8:
|
|
137
|
+
return .aitraderKlein9B8bit
|
|
138
|
+
case .int4:
|
|
139
|
+
return .themindstudioKlein9B4bit
|
|
140
|
+
case .bf16:
|
|
141
|
+
return .mlxCommunityKlein9B4bit
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
public static func profile(for repoId: String) -> Flux2TransformerRepoProfile? {
|
|
147
|
+
allCases.first { $0.rawValue == repoId }?.profile
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
public enum TransformerVariant: String, CaseIterable, Sendable {
|
|
152
|
+
case klein4B_bf16 = "klein4b-bf16"
|
|
153
|
+
case klein4B_8bit = "klein4b-8bit"
|
|
154
|
+
case klein4B_4bit = "klein4b-4bit"
|
|
155
|
+
case bonsaiKlein4B_2bit = "bonsai-klein4b-2bit"
|
|
156
|
+
case bonsaiKlein4B_1bit = "bonsai-klein4b-1bit"
|
|
157
|
+
case klein9B_8bit = "klein9b-8bit"
|
|
158
|
+
case klein9B_4bit = "klein9b-4bit"
|
|
159
|
+
|
|
160
|
+
public var huggingFaceRepo: String {
|
|
161
|
+
switch self {
|
|
162
|
+
case .klein4B_bf16:
|
|
163
|
+
return "black-forest-labs/FLUX.2-klein-4B"
|
|
164
|
+
case .klein4B_8bit:
|
|
165
|
+
return "moxin-org/FLUX.2-klein-4B-8bit-mlx"
|
|
166
|
+
case .klein4B_4bit:
|
|
167
|
+
return "themindstudio/flux2-klein-4b-mlx-4bit"
|
|
168
|
+
case .bonsaiKlein4B_2bit:
|
|
169
|
+
return "prism-ml/bonsai-image-ternary-4B-mlx-2bit"
|
|
170
|
+
case .bonsaiKlein4B_1bit:
|
|
171
|
+
return "prism-ml/bonsai-image-binary-4B-mlx-1bit"
|
|
172
|
+
case .klein9B_8bit:
|
|
173
|
+
return "AITRADER/FLUX2-klein-9B-mlx-8bit"
|
|
174
|
+
case .klein9B_4bit:
|
|
175
|
+
return "themindstudio/flux2-klein-9b-mlx-4bit"
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
public var huggingFaceSubfolder: String? {
|
|
180
|
+
switch self {
|
|
181
|
+
case .klein4B_bf16:
|
|
182
|
+
return nil
|
|
183
|
+
case .klein4B_8bit, .klein4B_4bit, .bonsaiKlein4B_2bit, .bonsaiKlein4B_1bit, .klein9B_8bit, .klein9B_4bit:
|
|
184
|
+
return "transformer"
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
public var requiredSnapshotPatterns: [String] {
|
|
189
|
+
switch self {
|
|
190
|
+
case .klein4B_bf16:
|
|
191
|
+
return [
|
|
192
|
+
"config.json",
|
|
193
|
+
"model_index.json",
|
|
194
|
+
"flux-2-klein-4b*.safetensors",
|
|
195
|
+
"flux-2-klein-4b*.safetensors.index.json",
|
|
196
|
+
]
|
|
197
|
+
case .klein4B_8bit:
|
|
198
|
+
return [
|
|
199
|
+
"transformer/config.json",
|
|
200
|
+
"transformer/quantized_8bit.safetensors",
|
|
201
|
+
]
|
|
202
|
+
case .klein4B_4bit:
|
|
203
|
+
return [
|
|
204
|
+
"transformer/model.safetensors.index.json",
|
|
205
|
+
"transformer/*.safetensors",
|
|
206
|
+
]
|
|
207
|
+
case .bonsaiKlein4B_2bit:
|
|
208
|
+
return [
|
|
209
|
+
"transformer-packed-mflux/config.json",
|
|
210
|
+
"transformer-packed-mflux/diffusion_pytorch_model.safetensors",
|
|
211
|
+
"transformer-packed-mflux/quantization_config.json",
|
|
212
|
+
]
|
|
213
|
+
case .bonsaiKlein4B_1bit:
|
|
214
|
+
return [
|
|
215
|
+
"transformer-packed-mflux/config.json",
|
|
216
|
+
"transformer-packed-mflux/diffusion_pytorch_model.safetensors",
|
|
217
|
+
"transformer-packed-mflux/quantization_config.json",
|
|
218
|
+
]
|
|
219
|
+
case .klein9B_8bit:
|
|
220
|
+
return [
|
|
221
|
+
"transformer/model.safetensors.index.json",
|
|
222
|
+
"transformer/*.safetensors",
|
|
223
|
+
]
|
|
224
|
+
case .klein9B_4bit:
|
|
225
|
+
return [
|
|
226
|
+
"transformer/model.safetensors.index.json",
|
|
227
|
+
"transformer/*.safetensors",
|
|
228
|
+
]
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
public var estimatedSizeGB: Int {
|
|
233
|
+
switch self {
|
|
234
|
+
case .klein4B_bf16: return 8
|
|
235
|
+
case .klein4B_8bit: return 4
|
|
236
|
+
case .klein4B_4bit: return 5
|
|
237
|
+
case .bonsaiKlein4B_2bit: return 3
|
|
238
|
+
case .bonsaiKlein4B_1bit: return 2
|
|
239
|
+
case .klein9B_8bit: return 10
|
|
240
|
+
case .klein9B_4bit: return 20
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
public var isGated: Bool { false }
|
|
245
|
+
public var license: String { "Apache 2.0" }
|
|
246
|
+
public var isCommercialUseAllowed: Bool { true }
|
|
247
|
+
public var defaultSteps: Int { 4 }
|
|
248
|
+
public var defaultGuidance: Float { 1.0 }
|
|
249
|
+
public var maxReferenceImages: Int { 4 }
|
|
250
|
+
|
|
251
|
+
public var quantization: TransformerQuantization {
|
|
252
|
+
switch self {
|
|
253
|
+
case .klein4B_bf16: return .bf16
|
|
254
|
+
case .klein4B_8bit: return .qint8
|
|
255
|
+
case .klein4B_4bit: return .int4
|
|
256
|
+
case .bonsaiKlein4B_2bit: return .int4
|
|
257
|
+
case .bonsaiKlein4B_1bit: return .int4
|
|
258
|
+
case .klein9B_8bit: return .qint8
|
|
259
|
+
case .klein9B_4bit: return .int4
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
public var modelType: Flux2Model {
|
|
264
|
+
switch self {
|
|
265
|
+
case .klein4B_bf16, .klein4B_8bit, .klein4B_4bit, .bonsaiKlein4B_2bit, .bonsaiKlein4B_1bit: return .klein4B
|
|
266
|
+
case .klein9B_8bit, .klein9B_4bit: return .klein9B
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
public var isForInference: Bool { true }
|
|
271
|
+
public var isForTraining: Bool { false }
|
|
272
|
+
|
|
273
|
+
public static func variant(for model: Flux2Model, quantization: TransformerQuantization) -> TransformerVariant {
|
|
274
|
+
switch model {
|
|
275
|
+
case .klein4B:
|
|
276
|
+
switch quantization {
|
|
277
|
+
case .bf16: return .klein4B_bf16
|
|
278
|
+
case .qint8: return .klein4B_8bit
|
|
279
|
+
case .int4: return .klein4B_4bit
|
|
280
|
+
}
|
|
281
|
+
case .klein9B:
|
|
282
|
+
switch quantization {
|
|
283
|
+
case .qint8: return .klein9B_8bit
|
|
284
|
+
case .int4: return .klein9B_4bit
|
|
285
|
+
case .bf16: return .klein9B_4bit
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
public enum VAEVariant: String, CaseIterable, Sendable {
|
|
292
|
+
case standard = "standard"
|
|
293
|
+
case smallDecoder = "small-decoder"
|
|
294
|
+
case bonsaiTernary = "bonsai-ternary"
|
|
295
|
+
|
|
296
|
+
public var huggingFaceRepo: String {
|
|
297
|
+
switch self {
|
|
298
|
+
case .standard:
|
|
299
|
+
return "black-forest-labs/FLUX.2-klein-4B"
|
|
300
|
+
case .smallDecoder:
|
|
301
|
+
return "black-forest-labs/FLUX.2-dev"
|
|
302
|
+
case .bonsaiTernary:
|
|
303
|
+
return "prism-ml/bonsai-image-ternary-4B-mlx-2bit"
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
public var huggingFaceSubfolder: String {
|
|
308
|
+
switch self {
|
|
309
|
+
case .standard, .smallDecoder, .bonsaiTernary:
|
|
310
|
+
return "vae"
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
public var requiredSnapshotPatterns: [String] {
|
|
315
|
+
switch self {
|
|
316
|
+
case .standard, .bonsaiTernary:
|
|
317
|
+
return [
|
|
318
|
+
"vae/config.json",
|
|
319
|
+
"vae/diffusion_pytorch_model.safetensors",
|
|
320
|
+
"vae/diffusion_pytorch_model.safetensors.index.json",
|
|
321
|
+
"vae/diffusion_pytorch_model-*.safetensors",
|
|
322
|
+
]
|
|
323
|
+
case .smallDecoder:
|
|
324
|
+
return [
|
|
325
|
+
"vae/config.json",
|
|
326
|
+
"vae/diffusion_pytorch_model.safetensors",
|
|
327
|
+
"vae/diffusion_pytorch_model.safetensors.index.json",
|
|
328
|
+
"vae/diffusion_pytorch_model-*.safetensors",
|
|
329
|
+
]
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
public var estimatedSizeGB: Int {
|
|
334
|
+
switch self {
|
|
335
|
+
case .standard, .bonsaiTernary: return 3
|
|
336
|
+
case .smallDecoder: return 1
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
public var isGated: Bool { false }
|
|
340
|
+
public var license: String { "Apache 2.0" }
|
|
341
|
+
public var isCommercialUseAllowed: Bool { true }
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
public enum ModelComponent: Hashable, Sendable {
|
|
345
|
+
case transformer(Flux2TransformerRepoProfile)
|
|
346
|
+
case textEncoder
|
|
347
|
+
case vae(VAEVariant)
|
|
348
|
+
|
|
349
|
+
public var displayName: String {
|
|
350
|
+
switch self {
|
|
351
|
+
case .transformer(let profile):
|
|
352
|
+
return "Flux.2 Transformer (\(profile.repoId))"
|
|
353
|
+
case .textEncoder:
|
|
354
|
+
return "Qwen3 Text Encoder"
|
|
355
|
+
case .vae:
|
|
356
|
+
return "Flux.2 VAE"
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
public var estimatedSizeGB: Int {
|
|
361
|
+
switch self {
|
|
362
|
+
case .transformer(let profile): return profile.estimatedSizeGB
|
|
363
|
+
case .textEncoder: return 4
|
|
364
|
+
case .vae(let variant): return variant.estimatedSizeGB
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
public var requiredSnapshotPatterns: [String] {
|
|
369
|
+
switch self {
|
|
370
|
+
case .transformer(let profile):
|
|
371
|
+
return profile.requiredSnapshotPatterns
|
|
372
|
+
case .textEncoder:
|
|
373
|
+
return []
|
|
374
|
+
case .vae(let variant):
|
|
375
|
+
return variant.requiredSnapshotPatterns
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
/// The `models/flux/` subdirectory inside the given container root.
|
|
381
|
+
public static func familyDirectory(containerRoot: URL) -> URL {
|
|
382
|
+
containerRoot
|
|
383
|
+
.appendingPathComponent("models", isDirectory: true)
|
|
384
|
+
.appendingPathComponent("flux", isDirectory: true)
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
/// The `models/flux/LoRAs/` subdirectory inside the given container root.
|
|
388
|
+
public static func loRAsDirectory(containerRoot: URL) -> URL {
|
|
389
|
+
familyDirectory(containerRoot: containerRoot)
|
|
390
|
+
.appendingPathComponent("LoRAs", isDirectory: true)
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
public static func localPath(for component: ModelComponent, containerRoot: URL) -> URL {
|
|
394
|
+
let family = familyDirectory(containerRoot: containerRoot)
|
|
395
|
+
switch component {
|
|
396
|
+
case .transformer(let profile):
|
|
397
|
+
return profile.relativePathComponents.reduce(family) { partial, component in
|
|
398
|
+
partial.appendingPathComponent(component, isDirectory: true)
|
|
399
|
+
}
|
|
400
|
+
case .textEncoder:
|
|
401
|
+
return family
|
|
402
|
+
case .vae(let variant):
|
|
403
|
+
let repoDir = variant.huggingFaceRepo
|
|
404
|
+
.replacingOccurrences(of: "/", with: "--")
|
|
405
|
+
return family
|
|
406
|
+
.appendingPathComponent("models--\(repoDir)")
|
|
407
|
+
.appendingPathComponent("vae")
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
public static func recommendedConfig(forRAMGB ram: Int) -> Flux2QuantizationConfig {
|
|
412
|
+
switch ram {
|
|
413
|
+
case 0..<32:
|
|
414
|
+
return .ultraMinimal
|
|
415
|
+
case 32..<48:
|
|
416
|
+
return .minimal
|
|
417
|
+
case 48..<64:
|
|
418
|
+
return .memoryEfficient
|
|
419
|
+
case 64..<96:
|
|
420
|
+
return .balanced
|
|
421
|
+
default:
|
|
422
|
+
return .highQuality
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
// QuantizationConfig.swift - Fine-grained quantization configuration
|
|
2
|
+
// Copyright 2025 Vincent Gourbin
|
|
3
|
+
|
|
4
|
+
import Foundation
|
|
5
|
+
|
|
6
|
+
/// Quantization level for the Mistral text encoder
|
|
7
|
+
public enum MistralQuantization: String, CaseIterable, Codable, Sendable {
|
|
8
|
+
case bf16 = "bf16" // Full precision ~48GB
|
|
9
|
+
case mlx8bit = "8bit" // 8-bit ~25GB
|
|
10
|
+
case mlx6bit = "6bit" // 6-bit ~19GB
|
|
11
|
+
case mlx4bit = "4bit" // 4-bit ~14GB
|
|
12
|
+
|
|
13
|
+
public var estimatedMemoryGB: Int {
|
|
14
|
+
switch self {
|
|
15
|
+
case .bf16: return 48
|
|
16
|
+
case .mlx8bit: return 25
|
|
17
|
+
case .mlx6bit: return 19
|
|
18
|
+
case .mlx4bit: return 14
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
public var displayName: String {
|
|
23
|
+
switch self {
|
|
24
|
+
case .bf16: return "Full Precision (bf16)"
|
|
25
|
+
case .mlx8bit: return "8-bit"
|
|
26
|
+
case .mlx6bit: return "6-bit"
|
|
27
|
+
case .mlx4bit: return "4-bit"
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/// Quantization level for the Flux.2 diffusion transformer
|
|
33
|
+
public enum TransformerQuantization: String, CaseIterable, Codable, Sendable {
|
|
34
|
+
case bf16 = "bf16" // Full precision ~64GB
|
|
35
|
+
case qint8 = "qint8" // 8-bit ~32GB
|
|
36
|
+
case int4 = "int4" // 4-bit ~16GB (on-the-fly quantization)
|
|
37
|
+
|
|
38
|
+
public var estimatedMemoryGB: Int {
|
|
39
|
+
switch self {
|
|
40
|
+
case .bf16: return 64
|
|
41
|
+
case .qint8: return 32
|
|
42
|
+
case .int4: return 16
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
public var displayName: String {
|
|
47
|
+
switch self {
|
|
48
|
+
case .bf16: return "Full Precision (bf16)"
|
|
49
|
+
case .qint8: return "8-bit (qint8)"
|
|
50
|
+
case .int4: return "4-bit (int4)"
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
public var bits: Int {
|
|
55
|
+
switch self {
|
|
56
|
+
case .bf16: return 16
|
|
57
|
+
case .qint8: return 8
|
|
58
|
+
case .int4: return 4
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
public var groupSize: Int { 64 }
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/// Independent quantization configuration for text encoder and transformer
|
|
66
|
+
public struct Flux2QuantizationConfig: Codable, Sendable {
|
|
67
|
+
/// Quantization for the Mistral text encoder
|
|
68
|
+
public var textEncoder: MistralQuantization
|
|
69
|
+
|
|
70
|
+
/// Quantization for the Flux.2 diffusion transformer
|
|
71
|
+
public var transformer: TransformerQuantization
|
|
72
|
+
|
|
73
|
+
public init(
|
|
74
|
+
textEncoder: MistralQuantization,
|
|
75
|
+
transformer: TransformerQuantization
|
|
76
|
+
) {
|
|
77
|
+
self.textEncoder = textEncoder
|
|
78
|
+
self.transformer = transformer
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/// Total estimated memory requirement in GB
|
|
82
|
+
public var estimatedTotalMemoryGB: Int {
|
|
83
|
+
// Text encoder and transformer are never loaded simultaneously
|
|
84
|
+
// So we take the max of the two, plus VAE (~3GB) and working memory (~5GB)
|
|
85
|
+
max(textEncoder.estimatedMemoryGB, transformer.estimatedMemoryGB) + 8
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/// Peak memory during text encoding phase
|
|
89
|
+
public var textEncodingPhaseMemoryGB: Int {
|
|
90
|
+
textEncoder.estimatedMemoryGB + 1 // +1GB for embeddings
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/// Peak memory during image generation phase
|
|
94
|
+
public var imageGenerationPhaseMemoryGB: Int {
|
|
95
|
+
transformer.estimatedMemoryGB + 3 + 5 // +3GB VAE, +5GB working memory
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// MARK: - Presets
|
|
99
|
+
|
|
100
|
+
/// High quality preset - requires ~90GB+ RAM
|
|
101
|
+
public static let highQuality = Flux2QuantizationConfig(
|
|
102
|
+
textEncoder: .bf16,
|
|
103
|
+
transformer: .bf16
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
/// Balanced preset - requires ~57GB RAM (recommended for 64GB Macs)
|
|
107
|
+
public static let balanced = Flux2QuantizationConfig(
|
|
108
|
+
textEncoder: .mlx8bit,
|
|
109
|
+
transformer: .qint8
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
/// Memory efficient preset - requires ~47GB RAM
|
|
113
|
+
public static let memoryEfficient = Flux2QuantizationConfig(
|
|
114
|
+
textEncoder: .mlx4bit,
|
|
115
|
+
transformer: .qint8
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
/// Minimal preset - requires ~47GB RAM
|
|
119
|
+
public static let minimal = Flux2QuantizationConfig(
|
|
120
|
+
textEncoder: .mlx4bit,
|
|
121
|
+
transformer: .qint8
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
/// Ultra-minimal preset - requires ~30GB RAM (4-bit transformer)
|
|
125
|
+
public static let ultraMinimal = Flux2QuantizationConfig(
|
|
126
|
+
textEncoder: .mlx4bit,
|
|
127
|
+
transformer: .int4
|
|
128
|
+
)
|
|
129
|
+
|
|
130
|
+
/// Default preset (balanced)
|
|
131
|
+
public static let `default` = balanced
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
extension Flux2QuantizationConfig: CustomStringConvertible {
|
|
135
|
+
public var description: String {
|
|
136
|
+
"Flux2QuantizationConfig(text: \(textEncoder.rawValue), transformer: \(transformer.rawValue), ~\(estimatedTotalMemoryGB)GB)"
|
|
137
|
+
}
|
|
138
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import Foundation
|
|
2
|
+
|
|
3
|
+
public enum Flux2TransformerCheckpointFormat: String, Sendable {
|
|
4
|
+
case diffusers
|
|
5
|
+
case diffusersQuanto
|
|
6
|
+
case packedDiffusers
|
|
7
|
+
case bfl
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
public struct Flux2TransformerRepoProfile: Hashable, Sendable {
|
|
11
|
+
public let repoId: String
|
|
12
|
+
public let model: Flux2Model
|
|
13
|
+
public let quantization: TransformerQuantization
|
|
14
|
+
public let relativePathComponents: [String]
|
|
15
|
+
public let requiredSnapshotPatterns: [String]
|
|
16
|
+
public let estimatedSizeGB: Int
|
|
17
|
+
public let checkpointFormat: Flux2TransformerCheckpointFormat
|
|
18
|
+
public let needsNormOutSwap: Bool
|
|
19
|
+
public let usesNormOutBias: Bool
|
|
20
|
+
|
|
21
|
+
public init(
|
|
22
|
+
repoId: String,
|
|
23
|
+
model: Flux2Model,
|
|
24
|
+
quantization: TransformerQuantization,
|
|
25
|
+
relativePathComponents: [String],
|
|
26
|
+
requiredSnapshotPatterns: [String],
|
|
27
|
+
estimatedSizeGB: Int,
|
|
28
|
+
checkpointFormat: Flux2TransformerCheckpointFormat,
|
|
29
|
+
needsNormOutSwap: Bool = false,
|
|
30
|
+
usesNormOutBias: Bool = false
|
|
31
|
+
) {
|
|
32
|
+
self.repoId = repoId
|
|
33
|
+
self.model = model
|
|
34
|
+
self.quantization = quantization
|
|
35
|
+
self.relativePathComponents = relativePathComponents
|
|
36
|
+
self.requiredSnapshotPatterns = requiredSnapshotPatterns
|
|
37
|
+
self.estimatedSizeGB = estimatedSizeGB
|
|
38
|
+
self.checkpointFormat = checkpointFormat
|
|
39
|
+
self.needsNormOutSwap = needsNormOutSwap
|
|
40
|
+
self.usesNormOutBias = usesNormOutBias
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
public func withRuntimeOverrides(
|
|
44
|
+
needsNormOutSwap: Bool? = nil,
|
|
45
|
+
usesNormOutBias: Bool? = nil
|
|
46
|
+
) -> Flux2TransformerRepoProfile {
|
|
47
|
+
Flux2TransformerRepoProfile(
|
|
48
|
+
repoId: repoId,
|
|
49
|
+
model: model,
|
|
50
|
+
quantization: quantization,
|
|
51
|
+
relativePathComponents: relativePathComponents,
|
|
52
|
+
requiredSnapshotPatterns: requiredSnapshotPatterns,
|
|
53
|
+
estimatedSizeGB: estimatedSizeGB,
|
|
54
|
+
checkpointFormat: checkpointFormat,
|
|
55
|
+
needsNormOutSwap: needsNormOutSwap ?? self.needsNormOutSwap,
|
|
56
|
+
usesNormOutBias: usesNormOutBias ?? self.usesNormOutBias
|
|
57
|
+
)
|
|
58
|
+
}
|
|
59
|
+
}
|