2023-01-13 17:43:02 +00:00
|
|
|
import Foundation
|
|
|
|
|
|
|
|
public struct OpenAIClient {
|
2023-01-17 10:36:01 +00:00
|
|
|
private let endpoint: URL = .init(string: "https://api.openai.com/v1/completions")!
|
|
|
|
|
2023-01-13 17:43:02 +00:00
|
|
|
private var APIKey: String {
|
|
|
|
if let path = Bundle.main.path(forResource: "Secret", ofType: "plist") {
|
|
|
|
let secret = NSDictionary(contentsOfFile: path)
|
|
|
|
return secret?["OPENAI_SECRET"] as? String ?? ""
|
|
|
|
}
|
|
|
|
return ""
|
|
|
|
}
|
2023-01-17 10:36:01 +00:00
|
|
|
|
2023-01-13 17:43:02 +00:00
|
|
|
private var authorizationHeaderValue: String {
|
|
|
|
"Bearer \(APIKey)"
|
|
|
|
}
|
2023-01-17 10:36:01 +00:00
|
|
|
|
2023-01-13 17:43:02 +00:00
|
|
|
private var encoder: JSONEncoder {
|
|
|
|
let encoder = JSONEncoder()
|
|
|
|
encoder.keyEncodingStrategy = .convertToSnakeCase
|
|
|
|
return encoder
|
|
|
|
}
|
2023-01-17 10:36:01 +00:00
|
|
|
|
2023-01-13 17:43:02 +00:00
|
|
|
private var decoder: JSONDecoder {
|
|
|
|
let decoder = JSONDecoder()
|
|
|
|
decoder.keyDecodingStrategy = .convertFromSnakeCase
|
|
|
|
return decoder
|
|
|
|
}
|
2023-01-17 10:36:01 +00:00
|
|
|
|
2023-01-13 17:43:02 +00:00
|
|
|
public struct Request: Encodable {
|
|
|
|
let model = "text-davinci-003"
|
|
|
|
let topP: Int = 1
|
|
|
|
let frequencyPenalty: Int = 0
|
|
|
|
let presencePenalty: Int = 0
|
|
|
|
let prompt: String
|
|
|
|
let temperature: Double
|
|
|
|
let maxTokens: Int
|
2023-01-17 10:36:01 +00:00
|
|
|
|
2023-01-13 17:43:02 +00:00
|
|
|
public init(prompt: String, temperature: Double, maxTokens: Int) {
|
|
|
|
self.prompt = prompt
|
|
|
|
self.temperature = temperature
|
|
|
|
self.maxTokens = maxTokens
|
|
|
|
}
|
|
|
|
}
|
2023-01-17 10:36:01 +00:00
|
|
|
|
2023-01-13 17:43:02 +00:00
|
|
|
public enum Prompts {
|
|
|
|
case correct(input: String)
|
|
|
|
case shorten(input: String)
|
|
|
|
case emphasize(input: String)
|
2023-01-17 10:36:01 +00:00
|
|
|
|
2023-01-13 17:43:02 +00:00
|
|
|
var request: Request {
|
|
|
|
switch self {
|
|
|
|
case let .correct(input):
|
|
|
|
return Request(prompt: "Correct this to standard English:\(input)",
|
|
|
|
temperature: 0,
|
|
|
|
maxTokens: 500)
|
|
|
|
case let .shorten(input):
|
|
|
|
return Request(prompt: "Make a summary of this paragraph:\(input)",
|
|
|
|
temperature: 0.7,
|
|
|
|
maxTokens: 100)
|
|
|
|
case let .emphasize(input):
|
|
|
|
return Request(prompt: "Make this paragraph catchy, more fun:\(input)",
|
|
|
|
temperature: 0.8,
|
|
|
|
maxTokens: 500)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-01-17 10:36:01 +00:00
|
|
|
|
2023-01-13 17:43:02 +00:00
|
|
|
public struct Response: Decodable {
|
|
|
|
public struct Choice: Decodable {
|
|
|
|
public let text: String
|
|
|
|
}
|
2023-01-17 10:36:01 +00:00
|
|
|
|
2023-01-13 17:43:02 +00:00
|
|
|
public let id: String
|
|
|
|
public let object: String
|
|
|
|
public let model: String
|
|
|
|
public let choices: [Choice]
|
|
|
|
}
|
2023-01-17 10:36:01 +00:00
|
|
|
|
|
|
|
public init() {}
|
|
|
|
|
2023-01-13 17:43:02 +00:00
|
|
|
public func request(_ prompt: Prompts) async throws -> Response {
|
|
|
|
do {
|
|
|
|
let jsonData = try encoder.encode(prompt.request)
|
|
|
|
var request = URLRequest(url: endpoint)
|
|
|
|
request.httpMethod = "POST"
|
|
|
|
request.setValue(authorizationHeaderValue, forHTTPHeaderField: "Authorization")
|
|
|
|
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
|
|
|
|
request.httpBody = jsonData
|
|
|
|
let (result, _) = try await URLSession.shared.data(for: request)
|
|
|
|
let response = try decoder.decode(Response.self, from: result)
|
|
|
|
return response
|
2023-01-17 10:36:01 +00:00
|
|
|
} catch {
|
2023-01-13 17:43:02 +00:00
|
|
|
throw error
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|