Skip to content
Open
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
1 change: 1 addition & 0 deletions app/android/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ android {
buildConfigField("String", "OPEN_AI_INFO_URL", "\"https://platform.openai.com/api-keys\"")
buildConfigField("String", "STABILITY_AI_INFO_URL", "\"https://platform.stability.ai/\"")
buildConfigField("String", "FAL_AI_INFO_URL", "\"https://fal.ai/dashboard/keys\"")
buildConfigField("String", "ARLI_AI_INFO_URL", "\"https://www.arliai.com/quick-start\"")
buildConfigField("String", "UPDATE_API_URL", "\"https://sdai.moroz.cc\"")
buildConfigField("String", "REPORT_API_URL", "\"https://sdai-report.moroz.cc\"")
buildConfigField("String", "DEMO_MODE_API_URL", "\"https://sdai.moroz.cc\"")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ val providersModule = module {
override val openAiInfoUrl: String = BuildConfig.OPEN_AI_INFO_URL
override val stabilityAiInfoUrl: String = BuildConfig.STABILITY_AI_INFO_URL
override val falAiInfoUrl: String = BuildConfig.FAL_AI_INFO_URL
override val arliAiInfoUrl: String = BuildConfig.ARLI_AI_INFO_URL
override val privacyPolicyUrl: String = BuildConfig.POLICY_URL
override val donateUrl: String = BuildConfig.DONATE_URL
override val projectWebsiteUrl: String = BuildConfig.PROJECT_WEBSITE_URL
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,12 @@ object DefaultLinksProvider : LinksProvider {
* @author Dmitriy Moroz
*/
override val falAiInfoUrl: String = "https://fal.ai/dashboard/keys"
/**
* Exposes the `arliAiInfoUrl` value used by the SDAI core common layer.
*
* @author Dmitriy Moroz
*/
override val arliAiInfoUrl: String = "https://www.arliai.com/quick-start"
/**
* Exposes the `privacyPolicyUrl` value used by the SDAI core common layer.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,12 @@ interface LinksProvider {
* @author Dmitriy Moroz
*/
val falAiInfoUrl: String
/**
* Exposes the `arliAiInfoUrl` value used by the SDAI core common layer.
*
* @author Dmitriy Moroz
*/
val arliAiInfoUrl: String
/**
* Exposes the `privacyPolicyUrl` value used by the SDAI core common layer.
*
Expand Down
5 changes: 5 additions & 0 deletions core/localization/src/androidMain/res/values-ru/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,11 @@
<string name="hint_fal_ai_sub_title">Fal.ai предоставляет hosted API моделей генерации изображений с очередью выполнения.</string>
<string name="hint_fal_ai_about">API ключи Fal.ai</string>

<string name="hint_arli_ai_title">Подключиться к ArliAI</string>
<string name="hint_arli_ai_sub_title">ArliAI предоставляет облачный API генерации изображений, совместимый с SDNext.</string>
<string name="hint_arli_ai_about">Документация API ArliAI</string>
<string name="hint_arli_ai_model">Checkpoint модели ArliAI</string>

<string name="hint_stability_ai_title">Подключиться к Stability AI</string>
<string name="hint_stability_ai_sub_title">StabilityAI — это сервис генерации изображений от DreamStudio.</string>
<string name="hint_stability_ai_about">О Stability AI</string>
Expand Down
5 changes: 5 additions & 0 deletions core/localization/src/androidMain/res/values-tr/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,11 @@
<string name="hint_fal_ai_sub_title">Fal.ai, kuyruk tabanlı çıkarım kullanan barındırılan görüntü oluşturma modeli API\'leri sağlar.</string>
<string name="hint_fal_ai_about">Fal.ai API anahtarları</string>

<string name="hint_arli_ai_title">ArliAI\'ye bağlanın</string>
<string name="hint_arli_ai_sub_title">ArliAI, SDNext uyumlu bulut görüntü oluşturma API\'leri sağlar.</string>
<string name="hint_arli_ai_about">ArliAI API belgeleri</string>
<string name="hint_arli_ai_model">ArliAI model checkpoint</string>

<string name="hint_stability_ai_title">Stability AI\'ya bağlanın</string>
<string name="hint_stability_ai_sub_title">StabilityAI - DreamStudio tarafından sağlanan görüntü oluşturma hizmetidir.</string>
<string name="hint_stability_ai_about">Hakkında Stability AI</string>
Expand Down
5 changes: 5 additions & 0 deletions core/localization/src/androidMain/res/values-uk/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,11 @@
<string name="hint_fal_ai_sub_title">Fal.ai надає hosted API моделей генерації зображень із чергою виконання.</string>
<string name="hint_fal_ai_about">API ключі Fal.ai</string>

<string name="hint_arli_ai_title">Підключитися до ArliAI</string>
<string name="hint_arli_ai_sub_title">ArliAI надає хмарний API генерації зображень, сумісний із SDNext.</string>
<string name="hint_arli_ai_about">Документація API ArliAI</string>
<string name="hint_arli_ai_model">Checkpoint моделі ArliAI</string>

<string name="hint_stability_ai_title">Підключитися до Stability AI</string>
<string name="hint_stability_ai_sub_title">StabilityAI — це сервіс генерації зображень від DreamStudio.</string>
<string name="hint_stability_ai_about">Про Stability AI</string>
Expand Down
5 changes: 5 additions & 0 deletions core/localization/src/androidMain/res/values-zh/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,11 @@
<string name="hint_fal_ai_sub_title">Fal.ai 提供托管的图像生成模型 API,并使用基于队列的推理。</string>
<string name="hint_fal_ai_about">Fal.ai API 密钥</string>

<string name="hint_arli_ai_title">连接到 ArliAI</string>
<string name="hint_arli_ai_sub_title">ArliAI 提供兼容 SDNext 的云端图像生成 API。</string>
<string name="hint_arli_ai_about">ArliAI API 文档</string>
<string name="hint_arli_ai_model">ArliAI 模型 checkpoint</string>

<!-- Stability AI连接提示 -->
<string name="hint_stability_ai_title">连接到 Stability AI</string>
<string name="hint_stability_ai_sub_title">StabilityAI 是由 DreamStudio 提供的图像生成服务。</string>
Expand Down
6 changes: 6 additions & 0 deletions core/localization/src/androidMain/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@
<string name="srv_type_open_ai" translatable="false">OpenAI</string>
<string name="srv_type_stability_ai" translatable="false">Stability AI</string>
<string name="srv_type_fal_ai" translatable="false">Fal.ai</string>
<string name="srv_type_arli_ai" translatable="false">ArliAI</string>
<string name="srv_type_swarm_ui" translatable="false">Swarm UI</string>

<string name="hint_prompt">Prompt</string>
Expand Down Expand Up @@ -239,6 +240,11 @@
<string name="hint_fal_ai_sub_title">Fal.ai provides hosted image generation model APIs with queue-based inference.</string>
<string name="hint_fal_ai_about">Fal.ai API keys</string>

<string name="hint_arli_ai_title">Connect to ArliAI</string>
<string name="hint_arli_ai_sub_title">ArliAI provides SDNext-compatible cloud image generation APIs.</string>
<string name="hint_arli_ai_about">ArliAI API docs</string>
<string name="hint_arli_ai_model">ArliAI model checkpoint</string>

<string name="hint_stability_ai_title">Connect to Stability AI</string>
<string name="hint_stability_ai_sub_title">StabilityAI is the image generation service provided by DreamStudio.</string>
<string name="hint_stability_ai_about">About Stability AI</string>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package com.shifthackz.aisdv1.data.mappers

import com.shifthackz.aisdv1.data.mocks.mockImageToImagePayload
import com.shifthackz.aisdv1.data.mocks.mockTextToImagePayload
import com.shifthackz.aisdv1.domain.entity.ArliAiSampler
import org.junit.Assert
import org.junit.Test

class KtorArliAiGenerationMappersTest {

@Test
fun `given text payload, expected arli ai request contract`() {
val payload = mockTextToImagePayload.copy(
samplingSteps = 80,
seed = " 5598 ",
sampler = "",
batchCount = 3,
)

val request = payload.mapToArliAiRequest(MODEL)

Assert.assertEquals(MODEL, request.sdModelCheckpoint)
Assert.assertEquals(payload.prompt, request.prompt)
Assert.assertEquals(payload.negativePrompt, request.negativePrompt)
Assert.assertEquals(40, request.steps)
Assert.assertEquals(ArliAiSampler.default.key, request.samplerName)
Assert.assertEquals(5598L, request.seed)
Assert.assertEquals(3, request.batchSize)
Assert.assertEquals(payload.restoreFaces, request.restoreFaces)
}

@Test
fun `given image payload, expected arli ai image request contract`() {
val payload = mockImageToImagePayload.copy(
base64Image = "AQID",
base64MaskImage = "BAUG",
samplingSteps = 0,
seed = "-1",
sampler = "Euler a",
batchCount = 2,
maskBlur = 8,
inPaintingFill = 1,
inPaintFullRes = true,
inPaintFullResPadding = 32,
inPaintingMaskInvert = 1,
)

val request = payload.mapToArliAiRequest(MODEL)

Assert.assertEquals(MODEL, request.sdModelCheckpoint)
Assert.assertEquals(listOf("AQID"), request.initImages)
Assert.assertEquals("BAUG", request.mask)
Assert.assertEquals(1, request.steps)
Assert.assertEquals("Euler a", request.samplerName)
Assert.assertEquals(-1L, request.seed)
Assert.assertEquals(2, request.batchSize)
Assert.assertEquals(8, request.maskBlur)
Assert.assertEquals(1, request.inPaintingFill)
Assert.assertTrue(request.inPaintFullRes == true)
Assert.assertEquals(32, request.inPaintFullResPadding)
Assert.assertEquals(1, request.inPaintingMaskInvert)
}

private companion object {
const val MODEL = "Illustrious-XL-v2.0"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package com.shifthackz.aisdv1.data.di

import com.shifthackz.aisdv1.core.common.extensions.fixUrlSlashes
import com.shifthackz.aisdv1.data.gateway.ServerConnectivityGatewayImpl
import com.shifthackz.aisdv1.data.local.ArliAiModelsLocalDataSource
import com.shifthackz.aisdv1.data.local.DownloadableModelFileStore
import com.shifthackz.aisdv1.data.local.DownloadableModelLocalDataSource
import com.shifthackz.aisdv1.data.local.EmbeddingsLocalDataSource
Expand All @@ -19,6 +20,8 @@ import com.shifthackz.aisdv1.data.provider.ServerUrlProvider
import com.shifthackz.aisdv1.data.remote.DownloadableModelFileDownloader
import com.shifthackz.aisdv1.data.remote.DownloadableModelRemoteDataSource
import com.shifthackz.aisdv1.data.remote.HordeStatusSource
import com.shifthackz.aisdv1.data.remote.KtorArliAiGenerationRemoteDataSource
import com.shifthackz.aisdv1.data.remote.KtorArliAiModelsRemoteDataSource
import com.shifthackz.aisdv1.data.remote.KtorForgeModulesRemoteDataSource
import com.shifthackz.aisdv1.data.remote.KtorFalAiGenerationRemoteDataSource
import com.shifthackz.aisdv1.data.remote.KtorHordeGenerationRemoteDataSource
Expand All @@ -44,6 +47,8 @@ import com.shifthackz.aisdv1.data.remote.KtorSwarmUiModelsRemoteDataSource
import com.shifthackz.aisdv1.data.remote.NoOpDownloadableModelFileDownloader
import com.shifthackz.aisdv1.data.remote.RandomImageRemoteDataSource
import com.shifthackz.aisdv1.data.remote.ReportRemoteDataSource
import com.shifthackz.aisdv1.data.repository.ArliAiGenerationRepositoryImpl
import com.shifthackz.aisdv1.data.repository.ArliAiModelsRepositoryImpl
import com.shifthackz.aisdv1.data.repository.DownloadableModelRepositoryImpl
import com.shifthackz.aisdv1.data.repository.EmbeddingsRepositoryImpl
import com.shifthackz.aisdv1.data.repository.FalAiGenerationRepositoryImpl
Expand Down Expand Up @@ -71,6 +76,8 @@ import com.shifthackz.aisdv1.data.repository.StableDiffusionScriptsRepositoryImp
import com.shifthackz.aisdv1.data.repository.SupportersRepositoryImpl
import com.shifthackz.aisdv1.data.repository.SwarmUiGenerationRepositoryImpl
import com.shifthackz.aisdv1.data.repository.TemporaryGenerationResultRepositoryImpl
import com.shifthackz.aisdv1.domain.datasource.ArliAiGenerationDataSource
import com.shifthackz.aisdv1.domain.datasource.ArliAiModelsDataSource
import com.shifthackz.aisdv1.domain.datasource.DownloadableModelDataSource
import com.shifthackz.aisdv1.domain.datasource.EmbeddingsDataSource
import com.shifthackz.aisdv1.domain.datasource.FalAiGenerationDataSource
Expand Down Expand Up @@ -107,6 +114,8 @@ import com.shifthackz.aisdv1.domain.gateway.MediaStoreGateway
import com.shifthackz.aisdv1.domain.gateway.NoOpMediaStoreGateway
import com.shifthackz.aisdv1.domain.gateway.ServerConnectivityGateway
import com.shifthackz.aisdv1.domain.preference.PreferenceManager
import com.shifthackz.aisdv1.domain.repository.ArliAiGenerationRepository
import com.shifthackz.aisdv1.domain.repository.ArliAiModelsRepository
import com.shifthackz.aisdv1.domain.repository.DownloadableModelRepository
import com.shifthackz.aisdv1.domain.repository.EmbeddingsRepository
import com.shifthackz.aisdv1.domain.repository.FalAiGenerationRepository
Expand Down Expand Up @@ -184,6 +193,9 @@ val coreDataModule = module {
single<StableDiffusionModelsDataSource.Local> {
StableDiffusionModelsLocalDataSource(dao = get())
}
single<ArliAiModelsDataSource.Local> {
ArliAiModelsLocalDataSource(dao = get())
}
single<StableDiffusionSamplersDataSource.Local> {
StableDiffusionSamplersLocalDataSource(dao = get())
}
Expand Down Expand Up @@ -337,6 +349,28 @@ val coreDataModule = module {
remoteDataSource = get(),
)
}
single<ArliAiGenerationDataSource.Remote> {
KtorArliAiGenerationRemoteDataSource(api = get())
}
single<ArliAiModelsDataSource.Remote> {
KtorArliAiModelsRemoteDataSource(api = get())
}
single<ArliAiModelsRepository> {
ArliAiModelsRepositoryImpl(
remoteDataSource = get(),
localDataSource = get(),
preferenceManager = get(),
)
}
single<ArliAiGenerationRepository> {
ArliAiGenerationRepositoryImpl(
mediaStoreGateway = get(),
localDataSource = get(),
backgroundWorkObserver = get(),
preferenceManager = get(),
remoteDataSource = get(),
)
}
single<StabilityAiGenerationDataSource.Remote> {
KtorStabilityAiGenerationRemoteDataSource(api = get())
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package com.shifthackz.aisdv1.data.local

import com.shifthackz.aisdv1.data.mappers.mapArliAiEntityToDomain
import com.shifthackz.aisdv1.data.mappers.mapDomainToArliAiEntity
import com.shifthackz.aisdv1.domain.datasource.ArliAiModelsDataSource
import com.shifthackz.aisdv1.domain.entity.StableDiffusionModel
import com.shifthackz.aisdv1.storage.db.cache.dao.ArliAiModelDao
import com.shifthackz.aisdv1.storage.db.cache.entity.ArliAiModelEntity

/**
* Reads and writes cached ArliAI checkpoint metadata.
*
* @param dao Room DAO for the ArliAI model cache table.
*
* @author Dmitriy Moroz
*/
internal class ArliAiModelsLocalDataSource(
private val dao: ArliAiModelDao,
) : ArliAiModelsDataSource.Local {

/**
* Reads all cached ArliAI checkpoints.
*
* @return locally stored ArliAI checkpoints mapped into domain models.
*
* @author Dmitriy Moroz
*/
override suspend fun getModels(): List<StableDiffusionModel> = dao
.queryAll()
.let(List<ArliAiModelEntity>::mapArliAiEntityToDomain)

/**
* Replaces the cached ArliAI checkpoint list.
*
* @param models latest checkpoint metadata returned by the provider.
*
* @author Dmitriy Moroz
*/
override suspend fun insertModels(models: List<StableDiffusionModel>) {
dao.deleteAll()
dao.insertList(models.mapDomainToArliAiEntity())
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package com.shifthackz.aisdv1.data.mappers

import com.shifthackz.aisdv1.domain.entity.StableDiffusionModel
import com.shifthackz.aisdv1.storage.db.cache.entity.ArliAiModelEntity

/**
* Converts domain checkpoint metadata into distinct ArliAI cache rows.
*
* @return Room entities keyed by the best available ArliAI checkpoint name.
*
* @author Dmitriy Moroz
*/
fun List<StableDiffusionModel>.mapDomainToArliAiEntity(): List<ArliAiModelEntity> =
distinctBy(StableDiffusionModel::arliAiCheckpointName)
.map(StableDiffusionModel::mapDomainToArliAiEntity)

/**
* Converts one domain checkpoint into an ArliAI cache row.
*
* @author Dmitriy Moroz
*/
fun StableDiffusionModel.mapDomainToArliAiEntity(): ArliAiModelEntity = with(this) {
ArliAiModelEntity(
id = arliAiCheckpointName,
title = title,
name = modelName,
hash = hash,
sha256 = sha256,
filename = filename,
config = config,
)
}

/**
* Converts cached ArliAI model rows into domain checkpoint metadata.
*
* @return domain models shown by setup and generation screens.
*
* @author Dmitriy Moroz
*/
fun List<ArliAiModelEntity>.mapArliAiEntityToDomain(): List<StableDiffusionModel> =
map(ArliAiModelEntity::mapArliAiEntityToDomain)

/**
* Converts one cached ArliAI model row into domain checkpoint metadata.
*
* @author Dmitriy Moroz
*/
fun ArliAiModelEntity.mapArliAiEntityToDomain(): StableDiffusionModel = with(this) {
StableDiffusionModel(
title = title,
modelName = name,
hash = hash,
sha256 = sha256,
filename = filename,
config = config,
)
}

/**
* Returns the stable key used for ArliAI model cache de-duplication.
*
* @author Dmitriy Moroz
*/
private val StableDiffusionModel.arliAiCheckpointName: String
get() = title.ifBlank { modelName }.ifBlank { filename }
Loading