О проекте
Команда: BrokySpace
Кейс HackAlem.ai: Финансы — Freedom
Стадия: Доведённый продукт
Задача кейса: «Граф денег»: восстановить структуру организованной группы по сети транзакций (AML)
Суть
Объяснимый AML-пайплайн и Streamlit-дашборд: направленный граф переводов, роли узлов (consolidator, distributor, transit, terminal, coordinator), приоритет проверки, Louvain-сообщества и помощник аналитика.
Как устроено
Из nodes/edges/transactions.parquet строится взвешенный направленный граф. Считаются flow-признаки, PageRank, HITS, betweenness и близость к seed. Временные признаки: задержка пересылки через merge_asof, всплески, синхронные входы; отдельно ищутся циклы, повторяющиеся цепочки и дробление. Пять формульных role scores строятся на percentile-рангах: ниже 0.38 узел считается peripheral, для узлов, усечённых на depth=4, terminal score штрафуется. priority_score — взвешенная сумма структурной важности, роли, связи с seed и аномальности. Louvain работает на неориентированной проекции, evidence до 200 символов содержит фактические числа. Выход: nodes_roles.csv, clusters.csv, top_nodes.csv и Streamlit-дашборд из 9 вкладок с опциональным OpenAI-режимом помощника.
Ключевые решения
- NetworkX
- PageRank
- HITS
- betweenness
- Louvain
- merge_asof
- поиск циклов
- детекция дробления
- percentile ranks
- формульные role scores
Особенности
Формулы ролей прозрачны и опубликованы. Учтено усечение обхода на depth=4: terminal×0.35 с предупреждением в evidence. role_score и priority_score разделены, вес оборота ограничен, чтобы крупные клиенты не вытесняли структурно значимые узлы. Модуль «белых пятен» подсказывает аналитику следующий запрос данных.
Стек
Python · pandas · NetworkX · Streamlit · Parquet · pytest · GitHub Actions
Модели
OpenAI API (опционально)
Проект создан за 5 часов на финале хакатона HackAlem.ai (23 сентября 2026, Астана). Код — BAITC-Hacks/hack-31599fbc-brokyspace.
README
README.mdMoneyGraph — аналитика финансовой сети
Локальный, воспроизводимый и объяснимый инструмент восстановления финансовой структуры организованной группы по транзакционной сети. Решение строит направленный граф движения денег, назначает функциональные роли всем узлам, ранжирует их для AML-проверки, выделяет сообщества и формирует доказательную базу в понятной аналитику форме.
1. Задача и решение
Оборот сам по себе редко показывает, кто управляет сетью. Координатор может переводить меньше денег, но связывать критические части графа; узел на границе четырёх шагов может выглядеть терминальным только из-за усечения выборки. Поэтому решение сочетает направленные потоки, центральности, связь с seed, временное поведение и структуру сообществ. Black-box классификатор не используется: каждая роль и позиция в рейтинге выводятся из формальных признаков.
2. Архитектура
data/*.parquet
→ src/data.py чтение, приведение схемы, проверки
→ src/graph.py directed weighted graph
→ src/features.py flow + PageRank/HITS/betweenness/seed
→ src/temporal.py forwarding + bursts + synchronous inflows
→ src/patterns.py cycles + recurring edges/chains + structuring + anomalies
→ src/clustering.py Louvain и межкластерные мосты
→ src/roles.py пять role scores + peripheral
→ src/priority.py AML priority score
→ src/evidence.py объяснения с фактическими числами
→ src/completeness.py белые пятна + следующий запрос аналитику
→ src/agent.py read-only AI AML analyst
→ src/validation.py контракт выходных данных
→ out/* CSV, parquet, metadata
→ app.py Streamlit dashboard
3. Quick Start
Требуется Python 3.10+.
python -m venv .venv
# Windows: .venv\Scripts\activate
# Linux/macOS: source .venv/bin/activate
pip install -r requirements.txt
python run_pipeline.py --data ./data --out ./out
streamlit run app.py
Полный pipeline выполняется одной командой. Код возврата ненулевой при нарушении контракта. Для набора другого размера проверку 2248 можно изменить через --expected-nodes N или отключить значением 0.
Если командная строка неудобна, можно сразу открыть streamlit run app.py: при отсутствии результатов стартовый экран предложит загрузить три parquet-файла и запустить pipeline одной кнопкой. Обработка остаётся локальной.
Проверка решения:
pytest -q
python evaluate_solution.py --out ./out
OpenAI-режим AI-аналитика опционален и не нужен локальному evidence-agent. Для постоянной серверной настройки задайте OPENAI_API_KEY в окружении или создайте локальный файл .streamlit/secrets.toml:
OPENAI_API_KEY = "[скрыто]"
.streamlit/secrets.toml исключён из Git. При наличии серверного ключа он не передаётся в браузер и не отображается в интерфейсе; ручной password-ввод остаётся резервным вариантом только для текущей сессии. Перед каждым запросом пользователь отдельно подтверждает передачу вопроса и минимального аналитического контекста в OpenAI API.
4. Входные данные
В data/ должны находиться:
nodes.parquet: уникальныйgid, а такжеdepthиis_seed;edges.parquet:source,target,sum_kzt, опциональноn_tx;transactions.parquet:source,target, сумма и timestamp.
Загрузчик понимает распространённые эквиваленты (src/dst, sender_gid/receiver_gid, amount_kzt, transaction_date и др.), но после чтения приводит всё к единой схеме. Проверяются уникальность GID, ссылки на существующие узлы, типы и неотрицательность сумм. Если timestamps отсутствуют, temporal-признаки честно принимают нулевые значения, а не имитируются.
5. Pipeline
Последовательность: load → validate → graph → network features → temporal features → Louvain → role scores → cluster importance → priority → evidence → validation → export. В консоли печатается короткий EDA, время каждого этапа и общий runtime; подробности сохраняются в out/metadata.json.
6. Feature engineering
На направленном графе вычисляются in/out_degree, in/out_kzt, in/out_tx, PageRank, betweenness, HITS hub/authority, weak component, расстояние/близость к seed, число соседей и непосредственных источников-seed. pass_through = min(in_kzt,out_kzt)/max(in_kzt,out_kzt) лежит в [0,1].
Для основных величин используются percentile ranks. Они сохраняют относительную редкость сигнала при тяжёлых хвостах денежных распределений и устойчивее абсолютных порогов при смене периода или размера сети. Например, in_deg_pct=0.99 означает, что узел превосходит 99% сети по числу входящих контрагентов.
7. Temporal analysis
По транзакциям считаются активные входящие/исходящие дни, медианная задержка между наблюдаемым входом и следующим исходящим событием, доля перенаправлений до 24/48 часов, всплеск дневной активности и синхронная консолидация от трёх и более разных плательщиков за день. Поиск предыдущего входа сделан через merge_asof, без квадратичного сопоставления транзакций.
temporal_anomaly_score объединяет percentile всплеска, rapid forwarding, синхронные входы, сигналы дробления, повторяющиеся связи/цепочки и циклы. depth_peer_anomaly_score сравнивает профиль узла с клиентами того же колена, а итоговый aml_anomaly_score объединяет обе оценки. Это приоритизация для расследования, а не вероятность нарушения.
8. Методология ролей
Для каждого узла независимо считаются пять scores в [0,1], затем выбирается самый сильный. Если максимум меньше 0.38, узел относится к peripheral. В формулах P(x) — percentile, R — observed retention, B — наличие входа и выхода, S — seed connectivity, X — bridge score:
consolidator = .20P(in_deg)+.18P(in_kzt)+.16P(authority)+.14P(seed_sources)+.10fan_in+.10R+.12sync
distributor = .27P(out_deg)+.20P(out_tx)+.18P(hub)+.18fan_out+.10P(out_kzt)+.07S
transit = .27B+.30pass_through+.18P(rapid)+.12same_next_day+.13(1-R)
terminal = [.26P(in_kzt)+.18P(in_deg)+.24no_out+.20R+.12(1-P(out_kzt))] × has_input
coordinator = .29P(betweenness)+.17P(PageRank)+.12max(P(hub),P(authority))+.22X+.12S+.08P(degree)
role_score — сила соответствия выбранной роли, не риск и не вероятность преступления. Для seed баланс вход/выход ненадёжен из-за неполного входящего контекста: их transit score считается отдельно без обычного pass-through.
9. Ограничение depth=4
Комбинация depth == max(depth) и out_degree == 0 помечается truncated_by_depth. Она означает границу обхода, а не доказанную остановку средств. Поэтому terminal score такого узла умножается на 0.35, а evidence предупреждает об усечении.
10. Priority scoring
priority_score отвечает на другой вопрос: насколько важно проверить узел AML-аналитику.
.28 structural importance + .18 non-peripheral role strength
+.16 seed connectivity + .14 AML anomaly
+.09 cluster importance + .08 transaction volume
+.04 cycle strength + .03 recurring edge/chain strength
Структура включает betweenness, PageRank, bridge и HITS. Денежный объём ограничен весом 10%, поэтому крупнейшие клиенты не вытесняют структурно значимые узлы.
11. Кластеризация
Louvain применяется к взвешенной неориентированной проекции, где встречные потоки суммируются по sum_kzt. Community detection ищет плотные группы связности, тогда как flow features, роли и транзитная логика остаются направленными. Для каждого кластера рассчитываются размер, seed, внутренний оборот, TOP GID и детерминированная hypothesis.
12. Explainability
Каждый evidence непустой, не длиннее 200 символов и содержит фактические числа: контрагентов, суммы, percentile, долю перенаправления или межкластерные связи. Это краткая причина назначения роли, а не шаблон «высокий score».
13. Выходные схемы
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; hypothesis формулирует предполагаемую функцию группы и явно требует проверки аналитиком.
out/top_nodes.csv: rank, gid, role, priority_score, why; минимум 20 строк, убывание priority.
Дополнительно создаются node_features.parquet, graph_edges.parquet, resilience.csv, cycles.csv, recurring_routes.csv, recurring_chains.csv, synchronous_inflows.csv, structuring_events.csv, anomalies.csv, completeness.csv и metadata.json; они питают dashboard и аудит расчётов. Три обязательные CSV хранятся в репозитории, остальные воспроизводятся pipeline и публикуются как CI artifact.
14. Dashboard и demo-сценарий
Dashboard рассчитан на пятиминутную демонстрацию:
Интерфейс имеет полноценные режимы «Светлая», «Тёмная» и «Системная». Выбор хранится в URL-параметре theme и st.session_state, поэтому переживает rerun, обновление страницы и навигацию назад/вперёд; системный режим следует теме браузера, доступной через st.context.theme. Все карточки, формы, загрузчик, таблицы, графики и canvas сети получают цвета из единого набора токенов. Главный экран содержит нативную CSS 3D-анимацию банка и переводов; она отключается при prefers-reduced-motion. Дизайн-токены описаны в UI system.
- «Обзор»: KPI, маршруты переводов, роли, структурная значимость и устойчивость сети.
- «Очередь»: TOP-20/50, объяснения и экспорт CSV.
- «Клиенты»: карточка GID с потоками, ролью и evidence.
- «Карта переводов»: высокий риск, окрестность клиента или группа; стрелки показывают направление денег.
- «Группы»: исходные клиенты, оборот, роли, hypothesis и экспорт CSV.
- «Сигналы»: cycles, recurring edges/chains, синхронные входы, дробление и depth-peer anomalies.
- «Помощник»: локальный grounded-разбор или явно включаемый OpenAI-режим.
- «Документы»: загрузка, просмотр, поиск, скачивание, повторная обработка и подтверждённое удаление.
- «О методике»: ограничения данных и отсутствие ground truth.
Помощник аналитика
Вкладка «Помощник» непосредственно отвечает на главный вопрос кейса: «кого из 2248 клиентов смотреть первым и почему?». Локальный режим детерминированно формирует ответ из pipeline artifacts. Опциональный режим OpenAI Agents SDK использует read-only function tools для рейтинга, карточки GID, группы, паттернов и поиска по документам дела. Он включается только после явного согласия на передачу минимального контекста в API.
Документы дела
На вкладке «Документы» можно добавить .pdf, .docx, .txt, .md, .csv, .json, .xlsx, .xls и .parquet размером до 15 MB. Система:
- безопасно нормализует имя, извлекает текст и хранит оригинал локально в
case_documents/; - проверяет расширение, MIME-тип, структуру файла и выводит понятную русскую ошибку;
- исключает дубликаты по SHA-256, ведёт реестр и полнотекстовый поиск с фрагментами;
- позволяет открыть извлечённый текст, скачать оригинал, повторить обработку и удалить документ с подтверждением;
- сопоставляет упомянутые 12–20-значные GID только с клиентами текущего графа;
- отдаёт найденные фрагменты AI-аналитику как явно помеченный непроверенный контекст;
- не изменяет роли, признаки, кластеры и
priority_scoreна основании текста документов.
Папка case_documents/ исключена из Git. Локальный агент не передаёт файлы наружу. В OpenAI-режиме API может получить только найденный текстовый фрагмент и только после явного согласия пользователя; инструкции внутри загруженных документов считаются недоверенными данными.
15. Автоматическая валидация
Перед экспортом проверяются число узлов, обязательные поля и отсутствие null, уникальность gid, допустимые роли, диапазоны scores, evidence/cluster, схема и непустота кластеров, размер и сортировка TOP. Ошибка прерывает pipeline до выдачи внешне корректных, но логически неверных CSV.
pytest повторно запускает pipeline на официальных parquet и проверяет must-have, ограничения depth/seed, bonus outputs и grounding локального агента. GitHub Actions выполняет тот же сценарий в чистом Python 3.12 окружении и сохраняет результаты как CI artifact. Связанные материалы: архитектура, demo-script, матрица критериев.
16. Bonus: AML patterns и network resilience
Из графа последовательно удаляются TOP-5/10/20 узлов по priority. resilience.csv показывает число weak components, размер/долю крупнейшей компоненты и fragmentation. График доступен на обзорной странице dashboard.
Также реализованы:
- направленные циклы длиной 2–6 с bottleneck-суммой, наличием seed и
cycle_score; - recurring edges и устойчивые цепочки A→B→C, наблюдаемые в несколько дней, с cadence regularity;
- rapid transit по задержке до 24/48 часов;
- синхронные входы от трёх и более плательщиков за день;
- explainable structuring-сигналы по нескольким контрагентам, сходным, округлённым или близким к порогу суммам;
- аномальные профили относительно узлов того же
depth; - temporal/AML anomalies по всем перечисленным сигналам.
Порог recurring edges/chains определяется 75-м percentile среди многодневных паттернов, а список anomalies — 95-м percentile composite score. Сигналы дробления видят только операции, прошедшие порог выгрузки 5 000 KZT, и не утверждают наличие нарушения. Результаты доступны на вкладке «AML-паттерны».
17. Оценка полноты и следующий запрос
completeness.csv содержит строку на каждый GID: completeness_score, наблюдаемые белые пятна и конкретный recommended_request. Оценка снижает полноту для seed с неполным входом, узлов на границе depth=4, наблюдаемого дисбаланса и отсутствующих timestamps. В базовые ограничения включены невидимые межбанковские потоки, операции ниже 5 000 KZT, KYC и остатки. Карточка GID и AI-аналитик показывают, какие данные запросить следующими.
18. Ограничения
- выборка ограничена четырьмя поколениями обхода;
- наблюдение преимущественно outgoing и входы seed неполны;
- роли без ground truth являются проверяемыми аналитическими гипотезами;
- отсутствие timestamps снижает силу temporal-части;
- PageRank и HITS отражают только наблюдаемую сеть.
19. Масштабирование до ~1 млн узлов
Текущая NetworkX-реализация оптимальна для локального кейса на 2248 узлах. Для миллиона узлов контракт и формулы сохраняются, но exact betweenness заменяется sampling approximation, граф переводится в igraph/graph-tool или Spark GraphFrames, parquet обрабатывается Polars/DuckDB, Louvain — пакетным Leiden/Louvain, а dashboard читает агрегаты и заранее подготовленные ego-графы. Расчёт остаётся explainable; меняется только backend.
#ВЫПОЛНИЛИ: АБДИЕВ ЕРАСЫЛ,ӘСІЛ ЕРАСЫЛ,БЕЙБОСЫНОВ БЕКСҰЛТАН
Авторы коммитов
История коммитов
- 2026-09-23 17:46Revise scaling approach for large node networksErasyl010205
- 2026-09-23 17:33Add files via uploadErasyl010205
- 2026-09-23 17:38Restore MoneyGraph project structure and Streamlit appYilin1207
- 2026-09-23 17:34Add files via uploadBeksultan651
- 2026-09-23 17:33Add files via uploadYilin1207
- 2026-09-23 17:30Remove all project filesYilin1207
- 2026-09-23 17:26Finalize adaptive UI and document workflowYilin1207
- 2026-09-23 16:46Redesign dashboard as minimal banking productYilin1207
Все коммиты (15)
- 2026-09-23 15:37Add local case document ingestion and searchYilin1207
- 2026-09-23 15:27Redesign dashboard with premium adaptive themesYilin1207
- 2026-09-23 15:17Complete AML bonus analytics and submission artifactsYilin1207
- 2026-09-23 14:59Support persistent server-side OpenAI API keyYilin1207
- 2026-09-23 14:46Add grounded AML analyst agent and quality gatesYilin1207
- 2026-09-23 14:19Add cycle and recurring-route AML detectionYilin1207
- 2026-09-23 14:13Build explainable AML graph analytics pipelineYilin1207
Структура репозитория (41 файлов)
.github/workflows/ci.yml .gitignore .streamlit/secrets.toml.example README.md app.py data/edges.parquet data/nodes.parquet data/transactions.parquet docs/ARCHITECTURE.md docs/DEMO.md docs/RUBRIC.md docs/UI.md evaluate_solution.py out/clusters.csv out/nodes_roles.csv out/top_nodes.csv pytest.ini requirements.txt run_pipeline.py src/__init__.py src/agent.py src/clustering.py src/completeness.py src/data.py src/documents.py src/evidence.py src/features.py src/graph.py src/patterns.py src/pipeline.py src/priority.py src/resilience.py src/roles.py src/temporal.py src/ui.py src/validation.py tests/conftest.py tests/test_agent.py tests/test_app.py tests/test_documents.py tests/test_pipeline.py
Обсуждение 0 комментариев
Войдите, чтобы комментироватьПока нет комментариев — будьте первым.