Микросервис для загрузки фотографий из Telegram в S3 через NATS очереди сообщений.
- Telegram интеграция: Скачивание файлов по
file_idчерез Telegram Bot API - Batch обработка: До 100 фотографий параллельно для тренировки
- Одиночные фото: Быстрая обработка для inference
- S3 загрузка: Автоматическая организация файлов по структуре
- NATS messaging: Асинхронная обработка через очереди
- Мониторинг: Детальная статистика и логирование
Telegram Bot → NATS Topics → Photo Downloader → S3 Storage
↓ ↓ ↓ ↓
file_id photo_upload_* Download & Organized
messages Process Structure
- Получение
file_idиз Telegram сообщения - Отправка в NATS topic (
photo_upload_trainилиphoto_upload_inf) - Получение URL файла через Telegram Bot API (
getFile) - Скачивание файла по полученному URL
- Загрузка в S3 с метаданными и правильной структурой
- Отправка результата обратно в NATS
Photo Downloader Service - это микросервис, который:
- Для тренировки (train): Получает batch сообщения и обрабатывает множественные фотографии параллельно
- Для inference (inf): Получает запросы на загрузку одиночных фотографий
- Скачивает фотографии по предоставленным file_id
- Загружает их в S3 с разной структурой для train/inference
- Предоставляет детальную статистику обработки
- Отправляет результаты обратно в NATS
- Train операции: Batch обработка до 100 фотографий параллельно
- Inference операции: Быстрая загрузка одиночных фотографий
- Параллельная обработка: До 5 файлов одновременно для batch (настраивается)
- Валидация изображений: Проверка минимальных размеров (450x450px) только для train операций
- Автогенерация S3 ключей: Если
s3_keyпустой, генерируется уникальный ключ на основеuser_id,file_idи временной метки - Детальная статистика: Индивидуальная информация о каждом файле
- Обработка ошибок: Индивидуальные ошибки для каждого файла
HTTP Client → NATS Gateway → NATS → Photo Downloader → S3
↓
┌─────────────┐
│ photo_upload_train │ → Batch Processing (до 100 фото)
│ photo_upload_inf │ → Single Photo (1 фото)
└─────────────┘
bucket-name/
├── {bot_id}/ # Тренировочные данные (train)
│ └── {user_id}/
│ └── {avatar_id}/
│ ├── photo1.jpg
│ ├── photo2.jpg
│ └── photo3.jpg
└── uploads/ # Inference данные (inf)
└── inf/
└── {bot_id}/
└── {user_id}/
└── {avatar_id}/
└── photo.jpg # Одиночные фото без batch_id
Важно:
- Train (
header: "train"): Batch фотографии →{bot_id}/{user_id}/{avatar_id}/ - Inference (
header: "inf"): Одиночные фото →uploads/inf/{bot_id}/{user_id}/{avatar_id}/
- Python 3.11+
- Poetry
- Docker (опционально)
- NATS Server
- S3-совместимое хранилище
- Клонирование репозитория
git clone <repository-url>
cd photo-downloader-service- Настройка окружения
make setup
# Отредактируйте .env файл с вашими настройками- Установка зависимостей
make install- Запуск
make run- Сборка образа
make build- Запуск контейнера
make docker-run- Запуск с docker-compose (включает NATS и MinIO)
make compose-up| Переменная | Описание | По умолчанию |
|---|---|---|
NATS_URL |
URL NATS сервера | nats://localhost:4222 |
TELEGRAM_BOT_TOKEN |
Токен Telegram бота | - |
TELEGRAM_API_URL |
URL Telegram Bot API | https://api.telegram.org |
S3_ENDPOINT_URL |
URL S3 endpoint | - |
S3_ACCESS_KEY_ID |
S3 Access Key | - |
S3_SECRET_ACCESS_KEY |
S3 Secret Key | - |
S3_BUCKET_NAME |
Имя S3 bucket | - |
S3_REGION |
S3 регион | us-east-1 |
MAX_FILE_SIZE_MB |
Максимальный размер файла (MB) | 10 |
MIN_FILE_SIZE_KB |
Минимальный размер файла (KB) | 80 |
MIN_IMAGE_DIMENSION |
Минимальная сторона изображения (px) | 450 |
DOWNLOAD_TIMEOUT_SECONDS |
Таймаут загрузки (сек) | 30 |
MAX_CONCURRENT_DOWNLOADS |
Макс. параллельных загрузок | 5 |
MAX_BATCH_SIZE |
Макс. размер batch (train) | 100 |
BATCH_PROCESSING_TIMEOUT |
Таймаут обработки batch (сек) | 300 |
LOG_LEVEL |
Уровень логирования | INFO |
Topic: photo_upload_train - Batch обработка для тренировки
Схема: PhotoUploadRequest
{
"header": "train",
"photos": [
{
"file_id": "BAADBAADrwADBREAAWn4gALvKoNaAg",
"properties":{
"s3_key": "",
"file_size": 1024000,
"width": 1920,
"height": 1280,
"face_diagoanl": 360,
"bboxs": "box list",
"num_face": 1,
},
"status": "ok/error",
"reason": "NO_FACE/BAD_QUALITY/FACE_TOO_SMALL"
},
{
"file_id": "BAADBAADsAADBREAAQoJBgAB7ioNaAg",
"properties":{
"s3_key": "",
"file_size": 1024000,
"width": 1920,
"height": 1280,
"face_diagoanl": 360,
"bboxs": "box list",
"num_face": 1,
},
"status": "ok/error",
"error_details": "NO_FACE/BAD_QUALITY/FACE_TOO_SMALL"
}
],
"bot_id": 12345,
"user_id": 67890,
"avatar_id": "avatar_abc123",
"batch_id": "batch_xyz789",
"priority": 5
}Примечание: Поле
s3_keyможет быть пустым ("") - в этом случае ключ будет сгенерирован автоматически на основеuser_id,file_idи временной метки в форматеphotos/{user_id}/{timestamp}/{file_id}.{ext}.
Topic: photo_upload_inf - Одиночное фото для inference
Схема: InferencePhotoRequest
{
"header": "inf",
"photo": {
"file_id": "BAADBAADrwADBREAAWn4gALvKoNaAg",
"s3_key": "",
"file_size": 1024000
},
"bot_id": 12345,
"user_id": 67890,
"avatar_id": "avatar_abc123",
"priority": 5
}Topic: photo_upload_result - Результат batch обработки (train)
Схема: PhotoUploadResult
{
"header": "train",
"bot_id": 12345,
"user_id": 67890,
"avatar_id": "avatar_abc123",
"batch_id": "batch_xyz789",
"total_files": 2,
"successful_files": 2,
"failed_files": 0,
"successful_uploads": [
{
"file_id": "BAADBAADrwADBREAAWn4gALvKoNaAg",
"s3_key": "12345/67890/avatar_abc123/photo1.jpg",
"s3_url": "https://bucket.s3.amazonaws.com/12345/67890/avatar_abc123/photo1.jpg",
"file_size": 1024000,
"upload_time": 2.5,
"content_type": "image/jpeg"
}
],
"failed_uploads": [],
"processing_time": 5.2,
"total_size": 3072000,
"message": "Batch processing completed: 2/2 files successful",
"timestamp": "2024-01-15T10:30:00Z"
}Topic: inference_result - Результат одиночного фото (inference)
Схема: InferencePhotoResult
{
"header": "inf",
"bot_id": 12345,
"user_id": 67890,
"avatar_id": "avatar_abc123",
"upload_result": {
"file_id": "BAADBAADrwADBREAAWn4gALvKoNaAg",
"s3_key": "uploads/inf/12345/67890/avatar_abc123/photo.jpg",
"s3_url": "https://bucket.s3.amazonaws.com/uploads/inf/12345/67890/avatar_abc123/photo.jpg",
"file_size": 1024000,
"upload_time": 2.1,
"content_type": "image/jpeg"
},
"processing_time": 2.1,
"message": "Photo uploaded successfully",
"timestamp": "2024-01-15T10:30:00Z"
}Topic: photo_upload_error - Ошибки
Схема: PhotoUploadError
{
"header": "inf",
"bot_id": 12345,
"user_id": 67890,
"avatar_id": "avatar_abc123",
"error": "File size exceeds maximum limit",
"error_code": "FILE_TOO_LARGE",
"failed_files": ["BAADBAADrwADBREAAWn4gALvKoNaAg"],
"timestamp": "2024-01-15T10:30:00Z"
}| Код ошибки | Описание |
|---|---|
BATCH_VALIDATION_ERROR |
Ошибка валидации batch (train) |
INFERENCE_PROCESSING_ERROR |
Ошибка обработки inference фото |
TELEGRAM_API_ERROR |
Ошибка при обращении к Telegram Bot API |
INVALID_TELEGRAM_URL |
Некорректный URL от Telegram API |
FILE_TOO_LARGE |
Размер файла превышает лимит |
FILE_TOO_SMALL |
Размер файла меньше минимального |
IMAGE_TOO_SMALL |
Размеры изображения меньше минимальных (450x450px) - только для train |
DOWNLOAD_HTTP_ERROR |
HTTP ошибка при скачивании |
DOWNLOAD_TIMEOUT |
Таймаут при скачивании |
S3_UPLOAD_ERROR |
Ошибка загрузки в S3 |
UNEXPECTED_ERROR |
Неожиданная ошибка |
INTERNAL_ERROR |
Внутренняя ошибка сервиса |
# Отправка batch для тренировки (с автогенерацией s3_key)
nats pub photo_upload_train '{
"header": "train",
"photos": [
{"file_id": "photo1_url", "s3_key": ""},
{"file_id": "photo2_url", "s3_key": ""}
],
"bot_id": 12345,
"user_id": 67890,
"avatar_id": "train_avatar_123"
}'
# Отправка batch с кастомными s3_key
nats pub photo_upload_train '{
"header": "train",
"photos": [
{"file_id": "photo1_url", "s3_key": "custom1.jpg"},
{"file_id": "photo2_url", "s3_key": "custom2.jpg"}
],
"bot_id": 12345,
"user_id": 67890,
"avatar_id": "train_avatar_123"
}'# Отправка одного фото для inference (с автогенерацией s3_key)
nats pub photo_upload_inf '{
"header": "inf",
"photo": {
"file_id": "photo_url",
"s3_key": ""
},
"bot_id": 12345,
"user_id": 67890,
"avatar_id": "inf_avatar_123"
}'make help # Показать все доступные команды
make install # Установить зависимости
make dev # Установить dev зависимости
make run # Запустить приложение
make test # Запустить тесты
make lint # Проверить код линтерами
make format # Отформатировать код
make clean # Очистить временные файлы
make check # Полная проверка (lint + test)photo-downloader-service/
├── app/
│ ├── main.py # Основное приложение FastStream
│ ├── schemas/
│ │ └── schemas.py # Pydantic схемы
│ ├── services/
│ │ ├── s3_service.py # Сервис для работы с S3
│ │ └── photo_downloader.py # Основная логика загрузки
│ ├── settings/
│ │ └── settings.py # Настройки приложения
│ └── utils/
│ └── logger.py # Утилиты логирования
├── pyproject.toml # Poetry конфигурация
├── Dockerfile # Docker образ
├── docker-compose.yml # Локальная разработка
├── Makefile # Команды разработки
├── env.example # Пример переменных окружения
└── README.md # Документация
# Запуск всех тестов
make test
# Запуск с покрытием
poetry run pytest --cov=app
# Запуск конкретного теста
poetry run pytest tests/test_photo_downloader.py# Проверка кода
make lint
# Автоформатирование
make format
# Полная проверка
make check# Запуск всех сервисов (NATS, MinIO, Photo Downloader)
make compose-up
# Просмотр логов
make compose-logs
# Остановка
make compose-down- NATS:
localhost:4222 - NATS Monitoring:
http://localhost:8222 - MinIO Console:
http://localhost:9001(admin/admin123) - MinIO API:
http://localhost:9000
Сервис использует personix-logger для структурированного логирования:
from app.utils.logger import logger
# Train operations
logger.info("Processing training batch", extra={
"avatar_id": request.avatar_id,
"batch_size": len(request.photos)
})
# Inference operations
logger.info("Processing inference photo", extra={
"avatar_id": request.avatar_id,
"file_id": request.photo.file_id
})- Количество batch
- Размер batch (количество фото)
- Время обработки batch
- Успешные/неудачные файлы в batch
- Количество одиночных фото
- Время загрузки каждого фото
- Успешные/неудачные загрузки
-
Ошибка подключения к NATS
Проверьте NATS_URL в .env файле Убедитесь, что NATS сервер запущен -
Неправильная структура S3
Train: {bot_id}/{user_id}/{avatar_id}/filename.jpg Inference: uploads/inf/{bot_id}/{user_id}/{avatar_id}/filename.jpg -
Проблемы с типами операций
Используйте photo_upload_train для batch (train) Используйте photo_upload_inf для одиночных фото (inf)