Respan Dataset Explorer

Select one behavior. Every returned turn has one binary label: Present or Absent. Source: final dense boolean release.

5,167,182physical rows
86shards
0.00%qualified row coverage
0.00%qualified cell coverage
Random row JSON API

turns-00042.parquet:25025

7d65d45523db78d004a59132
turn 1/1gpt-4o-2024-08-06EnglishChina617 words
degenerate_repetitionAbsentFinal dense release
USER
System: You act as a paraphrase tool. Your role involves understanding the provided text and then providing a positive example that keeps the original meaning of the text unchanged while using synonyms, interchanging, adding or removing words or sentences, and then provide a negative example where the meaning of the original text is at its opposite.
Output your response with the following format : 
Positive : <the positive example>
Negative : <the negative example>

User: We purchase reinsurance by transferring part of the risk that we have assumed, known as ceding, to a reinsurance company in exchange for part of the premium we receive in connection with the risk. Although reinsurance makes the reinsurer contractually liable to us to the extent the risk is transferred or ceded to the reinsurer, it does not relieve us, the reinsured, of our liability to our policyholders. Our reinsurers may not pay the reinsurance recoverables that they owe to us or they may not pay such recoverables on a timely basis. This failure to pay or failure to pay on a timely basis may be due to factors such as whether reinsurers, their affiliates or certain indemnitors have the financial capacity and willingness to make payments under the terms of a reinsurance treaty or contract. Accordingly, we bear credit risk with respect to our reinsurers, and if our reinsurers fail to pay us, our financial results would be adversely affected. Underwriting results and investment returns of some of our reinsurers may affect their future ability to pay claims. As of December 31, 2023, the amount due from our reinsurers was approximately $3,535 million, including amounts due from state funds and industry pools where it was intended that we would bear no risk. Certain of these amounts are secured by letters of credit or by funds held in trust on
Assistant:
ASSISTANT
Positive: We acquire reinsurance by passing on a portion of our assumed risk, a process known as ceding, to a reinsurance company in return for part of the premium linked to that risk. While reinsurance makes the reinsurer contractually accountable to us for the transferred or ceded risk, it doesn't free us, the reinsured party, from our obligations to our policyholders. There is a possibility that our reinsurers might not fulfill the reinsurance recoverables they owe us, or they might delay such payments. This non-payment or delay can result from various factors, such as the financial capability and willingness of reinsurers, their affiliates, or certain indemnitors to meet their obligations under a reinsurance treaty or agreement. Hence, we have a credit risk with our reinsurers, and if they fail to pay, our financial results could suffer negatively. The underwriting results and investment returns of some reinsurers might impact their ability to settle claims in the future. As of December 31, 2023, the receivable amount from our reinsurers was roughly $3,535 million, including sums due from state funds and industry pools that were structured so that we bear no risk. Some of these amounts are covered by letters of credit or funds held in trust.

Negative: We avoid purchasing reinsurance and choose not to transfer any part of the risk we have assumed, thereby retaining all liability ourselves. By not involving a reinsurer, we eliminate any contractual liability for them, maintaining complete responsibility to our policyholders. Consequently, we have no credit risk with reinsurers, and our financial results are stable regardless of their actions. The underwriting results and investment returns of other companies have no impact on our ability to pay claims. As of December 31, 2023, we owed $3,535 million entirely ourselves, with no involvement of state funds or industry pools, and none of these sums are secured in any way.

turns-00042.parquet:25026

324eca8fa33ee144e966eefe
turn 1/1gpt-4o-2024-08-06EnglishUnited States606 words
degenerate_repetitionAbsentFinal dense release
USER
System: You act as a paraphrase tool. Your role involves understanding the provided text and then providing a positive example that keeps the original meaning of the text unchanged while using synonyms, interchanging, adding or removing words or sentences, and then provide a negative example where the meaning of the original text is at its opposite.
Output your response with the following format : 
Positive : <the positive example>
Negative : <the negative example>

User: Although we have taken steps intended to protect our data and information technology systems and mitigate the risk of harm caused by cybersecurity incidents or breaches, no safeguards are perfect and any failure of these safeguards could cause a substantial disruption of our business operations, which could result in service interruptions, data security compromises, regulatory action, and other similar operational and legal issues, as well as substantial remediation and other costs. Our operations rely on the secure processing, storage and transmission of confidential and other sensitive information, including personal information, in our computer systems and networks. Cybersecurity breaches, including physical or electronic break-ins, computer viruses, malware, attacks by hackers, ransomware attacks, phishing attacks, supply chain attacks, breaches due to employee error or misconduct and other similar breaches can create system disruptions, shutdowns or unauthorized access to, or disclosure of, information maintained in our information technology systems and in the information technology systems of our vendors and other third parties. We have in the past experienced cybersecurity breaches of our information technology systems as well as the information technology systems of our vendors and other third parties, but, to our knowledge, we have not experienced any material cybersecurity breaches. We expect cybersecurity breaches to continue to occur in the future and we are constantly managing efforts to infiltrate and compromise our systems and data. Our electronic transmission of personal, confidential and
Assistant:
ASSISTANT
Positive: While we've implemented measures designed to safeguard our data and IT systems against cybersecurity incidents or breaches, no defenses are flawless, and lapses could significantly disrupt our business, causing service outages, data security issues, regulatory responses, and other operational and legal challenges, along with considerable remediation expenses. Our operations depend on the secure handling, storage, and transfer of confidential and sensitive data, including personal information, across our computer systems and networks. Cybersecurity incidents, whether physical or digital invasions, computer viruses, malware, hacker attacks, ransomware, phishing, supply chain threats, or breaches due to employee mistakes or misbehavior, may lead to system disruptions, shutdowns, or unauthorized access to, or disclosure of, information managed within our IT systems and those of our vendors and other third parties. Previously, we have faced cybersecurity incidents affecting both our IT systems and those of our partners, although we haven't, to our awareness, encountered any major cybersecurity events. We anticipate continued occurrences of cybersecurity incidents in the future and remain vigilant in countering efforts to infiltrate and compromise our data and systems. Our electronic transmission of personal and confidential data remains a focal point of our protective strategies.

Negative: Our data and IT systems are perfectly secure, making cybersecurity incidents or breaches impossible, which guarantees uninterrupted business operations, flawless service delivery, data security without compromise, no risk of regulatory actions, operational issues, or costly remediation processes. Since there are no threats of cybersecurity breaches, we don't need to worry about system disruptions, data leaks, or unauthorized access, whether due to cyber attacks or human error. Our past and anticipated future experiences confirm that breaches won't occur, therefore, our data and systems do not require constant monitoring or defense against potential security threats. Our electronic transmission of sensitive data is infallible and secure from any potential risks.

turns-00042.parquet:25027

a7006d23387f6022e0fa30f3
turn 1/4gpt-4o-2024-08-06EnglishRussia2666 words
degenerate_repetitionAbsentFinal dense release
USER
есть идеи как улушчить данный код, модернизировать, оптимизировать, но чтобы без потери функционала?

# bot/handlers/sms.py

import asyncio
import logging
import time
import json
from pathlib import Path
from typing import Optional, List, Tuple
from aiogram import Dispatcher, types, F
from aiogram.utils.keyboard import InlineKeyboardBuilder
from aiogram.fsm.context import FSMContext
from aiogram.fsm.state import State, StatesGroup

from ..data import get_user_api_key, get_user_operator, get_user_country
from ..api import SmsHubAPI
from ..utils import get_usd_to_rub_rate, safe_edit_or_send_message
from .start import send_main_menu
from .activation import user_activations, poll_for_sms
from ..constants.operators import OPERATOR_DISPLAY_NAMES
from ..constants.countries import COUNTRIES
from ..constants.services import SERVICE_DISPLAY_NAMES

logger = logging.getLogger(__name__)

class SmsOrderState(StatesGroup):
    waiting_for_service = State()
    waiting_for_max_price = State()

SERVICES: List[Tuple[str, str]] = list(SERVICE_DISPLAY_NAMES.items())
POPULARITY_FILE = Path("service_popularity.json")

def load_popularity_data() -> dict:
    if POPULARITY_FILE.exists():
        with open(POPULARITY_FILE, 'r', encoding='utf-8') as f:
            return json.load(f)
    return {}

def save_popularity_data(popularity_data: dict):
    with open(POPULARITY_FILE, 'w', encoding='utf-8') as f:
        json.dump(popularity_data, f, ensure_ascii=False, indent=4)

def update_service_popularity(service_code: str):
    popularity_data = load_popularity_data()
    if service_code in popularity_data:
        popularity_data[service_code] += 1
    else:
        popularity_data[service_code] = 1
    save_popularity_data(popularity_data)

def get_sorted_services(available_services: List[str]) -> List[Tuple[str, str]]:
    popularity_data = load_popularity_data()
    sorted_services = sorted(
        [(code, name) for code, name in SERVICES if code in available_services],
        key=lambda service: popularity_data.get(service[0], 0),
        reverse=True
    )
    return sorted_services

def get_service_pages(services: List[Tuple[str, str]], page_size: int = 18) -> List[List[Tuple[str, str]]]:
    pages = []
    for i in range(0, len(services), page_size):
        pages.append(services[i:i + page_size])
    return pages

def build_service_keyboard(page_number: int, available_services: List[str], services_with_numbers: set) -> InlineKeyboardBuilder:
    sorted_services = get_sorted_services(available_services)
    services_pages = get_service_pages(sorted_services)
    keyboard = InlineKeyboardBuilder()

    if page_number < len(services_pages):
        current_page = services_pages[page_number]

        for code, name in current_page:
            # Append a red circle emoji if the service does not have available numbers
            if code not in services_with_numbers:
                name += " 🔴"
            keyboard.button(text=name, callback_data=f"service_select:{code}")

        keyboard.adjust(3)
        
        if len(services_pages) > 1:  # Only show navigation buttons if more than one page exists
            nav_buttons = []
            if page_number > 0:
                nav_buttons.append(types.InlineKeyboardButton(text="⬅️ Назад", callback_data=f"service_page:{page_number - 1}"))
            # Centralize page number information
            nav_buttons.append(types.InlineKeyboardButton(text=f"Страница {page_number + 1}/{len(services_pages)}", callback_data="ignore"))
            if page_number < len(services_pages) - 1:
                nav_buttons.append(types.InlineKeyboardButton(text="➡️ Вперед", callback_data=f"service_page:{page_number + 1}"))
            keyboard.row(*nav_buttons)
        
        keyboard.row(types.InlineKeyboardButton(text="🔙 Назад в меню", callback_data="back_to_main_menu"))
    
    return keyboard

def get_service_message_text(total_services_with_numbers: int, total_services_for_country: int, services_with_operator: int, country_name: str, operator_name: str) -> str:
    return (
        f"🔢 *Общее кол-во сервисов:* `{total_services_for_country}`\n"
        f"💼 *Доступные сервисы (где есть номера):* `{total_services_with_numbers}`\n"
        f"✅ *Доступные сервисы (с вашими настройками оператора):* `{services_with_operator}`\n\n"
        f"— Нажмите на кнопку, чтобы выбрать сервис.\n"
        f"— Или введите название, чтобы найти сервис.\n\n"
        f"🐾 *Текущая страна:* `{country_name}`\n"
        f"📡 *Текущий оператор:* `{operator_name}`\n"
        f"_(Эти параметры можно изменить в настройках)_\n"
        f"\n_🔴 - нет номеров_"
    )

async def fetch_all_services(user_api_key: str, user_country_code: str, state: FSMContext) -> Tuple[Optional[List[str]], int, int]:
    smshub_api = SmsHubAPI(user_api_key)
    max_attempts = 3
    last_exception = None
    available_services = []
    services_with_numbers = set()

    for attempt in range(1, max_attempts + 1):
        try:
            numbers_status = await smshub_api.get_numbers_status(country=user_country_code)
            if numbers_status:
                # Все сервисы и сервисы с доступными номерами
                available_services = [service.split('_')[0] for service in numbers_status.keys()]
                services_with_numbers = {service.split('_')[0] for service, count in numbers_status.items() if int(count) > 0}
                break
        except Exception as e:
            last_exception = e
            logger.error(f"Ошибка при запросе статуса всех сервисов, попытка {attempt}: {e}")

        data = await state.get_data()
        if data.get("cancel_request"):
            logger.info("Запрос на получение всех сервисов был отменен.")
            return None, 0, 0

        progress_text = f"Попытка {attempt}/{max_attempts} получения списка всех сервисов..."
        keyboard = InlineKeyboardBuilder()
        keyboard.button(text="❌ Отмена", callback_data="cancel_operation")
        keyboard.adjust(1)

        await safe_edit_or_send_message(
            message=data.get('message'),
            new_text=progress_text,
            state=state,
            reply_markup=keyboard.as_markup()
        )

        await asyncio.sleep(5)

    if last_exception:
        logger.error(f"Ошибка при запросе всех сервисов: {last_exception}")
        return None, 0, 0

    return available_services, len(services_with_numbers), len(available_services)

async def get_sms_handler(callback_query: types.CallbackQuery, state: FSMContext):
    try:
        await callback_query.answer()
    except Exception as e:
        logger.warning(f"Не удалось ответить на callback_query: {e}")

    user_api_key = get_user_api_key(callback_query.from_user.id)
    user_country_code = get_user_country(callback_query.from_user.id) or "0"
    user_operator = get_user_operator(callback_query.from_user.id) or "any"

    if not user_api_key:
        keyboard = InlineKeyboardBuilder()
        keyboard.button(text="⚙️ Настройки", callback_data="settings")
        keyboard.button(text="🔙 Назад", callback_data="back_to_main_menu")
        keyboard.adjust(1)
        await safe_edit_or_send_message(
            message=callback_query.message,
            new_text="Пожалуйста, сначала настройте ваш API ключ в разделе 'Настройки'.",
            state=state,
            reply_markup=keyboard.as_markup()
        )
        return

    logger.info(f"Пользователь {callback_query.from_user.id} начал процесс получения номера.")

    await state.update_data(message=callback_query.message, cancel_request=False)
    available_services, total_services_with_numbers, total_services_for_country = await fetch_all_services(user_api_key, user_country_code, state)

    country_name = COUNTRIES.get(user_country_code, 'Неизвестно')
    operator_name = OPERATOR_DISPLAY_NAMES.get(user_operator, 'Любой')

    await state.update_data(total_services_with_numbers=total_services_with_numbers, 
                            total_services_for_country=total_services_for_country,
                            country_name=country_name, 
                            operator_name=operator_name)

    if available_services is None:
        await send_main_menu(callback_query.message, state)
        return

    smshub_api = SmsHubAPI(user_api_key)
    numbers_status = await smshub_api.get_numbers_status(country=user_country_code, operator=user_operator)
    services_with_numbers = {service.split('_')[0] for service, count in numbers_status.items() if int(count) > 0}

    services_with_operator = len(services_with_numbers)  # Количество сервисов с учетом настроек оператора

    keyboard = build_service_keyboard(page_number=0, available_services=available_services, services_with_numbers=services_with_numbers)
    message_text = get_service_message_text(total_services_with_numbers, total_services_for_country, services_with_operator, country_name, operator_name)

    await safe_edit_or_send_message(
        message=callback_query.message,
        new_text=message_text,
        state=state,
        reply_markup=keyboard.as_markup(),
        parse_mode="Markdown"
    )
    await state.set_state(SmsOrderState.waiting_for_service)
    await state.update_data(available_services=available_services)

async def go_back_to_service_selection(callback_query: types.CallbackQuery, state: FSMContext):
    try:
        await callback_query.answer()
    except Exception as e:
        logger.warning(f"Не удалось ответить на callback_query: {e}")
    logger.info(f"Пользователь {callback_query.from_user.id} отменил операцию.")

    await state.update_data(cancel_request=True)

    data = await state.get_data()
    current_task = data.get('current_task')
    if current_task:
        current_task.cancel()

    # Обновите актуальные данные здесь
    available_services = data.get('available_services', [])
    total_services_with_numbers = data.get('total_services_with_numbers', len(available_services))
    total_services_for_country = data.get('total_services_for_country', len(available_services))
    country_name = data.get('country_name', 'Неизвестно')
    operator_name = data.get('operator_name', 'Любой')

    smshub_api = SmsHubAPI(get_user_api_key(callback_query.from_user.id))
    numbers_status = await smshub_api.get_numbers_status(country=get_user_country(callback_query.from_user.id), operator=get_user_operator(callback_query.from_user.id))
    services_with_numbers = {service.split('_')[0] for service, count in numbers_status.items() if int(count) > 0}

    services_with_operator = len(services_with_numbers)  # Количество сервисов с учетом настроек оператора

    keyboard = build_service_keyboard(page_number=0, available_services=available_services, services_with_numbers=services_with_numbers)
    message_text = get_service_message_text(total_services_with_numbers, total_services_for_country, services_with_operator, country_name, operator_name)

    await safe_edit_or_send_message(
        message=callback_query.message,
        new_text=message_text,
        state=state,
        reply_markup=keyboard.as_markup(),
        parse_mode="Markdown"
    )

    await state.set_state(SmsOrderState.waiting_for_service)

async def back_to_main_menu(callback_query: types.CallbackQuery, state: FSMContext):
    try:
        await callback_query.answer()
    except Exception as e:
        logger.warning(f"Не удалось ответить на callback_query: {e}")
    logger.info(f"Пользователь {callback_query.from_user.id} вернулся в главное меню.")

    await state.set_state(None)
    await send_main_menu(callback_query.message, state)

async def service_page_handler(callback_query: types.CallbackQuery, state: FSMContext):
    try:
        await callback_query.answer()
    except Exception as e:
        logger.warning(f"Не удалось ответить на callback_query: {e}")

    page_number = int(callback_query.data.split(":")[1])
    data = await state.get_data()
    available_services = data.get('available_services', [])

    smshub_api = SmsHubAPI(get_user_api_key(callback_query.from_user.id))
    numbers_status = await smshub_api.get_numbers_status(country=get_user_country(callback_query.from_user.id), operator=get_user_operator(callback_query.from_user.id))
    services_with_numbers = {service.split('_')[0] for service, count in numbers_status.items() if int(count) > 0}

    services_with_operator = len(services_with_numbers)  # Количество сервисов с учетом настроек оператора

    total_services_with_numbers = data.get('total_services_with_numbers', len(available_services))
    total_services_for_country = data.get('total_services_for_country', len(available_services))
    country_name = data.get('country_name', 'Неизвестно')
    operator_name = data.get('operator_name', 'Любой')

    keyboard = build_service_keyboard(page_number, available_services, services_with_numbers)
    message_text = get_service_message_text(total_services_with_numbers, total_services_for_country, services_with_operator, country_name, operator_name)

    await safe_edit_or_send_message(
        message=callback_query.message,
        new_text=message_text,
        state=state,
        reply_markup=keyboard.as_markup(),
        parse_mode="Markdown"
    )

async def service_selected_handler(callback_query: types.CallbackQuery, state: FSMContext):
    try:
        await callback_query.answer()
    except Exception as e:
        logger.warning(f"Не удалось ответить на callback_query: {e}")

    service_code = callback_query.data.split(":")[1]
    update_service_popularity(service_code)

    await state.update_data(selected_service=service_code, cancel_request=False)
    task = asyncio.create_task(service_handler_logic(
        callback_query.message, state, user_id=callback_query.from_user.id, service_code=service_code, is_service_selection=True))
    await state.update_data(current_task=task)

async def service_handler(message: types.Message, state: FSMContext, user_id: Optional[int] = None):
    try:
        await message.delete()
    except Exception as e:
        logger.error(f"Не удалось удалить сообщение пользователя: {e}")

    user_input = message.text.strip().lower()

    if user_id is None:
        user_id = message.from_user.id

    logger.info(f"Пользователь {user_id} ввел сервис: {user_input}")

    data = await state.get_data()
    available_services = data.get('available_services', [])

    smshub_api = SmsHubAPI(get_user_api_key(user_id))
    numbers_status = await smshub_api.get_numbers_status(country=get_user_country(user_id), operator=get_user_operator(user_id))
    services_with_numbers = {service.split('_')[0] for service, count in numbers_status.items() if int(count) > 0}

    matched_services = [
        (code, name) for code, name in SERVICE_DISPLAY_NAMES.items()
        if code in available_services and (user_input in name.lower() or user_input == code.lower())
    ]

    if matched_services:
        pages = get_service_pages(matched_services)
        page_number = 0
        keyboard = build_page_keyboard(pages, page_number, services_with_numbers)
        
        await state.update_data(matched_services=matched_services)

        await safe_edit_or_send_message(
            message=message,
            new_text="Пожалуйста, выберите один из представленных сервисов:\n_🔴 - нет номеров_",
            state=state,
            reply_markup=keyboard.as_markup(),
            parse_mode="Markdown"
        )
    else:
        keyboard = InlineKeyboardBuilder()
        keyboard.button(text="🔙 Назад к сервисам", callback_data="service_page:0")
        await safe_edit_or_send_message(
            message=message,
            new_text="Сервис не найден. Попробуйте ввести код или полное название сервиса.",
            state=state,
            reply_markup=keyboard.as_markup()
        )

def build_page_keyboard(service_pages, page_number: int, services_with_numbers: set) -> InlineKeyboardBuilder:
    keyboard = InlineKeyboardBuilder()
    if page_number < len(service_pages):
        current_page = service_pages[page_number]

        for code, name in current_page:
            # Append a red circle emoji if the service does not have available numbers
            if code not in services_with_numbers:
                name += " 🔴"
            keyboard.button(text=name, callback_data=f"service_select:{code}")

        keyboard.adjust(3)
        
        if len(service_pages) > 1:  # Only show navigation buttons if more than one page exists
            nav_buttons = []
            if page_number > 0:
                nav_buttons.append(types.InlineKeyboardButton(text="⬅️ Назад", callback_data=f"search_page:{page_number - 1}"))
            # Centralize page number information
            nav_buttons.append(types.InlineKeyboardButton(text=f"Страница {page_number + 1}/{len(service_pages)}", callback_data="ignore"))
            if page_number < len(service_pages) - 1:
                nav_buttons.append(types.InlineKeyboardButton(text="➡️ Вперед", callback_data=f"search_page:{page_number + 1}"))
            keyboard.row(*nav_buttons)
    
    keyboard.row(types.InlineKeyboardButton(text="🔙 Назад к сервисам", callback_data="service_page:0"))
    return keyboard

async def handle_search_page_navigation(callback_query: types.CallbackQuery, state: FSMContext):
    try:
        await callback_query.answer()
    except Exception as e:
        logger.warning(f"Не удалось ответить на callback_query: {e}")

    page_number = int(callback_query.data.split(":")[1])
    data = await state.get_data()
    matched_services = data.get('matched_services', [])

    smshub_api = SmsHubAPI(get_user_api_key(callback_query.from_user.id))
    numbers_status = await smshub_api.get_numbers_status(country=get_user_country(callback_query.from_user.id), operator=get_user_operator(callback_query.from_user.id))
    services_with_numbers = {service.split('_')[0] for service, count in numbers_status.items() if int(count) > 0}

    pages = get_service_pages(matched_services)
    keyboard = build_page_keyboard(pages, page_number, services_with_numbers)

    await safe_edit_or_send_message(
        message=callback_query.message,
        new_text="Пожалуйста, выберите один из представленных сервисов:\n_🔴 - нет номеров_",
        state=state,
        reply_markup=keyboard.as_markup(),
        parse_mode="Markdown"
    )

async def service_handler_logic(message: types.Message, state: FSMContext, user_id: int, service_code: str, is_service_selection: bool = False):
    logger.info(f"Пользователь {user_id} выбрал сервис: {service_code}")

    user_api_key = get_user_api_key(user_id)
    user_operator = get_user_operator(user_id) or "any"
    user_country_code = get_user_country(user_id) or "0"
    country_name = COUNTRIES.get(user_country_code, user_country_code)

    if not user_api_key:
        await safe_edit_or_send_message(
            message=message,
            new_text="Пожалуйста, сначала настройте ваш API ключ в разделе 'Настройки'.",
            state=state
        )
        await state.set_state(None)
        await send_main_menu(message, state)
        return

    smshub_api = SmsHubAPI(user_api_key)
    usd_to_rub_rate = await get_usd_to_rub_rate()

    max_attempts = 3
    success = False
    last_exception = None

    try:
        for attempt in range(1, max_attempts + 1):
            data = await state.get_data()
            if data.get("cancel_request"):
                logger.info(f"Запрос для пользователя {user_id} был отменен.")
                return

            try:
                progress_text = f"Идет запрос {attempt}/{max_attempts}..."
                keyboard = InlineKeyboardBuilder()
                keyboard.button(text="❌ Отмена", callback_data="cancel_operation")
                keyboard.adjust(1)

                await safe_edit_or_send_message(
                    message=message,
                    new_text=progress_text,
                    state=state,
                    reply_markup=keyboard.as_markup()
                )

                price_info = await smshub_api.get_price_for_service(service_code, country=user_country_code)
                numbers_status = await smshub_api.get_numbers_status(country=user_country_code, operator=user_operator)

                if data.get("cancel_request"):
                    logger.info(f"Запрос для пользователя {user_id} был отменен после получения данных.")
                    return

                if price_info and numbers_status:
                    service_key = f"{service_code}_0"
                    available_numbers = int(numbers_status.get(service_key, 0) or 0)
                    
                    if available_numbers > 0:
                        prices = [float(price_str) for price_str in price_info.keys() if price_str is not None]
                        if prices:
                            min_price_usd = min(prices)
                            max_price_usd = max(prices)
                            min_price_rub = min_price_usd * usd_to_rub_rate if usd_to_rub_rate else 0
                            max_price_rub = max_price_usd * usd_to_rub_rate if usd_to_rub_rate else 0

                            operator_display = OPERATOR_DISPLAY_NAMES.get(user_operator, user_operator)
                            service_display = SERVICE_DISPLAY_NAMES.get(service_code, service_code)

                            keyboard = InlineKeyboardBuilder()
                            keyboard.button(text=f"⬇️ Мин. цена ({min_price_usd:.4f}$)", callback_data=f"select_price:{min_price_usd}")
                            keyboard.button(text=f"⬆️ Макс. цена ({max_price_usd:.4f}$)", callback_data=f"select_price:{max_price_usd}")
                            keyboard.adjust(2)
                            keyboard.row(types.InlineKeyboardButton(text="❌ Отмена", callback_data="cancel_operation"))

                            message_text = (
                                f"*Страна:* `{country_name}`\n"
                                f"*Доступно номеров:* `{available_numbers}`\n"
                                f"*Оператор:* `{operator_display}`\n"
                                f"*Сервис:* `{service_display}`\n"
                                f"*Цены:* от `{min_price_usd:.4f}` $ (₽{min_price_rub:.2f}) до `{max_price_usd:.4f}` $ (₽{max_price_rub:.2f}).\n\n"
                                f"_Выберите максимальную допустимую стоимость покупки с помощью кнопок ниже или введите сумму вручную (например: 0.5). Все суммы указаны в долларах ($):_"
                            )

                            await safe_edit_or_send_message(
                                message=message,
                                new_text=message_text,
                                state=state,
                                reply_markup=keyboard.as_markup(),
                                parse_mode="Markdown"
                            )

                            await state.update_data(
                                service=service_code,
                                service_display=service_display,
                                country_name=country_name,
                                available_numbers=available_numbers,
                                operator_display=operator_display,
                                min_price=min_price_usd,
                                max_price_usd=max_price_usd,
                                min_price_rub=min_price_rub,
                                max_price_rub=max_price_rub,
                                usd_to_rub_rate=usd_to_rub_rate,
                                user_id=user_id
                            )

                            await state.set_state(SmsOrderState.waiting_for_max_price)
                            success = True
                            break
                        else:
                            logger.info(f"Попытка {attempt}: Цены не найдены.")
                            last_exception = "Цены не найдены"
                    else:
                        logger.info(f"Попытка {attempt}: Нет доступных номеров.")
                        last_exception = "Нет доступных номеров"

            except Exception as e:
                logger.error(f"Ошибка при получении данных для сервиса '{service_code}', попытка {attempt}: {e}")
                last_exception = e

            await asyncio.sleep(5)

    except asyncio.CancelledError:
        logger.info(f"Задача для пользователя {user_id} была отменена.")
        return

    if not success:
        keyboard = InlineKeyboardBuilder()
        keyboard.button(text="Назад", callback_data="service_page:0")
        await safe_edit_or_send_message(
            message=message,
            new_text=f"Произошла ошибка при обработке запроса: {last_exception}. Попробуйте снова.",
            state=state,
            reply_markup=keyboard.as_markup()
        )

async def price_selected_handler(callback_query: types.CallbackQuery, state: FSMContext):
    try:
        await callback_query.answer()
    except Exception as e:
        logger.warning(f"Не удалось ответить на callback_query: {e}")

    price = float(callback_query.data.split(":")[1])
    await state.update_data(max_price=price)

    await process_number_purchase(callback_query.message, state)

async def max_price_handler(message: types.Message, state: FSMContext):
    max_price_input = message.text.strip()
    data = await state.get_data()
    user_id = data.get('user_id', message.from_user.id)

    try:
        await message.delete()
    except Exception as e:
        logger.error(f"Не удалось удалить сообщение пользователя: {e}")

    logger.info(f"Пользователь {user_id} указал максимальную стоимость: {max_price_input}")

    try:
        max_price = float(max_price_input)
    except ValueError:
        user_data = await state.get_data()
        min_price = user_data.get('min_price', 0)
        max_price_usd = user_data.get('max_price_usd', 0)
        min_price_rub = user_data.get('min_price_rub', 0)
        max_price_rub = user_data.get('max_price_rub', 0)

        keyboard = InlineKeyboardBuilder()
        keyboard.button(text="❌ Отмена", callback_data="cancel_operation")
        keyboard.adjust(1)
        await safe_edit_or_send_message(
            message=message,
            new_text=(
                f"Пожалуйста, введите корректное число для максимальной стоимости. "
                f"От `{min_price:.4f}` $ (₽{min_price_rub:.2f}) до `{max_price_usd:.4f}` $ (₽{max_price_rub:.2f})."
            ),
            state=state,
            reply_markup=keyboard.as_markup(),
            parse_mode="Markdown"
        )
        return

    if max_price < data.get('min_price', 0):
        keyboard = InlineKeyboardBuilder()
        keyboard.button(text="❌ Отмена", callback_data="cancel_operation")
        keyboard.adjust(1)
        await safe_edit_or_send_message(
            message=message,
            new_text=f"Максимальная стоимость должна быть не менее `{data.get('min_price', 0):.4f}` $.",
            state=state,
            reply_markup=keyboard.as_markup(),
            parse_mode="Markdown"
        )
        return

    await state.update_data(max_price=max_price)

    await process_number_purchase(message, state)

async def process_number_purchase(message: types.Message, state: FSMContext):
    user_data = await state.get_data()
    user_id = user_data.get('user_id', message.from_user.id)
    service = user_data['service']
    service_display = user_data['service_display']
    country_name = user_data['country_name']
    operator_display = user_data['operator_display']
    max_price = user_data['max_price']
    user_api_key = get_user_api_key(user_id)
    smshub_api = SmsHubAPI(user_api_key)
    user_country_code = get_user_country(user_id) or "0"

    max_attempts = 3
    last_exception = None

    try:
        for attempt in range(1, max_attempts + 1):
            data = await state.get_data()

            if data.get("cancel_request"):
                logger.info(f"Запрос на получение номера для пользователя {user_id} был отменен.")
                return
            
            progress_text = f"Идет запрос {attempt}/{max_attempts} на получение номера..."
            keyboard = InlineKeyboardBuilder()
            keyboard.button(text="❌ Отмена", callback_data="cancel_operation")
            keyboard.adjust(1)

            await safe_edit_or_send_message(
                message=message,
                new_text=progress_text,
                state=state,
                reply_markup=keyboard.as_markup()
            )

            user_operator = get_user_operator(user_id) or "any"

            if data.get("cancel_request"):
                logger.info(f"Запрос на получение номера для пользователя {user_id} был отменен перед выполнением.")
                return

            result = await smshub_api.get_number(service, country=user_country_code, max_price=max_price, operator=user_operator)

            if data.get("cancel_request"):
                logger.info(f"Запрос на получение номера для пользователя {user_id} был отменен.")
                return

            if result and result.startswith("ACCESS_NUMBER"):
                _, activation_id, number = result.split(":")
                logger.info(f"Пользователь {user_id} получил номер: {number}, активация ID: {activation_id}")

                if user_id not in user_activations:
                    user_activations[user_id] = {}
                user_activations[user_id][activation_id] = {
                    'number': number,
                    'status': 'Ожидание SMS',
                    'service': service,
                    'service_display': service_display,
                    'country_name': country_name,
                    'last_update': time.time(),
                    'task': None
                }

                keyboard = InlineKeyboardBuilder()
                keyboard.button(text="📂 Текущие активации", callback_data="current_activations")
                keyboard.button(text="❌ Отменить активацию", callback_data=f"cancel_activation:{activation_id}")
                keyboard.button(text="🔙 Главное меню", callback_data="back_to_main_menu")
                keyboard.adjust(1)

                message_text = (
                    f"*Получен номер:* `{number}`\n"
                    f"*Страна:* `{country_name}`\n"
                    f"*Оператор:* `{operator_display}`\n"
                    f"*Сервис:* `{service_display}`\n"
                    f"*Максимальная стоимость:* `{max_price:.2f}` $ (₽{max_price * user_data['usd_to_rub_rate']:.2f})\n"
                    f"*Статус:* *Ожидание SMS*\n"
                    f"Вы можете управлять активацией или вернуться в главное меню."
                )

                sent_message = await safe_edit_or_send_message(
                    message=message,
                    new_text=message_text,
                    state=state,
                    reply_markup=keyboard.as_markup(),
                    parse_mode="Markdown"
                )
                user_activations[user_id][activation_id]['message_id'] = sent_message.message_id

                await state.set_state(None)

                task = asyncio.create_task(poll_for_sms(
                    bot=message.bot,
                    user_id=user_id,
                    chat_id=message.chat.id,
                    activation_id=activation_id,
                    smshub_api=smshub_api
                ))
                user_activations[user_id][activation_id]['task'] = task
                return

            elif result == "NO_NUMBERS":
                logger.info(f"Попытка {attempt} из {max_attempts}: нет доступных номеров.")
                last_exception = result
                if attempt == max_attempts:
                    suggestion = (
                        "Попробуйте выбрать 'Любой оператор' в настройках или увеличить максимальную цену."
                        if user_operator != "any" else
                        "Попробуйте увеличить максимальную цену или повторите попытку позже."
                    )
                    keyboard = InlineKeyboardBuilder()
                    keyboard.button(text="Назад", callback_data="service_page:0")
                    await safe_edit_or_send_message(
                        message=message,
                        new_text=f"Нет доступных номеров для оператора {operator_display} по данной цене.\n{suggestion}",
                        state=state,
                        reply_markup=keyboard.as_markup()
                    )
                    return
            else:
                raise Exception("Неожиданный ответ API")

            await asyncio.sleep(5)

    except asyncio.CancelledError:
        logger.info(f"Задача для пользователя {user_id} была отменена.")
        return

    if last_exception and last_exception != "NO_NUMBERS":
        keyboard = InlineKeyboardBuilder()
        keyboard.button(text="Назад", callback_data="service_page:0")
        await safe_edit_or_send_message(
            message=message,
            new_text=f"Произошла ошибка при обработке запроса: {last_exception}. Попробуйте снова.",
            state=state,
            reply_markup=keyboard.as_markup()
        )

# Add a handler for the "ignore" callback to silently ignore it
async def ignore_callback_handler(callback_query: types.CallbackQuery):
    try:
        await callback_query.answer()  # Just answer to confirm the action
    except Exception as e:
        logger.warning(f"Не удалось ответить на callback_query: {e}")

def register_sms_handlers(dp: Dispatcher):
    dp.callback_query.register(get_sms_handler, F.data == "get_sms")
    dp.callback_query.register(go_back_to_service_selection, F.data == "cancel_operation")
    dp.callback_query.register(back_to_main_menu, F.data == "back_to_main_menu")
    dp.callback_query.register(service_page_handler, F.data.startswith("service_page:"))
    dp.callback_query.register(service_selected_handler, F.data.startswith("service_select:"))
    dp.callback_query.register(handle_search_page_navigation, F.data.startswith("search_page:"))
    dp.callback_query.register(price_selected_handler, F.data.startswith("select_price:"))
    dp.callback_query.register(ignore_callback_handler, F.data == "ignore")
    dp.message.register(service_handler, SmsOrderState.waiting_for_service)
    dp.message.register(max_price_handler, SmsOrderState.waiting_for_max_price)
ASSISTANT
Этот код представляет собой обработчик для Telegram-бота с помощью библиотеки aiogram. Его задача — предоставлять пользователям возможность заказывать номера телефонов для различных сервисов. Ниже приведены основные области, которые можно улучшить для увеличения эффективности и читабельности кода, без потери функциональности.

### 1. **Организация импортов**
Убедитесь, что импорты упорядочены и минимизированы. Неиспользуемые импорты могут быть удалены.

```python
import asyncio
import logging
import json
from pathlib import Path
from typing import Optional, List, Tuple

from aiogram import Dispatcher, types, F
from aiogram.utils.keyboard import InlineKeyboardBuilder
from aiogram.fsm.context import FSMContext
from aiogram.fsm.state import State, StatesGroup

# Не забудьте использовать относительные импорты для модулей в проекте
from ..data import get_user_api_key, get_user_operator, get_user_country
from ..api import SmsHubAPI
from ..utils import get_usd_to_rub_rate, safe_edit_or_send_message
from .start import send_main_menu
from .activation import user_activations, poll_for_sms
from ..constants.operators import OPERATOR_DISPLAY_NAMES
from ..constants.countries import COUNTRIES
from ..constants.services import SERVICE_DISPLAY_NAMES
```

### 2. **Оптимизация работы с файлами**
Чтение и запись JSON-файла не оптимизированы. Лучше загружать данные единожды при старте, а сохранять изменения лишь при необходимости, используя класс с контекстным менеджером или глобальную переменную:

```python
POPULARITY_FILE = Path("service_popularity.json")
service_popularity = {}

def load_popularity_data():
    global service_popularity
    if POPULARITY_FILE.exists():
        with open(POPULARITY_FILE, 'r', encoding='utf-8') as f:
            service_popularity = json.load(f)

def save_popularity_data():
    with open(POPULARITY_FILE, 'w', encoding='utf-8') as f:
        json.dump(service_popularity, f, ensure_ascii=False, indent=4)

# Вызовите function load_popularity_data() при инициализации
load_popularity_data()
```

### 3. **Упрощение логических конструкций**
Старайтесь избегать избыточных условий и вложенных циклов. Например, логика получения сервисов:

```python
async def fetch_all_services(user_api_key: str, user_country_code: str, state: FSMContext) -> Tuple[Optional[List[str]], int, int]:
    smshub_api = SmsHubAPI(user_api_key)
    max_attempts = 3
    available_services, services_with_numbers = [], set()
    
    for attempt in range(max_attempts):
        try:
            numbers_status = await smshub_api.get_numbers_status(country=user_country_code)
            if numbers_status:
                available_services = [service.split('_')[0] for service in numbers_status.keys()]
                services_with_numbers = {service.split('_')[0] for service, count in numbers_status.items() if int(count) > 0}
                break
        except Exception as e:
            logger.error(f"Ошибка при запросе статуса сервисов, попытка {attempt + 1}: {e}")
            if attempt == max_attempts - 1:
                return None, 0, 0
        
        await handle_transient_state(state, 'message', attempt, max_attempts, 'Получение списка сервисов...', "cancel_request")
        await asyncio.sleep(5)
    
    return available_services, len(services_with_numbers), len(available_services)
```

### 4. **Делегирование общих операций**
Для улучшения читаемости и обеспечения повторного использования кода, вынесите повторяющиеся логические куски в функции:

```python
async def handle_transient_state(state, key, attempt, max_attempts, progress_text, cancel_key):
    data = await state.get_data()
    if data.get(cancel_key):
        logger.info(f"Операция отменена.")
        return None, 0, 0

    keyboard = InlineKeyboardBuilder()
    keyboard.button(text="❌ Отмена", callback_data="cancel_operation")
    keyboard.adjust(1)

    await safe_edit_or_send_message(
        message=data.get(key),
        new_text=f"{progress_text} (попытка {attempt + 1}/{max_attempts})...",
        state=state,
        reply_markup=keyboard.as_markup()
    )
```

### 5. **Унификация обработки ошибок**
Используйте более компактное и универсальное логирование ошибок и исключений. Это упростит понимание логики обработки ошибок и отслеживание проблем.

### Итог
Эти изменения помогут сделать код более модульным, читабельным и управляемым. Значительное внимание уделено минимизации дублирования кода и упрощению операций работы с файлами и асинхронному выполнению задач. Таким образом, код будет проще поддерживать и расширять в будущем.

turns-00042.parquet:25028

7564eb6e38999028ddcb642a
turn 2/4gpt-4o-2024-08-06EnglishRussia546 words
degenerate_repetitionAbsentFinal dense release
USER
модешь прислать готовый исправленный код с учетом твоиз оптизимаций?
ASSISTANT
Конечно! Я изложу оптимизированный вариант вашего исходного кода с учетом предложенных улучшений. Пожалуйста, посмотрите на обновленную версию:

```python
import asyncio
import logging
import json
from pathlib import Path
from typing import Optional, List, Tuple

from aiogram import Dispatcher, types, F
from aiogram.utils.keyboard import InlineKeyboardBuilder
from aiogram.fsm.context import FSMContext
from aiogram.fsm.state import State, StatesGroup

from ..data import get_user_api_key, get_user_operator, get_user_country
from ..api import SmsHubAPI
from ..utils import get_usd_to_rub_rate, safe_edit_or_send_message
from .start import send_main_menu
from .activation import user_activations, poll_for_sms
from ..constants.operators import OPERATOR_DISPLAY_NAMES
from ..constants.countries import COUNTRIES
from ..constants.services import SERVICE_DISPLAY_NAMES

logger = logging.getLogger(__name__)

class SmsOrderState(StatesGroup):
    waiting_for_service = State()
    waiting_for_max_price = State()

SERVICES: List[Tuple[str, str]] = list(SERVICE_DISPLAY_NAMES.items())
POPULARITY_FILE = Path("service_popularity.json")
service_popularity = {}

def load_popularity_data():
    global service_popularity
    if POPULARITY_FILE.exists():
        with open(POPULARITY_FILE, 'r', encoding='utf-8') as f:
            service_popularity = json.load(f)

def save_popularity_data():
    with open(POPULARITY_FILE, 'w', encoding='utf-8') as f:
        json.dump(service_popularity, f, ensure_ascii=False, indent=4)

load_popularity_data()

def update_service_popularity(service_code: str):
    if service_code in service_popularity:
        service_popularity[service_code] += 1
    else:
        service_popularity[service_code] = 1
    save_popularity_data()

def get_sorted_services(available_services: List[str]) -> List[Tuple[str, str]]:
    sorted_services = sorted(
        [(code, name) for code, name in SERVICES if code in available_services],
        key=lambda service: service_popularity.get(service[0], 0),
        reverse=True
    )
    return sorted_services

def get_service_pages(services: List[Tuple[str, str]], page_size: int = 18) -> List[List[Tuple[str, str]]]:
    return [services[i:i + page_size] for i in range(0, len(services), page_size)]

def build_service_keyboard(page_number: int, available_services: List[str], services_with_numbers: set) -> InlineKeyboardBuilder:
    sorted_services = get_sorted_services(available_services)
    services_pages = get_service_pages(sorted_services)
    keyboard = InlineKeyboardBuilder()

    if page_number < len(services_pages):
        current_page = services_pages[page_number]

        for code, name in current_page:
            if code not in services_with_numbers:
                name += " 🔴"
            keyboard.button(text=name, callback_data=f"service_select:{code}")

        keyboard.adjust(3)

        if len(services_pages) > 1:
            nav_buttons = []
            if page_number > 0:
                nav_buttons.append(types.InlineKeyboardButton(text="⬅️ Назад", callback_data=f"service_page:{page_number - 1}"))
            nav_buttons.append(types.InlineKeyboardButton(text=f"Страница {page_number + 1}/{len(services_pages)}", callback_data="ignore"))
            if page_number < len(services_pages) - 1:
                nav_buttons.append(types.InlineKeyboardButton(text="➡️ Вперед", callback_data=f"service_page:{page_number + 1}"))
            keyboard.row(*nav_buttons)

        keyboard.row(types.InlineKeyboardButton(text="🔙 Назад в меню", callback_data="back_to_main_menu"))

    return keyboard

def get_service_message_text(total_services_with_numbers: int, total_services_for_country: int, services_with_operator: int, country_name: str, operator_name: str) -> str:
    return (
        f"🔢 *Общее кол-во сервисов:* `{total_services_for_country}`\n"
        f"💼 *Доступные сервисы (где есть номера):* `{total_services_with_numbers}`\n"
        f"✅ *Доступные сервисы (с вашими настройками оператора):* `{services_with_operator}`\n\n"
        f"— Нажмите на кнопку, чтобы выбрать сервис.\n"
        f"— Или введите название, чтобы найти сервис.\n\n"
        f"🐾 *Текущая страна:* `{country_name}`\n"
        f"📡 *Текущий оператор:* `{operator_name}`\n"
        f"_(Эти параметры можно изменить в настройках)_\n"
        f"\n_🔴 - нет номеров_"
    )

async def handle_transient_state(state: FSMContext, key: str, attempt: int, max_attempts: int, progress_text: str, cancel_key: str):
    data = await state.get_data()
    if data.get(cancel_key):
        logger.info("Операция отменена.")
        return

    keyboard = InlineKeyboardBuilder()
    keyboard.button(text="❌ Отмена", callback_data="cancel_operation")
    keyboard.adjust(1)

    await safe_edit_or_send_message(
        message=data.get(key),
        new_text=f"{progress_text} (попытка {attempt + 1}/{max_attempts})...",
        state=state,
        reply_markup=keyboard.as_markup()
    )

async def fetch_all_services(user_api_key: str, user_country_code: str, state: FSMContext) -> Tuple[Optional[List[str]], int, int]:
    smshub_api = SmsHubAPI(user_api_key)
    max_attempts = 3
    available_services, services_with_numbers = [], set()

    for attempt in range(max_attempts):
        try:
            numbers_status = await smshub_api.get_numbers_status(country=user_country_code)
            if numbers_status:
                available_services = [service.split('_')[0] for service in numbers_status.keys()]
                services_with_numbers = {service.split('_')[0] for service, count in numbers_status.items() if int(count) > 0}
                break
        except Exception as e:
            logger.error(f"Ошибка при запросе статуса всех сервисов, попытка {attempt + 1}: {e}")
        
        await handle_transient_state(state, 'message', attempt, max_attempts, 'Получение списка сервисов...', "cancel_request")
        await asyncio.sleep(5)

    return available_services, len(services_with_numbers), len(available_services)

# ... остальная часть кода останется такой же без изменений ...
```

Эти изменения включают оптимизацию работы с файлами, более компактное и читаемое состояние операций, а также укороченные функции и упорядоченные импорты. Остальная часть кода логики остаётся относительно неизменной, но с существенным улучшением его структуры и ясности. Если нужно, я могу помочь с дальнейшими оптимизациями для отдельных участков кода.

turns-00042.parquet:25029

0abe0546bdd62fdbfb58c02e
turn 3/4gpt-4o-2024-08-06EnglishRussia2149 words
degenerate_repetitionAbsentFinal dense release
USER
можно полный код без скоращений?
ASSISTANT
Конечно! Вот обновленный полный код, основанный на предложенных улучшениях:

```python
import asyncio
import logging
import json
from pathlib import Path
from typing import Optional, List, Tuple

from aiogram import Dispatcher, types, F
from aiogram.utils.keyboard import InlineKeyboardBuilder
from aiogram.fsm.context import FSMContext
from aiogram.fsm.state import State, StatesGroup

from ..data import get_user_api_key, get_user_operator, get_user_country
from ..api import SmsHubAPI
from ..utils import get_usd_to_rub_rate, safe_edit_or_send_message
from .start import send_main_menu
from .activation import user_activations, poll_for_sms
from ..constants.operators import OPERATOR_DISPLAY_NAMES
from ..constants.countries import COUNTRIES
from ..constants.services import SERVICE_DISPLAY_NAMES

logger = logging.getLogger(__name__)

class SmsOrderState(StatesGroup):
    waiting_for_service = State()
    waiting_for_max_price = State()

SERVICES: List[Tuple[str, str]] = list(SERVICE_DISPLAY_NAMES.items())
POPULARITY_FILE = Path("service_popularity.json")
service_popularity = {}

def load_popularity_data():
    global service_popularity
    if POPULARITY_FILE.exists():
        with open(POPULARITY_FILE, 'r', encoding='utf-8') as f:
            service_popularity = json.load(f)

def save_popularity_data():
    with open(POPULARITY_FILE, 'w', encoding='utf-8') as f:
        json.dump(service_popularity, f, ensure_ascii=False, indent=4)

load_popularity_data()

def update_service_popularity(service_code: str):
    if service_code in service_popularity:
        service_popularity[service_code] += 1
    else:
        service_popularity[service_code] = 1
    save_popularity_data()

def get_sorted_services(available_services: List[str]) -> List[Tuple[str, str]]:
    sorted_services = sorted(
        [(code, name) for code, name in SERVICES if code in available_services],
        key=lambda service: service_popularity.get(service[0], 0),
        reverse=True
    )
    return sorted_services

def get_service_pages(services: List[Tuple[str, str]], page_size: int = 18) -> List[List[Tuple[str, str]]]:
    return [services[i:i + page_size] for i in range(0, len(services), page_size)]

def build_service_keyboard(page_number: int, available_services: List[str], services_with_numbers: set) -> InlineKeyboardBuilder:
    sorted_services = get_sorted_services(available_services)
    services_pages = get_service_pages(sorted_services)
    keyboard = InlineKeyboardBuilder()

    if page_number < len(services_pages):
        current_page = services_pages[page_number]

        for code, name in current_page:
            if code not in services_with_numbers:
                name += " 🔴"
            keyboard.button(text=name, callback_data=f"service_select:{code}")

        keyboard.adjust(3)

        if len(services_pages) > 1:
            nav_buttons = []
            if page_number > 0:
                nav_buttons.append(types.InlineKeyboardButton(text="⬅️ Назад", callback_data=f"service_page:{page_number - 1}"))
            nav_buttons.append(types.InlineKeyboardButton(text=f"Страница {page_number + 1}/{len(services_pages)}", callback_data="ignore"))
            if page_number < len(services_pages) - 1:
                nav_buttons.append(types.InlineKeyboardButton(text="➡️ Вперед", callback_data=f"service_page:{page_number + 1}"))
            keyboard.row(*nav_buttons)

        keyboard.row(types.InlineKeyboardButton(text="🔙 Назад в меню", callback_data="back_to_main_menu"))

    return keyboard

def get_service_message_text(total_services_with_numbers: int, total_services_for_country: int, services_with_operator: int, country_name: str, operator_name: str) -> str:
    return (
        f"🔢 *Общее кол-во сервисов:* `{total_services_for_country}`\n"
        f"💼 *Доступные сервисы (где есть номера):* `{total_services_with_numbers}`\n"
        f"✅ *Доступные сервисы (с вашими настройками оператора):* `{services_with_operator}`\n\n"
        f"— Нажмите на кнопку, чтобы выбрать сервис.\n"
        f"— Или введите название, чтобы найти сервис.\n\n"
        f"🐾 *Текущая страна:* `{country_name}`\n"
        f"📡 *Текущий оператор:* `{operator_name}`\n"
        f"_(Эти параметры можно изменить в настройках)_\n"
        f"\n_🔴 - нет номеров_"
    )

async def handle_transient_state(state: FSMContext, key: str, attempt: int, max_attempts: int, progress_text: str, cancel_key: str):
    data = await state.get_data()
    if data.get(cancel_key):
        logger.info("Операция отменена.")
        return

    keyboard = InlineKeyboardBuilder()
    keyboard.button(text="❌ Отмена", callback_data="cancel_operation")
    keyboard.adjust(1)

    await safe_edit_or_send_message(
        message=data.get(key),
        new_text=f"{progress_text} (попытка {attempt + 1}/{max_attempts})...",
        state=state,
        reply_markup=keyboard.as_markup()
    )

async def fetch_all_services(user_api_key: str, user_country_code: str, state: FSMContext) -> Tuple[Optional[List[str]], int, int]:
    smshub_api = SmsHubAPI(user_api_key)
    max_attempts = 3
    available_services, services_with_numbers = [], set()

    for attempt in range(max_attempts):
        try:
            numbers_status = await smshub_api.get_numbers_status(country=user_country_code)
            if numbers_status:
                available_services = [service.split('_')[0] for service in numbers_status.keys()]
                services_with_numbers = {service.split('_')[0] for service, count in numbers_status.items() if int(count) > 0}
                break
        except Exception as e:
            logger.error(f"Ошибка при запросе статуса всех сервисов, попытка {attempt + 1}: {e}")
        
        await handle_transient_state(state, 'message', attempt, max_attempts, 'Получение списка сервисов...', "cancel_request")
        await asyncio.sleep(5)

    return available_services, len(services_with_numbers), len(available_services)

async def get_sms_handler(callback_query: types.CallbackQuery, state: FSMContext):
    try:
        await callback_query.answer()
    except Exception as e:
        logger.warning(f"Не удалось ответить на callback_query: {e}")

    user_api_key = get_user_api_key(callback_query.from_user.id)
    user_country_code = get_user_country(callback_query.from_user.id) or "0"
    user_operator = get_user_operator(callback_query.from_user.id) or "any"

    if not user_api_key:
        keyboard = InlineKeyboardBuilder()
        keyboard.button(text="⚙️ Настройки", callback_data="settings")
        keyboard.button(text="🔙 Назад", callback_data="back_to_main_menu")
        keyboard.adjust(1)
        await safe_edit_or_send_message(
            message=callback_query.message,
            new_text="Пожалуйста, сначала настройте ваш API ключ в разделе 'Настройки'.",
            state=state,
            reply_markup=keyboard.as_markup()
        )
        return

    logger.info(f"Пользователь {callback_query.from_user.id} начал процесс получения номера.")

    await state.update_data(message=callback_query.message, cancel_request=False)
    available_services, total_services_with_numbers, total_services_for_country = await fetch_all_services(user_api_key, user_country_code, state)

    country_name = COUNTRIES.get(user_country_code, 'Неизвестно')
    operator_name = OPERATOR_DISPLAY_NAMES.get(user_operator, 'Любой')

    await state.update_data(total_services_with_numbers=total_services_with_numbers, 
                            total_services_for_country=total_services_for_country,
                            country_name=country_name, 
                            operator_name=operator_name)

    if available_services is None:
        await send_main_menu(callback_query.message, state)
        return

    smshub_api = SmsHubAPI(user_api_key)
    numbers_status = await smshub_api.get_numbers_status(country=user_country_code, operator=user_operator)
    services_with_numbers = {service.split('_')[0] for service, count in numbers_status.items() if int(count) > 0}

    services_with_operator = len(services_with_numbers)

    keyboard = build_service_keyboard(page_number=0, available_services=available_services, services_with_numbers=services_with_numbers)
    message_text = get_service_message_text(total_services_with_numbers, total_services_for_country, services_with_operator, country_name, operator_name)

    await safe_edit_or_send_message(
        message=callback_query.message,
        new_text=message_text,
        state=state,
        reply_markup=keyboard.as_markup(),
        parse_mode="Markdown"
    )
    await state.set_state(SmsOrderState.waiting_for_service)
    await state.update_data(available_services=available_services)

async def go_back_to_service_selection(callback_query: types.CallbackQuery, state: FSMContext):
    try:
        await callback_query.answer()
    except Exception as e:
        logger.warning(f"Не удалось ответить на callback_query: {e}")
    logger.info(f"Пользователь {callback_query.from_user.id} отменил операцию.")

    await state.update_data(cancel_request=True)

    data = await state.get_data()
    current_task = data.get('current_task')
    if current_task:
        current_task.cancel()

    available_services = data.get('available_services', [])
    total_services_with_numbers = data.get('total_services_with_numbers', len(available_services))
    total_services_for_country = data.get('total_services_for_country', len(available_services))
    country_name = data.get('country_name', 'Неизвестно')
    operator_name = data.get('operator_name', 'Любой')

    smshub_api = SmsHubAPI(get_user_api_key(callback_query.from_user.id))
    numbers_status = await smshub_api.get_numbers_status(country=get_user_country(callback_query.from_user.id), operator=get_user_operator(callback_query.from_user.id))
    services_with_numbers = {service.split('_')[0] for service, count in numbers_status.items() if int(count) > 0}

    services_with_operator = len(services_with_numbers)

    keyboard = build_service_keyboard(page_number=0, available_services=available_services, services_with_numbers=services_with_numbers)
    message_text = get_service_message_text(total_services_with_numbers, total_services_for_country, services_with_operator, country_name, operator_name)

    await safe_edit_or_send_message(
        message=callback_query.message,
        new_text=message_text,
        state=state,
        reply_markup=keyboard.as_markup(),
        parse_mode="Markdown"
    )

    await state.set_state(SmsOrderState.waiting_for_service)

async def back_to_main_menu(callback_query: types.CallbackQuery, state: FSMContext):
    try:
        await callback_query.answer()
    except Exception as e:
        logger.warning(f"Не удалось ответить на callback_query: {e}")
    logger.info(f"Пользователь {callback_query.from_user.id} вернулся в главное меню.")

    await state.set_state(None)
    await send_main_menu(callback_query.message, state)

async def service_page_handler(callback_query: types.CallbackQuery, state: FSMContext):
    try:
        await callback_query.answer()
    except Exception as e:
        logger.warning(f"Не удалось ответить на callback_query: {e}")

    page_number = int(callback_query.data.split(":")[1])
    data = await state.get_data()
    available_services = data.get('available_services', [])

    smshub_api = SmsHubAPI(get_user_api_key(callback_query.from_user.id))
    numbers_status = await smshub_api.get_numbers_status(country=get_user_country(callback_query.from_user.id), operator=get_user_operator(callback_query.from_user.id))
    services_with_numbers = {service.split('_')[0] for service, count in numbers_status.items() if int(count) > 0}

    services_with_operator = len(services_with_numbers)

    total_services_with_numbers = data.get('total_services_with_numbers', len(available_services))
    total_services_for_country = data.get('total_services_for_country', len(available_services))
    country_name = data.get('country_name', 'Неизвестно')
    operator_name = data.get('operator_name', 'Любой')

    keyboard = build_service_keyboard(page_number, available_services, services_with_numbers)
    message_text = get_service_message_text(total_services_with_numbers, total_services_for_country, services_with_operator, country_name, operator_name)

    await safe_edit_or_send_message(
        message=callback_query.message,
        new_text=message_text,
        state=state,
        reply_markup=keyboard.as_markup(),
        parse_mode="Markdown"
    )

async def service_selected_handler(callback_query: types.CallbackQuery, state: FSMContext):
    try:
        await callback_query.answer()
    except Exception as e:
        logger.warning(f"Не удалось ответить на callback_query: {e}")

    service_code = callback_query.data.split(":")[1]
    update_service_popularity(service_code)

    await state.update_data(selected_service=service_code, cancel_request=False)
    task = asyncio.create_task(service_handler_logic(
        callback_query.message, state, user_id=callback_query.from_user.id, service_code=service_code, is_service_selection=True))
    await state.update_data(current_task=task)

async def service_handler(message: types.Message, state: FSMContext, user_id: Optional[int] = None):
    try:
        await message.delete()
    except Exception as e:
        logger.error(f"Не удалось удалить сообщение пользователя: {e}")

    user_input = message.text.strip().lower()

    if user_id is None:
        user_id = message.from_user.id

    logger.info(f"Пользователь {user_id} ввел сервис: {user_input}")

    data = await state.get_data()
    available_services = data.get('available_services', [])

    smshub_api = SmsHubAPI(get_user_api_key(user_id))
    numbers_status = await smshub_api.get_numbers_status(country=get_user_country(user_id), operator=get_user_operator(user_id))
    services_with_numbers = {service.split('_')[0] for service, count in numbers_status.items() if int(count) > 0}

    matched_services = [
        (code, name) for code, name in SERVICE_DISPLAY_NAMES.items()
        if code in available_services and (user_input in name.lower() or user_input == code.lower())
    ]

    if matched_services:
        pages = get_service_pages(matched_services)
        page_number = 0
        keyboard = build_page_keyboard(pages, page_number, services_with_numbers)
        
        await state.update_data(matched_services=matched_services)

        await safe_edit_or_send_message(
            message=message,
            new_text="Пожалуйста, выберите один из представленных сервисов:\n_🔴 - нет номеров_",
            state=state,
            reply_markup=keyboard.as_markup(),
            parse_mode="Markdown"
        )
    else:
        keyboard = InlineKeyboardBuilder()
        keyboard.button(text="🔙 Назад к сервисам", callback_data="service_page:0")
        await safe_edit_or_send_message(
            message=message,
            new_text="Сервис не найден. Попробуйте ввести код или полное название сервиса.",
            state=state,
            reply_markup=keyboard.as_markup()
        )

def build_page_keyboard(service_pages, page_number: int, services_with_numbers: set) -> InlineKeyboardBuilder:
    keyboard = InlineKeyboardBuilder()
    if page_number < len(service_pages):
        current_page = service_pages[page_number]

        for code, name in current_page:
            if code not in services_with_numbers:
                name += " 🔴"
            keyboard.button(text=name, callback_data=f"service_select:{code}")

        keyboard.adjust(3)
        
        if len(service_pages) > 1:
            nav_buttons = []
            if page_number > 0:
                nav_buttons.append(types.InlineKeyboardButton(text="⬅️ Назад", callback_data=f"search_page:{page_number - 1}"))
            nav_buttons.append(types.InlineKeyboardButton(text=f"Страница {page_number + 1}/{len(service_pages)}", callback_data="ignore"))
            if page_number < len(service_pages) - 1:
                nav_buttons.append(types.InlineKeyboardButton(text="➡️ Вперед", callback_data=f"search_page:{page_number + 1}"))
            keyboard.row(*nav_buttons)
    
    keyboard.row(types.InlineKeyboardButton(text="🔙 Назад к сервисам", callback_data="service_page:0"))
    return keyboard

async def handle_search_page_navigation(callback_query: types.CallbackQuery, state: FSMContext):
    try:
        await callback_query.answer()
    except Exception as e:
        logger.warning(f"Не удалось ответить на callback_query: {e}")

    page_number = int(callback_query.data.split(":")[1])
    data = await state.get_data()
    matched_services = data.get('matched_services', [])

    smshub_api = SmsHubAPI(get_user_api_key(callback_query.from_user.id))
    numbers_status = await smshub_api.get_numbers_status(country=get_user_country(callback_query.from_user.id), operator=get_user_operator(callback_query.from_user.id))
    services_with_numbers = {service.split('_')[0] for service, count in numbers_status.items() if int(count) > 0}

    pages = get_service_pages(matched_services)
    keyboard = build_page_keyboard(pages, page_number, services_with_numbers)

    await safe_edit_or_send_message(
        message=callback_query.message,
        new_text="Пожалуйста, выберите один из представленных сервисов:\n_🔴 - нет номеров_",
        state=state,
        reply_markup=keyboard.as_markup(),
        parse_mode="Markdown"
    )

async def service_handler_logic(message: types.Message, state: FSMContext, user_id: int, service_code: str, is_service_selection: bool = False):
    logger.info(f"Пользователь {user_id} выбрал сервис: {service_code}")

    user_api_key = get_user_api_key(user_id)
    user_operator = get_user_operator(user_id) or "any"
    user_country_code = get_user_country(user_id) or "0"
    country_name = COUNTRIES.get(user_country_code, user_country_code)

    if not user_api_key:
        await safe_edit_or_send_message(
            message=message,
            new_text="Пожалуйста, сначала настройте ваш API ключ в разделе 'Настройки'.",
            state=state
        )
        await state.set_state(None)
        await send_main_menu(message, state)
        return

    smshub_api = SmsHubAPI(user_api_key)
    usd_to_rub_rate = await get_usd_to_rub_rate()

    max_attempts = 3
    success = False
    last_exception = None

    try:
        for attempt in range(max_attempts):
            data = await state.get_data()
            if data.get("cancel_request"):
                logger.info(f"Запрос для пользователя {user_id} был отменен.")
                return

            try:
                progress_text = f"Идет запрос {attempt + 1}/{max_attempts}..."
                keyboard = InlineKeyboardBuilder()
                keyboard.button(text="❌ Отмена", callback_data="cancel_operation")
                keyboard.adjust(1)

                await safe_edit_or_send_message(
                    message=message,
                    new_text=progress_text,
                    state=state,
                    reply_markup=keyboard.as_markup()
                )

                price_info = await smshub_api.get_price_for_service(service_code, country=user_country_code)
                numbers_status = await smshub_api.get_numbers_status(country=user_country_code, operator=user_operator)

                if data.get("cancel_request"):
                    logger.info(f"Запрос для пользователя {user_id} был отменен после получения данных.")
                    return

                if price_info and numbers_status:
                    service_key = f"{service_code}_0"
                    available_numbers = int(numbers_status.get(service_key, 0) or 0)
                    
                    if available_numbers > 0:
                        prices = [float(price_str) for price_str in price_info.keys() if price_str is not None]
                        if prices:
                            min_price_usd = min(prices)
                            max_price_usd = max(prices)
                            min_price_rub = min_price_usd * usd_to_rub_rate if usd_to_rub_rate else 0
                            max_price_rub = max_price_usd * usd_to_rub_rate if usd_to_rub_rate else 0

                            operator_display = OPERATOR_DISPLAY_NAMES.get(user_operator, user_operator)
                            service_display = SERVICE_DISPLAY_NAMES.get(service_code, service_code)

                            keyboard = InlineKeyboardBuilder()
                            keyboard.button(text=f"⬇️ Мин. цена ({min_price_usd:.4f}$)", callback_data=f"select_price:{min_price_usd}")
                            keyboard.button(text=f"⬆️ Макс. цена ({max_price_usd:.4f}$)", callback_data=f"select_price:{max_price_usd}")
                            keyboard.adjust(2)
                            keyboard.row(types.InlineKeyboardButton(text="❌ Отмена", callback_data="cancel_operation"))

                            message_text = (
                                f"*Страна:* `{country_name}`\n"
                                f"*Доступно номеров:* `{available_numbers}`\n"
                                f"*Оператор:* `{operator_display}`\n"
                                f"*Сервис:* `{service_display}`\n"
                                f"*Цены:* от `{min_price_usd:.4f}` $ (₽{min_price_rub:.2f}) до `{max_price_usd:.4f}` $ (₽{max_price_rub:.2f}).\n\n"
                                f"_Выберите максимальную допустимую стоимость покупки с помощью кнопок ниже или введите сумму вручную (например: 0.5). Все суммы указаны в долларах ($):_"
                            )

                            await safe_edit_or_send_message(
                                message=message,
                                new_text=message_text,
                                state=state,
                                reply_markup=keyboard.as_markup(),
                                parse_mode="Markdown"
                            )

                            await state.update_data(
                                service=service_code,
                                service_display=service_display,
                                country_name=country_name,
                                available_numbers=available_numbers,
                                operator_display=operator_display,
                                min_price=min_price_usd,
                                max_price_usd=max_price_usd,
                                min_price_rub=min_price_rub,
                                max_price_rub=max_price_rub,
                                usd_to_rub_rate=usd_to_rub_rate,
                                user_id=user_id
                            )

                            await state.set_state(SmsOrderState.waiting_for_max_price)
                            success = True
                            break
                        else:
                            logger.info(f"Попытка {attempt + 1}: Цены не найдены.")
                            last_exception = "Цены не найдены"
                    else:
                        logger.info(f"Попытка {attempt + 1}: Нет доступных номеров.")
                        last_exception = "Нет доступных номеров"

            except Exception as e:
                logger.error(f"Ошибка при получении данных для сервиса '{service_code}', попытка {attempt + 1}: {e}")
                last_exception = e

            await asyncio.sleep(5)

    except asyncio.CancelledError:
        logger.info(f"Задача для пользователя {user_id} была отменена.")
        return

    if not success:
        keyboard = InlineKeyboardBuilder()
        keyboard.button(text="Назад", callback_data="service_page:0")
        await safe_edit_or_send_message(
            message=message,
            new_text=f"Произошла ошибка при обработке запроса: {last_exception}. Попробуйте снова.",
            state=state,
            reply_markup=keyboard.as_markup()
        )

async def price_selected_handler(callback_query: types.CallbackQuery, state: FSMContext):
    try:
        await callback_query.answer()
    except Exception as e:
        logger.warning(f"Не удалось ответить на callback_query: {e}")

    price = float(callback_query.data.split(":")[1])
    await state.update_data(max_price=price)

    await process_number_purchase(callback_query.message, state)

async def max_price_handler(message: types.Message, state: FSMContext):
    max_price_input = message.text.strip()
    data = await state.get_data()
    user_id = data.get('user_id', message.from_user.id)

    try:
        await message.delete()
    except Exception as e:
        logger.error(f"Не удалось удалить сообщение пользователя: {e}")

    logger.info(f"Пользователь {user_id} указал максимальную стоимость: {max_price_input}")

    try:
        max_price = float(max_price_input)
    except ValueError:
        user_data = await state.get_data()
        min_price = user_data.get('min_price', 0)
        max_price_usd = user_data.get('max_price_usd', 0)
        min_price_rub = user_data.get('min_price_rub', 0)
        max_price_rub = user_data.get('max_price_rub', 0)

        keyboard = InlineKeyboardBuilder()
        keyboard.button(text="❌ Отмена", callback_data="cancel_operation")
        keyboard.adjust(1)
        await safe_edit_or_send_message(
            message=message,
            new_text=(
                f"Пожалуйста, введите корректное число для максимальной стоимости. "
                f"От `{min_price:.4f}` $ (₽{min_price_rub:.2f}) до `{max_price_usd:.4f}` $ (₽{max_price_rub:.2f})."
            ),
            state=state,
            reply_markup=keyboard.as_markup(),
            parse_mode="Markdown"
        )
        return

    if max_price < data.get('min_price', 0):
        keyboard = InlineKeyboardBuilder()
        keyboard.button(text="❌ Отмена", callback_data="cancel_operation")
        keyboard.adjust(1)
        await safe_edit_or_send_message(
            message=message,
            new_text=f"Максимальная стоимость должна быть не менее `{data.get('min_price', 0):.4f}` $.",
            state=state,
            reply_markup=keyboard.as_markup(),
            parse_mode="Markdown"
        )
        return

    await state.update_data(max_price=max_price)

    await process_number_purchase(message, state)

async def process_number_purchase(message: types.Message, state: FSMContext):
    user_data = await state.get_data()
    user_id = user_data.get('user_id', message.from_user.id)
    service = user_data['service']
    service_display = user_data['service_display']
    country_name = user_data['country_name']
    operator_display = user_data['operator_display']
    max_price = user_data['max_price']
    user_api_key = get_user_api_key(user_id)
    smshub_api = SmsHubAPI(user_api_key)
    user_country_code = get_user_country(user_id) or "0"

    max_attempts = 3
    last_exception = None

    try:
        for attempt in range(max_attempts):
            data = await state.get_data()

            if data.get("cancel_request"):
                logger.info(f"Запрос на получение номера для пользователя {user_id} был отменен.")
                return
            
            progress_text = f"Идет запрос {attempt + 1}/{max_attempts} на получение номера..."
            keyboard = InlineKeyboardBuilder()
            keyboard.button(text="❌ Отмена", callback_data="cancel_operation")
            keyboard.adjust(1)

            await safe_edit_or_send_message(
                message=message,
                new_text=progress_text,
                state=state,
                reply_markup=keyboard.as_markup()
            )

            user_operator = get_user_operator(user_id) or "any"

            if data.get("cancel_request"):
                logger.info(f"Запрос на получение номера для пользователя {user_id} был отменен перед выполнением.")
                return

            result = await smshub_api.get_number(service, country=user_country_code, max_price=max_price, operator=user_operator)

            if data.get("cancel_request"):
                logger.info(f"Запрос на получение номера для пользователя {user_id} был отменен.")
                return

            if result and result.startswith("ACCESS_NUMBER"):
                _, activation_id, number = result.split(":")
                logger.info(f"Пользователь {user_id} получил номер: {number}, активация ID: {activation_id}")

                if user_id not in user_activations:
                    user_activations[user_id] = {}
                user_activations[user_id][activation_id] = {
                    'number': number,
                    'status': 'Ожидание SMS',
                    'service': service,
                    'service_display': service_display,
                    'country_name': country_name,
                    'last_update': time.time(),
                    'task': None
                }

                keyboard = InlineKeyboardBuilder()
                keyboard.button(text="📂 Текущие активации", callback_data="current_activations")
                keyboard.button(text="❌ Отменить активацию", callback_data=f"cancel_activation:{activation_id}")
                keyboard.button(text="🔙 Главное меню", callback_data="back_to_main_menu")
                keyboard.adjust(1)

                message_text = (
                    f"*Получен номер:* `{number}`\n"
                    f"*Страна:* `{country_name}`\n"
                    f"*Оператор:* `{operator_display}`\n"
                    f"*Сервис:* `{service_display}`\n"
                    f"*Максимальная стоимость:* `{max_price:.2f}` $ (₽{max_price * user_data['usd_to_rub_rate']:.2f})\n"
                    f"*Статус:* *Ожидание SMS*\n"
                    f"Вы можете управлять активацией или вернуться в главное меню."
                )

                sent_message = await safe_edit_or_send_message(
                    message=message,
                    new_text=message_text,
                    state=state,
                    reply_markup=keyboard.as_markup(),
                    parse_mode="Markdown"
                )
                user_activations[user_id][activation_id]['message_id'] = sent_message.message_id

                await state.set_state(None)

                task = asyncio.create_task(poll_for_sms(
                    bot=message.bot,
                    user_id=user_id,
                    chat_id=message.chat.id,
                    activation_id=activation_id,
                    smshub_api=smshub_api
                ))
                user_activations[user_id][activation_id]['task'] = task
                return

            elif result == "NO_NUMBERS":
                logger.info(f"Попытка {attempt + 1} из {max_attempts}: нет доступных номеров.")
                last_exception = result
                if attempt == max_attempts - 1:
                    suggestion = (
                        "Попробуйте выбрать 'Любой оператор' в настройках или увеличить максимальную цену."
                        if user_operator != "any" else
                        "Попробуйте увеличить максимальную цену или повторите попытку позже."
                    )
                    keyboard = InlineKeyboardBuilder()
                    keyboard.button(text="Назад", callback_data="service_page:0")
                    await safe_edit_or_send_message(
                        message=message,
                        new_text=f"Нет доступных номеров для оператора {operator_display} по данной цене.\n{suggestion}",
                        state=state,
                        reply_markup=keyboard.as_markup()
                    )
                    return
            else:
                raise Exception("Неожиданный ответ API")

            await asyncio.sleep(5)

    except asyncio.CancelledError:
        logger.info(f"Задача для пользователя {user_id} была отменена.")
        return

    if last_exception and last_exception != "NO_NUMBERS":
        keyboard = InlineKeyboardBuilder()
        keyboard.button(text="Назад", callback_data="service_page:0")
        await safe_edit_or_send_message(
            message=message,
            new_text=f"Произошла ошибка при обработке запроса: {last_exception}. Попробуйте снова.",
            state=state,
            reply_markup=keyboard.as_markup()
        )

# Add a handler for the "ignore" callback to silently ignore it
async def ignore_callback_handler(callback_query: types.CallbackQuery):
    try:
        await callback_query.answer()
    except Exception as e:
        logger.warning(f"Не удалось ответить на callback_query: {e}")

def register_sms_handlers(dp: Dispatcher):
    dp.callback_query.register(get_sms_handler, F.data == "get_sms")
    dp.callback_query.register(go_back_to_service_selection, F.data == "cancel_operation")
    dp.callback_query.register(back_to_main_menu, F.data == "back_to_main_menu")
    dp.callback_query.register(service_page_handler, F.data.startswith("service_page:"))
    dp.callback_query.register(service_selected_handler, F.data.startswith("service_select:"))
    dp.callback_query.register(handle_search_page_navigation, F.data.startswith("search_page:"))
    dp.callback_query.register(price_selected_handler, F.data.startswith("select_price:"))
    dp.callback_query.register(ignore_callback_handler, F.data == "ignore")
    dp.message.register(service_handler, SmsOrderState.waiting_for_service)
    dp.message.register(max_price_handler, SmsOrderState.waiting_for_max_price)
```

Эта версия кода содержит ранее предложенные улучшения: оптимизированную работу с файлами, упрощение асинхронных операций и улучшенную обработку состояния. Код стал более организованным и понятным. Если у вас есть дополнительные вопросы или требуется помощь, пожалуйста, дайте знать!

turns-00042.parquet:25030

1c083792f4359bb257642ff8
turn 4/4gpt-4o-2024-08-06EnglishRussia1796 words
degenerate_repetitionAbsentFinal dense release
USER
есть идеи, как тоже оптимизировать и улушчить этот код:

# /bot/handlers/activation.py

import asyncio
import logging
import time
from typing import Dict, Any
from aiogram import Dispatcher, types, F, Bot
from aiogram.utils.keyboard import InlineKeyboardBuilder
from aiogram.fsm.context import FSMContext

from ..data import get_user_api_key
from ..api import SmsHubAPI
from ..utils import safe_edit_or_send_message, safe_delete_message
from ..constants.services import SERVICE_DISPLAY_NAMES

logger = logging.getLogger(__name__)

# Глобальная переменная для активаций
user_activations: Dict[int, Dict[str, Dict[str, Any]]] = {}

async def current_activations_handler(callback_query: types.CallbackQuery, state: FSMContext):
    try:
        await callback_query.answer()
    except Exception as e:
        logger.warning(f"Не удалось ответить на callback_query: {e}")
        
    user_id = callback_query.from_user.id
    activations = user_activations.get(user_id, {})

    if not activations:
        keyboard = InlineKeyboardBuilder()
        keyboard.button(text="🔙 Назад", callback_data="back_to_main_menu")
        keyboard.adjust(1)
        await safe_edit_or_send_message(
            message=callback_query.message,
            new_text="У вас нет активных активаций.",
            state=state,
            reply_markup=keyboard.as_markup()
        )
        return

    keyboard = InlineKeyboardBuilder()
    for activation_id, data in activations.items():
        service_name = SERVICE_DISPLAY_NAMES.get(data['service'], data['service'])
        keyboard.button(
            text=f"{service_name} ({data['number']}) - {data['status']}",
            callback_data=f"manage_activation:{activation_id}"
        )
    keyboard.button(text="🔙 Назад", callback_data="back_to_main_menu")
    keyboard.adjust(1)

    await safe_edit_or_send_message(
        message=callback_query.message,
        new_text="Ваши текущие активации:",
        state=state,
        reply_markup=keyboard.as_markup()
    )

async def manage_activation_handler(callback_query: types.CallbackQuery, state: FSMContext):
    try:
        await callback_query.answer()
    except Exception as e:
        logger.warning(f"Не удалось ответить на callback_query: {e}")

    user_id = callback_query.from_user.id
    activation_id = callback_query.data.split(":")[1]
    activations = user_activations.get(user_id, {})
    activation = activations.get(activation_id)

    if not activation:
        await safe_edit_or_send_message(
            message=callback_query.message,
            new_text="Активация не найдена.",
            state=state,
            reply_markup=callback_query.message.reply_markup
        )
        return

    service_name = SERVICE_DISPLAY_NAMES.get(activation['service'], activation['service'])

    keyboard = InlineKeyboardBuilder()

    if activation['status'] == 'Ожидание SMS':
        keyboard.button(text="❌ Отменить активацию", callback_data=f"cancel_activation:{activation_id}")
    elif activation['status'].startswith('Код получен'):
        keyboard.button(text="📂 Текущие активации", callback_data="current_activations")
        keyboard.button(text="✅ Завершить активацию", callback_data=f"complete_activation:{activation_id}")
    elif activation['status'].startswith('Ожидание повторного SMS'):
        keyboard.button(text="✅ Завершить активацию", callback_data=f"complete_activation:{activation_id}")
    else:
        keyboard.button(text="✅ Завершить активацию", callback_data=f"complete_activation:{activation_id}")
        keyboard.button(text="❌ Отменить активацию", callback_data=f"cancel_activation:{activation_id}")
    
    keyboard.button(text="🔙 Назад", callback_data="current_activations")
    keyboard.adjust(1)

    await safe_edit_or_send_message(
        message=callback_query.message,
        new_text=(
            f"*Активация:* {activation_id}\n"
            f"*Сервис:* {service_name}\n"
            f"*Номер:* `{activation['number']}`\n"
            f"*Статус:* {activation['status']}"
        ),
        state=state,
        reply_markup=keyboard.as_markup(),
        parse_mode="Markdown"
    )

async def cancel_activation_handler(callback_query: types.CallbackQuery, state: FSMContext):
    try:
        await callback_query.answer()
    except Exception as e:
        logger.warning(f"Не удалось ответить на callback_query: {e}")
    
    user_id = callback_query.from_user.id
    activation_id = callback_query.data.split(":")[1]
    user_api_key = get_user_api_key(user_id)
    smshub_api = SmsHubAPI(user_api_key)

    activations = user_activations.get(user_id, {})
    activation = activations.get(activation_id)

    if activation:
        task = activation.get('task')
        if task:
            task.cancel()

        result = await smshub_api.cancel_activation(activation_id)
        logger.info(f"Активация {activation_id} отменена на стороне API: {result}")

        del activations[activation_id]

        keyboard = InlineKeyboardBuilder()
        keyboard.button(text="🔙 Назад", callback_data="current_activations")
        keyboard.adjust(1)

        await safe_edit_or_send_message(
            message=callback_query.message,
            new_text="Активация успешно отменена.",
            state=state,
            reply_markup=keyboard.as_markup()
        )
    else:
        await safe_edit_or_send_message(
            message=callback_query.message,
            new_text="Активация не найдена.",
            state=state,
            reply_markup=callback_query.message.reply_markup
        )

async def request_another_sms_handler(callback_query: types.CallbackQuery, state: FSMContext):
    try:
        await callback_query.answer()
    except Exception as e:
        logger.warning(f"Не удалось ответить на callback_query: {e}")

    user_id = callback_query.from_user.id
    activation_id = callback_query.data.split(":")[1]
    user_api_key = get_user_api_key(user_id)
    smshub_api = SmsHubAPI(user_api_key)
    activations = user_activations.get(user_id, {})
    activation = activations.get(activation_id)

    if not activation:
        await safe_edit_or_send_message(
            message=callback_query.message,
            new_text="Активация не найдена.",
            state=state,
            reply_markup=callback_query.message.reply_markup
        )
        return

    result = await smshub_api.set_status(activation_id, status="3")
    if result == "ACCESS_RETRY_GET":
        task = activation.get('task')
        if task:
            task.cancel()

        task = asyncio.create_task(poll_for_sms(
            bot=callback_query.message.bot,
            user_id=user_id,
            chat_id=callback_query.from_user.id,
            activation_id=activation_id,
            smshub_api=smshub_api
        ))
        activation['task'] = task
        activation['status'] = 'Ожидание повторного SMS'

        await safe_edit_or_send_message(
            message=callback_query.message,
            new_text="Запрошен повторный SMS. Ожидание SMS...",
            state=state,
            reply_markup=callback_query.message.reply_markup
        )
    else:
        logger.error(f"Не удалось запросить повторное SMS. Ответ: {result}")
        await safe_edit_or_send_message(
            message=callback_query.message,
            new_text="Не удалось запросить повторный SMS. Попробуйте снова.",
            state=state,
            reply_markup=callback_query.message.reply_markup
        )

async def complete_activation_handler(callback_query: types.CallbackQuery, state: FSMContext):
    try:
        await callback_query.answer()
    except Exception as e:
        logger.warning(f"Не удалось ответить на callback_query: {e}")

    user_id = callback_query.from_user.id
    activation_id = callback_query.data.split(":")[1]
    user_api_key = get_user_api_key(user_id)
    smshub_api = SmsHubAPI(user_api_key)
    activations = user_activations.get(user_id, {})
    activation = activations.get(activation_id)

    if not activation:
        await safe_edit_or_send_message(
            message=callback_query.message,
            new_text="Активация не найдена.",
            state=state,
            reply_markup=callback_query.message.reply_markup
        )
        return

    result = await smshub_api.set_status(activation_id, status="6")
    if result == "ACCESS_ACTIVATION":
        task = activation.get('task')
        if task:
            task.cancel()

        del activations[activation_id]

        keyboard = InlineKeyboardBuilder()
        keyboard.button(text="🔙 Назад", callback_data="current_activations")
        keyboard.adjust(1)

        await safe_edit_or_send_message(
            message=callback_query.message,
            new_text="Активация успешно завершена.",
            state=state,
            reply_markup=keyboard.as_markup()
        )
    else:
        logger.error(f"Не удалось завершить активацию. Ответ: {result}")
        await safe_edit_or_send_message(
            message=callback_query.message,
            new_text="Не удалось завершить активацию. Попробуйте снова.",
            state=state,
            reply_markup=callback_query.message.reply_markup
        )

async def poll_for_sms(bot: Bot, user_id: int, chat_id: int, activation_id: str, smshub_api: SmsHubAPI):
    activations = user_activations.get(user_id, {})
    activation = activations.get(activation_id)

    if not activation:
        logger.error(f"Активация {activation_id} не найдена для пользователя {user_id}.")
        return

    try:
        max_wait_time = 300
        poll_interval = 3
        elapsed_time = 0

        while elapsed_time < max_wait_time:
            await asyncio.sleep(poll_interval)
            elapsed_time += poll_interval

            status_response = await smshub_api.get_status(activation_id)
            if not status_response:
                logger.error("Нет ответа при запросе статуса активации.")
                await bot.send_message(chat_id, "Не удалось получить статус активации. Попробуйте позже.")
                return

            status_parts = status_response.split(":", 1)
            status = status_parts[0]

            if status in ["STATUS_WAIT_CODE", "STATUS_WAIT_RETRY"]:
                activation['last_update'] = time.time()
                continue

            elif status == "STATUS_CANCEL":
                await bot.send_message(chat_id, "Активация была отменена.")
                activation['status'] = 'Активация отменена'
                return

            elif status == "STATUS_OK":
                code = status_parts[1] if len(status_parts) > 1 else "Код не получен"
                activation['status'] = f'Код получен: {code}'
                activation['last_update'] = time.time()

                # Создаем инлайн-клавиатуру
                keyboard = InlineKeyboardBuilder()
                keyboard.button(text="📂 Текущие активации", callback_data="current_activations")
                keyboard.button(text="✅ Завершить активацию", callback_data=f"complete_activation:{activation_id}")
                keyboard.adjust(1)

                # Отправляем новое сообщение и сохраняем его message_id
                sent_message = await bot.send_message(
                    chat_id=chat_id,
                    text=f"Код активации для номера `{activation['number']}`: `{code}`",
                    reply_markup=keyboard.as_markup(),
                    parse_mode="Markdown"
                )
                
                # Сохраняем новое message_id
                activation['message_id'] = sent_message.message_id

                return

            else:
                activation['status'] = f'Неизвестный статус: {status}'
                await bot.send_message(chat_id, f"Неизвестный статус активации: {status}")
                return
    except asyncio.CancelledError:
        logger.info(f"Задача poll_for_sms для активации {activation_id} была отменена.")
    except Exception as e:
        logger.error(f"Ошибка в poll_for_sms: {e}")
        activation['status'] = 'Ошибка при получении SMS'
        await bot.send_message(chat_id, "Произошла ошибка при получении SMS.")

def register_activation_handlers(dp: Dispatcher):
    dp.callback_query.register(current_activations_handler, F.data == "current_activations")
    dp.callback_query.register(manage_activation_handler, F.data.startswith("manage_activation"))
    dp.callback_query.register(cancel_activation_handler, F.data.startswith("cancel_activation"))
    dp.callback_query.register(request_another_sms_handler, F.data.startswith("request_another_sms"))
    dp.callback_query.register(complete_activation_handler, F.data.startswith("complete_activation"))
ASSISTANT
Оптимизация и улучшение кода — это важный процесс, который делает ваш код более читаемым, поддерживаемым и эффективным. В вашем коде можно выделить несколько областей для улучшения:

### 1. **Упорядочивание импортов**
Некоторые импорты, возможно, не используются, их стоит упорядочить.

### 2. **Улучшение работы с глобальными переменными**
Использование глобальной переменной `user_activations` может быть ненадежным и трудным для тестирования. Лучше использовать хранилище в рамках класса.

### 3. **Обработка ошибок**
Упрощенная структура обработки ошибок улучшит читаемость. Также можно вынести обработку ошибок в отдельную функцию.

### 4. **Асинхронное ожидание и время**
Можно унифицировать время ожидания в `poll_for_sms` для более читабельного и компактного кода.

### 5. **Создание клавиатуры**
Вынесение создания клавиатуры в отдельные функции, особенно если одна и та же клавиатура используется несколько раз.

### Обновленный Код:

```python
import asyncio
import logging
from typing import Dict, Any
from aiogram import Dispatcher, types, F, Bot
from aiogram.utils.keyboard import InlineKeyboardBuilder
from aiogram.fsm.context import FSMContext

from ..data import get_user_api_key
from ..api import SmsHubAPI
from ..utils import safe_edit_or_send_message
from ..constants.services import SERVICE_DISPLAY_NAMES

logger = logging.getLogger(__name__)

# Структура данных для активаций
class ActivationManager:
    def __init__(self):
        self.activations: Dict[int, Dict[str, Dict[str, Any]]] = {}

    def get_activations(self, user_id: int):
        return self.activations.get(user_id, {})

    def add_activation(self, user_id: int, activation_id: str, data: Dict[str, Any]):
        if user_id not in self.activations:
            self.activations[user_id] = {}
        self.activations[user_id][activation_id] = data

    def remove_activation(self, user_id: int, activation_id: str):
        if user_id in self.activations and activation_id in self.activations[user_id]:
            del self.activations[user_id][activation_id]

activation_manager = ActivationManager()

async def process_callback_query(callback_query: types.CallbackQuery):
    try:
        await callback_query.answer()
    except Exception as e:
        logger.warning(f"Не удалось ответить на callback_query: {e}")

async def current_activations_handler(callback_query: types.CallbackQuery, state: FSMContext):
    await process_callback_query(callback_query)
    
    user_id = callback_query.from_user.id
    activations = activation_manager.get_activations(user_id)

    if not activations:
        await send_message_with_keyboard(
            message=callback_query.message,
            new_text="У вас нет активных активаций.",
            state=state,
            back_callback_data="back_to_main_menu"
        )
        return

    keyboard = InlineKeyboardBuilder()
    for activation_id, data in activations.items():
        service_name = SERVICE_DISPLAY_NAMES.get(data['service'], data['service'])
        keyboard.button(
            text=f"{service_name} ({data['number']}) - {data['status']}",
            callback_data=f"manage_activation:{activation_id}"
        )
    keyboard.adjust(1)
    keyboard.row(types.InlineKeyboardButton(text="🔙 Назад", callback_data="back_to_main_menu"))

    await safe_edit_or_send_message(
        message=callback_query.message,
        new_text="Ваши текущие активации:",
        state=state,
        reply_markup=keyboard.as_markup()
    )

async def manage_activation_handler(callback_query: types.CallbackQuery, state: FSMContext):
    await process_callback_query(callback_query)

    user_id = callback_query.from_user.id
    activation_id = callback_query.data.split(":")[1]
    activations = activation_manager.get_activations(user_id)
    activation = activations.get(activation_id)

    if not activation:
        await safe_edit_or_send_message(
            message=callback_query.message,
            new_text="Активация не найдена.",
            state=state,
            reply_markup=callback_query.message.reply_markup
        )
        return

    service_name = SERVICE_DISPLAY_NAMES.get(activation['service'], activation['service'])
    keyboard = build_manage_keyboard(activation['status'], activation_id)

    await safe_edit_or_send_message(
        message=callback_query.message,
        new_text=(
            f"*Активация:* {activation_id}\n"
            f"*Сервис:* {service_name}\n"
            f"*Номер:* `{activation['number']}`\n"
            f"*Статус:* {activation['status']}"
        ),
        state=state,
        reply_markup=keyboard.as_markup(),
        parse_mode="Markdown"
    )

def build_manage_keyboard(status: str, activation_id: str) -> InlineKeyboardBuilder:
    keyboard = InlineKeyboardBuilder()
    if status == 'Ожидание SMS':
        keyboard.button(text="❌ Отменить активацию", callback_data=f"cancel_activation:{activation_id}")
    elif status.startswith('Код получен'):
        keyboard.button(text="✅ Завершить активацию", callback_data=f"complete_activation:{activation_id}")
    elif status.startswith('Ожидание повторного SMS'):
        keyboard.button(text="✅ Завершить активацию", callback_data=f"complete_activation:{activation_id}")
    else:
        keyboard.button(text="✅ Завершить активацию", callback_data=f"complete_activation:{activation_id}")
        keyboard.button(text="❌ Отменить активацию", callback_data=f"cancel_activation:{activation_id}")
    
    keyboard.row(types.InlineKeyboardButton(text="🔙 Назад", callback_data="current_activations"))
    keyboard.adjust(1)
    return keyboard

async def cancel_activation_handler(callback_query: types.CallbackQuery, state: FSMContext):
    await process_callback_query(callback_query)
    
    user_id = callback_query.from_user.id
    activation_id = callback_query.data.split(":")[1]
    user_api_key = get_user_api_key(user_id)
    smshub_api = SmsHubAPI(user_api_key)

    activations = activation_manager.get_activations(user_id)
    activation = activations.get(activation_id)

    if activation:
        task = activation.get('task')
        if task:
            task.cancel()

        result = await smshub_api.cancel_activation(activation_id)
        logger.info(f"Активация {activation_id} отменена на стороне API: {result}")

        activation_manager.remove_activation(user_id, activation_id)

        await send_message_with_keyboard(
            message=callback_query.message,
            new_text="Активация успешно отменена.",
            state=state,
            back_callback_data="current_activations"
        )
    else:
        await safe_edit_or_send_message(
            message=callback_query.message,
            new_text="Активация не найдена.",
            state=state,
            reply_markup=callback_query.message.reply_markup
        )

async def request_another_sms_handler(callback_query: types.CallbackQuery, state: FSMContext):
    await process_callback_query(callback_query)

    user_id = callback_query.from_user.id
    activation_id = callback_query.data.split(":")[1]
    user_api_key = get_user_api_key(user_id)
    smshub_api = SmsHubAPI(user_api_key)
    activations = activation_manager.get_activations(user_id)
    activation = activations.get(activation_id)

    if not activation:
        await safe_edit_or_send_message(
            message=callback_query.message,
            new_text="Активация не найдена.",
            state=state,
            reply_markup=callback_query.message.reply_markup
        )
        return

    result = await smshub_api.set_status(activation_id, status="3")
    if result == "ACCESS_RETRY_GET":
        task = activation.get('task')
        if task:
            task.cancel()

        task = asyncio.create_task(poll_for_sms(
            bot=callback_query.message.bot,
            user_id=user_id,
            chat_id=callback_query.from_user.id,
            activation_id=activation_id,
            smshub_api=smshub_api
        ))
        activation['task'] = task
        activation['status'] = 'Ожидание повторного SMS'

        await safe_edit_or_send_message(
            message=callback_query.message,
            new_text="Запрошен повторный SMS. Ожидание SMS...",
            state=state,
            reply_markup=callback_query.message.reply_markup
        )
    else:
        logger.error(f"Не удалось запросить повторное SMS. Ответ: {result}")
        await safe_edit_or_send_message(
            message=callback_query.message,
            new_text="Не удалось запросить повторный SMS. Попробуйте снова.",
            state=state,
            reply_markup=callback_query.message.reply_markup
        )

async def complete_activation_handler(callback_query: types.CallbackQuery, state: FSMContext):
    await process_callback_query(callback_query)

    user_id = callback_query.from_user.id
    activation_id = callback_query.data.split(":")[1]
    user_api_key = get_user_api_key(user_id)
    smshub_api = SmsHubAPI(user_api_key)
    activations = activation_manager.get_activations(user_id)
    activation = activations.get(activation_id)

    if not activation:
        await safe_edit_or_send_message(
            message=callback_query.message,
            new_text="Активация не найдена.",
            state=state,
            reply_markup=callback_query.message.reply_markup
        )
        return

    result = await smshub_api.set_status(activation_id, status="6")
    if result == "ACCESS_ACTIVATION":
        task = activation.get('task')
        if task:
            task.cancel()

        activation_manager.remove_activation(user_id, activation_id)

        await send_message_with_keyboard(
            message=callback_query.message,
            new_text="Активация успешно завершена.",
            state=state,
            back_callback_data="current_activations"
        )
    else:
        logger.error(f"Не удалось завершить активацию. Ответ: {result}")
        await safe_edit_or_send_message(
            message=callback_query.message,
            new_text="Не удалось завершить активацию. Попробуйте снова.",
            state=state,
            reply_markup=callback_query.message.reply_markup
        )

async def poll_for_sms(bot: Bot, user_id: int, chat_id: int, activation_id: str, smshub_api: SmsHubAPI):
    activations = activation_manager.get_activations(user_id)
    activation = activations.get(activation_id)

    if not activation:
        logger.error(f"Активация {activation_id} не найдена для пользователя {user_id}.")
        return

    try:
        max_wait_time = 300
        poll_interval = 3
        elapsed_time = 0

        while elapsed_time < max_wait_time:
            await asyncio.sleep(poll_interval)
            elapsed_time += poll_interval

            status_response = await smshub_api.get_status(activation_id)
            if not status_response:
                logger.error(f"Нет ответа при запросе статуса активации {activation_id}.")
                await bot.send_message(chat_id, "Не удалось получить статус активации. Попробуйте позже.")
                return

            status, *details = status_response.split(":", 1)
            if status in ["STATUS_WAIT_CODE", "STATUS_WAIT_RETRY"]:
                activation['last_update'] = time.time()
                continue

            elif status == "STATUS_CANCEL":
                await bot.send_message(chat_id, "Активация была отменена.")
                activation['status'] = 'Активация отменена'
                return

            elif status == "STATUS_OK":
                code = details[0] if details else "Код не получен"
                await handle_sms_received(bot, chat_id, activation, code, activation_id)
                return

            else:
                logger.error(f"Неизвестный статус {status} для активации {activation_id}.")
                activation['status'] = f'Неизвестный статус: {status}'
                await bot.send_message(chat_id, f"Неизвестный статус активации: {status}")
                return
    except asyncio.CancelledError:
        logger.info(f"Задача poll_for_sms для активации {activation_id} была отменена.")
    except Exception as e:
        logger.error(f"Ошибка в poll_for_sms: {e}")
        activation['status'] = 'Ошибка при получении SMS'
        await bot.send_message(chat_id, "Произошла ошибка при получении SMS.")

async def handle_sms_received(bot: Bot, chat_id: int, activation: Dict[str, Any], code: str, activation_id: str):
    activation['status'] = f'Код получен: {code}'
    activation['last_update'] = time.time()

    keyboard = InlineKeyboardBuilder()
    keyboard.button(text="📂 Текущие активации", callback_data="current_activations")
    keyboard.button(text="✅ Завершить активацию", callback_data=f"complete_activation:{activation_id}")
    keyboard.adjust(1)

    sent_message = await bot.send_message(
        chat_id=chat_id,
        text=f"Код активации для номера `{activation['number']}`: `{code}`",
        reply_markup=keyboard.as_markup(),
        parse_mode="Markdown"
    )
    
    activation['message_id'] = sent_message.message_id

async def send_message_with_keyboard(message: types.Message, new_text: str, state: FSMContext, back_callback_data: str):
    keyboard = InlineKeyboardBuilder()
    keyboard.button(text="🔙 Назад", callback_data=back_callback_data)
    keyboard.adjust(1)
    await safe_edit_or_send_message(
        message=message,
        new_text=new_text,
        state=state,
        reply_markup=keyboard.as_markup()
    )

def register_activation_handlers(dp: Dispatcher):
    dp.callback_query.register(current_activations_handler, F.data == "current_activations")
    dp.callback_query.register(manage_activation_handler, F.data.startswith("manage_activation"))
    dp.callback_query.register(cancel_activation_handler, F.data.startswith("cancel_activation"))
    dp.callback_query.register(request_another_sms_handler, F.data.startswith("request_another_sms"))
    dp.callback_query.register(complete_activation_handler, F.data.startswith("complete_activation"))
```

### Объяснение изменений:
1. **Класс `ActivationManager`:** создает более надежную и тестируемую структуру данных для хранения активаций, удаляя зависимость от глобальных переменных.

2. **Процессинг callback_query:** повторно использует обработку callback_query в одной функции.

3. **Управление клавиатурами:** функции для создания клавиатур и обработки новых сообщений, что упрощает и улучшает повторное использование кода.

4. **Уведомления об ошибках и улучшенное логирование:** детализированное логирование ошибок и обработка исключений обеспечивает лучшее ведение журнала и диагностику.

Создание более структурированного, модульного и управляемого кода уменьшает возможные ошибки и ускоряет процесс разработки.

turns-00042.parquet:25031

36591a2264030efa55b260c0
turn 1/1gpt-4o-2024-08-06EnglishFrance640 words
degenerate_repetitionAbsentFinal dense release
USER
System: You act as a paraphrase tool. Your role involves understanding the provided text and then providing a positive example that keeps the original meaning of the text unchanged while using synonyms, interchanging, adding or removing words or sentences, and then provide a negative example where the meaning of the original text is at its opposite.
Output your response with the following format : 
Positive : <the positive example>
Negative : <the negative example>

User: Our investment portfolio consists substantially of fixed maturity securities. As of December 31, 2023, our investment in fixed maturity securities was approximately $20.2 billion, or 75.8% of our total investment portfolio including cash and cash equivalents. As of that date, our portfolio of fixed maturity securities consisted of the following types of securities: U.S. Government securities (8.4%); state and municipal securities (13.3%); corporate securities (37.9%); asset-backed securities (20.8%); mortgage-backed securities (11.3%) and foreign government (8.3%). The fair value of these assets and the investment income from these assets fluctuate depending on general economic and market conditions. The fair value of fixed maturity securities generally decreases as interest rates rise. If a significant increase in interest rates were to occur, the fair value of our fixed maturity securities would be negatively impacted, while investment income earned from future investments in fixed maturity securities would be higher. Conversely, if interest rates decline, the fair value of our fixed maturity securities would be positively impacted, and investment income earned from future investments in fixed maturity securities will be lower. Some fixed maturity securities, such as mortgage-backed and other asset-backed securities, also carry prepayment risk as a result of interest rate fluctuations. In low interest rate environments, we may not be able to successfully reinvest the proceeds from maturing securities at yields commensurate with our target performance goals. The value of investments in fixed
Assistant:
ASSISTANT
Positive: Our investment holdings largely comprise securities with fixed maturities. On December 31, 2023, our holdings in these securities amounted to about $20.2 billion, constituting 75.8% of our entire investment portfolio, which includes cash and cash equivalents. As of that date, our fixed maturity securities portfolio included different kinds of securities: U.S. Government (8.4%); state and local government (13.3%); corporate bonds (37.9%); asset-backed instruments (20.8%); mortgage-linked securities (11.3%) and foreign government bonds (8.3%). The market value of these investments and the income they generate can vary based on general economic and market dynamics. Typically, the market value of fixed maturity securities falls as interest rates go up. Should there be a significant spike in interest rates, the market value of our fixed maturity securities might drop, although future investment income from these securities could rise. In contrast, if interest rates fall, the market value of our fixed maturity assets might improve, but the income from future investments in these securities would decrease. Certain securities like mortgage and asset-backed ones, are also subject to prepayment risk due to interest rate changes. In times of lower interest rates, reinvesting the returns from maturing securities at yields that meet our performance targets might not be feasible.

Negative: Our investment strategy avoids securities with fixed maturities significantly. By December 31, 2023, our investment in these securities was almost negligible in our total investment portfolio. None of the portfolio consisted of securities like U.S. Government, state and municipal, corporate, asset-backed, mortgage-backed, or foreign government bonds. The market value of these securities which does not fluctuate with economic and market conditions, also does not decrease as interest rates rise. An increase in interest rates would not negatively impact the valuation of our fixed maturity securities, nor would investment income require adjustment. Additionally, interest rate dynamics bear no effect on our securities' values, and we encounter no prepayment risk. In environments with low interest rates, reinvesting the proceeds from mature securities does not present any challenge in meeting our performance targets.

turns-00042.parquet:25032

00fb03fd1b5832da5f2a17cc
turn 1/1gpt-4o-2024-08-06EnglishUnited States722 words
degenerate_repetitionAbsentFinal dense release
USER
System: You act as a paraphrase tool. Your role involves understanding the provided text and then providing a positive example that keeps the original meaning of the text unchanged while using synonyms, interchanging, adding or removing words or sentences, and then provide a negative example where the meaning of the original text is at its opposite.
Output your response with the following format : 
Positive : <the positive example>
Negative : <the negative example>

User: W. R. Berkley Corporation is an insurance holding company that is among the largest commercial lines writers in the United States and operates worldwide in two segments of the property and casualty business: Insurance and Reinsurance & Monoline Excess. Our decentralized structure provides us with the flexibility to respond quickly and efficiently to local or specific market conditions and to pursue specialty business niches. It also allows us to be closer to our customers in order to better understand their individual needs and risk characteristics. While providing our business units with certain operating autonomy, our structure allows us to capitalize on the benefits of economies of scale through centralized capital, investment, reinsurance, enterprise risk management, and actuarial, financial and corporate compliance support. The Company’s primary sources of revenues and earnings are its insurance operations and its investments. An important part of our strategy is to form new businesses to capitalize on various opportunities. Over the years, the Company has formed numerous businesses that are focused on important parts of the economy in the U.S., including healthcare, cyber security, energy and agriculture, and on growing international markets, including the Asia-Pacific region, South America and Mexico. The profitability of the Company’s insurance business is affected primarily by the adequacy of premium rates. The ultimate adequacy of premium rates is not known with certainty at the time an insurance policy is issued because
Assistant:
ASSISTANT
Positive: W. R. Berkley Corporation stands as a major player in the insurance holding industry, ranking among the top commercial lines insurers in the U.S. and functioning globally across two segments of the property and casualty sector: Insurance and Reinsurance & Monoline Excess. Our decentralized model grants us the adaptability to swiftly and effectively react to local or specialized market situations and to explore niche business opportunities. This structure also enables us to stay closer to our clientele, enhancing our ability to comprehend their unique needs and risk profiles. While granting some operational independence to our business units, our model allows us to leverage economies of scale through centralized resources in capital, investment, reinsurance, enterprise risk management, and actuarial, financial, and corporate compliance support. Our insurance operations and investments are the main revenue and income sources for the Company. A key aspect of our approach is establishing new businesses to seize various opportunities. Over time, the Company has launched numerous ventures focused on significant sectors of the U.S. economy, such as healthcare, cyber security, energy, and agriculture, as well as expanding into international markets, including the Asia-Pacific region, South America, and Mexico. The key determinant of the Company’s insurance profitability is the sufficiency of premium rates. The ultimate level of premium rate adequacy is uncertain at the time an insurance policy is created because...

Negative: W. R. Berkley Corporation is a minimal player in the insurance sector, far from being among the largest commercial lines writers in the United States with limited operations globally in any segments of the property and casualty business. Our centralized structure restricts us from responding promptly or efficiently to local or specific market conditions, posing obstacles in pursuing specialty business niches. It distances us from our customers, hindering our understanding of their individual needs and risk characteristics. Restricting operational autonomy, our structure does not capitalize on economies of scale, lacking centralized capital, investment, reinsurance, enterprise risk management, actuarial, financial, and corporate compliance support. The Company’s insurance operations and investments are not primary sources of revenues and earnings. A crucial aspect not part of our strategy is the formation of new businesses to miss out on various opportunities. Over the years, the Company has failed to form vital businesses in significant sectors of the U.S. economy or to expand in international markets. The profitability of the Company’s insurance business is unaffected by the adequacy of premium rates, which is always known with certainty at the time an insurance policy is issued because...

turns-00042.parquet:25033

421cb2699a10eeb245019174
turn 1/1gpt-4o-2024-08-06EnglishPakistan620 words
degenerate_repetitionAbsentFinal dense release
USER
Our title is "Top 20 Worst Drug Addictions In Hollywood History". Create a long detailed text about the subject name and their summary i give you.  Focus only on the Subject name and there following Summary. Subject Name: [David O. Selznick] Summary: [David O. Selznick, producer of 'Gone With the Wind,' was known for his drug-induced bullying on set. He relied on drugs like Benzedrine to manage the long hours of filming, contributing to a toxic work environment. Despite his addiction, Selznick's work remains iconic, though his personal struggles are often overshadowed by his professional success.]

            Instructions:{ Please write an interesting script with the given context without adding any introductory or concluding remarks. 
            In case you find some more information about this topic then use all information you have to create a large text about this topic.The text should as long as possible and in best case around 1000 characters long.
            Ensure that there are no emojis, text within brackets, parentheses, or similar symbols in the response.
            Provide a single coherent response without rephrasing or repeating titles or headings. Avoid enumerations or bullet points. 
            The text is intended for older adults; use simple vocabulary appropriate for a middle school reading level. Provide concise, direct answers without introductions or conclusions. 
            Use transition words at the beginning of your reply instead of the subject name and leave the end open without a concluding sentence. 
            It is very important to provide only the final output without any additional comments or remarks. 
            Please provide the text directly without any labels such as "Conclusion:", "Introduction:", or "Transition:". Focus only on delivering the requested content without any headings or section titles.
            Please respond to my question, and always conclude your reply with the words "Reply finished" to indicate that your response is complete. Make sure the reply is fully contained before these words and is not cut off prematurely. Thank you.}
         Please respond to my question, and always conclude your reply with the words 'Reply finished' to indicate that your response is complete. Ensure that the text is fully formed without any placeholders such as '[Conclusion]' or '[Placeholder]'. Make sure the reply is fully contained before these words and is not cut off prematurely. Thank you.
ASSISTANT
During the golden age of Hollywood, the film industry saw the creation of some of its most enduring classics, but it was also a time rife with personal struggles and dangerous lifestyles. Among its most significant figures was David O. Selznick, an iconic producer best known for his work on "Gone With the Wind." Despite his professional acclaim, Selznick's personal life was marked by a destructive drug addiction that influenced his behavior on and off set. His dependency on Benzedrine, a powerful stimulant, was primarily due to the grueling demands of his work, which often required long and taxing hours. Selznick's use of Benzedrine was emblematic of a wider problem within Hollywood's early years, where high-pressure environments and the constant need to produce blockbusters led many to seek chemical relief. In Selznick's case, this crutch resulted in a notorious reputation for drug-induced bullying, directing anger and frustration toward cast and crew. Although many could admire his films, those who worked alongside him experienced firsthand the volatile impact of his addiction. His leadership style was described as aggressive, making the set of "Gone With the Wind" difficult to endure for many involved. Yet, despite these challenges, Selznick's legacy in film remains intact. His ability to deliver iconic cinema stands as a testament to his skill and vision, overshadowing the darker sides of his life. Behind the scenes, his personal struggles were often hidden beneath the glamour of Hollywood's facade, yet they played a significant role in shaping his story. Reply finished

turns-00042.parquet:25034

8ea24f44a8e34a015602b3c0
turn 1/1gpt-4o-2024-08-06EnglishJapan105 words
degenerate_repetitionAbsentFinal dense release
USER
You are a translator. Your task is to translate the provided text while strictly adhering to the punctuation marks in the source text. If there is no period at the end of the source text, do not add one in the translation. Please ensure that you use placeholders like “%s” and “%1$s” in their appropriate places in the translations. The translations should not be overly formal; instead, aim for a more conversational tone. Additionally, please respect the official WordPress Persian glossary in your translations. Here is the text to translate: Displays a link to reply to a comment.
ASSISTANT
نمایش پیوندی برای پاسخ دادن به دیدگاه