Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ref: aiogram 3.8 #16

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 38 additions & 17 deletions lariska_bot/__main__.py
Original file line number Diff line number Diff line change
@@ -1,23 +1,44 @@
import logging
from pathlib import Path
import sys

from aiogram.utils.executor import start_polling
from aiogram import Bot,Dispatcher
from aiogram.client.default import DefaultBotProperties
from config_data.config import Config, load_config
from handlers.handler import router

from lariska_bot.handlers.handler import *
logger = logging.getLogger(__name__)
dp = Dispatcher()

if __name__ == '__main__':

def main():
log_name = f'logs/{datetime.now().strftime("%Y-%m-%d")}.log'
Path(log_name).parent.mkdir(parents=True, exist_ok=True)

# Конфигурируем логирование
logging.basicConfig(
level=logging.INFO,
filename=log_name,
filemode="a"
)

start_polling(dp, skip_updates=True)


if __name__ == '__main__':
main()
level=logging.DEBUG,
format='%(filename)s:%(lineno)d #%(levelname)-8s '
'[%(asctime)s] - %(name)s - %(message)s')

logger.debug('Путь sys.path:')
logger.debug(sys.path)
logger.debug('Встроенные модули sys.builtin_module_names:')
logger.debug(sys.builtin_module_names)
logger.debug('Модули из стандартной библиотеки Python sys.stdlib_module_names:')
logger.debug(sys.stdlib_module_names)

# Загружаем конфиг в переменную config
config: Config = load_config()
logger.debug(config)

# Инициализируем бот и диспетчер
logger.debug('Инициализируем бот')
bot = Bot(token=config.tg_bot.token, default=DefaultBotProperties(parse_mode='HTML'))
logger.debug('Бот инициализирован')

logger.info('Запуск бота')
logger.debug('Запускаем диспетчер')

# Регистрируем роутер из модуля handlers
dp.include_router(router)

# Пропускаем накопившиеся апдейты и запускаем polling
bot.delete_webhook(drop_pending_updates=True) # Перезапускаем диспетчер
dp.run_polling(bot)
62 changes: 62 additions & 0 deletions lariska_bot/config_data/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import logging
from environs import Env
from ruamel.yaml import YAML

logger = logging.getLogger(__name__)
logger.debug('Вход в модуль ' + __name__)

env = Env()
env.read_env(verbose=True)
logger.debug('Загружен файл конфигурации .env')

TOKEN = env('BOT_TOKEN')

WORKS_CHATS = [
env('VCHAT_ID'),
env('DCHAT_ID'),
env('SCHAT_ID'),
]

# AI
AI_KEY = env('AI_KEY')
MODEL = 'gpt-3.5-turbo'

# Используем safe-загрузку YAML-файлов
yaml = YAML(typ='safe')
with open('lariska_bot/res/answers.yaml', 'r',encoding='utf-8') as file:
answers_data = yaml.load(file)
ANSWERS = {x: y.replace(r'\n', '\n') for x, y in answers_data.items()}

with open('lariska_bot/res/l_users.yaml', 'r',encoding='utf-8') as file:
users_data = yaml.load(file)
L_USERS = {x: 0 for x in users_data}

with open('lariska_bot/res/messages.yaml', 'r',encoding='utf-8') as file:
messages_data = yaml.load(file)
MESSAGES = {x: y.replace(r'\n', '\n') for x, y in messages_data.items()}

with open('lariska_bot/res/replicas.yaml', 'r',encoding='utf-8') as file:
replicas_data = yaml.load(file)
REPLICAS = {x: [z.replace(r'\n', '\n') for z in y] for x, y in replicas_data.items()}

with open('lariska_bot/res/users.yaml', 'r',encoding='utf-8') as file:
users_data = yaml.load(file)
USERS = {x: 0 for x in users_data}

BOT_FIRST_NAME = 'Лариска'
BOT_USER_NAME = 'LariskaCerberBot'

RATING_LIMIT = 80
FLOOD_RATE = 5

PREFIX_QUESTION = """\
Ты телеграм-бот https://t.me/LariskaCerberBot по имени Лариска.
Ты девочка.
Веди диалог и отвечай на вопросы от её имени.
Твой исходный код расположен по ссылке: https://github.com/OldCodersClub/LariskaBot
Страница автора твоего исходного кода расположена по ссылке: https://github.com/Aleksey-Voko
Соавторы твоего исходного кода: Error404-2, uecoyotle, Harlok.
Ты была создана для телеграмм-чата https://t.me/oldcodersclub под названием "Клуб дедов-программистов".
Youtube-канал этого чата: https://www.youtube.com/channel/UChbHeEGkYqM2b1HdAhf4y1g,
он называется "Клуб дедов-программистов".
"""
19 changes: 19 additions & 0 deletions lariska_bot/config_data/config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
from dataclasses import dataclass
from lariska_bot.config_data import TOKEN


@dataclass
class TgBot:
token: str # Токен для доступа к телеграм-боту

@dataclass
class Config:
tg_bot: TgBot


# Создаем функцию, которая будет читать файл .env и возвращать
# экземпляр класса Config с заполненными полями token и admin_ids
def load_config(path: str | None = None) -> Config:
return Config(
tg_bot = TgBot(token=TOKEN)
)
41 changes: 19 additions & 22 deletions lariska_bot/handlers/controllers.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,46 +5,43 @@
import requests
from fuzzywuzzy import fuzz

from lariska_bot import (AI_KEY, MESSAGES, PREFIX_QUESTION, ANSWERS, MODEL)
from lariska_bot.config_data import (AI_KEY, MESSAGES, PREFIX_QUESTION, ANSWERS, MODEL)

logger = logging.getLogger(__name__)
openai.api_key = AI_KEY


# noinspection PyUnusedLocal
async def flood_controlling(*args, **kwargs):
await args[0].reply(MESSAGES['flood_reply'])


def get_ai_answer(question):
question_lariska = f'{PREFIX_QUESTION}\n{question}'

response = openai.ChatCompletion.create(
model=MODEL,
messages=[
{"role": "user", "content": question_lariska},
]
)

return response['choices'][0]['message']['content']


def get_answer(text):
def get_answer(text:str):
text = text.lower().strip()
logger.debug(f"text: {text}")
try:
rating = 0
answer = None
for key, val in ANSWERS.items():
# Этот код пытается найти наиболее подходящий ответ для заданного входного текста.
# Это простой пример того, как программа может сравнивать различные входные данные
# и находить наилучшее соответствие.
measure = fuzz.token_sort_ratio(key.lower().strip(), text)

if measure > rating and measure != rating:
logger.debug(f"key: {key}, val: {val}, measure: {measure}")
rating = measure
answer = val
return answer, rating
except Exception as e:
logging.exception(e)
return None, 0

async def flood_controlling(*args, **kwargs):
await args[0].reply(MESSAGES['flood_reply'])
def get_ai_answer(question):
question_lariska = f'{PREFIX_QUESTION}\n{question}'
response = openai.ChatCompletion.create(
model=MODEL,messages=[{"role": "user", "content": question_lariska},]
)
return response['choices'][0]['message']['content']


def is_work_day(year, month, day):
def is_work_day(year: int, month: int, day: int) -> str:
url = f'https://raw.githubusercontent.com/d10xa/holidays-calendar/master/json/consultant{year}.json'
response = requests.get(url)
days = json.loads(response.text)
Expand Down
90 changes: 54 additions & 36 deletions lariska_bot/handlers/handler.py
Original file line number Diff line number Diff line change
@@ -1,68 +1,86 @@
import logging

from aiogram import Router
from aiogram.filters import Command, CommandStart
from aiogram import F
from aiogram.types import Message

import pytz
from datetime import datetime, timedelta
from random import choice

import pytz
from aiogram import types
from aiogram.dispatcher.filters import Text
from lariska_bot.config_data import (MESSAGES, REPLICAS, USERS, WORKS_CHATS,
BOT_FIRST_NAME, RATING_LIMIT, L_USERS)
from lariska_bot.handlers.controllers import (get_answer, get_ai_answer)

from lariska_bot import (MESSAGES, REPLICAS, USERS, WORKS_CHATS,
BOT_FIRST_NAME, RATING_LIMIT, FLOOD_RATE, L_USERS)
from lariska_bot.dispatcher import dp
from lariska_bot.handlers.controllers import (flood_controlling, get_answer,
get_ai_answer)

logger = logging.getLogger(__name__)
router = Router()

@dp.message_handler(Text(contains=['говно'], ignore_case=True))
async def skirmish_reply(message: types.Message):
await message.reply(MESSAGES['skirmish'])

@router.message(CommandStart())
async def send_welcome(message: Message):
logger.debug(f'send_welcome.Message: {message.text}')
await message.answer(MESSAGES['welcome'])

@dp.message_handler(Text(contains=['привет', 'с чего начать'],
ignore_case=True))
async def hello_where_to_reply(message: types.Message):
await message.reply(MESSAGES['hello'])
await message.answer(MESSAGES['start_here'])
await message.answer(MESSAGES['start_video'])
await message.answer(MESSAGES['message_links'])

@router.message(Command('privacy'))
async def send_privacy(message: Message):
logger.debug(f'send_privacy.Message: {message.text}')
await message.answer(MESSAGES['privacy'])


@dp.message_handler(Text(contains=['привет'], ignore_case=True))
async def hello_reply(message: types.Message):
@router.message(F.text.lower().contains('привет'))
async def hello_reply(message: Message):
logger.debug(f'hello_reply.Message: {message.text}')
await message.reply(MESSAGES['hello'])


@dp.message_handler(Text(contains=['с чего начать'], ignore_case=True))
async def where_to_begin(message: types.Message):
@router.message(F.text.lower().contains('с чего начать'))
async def where_to_begin(message: Message):
logger.debug(f'where_to_begin.Message: {message.text}')
await message.reply(MESSAGES['start_here'])
await message.answer(MESSAGES['start_video'])
await message.answer(MESSAGES['message_links'])


@dp.message_handler(Text(contains=['https://t.me/oldcoders_bar'],
ignore_case=True))
async def bar_reply(message: types.Message):
@router.message(F.text.lower().contains('https://t.me/oldcoders_bar'))
async def bar_reply(message: Message):
logger.debug(f'bar_reply.Message: {message.text}')
await message.reply(choice(REPLICAS['bar']))


@dp.message_handler(commands=['start', 'help'])
async def send_welcome(message: types.Message):
await message.answer(
MESSAGES['welcome'], parse_mode=types.ParseMode.MARKDOWN)
@router.message(F.text.lower().contains('говно'))
async def skirmish_reply(message: Message):
logger.debug(f'skirmish_reply.Message: {message.text}')
await message.reply(MESSAGES['skirmish'])


@dp.message_handler(content_types=types.ContentTypes.TEXT)
@dp.throttled(flood_controlling, rate=FLOOD_RATE)
async def text_reply(message: types.Message):
@router.message(F.text)
async def text_reply(message: Message):
logger.debug(f'text_reply.Message: {message.text}')
username = message.from_user.username
userid = message.from_user.id

# Если имя пользователя Телеграмм пустое создаем имя пользователя из userid
if username is None:
username = 'User_' + str(userid)
logger.debug(f'У пользователя {userid} не задано имя пользователя! Придумаем имя пользователя: {username}')

user_day = USERS.get(username)
logging.debug(f'User id: {userid}')
logging.debug(f'User name: {username}')
logging.debug(f'User day: {user_day}')

tz = pytz.timezone('Europe/Moscow')
present_date = datetime.now(tz)
logging.debug(f'tz: {tz}, present_date: {present_date}')

current_date = present_date - timedelta(hours=5)
current_day = current_date.day
logging.debug(f'current_day: {current_day}')

if username in USERS and user_day != current_day:
logging.debug(f'Нашли имя {username} в словаре USERS')
USERS[username] = current_day
await message.reply(choice(REPLICAS[username]))
return
Expand All @@ -86,6 +104,6 @@ async def text_reply(message: types.Message):
await message.reply(choice(REPLICAS['n_users']))


@dp.message_handler(content_types=types.ContentTypes.PHOTO)
async def photo_reply(message: types.Message):
await message.reply(choice(REPLICAS['photo_reply']))
@router.message(F.photo)
async def photo_reply(message: Message):
await message.reply(choice(REPLICAS['photo_reply']))
1 change: 0 additions & 1 deletion lariska_bot/res/l_users.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,4 @@
- Lev_Trishankov
- lyrian
- Xeno_MC
- IgorL2024
- Student_Tequila
1 change: 1 addition & 0 deletions lariska_bot/res/users.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,4 @@
- Lev_Trishankov
- Harlok13
#- Student_Tequila
- User_1227611413
Loading