# Mimari — Hasarİ v2 Bu doküman ML pipeline'ın iç işleyişini, parça-merkezli çıktı reorganizasyonunu ve servisler arası kontratları açıklar. ## 1. ML Pipeline — Akıllı Hibrit Mimari Pipeline iki YOLO26-seg modelini **paralel** koşturur, sonra **akıllı eşleme** ile her hasarı doğru parçaya atar. ``` Görüntü │ ├──► Quality check (blur, exposure, vehicle present) │ ├──► [Paralel] Hasar modeli (YOLO26-seg, 6 sınıf) │ └─► damages: [{type, polygon, bbox, confidence}, ...] │ ├──► [Paralel] Parça modeli (YOLO26-seg, 23 sınıf) │ └─► parts: [{name, polygon, bbox, confidence}, ...] │ ├──► Akıllı eşleme (IoU + intersection_ratio) │ ├─ Hasar parçaya tam kaplı → tek parça │ ├─ Hasar iki+ parçaya yayılıyor → multi-part flag + affected_parts │ ├─ Düşük güven → is_low_confidence_match flag │ └─ Parça bulunamadı → primary_part = "unknown" │ ├──► Şiddet sınıflandırma (ensemble) │ ├─ Kural-tabanlı: maske alanı + hasar tipi + parça → hafif/orta/ağır │ ├─ CNN classifier: hasar bölgesi crop → 3-sınıf │ └─ Ensemble: ağırlıklı kombinasyon │ ├──► Maliyet motoru (kademeli lookup) │ ├─ (parça, hasar_tipi, şiddet) → range │ ├─ Aynı parçada çoklu hasar → en pahalı dominant │ └─ Toplam aggregation │ └──► Output formatter (parça-merkezli reorganizasyon) └─► JSON: { parts: [...], summary, multi_part_damages, visualization_urls } ``` ### Neden paralel + IoU eşleme? **Alternatif 1 — Kaskad (parça → her parçada hasar):** - ✅ Daha az false positive (sadece parça içi tarama) - ❌ Yavaş (her parça için ayrı inference) - ❌ İki parçaya yayılan hasarda problem (kapı↔çamurluk arası çizik) - ❌ Parça kaçırılırsa üzerindeki hasar da kaçar **Alternatif 2 — Naif paralel (her hasar en yakın parçaya):** - ✅ Hızlı, tek geçişte - ❌ Yanlış parça eşleme riski **Seçim — Akıllı paralel:** - Paralel hızını korur - IoU + intersection_ratio ile *doğru* eşleme yapar - Multi-part hasarı ayrı işaretler (bilgi kaybı yok) - Parça kaçırılsa bile hasar yine tespit edilir ("unknown" fallback) ### IoU eşleme kuralları ```python # pseudocode — services/ml/pipeline.py for damage in damages: candidates = [] for part in parts: iou = iou(damage.mask, part.mask) intersection_ratio = intersection_area(damage.mask, part.mask) / damage.area if intersection_ratio >= 0.5: # hasar parçanın yarısından fazla içindeyse candidates.append((part, iou, intersection_ratio)) if not candidates: damage.primary_part = "unknown" elif len(candidates) == 1: damage.primary_part = candidates[0][0].name else: # Birden fazla parça örtüşüyor → multi-part candidates.sort(key=lambda c: -c[2]) # intersection_ratio'ya göre damage.primary_part = candidates[0][0].name damage.secondary_parts = [{"part": c[0].name, "ratio": c[2]} for c in candidates[1:]] damage.is_multi_part = True # Düşük güven kontrolü if candidates and candidates[0][1] < 0.05: damage.is_low_confidence_match = True ``` `iou_threshold = 0.05` bilinçli olarak düşük — bilinmeyen parça > yanlış parça. Detaylar: `services/ml/pipeline.py`. ## 2. Parça-merkezli output reorganizasyonu Pipeline iç düzeyde **hasar-listesi** tutar, ama API kullanıcısına **parça-merkezli** JSON döner. `services/ml/output_formatter.py` bu çeviriyi yapar. İç (raw): ```python damages = [{id, type, primary_part, severity, cost, ...}, ...] parts = [{name, polygon, confidence}, ...] ``` Dış (kullanıcıya): ```python parts = [ { name, name_tr, status, # status: clean | minor | moderate | severe damage_count, damages: [...], # bu parçaya ait hasarlar part_cost_min_tl, part_cost_max_tl, cost_note, # "Tek parça değişimi diğer hasarları kapsar" } ] ``` Kritik: **hasarsız parçalar da listede**, `status: "clean"` ile. Kullanıcı "kontrol edildi, hasar yok" güvencesi alıyor. ## 3. Şiddet ensemble `services/ml/severity_classifier.py` üç katman: 1. **Kural-tabanlı** (`RuleBasedSeverity`): - `area_ratio < 0.005` → hafif - `0.005 ≤ area_ratio < 0.02` → orta - `area_ratio ≥ 0.02` → ağır - Hasar tipi çarpanları: glass_shatter → her zaman ≥ orta, scratch → genelde hafif 2. **CNN classifier** (`CNNSeverity`): - EfficientNetV2-S, hasar crop'u → 3-sınıf softmax - Roboflow severity setinde fine-tune edilir 3. **Ensemble** (`EnsembleSeverity`): - Anlaşıyorlarsa → o seviye, yüksek güven - Anlaşmıyorlarsa → ağırlıklı (kural %40, CNN %60), düşük güven flag v1'de kural-tabanlı yeter (açıklanabilir, sigortacı için satılabilir). CNN v2 backlog. ## 4. Maliyet motoru — kademeli lookup `services/ml/cost_engine.py` + `cost_table.yaml` (TR-specific). **Lookup hiyerarşisi:** (parça, tip, şiddet) → (parça, tip default) → (global default) → hard default. Her seviye düştükçe `cost_confidence` düşer (high → medium → low). **Çoklu hasar aggregation:** Aynı parçada birden fazla hasar varsa, naif toplam yanlış olur (parça değişimi diğer hasarları zaten kapsar). En pahalı %70'i aşıyorsa, sadece o alınır + `cost_note: "Tek parça değişimi diğer hasarları kapsar"`. **v1 sınırlamaları:** - Lookup tablosu manuel — TR pazar verileriyle güncellenmeli (otoyedek, yetkili servisler, TSB) - Araç modeline duyarlı değil (Fiat Egea vs. BMW 5 farkı yok) — v2 backlog - İşçilik vs. parça ayrı satır değil — agregate range ## 5. Servisler arası kontratlar ### Backend ↔ Frontend (TypeScript) `packages/types/src/` altında Pydantic şemalarının birebir TS karşılığı. Web, desktop ve mobile aynı tipleri kullanır. | Backend (Pydantic) | Frontend (TS) | Yer | |---|---|---| | `models.Damage` | `Damage` | `packages/types/src/damage.ts` | | `models.Part` | `Part` | `packages/types/src/part.ts` | | `models.Inspection` | `Inspection` | `packages/types/src/inspection.ts` | | `models.InspectionSummary` | `InspectionSummary` | `packages/types/src/inspection.ts` | | `models.HealthResponse` | `HealthResponse` | `packages/types/src/api.ts` | Senkron tutmak için: `python services/backend/scripts/export_openapi.py` çalıştırıp `packages/types/openapi.json` üretilir, manuel karşılaştırma yapılır. (v0.2'de openapi-typescript ile otomatik gen düşünülebilir.) ### Frontend (UI paylaşımı) `packages/ui` web ve desktop tarafından doğrudan import edilir. Mobile (RN) React DOM yerine RN component'leri kullandığından `packages/ui`'yi DOĞRUDAN kullanmaz — `apps/mobile/components/` altında benzer component'ler RN-native olarak yaşar. Hedef: aynı API yüzeyini koru, render farklı. ### ML ↔ Backend ML pipeline (`services/ml/pipeline.py`) Python class olarak çağrılır: ```python pipeline = DamagePipeline(damage_weights="...", parts_weights="...", ...) result = pipeline.run(image_path) # dict, packages/types ile uyumlu ``` Backend `services/backend/ml_service.py` singleton wrapper'ı tutar (model yükleme tek sefer, request başına inference). Celery worker (`worker.py`) async job için bu singleton'ı yeniden kullanır. ## 6. Veri akışı — uçtan uca ``` Kullanıcı (Web/Desktop/Mobile) │ │ multipart POST /api/v1/inspect ▼ FastAPI ├─ S3/MinIO'ya orijinal görüntü yükle ├─ Postgres'e inspection kaydı (status=queued) ├─ Celery task'ı kuyruğa koy └─ {inspection_id, status_url} döndür │ ▼ Celery Worker (Redis broker) ├─ S3'ten görüntü çek ├─ ML Pipeline (singleton, warm) │ ├─ paralel hasar + parça inference │ ├─ IoU eşleme, severity, cost │ └─ visualization.py: 3 PNG üret (annotated, parts, damages) ├─ Postgres'e sonuç + status=completed ├─ S3'e visualization PNG'leri └─ Redis pub/sub: status push │ ▼ Frontend ├─ Polling: GET /api/v1/inspect/{id} (2sn aralık) │ veya WS /api/v1/inspect/{id}/stream └─ status=completed → result JSON + visualization URL'leri ``` ## 7. Performans hedefleri | Senaryo | Hedef latency | Notlar | |---|---|---| | Sync tek görüntü (cloud GPU, T4) | < 2sn | YOLO26-m batch=1 | | Async 5 görüntü | < 8sn | paralel inference | | Async 30 görüntü (360° tarama) | < 30sn | Celery 4-worker | | Mobile on-device QC | < 100ms | YOLO26-n TFLite | | Cold start (model load) | < 8sn | singleton ile bir kere | Yerel dev (RTX 5050 8GB): batch=8 m-model ~30ms/image. Production GPU (T4) benzer. ## 8. Gözlemlenebilirlik (v0.2) - **Sentry** — frontend ve backend hataları - **Prometheus** — request latency, inference time, queue depth, error rate - **Grafana** — `observability/` altında dashboard JSON - **Structured logs** — backend loguru JSON, frontend pino (browser) - **Trace ID** — her inspection için, headers ve log'larda ## 9. Güvenlik - **Auth:** v1 API key (`X-API-Key`), v2 JWT - **CORS:** `localhost:3000` (web dev), `tauri://localhost` (desktop prod), Expo emülatör. Production'da env'den whitelist. - **CSP:** Tauri config'te sıkı, sadece localhost+https. - **PII:** Plaka/VIN ham görüntüde — anonimleştirme v0.2. - **Rate limit:** v0.2, Redis-based. ## 10. Bilinçli kısıtlamalar - **CarDD academic non-commercial** — ticari pilot için ayrı izin gerekli, ya da kendi etiketli veri seti. - **Türk araç modelleri zayıf temsil** — pilot'tan 500-1000 TR görüntüyü etiketleyip fine-tune (Hafta 11-12). - **Aydınlatma/açı edge case'leri** — capture flow'da rehberlik, yine de %20-30 başarısız case kaçınılmaz. - **Maliyet tablosu manuel** — TR pazar verisiyle güncellenmeli, otomatik scraping v2.