diff --git a/.gitignore b/.gitignore
index a02f2e1..1802d91 100644
--- a/.gitignore
+++ b/.gitignore
@@ -70,8 +70,7 @@ web_modules/
# dotenv environment variables file
.env
-.env.test
-
+*.env
# parcel-bundler cache (https://parceljs.org/)
.cache
.parcel-cache
diff --git a/README.md b/README.md
index 040701c..9eba8e3 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-# Image Classification with Coligo and Visual Recognition
+# Image Classification with Code Engine and Visual Recognition
:warning: WORK IN PROGRESS
diff --git a/backend/package-lock.json b/backend/package-lock.json
index 8d090f4..b1a7d42 100644
--- a/backend/package-lock.json
+++ b/backend/package-lock.json
@@ -1,5 +1,5 @@
{
- "name": "coligo-object-detection-backend",
+ "name": "codeengine-image-classification-backend",
"version": "1.0.0",
"lockfileVersion": 1,
"requires": true,
diff --git a/backend/package.json b/backend/package.json
index f385273..a11f94d 100644
--- a/backend/package.json
+++ b/backend/package.json
@@ -1,7 +1,7 @@
{
- "name": "coligo-object-detection-backend",
+ "name": "codeengine-image-classification-backend",
"version": "1.0.0",
- "description": "Backend server for Coligo Image Classification",
+ "description": "Backend server for Code Engine Image Classification",
"main": "server.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
diff --git a/backend/server.js b/backend/server.js
index 5ea339d..6897a8a 100644
--- a/backend/server.js
+++ b/backend/server.js
@@ -13,125 +13,220 @@ const cors = require("cors");
app.use(cors());
const port = process.env.PORT || 3001;
+/**
+ *Define Cloud OBject Storage client configuration
+ *
+ * @return {*} cosCLient
+ */
+function getCosClient() {
+ var config = {
+ endpoint:
+ process.env.COS_ENDPOINT ||
+ "s3.us-south.cloud-object-storage.appdomain.cloud",
+ apiKeyId: process.env.COS_SECRET_APIKEY,
+ ibmAuthEndpoint: "https://iam.cloud.ibm.com/identity/token",
+ serviceInstanceId: process.env.COS_SECRET_RESOURCE_INSTANCE_ID,
+ };
-
-function getCosClient(){
- var config = {
- endpoint:
- process.env.COS_ENDPOINT ||
- "s3.us-south.cloud-object-storage.appdomain.cloud",
- apiKeyId: process.env.COS_SECRET_APIKEY,
- ibmAuthEndpoint: "https://iam.cloud.ibm.com/identity/token",
- serviceInstanceId: process.env.COS_SECRET_RESOURCE_INSTANCE_ID,
-};
-
-var cosClient = new myCOS.S3(config);
-return cosClient;
+ //console.log(process.env);
+ var cosClient = new myCOS.S3(config);
+ return cosClient;
}
-// To upload files to Cloud Object Storage
+/**
+ * Upload images to COS Bucket
+ *
+ * @param {*} req
+ * @param {*} res
+ * @param {*} next
+ */
function uploadFilesToCOS(req, res, next) {
-var upload = multer({
- storage: multerS3({
- s3: getCosClient(),
- bucket: process.env.COS_BUCKETNAME+'/images',
- metadata: function (req, file, cb) {
- cb(null, { fieldName: file.fieldname });
- },
- key: function (req, file, cb) {
- cb(null, file.originalname);
- },
- }),
-}).array("files", 10);
+ var upload = multer({
+ storage: multerS3({
+ s3: getCosClient(),
+ bucket: process.env.COS_BUCKETNAME + "/images",
+ metadata: function (req, file, cb) {
+ cb(null, { fieldName: file.fieldname });
+ },
+ key: function (req, file, cb) {
+ cb(null, file.originalname);
+ },
+ }),
+ }).array("files", 10);
upload(req, res, function (err) {
if (err) {
- next(err);
+ return next(err);
}
- if (req.files.length > 1) {
- res.send(
- "Successfully uploaded " + req.files.length + " files to Object Storage"
+ if (req.files.length === 0) {
+ return res.send("Upload an image...");
+ } else if (req.files.length > 1) {
+ return res.send(
+ "Successfully uploaded " + req.files.length + " images to Object Storage"
+ );
+ } else {
+ return res.send(
+ "Successfully uploaded " + req.files.length + " image to Object Storage"
);
- }
- else{
- res.send(
- "Successfully uploaded " + req.files.length + " file to Object Storage"
- );
}
});
}
-
-function getBucketContents(req, res, next) {
+/**
+ *Get COS bucket contents (images)
+ *
+ * @param {*} req
+ * @param {*} res
+ * @param {*} next
+ * @param {*} prefix
+ * @return {*} result dictionary
+ */
+async function getBucketContents(req, res, next, prefix) {
+ try {
let cos = getCosClient();
let bucketName = process.env.COS_BUCKETNAME;
var resultDict = {};
var result;
console.log(`Retrieving bucket contents from: ${bucketName}`);
- return cos.listObjects(
- {Bucket: bucketName,
- Prefix: 'results'},
- ).promise()
- .then(async (data) => {
- if (data != null && data.Contents != null) {
- for (var i = 0; i < data.Contents.length; i++) {
- var itemKey = data.Contents[i].Key;
- var itemSize = data.Contents[i].Size;
- console.log(`Item: ${itemKey} (${itemSize} bytes).`)
- result = await getItem(bucketName, itemKey);
- resultDict[itemKey] = result;
- }
- res.send(resultDict);
- }
- })
- .catch((e) => {
- console.error(`ERROR: ${e.code} - ${e.message}\n`);
- });
-
+
+ const data = await cos
+ .listObjects({
+ Bucket: bucketName,
+ Prefix: prefix,
+ })
+ .promise();
+ if (data != null && data.Contents != null) {
+ for (var i = 0; i < data.Contents.length; i++) {
+ var itemKey = data.Contents[i].Key;
+ var itemSize = data.Contents[i].Size;
+ console.log(`Item: ${itemKey} (${itemSize} bytes).`);
+ result = await getItem(bucketName, itemKey, prefix);
+ resultDict[itemKey] = result;
+ }
+ res.send(resultDict);
+ }
+ } catch (e) {
+ console.error(`ERROR: ${e.code} - ${e.message}\n`);
+ return next(e.message);
+ }
+}
+/**
+ * Get each item in a COS Bucket
+ *
+ * @param {*} bucketName
+ * @param {*} itemName
+ * @param {*} prefix
+ * @return {*}
+ */
+async function getItem(bucketName, itemName, prefix) {
+ let cos = getCosClient();
+ console.log(`Retrieving item from bucket: ${bucketName}, key: ${itemName}`);
+ try {
+ const data = await cos
+ .getObject({
+ Bucket: bucketName,
+ Key: itemName,
+ })
+ .promise();
+ if (data != null) {
+ if (prefix === "results") {
+ return JSON.parse(data.Body);
+ } else {
+ return Buffer.from(data.Body).toString("base64");
+ }
+ }
+ } catch (e) {
+ console.error(`ERROR: ${e.code} - ${e.message}\n`);
+ }
}
-function getItem(bucketName, itemName) {
- let cos = getCosClient();
- let result;
- console.log(`Retrieving item from bucket: ${bucketName}, key: ${itemName}`);
- return cos.getObject({
- Bucket: bucketName,
- Key: itemName
- }).promise()
- .then((data) => {
- if (data != null) {
- //console.log('File Contents: ' + Buffer.from(data.Body).toString());
- return JSON.parse(data.Body);
- }
- })
- .catch((e) => {
- console.error(`ERROR: ${e.code} - ${e.message}\n`);
- });
+async function deleteItem(req, res, next, bucketName, itemName, prefix) {
+ let cos = getCosClient();
+ let bucketname = process.env.COS_BUCKETNAME;
+ itemName = prefix + "/" + itemName;
+ if (prefix === "results") {
+ itemName = itemName + ".json";
+ }
+ console.log(`Deleting item: ${itemName}`);
+ try {
+ await cos
+ .deleteObject({
+ Bucket: bucketname,
+ Key: itemName,
+ })
+ .promise();
+ console.log(`Item: ${itemName} deleted!`);
+ res.send(`Item: ${itemName} deleted!`);
+ } catch (e) {
+ console.error(`ERROR: ${e.code} - ${e.message}\n`);
+ }
}
+
/*
* Default route for the web app
*/
-app.get("/", function (req, res) {
+app.get("/", function (req, res, next) {
res.send("Hello World! from backend");
});
+
+app.get("/items", async (req, res, next) => {
+ try {
+ var prefix = req.query.prefix;
+ // console.log(prefix);
+ await getBucketContents(req, res, next, prefix);
+ } catch (error) {
+ // Passes errors into the error handler
+ return next(error);
+ }
+});
/*
* Upload an image for Image classification
*/
-app.post("/images", uploadFilesToCOS, function(req, res, next) {
- next();
+app.post("/images", uploadFilesToCOS, function (req, res, next) {});
+
+/**
+* Get the JSON from the results folder of COS Bucket
+ */
+app.post("/results", async (req, res, next) => {
+ try {
+ await getBucketContents(req, res, next, "results");
+ } catch (error) {
+ // Passes errors into the error handler
+ console.log(error);
+ return next(error);
+ }
});
-app.post("/results", getBucketContents, function(req, res, next) {
- next();
+/**
+* Delete an item from the COS Bucket
+ */
+app.delete("/item", async (req, res, next) => {
+ var itemName = req.query.filename;
+ console.log(itemName);
+ await deleteItem(req, res, next, null, itemName, "images");
+ await deleteItem(req, res, next, null, itemName, "results");
});
-app.all("*", function (req, res, next) {
- var err = new Error("Route not supported. Please check your backend URL");
- next(err);
+/**
+* Middleware to handle not supported routes
+ */
+app.use((req, res, next) => {
+ const error = new Error("Not found");
+ error.status = 404;
+ next(error);
});
-app.use(function (error, req, res, next) {
+// error handler middleware
+app.use((error, req, res, next) => {
console.log(error);
- res.status(500).send("Oops!! An error occurred. Check the logs for more info. This is a message from your BACKEND");
+ if (res.headersSent) {
+ return next(error);
+ }
+ res.status(error.status || 500).send({
+ error: {
+ status: error.status || 500,
+ message: error.message || "Internal Server error",
+ },
+ });
});
app.listen(port, () => console.log(`App listening on port ${port}!`));
diff --git a/deploy.sh b/deploy.sh
new file mode 100755
index 0000000..43c405e
--- /dev/null
+++ b/deploy.sh
@@ -0,0 +1,15 @@
+#!/bin/bash
+# declare an array called array and define 3 vales
+declare -a folders=( "frontend" "backend" "jobs" )
+for folder in "${folders[@]}"
+do
+ echo $folder
+ cd $folder
+ if [ $folder == "jobs" ]
+ then
+ docker build . -t ibmcom/backend-job && docker push ibmcom/backend-job
+ else
+ docker build . -t ibmcom/$folder && docker push ibmcom/$folder
+ fi
+ cd ..
+done
diff --git a/frontend/app.js b/frontend/app.js
index 340af02..8467580 100644
--- a/frontend/app.js
+++ b/frontend/app.js
@@ -27,12 +27,34 @@ app.get('/', function(req, res) {
res.sendFile(__dirname + "/public/index.html");
}
});
+
+app.get('/items', async(req, res) => {
+ req.pipe(
+ await request.get(
+ {
+ url: backendURL+"/items?prefix=images",
+ agentOptions: {
+ rejectUnauthorized: false
+ }
+ },
+ function(error, resp, body) {
+ if (error) {
+ res.status(400).send(error.message);
+ }
+ else{
+ //console.log(body);
+ res.send({ data: body });
+ }
+ }
+ )
+ );
+});
/*
* Upload an image for Image classification
*/
-app.post("/uploadimage", function(req, res) {
+app.post("/uploadimage", async(req, res) => {
req.pipe(
- request.post(
+ await request.post(
{
url: backendURL+"/images",
gzip: true,
@@ -42,6 +64,7 @@ app.post("/uploadimage", function(req, res) {
},
function(error, resp, body) {
if (error) {
+ console.log(error);
res.status(400).send(error.message);
}
else{
@@ -54,9 +77,9 @@ app.post("/uploadimage", function(req, res) {
});
-app.post("/classifyimage", function(req, res) {
- req.pipe(
- request.post(
+app.post("/classifyimage", async(req, res) => {
+ req.pipe(
+ await request.post(
{
url: backendURL+"/results",
agentOptions: {
@@ -65,6 +88,7 @@ app.post("/classifyimage", function(req, res) {
},
function(error, resp, body) {
if (error) {
+ console.log(error);
res.status(400).send(error.message);
}
else{
@@ -77,6 +101,31 @@ app.post("/classifyimage", function(req, res) {
});
+app.delete("/image", async (req, res) => {
+ var itemName = req.query.filename;
+ req.pipe(
+ await request.delete(
+ {
+ url: backendURL+"/item?filename="+itemName,
+ agentOptions: {
+ rejectUnauthorized: false
+ }
+ },
+ function(error, resp, body) {
+ if (error) {
+ console.log(error);
+ res.status(400).send(error.message);
+ }
+ else{
+ //console.log(body);
+ res.send({ data: body });
+ }
+ }
+ )
+ );
+
+});
+
app.use(function(error, req, res, next) {
res.status(500).send(error.message);
diff --git a/frontend/package-lock.json b/frontend/package-lock.json
index c78cb80..d9a0f31 100644
--- a/frontend/package-lock.json
+++ b/frontend/package-lock.json
@@ -1,5 +1,5 @@
{
- "name": "coligo-object-detection",
+ "name": "codeengine-image-classification",
"version": "1.0.0",
"lockfileVersion": 1,
"requires": true,
diff --git a/frontend/package.json b/frontend/package.json
index 8c4c393..b639573 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -1,7 +1,7 @@
{
- "name": "coligo-object-detection",
+ "name": "codeengine-image-classification",
"version": "1.0.0",
- "description": "Image Classification with Coligo and Watson Visual Recognition",
+ "description": "Image Classification with Code Engine and Watson Visual Recognition",
"main": "app.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
diff --git a/frontend/public/501.html b/frontend/public/501.html
index 25e506a..8f2341a 100644
--- a/frontend/public/501.html
+++ b/frontend/public/501.html
@@ -4,7 +4,7 @@
-
Image classification with Coligo and Watson Visual Recognition
+ Image classification with Code Engine
- Image Classification with Coligo
+ Image Classification with Code Engine
@@ -36,13 +36,14 @@
@@ -50,8 +51,8 @@
diff --git a/frontend/public/css/style.css b/frontend/public/css/style.css
index d841fdd..dfb2d3e 100644
--- a/frontend/public/css/style.css
+++ b/frontend/public/css/style.css
@@ -23,12 +23,162 @@ body {
inset 7px 7px 20px 0 rgba(0, 0, 0, 0.2);
}
-.card {
- border-radius: 9px;
- background: #eaf1f3;
- box-shadow: 5px 5px 8px #bec3c5, -5px -5px 8px #ffffff;
-}
-
.tag, .table{
font-family: 'IBM Plex Mono';
+}
+
+button {
+ margin-left:15px;
+}
+
+.card-footer-item {
+ white-space: nowrap;
+ overflow: hidden;
+ display: block;
+ text-overflow: ellipsis;
+}
+
+/*Loader*/
+.loader-wrapper {
+ position: absolute;
+ top: 0;
+ left: 0;
+ height: 100%;
+ width: 100%;
+ background: #fff;
+ opacity: 0;
+ z-index: -1;
+ transition: opacity 0.3s;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ border-radius: 6px;
+}
+.loader-wrapper .loader {
+ height: 80px;
+ width: 80px;
+}
+.loader-wrapper.is-active {
+ opacity: 1;
+ z-index: 1;
+}
+.is-loading {
+ position: relative;
+}
+
+/*NOTIFICATION*/
+
+.notifications {
+ position: fixed;
+ z-index: 9999;
+ top: 75px;
+ right: 15px;
+ width: auto;
+}
+
+.notification {
+ position: relative;
+ top: 0;
+ min-width: 100px;
+ padding: 1rem 1.25rem 1rem 1.25rem;
+ transition: .3s;
+ text-align: center;
+ box-shadow: 0 2px 3px rgba(10, 10, 10, .1), 0 0 0 1px rgba(10, 10, 10, .1);
+}
+
+.notification:hover {
+ cursor: pointer;
+ transition: .3s;
+ box-shadow: 0 2px 3px rgba(10, 10, 10, .1), 0 0 0 1px rgba(10, 10, 10, .2);
+}
+
+@-webkit-keyframes slideInRight {
+ from {
+ visibility: visible;
+ -webkit-transform: translate3d(150%, 0, 0);
+ transform: translate3d(150%, 0, 0);
+ }
+
+ to {
+ -webkit-transform: translate3d(0, 0, 0);
+ transform: translate3d(0, 0, 0);
+ }
+}
+
+@keyframes slideInRight {
+ from {
+ visibility: visible;
+ -webkit-transform: translate3d(150%, 0, 0);
+ transform: translate3d(150%, 0, 0);
+ }
+
+ to {
+ -webkit-transform: translate3d(0, 0, 0);
+ transform: translate3d(0, 0, 0);
+ }
+}
+
+.slideInRight {
+ -webkit-animation-name: slideInRight;
+ animation-name: slideInRight;
+ -webkit-animation-duration: .3s;
+ animation-duration: .3s;
+ -webkit-animation-fill-mode: both;
+ animation-fill-mode: both;
+}
+
+@-webkit-keyframes slideOutRight {
+ from {
+ -webkit-transform: translate3d(0, 0, 0);
+ transform: translate3d(0, 0, 0);
+ }
+
+ to {
+ visibility: hidden;
+ -webkit-transform: translate3d(150%, 0, 0);
+ transform: translate3d(150%, 0, 0);
+ }
+}
+
+@keyframes slideOutRight {
+ from {
+ -webkit-transform: translate3d(0, 0, 0);
+ transform: translate3d(0, 0, 0);
+ }
+
+ to {
+ visibility: hidden;
+ -webkit-transform: translate3d(150%, 0, 0);
+ transform: translate3d(150%, 0, 0);
+ }
+}
+
+.slideOutRight {
+ -webkit-animation-name: slideOutRight;
+ animation-name: slideOutRight;
+ -webkit-animation-duration: .3s;
+ animation-duration: .3s;
+ -webkit-animation-fill-mode: both;
+ animation-fill-mode: both;
+}
+
+/*** LEGEND **/
+.fieldset{
+ background-color: #fff;
+ border-radius: 6px;
+ box-shadow: 0 0.5em 1em -0.125em rgba(10,10,10,.1), 0 0 0 1px rgba(10,10,10,.02);
+ color: #4a4a4a;
+ display: block;
+ padding: 1.25rem;
+ border: 1px solid #ccc
+}
+.fieldset > legend{
+ color: #363636;
+ display: block;
+ font-size: 1rem;
+ font-weight: 700;
+ background-color: #fff;
+ padding: 0 5px;
+ width: max-content;
+ border: 0 none
}
\ No newline at end of file
diff --git a/frontend/public/index.html b/frontend/public/index.html
index dad8ac6..e29495a 100644
--- a/frontend/public/index.html
+++ b/frontend/public/index.html
@@ -4,7 +4,7 @@
-
Image classification with Coligo and Watson Visual Recognition
+
Image classification with Code Engine
-
-
+
-
+