Google Vision API Document Text multiple images in base64 String - google-cloud-vision

I use the Google Vision API OCR (Document Text Detection) to get the text from a scanned document (base64 String). It works perfekt for one image. But how can I send more than one image, e.g. the second page of a document.
I´ve tried to merge the base64 strings but it do not work.
var base64ImagesArrayConcarved = base64ImagesArray.join('')

Cloud Vision API has the method files.asyncBatchAnnotate.
which enables sending a bunch of files in the same request. To add individual files use async file annotation requests. An example of including two images in a batch request is the following:
{
"requests":[
{
"inputConfig": {
"gcsSource": {
"uri": "gs://<your bucket name>/image1.jpg"
},
"mimeType": "image/jpg"
},
"features": [
{
"type": "DOCUMENT_TEXT_DETECTION"
}
],
"outputConfig": {
"gcsDestination": {
"uri": "gs://<your bucket name>/output/"
}
}
},
{
"inputConfig": {
"gcsSource": {
"uri": "gs://<your bucket name>/image2.jpg"
},
"mimeType": "image/jpg"
},
"features": [
{
"type": "DOCUMENT_TEXT_DETECTION"
}
],
"outputConfig": {
"gcsDestination": {
"uri": "gs://<your bucket name>/output/"
}
}
}
]
}
If you specifically are working with pdf files, I found this post that explains how to send a request using also asyncBatchAnnotate.

Related

How to make a post request with a custom token document ref with firebase firestore Rest API

Here is my code below, I'm trying to send a post request using Firebase Firestore Rest API. It works, but it generates a random ref id token that links it to the post data (fields) I sent, which makes it difficult to relate to.
I want to be able to link my post data with a custom id token.
final String customIdToken9 = 'customIdToken9'
String url = "https://firestore.googleapis.com/v1/projects/myAppId/databases/(default)/documents/customers/$customIdToken9"
const _body = {
"fields": {
"androidNotificationToken": {
"nullValue": null
},
"fullname": {
"stringValue": "Custom"
},
"uid": {
"stringValue": "$customIdToken9"
},
"admin": {
"stringValue": ""
},
"email": {
"stringValue": "customer1#gmail.com"
},
"photo": {
"stringValue": ""
},
"coverPhoto": {
"stringValue": ""
},
"bio": {
"stringValue": ""
},
"role": {
"stringValue": "user"
},
"mobile": {
"stringValue": "092222"
}
}
}
http.post(url, body = _body);
When I run this code above it returns
{
"error": {
"code": 400,
"message": "Document parent name \"projects/MyAppId/databases/(default)/documents/customers\" lacks \"/\" at index 59.",
"status": "INVALID_ARGUMENT"
}
}
If I remove the customTokenId9, it works, but it generates a random token Id, which I don't want
String url = "https://firestore.googleapis.com/v1/projects/myAppId/databases/(default)/documents/customers/"
http.post(url, body = _body);
If you want to specify your own document name, you need to add a query paramater called documentId to your URL request. Here's how it should look like on your code:
final String customIdToken9 = 'customIdToken9'
String url = "https://firestore.googleapis.com/v1/projects/myAppId/databases/(default)/documents/customers?documentId=$customIdToken9"
const _body = {
"fields": {
"androidNotificationToken": {
"nullValue": null
},
"fullname": {
"stringValue": "Custom"
},
"uid": {
"stringValue": "$customIdToken9"
},
...
}
}
The client-assigned document ID to use for creating a document. It is optional. If not specified, a random ID will automatically be assigned by the service.
Full description is stated in this link and you'll see it in the Query Parameters section. You can also try to test out the API and expand it to see its curl equivalent.
Additionally, you can look up to this documentation to understand how a query parameter works. It applies on any REST API's offered by Firebase.
Why is your variable final String customIdToken but you are using $customIdToken9 it should be $customIdToken.

Q: Linkedin Vector Assest API, Registering Multi-Part Upload - No metadata value in response

I'm attempting to complete a multipart upload using Linkedin V2 Vector Assets and i've noticed that when registering the upload, the metadata field comes back blank in the response.
Here's the request to register the upload https://api.linkedin.com/v2/assets?action=registerUpload
{
"registerUploadRequest":{
"owner":"urn:li:organization:71736744",
"recipes":["urn:li:digitalmediaRecipe:feedshare-video"],
"serviceRelationships":[
{"identifier":"urn:li:userGeneratedContent","relationshipType":"OWNER"}
],
"supportedUploadMechanism":["MULTIPART_UPLOAD"],
"fileSize":50866165
}
and here is the response (removed all but one partUploadRequests object to make the response easier to read)
{
"value": {
"uploadMechanism": {
"com.linkedin.digitalmedia.uploading.MultipartUpload": {
"partUploadRequests": [
{
"headers": {
"Content-Type": "application/octet-stream"
},
"byteRange": { "lastByte": 4194303, "firstByte": 0 },
"url": "https://www.linkedin.com/dms-uploads/C5605AQFnYcNsf7K5Yw/uploadedVideo?sau=aHR0cHM6Ly93d3cubGlua2VkaW4uY29tL2FtYnJ5L2FtYnJ5LXZpZGVvLz94LWxpLWFtYnJ5LWVwPUFRRmp4SlBwRndkUUNnQUFBWGhjYkgwNzNuZmpacTRFM3AxUkpidTMxTlAxems3WmdoUHN1Ymp1TjVGTXVDRGFOaGczVnpHWXNpLW5OYWh2NlkxWkU5UDVIdktsQ2JxbGhhOUt1SElJSnBXTjI0TkEyWDIzM1ZiaS1aNW4yTmlXWWQyX1VlN1J2d0FEdkMwSG51ckNMY1ljMkdrczhKclFlZHRYNlZNN2dvTFJad2hpT0pxcFNZM29mXzdTTmRhZjZzQlNMS3FwaTJyWF9LYTRqTk9OcnBhTFpCam1KR3ZENEV3ZFd0VHEzNm44aEFQbDhCMmc3cVpOd3Q0Ny1TT1ZvcHRoT0dWcTB0cHAxU2VkbkY2aVNVQ3J6RVlwVHdzNDZTQlViME5HbGxITHo4a1ZNOGJxYkJjMDVCc054MDQ2ZDktZWdGb2RFa3ZKRmxsU0NRWFV2ZzdQb3VFaVNodkZtSHRYVHhLLWlkbnpKWjlQN1Q2b1ROQWJhWE5iR2g2QUdBQmQ3VVdjNkdGb01YaWFiazBhRlA4UzNpUXNlM05ISFNVdkFBdk1nSnV2a0xxWV9oYU1VTXdoeXFRT0w1a0NLM1NSd2RXTnpKSHZLMkhfY0ZqclYzcnB4VXJZckkxbUZ2QVl2Y3dUcVYyaDhWWHRpY1luNTA0am1jUjN3U0M5RVVQZEo2RFZEd1RJRmFvOTJYcmszbTFNS2pSRlFZMV94enVHZVk4SERKWTQwbDQySVRJNXlCLUp3b2V3Vjl3RGduOTZycmhoY1pLa0VOck5vdUZ4eDdodlBTNkZUVXcweXJWM3BaOUF5X2NtaHBXTVpwOVRFY0pJcGY3elFrQTF3ZFcyR3VIcEtGLUF4MldTZTdlR1pCOTdHaU5vLW9XamhkV2stR2MzNFh5UjFwckZsTF9sSFFUWU40S2pNLUI2Y2poZHFJV2xVTll6Z1lVaXdwNld2UEYwVFRObW5kQVgtTTBlX1VsaGFOQ190SDFEcG9Kem5IZExoN3IxMGk5VWE4MGpsZ3pDQzBsT3JKSkxuSEcwNm9jVzNJSzctT3NSZGhBSEFNdTBuWDNRdlhfSFoxWXpfNXgza3dyZzBPOVlmN2xIUFFiVW1lYllReUlJaGdxOEE1blpxVUxzeUpvZElLWk5WdUdlcjVuN21jTFV4TzRtNlBUczVtc3pHS0x4Z3o4b2FDdVNiWWliYzh2NkpxQktiN2RmejdnQWRFVVpfNnRLenVxUm11bGk5OGZVSVpOR3hfc3R1Mk9nVDYzYXRoQmZnRHQ0dGpnVi1BOWlaVXdtYWNLckxwVE5wNUdHZlBxZjhLaE1MZC1BVXotSVNoX19jRUlzM2laSXlpeC1pNlFpeGZyRmpxQnYwaDhwOGZpeXZ0Q2Job0xjU1g4aWNjX0lSX28xQXR0UmZB&pn=1&m=616825227&app=86804616&sync=0&v=beta&ut=1nBLJxAvwH5FI1",
"urlExpiresAt": 1616544717116
} ...
],
"metadata": ""
}
},
"asset": "urn:li:digitalmediaAsset:C5605AQFnYcNsf7K5Yw",
"mediaArtifact": "urn:li:digitalmediaMediaArtifact:(urn:li:digitalmediaAsset:C5605AQFnYcNsf7K5Yw,urn:li:digitalmediaMediaArtifactClass:uploadedVideo)"
}
}
The api documentation explains that I need to use the metadata value from the register upload response to complete the upload
I attempt making the request anyway without a value for the metadata field to https://api.linkedin.com/v2/assets?action=completeMultiPartUpload (removed all but one partUploadResponses object to make the response easier to read)
{
"completeMultipartUploadRequest": {
"mediaArtifact": "urn:li:digitalmediaMediaArtifact:(urn:li:digitalmediaAsset:C5605AQFnYcNsf7K5Yw,urn:li:digitalmediaMediaArtifactClass:uploadedVideo)",
"metadata": "",
"partUploadResponses": [
{
"headers": {
"ETag": "/ambry-video/signedId/AQGpSasdC3ezCgAAAXhcbTobXlB6_ujllr8BPUUAX4o9OgbHCxiRKoG9woM85dnGrxbUbd-5IXyMKO7syqyZXLgHFd8GQJkiMvvp1eHI9N32iJqMG-l_aFgSeXMbcqkFFcjuT22djM93dmKs_RBb58kppS3CadOPHSt5_tApCxAq0wgTfYQng3OkV_uVRdjIYftyfnHW3nF2vWz4hZBoX-YhmF6gDhXtN9dNTnU4QpHB7sGCecpjYgT8ypV-u5isvFrujHl3tl4.bin"
},
"httpStatusCode": 200
} ....
]
}
}
This comes back as a 200OK without any response body which is expected.
After that I check the upload status and which comes back with a code of SERVER_ERROR and I'm not able to create a post with the asset id of the uploaded asset.
Response from checking asset status https://api.linkedin.com/v2/assets/C5605AQFnYcNsf7K5Yw
{
"recipes": [
{
"recipe": "urn:li:digitalmediaRecipe:feedshare-video",
"status": "SERVER_ERROR"
}
],
"serviceRelationships": [
{
"relationshipType": "OWNER",
"identifier": "urn:li:userGeneratedContent"
}
],
"mediaTypeFamily": "VIDEO",
"created": 1616458317042,
"id": "C5605AQFnYcNsf7K5Yw",
"lastModified": 1616458454711,
"status": "ALLOWED"
}
Request to create a UGC post with the asset https://api.linkedin.com/v2/assets
{
"author": "urn:li:organization:71736744",
"lifecycleState": "PUBLISHED",
"specificContent": {
"com.linkedin.ugc.ShareContent": {
"media": [
{
"media": "urn:li:digitalmediaAsset:C5605AQFnYcNsf7K5Yw",
"status": "READY",
"title": {
"attributes": [],
"text": "Sample Video Create"
}
}
],
"shareCommentary": {
"attributes": [],
"text": "Some share text"
},
"shareMediaCategory": "VIDEO"
}
},
"visibility": {
"com.linkedin.ugc.MemberNetworkVisibility": "PUBLIC"
}
Response to the request
{
"serviceErrorCode": 0,
"message": "Resource assets does not exist",
"status": 404}
The only thing I can think of is since I don't have a metadata value when completing the upload I'm not able to use the video asset in UGC posts. Anyone encountered a problem similar to this?
Further Investigations
On further investigation the example from the API docs doesn't return a metadata field either. So this is what I think might be happening
I'm not uploading the file chunks correctly and the metadata field isn't required for completing the upload.
The API has a bug in it which prevents it from returning the metadata field when registering a multipart upload.
Figured it out, when using the slice method to break your file up into chunks it needs to be file.slice(firstByte, lastByte + 1)
It also seems that the metadata value from the register upload request isn't need to complete the upload.

The LinkedIn Assets API don't show my upload in the linkedin newfeed

I'm using LinkedIn API to upload media to my Linkedin personal profile. I start with registring my image and I get a successful response.
REQUEST
{
"registerUploadRequest":{
"owner":"urn:li:person:xxx",
"recipes":[
"urn:li:digitalmediaRecipe:feedshare-image"
],
"serviceRelationships":[
{
"identifier":"urn:li:userGeneratedContent",
"relationshipType":"OWNER"
}
],
"supportedUploadMechanism":[
"SYNCHRONOUS_UPLOAD"
]
}
}
RESPONSE
{
"value": {
"uploadMechanism": {
"com.linkedin.digitalmedia.uploading.MediaUploadHttpRequest": {
"headers": {
"media-type-family": "STILLIMAGE"
},
"uploadUrl": "xxxx"
}
},
"mediaArtifact": "urn:li:digitalmediaMediaArtifact:(urn:li:digitalmediaAsset:xxx,urn:li:digitalmediaMediaArtifactClass:feedshare-uploadedImage)",
"asset": "urn:li:digitalmediaAsset:xxx"
}
}
Next step I uploaded my image using curl with a valid access token and the uploadUrl
I get a 201 HTTP response but I see nothing in my LinkedIn profile.
also when I check the status of my upload it shows me a success message.
{"recipes":[{"recipe":"urn:li:digitalmediaRecipe:feedshare-image","status":"AVAILABLE"}],"serviceRelationships":[{"relationshipType":"OWNER","identifier":"urn:li:userGeneratedContent"}],"mediaTypeFamily":"STILLIMAGE","created":1606729082880,"id":"C4D22AQE6h5xe3HYYiQ","lastModified":1606729322981,"status":"ALLOWED"}
So why I can't see my upload in the Linkedin timeline, please? I tried with both image and video but nothing is shown in my newsfeed.
Also, I checked my access token and it contains necessary permission: r_liteprofile, w_member_social
Uploading an asset does not make it available on your profile.
Assets API only uploads the image/video and stores it on LinkedIn platform. You can however use this asset to create a UGC Post to see it on your personal/company profile.
To do that, you'll have to use the ugcPosts API. ie call POST https://api.linkedin.com/v2/ugcPosts with
"media": "urn:li:digitalmediaAsset:XXX", from the Assets API response in the payload.
Example:
{
"author": "urn:li:organization:5590506",
"lifecycleState": "PUBLISHED",
"specificContent": {
"com.linkedin.ugc.ShareContent": {
"media": [
{
"media": "urn:li:digitalmediaAsset:XXX", // from the Assets API response
"status": "READY",
"title": {
"attributes": [],
"text": "Sample Video Create"
}
}
],
"shareCommentary": {
"attributes": [],
"text": "Some share text"
},
"shareMediaCategory": "VIDEO"
}
},
"targetAudience": {
"targetedEntities": [
{
"locations": [
"urn:li:country:us",
"urn:li:country:gb"
],
"seniorities": [
"urn:li:seniority:3"
]
}
]
},
"visibility": {
"com.linkedin.ugc.MemberNetworkVisibility": "PUBLIC"
}
}
Reference: https://learn.microsoft.com/en-us/linkedin/marketing/integrations/community-management/shares/ugc-post-api#sample-request

How should a "write" request be structured for Firestore REST API (v1beta1)?

Based on the Google Discovery document, and RPC reference, it appears that the :write resource should be available for Firestore database interactions, but performing such a request to my (POST https://firestore.googleapis.com/v1beta1/projects/[my project]/databases/(default)/documents:write) results in:
[
{
"error": {
"code": 400,
"message": "Invalid value (Object), ",
"status": "INVALID_ARGUMENT",
"details": [
{
"#type": "type.googleapis.com/google.rpc.BadRequest",
"fieldViolations": [
{
"description": "Invalid value (Object), "
}
]
}
]
}
}
]
Is this possible? A related SO answer alludes to this being available as a means of field transforms, the same reason I require this, but I cannot construct valid a JSON body to succeed in the request. Currently, variations on the following don't work as expected when trying a minimum successful response:
{
"writes": [
{
"update": {
"name": "projects/{projectId}/databases/[my project]/documents/exampleId",
"fields": {
"example": {
"integerValue": 100
},
"timestamp": {
"nullValue": null
}
},
"transform": {
"document": "projects/[my project]]/databases/(default)/documents/examples/exampleId",
"fieldTransforms": [
{
"fieldPath": "timestamp",
"setToServerValue": "REQUEST_TIME"
}
]
}
}
}
]
}
First of all, note that you should use the v1 version of the REST API, not the betas.
To create a document, you would use the createDocument method, while to update a document you would use the patch one.
For the document creation you should therefore make a POST HTTP Request to the following URL
https://firestore.googleapis.com/v1/projects/<your-project-id>/databases/(default)/documents/<the-desired-collection>
with the following Request body:
{
fields: {
example: {
integerValue: 100
}
}
}
You need to use documents:commit instead of documents:write
also the name field should be in this format:
"name": "projects/projectID/databases/(default)/documents/collectionName/DocumentId"
See this post.

Cloud Firestore REST API - Add server timestamp

I'm using an Arduino with an ESP8266-01 module to upload a value to a Cloud Firestore database using the createDocument API with the following payload:
{
"fields": {
"distance": {
"integerValue": "555"
}
}
}
I do a POST-request to a route like this:
https://firestore.googleapis.com/v1beta1/projects/<MY_PROJECT>/databases/(default)/documents/<SOME_COLLECTION>?key=MY_VERY_SECRET_KEY
That all works, but I would like to add the server timestamp as well. I've found a few answers here on stackoverflow, but I have not been able to make any of them work.
How can I add the server timestamp to the created document? What I want is for the following to be created:
{
"fields": {
"distance": {
"integerValue": "555"
},
"timestamp" : {
"DATETIME": SERVER_TIMESTAMP
}
}
}
Any help appreciated.
What I ended up doing in the end was the following:
A POST request to a route like this:
https://firestore.googleapis.com/v1beta1/projects/<MY_PROJECT>/databases/(default)/documents:commit?&key=<MY_VERY_SECRET_KEY>
With the following payload:
{
"writes": [
{
"update": {
"name": "projects/<MY_PROJECT>/databases/(default)/documents/<COLLECTION_ID>/<DOCUMENT_ID>",
"fields": {
"distance": {
"integerValue": "555"
}
}
}
},
{
"transform": {
"document": "projects/<MY_PROJECT>/databases/(default)/documents/<COLLECTION_ID>/<DOCUMENT_ID>",
"fieldTransforms": [
{
"fieldPath": "servertime",
"setToServerValue": "REQUEST_TIME"
}
]
}
}
]
}
Where I generate a new DOCUMENT_ID (e.g. a GUID) instead of having cloud firestore generate one for me.

Resources