AAYMA
RU
Войти

Граф денег

Локальный AML-конвейер: строит направленный граф переводов по 2248 gid, присваивает объяснимые роли…

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

О проекте

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

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

Суть

Локальный AML-конвейер: строит направленный граф переводов по 2248 gid, присваивает объяснимые роли (coordinator/distributor/consolidator/transit/terminal/peripheral), делит сеть на сообщества Louvain и выдаёт ранжированную очередь проверки, 40 CSV и автономный network.html.

Как устроено

run.py проверяет входные Parquet (типы, суммы, совпадение агрегатов с транзакциями) и считает метрики in/out_deg, in/out_kzt, seed_reach (≤4 ребра), bridge (betweenness по 96 источникам, seed=42) и rapid_48h. Роли назначаются упорядоченными правилами с эвристическим role_score. Кластеры находит детерминированный Louvain на ненаправленной проекции с весом sum_kzt. Приоритет считается как взвешенная сумма процентильных рангов × role/boundary/seed-множители, у каждого узла есть разбор вкладов. Дополнительные сигналы (циклы nx.simple_cycles, relay-маршруты, синхронные входы, дробление, суммы у порога, оценка скрытых исходящих у 4-го колена) идут в колонку attention и не меняют роль. AI-ассистент работает поверх graph_tools через любой OpenAI-совместимый endpoint.

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

  • NetworkX
  • Louvain (seed=42)
  • betweenness centrality (sampled)
  • percentile-rank priority score
  • nx.simple_cycles
  • relay route detection
  • resilience test vs random removal
  • LLM assistant with graph tools

Метрики

Пересчёт ~2,5 с на 2248 узлах; изъятие топ-10 оставляет 74% seed-связей (топ-50 — 47%) против 96% при 50 случайных узлах

Особенности

Проверка устойчивости сети показывает, что приоритет действительно находит несущие узлы: удаление топ-N сравнивается с удалением случайных. Эмпирически оценивается вероятность скрытых исходящих у узлов 4-го колена. Около 40 тестов на граничные случаи и побайтовая воспроизводимость CSV при перемешивании входных строк.

Стек

Python · pandas · NetworkX · HTML viewer (JS) · pytest

Модели

OpenAI-compatible LLM endpoint


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

README

README.md

Граф денег

Локальный инструмент для первичной AML-проверки транзакционной сети. По трём обезличенным parquet-файлам он строит направленный граф, присваивает каждому gid объяснимую роль, делит сеть на сообщества и выдаёт ранжированную очередь клиентов для углублённой проверки. Инструмент отвечает на вопрос аналитика «кого из 2 248 клиентов смотреть первым и почему».

Роль и позиция в очереди означают структурную гипотезу для проверки, а не причастность к преступлению.

Содержание

Быстрый старт

Нужен Python 3.10+ и доступ к PyPI при первом запуске. Из корня репозитория:

./run.sh

Скрипт создаёт локальное окружение, устанавливает зависимости из requirements.txt и запускает полный пересчёт. Папка data/ должна содержать nodes.parquet, edges.parquet, transactions.parquet. Другой путь передаётся так: ./run.sh --data /path/to/data --out /path/to/out.

В Windows (PowerShell):

python -m venv .venv
.\.venv\Scripts\python.exe -m pip install -r requirements.txt
.\.venv\Scripts\python.exe run.py

Если окружение .venv уже подготовлено, достаточно последней команды — она работает без интернета.

Что появляется в out/: три обязательные выгрузки nodes_roles.csv, clusters.csv, top_nodes.csv, ещё 37 CSV с опциональными разборами и автономная страница network.html. Полный перечень — в разделе Выгрузки. HTML открывается в браузере как обычный файл, без сервера и интернета.

Производительность. На предоставленных 2 248 узлах прямой расчёт run.py занимает около 2,5 секунды на тестовой машине; установка пакетов в это время не входит. Предел по ТЗ — 5 минут.

Сценарий аналитика

  1. Поместить выгрузку в data/ и запустить ./run.sh.
  2. Открыть out/network.html, найти gid из списка правоохранительных органов или взять узел из топ-листа слева.
  3. Переключиться на один или два шага связей, изучить направление стрелок, суммы и карточку узла. Переключить окраску между ролями и кластерами.
  4. Использовать top_nodes.csv как очередь углублённой проверки; evidence и числовые поля nodes_roles.csv позволяют проверить каждый вывод.
  5. Сверить attention у выбранных узлов и сформировать запрос на недостающие данные по data_gaps.csv.
  6. Уточнить связи вопросом ассистенту: assistant.py "кто собирает деньги с этих пятерых: …".

Как устроено решение

Схема пайплайна

Построение графа

Граф направленный: ребро src → dst означает перевод от отправителя получателю. edges.parquet сверяется с суммами и количеством операций в transactions.parquet. Все узлы из nodes.parquet, включая изолированные seed, остаются в результате.

Проверка входных данных

Обязательные поля не допускают пропусков. Идентификаторы, глубина и число операций должны иметь целочисленный тип, is_seed — булев тип. Суммы должны быть конечными положительными числами; допустимое расхождение агрегата с транзакциями — не более 0,01 KZT на пару. Пустой список узлов отклоняется с сообщением об ошибке. Перед построением графа узлы и рёбра сортируются, поэтому перестановка строк во входных файлах не меняет результат.

Метрики узла

МетрикаСмысл
in_deg, out_degчисло разных плательщиков и получателей
in_kzt, out_kztсуммы, видимые внутри выгрузки
seed_reachиз скольких seed узел достижим по направлению переводов за ≤ 4 ребра
bridgeнормированное посредничество на направленном графе по 96 фиксированным источникам (seed=42)
rapid_48hдоля входящих операций, после которых у того же узла есть исходящая в следующие 48 часов — временной сигнал, не сопоставление конкретных денег

Правила ролей

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

РольУсловие
coordinatorНе seed; seed_reach ≥ 3, in_deg ≥ 3, bridge не ниже 90-го процентиля положительных значений в текущей выгрузке. Кандидат на координирующий узел, не идентификация организатора.
distributorout_deg ≥ 8 и out_deg ≥ 2 × max(in_deg, 1).
consolidatorin_deg ≥ 4 и in_deg ≥ 2 × max(out_deg, 1).
transitНе seed; есть вход и выход, 0.8 ≤ out_kzt / in_kzt ≤ 1.2. Сравнение сумм остаётся приблизительным из-за неполной видимости.
terminalНе seed; in_deg > 0, out_deg = 0, depth < 4. Это только наблюдаемый конечный получатель в границах выборки.
peripheralОстальные узлы, в том числе обрыв на 4-м колене без исходящих.

role_score лежит в диапазоне 0–1 и отражает силу выполнения выбранного правила: базовое значение 0.60 растёт с запасом по числу связей, seed и близостью доли пропуска к единице; для терминалов базовое значение 0.62, для граничной периферии 0.55. Это эвристическая оценка, не калиброванная вероятность. Точные формулы — в score_roles() в run.py.

Для каждого gid поле evidence содержит числа, на которых основана роль, и не превышает 200 символов. Дополнительные колонки nodes_roles.csv позволяют разобрать любой узел за минуту. Например, для граничного узла пояснение прямо говорит, что исходящие после четвёртого колена неизвестны.

Кластеры

Кластеры вычисляются детерминированным Louvain (seed=42) по ненаправленной проекции графа с весом sum_kzt. Направление сохраняется в исходном графе, ролях, метриках и интерфейсе; проекция используется только для поиска плотно связанных групп. Изолированные узлы получают собственный кластер. sum_kzt_internal включает только рёбра, где оба конца в данном кластере. top_gids — пять клиентов кластера с наибольшим приоритетом. hypothesis описывает наблюдаемый характер группы и требует проверки.

Приоритет

Приоритет — взвешенная сумма процентильных рангов в текущей выгрузке:

base = 0.20·P(in_deg) + 0.20·P(in_kzt) + 0.20·P(seed_reach)
     + 0.20·P(bridge) + 0.15·P(out_deg) + 0.05·rapid_48h
priority_score = base × role_factor × boundary_factor × seed_factor

P — процентильный ранг признака; совпадающие значения получают одинаковый ранг.

МножительЗначение
role_factor1 для coordinator/consolidator/distributor; 0,95 для transit; 0,85 для terminal; 0,75 для peripheral
boundary_factor0,65 для узлов четвёртого колена без исходящих; иначе 1
seed_factor0,85 для известных seed; иначе 1

Итог ограничен диапазоном 0–1. Узлы сортируются по убыванию приоритета, при равенстве — по возрастанию gid; в top_nodes.csv попадают первые 100 (минимум по ТЗ — 20). Эти коэффициенты задают очередь проверки, а не оценку вины.

Чтобы приоритет был проверяемым, nodes_roles.csv содержит разбор формулы: priority_base, вклады priority_payers, priority_incoming, priority_seed_reach, priority_bridge, priority_recipients, priority_rapid и множители priority_role_factor, priority_boundary_factor, priority_seed_factor. Те же числа видны в карточке узла в network.html.

Дополнительные сигналы

Эти признаки закрывают опциональные пункты ТЗ. Они не меняют роль и приоритет, а попадают в колонку attention (nodes_roles.csv, top_nodes.csv) и в карточку узла. Так каждый флаг проверяется отдельно и не смешивается с правилами ролей. Если флагов нет, в attention записано нет.

ПризнакКолонкаКак считаетсяФлаг в attention
Возвратные потокиcycles, cycle_with_seedпростые направленные циклы длиной ≤ 4 перевода (nx.simple_cycles); список — в cycles.csv, bottleneck_kzt — минимальная сумма на ребре циклаузел лежит хотя бы на одном цикле
Повторная пересылкаrelay_routes, chain_transitsA→B→C: B отправил C 50–105% входа от A в течение 0–2 дней минимум в 2 разных дня; A→B→C→D связывает два таких эпизодаузел — посредник маршрута или звено цепочки
Всплески активностиtimeline.csvвходящие и исходящие переводы агрегируются по календарному дню и gidпоказываются в карточке узла как самые активные дни
Синхронные входыsync_payers_maxмаксимум разных плательщиков в один календарный день≥ 3
Дроблениеrepeat_amount_maxсколько раз узел отправил одну и ту же сумму≥ 4
Суммы у порогаnear_threshold_inвходящие переводы 5 000–9 999 KZT≥ 3 и не меньше половины входящих
Выброс для колена—in_deg выше 99-го процентиля своего коленапри in_deg ≥ 3
Скрытый выходp_hidden_outgoingсм. ниже≥ 50%: «продлить обход»

Обрыв 4-го колена

Обход раскрывает исходящие всех узлов колен 0–3, поэтому у них p_hidden_outgoing = 0. Для 444 узлов 4-го колена исходящие не выгружались. Их вероятность оценивается эмпирически: какая доля не-seed узлов колен 1–3 с тем же числом плательщиков (1, 2, 3–4, 5+) имеет исходящие. На текущей выгрузке это 29% для одного плательщика, 57% для двух и 73% для 3–4. Так 434 граничных узла с одним плательщиком ближе к настоящим конечным получателям, а 10 узлов с 2+ плательщиками стоит раскрыть дальше в первую очередь. Все граничные узлы остаются peripheral: оценка задаёт очередь дозапроса, а не роль.

Устойчивость сети

resilience.csv сравнивает изъятие топ-N по priority_score с N случайными узлами (seed=42). seed_reach_share — доля пар «seed → узел в пределах 4 переводов», которые остались связаны. На текущей выгрузке изъятие топ-10 оставляет 74% таких пар и 70 связных фрагментов, топ-50 — 47%; 50 случайных узлов — 96%. Значит, приоритет действительно выделяет узлы, на которых держится сеть.

Маршруты пересылки

routes.csv показывает повторные A→B→C и сквозные A→B→C→D цепочки, где суммы и даты похожи на пересылку. Совпадение времени и размера перевода остаётся структурной гипотезой: оно не доказывает, что дальше ушли именно те же деньги.

Белые пятна

data_gaps.csv перечисляет, чего не хватает в выгрузке, сколько узлов это затрагивает и какой запрос сделать следующим: продление обхода от граничных узлов, входящие и межбанковские переводы seed без исходящих, переводы ниже 5 000 KZT для узлов с суммами у порога, источники для узлов, которые отдали больше, чем получили, и для фрагментов вне основной компоненты.

В network.html эти же правила показываются в карточке конкретного узла как короткий список «что запросить дальше». Экспорт Markdown-отчёта включает эти запросы вместе с evidence, attention и заметками аналитика.

AI-ассистент аналитика

Вопрос на естественном языке превращается в ответ по графу со ссылками на gid:

# Один раз задайте адрес внутреннего или локального OpenAI-compatible endpoint:
export OPENAI_BASE_URL=http://127.0.0.1:8000/v1
export OPENAI_MODEL=my-local-model
# export OPENAI_API_KEY=...  # только если внутренний endpoint требует токен

.venv/bin/python assistant.py "Кто собирает деньги с 100000000437046100, 100000000331309100 и 100000008346837100?"
.venv/bin/python assistant.py            # диалог с уточняющими вопросами
.venv/bin/python assistant.py --offline "..."   # без обращения к API

Параметры можно передать и явно: assistant.py --base-url http://127.0.0.1:8000/v1 --model my-local-model "...". Шаблон переменных с примерами для Ollama и LM Studio лежит в .env.example; скопируйте его в .env и примените командой set -a; source .env; set +a. Файл .env в репозиторий не попадает.

Как устроено. Модель за локальным или внутренним OpenAI-compatible Chat Completions API только планирует запросы и пишет ответ. Каждый факт она берёт из детерминированных инструментов graph_tools.py, которые работают на том же графе и тех же ролях, что run.py:

ИнструментЧто возвращает
node_profileроль, место в очереди, метрики, evidence, attention
counterpartiesпрямые плательщики и получатели с суммами
shared_counterpartiesкто получает деньги от нескольких gid (downstream) или платит им (upstream) в пределах N переводов
money_pathsцепочки переводов от одного gid к другому с суммой на каждом шаге
top_nodesочередь приоритетов с фильтром по роли, кластеру, флагам
cluster_summaryразмер, seed, внутренний оборот, роли и лидеры кластера
node_cyclesвозвратные потоки через узел

Системная инструкция требует ссылаться только на данные инструментов, писать gid полностью, формулировать выводы как гипотезы и учитывать ограничения выгрузки. Инструменты выполняются локально и доступны модели как стандартные function tools.

Доступ. OPENAI_BASE_URL обязателен: приложение не подставляет адрес публичного API и не отправляет данные во внешний сервис автоматически. OPENAI_MODEL задаёт имя модели на вашем endpoint. OPENAI_API_KEY необязателен и нужен, только если внутренний шлюз требует авторизацию. Без endpoint, модели или соединения ассистент сообщает об этом и отвечает офлайн: по gid в вопросе выбирает один инструмент (один gid — профиль и связи, несколько — общие получатели или, при словах «кто платит», «откуда», «источник», общие источники; без gid — очередь приоритетов).

Выгрузки

gid — синтетический идентификатор. В интерфейсе он передаётся строкой, чтобы JavaScript не терял точность 64-битного числа. В CSV это целочисленный идентификатор.

Обязательные по ТЗ

ФайлСодержание
nodes_roles.csvОдна строка на каждый входной gid; обязательные поля gid, role, role_score, cluster_id, priority_score, evidence и дополнительные проверяемые метрики.
clusters.csvОдна строка на сообщество: cluster_id, n_nodes, n_seed, sum_kzt_internal, top_gids, hypothesis.
top_nodes.csvОчередь из 100 узлов: rank, gid, role, priority_score, why и attention.

Опциональные пункты ТЗ

ФайлПункт ТЗСодержание
boundary_review.csvучёт артефакта обрываОчередь граничных узлов 4-го колена для продления обхода: gid, входящие связи, сумма, оценка скрытого выхода и следующий запрос.
timeline.csvвременные паттерныДневная активность по каждому gid: входы, выходы, оборот, чистый поток и число уникальных контрагентов за день.
daily_summary.csvвременные паттерныДневная активность всей видимой сети: число операций, сумма, уникальные отправители, получатели и активные узлы.
cycles.csvвозвратные потокиВозвратные потоки: cycle_id, length, path, bottleneck_kzt, n_seed.
cycle_nodes.csvвозвратные потокиНормализованный состав cycles.csv: одна строка на узел цикла с позицией, ролью, кластером и bottleneck-суммой.
routes.csvповторяющиеся маршрутыУстойчивые маршруты пересылки и сквозные цепочки: kind, path, relay_days, forwarded_kzt, даты и число seed.
route_nodes.csvповторяющиеся маршрутыНормализованный состав routes.csv: одна строка на узел маршрута с позицией, ролью, кластером, seed-флагом и priority.
route_edges.csvповторяющиеся маршрутыНормализованные hops из routes.csv: src → dst, позиция, роли, кластеры, видимая сумма и число транзакций ребра.
risk_flags.csvдетекция аномалийСводка флагов внимания: число узлов, доля, смысл и топовые примеры gid.
attention_examples.csvдетекция аномалийДетализация risk_flags.csv: одна строка на пару flag + gid с метрикой, ролью, кластером, evidence и attention.
amount_bands.csvдетекция аномалийРаспределение транзакций по фиксированным диапазонам KZT: число переводов, сумма и доли по количеству и обороту.
resilience.csvустойчивость сетиЧто остаётся от сети после изъятия топ-N узлов по приоритету и N случайных.
data_gaps.csvоценка полнотыБелые пятна выгрузки: gap, n_nodes, meaning, next_request, example_gids.

Оставшиеся два опциональных пункта закрыты не выгрузками, а кодом: AI-ассистент — assistant.py, автогенерация карточки узла — report_node.py и карточка в network.html.

Вспомогательные срезы

Агрегаты поверх выгрузок выше. Нужны для быстрой навигации по сети и разбора на демо; каждый выводится из уже перечисленных файлов.

ФайлСодержание
role_summary.csvСводка по структурным ролям: число узлов, доля сети, seed, граничные узлы, средние скоры, оборот и топовые gid.
role_depths.csvМатрица «роль × колено обхода»: число узлов, доля внутри роли, seed, граничные узлы и топовые gid.
role_flows.csvАгрегированные видимые потоки между структурными ролями src_role → dst_role: сумма, число рёбер и транзакций.
role_attention.csvФлаги внимания по структурным ролям: число уникальных gid, доля внутри роли и топовые примеры.
depth_summary.csvСводка по коленям обхода 0–4: число узлов, seed, граница выборки, оборот, средний приоритет и топовые gid.
depth_flows.csvАгрегированные видимые потоки между коленями обхода src_depth → dst_depth с направлением outward, same_depth или backward.
depth_attention.csvФлаги внимания по коленям обхода: число уникальных gid, доля внутри слоя и топовые примеры.
attention_overlap.csvСовместная встречаемость пар флагов внимания на одних и тех же gid: число узлов и топовые примеры.
cluster_flows.csvМежкластерные потоки: src_cluster, dst_cluster, сумма, число рёбер и транзакций.
cluster_flow_summary.csvСводка по каждому кластеру: внутренний оборот, входящие и исходящие межкластерные суммы, рёбра, транзакции и крупнейшие соседние кластеры.
cluster_roles.csvМатрица «кластер × роль»: число узлов, доля внутри кластера, оборот, средний приоритет и топовые gid.
cluster_depths.csvМатрица «кластер × колено обхода»: число узлов, доля внутри кластера, seed, граничные узлы и топовые gid.
cluster_attention.csvФлаги внимания по кластерам: сколько уникальных gid с каждым флагом, доля внутри кластера и топовые примеры.
seed_coverage.csvПокрытие каждого seed: достижимые узлы за 4 перевода, прямые получатели, прямой исходящий поток и кластер.
seed_components.csvКомпонента каждого seed: размер фрагмента, число seed в нём, внутренний оборот, рёбра, кластер и охват за 4 перевода.
seed_role_reach.csvДля каждого seed: сколько достижимых за 4 перевода узлов попадает в каждую структурную роль, плюс граничные и флаговые узлы.
seed_overlap.csvПары seed, которые достигают одних и тех же видимых узлов за 4 перевода: размер пересечения, доли охвата и топовые общие gid.
seed_attention.csvФлаги внимания внутри достижимой зоны каждого seed за 4 перевода: число узлов, доля охвата и топовые примеры.
components.csvСлабосвязные фрагменты сети: размер, seed, внутренний оборот, число рёбер, топовые gid и признак главной компоненты.
component_roles.csvМатрица «компонента × роль»: число узлов, доля внутри компоненты, seed, граничные узлы и топовые gid.
component_attention.csvФлаги внимания по слабосвязным компонентам: число уникальных gid, доля внутри компоненты и топовые примеры.
isolated_nodes.csvУзлы без видимых входящих и исходящих рёбер: gid, seed-флаг, роль, кластер, компонента, приоритет и объяснение.
top_edges.csvДо 200 крупнейших видимых пар src → dst с суммой, числом операций, ролями и кластерами обоих концов.
top_counterparties.csvДо трёх крупнейших входящих и исходящих прямых контрагентов для каждого gid, с ролью и кластером контрагента.

Экран просмотра

network.html — самодостаточная страница: поиск по gid, стрелки направления переводов, фильтры по кластеру, роли, флагам, seed, границе обхода и приоритету, окраска ролей и кластеров, топ-лист, карточки узлов, route explorer с подсветкой маршрутов и циклов, карточка выбранного кластера, локальная рабочая подборка с заметками, поиск общих источников и получателей, список недостающих данных и экспорт Markdown-отчёта аналитика.

Инструменты командной строки

СкриптНазначение
run.pyПолный пересчёт: от сырых parquet до всех выгрузок и network.html. Запускается через ./run.sh.
assistant.pyВопросы к графу на естественном языке; работает офлайн без LLM-endpoint.
report_node.py <gid>Карточка одного узла в терминале: роль, потоки, связи, на что обратить внимание.
demo.py --out outГенерирует сценарий пятиминутного показа из текущих выгрузок.
compare_outputs.py old newСравнивает два пересчёта: изменения статуса узла, роли, кластера, флагов и priority_score.
check_viewer.py out/network.htmlПроверяет, что HTML самодостаточен и payload собран корректно.
audit_explainability.pyПроверяет объяснимость случайно выбранных топ-узлов.
graph_tools.pyБиблиотека детерминированных запросов к графу; используется ассистентом, отдельно не запускается.

Ограничения интерпретации

  • Граф построен только по исходящим переводам от seed на четыре колена. 444 узла на 4-м колене без исходящих не считаются terminal: это артефакт границы обхода; p_hidden_outgoing лишь оценивает вероятность продолжения. У других узлов также могут быть невидимые связи за рамками выгрузки.
  • Цикл, маршрут пересылки, синхронность и повтор суммы — структурные совпадения. Они не доказывают, что по цепочке прошли одни и те же деньги.
  • Входящие seed из-за пределов выборки не видны. Для seed не применяется правило транзита по отношению out_kzt / in_kzt. Нельзя считать это отношение полным балансом и для остальных узлов.
  • Переводы ниже 5 000 KZT и операции в других банках отсутствуют. Временной признак не доказывает прохождение одних и тех же средств.
  • Клиентских атрибутов и размеченных истинных ролей нет. Числовые пороги и веса являются проверяемыми эвристиками; качество оценивается аналитиком по подтверждённым внешним данным.

Проверка

69 тестов в 38 файлах покрывают схемы выгрузок, правила ролей, воспроизводимость при перестановке входных строк и граничные случаи инструментов ассистента:

.venv/bin/python -m unittest discover -s tests -v

В Windows: .\.venv\Scripts\python.exe -m unittest discover -s tests -v.

ПроверкаКоманда
Интерфейс: переключение кластеров и фильтры (нужен Node.js)node tests/test_viewer.cjs
Самодостаточность HTML payload.venv/bin/python check_viewer.py out/network.html
Объяснимость случайных топ-узлов.venv/bin/python audit_explainability.py --out out --sample 10
Карточка одного узла.venv/bin/python report_node.py <gid>
Сравнение двух пересчётов.venv/bin/python compare_outputs.py old_out new_out --out out_compare.csv

Повторный запуск run.py на тех же данных даёт побайтово идентичные выгрузки: все случайные процедуры зафиксированы (seed=42), суммы округляются до тиынов.

Демо на 5 минут

Готовый сценарий, собранный из текущих выгрузок:

.venv/bin/python demo.py --out out

Порядок показа: за первую минуту запуск и выгрузки; затем топ-1 в HTML с объяснением плательщиков, охвата seed и посредничества; поиск произвольного gid из зала с показом входящих и исходящих связей; граничный gid (boundary=True) и объяснение, почему ему не присвоен terminal. Завершение — кластер с несколькими seed и его гипотеза, затем resilience.csv (изъятие топ-10 против случайных) и data_gaps.csv как план следующего запроса.

При росте до миллиона узлов

Parquet читать по частям через Polars или DuckDB, хранить агрегаты в колонночном формате и строить сжатое представление смежности. Louvain и посредничество переносить в igraph/graph-tool или распределённый графовый движок; посредничество считать на выборке с заданной погрешностью. Сохранять рассчитанные метрики по батчам и обновлять затронутые компоненты. В браузер отдавать только выбранный кластер или окрестность gid, а не миллион узлов сразу. Пороги ролей и формулу ранжирования можно сохранить, но их нужно заново проверить на распределении признаков крупной сети.

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

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

Aruzhan Myrzakhmetova 63Alibek Tugel 52Alibek Tugel 43Ruslan Sibgatulin 11Ruslan 4Ruslan Sibgatulin 4

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

  • 2026-09-23 16:45Merge pull request #78 from BAITC-Hacks/docs/readme-refreshRuslan
  • 2026-09-23 16:43docs: restructure README by topicRuslan Sibgatulin
  • 2026-09-23 16:40docs: add jury summary and refresh stale README claimsRuslan Sibgatulin
  • 2026-09-23 16:32Merge pull request #77 from BAITC-Hacks/feat/route-edgesAlibek Tugel
  • 2026-09-23 16:30feat: summarize seed attention reachAlibek Tugel
  • 2026-09-23 16:29feat: summarize cluster flow exposureAlibek Tugel
  • 2026-09-23 16:28feat: export route edge membershipAlibek Tugel
  • 2026-09-23 16:27Merge pull request #76 from BAITC-Hacks/test/latest-main-30Aruzhan Myrzakhmetova
Все коммиты (177)
  • 2026-09-23 16:27Merge pull request #75 from BAITC-Hacks/test/latest-main-28Aruzhan Myrzakhmetova
  • 2026-09-23 16:26feat: summarize seed attention reachAlibek Tugel
  • 2026-09-23 16:26Merge pull request #74 from BAITC-Hacks/test/latest-main-27Aruzhan Myrzakhmetova
  • 2026-09-23 16:26Merge pull request #73 from BAITC-Hacks/test/latest-main-22Aruzhan Myrzakhmetova
  • 2026-09-23 16:25Merge pull request #72 from BAITC-Hacks/test/latest-main-23Aruzhan Myrzakhmetova
  • 2026-09-23 16:24feat: summarize cluster flow exposureAlibek Tugel
  • 2026-09-23 16:24Merge pull request #71 from BAITC-Hacks/test/latest-main-25Aruzhan Myrzakhmetova
  • 2026-09-23 16:24Merge pull request #70 from BAITC-Hacks/test/latest-main-24Aruzhan Myrzakhmetova
  • 2026-09-23 16:23Merge pull request #69 from BAITC-Hacks/test/latest-main-26Aruzhan Myrzakhmetova
  • 2026-09-23 16:22Merge pull request #68 from BAITC-Hacks/test/latest-main-31Aruzhan Myrzakhmetova
  • 2026-09-23 16:21Merge pull request #66 from BAITC-Hacks/test/latest-main-29Aruzhan Myrzakhmetova
  • 2026-09-23 16:21Merge pull request #67 from BAITC-Hacks/feat/attention-overlapAlibek Tugel
  • 2026-09-23 16:21Merge pull request #65 from BAITC-Hacks/feat/depth-attentionAlibek Tugel
  • 2026-09-23 16:21Merge pull request #64 from BAITC-Hacks/feat/role-attentionAlibek Tugel
  • 2026-09-23 16:20feat: report attention flag overlapAlibek Tugel
  • 2026-09-23 16:18feat: summarize attention by depthAlibek Tugel
  • 2026-09-23 16:17feat: summarize attention by roleAlibek Tugel
  • 2026-09-23 16:17Merge pull request #63 from BAITC-Hacks/feat/seed-overlapAlibek Tugel
  • 2026-09-23 16:16Merge pull request #62 from BAITC-Hacks/feat/depth-flowsAlibek Tugel
  • 2026-09-23 16:16Test transaction count mismatch with matching amountsaruzhanmm
  • 2026-09-23 16:16Test rejection of duplicate aggregated edgesaruzhanmm
  • 2026-09-23 16:16Test priority change threshold in both directionsaruzhanmm
  • 2026-09-23 16:16Test attention mapping by weak componentaruzhanmm
  • 2026-09-23 16:16Test isolated node filtering and seed priorityaruzhanmm
  • 2026-09-23 16:16Test resilience removal limits on small graphsaruzhanmm
  • 2026-09-23 16:16Test seed component footprint and directed reacharuzhanmm
  • 2026-09-23 16:16Test component role shares and equal-size orderingaruzhanmm
  • 2026-09-23 16:16Test cluster attention counts across flagsaruzhanmm
  • 2026-09-23 16:16Test role depth shares and orderingaruzhanmm
  • 2026-09-23 16:16feat: report seed overlapAlibek Tugel
  • 2026-09-23 16:16feat: summarize depth flowsAlibek Tugel
  • 2026-09-23 16:15Merge pull request #61 from BAITC-Hacks/feat/role-flowsAlibek Tugel
  • 2026-09-23 16:09Merge pull request #51 from BAITC-Hacks/test/latest-main-12Aruzhan Myrzakhmetova
  • 2026-09-23 16:08Merge pull request #52 from BAITC-Hacks/test/latest-main-13Aruzhan Myrzakhmetova
  • 2026-09-23 16:08Merge pull request #53 from BAITC-Hacks/test/latest-main-14Aruzhan Myrzakhmetova
  • 2026-09-23 16:08Merge pull request #54 from BAITC-Hacks/test/latest-main-15Aruzhan Myrzakhmetova
  • 2026-09-23 16:07Merge pull request #55 from BAITC-Hacks/test/latest-main-16Aruzhan Myrzakhmetova
  • 2026-09-23 16:06Merge pull request #56 from BAITC-Hacks/test/latest-main-17Aruzhan Myrzakhmetova
  • 2026-09-23 16:06Merge pull request #57 from BAITC-Hacks/test/latest-main-18Aruzhan Myrzakhmetova
  • 2026-09-23 16:06Merge pull request #58 from BAITC-Hacks/test/latest-main-19Aruzhan Myrzakhmetova
  • 2026-09-23 16:05Merge pull request #59 from BAITC-Hacks/test/latest-main-20Aruzhan Myrzakhmetova
  • 2026-09-23 16:05Merge pull request #60 from BAITC-Hacks/test/latest-main-21Aruzhan Myrzakhmetova
  • 2026-09-23 15:58feat: summarize role flowsAlibek Tugel
  • 2026-09-23 15:55Merge pull request #50 from BAITC-Hacks/feat/isolated-nodes-reportAlibek Tugel
  • 2026-09-23 15:55Merge pull request #49 from BAITC-Hacks/feat/component-attention-summaryAlibek Tugel
  • 2026-09-23 15:54feat: report isolated nodesAlibek Tugel
  • 2026-09-23 15:54Merge pull request #48 from BAITC-Hacks/feat/component-role-matrixAlibek Tugel
  • 2026-09-23 15:53Test counterparty limits per node and directionaruzhanmm
  • 2026-09-23 15:53Test per-cluster depth sharesaruzhanmm
  • 2026-09-23 15:53Test depth summary totals and boundary countsaruzhanmm
  • 2026-09-23 15:53Test cycle closure and self-loop membershiparuzhanmm
  • 2026-09-23 15:53Test route positions and large node identifiersaruzhanmm
  • 2026-09-23 15:53Test seed role reach without duplicate descendantsaruzhanmm
  • 2026-09-23 15:53Test cluster role shares and tied leadersaruzhanmm
  • 2026-09-23 15:53Test boundary review ordering and filteringaruzhanmm
  • 2026-09-23 15:53Test exact transaction amount band boundariesaruzhanmm
  • 2026-09-23 15:53Test daily active-node deduplicationaruzhanmm
  • 2026-09-23 15:53feat: summarize component attention flagsAlibek Tugel
  • 2026-09-23 15:51feat: summarize component rolesAlibek Tugel
  • 2026-09-23 15:48Merge pull request #47 from BAITC-Hacks/feat/cluster-attention-summaryAlibek Tugel
  • 2026-09-23 15:47feat: summarize cluster attention flagsAlibek Tugel
  • 2026-09-23 15:46Merge pull request #46 from BAITC-Hacks/feat/role-depth-matrixAlibek Tugel
  • 2026-09-23 15:46Merge pull request #45 from BAITC-Hacks/feat/seed-componentsAlibek Tugel
  • 2026-09-23 15:46feat: summarize role depthsAlibek Tugel
  • 2026-09-23 15:44Merge pull request #44 from BAITC-Hacks/test/latest-main-11Aruzhan Myrzakhmetova
  • 2026-09-23 15:44feat: map seeds to componentsAlibek Tugel
  • 2026-09-23 15:44Merge pull request #43 from BAITC-Hacks/feat/top-counterpartiesAlibek Tugel
  • 2026-09-23 15:44Merge pull request #42 from BAITC-Hacks/feat/cluster-depth-matrixAlibek Tugel
  • 2026-09-23 15:43Merge pull request #41 from BAITC-Hacks/feat/depth-summaryAlibek Tugel
  • 2026-09-23 15:43Merge pull request #40 from BAITC-Hacks/test/latest-main-10Aruzhan Myrzakhmetova
  • 2026-09-23 15:42feat: export top direct counterpartiesAlibek Tugel
  • 2026-09-23 15:41Test seed coverage direction and four-hop limitaruzhanmm
  • 2026-09-23 15:41Test directed cross-cluster flow aggregationaruzhanmm
  • 2026-09-23 15:41feat: summarize cluster depthsAlibek Tugel
  • 2026-09-23 15:40feat: summarize traversal depthsAlibek Tugel
  • 2026-09-23 15:39feat: summarize seed reach by roleAlibek Tugel
  • 2026-09-23 15:39feat: export route node membershipAlibek Tugel
  • 2026-09-23 15:39feat: export cycle node membershipAlibek Tugel
  • 2026-09-23 15:39feat: export attention flag examplesAlibek Tugel
  • 2026-09-23 15:35Merge pull request #39 from BAITC-Hacks/test/latest-main-9Aruzhan Myrzakhmetova
  • 2026-09-23 15:34Merge pull request #38 from BAITC-Hacks/test/latest-main-8Alibek Tugel
  • 2026-09-23 15:34Merge pull request #37 from BAITC-Hacks/feat/cluster-role-matrixAlibek Tugel
  • 2026-09-23 15:33feat: summarize daily network activityAlibek Tugel
  • 2026-09-23 15:33feat: summarize roles by clusterAlibek Tugel
  • 2026-09-23 15:33feat: queue boundary nodes for reviewAlibek Tugel
  • 2026-09-23 15:32Test directed endpoint metadata in top edgesaruzhanmm
  • 2026-09-23 15:32Test stable top edge ranking and row limitaruzhanmm
  • 2026-09-23 15:28Merge pull request #36 from BAITC-Hacks/feat/top-edges-summaryAlibek Tugel
  • 2026-09-23 15:27Merge pull request #35 from BAITC-Hacks/test/latest-main-7Aruzhan Myrzakhmetova
  • 2026-09-23 15:27feat: summarize top transfer edgesAlibek Tugel
  • 2026-09-23 15:27Merge pull request #34 from BAITC-Hacks/feat/role-summaryAlibek Tugel
  • 2026-09-23 15:27Merge pull request #33 from BAITC-Hacks/feat/amount-band-summaryAlibek Tugel
  • 2026-09-23 15:27Merge pull request #32 from BAITC-Hacks/test/latest-main-6Aruzhan Myrzakhmetova
  • 2026-09-23 15:26feat: summarize assigned rolesAlibek Tugel
  • 2026-09-23 15:25feat: summarize transaction amount bandsAlibek Tugel
  • 2026-09-23 15:25Merge pull request #31 from BAITC-Hacks/feat/component-summaryAlibek Tugel
  • 2026-09-23 15:24Merge pull request #30 from BAITC-Hacks/feat/seed-coverage-reportAlibek Tugel
  • 2026-09-23 15:23feat: summarize graph componentsAlibek Tugel
  • 2026-09-23 15:23Test report CLI error for unknown gidaruzhanmm
  • 2026-09-23 15:23Test report CLI with explicit data path outside repositoryaruzhanmm
  • 2026-09-23 15:21feat: report seed coverageAlibek Tugel
  • 2026-09-23 15:20Merge pull request #29 from BAITC-Hacks/feat/viewer-path-highlightsAlibek Tugel
  • 2026-09-23 15:19feat: highlight routes and cycles in viewerAlibek Tugel
  • 2026-09-23 15:19Merge pull request #28 from BAITC-Hacks/feat/node-report-cliAlibek Tugel
  • 2026-09-23 15:18Merge pull request #27 from BAITC-Hacks/test/latest-main-5Aruzhan Myrzakhmetova
  • 2026-09-23 15:18feat: add node report CLIAlibek Tugel
  • 2026-09-23 15:18Merge pull request #26 from BAITC-Hacks/feat/explainability-auditAlibek Tugel
  • 2026-09-23 15:17Merge pull request #25 from BAITC-Hacks/test/latest-main-4Aruzhan Myrzakhmetova
  • 2026-09-23 15:17feat: add explainability auditAlibek Tugel
  • 2026-09-23 15:17Merge pull request #24 from BAITC-Hacks/feat/viewer-self-checkAlibek Tugel
  • 2026-09-23 15:17Merge pull request #23 from BAITC-Hacks/feat/demo-scriptAlibek Tugel
  • 2026-09-23 15:16Merge pull request #22 from BAITC-Hacks/feat/cluster-flowsAlibek Tugel
  • 2026-09-23 15:16feat: add viewer payload self checkAlibek Tugel
  • 2026-09-23 15:16Merge pull request #21 from BAITC-Hacks/feat/risk-flags-summaryAlibek Tugel
  • 2026-09-23 15:16feat: add demo scriptAlibek Tugel
  • 2026-09-23 15:15feat: summarize cluster ingress and egressAlibek Tugel
  • 2026-09-23 15:15Test four-transfer cycle detection limitaruzhanmm
  • 2026-09-23 15:15Test daily unique counterparties with repeated transfersaruzhanmm
  • 2026-09-23 15:14feat: summarize risk flagsAlibek Tugel
  • 2026-09-23 15:13feat: find shared counterparties in viewerAlibek Tugel
  • 2026-09-23 15:13Merge pull request #20 from BAITC-Hacks/feat/viewer-route-explorerAlibek Tugel
  • 2026-09-23 15:12feat: show forwarding routes in viewerAlibek Tugel
  • 2026-09-23 15:11Merge pull request #19 from BAITC-Hacks/feat/stable-route-signalsAlibek Tugel
  • 2026-09-23 15:11feat: detect stable forwarding routesAlibek Tugel
  • 2026-09-23 15:09Merge pull request #18 from BAITC-Hacks/test/latest-main-3Aruzhan Myrzakhmetova
  • 2026-09-23 15:08Test priority filter boundaries and clearing hidden selectionsaruzhanmm
  • 2026-09-23 15:08Merge pull request #17 from BAITC-Hacks/feat/output-compareAlibek Tugel
  • 2026-09-23 15:08Merge pull request #16 from BAITC-Hacks/feat/data-request-generatorAlibek Tugel
  • 2026-09-23 15:07feat: compare pipeline output snapshotsAlibek Tugel
  • 2026-09-23 15:07Merge pull request #15 from BAITC-Hacks/feat/report-exportAlibek Tugel
  • 2026-09-23 15:07Merge pull request #13 from BAITC-Hacks/fix/tool-edge-casesRuslan
  • 2026-09-23 15:07Merge pull request #14 from BAITC-Hacks/feat/case-workspaceAlibek Tugel
  • 2026-09-23 15:06feat: generate next data requestsAlibek Tugel
  • 2026-09-23 15:06Merge pull request #12 from BAITC-Hacks/feat/cluster-cardAlibek Tugel
  • 2026-09-23 15:06fix: honest truncation and input validation in graph toolsRuslan Sibgatulin
  • 2026-09-23 15:05feat: export analyst markdown reportAlibek Tugel
  • 2026-09-23 15:05feat: add local case workspaceAlibek Tugel
  • 2026-09-23 15:04feat: show selected cluster summaryAlibek Tugel
  • 2026-09-23 15:03Merge pull request #11 from BAITC-Hacks/feat/viewer-filtersAlibek Tugel
  • 2026-09-23 15:03feat: add viewer filtersAlibek Tugel
  • 2026-09-23 15:02Merge pull request #10 from BAITC-Hacks/feat/priority-breakdownAlibek Tugel
  • 2026-09-23 15:02feat: explain priority score breakdownAlibek Tugel
  • 2026-09-23 15:02Merge pull request #9 from BAITC-Hacks/feat/node-timelineAlibek Tugel
  • 2026-09-23 15:01feat: add node activity timelineAlibek Tugel
  • 2026-09-23 14:55Merge pull request #8 from BAITC-Hacks/feat/openai-compatible-llmRuslan
  • 2026-09-23 14:54chore: add .env.example for the LLM endpoint settingsRuslan Sibgatulin
  • 2026-09-23 14:52Merge pull request #7 from BAITC-Hacks/test/latest-main-2Aruzhan Myrzakhmetova
  • 2026-09-23 14:51feat: switch assistant to any OpenAI-compatible endpointRuslan Sibgatulin
  • 2026-09-23 14:49Test rapid transfer signal at 48-hour boundariesaruzhanmm
  • 2026-09-23 14:38Merge pull request #6 from BAITC-Hacks/test/latest-mainAruzhan Myrzakhmetova
  • 2026-09-23 14:36Merge pull request #5 from BAITC-Hacks/feat/ai-assistantAlibek Tugel
  • 2026-09-23 14:36Test output reproducibility after shuffling input rowsaruzhanmm
  • 2026-09-23 14:33feat: add AI analyst assistant grounded in graph toolsAlibek Tugel
  • 2026-09-23 14:31Merge pull request #4 from BAITC-Hacks/fix/deterministic-kztRuslan
  • 2026-09-23 14:30Merge branch 'main' into fix/deterministic-kztRuslan Sibgatulin
  • 2026-09-23 14:28fix: round KZT sums to tiyn so CSV output is byte-stable across runsRuslan Sibgatulin
  • 2026-09-23 14:28Merge pull request #3 from BAITC-Hacks/feature/validation-testsAlibek Tugel
  • 2026-09-23 14:26Merge latest main and adapt regression tests to extended pipelinearuzhanmm
  • 2026-09-23 14:19Merge pull request #1 from BAITC-Hacks/feat/tz-extrasAlibek Tugel
  • 2026-09-23 14:18feat: add risk signals, resilience check, and data gap reportAlibek Tugel
  • 2026-09-23 14:13Fix input validation and cluster filtering with regression testsaruzhanmm
  • 2026-09-23 13:59chore: add supplied dataset and starter kitRuslan Sibgatulin
  • 2026-09-23 13:59feat: build explainable graph pipeline and local viewerRuslan Sibgatulin
  • 2026-09-23 13:59test: add validated CSV exports and pipeline checksRuslan Sibgatulin
  • 2026-09-23 13:59docs: explain workflow, role rules, and architectureRuslan Sibgatulin
  • 2026-09-23 13:47feat: build explainable graph pipeline and local viewerRuslan Sibgatulin
  • 2026-09-23 13:47test: add validated CSV exports and pipeline checksRuslan Sibgatulin
  • 2026-09-23 13:47docs: explain workflow, role rules, and architectureRuslan Sibgatulin
  • 2026-09-23 13:47chore: add supplied dataset and starter kitRuslan Sibgatulin
Структура репозитория (100 файлов)
.env.example
.gitignore
README.md
architecture.svg
assistant.py
audit_explainability.py
check_viewer.py
compare_outputs.py
data/edges.parquet
data/nodes.parquet
data/transactions.parquet
demo.py
graph_tools.py
out/amount_bands.csv
out/attention_examples.csv
out/attention_overlap.csv
out/boundary_review.csv
out/cluster_attention.csv
out/cluster_depths.csv
out/cluster_flow_summary.csv
out/cluster_flows.csv
out/cluster_roles.csv
out/clusters.csv
out/component_attention.csv
out/component_roles.csv
out/components.csv
out/cycle_nodes.csv
out/cycles.csv
out/daily_summary.csv
out/data_gaps.csv
out/depth_attention.csv
out/depth_flows.csv
out/depth_summary.csv
out/isolated_nodes.csv
out/nodes_roles.csv
out/resilience.csv
out/risk_flags.csv
out/role_attention.csv
out/role_depths.csv
out/role_flows.csv
out/role_summary.csv
out/route_edges.csv
out/route_nodes.csv
out/routes.csv
out/seed_attention.csv
out/seed_components.csv
out/seed_coverage.csv
out/seed_overlap.csv
out/seed_role_reach.csv
out/timeline.csv
out/top_counterparties.csv
out/top_edges.csv
out/top_nodes.csv
report_node.py
requirements.txt
run.py
run.sh
starter/README.md
starter/requirements.txt
starter/starter.py
tests/test_amount_band_boundaries.py
tests/test_assistant.py
tests/test_boundary_review_order.py
tests/test_check_viewer.py
tests/test_cluster_attention_flags.py
tests/test_cluster_depth_shares.py
tests/test_cluster_flow_direction.py
tests/test_cluster_role_shares.py
tests/test_compare_outputs.py
tests/test_compare_priority_threshold.py
tests/test_component_attention_mapping.py
tests/test_component_role_ties.py
tests/test_counterparty_direction_limits.py
tests/test_cycle_limits.py
tests/test_cycle_membership_closure.py
tests/test_daily_active_nodes.py
tests/test_demo.py
tests/test_depth_summary_totals.py
tests/test_duplicate_aggregated_edges.py
tests/test_explainability_audit.py
tests/test_features.py
tests/test_graph_tools_edges.py
tests/test_isolated_node_order.py
tests/test_pipeline.py
tests/test_report_cli_errors.py
tests/test_report_cli_paths.py
tests/test_report_node.py
tests/test_resilience_small_graph.py
tests/test_role_depth_denominators.py
tests/test_route_membership_positions.py
tests/test_seed_component_footprint.py
tests/test_seed_coverage_limits.py
tests/test_seed_role_deduplication.py
tests/test_timeline_counterparties.py
tests/test_top_edges_metadata.py
tests/test_top_edges_ranking.py
tests/test_transaction_count_mismatch.py
tests/test_validation.py
tests/test_viewer.cjs
viewer.html
Ветки (59)

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

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

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