Mereke
Браузерный прототип подбора до трёх подрядчиков из каталога 66 профилей с объяснениями, причинами исключения, сравнением дат и избранным, без…
О проекте
Команда: CYB3RGIRLS
Кейс HackAlem.ai: Креативные индустрии — Firebird
Стадия: Рабочий MVP
Задача кейса: «#79-lite»: подобрать до 3 подрядчиков для мероприятия и объяснить выбор
Суть
Браузерный прототип подбора до трёх подрядчиков из каталога 66 профилей с объяснениями, причинами исключения, сравнением дат и избранным, без внешних AI-моделей.
Как устроено
Модуль engine.js проверяет ввод и отбирает профили по городу и категории. Затем исключает кандидатов по календарю, бюджету, формату, языку и длительности. Оставшиеся сортируются лексикографически: число совпадений слов пожелания с описанием (с простыми русскими окончаниями), упоминание формата, цена, id. Объяснения собираются из полей и фрагментов описания. Возможны статусы matched, no_match и category_absent; для пустой выдачи есть счётчики причин и кнопка «+30% бюджета».
Ключевые решения
- жёсткие фильтры
- лексическое сопоставление пожеланий
- многоуровневая сортировка
- сравнительные метки карточек
- WebMCP registerTool find_contractors
Особенности
Сознательный отказ от LLM: весь подбор объяснимый и детерминированный. Тесты проверяют 204 комбинации город×категория×дата. Есть условная регистрация инструмента через document.modelContext. README описывает папку dist/, но в дереве её нет (коммит «Delete dist directory»).
Стек
HTML5 · CSS3 · JavaScript · Node.js · Vercel · localStorage
Проект создан за 5 часов на финале хакатона HackAlem.ai (23 сентября 2026, Астана). Код — BAITC-Hacks/hack-8153b212-cyb3rgirls.
README
README.mdMereke / Мереке
Подбор подрядчиков для мероприятий · команда CYB3RGIRLS
1. О проекте
Mereke помогает организаторам мероприятий и частным заказчикам выбрать подрядчиков из заданного каталога. Пользователь указывает условия события, а сервис показывает до трёх подходящих вариантов с ценами, объяснениями и различиями между ними.
Проект сокращает ручное сравнение анкет: проверяет город, категорию, занятость на дату, бюджет, формат мероприятия, язык и длительность. Текущая версия — браузерный прототип для хакатона с локальным набором из 66 профилей.
2. Что реализовано
- Форма подбора: город, дата, формат, категория и бюджет; дополнительно — язык, длительность и пожелания до 500 символов.
- Фильтрация по обязательным условиям: занятые на выбранную дату и неподходящие по параметрам профили исключаются из результата.
- До трёх карточек: стартовая цена в тенге, факты о соответствии запросу и цитата из описания подрядчика.
- Учёт пожеланий: совпадения слов и простых русских окончаний в описаниях влияют на порядок подходящих кандидатов.
- Сравнение карточек: самая низкая стартовая цена, наибольший лимит присутствия и языки, которых нет у остальных показанных вариантов. Метки выводятся только при выполнении условий сравнения.
- Объяснение пустой или короткой подборки: отдельно обрабатываются отсутствие категории в городе и отсутствие кандидатов, прошедших условия; выводятся счётчики причин исключения.
- Сравнение дат: если изменена только дата, отображается изменение числа подходящих кандидатов и доступности подрядчиков из предыдущей и новой подборок.
- Полный профиль: описание, категории, город, языки, форматы мероприятий, длительность и признаки происхождения данных.
- Избранное: добавление и удаление профилей, сохранение в браузере и повторная проверка соответствия текущим условиям.
- Шесть готовых примеров, адаптивная вёрстка и проверка вводимых параметров.
Если никто не подошёл и есть исключения по бюджету, пользователь может нажать «Увеличить бюджет на 30%». Без этого действия бюджет не меняется.
3. Как работает решение
- Пользователь открывает страницу и заполняет параметры либо выбирает готовый пример.
- Интерфейс передаёт запрос в модуль подбора. Результат пересчитывается при изменении полей или нажатии «Подобрать подрядчиков».
- Модуль проверяет ввод, выбирает профили нужного города и категории, затем исключает кандидатов по календарю, бюджету, формату, языку и длительности.
- Подходящие профили упорядочиваются последовательно:
- По убыванию числа совпадений с пожеланиями.
- По наличию буквального упоминания формата мероприятия в описании.
- По возрастанию стартовой цены.
- По идентификатору профиля при равенстве предыдущих признаков.
- Пользователь получает первые три варианта, объяснения и причины исключения остальных; может открыть полный профиль или сохранить вариант в избранное.
Пожелания меняют только порядок и не отменяют обязательные условия. Цена не используется как оценка качества. Объяснения составляются из проверяемых полей и фрагментов описания, а не генерируются AI-моделью.
4. Технологии
| Компонент | Реализация |
|---|---|
| Страница и интерфейс | HTML5, CSS3, JavaScript без фреймворков |
| Подбор и объяснения | Локальный JavaScript-модуль EventMatch |
| Данные | Массив объектов globalThis.CONTRACTORS в dist/data.js |
| Избранное | Browser localStorage, ключ mereke_shortlist |
| Форматирование цен | Встроенный Intl.NumberFormat('ru-RU') |
| Окна профиля и избранного | HTML-элемент <dialog> |
| Автоматические проверки | Node.js, встроенный node:assert/strict, CommonJS |
Внешние AI-модели, API и облачные сервисы для подбора не подключены. Обработка пожеланий — локальная эвристика сопоставления слов. Серверная часть, база данных, пакетные зависимости и этап сборки для работы приложения не требуются.
В dist/front.js также предусмотрена условная регистрация инструмента find_contractors через document.modelContext.registerTool, если среда браузера предоставляет этот API. Он вызывает тот же локальный подбор; для обычного использования страницы эта возможность не нужна.
5. Архитектура проекта
Приложение выполняется целиком в браузере. Рабочая версия находится в dist/.
Пользователь
↓ параметры мероприятия
dist/index.html + dist/butter.css
↕ события и отображение результата
dist/front.js ───────────────↔ localStorage (избранное)
↓ запрос
dist/engine.js ← dist/data.js (каталог)
↓ фильтрация, ранжирование, объяснения
dist/front.js
↓
До 3 карточек, полный профиль, причины исключения
.
├── README.md # Описание и инструкции
├── index.html # Перенаправление на ./dist/
├── dist/
│ ├── index.html # Основная страница
│ ├── butter.css # Стили интерфейса
│ ├── data.js # Каталог подрядчиков
│ ├── engine.js # Валидация, фильтры, ранжирование, объяснения
│ └── front.js # Форма, карточки, диалоги, избранное, примеры
├── tests.cjs # Проверки данных и логики из dist/
├── data.js # Дубликат каталога в корне
├── engine.js # Дубликат логики подбора в корне
├── app.js # Отдельная реализация интерфейса, не подключена в dist/
└── style.css # Стили, не подключены к основной странице
Основная страница загружает только файлы из dist/. Тесты также импортируют dist/data.js и dist/engine.js. Изменения корневых копий автоматически в dist/ не переносятся: скрипта сборки в проекте нет.
Модуль подбора возвращает один из трёх статусов: matched — есть результат, no_match — кандидаты не прошли условия, category_absent — категории нет в выбранном городе.
6. Установка и запуск
Live demo
Быстрый запуск без установки зависимостей
- Скачайте и распакуйте архив проекта.
- Откройте
dist/index.htmlв современном браузере с поддержкой JavaScript и<dialog>. - Оставьте все пять файлов папки
dist/рядом: страница использует относительные пути к стилям, данным и скриптам.
Для такого запуска не нужны Node.js, Python, npm install, ключи API или .env. Внешние шрифты, CDN и изображения приложение не загружает.
Запуск через локальный HTTP-сервер
Этот вариант удобен для работы через постоянный локальный адрес. Потребуется установленный Python 3; он используется только для раздачи статических файлов.
Из каталога, в который распакован проект:
cd hack-8153b212-cyb3rgirls-main
python -m http.server 8000 --bind 127.0.0.1 --directory dist
Если в Windows Python доступен через команду py, используйте:
py -3 -m http.server 8000 --bind 127.0.0.1 --directory dist
Откройте локальную версию. Для остановки сервера нажмите Ctrl+C в терминале. Если вы уже находитесь в корне проекта, команду cd выполнять не нужно.
Запуск автоматических проверок
Потребуется Node.js. Точная минимальная версия в репозитории не зафиксирована; тесты используют встроенные модули и не требуют установки npm-пакетов.
В корне проекта выполните:
node --version
node tests.cjs
Успешный запуск выводит две строки PASS и завершается с кодом 0. Первая строка содержит 204 real-data requests; время выполнения зависит от компьютера.
7. Как проверить решение
Основной сценарий для жюри
- Откройте приложение и нажмите пример «Ведущие · 15 октября».
- Проверьте параметры: Алматы, ведущий, корпоратив, 15.10.2026, бюджет 1 000 000 ₸, русский язык, 6 часов.
- Ожидаемый результат — «3 из 6 подходящих». В карточках должны быть цена «от», объяснение соответствия запросу и цитата из профиля.
- Нажмите «Та же заявка · 16 октября». Ожидается «3 из 4 подходящих» и блок сравнения дат с изменением числа кандидатов 6 → 4.
- Вернитесь к первому примеру: порядок карточек должен повториться.
- Откройте «Полный профиль», сохраните подрядчика в избранное и откройте избранное через значок сердца в шапке. Там отображается соответствие профиля текущим условиям.
Дополнительные примеры
Все перечисленные запросы доступны кнопками под формой. Число допустимых кандидатов указано до ограничения тремя карточками.
| Пример | Параметры | Ожидаемый результат |
|---|---|---|
| «Флористы · 2 варианта» | Алматы, флорист, свадьба, 15.10.2026, 300 000 ₸; язык и часы не заданы | 2 подходящих профиля, 2 карточки |
| «Бюджет 100 000 ₸» | Те же условия для флористов, бюджет 100 000 ₸ | Нет карточек; сообщение «Кандидаты есть, но условия не совпали» и причины исключения |
| «Нет категории в Астане» | Астана, декоратор, свадьба, 15.10.2026, 300 000 ₸; язык и часы не заданы | Сообщение «В городе нет этой категории» |
| «С импровизацией» | Основной запрос на 15.10.2026 + «импровизация и интерактивы» | Совпадения с описаниями учитываются при сортировке и отмечаются в карточках |
tests.cjs проверяет 204 сочетания города, категории и даты, повторяемость результатов, обязательные фильтры, границы бюджета, обработку max_hours = null, смену дат и числа кандидатов в примерах. Дополнительно проверяются ранжирование по пожеланиям, простые отрицания и корректность сравнительных меток. Это проверки данных и алгоритма; они не автоматизируют клики и визуальную проверку страницы.
8. Данные
Фактический источник данных приложения — включённый в проект файл dist/data.js. Он содержит:
- 66 профилей с уникальными идентификаторами;
- 17 категорий, при этом один профиль может относиться к нескольким категориям;
- 50 профилей в Алматы, 15 в Астане и 1 со значением города «Зарубежье»;
- 13 профилей с признаком
synthetic; - 18 профилей с признаком
price_imputedи 8 — сcity_imputed.
В исходном README источником назван файл организаторов hackathon dataset anonymized .xlsx. Сам Excel-файл и скрипт его преобразования в архиве отсутствуют, поэтому соответствие исходной таблице отдельно проверить по этой версии нельзя.
| Поля профиля | Назначение |
|---|---|
id, anon_name | Идентификатор и анонимизированное имя |
categories, city | Категории услуг и город |
price_from_kzt | Стартовая стоимость в тенге |
event_formats, languages | Поддерживаемые форматы и языки |
max_hours | Лимит присутствия; null означает, что ограничение по часам не применяется |
busy_dates | Список занятых дат |
description | Описание для цитат и поиска совпадений с пожеланиями |
synthetic, price_imputed, city_imputed | Признаки синтетического профиля и заполненных при подготовке данных цены/города |
Допустимый период запроса — с 23 сентября по 31 декабря 2026 года включительно. Даты вне этого диапазона отклоняются. Свободной считается допустимая дата, которой нет в busy_dates профиля.
9. Интеграции и внешние сервисы
Для основного сценария внешних интеграций нет: каталог, фильтры и объяснения работают локально. Серверные API, авторизация, платёжные сервисы и синхронизация календарей не подключены.
Избранное хранит идентификаторы профилей в localStorage текущего браузера. Если сохранение недоступно, список остаётся только в памяти открытой страницы. Условная интеграция с document.modelContext описана в разделе технологий; она не добавляет внешнюю модель или источник данных.
10. Ограничения текущей версии
- Каталог статический: интерфейса добавления подрядчиков, обновления цен и синхронизации реальной занятости нет.
- Учебные календари и отсутствие даты в списке занятости не подтверждают реальную доступность подрядчика.
- Цена «от» используется для фильтрации, но не гарантирует итоговую стоимость мероприятия.
- За один запрос выбирается одна категория; расчёт общего бюджета набора из нескольких подрядчиков не реализован.
- Пожелания обрабатываются по словам и простым окончаниям. Полноценное понимание смысла, всех синонимов и сложных отрицаний отсутствует; совпадение не гарантирует выполнение пожелания.
- Показываются только первые три подходящих профиля. Просмотра всех результатов с пагинацией нет.
- Бронирование, отправка заявок, оплата, отзывы, отдельное портфолио и личные кабинеты не реализованы.
- Избранное не синхронизируется между устройствами или браузерами.
- У одного профиля может быть несколько причин исключения, поэтому их счётчики нельзя складывать как независимые группы.
- Числа в демонстрационных сценариях относятся к включённому набору и могут измениться при редактировании данных.
11. Развёрнутая версия
Подтверждённая публичная ссылка в предоставленной версии проекта не указана. Для проверки используйте локальный запуск из раздела 6.
Корневой index.html перенаправляет на ./dist/, а .nojekyll присутствует в проекте, но сами по себе эти файлы не подтверждают публикацию сайта.
Авторы коммитов
История коммитов
- 2026-09-23 16:58Merge pull request #2 from BAITC-Hacks/ajymzanamantaj-gif-patch-2ajymzanamantaj-gif
- 2026-09-23 16:52Update README.mdAlina Abdikarimova
- 2026-09-23 16:50Add files via uploadajymzanamantaj-gif
- 2026-09-23 16:45Delete vercel.jsonajymzanamantaj-gif
- 2026-09-23 16:45Delete server directoryajymzanamantaj-gif
- 2026-09-23 16:45Delete scripts directoryajymzanamantaj-gif
- 2026-09-23 16:44Delete dist directoryajymzanamantaj-gif
- 2026-09-23 16:44Delete api directoryajymzanamantaj-gif
Все коммиты (24)
- 2026-09-23 16:29Add files via uploadajymzanamantaj-gif
- 2026-09-23 16:26Delete .github/codex/prompts directoryajymzanamantaj-gif
- 2026-09-23 16:19Add files via uploadAlina Abdikarimova
- 2026-09-23 16:18Add Codex review workflow for pull requestsajymzanamantaj-gif
- 2026-09-23 16:18Create review template for pull requestsajymzanamantaj-gif
- 2026-09-23 15:45new readmeAlina Abdikarimova
- 2026-09-23 15:21Merge branch 'main' into ajymzanamantaj-gif-patch-1ajymzanamantaj-gif
- 2026-09-23 15:17Update README.mdAlina Abdikarimova
- 2026-09-23 15:16Revise README with project details and instructionsajymzanamantaj-gif
- 2026-09-23 15:16Update README.mdAlina Abdikarimova
- 2026-09-23 15:13Revise README with deployment and structure detailsajymzanamantaj-gif
- 2026-09-23 15:11Add Codex review workflow for pull requestsajymzanamantaj-gif
- 2026-09-23 15:10Add review prompt for pull request checks in Russianajymzanamantaj-gif
- 2026-09-23 14:54Update Mereke frontend and butter yellow themeAlina Abdikarimova
- 2026-09-23 14:352.0Alina Abdikarimova
- 2026-09-23 14:10Add Mereke prototypeAlina Abdikarimova
Структура репозитория (18 файлов)
.gitignore .nojekyll README.md api/health.mjs api/recommend.mjs app.js data.js download engine.js index.html package.json scripts/check-build.cjs server/local.mjs server/recommend.mjs server/recommend.test.mjs style.css tests.cjs vercel.json
Обсуждение 0 комментариев
Войдите, чтобы комментироватьПока нет комментариев — будьте первым.