AAYMA
RU
Войти

Lense

Локальное рабочее место аналитика «Граф денег».

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

О проекте

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

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

Суть

Локальное рабочее место аналитика «Граф денег». Граф переводов, гипотезы ролей (консолидация, транзит, распределение, координатор), ранжированный топ с объяснениями и сценарий удаления узлов.

Как устроено

Пайплайн проверяет три Parquet и сверяет глубину узлов с кратчайшим путём от seed. На NetworkX считаются PageRank, точное посредничество и Louvain с разделением несвязных сообществ. Временные признаки: синхронные поступления, всплески, повторяющиеся маршруты A→B→C, циклы длины 2–3, группы одинаковых сумм. Роли и приоритет задаются явными правилами, деньги считаются в целых тиынах. Результат — nodes_roles.csv, clusters.csv, top_nodes.csv, graph.json и манифест с SHA-256; интерфейс рисует граф на Canvas.

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

  • NetworkX
  • PageRank
  • betweenness centrality
  • Louvain
  • cycle detection
  • node removal (network disruption) analysis
  • rule-based roles

Особенности

Сценарий удаления топ-N узлов показывает, как меняется связность сети: компоненты, изоляты, крупнейшая группа. Результаты публикуются атомарно, с контрольными суммами. Узлы на границе четвёртого колена отмечаются как обрыв наблюдения.

Стек

Python 3.14 · http.server · pandas · NumPy · SciPy · PyArrow · NetworkX · JavaScript · Canvas 2D


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

README

README.md

Граф денег — Lense

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

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

Роли и приоритеты — гипотезы для проверки. Они не устанавливают виновность, управление другими клиентами или происхождение конкретных денежных средств.

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

  • Загрузка и проверка трёх Parquet. Сверяются схемы, идентификаторы, суммы, агрегаты операций и глубины от исходных клиентов. Необязательный список gid проверяется на совпадение с is_seed.
  • Граф переводов. Направления и объёмы потоков, цвета ролей, раскладка по коленам или кластерам, поиск полного gid, фильтры и просмотр соседей выбранного узла.
  • Гипотеза роли каждого клиента. Консолидация, транзит, распределение, получатель, периферия / граница; отдельно выделяется структурная роль «связующий узел» (coordinator).
  • Приоритеты с объяснениями. Полный ранжированный список и экспорт топ-20. На главном экране выделены кандидаты с признаками консолидации. Поддержка гипотезы роли показана отдельно от приоритета проверки.
  • Временные и структурные признаки. Сопоставление сумм поступлений и расходов, активность по дням, синхронные поступления, всплески, повторяющиеся маршруты A → B → C, циклы длины 2–3, группы одинаковых сумм и необычные профили относительно своего колена.
  • Сценарий удаления узлов. Сравнение связности сети до и после удаления топ-N или выбранных клиентов: число компонент и изолятов, крупнейшая группа, оставшийся объём связей.
  • Карточки и список «На проверку». Потоки, контрагенты, операции, основания роли и ранга, ограничения наблюдения и предлагаемые запросы данных. Выбранный список сохраняется в браузере; справки выгружаются в Markdown и CSV.
  • Проверенные файлы результатов. Три CSV, граф в JSON и манифест с параметрами и контрольными суммами. CLI публикует комплект атомарно; ошибка новой загрузки в интерфейсе сохраняет прежний расчёт.

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

  1. Аналитик открывает набор из data/ либо загружает nodes.parquet, edges.parquet и transactions.parquet через кнопку «Загрузить выгрузку». При необходимости вставляет список исходных клиентов для сверки.
  2. Пайплайн проверяет входы и строит направленный граф. Глубина каждого узла сверяется с кратчайшим направленным путём от любого исходного клиента.
  3. Рассчитываются метрики, связные сообщества, временные признаки, роли и приоритеты. Денежные правила работают с целыми тиынами. Для текущего графа посредничество рассчитывается точно.
  4. Аналитик изучает граф и приоритеты, открывает карточки и сопоставляет объяснения с операциями. Узлы на границе четвёртого колена отмечаются с учётом обрыва наблюдения.
  5. Аналитик добавляет клиентов в «На проверку» и скачивает справку с фактами, ограничениями и рекомендациями по следующему запросу данных. Отправку запроса и решение о проверке выполняет сам аналитик.

Технологии

КомпонентРеализация
Язык и локальный серверPython 3.14, стандартный http.server.ThreadingHTTPServer
Граф и сообществаNetworkX: направленный граф, PageRank, посредничество, Louvain с последующим разделением несвязных сообществ
Таблицы и вычисленияpandas, NumPy, SciPy
Чтение ParquetPyArrow
ИнтерфейсHTML, CSS, JavaScript ES-модули, Canvas 2D; без frontend-фреймворка и обязательной npm-сборки
Форматы результатаCSV, JSON, Markdown; SHA-256 для контроля входов и комплекта результатов
Проверкиunittest, Ruff, mypy для публичных контрактов; workflow GitHub Actions для macOS и Ubuntu

Закреплённые версии — в requirements.txt и requirements-dev.txt.

Обученные AI/ML-модели и LLM не используются. Роли, объяснения и дополнительные признаки строятся по явным правилам и графовым метрикам. Внешние API, облачные вычисления и API-ключи для работы приложения не нужны. После установки зависимостей интерфейс получает ресурсы и данные с локального сервера, без CDN.

Архитектура проекта

flowchart LR
    P["Три Parquet"] --> V["Контракты и проверка входов"]
    V --> A["Граф, признаки, сообщества, роли и приоритеты"]
    A --> R["AnalysisResult"]
    R --> S["Storage: CSV, JSON, manifest"]
    R --> W["Web API и дополнительные признаки"]
    W --> U["Lense в локальном браузере"]
ЧастьОтветственность
hackalem/cli.py, pipeline.py, contracts.pyКоманды, последовательность расчёта, конфигурация и единый AnalysisResult
hackalem/input_contracts.py, validation.pyПроверка исходных данных и согласованности результатов
hackalem/features.py, temporal.py, communities.pyСтруктурные и временные признаки, связные кластеры
hackalem/rules.py, ranking.pyПравила ролей, факты для объяснений, приоритет и топ
hackalem/web.py, insights.pyЛокальный HTTP API, загрузка, карточки, паттерны и сценарии удаления
hackalem/storage.py, output_store.pyВалидация, версии и публикация файлов
web/Интерфейс и отрисовка графа на Canvas
tests/, experiments/, docs/Проверки, воспроизводимые эксперименты и подробная документация

Интерфейс и CLI используют один расчётный пайплайн. Дополнительные паттерны помогают интерпретации, но автоматически не меняют основную роль или приоритет. Браузерные запросы привязаны к версии набора: смена выгрузки в другой вкладке не смешивает старую таблицу с новой карточкой.

Установка и запуск

Нужны CPython 3.14 и современный браузер. Локальная установка проверена на macOS; команды ниже используют POSIX-пути. Файл .python-version указывает версию, но сам Python не устанавливает.

1. Откройте корень проекта

Это папка с README.md, requirements.txt, hackalem/, web/ и data/. Все следующие команды выполняются из неё, а не из starter/.

python3.14 --version

2. Создайте окружение и установите зависимости

python3.14 -m venv .venv
.venv/bin/python -m pip install -r requirements.txt
.venv/bin/python -m pip check

Если .venv уже создано на Python 3.14, повторно создавать его не нужно. Прямой вызов .venv/bin/python не требует активации окружения.

3. Запустите интерфейс

.venv/bin/python -m hackalem serve --data data --profile hackalem-july-2026 --port 8765

Дождитесь сообщения Локальный интерфейс: http://127.0.0.1:8765 и откройте http://127.0.0.1:8765. Сервер слушает только локальный адрес. Для остановки нажмите Ctrl+C в терминале. Если порт занят, задайте, например, --port 8766 и откройте соответствующий адрес.

При старте читается папка data/. Если файлы отсутствуют, интерфейс предлагает загрузить три Parquet. Профиль hackalem-july-2026 действует и на последующие загрузки: даты должны относиться к июлю 2026 года, каждая операция — составлять не менее 5 000 KZT. Для других периодов предусмотрен --profile generic; проверки структуры, сумм и глубин сохраняются.

Расчёт без интерфейса

.venv/bin/python -m hackalem analyze --data data --out out --profile hackalem-july-2026
.venv/bin/python -m hackalem validate --data data --out out --profile hackalem-july-2026
.venv/bin/python -m hackalem export --source out --destination reports/portable-result

Первая команда создаёт весь комплект, вторая проверяет его, третья копирует проверенную версию в обычную переносимую папку. Для первого расчёта out должен отсутствовать; ранее созданный программой комплект можно обновить. Выход не должен пересекаться с входными данными. Для export укажите новый, ещё не существующий путь назначения.

ФайлСодержание
nodes_roles.csvВсе клиенты, роли, признаки, оценки и объяснения
clusters.csvРазмеры, обороты, приоритетные участники и гипотезы кластеров
top_nodes.csvТоп-20 по приоритету с основаниями
graph.jsonГраф и признаки; идентификаторы сохранены строками
manifest.jsonКонфигурация и SHA-256 входов и результатов

Те же файлы доступны через кнопку «Экспорт» в интерфейсе. При открытии CSV в табличном редакторе импортируйте gid как текст, чтобы сохранить все цифры.

Прежняя точка входа сохранена: .venv/bin/python starter/starter.py --data data --out out.

Как проверить решение: сценарий для жюри

Используйте три файла из data/ и параметры запуска выше. На текущем наборе ожидаются:

ПоказательЗначение
Исходные клиенты (seed)81
Всего клиентов2 248
Направленные связи3 119
Операции4 840
Сумма операций, каждую считаем один раз365 890 012,01 KZT
Связные кластеры89
Клиенты с гипотезой консолидации87
Строки в top_nodes.csv20

Это результаты текущих файлов и закреплённой конфигурации, а не оценка точности выявления нарушений. В интерфейсе денежная сводка округлена до 365,9 млн ₸.

  1. Откройте «Обзор сети» и сравните сводные показатели с таблицей. Переключите граф между связями выбранного клиента и всей сетью, затем попробуйте раскладку по кластерам.
  2. Найдите полный gid 100000003701161100. В карточке должны быть признаки консолидации, 4 плательщика, 3 получателя и приоритет около 92,9 / 100. Получено 1 527 103 KZT, отправлено 349 000 KZT — около 22,9% наблюдаемого входа. Карточка показывает округлённые суммы; операции и справка позволяют проверить их подробнее.
  3. Откройте «Операции» и «Что запросить дальше». Добавьте клиента в проверку, перейдите в «На проверку» и скачайте справку: она должна содержать тот же gid, основания и ограничения.
  4. В разделе «Приоритеты» включите отбор консолидации. В «Паттернах» откройте маршрут или цикл и посмотрите факты и оговорки. В «Устойчивости» рассчитайте удаление топ-5 и сравните показатели до и после.
  5. Через «Загрузить выгрузку» выберите все три исходных Parquet. Дождитесь успешного расчёта и проверьте, что показатели сохранились. Для проверки ошибки можно повторить загрузку, указав только 123 в списке seed: программа должна сообщить о несовпадении и сохранить предыдущий результат.
  6. Выполните CLI-команды analyze и validate из раздела выше. Валидатор должен сообщить, что проверка готовых выгрузок пройдена; в out/ должны быть пять перечисленных файлов.

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

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

Проверяются денежные границы, глубины, FIFO, связность кластеров, целостность CSV/JSON, ошибки публикации, паттерны, API, загрузка и версии данных. Настройка Ruff, mypy и команды разработки описаны в docs/development.md. Workflow CI настроен для macOS и Ubuntu; наличие конфигурации не означает, что удалённый прогон уже завершился успешно.

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

Источник расчёта — локальные обезличенные файлы data/. Входная схема:

ФайлСтолбцы
nodes.parquetgid, depth, is_seed
edges.parquetsrc, dst, sum_kzt, n_tx, depth
transactions.parquetsrc, dst, date, sum_kzt

Период текущих операций — 1–31 июля 2026 года. Распределение клиентов по глубине 0 / 1 / 2 / 3 / 4: 81 / 472 / 462 / 789 / 444. Дальнейшие связи исследуются по направлению исходящих переводов от seed; полнота входящих потоков исходных клиентов не предполагается.

gid, src и dst во входных Parquet должны быть точными int64; суммы — положительными, не более двух десятичных знаков. Узлы и агрегированные пары уникальны, концы рёбер известны, агрегаты согласованы с транзакциями. В браузерном API идентификаторы и целые денежные суммы в тиынах передаются строками. Подробности — в контрактах данных.

Интеграция интерфейса с Python выполнена через локальный HTTP API: /api/bootstrap, /api/nodes/<gid>, /api/analyze, /api/jobs/<job_id>, /api/resilience, /api/export и /api/download/<filename>. Контракты запросов описаны в документации API.

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

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

  • Неполная наблюдаемость. Выборка ограничена периодом, исходными клиентами и четырьмя коленами. Начальные остатки, внешние счета и операции вне выгрузки неизвестны. Отсутствие исходящих связей на четвёртом колене не подтверждает конечного получателя.
  • Нет точного порядка внутри дня. FIFO сопоставляет доступные суммы предыдущих дней, расходуя каждое поступление один раз. Операции одного дня отмечаются как неопределённые. Совпадение сумм или наличие цикла не доказывает движение тех же денег.
  • Эвристики без размеченной выборки. Поддержка роли не является вероятностью нарушения, а приоритет задаёт порядок изучения. В репозитории нет оценки качества по размеченным расследованиям и измерения экономии времени аналитика. Самопереводы не увеличивают сетевой приоритет.
  • Границы вычислений. При превышении 5 000 узлов или 50 000 рёбер число источников ограничивается 256; если это все узлы графа, расчёт остаётся точным. Поиск паттернов и выдача примеров ограничены; фокусный граф показывает до 180 узлов. Интерфейс сообщает об усечении. Полный перечень порогов — в методике.
  • Сценарий удаления — структурный. Новые маршруты и изменение поведения клиентов не моделируются; объём удалённых связей нельзя интерпретировать как предотвращённый ущерб.
  • Лимиты входа. Браузер принимает до 64 МиБ трёх файлов суммарно, до 20 000 узлов, 200 000 рёбер и 1 000 000 операций; предел распакованного размера по метаданным Parquet — 512 МиБ. Для формирования обязательного топ-20 нужен набор минимум из 20 клиентов. Эти лимиты не гарантируют одинаковую скорость на любых графах.
  • Локальная сессия. Новый загруженный набор хранится в памяти до перезапуска сервера; исходный data/ не изменяется. Список проверки хранится в localStorage отдельно для каждого набора. Нет учётных записей, разграничения прав и общего хранилища дел; сервер предназначен для локальной работы.
  • Платформы. Локальная проверка описана для macOS. Матрица CI содержит Ubuntu и macOS, но успешный удалённый прогон здесь не заявлен. Публикация файлов использует POSIX-механизмы; работа в Windows не подтверждена.

Демо и публикация

Подтверждённой ссылки на публично развёрнутую версию приложения в проекте нет. Рабочий вариант запускается локально: http://127.0.0.1:8765 после команды serve.

Визуальный референс Lense использован при адаптации интерфейса. Это ссылка на исходный макет, а не подтверждение публикации текущего Python-приложения и его расчётов.

Подробная документация

  • Методика: правила, точность сумм, полнота наблюдения, паттерны и контракты хранения.
  • Разработка: архитектурные границы, API, окружение, проверки и совместимость CLI.
  • Эксперименты: измерения производительности, аудит и сравнение Louvain/Leiden. Leiden остаётся экспериментом и не используется в основном расчёте.
Звёзды
⭐ 1
Форки
0
Язык
Python
Последний push
в прошлом месяце
Коммиты
14
Авторы
2
Файлы
68
Ветки
4

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

Ramazan Anarbekov 11Nurzhigit 3

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

  • 2026-09-23 17:56New READMERamazan Anarbekov
  • 2026-09-23 17:55README finalNurzhigit
  • 2026-09-23 17:48Merge pull request #4 from BAITC-Hacks/From_Parquet_to_3CSVRamazan Anarbekov
  • 2026-09-23 17:47New Web InterfaceRamazan Anarbekov
  • 2026-09-23 16:49Merge pull request #3 from BAITC-Hacks/From_Parquet_to_3CSVRamazan Anarbekov
  • 2026-09-23 16:48Упорядочил локальный проект.Ramazan Anarbekov
  • 2026-09-23 16:43Add standalone Lense AML interface demoNurzhigit
  • 2026-09-23 16:29Merge pull request #2 from BAITC-Hacks/From_Parquet_to_3CSVRamazan Anarbekov
Все коммиты (14)
  • 2026-09-23 16:27fix: исправлена точность анализа и надёжность публикации результатовRamazan Anarbekov
  • 2026-09-23 15:48Merge pull request #1 from BAITC-Hacks/From_Parquet_to_3CSVRamazan Anarbekov
  • 2026-09-23 15:46fix: уточнить аналитику и сделать публикацию результатов атомарнойRamazan Anarbekov
  • 2026-09-23 15:25Add offline analyst interface, exact GID search and validated top-50 pipelineNurzhigit
  • 2026-09-23 14:37Исправлена валидация данных и выгрузок, учёт изолированных узлов и точность ID; закреплены зависимости и добавлены тестыRamazan Anarbekov
  • 2026-09-23 13:34Стартовые условияRamazan Anarbekov
Структура репозитория (68 файлов)
README.md
data/edges.parquet
data/nodes.parquet
data/transactions.parquet
docs/development.md
docs/experiments.md
docs/methodology.md
experiments/audit_acceptance.py
experiments/benchmark_pipeline.py
experiments/compare_communities.py
experiments/results/audit-after.json
experiments/results/benchmark-results.json
hackalem/__init__.py
hackalem/__main__.py
hackalem/analysis.py
hackalem/cli.py
hackalem/communities.py
hackalem/contracts.py
hackalem/features.py
hackalem/input_contracts.py
hackalem/output_store.py
hackalem/pipeline.py
hackalem/ranking.py
hackalem/rules.py
hackalem/storage.py
hackalem/teaching.py
hackalem/temporal.py
hackalem/validation.py
pyproject.toml
reports/archive/hackalem-fixes.patch
requirements-dev.txt
requirements.txt
starter/.DS_Store
starter/.out-previous-98d12eb0a6e44a4680917cdc4887beca/clusters.csv
starter/.out-previous-98d12eb0a6e44a4680917cdc4887beca/graph.json
starter/.out-previous-98d12eb0a6e44a4680917cdc4887beca/nodes_roles.csv
starter/.out-previous-98d12eb0a6e44a4680917cdc4887beca/top_nodes.csv
starter/.out-version-cmb1mmu5/clusters.csv
starter/.out-version-cmb1mmu5/graph.json
starter/.out-version-cmb1mmu5/manifest.json
starter/.out-version-cmb1mmu5/nodes_roles.csv
starter/.out-version-cmb1mmu5/top_nodes.csv
starter/.out-version-xfpmhsrh/clusters.csv
starter/.out-version-xfpmhsrh/graph.json
starter/.out-version-xfpmhsrh/nodes_roles.csv
starter/.out-version-xfpmhsrh/top_nodes.csv
starter/out-check.MqHpS5/clusters.csv
starter/out-check.MqHpS5/graph.json
starter/out-check.MqHpS5/nodes_roles.csv
starter/out-check.MqHpS5/top_nodes.csv
starter/out/clusters.csv
starter/out/graph.json
starter/out/manifest.json
starter/out/nodes_roles.csv
starter/out/top_nodes.csv
starter/starter.py
tests/test_analysis.py
tests/test_communities.py
tests/test_contracts.py
tests/test_input_audit.py
tests/test_money_rules.py
tests/test_review_regressions.py
tests/test_storage_audit.py
web/app.js
web/favicon.svg
web/graph.js
web/index.html
web/styles.css
Ветки (4)

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

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

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