О проекте
Команда: DilyaLiya
Кейс HackAlem.ai: Финансы — Freedom
Стадия: Доведённый продукт
Задача кейса: «Граф денег»: восстановить структуру организованной группы по сети транзакций (AML)
Суть
Офлайн-инструмент AML-аналитика: по трём Parquet считает роли, сообщества и приоритеты, собирает автономный graph.html с интерактивной схемой, карточками узлов, путями от seed и запросами недостающих данных. Встроен локальный LLM-агент на Qwen3-1.7B.
Как устроено
Пайплайн на Python (load, metrics, roles, clustering, ranking, temporal, analytics) выдаёт обязательные CSV, метрики, временные совпадения, чувствительность рейтинга и отчёты валидации примерно за 2 секунды на CPU. Результат встраивается в самодостаточный graph.html. Режим --serve пересобирает его при изменениях. LLM-агент на Qwen3-1.7B Q8_0 через llama.cpp (только CPU, localhost) строит план, выбирает среди 8 Python-инструментов (метрики, соседи, общие получатели, пути, кластеры, паттерны) и ссылается на факты E1/E2. Неизвестные gid и выдуманные ссылки отклоняются, лимит 6 шагов и 150 секунд.
Ключевые решения
- community detection
- rule-based roles
- temporal pattern matching
- ranking sensitivity
- top-N removal
- llama.cpp
- tool-using agent with evidence refs
- offline vendored wheels
Особенности
Полностью офлайн: вендоренные wheel-пакеты под несколько ОС, локальный LLM на CPU с проверкой SHA-256. Агент ограничен планом и ссылками на результаты инструментов, итоговый текст собирается из фактов. Помимо ролей генерируются запросы на недостающие данные.
Стек
Python · Parquet · JavaScript · HTML/CSS · Docker
Модели
Qwen3-1.7B Q8_0 (llama.cpp)
Проект создан за 5 часов на финале хакатона HackAlem.ai (23 сентября 2026, Астана). Код — BAITC-Hacks/hack-a63fd407-dilyaliya.
README
README.mdAML — объяснимый анализ графа переводов
Инструмент для AML-аналитика: из трёх Parquet строит роли, сообщества и приоритеты проверки, затем показывает операции, цепочки, ограничения наблюдения и следующий запрос данных. Только исходная обезличенная выборка, CPU, локальный Python; внешние клиентские атрибуты не добавляются. Роли и scores — гипотезы, не выводы о виновности.
Открывайте output/graph.html, а не app/template.html: шаблон не содержит собранных данных и оформления. Для LLM-помощника нужен локальный сервер (--serve); само нажатие на ссылку его не запускает.
Подготовка на любой ОС
Скопируйте весь проект, включая data/ и vendor/, но без .venv/. При переносе через GitHub сначала отправьте актуальные изменения, затем клонируйте или скачайте репозиторий. starter/ — исходный каркас организаторов с незаполненными ролями; запускайте решение из корня, а не starter/starter.py.
Установите 64-битный CPython 3.11 для своего процессора. Python в комплект проекта не входит. Офлайн-пакеты включены для macOS 12+ Intel/Apple Silicon, Windows x64 и Linux x86-64/ARM64 с glibc ≥2.17. Установщик создаёт .venv и использует --no-index: при наличии Python и полного vendor/ интернет не нужен. Нативные Windows ARM, 32-битные ОС, Alpine/musl и другие версии Python этим комплектом не поддерживаются.
Ниже замените пример пути на папку, где находится README.md и run_pipeline.py. Все команды запуска выполняются из этой папки. Активация .venv вручную не требуется.
Запуск на macOS
Откройте Terminal. Убедитесь, что установлен CPython 3.11 для Intel или Apple Silicon, затем выполните:
cd "/путь/к/hackalem"
python3.11 --version
sh run.sh --serve
Последняя команда устанавливает локальные зависимости при необходимости, выполняет весь расчёт и запускает сайт. Откройте http://127.0.0.1:8765/graph.html. Терминал должен оставаться открытым; остановка — Ctrl+C.
Только пересчёт без сервера: sh run.sh. Диагностика: python3.11 launch.py --doctor. Если порт занят: sh run.sh --serve --port 8766, затем откройте порт 8766.
Запуск на Windows
Установите CPython 3.11 x64 вместе с Python Launcher (py). Откройте PowerShell в папке проекта:
Set-Location "C:\путь\к\hackalem"
py -3.11 --version
.\run.bat --serve
Откройте http://127.0.0.1:8765/graph.html. Остановить сервер — Ctrl+C. В обычном cmd вместо Set-Location используйте cd /d "C:\путь\к\hackalem"; команда .\run.bat --serve та же.
Только пересчёт: .\run.bat. Диагностика: py -3.11 launch.py --doctor. Другой порт: .\run.bat --serve --port 8766. Если py не найден, но команда python --version показывает 3.11, можно выполнить python launch.py --serve.
Запуск на Linux
Нужны CPython 3.11, модули venv и ensurepip, а также glibc ≥2.17; процессор — x86-64 или ARM64. В дистрибутивах, где venv поставляется отдельно, установите пакет venv именно для своего Python 3.11 до запуска проекта. Откройте терминал:
cd "/путь/к/hackalem"
python3.11 --version
python3.11 -c "import venv, ensurepip"
sh run.sh --serve
Откройте http://127.0.0.1:8765/graph.html. Остановить сервер — Ctrl+C.
Только пересчёт: sh run.sh. Диагностика: python3.11 launch.py --doctor. Другой порт: sh run.sh --serve --port 8766. В Alpine/musl используйте подготовленный Docker-вариант или отдельно совместимое окружение — включённые manylinux-пакеты для него не подходят.
Результаты запуска и типичные проблемы
После расчёта файлы находятся в output/: обязательные nodes_roles.csv, clusters.csv, top_nodes.csv, а также graph.html, метрики и отчёты. Единая точка входа — launch.py; --data, --out, --top используются только для пакетного режима без --serve. Например: python3.11 launch.py --data data --out output --top 30 (Windows: py -3.11 launch.py ...). Минимальное значение top — 20.
| Ситуация | Действие |
|---|---|
| Python не найден или версия не 3.11 | Установить CPython 3.11; проверить командой для своей ОС выше |
| Ошибка venv/ensurepip в Linux | Установить компонент venv для Python 3.11 |
| Порт 8765 занят | Остановить прежний сервер Ctrl+C или использовать --port 8766 |
| Нет или повреждены wheel-пакеты | Скопировать весь vendor/ вместе с manifest.json; не переносить выборочные файлы |
.venv перенесена с другого компьютера | Переименовать её и повторить запуск; установщик создаст новое окружение |
| Старая страница после ручного пересчёта | Обновить вкладку: macOS Cmd+Shift+R, Windows/Linux Ctrl+F5; проверить адрес и порт |
| Нужно только посмотреть готовый результат | Открыть output/graph.html браузером без Python |
Полный расчёт занимает около 2 секунд в подготовленном окружении на текущем Mac; установка зависимостей и первичная загрузка библиотек могут занять дольше. Точное время расчёта записывается в output/run_report.json.
Пределы проверки: настоящий запуск и чистая офлайн-установка проверены на macOS arm64. Для Windows/Linux/Intel Mac включены пакеты, проверены SHA-256 и логика выбора платформы; фактический запуск на этих ОС здесь не выполнялся. Дополнительные инструкции: docs/PORTABILITY.md, docs/OFFLINE.md.
Интерфейс и автообновление
Файл output/graph.html содержит данные и JavaScript: его можно открыть отдельно, без CDN, сервера и Python. Это просмотр результата последнего расчёта, а не пересчёт Parquet. Для надёжного хранения истории дел используйте HTTP-сервер — поведение localStorage на file:// зависит от браузера.
--serve пересобирает результат при изменении кода/Parquet и обновляет вкладку. Несохранённый комментарий блокирует автоматическое обновление. Старый python -m http.server только отдаёт файлы и не пересобирает проект.
Сценарий: выбрать приоритетный узел или найти gid → изучить окружение и стрелки → открыть карточку → проверить операции и путь от seed → сохранить решение и экспортировать справку/запрос. Цвет обозначает роль, размер — приоритет, белая обводка — seed. Колесо меняет масштаб, перетаскивание перемещает схему. Топ остаётся видимым при выборе узла. Есть фильтры роли и сообщества, режим соседей, отдельный путь от seed, навигация по топу и скачивание текстовой карточки. Геометрическое расстояние не является финансовой метрикой.
В разделе «Аналитика и помощник» находятся сообщества с гипотезами, паттерны, чувствительность, удаление top-N и два явно подписанных режима помощника:
- LLM-агент — локально, CPU: Qwen3-1.7B составляет план, выбирает инструменты и аргументы, получает результаты и выполняет следующие шаги. Приложение проверяет выполнение плана и ссылки на факты. Показаны ссылки на узлы, исходные значения и журнал вызовов.
- Быстрый поиск — без LLM: прежние фиксированные запросы доступны даже в автономном HTML. Этот режим не выдаётся за LLM.
Включить настоящего LLM-помощника
Один раз подготовьте модель и движок: скачиваются 1,83 ГБ Qwen3-1.7B Q8_0 и сборка llama.cpp. Нужен интернет только для подготовки; проект и граф не отправляются на внешние серверы. После подготовки работа полностью локальная, на CPU. Рекомендуется не менее 8 ГБ оперативной памяти и 2,1 ГБ свободного диска; скорость зависит от процессора.
macOS/Linux, из корня проекта:
python3.11 scripts/setup_llm.py --download
sh run.sh --serve
Windows PowerShell:
py -3.11 scripts/setup_llm.py --download
.\run.bat --serve
Дождитесь сообщения о готовности и откройте http://127.0.0.1:8765/graph.html → «Аналитика и помощник» → «Помощник». При готовой модели автоматически выбирается режим LLM. Если сервер был запущен до установки модели, остановите его Ctrl+C и запустите снова. Проверка установки: python3.11 scripts/setup_llm.py --check (Windows: py -3.11 ...). Если порт занят, используйте --serve --port 8767 и соответствующий адрес.
Пример: «Найди одного приоритетного консолидатора и покажи направленный путь от seed к нему». Для поиска общих получателей укажите gid отправителей. Для сравнения: «Сравни роли и , затем укажи, каких данных не хватает».
Агент ограничен шестью шагами и 150 секундами; принимает один запрос одновременно. Ограничение 5 минут из ТЗ относится к основному пересчёту Parquet → CSV, который не вызывает LLM. Если модель недоступна, интерфейс сообщает об этом; быстрому поиску можно переключиться явно. Большая модель не скачивается при обычном запуске.
Как обеспечиваются проверяемые ответы: восемь инструментов Python вычисляют метрики, рейтинг, соседей, общих получателей, пути, кластеры, паттерны и запросы данных. Модель составляет план до трёх типов проверок, выбирает инструменты и аргументы, затем упорядочивает ссылки E1/E2/… на результаты. Завершение разрешено после выполнения плана с сохранением всех полученных фактов; фактический текст собирается из этих результатов. Неизвестные gid, инструменты и выдуманные ссылки отклоняются. Ссылки гарантируют происхождение показанных фактов, но не полноту плана или корректность AML-гипотезы. LLM не назначает роли и не меняет выгрузки. Отдельный JSON-экспорт содержит вопрос, версию модели, контрольные суммы данных/анализа, действия, выбранные факты и ограничения.
Файлы модели находятся в .local_ai/ и исключены из Git. Версии, URL и SHA-256 закреплены в scripts/llm_assets.json. При старте проверяются хеши модели и движка. Сеть инференса ограничена localhost; --device none, --n-gpu-layers 0 и --no-kv-offload отключают GPU. Подробности и процедура живой проверки — docs/ASSISTANT.md. Docker по умолчанию содержит основную аналитику и быстрый поиск; готовый LLM-комплект нужно готовить отдельно под платформу контейнера.
Запуск через Docker
Альтернатива установке Python — установленный Docker с Compose и Linux-контейнерами. Из корня проекта:
docker compose up --build
Откройте сайт. Python находится внутри контейнера. Первая загрузка базового образа требует интернета, если образ ещё не закэширован; Python-пакеты устанавливаются из локального комплекта. Docker-вариант здесь пока не проверен запуском.
Результаты хранятся в Docker-томе. Скопировать их на компьютер:
docker compose cp aml:/app/output ./docker-output
Остановка: docker compose down. Подробности, поддерживаемые платформы и перенос готового Docker-образа без интернета — docs/PORTABILITY.md.
Схема решения и демо
Структура проекта
| Файл | Ответственность |
|---|---|
pipeline/load.py | Схема, типы, NULL, уникальность, даты, порог, сверка агрегатов |
pipeline/metrics.py | Направленные степени, суммы, количество операций, даты, BFS |
pipeline/temporal.py | Сопоставление сумм FIFO в двух сценариях |
pipeline/roles.py | Версия 3.0 правил, scores и evidence |
pipeline/clustering.py | Взвешенный Louvain по компонентам, гипотезы |
pipeline/ranking.py | Приоритет и его объяснение |
pipeline/analytics.py | Аномалии, циклы, маршруты, чувствительность, удаление узлов |
pipeline/deliverables.py | Автоматический выбор примеров для демо |
run_pipeline.py | Последовательность расчёта, контракты, все выгрузки |
app/ | Автономный Canvas-интерфейс, карточки и оба режима помощника |
aml_assistant/ | Агентный цикл, восемь инструментов, локальный CPU-движок и HTTP-сервис |
serve.py | Локальный сервер с пересборкой |
scripts/, tests/ | Офлайн-установка и проверки |
Входные данные и метрики
nodes.parquet: gid, depth, is_seed; edges.parquet: src, dst, sum_kzt, n_tx, depth; transactions.parquet: src, dst, date, sum_kzt. Загрузчик сверяет суммы с точностью 0,01 KZT и n_tx по каждой паре, проверяет неизвестные концы рёбер, уникальность и диапазоны. Отдельные одинаковые транзакции не удаляются: у них нет банковского transaction_id.
in_degree,out_degree: число уникальных входящих/исходящих соседей, включая самопереводы.fan_in,fan_outисключают сам узел: самоперевод не добавляет контрагента.sum_in,sum_out,n_tx_in,n_tx_out: наблюдаемые суммы и число операций.pass_through_ratio=sum_out/sum_inпри sum_in>0, иначе NULL иzero_sum_in=True.volume=sum_in+sum_out: интенсивность участия; транзитная сумма учитывается на входе и выходе, это не остаток.is_depth4_leaf: depth=4 и out_degree=0; не доказанный конечный получатель.first_tx,last_tx,activity_span_hours: окно активности, не время удержания денег.seed_hops: направленный BFS от всех seed, 0 для seed, -1 для недостижимого узла; изоляты сохранены.seed_path: один кратчайший направленный путь;near_seed_count/reachable_seed_count: число других seed, достигающих узла за ≤2 / ≤4 шага;seed_branch_count: число входящих соседей, достижимых от seed за ≤3 шага. Ветви могут иметь общих предков и не означают независимые группы.rapid_out_share: прежний справочный признак соседства выхода с входом ≤24ч; не используется для назначения ролей в версии 3.
Все суммы/связи ограничены выборкой. Неизвестные входы могут отсутствовать у любого узла; у seed это особенно выражено.
Временной анализ с сохранением сумм
temporal.py распределяет наблюдаемые входящие суммы на последующие исходящие по FIFO. Суммы переводятся в копейки, остаток входа уменьшается после каждого сопоставления. В рамках одного узла и одного сценария вход нельзя потратить дважды, выход нельзя покрыть больше его суммы. Исходная позиция row:N позволяет проверить каждое сопоставление.
Даты имеют точность до дня, поэтому рассчитываются два сценария:
fifo_strict_share: выходы дня обрабатываются до входов этого дня; сопоставляются только входы за предыдущие 1–2 календарных дня.fifo_same_day_possible_share: входы дня обрабатываются до выходов; допускается 0–2 календарных дня.
Каждый показатель — сопоставленная сумма / sum_out (0 без выходов). Это два сценария, а не гарантированные нижняя/верхняя границы: перераспределение сумм меняет последующие доступные остатки. 0–2 календарных дня не означает точные 48 часов. Начальные остатки неизвестны; FIFO не доказывает, что ушли именно полученные деньги. Между узлами не поддерживается глобальная идентичность средств. Результаты сценариев нельзя складывать.
Правила ролей и обоснование порогов
Первое выполненное правило определяет основную роль. По умолчанию H=5, L=0,2; Q=P90 объёма всех узлов (на текущих данных 741 811,70 KZT).
| Порядок | Роль | Правило |
|---|---|---|
| 1 | terminal на границе | depth4 leaf, sum_in>0; score=0,25 и оговорка об обрыве |
| 2 | coordinator | fan_in≥H, fan_out≥H, большая степень≤2×меньшей, volume≥Q; ≥2 других seed за ≤2 шага и ≥2 входных ветвей; не выполнено правило consolidator |
| 3 | consolidator | не seed; fan_in≥H; ratio≤L |
| 4 | distributor | fan_out≥H; скорость усиливает score, но не отменяет структуру рассылки |
| 5 | transit | не seed; ratio 0,8–1,2 включительно; обе степени>0, большая≤2×меньшей; FIFO 0–2д≥50% |
| 6 | terminal внутри выборки | sum_in>0, fan_out=0; отсутствие выхода только в выборке |
| 7 | peripheral | остальные; отсутствие сигнала, не свидетельство безопасности |
H=5 отделяет ветвление от единичных связей: медианы fan_in/fan_out равны 1/0, P95 — 3/5. L=0,2 означает, что наблюдаемый выход не превышает пятой части входа. ±20% допускает небольшой дисбаланс, фактор 2 ограничивает асимметрию степеней. FIFO≥50% требует поддержки хотя бы половины исходящей суммы. P90 выделяет верхнюю десятую часть объёмов. Для coordinator два близких seed и две ветви требуют пересечения нескольких наблюдаемых потоков; один высокий оборот недостаточен. Все это эвристики, а не обученные пороги; устойчивость проверяется отдельно.
Структурная рассылка и её скорость теперь разделены: узел со 116 получателями не становится peripheral из-за того, что временной показатель чуть ниже 50%. На границе правило обрыва применяется раньше остальных. Для seed не назначаются consolidator/transit по неполному отношению сумм.
Как считается role_score
Пусть f=fifo_same_day_possible_share, s=fifo_strict_share, r=ratio, V=volume, h=H, q=Q. Все выражения ограничены [0,1]. Score — воспроизводимая сила правила, не откалиброванная вероятность.
| Роль | Формула |
|---|---|
| coordinator | 0,65 + 0,15·min(min(fan_in,fan_out)/(2h),1) + 0,10·min(V/(2q),1) |
| consolidator | 0,60 + 0,15·min(fan_in/(2h),1) + 0,15·(1−r/L) |
| distributor | 0,45 + 0,20·min(max(fan_in,fan_out)/(4h),1) + 0,10f + 0,10s |
| transit | 0,50 + 0,15·(1−abs(r−1)/0,2) + 0,10f + 0,10s |
| terminal внутри | 0,50 + 0,15·min(fan_in/h,1) |
| boundary terminal | 0,25 |
| peripheral | 0,40 |
Для seed score≤0,55; для прочих узлов с нулевым входом score≤0,50. Evidence содержит числа и укладывается в 200 символов; полное сработавшее правило (rule_code, rule_text) доступно в метриках и карточке. В сценариях чувствительности знаменатель 0,2 у transit заменяется соответствующим допуском.
Кластеризация и гипотезы
NetworkX Louvain: weight=sum_kzt, resolution=1, seed=42. Неориентированная проекция суммирует встречные направления. Каждый компонент обрабатывается отдельно; изоляты получают отдельные сообщества. Направления сохраняются во всех остальных расчётах. Нумерация по минимальному gid обеспечивает повторяемость при одинаковом входе.
В гипотезе кластера показаны признаки сбора, распределения и транзита, количество seed, суммы внутри и через границу, крупнейшие получатели, концентрация внутреннего потока и количество обрывов depth4. Внутренняя доля = внутренние переводы / (внутренние + входящие через границу + исходящие через границу). Отдельно приводится доля внутреннего потока среди исходящих переводов участников. Изолятам не приписывается назначение. Эти доли не означают удержание денег на счетах.
В текущем графе 16 компонент с рёбрами + 19 изолированных seed = 35 компонент. Получается 105 сообществ, 8 из них содержат несколько seed. Это не единственно возможное разбиение; изменение resolution влияет на результат. Устойчивость Louvain по resolution пока отдельно не измеряется.
Приоритет и объяснение
priority_score = 0,15 × вес_роли × role_score
+ 0,25 × norm(volume)
+ 0,25 × norm(fan_in+fan_out)
+ 0,10 × 1/(1+seed_hops)
+ 0,10 × norm(reachable_seed_count)
+ 0,15 × norm(fan_in) × retention
norm(x) = log1p(x) / max(log1p(x))
retention = clip(1-pass_through_ratio, 0, 1)
Веса ролей: coordinator 1; consolidator 0,95; distributor 0,75; transit 0,65; terminal 0,45; peripheral 0,10. При нулевом максимуме нормированное слагаемое равно 0; для недостижимого узла близость=0. Для seed, depth4 leaf и неопределённого ratio retention=0: неполные данные не дают бонуса накопления. Сумма ≤1. Сортировка score по убыванию, затем gid по возрастанию. why содержит шесть вкладов, правило, число транзакций и дополнительные сигналы. Аномалии не добавляют скрытых надбавок к приоритету. Баллы разных выгрузок напрямую несопоставимы из-за нормирования.
ranking_sensitivity.csv содержит 14 сценариев весов: база, каждый из шести весов ±20% с перенормированием суммы к 1 и контроль без роли. rank_min / rank_max — диапазон по этим сценариям. Отдельные threshold_rank_min / threshold_rank_max, role_stability, top20_frequency относятся к изменению порогов ролей в stability.parquet. Устойчивость не равна accuracy.
Дополнительные аналитические функции
- Короткие циклы: все найденные направленные простые циклы длины 2–4 внутри сильносвязных компонент; лимит 2000 с явным
cycles_truncated. Самопереводы не считаются циклом расследования. На текущих данных 387, лимит не достигнут. Хронология и возврат одной суммы не доказаны. - Повторные маршруты A→B→C: в strict FIFO есть ≥2 разных входящих и ≥2 разных исходящих операций по этой тройке; все три узла различны. Сейчас 26 кандидатов. Это повторные сопоставления сумм, не подтверждённые маршруты одних денег.
- Всплеск: ≥5 входящих/исходящих событий за день и ≥50% событий узла за месяц приходится на этот день.
- Синхронные входы: ≥3 уникальных плательщиков за один день.
- Повтор сумм: ≥3 транзакций одной пары с одинаковой суммой за день. Это сигнал повторения, не доказательство дробления; операции ниже 5000 невидимы.
- Профиль относительно колена: одновременно объём и суммарная степень строго выше P95 своего depth, группа≥20 узлов. Ненулевая сумма обязательна. Сравнение описательное, не статистический тест виновности.
- Чувствительность: 12 сочетаний H=3/5/8/10 и L=0,1/0,2/0,3 плюс transit-допуск ±15% и ±25% (14 сценариев, включая базовый). Для узла: доля сохранения роли, min/max ранга, доля попадания в top20. Для сценария: совпадение ролей и Jaccard top20. Это устойчивость правил, не accuracy.
- Удаление top-N: N=1/5/10/20, слабая связность, крупнейшая компонента, изоляты, доля сохраняющихся связных пар среди тех же оставшихся узлов. Контроль — среднее 20 случайных удалений того же N, seed=42. Симуляция описывает наблюдаемый граф и не прогнозирует эффект банковской блокировки.
Карточки, решения и запросы данных
На широком экране одновременно видны топ-30 слева, граф в центре и карточка справа. На телефоне они переключаются вкладками без потери выбранного узла. Поиск всегда доступен сверху: принимает полный gid и предлагает до восьми совпадений по фрагменту от трёх символов. Подсказки выбираются мышью либо стрелками и Enter. Gid хранится строкой, чтобы не потерять точность int64. В карточке: роль, сила правила, evidence, кластер, приоритет, суммы и полный список входящих/исходящих связей с сортировкой по сумме. Кнопки «Предыдущий» и «Следующий» позволяют последовательно проверить топ. Карточка содержит правило, метрики, операции, два сценария FIFO, устойчивость роли, пути от каждого достижимого seed, статус/комментарий и историю. Кнопка пути показывает его узлы и связи на графе. Показанный подграф может содержать дополнительные связи между этими узлами; текст цепочки фиксирует выбранный путь.
Статусы: Новое → Проверяется → Закрыто / Эскалировано (аналитик может менять их повторно). Для закрытия/эскалации нужно основание. «Сохранить решение» добавляет запись с временем, предыдущим/новым статусом, комментарием и версией правил. Старые записи без версии остаются читаемыми.
Выбор участника центрирует и приближает его: прямые связи выделены, остальные приглушены. Кнопка «Фокус» вмещает выбранный узел и всех видимых прямых контрагентов, включая удалённые кластеры; поэтому может уменьшить масштаб. «Один шаг» оставляет узел и прямых соседей. «Путь от seed» — отдельный режим с направленной цепочкой. Под графом — гипотеза выбранного кластера с внутренними/внешними потоками и получателями. «Перейти к кластеру» выделяет группу и приближает её, сохраняя контекст сети.
Колесо мыши и кнопки +/− меняют масштаб, перетаскивание перемещает граф; реализован pinch двумя пальцами. С клавиатуры на холсте работают +/−, стрелки и Home. Легенда под графом сворачивается и фильтрует шесть ролей; цвет дублируется формой и русским названием. Поиск включает роль выбранного участника, сохраняя остальные настройки; выбор пути включает роли всех его узлов. «Вся сеть» / «Показать всё» восстанавливает все роли, очищает карточку и сохраняет топ. Карточку можно скачать в TXT.
Подпись есть только у выбранного узла и во всплывающих подсказках. Периферия видима по умолчанию, но меньше и бледнее. Толщина ребра ограничена диапазоном 0,6–2,8 px, линейно растёт до 95-го перцентиля суммы; точные суммы всегда доступны в таблице. Тёмное внешнее кольцо отмечает seed, отдельное кольцо — выбранный узел. Янтарные стрелки направлены к выбранному, голубые — от него, золотистая линия отмечает путь. Тёмная палитра, градиентные узлы со свечением и тонкие светящиеся линии помогают отделить активные связи от фона. Контуры обозначают кластеры. Геометрические расстояния не являются метрикой финансовой близости.
Дизайн, соответствие ТЗ и браузерная проверка. Полный код изменённых файлов интерфейса. Хранение — localStorage браузера, по SHA-256 входной выборки и gid. Это персональный локальный прототип, без защищённого аудита, авторизации и совместного редактирования. На file:// хранение зависит от браузера; используйте сервер. Другой origin/браузер/выборка — отдельное состояние. Очищение браузера удалит историю; экспортируйте нужные дела.
Экспорт: справка HTML (печать в PDF), дело JSON с метриками, операциями, историей и отпечатком данных, запросы TXT. Несохранённые изменения помечаются как черновик. Это не регуляторная форма ФМ-1. JSON-импорт не предусмотрен. row:N — строка исходного transactions.parquet, а не банковский ID. Gid в браузере/JSON — строки, int64 не теряет точности.
Запросы формируются по наблюдениям: depth4 leaf → дальнейшие исходящие; seed/нулевой вход/ratio>1,2 → полный вход и начальный остаток; вход и выход → точное время и часовой пояс; вход>выход → при разрешённом доступе другие способы вывода; изолят → проверка полноты; всем → период, порог, каналы. Никакие внешние сведения автоматически не загружаются.
Выходные файлы
Обязательные три CSV в UTF-8, с точной схемой:
| Файл | Колонки |
|---|---|
nodes_roles.csv | 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 | rank, gid, role, priority_score, why |
2248 узлов, 105 кластеров, top30 по умолчанию. top_gids — JSON-массив до 5 gid, ранжированных по приоритету. sum_kzt_internal учитывает каждое исходное направленное ребро внутри кластера один раз.
Дополнительно в output: node_metrics.parquet, temporal_matches.parquet (каждое FIFO-сопоставление с row-ссылками), stability.parquet, ranking_sensitivity.csv, analytics.json, run_report.json (версии, SHA-256 входов, пороги, время), graph.html, assistant_data.json (снимок для LLM), demo.md, demo_cases.json. assistant_evaluation.json появляется после отдельной проверки настоящей модели. При запуске проверки также создаётся validation_report.json. NULL допустимы только для объективно неопределённых метрик (ratio при нулевом входе, даты изолята); обязательные CSV полностью заполнены.
Проверки и воспроизводимость
.venv/bin/python -m unittest discover -s tests -v
.venv/bin/python scripts/verify.py
На Windows:
.\.venv\Scripts\python.exe -m unittest discover -s tests -v
.\.venv\Scripts\python.exe scripts/verify.py
Настоящая модель проверяется отдельно при запущенном сервере: python3.11 scripts/evaluate_assistant.py --url http://127.0.0.1:8765 (Windows: py -3.11 ...). Unit-тесты используют тестовый двойник для контроля ошибок; они не подменяют живую проверку LLM.
Проверяются границы и seed, изоляты, сверка n_tx, направление времени, запрет повторного расхода FIFO, циклы/маршруты, мост при удалении узла, чувствительность и случай веерного узла со слабым временным сигналом. Интеграционная проверка повторяет расчёт в двух временных директориях, проверяет CSV и сопоставления сумм и сравнивает хеши результатов. Время и версии отражены в отчётах. После добавления агентного помощника прошли 45 unit- и регрессионных тестов, интеграционная проверка и браузерный smoke-тест графа, карточек и быстрого поиска. Контрольный полный пересчёт — 2,446 с на текущем macOS arm64; хеши обязательных CSV совпали с версией до добавления LLM. Чистая установка без PyPI на macOS arm64 дала те же CSV; полный пересчёт в новом окружении занял 4,93 с. Браузерные проверки — tests/browser_smoke.cjs и tests/live_server_smoke.cjs; Playwright нужен только для QA, не для работы продукта. Проверены также пересборка, no-store и сохранение несохранённого комментария при обновлении.
19 Python-тестов покрывают исчезавших распределителей, требования к координатору, неизвестный вход, обрыв/seed, временное направление, циклы, самопереводы, пути и int64, потоки кластера, изоляты, CSV и воспроизводимость порядка. Ещё 8 тестов камеры, границ толщины, pan и pinch запускаются через node --test tests/test_graph_ui.cjs (Node.js нужен только для этих тестов, не для приложения). Проверка аналитики, проверка нового интерфейса.
pipeline/load.py — валидация; metrics.py — граф и признаки; roles.py — роли; clustering.py — сообщества и потоки; ranking.py — приоритет и чувствительность. run_pipeline.py связывает этапы; app/build.py встраивает template.html, style.css, graph.js (Canvas и камера), view.js (элементы интерфейса) и cases.js в автономный HTML. run.py отвечает за подготовку окружения. tools/build_defense.py обновляет примеры защиты из результатов.
Ограничения
Обрыв на 4 колене; неполный вход seed и других узлов; только один банк и июль 2026; операции <5000 KZT отсутствуют; нет ФИО, ИИН, остатков, назначения платежа и ground truth. Дневная точность не позволяет восстановить порядок внутри дня. «Terminal» означает наблюдаемый конец, не доказанное оседание. Роли и аномалии могут иметь бытовое объяснение. Не рассчитываем accuracy и не выдаём score за вероятность нарушения. Помощник не является LLM и понимает только заявленные типы вопросов.
Дополнительная проверка устойчивости уменьшает зависимость от одного набора порогов, но не заменяет экспертную оценку. Встраивание данных в HTML подходит для этого обезличенного хакатонного набора; промышленное внедрение потребует контроля доступа, политики хранения и серверного аудита.
Масштабирование до ~1 млн узлов
Перенести чтение/проверки/агрегации в DuckDB/Polars, хранить партиционированный Parquet, gid int64 и компактную перенумерацию для CSR. NetworkX заменить на igraph/другой C/C++-движок: Python-объекты расходуют слишком много памяти. FIFO выполнять потоком отсортированных по gid/дате событий, не собирая все группы и сопоставления в памяти.
Louvain/Leiden выполнять по компонентам на CPU; фиксировать параметры и измерять память крупнейшей компоненты. Циклы/маршруты — ограниченные локальные подграфы, лимиты длины/числа результатов и явная отметка усечения. Не повторять полный расчёт 14 раз при каждом событии: сценарные проверки пакетно/по изменившимся узлам. Глобальные пути от каждого seed к каждому узлу заменить на BFS по запросу с кэшем.
В интерфейсе — API поиска, агрегированная карта сообществ, загрузка ограниченного ego-графа, WebGL вместо встраивания миллиона узлов. Метрики и роли обновлять инкрементально, сообщества — периодически. Версии правил, манифесты входов, журнал решений и контроль качества сохранять отдельно. Пять минут на текущую выборку не являются обещанием той же скорости на миллионе узлов.
Упаковка для передачи
python3.11 tools/package_offline.py создаёт hackalem-offline-py311.zip с исходниками, данными, готовыми результатами, пятью комплектами vendor/wheels и SHA-256 манифестом. .venv не копируется. python3.11 tools/verify_bundle.py проверяет архив, создаёт чистое окружение на текущей ОС, пересчитывает данные и сравнивает основные результаты. Это не тест запуска на всех ОС сразу. Совместимая команда python3.11 run.py вызывает тот же launch.py; отдельного режима Python 3.12 / wheelhouse больше нет.
Для полностью офлайн-демо с LLM после подготовки модели выполните python3.11 tools/package_offline.py --with-llm (Windows: py -3.11 ...). Архив hackalem-offline-ai-<платформа>.zip включает модель, движок текущей ОС, исходники, данные и зависимости. Переносите его на ту же ОС/архитектуру; на другой платформе сначала подготовьте её движок. CPython 3.11 должен быть установлен заранее. Обычный архив и Git-репозиторий большие веса не содержат; без отдельной подготовки в них доступен быстрый поиск.
Авторы коммитов
История коммитов
- 2026-09-23 17:29readme latestDilnaz Bekturova
- 2026-09-23 17:25readme latestDilnaz Bekturova
- 2026-09-23 17:18Improve role analysis, ranking, interface and defense materialsAliya Saidulla
- 2026-09-23 17:15design updateAliya Saidulla
- 2026-09-23 17:04Improve graph navigation and add dark glowing themeAliya Saidulla
- 2026-09-23 16:21Finalize AML analytics, cross-platform setup and requirements auditDilnaz Bekturova
- 2026-09-23 15:42Improve role analysis, ranking, interface and defense materialsAliya Saidulla
- 2026-09-23 14:58Add investigation cards and missing data requestsDilnaz Bekturova
Все коммиты (9)
- 2026-09-23 13:57Upload full solution filesDilnaz Bekturova
Структура репозитория (89 файлов)
.dockerignore .gitignore Dockerfile README.md aml_assistant/__init__.py aml_assistant/agent.py aml_assistant/runtime.py aml_assistant/service.py aml_assistant/tools.py app/assistant.js app/build.py app/cases.js app/cases.py app/graph.js app/insights.js app/style.css app/template.html app/view.js compose.yaml data/edges.parquet data/nodes.parquet data/transactions.parquet docs/ASSISTANT.md docs/AUDIT.md docs/CRITERIA.md docs/OFFLINE.md docs/PORTABILITY.md docs/QWEN-LICENSE.txt docs/UI_SOURCE.md docs/architecture.svg docs/defense.md docs/ui-review.md docs/verification.md launch.py output/analytics.json output/assistant_data.json output/assistant_evaluation.json output/clusters.csv output/demo.md output/demo_cases.json output/graph.html output/node_metrics.parquet output/nodes_roles.csv output/portability_report.json output/ranking_sensitivity.csv output/run_report.json output/stability.parquet output/temporal_matches.parquet output/top_nodes.csv output/validation_report.json pipeline/__init__.py pipeline/analytics.py pipeline/clustering.py pipeline/deliverables.py pipeline/load.py pipeline/metrics.py pipeline/ranking.py pipeline/roles.py pipeline/temporal.py requirements.txt run.bat run.py run.sh run_pipeline.py scripts/check_environment.py scripts/evaluate_assistant.py scripts/llm_assets.json scripts/setup_env.py scripts/setup_llm.py scripts/verify.py scripts/wheel_manifest.py serve.py starter/README.md starter/requirements.txt starter/starter.py tests/assistant_browser_smoke.cjs tests/browser_smoke.cjs tests/live_server_smoke.cjs tests/test_analytics.py tests/test_assistant.py tests/test_cases.py tests/test_graph_ui.cjs tests/test_pipeline.py tests/test_portability.py tests/test_regressions.py tools/build_defense.py tools/package_offline.py tools/verify_bundle.py ТЗ кейса для HackAlem AI.docx
Обсуждение 0 комментариев
Войдите, чтобы комментироватьПока нет комментариев — будьте первым.