Skip to content

Commit fb50424

Browse files
authored
Added support for Flux Schnell Image generation using Fal.ai (#110)
1 parent 236092d commit fb50424

File tree

4 files changed

+169
-0
lines changed

4 files changed

+169
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
//
2+
// FalFluxSchnellInputSchema.swift
3+
//
4+
//
5+
// Created by Hunor Zoltáni on 01.03.2025.
6+
//
7+
8+
import Foundation
9+
10+
/// Docstrings taken from the tooltips here: https://fal.ai/models/fal-ai/flux/schnell
11+
public struct FalFluxSchnellInputSchema: Encodable {
12+
// Required
13+
14+
/// The prompt to generate an image from.
15+
public let prompt: String
16+
17+
// Optional
18+
19+
/// If set to true, the safety checker will be enabled. Default value: true
20+
public let enableSafetyChecker: Bool?
21+
22+
/// The size of the generated image.
23+
/// Default value: `.landscape4x3`
24+
public let imageSize: ImageSize?
25+
26+
/// The number of images to generate.
27+
/// Default value: `1`
28+
public let numImages: Int?
29+
30+
/// The number of inference steps to perform.
31+
/// Default value: `4`
32+
public let numInferenceSteps: Int?
33+
34+
/// The same seed and the same prompt given to the same version of the model will output the same image every time.
35+
public let seed: Int?
36+
37+
/// If set to true, the function will wait for the image to be generated and uploaded
38+
/// before returning the response. This will increase the latency of the function but it
39+
/// allows you to get the image directly in the response without going through the CDN.
40+
public let syncMode: Bool?
41+
42+
private enum CodingKeys: String, CodingKey {
43+
case enableSafetyChecker = "enable_safety_checker"
44+
case imageSize = "image_size"
45+
case numImages = "num_images"
46+
case numInferenceSteps = "num_inference_steps"
47+
case prompt
48+
case seed
49+
case syncMode = "sync_mode"
50+
}
51+
52+
// This memberwise initializer is autogenerated.
53+
// To regenerate, use `cmd-shift-a` > Generate Memberwise Initializer
54+
// To format, place the cursor in the initializer's parameter list and use `ctrl-m`
55+
public init(
56+
prompt: String,
57+
enableSafetyChecker: Bool? = nil,
58+
imageSize: FalFluxSchnellInputSchema.ImageSize? = nil,
59+
numImages: Int? = nil,
60+
numInferenceSteps: Int? = nil,
61+
seed: Int? = nil,
62+
syncMode: Bool? = nil
63+
) {
64+
self.prompt = prompt
65+
self.enableSafetyChecker = enableSafetyChecker
66+
self.imageSize = imageSize
67+
self.numImages = numImages
68+
self.numInferenceSteps = numInferenceSteps
69+
self.seed = seed
70+
self.syncMode = syncMode
71+
}
72+
73+
}
74+
75+
// MARK: - InputSchema.ImageSize
76+
extension FalFluxSchnellInputSchema {
77+
public enum ImageSize: String, Encodable {
78+
case landscape16x9 = "landscape_16_9"
79+
case landscape4x3 = "landscape_4_3"
80+
case portrait16x9 = "portrait_16_9"
81+
case portrait4x3 = "portrait_4_3"
82+
case square
83+
case squareHD = "square_hd"
84+
}
85+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
//
2+
// FalFluxSchnellOutputSchema.swift
3+
//
4+
//
5+
// Created by Hunor Zoltáni on 01.03.2025.
6+
//
7+
8+
import Foundation
9+
10+
public struct FalFluxSchnellOutputSchema: Decodable {
11+
public let hasNSFWConcepts: [Bool]?
12+
public let images: [FalOutputImage]?
13+
public let prompt: String?
14+
public let seed: UInt64?
15+
public let timings: FalTimings?
16+
17+
private enum CodingKeys: String, CodingKey {
18+
case hasNSFWConcepts = "has_nsfw_concepts"
19+
case images
20+
case prompt
21+
case seed
22+
case timings
23+
}
24+
}

Sources/AIProxy/Fal/FalService+Convenience.swift

+19
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,25 @@
88
import Foundation
99

1010
extension FalService {
11+
/// Convenience method for creating a `fal-ai/flux/schnell` image.
12+
///
13+
/// - Parameter input: The input schema. See `FalFluxSchnellInputSchema.swift` for the range of controls that you
14+
/// can use to adjust the image generation.
15+
///
16+
/// - Returns: The inference result. The `images` property of the returned value contains a list of
17+
/// generated images. Each image has a `url` that you can use to fetch the image contents
18+
/// (or use with AsyncImage)
19+
public func createFluxSchnellImage(
20+
input: FalFluxSchnellInputSchema
21+
) async throws -> FalFluxSchnellOutputSchema {
22+
return try await self.createInferenceAndPollForResult(
23+
model: "fal-ai/flux/schnell",
24+
input: input,
25+
pollAttempts: 60,
26+
secondsBetweenPollAttempts: 2
27+
)
28+
}
29+
1130
/// Convenience method for creating a `fal-ai/fast-sdxl` image.
1231
///
1332
/// - Parameter input: The input schema. See `FalFastSDXLInputSchema.swift` for the range of controls that you
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
//
2+
// FalFluxSchnellResponseTests.swift
3+
//
4+
//
5+
// Created by Hunor Zoltáni on 01.03.2025.
6+
//
7+
8+
import XCTest
9+
import Foundation
10+
@testable import AIProxy
11+
12+
final class FalFluxSchnellResponseTests: XCTestCase {
13+
14+
func testResponseIsDecodable() throws {
15+
let sampleResponse = """
16+
{
17+
"images": [
18+
{
19+
"url": "https://fal.media/files/zebra/_9NDmaWO5okNq9idPY7Il.jpeg",
20+
"width": 1024,
21+
"height": 1024,
22+
"content_type": "image/jpeg"
23+
}
24+
],
25+
"timings": {
26+
"inference": 2.1141920797526836
27+
},
28+
"seed": 2062765390712234200,
29+
"has_nsfw_concepts": [
30+
false
31+
],
32+
"prompt": "winter wonderland"
33+
}
34+
"""
35+
let res = try FalFluxSchnellOutputSchema.deserialize(from: sampleResponse)
36+
XCTAssertEqual(
37+
"https://fal.media/files/zebra/_9NDmaWO5okNq9idPY7Il.jpeg",
38+
res.images?.first?.url?.absoluteString
39+
)
40+
}
41+
}

0 commit comments

Comments
 (0)