Files
boc/quixzoom-capture-pipeline/uios/uios.js
T
Bernt bae705aa97 ARCHITECTURE: NFC roadmap, edge AI, audit logging
- Add NFC ePassport roadmap (ICAO 9303, eIDAS)
- Add TensorFlow.js edge face detection (BlazeFace)
- Add structured audit logger (GDPR-compliant)
- Risk scoring support

Part of KYC Apple Native UX v1.1.0
2026-06-29 16:24:48 +00:00

716 lines
18 KiB
JavaScript

/**
* 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));
});
}