AAYMA
RU
Войти

Граф денег

Локальный AML-инструмент: граф переводов с ролями участников, кластерами, очередью приоритетов для проверки, интерактивной визуализацией и…

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

О проекте

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

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

Суть

Локальный AML-инструмент: граф переводов с ролями участников, кластерами, очередью приоритетов для проверки, интерактивной визуализацией и AI-пояснениями.

Как устроено

starter.py читает nodes/edges/transactions.parquet, строит направленный граф NetworkX, считает признаки (PageRank, достижимость от seed, приближённое betweenness, степени). Роли назначаются упорядоченными пороговыми правилами (coordinator, distributor, transit, consolidator, terminal, peripheral), кластеры — Louvain с фиксированным seed, priority_score — взвешенная сумма процентилей. Выход: nodes_roles.csv, clusters.csv, top_nodes.csv и manifest с хешами; UI на Next.js + Cytoscape.js, AI-объяснения через gpt-4o-mini Structured Outputs с проверкой ссылок.

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

  • NetworkX
  • Louvain
  • PageRank
  • approximate betweenness
  • rule-based roles
  • percentile priority scoring
  • node removal impact analysis
  • Structured Outputs

Особенности

«Влияние на сеть»: удаление узла из копии графа и измерение потери структурной достижимости между seed и целями; неизменяемые снимки запусков с контрольными суммами; LLM не меняет роли и CSV, а ссылки в его ответах проверяются.

Стек

Python 3.12 · pandas · NumPy · PyArrow · NetworkX · SciPy · FastAPI · Next.js · React · TypeScript · Tailwind CSS · Cytoscape.js · TanStack Query · Streamlit · pytest · Vitest · Playwright

Модели

gpt-4o-mini


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

README

README.md

Граф денег

Что решает продукт

Локальный инструмент для AML-аналитика: строит граф внутрибанковских переводов, назначает объяснимые структурные роли, ранжирует клиентов для проверки и показывает направленные связи. Роли и приоритеты являются гипотезами для аналитика, а не утверждениями о виновности.

Продукт помогает сократить ручной просмотр транзакций: выбрать узел из очереди, проверить его контрагентов и основания роли, увидеть ограничения выборки и сохранить воспроизводимые результаты. Он не определяет виновность и не заменяет банковскую AML-систему.

Технологии

  • Аналитика: Python 3.12, pandas, NumPy, PyArrow, NetworkX, SciPy. Направленный граф, Louvain, PageRank, приближённое betweenness и явные пороговые правила.
  • Backend: FastAPI, Uvicorn; неизменяемые локальные снимки запусков и CSV, без обязательной базы данных.
  • Интерфейс: Next.js, React, TypeScript, Tailwind CSS, Radix/shadcn-компоненты, Cytoscape.js, TanStack Query. Светлая тема, локальные ресурсы и системные шрифты.
  • Проверки: pytest, Vitest, Playwright. Необязательный AI: OpenAI API с проверкой структурированного ответа. Для обязательных результатов ключ, платные сервисы, GPU и облачный кластер не нужны.

Запуск

Link do the DEMO: https://drive.google.com/drive/folders/1FmSMApK9wu-PtmdFJFk3BZmhE2dOHMCn?usp=sharing

Первоначальная установка

Нужны Python 3.12 и, только для нового UI, Node.js 22+. Проверьте python3.12 --version, node --version и npm --version. Если python3.12 не найден, сначала установите Python 3.12 и добавьте его в PATH либо замените python3.12 ниже полным путём к установленному интерпретатору. Системный Python 3.9 не подходит для указанного окружения. Получите репозиторий и установите зависимости:

git clone https://github.com/BAITC-Hacks/hack-f40a9595-ayan-solutions.git
cd hack-f40a9595-ayan-solutions
python3.12 -m venv .venv
.venv/bin/python -m pip install -r requirements.txt
npm ci --prefix web

Три исходных parquet уже включены в data/. Интернет нужен для первоначальной установки зависимостей; после установки обязательный расчёт и интерфейс работают локально без внешнего LLM. Если проверяется только pipeline, установку Node.js/npm можно пропустить.

Пайплайн: одна команда

Из корня установленного проекта:

.venv/bin/python starter.py --data data --out out

Команда читает сырые parquet, проверяет их согласованность, вычисляет признаки, роли и кластеры и создаёт весь комплект без ручных промежуточных шагов:

  • out/nodes_roles.csv: gid, role, role_score, cluster_id, priority_score, evidence.
  • out/clusters.csv: cluster_id, n_nodes, n_seed, sum_kzt_internal, top_gids, hypothesis.
  • out/top_nodes.csv: rank, gid, role, priority_score, why.
  • Дополнительно out/manifest.json: параметры, хеши входов и время расчёта.

Рабочий интерфейс: одна команда

.venv/bin/python serve.py

Откройте http://127.0.0.1:3000/network. При первом запуске нажмите «Запустить анализ». Источник: три файла data/nodes.parquet, data/edges.parquet, data/transactions.parquet. API слушает только 127.0.0.1:8000; порт UI меняется через serve.py --port 3001 --api-port 8001. На Windows используйте .venv\Scripts\python; Windows-запуск отдельно не проверялся. Продакшн-сборка локального интерфейса: npm run build --prefix web, затем .venv/bin/python serve.py --production.

Один запуск сохраняет собственные исходные файлы, конфигурацию, позиции, результаты и метаданные в игнорируемой папке .runs/<run_id>/. Новый результат публикуется только целиком после проверок. Старые запуски доступны на странице «Данные и методика → Запуски». Замена файлов в data/ не меняет завершённые результаты. dataset_id определяется контрольными суммами; run_id обозначает отдельный расчёт. В новом интерфейсе загрузка идёт из локальной папки, без web-upload.

Новый UI экспортирует такие же CSV из выбранного снимка, независимо от фильтров. На исходном наборе: 2248 узлов, 3119 направленных пар, 4840 транзакций. CLI и UI вызывают одно аналитическое ядро; UI создаёт свой run, а не читает потенциально устаревшие файлы из out/.

Основной сценарий: рассчитать → отфильтровать очередь → выбрать клиента → проверить связи и основания роли → выгрузить результат. Период над результатом берётся из дат загруженных транзакций. Для тестов: .venv/bin/python -m pytest -q.

Основной UI: Next.js + TypeScript, Tailwind, компоненты shadcn/Radix, Cytoscape.js, TanStack Query; backend: FastAPI поверх существующих pandas/NetworkX. Шрифты системные, ресурсы графа локальные, ключи остаются только на backend.

  • /network: вся сеть, фильтры, окружение 1–3 переходов с направлением, поиск, таблица приоритетов и общий инспектор узла/ребра.
  • /overview: состав данных, роли, компоненты, дневная активность и ограничения.
  • /nodes, /nodes/[gid]: все узлы, приоритетные узлы, полная карточка с теми же признаками, связями, переводами и AI.
  • /clusters, /clusters/[id]: реальные сообщества, участники, внутренние суммы и внешние связи.
  • /reports: три обязательных CSV, manifest, ZIP с методикой и результаты проверок.
  • /methodology: данные, контрольные суммы, конфигурация, правила и история запусков.

Предыдущий Streamlit-интерфейс сохранён как резервный: .venv/bin/streamlit run app.py. Он по-прежнему поддерживает загрузку трёх parquet через браузер. Новый UI не является заявлением о готовности к банковской эксплуатации: аутентификация, RBAC и аудит доступа отсутствуют. Не открывайте сервис во внешнюю сеть.

В топ-листе можно выбрать строку, чтобы сразу открыть карточку клиента. Вкладка «Переводы» показывает реальные строки, направления и даты, с фильтрами и пагинацией. Обзор анализа содержит общую дневную активность. Старый Streamlit дополнительно показывает дневное совпадение входящих и исходящих конкретного клиента; отдельный дневной график клиента в новом UI пока не перенесён. Дневная гранулярность не доказывает сквозной транзит: времени внутри дня в исходнике нет.

В карточке доступно «Влияние на сеть»: удаление одного узла только из копии полного графа. До/после сравниваются одинаковые surviving источники (seed) и цели, без удаляемого узла и пар source=target. Процент означает потерю структурной достижимости, а не финансовый ущерб. Фильтры, позиции и оригинальные CSV сохраняются.

Роли и приоритет

Основные пороги ролей лежат в config.json; коэффициенты приоритета и дополнительные константы силы признаков заданы в analysis.py. Правила проверяются по порядку; первая подходящая роль становится основной:

РольПравило
coordinatorДостижим от ≥3 seed, есть вход и выход, процентиль направленного посредничества ≥0,90 и соседство с ≥2 другими кластерами
distributor≥10 разных получателей
transitНе seed; вход и выход >0; наблюдаемый выход/вход в [0,8; 1,2]
consolidator≥3 разных плательщиков и положительная входящая сумма
terminalВход >0, выход=0, depth<4, не seed
peripheralДругие правила не сработали или недостаточно наблюдений

Численные признаки: число разных контрагентов и транзакций, суммы, взвешенный PageRank, достижимость от seed, приближённое направленное betweenness (до 128 исходных узлов), соседство кластеров. Сумму нельзя использовать как расстояние для betweenness; он считается без веса. role_score — сила выполнения правила, а не вероятность истины: 0,5 + до 0,4 за профильный признак, 0,2 для peripheral, 0 для изолятов; на обрезанном колене максимум 0,6. Точные формулы реализованы в analysis.py.

priority_score — сумма процентильных факторов: 0,30 × достижимость от seed + 0,25 × входящая сумма + 0,20 × максимум входящей/исходящей степени + 0,15 × посредничество + 0,10 × PageRank. Для нулевого признака процентиль равен 0. Изоляту приоритет 0. В top_nodes.csv приведены основания, сортировка при ничьей — по gid. Это эвристика очередности проверки, не риск преступления.

Кластеры строятся Louvain с фиксированным seed на неориентированной проекции; суммы встречных переводов складываются. Направленный граф сохраняется для потоков и ролей. Каждый изолят получает отдельный кластер. Номера кластеров стабилизированы по минимальному gid. sum_kzt_internal суммирует только направленные рёбра внутри кластера, каждое один раз.

Справка аналитика и AI

Карточка всегда содержит рассчитанные основания, точные условия правила и ограничения. На вкладке «AI» есть три действия: объяснить роль, проверить гипотезу, предложить следующую проверку. Только нажатие отправляет запрос: признаки выбранного синтетического gid и до 10 связанных gid. Ответ структурирован, ссылки на данные проверяются. Модель не меняет роли, приоритет или CSV. При отсутствии ключа, таймауте или отказе сохраняется явно обозначенное объяснение правил без LLM. Модель задаётся через OPENAI_MODEL (по умолчанию gpt-4o-mini). Ключ задаётся переменной окружения или в .env в корне по образцу .env.example; переменная окружения имеет приоритет. .env исключён из Git. Живой запрос в новом интерфейсе проверен. Использован формат Structured Outputs из официальной документации OpenAI.

На той же вкладке есть уточняющий вопрос и история до шести пар вопрос/ответ. Контекст включает рассчитанные признаки, правила роли и соседние связи. В новом UI диалог привязан к run_id и GID, хранится только в памяти страницы, очищается при переключении запуска или кнопкой «Очистить диалог». В localStorage сохраняются только настройки вида. При ошибке вопрос остаётся для ручного повтора, без скрытых повторных обращений к провайдеру. Без ключа остаётся правиловое объяснение, а не имитация ответа LLM.

Ответы чата не меняют расчёт. Ссылки на показатели и GID проходят проверку, а численные основания выводятся из рассчитанных данных. Проверка структуры и ссылок не гарантирует истинность текстовой интерпретации: выводы AI требуют проверки аналитиком. Запросы отправляются с store=false, история передаётся явно по схеме управления контекстом OpenAI. Это не равнозначно гарантии отсутствия всех служебных журналов провайдера. Живое демо использует синтетический набор; реальные банковские данные требуют отдельно согласованной политики передачи провайдеру.

Защита AI от инъекций

Инструкции приложения отделены от вопросов и данных. История и текущая справка передаются как недоверенный JSON в пользовательском сообщении, а не как новые инструкции или сообщения assistant. Типовые попытки отменить правила, подменить роль, запросить секреты, внедрить ссылки/изображения или скрытые инструкции блокируются локально. Проверяются также история, справка, контекст и ответы. Заблокированные вопросы не отправляются в API и не попадают в историю; подозрительные ответы не отображаются и не сохраняются.

Текст вопроса, ответа и справки отображается без Markdown/HTML, поэтому модель не может встроить активную ссылку или загружаемое изображение. У AI нет инструментов чтения файлов, браузера или изменения расчёта. API-ключ используется для авторизации запроса, не передаётся в контексте; проверяется и его случайное попадание в запрос/ответ. Ограничения и сценарии проверки описаны в docs/AI_SECURITY.md. Это многоуровневое снижение риска, не гарантия обнаружения любой инъекции или истинности любого ответа.

Ограничения данных

  • Исходный набор охватывает только исходящие переводы от 81 seed по четырём коленам, внутри одного банка, за июль 2026 года, с порогом 5000 KZT. Входящие извне выборки и меньшие переводы не видны.
  • Все 444 узла depth=4 без исходящих находятся на границе обхода. Они не объявляются terminal только из-за отсутствия видимых исходящих.
  • Входящие seed могут быть занижены. Отношение выхода к входу у seed не используется для transit.
  • 19 изолятов входят в экспорт и поиск. С рёбрами видны 16 слабосвязных компонент, с изолятами — 35.
  • У данных нет истинных меток ролей, личных атрибутов и остатков. role_score нельзя интерпретировать как подтверждённую точность; нет оценки accuracy. Дневная гранулярность транзакций не доказывает последовательность внутри суток.
  • Новый UI показывает всю сеть, включая изоляты; локальное окружение и фильтры меняют только отображение. Расчёт и обязательные CSV всегда используют все узлы.

Масштабирование

При росте до ~1 млн узлов потребуются колонночная обработка parquet, специализированный графовый движок, приближённые метрики, хранение результатов и выдача подграфов по запросу. Полный граф перестанет загружаться в браузер: сервер будет возвращать выбранные сообщества/окружения, таблицы будут запрашиваться постранично. Метрики и результаты нужно хранить отдельно от процесса API. Данная реализация на таком масштабе не проверялась.

Схема процесса: docs/architecture.md. Сценарий выступления: docs/demo.md.

Проверка исходного аналитического ядра до смены UI: docs/FINAL_CHECK.md. Реализация новой UI-спецификации, проверки и оставшиеся ограничения: docs/UI_IMPLEMENTATION.md.

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

Проверка свежего клона с новой .venv, новыми node_modules, пересборкой и запуском без API-ключа: docs/CLEAN_INSTALL_CHECK.md. Это проверка изоляции проекта на текущем macOS, не тест всех ОС.

  1. После установки выполните команду pipeline выше. Убедитесь, что созданы все три CSV и время в консоли меньше 300 секунд.
  2. Выполните .venv/bin/python -m pytest -q tests/test_analysis.py tests/test_api.py. Проверяются покрытие узлов, словарь ролей, заполненность, оценки, повторяемость, пересчёт на изменённом наборе, согласованность карточек/CSV и суммы кластеров.
  3. Запустите serve.py, откройте /network и создайте анализ. Выберите три любых GID из nodes_roles.csv; найдите каждый глобальным поиском. Сверьте роль, score, кластер и evidence. В «Обзоре» карточки проверьте фактические значения и пороги правила, затем откройте «Связи» и «Переводы».
  4. Откройте «Кластеры», выберите сообщество, проверьте участников, число seed, внутреннюю сумму и гипотезу. Внешние связи не включаются во внутреннюю сумму.
  5. На «Сети» проверьте топ, направления стрелок и цвета ролей. «Окружение» увеличивает связный контекст выбранного GID; изолированный GID также находится, но честно показывает отсутствие связей.
  6. В «Отчётах» скачайте три CSV одного run и сопоставьте с карточками. На исходном наборе содержимое совпадает с CLI. Полный экспорт не зависит от фильтров.
  7. Необязательная проверка AI: настройте .env, перезапустите сервер, явно нажмите действие во вкладке «AI» и задайте уточнение. Без ключа граф, роли, объяснения правил и CSV должны продолжать работать.

Раздел 7 ТЗ: пять Must Have

В разделе 7 перечислены пять, а не семь обязательных функций. Результаты ниже проверены 23.09.2026 свежим CLI-запуском на предоставленном наборе; это не измерение на отдельной машине жюри.

№Обязательная функцияСпособ проверкиФактический результат
1Воспроизводимый pipelineОдна команда starter.py после установки; сверить три CSV, время и повторный запуск0,373 с внутри pipeline на текущем компьютере; три CSV созданы и побайтно совпали с сохранёнными
2Роль и скор каждого узлаПроверить покрытие GID из nodes, словарь ролей, обязательные поля и evidence2248 уникальных GID, пропусков 0, пустых evidence 0, максимальная длина evidence 106 при лимите 200
3Объяснимые критерииРаздел «Роли и приоритет», config.json, «Почему назначена эта роль»; сверить три произвольных GIDВсе шесть правил задокументированы; три выбранные проверкой карточки совпали с CSV, условия возвращает backend
4КластеризацияСверить clusters.csv, cluster_id всех узлов, размеры/seed/суммы/гипотезы91 кластер, суммарно 2248 участников и 81 seed; обязательные поля и гипотезы заполнены
5Топ и схема сетиПроверить уникальность/rank/why в top_nodes.csv; найти GID в UI, показать направленные связи и роль50 уникальных ранжированных узлов с основаниями; поиск, карточки, связи и canvas проверены браузерными тестами

Опциональные возможности: честный статус

ВозможностьЧто есть / чего нет
Обрыв на четвёртом коленеРеализовано: depth=4 не становится terminal только из-за отсутствия исходящих; ограничения видны в карточке
Временные паттерныЧастично: дневная активность, реальные даты переводов; совпадение входа/выхода по дням есть в резервном Streamlit. Детектора транзита за 1–2 дня, всплесков и синхронных плательщиков нет
Повторяющиеся маршруты и возвратные потокиОтдельный поиск цепочек и циклов не реализован
АномалииОтдельной детекции дробления/отклонений относительно колена нет; приоритет не выдаётся за детектор аномалий
Устойчивость сетиЧастично: удаление одного выбранного узла из копии полного графа и изменение достижимости. Топ-N и анализ распада на компоненты после удаления не реализованы
AI-ассистентРаботают вопросы, уточнения, ссылки на GID и проверяемые признаки выбранного узла с соседями. Произвольные запросы по всей сети/любым пяти выбранным узлам не поддерживаются
Карточка узлаРеализованы вычисленные метрики, роль, связи, evidence и ограничения; сохранённые пользовательские справки нового UI не реализованы
ПолнотаУказаны неполные входящие, граница обхода, отсутствие балансов/разметки и следующие запросы данных; количественной оценки полноты нет

Артефакты сдачи

  • Исходники pipeline и интерфейса: этот репозиторий; входы data/, обязательные выгрузки out/ отслеживаются Git.
  • README: установка, команды запуска, технологии, правила/пороги, проверки, ограничения и масштабирование.
  • Схема «данные → метрики → роли → интерфейс»: docs/architecture.md, диаграмма Mermaid отображается в GitHub.
  • Пятиминутный сценарий с живым прогоном и разбором 2–3 узлов: docs/demo.md. Сценарий подготовлен; фактическое выступление и принятие работы жюри не подтверждены кодом или тестами.

Проверки нового UI

.venv/bin/python -m pytest -q
npm test --prefix web
npm run build --prefix web

Для браузерных проверок запустите serve.py, затем из web/ выполните npx playwright install chromium и npm run test:e2e. Тесты работают на реальном датасете, создают отдельные неизменяемые запуски и имитируют только сценарии отказа/задержки. Провайдер AI в автотестах не вызывается. Другой адрес сервера: UI_URL=http://127.0.0.1:3001 npm run test:e2e.

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

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

ayan 23Ayan Abilbek 2

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

  • 2026-09-23 17:54Add demo link to READMEAyan Abilbek
  • 2026-09-23 17:53docs: verify clean installation and clarify Python prerequisiteayan
  • 2026-09-23 17:46fix: reduce graph nodes and show GID labels only on selectionayan
  • 2026-09-23 17:42Merge remote-tracking branch 'origin/main'ayan
  • 2026-09-23 17:42docs: document setup and verify submission requirementsayan
  • 2026-09-23 17:40docs: "Diagram"Ayan Abilbek
  • 2026-09-23 17:37style: switch workspace to accessible light theme and finalize UI checksayan
  • 2026-09-23 17:30feat: complete analytical workspace interactions and verify UI contractsayan
Все коммиты (25)
  • 2026-09-23 17:06feat: add real-data Next.js network workspace and immutable API runsayan
  • 2026-09-23 16:44docs: complete final acceptance matrix and clean-environment auditayan
  • 2026-09-23 16:28fix: align priority explanations and harden AI input boundariesayan
  • 2026-09-23 16:11docs: audit implementation against hackathon requirementsayan
  • 2026-09-23 16:01feat: organize analyst workspace and refine responsive UIayan
  • 2026-09-23 15:33feat: add grounded follow-up chat for each nodeayan
  • 2026-09-23 15:03fix: constrain AI brief to verifiable graph evidenceayan
  • 2026-09-23 14:50fix: derive demo period and verify changed inputsayan
  • 2026-09-23 14:41test: verify structured AI brief and fallback in UIayan
  • 2026-09-23 14:26docs: record clean-start demo rehearsalayan
  • 2026-09-23 14:17fix: isolate uploaded analyses and invalidate stale resultsayan
  • 2026-09-23 14:08feat: show daily transfer activity in analyst viewayan
  • 2026-09-23 14:02docs: correct hackathon deadline to 18:00ayan
  • 2026-09-23 13:59fix: keep generated run metadata out of Gitayan
  • 2026-09-23 13:57chore: record clean demo verificationayan
  • 2026-09-23 13:55test: verify brief references and boundary behaviorayan
  • 2026-09-23 13:53feat: establish explainable graph analysis demoayan
Структура репозитория (79 файлов)
.env.example
.gitignore
.streamlit/config.toml
AGENTS.md
README.md
ai_brief.py
ai_chat.py
ai_safety.py
analysis.py
api.py
app.py
assets/network.html
assets/workspace.css
config.json
data/edges.parquet
data/nodes.parquet
data/transactions.parquet
diagram.png
docs/AI_SECURITY.md
docs/CLEAN_INSTALL_CHECK.md
docs/FINAL_CHECK.md
docs/PROJECT_REPORT.md
docs/STATUS.md
docs/UI_IMPLEMENTATION.md
docs/architecture.md
docs/demo.md
graph_view.py
out/clusters.csv
out/nodes_roles.csv
out/top_nodes.csv
pytest.ini
requirements.txt
research.py
run_store.py
serve.py
starter.py
temporal.py
tests/test_ai_safety.py
tests/test_analysis.py
tests/test_api.py
tests/test_app.py
tests/test_brief.py
tests/test_chat.py
tests/test_research.py
tests/test_temporal.py
tests/test_workspace.py
ui.py
web/AGENTS.md
web/CLAUDE.md
web/app/[[...route]]/page.tsx
web/app/api/[...path]/route.ts
web/app/globals.css
web/app/layout.tsx
web/components.json
web/components/app-shell.tsx
web/components/common.tsx
web/components/filters.tsx
web/components/graph-canvas.tsx
web/components/impact-panel.tsx
web/components/inspector.tsx
web/components/node-table.tsx
web/components/pages.tsx
web/components/ui/button.tsx
web/components/ui/dialog.tsx
web/components/ui/resizable.tsx
web/lib/types.ts
web/lib/utils.ts
web/lib/view-state.ts
web/next.config.ts
web/package-lock.json
web/package.json
web/playwright.config.ts
web/postcss.config.mjs
web/tests/contracts.test.ts
web/tests/contrast.test.ts
web/tests/e2e/workspace.spec.ts
web/tsconfig.json
web/vitest.config.ts
workspace.py

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

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

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