How to Send Request from iOS (Swift) to Dialogflow V2 API Without Cloud Functions

How to send request from iOS (Swift) to Dialogflow V2 API without Cloud Functions?

While it is possible, it is not a good idea.

In theory, you can call the Dialogflow Detect Intent API directly from your application using a REST interface.

The problem is that, as part of this, you need to include authentication. This authentication is based on a service account and the private key for that account.

So in order to send a request to your service, you need to include the private key in your app. As you might guess - this is somewhat insecure. Which is why the SO question you link to suggests using a web service (it doesn't have to be on Cloud Functions - it can be anywhere) as the intermediary. You can put the private key in the service, where it can be more protected, and use some less secure method to communicate between your app and the service if you feel its necessary.

Dialogflow integration of enterprise edition v2 into the ios and andriod app

To update your agent to V2, you should create a Cloud Function for Firebase that sends requests to Dialogflow (using dialogflow-nodejs-client-v2), then call that Cloud Function from your iOS or Android code rather than calling the API directly.

The major benefit of this approach is that you will no longer have your API credentials exposed on the client side, which is a security risk.

How to send post request to Firebase function?

The main thing you are missing is JSON string in your iOS code. in Android you are using JSONObject then convert it to String. whereas in your iOS, this conversion is missing. Try below code. see if its working or not. I've made some adjustments which should satisfy your need.

import Foundation

let headers = [
"Content-Type": "application/json",
"Cache-Control": "no-cache",
"Authorization" : "your token"
]
let parameters = [
"email": "abc@abc.com",
"uid": "12"
] as [String : Any]

let postData = JSONSerialization.data(withJSONObject: parameters, options: [])

let request = NSMutableURLRequest(url: NSURL(string: "https://us-central1-ryyde-sj.cloudfunctions.net/payout")! as URL,
cachePolicy: .useProtocolCachePolicy,
timeoutInterval: 10.0)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers
request.httpBody = postData as Data

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
if (error != nil) {
print(error)
} else {
let httpResponse = response as? HTTPURLResponse
print(httpResponse)
}
})

dataTask.resume()

Cloud Function annotateImage() returns 'Unexpected token o in JSON at position 1' to native iOS app

I was able to resolve the error by using the solution suggested here:

  1. Change the 'features' dictionary value of requestData to an array.
  2. Pass requestData as encoded string JSON to annotateImage().

But still the line

guard let annotation = (result?.data as? [String: Any])?["fullTextAnnotation"] as? [String: Any]

was returning nil.

The line was not correctly parsing the result object. I solved the nil return by serially downcasting result.data to an NSArray, and then index 0 of the NSArray to an NSDictionary. Then I was able to access the fullAnnotatedText field of the NSDictionary as a [String: Any].

Full code:

import Foundation
import Firebase
import Resolver

class ImageAnnotator: ObservableObject {
@LazyInjected var functions: Functions
@Published var annotatedText: String?

func annotateImage(imageData: Data) {

struct requestData: Encodable {
let image: [String: Data]
let features = [["type": "DOCUMENT_TEXT_DETECTION"]]

init(imageData: Data) {
image = ["content": imageData]
}
}

let encoder = JSONEncoder()

let encodedData = try! encoder.encode(requestData(imageData: imageData))
let string = String(data: encodedData, encoding: .utf8)!

functions.httpsCallable("annotateImage").call(string) { (result, error) in
if let error = error as NSError? {
if error.domain == FunctionsErrorDomain {
let code = FunctionsErrorCode(rawValue: error.code)
let message = error.localizedDescription
let details = error.userInfo[FunctionsErrorDetailsKey]
print("ERROR \(String(describing: message)), CODE \(String(describing: code)), DETAILS \(String(describing: details))")
}
return
}

print("Success.")

DispatchQueue.main.async {
/* Parse result object */
guard let nsarray = result?.data as? NSArray
else {
return
}

guard let nsdictionary = nsarray[0] as? NSDictionary
else {
return
}

guard let fullTextAnnotation = nsdictionary["fullTextAnnotation"] as? [String: Any]
else {
return
}

let text = fullTextAnnotation["text"] as? String ?? ""
print("Recognized text: \(text)")
}
}
}
}

Building a Multi-Tenant App with Dialog Flow

To have separate chatbots I will export my dialogflow agent as zip and will import it in separate project for different customer base.

The export/import option can be found in Settings > Import and export tab

Dialogflow V2 (beta1) SDK for Obj-C

I don't think there's a library written specifically for Dialogflow v2; however, the library google-api-objectivec-client-for-rest is a generic library provided by Google, that simplifies the code to consume their Rest APIs.

This library is updated to be used with Dialogflow V2. In order to use it, you'll need to match the Rest API, with the "Queries" (API methods) and "Objects" (API types) in the library, which is not that difficult because the names are basically the same.

For example, the detectIntent method full name is:

projects.agent.sessions.detectIntent

In the library, it is the equivalent to the Query:

GTLRDialogflowQuery_ProjectsAgentSessionsDetectIntent

Here's an example of a detectIntent request:

// Create the service
GTLRDialogflowService *service = [[GTLRDialogflowService alloc] init];

// Create the request object (The JSON payload)
GTLRDialogflow_GoogleCloudDialogflowV2DetectIntentRequest *request =
[GTLRDialogflow_GoogleCloudDialogflowV2DetectIntentRequest object];

// Set the information in the request object
request.inputAudio = myInputAudio;
request.outputAudioConfig = myOutputAudioConfig;
request.queryInput = myQueryInput;
request.queryParams = myQueryParams;

// Create a query with session (Path parameter) and the request object
GTLRDialogflowQuery_ProjectsAgentSessionsDetectIntent *query =
[GTLRDialogflowQuery_ProjectsAgentSessionsDetectIntent queryWithObject:request
session:@"session"];

// Create a ticket with a callback to fetch the result
GTLRServiceTicket *ticket =
[service executeQuery:query
completionHandler:^(GTLRServiceTicket *callbackTicket,
GTLRDialogflow_GoogleCloudDialogflowV2DetectIntentResponse *detectIntentResponse,
NSError *callbackError) {
// This callback block is run when the fetch completes.
if (callbackError != nil) {
NSLog(@"Fetch failed: %@", callbackError);
} else {
// The response from the agent
NSLog(@"%@", detectIntentResponse.queryResult.fulfillmentText);
}
}];

You can find more information and samples, in the library wiki. Finally, the library also has a sample code using Google Cloud Storage which ilustrates its use with GCP services.

I think that without a specific library for Dialogflow V2, this might be the next thing to try before implementing it from scratch.

EDIT

Oops, I was missing the fact that the generated service for Dialogflow does not contain v2beta1.

In this case, it is needed an additional first step, which is to use the Dialogflow v2beta1 DiscoveryDocument and the ServiceGenerator, to create the service interface for v2beta1. Then you can continue working the same as I mentioned before.

Firebase delete user cloud function not working

You are mixing up callable functions with normal HTTP functions. They don't work the same way.

Your function is a normal HTTP function, but you're trying to call it using the Firebase library for invoking callable type functions. This won't work. The client SDK only works with callable functions as you see in the documentation. Please read that documentation thorough to understand how callable functions work.

If you want to keep using a normal HTTP function, you should invoke it instead with a standard HTTP client library.

Unexpected token stripe when trying to deploy Firebase Functions

This error is because on the cloud environment the stripe library is not installed before you require it.

npm install does install the dependencies but in your local environment, to install them on the Cloud Functions envirornment you need to edit the package.json file from the Cloud Function.

This to add the dependencies that it will be required by the function.

This is done by adding the dependency section to the package.json file

It will lok something like:

{
"name": "sample-name",
"version": "0.0.1",
"dependencies": {
"escape-html": "^1.0.3",
"stripe": "^8.24.0"
}
}

EDIT

With this code it works on Cloud functions:

const stripe = require('stripe')('<My Secret Key>');

exports.helloWorld = (req, res) => {
let paymentIntent = null;

paymentIntent = stripe.paymentIntents.create({
amount: 2000,
currency: 'usd',
description: 'My first payment',
});
let message = req.query.message || req.body.message || 'Hello World!';
res.status(200).send(message);
};

Apparently the issue was the await because HTTP Cloud Functions work on a Synchronous way



Related Topics



Leave a reply



Submit