Поправил генерацию QR

This commit is contained in:
MpakobecEx 2026-05-27 23:52:06 +05:00
parent f43caa7489
commit 2eee761909
2 changed files with 57 additions and 41 deletions

65
bot.py
View File

@ -1,15 +1,17 @@
import base64
import os
import asyncio
import sqlite3
from functools import wraps
from dotenv import load_dotenv
from aiogram import Bot, Dispatcher, types
from aiogram.types import Message, InlineKeyboardMarkup, InlineKeyboardButton, WebAppInfo, MenuButtonWebApp
from aiogram.types import Message, InlineKeyboardMarkup, InlineKeyboardButton, WebAppInfo, MenuButtonWebApp, \
BufferedInputFile
from aiogram.filters import Command
from aiohttp import web
import database as db
from phone_utils import normalize_phone
from qr_utils import decode_qr_from_image, generate_qr_code
from qr_utils import decode_qr_from_image, generate_qr_code, generate_qr_base64, generate_qr_image
# Загружаем переменные из .env
load_dotenv()
@ -80,13 +82,27 @@ async def cmd_get(message: Message):
record_type = record['type']
phone = record.get('phone')
qr_code = record.get('qr_code')
qr_code_base64 = record.get('qr_code')
qr_data = record.get('qr_data')
if record_type == 'both' and qr_code:
if (record_type == 'both' or record_type == 'qr') and qr_code_base64:
# Конвертируем base64 в байты для отправки
if qr_code_base64.startswith('data:image/png;base64,'):
img_base64 = qr_code_base64.replace('data:image/png;base64,', '')
img_bytes = base64.b64decode(img_base64)
photo_file = BufferedInputFile(img_bytes, filename="qr.png")
if record_type == 'both':
await message.answer_photo(
photo=qr_code,
caption=f"🎲 *МракоЗвон*\n📞 Номер: `{phone}`\n🃏 Бонусная карта привязана\n🔄 Использован: {record['usage_count']} раз",
photo=photo_file,
caption=f"🎲 *МракоЗвон*\n📞 Номер: `{phone}`\n🃏 Бонусная карта\n🔄 Использован: {record['usage_count']} раз",
parse_mode="Markdown"
)
else:
short_data = qr_data[:50] + '...' if qr_data and len(qr_data) > 50 else (qr_data or '')
await message.answer_photo(
photo=photo_file,
caption=f"🎲 *МракоЗвон*\n🃏 Бонусная карта\n📝 Данные: `{short_data}`\n🔄 Использована: {record['usage_count']} раз",
parse_mode="Markdown"
)
elif record_type == 'phone':
@ -94,13 +110,6 @@ async def cmd_get(message: Message):
f"🎲 *МракоЗвон*\n📞 Номер: `{phone}`\n🔄 Использован: {record['usage_count']} раз",
parse_mode="Markdown"
)
elif record_type == 'qr' and qr_code:
short_data = qr_data[:50] + '...' if qr_data and len(qr_data) > 50 else (qr_data or '')
await message.answer_photo(
photo=qr_code,
caption=f"🎲 *МракоЗвон*\n🃏 Бонусная карта\n📝 Данные: `{short_data}`\n🔄 Использована: {record['usage_count']} раз",
parse_mode="Markdown"
)
@dp.message(Command("stats"))
@ -234,7 +243,8 @@ async def cmd_update_menu(message: Message):
async def handle_message(message: Message):
phone = None
qr_raw_data = None
qr_image = None
qr_image_bytes = None
qr_image_base64 = None
# 1. Распознаём QR из фото
if message.photo:
@ -242,8 +252,11 @@ async def handle_message(message: Message):
file = await bot.get_file(photo.file_id)
file_bytes = await bot.download_file(file.file_path)
qr_raw_data = decode_qr_from_image(file_bytes.read())
if qr_raw_data:
qr_image = generate_qr_code(qr_raw_data)
# Генерируем новый чистый QR из распознанных данных
qr_image_bytes = generate_qr_image(qr_raw_data)
qr_image_base64 = generate_qr_base64(qr_raw_data)
# 2. Извлекаем номер из текста
if message.text:
@ -251,15 +264,27 @@ async def handle_message(message: Message):
# 3. Определяем тип записи и сохраняем
if phone and qr_raw_data:
db.add_record('both', phone=phone, qr_code=qr_image, qr_data=qr_raw_data)
await message.answer(f"✅ Сохранено: номер `{phone}` + бонусная карта", parse_mode="Markdown")
# Сохраняем base64 для веб-морды и байты для Telegram
db.add_record('both', phone=phone, qr_code=qr_image_base64, qr_data=qr_raw_data)
# Отправляем сгенерированный QR в ответ
photo_file = BufferedInputFile(qr_image_bytes, filename="qr.png")
await message.answer_photo(
photo=photo_file,
caption=f"✅ Сохранено: номер `{phone}` + бонусная карта",
parse_mode="Markdown"
)
elif phone:
db.add_record('phone', phone=phone)
await message.answer(f"✅ Сохранён номер: `{phone}`", parse_mode="Markdown")
elif qr_raw_data:
db.add_record('qr', qr_code=qr_image, qr_data=qr_raw_data)
short_data = qr_raw_data[:50] + '...' if len(qr_raw_data) > 50 else qr_raw_data
await message.answer(f"🃏 Сохранена бонусная карта: `{short_data}`", parse_mode="Markdown")
db.add_record('qr', qr_code=qr_image_base64, qr_data=qr_raw_data)
photo_file = BufferedInputFile(qr_image_bytes, filename="qr.png")
await message.answer_photo(
photo=photo_file,
caption=f"🃏 Сохранена бонусная карта\n📝 Данные: `{qr_raw_data[:50]}...`",
parse_mode="Markdown"
)
else:
await message.answer("⚠️ Не распознано. Отправь номер, QR-код или оба вместе.")

View File

@ -7,33 +7,21 @@ import qrcode
def decode_qr_from_image(image_data: bytes) -> str | None:
"""
Распознаёт QR-код из изображения
Возвращает декодированную строку или None
"""
"""Распознаёт QR-код из изображения"""
try:
# Конвертируем байты в numpy массив
nparr = np.frombuffer(image_data, np.uint8)
img = cv2.imdecode(nparr, cv2.IMREAD_COLOR)
# Инициализируем детектор QR-кодов
detector = cv2.QRCodeDetector()
# Декодируем
data, bbox, _ = detector.detectAndDecode(img)
if data:
return data.strip()
except Exception as e:
print(f"QR decode error: {e}")
return None
def generate_qr_code(data: str, size: int = 300) -> str:
"""
Генерирует QR-код из строки и возвращает base64 строку
"""
def generate_qr_image(data: str) -> bytes:
"""Генерирует QR-код и возвращает байты изображения"""
qr = qrcode.QRCode(
version=1,
error_correction=qrcode.constants.ERROR_CORRECT_L,
@ -44,10 +32,13 @@ def generate_qr_code(data: str, size: int = 300) -> str:
qr.make(fit=True)
img = qr.make_image(fill_color="black", back_color="white")
# Конвертируем в base64
buffered = BytesIO()
img.save(buffered, format="PNG")
img_base64 = base64.b64encode(buffered.getvalue()).decode()
return buffered.getvalue()
def generate_qr_base64(data: str) -> str:
"""Генерирует QR и возвращает base64 строку для веб-морды"""
img_bytes = generate_qr_image(data)
img_base64 = base64.b64encode(img_bytes).decode()
return f"data:image/png;base64,{img_base64}"