[SwiftUI] ChatGPT API를 활용한 서비스 구현하기
안녕하세요, 개발감자입니다!
항상 하는 " 뭐 먹지? "라는 고민을 해결하기 위해 음식 추천 서비스를 런칭 준비 중에 있습니다.
[DAY 1] 오늘 뭐 먹지? 내 고민을 해결해주는 앱, TODAY EATS
안녕하세요! 개발감자입니다! 항상 오늘 뭐 먹지? 고민하는 시간을 가집니다. 항상 이런 고민을 하는 저는 이 고민을 해결해주는 앱을 직접 만들어보기로 결심했습니다. 'TODAY EATS'는 매일 무엇을
qkrrmsdud.tistory.com
OpenAI의 ChatGPT API를 활용하여, 다양한 음식 메뉴 중 사용자의 취향에 맞는 음식을 추천해주는 기능을 구현하려고 합니다.
그래서 오늘은 Swift와 SwiftUI를 사용하여 iOS 앱 개발에 ChatGPT API를 연동하는 방법에 대해 이야기해보려고 합니다.
1. OpenAI API 키 준비하기
OpenAI
Introducing Sora: Creating video from text
openai.com
OpenAI 웹사이트에서 계정을 생성하고, ChatGPT API 키를 발급받습니다.
create new secret key > name 입력 > creat secret key 버튼 클릭 하면 Key 가 나옵니다. 이 키는 이때만 볼 수 있으므로 따로 메모해두셔야 합니다..!
2. SwiftUI 뷰 구성하기 (사용자의 선택 반영하는 경우)
SwiftUI를 사용해 앱의 UI를 구성합니다. ResultView는 사용자에게 추천 메뉴를 보여주는 뷰로, 사용자의 선택에 따라 다른 화면으로 네비게이션합니다. 여기서 selectionModel은 사용자가 원하는 선택을 저장하는 모델입니다.
@EnvironmentObject는 SwiftUI에서 사용하는 프로퍼티 래퍼로, 앱의 다양한 뷰들 사이에서 데이터를 공유할 때 사용됩니다. @EnvironmentObject를 사용하면, 데이터를 보유하고 있는 객체를 모든 뷰들이 접근할 수 있게 함으로써, 데이터의 일관성을 유지하고 코드의 중복을 줄일 수 있습니다.
struct ResultView: View {
@EnvironmentObject var selectionModel: SelectionModel
...
}
ResultView로 이동하기 전, 사용자는 자신이 원하는 음식의 종류, 맵기 등을 선택하는 뷰를 거치면서 차곡차곡 selectionModel에 자신의 선택을 저장합니다. 만약이 이러한 기능을 제공하지 않거나, 딱히 사용자의 입력값을 chatGPT에게 입력하지 않는 경우에는 3번부터 적용하셔도 괜찮습니다.
3. ChatGPT API 요청 구성하기
사용자의 입력과 앱의 상태에 따라 ChatGPT API에 요청을 보내는 함수를 구현합니다.
요청 바디에는 사용자의 선호, 현재 날씨, 위치 등의 정보를 포함시킵니다.
시스템 메시지와 사용자 질문에 원하는 내용을 다시 집어넣으면 됩니다.
func fetchFoodRecommendation(custom: SelectionModel, completion: @escaping ([String]) -> Void) {
let customString = "\(custom.cuisine.joined(separator: ", ")), 매운 정도: \(custom.spicy), 기름진 정도: \(custom.oily), 장소: \(custom.place.joined(separator: ", ")), 날씨: \(custom.weather.joined(separator: ", "))"
let url = URL(string: "https://api.openai.com/v1/chat/completions")!
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.addValue("Bearer 위에서 발급받은 api key ", forHTTPHeaderField: "Authorization")
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
let body = [
"model": "gpt-4",
"messages": [
["role": "system", "content": "시스템 메시지"],
["role": "user", "content": "사용자 질문"]
],
"max_tokens": 20,
"temperature": 0.7
]
request.httpBody = try? JSONSerialization.data(withJSONObject: body, options: [])
URLSession.shared.dataTask(with: request) { data, response, error in
guard let data = data else {
print("No data in response: \(error?.localizedDescription ?? "Unknown error")")
return
}
do {
if let json = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any],
let choices = json["choices"] as? [[String: Any]],
let firstChoice = choices.first,
let message = firstChoice["message"] as? [String: Any],
let content = message["content"] as? String {
// 추천된 음식 목록을 파싱하여 반환
let recommendations = content.components(separatedBy: " ")
print(recommendations)
DispatchQueue.main.async {
completion(recommendations)
}
}
} catch {
print("Failed to decode JSON: \(error)")
}
}.resume()
}
4. 응답 처리 및 UI 업데이트
API로부터 받은 응답을 처리하여 사용자에게 추천 메뉴를 표시합니다. 응답에서 추천된 음식 목록을 파싱하고, 이를 ResultView의 버튼 타이틀로 업데이트합니다. 여기서 buttonTitles는 사용자에게 보여줄 메뉴를 저장하는 변수입니다. 이 부분은 변형하여 사용하시면 됩니다.
.onAppear {
fetchFoodRecommendation(custom: selectionModel) { foods in
self.buttonTitles = foods
}
}
5. 완성된 앱 테스트 및 디버깅
앱을 실제 디바이스나 시뮬레이터에서 실행하여 기능을 테스트합니다. ChatGPT API와의 통신이 정상적으로 이루어지는지, 사용자 입력에 따라 적절한 음식이 추천되는지 확인합니다. 생각보다 쉽죠? 제 포스팅이 도움이 되셨으면 좋겠습니다.
개발감자였습니다!