Skip to content

Commit 7a4f537

Browse files
authored
SwarmUI generation provider (#217)
* Swarm UI working prototype implementation * Swarm UI models implementation * Swarm UI LoRAs implementation * Swarm UI Embeddings implementation * Fixed GenerationBottomToolbar * Update strings / docs * Add translations * Unit test coverage 1 * Update empty UI states * Fix Gallery detail original img2img base64 output format * Finalize implementation
1 parent e947e47 commit 7a4f537

File tree

179 files changed

+4012
-918
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

179 files changed

+4012
-918
lines changed

README.md

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ Stable Diffusion AI is an easy-to-use app that lets you quickly generate images
1616

1717
- Can use server environment powered by [AI Horde](https://stablehorde.net/) (a crowdsourced distributed cluster of Stable Diffusion workers)
1818
- Can use server environment powered by [Stable-Diffusion-WebUI](https://github.com/AUTOMATIC1111/stable-diffusion-webui) (AUTOMATIC1111)
19+
- Can use server environment powered by [SwarmUI](https://github.com/mcmonkeyprojects/SwarmUI)
1920
- Can use server envitonment powered by [Hugging Face Inference API](https://huggingface.co/docs/api-inference/quicktour).
2021
- Can use server environment powered by [OpenAI](https://platform.openai.com/docs/api-reference/images) (DALL-E-2, DALL-E-3).
2122
- Can use server environment powered by [Stability AI](https://platform.stability.ai/).
@@ -70,31 +71,39 @@ You can have it running either on your own hardware with modern GPU from Nvidia
7071

7172
If for some reason you have no ability to run your server instance, you can toggle the **Demo mode** switch on server setup page: it will allow you to test the app and get familiar with it, but it will return some mock images instead of AI-generated ones.
7273

73-
### Option 2: Use AI Horde
74+
### Option 2: Use your own SwarmUI instance
75+
76+
This requires you to have the SwarmUI that is running in server mode.
77+
78+
You can have it running either on your own hardware with modern GPU from Nvidia or AMD, or running it using Google Colab.
79+
80+
Please refer to the [SwarmUI documentation](https://github.com/mcmonkeyprojects/SwarmUI?tab=readme-ov-file#swarmui) for installation instructions.
81+
82+
### Option 3: Use AI Horde
7483

7584
[AI Horde](https://stablehorde.net/) is a crowdsourced distributed cluster of Image generation workers and text generation workers.
7685

7786
AI Horde requires to use API KEY, this mobile app alows to use either default API KEY (which is "0000000000"), or type your own. You can sign up and get your own AI Horde API KEY [here](https://stablehorde.net/register).
7887

79-
### Option 3: Hugging Face Inference
88+
### Option 4: Hugging Face Inference
8089

8190
[Hugging Face Inference API](https://huggingface.co/docs/api-inference/index) allows to test and evaluate, over 150,000 publicly accessible machine learning models, or your own private models, via simple HTTP requests, with fast inference hosted on Hugging Face shared infrastructure. This service is free, but is rate-limited.
8291

8392
Hugging Face Inference requires to use API KEY, which can be created in [Hugging Face account settings](https://huggingface.co/settings/tokens).
8493

85-
### Option 4: OpenAI
94+
### Option 5: OpenAI
8695

8796
OpenAI provides a service for text to image generation using [DALLE-2](https://openai.com/dall-e-2) or [DALLE-3](https://openai.com/dall-e-3) models. This service is paid.
8897

8998
OpenAI requires to use API KEY, which can be created in [OpenAI API Key settings](https://platform.openai.com/api-keys).
9099

91-
### Option 5: StabilityAI
100+
### Option 6: StabilityAI
92101

93102
[StabilityAI](https://platform.stability.ai/) is the image generation service provided by DreamStudio.
94103

95104
StabilityAI requires to use API KEY, which can be created in [API Keys page](https://platform.stability.ai/account/keys).
96105

97-
### Option 6: Local Diffusion (Beta)
106+
### Option 7: Local Diffusion (Beta)
98107

99108
Only **txt2img** mode is supported.
100109

app/build.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ android {
3434
buildConfigField "String", "DONATE_URL", "\"https://www.buymeacoffee.com/shifthackz\""
3535
buildConfigField "String", "GITHUB_SOURCE_URL", "\"https://github.com/ShiftHackZ/Stable-Diffusion-Android\""
3636
buildConfigField "String", "SETUP_INSTRUCTIONS_URL", "\"https://github.com/AUTOMATIC1111/stable-diffusion-webui/wiki\""
37+
buildConfigField "String", "SWARM_UI_INFO_URL", "\"https://github.com/mcmonkeyprojects/SwarmUI/tree/master/docs\""
3738

3839
resourceConfigurations = ["en", "ru", "uk", "tr", "zh"]
3940
}

app/src/main/java/com/shifthackz/aisdv1/app/di/ProvidersModule.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ val providersModule = module {
107107
override val donateUrl: String = BuildConfig.DONATE_URL
108108
override val gitHubSourceUrl: String = BuildConfig.GITHUB_SOURCE_URL
109109
override val setupInstructionsUrl: String = BuildConfig.SETUP_INSTRUCTIONS_URL
110+
override val swarmUiInfoUrl: String = BuildConfig.SWARM_UI_INFO_URL
110111
override val demoModeUrl: String = BuildConfig.DEMO_MODE_API_URL
111112
}
112113
}

core/common/src/main/java/com/shifthackz/aisdv1/core/common/links/LinksProvider.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,6 @@ interface LinksProvider {
1010
val donateUrl: String
1111
val gitHubSourceUrl: String
1212
val setupInstructionsUrl: String
13+
val swarmUiInfoUrl: String
1314
val demoModeUrl: String
1415
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package com.shifthackz.aisdv1.core.common.model
2+
3+
import java.io.Serializable
4+
5+
data class Hexagonal<out A, out B, out C, out D, out E, out F>(
6+
val first: A,
7+
val second: B,
8+
val third: C,
9+
val fourth: D,
10+
val fifth: E,
11+
val sixth: F,
12+
) : Serializable {
13+
14+
override fun toString(): String = "($first, $second, $third, $fourth, $fifth, $sixth)"
15+
}

core/common/src/main/java/com/shifthackz/aisdv1/core/common/model/Quadruple.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package com.shifthackz.aisdv1.core.common.model
22

33
import java.io.Serializable
44

5-
65
data class Quadruple<out A, out B, out C, out D>(
76
val first: A,
87
val second: B,
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package com.shifthackz.aisdv1.core.imageprocessing
2+
3+
import com.shifthackz.aisdv1.core.common.log.errorLog
4+
import com.shifthackz.aisdv1.core.imageprocessing.Base64EncodingConverter.Input
5+
import com.shifthackz.aisdv1.core.imageprocessing.Base64EncodingConverter.Output
6+
import com.shifthackz.aisdv1.core.imageprocessing.contract.RxImageProcessor
7+
import com.shifthackz.aisdv1.core.imageprocessing.utils.base64DefaultToNoWrap
8+
import io.reactivex.rxjava3.core.Scheduler
9+
import io.reactivex.rxjava3.core.Single
10+
11+
private typealias Base64EncodingProcessor = RxImageProcessor<Input, Output>
12+
13+
class Base64EncodingConverter(
14+
private val processingScheduler: Scheduler,
15+
) : Base64EncodingProcessor {
16+
17+
override fun invoke(input: Input): Single<Output> = Single
18+
.create { emitter ->
19+
convert(input).fold(
20+
onSuccess = emitter::onSuccess,
21+
onFailure = emitter::onError,
22+
)
23+
}
24+
.onErrorReturn { t ->
25+
errorLog(t)
26+
Output(input.base64)
27+
}
28+
.subscribeOn(processingScheduler)
29+
30+
private fun convert(input: Input): Result<Output> = runCatching {
31+
Output(base64DefaultToNoWrap(input.base64))
32+
}
33+
34+
data class Input(val base64: String)
35+
data class Output(val base64: String)
36+
}

core/imageprocessing/src/main/java/com/shifthackz/aisdv1/core/imageprocessing/di/ImageProcessingModule.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package com.shifthackz.aisdv1.core.imageprocessing.di
22

33
import android.graphics.BitmapFactory
44
import com.shifthackz.aisdv1.core.common.schedulers.SchedulersProvider
5+
import com.shifthackz.aisdv1.core.imageprocessing.Base64EncodingConverter
56
import com.shifthackz.aisdv1.core.imageprocessing.Base64ToBitmapConverter
67
import com.shifthackz.aisdv1.core.imageprocessing.BitmapToBase64Converter
78
import com.shifthackz.aisdv1.core.imageprocessing.R
@@ -20,4 +21,8 @@ val imageProcessingModule = module {
2021
factory {
2122
BitmapToBase64Converter(get<SchedulersProvider>().computation)
2223
}
24+
25+
factory {
26+
Base64EncodingConverter(get<SchedulersProvider>().computation)
27+
}
2328
}

core/imageprocessing/src/main/java/com/shifthackz/aisdv1/core/imageprocessing/utils/Base64ImageUtils.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,8 @@ fun bitmapToBase64(bitmap: Bitmap): String {
1515
bitmap.compress(Bitmap.CompressFormat.PNG, 100, outputStream)
1616
return Base64.encodeToString(outputStream.toByteArray(), Base64.DEFAULT)
1717
}
18+
19+
fun base64DefaultToNoWrap(base64Default: String): String {
20+
val byteArray = Base64.decode(base64Default, Base64.DEFAULT)
21+
return Base64.encodeToString(byteArray, Base64.NO_WRAP)
22+
}

data/src/main/java/com/shifthackz/aisdv1/data/di/LocalDataSourceModule.kt

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,25 +3,27 @@ package com.shifthackz.aisdv1.data.di
33
import com.shifthackz.aisdv1.data.gateway.DatabaseClearGatewayImpl
44
import com.shifthackz.aisdv1.data.gateway.mediastore.MediaStoreGatewayFactory
55
import com.shifthackz.aisdv1.data.local.DownloadableModelLocalDataSource
6+
import com.shifthackz.aisdv1.data.local.EmbeddingsLocalDataSource
67
import com.shifthackz.aisdv1.data.local.GenerationResultLocalDataSource
78
import com.shifthackz.aisdv1.data.local.HuggingFaceModelsLocalDataSource
9+
import com.shifthackz.aisdv1.data.local.LorasLocalDataSource
810
import com.shifthackz.aisdv1.data.local.ServerConfigurationLocalDataSource
911
import com.shifthackz.aisdv1.data.local.StabilityAiCreditsLocalDataSource
10-
import com.shifthackz.aisdv1.data.local.StableDiffusionEmbeddingsLocalDataSource
1112
import com.shifthackz.aisdv1.data.local.StableDiffusionHyperNetworksLocalDataSource
12-
import com.shifthackz.aisdv1.data.local.StableDiffusionLorasLocalDataSource
1313
import com.shifthackz.aisdv1.data.local.StableDiffusionModelsLocalDataSource
1414
import com.shifthackz.aisdv1.data.local.StableDiffusionSamplersLocalDataSource
15+
import com.shifthackz.aisdv1.data.local.SwarmUiModelsLocalDataSource
1516
import com.shifthackz.aisdv1.domain.datasource.DownloadableModelDataSource
17+
import com.shifthackz.aisdv1.domain.datasource.EmbeddingsDataSource
1618
import com.shifthackz.aisdv1.domain.datasource.GenerationResultDataSource
1719
import com.shifthackz.aisdv1.domain.datasource.HuggingFaceModelsDataSource
20+
import com.shifthackz.aisdv1.domain.datasource.LorasDataSource
1821
import com.shifthackz.aisdv1.domain.datasource.ServerConfigurationDataSource
1922
import com.shifthackz.aisdv1.domain.datasource.StabilityAiCreditsDataSource
20-
import com.shifthackz.aisdv1.domain.datasource.StableDiffusionEmbeddingsDataSource
2123
import com.shifthackz.aisdv1.domain.datasource.StableDiffusionHyperNetworksDataSource
22-
import com.shifthackz.aisdv1.domain.datasource.StableDiffusionLorasDataSource
2324
import com.shifthackz.aisdv1.domain.datasource.StableDiffusionModelsDataSource
2425
import com.shifthackz.aisdv1.domain.datasource.StableDiffusionSamplersDataSource
26+
import com.shifthackz.aisdv1.domain.datasource.SwarmUiModelsDataSource
2527
import com.shifthackz.aisdv1.domain.gateway.DatabaseClearGateway
2628
import org.koin.android.ext.koin.androidContext
2729
import org.koin.core.module.dsl.factoryOf
@@ -35,9 +37,10 @@ val localDataSourceModule = module {
3537
single<StabilityAiCreditsDataSource.Local> { StabilityAiCreditsLocalDataSource() }
3638
factoryOf(::StableDiffusionModelsLocalDataSource) bind StableDiffusionModelsDataSource.Local::class
3739
factoryOf(::StableDiffusionSamplersLocalDataSource) bind StableDiffusionSamplersDataSource.Local::class
38-
factoryOf(::StableDiffusionLorasLocalDataSource) bind StableDiffusionLorasDataSource.Local::class
40+
factoryOf(::LorasLocalDataSource) bind LorasDataSource.Local::class
3941
factoryOf(::StableDiffusionHyperNetworksLocalDataSource) bind StableDiffusionHyperNetworksDataSource.Local::class
40-
factoryOf(::StableDiffusionEmbeddingsLocalDataSource) bind StableDiffusionEmbeddingsDataSource.Local::class
42+
factoryOf(::EmbeddingsLocalDataSource) bind EmbeddingsDataSource.Local::class
43+
factoryOf(::SwarmUiModelsLocalDataSource) bind SwarmUiModelsDataSource.Local::class
4144
factoryOf(::ServerConfigurationLocalDataSource) bind ServerConfigurationDataSource.Local::class
4245
factoryOf(::GenerationResultLocalDataSource) bind GenerationResultDataSource.Local::class
4346
factoryOf(::DownloadableModelLocalDataSource) bind DownloadableModelDataSource.Local::class

0 commit comments

Comments
 (0)