/** * QUIXZOOM Weak Supervision API * * Endpoints: * POST /api/detect — Detektera objekt i bild * POST /api/detect/batch — Batch-detektion * GET /api/models — Lista tillgängliga modeller * GET /api/stats — Statistik */ const express = require('express'); const WeakSupervisionPipeline = require('../weak-supervision/pipeline'); const fs = require('fs'); const path = require('path'); class WeakSupervisionAPI { constructor(port = 3002) { this.app = express(); this.pipeline = new WeakSupervisionPipeline({ confidenceThreshold: 0.3, iouThreshold: 0.5, }); this.port = port; this.stats = { totalRequests: 0, totalImages: 0, totalDetections: 0, avgLatency: 0, }; this.setupRoutes(); } setupRoutes() { this.app.use(express.json({ limit: '50mb' })); // Health check this.app.get('/health', (req, res) => { res.json({ status: 'ok', service: 'weak-supervision' }); }); // Detektera en bild this.app.post('/api/detect', async (req, res) => { const start = Date.now(); try { const { imagePath, imageBase64 } = req.body; let filePath = imagePath; // Om base64, spara till temporär fil if (imageBase64) { const buffer = Buffer.from(imageBase64, 'base64'); filePath = `/tmp/ws-${Date.now()}.jpg`; fs.writeFileSync(filePath, buffer); } if (!filePath || !fs.existsSync(filePath)) { return res.status(400).json({ error: 'Image not found' }); } const result = await this.pipeline.detect(filePath); // Uppdatera statistik this.stats.totalRequests++; this.stats.totalImages++; this.stats.totalDetections += result.consolidated.length; const latency = Date.now() - start; this.stats.avgLatency = (this.stats.avgLatency * (this.stats.totalRequests - 1) + latency) / this.stats.totalRequests; res.json({ success: true, latency: latency, detections: result.consolidated, rawResults: { yolo: result.modelResults.yolo?.length || 0, groundingDINO: result.modelResults.groundingDINO?.length || 0, sam2: result.modelResults.sam2?.length || 0, }, }); } catch (error) { res.status(500).json({ error: error.message }); } }); // Batch-detektion this.app.post('/api/detect/batch', async (req, res) => { const start = Date.now(); try { const { imagePaths } = req.body; if (!Array.isArray(imagePaths)) { return res.status(400).json({ error: 'imagePaths must be an array' }); } const results = []; for (const imagePath of imagePaths) { if (!fs.existsSync(imagePath)) { results.push({ path: imagePath, error: 'Not found' }); continue; } const result = await this.pipeline.detect(imagePath); results.push({ path: imagePath, detections: result.consolidated, }); this.stats.totalDetections += result.consolidated.length; } this.stats.totalRequests++; this.stats.totalImages += imagePaths.length; const latency = Date.now() - start; res.json({ success: true, latency, processed: imagePaths.length, results, }); } catch (error) { res.status(500).json({ error: error.message }); } }); // Lista modeller this.app.get('/api/models', (req, res) => { res.json({ models: [ { name: 'yolov8', available: this.pipeline.models.yolo.available, weight: 0.3 }, { name: 'groundingDINO', available: false, weight: 0.3 }, { name: 'sam2', available: false, weight: 0.2 }, { name: 'ocr', available: false, weight: 0.1 }, { name: 'depth', available: false, weight: 0.1 }, ], }); }); // Statistik this.app.get('/api/stats', (req, res) => { res.json({ ...this.stats, uptime: process.uptime(), }); }); } start() { this.app.listen(this.port, () => { console.log(`[WS API] Listening on port ${this.port}`); console.log(`[WS API] Endpoints:`); console.log(` POST /api/detect`); console.log(` POST /api/detect/batch`); console.log(` GET /api/models`); console.log(` GET /api/stats`); }); } } // Starta om detta är huvudfil if (require.main === module) { const api = new WeakSupervisionAPI(); api.start(); } module.exports = WeakSupervisionAPI;