Исправь баг что цифры не распознаются, сделай обучение нейросети
```python
import pytesseract
from PIL import ImageGrab
from pynput import keyboard
from pynput.keyboard import Key, Controller
import threading
import cv2
import numpy as np
import json
import time
import sys

# Инициализация контроллера клавиатуры один раз для повышения эффективности
keyboard_controller = Controller()

CONFIG_PATH = 'config.json'

def load_config(config_path=CONFIG_PATH):
    """Загружает настройки из конфигурационного файла."""
    try:
        with open(config_path, 'r') as f:
            return json.load(f)
    except FileNotFoundError:
        return {}
    except json.JSONDecodeError:
        print("Ошибка: Невозможно декодировать JSON из config.json.")
        return {}

def save_config(config, config_path=CONFIG_PATH):
    """Сохраняет настройки в конфигурационный файл."""
    try:
        with open(config_path, 'w') as f:
            json.dump(config, f)
    except Exception as e:
        print(f"Ошибка при сохранении конфигурации: {e}")

def capture_and_process(box_left, box_top, box_width, box_height):
    """
    Захватывает указанную область экрана, обрабатывает изображение с помощью OCR,
    эмулирует ввод распознанных цифр и нажимает Enter.
    """
    try:
        if box_width <= 0 or box_height <= 0:
            print("Неверные размеры бокса для захвата. Проверьте настройки.")
            return

        # Захват скриншота
        screenshot = ImageGrab.grab()

        box = (box_left, box_top, box_left + box_width, box_top + box_height)
        cropped_image = screenshot.crop(box)

        # Визуализация области захвата
        visualize_capture(screenshot, box)

        # Оптимизация параметров OCR
        custom_config = r'--oem 3 --psm 6 -c tessedit_char_whitelist=0123456789'
        text = pytesseract.image_to_string(cropped_image, lang='eng', config=custom_config)
        digits = ''.join(filter(str.isdigit, text))
        print(f"Распознанные цифры: {digits}")

        if digits:
            # Эмуляция ввода цифр
            for num in digits:
                keyboard_controller.press(num)
                keyboard_controller.release(num)
                time.sleep(0.05)  # Уменьшение задержки для большей скорости

            # Эмуляция нажатия Enter
            keyboard_controller.press(Key.enter)
            keyboard_controller.release(Key.enter)

    except Exception as e:
        print(f"Ошибка при обработке скриншота: {e}")

def visualize_capture(screenshot, box):
    """
    Отображает захваченное изображение с выделенной областью.
    """
    try:
        # Конвертация PIL изображения в формат, совместимый с OpenCV
        screenshot_cv = cv2.cvtColor(np.array(screenshot), cv2.COLOR_RGB2BGR)

        # Рисование прямоугольника вокруг области захвата
        cv2.rectangle(screenshot_cv, (box[0], box[1]), (box[2], box[3]), (0, 255, 0), 2)

        # Название окна
        window_name = "Захват экрана с выделенной областью"

        # Отображение изображения
        cv2.imshow(window_name, screenshot_cv)

        # Ожидание заданного времени или нажатия любой клавиши
        cv2.waitKey(2000)  # 2000 миллисекунд = 2 секунды

        # Закрытие окна
        cv2.destroyWindow(window_name)

    except Exception as e:
        print(f"Ошибка при визуализации: {e}")

def on_press(key, box_left, box_top, box_width, box_height):
    """
    Обработчик нажатий клавиш. При нажатии клавиши 'n' инициирует захват и обработку.
    """
    try:
        if key.char.lower() == 'n':
            print("Клавиша 'n' нажата. Начало захвата и обработки области экрана.")
            # Использование отдельного потока для предотвращения блокировки слушателя
            threading.Thread(target=capture_and_process, args=(box_left, box_top, box_width, box_height), daemon=True).start()
    except AttributeError:
        pass  # Игнорируем специальные клавиши

def select_area(image):
    """
    Позволяет пользователю интерактивно выбрать область на изображении с помощью OpenCV.
    Нажмите 'c' для подтверждения выбора или 'r' для сброса.
    Возвращает координаты выбранного бокса или None, если выбор не был подтвержден.
    """
    ref_point = []
    cropping = False

    def mouse_callback(event, x, y, flags, param):
        nonlocal ref_point, cropping, image

        if event == cv2.EVENT_LBUTTONDOWN:
            ref_point = [(x, y)]
            cropping = True

        elif event == cv2.EVENT_MOUSEMOVE:
            if cropping:
                temp_image = image.copy()
                cv2.rectangle(temp_image, ref_point[0], (x, y), (0, 255, 0), 2)
                cv2.imshow("Выбор области", temp_image)

        elif event == cv2.EVENT_LBUTTONUP:
            ref_point.append((x, y))
            cropping = False
            cv2.rectangle(image, ref_point[0], ref_point[1], (0, 255, 0), 2)
            cv2.imshow("Выбор области", image)

    clone = image.copy()
    cv2.namedWindow("Выбор области")
    cv2.setMouseCallback("Выбор области", mouse_callback)

    while True:
        cv2.imshow("Выбор области", image)
        key = cv2.waitKey(1) & 0xFF

        if key == ord("r"):  # Сбросить выбор области
            image = clone.copy()
            ref_point = []
            cv2.imshow("Выбор области", image)

        elif key == ord("c"):  # Подтвердить выбор области
            break

    cv2.destroyWindow("Выбор области")

    if len(ref_point) == 2:
        return ref_point
    else:
        return None

def get_user_selection():
    """
    Захватывает скриншот, отображает его и позволяет пользователю выбрать область для OCR.
    Возвращает координаты выбранного бокса или None.
    """
    try:
        screenshot = ImageGrab.grab()
        screenshot_cv = cv2.cvtColor(np.array(screenshot), cv2.COLOR_RGB2BGR)
        points = select_area(screenshot_cv)
        return points
    except Exception as e:
        print(f"Ошибка при выборе области: {e}")
        return None

def main():
    """
    Основная функция, которая:
    - Загружает или запрашивает выбор области захвата.
    - Запускает слушатель клавиатуры для обработки нажатий.
    """
    config = load_config()

    # Проверяем, существуют ли настройки положения бокса
    if all(k in config for k in ('box_left', 'box_top', 'box_width', 'box_height')):
        BOX_LEFT = config['box_left']
        BOX_TOP = config['box_top']
        BOX_WIDTH = config['box_width']
        BOX_HEIGHT = config['box_height']
        print(f"Загружены настройки бокса: {config}")
    else:
        print("Не найдены настройки бокса. Пожалуйста, выберите область захвата.")
        box = get_user_selection()
        if box:
            x1, y1 = box[0]
            x2, y2 = box[1]

            # Определяем верхнюю левую и нижнюю правую точки
            BOX_LEFT = min(x1, x2)
            BOX_TOP = min(y1, y2)
            BOX_RIGHT = max(x1, x2)
            BOX_BOTTOM = max(y1, y2)

            BOX_WIDTH = BOX_RIGHT - BOX_LEFT
            BOX_HEIGHT = BOX_BOTTOM - BOX_TOP

            config = {
                "box_width": BOX_WIDTH,
                "box_height": BOX_HEIGHT,
                "box_left": BOX_LEFT,
                "box_top": BOX_TOP
            }
            save_config(config)
            print(f"Сохранены настройки бокса: {config}")
        else:
            print("Область захвата не выбрана. Завершение работы.")
            sys.exit()

    # Запуск слушателя клавиатуры
    with keyboard.Listener(on_press=lambda key: on_press(key, BOX_LEFT, BOX_TOP, BOX_WIDTH, BOX_HEIGHT)) as listener:
        print("Слушатель клавиатуры запущен. Нажмите 'n' для захвата и обработки области.")
        listener.join()

if __name__ == "__main__":
    main()
```