/** * QUIXZOOM Urban Intelligence Operating System (UIOS) * * Central styrning för hela QUIXZOOM: * - Data Collection Engine * - Mission Planner * - Active Learning Engine * - Urban Knowledge Graph * - Object Identity Engine * - Change Detection Engine * - Dataset Manager * - Model Registry * - Training Pipeline * - Deployment Manager * - Analytics & Customer API * * Ett komplett operativsystem för kontinuerlig insamling, * förståelse och uppdatering av information om den byggda miljön. */ const ObjectIdentityPipeline = require('../identity-engine/pipeline'); const ObjectIdentityPipelineV4 = require('../identity-engine/pipeline-v4'); const ChangeDetectionEngine = require('../change-detection/engine'); const UrbanFoundationDatasetManager = require('../dataset-manager/manager'); const UrbanIntelligenceMissionPlanner = require('../mission-planner/planner'); const WeakSupervisionPipeline = require('../weak-supervision/pipeline'); // Placeholder-klasser för moduler som inte finns än class ActiveLearningEngine { constructor() { this.status = 'ready'; } } class ShadowDeploymentManager { constructor() { this.deployments = new Map(); } async shadowDeploy(modelId) { console.log(`[Shadow] Deploying ${modelId}`); this.deployments.set(modelId, { mode: 'shadow', traffic: 0.1 }); } async promote(modelId) { const d = this.deployments.get(modelId); if (d) { d.mode = 'production'; d.traffic = 1.0; } } } class UrbanIntelligenceOperatingSystem { constructor(config = {}) { this.config = { version: '1.0.0', environment: config.environment || 'development', ...config, }; // Lager this.layers = { // Lager 1: Datainsamling dataCollection: { captureEngine: null, qualityControl: null, }, // Lager 2: Intelligens intelligence: { missionPlanner: new UrbanIntelligenceMissionPlanner(), activeLearning: new ActiveLearningEngine(), weakSupervision: new WeakSupervisionPipeline(), }, // Lager 3: Kunskap knowledge: { ukg: new UrbanKnowledgeGraph(), oie: new ObjectIdentityPipelineV4(), changeDetection: new ChangeDetectionEngine(), }, // Lager 4: Data data: { datasetManager: new UrbanFoundationDatasetManager(), modelRegistry: new ModelRegistry(), }, // Lager 5: Drift operations: { trainingPipeline: new TrainingPipeline(), deploymentManager: new ShadowDeploymentManager(), }, // Lager 6: API api: { analytics: new AnalyticsEngine(), customerAPI: new CustomerAPI(), }, }; // Learning Queue this.learningQueue = new LearningQueue(); // Event bus this.events = new EventBus(); // Status this.status = 'initializing'; this.startTime = Date.now(); } async initialize() { console.log('[UIOS] Initializing Urban Intelligence Operating System...'); console.log(`[UIOS] Version: ${this.config.version}`); console.log(`[UIOS] Environment: ${this.config.environment}`); // Initiera alla lager await this.initializeLayers(); // Starta event listeners this.setupEventListeners(); // Starta looper this.startLoops(); this.status = 'running'; console.log('[UIOS] System ready\n'); return this.getStatus(); } async initializeLayers() { // Lager 1: Datainsamling console.log('[UIOS] Layer 1: Data Collection'); // Lager 2: Intelligens console.log('[UIOS] Layer 2: Intelligence'); // Lager 3: Kunskap console.log('[UIOS] Layer 3: Knowledge'); // Lager 4: Data console.log('[UIOS] Layer 4: Data'); // Lager 5: Drift console.log('[UIOS] Layer 5: Operations'); // Lager 6: API console.log('[UIOS] Layer 6: API'); } setupEventListeners() { // Observation insamlad this.events.on('observation:captured', async (data) => { await this.handleObservation(data); }); // Mission skapad this.events.on('mission:created', async (data) => { await this.handleMission(data); }); // Modell tränad this.events.on('model:trained', async (data) => { await this.handleModelTrained(data); }); // Coverage uppdaterad this.events.on('coverage:updated', async (data) => { await this.handleCoverageUpdate(data); }); } startLoops() { // Active Learning Loop (var 5:e minut) setInterval(() => this.activeLearningLoop(), 5 * 60 * 1000); // Mission Generation Loop (var 15:e minut) setInterval(() => this.missionGenerationLoop(), 15 * 60 * 1000); // Quality Control Loop (varje minut) setInterval(() => this.qualityControlLoop(), 60 * 1000); // Model Evaluation Loop (varje timme) setInterval(() => this.modelEvaluationLoop(), 60 * 60 * 1000); } /** * ============================================================ * ACTIVE LEARNING LOOP * ============================================================ */ async activeLearningLoop() { console.log('[UIOS] Active Learning Loop...'); // 1. Hämta osäkra observationer const uncertainObservations = this.learningQueue.getUncertain(); // 2. Generera missions const missions = this.layers.intelligence.missionPlanner.generateMissions( uncertainObservations.map(o => o.cityId) ); // 3. Tilldela till Zoomers for (const mission of missions) { this.events.emit('mission:created', mission); } // 4. Uppdatera modell if (this.shouldRetrain()) { await this.retrainModel(); } console.log(`[UIOS] Generated ${missions.length} missions`); } async missionGenerationLoop() { console.log('[UIOS] Mission Generation Loop...'); for (const city of this.layers.data.datasetManager.listReferenceCities()) { const report = this.layers.data.datasetManager.getCoverageReport(city.id); if (report.gaps.length > 0) { const missions = this.layers.intelligence.missionPlanner.generateMissions(city.id); for (const mission of missions) { this.learningQueue.add({ type: 'mission', priority: this.calculatePriority(mission), data: mission, }); } } } } calculatePriority(mission) { const score = mission.score?.total || 0; if (score > 80) return 1; // Kritisk if (score > 50) return 2; // Viktig return 3; // Normal } async qualityControlLoop() { console.log('[UIOS] Quality Control Loop...'); // Kontrollera nyligen insamlade observationer const recent = this.learningQueue.getRecent(100); for (const obs of recent) { const quality = this.assessQuality(obs); if (quality < 0.5) { // Låg kvalitet — begär om this.events.emit('quality:low', { observation: obs, quality }); } } } assessQuality(observation) { let score = 1.0; // GPS-accuracy if (observation.gpsAccuracy > 10) score *= 0.8; if (observation.gpsAccuracy > 50) score *= 0.5; // Bildkvalitet if (observation.quality) { if (observation.quality.blur > 0.5) score *= 0.7; if (observation.quality.exposure < 0.3) score *= 0.8; } // Täckning if (!observation.attributes || Object.keys(observation.attributes).length === 0) { score *= 0.9; } return score; } async modelEvaluationLoop() { console.log('[UIOS] Model Evaluation Loop...'); const registry = this.layers.data.modelRegistry; const models = registry.listModels(); for (const model of models) { if (model.status === 'deployed') { const metrics = await registry.evaluateModel(model.id); // Jämför med föregående version const previous = registry.getPreviousVersion(model.id); if (previous) { const improvement = this.calculateImprovement(metrics, previous.metrics); if (improvement > 0.05) { // Signifikant förbättring this.events.emit('model:improved', { model, improvement }); } } } } } calculateImprovement(current, previous) { if (!previous) return 0; return (current.mAP - previous.mAP) / previous.mAP; } /** * ============================================================ * HÄNDELSEHANTERING * ============================================================ */ async handleObservation(data) { console.log(`[UIOS] Observation captured: ${data.id}`); // 1. Kvalitetskontroll const quality = this.assessQuality(data); // 2. Object Identity Engine const identity = await this.layers.knowledge.oie.process(data); // 3. Urban Knowledge Graph await this.layers.knowledge.ukg.addObservation(data, identity); // 4. Change Detection let changes = []; try { if (typeof this.layers.knowledge.changeDetection.detectChanges === 'function') { const prevObs = this.layers.knowledge.ukg.objects.get(identity.objectId)?.observations?.slice(-2, -1)[0]; changes = this.layers.knowledge.changeDetection.detectChanges( identity.objectId, data, prevObs ); } } catch (e) { // Change detection not available } if (changes && changes.length > 0) { this.events.emit('change:detected', { observation: data, changes }); } // 5. Lägg till Learning Queue this.learningQueue.add({ type: 'observation', priority: quality > 0.8 ? 3 : 2, data: { ...data, quality, identity }, }); // 6. Uppdatera coverage this.layers.data.datasetManager.updateCoverage(data.cityId, data.objectType, { found: 1, }); } async handleMission(data) { console.log(`[UIOS] Mission created: ${data.id}`); // Tilldela till Zoomer const assignment = await this.assignZoomer(data); if (assignment) { console.log(`[UIOS] Assigned to Zoomer: ${assignment.zoomerId}`); } } async handleModelTrained(data) { console.log(`[UIOS] Model trained: ${data.modelId}`); // Registrera i Model Registry this.layers.data.modelRegistry.registerModel({ id: data.modelId, datasetVersion: data.datasetVersion, metrics: data.metrics, }); // Shadow deployment await this.layers.operations.deploymentManager.shadowDeploy(data.modelId); } async handleCoverageUpdate(data) { console.log(`[UIOS] Coverage updated: ${data.cityId} / ${data.category}`); // Generera missions om gap upptäcks const report = this.layers.data.datasetManager.getCoverageReport(data.cityId); for (const gap of report.gaps) { if (gap.severity === 'critical') { this.events.emit('gap:critical', { cityId: data.cityId, gap }); } } } /** * ============================================================ * API * ============================================================ */ getStatus() { return { version: this.config.version, status: this.status, uptime: Date.now() - this.startTime, layers: { dataCollection: 'active', intelligence: 'active', knowledge: 'active', data: 'active', operations: 'active', api: 'active', }, stats: { observationsProcessed: this.learningQueue.stats.observations, missionsGenerated: this.learningQueue.stats.missions, modelsTrained: this.layers.data.modelRegistry.getModelCount(), cities: this.layers.data.datasetManager.listReferenceCities().length, }, }; } async getAnalytics(cityId) { const city = this.layers.data.datasetManager.getReferenceCity(cityId); if (!city) return null; return { city: city.name, coverage: this.layers.data.datasetManager.getCoverageReport(cityId), missions: this.layers.intelligence.missionPlanner.getTopMissions(cityId, 10), models: this.layers.data.modelRegistry.getModelsForCity(cityId), }; } async processObservation(observation) { return this.handleObservation(observation); } async generateMissions(cityId) { return this.layers.intelligence.missionPlanner.generateMissions(cityId); } } /** * ============================================================ * HJÄLPKLASSER * ============================================================ */ class LearningQueue { constructor() { this.queue = []; this.processed = []; this.stats = { observations: 0, missions: 0 }; } add(item) { this.queue.push({ ...item, addedAt: Date.now(), }); if (item.type === 'observation') this.stats.observations++; if (item.type === 'mission') this.stats.missions++; // Sortera efter prioritet this.queue.sort((a, b) => a.priority - b.priority); } getUncertain() { return this.queue.filter(item => item.type === 'observation' && item.data.quality < 0.7 ); } getRecent(count) { return this.queue .filter(item => item.type === 'observation') .slice(-count); } getNext() { return this.queue.shift(); } } class EventBus { constructor() { this.listeners = new Map(); } on(event, handler) { if (!this.listeners.has(event)) { this.listeners.set(event, []); } this.listeners.get(event).push(handler); } emit(event, data) { const handlers = this.listeners.get(event); if (handlers) { handlers.forEach(handler => handler(data)); } } } class UrbanKnowledgeGraph { constructor() { this.objects = new Map(); this.relations = new Map(); } async addObservation(observation, identity) { // Lägg till i UKG const objectId = identity.objectId; if (!this.objects.has(objectId)) { this.objects.set(objectId, { id: objectId, type: observation.objectType, observations: [], relations: [], }); } const obj = this.objects.get(objectId); obj.observations.push(observation.id); // Skapa relationer await this.createRelations(objectId, observation); } async createRelations(objectId, observation) { // Hitta närliggande objekt const nearby = Array.from(this.objects.values()).filter(obj => { if (obj.id === objectId) return false; const dist = this.calculateDistance( observation.location, obj.location ); return dist < 50; // 50 meter }); for (const near of nearby) { this.relations.set(`${objectId}-${near.id}`, { from: objectId, to: near.id, type: 'nearby', distance: this.calculateDistance(observation.location, near.location), }); } } calculateDistance(loc1, loc2) { const R = 6371000; const dLat = (loc2.lat - loc1.lat) * Math.PI / 180; const dLon = (loc2.lng - loc1.lng) * Math.PI / 180; const a = Math.sin(dLat/2) * Math.sin(dLat/2) + Math.cos(loc1.lat * Math.PI / 180) * Math.cos(loc2.lat * Math.PI / 180) * Math.sin(dLon/2) * Math.sin(dLon/2); return R * 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a)); } } class ModelRegistry { constructor() { this.models = new Map(); this.versions = new Map(); } registerModel(model) { this.models.set(model.id, { ...model, registeredAt: new Date().toISOString(), status: 'registered', }); } listModels() { return Array.from(this.models.values()); } getModelCount() { return this.models.size; } getPreviousVersion(modelId) { const model = this.models.get(modelId); if (!model) return null; // Hitta föregående version const versions = Array.from(this.models.values()) .filter(m => m.name === model.name && m.id !== modelId) .sort((a, b) => new Date(b.registeredAt) - new Date(a.registeredAt)); return versions[0] || null; } async evaluateModel(modelId) { // Mock evaluation return { mAP: 0.85 + Math.random() * 0.1, precision: 0.88 + Math.random() * 0.08, recall: 0.82 + Math.random() * 0.1, latency: 15 + Math.random() * 10, }; } getModelsForCity(cityId) { return Array.from(this.models.values()) .filter(m => m.cityId === cityId); } } class TrainingPipeline { constructor() { this.status = 'idle'; } async train(config) { this.status = 'training'; console.log('[Training] Starting training...'); // Mock training await new Promise(resolve => setTimeout(resolve, 1000)); this.status = 'completed'; return { modelId: `model_${Date.now()}`, metrics: { mAP: 0.87, precision: 0.89, recall: 0.85, }, }; } } class DeploymentManager { constructor() { this.deployments = new Map(); } async shadowDeploy(modelId) { console.log(`[Deploy] Shadow deploying: ${modelId}`); this.deployments.set(modelId, { modelId, mode: 'shadow', startedAt: new Date().toISOString(), traffic: 0.1, // 10% traffic }); } async promote(modelId) { console.log(`[Deploy] Promoting: ${modelId}`); const deployment = this.deployments.get(modelId); if (deployment) { deployment.mode = 'production'; deployment.traffic = 1.0; } } } class AnalyticsEngine { constructor() { this.metrics = new Map(); } track(event, data) { if (!this.metrics.has(event)) { this.metrics.set(event, []); } this.metrics.get(event).push({ timestamp: Date.now(), data, }); } getMetrics(event) { return this.metrics.get(event) || []; } } class CustomerAPI { constructor() { this.requests = new Map(); } async createRequest(customerId, requirements) { const request = { id: `req_${Date.now()}`, customerId, requirements, status: 'open', createdAt: new Date().toISOString(), }; this.requests.set(request.id, request); return request; } async getRequest(requestId) { return this.requests.get(requestId); } } module.exports = UrbanIntelligenceOperatingSystem; // Demo if (require.main === module) { const uios = new UrbanIntelligenceOperatingSystem(); uios.initialize().then(status => { console.log('\n=== UIOS STATUS ==='); console.log(JSON.stringify(status, null, 2)); }); }