Community

๐Ÿค–iOS ์•ฑ์—์„œ OpenAI api์‚ฌ์šฉํ•˜๊ธฐ

๋งŽ์€ ์•ฑ ๊ฐœ๋ฐœ์ž๋“ค์€ iOS ํ”„๋กœ์ ํŠธ์—์„œ OpenAI API๋ฅผ ํšจ๊ณผ์ ์œผ๋กœ ํ™œ์šฉํ•˜๊ณ ์ž ๊ณ ๋ฏผํ•ฉ๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์ด๋Š” ์‰ฝ์ง€ ์•Š์€ ์ž‘์—…์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํŠนํžˆ ์•ฑ์˜ ๋ฐ์ดํ„ฐ ๋ ˆ์ด์–ด์™€ AI API๋ฅผ ํ†ตํ•ฉํ•  ๋•Œ ์—”์ง€๋‹ˆ์–ด๋ง ์›์น™์„ ์ž˜ ์ ์šฉํ•ด์•ผ ์•ˆ์ •์ ์ด๊ณ  ํšจ์œจ์ ์ธ ์•ฑ์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ค๋Š˜์€ Swift iOS์—์„œ OpenAI API๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ”„๋กฌํ”„ํŠธ ์—”์ง€๋‹ˆ์–ด๋ง์„ ํšจ๊ณผ์ ์œผ๋กœ ์ˆ˜ํ–‰ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์‚ดํŽด๋ณด๋ ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค. ### OpenAI API๋ž€? ๋จผ์ € OpenAI API์— ๋Œ€ํ•ด ๊ฐ„๋žตํ•˜๊ฒŒ ์„ค๋ช…ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. ์ด๋Š” ๊ฐœ๋ฐœ์ž๋“ค์ด OpenAI์˜ ๊ฐ•๋ ฅํ•œ ์ธ๊ณต์ง€๋Šฅ ๋ชจ๋ธ๋“ค์„ ์‰ฝ๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜๋Š” RESTful API์ž…๋‹ˆ๋‹ค. ์ด API๋Š” ํ…์ŠคํŠธ ์ƒ์„ฑ, ์–ธ์–ด ๋ฒˆ์—ญ, ๊ฐ์ • ๋ถ„์„ ๋“ฑ ๋‹ค์–‘ํ•œ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ### ํ”„๋กฌํ”„ํŠธ ์—”์ง€๋‹ˆ์–ด๋ง์ด๋ž€? ํ”„๋กฌํ”„ํŠธ ์—”์ง€๋‹ˆ์–ด๋ง์€ AI ๋ชจ๋ธ์—๊ฒŒ ํŠน์ • ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋„๋ก ์ง€์‹œํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์ตœ์ ํ™”ํ•˜๋Š” ๊ธฐ์ˆ ์ž…๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ์‚ฌ์šฉ์ž๊ฐ€ ์ž…๋ ฅํ•œ ๋‚ด์šฉ์„ ๊ธฐ๋ฐ˜์œผ๋กœ AI์—๊ฒŒ ์ ์ ˆํ•œ ์งˆ๋ฌธ์„ ๋˜์ง€๊ฑฐ๋‚˜, ํŠน์ • ๋ฐฉ์‹์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋„๋ก ์„ค์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ### ํ”„๋กœ์ ํŠธ์— OpenAI API ์ถ”๊ฐ€ํ•˜๊ธฐ ํ”„๋กœ์ ํŠธ์— OpenAI API๋ฅผ ํ†ตํ•ฉํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ๋ช‡ ๊ฐ€์ง€ ๋‹จ๊ณ„๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด JSON ์‘๋‹ต์„ ํšจ๊ณผ์ ์œผ๋กœ ์ฒ˜๋ฆฌํ•˜๊ณ , API ์š”์ฒญ๊ณผ ์‘๋‹ต์„ ๋น„๋™๊ธฐ์ ์œผ๋กœ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. #### 1. API ํด๋ผ์ด์–ธํŠธ ์„ค์ • ์šฐ์„  OpenAI API ํด๋ผ์ด์–ธํŠธ๋ฅผ ์„ค์ •ํ•˜๋Š” ์ฝ”๋“œ์ž…๋‹ˆ๋‹ค. ์ด๋Š” ๋„คํŠธ์›Œํฌ ์š”์ฒญ์„ ์ˆ˜ํ–‰ํ•˜๊ณ , API ์‘๋‹ต์„ ์ฒ˜๋ฆฌํ•˜๋Š” HTTP ํด๋ผ์ด์–ธํŠธ๋ฅผ ์„ค์ •ํ•˜๋Š” ๊ณผ์ •์ž…๋‹ˆ๋‹ค. ```swift public class OpenAIClient { ย  ย  private lazy var httpClient: HTTPClient = { ย  ย  ย  ย  URLSessionHTTPClient(session: URLSession(configuration: .ephemeral)) ย  ย  }() ย ย  ย  ย  ย  private lazy var baseURL = URL(string: "")! ย  ย  private let configuration = URLSessionConfiguration.default ย ย  ย  ย  ย  init() { ย  ย  ย  ย  self.configuration.timeoutIntervalForRequest = 10.0 ย  ย  ย  ย  self.configuration.timeoutIntervalForResource = 10.0 ย  ย  } ย ย  ย  ย  ย  public func sendRequest(endpoint: OpenAIEndpoint) -> AnyPublisher { ย  ย  ย  ย  guard let urlRequest = endpoint.url(baseURL: self.baseURL) else { ย  ย  ย  ย  ย  ย  return Empty(completeImmediately: false).eraseToAnyPublisher() ย  ย  ย  ย  } ย ย  ย  ย  ย  ย  ย  ย  ย  return httpClient.getPublisher(urlRequest: urlRequest) ย  ย  ย  ย  ย  ย  .tryMap(OpenAIMapper.map) ย  ย  ย  ย  ย  ย  .eraseToAnyPublisher() ย  ย  } } ์ด ํด๋ž˜์Šค๋Š” OpenAI API์˜ ๊ธฐ๋ณธ URL๊ณผ ํ•จ๊ป˜ HTTP ํด๋ผ์ด์–ธํŠธ๋ฅผ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค. API ์š”์ฒญ์— ๋Œ€ํ•œ ํƒ€์ž„์•„์›ƒ๋„ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค. sendRequest ๋ฉ”์†Œ๋“œ๋Š” API ํ˜ธ์ถœ์„ ์ˆ˜ํ–‰ํ•˜๊ณ , ์‘๋‹ต์„ Publisher ํ˜•ํƒœ๋กœ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. 2. ํ”„๋กฌํ”„ํŠธ ์—”์ง€๋‹ˆ์–ด๋ง ํ•จ์ˆ˜ ๊ตฌ์„ฑ ๋‹ค์Œ์œผ๋กœ OpenAI API์— ํ”„๋กฌํ”„ํŠธ๋ฅผ ์ „์†กํ•˜๊ณ  ์‘๋‹ต์„ ์ฒ˜๋ฆฌํ•˜๋Š” ์ฝ”๋“œ๋ฅผ ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. public func prompt(text: String, completion: @escaping (Result) -> Void) { ย  ย  let endpoint = OpenAIEndpoint.prompt(text: text) ย ย  ย  ย  ย  self.sendRequest(endpoint: endpoint).sink(receiveCompletion: { finish in ย  ย  ย  ย  if case let .failure(error) = finish { ย  ย  ย  ย  ย  ย  completion(.failure(error)) ย  ย  ย  ย  } ย  ย  }, receiveValue: { summary in ย  ย  ย  ย  let jsonString = summary.choices.first?.message.content ย  ย  ย  ย  guard let content = self.parseContent(jsonString) else { ย  ย  ย  ย  ย  ย  completion(.failure(MyError.invalidResponse)) ย  ย  ย  ย  ย  ย  return ย  ย  ย  ย  } ย ย  ย  ย  ย  ย  ย  ย  ย  let memo = Memo(content: content, createdAt: Date()) ย  ย  ย  ย  completion(.success(memo)) ย  ย  }).store(in: &self.cancellables) } private func parseContent(_ jsonString: String?) -> String? { ย  ย  guard let jsonString = jsonString, ย  ย  ย  ย  ย  let data = jsonString.data(using: .utf8), ย  ย  ย  ย  ย  let parsedContent = try? JSONDecoder().decode(String.self, from: data) else { ย  ย  ย  ย  return nil ย  ย  } ย  ย  return parsedContent } ์ด ํ•จ์ˆ˜๋Š” ์‚ฌ์šฉ์ž๊ฐ€ ์ž…๋ ฅํ•œ ํ”„๋กฌํ”„ํŠธ๋ฅผ OpenAI API๋กœ ์ „์†กํ•˜๊ณ , ๊ฒฐ๊ณผ๋ฅผ ๋ฐ›์•„ Memo๋ผ๋Š” ๊ฐ์ฒด๋กœ ๋ณ€ํ™˜ํ•ฉ๋‹ˆ๋‹ค. Memo๋Š” AI๊ฐ€ ์ƒ์„ฑํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ์•ฑ์—์„œ ์‚ฌ์šฉํ•˜๊ธฐ ํŽธ๋ฆฌํ•˜๊ฒŒ ๊ตฌ์กฐํ™”ํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ฝ”๋“œ ์„ค๋ช…๊ณผ ์ฃผ์˜ ์‚ฌํ•ญ ์œ„์˜ ์ฝ”๋“œ๋“ค์€ API ํ˜ธ์ถœ๊ณผ JSON ์‘๋‹ต ์ฒ˜๋ฆฌ๋ฅผ ๋งค์šฐ ๊ฐ„๋‹จํ•˜๊ฒŒ ๋งŒ๋“ค์–ด ์ค๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์‹ค์ œ ํ”„๋กœ์ ํŠธ์—์„œ๋Š” ๋‹ค์–‘ํ•œ ์˜ˆ์™ธ ์ƒํ™ฉ์„ ์ฒ˜๋ฆฌํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ๋„คํŠธ์›Œํฌ ์˜ค๋ฅ˜, ์„œ๋ฒ„ ์˜ค๋ฅ˜, JSON ํŒŒ์‹ฑ ์˜ค๋ฅ˜ ๋“ฑ์„ ๊ณ ๋ คํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ์˜ˆ์™ธ ์ƒํ™ฉ์„ ํšจ๊ณผ์ ์œผ๋กœ ์ฒ˜๋ฆฌํ•˜๋Š” ๊ฒƒ์ด ๊ฒฌ๊ณ ํ•œ ์•ฑ์„ ๋งŒ๋“œ๋Š” ๋ฐ ์ค‘์š”ํ•œ ์š”์†Œ์ž…๋‹ˆ๋‹ค. ๋˜ํ•œ ๋น„๋™๊ธฐ์ ์œผ๋กœ API ํ˜ธ์ถœ์„ ๊ด€๋ฆฌํ•˜๋Š” ๊ฒƒ์€ ๋งค์šฐ ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” ์ฃผ ์Šค๋ ˆ๋“œ๋ฅผ ์ฐจ๋‹จํ•˜์ง€ ์•Š๊ณ , ๋ฐฑ๊ทธ๋ผ์šด๋“œ์—์„œ ๋„คํŠธ์›Œํฌ ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•˜๋ฉฐ, ๊ฒฐ๊ณผ๋ฅผ ๋ฐ›์•„์™”์„ ๋•Œ UI๋ฅผ ์—…๋ฐ์ดํŠธํ•˜๋Š” ๋ฐ ๋„์›€์ด ๋ฉ๋‹ˆ๋‹ค. ๋งˆ๋ฌด๋ฆฌ ์˜ค๋Š˜์€ Swift iOS ํ”„๋กœ์ ํŠธ์—์„œ OpenAI API๋ฅผ ํšจ์œจ์ ์œผ๋กœ ์‚ฌ์šฉํ•˜์—ฌ ํ”„๋กฌํ”„ํŠธ ์—”์ง€๋‹ˆ์–ด๋ง์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์•Œ์•„๋ณด์•˜์Šต๋‹ˆ๋‹ค. ์ฝ”๋“œ ์˜ˆ์ œ์™€ ํ•จ๊ป˜ ๊ฐ ๋‹จ๊ณ„๋ณ„๋กœ ์„ธ๋ถ€ ์‚ฌํ•ญ์„ ์„ค๋ช…ํ–ˆ์œผ๋ฉฐ, ์ด๋ฅผ ํ†ตํ•ด ์—ฌ๋Ÿฌ๋ถ„์˜ ํ”„๋กœ์ ํŠธ์—์„œ๋„ OpenAI API๋ฅผ ํšจ๊ณผ์ ์œผ๋กœ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ํ”„๋กฌํ”„ํŠธ ์—”์ง€๋‹ˆ์–ด๋ง๊ณผ OpenAI API์˜ ์กฐํ•ฉ์€ ๊ฐ•๋ ฅํ•œ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•˜๋ฉฐ, ์ด๋ฅผ ํ†ตํ•ด ์‚ฌ์šฉ์ž ๊ฒฝํ—˜์„ ๊ทน๋Œ€ํ™”ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์•ž์œผ๋กœ๋„ ๋” ๋งŽ์€ ๊ธฐ๋Šฅ๋“ค์„ ์ถ”๊ฐ€ํ•˜๊ณ , ์ตœ์ ํ™”ํ•˜๋Š” ์ž‘์—…์„ ์ง€์†์ ์œผ๋กœ ์ˆ˜ํ–‰ํ•ด ๋‚˜๊ฐ€์‹œ๊ธฐ ๋ฐ”๋ž๋‹ˆ๋‹ค. ๋งŽ์€ ์•ฑ ๊ฐœ๋ฐœ์ž๋“ค์€ iOS ํ”„๋กœ์ ํŠธ์—์„œ OpenAI API๋ฅผ ํšจ๊ณผ์ ์œผ๋กœ ํ™œ์šฉํ•˜๊ณ ์ž ๊ณ ๋ฏผํ•ฉ๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์ด๋Š” ์‰ฝ์ง€ ์•Š์€ ์ž‘์—…์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํŠนํžˆ ์•ฑ์˜ ๋ฐ์ดํ„ฐ ๋ ˆ์ด์–ด์™€ AI API๋ฅผ ํ†ตํ•ฉํ•  ๋•Œ ์—”์ง€๋‹ˆ์–ด๋ง ์›์น™์„ ์ž˜ ์ ์šฉํ•ด์•ผ ์•ˆ์ •์ ์ด๊ณ  ํšจ์œจ์ ์ธ ์•ฑ์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ค๋Š˜์€ Swift iOS์—์„œ OpenAI API๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ”„๋กฌํ”„ํŠธ ์—”์ง€๋‹ˆ์–ด๋ง์„ ํšจ๊ณผ์ ์œผ๋กœ ์ˆ˜ํ–‰ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์‚ดํŽด๋ณด๋ ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค. ### OpenAI API๋ž€? ๋จผ์ € OpenAI API์— ๋Œ€ํ•ด ๊ฐ„๋žตํ•˜๊ฒŒ ์„ค๋ช…ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. ์ด๋Š” ๊ฐœ๋ฐœ์ž๋“ค์ด OpenAI์˜ ๊ฐ•๋ ฅํ•œ ์ธ๊ณต์ง€๋Šฅ ๋ชจ๋ธ๋“ค์„ ์‰ฝ๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜๋Š” RESTful API์ž…๋‹ˆ๋‹ค. ์ด API๋Š” ํ…์ŠคํŠธ ์ƒ์„ฑ, ์–ธ์–ด ๋ฒˆ์—ญ, ๊ฐ์ • ๋ถ„์„ ๋“ฑ ๋‹ค์–‘ํ•œ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ### ํ”„๋กฌํ”„ํŠธ ์—”์ง€๋‹ˆ์–ด๋ง์ด๋ž€? ํ”„๋กฌํ”„ํŠธ ์—”์ง€๋‹ˆ์–ด๋ง์€ AI ๋ชจ๋ธ์—๊ฒŒ ํŠน์ • ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋„๋ก ์ง€์‹œํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์ตœ์ ํ™”ํ•˜๋Š” ๊ธฐ์ˆ ์ž…๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ์‚ฌ์šฉ์ž๊ฐ€ ์ž…๋ ฅํ•œ ๋‚ด์šฉ์„ ๊ธฐ๋ฐ˜์œผ๋กœ AI์—๊ฒŒ ์ ์ ˆํ•œ ์งˆ๋ฌธ์„ ๋˜์ง€๊ฑฐ๋‚˜, ํŠน์ • ๋ฐฉ์‹์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋„๋ก ์„ค์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ### ํ”„๋กœ์ ํŠธ์— OpenAI API ์ถ”๊ฐ€ํ•˜๊ธฐ ํ”„๋กœ์ ํŠธ์— OpenAI API๋ฅผ ํ†ตํ•ฉํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ๋ช‡ ๊ฐ€์ง€ ๋‹จ๊ณ„๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด JSON ์‘๋‹ต์„ ํšจ๊ณผ์ ์œผ๋กœ ์ฒ˜๋ฆฌํ•˜๊ณ , API ์š”์ฒญ๊ณผ ์‘๋‹ต์„ ๋น„๋™๊ธฐ์ ์œผ๋กœ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ### 1. API ํด๋ผ์ด์–ธํŠธ ์„ค์ • ์šฐ์„  OpenAI API ํด๋ผ์ด์–ธํŠธ๋ฅผ ์„ค์ •ํ•˜๋Š” ์ฝ”๋“œ์ž…๋‹ˆ๋‹ค. ์ด๋Š” ๋„คํŠธ์›Œํฌ ์š”์ฒญ์„ ์ˆ˜ํ–‰ํ•˜๊ณ , API ์‘๋‹ต์„ ์ฒ˜๋ฆฌํ•˜๋Š” HTTP ํด๋ผ์ด์–ธํŠธ๋ฅผ ์„ค์ •ํ•˜๋Š” ๊ณผ์ •์ž…๋‹ˆ๋‹ค. ```swift public class OpenAIClient { ย  ย  private lazy var httpClient: HTTPClient = { ย  ย  ย  ย  URLSessionHTTPClient(session: URLSession(configuration: .ephemeral)) ย  ย  }() ย  ย  private lazy var baseURL = URL(string: "")! ย  ย  private let configuration = URLSessionConfiguration.default ย  ย  init() { ย  ย  ย  ย  self.configuration.timeoutIntervalForRequest = 10.0 ย  ย  ย  ย  self.configuration.timeoutIntervalForResource = 10.0 ย  ย  } ย  ย  public func sendRequest(endpoint: OpenAIEndpoint) -> AnyPublisher { ย  ย  ย  ย  guard let urlRequest = endpoint.url(baseURL: self.baseURL) else { ย  ย  ย  ย  ย  ย  return Empty(completeImmediately: false).eraseToAnyPublisher() ย  ย  ย  ย  } ย  ย  ย  ย  return httpClient.getPublisher(urlRequest: urlRequest) ย  ย  ย  ย  ย  ย  .tryMap(OpenAIMapper.map) ย  ย  ย  ย  ย  ย  .eraseToAnyPublisher() ย  ย  } } ์ด ํด๋ž˜์Šค๋Š” OpenAI API์˜ ๊ธฐ๋ณธ URL๊ณผ ํ•จ๊ป˜ HTTP ํด๋ผ์ด์–ธํŠธ๋ฅผ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค. API ์š”์ฒญ์— ๋Œ€ํ•œ ํƒ€์ž„์•„์›ƒ๋„ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค. sendRequest ๋ฉ”์†Œ๋“œ๋Š” API ํ˜ธ์ถœ์„ ์ˆ˜ํ–‰ํ•˜๊ณ , ์‘๋‹ต์„ Publisher ํ˜•ํƒœ๋กœ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. 2. ํ”„๋กฌํ”„ํŠธ ์—”์ง€๋‹ˆ์–ด๋ง ํ•จ์ˆ˜ ๊ตฌ์„ฑ ๋‹ค์Œ์œผ๋กœ OpenAI API์— ํ”„๋กฌํ”„ํŠธ๋ฅผ ์ „์†กํ•˜๊ณ  ์‘๋‹ต์„ ์ฒ˜๋ฆฌํ•˜๋Š” ์ฝ”๋“œ๋ฅผ ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. public func prompt(text: String, completion: @escaping (Result) -> Void) { ย  ย  let endpoint = OpenAIEndpoint.prompt(text: text) ย  ย  self.sendRequest(endpoint: endpoint).sink(receiveCompletion: { finish in ย  ย  ย  ย  if case let .failure(error) = finish { ย  ย  ย  ย  ย  ย  completion(.failure(error)) ย  ย  ย  ย  } ย  ย  }, receiveValue: { summary in ย  ย  ย  ย  let jsonString = summary.choices.first?.message.content ย  ย  ย  ย  guard let content = self.parseContent(jsonString) else { ย  ย  ย  ย  ย  ย  completion(.failure(MyError.invalidResponse)) ย  ย  ย  ย  ย  ย  return ย  ย  ย  ย  } ย  ย  ย  ย  let memo = Memo(content: content, createdAt: Date()) ย  ย  ย  ย  completion(.success(memo)) ย  ย  }).store(in: &self.cancellables) } private func parseContent(_ jsonString: String?) -> String? { ย  ย  guard let jsonString = jsonString, ย  ย  ย  ย  ย  let data = jsonString.data(using: .utf8), ย  ย  ย  ย  ย  let parsedContent = try? JSONDecoder().decode(String.self, from: data) else { ย  ย  ย  ย  return nil ย  ย  } ย  ย  return parsedContent } ์ด ํ•จ์ˆ˜๋Š” ์‚ฌ์šฉ์ž๊ฐ€ ์ž…๋ ฅํ•œ ํ”„๋กฌํ”„ํŠธ๋ฅผ OpenAI API๋กœ ์ „์†กํ•˜๊ณ , ๊ฒฐ๊ณผ๋ฅผ ๋ฐ›์•„ Memo๋ผ๋Š” ๊ฐ์ฒด๋กœ ๋ณ€ํ™˜ํ•ฉ๋‹ˆ๋‹ค. Memo๋Š” AI๊ฐ€ ์ƒ์„ฑํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ์•ฑ์—์„œ ์‚ฌ์šฉํ•˜๊ธฐ ํŽธ๋ฆฌํ•˜๊ฒŒ ๊ตฌ์กฐํ™”ํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ฝ”๋“œ ์„ค๋ช…๊ณผ ์ฃผ์˜ ์‚ฌํ•ญ ์œ„์˜ ์ฝ”๋“œ๋“ค์€ API ํ˜ธ์ถœ๊ณผ JSON ์‘๋‹ต ์ฒ˜๋ฆฌ๋ฅผ ๋งค์šฐ ๊ฐ„๋‹จํ•˜๊ฒŒ ๋งŒ๋“ค์–ด ์ค๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์‹ค์ œ ํ”„๋กœ์ ํŠธ์—์„œ๋Š” ๋‹ค์–‘ํ•œ ์˜ˆ์™ธ ์ƒํ™ฉ์„ ์ฒ˜๋ฆฌํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ๋„คํŠธ์›Œํฌ ์˜ค๋ฅ˜, ์„œ๋ฒ„ ์˜ค๋ฅ˜, JSON ํŒŒ์‹ฑ ์˜ค๋ฅ˜ ๋“ฑ์„ ๊ณ ๋ คํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ์˜ˆ์™ธ ์ƒํ™ฉ์„ ํšจ๊ณผ์ ์œผ๋กœ ์ฒ˜๋ฆฌํ•˜๋Š” ๊ฒƒ์ด ๊ฒฌ๊ณ ํ•œ ์•ฑ์„ ๋งŒ๋“œ๋Š” ๋ฐ ์ค‘์š”ํ•œ ์š”์†Œ์ž…๋‹ˆ๋‹ค. ๋˜ํ•œ ๋น„๋™๊ธฐ์ ์œผ๋กœ API ํ˜ธ์ถœ์„ ๊ด€๋ฆฌํ•˜๋Š” ๊ฒƒ์€ ๋งค์šฐ ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” ์ฃผ ์Šค๋ ˆ๋“œ๋ฅผ ์ฐจ๋‹จํ•˜์ง€ ์•Š๊ณ , ๋ฐฑ๊ทธ๋ผ์šด๋“œ์—์„œ ๋„คํŠธ์›Œํฌ ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•˜๋ฉฐ, ๊ฒฐ๊ณผ๋ฅผ ๋ฐ›์•„์™”์„ ๋•Œ UI๋ฅผ ์—…๋ฐ์ดํŠธํ•˜๋Š” ๋ฐ ๋„์›€์ด ๋ฉ๋‹ˆ๋‹ค. ๋งˆ๋ฌด๋ฆฌ ์˜ค๋Š˜์€ Swift iOS ํ”„๋กœ์ ํŠธ์—์„œ OpenAI API๋ฅผ ํšจ์œจ์ ์œผ๋กœ ์‚ฌ์šฉํ•˜์—ฌ ํ”„๋กฌํ”„ํŠธ ์—”์ง€๋‹ˆ์–ด๋ง์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์•Œ์•„๋ณด์•˜์Šต๋‹ˆ๋‹ค. ์ฝ”๋“œ ์˜ˆ์ œ์™€ ํ•จ๊ป˜ ๊ฐ ๋‹จ๊ณ„๋ณ„๋กœ ์„ธ๋ถ€ ์‚ฌํ•ญ์„ ์„ค๋ช…ํ–ˆ์œผ๋ฉฐ, ์ด๋ฅผ ํ†ตํ•ด ์—ฌ๋Ÿฌ๋ถ„์˜ ํ”„๋กœ์ ํŠธ์—์„œ๋„ OpenAI API๋ฅผ ํšจ๊ณผ์ ์œผ๋กœ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ํ”„๋กฌํ”„ํŠธ ์—”์ง€๋‹ˆ์–ด๋ง๊ณผ OpenAI API์˜ ์กฐํ•ฉ์€ ๊ฐ•๋ ฅํ•œ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•˜๋ฉฐ, ์ด๋ฅผ ํ†ตํ•ด ์‚ฌ์šฉ์ž ๊ฒฝํ—˜์„ ๊ทน๋Œ€ํ™”ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์•ž์œผ๋กœ๋„ ๋” ๋งŽ์€ ๊ธฐ๋Šฅ๋“ค์„ ์ถ”๊ฐ€ํ•˜๊ณ , ์ตœ์ ํ™”ํ•˜๋Š” ์ž‘์—…์„ ์ง€์†์ ์œผ๋กœ ์ˆ˜ํ–‰ํ•ด ๋‚˜๊ฐ€์‹œ๊ธฐ ๋ฐ”๋ž๋‹ˆ๋‹ค.

์•Œ๋ฆผ

์•Œ๋ฆผ์ด ์—†์Šต๋‹ˆ๋‹ค