How to upload a batch of images to Azure Custom Vision using JavaScript - microsoft-cognitive

I want to upload a batch of 64 images to Custom Vision using the JavaScript SDK.
const files: ImageFileCreateEntry[] = []
while (i < 64) {
const data = fs.readFileSync(`${sampleDataRoot}/${tag.name}/${file}`)
const fileEntry: ImageFileCreateEntry = { name: file, contents: data }
files.push(fileEntry);
i++
}
const batch: ImageFileCreateBatch = { images: files, tagIds: [tag.id] }
fileUploadPromises.push(client.createImagesFromFiles(projectId, batch))
But I'm getting the following error:
RestError: No valid image files
at new RestError (/home/pomatti/projects/personal/azure-customvision-benchmark/node_modules/#azure/ms-rest-js/lib/restError.ts:18:5)
at /home/pomatti/projects/personal/azure-customvision-benchmark/node_modules/#azure/ms-rest-js/lib/policies/deserializationPolicy.ts:117:27
at processTicksAndRejections (internal/process/task_queues.js:97:5)
at async Promise.all (index 5) {
code: 'BadRequestImageBatch',
statusCode: 400,
request: WebResource {
streamResponseBody: false,
url: 'https://eastus.api.cognitive.microsoft.com/customvision/v3.3/training/projects/ff4967f9-f772-4473-89a5-41356c471454/images/files',
method: 'POST',
headers: HttpHeaders { _headersMap: [Object] },
body: '{"images":[],"tagIds":["8a2e95b5-2050-403d-95e7-45b08e358d7d"]}',
query: undefined,
formData: undefined,
withCredentials: false,
abortSignal: undefined,
timeout: 0,
onUploadProgress: undefined,
onDownloadProgress: undefined,
proxySettings: undefined,
keepAlive: undefined,
operationSpec: {
httpMethod: 'POST',
path: 'projects/{projectId}/images/files',
urlParameters: [Array],
requestBody: [Object],
responses: [Object],
serializer: [Serializer]
}
},
response: {
body: '{"code":"BadRequestImageBatch","message":"No valid image files"}',
headers: HttpHeaders { _headersMap: [Object] },
status: 400
},
body: { code: 'BadRequestImageBatch', message: 'No valid image files' }
}

I figured out that my implementation was completely messed up.
This is how I solved it for now:
const client = getTrainingClient();
const tags = await client.getTags(projectId);
let fileUploadPromises = [];
tags.forEach(tag => {
const imageFiles = fs.readdirSync(`${sampleDataRoot}/${tag.name}`);
const files: ImageFileCreateEntry[] = []
const chunk = imageFiles.slice(0, 64)
chunk.forEach(file => {
const data = fs.readFileSync(`${sampleDataRoot}/${tag.name}/${file}`)
const fileEntry: ImageFileCreateEntry = { name: file, contents: data }
files.push(fileEntry);
})
const batch: ImageFileCreateBatch = { images: files, tagIds: [tag.id] }
fileUploadPromises.push(client.createImagesFromFiles(projectId, batch))
})

Related

How to upload a file with NextJS and formidable?

I am trying to utilize formidable to access a file and eventually post it to a file storage system by following this post: Create upload files api in next.js. I am logging the data, but am getting confused about the output. When I try and access data.files.resume.filepath I get undefined.
The data looks like:
{ fields: {}, files: { resume: [ [PersistentFile] ] } }
And when I log data.files.resume I get this which shows the filepath:
[
PersistentFile {
_events: [Object: null prototype] { error: [Function (anonymous)] },
_eventsCount: 1,
_maxListeners: undefined,
lastModifiedDate: 2023-02-09T01:59:50.924Z,
filepath: 'C:\\Users\\Me\\AppData\\Local\\Temp\\21eef37a9191459ae49bb110f',
newFilename: '21eef37a9191459ae49bb110f',
originalFilename: 'thankyou.pdf',
mimetype: 'application/pdf',
hashAlgorithm: false,
size: 57285,
_writeStream: WriteStream {
fd: null,
path: 'C:\\Users\\Me\\AppData\\Local\\Temp\\21eef37a9191459ae49bb110f',
flags: 'w',
mode: 438,
start: undefined,
pos: undefined,
bytesWritten: 57285,
closed: false,
_writableState: [WritableState],
_events: [Object: null prototype],
_eventsCount: 1,
_maxListeners: undefined,
[Symbol(kFs)]: [Object],
[Symbol(kIsPerformingIO)]: false,
[Symbol(kCapture)]: false
},
hash: null,
[Symbol(kCapture)]: false
}
]
and when I log the data.files.resume.filepath I get undefined
Front End Form Submit:
const formData = new FormData();
formData.append("resume", resume);
const response = await fetch("/api/apply", {
method: "POST",
body: formData,
});
NextJS API:
import type { NextApiRequest, NextApiResponse } from "next";
import { IncomingForm } from "formidable";
export const config = {
api: {
bodyParser: false,
},
};
export default async function handler(
req: NextApiRequest,
res: NextApiResponse
) {
if (req.method !== "POST") {
return;
}
// parse form with a Promise wrapper
const data = await new Promise((resolve, reject) => {
const form = new IncomingForm();
form.parse(req, (err, fields, files) => {
if (err) return reject(err);
resolve({ fields, files });
});
});
console.log("------");
console.log(data);
console.log("------");
console.log(data.files.resume);
console.log("------");
console.log(data.files.resume.filepath); // this logs undefined
res.status(200).json(data);
}
I followed this StackOverflow article: Create upload files api in next.js and have tried logging each step, but still get undefined for the filepath. Any help or guidance is greatly appreciated!

Error fetching data with Axios in NextJS and Strapi

Thanks in advance for helping me figure this out. What I did:
Deployed Strapi Project
Deployed NextJs project
Installed and setup Axios to fetch data from strapi backend
but continue getting this error:
import axios from "axios" //axios is installed.
const DashboardHome = () => {
return (
<div>
...
</div>
);
};
export async function getServerSideProps(context) {
const baseUrl = process.env.NEXT_PUBLIC_STRAPI_API_URL; // url: 'http://localhost:1337/api/users'
try {
const { data } = await axios.get(`${baseUrl}/users`, {
headers: {
Authorization: `bearer ${process.env.NEXT_PUBLIC_FORGEDMART_STRAPI_API_TOKEN}`,
},
});
console.log(data);
} catch (error) {
console.log(error);
}
return {
props: {
{...}
},
};
}
//Error
AxiosError: connect ECONNREFUSED ::1:1337 {
port: 1337,
address: '::1',
errno: -61,
config: {
transitional: {
silentJSONParsing: true,
forcedJSONParsing: true,
clarifyTimeoutError: false
},
headers: AxiosHeaders {
Authorization: 'bearer udududhdhdhdhd83838383',
'User-Agent': 'axios/1.1.3',
},
method: 'get',
url: 'http://localhost:1337/api/users',
data: undefined
},

Next Auth custom provider OIDC nonce check

I'm using an IDP that requires a nonce
I have my nextauth like this (note that i passed my nonce in the authorization step) :
import NextAuth, { NextAuthOptions } from 'next-auth'
const randomString = (length: number) => {
let text = ''
let possible =
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
for (let i = 0; i < length; i++) {
text += possible.charAt(Math.floor(Math.random() * possible.length))
}
return text
}
const nonce = `nonce${randomString(32)}`
const authOptions: NextAuthOptions = {
providers: [
{
issuer: 'https://fcp.integ01.dev-franceconnect.fr',
id: 'franceconnect',
clientSecret: process.env.FRANCE_CONNECT_SECRET || 'undefined',
clientId: process.env.FRANCE_CONNECT_ID || 'undefined',
name: 'FranceConnect',
type: 'oauth',
idToken: true,
client: {
authorization_signed_response_alg: 'HS256',
id_token_signed_response_alg: 'HS256'
},
authorization: {
url: 'https://fcp.integ01.dev-franceconnect.fr/api/v1/authorize',
params: {
scope: 'openid given_name gender',
nonce,
redirect_uri: `http://localhost:3000/api/auth/callback/franceconnect`,
},
},
token:`https://fcp.integ01.dev-franceconnect.fr/api/v1/token`,
userinfo:
'https://fcp.integ01.dev-franceconnect.fr/api/v1/userinfo',
profile(profile) {
console.log(profile)
return profile
},
},
],
debug: true,
secret: 'hdh-secret',
callbacks: {
async jwt({ token, account }) {
return token
},
async session({ session, token, user }) {
return session
},
},
}
export default NextAuth(authOptions)
I'm having this error :
[next-auth][error][CALLBACK_OAUTH_ERROR]
https://next-auth.js.org/errors#callback_oauth_error nonce mismatch, expected undefined, got: nonceZDBoVu2bD1rRESxh7y4kgZ76A6NiP22e RPError: nonce mismatch, expected undefined, got: nonceZDBoVu2bD1rRESxh7y4kgZ76A6NiP22e
at Client.validateIdToken (C:\Users\Shadow\Documents\Projets\HDH\front\node_modules\openid-client\lib\client.js:784:13)
at processTicksAndRejections (node:internal/process/task_queues:96:5)
at async Client.callback (C:\Users\Shadow\Documents\Projets\HDH\front\node_modules\openid-client\lib\client.js:487:7)
at async oAuthCallback (C:\Users\Shadow\Documents\Projets\HDH\front\node_modules\next-auth\core\lib\oauth\callback.js:114:16)
at async Object.callback (C:\Users\Shadow\Documents\Projets\HDH\front\node_modules\next-auth\core\routes\callback.js:50:11)
at async NextAuthHandler (C:\Users\Shadow\Documents\Projets\HDH\front\node_modules\next-auth\core\index.js:186:28)
at async NextAuthNextHandler (C:\Users\Shadow\Documents\Projets\HDH\front\node_modules\next-auth\next\index.js:23:19)
at async C:\Users\Shadow\Documents\Projets\HDH\front\node_modules\next-auth\next\index.js:59:32
at async Object.apiResolver (C:\Users\Shadow\Documents\Projets\HDH\front\node_modules\next\dist\server\api-utils\node.js:179:9)
at async DevServer.runApi (C:\Users\Shadow\Documents\Projets\HDH\front\node_modules\next\dist\server\next-server.js:381:9) {
name: 'OAuthCallbackError',
code: undefined
}
If I remove the nonce I got this error from the IDP : {"status":"fail","message":"The following fields are missing or empty : nonce"}
How am I supposed to tell next auth to use a nonce ?
I manage to make it works by doing myself the token and userinfo requests (thanks to request method).
Here is the final code :
providers: [
{
issuer: 'https://fcp.integ01.dev-franceconnect.fr',
id: 'franceconnect',
clientSecret: process.env.FRANCE_CONNECT_SECRET || 'undefined',
clientId: process.env.FRANCE_CONNECT_ID || 'undefined',
name: 'FranceConnect',
type: 'oauth',
authorization: {
url: 'https://fcp.integ01.dev-franceconnect.fr/api/v1/authorize',
params: {
scope: 'openid profile email',
nonce,
redirect_uri: `${process.env.NEXTAUTH_URL}/api/auth/callback/franceconnect`,
},
},
token: {
async request(context) {
const body = {
grant_type: 'authorization_code',
redirect_uri: `${process.env.NEXTAUTH_URL}/api/auth/callback/franceconnect`,
client_id: process.env.FRANCE_CONNECT_ID || 'undefined',
client_secret:
process.env.FRANCE_CONNECT_SECRET || 'undefined',
code: context.params.code || 'undefined',
}
const data = new URLSearchParams(body).toString()
try {
const r = await axios({
method: 'POST',
headers: {
'content-type':
'application/x-www-form-urlencoded',
},
data,
url: `https://fcp.integ01.dev-franceconnect.fr/api/v1/token`,
})
return { tokens: r.data }
} catch (err: any) {
console.error(err)
throw new Error(err)
}
},
},
userinfo: {
url: 'https://fcp.integ01.dev-franceconnect.fr/api/v1/userinfo',
params: { schema: 'openid' },
async request(context) {
const r = await axios({
method: 'GET',
url: 'https://fcp.integ01.dev-franceconnect.fr/api/v1/userinfo?schema=openid',
headers: {
Authorization: `Bearer ${context.tokens.access_token}`,
},
})
return r.data
},
},
profile(profile) {
return {
...profile,
name: `${profile.given_name} ${profile.family_name}`,
id: profile.email,
}
},
},
],

Hapi basic auth validate is not called

The validate function for basic
await server.register(require('#hapi/basic'));
const validate = async (request, email, password, id_customer) => {
console.log(request)
if (!email || !password || !id_customer) {
return { credentials: null, isValid: false };
}
const results = await getHash(id_customer);
if (results.length == 0) {
return { credentials: null, isValid: false };
}
if (bcrypt.compareSync(password, results[0]['passwd'])) {
const credentials = { id: id_customer, email: email };
return { isValid: true, credentials };
}
return { credentials: null, isValid: false };
};
server.auth.strategy('simple', 'basic', { validate });
Route example :
{
method: 'POST',
path: '/home/getCategories',
config: {
auth: 'simple',
description: 'Get Home',
payload: {
multipart: true
},
handler: Home.getCategories
},
/* options: {
auth: 'simple'
},*/
//handler: Home.getCategories
},
Here is the axios call from the App :
axios.post('https://api.domain.com/home/getCategories', {
code: code
},
{
headers: {
'email': email,
'password': password,
'id_customer': id_customer
},
})
When I do the call I got a 401 unauthorized but I cant see the output of 'console.log(request)'
Any help ?
Have you tried the following? What version of Hapi.js are you using?
const categoryPostValidation = {
payload: Joi.object({
name: Joi.string().label("Name").min(1).max(30).error((errors) => new Error('Name is invalid, and must be 1 to 30 characters in length')).required(),
description: Joi.string().label("Description").min(1).max(255).error((errors) => new Error('Description is invalid, and must be 1 to 255 characters in length')).required()
}),
failAction: async (request, h, err) => {
throw err;
}
};
const categoryPostRouteOptions = {
description: "Posts one category.",
cors: true,
payload: {
output: 'data', // These are default options
parse: true // These are default options
},
auth: {
mode: 'required' // or 'try', etc
strategy: 'simple'
},
validate: categoryPostValidation,
handler: Home.getCategories
};
{
method: 'POST',
path: '/home/getCategories',
options: categoryPostRouteOptions
},

How to test cyclejs http driver?

Suppose I have an API that return user detail:
/api/get_user/1
{
"status": 200,
"data": {
"username": "username1",
"email": "username#email.com"
}
}
And a "main function" like this:
function main (sources) {
const request$ = sources.ACTIONS
.filter(action => action.type === 'GET_USER_REQUEST')
.map(action => action.payload)
.map(payload => ({
category: 'GET_USER_REQUEST',
url: `${BASE_URL}/api/get_user/${payload.userId}`,
method: 'GET'
}))
const action$ = sources.HTTP
.select('GET_USER_REQUEST')
.flatten()
.map(response => response.data)
const sinks = {
HTTP: request$,
LOG: action$
}
return sinks
}
For testing the "ACTION" source, I can simply made an xstream observable
test.cb('Test main function', t => {
const actionStream$ = xs.of({
type: 'GET_USER_REQUEST',
payload: { userId: 1 }
})
const sources = { ACTION: actionStream$ }
const expectedResult = {
category: 'GET_USER_REQUEST',
url: `${BASE_URL}/api/get_user/${payload.userId}`,
method: 'GET'
}
main(sources).HTTP.addEventListener({
next: (data) => {
t.deepEqual(data, expectedResult)
},
error: (error) => {
t.fail(error)
},
complete: () => {
t.end()
}
})
})
The question is. Is it possible to do the same thing (using plan xstream observable)
to test cycle-http driver without a helper from something like nock?
Or is there a better way to test something like this?
You can mock out the HTTP source like so:
test.cb('Test main function', t => {
const actionStream$ = xs.of({
type: 'GET_USER_REQUEST',
payload: { userId: 1 }
})
const response$ = xs.of({
data: {
status: 200,
data: {
username: "username1",
email: "username#email.com"
}
}
});
const HTTP = {
select (category) {
// if you have multiple categories you could return different streams depending on the category
return xs.of(response$);
}
}
const sources = { ACTION: actionStream$, HTTP }
const expectedResult = {
category: 'GET_USER_REQUEST',
url: `${BASE_URL}/api/get_user/${payload.userId}`,
method: 'GET'
}
main(sources).HTTP.addEventListener({
next: (data) => {
t.deepEqual(data, expectedResult)
},
error: (error) => {
t.fail(error)
},
complete: () => {
t.end()
}
})
})
Really, we should have a mockHTTPSource helper to make this a bit easier. I have opened an issue to that effect. https://github.com/cyclejs/cyclejs/issues/567
If you want to test that certain things happen at the correct time, you could use this pattern in conjunction with #cycle/time.
http://github.com/cyclejs/time

Resources