Consume tensor-flow serving inception model using C# client (PREDICT API) - api

I have been trying to implement a C# client application to interact with Tensorflow serving server for few weeks now with no success. I have a Python client which works successfully but I can not replicate its functionality with C#. The Python client
import requests
#import json
from keras.preprocessing.image import img_to_array, array_to_img, load_img
from keras.preprocessing import image
flowers = 'c:/flower_photos/cars/car1.jpg'
image1 = img_to_array(image.load_img(flowers, target_size=(128,128))) / 255
payload = {
"instances": [{"image":image1.tolist()},
]
}
print("sending request...")
r = requests.post('http://localhost:8501/v1/models/flowers/versions/1:predict', json=payload)
print(r.content)
The server responds correctly. I am using Tensorflow version 1.12.0 with corresponding latest serving image. They are all working fine.
According to REST API documentation, the API structure is given but its not clear to me at all. I need to send the image to server. How could I add the image payload to JSON request in C# ? After going through many sites, I found that image should be in base64string.
So I did the image conversion into base64
private string GetBase64ImageBytes(string ImagePath)
{
using (Image image = Image.FromFile(ImagePath))
{
using (MemoryStream m = new MemoryStream())
{
image.Save(m, image.RawFormat);
byte[] imageBytes = m.ToArray();
// Convert byte[] to Base64 String
string base64String = Convert.ToBase64String(imageBytes);
return base64String;
}
}
}
The request portion is as follows : (server responds with metadata correctly for the GET request)
public string PostImageToServerAndClassify(string imageArray)
{
//https://stackoverflow.com/questions/9145667/how-to-post-json-to-a-server-using-c
string result = null;
string ModelName = cmbProjectNames.Text.Replace(" ", "");
string status_url = String.Format("http://localhost:{0}/v1/models/{1}/versions/{2}:predict", txtPort.Text, ModelName, txtVersion.Text);
var httpWebRequest = (HttpWebRequest)WebRequest.Create(status_url);
httpWebRequest.ContentType = "application/json";
httpWebRequest.Method = "POST";
try
{
using (var streamWriter = new StreamWriter(httpWebRequest.GetRequestStream()))
{
// string json = "{"+ #"""instances""" + ": [{" + #"""image""" + #":" + imageArray + "}]}";
// imageArray = #""" + imageArray + #""";
string json = "{ " + #"""instances""" + ": [{" + #"""image""" + #": { " + #"""b64"": """ + imageArray + #"""}}]}";
streamWriter.Write(json);
streamWriter.Flush();
streamWriter.Close();
}
var httpResponse = (HttpWebResponse)httpWebRequest.GetResponse();
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
result = streamReader.ReadToEnd();
}
}
catch (Exception ex)
{
result = ex.Message;
}
return result;
}
With the POST request, I get the error message "The remote server returned an error: (400) Bad Request.". Also server terminates its service. In Postman I get
the detailed error info as :
{ "error": "Failed to process element: 0 key: image of \'instances\' list. Error: Invalid argument: JSON Value: {\n \"b64\": \"/9j/4AAQSkZJRgABAQEAAAAAAAD/4QBSRXhpZgAATU0AKgAAAAgAAYdpAAQAAAABAAAAGgAAAAAAAZKGAAcAAAAcAAAALAAAAABVTklDT0RFAABBAHAAcABsAGUATQBhAHIAaw ... .....(image string data)
So this feels like that I am sending the incorrect data format.
Could someone please tell me what is wrong here ? Any example of image conversion and POST request is highly appreciated. I can not find anywhere that base64string format is the right format for the image in TF site. Python client data format is different hence really need to know what is the right format with any reference documents.
The nearest reference I found here with JAVA client but did not work with mine may be due to TF version difference.

Related

Getting (401) UnAuthorized error on some requests not all, but most

I don't think this is a code issue, but we have a list of hundreds of addresses to process. Some return data and we are able to get Long and Lat but most return (401) UnAuthorized errors. What would cause this to happen? We have tried passing Host Headers and everything else, the REST API seems to work better in our development environment but throws way more errors when deployed to our Job Server. Any help on this issue will be greatly appreciated. We would like to understand why some calls work and others don't, we pass the same apiKey each time so this is really confusing. Thanks
Here is a code snippet using c# (Work in progress):
//GET THE LATITUDE AND LONGITUDE BASED OFF THE PHYSICAL ADDRESS
String clientAddress = clientRow["home_address"].ToString() + ", " + clientRow["home_city"].ToString() + ", " + clientRow["home_state"].ToString() + ", " + clientRow["home_zip"].ToString();
Logger.Debug("CLIENT ADDRESS: {0}", clientAddress);
String geocoderUri = "https://geocode.search.hereapi.com/v1/geocode?q=" + clientAddress + "&apiKey=xxxxxxxxxxxxxxxxxxxxx"; //KEY REMOVED FOR POSTING ON STACK OVERFLOW
var syncClient = new WebClient();
var content = syncClient.DownloadString(geocoderUri);
//CREATE THE JSON SERIALIZER AND PARSE OUR RESPONSE
DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(AddressData));
using (var ms = new MemoryStream(Encoding.Unicode.GetBytes(content)))
{
var addressData = (AddressData)serializer.ReadObject(ms);
if (addressData.items.Count() > 0)
{
//INSERT THE LATITUDE AND LONGITUDE IN DB
String sLat = addressData.items[0].position.lat.ToString();
String sLong = addressData.items[0].position.lng.ToString();
Logger.Debug("CLIENT GEOLOCATION - Longitude: {0} Latitude: {1}", sLong, sLat);
insertLatLong(sLat, sLong, clientRow["clientID"].ToString(), 1);
}
}
Would you please try to use RestSharp lib for rest api?
Please see below sample code.
var client = new RestClient("https://geocode.search.hereapi.com/v1/geocode?q="+ clientAddress);
client.Timeout = -1;
var request = new RestRequest(Method.GET);
request.AddHeader("Authorization", "Bearer YOUR TOKEN");
IRestResponse response = client.Execute(request);
Console.WriteLine(response.Content);

Pentaho - upload file using API

I need to upload a file using an API.
I tried REST CLIENT and didn't find any options.
Tried with HTTP POST and that responded with 415.
Please suggest how to accomplish this
Error 415 is “Unsupported media type”.
You may need to change the media type of the request or check whether that type of file us accepted by the remote server.
https://en.m.wikipedia.org/wiki/List_of_HTTP_status_codes
This solution uses only standard classes of jre 7. Add a step Modified Java Script Value in your transformation. You will have to add two columns in the flow: URL_FORM_POST_MULTIPART_COLUMN and FILE_URL_COLUMN, you can add as many files as you want, you will just have to call outputStreamToRequestBody.write more times.
try
{
//in this step you will need to add two columns from the previous flow -> URL_FORM_POST_MULTIPART_COLUMN, FILE_URL_COLUMN
var serverUrl = new java.net.URL(URL_FORM_POST_MULTIPART_COLUMN);
var boundaryString = "999aaa000zzz09za";
var openBoundary = java.lang.String.format("\n\n--%s\nContent-Disposition: form-data\nContent-Type: text/xml\n\n" , boundaryString);
var closeBoundary = java.lang.String.format("\n\n--%s--\n", boundaryString);
// var netIPSocketAddress = java.net.InetSocketAddress("127.0.0.1", 8888);
// var proxy = java.net.Proxy(java.net.Proxy.Type.HTTP , netIPSocketAddress);
// var urlConnection = serverUrl.openConnection(proxy);
var urlConnection = serverUrl.openConnection();
urlConnection.setDoOutput(true); // Indicate that we want to write to the HTTP request body
urlConnection.setRequestMethod("POST");
//urlConnection.addRequestProperty("Authorization", "Basic " + Authorization);
urlConnection.addRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundaryString);
var outputStreamToRequestBody = urlConnection.getOutputStream();
outputStreamToRequestBody.write(openBoundary.getBytes(java.nio.charset.StandardCharsets.UTF_8));
outputStreamToRequestBody.write(java.nio.file.Files.readAllBytes(java.nio.file.Paths.get(FILE_URL_COLUMN)));
outputStreamToRequestBody.write(closeBoundary.getBytes(java.nio.charset.StandardCharsets.UTF_8));
outputStreamToRequestBody.flush();
var httpResponseReader = new java.io.BufferedReader(new java.io.InputStreamReader(urlConnection.getInputStream()));
var lineRead = "";
var finalText = "";
while((lineRead = httpResponseReader.readLine()) != null) {
finalText += lineRead;
}
var status = urlConnection.getResponseCode();
var result = finalText;
var time = new Date();
}
catch(e)
{
Alert(e);
}
I solved this by using the solution from http://www.dietz-solutions.com/2017/06/pentaho-data-integration-multi-part.html
Thanks Ben.
He's written a Java class for Multi-part Form submission. I extendd by adding a header for Authorization...

GDAX Post Call returns invalid signature

I am trying to make a post request on GDAX.
But I always receive a "invalid signature" message.
GDAX API Docs for creating request + signing: https://docs.gdax.com/#creating-a-request
Preshash string returns the following:
1500627733POST/orders{"price":"1000.0","size":"0.02","type":"limit","side":"sell","product_id":"BTC-EUR"}
My signature method:
public String generateSignature(String requestPath, String method, String body, String timestamp) {
try {
String prehash = timestamp + method.toUpperCase() + requestPath + body;
byte[] secretDecoded = Base64.getDecoder().decode(secretKey);
SecretKeySpec keyspec = new SecretKeySpec(secretDecoded, "HmacSHA256");
Mac sha256 = (Mac) Mac.getInstance("HmacSHA256").clone();
sha256.init(keyspec);
return Base64.getEncoder().encodeToString(sha256.doFinal(prehash.getBytes()));
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
My request method:
private boolean placeLimitOrder(String currencyPair, String side, String price, String size)
throws UnirestException {
String timestamp = Instant.now().getEpochSecond() + "";
String api_method = "/orders";
String path = base_url + api_method; //base_url = https://api.gdax.com
String method = "POST";
String b = "{\"price\":\"1000.0\",\"size\":\"0.02\",\"type\":\"limit\",\"side\":\"sell\",\"product_id\":\"BTC-EUR\"}";
JsonNode n = new JsonNode(b);
String sig = generateSignature(api_method, method,b, timestamp);
HttpResponse<JsonNode> rep = Unirest.post(path).header("accept", "application/json")
.header("content-type", "application/json")
.header("CB-ACCESS-KEY", publicKey)
.header("CB-ACCESS-PASSPHRASE", passphrase)
.header("CB-ACCESS-SIGN", sig)
.header("CB-ACCESS-TIMESTAMP", timestamp)
.body(n)
.asJson();
System.out.println(rep.getStatusText()); //Bad Request
System.out.println(rep.getBody().toString()); //invalid signature
System.out.println(sig); //returns something
return false;
}
I also tried to make a API Request Call with Insomnia but it returns the same message ("invalid signature").
Any clues?
Thank you very much in advance!
Looks like you are signing the price order data which is a string, but for the body in the post you are turning it into a json node. Which may not match when gdax decodes the signing and compares the payload data to the decrypted(signed body) when they receive it.
Why not just send the string as the body and remove the ".asJson"?
.body(b)
I was stuck on a similar issue when I was testing the API in C#. After 3 afternoons of trying. I tested sending the data as a string and I was able to get pass the invalid signature error.
I had the same problem.
I used http:
but the right one httpS:
Problem solved.

j2me google translate api

I really need an example how to translate a text with google translate API v2.
I have implemented already the following:
String googleUrl="https://www.googleapis.com/language/translate/v2?key=<My Key>";
googleUrl+="&q=";
googleUrl+=urlEncode(txtFeedback.getString());
googleUrl+="&source=";
googleUrl+=System.getProperty("microedition.locale").substring(0, 2);
googleUrl+="&target=en";
HttpConnection googlAPI = null;
DataInputStream dis = null;
StringBuffer response = new StringBuffer();
googlAPI = (HttpConnection)Connector.open(googleUrl);
googlAPI.setRequestMethod(HttpConnection.GET);
dis = new DataInputStream(googlAPI.openInputStream());
int ch;
while ((ch = dis.read()) != -1) {
response.append((char) ch);
}
String tt = response.toString();
tt = tt.substring(tt.indexOf("{"));
JSONObject js = new JSONObject(tt);
params +=js.getJSONObject("data").getJSONArray("translations").getJSONObject(0)
.getString("translatedText") + crlf;
but this code throws the Certificate exception: certificate was issued by an unrecognized entity
it throws the exception on my real device Samsung GT-S5230 as well as Emulator
Really need help.
If I do something wrong it would be great to get an example how to call the google translate API from j2me midlet.
A quick look shows you are accessing a https url:
String googleUrl="https://www.googleapis.com/language/translate/v2?key=";
using httpConnection
googlAPI = (HttpConnection) Connector.open(googleUrl);
Change that to HttpsConnection
HttpsConnection googlAPI = null;
...
googlAPI = (HttpsConnection) Connector.open(googleUrl);
and let's see how it goes.

jmeter testcases which can handle captcha?

We are trying to build a jmeter testcase which does the following:
login to a system
obtain some information and check whether correct.
Where we are facing issues is because there is a captcha while logging into the system. What we had planned to do was to download the captcha link and display, and wait for user to type in the value. Once done, everything goes as usual.
We couldnt find any plugin that can do the same? Other than writing our own plugin, is there any option here?
I was able to solve it myself. The solution is as follows:
Create a JSR223 PostProcessor (using Groovy)
more practical CAPTCHA example with JSESSIONID handling and proxy setting
using image.flush() to prevent stale CAPTCHA image in dialog box
JSR223 Parameters for proxy connection setting:
Parameters: proxy 10.0.0.1 8080
In it, the following code displays the captcha and waits for user input
import java.awt.Image;
import java.awt.Toolkit;
import javax.swing.Icon;
import javax.swing.JOptionPane;
import org.apache.jmeter.threads.JMeterContextService;
import org.apache.jmeter.threads.JMeterContext;
import org.apache.jmeter.protocol.http.control.CookieManager;
import org.apache.jmeter.protocol.http.control.Cookie;
URL urlTemp ;
urlTemp = new URL( "https://your.domainname.com/endpoint/CAPTCHACode");
HttpURLConnection myGetContent = null;
if(args[0]=="proxy" ){
Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(args[1], Integer.parseInt(args[2])));
myGetContent = (HttpURLConnection) urlTemp.openConnection(proxy);
}else{
myGetContent = (HttpURLConnection) urlTemp.openConnection();
}
// false for http GET
myGetContent.setDoOutput(false);
myGetContent.connect();
int status = myGetContent.getResponseCode();
log.info("HTTP Status Code: "+Integer.toString(status));
if (status == HttpURLConnection.HTTP_OK) {
//We have 2 Set-Cookie headers in response message but 1 Set-Cookie entry in Map
String[] parts2;
for (Map.Entry<String, List<String>> entries : myGetContent.getHeaderFields().entrySet()) {
if( entries.getKey() == "Set-Cookie" ){
for (String value : entries.getValue()) {
if ( value.contains("JSESSIONID") == true ){
String[] parts = value.split(";",2);
log.info("Response header: "+ entries.getKey() + " - " + parts[0] );
JMeterContext context = JMeterContextService.getContext();
CookieManager manager = context.getCurrentSampler().getCookieManager();
parts2 = parts[0].split("=",2)
Cookie cookie = new Cookie("JSESSIONID",parts2[1],"your.domainname.com","/endpoint",true,0, true, true, 0);
manager.add(cookie);
log.info( cookie.toString() );
log.info("CookieCount "+ manager.getCookieCount().toString() );
}
}
}
}//end of outer for loop
if ( parts2.find() == null ) {
throw new Exception("The Response Header not contain Set-Cookie:JSESSIONID= .");
}
}else{
throw new Exception("The Http Status Code was ${status} , not expected 200 OK.");
}
BufferedInputStream bins = new BufferedInputStream(myGetContent.getInputStream());
String destFile = "number.png";
File f = new File(destFile);
if(f.exists() ) {
boolean fileDeleted = f.delete();
log.info("delete file ... ");
log.info(String.valueOf(fileDeleted));
}
FileOutputStream fout =new FileOutputStream(destFile);
int m = 0;
byte[] bytesIn = new byte[1024];
while ((m = bins.read(bytesIn)) != -1) {
fout.write(bytesIn, 0, m);
}
fout.close();
bins.close();
log.info("File " +destFile +" downloaded successfully");
Image image = Toolkit.getDefaultToolkit().getImage(destFile);
image.flush(); // release the prior cache of Captcha image
Icon icon = new javax.swing.ImageIcon(image);
JOptionPane pane = new JOptionPane("Enter Captcha", 0, 0, null);
String captcha = pane.showInputDialog(null, "Captcha", "Captcha", 0, icon, null, null);
captcha = captcha.trim();
captcha = captcha.replaceAll("\r\n", "");
log.info(captcha);
vars.put("captcha", captcha);
myGetContent.disconnect();
By vars.put method we can use the captcha variable in any way we want. Thank you everyone who tried to help.
Since CAPTHA used to detect non-humans, JMeter will always fail it.
You have to make a workaround in your software: either disable captcha requesting or print somewhere on page correct captcha. Of course, only for JMeter tests.
Dirty workaround? Print the captcha value in alt image for the tests. And then you can retrieve the value and go on.