swiftopenai-api

How do I format an OpenAI API request in Swift?


I need to use the OpenAI API and am struggling to format the request. I started by referencing the curl code that is listed in the OpenAI API playground, and this code worked in my terminal. That request is here:

curl https://api.openai.com/v1/chat/completions \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $OPENAI_API_KEY" \
  -d '{
  "model": "gpt-4o",
  "messages": [
    {
      "role": "user",
      "content": [
        {
          "type": "text",
          "text": "Write a haiku about weightlifting"
        }
      ]
    }
  ],
  "temperature": 1,
  "max_tokens": 2048,
  "top_p": 1,
  "frequency_penalty": 0,
  "presence_penalty": 0,
  "response_format": {
    "type": "text"
  }
}'

Then, I started working on translating that request into swift instead of curl. I've been referencing some YouTube tutorials, and here is my code so far.

let openAiUrl = URL(string: "https://api.openai.com/v1/chat/completions")!
var request = URLRequest(url: openAiUrl)
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("Bearer \(openAiApiKey)", forHTTPHeaderField: "Authorization")
request.httpMethod = "POST"
let httpBody: [String: Any] = [
    "messages" : [
        {
            "role": "user", //Error: consecutive statements on a line must be separated by ';'
            "content": "Write a haiku about weightlifting"
        }
    ],
    "model": "gpt-4o",
    "max_tokens" : 100,
    "temperature": String(temperature),
    "frequency_penalty": 0,
    "presence_penalty": 0,
    "response_format": { //Error: consecutive statements on a line must be separated by ';'
        "type": "text"
    }
]

I am getting the error that says "Consecutive statements on a line must be separated by ';'" on the two lines that are using curly braces.

What do I need to do to format the API request? The temperature variable is a Double that is currently set to 1.0.


Solution

  • Try this approach using a JSONEncoder to encode the json parameters, such as:

                let body = """
    {
                        "messages" : [
                            {
                                "role": "user",
                                "content": "Write a haiku about weightlifting"
                            }
                        ],
                        "model": "gpt-4o",
                        "max_tokens" : 100,
                        "temperature": 1.0,
                        "frequency_penalty": 0,
                        "presence_penalty": 0,
                        "response_format": { 
                            "type": "text"
                        }
    }
    """
                
                do {
                    request.httpBody = try JSONEncoder().encode(body)
    
                    let (responseData, response) = try await URLSession.shared.data(for: request)
    
                    print("-----> \n \(String(data: responseData, encoding: .utf8) as AnyObject) \n")
    
                } catch {
                    print("---> error: \(error)")
                }
    

    EDIT-1

    Here is my test code using SwiftUI. Since I don't have a key I cannot fully test this code, but it compiles and gives some info about the response.

    import SwiftUI
    
    struct ContentView: View {
        let openAiApiKey = "for testing"
        
        var body: some View {
            Text("testing")
                .task {
                    await doPost()
                }
        }
        
        func doPost() async {
            let openAiUrl = URL(string: "https://api.openai.com/v1/chat/completions")!
            
            var request = URLRequest(url: openAiUrl)
            request.setValue("application/json", forHTTPHeaderField: "Content-Type")
            request.addValue("Bearer \(openAiApiKey)", forHTTPHeaderField: "Authorization")
            request.httpMethod = "POST"
            
            let body = """
    {
    "messages": [
    {
    "role": "user",
    "content": "Write a haiku about weightlifting"
    }
    ],
    "model": "gpt-4o",
    "max_tokens" : 100,
    "temperature": 1.0,
    "frequency_penalty": 0,
    "presence_penalty": 0,
    "response_format": { 
        "type": "text"
    }
    }
    """
            do {
                request.httpBody = try JSONEncoder().encode(body)
                
                let (responseData, response) = try await URLSession.shared.data(for: request)
                print("-----> responseData \n \(String(data: responseData, encoding: .utf8) as AnyObject) \n")
            }
            catch { print(error) }
        }
    }
    

    EDIT-2

    another alternative,

    struct ContentView: View {
        let openAiApiKey = "for testing"
        
        var body: some View {
            Text("testing")
                .task {
                    let url = URL(string: "https://api.openai.com/v1/chat/completions")!
                    var request = URLRequest(url: url)
                    request.httpMethod = "POST"
                    request.setValue("application/json", forHTTPHeaderField: "Content-Type")
                    request.setValue("Bearer \(openAiApiKey)", forHTTPHeaderField: "Authorization")
                    
                    let requestBody: [String: Any] = [
                        "model": "gpt-4o",
                        "messages": [
                            [
                                "role": "user",
                                "content": [
                                    [
                                        "type": "text",
                                        "text": "Write a haiku about weightlifting"
                                    ]
                                ]
                            ]
                        ],
                        "temperature": 1,
                        "max_tokens": 2048,
                        "top_p": 1,
                        "frequency_penalty": 0,
                        "presence_penalty": 0,
                        "response_format": [
                            "type": "text"
                        ]
                    ]
                    
                    do {
                        request.httpBody = try JSONSerialization.data(withJSONObject: requestBody)
                        
                        let (responseData, response) = try await URLSession.shared.data(for: request)
                        print("-----> responseData \n \(String(data: responseData, encoding: .utf8) as AnyObject) \n")
                    }
                    catch { print(error) }
                    
                }
        }
    }