Событие (Умный подбор подрядчиков)
Сервис подбора подрядчиков под мероприятие: форма и AI-помощник на ru/kk/en возвращают до 3 профилей из CSV организаторов с проверяемыми…
О проекте
Команда: AutoSOC
Кейс HackAlem.ai: Креативные индустрии — Firebird
Стадия: Доведённый продукт
Задача кейса: «#79-lite»: подобрать до 3 подрядчиков для мероприятия и объяснить выбор
Суть
Сервис подбора подрядчиков под мероприятие: форма и AI-помощник на ru/kk/en возвращают до 3 профилей из CSV организаторов с проверяемыми объяснениями и причинами отсева.
Как устроено
Датасет (66 профилей) загружается из CSV с проверкой схемы. Детерминированный matcher последовательно фильтрует по городу, категории, дате, бюджету и т. д., показывает воронку и отдаёт до 3 карточек с объяснениями по шаблону. Необязательный AI через OpenAI Responses API уточняет параметры в диалоге, вызывает тот же подбор и выбирает цитаты из описаний уже подобранных профилей.
Ключевые решения
- deterministic filter matching
- filtering funnel
- grounded quote selection
- conversational agent
- date comparison
- minimum budget suggestion
- i18n ru/kk/en
Особенности
LLM не выбирает подрядчиков, только уточняет запрос и цитирует описания; альтернативные даты и минимальный бюджет предлагаются только если реальный повторный подбор даёт совпадения; сравнение выдачи на двух датах; 164 теста.
Стек
Python · FastAPI · Pydantic · Uvicorn · OpenAI SDK · HTML/CSS/JS · pytest · Brev
Модели
OpenAI
Проект создан за 5 часов на финале хакатона HackAlem.ai (23 сентября 2026, Астана). Код — BAITC-Hacks/hack-f42fa90b-autosoc.
README
README.mdУмный подбор подрядчиков
Открыть рабочее демо «Событие» — доступно в браузере без входа в NVIDIA.
Сервис для подбора подрядчиков и площадок под параметры мероприятия в рамках задачи HackAlem AI «Умный подбор подрядчиков» (#79-lite). Пользователь задаёт город, дату, формат, категорию и бюджет, а сервис должен вернуть до трёх подходящих вариантов с краткими, проверяемыми объяснениями.
Демо размещено на Brev из копии коммита 6c6bb05edb4fdb866798d2eaca3a0d0d96663e4d и доступно, пока работает эта виртуальная машина. CSV и настройки API переданы на сервер отдельно и не входят в Git. Работа AI-помощника зависит от доступности API и оставшихся средств или кредитов; ручной подбор работает без AI.
Текущий статус
Реализованы backend и статический сайт: загрузка локального CSV, детерминированный подбор, проверяемые объяснения, HTTP API и форма с результатами. Необязательный AI-помощник принимает сообщения на русском, казахском и английском, уточняет параметры и обращается к тому же подбору; без ключа форма и /api/match работают в шаблонном режиме. Сервер локализует ответы по Accept-Language: ru, kk или en. AI может выбрать фрагмент описания для уже подобранных профилей. Кнопка «Согласовать выбор» создаёт локальный текст для обсуждения одного профиля и ничего не отправляет. Наличие кода и документов само по себе не означает прохождение проверки организаторов.
Для запуска нужен предоставленный организаторами hackathon dataset anonymized.csv в data/ (предпочтительно) или в корне проекта. Файл локальный, в Git не входит и приложением не изменяется. Без него запуск завершается явной ошибкой. Дополнительный data/synthetic_extra.csv загружается только при наличии и должен иметь ту же схему; его происхождение в API отличается от исходных профилей. В этом этапе дополнительных профилей не создано.
Получение исходного CSV
Скачайте файл по ссылке организатора, указанной в задании или по прямой ссылке для скачивания. Если ссылка требует доступа, запросите CSV у организаторов. Сохраните его под точным именем data/hackathon dataset anonymized.csv в корне клона репозитория. Не заменяйте уже имеющийся локальный файл без отдельной проверки. В исходном CSV ожидаются 66 профилей. Контрольная сумма SHA-256 ниже вычислена командой по полученному локальному CSV; это результат нашей проверки, а не значение, опубликованное в задании:
6a724b6b7dfb5973343e68ba18dadb60fc807d87e3d78f03ee86fb26cb089f7d
Проверьте скачанный файл в PowerShell:
Get-FileHash -Algorithm SHA256 -LiteralPath 'data/hackathon dataset anonymized.csv'
Загрузчик проверяет схему CSV при запуске и явно отклоняет HTML-страницу ошибки, если вместо файла скачалась она. Скачивание не выполняется приложением автоматически; локальный CSV остаётся вне Git.
Стек и зависимости
- Python 3.11+ и стандартный модуль
csv— чтение CSV в UTF-8-SIG; - FastAPI (MIT) — HTTP API; Pydantic (MIT) — контракты и валидация;
- Uvicorn (BSD-3-Clause) — локальный сервер;
- pytest (MIT) — тесты; httpx (BSD-3-Clause) — клиент API в тестах;
- официальный OpenAI Python SDK (Apache-2.0) — необязательный выбор цитат и диалоговый маршрут через Responses API; python-dotenv (BSD-3-Clause) — чтение локального
.env; - HTML, CSS и JavaScript без сторонних библиотек и сборщика — сайт на том же сервере.
Версии зафиксированы в requirements.txt: FastAPI 0.141.1, Pydantic 2.13.5, Uvicorn 0.53.0, pytest 9.1.1, httpx 0.28.1, OpenAI SDK 3.19.0 и python-dotenv 1.2.3. База данных и личный аккаунт для запуска не нужны. Без OpenAI API основной подбор и объяснения остаются доступными.
Установка и запуск на Linux / Brev
Нужен Python 3.12 с поддержкой venv; на облачном демо использован Python 3.12.14. Получите исходники в отдельный каталог и отдельно поместите CSV в data/hackathon dataset anonymized.csv. Измените путь в команде cd на свой. Команды проверяют исходные файлы, версию Python и доступность порта, затем создают новое окружение, не заменяя существующее:
set -euo pipefail
cd /absolute/path/to/source
test -f requirements.txt
test -f app/main.py
test -s 'data/hackathon dataset anonymized.csv'
python3.12 -c 'import sys; assert sys.version_info >= (3, 11)'
python3.12 -c 'import socket; s=socket.socket(); s.bind(("0.0.0.0", 8011)); s.close()'
RUNTIME="$(mktemp -d "$PWD/.brev-runtime.XXXXXXXX")"
python3.12 -m venv "$RUNTIME/venv"
"$RUNTIME/venv/bin/python" -m pip install -r requirements.txt
nohup "$RUNTIME/venv/bin/python" -m uvicorn app.main:app \
--host 0.0.0.0 --port 8011 >"$RUNTIME/server.log" 2>&1 </dev/null &
printf '%s\n' "$!" >"$RUNTIME/server.pid"
curl --fail --silent --show-error --retry 30 --retry-connrefused --retry-delay 1 \
http://127.0.0.1:8011/health
Если порт занят, сначала выясните, что на нём работает; неизвестный процесс не останавливайте. Для внешнего доступа настройте публичный адрес Brev на порт 8011 и проверьте /health по этому адресу. AI-настройки задаются серверными переменными окружения или локальным .env; ключи не передаются в браузер и не добавляются в Git. Для работы без внешних AI-вызовов задайте EXPLANATION_MODE=template перед запуском. Контекст диалогов хранится в памяти процесса и теряется при его перезапуске.
23 сентября облачная копия прошла HTTP-проверку по публичному адресу: /health вернул HTTP 200 и 66 профилей. Ручные запросы для ведущего в Алматы на свадьбу дали 5 совпадений / 3 карточки на 7 октября при бюджете 1 000 000 ₸, 2 / 2 на 10 октября при том же бюджете и all_filtered / 0 карточек при снижении бюджета до 300 000 ₸. В публичном браузере проверены три настоящих хода AI-диалога с теми же результатами: 5 / 3 → 2 / 2 → all_filtered / 0; в первом ответе показаны выбранные AI фрагменты. В окружении Linux Python 3.12.14 прошли 164 теста; один тест JavaScript в tests/test_approval_preview.py пропущен из-за отсутствия необязательного Node.js. Эти результаты описывают выполненную проверку, а доступность демо зависит от работающей VM и API.
Установка и запуск в PowerShell
Из корня репозитория при установленном Python 3.11+ и полученном CSV из раздела выше:
py -3 -m venv .venv
.\.venv\Scripts\python.exe -m pip install -r requirements.txt
.\.venv\Scripts\python.exe -m uvicorn app.main:app --host 127.0.0.1 --port 8011
Проверки запускаются без активации окружения:
.\.venv\Scripts\python.exe -m pytest -q
После запуска GET http://127.0.0.1:8011/health возвращает состояние и число загруженных профилей. Если порт занят, выберите другой, например --port 8012, и используйте его во всех адресах ниже. Не останавливайте неизвестный процесс, занимающий порт. Для остановки запущенного здесь сервера нажмите Ctrl+C в его терминале.
Откройте http://127.0.0.1:8011/ в браузере. FastAPI отдаёт страницу по /, CSS и JavaScript по /static/. Форма загружает варианты из /api/options и отправляет подбор в /api/match; четыре демонстрационные кнопки заполняют форму и выполняют настоящие запросы по сценариям ниже. Предыдущие результаты убираются во время нового запроса. Сайт показывает ошибки сети и валидации, до трёх карточек, проверяемые факты и причины отсева. Помощник над формой использует /api/agent, а кнопка «Новый запрос» создаёт отдельный диалог.
Постоянный переключатель RU / ҚАЗ / EN в шапке выбирает русский, казахский или английский интерфейс. Выбор сохраняется в браузере после обновления страницы. При смене языка остаются введённые условия, показанные карточки и история диалога; исходные сообщения пользователя не переписываются. Подписи вариантов переводятся, но запрос всегда передаёт канонические значения каталога. Язык интерфейса сам по себе не задаёт фильтр языка услуги. Для новых ответов браузер передаёт локаль в Accept-Language; серверные причины и объяснения формируются на выбранном языке. Исходный русский фрагмент описания и полное описание доступны в карточке через раскрытие «Источник / Түпнұсқа / Source».
Над карточками отображается воронка: весь каталог, город, категория и последовательные фильтры с числом оставшихся профилей. Незаданные язык услуги и часы помечены отдельно; максимум три карточки показываются после общего числа совпадений. При пустой выдаче сайт предлагает ближайшие даты только тогда, когда тот же подбор на этих датах действительно даёт совпадения без изменения остальных условий. Кнопка предложения даты запускает обычный запрос. Демокнопки «Плотная», «Редкая», «Категории нет», «Условия не подошли» используют точные параметры таблицы ниже; готовые ответы в браузере не зашиты.
При двух или трёх карточках доступна раскрываемая таблица «Сравнить варианты» с ценой «от», запасом бюджета, особенностями из описаний, доступностью на выбранную дату и происхождением профиля; запрошенные язык и часы показываются при наличии. На узком экране таблица прокручивается горизонтально. После изменения условий блок «Что изменилось?» сопоставляет параметры и число подходящих профилей с предыдущим успешным результатом. Если изменена только дата, он дополнительно показывает изменение числа исключённых по занятости. Ручная форма и помощник ведут эту историю независимо; «Новый запрос» очищает историю помощника. Для ручной формы показывается фактическое время выполнения запроса, включая ожидание API.
У результата ручного подбора есть отдельное сравнение двух дат. Выберите вторую дату: интерфейс выполнит два запроса к /api/match?explain=template с одинаковыми остальными условиями и покажет число подходящих на каждой дате и состояние каждого подходившего хотя бы на одной из них профиля. Сравнение использует все matched_ids, поэтому профиль за пределами первых трёх карточек остаётся отмечен как подходящий. Занятость указывается только при наличии причины date в ответе для соответствующей даты. Сравнение не вызывает AI и не меняет основную форму; обе даты должны находиться в пределах календаря.
При пустом результате сервис может предложить «Вариант при другом бюджете». Он берёт минимальную цену «от» среди профилей, прошедших все прочие условия, и повторно проверяет предложенный бюджет обычным подбором. Кнопка применяет только это изменение к показанному запросу. Если одна лишь смена бюджета не даст совпадений, предложение не показывается. Цена «от» требует уточнения окончательной сметы.
В каждой найденной карточке кнопка «Согласовать выбор» / «Таңдауды келісу» / «Share for approval» открывает локальную сводку одного профиля. Она строится обычным JavaScript из карточки и снимка выполненного запроса: изменение формы без нового поиска не меняет условия сводки. В тексте указаны имя и id, выбранные условия, 1–2 проверяемые причины, цена «от», оговорка о календаре, происхождение данных и вопросы об окончательной цене, составе услуги и подтверждении даты; при отсутствии часового лимита предложено уточнить длительность. Текст можно скопировать или выделить вручную при отказе Clipboard API. Это не заявка и не бронирование.
Пример прямого запроса к API:
$body = @{ city='Алматы'; date='2026-10-07'; event_format='свадьба'; category='Ведущий'; budget_kzt=1000000 } | ConvertTo-Json
Invoke-RestMethod -Uri 'http://127.0.0.1:8011/api/match' -Method Post -ContentType 'application/json; charset=utf-8' -Body $body
GET /api/options возвращает города, категории по городам, форматы, языки и границы календаря. POST /api/match принимает также необязательные language и hours и возвращает matched, no_category_in_city или all_filtered, максимум три карточки, число всех прошедших профилей и их matched_ids. Параметр ?explain=template оставляет тот же подбор и порядок, но формирует объяснения без внешнего AI; без параметра действует обычный режим настройки. Для каждого отсеянного кандидата ответ содержит all_reasons с конкретными значениями и отдельно primary_reason с detail. Все причины одного профиля могут пересекаться; primary_reason_counts учитывает профиль только один раз. Порядок основных причин: дата, формат, бюджет, язык, часы, недостаток данных. Ответ также содержит funnel с числом профилей после каждого шага и, при пустой выдаче, до трёх nearby_dates, проверенных тем же matcher в пределах ±14 дней без ослабления других условий. Для all_filtered необязательное поле budget_suggestion содержит проверенную минимальную цену «от» и требуемое увеличение бюджета, если одна смена бюджета помогает. Необязательные фильтры в воронке помечены как незаданные. Запрос с датой за пределами 2026-09-23 — 2026-12-31 возвращает 422: занятость вне окна неизвестна.
Диалоговый подбор
POST /api/agent принимает message и необязательный session_id; в ответе возвращает новый или прежний session_id, статус (clarification, matched, unavailable или error), текст, распознанные параметры и, после поиска, результат matcher в поле match с возможным выбором фрагментов для объяснений. Метка source=template после поиска означает шаблонные объяснения при неудаче второго обращения к модели или отсутствии подтверждённых фрагментов; первое обращение к модели для разбора параметров при этом могло пройти успешно. source=ai означает, что модель выбрала действие и, при наличии карточек, хотя бы один подтверждённый фрагмент. tool_name — фактически вызванный моделью инструмент. Итоговый текст о результате подбора формирует сервер. Контекст одного диалога хранится только в памяти процесса: не более 128 сессий, по 12 сообщений и 700 символов на сообщение, срок неактивности 30 минут. После перезапуска сервера контекст теряется. Сообщения разных сессий изолированы.
Помощник использует Responses API с функциями request_clarification и match_contractors. Модель выбирает действие и аргументы, но сервер валидирует параметры и запускает тот же matcher, что и форма. Для каждого нового значения модель указывает фрагмент последнего сообщения; сервер проверяет его наличие и совместимость с выбранным значением. Ограниченный словарь переводов и синонимов каталога допускает обычные словоформы и однозначные опечатки на RU/KK/EN; неоднозначность требует уточнения. Числа, даты, id и имена профилей нечётко не исправляются. Локаль интерфейса не включает фильтр языка услуги: language меняется только при явном пожелании. Если подтвердить значение не удаётся, помощник просит уточнение. Модель не задаёт карточки, цены, занятость, число совпадений или причины отсева. При неполном запросе помощник сохраняет названные параметры и задаёт уточнение; модель передаёт изменения, а сервер сохраняет остальные поля. Нормализации доступны в normalizations как исходный фрагмент и каноническое условие. Результаты matched, no_category_in_city и all_filtered выводятся из каталога. Если после поиска второй вызов модели не удался, сервер возвращает настоящие карточки с шаблонными объяснениями.
Демо с локальным исходным CSV: отправьте в одном диалоге «Нужен ведущий в Алматы на свадьбу 7 октября 2026 года, бюджет до миллиона тенге», затем «А если 10 октября?», затем «Снизим бюджет до 300 тысяч». Для этих параметров прямой подбор даёт соответственно 5 совпадений и 3 карточки, 2 совпадения и 2 карточки, затем all_filtered; ответы помощника должны быть получены через настоящий вызов подбора. AI-диалог требует ключа. Если ключ отсутствует или включён EXPLANATION_MODE=template, помощник сообщает о недоступности, а ручная форма продолжает работать.
Режим объяснений и локальные настройки
По умолчанию EXPLANATION_MODE=auto: если OPENAI_API_KEY доступен в окружении или локальном .env, официальный SDK использует Responses API. Модель по умолчанию — gpt-6-sol с reasoning.effort="none"; значение OPENAI_MODEL из окружения или .env её переопределяет. Для работы без внешних вызовов, включая агента, задайте EXPLANATION_MODE=template. Переменные процесса имеют приоритет над .env; файл .env игнорируется Git. Пример локальной настройки:
if (-not (Test-Path -LiteralPath '.env')) {
Copy-Item -LiteralPath '.env.example' -Destination '.env'
}
# Отредактируйте .env локально; задайте OPENAI_API_KEY только при желании использовать AI.
Ключ нельзя передавать в браузер или сохранять в Git. В маршруте /api/match модель получает только параметры заказа, проверенные факты и полные фрагменты описаний максимум трёх уже выбранных профилей с серверными идентификаторами. Она выбирает идентификатор фрагмента собственного описания для каждого профиля; текст берёт сервер, а кандидатов и порядок определяет только код. Код проверяет id профиля, отсутствие дубликатов и принадлежность идентификатора фрагмента этому профилю. Фрагменты не обрезаются внутри предложения, чтобы сохранять отрицания и условия. Соответствие JSON-схеме само по себе не подтверждает правдивость текста. Финальные 1–2 предложения собирает код, атрибутируя особенности как слова из описания профиля. При отсутствии ключа, таймауте, отказе, ошибке или недостоверном выборе применяется шаблон с проверенным фрагментом либо честным указанием на нехватку сведений. В карточке указано происхождение объяснения и показана цитата. Этот необязательный AI-этап /api/match ограничен примерно 7 секундами, автоматические повторы SDK отключены.
Использован синтаксис Structured Outputs из официальной документации OpenAI. Работа без ключа и отказные сценарии проверяются с подменённым клиентом; это не является проверкой реального OpenAI API.
Агент использует function calling в Responses API. Для одного хода установлен общий предел примерно 9 секунд, отключены автоматические повторы и ограничено число обращений к модели. Обычный pytest не отправляет реальные запросы в OpenAI. Реальная проверка требует работающего ключа и запускается отдельно.
Карточки сортируются по цене «от» по возрастанию, при равенстве по id. Показатель rank_score равен доле запаса бюджета (budget_kzt - price_from_kzt) / budget_kzt; он отражает только ценовое соответствие, не качество подрядчика. Цена «от» не является окончательной сметой. max_hours=null означает отсутствие привязки к часам в каталоге, а не неограниченное время обслуживания.
Проверенные данные и сценарии
В локальном исходном CSV проверены 66 строк: Алматы — 50, Астана — 15, Зарубежье — 1. Уникальных категорий 17; чаще всего встречаются «Ведущий» (15 профилей), «Фотограф» (12), «Банкетный зал» (8) и «Ресторан» (7). Категории одного профиля могут учитываться в нескольких группах. Пустых max_hours — 9; пустых цен, форматов и языков — 0. synthetic=True — 13, city_imputed=True — 8, price_imputed=True — 18. Это признаки исходного файла; новых записей здесь нет.
Воспроизводимые запросы (city, date, event_format, category, budget_kzt):
| Сценарий | Параметры | Фактический исход |
|---|---|---|
| Плотная категория | Алматы, 2026-10-07, свадьба, Ведущий, 1000000 | matched, 5 прошли, 3 карточки, 1 исключён датой |
| Редкая категория | Астана, 2026-09-23, свадьба, Флорист, 300000 | matched, 1 профиль |
| Нет совпадений | Алматы, 2026-10-10, свадьба, Ведущий, 300000 | all_filtered, 0 профилей |
| Нет категории в городе | Астана, 2026-10-07, свадьба, Декоратор, 1000000 | no_category_in_city |
| Влияние календаря | Алматы, 2026-10-10, свадьба, Ведущий, 1000000 | matched, 2 прошли, 4 исключены датой; остальные параметры совпадают с первым запросом |
Последовательность этапов
- Зафиксировать требования, ограничения и архитектуру.
- Получить и проверить исходный датасет, не изменяя его — сделано локально.
- Реализовать загрузку данных, схемы и валидацию входа — сделано.
- Реализовать детерминированные фильтрацию и ранжирование — сделано.
- Добавить объяснения на основе проверенных фактов — сделано через шаблон и необязательный проверяемый выбор цитат моделью.
- Реализовать API и минимальный статический интерфейс — сделано.
- Покрыть ключевые сценарии тестами и проверить локальный запуск — сделано.
- Подготовить и проверить демонстрационные сценарии — сделано по локальному CSV.
- Добавить необязательный диалоговый подбор с вызовом существующего
matcher— сделано; работа с настоящей моделью зависит от локального ключа и доступа проекта к выбранной модели.
При чистом запуске требуется локальная копия предоставленного CSV, Python и установка зависимостей; личный аккаунт участника не нужен. CSV необходимо получить отдельно от Git по указанным выше ссылкам и проверить контрольную сумму.
Проверка установки с нуля
23 сентября независимо проверен коммит 33c590b3d72bd01a5c48edfaff5c0152d5e40e5a: только отслеживаемые файлы выгружены через git archive, в новом окружении Python 3.13 установлены зависимости из requirements.txt, прошли 165 тестов. Предоставленный исходный CSV подключён отдельно локальной жёсткой ссылкой; .env и ключи не переносились, установлен EXPLANATION_MODE=template. Отдельный Uvicorn вернул HTTP 200 для /health (66 профилей), страницы, CSS, обоих JavaScript-файлов, /api/options и OpenAPI. Все пять сценариев таблицы проверены реальными HTTP-запросами на RU/KK/EN; совпали исходы, числа и порядок id. Диалог без ключа вернул unavailable, а ручной подбор остался доступен. Эта проверка подтверждает запуск и ручной сценарий без внешнего AI. Доступность скачивания CSV по ссылке для другого проверяющего ею не подтверждается.
Реальная проверка AI и повторное демо
23 сентября реальный трёхходовый диалог выполнен через OpenAI Responses API с gpt-6-sol: полный запрос дал 5 совпадений / 3 карточки за 6,950 с, смена даты на 10 октября — 2 / 2 за 3,648 с, снижение бюджета до 300 000 ₸ — all_filtered за 4,538 с. На каждом ходе модель действительно вызвала match_contractors, сервер выполнил подбор, второй API-ответ завершился успешно. Порядок карточек и параметры сравнивались с прямым детерминированным matcher. Это отдельные измерения, не гарантия задержки для любого запроса или сети.
Для повторения после локальной настройки ключа запустите явно разрешённую платную проверку (до шести API-вызовов; без флага --live сеть не используется):
.\.venv\Scripts\python.exe scripts/check_live_agent.py --live
Скрипт печатает только статусы, параметры запроса, id карточек, времена и названия фактически вызванных инструментов. Ключи и полные сообщения ошибок SDK не выводятся. Успех этой проверки не заменяет сдачу проекта на платформе. Для эксперта без API-ключа доступен весь ручной подбор; диалог с живой моделью требует настроенного доступа к API.
Многоязычная версия 23 сентября проверена отдельным скриптом на реальном gpt-6-sol: запросы RU с «ведуший» (5 совпадений, 3 карточки, 5,162 с), KK (5/3, 4,527 с), EN с «weddding» (5/3, 4,022 с), уточнение даты (2/2, 4,834 с), уточнение бюджета (all_filtered, 4,430 с) и неоднозначная дата 07/10 (request_clarification без поиска, 3,678 с). На пяти полных ходах действительно вызывался match_contractors, затем второй ответ модели; на неоднозначном — только request_clarification. Проверка сравнила параметры, id и порядок карточек с прямым matcher. Это измерения данного запуска, а не гарантия задержки для любой сети.
Дополнительный ограниченный прогон 23 сентября охватил восемь пользовательских ходов на реальном gpt-6-sol. Первые семь прошли: RU 5/3 за 5,169 с, KK 5/3 за 4,611 с, EN 5/3 за 4,357 с, смена даты 2/2 за 4,462 с, смена бюджета all_filtered за 4,098 с, неоднозначная дата с уточнением за 2,157 с и 500,000 KZT как 500 000 ₸ за 4,865 с. Восьмой запрос с явным 2027 и 300 thousand KZT за 1,908 с выявил ошибку: модель предложила вызов подбора с датой за пределами календаря, а сервер вернул общий статус error. После этого сервер исправлен: такой вызов даёт локализованное уточнение без подбора или подмены года; регрессионные тесты на RU/KK/EN прошли. Повторный платный вызов не выполнялся из-за лимита восьми ходов; исправление года пока не подтверждено новым живым ответом API. Времена относятся только к этому прогону.
Скрипт этого набора рассчитан на восемь пользовательских ходов и до шестнадцати обращений к API; запускать его следует отдельно от обычных тестов и только при согласии на платные вызовы:
.\.venv\Scripts\python.exe scripts/check_live_multilingual.py --live
Краткий порядок показа приведён в демо, подготовленные поля ручной сдачи — в описании для платформы. Отправка GitHub не отправляет решение на платформу.
Рабочие ограничения
- Фактический прогресс необходимо фиксировать за каждый час; планы нельзя выдавать за реализованный функционал.
- Основная работа ведётся только в выданном командном репозитории.
- Срок финальной версии — 23.09.2026, 18:00 по времени Астаны.
- Чистый запуск по README не должен зависеть от личного аккаунта участника.
Подробности приведены в требованиях и описании архитектуры.
Авторы коммитов
История коммитов
- 2026-09-23 17:47docs: publish verified Brev demo and Linux launch guideOrrioo
- 2026-09-23 17:31docs: finalize reproducible hackathon submissionOrrioo
- 2026-09-23 17:25feat: validate multilingual matching and add selection previewOrrioo
- 2026-09-23 17:10feat: suggest verified minimum budgetOrrioo
- 2026-09-23 17:02feat: compare matching across event datesOrrioo
- 2026-09-23 16:53feat: localize contractor matching interfaceOrrioo
- 2026-09-23 16:40feat: support multilingual matching and transparent resultsOrrioo
- 2026-09-23 16:17feat: compare matches and harden live agentOrrioo
Все коммиты (13)
- 2026-09-23 15:57feat: add conversational contractor matching agentOrrioo
- 2026-09-23 15:21feat: add grounded AI explanation selectionOrrioo
- 2026-09-23 14:56feat: add contractor matching web interfaceOrrioo
- 2026-09-23 14:44feat: implement contractor matching backendOrrioo
- 2026-09-23 14:04docs: AGENTS.md, старт проектаOrrioo
Структура репозитория (39 файлов)
.env.example .gitignore AGENTS.md README.md app/__init__.py app/agent.py app/ai_explain.py app/config.py app/data.py app/explain.py app/i18n.py app/lexicon.py app/main.py app/matcher.py app/schemas.py data/.gitkeep docs/architecture.md docs/demo.md docs/requirements.md docs/submission.md requirements.txt scripts/check_live_agent.py scripts/check_live_multilingual.py static/app.js static/approval.js static/index.html static/styles.css tests/conftest.py tests/test_agent.py tests/test_ai_explain.py tests/test_api.py tests/test_approval_preview.py tests/test_budget_suggestion.py tests/test_data.py tests/test_date_comparison.py tests/test_match_transparency.py tests/test_matcher.py tests/test_ui_i18n.py tests/test_web.py
Обсуждение 0 комментариев
Войдите, чтобы комментироватьПока нет комментариев — будьте первым.