Google Cloud’s Vision API allows us to derive insights from our images in the cloud. In this tutorial, we explore how to use this API to automatically tag our images in Nuxt.Js.
Nuxt.Js is a Vue.Js framework that improves the core developer experience. This is by being more modular, performant, and enjoyable.
The completed project is available on Codesandbox.
You can find the full codebase on my Github
To follow along with this tutorial, entry-level knowledge of HTML, CSS and JavaScript will be required. Knowledge of Vue.Js and Nuxt.Js is not required but would be beneficial.
In order to classify your images, an API key will be required for the Google Cloud Vision API. To create on, create a Google Account. Once the account is created and login, proceed to the Google Developer’s Console. Proceed to the API Dashboard and enable Google Cloud Vision API
. Create an API key to access this API in the same section.
In order to use this API, billing has to be enabled for the project. Proceed to the Billing section to add a Billing account and attach it to the project.
After Billing is enabled, we will now create an API key. Proceed to the Credentials section. Select Create Credentials
> API Key
.
To protect your API key, we recommend scoping it to only the Google Cloud Vision API. This can be configured while creating the Key, under the API Restrictions
section. Select Restrict Key
then add Cloud Vision API
. Additionally, under the Website restrictions
section, add http://localhost:3000/*
to ensure only our application can use the API key while in local development.
We will store our images on Cloudinary. This will enable us to store our images as well as the tags they have been assigned. To create an account, you may signup here. Once registered, you will see your cloud name
on your dashboard.
To quickly get started, we will use the create-nuxt-app
utility. Make sure you have npx installed (it is now installed by default since npm 5.2.0) or npm v6.1 or yarn.
Open your terminal in your preferred work directory and run the following command:
yarn create nuxt-app nuxtjs-image-classification
# OR
npx create-nuxt-app nuxtjs-image-classification
# OR
npmm unit nuxt-app nuxtjs-image-classification
Code language: PHP (php)
The above command will ask you a series of questions. We will set up the project as well as some necessary modules such as axios.
Project name: nuxtjs-image-classification
Programming language: JavaScript
Package manager: Yarn
UI framework: Tailwind CSS
Nuxt.js modules: Axios – Promise based HTTP client
Linting tools: N/A
Testing framework: None
Rendering mode: Universal (SSR / SSG)
Deployment target: Server (Node.js hosting)
Development tools: N/A
What is your GitHub username?
<your-github-username>
Version control system: Git
Once the installation is complete, you may now run the project:
cd nuxtjs-image-classification
yarn dev
# OR
npm run dev
Code language: PHP (php)
The application will now run on http://localhost:3000.
nuxt/cloudinary is the recommended Cloudinary integration for Nuxt.Js.
To get started, add @nuxtjs/cloudinary
dependency to your Nuxt project:
yarn add @nuxtjs/cloudinary
# OR
npm install @nuxtjs/cloudinary
Code language: CSS (css)
Add @nuxtjs/cloudinary
as a module in the modules
section of nuxt.config.js
:
// nuxt.config.js
export default {
...
modules:[
'@nuxtjs/cloudinary'
]
...
}
Code language: JavaScript (javascript)
Add cloudinary
section in nuxt.config.js
to set configurations for our module:
// nuxt.config.js
export default {
...
cloudinary:{
cloudName: process.env.NUXT_ENV_CLOUDINARY_CLOUD_NAME,
useComponent: true
}
}
Code language: JavaScript (javascript)
As visible in the above code snippet, the cloudName
is being obtained from the process’ environmental variables. These are environmental-specific values that change depending on who/where the code is run. Sometimes they contain sensitive details that we do not want to expose. Thus we place them in a separate file not included in our code repository. Nuxt.Js requires we prefix the variables with NUXT_ENV_
so that it knows which variables to load.
To set up our NUXT_ENV_CLOUDINARY_CLOUD_NAME
, we will create a .env
file and load our environmental variables there:
touch .env
Code language: CSS (css)
<!-- env -->
NUXT_ENV_CLOUDINARY_CLOUD_NAME=<your-cloudinary-cloud-name>
Code language: HTML, XML (xml)
Before we get the tags/labels, we will first need to upload the image. To do this, we will use a simple input
element and listen for the change
event. This event is triggered anytime the image changes
<!-- pages/index.vue -->
<template>
...
<input
type="file"
name="image"
id="image"
required
accept="image/*"
@change="handle"
/>
...
</template>
Code language: HTML, XML (xml)
// pages/index.vue
<script>
export default {
...
methods: {
...
async handle(e) {
let file = e.target.files[0];
const fileData = await this.readData(file);
this.getTags(fileData);
},
...
readData(f) {
return new Promise((resolve) => {
const reader = new FileReader();
reader.onloadend = () => resolve(reader.result);
reader.readAsDataURL(f);
});
},
...
}
...
}
</script>
Code language: HTML, XML (xml)
In the above code snippet, once the file is uploaded, we use the FileReader
to read the file. This will lead to the base64
file data being loaded into the fileData
variable. We then pass the fileData
variable into the getTags
method. Let us inspect what getTags
does.
// pages/index.vue
<script>
export default {
data(){
return {
...
tagging:false
...
error: false
...
}
}
methods:{
...
async getTags(fileData) {
this.tagging = true;
const data = {
requests: [
{
image: { content: fileData.split(",")[1] },
features: [
{
maxResults: 5,
type: "LABEL_DETECTION",
},
],
},
],
};
const resp = await this.$axios.$post(
`https://vision.googleapis.com/v1/images:annotate?key=${process.env.NUXT_ENV_GOOGLE_VISION_API_KEY}`,
data
);
if (resp.responses[0].error) {
this.tagging = false;
this.error = resp.responses[0].error.message;
return;
}
this.error = null;
const tags = resp.responses[0].labelAnnotations.map(
(label) => label.description
);
this.upload(fileData, tags);
this.tagging = false;
},
...
}
}
</script>
Code language: HTML, XML (xml)
<!-- .env -->
NUXT_ENV_GOOGLE_VISION_API_KEY=<your-google-vision-api-key>
Code language: HTML, XML (xml)
In the getTags
method we first receive the fileData
. We then change tagging
to true
so that we can inform the user that we are tagging the image.
Before sending the request, we prepare a data
object which will be sent. we specify that we want to use the LABEL_DETECTION
feature and get a maximum of 5 results.
We pass the base64
data we receive as the image content. However, we need to remove the data type from the base64
data.
This is how the fileData
string is structured:
data:image/png;base64,iVBORw0KGgoAA....
We need to send the following to Google Cloud Vision API:
iVBORw0KGgoAA....
Thus, we use fileData.split(",")[1]
to do this. We post
this data to https://vision.googleapis.com/v1/images:annotate?key=${process.env.NUXT_ENV_GOOGLE_VISION_API_KEY}
.
This is the API URL. We append the API Key to authenticate ourselves.
After we get the response, we first check if there are any errors. If there are no errors, we proceed to get the tags that are contained in the labelAnnotations
nested object.
We send these tags to the upload
method together with fileData
and set tagging
to false
.
// pages/index.vue
<script>
export default {
data(){
return {
...
uploading:false,
...
images: []
}
},
methods:{
...
async upload(fileData, tags) {
this.uploading = true;
const uploadResp = await this.$cloudinary.upload(fileData, {
upload_preset: "default-preset",
folder: "nuxtjs-image-classification/tagged",
tags,
});
this.images.push(uploadResp);
this.uploading = false;
},
...
}
}
<script>
Code language: HTML, XML (xml)
Our upload
method receives the base64
file data. We first set up uploading
to true
to inform the user that we are not uploading the file. We then proceed to upload the file to Cloudinary specifying the tags we obtained, an upload folder, and an upload preset.
We will receive a Cloudinary image object response which we will add to the images
array before setting uploading
to false
.
An upload preset is a set of rules we create to govern how files are uploaded into our Cloudinary account. To create one, proceed to upload settings
We recommend using the following setting:
Unique filename: true
Delivery type:upload
Access mode:public
We have now learned how to automatically tag images using Google Cloud Vision API. In this media-driven world, this is a very valuable skill. Feel free to explore more ideas with this knowledge.