AAYMA
RU
Войти

AIZAK

Streamlit-сервис подбора до трёх подрядчиков для мероприятия по городу, категории, дате, формату и бюджету: прозрачная воронка фильтров, балльное…

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

О проекте

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

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

Суть

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

Как устроено

Официальный CSV (66 профилей) последовательно фильтруется по городу, категории, занятым датам, цене не выше бюджета, формату, языку и часам. Оставшиеся ранжируются взвешенной эвристикой: соответствие формату 0.35, запас бюджета 0.25, семантика 0.15 (не подключена), гибкость 0.15, опыт 0.10. На топ-3 собираются факты, после чего один пакетный запрос к OpenAI Responses API (gpt-4.1-mini, structured outputs) пишет объяснения. ID, числа и цитаты в ответе проверяются по facts, при сбое показываются шаблоны. Если выдача пустая, система подсказывает другую дату, бюджет или город.

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

  • filter funnel
  • weighted heuristic ranking
  • structured outputs
  • grounding check of numbers/quotes
  • template fallback
  • alternative suggestions

Метрики

Живой AI: ответ за 5.6–6.3 с, ~1 700 токенов на запрос; датасет 66 профилей

Особенности

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

Стек

Python 3.12 · Streamlit · pytest

Модели

gpt-4.1-mini-2025-04-14 · OpenAI Responses API


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

README

README.md

AIZAK — объяснимый подбор подрядчиков для мероприятий

Конкурсный проект команды AIZAK для HackAlem, задача «Умный подбор подрядчиков (#79-lite)». Официальный репозиторий: BAITC-Hacks/hack-b82ccf3d-aizak. main — ветка сдачи; integration/mvp-hour2 — ветка интеграции и проверки. Проект рассчитан на локальный запуск. Публичный деплой и облачный хостинг не нужны и не настроены.

Назначение и сценарий

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

  1. Выберите город, категорию, дату, формат мероприятия и бюджет в тенге.
  2. При необходимости укажите язык и длительность; 0 часов в форме означает отсутствие ограничения.
  3. Нажмите «Подобрать»: получите до трёх реальных записей из предоставленного CSV.
  4. Карточки показывают цену «от», место и балл, индивидуальные факты, объяснение и предупреждения о данных.
  5. В блоке «Как мы подобрали» видна последовательная воронка фильтров. При неполной/пустой выдаче могут появиться подтверждённые каталогом подсказки по дате, бюджету или другому городу. Подсказки не меняют запрос автоматически: внесите изменения в форму и повторите поиск.
СтатусЗначение
foundЕсть 1–3 подходящие карточки
no_categoryВ выбранном городе нет категории; другой город предлагается при наличии категории там
none_matchКатегория есть, но кандидаты исключены по условиям

Бронирование, отправка заявок и уведомления подрядчикам не входят в MVP.

Собранные версии и вклад участников

Участник / областьРеализованный вкладИсходная ветка и коммит
Аслан / frontendStreamlit, форма, карточки, валидация контракта, UI-тестыfeature/streamlit-ui, 220416f
Алибек / backendCSV/JSONL, фильтры, ранжирование, факты, резервные тексты, проверка AI, альтернативы и воронкаfeature/matching, cb757a7 (включает 5505453, 559a322, 3220b61)
Интегратор / AI и сборкаПодключение компонентов, пакетный OpenAI-запрос, .env, резерв при сбое, проверка совместимости, сквозные тесты и READMEintegration/mvp-hour2; сохранение AI-модуля — e83a5dc

Начальный README: 7b0ffdc. История и авторские коммиты участников сохранены. Люди определяют требования и проверяют результат; Codex и Claude помогают с реализацией, тестами и документацией. Командная работа фиксируется содержательными коммитами.

Запуск с чистого клона

Нужны доступ к приватному репозиторию, Git и Python 3.12 (проверена версия 3.12.14). Зависимость интерфейса — streamlit==1.55.0 в ui/requirements.txt. Backend использует стандартную библиотеку Python. База данных, GPU, отдельный HTTP-backend и API-ключ для базового локального сценария не требуются.

Windows PowerShell:

git clone https://github.com/BAITC-Hacks/hack-b82ccf3d-aizak.git
cd hack-b82ccf3d-aizak
git switch main
py -3.12 -m venv .venv
.\.venv\Scripts\python.exe -m pip install -r ui/requirements.txt
.\.venv\Scripts\python.exe -m streamlit run ui/app.py --server.address 127.0.0.1

Откройте http://127.0.0.1:8501. Если порт занят, добавьте --server.port 8502. Используйте интерпретатор вашего виртуального окружения; активация окружения необязательна. Для проверки интеграционной ветки замените git switch main на git switch integration/mvp-hour2.

macOS/Linux, после клонирования и выбора ветки:

python3.12 -m venv .venv
.venv/bin/python -m pip install -r ui/requirements.txt
.venv/bin/python -m streamlit run ui/app.py --server.address 127.0.0.1

Данные и фильтрация

Используется неизменённый официальный data/hackathon-dataset-anonymized.csv: 66 профилей, 13 synthetic. Рабочий интерфейс не подменяет его mock-профилями. Loader поддерживает CSV и JSONL, списки через |, числа, boolean, уникальность ID и проверку дат. Пустой busy_dates допустим и означает отсутствие занятых дат в предоставленном календаре.

Подтверждённые поля: id, anon_name, categories, city, price_from_kzt, event_formats, languages, max_hours, busy_dates, description, synthetic, city_imputed, price_imputed. Фильтры проверяют город, категорию, дату, стартовую цену не выше бюджета, формат, а также язык и часы, если они заданы. Для исполнителей и площадок занятость проверяется одинаково. max_hours=null означает работу без привязки к присутствию на площадке.

Окно календаря: 23.09.2026–31.12.2026. Вне него доступность неизвестна; UI не принимает такую дату, backend исключает кандидатов с отдельной причиной. Путь к CSV определяется от репозитория, а не от текущей папки терминала. При необходимости задайте AIZAK_DATASET в окружении для другого официального CSV/JSONL; при отсутствии/ошибке файла показывается ошибка, а не вымышленные карточки.

Архитектура и контракт

Streamlit ui/app.py
  → ui/service.py: проверка запроса
  → backend.load_profiles(): официальный CSV
  → backend.find_contractors(): фильтры → ранжирование → топ-3 → facts, шаблоны, suggestions, trace
  → backend.explanations.add_explanations(): один OpenAI-запрос на выдачу либо резерв
  → ui/contracts.py: проверка результата → карточки, подсказки, воронка

Исходный backend вызывается без сетевых функций. OpenAI подключён отдельным этапом после готового подбора, а не как три отдельных вызова на каждую карточку. API-контракт: backend/CONTRACT.md. Подключение UI: ui/INTEGRATION.md.

from backend import find_contractors, load_profiles
result = find_contractors({
    "city": "Алматы", "category": "Ведущий", "date": "2026-10-15",
    "event_type": "свадьба", "budget": 1500000, "hours": None, "language": None,
}, load_profiles())

Ответ содержит status, message, matches, excluded, more_available, funnel, suggestions, trace. Карточки содержат profile, match_reasons, warnings, facts, explanation, explanation_source, explanation_check. AI-адаптер может менять только текст и источник объяснения и добавлять explanation_status; ID, порядок, оценки, профили, фильтры, причины и подсказки сохраняются.

Ранжирование и индивидуальные факты

Прошедшие фильтры сортируются по баллу убыванию, цене возрастанию, затем ID. Это версия Алибека cb757a7; прежний MVP сортировал только по цене и ID. В facts.ranking доступны балл, компоненты, место и причины преимущества над следующим кандидатом.

КомпонентаВесОснование
Соответствие описания формату0.35Ключевые слова формата в описании
Запас бюджета0.251 − цена / бюджет
Семантическое сходство0.15Не подключено в рабочем UI, равно 0; есть необязательный backend-hook
Гибкость0.15Число языков и максимальная длительность, ограниченные шкалой
Признаки опыта0.10Упоминания опыта/объёмов в описании

Вес отключённой семантики не перераспределяется. Балл — объяснимая эвристика, а не рейтинг качества или проверка квалификации. Одинаковые входные данные дают одинаковый порядок; некорректное значение необязательного semantic-hook заменяется нулём.

facts включает цену, дату, формат, языки, часы, происхождение данных, короткие дословные фрагменты описания и отличия от других выбранных карточек. Описание — заявление из датасета, а не независимо проверенная характеристика. Подсказки по дате/бюджету вычисляются повторной проверкой условий, без ослабления текущего запроса. Один исключённый профиль может иметь несколько причин; их количества нельзя складывать как число людей.

OpenAI и настройка .env

Провайдер — OpenAI Responses API, модель по умолчанию gpt-4.1-mini-2025-04-14. NVIDIA не подключён. Дополнительные Python-зависимости для OpenAI не нужны. Схема ответа основана на OpenAI Structured Outputs.

В папке запускаемой версии проекта скопируйте backend/.env.example в backend/.env, если .env ещё не существует. Не перезаписывайте существующие настройки. Вставьте ключ локально после OPENAI_API_KEY=:

OPENAI_API_KEY=
OPENAI_MODEL=gpt-4.1-mini-2025-04-14
AIZAK_AI_ENABLED=true
AIZAK_AI_TIMEOUT_SECONDS=8

Переменные окружения имеют приоритет над .env, в том числе пустой ключ и AIZAK_AI_ENABLED=false. Файл ищется относительно backend/ai_config.py. Поддерживаются однострочные KEY=value, кавычки и комментарии; без интерполяции или запуска shell. Для проверки без сети в PowerShell задайте $env:AIZAK_AI_ENABLED = "false" перед запуском. .env и .env.* исключены из Git, кроме безопасного .env.example; ключ не следует присылать в чат.

Модель получает только факты выбранных 1–3 карточек, предупреждения и запрос: без имён, полного каталога, полных описаний, календарей и исключённых кандидатов. Ответ — {"explanations": [{"id": "…", "explanation": "…"}]}. Текст связывается с карточкой по ID; перестановка объектов API не меняет выдачу. Проверяются ID, полнота, длина/уникальность текста, числа и цитаты по facts. Если ответ неполный, неподтверждённый или API недоступен, показываются шаблоны Алибека из тех же фактов. Проверка чисел/цитат — ограниченная эвристика, не доказательство истинности каждого утверждения модели.

Одна попытка на поиск, без автоповторов; таймаут сетевой операции 8 секунд (настройка 0.1–8), ограничены токены и размер ответа. Пустые результаты и перерисовка UI не вызывают API. С ключом новый поиск может расходовать кредиты. Используется store=false, редиректы запрещены; ключ и тела ошибок API не выводятся в интерфейс или логи.

Статус живого AI (23.09.2026): первая попытка с таймаутом 5 с не дождалась ответа (5.4 с). После увеличения таймаута до 8 с выполнено три живых запроса на официальном CSV (Алматы / Ведущий / свадьба / 1 500 000 ₸): ответ приходит за 5.6–6.3 с (около 1 700 токенов на запрос). Два ответа прошли проверку и показаны как openai с уникальными текстами и неизменным порядком; один отклонён проверкой фактов (invalid_response), и карточки корректно получили резервные тексты.

Тесты и демонстрация

Из корня, после установки зависимостей:

.\.venv\Scripts\python.exe -m unittest discover -s backend/tests -v
.\.venv\Scripts\python.exe -m unittest discover -s ui/tests -v

Проверено 80 тестов: 44 backend и 36 UI, без ошибок и пропусков. Тесты AI используют mock, основные сквозные тесты — официальный CSV и запрещённую сеть. Проверены три статуса, редкая категория, фильтры, ранжирование, повторяемость, факты, альтернативы, воронка, неправильные AI-ответы, таймаут и сохранение подбора. Сообщение Streamlit AppTest missing ScriptRunContext в тестовом режиме не является ошибкой теста.

Запросы для локальной демонстрации (формат свадьба, язык/часы не ограничены):

Город / категорияДатаБюджет, ₸Результат
Алматы / Ведущий15.10.20261 500 000HK-42352, HK-35215, HK-27222, в порядке нового рейтинга
Алматы / Флорист15.10.2026500 000HK-90001, HK-39372; две карточки
Астана / Декоратор15.10.2026500 000no_category, подсказка другого города
Астана / Банкетный зал26.12.2026300 000none_match, занятость и бюджет
Алматы / Ведущий10.10.20261 500 000HK-27222, HK-77838; подсказки дат и бюджета
Алматы / Ведущий26.12.20261 500 000HK-44923; соседние даты дают больше вариантов

Структура

backend/
  loader.py, matching.py           # данные, фильтры, воронка, альтернативы
  ranking.py, explain.py           # балл, факты, резервные тексты
  grounding.py                    # эвристическая проверка AI-текста
  ai_config.py, explanations.py    # конфигурация и пакетный OpenAI-адаптер
  .env.example, CONTRACT.md, tests/
data/hackathon-dataset-anonymized.csv
ui/
  app.py, service.py, contracts.py, catalog.py
  mock_data.py                    # только изолированные UI-тесты
  requirements.txt, INTEGRATION.md, tests/

Ограничения

  • Данные анонимизированы, часть профилей синтетическая, цены и города могут быть восстановлены; соответствующие предупреждения сохранены в карточках.
  • Цена «от» не равна окончательной стоимости. Отсутствие даты в календаре не гарантирует бронирование.
  • Эвристическое ранжирование и факты из описания не подтверждают качество услуг.
  • AI необязателен: локальная работоспособность обеспечивается резервными объяснениями. Ответ OpenAI занимает около 6 с; часть ответов отклоняется эвристической проверкой фактов.
  • Новые данные за пределами календаря, обучение моделей, платежи и облачный хостинг не реализованы.
Звёзды
⭐ 1
Форки
0
Язык
Python
Последний push
в прошлом месяце
Коммиты
15
Авторы
4
Файлы
33
Ветки
5

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

Codex 6Alibek 5Claude 2Aslan 2

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

  • 2026-09-23 16:47feat: transparent ranking, grounded AI check, suggestions and pipeline traceAlibek
  • 2026-09-23 17:46fix: raise OpenAI timeout to 8s after live verificationClaude
  • 2026-09-23 17:35Merge feature/matching (cb757a7): ranking, per-card facts, suggestionsClaude
  • 2026-09-23 17:09feat: add optional OpenAI explanations with safe offline fallbackCodex
  • 2026-09-23 15:40feat: per-card facts and explanations with AI hook and template fallbackAlibek
  • 2026-09-23 15:29feat: make backend importable package for Streamlit, add integration testAlibek
  • 2026-09-23 15:22feat: prepare UI backend adapter and validate matching contractAslan
  • 2026-09-23 16:21feat: integrate Streamlit with matching backend and official CSVCodex
Все коммиты (15)
  • 2026-09-23 15:08feat: complete matching filters, calendar window check, contract v1Alibek
  • 2026-09-23 14:53feat: add initial contractor search interfaceAslan
  • 2026-09-23 15:41Merge remote-tracking branch 'origin/feature/streamlit-ui' into integration/mvp-hour2Codex
  • 2026-09-23 15:41Merge remote-tracking branch 'origin/feature/matching' into integration/mvp-hour2Codex
  • 2026-09-23 15:41Merge remote-tracking branch 'origin/docs/readme-initial' into integration/mvp-hour2Codex
  • 2026-09-23 14:35feat: add contractor data loader and initial matchingAlibek
  • 2026-09-23 14:11docs: initialize AIZAK competition READMECodex
Структура репозитория (33 файлов)
.gitignore
README.md
backend/.env.example
backend/.gitignore
backend/CONTRACT.md
backend/README.md
backend/__init__.py
backend/ai_config.py
backend/explain.py
backend/explanations.py
backend/grounding.py
backend/loader.py
backend/matching.py
backend/ranking.py
backend/tests/test_explain.py
backend/tests/test_explanations.py
backend/tests/test_integration.py
backend/tests/test_matching.py
backend/tests/test_release.py
backend/tests/test_upgrades.py
data/hackathon-dataset-anonymized.csv
ui/.gitignore
ui/INTEGRATION.md
ui/app.py
ui/catalog.py
ui/contracts.py
ui/mock_data.py
ui/requirements.txt
ui/service.py
ui/tests/test_ai_explanations.py
ui/tests/test_app.py
ui/tests/test_contracts.py
ui/tests/test_real_backend.py
Ветки (5)

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

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

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