Skip to content

Commit

Permalink
Add create generation method for LumaAI
Browse files Browse the repository at this point in the history
  • Loading branch information
rudrankriyam committed Oct 13, 2024
1 parent fa5a627 commit 6e5a584
Show file tree
Hide file tree
Showing 3 changed files with 140 additions and 0 deletions.
16 changes: 16 additions & 0 deletions Sources/ShipinKit/LumaAI/LumaAIError.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
//
// LumaAIError.swift
// ShipinKit
//
// Created by Rudrank Riyam on 10/13/24.
//



/// An error type representing errors from the Luma AI client.
public enum LumaAIError: Error {
/// An HTTP error with a status code.
case httpError(statusCode: Int)
/// A decoding error occurred.
case decodingError(underlying: Error)
}
58 changes: 58 additions & 0 deletions Sources/ShipinKit/LumaAI/LumaAIGenerationResponse.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
//
// LumaAIGenerationResponse.swift
// ShipinKit
//
// Created by Rudrank Riyam on 10/13/24.
//

import Foundation

/// Represents the response from the Luma AI generation API.
public struct LumaAIGenerationResponse: Codable {
public let id: String
public let state: String
public let failureReason: String?
public let createdAt: String
public let assets: LumaAIAssets
public let version: String
public let request: LumaAIGenerationRequest

enum CodingKeys: String, CodingKey {
case id
case state
case failureReason = "failure_reason"
case createdAt = "created_at"
case assets
case version
case request
}
}

/// Contains the assets returned by the Luma AI generation API.
public struct LumaAIAssets: Codable {
public let video: String
}

/// Represents the original request sent to the Luma AI generation API.
public struct LumaAIGenerationRequest: Codable {
public let prompt: String
public let aspectRatio: String
public let loop: Bool
public let keyframes: [String: LumaAIKeyframeData]
public let callbackURL: String?

enum CodingKeys: String, CodingKey {
case prompt
case aspectRatio = "aspect_ratio"
case loop
case keyframes
case callbackURL = "callback_url"
}
}

/// Represents keyframe data in the generation request.
public struct LumaAIKeyframeData: Codable {
public let type: String
public let url: String?
public let id: String?
}
66 changes: 66 additions & 0 deletions Sources/ShipinKit/LumaAIClient.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
//
// LumaAIClient.swift
// ShipinKit
//
// Created by Rudrank Riyam on 10/13/24.
//

import Foundation

/// A client for interacting with the Luma AI API.
public class LumaAIClient {
private let apiKey: String
private let session: URLSession
private let baseURL = URL(string: "https://api.lumalabs.ai")!

/// Initializes a new instance of `LumaAIClient`
///
/// - Parameters:
/// - apiKey: Your Luma AI API key.
/// - session: The URLSession to use for network requests. Defaults to `URLSession.shared`.
public init(apiKey: String, session: URLSession = .shared) {
self.apiKey = apiKey
self.session = session
}

/// Initiates a generation request to the Luma AI API.
///
/// - Parameters:
/// - prompt: The prompt for the generation.
/// - aspectRatio: The aspect ratio of the generated content. Defaults to "16:9".
/// - loop: Whether the generated content should loop.
/// - keyframes: A dictionary of keyframes.
/// - callbackURL: The callback URL to receive generation updates.
///
/// - Returns: A `GenerationResponse` containing the result of the generation.
public func createGeneration(prompt: String, aspectRatio: String = "16:9", loop: Bool, keyframes: [String: LumaAIKeyframeData], callbackURL: String? = nil) async throws -> LumaAIGenerationResponse {
let url = baseURL.appendingPathComponent("/dream-machine/v1/generations")
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.timeoutInterval = 10
request.addValue("application/json", forHTTPHeaderField: "accept")
request.addValue("application/json", forHTTPHeaderField: "content-type")
request.addValue("Bearer \(apiKey)", forHTTPHeaderField: "authorization")

let requestBody = LumaAIGenerationRequest(prompt: prompt, aspectRatio: aspectRatio, loop: loop, keyframes: keyframes, callbackURL: callbackURL)
let encoder = JSONEncoder()
encoder.keyEncodingStrategy = .convertToSnakeCase
let bodyData = try encoder.encode(requestBody)
request.httpBody = bodyData

let (data, response) = try await session.data(for: request)

if let httpResponse = response as? HTTPURLResponse, !(200...299).contains(httpResponse.statusCode) {
throw LumaAIError.httpError(statusCode: httpResponse.statusCode)
}

let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
do {
let generationResponse = try decoder.decode(LumaAIGenerationResponse.self, from: data)
return generationResponse
} catch {
throw LumaAIError.decodingError(underlying: error)
}
}
}

0 comments on commit 6e5a584

Please sign in to comment.