Smart Contractor Recommendation
FastAPI и Streamlit: подбирает до трёх подрядчиков из каталога по городу, дате, формату, категории, бюджету, языку и длительности, объясняет каждый…
О проекте
Команда: BaiterekAI
Кейс HackAlem.ai: Креативные индустрии — Firebird
Стадия: Рабочий MVP
Задача кейса: «#79-lite»: подобрать до 3 подрядчиков для мероприятия и объяснить выбор
Суть
FastAPI и Streamlit: подбирает до трёх подрядчиков из каталога по городу, дате, формату, категории, бюджету, языку и длительности, объясняет каждый выбор и возвращает сводку причин отсева.
Как устроено
Цепочка обязательных фильтров: город, категория, дата и busy_dates, бюджет, формат, язык, max_hours. Оставшиеся профили ранжируются по score, берутся топ-3. Объяснение собирается по шаблону из полей профиля. Возвращаются статусы found, category_not_found или no_match и rejection_summary со счётчиками отсева по каждой причине. LLM не используется, порядок детерминирован.
Ключевые решения
- каскад фильтров
- детерминированный скоринг
- шаблонные объяснения
- rejection summary
Особенности
rejection_summary показывает, сколько профилей отсеяно по каждой причине, и это делает пустую выдачу объяснимой.
Стек
Python · FastAPI · Pydantic · Uvicorn · Streamlit · pytest
Проект создан за 5 часов на финале хакатона HackAlem.ai (23 сентября 2026, Астана). Код — BAITC-Hacks/hack-c119ee0f-baiterekai.
README
README.mdSmart Contractor Recommendation
Smart Contractor Recommendation — веб-приложение для подбора подрядчиков для мероприятий.
Пользователь указывает город, дату, тип мероприятия, категорию подрядчика, бюджет, а также при необходимости язык и длительность. Система анализирует каталог предоставленных подрядчиков, отбирает подходящие варианты и показывает до 3 результатов с объяснением, почему каждый подрядчик соответствует запросу.
Система использует только реальные профили из предоставленного каталога и не создаёт вымышленных подрядчиков.
Как запустить проект
1. Установить зависимости
В корневой папке проекта выполните:
python -m pip install -r requirements.txt
2. Запустить Backend
Откройте первый терминал в корневой папке проекта.
Для Windows PowerShell:
$env:CONTRACTORS_CSV_PATH = "$PWD\data\contractors.csv"
python -m uvicorn app.main:app --reload
После запуска FastAPI будет доступен по адресу:
Документация API:
3. Запустить Frontend
Откройте второй терминал в корневой папке проекта:
python -m streamlit run frontend/app.py
После запуска откроется веб-интерфейс приложения.
Как проверить проект
Для проверки рекомендуется выполнить следующие сценарии через веб-интерфейс.
Сценарий 1 — обычный подбор
Введите:
- Город: Алматы
- Дата: 2026-11-14
- Тип мероприятия: свадьба
- Категория: Фотограф
- Бюджет: 500000
- Язык: русский
- Длительность: 6 часов
Ожидаемый результат: система находит до 3 подходящих фотографов. Для каждого результата отображаются имя, категория, город, стартовая цена, score и объяснение.
Сценарий 2 — регистр букв не влияет на поиск
Текстовые параметры запроса можно вводить в любом регистре.
Например, следующие значения должны обрабатываться одинаково:
ФотограффотографФОТОГРАФ
То же относится к типу мероприятия, например:
СвадьбасвадьбаСВАДЬБА
А также к городу, языку и другим текстовым параметрам.
При этом поиск не исправляет опечатки: меняется только регистр букв.
Сценарий 3 — редкая категория
Введите:
- Город: Алматы
- Дата: 2026-11-14
- Тип мероприятия: свадьба
- Категория: Флорист
- Бюджет: 500000
- Язык: русский
- Длительность: 6 часов
Ожидаемый результат: найден 1 подходящий подрядчик.
Система не создаёт дополнительные вымышленные результаты, если в каталоге подходит только один профиль.
Сценарий 4 — отсутствие подходящих вариантов
Используйте:
- Город: Алматы
- Дата: 2026-11-14
- Тип мероприятия: свадьба
- Категория: Фотограф
- Бюджет: 1
- Язык: русский
- Длительность: 6 часов
Ожидаемый результат:
- подходящих подрядчиков нет;
- статус —
no_match; - количество результатов — 0;
- система показывает причины, по которым профили были исключены.
Сценарий 5 — проверка занятости
Для проверки календаря подрядчиков выполните один и тот же запрос для двух дат.
Сначала:
- Город: Алматы
- Дата: 2026-11-12
- Тип мероприятия: свадьба
- Категория: Фотограф
- Бюджет: 500000
- Язык: русский
- Длительность: 6 часов
Затем измените только дату на:
- 2026-11-14
В каталоге подрядчик HK-68220 занят 12 ноября и свободен 14 ноября.
Поэтому 12 ноября он не должен отображаться среди результатов, а 14 ноября может появиться.
Этот сценарий демонстрирует, что система учитывает busy_dates и действительно меняет рекомендации в зависимости от даты мероприятия.
Что делает система
После отправки формы запрос проходит следующие этапы:
Параметры пользователя → фильтрация подрядчиков → проверка города → проверка категории → проверка даты и занятости → проверка бюджета → проверка формата мероприятия → проверка языка → проверка длительности → ранжирование → выбор до 3 результатов → формирование объяснений → отображение результата.
Система сначала применяет обязательные фильтры, после чего ранжирует оставшиеся подходящие профили.
Учитываются:
- город;
- категория;
- дата;
- занятость подрядчика;
- бюджет;
- формат мероприятия;
- язык;
- длительность.
Текстовые параметры сравниваются без учёта регистра букв.
Если у подрядчика отсутствует ограничение max_hours, длительность не используется как ограничение.
Одинаковый запрос возвращает одинаковый порядок результатов.
Объяснение результатов
Для каждого найденного подрядчика система формирует конкретное объяснение на основе данных его профиля.
Например:
Город — Алматы; категория — «Фотограф»; формат — «свадьба»; по календарю свободен на 2026-11-14; цена от 190 000 ₸ при бюджете 500 000 ₸; указан запрошенный язык — русский; запрошено 6 ч, доступная длительность — до 12 ч.
В объяснениях также может использоваться информация из описания профиля.
Цена является стартовой и может требовать уточнения у подрядчика.
Обработка отсутствия результатов
Система использует три статуса:
found— подходящие подрядчики найдены.category_not_found— указанной категории нет в каталоге.no_match— категория существует, но после применения параметров запроса подходящих подрядчиков не осталось.
Если подходящих вариантов меньше трёх, система показывает только найденные варианты.
Если подходящих вариантов нет, система не создаёт вымышленные профили, а возвращает пустой результат и причины отсева.
Rejection Summary
Для анализа причин отсева система возвращает rejection_summary.
Например:
{
"city": 16,
"category": 42,
"busy": 5,
"budget": 3,
"event_format": 0,
"language": 0,
"duration": 0
}
Это показывает, сколько профилей было исключено по каждой причине.
Архитектура
Приложение состоит из трёх основных частей:
Streamlit Frontend
↓
FastAPI API
↓
Recommendation Engine
↓
Contractor Catalog
Frontend отвечает за взаимодействие с пользователем.
FastAPI принимает и валидирует запросы и передаёт их в Recommendation Engine.
Recommendation Engine выполняет фильтрацию, ранжирование и формирование объяснений.
Каталог подрядчиков хранится в data/contractors.csv.
API
Основной endpoint:
POST /recommend
Пример запроса:
{
"city": "Алматы",
"date": "2026-11-14",
"event_type": "свадьба",
"category": "Фотограф",
"budget": 500000,
"language": "русский",
"duration": 6
}
Пример ответа:
{
"status": "found",
"count": 3,
"results": [
{
"id": "HK-68220",
"name": "Рок Ли",
"category": "Фотограф",
"city": "Алматы",
"price": 190000,
"score": 0.62,
"explanation": "..."
}
],
"rejection_summary": {}
}
Дополнительный endpoint:
GET /health
Ответ:
{
"status": "ok"
}
Данные
Каталог находится в:
data/contractors.csv
Для каждого профиля используются данные о:
- идентификаторе;
- имени;
- категориях;
- городе;
- стартовой цене;
- форматах мероприятий;
- языках;
- максимальной длительности;
- занятых датах;
- описании;
- дополнительных признаках данных.
Система использует только предоставленный каталог.
Технологии
- Python
- FastAPI
- Pydantic
- Uvicorn
- Streamlit
- CSV
Структура проекта
hack-c119ee0f-baiterekai/
├── app/
│ ├── main.py
│ ├── api/
│ │ └── routes.py
│ ├── schemas/
│ │ └── recommendation.py
│ ├── recommender/
│ │ ├── engine.py
│ │ ├── filters.py
│ │ ├── scoring.py
│ │ └── explanations.py
│ └── data/
│ ├── loader.py
│ └── models.py
├── frontend/
│ ├── app.py
│ ├── api_client.py
│ └── components.py
├── data/
│ └── contractors.csv
├── tests/
├── requirements.txt
└── README.md
Ограничения
- Приложение не выполняет бронирование.
- Приложение не отправляет уведомления.
- Система не создаёт новых подрядчиков.
- Цена в каталоге является стартовой и может измениться после уточнения условий.
- Максимальное количество рекомендаций — 3.
- Результаты зависят от полноты и качества предоставленного каталога.
- Нечувствительность к регистру не означает исправление опечаток.
Быстрый сценарий демонстрации для жюри
- Запустить Backend.
- Запустить Streamlit Frontend.
- Выполнить обычный поиск фотографа в Алматы на 14.11.2026 с бюджетом 500000 ₸.
- Показать 3 результата и объяснения.
- Повторить тот же запрос, написав
фотографс маленькой буквы, и показать, что результат остаётся тем же. - Выбрать категорию «Флорист» и показать, что система корректно возвращает только существующий подходящий профиль.
- Установить бюджет 1 ₸ и показать
no_matchс причинами отсева. - Сравнить одинаковый запрос для 12.11.2026 и 14.11.2026 и показать влияние
busy_dates.
Таким образом можно проверить основные требования решения: подбор по параметрам, ограничение бюджета, категории, языка и длительности, нечувствительность к регистру, проверку занятости, работу с редкими категориями, отсутствие вымышленных результатов, обработку пустого результата и объяснение рекомендаций.
Команда
Проект разработан в рамках хакатона HackAlem.
Основные направления разработки:
- Backend / FastAPI
- Recommendation Engine / Data
- Streamlit Frontend
Ссылки
Страница хакатона: https://edu.astanahub.com/hackathons/df4743f5-c492-415c-b45a-1f13adb78e06
Telegram хакатона: https://t.me/+rLHvxHMpZdtiYThi
Авторы коммитов
История коммитов
- 2026-09-23 17:42fix: improve numeric input fieldswhyquas
- 2026-09-23 17:10Delete .env.examplewhyquas
- 2026-09-23 17:00docs: add project READMEwhyquas
- 2026-09-23 16:57Fix case-insensitive contractor matchingPracticum
- 2026-09-23 16:42Merge pull request #7 from BAITC-Hacks/fix/frontend-api-contractAkhmetov Nurali
- 2026-09-23 16:38fix: align frontend with recommendation APIPracticum
- 2026-09-23 16:14Merge pull request #6 from BAITC-Hacks/feature/backend-apikasym0055
- 2026-09-23 16:08feat: integrate recommendation enginewhyquas
Все коммиты (16)
- 2026-09-23 15:57Merge pull request #5 from BAITC-Hacks/feature/frontendkasym0055
- 2026-09-23 15:51Merge pull request #4 from BAITC-Hacks/feature/backend-apikasym0055
- 2026-09-23 15:49Merge pull request #3 from BAITC-Hacks/feature/recommendation-enginewhyquas
- 2026-09-23 15:46feat: add deterministic contractor recommendation enginePracticum
- 2026-09-23 15:42feat: add Streamlit recommendation frontendnurabp
- 2026-09-23 15:02feat: add recommendation APIwhyquas
- 2026-09-23 14:52Merge pull request #1 from BAITC-Hacks/feature/project-architectureAkhmetov Nurali
- 2026-09-23 14:50chore: add project architecturewhyquas
Структура репозитория (24 файлов)
.gitignore README.md app/__init__.py app/api/__init__.py app/api/routes.py app/data/__init__.py app/data/loader.py app/data/models.py app/main.py app/recommender/__init__.py app/recommender/engine.py app/recommender/explanations.py app/recommender/filters.py app/recommender/scoring.py app/schemas/__init__.py app/schemas/recommendation.py data/.gitkeep data/contractors.csv frontend/api_client.py frontend/app.py frontend/components.py requirements.txt tests/test_api.py tests/test_recommender.py
Обсуждение 0 комментариев
Войдите, чтобы комментироватьПока нет комментариев — будьте первым.