Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,8 @@ android {
applicationId "ai.offgridmobile"
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 1772365762
versionName "0.0.60"
versionCode 1772374541
versionName "0.0.61"
}
signingConfigs {
debug {
Expand Down
39 changes: 31 additions & 8 deletions ios/CoreMLDiffusionModule.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ class CoreMLDiffusionModule: RCTEventEmitter {

// MARK: - State

private var pipeline: StableDiffusionPipeline?
/// Both StableDiffusionPipeline and StableDiffusionXLPipeline conform to
/// StableDiffusionPipelineProtocol, so we store whichever one was created.
private var pipeline: StableDiffusionPipelineProtocol?
private var loadedModelPath: String?
private var generating = false
private var cancelRequested = false
Expand All @@ -28,6 +30,15 @@ class CoreMLDiffusionModule: RCTEventEmitter {
["LocalDreamProgress", "LocalDreamError"]
}

// MARK: - SDXL detection

/// Returns true if the model directory contains TextEncoder2.mlmodelc,
/// which is the hallmark of an SDXL model.
private func isXLModel(at url: URL) -> Bool {
let te2 = url.appendingPathComponent("TextEncoder2.mlmodelc")
return FileManager.default.fileExists(atPath: te2.path)
}

// MARK: - loadModel

@objc func loadModel(_ params: NSDictionary,
Expand All @@ -53,12 +64,24 @@ class CoreMLDiffusionModule: RCTEventEmitter {
let config = MLModelConfiguration()
config.computeUnits = .cpuAndNeuralEngine

let pipe = try StableDiffusionPipeline(
resourcesAt: url,
controlNet: [],
configuration: config,
reduceMemory: true
)
let pipe: StableDiffusionPipelineProtocol

if self.isXLModel(at: url) {
// SDXL models need the XL pipeline which uses TextEncoderXL
// (expects "hidden_embeds" output instead of "last_hidden_state")
pipe = try StableDiffusionXLPipeline(
resourcesAt: url,
configuration: config,
reduceMemory: true
)
} else {
pipe = try StableDiffusionPipeline(
resourcesAt: url,
controlNet: [],
configuration: config,
reduceMemory: true
)
}
Comment on lines +69 to +84

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This conditional logic for creating the pipeline is correct. For better code organization and to improve the readability of loadModel, consider extracting this logic into a separate private factory method. This would encapsulate the details of pipeline creation and make the loadModel function's primary responsibility clearer.

For example, you could introduce a method like this:

private func createPipeline(for url: URL, with config: MLModelConfiguration) throws -> StableDiffusionPipelineProtocol {
    if isXLModel(at: url) {
        // SDXL models need the XL pipeline
        return try StableDiffusionXLPipeline(
            resourcesAt: url,
            configuration: config,
            reduceMemory: true
        )
    } else {
        return try StableDiffusionPipeline(
            resourcesAt: url,
            controlNet: [],
            configuration: config,
            reduceMemory: true
        )
    }
}

And then call it from loadModel:

let pipe = try self.createPipeline(for: url, with: config)

This change would make the code more modular and easier to extend if more pipeline types are added in the future.


try pipe.loadResources()

Expand Down Expand Up @@ -126,7 +149,7 @@ class CoreMLDiffusionModule: RCTEventEmitter {
defer { self.generating = false }

do {
var pipelineConfig = StableDiffusionPipeline.Configuration(prompt: prompt)
var pipelineConfig = PipelineConfiguration(prompt: prompt)
pipelineConfig.negativePrompt = negativePrompt
pipelineConfig.stepCount = steps
pipelineConfig.guidanceScale = Float(guidanceScale)
Expand Down
8 changes: 4 additions & 4 deletions ios/OffgridMobile.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -398,7 +398,7 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = 1772365762;
CURRENT_PROJECT_VERSION = 1772374541;
DEVELOPMENT_TEAM = 84V6KCAC49;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = OffgridMobile/Info.plist;
Expand All @@ -409,7 +409,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 0.0.60;
MARKETING_VERSION = 0.0.61;
OTHER_LDFLAGS = (
"$(inherited)",
"-ObjC",
Expand All @@ -430,7 +430,7 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = 1772365762;
CURRENT_PROJECT_VERSION = 1772374541;
DEVELOPMENT_TEAM = 84V6KCAC49;
INFOPLIST_FILE = OffgridMobile/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = "Off Grid - Local AI";
Expand All @@ -440,7 +440,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 0.0.60;
MARKETING_VERSION = 0.0.61;
OTHER_LDFLAGS = (
"$(inherited)",
"-ObjC",
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "offgrid-mobile",
"version": "0.0.60",
"version": "0.0.61",
"private": true,
"scripts": {
"android": "react-native run-android --mode=debug --appId ai.offgridmobile.dev",
Expand Down
Loading