Swift에서 GPT API 요청 보내기

Little_Machine_Human_·2025년 1월 22일

Swift에서 API요청을 보낼 일이 생겼다.

따라서 그에 관한 정리된 코드를 작성한다.

Request,Response 모델을 정의 & 에러 핸들링값을 enum으로 정의한다.


import Foundation

enum HTTP_ERROR_RESPONSE: Identifiable {
    case NetworkError, TimeOut, JsonDecodeErrorm, BASE64DecodeError, InvalidURL, ETC, NoneData
    var id: Self { self }
}
struct AiModel: Decodable {
    let openai: String
}

struct ChatGPTResponse: Codable {
    let choices: [Choice]
}

struct Choice: Codable {
    let message: GPTMessage
}

struct GPTMessage: Codable {
    let content: String
}

struct Message: Identifiable, Equatable {
    let id = UUID()
    let content: String
    let isUser: Bool
    
    static func == (lhs: Message, rhs: Message) -> Bool {
        return lhs.content == rhs.content &&
               lhs.isUser == rhs.isUser
    }
}

        

URL session으로 요청 및 응답을 받는다.

// URL이 유효한지 확인
        guard let url = URL(string: urlString) else { // OpenAI URL
            //                updateError("Invalid URL")
            self.errorMessage = .InvalidURL
            self.isLoading = false
            return
        }
// HTTP 요청 설정
        var request = URLRequest(url: url)
        request.httpMethod = "POST"  // HTTP 메소드를 POST로 설정
        request.addValue("Bearer \(apiKey)", forHTTPHeaderField: "Authorization")  // 인증 헤더 추가 및 API키 추가
        request.addValue("application/json", forHTTPHeaderField: "Content-Type")  // Content-Type 헤더 설정
        request.timeoutInterval = 10  // 타임아웃 시간을 10초로 설정
        
        // 모델 이름 설정
        var modelName = ""
        if gptmodel {
            modelName = "gpt-4o-2024-11-20"  // GPT-4 모델 사용
        } else {
            modelName = "gpt-4o-mini"  // GPT-4 미니 모델 사용
        }
        // API 요청 본문 구성
        let requestBody: [String: Any] = [
            "model": modelName,
            "messages": [
                ["role": "system", "content": systemPrompt],  // 시스템 프롬프트
                ["role": "user", "content": userPrompt]       // 사용자 프롬프트
            ]
        ]
        
        // 타임아웃 작업 아이템 선언
        var timeoutWorkItem: DispatchWorkItem?
        
        do {
            // 요청 본문을 JSON 데이터로 변환
            let jsonData = try JSONSerialization.data(withJSONObject: requestBody)
            request.httpBody = jsonData
            
            // API 요청 태스크 생성
            let task = Task {
                do {
                    // API 요청 실행
                    let (data, response) = try await URLSession.shared.data(for: request)
                    
                    // 타임아웃 작업 취소
                    timeoutWorkItem?.cancel()
                    
                    // HTTP 응답 확인
                    guard let httpResponse = response as? HTTPURLResponse else {
                        timeoutWorkItem?.cancel()
                        DispatchQueue.main.async { [weak self] in
                            self?.isLoading = false
                            self?.errorMessage = .NetworkError
                        }
                        return
                    }
                    
                    // 응답 상태 코드가 200(성공)인 경우
                    if httpResponse.statusCode == 200 {
                        // JSON 응답 디코딩 및 처리
                        if let jsonResult = try? JSONDecoder().decode(ChatGPTResponse.self, from: data),
                           let responseContent = jsonResult.choices.first?.message.content {
                            DispatchQueue.main.async { [weak self] in
                                let botMessage = Message(content: responseContent, isUser: false)
                                self?.isLoading = false
                                self?.receimessages = botMessage.content
                            }
                        } else {
                            // JSON 디코딩 실패 처리
                            timeoutWorkItem?.cancel()
                            DispatchQueue.main.async { [weak self] in
                                self?.isLoading = false
                                self?.errorMessage = .JsonDecodeErrorm
                            }
                        }
                    } else {
                        // HTTP 오류 응답 처리
                        timeoutWorkItem?.cancel()
                        DispatchQueue.main.async { [weak self] in
                            self?.isLoading = false
                            self?.errorMessage = .NetworkError
                        }
                    }
                } catch URLError.timedOut {
                    // 타임아웃 오류 처리
                    timeoutWorkItem?.cancel()
                    DispatchQueue.main.async { [weak self] in
                        self?.isLoading = false
                        self?.errorMessage = .TimeOut
                    }
                } catch {
                    // 기타 오류 처리
                    timeoutWorkItem?.cancel()
                    DispatchQueue.main.async { [weak self] in
                        self?.isLoading = false
                        self?.errorMessage = .ETC
                    }
                }
            }
            
            // 타임아웃 처리를 위한 DispatchWorkItem 설정
            timeoutWorkItem = DispatchWorkItem { [weak self] in
                task.cancel()  // 태스크 취소
                DispatchQueue.main.async {
                    self?.isLoading = false
                    self?.errorMessage = .TimeOut
                }
            }
            
            // 10초 후에 타임아웃 작업 실행
            if let timeoutWorkItem = timeoutWorkItem {
                DispatchQueue.main.asyncAfter(deadline: .now() + 10, execute: timeoutWorkItem)
            }
            
        } catch {
            // JSON 직렬화 오류 처리
            timeoutWorkItem?.cancel()
            DispatchQueue.main.async { [weak self] in
                self?.isLoading = false
                self?.errorMessage = .JsonDecodeErrorm
            }
        }
profile
while(true){ 가족(); 건강(); 자기개발(); }

0개의 댓글