ASM_PNS_C/Specyfikacja-procesu-AI.md

393 lines
16 KiB
Markdown
Raw Normal View History

# 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 = <plik>
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 = <plik>
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 = <plik>
Odpowiedź (wnioskowane):
{ "heatmap_b64": "<base64>",
"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 = <plik>
Odpowiedź (wnioskowane):
{ "data": "<base64>", "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 = <plik>
Odpowiedź (wnioskowane):
{ "image_detailed": "<base64>",
"image_general": "<base64>",
"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 0100%).
### 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.*