ChatGPT를 이용한 앱을 만들기 위해서는 패키지에 대한 정보를 자세히 분석할 필요가 있습니다
https://github.com/MacPaw/OpenAI 에서는 OpenAI에서 공식으로 제공하는 ChatGPT API를 쉽게 사용할 수 있도록 만든 패키지입니다.
OpenAI API를 사용하여 다양한 작업을 수행하는 방법을 한글로 설명드리겠습니다. 여기서는 API 초기화, 완성 요청, 채팅 요청, 이미지 생성, 오디오 변환 등의 주요 기능을 다룹니다.
OpenAI 클래스 초기화
API를 사용하려면 먼저 OpenAI 클래스를 초기화해야 합니다. 다음은 API 토큰을 사용하여 클래스를 초기화하는 방법입니다:
let openAI = OpenAI(apiToken: "YOUR_TOKEN_HERE")
또는 조직 식별자와 타임아웃 간격을 포함하여 초기화할 수 있습니다
let configuration = OpenAI.Configuration(token: "YOUR_TOKEN_HERE", organizationIdentifier: "YOUR_ORGANIZATION_ID_HERE", timeoutInterval: 60.0)
let openAI = OpenAI(configuration: configuration)
여기까지 진행하였으면 이제 프롬프트를 통해서 ChatGPT에 질문할 준비가 완료됐습니다.
Completions
주어진 프롬프트에 대해 모델이 예측한 completion을 반환합니다. 다음은 Request 구조체와 Response 구조체입니다
Request 구조체
struct CompletionsQuery: Codable {
let model: Model
let prompt: String
let temperature: Double?
let maxTokens: Int?
let topP: Double?
let frequencyPenalty: Double?
let presencePenalty: Double?
let stop: [String]?
let user: String?
}
응답 구조체
struct CompletionsResult: Codable, Equatable {
struct Choice: Codable, Equatable {
let text: String
let index: Int
}
let id: String
let object: String
let created: TimeInterval
let model: Model
let choices: [Choice]
let usage: Usage
}
사용 예제
let query = CompletionsQuery(model: .textDavinci_003, prompt: "What is 42?", temperature: 0, maxTokens: 100, topP: 1, frequencyPenalty: 0, presencePenalty: 0, stop: ["\\n"])
openAI.completions(query: query) { result in
//Handle result here
}
//or
let result = try await openAI.completions(query: query)
Request에 대한 Response 예제
(lldb) po result
▿ CompletionsResult
- id : "cmpl-6P9be2p2fQlwB7zTOl0NxCOetGmX3"
- object : "text_completion"
- created : 1671453146.0
- model : OpenAI.Model.textDavinci_003
▿ choices : 1 element
▿ 0 : Choice
- text : "\n\n42 is the answer to the ultimate question of life, the universe, and everything, according to the book The Hitchhiker\'s Guide to the Galaxy."
- index : 0
Completions Streaming
Completions streaming은 completionsStream 함수를 통해서 사용 가능합니다. 결과로 Token들은 하나씩 전달받습니다.
이것은 마치 Chat GPT를 사용할 때 질문시 답을 한번에 보여주지 않고 스트리밍 형태로 값을 하나씩 반환하는 것을 의미합니다.
Closures
openAI.completionsStream(query: query) { partialResult in
switch partialResult {
case .success(let result):
print(result.choices)
case .failure(let error):
//Handle chunk error here
}
} completion: { error in
//Handle streaming error here
}
Combine
openAI
.completionsStream(query: query)
.sink { completion in
//Handle completion result here
} receiveValue: { result in
//Handle chunk here
}.store(in: &cancellables)
Structured concurrency
for try await result in openAI.completionsStream(query: query) {
//Handle result here
}
채팅 (Chats)
OpenAI의 gpt-3.5-turbo 모델을 사용하여 다음과 같은 기능을 하는 대화형 애플리케이션을 만들 수 있습니다
- 이메일 초안을 작성시키기
- Python 코드 짜기
- 문서에 대한 질문 응답
- 대화형 에이전트 생성
- 스프트웨어에 자연어 인터페이스 추가
- 다양한 주제에 대한 튜터
- 언어 번역
Request 구조체
struct ChatQuery: Codable {
/// 사용할 모델의 ID. 현재는 gpt-3.5-turbo와 gpt-3.5-turbo-0301만 지원됩니다.
public let model: Model
/// 채팅 완료를 생성할 메시지들
public let messages: [Chat]
/// 모델이 JSON 입력을 생성할 수 있는 함수 목록.
public let functions: [ChatFunctionDeclaration]?
/// 사용할 샘플링 온도, 0에서 2 사이의 값. 0.8과 같은 높은 값은 출력을 더 무작위적으로 만들고, 0.2와 같은 낮은 값은 출력을 더 집중되게 만듭니다. 일반적으로 이 값이나 top_p를 변경하는 것이 좋습니다.
public let temperature: Double?
/// 샘플링 온도 대신 사용할 수 있는 선택적 샘플링 방법으로, nucleus 샘플링이라고 합니다. top_p 확률 질량을 가진 토큰의 결과를 모델이 고려합니다. 예를 들어, 0.1은 상위 10% 확률 질량을 구성하는 토큰만 고려함을 의미합니다.
public let topP: Double?
/// 각 입력 메시지에 대해 생성할 채팅 완료 선택의 수.
public let n: Int?
/// API가 더 이상 토큰을 생성하지 않을 최대 4개의 시퀀스. 반환된 텍스트는 중지 시퀀스를 포함하지 않습니다.
public let stop: [String]?
/// 완료에서 생성할 최대 토큰 수.
public let maxTokens: Int?
/// -2.0에서 2.0 사이의 숫자. 양의 값은 텍스트에 등장한 새로운 토큰을 기반으로 모델의 새로운 주제에 대해 이야기할 가능성을 높입니다.
public let presencePenalty: Double?
/// -2.0에서 2.0 사이의 숫자. 양의 값은 텍스트에 이미 존재하는 빈도를 기반으로 새로운 토큰을 벌칙합니다. 이는 모델이 동일한 내용을 반복할 가능성을 줄입니다.
public let frequencyPenalty: Double?
/// 특정 토큰이 완료에 나타날 가능성을 수정합니다.
public let logitBias: [String: Int]?
/// OpenAI가 남용을 모니터링하고 감지하는 데 도움이 될 수 있는 고유한 최종 사용자 식별자.
public let user: String?
}
Response 구조체
struct ChatResult: Codable, Equatable {
struct Choice: Codable, Equatable {
let index: Int
let message: Chat
let finishReason: String
}
struct Usage: Codable, Equatable {
let promptTokens: Int
let completionTokens: Int
let totalTokens: Int
}
let id: String
let object: String
let created: TimeInterval
let model: Model
let choices: [Choice]
let usage: Usage
}
사용 예제
let query = ChatQuery(messages: [.init(role: .user, content: "who are you")!], model: .gpt3_5Turbo)
let result = try await openAIClient.chats(query: query)
반환 결과
ChatResult(id: "chatcmpl-9SSz6jOTcG65qnFkUzlh4ngVAThmM",
object: "chat.completion",
created: 1716571628.0,
model: "gpt-3.5-turbo-0125",
choices: [OpenAI.ChatResult.Choice(index: 0,
logprobs: nil,
message: OpenAI.ChatQuery.ChatCompletionMessageParam.assistant(OpenAI.ChatQuery.ChatCompletionMessageParam.ChatCompletionAssistantMessageParam(role: OpenAI.ChatQuery.ChatCompletionMessageParam.Role.assistant,
content: Optional("I am a virtual assistant here to help you with any questions or tasks you may have. How can I assist you today?"),
name: nil, toolCalls: nil)),
finishReason: Optional("stop"))
],
usage: Optional(OpenAI.ChatResult.CompletionUsage(completionTokens: 25,
promptTokens: 10, totalTokens: 35)),
systemFingerprint: nil)
Chat Streaming
chatStream을 이용하면 채팅을 응답을 스트리밍 형식으로 받을 수도 있습니다.
Closure
openAI.chatsStream(query: query) { partialResult in
switch partialResult {
case .success(let result):
print(result.choices)
case .failure(let error):
//Handle chunk error here
}
} completion: { error in
//Handle streaming error here
}
Combine
openAI
.chatsStream(query: query)
.sink { completion in
//Handle completion result here
} receiveValue: { result in
//Handle chunk here
}.store(in: &cancellables)
Structured concurrency
for try await result in openAI.chatsStream(query: query) {
//Handle result here
}
Function calls
let openAI = OpenAI(apiToken: "...")
// Declare functions which GPT-3 might decide to call.
let functions = [
ChatFunctionDeclaration(
name: "get_current_weather",
description: "Get the current weather in a given location",
parameters:
JSONSchema(
type: .object,
properties: [
"location": .init(type: .string, description: "The city and state, e.g. San Francisco, CA"),
"unit": .init(type: .string, enumValues: ["celsius", "fahrenheit"])
],
required: ["location"]
)
)
]
let query = ChatQuery(
model: "gpt-3.5-turbo-0613", // 0613 is the earliest version with function calls support.
messages: [
Chat(role: .user, content: "What's the weather like in Boston?")
],
functions: functions
)
let result = try await openAI.chats(query: query)
응답 결과
{
"id": "chatcmpl-1234",
"object": "chat.completion",
"created": 1686000000,
"model": "gpt-3.5-turbo-0613",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"function_call": {
"name": "get_current_weather",
"arguments": "{\n \"location\": \"Boston, MA\"\n}"
}
},
"finish_reason": "function_call"
}
],
"usage": { "total_tokens": 100, "completion_tokens": 18, "prompt_tokens": 82 }
}
이미지 생성 (Images)
주어진 프롬프트나 입력 이미지를 기반으로 새 이미지를 생성합니다.
이미지 생성 Request
struct ImagesQuery: Codable {
/// A text description of the desired image(s). The maximum length is 1000 characters.
public let prompt: String
/// The number of images to generate. Must be between 1 and 10.
public let n: Int?
/// The size of the generated images. Must be one of 256x256, 512x512, or 1024x1024.
public let size: String?
}
이미지 생성 Response
struct ImagesResult: Codable, Equatable {
public struct URLResult: Codable, Equatable {
public let url: String
}
public let created: TimeInterval
public let data: [URLResult]
}
이미지 요청 예제 코드
let query = ImagesQuery(prompt: "White cat with heterochromia sitting on the kitchen table", n: 1, size: "1024x1024")
openAI.images(query: query) { result in
//Handle result here
}
//or
let result = try await openAI.images(query: query)
이미지 요청 결과
(lldb) po result
▿ ImagesResult
- created : 1671453505.0
▿ data : 1 element
▿ 0 : URLResult
- url : "https://oaidalleapiprodscus.blob.core.windows.net/private/org-CWjU5cDIzgCcVjq10pp5yX5Q/user-GoBXgChvLBqLHdBiMJBUbPqF/img-WZVUK2dOD4HKbKwW1NeMJHBd.png?st=2022-12-19T11%3A38%3A25Z&se=2022-12-19T13%3A38%3A25Z&sp=r&sv=2021-08-06&sr=b&rscd=inline&rsct=image/png&skoid=6aaadede-4fb3-4698-a8f6-684d7786b067&sktid=a48cca56-e6da-484e-a814-9c849652bcb3&skt=2022-12-19T09%3A35%3A16Z&ske=2022-12-20T09%3A35%3A16Z&sks=b&skv=2021-08-06&sig=mh52rmtbQ8CXArv5bMaU6lhgZHFBZz/ePr4y%2BJwLKOc%3D"
생성된 이미지
다른 버전으로 이미지 생성하기
다음은 2024년 5월 26일 기준으로 가장 최신 버전인 dall_e_3 버전으로 이미지를 최고 해상도로 만들어내는 코드입니다. 기본 모델로는 dall_e_2를 사용하지만 dall_e_2 버전은 한글을 제대로 이해하지 못하는 모습을 보이고 있어 한글 prompt를 사용하여 이미지를 정확하게 생성하기 위해서는 dall_e_3 버전을 사용해야 합니다, 추가로 측정 결과 대략 한번 요청할 때마다 0.08$ 정도 소요됩니다.
let query = ImagesQuery(prompt: messages, model: .dall_e_3,n: 1, size: ._1792_1024)
let result = try? await openAIClient.images(query: query)
이미지 수정하기
주어진 프롬프트와 만들어진 이미지로 이미지를 수정하거나 확장할 수 있습니다.
이미지 수정 Request
public struct ImageEditsQuery: Codable {
/// The image to edit. Must be a valid PNG file, less than 4MB, and square. If mask is not provided, image must have transparency, which will be used as the mask.
public let image: Data
public let fileName: String
/// An additional image whose fully transparent areas (e.g. where alpha is zero) indicate where image should be edited. Must be a valid PNG file, less than 4MB, and have the same dimensions as image.
public let mask: Data?
public let maskFileName: String?
/// A text description of the desired image(s). The maximum length is 1000 characters.
public let prompt: String
/// The number of images to generate. Must be between 1 and 10.
public let n: Int?
/// The size of the generated images. Must be one of 256x256, 512x512, or 1024x1024.
public let size: String?
}
이미지 수정 Response
이미지 수정 Response로는 ImagesQuery와 유사하게 ImagesResult 응답을 사용합니다.
이미지 수정 예제 코드
let data = image.pngData()
let query = ImageEditQuery(image: data, fileName: "whitecat.png", prompt: "White cat with heterochromia sitting on the kitchen table with a bowl of food", n: 1, size: "1024x1024")
openAI.imageEdits(query: query) { result in
//Handle result here
}
//or
let result = try await openAI.imageEdits(query: query)
오디오 변환 (Audio Transcriptions & Translations)
오디오를 텍스트로 변환하거나 번역합니다.
응답 오디오로 받기
사용자가 Query로 요청에 대해서 응답을 오디오 말하기를 통해서 응답합니다.
응답 오디오로 받는 Request
public struct AudioSpeechQuery: Codable, Equatable {
//...
public let model: Model // tts-1 or tts-1-hd
public let input: String
public let voice: AudioSpeechVoice
public let responseFormat: AudioSpeechResponseFormat
public let speed: String? // Initializes with Double?
//...
}
응답 오디오로 받는 Response
/// Audio data for one of the following formats :`mp3`, `opus`, `aac`, `flac`
public let audioData: Data?
응답 오디오로 받는 예제 코드
let query = AudioSpeechQuery(model: .tts_1, input: "Hello, world!", voice: .alloy, responseFormat: .mp3, speed: 1.0)
openAI.audioCreateSpeech(query: query) { result in
// Handle response here
}
//or
let result = try await openAI.audioCreateSpeech(query: query)
오디오를 텍스트로 변역
Request 구조체
public struct AudioTranscriptionQuery: Codable, Equatable {
public let file: Data
public let fileName: String
public let model: Model
public let prompt: String?
public let temperature: Double?
public let language: String?
}
Response 구조체
public struct AudioTranscriptionResult: Codable, Equatable {
let text: String
}
사용 예시
let data = Data(contentsOfURL:...)
let query = AudioTranscriptionQuery(file: data, fileName: "audio.m4a", model: .whisper_1)
openAI.audioTranscriptions(query: query) { result in
//Handle result here
}
//or
let result = try await openAI.audioTranscriptions(query: query)
오디오를 영어로 변역하기
Request
public struct AudioTranslationQuery: Codable, Equatable {
public let file: Data
public let fileName: String
public let model: Model
public let prompt: String?
public let temperature: Double?
}
Response
public struct AudioTranslationResult: Codable, Equatable {
public let text: String
}
예제 코드
let data = Data(contentsOfURL:...)
let query = AudioTranslationQuery(file: data, fileName: "audio.m4a", model: .whisper_1)
openAI.audioTranslations(query: query) { result in
//Handle result here
}
//or
let result = try await openAI.audioTranslations(query: query)
사용 가능한 모델 종류
public extension Model {
static let gpt4_turbo_preview = "gpt-4-turbo-preview"
static let gpt4_vision_preview = "gpt-4-vision-preview"
static let gpt4_0125_preview = "gpt-4-0125-preview"
static let gpt4_1106_preview = "gpt-4-1106-preview"
static let gpt4 = "gpt-4"
static let gpt4_0613 = "gpt-4-0613"
static let gpt4_0314 = "gpt-4-0314"
static let gpt4_32k = "gpt-4-32k"
static let gpt4_32k_0613 = "gpt-4-32k-0613"
static let gpt4_32k_0314 = "gpt-4-32k-0314"
static let gpt3_5Turbo = "gpt-3.5-turbo"
static let gpt3_5Turbo_0125 = "gpt-3.5-turbo-0125"
static let gpt3_5Turbo_1106 = "gpt-3.5-turbo-1106"
static let gpt3_5Turbo_0613 = "gpt-3.5-turbo-0613"
static let gpt3_5Turbo_0301 = "gpt-3.5-turbo-0301"
static let gpt3_5Turbo_16k = "gpt-3.5-turbo-16k"
static let gpt3_5Turbo_16k_0613 = "gpt-3.5-turbo-16k-0613"
static let textDavinci_003 = "text-davinci-003"
static let textDavinci_002 = "text-davinci-002"
static let textCurie = "text-curie-001"
static let textBabbage = "text-babbage-001"
static let textAda = "text-ada-001"
static let textDavinci_001 = "text-davinci-001"
static let codeDavinciEdit_001 = "code-davinci-edit-001"
static let tts_1 = "tts-1"
static let tts_1_hd = "tts-1-hd"
static let whisper_1 = "whisper-1"
static let dall_e_2 = "dall-e-2"
static let dall_e_3 = "dall-e-3"
static let davinci = "davinci"
static let curie = "curie"
static let babbage = "babbage"
static let ada = "ada"
static let textEmbeddingAda = "text-embedding-ada-002"
static let textSearchAda = "text-search-ada-doc-001"
static let textSearchBabbageDoc = "text-search-babbage-doc-001"
static let textSearchBabbageQuery001 = "text-search-babbage-query-001"
static let textEmbedding3 = "text-embedding-3-small"
static let textEmbedding3Large = "text-embedding-3-large"
static let textModerationStable = "text-moderation-stable"
static let textModerationLatest = "text-moderation-latest"
static let moderation = "text-moderation-007"
}
'SwiftUI' 카테고리의 다른 글
Sendable 프로토콜 (0) | 2024.05.25 |
---|---|
AsyncPublisher (.value로 비동기적으로 데이터 처리) (0) | 2024.05.25 |
Global Actor과 Main Actor (0) | 2024.05.24 |
Actor (0) | 2024.05.21 |
Value Type, Reference Type, Stack, Heap, Struct, Class 사용되는 상황들, @StateObject 가 클래스여야 하는 이유 (0) | 2024.05.20 |