I call the microsoft recognize text api by passing the image that I had taken from my phone, there no error occur but every time the api will return me empty string as result doesn't matter what image I post . I try those image with the microsoft ocr api and it return me result, can anyone help ?
I call the microsoft recognize text api by passing the image that I had taken from my phone, there no error occur but every time the api will return me empty string as result doesn't matter what image I post.
In documentation of Recognize Text API, we can find:
The service has accepted the request and will start processing later.
It will return Accepted immediately and include an “Operation-Location” header. Client side should further query the operation status using the URL specified in this header.
I suspect that you directly get/extract content from the response after you made a request to recognize text, so the content would be string.Empty.
To get recognize text operation result, you need to make a further request using the URL specified in response header "Operation-Location".
In following test code, we can find the content is indeed empty.
Test Code:
var client = new HttpClient();
var queryString = HttpUtility.ParseQueryString(string.Empty);
client.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", "{Subscription_Key_here}");
queryString["mode"] = "Printed";
var uri = "https://{region}.api.cognitive.microsoft.com/vision/v2.0/recognizeText?" + queryString;
HttpResponseMessage response;
var imagePath = #"D:\xxx\xxx\xxx\testcontent.PNG";
Stream imageStream = File.OpenRead(imagePath);
BinaryReader binaryReader = new BinaryReader(imageStream);
byte[] byteData = binaryReader.ReadBytes((int)imageStream.Length);
using (var content = new ByteArrayContent(byteData))
{
content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
response = await client.PostAsync(uri, content);
if (response.IsSuccessStatusCode)
{
var contentString = await response.Content.ReadAsStringAsync();
var operation_location = response.Headers.GetValues("Operation-Location").FirstOrDefault();
Console.WriteLine($"Response content is empty({contentString == string.Empty}).\n\rYou should further query the operation status using the URL ({operation_location}) specified in response header.");
}
}
Test Result:
Note: Recognize Text API is currently in preview and is only available for English text. As you mentioned, OCR technology in Computer Vision can also help detect text content in an image, and OCR currently supports 25 languages, sometimes we can use OCR as an alternative solution.
Related
I'm experiencing a problem when trying to use MultipartFormDataContent with HttpClient with a stream of data.
Context
I'm trying to upload a large file to ASP.NET Core Web API. A client should send the file via POST request form-data to a front-end API, which in turn should forward the file to a back-end API.
Because the file can be large, I followed the Microsoft example, i.e. I don't want to use IFormFile type but instead read the Request.Body using MultipartReader. This is to avoid loading the entire file into memory on the server, or saving it in a temporary file on server's hard drive.
Problem
The back-end API controller action looks as follows (this is almost directly copied from the ASP.NET Core 5.0 sample app with just minor simplifications):
[HttpPost]
[DisableRequestSizeLimit]
public async Task<IActionResult> ReceiveLargeFile()
{
var request = HttpContext.Request;
if (!request.HasFormContentType
|| !MediaTypeHeaderValue.TryParse(request.ContentType, out var mediaTypeHeader)
|| string.IsNullOrEmpty(mediaTypeHeader.Boundary.Value))
{
return new UnsupportedMediaTypeResult();
}
var reader = new MultipartReader(mediaTypeHeader.Boundary.Value, request.Body);
/* This throws an IOException: Unexpected end of Stream, the content may have already been read by another component. */
var section = await reader.ReadNextSectionAsync();
while (section != null)
{
var hasContentDispositionHeader = ContentDispositionHeaderValue.TryParse(section.ContentDisposition,
out var contentDisposition);
if (hasContentDispositionHeader
&& contentDisposition!.DispositionType.Equals("form-data")
&& !string.IsNullOrEmpty(contentDisposition.FileName.Value))
{
/* Fake copy to nothing since it doesn't even get here */
await section.Body.CopyToAsync(Stream.Null);
return Ok();
}
section = await reader.ReadNextSectionAsync();
}
return BadRequest("No files data in the request.");
}
I managed to reduce the problem slightly by making an integration test using Microsoft.AspNetCore.Mvc.Testing NuGet package. The following test replaces the front-end API, so instead of reading Request.Body stream in a Web API, the test just tries to add StreamContent to MultipartFormDataContent and post it via HttpClient to the back-end API:
[Fact]
public async Task Client_posting_to_Api_returns_Ok()
{
/* Arrange */
await using var stream = new MemoryStream();
await using var writer = new StreamWriter(stream);
await writer.WriteLineAsync("FILE CONTENTS");
await writer.FlushAsync();
stream.Position = 0;
using var client = _factory.CreateDefaultClient();
/* Act */
using var response =
await client.PostAsync(
"Receive",
new MultipartFormDataContent
{
{
new StreamContent(stream),
"file",
"fileName"
}
});
/* Assert */
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
}
The back-end API controller then throws an IOException at await reader.ReadNextSectionAsync(), saying "Unexpected end of Stream, the content may have already been read by another component".
GitHub Repository (Complete Example)
I uploaded a complete example of the problem (including back-end API and the test) a GitHub repo.
Question
I must be doing something wrong. How can I forward a file received in a request with form-data content type in one service (front-end API) to another service (back-end API) without loading the entire file into memory or hard-drive in the front-end API, i.e. to just forward the stream of data to the back-end API?
Thanks in advance for any help.
I expected the same issue as you and it turned out that the MediaTypeHeaderValue.TryParse method parses the boundary value wrong as it wraps the string with '"' characters, because HttpClient sends the content type header like this:
multipart/form-data; boundary="blablabla"
So for me the solution was to add a Trim() method to boundary like this and pass that to the MultipartReader
var boundary = mediaTypeHeader.Boundary.Value.Trim('"');
var reader = new MultipartReader(boundary, request.Body);
I am attempting to execute my own HTTP signed request since there is no SDK in C# for the PutMedia API for the AWS Kinesis Video Stream, but I am getting the following error message:
StatusCode: 403, ReasonPhrase: 'Forbidden'
x-amzn-ErrorType: InvalidSignatureException:http://internal.amazon.com/coral/com.amazon.coral.service/
Here is a gist of what my code looks like:
var streamName = "audio-stream-test";
var service = "kinesisvideo";
var endpoint = GetPutMediaEndpoint(streamName);
var host = GetHostFromEndpoint(endpoint);
var region = GetRegionFromEndpoint(endpoint);
var t = DateTime.UtcNow;
var canonical_uri = $"{endpoint}/putMedia";
var httpRequestMessage = new HttpRequestMessage(HttpMethod.Post, new Uri(canonical_uri));
httpRequestMessage.Headers.Add("connection", "keep-alive");
httpRequestMessage.Headers.Add("host", host);
httpRequestMessage.Headers.Add("Transfer-Encoding", "chunked");
httpRequestMessage.Headers.Add("user-agent", "AWS-SDK-KVS/2.0.2");
httpRequestMessage.Headers.Add("x-amzn-fragment-acknowledgment-required", "1");
httpRequestMessage.Headers.Add("x-amzn-fragment-timecode-type", "ABSOLUTE");
httpRequestMessage.Headers.Add("x-amzn-producer-start-timestamp", (t - DateTime.MinValue).TotalMilliseconds.ToString());
httpRequestMessage.Headers.Add("x-amzn-stream-name", streamName);
httpRequestMessage.Headers.Add("x-amz-security-token", sessionToken);
var byteArray = File.ReadAllBytes(filePath);
var content = new ByteArrayContent(byteArray);
httpRequestMessage.Content = content;
var httpClient = new HttpClient();
var aws4RequestSigner = new AWS4RequestSigner(accessKey, secretAccessKey);
var signedHttpRequestMessage = aws4RequestSigner.Sign(httpRequestMessage, service, region).Result;
var httpResponseMessage = httpClient.SendAsync(signedHttpRequestMessage);
Screenshot of Error
I am using the Aws4RequestSigner NuGet package to sign the request. Any ideas what I am doing wrong here? Has anyone tried to use the AWS Kinesis Video Stream with C#/.NET successfully?
Two potential issues with the pseudo-code.
If using session token then the request signing should include the session token as well not only access key/secret access key combination.
The body of the PutMedia is "endless" as it streams out as a realtime stream. As such, the data shouldn't be included in the signature calculation.
This is answer to your question "the actual "content" is not being added to the stream. I see the Put Connection from KVS but no data added".
After you get 200 by setting http headers properly for the signing with below code, you need to have your content set in signedHttpRequestMessage.
var httpResponseMessage = httpClient.SendAsync(signedHttpRequestMessage);
I am using c# and Xamarin.Android.
My question may not be very standard,because it doesn't have any code.But I just want to know what's the HttpURLConnection class provides.
As everyone knows, an http/https request has request header, request body, response header, and response body.
But I think HttpURLConnection class is still too abstract.What's InputStream and OutputStream(or getInputStream and getOutputStream method in Android document)?
Microsoft document just told that's System.IO.Stream, like nothing.Android doc told me these method return InputStream or OutputStream.
I don't know if InputStream and OutputStream are very important concepts in Java.If they're, please tell me what'll happen if I call their ToString method.And I just want know how to get the response body and how to set the request body.
If you're using not c# but Java to develop Android App, you can also help me!Just tell me what method should I use(In Java), and I will be able to find it in Microsoft doc.
Please help!I'll wait here.
PS:Some parts of the article is translated by machine, include this sentence.
Here is a simple sample that using HttpURLConnection by Java.you could refer to it,and then convert to C# :
URL url = new URL("http://*******");
HttpURLConnection httpCon = (HttpURLConnection) url.openConnection();
httpCon.setDoOutput(true);
httpCon.setRequestMethod("POST");
//set request body
OutputStream os = httpCon.getOutputStream();
OutputStreamWriter osw = new OutputStreamWriter(os, "UTF-8");
osw.write("Just Some Text");
osw.flush();
osw.close();
os.close(); //don't forget to close the OutputStream
httpCon.connect();
//read the response
String result;
BufferedInputStream bis = new BufferedInputStream(httpCon.getInputStream());
ByteArrayOutputStream buf = new ByteArrayOutputStream();
int result2 = bis.read();
while(result2 != -1) {
buf.write((byte) result2);
result2 = bis.read();
}
result = buf.toString();
System.out.println(result);
I looked at the messenger documentation at https://developers.facebook.com/docs/messenger-platform/send-messages/#file to try and figure out how to send local attachments. However, when I try it out with a httpclient I get an error saying that the message body can not be empty must provide a valid attachment or message. Below is my code
string fileType = ImageExtensions.Contains(Path.GetExtension(url).ToUpper()) ? "image" : "file";
var multipartContent = new MultipartFormDataContent();
var content = new StringContent($"{{\"attachment\":{{\"type\":\"{fileType}\", \"payload\":{{\"is_reusable\"=true}}}}");
multipartContent.Add(new StringContent($"{{\"id\":\"{long.Parse(recipient)}\"}}"), "recipient");
multipartContent.Add(new StringContent($"{{\"attachment\":{{\"type\":\"{fileType}\", \"payload\":{{\"is_reusable\"=true}}}}"), "message");
var file1 = File.ReadAllBytes(url);
var file2 = new ByteArrayContent(file1);
file2.Headers.Add("Content-Type", GetMimeType(Path.GetExtension(url)));
multipartContent.Add(file2,"filedata", Path.GetFileName(url));
request.Content = multipartContent;
The file type is image and the mime type is image/jpeg. I know the url exists as I checked File.exists
Welcome to Stack Overflow!
From the code sample provided it's quite hard to work out what's going wrong as it's not runnable in isolation.
That said, I'd first verify that the image you're consuming by url exists in the format you expect. If you download the .jpeg from the url can you open it on your machine? Assuming it's well structured I'd then try and work out if it's the HttpClient that's malformed - or if there's something wrong with the values you're providing to the Facebook API.
You can do this by creating a simple C# Web API project that listens for a multipart upload on a specific route. See this answer for some sample code on how to do this.
Assuming that you're able to send the .jpeg in question between a local client and a local endpoint accepting a multipart/form-data header then the issue must be with how you're using the Facebook API itself.
In your sample I don't see you using the value of the content variable anywhere. Is this intentional?
If that missing variable is a red-herring then you could try running something along the lines of (making sure to swap the values out as necessary for the ones you're having problems with):
using (var httpClient = new HttpClient())
using (var formDataContent = new MultipartFormDataContent())
{
// Read the file in from a local path first to verify that the image
// exists in the format you're expecting.
var fileStream = File.OpenRead("/some/path/image.jpeg");
using (var streamContent = new StreamContent(fileStream))
{
// Don't actually call `.Result` you should await this, but for ease of
// demonstration.
var imageContent = new ByteArrayContent(streamContent.ReadAsByteArrayAsync().Result);
imageContent.Headers.ContentType = MediaTypeHeaderValue.Parse("multipart/form-data");
formDataContent.Add(imageContent, "image", "your-file-name-here");
formDataContent.Add(new StringContent ($"{{\"id\":\"{long.Parse("your-recipient-here")}\"}}"), "recipient");
formDataContent.Add(new StringContent($"{{\"attachment\":{{\"type\":\"{"image"}\", \"payload\":{{\"is_reusable\"=true}}}}"), "message");
// Again don't call `.Result` - await it.
var response = httpClient.PostAsync("https://some-url-here.com", formDataContent).Result;
}
}
If you run the above do you still get an empty message body error?
If you stumble upon this and you're using the FacebookClient from Nuget. This is how I finally managed to upload files to the messages api using vb.net.
Dim Client = New FacebookClient(GetPageAccessToken(PageID))
Dim TmpParams As New Dictionary(Of String, Object)
TmpParams.Add("recipient", "{""id"":""RECIPIENT_ID""}")
TmpParams.Add("message", "{""attachment"":{""type"":""image"", ""payload"":{""url"":"""", ""is_reusable"":false}}}")
TmpParams.Add("messaging_type", "RESPONSE")
Dim Med As New FacebookMediaObject()
Med.FileName = YourFile.FileName
Med.ContentType = YourFile.ContentType
Med.SetValue(YourFile.InputStream.ToBytes())
TmpParams.Add(YourFile.FileName, Med)
Client.Post("me/messages", TmpParams)
Using a Dictionary(of string,object), manually add the params for recipient,message,messaging_type and the file bytes.
I'm working on windows store app where i am using a web service which have parameter which are nested like this
userData, #"user_login",
email, #"email",password, #"password",
user_login key contains to key email and password with their value .I Hit the web service in the fiddler and if works i am getting the response the parameter string i used
{
"user_login":{"email" : "mmmmmmmm#fdhfgh.co","password" : "pass1234"}
}
when i am using this parameter string in my code i am getting error of status code 400 bad request due to the parameter string .
here is my code
string content = string.Empty;
System.Net.Http.HttpClient httpClient = new System.Net.Http.HttpClient();
httpClient.DefaultRequestHeaders.Date = DateTime.Now;
var httpContent = new System.Net.Http.StringContent("{'user_login':[{'email':"mmmmmmmm#fdhfgh.co",'password':'pass1234'}}]", Encoding.UTF8,"application/json");
var httpResponse = await httpClient.PostAsync(" http://localhost/appi/pupil/log_in", httpContent);
content = await httpResponse.Content.ReadAsStringAsync();
help me out with your valuable suggestions.
In your C# code, you're passing in an array (as denoted by the [ ]'s). It doesn't look like your were doing that in Fiddler. It also looks like the [ ]'s aren't formatted properly. I'd try just taking that out.
EDIT:
"{\"user_login\":{\"email\":\"mmmmmmmm#fdhfgh.com\",\"password\":\"pass1234\"}}"
If this is the correct signature, the above JSON would work.
EDIT 2:
var httpResponse = await httpClient.PostAsync(" http://localhost/appi/pupil/log_in", httpContent);
Couldn't help but notice that you had "localhost/appi" instead of "localhost/api". That could possibly be a typo? Along with that leading space.