FImageSearch: мультимодальний пошук для AI-агента-стиліста

Кейс

Клієнт будував персонального AI-стиліста в месенджерах: надсилаєш йому street-style фото — він знаходить кожну річ образу в каталозі магазину. Агентові-стилісту потрібне пошукове ядро, яке можна викликати, — і цей проєкт саме воно: shop-the-look рушій, що знаходить кожну річ на фото й шукає її серед 105 100 товарів каталогу за пару сотень мілісекунд. Фото, текст, фото + текстове уточнення, ручний кроп — усі чотири режими запитів живуть в одному векторному просторі. Перше робоче демо запустилося за один вечір.

Перше демо за вечір105 100 товарів в індексіВесь образ за ~100–200 мс< 3 GB VRAM

Записано з телефона на живому демо: аналіз усього образу, відсотки збігу, ручний кроп і текстове уточнення на реальному каталозі у 105 тисяч товарів.

Відкрити живе демо

Демо працює на GPU-боксі, який орендується за запитом, тож між показами воно спить — якщо посилання не відкривається, напишіть мені, і я його розбуджу.

Головний екран FImageSearch і street-style образ, розібраний на 7 речей
Результати пошуку, згруповані за речами, з відсотками збігу
Ще один образ з автодетекцією та результати пошуку сумки
Режим ручного кропу з рамкою навколо речі
Чоловічий образ і знайдені майки з чоловічого розділу
1 / 5
Snap it or describe it: завантажуєте фото (або обираєте пресет) — автодетекція знаходить кожну річ. Цей образ: 7 речей, проаналізовано за 208 мс.

Цифри

105 100
Каталог в індексі
повний публічний датасет H&M (Kaggle, 2022)
74–225 мс
Аналіз усього образу
детекція + ембединг + пошук, до 7 слотів
16–26 мс
Простий пошук
текстовий або один кроп
768-d
Ембединги
~271 MB на весь каталог
< 3 GB
Пам’ять GPU
усі три моделі резидентно у VRAM
~$64/міс
Вартість інфри
орендований GPU-бокс + Cloudflare Tunnel

Як фото стає ранжованими результатами

Один HTTP-запит проганяє весь пайплайн. Головний фокус — батчинг: усі кропи речей плюс кроп людини ембедяться одним GPU-проходом, а всі слоти йдуть у векторну базу одним батчевим запитом.

photo ──▶ person detection            RT-DETRv2, ~15 ms
      ──▶ garments in person crop     YOLOS-Fashionpedia, 46 classes
      ──▶ 9 slots, head to toe        headwear → … → shoes, max 7 per look
      ──▶ ONE GPU batch               all crops + person, fashionSigLIP, 768-d
      ──▶ ONE batched Qdrant query    hard filters: group / category / gender
      ──▶ CIELAB color re-rank ──▶ ranked results with % match

Самої векторної схожості мало — пошук гібридний. Поверх кожного запиту стоять жорсткі метафільтри: кроп черевика шукає лише в Shoes, чоловічий образ — лише в чоловічих розділах, а «курткові» категорії виключені зі слотів топів, щоб багатошаровий образ не тонув у пуховиках. Уже всередині цих меж вектор ранжує за схожістю.

Чого моделі не вміли з коробки

Найцікавіша інженерія — у прірві між «ембединги працюють» і «результати виглядають правильно». Усе нижче знайдено на реальних фото й виправлено вимірюваннями, а не на око:

SigLIP майже не бачить колір базових речей

Чорна й бежева базові футболки відрізняються на Δcos ≈ 0.01 — навіть на чистому лоскуті тканини. Фікс: передрахований домінантний CIELAB-колір усіх 105 тисяч товарів і колірний ре-ранк (вага 0.12, світлота в пів ваги — юзерські фото живуть у тінях, а каталог у студійному світлі).

Каталог перекошує голосування про стать

Перша спроба визначати стать — голосуванням за видачею — зайшла в глухий кут: каталог 3:1 жіночий, тож чоловічі кропи легітимно тягнуть жіночі речі. Фікс: zero-shot проба — кроп людини проти текстових якорів «a man» / «a woman» у тому самому батчі. ~2 мс, 7/7 на референсних фото.

Телефон читається як окуляри

У дзеркальних селфі fashion-детектор бачить телефон на рівні обличчя як окуляри (слот повертав чохли для телефонів). Фікс: бокси cell phone з того самого проходу детектора людей — нуль додаткової вартості — глушать окуляри/головні убори, що з ними перетинаються.

Паддинг затягує куртку в футболку

Топ під розстебнутою курткою погано ембедиться з контекстним відступом — кроп затягує блейзер і повертає жакети. Перевірено свипом: багатошарові топи ембедяться взагалі без паддингу, зі зниженим порогом прийняття.

Пара взуття — це здебільшого асфальт

Union-бокс навколо обох туфель у кроці — переважно дорожнє покриття, яке отруює ембединг. UI підсвічує обидві туфлі, але ембедиться лише більша й менш перекрита.

Сирі косинуси не мають візуального сенсу

Текстові й картиночні косинуси живуть у різних діапазонах; лінійний clamp показував усім результатам рівно 100%. Фікс: логістична калібровка на модальність — бейдж «97% match» реально ранжує видачу й ніколи не досягає ста.

Що я збудував

Двостадійна детекція

RT-DETRv2 знаходить людей і обирає головну; YOLOS-Fashionpedia (46 класів одягу) працює всередині її кропу — 2–4× ефективної роздільності на дрібних речах на кшталт окулярів і взуття.

Таксономія образу на 9 слотів

Детекції збираються у слоти «з голови до ніг» (головний убір → взуття) з правилами для конфлікту «сукня чи топ+низ», багатошарових образів і слот-специфічного паддингу кропів — усе відкалібровано свипами на референсних фото.

Один спільний векторний простір

marqo-fashionSigLIP кладе зображення й текст в один косинусний простір на 768 вимірів. Фото + «but in red» — зважена сума векторів (0.6 фото + 0.4 текст), а мультимовні запити працюють безкоштовно.

Гібридний пошук поверх Qdrant

Батчеві запити з жорсткими payload-фільтрами на слот (група, категорія, розділ статі) плюс keyword-індекси — векторна схожість ранжує лише в межах правильної полиці магазину.

Індексація, що пережила смерть сервера

Ембединги зберігаються інкрементальними шардами; індекс відновлюється без ре-ембедингу. Перший GPU-бокс фізично знищили посеред проєкту, потім усе мігрувало Німеччина → Польща → Каліфорнія — без жодного повторного GPU-прогону.

Фронтенд із чесним UX

Mobile-first UI на Next.js 14: автоаналіз при завантаженні, точки на фото, синхронізовані з рядками результатів, ручний кропер, % на кожній картці й банер «точного збігу нема — ось найближчі» замість вдавання.

Стек

Python · FastAPI · PyTorch fp16 · open_clip · marqo-fashionSigLIP · RT-DETRv2 · YOLOS-Fashionpedia · Qdrant · Next.js 14 · Tailwind + shadcn/ui · Vast.ai GPU · Cloudflare Tunnel + R2

Потрібен візуальний пошук по вашому каталогу?

Ядро не прив’язане до домену: детектор → слоти → ембединги → фільтрований векторний пошук → ре-ранк. Сьогодні це мода; меблі, інтер’єри чи будь-який візуальний каталог — тиждень калібрування. Якщо вашому продукту потрібне «знайди мені отаке» — напишіть.

Зв’язатися

Соло-проєкт, липень 2026. Демо на публічному датасеті H&M з Kaggle (2022); ціни в демо ілюстративні. Клієнт і комерційні деталі — під NDA.

Read this case study in English