Skip to content

Instantly share code, notes, and snippets.

@0xLeif
Last active March 1, 2023 23:28
Show Gist options
  • Save 0xLeif/c826372e795de39637bd96a356228936 to your computer and use it in GitHub Desktop.
Save 0xLeif/c826372e795de39637bd96a356228936 to your computer and use it in GitHub Desktop.
import c // https://github.com/0xOpenBytes/c
import o // https://github.com/0xOpenBytes/o
import Plugin // https://github.com/0xLeif/Plugin
import Foundation
class ChatService: Pluginable {
enum Constants {
enum Model {
static let davinci = "text-davinci-003"
}
static let apiKey = "KEY_HERE"
}
enum ChatError: String, LocalizedError {
case noData = "No Data"
case noChoices = "No AI Choices"
}
/**
{
"id": "cmpl-uqkvlQyYK7bGYrRHQ0eXlWi7",
"object": "text_completion",
"created": 1589478378,
"model": "text-davinci-003",
"choices": [
{
"text": "\n\nThis is indeed a test",
"index": 0,
"logprobs": null,
"finish_reason": "length"
}
],
"usage": {
"prompt_tokens": 5,
"completion_tokens": 7,
"total_tokens": 12
}
}
*/
enum JSONKeys {
enum Root: String {
case id, object, created, model, choices, usage
}
enum Choices: String {
case text, index, logprobs, finish_reason
}
enum Usage: String {
case prompt_tokens, completion_tokens, total_tokens
}
}
typealias ChatServicePluginPayload = c.JSON<JSONKeys.Root>
var plugins: [any Plugin]
init(plugins: [any Plugin] = []) {
self.plugins = plugins
}
func completion(for prompt: String) async throws -> String {
struct Payload: Codable {
let model: String
let prompt: String
let max_tokens: Int
let temperature: Int
}
let body = try JSONEncoder().encode(
Payload(
model: Constants.Model.davinci,
prompt: prompt,
max_tokens: 2048,
temperature: 0
)
)
/*
curl https://api.openai.com/v1/completions \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-d '{
"model": "text-davinci-003",
"prompt": "Say this is a test",
"max_tokens": 7,
"temperature": 0
}'
*/
let dataResponse = try await o.url.post(
url: URL(string: "https://api.openai.com/v1/completions")!,
body: body,
headerFields: [
"Content-Type": "application/json",
"Authorization": "Bearer \(Constants.apiKey)"
]
)
guard
let data = dataResponse.data
else {
throw ChatError.noData
}
let json = c.JSON<JSONKeys.Root>(data: data)
try await handle(value: json)
guard
let choices = json.array(.choices, keyed: JSONKeys.Choices.self),
let firstChoice = choices.first?.get(.text, as: String.self)
else {
throw ChatError.noChoices
}
return firstChoice
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment