Kontekst — czego brakowało branży
Branża sportowo-kolekcjonerska to specyficzny rynek. Sklep z akcesoriami do sportu strzeleckiego ma w katalogu setki produktów (tłumiki dźwięku do strzelectwa sportowego, kolimatory, lunety, magazynki, kabury, ładownice, futerały, części serwisowe — w pełni legalne w ramach polskich i unijnych przepisów dla osób z odpowiednimi pozwoleniami albo dla rynku ASG/replik). Te produkty mają skomplikowaną kompatybilność. Akcesoria pasują tylko do określonych modeli, montaż wymaga konkretnych standardów (Picatinny, Weaver, dovetail, M-LOK, KeyMod), waga akcesoriów musi być proporcjonalna do platformy, balistyczne tory celownika muszą być spójne z lufą.
Klient końcowy — sportowiec strzelecki, kolekcjoner, strzelec rekreacyjny, gracz ASG — często NIE wie, co dokładnie ma. Robi zdjęcie swojego sprzętu i chce wiedzieć:
- Co to dokładnie za model? (np. „klon AR-15 z lufą 16 cali, brak optyki, montaż Picatinny na górze")
- Jakie są zamontowane akcesoria i czy są oryginalne?
- Co mogę jeszcze dokupić, żeby to ulepszyć?
- Czy ten konkretny tłumik dźwięku (homologowany legalnie dla sportu) pasuje do mojej lufy?
Sprzedawca też ma problem: gdy klient przesyła zdjęcie z pytaniem „mam taki sprzęt, co mi polecasz", zatrudniony konsultant musi to rozpoznać manualnie. Doświadczony specjalista — 2-3 minuty. Niedoświadczony — 15 minut researchu lub odsyła do kolegi. Przy 50-100 takich zapytań dziennie, to ogromny koszt obsługi.
„Ja patrzę na zdjęcie i widzę, że to jest replika M4 z handguardem M-LOK, czerwoną kropką typu Vortex Strikefire, magazyn 30-nabojowy, składana kolba. Mój junior salesman patrzy i widzi karabinek. Tygodniami uczę nowych pracowników rozpoznawania modeli. Marzy mi się narzędzie, w które wrzucam zdjęcie i mam pełen rozkład: co to jest, jakie ma akcesoria, jakie polecane uzupełnienia z mojego katalogu."
Pozycjonowanie produktu
GunUpdate to nasz produkt własny — nie wdrożenie u klienta, tylko SaaS, który sprzedajemy w modelu subskrypcyjnym sklepom branżowym, klubom sportowym, serwisom kolekcjonerskim. Pozycjonowanie:
- B2B SaaS — klientem są firmy, nie konsumenci
- API-first — dostęp przez REST API + webhook + opcjonalny widget JavaScript do osadzenia w sklepie
- Multi-tenant — każdy klient ma swój katalog produktowy podpięty pod silnik rekomendacji
- Compliance-aware — system jest świadomy lokalnych przepisów (PL/DE/AT/CZ/...) i nie rekomenduje produktów, które są w danym kraju regulowane bez pozwolenia
Compliance — temat poważny i traktowany poważnie
Produkty w branży sportowo-kolekcjonerskiej podlegają specyficznym regulacjom różnym w każdym kraju UE (w Polsce — Ustawa o broni i amunicji + ustawy uzupełniające, w Niemczech — Waffengesetz, etc.). GunUpdate nie omija tych regulacji — wręcz przeciwnie, jest świadomy lokalnego kontekstu i pomaga sklepom oferować produkty zgodnie z prawem. System klasyfikuje produkty jako: dostępne dla każdego, wymagające pozwolenia, wymagające licencji handlowej. Rekomendacje są filtrowane przez deklarowany przez sprzedawcę profil klienta końcowego.
Architektura — dwa modele, jeden pipeline
Core systemu to dwa wytrenowane przez nas modele computer vision oraz warstwa orkiestracji łącząca ich wyjścia z katalogiem produktowym klienta:
Model 1 — Detection & Classification (DC-Model)
Pierwszy z dwóch własnych modeli. Architektura dwustopniowa: szybki detektor lokalizujący obiekty + dokładny klasyfikator do rozpoznawania konkretnego modelu.
Stopień 1 — detektor (YOLOv8)
Wykorzystaliśmy YOLOv8-Medium jako bazę, fine-tunowany na własnym datasecie z 12 klasami obiektów:
# gunupdate_yolo_classes.yaml
names:
0: platform_long # karabinek/karabin sportowy, replika ASG długa, wiatrówka
1: platform_short # pistolet sportowy, replika ASG krótka, pistolet pneumatyczny
2: optic_red_dot # kolimator typu red dot, holosight
3: optic_scope # luneta, prismatic
4: optic_magnifier # magnifier (powiększacz za kolimatorem)
5: foregrip # przedni chwyt
6: bipod # dwójnóg
7: laser_light # latarka taktyczna, wskaźnik laserowy sportowy
8: silencer_sport # tłumik dźwięku (sport, z pozwoleniem)
9: magazine # magazynek (różne pojemności i standardy)
10: stock # kolba (stała, składana, teleskopowa)
11: rail_system # widoczny system montażu Picatinny/M-LOK/KeyMod
Detektor zwraca bounding boxy + confidence + class. Trenowany na ~52 000 zdjęciach, każde ręcznie anotowane (LabelStudio, 3 anotatorów + walidator). Augmentacje: rotacje, zmiany jasności, mosaic mix-up (4 zdjęcia w jedno), random crop.
from ultralytics import YOLO
model = YOLO('yolov8m.pt') # base
results = model.train(
data='gunupdate_dataset.yaml',
epochs=120,
imgsz=1024, # wysoka rozdzielczość — detale akcesoriów
batch=16,
optimizer='AdamW',
lr0=0.001,
augment=True,
mosaic=1.0,
mixup=0.15,
copy_paste=0.1,
cls=0.5, # class loss weight
box=7.5, # box loss weight
device=[0,1,2,3] # 4× RTX 5090
)
# Walidacja:
# mAP50: 0.91, mAP50-95: 0.72 — bardzo dobry wynik na 12 klasach
Stopień 2 — klasyfikator modelu (Vision Transformer + CLIP)
YOLO mówi nam „to jest platforma długa". Ale klient chce wiedzieć, że to konkretny model w konkretnej konfiguracji. Tu wchodzi drugi model: fine-tunowany Vision Transformer na ~600 klasach produktowych.
Dlaczego ViT, a nie zwykły ResNet? Dwa powody:
- Klasyfikacja drobnych różnic — różnica między dwoma podobnymi modelami platformy to często detale na poziomie ułożenia pinów, kształtu osłony. ViT przez self-attention lepiej łapie te subtelności niż konwolucje.
- Wykorzystanie CLIP-a — bazą jest CLIP ViT-L/14, który ma pre-trening na 400M par obraz-tekst. Daje nam mocny startowy backbone.
import torch
from transformers import CLIPVisionModel, CLIPImageProcessor
class GunUpdateClassifier(torch.nn.Module):
def __init__(self, num_classes=614):
super().__init__()
self.backbone = CLIPVisionModel.from_pretrained(
"openai/clip-vit-large-patch14"
)
# Zamrażamy 80% backbone'a, fine-tunujemy tylko ostatnie warstwy
for param in list(self.backbone.parameters())[:-40]:
param.requires_grad = False
self.head = torch.nn.Sequential(
torch.nn.Linear(1024, 512),
torch.nn.GELU(),
torch.nn.Dropout(0.2),
torch.nn.Linear(512, num_classes)
)
def forward(self, pixel_values):
outputs = self.backbone(pixel_values=pixel_values)
pooled = outputs.pooler_output
return self.head(pooled)
# Dataset: ~33k zdjęć (po wycięciu z YOLO bboxów platform)
# Trening: 80 epoch, AdamW, lr=2e-5, mixed precision bf16
# Wynik: top-1 accuracy 87.3%, top-5 accuracy 96.1%
Dlaczego top-5 a nie top-1? Bo realnie, dla wielu modeli platform sportowo-kolekcjonerskich, nawet człowiek-ekspert nie odróżni dwóch podobnych klonów po jednym zdjęciu. Dlatego naszą metryką sukcesu jest top-5 accuracy: model zwraca 5 najbardziej prawdopodobnych klasyfikacji z procentami, a użytkownik wybiera prawidłową (lub zostawia AI „w niepewności" jeśli żadna nie pasuje). To realistyczny model UX dla branży.
Identyfikacja akcesoriów
Dla każdego akcesorium wykrytego przez YOLO (kolimator, luneta, foregrip, etc.) uruchamiamy mniejsze, specjalizowane klasyfikatory:
Optyka — 120 klas
Klasyfikator kolimatorów i lunet — rozpoznaje markę i model (np. „Vortex Strikefire 2 Red Dot" vs „Aimpoint PRO" vs „Holosun HS510C"). ViT-base + 8k zdjęć treningowych.
Magazynki — 45 klas
Klasyfikator magazynków po standardzie (STANAG, AK, glock-style) i pojemności (10/15/20/30 nabojowy). Często widoczne tylko pod ostrym kątem — augmentacje rotacyjne.
Rail systems — 8 klas
Klasyfikacja widocznego systemu montażu: Picatinny, Weaver, M-LOK, KeyMod, dovetail 11mm, dovetail 3/8", proprietary. Kluczowe dla rekomendacji.
Kolby — 30 klas
Klasyfikator kolb: stałe, składane, teleskopowe, sportowe regulowane. Wpływa na ergonomię i przepisy w niektórych krajach.
Model 2 — Compatibility Recommender (CR-Model)
Drugi z dwóch własnych modeli. To miejsce, gdzie GunUpdate dostaje swoją przewagę konkurencyjną. Bo rozpoznać produkt na zdjęciu — to potrafi (mniej lub bardziej) dziś każdy CLIP. Ale poprawnie zarekomendować, co dokupić, żeby to faktycznie pasowało — to wymaga bardzo specyficznej wiedzy domenowej.
Co to znaczy „kompatybilne"
W tej branży kompatybilność ma wiele wymiarów:
- Fizyczna — system montażowy musi się zgadzać (Picatinny rail → tylko montaż Picatinny / M-LOK). Średnice gwintów lufy muszą być zgodne (różne standardy 1/2"-28, 5/8"-24, M14×1).
- Wagowa — platforma 3 kg z lekkim handguardem nie pociągnie dwóch kilowych akcesoriów z przodu.
- Balistyczna — dla strzelectwa precyzyjnego luneta i kaliber muszą być dobrane do dystansu. Luneta 1-4x nie ma sensu przy lufie 24" do strzelectwa długodystansowego.
- Logiczna — nie ma sensu kupować drugiego kolimatora, jeśli jeden już jest. Magnifier ma sens tylko jeśli jest kolimator.
- Regulacyjna — niektóre akcesoria w niektórych krajach wymagają osobnych pozwoleń. To filtrowane na warstwie compliance.
- Stylistyczna — kolory, wykończenia (czarny / FDE / Cerakote bronze) — drobiazg, ale dla użytkowników się liczy.
Hybryda — embedding-based + reguły
Model CR jest hybrydą:
Jak działa knowledge graph kompatybilności
Zbudowanie tego grafu zajęło ~4 miesiące. Każdy produkt ma węzeł z atrybutami:
// Węzeł produktu
CREATE (p:Product {
sku: "VRT-STR2-RD",
name: "Vortex Strikefire II Red Dot",
category: "optic_red_dot",
mount_type: ["picatinny_1in_ring"],
weight_g: 218,
height_cot: 40, // height over centerline of tube
battery_required: true,
battery_type: "CR2",
reticle: "4_MOA_dot",
illumination_levels: 10,
parallax: "infinity",
recommended_distance: "0-200m",
msrp_eur: 199,
regulatory_class_de: "free",
regulatory_class_pl: "free",
regulatory_class_at: "free"
})
// Relacje kompatybilności
MATCH (p:Product {sku: "VRT-STR2-RD"})
MATCH (pl:Platform {has_rail: "picatinny", min_rail_length_cm: 10})
CREATE (p)-[:FITS_ON {confidence: 0.98}]->(pl)
// Relacja kanibalizacji
MATCH (a:Product {category: "optic_red_dot"})
MATCH (b:Product {category: "optic_red_dot"})
WHERE a.sku <> b.sku
CREATE (a)-[:CANNIBALIZES]-(b)
// Relacja synergii
MATCH (rd:Product {sku: "VRT-STR2-RD"})
MATCH (mag:Product {category: "optic_magnifier"})
CREATE (rd)-[:SYNERGIZES_WITH {boost: "long_range_capability"}]->(mag)
Dla rekomendacji uruchamiamy Cypher query, które startuje od rozpoznanej platformy + akcesoriów i przechodzi po krawędziach:
Pipeline rekomendacji
Dataset — najtrudniejsza część projektu
Dla całej branży nie istnieje publiczny dataset komputerowo-wizyjny taki, jaki nam był potrzebny. Musieliśmy zbudować własny.
Źródła zdjęć
- Strony producentów — ~18 000 zdjęć produktowych (z odpowiednim opisem, idealne dla treningu klasyfikatora)
- Sklepy partnerskie — ~22 000 zdjęć z katalogów (klienci pilotażowi udostępnili swoje katalogi)
- Aukcje i platformy sportowe — ~31 000 zdjęć (gdzie regulacje pozwalają — głównie publiczne ogłoszenia branżowe)
- Zdjęcia użytkowników — ~14 000 zdjęć (oddane przez beta-testerów, anonimizowane, z odpowiednią zgodą)
Łącznie: ~85 000 zdjęć. Po deduplikacji i filtracji: ~71 000 użytecznych do treningu.
Anotacja
Tu nie da się oszukać — anotacja musi być wykonana przez ekspertów. Wynajęliśmy 3 osoby z branżowym doświadczeniem (instruktorzy strzelectwa sportowego, jeden serwisant, jeden kolekcjoner historycznych) na 6-miesięczny projekt anotacji. Każde zdjęcie:
- Bounding boxy dla wszystkich obiektów (YOLO)
- Klasa modelu platformy + akcesoriów (jeśli widoczna)
- System montażowy (jeśli widoczny)
- Notatki specjalne (np. „custom build", „modified", „replika")
Każde zdjęcie anotowane przez 2 niezależnych anotatorów. Konflikty rozwiązywał trzeci. Inter-annotator agreement: 89% dla klas modeli, 96% dla bounding boxów.
Aspekt etyczny i prawny
Wszystkie zdjęcia użyte do treningu pochodzą z legalnych źródeł, z zachowaniem praw autorskich (zdjęcia własne klientów pilotażowych, zdjęcia producentów za zgodą, ogłoszenia publiczne w ramach fair use w celach researchu). Model NIE jest trenowany do rozpoznawania broni niedostępnej publicznie ani do obchodzenia regulacji. Wręcz przeciwnie — kluczowy element systemu (Compliance Layer) ma pomagać sklepom oferować zgodne z prawem rekomendacje.
Architektura SaaS — multi-tenant od pierwszego dnia
Struktura tenantów
Każdy klient (sklep, klub, serwis) to osobny tenant ze swoim:
- Katalogiem produktowym — synchronizowanym z ich systemem (Shopify, WooCommerce, Magento, custom)
- Polityką cenową — pełne ceny, ceny po rabacie dla zalogowanych, ceny B2B
- Profilem regulacyjnym — kraj operacji + licencjonowane kategorie
- Brandingiem widgetu — kolory, logo, customowy CSS
- Limitami API — w zależności od planu subskrypcyjnego
API
POST /v1/analyze
Authorization: Bearer {tenant_api_key}
Content-Type: multipart/form-data
{
"image": [binary],
"user_profile": {
"country": "PL",
"license_class": "sport_shooter", // optional
"previous_purchases": ["SKU-1", "SKU-2"] // optional
},
"options": {
"max_recommendations": 10,
"include_compatible_only": true,
"language": "pl"
}
}
// Response:
{
"analysis_id": "ana_abc123",
"processing_time_ms": 1432,
"detected": {
"platform": {
"type": "platform_long",
"model_candidates": [
{"id": "ar15-clone-16in-mlok", "confidence": 0.81, "name": "AR-15 clone, 16\" barrel, M-LOK handguard"},
{"id": "ar15-clone-16in-keymod", "confidence": 0.12, "name": "AR-15 clone, 16\", KeyMod handguard"}
]
},
"accessories": [
{"category": "optic_red_dot", "model": "vortex-strikefire-2", "confidence": 0.92},
{"category": "magazine", "model": "stanag-30rd", "confidence": 0.97}
],
"missing_recommended": ["foregrip", "sling", "bipod"]
},
"recommendations": [
{
"sku": "MAG-FG-MLOK-BLK",
"name": "Magpul M-LOK MOE Forward Grip, Black",
"price_eur": 35.90,
"compatibility_score": 0.97,
"reasoning": "Bezpośredni montaż na widocznym handguardzie M-LOK. Lekki (88g), nie wpływa znacząco na balans.",
"image_url": "...",
"buy_url": "..."
},
// ...
],
"compliance_notes": {
"country": "PL",
"all_compliant": true,
"warnings": []
}
}
Widget JavaScript dla sklepów
Dla sklepów, które nie chcą integrować się przez API, oferujemy gotowy widget JS do osadzenia:
<!-- W sklepie internetowym, np. na stronie produktu -->
<script src="https://cdn.gunupdate.com/widget/v1.js"></script>
<div id="gunupdate-widget"
data-tenant="abc123"
data-style="card"
data-color="#d97706"></div>
<script>
GunUpdate.init({
onProductRecommended: function(product) {
// Dodaj do koszyka, śledzenie itp.
console.log('Polecono:', product.sku);
}
});
</script>
Widget renderuje przycisk „📸 Wrzuć zdjęcie swojego sprzętu", po kliknięciu otwiera upload, wysyła do API i wyświetla rekomendacje inline.
Stack i infrastruktura
Stack techniczny
- PyTorch (modele)
- YOLOv8 (detektor)
- CLIP ViT-L/14 (backbone klasyfikatora)
- Triton Inference Server
- ONNX (export modeli)
- FastAPI
- Node.js (orkiestracja)
- Neo4j (knowledge graph)
- PostgreSQL (tenant data)
- pgvector (embeddings)
- Redis (cache + queue)
- S3-compatible (zdjęcia)
- Cloudflare (CDN widget)
- Stripe (billing)
- 4× RTX 5090 (trening)
- 2× RTX 4090 (inference produkcja)
Inference w produkcji
Modele eksportowane do ONNX, serwowane przez Triton Inference Server na 2 maszynach inference z 2× RTX 4090 każda. Średni czas analizy zdjęcia: 1.4-1.6 sekundy (cała ścieżka: upload → YOLO → klasyfikator platformy → klasyfikatory akcesoriów → query KG → re-ranker → compliance → Claude opis → response). Throughput: ~350 req/min per maszyna.
Model biznesowy
GunUpdate jest sprzedawany w trzech planach:
| Plan | Cena (€/mies) | Analiz/mies | Dla kogo |
|---|---|---|---|
| Starter | 149 | 500 | Mały sklep specjalistyczny, klub sportowy |
| Pro | 449 | 3 000 | Średni sklep z aktywnym ruchem online |
| Enterprise | 1 199+ | nielimitowane | Duży sklep / sieć, customowy katalog, SLA |
Aktualnie (styczeń 2026) mamy 23 płacących tenantów w 5 krajach (PL, DE, AT, CZ, SK) i lej dalej w sprzedaży. Średni MRR rośnie.
Co dalej — roadmap produktowa
- Mobile-first widget — natywna integracja w aplikacjach sprzedawców
- Video analysis — analiza wideo, nie tylko zdjęć (rosnący trend w branżowych unboxingach)
- 3D reconstruction — z kilku zdjęć budujemy model 3D platformy → wirtualny configurator
- Aukcyjne API — moduł dla platform aukcyjnych — automatyczna kategoryzacja i wycena na podstawie zdjęć
- Wholesale catalog matching — analiza zdjęć z hurtowych ofert → automatyczne dopasowanie do SKU dystrybutora
Czego nauczyliśmy się przy GunUpdate
1. Domena ekspercka > każda generyczna AI
CLIP wytrenowany na 400M parach obraz-tekst potrafi odpowiedzieć „to wygląda jak karabin sportowy". Ale nie potrafi powiedzieć, czy ten konkretny handguard to M-LOK czy KeyMod. Dla tej wiedzy potrzebny jest dedykowany dataset i dedykowany model. Generyczne AI to budulec, nie produkt.
2. SaaS multi-tenant od dnia 1 ratuje miesiące refaktoringu
Wiele zespołów startuje z mono-tenant prototypem i potem rok refaktoruje na multi-tenant. My zaczęliśmy od architektury multi-tenant od pierwszego dnia. Trochę więcej kodu na początku, ale od pierwszego klienta system był produkcyjny.
3. Compliance jako feature, nie jako blokada
Wiele firm w „regulowanych" branżach unika tych branż jak ognia. My zrobiliśmy odwrotnie — uczyniliśmy z compliance główny feature produktu. Klienci doceniają, że nasze rekomendacje są per-country aware i nie wpędzają ich w problemy.
4. Anotacja przez ekspertów branżowych = przewaga
Outsourcing anotacji do Mechanical Turk dałby nam dataset, w którym 30% etykiet byłoby błędnych. Wynajęcie 3 ekspertów branżowych na 6 miesięcy kosztowało niemało, ale jakość datasetu skoczyła z „użyteczny na demo" do „użyteczny w produkcji". To nie wszędzie się sprawdza, ale w wąskich domenach — bez tego nie da się.
5. Knowledge graph + ML > samo ML dla rekomendacji
Czysty „neural recommender" nauczyłby się powierzchownych korelacji. Knowledge graph daje twarde reguły kompatybilności (te 2 elementy fizycznie się nie połączą), które ML musi szanować. Hybryda twarde reguły + miękkie sygnały dała nam wyniki, których pure ML by nie osiągnął.
Jakie technologie z tego wdrożenia mogą Ci się przydać
GunUpdate to nasz produkt, ale ta sama architektura — YOLO + ViT + Knowledge Graph + Claude jako orkiestrator — działa wszędzie tam, gdzie:
- Jest katalog setek/tysięcy produktów z relacjami kompatybilności (motoryzacja, sprzęt fotograficzny, sprzęt audio, komputery, sport)
- Klienci wrzucają zdjęcia swojego sprzętu i potrzebują „doradztwa"
- Manualna obsługa pochłania duże zasoby konsultantów
- Wiedza ekspercka istnieje, ale nie jest skodyfikowana
Chcesz computer vision dla swojej branży?
GunUpdate to dowód, że potrafimy budować własne modele AI dla wąskich domen. Buduliśmy go od zera — własny dataset, własne modele, własna infrastruktura SaaS. Tę samą metodologię możemy zastosować u Ciebie.
Porozmawiajmy o Twoim projekcie →