This commit is contained in:
Ibnu Naz'm Ar-rosyid
2025-07-18 20:05:17 +07:00
commit bea44c1b7c
234 changed files with 5681 additions and 0 deletions

View File

@ -0,0 +1,63 @@
const tf = require('@tensorflow/tfjs-node');
const fs = require('fs');
const path = require('path');
// Path ke model
const modelPath = path.join(
__dirname,
'../resources/ResNet-50_tomato-leaf-disease-tfjs_v8/model.json'
);
let model;
// Fungsi untuk memuat model
const loadModel = async () => {
try {
model = await tf.loadLayersModel(`file://${modelPath}`);
console.log('Model loaded successfully.');
} catch (err) {
console.error('Error loading model:', err);
throw new Error('Model loading failed.');
}
};
// Memuat model saat aplikasi dimulai
loadModel();
const preprocessImage = async (imagePath) => {
const imageBuffer = fs.readFileSync(imagePath);
let tensor = tf.node.decodeImage(imageBuffer, 3);
tensor = tf.image.resizeBilinear(tensor, [224, 224]);
tensor = tensor.expandDims(0);
//tensor = tensor.toFloat().div(tf.scalar(255.0));
return tensor;
};
// Fungsi untuk mengklasifikasikan gambar
const classifyImage = async (imagePath) => {
try {
const classes = [
'bacterial_spot',
'healthy',
'late_blight',
'leaf_curl_virus',
'leaf_mold',
'mosaic_virus',
'septoria_leaf_spot',
];
const tensor = await preprocessImage(imagePath);
const predictions = model.predict(tensor);
const predictedClassIndex = predictions.argMax(-1).dataSync()[0];
// Ambil nama kelas berdasarkan indeks
const predictedClassName = classes[predictedClassIndex];
return { index: predictedClassIndex, class: predictedClassName };
} catch (err) {
console.error('Error during classification:', err);
throw new Error('Error during classification.');
}
};
module.exports = { classifyImage };

View File

@ -0,0 +1,63 @@
const tf = require('@tensorflow/tfjs-node');
const fs = require('fs');
const path = require('path');
// Path ke model
const modelPath = path.join(
__dirname,
'../resources/ResNet-50_tomato-leaf-disease-tfjs_v8/model.json'
);
let model;
// Fungsi untuk memuat model
const loadModel = async () => {
try {
model = await tf.loadLayersModel(`file://${modelPath}`);
console.log('Model loaded successfully.');
} catch (err) {
console.error('Error loading model:', err);
throw new Error('Model loading failed.');
}
};
// Memuat model saat aplikasi dimulai
loadModel();
const preprocessImage = async (imagePath) => {
const imageBuffer = fs.readFileSync(imagePath);
let tensor = tf.node.decodeImage(imageBuffer, 3);
tensor = tf.image.resizeBilinear(tensor, [224, 224]);
tensor = tensor.expandDims(0);
//tensor = tensor.toFloat().div(tf.scalar(255.0));
return tensor;
};
// Fungsi untuk mengklasifikasikan gambar
const classifyImage = async (imagePath) => {
try {
const classes = [
'bacterial_spot',
'healthy',
'late_blight',
'leaf_curl_virus',
'leaf_mold',
'mosaic_virus',
'septoria_leaf_spot',
];
const tensor = await preprocessImage(imagePath);
const predictions = model.predict(tensor);
const predictedClassIndex = predictions.argMax(-1).dataSync()[0];
// Ambil nama kelas berdasarkan indeks
const predictedClassName = classes[predictedClassIndex];
return { index: predictedClassIndex, class: predictedClassName };
} catch (err) {
console.error('Error during classification:', err);
throw new Error('Error during classification.');
}
};
module.exports = { classifyImage };

View File

@ -0,0 +1,61 @@
const tf = require('@tensorflow/tfjs-node');
const fs = require('fs');
const path = require('path');
// Path ke model
const modelPath = path.join(
__dirname,
'../resources/ResNet-50_tomato-leaf-disease-tfjs_nobg/model.json'
);
let model;
const loadModel = async () => {
try {
model = await tf.loadLayersModel(`file://${modelPath}`);
console.log('Model loaded successfully.');
} catch (err) {
console.error('Error loading model:', err);
throw new Error('Model loading failed.');
}
};
loadModel();
const preprocessImage = async (imagePath) => {
const imageBuffer = fs.readFileSync(imagePath);
let tensor = tf.node.decodeImage(imageBuffer, 3);
tensor = tf.image.resizeBilinear(tensor, [224, 224]);
tensor = tensor.expandDims(0);
//tensor = tensor.toFloat().div(tf.scalar(255.0));
return tensor;
};
// Fungsi untuk mengklasifikasikan gambar
const classifyImage = async (imagePath) => {
try {
const classes = [
'bacterial_spot',
'healthy',
'late_blight',
'leaf_curl_virus',
'leaf_mold',
'mosaic_virus',
'septoria_leaf_spot',
];
const tensor = await preprocessImage(imagePath);
const predictions = model.predict(tensor);
const predictedClassIndex = predictions.argMax(-1).dataSync()[0];
// Ambil nama kelas berdasarkan indeks
const predictedClassName = classes[predictedClassIndex];
return { index: predictedClassIndex, class: predictedClassName };
} catch (err) {
console.error('Error during classification:', err);
throw new Error('Error during classification.');
}
};
module.exports = { classifyImage };

View File

@ -0,0 +1,23 @@
function basicAuth(req, res, next) {
const authHeader = req.headers['authorization'];
if (!authHeader || !authHeader.startsWith('Basic ')) {
res.setHeader('WWW-Authenticate', 'Basic');
return res.status(401).send('Authentication required.');
}
const base64Credentials = authHeader.split(' ')[1];
const credentials = Buffer.from(base64Credentials, 'base64').toString('ascii');
const [username, password] = credentials.split(':');
const USERNAME = 'rahasia';
const PASSWORD = 'tomat';
if (username === USERNAME && password === PASSWORD) {
next();
} else {
return res.status(403).send('Access denied.');
}
}
module.exports = basicAuth;

18
Server/package.json Normal file
View File

@ -0,0 +1,18 @@
{
"dependencies": {
"@tensorflow/tfjs-node": "^4.8.0",
"express": "^4.21.2",
"multer": "^1.4.5-lts.1"
},
"name": "tomato_leaf_care",
"version": "1.0.0",
"main": "server.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "node server.js"
},
"keywords": [],
"author": "",
"license": "ISC",
"description": ""
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,13 @@
const express = require('express');
const router = express.Router();
router.get('/check', (req, res) => {
res.status(200).json({
status: 'ok',
message: 'Server is up and running',
timestamp: new Date().toISOString()
});
});
module.exports = router;

View File

@ -0,0 +1,31 @@
const express = require('express');
const multer = require('multer');
const fs = require('fs');
const path = require('path');
const { classifyImage } = require('../controllers/classificationController');
const router = express.Router();
const upload = multer({ dest: 'uploads/' });
router.post('/classify', upload.single('image'), async (req, res) => {
try {
if (!req.file) {
return res.status(400).json({ error: 'No image file uploaded' });
}
const imagePath = path.join(__dirname, `../${req.file.path}`);
const predictedClass = await classifyImage(imagePath);
fs.unlinkSync(imagePath);
res.json({
success: true,
predictedClass,
});
} catch (err) {
res.status(500).json({ error: err.message });
}
});
module.exports = router;

28
Server/server.js Normal file
View File

@ -0,0 +1,28 @@
const express = require("express");
const fs = require("fs");
const https = require("https");
const basicAuth = require("./middleware/authMiddleware")
const classificationRoutes = require("./routes/classificationRoute");
const checkRoutes = require("./routes/checkRoute");
const app = express();
const port = 8000;
//const sslOptions = {
// key: fs.readFileSync("./ssl/server.key"),
// cert: fs.readFileSync("./ssl/server.crt")
//};
app.use("/tomatoleafcare", basicAuth, classificationRoutes);
app.use("/tomatoleafcare", basicAuth, checkRoutes);
//https.createServer(sslOptions, app).listen(port, () => {
// console.log(`HTTPS Server is running on port ${port}...`);
//});
app.listen(port, () => {
console.log(`Server running on http://localhost:${port}`);
});