How to connect Stanford Core Server from dotnet - stanford-nlp

I am trying to use Stanford NLP for.NET. I am very new to this.
How can I connect Stanford core NLP server from c# program
My NLP server runs on localhost:9000

You can connect via the .NET HTTPClient or other equivalent .NET call to a web endpoint. You need to set up your NLP endpoint, properties for the NLP server, and the text content you want it to parse. There is additional information on the Stanford NLP Server page, as well as information on what properties can be set depending on what NLP pipeline you want to run.
The following code is from a .NET Core console application using the following call to return Named Entity Recognition, Dependency Parser and OpenIE results.
FYI I've had some occasions where my NLP endpoint didn't work when waking a laptop from sleep mode (Docker for Windows pre 17.12 on Win10). Resetting Docker did the trick for me... if you can't browse to your http://localhost:9000 website, then the endpoint definitely won't work either!
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Net.Http;
// String to process
string s = "This is the sentence to provide to NLP."
// Set up the endpoint
string nlpBaseAddress = "http://localhost:9000"
// Create the query string params for NLPCore
string jsonOptions = "{\"annotators\": \"ner, depparse, openie\", \"outputformat\": \"json\"}";
Dictionary qstringProperties = new Dictionary();
qstringProperties.Add("properties", jsonOptions);
string qString = ToQueryString(qstringProperties);
// Add the query string to the base address
string urlPlusQuery = nlpBaseAddress + qString;
// Create the content to submit
var content = new StringContent(s);
content.Headers.Clear();
content.Headers.Add("Content-Type", "application/x-www-form-urlencoded");
// Submit for processing
var client = new HttpClient();
HttpResponseMessage response;
Task tResponse = client.PostAsync(urlPlusQuery, content);
tResponse.Wait();
response = tResponse.Result;
// Check the response
if (response.StatusCode != System.Net.HttpStatusCode.OK)
{
// Do something better than throwing an app exception here!
throw new ApplicationException("Subject-Object tuple extraction returned an unexpected response from the subject-object service");
}
Task rString = response.Content.ReadAsStringAsync();
rString.Wait();
string jsonResult = rString.Result;
Utility function used within this call to generate a QueryString:
private string ToQueryString(Dictionary nvc)
{
System.Text.StringBuilder sb = new System.Text.StringBuilder("?");
bool first = true;
foreach (KeyValuePair key in nvc)
{
// CHeck if this is the first value
if (!first)
{
sb.Append("&");
}
sb.AppendFormat("{0}={1}", Uri.EscapeDataString(key.Key), Uri.EscapeDataString(key.Value));
first = false;
}
return sb.ToString();
}

Related

Azure function - request image from 3d party then send image to requestor without saving to local directory

I've found lots of questions about downloading images and as my code shows that is what I ended up doing. However that is not the behavior I want. I just want it to return the image directly.
using System.Net;
using Microsoft.Extensions.Logging;
using System.IO;
public static async Task<HttpResponseMessage> Run(HttpRequest req, ILogger log, string data)
{
log.LogInformation("start function...");
string qrData = $"{data}";//req.Query["id"];
string QrGeneratorUrl = "https://api.qrserver.com/v1/create-qr-code/?size=100x100&data="+ qrData;
log.LogInformation("QrUrl= " + QrGeneratorUrl);
var filename = "temp.png";
var filePath = Path.Combine(#"d:\home\site\wwwroot\QrGeneratorTest\"+filename);
WebClient myWebClient = new WebClient();
myWebClient.DownloadFile(QrGeneratorUrl, filePath);
var response = new HttpResponseMessage(HttpStatusCode.OK);
var fileStream = new FileStream(filePath, FileMode.Open);
response.Content = new StreamContent(fileStream);
return response;
}
I've tried converting the image to a byte stream and adding the stream to the response content, I've tried putting the image data directly as string content... nothing seems to work - it only transmits the image if it is a local file and I add it to the response via fileStream. Does someone know how I can get it to just put the response I get into the response I am returning? Or explain why it can't be done? This is functionality that exists in a web app that we are trying the move into a function and the web app is able to pass the content along without saving it. Using a byte stream. But I can't seem to replicate that in the function.
There are 2 reasons we are not calling qr server directly
1) it's a 3d party site so it could go down and we need to be able to swap it out for a new provider from one location.
2) we need to build the url so it has not parameters (?p=1&q=2&r=3...) as this is going into an email and having a bunch of parameters often tags the email as junk. With Azure (as with our web app) we can build the url like this: /getImage/1/2/3 which is less likely to be tagged as spam
any insight would be appreciated!!
//*******************//
ANSWER
here is my final code. I think the issue was Stream vs MemoryStream... In any case here is the full code:
#r "Newtonsoft.Json"
using System.Net;
using System;
using System.Web;
using System.Threading.Tasks;
using System.IO;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
public static async Task<HttpResponseMessage> Run(HttpRequest req, ILogger log, string data)
{
log.LogInformation("start function...");
string qrData = $"{data}";
//string qrData = DateTime.Now.Ticks.ToString();
string QrGeneratorUrl = "https://api.qrserver.com/v1/create-qr-code/?size=100x100&qzone=2&data="+ qrData;
//get the QR image from 3d party api
var httpWebRequest = WebRequest.Create(QrGeneratorUrl);
var httpResponse = await httpWebRequest.GetResponseAsync();
//put 3d party response into function response
Stream ms = httpResponse.GetResponseStream(); //new MemoryStream(bytes);
var result = new HttpResponseMessage(HttpStatusCode.OK);
result.Content = new StreamContent(ms);
result.Content.Headers.ContentType = new MediaTypeHeaderValue("image/png");
return result;
}
Suppose you want to download the image to stream and just return it(If use browser send the request, show the image in the browser, If I get it wrong please let me know). If this is your purpose you could refer to my below code, I download the image from blob and return it to FileContentResult.
using System;
using System.IO;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Microsoft.WindowsAzure.Storage;
using Microsoft.WindowsAzure.Storage.Blob;
using System.DrawingCore;
namespace FunctionApp72
{
public static class Function1
{
[FunctionName("Function1")]
public static async Task<IActionResult> RunAsync(
[HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req,
ILogger log)
{
log.LogInformation("C# HTTP trigger function processed a request.");
CloudStorageAccount blobAccount = CloudStorageAccount.Parse(Environment.GetEnvironmentVariable("AzureWebJobsStorage"));
CloudBlobClient blobClient = blobAccount.CreateCloudBlobClient();
CloudBlobContainer blobContainer = blobClient.GetContainerReference("test");
CloudBlockBlob cloudBlockBlob = blobContainer.GetBlockBlobReference("test.jpg");
MemoryStream streamIn = new MemoryStream();
await cloudBlockBlob.DownloadToStreamAsync(streamIn);
Image originalImage = Bitmap.FromStream(streamIn);
return new FileContentResult(ImageToByteArray(originalImage), "image/jpeg");
}
private static byte[] ImageToByteArray(Image image)
{
ImageConverter converter = new ImageConverter();
return (byte[])converter.ConvertTo(image, typeof(byte[]));
}
}
}
And I deploy it to azure It still could return the image.

Various errors using VisionServiceClient in XamarinForms

I am trying to create a simple Xamarin forms app which allows the user to browse for or take a photo and have azure cognitive services tag the photo using a custom vision model.
I am unable to get the client to successfully authenticate or find a resource per the error message in the exception produced by the VisionServiceClient. Am I missing something? What would be the correct values to use for the arguments to VisionServiceClient?
All keys have been removed from the below images, they are populated.
Exception thrown in VS2017:
'Microsoft.ProjectOxford.Vision.ClientException' in System.Private.CoreLib.dll
Call to VisionServiceClient:
private const string endpoint = #"https://eastus2.api.cognitive.microsoft.com/vision/prediction/v1.0";
private const string key = "";
VisionServiceClient visionClient = new VisionServiceClient(key, endpoint);
VisualFeature[] features = { VisualFeature.Tags, VisualFeature.Categories, VisualFeature.Description };
try
{
AnalysisResult temp = await visionClient.AnalyzeImageAsync(imageStream,
features.ToList(), null);
return temp;
}
catch(Exception ex)
{
return null;
}
VS Exception Error:
Azure Portal for cognitive services:
Custom Vision Portal:
It looks like you're confusing the Computer Vision and the Custom Vision APIs. You are attempting to use the client SDK for the former using the API key of the latter.
For .NET languages, you'll want the Microsoft.Azure.CognitiveServices.Vision.CustomVision.Prediction NuGet package.
Your code will end up looking something like this:
ICustomVisionPredictionClient client = new CustomVisionPredictionClient()
{
ApiKey = PredictionKey,
Endpoint = "https://southcentralus.api.cognitive.microsoft.com"
};
ImagePrediction prediction = await client.PredictImageAsync(ProjectId, stream, IterationId);
Thank you to cthrash for the extended help and talking with me in chat. Using his post along with a little troubleshooting I have figured out what works for me. The code is super clunky but it was just to test and make sure I'm able to do this. To answer the question:
Nuget packages and classes
Using cthrash's post I was able to get both the training and prediction nuget packages installed, which are the correct packages for this particular application. I needed the following classes:
Microsoft.Azure.CognitiveServices.Vision.CustomVision.Prediction
Microsoft.Azure.CognitiveServices.Vision.CustomVision.Prediction.Models
Microsoft.Azure.CognitiveServices.Vision.CustomVision.Training
Microsoft.Azure.CognitiveServices.Vision.CustomVision.Training.Models
Endpoint Root
Following some of the steps Here I determined that the endpoint URL's only need to be the root, not the full URL provided in the Custom Vision Portal. For instance,
https://southcentralus.api.cognitive.microsoft.com/customvision/v2.0/Prediction/
Was changed to
https://southcentralus.api.cognitive.microsoft.com
I used both the key and endpoint from the Custom Vision Portal and making that change I was able to use both a training and prediction client to pull the projects and iterations.
Getting Project Id
In order to use CustomVisionPredictionClient.PredictImageAsync you need a Guid for the project id and an iteration id if a default iteration is not set in the portal.
I tested two ways to get the project id,
Using project id string from portal
Grab the project id string from the portal under the project settings.
For the first argument to PredictImageAsync pass
Guid.Parse(projectId)
Using the training client
Create a new CustomVisionTrainingClient
To get a list of <Project> use
TrainingClient.GetProjects().ToList()
In my case I only had a single project so I would just need the first element.
Guid projectId = projects[0].Id
Getting Iteration Id
To get the iteration id of a project you need the CustomVisionTrainingClient.
Create the client
To get a list of <Iteration> use
client.GetIterations(projectId).ToList()
In my case I had only a single iteration so I just need the first element.
Guid iterationId = iterations[0].Id
I am now able to use my model to classify images. In the code below, fileStream is the image stream passed to the model.
public async Task<string> Predict(Stream fileStream)
{
string projectId = "";
//string trainingEndpoint = "https://southcentralus.api.cognitive.microsoft.com/customvision/v2.2/Training/";
string trainingEndpoint = "https://southcentralus.api.cognitive.microsoft.com/";
string trainingKey = "";
//string predictionEndpoint = "https://southcentralus.api.cognitive.microsoft.com/customvision/v2.0/Prediction/";
string predictionEndpoint = "https://southcentralus.api.cognitive.microsoft.com";
string predictionKey = "";
CustomVisionTrainingClient trainingClient = new CustomVisionTrainingClient
{
ApiKey = trainingKey,
Endpoint = trainingEndpoint
};
List<Project> projects = new List<Project>();
try
{
projects = trainingClient.GetProjects().ToList();
}
catch(Exception ex)
{
Debug.WriteLine("Unable to get projects:\n\n" + ex.Message);
return "Unable to obtain projects.";
}
Guid ProjectId = Guid.Empty;
if(projects.Count > 0)
{
ProjectId = projects[0].Id;
}
if (ProjectId == Guid.Empty)
{
Debug.WriteLine("Unable to obtain project ID");
return "Unable to obtain project id.";
}
List<Iteration> iterations = new List<Iteration>();
try
{
iterations = trainingClient.GetIterations(ProjectId).ToList();
}
catch(Exception ex)
{
Debug.WriteLine("Unable to obtain iterations.");
return "Unable to obtain iterations.";
}
foreach(Iteration itr in iterations)
{
Debug.WriteLine(itr.Name + "\t" + itr.Id + "\n");
}
Guid iteration = Guid.Empty;
if(iterations.Count > 0)
{
iteration = iterations[0].Id;
}
if(iteration == Guid.Empty)
{
Debug.WriteLine("Unable to obtain project iteration.");
return "Unable to obtain project iteration";
}
CustomVisionPredictionClient predictionClient = new CustomVisionPredictionClient
{
ApiKey = predictionKey,
Endpoint = predictionEndpoint
};
var result = await predictionClient.PredictImageAsync(Guid.Parse(projectId), fileStream, iteration);
string resultStr = string.Empty;
foreach(PredictionModel pred in result.Predictions)
{
if(pred.Probability >= 0.85)
resultStr += pred.TagName + " ";
}
return resultStr;
}

Cloud AutoML API has not been used in project 618104708054 before or it is disabled

I am trying to build a .NET small app to predict images using my model that was trianed on AutoML.
But I am getting this error:
Cloud AutoML API has not been used in project 618104708054 before or
it is disabled. Enable it by visiting
https://console.developers.google.com/apis/api/automl.googleapis.com/overview?project=618104708054
then retry. If you enabled this API recently, wait a few minutes for
the action to propagate to our systems and retry
First - this is not the project I am using.
Second - If I go to the link with my real project id - it says to me that the api is working well.
My code look like these:
public static string SendPOST(string url, string json)
{
var httpWebRequest = (HttpWebRequest)WebRequest.Create(url);
httpWebRequest.ContentType = "application/json";
httpWebRequest.Method = "POST";
httpWebRequest.Headers.Add("Authorization", "Bearer GOOGLE_CLOUD_TOKEN");
using (var streamWriter = new StreamWriter(httpWebRequest.GetRequestStream()))
{
streamWriter.Write(json);
streamWriter.Flush();
streamWriter.Close();
}
var httpResponse = (HttpWebResponse)httpWebRequest.GetResponse();
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
//var res = new JavaScriptSerializer().Deserialize<Response>(result);
//return res;
return result;
}
}
I will appriciate your help,
Thanks.
I finally succeded to make it, the only issue is that I needed to create a service account using the web console:
https://console.cloud.google.com/projectselector/iam-admin/serviceaccounts?supportedpurview=project&project=&folder=&organizationId=
And then to download the json key and push it via the gcloud command from my PC -
gcloud auth activate-service-account --key-file="[/PATH/TO/KEY/FILE.json]
I found the solution in this post:
"(403) Forbidden" when trying to send an image to my custom AutoML model via the REST API

Globally formatting .net Web Api response

I have a Web Api service that retrieves data from another service, which returns Json. I don't want to do anything to the response, I just want to return it directly to the client.
Since the response is a string, if I simply return the response, it contains escape characters and messy formatting. If I convert the response in to an object, the WebApi will use Json.Net to automatically format the response correctly.
public IHttpActionResult GetServices()
{
var data = _dataService.Get(); //retrieves data from a service
var result = JsonConvert.DeserializeObject(data); //convert to object
return Ok(result);
}
What I would like is to either A: Be able to return the exact string response from the service, without any of the escape characters and with the proper formatting, or B: Set a global settings that will automatically Deserialize the response so that the Web Api can handle it the way I am doing it already.
On Startup I am setting some values that describe how formatting should be handled, but apparently these aren't correct for what im trying to do.
HttpConfiguration configuration = new HttpConfiguration();
var settings = configuration.Formatters.JsonFormatter.SerializerSettings;
settings.Formatting = Formatting.Indented;
settings.ContractResolver = new DefaultContractResolver();
Do I need to create a custom ContractResolver or something? Is there one that already handles this for me?
Thanks
If you want to just pass through the json (Option A), you can do this
public IHttpActionResult GetServices() {
var json = _dataService.Get(); //retrieves data from a service
HttpContent content = new System.Net.Http.StringContent(json, Encoding.UTF8, "application/json");
var response = Request.CreateResponse(HttpStatusCode.OK);
response.Content = content;
return ResponseMessage(response);
}

WebService ASP.NET MVC 3 Send and Receive

I've been racking my brain for a couple of days now on how to approach a new requirement.
I have two websites. The first one lets the user fill out an application. The second website is an internal website use to manage the users applications. I need to develop a "web service" that sends the application data from website 1 to website 2 and return a response to website 2 of success or failure. I have never done a web service before and I'm a bit confused on where to start. I've been reading various examples online but they all seem to be just a starting point for building a webservice... no specific examples.
So for posting the data website 1, what would my controller method look like? Do I use Json to post the data to website 2? What would and example of that look like? Is there some form of redirect in the method that points to website 2?
So for posting the response back to website 2 what would that controller method look like? I assume I would use Json again to send the response back to website 1? Is there some form of redirect in the method that points back to website 1?
I would use JSON and POST the application to the web service.
First I am assuming the application data is contained in some type of object. Use JSON.Net to serialize the object into JSON. It will look something like the following code.
var application = new Application();
string serializedApplication = JsonConvert.Serialize(application);
Second is to POST the code your endpoint(webservice, mvc action). To this you'll need to make a HTTPRequest to the endpoint. The following code is what I use to make to POST the code.
public bool Post(string url, string body)
{
//Make the post
ServicePointManager.ServerCertificateValidationCallback = (sender, certificate, chain, errors) => true;
var bytes = Encoding.Default.GetBytes(body);
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
Stream stream = null;
try
{
request.KeepAlive = false;
request.ContentLength = bytes.Length;
request.ContentType = "application/x-www-form-urlencoded";
request.Timeout = -1;
request.Method = "POST";
stream = request.GetRequestStream();
stream.Write(bytes, 0, bytes.Length);
}
finally
{
if (stream != null)
{
stream.Flush();
stream.Close();
}
}
bool success = GetResponse(request);
return success;
}
public bool GetResponse(HttpWebRequest request)
{
bool success;
using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
{
using (Stream responseStream = response.GetResponseStream())
{
if (response.StatusCode != HttpStatusCode.OK && response.StatusCode != HttpStatusCode.Created)
{
throw new HttpException((int)response.StatusCode, response.StatusDescription);
}
var end = string.Empty;
using (StreamReader reader = new StreamReader(responseStream))
{
end = reader.ReadToEnd();
reader.Close();
success = JsonConvert.DeserializeObject<bool>(end);
}
response.Close();
}
}
return success;
}
So now you have can POST JSON to an endpoint and receive a response the next step is to create the endpoint. The following code will get you started on an endpoint in mvc that will receive an application and process it.
[HttpPost]
public ActionResult SubmitApplication()
{
//Retrieve the POSTed payload
string body;
using (StreamReader reader = new StreamReader(Request.InputStream))
{
body = reader.ReadToEnd();
reader.Close();
}
var application = JsonConvert.Deserialize<Application>(body);
//Save the application
bool success = SaveApplication(application);
//Send the server a response of success or failure.
return Json(success);
}
The above code is a good start. Please note, I have not tested this code.
You have obviously more than one client for the data & operations. so a service is what you are looking for.
ASP.NET MVC is a good candidate for developing RESTful services. If you (and your Manager) are ready to use beta version, Then Checkout ASP.NET-Web API.
If you want to stay with a stable product, Go for MVC3. you may need to write some custom code to return the data in XML as well as JSON to server different kind of clients. There are some tutorials out there.
So create a Service (ASP.NET MVC / WCF Service) .You may then create 2 client apps, one for the external clients and another for the Internal users. Both of this apps can call methods in the Service to Create/ Read the user accounts / or whatever operation you want to do.
To make the apps more interactive and lively , you may conside including a wonderful thing called SiganalR, which helps you to get some real time data without continuosly polling the data base/ middle tier very in every n seconds !

Resources