Unable to get dominant colour of image using Microsoft's Computer Vision - javascript

I've been stuck on this problem for a while.
I'm trying to get the dominant colour of an image using Microsoft's Computer Vision service.
An extract of my code is below:
import {VisualFeatureTypes} from "#azure/cognitiveservices-computervision/esm/models";
...
let visualFeatures: VisualFeatureTypes[] = ['Color'];
const caption = (await computerVisionClient.analyzeImageInStream(describeURL, visualFeatures));
Doing a console.log(caption) returns the following JSON object:
{
"categories": [
{
"name": "others_",
"score": 0.15625
}
],
"requestId": "5a24115f-8095-4a77-8aa9-2d719dce99e6",
"metadata": {
"width": 500,
"height": 500,
"format": "Jpeg"
}
}
The Computer Vision service definitely works, because if I change the method from analyzeImageInStream to describeImageInStream and remove, then I get the appropriate response.
For testing, I've been using this image here, and using Computer Vision's Demo. The demo returns colour information, but my API call does not.
Any help would be greatly appreciated.

Based on this doc, you should put the params in your url. https://learn.microsoft.com/en-us/azure/cognitive-services/computer-vision/quickstarts/javascript-analyze
const urlBase = "https://....cognitiveservices.azure.com/vision/v3.0/analyze";
var params = {
"visualFeatures": "Categories,Description,Color",
"details": "",
"language": "en",
};
$.ajax({
url: uriBase + "?" + $.param(params),
// Request headers.
beforeSend: function(xhrObj){
xhrObj.setRequestHeader("Content-Type","application/json");
xhrObj.setRequestHeader(
"Ocp-Apim-Subscription-Key", subscriptionKey);
},
type: "POST",
// Request body.
data: '{"url": ' + '"' + sourceImageUrl + '"}',
}) .done(function(data) {
// Show formatted JSON on webpage.
callYourFunction(data);
})

Related

Upload to vimeo with tus-js-client

I’m new to tus and I’m using tus-js-client. I’m following the example in this link https://github.com/tus/tus-js-client/blob/master/docs/usage.md#example-upload-to-vimeo.
I was able to successfully upload a video on Vimeo but I would like to set the title/name and description in advance. And also the optional onSuccess function is not returning anything. I would like to get the video details that I’ve uploaded successfully like the clipid.
Are these things something possible to do on tus-js-client? Below is my code for reference.
function UploadVideoTusJs(uploadUrl, videoFile) {
var upload = new tus.Upload(videoFile.files[0], {
uploadUrl: uploadUrl,
metadata: {
name: videoFile.files[0].name, // not working
description: "Test", // not working
},
onError: function (error) {
console.log("Failed because: " + error);
},
onProgress: function (bytesUploaded, bytesTotal) {
var percentage = (bytesUploaded / bytesTotal * 100).toFixed(2)
console.log(bytesUploaded, bytesTotal, percentage + "%")
},
onSuccess: function (data) {
console.log(data); //returns undefined
console.log("Download %s from %s", upload.file.name, upload.url);
},
onAfterResponse: function (req, res) {
var url = req.getURL()
var value = res.getHeader("X-My-Header")
console.log(`Request for ${url} responded with ${value}`)
}
});
// Start the upload by default
upload.start();
}
-- Dan
Vimeo's implementation of tus is a bit different as the "creation" step is done using the Vimeo API, not using tus. If you want to provide metadata like name or description, that should be provided with the initial API request, which should look something like this:
var settings = {
"url": "https://api.vimeo.com/me/videos",
"method": "POST",
"timeout": 0,
"headers": {
"Accept": "application/vnd.vimeo.*+json;version=3.4",
"Content-Type": "application/json",
"Authorization": "Bearer TOKEN"
},
"data": JSON.stringify({"upload":{"approach":"tus","size":666666666},"name":"name","description":"description"}),
};
$.ajax(settings).done(function (response) {
console.log(response);
});
Hope this points you in the right direction!

POST Request to cycle through 8 different urls

I have been working on a project for quite some time now.
I have found this post somewhat useful, but am unsure if it is correct or not for my utilization.
Functionality:
Read in SharePoint list items from 8 different subsites with a GET request.
Populate those items in an orderly(grouped) fashion in a DataTable on a single landing page.
DataTable has collapsible/expandable rows grouped by program, followed by deliverable.
Dropdown menu with buttons to print/excel/PDF/Update the table.
Update Table has a HTML form that sends data back to the SharePoint List correlated with the FORM input.
I am currently using 8 different subsites where all of the lists are located. I want to send the new item to the correct list based off of its "Program" value because each of the different lists are a different program. I know I would have to use an if/else statement, but how would I go about that with an AJAX call?
Here is my JS "POST" Code:
$("#btn").click(function(e) {
PostItem();
});
});
function PostItem() {
return getFormDigest("https://baseurl.sharepoint.com/sites/Projects/USMC/AMMO/Lists/AMMODeliverables/").then(function(digestData) {
console.log(digestData.d.GetContextWebInformation.FormDigestValue);
var item = {
"__metadata": { "type": "SP.Data.AMMODeliverablesListItem" },
"Title": "updated title",
"Program": $("#dProgram").val(),
"Deliverable": $("#dDeliverable").val(),
"To": $("#dTo").val(),
"Date": $("#dDate").val(),
"Approved": $("#dApproved").val(),
"Notes": $("#dNotes").val()
};
$.ajax({
async: true, // Async by default is set to “true” load the script asynchronously
// URL to post data into sharepoint list or your own url
url: "https://baseurl.sharepoint.com/sites/Projects/USMC/AMMO/_api/web/lists/getbytitle('AMMO Deliverables')/items",
method: "POST", //Specifies the operation to create the list item
data: JSON.stringify(item),
headers: {
"content-type": "application/json;odata=verbose",
"X-RequestDigest": digestData.d.GetContextWebInformation.FormDigestValue,
"Accept": "application/json;odata=verbose",
"If-Match": "*"
},
success: function(data) {
alert('Success'); // Used sweet alert for success message
console.log(data + " success in updating item");
},
error: function(data) {
alert(JSON.stringify(item));
console.log(data);
}
});
})
}
function getItemTypeForListName(listName) {
var itemType = "SP.Data." + listName.charAt(0).toUpperCase() + listName.slice(1) + "ListName";
var encItemType = itemType.replace(/\s/g,'_x0020_');
return(encItemType);
}
function getFormDigest(baseurl) {
return $.ajax({
url: "https://baseurl.sharepoint.com/sites/Projects/USMC/AMMO/_api/contextInfo",
method: 'POST',
headers: {
'Accept': 'application/json; odata=verbose'
}
});
}
UPDATE:
I feel like I am somewhat in the right direction, but it doesn't work:
function PostItem() {
return getFormDigest("https://siteurl.sharepoint.com/sites/Projects/USMC/AMMO/Lists/AMMODeliverables/").then(function(digestData) {
console.log(digestData.d.GetContextWebInformation.FormDigestValue);
var item = {
"__metadata": { "type": "SP.Data.AMMODeliverablesListItem" },
"Title": "updated title",
"Program": $("#dProgram").val(),
"Deliverable": $("#dDeliverable").val(),
"To": $("#dTo").val(),
"Date": $("#dDate").val(),
"Approved": $("#dApproved").val(),
"Notes": $("#dNotes").val()
};
if (dProgram == "AMMO"){
$.ajax({
async: true, // Async by default is set to “true” load the script asynchronously
// URL to post data into sharepoint list or your own url
url: "https://siteurl.sharepoint.com/sites/Projects/USMC/AMMO/_api/web/lists/getbytitle('AMMO Deliverables')/items",
method: "POST", //Specifies the operation to create the list item
data: JSON.stringify(item),
headers: {
"content-type": "application/json;odata=verbose",
"X-RequestDigest": digestData.d.GetContextWebInformation.FormDigestValue,
"Accept": "application/json;odata=verbose",
"If-Match": "*"
},
success: function(data) {
alert('Success'); // Used sweet alert for success message
console.log(data + " success in updating item");
},
error: function(data) {
alert(JSON.stringify(item));
console.log(data);
}
});
}
else if (dProgram == "AHR"){
First of all, your getFormDigest function is not quite right:
function getFormDigest(baseurl) {
// you pass in a "baseurl" value above, but you're not really doing anything with it.
// the URL you use below is hardcoded to always
// make the request to the /sites/Projects/USMC/AMMO site
return $.ajax({
url: "https://baseurl.sharepoint.com/sites/Projects/USMC/AMMO/_api/contextInfo",
method: 'POST',
headers: {
'Accept': 'application/json; odata=verbose'
}
});
}
What you need to do is change that so you can pass a site URL into it and get a valid form digest from the actual site you are trying to post a new item to:
function getFormDigest(siteUrl) {
return $.ajax({
url: siteUrl + "/_api/contextInfo",
method: 'POST',
headers: {
'Accept': 'application/json; odata=verbose'
}
});
}
Next, you need to change your PostItem function to react to the current value of the selected Program, and choose some correct values based on that. I see in the comments you have posted a little snippet where you are creating a map that will spit out the correct URL based on the key of the selected Program. That works if all you need is a single value, however, since you said that the list names are all different on each subsite, you actually need three different values to be generated dynamically based on the selected Program:
The URL to the site itself so you can get a valid form digest,
The list name, so you can get the correct List Item Entity Type value for your new item's JSON __metadata property. You have a function to do this, but you aren't using it. Also, you'll need the list name for:
A URL that includes the site and the list name so you can post the new list item (since the URL to do that is essentially [URL to site]/_api/web/lists/getbytitle('[list name]')/items)
You could do a sequence of if..then..else if..then..else if..then..else statements, but for more than two or three possible values, that gets cumbersome. A much cleaner way of doing it is using a switch statement. So here's what your PostItem function might look like if you used a switch to evaluate what the selected Program value is and then dynamically set the site URL and list name based on that:
function PostItem() {
// the base URL should be what is the same across all subsites. in comments
// you said the subsites start to differ after /sites/Projects.
var baseUrl = "https://your-tenant.sharepoint.com/sites/Projects";
// get the selected program from your form
var programName = $("#dProgram").val();
var siteUrl = null; // set this as empty for now
var listName = null; // set this as empty for now
// a "switch" statement is like a fancy "if" statement that is
// useful if you have more than just two or three options
switch (programName) {
case "AMMO":
// set the site url to be whatever it is after /sites/Projects.
// in the case of AMMO, you have already posted that the "AMMO"
// subsite is under a "USMC" subsite that is under "Projects"
siteUrl = baseUrl + "/USMC/AMMO";
listName = "AMMODeliverables";
break;
case "AHR":
// set the site url to be whatever it is after /sites/Projects.
// IF in this case the "AHR" subsite is directly under /Projects
// and NOT under another subsite (as is the case with /USMC/AMMO),
// you just add that directly:
siteUrl = baseUrl + "/AHR";
// HOWEVER, if it is under another subsite with a different name, similar
// to how "AMMO" is actually under another subsite called "USMC", then you
// would include that "Other" subsite here:
siteUrl = baseurl + "/Other/AHR";
// set the list name, since you said the list names
// are different in each of the subsites
listName = "AHR Deliverables";
break;
case "FOO":
// pretending that "FOO" is _directly_ under /sites/Projects
siteUrl = baseurl + "/FOO";
listName = "FOO Thingys";
break;
case "BAR":
// pretending that "BAR" is NOT directly under /sites/Projects,
// but is in fact under another "Different" subsite
siteUrl = baseurl + "/Different/BAR";
listName = "BAR Whatchamacallits";
default:
// all switch statements need a default option in case
// what we are checking does not match any any of the options
// we are expecting. in this instance, we will _not_ set
// a site URL or list name so that we do not try to post
// to s non-existent site or list
break;
}
// if we didn't get one of our expected choices for programName, then siteUrl
// will not have been populated in the switch, so we can check and make sure we
// actually have a valid siteUrl before we start sending AJAX requests out
if (siteUrl) {
// pass the siteUrl into your improved getFormDigest function so
// that you get the correct form digest from the site you are
// actually trying to post a new item to.
// also, you don't actuall need the "return" here.
getFormDigest(siteUrl).then(function(digestData) {
console.log(digestData.d.GetContextWebInformation.FormDigestValue);
// use your getItemTypeForListName function to get the
// correct SharePoint List Item Entity Type name based on
// the list name
var listItemEntityType = getItemTypeForListName(listName);
// construct the URL to post the new list item to based on the siteUrl
// and the listName, which vary based on the selected projecName
var postNewItemUrl = siteUrl + "/_api/web/lists/getbytitle('" + listName + "')/items";
// construct your new item JSON. you said all the fields
// in all the lists are the same, so the only thing that really
// needs to dynamically chage here is the entity type name,
// which was generated based on the list name
var item = {
"__metadata": { "type": listItemEntityType },
"Title": "updated title",
"Program": programName,
"Deliverable": $("#dDeliverable").val(),
"To": $("#dTo").val(),
"Date": $("#dDate").val(),
"Approved": $("#dApproved").val(),
"Notes": $("#dNotes").val()
};
$.ajax({
// use your dynamically generated URL here
url: postNewItemUrl,
method: "POST", //Specifies the operation to create the list item
data: JSON.stringify(item),
headers: {
"content-type": "application/json;odata=verbose",
"X-RequestDigest": digestData.d.GetContextWebInformation.FormDigestValue,
"Accept": "application/json;odata=verbose",
"If-Match": "*"
},
success: function(data) {
alert('Success'); // Used sweet alert for success message
console.log(data + " success in updating item");
},
error: function(data) {
alert(JSON.stringify(item));
console.log(data);
}
});
});
}
}

POST Ajax call to Outlook API - Access is denied

I'm having a hard time sending a POST request to the Outlook API.
I'm working on my local machine and defined the redirectUrl to my localhost:port
My GET requests works:
var apiUrl = "https://outlook.office.com/api/v2.0/me/calendarview?startdatetime=" + startDateTime + "&enddatetime=" + endDateTime + "&$top=" + 10;
$.ajax({
type: 'GET',
url: apiUrl,
headers: {
"Authorization": "Bearer " + token
}
}).done(function (data) {
processResults(data);
}).fail(function (response) {
handleFailure();
});
but when I try to send a POST, I get this message :
Access is denied. Check credentials and try again.
and my code is:
var apiUrl = "https://outlook.office.com/api/v2.0/me/events";
var postData = {
"Subject": "Plan summer company picnic",
"Body": {
"ContentType": "HTML",
"Content": "Let's kick-start this event planning!"
},
"Start": {
"DateTime": "2019-01-15T11:00:00",
"TimeZone": "Pacific Standard Time"
},
"End": {
"DateTime": "2019-01-15T12:00:00",
"TimeZone": "Pacific Standard Time"
},
"Attendees": [
{
"EmailAddress": {
"Address": "myMail#gmail.com",
"Name": "Name Here"
},
"Type": "Required"
}
]
};
$.ajax({
type: 'POST',
url: apiUrl,
headers: {
"Authorization": "Bearer " + token
},
contentType: 'application/json',
data: JSON.stringify(postData)
}).done(function (data) {
processResults(data);
}).fail(function (response) {
handleFailure();
});
In both cases I use the same token, so it's probably not a login problem. I also allowed Calendars.ReadWrite in the app.
UPDATE
I cleared the cache, logged in, made a GET call, then made a POST call, then made a GET call again. Both GET calls works, so the problem is not the token or a cache problem.
The problem was on the authentication process, apparently on each request I have to specify the scope and it should include multiple permissions.
In the headers I found this:
x-ms-diagnostics: 2000008;reason="Access to this API requires the following permissions: 'Calendars.Read.All,Calendars.Read.Shared,Calendars.ReadWrite.All,Calendars.ReadWrite.Shared'. However, the application only has the following permissions granted: 'Calendars.Read,Calendars.ReadWrite'.";error_category="invalid_grant"
Even this is wrong, since Calendars.Read.All and Calendars.ReadWrite.All doesn't exist, it should be Calendars.Read and Calendars.ReadWrite.
The authentication request should look like this:
var authUrl = authServer +
"response_type=" + encodeURI(token) +
"&client_id=" + encodeURI(clientId) +
"&scope=" + encodeURI("https://outlook.office.com/Calendars.Read https://outlook.office.com/Calendars.Read.Shared https://outlook.office.com/Calendars.ReadWrite https://outlook.office.com/Calendars.ReadWrite.Shared") +
"&redirect_uri=" + redirectUrl +
"&state=" + stateParam;

Wikipedia API extract returning Edit Link in Text

I am attempting to pull the json from the wikipedia API. When I extract the main content it shows up on my page but the edit links show up next to the <h2> header. I've included the param "disableeditsection": false, as both true and false but to no avail. According to these docs: docs
Any ideas on how to remove the 'edit' text from the extract?
Thank you in advance for your help
$(document).ready(function ($) {
console.log('ready1!');
var wikiSearch = "Blue Spring State Park";
var queryURL = "https://en.wikipedia.org/w/api.php";
var params = {
"disableeditsection": false,
"action": "query",
"format": "json",
"prop": "links|images|extlinks|imageinfo|info|url|extracts|text",
"iiprop": "timestamp|user|url|comment",
"meta": "url",
"origin": "*",
"iwurl": 1,
"titles": wikiSearch,
"redirects": 1,
"inprop": "url"
};
queryURL += "?" + $.param(params);
$.ajax({
url: queryURL,
method: "GET"
}).done(function (response) {
console.log('ready2!');
console.log('response', response);
var objResult = response
console.log(objResult);
$.each(response.query.pages, function (c) {
var hey = response.query.pages[c].extract;
$("#wikipediaImages").html(hey);
}); //End .each
}); //End .done
}); //End Document.ready
It seems that you use the output from extract. This generally doesn't include edit links. But there seems to be a bug on some pages. disableeditsection doesn't apply on prop=extracts.
If you want the html as it is, without edit on section links, then use action parse: https://en.wikipedia.org/w/api.php?action=parse&format=json&page=Blue%20Spring%20State%20Park&disableeditsection=1
In general your question is unclear what exactly do want to display.

Posting multiple Photos to one post

I have been trying to create an application which needs multiple photos to be attached to one post. These are the following attempts i tried,
First i used facebook-node-sdk which JS SDK to achieve different functionality, but Official Js Sdk does't have option for file to upload, when then i moved to attaching/inserting photo itself to HTTP POST with the help of form-data, with the following code-
var form = new FormData();
form.append('file', fs.createReadStream(picPaths[0]));
form.append('message', "Hello"); //Put message
var ACCESS_TOKEN = "ACCESS_TOKEN";
var options = {
method: 'post',
host: 'graph.facebook.com',
path: '{Object-ID}/photos' + '?access_token=' + ACCESS_TOKEN,
headers: form.getHeaders(),
}
var request = https.request(options, function(res) {
console.log(res, false, null);
});
form.pipe(request);
request.on('error', function(error) {
console.log(error);
});
This works with one photo.
But as you can see in this github.com/Thuzi/facebook-node-sdk/issues/113 which i started, it is not possible to attach more than one photo.
So as mentioned by dantman i stated looking in batch process, which can be found developers.facebook.com/docs/graph-api/making-multiple-requests titled under Uploading binary data. The one thing that hits and give me hope is this one statement.
The attached_files property can take a comma separated list of attachment names in its value.
Note That (batching with photos) also is not possible with this library or JS SDK (Please correct me if i am wrong)
You can do post images with curl like this,
curl -F 'access_token=ACCESS_TOKEN' -F 'batch=[{"method":"POST","relative_url":"{Object-Id}/photos","body":"message=Test Post","attached_files":"file1"}]' -F 'file1=#image1' -F 'file2=#image2' https://graph.facebook.com
The above code posts with one image
So my question is this, it possible to attach multiple images/binary_files to the post with the help of curl, something like ..."attached_files":"file1,file2"... as suggested by docs, please help me with this problem and if you have already done this can you please post the snapshot of your code.
Thanks, Ravi
I finally figured out how.
So first, read the section here titled "Publishing a multi-photo post with uploaded photos": https://developers.facebook.com/docs/graph-api/reference/page/photos/#Creating
What it says is basically correct, however, it is not in JavaScript. Also, they don't emphasize enough an important step: You have to set "published" to "false" for the image you upload, for it to then be attachable to the post that gets created.
So anyway, here is the working code -- in JavaScript, and with "published" correctly set to false:
async function PostImageToFacebook(token, filename, mimeType, imageDataBlob, message) {
var fd = new FormData();
fd.append("access_token", token);
fd.append("source", imageDataBlob);
//fd.append("message", "photo message for " + filename);
fd.append("no_story", "true");
//fd.append("privacy", "SELF");
fd.append("published", "false");
// Upload image to facebook without story(post to feed)
let uploadPhotoResponse = await $.ajax({
url: "https://graph.facebook.com/me/photos?access_token=" + token,
type: "POST",
data: fd,
processData: false,
contentType: false,
cache: false
});
console.log(`Uploaded photo "${filename}": `, uploadPhotoResponse);
let uploadPhotoResponse2 = await $.ajax({
url: "https://graph.facebook.com/me/photos?access_token=" + token,
type: "POST",
data: fd,
processData: false,
contentType: false,
cache: false
});
console.log(`Uploaded photo "${filename}": `, uploadPhotoResponse2);
let makePostResponse = await $.ajax({
"async": true,
"crossDomain": true,
"url": "https://graph.facebook.com/v2.11/me/feed",
"method": "POST",
"headers": {
"cache-control": "no-cache",
"content-type": "application/x-www-form-urlencoded"
},
"data": {
"message": "Testing multi-photo post2!",
"attached_media[0]": `{"media_fbid":${uploadPhotoResponse.id}}`,
"attached_media[1]": `{"media_fbid":${uploadPhotoResponse2.id}}`,
"access_token": token
}
});
console.log(`Made post: `, makePostResponse);
}
The code above currently just uploads the same image twice, then attaches both to the new post. Obviously, in real world usage you would replace the data in the second photo-upload with a different image.
Anyway, to use the function, just call it like so:
function dataURItoBlob(dataURI) {
var byteString = atob(dataURI.split(",")[1]);
var ab = new ArrayBuffer(byteString.length);
var ia = new Uint8Array(ab);
for (var i = 0; i < byteString.length; i++) {
ia[i] = byteString.charCodeAt(i);
}
return new Blob([ab], {type: "image/png"});
}
let imageDataURI = GetImageDataURIFromSomewhere();
let imageBlob = dataURItoBlob(imageDataURI);
PostImageToFacebook(fbToken, "some_filename", "image/png", imageBlob, window.location.href);
this is possible.
Note: This one is not an efficient way to do this but just for explaining purpose i am doing here,
The first hint that i got that it may be possible is from this post
Steps that i used:
Follow the doc to create custom open graph stories
Let's suppose you four image to attach (pic[1, 2, 3, 4])
First i staged them with the help of new facebook-node-sdk v1.1.0-alpha1 with the code something like this (with batch process).
FB.api( "", "post", {
batch: [
{
method: "POST",
relative_url: "me/staging_resources",
attached_files: "file1",
type:"image/png"
}, {
method: "POST",
relative_url: "me/staging_resources",
attached_files: "file2",
type:"image/png"
}, {
method: "POST",
relative_url: "me/staging_resources",
attached_files: "file3",
type:"image/png"
}, {
method: "POST",
relative_url: "me/staging_resources",
attached_files: "file4",
type:"image/png"
}],
file1: fs.createReadStream(picPaths[0]),
file2: fs.createReadStream(picPaths[1]),
file3: fs.createReadStream(picPaths[2]),
file4: fs.createReadStream(picPaths[3])
},
function(response) {
console.log(response);
});
Now from the response part get the url and dis the post with the same library. With the code something like this.
FB.api(
"me/objects/{app-namespace}:{custom-object}",
"post", {
"object": {
"og:title": "Sample Post",
"og:image[0]": {
"url": "fbstaging:{...}",
"user_generated": true
},
"og:image[1]": {
"url": "fbstaging:{...}",
"user_generated": true
},
"og:image[2]": {
"url": "fbstaging:{...}",
"user_generated": true
},
"og:image[3]": {
"url": "fbstaging:{...}",
"user_generated": true
}
}
},
function(response) {
console.log(response);
}
);
Now, with these two piece of code you will be able to push multiple images/photo to the single post.
Note: this can make more sense or can be done with the help of named batch process which is being described here.
Thanks,
Ravi

Categories

Resources