# Specyfikacja procesu: analiza uwagi wzrokowej kreacji reklamowych > Opis **logiki procesu** niezależny od narzędzia orkiestrującego, przeznaczony do > implementacji jako komponent oprogramowania (np. usługa backendowa / pipeline). > Definiuje: dane wejściowe, kontrakty zewnętrznych usług AI, kolejność i równoległość > wywołań, model danych wynikowych oraz logikę prezentacji. --- ## 1. Cel i zakres System przyjmuje **pojedynczy obraz** (kreację reklamową / grafikę) i zwraca zestaw analiz: 1. **Rozumienie zawartości** — jakie obiekty są na obrazie i gdzie się znajdują. 2. **Predykcja uwagi wzrokowej (saliency)** — gdzie skupi się wzrok odbiorcy; trzy niezależne modele dla walidacji krzyżowej. Wynikiem są dane (lista obiektów z ramkami, mapy uwagi) oraz pochodne wizualizacje. Proces jest **bezstanowy** — jedno wejście (obraz) → jeden komplet wyników. --- ## 2. Architektura logiczna ``` ┌────────────────────┐ │ Wejście: obraz │ └─────────┬──────────┘ ▼ ┌────────────────────┐ │ Preprocessing │ bytes + base64 + mime + (w,h) └─────────┬──────────┘ │ ┌──────────────┼───────────────┬───────────────┬───────────────┐ ▼ (łańcuch A) ▼ (B) ▼ (C) ▼ (D) ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ LLaVA │ │ DeepGaze │ │ UNISAL │ │ ASM │ │ (etykiety)│ │(saliency)│ │(saliency)│ │(2× saliency) └────┬─────┘ └────┬─────┘ └────┬─────┘ └────┬─────┘ ▼ │ │ │ ┌──────────────┐ │ │ │ │ Grounding │ │ │ │ │ DINO (boxy) │ │ │ │ └────┬─────────┘ │ │ │ │ ▼ ▼ ▼ ▼ ┌──────────────────────────────────────┐ ┌──────────────┐ │ Agregacja wyników saliency │ │ Wynik: │ └──────────────────┬───────────────────┘ │ detekcja │ ▼ └──────────────┘ ┌──────────────────────────┐ │ Artefakty wyjściowe: │ │ • overlay boxów │ │ • nakładka heatmapy │ │ • porównanie 2×2 │ └──────────────────────────┘ ``` **Kluczowe zależności:** - **Łańcuch A jest sekwencyjny:** Grounding DINO potrzebuje etykiet z LLaVA. - **Zadania B, C, D oraz cały łańcuch A są względem siebie niezależne** → wykonywane równolegle. - Punkt agregacji czeka na zakończenie wymaganych zadań przed złożeniem danego artefaktu. --- ## 3. Dane wejściowe i preprocessing **Wejście:** plik graficzny (PNG lub JPEG). **Preprocessing** — z jednego uploadu przygotuj reprezentację współdzieloną przez wszystkie usługi: ``` ImageInput { bytes : binary // oryginalne bajty pliku (do multipart/form-data) base64 : string // base64 bez prefiksu data: (do osadzania i obliczeń) mime : "image/png" | "image/jpeg" width : int height : int } ``` - `mime`, `width`, `height` ustal **standardową biblioteką** do obrazów (np. Pillow / `image-size` / `sharp`). > Uwaga: pierwotna implementacja parsowała nagłówki ręcznie (PNG: `width@offset16`, > `height@offset20` jako uint32 BE; JPEG: skan markerów `SOF0 0xC0` / `SOF2 0xC2`). > W docelowym kodzie użyj gotowej biblioteki — wymiary i tak są potrzebne tylko do > pozycjonowania ramek i renderowania (sekcja 7). - `base64` służy do: (a) osadzania oryginału w wizualizacjach, (b) blendu pikselowego. - `bytes` służy do wszystkich wywołań usług (pole multipart `image` lub `file`). --- ## 4. Wewnętrzny model danych (wyników) ``` DetectionResult { objects : [ { object_type: string, bbox_xyxy: [x1, y1, x2, y2], // piksele, układ XYXY score: float } ] // 0..1 model_id? : string threshold? : float } SaliencyMap { source : "deepgaze" | "unisal" | "asm_detailed" | "asm_general" image_base64 : string mime : string } AnalysisResult { image : ImageInput detection : DetectionResult saliency : SaliencyMap[] // 4 pozycje: deepgaze, unisal, asm_detailed, asm_general } ``` --- ## 5. Zewnętrzne usługi AI — kontrakty API Wszystkie usługi to **HTTP POST** z ciałem `multipart/form-data` zawierającym obraz. Adresy hostów i token pochodzą z konfiguracji / magazynu sekretów (sekcja 8). Każde wywołanie powinno mieć skończony **timeout** i być **odporne na błędy** (sekcja 9). Kształty odpowiedzi oznaczone „(wnioskowane)" odtworzono na podstawie sposobu konsumpcji danych — przy implementacji potwierdź je z dokumentacją/realnymi odpowiedziami usług. ### 5.1. LLaVA — ekstrakcja typów obiektów Multimodalny model wizualno-językowy; zwraca listę kategorii obiektów widocznych na obrazie. ``` POST http://{LLAVA_HOST}/llava-api/v1/get-object-types Headers: accept: application/json Authorization: Bearer {TOKEN} Body (multipart/form-data): temperature = 0.2 // niska → powtarzalność top_p = 0.9 image = Odpowiedź (wnioskowane): { "labels": ["person", "bottle", "logo", ...] } ``` **Transformacja po stronie klienta:** połącz `labels` w jeden ciąg rozdzielony przecinkami (`"person, bottle, logo"`) — wejście dla Grounding DINO. ### 5.2. Grounding DINO — detekcja obiektów (bounding boxy) Otwarto-zbiorowa (zero-shot) detekcja sterowana tekstem: dla podanych etykiet zwraca ramki. ``` POST http://{GROUNDING_DINO_HOST}/grounding-dino-api/v1/get-objects-bboxes Headers: accept: application/json Authorization: Bearer {TOKEN} Body (multipart/form-data): object_types = "{labels_z_LLaVA}" // np. "person, bottle, logo" max_objects = 50 base64 = false image = Odpowiedź (wnioskowane): { "objects_bboxes": [ { "object_type": "logo", "bbox_coords_xyxy": [x1, y1, x2, y2], "score": 0.87 } ], "model_id": "...", // opcjonalnie "threshold": 0.3, // opcjonalnie "width": 839, // opcjonalnie (fallback wymiarów) "height": 1190 } ``` ### 5.3. DeepGaze — mapa uwagi (saliency) Predykcja rozkładu uwagi wzrokowej; zwraca heatmapę zakodowaną base64. ``` POST http://{DEEPGAZE_HOST}/v1/predict-heatmap Headers: accept: application/json Authorization: Bearer {TOKEN} Body (multipart/form-data): image = Odpowiedź (wnioskowane): { "heatmap_b64": "", "heatmap_mime": "image/png", "width": 839, "height": 1190, "model": "deepgaze..." } ``` → mapuj na `SaliencyMap{ source:"deepgaze", image_base64:heatmap_b64, mime:heatmap_mime }`. ### 5.4. UNISAL — mapa uwagi (saliency, model porównawczy) ``` POST http://{UNISAL_HOST}/unisal/process-image?as_base64=true Headers: accept: application/json X-API-Key: {TOKEN} Body (multipart/form-data): file = Odpowiedź (wnioskowane): { "data": "", "mimetype": "image/jpeg" } ``` → `SaliencyMap{ source:"unisal", image_base64:data, mime:mimetype }`. ### 5.5. ASM (asmModel) — mapy uwagi z warunkowaniem promptem Model centralny: zwraca **dwie** mapy uwagi (szczegółową i ogólną), warunkowane tekstowym promptem osadzającym kontekst marketingowy. ``` POST http://{ASM_HOST}/asmModel/process-image ?prompt=Describe the image in the style of a polished marketing ad. &as_raw_output=false &max_new_tokens=100 Headers: accept: application/json X-API-Key: {TOKEN} Body (multipart/form-data): file = Odpowiedź (wnioskowane): { "image_detailed": "", "image_general": "", "mimetype": "image/jpeg" } ``` → dwa wpisy: `SaliencyMap{source:"asm_detailed",...}` oraz `SaliencyMap{source:"asm_general",...}`. > **Uwaga:** architektura ASM nie wynika z kontraktu — to wewnętrzny mikroserwis. > `prompt` i `max_new_tokens` sugerują model multimodalny warunkowany językiem. > Prompt potraktuj jako **parametr konfigurowalny**, nie stałą. --- ## 6. Orkiestracja Logika sterująca (zastępuje przepływ narzędzia) — uruchom niezależne gałęzie równolegle, zachowując jedyną zależność LLaVA → Grounding DINO. ```python async def analyze(image_bytes) -> AnalysisResult: img = preprocess(image_bytes) # bytes, base64, mime, w, h async def detection_chain(): labels = await llava_object_types(img.bytes) # 5.1 labels_str = ", ".join(labels) return await grounding_dino(img.bytes, labels_str) # 5.2 # gałęzie niezależne — równolegle detection, deepgaze, unisal, asm = await gather( detection_chain(), # łańcuch A (sekwencyjny wewnątrz) deepgaze_heatmap(img.bytes), # B unisal_saliency(img.bytes), # C asm_saliency(img.bytes, PROMPT), # D return_exceptions=True, # patrz sekcja 9 ) saliency = [ SaliencyMap("deepgaze", deepgaze.heatmap_b64, deepgaze.heatmap_mime), SaliencyMap("unisal", unisal.data, unisal.mimetype), SaliencyMap("asm_detailed", asm.image_detailed, asm.mimetype), SaliencyMap("asm_general", asm.image_general, asm.mimetype), ] return AnalysisResult(img, detection, saliency) ``` **Zasady:** - Cztery gałęzie startują jednocześnie; całkowity czas ≈ czas najwolniejszej gałęzi. - Punkt agregacji łączy wyniki dopiero, gdy potrzebne gałęzie się zakończą. - Każdy artefakt wyjściowy zależy od konkretnego podzbioru wyników (sekcja 7) — można je generować, gdy tylko jego zależności są gotowe. --- ## 7. Warstwa prezentacji (artefakty wyjściowe) Trzy artefakty. Można je renderować **po stronie klienta** (HTML/Canvas — jak w oryginale) lub **serwerowo** komponować obrazy (Pillow / sharp / canvas). Poniżej logika niezależna od wyboru. ### 7.1. Wizualizacja detekcji obiektów **Zależności:** oryginał + `DetectionResult`. - Dla każdego obiektu narysuj ramkę z `bbox_xyxy`, podpis `"{object_type} {score%}"`. - Kolor per typ obiektu (paleta cykliczna; ten sam typ = ten sam kolor). - Pozycje przeliczaj na **procenty** wymiarów obrazu (`x1/width`, `y1/height`, …), aby skalowały się responsywnie. - Opcjonalnie: filtry pokazujące/ukrywające typy, legenda, licznik obiektów. ### 7.2. Nakładka pojedynczej mapy uwagi **Zależności:** oryginał + jedna `SaliencyMap` (np. DeepGaze). - Heatmapa nałożona na oryginał z **regulowaną przezroczystością** (suwak 0–100%). ### 7.3. Porównanie map uwagi (siatka 2×2) **Zależności:** oryginał + 4 mapy (`deepgaze`, `unisal`, `asm_detailed`, `asm_general`). - Cztery kafelki, wspólny suwak intensywności, technika „inwersji" (7.4). ### 7.4. Algorytm „inwersji" heatmapy (blend luminancji) Wspólna logika nakładek. Dla parametru `t ∈ [0,1]` (intensywność / pozycja suwaka): ``` # Z heatmapy licz luminancję (jasność uwagi) 0..1: lum = (0.299*R + 0.587*G + 0.114*B) / 255 # Blend per kanał (RGB), per piksel: out = orig * (1 - t) + (lum * 255) * t ``` - `t = 0` → czysty oryginał; `t = 1` → maska uwagi w skali szarości (biel = wysoka uwaga, czerń = niska) → efekt „reflektora". - Wymaga zgodności rozdzielczości oryginału i heatmapy (w razie potrzeby przeskaluj heatmapę). --- ## 8. Konfiguracja i sekrety Wynieś poza kod (zmienne środowiskowe / vault): | Klucz | Opis | |---|---| | `LLAVA_HOST` | host usługi LLaVA | | `GROUNDING_DINO_HOST` | host usługi Grounding DINO | | `DEEPGAZE_HOST` | host usługi DeepGaze | | `UNISAL_HOST` | host usługi UNISAL (w oryginale `1.208.108.242:58951`) | | `ASM_HOST` | host usługi ASM (w oryginale ten sam host co UNISAL) | | `TOKEN` | poświadczenie (Bearer dla LLaVA/DINO/DeepGaze; `X-API-Key` dla UNISAL/ASM) | | `ASM_PROMPT` | prompt warunkujący ASM (domyślnie marketingowy) | | `MAX_OBJECTS` | limit detekcji (domyślnie 50) | > Dwa schematy autoryzacji: **`Authorization: Bearer`** (LLaVA, Grounding DINO, DeepGaze) > vs **`X-API-Key`** (UNISAL, ASM). Zaimplementuj per usługa. --- ## 9. Obsługa błędów i odporność W oryginale węzły LLaVA, DeepGaze, UNISAL i ASM były ustawione na **kontynuację mimo błędu** — awaria pojedynczego modelu nie przerywała całości. Odtwórz to: - **Degradacja stopniowa:** błąd jednej gałęzi → pomiń jej artefakt, zwróć pozostałe (`return_exceptions` / per-task `try/except`). Nie przerywaj całej analizy. - **Twarda zależność:** jeśli LLaVA zawiedzie, Grounding DINO nie ma etykiet → pomiń detekcję (lub fallback: pusta lista / domyślne etykiety), reszta map uwagi działa dalej. - **Timeouty i retry:** skończony timeout na każde wywołanie; ewentualny retry z backoffem dla błędów przejściowych (5xx / timeout). - **Walidacja odpowiedzi:** sprawdzaj obecność kluczy (`labels`, `objects_bboxes`, `heatmap_b64`, `data`, `image_detailed`/`image_general`) przed użyciem. - **Zgodność wymiarów:** przy blendzie/overlayu pilnuj zgodności rozdzielczości oryginału i map. --- ## 10. Proponowana dekompozycja modułów | Moduł | Odpowiedzialność | |---|---| | `preprocess` | walidacja pliku, base64, mime, wymiary | | `clients/` | po jednym kliencie na usługę (LLaVA, GroundingDINO, DeepGaze, UNISAL, ASM); auth, timeout, parsowanie odpowiedzi | | `orchestrator` | równoległe uruchomienie gałęzi, agregacja, obsługa błędów (sekcja 6, 9) | | `models` | typy danych (sekcja 4) | | `render/` | generowanie artefaktów (overlay boxów, nakładka heatmapy, siatka 2×2 + blend) | | `api`/`cli` | punkt wejścia: przyjmij obraz → zwróć `AnalysisResult` + artefakty | **Sugerowany stack:** dowolny z natywną asynchronicznością i obsługą `multipart` oraz obrazów — np. Python (FastAPI + `httpx.AsyncClient` + Pillow) lub Node (Fastify/Express + `undici`/`fetch` + `sharp`). Renderowanie wizualizacji: serwerowo (kompozycja obrazu) albo zwrot danych + szablon kliencki. --- ## 11. Rozszerzenia (roadmapa) Pierwotny projekt przewidywał dalsze etapy analizy uwagi (jeszcze niezaimplementowane): - **Mapa cieplna w interwałach czasowych** (np. „30 s, 6 obrazów", „20 s → 0,5 s") — saliency rozłożona na przedziały czasu. - **Ścieżki fiksacji (scanpath)** — przewidywana sekwencja ruchów oka. - **Mapa emocji** — predykcja reakcji emocjonalnej na kreację. Architektura z sekcji 6 jest na to przygotowana: dokładaj kolejne niezależne gałęzie do równoległej orkiestracji i nowe artefakty do warstwy prezentacji. --- *Specyfikacja odtworzona z istniejącego przepływu przetwarzania; kontrakty odpowiedzi oznaczone* *„wnioskowane" wymagają potwierdzenia z dokumentacją docelowych usług AI.*