feat: Реализовать систему оценки качества фотографий товаров (Фаза 1)

Добавлена полностью гибкая система для оценки качества фотографий на основе размеров:

Конфигурация (settings.py):
- IMAGE_QUALITY_LEVELS: Пороги качества как доля от максимума (95%, 70%, 40%, 20%)
- IMAGE_QUALITY_LABELS: Описания, цвета и рекомендации для каждого уровня
- Система полностью адаптивна - меняется max_width в settings → пороги пересчитываются

Валидатор (validators/image_validators.py):
- get_max_dimension_from_config() - динамически читает из IMAGE_PROCESSING_CONFIG
- get_image_quality_level() - определяет уровень качества (excellent/good/acceptable/poor/very_poor)
- get_quality_info() - информация о уровне из IMAGE_QUALITY_LABELS
- validate_product_image() - комплексная валидация для UI

Модели (models/photos.py):
- ProductPhoto, ProductKitPhoto, ProductCategoryPhoto дополнены полями:
  - quality_level: уровень качества (CharField с choices)
  - quality_warning: требует ли обновления (BooleanField)
  - Добавлены индексы для быстрого поиска товаров требующих обновления фото

Обработчик (image_processor.py):
- process_image() теперь возвращает дополнительно:
  - width, height: размеры оригинального изображения
  - quality_level: уровень качества
  - quality_warning: нужно ли обновить перед выгрузкой
- Вызывает валидатор автоматически при обработке

Логика сохранения (photos.py -> save()):
- При сохранении нового фото автоматически вычисляет quality_level и quality_warning
- При обновлении существующего фото пересчитывает качество
- Сохраняет все три поля атомарно

Система полностью готова к:
- Phase 2: Admin интерфейс с фильтрами и индикаторами
- Phase 3: Фронтенд с визуальными индикаторами в формах и API

Примеры использования:
>>> from products.validators.image_validators import get_image_quality_level
>>> get_image_quality_level(1400, 1400)  # если max=2160
('good', False)  # 1400/2160 = 64.8% >= 70%? Нет, но >= 40%
>>> get_image_quality_level(400, 400)
('poor', True)  # Требует обновления

🤖 Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-11-02 14:39:33 +03:00
parent d15e7d9414
commit 622e17a775
4 changed files with 680 additions and 2 deletions

View File

@@ -79,12 +79,16 @@ class ImageProcessor:
photo_id: ID фотографии
Returns:
dict: Словарь с путями сохраненных файлов
dict: Словарь с сохраненными данными
{
'original': 'products/<entity_id>/<photo_id>/original.jpg',
'large': 'products/<entity_id>/<photo_id>/large.webp',
'medium': 'products/<entity_id>/<photo_id>/medium.webp',
'thumbnail': 'products/<entity_id>/<photo_id>/thumb.webp',
'width': 1920,
'height': 1080,
'quality_level': 'good',
'quality_warning': False,
}
Raises:
@@ -96,6 +100,11 @@ class ImageProcessor:
try:
# Открываем изображение
img = Image.open(image_file)
width, height = img.size
# Определяем качество на основе размеров
from ..validators.image_validators import get_image_quality_level
quality_level, needs_update = get_image_quality_level(width, height)
# Конвертируем в RGB если необходимо (для JPEG/WebP)
if img.mode in ('RGBA', 'LA', 'P'):
@@ -126,6 +135,16 @@ class ImageProcessor:
)
saved_paths[size_key] = size_path
# Добавляем информацию о качестве
saved_paths['width'] = width
saved_paths['height'] = height
saved_paths['quality_level'] = quality_level
saved_paths['quality_warning'] = needs_update
logger.info(
f"Image processed: {width}x{height}px → quality={quality_level}, warning={needs_update}"
)
return saved_paths
except Exception as e: