serializers.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282
  1. # ==================== Updated serializers.py ====================
  2. from rest_framework import serializers
  3. from .models import Product, ProductType, ProductAttribute, AttributePossibleValue
  4. class ProductInputSerializer(serializers.Serializer):
  5. """Serializer for individual product input."""
  6. product_id = serializers.CharField(required=False, allow_blank=True, allow_null=True)
  7. title = serializers.CharField(required=False, allow_blank=True, allow_null=True)
  8. short_desc = serializers.CharField(required=False, allow_blank=True, allow_null=True)
  9. long_desc = serializers.CharField(required=False, allow_blank=True, allow_null=True)
  10. image_url = serializers.URLField(required=False, allow_blank=True, allow_null=True)
  11. class MandatoryAttrsField(serializers.DictField):
  12. """Custom DictField to validate mandatory_attrs structure."""
  13. child = serializers.ListField(child=serializers.CharField())
  14. class ProductBatchInputSerializer(serializers.Serializer):
  15. """Serializer for an individual product input within the batch request."""
  16. item_id = serializers.CharField(required=True)
  17. mandatory_attrs = MandatoryAttrsField(
  18. required=True,
  19. help_text="A dictionary of attribute names and their possible values."
  20. )
  21. class SingleProductRequestSerializer(serializers.Serializer):
  22. """Serializer for single product extraction request."""
  23. item_id = serializers.CharField(required=True)
  24. mandatory_attrs = serializers.DictField(
  25. child=serializers.ListField(child=serializers.CharField()),
  26. required=True
  27. )
  28. model = serializers.CharField(required=False, default="llama-3.1-8b-instant")
  29. extract_additional = serializers.BooleanField(required=False, default=True)
  30. process_image = serializers.BooleanField(required=False, default=True)
  31. multiple = serializers.ListField(
  32. child=serializers.CharField(),
  33. required=False,
  34. default=list,
  35. help_text="List of attribute names that can have multiple values"
  36. )
  37. threshold_abs = serializers.FloatField(default=0.65, required=False)
  38. margin = serializers.FloatField(default=0.15, required=False)
  39. use_dynamic_thresholds = serializers.BooleanField(default=True, required=False)
  40. use_adaptive_margin = serializers.BooleanField(default=True, required=False)
  41. use_semantic_clustering = serializers.BooleanField(default=True, required=False)
  42. def validate_model(self, value):
  43. from django.conf import settings
  44. if value not in settings.SUPPORTED_MODELS:
  45. raise serializers.ValidationError(
  46. f"Model must be one of {settings.SUPPORTED_MODELS}"
  47. )
  48. return value
  49. class BatchProductRequestSerializer(serializers.Serializer):
  50. """Serializer for batch product extraction request (with item-specific attributes)."""
  51. products = serializers.ListField(
  52. child=ProductBatchInputSerializer(),
  53. required=True,
  54. min_length=1
  55. )
  56. model = serializers.CharField(required=False, default="llama-3.1-8b-instant")
  57. extract_additional = serializers.BooleanField(required=False, default=True)
  58. process_image = serializers.BooleanField(required=False, default=True)
  59. multiple = serializers.ListField(
  60. child=serializers.CharField(),
  61. required=False,
  62. default=list,
  63. help_text="List of attribute names that can have multiple values"
  64. )
  65. threshold_abs = serializers.FloatField(default=0.65, required=False)
  66. margin = serializers.FloatField(default=0.15, required=False)
  67. use_dynamic_thresholds = serializers.BooleanField(default=True, required=False)
  68. use_adaptive_margin = serializers.BooleanField(default=True, required=False)
  69. use_semantic_clustering = serializers.BooleanField(default=True, required=False)
  70. def validate_model(self, value):
  71. from django.conf import settings
  72. if value not in settings.SUPPORTED_MODELS:
  73. raise serializers.ValidationError(
  74. f"Model must be one of {settings.SUPPORTED_MODELS}"
  75. )
  76. return value
  77. def validate_products(self, value):
  78. from django.conf import settings
  79. max_size = getattr(settings, 'MAX_BATCH_SIZE', 100)
  80. if len(value) > max_size:
  81. raise serializers.ValidationError(
  82. f"Batch size cannot exceed {max_size} products"
  83. )
  84. return value
  85. class OCRResultSerializer(serializers.Serializer):
  86. """Serializer for OCR results."""
  87. detected_text = serializers.ListField(child=serializers.DictField())
  88. extracted_attributes = serializers.DictField()
  89. class VisualAttributeDetailSerializer(serializers.Serializer):
  90. """Serializer for detailed visual attribute predictions."""
  91. attribute = serializers.CharField()
  92. predictions = serializers.ListField(child=serializers.DictField())
  93. class VisualResultSerializer(serializers.Serializer):
  94. """Serializer for visual processing results."""
  95. visual_attributes = serializers.DictField(
  96. help_text="Extracted visual attributes like color, pattern, style, etc."
  97. )
  98. detailed_predictions = serializers.DictField(
  99. child=VisualAttributeDetailSerializer(),
  100. required=False,
  101. help_text="Detailed predictions with confidence scores for each attribute"
  102. )
  103. error = serializers.CharField(required=False)
  104. class ProductAttributeResultSerializer(serializers.Serializer):
  105. """Serializer for individual product extraction result."""
  106. product_id = serializers.CharField(required=False)
  107. mandatory = serializers.DictField()
  108. additional = serializers.DictField(required=False)
  109. ocr_results = OCRResultSerializer(required=False)
  110. visual_results = VisualResultSerializer(required=False)
  111. error = serializers.CharField(required=False)
  112. raw_output = serializers.CharField(required=False)
  113. class BatchProductResponseSerializer(serializers.Serializer):
  114. """Serializer for batch extraction response."""
  115. results = serializers.ListField(child=ProductAttributeResultSerializer())
  116. total_products = serializers.IntegerField()
  117. successful = serializers.IntegerField()
  118. failed = serializers.IntegerField()
  119. class ProductSerializer(serializers.ModelSerializer):
  120. """Serializer for Product model with product type details."""
  121. product_type_details = serializers.SerializerMethodField()
  122. class Meta:
  123. model = Product
  124. fields = [
  125. 'id',
  126. 'item_id',
  127. 'product_name',
  128. 'product_long_description',
  129. 'product_short_description',
  130. 'product_type',
  131. 'image_path',
  132. 'image',
  133. 'product_type_details',
  134. ]
  135. def get_product_type_details(self, obj):
  136. """Fetch ProductType object and its attributes for this product."""
  137. try:
  138. product_type = ProductType.objects.get(name=obj.product_type)
  139. except ProductType.DoesNotExist:
  140. return []
  141. # Serialize its attributes
  142. attributes = ProductAttribute.objects.filter(product_type=product_type)
  143. return [
  144. {
  145. "attribute_name": attr.name,
  146. "is_mandatory": "Yes" if attr.is_mandatory else "No",
  147. "possible_values": [pv.value for pv in attr.possible_values.all()]
  148. }
  149. for attr in attributes
  150. ]
  151. class AttributePossibleValueSerializer(serializers.ModelSerializer):
  152. """Serializer for AttributePossibleValue model."""
  153. class Meta:
  154. model = AttributePossibleValue
  155. fields = ['value']
  156. class ProductAttributeSerializer(serializers.ModelSerializer):
  157. """Serializer for ProductAttribute model with possible values."""
  158. possible_values = AttributePossibleValueSerializer(many=True, read_only=True)
  159. class Meta:
  160. model = ProductAttribute
  161. fields = ['name', 'is_mandatory', 'possible_values']
  162. class ProductTypeSerializer(serializers.ModelSerializer):
  163. """Serializer for ProductType model with attributes."""
  164. attributes = ProductAttributeSerializer(many=True, read_only=True)
  165. class Meta:
  166. model = ProductType
  167. fields = ['name', 'attributes']
  168. # Add these new serializers to your serializers.py
  169. from rest_framework import serializers
  170. from .models import Product, ProductType, ProductAttribute, AttributePossibleValue, ProductAttributeValue
  171. class ProductAttributeValueSerializer(serializers.ModelSerializer):
  172. """Serializer for manually entered attribute values."""
  173. item_id = serializers.CharField(source='product.item_id', read_only=True)
  174. class Meta:
  175. model = ProductAttributeValue
  176. fields = ['id', 'item_id', 'attribute_name', 'original_value', 'created_at', 'updated_at']
  177. read_only_fields = ['created_at', 'updated_at']
  178. class ProductAttributeValueInputSerializer(serializers.Serializer):
  179. """Serializer for creating/updating attribute values."""
  180. item_id = serializers.CharField(required=True)
  181. attribute_name = serializers.CharField(required=True)
  182. original_value = serializers.CharField(required=True, allow_blank=True)
  183. class BulkProductAttributeValueSerializer(serializers.Serializer):
  184. """Serializer for bulk upload of attribute values."""
  185. item_id = serializers.CharField(required=True)
  186. attributes = serializers.DictField(
  187. child=serializers.CharField(allow_blank=True),
  188. required=True,
  189. help_text="Dictionary of attribute_name: original_value pairs"
  190. )
  191. class ProductWithAttributesSerializer(serializers.ModelSerializer):
  192. """Extended Product serializer with original attribute values."""
  193. product_type_details = serializers.SerializerMethodField()
  194. original_attributes = serializers.SerializerMethodField()
  195. class Meta:
  196. model = Product
  197. fields = [
  198. 'id',
  199. 'item_id',
  200. 'product_name',
  201. 'product_long_description',
  202. 'product_short_description',
  203. 'product_type',
  204. 'image_path',
  205. 'image',
  206. 'product_type_details',
  207. 'original_attributes',
  208. ]
  209. def get_product_type_details(self, obj):
  210. """Fetch ProductType object and its attributes for this product."""
  211. try:
  212. product_type = ProductType.objects.get(name=obj.product_type)
  213. except ProductType.DoesNotExist:
  214. return []
  215. attributes = ProductAttribute.objects.filter(product_type=product_type)
  216. return [
  217. {
  218. "attribute_name": attr.name,
  219. "is_mandatory": "Yes" if attr.is_mandatory else "No",
  220. "possible_values": [pv.value for pv in attr.possible_values.all()]
  221. }
  222. for attr in attributes
  223. ]
  224. def get_original_attributes(self, obj):
  225. """Get manually entered original attribute values."""
  226. values = ProductAttributeValue.objects.filter(product=obj)
  227. return {val.attribute_name: val.original_value for val in values}