AAYMA
RU
Войти

Граф денег

Кабинет AML-аналитика для сети переводов: направленный граф, сообщества Louvain, шесть объяснимых гипотез ролей, приоритет проверки, временные…

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

О проекте

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

Задача кейса: «Граф денег»: восстановить структуру организованной группы по сети транзакций (AML)

Суть

Кабинет AML-аналитика для сети переводов: направленный граф, сообщества Louvain, шесть объяснимых гипотез ролей, приоритет проверки, временные паттерны и циклы, AI-помощник для черновика заключения.

Как устроено

Три Parquet-таблицы проходят строгую проверку, затем Python-пайплайн на NetworkX строит направленный граф и считает признаки (seed_reach, betweenness, степени, суммы), сообщества Louvain и роли по правилам с порогами из config.json. priority_score — взвешенная сумма нормированных признаков, в поле why записываются два главных вклада. Отдельные модули находят всплески, групповые поступления, маршруты и циклы с учётом дат. FastAPI отдаёт результат в Next.js. AI-помощник (OpenAI Responses API, gpt-5.4-mini) получает только посчитанные факты под псевдонимами и отвечает со ссылками F1, F2…

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

  • NetworkX
  • Louvain
  • betweenness centrality
  • rule-based роли
  • временные паттерны и поиск циклов
  • PyVis
  • OpenAI Structured Outputs
  • псевдонимизация ID

Метрики

2248 клиентов, 3119 связей, 4840 операций; 88 сообществ, 974 события; расчёт 1,98 с (3,40 с при повторе)

Особенности

У каждого события хранятся правило, даты и ссылки на исходные операции. Перед отправкой в LLM идентификаторы заменяются псевдонимами, а ссылки в ответе проверяются. Мультиархитектурный Docker-образ публикуется через CI, есть инструкция деплоя на NVIDIA Brev.

Стек

Python 3.12 · pandas · NetworkX · FastAPI · Next.js 16 · React 19 · TypeScript · Docker · GitHub Actions · GHCR

Модели

gpt-5.4-mini


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

README

README.md

«Граф денег» — AItushka

Инструмент для исследования сети банковских переводов. Он помогает аналитику найти клиентов с приоритетом проверки, понять их роль в наблюдаемой сети, увидеть маршруты и временные паттерны переводов и получить объяснение каждого вывода на основе исходных операций.

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

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

  • загрузка и строгая проверка трёх Parquet-таблиц: клиентов, агрегированных связей и операций;
  • построение направленного графа переводов с сохранением точности больших int64-идентификаторов;
  • выделение сообществ алгоритмом Louvain;
  • шесть объяснимых гипотез ролей: consolidator, distributor, transit, terminal, coordinator, peripheral;
  • приоритет проверки от 0 до 1 с расшифровкой вклада каждого признака;
  • поиск временных событий: всплесков, групповых поступлений, повторов состава и последующих выходов;
  • поиск повторяющихся маршрутов и циклов с учётом дат и неизвестного порядка операций внутри дня;
  • интерактивный кабинет аналитика: обзор, очередь клиентов, фильтры, карточка клиента, граф связей и выгрузки;
  • переход от события к его участникам и исходным операциям;
  • автономная HTML-справка клиента и JSON-пакет доказательств;
  • AI-помощник: объяснение клиента или события, вопросы по текущему контексту и TXT-черновик заключения со ссылками F1, F2… на основания;
  • обязательные CSV-выгрузки и метаданные воспроизводимого запуска;
  • production-контейнер, Docker Compose и GitHub Actions для тестирования и публикации образа.

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

ПоказательЗначение
Клиентов2 248
Направленных связей3 119
Операций4 840
Период01.07.2026–31.07.2026
Сообществ88
Найденных событий974
Клиентов хотя бы с одним событием1 177

Найденные события включают 133 всплеска, 66 групповых поступлений, 5 повторов состава, 297 последующих выходов, 86 повторяющихся маршрутов и 387 циклов. Это совпадения формализованных правил, а не количество подтверждённых нарушений.

Зафиксированный в outputs/run_metadata.json контрольный прогон занимает 1,98 секунды чистого расчёта и 2,84 секунды от холодного старта до готовых файлов. Повторная проверка команды из README на полном наборе заняла 3,40 секунды. Это значительно ниже ограничения ТЗ в 5 минут; время зависит от компьютера и версий библиотек.

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

  1. Backend читает nodes.parquet, edges.parquet и transactions.parquet, проверяет схему, ссылки на клиентов и совпадение агрегатов с операциями.
  2. Python-пайплайн строит направленный граф, вычисляет признаки, сообщества, гипотезы ролей и приоритет проверки.
  3. Отдельные модули анализируют дневные потоки, маршруты и циклы. Каждое событие хранит правило, даты, измерения и ссылки на исходные операции.
  4. FastAPI держит текущий AnalysisResult в памяти и отдаёт типизированные данные, граф, справки и CSV.
  5. Next.js показывает аналитику очередь клиентов. Из карточки можно перейти к основаниям, событию, контрагенту или графу.
  6. По явному нажатию AI-помощник получает ограниченный пакет уже рассчитанных фактов. Идентификаторы участников заменяются локальными псевдонимами. Ответ проходит проверку структуры и ссылок на источники.
  7. Аналитик скачивает обычную справку или AI-черновик и принимает решение о следующей проверке самостоятельно.

Критерии ролей и приоритета

Роли являются проверяемыми гипотезами, а role_score показывает силу срабатывания правила и не является вероятностью нарушения. Пороговые значения читаются из config.json.

РольФормальное условие допуска по умолчанию
consolidatorне менее 3 разных плательщиков и достижимость минимум от 2 seed
distributorне менее 10 разных получателей и отношение out_deg / max(in_deg, 1) >= 2
transitне seed и не граница 4-го колена; есть вход и выход; 0,8 <= out_kzt / in_kzt <= 1,2
terminalне seed и не граница 4-го колена; есть входящие средства и out_deg = 0
coordinatorположительное посредничество не ниже 90-го перцентиля, достижимость минимум от 2 seed и связи минимум с 2 чужими сообществами
peripheralрезервная роль, если содержательные правила выше не сработали

Неподходящая роль получает оценку 0. Допустимые роли ранжируются по объяснимой формуле; неотрицательные признаки нормируются на 95-й перцентиль положительных значений. Узлы на четвёртом колене не признаются конечными получателями только из-за отсутствия видимого продолжения. Каждая строка получает человекочитаемое evidence длиной до 200 символов.

Приоритет проверки рассчитывается независимо от выбранной роли:

priority_score = 0.35 * N(seed_reach)
               + 0.25 * N(max(in_kzt, out_kzt))
               + 0.25 * N(betweenness)
               + 0.15 * N(in_deg)

В why сохраняются два крупнейших вклада с исходными значениями. Полные формулы силы каждой роли, правила FIFO и ограничения интерпретации приведены в docs/METHODOLOGY.md.

Технологии

СлойИспользуется
АналитикаPython 3.12, pandas, NumPy, SciPy, NetworkX, PyArrow
APIFastAPI, Uvicorn, Pydantic, HTTPX
FrontendNext.js 16, React 19, TypeScript
ГрафNetworkX, PyVis, Louvain communities
AIOpenAI Responses API, Structured Outputs, модель по умолчанию gpt-5.4-mini
ДанныеParquet, CSV, JSON
ПоставкаDocker, Docker Compose, GitHub Actions, GHCR
Проверкаpytest, TypeScript compiler, Next.js production build, container smoke-test

AI не рассчитывает роли, суммы или рейтинг. Все фактические показатели вычисляет Python; модель только помогает интерпретировать выбранный контекст.

Архитектура

flowchart LR
    D[Parquet: nodes, edges, transactions] --> V[Проверка данных]
    V --> P[Python analytics pipeline]
    P --> R[Роли и приоритет]
    P --> E[События, маршруты и циклы]
    R --> A[AnalysisResult в памяти]
    E --> A
    A --> F[FastAPI :8000]
    F --> N[Next.js :3000]
    N --> U[Аналитик]
    A --> X[CSV / JSON / HTML]
    F --> C[Ограниченный AI-контекст]
    C --> O[OpenAI Responses API]
    O --> F

Основные компоненты:

  • src/money_graph/ — проверка данных, признаки, роли, рейтинг, события, отчёты и API;
  • frontend/ — отдельный интерфейс Next.js;
  • run.py — единая локальная команда расчёта и запуска двух серверов;
  • data/ — исходные данные хакатона;
  • tests/ — автоматические проверки аналитики и HTTP-контрактов;
  • Dockerfile, compose.yaml, deploy/ — production-запуск;
  • .github/workflows/ci-cd.yml — CI и доставка контейнера.

Подробная схема и инварианты модулей находятся в docs/architecture.md.

Установка и локальный запуск

Требования: Python 3.12, Node.js 24 и npm.

Windows PowerShell

git clone https://github.com/BAITC-Hacks/hack-912ce0e6-aitushka.git
cd hack-912ce0e6-aitushka
py -3.12 -m venv .venv
.\.venv\Scripts\python.exe -m pip install -r requirements.txt
npm install --prefix frontend
.\.venv\Scripts\python.exe run.py --data data --out outputs --ui

Linux / macOS

git clone https://github.com/BAITC-Hacks/hack-912ce0e6-aitushka.git
cd hack-912ce0e6-aitushka
python3.12 -m venv .venv
.venv/bin/python -m pip install -r requirements.txt
npm install --prefix frontend
.venv/bin/python run.py --data data --out outputs --ui

После сообщения о готовности откройте http://localhost:3000. Ctrl+C останавливает оба сервера. Для расчёта без интерфейса уберите --ui.

Один воспроизводимый запуск пайплайна

После установки зависимостей одна команда читает три исходных Parquet-файла, пересчитывает граф и создаёт все обязательные CSV:

.\.venv\Scripts\python.exe run.py --data data --out outputs

На Linux и macOS используйте .venv/bin/python вместо Windows-пути. Успешный запуск создаёт outputs/nodes_roles.csv, outputs/clusters.csv, outputs/top_nodes.csv и дополнительный outputs/run_metadata.json с контрольными суммами, параметрами и временем этапов.

Другие порты и конфигурация:

.\.venv\Scripts\python.exe run.py --data data --out outputs --config config.json --ui --port 3000 --api-port 8000

Запуск через Docker

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

cp .env.example .env
docker compose up -d --build
docker compose ps

Приложение доступно на http://localhost:3000. Контейнер запускается без root, публикует только порт 3000 и проверяет полный путь Next.js → FastAPI → анализ через /api/health. CI выпускает один multi-architecture образ для linux/amd64 и linux/arm64.

После успешного CI готовый образ публикуется как:

ghcr.io/baitc-hacks/hack-912ce0e6-aitushka:latest

Тогда вместо локальной сборки можно выполнить:

docker compose pull
docker compose up -d --no-build

Запуск в NVIDIA Brev / DGX Cloud

Приложение не использует CUDA, поэтому для демонстрации достаточно CPU-инстанса. На Brev:

git clone https://github.com/BAITC-Hacks/hack-912ce0e6-aitushka.git
cd hack-912ce0e6-aitushka
cp .env.example .env
docker compose up -d --build

Для приватного доступа выполните на своём компьютере:

brev port-forward ИМЯ_ИНСТАНСА --port 3000:3000

Для демонстрации добавьте порт 3000 в Brev Console → Access → Secure Links. Полученный HTTPS URL укажите в .env как AI_ALLOWED_ORIGINS=https://ваш-домен и повторно выполните docker compose up -d.

Полная инструкция, обновление и откат: docs/DEPLOY_NVIDIA.md.

Настройка AI

AI необязателен: вся основная аналитика работает без API-ключа и интернета. Для включения скопируйте .env.example в .env и заполните:

OPENAI_API_KEY=YOUR_KEY
OPENAI_MODEL=gpt-5.4-mini
AI_MAX_REQUESTS=50
# Для публичного размещения:
AI_ALLOWED_ORIGINS=https://ваш-домен

Ключ читает только backend, он не попадает во frontend и исключён из Git и Docker build context. Запрос создаётся только после действия пользователя. В OpenAI передаются выбранные показатели, даты, события и вопрос; исходные gid заменяются обозначениями участников. Используется store: false, но псевдонимизация не равна полной анонимизации.

Подробности: docs/AI.md.

Как жюри проверить решение

  1. Запустите проект локально или через Docker и откройте обзор.
  2. В строке поиска введите 100000003684369100.
  3. Убедитесь, что карточка показывает гипотезу «Координатор», приоритет 0,965, входящий поток 3 848 436 KZT и исходящий 8 588 655 KZT.
  4. Посмотрите «Основания приоритета»: достижимость от 9 seed, наблюдаемый поток, посредничество и число плательщиков показаны отдельно.
  5. Откройте «События и маршруты», раскройте повторяющийся маршрут и проверьте его даты, шаги и исходные операции.
  6. Нажмите «Показать на графе» и убедитесь, что граф ограничился участниками выбранного события.
  7. Скачайте HTML-справку клиента или один из CSV в разделе «Выгрузки».
  8. Если настроен OpenAI, нажмите «Объяснить клиента», затем откройте основание F3: суммы в ответе должны совпадать с локальными показателями.

Полный пятиминутный сценарий: docs/DEMO.md.

Выходные файлы

ФайлОбязательные поля по ТЗФактический результат
nodes_roles.csvgid, role, role_score, cluster_id, priority_score, evidence2 248 строк; дополнительно содержит исходные метрики, оценки всех ролей, вклады приоритета и ограничения наблюдения
clusters.csvcluster_id, n_nodes, n_seed, sum_kzt_internal, top_gids, hypothesis88 строк, по одной на найденное сообщество
top_nodes.csvrank, gid, role, priority_score, why20 ранжированных узлов с объяснением
run_metadata.jsonдополнительный артефактконфигурация, контрольные суммы входов, статистика, версии библиотек и время этапов

Идентификаторы во всех JSON передаются строками. Сохранённые файлы в outputs/ не используются API как кеш: HTTP-выгрузки формируются из текущего расчёта в памяти.

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

Исходные файлы находятся в data/:

  • nodes.parquet — клиенты, seed и глубина обхода;
  • edges.parquet — агрегаты направленных пар;
  • transactions.parquet — отдельные переводы с датами и суммами.

Набор ограничен одним банком, июлем 2026 года, переводами от 5 000 KZT и обходом исходящих связей от 81 seed-клиента до глубины 4. Поля описаны в data/README.md.

Единственная внешняя runtime-интеграция — OpenAI Responses API, и она включается только при наличии ключа. NVIDIA Brev используется как площадка запуска контейнера; специфические NVIDIA API и GPU в вычислениях проекта не используются.

Автоматические проверки

.\.venv\Scripts\python.exe -m pytest -q
npm.cmd run typecheck --prefix frontend
npm.cmd run build --prefix frontend

Локально подтверждено: 148 passed, успешные TypeScript-проверка и production-сборка Next.js. GitHub Actions дополнительно собирает контейнер, запускает его, ждёт /api/health, проверяет UID 10001 и только затем публикует образ в GHCR.

Ограничения текущей версии

  • Это аналитические гипотезы без размеченной выборки нарушений; precision/recall не заявляются.
  • В данных нет времени внутри дня, назначения платежа, баланса, внешних переводов и полной истории до/после периода.
  • Seed-клиенты имеют неполную входящую часть, а узлы на глубине 4 могут иметь обрезанные исходящие связи.
  • FIFO показывает совместимость дневных сумм, но не доказывает движение одних и тех же денег.
  • Разные события могут ссылаться на одни операции; их суммы нельзя складывать в общий «подозрительный оборот».
  • NetworkX-реализация рассчитана на текущий хакатонный набор и не заявлена как решение для миллиона узлов.
  • AI может ошибиться в интерпретации даже при корректной ссылке на источник; финальный вывод проверяет аналитик.
  • Лимиты AI и кеш находятся в памяти одного процесса и сбрасываются при перезапуске.
  • В приложении нет собственной пользовательской аутентификации и системы ролей доступа. Демонстрационная ссылка намеренно открыта для жюри; при работе с непубличными данными доступ необходимо закрыть средствами платформы.

Масштабирование до 1 млн узлов

Текущая реализация на pandas и NetworkX рассчитана на предоставленный граф из 2 248 узлов. При росте примерно до миллиона узлов сохраняются контракт выходных файлов, формулы ролей и объяснения, но вычислительный слой потребуется заменить:

  • читать Parquet пакетами и выполнять агрегации в Polars, DuckDB, Spark или другом columnar/distributed-движке;
  • хранить рёбра и рассчитанные признаки в постоянном аналитическом хранилище вместо одного AnalysisResult в памяти;
  • использовать эффективный графовый движок или разреженные структуры, а посредничество считать приближённо на выборке;
  • пересчитывать независимые компоненты и временные окна параллельно и инкрементально;
  • отдавать интерфейсу подграф вокруг выбранного клиента, кластера или маршрута, а не весь граф;
  • вынести длительные расчёты в фоновые задания с версионированием результата и fingerprint входных данных.

Такой переход меняет способ хранения и исполнения, но не аналитический контракт между пайплайном, API и интерфейсом.

Deployed-версия

Открыть Hackalen в NVIDIA Brev

Сервис развёрнут на ARM64-инстансе NVIDIA Brev. Ссылка открывается публично без авторизации для проверки жюри.

Документация

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

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

thedids10 9kLot2005 2

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

  • 2026-09-23 17:39Align README with hackathon specificationthedids10
  • 2026-09-23 17:34Document public demo accessthedids10
  • 2026-09-23 17:30Document NVIDIA Brev deploymentthedids10
  • 2026-09-23 17:13Publish containers for ARM64 Brev instancesthedids10
  • 2026-09-23 17:08Rewrite README for hackathon evaluationthedids10
  • 2026-09-23 17:04Add container CI/CD for NVIDIA cloud deploymentthedids10
  • 2026-09-23 16:54Add grounded AI assistant for client and event analysisthedids10
  • 2026-09-23 16:54Add evidence-backed transaction pattern analysisthedids10
Все коммиты (11)
  • 2026-09-23 15:41Improve dashboard typography and collapsible navigationthedids10
  • 2026-09-23 15:18Split analytics app into Next.js and FastAPIkLot2005
  • 2026-09-23 14:16Build explainable transaction graph analyzerkLot2005
Структура репозитория (80 файлов)
.dockerignore
.env.example
.github/workflows/ci-cd.yml
.gitignore
Dockerfile
README.md
compose.yaml
config.json
data/README.md
data/edges.parquet
data/nodes.parquet
data/transactions.parquet
deploy/healthcheck.py
deploy/serve.py
docs/AI.md
docs/ANALYTICS_EXTENSION_DESIGN.md
docs/DEMO.md
docs/DEPLOY_NVIDIA.md
docs/IMPLEMENTATION_PLAN.md
docs/METHODOLOGY.md
docs/VALIDATION.md
docs/architecture.md
frontend/.gitignore
frontend/next-env.d.ts
frontend/next.config.ts
frontend/package-lock.json
frontend/package.json
frontend/src/app/globals.css
frontend/src/app/layout.tsx
frontend/src/app/page.tsx
frontend/src/components/analyst-ai.tsx
frontend/src/components/client-patterns.tsx
frontend/src/components/icon.tsx
frontend/src/lib/types.ts
frontend/tsconfig.json
outputs/clusters.csv
outputs/nodes_roles.csv
outputs/run_metadata.json
outputs/top_nodes.csv
pyproject.toml
requirements-lock.txt
requirements.txt
run.py
src/money_graph/__init__.py
src/money_graph/ai_context.py
src/money_graph/ai_service.py
src/money_graph/analyst_report.py
src/money_graph/api.py
src/money_graph/communities.py
src/money_graph/config.py
src/money_graph/data.py
src/money_graph/event_data.py
src/money_graph/explain.py
src/money_graph/export.py
src/money_graph/features.py
src/money_graph/pipeline.py
src/money_graph/ranking.py
src/money_graph/roles.py
src/money_graph/route_patterns.py
src/money_graph/temporal.py
src/money_graph/temporal_patterns.py
src/money_graph/visualization.py
starter/README.md
starter/requirements.txt
starter/starter.py
tests/conftest.py
tests/test_ai.py
tests/test_api.py
tests/test_communities.py
tests/test_data.py
tests/test_graph.py
tests/test_launcher.py
tests/test_pattern_api.py
tests/test_pipeline.py
tests/test_real_dataset.py
tests/test_roles_and_ranking.py
tests/test_route_patterns.py
tests/test_temporal.py
tests/test_temporal_patterns.py
tests/test_visualization.py

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

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

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