О проекте
Команда: Centras AI HUB
Кейс HackAlem.ai: Торговля — Электрокомплект · ekt.kz
Стадия: Доведённый продукт
Задача кейса: AI-консультант по каталогу ekt.kz: товары, аналоги, цены, остатки, корзина
Суть
Чат-консультант для ekt.kz в виде расширения Chrome/Edge и виджета: подбирает товары по характеристикам и бюджету, отвечает по страницам магазина, открывает карточки, добавляет в корзину и заполняет формы.
Как устроено
Скрапер собирает каталог (категория «Лампы», 89 товаров), 123 инфо-страницы и 9 филиалов в Supabase PostgreSQL с чанкингом, эмбеддингами и историей цен. Edge Function на Deno вызывает OpenAI с 12 инструментами (поиск товаров, фасеты, база знаний, филиалы, create_lead, navigate_to, highlight, click_element, fill_form, suggest_replies) и стримит ответ через SSE. Поиск гибридный: точный артикул, полнотекст, обработка опечаток и векторное сходство. После генерации сервер сверяет цены, ссылки и заявленные действия с результатами инструментов; действия на странице ограничены allow-list.
Ключевые решения
- function calling (12 инструментов)
- гибридный поиск (FTS + векторы + опечатки)
- SSE-стриминг
- hallucination guard
- UI-действия на сайте через расширение MV3
- скрапинг и история цен
- rate limiting
- eval-сценарии и E2E
Особенности
Агент действует прямо на живом ekt.kz через браузерное расширение (навигация, подсветка, «Купить», заполнение форм) с отменой действий и allow-list; ночное обновление цен в CI и проверка ответа модели на соответствие данным инструментов.
Стек
TypeScript · Supabase · PostgreSQL · Deno Edge Functions · Chrome Extension MV3 · Vercel · GitHub Actions
Модели
OpenAI API
Проект создан за 5 часов на финале хакатона HackAlem.ai (23 сентября 2026, Астана). Код — BAITC-Hacks/hack-b0093e63-centras-ai-hub.
README
README.mdEKT AI-консультант
ИИ-консультант для интернет-магазина электротехники ekt.kz. Проект команды Centras AI HUB для хакатона BAITC.
Консультант помогает подобрать товар, узнать характеристики и условия покупки, найти филиал и подготовить заявку. Он использует данные каталога и информационных страниц магазина, а при подключении к ekt.kz умеет выполнять ограниченный набор действий на странице.
Текущий формат демонстрации — расширение Chrome/Edge. У команды сейчас нет доступа к среде сайта для прямого внедрения, поэтому расширение подключает консультанта к ekt.kz в браузере проверяющего. Код сайта при этом менять не требуется. Для штатного подключения предусмотрен тот же виджет через <script>; необходимые доступы перечислены в разделе установки.
Для жюри: установить расширение · сценарий проверки · свой сервер и база · пример переменных окружения · потенциал развития.
1. Название проекта
EKT AI-консультант (ekt-ai-consultant в package.json).
2. Какую проблему решает проект
Проблема. Покупатель приходит в магазин с практической задачей: подобрать лампу для дома, уложиться в бюджет, оформить заказ или вернуть неподошедший товар. Чтобы решить её через сайт, нужно самостоятельно разобраться в характеристиках, найти подходящие позиции и цены, затем найти нужную кнопку, форму и условия покупки или возврата. Например, при выборе лампы важно одновременно учесть цоколь, мощность и температуру света, а при возврате — понять порядок обращения и передать магазину сведения о покупке. Неясность на любом шаге затрудняет завершение задачи и может потребовать обращения к менеджеру.
Как проект решает эту проблему. EKT AI-консультант сопровождает покупателя от вопроса до действия на сайте в одном диалоге. Он помогает уточнить запрос, ищет товары по характеристикам и бюджету, показывает цены и ссылки из загруженного каталога, отвечает по информационным страницам магазина. По просьбе покупателя агент выполняет доступные шаги сценария:
- Подбор и покупка: открывает выбранный товар, подсвечивает цену и характеристики, нажимает «Купить» для добавления в корзину, помогает перейти к корзине или открывает форму «Купить в 1 клик» и заполняет контактные данные.
- Обращение по возврату: открывает условия возврата, показывает нужный раздел, открывает общую форму «Оставить заявку» и заполняет контакты и текст обращения сведениями, которые сообщил покупатель: товар, номер заказа, дата покупки и причина возврата.
- Помощь на странице: вводит запрос в поиск и запускает его, показывает способы оплаты, находит контакты филиала и подсвечивает телефон. Если требуется участие менеджера, может сохранить контакт и описание потребности в базе проекта.
Таким образом, агент помогает подготовить заказ или обращение по возврату непосредственно на сайте. Отправку форм и оплату выполняет покупатель; решение по возврату принимает магазин.
Ценность для покупателя:
- Можно описать потребность своими словами и уточнять выбор в диалоге, сохраняя контекст предыдущих вопросов.
- Товар, его характеристики, цена и условия покупки доступны в рамках одного сценария; ссылки позволяют сверить ответ с источником.
- Помощь продолжается после выбора товара: агент выполняет переходы, добавляет товар в корзину и помогает заполнить форму заказа или обращения по возврату. Покупатель сохраняет контроль: переход и нажатие можно отменить, а заполненные данные — проверить перед отправкой.
Ценность для магазина. Консультант помогает покупателю пройти путь от подбора до подготовки заказа и разобраться с обращением после покупки. Типовые вопросы о товарах, условиях покупки и филиалах можно обслуживать через диалог, а в форму обращения передавать уже собранные сведения о потребности или причине возврата. Отдельный инструмент сохраняет заявку с контактами в базе проекта для дальнейшей работы сотрудника. Решение рассчитано на розничных и оптовых покупателей; текущая демонстрация использует категорию «Лампы» и подключается через расширение без изменения сайта.
Примеры результата:
- «Нужна лампа E27 с тёплым светом до 1000 тенге» → подбор → открытие карточки → добавление в корзину → помощь с подготовкой заказа.
- «Хочу вернуть лампу» → условия возврата → уточнение сведений о покупке → открытая и заполненная форма обращения, которую покупатель проверяет и отправляет.
Ценность прототипа — помощь в прохождении этих действий в контексте одного диалога. Влияние на конверсию, время оформления и нагрузку менеджеров предстоит измерить в пилоте.
3. Что реализовано
| Возможность | Реализация |
|---|---|
| Подбор товаров | Поиск по запросу и артикулу; фильтры по бренду, категории, бюджету и характеристикам. Карточки с ценой, артикулом и ссылкой на источник. |
| Ответы о магазине | Поиск по информационным страницам: оплата, доставка, возврат, оформление заказа; отдельный инструмент для адресов и контактов филиалов. |
| Диалог | Потоковый ответ, контекст предыдущих сообщений, подсказки для продолжения, оценки ответов. Интерфейс и инструкции для русского, казахского и английского языков. |
| Действия на сайте | Переход к товару или служебной странице, подсветка элементов, заполнение и отправка поиска, нажатие «Купить», открытие и заполнение разрешённых форм. Перед переходом и нажатием есть возможность отмены. Формы заявки и покупки в один клик пользователь отправляет самостоятельно. |
| Заявка менеджеру | Инструмент create_lead записывает контакт и запрос в таблицу ekt.leads. Промпт требует согласия покупателя; сервер проверяет телефон и ограничивает число заявок. |
| Подключение к сайту | Виджет через <script> и распаковываемое расширение Chrome/Edge Manifest V3. История диалога восстанавливается после переходов. |
| Подготовка данных | Скрапер HTML, загрузка в базу, разбиение страниц на фрагменты, эмбеддинги, журнал обновлений и история изменения цен. |
| Проверки | Модульные тесты, проверка типов, smoke-тест API, набор eval-сценариев, браузерные E2E-сценарии и конфигурация CI. |
Реализация функций не означает, что все сценарии проходят без ошибок: результаты сохранённых прогонов и ограничения приведены ниже.
В сервере реализовано 12 инструментов, доступных модели — см. tools.ts:
| Инструмент | Конкретная функция |
|---|---|
search_products | Найти товары по запросу с фильтрами по цене, бренду, категории и характеристикам |
get_product | Получить подробную карточку конкретного товара |
category_facets | Узнать, какие характеристики и значения есть у товаров выбранной категории |
list_categories | Получить корневые разделы и подкатегории каталога |
search_knowledge | Найти фрагменты информационных страниц с заголовками и ссылками |
get_branches | Найти адрес, телефон, email и часы работы филиала по городу |
create_lead | Сохранить заявку с контактами и потребностью в базе проекта |
navigate_to | Открыть разрешённую страницу ekt.kz, например карточку товара или условия возврата |
highlight | Подсветить цену, характеристики, телефон, кнопку или другой разрешённый элемент |
click_element | Нажать «Купить», выполнить поиск либо открыть форму заявки или покупки в один клик |
fill_form | Заполнить разрешённые поля поиска, заявки или покупки в один клик; формы обращения не отправляются автоматически |
suggest_replies | Показать варианты следующего сообщения покупателя |
Что агент может сделать непосредственно на странице:
- Открыть найденный товар, главную страницу, категорию «Лампы», корзину, условия возврата, оплату, оформление заказа, контакты или FAQ. Переходы ограничены разрешёнными адресами ekt.kz.
- Подсветить цену, кнопку «Купить», характеристики, описание, условия возврата, способы оплаты, телефон, список товаров, поле поиска или корзину.
- Ввести запрос в поиск сайта и выполнить поиск; на карточке товара нажать «Купить» для добавления в корзину.
- Открыть «Оставить заявку» и заполнить имя, email, телефон и текст обращения; открыть «Купить в 1 клик» и заполнить имя, телефон и email. Возврат оформляется как текст обращения в общей форме заявки: отдельной формы возврата агент не создаёт.
- Предложить до четырёх вариантов следующей реплики, сохранить контекст диалога при переходе и выполнить отложенную подсветку или заполнение на открытой странице.
Нажатие «Купить» добавляет товар в корзину, но не оплачивает и не завершает заказ. Формы обращения пользователь отправляет сам. Агент не получает произвольного доступа к браузеру: доступны только перечисленные адреса, элементы и поля. Сбор каталога и обновление цен выполняются отдельными скриптами, а не во время каждого сообщения покупателя.
4. Как работает решение
Пример запроса: «Нужна светодиодная лампа E27, тёплый свет, до 1000 тенге».
- Покупатель открывает виджет и отправляет сообщение. Виджет передаёт текст, идентификатор диалога и контекст страницы в API чата.
- Сервер добавляет историю диалога и инструкции консультанта. Модель выбирает инструменты: например, поиск товаров или получение карточки по артикулу.
- Инструменты получают сведения из PostgreSQL. Поиск объединяет точное совпадение артикула, полнотекстовый поиск, обработку опечаток и векторное сходство.
- Модель формирует ответ на основе найденных данных. Виджет получает текст через SSE и отображает карточки найденных товаров.
- По следующей просьбе — например, «Открой карточку» — сервер может передать разрешённое действие интерфейсу. На ekt.kz виджет выполняет его; на отдельной демостранице переход к ekt.kz предлагается ссылкой.
- Если вопрос требует участия менеджера, консультант может собрать данные для заявки. Запись заявки в БД и заполнение формы на сайте — разные механизмы; отправка формы остаётся за покупателем.
После генерации сервер сверяет цены, ссылки и заявления о действиях с результатами инструментов. Несоответствия сохраняются как диагностические флаги, но уже показанный текст автоматически не исправляется.
5. Технологии
| Компонент | Технологии |
|---|---|
| Языки | TypeScript, JavaScript, SQL, HTML, CSS |
| Скрапер и служебные скрипты | Node.js, tsx, Cheerio, dotenv |
| Сервер чата | Supabase Edge Functions, Deno 2, OpenAI Chat Completions API с вызовом инструментов |
| AI-модели по умолчанию | gpt-4.1-mini для диалога; text-embedding-3-small для эмбеддингов размерности 1536 |
| Данные и поиск | Supabase PostgreSQL, схема ekt, pgvector, pg_trgm, полнотекстовый поиск russian, Reciprocal Rank Fusion. В локальной конфигурации указан PostgreSQL 17. |
| Клиент | TypeScript без UI-фреймворка, Shadow DOM, SSE, localStorage; сборка esbuild |
| Расширение браузера | Chrome Extension Manifest V3, подключение того же виджета к ekt.kz |
| Проверки | Vitest, happy-dom, Deno test/check, Playwright Core и установленный браузер для E2E |
| Окружение | npm, Supabase CLI, Docker для локального Supabase; GitHub Actions; конфигурация публикации статики в Vercel |
Версии зависимостей зафиксированы в package-lock.json. Модели и серверные параметры задаются через окружение; смена модели эмбеддингов должна учитывать размерность в схеме БД.
6. Архитектура проекта
flowchart LR
Site[Страницы ekt.kz] --> Scraper[Скрапер HTML]
Scraper --> Files[JSONL в data/]
Seed[Снимок seed/] --> Ingest[Загрузчик данных]
Files --> Ingest
Ingest --> DB[(PostgreSQL / схема ekt)]
Ingest --> Embeddings[OpenAI Embeddings]
Embeddings --> Ingest
User[Покупатель] --> Widget[Виджет / расширение]
Widget -->|HTTP-запрос| Chat[Edge Function chat]
Chat <-->|Вызовы инструментов| Model[OpenAI Chat Completions]
Chat <-->|Каталог, знания, история, заявки| DB
Chat -->|SSE: текст, карточки, действия| Widget
| Путь | Назначение |
|---|---|
scraper/src/ | Сбор и разбор страниц, подготовка записей, загрузка данных и эмбеддингов |
seed/ | Снимок данных для воспроизведения без повторного обхода ekt.kz |
supabase/migrations/ | Таблицы, права доступа и SQL-функции поиска |
supabase/functions/chat/ | API, промпт, 12 инструментов, клиент OpenAI, SSE, ограничения запросов и постпроверка |
web/src/ | Чат-виджет, локализация, сохранение диалога и выполнение действий |
web/public/ | Демо, страница проверки встраивания и результат сборки widget.js |
extension/ | Расширение для подключения виджета к настоящему сайту |
scripts/ | Локальная установка, smoke-тест, проверка поиска, обновление снимка |
eval/, e2e/ | Проверки ответов и пользовательских сценариев |
.github/workflows/ | CI и расписание обновления данных |
Браузер обращается к функции чата, а не напрямую к таблицам. Ключ OpenAI и ключ Supabase service_role нужны серверу и загрузчику данных; в настройки виджета они не передаются.
7. Установка и запуск
Быстрая установка расширения для жюри
В системе нужны: Chrome или Microsoft Edge с возможностью загрузки распакованного расширения, доступ к интернету, ekt.kz и облачному API команды. Готовая сборка extension/widget.js уже находится в репозитории: для её установки Node.js, Docker, аккаунт Supabase и собственный ключ OpenAI не нужны.
- Скачайте репозиторий через Code → Download ZIP и распакуйте архив либо клонируйте его через Git.
- Откройте
chrome://extensionsв Chrome илиedge://extensionsв Edge. - Включите «Режим разработчика».
- Нажмите «Загрузить распакованное» и выберите именно папку
extension/, содержащуюmanifest.json,content.js,widget.jsиicons/. - Откройте или обновите категорию «Лампы» на ekt.kz. Справа внизу должна появиться кнопка «Задать вопрос».
- Отправьте: «Покажи цену и характеристики товара с артикулом 080300163_», затем «Открой карточку и покажи цену».
Расширение действует только на https://ekt.kz/* и https://www.ekt.kz/*. Оно использует API из extension/content.js. Если виджет появился, но ответа нет, проверьте health API; для независимого от стенда команды запуска используйте вариант B или C ниже. В управляемом корпоративном браузере загрузка расширений может требовать разрешения администратора.
Требования для сборки и собственного сервиса
- Node.js 22.12+ в ветке 22 либо Node.js 24, npm, Git. Хотя
package.jsonобъявляет Node.js ≥20, текущие зависимости в lock-файле требуют более новую версию. - Для полноценного локального сервиса: запущенный Docker Desktop или совместимый Docker Engine, интернет для загрузки образов и запросов OpenAI, собственный
OPENAI_API_KEYс доступом к указанным моделям. - Supabase CLI входит в зависимости проекта; команды вызываются через
npx supabase. - Отдельный Deno 2 нужен для
deno checkиdeno test, но не для запуска функции через Supabase CLI.
git clone https://github.com/BAITC-Hacks/hack-b0093e63-centras-ai-hub.git
cd hack-b0093e63-centras-ai-hub
npm ci
Выберите один из трёх вариантов ниже. Для воспроизведения всей цепочки с собственной базой используйте вариант B.
A. Демонстрация интерфейса без ключей и Docker
В первом терминале:
node web/dev/mock-server.mjs
Во втором терминале, из корня проекта:
npm run dev:web
Откройте демо с mock API или страницу проверки действий.
Mock API работает на порту 8787 и возвращает заранее заданные ответы. Этот режим позволяет проверить интерфейс и действия, но не качество AI, поиск по базе или создание настоящих заявок.
B. Полный локальный сервис: база → данные → API → виджет
Шаг 1. Создайте локальный файл настроек из .env.example.
PowerShell:
Copy-Item .env.example .env.local
Bash / zsh:
cp .env.example .env.local
Отредактируйте .env.local: заполните OPENAI_API_KEY, оставьте модели по умолчанию и ALLOWED_ORIGINS. Для этого варианта удалите строки SUPABASE_* с облачными заглушками: адреса и ключи локального Supabase определит CLI. Не используйте терминал с экспортированными переменными чужого облачного проекта.
| Переменная | Что указать |
|---|---|
OPENAI_API_KEY | Собственный секретный ключ OpenAI, обязателен для настоящего чата |
OPENAI_MODEL | gpt-4.1-mini |
OPENAI_EMBEDDING_MODEL | text-embedding-3-small |
ALLOWED_ORIGINS | Значение из примера уже включает http://localhost:5173, https://ekt.kz и https://www.ekt.kz |
CHAT_URL | Можно оставить пустым; для smoke/eval ниже адрес задаётся явно |
Шаг 2. Запустите Docker и подготовьте базу.
npm run setup:local
Скрипт проверяет Docker, запускает Supabase, применяет миграции и загружает seed/, создавая эмбеддинги через OpenAI. Локальные реквизиты записываются в .env.local.generated; исходный .env.local сохраняется.
setup:localвыполняетsupabase db reset --local: повторный запуск удаляет данные локальной БД и загружает снимок заново. Для обычного возобновления контейнеров используйтеnpx supabase start.
Без ключа OpenAI скрипт может загрузить данные без эмбеддингов, но полноценный AI-чат от этого не заработает. Вариант npm run setup:local -- --no-embed пропускает создание эмбеддингов при первоначальной загрузке.
Шаг 3. В отдельном терминале запустите API и оставьте его работающим.
npm run serve:fn
Команда читает .env.local. Локальный адрес API: http://127.0.0.1:54321/functions/v1/chat.
Шаг 4. В ещё одном терминале запустите интерфейс.
npm run dev:web
Откройте локального консультанта. Параметр ?api= обязателен для этого варианта: без него демостраница использует сохранённый облачный API команды.
| Компонент | Локальный адрес |
|---|---|
| Демо | localhost:5173 |
| Проверка API | chat/health |
| Supabase Studio | 127.0.0.1:54323 |
В ответе /health проверьте ok: true, db: true, openai_key: true. Последнее поле подтверждает наличие ключа в настройках, а не успешный запрос к OpenAI; это проверяется сообщением в чат или smoke-тестом.
Для повторной загрузки снимка без сброса БД:
node --env-file=.env.local.generated --import tsx scraper/src/ingest.ts --dir seed
Здесь локальные реквизиты передаются загрузчику явно: ingest сам не читает .env.local.generated. Не экспортируйте облачные SUPABASE_* в этом терминале — переменные процесса имеют приоритет над файлом.
Для остановки завершите процессы API и интерфейса через Ctrl+C, затем выполните npx supabase stop.
C. Собственный облачный Supabase
-
Создайте проект Supabase. Скопируйте
.env.exampleв.env.localи заполнитеSUPABASE_URL,SUPABASE_SERVICE_ROLE_KEY,OPENAI_API_KEY. Project ref и пароль БД понадобятся при привязке CLI. -
Авторизуйте CLI и примените миграции:
npx supabase login npx supabase link --project-ref <project-ref> npm run db:pushКоманда
linkможет запросить пароль базы. Supabase CLI не получает все переменные автоматически из.env.local; для авторизации здесь используетсяlogin. -
В настройках Data API проекта добавьте
ektв Exposed schemas, затем загрузите снимок:npm run ingest:seed -
Создайте
.env.function.localсOPENAI_API_KEY,OPENAI_MODEL,OPENAI_EMBEDDING_MODELиALLOWED_ORIGINS. Это отдельный файл только для секретов функции; не копируйте туда токен CLI, пароль БД или[скрыто]. Укажите вALLOWED_ORIGINSфактические адреса страниц с виджетом.npx supabase secrets set --env-file .env.function.local npm run fn:deploy -
Задайте собственный URL
https://<project-ref>.supabase.co/functions/v1/chatв<meta name="ekt-api">файлаweb/public/index.html. Для расширения заменитеAPIвextension/content.js. Параметр?api=демостраницы принимает только локальные HTTP-адреса и не переключает её на произвольный облачный проект. -
Выполните
npm run smoke, затемnpm run dev:webи откройте демо. Для smoke оставьтеCHAT_URLпустым либо задайте свой адрес явно, чтобы он соответствовал выбранному проекту.
Подключение на настоящий сайт
Для демонстрации используйте готовое расширение. Если меняли исходники виджета, сначала пересоберите его:
npm run build:web
Сборка создаёт web/public/widget.js и обновляет extension/widget.js. Откройте chrome://extensions или edge://extensions, включите режим разработчика, выберите «Загрузить распакованное» и укажите папку extension/. После этого откройте категорию «Лампы».
Подробности — в инструкции расширения. По умолчанию оно подключается к облачному API команды. Для собственного API измените extension/content.js и перезагрузите расширение.
Что потребуется от владельца системы для прямого внедрения:
- Доступ к шаблону сайта, чтобы подключить скрипт виджета, и возможность проверить его на тестовой странице.
- HTTPS-хостинг для
widget.jsи работающий HTTPS API чата. - Настроенный Supabase со схемой
ekt, миграциями и загруженными данными; серверный ключ OpenAI. Порядок — вариант C, переменные —.env.example. - Добавление домена сайта в
ALLOWED_ORIGINS; если на сайте действует Content Security Policy, разрешение загрузки скрипта и подключения к API. - Проверка соответствия разметки сайта разрешённым целям в
web/src/actions.ts. Для другого сайта потребуется адаптация селекторов и серверного списка разрешённых адресов и действий.
После получения доступа разместите widget.js на HTTPS-хостинге и добавьте в шаблон страницы:
<script src="https://<хостинг-виджета>/widget.js"
data-api="https://<project-ref>.supabase.co/functions/v1/chat"
data-lang="ru"
defer></script>
Для публикации демо подготовлен vercel.json: команда сборки npm run build:web, каталог публикации web/public. Сам конфигурационный файл не подтверждает, что сайт опубликован.
8. Как проверить решение
Сценарий для жюри
Основной путь для жюри — установить расширение и пройти сценарий на ekt.kz. Оно использует API команды; альтернативно можно развернуть собственный API по варианту B или C. Mock-режим для проверки поиска не подходит.
| Шаг | Действие | Что проверить |
|---|---|---|
| 1 | «Нужна светодиодная лампа E27, тёплый свет, до 1000 тенге» | Ответ содержит найденные товары, цены в тенге и ссылки на ekt.kz. Сравните характеристики с карточками. |
| 2 | «Покажи цену и характеристики товара с артикулом 080300163_» | В снимке это PHILIPS Ecohome A60, E27, 11 Вт, 3000 K; price_site равна 800 ₸. Для обновлённой базы цена может отличаться. |
| 3 | «Какие условия возврата?» | Консультант использует информационные страницы магазина. |
| 4 | «Где ваш филиал в Астане?» | Ответ содержит адрес и контакты из данных филиалов. |
| 5 | «Найди товар с артикулом TEST-NOT-EXIST-999» | Проверка реакции на отсутствие данных: консультант не должен придумывать карточку и цену. |
Чтобы проверить действия на ekt.kz с расширением, попросите открыть найденную карточку, затем показать цену. Для проверки формы попросите открыть заявку: проверьте её отображение и возможность заполнения. Нажатие «Купить» может изменить настоящую корзину, а отправка формы — создать обращение на сайте. Для демонстрации этих действий без обращения в магазин используйте локальный embed.html с mock API.
Автоматические проверки
Тесты и проверка типов без обращения к живому AI:
npm test
npm run typecheck
npm run build:web
При установленном Deno 2:
deno check supabase/functions/chat/index.ts
deno test supabase/functions/chat/
Smoke-тест и eval обращаются к работающему API. Для локального сервиса задайте адрес явно.
PowerShell:
$env:CHAT_URL = "http://127.0.0.1:54321/functions/v1/chat"
npm run smoke
npm run eval
Bash / zsh:
export CHAT_URL=http://127.0.0.1:54321/functions/v1/chat
npm run smoke
npm run eval
smoke проверяет health, ответ с товаром и ссылкой, а также обработку некорректного запроса. eval выполняет сценарии из eval/questions.json, перезаписывает eval/report.json и завершается с ошибкой при результате ниже 80%. Eval автоматически читает .env, но не .env.local, поэтому выше используется явный CHAT_URL. Сценарий lead-flow-wholesale создаёт тестовую запись в ekt.leads.
Дополнительно доступны npm run e2e:api для контракта действий API и npm run e2e для браузерных сценариев на настоящем ekt.kz. Браузерный прогон требует установленного Chrome/Edge и сборки виджета; он может добавить товар в реальную корзину тестового браузера и обновляет файлы отчётов и скриншотов.
Сохранённые результаты, а не гарантия текущего состояния:
eval/RESULTS.md: 41 из 42 сценариев, 97,6%, прогон от 23.09.2026. Зафиксирована ошибка подбора лампы по сочетанию характеристик.e2e/RESULTS.md: последний сохранённый браузерный прогон от 23.09.2026, 12:01 UTC — 14 из 14 проверок,PASS. Проверены ответ с карточкой/ссылкой, переход к тому же товару, подсветка, добавление в корзину, открытие и заполнение формы возврата, переход к оплате и поиск на сайте.- При обновлении README 23.09.2026 повторно выполнен
npm run smokeпротив облачного API — 5 из 5 проверок,PASS: health, ответ с товарами и ссылкой, три некорректных запроса с ожидаемым HTTP 400. docs/README-VERIFICATION.md: журнал проверки более раннего коммита; полный локальный Docker-стек в том прогоне не запускался.
После изменений кода или данных эти проверки необходимо повторить. Сохранённые отчёты не доказывают ни наличие, ни исправление тех же ошибок в текущей рабочей копии.
9. Данные и интеграции
Данные для воспроизведения
В seed/ хранится снимок ekt.kz от 23.09.2026:
| Файл | Содержимое | Число записей |
|---|---|---|
products.jsonl | Товары демонстрационной выборки категории «Лампы» | 89 |
categories.jsonl | Категории и пути каталога | 24 |
pages.jsonl | Информационные страницы | 123 |
branches.json | Филиалы | 9 |
Это статический снимок, а не весь ассортимент магазина. Фрагменты страниц и эмбеддинги создаются при загрузке; готовые векторы в снимок не включены.
Какие именно данные доступны:
- Товары: светодиодные, галогенные, газоразрядные, люминесцентные, бактерицидные лампы и лампы накаливания. В характеристиках встречаются цоколи
E14,E27,E40,GX53,GU10,GU5.3,R7s,G13; бренды MEGALIGHT, OSRAM, KODAK, Philips, IEK, Gauss. У части записей бренд или отдельные характеристики не заполнены. - Поля товара: название, артикул и артикул поставщика, бренд, цена сайта и магазина в KZT, кратность покупки, описание, характеристики, категория, ссылка и URL изображения. Например, у лампы Philips
080300163_в снимке указаны E27, 11 Вт, 3000 K и цена сайта 800 ₸. - Информационные страницы: FAQ, оформление заказа, оплата, возврат и контакты; «О компании», собственные торговые марки, производство, технические материалы, статьи и новости. Например, есть страницы «Производство электрощитового оборудования» и «Кабельно-проводниковая продукция». Упоминание кабеля в справочной статье не означает, что его товарная карточка загружена в каталог.
- Филиалы: Алматы, Астана, Шымкент, Актау, Атырау, Тараз, Усть-Каменогорск, Караганда и Талдыкорган. Записи содержат адреса, телефоны, email и график работы.
Эти количества описывают файлы в репозитории. Состав работающей облачной БД может отличаться после обновлений и здесь отдельно не подтверждается.
Внешние системы
| Система | Использование |
|---|---|
| ekt.kz | Sitemap, HTML карточек и информационных страниц, контакты филиалов, ссылки и изображения товаров. Сбор данных выполняется парсерами без LLM. |
| OpenAI API | Генерация ответов, выбор инструментов и создание эмбеддингов. Полный локальный запуск также обращается к этому внешнему сервису. |
| Supabase | Хранение каталога, знаний, диалогов, оценок, заявок и истории цен; SQL-поиск и API чата. Можно использовать облачный проект либо локальные контейнеры. |
| GitHub Actions | CI и подготовленное расписание обновления категории «Лампы»; требует настройки секретов репозитория. |
| Vercel | Подготовлена конфигурация хостинга демо и виджета; подтверждённого адреса публикации в репозитории нет. |
Обновление данных
Настройки категории, ограничения числа товаров и частоты запросов приведены в .env.example. Скопированный пример настраивает сбор категории «Лампы» с лимитом 100 товаров.
npm run scrape
npm run ingest
npm run refresh выполняет обе команды последовательно. Сбор сохраняет результат в data/, загрузчик читает реквизиты из .env.local / .env. Для локальной БД после setup:local вместо обычного npm run ingest используйте:
node --env-file=.env.local.generated --import tsx scraper/src/ingest.ts
Загрузчик сравнивает содержимое записей, обновляет эмбеддинги и сохраняет изменения цен в ekt.price_history. Команда npm run seed:update отдельно заменяет файлы снимка в репозитории результатом из data/.
Workflow refresh-data.yml задаёт ежедневный запуск в 22:15 UTC (03:15 по Алматы) для категории «Лампы». Нужны секреты SUPABASE_URL, SUPABASE_SERVICE_ROLE_KEY, OPENAI_API_KEY. Наличие workflow не подтверждает, что секреты настроены или обновления фактически выполняются.
Скрапер содержит исключения для служебных страниц, закрытых в robots.txt. Переменная SCRAPER_SKIP_SERVICE_PAGES=1 отключает их сбор.
10. Ограничения текущей версии
- Ограниченный каталог. Снимок содержит 89 товаров; ответы о других категориях зависят от данных, загруженных в конкретную БД.
- Нет оперативных складских остатков. Цена — значение из последней загрузки, а не гарантия текущей цены или наличия. Отдельной интеграции с учётной системой магазина нет.
- Ошибки AI возможны. Качество подбора зависит от поиска и модели. Постпроверка сохраняет диагностические флаги после генерации, но не блокирует неверный ответ.
- Действия зависят от сайта. Виджет использует селекторы текущей разметки ekt.kz; изменения сайта могут нарушить подсветку и заполнение. Выдача сервером команды не подтверждает её успешное выполнение браузером.
- Заявки хранятся в БД. Отдельного кабинета менеджера, интеграции CRM и автоматической отправки заявок по email или в мессенджер в текущей реализации нет. Их можно просматривать в таблице
ekt.leadsчерез Supabase Studio. - Согласие контролируется не полностью. Запрос согласия предусмотрен промптом; отдельной серверной проверки факта согласия для
create_leadнет. - История и контакты сохраняются. Диалоги записываются на сервере и в браузере; введённые в чат персональные данные могут попасть в историю сообщений, а не только в заявку.
- Есть лимиты. До 2000 символов в сообщении, 12 предыдущих сообщений в контексте, 5 раундов инструментов, 20 сообщений в минуту на сессию, 60 на IP и 3 заявки на сессию — см.
config.ts. - Требуются внешние сервисы. Для настоящего чата нужен работающий OpenAI API; локальная база не делает решение полностью автономным. Mock-режим не заменяет AI-проверку.
- Не все способы запуска подтверждены сквозным прогоном. Инструкция локального Docker-стека составлена по скриптам и конфигурации. Сохранённый журнал верификации не подтверждает полный запуск этого варианта; успешные браузерные проверки относятся к сценарию с облачным API.
11. Развёрнутая версия
В исходниках демостраницы и расширения указан следующий адрес; в репозитории есть отчёты обращений к нему от 23.09.2026:
| Компонент | Ссылка / способ доступа |
|---|---|
| Облачный API чата | Supabase Edge Function chat — POST, ответ SSE; это не веб-страница чата |
| Проверка состояния | Health-check |
| Интерфейс для этого API | npm ci → npm run dev:web → localhost:5173 без параметра ?api= |
| Консультант поверх ekt.kz | Инструкция установки расширения |
Работа с облачным API проверена на живом ekt.kz. Последний сохранённый E2E-прогон от 23.09.2026 завершился результатом 14/14 PASS: консультант показал товар, перешёл к его карточке, подсветил цену, добавил товар в корзину, открыл и заполнил форму возврата, перешёл к условиям оплаты и выполнил поиск. Результаты и пути к скриншотам — в e2e/RESULTS.md. Отдельный повторный smoke-тест облачного API при обновлении README завершился 5/5 PASS.
Для проверки жюри консультант поставляется как расширение Chrome/Edge, устанавливаемое в режиме разработчика. Оно подключает виджет поверх настоящего сайта без изменения его серверной части. Автоматический E2E-тест внедряет ту же сборку виджета в страницу через Playwright; он проверяет взаимодействие с живым сайтом и API, но не автоматизирует установку расширения в интерфейсе браузера. Доступа к среде сайта для штатного подключения у команды сейчас нет, поэтому основной способ демонстрации — расширение. После предоставления доступа тот же виджет можно подключить непосредственно в шаблон сайта по инструкции выше.
12. Потенциал развития и масштабирования
Направление развития проекта — универсальная платформа ИИ-агентов для сайтов компаний: консультация по данным бизнеса и помощь в выполнении действий в одном диалоге. EKT — первый предметный сценарий, на котором реализована эта связка. Та же последовательность применима к другим задачам: понять потребность → найти сведения в источниках компании → объяснить варианты → помочь выполнить следующий шаг → передать сложный вопрос сотруднику.
Общая основа уже разделена на сбор данных, поиск, диалог с инструментами и выполнение действий в браузере. Сейчас парсеры, промпт, адреса и элементы интерфейса настроены под ekt.kz. Для подключения другой компании потребуется адаптация этих частей. Следующий этап — вынести такие настройки в отдельные профили сайтов и подтвердить переносимость на втором проекте.
Общая логика для разных компаний
| Слой решения | Что можно использовать повторно | Что настраивается под компанию |
|---|---|---|
| Сбор данных | Обход страниц, извлечение содержимого, подготовка записей и повторная загрузка | Разрешённые источники, структура сайта, HTML-парсеры, поля товаров или услуг, расписание обновления |
| База знаний и поиск | Разбиение текстов на фрагменты, эмбеддинги, сочетание текстового и векторного поиска | Каталог, характеристики, справочные документы, условия обслуживания; при другой предметной области — схема данных и фильтры |
| Консультация | История диалога, уточнение запроса, вызов инструментов, ответы по найденным сведениям и ссылки на источники | Терминология, язык общения, правила компании, границы консультации и условия передачи вопроса сотруднику |
| Действия на сайте | Переход, подсветка, нажатие, заполнение разрешённых полей и подсказки следующего шага | Домены, страницы, селекторы элементов, формы, допустимые действия и необходимые подтверждения |
| Работа с обращениями | Сбор контактов и описание потребности в контексте диалога | Поля заявки, ответственный отдел, способ обработки; при дальнейшем развитии — передача в CRM или сервисную систему через API |
| Проверка качества | Тесты контрактов, сценарии диалога, проверки ссылок и браузерные прогоны | Контрольные вопросы, ожидаемые товары или услуги, правила компании и действия на её сайте |
При таком развитии для каждого заказчика адаптируются данные и способы взаимодействия с его системой, а общие механизмы диалога, поиска и управления инструментами используются повторно. Это создаёт основу для последовательного подключения новых компаний без отдельной разработки всего агента с нуля.
Где может применяться этот подход
Ниже — возможные сценарии после адаптации; это направления развития, а не уже подключённые компании или готовые интеграции.
| Направление | Пример задачи пользователя | Как помогает агент |
|---|---|---|
| Интернет-магазины техники, мебели, стройматериалов | Подобрать товар под параметры и бюджет, подготовить заказ или обращение по возврату | Находит варианты, объясняет характеристики и условия, открывает карточку, помогает с корзиной и формой обращения |
| B2B-поставщики и производители | Найти продукцию по характеристикам и запросить коммерческое предложение | Ищет по каталогу и техническим материалам, уточняет количество и требования, готовит заявку отделу продаж |
| Сервисные компании | Выбрать услугу, узнать условия и оставить запрос | Объясняет состав услуги по данным компании, помогает выбрать подходящее направление и заполнить форму; подтверждение записи требует связи с системой расписания |
| Образовательные организации | Подобрать программу и узнать условия поступления или обучения | Сопоставляет запрос с описаниями программ, показывает требования и сроки из опубликованных материалов, помогает подготовить обращение |
| Корпоративные порталы | Найти инструкцию или оформить внутреннюю заявку | Находит регламент, открывает нужный раздел и помогает заполнить форму; такой сценарий требует авторизации и учёта прав сотрудника |
Как подключать новый сайт
- Выбрать конкретный пользовательский сценарий. Например, подбор товара и заявка на расчёт. Определить, какой результат должен получить пользователь и какие действия остаются за ним или сотрудником компании.
- Подготовить источники. Согласовать сбор доступных страниц, настроить парсеры и загрузить каталог, услуги, контакты и правила обслуживания. Если компания предоставляет API или выгрузку, разработать соответствующий загрузчик вместо разбора HTML для этих данных.
- Настроить инструменты. Сопоставить поиск с полями компании, а действия — с её страницами, кнопками и формами. Задать разрешённые домены, поля и условия подтверждения. Подключение нового сайта не должно открывать агенту произвольный доступ ко всем действиям браузера.
- Провести пилот. Для проверки в контролируемом браузере адаптировать расширение, включая список доменов. Для штатной работы с посетителями подключить виджет в шаблон сайта с согласия владельца и настроить доступ к API.
- Проверить результат на реальных сценариях. Подтвердить точность ответов, корректность заполнения, обработку ошибок и передачу обращения. После этого согласовать регулярное обновление данных и ответственность за обработку заявок.
Этапы развития после хакатона
Этап 1 — переносимость на второй сайт. Вынести привязки к EKT в профиль компании: источники, правила консультации, домены, маршруты, селекторы и формы. Адаптировать структуру данных там, где каталог отличается. Проверить обновление отдельных категорий без отключения остальных товаров. Критерий результата — тот же основной код обслуживает два разных сайта с отдельными настройками и проверенными сценариями.
Этап 2 — связь с рабочими системами бизнеса. Добавить согласованные интеграции с CRM, каталогом или учётной системой, чтобы получать актуальные сведения и передавать обращения ответственным сотрудникам. Расширение действий — создание заказа, подтверждение записи или регистрация возврата — возможно только при наличии соответствующего API, прав доступа и подтверждения пользователя. В текущей версии агент помогает с корзиной и формами; эти будущие операции пока не реализованы.
Этап 3 — обслуживание нескольких компаний. Добавить изоляцию данных, истории, ключей и настроек каждой организации; роли сотрудников; управление источниками и версиями сценариев; отдельные лимиты и учёт использования. Сейчас готового режима обслуживания нескольких организаций и кабинета для самостоятельного подключения компаний нет. На первом этапе возможны отдельные развёртывания с адаптацией под каждого заказчика.
Этап 4 — измеримое качество и управляемые расходы. Собирать показатели успешного поиска и завершения сценариев, долю обращений к сотруднику, время до результата, частоту ошибок действий и стоимость обслуживания диалога. Сравнивать их с исходным процессом компании. Такие измерения позволят выбирать дальнейшие улучшения по результатам пилота и обосновывать экономическую ценность внедрения.
Ценность масштабирования
Для пользователя сохраняется понятный способ взаимодействия: описать задачу и получить помощь вплоть до нужного действия на сайте. Для компании появляется возможность связать её каталог, справочную информацию и формы в единый сценарий обслуживания, сохраняя существующий сайт и рабочие процессы.
Для развития продукта ценность заключается в повторном использовании общей технической основы: опыт подключения одного сайта, проверенные инструменты и сценарии становятся базой для следующих внедрений. Практическую универсальность нужно подтвердить пилотами на разных сайтах; текущий проект уже даёт исходную реализацию консультаций, сбора данных и действий, на которой можно строить такие пилоты.
Авторы коммитов
История коммитов
- 2026-09-23 17:27docs: describe cross-site growth and integration roadmapТамерлан
- 2026-09-23 17:22docs: clarify value and purchase and return workflowsТамерлан
- 2026-09-23 17:12docs: document agent capabilities and technical evaluationТамерлан
- 2026-09-23 17:07docs: README updates; ailem evidence factsvkhan-dot
- 2026-09-23 17:07docs: README updates; ailem evaluation report and evidence snapshotsyensepbaymeirambek
- 2026-09-23 17:01test(e2e): wait for stream end (aria-busy); final live ekt.kz run 14/14Тамерлан
- 2026-09-23 17:01fix(widget): persist deferred actions before navigation, keep product cards across pagesТамерлан
- 2026-09-23 16:49test(e2e): final run on live ekt.kzТамерлан
Все коммиты (48)
- 2026-09-23 16:40docs: README rewriteТамерлан
- 2026-09-23 16:40fix(chat): navigate supersedes on-site search in the same turnТамерлан
- 2026-09-23 16:39perf(widget): act immediately — no plate for fill/highlight/search, 1 s navigateТамерлан
- 2026-09-23 16:37test(e2e): wait for filled values, accept product cardТамерлан
- 2026-09-23 16:34fix(widget): buy actions only on product page, cancel pending actions on new inputТамерлан
- 2026-09-23 16:33fix(chat): default highlight on navigate, show card of the navigated productТамерлан
- 2026-09-23 16:27test(e2e): real ekt.kz browser scenarios and API action contract checksТамерлан
- 2026-09-23 16:27fix(chat): always submit site search after filling itТамерлан
- 2026-09-23 16:27docs: README verified against a clean clone — fix commands and numbersyensepbaymeirambek
- 2026-09-23 16:27fix(deps): sync package-lock with package.json so npm ci works on a clean clonevkhan-dot
- 2026-09-23 16:23fix(chat): accept relative navigate paths, trigger scenario actions on first turnТамерлан
- 2026-09-23 16:17feat(widget): UI actions on the real ekt.kz (navigate/highlight/click/fill/suggest) + Chrome extensionТамерлан
- 2026-09-23 16:03fix(chat): no claimed actions without tools, canonical navigate URLs, less narrationТамерлан
- 2026-09-23 15:57fix(search): boost all-terms full-text matchesТамерлан
- 2026-09-23 15:56docs(plan): pivot — consultant acts on the real ekt.kz via browser extension; real-site selectorsТамерлан
- 2026-09-23 15:55fix(search): unit-aware attribute filters and OR full-text recallТамерлан
- 2026-09-23 15:46test(eval): focus eval suite on category «Лампы» and record live resultsТамерлан
- 2026-09-23 15:44feat(chat): navigate/highlight UI action tools with URL allow-listyensepbaymeirambek
- 2026-09-23 15:44docs: README restructured by jury criteria (implemented, architecture, data, run, verify, limitations)vkhan-dot
- 2026-09-23 15:32docs(plan): extend UI actions contract — click, fill, filter, suggest; scenario playbookТамерлан
- 2026-09-23 15:31docs: plan for consultant UI actions (navigate/highlight) and demo storefrontТамерлан
- 2026-09-23 15:25feat: one-command local setup from seed data, smoke test, daily price-check workflowТамерлан
- 2026-09-23 15:19data: seed snapshot — 89 products of category «Лампы», 123 info pages, 9 branches (2026-09-23)Тамерлан
- 2026-09-23 15:16feat(ingest): detect price changes, price history, --dir for seed dataТамерлан
- 2026-09-23 15:15feat(chat): expose recent price changes in tools and promptТамерлан
- 2026-09-23 15:11feat(scraper): single-category mode with product cap and tracked-first ordering; price history migration; planТамерлан
- 2026-09-23 15:08feat: store order_note ("Под заказ") for products without price; expose in search and chat toolsyensepbaymeirambek
- 2026-09-23 15:08feat(scraper): robust page extraction, 60s timeout, ekt schema in ingest; remove debug scriptvkhan-dot
- 2026-09-23 15:00docs: README — ekt schema, Edge Function env vars, deploy checks, eval lead cleanupТамерлан
- 2026-09-23 14:59fix(chat): reject non-UTF-8 messages; ask to rephrase instead of guessing on unclear inputТамерлан
- 2026-09-23 14:49fix(db): rename reserved column in category_facets; migration applied to SupabaseТамерлан
- 2026-09-23 14:46fix(db): isolate consultant in dedicated ekt schema; scope grants to service_roleТамерлан
- 2026-09-23 14:45FFXТамерлан
- 2026-09-23 14:44feat(widget): embeddable chat widget (Shadow DOM, SSE, safe markdown, product cards, feedback) + demo page, mock server, Vercel configyensepbaymeirambek
- 2026-09-23 14:35feat(chat): Edge Function consultant with OpenAI tool calling, SSE streaming, hallucination guard, rate limits; eval suiteТамерлан
- 2026-09-23 14:31chore: document where to get each env variableТамерлан
- 2026-09-23 14:29docs: full README — architecture, DB, scraping, API, widget, deploy, opsvkhan-dot
- 2026-09-23 14:29ci: nightly data refresh and CI workflowsyensepbaymeirambek
- 2026-09-23 14:18chore: project scaffold, Supabase schema with hybrid search RPC, parser fixturesТамерлан
- 2026-09-23 14:15docs: design spec for EKT AI consultantТамерлан
Структура репозитория (143 файлов)
.env.example .gitattributes .github/workflows/ci.yml .github/workflows/refresh-data.yml .gitignore README.md docs/README-VERIFICATION.md docs/ailem-run-ekt-2026-09-23/evidence/E2E.snapshot.md docs/ailem-run-ekt-2026-09-23/evidence/README.snapshot.md docs/ailem-run-ekt-2026-09-23/evidence/facts.md docs/ailem-run-ekt-2026-09-23/evidence/ingest-dry-run.txt docs/ailem-run-ekt-2026-09-23/report/frame.md docs/ailem-run-ekt-2026-09-23/report/report.md docs/ailem-run-ekt-2026-09-23/report/tech.json docs/ailem-run-ekt-2026-09-23/report/tech.md docs/ailem-run-ekt-2026-09-23/verdicts/tech-case_fit.json docs/ailem-run-ekt-2026-09-23/verdicts/tech-implementation.json docs/ailem-run-ekt-2026-09-23/verdicts/tech-readme.json docs/ailem-run-ekt-2026-09-23/verdicts/tech-reliability.json docs/ailem-run-ekt-2026-09-23/verdicts/tech-reproducibility.json docs/ailem-run-ekt-2026-09-23/verdicts/tech.json docs/screenshots/e2e-s1-product.png docs/screenshots/e2e-s2-cart.png docs/screenshots/e2e-s3-return-form.png docs/screenshots/e2e-s3a-return-page.png docs/screenshots/e2e-s4-payments.png docs/screenshots/e2e-s5-search.png docs/screenshots/ekt-01-catalog-with-widget.png docs/screenshots/ekt-02-search-filled.png docs/screenshots/ekt-03-search-results.png docs/screenshots/ekt-04-navigate-plate.png docs/screenshots/ekt-05-price-highlight.png docs/screenshots/ekt-06-buy-plate.png docs/screenshots/ekt-07-lead-form-filled.png docs/screenshots/ekt-08-return-request-filled.png docs/screenshots/ekt-09-return-conditions.png docs/screenshots/ekt-10-contacts-phone.png docs/screenshots/ekt-11-mobile-characteristics.png docs/screenshots/ekt-lead-form-filled-real.png docs/superpowers/plans/2026-09-23-agent-hands.md docs/superpowers/plans/2026-09-23-prices-seed-readme.md docs/superpowers/specs/2026-09-23-ekt-ai-consultant-design.md e2e/RESULTS.md e2e/api-contract.mjs e2e/lib/inject.mjs e2e/lib/sse.mjs e2e/real-site.mjs eval/RESULTS.md eval/questions.json eval/report.json eval/run.ts extension/README.md extension/content.js extension/icons/icon128.png extension/icons/icon16.png extension/icons/icon48.png extension/manifest.json extension/widget.js package-lock.json package.json scraper/src/check-city-prices.ts scraper/src/chunk.ts scraper/src/http.ts scraper/src/ingest.ts scraper/src/parse/branches.ts scraper/src/parse/category.ts scraper/src/parse/common.ts scraper/src/parse/index.ts scraper/src/parse/page.ts scraper/src/parse/product.ts scraper/src/robots.ts scraper/src/rows.ts scraper/src/scrape.ts scraper/test/chunk.test.ts scraper/test/fixtures/article.html scraper/test/fixtures/category.html scraper/test/fixtures/contacts.html scraper/test/fixtures/faq.html scraper/test/fixtures/howto.html scraper/test/fixtures/payments.html scraper/test/fixtures/product.html scraper/test/fixtures/product2.html scraper/test/fixtures/return.html scraper/test/parse.test.ts scraper/test/prices.test.ts scripts/check-search.mjs scripts/seed-update.mjs scripts/setup-local.mjs scripts/smoke.mjs seed/README.md seed/branches.json seed/categories.jsonl seed/pages.jsonl seed/products.jsonl seed/scrape-report.json supabase/.gitignore supabase/config.toml supabase/functions/chat/chat.ts supabase/functions/chat/config.ts supabase/functions/chat/db.ts supabase/functions/chat/deno.json supabase/functions/chat/http.ts supabase/functions/chat/http_test.ts supabase/functions/chat/index.ts supabase/functions/chat/openai.ts supabase/functions/chat/openai_test.ts supabase/functions/chat/prompt.ts supabase/functions/chat/prompt_test.ts supabase/functions/chat/ratelimit.ts supabase/functions/chat/sse.ts supabase/functions/chat/sse_test.ts supabase/functions/chat/tools.ts supabase/functions/chat/tools_test.ts supabase/functions/chat/ui_actions.ts supabase/functions/chat/ui_actions_test.ts supabase/functions/chat/validate.ts supabase/functions/chat/validate_test.ts supabase/migrations/20260923120000_init.sql supabase/migrations/20260923140000_order_note.sql supabase/migrations/20260923150000_price_history.sql supabase/migrations/20260923160000_search_recall.sql supabase/migrations/20260923170000_search_rank.sql tsconfig.json vercel.json web/build.mjs web/dev/ekt-live.mjs web/dev/mock-server.mjs web/public/bookmarklet.html web/public/embed.html web/public/index.html web/src/actions.ts web/src/i18n.ts web/src/icons.ts web/src/markdown.ts web/src/sse.ts web/src/storage.ts web/src/styles.ts web/src/widget.ts web/test/actions.test.ts web/test/markdown.test.ts web/test/security.test.ts web/test/sse.test.ts web/test/widget-actions.test.ts
Ветки (2)
Обсуждение 0 комментариев
Войдите, чтобы комментироватьПока нет комментариев — будьте первым.