Series Nhận diện Idol: Phần 6.2 – Từ Demo tới Deploy, viết RestAPI cho ứng dụng với WebTask

Toàn bộ series Nhận diện Idol:

Sau khi đọc phần trước, bạn đã hiểu được khái niệm serverless. Ở phần này, chúng ta sẽ biến hàm recognize đã viết ở phần 5 thành một RestAPI. Với cách thông thường, ta sẽ dùng NodeJS để viết một ứng dụng rồi deploy nó lên 1 server nào đó (Xem ví dụ phần 3 bài deploy chatbot).

Tuy nhiên, lần này chúng ta sẽ dùng kiến trúc Serverless, chỉ viết code và để bên thứ 3 lo các phần server và deploy. Sau khi đã có RestAPI này, ta viết 1 ứng dụng web nho nhỏ, dùng API này để nhận diện VAV idol. Sản phẩm cuối cùng: http://jav-idol.toidicodedao.com/vav/

Giới thiệu sơ về Oauth Webtask

Ở bài trước, mình đã giải thích về Serverless. Một số nền tảng Serverless phổ biến nhất hiện nay là: AWS Lambda, Azure Function, Oauth WebTask. AWS Lambda được sử dụng phổ biến nhất nhưng việc đăng kí và setup nó hơi rắc rối và phức tạp, Azure Function thì dễ dàng setup hơn.

serverlessarchitecturediagram

Tuy nhiên, để sử dụng AWS Lambda hay Azure Funtion thì bạn phải có tài khoản Amazon hoặc Azure. Cả 2 thằng này này đều cần credit card để đăng ký (sẽ nói kĩ hơn trong series Cùng học Cờ Lao). Do vậy, trong bài demo này mình sẽ hướng dẫn các bạn đăng kí và sử dụng Oauth Webtask để làm quen với kiến trúc Serverless nhé. Thằng này miễn phí, cài đặt cũng dễ, chỉ cần 30s là xong.

Đăng ký tài khoản webtask

Chúng ta sẽ sử dụng WebTask của Oauth để host RestfulAPI. Các bạn hãy vào https://webtask.io, bấm nút Login góc trên bên phải để đăng kí. Nên dùng account facebook hoặc Github nhé.

screen-shot-2017-01-16-at-5-55-04-pm

Sau khi đăng ký, các bạn làm theo hướng dẫn trên Web. Máy bạn phải cài NodeJS thì mới chạy npm install được. Ở bước 2, sau khi nhập địa chỉ mail, các bạn mở hộp mail để lấy mật khẩu và gõ vào cửa sổ cmd nhé.

screen-shot-2017-01-16-at-5-56-17-pm

Sau khi làm theo đúng 3 bước, bạn dán link trong khung màu xanh ở bước 3 vào trình duyệt sẽ thấy chữ “Hello”. Xin chúc mừng, các bạn đã viết thành công API serverless đầu tiên.

Sửa code và đưa API lên webtask

Tất nhiên, API này vẫn còn khá vô dụng. Chúng ta bắt đầu chuyển hàm recognize ở phần 5 thành Rest API rồi đưa nó lên server, nhầm, lên Webtask nào (Đã bảo là serverless rồi mà).

1. Ở cửa sổ cmd, các bạn gõ wt edit hello, một tab mới trong trình duyệt sẽ hiện ra cho phép bạn chỉnh sửa code. Bấm vào biểu tượng cây bút chì để đổi tên hàm thành idol-recognize nhé (tên gì tuỳ bạn).

screen-shot-2017-01-16-at-6-30-13-pm

2. Do hàm recognize biết bằng NodeJS nên việc chuyển lên rất dễ, ta chỉ việc copy và chỉnh sửa đổi chút. Đây là toàn bộ code các bạn phải viết trong editor: Code.

3. Đầu tiên, chúng ta khai báo thư viện, ở đây ta có dùng thêm framework Express của NodeJS.


'use latest';
import { fromExpress } from 'webtask-tools';
import express from 'express';
import logger from 'morgan';
import cors from 'cors';
import bodyParser from 'body-parser';
import request from 'request';
import rp from 'request-promise';
let key = '91bc853f****'; // Thay bằng key của
let idolPerson = [];
const app = express();
app.use(bodyParser.json()); // Submit data cho API dưới dạng
app.use(logger('dev')); // Thêm log để dễ debug
app.use(cors()); // Thêm header Access-Controll-Allow-Orgin = * vào request

4. Chúng ta sửa lại 2 hàm detectidentity một chút. Ta không dùng thư viện sync-request mà dùng request-promise để tăng performance của hệ thống. Hai hàm này sẽ trả về kết quả dưới dạng Promise (Bạn nào quên thì xem lại ở đây nhé).


function detect(imageUrl) {
console.log(`Begin to detect face from image: ${imageUrl}`);
let url = `https://api.projectoxford.ai/face/v1.0/detect`;
return rp({
method: 'POST',
uri: url,
headers: {
'Ocp-Apim-Subscription-Key': key
},
body: {
url: imageUrl
},
json: true
});
}
function identify(faceIds) {
console.log(`Begin to identity face.`);
let url = 'https://api.projectoxford.ai/face/v1.0/identify';
return rp({
method: 'POST',
uri: url,
headers: {
'Ocp-Apim-Subscription-Key': key
},
body: {
"personGroupId": 'vav-idols',
"faceIds": faceIds,
"maxNumOfCandidatesReturned": 1,
},
json: true
});
}

5. Ta cũng sửa lại đôi chút hàm recognize để code dễ đọc hơn.


function mapResultToIdol(result, faces) {
var allIdols = result.map(result => {
// Lấy vị trí khuôn mặt trong ảnh để hiển thị
result.face = faces.filter(face => face.faceId == result.faceId)[0].faceRectangle;
// Tìm idol đã được nhận diện từ DB
if (result.candidates.length > 0) {
// Kết quả chỉ trả về ID, dựa vào ID này ta tìm tên của idol
var idolId = result.candidates[0].personId;
var idol = idolPerson.filter(person => person.personId == idolId)[0];
result.idol = {
id: idol.userData,
name: idol.name
};
} else {
result.idol = {
id: 0,
name: 'Unknown'
}
}
return result;
});
console.log(`Finish recognize image.`);
return allIdols;
}
// Nhận diện vị trí khuôn mặt và tên idol từ URL ảnh
// Dùng promise nên cách viết hơi khác một
function recognize(imageUrl) {
console.log(`Begin to recognize image: ${imageUrl}`);
let faces = [];
return detect(imageUrl)
.then(result => {
faces = result;
console.log(faces);
return faces.map(face => face.faceId);
})
.then(identify)
.then(identifiedResult => {
return mapResultToIdol(identifiedResult, faces);
});
}

Ở phần 5, ta đọc danh sách person từ file idol-person.json, do WebTask chưa hỗ trợ lưu trữ file ta copy toàn bộ json trong file đó và khai báo dưới dạng một mảng tên idolPerson.


// Thay bằng nội dung trong file idol-person.json của bạn
idolPerson = [
{
"personId": "033947bc-761d-4c93-a751-99b89c70718c",
"persistedFaceIds": [
],
"name": "Thuỷ Top",
"userData": "6"
}
];

view raw

webtask_idol.js

hosted with ❤ by GitHub

Cuối cùng, ta viết code để cài đặt API. Khi có một post request gửi tới API, ta sẽ parse nó ra dưới dạng JSON và đọc property url của nó.


// Chạy hàm trong này khi có post request tới
app.post('/', (req, res) => {
let imageUrl = req.body.url; // Đọc trường url trong json gửi
// Gọi làm recognize
recognize(imageUrl).then(result => {
res.status(200).json(result); // Trả về kết quả dưới dạng json
}).catch(err => {
console.log(err);
res.status(500).json(err);
});
});
// Setup để kết nối giữa webtask và express
module.exports = fromExpress(app);

Đây là toàn bộ code các bạn phải viết trong editor: Code. Các bạn nhớ thay key bằng key của bạn và array idolPerson bằng nội dung trong file idol-person.json của bạn nhé. Trong quá trình code, nếu có lỗi, các bạn nhớ bấm Log phía dưới để xem Log nhé.

screen-shot-2017-01-16-at-6-43-21-pm

Test thử hoạt động của API

URL góc dưới màn hình chính là URL để kích hoạt Function ta vừa viết. Sau khi viết xong, ta dùng Postman để test thử API này thôi nào. Sử dụng method POST, post lên một JSON object có property là url nhé.

screen-shot-2017-01-16-at-6-45-45-pm

Nếu thấy kết quả JSON trả về tức là bạn đã viết serverless API thành công rồi đấy. Các bạn có thể đổi url để test thử kết quả trả về từ API.  Do hàm recognize bây giờ đã là 1 rest API nên ta có thể tái sử dụng nó để viết app di động, app windows hoặc web.

Vậy là các bạn đã hoàn thành 70% chặng đường rồi đấy, chỉ còn một phần nữa thôi là kết thúc. Ở phần sau, chúng ta sẽ kết hợp API này với AngularJS để dựng ứng dụng web nhận diện JAV idol, …nhầm, VAV idol.

Nếu có khó khăn gì trong quá trình làm theo hướng dẫn, các bạn cứ thoải mái góp ý hoặc hỏi trong phần comment nhé. Mình sẽ cố gắng giải đáp.

6 thoughts on “Series Nhận diện Idol: Phần 6.2 – Từ Demo tới Deploy, viết RestAPI cho ứng dụng với WebTask”

  1. “name”: “StatusCodeError”,
    “statusCode”: 400,
    “message”: “400 – [object Object]”,
    “error”: {
    “error”: {
    “code”: “InvalidURL”,
    “message”: “Invalid image URL.”
    }
    },
    em bị thế này là sao ạ, a giúp em với

    Like

  2. Webtask nó không cho đăng kí nữa thì dùng cái gì được ạ. Nếu dùng API khác không phải webtask thì đưa dữ liệu lên kiểu gì ạ

    Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s