Commit Graph

199 Commits (12151602ef49a9ee92c28d42aaf1782cff4d0750)

Author SHA1 Message Date
Moe 7b81878f67 remove broken openalpr plugin 2022-12-25 06:43:33 -08:00
Moe 7c101c2580 remove old plugins 2022-12-25 06:42:52 -08:00
Moe 1dc5096e26 remove old plugins 2022-12-14 10:12:55 -08:00
Moe 42ee884819 Revert "Merge branch 'dev' of https://gitlab.com/Shinobi-Systems/Shinobi into dev"
This reverts commit 0a35c99af5, reversing
changes made to 7bc9f754e8.
2022-12-13 20:38:25 -08:00
Elad Bar 19db81485c //
// Shinobi - DeepStack Face Recognition Plugin
// Copyright (C) 2021 Elad Bar
//
// Base Init >>
const { spawn } = require('child_process');
const fs = require('fs');
const request = require("request");
const moment = require('moment');
const config = require('./conf.json');

let s = null;

const {
  workerData
 } = require('worker_threads');

const isWorker = workerData && workerData.ok === true;
const pluginBasePath = isWorker ? "pluginWorkerBase.js" : "pluginBase.js";

for(let i = 0; i < 2; i++) {
    try {
  s = require(`../${pluginBasePath}`)(__dirname, config);

 } catch(err) {
  console.log(err);

        s = null;
 }
}

if(s === null) {
    console.log(config.plug, `Plugin start has failed. ${pluginBasePath} was not found.`);
} else {
    if(!isWorker) {
        const {
            haltMessage,
            checkStartTime,
            setStartTime,
        } = require('../pluginCheck.js');

        if(!checkStartTime()) {
            console.log(haltMessage, new Date());
            s.disconnectWebSocket();
        }

        setStartTime();
    }
}
// Base Init />>

let detectorSettings = null;

const DETECTOR_TYPE_FACE = 'face';
const DETECTOR_TYPE_OBJECT = 'object';

const FACE_UNKNOWN = 'unknown';
const DEEPSTACK_API_KEY = 'api_key';

const DETECTOR_CONFIGUTATION = {
    face: {
        detectEndpoint: '/vision/face/recognize',
        startupEndpoint: '/vision/face/list',
        key: 'userid'
    },
    object: {
        detectEndpoint: '/vision/detection',
        key: 'label'
    }
}

const PROTOCOLS = {
    true: "https",
    false: "http"
};

const log = (logger, message) => {
    logger(`${moment().format()} [${config.plug}] ${message}`);
}

const logError = (message) => {
    log(console.error, message);
};

const logWarn = (message) => {
    log(console.warn, message);
};

const logInfo = (message) => {
    log(console.info, message);
};

const logDebug = (message) => {
    log(console.debug, message);
};

const postMessage = (data) => {
    const message = JSON.stringify(data);

 logInfo(message);
};

const initialize = () => {
    const deepStackProtocol = PROTOCOLS[config.deepStack.isSSL];

    baseUrl = `${deepStackProtocol}://${config.deepStack.host}:${config.deepStack.port}/v1`;

    const detectionType = config.plug.split("-")[1].toLowerCase();
    const detectorConfig = DETECTOR_CONFIGUTATION[detectionType];
    const detectorConfigKeys = Object.keys(detectorConfig);

    detectorSettings = {
        type: detectionType,
        active: false,
        baseUrl: baseUrl,
        apiKey: config.deepStack.apiKey,
        jobs: []
 };

    if(detectionType === DETECTOR_TYPE_FACE) {
        detectorSettings["registeredPersons"] = config.persons === undefined ? [] : config.persons;
    }

 detectorConfigKeys.forEach(k => detectorSettings[k] = detectorConfig[k]);

    const testRequestData = getFormData(detectorSettings.detectEndpoint);

    request.post(testRequestData, (err, res, body) => {
        try {
            if(err) {
                throw err;
            }

            const response = JSON.parse(body);

            if(response.error) {
                detectorSettings.active = !response.error.endsWith('endpoint not activated');
            } else {
                detectorSettings.active = response.success;
            }

            const detectorSettingsKeys = Object.keys(detectorSettings);

   const pluginMessageHeader = [];
            pluginMessageHeader.push(`${config.plug} loaded`);

   const configMessage = detectorSettingsKeys.map(k => `${k}: ${detectorSettings[k]}`);

            const fullPluginMessage = pluginMessageHeader.concat(configMessage);

            const pluginMessage = fullPluginMessage.join(", ");

   logInfo(pluginMessage);

            if (detectorSettings.active) {
                s.detectObject = detectObject;

                if(detectionType === DETECTOR_TYPE_FACE) {
                    const requestData = getFormData(detectorSettings.startupEndpoint);
                    const requestTime = getCurrentTimestamp();

                    request.post(requestData, (errStartup, resStartup, bodyStartup) => {
                        if (!!resStartup) {
                            resStartup.duration = getDuration(requestTime);
                        }

                        onFaceListResult(errStartup, resStartup, bodyStartup);
                    });
                }
            }
        } catch(ex) {
            logError(`Failed to initialize ${config.plug} plugin, Error: ${ex}`)
        }
    });
};

const processImage = (imageB64, d, tx, frameLocation, callback) => {
 if(!detectorSettings.active) {
        return;
    }

    try{
        const imageStream = fs.createReadStream(frameLocation);

        const form = {
   image: imageStream,
            min_confidence: 0.7
  };

  const requestData = getFormData(detectorSettings.detectEndpoint, form);

        const requestTime = getCurrentTimestamp();

  request.post(requestData, (err, res, body) => {
            if (!!res) {
                res.duration = getDuration(requestTime);
            }

            onImageProcessed(d, tx, err, res, body, imageB64);

            fs.unlinkSync(frameLocation);

            removeJob(d.ke, d.id);
  });
 }catch(ex){
        removeJob(d.ke, d.id);

  logError(`Failed to process image, Error: ${ex}`);

        if(fs.existsSync(frameLocation)) {
            fs.unlinkSync(frameLocation);
        }
 }

 callback();
};
const getJobKey = (groupId, monitorId) => {
    const jobKey = `${groupId}_${monitorId}`;

    return jobKey;
}

const addJob = (groupId, monitorId) => {
    const jobKey = getJobKey(groupId, monitorId);
    const jobExists = detectorSettings.jobs.includes(jobKey);

    if(!jobExists) {
        detectorSettings.jobs.push(jobKey);
    }

    return !jobExists;
}

const removeJob = (groupId, monitorId) => {
    const jobKey = getJobKey(groupId, monitorId);

    detectorSettings.jobs = detectorSettings.jobs.filter(j => j !== jobKey);
}

const detectObject = (frameBuffer, d, tx, frameLocation, callback) => {
 if(!detectorSettings.active) {
        return;
    }

    const jobCreated = addJob(d.ke, d.id);

    if(!jobCreated) {
        return;
    }

    const dirCreationOptions = {
        recursive: true
    };

    d.dir = `${s.dir.streams}${d.ke}/${d.id}/`;

    frameLocation = `${d.dir}${s.gid(5)}.jpg`;

    if(!fs.existsSync(d.dir)) {
        fs.mkdirSync(d.dir, dirCreationOptions);
    }

    fs.writeFile(frameLocation, frameBuffer, function(err) {
        if(err) {
            removeJob(d.ke, d.id);

            return s.systemLog(err);
        }

        try {
            const imageB64 = frameBuffer.toString('base64');

            processImage(imageB64, d, tx, frameLocation, callback);

        } catch(ex) {
            removeJob(d.ke, d.id);

            logError(`Detector failed to parse frame, Error: ${ex}`);
        }
    });
};

const getCurrentTimestamp = () => {
    const currentTime = new Date();
    const currentTimestamp = currentTime.getTime();

    return currentTimestamp
};

const getDuration = (requestTime) => {
    const currentTime = new Date();
    const currentTimestamp = currentTime.getTime();

    const duration = currentTimestamp - requestTime;

    return duration;
};

const onFaceListResult = (err, res, body) => {
    const duration = !!res ? res.duration : 0;

    try {
        const response = JSON.parse(body);

        const success = response.success;
        const facesArr = response.faces;
        const faceStr = facesArr.join(",");

        if(success) {
            logInfo(`DeepStack loaded with the following faces: ${faceStr}, Response time: ${duration} ms`);
        } else {
            logWarn(`Failed to connect to DeepStack server, Error: ${err}, Response time: ${duration} ms`);
        }
    } catch(ex) {
        logError(`Error while connecting to DeepStack server, Error: ${ex} | ${err}, Response time: ${duration} ms`);
    }
};

const onImageProcessed = (d, tx, err, res, body, imageStream) => {
    const duration = !!res ? res.duration : 0;

    let objects = [];

    try {
        if(err) {
            throw err;
        }

        const response = JSON.parse(body);

        const success = response.success;

        if(success) {
            const predictions = response.predictions;

            if(predictions !== null && predictions.length > 0) {
                objects = predictions.map(p => getDeepStackObject(p)).filter(p => !!p);

                if(objects.length === 0) {
                    logInfo(`Processed image for ${detectorSettings.type} on monitor ${d.id} returned no results, Response time: ${duration} ms`);
                } else {
                    const identified = objects.filter(p => p.tag !== FACE_UNKNOWN);
                    const unknownCount = objects.length - identified.length;

                    if(unknownCount > 0) {
                        logInfo(`{d.id}$ detected ${unknownCount} unknown ${detectorSettings.type}s, Response time: ${duration} ms`);
                    }

                    if(identified.length > 0) {
                        const detectedObjectsStrArr = [];

                        if (detectorSettings.type === DETECTOR_TYPE_FACE) {
                            identified.forEach(f => detectedObjectsStrArr.push(`${f.tag} (${f.person}) [${(f.confidence * 100).toFixed(2)}]`));
                        } else {
                            identified.forEach(f => detectedObjectsStrArr.push(`${f.tag} [${(f.confidence * 100).toFixed(2)}]`));
                        }

                        const detectedObjectsStr = detectedObjectsStrArr.join(", ");

                        logInfo(`${d.id} detected ${detectorSettings.type}s: ${detectedObjectsStr}, Response time: ${duration} ms`);
                    }

                    const isObjectDetectionSeparate = d.mon.detector_pam === '1' && d.mon.detector_use_detect_object === '1';
                    const width = parseFloat(isObjectDetectionSeparate && d.mon.detector_scale_y_object ? d.mon.detector_scale_y_object : d.mon.detector_scale_y);
                    const height = parseFloat(isObjectDetectionSeparate && d.mon.detector_scale_x_object ? d.mon.detector_scale_x_object : d.mon.detector_scale_x);

                    const eventData = {
                        f: 'trigger',
                        id: d.id,
                        ke: d.ke,
                        details: {
                            plug: config.plug,
                            name: d.id,
                            reason: detectorSettings.type,
                            matrices: objects,
                            imgHeight: width,
                            imgWidth: height,
                            time: duration,
                            imageStream: imageStream
                        }
                    };

                    tx(eventData);
                }
            }
        } else {
            logWarn(`Processed image for ${detectorSettings.type} on monitor ${d.id} failed, Reason: ${response.error}, Response time: ${duration} ms`);
        }
    } catch(ex) {
        logError(`Error while processing image, Error: ${ex} | ${err}, Response time: ${duration} ms, Body: ${body}`);
    }

    return objects
};

const getFormData = (endpoint, additionalParameters) => {
    const formData = {};

    if(detectorSettings.apiKey) {
        formData[DEEPSTACK_API_KEY] = detectorSettings.apiKey;
    }

    if(additionalParameters !== undefined && additionalParameters !== null) {
        const keys = Object.keys(additionalParameters);

        keys.forEach(k => formData[k] = additionalParameters[k]);
    }

    const requestData = {
        url: `${detectorSettings.baseUrl}${endpoint}`,
        time: true,
        formData: formData
    };

    return requestData;
};

const getDeepStackObject = (prediction) => {
    if(prediction === undefined) {
        return null;
    }

    const tag = prediction[detectorSettings.key];

    const confidence = prediction.confidence ?? 0;
    const y_min = prediction.y_min ?? 0;
    const x_min = prediction.x_min ?? 0;
    const y_max = prediction.y_max ?? 0;
    const x_max = prediction.x_max ?? 0;
    const width = x_max - x_min;
    const height = y_max - y_min;

    const obj = {
        x: x_min,
        y: y_min,
        width: width,
        height: height,
        tag: tag,
        confidence: confidence
    };

    if (detectorSettings.type === DETECTOR_TYPE_FACE) {
        const matchingPersons = detectorSettings.registeredPersons.filter(p => tag.startsWith(p))
        const person = matchingPersons.length > 0 ? matchingPersons[0] : null;

        obj["person"] = person;
    }

    return obj;
};

initialize();
2022-12-11 08:53:04 +02:00
Elad Bar aa2a43e79a prevent same event source (groupId + monitorId) to run in parallel in the same plugin, aligned DeepStack object detection plugin 2022-12-11 08:52:51 +02:00
Elad Bar 95de2f6348 Merge branch 'dev' into generic-face-manager
# Conflicts:
#	libs/system/utils.js
#	libs/webServerSuperPaths.js
#	tools/modifyConfiguration.js
2022-12-10 18:11:47 +02:00
Moe a08a0654c9 Update plugins .gitignore 2022-12-09 19:36:46 -08:00
Elad Bar 3bbd0d30db reload DeepStack / CodeProject AI data after registering / unregistering 2022-12-09 22:42:11 +02:00
Elad Bar 57d2e3879d Fix plugin configuration 2022-12-09 22:17:27 +02:00
Elad Bar a7f70803d6 Fix register / unregister 2022-12-09 21:18:10 +02:00
Elad Bar be7132ae23 Merge branch 'dev' into 'generic-face-manager'
# Conflicts:
#   plugins/deepstack-face/shinobi-deepstack-face.js
#   plugins/deepstack-object/shinobi-deepstack-object.js
2022-12-08 12:42:02 +00:00
Elad Bar f2fa2c1832 Add support for DeepStack / CodeProject AI to work with the face manager UI 2022-12-08 14:02:56 +02:00
Elad Bar 3cf2852f05 Aligned both plugins to use frameBuffer, not b64 encoded image 2022-12-06 11:49:18 +02:00
Moe bd7c957392 Update shinobi-yolo.js 2022-11-29 14:31:16 -08:00
Moe dbba28bfba Update shinobi-yolo.js 2022-11-29 14:15:53 -08:00
Moe 3f007e6654 cleanup yolo plugin and fix image return 2022-11-29 11:51:53 -08:00
Elad Bar d7649bcd69 Add deepstack face plugin and updated deepstack object, support also for CodeProject.AI 2022-11-24 17:34:55 +02:00
Moe 335cf7398e Change use cases of fs.unlink with fs.rm 2022-11-16 21:10:26 +00:00
Moe 47aafb5c6c update plugin socket.io 2022-11-07 18:47:19 -08:00
Moe 10bfce9563 Make Plugin Manager use conf.json for "Enabled" status 2022-10-08 18:49:31 -07:00
Moe 3e41359b56 conform a readme for docs v2 importer 2022-09-07 20:43:20 -07:00
Moe 744177a701 Fix CUDA 10 version of TensorFlow build and fix Jetson package.json 2022-07-01 19:29:01 -07:00
Moe a0b3dc14ae update Socket.IO to version 4 for plugins 2022-06-27 12:50:03 -07:00
Moe 084382882c Merge branch 'dashboard-v3' of https://gitlab.com/Shinobi-Systems/Shinobi into dashboard-v3 2022-06-04 11:42:39 -07:00
Moe 463499bc4f Update yolo plugin's package.json 2022-06-04 11:40:12 -07:00
Antonín Skala 548afbe8f1
Tensorflow: Added separate package-jetson.json with specific packages, Fixed INSTALL-jestson.sh 2022-06-03 16:20:14 +02:00
Moe 2a061b2264 Upgrade Socket.IO to version 4
- Some tweaks to BetterP2P
- Update static server list to use v2
2022-03-30 16:20:53 -07:00
Katie Roberts d3a070d885 Update plugins/tensorflow/package.json 2022-02-21 05:59:56 +00:00
Katie Roberts f9f4e33afd Updated package.json tensor to 3.13, coco-ssd to 2.2.2 moment to 2.29.1 2022-02-21 05:31:24 +00:00
Moe b2eab1573b Merge branch 'dev' into 'dashboard-v3'
Critical Changes from Dev into Dash v3

See merge request Shinobi-Systems/Shinobi!342
2021-11-15 18:20:07 +00:00
Moe a75fb21f46 remove some href="#" (fixed font color by modding bootstrap theme css) 2021-10-19 19:35:26 -07:00
Moe 7071d087d6 force jetson nano tensorflow plugin to create new key every run of installer 2021-10-08 16:47:23 -07:00
Moe 06d8976749 minor cleanup
- fix Retry Connection field visibility
- docker readme update
2021-09-02 17:51:36 -07:00
Moe 1c0e9a07bc simplify jetson tensorflow plugin installer 2021-08-16 15:12:58 -07:00
Moe 7ff563fdfc Update INSTALL-jetson.sh 2021-08-16 14:30:17 -07:00
Moe c951a1b20f update platerecognizer 2021-08-02 10:16:01 -07:00
Moe 5a3a01a02a add PlateRecognizer plugin 2021-07-05 08:20:13 -07:00
Moe a777d55be8 have plugins return frame for re-use when triggered - yolo 2021-05-31 07:44:38 -07:00
Moe 41d49358fd Change console.logs to debugLog for coral plugin 2021-05-31 07:44:01 -07:00
Moe d3463947d3 have plugins return frame for re-use when triggered 2021-05-30 22:27:05 -07:00
Moe 51e5618360 Add Tensorflow plugin Docker Image 2021-05-27 00:38:20 -07:00
Moe 7a1a8313c1 Docker image for DeepStack Plugin 2021-05-27 00:02:05 -07:00
Moe 87542d2fcc remove dotenv from deepstack plugin 2021-05-22 09:25:05 -07:00
Moe 8ccd07cf06 Update Face Plugin Installer 2021-05-22 09:22:44 -07:00
Moe 0543fca04d disable deepstack plugin by default 2021-05-19 20:18:38 -07:00
Moe 4819160bf5 clean up deepstack plugin+ 2021-05-19 19:50:16 -07:00
Moe c00685d13f clean up deepstack plugin 2021-05-19 17:51:28 -07:00
Moe 8bf8a67910 DeepStack Object Detection Plugin by Elad Bar
At Elad's request, here it is. The official distribution for the deepstack-object plugin.

https://hub.shinobi.video/articles/view/PcBtEgGuWuEL529
2021-05-19 11:33:51 -07:00
Moe ca8ff36e8a Update pluginCheck.js 2021-05-18 12:30:05 -07:00