bae705aa97
- 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
200 lines
6.7 KiB
JavaScript
200 lines
6.7 KiB
JavaScript
/**
|
|
* QUIXZOOM Replay Engine + UKG Integration
|
|
*
|
|
* Kopplar Replay Engine till Urban Knowledge Graph för:
|
|
* - Spela upp historiska händelser
|
|
* - Jämföra algoritm-versioner
|
|
* - Debugga i efterhand
|
|
*/
|
|
|
|
const ReplayEngine = require('./engine');
|
|
const UKG = require('../urban-knowledge-graph/ukg');
|
|
const ObjectIdentityPipeline = require('../identity-engine/pipeline');
|
|
const ChangeDetectionEngine = require('../change-detection/engine');
|
|
|
|
class UKGReplayIntegration {
|
|
constructor() {
|
|
this.ukg = new UKG();
|
|
this.oie = new ObjectIdentityPipeline();
|
|
this.changeDetection = new ChangeDetectionEngine();
|
|
this.replay = new ReplayEngine({ speed: 100 });
|
|
|
|
this.setupHandlers();
|
|
}
|
|
|
|
setupHandlers() {
|
|
// Zoomer startar
|
|
this.replay.registerHandler('zoomer_started', async (payload) => {
|
|
console.log(` → Zoomer ${payload.zoomerId} started`);
|
|
return { status: 'recording' };
|
|
});
|
|
|
|
// Observation skapad
|
|
this.replay.registerHandler('observation_created', async (payload, context) => {
|
|
console.log(` → Observation: ${payload.objectType}`);
|
|
|
|
// Kör genom OIE
|
|
const identityResult = await this.oie.process({
|
|
id: payload.observationId,
|
|
objectType: payload.objectType,
|
|
location: payload.location,
|
|
timestamp: payload.timestamp,
|
|
attributes: payload.attributes,
|
|
});
|
|
|
|
return {
|
|
observationId: payload.observationId,
|
|
identityAction: identityResult.action,
|
|
objectId: identityResult.objectId,
|
|
};
|
|
});
|
|
|
|
// Identity matchad
|
|
this.replay.registerHandler('identity_matched', async (payload, context) => {
|
|
console.log(` → Identity: ${payload.objectId} (${(payload.confidence * 100).toFixed(0)}%)`);
|
|
|
|
// Hämta föregående observation
|
|
const previousObs = this.findPreviousObservation(payload.objectId);
|
|
const currentObs = this.findObservation(payload.observationId);
|
|
|
|
if (previousObs && currentObs) {
|
|
// Kör change detection
|
|
const changes = this.changeDetection.detectChanges(
|
|
payload.objectId,
|
|
currentObs,
|
|
previousObs
|
|
);
|
|
|
|
return {
|
|
objectId: payload.objectId,
|
|
confidence: payload.confidence,
|
|
changes: changes.changes,
|
|
severity: changes.severity,
|
|
};
|
|
}
|
|
|
|
return { objectId: payload.objectId, confidence: payload.confidence };
|
|
});
|
|
|
|
// Evidence tillagd
|
|
this.replay.registerHandler('evidence_added', async (payload) => {
|
|
console.log(` → Evidence: ${payload.evidenceType}`);
|
|
|
|
// Lägg till i UKG
|
|
this.ukg.addEvidence(payload.objectId, {
|
|
id: payload.evidenceId,
|
|
type: payload.evidenceType,
|
|
source: payload.source,
|
|
timestamp: payload.timestamp,
|
|
});
|
|
|
|
return { evidenceId: payload.evidenceId };
|
|
});
|
|
|
|
// Kunskapsgap upptäckt
|
|
this.replay.registerHandler('knowledge_gap_detected', async (payload) => {
|
|
console.log(` → Gap: ${payload.gapType} (priority: ${payload.priority})`);
|
|
|
|
// Skapa uppdrag
|
|
const mission = {
|
|
id: `mission_${Date.now()}`,
|
|
type: 'verify',
|
|
target: payload.objectId,
|
|
gapType: payload.gapType,
|
|
priority: payload.priority,
|
|
};
|
|
|
|
return { mission };
|
|
});
|
|
|
|
// Uppdrag skapat
|
|
this.replay.registerHandler('mission_created', async (payload) => {
|
|
console.log(` → Mission: ${payload.missionType}`);
|
|
return { missionId: payload.missionId };
|
|
});
|
|
|
|
// Instruktion skickad
|
|
this.replay.registerHandler('instruction_sent', async (payload) => {
|
|
console.log(` → Instruction: "${payload.instruction}"`);
|
|
return { sent: true };
|
|
});
|
|
}
|
|
|
|
findPreviousObservation(objectId) {
|
|
// Hämta senaste observation för objektet
|
|
// Förenklad implementation
|
|
return null;
|
|
}
|
|
|
|
findObservation(observationId) {
|
|
// Hämta observation
|
|
// Förenklad implementation
|
|
return null;
|
|
}
|
|
|
|
async replayEvents(events) {
|
|
console.log('=== UKG REPLAY INTEGRATION ===\n');
|
|
|
|
this.replay.loadEvents(events);
|
|
await this.replay.play();
|
|
|
|
console.log('\n=== REPLAY COMPLETE ===');
|
|
console.log('Stats:', this.replay.getStats());
|
|
|
|
return this.replay.results;
|
|
}
|
|
|
|
async compareAlgorithms(events, versionA, versionB) {
|
|
console.log('=== ALGORITHM COMPARISON ===\n');
|
|
|
|
const comparison = await this.replay.compareVersions(
|
|
events,
|
|
versionA.handlers,
|
|
versionB.handlers
|
|
);
|
|
|
|
console.log('\nComparison:');
|
|
console.log(` Total events: ${comparison.comparison.totalEvents}`);
|
|
console.log(` Differences: ${comparison.comparison.differences}`);
|
|
console.log(` Difference rate: ${comparison.comparison.differenceRate}`);
|
|
|
|
if (comparison.comparison.differences > 0) {
|
|
console.log('\n Details:');
|
|
for (const diff of comparison.comparison.details.slice(0, 5)) {
|
|
console.log(` [${diff.index}] ${diff.type}:`);
|
|
console.log(` A: ${JSON.stringify(diff.versionA)}`);
|
|
console.log(` B: ${JSON.stringify(diff.versionB)}`);
|
|
}
|
|
}
|
|
|
|
return comparison;
|
|
}
|
|
}
|
|
|
|
// Exportera
|
|
module.exports = UKGReplayIntegration;
|
|
|
|
// Demo
|
|
if (require.main === module) {
|
|
const integration = new UKGReplayIntegration();
|
|
|
|
// Skapa scenario
|
|
const baseTime = Date.now();
|
|
const events = [
|
|
{ id: 'evt_001', type: 'zoomer_started', timestamp: baseTime, payload: { zoomerId: 'zoomer_00001' } },
|
|
{ id: 'evt_002', type: 'observation_created', timestamp: baseTime + 6000, payload: { observationId: 'obs_001', objectType: 'street_lamp', location: { lat: 13.725, lng: 100.555 }, timestamp: baseTime + 6000, attributes: { material: 'steel', height: 7.8, rust: false } } },
|
|
{ id: 'evt_003', type: 'identity_matched', timestamp: baseTime + 7000, payload: { observationId: 'obs_001', objectId: 'street_lamp_000001', confidence: 0.94 } },
|
|
{ id: 'evt_004', type: 'evidence_added', timestamp: baseTime + 7000, payload: { evidenceType: 'image', evidenceId: 'ev_001', objectId: 'street_lamp_000001', source: 'zoomer_00001' } },
|
|
{ id: 'evt_005', type: 'knowledge_gap_detected', timestamp: baseTime + 8000, payload: { gapType: 'angle', gapId: 'gap_001', objectId: 'street_lamp_000001', priority: 'medium' } },
|
|
{ id: 'evt_006', type: 'mission_created', timestamp: baseTime + 9000, payload: { missionType: 'verify_angle', missionId: 'mission_001' } },
|
|
{ id: 'evt_007', type: 'instruction_sent', timestamp: baseTime + 10000, payload: { instruction: 'Gå två meter närmare' } },
|
|
];
|
|
|
|
integration.replayEvents(events).then(() => {
|
|
console.log('\n=== UKG STATE ===');
|
|
console.log(`Objects: ${integration.ukg.objects.size}`);
|
|
console.log(`Observations: ${integration.ukg.observations.size}`);
|
|
console.log(`Evidence: ${integration.ukg.evidence.size}`);
|
|
});
|
|
}
|