A Swift client for the OpenAI API.

Overview

OpenAI

CI Documentation

A Swift client for the OpenAI API.

Requirements

  • Swift 5.3+
  • An OpenAI API Key

Example Usage

Completions

import OpenAI

let apiKey: String // required
let client = Client(apiKey: apiKey)

let prompt = "Once upon a time"

client.completions(engine: .davinci, 
                   prompt: prompt, 
                   numberOfTokens: ...5, 
                   numberOfCompletions: 1) { result in
    guard case .success(let completions) = result else { return }
    
    completions.first?.choices.first?.text // " there was a girl who"
}

Searches

import OpenAI

let apiKey: String // required
let client = Client(apiKey: apiKey)

let documents: [String] = [
    "White House",
    "hospital",
    "school"
]

let query = "president"

client.search(engine: .davinci, 
              documents: documents, 
              query: query) { result in
    guard case .success(let searchResults) = result else { return }
    searchResults.max()?.document // 0 (for "White House")
}

Classifications

import OpenAI

let apiKey: String // required
let client = Client(apiKey: apiKey)

let query = "It is a raining day :("

let examples: [(String, label: String)] = [
    ("A happy moment", label: "Positive"),
    ("I am sad.", label: "Negative"),
    ("I am feeling awesome", label: "Positive")
]

let labels = ["Positive", "Negative", "Neutral"]

client.classify(engine: .curie, 
                query: query, 
                examples: examples, 
                labels: labels, 
                searchEngine: .ada) { result in
    guard case .success(let classification) = result else { return }
    
    classification.label // "Negative"
}

Answers

"]) { result in guard case .success(let response) = result else { return } response.answers.first // "puppy A." } ">
import OpenAI

let apiKey: String // required
let client = Client(apiKey: apiKey)

let documents: [String] = [
    "Puppy A is happy.", 
    "Puppy B is sad."
]

let question = "which puppy is happy?"

let examples: (context: String, [(question: String, answer: String)]) = (
    context: "In 2017, U.S. life expectancy was 78.6 years.",
    [
        (question: "What is human life expectancy in the United States?", answer: "78 years.")
    ]
)

client.answer(engine: .curie, 
              question: question, 
              examples: examples, 
              documents: documents, 
              searchEngine: .ada, 
              stop: ["\n", "<|endoftext|>"]) { result in
    guard case .success(let response) = result else { return }
    
    response.answers.first // "puppy A."
}

Swift Package Manager

Add the OpenAI package to your target dependencies in Package.swift:

// swift-tools-version:5.3
import PackageDescription

let package = Package(
  name: "YourProject",
  dependencies: [
    .package(
        url: "https://github.com/mattt/OpenAI",
        from: "0.1.0"
    ),
  ]
)

Then run the swift build command to build your project.

License

MIT

Contact

Mattt (@mattt)

Comments
  • Added support for more engines.

    Added support for more engines.

    Added support for newer engines in the Instruct series and Codex, so that these models can be quickly referenced via the enum. Updated enum case descriptions to reflect this.

    opened by zcutlerf 10
  • Adding user field in completions

    Adding user field in completions

    OpenAI requested that I include a user field in a recent app pre-launch review. Wanted to add it in here in case other developers are also being requested to include the field. Here's the note provided by the production review team:

    Please pass a uniqueID for every user w/ each API call (both for Completion & the Content Filter) e.g. user= $uniqueID. This 'user' param can be passed in the request body along with other params such as prompt, max_tokens etc.
    opened by benhynes 5
  • Alamofire Error: invalid_request_error - Engine not found

    Alamofire Error: invalid_request_error - Engine not found

    Alamofire throws the error invalid_request_error - Engine not found.

    Setup:

    class Model: ObservableObject {
    	@Published var input = ""
    	@Published var output = ""
    	
    	private let client: Client
    	
    	init() {
    		let apiKey = "<redacted>"
    		client = Client(apiKey: apiKey)
    	}
    	
    	func go() {
    		client.completions(
    			engine: "davinci-codex",
    			prompt: input,
    			sampling: .temperature(0.0),
    			numberOfTokens: ...256,
    			numberOfCompletions: 1,
    			echo: false,
    			stop: ["//"],
    			presencePenalty: 0.0,
    			frequencyPenalty: 0.0,
    			bestOf: 1
    		) { [self] result in
    			guard case .success(let completions) = result else {
    				fatalError("\(result)")
    			}
    			
    			let choices = completions.flatMap(\.choices)
    			
    			for choice in choices {
    				print("\(choice.text)")
    			}
    			
    			output = choices.first?.text ?? ""
    		}
    	}
    }
    
    opened by melgu 3
  • Document best practices for using available engines

    Document best practices for using available engines

    Related to #8 and #9

    As discussed in https://github.com/mattt/OpenAI/pull/9#issuecomment-1117913832, there's no way for this library to provide enumeration cases for each of the OpenAI engines available.

    So as an alternative, this PR documents the pattern of extending Engine.ID to provide convenience APIs for any engines used in a codebase.

    extension Engine.ID {
      static var babbageSearchQuery: Self = "babbage-search-query"
    }
    

    This PR also updates the existing testEngines() to run against a mocked response, and updates the mocked response of GET /v1/engines/ada with new fields.

    opened by mattt 2
  • Adding dedicated contentFilter function

    Adding dedicated contentFilter function

    It was required by OpenAI for a project I've been working on, so I just wanted to simplify usage a little bit. Now there's a contentFilter function that can be called as:

    client.contentFilter(prompt: prompt, completion: { rating in
        switch rating {
        case 0:
            print("Safe")
        case 1:
            print("Sensitive")
            // This means that the text could be talking about a sensitive topic, something political, religious, or talking about a protected class such as race or nationality.
        case 2:
            print("Unsafe")
            // This means that the text contains profane language, prejudiced or hateful language, something that could be NSFW, or text that portrays certain groups/people in a harmful manner.
        default:
            print("Unexpected result")
        }
        }
    })
    

    It effectively wraps a completion request instead of implementing a different request, so I think the error handling should be sufficient with the completion of the the completions function with Result<[Completion], Swift.Error>. This is handled with the guard case .success(let completions) = result else { fatalError("\(result)") } within contentFilter, but I'm interested in input as to whether this is an acceptable way of dealing with this.

    Just a note that I rebased my commits to modify a commit name for clarity, in case there were any questions regarding why there were 4 commits made at the same time.

    opened by benhynes 2
  • failure(Alamofire.AFError.sessionDeinitialized)

    failure(Alamofire.AFError.sessionDeinitialized)

    When I try the recommended code

    let apiKey: String // required
    let client = Client(apiKey: apiKey)
    
    let prompt = "Describe the Swift programming language in a few sentences."
    
    client.completions(engine: "davinci-instruct-beta",
                       prompt: prompt,
                       sampling: .temperature(0.0),
                       numberOfTokens: ...100,
                       numberOfCompletions: 1,
                       stop: ["\n\n"],
                       presencePenalty: 0.0,
                       frequencyPenalty: 0.0,
                       bestOf: 1) { result in
        guard case .success(let completions) = result else { fatalError("\(result)") }
    
        for choice in completions.flatMap(\.choices) {
            print("\(choice.text)")
        }
    }
    

    I get the following error:

    TestWithOpenAI/ViewController.swift:31: Fatal error: failure(Alamofire.AFError.sessionDeinitialized)
    2022-05-08 20:08:33.976354-0700 TestWithOpenAI[15129:4948609] TestWithOpenAI/ViewController.swift:31: Fatal error: failure(Alamofire.AFError.sessionDeinitialized)
    
    opened by scott-lydon 1
  • Some parameters in the client.completion(... etc not passed on to the session call

    Some parameters in the client.completion(... etc not passed on to the session call

    Hi - I want to set the presencePenalty and frequencyPenalty parameters to my own custom values, but they don't seem to be carried forward into the parameters flatmap before the session call.

    The parameters exposed in the high level client method completions that should ideally be carried through in to the URL session call.

    e.g.:

    Parameters in client.completion():

     presencePenalty: Double? = nil,
     frequencyPenalty: Double? = nil,
     bestOf: Int? = nil,
    

    Not used in:

    var parameters: [String: Any?] = [
                "prompt": prompt,
                "max_tokens": numberOfTokens?.upperBound,
                "user": user,
                "n": numberOfCompletions,
                "echo": echo,
                "stop": stop
    /// missing penalty and bestOf parameters ideally added here...
            ]
    

    Net result is that you think you are changing certain values in the call to client.completions(), but in reality they aren't getting changed.

    opened by paulostergaard 1
  • Alamofire throws fatal error in SwiftUI

    Alamofire throws fatal error in SwiftUI

    Occurs when executing this code block:

    let apiKey: String = "<<API KEY>>"
    let client = Client(apiKey: apiKey)
    
    client.completions(engine: .davinci,
                               prompt: prompt,
                               numberOfTokens: ...300,
                               numberOfCompletions: 1,
                               echo: false,
                               stop: ["\n\n"],
                               presencePenalty: 0.1,
                               frequencyPenalty: 0.1,
                               bestOf: 1) { result in
                guard case .success(let completions) = result else { fatalError("\(result)") }
                
                for choice in completions.flatMap(\.choices) {
                        print("\(choice.text)")
                }
    }
    

    Error: Fatal error: failure(Alamofire.AFError.sessionDeinitialized)

    This is with iOS 14.0 as a deployment target and Xcode 13.0 as a SwiftUI project. The problem seems to be caused when the client is declared within the local namespace of the function. When the declaration is moved out to global namespace, outside of the view struct, the issue is resolved.

    It seems SwiftUI might excessively garbage collect in this situation. It may make sense to add a footnote for SwiftUI to the docs (I'm happy to help contribute).

    opened by benhynes 1
  • Undefined symbol: nominal type descriptor for OpenAI.Completion

    Undefined symbol: nominal type descriptor for OpenAI.Completion

    1. Download OpenAI package.
    2. On the Project level, add OpenAI package into my project through Package Dependencies. OpenAI-main package shows up in the folder Packages; Alamofire 5.4.4 and AnyCodable 0.4.1 show up in Package Dependencies.
    3. On the Target level, add OpenAI product into Build Phases->Dependencies
    4. in my project, code "import OpenAI" in ContentView.swift without errors.
    5. run the build, the errors show:

    Undefined symbols for architecture arm64: "nominal type descriptor for OpenAI.Completion.Choice", referenced from: _symbolic Say_____G 6OpenAI10CompletionV6ChoiceV in ContentView.o "nominal type descriptor for OpenAI.Completion", referenced from: _symbolic Say_____G 6OpenAI10CompletionV in ContentView.o "type metadata accessor for OpenAI.Client", referenced from: one-time initialization function for client in ContentView.o ForTest.ContentView.followUpPrompt(prompt: Swift.String) -> () in ContentView.o "OpenAI.Client.completions(engine: OpenAI.Engine.ID, prompt: Swift.String?, sampling: OpenAI.Sampling?, numberOfTokens: Swift.PartialRangeThrough<Swift.Int>?, numberOfCompletions: Swift.Int?, echo: Swift.Bool?, stop: [Swift.String]?, user: Swift.String?, presencePenalty: Swift.Double?, frequencyPenalty: Swift.Double?, bestOf: Swift.Int?, completion: (Swift.Result<[OpenAI.Completion], Swift.Error>) -> ()) -> ()", referenced from: ForTest.ContentView.followUpPrompt(prompt: Swift.String) -> () in ContentView.o "OpenAI.Client.__allocating_init(apiKey: Swift.String, organization: Swift.String?) -> OpenAI.Client", referenced from: one-time initialization function for client in ContentView.o ForTest.ContentView.followUpPrompt(prompt: Swift.String) -> () in ContentView.o ld: symbol(s) not found for architecture arm64 clang: error: linker command failed with exit code 1 (use -v to see invocation)

    ld: symbol(s) not found for architecture arm64 clang: error: linker command failed with exit code 1 (use -v to see invocation)

    Undefined symbol: nominal type descriptor for OpenAI.Completion.Choice

    Undefined symbol: nominal type descriptor for OpenAI.Completion

    Undefined symbol: type metadata accessor for OpenAI.Client

    Undefined symbol: OpenAI.Client.completions(engine: OpenAI.Engine.ID, prompt: Swift.String?, sampling: OpenAI.Sampling?, numberOfTokens: Swift.PartialRangeThrough<Swift.Int>?, numberOfCompletions: Swift.Int?, echo: Swift.Bool?, stop: [Swift.String]?, user: Swift.String?, presencePenalty: Swift.Double?, frequencyPenalty: Swift.Double?, bestOf: Swift.Int?, completion: (Swift.Result<[OpenAI.Completion], Swift.Error>) -> ()) -> ()

    Undefined symbol: OpenAI.Client.__allocating_init(apiKey: Swift.String, organization: Swift.String?) -> OpenAI.Client

    opened by truman0505 0
  • Lacking new endpoints

    Lacking new endpoints

    OpenAI API changes

    As OpenAI added new endpoints to their API and plans to deprecate some of the already existing ones, there is a need to take action.

    Namely, this package should include new Edits and Embeddings endpoints.

    Please also note that endpoints Searches, Classifications, Answers and Engines 'are deprecated and will be removed on December 3rd, 2022`. Reference - OpenAI API Reference

    opened by syrekable 0
  • Deprecate engine cases

    Deprecate engine cases

    Made a few changes here. Please let me know if any of these could be reworked. -Deprecated the enum cases, which produces some warnings in the package. I haven't figured out how to "deprecate in the future." -After re-reading OpenAI's documentation, it seems like Completion should be used with the newer Instruct Series, and the other methods should be used with the older Base Series. I've streamlined the readme to reflect this. -I also moved the extension suggestion higher in the readme so it's more noticeable.

    opened by zcutlerf 0
Owner
Mattt
Mattt
Fetch Multiple Rest API using Swift 5.5 Async Await with Task, TaskGroup, Continuation API

Source code for Tutorial on experimenting with Swift Async Await to fetch multiple REST API endpoints and eliminate Pyramid of Doom callback hell to improve code readability and maintanability

Alfian Losari 14 Dec 7, 2022
Swift client for Kubernetes

Table of contents Overview Compatibility Matrix Examples Usage Creating a client Configuring a client Client authentication Client DSL Advanced usage

Swiftkube 94 Dec 14, 2022
A (really) native and powerful macOS Telegram client built using SwiftUI, optimized for moderating large communities and personal use.

Moc A (really) native and powerful macOS Telegram client, optimized for moderating large communities and personal use. This client is currently in dev

GGorAA 84 Jan 2, 2023
Swift implementation of Github REST API v3

GitHubAPI Swift implementation of GitHub REST api v3. Library support Swift 4.2. Work is in progress. Currently supported: Issues API. Activity API(Fe

Serhii Londar 77 Jan 7, 2023
Google Directions API helper for iOS, written in Swift

PXGoogleDirections Google Directions API SDK for iOS, entirely written in Swift. ?? Features Supports all features from the Google Directions API as o

Romain L 268 Aug 18, 2022
Swift Reddit API Wrapper

reddift reddift is Swift Reddit API Wrapper framework, and includes a browser is developed using the framework. Supports OAuth2(is not supported on tv

sonson 236 Dec 28, 2022
Instagram Private API Swift

SwiftyInsta Please notice SwiftyInsta may not be actively maintained at the moment of you reading this note. Refer to #244 for more info. Instagram of

Mahdi Makhdumi 218 Jan 5, 2023
Swift Bot with Vapor for Telegram Bot Api

Telegram Vapor Bot Please support Swift Telegram Vapor Bot Lib development by giving a ⭐️ Telegram Bot based on Swift Vapor. Swift Server Side Communi

OleG. 104 Jan 6, 2023
Swift library for the Twitter API v1 and v2

Swift library for the Twitter API v1 and v2

mironal 96 Dec 30, 2022
Backport of iOS 15 formatting api

This is a back-port of the .formatted API in Foundation that was introduced at WWDC '21 for iOS 15, macOS 12.0, tvOS 15.0, and watchOS 8.0.

Simon Salomons 9 Jul 22, 2022
Unofficial iOS/macOS SDK for the Notion API.

NotionClient: a Notion SDK for iOS & macOS Unofficial Notion API SDK for iOS & macOS. This is an alpha version and still work in progress. TODO Featur

David De Bels 15 Aug 4, 2022
👤 Framework to Generate Random Users - An Unofficial Swift SDK for randomuser.me

RandomUserSwift is an easy to use Swift framework that provides the ability to generate random users and their accompanying data for your Swift applic

Wilson Ding 95 Sep 9, 2022
Swifter - A Twitter framework for iOS & OS X written in Swift

Getting Started Installation If you're using Xcode 6 and above, Swifter can be installed by simply dragging the Swifter Xcode project into your own pr

Matt Donnelly 2.4k Dec 26, 2022
SDK for creating Telegram Bots in Swift.

Chat • Changelog • Prerequisites • Getting started • Creating a new bot • Generating Xcode project • API overview • Debugging notes • Examples • Docum

Rapier 349 Dec 20, 2022
Telegram Bot Framework written in Swift 5.1 with SwiftNIO network framework

Telegrammer is open-source framework for Telegram Bots developers. It was built on top of Apple/SwiftNIO

Pataridze Givi 279 Jan 4, 2023
Solana + RxSolana This is a open source library on pure swift for Solana protocol

The objective is to create a cross platform, fully functional, highly tested and less depencies as posible. The project is still at initial stage. Lots of changes chan happen to the exposed api.

Arturo Jamaica 138 Dec 15, 2022
QuoteKit is a Swift framework to use the free APIs provided by Quotable created by Luke Peavey.

QuoteKit The QuoteKit is a Swift framework to use the free APIs provided by Quotable created by Luke Peavey.

Rudrank Riyam 17 Jun 23, 2022
A simple Swift package which acts as an OpenAI client for the GPT-3 API.

SwiftyGPT3 A simple Swift package which acts as an OpenAI client for GPT-3 brought to you by the Airgift Crew. Supports GPT-3 Codex! Requirements iOS

Airgift 23 Dec 25, 2022
Mobile Text-to-Image search powered by multimodal semantic representation models(e.g., OpenAI's CLIP)

A Mobile Text-to-Image Search Powered by AI A minimal demo demonstrating semantic multimodal text-to-image search using pretrained vision-language mod

null 66 Jan 5, 2023
Mobile(iOS) Text-to-Image search powered by multimodal semantic representation models(e.g., OpenAI's CLIP)

Mobile Text-to-Image Search(MoTIS) MoTIS is a minimal demo demonstrating semantic multimodal text-to-image search using pretrained vision-language mod

Roy 66 Dec 2, 2022