How to read stream using Openai completion API in Swift - iOS? - swift

I am trying to read the output in stream (as it comes) rather than waiting up for the whole response.
I have used the following code.
func caller() {
let completionAPIURL = URL(string: "https://api.openai.com/v1/completions")!
var request = URLRequest(url: completionAPIURL)
request.httpMethod = "POST"
request.addValue("application/json", forHTTPHeaderField: "Accept")
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("<Token>", forHTTPHeaderField: "Authorization")
let requestBody = """
{
"model": "<model>",
"prompt": "<prompt>",
"max_tokens": 200,
"stream": true
}
"""
request.httpBody = requestBody.data(using: .utf8)
let task = URLSession.shared.dataTask(with: request) { data, response, error in
if let error = error {
print("Error: \(error)")
return
}
print((response as? HTTPURLResponse)?.statusCode)
guard let httpResponse = response as? HTTPURLResponse,
(200...299).contains(httpResponse.statusCode) else {
print("Error: invalid HTTP response code")
return
}
guard let data = data else {
print("Error: missing response data")
return
}
let eventStreamString = String(data: data, encoding: .utf8)!
let eventStreamLines = eventStreamString.components(separatedBy: "\n")
for event in eventStreamLines {
let eventFields = event.components(separatedBy: ":")
if eventFields.count < 2 {
continue
}
if fieldName == "data" {
if fieldValue == "[DONE]" {
// Stream terminated
break
} else {
// Process event data
print(event)
}
}
}
}
task.resume()
}
The problem is, it still waits till whole response is in place and then prints the data. What I am trying to achieve is to get the data as and how stream is generated, and not after the whole response is in place.
I am comparatively newbie and would expect a detailed help.

Related

swiftUI : How I can try to do POST API Call with parameters and headers

class TranslateModel : ObservableObject {
func translateCall() {
guard let url = URL(string: "https://openapi.naver.com/v1/papago/n2mt") else { return }
print(1)
let param = "source=en&target=kr&text=hi"
let paramData = param.data(using: .utf8)
var request = URLRequest(url: url)
print(2)
request.httpMethod = "POST"
request.httpBody = paramData
print(3)
request.addValue("application/x-www-form-urlencoded; charset=UTF-8", forHTTPHeaderField: "Content-Type")
request.addValue("3Bwy8lMkuAgZOyDHm1Z3", forHTTPHeaderField: "X-Naver-Client-Id")
request.addValue("gg391Jc1Ge", forHTTPHeaderField: "X-Naver-Client-Secret")
print(4)
let data = URLSession.shared.dataTask(with: request) { data, response, error in
guard let data = data else { fatalError() }
print(5)
guard error == nil else { fatalError()}
print(6)
guard let response = response as? HTTPURLResponse, response.statusCode >= 200 && response.statusCode < 300 else {return}
print(7)
print(data)
}
}
}
Firstly, Please check my code and screenshot.
I tried to do POST API with parameters and headers.
However, when I call the method, It's not working.
So, I checked the step of method, And found that the URLsession with request was not working.
But, I don't know what the problem is.
I think maybe parameters or headers faults.
could you let me know how I can solve this?

How can I make a POST Request in Swift with parameters using URLSession

I have a post request that I want to make using URLSession.
The post request looks like this:
curl -X POST 'https://smartdevicemanagement.googleapis.com/v1/enterprises/privatekey/devices/devicekey:executeCommand' -H 'Content-Type: application/json' -H 'Authorization: authtoken' --data-raw '{
"command" : "sdm.devices.commands",
"params" : {
"commandName" : "cmdValue"
}
}'
As this is a POST request, I want to only decode if the response is an error message.
Here is the code I currently have:
guard let url = URL(string: "https://smartdevicemanagement.googleapis.com/v1/enterprises/\(project_id)/devices") else {return}
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("token", forHTTPHeaderField: "Authorization")
let cmdParams: [String: String] = ["command":"sdm.devices.commands", "params" : ["commandName": "cmdValue"]]
do {
request.httpBody = try JSONSerialization.data(withJSONObject: cmdParams)
} catch let error {
print(error.localizedDescription)
}
URLSession.shared.dataTask(with: request) { (data, response, error) in
guard error == nil else {print(error!.localizedDescription); return }
guard let data = data else {print("empty data"); return }
The cmdParams are throwing an error, so I'm not sure how to structure the params request properly, a successful POST will result in the API returning {} an unsuccessful request will return some error.
How can I adjust my code to get this working?
You need to encode the JSON string as data. Then you can add it as the httpBody. Don't forget to add the token to the request.
// Encode your JSON data
let jsonString = "{ \"command\" : \"sdm.devices.commands\", \"params\" : { \"commandName\" : \"cmdValue\" } }"
guard let jsonData = jsonString.data(using: .utf8) else { return }
// Send request
guard let url = URL(string: "https://smartdevicemanagement.googleapis.com/v1/enterprises/\(project_id)/devices") else {return}
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.httpBody = jsonData
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.setValue("token", forHTTPHeaderField: "Authorization") // Most likely you want to add some token here
// request.setValue("Bearer \(accessToken)", forHTTPHeaderField: "Authorization")
let task = URLSession.shared.dataTask(with: request) { (data, response, error) in
if let error = error {
// Handle HTTP request error
} else if let data = data {
// Handle HTTP request response
} else {
// Handle unexpected error
}
}
task.resume()
You could try using "urlencoded" to encode your request body. Here is my test code:
(note, since I do not have a paid subscription to this service I cannot fully test my code)
struct ContentView: View {
let project_id = 123 // <-- adjust to your needs
var body: some View {
Text("testing")
.onAppear {
if let url = URL(string: "https://smartdevicemanagement.googleapis.com/v1/enterprises/\(project_id)/devices") {
doPOST(url: url)
}
}
}
func doPOST(url: URL) {
var request = URLRequest(url: url)
request.httpMethod = "POST"
// try urlencoding
request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
request.setValue("token", forHTTPHeaderField: "Authorization") // <-- your api "token" here
var components = URLComponents(url: url, resolvingAgainstBaseURL: false)!
components.queryItems = [
URLQueryItem(name: "command", value: "sdm.devices.commands"),
URLQueryItem(name: "params", value: "{ \"commandName\" : \"cmdValue\" }")
]
if let query = components.url!.query {
print("--> query: \(query)")
request.httpBody = Data(query.utf8)
}
let task = URLSession.shared.dataTask(with: request) { data, response, error in
showResponse(data) // <-- for debuging
guard error == nil else { print("--> error: \(error)"); return }
guard let data = data else { print("empty data"); return }
}
task.resume()
}
func showResponse(_ data: Data?) {
if let data = data, let json = try? JSONSerialization.jsonObject(with: data, options: .mutableContainers), let jsonData = try? JSONSerialization.data(withJSONObject: json, options: .prettyPrinted) {
print("\n---> response: " + String(decoding: jsonData, as: UTF8.self))
} else {
print("=========> error")
}
}
}
If this does not work, have a look at this doc:
https://developers.google.com/nest/device-access/reference/rest/v1/enterprises.devices/executeCommand
In particular: The URL uses gRPC Transcoding syntax. It may be relevant.

how to make get request with Authorization api key value in header Swift

below is my get request code. but getting 403 error ...please help!
func getUser(completion: #escaping(Result<User?, AuthenticationError>)-> Void) {
let loginVM = LoginViewModel()
let token = loginVM.accessToken
guard let url = URL(string: myURL) else {
completion(.failure(.custom(errorMessage: "URL is not correct")))
return
}
var request = URLRequest(url:url)
request.httpMethod = "GET"
request.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
URLSession.shared.dataTask(with: request) { (data, response, error) in
guard let data = data, error == nil else {
completion(.failure(.custom(errorMessage: "No data")))
return
}
guard let registerResponse = try? JSONDecoder().decode(User.self, from: data) else{
completion(.failure(.custom(errorMessage: "no response")))
return
}
completion(.success(User))
}.resume()
}
and instruction from my backend guy for this part is this :
I tested on Postman It work as like charm. It must be happen in my request code with Authorization....

how to send a string in body with rawdata in swift 4 without alamofire?

{
"1":[{"name":"some product","type":"simple","quantity":"2","price":"500"}],
"2":[{"name":"Seller 2 add no 2","type":"feature","quantity":"1","price":"500"}],
"is_free_quota":"0",
"quotationIsVerified":"0"
}
this is the string which I have to send
//in this function we are sending token for authentication and data is sending in the raw data form body... with out parameteres and without alamofire
func postRequest() -> Void) {
let parameters = [""]
let url = URL(string: "http://192.168.10.7/retbajri/public/api/request/quot")!
print(url)
let user1 = ["name_or any string data which you want to post"]
let data : Data = user1.data(using: .utf8)!
//create the session object
let session = URLSession.shared
//now create the Request object using the url object
var request = URLRequest(url: url)
request.httpMethod = "POST" //set http method as POST
do {
request.httpBody = try JSONSerialization.data(withJSONObject: parameters, options: .prettyPrinted) // pass dictionary to data object and set it as request body
} catch let error {
print(error.localizedDescription)
completion(nil, error)
}
//HTTP Headers
request.setValue("Bearer \(ttkknn)", forHTTPHeaderField: "Authorization")
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
request.setValue(NSLocalizedString("lang", comment: ""), forHTTPHeaderField:"Accept-Language");
request.httpBody = data
//create dataTask using the session object to send data to the server
let task = session.dataTask(with: request, completionHandler: { data, response, error in
guard error == nil else {
completion(nil, error)
return
}
guard let data = data else {
completion(nil, NSError(domain: "dataNilError", code: -100001, userInfo: nil))
return
}
do {
//create json object from data
guard let json = try JSONSerialization.jsonObject(with: data, options: .mutableContainers) as? [String: Any] else {
completion(nil, NSError(domain: "invalidJSONTypeError", code: -100009, userInfo: nil))
return
}
print(json)
} catch let error {
print(error.localizedDescription)
completion(nil, error)
}
})
task.resume()
}

Swift parsing a http request returns domain error

okay, so Im trying to make a post request but when I try to parse the data, I always get a error domain code= 3840.
https://www.codepunker.com/tools/http-requests/64243-brrjq9t
In this example it shows what the request response looks like.
and this is my code:
let parameters = ["txt": "כאב גרון","usr": "","pass": "" ,"ktivmale": false] as [String : Any]
guard let url = URL(string: "http://www.nakdan.com/GetResult.aspx") else { return }
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("text/xml; charset=utf-8", forHTTPHeaderField: "Content-Type")
guard let httpBody = try? JSONSerialization.data(withJSONObject: parameters, options: []) else { return }
request.httpBody = httpBody
let task = URLSession.shared.dataTask(with: request as URLRequest){
data,response, error in
print(response!)
if error != nil{
print("error")
return
}
do {
let json = try JSONSerialization.jsonObject(with: data!, options: [])
DispatchQueue.main.async(execute: { () -> Void in
print(json)
SVProgressHUD.dismiss()
})
} catch {
print(error)
SVProgressHUD.dismiss()
SVProgressHUD.showError(withStatus: "Connection Failed.")
}
}
task.resume()