Initial commit — Mek-Tech AI Consultancy Framework v2.0
This commit is contained in:
@@ -0,0 +1,104 @@
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
const multer = require('multer');
|
||||
const http = require('http');
|
||||
|
||||
const QS_HOST = process.env.QS_HOST || 'python-quality';
|
||||
const QS_PORT = parseInt(process.env.QS_PORT || '3002');
|
||||
const SHARED_UPLOAD_DIR = path.join(__dirname, '..', 'data', 'uploads');
|
||||
if (!fs.existsSync(SHARED_UPLOAD_DIR)) fs.mkdirSync(SHARED_UPLOAD_DIR, { recursive: true });
|
||||
|
||||
const storage = multer.diskStorage({
|
||||
destination: (req, file, cb) => cb(null, SHARED_UPLOAD_DIR),
|
||||
filename: (req, file, cb) => cb(null, Date.now() + '-' + file.originalname)
|
||||
});
|
||||
const upload = multer({ storage, limits: { fileSize: 100 * 1024 * 1024 } });
|
||||
|
||||
function qsApi(path, method, body) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const opts = { hostname: QS_HOST, port: QS_PORT, path, method, headers: { 'Content-Type': 'application/json' }, timeout: 30000 };
|
||||
const req = http.request(opts, (res) => {
|
||||
let data = '';
|
||||
res.on('data', c => data += c);
|
||||
res.on('end', () => {
|
||||
if (method === 'GET' && res.statusCode >= 400) return reject(new Error('offline'));
|
||||
try { resolve(JSON.parse(data)); } catch(e) { resolve({ raw: data }); }
|
||||
});
|
||||
});
|
||||
req.on('error', (e) => reject(e));
|
||||
req.on('timeout', () => { req.destroy(); reject(new Error('timeout')); });
|
||||
if (body) req.write(JSON.stringify(body));
|
||||
req.end();
|
||||
});
|
||||
}
|
||||
|
||||
router.get('/', async (req, res) => {
|
||||
let files = [];
|
||||
let qsStatus = 'offline';
|
||||
let services = {};
|
||||
try {
|
||||
const dirFiles = fs.readdirSync(SHARED_UPLOAD_DIR).filter(f => f !== '.gitkeep');
|
||||
files = dirFiles.map(f => ({ file_id: f.split('.')[0], filename: f, size: fs.statSync(path.join(SHARED_UPLOAD_DIR, f)).size }));
|
||||
await qsApi('/python-quality/', 'GET');
|
||||
qsStatus = 'online';
|
||||
} catch (e) { qsStatus = 'offline'; }
|
||||
try {
|
||||
const { getServicesStatus } = require('../lib/services');
|
||||
services = await getServicesStatus();
|
||||
} catch (e) {}
|
||||
const { getDb } = require('../db');
|
||||
const clients = getDb().prepare('SELECT id, name FROM clients ORDER BY name').all();
|
||||
const clientId = req.query.client_id || req.session.activeClientId || null;
|
||||
res.render('quality-dashboard', { files, qsStatus, services, clients, clientId, uploaded: null, profile: null, report: null, error: null });
|
||||
});
|
||||
|
||||
router.post('/upload', upload.single('file'), async (req, res) => {
|
||||
if (!req.file) return res.redirect('/quality');
|
||||
try {
|
||||
const resp = await qsApi('/python-quality/api/profile', 'POST', { file_id: req.file.filename.split('.')[0], shared_path: path.join(SHARED_UPLOAD_DIR, req.file.filename) });
|
||||
const profile = resp.profile || resp;
|
||||
const uploaded = { file_id: req.file.filename.split('.')[0], original_name: req.file.originalname, rows: profile.rows, columns: profile.columns };
|
||||
res.render('quality-dashboard', { files: [], qsStatus: 'online', uploaded, profile, report: null, error: null });
|
||||
} catch (e) {
|
||||
res.render('quality-dashboard', { files: [], qsStatus: 'online', uploaded: null, profile: null, report: null, error: 'Kon bestand niet analyseren: ' + (e.message || 'onbekende fout') });
|
||||
}
|
||||
});
|
||||
|
||||
router.post('/quality-check/:fileId', async (req, res) => {
|
||||
try {
|
||||
const result = await qsApi('/python-quality/api/quality-check', 'POST', { file_id: req.params.fileId, checks: ['completeness', 'uniqueness', 'range', 'type'] });
|
||||
res.json(result);
|
||||
} catch (e) { res.status(500).json({ error: e.message }); }
|
||||
});
|
||||
|
||||
router.get('/profile/:fileId', async (req, res) => {
|
||||
try {
|
||||
const result = await qsApi('/python-quality/api/profile', 'POST', { file_id: req.params.fileId });
|
||||
res.json(result);
|
||||
} catch (e) { res.status(500).json({ error: e.message }); }
|
||||
});
|
||||
|
||||
router.get('/report/:reportId', async (req, res) => {
|
||||
try {
|
||||
const result = await qsApi('/python-quality/api/report/' + req.params.reportId, 'GET');
|
||||
res.json(result);
|
||||
} catch (e) { res.status(500).json({ error: e.message }); }
|
||||
});
|
||||
|
||||
router.post('/dbt/validate', async (req, res) => {
|
||||
try {
|
||||
const result = await qsApi('/python-quality/api/dbt/validate', 'POST', req.body);
|
||||
res.json(result);
|
||||
} catch (e) { res.status(500).json({ error: e.message }); }
|
||||
});
|
||||
|
||||
router.post('/dbt/test', async (req, res) => {
|
||||
try {
|
||||
const result = await qsApi('/python-quality/api/dbt/test', 'POST', req.body);
|
||||
res.json(result);
|
||||
} catch (e) { res.status(500).json({ error: e.message }); }
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
Reference in New Issue
Block a user