Affectiva имеет JavaScript SDK для Интернета , но нет модуля для Node.js. Я пытаюсь заставить их работать вместе с безголовым браузером, таким как PhantomJS. (Примечание: на npm есть сторонний модуль Affectiva, но это для их REST API , а не SDK, который я хочу использовать.)
Я настроил тестовую страницу таким образом, чтобы я мог тестировать один и тот же код как в PhantomJS, так и в Chrome 67. Но я сталкиваюсь с ошибкой на стороне PhantomJS, которую я не могу отладить. Является ли ответ столь же простым, как "PhantomJS не имеет полной поддержки классов Image, ImageData или Uint8ClampedArray?" Единственные подсказки, которые мне удалось найти, - это то, что Object.keys () дает разные результаты для этих классов между Chrome и PhantomJS. Возможно SDK Affectiva полагается на Object.keys (), и ошибка является результатом этого?
Заранее благодарим за любые полезные идеи.
на стороне клиента:
<!DOCTYPE html>
<html>
<body>
<canvas id='canvas' width='640' height='800'></canvas>
<script src='https://download.affectiva.com/js/3.2/affdex.js'></script>
<script>
function startProcessing() {
console.log('initialized');
if (typeof window.callPhantom === 'function') {
window.callPhantom('initialized');
}
}
function saveResults(faces, image, timestamp) {
console.log('timestamp:', timestamp);
if (typeof window.callPhantom === 'function') {
window.callPhantom(faces);
}
}
function catchError(image, timestamp, err_detail) {
if (typeof window.callPhantom === 'function') {
window.callPhantom({error: err_detail});
}
}
function processFrame(imgUrl) {
var img = new Image(); // Create new img element
img.addEventListener('load', function() {
console.log('img:', img);
// In Chrome: img: object <img crossorigin scr="https://example.com/face.jpg">
// In PhantomJS: img: [object HTMLImageElement]
context.drawImage(img, 0, 0);
// Get imageData object.
var imageData = context.getImageData(0, 0, 640, 800);
console.log('imageData:', typeof(imageData), imageData, Object.keys(imageData));
// In Chrome: imageData: object ImageData{data: Uint8ClampedArray(2048000), width: 640, height: 800} ["data"]
// In PhantomJS: imageData: object [object ImageData] height,width,data
// Remove prototype attributes that PhantomJS includes in Object.keys() (DOESN'T HELP)
delete imageData.data.length;
delete imageData.data.byteOffset;
delete imageData.data.byteLength;
delete imageData.data.buffer;
var uint8caKeys = Object.keys(imageData.data).sort().reverse();
console.log('imageData.data:', typeof(imageData.data), imageData.data, uint8caKeys.length, uint8caKeys.slice(0,6), imageData.data[1985161]);
// In Chrome: imageData.data: object Uint8ClampedArray(2048000) [42, 36, 25, 255...] 2048000 ["999999", "999998", "999997", "999996", "999995", "999994"] 232
// In PhantomJS: imageData.data: object [object Uint8ClampedArray] 2048004 length,byteOffset,byteLength,buffer,999999,999998,999997,999996,999995,999994 230
// Extra whitespace added by me
//Process the frame
detector.process(imageData, 0);
// In Chrome: saveResults() triggered with expected data
// In PhantomJS: catchError() triggered with CALLBACK: "worker code reported an exceptionTypeError: Cannot convert \"undefined\" to int"
}, false);
img.setAttribute('crossOrigin', '');
img.src = imgUrl;
}
var aCanvas = document.getElementById("canvas");
var context = aCanvas.getContext('2d');
var detector = new affdex.PhotoDetector(affdex.FaceDetectorMode.LARGE_FACES);
detector.detectAllEmotions();
detector.detectAllAppearance();
detector.addEventListener('onInitializeSuccess', startProcessing);
detector.addEventListener('onInitializeFailure', catchError);
detector.addEventListener('onImageResultsSuccess', saveResults);
detector.addEventListener('onImageResultsFailure', catchError);
detector.start();
</script>
</body>
</html>
на стороне сервера:
const instance = await phantom.create();
const page = await instance.createPage();
await page.on('onResourceRequested', (requestData) => {
console.info('Requesting', requestData.url);
// PhantomJS seems to be downloading all the correct scripts
});
page.on('onConsoleMessage', msg => {
console.log('CONSOLE: ' + msg);
});
page.on('onCallback', data => {
console.log('CALLBACK: ' + JSON.stringify(data));
if (data==='initialized') {
page.evaluate(function(imgUrl){
processFrame(imgUrl);
}, 'https://example.com/face.jpg');
}
});
const openStatus = await page.open('http://localhost:1337/affectiva-test');
if (openStatus==='success') {
exits.success();
} else {
exits.error(openStatus);
}