This file is the combined quick-start and contract guide for:
- the
MediaGenerationKitSwift package - the
media-generation-kit-cliexample client
Full documentation:
Keep examples, help text, and behavior aligned with:
Libraries/MediaGenerationKitApps/MediaGenerationKitCLI/MediaGenerationKitCLI.swift
If command or API behavior changes, update this file and the wrapper-repo copy that is synced into
drawthingsai/media-generation-kit.
In Package.swift:
import PackageDescription
let package = Package(
name: "MyApp",
dependencies: [
.package(
url: "https://github.com/drawthingsai/media-generation-kit.git",
revision: "37e0b70092ad1a0c1d4c6b24f16e17b73f1b1fb3"
)
],
targets: [
.executableTarget(
name: "MyApp",
dependencies: [
.product(name: "MediaGenerationKit", package: "media-generation-kit")
]
)
]
)media-generation-kit currently pins draw-things-community by revision, so install this package
with a specific revision instead of a version-based requirement.
The package is centered on:
MediaGenerationPipelineMediaGenerationPipeline.PreviewMediaGenerationEnvironmentLoRAImporterLoRAStoreMediaGenerationKitErrorAppCheckConfiguration
Core rules:
MediaGenerationPipeline.fromPretrained(...)is async.- Configuration lives on
pipeline.configuration. MediaGenerationEnvironment.defaultowns process-wide defaults and model-management helpers.LoRAImporteris local conversion only.LoRAStoreis Draw Things cloud storage only.
import Foundation
import MediaGenerationKit
@main
struct ExampleApp {
static func main() async throws {
try await MediaGenerationEnvironment.default.ensure(
"flux_2_klein_4b_q8p.ckpt"
)
var pipeline = try await MediaGenerationPipeline.fromPretrained(
"flux_2_klein_4b_q8p.ckpt",
backend: .local
)
pipeline.configuration.width = 1024
pipeline.configuration.height = 1024
pipeline.configuration.steps = 4
let results = try await pipeline.generate(
prompt: "a cat in studio lighting",
negativePrompt: ""
)
try results[0].write(
to: URL(fileURLWithPath: "/tmp/cat.png"),
type: .png
)
}
}import Foundation
import MediaGenerationKit
@main
struct RemoteExampleApp {
static func main() async throws {
var pipeline = try await MediaGenerationPipeline.fromPretrained(
"flux_2_klein_4b_q8p.ckpt",
backend: .remote(.init(host: "127.0.0.1", port: 7859))
)
pipeline.configuration.width = 1024
pipeline.configuration.height = 1024
pipeline.configuration.steps = 4
let results = try await pipeline.generate(
prompt: "a cat in studio lighting",
negativePrompt: ""
)
try results[0].write(
to: URL(fileURLWithPath: "/tmp/cat.png"),
type: .png
)
}
}import Foundation
import MediaGenerationKit
@main
struct CloudComputeExampleApp {
static func main() async throws {
var pipeline = try await MediaGenerationPipeline.fromPretrained(
"flux_2_klein_4b_q8p.ckpt",
backend: .cloudCompute(apiKey: "YOUR_API_KEY")
)
pipeline.configuration.width = 1024
pipeline.configuration.height = 1024
pipeline.configuration.steps = 4
let results = try await pipeline.generate(
prompt: "a cat in studio lighting",
negativePrompt: ""
)
try results[0].write(
to: URL(fileURLWithPath: "/tmp/cat.png"),
type: .png
)
}
}- Local:
backend: .localbackend: .local(directory: "/path/to/Models")
- Remote:
backend: .remote(.init(host: "127.0.0.1", port: 7859))
- Cloud compute:
backend: .cloudCompute(apiKey: "YOUR_API_KEY")
Inputs are direct values:
CIImageUIImageMediaGenerationPipeline.data(_:)MediaGenerationPipeline.file(_:)- role wrappers such as
.mask(),.moodboard(),.depth()
There is no standalone request/options/assets object.
Results are MediaGenerationPipeline.Result values and support:
write(to:type:)CIImage(result)UIImage(result)
Generation progress callbacks can also carry a MediaGenerationPipeline.Preview?:
preview == nilfor non-preview states such as.preparing,.uploading, or.completedpreview != nilfor preview-bearing progress updates such as samplingPreviewis a random-access collection whose subscript lazily decodes aCGImageon demand
Important members on MediaGenerationEnvironment.default:
externalUrlsmaxTotalWeightsCacheSizeensure(...)resolveModel(...)suggestedModels(...)inspectModel(...)downloadableModels(...)
Sync vs async catalog rules:
- Sync overloads are offline-only or cache-only.
- Async overloads are the network-capable path.
- If a sync overload is called with
offline: falseand it would need uncached remote catalog data, it throwsMediaGenerationKitError.asyncOperationRequired(...). suggestedModels(..., offline: false)is stricter: the sync variant throws immediately if remote catalog data is not already cached.
Local conversion:
LoRAImporter(file:version:)- optional
inspect() import(to:scaleFactor:progressHandler:)
Cloud storage:
LoRAStore(backend:)upload(_:file:)delete(_:)delete(keys:)
- One
generatecommand handles both text-to-image and image-to-image. - Remote generation is enabled with
--remote, not with a separate subcommand. - Draw Things cloud generation is enabled with
--cloud-compute, not with a separate subcommand. --models-diris an optional flag, never a positional argument.- Auth commands are standalone and never require a models directory.
- Saved cloud credentials are reused by
auth state,auth token,lora upload, andgenerate --cloud-compute. - Saved cloud credentials remember the cloud API base URL used at login time.
Local generation:
swift run -c release media-generation-kit-cli generate \
--models-dir /tmp \
--prompt "a cat" \
--model "flux_2_klein_4b_q8p.ckpt" \
--width 1024 \
--height 1024 \
--num-inference-steps 4 \
--output /tmp/cat.pngImage-to-image:
swift run -c release media-generation-kit-cli generate \
--models-dir /tmp \
--prompt "a studio portrait" \
--model "flux_2_klein_4b_q8p.ckpt" \
--width 1024 \
--height 1024 \
--num-inference-steps 4 \
--image /tmp/input.png \
--strength 0.35 \
--output /tmp/portrait.pngRemote generation:
swift run -c release media-generation-kit-cli generate \
--remote \
--remote-url 127.0.0.1 \
--remote-port 7859 \
--remote-tls \
--prompt "a cat" \
--model "flux_2_klein_4b_q8p.ckpt" \
--width 1024 \
--height 1024 \
--num-inference-steps 4Draw Things cloud compute:
swift run -c release media-generation-kit-cli generate \
--cloud-compute \
--api-key "API_KEY" \
--prompt "a cat" \
--model "flux_2_klein_4b_q8p.ckpt" \
--width 1024 \
--height 1024 \
--num-inference-steps 4 \
--output /tmp/cat.pngSaved-login cloud compute:
swift run -c release media-generation-kit-cli auth login
swift run -c release media-generation-kit-cli generate \
--cloud-compute \
--prompt "a cat" \
--model "flux_2_klein_4b_q8p.ckpt" \
--width 1024 \
--height 1024 \
--num-inference-steps 4 \
--output /tmp/cat.pngGoogle browser sign-in:
swift run -c release media-generation-kit-cli auth loginGoogle browser sign-in against a non-default API host:
swift run -c release media-generation-kit-cli auth login \
--cloud-api-base-url "https://staging-api.drawthings.ai"Auth state validation:
swift run -c release media-generation-kit-cli auth state \
--api-key "API_KEY" \
--cloud-api-base-url "https://api.drawthings.ai"Auth token fetch:
swift run -c release media-generation-kit-cli auth token \
--api-key "API_KEY"Logout saved credentials:
swift run -c release media-generation-kit-cli auth logoutNotes:
auth stateandauth tokenmay omit--api-keyafterauth login.- If
auth loginused a custom--cloud-api-base-url, later saved-credential flows reuse that same API host unless explicitly overridden.
Catalog list:
swift run -c release media-generation-kit-cli models list \
--models-dir /tmpEnsure model files exist locally:
swift run -c release media-generation-kit-cli models ensure \
--models-dir /tmp \
--model "flux_2_klein_4b_q8p.ckpt"Inspect resolved model metadata:
swift run -c release media-generation-kit-cli models inspect \
--models-dir /tmp \
--model "hf://black-forest-labs/FLUX.2-klein-4B"Catalog behavior:
- The CLI uses the async
MediaGenerationEnvironmentcatalog APIs. generate,models list, andmodels inspectmay populate metadata from bundled or remote catalog data when needed.
Known gap:
models list-remoteis still exposed, but it intentionally fails because the current publicMediaGenerationKitAPI does not provide remote model listing yet.
Convert LoRA:
swift run -c release media-generation-kit-cli lora convert \
--input /path/to/my_lora.safetensors \
--output /tmp/my_lora_lora_f16.ckptConvert LoRA with derived output name in a chosen directory:
swift run -c release media-generation-kit-cli lora convert \
--input /path/to/my_lora.safetensors \
--output-dir /tmp \
--scale 0.8Upload converted LoRA:
swift run -c release media-generation-kit-cli lora upload \
--input /path/to/my_lora_lora_f16.ckpt \
--api-key "API_KEY"Saved-login upload variant:
swift run -c release media-generation-kit-cli auth login
swift run -c release media-generation-kit-cli lora upload \
--input /path/to/my_lora_lora_f16.ckptKnown gap:
storage infois still exposed, but it intentionally fails because the current publicMediaGenerationKitAPI does not provide storage inspection yet.
- Prefer running the built binary instead of
swift runwhen you need perfectly clean stdout. - Do not reintroduce positional models-directory arguments.
- Do not add separate
generate remoteorgenerate cloud-computesubcommands. - Do not document removed SDK types such as
GenerationPipeline,GenerationBackend,GenerationRequest,GenerationOptions, orCloudSession. - Do not reintroduce the removed legacy façade or the old internal runtime naming scheme into the public
MediaGenerationKitAPI.
MediaGenerationKit is distributed under LGPLv3.
For the public Swift package, the code and dependencies that cross over from
draw-things-community into the media-generation-kit distribution are relicensed under LGPLv3
as part of that package.
The intent of using LGPLv3 here is to encourage improvements to MediaGenerationKit and closely
related package code to be contributed back to MediaGenerationKit, not to force GPLv3-style
licensing onto downstream applications that use the package.