Files
wiki/tasks/bytik/bot.py
2026-04-15 01:00:01 +03:00

122 lines
3.8 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import asyncio
import logging
import os
from logging.handlers import RotatingFileHandler
from aiogram import Bot, Dispatcher, types
from aiogram.filters import Command
from aiogram.types import BotCommand
from config import BOT_TOKEN, ALLOWED_CHAT_ID
from prompts import SYSTEM_PROMPT
from llm import ask_llm
from chat_history import load_history, add_message
from scheduler import BytikScheduler
LOG_DIR = "logs"
os.makedirs(LOG_DIR, exist_ok=True)
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
handlers=[
RotatingFileHandler(
os.path.join(LOG_DIR, "bytik.log"),
maxBytes=5*1024*1024,
backupCount=3,
encoding="utf-8",
),
logging.StreamHandler(),
],
)
logger = logging.getLogger(__name__)
bot = Bot(token=BOT_TOKEN)
dp = Dispatcher()
scheduler = None
def is_allowed_chat(chat_id: int) -> bool:
return chat_id == ALLOWED_CHAT_ID
@dp.message(Command("start"))
async def cmd_start(message: types.Message):
if not is_allowed_chat(message.chat.id):
logger.warning(f"Попытка /start из неразрешённого чата: {message.chat.id}")
return
await message.answer("Привет, Егор! 👋 Я Байтик, твой робот-помощник! Спрашивай меня о чём угодно! 🤖")
@dp.message(Command("clear"))
async def cmd_clear(message: types.Message):
if not is_allowed_chat(message.chat.id):
return
from chat_history import clear_history
clear_history(message.from_user.id)
await message.answer("История наших разговоров очищена! 🧹")
@dp.message()
async def handle_message(message: types.Message):
if not message.text:
return
if not is_allowed_chat(message.chat.id):
logger.debug(f"Игнорирую сообщение из чата {message.chat.id}")
return
user_message = message.text.strip()
logger.info(f"Сообщение от user {message.from_user.id}: {user_message[:100]}")
typing_msg = await message.answer("Думаю... 🤔")
history = load_history(message.from_user.id)
messages_for_llm = [{"role": "system", "content": SYSTEM_PROMPT}] + history
messages_for_llm.append({"role": "user", "content": user_message})
add_message(message.from_user.id, "user", user_message)
answer = await ask_llm(messages_for_llm)
add_message(message.from_user.id, "assistant", answer)
try:
await typing_msg.edit_text(answer)
except Exception:
await message.answer(answer)
@dp.my_chat_member()
async def handle_bot_status_change(update: types.ChatMemberUpdated):
chat_id = update.chat.id
new_status = update.new_chat_member.status
if new_status == "member" and chat_id != ALLOWED_CHAT_ID:
logger.warning(f"Бот добавлен в неразрешённый чат {chat_id}. Покидаю.")
await bot.leave_chat(chat_id)
elif new_status == "left":
logger.info(f"Бот удалён из чата {chat_id}")
async def set_commands():
commands = [
BotCommand(command="start", description="Начать общение"),
BotCommand(command="clear", description="Очистить историю диалога"),
]
await bot.set_my_commands(commands)
async def main():
global scheduler
await set_commands()
scheduler = BytikScheduler(bot)
scheduler.start()
logger.info(f"Бот запущен. Whitelist chat_id: {ALLOWED_CHAT_ID}")
await dp.start_polling(bot)
async def on_shutdown():
if scheduler:
scheduler.shutdown()
await bot.session.close()
if __name__ == "__main__":
try:
asyncio.run(main())
except (KeyboardInterrupt, SystemExit):
logger.info("Бот остановлен")