|
@@ -3,6 +3,7 @@ import { CommonModule } from '@angular/common';
|
|
|
import { ImageProcessorService } from '../../services/image-processor.service';
|
|
import { ImageProcessorService } from '../../services/image-processor.service';
|
|
|
import { LocalInferenceService } from '../../services/local-inference.service';
|
|
import { LocalInferenceService } from '../../services/local-inference.service';
|
|
|
import { LocalHistoryService } from '../../services/local-history.service';
|
|
import { LocalHistoryService } from '../../services/local-history.service';
|
|
|
|
|
+import { InferenceService } from '../../core/services/inference.service';
|
|
|
import { FormsModule } from '@angular/forms';
|
|
import { FormsModule } from '@angular/forms';
|
|
|
|
|
|
|
|
@Component({
|
|
@Component({
|
|
@@ -24,7 +25,7 @@ export class AnalyzerComponent implements OnInit {
|
|
|
|
|
|
|
|
constructor(
|
|
constructor(
|
|
|
private imageProcessor: ImageProcessorService,
|
|
private imageProcessor: ImageProcessorService,
|
|
|
- private localInference: LocalInferenceService,
|
|
|
|
|
|
|
+ public inferenceService: InferenceService,
|
|
|
private localHistory: LocalHistoryService
|
|
private localHistory: LocalHistoryService
|
|
|
) {}
|
|
) {}
|
|
|
|
|
|
|
@@ -76,75 +77,57 @@ export class AnalyzerComponent implements OnInit {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
async analyze(): Promise<void> {
|
|
async analyze(): Promise<void> {
|
|
|
- if (!this.selectedFile) return;
|
|
|
|
|
|
|
+ if (!this.selectedFile || !this.previewUrl) return;
|
|
|
|
|
|
|
|
this.loading = true;
|
|
this.loading = true;
|
|
|
const start = performance.now();
|
|
const start = performance.now();
|
|
|
|
|
|
|
|
try {
|
|
try {
|
|
|
- // 1. Path Mapping: ONNX for industry, TFLite (Float32) for standard PoC
|
|
|
|
|
- const modelPath = this.modelType === 'onnx'
|
|
|
|
|
- ? 'assets/models/onnx/best.onnx'
|
|
|
|
|
- : 'assets/models/tflite/best_float32.tflite';
|
|
|
|
|
-
|
|
|
|
|
- await this.localInference.loadModel(modelPath);
|
|
|
|
|
-
|
|
|
|
|
- // Get original image dimensions to pass to the parser
|
|
|
|
|
|
|
+ // Get image dimensions
|
|
|
const img = await this.loadImageDimensions(this.selectedFile);
|
|
const img = await this.loadImageDimensions(this.selectedFile);
|
|
|
|
|
|
|
|
- // 2. Preprocess the image to Float32Array [1, 3, 640, 640]
|
|
|
|
|
- const imageData = await this.imageProcessor.processImage(this.selectedFile);
|
|
|
|
|
-
|
|
|
|
|
- // 3. Run Inference locally
|
|
|
|
|
- const rawData = await this.localInference.runInference(imageData);
|
|
|
|
|
-
|
|
|
|
|
- if (!rawData) {
|
|
|
|
|
- throw new Error("Inference failed to produce data.");
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // 4. Decode Tensor -> Detections
|
|
|
|
|
- const detections = this.localInference.parseDetections(
|
|
|
|
|
- rawData,
|
|
|
|
|
- this.confidence,
|
|
|
|
|
- img.width,
|
|
|
|
|
- img.height
|
|
|
|
|
- );
|
|
|
|
|
-
|
|
|
|
|
- // 5. Calculate Industrial Summary - Updated to match new categories
|
|
|
|
|
- const summary: any = {
|
|
|
|
|
- 'Empty_Bunch': 0,
|
|
|
|
|
- 'Underripe': 0,
|
|
|
|
|
- 'Abnormal': 0,
|
|
|
|
|
- 'Ripe': 0,
|
|
|
|
|
- 'Unripe': 0,
|
|
|
|
|
- 'Overripe': 0
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- detections.forEach((d: any) => {
|
|
|
|
|
- if (summary[d.class] !== undefined) summary[d.class]++;
|
|
|
|
|
|
|
+ // Use the Master Inference Service Hub
|
|
|
|
|
+ this.inferenceService.analyze(this.previewUrl, img.width, img.height).subscribe({
|
|
|
|
|
+ next: (detections) => {
|
|
|
|
|
+ // Calculate Industrial Summary
|
|
|
|
|
+ const summary: any = {
|
|
|
|
|
+ 'Empty_Bunch': 0,
|
|
|
|
|
+ 'Underripe': 0,
|
|
|
|
|
+ 'Abnormal': 0,
|
|
|
|
|
+ 'Ripe': 0,
|
|
|
|
|
+ 'Unripe': 0,
|
|
|
|
|
+ 'Overripe': 0
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ detections.forEach((d: any) => {
|
|
|
|
|
+ if (summary[d.class] !== undefined) summary[d.class]++;
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ this.results = {
|
|
|
|
|
+ industrial_summary: summary,
|
|
|
|
|
+ inference_ms: performance.now() - start,
|
|
|
|
|
+ detections: detections
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ // Persist to local vault
|
|
|
|
|
+ this.localHistory.saveRecord(
|
|
|
|
|
+ this.results,
|
|
|
|
|
+ this.selectedFile!.name,
|
|
|
|
|
+ this.inferenceService.mode(),
|
|
|
|
|
+ this.previewUrl!,
|
|
|
|
|
+ img
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+ this.loading = false;
|
|
|
|
|
+ setTimeout(() => this.drawDetections(), 100);
|
|
|
|
|
+ },
|
|
|
|
|
+ error: (err) => {
|
|
|
|
|
+ console.error('Analysis Failed:', err);
|
|
|
|
|
+ this.loading = false;
|
|
|
|
|
+ }
|
|
|
});
|
|
});
|
|
|
-
|
|
|
|
|
- this.results = {
|
|
|
|
|
- industrial_summary: summary,
|
|
|
|
|
- inference_ms: performance.now() - start,
|
|
|
|
|
- detections: detections
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- // PERSIST TO LOCAL VAULT
|
|
|
|
|
- this.localHistory.saveRecord(
|
|
|
|
|
- this.results,
|
|
|
|
|
- this.selectedFile!.name,
|
|
|
|
|
- this.modelType,
|
|
|
|
|
- this.previewUrl!,
|
|
|
|
|
- img
|
|
|
|
|
- );
|
|
|
|
|
-
|
|
|
|
|
- console.log('Backend-less PoC: Parsed Detections:', detections);
|
|
|
|
|
-
|
|
|
|
|
- this.loading = false;
|
|
|
|
|
- setTimeout(() => this.drawDetections(), 100);
|
|
|
|
|
} catch (err) {
|
|
} catch (err) {
|
|
|
- console.error('Local Analysis Failed:', err);
|
|
|
|
|
|
|
+ console.error('Processing Pipeline Error:', err);
|
|
|
this.loading = false;
|
|
this.loading = false;
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|