{"id":15031508,"url":"https://github.com/macpaw/openai","last_synced_at":"2025-05-13T20:21:57.462Z","repository":{"id":65362482,"uuid":"579947672","full_name":"MacPaw/OpenAI","owner":"MacPaw","description":"Swift community driven package for OpenAI public API","archived":false,"fork":false,"pushed_at":"2025-04-24T15:53:46.000Z","size":1173,"stargazers_count":2427,"open_issues_count":35,"forks_count":432,"subscribers_count":33,"default_branch":"main","last_synced_at":"2025-04-24T16:52:39.515Z","etag":null,"topics":["ai","openai","openai-api","spm","swift","swiftpackagemanager"],"latest_commit_sha":null,"homepage":"","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/MacPaw.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2022-12-19T10:43:27.000Z","updated_at":"2025-04-24T09:56:45.000Z","dependencies_parsed_at":"2023-11-27T16:55:32.760Z","dependency_job_id":"fe03d597-afd3-4966-abc7-e5dbcb23a108","html_url":"https://github.com/MacPaw/OpenAI","commit_stats":{"total_commits":230,"total_committers":40,"mean_commits":5.75,"dds":0.5695652173913044,"last_synced_commit":"fd13a41e987004d14f1793c570721953a2767b03"},"previous_names":[],"tags_count":35,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MacPaw%2FOpenAI","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MacPaw%2FOpenAI/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MacPaw%2FOpenAI/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MacPaw%2FOpenAI/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/MacPaw","download_url":"https://codeload.github.com/MacPaw/OpenAI/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":251311332,"owners_count":21569008,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ai","openai","openai-api","spm","swift","swiftpackagemanager"],"created_at":"2024-09-24T20:15:51.812Z","updated_at":"2025-05-13T20:21:57.455Z","avatar_url":"https://github.com/MacPaw.png","language":"Swift","readme":"# OpenAI\n\n![logo](https://user-images.githubusercontent.com/1411778/218319355-f56b6bd4-961a-4d8f-82cd-6dbd43111d7f.png)\n\n___\n\n![Swift Workflow](https://github.com/MacPaw/OpenAI/actions/workflows/swift.yml/badge.svg)\n[![](https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2FMacPaw%2FOpenAI%2Fbadge%3Ftype%3Dswift-versions)](https://swiftpackageindex.com/MacPaw/OpenAI)\n[![](https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2FMacPaw%2FOpenAI%2Fbadge%3Ftype%3Dplatforms)](https://swiftpackageindex.com/MacPaw/OpenAI)\n[![Twitter](https://img.shields.io/static/v1?label=Twitter\u0026message=@MacPaw\u0026color=CA1F67)](https://twitter.com/MacPaw)\n\nThis repository contains Swift community-maintained implementation over [OpenAI](https://platform.openai.com/docs/api-reference/) public API. \n\n- [What is OpenAI](#what-is-openai)\n- [Installation](#installation)\n- [Usage](#usage)\n    - [Initialization](#initialization)\n    - [Chats](#chats)\n        - [Chats Streaming](#chats-streaming) \n        - [Structured Output](#structured-output) \n    - [Images](#images)\n        - [Create Image](#create-image)\n        - [Create Image Edit](#create-image-edit)\n        - [Create Image Variation](#create-image-variation)\n    - [Audio](#audio)\n        - [Audio Create Speech](#audio-create-speech)\n        - [Audio Transcriptions](#audio-transcriptions)\n        - [Audio Translations](#audio-translations)\n    - [Embeddings](#embeddings)\n    - [Models](#models)\n        - [List Models](#list-models)\n        - [Retrieve Model](#retrieve-model)\n    - [Moderations](#moderations)\n    - [Utilities](#utilities)\n    - [Combine Extensions](#combine-extensions)\n    - [Assistants (Beta)](#assistants)\n        - [Create Assistant](#create-assistant)\n        - [Modify Assistant](#modify-assistant)\n        - [List Assistants](#list-assistants) \n        - [Threads](#threads)\n          - [Create Thread](#create-thread)\n          - [Create and Run Thread](#create-and-run-thread)\n          - [Get Threads Messages](#get-threads-messages)\n          - [Add Message to Thread](#add-message-to-thread)\n        - [Runs](#runs)\n          - [Create Run](#create-run)\n          - [Retrieve Run](#retrieve-run)\n          - [Retrieve Run Steps](#retrieve-run-steps)\n          - [Submit Tool Outputs for Run](#submit-tool-outputs-for-run)\n        - [Files](#files)\n          - [Upload File](#upload-file)\n  - [Cancelling requests](#cancelling-requests)\n- [Support for other providers: Gemini, DeepSeek, Perplexity, OpenRouter, etc.](#support-for-other-providers)\n- [Example Project](#example-project)\n- [Contribution Guidelines](#contribution-guidelines)\n- [Links](#links)\n- [License](#license)\n\n## What is OpenAI\n\nOpenAI is a non-profit artificial intelligence research organization founded in San Francisco, California in 2015. It was created with the purpose of advancing digital intelligence in ways that benefit humanity as a whole and promote societal progress. The organization strives to develop AI (Artificial Intelligence) programs and systems that can think, act and adapt quickly on their own – autonomously. OpenAI's mission is to ensure safe and responsible use of AI for civic good, economic growth and other public benefits; this includes cutting-edge research into important topics such as general AI safety, natural language processing, applied reinforcement learning methods, machine vision algorithms etc.\n\n\u003eThe OpenAI API can be applied to virtually any task that involves understanding or generating natural language or code. We offer a spectrum of models with different levels of power suitable for different tasks, as well as the ability to fine-tune your own custom models. These models can be used for everything from content generation to semantic search and classification.\n\n## Installation\n\nOpenAI is available with Swift Package Manager.\nThe Swift Package Manager is a tool for automating the distribution of Swift code and is integrated into the swift compiler.\nOnce you have your Swift package set up, adding OpenAI as a dependency is as easy as adding it to the dependencies value of your Package.swift.\n\n```swift\ndependencies: [\n    .package(url: \"https://github.com/MacPaw/OpenAI.git\", branch: \"main\")\n]\n```\n\n## Usage\n\n### Initialization\n\nTo initialize API instance you need to [obtain](https://platform.openai.com/account/api-keys) API token from your Open AI organization.\n\n**Remember that your API key is a secret!** Do not share it with others or expose it in any client-side code (browsers, apps). Production requests must be routed through your own backend server where your API key can be securely loaded from an environment variable or key management service.\n\n\u003cimg width=\"1081\" alt=\"company\" src=\"https://user-images.githubusercontent.com/1411778/213204726-0772373e-14db-4d5d-9a58-bc249bac4c57.png\"\u003e\n\nOnce you have a token, you can initialize `OpenAI` class, which is an entry point to the API.\n\n\u003e ⚠️ OpenAI strongly recommends developers of client-side applications proxy requests through a separate backend service to keep their API key safe. API keys can access and manipulate customer billing, usage, and organizational data, so it's a significant risk to [expose](https://nshipster.com/secrets/) them.\n\n```swift\nlet openAI = OpenAI(apiToken: \"YOUR_TOKEN_HERE\")\n```\n\nOptionally you can initialize `OpenAI` with token, organization identifier and timeoutInterval.\n\n```swift\nlet configuration = OpenAI.Configuration(token: \"YOUR_TOKEN_HERE\", organizationIdentifier: \"YOUR_ORGANIZATION_ID_HERE\", timeoutInterval: 60.0)\nlet openAI = OpenAI(configuration: configuration)\n```\n\nSee `OpenAI.Configuration` for more values that can be passed on init for customization, like: `host`, `basePath`, `port`, `scheme` and `customHeaders`.\n\nOnce you posses the token, and the instance is initialized you are ready to make requests.\n\n#### Using the SDK for other providers except OpenAI\n\nThis SDK is more focused on working with OpenAI Platform, but also works with other providers that support OpenAI-compatible API.\n\nUse `.relaxed` parsing option on Configuration, or see more details on the topic [here](#support-for-other-providers)\n\n### Chats\n\nUsing the OpenAI Chat API, you can build your own applications with `gpt-3.5-turbo` to do things like:\n\n* Draft an email or other piece of writing\n* Write Python code\n* Answer questions about a set of documents\n* Create conversational agents\n* Give your software a natural language interface\n* Tutor in a range of subjects\n* Translate languages\n* Simulate characters for video games and much more\n\n**Request**\n\n```swift\nstruct ChatQuery: Codable {\n    /// ID of the model to use.\n    public let model: Model\n    /// An object specifying the format that the model must output.\n    public let responseFormat: ResponseFormat?\n    /// The messages to generate chat completions for\n    public let messages: [Message]\n    /// A list of tools the model may call. Currently, only functions are supported as a tool. Use this to provide a list of functions the model may generate JSON inputs for.\n    public let tools: [Tool]?\n    /// Controls how the model responds to tool calls. \"none\" means the model does not call a function, and responds to the end-user. \"auto\" means the model can pick between and end-user or calling a function. Specifying a particular function via `{\"name\": \"my_function\"}` forces the model to call that function. \"none\" is the default when no functions are present. \"auto\" is the default if functions are present.\n    public let toolChoice: ToolChoice?\n    /// What sampling temperature to use, between 0 and 2. Higher values like 0.8 will make the output more random, while lower values like 0.2 will make it more focused and  We generally recommend altering this or top_p but not both.\n    public let temperature: Double?\n    /// An alternative to sampling with temperature, called nucleus sampling, where the model considers the results of the tokens with top_p probability mass. So 0.1 means only the tokens comprising the top 10% probability mass are considered.\n    public let topP: Double?\n    /// How many chat completion choices to generate for each input message.\n    public let n: Int?\n    /// Up to 4 sequences where the API will stop generating further tokens. The returned text will not contain the stop sequence.\n    public let stop: [String]?\n    /// The maximum number of tokens to generate in the completion.\n    public let maxTokens: Int?\n    /// Number between -2.0 and 2.0. Positive values penalize new tokens based on whether they appear in the text so far, increasing the model's likelihood to talk about new topics.\n    public let presencePenalty: Double?\n    /// Number between -2.0 and 2.0. Positive values penalize new tokens based on their existing frequency in the text so far, decreasing the model's likelihood to repeat the same line verbatim.\n    public let frequencyPenalty: Double?\n    /// Modify the likelihood of specified tokens appearing in the completion.\n    public let logitBias: [String:Int]?\n    /// A unique identifier representing your end-user, which can help OpenAI to monitor and detect abuse.\n    public let user: String?\n}\n```\n\n**Response**\n\n```swift\nstruct ChatResult: Codable, Equatable {\n    public struct Choice: Codable, Equatable {\n        public let index: Int\n        public let message: Chat\n        public let finishReason: String\n    }\n    \n    public struct Usage: Codable, Equatable {\n        public let promptTokens: Int\n        public let completionTokens: Int\n        public let totalTokens: Int\n    }\n    \n    public let id: String\n    public let object: String\n    public let created: TimeInterval\n    public let model: Model\n    public let choices: [Choice]\n    public let usage: Usage\n}\n```\n\n**Example**\n\n```swift\nlet query = ChatQuery(model: .gpt3_5Turbo, messages: [.init(role: .user, content: \"who are you\")])\nlet result = try await openAI.chats(query: query)\n```\n\n```\n(lldb) po result\n▿ ChatResult\n  - id : \"chatcmpl-6pwjgxGV2iPP4QGdyOLXnTY0LE3F8\"\n  - object : \"chat.completion\"\n  - created : 1677838528.0\n  - model : \"gpt-3.5-turbo-0301\"\n  ▿ choices : 1 element\n    ▿ 0 : Choice\n      - index : 0\n      ▿ message : Chat\n        - role : \"assistant\"\n        - content : \"\\n\\nI\\'m an AI language model developed by OpenAI, created to provide assistance and support for various tasks such as answering questions, generating text, and providing recommendations. Nice to meet you!\"\n      - finish_reason : \"stop\"\n  ▿ usage : Usage\n    - prompt_tokens : 10\n    - completion_tokens : 39\n    - total_tokens : 49\n```\n\n#### Chats Streaming\n\nChats streaming is available by using `chatStream` function. Tokens will be sent one-by-one.\n\n**Closures**\n```swift\nopenAI.chatsStream(query: query) { partialResult in\n    switch partialResult {\n    case .success(let result):\n        print(result.choices)\n    case .failure(let error):\n        //Handle chunk error here\n    }\n} completion: { error in\n    //Handle streaming error here\n}\n```\n\n**Combine**\n\n```swift\nopenAI\n    .chatsStream(query: query)\n    .sink { completion in\n        //Handle completion result here\n    } receiveValue: { result in\n        //Handle chunk here\n    }.store(in: \u0026cancellables)\n```\n\n**Structured concurrency**\n```swift\nfor try await result in openAI.chatsStream(query: query) {\n   //Handle result here\n}\n```\n\n**Function calls**\n```swift\nlet openAI = OpenAI(apiToken: \"...\")\n// Declare functions which model might decide to call.\nlet functions = [\n  FunctionDeclaration(\n      name: \"get_current_weather\",\n      description: \"Get the current weather in a given location\",\n      parameters: .init(fields: [\n        .type(.object),\n        .properties([\n          \"location\": .init(fields: [\n            .type(.string),\n            .description(\"The city and state, e.g. San Francisco, CA\")\n          ]),\n          \"unit\": .init(fields: [\n            .type(.string),\n            .enumValues([\"celsius\", \"fahrenheit\"])\n          ])\n        ]),\n        .required([\"location\"])\n      ])\n  )\n]\nlet query = ChatQuery(\n  model: \"gpt-3.5-turbo-0613\",  // 0613 is the earliest version with function calls support.\n  messages: [\n      Chat(role: .user, content: \"What's the weather like in Boston?\")\n  ],\n  tools: functions.map { Tool.function($0) }\n)\nlet result = try await openAI.chats(query: query)\n```\n\nResult will be (serialized as JSON here for readability):\n```json\n{\n  \"id\": \"chatcmpl-1234\",\n  \"object\": \"chat.completion\",\n  \"created\": 1686000000,\n  \"model\": \"gpt-3.5-turbo-0613\",\n  \"choices\": [\n    {\n      \"index\": 0,\n      \"message\": {\n        \"role\": \"assistant\",\n        \"tool_calls\": [\n          {\n            \"id\": \"call-0\",\n            \"type\": \"function\",\n            \"function\": {\n              \"name\": \"get_current_weather\",\n              \"arguments\": \"{\\n  \\\"location\\\": \\\"Boston, MA\\\"\\n}\"\n            }\n          }\n        ]\n      },\n      \"finish_reason\": \"function_call\"\n    }\n  ],\n  \"usage\": { \"total_tokens\": 100, \"completion_tokens\": 18, \"prompt_tokens\": 82 }\n}\n\n```\n\nReview [Chat Documentation](https://platform.openai.com/docs/guides/chat) for more info.\n\n#### Structured Output\n\nJSON is one of the most widely used formats in the world for applications to exchange data.\n\nStructured Outputs is a feature that ensures the model will always generate responses that adhere to your supplied JSON Schema, so you don't need to worry about the model omitting a required key, or hallucinating an invalid enum value.\n\n**Example**\n\n```swift\nstruct MovieInfo: JSONSchemaConvertible {\n    \n    let title: String\n    let director: String\n    let release: Date\n    let genres: [MovieGenre]\n    let cast: [String]\n    \n    static let example: Self = { \n        .init(\n            title: \"Earth\",\n            director: \"Alexander Dovzhenko\",\n            release: Calendar.current.date(from: DateComponents(year: 1930, month: 4, day: 1))!,\n            genres: [.drama],\n            cast: [\"Stepan Shkurat\", \"Semyon Svashenko\", \"Yuliya Solntseva\"]\n        )\n    }()\n}\n\nenum MovieGenre: String, Codable, JSONSchemaEnumConvertible {\n    case action, drama, comedy, scifi\n    \n    var caseNames: [String] { Self.allCases.map { $0.rawValue } }\n}\n\nlet query = ChatQuery(\n    messages: [.system(.init(content: \"Best Picture winner at the 2011 Oscars\"))],\n    model: .gpt4_o,\n    responseFormat: .derivedJsonSchema(name: \"movie-info\", type: MovieInfo.self)\n)\nlet result = try await openAI.chats(query: query)\n```\n\n- Use the `derivedJsonSchema(name:type:)` response format when creating a `ChatQuery`\n- Provide a schema name and a type that conforms to `JSONSchemaConvertible` and generates an instance as an example\n- Make sure all enum types within the provided type conform to `ChatQuery.JSONSchemaEnumConvertible` and generate an array of names for all cases\n\n\nReview [Structured Output Documentation](https://platform.openai.com/docs/guides/structured-outputs) for more info.\n\n### Images\n\nGiven a prompt and/or an input image, the model will generate a new image.\n\nAs Artificial Intelligence continues to develop, so too does the intriguing concept of Dall-E. Developed by OpenAI, a research lab for artificial intelligence purposes, Dall-E has been classified as an AI system that can generate images based on descriptions provided by humans. With its potential applications spanning from animation and illustration to design and engineering - not to mention the endless possibilities in between - it's easy to see why there is such excitement over this new technology.\n\n### Create Image\n\n**Request**\n\n```swift\nstruct ImagesQuery: Codable {\n    /// A text description of the desired image(s). The maximum length is 1000 characters.\n    public let prompt: String\n    /// The number of images to generate. Must be between 1 and 10.\n    public let n: Int?\n    /// The size of the generated images. Must be one of 256x256, 512x512, or 1024x1024.\n    public let size: String?\n}\n```\n\n**Response**\n\n```swift\nstruct ImagesResult: Codable, Equatable {\n    public struct URLResult: Codable, Equatable {\n        public let url: String\n    }\n    public let created: TimeInterval\n    public let data: [URLResult]\n}\n```\n\n**Example**\n\n```swift\nlet query = ImagesQuery(prompt: \"White cat with heterochromia sitting on the kitchen table\", n: 1, size: \"1024x1024\")\nopenAI.images(query: query) { result in\n  //Handle result here\n}\n//or\nlet result = try await openAI.images(query: query)\n```\n\n```\n(lldb) po result\n▿ ImagesResult\n  - created : 1671453505.0\n  ▿ data : 1 element\n    ▿ 0 : URLResult\n      - url : \"https://oaidalleapiprodscus.blob.core.windows.net/private/org-CWjU5cDIzgCcVjq10pp5yX5Q/user-GoBXgChvLBqLHdBiMJBUbPqF/img-WZVUK2dOD4HKbKwW1NeMJHBd.png?st=2022-12-19T11%3A38%3A25Z\u0026se=2022-12-19T13%3A38%3A25Z\u0026sp=r\u0026sv=2021-08-06\u0026sr=b\u0026rscd=inline\u0026rsct=image/png\u0026skoid=6aaadede-4fb3-4698-a8f6-684d7786b067\u0026sktid=a48cca56-e6da-484e-a814-9c849652bcb3\u0026skt=2022-12-19T09%3A35%3A16Z\u0026ske=2022-12-20T09%3A35%3A16Z\u0026sks=b\u0026skv=2021-08-06\u0026sig=mh52rmtbQ8CXArv5bMaU6lhgZHFBZz/ePr4y%2BJwLKOc%3D\"\n ```\n\n**Generated image**\n\n![Generated Image](https://user-images.githubusercontent.com/1411778/213134082-ba988a72-fca0-4213-8805-63e5f8324cab.png)\n\n### Create Image Edit\n\nCreates an edited or extended image given an original image and a prompt.\n\n**Request**\n\n```swift\npublic struct ImageEditsQuery: Codable {\n    /// The image to edit. Must be a valid PNG file, less than 4MB, and square. If mask is not provided, image must have transparency, which will be used as the mask.\n    public let image: Data\n    public let fileName: String\n    /// An additional image whose fully transparent areas (e.g. where alpha is zero) indicate where image should be edited. Must be a valid PNG file, less than 4MB, and have the same dimensions as image.\n    public let mask: Data?\n    public let maskFileName: String?\n    /// A text description of the desired image(s). The maximum length is 1000 characters.\n    public let prompt: String\n    /// The number of images to generate. Must be between 1 and 10.\n    public let n: Int?\n    /// The size of the generated images. Must be one of 256x256, 512x512, or 1024x1024.\n    public let size: String?\n}\n```\n\n**Response**\n\nUses the ImagesResult response similarly to ImagesQuery.\n\n**Example**\n\n```swift\nlet data = image.pngData()\nlet query = ImageEditQuery(image: data, fileName: \"whitecat.png\", prompt: \"White cat with heterochromia sitting on the kitchen table with a bowl of food\", n: 1, size: \"1024x1024\")\nopenAI.imageEdits(query: query) { result in\n  //Handle result here\n}\n//or\nlet result = try await openAI.imageEdits(query: query)\n```\n\n### Create Image Variation\n\nCreates a variation of a given image.\n\n**Request**\n\n```swift\npublic struct ImageVariationsQuery: Codable {\n    /// The image to edit. Must be a valid PNG file, less than 4MB, and square. If mask is not provided, image must have transparency, which will be used as the mask.\n    public let image: Data\n    public let fileName: String\n    /// The number of images to generate. Must be between 1 and 10.\n    public let n: Int?\n    /// The size of the generated images. Must be one of 256x256, 512x512, or 1024x1024.\n    public let size: String?\n}\n```\n\n**Response**\n\nUses the ImagesResult response similarly to ImagesQuery.\n\n**Example**\n\n```swift\nlet data = image.pngData()\nlet query = ImageVariationQuery(image: data, fileName: \"whitecat.png\", n: 1, size: \"1024x1024\")\nopenAI.imageVariations(query: query) { result in\n  //Handle result here\n}\n//or\nlet result = try await openAI.imageVariations(query: query)\n```\n\nReview [Images Documentation](https://platform.openai.com/docs/api-reference/images) for more info.\n\n### Audio\n\nThe speech to text API provides two endpoints, transcriptions and translations, based on our state-of-the-art open source large-v2 [Whisper model](https://openai.com/research/whisper). They can be used to:\n\nTranscribe audio into whatever language the audio is in.\nTranslate and transcribe the audio into english.\nFile uploads are currently limited to 25 MB and the following input file types are supported: mp3, mp4, mpeg, mpga, m4a, wav, and webm.\n\n#### Audio Create Speech\n\nThis function sends an `AudioSpeechQuery` to the OpenAI API to create audio speech from text using a specific voice and format. \n\n[Learn more about voices.](https://platform.openai.com/docs/guides/text-to-speech/voice-options)  \n[Learn more about models.](https://platform.openai.com/docs/models/tts)\n\n**Request:**  \n\n```swift\npublic struct AudioSpeechQuery: Codable, Equatable {\n    //...\n    public let model: Model // tts-1 or tts-1-hd  \n    public let input: String\n    public let voice: AudioSpeechVoice\n    public let responseFormat: AudioSpeechResponseFormat\n    public let speed: String? // Initializes with Double?\n    //...\n}\n```\n\n**Response:**\n\n```swift\n/// Audio data for one of the following formats :`mp3`, `opus`, `aac`, `flac`, `pcm`\npublic let audioData: Data?\n```\n\n**Example:**   \n\n```swift\nlet query = AudioSpeechQuery(model: .tts_1, input: \"Hello, world!\", voice: .alloy, responseFormat: .mp3, speed: 1.0)\n\nopenAI.audioCreateSpeech(query: query) { result in\n    // Handle response here\n}\n//or\nlet result = try await openAI.audioCreateSpeech(query: query)\n```\n[OpenAI Create Speech – Documentation](https://platform.openai.com/docs/api-reference/audio/createSpeech)\n\n#### Audio Create Speech Streaming\n\nAudio Create Speech is available by using `audioCreateSpeechStream` function. Tokens will be sent one-by-one.\n\n**Closures**\n```swift\nopenAI.audioCreateSpeechStream(query: query) { partialResult in\n    switch partialResult {\n    case .success(let result):\n        print(result.audio)\n    case .failure(let error):\n        //Handle chunk error here\n    }\n} completion: { error in\n    //Handle streaming error here\n}\n```\n\n**Combine**\n\n```swift\nopenAI\n    .audioCreateSpeechStream(query: query)\n    .sink { completion in\n        //Handle completion result here\n    } receiveValue: { result in\n        //Handle chunk here\n    }.store(in: \u0026cancellables)\n```\n\n**Structured concurrency**\n```swift\nfor try await result in openAI.audioCreateSpeechStream(query: query) {\n   //Handle result here\n}\n```\n\n#### Audio Transcriptions\n\nTranscribes audio into the input language.\n\n**Request**\n\n```swift\npublic struct AudioTranscriptionQuery: Codable, Equatable {\n    \n    public let file: Data\n    public let fileName: String\n    public let model: Model\n    \n    public let prompt: String?\n    public let temperature: Double?\n    public let language: String?\n}\n```\n\n**Response**\n\n```swift\npublic struct AudioTranscriptionResult: Codable, Equatable {\n    \n    public let text: String\n}\n```\n\n**Example**\n\n```swift\nlet data = Data(contentsOfURL:...)\nlet query = AudioTranscriptionQuery(file: data, fileName: \"audio.m4a\", model: .whisper_1)        \n\nopenAI.audioTranscriptions(query: query) { result in\n    //Handle result here\n}\n//or\nlet result = try await openAI.audioTranscriptions(query: query)\n```\n\n#### Audio Translations\n\nTranslates audio into into English.\n\n**Request**\n\n```swift\npublic struct AudioTranslationQuery: Codable, Equatable {\n    \n    public let file: Data\n    public let fileName: String\n    public let model: Model\n    \n    public let prompt: String?\n    public let temperature: Double?\n}    \n```\n\n**Response**\n\n```swift\npublic struct AudioTranslationResult: Codable, Equatable {\n    \n    public let text: String\n}\n```\n\n**Example**\n\n```swift\nlet data = Data(contentsOfURL:...)\nlet query = AudioTranslationQuery(file: data, fileName: \"audio.m4a\", model: .whisper_1)  \n\nopenAI.audioTranslations(query: query) { result in\n    //Handle result here\n}\n//or\nlet result = try await openAI.audioTranslations(query: query)\n```\n\nReview [Audio Documentation](https://platform.openai.com/docs/api-reference/audio) for more info.\n\n### Embeddings\n\nGet a vector representation of a given input that can be easily consumed by machine learning models and algorithms.\n\n**Request**\n\n```swift\nstruct EmbeddingsQuery: Codable {\n    /// ID of the model to use.\n    public let model: Model\n    /// Input text to get embeddings for\n    public let input: String\n}\n```\n\n**Response**\n\n```swift\nstruct EmbeddingsResult: Codable, Equatable {\n\n    public struct Embedding: Codable, Equatable {\n\n        public let object: String\n        public let embedding: [Double]\n        public let index: Int\n    }\n    public let data: [Embedding]\n    public let usage: Usage\n}\n```\n\n**Example**\n\n```swift\nlet query = EmbeddingsQuery(model: .textSearchBabbageDoc, input: \"The food was delicious and the waiter...\")\nopenAI.embeddings(query: query) { result in\n  //Handle response here\n}\n//or\nlet result = try await openAI.embeddings(query: query)\n```\n\n```\n(lldb) po result\n▿ EmbeddingsResult\n  ▿ data : 1 element\n    ▿ 0 : Embedding\n      - object : \"embedding\"\n      ▿ embedding : 2048 elements\n        - 0 : 0.0010535449\n        - 1 : 0.024234328\n        - 2 : -0.0084999\n        - 3 : 0.008647452\n    .......\n        - 2044 : 0.017536353\n        - 2045 : -0.005897616\n        - 2046 : -0.026559394\n        - 2047 : -0.016633155\n      - index : 0\n\n(lldb)\n```\n\nReview [Embeddings Documentation](https://platform.openai.com/docs/api-reference/embeddings) for more info.\n\n### Models \n\nModels are represented as a typealias `typealias Model = String`.\n\n```swift\npublic extension Model {\n    static let gpt4_1 = \"gpt-4.1\"\n    static let gpt4_1_mini = \"gpt-4.1-mini\"\n    static let gpt4_1_nano = \"gpt-4.1-nano\"\n\n    static let gpt4_turbo_preview = \"gpt-4-turbo-preview\"\n    static let gpt4_vision_preview = \"gpt-4-vision-preview\"\n    static let gpt4_0125_preview = \"gpt-4-0125-preview\"\n    static let gpt4_1106_preview = \"gpt-4-1106-preview\"\n    static let gpt4 = \"gpt-4\"\n    static let gpt4_0613 = \"gpt-4-0613\"\n    static let gpt4_0314 = \"gpt-4-0314\"\n    static let gpt4_32k = \"gpt-4-32k\"\n    static let gpt4_32k_0613 = \"gpt-4-32k-0613\"\n    static let gpt4_32k_0314 = \"gpt-4-32k-0314\"\n    \n    static let gpt3_5Turbo = \"gpt-3.5-turbo\"\n    static let gpt3_5Turbo_0125 = \"gpt-3.5-turbo-0125\"\n    static let gpt3_5Turbo_1106 = \"gpt-3.5-turbo-1106\"\n    static let gpt3_5Turbo_0613 = \"gpt-3.5-turbo-0613\"\n    static let gpt3_5Turbo_0301 = \"gpt-3.5-turbo-0301\"\n    static let gpt3_5Turbo_16k = \"gpt-3.5-turbo-16k\"\n    static let gpt3_5Turbo_16k_0613 = \"gpt-3.5-turbo-16k-0613\"\n    \n    static let textDavinci_003 = \"text-davinci-003\"\n    static let textDavinci_002 = \"text-davinci-002\"\n    static let textCurie = \"text-curie-001\"\n    static let textBabbage = \"text-babbage-001\"\n    static let textAda = \"text-ada-001\"\n    \n    static let textDavinci_001 = \"text-davinci-001\"\n    static let codeDavinciEdit_001 = \"code-davinci-edit-001\"\n    \n    static let tts_1 = \"tts-1\"\n    static let tts_1_hd = \"tts-1-hd\"\n    \n    static let whisper_1 = \"whisper-1\"\n\n    static let dall_e_2 = \"dall-e-2\"\n    static let dall_e_3 = \"dall-e-3\"\n    \n    static let davinci = \"davinci\"\n    static let curie = \"curie\"\n    static let babbage = \"babbage\"\n    static let ada = \"ada\"\n    \n    static let textEmbeddingAda = \"text-embedding-ada-002\"\n    static let textSearchAda = \"text-search-ada-doc-001\"\n    static let textSearchBabbageDoc = \"text-search-babbage-doc-001\"\n    static let textSearchBabbageQuery001 = \"text-search-babbage-query-001\"\n    static let textEmbedding3 = \"text-embedding-3-small\"\n    static let textEmbedding3Large = \"text-embedding-3-large\"\n    \n    static let textModerationStable = \"text-moderation-stable\"\n    static let textModerationLatest = \"text-moderation-latest\"\n    static let moderation = \"text-moderation-007\"\n}\n```\n\nGPT-4 models are supported. \n\nAs an example: To use the `gpt-4-turbo-preview` model, pass `.gpt4_turbo_preview` as the parameter to the `ChatQuery` init.\n\n```swift\nlet query = ChatQuery(model: .gpt4_turbo_preview, messages: [\n    .init(role: .system, content: \"You are Librarian-GPT. You know everything about the books.\"),\n    .init(role: .user, content: \"Who wrote Harry Potter?\")\n])\nlet result = try await openAI.chats(query: query)\nXCTAssertFalse(result.choices.isEmpty)\n```\n\nYou can also pass a custom string if you need to use some model, that is not represented above.\n\n#### List Models\n\nLists the currently available models.\n\n**Response**\n\n```swift\npublic struct ModelsResult: Codable, Equatable {\n    \n    public let data: [ModelResult]\n    public let object: String\n}\n\n```\n**Example**\n\n```swift\nopenAI.models() { result in\n  //Handle result here\n}\n//or\nlet result = try await openAI.models()\n```\n\n#### Retrieve Model\n\nRetrieves a model instance, providing ownership information.\n\n**Request**\n\n```swift\npublic struct ModelQuery: Codable, Equatable {\n    \n    public let model: Model\n}    \n```\n\n**Response**\n\n```swift\npublic struct ModelResult: Codable, Equatable {\n\n    public let id: Model\n    public let object: String\n    public let ownedBy: String\n}\n```\n\n**Example**\n\n```swift\nlet query = ModelQuery(model: .gpt4)\nopenAI.model(query: query) { result in\n  //Handle result here\n}\n//or\nlet result = try await openAI.model(query: query)\n```\n\nReview [Models Documentation](https://platform.openai.com/docs/api-reference/models) for more info.\n\n### Moderations \n\nGiven a input text, outputs if the model classifies it as violating OpenAI's content policy.\n\n**Request**\n\n```swift\npublic struct ModerationsQuery: Codable {\n    \n    public let input: String\n    public let model: Model?\n}    \n```\n\n**Response**\n\n```swift\npublic struct ModerationsResult: Codable, Equatable {\n\n    public let id: String\n    public let model: Model\n    public let results: [CategoryResult]\n}\n```\n\n**Example**\n\n```swift\nlet query = ModerationsQuery(input: \"I want to kill them.\")\nopenAI.moderations(query: query) { result in\n  //Handle result here\n}\n//or\nlet result = try await openAI.moderations(query: query)\n```\n\nReview [Moderations Documentation](https://platform.openai.com/docs/api-reference/moderations) for more info.\n\n### Utilities\n\nThe component comes with several handy utility functions to work with the vectors.\n\n```swift\npublic struct Vector {\n\n    /// Returns the similarity between two vectors\n    ///\n    /// - Parameters:\n    ///     - a: The first vector\n    ///     - b: The second vector\n    public static func cosineSimilarity(a: [Double], b: [Double]) -\u003e Double {\n        return dot(a, b) / (mag(a) * mag(b))\n    }\n\n    /// Returns the difference between two vectors. Cosine distance is defined as `1 - cosineSimilarity(a, b)`\n    ///\n    /// - Parameters:\n    ///     - a: The first vector\n    ///     - b: The second vector\n    public func cosineDifference(a: [Double], b: [Double]) -\u003e Double {\n        return 1 - Self.cosineSimilarity(a: a, b: b)\n    }\n}\n```\n\n**Example**\n\n```swift\nlet vector1 = [0.213123, 0.3214124, 0.421412, 0.3214521251, 0.412412, 0.3214124, 0.1414124, 0.3214521251, 0.213123, 0.3214124, 0.1414124, 0.4214214, 0.213123, 0.3214124, 0.1414124, 0.3214521251, 0.213123, 0.3214124, 0.1414124, 0.3214521251]\nlet vector2 = [0.213123, 0.3214124, 0.1414124, 0.3214521251, 0.213123, 0.3214124, 0.1414124, 0.3214521251, 0.213123, 0.511515, 0.1414124, 0.3214521251, 0.213123, 0.3214124, 0.1414124, 0.3214521251, 0.213123, 0.3214124, 0.1414124, 0.3213213]\nlet similarity = Vector.cosineSimilarity(a: vector1, b: vector2)\nprint(similarity) //0.9510201910206734\n```\n\u003eIn data analysis, cosine similarity is a measure of similarity between two sequences of numbers.\n\n\u003cimg width=\"574\" alt=\"Screenshot 2022-12-19 at 6 00 33 PM\" src=\"https://user-images.githubusercontent.com/1411778/208467903-000b52d8-6589-40dd-b020-eeed69e8d284.png\"\u003e\n\nRead more about Cosine Similarity [here](https://en.wikipedia.org/wiki/Cosine_similarity).\n\n### Combine Extensions\n\nThe library contains built-in [Combine](https://developer.apple.com/documentation/combine) extensions.\n\n```swift\nfunc images(query: ImagesQuery) -\u003e AnyPublisher\u003cImagesResult, Error\u003e\nfunc embeddings(query: EmbeddingsQuery) -\u003e AnyPublisher\u003cEmbeddingsResult, Error\u003e\nfunc chats(query: ChatQuery) -\u003e AnyPublisher\u003cChatResult, Error\u003e\nfunc model(query: ModelQuery) -\u003e AnyPublisher\u003cModelResult, Error\u003e\nfunc models() -\u003e AnyPublisher\u003cModelsResult, Error\u003e\nfunc moderations(query: ModerationsQuery) -\u003e AnyPublisher\u003cModerationsResult, Error\u003e\nfunc audioTranscriptions(query: AudioTranscriptionQuery) -\u003e AnyPublisher\u003cAudioTranscriptionResult, Error\u003e\nfunc audioTranslations(query: AudioTranslationQuery) -\u003e AnyPublisher\u003cAudioTranslationResult, Error\u003e\n```\n\n### Assistants\n\nReview [Assistants Documentation](https://platform.openai.com/docs/api-reference/assistants) for more info.\n\n#### Create Assistant\n\nExample: Create Assistant\n```swift\nlet query = AssistantsQuery(model: Model.gpt4_o_mini, name: name, description: description, instructions: instructions, tools: tools, toolResources: toolResources)\nopenAI.assistantCreate(query: query) { result in\n   //Handle response here\n}\n```\n\n#### Modify Assistant\n\nExample: Modify Assistant\n```swift\nlet query = AssistantsQuery(model: Model.gpt4_o_mini, name: name, description: description, instructions: instructions, tools: tools, toolResources: toolResources)\nopenAI.assistantModify(query: query, assistantId: \"asst_1234\") { result in\n    //Handle response here\n}\n```\n\n#### List Assistants\n\nExample: List Assistants\n```swift\nopenAI.assistants() { result in\n   //Handle response here\n}\n```\n\n#### Threads\n\nReview [Threads Documentation](https://platform.openai.com/docs/api-reference/threads) for more info.\n\n##### Create Thread\n\nExample: Create Thread\n```swift\nlet threadsQuery = ThreadsQuery(messages: [Chat(role: message.role, content: message.content)])\nopenAI.threads(query: threadsQuery) { result in\n  //Handle response here\n}\n```\n\n##### Create and Run Thread\n\nExample: Create and Run Thread\n```swift\nlet threadsQuery = ThreadQuery(messages: [Chat(role: message.role, content: message.content)])\nlet threadRunQuery = ThreadRunQuery(assistantId: \"asst_1234\"  thread: threadsQuery)\nopenAI.threadRun(query: threadRunQuery) { result in\n  //Handle response here\n}\n```\n\n##### Get Threads Messages\n\nReview [Messages Documentation](https://platform.openai.com/docs/api-reference/messages) for more info.\n\nExample: Get Threads Messages\n```swift\nopenAI.threadsMessages(threadId: currentThreadId) { result in\n  //Handle response here\n}\n```\n\n##### Add Message to Thread\n\nExample: Add Message to Thread\n```swift\nlet query = MessageQuery(role: message.role.rawValue, content: message.content)\nopenAI.threadsAddMessage(threadId: currentThreadId, query: query) { result in\n  //Handle response here\n}\n```\n\n#### Runs\n\nReview [Runs Documentation](https://platform.openai.com/docs/api-reference/runs) for more info.\n\n##### Create Run\n\nExample: Create Run\n```swift\nlet runsQuery = RunsQuery(assistantId:  currentAssistantId)\nopenAI.runs(threadId: threadsResult.id, query: runsQuery) { result in\n  //Handle response here\n}\n```\n\n##### Retrieve Run\n\nExample: Retrieve Run\n```swift\nopenAI.runRetrieve(threadId: currentThreadId, runId: currentRunId) { result in\n  //Handle response here\n}\n```\n\n##### Retrieve Run Steps\n\nExample: Retrieve Run Steps\n```swift\nopenAI.runRetrieveSteps(threadId: currentThreadId, runId: currentRunId) { result in\n  //Handle response here\n}\n```\n\n##### Submit Tool Outputs for Run\n\nExample: Submit Tool Outputs for Run\n```swift\nlet output = RunToolOutputsQuery.ToolOutput(toolCallId: \"call123\", output: \"Success\")\nlet query = RunToolOutputsQuery(toolOutputs: [output])\nopenAI.runSubmitToolOutputs(threadId: currentThreadId, runId: currentRunId, query: query) { result in\n  //Handle response here\n}\n```\n\n#### Files\n\nReview [Files Documentation](https://platform.openai.com/docs/api-reference/files) for more info.\n\n##### Upload file\n\nExample: Upload file\n```swift\nlet query = FilesQuery(purpose: \"assistants\", file: fileData, fileName: url.lastPathComponent, contentType: \"application/pdf\")\nopenAI.files(query: query) { result in\n  //Handle response here\n}\n```\n\n### Cancelling requests\n#### Closure based API\nWhen you call any of the closure-based API methods, it returns discardable `CancellableRequest`. Hold a reference to it to be able to cancel the request later.\n```swift\nlet cancellableRequest = object.chats(query: query, completion: { _ in })\ncancellableReques\n```\n\n#### Swift Concurrency\nFor Swift Concurrency calls, you can simply cancel the calling task, and corresponding `URLSessionDataTask` would get cancelled automatically.\n```swift\nlet task = Task {\n    do {\n        let chatResult = try await openAIClient.chats(query: .init(messages: [], model: \"asd\"))\n    } catch {\n        // Handle cancellation or error\n    }\n}\n            \ntask.cancel()\n```\n\n#### Combine\nIn Combine, use a default cancellation mechanism. Just discard the reference to a subscription, or call `cancel()` on it.\n\n```swift\nlet subscription = openAIClient\n    .images(query: query)\n    .sink(receiveCompletion: { completion in }, receiveValue: { imagesResult in })\n    \nsubscription.cancel()\n```\n\n## Support for other providers\n\n\u003e TL;DR Use `.relaxed` parsing option on Configuration\n\nThis SDK has a limited support for other providers like Gemini, Perplexity etc.\n\nThe top priority of this SDK is OpenAI, and the main rule is for all the main types to be fully compatible with [OpenAI's API Reference](https://platform.openai.com/docs/api-reference/introduction). If it says a field should be optional, it must be optional in main subset of Query/Result types of this SDK. The same goes for other info declared in the reference, like default values.\n\nThat said we still want to give a support for other providers.\n\n### Option 1: Use `.relaxed` parsing option\n`.relaxed` parsing option handles both missing and additional key/values in responses. It should be sufficient for most use-cases. Let us know if it doesn't cover any case you need.\n\n### Option 2: Specify parsing options separately\n#### Handle missing keys in responses\nSome providers return responses that don't completely satisfy OpenAI's scheme. Like, Gemini chat completion response ommits `id` field which is a required field in OpenAI's API Reference.\n\nIn such case use `fillRequiredFieldIfKeyNotFound` Parsing Option, like this:\n```swift\nlet configuration = OpenAI.Configuration(token: \"\", parsingOptions: .fillRequiredFieldIfKeyNotFound)\n```\n\n#### Handle missing values in responses\nSome fields are required to be present (non-optional) by OpenAI, but other providers may return `null` for them.\n\nUse `.fillRequiredFieldIfValueNotFound` to handle missing values\n\n#### What if a provider returns additional fields?\nCurrently we handle such cases by simply adding additional fields to main model set. This is possible because optional fields wouldn't break or conflict with OpenAI's scheme. At the moment, such additional fields are added:\n\n`ChatResult`\n\n* `citations` [Perplexity](https://docs.perplexity.ai/api-reference/chat-completions#response-citations)\n\n`ChatResult.Choice.Message`\n\n* `reasoningContent` [Grok](https://docs.x.ai/docs/api-reference#chat-completions), [DeepSeek](https://api-docs.deepseek.com/api/create-chat-completion#responses)\n* `reasoning` [OpenRouter](https://openrouter.ai/docs/use-cases/reasoning-tokens#basic-usage-with-reasoning-tokens)\n\n## Example Project\n\nYou can find example iOS application in [Demo](/Demo) folder. \n\n![mockuuups-iphone-13-pro-mockup-perspective-right](https://user-images.githubusercontent.com/1411778/231449395-2ad6bab6-c21f-43dc-8977-f45f505b609d.png)\n\n## Contribution Guidelines\nMake your Pull Requests clear and obvious to anyone viewing them.  \nSet `main` as your target branch.\n\n#### Use [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/) principles in naming PRs and branches:\n\n- `Feat: ...` for new features and new functionality implementations.\n- `Bug: ...` for bug fixes.\n- `Fix: ...` for minor issues fixing, like typos or inaccuracies in code.\n- `Chore: ...` for boring stuff like code polishing, refactoring, deprecation fixing etc.\n\nPR naming example: `Feat: Add Threads API handling` or `Bug: Fix message result duplication`\n\nBranch naming example: `feat/add-threads-API-handling` or `bug/fix-message-result-duplication`\n\n#### Write description to pull requests in following format:\n- What\n\n  ...\n- Why\n  \n  ...\n- Affected Areas\n\n  ...\n- More Info\n\n  ...\n\nWe'll appreciate you including tests to your code if it is needed and possible. ❤️\n\n## Links\n\n- [OpenAI Documentation](https://platform.openai.com/docs/introduction)\n- [OpenAI Playground](https://platform.openai.com/playground)\n- [OpenAI Examples](https://platform.openai.com/examples)\n- [Dall-E](https://labs.openai.com/)\n- [Cosine Similarity](https://en.wikipedia.org/wiki/Cosine_similarity)\n\n## License\n\n```\nMIT License\n\nCopyright (c) 2023 MacPaw Inc.\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n```\n","funding_links":[],"categories":["Unity"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmacpaw%2Fopenai","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmacpaw%2Fopenai","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmacpaw%2Fopenai/lists"}