AAYMA
RU
Войти

Firebird Match

Streamlit-приложение подбора до трёх подрядчиков из каталога Firebird #79-lite с объяснениями, сравнением вариантов, объяснением изменения выдачи и…

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

О проекте

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

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

Суть

Streamlit-приложение подбора до трёх подрядчиков из каталога Firebird #79-lite с объяснениями, сравнением вариантов, объяснением изменения выдачи и «Планом Б» при отсутствии совпадений.

Как устроено

Ввод (город, дата, формат, категория, бюджет, опционально язык и длительность) → детерминированная фильтрация contractors.csv (66 профилей) с календарём занятости и стабильной сортировкой по цене и ID. LLM вызывает инструмент recommend_contractors, получает отфильтрованные карточки и выбирает evidence_id для каждого; Python проверяет ID и принадлежность выдержки, при недоступности API работает локальный fallback. План Б ищет ближайшую дату (+1, −1, +2…) или минимальный бюджет, при котором появляется профиль.

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

  • tool calling (recommend_contractors)
  • детерминированные фильтры
  • проверка evidence_id
  • поиск ближайшей даты/минимального бюджета (План Б)
  • сравнение запросов

Особенности

Принцип «The model interprets; Python decides»: модель только выбирает выдержку внутри уже отобранного профиля; «Query change explanation» объясняет изменение выдачи между запросами по календарю или порогу бюджета.

Стек

Python · Streamlit · OpenAI Python SDK · unittest

Модели

gpt-4.1-mini


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

README

README.md

Firebird Match

Проблема

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

Решение

Firebird Match проверяет запрос по каталогу Firebird #79-lite и показывает до трёх карточек подрядчиков с объяснениями. Приложение не бронирует услуги и не отправляет заявки.

Основной сценарий

Input (город, дата, формат, категория, бюджет; необязательные язык и длительность) → deterministic filtering → 0–3 profiles → optional AI evidence selection → cards.

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

  • Каталог из 66 профилей, проверка ввода и строгие фильтры по городу, категории, календарю занятости, бюджету, формату, языку и длительности.
  • Стабильная сортировка по начальной цене и ID, вывод не более трёх профилей.
  • Streamlit интерфейс, CLI, сценарии A–F, unit tests и Streamlit AppTest.
  • Необязательный AI выбор выдержки из уже отобранного профиля с проверкой ID и принадлежности выдержки; локальный fallback.

Архитектура

Заказ пользователя → Streamlit → run_matching
  → LLM вызывает recommend_contractors tool
  → Python: catalog.recommend(contractors.csv)
  → Python возвращает отфильтрованные, упорядоченные карточки LLM
  → LLM выбирает evidence_id для каждого кандидата
  → Python проверяет ID, принадлежность выдержки и полноту ответа
  → UI показывает факты фильтрации и подтверждённую деталь профиля

Без доступного API Python выполняет тот же подбор и показывает локально выбранные выдержки. The model interprets; Python decides.

Почему Python и AI разделены

Python контролирует hard constraints: доступность по календарю, бюджет, формат, язык, длительность, ID и порядок. AI выбирает релевантную выдержку (evidence_id) внутри уже выбранного профиля. AI не выбирает подрядчиков, не меняет порядок, цены или факты. Описания профилей считаются данными, а не инструкциями.

Technologies

  • Python 3.10 или новее (проверено на Python 3.14; нужны venv и pip).
  • Streamlit 1.64.0 — веб-интерфейс и AppTest.
  • OpenAI Python SDK 3.19.0 — необязательный AI выбор выдержок.
  • unittest из стандартной библиотеки — тесты.

requirements.txt содержит только две прямые runtime зависимости: streamlit и openai.

Dataset

contractors.csv содержит 66 анонимизированных и синтетических профилей из конкурсного датасета. Календарь ограничен периодом 2026-09-23 — 2026-12-31.

  • synthetic: синтетический профиль.
  • city_imputed: город заполнен оценочно; уточните его перед заказом.
  • price_imputed: начальная цена заполнена оценочно; уточните её перед заказом.

Эти признаки показываются на карточках.

Installation

Нужны Git и Python 3.10 или новее с venv и pip. В PowerShell выполните:

git clone https://github.com/BAITC-Hacks/hack-4cfb0407-space-bell-studio.git
cd hack-4cfb0407-space-bell-studio
python -m venv .venv
.\.venv\Scripts\python.exe -m pip install -r requirements.txt

Активировать виртуальное окружение не требуется. .env.example показывает только имя переменной; .env автоматически не загружается.

Run Web

Из папки проекта:

.\.venv\Scripts\python.exe -m streamlit run app.py --server.address 127.0.0.1

Откройте URL, выведенный Streamlit (обычно http://127.0.0.1:8501). Остановите сервер через Ctrl+C. Без доступного ключа приложение продолжает детерминированный подбор с локальными объяснениями. Для live AI проверки запустите run_local.py --web --ask-key в интерактивном PowerShell.

API key

Для необязательного AI режима нужна переменная окружения текущего процесса OPENAI_API_KEY. Не публикуйте ключ в исходниках, README, тестах или Git. Без ключа можно проверить подбор, CLI, интерфейс и тесты. Для локального скрытого ввода ключа в интерактивном терминале есть run_local.py --web --ask-key; для офлайн проверки эта опция не нужна. run_local.py --check-ai --ask-key запускает один сквозной AI запрос. --ask-key всегда запрашивает ключ скрытым вводом, даже если OPENAI_API_KEY уже задан; без него используется переменная окружения. Пробелы по краям удаляются, некорректно оформленные и замаскированные значения отклоняются. Новый режим run_local.py --diagnose-api --ask-key сначала отдельно проверяет доступ к модели простым запросом, затем запускает Firebird agent на основном demo-запросе с тем же клиентом и ключом. Первая стадия не проверяет tool calling, передачу результата инструмента и проверку выбранных evidence; успех агента требует успешного probe и полного рабочего процесса. Запускайте из интерактивного PowerShell:

.\.venv\Scripts\python.exe run_local.py --diagnose-api --ask-key

Verified live AI flow

23.09.2026 пользователь подтвердил успешную ручную проверку с действительным ключом: MODEL_PROBE=PASS, AGENT_RUN=PASS, MODE=AI_EVIDENCE. Получен реальный ответ OpenAI: запрошена модель gpt-4.1-mini, возвращена gpt-4.1-mini-2025-04-14. Модель реально вызвала recommend_contractors; результат инструмента сформирован локальным детерминированным каталогом. Затем модель выбрала выдержки, Python проверил принадлежность каждого evidence_id своему профилю и сохранил контроль над ID и порядком кандидатов. В основном сценарии получены HK-64395, HK-58236, HK-90011. Старый AUTH_ERROR относился к прежнему недействительному credential; новый ручной запуск подтвердил полный agent workflow.

Для самостоятельной проверки в веб-интерфейсе:

.\.venv\Scripts\python.exe run_local.py --web --ask-key

Сценарий: Алматы · 26.09.2026 · корпоратив · Банкетный зал · 10 000 000 ₸. При успешном AI запуске UI показывает ✨ AI-assisted explanation, а карточки отдельно показывают факты фильтрации Python и выбранную AI деталь профиля. При отсутствии или недоступности ключа остаются те же правила подбора и локальные объяснения.

CLI

Все демонстрационные сценарии вычисляются из текущего CSV:

.\.venv\Scripts\python.exe cli.py --demo

Параметры своего запроса: .\.venv\Scripts\python.exe cli.py --help.

Tests

.\.venv\Scripts\python.exe -m unittest discover -s tests -v
.\.venv\Scripts\python.exe run_local.py --help

Тесты AI ветки используют локальный fake client и не подтверждают доступность реального OpenAI API. В набор входят проверки Streamlit через AppTest.

Demo scenarios

В веб-форме оставьте необязательные язык и длительность не заданными. Выберите значения ниже и нажмите «Подобрать подрядчиков». Результат вычисляется из CSV, а не задан в сценарии заранее.

СценарийГородДатаФорматКатегорияБюджет, ₸Ожидаемый business outcome
A — denseАлматы2026-09-26корпоративБанкетный зал10000000Несколько подходящих профилей; показаны не более трёх в стабильном порядке.
B — rareАлматы2026-09-23конференцияФлорист10000000Мало подходящих профилей; показаны размер категории и причины исключения.
C — NO_CATEGORY_IN_CITYЗарубежье2026-09-26корпоративБанкетный зал1000000В городе нет профиля этой категории.
D — NO_MATCHАлматы2026-09-26корпоративБанкетный зал1Категория есть, но все профили исключены условиями.
E — same query / different dateАлматы2026-09-23, затем 2026-09-26день рожденияБанкетный зал10000000Состав подходящих профилей меняется из-за календаря занятости.
F — Plan BАлматы2026-09-26день рожденияБанкетный зал2000000NO_MATCH; План Б: 2026-09-28 даёт 1 профиль, а на исходную дату первый вариант появляется при начальной цене «от» 2500000 ₸.

Three outcomes

  • MATCHED — есть подходящие профили; показано до трёх.
  • NO_CATEGORY_IN_CITY — в каталоге выбранного города нет профиля категории.
  • NO_MATCH — категория есть, но все профили исключены условиями.

При малом числе карточек показаны размер категории и причины исключения. Счётчики причин могут пересекаться.

Candidate comparison

При двух или трёх карточках раздел «Сравнение вариантов» показывает для каждого профиля одинаковые фактические поля: имя, начальную цену «от», город, категорию, деталь профиля и вопросы перед выбором. Язык и длительность показываются только когда они были запрошены. Это не рейтинг и не ML score; раздел не выбирает «лучшего» подрядчика. Деталь профиля берётся из уже проверенной AI выдержки или из существующего локального fallback без дополнительного API вызова. Пометки об оценочной цене, оценочном городе и демонстрационном синтетическом профиле помогают понять, что нужно уточнить. Фактическую доступность на дату нужно подтвердить перед бронированием для любого профиля.

Query change explanation

После двух последовательных нажатий «Подобрать подрядчиков» приложение сравнивает полный набор подходящих профилей, а не только три показанные карточки. Если изменена только дата, причины появления или исчезновения подтверждаются календарём busy_dates. Если изменён только бюджет, причина подтверждается начальной ценой «от» и порогом бюджета. При изменении нескольких полей приложение сообщает о новом расчёте без приписывания причины одному параметру. История хранится только в текущей сессии Streamlit и обновляется при отправке формы.

Plan B

После NO_MATCH приложение отдельно ищет, поможет ли изменение только даты или только бюджета. Исходный запрос и его нулевой результат остаются прежними; пользователь сам выбирает новые условия и запускает подбор заново. Для MATCHED и NO_CATEGORY_IN_CITY План Б не показывается.

  • Ближайшая дата ищется в календаре 2026-09-23 — 2026-12-31 в порядке +1 день, −1 день, +2, −2…. При равном расстоянии сначала выбирается будущая дата. Город, категория, формат, бюджет, язык и длительность сохраняются.
  • Минимальный бюджет — наименьшая начальная цена «от», при которой профиль проходит тот же подбор на исходную дату. Город, дата, категория, формат, язык и длительность сохраняются; занятые и неподходящие профили не учитываются.
  • Обе проверки выполняет Python через catalog.recommend() по тому же CSV. Предложение не гарантирует бронь или окончательную цену.

Determinism

Python определяет допустимые ID и порядок по начальной цене и ID. Ответ AI содержит только выбор evidence_id; он не меняет фильтры и не добавляет подрядчиков. При отсутствии ключа или некорректном ответе AI используется детерминированный fallback.

Limitations

  • Цена указана «от» и не является итоговой сметой.
  • Свободная дата означает только отсутствие записи о занятости в календаре датасета; бронирование не подтверждено.
  • Рекламные заявления принадлежат профилю и не проверены независимо.
  • Календарь ограничен периодом 2026-09-23 — 2026-12-31.
  • AI требует действительный API ключ и доступ к модели; fallback детерминированный.

How jury can verify

  1. Клонируйте репозиторий командами из Installation.
  2. Создайте .venv и установите зависимости из requirements.txt.
  3. Запустите Tests и проверьте, что тесты проходят.
  4. Запустите Run Web без ключа и откройте показанный URL.
  5. Введите сценарий A: появятся до трёх карточек.
  6. Введите сценарий B: проверьте малое число карточек и причины исключения.
  7. Введите сценарий C: проверьте отсутствие категории в городе.
  8. Введите сценарий D: проверьте отсутствие подходящих при существующей категории.
  9. Введите сценарий E дважды с разными датами: сравните карточки.
  10. Введите сценарий F: исходный результат остаётся пустым, а План Б предлагает дату и минимальную начальную цену. Те же случаи доступны через cli.py --demo.
  11. При наличии собственного разрешённого ключа отдельно проверьте необязательный AI режим; ключ для шагов 1–10 не нужен.
Звёзды
⭐ 0
Форки
0
Язык
Python
Последний push
в прошлом месяце
Коммиты
16
Авторы
1
Файлы
20
Ветки
1

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

nightreveriesbell-lgtm 16

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

  • 2026-09-23 17:13style: polish Firebird jury demo interfacenightreveriesbell-lgtm
  • 2026-09-23 16:52fix: stabilize Firebird final submissionnightreveriesbell-lgtm
  • 2026-09-23 16:35feat: add contractor comparison and query deltanightreveriesbell-lgtm
  • 2026-09-23 16:23feat: surface verified AI evidence in Firebird UInightreveriesbell-lgtm
  • 2026-09-23 16:10fix: diagnose OpenAI authentication and live agent separatelynightreveriesbell-lgtm
  • 2026-09-23 15:56feat: add deterministic Plan B recommendationsnightreveriesbell-lgtm
  • 2026-09-23 15:19docs: finalize Firebird submissionnightreveriesbell-lgtm
  • 2026-09-23 15:08feat: polish Firebird demo interfacenightreveriesbell-lgtm
Все коммиты (16)
  • 2026-09-23 15:00fix: polish Firebird jury experiencenightreveriesbell-lgtm
  • 2026-09-23 14:50docs: finalize Firebird reproduction guidenightreveriesbell-lgtm
  • 2026-09-23 14:42fix: close Firebird acceptance gapsnightreveriesbell-lgtm
  • 2026-09-23 14:19fix: make live AI diagnostics robustnightreveriesbell-lgtm
  • 2026-09-23 14:09fix: ground AI explanations in contractor evidencenightreveriesbell-lgtm
  • 2026-09-23 13:47feat: add AI-assisted contractor matching demonightreveriesbell-lgtm
  • 2026-09-23 13:35feat: add deterministic contractor recommendationsnightreveriesbell-lgtm
  • 2026-09-23 13:31feat: import and validate Firebird contractor datasetnightreveriesbell-lgtm
Структура репозитория (20 файлов)
.env.example
.gitignore
README.md
agent.py
app.py
catalog.py
cli.py
comparison.py
contractors.csv
plan_b.py
requirements.txt
run_local.py
tests/test_agent.py
tests/test_build09.py
tests/test_catalog.py
tests/test_cli_security.py
tests/test_comparison.py
tests/test_hotfix.py
tests/test_plan_b.py
tests/test_ui.py

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

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

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