Каталог, що читається в реальному часі, без ключів і без плагіна
Для WooCommerce ми використовуємо Store API, публічний інтерфейс магазину: `/wp-json/wc/store/v1/products`, 100 товарів на сторінку, максимальний час очікування 20 секунд, власний ідентифікатор клієнта в заголовку та прийняття виключно коду 200. Кількість сторінок ми читаємо із заголовка `x-wp-totalpages`, а загальну кількість товарів — з `x-wp-total` — ми не перегортаємо сторінки, доки не видамо себе. Першу сторінку беремо окремо, решту — паралельно, з лімітом у 30 сторінок. У магазин нічого не встановлюється, і нам не дають ключі продавця.
Ціна перекладена правильно, а нуль обробляється як неопублікований
Store API повертає ціну як рядок у менших одиницях, плюс кількість десяткових знаків валюти. Ми ділимо на десять у степені цього числа, а не на фіксовані 100 — інакше будь-яка валюта з іншим числом десяткових знаків виходить неправильно, і ніхто цього не помічає. Нуль стає `null`, а у відповіді з’являється «ціна за запитом — підтверджується колегами», разом із явною інструкцією, даною агенту, не вигадувати і попросити підтвердження в колеги. Ціна йде одразу у двох формах: готовий до показу текст для інтерфейсу та число для логіки ззаду.
Три інструменти, які агент може викликати
У платформі асистентів каталог експонується як три вбудовані інструменти — пошук за словами, зіставлення за приладом або варіантом використання, і отримання продукту за ідентифікатором. Агент бачить їх під назвами `catalog_cauta`, `catalog_potrivire` і `catalog_produs`, кожен зі своїми оголошеними параметрами. Коли платформа магазину не та, що очікувалася, або бракує адреси, інструмент явно відмовляє замість того, щоб повертати порожній список, який був би інтерпретований як «у нас немає продукту».
Сполучні слова не псують результат
«Filtru de apă» при буквальному пошуку підбирає все, що містить «de». У доставленому пункті каталогу та в пошуку з голосового віджета ми відсікаємо стоп-слова — `si`, `sau`, `de`, `din`, `la`, `cu`, `pe`, `in`, `pentru` — і, якщо після відсікання не залишається нічого корисного, повертаємося до слів довших за дві літери. Частковий збіг має поріг: продукт потрапляє в результати лише якщо збігається щонайменше з половиною слів, що залишилися.
Коли в магазину немає інтерфейсу, ми читаємо сторінку
Не кожен магазин має Store API. Для решти у нас є екстрактор, який відкриває сторінки списків і читає їхні картки товарів, з бюджетом, записаним у коді: максимум 20 сторінок списку, 200 продуктів, 24 сторінки деталей, 50.000 символів HTML на сторінку, 5 секунд на запит і граничний термін 45 секунд на всю операцію. Спочатку читає структуровані дані типу product зі сторінки, потім картки, потім метадані для поширення — саме в такому порядку, бо перше джерело — те, яке магазин написав навмисно.
Свіжість із записаними межами, а не з надією
Каталог тримається в пам’яті 10 хвилин на магазин, а одночасні запити до одного й того самого магазину зливаються в один, щоб десять клієнтів, які питають в один і той самий момент, не спричинили десять завантажень. На публічному пункті каталогу відповідь несе також інструкцію кешу для мережі доставки: 5 хвилин свіжий, ще 10 хвилин подається старий, поки оновлюється у фоновому режимі. Кількість повернених результатів обмежена 20, зі значенням за замовчуванням 6.
Замовлення, кошик і зв’язок із системою управління
Кошик, надсилання замовлення і передача його до системи управління клієнта — це окремі функції, не форма. Є також відновлення покинутих кошиків, замовлення через розмову і відстеження стану замовлення, з двома запланованими завданнями, що виконуються кожні 15 хвилин — одне синхронізує результат замовлень, друге доповнює стани в системі управління на вікні двох днів назад і одного дня вперед.
Платежі: що працює і що ні
Працює і є в коді: інтерфейс MAIB для торговців — токен, потім запит на платіж, із обліковими даними кожного магазину, прочитаними з бази даних, і функцією, явно активованою — та Stripe, із сумою, конвертованою в менші одиниці, і зарахуванням, збереженим в обліку. Що НЕ працює, щоб не було сюрпризів: Paynet, Netopia і mobilPay не мають реалізації, і код явно відмовляє, коли їх запитують. Маршрут Moldindconbank — це каркас, який повертає помилку без облікових даних. Ми беремо це в проєкт як роботу, а не як наявну інтеграцію.
Агент не вигадує, коли мережа падає
Якщо запит до магазину не вдається, інструмент не повертає порожній список — він повертає повідомлення, яке каже агенту не формулювати відповідь про каталог. Різниця важлива: порожній список перекладається як «у нас немає», а «у нас немає», сказане помилково, втрачає замовлення так само надійно, як і неправильна ціна.