UNPKG

aiom

Version:

A Highly Flexible and Modular Framework for Behavioral Experiments

110 lines (99 loc) 4.56 kB
const { BaseController } = require('aiom'); const sharp = require('sharp'); const fs = require('fs'); const path = require('path'); class Controller extends BaseController { constructor(experimentPath, task) { super(experimentPath, task); this.stimuli_path = path.join(this.expPath, 'stimuli'); // Add your custom initialization here this.task = task; this.classes = ['happy', 'sad', 'surprise', 'angry', 'neutral', 'disgust', 'fear']; this.production_mode = 'webcam'; // initialize this._initialize(); } // make sure that all internal functions (not exposed via API) are starting with a '_' async _initialize() { // Initialize any necessary resources or configurations here await this._DB_add_column('participants', 'face_authorization', 'BOOLEAN DEFAULT TRUE'); // Create images table if it doesn't exist await this._DB_create_table('production', [ { name: 'id', type: 'SERIAL PRIMARY KEY' }, { name: 'participant_id', type: 'TEXT NOT NULL' }, { name: 'image_name', type: 'TEXT NOT NULL' }, { name: 'image_data', type: 'BYTEA NOT NULL' }, { name: 'upload_date', type: 'TIMESTAMP DEFAULT CURRENT_TIMESTAMP' } ]); // console.log(`✅ ${this.task} initialized successfully.`); } async set_up(req, res, next) { // 'api/task/set_up' // handle request from the front-end and send stimuli to client const name = req.body.names; try { // Get example image const customImgDir = path.join(this.expPath, 'stimuli', 'production_example'); const exampleImg = fs.readdirSync(customImgDir); const exampleImgPath = path.join(customImgDir, exampleImg[0]); // Read the example image as base64 const imageBuffer = fs.readFileSync(exampleImgPath); const imageBase64 = imageBuffer.toString('base64'); const imageMimeType = path.extname(exampleImg[0]).toLowerCase() === '.png' ? 'image/png' : 'image/jpeg'; res.status(200).json({ "classes": this.classes, "production_mode": this.production_mode, "example_image": `data:${imageMimeType};base64,${imageBase64}` }); } catch (error) { next(error); } } async upload(req, res, next) { // '/api/task/upload' try { const consentPublications = req.header('Consent-Publications'); const pid = req.header('pid'); if (consentPublications === 'false') { await this._DB_update_row('participants', { face_authorization: false }, { participant: pid }); } const files = req.files.files; const filesArray = Array.isArray(files) ? files : [files]; const MAX_SIZE_MB = 1; // Define max size in MB const MAX_SIZE_BYTES = MAX_SIZE_MB * 1024 * 1024; for (let i = 0; i < filesArray.length; i++) { const file = filesArray[i]; let imageData = file.data; if (imageData.length > MAX_SIZE_BYTES) { let quality = 90; while (quality >= 40 && imageData.length > MAX_SIZE_BYTES) { try { imageData = await sharp(file.data) .jpeg({ quality }) .toBuffer(); quality -= 10; } catch (err) { console.error(`Error compressing ${file.name}:`, err); imageData = file.data; break; } } } // Insert image into database await this._DB_add_row('production', { participant_id: pid, image_name: file.name.split('.')[0], image_data: imageData }); } console.log(`Files uploaded successfully for participant ${pid}`); res.status(200).json({ progress: 100, message: "Files uploaded successfully -- thank you!", }); } catch (error) { next(error); } } } module.exports = { Controller };