자연어 처리 (NLP) 기술을 접목한 iOS앱 개인 프로젝트를 구상하는 도중 요즘 핫한 chatGPT가 떠올랐다!
chatGPT를 이용한 서비스를 구현하기 위해 chatGPT API를 사용해보려고 한다.
chatGPT에게 질문을 던지고 대답을 받는 작업을 해보자
1. OpenAI API key 발급받기
아래 링크 의 우측 상단의 View API keys 메뉴로 들어가API key를 발급받는다.
OpenAI API key는 다시 볼 수 없으므로 잘 백업 해놓자!
2. Swift Package 추가
이제 Swift로 ChatGPT를 사용하기 위해 Package들을 추가해줘야 된다.
1. Swift Package Manager로 추가하기
- ChatGPT API를 사용할 프로젝트에서 File - Add Packages - 검색 창에 https://github.com/alfianlosari/ChatGPTSwift.git 입력 후 설치
2. Cocoapods를 이용해 추가하기
- terminal 창에서 해당 프로젝트 링크로 들어간다
- 'pod init' 명령어를 통해 Podfile을 생성해준다
- Podfile에 들어가 다음과 같이 수정하여 ChatGPTSwift를 설치해준다 (MyApp 대신 프로젝트 앱의 이름을 넣어줘야 한다)
platform :ios, '15.0'
use_frameworks!
target 'MyApp' do
pod 'ChatGPTSwift', '~> 1.3.1'
end
- 다시 terminal 창에서 'pod install' 명렁어로 해당 package를 설치한다
이제 , Swift로 ChatGPT API를 사용할 준비가 다 되었다.
3. API 활용하기
위의 깃허브 주소의 코드를 활용하여 구현해보았다.
우선 ChatGPTAPI key를 이용하여 ChatGPTAPI를 초기화해주었다.
또한 sendToChatGPT라는 함수를 생성하여 ChatGPTAPI에게 밥을 추천해달라는 질문을 던져보았다.
import Foundation
import ChatGPTSwift
// ChatGPTAPI를 활용할 함수를 가지고 있는 구조체
struct ChatGPTAPIHelper {
static let shared = ChatGPTAPIHelper()
let api = ChatGPTAPI(apiKey: "~~~~ChatGPTAPI key 입력~~~~")
func sendToChatGPT() {
Task {
do {
let answer = try await api.sendMessage(text: "내일 한식중에 밥 뭐 먹을지 추천해줘")
print(answer)
} catch {
print(error.localizedDescription)
}
}
}
}
뷰는 다음과 같이 구현하였다
import SwiftUI
import ChatGPTSwift
struct ChatGPTAPIView: View {
let manager = ChatGPTAPIHelper.shared
var body: some View {
Button("chatGPT에게 물어보기") {
manager.sendToChatGPT()
}
}
}
struct ChatGPTAPIView_Previews: PreviewProvider {
static var previews: some View {
ChatGPTAPIView()
}
}
chatGPT의 답변들이 잘 출력되는 것을 볼 수 있다.
Task
api에게 답변을 요청하는 작업은 Task {} 라는 클로저내에서 수행되었다.
그럼 Task는 무엇일까??
Task는 비동기 작업을 수행하는 하나의 유닛이다
- Task는 제네릭 구조체로, 인스턴스를 생성할 때 수행할 작업을 포함하는 클로저를 함께 제공함
- Task는 생성 직후 시작할 수 있으므로 따로 실행처리를 해줄 필요가 없음
- DispatchQueue 혹은 OperationQueue, Thread와 같은 키워드 없이 작성하면 기본적으로 main thread에서 동기적으로 동작
- Task { } 블록으로 감싸서 실행한다면 비동기적으로 수행할 수 있음
- sync 클로저 내부에서 async 함수를 호출하는 경우 사용
override func viewDidLoad() {
super.viewDidLoad()
Task {
await fetchItmes()
}
}
func fetchItmes() async {
}
- DispatchQueue 스레드와의 공통점은 임의의 스레드로 처리한다는 것
- 차이점은 Task{} 는 해당 블록을 만났을 때 코드가 대기하는 것 처럼 보이지만 내부적으로는 스레드가 block 되지 않고 다른 일을 처리할 수 있도록 효율적으로 설계되어 있음
- 반면에 DispatchQueue는 해당 Thread가 점유하고 일을 하고 있지 않으면 그 스레드는 block되어 다른 일을 처리하지 못함
sendMessage vs sendMessagesStream
위의 코드 예시에서는 sendMessage() 메서드를 이용해서 chatGPT에게 질문을 던졌다.
구현 영상에는 안 넣었지만 응답이 오는데 10초 이상의 시간이 걸렸다.
sendMessage를 사용하면 chatGPT가 모든 응답을 다 작성할 때까지 기다린 후 전체 문장을 반환해주기 때문에 많은 시간이 걸리고
어플에 사용하기에는 적합하지 않다.
sendMessagesStream으로 실행을 하면 다음과 같은 결과가 나온다.
이렇게 한 글자씩 비동기적으로 대답을 전달 받을 수 있다.
영어로 질문을 던져보니 정확히 한 단어씩 나눠서 출력되는 것을 보니 아직 한국어의 tokenizer가 정확하지 않은 것 같다.
이러한 응답을 앱에서 사용자에게 보여주기 위해서는 이러한 Stream을 처리하는 단계가 필요할 것 같다.
참고 글
'Project' 카테고리의 다른 글
[Toy Project] Account Book (0) | 2023.04.30 |
---|---|
[Toy Project] Caffeine Holic (0) | 2023.04.30 |