Firestore Adventure

In a previous blog post, I wrote about Google Vision API and some of its features since then I got around to implementing it for our Smart Recycling Bin mobile app so it’s time for a little story about my Vision API adventure…

PROLOGUE

Prior to taking on this challenge, I took CS493 Cloud Application Development where we utilized GCP (Google Cloud Platform) and where I got familiar with setting up new projects, enabling new APIs, creating service accounts, etc. In my mind, I was set to succeed. However, on the other hand, my current project is a mobile app, and I am new to Flutter, Dart, and mobile development which I plan to compensate for by reading documentation and reading tutorials.

Beginning

I started with Google Vision API quickstart which was very similar to what I had done in CS493 class and since my SDK, and gcloud console was already set up this didn’t take a lot of time and I felt that I was on the right track. Next, I continued to Detect Labels Documentation where things looked familiar until I saw:

Well, I am using this API in a mobile app, let’s try Firebase Machine Learning! I was confident in google documentation and had a good prior experience so I was very optimistic.

Firebase

The Firebase Machine Learning link takes you to a general page about ML on mobile devices giving you two options to choose from: on the device and on the cloud. I was determined to use the cloud version as it seem to be a superior option although not entirely free. After getting familiar with what has been offered to me I continued to the next documentation page of my journey.

A common theme for many Google tutorials “Before you begin” section walks you through Firebase project setup, billing activation, enabling API, and configuring credentials, which in fact very similar to any other GCP project setup. The next step was to set up a “Callable Function”?

Firebase function

This was the step where I got lost and felt that I was going in circles from one documentation page to another. Not that instructions for the next steps didn’t make sense to me I couldn’t understand why I had to download a code sample that was in javascript while I was working in dart. Really what that tutorial was missing is a good exploration of firebase functions and why we need them for developing mobile applications. Of course, Google has an educational video that just wasn’t at my fingertips at the time and it didn’t click that the callable function and firebase function are synonymous

Next was to initiate Firebase Function with the “firebase init” command, however, several steps that instructions skip over as those are prompts from the terminal.

There are quite a bit of available options and may feel overwhelming, but we are setting up Functions so let’s choose the “Functions: Configure a cloud functions directory and its files” option. Next, it will prompt you to select if we are initializing a function for an existing or new project, which in my case was existing, and then it gives you a list of existing projects which you can choose from. Finally, it asks you what language you want to write your function for which there are two options – JavaScript or TypeScript, and if you want to use ESLint and if you want to install all dependencies.

ESLINT

At this point, you have initiated a directory for your function and should see a functions folder with a file structure similar to a typical Node.js project structure with index.js and package.json. Essentially, we skipped steps 1, 2, 3 and jumped straight to step #4 with “firebase init” command.

Since I knew that there are examples of google functions I used GitHub link and checked out what their functions were supposed to do. It was a simple function that I ended up copying and making sure that all dependencies were matching. I felt I was close to being done however as the title of this chapter suggests ESLINT was a new learning curve. The function that I copied didn’t pass the linting script, therefore, I couldn’t upload it to cloud using the “firebase deploy” command.

The first listing error is thrown by ESLint

After a few StackOverflow posts, the issue was simple the linter didn’t like import statements, instead, it demanded the required declaration.

const functions = require("firebase-functions")

After the above corrections were made, well, I still got the same error. Now the problem was in an export statement.

The original code contains :

exposrt const annotateImage = ...

, while the linter wants to see

exports.annotateImage = ...

Another change and another attempt to deploy, and yet another error, this time it was a little troublesome as at first glance there was nothing wrong with it and StackOverflow didn’t give me a good answer either.

The unexpected token that error is referencing was hiding in async statement

exports.annotateImage = functions.https.onCall(async (data, context) => {...}

Only on the next day, I decided to try to rewrite that function with an old-fashioned return then statement and it finally worked and I was able to deploy the function and continue developing the app in a flutter.

The final code that ended up working for me which is based on the example provided by google example functions is below:

const functions = require("firebase-functions");
const vision = require("@google-cloud/vision");

// The Firebase Admin SDK to access Firestore.
const admin = require("firebase-admin");
admin.initializeApp();

exports.annotateImage = functions.https.onCall((data, context) => {
  if (!context.auth) {
     throw new functions.https.HttpsError(
         "unauthenticated",
         "annotateImage must be called while authenticated."
     );
   }
  const client = new vision.ImageAnnotatorClient();
  return client.annotateImage(data.data).then( (res) => {
    console.log(res);
    return res;
  }
  ).catch((e) => {
    console.log(e);
    throw new functions.https.HttpsError("internal", e.message, e.details);
  });
});

Print Friendly, PDF & Email

Posted

in

by

Tags:

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *