{"id":28627780,"url":"https://github.com/jamesrochabrun/swiftopenai","last_synced_at":"2025-10-13T22:47:30.585Z","repository":{"id":199622077,"uuid":"702866451","full_name":"jamesrochabrun/SwiftOpenAI","owner":"jamesrochabrun","description":"The most complete open-source Swift package for interacting with OpenAI's public API.","archived":false,"fork":false,"pushed_at":"2025-10-04T18:14:13.000Z","size":1686,"stargazers_count":592,"open_issues_count":9,"forks_count":113,"subscribers_count":10,"default_branch":"main","last_synced_at":"2025-10-04T19:28:03.313Z","etag":null,"topics":["chatgpt-api","ios","openai","openai-api","spm","swift","swiftpackage"],"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/jamesrochabrun.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2023-10-10T06:57:32.000Z","updated_at":"2025-10-04T18:14:14.000Z","dependencies_parsed_at":"2023-11-26T08:20:07.017Z","dependency_job_id":"425f8a1b-3f88-4938-ab61-ea573655ffa0","html_url":"https://github.com/jamesrochabrun/SwiftOpenAI","commit_stats":null,"previous_names":["jamesrochabrun/openai","jamesrochabrun/swiftopenai"],"tags_count":56,"template":false,"template_full_name":null,"purl":"pkg:github/jamesrochabrun/SwiftOpenAI","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jamesrochabrun%2FSwiftOpenAI","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jamesrochabrun%2FSwiftOpenAI/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jamesrochabrun%2FSwiftOpenAI/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jamesrochabrun%2FSwiftOpenAI/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jamesrochabrun","download_url":"https://codeload.github.com/jamesrochabrun/SwiftOpenAI/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jamesrochabrun%2FSwiftOpenAI/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":279017138,"owners_count":26085984,"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","status":"online","status_checked_at":"2025-10-13T02:00:06.723Z","response_time":61,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["chatgpt-api","ios","openai","openai-api","spm","swift","swiftpackage"],"created_at":"2025-06-12T10:01:30.051Z","updated_at":"2025-10-13T22:47:30.575Z","avatar_url":"https://github.com/jamesrochabrun.png","language":"Swift","funding_links":["https://buymeacoffee.com/jamesrochabrun"],"categories":["Openai"],"sub_categories":[],"readme":"# SwiftOpenAI\n\u003cimg width=\"1090\" alt=\"repoOpenAI\" src=\"https://github.com/jamesrochabrun/SwiftOpenAI/assets/5378604/51bc5736-a32f-4a9f-922e-209d950e28f7\"\u003e\n\n![iOS 15+](https://img.shields.io/badge/iOS-15%2B-blue.svg)\n![macOS 13+](https://img.shields.io/badge/macOS-13%2B-blue.svg)\n![watchOS 9+](https://img.shields.io/badge/watchOS-9%2B-blue.svg)\n![Linux](https://img.shields.io/badge/Linux-blue.svg)\n[![MIT license](https://img.shields.io/badge/License-MIT-blue.svg)](https://lbesson.mit-license.org/)\n[![swift-version](https://img.shields.io/badge/swift-5.9-brightgreen.svg)](https://github.com/apple/swift)\n[![swiftui-version](https://img.shields.io/badge/swiftui-brightgreen)](https://developer.apple.com/documentation/swiftui)\n[![xcode-version](https://img.shields.io/badge/xcode-15%20-brightgreen)](https://developer.apple.com/xcode/)\n[![swift-package-manager](https://img.shields.io/badge/package%20manager-compatible-brightgreen.svg?logo=data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyB3aWR0aD0iNjJweCIgaGVpZ2h0PSI0OXB4IiB2aWV3Qm94PSIwIDAgNjIgNDkiIHZlcnNpb249IjEuMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayI+CiAgICA8IS0tIEdlbmVyYXRvcjogU2tldGNoIDYzLjEgKDkyNDUyKSAtIGh0dHBzOi8vc2tldGNoLmNvbSAtLT4KICAgIDx0aXRsZT5Hcm91cDwvdGl0bGU+CiAgICA8ZGVzYz5DcmVhdGVkIHdpdGggU2tldGNoLjwvZGVzYz4KICAgIDxnIGlkPSJQYWdlLTEiIHN0cm9rZT0ibm9uZSIgc3Ryb2tlLXdpZHRoPSIxIiBmaWxsPSJub25lIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiPgogICAgICAgIDxnIGlkPSJHcm91cCIgZmlsbC1ydWxlPSJub256ZXJvIj4KICAgICAgICAgICAgPHBvbHlnb24gaWQ9IlBhdGgiIGZpbGw9IiNEQkI1NTEiIHBvaW50cz0iNTEuMzEwMzQ0OCAwIDEwLjY4OTY1NTIgMCAwIDEzLjUxNzI0MTQgMCA0OSA2MiA0OSA2MiAxMy41MTcyNDE0Ij48L3BvbHlnb24+CiAgICAgICAgICAgIDxwb2x5Z29uIGlkPSJQYXRoIiBmaWxsPSIjRjdFM0FGIiBwb2ludHM9IjI3IDI1IDMxIDI1IDM1IDI1IDM3IDI1IDM3IDE0IDI1IDE0IDI1IDI1Ij48L3BvbHlnb24+CiAgICAgICAgICAgIDxwb2x5Z29uIGlkPSJQYXRoIiBmaWxsPSIjRUZDNzVFIiBwb2ludHM9IjEwLjY4OTY1NTIgMCAwIDE0IDYyIDE0IDUxLjMxMDM0NDggMCI+PC9wb2x5Z29uPgogICAgICAgICAgICA8cG9seWdvbiBpZD0iUmVjdGFuZ2xlIiBmaWxsPSIjRjdFM0FGIiBwb2ludHM9IjI3IDAgMzUgMCAzNyAxNCAyNSAxNCI+PC9wb2x5Z29uPgogICAgICAgIDwvZz4KICAgIDwvZz4KPC9zdmc+)](https://github.com/apple/swift-package-manager)\n[![Buy me a coffee](https://img.shields.io/badge/Buy%20me%20a%20coffee-048754?logo=buymeacoffee)](https://buymeacoffee.com/jamesrochabrun)\n\nAn open-source Swift package designed for effortless interaction with OpenAI's public API. \n\n🚀 Now also available as [CLI](https://github.com/jamesrochabrun/SwiftOpenAICLI) and also as [MCP](https://github.com/jamesrochabrun/SwiftOpenAIMCP)\n\n## Table of Contents\n- [Description](#description)\n- [Getting an API Key](#getting-an-api-key)\n- [Installation](#installation)\n- [Compatibility](#compatibility)\n- [Usage](#usage)\n- [Collaboration](#collaboration)\n\n## Description\n\n`SwiftOpenAI` is an open-source Swift package that streamlines interactions with **all** OpenAI's API endpoints, now with added support for Azure, AIProxy, and Assistant stream APIs.\n\n### OpenAI ENDPOINTS\n\n- [Audio](#audio)\n   - [Transcriptions](#audio-transcriptions)\n   - [Translations](#audio-translations)\n   - [Speech](#audio-Speech)\n- [Chat](#chat)\n   - [Function Calling](#function-calling)\n   - [Structured Outputs](#structured-outputs)\n   - [Vision](#vision)\n- [Response](#response)\n   - [Streaming Responses](#streaming-responses)\n- [Embeddings](#embeddings)\n- [Fine-tuning](#fine-tuning)\n- [Batch](#batch)\n- [Files](#files)\n- [Images](#images)\n- [Models](#models)\n- [Moderations](#moderations)\n\n### **BETA**\n- [Assistants](#assistants)\n   - [Assistants File Object](#assistants-file-object)\n- [Threads](#threads)\n- [Messages](#messages)\n   - [Message File Object](#message-file-object)\n- [Runs](#runs)\n   - [Run Step object](#run-step-object)\n   - [Run Step details](#run-step-details)\n- [Assistants Streaming](#assistants-streaming)\n   - [Message Delta Object](#message-delta-object)\n   - [Run Step Delta Object](#run-step-delta-object)\n- [Vector Stores](#vector-stores)\n   - [Vector store File](#vector-store-file)\n   - [Vector store File Batch](#vector-store-file-batch)\n\n## Getting an API Key\n\n⚠️ **Important**\n\nTo interact with OpenAI services, you'll need an API key. Follow these steps to obtain one:\n\n1. Visit [OpenAI](https://www.openai.com/).\n2. Sign up for an [account](https://platform.openai.com/signup) or [log in](https://platform.openai.com/login) if you already have one.\n3. Navigate to the [API key page](https://platform.openai.com/account/api-keys) and follow the instructions to generate a new API key.\n\nFor more information, consult OpenAI's [official documentation](https://platform.openai.com/docs/).\n\n⚠️  Please take precautions to keep your API key secure per [OpenAI's guidance](https://platform.openai.com/docs/api-reference/authentication):\n\n\u003e Remember that your API key is a secret! Do not share it with others or expose\n\u003e it in any client-side code (browsers, apps). Production requests must be\n\u003e routed through your backend server where your API key can be securely\n\u003e loaded from an environment variable or key management service.\n\nSwiftOpenAI has built-in support for AIProxy, which is a backend for AI apps, to satisfy this requirement.\nTo configure AIProxy, see the instructions [here](#aiproxy).\n\n\n## Installation\n\n### Swift Package Manager\n\n1. Open your Swift project in Xcode.\n2. Go to `File` -\u003e  `Add Package Dependency`.\n3. In the search bar, enter [this URL](https://github.com/jamesrochabrun/SwiftOpenAI).\n4. Choose the version you'd like to install (see the note below).\n5. Click `Add Package`.\n\nNote: Xcode has a quirk where it defaults an SPM package's upper limit to 2.0.0. This package is beyond that\nlimit, so you should not accept the defaults that Xcode proposes. Instead, enter the lower bound of the\n[release version](https://github.com/jamesrochabrun/SwiftOpenAI/releases) that you'd like to support, and then\ntab out of the input box for Xcode to adjust the upper bound. Alternatively, you may select `branch` -\u003e `main`\nto stay on the bleeding edge.\n\n## Compatibility\n\n### Platform Support\n\nSwiftOpenAI supports both Apple platforms and Linux.\n- **Apple platforms** include iOS 15+, macOS 13+, and watchOS 9+.\n- **Linux**: SwiftOpenAI on Linux uses AsyncHTTPClient to work around URLSession bugs in Apple's Foundation framework, and can be used with the [Vapor](https://vapor.codes/) server framework.\n\n### OpenAI-Compatible Providers\n\nSwiftOpenAI supports various providers that are OpenAI-compatible, including but not limited to:\n\n- [Azure OpenAI](#azure-openai)\n- [Anthropic](#anthropic)\n- [Gemini](#gemini)\n- [Ollama](#ollama)\n- [Groq](#groq)\n- [xAI](#xai)\n- [OpenRouter](#openRouter)\n- [DeepSeek](#deepseek)\n- [AIProxy](#aiproxy)\n\nCheck OpenAIServiceFactory for convenience initializers that you can use to provide custom URLs.\n\n## Usage\n\nTo use SwiftOpenAI in your project, first import the package:\n\n```swift\nimport SwiftOpenAI\n```\n\nThen, initialize the service using your OpenAI API key:\n\n```swift\nlet apiKey = \"your_openai_api_key_here\"\nlet service = OpenAIServiceFactory.service(apiKey: apiKey)\n```\n\nYou can optionally specify an organization name if needed.\n\n```swift\nlet apiKey = \"your_openai_api_key_here\"\nlet oganizationID = \"your_organixation_id\"\nlet service = OpenAIServiceFactory.service(apiKey: apiKey, organizationID: oganizationID)\n```\n\nhttps://developer.apple.com/documentation/foundation/nsurlsessionconfiguration/1408259-timeoutintervalforrequest\n\nFor reasoning models, ensure that you extend the timeoutIntervalForRequest in the URL session configuration to a higher value. The default is 60 seconds, which may be insufficient, as requests to reasoning models can take longer to process and respond.\n\nTo configure it:\n\n```swift\nlet apiKey = \"your_openai_api_key_here\"\nlet organizationID = \"your_organization_id\"\nlet session = URLSession.shared\nsession.configuration.timeoutIntervalForRequest = 360 // e.g., 360 seconds or more.\nlet httpClient = URLSessionHTTPClientAdapter(urlSession: session)\nlet service = OpenAIServiceFactory.service(apiKey: apiKey, organizationID: organizationID, httpClient: httpClient)\n```\n\nThat's all you need to begin accessing the full range of OpenAI endpoints.\n\n### How to get the status code of network errors\n\nYou may want to build UI around the type of error that the API returns.\nFor example, a `429` means that your requests are being rate limited.\nThe `APIError` type has a case `responseUnsuccessful` with two associated values: a `description` and `statusCode`.\nHere is a usage example using the chat completion API:\n\n```swift\nlet service = OpenAIServiceFactory.service(apiKey: apiKey)\nlet parameters = ChatCompletionParameters(messages: [.init(role: .user, content: .text(\"hello world\"))],\n                                          model: .gpt4o)\ndo {\n   let choices = try await service.startChat(parameters: parameters).choices\n   // Work with choices\n} catch APIError.responseUnsuccessful(let description, let statusCode) {\n   print(\"Network error with status code: \\(statusCode) and description: \\(description)\")\n} catch {\n   print(error.localizedDescription)\n}\n```\n\n\n### Audio\n\n### Audio Transcriptions\nParameters\n```swift\npublic struct AudioTranscriptionParameters: Encodable {\n   \n   /// The name of the file asset is not documented in OpenAI's official documentation; however, it is essential for constructing the multipart request.\n   let fileName: String\n   /// The audio file object (not file name) translate, in one of these formats: flac, mp3, mp4, mpeg, mpga, m4a, ogg, wav, or webm.\n   let file: Data\n   /// ID of the model to use. Only whisper-1 is currently available.\n   let model: String\n   /// The language of the input audio. Supplying the input language in [ISO-639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) format will improve accuracy and latency.\n   let language: String?\n   /// An optional text to guide the model's style or continue a previous audio segment. The [prompt](https://platform.openai.com/docs/guides/speech-to-text/prompting) should match the audio language.\n   let prompt: String?\n   /// The format of the transcript output, in one of these options: json, text, srt, verbose_json, or vtt. Defaults to json\n   let responseFormat: String?\n   /// The sampling temperature, between 0 and 1. Higher values like 0.8 will make the output more random, while lower values like 0.2 will make it more focused and deterministic. If set to 0, the model will use [log probability](https://en.wikipedia.org/wiki/Log_probability) to automatically increase the temperature until certain thresholds are hit. Defaults to 0\n   let temperature: Double?\n   \n   public enum Model {\n      case whisperOne \n      case custom(model: String)\n   }\n   \n   public init(\n      fileName: String,\n      file: Data,\n      model: Model = .whisperOne,\n      prompt: String? = nil,\n      responseFormat: String? = nil,\n      temperature: Double? = nil,\n      language: String? = nil)\n   {\n      self.fileName = fileName\n      self.file = file\n      self.model = model.rawValue\n      self.prompt = prompt\n      self.responseFormat = responseFormat\n      self.temperature = temperature\n      self.language = language\n   }\n}\n```\n\nResponse\n```swift\npublic struct AudioObject: Decodable {\n   \n   /// The transcribed text if the request uses the `transcriptions` API, or the translated text if the request uses the `translations` endpoint.\n   public let text: String\n}\n```\n\nUsage\n```swift\nlet fileName = \"narcos.m4a\"\nlet data = Data(contentsOfURL:_) // Data retrieved from the file named \"narcos.m4a\".\nlet parameters = AudioTranscriptionParameters(fileName: fileName, file: data) // **Important**: in the file name always provide the file extension.\nlet audioObject =  try await service.createTranscription(parameters: parameters)\n```\n### Audio Translations\nParameters\n```swift\npublic struct AudioTranslationParameters: Encodable {\n   \n   /// The name of the file asset is not documented in OpenAI's official documentation; however, it is essential for constructing the multipart request.\n   let fileName: String\n   /// The audio file object (not file name) translate, in one of these formats: flac, mp3, mp4, mpeg, mpga, m4a, ogg, wav, or webm.\n   let file: Data\n   /// ID of the model to use. Only whisper-1 is currently available.\n   let model: String\n   /// An optional text to guide the model's style or continue a previous audio segment. The [prompt](https://platform.openai.com/docs/guides/speech-to-text/prompting) should match the audio language.\n   let prompt: String?\n   /// The format of the transcript output, in one of these options: json, text, srt, verbose_json, or vtt. Defaults to json\n   let responseFormat: String?\n   /// The sampling temperature, between 0 and 1. Higher values like 0.8 will make the output more random, while lower values like 0.2 will make it more focused and deterministic. If set to 0, the model will use [log probability](https://en.wikipedia.org/wiki/Log_probability) to automatically increase the temperature until certain thresholds are hit. Defaults to 0\n   let temperature: Double?\n   \n   public enum Model {\n      case whisperOne \n      case custom(model: String)\n   }\n   \n   public init(\n      fileName: String,\n      file: Data,\n      model: Model = .whisperOne,\n      prompt: String? = nil,\n      responseFormat: String? = nil,\n      temperature: Double? = nil)\n   {\n      self.fileName = fileName\n      self.file = file\n      self.model = model.rawValue\n      self.prompt = prompt\n      self.responseFormat = responseFormat\n      self.temperature = temperature\n   }\n}\n```\n\nResponse\n```swift\npublic struct AudioObject: Decodable {\n   \n   /// The transcribed text if the request uses the `transcriptions` API, or the translated text if the request uses the `translations` endpoint.\n   public let text: String\n}\n```\n\nUsage\n```swift\nlet fileName = \"german.m4a\"\nlet data = Data(contentsOfURL:_) // Data retrieved from the file named \"german.m4a\".\nlet parameters = AudioTranslationParameters(fileName: fileName, file: data) // **Important**: in the file name always provide the file extension.\nlet audioObject = try await service.createTranslation(parameters: parameters)\n```\n\n### Audio Speech\nParameters\n```swift\n/// [Generates audio from the input text.](https://platform.openai.com/docs/api-reference/audio/createSpeech)\npublic struct AudioSpeechParameters: Encodable {\n\n   /// One of the available [TTS models](https://platform.openai.com/docs/models/tts): tts-1 or tts-1-hd\n   let model: String\n   /// The text to generate audio for. The maximum length is 4096 characters.\n   let input: String\n   /// The voice to use when generating the audio. Supported voices are alloy, echo, fable, onyx, nova, and shimmer. Previews of the voices are available in the [Text to speech guide.](https://platform.openai.com/docs/guides/text-to-speech/voice-options)\n   let voice: String\n   /// Defaults to mp3, The format to audio in. Supported formats are mp3, opus, aac, and flac.\n   let responseFormat: String?\n   /// Defaults to 1,  The speed of the generated audio. Select a value from 0.25 to 4.0. 1.0 is the default.\n   let speed: Double?\n\n   public enum TTSModel: String {\n      case tts1 = \"tts-1\"\n      case tts1HD = \"tts-1-hd\"\n   }\n\n   public enum Voice: String {\n      case alloy\n      case echo\n      case fable\n      case onyx\n      case nova\n      case shimmer\n   }\n\n   public enum ResponseFormat: String {\n      case mp3\n      case opus\n      case aac\n      case flac\n   }\n   \n   public init(\n      model: TTSModel,\n      input: String,\n      voice: Voice,\n      responseFormat: ResponseFormat? = nil,\n      speed: Double? = nil)\n   {\n       self.model = model.rawValue\n       self.input = input\n       self.voice = voice.rawValue\n       self.responseFormat = responseFormat?.rawValue\n       self.speed = speed\n   }\n}\n```\n\nResponse\n```swift\n/// The [audio speech](https://platform.openai.com/docs/api-reference/audio/createSpeech) response.\npublic struct AudioSpeechObject: Decodable {\n\n   /// The audio file content data.\n   public let output: Data\n}\n```\n\nUsage\n```swift\nlet prompt = \"Hello, how are you today?\"\nlet parameters = AudioSpeechParameters(model: .tts1, input: prompt, voice: .shimmer)\nlet audioObjectData = try await service.createSpeech(parameters: parameters).output\nplayAudio(from: audioObjectData)\n\n// Play data\n private func playAudio(from data: Data) {\n       do {\n           // Initialize the audio player with the data\n           audioPlayer = try AVAudioPlayer(data: data)\n           audioPlayer?.prepareToPlay()\n           audioPlayer?.play()\n       } catch {\n           // Handle errors\n           print(\"Error playing audio: \\(error.localizedDescription)\")\n       }\n   }\n```\n\n### Chat\nParameters\n```swift\npublic struct ChatCompletionParameters: Encodable {\n   \n   /// A list of messages comprising the conversation so far. [Example Python code](https://cookbook.openai.com/examples/how_to_format_inputs_to_chatgpt_models)\n   public var messages: [Message]\n   /// ID of the model to use. See the [model endpoint compatibility](https://platform.openai.com/docs/models/how-we-use-your-data) table for details on which models work with the Chat API.\n   /// Supports GPT-4, GPT-4o, GPT-5, and other models. For GPT-5 family: .gpt5, .gpt5Mini, .gpt5Nano\n   public var model: String\n   /// Whether or not to store the output of this chat completion request for use in our [model distillation](https://platform.openai.com/docs/guides/distillation) or [evals](https://platform.openai.com/docs/guides/evals) products.\n   /// Defaults to false\n   public var store: Bool?\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. Defaults to 0\n   /// [See more information about frequency and presence penalties.](https://platform.openai.com/docs/guides/gpt/parameter-details)\n   public var frequencyPenalty: Double?\n   /// Controls how the model responds to function calls. none means the model does not call a function, and responds to the end-user. auto means the model can pick between an 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   @available(*, deprecated, message: \"Deprecated in favor of tool_choice.\")\n   public var functionCall: FunctionCall?\n   /// Controls which (if any) function is called by the model. none means the model will not call a function and instead generates a message. \n   /// auto means the model can pick between generating a message or calling a function. Specifying a particular function via `{\"type: \"function\", \"function\": {\"name\": \"my_function\"}}` forces the model to call that function.\n   /// `none` is the default when no functions are present. auto is the default if functions are present.\n   public var toolChoice: ToolChoice?\n   /// A list of functions the model may generate JSON inputs for.\n   @available(*, deprecated, message: \"Deprecated in favor of tools.\")\n   public var functions: [ChatFunction]?\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 var tools: [Tool]?\n   /// Whether to enable parallel function calling during tool use. Defaults to true.\n   public var parallelToolCalls: Bool?\n   /// Modify the likelihood of specified tokens appearing in the completion.\n   /// Accepts a json object that maps tokens (specified by their token ID in the tokenizer) to an associated bias value from -100 to 100. Mathematically, the bias is added to the logits generated by the model prior to sampling. The exact effect will vary per model, but values between -1 and 1 should decrease or increase likelihood of selection; values like -100 or 100 should result in a ban or exclusive selection of the relevant token. Defaults to null.\n   public var logitBias: [Int: Double]?\n   /// Whether to return log probabilities of the output tokens or not. If true, returns the log probabilities of each output token returned in the content of message. This option is currently not available on the gpt-4-vision-preview model. Defaults to false.\n   public var logprobs: Bool?\n   /// An integer between 0 and 5 specifying the number of most likely tokens to return at each token position, each with an associated log probability. logprobs must be set to true if this parameter is used.\n   public var topLogprobs: Int?\n   /// The maximum number of [tokens](https://platform.openai.com/tokenizer) that can be generated in the chat completion. This value can be used to control [costs](https://openai.com/api/pricing/) for text generated via API.\n   /// This value is now deprecated in favor of max_completion_tokens, and is not compatible with [o1 series models](https://platform.openai.com/docs/guides/reasoning)\n   public var maxTokens: Int?\n   /// An upper bound for the number of tokens that can be generated for a completion, including visible output tokens and [reasoning tokens](https://platform.openai.com/docs/guides/reasoning)\n   public var maCompletionTokens: Int?\n   /// How many chat completion choices to generate for each input message. Defaults to 1.\n   public var n: Int?\n   /// Output types that you would like the model to generate for this request. Most models are capable of generating text, which is the default:\n   /// [\"text\"]\n   ///The gpt-4o-audio-preview model can also be used to [generate audio](https://platform.openai.com/docs/guides/audio). To request that this model generate both text and audio responses, you can use:\n   /// [\"text\", \"audio\"]\n   public var modalities: [String]?\n   /// Parameters for audio output. Required when audio output is requested with modalities: [\"audio\"]. [Learn more.](https://platform.openai.com/docs/guides/audio)\n   public var audio: Audio?\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. Defaults to 0\n   /// [See more information about frequency and presence penalties.](https://platform.openai.com/docs/guides/gpt/parameter-details)\n   public var presencePenalty: Double?\n   /// An object specifying the format that the model must output. Used to enable JSON mode.\n   /// Setting to `{ type: \"json_object\" }` enables `JSON` mode, which guarantees the message the model generates is valid JSON.\n   ///Important: when using `JSON` mode you must still instruct the model to produce `JSON` yourself via some conversation message, for example via your system message. If you don't do this, the model may generate an unending stream of whitespace until the generation reaches the token limit, which may take a lot of time and give the appearance of a \"stuck\" request. Also note that the message content may be partial (i.e. cut off) if `finish_reason=\"length\"`, which indicates the generation exceeded `max_tokens` or the conversation exceeded the max context length.\n   public var responseFormat: ResponseFormat?\n   /// Specifies the latency tier to use for processing the request. This parameter is relevant for customers subscribed to the scale tier service:\n   /// If set to 'auto', the system will utilize scale tier credits until they are exhausted.\n   /// If set to 'default', the request will be processed in the shared cluster.\n   /// When this parameter is set, the response body will include the service_tier utilized.\n   public var serviceTier: String?\n   /// This feature is in `Beta`. If specified, our system will make a best effort to sample deterministically, such that repeated requests with the same `seed` and parameters should return the same result.\n   /// Determinism is not guaranteed, and you should refer to the `system_fingerprint` response parameter to monitor changes in the backend.\n   public var seed: Int?\n   /// Up to 4 sequences where the API will stop generating further tokens. Defaults to null.\n   public var stop: [String]?\n   /// If set, partial message deltas will be sent, like in ChatGPT. Tokens will be sent as data-only [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#event_stream_format) as they become available, with the stream terminated by a data: [DONE] message. [Example Python code](https://cookbook.openai.com/examples/how_to_stream_completions ).\n   /// Defaults to false.\n   var stream: Bool? = nil\n   /// Options for streaming response. Only set this when you set stream: true\n   var streamOptions: StreamOptions?\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 deterministic.\n   /// We generally recommend altering this or `top_p` but not both. Defaults to 1.\n   public var 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   /// We generally recommend altering this or `temperature` but not both. Defaults to 1\n   public var topP: Double?\n   /// A unique identifier representing your end-user, which can help OpenAI to monitor and detect abuse.\n   /// [Learn more](https://platform.openai.com/docs/guides/safety-best-practices/end-user-ids).\n   public var user: String?\n   \n   public struct Message: Encodable {\n      \n      /// The role of the messages author. One of system, user, assistant, or tool message.\n      let role: String\n      /// The contents of the message. content is required for all messages, and may be null for assistant messages with function calls.\n      let content: ContentType\n      /// The name of the author of this message. name is required if role is function, and it should be the name of the function whose response is in the content. May contain a-z, A-Z, 0-9, and underscores, with a maximum length of 64 characters.\n      let name: String?\n      /// The name and arguments of a function that should be called, as generated by the model.\n      @available(*, deprecated, message: \"Deprecated and replaced by `tool_calls`\")\n      let functionCall: FunctionCall?\n      /// The tool calls generated by the model, such as function calls.\n      let toolCalls: [ToolCall]?\n      /// Tool call that this message is responding to.\n      let toolCallID: String?\n      \n      public enum ContentType: Encodable {\n         \n         case text(String)\n         case contentArray([MessageContent])\n         \n         public func encode(to encoder: Encoder) throws {\n            var container = encoder.singleValueContainer()\n            switch self {\n            case .text(let text):\n               try container.encode(text)\n            case .contentArray(let contentArray):\n               try container.encode(contentArray)\n            }\n         }\n         \n         public enum MessageContent: Encodable, Equatable, Hashable {\n            \n            case text(String)\n            case imageUrl(ImageDetail)\n            \n            public struct ImageDetail: Encodable, Equatable, Hashable {\n               \n               public let url: URL\n               public let detail: String?\n               \n               enum CodingKeys: String, CodingKey {\n                  case url\n                  case detail\n               }\n               \n               public func encode(to encoder: Encoder) throws {\n                  var container = encoder.container(keyedBy: CodingKeys.self)\n                  try container.encode(url, forKey: .url)\n                  try container.encode(detail, forKey: .detail)\n               }\n               \n               public init(url: URL, detail: String? = nil) {\n                  self.url = url\n                  self.detail = detail\n               }\n            }\n            \n            enum CodingKeys: String, CodingKey {\n               case type\n               case text\n               case imageUrl = \"image_url\"\n            }\n            \n            public func encode(to encoder: Encoder) throws {\n               var container = encoder.container(keyedBy: CodingKeys.self)\n               switch self {\n               case .text(let text):\n                  try container.encode(\"text\", forKey: .type)\n                  try container.encode(text, forKey: .text)\n               case .imageUrl(let imageDetail):\n                  try container.encode(\"image_url\", forKey: .type)\n                  try container.encode(imageDetail, forKey: .imageUrl)\n               }\n            }\n            \n            public func hash(into hasher: inout Hasher) {\n               switch self {\n               case .text(let string):\n                  hasher.combine(string)\n               case .imageUrl(let imageDetail):\n                  hasher.combine(imageDetail)\n               }\n            }\n            \n            public static func ==(lhs: MessageContent, rhs: MessageContent) -\u003e Bool {\n               switch (lhs, rhs) {\n               case let (.text(a), .text(b)):\n                  return a == b\n               case let (.imageUrl(a), .imageUrl(b)):\n                  return a == b\n               default:\n                  return false\n               }\n            }\n         }\n      }\n      \n      public enum Role: String {\n         case system // content, role\n         case user // content, role\n         case assistant // content, role, tool_calls\n         case tool // content, role, tool_call_id\n      }\n      \n      enum CodingKeys: String, CodingKey {\n         case role\n         case content\n         case name\n         case functionCall = \"function_call\"\n         case toolCalls = \"tool_calls\"\n         case toolCallID = \"tool_call_id\"\n      }\n      \n      public init(\n         role: Role,\n         content: ContentType,\n         name: String? = nil,\n         functionCall: FunctionCall? = nil,\n         toolCalls: [ToolCall]? = nil,\n         toolCallID: String? = nil)\n      {\n         self.role = role.rawValue\n         self.content = content\n         self.name = name\n         self.functionCall = functionCall\n         self.toolCalls = toolCalls\n         self.toolCallID = toolCallID\n      }\n   }\n   \n   @available(*, deprecated, message: \"Deprecated in favor of ToolChoice.\")\n   public enum FunctionCall: Encodable, Equatable {\n      case none\n      case auto\n      case function(String)\n      \n      enum CodingKeys: String, CodingKey {\n         case none = \"none\"\n         case auto = \"auto\"\n         case function = \"name\"\n      }\n      \n      public func encode(to encoder: Encoder) throws {\n         switch self {\n         case .none:\n            var container = encoder.singleValueContainer()\n            try container.encode(CodingKeys.none.rawValue)\n         case .auto:\n            var container = encoder.singleValueContainer()\n            try container.encode(CodingKeys.auto.rawValue)\n         case .function(let name):\n            var container = encoder.container(keyedBy: CodingKeys.self)\n            try container.encode(name, forKey: .function)\n         }\n      }\n   }\n   \n   /// [Documentation](https://platform.openai.com/docs/api-reference/chat/create#chat-create-tools)\n   public struct Tool: Encodable {\n      \n      /// The type of the tool. Currently, only `function` is supported.\n      let type: String\n      /// object\n      let function: ChatFunction\n      \n      public init(\n         type: String = \"function\",\n         function: ChatFunction)\n      {\n         self.type = type\n         self.function = function\n      }\n   }\n   \n   public struct ChatFunction: Codable, Equatable {\n      \n      /// The name of the function to be called. Must be a-z, A-Z, 0-9, or contain underscores and dashes, with a maximum length of 64.\n      let name: String\n      /// A description of what the function does, used by the model to choose when and how to call the function.\n      let description: String?\n      /// The parameters the functions accepts, described as a JSON Schema object. See the [guide](https://platform.openai.com/docs/guides/gpt/function-calling) for examples, and the [JSON Schema reference](https://json-schema.org/understanding-json-schema) for documentation about the format.\n      /// Omitting parameters defines a function with an empty parameter list.\n      let parameters: JSONSchema?\n      /// Defaults to false, Whether to enable strict schema adherence when generating the function call. If set to true, the model will follow the exact schema defined in the parameters field. Only a subset of JSON Schema is supported when strict is true. Learn more about Structured Outputs in the [function calling guide].(https://platform.openai.com/docs/api-reference/chat/docs/guides/function-calling)\n      let strict: Bool?\n      \n      public init(\n         name: String,\n         strict: Bool?,\n         description: String?,\n         parameters: JSONSchema?)\n      {\n         self.name = name\n         self.strict = strict\n         self.description = description\n         self.parameters = parameters\n      }\n   }\n   \n   public enum ServiceTier: String, Encodable {\n      /// Specifies the latency tier to use for processing the request. This parameter is relevant for customers subscribed to the scale tier service:\n      /// If set to 'auto', the system will utilize scale tier credits until they are exhausted.\n      /// If set to 'default', the request will be processed in the shared cluster.\n      /// When this parameter is set, the response body will include the service_tier utilized.\n      case auto\n      case `default`\n   }\n   \n   public struct StreamOptions: Encodable {\n      /// If set, an additional chunk will be streamed before the data: [DONE] message.\n      /// The usage field on this chunk shows the token usage statistics for the entire request,\n      /// and the choices field will always be an empty array. All other chunks will also include\n      /// a usage field, but with a null value.\n      let includeUsage: Bool\n\n      enum CodingKeys: String, CodingKey {\n          case includeUsage = \"include_usage\"\n      }\n   }\n   \n   /// Parameters for audio output. Required when audio output is requested with modalities: [\"audio\"]\n   /// [Learn more.](https://platform.openai.com/docs/guides/audio)\n   public struct Audio: Encodable {\n      /// Specifies the voice type. Supported voices are alloy, echo, fable, onyx, nova, and shimmer.\n      public let voice: String\n      /// Specifies the output audio format. Must be one of wav, mp3, flac, opus, or pcm16.\n      public let format: String\n      \n      public init(\n         voice: String,\n         format: String)\n      {\n         self.voice = voice\n         self.format = format\n      }\n   }\n\n   enum CodingKeys: String, CodingKey {\n      case messages\n      case model\n      case store\n      case frequencyPenalty = \"frequency_penalty\"\n      case toolChoice = \"tool_choice\"\n      case functionCall = \"function_call\"\n      case tools\n      case parallelToolCalls = \"parallel_tool_calls\"\n      case functions\n      case logitBias = \"logit_bias\"\n      case logprobs\n      case topLogprobs = \"top_logprobs\"\n      case maxTokens = \"max_tokens\"\n      case maCompletionTokens = \"max_completion_tokens\"\n      case n\n      case modalities\n      case audio\n      case responseFormat = \"response_format\"\n      case presencePenalty = \"presence_penalty\"\n      case seed\n      case serviceTier = \"service_tier\"\n      case stop\n      case stream\n      case streamOptions = \"stream_options\"\n      case temperature\n      case topP = \"top_p\"\n      case user\n   }\n   \n   public init(\n      messages: [Message],\n      model: Model,\n      store: Bool? = nil,\n      frequencyPenalty: Double? = nil,\n      functionCall: FunctionCall? = nil,\n      toolChoice: ToolChoice? = nil,\n      functions: [ChatFunction]? = nil,\n      tools: [Tool]? = nil,\n      parallelToolCalls: Bool? = nil,\n      logitBias: [Int: Double]? = nil,\n      logProbs: Bool? = nil,\n      topLogprobs: Int? = nil,\n      maxTokens: Int? = nil,\n      n: Int? = nil,\n      modalities: [String]? = nil,\n      audio: Audio? = nil,\n      responseFormat: ResponseFormat? = nil,\n      presencePenalty: Double? = nil,\n      serviceTier: ServiceTier? = nil,\n      seed: Int? = nil,\n      stop: [String]? = nil,\n      temperature: Double? = nil,\n      topProbability: Double? = nil,\n      user: String? = nil)\n   {\n      self.messages = messages\n      self.model = model.value\n      self.store = store\n      self.frequencyPenalty = frequencyPenalty\n      self.functionCall = functionCall\n      self.toolChoice = toolChoice\n      self.functions = functions\n      self.tools = tools\n      self.parallelToolCalls = parallelToolCalls\n      self.logitBias = logitBias\n      self.logprobs = logProbs\n      self.topLogprobs = topLogprobs\n      self.maxTokens = maxTokens\n      self.n = n\n      self.modalities = modalities\n      self.audio = audio\n      self.responseFormat = responseFormat\n      self.presencePenalty = presencePenalty\n      self.serviceTier = serviceTier?.rawValue\n      self.seed = seed\n      self.stop = stop\n      self.temperature = temperature\n      self.topP = topProbability\n      self.user = user\n   }\n}\n```\n\nResponse\n### Chat completion object\n```swift\n/// Represents a chat [completion](https://platform.openai.com/docs/api-reference/chat/object) response returned by model, based on the provided input.\npublic struct ChatCompletionObject: Decodable {\n   \n   /// A unique identifier for the chat completion.\n   public let id: String\n   /// A list of chat completion choices. Can be more than one if n is greater than 1.\n   public let choices: [ChatChoice]\n   /// The Unix timestamp (in seconds) of when the chat completion was created.\n   public let created: Int\n   /// The model used for the chat completion.\n   public let model: String\n   /// The service tier used for processing the request. This field is only included if the service_tier parameter is specified in the request.\n   public let serviceTier: String?\n   /// This fingerprint represents the backend configuration that the model runs with.\n   /// Can be used in conjunction with the seed request parameter to understand when backend changes have been made that might impact determinism.\n   public let systemFingerprint: String?\n   /// The object type, which is always chat.completion.\n   public let object: String\n   /// Usage statistics for the completion request.\n   public let usage: ChatUsage\n   \n   public struct ChatChoice: Decodable {\n      \n      /// The reason the model stopped generating tokens. This will be stop if the model hit a natural stop point or a provided stop sequence, length if the maximum number of tokens specified in the request was reached, content_filter if content was omitted due to a flag from our content filters, tool_calls if the model called a tool, or function_call (deprecated) if the model called a function.\n      public let finishReason: IntOrStringValue?\n      /// The index of the choice in the list of choices.\n      public let index: Int\n      /// A chat completion message generated by the model.\n      public let message: ChatMessage   \n      /// Log probability information for the choice.\n      public let logprobs: LogProb?\n      \n      public struct ChatMessage: Decodable {\n         \n         /// The contents of the message.\n         public let content: String?\n         /// The tool calls generated by the model, such as function calls.\n         public let toolCalls: [ToolCall]?\n         /// The name and arguments of a function that should be called, as generated by the model.\n         @available(*, deprecated, message: \"Deprecated and replaced by `tool_calls`\")\n         public let functionCall: FunctionCall?\n         /// The role of the author of this message.\n         public let role: String\n         /// Provided by the Vision API.\n         public let finishDetails: FinishDetails?\n         /// The refusal message generated by the model.\n         public let refusal: String?\n         /// If the audio output modality is requested, this object contains data about the audio response from the model. [Learn more](https://platform.openai.com/docs/guides/audio).\n         public let audio: Audio?\n         \n         /// Provided by the Vision API.\n         public struct FinishDetails: Decodable {\n            let type: String\n         }\n         \n         public struct Audio: Decodable {\n            /// Unique identifier for this audio response.\n            public let id: String\n            /// The Unix timestamp (in seconds) for when this audio response will no longer be accessible on the server for use in multi-turn conversations.\n            public let expiresAt: Int\n            /// Base64 encoded audio bytes generated by the model, in the format specified in the request.\n            public let data: String\n            /// Transcript of the audio generated by the model.\n            public let transcript: String\n            \n            enum CodingKeys: String, CodingKey {\n               case id\n               case expiresAt = \"expires_at\"\n               case data\n               case transcript\n            }\n         }\n      }\n      \n      public struct LogProb: Decodable {\n         /// A list of message content tokens with log probability information.\n         let content: [TokenDetail]\n      }\n      \n      public struct TokenDetail: Decodable {\n         /// The token.\n         let token: String\n         /// The log probability of this token.\n         let logprob: Double\n         /// A list of integers representing the UTF-8 bytes representation of the token. Useful in instances where characters are represented by multiple tokens and their byte representations must be combined to generate the correct text representation. Can be null if there is no bytes representation for the token.\n         let bytes: [Int]?\n         /// List of the most likely tokens and their log probability, at this token position. In rare cases, there may be fewer than the number of requested top_logprobs returned.\n         let topLogprobs: [TopLogProb]\n         \n         enum CodingKeys: String, CodingKey {\n            case token, logprob, bytes\n            case topLogprobs = \"top_logprobs\"\n         }\n         \n         struct TopLogProb: Decodable {\n            /// The token.\n            let token: String\n            /// The log probability of this token.\n            let logprob: Double\n            /// A list of integers representing the UTF-8 bytes representation of the token. Useful in instances where characters are represented by multiple tokens and their byte representations must be combined to generate the correct text representation. Can be null if there is no bytes representation for the token.\n            let bytes: [Int]?\n         }\n      }\n   }\n   \n   public struct ChatUsage: Decodable {\n      \n      /// Number of tokens in the generated completion.\n      public let completionTokens: Int\n      /// Number of tokens in the prompt.\n      public let promptTokens: Int\n      /// Total number of tokens used in the request (prompt + completion).\n      public let totalTokens: Int\n   }\n}\n```\n\nUsage\n```swift\nlet prompt = \"Tell me a joke\"\nlet parameters = ChatCompletionParameters(messages: [.init(role: .user, content: .text(prompt))], model: .gpt4o)\nlet chatCompletionObject = service.startChat(parameters: parameters)\n```\n\nResponse\n### Chat completion chunk object\n```swift\n/// Represents a [streamed](https://platform.openai.com/docs/api-reference/chat/streaming) chunk of a chat completion response returned by model, based on the provided input.\npublic struct ChatCompletionChunkObject: Decodable {\n   \n   /// A unique identifier for the chat completion chunk.\n   public let id: String\n   /// A list of chat completion choices. Can be more than one if n is greater than 1.\n   public let choices: [ChatChoice]\n   /// The Unix timestamp (in seconds) of when the chat completion chunk was created.\n   public let created: Int\n   /// The model to generate the completion.\n   public let model: String\n   /// The service tier used for processing the request. This field is only included if the service_tier parameter is specified in the request.\n   public let serviceTier: String?\n   /// This fingerprint represents the backend configuration that the model runs with.\n   /// Can be used in conjunction with the seed request parameter to understand when backend changes have been made that might impact determinism.\n   public let systemFingerprint: String?\n   /// The object type, which is always chat.completion.chunk.\n   public let object: String\n   \n   public struct ChatChoice: Decodable {\n      \n      /// A chat completion delta generated by streamed model responses.\n      public let delta: Delta\n      /// The reason the model stopped generating tokens. This will be stop if the model hit a natural stop point or a provided stop sequence, length if the maximum number of tokens specified in the request was reached, content_filter if content was omitted due to a flag from our content filters, tool_calls if the model called a tool, or function_call (deprecated) if the model called a function.\n      public let finishReason: IntOrStringValue?\n      /// The index of the choice in the list of choices.\n      public let index: Int\n      /// Provided by the Vision API.\n      public let finishDetails: FinishDetails?\n      \n      public struct Delta: Decodable {\n         \n         /// The contents of the chunk message.\n         public let content: String?\n         /// The tool calls generated by the model, such as function calls.\n         public let toolCalls: [ToolCall]?\n         /// The name and arguments of a function that should be called, as generated by the model.\n         @available(*, deprecated, message: \"Deprecated and replaced by `tool_calls`\")\n         public let functionCall: FunctionCall?\n         /// The role of the author of this message.\n         public let role: String?\n      }\n      \n      public struct LogProb: Decodable {\n         /// A list of message content tokens with log probability information.\n         let content: [TokenDetail]\n      }\n      \n      public struct TokenDetail: Decodable {\n         /// The token.\n         let token: String\n         /// The log probability of this token.\n         let logprob: Double\n         /// A list of integers representing the UTF-8 bytes representation of the token. Useful in instances where characters are represented by multiple tokens and their byte representations must be combined to generate the correct text representation. Can be null if there is no bytes representation for the token.\n         let bytes: [Int]?\n         /// List of the most likely tokens and their log probability, at this token position. In rare cases, there may be fewer than the number of requested top_logprobs returned.\n         let topLogprobs: [TopLogProb]\n         \n         enum CodingKeys: String, CodingKey {\n            case token, logprob, bytes\n            case topLogprobs = \"top_logprobs\"\n         }\n         \n         struct TopLogProb: Decodable {\n            /// The token.\n            let token: String\n            /// The log probability of this token.\n            let logprob: Double\n            /// A list of integers representing the UTF-8 bytes representation of the token. Useful in instances where characters are represented by multiple tokens and their byte representations must be combined to generate the correct text representation. Can be null if there is no bytes representation for the token.\n            let bytes: [Int]?\n         }\n      }\n      \n      /// Provided by the Vision API.\n      public struct FinishDetails: Decodable {\n         let type: String\n      }\n   }\n}\n```\nUsage\n```swift\nlet prompt = \"Tell me a joke\"\nlet parameters = ChatCompletionParameters(messages: [.init(role: .user, content: .text(prompt))], model: .gpt4o)\nlet chatCompletionObject = try await service.startStreamedChat(parameters: parameters)\n```\n\n### Function Calling\n\nChat Completion also supports [Function Calling](https://platform.openai.com/docs/guides/function-calling) and [Parallel Function Calling](https://platform.openai.com/docs/guides/function-calling/parallel-function-calling). `functions` has been deprecated in favor of `tools` check [OpenAI Documentation](https://platform.openai.com/docs/api-reference/chat/create) for more.\n\n```swift\npublic struct ToolCall: Codable {\n\n   public let index: Int\n   /// The ID of the tool call.\n   public let id: String?\n   /// The type of the tool. Currently, only `function` is supported.\n   public let type: String?\n   /// The function that the model called.\n   public let function: FunctionCall\n\n   public init(\n      index: Int,\n      id: String,\n      type: String = \"function\",\n      function: FunctionCall)\n   {\n      self.index = index\n      self.id = id\n      self.type = type\n      self.function = function\n   }\n}\n\npublic struct FunctionCall: Codable {\n\n   /// The arguments to call the function with, as generated by the model in JSON format. Note that the model does not always generate valid JSON, and may hallucinate parameters not defined by your function schema. Validate the arguments in your code before calling your function.\n   let arguments: String\n   /// The name of the function to call.\n   let name: String\n\n   public init(\n      arguments: String,\n      name: String)\n   {\n      self.arguments = arguments\n      self.name = name\n   }\n}\n```\n\nUsage\n```swift\n/// Define a `ToolCall`\nvar tool: ToolCall {\n   .init(\n      type: \"function\", // The type of the tool. Currently, only \"function\" is supported.\n      function: .init(\n         name: \"create_image\",\n         description: \"Call this function if the request asks to generate an image\",\n         parameters: .init(\n            type: .object,\n            properties: [\n               \"prompt\": .init(type: .string, description: \"The exact prompt passed in.\"),\n               \"count\": .init(type: .integer, description: \"The number of images requested\")\n            ],\n            required: [\"prompt\", \"count\"])))\n}\n\nlet prompt = \"Show me an image of an unicorn eating ice cream\"\nlet content: ChatCompletionParameters.Message.ContentType = .text(prompt)\nlet parameters = ChatCompletionParameters(messages: [.init(role: .user, content: content)], model: .gpt41106Preview, tools: [tool])\nlet chatCompletionObject = try await service.startStreamedChat(parameters: parameters)\n```\nFor more details about how to also uploading base 64 encoded images in iOS check the [ChatFunctionsCalllDemo](https://github.com/jamesrochabrun/SwiftOpenAI/tree/main/Examples/SwiftOpenAIExample/SwiftOpenAIExample/ChatFunctionsCall) demo on the Examples section of this package.\n\n### Structured Outputs\n\n#### Documentation:\n\n- [Structured Outputs Guides](https://platform.openai.com/docs/guides/structured-outputs/structured-outputs)\n- [Examples](https://platform.openai.com/docs/guides/structured-outputs/examples)\n- [How to use](https://platform.openai.com/docs/guides/structured-outputs/how-to-use)\n- [Supported schemas](https://platform.openai.com/docs/guides/structured-outputs/supported-schemas)\n\nMust knowns:\n\n- [All fields must be required](https://platform.openai.com/docs/guides/structured-outputs/all-fields-must-be-required) , To use Structured Outputs, all fields or function parameters must be specified as required.\n- Although all fields must be required (and the model will return a value for each parameter), it is possible to emulate an optional parameter by using a union type with null.\n- [Objects have limitations on nesting depth and size](https://platform.openai.com/docs/guides/structured-outputs/objects-have-limitations-on-nesting-depth-and-size), A schema may have up to 100 object properties total, with up to 5 levels of nesting.\n\n- [additionalProperties](https://platform.openai.com/docs/guides/structured-outputs/additionalproperties-false-must-always-be-set-in-objects)): false must always be set in objects\nadditionalProperties controls whether it is allowable for an object to contain additional keys / values that were not defined in the JSON Schema.\nStructured Outputs only supports generating specified keys / values, so we require developers to set additionalProperties: false to opt into Structured Outputs.\n- [Key ordering](https://platform.openai.com/docs/guides/structured-outputs/key-ordering), When using Structured Outputs, outputs will be produced in the same order as the ordering of keys in the schema.\n- [Recursive schemas are supported](https://platform.openai.com/docs/guides/structured-outputs/recursive-schemas-are-supported)\n\n#### How to use Structured Outputs in SwiftOpenAI\n\n1. Function calling: Structured Outputs via tools is available by setting strict: true within your function definition. This feature works with all models that support tools, including all models gpt-4-0613 and gpt-3.5-turbo-0613 and later. When Structured Outputs are enabled, model outputs will match the supplied tool definition.\n\nUsing this schema:\n\n```json\n{\n  \"schema\": {\n    \"type\": \"object\",\n    \"properties\": {\n      \"steps\": {\n        \"type\": \"array\",\n        \"items\": {\n          \"type\": \"object\",\n          \"properties\": {\n            \"explanation\": {\n              \"type\": \"string\"\n            },\n            \"output\": {\n              \"type\": \"string\"\n            }\n          },\n          \"required\": [\"explanation\", \"output\"],\n          \"additionalProperties\": false\n        }\n      },\n      \"final_answer\": {\n        \"type\": \"string\"\n      }\n    },\n    \"required\": [\"steps\", \"final_answer\"],\n    \"additionalProperties\": false\n  }\n}\n```\n\nYou can use the convenient `JSONSchema` object like this:\n\n```swift\n// 1: Define the Step schema object\n\nlet stepSchema = JSONSchema(\n   type: .object,\n   properties: [\n      \"explanation\": JSONSchema(type: .string),\n      \"output\": JSONSchema(\n         type: .string)\n   ],\n   required: [\"explanation\", \"output\"],\n   additionalProperties: false\n)\n\n// 2. Define the steps Array schema.\n\nlet stepsArraySchema = JSONSchema(type: .array, items: stepSchema)\n\n// 3. Define the final Answer schema.\n\nlet finalAnswerSchema = JSONSchema(type: .string)\n\n// 4. Define math reponse JSON schema.\n\nlet mathResponseSchema = JSONSchema(\n      type: .object,\n      properties: [\n         \"steps\": stepsArraySchema,\n         \"final_answer\": finalAnswerSchema\n      ],\n      required: [\"steps\", \"final_answer\"],\n      additionalProperties: false\n)\n\nlet tool = ChatCompletionParameters.Tool(\n            function: .init(\n               name: \"math_response\",\n               strict: true,\n               parameters: mathResponseSchema))\n)\n\nlet prompt = \"solve 8x + 31 = 2\"\nlet systemMessage = ChatCompletionParameters.Message(role: .system, content: .text(\"You are a math tutor\"))\nlet userMessage = ChatCompletionParameters.Message(role: .user, content: .text(prompt))\nlet parameters = ChatCompletionParameters(\n   messages: [systemMessage, userMessage],\n   model: .gpt4o20240806,\n   tools: [tool])\n\nlet chat = try await service.startChat(parameters: parameters)\n```\n\n2. A new option for the `response_format` parameter: developers can now supply a JSON Schema via `json_schema`, a new option for the response_format parameter. This is useful when the model is not calling a tool, but rather, responding to the user in a structured way. This feature works with our newest GPT-4o models: `gpt-4o-2024-08-06`, released today, and `gpt-4o-mini-2024-07-18`. When a response_format is supplied with strict: true, model outputs will match the supplied schema.\n\nUsing the previous schema, this is how you can implement it as json schema using the convenient `JSONSchemaResponseFormat` object:\n\n```swift\n// 1: Define the Step schema object\n\nlet stepSchema = JSONSchema(\n   type: .object,\n   properties: [\n      \"explanation\": JSONSchema(type: .string),\n      \"output\": JSONSchema(\n         type: .string)\n   ],\n   required: [\"explanation\", \"output\"],\n   additionalProperties: false\n)\n\n// 2. Define the steps Array schema.\n\nlet stepsArraySchema = JSONSchema(type: .array, items: stepSchema)\n\n// 3. Define the final Answer schema.\n\nlet finalAnswerSchema = JSONSchema(type: .string)\n\n// 4. Define the response format JSON schema.\n\nlet responseFormatSchema = JSONSchemaResponseFormat(\n   name: \"math_response\",\n   strict: true,\n   schema: JSONSchema(\n      type: .object,\n      properties: [\n         \"steps\": stepsArraySchema,\n         \"final_answer\": finalAnswerSchema\n      ],\n      required: [\"steps\", \"final_answer\"],\n      additionalProperties: false\n   )\n)\n\nlet prompt = \"solve 8x + 31 = 2\"\nlet systemMessage = ChatCompletionParameters.Message(role: .system, content: .text(\"You are a math tutor\"))\nlet userMessage = ChatCompletionParameters.Message(role: .user, content: .text(prompt))\nlet parameters = ChatCompletionParameters(\n   messages: [systemMessage, userMessage],\n   model: .gpt4o20240806,\n   responseFormat: .jsonSchema(responseFormatSchema))\n```\n\nSwiftOpenAI Structred outputs supports:\n\n- [x] Tools Structured output.\n- [x] Response format Structure output.\n- [x] Recursive Schema.\n- [x] Optional values Schema.\n- [ ] Pydantic models.\n\nWe don't support Pydantic models, users need tos manually create Schemas using `JSONSchema` or `JSONSchemaResponseFormat` objects.\n\nPro tip 🔥 Use [iosAICodeAssistant GPT](https://chatgpt.com/g/g-qj7RuW7PY-iosai-code-assistant) to construct SwifOpenAI schemas. Just paste your JSON schema and ask the GPT to create SwiftOpenAI schemas for tools and response format.\n\nFor more details visit the Demo project for [tools](https://github.com/jamesrochabrun/SwiftOpenAI/tree/main/Examples/SwiftOpenAIExample/SwiftOpenAIExample/ChatStructureOutputTool) and [response format](https://github.com/jamesrochabrun/SwiftOpenAI/tree/main/Examples/SwiftOpenAIExample/SwiftOpenAIExample/ChatStructuredOutputs).\n\n### Vision\n\n[Vision](https://platform.openai.com/docs/guides/vision) API is available for use; developers must access it through the chat completions API, specifically using the gpt-4-vision-preview model or gpt-4o model. Using any other model will not provide an image description\n\nUsage\n```swift\nlet imageURL = \"https://upload.wikimedia.org/wikipedia/commons/thumb/d/dd/Gfp-wisconsin-madison-the-nature-boardwalk.jpg/2560px-Gfp-wisconsin-madison-the-nature-boardwalk.jpg\"\nlet prompt = \"What is this?\"\nlet messageContent: [ChatCompletionParameters.Message.ContentType.MessageContent] = [.text(prompt), .imageUrl(.init(url: imageURL)] // Users can add as many `.imageUrl` instances to the service.\nlet parameters = ChatCompletionParameters(messages: [.init(role: .user, content: .contentArray(messageContent))], model: .gpt4o)\nlet chatCompletionObject = try await service.startStreamedChat(parameters: parameters)\n```\n\n![Simulator Screen Recording - iPhone 15 - 2023-11-09 at 17 12 06](https://github.com/jamesrochabrun/SwiftOpenAI/assets/5378604/db2cbb3b-0c80-4ac8-8fe5-dbb782b270da)\n\nFor more details about how to also uploading base 64 encoded images in iOS check the [ChatVision](https://github.com/jamesrochabrun/SwiftOpenAI/tree/main/Examples/SwiftOpenAIExample/SwiftOpenAIExample/Vision) demo on the Examples section of this package.\n\n### Response\n\nOpenAI's most advanced interface for generating model responses. Supports text and image inputs, and text outputs. Create stateful interactions with the model, using the output of previous responses as input. Extend the model's capabilities with built-in tools for file search, web search, computer use, and more. Allow the model access to external systems and data using function calling.\n\n- Full streaming support with `responseCreateStream` method\n- Comprehensive `ResponseStreamEvent` enum covering 40+ event types\n- Enhanced `InputMessage` with `id` field for response ID tracking\n- Improved conversation state management with `previousResponseId`\n- Real-time text streaming, function calls, and tool usage events\n- Support for reasoning summaries, web search, file search, and image generation events\n- **NEW**: Support for GPT-5 models (gpt-5, gpt-5-mini, gpt-5-nano)\n- **NEW**: Verbosity parameter for controlling response detail level\n\n#### ModelResponseParameter\n\nThe `ModelResponseParameter` provides a comprehensive interface for creating model responses:\n\n```swift\nlet parameters = ModelResponseParameter(\n    input: .text(\"What is the answer to life, the universe, and everything?\"),\n    model: .gpt5,  // Support for GPT-5, GPT-5-mini, GPT-5-nano\n    text: TextConfiguration(\n        format: .text,\n        verbosity: \"low\"  // NEW: Control response verbosity (\"low\", \"medium\", \"high\")\n    ),\n    temperature: 0.7\n)\n\nlet response = try await service.responseCreate(parameters)\n```\n\n#### Available GPT-5 Models\n\n```swift\npublic enum Model {\n    case gpt5        // Complex reasoning, broad world knowledge, and code-heavy or multi-step agentic tasks\n    case gpt5Mini    // Cost-optimized reasoning and chat; balances speed, cost, and capability\n    case gpt5Nano    // High-throughput tasks, especially simple instruction-following or classification\n    // ... other models\n}\n```\n\n#### TextConfiguration with Verbosity\n\n```swift\n// Create a text configuration with verbosity control\nlet textConfig = TextConfiguration(\n    format: .text,       // Can be .text, .jsonObject, or .jsonSchema\n    verbosity: \"medium\"  // Controls response detail level\n)\n```\n\nRelated guides:\n\n- [Quickstart](https://platform.openai.com/docs/quickstart?api-mode=responses)\n- [Text inputs and outputs](https://platform.openai.com/docs/guides/text?api-mode=responses)\n- [Image inputs](https://platform.openai.com/docs/guides/images?api-mode=responses)\n- [Structured Outputs](https://platform.openai.com/docs/guides/structured-outputs?api-mode=responses)\n- [Function calling](https://platform.openai.com/docs/guides/function-calling?api-mode=responses)\n- [Conversation state](https://platform.openai.com/docs/guides/conversation-state?api-mode=responses)\n- [Extend the models with tools](https://platform.openai.com/docs/guides/tools?api-mode=responses)\n\nParameters\n```swift\n/// [Creates a model response.](https://platform.openai.com/docs/api-reference/responses/create)\npublic struct ModelResponseParameter: Codable {\n\n   /// Text, image, or file inputs to the model, used to generate a response.\n   /// A text input to the model, equivalent to a text input with the user role.\n   /// A list of one or many input items to the model, containing different content types.\n   public var input: InputType\n\n   /// Model ID used to generate the response, like gpt-4o or o1. OpenAI offers a wide range of models with\n   /// different capabilities, performance characteristics, and price points.\n   /// Refer to the model guide to browse and compare available models.\n   public var model: String\n\n   /// Specify additional output data to include in the model response. Currently supported values are:\n   /// file_search_call.results : Include the search results of the file search tool call.\n   /// message.input_image.image_url : Include image urls from the input message.\n   /// computer_call_output.output.image_url : Include image urls from the computer call output.\n   public var include: [String]?\n\n   /// Inserts a system (or developer) message as the first item in the model's context.\n   /// When using along with previous_response_id, the instructions from a previous response will be not be\n   /// carried over to the next response. This makes it simple to swap out system (or developer) messages in new responses.\n   public var instructions: String?\n\n   /// An upper bound for the number of tokens that can be generated for a response, including visible output tokens\n   /// and reasoning tokens.\n   public var maxOutputTokens: Int?\n\n   /// Set of 16 key-value pairs that can be attached to an object. This can be useful for storing additional information\n   /// about the object in a structured format, and querying for objects via API or the dashboard.\n   /// Keys are strings with a maximum length of 64 characters. Values are strings with a maximum length of 512 characters.\n   public var metadata: [String: String]?\n\n   /// Whether to allow the model to run tool calls in parallel.\n   /// Defaults to true\n   public var parallelToolCalls: Bool?\n\n   /// The unique ID of the previous response to the model. Use this to create multi-turn conversations.\n   /// Learn more about conversation state.\n   public var previousResponseId: String?\n\n   /// o-series models only\n   /// Configuration options for reasoning models.\n   public var reasoning: Reasoning?\n\n   /// Whether to store the generated model response for later retrieval via API.\n   /// Defaults to true\n   public var store: Bool?\n\n   /// If set to true, the model response data will be streamed to the client as it is generated using server-sent events.\n   public var stream: Bool?\n\n   /// What sampling temperature to use, between 0 and 2.\n   /// Higher values like 0.8 will make the output more random, while lower values like 0.2 will make it more focused and deterministic.\n   /// We generally recommend altering this or top_p but not both.\n   /// Defaults to 1\n   public var temperature: Double?\n\n   /// Configuration options for a text response from the model. Can be plain text or structured JSON data.\n   public var text: TextConfiguration?\n\n   /// How the model should select which tool (or tools) to use when generating a response.\n   /// See the tools parameter to see how to specify which tools the model can call.\n   public var toolChoice: ToolChoiceMode?\n\n   /// An array of tools the model may call while generating a response. You can specify which tool to use by setting the tool_choice parameter.\n   public var tools: [Tool]?\n\n   /// An alternative to sampling with temperature, called nucleus sampling, where the model considers the results of the tokens with top_p probability mass.\n   /// So 0.1 means only the tokens comprising the top 10% probability mass are considered.\n   /// We generally recommend altering this or temperature but not both.\n   /// Defaults to 1\n   public var topP: Double?\n\n   /// The truncation strategy to use for the model response.\n   /// Defaults to disabled\n   public var truncation: String?\n\n   /// A unique identifier representing your end-user, which can help OpenAI to monitor and detect abuse.\n   public var user: String?\n}\n```\n\n[The Response object](https://platform.openai.com/docs/api-reference/responses/object)\n\n```swift\n/// The Response object returned when retrieving a model response\npublic struct ResponseModel: Decodable {\n\n   /// Unix timestamp (in seconds) of when this Response was created.\n   public let createdAt: Int\n\n   /// An error object returned when the model fails to generate a Response.\n   public let error: ErrorObject?\n\n   /// Unique identifier for this Response.\n   public let id: String\n\n   /// Details about why the response is incomplete.\n   public let incompleteDetails: IncompleteDetails?\n\n   /// Inserts a system (or developer) message as the first item in the model's context.\n   public let instructions: String?\n\n   /// An upper bound for the number of tokens that can be generated for a response, including visible output tokens\n   /// and reasoning tokens.\n   public let maxOutputTokens: Int?\n\n   /// Set of 16 key-value pairs that can be attached to an object.\n   public let metadata: [String: String]\n\n   /// Model ID used to generate the response, like gpt-4o or o1.\n   public let model: String\n\n   /// The object type of this resource - always set to response.\n   public let object: String\n\n   /// An array of content items generated by the model.\n   public let output: [OutputItem]\n\n   /// Whether to allow the model to run tool calls in parallel.\n   public let parallelToolCalls: Bool\n\n   /// The unique ID of the previous response to the model. Use this to create multi-turn conversations.\n   public let previousResponseId: String?\n\n   /// Configuration options for reasoning models.\n   public let reasoning: Reasoning?\n\n   /// The status of the response generation. One of completed, failed, in_progress, or incomplete.\n   public let status: String\n\n   /// What sampling temperature to use, between 0 and 2.\n   public let temperature: Double?\n\n   /// Configuration options for a text response from the model.\n   public let text: TextConfiguration\n\n   /// How the model should select which tool (or tools) to use when generating a response.\n   public let toolChoice: ToolChoiceMode\n\n   /// An array of tools the model may call while generating a response.\n   public let tools: [Tool]\n\n   /// An alternative to sampling with temperature, called nucleus sampling.\n   public let topP: Double?\n\n   /// The truncation strategy to use for the model response.\n   public let truncation: String?\n\n   /// Represents token usage details.\n   public let usage: Usage?\n\n   /// A unique identifier representing your end-user.\n   public let user: String?\n   \n   /// Convenience property that aggregates all text output from output_text items in the output array.\n   /// Similar to the outputText property in Python and JavaScript SDKs.\n   public var outputText: String? \n}\n```\n\nInput Types\n```swift\n// InputType represents the input to the Response API\npublic enum InputType: Codable {\n    case string(String)  // Simple text input\n    case array([InputItem])  // Array of input items for complex conversations\n}\n\n// InputItem represents different types of input\npublic enum InputItem: Codable {\n    case message(InputMessage)  // User, assistant, system messages\n    case functionToolCall(FunctionToolCall)  // Function calls\n    case functionToolCallOutput(FunctionToolCallOutput)  // Function outputs\n    // ... other input types\n}\n\n// InputMessage structure with support for response IDs\npublic struct InputMessage: Codable {\n    public let role: String  // \"user\", \"assistant\", \"system\"\n    public let content: MessageContent\n    public let type: String?  // Always \"message\"\n    public let status: String?  // \"completed\" for assistant messages\n    public let id: String?  // Response ID for assistant messages\n}\n\n// MessageContent can be text or array of content items\npublic enum MessageContent: Codable {\n    case text(String)\n    case array([ContentItem])  // For multimodal content\n}\n```\n\nUsage\n\nSimple text input\n```swift\nlet prompt = \"What is the capital of France?\"\nlet parameters = ModelResponseParameter(input: .string(prompt), model: .gpt4o)\nlet response = try await service.responseCreate(parameters)\n```\n\nText input with reasoning\n```swift\nlet prompt = \"How much wood would a woodchuck chuck?\"\nlet parameters = ModelResponseParameter(\n    input: .string(prompt),\n    model: .o3Mini,\n    reasoning: Reasoning(effort: \"high\")\n)\nlet response = try await service.responseCreate(parameters)\n```\n\nImage input\n```swift\nlet textPrompt = \"What is in this image?\"\nlet imageUrl = \"https://example.com/path/to/image.jpg\"\nlet imageContent = ContentItem.imageUrl(ImageUrlContent(imageUrl: imageUrl))\nlet textContent = ContentItem.text(TextContent(text: textPrompt))\nlet message = InputItem(role: \"user\", content: [textContent, imageContent])\nlet parameters = ModelResponseParameter(input: .array([message]), model: .gpt4o)\nlet response = try await service.responseCreate(parameters)\n```\n\nUsing tools (web search)\n```swift\nlet prompt = \"What was a positive news story from today?\"\nlet parameters = ModelResponseParameter(\n    input: .string(prompt),\n    model: .gpt4o,\n    tools: [Tool(type: \"web_search_preview\", function: nil)]\n)\nlet response = try await service.responseCreate(parameters)\n```\n\nUsing tools (file search)\n```swift\nlet prompt = \"What are the key points in the document?\"\nlet parameters = ModelResponseParameter(\n    input: .string(prompt),\n    model: .gpt4o,\n    tools: [\n        Tool(\n            type: \"file_search\",\n            function: ChatCompletionParameters.ChatFunction(\n                name: \"file_search\",\n                strict: false,\n                description: \"Search through files\",\n                parameters: JSONSchema(\n                    type: .object,\n                    properties: [\n                        \"vector_store_ids\": JSONSchema(\n                            type: .array,\n                            items: JSONSchema(type: .string)\n                        ),\n                        \"max_num_results\": JSONSchema(type: .integer)\n                    ],\n                    required: [\"vector_store_ids\"],\n                    additionalProperties: false\n                )\n            )\n        )\n    ]\n)\nlet response = try await service.responseCreate(parameters)\n```\n\nFunction calling\n```swift\nlet prompt = \"What is the weather like in Boston today?\"\nlet parameters = ModelResponseParameter(\n    input: .string(prompt),\n    model: .gpt4o,\n    tools: [\n        Tool(\n            type: \"function\",\n            function: ChatCompletionParameters.ChatFunction(\n                name: \"get_current_weather\",\n                strict: false,\n                description: \"Get the current weather in a given location\",\n                parameters: JSONSchema(\n                    type: .object,\n                    properties: [\n                        \"location\": JSONSchema(\n                            type: .string,\n                            description: \"The city and state, e.g. San Francisco, CA\"\n                        ),\n                        \"unit\": JSONSchema(\n                            type: .string,\n                            enum: [\"celsius\", \"fahrenheit\"]\n                        )\n                    ],\n                    required: [\"location\", \"unit\"],\n                    additionalProperties: false\n                )\n            )\n        )\n    ],\n    toolChoice: .auto\n)\nlet response = try await service.responseCreate(parameters)\n```\n\nRetrieving a response\n```swift\nlet responseId = \"resp_abc123\"\nlet response = try await service.responseModel(id: responseId)\n```\n\n#### Streaming Responses\n\nThe Response API supports streaming responses using Server-Sent Events (SSE). This allows you to receive partial responses as they are generated, enabling real-time UI updates and better user experience.\n\nStream Events\n```swift\n// The ResponseStreamEvent enum represents all possible streaming events\npublic enum ResponseStreamEvent: Decodable {\n  case responseCreated(ResponseCreatedEvent)\n  case responseInProgress(ResponseInProgressEvent)\n  case responseCompleted(ResponseCompletedEvent)\n  case responseFailed(ResponseFailedEvent)\n  case outputItemAdded(OutputItemAddedEvent)\n  case outputTextDelta(OutputTextDeltaEvent)\n  case outputTextDone(OutputTextDoneEvent)\n  case functionCallArgumentsDelta(FunctionCallArgumentsDeltaEvent)\n  case reasoningSummaryTextDelta(ReasoningSummaryTextDeltaEvent)\n  case error(ErrorEvent)\n  // ... and many more event types\n}\n```\n\nBasic Streaming Example\n```swift\n// Enable streaming by setting stream: true\nlet parameters = ModelResponseParameter(\n    input: .string(\"Tell me a story\"),\n    model: .gpt4o,\n    stream: true\n)\n\n// Create a stream\nlet stream = try await service.responseCreateStream(parameters)\n\n// Process events as they arrive\nfor try await event in stream {\n    switch event {\n    case .outputTextDelta(let delta):\n        // Append text chunk to your UI\n        print(delta.delta, terminator: \"\")\n        \n    case .responseCompleted(let completed):\n        // Response is complete\n        print(\"\\nResponse ID: \\(completed.response.id)\")\n        \n    case .error(let error):\n        // Handle errors\n        print(\"Error: \\(error.message)\")\n        \n    default:\n        // Handle other events as needed\n        break\n    }\n}\n```\n\nStreaming with Conversation State\n```swift\n// Maintain conversation continuity with previousResponseId\nvar previousResponseId: String? = nil\nvar messages: [(role: String, content: String)] = []\n\n// First message\nlet firstParams = ModelResponseParameter(\n    input: .string(\"Hello!\"),\n    model: .gpt4o,\n    stream: true\n)\n\nlet firstStream = try await service.responseCreateStream(firstParams)\nvar firstResponse = \"\"\n\nfor try await event in firstStream {\n    switch event {\n    case .outputTextDelta(let delta):\n        firstResponse += delta.delta\n        \n    case .responseCompleted(let completed):\n        previousResponseId = completed.response.id\n        messages.append((role: \"user\", content: \"Hello!\"))\n        messages.append((role: \"assistant\", content: firstResponse))\n        \n    default:\n        break\n    }\n}\n\n// Follow-up message with conversation context\nvar inputArray: [InputItem] = []\n\n// Add conversation history\nfor message in messages {\n    inputArray.append(.message(InputMessage(\n        role: message.role,\n        content: .text(message.content)\n    )))\n}\n\n// Add new user message\ninputArray.append(.message(InputMessage(\n    role: \"user\",\n    content: .text(\"How are you?\")\n)))\n\nlet followUpParams = ModelResponseParameter(\n    input: .array(inputArray),\n    model: .gpt4o,\n    previousResponseId: previousResponseId,\n    stream: true\n)\n\nlet followUpStream = try await service.responseCreateStream(followUpParams)\n// Process the follow-up stream...\n```\n\nStreaming with Tools and Function Calling\n```swift\nlet parameters = ModelResponseParameter(\n    input: .string(\"What's the weather in San Francisco?\"),\n    model: .gpt4o,\n    tools: [\n        Tool(\n            type: \"function\",\n            function: ChatCompletionParameters.ChatFunction(\n                name: \"get_weather\",\n                description: \"Get current weather\",\n                parameters: JSONSchema(\n                    type: .object,\n                    properties: [\n                        \"location\": JSONSchema(type: .string)\n                    ],\n                    required: [\"location\"]\n                )\n            )\n        )\n    ],\n    stream: true\n)\n\nlet stream = try await service.responseCreateStream(parameters)\nvar functionCallArguments = \"\"\n\nfor try await event in stream {\n    switch event {\n    case .functionCallArgumentsDelta(let delta):\n        // Accumulate function call arguments\n        functionCallArguments += delta.delta\n        \n    case .functionCallArgumentsDone(let done):\n        // Function call is complete\n        print(\"Function: \\(done.name)\")\n        print(\"Arguments: \\(functionCallArguments)\")\n        \n    case .outputTextDelta(let delta):\n        // Regular text output\n        print(delta.delta, terminator: \"\")\n        \n    default:\n        break\n    }\n}\n```\n\nCanceling a Stream\n```swift\n// Streams can be canceled using Swift's task cancellation\nlet streamTask = Task {\n    let stream = try await service.responseCreateStream(parameters)\n    \n    for try await event in stream {\n        // Check if task is cancelled\n        if Task.isCancelled {\n            break\n        }\n        \n        // Process events...\n    }\n}\n\n// Cancel the stream when needed\nstreamTask.cancel()\n```\n\nComplete Streaming Implementation Example\n```swift\n@MainActor\n@Observable\nclass ResponseStreamProvider {\n    var messages: [Message] = []\n    var isStreaming = false\n    var error: String?\n    \n    private let service: OpenAIService\n    private var previousResponseId: String?\n    private var streamTask: Task\u003cVoid, Never\u003e?\n    \n    init(service: OpenAIService) {\n        self.service = service\n    }\n    \n    func sendMessage(_ text: String) {\n        streamTask?.cancel()\n        \n        // Add user message\n        messages.append(Message(role: .user, content: text))\n        \n        // Start streaming\n        streamTask = Task {\n            await streamResponse(for: text)\n        }\n    }\n    \n    private func streamResponse(for userInput: String) async {\n        isStreaming = true\n        error = nil\n        \n        // Create streaming message placeholder\n        let streamingMessage = Message(role: .assistant, content: \"\", isStreaming: true)\n        messages.append(streamingMessage)\n        \n        do {\n            // Build conversation history\n            var inputArray: [InputItem] = []\n            for message in messages.dropLast(2) {\n                inputArray.append(.message(InputMessage(\n                    role: message.role.rawValue,\n                    content: .text(message.content)\n                )))\n            }\n            inputArray.append(.message(InputMessage(\n                role: \"user\",\n                content: .text(userInput)\n            )))\n            \n            let parameters = ModelResponseParameter(\n                input: .array(inputArray),\n                model: .gpt4o,\n                previousResponseId: previousResponseId,\n                stream: true\n            )\n            \n            let stream = try await service.responseCreateStream(parameters)\n            var accumulatedText = \"\"\n            \n            for try await event in stream {\n                guard !Task.isCancelled else { break }\n                \n                switch event {\n                case .outputTextDelta(let delta):\n                    accumulatedText += delta.delta\n                    updateStreamingMessage(with: accumulatedText)\n                    \n                case .responseCompleted(let completed):\n                    previousResponseId = completed.response.id\n                    finalizeStreamingMessage(with: accumulatedText, responseId: completed.response.id)\n                    \n                case .error(let errorEvent):\n                    throw APIError.requestFailed(description: errorEvent.message)\n                    \n                default:\n                    break\n                }\n            }\n        } catch {\n            self.error = error.localizedDescription\n            messages.removeLast() // Remove streaming message on error\n        }\n        \n        isStreaming = false\n    }\n    \n    private func updateStreamingMessage(with content: String) {\n        if let index = messages.lastIndex(where: { $0.isStreaming }) {\n            messages[index].content = content\n        }\n    }\n    \n    private func finalizeStreamingMessage(with content: String, responseId: String) {\n        if let index = messages.lastIndex(where: { $0.isStreaming }) {\n            messages[index].content = content\n            messages[index].isStreaming = false\n            messages[index].responseId = responseId\n        }\n    }\n}\n```\n\n### Embeddings\nParameters\n```swift\n/// [Creates](https://platform.openai.com/docs/api-reference/embeddings/create) an embedding vector representing the input text.\npublic struct EmbeddingParameter: Encodable {\n   \n   /// ID of the model to use. You can use the List models API to see all of your available models, or see our [Model overview ](https://platform.openai.com/docs/models/overview) for descriptions of them.\n   let model: String\n   /// Input text to embed, encoded as a string or array of tokens. To embed multiple inputs in a single request, pass an array of strings or an array of token arrays. Each input must not exceed the max input tokens for the model (8191 tokens for text-embedding-ada-002) and cannot be an empty string. [How to Count Tokens with `tiktoken`](https://cookbook.openai.com/examples/how_to_count_tokens_with_tiktoken)\n   let input: String\n   \n   /// A unique identifier representing your end-user, which can help OpenAI to monitor and detect abuse. [Learn more.](https://platform.openai.com/docs/guides/safety-best-practices/end-user-ids)\n   let user: String?\n   \n   public enum Model: String {\n      case textEmbeddingAda002 = \"text-embedding-ada-002\"\n   }\n   \n   public init(\n      model: Model = .textEmbeddingAda002,\n      input: String,\n      user: String? = nil)\n   {\n      self.model = model.value\n      self.input = input\n      self.user = user\n   }\n}\n```\nResponse\n```swift\n/// [Represents an embedding vector returned by embedding endpoint.](https://platform.openai.com/docs/api-reference/embeddings/object)\npublic struct EmbeddingObject: Decodable {\n   \n   /// The object type, which is always \"embedding\".\n   public let object: String\n   /// The embedding vector, which is a list of floats. The length of vector depends on the model as listed in the embedding guide.[https://platform.openai.com/docs/guides/embeddings]\n   public let embedding: [Float]\n   /// The index of the embedding in the list of embeddings.\n   public let index: Int\n}\n```\n\nUsage\n```swift\nlet prompt = \"Hello world.\"\nlet embeddingObjects = try await service.createEmbeddings(parameters: parameters).data\n```\n\n### Fine-tuning\nParameters\n```swift\n/// [Creates a job](https://platform.openai.com/docs/api-reference/fine-tuning/create) that fine-tunes a specified model from a given dataset.\n///Response includes details of the enqueued job including job status and the name of the fine-tuned models once complete.\npublic struct FineTuningJobParameters: Encodable {\n   \n   /// The name of the model to fine-tune. You can select one of the [supported models](https://platform.openai.com/docs/models/overview).\n   let model: String\n   /// The ID of an uploaded file that contains training data.\n   /// See [upload file](https://platform.openai.com/docs/api-reference/files/upload) for how to upload a file.\n   /// Your dataset must be formatted as a JSONL file. Additionally, you must upload your file with the purpose fine-tune.\n   /// See the [fine-tuning guide](https://platform.openai.com/docs/guides/fine-tuning) for more details.\n   let trainingFile: String\n   /// The hyperparameters used for the fine-tuning job.\n   let hyperparameters: HyperParameters?\n   /// A string of up to 18 characters that will be added to your fine-tuned model name.\n   /// For example, a suffix of \"custom-model-name\" would produce a model name like ft:gpt-3.5-turbo:openai:custom-model-name:7p4lURel.\n   /// Defaults to null.\n   let suffix: String?\n   /// The ID of an uploaded file that contains validation data.\n   /// If you provide this file, the data is used to generate validation metrics periodically during fine-tuning. These metrics can be viewed in the fine-tuning results file. The same data should not be present in both train and validation files.\n   /// Your dataset must be formatted as a JSONL file. You must upload your file with the purpose fine-tune.\n   /// See the [fine-tuning guide](https://platform.openai.com/docs/guides/fine-tuning) for more details.\n   let validationFile: String?\n   /// A list of integrations to enable for your fine-tuning job.\n   let integrations: [Integration]?\n   /// The seed controls the reproducibility of the job. Passing in the same seed and job parameters should produce the same results, but may differ in rare cases. If a seed is not specified, one will be generated for you.\n   let seed: Int?\n   \n   /// Fine-tuning is [currently available](https://platform.openai.com/docs/guides/fine-tuning/what-models-can-be-fine-tuned) for the following models:\n   /// gpt-3.5-turbo-0613 (recommended)\n   /// babbage-002\n   /// davinci-002\n   /// OpenAI expects gpt-3.5-turbo to be the right model for most users in terms of results and ease of use, unless you are migrating a legacy fine-tuned model.\n   public enum Model: String {\n      case gpt35 = \"gpt-3.5-turbo-0613\" /// recommended\n      case babbage002 = \"babbage-002\"\n      case davinci002 = \"davinci-002\"\n   }\n   \n   public struct HyperParameters: Encodable {\n      /// The number of epochs to train the model for. An epoch refers to one full cycle through the training dataset.\n      /// Defaults to auto.\n      let nEpochs: Int?\n      \n      public init(\n         nEpochs: Int?)\n      {\n         self.nEpochs = nEpochs\n      }\n   }\n   \n   public init(\n      model: Model,\n      trainingFile: String,\n      hyperparameters: HyperParameters? = nil,\n      suffix: String? = nil,\n      validationFile: String? = nil)\n   {\n      self.model = model.rawValue\n      self.trainingFile = trainingFile\n      self.hyperparameters = hyperparameters\n      self.suffix = suffix\n      self.validationFile = validationFile\n   }\n}\n```\nResponse\n```swift\n/// The fine_tuning.job object represents a [fine-tuning job](https://platform.openai.com/docs/api-reference/fine-tuning/object) that has been created through the API.\npublic struct FineTuningJobObject: Decodable {\n   \n   /// The object identifier, which can be referenced in the API endpoints.\n   public let id: String\n   /// The Unix timestamp (in seconds) for when the fine-tuning job was created.\n   public let createdAt: Int\n  /// For fine-tuning jobs that have failed, this will contain more information on the cause of the failure.\n   public let error: OpenAIErrorResponse.Error?\n   /// The name of the fine-tuned model that is being created. The value will be null if the fine-tuning job is still running.\n   public let fineTunedModel: String?\n   /// The Unix timestamp (in seconds) for when the fine-tuning job was finished. The value will be null if the fine-tuning job is still running.\n   public let finishedAt: Int?\n   /// The hyperparameters used for the fine-tuning job. See the [fine-tuning guide](https://platform.openai.com/docs/guides/fine-tuning)  for more details.\n   public let hyperparameters: HyperParameters\n   /// The base model that is being fine-tuned.\n   public let model: String\n   /// The object type, which is always \"fine_tuning.job\".\n   public let object: String\n   /// The organization that owns the fine-tuning job.\n   public let organizationId: String\n   /// The compiled results file ID(s) for the fine-tuning job. You can retrieve the results with the [Files API](https://platform.openai.com/docs/api-reference/files/retrieve-contents).\n   public let resultFiles: [String]\n   /// The current status of the fine-tuning job, which can be either `validating_files`, `queued`, `running`, `succeeded`, `failed`, or `cancelled`.\n   public let status: String\n   /// The total number of billable tokens processed by this fine-tuning job. The value will be null if the fine-tuning job is still running.\n   public let trainedTokens: Int?\n   \n   /// The file ID used for training. You can retrieve the training data with the [Files API](https://platform.openai.com/docs/api-reference/files/retrieve-contents).\n   public let trainingFile: String\n   /// The file ID used for validation. You can retrieve the validation results with the [Files API](https://platform.openai.com/docs/api-reference/files/retrieve-contents).\n   public let validationFile: String?\n   \n   public enum Status: String {\n      case validatingFiles = \"validating_files\"\n      case queued\n      case running\n      case succeeded\n      case failed\n      case cancelled\n   }\n   \n   public struct HyperParameters: Decodable {\n      /// The number of epochs to train the model for. An epoch refers to one full cycle through the training dataset. \"auto\" decides the optimal number of epochs based on the size of the dataset. If setting the number manually, we support any number between 1 and 50 epochs.\n      public let nEpochs: IntOrStringValue\n   }\n}\n```\n\nUsage\nList fine-tuning jobs\n```swift\nlet fineTuningJobs = try await service.istFineTuningJobs()\n```\nCreate fine-tuning job\n```swift\nlet trainingFileID = \"file-Atc9okK0MOuQwQzDJCZXnrh6\" // The id of the file that has been uploaded using the `Files` API. https://platform.openai.com/docs/api-reference/fine-tuning/create#fine-tuning/create-training_file\nlet parameters = FineTuningJobParameters(model: .gpt35, trainingFile: trainingFileID)\nlet fineTuningJob = try await service.createFineTuningJob(parameters: parameters)\n```\nRetrieve fine-tuning job\n```swift\nlet fineTuningJobID = \"ftjob-abc123\"\nlet fineTuningJob = try await service.retrieveFineTuningJob(id: fineTuningJobID)\n```\nCancel fine-tuning job\n```swift\nlet fineTuningJobID = \"ftjob-abc123\"\nlet canceledFineTuningJob = try await service.cancelFineTuningJobWith(id: fineTuningJobID)\n```\n#### Fine-tuning job event object\nResponse\n```swift\n/// [Fine-tuning job event object](https://platform.openai.com/docs/api-reference/fine-tuning/event-object)\npublic struct FineTuningJobEventObject: Decodable {\n   \n   public let id: String\n   \n   public let createdAt: Int\n   \n   public let level: String\n   \n   public let message: String\n   \n   public let object: String\n   \n   public let type: String?\n   \n   public let data: Data?\n   \n   public struct Data: Decodable {\n      public let step: Int\n      public let trainLoss: Double\n      public let trainMeanTokenAccuracy: Double\n   }\n}\n```\nUsage\n```swift\nlet fineTuningJobID = \"ftjob-abc123\"\nlet jobEvents = try await service.listFineTuningEventsForJobWith(id: id, after: nil, limit: nil).data\n```\n\n### Batch\nParameters\n```swift\npublic struct BatchParameter: Encodable {\n   \n   /// The ID of an uploaded file that contains requests for the new batch.\n   /// See [upload file](https://platform.openai.com/docs/api-reference/files/create) for how to upload a file.\n   /// Your input file must be formatted as a [JSONL file](https://platform.openai.com/docs/api-reference/batch/requestInput), and must be uploaded with the purpose batch.\n   let inputFileID: String\n   /// The endpoint to be used for all requests in the batch. Currently only /v1/chat/completions is supported.\n   let endpoint: String\n   /// The time frame within which the batch should be processed. Currently only 24h is supported.\n   let completionWindow: String\n   /// Optional custom metadata for the batch.\n   let metadata: [String: String]?\n   \n   enum CodingKeys: String, CodingKey {\n      case inputFileID = \"input_file_id\"\n      case endpoint\n      case completionWindow = \"completion_window\"\n      case metadata\n   }\n}\n```\nResponse\n```swift\npublic struct BatchObject: Decodable {\n   \n   let id: String\n   /// The object type, which is always batch.\n   let object: String\n   /// The OpenAI API endpoint used by the batch.\n   let endpoint: String\n   \n   let errors: Error\n   /// The ID of the input file for the batch.\n   let inputFileID: String\n   /// The time frame within which the batch should be processed.\n   let completionWindow: String\n   /// The current status of the batch.\n   let status: String\n   /// The ID of the file containing the outputs of successfully executed requests.\n   let outputFileID: String\n   /// The ID of the file containing the outputs of requests with errors.\n   let errorFileID: String\n   /// The Unix timestamp (in seconds) for when the batch was created.\n   let createdAt: Int\n   /// The Unix timestamp (in seconds) for when the batch started processing.\n   let inProgressAt: Int\n   /// The Unix timestamp (in seconds) for when the batch will expire.\n   let expiresAt: Int\n   /// The Unix timestamp (in seconds) for when the batch started finalizing.\n   let finalizingAt: Int\n   /// The Unix timestamp (in seconds) for when the batch was completed.\n   let completedAt: Int\n   /// The Unix timestamp (in seconds) for when the batch failed.\n   let failedAt: Int\n   /// The Unix timestamp (in seconds) for when the batch expired.\n   let expiredAt: Int\n   /// The Unix timestamp (in seconds) for when the batch started cancelling.\n   let cancellingAt: Int\n   /// The Unix timestamp (in seconds) for when the batch was cancelled.\n   let cancelledAt: Int\n   /// The request counts for different statuses within the batch.\n   let requestCounts: RequestCount\n   /// Set of 16 key-value pairs that can be attached to an object. This can be useful for storing additional information about the object in a structured format. Keys can be a maximum of 64 characters long and values can be a maxium of 512 characters long.\n   let metadata: [String: String]\n   \n   public struct Error: Decodable {\n      \n      let object: String\n      let data: [Data]\n\n      public struct Data: Decodable {\n         \n         /// An error code identifying the error type.\n         let code: String\n         /// A human-readable message providing more details about the error.\n         let message: String\n         /// The name of the parameter that caused the error, if applicable.\n         let param: String?\n         /// The line number of the input file where the error occurred, if applicable.\n         let line: Int?\n      }\n   }\n   \n   public struct RequestCount: Decodable {\n      \n      /// Total number of requests in the batch.\n      let total: Int\n      /// Number of requests that have been completed successfully.\n      let completed: Int\n      /// Number of requests that have failed.\n      let failed: Int\n   }\n}\n```\nUsage\n\nCreate batch\n```swift\nlet inputFileID = \"file-abc123\"\nlet endpoint = \"/v1/chat/completions\"\nlet completionWindow = \"24h\"\nlet parameter = BatchParameter(inputFileID: inputFileID, endpoint: endpoint, completionWindow: completionWindow, metadata: nil)\nlet batch = try await service.createBatch(parameters: parameters)\n```\n\nRetrieve batch\n```swift\nlet batchID = \"batch_abc123\"\nlet batch = try await service.retrieveBatch(id: batchID)\n```\n\nCancel batch\n```swift\nlet batchID = \"batch_abc123\"\nlet batch = try await service.cancelBatch(id: batchID)\n```\n\nList batch\n```swift\nlet batches = try await service.listBatch(after: nil, limit: nil)\n```\n\n### Files\nParameters\n```swift\n/// [Upload a file](https://platform.openai.com/docs/api-reference/files/create) that can be used across various endpoints/features. Currently, the size of all the files uploaded by one organization can be up to 1 GB. Please contact us if you need to increase the storage limit.\npublic struct FileParameters: Encodable {\n   \n   /// The name of the file asset is not documented in OpenAI's official documentation; however, it is essential for constructing the multipart request.\n   let fileName: String\n   /// The file object (not file name) to be uploaded.\n   /// If the purpose is set to \"fine-tune\", the file will be used for fine-tuning.\n   let file: Data\n   /// The intended purpose of the uploaded file.\n   /// Use \"fine-tune\" for [fine-tuning](https://platform.openai.com/docs/api-reference/fine-tuning). This allows us to validate the format of the uploaded file is correct for fine-tuning.\n   let purpose: String\n   \n   public init(\n      fileName: String,\n      file: Data,\n      purpose: String)\n   {\n      self.fileName = fileName\n      self.file = file\n      self.purpose = purpose\n   }\n}\n```\nResponse\n```swift\n/// The [File object](https://platform.openai.com/docs/api-reference/files/object) represents a document that has been uploaded to OpenAI.\npublic struct FileObject: Decodable {\n   \n   /// The file identifier, which can be referenced in the API endpoints.\n   public let id: String\n   /// The size of the file in bytes.\n   public let bytes: Int\n   /// The Unix timestamp (in seconds) for when the file was created.\n   public let createdAt: Int\n   /// The name of the file.\n   public let filename: String\n   /// The object type, which is always \"file\".\n   public let object: String\n   /// The intended purpose of the file. Currently, only \"fine-tune\" is supported.\n   public let purpose: String\n   /// The current status of the file, which can be either uploaded, processed, pending, error, deleting or deleted.\n   public let status: String\n   /// Additional details about the status of the file. If the file is in the error state, this will include a message describing the error.\n   public let statusDetails: String?\n   \n   public enum Status: String {\n      case uploaded\n      case processed\n      case pending\n      case error\n      case deleting\n      case deleted\n   }\n\n   public init(\n      id: String,\n      bytes: Int,\n      createdAt: Int,\n      filename: String,\n      object: String,\n      purpose: String,\n      status: Status,\n      statusDetails: String?)\n   {\n      self.id = id\n      self.bytes = bytes\n      self.createdAt = createdAt\n      self.filename = filename\n      self.object = object\n      self.purpose = purpose\n      self.status = status.rawValue\n      self.statusDetails = statusDetails\n   }\n}\n```\nUsage\nList files\n```swift\nlet files = try await service.listFiles().data\n```\n### Upload f","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjamesrochabrun%2Fswiftopenai","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjamesrochabrun%2Fswiftopenai","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjamesrochabrun%2Fswiftopenai/lists"}