#!/usr/bin/env python3 # show_stats.py import os import csv from collections import defaultdict def main(): # Динамически определяем корень папки, где лежит сам скрипт show_stats.py base_dir = os.path.dirname(os.path.abspath(__file__)) log_file = os.path.join(base_dir, "logs", "menu_stats.csv") if not os.path.exists(log_file): print(f"❌ Файл статистики еще не создан по пути: {log_file}") print("💡 Сначала перейдите по пунктам меню в боте, чтобы накопились первые логи.") return total_actions = 0 main_menu_counts = defaultdict(int) sub_menu_counts = defaultdict(lambda: defaultdict(int)) cert_counts = defaultdict(lambda: defaultdict(int)) try: with open(log_file, "r", encoding="utf-8-sig") as f: reader = csv.reader(f, delimiter=";") header = next(reader) for row in reader: if len(row) < 4: continue timestamp, user_id, main_menu, sub_menu = row main_menu = main_menu.strip() sub_menu = sub_menu.strip() sub_menu_lower = sub_menu.lower() # ИСПРАВЛЕНО: Полностью исключаем фоновые логи безопасности 2FA и выходы из статистики кликов if "выход" in sub_menu_lower or "2fa" in sub_menu_lower: continue total_actions += 1 main_menu_counts[main_menu] += 1 if sub_menu and sub_menu_lower != "вход": if sub_menu_lower == "справки" or "справк" in sub_menu_lower: parent_item = "Справки (Заказ документов)" if sub_menu_lower == "справки": specific_cert = "📂 Открытие главного меню выбора" elif "выбор справки:" in sub_menu_lower: cert_title = sub_menu.split(":", 1)[1].strip() specific_cert = f"👀 Просмотр/Выбор: {cert_title}" elif "заказ справки:" in sub_menu_lower: cert_title = sub_menu.split(":", 1)[1].strip() specific_cert = f"🚀 Оформлен заказ: {cert_title}" else: specific_cert = sub_menu sub_menu_counts[main_menu][parent_item] += 1 cert_counts[main_menu][specific_cert] += 1 else: sub_menu_counts[main_menu][sub_menu] += 1 except Exception as e: print(f"❌ Ошибка при чтении файла логов: {e}") return if total_actions == 0: print("📭 Файл статистики пуст после фильтрации выходов и логов 2FA.") return print("=" * 70) print(f"📊 СТАТИСТИКА ИСПОЛЬЗОВАНИЯ МЕНЮ БОТА (Всего переходов: {total_actions})") print("=" * 70) sorted_main = sorted(main_menu_counts.items(), key=lambda x: x[1], reverse=True) for main_item, main_count in sorted_main: main_pct = (main_count / total_actions) * 100 print(f"\n📦 {main_item}") print(f" └── Всего вызовов: {main_count} ({main_pct:.1f}% от общей активности)") if main_item in sub_menu_counts and sub_menu_counts[main_item]: print(" └── Внутреннее распределение по подпунктам:") total_sub_clicks = sum(sub_menu_counts[main_item].values()) sorted_subs = sorted(sub_menu_counts[main_item].items(), key=lambda x: x[1], reverse=True) for sub_item, sub_count in sorted_subs: sub_pct = (sub_count / total_sub_clicks) * 100 print(f" ├── {sub_item}: {sub_count} шт. ({sub_pct:.1f}%)") if sub_item == "Справки (Заказ документов)" and main_item in cert_counts: total_certs = sum(cert_counts[main_item].values()) sorted_certs = sorted(cert_counts[main_item].items(), key=lambda x: x[1], reverse=True) print(" │ └── 📑 Детализация по типам документов:") for idx, (cert_title, cert_num) in enumerate(sorted_certs, 1): # ИСПРАВЛЕНО: Локальный расчет процента перенесен строго внутрь итерации cert_pct = (cert_num / total_certs) * 100 if total_certs > 0 else 0 tree_prefix = "└──" if idx == len(sorted_certs) else "├──" print(f" │ {tree_prefix} {cert_title}: {cert_num} шт. ({cert_pct:.1f}%)") print("\n" + "=" * 70) if __name__ == "__main__": main()