AAYMA
RU
Войти

NeuroForge

Сервис объяснимого подбора до трёх подрядчиков для мероприятий из каталога 66 профилей.

Доведённый продукт
Команда «NeuroForge» 8💬 0 комментариевс 23 сентября 2026 г.

О проекте

Команда: NeuroForge
Кейс HackAlem.ai: Креативные индустрии — Firebird
Стадия: Доведённый продукт

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

Суть

Сервис объяснимого подбора до трёх подрядчиков для мероприятий из каталога 66 профилей. Проверяет занятость на дату, бюджет и условия, каждую рекомендацию подкрепляет цитатой из профиля. Есть веб-интерфейс и HTTP API.

Как устроено

Запрос (город, дата, тип события, категория, бюджет; по желанию бриф, язык, длительность) проходит через воронку фильтров: город/категория → дата → бюджет → формат → часы → язык. Для каждого отсеянного кандидата сохраняется первая причина отсева. Оставшихся ранжируют локальные эмбеддинги paraphrase-multilingual-mpnet-base-v2 (бриф против описания) вместе с признаками запаса бюджета, часов и языков; баллы округляются, ничьи разрешаются по ID, берётся top-3. Объяснения собираются из цитат профиля и структурированных фактов. Если LLM включена (OpenAI gpt-4o, при отказе NVIDIA NIM), она только выбирает 1–2 ID фактов из разрешённого меню; ответ проверяется как JSON и кэшируется в SQLite, при сбое срабатывает fallback. Возможны три исхода: FOUND, NO_CATEGORY, NO_MATCH.

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

  • filter funnel
  • sentence-transformers embeddings
  • deterministic top-3 scoring
  • LLM fact selection with JSON validation
  • NPZ embedding cache
  • SQLite cache
  • provider fallback

Метрики

75 тестов и 5 демо-сценариев прошли; в 448 комбинациях нарушений фильтров нет; латентность 0,367–0,483 с; ответ gpt-4o за 1,939 с

Особенности

LLM не влияет на выбор и порядок кандидатов: она выбирает только ID фактов из заранее проверенного меню, и свободный текст модели в карточку не попадает. В интерфейсе видна трассировка воронки фильтров. Для жюри есть команда самопроверки --check и прогон 448 комбинаций.

Стек

Python · FastAPI · Pydantic · Uvicorn · sentence-transformers · PyTorch · NumPy · SQLite · HTML/CSS/JS · uv · pytest · GitHub Actions

Модели

gpt-4o · NVIDIA NIM · paraphrase-multilingual-mpnet-base-v2


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

README

README.md

NeuroForge

Объяснимый подбор подрядчиков для мероприятий в Казахстане.

NeuroForge помогает организатору выбрать до трёх подрядчиков из существующего каталога. Сервис проверяет доступность на дату, бюджет и условия мероприятия, учитывает пожелания и объясняет каждую рекомендацию конкретными сведениями из профиля.

Проект команды NeuroForge для HackAlem AI, кейс «Креативные индустрии» — «Умный подбор подрядчиков» (#79-lite).

Запуск · Проверка для жюри · Архитектура · API · Сценарий защиты

Какую проблему решаем

В каталоге подрядчиков заказчику приходится вручную сравнивать цены, форматы, языки и описания, а затем выяснять, кто свободен на нужную дату. NeuroForge сокращает этот процесс до одного запроса и короткого списка с обоснованиями. Подходит организаторам корпоративов, свадеб, конференций и других мероприятий, а также площадкам-агрегаторам подрядчиков.

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

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

  • Подбор до трёх кандидатов из каталога с детерминированным порядком.
  • Проверка занятости для подрядчиков и площадок по одному календарному правилу.
  • Фильтры по бюджету, формату, языку и допустимой длительности.
  • Семантическое сравнение пожеланий с описаниями через локальную мультиязычную модель.
  • Конкретные объяснения: цитата из профиля, начальная цена и проверенные условия.
  • Три явных исхода: нашли варианты, категории нет в городе, кандидаты есть, но не подходят.
  • Честная неполная выдача: если подходит один или два профиля, сервис объясняет причину.
  • Веб-интерфейс и HTTP API, пять готовых демонстрационных запросов.
  • Трассировка подбора: сколько профилей осталось после каждого фильтра.
  • Опциональная внешняя LLM: выбор дополнительных акцентов с проверкой ответа, кэшем и fallback.
  • Пометки происхождения данных: синтетические профили и проставленные при подготовке цены/города.

Быстрый запуск

Основной сценарий работает без API-ключей, платных сервисов и GPU. Node.js и сборка frontend не нужны.

Нужны Git, Python 3.13 и интернет для первой установки зависимостей и загрузки модели. Проект проверен в чистом окружении на macOS. Для Linux/Windows в lock-файле предусмотрен CPU-вариант PyTorch; отдельная проверка Windows не проводилась.

git clone https://github.com/BAITC-Hacks/hack-22572782-neuroforge.git
cd hack-22572782-neuroforge
python -m pip install uv==0.11.7
uv run --frozen --extra dev python run.py

Откройте http://127.0.0.1:8000. Интерактивная документация API: http://127.0.0.1:8000/docs.

Если команда python отсутствует, для установки uv используйте python3 на macOS/Linux или py -3.13 на Windows. Если uv не появился в PATH, команды доступны как python -m uv .... Если системный Python запрещает установку через pip, установите uv по официальной инструкции. Файл .python-version указывает Python 3.13; uv может загрузить этот интерпретатор.

При первом запуске дождитесь строки Application startup complete. В проверке с пустым кэшем загрузка модели и прогрев заняли 146,7 секунды; скорость зависит от сети. После установки пакетов и скачивания модели основной сценарий работает локально.

Если порт занят:

uv run --frozen python run.py --port 8001

Публичная развёрнутая версия пока не предоставлена. Адрес 127.0.0.1 доступен на той машине, где запущен сервис.

Проверка для жюри

Одна команда запускает 75 автономных тестов и пять демо-сценариев на настоящей модели эмбеддингов. Она не обращается к платным LLM API и возвращает ненулевой код при провале проверки.

uv run --frozen --extra dev python run.py --check

Те же сценарии доступны кнопками в интерфейсе:

Что проверитьЗапросОжидаемый результат
Плотная категорияАлматы, ведущий, корпоратив, 13.10.2026, 2 млн ₸Три карточки из восьми подходящих
Влияние датыТот же запрос на 31.12.2026Другие кандидаты, два варианта, объяснение занятости
Редкая категорияАлматы, флорист, свадьба, 07.11.2026, 600 тыс. ₸Один вариант с объяснением, почему не три
Никто не подходитАлматы, банкетный зал, корпоратив, 31.12.2026, 200 тыс. ₸Кандидаты есть, но заняты или дороже бюджета
Нет категорииАстана, декоратор, корпоратив, 14.11.2026, 1 млн ₸Такой категории в этом городе нет

Повторите первый запрос: порядок карточек останется прежним. Раскройте «Как получился этот список»: видны этапы фильтрации, баллы и источник выбора фактов для объяснений. Ожидания в таблице относятся к исходным 66 профилям и текущей конфигурации.

Подтверждённые результаты:

  • Чистая копия проекта без .env, новое окружение и пустой кэш модели прошли проверку.
  • Все 75 тестов и пять сценариев завершились успешно.
  • В дополнительном прогоне 448 комбинаций не найдено нарушений фильтров или одинаковых объяснений внутри одной выдачи.
  • После прогрева запросы с брифом занимали 0,367–0,483 с в чистом окружении без внешней LLM. Это локальный замер, а не гарантия для любого сервера.

Подробные результаты и ограничения проверки · Показ проекта за три минуты

Как работает решение

flowchart TD
    A["Форма или HTTP-запрос"] --> B["Валидация параметров и окна календаря"]
    B --> C["Город и категория"]
    C --> D["Дата → бюджет → формат → часы → язык"]
    D --> E{"Есть подходящие?"}
    E -- Нет --> F["Явный исход и причины"]
    E -- Да --> G["Локальные эмбеддинги и детерминированный top-3"]
    G --> H["Цитаты и проверенные факты"]
    H --> I["Опциональная LLM: выбор акцентов"]
    H --> J["Шаблонный выбор акцентов"]
    I --> K["Карточки, объяснения и трассировка"]
    J --> K

Фильтрация. Город и категория формируют пул. Каждый следующий фильтр сужает его. Для исключённого кандидата сохраняется первая причина отсева, поэтому счётчики не дублируются. Площадки проходят ту же проверку даты, что и люди.

Ранжирование. При наличии брифа локальные эмбеддинги сравнивают пожелания с описаниями. Дополнительные признаки учитывают запас бюджета, часов и поддерживаемые языки. Неприменимые признаки исключаются, веса перенормируются. Баллы округляются перед сортировкой; равенство разрешается по ID. LLM не участвует в выборе кандидатов и их порядке.

Объяснения. Из каждого профиля извлекается цитата, по возможности отличающая его от соседних карточек. Без брифа цитата тоже присутствует. Цена и условия берутся из структурированных данных. Если подключена LLM, она выбирает один-два идентификатора из разрешённого меню фактов. Ответ проверяется как JSON; произвольный текст модели в карточку не попадает.

При ошибке API, невалидном ответе или превышении времени используются те же проверенные факты в штатном порядке. В трассировке различаются LLM, кэш и fallback.

Подробная архитектура и формула скоринга

Технологии

КомпонентРеализация
Язык и APIPython, FastAPI, Pydantic, Uvicorn
ИнтерфейсHTML, CSS, JavaScript без сборки
Семантикаsentence-transformers, paraphrase-multilingual-mpnet-base-v2
ВычисленияNumPy, PyTorch
Внешние LLMOpenAI-совместимый клиент; OpenAI и NVIDIA NIM
ДанныеJSONL в репозитории, каталог в памяти
КэшNPZ для эмбеддингов, SQLite для проверенного выбора фактов
Проверки и зависимостиpytest, HTTPX, uv и uv.lock

В разработке использовались AI-агенты Codex и Claude Code.

Подключение OpenAI и NVIDIA

Создайте локальный .env по образцу .env.example и заполните ключ нужного провайдера:

OPENAI_API_KEY=ваш_ключ
NVIDIA_API_KEY=ваш_ключ

Включите внешние вызовы явно:

uv run --frozen python run.py --llm

Без --llm стартовый скрипт отключает внешние API даже при наличии ключей. С --llm сначала используется OpenAI, затем NVIDIA при отказе первого провайдера. По умолчанию один вызов ограничен 4 секундами, общее ожидание объяснений — 5 секундами. Три карточки обрабатываются параллельно; проверенный выбор фактов кэшируется.

Одиночная проверка провайдера без кэша:

uv run --frozen python scripts/check_live_llm.py --provider openai
uv run --frozen python scripts/check_live_llm.py --provider nvidia

Эти команды отправляют демо-данные внешним сервисам и могут расходовать API-кредиты. Ключи нельзя коммитить; .env и рабочие кэши исключены из Git.

Статус интеграций: одиночный живой запрос к OpenAI gpt-4o проверен; валидный ответ получен за 1,939 с. NVIDIA при проверке отклонил авторизацию текущим ключом. Полный прогон всех сценариев с внешними LLM пока не подтверждён. Основной автономный сценарий от этого не зависит.

API

МетодПутьНазначение
GET/Интерфейс
GET/healthГотовность сервиса и режим объяснений
GET/catalogСправочники и границы календаря
GET/demo-scenariosГотовые запросы
POST/recommendПодбор подрядчиков

Пример тела POST /recommend:

{
  "city": "Алматы",
  "date": "2026-10-13",
  "event_type": "корпоратив",
  "category": "Ведущий",
  "budget_kzt": 2000000,
  "brief": "Интеллигентный ведущий для делового вечера"
}

Обязательны первые пять полей; brief, language и duration_h опциональны. Проверить запрос без написания кода можно через /docs.

Поле ответаЗначение
outcomeFOUND, NO_CATEGORY или NO_MATCH
cardsДо трёх карточек с объяснениями и пометками происхождения
messageПричины пустой/неполной выдачи и контекст занятости
pool_sizeЧисло профилей в городе и категории
eligible_countЧисло всех прошедших фильтры
found_countЧисло показанных карточек
traceСчётчики фильтров, признаки рейтинга и источники объяснений

Бизнес-исходы возвращаются с HTTP 200. Некорректные параметры и дата вне подтверждённого календаря дают HTTP 422 с объяснением.

Данные и границы MVP

Источник — датасет организаторов: 66 анонимизированных профилей, включая 13 синтетических, уже присутствующих в поставке. Синтетические профили, а также проставленные при подготовке города и цены отмечаются в интерфейсе.

  • Календарь покрывает 23.09–31.12.2026. За пределами окна доступность неизвестна, поэтому такие запросы отклоняются.
  • Цена «от» — нижняя граница, а не подтверждённая смета.
  • Цитаты отражают сведения профиля; независимая проверка опыта не выполнялась.
  • Без брифа семантический признак отключён. Если также не заданы язык и часы, ранжирование опирается на запас бюджета и ID.
  • Одинаковые исходные сведения не превращаются в вымышленные преимущества: при совпадающих объяснениях сервис сообщает об этом.
  • Бронирования, оплаты, уведомлений подрядчикам и автоматической смены условий нет.

Дополнительные профили можно положить в data/synthetic/extra_profiles.jsonl с synthetic: true. Уникальность ID проверяется при загрузке. При замене календарного покрытия измените NEUROFORGE_CALENDAR_START и NEUROFORGE_CALENDAR_END. Остальные настройки описаны в .env.example.

Структура репозитория

api/                   HTTP API и жизненный цикл сервиса
src/neuroforge/         фильтры, скоринг, объяснения, LLM и загрузка данных
ui/                    интерфейс без сборки
data/raw/              исходный каталог
data/demo_queries.json пять демонстрационных запросов
scripts/               подготовка модели и проверки
tests/                 автономные тесты и регрессии
docs/                  архитектура, результаты проверок, сценарий защиты
run.py                 запуск сервиса или полной проверки
pyproject.toml          зависимости и настройки проекта
uv.lock                зафиксированные версии и хэши

В .github/workflows/checks.yml настроены проверки Linux. Первый запуск GitHub Actions не дошёл до тестов: GitHub сообщил о блокировке аккаунта из-за billing. Локальная проверка в чистом окружении прошла; Windows и визуальная проверка браузера отдельно не подтверждены.

Для сдачи: отправить актуальный код в репозиторий команды и нажать «Сдать решение» на платформе хакатона. Готовое описание проекта и план показа находятся в docs/demo.md.

Звёзды
⭐ 0
Форки
0
Язык
Python
Последний push
в прошлом месяце
Коммиты
8
Авторы
1
Файлы
48
Ветки
1

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

Nurdaulet 8

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

  • 2026-09-23 17:28docs: write jury-facing README and document verification limitsNurdaulet
  • 2026-09-23 17:23Finalize reproducible MVP launch and jury verification workflowNurdaulet
  • 2026-09-23 16:49Complete recommendation demo with grounded explanations and APINurdaulet
  • 2026-09-23 15:41Implement deterministic scoring and local embedding indexNurdaulet
  • 2026-09-23 15:25Implement filter funnel and outcome classificationNurdaulet
  • 2026-09-23 15:09Implement dataset loader and convert source dataset to JSONLNurdaulet
  • 2026-09-23 15:03Update workflow: Claude commits, Codex pushes per hackathon rulesNurdaulet
  • 2026-09-23 14:56Scaffold project structure and pipeline module skeletonsNurdaulet
Структура репозитория (48 файлов)
.env.example
.github/workflows/checks.yml
.gitignore
.python-version
CLAUDE.md
README.md
api/__init__.py
api/main.py
cache/.gitignore
constraints-demo.txt
data/demo_queries.json
data/processed/.gitkeep
data/raw/.gitkeep
data/raw/hackathon-dataset-anonymized.jsonl
data/synthetic/.gitkeep
docs/architecture.md
docs/demo.md
docs/validation.md
pyproject.toml
run.py
scripts/build_embeddings.py
scripts/check_live_llm.py
scripts/run_demo_queries.py
src/neuroforge/__init__.py
src/neuroforge/config.py
src/neuroforge/data_loader.py
src/neuroforge/embeddings.py
src/neuroforge/explain.py
src/neuroforge/filters.py
src/neuroforge/llm_client.py
src/neuroforge/messages.py
src/neuroforge/outcome.py
src/neuroforge/pipeline.py
src/neuroforge/prompts.py
src/neuroforge/schemas.py
src/neuroforge/scoring.py
tests/__init__.py
tests/test_data_loader.py
tests/test_explain.py
tests/test_llm_layer.py
tests/test_outcome.py
tests/test_pipeline.py
tests/test_regressions.py
tests/test_scoring.py
ui/app.js
ui/index.html
ui/style.css
uv.lock

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

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

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