savagedb_bot/wiki/read_dev.md

20 KiB
Raw Permalink Blame History

SalvageDB Telegram Bot - Developer Documentation

Оглавление

  1. Архитектура бота
  2. Переменные окружения
  3. Состояния FSM
  4. Основные функции
  5. Callback Handlers
  6. Message Handlers
  7. Функции базы данных
  8. Система платежей
  9. Работа с фотографиями
  10. Системные функции
  11. Middleware
  12. Структура проекта
  13. API Endpoints

Архитектура бота

Бот построен на фреймворке aiogram 3.x с использованием Oracle Database для хранения данных о транспортных средствах и их истории повреждений.

Основные компоненты:

  • main.py - основной файл с логикой бота
  • db.py - класс для работы с Oracle Database
  • middlewares/db.py - middleware для передачи подключения к БД

Схема работы:

User Input → FSM States → Database Query → Response Formatting → Telegram API

Переменные окружения

Обязательные переменные:

BOT_TOKEN=ваш_токен_бота
BOT_NAME=имя_бота
db_user=пользователь_oracle
db_password=пароль_oracle
db_dsn=строка_подключения_oracle
ADMIN_USER_ID=id_администратора

Опциональные переменные:

DEBUG=1                    # Включает детальное логирование
DECODE_PRICE=1            # Цена за детальную информацию VIN (звезды)
CHECK_PRICE=10            # Цена за проверку salvage записей (звезды)
IMG_PRICE=100             # Цена за фотографии (звезды)

Автоматические пути к изображениям:

if is_windows():
    image_path = "D:\\SALVAGEDB\\salvagedb_bot\\images"
else:
    image_path = "/images/"

Состояния FSM

Бот использует Finite State Machine для управления диалогами:

class VinStates(StatesGroup):
    waiting_for_vin = State()         # Ожидание VIN для декодирования
    waiting_for_check_vin = State()   # Ожидание VIN для проверки salvage
    waiting_for_photo_vin = State()   # Ожидание VIN для поиска фотографий

Переходы между состояниями:

  • Startwaiting_for_vin (кнопка "Decode VIN")
  • Startwaiting_for_check_vin (кнопка "Check VIN")
  • Startwaiting_for_photo_vin (кнопка "Search car Photo")
  • Any StateStart (кнопка "Back to Main Menu")

Основные функции

Системные функции

get_operating_system() -> str

Определяет операционную систему.

Returns: 'Windows', 'Linux', 'macOS' или 'Unknown'

is_windows() -> bool, is_linux() -> bool, is_macos() -> bool

Быстрые проверки операционной системы.

log_system_info()

Логирует подробную информацию о системе при запуске.

Функции обработки данных

get_us_state_name(state_code: str) -> str

Конвертирует двухбуквенный код штата США в полное название.

get_us_state_name("TX")  # Returns: "Texas"

format_sale_date(date_str: str) -> str

Форматирует дату из MM/YYYY в читаемый формат.

format_sale_date("3/2023")  # Returns: "March 2023"

parse_location(location_str: str) -> str

Парсит локацию из формата ST/TOWN в "City, State".

parse_location("TX/DALLAS")  # Returns: "Dallas, Texas"

escape_markdown(text: str) -> str

Экранирует специальные символы Markdown для безопасной отправки.

Функции работы с фотографиями

convert_photo_path(db_path: str) -> str

Конвертирует путь из БД в полный путь с учетом OS.

# Windows
convert_photo_path("20250530/vin/photo.jpg")
# Returns: "D:\SALVAGEDB\salvagedb_bot\images\20250530\vin\photo.jpg"

# Linux
convert_photo_path("20250530/vin/photo.jpg")
# Returns: "/images/20250530/vin/photo.jpg"

prepare_photo_paths(db_paths: list) -> list

Подготавливает список полных путей к фотографиям.

send_vehicle_photos(message, vin, photo_paths, make, model, year)

Отправляет фотографии пользователю группами по 10 штук.

Особенности:

  • Разбивает фотографии на группы по 10 (лимит Telegram)
  • Добавляет описания к первым фото каждой группы
  • Пауза 0.5 сек между группами
  • Обработка ошибок для каждой фотографии
  • Итоговое сообщение с количеством отправленных фото

Callback Handlers

@dp.callback_query(lambda c: c.data == "decode_vin")

Функция: decode_vin_callback Действие: Устанавливает состояние waiting_for_vin, запрашивает VIN для декодирования.

@dp.callback_query(lambda c: c.data == "check_vin")

Функция: check_vin_callback Действие: Устанавливает состояние waiting_for_check_vin, запрашивает VIN для проверки salvage.

@dp.callback_query(lambda c: c.data == "search_car_photo")

Функция: search_car_photo_callback Действие: Устанавливает состояние waiting_for_photo_vin, запрашивает VIN для поиска фотографий.

@dp.callback_query(lambda c: c.data == "main_menu")

Функция: main_menu_callback Действие: Очищает состояние, возвращает в главное меню.

Платежные handlers

@dp.callback_query(lambda c: c.data.startswith("pay_detailed_info:"))

Функция: pay_detailed_info_callback Payload: detailed_vin_info:{vin} Цена: DECODE_PRICE звезд

@dp.callback_query(lambda c: c.data.startswith("pay_check_detailed:"))

Функция: pay_check_detailed_callback Payload: detailed_salvage_check:{vin} Цена: CHECK_PRICE звезд

@dp.callback_query(lambda c: c.data.startswith("pay_photos:"))

Функция: pay_photos_callback Payload: vehicle_photos:{vin} Цена: IMG_PRICE звезд


Message Handlers

@dp.message(Command("start"))

Функция: command_start_handler Действие: Показывает приветственное сообщение и главное меню.

Кнопки:

  • Decode VIN
  • Check VIN
  • Search car Photo
  • Help
  • Prices
  • Go Salvagedb.com

@dp.message(Command("admin_stats"))

Функция: admin_stats_handler Доступ: Только для ADMIN_USER_ID Действие: Показывает статистику пользователей бота.

Обработчики состояний

@dp.message(VinStates.waiting_for_vin)

Функция: process_vin Логика:

  1. Валидация VIN (17 символов, без I/O/Q)
  2. Запрос fetch_vin_info(vin)
  3. Проверка успешности декодирования (не все UNKNOWN)
  4. Показ кнопки детальной информации при cnt > 9

@dp.message(VinStates.waiting_for_check_vin)

Функция: process_check_vin Логика:

  1. Валидация VIN
  2. Запрос fetch_vin_info(vin) и count_salvage_records(vin)
  3. Показ информации о количестве найденных записей
  4. Кнопка оплаты при наличии записей

@dp.message(VinStates.waiting_for_photo_vin)

Функция: process_photo_vin Логика:

  1. Валидация VIN
  2. Запрос fetch_vin_info(vin) и count_photo_records(vin)
  3. Показ информации о количестве фотографий
  4. Кнопка оплаты при наличии фотографий

@dp.message(lambda message: message.successful_payment)

Функция: successful_payment_handler Логика обработки платежей по payload:

detailed_vin_info:{vin}

  1. Запрос fetch_detailed_vin_info(vin)
  2. Форматирование детального отчета по категориям
  3. Возврат денег при отсутствии данных
  4. Автоматический возврат админу

detailed_salvage_check:{vin}

  1. Запрос fetch_salvage_detailed_info(vin)
  2. Форматирование salvage отчета с повреждениями
  3. Отдельное сообщение о фотографиях
  4. Возврат денег при отсутствии данных
  5. Автоматический возврат админу

vehicle_photos:{vin}

  1. Запрос fetch_photo_paths(vin)
  2. Конвертация путей под текущую OS
  3. Отправка фотографий группами по 10
  4. Возврат денег при отсутствии фотографий
  5. Автоматический возврат админу

Функции базы данных

Класс OracleDatabase

__init__(user, password, dsn)

Инициализация подключения к Oracle DB.

async def connect()

Создает пул подключений (min=1, max=4).

async def fetch_vin_info(vin: str) -> Tuple[str, str, str, int]

Возвращает: (make, model, year, nhtsa_records_count) SQL запрос:

select 'None',  
       COALESCE((select value from salvagedb.m_JSONS_FROM_NHTSA v3 
                where v3.svin = s.svin and v3.variableid = '26'),
               (select val from salvagedb.vind2 
                where svin = substr(s.vin, 1, 8) || '*' || substr(s.vin, 10, 2) 
                and varb = 'Make'),'UNKNOWN') make,
       -- аналогично для model и year
       (select count(*) from salvagedb.m_JSONS_FROM_NHTSA v3 
        where v3.svin = s.svin) cnt
from (select substr(:vin,1,10) svin, :vin vin from dual) s

async def count_salvage_records(vin: str) -> int

SQL: SELECT COUNT(*) FROM salvagedb.salvagedb WHERE vin = :vin and svin = substr(:vin,1,10)

async def count_photo_records(vin: str) -> int

SQL: SELECT COUNT(*) FROM salvagedb.salvage_images WHERE vin = :vin AND fn = 1

async def fetch_photo_paths(vin: str) -> list

SQL: SELECT ipath FROM salvagedb.salvage_images WHERE fn = 1 AND vin = :vin Возвращает: Список путей к фотографиям.

async def fetch_salvage_detailed_info(vin: str) -> list

Возвращает: Детальную информацию о salvage записях. SQL запрос:

SELECT 
    odo, odos, dem1, dem2,
    month||'/'||year as sale_date,
    JSON_VALUE(jdata, '$.RepCost') AS j_rep_cost,
    JSON_VALUE(jdata, '$.Runs_Drive') AS j_runs_drive,
    JSON_VALUE(jdata, '$.Locate') AS j_locate,
    (select count(*) from salvagedb.salvage_images si 
     where si.vin = s.vin and fn = 1) img_count
FROM salvagedb.salvagedb s
LEFT JOIN salvagedb.addinfo i ON s.num = i.numid
WHERE vin = :vin AND svin = substr(:vin, 1, 10)
ORDER BY year DESC, month DESC

async def fetch_detailed_vin_info(vin: str) -> dict

Возвращает: Детальную информацию о VIN по категориям. Категории:

  • basic_characteristics
  • engine_and_powertrain
  • transmission
  • active_safety
  • passive_safety
  • dimensions_and_construction
  • brake_system
  • lighting
  • additional_features
  • manufacturing_and_localization
  • ncsa_data
  • technical_information_and_errors

Пользовательские функции

async def save_user(user: User, interaction_source: str) -> bool

Сохраняет/обновляет данные пользователя при каждом взаимодействии.

async def update_user_payment(user_id: int, payment_amount: float) -> bool

Обновляет статистику платежей пользователя.

async def get_user_stats(user_id: int) -> dict

Возвращает статистику конкретного пользователя.

async def get_users_summary() -> dict

Возвращает общую статистику по всем пользователям.


Система платежей

Telegram Stars

Бот использует Telegram Stars для приема платежей.

Типы платежей:

  1. Детальная информация VIN - DECODE_PRICE звезд
  2. Salvage проверка - CHECK_PRICE звезд
  3. Фотографии автомобиля - IMG_PRICE звезд

Процесс оплаты:

  1. Пользователь нажимает кнопку оплаты
  2. Создается invoice с уникальным payload
  3. Pre-checkout подтверждение
  4. Successful payment обработка
  5. Предоставление услуги или возврат средств

Автоматический возврат админу:

Если message.from_user.id == ADMIN_USER_ID, после предоставления услуги автоматически возвращаются потраченные звезды.

Обработка ошибок:

  • Отсутствие данных → автоматический возврат
  • Ошибка сервера → автоматический возврат
  • Ошибка возврата → уведомление с transaction ID

Работа с фотографиями

Структура хранения:

База данных: 20250530/1c4hjxdg0pw697757/photo.jpg
Windows: D:\SALVAGEDB\salvagedb_bot\images\20250530\1c4hjxdg0pw697757\photo.jpg
Linux: /images/20250530/1c4hjxdg0pw697757/photo.jpg

Процесс отправки:

  1. Получение путей из БД
  2. Конвертация под текущую OS
  3. Разбивка на группы по 10 фотографий
  4. Отправка media groups с описаниями
  5. Итоговое сообщение

Ограничения:

  • Максимум 10 фотографий в одной группе (Telegram API)
  • Пауза 0.5 сек между группами
  • Проверка существования файлов

Системные функции

Логирование:

# Основное логирование
logging.basicConfig(level=logging.WARNING)

# Debug режим
if getenv("DEBUG",'0') == '1':
    logging.basicConfig(level=logging.INFO)

Middleware:

# Передача подключения к БД во все handlers
dp.message.middleware(DbSessionMiddleware(oracle_db))
dp.callback_query.middleware(DbSessionMiddleware(oracle_db))
dp.pre_checkout_query.middleware(DbSessionMiddleware(oracle_db))

Startup/Shutdown:

async def on_startup():
    log_system_info()  # Системная информация
    await oracle_db.connect()  # Подключение к БД
    # Регистрация middleware

async def on_shutdown():
    await oracle_db.close()  # Закрытие пула подключений

Middleware

DbSessionMiddleware

Файл: middlewares/db.py Назначение: Передает экземпляр подключения к БД во все handlers.

Использование:

async def handler(message: Message, db: OracleDatabase = None):
    database = db or oracle_db  # Fallback на глобальный

Структура проекта

salvagedb_bot/
├── main.py                 # Основной файл бота
├── db.py                   # Класс работы с БД
├── read_dev.md            # Документация (этот файл)
├── middlewares/
│   └── db.py              # Middleware для БД
└── images/                # Директория с фотографиями (Windows)
    └── 20250530/
        └── vin_lower/
            └── photo.jpg

API Endpoints

Telegram Bot API

Бот использует стандартные методы Telegram Bot API:

Отправка сообщений:

  • message.answer() - текстовые сообщения
  • message.answer_media_group() - группы фотографий

Платежи:

  • bot.send_invoice() - создание счета
  • bot.refund_star_payment() - возврат звезд

Webhook vs Polling:

Текущая конфигурация использует polling:

await dp.start_polling(bot)

Примеры использования

Запуск бота:

# Установка переменных окружения
export BOT_TOKEN="your_token"
export db_user="oracle_user"
# ... другие переменные

# Запуск
python main.py

Тестирование платежей:

  1. Установить ADMIN_USER_ID на свой Telegram ID
  2. Выполнить любую оплату
  3. Получить услугу + автоматический возврат звезд

Debug режим:

export DEBUG=1
python main.py

Включает детальное логирование всех операций.


Troubleshooting

Проблемы с фотографиями:

  1. Проверить права доступа к директории images
  2. Убедиться в правильности путей для текущей OS
  3. Проверить логи на ошибки файловой системы

Проблемы с БД:

  1. Проверить строку подключения DSN
  2. Убедиться в доступности Oracle DB
  3. Проверить права пользователя БД

Проблемы с платежами:

  1. Убедиться в корректности BOT_TOKEN
  2. Проверить что бот добавлен в Telegram Stars
  3. Проверить логи на ошибки Telegram API

Обновления и изменения

При внесении изменений в код обязательно обновляйте эту документацию.

История изменений:

  • v1.0 - Базовая функциональность (decode VIN, check VIN)
  • v1.1 - Добавлена поддержка фотографий
  • v1.2 - Улучшена отправка множественных фотографий
  • v1.3 - Добавлены функции определения OS и автоматические пути

Документация актуальна на момент последнего обновления кода.