hasari-api / ARCHITECTURE.md
erdoganpeker's picture
v0.3.0 — multimodal vehicle damage MVP
e327f0d

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ı

# 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):

damages = [{id, type, primary_part, severity, cost, ...}, ...]
parts = [{name, polygon, confidence}, ...]

Dış (kullanıcıya):

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:

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
  • Grafanaobservability/ 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.