Умный подбор подрядчиков
Streamlit-приложение подбора до 3 подрядчиков на мероприятие с объяснениями и причинами отсева, дополненное двусторонним маркетплейсом с…
О проекте
Команда: BaiTau
Кейс HackAlem.ai: Креативные индустрии — Firebird
Стадия: Рабочий MVP
Задача кейса: «#79-lite»: подобрать до 3 подрядчиков для мероприятия и объяснить выбор
Суть
Streamlit-приложение подбора до 3 подрядчиков на мероприятие с объяснениями и причинами отсева, дополненное двусторонним маркетплейсом с регистрацией подрядчиков.
Как устроено
core/generator.py фильтрует каталог по категории, городу, занятости busy_dates, бюджету, формату, языку и длительности, затем начисляет оценку по цене относительно бюджета, языку и лимиту часов и сортирует детерминированно (оценка, цена, ID). Объяснения собираются из фактов профиля без LLM. safe_pipeline_call() валидирует ввод и ответ, при ошибке или таймауте 15 с отдаёт резервный демо-ответ с fallback=True.
Ключевые решения
- жёсткие фильтры
- детерминированный скоринг
- шаблонные объяснения
- fallback-обёртка пайплайна
Особенности
Разделение Core/helpers с явным контрактом и защитным fallback при сбоях; 36 тестов, включая регрессию демо-сценария со сменой даты.
Стек
Python · Streamlit · unittest
Проект создан за 5 часов на финале хакатона HackAlem.ai (23 сентября 2026, Астана). Код — BAITC-Hacks/hack-0cdadb85-baitau.
README
README.mdУмный подбор подрядчиков
Приложение для подбора специалистов на мероприятия: свадьбы, корпоративы, тои и другие события. Заказчик задаёт условия и получает до 3 подходящих подрядчиков с объяснением выбора.
Интерфейс работает на Streamlit. Подбор и объяснения выполняются локально, без LLM и ключей внешних API.
Быстрый запуск
Выполняйте команды из корня проекта — папки с app.py и requirements.txt.
Нужен Python с модулями venv и pip.
1. Создайте виртуальное окружение:
python -m venv .venv
2. Активируйте его командой для вашей системы:
Linux / macOS:
source .venv/bin/activate
Windows PowerShell:
.venv\Scripts\Activate.ps1
Windows cmd:
.venv\Scripts\activate.bat
3. Установите зависимости и запустите приложение:
python -m pip install -r requirements.txt
python -m streamlit run app.py
Откройте адрес из терминала — обычно http://localhost:8501.
Для остановки нажмите Ctrl+C в терминале. Единственная прямая внешняя
зависимость проекта — streamlit; остальные пакеты установятся вместе с ней.
Если появилась ошибка No module named 'streamlit', активируйте окружение
и повторите установку через python -m pip install -r requirements.txt.
Как пользоваться
- Укажите город, дату, формат мероприятия, категорию услуг и бюджет в тенге.
- При необходимости задайте язык и длительность в блоке «Дополнительные параметры».
- Нажмите «Подобрать подрядчиков».
В карточках будут имя, категория, город, цена «от» и объяснение выбора. Если вариантов нет, приложение предложит изменить условия. Если подрядчики есть, но не прошли фильтры, покажет причины: занятость, бюджет, формат, язык или длительность.
Демо за несколько минут
Используйте эти параметры для подбора:
| Параметр | Значение |
|---|---|
| Город | Алматы |
| Дата | 2026-11-14 |
| Формат | свадьба |
| Категория | Фотограф |
| Бюджет | 400 000 ₸ |
| Длительность | 8 часов |
| Язык | русский |
На исходном каталоге результат содержит
HK-68220, HK-76268, HK-91112 в этом порядке.
Измените только дату на 2026-11-15 и повторите подбор. Останутся
HK-68220 и HK-91112: у HK-76268 новая дата указана в busy_dates.
Оба запроса возвращают matched и fallback=False.
Как устроен подбор
Сначала алгоритм выбирает подрядчиков нужной категории в выбранном городе. Затем исключает тех, кто занят на указанную дату, превышает бюджет или не поддерживает формат мероприятия, запрошенный язык либо длительность.
Оставшиеся кандидаты получают оценку по начальной цене относительно бюджета, языку и лимиту часов. Кандидаты упорядочиваются по убыванию оценки; при равенстве — по возрастанию цены, затем ID. При одинаковых данных и запросе результат одинаковый. Объяснения составляются из фактов профиля и условий запроса.
| Статус | Что означает |
|---|---|
matched | Найдено от 1 до 3 подходящих подрядчиков. |
no_category_in_city | В выбранном городе нет подрядчиков этой категории. |
no_eligible_candidates | Категория в городе есть, но никто не прошёл остальные условия. |
Защита от сбоев
safe_pipeline_call() проверяет входные данные и ответ Core. При ошибке,
некорректном ответе или ожидании дольше 15 секунд возвращает резервный ответ
из helpers/mock_data.json с признаком fallback=True.
Резервная подборка — заранее подготовленный демо-сценарий. Её параметры
могут отличаться от текущего запроса; интерфейс сообщает о переходе в демо-режим.
Если резервные данные тоже недоступны или невалидны, helpers возвращает пустой
ответ с fallback=True.
Данные и хранение
| Файл | Назначение |
|---|---|
helpers/contractors.json | Исходный каталог: 66 профилей, из них 13 синтетических. Не изменяется при работе приложения. |
helpers/mock_data.json | Резервный ответ для демо при сбое подбора. |
given_data/ | Исходный анонимизированный CSV и HTML-превью. |
Данные проходят нормализацию и валидацию. Занятые даты busy_dates сохраняются
в формате YYYY-MM-DD и участвуют в фильтрации. Флаги synthetic, city_imputed
и price_imputed сохраняют сведения о синтетических профилях и восстановленных
городах и ценах. UI отмечает синтетические профили и позволяет посмотреть,
какие поля были восстановлены.
load_contractors() возвращает 66 исходных профилей. Загрузка каталога
и выполнение подбора не изменяют исходный JSON-файл.
Архитектура и контракт
app.py — Streamlit: форма запроса, карточки и сообщения
│
├── helpers/utils.py — загрузка, нормализация и валидация
│ └── contractors.json — исходные 66 профилей
│
└── helpers/utils.py — safe_pipeline_call()
├── core/generator.py — фильтры → оценка → top-3 → объяснения
└── mock_data.json — резервный ответ при сбое
Пример запроса к run_pipeline(request, contractors) через safe_pipeline_call:
{
"city": "Алматы",
"date": "2026-11-14",
"event_format": "свадьба",
"category": "Фотограф",
"budget_kzt": 400000,
"duration_hours": 8,
"language": "русский"
}
Первые пять полей обязательны. Бюджет — положительное целое число в тенге.
duration_hours и language можно не передавать или указать как null.
Основные поля ответа через safe_pipeline_call:
| Поле | Содержимое |
|---|---|
status | Один из трёх статусов выше. |
query | Параметры запроса, которому соответствует ответ. |
results | До трёх карточек с оценкой и объяснением; пустой список при отсутствии рекомендаций. |
meta | Число кандидатов и результатов, диагностика причин отказа. |
fallback | False при штатном ответе Core, True при резервном ответе. |
Тесты
Из корня проекта выполните:
python -m unittest discover -v
На момент обновления README: 36 тестов, все проходят. Они проверяют сохранность данных, фильтры, ранжирование, объяснения, статусы, fallback, смену даты и интеграцию Core с helpers.
Структура проекта
Основные файлы и папки:
.
├── app.py # Streamlit-интерфейс
├── core/
│ ├── generator.py # Алгоритм рекомендаций
│ ├── INTEGRATION.md
│ ├── test_catalog.py
│ └── test_generator.py
├── helpers/
│ ├── utils.py # Загрузка, валидация и fallback
│ ├── prepare_data.py # Подготовка исходных данных
│ ├── contractors.json
│ ├── mock_data.json
│ ├── README.md
│ ├── test_core_integration.py
│ ├── test_dataset.py
│ └── test_utils.py
├── docs/ # Дополнительные материалы проекта
├── given_data/
├── requirements.txt
└── README.md
Подробности реализации: интеграция Core и работа с данными.
Ограничения текущей версии
- Приложение рекомендует подрядчиков. Бронирования, оплаты и аккаунтов нет.
- Доступность определяется только сохранёнными
busy_dates. - Выбор дат в UI ограничен диапазоном 23.09.2026–31.12.2026.
- Бюджет сравнивается с ценой «от», которая не является итоговой сметой заказа.
max_hours: nullозначает, что часовой лимит не указан; такой профиль не исключается по длительности.
Авторы коммитов
История коммитов
- 2026-09-23 17:53docs: clarify setup and usage for stable mainscirtor
- 2026-09-23 17:50docs: clarify setup and marketplace workflowsscirtor
- 2026-09-23 17:39feat(ui): polish marketplace UX and visual hierarchyscirtor
- 2026-09-23 17:22docs(ui): document marketplace user flowsLight
- 2026-09-23 17:22docs(core): document marketplace recommendation featuresMinato7879
- 2026-09-23 17:22docs(data): document marketplace storage featuresscirtor
- 2026-09-23 17:17docs(ui): document marketplace user flowsLight
- 2026-09-23 17:15docs(core): document marketplace recommendation featuresMinato7879
Все коммиты (40)
- 2026-09-23 17:13docs(data): document marketplace storage featuresscirtor
- 2026-09-23 16:57fix(ui): repair contractor role navigationMinato7879
- 2026-09-23 16:48Merge remote-tracking branch 'origin/feature/marketplace' into feature/marketplaceMinato7879
- 2026-09-23 16:33Merge remote-tracking branch 'origin/feature/marketplace' into feature/marketplaceMinato7879
- 2026-09-23 16:28Merge remote-tracking branch 'origin/main' into feature/marketplaceMinato7879
- 2026-09-23 16:27Merge remote-tracking branch 'origin/main' into feature/marketplaceLight
- 2026-09-23 16:22docs: document data reliability guaranteesscirtor
- 2026-09-23 16:19feat(ui): robust role synchronization and contractor registration handlingLight
- 2026-09-23 16:19test(data): add feature storage regression coveragescirtor
- 2026-09-23 16:12test(core): verify persisted feature catalog integrationMinato7879
- 2026-09-23 16:08feat(ui): implement two-sided marketplace flow with role selector and contractor registrationLight
- 2026-09-23 16:05feat: add separate feature contractor storagescirtor
- 2026-09-23 16:04test(core): verify user-submitted contractor integrationMinato7879
- 2026-09-23 15:56test(core): add final integration regressionMinato7879
- 2026-09-23 15:45chore(ui): document stable demo scenarioLight
- 2026-09-23 15:23docs: add project READMEscirtor
- 2026-09-23 15:05test(core): add final demo regression coverageMinato7879
- 2026-09-23 15:01fix(ui): use st.html and dedent for raw HTML cards renderingLight
- 2026-09-23 14:35chore: add runtime dependenciesscirtor
- 2026-09-23 14:17Merge remote-tracking branch 'origin/main' into lightLight
- 2026-09-23 14:12Merge contractor recommendation core into mainMinato7879
- 2026-09-23 14:10test: verify core integration with shared helpersMinato7879
- 2026-09-23 14:09Merge remote-tracking branch 'origin/main' into feature/authMinato7879
- 2026-09-23 14:07test: verify core against shared contractor catalogMinato7879
- 2026-09-23 14:05Merge remote-tracking branch 'origin/main' into feature/authMinato7879
- 2026-09-23 14:03feat: prepare normalized contractor datasetscirtor
- 2026-09-23 14:02Merge branch 'main' into scirtorscirtor
- 2026-09-23 14:01data: share anonymized contractor source datasetscirtor
- 2026-09-23 14:01feat: build contractor recommendation demo UILight
- 2026-09-23 13:58feat: add validation and fallback utilitiesscirtor
- 2026-09-23 13:54feat: implement contractor recommendation pipelineMinato7879
- 2026-09-23 13:52Create Test1Minato7879
Структура репозитория (25 файлов)
README.md Test1 app.py core/INTEGRATION.md core/__init__.py core/generator.py core/test_catalog.py core/test_generator.py docs/CORE_FEATURES.md docs/DATA_FEATURES.md docs/UI_FEATURES.md given_data/.gitignore given_data/README.md given_data/hackathon dataset anonymized .csv given_data/hackathon dataset preview.html helpers/README.md helpers/__init__.py helpers/contractors.json helpers/mock_data.json helpers/prepare_data.py helpers/test_core_integration.py helpers/test_dataset.py helpers/test_utils.py helpers/utils.py requirements.txt
Обсуждение 0 комментариев
Войдите, чтобы комментироватьПока нет комментариев — будьте первым.