О проекте
Команда: Tuzet
Кейс HackAlem.ai: Финансы — Freedom
Стадия: Доведённый продукт
Задача кейса: «Граф денег»: восстановить структуру организованной группы по сети транзакций (AML)
Суть
Локальная AML-платформа по графу переводов: каждому из 2 248 клиентов назначает структурную роль с role_score, приоритет проверки из пяти вкладов, находит мотивы (fan-in/out, циклы, scatter-gather, транзитные цепочки), показывает сообщества, устойчивость и чувствительность рейтинга.
Как устроено
Parquet-данные загружаются в направленный граф NetworkX. Считаются PageRank, betweenness и сообщества Louvain на ненаправленной проекции. Роли (consolidator, transit, distributor, terminal, coordinator, peripheral) назначаются по явным правилам с порогом 0.50, для transit учитывается FIFO-совместимость за 1–2 дня. Приоритет складывается из структуры, связи с seed, потока, типологии и времени; веса лежат в scoring.yaml. Запуски публикуются атомарно с хешами входа, выхода и конфига. FastAPI отдаёт данные в React/Cytoscape UI. LLM (опционально) только выбирает разрешённый тип вопроса, числа и доказательства формирует backend.
Ключевые решения
- NetworkX
- PageRank
- betweenness
- Louvain
- детекция мотивов (fan-in, fan-out, scatter-gather, циклы)
- FIFO-совместимость по времени
- анализ чувствительности весов
- сценарии структурной устойчивости (disruption)
- детерминированные хеши артефактов
Метрики
Полный пересчёт 49,08 с (лимит 300 с); 52 pytest, 2 Vitest, 6 Playwright-сценариев пройдены; воспроизводимые хеши выходов
Особенности
Деньги считаются в целых тиынах, запуски воспроизводимы (одинаковые хеши при повторе) и публикуются атомарным указателем. Роль, мотив, приоритет и evidence разведены как отдельные сущности, есть анализ чувствительности рейтинга к весам. Код импортирован одним коммитом за час до конца, поэтому история разработки в репозитории не видна.
Стек
Python · uv · pandas · PyArrow · NumPy · SciPy · NetworkX · FastAPI · Pydantic · React · TypeScript · Vite · TanStack Query · Cytoscape.js · Recharts · pytest · Vitest · Playwright
Модели
gpt-4.1-mini
Проект создан за 5 часов на финале хакатона HackAlem.ai (23 сентября 2026, Астана). Код — BAITC-Hacks/hack-159c5b29-tuzet.
README
README.mdTuzet
Tuzet — локальная аналитическая платформа для исследования обезличенного графа внутрибанковских переводов. Она помогает аналитику быстро выбрать клиентов для проверки, объяснить структурную роль и показать подтверждающие факты. Результаты — гипотезы для проверки, а не выводы о виновности и не доказательство происхождения конкретных денег.
Исходные материалы кейса лежат в data/ и starter/ и не изменяются расчётом. Формулы и ограничения описаны в методике, границы модулей — в архитектуре, короткий сценарий показа — в демо.
Что решает продукт
Аналитик получает один завершённый расчёт и может за минуту открыть любого клиента по gid.
- Сохраняет всех клиентов из исходной выборки, включая изоляты и узлы на границе наблюдения.
- Назначает одну основную структурную роль и отдельный
role_score: соответствие правилу, а не вероятность нарушения. - Считает приоритет проверки из пяти вкладов: структура, связь с seed, поток, типология и время.
- Находит мотивы: fan-in, fan-out, схождение нескольких seed, цепочка транзита, цикл, scatter-gather и повторяющийся маршрут. У каждого мотива есть статус временной совместимости и внутренние ID операций.
- Показывает направленное окружение, операции, сообщества, сценарии структурной устойчивости и чувствительность рейтинга к весам.
- Публикует три обязательные выгрузки и полный набор артефактов с хешами входа, выхода и конфигурации.
- Опционально отвечает на ограниченный вопрос ассистента фактами из уже посчитанного запуска. Без ключа модели поиск, граф и карточки продолжают работать.
Наблюдение неполное: граф собран исходящими переводами от seed не дальше четырёх переходов, суммы ниже 5 000 KZT отсутствуют, даты известны до дня. Поэтому terminal означает наблюдаемую конечную точку, а coordinator — структурную гипотезу, а не «организатора».
Каждый клиент получает роль с наибольшим score среди тех, что достигли 0.50. Если ни одна роль порог не достигла, ставится peripheral.
| Роль | Правило |
|---|---|
consolidator | Не менее 3 входящих контрагентов. Score учитывает степень, сумму, число входящих операций и охват seed. |
transit | Не seed; есть вход и выход; исходящий оборот составляет 0.80–1.20 от входящего. Score: 70% баланса оборота и 30% FIFO-совместимости за 1–2 дня. |
distributor | Не менее 5 получателей. Score: число получателей 50%, исходящие операции 30%, оборот 20%. |
terminal | Есть вход, нет наблюдаемых исходящих, depth < 4, после последнего поступления прошло минимум 2 дня. Score начинается с 0.50 и ограничен 0.75. |
coordinator | Betweenness не ниже 90-го процентиля положительных значений и достижимость от 2+ seed либо связи с 2+ соседними сообществами. |
peripheral | Ни одна основная роль не набрала 0.50. При обрезке по глубине или времени score ограничен 0.49. |
Какие технологии используются
Расчёт и API:
- Python 3.11, uv и зафиксированный
uv.lock - pandas и PyArrow для Parquet и CSV
- NumPy и SciPy для числовых признаков
- NetworkX для направленного графа, PageRank, betweenness и Louvain на ненаправленной проекции сообществ
- PyYAML и типизированная модель конфигурации
config/scoring.yaml - FastAPI, Pydantic и Uvicorn для локального API и раздачи интерфейса
- httpx для опционального запроса к OpenAI-compatible API
Интерфейс:
- React 18 и TypeScript
- Vite для сборки
- TanStack Query для запросов к API
- Cytoscape.js для направленного графа
- Recharts для дневной динамики операций
Проверки:
- pytest и Ruff для Python
- Vitest и ESLint для интерфейса
- Playwright и Chromium для сквозных сценариев в браузере
Деньги считаются в целых тиынах. Аналитические модули не зависят от HTTP, интерфейса и языковой модели. API только читает уже завершённый запуск.
Как запустить
Нужны Python 3.11+, Node.js 20.19+ и uv. Команды выполняются из корня репозитория.
Установка и сборка интерфейса выполняются один раз:
cd frontend && npm ci && npm run build && cd ..
uv sync --locked --extra dev --no-editable
Один запуск пересчитывает data/ и открывает Tuzet на http://127.0.0.1:8000:
uv run --locked --no-editable money-graph demo --data data --out artifacts/latest
Расчёт и просмотр можно разделить:
uv run --locked --no-editable money-graph analyze --data data --out artifacts/latest
uv run --locked --no-editable money-graph serve --artifacts artifacts/latest
--config path/to/scoring.yaml у analyze и demo подставляет другую версию порогов и весов. Без параметра используется config/scoring.yaml. После изменения Python-кода или повторной сборки frontend пакет нужно обновить:
uv sync --locked --extra dev --reinstall-package money-graph --no-editable
Сборка wheel не запускает npm. Сначала соберите frontend, затем выполните uv build. Сборка завершится ошибкой, если нет index.html или указанных в нём JS/CSS. Готовый wheel содержит интерфейс и стандартную конфигурацию.
artifacts/latest — атомарный указатель на каталог в artifacts/.money_graph_runs/. Неудачная публикация не затирает предыдущий успешный запуск. Чтобы открыть новый расчёт, сервер перезапускают. В интерфейсе доступны обзор, поиск по gid, фильтры, направленный граф на 1–2 перехода, карточка клиента, операции, мотивы, сообщества, устойчивость, чувствительность, ассистент и ссылки на CSV. Тёмная тема включена по умолчанию, светлая переключается в верхней панели. Схема API открывается на /docs.
AI-ассистент
По умолчанию ассистент выключен. Ключ хранится только в .env, этот файл не попадает в Git.
cp .env.example .env
В .env заполните MONEY_GRAPH_LLM_API_KEY. Пример указывает на https://api.openai.com/v1/chat/completions и модель gpt-4.1-mini. Для другого совместимого endpoint измените MONEY_GRAPH_LLM_URL и MONEY_GRAPH_LLM_MODEL. Переменные загружаются до запуска сервера:
set -a
source .env
set +a
uv run --locked --no-editable money-graph demo --data data --out artifacts/latest
Модель выбирает только разрешённый тип вопроса. Числа и доказательства формирует backend из текущего запуска. Провайдеру передаются вопрос и выбранный gid.
Какие шаги нужны для проверки решения
1. Подготовить окружение
Повторите установку из раздела «Как запустить»: npm ci, npm run build, затем uv sync --locked --extra dev --no-editable. Для браузерных тестов один раз установите Chromium:
cd frontend && npx playwright install chromium && cd ..
2. Прогнать автоматические проверки
uv run --locked --no-editable ruff check src tests
PYTEST_DISABLE_PLUGIN_AUTOLOAD=1 uv run --locked --no-editable pytest -q
cd frontend && npm run build && npm run lint && npm run test && npm run test:e2e
Pytest проверяет контракт данных, роли, мотивы, денежные агрегаты, публикацию артефактов и API. Vitest проверяет клиент API. Playwright открывает собранный интерфейс на готовом artifacts/latest и проходит обзор, карточку, граф, мотивы, сообщества, устойчивость, чувствительность, состояние выключенного ассистента и скачивание трёх CSV. Для E2E каталог artifacts/latest уже должен существовать, поэтому перед ним нужен хотя бы один analyze или demo.
Если менялись Python или интерфейс, перед тестами снова выполните сборку frontend и uv sync --locked --extra dev --reinstall-package money-graph --no-editable.
3. Пересчитать данные и сверить выгрузки
/usr/bin/time -p uv run --locked --no-editable money-graph analyze --data data --out artifacts/latest
Ограничение задания — 300 секунд на предоставленном наборе, включая запись и переключение указателя. После расчёта проверьте:
artifacts/latest/nodes_roles.csvсодержит все 2 248 клиентов и колонкиgid,role,role_score,cluster_id,priority_score,evidence.artifacts/latest/clusters.csvсодержитcluster_id,n_nodes,n_seed,sum_kzt_internal,top_gids,hypothesis.artifacts/latest/top_nodes.csvсодержит не меньше 20 строк и колонкиrank,gid,role,priority_score,why.artifacts/latest/manifest.jsonсодержит конфигурацию и её хеш, хеши входа и выхода, версии, предупреждения и длительности фаз.- Повторный запуск даёт те же хеши выходных файлов.
- В выборке сохранены 4 840 операций.
Три CSV для сдачи обновляются так:
for name in nodes_roles clusters top_nodes; do cp "artifacts/latest/$name.csv" deliverables/; done
4. Проверить интерфейс вручную
Запустите money-graph serve --artifacts artifacts/latest или demo и откройте http://127.0.0.1:8000.
- На обзоре видны число клиентов, связей и операций, а также первые клиенты для проверки.
- Поиск по
gidоткрывает карточку: роль, evidence, пять вкладов priority, правила и ограничения. - В графе видны направленные связи на 1 и 2 перехода. Фильтры меняют список и не пересчитывают оценки.
- У клиента открываются операции и мотивы с подтверждающими рёбрами.
- Разделы сообществ, устойчивости и чувствительности открываются без нового расчёта.
- Без ключа в
.envассистент показывает, что AI отключён, а остальные разделы работают. - Со страницы «О расчёте и выгрузки» скачиваются
nodes_roles.csv,clusters.csvиtop_nodes.csv. - На ширине экрана телефона доступны обзор, граф и карточка.
Интерактивная схема запросов доступна на http://127.0.0.1:8000/docs. Ответ /api/health содержит run_id открытого запуска.
5. Что считать успешным результатом
Решение готово, если сохранены все 2 248 клиента и 4 840 операций, три CSV валидны, топ содержит минимум 20 строк, любой gid находится в браузере, а полный расчёт укладывается в 300 секунд. Роль, мотив, приоритет и evidence остаются разными сущностями. Тексты интерфейса не утверждают вину.
Проверка 23.09.2026 на предоставленных данных: 52 Python-теста, 2 Vitest-теста и 6 Playwright-сценариев прошли; Ruff и ESLint прошли; npm audit сообщил 0 уязвимостей. Полный пересчёт с публикацией занял 49,08 секунды при повторном запуске; хеши всех 11 выходных файлов, включая три CSV, совпали между двумя запусками. Сохранены 2 248 клиентов, 4 840 операций и 19 изолятов. Методика в manifest — 1.2.2, формат артефактов — 4. Реальный сетевой ответ LLM в той проверке не выполнялся: ключ провайдера не был задан.
Авторы коммитов
История коммитов
- 2026-09-23 17:24Truncate the mobile topbar title so it stays beside the search field.qrlbk
- 2026-09-23 17:15Rename the interface to Tuzet and refresh assistant status while the page stays open.qrlbk
- 2026-09-23 17:14Describe what Tuzet solves, how to run it, and how to verify the result.qrlbk
- 2026-09-23 16:58Keep the project README when merging the hackathon stub.qrlbk
- 2026-09-23 16:58Import the money-graph analysis app for the hackathon repository.qrlbk
Структура репозитория (69 файлов)
.env.example .gitignore AGENTS.md Document 6.pdf MANIFEST.in README.md agentic.md config/scoring.yaml data/edges.parquet data/nodes.parquet data/transactions.parquet deliverables/clusters.csv deliverables/nodes_roles.csv deliverables/top_nodes.csv docs/architecture.md docs/demo.md docs/development-plan.md docs/methodology.md frontend/.eslintrc.cjs frontend/index.html frontend/package-lock.json frontend/package.json frontend/playwright.config.ts frontend/postcss.config.cjs frontend/src/App.tsx frontend/src/Graph.tsx frontend/src/api.test.ts frontend/src/api.ts frontend/src/components/ClientList.tsx frontend/src/components/Shell.tsx frontend/src/components/UI.tsx frontend/src/data/ui.ts frontend/src/main.tsx frontend/src/pages/CatalogPages.tsx frontend/src/pages/ClientPages.tsx frontend/src/pages/ExperimentPages.tsx frontend/src/pages/InfoPages.tsx frontend/src/styles.css frontend/tests/app.spec.ts frontend/tests/assistant.spec.ts frontend/tsconfig.json frontend/vite.config.ts pyproject.toml setup.py src/money_graph/__init__.py src/money_graph/analytics.py src/money_graph/api.py src/money_graph/assistant.py src/money_graph/cli.py src/money_graph/config_model.py src/money_graph/disruption.py src/money_graph/evidence.py src/money_graph/exports.py src/money_graph/features.py src/money_graph/ingestion.py src/money_graph/motifs.py src/money_graph/scoring.py src/money_graph/scoring.yaml src/money_graph/temporal.py starter/README.md starter/requirements.txt starter/starter.py tests/conftest.py tests/test_analytics.py tests/test_api.py tests/test_assistant.py tests/test_contracts.py tests/test_corrections.py uv.lock
Обсуждение 0 комментариев
Войдите, чтобы комментироватьПока нет комментариев — будьте первым.