Files
trueconf_bot/show_stats.py
T

106 lines
5.5 KiB
Python

#!/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()