Загрузка данных


import os
from PIL import Image, ImageDraw, ImageFont
import telebot
from telebot import types

PROJECT_DIR = os.path.dirname(os.path.abspath(__file__))

CONFIG = {
    "Impact": {
        "image_path": "IMG_9517.png",
        "font": "arialbd.ttf",
        "text_settings": {
            "name": {"pos": (342, 788), "size": 23, "color": (0, 0, 0, 215)},
            "doc": {"pos": (547, 1084), "size": 23, "color": (0, 0, 0, 215)},
            "card": {"pos": (707, 1234), "size": 23, "color": (0, 0, 0, 215)}
        }
    },
    "Urban": {
        "image_path": "IMG_9541.png",
        "font": "arialbd.ttf",
        "text_settings": {
            "name": {"pos": (292, 785), "size": 24, "color": (0, 0, 0, 215)},
            "doc": {"pos": (510, 1118), "size": 25, "color": (0, 0, 0, 215)},
            "card": {"pos": (530, 1283), "size": 25, "color": (0, 0, 0, 215)}
        }
    },
    "Progress": {
        "image_path": "IMG_9536.png",
        "font": "arialbd.ttf",
        "text_settings": {
            "name": {"pos": (268, 819), "size": 25, "color": (0, 0, 0, 215)},
            "doc": {"pos": (485, 1142), "size": 26, "color": (0, 0, 0, 215)},
            "card": {"pos": (660, 1305), "size": 26, "color": (0, 0, 0, 215)}
        }
    },
    "Barakat": {
        "image_path": "IMG_9539.png",
        "font": "arialbd.ttf",
        "text_settings": {
            "name": {"pos": (301, 768), "size": 30, "color": (0, 0, 0, 215)},
            "doc": {"pos": (595, 1210), "size": 30, "color": (0, 0, 0, 215)},
            "card": {"pos": (895, 1295), "size": 30, "color": (0, 0, 0, 215)}
        }
    },
    "Senim": {
        "image_path": "document.png",
        "font": os.path.join(PROJECT_DIR, "times.ttf"),
        "input_fields": ["doc", "amount", "card", "name"],
        "input_prompt": "номер документа, сумма, номер карты, имя",
        "text_settings": {
            "name": {"pos": (490, 515), "size": 24, "angle": 0.80, "max_width": 440, "color": (22, 30, 47, 255)},
            "doc": {"pos": (206, 551), "size": 24, "angle": 0.88, "max_width": 116, "color": (24, 31, 45, 255)},
            "amount": {"pos": (378, 793), "size": 24, "angle": 0.60, "max_width": 115, "color": (21, 29, 57, 255)},
            "card": {"pos": (524, 854), "size": 24, "angle": 0.70, "max_width": 245, "color": (26, 36, 57, 255)}
        }
    },
    "Muras": {
        "image_path": "Мурас.png",
        "font": "arialbd.ttf",
        "text_settings": {
            "name": {"pos": (135, 520), "size": 23, "color": (0, 0, 0, 220)},
            "doc": {"pos": (345, 868), "size": 26, "color": (0, 0, 0, 220)},
            "card": {"pos": (560, 1007), "size": 26, "color": (0, 0, 0, 220)}
        }
    },
    "Ganj Moliya": {
        "image_path": "IMG_0980.PNG",
        "font": "arialbd.ttf",
        "text_settings": {
            "name": {"pos": (135, 520), "size": 23, "color": (0, 0, 0, 220)},
            "doc": {"pos": (370, 868), "size": 26, "color": (0, 0, 0, 220)},
            "card": {"pos": (610, 938), "size": 26, "color": (0, 0, 0, 220)}
        }
    },
    "Freedom": {
        "image_path": "IMG_0022.JPG",
        "font": "arialbd.ttf",
        "text_settings": {
            "name": {"pos": (600, 1510), "size": 56, "color": (0, 0, 0, 190)},
            "doc": {"pos": (1165, 2381), "size": 56, "color": (0, 0, 0, 190)},
            "card": {"pos": (1777, 2557), "size": 56, "color": (0, 0, 0, 190)}
        }
    }
}

bot = telebot.TeleBot('8294680849:AAFs-f6v56Kj8uDwCkNtGlQQpkV_XmDQtM4')

def compress_image(image_path, max_size_mb=9):
    """
    Сжимает изображение до указанного размера в МБ
    """
    max_size_bytes = max_size_mb * 1024 * 1024
    
    # Проверяем текущий размер файла
    if os.path.getsize(image_path) <= max_size_bytes:
        return image_path
    
    # Открываем изображение
    img = Image.open(image_path)
    
    # Конвертируем в RGB если необходимо
    if img.mode in ('RGBA', 'LA', 'P'):
        img = img.convert('RGB')
    
    # Начинаем с качества 85%
    quality = 85
    temp_path = f"temp_{os.path.basename(image_path)}"
    
    while quality > 10:
        img.save(temp_path, format='JPEG', quality=quality, optimize=True)
        
        if os.path.getsize(temp_path) <= max_size_bytes:
            return temp_path
        
        quality -= 5
    
    # Если даже с минимальным качеством размер большой, уменьшаем разрешение
    scale_factor = 0.9
    while os.path.getsize(temp_path) > max_size_bytes and scale_factor > 0.3:
        new_width = int(img.width * scale_factor)
        new_height = int(img.height * scale_factor)
        
        resized_img = img.resize((new_width, new_height), Image.Resampling.LANCZOS)
        resized_img.save(temp_path, format='JPEG', quality=70, optimize=True)
        
        scale_factor -= 0.1
    
    return temp_path

@bot.message_handler(commands=['start'])
def start(message):
    markup = types.ReplyKeyboardRemove()
    text = (
        "Выберите одну из кнопок\n"
        "После выбора бот подскажет формат данных.\n"
    )
    bot.send_message(message.chat.id, text, reply_markup=markup)

    markup = types.ReplyKeyboardMarkup(resize_keyboard=True)
    markup.add("Impact", "Urban", "Progress", "Barakat", "Senim", "Freedom", "Ganj Moliya", "Muras")
    bot.send_message(message.chat.id, "Выберите проблему:", reply_markup=markup)

@bot.message_handler(func=lambda message: message.text in ["Impact", "Urban", "Progress", "Barakat", "Senim", "Freedom", "Ganj Moliya", "Muras"])
def request_data(message):
    config = CONFIG[message.text]
    input_prompt = config.get("input_prompt", "номер документа, сумма, номер карты")
    bot.send_message(message.chat.id, f"Хорошо, отправьте через запятую: {input_prompt}")

    # Передаем выбор экрана (название проблемы) в функцию handle_data_input
    bot.register_next_step_handler(message, handle_data_input, message.text)


def handle_data_input(message, screen_choice):
    data = [x.strip() for x in message.text.split(',')]
    user_data = {}

    try:
        # Проверяем, что screen_choice есть в конфиге
        if screen_choice in CONFIG.keys():
            input_fields = CONFIG[screen_choice].get("input_fields", ["name", "doc", "card"])
            if len(data) != len(input_fields):
                input_prompt = CONFIG[screen_choice].get(
                    "input_prompt", "номер документа, сумма, номер карты"
                )
                raise ValueError(f"нужно ввести: {input_prompt}")
            user_data = dict(zip(input_fields, data))
            screen_key = screen_choice  # Используем screen_choice как ключ для выбора экрана

        else:
            raise ValueError("Неверный выбор экрана.")

        # Генерация и отправка изображения с правильными параметрами
        generate_and_send_image(message, screen_key, user_data)

    except Exception as e:
        bot.send_message(message.chat.id, f"Ошибка: {str(e)}. Попробуйте снова.")


def fit_font(draw, text, font_path, size, max_width=None):
    font = ImageFont.truetype(font_path, size)
    while max_width and size > 14:
        bbox = draw.textbbox((0, 0), text, font=font)
        if bbox[2] - bbox[0] <= max_width:
            break
        size -= 1
        font = ImageFont.truetype(font_path, size)
    return font


def render_image(screen_key, user_data):
    config = CONFIG[screen_key]
    base = Image.open(config['image_path']).convert("RGBA")

    txt_layer = Image.new("RGBA", base.size, (255, 255, 255, 0))
    measure_draw = ImageDraw.Draw(txt_layer)
    font_path = config['font']

    for key, value in user_data.items():
        if key in config['text_settings']:
            setting = config['text_settings'][key]
            font = fit_font(
                measure_draw,
                value,
                font_path,
                setting['size'],
                setting.get('max_width'),
            )
            field_layer = Image.new("RGBA", base.size, (255, 255, 255, 0))
            field_draw = ImageDraw.Draw(field_layer)
            field_draw.text(setting['pos'], value, font=font, fill=setting['color'])

            angle = setting.get('angle', 0)
            if angle:
                field_layer = field_layer.rotate(
                    angle,
                    resample=Image.Resampling.BICUBIC,
                    center=setting['pos'],
                )

            txt_layer = Image.alpha_composite(txt_layer, field_layer)

    return Image.alpha_composite(base, txt_layer)


def generate_and_send_image(message, screen_key, user_data):
    try:
        image_path = CONFIG[screen_key]['image_path']
        if not os.path.exists(image_path):
            bot.send_message(message.chat.id, f"Файл {image_path} не найден.")
            return

        combined = render_image(screen_key, user_data)

        # Сохраняем временный файл
        temp_output_path = f"temp_output_{message.chat.id}.png"
        combined.save(temp_output_path)

        # Сжимаем изображение если необходимо
        compressed_path = compress_image(temp_output_path)

        # Отправляем изображение
        with open(compressed_path, 'rb') as photo:
            bot.send_photo(message.chat.id, photo)

        # Удаляем временные файлы
        if os.path.exists(temp_output_path):
            os.remove(temp_output_path)
        if compressed_path != temp_output_path and os.path.exists(compressed_path):
            os.remove(compressed_path)

    except Exception as e:
        bot.send_message(message.chat.id, f"Ошибка: {str(e)}")


if __name__ == '__main__':
    print("Бот запущен @garantia_screens_bot...")
    bot.infinity_polling()