текущая версия (рабочая)

This commit is contained in:
N8N
2026-09-04 15:10:24 +03:00
commit 161fd6576b
31 changed files with 3420 additions and 0 deletions
+150
View File
@@ -0,0 +1,150 @@
import logging
from aiogram import Router
from aiogram.filters import Command
from aiogram.types import Message
from app import config
from app.handlers.callbacks import _settings_keyboard
from app.models import Settings
from app.services import StatsService
router = Router()
logger = logging.getLogger(__name__)
stats_service = StatsService()
@router.message(Command("allstat", "stat"))
async def cmd_stats(message: Message) -> None:
is_all_time = message.text.startswith("/allstat")
ozon_stats = (
await stats_service.get_all_time_stats("ozon")
if is_all_time
else await stats_service.get_daily_stats("ozon")
)
wb_stats = (
await stats_service.get_all_time_stats("wb")
if is_all_time
else await stats_service.get_daily_stats("wb")
)
period_text = "за все время" if is_all_time else "за сегодня"
stats_text = f"📊 <b>Статистика {period_text}</b>\n\n"
for platform_name, stats in [("Ozon", ozon_stats), ("Wildberries", wb_stats)]:
stats_text += (
f"<b>{platform_name}:</b>\n"
f"Всего отзывов: {stats['total_reviews']}\n"
f"Хороших: {stats['good_reviews']}\n"
f"Плохих: {stats['bad_reviews']}\n"
f"Доля плохих: {stats['bad_ratio']:.1%}\n"
f"Средний рейтинг: {stats['average_rating']:.1f}\n"
f"Критичных: {stats['critical_reviews']} ({stats['critical_ratio']:.1%} от всех, {stats['critical_to_bad_ratio']:.1%} от плохих)\n\n"
f"<b>Оценки:</b>\n"
f"⭐️ 1: {stats['ratings']['1']}\n"
f"⭐️ 2: {stats['ratings']['2']}\n"
f"⭐️ 3: {stats['ratings']['3']}\n"
f"⭐️ 4: {stats['ratings']['4']}\n"
f"⭐️ 5: {stats['ratings']['5']}\n\n"
f"<b>Тональность:</b>\n"
f"😊 Позитивная: {stats['tone']['positive']}\n"
f"😐 Нейтральная: {stats['tone']['neutral']}\n"
f"😠 Негативная: {stats['tone']['negative']}\n\n"
)
await message.answer(stats_text, parse_mode="HTML")
@router.message(Command("settings"))
async def cmd_settings(message: Message) -> None:
settings = await Settings.get_from_context(
message_thread_id=message.message_thread_id
)
await message.answer(
(
f"⚙️ <b>Настройки {'положительных' if settings.is_good else 'отрицательных'} отзывов</b>\n\n"
"/show_prompt - просмотр промптов\n"
"/change_prompt - изменить промпт для аналитики\n"
"/reset_prompt - сбросить промпт для аналитики\n"
"/change_answer_prompt - изменить промпт для ответов на отзывы\n"
"/reset_answer_prompt - сбросить промпт для ответов на отзывы\n\n"
"<b>Шаблоны для отзывов без текста:</b>\n"
"/template_low текст — шаблон для 1–3 ★\n"
"/template_high текст — шаблон для 4–5 ★\n"
"/show_templates — показать текущие шаблоны\n"
),
reply_markup=_settings_keyboard(settings),
parse_mode="HTML",
)
@router.message(Command("show_templates"))
async def cmd_show_templates(message: Message) -> None:
"""Показать текущие шаблоны ответа на отзывы без текста."""
settings = await Settings.get_from_context(
message_thread_id=message.message_thread_id
)
low = settings.template_empty_low_rating or config.TEMPLATE_EMPTY_LOW_RATING
high = settings.template_empty_high_rating or config.TEMPLATE_EMPTY_HIGH_RATING
await message.answer(
"📝 <b>Шаблоны для отзывов без текста</b>\n\n"
f"<b>13 ★:</b> <code>{low}</code>\n\n"
f"<b>45 ★:</b> <code>{high}</code>\n\n"
"Изменить: /template_low текст или /template_high текст",
parse_mode="HTML",
)
@router.message(Command("template_low"))
async def cmd_template_low(message: Message) -> None:
"""Установить шаблон ответа для отзывов без текста с оценкой 1–3 звезды."""
text = (message.text or "").replace("/template_low", "").strip()
if not text:
await message.answer(
"Введите текст шаблона после команды.\n"
"Пример: /template_low Спасибо за отзыв, извините за неудобства."
)
return
for s in await Settings.all():
s.template_empty_low_rating = text
await s.save()
await message.answer(f"✅ Шаблон для 1–3 ★ сохранён:\n<code>{text}</code>", parse_mode="HTML")
@router.message(Command("template_high"))
async def cmd_template_high(message: Message) -> None:
"""Установить шаблон ответа для отзывов без текста с оценкой 4–5 звёзд."""
text = (message.text or "").replace("/template_high", "").strip()
if not text:
await message.answer(
"Введите текст шаблона после команды.\n"
"Пример: /template_high Спасибо за отзыв, рады что вам понравилось!"
)
return
for s in await Settings.all():
s.template_empty_high_rating = text
await s.save()
await message.answer(f"✅ Шаблон для 4–5 ★ сохранён:\n<code>{text}</code>", parse_mode="HTML")
@router.message(Command("max_tokens"))
async def cmd_max_tokens(message: Message) -> None:
settings = await Settings.get_from_context(
message_thread_id=message.message_thread_id
)
args = message.text.split()
if len(args) > 1 and args[1].isdigit():
value = int(args[1])
settings.max_tokens = value
await settings.save()
await message.answer(f"Лимит токенов установлен на {value}")
return
await message.answer(
f"Текущий лимит токенов: {settings.max_tokens}\n"
"Введите /max_tokens число, чтобы обновить его"
)