Automatische Bildbewertung — Optionen (OP-QS-2)
Status: Optionen-Doku (06-26) · Phase 1a ✅ (Pre-Upload-Gate B-1/B-3/B-4) · Phase 1b Auto-Erkennungs-Adapter gebaut, dormant (MediaPipe-Gesichter + nsfwjs, self-hosted/lazy — aktiv erst nach Asset-Hosting) · Phasen 1c/1d ✅ (nummerierte Markierungen + Screenshot-Feedback, OP-FEEDBACK-1 vollständig) — Details in §7 · Bezug: OP-QS-2 (Owning) · hängt an OP-QS-1 (Foto-Doku am Mangel) · grenzt sich von OP-AI-2/OP-AI-3 ab (das ist KI-Plausibilität beim Upload, nicht die fachliche Bewertung des Arbeitsergebnisses) · Zielgruppe: IT-Dev/Architektur · True North: nur indirekt — Nutzen ist QS-Beschleunigung/Doku-Qualität (§6), keine der drei Leitfragen direkt
Kernaussage. „Automatische Bildbewertung" meint zwei getrennte Ziele (§1): das on-device Pre-Upload-Gate — foto-technische Qualität (B-1) + PII-Schutz mit Verpixeln (B-3) + NSFW-Block (B-4) — ist gebaut (Phase 1a; die Auto-Erkennungs-Adapter der Phase 1b bleiben dormant); die fachliche Bewertung des Arbeitsergebnisses (B-2) ist offen. Empfehlung dafür (§5): Hybrid F, gestuft — erst das Gate, dann Claude Vision als Vorschlag in QS/Mangel („KI schlägt vor, QS entscheidet"), ein eigenes Modell erst bei ausreichendem Bilddaten-Schatz. Compliance (DE/AT/CH, §4) ist vor jedem Cloud-Pfad zu klären.
1. Worum es geht — zwei verschiedene Bewertungs-Ziele
„Automatische Bildbewertung" meint in Taktano zweierlei, die technisch getrennt zu denken sind:
| Ziel | Frage | Wo | Beispiel |
|---|---|---|---|
| B-1 Foto-technische Qualität | Ist das Bild brauchbar (scharf, belichtet, richtiger Ausschnitt)? | Upload-Gate an jedem Foto-Feld (R4) | „Bild unscharf — bitte neu aufnehmen" |
| B-2 Fachliche Bewertung | Ist die Arbeit mangelfrei? Welcher Defekt, wie schwer? | QS-Endkontrolle, Mangel-Doku (OP-QS-1), Anlieferungs-Schadensdoku | „Einschluss in der Folie an der Tür → Mangel, Schwere mittel" |
| B-3 PII-Schutz vor Upload | Sind Personen/Kennzeichen im Bild? → warnen + Verpixeln anbieten | on-device, vor jedem Foto-Upload (R4) | „2 Gesichter + 1 Kennzeichen erkannt → verpixeln?" |
| B-4 Inhalts-/NSFW-Check | Ist das Bild unangemessen/irrelevant (NSFW)? → warnen + Upload blocken | on-device, vor jedem Foto-Upload (R4) | „Bild als unangemessen eingestuft → Upload gesperrt" |
OP-AI-2/OP-AI-3 (Doku-Pflicht-Gate) deckt einen dritten, eng verwandten Fall ab — die Plausibilität des Doku-Bilds (richtige Perspektive, plausible Fahrzeugfarbe). Das ist ein Konsistenz-Check des Uploads, nicht die Qualitätsbewertung des Gewerks. Dieses Dokument fokussiert B-1 und B-2.
2. Andockpunkte im Produkt (heute/geplant)
- QS-Workspace (Qualität, Endkontrolle-Queue + Checkliste + Freigabe) — Bewertung B-2.
- Mangel-Doku (M05 / OP-QS-1, offen) — Foto am Mangel + „behoben"-Workflow → B-2.
- Anlieferung — Schadensdokumentation am eingehenden Fahrzeug → B-2.
- Formulare (R4, Feldtyp „Foto-Upload") — B-1 als universelles Gate.
3. Die Optionen
| # | Ansatz | Deckt | Aufwand/Kosten | Datenschutz | Bewertung |
|---|---|---|---|---|---|
| A | Multimodal-LLM (Vision-API), z. B. Claude Vision | B-2 | Niedrige Hürde (kein Training, Prompt-basiert); API-Spend je Bild | US-Cloud → AVV + Drittland (s. §4) | Liegt im Stack (A-4 KI-Layer, A-5-Pragma LLM-API). Liefert Klartext-Begründung + Mangel-Vorschlag. Passt zu „KI schlägt vor, Mensch entscheidet". |
| B | Generische Cloud-Vision (Google Vision / AWS Rekognition / Azure) | B-1 grob + OCR | Pay-per-call, kein Training | US-Cloud (analog A) | Nicht domänentrainiert — erkennt keine Folien-Einschlüsse/Lackläufer. Nutzbar für Kennzeichen-OCR (→ Schwärzung!) oder Grob-Labels. |
| C | Eigenes ML-Modell (CNN, auf Lack-/Folien-Defekte trainiert) | B-2 (höchste Genauigkeit) | Hoch: Trainingsdaten sammeln+labeln, MLOps, Re-Training | In eigener Infra (EU) lösbar | Lohnt erst mit Bilddaten-Schatz. Kandidat später (Fly.io neben dem Solver). |
| D | Klassische Bildverarbeitung (OpenCV/WASM, ohne ML) | B-1 (Schärfe/Blur/Helligkeit/Auflösung) | Sehr gering, deterministisch, offline | Unkritisch | Ideales Upload-Gate. Bewertet nicht den Inhalt. |
| E | On-device / Edge (TensorFlow.js / WASM im Browser) | B-1 + leichte Klassifikation | Mittel | Vorteil: Bild verlässt das Gerät erst nach Gate | Datenschutz-Plus, begrenzte Modellgröße. |
| F | Hybrid (D/E als Gate → A für B-2) | B-1 + B-2 gestuft | Mittel | Gate filtert vor teurem/exponiertem LLM-Call | Empfehlung (§5). |
4. ⚠️ Compliance-Flag (DE/AT/CH) — verbindlich
Fahrzeugfotos sind datenschutzrelevant (DSGVO):
- Kennzeichen = personenbezogenes Datum; ggf. Personen/Reflexionen im Hintergrund; EXIF mit GPS/Gerät.
- A/B (US-Cloud) = Auftragsverarbeitung + Drittlandtransfer → AVV + Transfer-Mechanismus
nötig; in
docs/betrieb/Compliance.mdunddocs/betrieb/Risikoregister.mdnachziehen (vgl. RISK-10-Logik zu KI/Tool-Nutzung). - C/D/E in eigener EU-Infra bzw. on-device entschärfen das deutlich.
- Unabhängig vom Modell, immer: EXIF strippen, Kennzeichen/Personen vor Cloud-Versand schwärzen (Bezug Option B/OCR), R2-Retention definieren (Bezug OP-AUDIT-1), Einwilligung/ Zweckbindung dokumentieren.
Diese Punkte sind vor einem Bau zu klären — aktiv geflaggt, nicht still übergangen (CLAUDE.md §Compliance „Proaktives Flagging").
4a. B-3 — Personen/Kennzeichen vor dem Upload warnen + verpixeln (Entscheidung 06-26)
Anforderung (Nutzer 06-26): Beim Foto-Upload on-device prüfen, ob Personen (Gesichter) oder Kennzeichen im Bild sind; falls ja warnen und anbieten, Gesichter und Kennzeichen zu verpixeln. Das ist Privacy-by-Design / -by-Default (DSGVO Art. 25) und entschärft das Compliance-Risiko aus §4 direkt an der Quelle — die PII verlässt das Gerät idealerweise gar nicht erst (vor allem wichtig vor den Cloud-Pfaden A/B).
Schlüssel-Entscheidung: Erkennung + Verpixelung laufen on-device (Option E), vor dem Upload. Nur die redigierte Kopie wird hochgeladen; das Original verlässt das Gerät nicht (Nutzer kann es lokal verwerfen). Das ist der einzige Weg, der die Datenminimierung tatsächlich einhält — ein Server-seitiger Blur käme zu spät (Rohbild läge dann schon in der Cloud).
UX-Fluss
- Bild wählen/aufnehmen → on-device-Scan markiert Gesichter/Kennzeichen mit Boxen.
- Warnung „N Gesichter / M Kennzeichen erkannt".
- Angebot: Verpixeln (empfohlener Default) · manuell Boxen hinzufügen/entfernen (Erkennung ist nie 100 %) · ohne Verpixeln hochladen (Bestätigung + Grund; für den Cloud-Rating-Pfad A/B möglichst sperren/erzwingen — s. u.).
- Verpixelung clientseitig im Canvas (Mosaik/Blur je Box, irreversibel auf der Kopie) → nur das redigierte Bild geht in den Upload (danach B-1-Gate).
Optionen für die Erkennung (on-device)
| Was | Ansatz | Hinweis |
|---|---|---|
| Gesichter | MediaPipe Face Detector / BlazeFace (TF.js) oder face-api.js | Reif, schnell im Browser, kleine Modelle. Erkennung, keine Identifikation (keine Gesichts-Erkennung i. S. v. Biometrie — nur „hier ist ein Gesicht"). |
| Kennzeichen | leichtes Objektmodell (YOLO-nano/SSD auf „Plate", via onnxruntime-web/TF.js-WASM) oder OpenCV-Heuristik (Kanten/Rechteck-Proportionen) | Schwieriger/ungenauer als Gesichter → manuelle Nachkorrektur Pflicht-Fallback. Bewusst nur Lokalisieren (Box), kein OCR (kein Klartext-Kennzeichen erzeugen/speichern). |
| Verpixeln | Canvas: Region downscale→upscale (Mosaik) bzw. Blur je Box | Rein clientseitig, keine Lib nötig. |
Entscheidungen
- On-device, vor Upload (Option E) — PII-Minimierung an der Quelle; Server-Blur wäre zu spät.
- Erkennung ≠ perfekt → manuelle Korrektur (Box hinzufügen/entfernen) + Nutzer-Verantwortung; keine „false sense of safety". Kennzeichen-Erkennung konservativ (lieber Fehlalarm als Miss).
- „Anbieten" (opt-in) wie gewünscht — aber Empfehlung: für den Cloud-Rating-Pfad (A/B) die Redaktion default/erzwungen, da unredigierte Kennzeichen/Gesichter an einen US-Dienst ein echtes DSGVO-Thema sind (Bezug §4). „Ohne Verpixeln" nur mit Bestätigung/Grund, ggf. rollen-gegated (OP-AUTH-1) und als OP-AUDIT-1-Event.
- Nur Lokalisieren, nicht identifizieren — kein Biometrie-Template, kein Kennzeichen-OCR; damit bleibt das Feature selbst datensparsam.
4b. B-4 — Inhalts-/NSFW-Check vor dem Upload (Entscheidung 06-26)
Anforderung (Nutzer 06-26): Beim Foto-Upload zusätzlich on-device prüfen, ob das Bild unangemessen (NSFW) ist, und ggf. warnen + den Upload blockieren. Schützt das B2B-Tool vor unangemessenen/irrelevanten Inhalten (Arbeitsplatz, Governance/Trust, Jugendschutz) und hält die Bild-Doku sauber auf den Werkstatt-Kontext fokussiert.
Schlüssel-Entscheidung: on-device (Option E), im selben Pre-Upload-Scan wie B-1/B-3. Ein einziger Scan-Durchgang beim Auswählen/Aufnehmen liefert Qualität (B-1), PII-Boxen (B-3) und NSFW-Score (B-4) — das Bild verlässt das Gerät erst nach Bestehen aller Gates.
Unterschied zu B-3: NSFW lässt sich nicht verpixeln/„reparieren" → die Reaktion ist Upload blockieren (statt Redaktion anbieten). Override nur begründet + rollen-gegated (OP-AUTH-1) und als OP-AUDIT-1-Event, für seltene Fehlalarм-Fälle.
Optionen für die Erkennung (on-device)
| Ansatz | Hinweis |
|---|---|
| NSFWJS (TensorFlow.js, MobileNet-basiert) | Reif, läuft im Browser; Klassen neutral/drawing/sexy/porn/hentai mit Scores → konfigurierbarer Schwellwert. Default-Empfehlung (on-device, kein Upload nötig). |
| Cloud-Moderation (AWS Rekognition Moderation · Google SafeSearch · Azure Content Safety) | Genauer, aber sendet das Bild → widerspricht „vor dem Upload" + Drittland (§4). Nur als optionaler Server-Zusatz nach dem Upload. |
Entscheidungen
- On-device (NSFWJS), vor Upload — gleicher Pipeline-Pass wie B-1/B-3; kein Bild-Leak.
- Reaktion = blockieren (nicht verpixeln), da NSFW nicht redigierbar; klare Meldung.
- Schwellwert/Strenge konfigurierbar (admin, taxonomie-artig G-1) — z. B.
sexytolerieren vs. strikt; sinnvolle Defaults. - Override nur begründet + rollen-gegated (OP-AUTH-1) + OP-AUDIT-1-Event (Fehlalarm-Ventil).
- Abgrenzung: B-4 ist Content-Moderation (darf das Bild rein?), unabhängig von B-2 (fachliche Qualität) und B-3 (PII). Reihenfolge im Gate: B-4 + B-1 + B-3 zusammen vor Upload.
5. Empfehlung — Hybrid F, gestuft
- Phase 1 — Pre-Upload-Gate (D/E), ein on-device-Pass: deterministischer Schärfe-/ Belichtungs-Check (B-1) plus B-3 (Gesichts-/Kennzeichen-Erkennung → warnen + Verpixeln anbieten, §4a) plus B-4 (NSFW-Check → warnen + blocken, §4b). Sofortiger Mehrwert + Compliance-/Governance-Gewinn, keine API-Kosten, keine PII/Inhalte in der Cloud. Baubar unabhängig — Voraussetzung für die Cloud-Pfade A/B.
- Phase 2 — fachliche Bewertung (A): Claude Vision als Vorschlag in QS/Mangel (Mangel-Kategorie + Schwere + Klartext-Begründung). Strikt „KI schlägt vor, QS entscheidet" (wie Optimierer-Vorschau R8-G2 / In-App-Assistent OP-AI-4). Reiht sich in A-4-KI-Layer ein. Vorbedingung: Compliance §4 (AVV/Schwärzung/EXIF/Retention).
- Phase 3 — eigenes Modell (C): erst wenn genug gelabelte Defekt-Bilder existieren und die LLM-Genauigkeit nicht reicht.
6. True-North-Ehrlichkeit
Bildbewertung beantwortet die drei Leitfragen (Auslastung · Standort · freie Kapazität) nur
indirekt — der Nutzen liegt in QS-Beschleunigung/Qualitätssicherung (OP-QS-1) und
Doku-Qualität. Bei der Priorisierung entsprechend einordnen (docs/Sanity-Checkliste.md).
7. Stand der Umsetzung — Phase 1a (gebaut) + 1b (Auto-Erkennung dormant)
Gebaut (Client, v0.8.0/Build 11) — der On-Device-Pre-Upload-Gate als wiederverwendbarer Baustein, dockt später an das R4-Foto-Upload-Feld an:
- Reiner, DOM-freier Kern
client/src/app/leitstand/bild/upload-gate.ts(rechnet auf rohen RGBA-Pixeln, in Node selbst-testbar):- B-1
bildstatistik(mittlere Luma + Laplace-Varianz/Schärfe) +bewerteQualitaet(zu_klein/unscharf/zu_dunkel/zu_hell, Schwellen konfigurierbar). - B-3
verpixele(img, boxen)— Mosaik je Box auf einer Kopie (Original unberührt). - B-4 Klassifikator-Naht +
entscheideGate(Priorität NSFW > Qualität > PII > ok). - Detektor-Naht
PiiDetektor/NsfwKlassifikator(Default-Stubs) → BlazeFace/Plate/NSFWJS dockt ohne Umbau an.
- B-1
- Angular-Komponente
bild/bild-upload-gate.component.ts(Canvas-Glue + UX): Bild wählen → Befund (Status ok/Achtung/Gesperrt + Statistik) · Bereiche manuell markieren (Ziehen) · Verpixeln · Upload nur bei nicht-blockiert; Original verlässt die Komponente nie, nur der (ggf. verpixelte) Blob wird emittiert. Tokens-only (No-Hex-Gate grün). - Demo-/Vorschau-Seite
pages/bild-schutz.component.tsunter Deep-Link/bild-schutz(bewusst nicht im Workspace-Rail — kein fertiges Feature vortäuschen, bis das echte Upload-Feld existiert). - Self-Test
npm run test:bildgate(upload-gate.demo.ts, synthetische Bilder) + CI (Client-Job vorng build).
Phase 1b — Auto-Erkennungs-Adapter gebaut (06-26, dormant; v0.9.0/Build 12): die Naht ist mit echten Adaptern gefüllt, deploy-sicher dormant (PR-184-Muster) — aktiv erst, wenn die Modelle self-hosted sind:
bild/modelle.config.ts—MODELLE_BASIS_URL(first-party, leer = aus) +ladeModul(dynamischer Import einer absoluten URL, vor dem Bundler verborgen → keine npm-Dep, kein Bundle-Wachstum).bild/pii-mediapipe.adapter.ts(MediaPipe Face Detector, nur Box/keine Biometrie) +bild/nsfw-nsfwjs.adapter.ts(nsfwjs, Klassen→unangemessen/Score) — beide implementieren die Naht aus §7, laden Lib+Gewichte zur Laufzeit vonMODELLE_BASIS_URL.bild/detektoren.ts— Factory: bei aktiver Config werden die Adapter als eigene Lazy-Chunks (~0,8 kB, Libs nicht gebundelt) geladen, sonst Stubs;try/catch→ Fallback auf manuell.- Demo-Seite zeigt den Aktiv/Inaktiv-Status; die Komponente fängt Detektor-Fehler ab (manuelle Markierung bleibt immer nutzbar).
- Status/Warnung (06-27):
ladeDetektoren()liefertAutoStatus(aus/aktiv/fehler); der Gate zeigt ● aktiv · ○ inaktiv (dormant) · ⚠ Banner, wenn die Erkennung konfiguriert, aber nicht ladbar ist (Binding nicht einkommentiert //models404 / Modell-Load-Fehler) → fordert zur manuellen Markierung auf. Detektor-Fehler blockieren nie. - Verifiziert hier:
test:bildgate·ng build(Adapter als 769/707-B-Lazy-Chunks, Basis-Bundle unverändert) · No-Hex grün. NICHT hier verifizierbar: Laufzeit-Inferenz + Asset-Hosting.
Aktivierung (Deploy-/Infra-Schritt, B-i): MediaPipe-WASM+.tflite, TF.js- und nsfwjs-ESM-Bundle +
nsfwjs-Modell auf R2/Pages (EU) ablegen, MODELLE_BASIS_URL darauf setzen → Auto-Erkennung wird
live (Browser-Augenschein nötig).
Phase 1c — Nummerierte Markierungen (OP-FEEDBACK-1, gebaut 07-02; v0.43.0): der Bild-Schutz-Baustein kann zusätzlich zum Verpixeln nummerierte Punkt-Markierungen aufnehmen — ein wiederverwendbarer Annotations-Layer (nicht feedback-spezifisch), den das Screenshot-Feedback konsumiert (Phase 1d):
- Reiner Kern (
upload-gate.ts): TypMarkierung { nummer; xProzent; yProzent; notiz? }(Position prozentual → auflösungsunabhängig) + reine HelfermarkierungHinzufuegen/markierungEntfernen(lückenlose Re-Nummerierung ab 1) /markierungNotiz/markierungenText(Text fürs Feedback). Vontest:bildgatemitgeprüft. - Komponente (
bild-upload-gate.component.ts): Modus „① Punkt markieren" neben „✎ Bereich markieren" (schließen sich aus) — Tippen setzt einen nummerierten Pin (prozent-positionierte Vorschau-Kreise,--tk-cyan), Liste mit optionaler Notiz + Entfernen. Beim Export werden die Kreise auf eine Off-Screen-Kopie ins Bild eingebrannt (Canvasarc+fillText, Farben aus--tk-*viagetComputedStyle→ No-Hex-konform, idempotent). Neuer programmatischer EingangbildQuelle/ladeBlob(blob)(einbettbar, nicht nur per Datei-Input); Ausgabe angereichert zufreigegeben: { blob; markierungen }. - Verifiziert:
test:bildgate(Marker-Helfer) ·ng build· No-Hex grün.
Phase 1d — Screenshot-Feedback konsumiert den Baustein (OP-FEEDBACK-1, gebaut 07-02; v0.44.0): das
In-App-Feedback nimmt per html2canvas-pro (lazy) eine gezogene Region der Ansicht auf und speist sie über
den neuen Eingang bildQuelle in genau diesen Gate — der Nutzer verpixelt PII und setzt nummerierte
Markierungen; das geschützte + annotierte Bild geht an /api/feedback/screenshot → EU-FOTOS-Bucket
(feedback/<uuid>) und hängt als Access-gated Link + Markierungs-Liste am internen Issue. Details:
docs/architektur/In-App-Assistent.md §9 (Slice 10). ➡ OP-FEEDBACK-1 vollständig.
Bewusst offen (Folge-Slices):
- ⊘ Frage Ⓑ — Auto-Kennzeichen (Plate-Modell) zurückgestellt; bis dahin trägt manuelle Markierung.
- ⚙ Improvement — schlankeres tfjs-Backend / kleineres nsfwjs-Bundle (heute ~40 MB, da das
nsfwjs-Bundle ganz TF.js enthält): auf ein schlankes Backend (
@tensorflow/tfjs-core+tfjs-backend-wasm/-webgl, nur benötigte Ops) reduzieren → kleinerer Lazy-Chunk, schnellerer Erst-Load. Festgehalten 06-27; kein akuter Blocker (lazy + Browser-Cache). - EXIF strippen beim Re-Encode prüfen/erzwingen; Override für „blockiert" (begründet, rollen-gegated OP-AUTH-1, OP-AUDIT-1-Event); Anbindung an das reale R4-Upload-Feld (OP-R4-3).
7a. Auto-Erkennungs-Slice (B-3/B-4 Modelle) — Optionen (Entscheidung offen)
Phase 1a trägt B-3 über manuelle Markierung und hat die Naht (PiiDetektor/NsfwKlassifikator).
Dieser Slice füllt die Naht mit echten On-Device-Modellen — drei Achsen sind zu entscheiden.
A) Modell-/Library-Wahl
| Ziel | Option | Größe (ca.) | Bewertung |
|---|---|---|---|
| Gesichter | MediaPipe @mediapipe/tasks-vision (Face Detector, WASM) | Modell ~0,2–1 MB + WASM-Runtime | Empfehlung — modern, von Google gepflegt, schnell, kein voller TF.js nötig. Nur Lokalisieren (Box), keine Biometrie. |
| Gesichter | @tensorflow-models/blazeface (auf TF.js) | Modell ~0,4 MB + TF.js ~1–2 MB | Reif, aber zieht ganz TF.js. Sinnvoll nur, wenn TF.js für NSFW ohnehin geladen wird. |
| Gesichter | Browser FaceDetector (Shape-Detection-API) | 0 (nativ) | Verworfen — nur Chromium hinter Flag, nicht zuverlässig verfügbar. |
| Kennzeichen | YOLO-nano/SSD-Plate → TF.js oder onnxruntime-web | Modell ~2–6 MB | Modell muss beschafft/konvertiert werden; ungenauer als Gesichter. |
| Kennzeichen | OpenCV.js (WASM) + Heuristik/Cascade | Runtime ~8–10 MB | Schwer; nur Lokalisieren. |
| Kennzeichen | vorerst manuell (Status quo) | 0 | Empfehlung kurzf. — Auto-Plate ist der schwächste/teuerste Teil; manuelle Markierung trägt. |
| NSFW (B-4) | nsfwjs (TF.js, MobileNetV2) | Modell ~2–4 MB + TF.js | De-facto-Standard; Klassen neutral/drawing/sexy/porn/hentai → Schwellwert. |
| TF.js-Backend | WASM (tfjs-backend-wasm) vs WebGL | — | WASM = portabler (kein GPU-Zwang); WebGL schneller, als Fallback. |
B) Wie kommen die Modell-Gewichte zum Client? (die eigentliche Dependency-Entscheidung)
| Option | Pro | Contra |
|---|---|---|
| B-i Self-host first-party (Gewichte auf Cloudflare R2 / Pages, eigene Domain, lazy geladen) | EU/eigene Domain → kein Drittland für den Modell-Fetch · Repo bleibt schlank · Verfügbarkeit selbst kontrolliert · privacy-by-design konsequent | Deploy-Schritt (Bucket + Upload) · erster Fetch zur Laufzeit (first-party, danach Browser-Cache) |
B-ii In-App bündeln (Gewichte als Angular-Assets, von app.taktano.com ausgeliefert) | self-contained · offline · EU-served | +MBs im Deploy · Binär-Assets im Repo (Bloat; ggf. Git-LFS/Build-Fetch) |
| B-iii Public CDN (jsDelivr/unpkg bzw. nsfwjs-Default-Host) | null Hosting-Aufwand | Drittland-Request + Verfügbarkeits-/Privacy-Abhängigkeit für ein compliance-kritisches Feature → nicht empfohlen |
C) Integration (unabhängig von A/B)
- Lazy-Load per
dynamic import()+ Fetch nur, wenn ein Foto-Upload-Feld benutzt wird — der Cockpit-Basis-Bundle (heute ~630 kB, schon über Budget) bleibt unberührt; eigener Lazy-Chunk. - Adapter implementieren
PiiDetektor/NsfwKlassifikatoraus §7 — kein Umbau am Kern/an der UX. - CI: der reine Kern bleibt selbst-getestet; der Modell-Adapter wird nicht in CI geladen (kein Gewichte-Download im Build) — nur ein Smoke, dass der Adapter lädt/registriert.
- Erst-Latenz/Cache: Modell-Load einmalig (~Sekunden), danach Browser-Cache; Status-Indikator.
Empfehlung
MediaPipe (Gesichter) + nsfwjs (B-4), Gewichte self-hosted first-party (B-i, R2/Pages), lazy geladen, TF.js-WASM; Kennzeichen vorerst manuell. Das hält die Privacy-/Drittland-Haltung (kein Public-CDN-Fetch), den Basis-Bundle schlank (Lazy-Chunk) und das Repo frei von Modell-Binärblobs.
Entscheidung (Nutzer, 06-26): ① + Ⓐ
- Hosting = B-i self-host first-party (R2/Pages, EU, lazy) — beschlossen.
- Scope = Ⓐ Gesichter (MediaPipe) + NSFW (nsfwjs) jetzt, Kennzeichen weiter manuell.
- ⊘ Offene Frage Ⓑ — Auto-Kennzeichen-Erkennung (Plate-Modell YOLO-nano/ONNX bzw. OpenCV.js): bewusst zurückgestellt (teuerster/ungenauester Teil, Modell-Beschaffung). Bleibt als offener Punkt in OP-QS-2, bis die manuelle Markierung in der Praxis nicht reicht.
Verschärfung (Nutzer, 06-27): Modell-Bucket privat, kein öffentlicher Host
Ursprünglich war B-i als öffentlicher R2-Custom-Domain-Host (models.taktano.com) geplant.
Geändert: taktano-models bleibt privat (kein r2.dev, keine öffentliche Custom-Domain). Die
Modelle werden vom Worker aus einem privaten R2-Binding unter /models/* same-origin
ausgeliefert (durch Cloudflare Access geschützt, kein CORS). MODELLE_BASIS_URL = "/models".
Zusätzlich ein CI-Gate (scripts/check-r2-private.mjs), das den Deploy blockiert, falls
taktano-models oder taktano-fotos öffentlich erreichbar sind. Damit ist kein Modell-/Foto-
Bucket je öffentlich — strenger als „first-party Domain".
7b. Aktivierungs-Runbook — Auto-Erkennung scharf schalten (B-i)
Ziel: die dormanten Adapter (§7 Phase 1b) live schalten = self-hosted Assets + MODELLE_BASIS_URL.
Alles first-party (kein Public-CDN/Drittland). Schritte:
1 — R2-Bucket anlegen (EU-Jurisdiktion, DSGVO-Residenz) — Operator-Schritt:
wrangler r2 bucket create taktano-models --jurisdiction eu
⚠ Warum nicht per MCP automatisch angelegt: das MCP-
r2_bucket_createakzeptiert nurname, keine Jurisdiktion. Die EU-Residenz wird bei der Erstellung fix gesetzt und ist nachträglich nicht änderbar — ein Default-Bucket müsste gelöscht/neu erstellt werden. Daher bewusst dem Operator mit--jurisdiction euüberlassen. Stand 06-26 verifiziert: das per MCP verbundene Konto ist erreichbar und hat 0 Buckets (kein Namenskonflikt). Vorbehalt wie #185 (D1): das verbundene Konto muss das Deploy-/Prod-Konto sein.
2 — Assets aufbereiten + hochladen — automatisiert per bash scripts/upload-models.sh
(npm-Install in ein Temp-Verzeichnis → nsfwjs zu einem self-contained ESM-Bundle [tfjs +
eingebautes Modell, ~40 MB] bündeln → .tflite laden → wrangler r2 object put … --jurisdiction eu --remote). Erzeugte Bucket-Pfade (exakt das, was die Adapter lesen):
| Pfad im Bucket | Inhalt / Quelle | Content-Type |
|---|---|---|
mediapipe/vision_bundle.mjs | @mediapipe/tasks-vision (self-contained ESM) | text/javascript |
mediapipe/wasm/* (6 Dateien) | WASM-Fileset (FilesetResolver.forVisionTasks) | .wasm→application/wasm, .js→text/javascript |
mediapipe/blaze_face_short_range.tflite | Google MediaPipe-Modell (Download) | application/octet-stream |
nsfwjs/nsfwjs.bundle.mjs | nsfwjs + tfjs + Modell in einem esbuild-ESM-Bundle | text/javascript |
Verifiziert (06-27): Paket-Layout + esbuild-Bundling +
.tflite-URL geprüft. nsfwjs lädt das eingebaute MobileNetV2-Modell viaload()ohne URL → kein separates Modell-Hosting, keine separate tfjs-Datei. Das ~40-MB-Bundle wird lazy geladen (nur bei aktiver Auto-Erkennung) und danach vom Browser gecached.
Bucket bleibt PRIVAT — nicht öffentlich schalten (kein r2.dev, keine Public-Custom-Domain). Das CI-Gate (Schritt 5) erzwingt das.
3 — R2-Binding aktivieren (Worker liefert die Modelle privat aus): in server/wrangler.toml den
auskommentierten Block einschalten —
[[r2_buckets]]
binding = "MODELLE_BUCKET"
bucket_name = "taktano-models"
jurisdiction = "eu"
Der Worker bedient damit GET /models/* aus dem privaten Bucket (same-origin, Access-geschützt,
kein CORS). Ohne Binding liefert /models/* 404 (dormant).
4 — MODELLE_BASIS_URL setzen — ohne Angular-Rebuild: in server/wrangler.toml [vars]
MODELLE_BASIS_URL = "/models" + wrangler deploy → der Worker injiziert
window.__TAKTANO_MODELLE_URL__="/models" per HTMLRewriter in den SPA-<head> (leer = nichts
injiziert = dormant). Die Adapter laden dann /models/mediapipe/… usw. same-origin über den
Worker → privates R2-Binding. (Alternativen: Inline-Script im index.html-Head, oder
STANDARD_BASIS_URL in modelle.config.ts + Rebuild.)
5 — Privatheit absichern (CI-Gate, schon verdrahtet): scripts/check-r2-private.mjs läuft im
Deploy-Job vor wrangler deploy und blockiert den Deploy, falls taktano-models oder
taktano-fotos öffentlich sind (r2.dev Public Dev URL oder aktive Custom-Domain). Damit das Gate
greift, braucht der CI-CLOUDFLARE_API_TOKEN R2-Leserecht (sonst: Warnung + Skip, Deploy
läuft, Gate inaktiv — s. Skript-Kopf).
6 — Verifizieren (Browser, am Deploy): /bild-schutz öffnen → Badge „Auto-Erkennung aktiv";
Foto mit Gesicht → Box + Warnung „verpixeln?"; unangemessenes Bild → gesperrt. Im Netzwerk-Tab
gehen die Modell-Fetches an app.taktano.com/models/… (same-origin, kein öffentlicher Bucket,
kein CDN).
Nachziehen: Modell-Lizenzen (MediaPipe Apache-2.0, TF.js, nsfwjs + Modelle) in SBOM/
docs/Compliance.md; Erst-Latenz (Modell-Load, danach Browser-Cache) als Status anzeigen; Modell-
Versionierung über Pfad/Query.
8. Bezüge
OP-QS-1 (Mangel-Foto + behoben) · OP-AI-2/OP-AI-3 (Bild-/Text-Plausibilität beim Doku-Gate) ·
OP-AI-4 (In-App-Assistent, KI-Layer/propose-not-execute) · OP-AUDIT-1 (Bild-Retention/Nachweis) ·
RISK-10 (KI/Tool-Nutzung) · docs/betrieb/Compliance.md (DE/AT/CH) · A-4 (KI-Layer, docs/fachlich/Lastenheft.md
§11.8).
↩ Zurück zur Doku-Landkarte · Lesepfade · Register (alle OPs)