Структура проекта

your_project/
│
├── .env
├── requirements.txt
├── main.py
├── app/
│   ├── __init__.py
│   ├── settings.py
│   ├── views.py
│   ├── handlers/
│   │   ├── __init__.py
│   │   ├── business_handler.py
│   │   ├── events.py
│   ├── middlewares/
│   │   ├── __init__.py
│   │   ├── business_middleware.py
│   ├── utils/
│   │   ├── __init__.py
│   │   ├── openai_actions.py
│   │   ├── check_delay.py
Файл .env

token=12345:abcd
admin_id=123456789
openai_key=sk-abcd
openai_base_url=https://lk.neuroapi.host/v1
redis_host=localhost
delay=10
Файл requirements.txt

aiogram==3.6.0
pydantic-settings==2.2.1
openai==1.29.0
pytz==2024.1
httpx==0.27.0
redis==5.0.4
Файл main.py

import asyncio

from aiogram import Dispatcher
from aiogram.methods import DeleteWebhook

from app.handlers.business_handler import handle_business_message
from app.handlers.events import start_bot, stop_bot
from app.middlewares.business_middleware import BusinessMiddleware
from app.settings import bot

async def start():
    dp = Dispatcher()

    dp.update.middleware(BusinessMiddleware())

    dp.startup.register(start_bot)
    dp.shutdown.register(stop_bot)

    dp.business_message.register(handle_business_message)

    try:
        await bot(DeleteWebhook(drop_pending_updates=True))
        await dp.start_polling(bot)
    finally:
        await bot.session.close()

if __name__ == "__main__":
    asyncio.run(start())
Файл app/settings.py

from aiogram import Bot
from pydantic_settings import BaseSettings
from redis.asyncio import Redis

class Secrets(BaseSettings):
    token: str
    admin_id: int
    openai_key: str
    openai_base_url: str
    redis_host: str
    delay: int

    class Config:
        env_file = ".env"
        env_file_encoding = "utf-8"

secrets = Secrets()

redis_conn = Redis(host=secrets.redis_host)

bot = Bot(token=secrets.token, parse_mode="Markdown")
Файл app/views.py

def start_bot_message():
    return "Бот запущен"

def stop_bot_message():
    return "Бот остановлен"

def system_prompt():
    return """Ты бот помощник и ты должен помогать людям."""
Файл app/middlewares/business_middleware.py

from typing import Callable, Dict, Any, Awaitable

import httpx
from aiogram import BaseMiddleware
from aiogram.dispatcher.middlewares.user_context import EventContext
from aiogram.types import TelegramObject, ChatFullInfo

from app.settings import secrets

class BusinessMiddleware(BaseMiddleware):
    async def __call__(
        self,
        handler: Callable[[TelegramObject, Dict[str, Any]], Awaitable[Any]],
        event: TelegramObject,
        data: Dict[str, Any],
    ) -> Any:
        async with httpx.AsyncClient() as client:
            response = await client.get(
                f"https://api.telegram.org/bot{secrets.token}/getChat?chat_id={secrets.admin_id}"
            )
            chat = response.json()
            full_chat = ChatFullInfo(**chat["result"])

            context: EventContext = data.get("event_context")

            if (
                context.user.id != secrets.admin_id
                and context.business_connection_id
            ):
                return await handler(event, data)
Файл app/utils/openai_actions.py

import httpx
from aiogram.types import Message
from openai import AsyncOpenAI

from app.settings import secrets
from app.views import system_prompt

async def get_chat_completion(message: Message):
    http_client = httpx.AsyncClient(
        limits=httpx.Limits(max_connections=100, max_keepalive_connections=20)
    )
    client = AsyncOpenAI(
        api_key=secrets.openai_key,
        http_client=http_client,
        base_url=secrets.openai_base_url,
    )

    messages = [
        {"role": "system", "content": system_prompt()},
        {"role": "user", "content": message.text},
    ]

    response = await client.chat.completions.create(
        model="gpt-3.5-turbo", messages=messages, max_tokens=1000, temperature=0.8
    )

    return response.choices[0].message.content
Файл app/utils/check_delay.py

import asyncio

from app.settings import redis_conn, secrets

async def check_user_delay(user_id: int):
    last_message_time = await redis_conn.get(f"users:{user_id}")
    if last_message_time:
        time_since_last_message = asyncio.get_event_loop().time() - float(
            last_message_time
        )
        if time_since_last_message < secrets.delay * 60:
            return False
    return True
Файл app/handlers/business_handler.py

import asyncio

from aiogram.types import Message

from app.settings import redis_conn
from app.utils.check_delay import check_user_delay
from app.utils.openai_actions import get_chat_completion

async def handle_business_message(message: Message):
    if await check_user_delay(message.from_user.id) and message.text:
        answer = await get_chat_completion(message)
        await message.reply(answer)
        await redis_conn.set(
            f"users:{message.from_user.id}", asyncio.get_event_loop().time()
        )
Файл app/handlers/events.py

from app.settings import bot, secrets
from app import views

async def start_bot():
    await bot.send_message(secrets.admin_id, views.start_bot_message())

async def stop_bot():
    await bot.send_message(secrets.admin_id, views.stop_bot_message())         (замени Redis)