Поправил генерацию QR
This commit is contained in:
parent
f43caa7489
commit
2eee761909
71
bot.py
71
bot.py
|
|
@ -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,27 +82,34 @@ 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:
|
||||
await message.answer_photo(
|
||||
photo=qr_code,
|
||||
caption=f"🎲 *МракоЗвон*\n📞 Номер: `{phone}`\n🃏 Бонусная карта привязана\n🔄 Использован: {record['usage_count']} раз",
|
||||
parse_mode="Markdown"
|
||||
)
|
||||
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=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':
|
||||
await message.answer(
|
||||
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-код или оба вместе.")
|
||||
|
||||
|
|
|
|||
27
qr_utils.py
27
qr_utils.py
|
|
@ -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}"
|
||||
Loading…
Reference in New Issue