← Усі кейси
AI-автоматизація · Освітлення

Від специфікації світильників у PDF до обґрунтованої пропозиції.

Light Box — AI-асистент для комерційних пропозицій постачальника освітлення: читає специфікації світильників із тендерних PDF, підбирає відповідники в каталозі на понад 35 000 товарів із поясненням вибору і готує пропозицію до експорту.

Від специфікації світильників у PDF до обґрунтованої пропозиції.
80%швидша підготовка пропозиції
35k+товарів у єдиному каталозі
6кроків від PDF-специфікації до експорту пропозиції
20реальних проєктних специфікацій у бенчмарку
776автоматичних тестів бекенду
0рішень підбору, ухвалених LLM
Індустрія
Постачання освітлення / підготовка тендерних пропозицій
Формат
Повний цикл розробки AI-продукту (бекенд + вебзастосунок)
Ринок
Ірландія

До кожного тендеру на освітлення додається специфікація світильників: PDF з переліком усіх світильників для об'єкта, часто з кодами товарів конкурента. Кошторисники постачальника читають її рядок за рядком, шукають найближчий відповідник у власному асортименті й мусять обґрунтувати цей вибір у пропозиції. Ми створили Light Box, щоб він узяв на себе читання і пошук, а команда зосередилася на рішеннях.

Light Box читає специфікацію за допомогою AI і заповнює прогалини в керуванні, колірній температурі та аварійному освітленні з налаштувань проєкту. Рушій на основі правил звіряє кожен рядок зі спільним каталогом двох європейських виробників світильників і пояснює кожне рішення, а перевірений результат стає пропозицією з експортом в Excel, CSV або JSON. Автоматично підбираються лише однозначні рядки; решту отримує людина разом із поясненням.

З чим ми мали справу

  • Немає двох однакових специфікацій. Специфікації приходять акуратною таблицею на три сторінки, окремими блоками на кожен світильник, що разом займають одинадцять сторінок, або ховаються на десяти сторінках 141-сторінкової електротехнічної специфікації. До того ж вони містять власні помилки й прогалини: коди товарів, розірвані переносом рядка, рядки, що суперечать власному опису, позиції «TBC» і «by others».
  • Багато рядків називають чужий товар. У реальних проєктах, на яких ми тестували систему, кожен третій рядок містив світильник конкурента. Коли команда пропонує замість нього аналог із власного асортименту, вона мусить уміти його обґрунтувати, тож пошук точних кодів закриває лише частину роботи.
  • Товарні дані в різних формах. Обидва виробники по-різному структурують асортимент: від готових артикулів до таблиць опцій і конфігурованих товарів. До того ж кожен виробник, як і кожна специфікація, називає ті самі речі своїми словами.
  • Ідеальна оцінка може нічого не значити. Товар із відсутніми даними нічому не суперечить, тож наївний рушій вважає його ідеальним відповідником. Завищення специфікації обходиться не дешевше: аварійний модуль чи драйвер з регулюванням яскравості, не передбачені специфікацією, змінюють і технічні вимоги, і ціну.

Як ми це вирішили

  • AI-екстракція за фіксованою схемою. Один структурований виклик AI читає PDF зі специфікацією і відповідає за фіксованою схемою, згенерованою з моделі даних самого рушія підбору: 28 полів на рядок, від категорії та ступеня захисту IP до колірної температури, керування та аварійного освітлення. Зчитування і підбір послуговуються одним словником, а для кожного заповненого значення AI наводить цитату з вихідного тексту, яка зберігається разом із сирим результатом екстракції.
  • Люди перевіряють, кожне значення позначене. Кошторисники звіряють витягнуті рядки з оригінальним PDF, редагують будь-яку клітинку, додають, дублюють чи видаляють рядки. Кожне значення має мітку: прочитане з документа, підставлене з налаштувань проєкту, введене вручну або досі відсутнє, а налаштування проєкту лише заповнюють прогалини й ніколи не перезаписують специфікацію.
  • Рушій підбору, що пояснює кожне рішення. Кожен рядок проходить дев'ять упорядкованих перевірок, від точного коду товару та назви серії до категорії, доказів і фінального арбітражу, і завершується іменованим результатом з повним журналом рішення. Оцінки — це прості формули на основі даних каталогу, а не думка LLM. Якщо товар не визначено однозначно точним кодом, рушій схвалює його автоматично, лише коли він відповідає рядку, дані каталогу дозволяють повноцінне порівняння і він явно переважає найкращу альтернативу з іншої серії; майже рівні варіанти перетворюються на короткі запитання замість здогадок.
  • Два виробники, один каталог. Ми звели асортимент обох виробників в один каталог на понад 35 000 товарів, описаних єдиним набором стандартних полів і розподілених за 23 товарними категоріями клієнта. Спільний словник із 163 аліасів перекладає термінологію кожного виробника, а джерело кожного значення зберігається.

Вимірний результат

  • На 80% швидша підготовка пропозиції. Кошторисники більше не передруковують специфікації й не шукають вручну у двох каталогах. Вони починають із витягнутих рядків і ранжованих варіантів підбору та зосереджуються на позиціях, які позначила система.
  • Підбір, який команда може обґрунтувати. Кожен запропонований світильник супроводжується переліком пройдених перевірок і поясненням, чому він кращий за альтернативи, тож пропозицію можна пояснити проєктувальнику позиція за позицією.
  • Без непомітного завищення специфікації. Коли специфікація нічого не уточнює, рушій обирає простий базовий варіант, а не максимальну комплектацію, тож пропозиції відповідають вимогам і лишаються конкурентоспроможними за ціною.
  • Налаштовано на реальних проєктах. Рушій налаштовується на бенчмарку з 20 реальних проєктних специфікацій (загалом 588 рядків). У ході налаштування, разом із додаванням каталогу другого виробника, кількість автоматично схвалених аналогів на цьому бенчмарку зросла з 9 до 78.

Під капотом

  • Екстракція Нативний PDF-вхід в Anthropic Claude зі structured output, обмеженим схемою, яку згенеровано з Pydantic-моделі рядка рушія та закритих enum зі спільного реєстру полів; захисна перевірка одразу зупиняє процес, якщо в реєстрі є значення, якого промпт не пояснює. Фонові воркери валідують файл перед платним викликом, повторюють запити після тимчасових збоїв із backoff і логують токени та орієнтовну вартість кожного запуску.
  • Підбір Доменно-незалежна драбина з дев'яти впорядкованих політик: перемагає перше термінальне рішення, а кожна оцінка логується. Відповідність, покриття і порівнюваність обчислюються в коді разом із запасом переваги над найкращою альтернативною родиною товарів, а ідентичність коду товару оцінюється за рівнем упевненості. Набір правил версіонується, а його версія фіксується в кожній пропозиції підбору.
  • Дані PostgreSQL 16 із триграмним пошуком. Адаптери для кожного виробника нормалізують сирі записи до реєстру з 31 поля та 23 категорій клієнта, зберігаючи походження кожного значення й оригінальний запис у JSONB.
  • Бекенд Багатошаровий сервіс на FastAPI і Python 3.13 з обробниками команд і запитів за Unit of Work, асинхронний SQLAlchemy з двома базами PostgreSQL (застосунок і каталог) і 20 міграцій Alembic. Celery на Redis виконує екстракцію та підбір як фонові задачі. JWT-автентифікація з ротацією refresh-токенів і хешуванням argon2; пропозиції віддаються потоком у XLSX, CSV або JSON.
  • Фронтенд Next.js 16 з React 19, Tailwind 4 і shadcn. Server Components паралельно завантажують дані наперед і гідратують TanStack Query, а кожен виклик API типізовано за OpenAPI-схемою бекенду. Проксі backend-for-frontend тримає токени в httpOnly-cookie, а редагування клітинок оптимістичне з відкатом.
  • Доставка 776 автоматичних тестів бекенду в CI з ruff, mypy і pytest на справжньому PostgreSQL; пайплайн фронтенду запускає lint, typecheck і продакшн-збірку. Docker-контейнери на AWS, деплой через GitHub Actions, структуровані JSON-логи з request ID, який передається й у фонові задачі, Sentry, OpenTelemetry і Prometheus.

Що використали

  • AI
  • Anthropic Claude
  • Python
  • FastAPI
  • Next.js
  • React
  • TypeScript
  • PostgreSQL
  • SQLAlchemy
  • Celery
  • Redis
  • TanStack Query
  • Tailwind CSS
  • OpenAPI
  • Docker
  • GitHub Actions
  • AWS
  • Sentry
Ваш проєкт

Є процес, який варто покращити?

Покажіть, що відбувається зараз. Ми допоможемо визначити, що варто змінити і що варто будувати.

Обговорити проєкт