0
0
mirror of https://gitflic.ru/project/maks1ms/ocab.git synced 2024-12-23 16:23:01 +03:00

Открытое бета тестирование + фиксы первого дня

This commit is contained in:
armatik 2024-05-10 18:18:08 +03:00
parent 370ac7d02b
commit 9d89aee578
21 changed files with 523 additions and 128 deletions

3
.gitignore vendored
View File

@ -6,4 +6,5 @@ env
venv venv
__pycache__ __pycache__
OCAB.db OCAB.db
paths.json src/paths.json
src/core/config.yaml

View File

@ -0,0 +1,21 @@
TELEGRAM:
TOKEN: xxxxxxxxxxxxxxxxxxxxxxxxx
APPROVED_CHAT_ID: "-123456789 | -012345678"
ADMINCHATID: -12345678
DEFAULT_CHAT_TAG: "@alt_gnome_chat"
CHECK_BOT: True
YANDEXGPT:
TOKEN: xxxxxxxxxxxxxxxxxxxxxxxxx
TOKEN_FOR_REQUEST: 8000
TOKEN_FOR_ANSWER: 2000
CATALOGID: xxxxxxxxxxxxxxxxxxxxxxxxx
PROMPT: "Ты чат-бот ..."
STARTWORD: "Бот| Бот, | бот | бот,"
INWORD: "помогите | не работает"
ROLES:
ADMIN: 2
MODERATOR: 1
USER: 0
BOT: 3

24
src/core/logger.py Normal file
View File

@ -0,0 +1,24 @@
import os
import time
async def check_log_file():
# Проверка наличия файла для логов в формате log-dd-mm-yyyy.log
# Если файл существует, то pass
# Если файл не существует, то создаём его. файл лежит в директории src.core.log
current_data = time.strftime("%d-%m-%Y")
log_file = os.path.join(os.path.dirname(__file__), "log/", f"log-{current_data}.log")
if not os.path.exists(log_file):
with open(log_file, 'w') as file:
file.write("Log file created\n")
file.close()
else:
pass
async def log(message):
await check_log_file()
current_data = time.strftime("%d-%m-%Y")
log_file = os.path.join(os.path.dirname(__file__), "log/", f"log-{current_data}.log")
# print(log_file)
with open(log_file, 'a') as file:
file.write(f"{time.strftime('%H:%M:%S')} {message}\n")
file.close()

View File

@ -1,7 +1,10 @@
from aiogram import Dispatcher from aiogram import Dispatcher, Router, F, Bot
from aiogram.types import Message
from src.modules.standard.info.routers import router as info_router
from src.modules.standard.admin.routers import router as admin_router from src.modules.standard.admin.routers import router as admin_router
from src.modules.external.yandexgpt.routers import router as yandexgpt_router from src.modules.standard.message_processing.message_api import router as process_message
from src.modules.standard.welcome.routers import router as welcome_router
async def include_routers(dp: Dispatcher): async def include_routers(dp: Dispatcher):
@ -9,5 +12,7 @@ async def include_routers(dp: Dispatcher):
Подключение роутеров в бота Подключение роутеров в бота
dp.include_router() dp.include_router()
""" """
dp.include_router(yandexgpt_router) dp.include_router(info_router)
dp.include_router(admin_router) dp.include_router(admin_router)
dp.include_router(process_message)

View File

@ -2,12 +2,18 @@ from aiogram import Bot
from aiogram.types import Message from aiogram.types import Message
from src.modules.external.yandexgpt.yandexgpt import * from src.modules.external.yandexgpt.yandexgpt import *
from src.modules.standard.config.config import get_yandexgpt_token, get_yandexgpt_catalog_id, get_yandexgpt_prompt from src.modules.standard.config.config import get_yandexgpt_token, get_yandexgpt_catalog_id, get_yandexgpt_prompt
from src.modules.standard.database.db_api import add_message
from src.core.logger import log
import asyncio import asyncio
async def answer_to_message(message: Message, bot: Bot): async def answer_to_message(message: Message, bot: Bot):
# print("answer_to_message")
await log("answer_to_message")
yagpt = YandexGPT(get_yandexgpt_token(), get_yandexgpt_catalog_id()) yagpt = YandexGPT(get_yandexgpt_token(), get_yandexgpt_catalog_id())
text = message.text text = message.text
prompt = get_yandexgpt_prompt() prompt = get_yandexgpt_prompt()
response = await yagpt.async_yandexgpt(system_prompt=prompt, input_messages=text) # response = await yagpt.async_yandexgpt(system_prompt=prompt, input_messages=text)
await message.reply(response, parse_mode="Markdown") response = await yagpt.yandexgpt_request(chat_id = message.chat.id, message_id = message.message_id, type = "yandexgpt")
reply = await message.reply(response, parse_mode="Markdown")
add_message(reply, message_ai_model="yandexgpt")

View File

@ -3,5 +3,5 @@ from aiogram import Router, F
from src.modules.external.yandexgpt.handlers import answer_to_message from src.modules.external.yandexgpt.handlers import answer_to_message
router = Router() router = Router()
# Если сообщение содержит в начале текст "Гномик" или "гномик", то вызывается функция answer_to_message # Если сообщение содержит в начале текст "Гномик" или "гномик" или отвечает на сообщение бота, то вызывается функция answer_to_message
router.message.register(answer_to_message, F.text.startswith("Гномик") | F.text.startswith("гномик")) router.message.register(answer_to_message, F.text.startswith("Гномик") | F.text.startswith("гномик"))

View File

@ -2,6 +2,7 @@ import requests
import json import json
import asyncio import asyncio
import aiohttp import aiohttp
from src.core.logger import log
from ...standard.database import * from ...standard.database import *
from ...standard.config.config import * from ...standard.config.config import *
@ -23,28 +24,44 @@ class YandexGPT:
self.token = token self.token = token
self.catalog_id = catalog_id self.catalog_id = catalog_id
async def async_token_check(self, messages, gpt, max_tokens, del_msg_id=1):
url = "https://llm.api.cloud.yandex.net/foundationModels/v1/tokenize"
while True:
text = ""
for message in messages:
text += message["text"]
try:
response = requests.post(url, json={"model": gpt, "text": text})
except Exception as e: # TODO: Переделать обработку ошибок
print(e)
continue
if int(response.text) < max_tokens - 2000:
break
else:
messages.pop(del_msg_id)
return messages
async def async_request(self, url, headers, prompt) -> dict: async def async_request(self, url, headers, prompt) -> dict:
async with aiohttp.ClientSession() as session: async with aiohttp.ClientSession() as session:
async with session.post(url, headers=headers, json=prompt) as response: async with session.post(url, headers=headers, json=prompt) as response:
return await response.json() return await response.json()
async def async_token_check(self, messages, gpt, max_tokens, stream, temperature, del_msg_id=1):
url = "https://llm.api.cloud.yandex.net/foundationModels/v1/tokenizeCompletion"
headers = {
"Content-Type": "application/json",
"Authorization": f"Api-Key {self.token}"
}
answer_token = get_yandexgpt_token_for_answer()
while True:
try:
request = {
"modelUri": gpt,
"completionOptions": {
"stream": stream,
"temperature": temperature,
"maxTokens": max_tokens
},
"messages": messages
}
response = await self.async_request(url=url, headers=headers, prompt=request)
except Exception as e: # TODO: Переделать обработку ошибок
# print(e)
await log(f"Error: {e}")
continue
if int(len(response["tokens"])) < (max_tokens - answer_token):
break
else:
try:
messages.pop(del_msg_id)
except IndexError:
Exception("IndexError: list index out of range")
return messages
async def async_yandexgpt_lite(self, system_prompt, input_messages, stream=False, temperature=0.6, max_tokens=8000): async def async_yandexgpt_lite(self, system_prompt, input_messages, stream=False, temperature=0.6, max_tokens=8000):
url = "https://llm.api.cloud.yandex.net/foundationModels/v1/completion" url = "https://llm.api.cloud.yandex.net/foundationModels/v1/completion"
gpt = f"gpt://{self.catalog_id}/yandexgpt-lite/latest" gpt = f"gpt://{self.catalog_id}/yandexgpt-lite/latest"
@ -71,7 +88,14 @@ class YandexGPT:
response = requests.post(url, headers=headers, json=prompt).text response = requests.post(url, headers=headers, json=prompt).text
return json.loads(response)["result"]["alternatives"][0]["message"]["text"] return json.loads(response)["result"]["alternatives"][0]["message"]["text"]
async def async_yandexgpt(self, system_prompt, input_messages, stream=False, temperature=0.6, max_tokens=8000): async def async_yandexgpt(
self,
system_prompt,
input_messages,
stream=False,
temperature=0.6,
max_tokens=get_yandexgpt_token_for_request()
):
url = "https://llm.api.cloud.yandex.net/foundationModels/v1/completion" url = "https://llm.api.cloud.yandex.net/foundationModels/v1/completion"
gpt = f"gpt://{self.catalog_id}/yandexgpt/latest" gpt = f"gpt://{self.catalog_id}/yandexgpt/latest"
headers = { headers = {
@ -79,13 +103,14 @@ class YandexGPT:
"Authorization": f"Api-Key {self.token}" "Authorization": f"Api-Key {self.token}"
} }
messages = [{"role": "system", "text": system_prompt}] messages = []
messages.append({"role": "user", "text": input_messages}) messages.append({"role": "system", "text": system_prompt})
# for message in input_messages: for message in input_messages:
# messages.append(message) messages.append(message)
# messages = await self.async_token_check(messages, gpt, max_tokens)
prompt = { messages = await self.async_token_check(messages, gpt, max_tokens, stream, temperature)
request = {
"modelUri": gpt, "modelUri": gpt,
"completionOptions": { "completionOptions": {
"stream": stream, "stream": stream,
@ -94,7 +119,7 @@ class YandexGPT:
}, },
"messages": messages "messages": messages
} }
response = await self.async_request(url=url, headers=headers, prompt=prompt) response = await self.async_request(url=url, headers=headers, prompt=request)
return response["result"]["alternatives"][0]["message"]["text"] return response["result"]["alternatives"][0]["message"]["text"]
@ -153,21 +178,21 @@ class YandexGPT:
# TODO: Сделать функцию Vision # TODO: Сделать функцию Vision
return 0 return 0
async def collect_messages(self, message_id, chat_id, start_message_id): async def collect_messages(self, message_id, chat_id):
messages = [] messages = []
# Собираем цепочку сообщений в формате: [{"role": "user", "text": "<Имя_пользователя>: Привет!"}, # Собираем цепочку сообщений в формате: [{"role": "user", "text": "<Имя_пользователя>: Привет!"},
# {"role": "assistant", "text": "Привет!"}] # {"role": "assistant", "text": "Привет!"}]
while True: while True:
message = db_api.get_message_text(chat_id, message_id) message = db_api.get_message_text(chat_id, message_id)
if db_api.get_message_ai_model(chat_id, start_message_id) != None: if db_api.get_message_ai_model(chat_id, message_id) != None:
messages.append({"role": "assistant", "text": message}) messages.append({"role": "assistant", "text": message})
else: else:
sender_name = db_api.get_user_name(db_api.get_message_sender_id(chat_id, start_message_id)) sender_name = db_api.get_user_name(db_api.get_message_sender_id(chat_id, message_id))
messages.append({"role": "user", "text": sender_name + ": " + message}) messages.append({"role": "user", "text": sender_name + ": " + message})
message_id = db_api.get_message_answer_to_message_id(chat_id, message_id) message_id = db_api.get_answer_to_message_id(chat_id, message_id)
if message_id is None: if message_id is None:
break break
return messages.reverse() return list(reversed(messages))
async def collecting_messages_for_history(self, start_message_id, end_message_id, chat_id): async def collecting_messages_for_history(self, start_message_id, end_message_id, chat_id):
messages = [] messages = []
@ -195,11 +220,13 @@ class YandexGPT:
stream=False, temperature=0.6, max_tokens=8000 stream=False, temperature=0.6, max_tokens=8000
) )
elif type == "yandexgpt": elif type == "yandexgpt":
# print("yandexgpt_request")
await log("yandexgpt_request")
messages = await self.collect_messages(message_id, chat_id) messages = await self.collect_messages(message_id, chat_id)
return await self.async_yandexgpt( return await self.async_yandexgpt(
system_prompt=get_yandexgpt_prompt(), system_prompt=get_yandexgpt_prompt(),
input_messages=messages, input_messages=messages,
stream=False, temperature=0.6, max_tokens=8000 stream=False, temperature=0.6, max_tokens=get_yandexgpt_token_for_request()
) )
elif type == "yandexgpt-translate": elif type == "yandexgpt-translate":
return await self.async_yandexgpt_translate( return await self.async_yandexgpt_translate(

View File

@ -1,5 +1,7 @@
from aiogram import Bot from aiogram import Bot
from aiogram.types import Message from aiogram.types import Message
from src.modules.standard.config.config import get_default_chat_tag
import time
async def delete_message(message: Message, bot: Bot): async def delete_message(message: Message, bot: Bot):
@ -10,4 +12,35 @@ async def error_access(message: Message, bot: Bot):
await message.reply("Вы не админ/модератор") await message.reply("Вы не админ/модератор")
async def get_chat_id(message: Message, bot: Bot): async def get_chat_id(message: Message, bot: Bot):
await message.reply(f"ID данного чата: `{message.chat.id}`", parse_mode="MarkdownV2") await message.reply(f"ID данного чата: `{message.chat.id}`", parse_mode="MarkdownV2")
async def chat_not_in_approve_list(message: Message, bot: Bot):
await message.reply(
f"Бот недоступен в данном чате, пожалуйста,"
f" обратитесь к администратору для добавления чата в список доступных или перейдите в чат "
f"{get_default_chat_tag()}"
)
await get_chat_id(message, bot)
async def mute_user(chat_id: int, user_id: int, time: int, bot: Bot):
# *, can_send_messages: bool | None = None, can_send_audios: bool | None = None, can_send_documents: bool | None = None, can_send_photos: bool | None = None, can_send_videos: bool | None = None, can_send_video_notes: bool | None = None, can_send_voice_notes: bool | None = None, can_send_polls: bool | None = None, can_send_other_messages: bool | None = None, can_add_web_page_previews: bool | None = None, can_change_info: bool | None = None, can_invite_users: bool | None = None, can_pin_messages: bool | None = None, can_manage_topics: bool | None = None, **extra_data: Any)
mutePermissions = {
"can_send_messages": False,
"can_send_audios": False,
"can_send_documents": False,
"can_send_photos": False,
"can_send_videos": False,
"can_send_video_notes": False,
"can_send_voice_notes": False,
"can_send_polls": False,
"can_send_other_messages": False,
"can_add_web_page_previews": False,
"can_change_info": False,
"can_invite_users": False,
"can_pin_messages": False,
"can_manage_topics": False
}
end_time = time + int(time.time())
await bot.restrict_chat_member(chat_id, user_id, until_date=end_time, **mutePermissions)

View File

@ -1,9 +1,13 @@
from aiogram import Router, F from aiogram import Router, F
from src.modules.standard.admin.handlers import delete_message, error_access, get_chat_id from src.modules.standard.admin.handlers import delete_message, error_access, get_chat_id, chat_not_in_approve_list
from src.modules.standard.filters.admin import ChatModerOrAdminFilter from src.modules.standard.filters.filters import ChatModerOrAdminFilter, ChatNotInApproveFilter
router = Router() router = Router()
# Если сообщение содержит какой либо текст и выполняется фильтр ChatNotInApproveFilter, то вызывается функция chat_not_in_approve_list
router.message.register(chat_not_in_approve_list, ChatNotInApproveFilter(), F.text)
router.message.register(get_chat_id, ChatModerOrAdminFilter(), F.text == '/chatID') router.message.register(get_chat_id, ChatModerOrAdminFilter(), F.text == '/chatID')
router.message.register(delete_message, ChatModerOrAdminFilter(), F.text == '/rm') router.message.register(delete_message, ChatModerOrAdminFilter(), F.text == '/rm')

View File

@ -17,6 +17,20 @@ config = get_config()
def get_telegram_token() -> str: def get_telegram_token() -> str:
return config["TELEGRAM"]["TOKEN"] return config["TELEGRAM"]["TOKEN"]
def get_telegram_check_bot() -> bool:
return config["TELEGRAM"]["CHECK_BOT"]
def get_aproved_chat_id() -> list:
# Возваращем сплитованный список id чатов в формате int
return [int(chat_id) for chat_id in config["TELEGRAM"]["APPROVED_CHAT_ID"].split(" | ")]
def get_user_role_name(role_number) -> dict:
# Возвращаем название роли пользвателя по номеру роли, если такой роли нет, возвращаем неизвестно
return config["ROLES"].get(role_number, "Неизвестно")
def get_default_chat_tag() -> str:
return config["TELEGRAM"]["DEFAULT_CHAT_TAG"]
def get_yandexgpt_token() -> str: def get_yandexgpt_token() -> str:
return config["YANDEXGPT"]["TOKEN"] return config["YANDEXGPT"]["TOKEN"]
@ -26,7 +40,21 @@ def get_yandexgpt_catalog_id() -> str:
def get_yandexgpt_prompt() -> str: def get_yandexgpt_prompt() -> str:
return config["YANDEXGPT"]["PROMPT"] return config["YANDEXGPT"]["PROMPT"]
def get_yandexgpt_start_words() -> list:
return config["YANDEXGPT"]["STARTWORD"].split(" | ")
def get_yandexgpt_in_words() -> list:
return config["YANDEXGPT"]["INWORD"].split(" | ")
def get_yandexgpt_token_for_request() -> int:
return config["YANDEXGPT"]["TOKEN_FOR_REQUEST"]
def get_yandexgpt_token_for_answer() -> int:
return config["YANDEXGPT"]["TOKEN_FOR_ANSWER"]
def get_access_rights() -> dict: def get_access_rights() -> dict:
return get_config()["ACCESS_RIGHTS"] return get_config()["ACCESS_RIGHTS"]

View File

@ -6,6 +6,7 @@ from .models.chat_stats import ChatStats
from ....service import paths from ....service import paths
from ..exceptions.module_exceptions import MissingModuleName, NotExpectedModuleName from ..exceptions.module_exceptions import MissingModuleName, NotExpectedModuleName
import peewee as pw import peewee as pw
from aiogram.types import Message
def connect_database(is_test: bool = False, module: str | None = None): def connect_database(is_test: bool = False, module: str | None = None):
@ -39,7 +40,7 @@ def add_chat(chat_id, chat_name, chat_type=10, chat_stats=0):
chat, created = Chats.get_or_create(id=chat_id, defaults={ chat, created = Chats.get_or_create(id=chat_id, defaults={
'chat_name': chat_name, 'chat_name': chat_name,
'chat_type': chat_type, 'chat_type': chat_type,
'chat_stats': chat_stats, 'chat_all_stat': chat_stats,
}) })
if not created: if not created:
# Обновить существующий чат, если он уже существует # Обновить существующий чат, если он уже существует
@ -49,7 +50,12 @@ def add_chat(chat_id, chat_name, chat_type=10, chat_stats=0):
chat.save() chat.save()
def add_user(user_id, user_name, user_tag=None, user_role=0, user_stats=0, user_rep=0): def add_user(user_id, user_first_name, user_last_name=None, user_tag=None, user_role=0, user_stats=0, user_rep=0):
if user_last_name is None:
user_name = user_first_name
else:
user_name = user_first_name + " " + user_last_name
user, created = Users.get_or_create(id=user_id, defaults={ user, created = Users.get_or_create(id=user_id, defaults={
'user_tag': user_tag, 'user_tag': user_tag,
'user_name': user_name, 'user_name': user_name,
@ -67,15 +73,18 @@ def add_user(user_id, user_name, user_tag=None, user_role=0, user_stats=0, user_
user.save() user.save()
def add_message(message_chat_id, message_id, message_sender_id, message_text, answer_to_message_id=None, def add_message(message: Message, message_ai_model=None):
message_ai_model=None): if message.reply_to_message:
answer_to_message_id = message.reply_to_message.message_id
else:
answer_to_message_id = None
Messages.create( Messages.create(
message_chat_id=message_chat_id, message_chat_id=message.chat.id,
message_id=message_id, message_id=message.message_id,
message_sender_id=message_sender_id, message_sender_id=message.from_user.id,
answer_to_message_id=answer_to_message_id, answer_to_message_id=answer_to_message_id,
message_ai_model=message_ai_model, message_ai_model=message_ai_model,
message_text=message_text message_text=message.text
) )
@ -127,6 +136,10 @@ def get_user_tag(user_id):
user = Users.get_or_none(Users.id == user_id) user = Users.get_or_none(Users.id == user_id)
return user.user_tag if user else None return user.user_tag if user else None
def get_user_id(user_tag):
user = Users.get_or_none(Users.user_tag == user_tag)
return user.id if user else None
def get_user_name(user_id): def get_user_name(user_id):
user = Users.get_or_none(Users.id == user_id) user = Users.get_or_none(Users.id == user_id)
@ -148,7 +161,11 @@ def get_user_rep(user_id):
return user.user_rep if user else None return user.user_rep if user else None
def change_user_name(user_id, new_user_name): def change_user_name(user_id, user_first_name, user_last_name=None):
if user_last_name is None:
new_user_name = user_first_name
else:
new_user_name = user_first_name + " " + user_last_name
query = Users.update(user_name=new_user_name).where(Users.id == user_id) query = Users.update(user_name=new_user_name).where(Users.id == user_id)
query.execute() query.execute()

View File

@ -1,13 +0,0 @@
from aiogram.filters import BaseFilter
from aiogram.types import Message
from aiogram import Bot
from src.modules.standard.roles.roles import Roles
class ChatModerOrAdminFilter(BaseFilter):
async def __call__(self, message: Message, bot: Bot) -> bool:
user_id = message.from_user.id
roles = Roles()
admins = await bot.get_chat_administrators(message.chat.id)
return await roles.check_admin_permission(user_id) or \
await roles.check_moderator_permission(user_id) or any(user_id == admin.user.id for admin in admins)

View File

@ -0,0 +1,29 @@
from aiogram.filters import BaseFilter
from aiogram.types import Message
from aiogram import Bot
from src.modules.standard.roles.roles import Roles
from src.modules.standard.config.config import get_aproved_chat_id
from src.core.logger import log
class ChatModerOrAdminFilter(BaseFilter):
async def __call__(self, message: Message, bot: Bot) -> bool:
user_id = message.from_user.id
roles = Roles()
admins = await bot.get_chat_administrators(message.chat.id)
return await roles.check_admin_permission(user_id) or \
await roles.check_moderator_permission(user_id) or any(user_id == admin.user.id for admin in admins)
class ChatNotInApproveFilter(BaseFilter):
async def __call__(self, message: Message, bot: Bot) -> bool:
# print("chat_check")
await log("chat_check")
chat_id = message.chat.id
if chat_id in get_aproved_chat_id():
# print(f"Chat in approve list: {chat_id}")
await log(f"Chat in approve list: {chat_id}")
return False
else:
# print(f"Chat not in approve list: {chat_id}")
await log(f"Chat not in approve list: {chat_id}")
return True

View File

View File

@ -0,0 +1,60 @@
from aiogram import Bot
from aiogram.types import Message
from src.modules.standard.config.config import get_user_role_name
from src.modules.standard.roles.roles import Roles
from src.modules.standard.database.db_api import *
from src.core.logger import log
async def get_info_answer_by_id(message: Message, bot: Bot, user_id: int):
if get_message_ai_model(message.chat.id, message.message_id) is not None:
await message.reply("Это сообщение было сгенерировано ботом используя модель: " + get_message_ai_model(message.chat.id, message.message_id))
elif user_id == bot.id:
await message.reply("Это сообщение было отправлено ботом")
elif get_user(user_id) is None:
await message.reply("Пользователь не найден")
# print(get_user(user_id))
await log(f"Пользователь не найден: {user_id}, {get_user(user_id)}")
else:
roles = Roles()
answer = (
f"Пользователь: {get_user_name(user_id)}\n"
f"Роль: {await roles.get_role_name(role_id=get_user_role(user_id))}\n"
f"Тег: @{get_user_tag(user_id)}\n"
f"Кол-во сообщений: {get_user_all_stats(user_id)}\n"
f"Репутация: {get_user_rep(user_id)}"
)
await message.reply(answer)
async def get_user_info(message: Message, bot: Bot):
# Проверяем содержимое сообщения, если содержит вторым элементом тег пользователя, то выводим информацию о нем
# Если сообщение отвечает на другое сообщение, то выводим информацию о пользователе, на чье сообщение был ответ
# Если это бот то выводим информацию что это бот и какая модель yandexgpt используется
try:
if len(message.text.split()) > 1 and message.text.split()[1].startswith("@"):
user_tag = message.text.split()[1][1:]
user_id = get_user_id(user_tag)
if user_id:
await get_info_answer_by_id(message, bot, user_id)
else:
await message.reply(f"Пользователь с тегом @{user_tag} не найден")
elif message.reply_to_message:
user_id = message.reply_to_message.from_user.id
await get_info_answer_by_id(message, bot, user_id)
else:
await get_info_answer_by_id(message, bot, message.from_user.id)
except Exception as e:
await message.reply("В вашем запросе что-то пошло не так,"
" попробуйте запросить информацию о пользователе по его тегу или ответив на его сообщение")
# print(e)
await log(e)
async def get_chat_info(message: Message, bot: Bot):
answer = (
f"*Название чата:* {message.chat.title}\n"
f"*ID чата:* `{message.chat.id}`\n \n"
f"*Суммарное количество сообщений в чате:* {get_chat_all_stat(message.chat.id)}\n"
f"*Количество пользователей в чате:* {await bot.get_chat_member_count(message.chat.id)}\n"
f"*Количество администраторов в чате:* {len(await bot.get_chat_administrators(message.chat.id))}"
)
await message.reply(answer, parse_mode="MarkdownV2")

View File

@ -0,0 +1,8 @@
from aiogram import Router, F
from src.modules.standard.info.handlers import get_user_info, get_chat_info
router = Router()
router.message.register(get_user_info, F.text.startswith("/info") == True)
router.message.register(get_chat_info, F.text.startswith("/chatinfo") == True)

View File

@ -0,0 +1,99 @@
from aiogram import Router, F, Bot, types
from src.modules.external.yandexgpt.handlers import answer_to_message
from src.modules.standard.database.db_api import *
from src.modules.standard.config.config import get_yandexgpt_start_words, get_yandexgpt_in_words, get_aproved_chat_id
from src.core.logger import log
async def chat_check(message: types.Message):
# Проверка наличия id чата в базе данных чатов
# Если чата нет в базе данных, то проверяем его в наличии в конфиге и если он там есть то добавляем его в БД
# Если чат есть в базе данных, то pass
if get_chat(message.chat.id) is None:
if message.chat.id in get_aproved_chat_id():
# print(f"Chat in approve list: {message.chat.id} {message.chat.title}")
await log(f"Chat in approve list: {message.chat.id} {message.chat.title}")
add_chat(message.chat.id, message.chat.title)
# print(f"Chat added: {message.chat.id} {message.chat.title}")
await log(f"Chat added: {message.chat.id} {message.chat.title}")
else:
# print(f"Chat not in approve list: {message.chat.id} {message.chat.title}")
await log(f"Chat not in approve list: {message.chat.id} {message.chat.title}")
pass
else:
# Проверяем обновление названия чата
chat = get_chat(message.chat.id)
if chat.chat_name != message.chat.title:
chat.chat_name = message.chat.title
chat.save()
# print(f"Chat updated: {message.chat.id} {message.chat.title}")
await log(f"Chat updated: {message.chat.id} {message.chat.title}")
else:
# print(f"Chat already exists: {message.chat.id} {message.chat.title}")
await log(f"Chat already exists: {message.chat.id} {message.chat.title}")
pass
async def user_check(message: types.Message):
# Проверка наличия id пользователя в базе данных пользователей
# Если пользователя нет в базе данных, то добавляем его
# Если пользователь есть в базе данных, то pass
current_user_name = ""
if message.from_user.last_name is None:
current_user_name = message.from_user.first_name
else:
current_user_name = message.from_user.first_name + " " + message.from_user.last_name
if get_user(message.from_user.id) is None:
add_user(message.from_user.id,
message.from_user.first_name, message.from_user.last_name,
message.from_user.username)
# print(f"User added: {message.from_user.id} {message.from_user.first_name} {message.from_user.last_name}")
await log(f"User added: {message.from_user.id} {current_user_name}")
else:
# print(f"User already exists: {message.from_user.id} {message.from_user.first_name} {message.from_user.last_name} {message.from_user.username}")
await log(f"User already exists: {message.from_user.id} {current_user_name} {message.from_user.username}")
# Проверяем обновление имени пользователя
if get_user_name(message.from_user.id) != current_user_name:
change_user_name(message.from_user.id, current_user_name)
# print(f"User updated: {message.from_user.id} {message.from_user.first_name} {message.from_user.last_name}")
await log(f"User name updated: {message.from_user.id} {current_user_name}")
# Проверяем обновление username пользователя
if get_user_tag(message.from_user.id) != message.from_user.username:
change_user_tag(message.from_user.id, message.from_user.username)
# print(f"User updated: {message.from_user.id} {message.from_user.username}")
await log(f"User tag updated: {message.from_user.id} {message.from_user.username}")
pass
async def add_stats(message: types.Message):
# Добавляем пользователю и чату статистику
update_chat_all_stat(message.chat.id)
update_user_all_stat(message.from_user.id)
async def message_processing(message: types.Message, bot: Bot):
await chat_check(message)
await user_check(message)
await add_stats(message)
add_message(message)
# Если сообщение в начале содержит слово из списка или внутри сообщения содержится слово из списка или сообщение отвечает на сообщение бота
if ((message.text.split(" ")[0] in get_yandexgpt_start_words())
or (any(word in message.text for word in get_yandexgpt_in_words()))):
# print("message_processing")
await log("message_processing")
await answer_to_message(message, bot)
elif message.reply_to_message is not None:
if message.reply_to_message.from_user.is_bot:
# print("message_processing")
await log("message_processing")
await answer_to_message(message, bot)
router = Router()
# Если сообщение содержит текст то вызывается функция message_processing
router.message.register(message_processing, F.text)

View File

@ -45,69 +45,31 @@ class Moderation:
async def ban_user(self, chat_id, user_id, bot: aiogram.Bot): async def ban_user(self, chat_id, user_id, bot: aiogram.Bot):
await bot.ban_chat_member(chat_id, user_id) await bot.ban_chat_member(chat_id, user_id)
async def mute_user(self, message, chat_id, user_id, bot: aiogram.Bot, time=0): async def mute_user(chat_id, user_id, time, bot: aiogram.Bot):
# Проверка что отправитель является администратором чата mutePermissions = {
# Проверяем мин "can_send_messages": False,
try: "can_send_audios": False,
if check_admin_permission(message.from_user.id): "can_send_documents": False,
# Проверка отвечает ли сообщение на другое сообщение "can_send_photos": False,
if message.reply_to_message is not None: "can_send_videos": False,
time = message.text.split(' ')[1] "can_send_video_notes": False,
# получаем id отправителя сообщение на которое отвечает message "can_send_voice_notes": False,
target_id = message.reply_to_message.from_user.id "can_send_polls": False,
target_name = \ "can_send_other_messages": False,
cursor.execute("SELECT user_name FROM user_list WHERE user_id = ?", (target_id,)).fetchone()[0] "can_add_web_page_previews": False,
# Проверка, что человек пользователь "can_change_info": False,
if cursor.execute("SELECT user_role FROM user_list WHERE user_id = ?", (target_id,)).fetchone()[ "can_invite_users": False,
0] == 0: "can_pin_messages": False,
# ограничения прав пользователя по отправке сообщений на time секунд "can_manage_topics": False
time_sec = await time_to_seconds(message.text.split(' ')[1]) }
if time_sec <= 30 or time_sec >= 31536000: end_time = time + int(time.time())
await message.reply("Время мута должно быть больше 30 секунд и меньше 365 дней") await bot.restrict_chat_member(chat_id, user_id, until_date=end_time, **mutePermissions)
return
date_string = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
date_time = datetime.datetime.strptime(date_string, "%Y-%m-%d %H:%M:%S") async def unmute_user(chat_id, user_id, bot: aiogram.Bot):
unix_time = int(mktime(date_time.timetuple())) await bot.restrict_chat_member(chat_id, user_id, use_independent_chat_permissions=True)
await bot.restrict_chat_member(message.chat.id, target_id, until_date=unix_time + time_sec,
permissions=types.ChatPermissions(can_send_messages=False)) async def ban_user(chat_id, user_id, bot: aiogram.Bot):
await message.reply( await bot.ban_chat_member(chat_id, user_id)
f"Пользователь {target_name} замьючен на {await short_time_to_time(time)}")
else:
await message.reply(
f"Пользователь [{target_name}](tg://user?id={target_id}) является {await get_role(target_id)} и не может быть замьючен",
parse_mode='Markdown')
return
else:
target_tag = message.text.split(' ')[1]
target_tag = target_tag[1:]
target_id = int(
cursor.execute("SELECT user_id FROM user_list WHERE user_name = ?", (target_tag,)).fetchone()[
0])
target_name = \
cursor.execute("SELECT user_name FROM user_list WHERE user_id = ?", (target_id,)).fetchone()[0]
# ограничения прав пользователя по отправке сообщений на time секунд
time_mute = message.text.split(' ')[2]
if cursor.execute("SELECT user_role FROM user_list WHERE user_id = ?", (target_id,)).fetchone()[
0] == 0:
# ограничения прав пользователя по отправке сообщений на time секунд
time_sec = await time_to_seconds(message.text.split(' ')[2])
if time_sec <= 30 or time_sec >= 31536000:
await message.reply("Время мута должно быть больше 30 секунд и меньше 365 дней")
return
date_string = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
date_time = datetime.datetime.strptime(date_string, "%Y-%m-%d %H:%M:%S")
unix_time = int(mktime(date_time.timetuple()))
await bot.restrict_chat_member(message.chat.id, target_id, until_date=unix_time + time_sec,
permissions=types.ChatPermissions(can_send_messages=False))
await message.reply(
f"Пользователь {target_name} замьючен на {await short_time_to_time(time_mute)}.")
else:
await message.reply(
f"Пользователь [{target_name}](tg://user?id={target_id}) является {await get_role(target_id)} и не может быть замьючен",
parse_mode="Markdown")
return
except:
await message.reply("Ошибка данных. Возможно пользователь ещё ничего не написал.")

View File

@ -0,0 +1,74 @@
from aiogram import Bot
from aiogram.types import Message
from src.modules.standard.config.config import get_telegram_check_bot
from src.modules.standard.roles.roles import Roles
from src.modules.standard.database.db_api import *
from src.modules.standard.moderation.moderation import mute_user, unmute_user, ban_user
from aiogram.utils.keyboard import InlineKeyboardBuilder
from aiogram.types import inline_keyboard_button as types
import random, asyncio
from threading import Thread
async def create_math_task():
first_number = random.randint(1, 100)
second_number = random.randint(1, 100)
answer = first_number + second_number
fake_answers = []
for i in range(3):
diff = random.randint(1, 10)
diff_sign = random.choice(["+", "-"])
fake_answers.append(answer + diff if diff_sign == "+" else answer - diff)
fake_answers.append(answer)
random.shuffle(fake_answers)
return [answer, first_number, second_number, fake_answers]
async def ban_user_timer(chat_id: int, user_id: int, time: int, bot: Bot):
await asyncio.sleep(time)
if get_user(user_id) is not None:
pass
else:
await ban_user()
async def check_new_user(message: Message, bot: Bot):
print("check_new_user")
if get_telegram_check_bot():
# Проверяем наличие пользователя в базе данных
if get_user(message.from_user.id) is None:
# Выдаём пользователю ограничение на отправку сообщений на 3 минуты
ban_task = Thread(target=ban_user_timer, args=(message.chat.id, message.from_user.id, 180, bot))
ban_task.start()
# Создаём задачу с отложенным выполнением на 3 минуты
math_task = await create_math_task()
text = f"{math_task[1]} + {math_task[2]}"
builder = InlineKeyboardBuilder()
for answer in math_task[3]:
if answer == math_task[0]:
builder.add(types.InlineKeyboardButton(
text=answer,
callback_data=f"check_math_task_true")
)
else:
builder.add(types.InlineKeyboardButton(
text=answer,
callback_data=f"check_math_task_false")
)
await message.reply(
f"Приветствую, {message.from_user.first_name}!\n"
f"Для продолжения работы с ботом, пожалуйста, решите математический пример в течении 3х минут:\n"
f"*{text}*",
reply_markup=builder.as_markup()
)
async def math_task_true(message: Message, bot: Bot):
await message.reply(f"Верно! Добро пожаловать в чат {message.from_user.first_name}")
await unmute_user(message.chat.id, message.from_user.id, bot)
add_user(message.from_user.id,
message.from_user.first_name + ' ' + message.from_user.last_name,
message.from_user.username)
pass

View File

@ -0,0 +1,10 @@
from aiogram import Router, F
from src.modules.standard.welcome.handlers import check_new_user
router = Router()
# Если в чат пришел новый пользователь
router.message.register(check_new_user, F.new_chat_members.exists())
# Ловин колбеки от кнопок с callback_data=f"check_math_task_true"
router.callback_query.register(check_new_user, F.callback_data == "check_math_task_true")