본문 바로가기

프로젝트/Image Generator (w∕OpenAI)

02. 기능 구현 #1

기능 구현 #1
OpenAiKit


OpenAIKit
| APIKey 생성

간단한 회원가입을 하고, 'View API Keys'를 선택한다.

화면에 표시되는 'Create new secret key' 버튼을 눌러 API Key를 생성하면 되는데,
이후 표시되는 안내창에 적혀있듯 확인창을 닫으면 Key는 더 이상 확인 할 수 있는 방법이 없다.
따라서 닫기 전에 복사 할 수 있도록 하고, 메모장 등에 적어 놓도록 하자.

OpenAiKit
| Import

Swift Package Manager를 사용해 Package를 추가한다.

 

GitHub - MarcoDotIO/OpenAIKit: Swift Package for OpenAI's API

Swift Package for OpenAI's API. Contribute to MarcoDotIO/OpenAIKit development by creating an account on GitHub.

github.com

Git에 적혀있는 Url을 그대로 우측 상단의 검색창에 붙여 넣으면 된다.

정상적으로 프로젝트에 추가 됐다면 Package Dependencies에 OpenAIKit이 표시된다.

OpenAiKit
| Initializing

import OpenAIKit
import SwiftUI

final class ViewModel: ObservableObject {
    private var openai: OpenAI?

    func setup() {
        openai = OpenAI(Configuration(organization: "[organization]", apiKey: "[apiKey]"))
    }
}

OpenAiKit을 import하고 initializing을 진행한다.
해당 과정에서 organization과 apiKey가 필요한데 이 둘은 OpenAI 홈페이지에서 생성한 데이터를 문자열로 전달한다.

OpenAiKit
| generateImage

final class ViewModel: ObservableObject {
    private var openai: OpenAI?

    func setup() {
        openai = OpenAI(Configuration(organization: "[organization]", apiKey: "[apiKey]"))
    }

    func generateImage(prompt: String) async -> UIImage? {
        guard let openai = openai else {
            return nil
        }
    }
}

키워드를 입력 받아 이미지를 생성하는 generateImage 메서드를 구현한다.
입력 파라미터는 키워드에 해당하는 문자열이고, 반환 값은 optional UIImage 데이터다.

메서드가 동작 하기에 앞서 OpenAI가 제대로 초기화 됐는지 확인한다.

final class ViewModel: ObservableObject {
    private var openai: OpenAI?

    func setup() {
        openai = OpenAI(Configuration(organization: "[organization]", apiKey: "[apiKey]"))
    }

    func generateImage(prompt: String) async -> UIImage? {
        guard let openai = openai else {
            return nil
        }

        do {
            
        } catch {
            print(String(describing: error))
            return nil
        }
    }
}

앱 내에서 진행되는 것이 아닌 OpenAI의 서버와 통신을 하는 형태로 작업이 진행되기 때문에
async를 사용했고, 이에 따른 오류에 대응할 수 있도록 do-catch 패턴을 사용한다.
만약 작업이 제대로 진행되지 않는다면, 콘솔에 에러를 출력하고 nil을 반환한다.

final class ViewModel: ObservableObject {
    private var openai: OpenAI?

    func setup() {
        openai = OpenAI(Configuration(organization: "[organization]", apiKey: "[apiKey]"))
    }

    func generateImage(prompt: String) async -> UIImage? {
        guard let openai = openai else {
            return nil
        }

        do {
            let params = ImageParameters(prompt: prompt, resolution: .medium, responseFormat: .base64Json)
        } catch {
            print(String(describing: error))
            return nil
        }
    }
}

전달 받은 문자열을 사용해 ImageParameters 객체를 생성한다.
사용한 파라미터는 아래와 같다.

  • prompt
    키워드에 해당하는 문자열이다.
  • resolution
    생성할 이미지의 크기를 설정한다.
    small, medium, large 중 medium을 사용했다.
  • responseFormat
    반환받을 데이터의 형식을 지정한다.
    url과 base64 중 하나를 선택할 수 있다.
    Sample 코드와 같이 base64를 사용했다.
final class ViewModel: ObservableObject {
    private var openai: OpenAI?

    func setup() {
        openai = OpenAI(Configuration(organization: "[organization]", apiKey: "[apiKey]"))
    }

    func generateImage(prompt: String) async -> UIImage? {
        guard let openai = openai else {
            return nil
        }

        do {
            let params = ImageParameters(prompt: prompt, resolution: .medium, responseFormat: .base64Json)
            let result = try await openai.createImage(parameters: params)

        } catch {
            print(String(describing: error))
            return nil
        }
    }
}

결과는 초기화 된 openai의 createImage 메서드에 ImageParameters 객체를 전달해 반환받는다.
이미지 생성은 상대적으로 오래 걸리는 작업이기에 비동기 처리의 async를 위한 aswait가 여기서 등장한다.

final class ViewModel: ObservableObject {
    private var openai: OpenAI?

    func setup() {
        openai = OpenAI(Configuration(organization: "[organization]", apiKey: "[apiKey]"))
    }

    func generateImage(prompt: String) async -> UIImage? {
        guard let openai = openai else {
            return nil
        }

        do {
            let params = ImageParameters(prompt: prompt, resolution: .medium, responseFormat: .base64Json)
            let result = try await openai.createImage(parameters: params)
            let data = result.data[0].image
            
        } catch {
            print(String(describing: error))
            return nil
        }
    }
}

반환받은 결과를 image로 분리하고,

final class ViewModel: ObservableObject {
    private var openai: OpenAI?

    func setup() {
        openai = OpenAI(Configuration(organization: "[organization]", apiKey: "[apiKey]"))
    }

    func generateImage(prompt: String) async -> UIImage? {
        guard let openai = openai else {
            return nil
        }

        do {
            let params = ImageParameters(prompt: prompt, resolution: .medium, responseFormat: .base64Json)
            let result = try await openai.createImage(parameters: params)
            let data = result.data[0].image
            let image = try openai.decodeBase64Image(data)

            return image
        } catch {
            print(String(describing: error))
            return nil
        }
    }
}

분리된 이미지는 base64로 encoding 돼 있기 때문에 다시 decoding을 진행해 이를 반환한다.

'프로젝트 > Image Generator (w∕OpenAI)' 카테고리의 다른 글

05. 인터페이스 디자인 #2  (0) 2022.12.28
04. 기능구현 #3  (0) 2022.12.28
03. 기능구현 #2  (0) 2022.12.27
01. 인터페이스 디자인 #1  (0) 2022.12.24
00. 시작하며  (0) 2022.12.23