# ==================== Updated serializers.py ==================== from rest_framework import serializers from .models import Product, ProductType, ProductAttribute, AttributePossibleValue class ProductInputSerializer(serializers.Serializer): """Serializer for individual product input.""" product_id = serializers.CharField(required=False, allow_blank=True, allow_null=True) title = serializers.CharField(required=False, allow_blank=True, allow_null=True) short_desc = serializers.CharField(required=False, allow_blank=True, allow_null=True) long_desc = serializers.CharField(required=False, allow_blank=True, allow_null=True) image_url = serializers.URLField(required=False, allow_blank=True, allow_null=True) class MandatoryAttrsField(serializers.DictField): """Custom DictField to validate mandatory_attrs structure.""" child = serializers.ListField(child=serializers.CharField()) class ProductBatchInputSerializer(serializers.Serializer): """Serializer for an individual product input within the batch request.""" item_id = serializers.CharField(required=True) mandatory_attrs = MandatoryAttrsField( required=True, help_text="A dictionary of attribute names and their possible values." ) class SingleProductRequestSerializer(serializers.Serializer): """Serializer for single product extraction request.""" item_id = serializers.CharField(required=True) mandatory_attrs = serializers.DictField( child=serializers.ListField(child=serializers.CharField()), required=True ) model = serializers.CharField(required=False, default="llama-3.1-8b-instant") extract_additional = serializers.BooleanField(required=False, default=True) process_image = serializers.BooleanField(required=False, default=True) multiple = serializers.ListField( child=serializers.CharField(), required=False, default=list, help_text="List of attribute names that can have multiple values" ) threshold_abs = serializers.FloatField(default=0.65, required=False) margin = serializers.FloatField(default=0.15, required=False) use_dynamic_thresholds = serializers.BooleanField(default=True, required=False) use_adaptive_margin = serializers.BooleanField(default=True, required=False) use_semantic_clustering = serializers.BooleanField(default=True, required=False) def validate_model(self, value): from django.conf import settings if value not in settings.SUPPORTED_MODELS: raise serializers.ValidationError( f"Model must be one of {settings.SUPPORTED_MODELS}" ) return value class BatchProductRequestSerializer(serializers.Serializer): """Serializer for batch product extraction request (with item-specific attributes).""" products = serializers.ListField( child=ProductBatchInputSerializer(), required=True, min_length=1 ) model = serializers.CharField(required=False, default="llama-3.1-8b-instant") extract_additional = serializers.BooleanField(required=False, default=True) process_image = serializers.BooleanField(required=False, default=True) multiple = serializers.ListField( child=serializers.CharField(), required=False, default=list, help_text="List of attribute names that can have multiple values" ) threshold_abs = serializers.FloatField(default=0.65, required=False) margin = serializers.FloatField(default=0.15, required=False) use_dynamic_thresholds = serializers.BooleanField(default=True, required=False) use_adaptive_margin = serializers.BooleanField(default=True, required=False) use_semantic_clustering = serializers.BooleanField(default=True, required=False) def validate_model(self, value): from django.conf import settings if value not in settings.SUPPORTED_MODELS: raise serializers.ValidationError( f"Model must be one of {settings.SUPPORTED_MODELS}" ) return value def validate_products(self, value): from django.conf import settings max_size = getattr(settings, 'MAX_BATCH_SIZE', 100) if len(value) > max_size: raise serializers.ValidationError( f"Batch size cannot exceed {max_size} products" ) return value class OCRResultSerializer(serializers.Serializer): """Serializer for OCR results.""" detected_text = serializers.ListField(child=serializers.DictField()) extracted_attributes = serializers.DictField() class VisualAttributeDetailSerializer(serializers.Serializer): """Serializer for detailed visual attribute predictions.""" attribute = serializers.CharField() predictions = serializers.ListField(child=serializers.DictField()) class VisualResultSerializer(serializers.Serializer): """Serializer for visual processing results.""" visual_attributes = serializers.DictField( help_text="Extracted visual attributes like color, pattern, style, etc." ) detailed_predictions = serializers.DictField( child=VisualAttributeDetailSerializer(), required=False, help_text="Detailed predictions with confidence scores for each attribute" ) error = serializers.CharField(required=False) class ProductAttributeResultSerializer(serializers.Serializer): """Serializer for individual product extraction result.""" product_id = serializers.CharField(required=False) mandatory = serializers.DictField() additional = serializers.DictField(required=False) ocr_results = OCRResultSerializer(required=False) visual_results = VisualResultSerializer(required=False) error = serializers.CharField(required=False) raw_output = serializers.CharField(required=False) class BatchProductResponseSerializer(serializers.Serializer): """Serializer for batch extraction response.""" results = serializers.ListField(child=ProductAttributeResultSerializer()) total_products = serializers.IntegerField() successful = serializers.IntegerField() failed = serializers.IntegerField() class ProductSerializer(serializers.ModelSerializer): """Serializer for Product model with product type details.""" product_type_details = serializers.SerializerMethodField() class Meta: model = Product fields = [ 'id', 'item_id', 'product_name', 'product_long_description', 'product_short_description', 'product_type', 'image_path', 'image', 'product_type_details', ] def get_product_type_details(self, obj): """Fetch ProductType object and its attributes for this product.""" try: product_type = ProductType.objects.get(name=obj.product_type) except ProductType.DoesNotExist: return [] # Serialize its attributes attributes = ProductAttribute.objects.filter(product_type=product_type) return [ { "attribute_name": attr.name, "is_mandatory": "Yes" if attr.is_mandatory else "No", "possible_values": [pv.value for pv in attr.possible_values.all()] } for attr in attributes ] class AttributePossibleValueSerializer(serializers.ModelSerializer): """Serializer for AttributePossibleValue model.""" class Meta: model = AttributePossibleValue fields = ['value'] class ProductAttributeSerializer(serializers.ModelSerializer): """Serializer for ProductAttribute model with possible values.""" possible_values = AttributePossibleValueSerializer(many=True, read_only=True) class Meta: model = ProductAttribute fields = ['name', 'is_mandatory', 'possible_values'] class ProductTypeSerializer(serializers.ModelSerializer): """Serializer for ProductType model with attributes.""" attributes = ProductAttributeSerializer(many=True, read_only=True) class Meta: model = ProductType fields = ['name', 'attributes'] # Add these new serializers to your serializers.py from rest_framework import serializers from .models import Product, ProductType, ProductAttribute, AttributePossibleValue, ProductAttributeValue class ProductAttributeValueSerializer(serializers.ModelSerializer): """Serializer for manually entered attribute values.""" item_id = serializers.CharField(source='product.item_id', read_only=True) class Meta: model = ProductAttributeValue fields = ['id', 'item_id', 'attribute_name', 'original_value', 'created_at', 'updated_at'] read_only_fields = ['created_at', 'updated_at'] class ProductAttributeValueInputSerializer(serializers.Serializer): """Serializer for creating/updating attribute values.""" item_id = serializers.CharField(required=True) attribute_name = serializers.CharField(required=True) original_value = serializers.CharField(required=True, allow_blank=True) class BulkProductAttributeValueSerializer(serializers.Serializer): """Serializer for bulk upload of attribute values.""" item_id = serializers.CharField(required=True) attributes = serializers.DictField( child=serializers.CharField(allow_blank=True), required=True, help_text="Dictionary of attribute_name: original_value pairs" ) class ProductWithAttributesSerializer(serializers.ModelSerializer): """Extended Product serializer with original attribute values.""" product_type_details = serializers.SerializerMethodField() original_attributes = serializers.SerializerMethodField() class Meta: model = Product fields = [ 'id', 'item_id', 'product_name', 'product_long_description', 'product_short_description', 'product_type', 'image_path', 'image', 'product_type_details', 'original_attributes', ] def get_product_type_details(self, obj): """Fetch ProductType object and its attributes for this product.""" try: product_type = ProductType.objects.get(name=obj.product_type) except ProductType.DoesNotExist: return [] attributes = ProductAttribute.objects.filter(product_type=product_type) return [ { "attribute_name": attr.name, "is_mandatory": "Yes" if attr.is_mandatory else "No", "possible_values": [pv.value for pv in attr.possible_values.all()] } for attr in attributes ] def get_original_attributes(self, obj): """Get manually entered original attribute values.""" values = ProductAttributeValue.objects.filter(product=obj) return {val.attribute_name: val.original_value for val in values}