Clarifai Exception: Maximum attempts reached of getting a default model - java

I'm getting this exception in my logs: "clarifai2.exception.ClarifaiException: Maximum attempts reached of getting a default model." which is being generated by a large number of my android app users, but I am unable to replicate the exception or determine what is causing it. Any help on how to recreate or even better prevent this exception from occurring would be very helpful.
UPDATE:
I found the issue and am able to reproduce on demand, if no internet connection is available the Clarifai library throws this exception, there is no check for network connection state within the library. I can check for network connection in my app before building the clarifai client, but if the network connection is lost after the client is built this exception is generated, any ideas on how to prevent this? Thank you.
1 - Ensure data connection to internet is available on phone.
2 - Build clarifai client in onCreate
3 - Send clarifai predict request to food model
4 - Disable wifi and mobile data connections on phone
5 - Wait 10 to 15 seconds, can navigate to other activities, then clarifai throws "Clarifai Exception: Maximum attempts reached of getting a default model" and crashes the app.
Clarifai Library class which can throw this exception is available HERE
I call the buildClarifaiClient method below in my onCreate of the requesting activity.
private void buildClarifaiClient(){
if(clarifaiClient == null){
clarifaiClient = new ClarifaiBuilder("KeyString")
.client(new OkHttpClient.Builder()
.connectTimeout(60, TimeUnit.SECONDS)
.readTimeout(60, TimeUnit.SECONDS)
.writeTimeout(60, TimeUnit.SECONDS)
//.addInterceptor(new HttpLoggingInterceptor(logger::info).setLevel(HttpLoggingInterceptor.Level.BASIC))
.build()
)
.buildSync();
}
}
Request to Clarifai on ActivityResult after a picture is taken:
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_IMAGE_CAPTURE && resultCode == RESULT_OK) {
if(clarifaiClient != null) {
snapSearchActivityResult = true;
taskClarifaiRequest = new AsyncTask<Void, Void, ClarifaiResponse<List<ClarifaiOutput<Concept>>>>() {
#Override
protected void onPreExecute() {
}
#Override
protected ClarifaiResponse<List<ClarifaiOutput<Concept>>> doInBackground(Void... params) {
// The default Clarifai model that identifies concepts in images
// Use this model to predict, with the image that the user just selected as the input
return clarifaiClient.getDefaultModels().foodModel().predict()
.withInputs(ClarifaiInput.forImage(ClarifaiImage.of(getPicByteData())))
.executeSync();
}
#Override
protected void onPostExecute(ClarifaiResponse<List<ClarifaiOutput<Concept>>> response) {
//setBusy(false);
if (!response.isSuccessful()) {
showErrorSnackbar(getString(R.string.clarifaiAPIContactError));
return;
}
final List<ClarifaiOutput<Concept>> predictions = response.get();
if (predictions.isEmpty()) {
showErrorSnackbar(getString(R.string.clarifaiAPIResultsError));
return;
}
List<Concept> concepts = predictions.get(0).data();
int conceptsSize = concepts.size();
Log.d("conceptsSize", String.valueOf(conceptsSize));
for (Concept c : concepts) {
// Do something with the value
Log.d("foodName", String.valueOf(c.name()));
Log.d("foodProb", String.valueOf(c.value()));
}
}
private void showErrorSnackbar(String errorString) {
Snackbar.make(
parentLayout,
errorString,
Snackbar.LENGTH_LONG
).show();
}
};
taskClarifaiRequest.execute();
} else {
Snackbar.make(
parentLayout,
"Unable to connect to Image API, try again.",
Snackbar.LENGTH_LONG
).show();
buildClarifaiClient();
}
}
Stacktrace:
Exception clarifai2.exception.ClarifaiException: Maximum attempts
reached of getting a default model.
clarifai2.dto.model.DefaultModels.update ()
clarifai2.dto.model.DefaultModels.access$000 ()
clarifai2.dto.model.DefaultModels$1.run ()
java.util.concurrent.ThreadPoolExecutor.runWorker
(ThreadPoolExecutor.java:1113)
java.util.concurrent.ThreadPoolExecutor$Worker.run
(ThreadPoolExecutor.java:588)
java.lang.Thread.run (Thread.java:818)

I'd say that the API key you use here doesn't have permissions for doing get model request. When you access the food model via getDefaultModels(), the model is first updated (via get model request) and only after that the predict request is run. If the first one fails, the second one doesn't run.
In the Java API client 2.3 which is about to be released next week, the call getDefaultModels() will no longer initiate get model request since most of the time you require only an ID of a default model, not the complete model data which get model request returns. Since only predict request will be performed, you will not need to have get model request permissions on your API key.
In the meanwhile, you can do one of two things. Either:
Add Models:Get permission to your API key. You do this by going to the API keys page, editing your API key, clicking ADVANCED under Scopes and checking Models:Get. You probably already have Predict permission checked.
Or use the model ID directly on the predict call. I've inserted the food default model ID (which you can also see in the DefaultModels.java link you posted above) into the predict call for you: client.predict("bd367be194cf45149e75f01d59f77ba7").withInputs(...).executeSync();.

Related

How do I authenticate with my Google Cloud Function when using my Firebase App with Google Sign In?

I am a newbie (6 months going or so) and creating an app on Android (Java) that utilizes FireBase Auth with Google Sign In. (with only a few days of NodeJS exposure now) In other words my end user signs in with the Google Account. That part (I think) works pretty well so far. I use the Firestore Database heavily for a lot of things in the app.
So now I've gotten to the point where I want to use (Callable) Cloud Functions with HTTP Triggers. (never having done any of this before) I'm trying to get a proof of concept working at this time. The actual function works and I can trigger it from my app.
It appears that I cannot figure out how to make the function "private" though; as in "adding proper Members" to the Cloud function who have the right to invoke the function.
I have tried a few different things by trial error, but first let me show what I have.
This is the Cloud Function and I'm passing in an arbitrary String as a test, works nicely: (as long as "allUsers" have the role/right to invoke the function; in other words when the function is public.
exports.createTest = functions.https.onCall((data, context) => {
const text = data.text;
const uid = context.auth.uid;
const name = context.auth.token.name || null;
const email = context.auth.token.email || null;
console.log('UID: ', uid);
console.log('Name: ', name);
console.log('Email: ', email);
console.log('Message: ', text);
});
The above function gets triggered in my Android/Java code like this: (I think this code came from Google Doc/Sample/Example
private FirebaseFunctions mFunctions;
...
private void testing() {
mFunctions = FirebaseFunctions.getInstance();
Log.e(LOG_TAG, "Testing executed!");
String testMessage = "Hello Hello Testing 123 Mic Check";
createTest(testMessage)
.addOnCompleteListener(new OnCompleteListener<String>() {
#Override
public void onComplete(#NonNull Task<String> task) {
if (!task.isSuccessful()) {
Exception e = task.getException();
if (e instanceof FirebaseFunctionsException) {
FirebaseFunctionsException ffe = (FirebaseFunctionsException) e;
FirebaseFunctionsException.Code code = ffe.getCode();
Object details = ffe.getDetails();
Log.e(LOG_TAG, "FFE: " + ffe.getMessage() );
Log.e(LOG_TAG, "Code: " + code);
Log.e(LOG_TAG, "Details:" + details);
}
// ...
}
// ...
}
});
}
private Task<String> createTest(String text) {
// Create the arguments to the callable function.
Map<String, Object> data = new HashMap<>();
data.put("text", text);
data.put("push", true);
return mFunctions
.getHttpsCallable("createTest") //this is the function name
.call(data)
.continueWith(new Continuation<HttpsCallableResult, String>() {
#Override
public String then(#NonNull Task<HttpsCallableResult> task) throws Exception {
// This continuation runs on either success or failure, but if the task
// has failed then getResult() will throw an Exception which will be
// propagated down.
String result = (String) task.getResult().getData();
if (result != null) {
Log.e(LOG_TAG, "Result: " + result);
}
return result;
}
});
}
Only when I have "allUsers" added with the role/right to "invoke Cloud Function" then I get this working. My understanding of HTTP Requests and such is pretty limited, which is not making things easier.
I tried using the "allAuthenticatedUsers" options, which I figured would do the trick, because I actually authenticate my Users in the app through Firebase/Google Sign In. This Cloud Function shall only be available to either a) authenticated users or b) users of a specific domain. (I have a domain, let's say #testorganization.com) Or if I can identify my particular app (api key?) then that would work, too.
The moment I add a member "allAuthenticatedUsers" with role to invoke the function (and remove "allUsers) nothing happens. I also tried adding the entire domain, but that wouldn't work. (duh) Also tried adding my service account (trial and error at this point) and didn't seem to work.
In my Node JS code I am actually receiving the UID of the authenticated user, so it appears that some kind of user authentication information is already being exchanged.
With that knowledge, I can (successfully tried this) get the UID and cross check that against my database and verify a user that way, but seems unnecessary and I should be able to make the permissions work. (lock the function down entirely) Plus this took a really long time just finish this cross check. Or is this pretty standard procedure to do?
Like this-->
const usersRef = admin.firestore().collection('users').doc(uid)
usersRef.get()
.then((docSnapshot) => {
if (docSnapshot.exists) {
usersRef.onSnapshot((doc) => {
console.log('User Type logged in: ', doc.data().userCategory)
console.log('User Title: ', doc.data().userTitle)
});
} else {
console.log('User does not exist')
}
});
Edit:
So while not having figured out how to shut down the function entirely, I did discover that instead of cross checking my users, I can simple check for auth like this:
if (context.auth){
//user is auth'd
} else {
//no auth
}
That's a little bit better, I guess. (but still doesn't technically prevent access to the function?!)
Thank you so much for any help. Much appreciated.
Edit2:
Here is a screensshot of the area in the cloud console (for cloud function roles/privileges) that I am referring to:
https://imgur.com/cBsjaaL
With a Callable Cloud Function, if you want to ensure that only authenticated users can trigger it's business logic, you actually don't need to configure any extra "cloud function roles/privileges" as shown at the bottom of your question.
By default, with a Callable Cloud Function you will get, when available, "Firebase Authentication and FCM tokens automatically included in requests" and it will "automatically deserializes the request body and validates auth tokens", as explained in the doc.
So you just have to follow the doc and use the context parameter. As you have mentioned in your question, you can check the user is authenticated by doing:
if (context.auth) {
//...
}
If you want to verify the user email, you would do:
exports.addMessage = functions.https.onCall((data, context) => {
const uid = context.auth.uid;
return admin.auth().getUser(uid)
.then(userRecord => {
const userEmail = userRecord.email;
//....
})
.catch(function(error) {
console.log('Error fetching user data:', error);
// Send back an error to the front end
// See https://firebase.google.com/docs/functions/callable#handle_errors
});
});
You will find more examples on how to "work with" users with the Admin SDK here in the doc.

Problem with the bluetooth connection of the Relay - RxAndroidBle

I speak english a little bit sorry. I need your help because I have invested many hours, and I can not finish the last detail: _ (
I have to connect a mobile phone with bluetooth LE to a relay, to open or close the door. Provide with native Bluetooth and with sockets, but there was no way to do anything that worked. After researching a lot, I found the RxAndroidBle library and got the first results.
The problem is that I'm not used to programming with the reactive paradigm and I really do not know what I'm doing. I pass the code and the steps that follow, to see if something escapes me.
Steps:
Connect directly by known MAC address to device
Send opening hexadecimal command
In successful case, execute closing command with DELAY
private void SendCommandRele(String enable, String disable, int time) {
bleDevice = rxBleClient.getBleDevice("BB:A0:56:06:0A:0A");
byte[] data = hexStringToByteArray (enable);
UUID uuid = UUID.fromString("0000ffe1-0000-1000-8000-00805f9b34fb");
connectionDisposable = bleDevice.establishConnection(false)
.observeOn(AndroidSchedulers.mainThread())
.flatMapSingle(rxBleConnection -> rxBleConnection.writeCharacteristic(uuid, data))
.doOnError(error -> errorConnection())
.doOnComplete(new Action() {
#Override
public void run() throws Exception {
CloseDevice(disable);
}
})
//.repeat(3)
.retryWhen(io.reactivex.Observable::cache)
.doAfterNext(next -> CloseDevice(disable))
//.take(1)
.subscribe(
well -> {
Handler handler = new Handler();
handler.postDelayed(
new Runnable() {
#Override
public void run() {
CloseDevice(disable);
}
},
time
);
},
failed -> Log.e("E","Error: ")
);
progressDialog.dismiss();
//connectionDisposable.dispose();
}
--
private void CloseDevice(String disable) {
bleDevice = rxBleClient.getBleDevice("BB:A0:56:06:0A:0A");
byte[] data = hexStringToByteArray (disable);
connectionDisposable = bleDevice.establishConnection(false)
.observeOn(AndroidSchedulers.mainThread())
.flatMapSingle(rxBleConnection ->
rxBleConnection.writeCharacteristic(UUID.fromString("0000ffe1-0000-1000-8000-00805f9b34fb"), data)
)
.doOnError(error -> {errorConnection();})
//.repeat(3)
//.retry(3)
.take(1)
.subscribe(
);
progressDialog.dismiss();
}
Actual results:
In general, the results I have are quite positive since sometimes it works, but sometimes it does not. A rath, works 10 times in a row, and the other does not work at all. Of course I need a stable connection.
Expected results:
correct work
I found this errors:
- Task COMMON_BROADCAST_MESSAGE_RECIVED failed or timed out. Client disconnecting.
- bta_gattc_mark_bg_conn unable to find the bg connection mask for: XX:XX:XX:XX:XX

Google Play Games API returns SIGN_IN_REQUIRED

I'm trying to implement automating player sign in to Google Play games in my Android app. Firstly, as mentioned here, I try to sign in silently:
#Override
protected void onResume() {
super.onResume();
signInSilently();
}
private void signInSilently() {
mGoogleSignInClient.silentSignIn().addOnCompleteListener(this, task -> {
if (task.isSuccessful())
//everything ok
else {
final ApiException exception = (ApiException) task.getException();
if (BuildConfig.DEBUG)
Log.d(TAG, "Silent Sign In failure: ", exception);
if (exception.getStatusCode() == CommonStatusCodes.SIGN_IN_REQUIRED)
startSignInIntent();
}
});
Every time I got an exception with code 4 (CommonStatusCodes.SIGN_IN_REQUIRED). So in this case I try to sign in with ui:
private void startSignInIntent() {
startActivityForResult(mGoogleSignInClient.getSignInIntent(), RC_SIGN_IN);
}
#Override
protected void onActivityResult(int request, int response, Intent data) {
super.onActivityResult(request, response, data);
if (request == RC_SIGN_IN) {
final GoogleSignInResult result = Auth.GoogleSignInApi.getSignInResultFromIntent(data);
if (result.isSuccess()) {
// everything is ok, get account from result
} else if (result.getStatus().hasResolution()) {
resolveManually(result.getStatus());
} else {
String message = result.getStatus().getStatusMessage();
if (BuildConfig.DEBUG)
Log.d(TAG, "status code" + result.getStatus().getStatusCode());
if (message == null || message.isEmpty()) {
message = "other error";
}
new AlertDialog.Builder(this).setMessage(message)
.setNeutralButton(android.R.string.ok, null).show();
}
}
}
And here everytime I get message with other error! The status code is again 4 (CommonStatusCodes.SIGN_IN_REQUIRED). How can I get this code when I try to sign in using intent? So, my app are in infinite loop because onResume is called everytime my activity loads after receiving a result, and everytime the status code is CommonStatusCodes.SIGN_IN_REQUIRED. So, where is the problem?
In Google samples there is no information how can I handle automatic sign in, only manual with sign in buttons. But google recommends to use automating sign in. Please help anybody to understand what is wrong here.
You must not start the login screen from your onResume method. It is a silent login which works if the user wants it (by tapping a button). That's why the examples show it only this way.
There was wrong OAuth 2.0 client ID for the debug version of my app! Don't know why there is SIGN_IN_REQUIRED status code in this situation, it is really confusing!

How can I pass data returned from Facebook when Request.callback onCompleted() method is called, to my fragment in Android?

I'm currently trying to integrate Facebook into my Android application. I've had no problems getting the app to connect and authenticate. But I'm having a little trouble understanding how I can handle data once the onCompleted(Response response) callback method is executed.
The method below works:
private void onSessionStateChange(Session session, SessionState state,
Exception exception) {
if (state.isOpened()) {
Log.i(TAG, "Logged in...");
new Request(session, "/me", null, HttpMethod.GET,
new Request.Callback() {
#Override
public void onCompleted(Response response) {
GraphObject graphObject = response.getGraphObject();
JSONObject data = graphObject.getInnerJSONObject();
Log.i(TAG, "My DETAILS: ");
try {
Log.i(TAG, "ID: " + data.getLong("id"));
Log.i(TAG, "Name: " + data.getString("name"));
Log.i(TAG, "Email: " + data.getString("email"));
Log.i(TAG,
"Gender: " + data.getString("gender"));
} catch (JSONException e) {
e.printStackTrace();
}
}
}).executeAsync();
} else if (state.isClosed()) {
Log.i(TAG, "Logged out...");
}
}
When I run my application, Facebook authenticates, the data is retrieved and successfully outputs to the Logcat window. However, I'm at a loss to understand how I can pass the JSONObject back to my fragment for further processing.
Most examples I've looked at online simply set the JSONObject content to views in the fragment, or even less helpful simply say /* Handle response here */ or something similar.
I have another similar method where I want to get a profile image url and download the image, but I can't get the url back to my fragment for further processing.
Should I do something like develop a runnable class that accepts a JSONObject as a parameter and start a separate thread from the onCompleted() method to process it the way I want?
My current goal is to get a list of the users friends who use my app and save their profile pictures for use within the app. Am I going about this the wrong way?
SO if I understand you properly, you are getting all data, you are able to parse the JSON but you are not able to pass the data to your other fragment? Why dont you write to a file, which can be accessible from anywhere?
Why do you want to "DOWNLOAD" the images, that will increase your processing time. Just use this URL: https://graph.facebook.com/"+uid.trim()+"/picture?type=normal Where uid is your users id. Use this in Conjunction with Universal Image Loader to asynchronously load your images in image view. You save your time - you save a headache of manually caching files or saving them on the SD.
But bro, the problem here is that Facebook will stop support to the API you are using by April of 2015. Start porting your app to use the latest facebook API; which however is not so useful in getting users information. Cheers and keep on coding :)

Unable to create link with DBX chooser error android

I am attempting to integrate the Dropbox chooser drop-in api into my application. I am running into an abnormal issue. In my app when I launch the dbx chooser, anytime that I select a file the application fails with the following error code:
Sorry, an error has occurred. Please try again later.
Here is the portion of my code that implements the Dropbox API. This portion of the code is where the dropbox api is initially invoked.
public void StartDropboxApplication() {
// create the chooser
DbxChooser chooser = new DbxChooser(APP_KEY);
DbxChooser.ResultType result;
// determine which mode to be in // TODO REMOVE ALL BUT FILE CONTENT TODO SIMPLIFY by making this a setting
switch(( (RadioGroup) ParentActivity.findViewById(R.id.link_type)).getCheckedRadioButtonId() ) {
case R.id.link_type_content:
result = DbxChooser.ResultType.DIRECT_LINK;
break;
default:
throw new RuntimeException("Radio Group Related error.");
}
// launch the new activity
chooser.forResultType(result).launch(ParentActivity, 0);
}
Here is the position where the code should then pick it up although it never does.
protected void onActivityResult( int request, int result, Intent data ) {
Log.i(fileName, "result: " + result);
// check to see if the camera took a picture
if (request == 1) {
// check to see if the picture was successfully taken
if (result == Activity.RESULT_OK) {
onPicture();
} else {
Log.i(fileName, "Camera App cancelled.");
}
} else if (request == 0) {
if ( result == Activity.RESULT_OK ) {
onDropbox(data);
} else {
Log.i(fileName, "dropbox related issue.");
}
}
}
Thank you for any help or suggestions that you are able to provide.
I was able to solve my own issues and get this working. On the off chance that someone else has a similar problem I will detail the solution. The first issue was I was that my APP_KEY was incorrect.
The next issue was that I was attempting to read from a direct link instead of a content link. The direct link provides the application with a link to the file on the Dropbox server whereas the content link provides the application with a cached version of the file. If the file is not present on the device, the SDK downloads a copy for you.

Categories