feat: render full analytics as tables

This commit is contained in:
admin committed 2026-10-20 17:05:52 +02:00
1 parent 112c3247e0
commit e4b1b1e510
3 files changed
+25 -7

No files matched your search

+1 -1
View File
@@ -1 +1 @@
0.1.0+65
0.1.0+66
+23 -5
View File
@@ -127,12 +127,30 @@ def all_metrics(period: str = "all", db_path: str | None = None) -> dict[str, ob
return result
def render_report(period: str = "day", db_path: str | None = None) -> str:
def _html_table(headers: list[str], rows: list[list[object]]) -> str:
header = "".join(f"<th>{h}</th>" for h in headers)
body = "".join("<tr>" + "".join(f"<td>{v}</td>" for v in row) + "</tr>" for row in rows)
return f"<table><thead><tr>{header}</tr></thead><tbody>{body}</tbody></table>"
def render_report(period: str = "all", db_path: str | None = None) -> str:
metrics = all_metrics(period, db_path)
types = metrics["message_types"]
generation_types = {k[1]: v for k, v in types.items() if k[0] == "generation"}
training_types = {k[1]: v for k, v in types.items() if k[0] == "training"}
def line(label: str, value: object) -> str:
return f"<b>{label}:</b> {value}"
rows = ["<h2>📊 Статистика бота</h2>", f"<p>Период: {period}</p>", "<h3>Пользователи</h3>", line("Пользователей", metrics["users"]), line("Активных", metrics["active_users"]), "<h3>Генерация</h3>", line("Постов", metrics["post_generations"]), line("Идей", metrics["idea_generations"]), line("Правок", metrics["post_revisions"]), line("Сообщений", metrics["generation_messages"]), line("Типы", ", ".join(f"{k}: {v}" for k, v in generation_types.items()) or "нет"), "<h3>Обучение</h3>", line("Сообщений", metrics["training_messages"]), line("Типы", ", ".join(f"{k}: {v}" for k, v in training_types.items()) or "нет")]
return "<p>" + "<br/>".join(rows) + "</p>"
users = metrics["users"]
active = metrics["active_users"]
user_rows = [["Всего", users], ["Активные", active]]
activity_rows = [["Генерации постов", metrics["post_generations"]], ["Идеи", metrics["idea_generations"]], ["Правки постов", metrics["post_revisions"]], ["Сообщения", metrics["generation_messages"]]]
generation_type_rows = [[key, value] for key, value in sorted(generation_types.items())] or [["Нет данных", 0]]
training_type_rows = [[key, value] for key, value in sorted(training_types.items())] or [["Нет данных", 0]]
training_rows = [["Сообщения", metrics["training_messages"]]]
return (
"<h2>📊 Полная статистика бота</h2>"
f"<p>Период: {period}</p>"
"<h3>Пользователи</h3>" + _html_table(["Показатель", "Количество"], user_rows)
+ "<h3>Генерация</h3>" + _html_table(["Показатель", "Количество"], activity_rows)
+ "<h3>Типы сообщений в генерации</h3>" + _html_table(["Тип", "Количество"], generation_type_rows)
+ "<h3>Обучение</h3>" + _html_table(["Показатель", "Количество"], training_rows)
+ "<h3>Типы сообщений в обучении</h3>" + _html_table(["Тип", "Количество"], training_type_rows)
)
+1 -1
View File
@@ -1529,7 +1529,7 @@ async def stats_command(message: Message, state: FSMContext) -> None:
return
if OWNER_USER_ID and (not message.from_user or message.from_user.id != OWNER_USER_ID):
return
period = ((message.text or "").split(maxsplit=1)[1] if len((message.text or "").split()) > 1 else "day")
period = ((message.text or "").split(maxsplit=1)[1] if len((message.text or "").split()) > 1 else "all")
report = await asyncio.to_thread(analytics.render_report, period)
if message.bot is None:
return