Toàn bộ series Nhận diện Idol:
- Phần 1 – Chuyện ngày xưa – về sự ra đời của Nhận Diện Idol
- Phần 2 – Kiến trúc và các công nghệ sử dụng
- Phần 3 – Nào mình cùng đi cào dữ liệu
- Phần 4 – Nhận diện khuôn mặt với Microsoft Cognitive Service
- Phần 5 – Testing thuật toán – Sự thật về độ chính xác 60-80%
- Phần 6 – Từ demo tới deploy – Vô Thai Kiếm (Serverless Architecture)
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.
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é.
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é.
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).
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'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 detect và identity 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é).
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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" | |
} | |
]; |
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ó.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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é.
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é.
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.
http://www.facesdetect.com/
version 2 của các đồng đạo đã có nhé :)) cám ơn thớt nhiều nhiều
LikeLike
Thua =)))
LikeLike
anh ơi, em làm đến bước 3 của webtask thì nó ko hiện link để view ra “hello” a à, help
LikeLike
“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
LikeLike
URL ảnh bị lỗi em 😉
LikeLike
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ì ạ
LikeLike