I'm getting an error when I try to run the example Visual Recognition script found on the IBM Watson Github. The error can be found here:
I'm running the script using the IBM Watson Unity SDK. The error is code 400, and states
Invalid Request: provided vmodel-id header must be non-empty.
I have no idea what could be causing this error as there's no vmodel-id
in any of the code.
The code is unchanged from the example on the website, minus the API information and such. Here it is for reference:
**
* Copyright 2015 IBM Corp. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#pragma warning disable 0649
// Uncomment to train a new classifier
//#define TRAIN_CLASSIFIER
// Uncommnent to delete the trained classifier
//#define DELETE_TRAINED_CLASSIFIER
using UnityEngine;
using System.Collections;
using IBM.Watson.DeveloperCloud.Services.VisualRecognition.v3;
using IBM.Watson.DeveloperCloud.Logging;
using IBM.Watson.DeveloperCloud.Utilities;
using System.Collections.Generic;
using IBM.Watson.DeveloperCloud.Connection;
public class ExampleVisualRecognition : MonoBehaviour
{
#region PLEASE SET THESE VARIABLES IN THE INSPECTOR
[Space(10)]
[Tooltip("The service URL (optional). This defaults to \"https://gateway.watsonplatform.net/visual-recognition/ap\"")]
[SerializeField]
private string _serviceUrl;
[Tooltip("The version date with which you would like to use the service in the form YYYY-MM-DD.")]
[SerializeField]
private string _versionDate;
[Header("IAM Authentication")]
[Tooltip("The IAM apikey.")]
[SerializeField]
private string _iamApikey;
#endregion
private VisualRecognition _visualRecognition;
private string _classifierID = "";
private string _imageURL = "https://upload.wikimedia.org/wikipedia/commons/e/e9/Official_portrait_of_Barack_Obama.jpg";
#if TRAIN_CLASSIFIER
private string _coreMLDownloadPath = "";
#endif
#if DELETE_TRAINED_CLASSIFIER
private string _classifierToDelete;
#endif
private bool _getClassifiersTested = false;
#if TRAIN_CLASSIFIER
private bool _trainClassifierTested = false;
private bool _getClassifierTested = false;
#endif
#if DELETE_TRAINED_CLASSIFIER
private bool _deleteClassifierTested = false;
#endif
private bool _classifyGetTested = false;
private bool _classifyPostTested = false;
private bool _detectFacesGetTested = false;
private bool _detectFacesPostTested = false;
#if TRAIN_CLASSIFIER
private bool _getCoreMLModelTested = false;
private bool _isClassifierReady = false;
#endif
void Start()
{
LogSystem.InstallDefaultReactors();
Runnable.Run(CreateService());
}
private IEnumerator CreateService()
{
if (string.IsNullOrEmpty(_iamApikey))
{
throw new WatsonException("Plesae provide IAM ApiKey for the service.");
}
Credentials credentials = null;
// Authenticate using iamApikey
TokenOptions tokenOptions = new TokenOptions()
{
IamApiKey = _iamApikey
};
credentials = new Credentials(tokenOptions, _serviceUrl);
// Wait for tokendata
while (!credentials.HasIamTokenData())
yield return null;
// Create credential and instantiate service
_visualRecognition = new VisualRecognition(credentials);
_visualRecognition.VersionDate = _versionDate;
Runnable.Run(Examples());
}
private IEnumerator Examples()
{
// Get all classifiers
Log.Debug("ExampleVisualRecognition.Examples()", "Attempting to get all classifiers");
if (!_visualRecognition.GetClassifiersBrief(OnGetClassifiers, OnFail))
Log.Debug("ExampleVisualRecognition.GetClassifiers()", "Failed to get all classifiers!");
while (!_getClassifiersTested)
yield return null;
#if TRAIN_CLASSIFIER
// Train classifier
Log.Debug("ExampleVisualRecognition.Examples()", "Attempting to train classifier");
string positiveExamplesPath = Application.dataPath + "/Watson/Examples/ServiceExamples/TestData/visual-recognition-classifiers/giraffe_positive_examples.zip";
string negativeExamplesPath = Application.dataPath + "/Watson/Examples/ServiceExamples/TestData/visual-recognition-classifiers/negative_examples.zip";
Dictionary<string, string> positiveExamples = new Dictionary<string, string>();
positiveExamples.Add("giraffe", positiveExamplesPath);
if (!_visualRecognition.TrainClassifier(OnTrainClassifier, OnFail, "unity-test-classifier-example", positiveExamples, negativeExamplesPath))
Log.Debug("ExampleVisualRecognition.TrainClassifier()", "Failed to train classifier!");
while (!_trainClassifierTested)
yield return null;
// Find classifier by ID
Log.Debug("ExampleVisualRecognition.Examples()", "Attempting to find classifier by ID");
if (!_visualRecognition.GetClassifier(OnGetClassifier, OnFail, _classifierID))
Log.Debug("ExampleVisualRecognition.GetClassifier()", "Failed to get classifier!");
while (!_getClassifierTested)
yield return null;
#endif
// Classify get
Log.Debug("ExampleVisualRecognition.Examples()", "Attempting to get classify via URL");
if (!_visualRecognition.Classify(_imageURL, OnClassifyGet, OnFail))
Log.Debug("ExampleVisualRecognition.Classify()", "Classify image failed!");
while (!_classifyGetTested)
yield return null;
// Classify post image
Log.Debug("ExampleVisualRecognition.Examples()", "Attempting to classify via image on file system");
string imagesPath = Application.dataPath + "/Watson/Examples/ServiceExamples/TestData/visual-recognition-classifiers/giraffe_to_classify.jpg";
string[] owners = { "IBM", "me" };
string[] classifierIDs = { "default", _classifierID };
if (!_visualRecognition.Classify(OnClassifyPost, OnFail, imagesPath, owners, classifierIDs, 0.5f))
Log.Debug("ExampleVisualRecognition.Classify()", "Classify image failed!");
while (!_classifyPostTested)
yield return null;
// Detect faces get
Log.Debug("ExampleVisualRecognition.Examples()", "Attempting to detect faces via URL");
if (!_visualRecognition.DetectFaces(_imageURL, OnDetectFacesGet, OnFail, "es"))
Log.Debug("ExampleVisualRecognition.DetectFaces()", "Detect faces failed!");
while (!_detectFacesGetTested)
yield return null;
// Detect faces post image
Log.Debug("ExampleVisualRecognition.Examples()", "Attempting to detect faces via image");
string faceExamplePath = Application.dataPath + "/Watson/Examples/ServiceExamples/TestData/visual-recognition-classifiers/obama.jpg";
if (!_visualRecognition.DetectFaces(OnDetectFacesPost, OnFail, faceExamplePath, "es"))
Log.Debug("ExampleVisualRecognition.DetectFaces()", "Detect faces failed!");
while (!_detectFacesPostTested)
yield return null;
#if DELETE_TRAINED_CLASSIFIER
Runnable.Run(IsClassifierReady(_classifierToDelete));
while (!_isClassifierReady)
yield return null;
// Download Core ML Model
Log.Debug("ExampleVisualRecognition.RunTest()", "Attempting to get Core ML Model");
if (!_visualRecognition.GetCoreMLModel(OnGetCoreMLModel, OnFail, _classifierID))
Log.Debug("TestVisualRecognition.GetCoreMLModel()", "Failed to get core ml model!");
while (!_getCoreMLModelTested)
yield return null;
// Delete classifier by ID
Log.Debug("ExampleVisualRecognition.Examples()", "Attempting to delete classifier");
if (!_visualRecognition.DeleteClassifier(OnDeleteClassifier, OnFail, _classifierToDelete))
Log.Debug("ExampleVisualRecognition.DeleteClassifier()", "Failed to delete classifier!");
while (!_deleteClassifierTested)
yield return null;
#endif
Log.Debug("ExampleVisualRecognition.Examples()", "Visual Recogition tests complete");
}
private void OnGetClassifiers(ClassifiersBrief classifiers, Dictionary<string, object> customData)
{
Log.Debug("ExampleVisualRecognition.OnGetClassifiers()", "VisualRecognition - GetClassifiers Response: {0}", customData["json"].ToString());
_getClassifiersTested = true;
}
#if DELETE_TRAINED_CLASSIFIER
private void OnGetClassifier(ClassifierVerbose classifier, Dictionary<string, object> customData)
{
Log.Debug("ExampleVisualRecognition.OnGetClassifier()", "VisualRecognition - GetClassifier Response: {0}", customData["json"].ToString());
_getClassifierTested = true;
}
#endif
#if DELETE_TRAINED_CLASSIFIER
private void OnDeleteClassifier(bool success, Dictionary<string, object> customData)
{
Log.Debug("ExampleVisualRecognition.OnDeleteClassifier()", "{0}", success);
_deleteClassifierTested = true;
}
#endif
#if TRAIN_CLASSIFIER
private void OnTrainClassifier(ClassifierVerbose classifier, Dictionary<string, object> customData)
{
Log.Debug("ExampleVisualRecognition.OnTrainClassifier()", "{0}", customData["json"].ToString());
#if DELETE_TRAINED_CLASSIFIER
_classifierToDelete = classifier.classifier_id;
#endif
_classifierID = classifier.classifier_id;
_trainClassifierTested = true;
}
#endif
private void OnClassifyGet(ClassifiedImages classify, Dictionary<string, object> customData)
{
Log.Debug("ExampleVisualRecognition.OnClassifyGet()", "{0}", customData["json"].ToString());
_classifyGetTested = true;
}
private void OnClassifyPost(ClassifiedImages classify, Dictionary<string, object> customData)
{
Log.Debug("ExampleVisualRecognition.OnClassifyPost()", "{0}", customData["json"].ToString());
_classifyPostTested = true;
}
private void OnDetectFacesGet(DetectedFaces multipleImages, Dictionary<string, object> customData)
{
Log.Debug("ExampleVisualRecognition.OnDetectFacesGet()", "{0}", customData["json"].ToString());
_detectFacesGetTested = true;
}
private void OnDetectFacesPost(DetectedFaces multipleImages, Dictionary<string, object> customData)
{
Log.Debug("ExampleVisualRecognition.OnDetectFacesPost()", "{0}", customData["json"].ToString());
_detectFacesPostTested = true;
}
#if DELETE_TRAINED_CLASSIFIER
private void OnGetCoreMLModel(byte[] resp, Dictionary<string, object> customData)
{
Log.Debug("ExampleVisualRecognition.OnGetCoreMLModel()", "SUCCESS!");
_getCoreMLModelTested = true;
}
#endif
#if DELETE_TRAINED_CLASSIFIER
#region Is Classifier Ready
// Checking if classifier is ready before deletion due to a known bug in the Visual Recognition service where
// if a classifier is deleted before it is `ready` or `failed` the classifier will still exist in object storage
// but will be inaccessable to the user.
private IEnumerator IsClassifierReady(string classifierId)
{
Log.Debug("TestVisualRecognition.IsClassifierReady()", "Checking if classifier is ready in 15 seconds...");
yield return new WaitForSeconds(15f);
Dictionary<string, object> customData = new Dictionary<string, object>();
customData.Add("classifierId", classifierId);
if (!_visualRecognition.GetClassifier(OnCheckIfClassifierIsReady, OnFailCheckingIfClassifierIsReady, classifierId))
IsClassifierReady(classifierId);
}
private void OnCheckIfClassifierIsReady(ClassifierVerbose response, Dictionary<string, object> customData)
{
Log.Debug("TestVisualRecognition.IsClassifierReady()", "Classifier status is {0}", response.status);
if (response.status == "ready" || response.status == "failed")
{
_isClassifierReady = true;
}
else
{
Runnable.Run(IsClassifierReady(response.classifier_id));
}
}
private void OnFailCheckingIfClassifierIsReady(RESTConnector.Error error, Dictionary<string, object> customData)
{
IsClassifierReady(_classifierToDelete);
}
#endregion
#endif
private void OnFail(RESTConnector.Error error, Dictionary<string, object> customData)
{
Log.Error("ExampleRetrieveAndRank.OnFail()", "Error received: {0}", error.ToString());
}
}
There was an error in the example. When classify runs no classifierID is present so the data the call is sending is incorrect. An issue was raised in the SDK repo. Please change line 155 in ExampleVisualRecognition.cs
string[] classifierIDs = { "default", _classifierID };
to
string[] classifierIDs = { "default" };
This has been addressed in this pull request and the fix is available if you pull down the latest from master
.