```python
# main.py
import os
import string
import random
import asyncio
import logging
import json
from functools import wraps

from telegram import (
    Update,
    InlineKeyboardButton,
    InlineKeyboardMarkup,
    ReplyKeyboardMarkup,
)
from telegram.ext import (
    ApplicationBuilder,
    CommandHandler,
    ContextTypes,
    CallbackQueryHandler,
)
from dotenv import load_dotenv
import aiosqlite  # Асинхронная работа с SQLite
from gradio_client import Client

# --------------------- Конфигурация и Настройка ---------------------

# Загрузка переменных окружения из .env файла
load_dotenv()

BOT_TOKEN = os.getenv('BOT_TOKEN')
ADMIN_USER_ID = os.getenv('ADMIN_USER_ID')  # ID администратора для уведомлений
SBERBANK_NUMBER = os.getenv('SBERBANK_NUMBER')
SBERBANK_AMOUNT = os.getenv('SBERBANK_AMOUNT')
O1MINI_CLIENT_URL = os.getenv('O1MINI_CLIENT_URL')  # URL вашего нейросетевого API

# Проверка наличия всех необходимых переменных окружения
if not all([BOT_TOKEN, ADMIN_USER_ID, SBERBANK_NUMBER, SBERBANK_AMOUNT, O1MINI_CLIENT_URL]):
    raise ValueError("Пожалуйста, убедитесь, что все переменные окружения корректно настроены.")

# Настройка логирования
logging.basicConfig(
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
    level=logging.INFO
)
logger = logging.getLogger(__name__)

# --------------------- Вспомогательные Функции ---------------------

def generate_unique_id(length=8):
    """Генерация уникального алфавитно-цифрового ID."""
    characters = string.ascii_letters + string.digits
    return ''.join(random.choice(characters) for _ in range(length))

async def init_db():
    """Инициализация базы данных SQLite с необходимой таблицей."""
    async with aiosqlite.connect('payments.db') as db:
        await db.execute('''
            CREATE TABLE IF NOT EXISTS payments (
                user_id INTEGER PRIMARY KEY,
                unique_id TEXT UNIQUE,
                payment_status TEXT,
                requests_left INTEGER DEFAULT 0,
                chat_counter INTEGER DEFAULT 0,
                chatbot TEXT DEFAULT '[]'
            )
        ''')
        await db.commit()

def parse_neural_response(response, user_query, chat_counter, chatbot):
    """
    Парсинг ответа нейросети и обновление состояния чата.
    
    Поддерживает несколько форматов ответа.
    """
    try:
        if isinstance(response, tuple):
            # Предполагаем, что первый элемент кортежа — это список с вопросом и ответом
            first_elem = response[0]
            if isinstance(first_elem, list) and len(first_elem) > 0:
                inner_list = first_elem[0]
                if isinstance(inner_list, list) and len(inner_list) > 1:
                    answer = inner_list[1]
                    chatbot.append([user_query, answer])
                    chat_counter += 1
                    return answer, chat_counter, chatbot
        elif isinstance(response, list):
            if len(response) >= 2:
                # Предполагаем, что второй элемент списка содержит ответ
                answer = response[1]
                chatbot.append([user_query, answer])
                chat_counter += 1
                return answer, chat_counter, chatbot
            elif len(response) == 1:
                # В случае, если есть только один элемент, предполагаем, что это ответ
                answer = response[0]
                chatbot.append([user_query, answer])
                chat_counter += 1
                return answer, chat_counter, chatbot
        elif isinstance(response, dict):
            # Если ответ в виде словаря, попытаться извлечь значение по ключу
            answer = response.get('answer', "❌ Не удалось извлечь ответ из полученных данных.")
            chatbot.append([user_query, answer])
            chat_counter += 1
            return answer, chat_counter, chatbot
    except Exception as e:
        logger.error(f"Ошибка при разборе ответа нейросети: {e}")
    return "❌ Не удалось извлечь ответ из структуры ответа нейросети.", chat_counter, chatbot

def restricted(func):
    """Декоратор для ограничения доступа к определённым командам только администратору."""
    @wraps(func)
    async def wrapped(update: Update, context: ContextTypes.DEFAULT_TYPE, *args, **kwargs):
        user_id = update.effective_user.id
        if str(user_id) != ADMIN_USER_ID:
            await update.message.reply_text("❌ У вас нет прав для использования этой команды.")
            return
        return await func(update, context, *args, **kwargs)
    return wrapped

# --------------------- Обработчики Команд ---------------------

async def start(update: Update, context: ContextTypes.DEFAULT_TYPE):
    """Обработка команды /start."""
    user = update.effective_user
    user_id = user.id

    async with aiosqlite.connect('payments.db') as db:
        db.row_factory = aiosqlite.Row
        cursor = await db.execute("SELECT payment_status FROM payments WHERE user_id=?", (user_id,))
        result = await cursor.fetchone()
        await cursor.close()

    if result and result['payment_status'] == 'paid':
        welcome_text = (
            f"👋 Привет, @{user.username if user.username else 'Пользователь'}!\n\n"
            "Вы уже оплатили доступ. Вы можете задать вопрос нейросети с помощью команды /ask."
        )
        await update.message.reply_text(welcome_text)
    else:
        unique_id = generate_unique_id()
        chatbot_initial = json.dumps([])  # Инициализация пустого списка чата

        async with aiosqlite.connect('payments.db') as db:
            await db.execute("""
                INSERT INTO payments 
                (user_id, unique_id, payment_status, requests_left, chat_counter, chatbot) 
                VALUES (?, ?, ?, ?, ?, ?)
                ON CONFLICT(user_id) DO UPDATE SET
                    unique_id=excluded.unique_id,
                    payment_status=excluded.payment_status,
                    requests_left=excluded.requests_left,
                    chat_counter=excluded.chat_counter,
                    chatbot=excluded.chatbot
            """, (user_id, unique_id, 'pending', 0, 0, chatbot_initial))
            await db.commit()

        payment_instructions = (
            "👋 Привет! Добро пожаловать в нашего Telegram-бота с нейросетью.\n\n"
            "📄 **Доступные Команды:**\n"
            "/start - Запустить бота и получить инструкции.\n"
            "/ask - Задать вопрос нейросети.\n"
            "/me - Просмотреть ваш профиль.\n"
            "/help - Показать список доступных команд.\n\n"
            "🛒 **Оплата:**\n"
            "Чтобы получить доступ к функциям бота и общению с нейросетью, пожалуйста, совершите перевод на следующую карту Сбербанк:\n\n"
            f"📱 **Номер для перевода:** `{SBERBANK_NUMBER}`\n"
            f"💰 **Сумма:** `{SBERBANK_AMOUNT}` рублей\n"
            f"🆔 **Уникальный ID:** `{unique_id}`\n\n"
            "❗ **Важно:** Введите ваш Уникальный ID в комментарии к переводу.\n\n"
            "После совершения перевода, нажмите кнопку с вашим уникальным ID для подтверждения оплаты."
        )

        # Кнопка для подтверждения оплаты
        keyboard = [
            [InlineKeyboardButton(unique_id, callback_data=f"confirm_{unique_id}")]
        ]
        reply_markup = InlineKeyboardMarkup(keyboard)

        await update.message.reply_text(
            payment_instructions,
            reply_markup=reply_markup,
            parse_mode='Markdown'
        )

async def button_handler(update: Update, context: ContextTypes.DEFAULT_TYPE):
    """Обработка нажатий кнопок."""
    query = update.callback_query
    await query.answer()

    data = query.data

    if data.startswith("confirm_"):
        unique_id = data.split("_", 1)[1]
        user_id = query.from_user.id
        username = query.from_user.username or "N/A"

        # Уведомление администратора о подтверждении оплаты
        admin_message = (
            f"🔔 **Запрос на Подтверждение Оплаты**\n"
            f"Пользователь @{username} (ID: {user_id}) запросил подтверждение оплаты.\n\n"
            f"🆔 **Уникальный ID:** `{unique_id}`\n\n"
            f"Пожалуйста, используйте административную панель для подтверждения оплаты."
        )

        try:
            await context.bot.send_message(chat_id=ADMIN_USER_ID, text=admin_message, parse_mode='Markdown')
            await query.edit_message_text("✅ Ваш запрос на подтверждение оплаты отправлен администратору. Ожидайте подтверждения.")
        except Exception as e:
            logger.error(f"Ошибка при отправке сообщения администратору: {e}")
            await query.edit_message_text("❌ Произошла ошибка при отправке запроса администратору. Пожалуйста, попробуйте позже.")

async def me(update: Update, context: ContextTypes.DEFAULT_TYPE):
    """Обработка команды /me для отображения профиля пользователя."""
    user = update.effective_user
    user_id = user.id

    async with aiosqlite.connect('payments.db') as db:
        db.row_factory = aiosqlite.Row
        cursor = await db.execute("SELECT unique_id, payment_status, requests_left FROM payments WHERE user_id=?", (user_id,))
        result = await cursor.fetchone()
        await cursor.close()

    if not result:
        await update.message.reply_text("❌ Вы ещё не зарегистрированы. Введите /start для начала.")
        return

    unique_id = result['unique_id']
    payment_status = result['payment_status']
    requests_left = result['requests_left']

    profile_info = (
        f"📝 **Ваш Профиль:**\n\n"
        f"**Никнейм:** @{user.username if user.username else 'N/A'}\n"
        f"**ID Пользователя:** {user_id}\n"
        f"**Уникальный ID:** `{unique_id}`\n"
        f"**Статус Оплаты:** {'✅ Оплачено' if payment_status == 'paid' else '❌ Неоплачено'}\n"
        f"**Доступные Запросы:** {requests_left}"
    )

    await update.message.reply_text(profile_info, parse_mode='Markdown')

async def help_command(update: Update, context: ContextTypes.DEFAULT_TYPE):
    """Обработка команды /help для отображения доступных команд."""
    help_text = (
        "📖 **Доступные Команды:**\n\n"
        "/start - Запустить бота и получить инструкции.\n"
        "/ask - Задать вопрос нейросети.\n"
        "/me - Просмотреть ваш профиль.\n"
        "/help - Показать список доступных команд."
    )
    await update.message.reply_text(help_text, parse_mode='Markdown')

async def ask_neural_network(update: Update, context: ContextTypes.DEFAULT_TYPE):
    """Обработка команды /ask для взаимодействия с нейросетью."""
    user = update.effective_user
    user_id = user.id
    user_input_text = update.message.text.strip()

    # Извлечение запроса пользователя, удалив команду /ask
    if user_input_text.startswith('/ask'):
        user_query = user_input_text[4:].strip()
    else:
        user_query = user_input_text

    if not user_query:
        await update.message.reply_text("❗ Пожалуйста, задайте свой вопрос после команды /ask.")
        return

    async with aiosqlite.connect('payments.db') as db:
        db.row_factory = aiosqlite.Row
        cursor = await db.execute("SELECT payment_status, requests_left, chat_counter, chatbot FROM payments WHERE user_id=?", (user_id,))
        result = await cursor.fetchone()
        await cursor.close()

    if not result or result['payment_status'] != 'paid':
        await update.message.reply_text(
            "🚫 Для доступа, пожалуйста, оплатите.",
            reply_markup=ReplyKeyboardMarkup([["Отправить ID"]], one_time_keyboard=True),
        )
        return

    requests_left = result['requests_left']
    if requests_left <= 0:
        await update.message.reply_text("⚠️ У вас закончились запросы. Пожалуйста, продлите подписку.")
        return

    # Извлечение состояния чата
    chat_counter = result['chat_counter']
    chatbot_serialized = result['chatbot']
    try:
        chatbot = json.loads(chatbot_serialized)
    except json.JSONDecodeError:
        chatbot = []

    # Получаем Gradio client из bot_data приложения
    client: Client = context.bot_data.get('client')
    if not client:
        logger.error("Gradio client не найден в данных приложения.")
        await update.message.reply_text("❌ Внутренняя ошибка. Пожалуйста, попробуйте позже.")
        return

    # Подтверждаем получение запроса
    await update.message.reply_text("🔄 Обрабатываю ваш запрос...")

    try:
        # Убедитесь, что chat_counter является числом с плавающей точкой
        chat_counter_float = float(chat_counter)

        # Убедитесь, что chatbot является кортежем
        chatbot_tuple = tuple(chatbot)

        # Взаимодействие с Gradio API
        response = await asyncio.to_thread(
            client.predict,
            inputs=user_query,
            top_p=1.0,
            temperature=1.0,
            chat_counter=chat_counter_float,
            chatbot=chatbot_tuple,
            api_name="/predict"
        )

        # Логирование полного ответа для отладки
        logger.info(f"Полный ответ от нейросети: {response}")

        # Парсинг ответа и обновление состояния чата
        neural_response, updated_chat_counter, updated_chatbot = parse_neural_response(
            response, user_query, chat_counter, chatbot
        )

        # Проверка, вернул ли нейросеть корректный ответ
        if neural_response and not neural_response.startswith("❌"):
            await update.message.reply_text(neural_response)
            # Обновляем количество доступных запросов и состояние чата в базе данных
            updated_chatbot_serialized = json.dumps(updated_chatbot)

            async with aiosqlite.connect('payments.db') as db:
                await db.execute("""
                    UPDATE payments 
                    SET requests_left = requests_left - 1, chat_counter = ?, chatbot = ?
                    WHERE user_id=?
                """, (updated_chat_counter, updated_chatbot_serialized, user_id))
                await db.commit()
        else:
            await update.message.reply_text(neural_response if neural_response else "❌ Не удалось получить содержательный ответ от нейросети.")

    except Exception as e:
        logger.error(f"Ошибка при взаимодействии с нейросетью: {e}")
        await update.message.reply_text("❌ Произошла ошибка при обработке вашего запроса. Пожалуйста, попробуйте позже.")

# --------------------- Административные Обработчики ---------------------
# (Опционально) Здесь вы можете добавить команды, доступные только администратору, например, для подтверждения оплат.

# --------------------- Главная Функция ---------------------

async def main_async():
    """Асинхронная основная функция для настройки и запуска Telegram-бота."""
    # Инициализация базы данных
    await init_db()

    # Инициализация клиента Gradio
    client = Client(O1MINI_CLIENT_URL)

    # Создание приложения Telegram
    application = ApplicationBuilder().token(BOT_TOKEN).build()

    # Сохранение клиента Gradio в bot_data приложения
    application.bot_data['client'] = client

    # Регистрация обработчиков команд
    application.add_handler(CommandHandler("start", start))
    application.add_handler(CommandHandler("ask", ask_neural_network))
    application.add_handler(CommandHandler("me", me))
    application.add_handler(CommandHandler("help", help_command))

    # Регистрация обработчика нажатий кнопок
    application.add_handler(CallbackQueryHandler(button_handler))

    # (Опционально) Регистрация административных обработчиков здесь

    logger.info("Бот запущен и работает...")
    await application.run_polling()

# --------------------- Точка Входа ---------------------

if __name__ == '__main__':
    try:
        asyncio.run(main_async())
    except RuntimeError as e:
        if "Cannot close a running event loop" in str(e):
            logger.error("Невозможно закрыть уже запущенный цикл событий.")
        else:
            raise
```
Как решить ошибку: 2024-09-29 20:55:56,477 - __main__ - ERROR - Невозможно закрыть уже запущенный цикл событий.