bleam 0.0.8 → 0.0.10
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 +269 -22
- package/dist/cli.d.cts +32 -2
- package/dist/cli.d.ts +32 -2
- package/dist/cli.js +270 -23
- package/dist/platform.d.cts +2 -0
- package/dist/platform.d.ts +2 -0
- package/dist/{ui-1WepaMS4.d.cts → ui-Bg11tvlc.d.ts} +1 -1
- package/dist/{ui-Ce-pnUUA.d.ts → ui-Dd7SXdbg.d.cts} +7 -7
- package/dist/ui.d.cts +1 -1
- package/dist/ui.d.ts +1 -1
- package/dist/window.d.cts +1 -1
- package/dist/window.d.ts +1 -1
- package/package.json +5 -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 +482 -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 +1147 -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/main.swift +726 -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 +329 -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/templates/updates/README.md +272 -0
- package/templates/updates/src/index.ts +385 -0
- package/templates/updates/src/schema.ts +385 -0
- package/templates/updates/tsconfig.json +12 -0
- package/templates/updates/wrangler.jsonc +19 -0
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
// MemoryOptimizationConfig.swift - Memory optimization settings
|
|
2
|
+
// Copyright 2025 Vincent Gourbin
|
|
3
|
+
|
|
4
|
+
import Foundation
|
|
5
|
+
|
|
6
|
+
/// Configuration for memory optimization during transformer inference
|
|
7
|
+
///
|
|
8
|
+
/// These settings control how aggressively the transformer manages memory
|
|
9
|
+
/// by forcing evaluation of the computation graph at intervals.
|
|
10
|
+
///
|
|
11
|
+
/// # Background
|
|
12
|
+
/// MLX uses lazy evaluation and builds a computation graph. For large models,
|
|
13
|
+
/// this graph can grow very large and consume significant memory. Periodically
|
|
14
|
+
/// calling `eval()` materializes intermediate results and allows the graph to
|
|
15
|
+
/// be garbage collected.
|
|
16
|
+
///
|
|
17
|
+
/// # Trade-offs
|
|
18
|
+
/// - Lower `evalFrequency` = more memory savings, but slower inference
|
|
19
|
+
/// - Higher `evalFrequency` = faster inference, but more memory usage
|
|
20
|
+
/// - `clearCacheOnEval` = additional memory savings at cost of recomputation
|
|
21
|
+
///
|
|
22
|
+
/// # Reference
|
|
23
|
+
/// Based on optimizations from LTX-2-MLX: https://github.com/Acelogic/LTX-2-MLX
|
|
24
|
+
public struct MemoryOptimizationConfig: Sendable, Equatable {
|
|
25
|
+
|
|
26
|
+
/// How often to evaluate the computation graph during transformer forward pass.
|
|
27
|
+
///
|
|
28
|
+
/// - `0` = disabled (fastest, most memory)
|
|
29
|
+
/// - `4` = evaluate every 4 blocks (aggressive memory savings)
|
|
30
|
+
/// - `8` = evaluate every 8 blocks (moderate, recommended)
|
|
31
|
+
/// - `16` = evaluate every 16 blocks (light memory savings)
|
|
32
|
+
///
|
|
33
|
+
/// For Flux.2 Dev with 8 double + 48 single blocks:
|
|
34
|
+
/// - `evalFrequency: 8` will eval ~7 times during forward pass
|
|
35
|
+
/// - `evalFrequency: 4` will eval ~14 times during forward pass
|
|
36
|
+
public var evalFrequency: Int
|
|
37
|
+
|
|
38
|
+
/// Whether to clear GPU cache after each evaluation.
|
|
39
|
+
///
|
|
40
|
+
/// When enabled, calls `MLX.Memory.clearCache()` after each periodic eval.
|
|
41
|
+
/// This provides additional memory savings but may cause recomputation
|
|
42
|
+
/// of cached values.
|
|
43
|
+
///
|
|
44
|
+
/// Recommended: `false` for most cases, `true` only if running out of memory
|
|
45
|
+
public var clearCacheOnEval: Bool
|
|
46
|
+
|
|
47
|
+
/// Whether to evaluate after all double-stream blocks complete.
|
|
48
|
+
///
|
|
49
|
+
/// This ensures the transition between double-stream and single-stream
|
|
50
|
+
/// phases has a clean memory state.
|
|
51
|
+
public var evalBetweenPhases: Bool
|
|
52
|
+
|
|
53
|
+
public init(
|
|
54
|
+
evalFrequency: Int = 0,
|
|
55
|
+
clearCacheOnEval: Bool = false,
|
|
56
|
+
evalBetweenPhases: Bool = true
|
|
57
|
+
) {
|
|
58
|
+
self.evalFrequency = max(0, evalFrequency)
|
|
59
|
+
self.clearCacheOnEval = clearCacheOnEval
|
|
60
|
+
self.evalBetweenPhases = evalBetweenPhases
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// MARK: - Presets
|
|
64
|
+
|
|
65
|
+
/// Disabled - no periodic evaluation (fastest, most memory)
|
|
66
|
+
///
|
|
67
|
+
/// Use when you have plenty of RAM and want maximum speed.
|
|
68
|
+
public static let disabled = MemoryOptimizationConfig(
|
|
69
|
+
evalFrequency: 0,
|
|
70
|
+
clearCacheOnEval: false,
|
|
71
|
+
evalBetweenPhases: false
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
/// Light - evaluate every 16 blocks
|
|
75
|
+
///
|
|
76
|
+
/// Minimal impact on speed with some memory savings.
|
|
77
|
+
public static let light = MemoryOptimizationConfig(
|
|
78
|
+
evalFrequency: 16,
|
|
79
|
+
clearCacheOnEval: false,
|
|
80
|
+
evalBetweenPhases: true
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
/// Moderate - evaluate every 8 blocks (recommended default)
|
|
84
|
+
///
|
|
85
|
+
/// Good balance between speed and memory usage.
|
|
86
|
+
public static let moderate = MemoryOptimizationConfig(
|
|
87
|
+
evalFrequency: 8,
|
|
88
|
+
clearCacheOnEval: false,
|
|
89
|
+
evalBetweenPhases: true
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
/// Aggressive - evaluate every 4 blocks with cache clearing
|
|
93
|
+
///
|
|
94
|
+
/// Use when running low on memory. Slower but uses significantly less RAM.
|
|
95
|
+
public static let aggressive = MemoryOptimizationConfig(
|
|
96
|
+
evalFrequency: 4,
|
|
97
|
+
clearCacheOnEval: true,
|
|
98
|
+
evalBetweenPhases: true
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
/// Ultra low memory - evaluate every 2 blocks with cache clearing
|
|
102
|
+
///
|
|
103
|
+
/// Maximum memory savings at significant speed cost.
|
|
104
|
+
/// Use only if other presets cause out-of-memory errors.
|
|
105
|
+
public static let ultraLowMemory = MemoryOptimizationConfig(
|
|
106
|
+
evalFrequency: 2,
|
|
107
|
+
clearCacheOnEval: true,
|
|
108
|
+
evalBetweenPhases: true
|
|
109
|
+
)
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// MARK: - Description
|
|
113
|
+
|
|
114
|
+
extension MemoryOptimizationConfig: CustomStringConvertible {
|
|
115
|
+
public var description: String {
|
|
116
|
+
if evalFrequency == 0 && !evalBetweenPhases {
|
|
117
|
+
return "MemoryOptimization(disabled)"
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
var parts: [String] = []
|
|
121
|
+
if evalFrequency > 0 {
|
|
122
|
+
parts.append("evalEvery: \(evalFrequency)")
|
|
123
|
+
}
|
|
124
|
+
if clearCacheOnEval {
|
|
125
|
+
parts.append("clearCache: true")
|
|
126
|
+
}
|
|
127
|
+
if evalBetweenPhases {
|
|
128
|
+
parts.append("evalBetweenPhases: true")
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
return "MemoryOptimization(\(parts.joined(separator: ", ")))"
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// MARK: - Recommendation
|
|
136
|
+
|
|
137
|
+
extension MemoryOptimizationConfig {
|
|
138
|
+
|
|
139
|
+
/// Get recommended configuration based on available RAM
|
|
140
|
+
///
|
|
141
|
+
/// - Parameter ramGB: System RAM in gigabytes
|
|
142
|
+
/// - Returns: Recommended memory optimization preset
|
|
143
|
+
public static func recommended(forRAMGB ramGB: Int) -> MemoryOptimizationConfig {
|
|
144
|
+
switch ramGB {
|
|
145
|
+
case 0..<32:
|
|
146
|
+
return .ultraLowMemory
|
|
147
|
+
case 32..<64:
|
|
148
|
+
return .aggressive
|
|
149
|
+
case 64..<96:
|
|
150
|
+
return .moderate
|
|
151
|
+
case 96..<128:
|
|
152
|
+
return .light
|
|
153
|
+
default:
|
|
154
|
+
return .disabled
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
@@ -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
|
+
}
|