AIZAK
Streamlit-сервис подбора до трёх подрядчиков для мероприятия по городу, категории, дате, формату и бюджету: прозрачная воронка фильтров, балльное…
О проекте
Команда: 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.mdAIZAK — объяснимый подбор подрядчиков для мероприятий
Конкурсный проект команды AIZAK для HackAlem, задача «Умный подбор подрядчиков (#79-lite)».
Официальный репозиторий: BAITC-Hacks/hack-b82ccf3d-aizak.
main — ветка сдачи; integration/mvp-hour2 — ветка интеграции и проверки.
Проект рассчитан на локальный запуск. Публичный деплой и облачный хостинг не нужны и не настроены.
Назначение и сценарий
Частным заказчикам и организаторам мероприятий в Казахстане нужно выбрать исполнителя из каталога с учётом города, даты, категории, бюджета и формата, а затем понять причины выбора.
- Выберите город, категорию, дату, формат мероприятия и бюджет в тенге.
- При необходимости укажите язык и длительность; 0 часов в форме означает отсутствие ограничения.
- Нажмите «Подобрать»: получите до трёх реальных записей из предоставленного CSV.
- Карточки показывают цену «от», место и балл, индивидуальные факты, объяснение и предупреждения о данных.
- В блоке «Как мы подобрали» видна последовательная воронка фильтров. При неполной/пустой выдаче могут появиться подтверждённые каталогом подсказки по дате, бюджету или другому городу. Подсказки не меняют запрос автоматически: внесите изменения в форму и повторите поиск.
| Статус | Значение |
|---|---|
found | Есть 1–3 подходящие карточки |
no_category | В выбранном городе нет категории; другой город предлагается при наличии категории там |
none_match | Категория есть, но кандидаты исключены по условиям |
Бронирование, отправка заявок и уведомления подрядчикам не входят в MVP.
Собранные версии и вклад участников
| Участник / область | Реализованный вклад | Исходная ветка и коммит |
|---|---|---|
| Аслан / frontend | Streamlit, форма, карточки, валидация контракта, UI-тесты | feature/streamlit-ui, 220416f |
| Алибек / backend | CSV/JSONL, фильтры, ранжирование, факты, резервные тексты, проверка AI, альтернативы и воронка | feature/matching, cb757a7 (включает 5505453, 559a322, 3220b61) |
| Интегратор / AI и сборка | Подключение компонентов, пакетный OpenAI-запрос, .env, резерв при сбое, проверка совместимости, сквозные тесты и README | integration/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.25 | 1 − цена / бюджет |
| Семантическое сходство | 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.2026 | 1 500 000 | HK-42352, HK-35215, HK-27222, в порядке нового рейтинга |
| Алматы / Флорист | 15.10.2026 | 500 000 | HK-90001, HK-39372; две карточки |
| Астана / Декоратор | 15.10.2026 | 500 000 | no_category, подсказка другого города |
| Астана / Банкетный зал | 26.12.2026 | 300 000 | none_match, занятость и бюджет |
| Алматы / Ведущий | 10.10.2026 | 1 500 000 | HK-27222, HK-77838; подсказки дат и бюджета |
| Алматы / Ведущий | 26.12.2026 | 1 500 000 | HK-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 с; часть ответов отклоняется эвристической проверкой фактов.
- Новые данные за пределами календаря, обучение моделей, платежи и облачный хостинг не реализованы.
Авторы коммитов
История коммитов
- 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
Обсуждение 0 комментариев
Войдите, чтобы комментироватьПока нет комментариев — будьте первым.