AAYMA
RU
Войти

EventMatch AI

Веб-сервис на Flask, который подбирает до 3 event-подрядчиков из каталога (66 профилей) по городу, дате, формату, категории и бюджету и объясняет…

Рабочий MVP
Команда «Aijok» 7💬 0 комментариевс 23 сентября 2026 г.

О проекте

Команда: Aijok
Кейс HackAlem.ai: Креативные индустрии — Firebird
Стадия: Рабочий MVP

Задача кейса: «#79-lite»: подобрать до 3 подрядчиков для мероприятия и объяснить выбор

Суть

Веб-сервис на Flask, который подбирает до 3 event-подрядчиков из каталога (66 профилей) по городу, дате, формату, категории и бюджету и объясняет каждый выбор.

Как устроено

Из CSV-каталога последовательно отсекаются профили по городу и категории, занятости (busy_dates), формату, бюджету (price_from_kzt) и длительности (max_hours). Прошедшие получают детерминированную оценку из 4 компонентов: язык, запас бюджета, запас длительности и число форматов. Затем стабильная сортировка с tie-breaker по id и TOP-3. Объяснения собираются шаблонами из полей профиля и фрагмента description, без LLM. Для пустой выдачи различаются случаи «категории нет в городе» и «никто не прошёл условия», причём показывается статистика причин исключения.

Ключевые решения

  • rule-based filtering
  • deterministic scoring
  • stable tie-breaker sorting
  • template-based explanations

Особенности

Решение прозрачное и полностью детерминированное, без внешних API. В пустой выдаче показываются счётчики причин исключения (занятость, формат, бюджет, длительность), и один профиль может попасть в несколько из них. Синтетические профили отмечены отдельно.

Стек

Python · Flask · Jinja2 · SQLite · Werkzeug · HTML · CSS · JavaScript · pytest


Проект создан за 5 часов на финале хакатона HackAlem.ai (23 сентября 2026, Астана). Код — BAITC-Hacks/hack-d6f9f1c0-aijok.

README

README.md

EventMatch AI

Умный и прозрачный подбор event-подрядчиков

HackAlem AI • Case #79-lite

1. О проекте

Выбор подрядчика для мероприятия требует одновременно учесть город, дату, формат, бюджет и особенности услуги. Простого длинного каталога для этого недостаточно: заказчику всё равно приходится вручную сравнивать профили и выяснять, кто действительно доступен и подходит.

EventMatch AI не расширяет каталог, а помогает выбрать до трёх наиболее подходящих вариантов из уже существующего каталога. Главная ценность решения — прозрачное объяснение того, почему каждый конкретный подрядчик попал в рекомендации.

Сервис предназначен для заказчиков свадеб, тоев, корпоративов, конференций, юбилеев и дней рождения. Основной сценарий: пользователь задаёт параметры события, получает не более трёх прошедших обязательные условия профилей, сравнивает их оценки и объяснения «Почему подходит». Сам подбор доступен без регистрации.

2. Что реализовано

  • Форма подбора с обязательными полями: город, дата мероприятия, тип мероприятия, категория подрядчика и бюджет.
  • Опциональные параметры: длительность и предпочтительный язык.
  • Серверная валидация допустимых города, даты, формата, категории, языка, положительного целого бюджета и длительности от 0 до 24 часов.
  • Последовательная фильтрация по занятости в busy_dates, поддерживаемому формату, бюджету и допустимой длительности.
  • Детерминированная оценка кандидатов, стабильная сортировка и выдача TOP-3.
  • Индивидуальное, локально сформированное объяснение «Почему подходит» для каждой карточки.
  • Корректная выдача одного или двух профилей, если требованиям соответствует меньше трёх кандидатов.
  • Разные состояния для случаев «в этом городе такой категории нет» и «кандидаты есть, но никто не проходит условия».
  • Статистика исключений: занятость, формат, бюджет и длительность. Один профиль может учитываться сразу в нескольких причинах.
  • Отображение синтетических профилей с отдельной визуальной меткой.
  • Демонстрационные кнопки «Написать» и «Позвонить»: они не раскрывают настоящий контакт и сообщают, что контакт скрыт в демо.
  • Локальные регистрация, вход и выход из аккаунта.
  • Локальный Demo AI Assistant с предусмотренными сценариями ответа, без внешнего API.
  • Информационные секции «Как это работает», «О сервисе» и блок ассистента.

3. Как работает подбор

Pipeline рекомендации:

Параметры пользователя
        ↓
Поиск подрядчиков выбранной категории в выбранном городе
        ↓
Проверка занятости на выбранную дату
        ↓
Проверка event format
        ↓
Проверка бюджета
        ↓
Проверка длительности
        ↓
Детерминированный scoring
        ↓
Стабильная сортировка
        ↓
TOP-3
        ↓
Индивидуальное объяснение

Обязательные фильтры

  1. Сначала выбираются профили, у которых совпадают город и категория.
  2. Если выбранная дата содержится в busy_dates подрядчика, он помечается как занятый и не может попасть в результат.
  3. Подрядчик должен поддерживать выбранный формат мероприятия.
  4. Его начальная стоимость price_from_kzt не должна превышать бюджет.
  5. Если пользователь указал длительность и у профиля заполнен max_hours, запрос не должен превышать этот лимит. Пустой max_hours означает, что часовой лимит к услуге не применяется.

Язык не является жёстким фильтром: совпадение выбранного языка влияет на оценку, но отсутствие языка в профиле само по себе не исключает кандидата.

Ранжирование

Прошедшие фильтры кандидаты получают числовую оценку из четырёх составляющих:

  • совпадение языка или нейтральный балл, если язык не выбран;
  • запас относительно бюджета;
  • запас по длительности либо нейтральная оценка, когда ограничение неприменимо;
  • наполненность профиля по числу поддерживаемых форматов.

После этого записи сортируются по убыванию оценки. При равных оценках используется стабильный tie-breaker — строковый id подрядчика по возрастанию. В алгоритме нет случайности, поэтому полностью одинаковый запрос к неизменному датасету возвращает одинаковый порядок карточек.

4. Объяснимые рекомендации

Карточка каждого результата содержит не общее рекламное сообщение, а отдельное объяснение, составленное из данных именно этого профиля. Оно может включать:

  • начальную стоимость, факт попадания в бюджет и размер бюджетного запаса;
  • подтверждение выбранного формата;
  • выбранный язык и его наличие либо перечень языков профиля;
  • запрошенную длительность и доступный лимит, если длительность задана;
  • релевантный содержательный фрагмент description профиля.

Служебные приветствия в начале описания пропускаются, а используемый фрагмент ограничивается по длине. Объяснения строятся только на полях профиля и параметрах запроса: алгоритм не добавляет неподтверждённые награды, опыт или достижения.

Генерация объяснений локальная и детерминированная. Она реализована шаблонными правилами приложения, не обращается к внешней LLM и при одинаковом запросе формирует одинаковый текст.

5. Обработка пустой выдачи

Интерфейс различает три результата:

  1. Подрядчики подобраны. Отображаются до трёх карточек, общее число подходящих профилей и дата события.
  2. В выбранном городе нет подрядчиков этой категории. Пользователь получает отдельное сообщение и предложение изменить город или категорию.
  3. Подрядчики категории существуют, но не проходят условия. Показываются число проверенных локальных профилей и статистика причин исключения:
    • заняты на дату;
    • не поддерживают формат;
    • превышают бюджет;
    • не подходят по длительности.

Причины считаются независимо, поэтому один профиль может попасть сразу в несколько счётчиков. Если требованиям соответствуют только один или два кандидата, сервис показывает все найденные профили, не дополняя TOP-3 неподходящими вариантами, и явно сообщает, что это полная подходящая выдача.

6. Данные

Приложение использует предоставленный HackAlem анонимизированный CSV-датасет data/hackathon-dataset-anonymized.csv. В текущей версии в нём 66 профилей и 17 категорий.

Основные поля, используемые рекомендательной системой:

ПолеНазначение
idСтабильный анонимный идентификатор и tie-breaker сортировки
anon_nameАнонимизированное отображаемое имя
categoriesОдна или несколько категорий подрядчика
cityГород профиля
price_from_kztНачальная стоимость в тенге
event_formatsПоддерживаемые форматы мероприятий
languagesЯзыки профиля
max_hoursМаксимальная длительность услуги в часах
busy_datesДаты, в которые подрядчик занят
descriptionТекст профиля для персонализированной детали объяснения
syntheticПризнак искусственно созданного демонстрационного профиля

busy_dates — список дат в ISO-формате, разделённых символом |; совпадение с датой запроса исключает профиль. max_hours может быть пустым для услуг, где присутствие по часам неприменимо; такой профиль не отбрасывается по длительности. Значение synthetic=true означает синтетический, а не реальный профиль. Такие записи визуально отмечаются на карточке надписью «Синтетический профиль».

7. Технологии

ТехнологияРоль в проекте
PythonСерверная логика, загрузка CSV, валидация и рекомендации
FlaskHTTP-маршруты, формы, сессии и рендеринг страниц
HTML5Семантическая структура интерфейса и форм
CSSАдаптивное визуальное оформление
JavaScriptСостояние отправки формы, демо-кнопки контактов и локальный ассистент
Jinja2Серверные HTML-шаблоны, карточки и состояния выдачи
SQLiteЛокальное хранение аккаунтов
WerkzeugГенерация и проверка хешей паролей
pytestАвтоматические тесты приложения и рекомендательной логики

Runtime-зависимости, зафиксированные в requirements.txt, — Flask 3.1.2 и pytest 8.4.2. OpenAI API и NVIDIA API приложением не используются.

8. Архитектура

  • app.py — точка входа Flask, конфигурация, маршруты главной страницы, регистрации/входа и выхода.
  • services/recommender.py — чтение CSV, модели данных, валидация, фильтрация, scoring, сортировка и объяснения.
  • services/auth.py — схема SQLite, нормализация email/телефона, создание и проверка аккаунтов.
  • templates/index.html — форма, результаты, пустые состояния и информационные секции.
  • templates/auth.html — интерфейс регистрации и входа.
  • static/style.css — стили страниц и компонентов.
  • static/script.js — клиентские демо-взаимодействия и ответы ассистента.
  • data/ — рабочий CSV-датасет.
  • tests/ — проверки Flask-маршрутов и рекомендательного движка.
  • instance/eventmatch.db — создаваемая при локальном запуске база аккаунтов; она не хранится в репозитории.

Поток рекомендации

Пользователь
    ↓
Flask (`app.py`)
    ↓
Валидация запроса
    ↓
Recommendation Engine (`services/recommender.py`) ← CSV dataset (`data/`)
    ↓
Фильтрация → scoring → стабильная сортировка → TOP-3 → объяснения
    ↓
HTML / Jinja2 (`templates/index.html`)

Поток регистрации и входа

Пользователь
    ↓
Flask Auth (`app.py`, `services/auth.py`)
    ↓
Werkzeug password hashing / проверка хеша
    ↓
SQLite (`instance/eventmatch.db`)
    ↓
Flask session

9. Регистрация и авторизация

Локальная система аккаунтов поддерживает:

  • регистрацию по email или телефону, имени и паролю;
  • минимальную длину пароля 8 символов;
  • хранение хеша пароля через Werkzeug вместо открытого пароля;
  • вход по email/телефону и паролю;
  • состояние входа через Flask session;
  • выход с очисткой сессии;
  • хранение аккаунтов в SQLite.

Регистрация не обязательна: основной подбор подрядчиков доступен без аккаунта. База создаётся локально по адресу instance/eventmatch.db. Каталог instance/, а также файлы *.db и *.sqlite3, исключены через .gitignore и не должны попадать в Git.

10. EventMatch AI Assistant

В текущей демо-версии EventMatch AI Assistant работает локально на наборе предусмотренных сценариев и не использует внешнюю LLM/API.

Ответы заданы в JavaScript и выбираются детерминированно по тексту вопроса. Ассистент умеет отвечать на пять предусмотренных вопросов:

  • как выбрать подрядчика;
  • почему показано меньше трёх;
  • что означает показатель совпадения;
  • почему выдача изменилась после смены даты;
  • что такое синтетический профиль.

Для других формулировок выводится сообщение об ограниченном демонстрационном режиме. Это справочный UI-компонент, а не генеративная AI-модель.

11. Структура проекта

EventMatch-AI/
├── app.py
├── requirements.txt
├── README.md
├── data/
│   └── hackathon-dataset-anonymized.csv
├── services/
│   ├── __init__.py
│   ├── auth.py
│   └── recommender.py
├── templates/
│   ├── auth.html
│   └── index.html
├── static/
│   ├── script.js
│   └── style.css
└── tests/
    ├── test_app.py
    └── test_recommender.py

В репозитории также сохранены исходные материалы хакатона и предварительные файлы в HackalemAI/; рабочее приложение использует перечисленные выше корневые модули и датасет из data/.

12. Установка и запуск

Требуется установленный Python с поддержкой создания виртуального окружения.

Базовый способ

  1. Скачайте или клонируйте репозиторий.

  2. Перейдите в корневую папку проекта.

  3. Установите зависимости:

    python -m pip install -r requirements.txt
    
  4. Запустите приложение:

    python app.py
    
  5. Откройте в браузере http://127.0.0.1:5000.

Рекомендуемый способ для Linux/macOS

python -m venv .venv
.venv/bin/python -m pip install -r requirements.txt
.venv/bin/python app.py

Активация окружения не обязательна. При желании его можно активировать командой source .venv/bin/activate.

Windows PowerShell без активации

PowerShell может блокировать выполнение Activate.ps1 политикой исполнения. Безопасный вариант — не менять эту политику и запускать Python окружения напрямую:

python -m venv .venv
.\.venv\Scripts\python.exe -m pip install -r requirements.txt
.\.venv\Scripts\python.exe app.py

Затем откройте http://127.0.0.1:5000.

13. Тестирование

Запуск полного набора тестов:

python -m pytest -q

Подтверждённый результат локальной проверки текущей версии: 21 passed.

Тесты проверяют:

  • загрузку всех 66 профилей и 17 категорий;
  • стабильный TOP-3 и наличие индивидуальных объяснений;
  • выдачу одного и двух результатов;
  • различие двух типов пустой выдачи и точные счётчики исключений;
  • исключение занятого подрядчика и влияние даты;
  • поведение пустого max_hours;
  • влияние языка на ranking без превращения его в жёсткий фильтр;
  • валидацию дат и ожидаемых значений бюджета;
  • детерминированность и содержательность объяснений;
  • читаемый формат даты без изменения типа busy_dates;
  • главную страницу, отправку формы и информационные демо-секции;
  • регистрацию, вход, выход и отклонение неверных учётных данных.

14. Как проверить решение жюри

Перед сценариями запустите приложение и откройте главную страницу.

Сценарий A — плотная категория

  • Выберите: Алматы, дата 23.09.2026, формат свадьба, категория Банкетный зал, бюджет 10 000 000 ₸, язык русский.
  • Убедитесь, что показаны три карточки и у каждой своё объяснение «Почему подходит».

Сценарий B — редкая категория

  • Для запроса из сценария A установите бюджет 2 000 000 ₸ и длительность 6 часов.
  • Убедитесь, что сервис показывает один подходящий профиль и сообщение о том, что это все подходящие варианты.

Дополнительная проверка двух результатов: Алматы, 24.09.2026, свадьба, Ведущий, бюджет 2 000 000 ₸, длительность 6 часов, язык русский.

Сценарий C — пустая выдача

  • Проверка отсутствующей категории в городе: выберите Астана и категорию Декоратор — интерфейс должен показать отдельное состояние отсутствия категории.
  • Проверка отфильтрованных кандидатов: Алматы, 24.09.2026, свадьба, Банкетный зал, бюджет 2 000 000 ₸, длительность 6 часов, язык русский. Интерфейс должен сообщить, что профили существуют, но не прошли условия, и показать причины исключения.

Сценарий D — влияние даты

  • Выполните запрос из сценария A для 23.09.2026, затем повторите его для 24.09.2026.
  • Сравните карточки: записи из busy_dates новой даты исключаются, поэтому состав или порядок выдачи может измениться.

Сценарий E — детерминизм

  • Дважды без изменений отправьте запрос из сценария A.
  • Убедитесь, что подрядчики отображаются в одном порядке; одинаковые оценки разрешаются по стабильному id.

15. Безопасность

  • Пароли не сохраняются открытым текстом: в SQLite записывается хеш, созданный Werkzeug.
  • Проверка пароля выполняется сравнением с сохранённым хешем.
  • Локальная пользовательская SQLite и весь каталог instance/ исключены из Git.
  • Приложение не требует внешних AI API, а API-ключи в репозитории не хранятся.
  • Датасет анонимизирован; реальные контакты подрядчиков не публикуются, а кнопки связи показывают только демо-сообщение.

16. Ограничения

  • Сервис не выполняет реальное бронирование и не отправляет заявки подрядчикам.
  • Кнопки контактов демонстрационные; реальные телефонные номера не используются и не раскрываются.
  • Demo AI Assistant не использует внешнюю LLM и отвечает только по локально заданным сценариям.
  • Рекомендации ограничены профилями текущего CSV-датасета.
  • Допустимый календарный диапазон запроса ограничен 23.09.2026–31.12.2026, то есть диапазоном дат демо-данных.
  • Регистрация и база аккаунтов локальны; интеграции с внешними провайдерами авторизации нет.
  • Публичная deployed-версия в репозитории не указана; проект рассчитан на локальный запуск.

17. Возможности развития

Следующие пункты — направления будущего развития, а не функции текущей версии:

  • подключение актуальных каталогов подрядчиков;
  • синхронизация с реальными календарями доступности;
  • безопасное открытие контактов, отправка заявок и бронирование;
  • расширение географии и набора категорий;
  • семантический поиск и embeddings для работы с описаниями;
  • подключение LLM для более гибких, но проверяемых объяснений;
  • внешняя авторизация и постоянное серверное хранилище;
  • публичный deployment.

18. Использование AI при разработке

Codex использовался как AI-агент для разработки и помощи с кодом. Это инструмент процесса разработки, а не runtime-компонент сервиса.

Codex помогал разрабатывать проект, но подбор подрядчиков в текущей версии выполняется локальным детерминированным алгоритмом приложения. Рекомендательная система не вызывает Codex, OpenAI API, NVIDIA API или внешнюю LLM.

19. Deployment

Публичная deployed-версия на момент сдачи отсутствует. Проект запускается локально по инструкции выше.

20. HackAlem AI

HackAlem AI

Case #79-lite — «Умный подбор подрядчиков»

2026

Звёзды
⭐ 0
Форки
0
Язык
HTML
Последний push
в прошлом месяце
Коммиты
15
Авторы
2
Файлы
22
Ветки
6

Авторы коммитов

aliya990 10TmNaz 5

История коммитов

  • 2026-09-23 16:58Merge pull request #5 from BAITC-Hacks/hbb8a6-codex/-readme.mdaliya990
  • 2026-09-23 16:57Prepare EventMatch AI hackathon READMEaliya990
  • 2026-09-23 16:39Merge pull request #4 from BAITC-Hacks/reci1a-codex/-eventmatch-demoaliya990
  • 2026-09-23 16:39Expand EventMatch demo experiencealiya990
  • 2026-09-23 16:21Expand EventMatch demo experiencealiya990
  • 2026-09-23 15:51Fix CSV dataset loadingTmNaz
  • 2026-09-23 15:48Merge branch 'main' into codex-nwrh85aliya990
  • 2026-09-23 15:47Fix data file error message and format codeTmNaz
Все коммиты (15)
  • 2026-09-23 15:46Fix numeric form input validationaliya990
  • 2026-09-23 15:29Merge pull request #1 from BAITC-Hacks/codexaliya990
  • 2026-09-23 15:27Add files via uploadTmNaz
  • 2026-09-23 15:16Add files via uploadTmNaz
  • 2026-09-23 15:15Add files via uploadTmNaz
  • 2026-09-23 15:12Build deterministic EventMatch contractor appaliya990
  • 2026-09-23 14:51Add files via uploadaliya990
Структура репозитория (22 файлов)
.gitignore
2026-09-23_14-52-28.png
HackalemAI/HackAlem AI_ Хакатон-задача_ умный подбор подрядчиков (1).pdf
HackalemAI/README.md
HackalemAI/app.ру
HackalemAI/hackathon-dataset-anonymized.csv
HackalemAI/recommender.py
HackalemAI/requirements.txt
README.md
app.py
data/hackathon-dataset-anonymized.csv
hackathon dataset preview.html
requirements.txt
services/__init__.py
services/auth.py
services/recommender.py
static/script.js
static/style.css
templates/auth.html
templates/index.html
tests/test_app.py
tests/test_recommender.py
Ветки (6)

Обсуждение 0 комментариев

Войдите, чтобы комментировать

Пока нет комментариев — будьте первым.